* [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 an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.