]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
scsi: hisi_sas: us start_phy in PHY_FUNC_LINK_RESET
[mirror_ubuntu-bionic-kernel.git] / drivers / scsi / hisi_sas / hisi_sas_v3_hw.c
index 83d2dca1c650c3e0c32568ac1c6fba5505ece351..67ebd8f6f84af018e33f3357a3f737af5cde5763 100644 (file)
 #define PHY_STATE                      0x24
 #define PHY_PORT_NUM_MA                        0x28
 #define PHY_CONN_RATE                  0x30
-#define AXI_AHB_CLK_CFG                        0x3c
 #define ITCT_CLR                       0x44
 #define ITCT_CLR_EN_OFF                        16
 #define ITCT_CLR_EN_MSK                        (0x1 << ITCT_CLR_EN_OFF)
 #define ITCT_DEV_OFF                   0
 #define ITCT_DEV_MSK                   (0x7ff << ITCT_DEV_OFF)
-#define AXI_USER1                      0x48
-#define AXI_USER2                      0x4c
 #define IO_SATA_BROKEN_MSG_ADDR_LO     0x58
 #define IO_SATA_BROKEN_MSG_ADDR_HI     0x5c
 #define SATA_INITI_D2H_STORE_ADDR_LO   0x60
 #define TX_HARDRST_MSK          (0x1 << TX_HARDRST_OFF)
 #define RX_IDAF_DWORD0                 (PORT_BASE + 0xc4)
 #define RXOP_CHECK_CFG_H               (PORT_BASE + 0xfc)
+#define STP_LINK_TIMER                 (PORT_BASE + 0x120)
 #define SAS_SSP_CON_TIMER_CFG          (PORT_BASE + 0x134)
 #define SAS_SMP_CON_TIMER_CFG          (PORT_BASE + 0x138)
 #define SAS_STP_CON_TIMER_CFG          (PORT_BASE + 0x13c)
 #define PHYCTRL_PHY_ENA_MSK            (PORT_BASE + 0x2bc)
 #define SL_RX_BCAST_CHK_MSK            (PORT_BASE + 0x2c0)
 #define PHYCTRL_OOB_RESTART_MSK                (PORT_BASE + 0x2c4)
+#define DMA_TX_STATUS                  (PORT_BASE + 0x2d0)
+#define DMA_TX_STATUS_BUSY_OFF         0
+#define DMA_TX_STATUS_BUSY_MSK         (0x1 << DMA_TX_STATUS_BUSY_OFF)
+#define DMA_RX_STATUS                  (PORT_BASE + 0x2e8)
+#define DMA_RX_STATUS_BUSY_OFF         0
+#define DMA_RX_STATUS_BUSY_MSK         (0x1 << DMA_RX_STATUS_BUSY_OFF)
+
+#define DEFAULT_ITCT_HW                2048 /* reset value, not reprogrammed */
+#if (HISI_SAS_MAX_DEVICES > DEFAULT_ITCT_HW)
+#error Max ITCT exceeded
+#endif
+
+#define AXI_MASTER_CFG_BASE            (0x5000)
+#define AM_CTRL_GLOBAL                 (0x0)
+#define AM_CURR_TRANS_RETURN   (0x150)
+
+#define AM_CFG_MAX_TRANS               (0x5010)
+#define AM_CFG_SINGLE_PORT_MAX_TRANS   (0x5014)
+#define AXI_CFG                                        (0x5100)
+#define AM_ROB_ECC_ERR_ADDR            (0x510c)
+#define AM_ROB_ECC_ONEBIT_ERR_ADDR_OFF 0
+#define AM_ROB_ECC_ONEBIT_ERR_ADDR_MSK (0xff << AM_ROB_ECC_ONEBIT_ERR_ADDR_OFF)
+#define AM_ROB_ECC_MULBIT_ERR_ADDR_OFF 8
+#define AM_ROB_ECC_MULBIT_ERR_ADDR_MSK (0xff << AM_ROB_ECC_MULBIT_ERR_ADDR_OFF)
 
 /* HW dma structures */
 /* Delivery queue header */
@@ -354,8 +376,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
        /* Global registers init */
        hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE,
                         (u32)((1ULL << hisi_hba->queue_count) - 1));
-       hisi_sas_write32(hisi_hba, AXI_USER1, 0x0);
-       hisi_sas_write32(hisi_hba, AXI_USER2, 0x40000060);
+       hisi_sas_write32(hisi_hba, CFG_MAX_TAG, 0xfff0400);
        hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x108);
        hisi_sas_write32(hisi_hba, CFG_1US_TIMER_TRSH, 0xd);
        hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x1);
@@ -371,15 +392,14 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
        hisi_sas_write32(hisi_hba, CHNL_PHYUPDOWN_INT_MSK, 0x0);
        hisi_sas_write32(hisi_hba, CHNL_ENT_INT_MSK, 0x0);
        hisi_sas_write32(hisi_hba, HGC_COM_INT_MSK, 0x0);
-       hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0xfff00c30);
+       hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0x0);
        hisi_sas_write32(hisi_hba, AWQOS_AWCACHE_CFG, 0xf0f0);
        hisi_sas_write32(hisi_hba, ARQOS_ARCACHE_CFG, 0xf0f0);
        for (i = 0; i < hisi_hba->queue_count; i++)
                hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK+0x4*i, 0);
 
-       hisi_sas_write32(hisi_hba, AXI_AHB_CLK_CFG, 1);
        hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1);
-       hisi_sas_write32(hisi_hba, CFG_MAX_TAG, 0xfff07fff);
+       hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE, 0x30000);
 
        for (i = 0; i < hisi_hba->n_phy; i++) {
                hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x801);
@@ -389,7 +409,6 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
                hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000);
                hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xffffffff);
                hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbff);
-               hisi_sas_phy_write32(hisi_hba, i, SL_CFG, 0x83f801fc);
                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);
@@ -398,9 +417,11 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
                hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_OOB_RESTART_MSK, 0x0);
                hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL, 0x199b4fa);
                hisi_sas_phy_write32(hisi_hba, i, SAS_SSP_CON_TIMER_CFG,
-                                    0xa0064);
+                                    0xa03e8);
                hisi_sas_phy_write32(hisi_hba, i, SAS_STP_CON_TIMER_CFG,
-                                    0xa0064);
+                                    0xa03e8);
+               hisi_sas_phy_write32(hisi_hba, i, STP_LINK_TIMER,
+                                    0x7f7a120);
        }
        for (i = 0; i < hisi_hba->queue_count; i++) {
                /* Delivery queue */
@@ -578,8 +599,6 @@ static void free_device_v3_hw(struct hisi_hba *hisi_hba,
                memset(itct, 0, sizeof(struct hisi_sas_itct));
                hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
                                 ENT_INT_SRC3_ITC_INT_MSK);
-               hisi_hba->devices[dev_id].dev_type = SAS_PHY_UNUSED;
-               hisi_hba->devices[dev_id].dev_status = HISI_SAS_DEV_NORMAL;
 
                /* clear the itct */
                hisi_sas_write32(hisi_hba, ITCT_CLR, 0);
@@ -610,8 +629,52 @@ static void dereg_device_v3_hw(struct hisi_hba *hisi_hba,
                                        1 << CFG_ABT_SET_IPTT_DONE_OFF);
 }
 
+static int reset_hw_v3_hw(struct hisi_hba *hisi_hba)
+{
+       struct device *dev = hisi_hba->dev;
+       int ret;
+       u32 val;
+
+       hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0);
+
+       /* Disable all of the PHYs */
+       hisi_sas_stop_phys(hisi_hba);
+       udelay(50);
+
+       /* Ensure axi bus idle */
+       ret = readl_poll_timeout(hisi_hba->regs + AXI_CFG, val, !val,
+                       20000, 1000000);
+       if (ret) {
+               dev_err(dev, "axi bus is not idle, ret = %d!\n", ret);
+               return -EIO;
+       }
+
+       if (ACPI_HANDLE(dev)) {
+               acpi_status s;
+
+               s = acpi_evaluate_object(ACPI_HANDLE(dev), "_RST", NULL, NULL);
+               if (ACPI_FAILURE(s)) {
+                       dev_err(dev, "Reset failed\n");
+                       return -EIO;
+               }
+       } else
+               dev_err(dev, "no reset method!\n");
+
+       return 0;
+}
+
 static int hw_init_v3_hw(struct hisi_hba *hisi_hba)
 {
+       struct device *dev = hisi_hba->dev;
+       int rc;
+
+       rc = reset_hw_v3_hw(hisi_hba);
+       if (rc) {
+               dev_err(dev, "hisi_sas_reset_hw failed, rc=%d", rc);
+               return rc;
+       }
+
+       msleep(100);
        init_reg_v3_hw(hisi_hba);
 
        return 0;
@@ -640,25 +703,12 @@ static void start_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
        enable_phy_v3_hw(hisi_hba, phy_no);
 }
 
-static void stop_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
-{
-       disable_phy_v3_hw(hisi_hba, phy_no);
-}
-
-static void start_phys_v3_hw(struct hisi_hba *hisi_hba)
-{
-       int i;
-
-       for (i = 0; i < hisi_hba->n_phy; i++)
-               start_phy_v3_hw(hisi_hba, i);
-}
-
 static void phy_hard_reset_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
 {
        struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
        u32 txid_auto;
 
-       stop_phy_v3_hw(hisi_hba, phy_no);
+       disable_phy_v3_hw(hisi_hba, phy_no);
        if (phy->identify.device_type == SAS_END_DEVICE) {
                txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO);
                hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO,
@@ -675,7 +725,17 @@ enum sas_linkrate phy_get_max_linkrate_v3_hw(void)
 
 static void phys_init_v3_hw(struct hisi_hba *hisi_hba)
 {
-       start_phys_v3_hw(hisi_hba);
+       int i;
+
+       for (i = 0; i < hisi_hba->n_phy; i++) {
+               struct hisi_sas_phy *phy = &hisi_hba->phy[i];
+               struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+               if (!sas_phy->phy->enabled)
+                       continue;
+
+               start_phy_v3_hw(hisi_hba, i);
+       }
 }
 
 static void sl_notify_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
@@ -928,20 +988,6 @@ err_out_req:
        return rc;
 }
 
-static int get_ncq_tag_v3_hw(struct sas_task *task, u32 *tag)
-{
-       struct ata_queued_cmd *qc = task->uldd_task;
-
-       if (qc) {
-               if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
-                       qc->tf.command == ATA_CMD_FPDMA_READ) {
-                       *tag = qc->tag;
-                       return 1;
-               }
-       }
-       return 0;
-}
-
 static int prep_ata_v3_hw(struct hisi_hba *hisi_hba,
                          struct hisi_sas_slot *slot)
 {
@@ -990,7 +1036,7 @@ static int prep_ata_v3_hw(struct hisi_hba *hisi_hba,
        hdr->dw1 = cpu_to_le32(dw1);
 
        /* dw2 */
-       if (task->ata_task.use_ncq && get_ncq_tag_v3_hw(task, &hdr_tag)) {
+       if (task->ata_task.use_ncq && hisi_sas_get_ncq_tag(task, &hdr_tag)) {
                task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
                dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF;
        }
@@ -1140,7 +1186,6 @@ end:
 
 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;
 
@@ -1161,7 +1206,7 @@ static int phy_down_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
        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;
+       return 0;
 }
 
 static void phy_bcast_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
@@ -1259,7 +1304,7 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p)
                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_RX_BCST_ACK_MSK)
                                        & (~CHL_INT0_SL_PHY_ENABLE_MSK)
                                        & (~CHL_INT0_NOT_RDY_MSK));
                }
@@ -1355,7 +1400,9 @@ slot_complete_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
        ts->resp = SAS_TASK_COMPLETE;
        if (unlikely(aborted)) {
                ts->stat = SAS_ABORTED_TASK;
+               spin_lock_irqsave(&hisi_hba->lock, flags);
                hisi_sas_slot_task_free(hisi_hba, task, slot);
+               spin_unlock_irqrestore(&hisi_hba->lock, flags);
                return -1;
        }
 
@@ -1620,6 +1667,104 @@ static int hisi_sas_v3_init(struct hisi_hba *hisi_hba)
        return 0;
 }
 
+static void phy_set_linkrate_v3_hw(struct hisi_hba *hisi_hba, int phy_no,
+               struct sas_phy_linkrates *r)
+{
+       u32 prog_phy_link_rate =
+               hisi_sas_phy_read32(hisi_hba, phy_no, PROG_PHY_LINK_RATE);
+       struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+       struct asd_sas_phy *sas_phy = &phy->sas_phy;
+       int i;
+       enum sas_linkrate min, max;
+       u32 rate_mask = 0;
+
+       if (r->maximum_linkrate == SAS_LINK_RATE_UNKNOWN) {
+               max = sas_phy->phy->maximum_linkrate;
+               min = r->minimum_linkrate;
+       } else if (r->minimum_linkrate == SAS_LINK_RATE_UNKNOWN) {
+               max = r->maximum_linkrate;
+               min = sas_phy->phy->minimum_linkrate;
+       } else
+               return;
+
+       sas_phy->phy->maximum_linkrate = max;
+       sas_phy->phy->minimum_linkrate = min;
+
+       min -= SAS_LINK_RATE_1_5_GBPS;
+       max -= SAS_LINK_RATE_1_5_GBPS;
+
+       for (i = 0; i <= max; i++)
+               rate_mask |= 1 << (i * 2);
+
+       prog_phy_link_rate &= ~0xff;
+       prog_phy_link_rate |= rate_mask;
+
+       hisi_sas_phy_write32(hisi_hba, phy_no, PROG_PHY_LINK_RATE,
+                       prog_phy_link_rate);
+
+       phy_hard_reset_v3_hw(hisi_hba, phy_no);
+}
+
+static void interrupt_disable_v3_hw(struct hisi_hba *hisi_hba)
+{
+       struct pci_dev *pdev = hisi_hba->pci_dev;
+       int i;
+
+       synchronize_irq(pci_irq_vector(pdev, 1));
+       synchronize_irq(pci_irq_vector(pdev, 2));
+       synchronize_irq(pci_irq_vector(pdev, 11));
+       for (i = 0; i < hisi_hba->queue_count; i++) {
+               hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK + 0x4 * i, 0x1);
+               synchronize_irq(pci_irq_vector(pdev, i + 16));
+       }
+
+       hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0xffffffff);
+       hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0xffffffff);
+       hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xffffffff);
+       hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0xffffffff);
+
+       for (i = 0; i < hisi_hba->n_phy; i++) {
+               hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xffffffff);
+               hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0xffffffff);
+               hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_NOT_RDY_MSK, 0x1);
+               hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_PHY_ENA_MSK, 0x1);
+               hisi_sas_phy_write32(hisi_hba, i, SL_RX_BCAST_CHK_MSK, 0x1);
+       }
+}
+
+static u32 get_phys_state_v3_hw(struct hisi_hba *hisi_hba)
+{
+       return hisi_sas_read32(hisi_hba, PHY_STATE);
+}
+
+static int soft_reset_v3_hw(struct hisi_hba *hisi_hba)
+{
+       struct device *dev = hisi_hba->dev;
+       int rc;
+       u32 status;
+
+       interrupt_disable_v3_hw(hisi_hba);
+       hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);
+
+       hisi_sas_stop_phys(hisi_hba);
+
+       mdelay(10);
+
+       hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE + AM_CTRL_GLOBAL, 0x1);
+
+       /* wait until bus idle */
+       rc = readl_poll_timeout(hisi_hba->regs + AXI_MASTER_CFG_BASE +
+               AM_CURR_TRANS_RETURN, status, status == 0x3, 10, 100);
+       if (rc) {
+               dev_err(dev, "axi bus is not idle, rc = %d\n", rc);
+               return rc;
+       }
+
+       hisi_sas_init_mem(hisi_hba);
+
+       return hw_init_v3_hw(hisi_hba);
+}
+
 static const struct hisi_sas_hw hisi_sas_v3_hw = {
        .hw_init = hisi_sas_v3_init,
        .setup_itct = setup_itct_v3_hw,
@@ -1636,11 +1781,14 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = {
        .start_delivery = start_delivery_v3_hw,
        .slot_complete = slot_complete_v3_hw,
        .phys_init = phys_init_v3_hw,
-       .phy_enable = enable_phy_v3_hw,
+       .phy_start = start_phy_v3_hw,
        .phy_disable = disable_phy_v3_hw,
        .phy_hard_reset = phy_hard_reset_v3_hw,
        .phy_get_max_linkrate = phy_get_max_linkrate_v3_hw,
+       .phy_set_linkrate = phy_set_linkrate_v3_hw,
        .dereg_device = dereg_device_v3_hw,
+       .soft_reset = soft_reset_v3_hw,
+       .get_phys_state = get_phys_state_v3_hw,
 };
 
 static struct Scsi_Host *
@@ -1651,8 +1799,10 @@ hisi_sas_shost_alloc_pci(struct pci_dev *pdev)
        struct device *dev = &pdev->dev;
 
        shost = scsi_host_alloc(hisi_sas_sht, sizeof(*hisi_hba));
-       if (!shost)
-               goto err_out;
+       if (!shost) {
+               dev_err(dev, "shost alloc failed\n");
+               return NULL;
+       }
        hisi_hba = shost_priv(shost);
 
        hisi_hba->hw = &hisi_sas_v3_hw;
@@ -1673,6 +1823,7 @@ hisi_sas_shost_alloc_pci(struct pci_dev *pdev)
 
        return shost;
 err_out:
+       scsi_host_put(shost);
        dev_err(dev, "shost alloc failed\n");
        return NULL;
 }
@@ -1781,7 +1932,7 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 err_out_register_ha:
        scsi_remove_host(shost);
 err_out_ha:
-       kfree(shost);
+       scsi_host_put(shost);
 err_out_regions:
        pci_release_regions(pdev);
 err_out_disable_device:
@@ -1801,6 +1952,7 @@ hisi_sas_v3_destroy_irqs(struct pci_dev *pdev, struct hisi_hba *hisi_hba)
                struct hisi_sas_cq *cq = &hisi_hba->cq[i];
 
                free_irq(pci_irq_vector(pdev, i+16), cq);
+               tasklet_kill(&cq->tasklet);
        }
        pci_free_irq_vectors(pdev);
 }
@@ -1810,14 +1962,16 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev)
        struct device *dev = &pdev->dev;
        struct sas_ha_struct *sha = dev_get_drvdata(dev);
        struct hisi_hba *hisi_hba = sha->lldd_ha;
+       struct Scsi_Host *shost = sha->core.shost;
 
        sas_unregister_ha(sha);
        sas_remove_host(sha->core.shost);
 
-       hisi_sas_free(hisi_hba);
        hisi_sas_v3_destroy_irqs(pdev, hisi_hba);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
+       hisi_sas_free(hisi_hba);
+       scsi_host_put(shost);
 }
 
 enum {
@@ -1839,7 +1993,6 @@ static struct pci_driver sas_v3_pci_driver = {
 
 module_pci_driver(sas_v3_pci_driver);
 
-MODULE_VERSION(DRV_VERSION);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
 MODULE_DESCRIPTION("HISILICON SAS controller v3 hw driver based on pci device");