powerpc/mpc5200: Add support for ATA DMA
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.
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
@@ -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; }
PATCH 2/4 powerpc/mpc5200: Bestcomm fixes to ATA support
In reply to Grant LikelyFrom: 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
@@ -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
@@ -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
PATCH 3/4 powerpc/mpc5200: Disable bestcomm prefetching when ATA DMA enabled
In reply to Grant LikelyFrom: 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
@@ -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
@@ -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
@@ -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) {
PATCH 4/4 powerpc/mpc5200: Add MDMA/UDMA support to MPC5200 ATA driver
In reply to Grant LikelyFrom: 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
@@ -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
@@ -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