Re: [PATCH v3 4/4] powerpc/mpc5200: Add mpc5200-spi (non-PSC) device driver

2008-07-27 Thread David Brownell
On Friday 25 July 2008, Grant Likely wrote:
 From: Grant Likely [EMAIL PROTECTED]
 
 Adds support for the dedicated SPI device on the Freescale MPC5200(b)
 SoC.

It'd be a bit more clear if you said dedicated SPI controller;
device sounds like it's a struct spi_device.

Capsule summary:  fault handling needs work.  (Details below.)


 Signed-off-by: Grant Likely [EMAIL PROTECTED]
 ---
 
  drivers/spi/Kconfig |8 +
  drivers/spi/Makefile|1 
  drivers/spi/mpc52xx_spi.c   |  595 
 +++
  include/linux/spi/mpc52xx_spi.h |   10 +
  4 files changed, 614 insertions(+), 0 deletions(-)
 
 diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
 index 2303521..68e4a4a 100644
 --- a/drivers/spi/Kconfig
 +++ b/drivers/spi/Kconfig
 @@ -116,6 +116,14 @@ config SPI_LM70_LLP
 which interfaces to an LM70 temperature sensor using
 a parallel port.
  
 +config SPI_MPC52xx
 + tristate Freescale MPC52xx SPI (non-PSC) controller support
 + depends on PPC_MPC52xx  SPI
 + select SPI_MASTER_OF
 + help
 +   This drivers supports the MPC52xx SPI controller in master SPI
 +   mode.
 +
  config SPI_MPC52xx_PSC
   tristate Freescale MPC52xx PSC SPI controller
   depends on PPC_MPC52xx  EXPERIMENTAL
 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
 index 7fca043..340b878 100644
 --- a/drivers/spi/Makefile
 +++ b/drivers/spi/Makefile
 @@ -22,6 +22,7 @@ obj-$(CONFIG_SPI_PXA2XX)+= pxa2xx_spi.o
  obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o
  obj-$(CONFIG_SPI_OMAP24XX)   += omap2_mcspi.o
  obj-$(CONFIG_SPI_MPC52xx_PSC)+= mpc52xx_psc_spi.o
 +obj-$(CONFIG_SPI_MPC52xx)+= mpc52xx_spi.o
  obj-$(CONFIG_SPI_MPC83xx)+= spi_mpc83xx.o
  obj-$(CONFIG_SPI_S3C24XX_GPIO)   += spi_s3c24xx_gpio.o
  obj-$(CONFIG_SPI_S3C24XX)+= spi_s3c24xx.o
 diff --git a/drivers/spi/mpc52xx_spi.c b/drivers/spi/mpc52xx_spi.c
 new file mode 100644
 index 000..453690f
 --- /dev/null
 +++ b/drivers/spi/mpc52xx_spi.c
 @@ -0,0 +1,595 @@
 +/*
 + * MPC52xx SPI master driver.
 + * Copyright (C) 2008 Secret Lab Technologies Ltd.
 + *
 + * This is the driver for the MPC5200's dedicated SPI device (not for a
 + * PSC in SPI mode)
 + */
 +
 +#include linux/module.h
 +#include linux/init.h
 +#include linux/errno.h
 +#include linux/of_platform.h
 +#include linux/interrupt.h
 +#include linux/delay.h
 +#include linux/spi/spi.h
 +#include linux/spi/mpc52xx_spi.h
 +#include linux/of_spi.h
 +#include linux/io.h
 +#include asm/time.h
 +#include asm/mpc52xx.h
 +
 +MODULE_AUTHOR(Grant Likely [EMAIL PROTECTED]);
 +MODULE_DESCRIPTION(MPC52xx SPI (non-PSC) Driver);
 +MODULE_LICENSE(GPL);
 +
 +/* Register offsets */
 +#define SPI_CTRL10x00
 +#define SPI_CTRL1_SPIE   (1  7)
 +#define SPI_CTRL1_SPE(1  6)
 +#define SPI_CTRL1_MSTR   (1  4)
 +#define SPI_CTRL1_CPOL   (1  3)
 +#define SPI_CTRL1_CPHA   (1  2)
 +#define SPI_CTRL1_SSOE   (1  1)
 +#define SPI_CTRL1_LSBFE  (1  0)
 +
 +#define SPI_CTRL20x01
 +#define SPI_BRR  0x04
 +
 +#define SPI_STATUS   0x05
 +#define SPI_STATUS_SPIF  (1  7)
 +#define SPI_STATUS_WCOL  (1  6)
 +#define SPI_STATUS_MODF  (1  4)
 +
 +#define SPI_DATA 0x09
 +#define SPI_PORTDATA 0x0d
 +#define SPI_DATADIR  0x10
 +
 +/* FSM state return values */
 +#define FSM_STOP 0
 +#define FSM_POLL 1
 +#define FSM_CONTINUE 2
 +
 +/* Driver internal data */
 +struct mpc52xx_spi {
 + struct spi_master *master;
 + u32 sysclk;
 + void __iomem *regs;
 + int irq0;   /* MODF irq */
 + int irq1;   /* SPIF irq */
 + int ipb_freq;
 +
 + /* Statistics */
 + int msg_count;
 + int wcol_count;
 + int wcol_ticks;
 + u32 wcol_tx_timestamp;
 + int modf_count;
 + int byte_count;
 +
 + /* Hooks for platform modification of behaviour */
 + void (*premessage)(struct spi_message *m, void *context);
 + void *premessage_context;
 +
 + struct list_head queue; /* queue of pending messages */
 + spinlock_t lock;
 + struct work_struct work;
 +
 +
 + /* Details of current transfer (length, and buffer pointers) */
 + struct spi_message *message;/* current message */
 + struct spi_transfer *transfer;  /* current transfer */
 + int (*state)(int irq, struct mpc52xx_spi *ms, u8 status, u8 data);
 + int len;
 + int timestamp;
 + u8 *rx_buf;
 + const u8 *tx_buf;
 + int cs_change;
 +};
 +
 +/*
 + * CS control function
 + */
 +static void mpc52xx_spi_chipsel(struct mpc52xx_spi *ms, int value)
 +{
 + if (value)
 + writeb(0, ms-regs + SPI_PORTDATA); /* Assert SS pin */
 + else
 + writeb(0x08, ms-regs + SPI_PORTDATA); /* Deassert SS pin */
 +}
 +
 +/*
 + * Start a new transfer.  This is called both by 

Re: [PATCH v3 4/4] powerpc/mpc5200: Add mpc5200-spi (non-PSC) device driver

2008-07-25 Thread Daniel Walker
On Fri, 2008-07-25 at 03:33 -0400, Grant Likely wrote:

 + if (status  (irq != NO_IRQ))
 + dev_err(ms-master-dev, spurious irq, status=0x%.2x\n,
 + status);
 +
 + /* Check if there is another transfer waiting */
 + if (list_empty(ms-queue))
 + return FSM_STOP;

I don't think doing list_empty outside the critical section is totally
safe.. You might want to move it down inside the spin_lock() section.

 + /* Get the next message */
 + spin_lock(ms-lock);

The part that's a little confusing here is that the interrupt can
actually activate the workqueue .. So I'm wondering if maybe you could
have this interrupt driven any workqueue driven at the same time? If you
could then you would need the above to be 
spin_lock_irq/spin_lock_irqsave ..

Daniel

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


Re: [PATCH v3 4/4] powerpc/mpc5200: Add mpc5200-spi (non-PSC) device driver

2008-07-25 Thread Grant Likely
On Fri, Jul 25, 2008 at 2:19 PM, Daniel Walker [EMAIL PROTECTED] wrote:
 On Fri, 2008-07-25 at 03:33 -0400, Grant Likely wrote:

 + if (status  (irq != NO_IRQ))
 + dev_err(ms-master-dev, spurious irq, status=0x%.2x\n,
 + status);
 +
 + /* Check if there is another transfer waiting */
 + if (list_empty(ms-queue))
 + return FSM_STOP;

 I don't think doing list_empty outside the critical section is totally
 safe.. You might want to move it down inside the spin_lock() section.

This should be fine.  This is the only place where items are dequeued,
and it will only ever be called from the ISR or the work queue.  The
work queue and IRQ will never be active at the same time (I'll add a
comment to the fact).  It also looks like list_empty is perfectly safe
to call without the protection of a spin lock (but somebody correct me
if I'm out to lunch).  It doesn't dereference any of the pointers in
the list_head structure.


 + /* Get the next message */
 + spin_lock(ms-lock);

 The part that's a little confusing here is that the interrupt can
 actually activate the workqueue .. So I'm wondering if maybe you could
 have this interrupt driven any workqueue driven at the same time? If you
 could then you would need the above to be
 spin_lock_irq/spin_lock_irqsave ..

Ditto here, since the irq and workqueue are not enabled at the same
time there is no worry about collision.

Cheers,
g.



-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
___
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev


Re: [PATCH v3 4/4] powerpc/mpc5200: Add mpc5200-spi (non-PSC) device driver

2008-07-25 Thread Daniel Walker
On Fri, 2008-07-25 at 22:45 -0400, Grant Likely wrote:
 On Fri, Jul 25, 2008 at 2:19 PM, Daniel Walker [EMAIL PROTECTED] wrote:
  On Fri, 2008-07-25 at 03:33 -0400, Grant Likely wrote:
 
  + if (status  (irq != NO_IRQ))
  + dev_err(ms-master-dev, spurious irq, status=0x%.2x\n,
  + status);
  +
  + /* Check if there is another transfer waiting */
  + if (list_empty(ms-queue))
  + return FSM_STOP;
 
  I don't think doing list_empty outside the critical section is totally
  safe.. You might want to move it down inside the spin_lock() section.
 
 This should be fine.  This is the only place where items are dequeued,
 and it will only ever be called from the ISR or the work queue.  The
 work queue and IRQ will never be active at the same time (I'll add a
 comment to the fact).  It also looks like list_empty is perfectly safe
 to call without the protection of a spin lock (but somebody correct me
 if I'm out to lunch).  It doesn't dereference any of the pointers in
 the list_head structure.

The list_empty wouldn't crash, but the result isn't necessarily
accurate.

 
  + /* Get the next message */
  + spin_lock(ms-lock);
 
  The part that's a little confusing here is that the interrupt can
  actually activate the workqueue .. So I'm wondering if maybe you could
  have this interrupt driven any workqueue driven at the same time? If you
  could then you would need the above to be
  spin_lock_irq/spin_lock_irqsave ..
 
 Ditto here, since the irq and workqueue are not enabled at the same
 time there is no worry about collision.

Why are you waking up the work queue from inside the irq handler? You
might also want to break out the handling from inside the irq handler
and call that from the workqueue, instead of re-calling the irq handler
function from the workqueue.. It's a little confusing from a context
perspective.

Daniel

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


Re: [PATCH v3 4/4] powerpc/mpc5200: Add mpc5200-spi (non-PSC) device driver

2008-07-25 Thread Grant Likely
On Sat, Jul 26, 2008 at 12:47 AM, Daniel Walker [EMAIL PROTECTED] wrote:
 On Fri, 2008-07-25 at 22:45 -0400, Grant Likely wrote:
 On Fri, Jul 25, 2008 at 2:19 PM, Daniel Walker [EMAIL PROTECTED] wrote:
  On Fri, 2008-07-25 at 03:33 -0400, Grant Likely wrote:
 
  + if (status  (irq != NO_IRQ))
  + dev_err(ms-master-dev, spurious irq, status=0x%.2x\n,
  + status);
  +
  + /* Check if there is another transfer waiting */
  + if (list_empty(ms-queue))
  + return FSM_STOP;
 
  I don't think doing list_empty outside the critical section is totally
  safe.. You might want to move it down inside the spin_lock() section.

 This should be fine.  This is the only place where items are dequeued,
 and it will only ever be called from the ISR or the work queue.  The
 work queue and IRQ will never be active at the same time (I'll add a
 comment to the fact).  It also looks like list_empty is perfectly safe
 to call without the protection of a spin lock (but somebody correct me
 if I'm out to lunch).  It doesn't dereference any of the pointers in
 the list_head structure.

 The list_empty wouldn't crash, but the result isn't necessarily
 accurate.

It doesn't need to be accurate because the spinlock is obtained before
actually trying to dequeue anything.  Even if it held the spinlock
there would still be uncertainty depending on which routine ran first.
 If this function ran first, then it's going to stop the state machine
regardless and the enqueue function will have to kick it off again
anyway.

But, I've taken a look at the code, and you're right, the spin lock
does need to be held while running the state machine because I do have
a case where the IRQ and workqueue could get executed at the same
time.  I'll fix it up.


 
  + /* Get the next message */
  + spin_lock(ms-lock);
 
  The part that's a little confusing here is that the interrupt can
  actually activate the workqueue .. So I'm wondering if maybe you could
  have this interrupt driven any workqueue driven at the same time? If you
  could then you would need the above to be
  spin_lock_irq/spin_lock_irqsave ..

 Ditto here, since the irq and workqueue are not enabled at the same
 time there is no worry about collision.

 Why are you waking up the work queue from inside the irq handler? You
 might also want to break out the handling from inside the irq handler
 and call that from the workqueue, instead of re-calling the irq handler
 function from the workqueue.. It's a little confusing from a context
 perspective.

Sure, I can rework that.  The irq handler would then just simply be a
straight call into the state machine runner.  I just dropped the
additional 4 lines of code for conciseness, but I can change it around
for clarity... actually, with the spin lock stuff above I need to do
this rework.

g.

-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
___
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev