Skip to contentSkip to conversation

powerpc/mpc5200: Add support for ATA DMA

PATCH New Grant Likely 1 participant 5 messages Dec 21, 2008

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

cover powerpc/mpc5200: Add support for ATA DMA

Hey everyone; here is the latest version of the patches to add ATA DMA support for the MPC5200. I'm pretty confident that these patches won't break anything and by default DMA support is turned off. Users wanting to test ATA DMA should add the 'libata.force=udma2' parameter to the kernel command line.

Since there are just minor changes from the last iteration and a couple of changes have been broken out into separate patches, I'm pushing this series out to my -next tree for Paul to pick up.

Cheers,
g.

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

#1 lore raw

PATCH 1/4 powerpc/mpc5200: Bugfix on handling variable sized buffer descriptors

From: Grant Likely <[email protected]>

The buffer descriptors for the ATA BestComm task are larger than the current definition for bcom_bd. This causes problems because the various bcom_... functions dereference the buffer descriptor pointer by using the array operator which doesn't work when the buffer descriptors are a different size.

This patch adds the bcom_get_bd() function which uses the value in bcom_task.bd_size to calculate the offset into the BD table. This patch also changes the definition of bcom_bd to specify a data size of 0 instead of 1 so that it will never work if anyone attempts to dereference the bd list as an array (as opposed to something that might work even though it is wrong).

Finally, this patch moves the definition of bcom_bd up in the file to eliminate a forward declaration.

Based on patch originally written by Tim Yamin.

---

 arch/powerpc/sysdev/bestcomm/bestcomm.h |   61 +++++++++++++++++++++----------
 1 files changed, 42 insertions(+), 19 deletions(-)
arch/powerpc/sysdev/bestcomm/bestcomm.h +42 -19
index c960a8b..23a95f8 100644
@@ -16,8 +16,19 @@
 #ifndef __BESTCOMM_H__
 #define __BESTCOMM_H__
 
-struct bcom_bd; /* defined later on ... */
-
+/**
+ * struct bcom_bd - Structure describing a generic BestComm buffer descriptor
+ * @status: The current status of this buffer. Exact meaning depends on the
+ *          task type
+ * @data: An array of u32 extra data.  Size of array is task dependant.
+ *
+ * Note: Don't dereference a bcom_bd pointer as an array.  The size of the
+ *       bcom_bd is variable.  Use bcom_get_bd() instead.
+ */
+struct bcom_bd {
+	u32	status;
+	u32	data[0];	/* variable payload size */
+};
 
 /* ======================================================================== */
 /* Generic task management                                                   */
@@ -84,17 +95,6 @@ bcom_get_task_irq(struct bcom_task *tsk) {
 /* BD based tasks helpers                                                   */
 /* ======================================================================== */
 
-/**
- * struct bcom_bd - Structure describing a generic BestComm buffer descriptor
- * @status: The current status of this buffer. Exact meaning depends on the
- *          task type
- * @data: An array of u32 whose meaning depends on the task type.
- */
-struct bcom_bd {
-	u32	status;
-	u32	data[1];	/* variable, but at least 1 */
-};
-
 #define BCOM_BD_READY	0x40000000ul
 
 /** _bcom_next_index - Get next input index.
@@ -140,15 +140,31 @@ 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)
+{
+	/* A cast to (void*) so the address can be incremented by the
+	 * real size instead of by sizeof(struct bcom_bd) */
+	return ((void *)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 +176,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 +200,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;
 }
#2 lore raw

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

In reply to Grant Likely

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 experienced with heavy DMA occurring on both the ATA and Ethernet BestComm tasks, e.g. when downloading a large file over a LAN to disk.

---

 arch/powerpc/sysdev/bestcomm/ata.h           |    2 +-
 arch/powerpc/sysdev/bestcomm/bestcomm_priv.h |    4 ++--
 2 files changed, 3 insertions(+), 3 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_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
#3 lore raw

PATCH 3/4 powerpc/mpc5200: Disable bestcomm prefetching when ATA DMA enabled

In reply to Grant Likely

From: Grant Likely <[email protected]>

When ATA DMA is enabled, bestcomm prefetching does not work. This patch adds a function to disable bestcomm prefetch when the ATA Bestcomm task is initialized.

---

 arch/powerpc/sysdev/bestcomm/ata.c           |    3 +++
 arch/powerpc/sysdev/bestcomm/bestcomm.c      |    7 ++-----
 arch/powerpc/sysdev/bestcomm/bestcomm_priv.h |   16 ++++++++++++++++
 3 files changed, 21 insertions(+), 5 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)
 {
#4 lore raw

PATCH 4/4 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.h |   17 -
 drivers/ata/Kconfig                |    3 
 drivers/ata/pata_mpc52xx.c         |  546 ++++++++++++++++++++++++++++++++----
 3 files changed, 488 insertions(+), 78 deletions(-)
arch/powerpc/sysdev/bestcomm/ata.h +5 -12
index 0374322..0b23718 100644
@@ -20,18 +20,11 @@ struct bcom_ata_bd {
 	u32	dst_pa;
 };
 
-extern struct bcom_task *
-bcom_ata_init(int queue_len, int maxbufsize);
-
-extern void
-bcom_ata_rx_prepare(struct bcom_task *tsk);
-
-extern void
-bcom_ata_tx_prepare(struct bcom_task *tsk);
-
-extern void
-bcom_ata_reset_bd(struct bcom_task *tsk);
-
+extern struct bcom_task * bcom_ata_init(int queue_len, int maxbufsize);
+extern void bcom_ata_rx_prepare(struct bcom_task *tsk);
+extern void bcom_ata_tx_prepare(struct bcom_task *tsk);
+extern void bcom_ata_reset_bd(struct bcom_task *tsk);
+extern void bcom_ata_release(struct bcom_task *tsk);
 
 #endif /* __BESTCOMM_ATA_H__ */
 
drivers/ata/Kconfig +2 -1
index 421b7c7..1a7be96 100644
@@ -456,7 +456,8 @@ config PATA_MARVELL
 
 config PATA_MPC52xx
 	tristate "Freescale MPC52xx SoC internal IDE"
-	depends on PPC_MPC52xx
+	depends on PPC_MPC52xx && PPC_BESTCOMM
+	select PPC_BESTCOMM_ATA
 	help
 	  This option enables support for integrated IDE controller
 	  of the Freescale MPC52xx SoC.
drivers/ata/pata_mpc52xx.c +481 -65

728 lines not on this page · raw message