From patchwork Wed May 31 14:33:05 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Garry X-Patchwork-Id: 100766 Delivered-To: patch@linaro.org Received: by 10.140.96.100 with SMTP id j91csp339783qge; Wed, 31 May 2017 07:05:46 -0700 (PDT) X-Received: by 10.99.132.194 with SMTP id k185mr32374626pgd.43.1496239546565; Wed, 31 May 2017 07:05:46 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496239546; cv=none; d=google.com; s=arc-20160816; b=XevXDhkwQnoVx/OXrO/lP4k90TGNkOr/cxOjVgWIRFLiYVHkcqHXzkRInUk6qTZsBa WmqfUPbC9N4fgd6xWj9S+VQz+gYV6iIhJO/i01hVnTrM6/Hnu0FUHP96+c0wkzdR4CBh 1W5NHMz7woTtN7dQXad0TCvAJr+FGtlKFk9CuGkbZ5cM1WJkQHAp9MxDg7w8gWeZIBP7 TzBVkl9jnz1WNbMWQLwF1RwsuGcnj3oWfsJlNtv6PMZ17ifGiT8yFtERvfHRckTjQnXU lADivpyIJveb9hs+gaQeN2zPPaIRBhKkyse/0lnywSRBGUH/rz5sLMEaXhiw2oBq/DM8 MW4w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:arc-authentication-results; bh=brrmwnj9zjU+DyK+OM/BKZA86IMjbVbNe/UWTXv49JA=; b=RAw1L0JQZ86EEhBRvCGCvLdvY7sXthAwkJaVaAhbIwFQbNp4BhGW+XUq04GYAPtJtq 7WAQd1XdHCGXHUM2OfA3ckXgvPXGv1YdWbds3kKfA/S837qRvC4bjgptN538LxOZexqN X9Co4XNtBkf4u6AB/6oYq46EU+/sMd8X6z8uL48E1PiYdbMsOhlbon6o9INRPjkm27PO Frm+g8uwMqpJVjiDxteUXwS/FRFesYpbhOjg0NT7Wy2l/z9n7F0hzEjX04qKeAi1ZFW7 iegx2WSFdC3Cqk3nbg7ABWDTFRE4c0188MbT7LYp4cmzuuf7/qF2i4gG0czCdOZxijrm 7O0g== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id k14si47937362pln.122.2017.05.31.07.05.46; Wed, 31 May 2017 07:05:46 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751473AbdEaOF2 (ORCPT + 25 others); Wed, 31 May 2017 10:05:28 -0400 Received: from szxga02-in.huawei.com ([45.249.212.188]:6846 "EHLO szxga02-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751394AbdEaOFV (ORCPT ); Wed, 31 May 2017 10:05:21 -0400 Received: from 172.30.72.53 (EHLO dggeml405-hub.china.huawei.com) ([172.30.72.53]) by dggrg02-dlp.huawei.com (MOS 4.4.6-GA FastPath queued) with ESMTP id AON26164; Wed, 31 May 2017 22:05:12 +0800 (CST) Received: from localhost.localdomain (10.67.212.75) by dggeml405-hub.china.huawei.com (10.3.17.49) with Microsoft SMTP Server id 14.3.301.0; Wed, 31 May 2017 22:05:01 +0800 From: John Garry To: , CC: , , , , , Xiang Chen , John Garry Subject: [PATCH v3 13/23] scsi: hisi_sas: add phy up/down/bcast and channel ISR Date: Wed, 31 May 2017 22:33:05 +0800 Message-ID: <1496241195-217678-14-git-send-email-john.garry@huawei.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1496241195-217678-1-git-send-email-john.garry@huawei.com> References: <1496241195-217678-1-git-send-email-john.garry@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.212.75] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A090205.592ECD99.001A, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2014-11-16 11:51:01, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: 909931b9e571e915e9a738a5e47de7ba Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Xiang Chen Add code to initialise interrupts and add some interrupt handlers. Signed-off-by: John Garry Signed-off-by: Xiang Chen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 281 +++++++++++++++++++++++++++++++++ 1 file changed, 281 insertions(+) -- 1.9.1 diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 9651658..49f14d2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -173,6 +173,13 @@ enum { HISI_SAS_PHY_INT_NR }; +static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) +{ + void __iomem *regs = hisi_hba->regs + off; + + return readl(regs); +} + static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val) { void __iomem *regs = hisi_hba->regs + off; @@ -397,6 +404,276 @@ static void sl_notify_v3_hw(struct hisi_hba *hisi_hba, int phy_no) hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control); } +static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) +{ + int i, res = 0; + u32 context, port_id, link_rate, hard_phy_linkrate; + struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + struct device *dev = hisi_hba->dev; + + hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1); + + port_id = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA); + port_id = (port_id >> (4 * phy_no)) & 0xf; + link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE); + link_rate = (link_rate >> (phy_no * 4)) & 0xf; + + if (port_id == 0xf) { + dev_err(dev, "phyup: phy%d invalid portid\n", phy_no); + res = IRQ_NONE; + goto end; + } + sas_phy->linkrate = link_rate; + hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no, + HARD_PHY_LINKRATE); + phy->maximum_linkrate = hard_phy_linkrate & 0xf; + phy->minimum_linkrate = (hard_phy_linkrate >> 4) & 0xf; + phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); + + /* Check for SATA dev */ + context = hisi_sas_read32(hisi_hba, PHY_CONTEXT); + if (context & (1 << phy_no)) { + struct hisi_sas_initial_fis *initial_fis; + struct dev_to_host_fis *fis; + u8 attached_sas_addr[SAS_ADDR_SIZE] = {0}; + + dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate); + initial_fis = &hisi_hba->initial_fis[phy_no]; + fis = &initial_fis->fis; + sas_phy->oob_mode = SATA_OOB_MODE; + attached_sas_addr[0] = 0x50; + attached_sas_addr[7] = phy_no; + memcpy(sas_phy->attached_sas_addr, + attached_sas_addr, + SAS_ADDR_SIZE); + memcpy(sas_phy->frame_rcvd, fis, + sizeof(struct dev_to_host_fis)); + phy->phy_type |= PORT_TYPE_SATA; + phy->identify.device_type = SAS_SATA_DEV; + phy->frame_rcvd_size = sizeof(struct dev_to_host_fis); + phy->identify.target_port_protocols = SAS_PROTOCOL_SATA; + } else { + u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd; + struct sas_identify_frame *id = + (struct sas_identify_frame *)frame_rcvd; + + dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate); + 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); + } + sas_phy->oob_mode = SAS_OOB_MODE; + memcpy(sas_phy->attached_sas_addr, + &id->sas_addr, + SAS_ADDR_SIZE); + phy->phy_type |= PORT_TYPE_SAS; + 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; + } + + phy->port_id = port_id; + phy->phy_attached = 1; + queue_work(hisi_hba->wq, &phy->phyup_ws); + +end: + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, + CHL_INT0_SL_PHY_ENABLE_MSK); + hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 0); + + return res; +} + +static int phy_down_v3_hw(int phy_no, struct hisi_hba *hisi_hba) +{ + int res = 0; + u32 phy_state, sl_ctrl, txid_auto; + struct device *dev = hisi_hba->dev; + + hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1); + + phy_state = hisi_sas_read32(hisi_hba, PHY_STATE); + dev_info(dev, "phydown: phy%d phy_state=0x%x\n", phy_no, phy_state); + hisi_sas_phy_down(hisi_hba, phy_no, (phy_state & 1 << phy_no) ? 1 : 0); + + sl_ctrl = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL); + hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, + sl_ctrl&(~SL_CTA_MSK)); + + txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO); + hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO, + txid_auto | CT3_MSK); + + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_NOT_RDY_MSK); + hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 0); + + return res; +} + +static void phy_bcast_v3_hw(int phy_no, struct hisi_hba *hisi_hba) +{ + struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + struct sas_ha_struct *sas_ha = &hisi_hba->sha; + + hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 1); + sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, + CHL_INT0_SL_RX_BCST_ACK_MSK); + hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 0); +} + +static irqreturn_t int_phy_up_down_bcast_v3_hw(int irq_no, void *p) +{ + struct hisi_hba *hisi_hba = p; + u32 irq_msk; + int phy_no = 0; + irqreturn_t res = IRQ_NONE; + + irq_msk = hisi_sas_read32(hisi_hba, CHNL_INT_STATUS) + & 0x11111111; + while (irq_msk) { + if (irq_msk & 1) { + u32 irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, + CHL_INT0); + u32 phy_state = hisi_sas_read32(hisi_hba, PHY_STATE); + int rdy = phy_state & (1 << phy_no); + + if (rdy) { + if (irq_value & CHL_INT0_SL_PHY_ENABLE_MSK) + /* phy up */ + if (phy_up_v3_hw(phy_no, hisi_hba) + == IRQ_HANDLED) + res = IRQ_HANDLED; + if (irq_value & CHL_INT0_SL_RX_BCST_ACK_MSK) + /* phy bcast */ + phy_bcast_v3_hw(phy_no, hisi_hba); + } else { + if (irq_value & CHL_INT0_NOT_RDY_MSK) + /* phy down */ + if (phy_down_v3_hw(phy_no, hisi_hba) + == IRQ_HANDLED) + res = IRQ_HANDLED; + } + } + irq_msk >>= 4; + phy_no++; + } + + return res; +} + +static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p) +{ + struct hisi_hba *hisi_hba = p; + struct device *dev = hisi_hba->dev; + u32 ent_msk, ent_tmp, irq_msk; + int phy_no = 0; + + ent_msk = hisi_sas_read32(hisi_hba, ENT_INT_SRC_MSK3); + ent_tmp = ent_msk; + ent_msk |= ENT_INT_SRC_MSK3_ENT95_MSK_MSK; + hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, ent_msk); + + irq_msk = hisi_sas_read32(hisi_hba, CHNL_INT_STATUS) + & 0xeeeeeeee; + + while (irq_msk) { + u32 irq_value0 = hisi_sas_phy_read32(hisi_hba, phy_no, + CHL_INT0); + u32 irq_value1 = hisi_sas_phy_read32(hisi_hba, phy_no, + CHL_INT1); + u32 irq_value2 = hisi_sas_phy_read32(hisi_hba, phy_no, + CHL_INT2); + + if ((irq_msk & (4 << (phy_no * 4))) && + irq_value1) { + if (irq_value1 & (CHL_INT1_DMAC_RX_ECC_ERR_MSK | + CHL_INT1_DMAC_TX_ECC_ERR_MSK)) + panic("%s: DMAC RX/TX ecc bad error! (0x%x)", + dev_name(dev), irq_value1); + + hisi_sas_phy_write32(hisi_hba, phy_no, + CHL_INT1, irq_value1); + } + + if (irq_msk & (8 << (phy_no * 4)) && irq_value2) + hisi_sas_phy_write32(hisi_hba, phy_no, + CHL_INT2, irq_value2); + + + if (irq_msk & (2 << (phy_no * 4)) && irq_value0) { + hisi_sas_phy_write32(hisi_hba, phy_no, + CHL_INT0, irq_value0 + & (~CHL_INT0_HOTPLUG_TOUT_MSK) + & (~CHL_INT0_SL_PHY_ENABLE_MSK) + & (~CHL_INT0_NOT_RDY_MSK)); + } + irq_msk &= ~(0xe << (phy_no * 4)); + phy_no++; + } + + hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, ent_tmp); + + return IRQ_HANDLED; +} + +static irq_handler_t phy_interrupts[HISI_SAS_PHY_INT_NR] = { + int_phy_up_down_bcast_v3_hw, + int_chnl_int_v3_hw, +}; + +static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) +{ + struct device *dev = hisi_hba->dev; + struct pci_dev *pdev = hisi_hba->pci_dev; + int vectors, i, irq, rc; + int max_msi = HISI_SAS_MSI_COUNT_V3_HW; + int msi_vectors[HISI_SAS_MSI_COUNT_V3_HW]; + + if (pdev->msi_enabled) + pci_disable_msi(pdev); + + vectors = pci_alloc_irq_vectors(hisi_hba->pci_dev, 1, + max_msi, PCI_IRQ_MSI); + if (vectors < max_msi) { + dev_err(dev, "could not allocate all msi (%d)\n", vectors); + return -ENOENT; + } + + for (i = 0; i < vectors; i++) + msi_vectors[i] = pdev->irq + i; + + for (i = 0; i < HISI_SAS_PHY_INT_NR; i++) { + int idx = i; + + irq = msi_vectors[idx + 1]; /* Phy up/down/bcast is irq1 */ + if (!irq) { + dev_err(dev, "irq init: failed to map PHY interrupt %d\n", + idx); + return -ENOENT; + } + + rc = devm_request_irq(dev, irq, phy_interrupts[i], 0, + DRV_NAME " phy", hisi_hba); + if (rc) { + dev_err(dev, "irq init: could not request " + "phy interrupt %d, rc=%d\n", + irq, rc); + return -ENOENT; + } + } + + return 0; +} + static int hisi_sas_v3_init(struct hisi_hba *hisi_hba) { int rc; @@ -405,6 +682,10 @@ static int hisi_sas_v3_init(struct hisi_hba *hisi_hba) if (rc) return rc; + rc = interrupt_init_v3_hw(hisi_hba); + if (rc) + return rc; + return 0; }