Commit 057c3d1f authored by Xiaofei Tan's avatar Xiaofei Tan Committed by Martin K. Petersen
Browse files

scsi: hisi_sas: do link reset for some CHL_INT2 ints



We should do link reset of PHY when identify timeout or STP link timeout. They
are internal events of SOC and are notified to driver through interrupts of
CHL_INT2.

Besides, we should add an delay work to do link reset as it needs sleep. So,
this patch add an new PHY event HISI_PHYE_LINK_RESET for this.

Notes: v2 HW doesn't report the event of STP link timeout.  So, we only need
to handle event of identify timeout for v2 HW.

Signed-off-by: default avatarXiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: default avatarJohn Garry <john.garry@huawei.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent e537b62b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -126,6 +126,7 @@ enum hisi_sas_bit_err_type {

enum hisi_sas_phy_event {
	HISI_PHYE_PHY_UP   = 0U,
	HISI_PHYE_LINK_RESET,
	HISI_PHYES_NUM,
};

+12 −0
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
			     struct domain_device *device,
			     int abort_flag, int tag);
static int hisi_sas_softreset_ata_disk(struct domain_device *device);
static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
				void *funcdata);

u8 hisi_sas_get_ata_protocol(u8 cmd, int direction)
{
@@ -631,8 +633,18 @@ static void hisi_sas_phyup_work(struct work_struct *work)
	hisi_sas_bytes_dmaed(hisi_hba, phy_no);
}

static void hisi_sas_linkreset_work(struct work_struct *work)
{
	struct hisi_sas_phy *phy =
		container_of(work, typeof(*phy), works[HISI_PHYE_LINK_RESET]);
	struct asd_sas_phy *sas_phy = &phy->sas_phy;

	hisi_sas_control_phy(sas_phy, PHY_FUNC_LINK_RESET, NULL);
}

static const work_func_t hisi_sas_phye_fns[HISI_PHYES_NUM] = {
	[HISI_PHYE_PHY_UP] = hisi_sas_phyup_work,
	[HISI_PHYE_LINK_RESET] = hisi_sas_linkreset_work,
};

bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy,
+14 −4
Original line number Diff line number Diff line
@@ -245,6 +245,7 @@
#define CHL_INT1_DMAC_RX_AXI_WR_ERR_OFF	21
#define CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF	22
#define CHL_INT2			(PORT_BASE + 0x1bc)
#define CHL_INT2_SL_IDAF_TOUT_CONF_OFF	0
#define CHL_INT0_MSK			(PORT_BASE + 0x1c0)
#define CHL_INT1_MSK			(PORT_BASE + 0x1c4)
#define CHL_INT2_MSK			(PORT_BASE + 0x1c8)
@@ -1187,7 +1188,7 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, 0xfff87fff);
		hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000);
		hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xff857fff);
		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbff);
		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbfe);
		hisi_sas_phy_write32(hisi_hba, i, SL_CFG, 0x13f801fc);
		hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL_RDY_MSK, 0x0);
		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_NOT_RDY_MSK, 0x0);
@@ -2905,10 +2906,19 @@ static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
					     CHL_INT1, irq_value1);
		}

		if ((irq_msk & (1 << phy_no)) && irq_value2)
		if ((irq_msk & (1 << phy_no)) && irq_value2) {
			struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];

			if (irq_value2 & BIT(CHL_INT2_SL_IDAF_TOUT_CONF_OFF)) {
				dev_warn(dev, "phy%d identify timeout\n",
						phy_no);
				hisi_sas_notify_phy_event(phy,
						HISI_PHYE_LINK_RESET);
			}

			hisi_sas_phy_write32(hisi_hba, phy_no,
						 CHL_INT2, irq_value2);

		}

		if ((irq_msk & (1 << phy_no)) && irq_value0) {
			if (irq_value0 & CHL_INT0_SL_RX_BCST_ACK_MSK)
+27 −2
Original line number Diff line number Diff line
@@ -140,6 +140,7 @@
#define RX_IDAF_DWORD0			(PORT_BASE + 0xc4)
#define RXOP_CHECK_CFG_H		(PORT_BASE + 0xfc)
#define STP_LINK_TIMER			(PORT_BASE + 0x120)
#define STP_LINK_TIMEOUT_STATE		(PORT_BASE + 0x124)
#define CON_CFG_DRIVER			(PORT_BASE + 0x130)
#define SAS_SSP_CON_TIMER_CFG		(PORT_BASE + 0x134)
#define SAS_SMP_CON_TIMER_CFG		(PORT_BASE + 0x138)
@@ -165,6 +166,8 @@
#define CHL_INT1_DMAC_RX_AXI_WR_ERR_OFF	21
#define CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF	22
#define CHL_INT2			(PORT_BASE + 0x1bc)
#define CHL_INT2_SL_IDAF_TOUT_CONF_OFF	0
#define CHL_INT2_STP_LINK_TIMEOUT_OFF	31
#define CHL_INT0_MSK			(PORT_BASE + 0x1c0)
#define CHL_INT1_MSK			(PORT_BASE + 0x1c4)
#define CHL_INT2_MSK			(PORT_BASE + 0x1c8)
@@ -429,7 +432,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, 0xffffffff);
		hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000);
		hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xff87ffff);
		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbff);
		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0xffffbfe);
		hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL_RDY_MSK, 0x0);
		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_NOT_RDY_MSK, 0x0);
		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_DWS_RESET_MSK, 0x0);
@@ -1342,9 +1345,31 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p)
					     CHL_INT1, irq_value1);
		}

		if (irq_msk & (8 << (phy_no * 4)) && irq_value2)
		if (irq_msk & (8 << (phy_no * 4)) && irq_value2) {
			struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];

			if (irq_value2 & BIT(CHL_INT2_SL_IDAF_TOUT_CONF_OFF)) {
				dev_warn(dev, "phy%d identify timeout\n",
							phy_no);
				hisi_sas_notify_phy_event(phy,
					HISI_PHYE_LINK_RESET);

			}

			if (irq_value2 & BIT(CHL_INT2_STP_LINK_TIMEOUT_OFF)) {
				u32 reg_value = hisi_sas_phy_read32(hisi_hba,
						phy_no, STP_LINK_TIMEOUT_STATE);

				dev_warn(dev, "phy%d stp link timeout (0x%x)\n",
							phy_no, reg_value);
				if (reg_value & BIT(4))
					hisi_sas_notify_phy_event(phy,
						HISI_PHYE_LINK_RESET);
			}

			hisi_sas_phy_write32(hisi_hba, phy_no,
					     CHL_INT2, irq_value2);
		}


		if (irq_msk & (2 << (phy_no * 4)) && irq_value0) {