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

usb: cdns3: fix iso transfer error when mult is not zero

ISO basic transfer is
ITP(SOF) Package_0 Package_1 ... Package_n

CDNS3 DMA start dma transfer from memmory to internal FIFO when get SOF,
controller will transfer data to usb bus from internal FIFO when get IN
token.

According USB spec defination:
Maximum number of packets = (bMaxBurst + 1) * (Mult + 1)

Internal memory should be the same as (bMaxBurst + 1) * (Mult + 1). DMA
don't fetch data advance when ISO transfer, so only reserve
(bMaxBurst + 1) * (Mult + 1) internal memory for ISO transfer.

Need save Mult and bMaxBurst information and set it into EP_CFG register,
otherwise only 1 package is sent by controller, other package will be
lost.

Cc: <stable@vger.kernel.org>
Fixes: 7733f6c32e36 ("usb: cdns3: Add Cadence USB3 DRD Driver")
Signed-off-by: Frank Li <Frank.Li@nxp.com>
Link: https://lore.kernel.org/r/20231224153816.1664687-3-Frank.Li@nxp.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Frank Li and committed by
Greg Kroah-Hartman
92f02efa 1b8be5ec

+39 -23
+36 -23
drivers/usb/cdns3/cdns3-gadget.c
··· 2065 2065 bool is_iso_ep = (priv_ep->type == USB_ENDPOINT_XFER_ISOC); 2066 2066 struct cdns3_device *priv_dev = priv_ep->cdns3_dev; 2067 2067 u32 bEndpointAddress = priv_ep->num | priv_ep->dir; 2068 - u32 max_packet_size = 0; 2069 - u8 maxburst = 0; 2068 + u32 max_packet_size = priv_ep->wMaxPacketSize; 2069 + u8 maxburst = priv_ep->bMaxBurst; 2070 2070 u32 ep_cfg = 0; 2071 2071 u8 buffering; 2072 - u8 mult = 0; 2073 2072 int ret; 2074 2073 2075 2074 buffering = priv_dev->ep_buf_size - 1; ··· 2090 2091 break; 2091 2092 default: 2092 2093 ep_cfg = EP_CFG_EPTYPE(USB_ENDPOINT_XFER_ISOC); 2093 - mult = priv_dev->ep_iso_burst - 1; 2094 - buffering = mult + 1; 2094 + buffering = (priv_ep->bMaxBurst + 1) * (priv_ep->mult + 1) - 1; 2095 2095 } 2096 2096 2097 2097 switch (priv_dev->gadget.speed) { ··· 2101 2103 max_packet_size = is_iso_ep ? 1024 : 512; 2102 2104 break; 2103 2105 case USB_SPEED_SUPER: 2104 - /* It's limitation that driver assumes in driver. */ 2105 - mult = 0; 2106 - max_packet_size = 1024; 2107 - if (priv_ep->type == USB_ENDPOINT_XFER_ISOC) { 2108 - maxburst = priv_dev->ep_iso_burst - 1; 2109 - buffering = (mult + 1) * 2110 - (maxburst + 1); 2111 - 2112 - if (priv_ep->interval > 1) 2113 - buffering++; 2114 - } else { 2106 + if (priv_ep->type != USB_ENDPOINT_XFER_ISOC) { 2107 + max_packet_size = 1024; 2115 2108 maxburst = priv_dev->ep_buf_size - 1; 2116 2109 } 2117 2110 break; ··· 2131 2142 if (priv_dev->dev_ver < DEV_VER_V2) 2132 2143 priv_ep->trb_burst_size = 16; 2133 2144 2134 - mult = min_t(u8, mult, EP_CFG_MULT_MAX); 2135 2145 buffering = min_t(u8, buffering, EP_CFG_BUFFERING_MAX); 2136 2146 maxburst = min_t(u8, maxburst, EP_CFG_MAXBURST_MAX); 2137 2147 ··· 2164 2176 } 2165 2177 2166 2178 ep_cfg |= EP_CFG_MAXPKTSIZE(max_packet_size) | 2167 - EP_CFG_MULT(mult) | 2179 + EP_CFG_MULT(priv_ep->mult) | /* must match EP setting */ 2168 2180 EP_CFG_BUFFERING(buffering) | 2169 2181 EP_CFG_MAXBURST(maxburst); 2170 2182 ··· 2254 2266 priv_ep->type = usb_endpoint_type(desc); 2255 2267 priv_ep->flags |= EP_CLAIMED; 2256 2268 priv_ep->interval = desc->bInterval ? BIT(desc->bInterval - 1) : 0; 2269 + priv_ep->wMaxPacketSize = usb_endpoint_maxp(desc); 2270 + priv_ep->mult = USB_EP_MAXP_MULT(priv_ep->wMaxPacketSize); 2271 + priv_ep->wMaxPacketSize &= USB_ENDPOINT_MAXP_MASK; 2272 + if (priv_ep->type == USB_ENDPOINT_XFER_ISOC && comp_desc) { 2273 + priv_ep->mult = USB_SS_MULT(comp_desc->bmAttributes) - 1; 2274 + priv_ep->bMaxBurst = comp_desc->bMaxBurst; 2275 + } 2257 2276 2258 2277 spin_unlock_irqrestore(&priv_dev->lock, flags); 2259 2278 return &priv_ep->endpoint; ··· 3044 3049 struct cdns3_endpoint *priv_ep; 3045 3050 struct usb_ep *ep; 3046 3051 int n_in = 0; 3052 + int iso = 0; 3053 + int out = 1; 3047 3054 int total; 3055 + int n; 3048 3056 3049 3057 list_for_each_entry(ep, &gadget->ep_list, ep_list) { 3050 3058 priv_ep = ep_to_cdns3_ep(ep); 3051 - if ((priv_ep->flags & EP_CLAIMED) && (ep->address & USB_DIR_IN)) 3052 - n_in++; 3059 + if (!(priv_ep->flags & EP_CLAIMED)) 3060 + continue; 3061 + 3062 + n = (priv_ep->mult + 1) * (priv_ep->bMaxBurst + 1); 3063 + if (ep->address & USB_DIR_IN) { 3064 + /* 3065 + * ISO transfer: DMA start move data when get ISO, only transfer 3066 + * data as min(TD size, iso). No benefit for allocate bigger 3067 + * internal memory than 'iso'. 3068 + */ 3069 + if (priv_ep->type == USB_ENDPOINT_XFER_ISOC) 3070 + iso += n; 3071 + else 3072 + n_in++; 3073 + } else { 3074 + if (priv_ep->type == USB_ENDPOINT_XFER_ISOC) 3075 + out = max_t(int, out, n); 3076 + } 3053 3077 } 3054 3078 3055 3079 /* 2KB are reserved for EP0, 1KB for out*/ 3056 - total = 2 + n_in + 1; 3080 + total = 2 + n_in + out + iso; 3057 3081 3058 3082 if (total > priv_dev->onchip_buffers) 3059 3083 return -ENOMEM; 3060 3084 3061 - priv_dev->ep_buf_size = priv_dev->ep_iso_burst = 3062 - (priv_dev->onchip_buffers - 2) / (n_in + 1); 3085 + priv_dev->ep_buf_size = (priv_dev->onchip_buffers - 2 - iso) / (n_in + out); 3063 3086 3064 3087 return 0; 3065 3088 }
+3
drivers/usb/cdns3/cdns3-gadget.h
··· 1168 1168 u8 dir; 1169 1169 u8 num; 1170 1170 u8 type; 1171 + u8 mult; 1172 + u8 bMaxBurst; 1173 + u16 wMaxPacketSize; 1171 1174 int interval; 1172 1175 1173 1176 int free_trbs;