Commit 864db4d5 authored by Amitkumar Karwar's avatar Amitkumar Karwar Committed by Kalle Valo

rsi: fix kernel panic observed on 64bit machine

Following kernel panic is observed on 64bit machine while loading
the driver. It is fixed if we pass dynamically allocated memory to
SDIO for DMA.

BUG: unable to handle kernel paging request at ffffeb04000172e0
IP: sg_miter_stop+0x56/0x70
PGD 0 P4D 0
Oops: 0000 [#1] SMP PTI
Modules linked in: rsi_sdio(OE+) rsi_91x(OE) btrsi(OE) rfcomm bluetooth
ecdh_generic mac80211 mmc_block fuse xt_CHECKSUM iptable_mangle
drm_kms_helper mmc_core serio_raw drm firewire_ohci tg3
CPU: 0 PID: 4003 Comm: insmod Tainted: G           OE    4.16.0-rc1+ #27
Hardware name: Dell Inc. Latitude E5500                  /0DW634, BIOS
A19 06/13/2013
RIP: 0010:sg_miter_stop+0x56/0x70
RSP: 0018:ffff88007d003e78 EFLAGS: 00010002
RAX: 0000000000000003 RBX: 0000000000000004 RCX: 0000000000000000
RDX: ffffeb04000172c0 RSI: ffff88002f58002c RDI: ffff88007d003e80
RBP: 0000000000000004 R08: ffff88007d003e80 R09: 0000000000000008
R10: 0000000000000003 R11: 0000000000000001 R12: 0000000000000004
R13: ffff88002f580028 R14: 0000000000000000 R15: 0000000000000004
FS:  00007f35c29db700(0000) GS:ffff88007d000000(0000)
knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: ffffeb04000172e0 CR3: 000000007038e000 CR4: 00000000000406f0
Call Trace:
<IRQ>
sg_copy_buffer+0xc6/0xf0
sdhci_tasklet_finish+0x170/0x260 [sdhci]
tasklet_action+0xf4/0x100
__do_softirq+0xef/0x26e
irq_exit+0xbe/0xd0
do_IRQ+0x4a/0xc0
common_interrupt+0xa2/0xa2
</IRQ>
Signed-off-by: default avatarAmitkumar Karwar <amit.karwar@redpinesignals.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 90b12aeb
...@@ -653,11 +653,14 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, ...@@ -653,11 +653,14 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr,
u32 *read_buf, u16 size) u32 *read_buf, u16 size)
{ {
u32 addr_on_bus, *data; u32 addr_on_bus, *data;
u32 align[2] = {};
u16 ms_addr; u16 ms_addr;
int status; int status;
data = PTR_ALIGN(&align[0], 8); data = kzalloc(RSI_MASTER_REG_BUF_SIZE, GFP_KERNEL);
if (!data)
return -ENOMEM;
data = PTR_ALIGN(data, 8);
ms_addr = (addr >> 16); ms_addr = (addr >> 16);
status = rsi_sdio_master_access_msword(adapter, ms_addr); status = rsi_sdio_master_access_msword(adapter, ms_addr);
...@@ -665,7 +668,7 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, ...@@ -665,7 +668,7 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr,
rsi_dbg(ERR_ZONE, rsi_dbg(ERR_ZONE,
"%s: Unable to set ms word to common reg\n", "%s: Unable to set ms word to common reg\n",
__func__); __func__);
return status; goto err;
} }
addr &= 0xFFFF; addr &= 0xFFFF;
...@@ -683,7 +686,7 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, ...@@ -683,7 +686,7 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr,
(u8 *)data, 4); (u8 *)data, 4);
if (status < 0) { if (status < 0) {
rsi_dbg(ERR_ZONE, "%s: AHB register read failed\n", __func__); rsi_dbg(ERR_ZONE, "%s: AHB register read failed\n", __func__);
return status; goto err;
} }
if (size == 2) { if (size == 2) {
if ((addr & 0x3) == 0) if ((addr & 0x3) == 0)
...@@ -705,17 +708,23 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, ...@@ -705,17 +708,23 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr,
*read_buf = *data; *read_buf = *data;
} }
return 0; err:
kfree(data);
return status;
} }
static int rsi_sdio_master_reg_write(struct rsi_hw *adapter, static int rsi_sdio_master_reg_write(struct rsi_hw *adapter,
unsigned long addr, unsigned long addr,
unsigned long data, u16 size) unsigned long data, u16 size)
{ {
unsigned long data1[2], *data_aligned; unsigned long *data_aligned;
int status; int status;
data_aligned = PTR_ALIGN(&data1[0], 8); data_aligned = kzalloc(RSI_MASTER_REG_BUF_SIZE, GFP_KERNEL);
if (!data_aligned)
return -ENOMEM;
data_aligned = PTR_ALIGN(data_aligned, 8);
if (size == 2) { if (size == 2) {
*data_aligned = ((data << 16) | (data & 0xFFFF)); *data_aligned = ((data << 16) | (data & 0xFFFF));
...@@ -734,6 +743,7 @@ static int rsi_sdio_master_reg_write(struct rsi_hw *adapter, ...@@ -734,6 +743,7 @@ static int rsi_sdio_master_reg_write(struct rsi_hw *adapter,
rsi_dbg(ERR_ZONE, rsi_dbg(ERR_ZONE,
"%s: Unable to set ms word to common reg\n", "%s: Unable to set ms word to common reg\n",
__func__); __func__);
kfree(data_aligned);
return -EIO; return -EIO;
} }
addr = addr & 0xFFFF; addr = addr & 0xFFFF;
...@@ -743,12 +753,12 @@ static int rsi_sdio_master_reg_write(struct rsi_hw *adapter, ...@@ -743,12 +753,12 @@ static int rsi_sdio_master_reg_write(struct rsi_hw *adapter,
(adapter, (adapter,
(addr | RSI_SD_REQUEST_MASTER), (addr | RSI_SD_REQUEST_MASTER),
(u8 *)data_aligned, size); (u8 *)data_aligned, size);
if (status < 0) { if (status < 0)
rsi_dbg(ERR_ZONE, rsi_dbg(ERR_ZONE,
"%s: Unable to do AHB reg write\n", __func__); "%s: Unable to do AHB reg write\n", __func__);
return status;
} kfree(data_aligned);
return 0; return status;
} }
/** /**
......
...@@ -46,6 +46,8 @@ enum sdio_interrupt_type { ...@@ -46,6 +46,8 @@ enum sdio_interrupt_type {
#define PKT_BUFF_AVAILABLE 1 #define PKT_BUFF_AVAILABLE 1
#define FW_ASSERT_IND 2 #define FW_ASSERT_IND 2
#define RSI_MASTER_REG_BUF_SIZE 12
#define RSI_DEVICE_BUFFER_STATUS_REGISTER 0xf3 #define RSI_DEVICE_BUFFER_STATUS_REGISTER 0xf3
#define RSI_FN1_INT_REGISTER 0xf9 #define RSI_FN1_INT_REGISTER 0xf9
#define RSI_INT_ENABLE_REGISTER 0x04 #define RSI_INT_ENABLE_REGISTER 0x04
......
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