]> err.no Git - linux-2.6/blobdiff - drivers/ata/sata_mv.c
sata_mv ncq Enable NCQ operation
[linux-2.6] / drivers / ata / sata_mv.c
index c60255810e68d787b1686a0a65b2630fd0e1c90f..817595cfc2f7ab7435bf9ded8ccd4a8912b300b4 100644 (file)
@@ -107,14 +107,12 @@ enum {
 
        /* CRQB needs alignment on a 1KB boundary. Size == 1KB
         * CRPB needs alignment on a 256B boundary. Size == 256B
-        * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB
         * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B
         */
        MV_CRQB_Q_SZ            = (32 * MV_MAX_Q_DEPTH),
        MV_CRPB_Q_SZ            = (8 * MV_MAX_Q_DEPTH),
-       MV_MAX_SG_CT            = 176,
+       MV_MAX_SG_CT            = 256,
        MV_SG_TBL_SZ            = (16 * MV_MAX_SG_CT),
-       MV_PORT_PRIV_DMA_SZ     = (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ),
 
        MV_PORTS_PER_HC         = 4,
        /* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
@@ -400,8 +398,8 @@ struct mv_port_priv {
        dma_addr_t              crqb_dma;
        struct mv_crpb          *crpb;
        dma_addr_t              crpb_dma;
-       struct mv_sg            *sg_tbl;
-       dma_addr_t              sg_tbl_dma;
+       struct mv_sg            *sg_tbl[MV_MAX_Q_DEPTH];
+       dma_addr_t              sg_tbl_dma[MV_MAX_Q_DEPTH];
 
        unsigned int            req_idx;
        unsigned int            resp_idx;
@@ -421,6 +419,14 @@ struct mv_host_priv {
        u32                     irq_cause_ofs;
        u32                     irq_mask_ofs;
        u32                     unmask_all_irqs;
+       /*
+        * These consistent DMA memory pools give us guaranteed
+        * alignment for hardware-accessed data structures,
+        * and less memory waste in accomplishing the alignment.
+        */
+       struct dma_pool         *crqb_pool;
+       struct dma_pool         *crpb_pool;
+       struct dma_pool         *sg_tbl_pool;
 };
 
 struct mv_hw_ops {
@@ -449,6 +455,7 @@ static void mv_error_handler(struct ata_port *ap);
 static void mv_post_int_cmd(struct ata_queued_cmd *qc);
 static void mv_eh_freeze(struct ata_port *ap);
 static void mv_eh_thaw(struct ata_port *ap);
+static void mv6_dev_config(struct ata_device *dev);
 static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 
 static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
@@ -476,6 +483,10 @@ static void mv_edma_cfg(struct mv_port_priv *pp, struct mv_host_priv *hpriv,
                        void __iomem *port_mmio, int want_ncq);
 static int __mv_stop_dma(struct ata_port *ap);
 
+/* .sg_tablesize is (MV_MAX_SG_CT / 2) in the structures below
+ * because we have to allow room for worst case splitting of
+ * PRDs for 64K boundaries in mv_fill_sg().
+ */
 static struct scsi_host_template mv5_sht = {
        .module                 = THIS_MODULE,
        .name                   = DRV_NAME,
@@ -499,7 +510,8 @@ static struct scsi_host_template mv6_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
-       .can_queue              = ATA_DEF_QUEUE,
+       .change_queue_depth     = ata_scsi_change_queue_depth,
+       .can_queue              = MV_MAX_Q_DEPTH - 1,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = MV_MAX_SG_CT / 2,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
@@ -541,6 +553,7 @@ static const struct ata_port_operations mv5_ops = {
 };
 
 static const struct ata_port_operations mv6_ops = {
+       .dev_config             = mv6_dev_config,
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -560,6 +573,7 @@ static const struct ata_port_operations mv6_ops = {
        .post_internal_cmd      = mv_post_int_cmd,
        .freeze                 = mv_eh_freeze,
        .thaw                   = mv_eh_thaw,
+       .qc_defer               = ata_std_qc_defer,
 
        .scr_read               = mv_scr_read,
        .scr_write              = mv_scr_write,
@@ -588,6 +602,7 @@ static const struct ata_port_operations mv_iie_ops = {
        .post_internal_cmd      = mv_post_int_cmd,
        .freeze                 = mv_eh_freeze,
        .thaw                   = mv_eh_thaw,
+       .qc_defer               = ata_std_qc_defer,
 
        .scr_read               = mv_scr_read,
        .scr_write              = mv_scr_write,
@@ -616,26 +631,29 @@ static const struct ata_port_info mv_port_info[] = {
                .port_ops       = &mv5_ops,
        },
        {  /* chip_604x */
-               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS,
+               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+                                 ATA_FLAG_NCQ,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv6_ops,
        },
        {  /* chip_608x */
                .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
-                                 MV_FLAG_DUAL_HC,
+                                 ATA_FLAG_NCQ | MV_FLAG_DUAL_HC,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv6_ops,
        },
        {  /* chip_6042 */
-               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS,
+               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+                                 ATA_FLAG_NCQ,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv_iie_ops,
        },
        {  /* chip_7042 */
-               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS,
+               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+                                 ATA_FLAG_NCQ,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv_iie_ops,
@@ -1054,6 +1072,17 @@ static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
                return -EINVAL;
 }
 
+static void mv6_dev_config(struct ata_device *adev)
+{
+       /*
+        * We don't have hob_nsect when doing NCQ commands on Gen-II.
+        * See mv_qc_prep() for more info.
+        */
+       if (adev->flags & ATA_DFLAG_NCQ)
+               if (adev->max_sectors > ATA_MAX_SECTORS)
+                       adev->max_sectors = ATA_MAX_SECTORS;
+}
+
 static void mv_edma_cfg(struct mv_port_priv *pp, struct mv_host_priv *hpriv,
                        void __iomem *port_mmio, int want_ncq)
 {
@@ -1084,6 +1113,35 @@ static void mv_edma_cfg(struct mv_port_priv *pp, struct mv_host_priv *hpriv,
        writelfl(cfg, port_mmio + EDMA_CFG_OFS);
 }
 
+static void mv_port_free_dma_mem(struct ata_port *ap)
+{
+       struct mv_host_priv *hpriv = ap->host->private_data;
+       struct mv_port_priv *pp = ap->private_data;
+       int tag;
+
+       if (pp->crqb) {
+               dma_pool_free(hpriv->crqb_pool, pp->crqb, pp->crqb_dma);
+               pp->crqb = NULL;
+       }
+       if (pp->crpb) {
+               dma_pool_free(hpriv->crpb_pool, pp->crpb, pp->crpb_dma);
+               pp->crpb = NULL;
+       }
+       /*
+        * For GEN_I, there's no NCQ, so we have only a single sg_tbl.
+        * For later hardware, we have one unique sg_tbl per NCQ tag.
+        */
+       for (tag = 0; tag < MV_MAX_Q_DEPTH; ++tag) {
+               if (pp->sg_tbl[tag]) {
+                       if (tag == 0 || !IS_GEN_I(hpriv))
+                               dma_pool_free(hpriv->sg_tbl_pool,
+                                             pp->sg_tbl[tag],
+                                             pp->sg_tbl_dma[tag]);
+                       pp->sg_tbl[tag] = NULL;
+               }
+       }
+}
+
 /**
  *      mv_port_start - Port specific init/start routine.
  *      @ap: ATA channel to manipulate
@@ -1100,51 +1158,47 @@ static int mv_port_start(struct ata_port *ap)
        struct mv_host_priv *hpriv = ap->host->private_data;
        struct mv_port_priv *pp;
        void __iomem *port_mmio = mv_ap_base(ap);
-       void *mem;
-       dma_addr_t mem_dma;
        unsigned long flags;
-       int rc;
+       int tag, rc;
 
        pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
        if (!pp)
                return -ENOMEM;
-
-       mem = dmam_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma,
-                                 GFP_KERNEL);
-       if (!mem)
-               return -ENOMEM;
-       memset(mem, 0, MV_PORT_PRIV_DMA_SZ);
+       ap->private_data = pp;
 
        rc = ata_pad_alloc(ap, dev);
        if (rc)
                return rc;
 
-       /* First item in chunk of DMA memory:
-        * 32-slot command request table (CRQB), 32 bytes each in size
-        */
-       pp->crqb = mem;
-       pp->crqb_dma = mem_dma;
-       mem += MV_CRQB_Q_SZ;
-       mem_dma += MV_CRQB_Q_SZ;
+       pp->crqb = dma_pool_alloc(hpriv->crqb_pool, GFP_KERNEL, &pp->crqb_dma);
+       if (!pp->crqb)
+               return -ENOMEM;
+       memset(pp->crqb, 0, MV_CRQB_Q_SZ);
 
-       /* Second item:
-        * 32-slot command response table (CRPB), 8 bytes each in size
-        */
-       pp->crpb = mem;
-       pp->crpb_dma = mem_dma;
-       mem += MV_CRPB_Q_SZ;
-       mem_dma += MV_CRPB_Q_SZ;
+       pp->crpb = dma_pool_alloc(hpriv->crpb_pool, GFP_KERNEL, &pp->crpb_dma);
+       if (!pp->crpb)
+               goto out_port_free_dma_mem;
+       memset(pp->crpb, 0, MV_CRPB_Q_SZ);
 
-       /* Third item:
-        * Table of scatter-gather descriptors (ePRD), 16 bytes each
+       /*
+        * For GEN_I, there's no NCQ, so we only allocate a single sg_tbl.
+        * For later hardware, we need one unique sg_tbl per NCQ tag.
         */
-       pp->sg_tbl = mem;
-       pp->sg_tbl_dma = mem_dma;
+       for (tag = 0; tag < MV_MAX_Q_DEPTH; ++tag) {
+               if (tag == 0 || !IS_GEN_I(hpriv)) {
+                       pp->sg_tbl[tag] = dma_pool_alloc(hpriv->sg_tbl_pool,
+                                             GFP_KERNEL, &pp->sg_tbl_dma[tag]);
+                       if (!pp->sg_tbl[tag])
+                               goto out_port_free_dma_mem;
+               } else {
+                       pp->sg_tbl[tag]     = pp->sg_tbl[0];
+                       pp->sg_tbl_dma[tag] = pp->sg_tbl_dma[0];
+               }
+       }
 
        spin_lock_irqsave(&ap->host->lock, flags);
 
        mv_edma_cfg(pp, hpriv, port_mmio, 0);
-
        mv_set_edma_ptrs(port_mmio, hpriv, pp);
 
        spin_unlock_irqrestore(&ap->host->lock, flags);
@@ -1153,8 +1207,11 @@ static int mv_port_start(struct ata_port *ap)
         * we'll be unable to send non-data, PIO, etc due to restricted access
         * to shadow regs.
         */
-       ap->private_data = pp;
        return 0;
+
+out_port_free_dma_mem:
+       mv_port_free_dma_mem(ap);
+       return -ENOMEM;
 }
 
 /**
@@ -1169,6 +1226,7 @@ static int mv_port_start(struct ata_port *ap)
 static void mv_port_stop(struct ata_port *ap)
 {
        mv_stop_dma(ap);
+       mv_port_free_dma_mem(ap);
 }
 
 /**
@@ -1187,7 +1245,7 @@ static void mv_fill_sg(struct ata_queued_cmd *qc)
        struct mv_sg *mv_sg, *last_sg = NULL;
        unsigned int si;
 
-       mv_sg = pp->sg_tbl;
+       mv_sg = pp->sg_tbl[qc->tag];
        for_each_sg(qc->sg, sg, qc->n_elem, si) {
                dma_addr_t addr = sg_dma_address(sg);
                u32 sg_len = sg_dma_len(sg);
@@ -1243,7 +1301,8 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
        u16 flags = 0;
        unsigned in_index;
 
-       if (qc->tf.protocol != ATA_PROT_DMA)
+       if ((qc->tf.protocol != ATA_PROT_DMA) &&
+           (qc->tf.protocol != ATA_PROT_NCQ))
                return;
 
        /* Fill in command request block
@@ -1257,9 +1316,9 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
        in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
 
        pp->crqb[in_index].sg_addr =
-               cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
+               cpu_to_le32(pp->sg_tbl_dma[qc->tag] & 0xffffffff);
        pp->crqb[in_index].sg_addr_hi =
-               cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
+               cpu_to_le32((pp->sg_tbl_dma[qc->tag] >> 16) >> 16);
        pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags);
 
        cw = &pp->crqb[in_index].ata_cmd[0];
@@ -1279,13 +1338,11 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
        case ATA_CMD_WRITE_FUA_EXT:
                mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0);
                break;
-#ifdef LIBATA_NCQ              /* FIXME: remove this line when NCQ added */
        case ATA_CMD_FPDMA_READ:
        case ATA_CMD_FPDMA_WRITE:
                mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0);
                mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0);
                break;
-#endif                         /* FIXME: remove this line when NCQ added */
        default:
                /* The only other commands EDMA supports in non-queued and
                 * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none
@@ -1334,7 +1391,8 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
        unsigned in_index;
        u32 flags = 0;
 
-       if (qc->tf.protocol != ATA_PROT_DMA)
+       if ((qc->tf.protocol != ATA_PROT_DMA) &&
+           (qc->tf.protocol != ATA_PROT_NCQ))
                return;
 
        /* Fill in Gen IIE command request block
@@ -1350,8 +1408,8 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
        in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
 
        crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
-       crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
-       crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
+       crqb->addr = cpu_to_le32(pp->sg_tbl_dma[qc->tag] & 0xffffffff);
+       crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma[qc->tag] >> 16) >> 16);
        crqb->flags = cpu_to_le32(flags);
 
        tf = &qc->tf;
@@ -1400,7 +1458,8 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
        struct mv_port_priv *pp = ap->private_data;
        u32 in_index;
 
-       if (qc->tf.protocol != ATA_PROT_DMA) {
+       if ((qc->tf.protocol != ATA_PROT_DMA) &&
+           (qc->tf.protocol != ATA_PROT_NCQ)) {
                /* We're about to send a non-EDMA capable command to the
                 * port.  Turn off EDMA so there won't be problems accessing
                 * shadow block, etc registers.
@@ -1411,12 +1470,6 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
 
        mv_start_dma(ap, port_mmio, pp, qc->tf.protocol);
 
-       in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
-
-       /* until we do queuing, the queue should be empty at this point */
-       WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
-               >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
-
        pp->req_idx++;
 
        in_index = (pp->req_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_REQ_Q_PTR_SHIFT;
@@ -1590,13 +1643,12 @@ static void mv_intr_edma(struct ata_port *ap)
 
                qc = ata_qc_from_tag(ap, tag);
 
-               /* lower 8 bits of status are EDMA_ERR_IRQ_CAUSE_OFS
-                * bits (WARNING: might not necessarily be associated
-                * with this command), which -should- be clear
-                * if all is well
+               /* For non-NCQ mode, the lower 8 bits of status
+                * are from EDMA_ERR_IRQ_CAUSE_OFS,
+                * which should be zero if all went well.
                 */
                status = le16_to_cpu(pp->crpb[out_index].flags);
-               if (unlikely(status & 0xff)) {
+               if ((status & 0xff) && !(pp->pp_flags & MV_PP_FLAG_NCQ_EN)) {
                        mv_err_intr(ap, qc);
                        return;
                }
@@ -2753,6 +2805,26 @@ static void mv_print_info(struct ata_host *host)
               scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
 }
 
+static int mv_create_dma_pools(struct mv_host_priv *hpriv, struct device *dev)
+{
+       hpriv->crqb_pool   = dmam_pool_create("crqb_q", dev, MV_CRQB_Q_SZ,
+                                                            MV_CRQB_Q_SZ, 0);
+       if (!hpriv->crqb_pool)
+               return -ENOMEM;
+
+       hpriv->crpb_pool   = dmam_pool_create("crpb_q", dev, MV_CRPB_Q_SZ,
+                                                            MV_CRPB_Q_SZ, 0);
+       if (!hpriv->crpb_pool)
+               return -ENOMEM;
+
+       hpriv->sg_tbl_pool = dmam_pool_create("sg_tbl", dev, MV_SG_TBL_SZ,
+                                                            MV_SG_TBL_SZ, 0);
+       if (!hpriv->sg_tbl_pool)
+               return -ENOMEM;
+
+       return 0;
+}
+
 /**
  *      mv_init_one - handle a positive probe of a Marvell host
  *      @pdev: PCI device found
@@ -2798,6 +2870,10 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                return rc;
 
+       rc = mv_create_dma_pools(hpriv, &pdev->dev);
+       if (rc)
+               return rc;
+
        /* initialize adapter */
        rc = mv_init_host(host, board_idx);
        if (rc)