Re: [PATCH]: [MPC5200] (v2) Add ATA DMA support

2008-07-03 Thread Tim Yamin
On Wed, Jul 2, 2008 at 6:30 PM, Grant Likely [EMAIL PROTECTED] wrote:
 I know that only ATA uses this; but it is nice to have fixes to things
 that are obviously wrong in existing code to be split into their own
 patches.  That way, even if the ATA patch gets backed out, the bug fix
 will remain.

Ok, so I've split the patch up into two pieces now...

 +static void
 +mpc52xx_bmdma_start(struct ata_queued_cmd *qc)
 +{
 + struct ata_port *ap = qc-ap;
 + struct mpc52xx_ata_priv *priv = ap-host-private_data;
 +
 + /* LocalBus lock */
 + while (test_and_set_bit(0, pata_mpc52xx_ata_dma_lock) != 0)
 + ;

 Need to be able to bail on timeout.

A deadlock can't occur within the PATA driver because you won't have
two DMA requests happening at once, so there is no point in adding a
timeout. And even if you do have a timeout, you'd have to drop the I/O
request somehow, so it's not really a good idea. If anything else
needs to touch the DMA lock, it should do so in a sensible fashion...

Thanks,

Tim
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.

Signed-off-by: Tim Yamin [EMAIL PROTECTED]

diff -urp linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/ata.h linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/ata.h
--- linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/ata.h	2008-04-17 03:49:44.0 +0100
+++ linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/ata.h	2008-07-03 16:17:05.0 +0100
@@ -16,8 +16,8 @@
 
 struct bcom_ata_bd {
 	u32	status;
-	u32	dst_pa;
 	u32	src_pa;
+	u32	dst_pa;
 };
 
 extern struct bcom_task *
diff -urp linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm.h linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/bestcomm.h
--- linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm.h	2008-04-17 03:49:44.0 +0100
+++ linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/bestcomm.h	2008-07-03 16:17:05.0 +0100
@@ -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;
 }
diff -urp linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h
--- linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h	2008-04-17 03:49:44.0 +0100
+++ linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h	2008-07-03 16:17:05.0 +0100
@@ -198,8 +198,8 @@ struct bcom_task_header {
 #define BCOM_IPR_SCTMR_1	2
 #define BCOM_IPR_FEC_RX		6
 #define 

Re: [PATCH]: [MPC5200] (v2) Add ATA DMA support

2008-07-03 Thread Benjamin Herrenschmidt
On Thu, 2008-07-03 at 16:35 +0100, Tim Yamin wrote:
  +static void
  +mpc52xx_bmdma_start(struct ata_queued_cmd *qc)
  +{
  + struct ata_port *ap = qc-ap;
  + struct mpc52xx_ata_priv *priv = ap-host-private_data;
  +
  + /* LocalBus lock */
  + while (test_and_set_bit(0, pata_mpc52xx_ata_dma_lock) != 0)
  + ;
 
  Need to be able to bail on timeout.
 
 A deadlock can't occur within the PATA driver because you won't have
 two DMA requests happening at once, so there is no point in adding a
 timeout. And even if you do have a timeout, you'd have to drop the I/O
 request somehow, so it's not really a good idea. If anything else
 needs to touch the DMA lock, it should do so in a sensible fashion...

But why a hand-coded lock with bitops ? Why not a real spinlock then ?
The later is more efficient anyway.

Ben.


___
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev


Re: [PATCH]: [MPC5200] (v2) Add ATA DMA support

2008-07-03 Thread Grant Likely
On Fri, Jul 04, 2008 at 09:47:03AM +1000, Benjamin Herrenschmidt wrote:
 On Thu, 2008-07-03 at 16:35 +0100, Tim Yamin wrote:
   +static void
   +mpc52xx_bmdma_start(struct ata_queued_cmd *qc)
   +{
   + struct ata_port *ap = qc-ap;
   + struct mpc52xx_ata_priv *priv = ap-host-private_data;
   +
   + /* LocalBus lock */
   + while (test_and_set_bit(0, pata_mpc52xx_ata_dma_lock) != 0)
   + ;
  
   Need to be able to bail on timeout.
  
  A deadlock can't occur within the PATA driver because you won't have
  two DMA requests happening at once, so there is no point in adding a
  timeout. And even if you do have a timeout, you'd have to drop the I/O
  request somehow, so it's not really a good idea. If anything else
  needs to touch the DMA lock, it should do so in a sensible fashion...
 
 But why a hand-coded lock with bitops ? Why not a real spinlock then ?
 The later is more efficient anyway.

Umm, yeah (don't know why I didn't clue into that).  This definitely
should be a spinlock.

g.
___
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev


Re: [PATCH]: [MPC5200] (v2) Add ATA DMA support

2008-07-03 Thread Grant Likely
On Thu, Jul 03, 2008 at 04:35:27PM +0100, Tim Yamin wrote:
 There's also what I believe to be a hardware bug if you have high levels
 of BestComm ATA DMA activity along with heavy LocalPlus Bus activity;
 the address bus seems to sometimes get corrupted with ATA commands while
 the LocalPlus Bus operation is still active (i.e. Chip Select is asserted).
 
 I've asked Freescale about this but have not received a reply yet -- if
 anybody from Freescale has any ideas please contact me; I can supply some
 analyzer traces if needed. Therefore, for now, do not enable DMA if you
 need reliable LocalPlus Bus unless you do a fixup in your driver as
 follows:
 
 Locking example:
 
 while (test_and_set_bit(0, pata_mpc52xx_ata_dma_lock) != 0)
 {
 struct bcom_task_2 *tsk = pata_mpc52xx_ata_dma_task;
 
 if(bcom_buffer_done_2(tsk))
 return 1;
 }
 
   return 0;
 
 (Save the return value to `flags`)
 
 Unlocking example:
 
 if(flags == 0)
 clear_bit(0, pata_mpc52xx_ata_dma_lock);
 

One more thing.  For this description to be of any use, it needs to be
documented where somebody will actually see it.  The commit message is
great for describing *why* a change is needed, but it's not seen
so much after the change is merged.

This description should probably be added to the header comment block of
the ATA driver, and it should be talked about in the Kconfig help text
too.

g.
___
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev


Re: [PATCH]: [MPC5200] (v2) Add ATA DMA support

2008-07-02 Thread Tim Yamin
Hi Grant,

Thanks for the feedback. New version is attached.

 Is this a bug fix?  If so, please put it into a separate patch.

I suppose so, yes. If Ethernet has higher priority than ATA, you can
get a deadlock if you try and download a large file over a LAN to
disk, for example. But given that nothing other than this patch uses
BestComm for ATA do you have any specific reason to split it out into
another patch?

 Good, it can be turned off.  Do you think there is any risk to existing
 ATA users with this patch applied if this is turned off?

With the new version, the only risk if this is turned off is the
change I've made to bestcomm.h. Other than that, you should get no
risk because none of the new
code is executed (mwdma_mask and udma_mask are set to 0 if the option
is turned off).

 Can you find any way to avoid this?  This could be a performance drain.

Previous code had this, so I kept it. Things do seem to work OK
without it, so I've removed it...

 Is there any way to turn on/off DMA at runtime instead of CONFIG time?

You could use libata.dma=0 to force DMA off even if it's enabled at CONFIG time.

   priv-ipb_period = 10 / (ipb_freq / 1000);
   priv-ata_regs = ata_regs;
 + priv-ata_regs_pa = (struct mpc52xx_ata __iomem *) res_mem.start;

 I'm not fond of this.  First off, it is *not* __iomem.  It is physical
 address.  It would be better to use the offset_of macro to add an offset
 to the physical base address.  Doing it this way forces you to cast and
 sidestep the compile time checks for incorrect dereferences.

I'm afraid I'm not quite sure what you have in mind here, could you
please provide a pointer?

Thanks,

Tim
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.

Using a SanDisk Extreme IV CF card I get read speeds of approximately
26.70 MB/sec.

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.

There's also what I believe to be a hardware bug if you have high levels
of BestComm ATA DMA activity along with heavy LocalPlus Bus activity;
the address bus seems to sometimes get corrupted with ATA commands while
the LocalPlus Bus operation is still active (i.e. Chip Select is asserted).

I've asked Freescale about this but have not received a reply yet -- if
anybody from Freescale has any ideas please contact me; I can supply some
analyzer traces if needed. Therefore, for now, do not enable DMA if you
need reliable LocalPlus Bus unless you do a fixup in your driver as
follows:

Locking example:

while (test_and_set_bit(0, pata_mpc52xx_ata_dma_lock) != 0)
{
struct bcom_task_2 *tsk = pata_mpc52xx_ata_dma_task;

if(bcom_buffer_done_2(tsk))
return 1;
}

	return 0;

(Save the return value to `flags`)

Unlocking example:

if(flags == 0)
clear_bit(0, pata_mpc52xx_ata_dma_lock);

Comments and testing would of course be very welcome.

Thanks,

Signed-off-by: Tim Yamin [EMAIL PROTECTED]

diff -urp linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/ata.h linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/ata.h
--- linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/ata.h	2008-04-17 03:49:44.0 +0100
+++ linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/ata.h	2008-07-02 12:48:14.0 +0100
@@ -16,8 +16,8 @@
 
 struct bcom_ata_bd {
 	u32	status;
-	u32	dst_pa;
 	u32	src_pa;
+	u32	dst_pa;
 };
 
 extern struct bcom_task *
diff -urp linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm.c linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/bestcomm.c
--- linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm.c	2008-04-17 03:49:44.0 +0100
+++ linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/bestcomm.c	2008-07-02 12:48:14.0 +0100
@@ -330,11 +330,16 @@ bcom_engine_init(void)
 	/* Init 'always' initiator */
 	out_8(bcom_eng-regs-ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS);
 
+	/* If ATA DMA is enabled, always turn prefetch off (it breaks things) */
+#ifndef CONFIG_PATA_MPC52xx_DMA
 	/* Disable COMM Bus Prefetch on the original 5200; it's broken */
 	if ((mfspr(SPRN_SVR)  MPC5200_SVR_MASK) == MPC5200_SVR) {
+#endif
 		regval = in_be16(bcom_eng-regs-PtdCntrl);
 		out_be16(bcom_eng-regs-PtdCntrl,  regval | 1);
+#ifndef CONFIG_PATA_MPC52xx_DMA
 	}
+#endif
 
 	/* Init lock */
 	spin_lock_init(bcom_eng-lock);
diff -urp linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm.h linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/bestcomm.h
--- linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm.h	2008-04-17 03:49:44.0 +0100
+++ linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/bestcomm.h	2008-07-02 12:48:14.0 +0100
@@ -140,15 +140,29 @@ 

Re: [PATCH]: [MPC5200] (v2) Add ATA DMA support

2008-07-01 Thread Grant Likely
On Fri, Jun 27, 2008 at 01:44:08PM +0100, Tim Yamin wrote:
 diff -Nurp linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm.c 
 linux-2.6.26-rc6.new/arch/powerpc/sysdev/bestcomm/bestcomm.c
 --- linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm.c  2008-03-18 
 15:49:53.0 +
 +++ linux-2.6.26-rc6.new/arch/powerpc/sysdev/bestcomm/bestcomm.c  
 2008-04-15 10:42:38.0 +0100
 @@ -330,11 +330,10 @@
   /* Init 'always' initiator */
   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);
 - }
 + /* Disable COMM Bus Prefetch; ATA DMA does not work properly with it
 +enabled. */
 + regval = in_be16(bcom_eng-regs-PtdCntrl);
 + out_be16(bcom_eng-regs-PtdCntrl, regval | 1);

This could have a performance impact on existing systems that don't
use/need ATA DMA.

Please run next version through checkpatch.  There's lots of minor
cosmetic stuff, but there are also a few important errors.

 diff -Nurp linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm.h 
 linux-2.6.26-rc6.new/arch/powerpc/sysdev/bestcomm/bestcomm.h
 --- linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm.h  2008-03-18 
 15:49:53.0 +
 +++ linux-2.6.26-rc6.new/arch/powerpc/sysdev/bestcomm/bestcomm.h  
 2008-04-15 10:42:38.0 +0100
 @@ -17,6 +17,7 @@
  #define __BESTCOMM_H__
  
  struct bcom_bd; /* defined later on ... */
 +struct bcom_bd_2;
  
  
  /*  
 */
 @@ -49,6 +50,22 @@
   void*   priv;
  };
  
 +struct bcom_task_2 {
 + unsigned inttasknum;
 + unsigned intflags;
 + int irq;
 +
 + struct bcom_bd_2*bd;
 + phys_addr_t bd_pa;
 + void**cookie;
 + unsigned short  index;
 + unsigned short  outdex;
 + unsigned intnum_bd;
 + unsigned intbd_size;
 +
 + void*   priv;
 +};
 +

Oh, ugly.  The only difference seems to be that bcom_bd_2 is 1 word
larger than bcom_bd.  There must be a better way to do this rather
than just duplicating all the functions and structures..  It would
probably be better to use bd_size to determine how to dereference an
index into the *bd list.  It will require a bit of refactoring, but
it will be much cleaner and more maintainable that way.

 diff -Nurp linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h 
 linux-2.6.26-rc6.new/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h
 --- linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h 
 2008-03-18 15:49:53.0 +
 +++ linux-2.6.26-rc6.new/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h 
 2008-04-15 10:42:38.0 +0100
 @@ -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_RX2
  #define BCOM_IPR_SCPCI_TX2
  #define BCOM_IPR_PSC3_RX 2

Is this a bug fix?  If so, please put it into a separate patch.

 diff -Nurp linux-2.6.26-rc6/drivers/ata/Kconfig 
 linux-2.6.26-rc6.new/drivers/ata/Kconfig
 --- linux-2.6.26-rc6/drivers/ata/Kconfig  2008-03-18 15:49:33.0 
 +
 +++ linux-2.6.26-rc6.new/drivers/ata/Kconfig  2008-04-15 10:41:51.0 
 +0100
 @@ -462,6 +462,15 @@
  
 If unsure, say N.
  
 +config PATA_MPC52xx_DMA
 + tristate Freescale MPC52xx SoC internal IDE DMA
 + depends on PATA_MPC52xx
 + help
 +   This option enables support for DMA on the MPC52xx SoC PATA
 +   controller.
 +
 +   If unsure, say N.
 +

Good, it can be turned off.  Do you think there is any risk to existing
ATA users with this patch applied if this is turned off?

  config PATA_MPIIX
   tristate Intel PATA MPIIX support
   depends on PCI
 diff -Nurp linux-2.6.26-rc6/drivers/ata/pata_mpc52xx.c 
 linux-2.6.26-rc6.new/drivers/ata/pata_mpc52xx.c
 --- linux-2.6.26-rc6/drivers/ata/pata_mpc52xx.c   2008-03-18 
 15:49:33.0 +
 +++ linux-2.6.26-rc6.new/drivers/ata/pata_mpc52xx.c   2008-04-15 
 10:41:49.0 +0100
 @@ -6,6 +6,9 @@
   * Copyright (C) 2006 Sylvain Munaut [EMAIL PROTECTED]
   * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt
   *
 + * UDMA support based on patches by Freescale (Bernard Kuhn, John Rigby),
 + * Domen Puncer and Tim Yamin.
 + *
   * This file is licensed under the terms of the GNU General Public License
   * version 2. This program is licensed as is without any warranty of any
   * kind, whether express or implied.
 @@ -17,28 +20,47 @@
  #include 

RE: [PATCH]: [MPC5200] (v2) Add ATA DMA support

2008-06-30 Thread Daniel Schnell
Hi,

Against which kernel is this patch against ?



Regards,

Daniel.


Tim Yamin wrote:
 Changes from previous version:
 
 - Add FIFO status error checking code before a DMA transaction starts
 and after it is completed. 
 - Fix an incorrect check in the previous patch causing spurious dma
 table too small errors. 
 
 Tim
___
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev