[PATCH] libertas: add abilty to set DMA buffers alignmnet for SPI interface in compile time

Andrey Yurovsky andrey at cozybit.com
Tue Feb 3 11:17:12 EST 2009


On Tue, Feb 3, 2009 at 7:47 AM, Dan Williams <dcbw at redhat.com> wrote:
> On Tue, 2009-02-03 at 09:04 +0200, Mike Rapoport wrote:
>> Different SPI controllers pose different alignment requirements on DMAable
>> buffers. It's possible to alter the SPI controller driver to use it's own
>> properly aligned buffers for DMA and copy the data it gets from the client
>> into these buffers. However, this approach also impacts overall performance.
>> Adding ability to set DMA buffers alignment for SPI interface in compile
>> time prevents unnecessary memcpy calls.
>
> I'd still rather that alignment constraints were handled in the
> *controller* code, where the constraint actually is.  If this path is
> followed, then every SPI-connected device for a platform would have to
> have specific hacks for every platform, which is quite unmaintainable.
> Is there a good way to fit the alignment constraints into the SPI
> controller code?
>
> Dan

"struct spi_device" currently stores things like the IRQ number (ie:
"spi->irq"), how about we add an optional field to struct spi_device,
something like "dma_alignment" that drivers can use as a hint?  On PXA
it would be set to 8, on Blackfin it can be left at 0 or set to 4 or
something.

In our case we have:
- a device that needs ALIGN(4) or a multiple of 4 to work
- a controller that wants ALIGN(8)

So our if_spi_probe would then use the spi->dma_alignment field to
choose a sane value to use with ALIGN.  This would work for run-time
stuff but it wouldn't help us align a static buffer correctly while
Mike's approach would, though we could do something fancy to align
that too.  What do you think?  Thanks,

  -Andrey

>> Signed-off-by: Mike Rapoport <mike at compulab.co.il>
>> ---
>>  drivers/net/wireless/Kconfig           |   10 ++++++++++
>>  drivers/net/wireless/libertas/if_spi.c |   27 ++++++++++++++++-----------
>>  2 files changed, 26 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
>> index fe819a7..3bbb7b2 100644
>> --- a/drivers/net/wireless/Kconfig
>> +++ b/drivers/net/wireless/Kconfig
>> @@ -157,6 +157,16 @@ config LIBERTAS_SPI
>>       ---help---
>>         A driver for Marvell Libertas 8686 SPI devices.
>>
>> +config LIBERTAS_SPI_DMA_ALIGN
>> +     int "DMA buffers alignment for SPI interface"
>> +     depends on LIBERTAS_SPI
>> +     default 4 if !ARCH_PXA
>> +     default 8 if ARCH_PXA
>> +     ---help---
>> +       Different SPI controllers pose different alignment
>> +       requirements on DMAable buffers. Allow proper setting of
>> +       this value in compile-time.
>> +
>>  config LIBERTAS_DEBUG
>>       bool "Enable full debugging output in the Libertas module."
>>       depends on LIBERTAS
>> diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
>> index 07311e7..3499948 100644
>> --- a/drivers/net/wireless/libertas/if_spi.c
>> +++ b/drivers/net/wireless/libertas/if_spi.c
>> @@ -33,10 +33,12 @@
>>  #include "dev.h"
>>  #include "if_spi.h"
>>
>> +#define DMA_ALIGN CONFIG_LIBERTAS_SPI_DMA_ALIGN
>> +
>>  struct if_spi_packet {
>> -     struct list_head                list;
>> -     u16                             blen;
>> -     u8                              buffer[0] __attribute__((aligned(4)));
>> +     struct list_head        list;
>> +     u16                     blen;
>> +     u8                      buffer[0] __attribute__((aligned(DMA_ALIGN)));
>>  };
>>
>>  struct if_spi_card {
>> @@ -73,7 +75,7 @@ struct if_spi_card {
>>       struct semaphore                spi_ready;
>>       struct semaphore                spi_thread_terminated;
>>
>> -     u8                              cmd_buffer[IF_SPI_CMD_BUF_SIZE];
>> +     u8                              cmd_buffer[IF_SPI_CMD_BUF_SIZE] __attribute__((aligned(DMA_ALIGN)));
>>
>>       /* A buffer of incoming packets from libertas core.
>>        * Since we can't sleep in hw_host_to_card, we have to buffer
>> @@ -665,10 +667,13 @@ static int if_spi_c2h_cmd(struct if_spi_card *card)
>>       BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_CMD_BUFFER_SIZE);
>>       BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_UPLD_SIZE);
>>
>> -     /* It's just annoying if the buffer size isn't a multiple of 4, because
>> -      * then we might have len <  IF_SPI_CMD_BUF_SIZE but
>> -      * ALIGN(len, 4) > IF_SPI_CMD_BUF_SIZE */
>> -     BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE % 4 != 0);
>> +     /*
>> +      * It's just annoying if the buffer size isn't a multiple of
>> +      * DMA_ALIGN, because then we might have
>> +      * len < IF_SPI_CMD_BUF_SIZE but
>> +      * ALIGN(len, DMA_ALIGN) > IF_SPI_CMD_BUF_SIZE
>> +      */
>> +     BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE % DMA_ALIGN != 0);
>>
>>       lbs_deb_enter(LBS_DEB_SPI);
>>
>> @@ -691,7 +696,7 @@ static int if_spi_c2h_cmd(struct if_spi_card *card)
>>
>>       /* Read the data from the WLAN module into our command buffer */
>>       err = spu_read(card, IF_SPI_CMD_RDWRPORT_REG,
>> -                             card->cmd_buffer, ALIGN(len, 4));
>> +                             card->cmd_buffer, ALIGN(len, DMA_ALIGN));
>>       if (err)
>>               goto out;
>>
>> @@ -747,7 +752,7 @@ static int if_spi_c2h_data(struct if_spi_card *card)
>>       data = skb_put(skb, len);
>>
>>       /* Read the data from the WLAN module into our skb... */
>> -     err = spu_read(card, IF_SPI_DATA_RDWRPORT_REG, data, ALIGN(len, 4));
>> +     err = spu_read(card, IF_SPI_DATA_RDWRPORT_REG, data, ALIGN(len, DMA_ALIGN));
>>       if (err)
>>               goto free_skb;
>>
>> @@ -940,7 +945,7 @@ static int if_spi_host_to_card(struct lbs_private *priv,
>>               err = -EINVAL;
>>               goto out;
>>       }
>> -     blen = ALIGN(nb, 4);
>> +     blen = ALIGN(nb, DMA_ALIGN);
>>       packet = kzalloc(sizeof(struct if_spi_packet) + blen, GFP_ATOMIC);
>>       if (!packet) {
>>               err = -ENOMEM;
>> --
>> 1.5.6.4
>>
>>
>> --
>> Sincerely yours,
>> Mike.
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



More information about the libertas-dev mailing list