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

usb: hsotg: samsung: smp Provide *_lock functions abstraction layer for SMP SoCs

For SMP processors the spin_lock_irqsave is _only_ able to disable interrupt
on a core on which it is executed.

Therefore there may be a situation when other cores raise s3c-hsotg IRQ.
Then there are several places where critical sections can be overwritten.

To protect the above thread, a spin_lock in the interrupt handler has been
added. Due to coherent memory view (especially L1 cache) the spin lock
variable control access to IRQ handler only for one CPU core. In this way
serialization to access this driver is provided and hence several spin_lock_*
routines could be removed from IRQ handler's related functions.

The complete_request_lock function has been removed since all its calls
are performed from interrupt (spin lock protected) context.

Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>

authored by

Lukasz Majewski and committed by
Felipe Balbi
5ad1d316 2b19a52c

+48 -49
+48 -49
drivers/usb/gadget/s3c-hsotg.c
··· 895 895 struct s3c_hsotg_req *hs_req = our_req(req); 896 896 struct s3c_hsotg_ep *hs_ep = our_ep(ep); 897 897 struct s3c_hsotg *hs = hs_ep->parent; 898 - unsigned long irqflags; 899 898 bool first; 900 899 901 900 dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n", 902 901 ep->name, req, req->length, req->buf, req->no_interrupt, 903 902 req->zero, req->short_not_ok); 904 - 905 - spin_lock_irqsave(&hs->lock, irqflags); 906 903 907 904 /* initialise status of the request */ 908 905 INIT_LIST_HEAD(&hs_req->queue); ··· 919 922 if (first) 920 923 s3c_hsotg_start_req(hs, hs_ep, hs_req, false); 921 924 922 - spin_unlock_irqrestore(&hs->lock, irqflags); 923 - 924 925 return 0; 926 + } 927 + 928 + static int s3c_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, 929 + gfp_t gfp_flags) 930 + { 931 + struct s3c_hsotg_ep *hs_ep = our_ep(ep); 932 + struct s3c_hsotg *hs = hs_ep->parent; 933 + unsigned long flags = 0; 934 + int ret = 0; 935 + 936 + spin_lock_irqsave(&hs->lock, flags); 937 + ret = s3c_hsotg_ep_queue(ep, req, gfp_flags); 938 + spin_unlock_irqrestore(&hs->lock, flags); 939 + 940 + return ret; 925 941 } 926 942 927 943 static void s3c_hsotg_ep_free_request(struct usb_ep *ep, ··· 1413 1403 } 1414 1404 1415 1405 /** 1416 - * s3c_hsotg_complete_request_lock - complete a request given to us (locked) 1417 - * @hsotg: The device state. 1418 - * @hs_ep: The endpoint the request was on. 1419 - * @hs_req: The request to complete. 1420 - * @result: The result code (0 => Ok, otherwise errno) 1421 - * 1422 - * See s3c_hsotg_complete_request(), but called with the endpoint's 1423 - * lock held. 1424 - */ 1425 - static void s3c_hsotg_complete_request_lock(struct s3c_hsotg *hsotg, 1426 - struct s3c_hsotg_ep *hs_ep, 1427 - struct s3c_hsotg_req *hs_req, 1428 - int result) 1429 - { 1430 - unsigned long flags; 1431 - 1432 - spin_lock_irqsave(&hsotg->lock, flags); 1433 - s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, result); 1434 - spin_unlock_irqrestore(&hsotg->lock, flags); 1435 - } 1436 - 1437 - /** 1438 1406 * s3c_hsotg_rx_data - receive data from the FIFO for an endpoint 1439 1407 * @hsotg: The device state. 1440 1408 * @ep_idx: The endpoint index for the data ··· 1431 1443 int max_req; 1432 1444 int read_ptr; 1433 1445 1434 - spin_lock(&hsotg->lock); 1435 1446 1436 1447 if (!hs_req) { 1437 1448 u32 epctl = readl(hsotg->regs + DOEPCTL(ep_idx)); ··· 1444 1457 for (ptr = 0; ptr < size; ptr += 4) 1445 1458 (void)readl(fifo); 1446 1459 1447 - spin_unlock(&hsotg->lock); 1448 1460 return; 1449 1461 } 1450 1462 ··· 1473 1487 * alignment of the data. 1474 1488 */ 1475 1489 readsl(fifo, hs_req->req.buf + read_ptr, to_read); 1476 - 1477 - spin_unlock(&hsotg->lock); 1478 1490 } 1479 1491 1480 1492 /** ··· 1593 1609 s3c_hsotg_send_zlp(hsotg, hs_req); 1594 1610 } 1595 1611 1596 - s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, result); 1612 + s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, result); 1597 1613 } 1598 1614 1599 1615 /** ··· 1848 1864 /* Finish ZLP handling for IN EP0 transactions */ 1849 1865 if (hsotg->eps[0].sent_zlp) { 1850 1866 dev_dbg(hsotg->dev, "zlp packet received\n"); 1851 - s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, 0); 1867 + s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 1852 1868 return; 1853 1869 } 1854 1870 ··· 1899 1915 dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__); 1900 1916 s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true); 1901 1917 } else 1902 - s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, 0); 1918 + s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 1903 1919 } 1904 1920 1905 1921 /** ··· 2107 2123 int result, bool force) 2108 2124 { 2109 2125 struct s3c_hsotg_req *req, *treq; 2110 - unsigned long flags; 2111 - 2112 - spin_lock_irqsave(&hsotg->lock, flags); 2113 2126 2114 2127 list_for_each_entry_safe(req, treq, &ep->queue, queue) { 2115 2128 /* ··· 2120 2139 s3c_hsotg_complete_request(hsotg, ep, req, 2121 2140 result); 2122 2141 } 2123 - 2124 - spin_unlock_irqrestore(&hsotg->lock, flags); 2125 2142 } 2126 2143 2127 2144 #define call_gadget(_hs, _entry) \ 2128 2145 if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN && \ 2129 - (_hs)->driver && (_hs)->driver->_entry) \ 2130 - (_hs)->driver->_entry(&(_hs)->gadget); 2146 + (_hs)->driver && (_hs)->driver->_entry) { \ 2147 + spin_unlock(&_hs->lock); \ 2148 + (_hs)->driver->_entry(&(_hs)->gadget); \ 2149 + spin_lock(&_hs->lock); \ 2150 + } 2131 2151 2132 2152 /** 2133 2153 * s3c_hsotg_disconnect - disconnect service ··· 2370 2388 u32 gintsts; 2371 2389 u32 gintmsk; 2372 2390 2391 + spin_lock(&hsotg->lock); 2373 2392 irq_retry: 2374 2393 gintsts = readl(hsotg->regs + GINTSTS); 2375 2394 gintmsk = readl(hsotg->regs + GINTMSK); ··· 2540 2557 if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) 2541 2558 goto irq_retry; 2542 2559 2560 + spin_unlock(&hsotg->lock); 2561 + 2543 2562 return IRQ_HANDLED; 2544 2563 } 2545 2564 ··· 2695 2710 2696 2711 epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 2697 2712 2713 + spin_lock_irqsave(&hsotg->lock, flags); 2698 2714 /* terminate all requests with shutdown */ 2699 2715 kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false); 2700 2716 2701 - spin_lock_irqsave(&hsotg->lock, flags); 2702 2717 2703 2718 ctrl = readl(hsotg->regs + epctrl_reg); 2704 2719 ctrl &= ~DxEPCTL_EPEna; ··· 2769 2784 struct s3c_hsotg_ep *hs_ep = our_ep(ep); 2770 2785 struct s3c_hsotg *hs = hs_ep->parent; 2771 2786 int index = hs_ep->index; 2772 - unsigned long irqflags; 2773 2787 u32 epreg; 2774 2788 u32 epctl; 2775 2789 u32 xfertype; 2776 2790 2777 2791 dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value); 2778 - 2779 - spin_lock_irqsave(&hs->lock, irqflags); 2780 2792 2781 2793 /* write both IN and OUT control registers */ 2782 2794 ··· 2809 2827 2810 2828 writel(epctl, hs->regs + epreg); 2811 2829 2812 - spin_unlock_irqrestore(&hs->lock, irqflags); 2813 - 2814 2830 return 0; 2831 + } 2832 + 2833 + /** 2834 + * s3c_hsotg_ep_sethalt_lock - set halt on a given endpoint with lock held 2835 + * @ep: The endpoint to set halt. 2836 + * @value: Set or unset the halt. 2837 + */ 2838 + static int s3c_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) 2839 + { 2840 + struct s3c_hsotg_ep *hs_ep = our_ep(ep); 2841 + struct s3c_hsotg *hs = hs_ep->parent; 2842 + unsigned long flags = 0; 2843 + int ret = 0; 2844 + 2845 + spin_lock_irqsave(&hs->lock, flags); 2846 + ret = s3c_hsotg_ep_sethalt(ep, value); 2847 + spin_unlock_irqrestore(&hs->lock, flags); 2848 + 2849 + return ret; 2815 2850 } 2816 2851 2817 2852 static struct usb_ep_ops s3c_hsotg_ep_ops = { ··· 2836 2837 .disable = s3c_hsotg_ep_disable, 2837 2838 .alloc_request = s3c_hsotg_ep_alloc_request, 2838 2839 .free_request = s3c_hsotg_ep_free_request, 2839 - .queue = s3c_hsotg_ep_queue, 2840 + .queue = s3c_hsotg_ep_queue_lock, 2840 2841 .dequeue = s3c_hsotg_ep_dequeue, 2841 - .set_halt = s3c_hsotg_ep_sethalt, 2842 + .set_halt = s3c_hsotg_ep_sethalt_lock, 2842 2843 /* note, don't believe we have any call for the fifo routines */ 2843 2844 }; 2844 2845