All of lore.kernel.org
 help / color / mirror / Atom feed
* possible bug in pxa2xx_spi.c
@ 2009-03-16 12:32 iw3gtf-IWqWACnzNjyonA0d6jMUrA
  0 siblings, 0 replies; only message in thread
From: iw3gtf-IWqWACnzNjyonA0d6jMUrA @ 2009-03-16 12:32 UTC (permalink / raw)
  To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

Hi,
I think I've found a bug in the pxa2xx_spi driver.

I'm running a linux 2.6.28.7 kernel on a pxa320 arm cpu with an m25p80 flash

connected to the cpu through the port ssp4.
If I configure the system to run in pio mode (dma disabled):

static struct pxa2xx_spi_master

pxa_ssp4_master_info = {
  .clock_enable = CKEN_SSP4, // SSP4 Peripheral clock
  .num_chipselect = 1, // Matches the number of chips 
attached to SSP4
  .enable_dma = 0, // Disables SSP4 DMA
};

static struct platform_device pxa_spi_ssp4 = {
  .name = "pxa2xx-spi", // MUST 
BE THIS VALUE, so device match driver
  .id = 4, // Bus number, MUST MATCH SSP number 1..n
  .dev = {
    .platform_data = 
&pxa_ssp4_master_info, // Passed to the controller driver
  },
};

I can correctly operate with the flash (using the mtd interface).



Nevertheless, if I enable the dma I have problems: the mtd->write(...)
function returns an absurd value in its fourth argument, the count

of successfully written bytes.

I could track this problem down to the source file:

drivers/spi/pxa2xx_spi.c

Assume we call the method 
mtd->write(...) to write 32 bytes to the flash.
The m25p80 driver prepares a struct spi_message with a couple of transfers in it and

inserts it in a message queue for the ssp controller driver.
The message is then extracted from the queue within the function

pxa2xx_spi.c:
pump_transfers(unsigned long data)

the message contains 2 transfers: the 'flash program' command and the
real 'bytes to be written' 
transfer.
The struct spi_transfer for this second transfer has the following setup:

transfer->tx_buf: 0xcf1c80c0 (a valid pointer)

transfer->rx_buf: 0x00000000
transfer->len: 32

the rx_buf is a null pointer because we don't want to read anything from the flash.
With 
this (I think valid) setup and with the dma enabled something wrong happens:
the tranfer is copied to the struct driver_data drv_data:


drv_data->tx = (void *)transfer->tx_buf;
drv_data->tx_end = drv_data->tx + transfer->len;
drv_data->rx = transfer->rx_buf;
drv_data->rx_end 
= drv_data->rx + transfer->len;

this way the field drv_data->rx gets a null and drv_data->rx_end gets 0 + 32 = 32:

...
drv_data->rx = 0

drv_data->rx_end = 32
...

sometime later the rx buffer must be dma mapped within the function:

pxa2xx_spi.c:map_dma_buffers(struct 
driver_data *drv_data)


/* Modify setup if rx buffer is null */
if (drv_data->rx == NULL) {
  *drv_data->null_dma_buf = 0;
  drv_data->rx 
= drv_data->null_dma_buf;
  drv_data->rx_map_len = 4;
} else
  drv_data->rx_map_len = drv_data->len;

being a null pointer the drv_data->rx 
gets a dummy, but dma valid, pointer value
(drv_data->null_dma_buf) and the transfer can now start with dma.
When finished the function:


pxa2xx_spi.c:dma_transfer_complete(struct driver_data *drv_data)

is called and here we have the following wrong computations:

drv_data-
>rx += drv_data->len -
  (DCMD(drv_data->rx_channel) & DCMD_LENGTH);


/* read trailing data from fifo, it does not matter how many
 * 
bytes are in the fifo just read until buffer is full
 * or fifo is empty, which ever occurs first */

 drv_data->read(drv_data);

/* return 
count of what was actually read */
 msg->actual_length += drv_data->len -
   (drv_data->rx_end - drv_data->rx);

drv_data->rx has the dummy 
pointer value (somewhere around 0xc03d6a28 for me) but
drv_data->rx_end still has the value 32!!!

drv_data->rx: 0xc03d6a28+...
drv_data-
>rx_end: 32

from this values we get an absurd result for msg->actual_length.

A fix for this problem could be to also update the drv_data-
>rx_end
field in the call to

pxa2xx_spi.c:map_dma_buffers(struct driver_data *drv_data)


/* Modify setup if rx buffer is null */
if 
(drv_data->rx == NULL) {
  *drv_data->null_dma_buf = 0;
  drv_data->rx = drv_data->null_dma_buf;
  drv_data->rx_end = drv_data->rx + 
drv_data->len; <======== fix
  drv_data->rx_map_len = 4;
} else
  drv_data->rx_map_len = drv_data->len;


I have also a second question 
about pxa2xx_spi.c: the value of the
dummy dma pointer 'drv_data->null_dma_buf' is assigned as follows in:

pxa2xx_spi.c:pxa2xx_spi_probe
(struct platform_device *pdev)


drv_data->null_dma_buf =
  (u32 *)ALIGN((u32)(drv_data + sizeof(struct driver_data)), 8);

is this address 
safe to write to? Or could we potentially overwrite
something already allocated there ?

thanks for your attention.

best regards

giorgio



Con Tiscali Tutto Incluso telefoni e navighi senza limiti A SOLI €10 AL MESE FINO ALL’ESTATE. 

Attiva entro il 18/03/09! http://abbonati.tiscali.it/promo/tuttoincluso/

------------------------------------------------------------------------------
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
_______________________________________________
spi-devel-general mailing list
spi-devel-general@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2009-03-16 12:32 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-16 12:32 possible bug in pxa2xx_spi.c iw3gtf-IWqWACnzNjyonA0d6jMUrA

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.