Skip to content

Commit 174beab

Browse files
andreamerellolinvjw
authored andcommitted
at76c50x-usb: Don't perform DMA from stack memory
Loading the driver with DMA debugging enabled makes the kernel to complain about the ehci driver trying to perform DMA from memory from the stack. [ 9848.229514] WARNING: CPU: 1 PID: 627 at lib/dma-debug.c:1153 check_for_stack+0xa4/0xf0() [ 9848.237678] ehci-pci 0000:00:04.1: DMA-API: device driver maps memory fromstack [addr=ffff88006c80da01] This is due to at76c50x-usb driver passing buffers allocated on the stack to the USB layer, that attempts DMA. This occurs is several places. This patch fixes the problem by allocating those buffers via kmalloc. Since this adds some kfree() before leaving a couple of functions, I caught the occasion to clean-up the exit path on error. Signed-off-by: Andrea Merello <[email protected]> Signed-off-by: John W. Linville <[email protected]>
1 parent 7dd74f5 commit 174beab

File tree

1 file changed

+56
-31
lines changed

1 file changed

+56
-31
lines changed

drivers/net/wireless/at76c50x-usb.c

Lines changed: 56 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -365,15 +365,15 @@ static inline unsigned long at76_get_timeout(struct dfu_status *s)
365365
static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
366366
int manifest_sync_timeout)
367367
{
368-
u8 *block;
369-
struct dfu_status dfu_stat_buf;
370368
int ret = 0;
371369
int need_dfu_state = 1;
372370
int is_done = 0;
373-
u8 dfu_state = 0;
374371
u32 dfu_timeout = 0;
375372
int bsize = 0;
376373
int blockno = 0;
374+
struct dfu_status *dfu_stat_buf = NULL;
375+
u8 *dfu_state = NULL;
376+
u8 *block = NULL;
377377

378378
at76_dbg(DBG_DFU, "%s( %p, %u, %d)", __func__, buf, size,
379379
manifest_sync_timeout);
@@ -383,13 +383,28 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
383383
return -EINVAL;
384384
}
385385

386+
dfu_stat_buf = kmalloc(sizeof(struct dfu_status), GFP_KERNEL);
387+
if (!dfu_stat_buf) {
388+
ret = -ENOMEM;
389+
goto exit;
390+
}
391+
386392
block = kmalloc(FW_BLOCK_SIZE, GFP_KERNEL);
387-
if (!block)
388-
return -ENOMEM;
393+
if (!block) {
394+
ret = -ENOMEM;
395+
goto exit;
396+
}
397+
398+
dfu_state = kmalloc(sizeof(u8), GFP_KERNEL);
399+
if (!dfu_state) {
400+
ret = -ENOMEM;
401+
goto exit;
402+
}
403+
*dfu_state = 0;
389404

390405
do {
391406
if (need_dfu_state) {
392-
ret = at76_dfu_get_state(udev, &dfu_state);
407+
ret = at76_dfu_get_state(udev, dfu_state);
393408
if (ret < 0) {
394409
dev_err(&udev->dev,
395410
"cannot get DFU state: %d\n", ret);
@@ -398,13 +413,13 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
398413
need_dfu_state = 0;
399414
}
400415

401-
switch (dfu_state) {
416+
switch (*dfu_state) {
402417
case STATE_DFU_DOWNLOAD_SYNC:
403418
at76_dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_SYNC");
404-
ret = at76_dfu_get_status(udev, &dfu_stat_buf);
419+
ret = at76_dfu_get_status(udev, dfu_stat_buf);
405420
if (ret >= 0) {
406-
dfu_state = dfu_stat_buf.state;
407-
dfu_timeout = at76_get_timeout(&dfu_stat_buf);
421+
*dfu_state = dfu_stat_buf->state;
422+
dfu_timeout = at76_get_timeout(dfu_stat_buf);
408423
need_dfu_state = 0;
409424
} else
410425
dev_err(&udev->dev,
@@ -447,12 +462,12 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
447462
case STATE_DFU_MANIFEST_SYNC:
448463
at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST_SYNC");
449464

450-
ret = at76_dfu_get_status(udev, &dfu_stat_buf);
465+
ret = at76_dfu_get_status(udev, dfu_stat_buf);
451466
if (ret < 0)
452467
break;
453468

454-
dfu_state = dfu_stat_buf.state;
455-
dfu_timeout = at76_get_timeout(&dfu_stat_buf);
469+
*dfu_state = dfu_stat_buf->state;
470+
dfu_timeout = at76_get_timeout(dfu_stat_buf);
456471
need_dfu_state = 0;
457472

458473
/* override the timeout from the status response,
@@ -484,14 +499,17 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
484499
break;
485500

486501
default:
487-
at76_dbg(DBG_DFU, "DFU UNKNOWN STATE (%d)", dfu_state);
502+
at76_dbg(DBG_DFU, "DFU UNKNOWN STATE (%d)", *dfu_state);
488503
ret = -EINVAL;
489504
break;
490505
}
491506
} while (!is_done && (ret >= 0));
492507

493508
exit:
509+
kfree(dfu_state);
494510
kfree(block);
511+
kfree(dfu_stat_buf);
512+
495513
if (ret >= 0)
496514
ret = 0;
497515

@@ -1277,6 +1295,7 @@ static int at76_load_external_fw(struct usb_device *udev, struct fwentry *fwe)
12771295
dev_err(&udev->dev,
12781296
"loading %dth firmware block failed: %d\n",
12791297
blockno, ret);
1298+
ret = -EIO;
12801299
goto exit;
12811300
}
12821301
buf += bsize;
@@ -2330,16 +2349,22 @@ static int at76_probe(struct usb_interface *interface,
23302349
struct usb_device *udev;
23312350
int op_mode;
23322351
int need_ext_fw = 0;
2333-
struct mib_fw_version fwv;
2352+
struct mib_fw_version *fwv = NULL;
23342353
int board_type = (int)id->driver_info;
23352354

23362355
udev = usb_get_dev(interface_to_usbdev(interface));
23372356

2357+
fwv = kmalloc(sizeof(*fwv), GFP_KERNEL);
2358+
if (!fwv) {
2359+
ret = -ENOMEM;
2360+
goto exit;
2361+
}
2362+
23382363
/* Load firmware into kernel memory */
23392364
fwe = at76_load_firmware(udev, board_type);
23402365
if (!fwe) {
23412366
ret = -ENOENT;
2342-
goto error;
2367+
goto exit;
23432368
}
23442369

23452370
op_mode = at76_get_op_mode(udev);
@@ -2353,7 +2378,7 @@ static int at76_probe(struct usb_interface *interface,
23532378
dev_err(&interface->dev,
23542379
"cannot handle a device in HW_CONFIG_MODE\n");
23552380
ret = -EBUSY;
2356-
goto error;
2381+
goto exit;
23572382
}
23582383

23592384
if (op_mode != OPMODE_NORMAL_NIC_WITH_FLASH
@@ -2366,10 +2391,10 @@ static int at76_probe(struct usb_interface *interface,
23662391
dev_err(&interface->dev,
23672392
"error %d downloading internal firmware\n",
23682393
ret);
2369-
goto error;
2394+
goto exit;
23702395
}
23712396
usb_put_dev(udev);
2372-
return ret;
2397+
goto exit;
23732398
}
23742399

23752400
/* Internal firmware already inside the device. Get firmware
@@ -2382,8 +2407,8 @@ static int at76_probe(struct usb_interface *interface,
23822407
* query the device for the fw version */
23832408
if ((fwe->fw_version.major > 0 || fwe->fw_version.minor >= 100)
23842409
|| (op_mode == OPMODE_NORMAL_NIC_WITH_FLASH)) {
2385-
ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv));
2386-
if (ret < 0 || (fwv.major | fwv.minor) == 0)
2410+
ret = at76_get_mib(udev, MIB_FW_VERSION, fwv, sizeof(*fwv));
2411+
if (ret < 0 || (fwv->major | fwv->minor) == 0)
23872412
need_ext_fw = 1;
23882413
} else
23892414
/* No way to check firmware version, reload to be sure */
@@ -2394,37 +2419,37 @@ static int at76_probe(struct usb_interface *interface,
23942419
"downloading external firmware\n");
23952420

23962421
ret = at76_load_external_fw(udev, fwe);
2397-
if (ret)
2398-
goto error;
2422+
if (ret < 0)
2423+
goto exit;
23992424

24002425
/* Re-check firmware version */
2401-
ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv));
2426+
ret = at76_get_mib(udev, MIB_FW_VERSION, fwv, sizeof(*fwv));
24022427
if (ret < 0) {
24032428
dev_err(&interface->dev,
24042429
"error %d getting firmware version\n", ret);
2405-
goto error;
2430+
goto exit;
24062431
}
24072432
}
24082433

24092434
priv = at76_alloc_new_device(udev);
24102435
if (!priv) {
24112436
ret = -ENOMEM;
2412-
goto error;
2437+
goto exit;
24132438
}
24142439

24152440
usb_set_intfdata(interface, priv);
24162441

2417-
memcpy(&priv->fw_version, &fwv, sizeof(struct mib_fw_version));
2442+
memcpy(&priv->fw_version, fwv, sizeof(struct mib_fw_version));
24182443
priv->board_type = board_type;
24192444

24202445
ret = at76_init_new_device(priv, interface);
24212446
if (ret < 0)
24222447
at76_delete_device(priv);
24232448

2424-
return ret;
2425-
2426-
error:
2427-
usb_put_dev(udev);
2449+
exit:
2450+
kfree(fwv);
2451+
if (ret < 0)
2452+
usb_put_dev(udev);
24282453
return ret;
24292454
}
24302455

0 commit comments

Comments
 (0)