scsi: hisi_sas: Introduce hisi_sas_phy_set_linkrate()
[sfrench/cifs-2.6.git] / drivers / scsi / hisi_sas / hisi_sas_v3_hw.c
index 5c0d9683630bc0f5d9ca54d18d233085736431e7..0a80a39eccddc698eef08d80069a0f3e39c82d0c 100644 (file)
 #define COMPL_Q_0_RD_PTR               0x4f0
 #define AWQOS_AWCACHE_CFG      0xc84
 #define ARQOS_ARCACHE_CFG      0xc88
+#define HILINK_ERR_DFX         0xe04
 
 /* phy registers requiring init */
 #define PORT_BASE                      (0x2000)
 #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_RX_INVLD_DW_OFF       30
 #define CHL_INT2_STP_LINK_TIMEOUT_OFF  31
 #define CHL_INT0_MSK                   (PORT_BASE + 0x1c0)
 #define CHL_INT1_MSK                   (PORT_BASE + 0x1c4)
@@ -351,10 +353,11 @@ struct hisi_sas_err_record_v3 {
 #define DIR_TO_DEVICE 2
 #define DIR_RESERVED 3
 
-#define CMD_IS_UNCONSTRAINT(cmd) \
-       ((cmd == ATA_CMD_READ_LOG_EXT) || \
-       (cmd == ATA_CMD_READ_LOG_DMA_EXT) || \
-       (cmd == ATA_CMD_DEV_RESET))
+#define FIS_CMD_IS_UNCONSTRAINED(fis) \
+       ((fis.command == ATA_CMD_READ_LOG_EXT) || \
+       (fis.command == ATA_CMD_READ_LOG_DMA_EXT) || \
+       ((fis.command == ATA_CMD_DEV_RESET) && \
+       ((fis.control & ATA_SRST) != 0)))
 
 static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
 {
@@ -393,6 +396,20 @@ static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba,
        return readl(regs);
 }
 
+#define hisi_sas_read32_poll_timeout(off, val, cond, delay_us,         \
+                                    timeout_us)                        \
+({                                                                     \
+       void __iomem *regs = hisi_hba->regs + off;                      \
+       readl_poll_timeout(regs, val, cond, delay_us, timeout_us);      \
+})
+
+#define hisi_sas_read32_poll_timeout_atomic(off, val, cond, delay_us,  \
+                                           timeout_us)                 \
+({                                                                     \
+       void __iomem *regs = hisi_hba->regs + off;                      \
+       readl_poll_timeout_atomic(regs, val, cond, delay_us, timeout_us);\
+})
+
 static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
 {
        struct pci_dev *pdev = hisi_hba->pci_dev;
@@ -429,7 +446,22 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
        hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1);
 
        for (i = 0; i < hisi_hba->n_phy; i++) {
-               hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x855);
+               struct hisi_sas_phy *phy = &hisi_hba->phy[i];
+               struct asd_sas_phy *sas_phy = &phy->sas_phy;
+               u32 prog_phy_link_rate = 0x800;
+
+               if (!sas_phy->phy || (sas_phy->phy->maximum_linkrate <
+                               SAS_LINK_RATE_1_5_GBPS)) {
+                       prog_phy_link_rate = 0x855;
+               } else {
+                       enum sas_linkrate max = sas_phy->phy->maximum_linkrate;
+
+                       prog_phy_link_rate =
+                               hisi_sas_get_prog_phy_linkrate_mask(max) |
+                               0x800;
+               }
+               hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE,
+                       prog_phy_link_rate);
                hisi_sas_phy_write32(hisi_hba, i, SAS_RX_TRAIN_TIMER, 0x13e80);
                hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, 0xffffffff);
                hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff);
@@ -668,8 +700,8 @@ static int reset_hw_v3_hw(struct hisi_hba *hisi_hba)
        udelay(50);
 
        /* Ensure axi bus idle */
-       ret = readl_poll_timeout(hisi_hba->regs + AXI_CFG, val, !val,
-                       20000, 1000000);
+       ret = hisi_sas_read32_poll_timeout(AXI_CFG, val, !val,
+                                          20000, 1000000);
        if (ret) {
                dev_err(dev, "axi bus is not idle, ret = %d!\n", ret);
                return -EIO;
@@ -808,42 +840,49 @@ get_free_slot_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq)
        r = hisi_sas_read32_relaxed(hisi_hba,
                                DLVRY_Q_0_RD_PTR + (queue * 0x14));
        if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
-               dev_warn(dev, "full queue=%d r=%d w=%d\n\n",
+               dev_warn(dev, "full queue=%d r=%d w=%d\n",
                                queue, r, w);
                return -EAGAIN;
        }
 
-       return 0;
+       dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS;
+
+       return w;
 }
 
 static void start_delivery_v3_hw(struct hisi_sas_dq *dq)
 {
        struct hisi_hba *hisi_hba = dq->hisi_hba;
-       int dlvry_queue = dq->slot_prep->dlvry_queue;
-       int dlvry_queue_slot = dq->slot_prep->dlvry_queue_slot;
+       struct hisi_sas_slot *s, *s1;
+       struct list_head *dq_list;
+       int dlvry_queue = dq->id;
+       int wp, count = 0;
+
+       dq_list = &dq->list;
+       list_for_each_entry_safe(s, s1, &dq->list, delivery) {
+               if (!s->ready)
+                       break;
+               count++;
+               wp = (s->dlvry_queue_slot + 1) % HISI_SAS_QUEUE_SLOTS;
+               list_del(&s->delivery);
+       }
+
+       if (!count)
+               return;
 
-       dq->wr_point = ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS;
-       hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14),
-                        dq->wr_point);
+       hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14), wp);
 }
 
-static int prep_prd_sge_v3_hw(struct hisi_hba *hisi_hba,
+static void prep_prd_sge_v3_hw(struct hisi_hba *hisi_hba,
                              struct hisi_sas_slot *slot,
                              struct hisi_sas_cmd_hdr *hdr,
                              struct scatterlist *scatter,
                              int n_elem)
 {
        struct hisi_sas_sge_page *sge_page = hisi_sas_sge_addr_mem(slot);
-       struct device *dev = hisi_hba->dev;
        struct scatterlist *sg;
        int i;
 
-       if (n_elem > HISI_SAS_SGE_PAGE_CNT) {
-               dev_err(dev, "prd err: n_elem(%d) > HISI_SAS_SGE_PAGE_CNT",
-                       n_elem);
-               return -EINVAL;
-       }
-
        for_each_sg(scatter, sg, n_elem, i) {
                struct hisi_sas_sge *entry = &sge_page->sge[i];
 
@@ -856,11 +895,9 @@ static int prep_prd_sge_v3_hw(struct hisi_hba *hisi_hba,
        hdr->prd_table_addr = cpu_to_le64(hisi_sas_sge_addr_dma(slot));
 
        hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF);
-
-       return 0;
 }
 
-static int prep_ssp_v3_hw(struct hisi_hba *hisi_hba,
+static void prep_ssp_v3_hw(struct hisi_hba *hisi_hba,
                          struct hisi_sas_slot *slot, int is_tmf,
                          struct hisi_sas_tmf_task *tmf)
 {
@@ -871,7 +908,7 @@ static int prep_ssp_v3_hw(struct hisi_hba *hisi_hba,
        struct hisi_sas_port *port = slot->port;
        struct sas_ssp_task *ssp_task = &task->ssp_task;
        struct scsi_cmnd *scsi_cmnd = ssp_task->cmd;
-       int has_data = 0, rc, priority = is_tmf;
+       int has_data = 0, priority = is_tmf;
        u8 *buf_cmd;
        u32 dw1 = 0, dw2 = 0;
 
@@ -912,12 +949,9 @@ static int prep_ssp_v3_hw(struct hisi_hba *hisi_hba,
        hdr->dw2 = cpu_to_le32(dw2);
        hdr->transfer_tags = cpu_to_le32(slot->idx);
 
-       if (has_data) {
-               rc = prep_prd_sge_v3_hw(hisi_hba, slot, hdr, task->scatter,
+       if (has_data)
+               prep_prd_sge_v3_hw(hisi_hba, slot, hdr, task->scatter,
                                        slot->n_elem);
-               if (rc)
-                       return rc;
-       }
 
        hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
        hdr->cmd_table_addr = cpu_to_le64(hisi_sas_cmd_hdr_addr_dma(slot));
@@ -944,48 +978,25 @@ static int prep_ssp_v3_hw(struct hisi_hba *hisi_hba,
                        break;
                }
        }
-
-       return 0;
 }
 
-static int prep_smp_v3_hw(struct hisi_hba *hisi_hba,
+static void prep_smp_v3_hw(struct hisi_hba *hisi_hba,
                          struct hisi_sas_slot *slot)
 {
        struct sas_task *task = slot->task;
        struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
        struct domain_device *device = task->dev;
-       struct device *dev = hisi_hba->dev;
        struct hisi_sas_port *port = slot->port;
-       struct scatterlist *sg_req, *sg_resp;
+       struct scatterlist *sg_req;
        struct hisi_sas_device *sas_dev = device->lldd_dev;
        dma_addr_t req_dma_addr;
-       unsigned int req_len, resp_len;
-       int elem, rc;
+       unsigned int req_len;
 
-       /*
-        * DMA-map SMP request, response buffers
-        */
        /* req */
        sg_req = &task->smp_task.smp_req;
-       elem = dma_map_sg(dev, sg_req, 1, DMA_TO_DEVICE);
-       if (!elem)
-               return -ENOMEM;
        req_len = sg_dma_len(sg_req);
        req_dma_addr = sg_dma_address(sg_req);
 
-       /* resp */
-       sg_resp = &task->smp_task.smp_resp;
-       elem = dma_map_sg(dev, sg_resp, 1, DMA_FROM_DEVICE);
-       if (!elem) {
-               rc = -ENOMEM;
-               goto err_out_req;
-       }
-       resp_len = sg_dma_len(sg_resp);
-       if ((req_len & 0x3) || (resp_len & 0x3)) {
-               rc = -EINVAL;
-               goto err_out_resp;
-       }
-
        /* create header */
        /* dw0 */
        hdr->dw0 = cpu_to_le32((port->id << CMD_HDR_PORT_OFF) |
@@ -1007,18 +1018,9 @@ static int prep_smp_v3_hw(struct hisi_hba *hisi_hba,
        hdr->cmd_table_addr = cpu_to_le64(req_dma_addr);
        hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
 
-       return 0;
-
-err_out_resp:
-       dma_unmap_sg(dev, &slot->task->smp_task.smp_resp, 1,
-                    DMA_FROM_DEVICE);
-err_out_req:
-       dma_unmap_sg(dev, &slot->task->smp_task.smp_req, 1,
-                    DMA_TO_DEVICE);
-       return rc;
 }
 
-static int prep_ata_v3_hw(struct hisi_hba *hisi_hba,
+static void prep_ata_v3_hw(struct hisi_hba *hisi_hba,
                          struct hisi_sas_slot *slot)
 {
        struct sas_task *task = slot->task;
@@ -1029,7 +1031,7 @@ static int prep_ata_v3_hw(struct hisi_hba *hisi_hba,
        struct asd_sas_port *sas_port = device->port;
        struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
        u8 *buf_cmd;
-       int has_data = 0, rc = 0, hdr_tag = 0;
+       int has_data = 0, hdr_tag = 0;
        u32 dw1 = 0, dw2 = 0;
 
        hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF);
@@ -1060,7 +1062,7 @@ static int prep_ata_v3_hw(struct hisi_hba *hisi_hba,
                << CMD_HDR_FRAME_TYPE_OFF;
        dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF;
 
-       if (CMD_IS_UNCONSTRAINT(task->ata_task.fis.command))
+       if (FIS_CMD_IS_UNCONSTRAINED(task->ata_task.fis))
                dw1 |= 1 << CMD_HDR_UNCON_CMD_OFF;
 
        hdr->dw1 = cpu_to_le32(dw1);
@@ -1078,12 +1080,9 @@ static int prep_ata_v3_hw(struct hisi_hba *hisi_hba,
        /* dw3 */
        hdr->transfer_tags = cpu_to_le32(slot->idx);
 
-       if (has_data) {
-               rc = prep_prd_sge_v3_hw(hisi_hba, slot, hdr, task->scatter,
+       if (has_data)
+               prep_prd_sge_v3_hw(hisi_hba, slot, hdr, task->scatter,
                                        slot->n_elem);
-               if (rc)
-                       return rc;
-       }
 
        hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
        hdr->cmd_table_addr = cpu_to_le64(hisi_sas_cmd_hdr_addr_dma(slot));
@@ -1095,11 +1094,9 @@ static int prep_ata_v3_hw(struct hisi_hba *hisi_hba,
                task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
        /* fill in command FIS */
        memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
-
-       return 0;
 }
 
-static int prep_abort_v3_hw(struct hisi_hba *hisi_hba,
+static void prep_abort_v3_hw(struct hisi_hba *hisi_hba,
                struct hisi_sas_slot *slot,
                int device_id, int abort_flag, int tag_to_abort)
 {
@@ -1124,7 +1121,6 @@ static int prep_abort_v3_hw(struct hisi_hba *hisi_hba,
        hdr->dw7 = cpu_to_le32(tag_to_abort << CMD_HDR_ABORT_IPTT_OFF);
        hdr->transfer_tags = cpu_to_le32(slot->idx);
 
-       return 0;
 }
 
 static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
@@ -1315,14 +1311,10 @@ 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;
+       struct pci_dev *pci_dev = hisi_hba->pci_dev;
+       u32 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;
 
@@ -1385,8 +1377,28 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p)
 
                        hisi_sas_phy_write32(hisi_hba, phy_no,
                                             CHL_INT2, irq_value2);
-               }
 
+                       if ((irq_value2 & BIT(CHL_INT2_RX_INVLD_DW_OFF)) &&
+                           (pci_dev->revision == 0x20)) {
+                               u32 reg_value;
+                               int rc;
+
+                               rc = hisi_sas_read32_poll_timeout_atomic(
+                                       HILINK_ERR_DFX, reg_value,
+                                       !((reg_value >> 8) & BIT(phy_no)),
+                                       1000, 10000);
+                               if (rc) {
+                                       disable_phy_v3_hw(hisi_hba, phy_no);
+                                       hisi_sas_phy_write32(hisi_hba, phy_no,
+                                               CHL_INT2,
+                                               BIT(CHL_INT2_RX_INVLD_DW_OFF));
+                                       hisi_sas_phy_read32(hisi_hba, phy_no,
+                                               ERR_CNT_INVLD_DW);
+                                       mdelay(1);
+                                       enable_phy_v3_hw(hisi_hba, phy_no);
+                               }
+                       }
+               }
 
                if (irq_msk & (2 << (phy_no * 4)) && irq_value0) {
                        hisi_sas_phy_write32(hisi_hba, phy_no,
@@ -1399,8 +1411,6 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p)
                phy_no++;
        }
 
-       hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, ent_tmp);
-
        return IRQ_HANDLED;
 }
 
@@ -1869,39 +1879,12 @@ static int hisi_sas_v3_init(struct hisi_hba *hisi_hba)
 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;
-
-       max -= SAS_LINK_RATE_1_5_GBPS;
+       enum sas_linkrate max = r->maximum_linkrate;
+       u32 prog_phy_link_rate = 0x800;
 
-       for (i = 0; i <= max; i++)
-               rate_mask |= 1 << (i * 2);
-
-       prog_phy_link_rate &= ~0xff;
-       prog_phy_link_rate |= rate_mask;
-
-       disable_phy_v3_hw(hisi_hba, phy_no);
-       msleep(100);
+       prog_phy_link_rate |= hisi_sas_get_prog_phy_linkrate_mask(max);
        hisi_sas_phy_write32(hisi_hba, phy_no, PROG_PHY_LINK_RATE,
-                       prog_phy_link_rate);
-       start_phy_v3_hw(hisi_hba, phy_no);
+                            prog_phy_link_rate);
 }
 
 static void interrupt_disable_v3_hw(struct hisi_hba *hisi_hba)
@@ -1978,8 +1961,9 @@ static int soft_reset_v3_hw(struct hisi_hba *hisi_hba)
        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);
+       rc = hisi_sas_read32_poll_timeout(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;
@@ -2372,7 +2356,6 @@ static int hisi_sas_v3_suspend(struct pci_dev *pdev, pm_message_t state)
        u32 device_state, status;
        int rc;
        u32 reg_val;
-       unsigned long flags;
 
        if (!pdev->pm_cap) {
                dev_err(dev, "PCI PM not supported\n");
@@ -2397,8 +2380,9 @@ static int hisi_sas_v3_suspend(struct pci_dev *pdev, pm_message_t state)
                AM_CTRL_GLOBAL, reg_val);
 
        /* wait until bus idle */
-       rc = readl_poll_timeout(hisi_hba->regs + AXI_MASTER_CFG_BASE +
-               AM_CURR_TRANS_RETURN, status, status == 0x3, 10, 100);
+       rc = hisi_sas_read32_poll_timeout(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);
                clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
@@ -2416,9 +2400,7 @@ static int hisi_sas_v3_suspend(struct pci_dev *pdev, pm_message_t state)
        pci_disable_device(pdev);
        pci_set_power_state(pdev, device_state);
 
-       spin_lock_irqsave(&hisi_hba->lock, flags);
        hisi_sas_release_tasks(hisi_hba);
-       spin_unlock_irqrestore(&hisi_hba->lock, flags);
 
        sas_suspend_ha(sha);
        return 0;