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: kbuild test robot <fengguang.wu@intel.com> Signed-off-by: David Mosberger <davidm@egauge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
00c5aa178a
commit
05dfa5c9bc
1 changed files with 60 additions and 34 deletions
|
@ -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 {
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
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)
|
||||||
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)
|
||||||
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
|
||||||
|
|
Loading…
Add table
Reference in a new issue