mirror of
https://github.com/torvalds/linux.git
synced 2024-12-26 21:02:19 +00:00
ath6kl: Use mutex to protect dma buffer in sync read write
Firmware crashes while starting Soft AP in 32 bit x86 platform.
The reason is that the single dma buffer (ar_sdio->dma_buffer)
is used in ath6kl_sdio_read_write_sync() for unaligned buffer
handling and this function is called in the multiple context
at the same time. So, finally hits dma buffer corruption and
firmware crash.
Mutex is used to protect dma buffer to avoid data corruption.
Spin lock can not used to fix this issue since mmc stack
read/write calls may for sleep.
Observed this issue with recently commited patch
"ath6kl: Claim sdio function only at appropriate places"
861dd058f4
kvalo: change name of mutex to more descriptive and add a comment
about what it protects
Signed-off-by: Raja Mani <rmani@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
This commit is contained in:
parent
743b4518f9
commit
fdb28589b1
@ -39,8 +39,12 @@ struct ath6kl_sdio {
|
|||||||
struct bus_request bus_req[BUS_REQUEST_MAX_NUM];
|
struct bus_request bus_req[BUS_REQUEST_MAX_NUM];
|
||||||
|
|
||||||
struct ath6kl *ar;
|
struct ath6kl *ar;
|
||||||
|
|
||||||
u8 *dma_buffer;
|
u8 *dma_buffer;
|
||||||
|
|
||||||
|
/* protects access to dma_buffer */
|
||||||
|
struct mutex dma_buffer_mutex;
|
||||||
|
|
||||||
/* scatter request list head */
|
/* scatter request list head */
|
||||||
struct list_head scat_req;
|
struct list_head scat_req;
|
||||||
|
|
||||||
@ -395,6 +399,7 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
|
|||||||
if (buf_needs_bounce(buf)) {
|
if (buf_needs_bounce(buf)) {
|
||||||
if (!ar_sdio->dma_buffer)
|
if (!ar_sdio->dma_buffer)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
mutex_lock(&ar_sdio->dma_buffer_mutex);
|
||||||
tbuf = ar_sdio->dma_buffer;
|
tbuf = ar_sdio->dma_buffer;
|
||||||
memcpy(tbuf, buf, len);
|
memcpy(tbuf, buf, len);
|
||||||
bounced = true;
|
bounced = true;
|
||||||
@ -405,6 +410,9 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
|
|||||||
if ((request & HIF_READ) && bounced)
|
if ((request & HIF_READ) && bounced)
|
||||||
memcpy(buf, tbuf, len);
|
memcpy(buf, tbuf, len);
|
||||||
|
|
||||||
|
if (bounced)
|
||||||
|
mutex_unlock(&ar_sdio->dma_buffer_mutex);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1219,6 +1227,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
|
|||||||
spin_lock_init(&ar_sdio->lock);
|
spin_lock_init(&ar_sdio->lock);
|
||||||
spin_lock_init(&ar_sdio->scat_lock);
|
spin_lock_init(&ar_sdio->scat_lock);
|
||||||
spin_lock_init(&ar_sdio->wr_async_lock);
|
spin_lock_init(&ar_sdio->wr_async_lock);
|
||||||
|
mutex_init(&ar_sdio->dma_buffer_mutex);
|
||||||
|
|
||||||
INIT_LIST_HEAD(&ar_sdio->scat_req);
|
INIT_LIST_HEAD(&ar_sdio->scat_req);
|
||||||
INIT_LIST_HEAD(&ar_sdio->bus_req_freeq);
|
INIT_LIST_HEAD(&ar_sdio->bus_req_freeq);
|
||||||
|
Loading…
Reference in New Issue
Block a user