Commit 05dfa5c9 authored by David Mosberger-Tang's avatar David Mosberger-Tang Committed by Greg Kroah-Hartman

usb: host: max3421-hcd: fix "spi_rd8" uses dynamic stack allocation warning

kmalloc the SPI rx and tx data buffers.  This appears to be the only
portable way to guarantee that the buffers are DMA-safe (e.g., in
separate DMA cache-lines).  This patch makes the spi_rdX()/spi_wrX()
non-reentrant, but that's OK because calls to them are guaranteed to
be serialized by the per-HCD SPI-thread.
Reported-by: default avatarkbuild test robot <fengguang.wu@intel.com>
Signed-off-by: default avatarDavid Mosberger <davidm@egauge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 00c5aa17
...@@ -102,6 +102,10 @@ enum scheduling_pass { ...@@ -102,6 +102,10 @@ enum scheduling_pass {
SCHED_PASS_DONE SCHED_PASS_DONE
}; };
struct max3421_dma_buf {
u8 data[2];
};
struct max3421_hcd { struct max3421_hcd {
spinlock_t lock; spinlock_t lock;
...@@ -123,6 +127,12 @@ struct max3421_hcd { ...@@ -123,6 +127,12 @@ struct max3421_hcd {
*/ */
u8 rev; /* chip revision */ u8 rev; /* chip revision */
u16 frame_number; u16 frame_number;
/*
* kmalloc'd buffers guaranteed to be in separate (DMA)
* cache-lines:
*/
struct max3421_dma_buf *tx;
struct max3421_dma_buf *rx;
/* /*
* URB we're currently processing. Must not be reset to NULL * URB we're currently processing. Must not be reset to NULL
* unless MAX3421E chip is idle: * unless MAX3421E chip is idle:
...@@ -332,51 +342,47 @@ max3421_to_hcd(struct max3421_hcd *max3421_hcd) ...@@ -332,51 +342,47 @@ max3421_to_hcd(struct max3421_hcd *max3421_hcd)
static u8 static u8
spi_rd8(struct usb_hcd *hcd, unsigned int reg) spi_rd8(struct usb_hcd *hcd, unsigned int reg)
{ {
struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd);
struct spi_device *spi = to_spi_device(hcd->self.controller); struct spi_device *spi = to_spi_device(hcd->self.controller);
struct spi_transfer transfer; struct spi_transfer transfer;
u8 tx_data[1];
/*
* RX data must be in its own cache-line so it stays flushed
* from the cache until the transfer is complete. Otherwise,
* we get stale data from the cache.
*/
u8 rx_data[SMP_CACHE_BYTES] ____cacheline_aligned;
struct spi_message msg; struct spi_message msg;
memset(&transfer, 0, sizeof(transfer)); memset(&transfer, 0, sizeof(transfer));
spi_message_init(&msg); spi_message_init(&msg);
tx_data[0] = (field(reg, MAX3421_SPI_REG_SHIFT) | max3421_hcd->tx->data[0] =
field(MAX3421_SPI_DIR_RD, MAX3421_SPI_DIR_SHIFT)); (field(reg, MAX3421_SPI_REG_SHIFT) |
field(MAX3421_SPI_DIR_RD, MAX3421_SPI_DIR_SHIFT));
transfer.tx_buf = tx_data; transfer.tx_buf = max3421_hcd->tx->data;
transfer.rx_buf = rx_data; transfer.rx_buf = max3421_hcd->rx->data;
transfer.len = 2; transfer.len = 2;
spi_message_add_tail(&transfer, &msg); spi_message_add_tail(&transfer, &msg);
spi_sync(spi, &msg); spi_sync(spi, &msg);
return rx_data[1]; return max3421_hcd->rx->data[1];
} }
static void static void
spi_wr8(struct usb_hcd *hcd, unsigned int reg, u8 val) spi_wr8(struct usb_hcd *hcd, unsigned int reg, u8 val)
{ {
struct spi_device *spi = to_spi_device(hcd->self.controller); struct spi_device *spi = to_spi_device(hcd->self.controller);
struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd);
struct spi_transfer transfer; struct spi_transfer transfer;
struct spi_message msg; struct spi_message msg;
u8 tx_data[2];
memset(&transfer, 0, sizeof(transfer)); memset(&transfer, 0, sizeof(transfer));
spi_message_init(&msg); spi_message_init(&msg);
tx_data[0] = (field(reg, MAX3421_SPI_REG_SHIFT) | max3421_hcd->tx->data[0] =
field(MAX3421_SPI_DIR_WR, MAX3421_SPI_DIR_SHIFT)); (field(reg, MAX3421_SPI_REG_SHIFT) |
tx_data[1] = val; field(MAX3421_SPI_DIR_WR, MAX3421_SPI_DIR_SHIFT));
max3421_hcd->tx->data[1] = val;
transfer.tx_buf = tx_data; transfer.tx_buf = max3421_hcd->tx->data;
transfer.len = 2; transfer.len = 2;
spi_message_add_tail(&transfer, &msg); spi_message_add_tail(&transfer, &msg);
...@@ -387,18 +393,18 @@ static void ...@@ -387,18 +393,18 @@ static void
spi_rd_buf(struct usb_hcd *hcd, unsigned int reg, void *buf, size_t len) spi_rd_buf(struct usb_hcd *hcd, unsigned int reg, void *buf, size_t len)
{ {
struct spi_device *spi = to_spi_device(hcd->self.controller); struct spi_device *spi = to_spi_device(hcd->self.controller);
struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd);
struct spi_transfer transfer[2]; struct spi_transfer transfer[2];
struct spi_message msg; struct spi_message msg;
u8 cmd;
memset(transfer, 0, sizeof(transfer)); memset(transfer, 0, sizeof(transfer));
spi_message_init(&msg); spi_message_init(&msg);
cmd = (field(reg, MAX3421_SPI_REG_SHIFT) | max3421_hcd->tx->data[0] =
field(MAX3421_SPI_DIR_RD, MAX3421_SPI_DIR_SHIFT)); (field(reg, MAX3421_SPI_REG_SHIFT) |
field(MAX3421_SPI_DIR_RD, MAX3421_SPI_DIR_SHIFT));
transfer[0].tx_buf = &cmd; transfer[0].tx_buf = max3421_hcd->tx->data;
transfer[0].len = 1; transfer[0].len = 1;
transfer[1].rx_buf = buf; transfer[1].rx_buf = buf;
...@@ -413,18 +419,19 @@ static void ...@@ -413,18 +419,19 @@ static void
spi_wr_buf(struct usb_hcd *hcd, unsigned int reg, void *buf, size_t len) spi_wr_buf(struct usb_hcd *hcd, unsigned int reg, void *buf, size_t len)
{ {
struct spi_device *spi = to_spi_device(hcd->self.controller); struct spi_device *spi = to_spi_device(hcd->self.controller);
struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd);
struct spi_transfer transfer[2]; struct spi_transfer transfer[2];
struct spi_message msg; struct spi_message msg;
u8 cmd;
memset(transfer, 0, sizeof(transfer)); memset(transfer, 0, sizeof(transfer));
spi_message_init(&msg); spi_message_init(&msg);
cmd = (field(reg, MAX3421_SPI_REG_SHIFT) | max3421_hcd->tx->data[0] =
field(MAX3421_SPI_DIR_WR, MAX3421_SPI_DIR_SHIFT)); (field(reg, MAX3421_SPI_REG_SHIFT) |
field(MAX3421_SPI_DIR_WR, MAX3421_SPI_DIR_SHIFT));
transfer[0].tx_buf = &cmd; transfer[0].tx_buf = max3421_hcd->tx->data;
transfer[0].len = 1; transfer[0].len = 1;
transfer[1].tx_buf = buf; transfer[1].tx_buf = buf;
...@@ -1834,8 +1841,8 @@ static int ...@@ -1834,8 +1841,8 @@ static int
max3421_probe(struct spi_device *spi) max3421_probe(struct spi_device *spi)
{ {
struct max3421_hcd *max3421_hcd; struct max3421_hcd *max3421_hcd;
struct usb_hcd *hcd; struct usb_hcd *hcd = NULL;
int retval; int retval = -ENOMEM;
if (spi_setup(spi) < 0) { if (spi_setup(spi) < 0) {
dev_err(&spi->dev, "Unable to setup SPI bus"); dev_err(&spi->dev, "Unable to setup SPI bus");
...@@ -1846,7 +1853,7 @@ max3421_probe(struct spi_device *spi) ...@@ -1846,7 +1853,7 @@ max3421_probe(struct spi_device *spi)
dev_name(&spi->dev)); dev_name(&spi->dev));
if (!hcd) { if (!hcd) {
dev_err(&spi->dev, "failed to create HCD structure\n"); dev_err(&spi->dev, "failed to create HCD structure\n");
return -ENOMEM; goto error;
} }
set_bit(HCD_FLAG_POLL_RH, &hcd->flags); set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
max3421_hcd = hcd_to_max3421(hcd); max3421_hcd = hcd_to_max3421(hcd);
...@@ -1854,29 +1861,48 @@ max3421_probe(struct spi_device *spi) ...@@ -1854,29 +1861,48 @@ max3421_probe(struct spi_device *spi)
max3421_hcd_list = max3421_hcd; max3421_hcd_list = max3421_hcd;
INIT_LIST_HEAD(&max3421_hcd->ep_list); INIT_LIST_HEAD(&max3421_hcd->ep_list);
max3421_hcd->tx = kmalloc(sizeof(*max3421_hcd->tx), GFP_KERNEL);
if (!max3421_hcd->tx) {
dev_err(&spi->dev, "failed to kmalloc tx buffer\n");
goto error;
}
max3421_hcd->rx = kmalloc(sizeof(*max3421_hcd->rx), GFP_KERNEL);
if (!max3421_hcd->rx) {
dev_err(&spi->dev, "failed to kmalloc rx buffer\n");
goto error;
}
max3421_hcd->spi_thread = kthread_run(max3421_spi_thread, hcd, max3421_hcd->spi_thread = kthread_run(max3421_spi_thread, hcd,
"max3421_spi_thread"); "max3421_spi_thread");
if (max3421_hcd->spi_thread == ERR_PTR(-ENOMEM)) { if (max3421_hcd->spi_thread == ERR_PTR(-ENOMEM)) {
dev_err(&spi->dev, dev_err(&spi->dev,
"failed to create SPI thread (out of memory)\n"); "failed to create SPI thread (out of memory)\n");
return -ENOMEM; goto error;
} }
retval = usb_add_hcd(hcd, 0, 0); retval = usb_add_hcd(hcd, 0, 0);
if (retval) { if (retval) {
dev_err(&spi->dev, "failed to add HCD\n"); dev_err(&spi->dev, "failed to add HCD\n");
usb_put_hcd(hcd); goto error;
return retval;
} }
retval = request_irq(spi->irq, max3421_irq_handler, retval = request_irq(spi->irq, max3421_irq_handler,
IRQF_TRIGGER_LOW, "max3421", hcd); IRQF_TRIGGER_LOW, "max3421", hcd);
if (retval < 0) { if (retval < 0) {
usb_put_hcd(hcd);
dev_err(&spi->dev, "failed to request irq %d\n", spi->irq); dev_err(&spi->dev, "failed to request irq %d\n", spi->irq);
return retval; goto error;
} }
return 0; return 0;
error:
if (hcd) {
kfree(max3421_hcd->tx);
kfree(max3421_hcd->rx);
if (max3421_hcd->spi_thread)
kthread_stop(max3421_hcd->spi_thread);
usb_put_hcd(hcd);
}
return retval;
} }
static int static int
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment