Skip to contentSkip to conversation

Addition of MWDMA/UDMA modes to MPC5200 ATA driver

PATCH In review Grant Likely 2 participants 4 messages Nov 13, 2008 – Nov 14, 2008

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover Addition of MWDMA/UDMA modes to MPC5200 ATA driver

Hi all,

This is Tim's series for adding UDMA/MWDMA support to the Freescale MPC5200 ATA device driver. Tested on Genesi's Efika board.

Jeff, if it is okay by you, I'm going to push this through my mpc5200 powerpc tree (after addressing any comments of course) since it only affects the MPC5200 PowerPC SoC.

g.

--
Grant Likely, B.Sc. P.Eng.
Secret Lab Technologies Ltd.

#1 lore raw

PATCH 1/2 powerpc/mpc5200: Bestcomm fixes to ATA support

From: Tim Yamin <[email protected]>

1) ata.h has dst_pa in the wrong place (needs to match what the BestComm task microcode in bcom_ata_task.c expects); fix it.

2) The BestComm ATA task priority was changed to maximum in bestcomm_priv.h; this fixes a deadlock issue I was experiencing when heavy DMA was occuring on both the ATA and Ethernet BestComm tasks, e.g. when downloading a large file over a LAN to disk.

3) The ATA BestComm driver uses bcom_ata_bd which is bigger than bcom_bd and this causes problems because the various bcom_... functions do not dereference the correct location. I've introduced bcom_get_bd which uses bcom_task.bd_size and this fixes the problem.

---

 arch/powerpc/sysdev/bestcomm/ata.h           |    2 +
 arch/powerpc/sysdev/bestcomm/bestcomm.h      |   35 +++++++++++++++++++++-----
 arch/powerpc/sysdev/bestcomm/bestcomm_priv.h |    4 +--
 3 files changed, 31 insertions(+), 10 deletions(-)
arch/powerpc/sysdev/bestcomm/ata.h +1 -1
index 1098276..0374322 100644
@@ -16,8 +16,8 @@
 
 struct bcom_ata_bd {
 	u32	status;
-	u32	dst_pa;
 	u32	src_pa;
+	u32	dst_pa;
 };
 
 extern struct bcom_task *
arch/powerpc/sysdev/bestcomm/bestcomm.h +28 -7
index c960a8b..dc2b143 100644
@@ -38,7 +38,7 @@ struct bcom_task {
 	unsigned int	flags;
 	int		irq;
 
-	struct bcom_bd	*bd;
+	void		*bd;
 	phys_addr_t	bd_pa;
 	void		**cookie;
 	unsigned short	index;
@@ -140,15 +140,29 @@ bcom_queue_full(struct bcom_task *tsk)
 }
 
 /**
+ * bcom_get_bd - Get a BD from the queue
+ * @tsk: The BestComm task structure
+ * index: Index of the BD to fetch
+ */
+static inline struct bcom_bd
+*bcom_get_bd(struct bcom_task *tsk, unsigned int index)
+{
+	return tsk->bd + index * tsk->bd_size;
+}
+
+/**
  * bcom_buffer_done - Checks if a BestComm 
  * @tsk: The BestComm task structure
  */
 static inline int
 bcom_buffer_done(struct bcom_task *tsk)
 {
+	struct bcom_bd *bd;
 	if (bcom_queue_empty(tsk))
 		return 0;
-	return !(tsk->bd[tsk->outdex].status & BCOM_BD_READY);
+
+	bd = bcom_get_bd(tsk, tsk->outdex);
+	return !(bd->status & BCOM_BD_READY);
 }
 
 /**
@@ -160,16 +174,21 @@ bcom_buffer_done(struct bcom_task *tsk)
 static inline struct bcom_bd *
 bcom_prepare_next_buffer(struct bcom_task *tsk)
 {
-	tsk->bd[tsk->index].status = 0;	/* cleanup last status */
-	return &tsk->bd[tsk->index];
+	struct bcom_bd *bd;
+
+	bd = bcom_get_bd(tsk, tsk->index);
+	bd->status = 0;	/* cleanup last status */
+	return bd;
 }
 
 static inline void
 bcom_submit_next_buffer(struct bcom_task *tsk, void *cookie)
 {
+	struct bcom_bd *bd = bcom_get_bd(tsk, tsk->index);
+
 	tsk->cookie[tsk->index] = cookie;
 	mb();	/* ensure the bd is really up-to-date */
-	tsk->bd[tsk->index].status |= BCOM_BD_READY;
+	bd->status |= BCOM_BD_READY;
 	tsk->index = _bcom_next_index(tsk);
 	if (tsk->flags & BCOM_FLAGS_ENABLE_TASK)
 		bcom_enable(tsk);
@@ -179,10 +198,12 @@ static inline void *
 bcom_retrieve_buffer(struct bcom_task *tsk, u32 *p_status, struct bcom_bd **p_bd)
 {
 	void *cookie = tsk->cookie[tsk->outdex];
+	struct bcom_bd *bd = bcom_get_bd(tsk, tsk->outdex);
+
 	if (p_status)
-		*p_status = tsk->bd[tsk->outdex].status;
+		*p_status = bd->status;
 	if (p_bd)
-		*p_bd = &tsk->bd[tsk->outdex];
+		*p_bd = bd;
 	tsk->outdex = _bcom_next_outdex(tsk);
 	return cookie;
 }
arch/powerpc/sysdev/bestcomm/bestcomm_priv.h +2 -2
index 866a291..746f155 100644
@@ -198,8 +198,8 @@ struct bcom_task_header {
 #define BCOM_IPR_SCTMR_1	2
 #define BCOM_IPR_FEC_RX		6
 #define BCOM_IPR_FEC_TX		5
-#define BCOM_IPR_ATA_RX		4
-#define BCOM_IPR_ATA_TX		3
+#define BCOM_IPR_ATA_RX		7
+#define BCOM_IPR_ATA_TX		7
 #define BCOM_IPR_SCPCI_RX	2
 #define BCOM_IPR_SCPCI_TX	2
 #define BCOM_IPR_PSC3_RX	2
#2 lore raw

PATCH 2/2 powerpc/mpc5200: Add MDMA/UDMA support to MPC5200 ATA driver

In reply to Grant Likely

From: Tim Yamin <[email protected]>

This patch adds MDMA/UDMA support using BestComm for DMA on the MPC5200 platform. Based heavily on previous work by Freescale (Bernard Kuhn, John Rigby) and Domen Puncer.

With this patch, a SanDisk Extreme IV CF card gets read speeds of approximately 26.70 MB/sec.

---

 arch/powerpc/sysdev/bestcomm/ata.c           |    3 
 arch/powerpc/sysdev/bestcomm/bestcomm.c      |    7 
 arch/powerpc/sysdev/bestcomm/bestcomm_priv.h |   16 +
 drivers/ata/pata_mpc52xx.c                   |  440 +++++++++++++++++++++++++-
 4 files changed, 443 insertions(+), 23 deletions(-)
arch/powerpc/sysdev/bestcomm/ata.c +3 -0
index 1f5258f..901c9f9 100644
@@ -61,6 +61,9 @@ bcom_ata_init(int queue_len, int maxbufsize)
 	struct bcom_ata_var *var;
 	struct bcom_ata_inc *inc;
 
+	/* Prefetch breaks ATA DMA.  Turn it off for ATA DMA */
+	bcom_disable_prefetch();
+
 	tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_ata_bd), 0);
 	if (!tsk)
 		return NULL;
arch/powerpc/sysdev/bestcomm/bestcomm.c +2 -5
index 446c9ea..378ebd9 100644
@@ -279,7 +279,6 @@ bcom_engine_init(void)
 	int task;
 	phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa;
 	unsigned int tdt_size, ctx_size, var_size, fdt_size;
-	u16 regval;
 
 	/* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */
 	tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt);
@@ -331,10 +330,8 @@ bcom_engine_init(void)
 	out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS);
 
 	/* Disable COMM Bus Prefetch on the original 5200; it's broken */
-	if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) {
-		regval = in_be16(&bcom_eng->regs->PtdCntrl);
-		out_be16(&bcom_eng->regs->PtdCntrl,  regval | 1);
-	}
+	if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR)
+		bcom_disable_prefetch();
 
 	/* Init lock */
 	spin_lock_init(&bcom_eng->lock);
arch/powerpc/sysdev/bestcomm/bestcomm_priv.h +16 -0
index 746f155..eb0d1c8 100644
@@ -241,6 +241,22 @@ extern void bcom_set_initiator(int task, int initiator);
 
 #define TASK_ENABLE             0x8000
 
+/**
+ * bcom_disable_prefetch - Hook to disable bus prefetching
+ *
+ * ATA DMA and the original MPC5200 need this due to silicon bugs.  At the
+ * moment disabling prefetch is a one-way street.  There is no mechanism
+ * in place to turn prefetch back on after it has been disabled.  There is
+ * no reason it couldn't be done, it would just be more complex to implement.
+ */
+static inline void bcom_disable_prefetch(void)
+{
+	u16 regval;
+
+	regval = in_be16(&bcom_eng->regs->PtdCntrl);
+	out_be16(&bcom_eng->regs->PtdCntrl, regval | 1);
+};
+
 static inline void
 bcom_enable_task(int task)
 {
drivers/ata/pata_mpc52xx.c +422 -18

563 lines not on this page · raw message

#3 lore raw

Re: [PATCH 2/2] powerpc/mpc5200: Add MDMA/UDMA support to MPC5200 ATA driver

ACK