Skip to contentSkip to conversation

sata_mv: cache frequently read registers

PATCH Applied Mark Lord 2 participants 9 messages Feb 13, 2009 – Feb 25, 2009 1 message not in the archive libata

lore
Share & tools
lore

Mark Lord

author
#0 lore raw

PATCH 1/6 sata_mv: cache frequently read registers

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.

--

Resending without any changes from original.

drivers/ata/sata_mv.c +72 -23
@@ -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;
author
#1 lore raw

PATCH 2/6 sata_mv: enable ATAPI DMA for GEN_IIE chips

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.

drivers/ata/sata_mv.c +28 -24
@@ -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.
  *
author
#2 lore raw

PATCH 3/6 sata_mv: stricter irq masking

Tighten up interrupt masking in mv_qc_issue() so that it doesn't miss any protocols. Handle future cases where a qc is specially marked for polled issue or where a particular chip version prefers interrupts over polling for PIO.

This mimics the polling decision logic from ata_sff_qc_issue().

drivers/ata/sata_mv.c +21 -13
@@ -1809,7 +1809,7 @@
 	void __iomem *port_mmio = mv_ap_base(ap);
 	struct mv_port_priv *pp = ap->private_data;
 	u32 in_index;
-	unsigned int port_irqs = DONE_IRQ | ERR_IRQ;
+	unsigned int port_irqs;
 
 	switch (qc->tf.protocol) {
 	case ATA_PROT_DMA:
@@ -1842,20 +1842,28 @@
 					"this may fail due to h/w errata\n");
 		}
 		/* drop through */
+	case ATA_PROT_NODATA:
 	case ATAPI_PROT_PIO:
-		port_irqs = ERR_IRQ;	/* leave DONE_IRQ masked for PIO */
-		/* drop through */
-	default:
-		/*
-		 * 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.
-		 */
-		mv_stop_edma(ap);
-		mv_clear_and_enable_port_irqs(ap, mv_ap_base(ap), port_irqs);
-		mv_pmp_select(ap, qc->dev->link->pmp);
-		return ata_sff_qc_issue(qc);
+	case ATAPI_PROT_NODATA:
+		if (ap->flags & ATA_FLAG_PIO_POLLING)
+			qc->tf.flags |= ATA_TFLAG_POLLING;
+		break;
 	}
+
+	if (qc->tf.flags & ATA_TFLAG_POLLING)
+		port_irqs = ERR_IRQ;	/* mask device interrupt when polling */
+	else
+		port_irqs = ERR_IRQ | DONE_IRQ;	/* unmask all interrupts */
+
+	/*
+	 * 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.
+	 */
+	mv_stop_edma(ap);
+	mv_clear_and_enable_port_irqs(ap, mv_ap_base(ap), port_irqs);
+	mv_pmp_select(ap, qc->dev->link->pmp);
+	return ata_sff_qc_issue(qc);
 }
 
 static struct ata_queued_cmd *mv_get_active_qc(struct ata_port *ap)
author
#3 lore raw

PATCH 4/6 sata_mv: implement mv_sff_check_status

Add a new mv_sff_check_status() function to sata_mv.
This is necessary for use with the upcoming "mv_qc_issue_fis()" patch, but is being added separately here for easier code review.

When using command issue via the "mv_qc_issue_fis()" mechanism, the initial ATA_BUSY bit does not show in the ATA status (shadow) register. This can confuse libata! So here we add a hook to fake ATA_BUSY for that situation, until the first time a BUSY, DRQ, or ERR bit is seen.

drivers/ata/sata_mv.c +36 -1
@@ -370,6 +370,7 @@
 	MV_PP_FLAG_NCQ_EN	= (1 << 1),	/* is EDMA set up for NCQ? */
 	MV_PP_FLAG_FBS_EN	= (1 << 2),	/* is EDMA set up for FBS? */
 	MV_PP_FLAG_DELAYED_EH	= (1 << 3),	/* delayed dev err handling */
+	MV_PP_FLAG_FAKE_ATA_BUSY = (1 << 4),	/* ignore initial ATA_DRDY */
 };
 
 #define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
@@ -570,6 +571,7 @@
 static void mv_bmdma_start(struct ata_queued_cmd *qc);
 static void mv_bmdma_stop(struct ata_queued_cmd *qc);
 static u8   mv_bmdma_status(struct ata_port *ap);
+static u8 mv_sff_check_status(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
@@ -619,6 +621,7 @@
 	.softreset		= mv_softreset,
 	.error_handler		= mv_pmp_error_handler,
 
+ 	.sff_check_status	= mv_sff_check_status,
 	.sff_irq_clear		= mv_sff_irq_clear,
 	.check_atapi_dma	= mv_check_atapi_dma,
 	.bmdma_setup		= mv_bmdma_setup,
@@ -1284,7 +1287,8 @@
 
 	/* set up non-NCQ EDMA configuration */
 	cfg = EDMA_CFG_Q_DEPTH;		/* always 0x1f for *all* chips */
-	pp->pp_flags &= ~(MV_PP_FLAG_FBS_EN | MV_PP_FLAG_NCQ_EN);
+	pp->pp_flags &=
+	  ~(MV_PP_FLAG_FBS_EN | MV_PP_FLAG_NCQ_EN | MV_PP_FLAG_FAKE_ATA_BUSY);
 
 	if (IS_GEN_I(hpriv))
 		cfg |= (1 << 8);	/* enab config burst size mask */
@@ -1791,6 +1795,33 @@
 }
 
 /**
+ *	mv_sff_check_status - fetch device status, if valid
+ *	@ap: ATA port to fetch status from
+ *
+ *	When using command issue via mv_qc_issue_fis(),
+ *	the initial ATA_BUSY state does not show up in the
+ *	ATA status (shadow) register.  This can confuse libata!
+ *
+ *	So we have a hook here to fake ATA_BUSY for that situation,
+ *	until the first time a BUSY, DRQ, or ERR bit is seen.
+ *
+ *	The rest of the time, it simply returns the ATA status register.
+ */
+static u8 mv_sff_check_status(struct ata_port *ap)
+{
+	u8 stat = ioread8(ap->ioaddr.status_addr);
+	struct mv_port_priv *pp = ap->private_data;
+
+	if (pp->pp_flags & MV_PP_FLAG_FAKE_ATA_BUSY) {
+		if (stat & (ATA_BUSY | ATA_DRQ | ATA_ERR))
+			pp->pp_flags &= ~MV_PP_FLAG_FAKE_ATA_BUSY;
+		else
+			stat = ATA_BUSY;
+	}
+	return stat;
+}
+
+/**
  *      mv_qc_issue - Initiate a command to the host
  *      @qc: queued command to start
  *
@@ -1811,6 +1842,8 @@
 	u32 in_index;
 	unsigned int port_irqs;
 
+	pp->pp_flags &= ~MV_PP_FLAG_FAKE_ATA_BUSY; /* paranoia */
+
 	switch (qc->tf.protocol) {
 	case ATA_PROT_DMA:
 	case ATA_PROT_NCQ:
@@ -3037,6 +3070,8 @@
 
 	mv_reset_channel(hpriv, mmio, ap->port_no);
 	pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+	pp->pp_flags &=
+	  ~(MV_PP_FLAG_FBS_EN | MV_PP_FLAG_NCQ_EN | MV_PP_FLAG_FAKE_ATA_BUSY);
 
 	/* Workaround for errata FEr SATA#10 (part 2) */
 	do {
author
#4 lore raw

PATCH 5/6 sata_mv: export ata_pio_queue_task()

Export ata_pio_queue_task() so that it can be used from sata_mv.

drivers/ata/libata-core.c +1 -0
@@ -6707,6 +6707,7 @@
 EXPORT_SYMBOL_GPL(ata_do_dev_read_id);
 EXPORT_SYMBOL_GPL(ata_scsi_simulate);
 
+EXPORT_SYMBOL_GPL(ata_pio_queue_task);
 EXPORT_SYMBOL_GPL(ata_pio_need_iordy);
 EXPORT_SYMBOL_GPL(ata_timing_find_mode);
 EXPORT_SYMBOL_GPL(ata_timing_compute);
drivers/ata/libata.h +0 -2
@@ -79,8 +79,6 @@
 			   u64 block, u32 n_block, unsigned int tf_flags,
 			   unsigned int tag);
 extern u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev);
-extern void ata_pio_queue_task(struct ata_port *ap, void *data,
-			       unsigned long delay);
 extern void ata_port_flush_task(struct ata_port *ap);
 extern unsigned ata_exec_internal(struct ata_device *dev,
 				  struct ata_taskfile *tf, const u8 *cdb,
include/linux/libata.h +3 -0
@@ -1006,6 +1006,9 @@
 extern int ata_cable_ignore(struct ata_port *ap);
 extern int ata_cable_unknown(struct ata_port *ap);
 
+extern void ata_pio_queue_task(struct ata_port *ap, void *data,
+			       unsigned long delay);
+
 /* Timing helpers */
 extern unsigned int ata_pio_need_iordy(const struct ata_device *);
 extern const struct ata_timing *ata_timing_find_mode(u8 xfer_mode);
author
#5 lore raw

PATCH 6/6 sata_mv: implement mv_qc_issue_fis() for errata workaround

Implement direct FIS transmission via mv_qc_issue_fis(). This is initially needed to work around NCQ errata, whereby the READ_LOG_EXT command sometimes fails when issued in the traditional (sff) fashion.

Portions of this code will likely be reused for implementation of the target mode feature later on.

drivers/ata/sata_mv.c +116 -0
@@ -1822,6 +1822,105 @@
 }
 
 /**
+ *	mv_send_fis - Send a FIS, using the "Vendor-Unique FIS" register
+ *	@fis: fis to be sent
+ *	@nwords: number of 32-bit words in the fis
+ */
+static unsigned int mv_send_fis(struct ata_port *ap, u32 *fis, int nwords)
+{
+	void __iomem *port_mmio = mv_ap_base(ap);
+	u32 ifctl, old_ifctl, ifstat;
+	int i, timeout = 200, final_word = nwords - 1;
+
+	/* Initiate FIS transmission mode */
+	old_ifctl = readl(port_mmio + SATA_IFCTL_OFS);
+	ifctl = 0x100 | (old_ifctl & 0xf);
+	writelfl(ifctl, port_mmio + SATA_IFCTL_OFS);
+
+	/* Send all words of the FIS except for the final word */
+	for (i = 0; i < final_word; ++i)
+		writel(fis[i], port_mmio + VENDOR_UNIQUE_FIS_OFS);
+
+	/* Flag end-of-transmission, and then send the final word */
+	writelfl(ifctl | 0x200, port_mmio + SATA_IFCTL_OFS);
+	writelfl(fis[final_word], port_mmio + VENDOR_UNIQUE_FIS_OFS);
+
+	/*
+	 * Wait for FIS transmission to complete.
+	 * This typically takes just a single iteration.
+	 */
+	do {
+		ifstat = readl(port_mmio + SATA_IFSTAT_OFS);
+	} while (!(ifstat & 0x1000) && --timeout);
+
+	/* Restore original port configuration */
+	writelfl(old_ifctl, port_mmio + SATA_IFCTL_OFS);
+
+	/* See if it worked */
+	if ((ifstat & 0x3000) != 0x1000) {
+		ata_port_printk(ap, KERN_WARNING,
+				"%s transmission error, ifstat=%08x\n",
+				__func__, ifstat);
+		return AC_ERR_OTHER;
+	}
+	return 0;
+}
+
+/**
+ *	mv_qc_issue_fis - Issue a command directly as a FIS
+ *	@qc: queued command to start
+ *
+ *	Note that the ATA shadow registers are not updated
+ *	after command issue, so the device will appear "READY"
+ *	if polled, even while it is BUSY processing the command.
+ *
+ *	So we use a status hook to fake ATA_BUSY until the drive changes state.
+ *
+ *	Note: we don't get updated shadow regs on *completion*
+ *	of non-data commands. So avoid sending them via this function,
+ *	as they will appear to have completed immediately.
+ *
+ *	GEN_IIE has special registers that we could get the result tf from,
+ *	but earlier chipsets do not.  For now, we ignore those registers.
+ */
+static unsigned int mv_qc_issue_fis(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct mv_port_priv *pp = ap->private_data;
+	struct ata_link *link = qc->dev->link;
+	u32 fis[5];
+	int err = 0;
+
+	ata_tf_to_fis(&qc->tf, link->pmp, 1, (void *)fis);
+	err = mv_send_fis(ap, fis, sizeof(fis) / sizeof(fis[0]));
+	if (err)
+		return err;
+
+	switch (qc->tf.protocol) {
+	case ATAPI_PROT_PIO:
+		pp->pp_flags |= MV_PP_FLAG_FAKE_ATA_BUSY;
+		/* fall through */
+	case ATAPI_PROT_NODATA:
+		ap->hsm_task_state = HSM_ST_FIRST;
+		break;
+	case ATA_PROT_PIO:
+		pp->pp_flags |= MV_PP_FLAG_FAKE_ATA_BUSY;
+		if (qc->tf.flags & ATA_TFLAG_WRITE)
+			ap->hsm_task_state = HSM_ST_FIRST;
+		else
+			ap->hsm_task_state = HSM_ST;
+		break;
+	default:
+		ap->hsm_task_state = HSM_ST_LAST;
+		break;
+	}
+
+	if (qc->tf.flags & ATA_TFLAG_POLLING)
+		ata_pio_queue_task(ap, qc, 0);
+	return 0;
+}
+
+/**
  *      mv_qc_issue - Initiate a command to the host
  *      @qc: queued command to start
  *
@@ -1896,6 +1995,23 @@
 	mv_stop_edma(ap);
 	mv_clear_and_enable_port_irqs(ap, mv_ap_base(ap), port_irqs);
 	mv_pmp_select(ap, qc->dev->link->pmp);
+
+	if (qc->tf.command == ATA_CMD_READ_LOG_EXT) {
+		struct mv_host_priv *hpriv = ap->host->private_data;
+		/*
+		 * Workaround for 88SX60x1 FEr SATA#25 (part 2).
+		 *
+		 * After any NCQ error, the READ_LOG_EXT command
+		 * from libata-eh *must* use mv_qc_issue_fis().
+		 * Otherwise it might fail, due to chip errata.
+		 *
+		 * Rather than special-case it, we'll just *always*
+		 * use this method here for READ_LOG_EXT, making for
+		 * easier testing.
+		 */
+		if (IS_GEN_II(hpriv))
+			return mv_qc_issue_fis(qc);
+	}
 	return ata_sff_qc_issue(qc);
 }
 
#6 lore raw
In reply to Mark Lord
Quoted 9 lines · Mark Lord

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.

Signature · 1 line
Resending without any changes from original.

ACK patches 1-6

however, they do not seem to apply to libata-dev.git#upstream, which already has several sata_mv changes in it.

Can you regenerate please? No need to copy the list on resend, unless the patch content changes....

Jeff

author
#7 lore raw
Quoted 9 lines · Jeff Garzik
Quoted 8 lines · Mark Lord

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.

Quoted 7 lines
Quoted 1 line

Resending without any changes from original.

ACK patches 1-6

however, they do not seem to apply to libata-dev.git#upstream, which already has several sata_mv changes in it.

Can you regenerate please? No need to copy the list on resend, unless the patch content changes....

..

I sent you the patches via email a week ago now, and no word back .. and no updates visible in libata-dev.

Did you get them?

Thanks

Mark

A message that is not in the archive (sent off-list or not yet received): [email protected]

Applied
#9 lore raw
Quoted 4 lines · Mark Lord

Jeff Garzik wrote:
..

Quoted 2 lines

ACK patches 1-6

Quoted 8 lines
Quoted 3 lines

however, they do not seem to apply to libata-dev.git#upstream, which already has several sata_mv changes in it.

Can you regenerate please? No need to copy the list on resend, unless the patch content changes....

..

Mmm.. strange. Here (attached) are the six patches again, along with what my git here gives for the upstream copy of sata_mv.c from *before* applying the patches.

Sorry for the delay... the attachments applied and worked just fine.

I eyeballed the first patch and it looked the same as your emailed first patch, so I'm guessing there was an email bugaboo somewhere, rather than a patch content problem.

Applied all 6 to #upstream.

Jeff