* [PATCH 1/3] usb: cdns3: gadget: suspicious implicit sign extension [not found] <20201016101659.29482-1-peter.chen@nxp.com> @ 2020-10-16 10:16 ` Peter Chen 2020-10-27 9:03 ` Felipe Balbi 2020-10-27 9:03 ` Felipe Balbi 2020-10-16 10:16 ` [PATCH 3/3] usb: cdns3: Fix on-chip memory overflow issue Peter Chen 1 sibling, 2 replies; 9+ messages in thread From: Peter Chen @ 2020-10-16 10:16 UTC (permalink / raw) To: pawell, rogerq Cc: balbi, linux-usb, linux-imx, gregkh, jun.li, Peter Chen, stable For code: trb->length = cpu_to_le32(TRB_BURST_LEN(priv_ep->trb_burst_size) | TRB_LEN(length)); TRB_BURST_LEN(priv_ep->trb_burst_size) may be overflow for int 32 if priv_ep->trb_burst_size is equal or larger than 0x80; Below is the Coverity warning: sign_extension: Suspicious implicit sign extension: priv_ep->trb_burst_size with type u8 (8 bits, unsigned) is promoted in priv_ep->trb_burst_size << 24 to type int (32 bits, signed), then sign-extended to type unsigned long (64 bits, unsigned). If priv_ep->trb_burst_size << 24 is greater than 0x7FFFFFFF, the upper bits of the result will all be 1. Cc: <stable@vger.kernel.org> #v5.8+ Fixes: 7733f6c32e36 ("usb: cdns3: Add Cadence USB3 DRD Driver") Signed-off-by: Peter Chen <peter.chen@nxp.com> --- drivers/usb/cdns3/gadget.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h index 1ccecd237530..020936cb9897 100644 --- a/drivers/usb/cdns3/gadget.h +++ b/drivers/usb/cdns3/gadget.h @@ -1072,7 +1072,7 @@ struct cdns3_trb { #define TRB_TDL_SS_SIZE_GET(p) (((p) & GENMASK(23, 17)) >> 17) /* transfer_len bitmasks - bits 31:24 */ -#define TRB_BURST_LEN(p) (((p) << 24) & GENMASK(31, 24)) +#define TRB_BURST_LEN(p) (unsigned int)(((p) << 24) & GENMASK(31, 24)) #define TRB_BURST_LEN_GET(p) (((p) & GENMASK(31, 24)) >> 24) /* Data buffer pointer bitmasks*/ -- 2.17.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 1/3] usb: cdns3: gadget: suspicious implicit sign extension 2020-10-16 10:16 ` [PATCH 1/3] usb: cdns3: gadget: suspicious implicit sign extension Peter Chen @ 2020-10-27 9:03 ` Felipe Balbi 2020-10-27 9:48 ` Peter Chen 2020-10-27 9:03 ` Felipe Balbi 1 sibling, 1 reply; 9+ messages in thread From: Felipe Balbi @ 2020-10-27 9:03 UTC (permalink / raw) To: Peter Chen, pawell, rogerq Cc: linux-usb, linux-imx, gregkh, jun.li, Peter Chen, stable [-- Attachment #1: Type: text/plain, Size: 1709 bytes --] Hi, Peter Chen <peter.chen@nxp.com> writes: > For code: > trb->length = cpu_to_le32(TRB_BURST_LEN(priv_ep->trb_burst_size) > | TRB_LEN(length)); > > TRB_BURST_LEN(priv_ep->trb_burst_size) may be overflow for int 32 if > priv_ep->trb_burst_size is equal or larger than 0x80; > > Below is the Coverity warning: > sign_extension: Suspicious implicit sign extension: priv_ep->trb_burst_size > with type u8 (8 bits, unsigned) is promoted in priv_ep->trb_burst_size << 24 > to type int (32 bits, signed), then sign-extended to type unsigned long > (64 bits, unsigned). If priv_ep->trb_burst_size << 24 is greater than 0x7FFFFFFF, > the upper bits of the result will all be 1. looks like a false positive... > Cc: <stable@vger.kernel.org> #v5.8+ > Fixes: 7733f6c32e36 ("usb: cdns3: Add Cadence USB3 DRD Driver") > Signed-off-by: Peter Chen <peter.chen@nxp.com> > --- > drivers/usb/cdns3/gadget.h | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h > index 1ccecd237530..020936cb9897 100644 > --- a/drivers/usb/cdns3/gadget.h > +++ b/drivers/usb/cdns3/gadget.h > @@ -1072,7 +1072,7 @@ struct cdns3_trb { > #define TRB_TDL_SS_SIZE_GET(p) (((p) & GENMASK(23, 17)) >> 17) > > /* transfer_len bitmasks - bits 31:24 */ > -#define TRB_BURST_LEN(p) (((p) << 24) & GENMASK(31, 24)) > +#define TRB_BURST_LEN(p) (unsigned int)(((p) << 24) & GENMASK(31, 24)) ... because TRB_BURST_LEN() is used to intialize a __le32 type. Even if it ends up being sign extended, the top 32-bits will be ignored. I'll apply, but it looks like a pointless fix. We shouldn't need it for stable -- balbi [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 857 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/3] usb: cdns3: gadget: suspicious implicit sign extension 2020-10-27 9:03 ` Felipe Balbi @ 2020-10-27 9:48 ` Peter Chen 2020-10-27 10:08 ` David Laight 2020-10-27 14:21 ` Alan Stern 0 siblings, 2 replies; 9+ messages in thread From: Peter Chen @ 2020-10-27 9:48 UTC (permalink / raw) To: Felipe Balbi Cc: pawell, rogerq, linux-usb, dl-linux-imx, gregkh, Jun Li, stable On 20-10-27 11:03:29, Felipe Balbi wrote: > > Hi, > > Peter Chen <peter.chen@nxp.com> writes: > > For code: > > trb->length = cpu_to_le32(TRB_BURST_LEN(priv_ep->trb_burst_size) > > | TRB_LEN(length)); > > > > TRB_BURST_LEN(priv_ep->trb_burst_size) may be overflow for int 32 if > > priv_ep->trb_burst_size is equal or larger than 0x80; > > > > Below is the Coverity warning: > > sign_extension: Suspicious implicit sign extension: priv_ep->trb_burst_size > > with type u8 (8 bits, unsigned) is promoted in priv_ep->trb_burst_size << 24 > > to type int (32 bits, signed), then sign-extended to type unsigned long > > (64 bits, unsigned). If priv_ep->trb_burst_size << 24 is greater than 0x7FFFFFFF, > > the upper bits of the result will all be 1. > > looks like a false positive... > > > Cc: <stable@vger.kernel.org> #v5.8+ > > Fixes: 7733f6c32e36 ("usb: cdns3: Add Cadence USB3 DRD Driver") > > Signed-off-by: Peter Chen <peter.chen@nxp.com> > > --- > > drivers/usb/cdns3/gadget.h | 2 +- > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h > > index 1ccecd237530..020936cb9897 100644 > > --- a/drivers/usb/cdns3/gadget.h > > +++ b/drivers/usb/cdns3/gadget.h > > @@ -1072,7 +1072,7 @@ struct cdns3_trb { > > #define TRB_TDL_SS_SIZE_GET(p) (((p) & GENMASK(23, 17)) >> 17) > > > > /* transfer_len bitmasks - bits 31:24 */ > > -#define TRB_BURST_LEN(p) (((p) << 24) & GENMASK(31, 24)) > > +#define TRB_BURST_LEN(p) (unsigned int)(((p) << 24) & GENMASK(31, 24)) > > ... because TRB_BURST_LEN() is used to intialize a __le32 type. Even if > it ends up being sign extended, the top 32-bits will be ignored. > > I'll apply, but it looks like a pointless fix. We shouldn't need it for stable > At my v2: It is: #define TRB_BURST_LEN(p) ((unsigned int)((p) << 24) & GENMASK(31, 24)) It is not related to high 32-bits issue, it is sign extended issue for 32 bits. If p is a unsigned char data, the compiler will consider (p) << 24 is int, but not unsigned int. So, if the p is larger than 0x80, the (p) << 24 will be overflow. If you compile the code: unsigned int k = 0x80 << 24 + 0x81; It will report build warning: warning: left shift count >= width of type [-Wshift-count-overflow] -- Thanks, Peter Chen ^ permalink raw reply [flat|nested] 9+ messages in thread
* RE: [PATCH 1/3] usb: cdns3: gadget: suspicious implicit sign extension 2020-10-27 9:48 ` Peter Chen @ 2020-10-27 10:08 ` David Laight 2020-10-27 14:21 ` Alan Stern 1 sibling, 0 replies; 9+ messages in thread From: David Laight @ 2020-10-27 10:08 UTC (permalink / raw) To: 'Peter Chen', Felipe Balbi Cc: pawell, rogerq, linux-usb, dl-linux-imx, gregkh, Jun Li, stable From: Peter Chen > Sent: 27 October 2020 09:49 > > On 20-10-27 11:03:29, Felipe Balbi wrote: > > > > Hi, > > > > Peter Chen <peter.chen@nxp.com> writes: > > > For code: > > > trb->length = cpu_to_le32(TRB_BURST_LEN(priv_ep->trb_burst_size) > > > | TRB_LEN(length)); > > > > > > TRB_BURST_LEN(priv_ep->trb_burst_size) may be overflow for int 32 if > > > priv_ep->trb_burst_size is equal or larger than 0x80; > > > > > > Below is the Coverity warning: > > > sign_extension: Suspicious implicit sign extension: priv_ep->trb_burst_size > > > with type u8 (8 bits, unsigned) is promoted in priv_ep->trb_burst_size << 24 > > > to type int (32 bits, signed), then sign-extended to type unsigned long > > > (64 bits, unsigned). If priv_ep->trb_burst_size << 24 is greater than 0x7FFFFFFF, > > > the upper bits of the result will all be 1. > > > > looks like a false positive... > > > > > Cc: <stable@vger.kernel.org> #v5.8+ > > > Fixes: 7733f6c32e36 ("usb: cdns3: Add Cadence USB3 DRD Driver") > > > Signed-off-by: Peter Chen <peter.chen@nxp.com> > > > --- > > > drivers/usb/cdns3/gadget.h | 2 +- > > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > > > diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h > > > index 1ccecd237530..020936cb9897 100644 > > > --- a/drivers/usb/cdns3/gadget.h > > > +++ b/drivers/usb/cdns3/gadget.h > > > @@ -1072,7 +1072,7 @@ struct cdns3_trb { > > > #define TRB_TDL_SS_SIZE_GET(p) (((p) & GENMASK(23, 17)) >> 17) > > > > > > /* transfer_len bitmasks - bits 31:24 */ > > > -#define TRB_BURST_LEN(p) (((p) << 24) & GENMASK(31, 24)) > > > +#define TRB_BURST_LEN(p) (unsigned int)(((p) << 24) & GENMASK(31, 24)) > > > > ... because TRB_BURST_LEN() is used to intialize a __le32 type. Even if > > it ends up being sign extended, the top 32-bits will be ignored. > > > > I'll apply, but it looks like a pointless fix. We shouldn't need it for stable > > > At my v2: > > It is: > #define TRB_BURST_LEN(p) ((unsigned int)((p) << 24) & GENMASK(31, 24)) > > It is not related to high 32-bits issue, it is sign extended issue for > 32 bits. If p is a unsigned char data, the compiler will consider > (p) << 24 is int, but not unsigned int. So, if the p is larger than > 0x80, the (p) << 24 will be overflow. > > If you compile the code: > > unsigned int k = 0x80 << 24 + 0x81; > > It will report build warning: > warning: left shift count >= width of type [-Wshift-count-overflow] Something like: #define TRB_BURST_LEN(p) (((p) + 0u) << 24) will remove the warning. The GENMASK() is pretty pointless - the compiler may fail to optimise it away. If p is 64bit the high bits should get discarded pretty quickly. David - Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales) ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/3] usb: cdns3: gadget: suspicious implicit sign extension 2020-10-27 9:48 ` Peter Chen 2020-10-27 10:08 ` David Laight @ 2020-10-27 14:21 ` Alan Stern 2020-10-28 6:41 ` Peter Chen 1 sibling, 1 reply; 9+ messages in thread From: Alan Stern @ 2020-10-27 14:21 UTC (permalink / raw) To: Peter Chen Cc: Felipe Balbi, pawell, rogerq, linux-usb, dl-linux-imx, gregkh, Jun Li, stable On Tue, Oct 27, 2020 at 09:48:54AM +0000, Peter Chen wrote: > If you compile the code: > > unsigned int k = 0x80 << 24 + 0x81; > > It will report build warning: > warning: left shift count >= width of type [-Wshift-count-overflow] That's a separate issue. I believe (but haven't checked) that the << operator has lower precedence than +, so the compiler interprets the expression as: unsigned int k = 0x80 << (24 + 0x81); and it's pretty obvious why this causes an error. Instead, try compiling: unsigned int k = (0x80 << 24) + 0x81; You may get an error message about signed-integer overflow, but not about shift-count overflow. Alan Stern ^ permalink raw reply [flat|nested] 9+ messages in thread
* RE: [PATCH 1/3] usb: cdns3: gadget: suspicious implicit sign extension 2020-10-27 14:21 ` Alan Stern @ 2020-10-28 6:41 ` Peter Chen 0 siblings, 0 replies; 9+ messages in thread From: Peter Chen @ 2020-10-28 6:41 UTC (permalink / raw) To: Alan Stern Cc: Felipe Balbi, pawell, rogerq, linux-usb, dl-linux-imx, gregkh, Jun Li, stable > That's a separate issue. I believe (but haven't checked) that the << operator > has lower precedence than +, so the compiler interprets the expression as: > > unsigned int k = 0x80 << (24 + 0x81); > > and it's pretty obvious why this causes an error. Instead, try > compiling: > > unsigned int k = (0x80 << 24) + 0x81; > > You may get an error message about signed-integer overflow, but not about > shift-count overflow. > Hi Alan, Your analysis is correct, I did not check the warning message correctly. Peter ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/3] usb: cdns3: gadget: suspicious implicit sign extension 2020-10-16 10:16 ` [PATCH 1/3] usb: cdns3: gadget: suspicious implicit sign extension Peter Chen 2020-10-27 9:03 ` Felipe Balbi @ 2020-10-27 9:03 ` Felipe Balbi 1 sibling, 0 replies; 9+ messages in thread From: Felipe Balbi @ 2020-10-27 9:03 UTC (permalink / raw) To: Peter Chen, pawell, rogerq Cc: linux-usb, linux-imx, gregkh, jun.li, Peter Chen, stable [-- Attachment #1: Type: text/plain, Size: 1711 bytes --] Hi, Peter Chen <peter.chen@nxp.com> writes: > For code: > trb->length = cpu_to_le32(TRB_BURST_LEN(priv_ep->trb_burst_size) > | TRB_LEN(length)); > > TRB_BURST_LEN(priv_ep->trb_burst_size) may be overflow for int 32 if > priv_ep->trb_burst_size is equal or larger than 0x80; > > Below is the Coverity warning: > sign_extension: Suspicious implicit sign extension: priv_ep->trb_burst_size > with type u8 (8 bits, unsigned) is promoted in priv_ep->trb_burst_size << 24 > to type int (32 bits, signed), then sign-extended to type unsigned long > (64 bits, unsigned). If priv_ep->trb_burst_size << 24 is greater than 0x7FFFFFFF, > the upper bits of the result will all be 1. looks like a false positive... > Cc: <stable@vger.kernel.org> #v5.8+ > Fixes: 7733f6c32e36 ("usb: cdns3: Add Cadence USB3 DRD Driver") > Signed-off-by: Peter Chen <peter.chen@nxp.com> > --- > drivers/usb/cdns3/gadget.h | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h > index 1ccecd237530..020936cb9897 100644 > --- a/drivers/usb/cdns3/gadget.h > +++ b/drivers/usb/cdns3/gadget.h > @@ -1072,7 +1072,7 @@ struct cdns3_trb { > #define TRB_TDL_SS_SIZE_GET(p) (((p) & GENMASK(23, 17)) >> 17) > > /* transfer_len bitmasks - bits 31:24 */ > -#define TRB_BURST_LEN(p) (((p) << 24) & GENMASK(31, 24)) > +#define TRB_BURST_LEN(p) (unsigned int)(((p) << 24) & GENMASK(31, 24)) ... because TRB_BURST_LEN() is used to intialize a __le32 type. Even if it ends up being sign extended, the top 32-bits will be ignored. I'll apply, but it looks like a pointless fix. We shouldn't need it for stable. -- balbi [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 857 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/3] usb: cdns3: Fix on-chip memory overflow issue [not found] <20201016101659.29482-1-peter.chen@nxp.com> 2020-10-16 10:16 ` [PATCH 1/3] usb: cdns3: gadget: suspicious implicit sign extension Peter Chen @ 2020-10-16 10:16 ` Peter Chen 2020-10-27 9:11 ` Felipe Balbi 1 sibling, 1 reply; 9+ messages in thread From: Peter Chen @ 2020-10-16 10:16 UTC (permalink / raw) To: pawell, rogerq Cc: balbi, linux-usb, linux-imx, gregkh, jun.li, stable, Peter Chen From: Pawel Laszczak <pawell@cadence.com> Patch fixes issue caused setting On-chip memory overflow bit in usb_sts register. The issue occurred because EP_CFG register was set twice before USB_STS.CFGSTS was set. Every write operation on EP_CFG.BUFFERING causes that controller increases internal counter holding the number of reserved on-chip buffers. First time this register was updated in function cdns3_ep_config before delegating SET_CONFIGURATION request to class driver and again it was updated when class wanted to enable endpoint. This patch fixes this issue by configuring endpoints enabled by class driver in cdns3_gadget_ep_enable and others just before status stage. Cc: <stable@vger.kernel.org> #v5.8+ Fixes: 7733f6c32e36 ("usb: cdns3: Add Cadence USB3 DRD Driver") Reported-and-tested-by: Peter Chen <peter.chen@nxp.com> Signed-off-by: Pawel Laszczak <pawell@cadence.com> Signed-off-by: Peter Chen <peter.chen@nxp.com> --- drivers/usb/cdns3/ep0.c | 65 ++++++++++++----------- drivers/usb/cdns3/gadget.c | 102 +++++++++++++++++++++---------------- drivers/usb/cdns3/gadget.h | 3 +- 3 files changed, 94 insertions(+), 76 deletions(-) diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c index 4761c852d9c4..d3121a32cc68 100644 --- a/drivers/usb/cdns3/ep0.c +++ b/drivers/usb/cdns3/ep0.c @@ -137,48 +137,36 @@ static int cdns3_req_ep0_set_configuration(struct cdns3_device *priv_dev, struct usb_ctrlrequest *ctrl_req) { enum usb_device_state device_state = priv_dev->gadget.state; - struct cdns3_endpoint *priv_ep; u32 config = le16_to_cpu(ctrl_req->wValue); int result = 0; - int i; switch (device_state) { case USB_STATE_ADDRESS: - /* Configure non-control EPs */ - for (i = 0; i < CDNS3_ENDPOINTS_MAX_COUNT; i++) { - priv_ep = priv_dev->eps[i]; - if (!priv_ep) - continue; - - if (priv_ep->flags & EP_CLAIMED) - cdns3_ep_config(priv_ep); - } - result = cdns3_ep0_delegate_req(priv_dev, ctrl_req); - if (result) - return result; - - if (!config) { - cdns3_hw_reset_eps_config(priv_dev); - usb_gadget_set_state(&priv_dev->gadget, - USB_STATE_ADDRESS); - } + if (result || !config) + goto reset_config; break; case USB_STATE_CONFIGURED: result = cdns3_ep0_delegate_req(priv_dev, ctrl_req); + if (!config && !result) + goto reset_config; - if (!config && !result) { - cdns3_hw_reset_eps_config(priv_dev); - usb_gadget_set_state(&priv_dev->gadget, - USB_STATE_ADDRESS); - } break; default: - result = -EINVAL; + return -EINVAL; } + return 0; + +reset_config: + if (result != USB_GADGET_DELAYED_STATUS) + cdns3_hw_reset_eps_config(priv_dev); + + usb_gadget_set_state(&priv_dev->gadget, + USB_STATE_ADDRESS); + return result; } @@ -705,6 +693,7 @@ static int cdns3_gadget_ep0_queue(struct usb_ep *ep, unsigned long flags; int ret = 0; u8 zlp = 0; + int i; spin_lock_irqsave(&priv_dev->lock, flags); trace_cdns3_ep0_queue(priv_dev, request); @@ -720,6 +709,17 @@ static int cdns3_gadget_ep0_queue(struct usb_ep *ep, u32 val; cdns3_select_ep(priv_dev, 0x00); + + /* + * Configure all non-control EPs which are not enabled by class driver + */ + for (i = 0; i < CDNS3_ENDPOINTS_MAX_COUNT; i++) { + priv_ep = priv_dev->eps[i]; + if (priv_ep && priv_ep->flags & EP_CLAIMED && + !(priv_ep->flags & EP_ENABLED)) + cdns3_ep_config(priv_ep, 0); + } + cdns3_set_hw_configuration(priv_dev); cdns3_ep0_complete_setup(priv_dev, 0, 1); /* wait until configuration set */ @@ -811,6 +811,7 @@ void cdns3_ep0_config(struct cdns3_device *priv_dev) struct cdns3_usb_regs __iomem *regs; struct cdns3_endpoint *priv_ep; u32 max_packet_size = 64; + u32 ep_cfg; regs = priv_dev->regs; @@ -842,8 +843,10 @@ void cdns3_ep0_config(struct cdns3_device *priv_dev) BIT(0) | BIT(16)); } - writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size), - ®s->ep_cfg); + ep_cfg = EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size); + + if (!(priv_ep->flags & EP_CONFIGURED)) + writel(ep_cfg, ®s->ep_cfg); writel(EP_STS_EN_SETUPEN | EP_STS_EN_DESCMISEN | EP_STS_EN_TRBERREN, ®s->ep_sts_en); @@ -851,8 +854,10 @@ void cdns3_ep0_config(struct cdns3_device *priv_dev) /* init ep in */ cdns3_select_ep(priv_dev, USB_DIR_IN); - writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size), - ®s->ep_cfg); + if (!(priv_ep->flags & EP_CONFIGURED)) + writel(ep_cfg, ®s->ep_cfg); + + priv_ep->flags |= EP_CONFIGURED; writel(EP_STS_EN_SETUPEN | EP_STS_EN_TRBERREN, ®s->ep_sts_en); diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index c127af6c0fe8..5fa89baa53da 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -296,6 +296,8 @@ static void cdns3_ep_stall_flush(struct cdns3_endpoint *priv_ep) */ void cdns3_hw_reset_eps_config(struct cdns3_device *priv_dev) { + int i; + writel(USB_CONF_CFGRST, &priv_dev->regs->usb_conf); cdns3_allow_enable_l1(priv_dev, 0); @@ -304,6 +306,10 @@ void cdns3_hw_reset_eps_config(struct cdns3_device *priv_dev) priv_dev->out_mem_is_allocated = 0; priv_dev->wait_for_setup = 0; priv_dev->using_streams = 0; + + for (i = 0; i < CDNS3_ENDPOINTS_MAX_COUNT; i++) + if (priv_dev->eps[i]) + priv_dev->eps[i]->flags &= ~EP_CONFIGURED; } /** @@ -1976,27 +1982,6 @@ static int cdns3_ep_onchip_buffer_reserve(struct cdns3_device *priv_dev, return 0; } -static void cdns3_stream_ep_reconfig(struct cdns3_device *priv_dev, - struct cdns3_endpoint *priv_ep) -{ - if (!priv_ep->use_streams || priv_dev->gadget.speed < USB_SPEED_SUPER) - return; - - if (priv_dev->dev_ver >= DEV_VER_V3) { - u32 mask = BIT(priv_ep->num + (priv_ep->dir ? 16 : 0)); - - /* - * Stream capable endpoints are handled by using ep_tdl - * register. Other endpoints use TDL from TRB feature. - */ - cdns3_clear_register_bit(&priv_dev->regs->tdl_from_trb, mask); - } - - /* Enable Stream Bit TDL chk and SID chk */ - cdns3_set_register_bit(&priv_dev->regs->ep_cfg, EP_CFG_STREAM_EN | - EP_CFG_TDL_CHK | EP_CFG_SID_CHK); -} - static void cdns3_configure_dmult(struct cdns3_device *priv_dev, struct cdns3_endpoint *priv_ep) { @@ -2034,8 +2019,9 @@ static void cdns3_configure_dmult(struct cdns3_device *priv_dev, /** * cdns3_ep_config Configure hardware endpoint * @priv_ep: extended endpoint object + * @enable: set EP_CFG_ENABLE bit in ep_cfg register. */ -void cdns3_ep_config(struct cdns3_endpoint *priv_ep) +int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable) { bool is_iso_ep = (priv_ep->type == USB_ENDPOINT_XFER_ISOC); struct cdns3_device *priv_dev = priv_ep->cdns3_dev; @@ -2096,7 +2082,7 @@ void cdns3_ep_config(struct cdns3_endpoint *priv_ep) break; default: /* all other speed are not supported */ - return; + return -EINVAL; } if (max_packet_size == 1024) @@ -2106,11 +2092,33 @@ void cdns3_ep_config(struct cdns3_endpoint *priv_ep) else priv_ep->trb_burst_size = 16; - ret = cdns3_ep_onchip_buffer_reserve(priv_dev, buffering + 1, - !!priv_ep->dir); - if (ret) { - dev_err(priv_dev->dev, "onchip mem is full, ep is invalid\n"); - return; + /* onchip buffer is only allocated before configuration */ + if (!priv_dev->hw_configured_flag) { + ret = cdns3_ep_onchip_buffer_reserve(priv_dev, buffering + 1, + !!priv_ep->dir); + if (ret) { + dev_err(priv_dev->dev, "onchip mem is full, ep is invalid\n"); + return ret; + } + } + + if (enable) + ep_cfg |= EP_CFG_ENABLE; + + if (priv_ep->use_streams && priv_dev->gadget.speed >= USB_SPEED_SUPER) { + if (priv_dev->dev_ver >= DEV_VER_V3) { + u32 mask = BIT(priv_ep->num + (priv_ep->dir ? 16 : 0)); + + /* + * Stream capable endpoints are handled by using ep_tdl + * register. Other endpoints use TDL from TRB feature. + */ + cdns3_clear_register_bit(&priv_dev->regs->tdl_from_trb, + mask); + } + + /* Enable Stream Bit TDL chk and SID chk */ + ep_cfg |= EP_CFG_STREAM_EN | EP_CFG_TDL_CHK | EP_CFG_SID_CHK; } ep_cfg |= EP_CFG_MAXPKTSIZE(max_packet_size) | @@ -2120,9 +2128,12 @@ void cdns3_ep_config(struct cdns3_endpoint *priv_ep) cdns3_select_ep(priv_dev, bEndpointAddress); writel(ep_cfg, &priv_dev->regs->ep_cfg); + priv_ep->flags |= EP_CONFIGURED; dev_dbg(priv_dev->dev, "Configure %s: with val %08x\n", priv_ep->name, ep_cfg); + + return 0; } /* Find correct direction for HW endpoint according to description */ @@ -2263,7 +2274,7 @@ static int cdns3_gadget_ep_enable(struct usb_ep *ep, u32 bEndpointAddress; unsigned long flags; int enable = 1; - int ret; + int ret = 0; int val; priv_ep = ep_to_cdns3_ep(ep); @@ -2302,6 +2313,17 @@ static int cdns3_gadget_ep_enable(struct usb_ep *ep, bEndpointAddress = priv_ep->num | priv_ep->dir; cdns3_select_ep(priv_dev, bEndpointAddress); + /* + * For some versions of controller at some point during ISO OUT traffic + * DMA reads Transfer Ring for the EP which has never got doorbell. + * This issue was detected only on simulation, but to avoid this issue + * driver add protection against it. To fix it driver enable ISO OUT + * endpoint before setting DRBL. This special treatment of ISO OUT + * endpoints are recommended by controller specification. + */ + if (priv_ep->type == USB_ENDPOINT_XFER_ISOC && !priv_ep->dir) + enable = 0; + if (usb_ss_max_streams(comp_desc) && usb_endpoint_xfer_bulk(desc)) { /* * Enable stream support (SS mode) related interrupts @@ -2312,13 +2334,17 @@ static int cdns3_gadget_ep_enable(struct usb_ep *ep, EP_STS_EN_SIDERREN | EP_STS_EN_MD_EXITEN | EP_STS_EN_STREAMREN; priv_ep->use_streams = true; - cdns3_stream_ep_reconfig(priv_dev, priv_ep); + ret = cdns3_ep_config(priv_ep, enable); priv_dev->using_streams |= true; } + } else { + ret = cdns3_ep_config(priv_ep, enable); } - ret = cdns3_allocate_trb_pool(priv_ep); + if (ret) + goto exit; + ret = cdns3_allocate_trb_pool(priv_ep); if (ret) goto exit; @@ -2348,20 +2374,6 @@ static int cdns3_gadget_ep_enable(struct usb_ep *ep, writel(reg, &priv_dev->regs->ep_sts_en); - /* - * For some versions of controller at some point during ISO OUT traffic - * DMA reads Transfer Ring for the EP which has never got doorbell. - * This issue was detected only on simulation, but to avoid this issue - * driver add protection against it. To fix it driver enable ISO OUT - * endpoint before setting DRBL. This special treatment of ISO OUT - * endpoints are recommended by controller specification. - */ - if (priv_ep->type == USB_ENDPOINT_XFER_ISOC && !priv_ep->dir) - enable = 0; - - if (enable) - cdns3_set_register_bit(&priv_dev->regs->ep_cfg, EP_CFG_ENABLE); - ep->desc = desc; priv_ep->flags &= ~(EP_PENDING_REQUEST | EP_STALLED | EP_STALL_PENDING | EP_QUIRK_ISO_OUT_EN | EP_QUIRK_EXTRA_BUF_EN); diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h index 020936cb9897..5df153ca4389 100644 --- a/drivers/usb/cdns3/gadget.h +++ b/drivers/usb/cdns3/gadget.h @@ -1159,6 +1159,7 @@ struct cdns3_endpoint { #define EP_QUIRK_EXTRA_BUF_DET BIT(12) #define EP_QUIRK_EXTRA_BUF_EN BIT(13) #define EP_TDLCHK_EN BIT(15) +#define EP_CONFIGURED BIT(16) u32 flags; struct cdns3_request *descmis_req; @@ -1360,7 +1361,7 @@ void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep, int cdns3_init_ep0(struct cdns3_device *priv_dev, struct cdns3_endpoint *priv_ep); void cdns3_ep0_config(struct cdns3_device *priv_dev); -void cdns3_ep_config(struct cdns3_endpoint *priv_ep); +int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable); void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir); int __cdns3_gadget_wakeup(struct cdns3_device *priv_dev); -- 2.17.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 3/3] usb: cdns3: Fix on-chip memory overflow issue 2020-10-16 10:16 ` [PATCH 3/3] usb: cdns3: Fix on-chip memory overflow issue Peter Chen @ 2020-10-27 9:11 ` Felipe Balbi 0 siblings, 0 replies; 9+ messages in thread From: Felipe Balbi @ 2020-10-27 9:11 UTC (permalink / raw) To: Peter Chen, pawell, rogerq Cc: linux-usb, linux-imx, gregkh, jun.li, stable, Peter Chen Hi, Peter Chen <peter.chen@nxp.com> writes: > From: Pawel Laszczak <pawell@cadence.com> > > Patch fixes issue caused setting On-chip memory overflow bit in usb_sts > register. The issue occurred because EP_CFG register was set twice > before USB_STS.CFGSTS was set. Every write operation on EP_CFG.BUFFERING > causes that controller increases internal counter holding the number > of reserved on-chip buffers. First time this register was updated in > function cdns3_ep_config before delegating SET_CONFIGURATION request > to class driver and again it was updated when class wanted to enable > endpoint. This patch fixes this issue by configuring endpoints > enabled by class driver in cdns3_gadget_ep_enable and others just > before status stage. > > Cc: <stable@vger.kernel.org> #v5.8+ > Fixes: 7733f6c32e36 ("usb: cdns3: Add Cadence USB3 DRD Driver") > Reported-and-tested-by: Peter Chen <peter.chen@nxp.com> > Signed-off-by: Pawel Laszczak <pawell@cadence.com> > Signed-off-by: Peter Chen <peter.chen@nxp.com> This looks very large for a fix, are you sure there isn't a minimal fix hidden somewhere? -- balbi ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2020-10-28 22:13 UTC | newest] Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- [not found] <20201016101659.29482-1-peter.chen@nxp.com> 2020-10-16 10:16 ` [PATCH 1/3] usb: cdns3: gadget: suspicious implicit sign extension Peter Chen 2020-10-27 9:03 ` Felipe Balbi 2020-10-27 9:48 ` Peter Chen 2020-10-27 10:08 ` David Laight 2020-10-27 14:21 ` Alan Stern 2020-10-28 6:41 ` Peter Chen 2020-10-27 9:03 ` Felipe Balbi 2020-10-16 10:16 ` [PATCH 3/3] usb: cdns3: Fix on-chip memory overflow issue Peter Chen 2020-10-27 9:11 ` Felipe Balbi
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).