diff options
author | Peter Chen <peter.chen@nxp.com> | 2018-05-07 10:59:55 +0800 |
---|---|---|
committer | Leonard Crestez <leonard.crestez@nxp.com> | 2018-08-24 12:41:33 +0300 |
commit | cf833b13e6cd1c8635960ddc6ca361b3fca12093 (patch) | |
tree | 582a000f3a6b0384ca00a9eb2a61d22a75889323 /drivers/usb/cdns3 | |
parent | 9ee234eef92e0bce78c411ac42a026ef8e048493 (diff) |
MLK-18206-1 usb: cdns3: gadget: show error message when onchip memory is full
For Cadence USB3 device mode, the onchip buffer size is fixed
(eg: 18KB at this version), and the software needs to judge
if the onchip buffer is full when tries to configure endpoint.
For IN endpoint, each endpoint has its own onchip buffer;
For OUT endpoint, all endpoints share the same onchip buffer.
Reviewed-by: Li Jun <jun.li@nxp.com>
Signed-off-by: Peter Chen <peter.chen@nxp.com>
Diffstat (limited to 'drivers/usb/cdns3')
-rw-r--r-- | drivers/usb/cdns3/gadget.c | 52 | ||||
-rw-r--r-- | drivers/usb/cdns3/gadget.h | 6 |
2 files changed, 50 insertions, 8 deletions
diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index 311ad028fd59..9f975f3cd65e 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -294,6 +294,8 @@ static void cdns_gadget_unconfig(struct usb_ss_dev *usb_ss) cdns_enable_l1(usb_ss, 0); usb_ss->hw_configured_flag = 0; + usb_ss->onchip_mem_allocated_size = 0; + usb_ss->out_mem_is_allocated = 0; } /** @@ -1402,6 +1404,37 @@ static int usb_ss_gadget_ep0_queue(struct usb_ep *ep, return 0; } +/** + * ep_onchip_buffer_alloc - Try to allocate onchip buf for EP + * + * The real allocation will occur during write to EP_CFG register, + * this function is used to check if the 'size' allocation is allowed. + * + * @usb_ss: extended gadget object + * @size: the size (KB) for EP would like to allocate + * @is_in: the direction for EP + * + * Return 0 if the later allocation is allowed or negative value on failure + */ + +static int ep_onchip_buffer_alloc(struct usb_ss_dev *usb_ss, + int size, int is_in) +{ + if (is_in) { + usb_ss->onchip_mem_allocated_size += size; + } else if (!usb_ss->out_mem_is_allocated) { + /* ALL OUT EPs are shared the same chunk onchip memory */ + usb_ss->onchip_mem_allocated_size += size; + usb_ss->out_mem_is_allocated = 1; + } + + if (usb_ss->onchip_mem_allocated_size > CDNS3_ONCHIP_BUF_SIZE) { + usb_ss->onchip_mem_allocated_size -= size; + return -EPERM; + } else { + return 0; + } +} /** * cdns_ep_config Configure hardware endpoint @@ -1414,7 +1447,9 @@ static void cdns_ep_config(struct usb_ss_endpoint *usb_ss_ep) u32 max_packet_size = 0; u32 bEndpointAddress = usb_ss_ep->num | usb_ss_ep->dir; u32 interrupt_mask = 0; + int is_in = !!usb_ss_ep->dir; bool is_iso_ep = (usb_ss_ep->type == USB_ENDPOINT_XFER_ISOC); + int default_buf_size = CDNS3_EP_BUF_SIZE; dev_dbg(&usb_ss->dev, "%s: %s addr=0x%x\n", __func__, usb_ss_ep->name, bEndpointAddress); @@ -1461,16 +1496,15 @@ static void cdns_ep_config(struct usb_ss_endpoint *usb_ss_ep) break; } - ep_cfg |= EP_CFG__MAXPKTSIZE__WRITE(max_packet_size); - - if (is_iso_ep) { - ep_cfg |= EP_CFG__BUFFERING__WRITE(1); - ep_cfg |= EP_CFG__MAXBURST__WRITE(0); - } else { - ep_cfg |= EP_CFG__BUFFERING__WRITE(3); - ep_cfg |= EP_CFG__MAXBURST__WRITE(15); + if (ep_onchip_buffer_alloc(usb_ss, default_buf_size, is_in)) { + dev_err(&usb_ss->dev, "onchip mem is full, ep is invalid\n"); + return; } + ep_cfg |= EP_CFG__MAXPKTSIZE__WRITE(max_packet_size) | + EP_CFG__BUFFERING__WRITE(default_buf_size - 1) | + EP_CFG__MAXBURST__WRITE(usb_ss_ep->endpoint.maxburst); + select_ep(usb_ss, bEndpointAddress); gadget_writel(usb_ss, &usb_ss->regs->ep_cfg, ep_cfg); gadget_writel(usb_ss, &usb_ss->regs->ep_sts_en, @@ -2017,6 +2051,8 @@ static int usb_ss_gadget_udc_stop(struct usb_gadget *gadget) usb_ss_ep->used = false; } + usb_ss->onchip_mem_allocated_size = 0; + usb_ss->out_mem_is_allocated = 0; if (!usb_ss->start_gadget) return 0; diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h index be0ae6a94b21..f4d15afee1ca 100644 --- a/drivers/usb/cdns3/gadget.h +++ b/drivers/usb/cdns3/gadget.h @@ -146,6 +146,9 @@ #define CAST_INDEX_TO_EP_ADDR(index) \ ((index / 2 + 1) | ((index % 2) ? 0x80 : 0x00)) +/* 18KB is the total size, and 2KB is used for EP0 and configuration */ +#define CDNS3_ONCHIP_BUF_SIZE 16 /* KB */ +#define CDNS3_EP_BUF_SIZE 2 /* KB */ /*-------------------------------------------------------------------------*/ /* Used structs */ @@ -208,6 +211,9 @@ struct usb_ss_dev { struct device *sysdev; bool start_gadget; /* The device mode is enabled */ struct list_head ep_match_list; + int onchip_mem_allocated_size; /* KB */ + /* Memory is allocated for OUT */ + int out_mem_is_allocated:1; }; #endif /* __DRIVERS_CDNS3_GADGET */ |