* [PATCH] sata_mv: enable ATAPI DMA for GEN_IIE chips
@ 2009-02-04 18:05 Mark Lord
2009-02-05 15:33 ` Mark Lord
0 siblings, 1 reply; 4+ messages in thread
From: Mark Lord @ 2009-02-04 18:05 UTC (permalink / raw)
To: Jeff Garzik, IDE/ATA development list
Enable ATAPI DMA transfers on GEN_IIE chips (6042/7042/SOC).
This also gets rid of any need for mv_mode_filter().
Signed-off-by: Mark Lord <mlord@pobox.com>
--- old/drivers/ata/sata_mv.c 2009-02-03 14:58:13.000000000 -0500
+++ linux/drivers/ata/sata_mv.c 2009-02-04 12:58:52.000000000 -0500
@@ -345,7 +345,7 @@
EDMA_ARB_CFG_OFS = 0x38,
EDMA_HALTCOND_OFS = 0x60, /* GenIIe halt conditions */
-
+ EDMA_UNKNOWN_RSVD_OFS = 0x6C, /* GenIIe unknown/reserved */
BMDMA_CMD_OFS = 0x224, /* bmdma command register */
BMDMA_STATUS_OFS = 0x228, /* bmdma status register */
@@ -551,8 +551,6 @@
static void mv_process_crpb_entries(struct ata_port *ap,
struct mv_port_priv *pp);
-static unsigned long mv_mode_filter(struct ata_device *dev,
- unsigned long xfer_mask);
static void mv_sff_irq_clear(struct ata_port *ap);
static int mv_check_atapi_dma(struct ata_queued_cmd *qc);
static void mv_bmdma_setup(struct ata_queued_cmd *qc);
@@ -614,7 +612,6 @@
.bmdma_start = mv_bmdma_start,
.bmdma_stop = mv_bmdma_stop,
.bmdma_status = mv_bmdma_status,
- .mode_filter = mv_mode_filter,
};
static struct ata_port_operations mv_iie_ops = {
@@ -1260,6 +1257,25 @@
writelfl(cfg, port_mmio + EDMA_CFG_OFS);
}
+/**
+ * mv_bmdma_enable - set a magic bit on GEN_IIE to allow bmdma
+ * @ap: Port being initialized
+ */
+static void mv_bmdma_enable(struct ata_port *ap)
+{
+ struct mv_host_priv *hpriv = ap->host->private_data;
+
+ if (IS_GEN_IIE(hpriv)) {
+ void __iomem *port_mmio = mv_ap_base(ap);
+ /*
+ * Some magic is required to get non-EDMA DMA to work:
+ */
+ u32 rsvd = readl(port_mmio + EDMA_UNKNOWN_RSVD_OFS);
+ if (!(rsvd & 1))
+ writel(rsvd | 1, port_mmio + EDMA_UNKNOWN_RSVD_OFS);
+ }
+}
+
static void mv_port_free_dma_mem(struct ata_port *ap)
{
struct mv_host_priv *hpriv = ap->host->private_data;
@@ -1340,6 +1356,7 @@
}
}
mv_edma_cfg(ap, 0, 0);
+ mv_bmdma_enable(ap);
return 0;
out_port_free_dma_mem:
@@ -1417,26 +1434,6 @@
}
/**
- * mv_mode_filter - Allow ATAPI DMA only on GenII chips.
- * @dev: device whose xfer modes are being configured.
- *
- * Only the GenII hardware can use DMA with ATAPI drives.
- */
-static unsigned long mv_mode_filter(struct ata_device *adev,
- unsigned long xfer_mask)
-{
- if (adev->class == ATA_DEV_ATAPI) {
- struct mv_host_priv *hpriv = adev->link->ap->host->private_data;
- if (!IS_GEN_II(hpriv)) {
- xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
- ata_dev_printk(adev, KERN_INFO,
- "ATAPI DMA not supported on this chipset\n");
- }
- }
- return xfer_mask;
-}
-
-/**
* mv_sff_irq_clear - Clear hardware interrupt after DMA.
* @ap: Port associated with this ATA transaction.
*
@@ -2997,7 +2994,7 @@
}
} while (sstatus != 0x0 && sstatus != 0x113 && sstatus != 0x123);
mv_edma_cfg(ap, 0, 0);
-
+ mv_bmdma_enable(ap);
return rc;
}
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH] sata_mv: enable ATAPI DMA for GEN_IIE chips 2009-02-04 18:05 [PATCH] sata_mv: enable ATAPI DMA for GEN_IIE chips Mark Lord @ 2009-02-05 15:33 ` Mark Lord 2009-02-05 15:36 ` [PATCH 01/02] sata_mv: cache frequently read port registers Mark Lord 0 siblings, 1 reply; 4+ messages in thread From: Mark Lord @ 2009-02-05 15:33 UTC (permalink / raw) To: Jeff Garzik, IDE/ATA development list Mark Lord wrote: > Enable ATAPI DMA transfers on GEN_IIE chips (6042/7042/SOC). > This also gets rid of any need for mv_mode_filter(). > > Signed-off-by: Mark Lord <mlord@pobox.com> > > --- old/drivers/ata/sata_mv.c 2009-02-03 14:58:13.000000000 -0500 > +++ linux/drivers/ata/sata_mv.c 2009-02-04 12:58:52.000000000 -0500 > @@ -345,7 +345,7 @@ > EDMA_ARB_CFG_OFS = 0x38, > > EDMA_HALTCOND_OFS = 0x60, /* GenIIe halt conditions */ > - > + EDMA_UNKNOWN_RSVD_OFS = 0x6C, /* GenIIe unknown/reserved */ .. Scuttle that patch. I'll re-issue a (v2) version shortly. -ml ^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 01/02] sata_mv: cache frequently read port registers 2009-02-05 15:33 ` Mark Lord @ 2009-02-05 15:36 ` Mark Lord 2009-02-05 15:37 ` [PATCH 02/02] sata_mv: enable ATAPI DMA for GEN_IIE (v2) Mark Lord 0 siblings, 1 reply; 4+ messages in thread From: Mark Lord @ 2009-02-05 15:36 UTC (permalink / raw) To: Jeff Garzik, IDE/ATA development list; +Cc: Grant Grundler Maintain a local (mv_port_priv) cache of frequently accessed registers, to avoid having to re-read them (very slow) on every transistion between EDMA and non-EDMA modes. This speeds up things like flushing the drive write cache, and anything using basic DMA transfers. Signed-off-by: Mark Lord <mlord@pobox.com> --- old/drivers/ata/sata_mv.c 2009-02-05 10:16:58.000000000 -0500 +++ linux/drivers/ata/sata_mv.c 2009-02-05 10:14:43.000000000 -0500 @@ -438,6 +438,17 @@ __le32 reserved; }; +/* + * We keep a local cache of a few frequently accessed port + * registers here, to avoid having to read them (very slow) + * when switching between EDMA and non-EDMA modes. + */ +struct mv_cached_regs { + u32 fiscfg; + u32 ltmode; + u32 haltcond; +}; + struct mv_port_priv { struct mv_crqb *crqb; dma_addr_t crqb_dma; @@ -450,6 +461,7 @@ unsigned int resp_idx; u32 pp_flags; + struct mv_cached_regs cached; unsigned int delayed_eh_pmp_map; }; @@ -812,6 +824,43 @@ return ((port_flags & MV_FLAG_DUAL_HC) ? 2 : 1); } +/** + * mv_save_cached_regs - (re-)initialize cached port registers + * @ap: the port whose registers we are caching + * + * Initialize the local cache of port registers, + * so that reading them over and over again can + * be avoided on the hotter paths of this driver. + * This saves a few microseconds each time we switch + * to/from EDMA mode to perform (eg.) a drive cache flush. + */ +static void mv_save_cached_regs(struct ata_port *ap) +{ + void __iomem *port_mmio = mv_ap_base(ap); + struct mv_port_priv *pp = ap->private_data; + + pp->cached.fiscfg = readl(port_mmio + FISCFG_OFS); + pp->cached.ltmode = readl(port_mmio + LTMODE_OFS); + pp->cached.haltcond = readl(port_mmio + EDMA_HALTCOND_OFS); +} + +/** + * mv_write_cached_reg - write to a cached port register + * @addr: hardware address of the register + * @old: pointer to cached value of the register + * @new: new value for the register + * + * Write a new value to a cached register, + * but only if the value is different from before. + */ +static inline void mv_write_cached_reg(void __iomem *addr, u32 *old, u32 new) +{ + if (new != *old) { + *old = new; + writel(new, addr); + } +} + static void mv_set_edma_ptrs(void __iomem *port_mmio, struct mv_host_priv *hpriv, struct mv_port_priv *pp) @@ -1159,35 +1208,33 @@ return ATA_DEFER_PORT; } -static void mv_config_fbs(void __iomem *port_mmio, int want_ncq, int want_fbs) +static void mv_config_fbs(struct ata_port *ap, int want_ncq, int want_fbs) { - u32 new_fiscfg, old_fiscfg; - u32 new_ltmode, old_ltmode; - u32 new_haltcond, old_haltcond; - - old_fiscfg = readl(port_mmio + FISCFG_OFS); - old_ltmode = readl(port_mmio + LTMODE_OFS); - old_haltcond = readl(port_mmio + EDMA_HALTCOND_OFS); - - new_fiscfg = old_fiscfg & ~(FISCFG_SINGLE_SYNC | FISCFG_WAIT_DEV_ERR); - new_ltmode = old_ltmode & ~LTMODE_BIT8; - new_haltcond = old_haltcond | EDMA_ERR_DEV; + struct mv_port_priv *pp = ap->private_data; + void __iomem *port_mmio; + + u32 fiscfg, *old_fiscfg = &pp->cached.fiscfg; + u32 ltmode, *old_ltmode = &pp->cached.ltmode; + u32 haltcond, *old_haltcond = &pp->cached.haltcond; + + ltmode = *old_ltmode & ~LTMODE_BIT8; + haltcond = *old_haltcond | EDMA_ERR_DEV; if (want_fbs) { - new_fiscfg = old_fiscfg | FISCFG_SINGLE_SYNC; - new_ltmode = old_ltmode | LTMODE_BIT8; + fiscfg = *old_fiscfg | FISCFG_SINGLE_SYNC; + ltmode = *old_ltmode | LTMODE_BIT8; if (want_ncq) - new_haltcond &= ~EDMA_ERR_DEV; + haltcond &= ~EDMA_ERR_DEV; else - new_fiscfg |= FISCFG_WAIT_DEV_ERR; + fiscfg |= FISCFG_WAIT_DEV_ERR; + } else { + fiscfg = *old_fiscfg & ~(FISCFG_SINGLE_SYNC | FISCFG_WAIT_DEV_ERR); } - if (new_fiscfg != old_fiscfg) - writelfl(new_fiscfg, port_mmio + FISCFG_OFS); - if (new_ltmode != old_ltmode) - writelfl(new_ltmode, port_mmio + LTMODE_OFS); - if (new_haltcond != old_haltcond) - writelfl(new_haltcond, port_mmio + EDMA_HALTCOND_OFS); + port_mmio = mv_ap_base(ap); + mv_write_cached_reg(port_mmio + FISCFG_OFS, old_fiscfg, fiscfg); + mv_write_cached_reg(port_mmio + LTMODE_OFS, old_ltmode, ltmode); + mv_write_cached_reg(port_mmio + EDMA_HALTCOND_OFS, old_haltcond, haltcond); } static void mv_60x1_errata_sata25(struct ata_port *ap, int want_ncq) @@ -1235,7 +1282,7 @@ */ want_fbs &= want_ncq; - mv_config_fbs(port_mmio, want_ncq, want_fbs); + mv_config_fbs(ap, want_ncq, want_fbs); if (want_fbs) { pp->pp_flags |= MV_PP_FLAG_FBS_EN; @@ -1339,6 +1386,7 @@ pp->sg_tbl_dma[tag] = pp->sg_tbl_dma[0]; } } + mv_save_cached_regs(ap); mv_edma_cfg(ap, 0, 0); return 0; @@ -2996,6 +3044,7 @@ extra = HZ; /* only extend it once, max */ } } while (sstatus != 0x0 && sstatus != 0x113 && sstatus != 0x123); + mv_save_cached_regs(ap); mv_edma_cfg(ap, 0, 0); return rc; ^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 02/02] sata_mv: enable ATAPI DMA for GEN_IIE (v2) 2009-02-05 15:36 ` [PATCH 01/02] sata_mv: cache frequently read port registers Mark Lord @ 2009-02-05 15:37 ` Mark Lord 0 siblings, 0 replies; 4+ messages in thread From: Mark Lord @ 2009-02-05 15:37 UTC (permalink / raw) To: Jeff Garzik, IDE/ATA development list; +Cc: Grant Grundler Enable use of (basic) DMA for ATAPI on GEN_IIE chips. This also gets rid of any need for mv_mode_filter(). Using basic DMA on GEN_IIE requires setting an undocumented bit in an undocumented register. For safety, we clear that bit again when switching back to EDMA mode. To avoid a performance penalty when switching modes, we cache the register in port_priv, as already done for other regs. Signed-off-by: Mark Lord <mlord@pobox.com> --- This replaces the original patch posted earlier. --- old/drivers/ata/sata_mv.c 2009-02-05 10:14:43.000000000 -0500 +++ linux/drivers/ata/sata_mv.c 2009-02-05 10:13:12.000000000 -0500 @@ -345,7 +345,7 @@ EDMA_ARB_CFG_OFS = 0x38, EDMA_HALTCOND_OFS = 0x60, /* GenIIe halt conditions */ - + EDMA_UNKNOWN_RSVD_OFS = 0x6C, /* GenIIe unknown/reserved */ BMDMA_CMD_OFS = 0x224, /* bmdma command register */ BMDMA_STATUS_OFS = 0x228, /* bmdma status register */ @@ -447,6 +447,7 @@ u32 fiscfg; u32 ltmode; u32 haltcond; + u32 unknown_rsvd; }; struct mv_port_priv { @@ -563,8 +564,6 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp); -static unsigned long mv_mode_filter(struct ata_device *dev, - unsigned long xfer_mask); static void mv_sff_irq_clear(struct ata_port *ap); static int mv_check_atapi_dma(struct ata_queued_cmd *qc); static void mv_bmdma_setup(struct ata_queued_cmd *qc); @@ -626,7 +625,6 @@ .bmdma_start = mv_bmdma_start, .bmdma_stop = mv_bmdma_stop, .bmdma_status = mv_bmdma_status, - .mode_filter = mv_mode_filter, }; static struct ata_port_operations mv_iie_ops = { @@ -842,6 +840,7 @@ pp->cached.fiscfg = readl(port_mmio + FISCFG_OFS); pp->cached.ltmode = readl(port_mmio + LTMODE_OFS); pp->cached.haltcond = readl(port_mmio + EDMA_HALTCOND_OFS); + pp->cached.unknown_rsvd = readl(port_mmio + EDMA_UNKNOWN_RSVD_OFS); } /** @@ -1252,6 +1251,30 @@ writel(new, hpriv->base + MV_GPIO_PORT_CTL_OFS); } +/** + * mv_bmdma_enable - set a magic bit on GEN_IIE to allow bmdma + * @ap: Port being initialized + * + * There are two DMA modes on these chips: basic DMA, and EDMA. + * + * Bit-0 of the "EDMA RESERVED" register enables/disables use + * of basic DMA on the GEN_IIE versions of the chips. + * + * This bit survives EDMA resets, and must be set for basic DMA + * to function, and should be cleared when EDMA is active. + */ +static void mv_bmdma_enable_iie(struct ata_port *ap, int enable_bmdma) +{ + struct mv_port_priv *pp = ap->private_data; + u32 new, *old = &pp->cached.unknown_rsvd; + + if (enable_bmdma) + new = *old | 1; + else + new = *old & ~1; + mv_write_cached_reg(mv_ap_base(ap) + EDMA_UNKNOWN_RSVD_OFS, old, new); +} + static void mv_edma_cfg(struct ata_port *ap, int want_ncq, int want_edma) { u32 cfg; @@ -1297,6 +1320,7 @@ } if (hpriv->hp_flags & MV_HP_CUT_THROUGH) cfg |= (1 << 17); /* enab cut-thru (dis stor&forwrd) */ + mv_bmdma_enable_iie(ap, !want_edma); } if (want_ncq) { @@ -1465,26 +1489,6 @@ } /** - * mv_mode_filter - Allow ATAPI DMA only on GenII chips. - * @dev: device whose xfer modes are being configured. - * - * Only the GenII hardware can use DMA with ATAPI drives. - */ -static unsigned long mv_mode_filter(struct ata_device *adev, - unsigned long xfer_mask) -{ - if (adev->class == ATA_DEV_ATAPI) { - struct mv_host_priv *hpriv = adev->link->ap->host->private_data; - if (!IS_GEN_II(hpriv)) { - xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); - ata_dev_printk(adev, KERN_INFO, - "ATAPI DMA not supported on this chipset\n"); - } - } - return xfer_mask; -} - -/** * mv_sff_irq_clear - Clear hardware interrupt after DMA. * @ap: Port associated with this ATA transaction. * ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2009-02-05 15:37 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-02-04 18:05 [PATCH] sata_mv: enable ATAPI DMA for GEN_IIE chips Mark Lord 2009-02-05 15:33 ` Mark Lord 2009-02-05 15:36 ` [PATCH 01/02] sata_mv: cache frequently read port registers Mark Lord 2009-02-05 15:37 ` [PATCH 02/02] sata_mv: enable ATAPI DMA for GEN_IIE (v2) Mark Lord
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).