From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752773AbbKPNdf (ORCPT ); Mon, 16 Nov 2015 08:33:35 -0500 Received: from szxga03-in.huawei.com ([119.145.14.66]:31306 "EHLO szxga03-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752719AbbKPNdb (ORCPT ); Mon, 16 Nov 2015 08:33:31 -0500 From: John Garry To: , , , , , , CC: , , , , , , , , Subject: [PATCH v4 20/32] scsi: hisi_sas: add v1 hw interrupt init Date: Mon, 16 Nov 2015 21:06:06 +0800 Message-ID: <1447679178-220222-21-git-send-email-john.garry@huawei.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1447679178-220222-1-git-send-email-john.garry@huawei.com> References: <1447679178-220222-1-git-send-email-john.garry@huawei.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.67.212.75] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A090204.5649D9AD.002A,ss=1,re=0.000,recu=0.000,reip=0.000,cl=1,cld=1,fgs=0, ip=0.0.0.0, so=2013-05-26 15:14:31, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: 0a2974fd38961815084438b0e03f907c Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add code to interrupts, so now we can get a phy up interrupt when a disk is connected. Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas.h | 5 + drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 161 +++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index ba3bf5e..938fa75 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -38,6 +38,11 @@ #define HISI_SAS_NAME_LEN 32 +enum { + PORT_TYPE_SAS = (1U << 1), + PORT_TYPE_SATA = (1U << 0), +}; + enum dev_status { HISI_SAS_DEV_NORMAL, HISI_SAS_DEV_EH, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 9bfe1aa..3ea666f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -728,6 +728,159 @@ static void phys_init_v1_hw(struct hisi_hba *hisi_hba) mod_timer(timer, jiffies + HZ); } +/* Interrupts */ +static irqreturn_t int_phyup_v1_hw(int irq_no, void *p) +{ + struct hisi_sas_phy *phy = p; + struct hisi_hba *hisi_hba = phy->hisi_hba; + struct device *dev = &hisi_hba->pdev->dev; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + int i, phy_no = sas_phy->id; + u32 irq_value, context, port_id, link_rate; + u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd; + struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd; + irqreturn_t res = IRQ_HANDLED; + + irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2); + if (!(irq_value & CHL_INT2_SL_PHY_ENA_MSK)) { + dev_dbg(dev, "phyup: irq_value = %x not set enable bit\n", + irq_value); + res = IRQ_NONE; + goto end; + } + + context = hisi_sas_read32(hisi_hba, PHY_CONTEXT); + if (context & 1 << phy_no) { + dev_err(dev, "phyup: phy%d SATA attached equipment\n", + phy_no); + goto end; + } + + port_id = (hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA) >> (4 * phy_no)) + & 0xf; + if (port_id == 0xf) { + dev_err(dev, "phyup: phy%d invalid portid\n", phy_no); + res = IRQ_NONE; + goto end; + } + + for (i = 0; i < 6; i++) { + u32 idaf = hisi_sas_phy_read32(hisi_hba, phy_no, + RX_IDAF_DWORD0 + (i * 4)); + frame_rcvd[i] = __swab32(idaf); + } + + /* Get the linkrate */ + link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE); + link_rate = (link_rate >> (phy_no * 4)) & 0xf; + sas_phy->linkrate = link_rate; + sas_phy->oob_mode = SAS_OOB_MODE; + memcpy(sas_phy->attached_sas_addr, + &id->sas_addr, SAS_ADDR_SIZE); + dev_info(dev, "phyup: phy%d link_rate=%d\n", + phy_no, link_rate); + phy->port_id = port_id; + phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); + phy->phy_type |= PORT_TYPE_SAS; + phy->phy_attached = 1; + phy->identify.device_type = id->dev_type; + phy->frame_rcvd_size = sizeof(struct sas_identify_frame); + if (phy->identify.device_type == SAS_END_DEVICE) + phy->identify.target_port_protocols = + SAS_PROTOCOL_SSP; + else if (phy->identify.device_type != SAS_PHY_UNUSED) + phy->identify.target_port_protocols = + SAS_PROTOCOL_SMP; + +end: + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2, + CHL_INT2_SL_PHY_ENA_MSK); + + if (irq_value & CHL_INT2_SL_PHY_ENA_MSK) { + u32 chl_int0 = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT0); + + chl_int0 &= ~CHL_INT0_PHYCTRL_NOTRDY_MSK; + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, chl_int0); + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0_MSK, 0x3ce3ee); + } + + return res; +} +static const char phy_int_names[HISI_SAS_PHY_INT_NR][32] = { + {"Phy Up"}, +}; +static irq_handler_t phy_interrupts[HISI_SAS_PHY_INT_NR] = { + int_phyup_v1_hw, +}; + +static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba) +{ + struct device *dev = &hisi_hba->pdev->dev; + struct device_node *np = dev->of_node; + char *int_names = hisi_hba->int_names; + int i, j, irq, rc, idx; + + if (!np) + return -ENOENT; + + for (i = 0; i < hisi_hba->n_phy; i++) { + struct hisi_sas_phy *phy = &hisi_hba->phy[i]; + + idx = i * HISI_SAS_PHY_INT_NR; + for (j = 0; j < HISI_SAS_PHY_INT_NR; j++, idx++) { + irq = irq_of_parse_and_map(np, idx); + if (!irq) { + dev_err(dev, + "irq init: fail map phy interrupt %d\n", + idx); + return -ENOENT; + } + + (void)snprintf(&int_names[idx * HISI_SAS_NAME_LEN], + HISI_SAS_NAME_LEN, + "%s %s:%d", dev_name(dev), + phy_int_names[j], i); + rc = devm_request_irq(dev, irq, phy_interrupts[j], 0, + &int_names[idx * HISI_SAS_NAME_LEN], + phy); + if (rc) { + dev_err(dev, "irq init: could not request " + "phy interrupt %d, rc=%d\n", + irq, rc); + return -ENOENT; + } + } + } + return 0; +} + +static int interrupt_openall_v1_hw(struct hisi_hba *hisi_hba) +{ + int i; + u32 val; + + for (i = 0; i < hisi_hba->n_phy; i++) { + /* Clear interrupt status */ + val = hisi_sas_phy_read32(hisi_hba, i, CHL_INT0); + hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, val); + val = hisi_sas_phy_read32(hisi_hba, i, CHL_INT1); + hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, val); + val = hisi_sas_phy_read32(hisi_hba, i, CHL_INT2); + hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, val); + + /* Unmask interrupt */ + hisi_sas_phy_write32(hisi_hba, i, CHL_INT0_MSK, 0x3ce3ee); + hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0x17fff); + hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8000012a); + + /* bypass chip bug mask abnormal intr */ + hisi_sas_phy_write32(hisi_hba, i, CHL_INT0_MSK, + 0x3fffff & ~CHL_INT0_MSK_PHYCTRL_NOTRDY_MSK); + } + + return 0; +} + static int hisi_sas_v1_init(struct hisi_hba *hisi_hba) { int rc; @@ -736,6 +889,14 @@ static int hisi_sas_v1_init(struct hisi_hba *hisi_hba) if (rc) return rc; + rc = interrupt_init_v1_hw(hisi_hba); + if (rc) + return rc; + + rc = interrupt_openall_v1_hw(hisi_hba); + if (rc) + return rc; + phys_init_v1_hw(hisi_hba); return 0; -- 1.9.1 From mboxrd@z Thu Jan 1 00:00:00 1970 From: John Garry Subject: [PATCH v4 20/32] scsi: hisi_sas: add v1 hw interrupt init Date: Mon, 16 Nov 2015 21:06:06 +0800 Message-ID: <1447679178-220222-21-git-send-email-john.garry@huawei.com> References: <1447679178-220222-1-git-send-email-john.garry@huawei.com> Mime-Version: 1.0 Content-Type: text/plain Return-path: In-Reply-To: <1447679178-220222-1-git-send-email-john.garry@huawei.com> Sender: linux-scsi-owner@vger.kernel.org To: JBottomley@odin.com, robh+dt@kernel.org, pawel.moll@arm.com, mark.rutland@arm.com, ijc+devicetree@hellion.org.uk, galak@codeaurora.org, arnd@arndb.de Cc: linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linuxarm@huawei.com, john.garry2@mail.dcu.ie, hare@suse.de, xuwei5@hisilicon.com, zhangfei.gao@linaro.org, john.garry@huawei.com List-Id: devicetree@vger.kernel.org Add code to interrupts, so now we can get a phy up interrupt when a disk is connected. Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas.h | 5 + drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 161 +++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index ba3bf5e..938fa75 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -38,6 +38,11 @@ #define HISI_SAS_NAME_LEN 32 +enum { + PORT_TYPE_SAS = (1U << 1), + PORT_TYPE_SATA = (1U << 0), +}; + enum dev_status { HISI_SAS_DEV_NORMAL, HISI_SAS_DEV_EH, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 9bfe1aa..3ea666f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -728,6 +728,159 @@ static void phys_init_v1_hw(struct hisi_hba *hisi_hba) mod_timer(timer, jiffies + HZ); } +/* Interrupts */ +static irqreturn_t int_phyup_v1_hw(int irq_no, void *p) +{ + struct hisi_sas_phy *phy = p; + struct hisi_hba *hisi_hba = phy->hisi_hba; + struct device *dev = &hisi_hba->pdev->dev; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + int i, phy_no = sas_phy->id; + u32 irq_value, context, port_id, link_rate; + u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd; + struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd; + irqreturn_t res = IRQ_HANDLED; + + irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2); + if (!(irq_value & CHL_INT2_SL_PHY_ENA_MSK)) { + dev_dbg(dev, "phyup: irq_value = %x not set enable bit\n", + irq_value); + res = IRQ_NONE; + goto end; + } + + context = hisi_sas_read32(hisi_hba, PHY_CONTEXT); + if (context & 1 << phy_no) { + dev_err(dev, "phyup: phy%d SATA attached equipment\n", + phy_no); + goto end; + } + + port_id = (hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA) >> (4 * phy_no)) + & 0xf; + if (port_id == 0xf) { + dev_err(dev, "phyup: phy%d invalid portid\n", phy_no); + res = IRQ_NONE; + goto end; + } + + for (i = 0; i < 6; i++) { + u32 idaf = hisi_sas_phy_read32(hisi_hba, phy_no, + RX_IDAF_DWORD0 + (i * 4)); + frame_rcvd[i] = __swab32(idaf); + } + + /* Get the linkrate */ + link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE); + link_rate = (link_rate >> (phy_no * 4)) & 0xf; + sas_phy->linkrate = link_rate; + sas_phy->oob_mode = SAS_OOB_MODE; + memcpy(sas_phy->attached_sas_addr, + &id->sas_addr, SAS_ADDR_SIZE); + dev_info(dev, "phyup: phy%d link_rate=%d\n", + phy_no, link_rate); + phy->port_id = port_id; + phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); + phy->phy_type |= PORT_TYPE_SAS; + phy->phy_attached = 1; + phy->identify.device_type = id->dev_type; + phy->frame_rcvd_size = sizeof(struct sas_identify_frame); + if (phy->identify.device_type == SAS_END_DEVICE) + phy->identify.target_port_protocols = + SAS_PROTOCOL_SSP; + else if (phy->identify.device_type != SAS_PHY_UNUSED) + phy->identify.target_port_protocols = + SAS_PROTOCOL_SMP; + +end: + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2, + CHL_INT2_SL_PHY_ENA_MSK); + + if (irq_value & CHL_INT2_SL_PHY_ENA_MSK) { + u32 chl_int0 = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT0); + + chl_int0 &= ~CHL_INT0_PHYCTRL_NOTRDY_MSK; + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, chl_int0); + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0_MSK, 0x3ce3ee); + } + + return res; +} +static const char phy_int_names[HISI_SAS_PHY_INT_NR][32] = { + {"Phy Up"}, +}; +static irq_handler_t phy_interrupts[HISI_SAS_PHY_INT_NR] = { + int_phyup_v1_hw, +}; + +static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba) +{ + struct device *dev = &hisi_hba->pdev->dev; + struct device_node *np = dev->of_node; + char *int_names = hisi_hba->int_names; + int i, j, irq, rc, idx; + + if (!np) + return -ENOENT; + + for (i = 0; i < hisi_hba->n_phy; i++) { + struct hisi_sas_phy *phy = &hisi_hba->phy[i]; + + idx = i * HISI_SAS_PHY_INT_NR; + for (j = 0; j < HISI_SAS_PHY_INT_NR; j++, idx++) { + irq = irq_of_parse_and_map(np, idx); + if (!irq) { + dev_err(dev, + "irq init: fail map phy interrupt %d\n", + idx); + return -ENOENT; + } + + (void)snprintf(&int_names[idx * HISI_SAS_NAME_LEN], + HISI_SAS_NAME_LEN, + "%s %s:%d", dev_name(dev), + phy_int_names[j], i); + rc = devm_request_irq(dev, irq, phy_interrupts[j], 0, + &int_names[idx * HISI_SAS_NAME_LEN], + phy); + if (rc) { + dev_err(dev, "irq init: could not request " + "phy interrupt %d, rc=%d\n", + irq, rc); + return -ENOENT; + } + } + } + return 0; +} + +static int interrupt_openall_v1_hw(struct hisi_hba *hisi_hba) +{ + int i; + u32 val; + + for (i = 0; i < hisi_hba->n_phy; i++) { + /* Clear interrupt status */ + val = hisi_sas_phy_read32(hisi_hba, i, CHL_INT0); + hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, val); + val = hisi_sas_phy_read32(hisi_hba, i, CHL_INT1); + hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, val); + val = hisi_sas_phy_read32(hisi_hba, i, CHL_INT2); + hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, val); + + /* Unmask interrupt */ + hisi_sas_phy_write32(hisi_hba, i, CHL_INT0_MSK, 0x3ce3ee); + hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0x17fff); + hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8000012a); + + /* bypass chip bug mask abnormal intr */ + hisi_sas_phy_write32(hisi_hba, i, CHL_INT0_MSK, + 0x3fffff & ~CHL_INT0_MSK_PHYCTRL_NOTRDY_MSK); + } + + return 0; +} + static int hisi_sas_v1_init(struct hisi_hba *hisi_hba) { int rc; @@ -736,6 +889,14 @@ static int hisi_sas_v1_init(struct hisi_hba *hisi_hba) if (rc) return rc; + rc = interrupt_init_v1_hw(hisi_hba); + if (rc) + return rc; + + rc = interrupt_openall_v1_hw(hisi_hba); + if (rc) + return rc; + phys_init_v1_hw(hisi_hba); return 0; -- 1.9.1