]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
spi: Guarantee cacheline alignment of driver-private data
authorLukas Wunner <lukas@wunner.de>
Wed, 11 Sep 2019 10:15:30 +0000 (12:15 +0200)
committerMark Brown <broonie@kernel.org>
Wed, 11 Sep 2019 14:53:11 +0000 (15:53 +0100)
__spi_alloc_controller() uses a single allocation to accommodate struct
spi_controller and the driver-private data, but places the latter behind
the former.  This order does not guarantee cacheline alignment of the
driver-private data.  (It does guarantee cacheline alignment of struct
spi_controller but the structure doesn't make any use of that property.)

Round up struct spi_controller to cacheline size.  A forthcoming commit
leverages this to grant DMA access to driver-private data of the BCM2835
SPI master.

An alternative, less economical approach would be to use two allocations.

A third approach consists of reversing the order to conserve memory.
But Mark Brown is concerned that it may result in a performance penalty
on architectures that don't like unaligned accesses.

Signed-off-by: Lukas Wunner <lukas@wunner.de>
Link: https://lore.kernel.org/r/01625b9b26b93417fb09d2c15ad02dfe9cdbbbe5.1568187525.git.lukas@wunner.de
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi.c

index b2890923d25698f677bce349e144169a2058a727..f8b4654a57d3950f9678e0b3df0de8ddbfe4bee5 100644 (file)
@@ -2188,8 +2188,10 @@ extern struct class spi_slave_class;     /* dummy */
  * __spi_alloc_controller - allocate an SPI master or slave controller
  * @dev: the controller, possibly using the platform_bus
  * @size: how much zeroed driver-private data to allocate; the pointer to this
- *     memory is in the driver_data field of the returned device,
- *     accessible with spi_controller_get_devdata().
+ *     memory is in the driver_data field of the returned device, accessible
+ *     with spi_controller_get_devdata(); the memory is cacheline aligned;
+ *     drivers granting DMA access to portions of their private data need to
+ *     round up @size using ALIGN(size, dma_get_cache_alignment()).
  * @slave: flag indicating whether to allocate an SPI master (false) or SPI
  *     slave (true) controller
  * Context: can sleep
@@ -2211,11 +2213,12 @@ struct spi_controller *__spi_alloc_controller(struct device *dev,
                                              unsigned int size, bool slave)
 {
        struct spi_controller   *ctlr;
+       size_t ctlr_size = ALIGN(sizeof(*ctlr), dma_get_cache_alignment());
 
        if (!dev)
                return NULL;
 
-       ctlr = kzalloc(size + sizeof(*ctlr), GFP_KERNEL);
+       ctlr = kzalloc(size + ctlr_size, GFP_KERNEL);
        if (!ctlr)
                return NULL;
 
@@ -2229,7 +2232,7 @@ struct spi_controller *__spi_alloc_controller(struct device *dev,
                ctlr->dev.class = &spi_master_class;
        ctlr->dev.parent = dev;
        pm_suspend_ignore_children(&ctlr->dev, true);
-       spi_controller_set_devdata(ctlr, &ctlr[1]);
+       spi_controller_set_devdata(ctlr, (void *)ctlr + ctlr_size);
 
        return ctlr;
 }