Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: host: Fix excessive alignment restriction for local memory allocations

The PAGE_SHIFT alignment restriction to devm_gen_pool_create() quickly
exhaust local memory because most allocations are much smaller than
PAGE_SIZE. This causes USB device failures such as

usb 1-2.1: reset full-speed USB device number 4 using sm501-usb
sd 1:0:0:0: [sda] tag#0 UNKNOWN(0x2003) Result: hostbyte=0x03 driverbyte=0x00
sd 1:0:0:0: [sda] tag#0 CDB: opcode=0x28 28 00 00 00 08 7c 00 00 f0 00
print_req_error: I/O error, dev sda, sector 2172 flags 80700

when trying to boot from the SM501 USB controller on SH4 with QEMU.

Align allocations as required but not necessarily much more than that.
The HCCA, TD and ED structures align with 256, 32 and 16 byte memory
boundaries, as specified by the Open HCI[1]. The min_alloc_order argument
to devm_gen_pool_create is now somewhat arbitrarily set to 4 (16 bytes).
Perhaps it could be somewhat lower for general buffer allocations.

Reference:

[1] "Open Host Controller Interface Specification for USB",
release 1.0a, Compaq, Microsoft, National Semiconductor, 1999,
pp. 16, 19, 33.

Reported-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Fredrik Noring <noring@nocrew.org>
Tested-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Christoph Hellwig <hch@lst.de>

authored by

Fredrik Noring and committed by
Christoph Hellwig
ff2437be cf394fc5

+7 -5
+1 -1
drivers/usb/core/hcd.c
··· 3044 3044 int err; 3045 3045 void *local_mem; 3046 3046 3047 - hcd->localmem_pool = devm_gen_pool_create(hcd->self.sysdev, PAGE_SHIFT, 3047 + hcd->localmem_pool = devm_gen_pool_create(hcd->self.sysdev, 4, 3048 3048 dev_to_node(hcd->self.sysdev), 3049 3049 dev_name(hcd->self.sysdev)); 3050 3050 if (IS_ERR(hcd->localmem_pool))
+2 -2
drivers/usb/host/ohci-hcd.c
··· 507 507 ohci->prev_frame_no = IO_WATCHDOG_OFF; 508 508 509 509 if (hcd->localmem_pool) 510 - ohci->hcca = gen_pool_dma_alloc(hcd->localmem_pool, 510 + ohci->hcca = gen_pool_dma_alloc_align(hcd->localmem_pool, 511 511 sizeof(*ohci->hcca), 512 - &ohci->hcca_dma); 512 + &ohci->hcca_dma, 256); 513 513 else 514 514 ohci->hcca = dma_alloc_coherent(hcd->self.controller, 515 515 sizeof(*ohci->hcca),
+4 -2
drivers/usb/host/ohci-mem.c
··· 94 94 struct usb_hcd *hcd = ohci_to_hcd(hc); 95 95 96 96 if (hcd->localmem_pool) 97 - td = gen_pool_dma_zalloc(hcd->localmem_pool, sizeof(*td), &dma); 97 + td = gen_pool_dma_zalloc_align(hcd->localmem_pool, 98 + sizeof(*td), &dma, 32); 98 99 else 99 100 td = dma_pool_zalloc(hc->td_cache, mem_flags, &dma); 100 101 if (td) { ··· 138 137 struct usb_hcd *hcd = ohci_to_hcd(hc); 139 138 140 139 if (hcd->localmem_pool) 141 - ed = gen_pool_dma_zalloc(hcd->localmem_pool, sizeof(*ed), &dma); 140 + ed = gen_pool_dma_zalloc_align(hcd->localmem_pool, 141 + sizeof(*ed), &dma, 16); 142 142 else 143 143 ed = dma_pool_zalloc(hc->ed_cache, mem_flags, &dma); 144 144 if (ed) {