From: Roger Quadros <rogerq@ti.com>
To: Pawel Laszczak <pawell@cadence.com>, devicetree@vger.kernel.org
Cc: gregkh@linuxfoundation.org, linux-usb@vger.kernel.org,
linux-kernel@vger.kernel.org, adouglas@cadence.com,
jbergsagel@ti.com, nsekhar@ti.com, nm@ti.com,
sureshp@cadence.com, peter.chen@nxp.com, pjez@cadence.com,
kurahul@cadence.com
Subject: [RFC,v2,11/15] usb:cdns3: Implements ISR functionality.
Date: Wed, 28 Nov 2018 16:54:12 +0200 [thread overview]
Message-ID: <5BFEAC14.1030408@ti.com> (raw)
On 18/11/18 12:09, Pawel Laszczak wrote:
> Patch adds set of generic functions used for handling interrupts
> generated by controller. Interrupt related functions are divided
> into three groups. The first is related to ep0 and is placed in ep0.c.
> The second is responsible for non-default endpoints and is
> implemented in gadget.c file. The last group is not related to
> endpoints interrupts and is placed in gadget.c.
> All groups have common entry point in cdns3_irq_handler_thread function.
>
> Signed-off-by: Pawel Laszczak <pawell@cadence.com>
> ---
> drivers/usb/cdns3/ep0.c | 63 +++++++++++
> drivers/usb/cdns3/gadget.c | 224 ++++++++++++++++++++++++++++++++++++-
> drivers/usb/cdns3/gadget.h | 1 +
> 3 files changed, 287 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c
> index d05169e73631..eb92fd234bd7 100644
> --- a/drivers/usb/cdns3/ep0.c
> +++ b/drivers/usb/cdns3/ep0.c
> @@ -90,6 +90,69 @@ static void cdns3_set_hw_configuration(struct cdns3_device *priv_dev)
> }
> }
>
> +static void __pending_setup_status_handler(struct cdns3_device *priv_dev)
> +{
> + //TODO: Implements this function
> +}
> +
> +/**
> + * cdns3_ep0_setup_phase - Handling setup USB requests
> + * @priv_dev: extended gadget object
> + */
> +static void cdns3_ep0_setup_phase(struct cdns3_device *priv_dev)
> +{
> + //TODO: Implements this function.
> +}
> +
> +static void cdns3_transfer_completed(struct cdns3_device *priv_dev)
> +{
> + //TODO: Implements this function
> +}
> +
> +/**
> + * cdns3_check_ep0_interrupt_proceed - Processes interrupt related to endpoint 0
> + * @priv_dev: extended gadget object
> + * @dir: 1 for IN direction, 0 for OUT direction
> + */
> +void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir)
> +{
> + struct cdns3_usb_regs __iomem *regs = priv_dev->regs;
> + u32 ep_sts_reg;
> +
> + cdns3_select_ep(priv_dev, 0 | (dir ? USB_DIR_IN : USB_DIR_OUT));
> + ep_sts_reg = readl(®s->ep_sts);
> +
> + __pending_setup_status_handler(priv_dev);
> +
> + if ((ep_sts_reg & EP_STS_SETUP) && dir == 0) {
> + struct usb_ctrlrequest *setup = priv_dev->setup;
> +
> + writel(EP_STS_SETUP | EP_STS_IOC | EP_STS_ISP, ®s->ep_sts);
instead you can just clear all events at the end of this function by
writel(ep_sts_reg, ®s->ep_sts);
> +
> + priv_dev->ep0_data_dir = setup->bRequestType & USB_DIR_IN;
> + cdns3_ep0_setup_phase(priv_dev);
> + ep_sts_reg &= ~(EP_STS_SETUP | EP_STS_IOC | EP_STS_ISP);
Not required.
> + }
> +
> + if (ep_sts_reg & EP_STS_TRBERR)
> + writel(EP_STS_TRBERR, &priv_dev->regs->ep_sts);
Can be omitted.
> +
> + if (ep_sts_reg & EP_STS_DESCMIS) {
> + writel(EP_STS_DESCMIS, &priv_dev->regs->ep_sts);
This as well.
> +
> + if (dir == 0 && !priv_dev->setup_pending) {
> + priv_dev->ep0_data_dir = 0;
> + cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma,
> + 8, 0);
> + }
> + }
> +
> + if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) {
> + writel(EP_STS_IOC, &priv_dev->regs->ep_sts);
this write can be omitted.
> + cdns3_transfer_completed(priv_dev);
> + }
here you can do
writel(ep_sts_reg, ®s->ep_sts);
> +}
> +
> /**
> * cdns3_gadget_ep0_enable
> * Function shouldn't be called by gadget driver,
> diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c
> index c965da16c0c8..309202474e57 100644
> --- a/drivers/usb/cdns3/gadget.c
> +++ b/drivers/usb/cdns3/gadget.c
> @@ -58,6 +58,18 @@ void cdns3_set_register_bit(void __iomem *ptr, u32 mask)
> writel(mask, ptr);
> }
>
> +/**
> + * cdns3_ep_reg_pos_to_index - Macro converts bit position of ep_ists register
> + * to index of endpoint object in cdns3_device.eps[] container
> + * @i: bit position of endpoint for which endpoint object is required
> + *
> + * Remember that endpoint container doesn't contain default endpoint
> + */
> +static u8 cdns3_ep_reg_pos_to_index(int i)
> +{
> + return ((i / 16) + (((i % 16) - 2) * 2));
> +}
> +
> /**
> * cdns3_next_request - returns next request from list
> * @list: list containing requests
> @@ -188,6 +200,21 @@ static void cdns3_ep_stall_flush(struct cdns3_endpoint *priv_ep)
> priv_ep->flags |= EP_STALL;
> }
>
> +/**
> + * cdns3_gadget_unconfig - reset device configuration
> + * @priv_dev: extended gadget object
> + */
> +void cdns3_gadget_unconfig(struct cdns3_device *priv_dev)
> +{
> + /* RESET CONFIGURATION */
> + writel(USB_CONF_CFGRST, &priv_dev->regs->usb_conf);
> +
> + cdns3_enable_l1(priv_dev, 0);
> + priv_dev->hw_configured_flag = 0;
> + priv_dev->onchip_mem_allocated_size = 0;
> + priv_dev->out_mem_is_allocated = 0;
> +}
> +
> void cdns3_enable_l1(struct cdns3_device *priv_dev, int enable)
> {
> if (enable)
> @@ -196,6 +223,23 @@ void cdns3_enable_l1(struct cdns3_device *priv_dev, int enable)
> writel(USB_CONF_L1DS, &priv_dev->regs->usb_conf);
> }
>
> +static enum usb_device_speed cdns3_get_speed(struct cdns3_device *priv_dev)
> +{
> + u32 reg;
> +
> + reg = readl(&priv_dev->regs->usb_sts);
> +
> + if (DEV_SUPERSPEED(reg))
> + return USB_SPEED_SUPER;
> + else if (DEV_HIGHSPEED(reg))
> + return USB_SPEED_HIGH;
> + else if (DEV_FULLSPEED(reg))
> + return USB_SPEED_FULL;
> + else if (DEV_LOWSPEED(reg))
> + return USB_SPEED_LOW;
> + return USB_SPEED_UNKNOWN;
> +}
> +
> /**
> * cdns3_gadget_giveback - call struct usb_request's ->complete callback
> * @priv_ep: The endpoint to whom the request belongs to
> @@ -221,12 +265,136 @@ void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep,
> */
> int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
> struct usb_request *request)
> +{
> + return 0;
> +}
> +
> +static void cdns3_transfer_completed(struct cdns3_device *priv_dev,
> + struct cdns3_endpoint *priv_ep)
> {
> //TODO: Implements this function.
> +}
> +
> +/**
> + * cdns3_check_ep_interrupt_proceed - Processes interrupt related to endpoint
> + * @priv_ep: endpoint object
> + *
> + * Returns 0
> + */
> +static int cdns3_check_ep_interrupt_proceed(struct cdns3_endpoint *priv_ep)
> +{
> + struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
> + struct cdns3_usb_regs __iomem *regs;
> + u32 ep_sts_reg;
> +
> + regs = priv_dev->regs;
> +
> + cdns3_select_ep(priv_dev, priv_ep->endpoint.address);
> + ep_sts_reg = readl(®s->ep_sts);
> +
> + if (ep_sts_reg & EP_STS_TRBERR)
> + writel(EP_STS_TRBERR, ®s->ep_sts);
> +
> + if (ep_sts_reg & EP_STS_ISOERR)
> + writel(EP_STS_ISOERR, ®s->ep_sts);
> +
> + if (ep_sts_reg & EP_STS_OUTSMM)
> + writel(EP_STS_OUTSMM, ®s->ep_sts);
> +
> + if (ep_sts_reg & EP_STS_NRDY)
> + writel(EP_STS_NRDY, ®s->ep_sts);
Why check for each bit when you are not doing anything. Instead at the end
you could just do
writel(ep_sts_reg, ®s->ep_sts)
to clear all pending events.
> +
> + if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) {
> + writel(EP_STS_IOC | EP_STS_ISP, ®s->ep_sts);
> + cdns3_transfer_completed(priv_dev, priv_ep);
> + }
> +
> + if (ep_sts_reg & EP_STS_DESCMIS)
> + writel(EP_STS_DESCMIS, ®s->ep_sts);
>
> return 0;
> }
>
> +/**
> + * cdns3_check_usb_interrupt_proceed - Processes interrupt related to device
> + * @priv_dev: extended gadget object
> + * @usb_ists: bitmap representation of device's reported interrupts
> + * (usb_ists register value)
> + */
> +static void cdns3_check_usb_interrupt_proceed(struct cdns3_device *priv_dev,
> + u32 usb_ists)
> +{
> + struct cdns3_usb_regs __iomem *regs;
> + int speed = 0;
> +
> + regs = priv_dev->regs;
> +
> + /* Connection detected */
> + if (usb_ists & (USB_ISTS_CON2I | USB_ISTS_CONI)) {
> + writel(USB_ISTS_CON2I | USB_ISTS_CONI, ®s->usb_ists);
> + speed = cdns3_get_speed(priv_dev);
> +
> + dev_dbg(&priv_dev->dev, "Connection detected at speed: %s %d\n",
> + usb_speed_string(speed), speed);
> +
> + priv_dev->gadget.speed = speed;
> + priv_dev->is_connected = 1;
> + usb_gadget_set_state(&priv_dev->gadget, USB_STATE_POWERED);
> + cdns3_ep0_config(priv_dev);
> + }
> +
> + /* SS Disconnection detected */
> + if (usb_ists & (USB_ISTS_DIS2I | USB_ISTS_DISI)) {
> + dev_dbg(&priv_dev->dev, "Disconnection detected\n");
> +
> + writel(USB_ISTS_DIS2I | USB_ISTS_DISI, ®s->usb_ists);
> + if (priv_dev->gadget_driver &&
> + priv_dev->gadget_driver->disconnect) {
> + spin_unlock(&priv_dev->lock);
> + priv_dev->gadget_driver->disconnect(&priv_dev->gadget);
> + spin_lock(&priv_dev->lock);
> + }
> + priv_dev->gadget.speed = USB_SPEED_UNKNOWN;
> + usb_gadget_set_state(&priv_dev->gadget, USB_STATE_NOTATTACHED);
> + priv_dev->is_connected = 0;
> + cdns3_gadget_unconfig(priv_dev);
> + }
What about non Super-Speed disconnects?
> +
> + if (usb_ists & USB_ISTS_L2ENTI) {
> + dev_dbg(&priv_dev->dev, "Device suspended\n");
> + writel(USB_ISTS_L2ENTI, ®s->usb_ists);
> + }
> +
> + /* Exit from standby mode on L2 exit (Suspend in HS/FS or SS) */
> + if (usb_ists & USB_ISTS_L2EXTI) {
> + dev_dbg(&priv_dev->dev, "[Interrupt] L2 exit detected\n");
> + writel(USB_ISTS_L2EXTI, ®s->usb_ists);
> + }
> +
> + /* Exit from standby mode on U3 exit (Suspend in HS/FS or SS). */
> + if (usb_ists & USB_ISTS_U3EXTI) {
> + dev_dbg(&priv_dev->dev, "U3 exit detected\n");
> + writel(USB_ISTS_U3EXTI, ®s->usb_ists);
> + }
> +
> + /* resets cases */
> + if (usb_ists & (USB_ISTS_UWRESI | USB_ISTS_UHRESI | USB_ISTS_U2RESI)) {
> + writel(USB_ISTS_U2RESI | USB_ISTS_UWRESI | USB_ISTS_UHRESI,
> + ®s->usb_ists);
> +
> + /*read again to check the actuall speed*/
> + speed = cdns3_get_speed(priv_dev);
> +
> + dev_dbg(&priv_dev->dev, "Reset detected at speed: %s %d\n",
> + usb_speed_string(speed), speed);
> +
> + usb_gadget_set_state(&priv_dev->gadget, USB_STATE_DEFAULT);
> + priv_dev->gadget.speed = speed;
> + cdns3_gadget_unconfig(priv_dev);
> + cdns3_ep0_config(priv_dev);
> + }
> +}
> +
> /**
> * cdns3_irq_handler - irq line interrupt handler
> * @cdns: cdns3 instance
> @@ -237,8 +405,62 @@ int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
> */
> static irqreturn_t cdns3_irq_handler_thread(struct cdns3 *cdns)
> {
> + struct cdns3_device *priv_dev;
> irqreturn_t ret = IRQ_NONE;
> - //TODO: implements this function
> + unsigned long flags;
> + u32 reg;
> +
> + priv_dev = container_of(cdns->gadget_dev, struct cdns3_device, dev);
> + spin_lock_irqsave(&priv_dev->lock, flags);
> +
> + /* check USB device interrupt */
> + reg = readl(&priv_dev->regs->usb_ists);
> + if (reg) {
> + dev_dbg(&priv_dev->dev, "IRQ: usb_ists: %08X\n", reg);
dev_dbg will be terribly slow to be useful. Tracepoints?
> + cdns3_check_usb_interrupt_proceed(priv_dev, reg);
> + ret = IRQ_HANDLED;
> + }
> +
> + /* check endpoint interrupt */
> + reg = readl(&priv_dev->regs->ep_ists);
> + if (reg != 0) {
> + dev_dbg(&priv_dev->dev, "IRQ ep_ists: %08X\n", reg);
> + } else {
> + if (USB_STS_CFGSTS(readl(&priv_dev->regs->usb_sts)))
> + ret = IRQ_HANDLED;
Why is this done. We don't seem to be handling anything here.
Don't we need to clear the usb_sts?
> + goto irqend;
> + }
> +
> + /* handle default endpoint OUT */
> + if (reg & EP_ISTS_EP_OUT0) {
> + cdns3_check_ep0_interrupt_proceed(priv_dev, 0);
> + ret = IRQ_HANDLED;
> + }
> +
> + /* handle default endpoint IN */
> + if (reg & EP_ISTS_EP_IN0) {
> + cdns3_check_ep0_interrupt_proceed(priv_dev, 1);
> + ret = IRQ_HANDLED;
> + }
> +
> + /* check if interrupt from non default endpoint, if no exit */
> + reg &= ~(EP_ISTS_EP_OUT0 | EP_ISTS_EP_IN0);
> + if (!reg)
> + goto irqend;
> +
> + do {
> + unsigned int bit_pos = ffs(reg);
> + u32 bit_mask = 1 << (bit_pos - 1);
> + int index;
> +
> + index = cdns3_ep_reg_pos_to_index(bit_pos);
> + cdns3_check_ep_interrupt_proceed(priv_dev->eps[index]);
> + reg &= ~bit_mask;
> + ret = IRQ_HANDLED;
> + } while (reg);
> +
> +irqend:
> + spin_unlock_irqrestore(&priv_dev->lock, flags);
> return ret;
> }
>
> diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h
> index 224f6b830bc9..8c2f363f9340 100644
> --- a/drivers/usb/cdns3/gadget.h
> +++ b/drivers/usb/cdns3/gadget.h
> @@ -1072,6 +1072,7 @@ int cdns3_handshake(void __iomem *ptr, u32 mask, u32 done, int usec);
> void cdns3_set_register_bit(void __iomem *ptr, u32 mask);
> int cdns3_init_ep0(struct cdns3_device *priv_dev);
> void cdns3_ep0_config(struct cdns3_device *priv_dev);
> +void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir);
> void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep);
> void cdns3_enable_l1(struct cdns3_device *priv_dev, int enable);
> struct usb_request *cdns3_next_request(struct list_head *list);
>
cheers,
-roger
WARNING: multiple messages have this Message-ID (diff)
From: Roger Quadros <rogerq@ti.com>
To: Pawel Laszczak <pawell@cadence.com>, devicetree@vger.kernel.org
Cc: gregkh@linuxfoundation.org, linux-usb@vger.kernel.org,
linux-kernel@vger.kernel.org, adouglas@cadence.com,
jbergsagel@ti.com, nsekhar@ti.com, nm@ti.com,
sureshp@cadence.com, peter.chen@nxp.com, pjez@cadence.com,
kurahul@cadence.com
Subject: Re: [RFC PATCH v2 11/15] usb:cdns3: Implements ISR functionality.
Date: Wed, 28 Nov 2018 16:54:12 +0200 [thread overview]
Message-ID: <5BFEAC14.1030408@ti.com> (raw)
In-Reply-To: <1542535751-16079-12-git-send-email-pawell@cadence.com>
On 18/11/18 12:09, Pawel Laszczak wrote:
> Patch adds set of generic functions used for handling interrupts
> generated by controller. Interrupt related functions are divided
> into three groups. The first is related to ep0 and is placed in ep0.c.
> The second is responsible for non-default endpoints and is
> implemented in gadget.c file. The last group is not related to
> endpoints interrupts and is placed in gadget.c.
> All groups have common entry point in cdns3_irq_handler_thread function.
>
> Signed-off-by: Pawel Laszczak <pawell@cadence.com>
> ---
> drivers/usb/cdns3/ep0.c | 63 +++++++++++
> drivers/usb/cdns3/gadget.c | 224 ++++++++++++++++++++++++++++++++++++-
> drivers/usb/cdns3/gadget.h | 1 +
> 3 files changed, 287 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c
> index d05169e73631..eb92fd234bd7 100644
> --- a/drivers/usb/cdns3/ep0.c
> +++ b/drivers/usb/cdns3/ep0.c
> @@ -90,6 +90,69 @@ static void cdns3_set_hw_configuration(struct cdns3_device *priv_dev)
> }
> }
>
> +static void __pending_setup_status_handler(struct cdns3_device *priv_dev)
> +{
> + //TODO: Implements this function
> +}
> +
> +/**
> + * cdns3_ep0_setup_phase - Handling setup USB requests
> + * @priv_dev: extended gadget object
> + */
> +static void cdns3_ep0_setup_phase(struct cdns3_device *priv_dev)
> +{
> + //TODO: Implements this function.
> +}
> +
> +static void cdns3_transfer_completed(struct cdns3_device *priv_dev)
> +{
> + //TODO: Implements this function
> +}
> +
> +/**
> + * cdns3_check_ep0_interrupt_proceed - Processes interrupt related to endpoint 0
> + * @priv_dev: extended gadget object
> + * @dir: 1 for IN direction, 0 for OUT direction
> + */
> +void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir)
> +{
> + struct cdns3_usb_regs __iomem *regs = priv_dev->regs;
> + u32 ep_sts_reg;
> +
> + cdns3_select_ep(priv_dev, 0 | (dir ? USB_DIR_IN : USB_DIR_OUT));
> + ep_sts_reg = readl(®s->ep_sts);
> +
> + __pending_setup_status_handler(priv_dev);
> +
> + if ((ep_sts_reg & EP_STS_SETUP) && dir == 0) {
> + struct usb_ctrlrequest *setup = priv_dev->setup;
> +
> + writel(EP_STS_SETUP | EP_STS_IOC | EP_STS_ISP, ®s->ep_sts);
instead you can just clear all events at the end of this function by
writel(ep_sts_reg, ®s->ep_sts);
> +
> + priv_dev->ep0_data_dir = setup->bRequestType & USB_DIR_IN;
> + cdns3_ep0_setup_phase(priv_dev);
> + ep_sts_reg &= ~(EP_STS_SETUP | EP_STS_IOC | EP_STS_ISP);
Not required.
> + }
> +
> + if (ep_sts_reg & EP_STS_TRBERR)
> + writel(EP_STS_TRBERR, &priv_dev->regs->ep_sts);
Can be omitted.
> +
> + if (ep_sts_reg & EP_STS_DESCMIS) {
> + writel(EP_STS_DESCMIS, &priv_dev->regs->ep_sts);
This as well.
> +
> + if (dir == 0 && !priv_dev->setup_pending) {
> + priv_dev->ep0_data_dir = 0;
> + cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma,
> + 8, 0);
> + }
> + }
> +
> + if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) {
> + writel(EP_STS_IOC, &priv_dev->regs->ep_sts);
this write can be omitted.
> + cdns3_transfer_completed(priv_dev);
> + }
here you can do
writel(ep_sts_reg, ®s->ep_sts);
> +}
> +
> /**
> * cdns3_gadget_ep0_enable
> * Function shouldn't be called by gadget driver,
> diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c
> index c965da16c0c8..309202474e57 100644
> --- a/drivers/usb/cdns3/gadget.c
> +++ b/drivers/usb/cdns3/gadget.c
> @@ -58,6 +58,18 @@ void cdns3_set_register_bit(void __iomem *ptr, u32 mask)
> writel(mask, ptr);
> }
>
> +/**
> + * cdns3_ep_reg_pos_to_index - Macro converts bit position of ep_ists register
> + * to index of endpoint object in cdns3_device.eps[] container
> + * @i: bit position of endpoint for which endpoint object is required
> + *
> + * Remember that endpoint container doesn't contain default endpoint
> + */
> +static u8 cdns3_ep_reg_pos_to_index(int i)
> +{
> + return ((i / 16) + (((i % 16) - 2) * 2));
> +}
> +
> /**
> * cdns3_next_request - returns next request from list
> * @list: list containing requests
> @@ -188,6 +200,21 @@ static void cdns3_ep_stall_flush(struct cdns3_endpoint *priv_ep)
> priv_ep->flags |= EP_STALL;
> }
>
> +/**
> + * cdns3_gadget_unconfig - reset device configuration
> + * @priv_dev: extended gadget object
> + */
> +void cdns3_gadget_unconfig(struct cdns3_device *priv_dev)
> +{
> + /* RESET CONFIGURATION */
> + writel(USB_CONF_CFGRST, &priv_dev->regs->usb_conf);
> +
> + cdns3_enable_l1(priv_dev, 0);
> + priv_dev->hw_configured_flag = 0;
> + priv_dev->onchip_mem_allocated_size = 0;
> + priv_dev->out_mem_is_allocated = 0;
> +}
> +
> void cdns3_enable_l1(struct cdns3_device *priv_dev, int enable)
> {
> if (enable)
> @@ -196,6 +223,23 @@ void cdns3_enable_l1(struct cdns3_device *priv_dev, int enable)
> writel(USB_CONF_L1DS, &priv_dev->regs->usb_conf);
> }
>
> +static enum usb_device_speed cdns3_get_speed(struct cdns3_device *priv_dev)
> +{
> + u32 reg;
> +
> + reg = readl(&priv_dev->regs->usb_sts);
> +
> + if (DEV_SUPERSPEED(reg))
> + return USB_SPEED_SUPER;
> + else if (DEV_HIGHSPEED(reg))
> + return USB_SPEED_HIGH;
> + else if (DEV_FULLSPEED(reg))
> + return USB_SPEED_FULL;
> + else if (DEV_LOWSPEED(reg))
> + return USB_SPEED_LOW;
> + return USB_SPEED_UNKNOWN;
> +}
> +
> /**
> * cdns3_gadget_giveback - call struct usb_request's ->complete callback
> * @priv_ep: The endpoint to whom the request belongs to
> @@ -221,12 +265,136 @@ void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep,
> */
> int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
> struct usb_request *request)
> +{
> + return 0;
> +}
> +
> +static void cdns3_transfer_completed(struct cdns3_device *priv_dev,
> + struct cdns3_endpoint *priv_ep)
> {
> //TODO: Implements this function.
> +}
> +
> +/**
> + * cdns3_check_ep_interrupt_proceed - Processes interrupt related to endpoint
> + * @priv_ep: endpoint object
> + *
> + * Returns 0
> + */
> +static int cdns3_check_ep_interrupt_proceed(struct cdns3_endpoint *priv_ep)
> +{
> + struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
> + struct cdns3_usb_regs __iomem *regs;
> + u32 ep_sts_reg;
> +
> + regs = priv_dev->regs;
> +
> + cdns3_select_ep(priv_dev, priv_ep->endpoint.address);
> + ep_sts_reg = readl(®s->ep_sts);
> +
> + if (ep_sts_reg & EP_STS_TRBERR)
> + writel(EP_STS_TRBERR, ®s->ep_sts);
> +
> + if (ep_sts_reg & EP_STS_ISOERR)
> + writel(EP_STS_ISOERR, ®s->ep_sts);
> +
> + if (ep_sts_reg & EP_STS_OUTSMM)
> + writel(EP_STS_OUTSMM, ®s->ep_sts);
> +
> + if (ep_sts_reg & EP_STS_NRDY)
> + writel(EP_STS_NRDY, ®s->ep_sts);
Why check for each bit when you are not doing anything. Instead at the end
you could just do
writel(ep_sts_reg, ®s->ep_sts)
to clear all pending events.
> +
> + if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) {
> + writel(EP_STS_IOC | EP_STS_ISP, ®s->ep_sts);
> + cdns3_transfer_completed(priv_dev, priv_ep);
> + }
> +
> + if (ep_sts_reg & EP_STS_DESCMIS)
> + writel(EP_STS_DESCMIS, ®s->ep_sts);
>
> return 0;
> }
>
> +/**
> + * cdns3_check_usb_interrupt_proceed - Processes interrupt related to device
> + * @priv_dev: extended gadget object
> + * @usb_ists: bitmap representation of device's reported interrupts
> + * (usb_ists register value)
> + */
> +static void cdns3_check_usb_interrupt_proceed(struct cdns3_device *priv_dev,
> + u32 usb_ists)
> +{
> + struct cdns3_usb_regs __iomem *regs;
> + int speed = 0;
> +
> + regs = priv_dev->regs;
> +
> + /* Connection detected */
> + if (usb_ists & (USB_ISTS_CON2I | USB_ISTS_CONI)) {
> + writel(USB_ISTS_CON2I | USB_ISTS_CONI, ®s->usb_ists);
> + speed = cdns3_get_speed(priv_dev);
> +
> + dev_dbg(&priv_dev->dev, "Connection detected at speed: %s %d\n",
> + usb_speed_string(speed), speed);
> +
> + priv_dev->gadget.speed = speed;
> + priv_dev->is_connected = 1;
> + usb_gadget_set_state(&priv_dev->gadget, USB_STATE_POWERED);
> + cdns3_ep0_config(priv_dev);
> + }
> +
> + /* SS Disconnection detected */
> + if (usb_ists & (USB_ISTS_DIS2I | USB_ISTS_DISI)) {
> + dev_dbg(&priv_dev->dev, "Disconnection detected\n");
> +
> + writel(USB_ISTS_DIS2I | USB_ISTS_DISI, ®s->usb_ists);
> + if (priv_dev->gadget_driver &&
> + priv_dev->gadget_driver->disconnect) {
> + spin_unlock(&priv_dev->lock);
> + priv_dev->gadget_driver->disconnect(&priv_dev->gadget);
> + spin_lock(&priv_dev->lock);
> + }
> + priv_dev->gadget.speed = USB_SPEED_UNKNOWN;
> + usb_gadget_set_state(&priv_dev->gadget, USB_STATE_NOTATTACHED);
> + priv_dev->is_connected = 0;
> + cdns3_gadget_unconfig(priv_dev);
> + }
What about non Super-Speed disconnects?
> +
> + if (usb_ists & USB_ISTS_L2ENTI) {
> + dev_dbg(&priv_dev->dev, "Device suspended\n");
> + writel(USB_ISTS_L2ENTI, ®s->usb_ists);
> + }
> +
> + /* Exit from standby mode on L2 exit (Suspend in HS/FS or SS) */
> + if (usb_ists & USB_ISTS_L2EXTI) {
> + dev_dbg(&priv_dev->dev, "[Interrupt] L2 exit detected\n");
> + writel(USB_ISTS_L2EXTI, ®s->usb_ists);
> + }
> +
> + /* Exit from standby mode on U3 exit (Suspend in HS/FS or SS). */
> + if (usb_ists & USB_ISTS_U3EXTI) {
> + dev_dbg(&priv_dev->dev, "U3 exit detected\n");
> + writel(USB_ISTS_U3EXTI, ®s->usb_ists);
> + }
> +
> + /* resets cases */
> + if (usb_ists & (USB_ISTS_UWRESI | USB_ISTS_UHRESI | USB_ISTS_U2RESI)) {
> + writel(USB_ISTS_U2RESI | USB_ISTS_UWRESI | USB_ISTS_UHRESI,
> + ®s->usb_ists);
> +
> + /*read again to check the actuall speed*/
> + speed = cdns3_get_speed(priv_dev);
> +
> + dev_dbg(&priv_dev->dev, "Reset detected at speed: %s %d\n",
> + usb_speed_string(speed), speed);
> +
> + usb_gadget_set_state(&priv_dev->gadget, USB_STATE_DEFAULT);
> + priv_dev->gadget.speed = speed;
> + cdns3_gadget_unconfig(priv_dev);
> + cdns3_ep0_config(priv_dev);
> + }
> +}
> +
> /**
> * cdns3_irq_handler - irq line interrupt handler
> * @cdns: cdns3 instance
> @@ -237,8 +405,62 @@ int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
> */
> static irqreturn_t cdns3_irq_handler_thread(struct cdns3 *cdns)
> {
> + struct cdns3_device *priv_dev;
> irqreturn_t ret = IRQ_NONE;
> - //TODO: implements this function
> + unsigned long flags;
> + u32 reg;
> +
> + priv_dev = container_of(cdns->gadget_dev, struct cdns3_device, dev);
> + spin_lock_irqsave(&priv_dev->lock, flags);
> +
> + /* check USB device interrupt */
> + reg = readl(&priv_dev->regs->usb_ists);
> + if (reg) {
> + dev_dbg(&priv_dev->dev, "IRQ: usb_ists: %08X\n", reg);
dev_dbg will be terribly slow to be useful. Tracepoints?
> + cdns3_check_usb_interrupt_proceed(priv_dev, reg);
> + ret = IRQ_HANDLED;
> + }
> +
> + /* check endpoint interrupt */
> + reg = readl(&priv_dev->regs->ep_ists);
> + if (reg != 0) {
> + dev_dbg(&priv_dev->dev, "IRQ ep_ists: %08X\n", reg);
> + } else {
> + if (USB_STS_CFGSTS(readl(&priv_dev->regs->usb_sts)))
> + ret = IRQ_HANDLED;
Why is this done. We don't seem to be handling anything here.
Don't we need to clear the usb_sts?
> + goto irqend;
> + }
> +
> + /* handle default endpoint OUT */
> + if (reg & EP_ISTS_EP_OUT0) {
> + cdns3_check_ep0_interrupt_proceed(priv_dev, 0);
> + ret = IRQ_HANDLED;
> + }
> +
> + /* handle default endpoint IN */
> + if (reg & EP_ISTS_EP_IN0) {
> + cdns3_check_ep0_interrupt_proceed(priv_dev, 1);
> + ret = IRQ_HANDLED;
> + }
> +
> + /* check if interrupt from non default endpoint, if no exit */
> + reg &= ~(EP_ISTS_EP_OUT0 | EP_ISTS_EP_IN0);
> + if (!reg)
> + goto irqend;
> +
> + do {
> + unsigned int bit_pos = ffs(reg);
> + u32 bit_mask = 1 << (bit_pos - 1);
> + int index;
> +
> + index = cdns3_ep_reg_pos_to_index(bit_pos);
> + cdns3_check_ep_interrupt_proceed(priv_dev->eps[index]);
> + reg &= ~bit_mask;
> + ret = IRQ_HANDLED;
> + } while (reg);
> +
> +irqend:
> + spin_unlock_irqrestore(&priv_dev->lock, flags);
> return ret;
> }
>
> diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h
> index 224f6b830bc9..8c2f363f9340 100644
> --- a/drivers/usb/cdns3/gadget.h
> +++ b/drivers/usb/cdns3/gadget.h
> @@ -1072,6 +1072,7 @@ int cdns3_handshake(void __iomem *ptr, u32 mask, u32 done, int usec);
> void cdns3_set_register_bit(void __iomem *ptr, u32 mask);
> int cdns3_init_ep0(struct cdns3_device *priv_dev);
> void cdns3_ep0_config(struct cdns3_device *priv_dev);
> +void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir);
> void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep);
> void cdns3_enable_l1(struct cdns3_device *priv_dev, int enable);
> struct usb_request *cdns3_next_request(struct list_head *list);
>
cheers,
-roger
--
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
WARNING: multiple messages have this Message-ID (diff)
From: Roger Quadros <rogerq@ti.com>
To: Pawel Laszczak <pawell@cadence.com>, <devicetree@vger.kernel.org>
Cc: <gregkh@linuxfoundation.org>, <linux-usb@vger.kernel.org>,
<linux-kernel@vger.kernel.org>, <adouglas@cadence.com>,
<jbergsagel@ti.com>, <nsekhar@ti.com>, <nm@ti.com>,
<sureshp@cadence.com>, <peter.chen@nxp.com>, <pjez@cadence.com>,
<kurahul@cadence.com>
Subject: Re: [RFC PATCH v2 11/15] usb:cdns3: Implements ISR functionality.
Date: Wed, 28 Nov 2018 16:54:12 +0200 [thread overview]
Message-ID: <5BFEAC14.1030408@ti.com> (raw)
In-Reply-To: <1542535751-16079-12-git-send-email-pawell@cadence.com>
On 18/11/18 12:09, Pawel Laszczak wrote:
> Patch adds set of generic functions used for handling interrupts
> generated by controller. Interrupt related functions are divided
> into three groups. The first is related to ep0 and is placed in ep0.c.
> The second is responsible for non-default endpoints and is
> implemented in gadget.c file. The last group is not related to
> endpoints interrupts and is placed in gadget.c.
> All groups have common entry point in cdns3_irq_handler_thread function.
>
> Signed-off-by: Pawel Laszczak <pawell@cadence.com>
> ---
> drivers/usb/cdns3/ep0.c | 63 +++++++++++
> drivers/usb/cdns3/gadget.c | 224 ++++++++++++++++++++++++++++++++++++-
> drivers/usb/cdns3/gadget.h | 1 +
> 3 files changed, 287 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c
> index d05169e73631..eb92fd234bd7 100644
> --- a/drivers/usb/cdns3/ep0.c
> +++ b/drivers/usb/cdns3/ep0.c
> @@ -90,6 +90,69 @@ static void cdns3_set_hw_configuration(struct cdns3_device *priv_dev)
> }
> }
>
> +static void __pending_setup_status_handler(struct cdns3_device *priv_dev)
> +{
> + //TODO: Implements this function
> +}
> +
> +/**
> + * cdns3_ep0_setup_phase - Handling setup USB requests
> + * @priv_dev: extended gadget object
> + */
> +static void cdns3_ep0_setup_phase(struct cdns3_device *priv_dev)
> +{
> + //TODO: Implements this function.
> +}
> +
> +static void cdns3_transfer_completed(struct cdns3_device *priv_dev)
> +{
> + //TODO: Implements this function
> +}
> +
> +/**
> + * cdns3_check_ep0_interrupt_proceed - Processes interrupt related to endpoint 0
> + * @priv_dev: extended gadget object
> + * @dir: 1 for IN direction, 0 for OUT direction
> + */
> +void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir)
> +{
> + struct cdns3_usb_regs __iomem *regs = priv_dev->regs;
> + u32 ep_sts_reg;
> +
> + cdns3_select_ep(priv_dev, 0 | (dir ? USB_DIR_IN : USB_DIR_OUT));
> + ep_sts_reg = readl(®s->ep_sts);
> +
> + __pending_setup_status_handler(priv_dev);
> +
> + if ((ep_sts_reg & EP_STS_SETUP) && dir == 0) {
> + struct usb_ctrlrequest *setup = priv_dev->setup;
> +
> + writel(EP_STS_SETUP | EP_STS_IOC | EP_STS_ISP, ®s->ep_sts);
instead you can just clear all events at the end of this function by
writel(ep_sts_reg, ®s->ep_sts);
> +
> + priv_dev->ep0_data_dir = setup->bRequestType & USB_DIR_IN;
> + cdns3_ep0_setup_phase(priv_dev);
> + ep_sts_reg &= ~(EP_STS_SETUP | EP_STS_IOC | EP_STS_ISP);
Not required.
> + }
> +
> + if (ep_sts_reg & EP_STS_TRBERR)
> + writel(EP_STS_TRBERR, &priv_dev->regs->ep_sts);
Can be omitted.
> +
> + if (ep_sts_reg & EP_STS_DESCMIS) {
> + writel(EP_STS_DESCMIS, &priv_dev->regs->ep_sts);
This as well.
> +
> + if (dir == 0 && !priv_dev->setup_pending) {
> + priv_dev->ep0_data_dir = 0;
> + cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma,
> + 8, 0);
> + }
> + }
> +
> + if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) {
> + writel(EP_STS_IOC, &priv_dev->regs->ep_sts);
this write can be omitted.
> + cdns3_transfer_completed(priv_dev);
> + }
here you can do
writel(ep_sts_reg, ®s->ep_sts);
> +}
> +
> /**
> * cdns3_gadget_ep0_enable
> * Function shouldn't be called by gadget driver,
> diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c
> index c965da16c0c8..309202474e57 100644
> --- a/drivers/usb/cdns3/gadget.c
> +++ b/drivers/usb/cdns3/gadget.c
> @@ -58,6 +58,18 @@ void cdns3_set_register_bit(void __iomem *ptr, u32 mask)
> writel(mask, ptr);
> }
>
> +/**
> + * cdns3_ep_reg_pos_to_index - Macro converts bit position of ep_ists register
> + * to index of endpoint object in cdns3_device.eps[] container
> + * @i: bit position of endpoint for which endpoint object is required
> + *
> + * Remember that endpoint container doesn't contain default endpoint
> + */
> +static u8 cdns3_ep_reg_pos_to_index(int i)
> +{
> + return ((i / 16) + (((i % 16) - 2) * 2));
> +}
> +
> /**
> * cdns3_next_request - returns next request from list
> * @list: list containing requests
> @@ -188,6 +200,21 @@ static void cdns3_ep_stall_flush(struct cdns3_endpoint *priv_ep)
> priv_ep->flags |= EP_STALL;
> }
>
> +/**
> + * cdns3_gadget_unconfig - reset device configuration
> + * @priv_dev: extended gadget object
> + */
> +void cdns3_gadget_unconfig(struct cdns3_device *priv_dev)
> +{
> + /* RESET CONFIGURATION */
> + writel(USB_CONF_CFGRST, &priv_dev->regs->usb_conf);
> +
> + cdns3_enable_l1(priv_dev, 0);
> + priv_dev->hw_configured_flag = 0;
> + priv_dev->onchip_mem_allocated_size = 0;
> + priv_dev->out_mem_is_allocated = 0;
> +}
> +
> void cdns3_enable_l1(struct cdns3_device *priv_dev, int enable)
> {
> if (enable)
> @@ -196,6 +223,23 @@ void cdns3_enable_l1(struct cdns3_device *priv_dev, int enable)
> writel(USB_CONF_L1DS, &priv_dev->regs->usb_conf);
> }
>
> +static enum usb_device_speed cdns3_get_speed(struct cdns3_device *priv_dev)
> +{
> + u32 reg;
> +
> + reg = readl(&priv_dev->regs->usb_sts);
> +
> + if (DEV_SUPERSPEED(reg))
> + return USB_SPEED_SUPER;
> + else if (DEV_HIGHSPEED(reg))
> + return USB_SPEED_HIGH;
> + else if (DEV_FULLSPEED(reg))
> + return USB_SPEED_FULL;
> + else if (DEV_LOWSPEED(reg))
> + return USB_SPEED_LOW;
> + return USB_SPEED_UNKNOWN;
> +}
> +
> /**
> * cdns3_gadget_giveback - call struct usb_request's ->complete callback
> * @priv_ep: The endpoint to whom the request belongs to
> @@ -221,12 +265,136 @@ void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep,
> */
> int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
> struct usb_request *request)
> +{
> + return 0;
> +}
> +
> +static void cdns3_transfer_completed(struct cdns3_device *priv_dev,
> + struct cdns3_endpoint *priv_ep)
> {
> //TODO: Implements this function.
> +}
> +
> +/**
> + * cdns3_check_ep_interrupt_proceed - Processes interrupt related to endpoint
> + * @priv_ep: endpoint object
> + *
> + * Returns 0
> + */
> +static int cdns3_check_ep_interrupt_proceed(struct cdns3_endpoint *priv_ep)
> +{
> + struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
> + struct cdns3_usb_regs __iomem *regs;
> + u32 ep_sts_reg;
> +
> + regs = priv_dev->regs;
> +
> + cdns3_select_ep(priv_dev, priv_ep->endpoint.address);
> + ep_sts_reg = readl(®s->ep_sts);
> +
> + if (ep_sts_reg & EP_STS_TRBERR)
> + writel(EP_STS_TRBERR, ®s->ep_sts);
> +
> + if (ep_sts_reg & EP_STS_ISOERR)
> + writel(EP_STS_ISOERR, ®s->ep_sts);
> +
> + if (ep_sts_reg & EP_STS_OUTSMM)
> + writel(EP_STS_OUTSMM, ®s->ep_sts);
> +
> + if (ep_sts_reg & EP_STS_NRDY)
> + writel(EP_STS_NRDY, ®s->ep_sts);
Why check for each bit when you are not doing anything. Instead at the end
you could just do
writel(ep_sts_reg, ®s->ep_sts)
to clear all pending events.
> +
> + if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) {
> + writel(EP_STS_IOC | EP_STS_ISP, ®s->ep_sts);
> + cdns3_transfer_completed(priv_dev, priv_ep);
> + }
> +
> + if (ep_sts_reg & EP_STS_DESCMIS)
> + writel(EP_STS_DESCMIS, ®s->ep_sts);
>
> return 0;
> }
>
> +/**
> + * cdns3_check_usb_interrupt_proceed - Processes interrupt related to device
> + * @priv_dev: extended gadget object
> + * @usb_ists: bitmap representation of device's reported interrupts
> + * (usb_ists register value)
> + */
> +static void cdns3_check_usb_interrupt_proceed(struct cdns3_device *priv_dev,
> + u32 usb_ists)
> +{
> + struct cdns3_usb_regs __iomem *regs;
> + int speed = 0;
> +
> + regs = priv_dev->regs;
> +
> + /* Connection detected */
> + if (usb_ists & (USB_ISTS_CON2I | USB_ISTS_CONI)) {
> + writel(USB_ISTS_CON2I | USB_ISTS_CONI, ®s->usb_ists);
> + speed = cdns3_get_speed(priv_dev);
> +
> + dev_dbg(&priv_dev->dev, "Connection detected at speed: %s %d\n",
> + usb_speed_string(speed), speed);
> +
> + priv_dev->gadget.speed = speed;
> + priv_dev->is_connected = 1;
> + usb_gadget_set_state(&priv_dev->gadget, USB_STATE_POWERED);
> + cdns3_ep0_config(priv_dev);
> + }
> +
> + /* SS Disconnection detected */
> + if (usb_ists & (USB_ISTS_DIS2I | USB_ISTS_DISI)) {
> + dev_dbg(&priv_dev->dev, "Disconnection detected\n");
> +
> + writel(USB_ISTS_DIS2I | USB_ISTS_DISI, ®s->usb_ists);
> + if (priv_dev->gadget_driver &&
> + priv_dev->gadget_driver->disconnect) {
> + spin_unlock(&priv_dev->lock);
> + priv_dev->gadget_driver->disconnect(&priv_dev->gadget);
> + spin_lock(&priv_dev->lock);
> + }
> + priv_dev->gadget.speed = USB_SPEED_UNKNOWN;
> + usb_gadget_set_state(&priv_dev->gadget, USB_STATE_NOTATTACHED);
> + priv_dev->is_connected = 0;
> + cdns3_gadget_unconfig(priv_dev);
> + }
What about non Super-Speed disconnects?
> +
> + if (usb_ists & USB_ISTS_L2ENTI) {
> + dev_dbg(&priv_dev->dev, "Device suspended\n");
> + writel(USB_ISTS_L2ENTI, ®s->usb_ists);
> + }
> +
> + /* Exit from standby mode on L2 exit (Suspend in HS/FS or SS) */
> + if (usb_ists & USB_ISTS_L2EXTI) {
> + dev_dbg(&priv_dev->dev, "[Interrupt] L2 exit detected\n");
> + writel(USB_ISTS_L2EXTI, ®s->usb_ists);
> + }
> +
> + /* Exit from standby mode on U3 exit (Suspend in HS/FS or SS). */
> + if (usb_ists & USB_ISTS_U3EXTI) {
> + dev_dbg(&priv_dev->dev, "U3 exit detected\n");
> + writel(USB_ISTS_U3EXTI, ®s->usb_ists);
> + }
> +
> + /* resets cases */
> + if (usb_ists & (USB_ISTS_UWRESI | USB_ISTS_UHRESI | USB_ISTS_U2RESI)) {
> + writel(USB_ISTS_U2RESI | USB_ISTS_UWRESI | USB_ISTS_UHRESI,
> + ®s->usb_ists);
> +
> + /*read again to check the actuall speed*/
> + speed = cdns3_get_speed(priv_dev);
> +
> + dev_dbg(&priv_dev->dev, "Reset detected at speed: %s %d\n",
> + usb_speed_string(speed), speed);
> +
> + usb_gadget_set_state(&priv_dev->gadget, USB_STATE_DEFAULT);
> + priv_dev->gadget.speed = speed;
> + cdns3_gadget_unconfig(priv_dev);
> + cdns3_ep0_config(priv_dev);
> + }
> +}
> +
> /**
> * cdns3_irq_handler - irq line interrupt handler
> * @cdns: cdns3 instance
> @@ -237,8 +405,62 @@ int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
> */
> static irqreturn_t cdns3_irq_handler_thread(struct cdns3 *cdns)
> {
> + struct cdns3_device *priv_dev;
> irqreturn_t ret = IRQ_NONE;
> - //TODO: implements this function
> + unsigned long flags;
> + u32 reg;
> +
> + priv_dev = container_of(cdns->gadget_dev, struct cdns3_device, dev);
> + spin_lock_irqsave(&priv_dev->lock, flags);
> +
> + /* check USB device interrupt */
> + reg = readl(&priv_dev->regs->usb_ists);
> + if (reg) {
> + dev_dbg(&priv_dev->dev, "IRQ: usb_ists: %08X\n", reg);
dev_dbg will be terribly slow to be useful. Tracepoints?
> + cdns3_check_usb_interrupt_proceed(priv_dev, reg);
> + ret = IRQ_HANDLED;
> + }
> +
> + /* check endpoint interrupt */
> + reg = readl(&priv_dev->regs->ep_ists);
> + if (reg != 0) {
> + dev_dbg(&priv_dev->dev, "IRQ ep_ists: %08X\n", reg);
> + } else {
> + if (USB_STS_CFGSTS(readl(&priv_dev->regs->usb_sts)))
> + ret = IRQ_HANDLED;
Why is this done. We don't seem to be handling anything here.
Don't we need to clear the usb_sts?
> + goto irqend;
> + }
> +
> + /* handle default endpoint OUT */
> + if (reg & EP_ISTS_EP_OUT0) {
> + cdns3_check_ep0_interrupt_proceed(priv_dev, 0);
> + ret = IRQ_HANDLED;
> + }
> +
> + /* handle default endpoint IN */
> + if (reg & EP_ISTS_EP_IN0) {
> + cdns3_check_ep0_interrupt_proceed(priv_dev, 1);
> + ret = IRQ_HANDLED;
> + }
> +
> + /* check if interrupt from non default endpoint, if no exit */
> + reg &= ~(EP_ISTS_EP_OUT0 | EP_ISTS_EP_IN0);
> + if (!reg)
> + goto irqend;
> +
> + do {
> + unsigned int bit_pos = ffs(reg);
> + u32 bit_mask = 1 << (bit_pos - 1);
> + int index;
> +
> + index = cdns3_ep_reg_pos_to_index(bit_pos);
> + cdns3_check_ep_interrupt_proceed(priv_dev->eps[index]);
> + reg &= ~bit_mask;
> + ret = IRQ_HANDLED;
> + } while (reg);
> +
> +irqend:
> + spin_unlock_irqrestore(&priv_dev->lock, flags);
> return ret;
> }
>
> diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h
> index 224f6b830bc9..8c2f363f9340 100644
> --- a/drivers/usb/cdns3/gadget.h
> +++ b/drivers/usb/cdns3/gadget.h
> @@ -1072,6 +1072,7 @@ int cdns3_handshake(void __iomem *ptr, u32 mask, u32 done, int usec);
> void cdns3_set_register_bit(void __iomem *ptr, u32 mask);
> int cdns3_init_ep0(struct cdns3_device *priv_dev);
> void cdns3_ep0_config(struct cdns3_device *priv_dev);
> +void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir);
> void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep);
> void cdns3_enable_l1(struct cdns3_device *priv_dev, int enable);
> struct usb_request *cdns3_next_request(struct list_head *list);
>
cheers,
-roger
--
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
next reply other threads:[~2018-11-28 14:54 UTC|newest]
Thread overview: 202+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-11-28 14:54 Roger Quadros [this message]
2018-11-28 14:54 ` [RFC PATCH v2 11/15] usb:cdns3: Implements ISR functionality Roger Quadros
2018-11-28 14:54 ` Roger Quadros
-- strict thread matches above, loose matches on Subject: below --
2018-12-16 13:31 [RFC,v2,08/15] usb:cdns3: Implements device operations part of the API Pawel Laszczak
2018-12-16 13:31 ` [RFC PATCH v2 08/15] " Pawel Laszczak
2018-12-14 12:30 [RFC,v2,08/15] " Felipe Balbi
2018-12-14 12:30 ` [RFC PATCH v2 08/15] " Felipe Balbi
2018-12-14 12:20 [RFC,v2,08/15] " Sekhar Nori
2018-12-14 12:20 ` [RFC PATCH v2 08/15] " Sekhar Nori
2018-12-14 12:20 ` Sekhar Nori
2018-12-14 11:26 [RFC,v2,08/15] " Felipe Balbi
2018-12-14 11:26 ` [RFC PATCH v2 08/15] " Felipe Balbi
2018-12-14 11:13 [RFC,v2,08/15] " Sekhar Nori
2018-12-14 11:13 ` [RFC PATCH v2 08/15] " Sekhar Nori
2018-12-14 11:13 ` Sekhar Nori
2018-12-14 10:47 [RFC,v2,08/15] " Felipe Balbi
2018-12-14 10:47 ` [RFC PATCH v2 08/15] " Felipe Balbi
2018-12-14 10:39 [RFC,v2,08/15] " Sekhar Nori
2018-12-14 10:39 ` [RFC PATCH v2 08/15] " Sekhar Nori
2018-12-14 10:39 ` Sekhar Nori
2018-12-14 6:49 [RFC,v2,08/15] " Pawel Laszczak
2018-12-14 6:49 ` [RFC PATCH v2 08/15] " Pawel Laszczak
2018-12-14 1:34 [RFC,v2,08/15] " Peter Chen
2018-12-14 1:34 ` [RFC PATCH v2 08/15] " Peter Chen
2018-12-11 19:49 [RFC,v2,08/15] " Pawel Laszczak
2018-12-11 19:49 ` [RFC PATCH v2 08/15] " Pawel Laszczak
2018-12-11 11:26 [RFC,v2,08/15] " Sekhar Nori
2018-12-11 11:26 ` [RFC PATCH v2 08/15] " Sekhar Nori
2018-12-11 11:26 ` Sekhar Nori
2018-12-10 2:12 [RFC,v2,08/15] " Peter Chen
2018-12-10 2:12 ` [RFC PATCH v2 08/15] " Peter Chen
2018-12-06 10:26 [RFC,v2,03/15] dt-bindings: add binding for USBSS-DRD controller Pawel Laszczak
2018-12-06 10:26 ` [RFC PATCH v2 03/15] " Pawel Laszczak
2018-12-06 10:02 [RFC,v2,04/15] usb:cdns3: Driver initialization code Pawel Laszczak
2018-12-06 10:02 ` [RFC PATCH v2 04/15] " Pawel Laszczak
2018-12-06 9:31 [RFC,v2,04/15] " Pawel Laszczak
2018-12-06 9:31 ` [RFC PATCH v2 04/15] " Pawel Laszczak
2018-12-06 7:25 [RFC,v2,05/15] usb:cdns3: Added DRD support Pawel Laszczak
2018-12-06 7:25 ` [RFC PATCH v2 05/15] " Pawel Laszczak
2018-12-06 7:00 [RFC,v2,04/15] usb:cdns3: Driver initialization code Pawel Laszczak
2018-12-06 7:00 ` [RFC PATCH v2 04/15] " Pawel Laszczak
2018-12-05 19:42 [RFC,v2,04/15] " Pawel Laszczak
2018-12-05 19:42 ` [RFC PATCH v2 04/15] " Pawel Laszczak
2018-12-05 19:24 [RFC,v2,04/15] " Pawel Laszczak
2018-12-05 19:24 ` [RFC PATCH v2 04/15] " Pawel Laszczak
2018-12-05 9:07 [RFC,v2,04/15] " Peter Chen
2018-12-05 9:07 ` [RFC PATCH v2 04/15] " Peter Chen
2018-12-05 8:57 [RFC,v2,04/15] " Peter Chen
2018-12-05 8:57 ` [RFC PATCH v2 04/15] " Peter Chen
2018-12-05 8:55 [RFC,v2,04/15] " Alan Douglas
2018-12-05 8:55 ` [RFC PATCH v2 04/15] " Alan Douglas
2018-12-05 8:41 [RFC,v2,06/15] usb:cdns3: Adds Host support Peter Chen
2018-12-05 8:41 ` [RFC PATCH v2 06/15] " Peter Chen
2018-12-05 7:19 [RFC,v2,04/15] usb:cdns3: Driver initialization code Pawel Laszczak
2018-12-05 7:19 ` [RFC PATCH v2 04/15] " Pawel Laszczak
2018-12-04 22:41 [RFC,v2,03/15] dt-bindings: add binding for USBSS-DRD controller Rob Herring
2018-12-04 22:41 ` [RFC PATCH v2 03/15] " Rob Herring
2018-12-04 10:46 [RFC,v2,04/15] usb:cdns3: Driver initialization code Roger Quadros
2018-12-04 10:46 ` [RFC PATCH v2 04/15] " Roger Quadros
2018-12-04 10:46 ` Roger Quadros
2018-12-04 9:18 [RFC,v2,05/15] usb:cdns3: Added DRD support Peter Chen
2018-12-04 9:18 ` [RFC PATCH v2 05/15] " Peter Chen
2018-12-04 9:09 [RFC,v2,04/15] usb:cdns3: Driver initialization code Peter Chen
2018-12-04 9:09 ` [RFC PATCH v2 04/15] " Peter Chen
2018-12-04 8:50 [RFC,v2,04/15] " Peter Chen
2018-12-04 8:50 ` [RFC PATCH v2 04/15] " Peter Chen
2018-12-04 7:11 [RFC,v2,04/15] " Peter Chen
2018-12-04 7:11 ` [RFC PATCH v2 04/15] " Peter Chen
2018-12-03 10:19 [RFC,v2,08/15] usb:cdns3: Implements device operations part of the API Pawel Laszczak
2018-12-03 10:19 ` [RFC PATCH v2 08/15] " Pawel Laszczak
2018-12-02 20:34 [RFC,v2,04/15] usb:cdns3: Driver initialization code Pawel Laszczak
2018-12-02 20:34 ` [RFC PATCH v2 04/15] " Pawel Laszczak
2018-12-02 19:27 [RFC,v2,02/15] usb:cdns3: Device side header file Pawel Laszczak
2018-12-02 19:27 ` [RFC PATCH v2 02/15] " Pawel Laszczak
2018-12-02 16:39 [RFC,v2,12/15] usb:cdns3: Adds enumeration related function Pawel Laszczak
2018-12-02 16:39 ` [RFC PATCH v2 12/15] " Pawel Laszczak
2018-12-02 12:52 [RFC,v2,11/15] usb:cdns3: Implements ISR functionality Pawel Laszczak
2018-12-02 12:52 ` [RFC PATCH v2 11/15] " Pawel Laszczak
2018-12-02 11:49 [RFC,v2,11/15] " Pawel Laszczak
2018-12-02 11:49 ` [RFC PATCH v2 11/15] " Pawel Laszczak
2018-12-02 10:34 [RFC,v2,10/15] usb:cdns3: Ep0 operations part of the API Pawel Laszczak
2018-12-02 10:34 ` [RFC PATCH v2 10/15] " Pawel Laszczak
2018-12-02 10:34 ` Pawel Laszczak
2018-12-01 13:30 [RFC,v2,09/15] usb:cdns3: EpX " Pawel Laszczak
2018-12-01 13:30 ` [RFC PATCH v2 09/15] " Pawel Laszczak
2018-12-01 11:11 [RFC,v2,08/15] usb:cdns3: Implements device " Pawel Laszczak
2018-12-01 11:11 ` [RFC PATCH v2 08/15] " Pawel Laszczak
2018-11-30 14:36 [RFC,v2,07/15] usb:cdns3: Adds Device mode support - initialization Pawel Laszczak
2018-11-30 14:36 ` [RFC PATCH v2 07/15] " Pawel Laszczak
2018-11-30 7:32 [RFC,v2,04/15] usb:cdns3: Driver initialization code Peter Chen
2018-11-30 7:32 ` [RFC PATCH v2 04/15] " Peter Chen
2018-11-30 6:48 [RFC,v2,02/15] usb:cdns3: Device side header file Peter Chen
2018-11-30 6:48 ` [RFC PATCH v2 02/15] " PETER CHEN
2018-11-30 6:29 [RFC,v2,07/15] usb:cdns3: Adds Device mode support - initialization Pawel Laszczak
2018-11-30 6:29 ` [RFC PATCH v2 07/15] " Pawel Laszczak
2018-11-30 4:20 [RFC,v2,07/15] " Peter Chen
2018-11-30 4:20 ` [RFC PATCH v2 07/15] " PETER CHEN
2018-11-28 15:50 [RFC,v2,12/15] usb:cdns3: Adds enumeration related function Roger Quadros
2018-11-28 15:50 ` [RFC PATCH v2 12/15] " Roger Quadros
2018-11-28 15:50 ` Roger Quadros
2018-11-28 14:31 [RFC,v2,10/15] usb:cdns3: Ep0 operations part of the API Roger Quadros
2018-11-28 14:31 ` [RFC PATCH v2 10/15] " Roger Quadros
2018-11-28 14:31 ` Roger Quadros
2018-11-28 12:46 [RFC,v2,09/15] usb:cdns3: EpX " Roger Quadros
2018-11-28 12:46 ` [RFC PATCH v2 09/15] " Roger Quadros
2018-11-28 12:46 ` Roger Quadros
2018-11-28 12:22 [RFC,v2,08/15] usb:cdns3: Implements device " Roger Quadros
2018-11-28 12:22 ` [RFC PATCH v2 08/15] " Roger Quadros
2018-11-28 12:22 ` Roger Quadros
2018-11-28 11:40 [RFC,v2,07/15] usb:cdns3: Adds Device mode support - initialization Felipe Balbi
2018-11-28 11:40 ` [RFC PATCH v2 07/15] " Felipe Balbi
2018-11-28 11:34 [RFC,v2,07/15] " Roger Quadros
2018-11-28 11:34 ` [RFC PATCH v2 07/15] " Roger Quadros
2018-11-28 11:34 ` Roger Quadros
2018-11-27 12:10 [RFC,v2,05/15] usb:cdns3: Added DRD support Roger Quadros
2018-11-27 12:10 ` [RFC PATCH v2 05/15] " Roger Quadros
2018-11-27 11:29 [RFC,v2,05/15] " Pawel Laszczak
2018-11-27 11:29 ` [RFC PATCH v2 05/15] " Pawel Laszczak
2018-11-26 10:17 [RFC,v2,06/15] usb:cdns3: Adds Host support Pawel Laszczak
2018-11-26 10:17 ` [RFC PATCH v2 06/15] " Pawel Laszczak
2018-11-26 10:15 [RFC,v2,05/15] usb:cdns3: Added DRD support Roger Quadros
2018-11-26 10:15 ` [RFC PATCH v2 05/15] " Roger Quadros
2018-11-26 10:09 [RFC,v2,05/15] " Pawel Laszczak
2018-11-26 10:09 ` [RFC PATCH v2 05/15] " Pawel Laszczak
2018-11-26 9:50 [RFC,v2,06/15] usb:cdns3: Adds Host support Roger Quadros
2018-11-26 9:50 ` [RFC PATCH v2 06/15] " Roger Quadros
2018-11-26 9:39 [RFC,v2,05/15] usb:cdns3: Added DRD support Roger Quadros
2018-11-26 9:39 ` [RFC PATCH v2 05/15] " Roger Quadros
2018-11-26 8:39 [RFC,v2,05/15] " Pawel Laszczak
2018-11-26 8:39 ` [RFC PATCH v2 05/15] " Pawel Laszczak
2018-11-26 8:24 [RFC,v2,06/15] usb:cdns3: Adds Host support Pawel Laszczak
2018-11-26 8:24 ` [RFC PATCH v2 06/15] " Pawel Laszczak
2018-11-26 8:07 [RFC,v2,05/15] usb:cdns3: Added DRD support Roger Quadros
2018-11-26 8:07 ` [RFC PATCH v2 05/15] " Roger Quadros
2018-11-26 7:23 [RFC,v2,05/15] " Pawel Laszczak
2018-11-26 7:23 ` [RFC PATCH v2 05/15] " Pawel Laszczak
2018-11-25 12:35 [RFC,v2,04/15] usb:cdns3: Driver initialization code Pawel Laszczak
2018-11-25 12:35 ` [RFC PATCH v2 04/15] " Pawel Laszczak
2018-11-25 7:33 [RFC,v2,03/15] dt-bindings: add binding for USBSS-DRD controller Pawel Laszczak
2018-11-25 7:33 ` [RFC PATCH v2 03/15] " Pawel Laszczak
2018-11-23 14:51 [RFC,v2,05/15] usb:cdns3: Added DRD support Roger Quadros
2018-11-23 14:51 ` [RFC PATCH v2 05/15] " Roger Quadros
2018-11-23 14:51 ` Roger Quadros
2018-11-23 14:23 [RFC,v2,06/15] usb:cdns3: Adds Host support Roger Quadros
2018-11-23 14:23 ` [RFC PATCH v2 06/15] " Roger Quadros
2018-11-23 14:23 ` Roger Quadros
2018-11-23 11:35 [RFC,v2,04/15] usb:cdns3: Driver initialization code Roger Quadros
2018-11-23 11:35 ` [RFC PATCH v2 04/15] " Roger Quadros
2018-11-23 11:35 ` Roger Quadros
2018-11-23 10:53 [RFC,v2,03/15] dt-bindings: add binding for USBSS-DRD controller Roger Quadros
2018-11-23 10:53 ` [RFC PATCH v2 03/15] " Roger Quadros
2018-11-23 10:53 ` Roger Quadros
2018-11-23 10:44 [RFC,v2,01/15] usb:cdns3: add pci to platform driver wrapper Roger Quadros
2018-11-23 10:44 ` [RFC PATCH v2 01/15] " Roger Quadros
2018-11-23 10:44 ` Roger Quadros
2018-11-18 10:09 [RFC,v2,15/15] usb:cdns3: Feature for changing role Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 15/15] " Pawel Laszczak
2018-11-18 10:09 ` Pawel Laszczak
2018-11-18 10:09 [RFC,v2,14/15] usb:cdns3: Adds debugging function Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 14/15] " Pawel Laszczak
2018-11-18 10:09 ` Pawel Laszczak
2018-11-18 10:09 [RFC,v2,13/15] usb:cdns3: Adds transfer related function Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 13/15] " Pawel Laszczak
2018-11-18 10:09 ` Pawel Laszczak
2018-11-18 10:09 [RFC,v2,12/15] usb:cdns3: Adds enumeration " Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 12/15] " Pawel Laszczak
2018-11-18 10:09 ` Pawel Laszczak
2018-11-18 10:09 [RFC,v2,11/15] usb:cdns3: Implements ISR functionality Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 11/15] " Pawel Laszczak
2018-11-18 10:09 ` Pawel Laszczak
2018-11-18 10:09 [RFC,v2,10/15] usb:cdns3: Ep0 operations part of the API Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 10/15] " Pawel Laszczak
2018-11-18 10:09 ` Pawel Laszczak
2018-11-18 10:09 [RFC,v2,09/15] usb:cdns3: EpX " Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 09/15] " Pawel Laszczak
2018-11-18 10:09 ` Pawel Laszczak
2018-11-18 10:09 [RFC,v2,08/15] usb:cdns3: Implements device " Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 08/15] " Pawel Laszczak
2018-11-18 10:09 ` Pawel Laszczak
2018-11-18 10:09 [RFC,v2,07/15] usb:cdns3: Adds Device mode support - initialization Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 07/15] " Pawel Laszczak
2018-11-18 10:09 ` Pawel Laszczak
2018-11-18 10:09 [RFC,v2,06/15] usb:cdns3: Adds Host support Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 06/15] " Pawel Laszczak
2018-11-18 10:09 ` Pawel Laszczak
2018-11-18 10:09 [RFC,v2,05/15] usb:cdns3: Added DRD support Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 05/15] " Pawel Laszczak
2018-11-18 10:09 ` Pawel Laszczak
2018-11-18 10:09 [RFC,v2,04/15] usb:cdns3: Driver initialization code Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 04/15] " Pawel Laszczak
2018-11-18 10:09 ` Pawel Laszczak
2018-11-18 10:08 [RFC,v2,03/15] dt-bindings: add binding for USBSS-DRD controller Pawel Laszczak
2018-11-18 10:08 ` [RFC PATCH v2 03/15] " Pawel Laszczak
2018-11-18 10:08 ` Pawel Laszczak
2018-11-18 10:08 [RFC,v2,02/15] usb:cdns3: Device side header file Pawel Laszczak
2018-11-18 10:08 ` [RFC PATCH v2 02/15] " Pawel Laszczak
2018-11-18 10:08 ` Pawel Laszczak
2018-11-18 10:08 [RFC,v2,01/15] usb:cdns3: add pci to platform driver wrapper Pawel Laszczak
2018-11-18 10:08 ` [RFC PATCH v2 01/15] " Pawel Laszczak
2018-11-18 10:08 ` Pawel Laszczak
2018-11-18 10:08 [RFC PATCH v2 00/15] Introduced new Cadence USBSS DRD Driver Pawel Laszczak
2018-11-18 10:08 ` Pawel Laszczak
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5BFEAC14.1030408@ti.com \
--to=rogerq@ti.com \
--cc=adouglas@cadence.com \
--cc=devicetree@vger.kernel.org \
--cc=gregkh@linuxfoundation.org \
--cc=jbergsagel@ti.com \
--cc=kurahul@cadence.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=nm@ti.com \
--cc=nsekhar@ti.com \
--cc=pawell@cadence.com \
--cc=peter.chen@nxp.com \
--cc=pjez@cadence.com \
--cc=sureshp@cadence.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.