LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v15 07/10] USB/ppc4xx: Add Synopsys DWC OTG PCD function
From: Pratyush Anand @ 2011-10-20  9:55 UTC (permalink / raw)
  To: tmarri; +Cc: Mark Miesfeld, greg, linux-usb, linuxppc-dev, Fushen Chen
In-Reply-To: <1318630147-14358-1-git-send-email-tmarri@apm.com>

On Sat, Oct 15, 2011 at 3:39 AM,  <tmarri@apm.com> wrote:
> From: Tirumala Marri <tmarri@apm.com>
>
> The PCD is responsible for translating requests from the gadget driver
> to appropriate actions on the DWC OTG controller.
>

[...]

> +static int dwc_otg_pcd_ep_disable(struct usb_ep *_ep)
> +{
> +       struct pcd_ep *ep;
> +       struct core_if *core_if;
> +       unsigned long flags;
> +
> +       ep = container_of(_ep, struct pcd_ep, ep);
> +       if (!_ep || !ep->desc)
> +               return -EINVAL;
> +
> +       core_if = ep->pcd->otg_dev->core_if;
> +
> +       spin_lock_irqsave(&ep->pcd->lock, flags);
> +
> +       request_nuke(ep);
> +       dwc_otg_ep_deactivate(core_if, &ep->dwc_ep);
> +
> +       ep->desc = NULL;
> +       ep->stopped = 1;
> +       if (ep->dwc_ep.is_in) {
> +               release_perio_tx_fifo(core_if, ep->dwc_ep.tx_fifo_num);
> +               release_tx_fifo(core_if, ep->dwc_ep.tx_fifo_num);

Is only releasing fifo sufficient?
Will the above procedure insures that EP is disable?
I think not.
To insure that EP is disabled , you need to fllow steps as defines in specs.

Also, Fifo must be flushed completely.

Just a question: Which test have you run to test the driver?

I had tested your v13 with testusb and zero gadget and found that all the IN
test were failing because of this limitation.


> +       }
> +

[...]

> +/**
> + * Set the EP STALL.
> + */
> +void dwc_otg_ep_set_stall(struct core_if *core_if, struct dwc_ep *ep)
> +{
> +       u32 depctl = 0;
> +       ulong depctl_addr;
> +
> +       if (ep->is_in) {
> +               depctl_addr =
> +                   (core_if->dev_if->in_ep_regs[ep->num]) + DWC_DIEPCTL;
> +               depctl = dwc_reg_read(depctl_addr, 0);
> +
> +               /* set the disable and stall bits */
> +               if (DWC_DEPCTL_EPENA_RD(depctl))
> +                       depctl = DWC_DEPCTL_EPDIS_RW(depctl, 1);
> +               depctl = DWC_DEPCTL_STALL_HNDSHK_RW(depctl, 1);
> +               dwc_reg_write(depctl_addr, 0, depctl);

After stall bit set, you must disable EP.
Also you must clear TX fifo completetly for respective EP.


> +       } else {
> +               depctl_addr =
> +                   (core_if->dev_if->out_ep_regs[ep->num] + DWC_DOEPCTL);
> +               depctl = dwc_reg_read(depctl_addr, 0);
> +
> +               /* set the stall bit */
> +               depctl = DWC_DEPCTL_STALL_HNDSHK_RW(depctl, 1);
> +               dwc_reg_write(depctl_addr, 0, depctl);
> +       }
> +}

Regards
Pratyush

^ permalink raw reply

* Re: [PATCH v15 06/10] USB/ppc4xx: Add Synopsys DWC OTG HCD queue function
From: Pratyush Anand @ 2011-10-20  9:29 UTC (permalink / raw)
  To: tmarri; +Cc: Mark Miesfeld, greg, linux-usb, linuxppc-dev, Fushen Chen
In-Reply-To: <1318630143-14327-1-git-send-email-tmarri@apm.com>

On Sat, Oct 15, 2011 at 3:39 AM,  <tmarri@apm.com> wrote:
> From: Tirumala Marri <tmarri@apm.com>
>
> Implements functions to manage Queue Heads and Queue
> Transfer Descriptors of DWC USB OTG Controller.
>
> Signed-off-by: Tirumala R Marri <tmarri@apm.com>
> Signed-off-by: Fushen Chen <fchen@apm.com>
> Signed-off-by: Mark Miesfeld <mmiesfeld@apm.com>
> ---
> =A0drivers/usb/dwc/hcd_queue.c | =A0696 +++++++++++++++++++++++++++++++++=
++++++++++
> =A01 files changed, 696 insertions(+), 0 deletions(-)
> =A0create mode 100644 drivers/usb/dwc/hcd_queue.c
>
> diff --git a/drivers/usb/dwc/hcd_queue.c b/drivers/usb/dwc/hcd_queue.c
> new file mode 100644
> index 0000000..67f0409
> --- /dev/null
> +++ b/drivers/usb/dwc/hcd_queue.c
> @@ -0,0 +1,696 @@
> +/*
> + * DesignWare HS OTG controller driver
> + * Copyright (C) 2006 Synopsys, Inc.
> + * Portions Copyright (C) 2010 Applied Micro Circuits Corporation.
> + *
> + * This program is free software: you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License version 2 for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see http://www.gnu.org/licenses
> + * or write to the Free Software Foundation, Inc., 51 Franklin Street,
> + * Suite 500, Boston, MA 02110-1335 USA.
> + *
> + * Based on Synopsys driver version 2.60a
> + * Modified by Mark Miesfeld <mmiesfeld@apm.com>
> + * Modified by Stefan Roese <sr@denx.de>, DENX Software Engineering
> + * Modified by Chuck Meade <chuck@theptrgroup.com>
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "=
AS IS"
> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO T=
HE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PU=
RPOSE
> + * ARE DISCLAIMED. IN NO EVENT SHALL SYNOPSYS, INC. BE LIABLE FOR ANY DI=
RECT,
> + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES
> + * (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SER=
VICES;
> + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUS=
ED AND
> + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR =
TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE=
 OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + */
> +
> +/*
> + * This file contains the functions to manage Queue Heads and Queue
> + * Transfer Descriptors.
> + */
> +
> +#include "hcd.h"
> +
> +static inline int is_fs_ls(enum usb_device_speed speed)
> +{
> + =A0 =A0 =A0 return speed =3D=3D USB_SPEED_FULL || speed =3D=3D USB_SPEE=
D_LOW;
> +}
> +
> +/* Allocates memory for a QH structure. */
> +static inline struct dwc_qh *dwc_otg_hcd_qh_alloc(void)
> +{
> + =A0 =A0 =A0 return kmalloc(sizeof(struct dwc_qh), GFP_ATOMIC);
> +}
> +
> +/**
> + * Initializes a QH structure to initialize the QH.
> + */
> +#define SCHEDULE_SLOP 10
> +static void dwc_otg_hcd_qh_init(struct dwc_hcd *hcd, struct dwc_qh *qh,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct urb =
*urb)
> +{
> + =A0 =A0 =A0 memset(qh, 0, sizeof(struct dwc_qh));
> +
> + =A0 =A0 =A0 /* Initialize QH */
> + =A0 =A0 =A0 switch (usb_pipetype(urb->pipe)) {
> + =A0 =A0 =A0 case PIPE_CONTROL:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->ep_type =3D USB_ENDPOINT_XFER_CONTROL;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case PIPE_BULK:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->ep_type =3D USB_ENDPOINT_XFER_BULK;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case PIPE_ISOCHRONOUS:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->ep_type =3D USB_ENDPOINT_XFER_ISOC;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case PIPE_INTERRUPT:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->ep_type =3D USB_ENDPOINT_XFER_INT;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 qh->ep_is_in =3D usb_pipein(urb->pipe) ? 1 : 0;
> + =A0 =A0 =A0 qh->data_toggle =3D DWC_OTG_HC_PID_DATA0;
> + =A0 =A0 =A0 qh->maxp =3D usb_maxpacket(urb->dev, urb->pipe, !(usb_pipei=
n(urb->pipe)));
> +
> + =A0 =A0 =A0 INIT_LIST_HEAD(&qh->qtd_list);
> + =A0 =A0 =A0 INIT_LIST_HEAD(&qh->qh_list_entry);
> +
> + =A0 =A0 =A0 qh->channel =3D NULL;
> + =A0 =A0 =A0 qh->speed =3D urb->dev->speed;
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* FS/LS Enpoint on HS Hub NOT virtual root hub
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 qh->do_split =3D 0;
> + =A0 =A0 =A0 if (is_fs_ls(urb->dev->speed) && urb->dev->tt && urb->dev->=
tt->hub &&
> + =A0 =A0 =A0 =A0 =A0 urb->dev->tt->hub->devnum !=3D 1)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->do_split =3D 1;
> +
> + =A0 =A0 =A0 if (qh->ep_type =3D=3D USB_ENDPOINT_XFER_INT ||
> + =A0 =A0 =A0 =A0 =A0 qh->ep_type =3D=3D USB_ENDPOINT_XFER_ISOC) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Compute scheduling parameters once and s=
ave them. */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 u32 hprt;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 int bytecount =3D dwc_hb_mult(qh->maxp) *
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_max_packet(qh->maxp);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->usecs =3D NS_TO_US(usb_calc_bus_time(ur=
b->dev->speed,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0usb_pipein(urb->pipe),
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(qh->ep_type =3D=3D
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 USB_ENDPOINT_XFER_ISOC),
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0bytecount));
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Start in a slightly future (micro)frame.=
 */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->sched_frame =3D dwc_frame_num_inc(hcd->=
frame_number,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 SCHEDULE_SLOP);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->interval =3D urb->interval;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 hprt =3D dwc_reg_read(hcd->core_if->host_if=
->hprt0, 0);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (DWC_HPRT0_PRT_SPD_RD(hprt) =3D=3D DWC_H=
PRT0_PRTSPD_HIGH_SPEED &&
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 is_fs_ls(urb->dev->speed)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->interval *=3D 8;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->sched_frame |=3D 0x7;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->start_split_frame =3D q=
h->sched_frame;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> +}
> +
> +/**
> + * This function allocates and initializes a QH.
> + */
> +static struct dwc_qh *dwc_otg_hcd_qh_create(struct dwc_hcd *hcd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 struct urb *urb)
> +{
> + =A0 =A0 =A0 struct dwc_qh *qh;
> +
> + =A0 =A0 =A0 /* Allocate memory */
> + =A0 =A0 =A0 qh =3D dwc_otg_hcd_qh_alloc();
> + =A0 =A0 =A0 if (qh =3D=3D NULL)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
> +
> + =A0 =A0 =A0 dwc_otg_hcd_qh_init(hcd, qh, urb);
> + =A0 =A0 =A0 return qh;
> +}
> +
> +/**
> + * Free each QTD in the QH's QTD-list then free the QH. =A0QH should alr=
eady be
> + * removed from a list. =A0QTD list should already be empty if called fr=
om URB
> + * Dequeue.
> + */
> +void dwc_otg_hcd_qh_free(struct dwc_qh *qh)
> +{
> + =A0 =A0 =A0 struct dwc_qtd *qtd;
> + =A0 =A0 =A0 struct list_head *pos, *temp;
> +
> + =A0 =A0 =A0 /* Free each QTD in the QTD list */
> + =A0 =A0 =A0 list_for_each_safe(pos, temp, &qh->qtd_list) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_del(pos);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd =3D dwc_list_to_qtd(pos);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_hcd_qtd_free(qtd);
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 kfree(qh);
> +}
> +
> +/**
> + * Microframe scheduler
> + * track the total use in hcd->frame_usecs
> + * keep each qh use in qh->frame_usecs
> + * when surrendering the qh then donate the time back
> + */
> +static const u16 max_uframe_usecs[] =3D { 100, 100, 100, 100, 100, 100, =
30, 0 };
> +
> +/*
> + * called from dwc_otg_hcd.c:dwc_otg_hcd_init
> + */
> +int init_hcd_usecs(struct dwc_hcd *hcd)
> +{
> + =A0 =A0 =A0 int i;
> +
> + =A0 =A0 =A0 for (i =3D 0; i < 8; i++)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 hcd->frame_usecs[i] =3D max_uframe_usecs[i]=
;
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static int find_single_uframe(struct dwc_hcd *hcd, struct dwc_qh *qh)
> +{
> + =A0 =A0 =A0 int i;
> + =A0 =A0 =A0 u16 utime;
> + =A0 =A0 =A0 int t_left;
> + =A0 =A0 =A0 int ret;
> + =A0 =A0 =A0 int done;
> +
> + =A0 =A0 =A0 ret =3D -1;
> + =A0 =A0 =A0 utime =3D qh->usecs;
> + =A0 =A0 =A0 t_left =3D utime;
> + =A0 =A0 =A0 i =3D 0;
> + =A0 =A0 =A0 done =3D 0;
> + =A0 =A0 =A0 while (done =3D=3D 0) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* At the start hcd->frame_usecs[i] =3D max=
_uframe_usecs[i]; */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (utime <=3D hcd->frame_usecs[i]) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hcd->frame_usecs[i] -=3D ut=
ime;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->frame_usecs[i] +=3D uti=
me;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 t_left -=3D utime;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D i;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 done =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return ret;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 i++;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (i =3D=3D 8) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 done =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D -1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 return ret;
> +}
> +
> +/*
> + * use this for FS apps that can span multiple uframes
> + */
> +static int find_multi_uframe(struct dwc_hcd *hcd, struct dwc_qh *qh)
> +{
> + =A0 =A0 =A0 int i;
> + =A0 =A0 =A0 int j;
> + =A0 =A0 =A0 u16 utime;
> + =A0 =A0 =A0 int t_left;
> + =A0 =A0 =A0 int ret;
> + =A0 =A0 =A0 int done;
> + =A0 =A0 =A0 u16 xtime;
> +
> + =A0 =A0 =A0 ret =3D -1;
> + =A0 =A0 =A0 utime =3D qh->usecs;
> + =A0 =A0 =A0 t_left =3D utime;
> + =A0 =A0 =A0 i =3D 0;
> + =A0 =A0 =A0 done =3D 0;
> +loop:
> + =A0 =A0 =A0 while (done =3D=3D 0) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (hcd->frame_usecs[i] <=3D 0) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 i++;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (i =3D=3D 8) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 done =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D -1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto loop;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* We need n consequtive slots so use j a=
s a start slot.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* j plus j+1 must be enough time (for no=
w)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 xtime =3D hcd->frame_usecs[i];
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 for (j =3D i + 1; j < 8; j++) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* if we add this frame r=
emaining time to xtime we may
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* be OK, if not we need =
to test j for a complete frame.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if ((xtime + hcd->frame_use=
cs[j]) < utime) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (hcd->fr=
ame_usecs[j] < max_uframe_usecs[j]) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 j =3D 8;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 ret =3D -1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 continue;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (xtime >=3D utime) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D i;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 j =3D 8; =
=A0/* stop loop with a good value ret */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* add the frame time to x =
time */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 xtime +=3D hcd->frame_usecs=
[j];
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* we must have a fully ava=
ilable next frame or break */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if ((xtime < utime) &&
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (hcd->frame_usecs[j=
] =3D=3D max_uframe_usecs[j])) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D -1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 j =3D 8; =
=A0/* stop loop with a bad value ret */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (ret >=3D 0) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 t_left =3D utime;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 for (j =3D i; (t_left > 0) =
&& (j < 8); j++) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 t_left -=3D=
 hcd->frame_usecs[j];
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (t_left =
<=3D 0) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 qh->frame_usecs[j] +=3D
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 hcd->frame_usecs[j] + t_left;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 hcd->frame_usecs[j] =3D -t_left;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 ret =3D i;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 done =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 qh->frame_usecs[j] +=3D
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 hcd->frame_usecs[j];
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 hcd->frame_usecs[j] =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 i++;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (i =3D=3D 8) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 done =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D -1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 return ret;
> +}
> +
> +static int find_uframe(struct dwc_hcd *hcd, struct dwc_qh *qh)
> +{
> + =A0 =A0 =A0 int ret =3D -1;
> +
> + =A0 =A0 =A0 if (qh->speed =3D=3D USB_SPEED_HIGH)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* if this is a hs transaction we need a fu=
ll frame */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D find_single_uframe(hcd, qh);
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* FS transaction may need a sequence of fr=
ames */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D find_multi_uframe(hcd, qh);
> +
> + =A0 =A0 =A0 return ret;
> +}
> +
> +/**
> + * Checks that the max transfer size allowed in a host channel is large =
enough
> + * to handle the maximum data transfer in a single (micro)frame for a pe=
riodic
> + * transfer.
> + */
> +static int check_max_xfer_size(struct dwc_hcd *hcd, struct dwc_qh *qh)
> +{
> + =A0 =A0 =A0 int status =3D 0;
> + =A0 =A0 =A0 u32 max_xfer_size;
> + =A0 =A0 =A0 u32 max_channel_xfer_size;
> +
> + =A0 =A0 =A0 max_xfer_size =3D dwc_max_packet(qh->maxp) * dwc_hb_mult(qh=
->maxp);
> + =A0 =A0 =A0 max_channel_xfer_size =3D hcd->core_if->core_params->max_tr=
ansfer_size;
> +
> + =A0 =A0 =A0 if (max_xfer_size > max_channel_xfer_size) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_notice("%s: Periodic xfer length %d > ma=
x xfer "
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "length for channel %d\=
n", __func__, max_xfer_size,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 max_channel_xfer_size);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 status =3D -ENOSPC;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 return status;
> +}
> +
> +/**
> + * Schedules an interrupt or isochronous transfer in the periodic schedu=
le.
> + */
> +static int schedule_periodic(struct dwc_hcd *hcd, struct dwc_qh *qh)
> +{
> + =A0 =A0 =A0 int status;
> + =A0 =A0 =A0 struct usb_bus *bus =3D hcd_to_bus(dwc_otg_hcd_to_hcd(hcd))=
;
> + =A0 =A0 =A0 int frame;
> +
> + =A0 =A0 =A0 status =3D find_uframe(hcd, qh);
> + =A0 =A0 =A0 frame =3D -1;
> + =A0 =A0 =A0 if (status =3D=3D 0) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 frame =3D 7;
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (status > 0)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 frame =3D status - 1;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 /* Set the new frame up */
> + =A0 =A0 =A0 if (frame > -1) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->sched_frame &=3D ~0x7;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->sched_frame |=3D (frame & 7);
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 if (status !=3D -1)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 status =3D 0;
> + =A0 =A0 =A0 if (status) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_notice("%s: Insufficient periodic bandwi=
dth for "
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "periodic transfer.\n",=
 __func__);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return status;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 status =3D check_max_xfer_size(hcd, qh);
> + =A0 =A0 =A0 if (status) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_notice("%s: Channel max transfer size to=
o small "
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "for periodic transfer.=
\n", __func__);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return status;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 /* Always start in the inactive schedule. */
> + =A0 =A0 =A0 list_add_tail(&qh->qh_list_entry, &hcd->periodic_sched_inac=
tive);
> +
> + =A0 =A0 =A0 /* Update claimed usecs per (micro)frame. */
> + =A0 =A0 =A0 hcd->periodic_usecs +=3D qh->usecs;
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* Update average periodic bandwidth claimed and # period=
ic reqs for
> + =A0 =A0 =A0 =A0* usbfs.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 bus->bandwidth_allocated +=3D qh->usecs / qh->interval;
> +
> + =A0 =A0 =A0 if (qh->ep_type =3D=3D USB_ENDPOINT_XFER_INT)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 bus->bandwidth_int_reqs++;
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 bus->bandwidth_isoc_reqs++;
> +
> + =A0 =A0 =A0 return status;
> +}
> +
> +/**
> + * This function adds a QH to either the non periodic or periodic schedu=
le if
> + * it is not already in the schedule. If the QH is already in the schedu=
le, no
> + * action is taken.
> + */
> +static int dwc_otg_hcd_qh_add(struct dwc_hcd *hcd, struct dwc_qh *qh)
> +{
> + =A0 =A0 =A0 int status =3D 0;
> +
> + =A0 =A0 =A0 /* QH may already be in a schedule. */
> + =A0 =A0 =A0 if (!list_empty(&qh->qh_list_entry))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto done;
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* Add the new QH to the appropriate schedule. For non-pe=
riodic, always
> + =A0 =A0 =A0 =A0* start in the inactive schedule.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 if (dwc_qh_is_non_per(qh))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_add_tail(&qh->qh_list_entry,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &hcd->non_perio=
dic_sched_inactive);
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 status =3D schedule_periodic(hcd, qh);
> +
> +done:
> + =A0 =A0 =A0 return status;
> +}
> +
> +/**
> + * This function adds a QH to the non periodic deferred schedule.
> + *
> + * @return 0 if successful, negative error code otherwise.
> + */
> +static int dwc_otg_hcd_qh_add_deferred(struct dwc_hcd *hcd, struct dwc_q=
h *qh)
> +{
> + =A0 =A0 =A0 if (!list_empty(&qh->qh_list_entry))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* QH already in a schedule. */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto done;
> +
> + =A0 =A0 =A0 /* Add the new QH to the non periodic deferred schedule */
> + =A0 =A0 =A0 if (dwc_qh_is_non_per(qh))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_add_tail(&qh->qh_list_entry,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &hcd->non_perio=
dic_sched_deferred);
> +done:
> + =A0 =A0 =A0 return 0;
> +}
> +
> +/**
> + * Removes an interrupt or isochronous transfer from the periodic schedu=
le.
> + */
> +static void deschedule_periodic(struct dwc_hcd *hcd, struct dwc_qh *qh)
> +{
> + =A0 =A0 =A0 struct usb_bus *bus =3D hcd_to_bus(dwc_otg_hcd_to_hcd(hcd))=
;
> + =A0 =A0 =A0 int i;
> +
> + =A0 =A0 =A0 list_del_init(&qh->qh_list_entry);
> + =A0 =A0 =A0 /* Update claimed usecs per (micro)frame. */
> + =A0 =A0 =A0 hcd->periodic_usecs -=3D qh->usecs;
> + =A0 =A0 =A0 for (i =3D 0; i < 8; i++) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 hcd->frame_usecs[i] +=3D qh->frame_usecs[i]=
;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->frame_usecs[i] =3D 0;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* Update average periodic bandwidth claimed and # period=
ic reqs for
> + =A0 =A0 =A0 =A0* usbfs.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 bus->bandwidth_allocated -=3D qh->usecs / qh->interval;
> +
> + =A0 =A0 =A0 if (qh->ep_type =3D=3D USB_ENDPOINT_XFER_INT)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 bus->bandwidth_int_reqs--;
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 bus->bandwidth_isoc_reqs--;
> +}
> +
> +/**
> + * Removes a QH from either the non-periodic or periodic schedule. =A0Me=
mory is
> + * not freed.
> + */
> +void dwc_otg_hcd_qh_remove(struct dwc_hcd *hcd, struct dwc_qh *qh)
> +{
> + =A0 =A0 =A0 /* Do nothing if QH is not in a schedule */
> + =A0 =A0 =A0 if (list_empty(&qh->qh_list_entry))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
> +
> + =A0 =A0 =A0 if (dwc_qh_is_non_per(qh)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (hcd->non_periodic_qh_ptr =3D=3D &qh->qh=
_list_entry)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hcd->non_periodic_qh_ptr =
=3D
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hcd->non_periodic_q=
h_ptr->next;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_del_init(&qh->qh_list_entry);
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 deschedule_periodic(hcd, qh);
> + =A0 =A0 =A0 }
> +}
> +
> +/**
> + * Defers a QH. For non-periodic QHs, removes the QH from the active
> + * non-periodic schedule. The QH is added to the deferred non-periodic
> + * schedule if any QTDs are still attached to the QH.
> + */
> +int dwc_otg_hcd_qh_deferr(struct dwc_hcd *hcd, struct dwc_qh *qh, int de=
lay)
> +{
> + =A0 =A0 =A0 int deact =3D 1;
> +
> + =A0 =A0 =A0 if (dwc_qh_is_non_per(qh)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->sched_frame =3D dwc_frame_num_inc(hcd->=
frame_number, delay);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->channel =3D NULL;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->qtd_in_process =3D NULL;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 deact =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_hcd_qh_remove(hcd, qh);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!list_empty(&qh->qtd_list))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Add back to deferred non=
-periodic schedule. */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_hcd_qh_add_deferred=
(hcd, qh);
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 return deact;
> +}
> +
> +/**
> + * =A0Schedule the next continuing periodic split transfer
> + */
> +static void sched_next_per_split_xfr(struct dwc_qh *qh, u16 fr_num,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
int sched_split)
> +{
> + =A0 =A0 =A0 if (sched_split) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->sched_frame =3D fr_num;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (dwc_frame_num_le(fr_num,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
dwc_frame_num_inc(qh->start_split_frame,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A01))) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Allow one frame to ela=
pse after start split
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* microframe before sche=
duling complete split, but DONT
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* if we are doing the ne=
xt start split in the
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* same frame for an ISOC=
 out.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (qh->ep_type !=3D USB_EN=
DPOINT_XFER_ISOC ||
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->ep_is_in)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->sched_f=
rame =3D
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc=
_frame_num_inc(qh->sched_frame, 1);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->sched_frame =3D dwc_frame_num_inc(qh->s=
tart_split_frame,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->interval);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (dwc_frame_num_le(qh->sched_frame, fr_nu=
m))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->sched_frame =3D fr_num;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->sched_frame |=3D 0x7;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->start_split_frame =3D qh->sched_frame;
> + =A0 =A0 =A0 }
> +}
> +
> +/**
> + * Deactivates a periodic QH. =A0The QH is removed from the periodic que=
ued
> + * schedule. If there are any QTDs still attached to the QH, the QH is a=
dded to
> + * either the periodic inactive schedule or the periodic ready schedule =
and its
> + * next scheduled frame is calculated. The QH is placed in the ready sch=
edule if
> + * the scheduled frame has been reached already. Otherwise it's placed i=
n the
> + * inactive schedule. If there are no QTDs attached to the QH, the QH is
> + * completely removed from the periodic schedule.
> + */
> +static void deactivate_periodic_qh(struct dwc_hcd *hcd, struct dwc_qh *q=
h,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int =
sched_next_split)
> +{
> + =A0 =A0 =A0 /* unsigned long flags; */
> + =A0 =A0 =A0 u16 fr_num =3D dwc_otg_hcd_get_frame_number(dwc_otg_hcd_to_=
hcd(hcd));
> +
> + =A0 =A0 =A0 if (qh->do_split) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 sched_next_per_split_xfr(qh, fr_num, sched_=
next_split);
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->sched_frame =3D dwc_frame_num_inc(qh->s=
ched_frame,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->interval);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (dwc_frame_num_le(qh->sched_frame, fr_nu=
m))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->sched_frame =3D fr_num;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 if (list_empty(&qh->qtd_list)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_hcd_qh_remove(hcd, qh);
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Remove from periodic_sched_queued and =
move to appropriate
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* queue.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (qh->sched_frame =3D=3D fr_num)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_move(&qh->qh_list_entr=
y,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &hcd->p=
eriodic_sched_ready);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_move(&qh->qh_list_entr=
y,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &hcd->p=
eriodic_sched_inactive);
> + =A0 =A0 =A0 }
> +}
> +
> +/**
> + * Deactivates a non-periodic QH. =A0Removes the QH from the active non-=
periodic
> + * schedule. The QH is added to the inactive non-periodic schedule if an=
y QTDs
> + * are still attached to the QH.
> + */
> +static void deactivate_non_periodic_qh(struct dwc_hcd *hcd, struct dwc_q=
h *qh)
> +{
> + =A0 =A0 =A0 dwc_otg_hcd_qh_remove(hcd, qh);
> + =A0 =A0 =A0 if (!list_empty(&qh->qtd_list))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_hcd_qh_add(hcd, qh);
> +}
> +
> +/**
> + * Deactivates a QH. =A0Determines if the QH is periodic or non-periodic=
 and takes
> + * the appropriate action.
> + */
> +void dwc_otg_hcd_qh_deactivate(struct dwc_hcd *hcd, struct dwc_qh *qh,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int sched_ne=
xt_periodic_split)
> +{
> + =A0 =A0 =A0 if (dwc_qh_is_non_per(qh))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 deactivate_non_periodic_qh(hcd, qh);
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 deactivate_periodic_qh(hcd, qh, sched_next_=
periodic_split);
> +}
> +
> +/**
> + * Initializes a QTD structure.
> + */
> +static void dwc_otg_hcd_qtd_init(struct dwc_qtd *qtd, struct urb *urb)
> +{
> + =A0 =A0 =A0 memset(qtd, 0, sizeof(struct dwc_qtd));
> + =A0 =A0 =A0 qtd->urb =3D urb;
> +
> + =A0 =A0 =A0 if (usb_pipecontrol(urb->pipe)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* The only time the QTD data toggle is u=
sed is on the data
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* phase of control transfers. This phase=
 always starts with
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* DATA1.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->data_toggle =3D DWC_OTG_HC_PID_DATA1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->control_phase =3D DWC_OTG_CONTROL_SETU=
P;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /* start split */
> + =A0 =A0 =A0 qtd->complete_split =3D 0;
> + =A0 =A0 =A0 qtd->isoc_split_pos =3D DWC_HCSPLIT_XACTPOS_ALL;
> + =A0 =A0 =A0 qtd->isoc_split_offset =3D 0;
> +
> + =A0 =A0 =A0 /* Store the qtd ptr in the urb to reference what QTD. */
> + =A0 =A0 =A0 urb->hcpriv =3D qtd;
> +
> + =A0 =A0 =A0 INIT_LIST_HEAD(&qtd->qtd_list_entry);
> + =A0 =A0 =A0 return;
> +}
> +
> +/* Allocates memory for a QTD structure. */
> +static inline struct dwc_qtd *dwc_otg_hcd_qtd_alloc(gfp_t _mem_flags)
> +{
> + =A0 =A0 =A0 return kmalloc(sizeof(struct dwc_qtd), _mem_flags);
> +}
> +
> +/**
> + * This function allocates and initializes a QTD.
> + */
> +struct dwc_qtd *dwc_otg_hcd_qtd_create(struct urb *urb, gfp_t _mem_flags=
)
> +{
> + =A0 =A0 =A0 struct dwc_qtd *qtd =3D dwc_otg_hcd_qtd_alloc(_mem_flags);
> +
> + =A0 =A0 =A0 if (!qtd)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
> +
> + =A0 =A0 =A0 dwc_otg_hcd_qtd_init(qtd, urb);
> + =A0 =A0 =A0 return qtd;
> +}
> +
> +/**
> + * This function adds a QTD to the QTD-list of a QH. =A0It will find the=
 correct
> + * QH to place the QTD into. =A0If it does not find a QH, then it will c=
reate a
> + * new QH. If the QH to which the QTD is added is not currently schedule=
d, it
> + * is placed into the proper schedule based on its EP type.
> + *
> + */
> +int dwc_otg_hcd_qtd_add(struct dwc_qtd *qtd, struct dwc_hcd *hcd)
> +{
> + =A0 =A0 =A0 struct usb_host_endpoint *ep;
> + =A0 =A0 =A0 struct dwc_qh *qh;
> + =A0 =A0 =A0 int retval =3D 0;
> + =A0 =A0 =A0 struct urb *urb =3D qtd->urb;
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* Get the QH which holds the QTD-list to insert to. Crea=
te QH if it
> + =A0 =A0 =A0 =A0* doesn't exist.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 ep =3D dwc_urb_to_endpoint(urb);
> +
> + =A0 =A0 =A0 qh =3D (struct dwc_qh *)ep->hcpriv;
> + =A0 =A0 =A0 if (!qh) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh =3D dwc_otg_hcd_qh_create(hcd, urb);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!qh) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval =3D -1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto done;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ep->hcpriv =3D qh;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 qtd->qtd_qh_ptr =3D qh;
> + =A0 =A0 =A0 retval =3D dwc_otg_hcd_qh_add(hcd, qh);
> + =A0 =A0 =A0 if (!retval)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_add_tail(&qtd->qtd_list_entry, &qh->qt=
d_list);
> +
> +done:
> + =A0 =A0 =A0 return retval;
> +}
> --
> 1.6.1.rc3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at =A0http://vger.kernel.org/majordomo-info.html
>

Reviewed-by: Pratyush Anand <pratyush.anand@st.com>

^ permalink raw reply

* Re: [PATCH v15 05/10] USB/ppc4xx: Add Synopsys DWC OTG HCD interrupt function
From: Pratyush Anand @ 2011-10-20  9:25 UTC (permalink / raw)
  To: tmarri; +Cc: Mark Miesfeld, greg, linux-usb, linuxppc-dev, Fushen Chen
In-Reply-To: <1318630139-14296-1-git-send-email-tmarri@apm.com>

On Sat, Oct 15, 2011 at 3:38 AM,  <tmarri@apm.com> wrote:
> From: Tirumala Marri <tmarri@apm.com>
>
> Implements DWC OTG USB HCD interrupt service routine.
>
> Signed-off-by: Tirumala R Marri <tmarri@apm.com>
> Signed-off-by: Fushen Chen <fchen@apm.com>
> Signed-off-by: Mark Miesfeld <mmiesfeld@apm.com>
> ---
> =A0drivers/usb/dwc/hcd_intr.c | 1477 ++++++++++++++++++++++++++++++++++++=
++++++++
> =A01 files changed, 1477 insertions(+), 0 deletions(-)
> =A0create mode 100644 drivers/usb/dwc/hcd_intr.c
>
> diff --git a/drivers/usb/dwc/hcd_intr.c b/drivers/usb/dwc/hcd_intr.c
> new file mode 100644
> index 0000000..b16934d
> --- /dev/null
> +++ b/drivers/usb/dwc/hcd_intr.c
> @@ -0,0 +1,1477 @@
> +/*
> + * DesignWare HS OTG controller driver
> + * Copyright (C) 2006 Synopsys, Inc.
> + * Portions Copyright (C) 2010 Applied Micro Circuits Corporation.
> + *
> + * This program is free software: you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License version 2 for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see http://www.gnu.org/licenses
> + * or write to the Free Software Foundation, Inc., 51 Franklin Street,
> + * Suite 500, Boston, MA 02110-1335 USA.
> + *
> + * Based on Synopsys driver version 2.60a
> + * Modified by Mark Miesfeld <mmiesfeld@apm.com>
> + * Modified by Stefan Roese <sr@denx.de>, DENX Software Engineering
> + * Modified by Chuck Meade <chuck@theptrgroup.com>
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "=
AS IS"
> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO T=
HE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PU=
RPOSE
> + * ARE DISCLAIMED. IN NO EVENT SHALL SYNOPSYS, INC. BE LIABLE FOR ANY DI=
RECT,
> + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES
> + * (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SER=
VICES;
> + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUS=
ED AND
> + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR =
TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE=
 OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + */
> +
> +#include "hcd.h"
> +
> +/* This file contains the implementation of the HCD Interrupt handlers. =
=A0 =A0 =A0 =A0*/
> +static const int erratum_usb09_patched;
> +static const int deferral_on =3D 1;
> +static const int nak_deferral_delay =3D 8;
> +static const int nyet_deferral_delay =3D 1;
> +
> +/**
> + * Handles the start-of-frame interrupt in host mode. Non-periodic
> + * transactions may be queued to the DWC_otg controller for the current
> + * (micro)frame. Periodic transactions may be queued to the controller f=
or the
> + * next (micro)frame.
> + */
> +static int dwc_otg_hcd_handle_sof_intr(struct dwc_hcd *hcd)
> +{
> + =A0 =A0 =A0 u32 hfnum =3D 0;
> + =A0 =A0 =A0 struct list_head *qh_entry;
> + =A0 =A0 =A0 struct dwc_qh *qh;
> + =A0 =A0 =A0 enum dwc_transaction_type tr_type;
> + =A0 =A0 =A0 u32 gintsts =3D 0;
> +
> + =A0 =A0 =A0 hfnum =3D
> + =A0 =A0 =A0 =A0 =A0 dwc_reg_read(hcd->core_if->host_if->host_global_reg=
s,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DWC_HFNUM);
> +
> + =A0 =A0 =A0 hcd->frame_number =3D DWC_HFNUM_FRNUM_RD(hfnum);
> +
> + =A0 =A0 =A0 /* Determine whether any periodic QHs should be executed. *=
/
> + =A0 =A0 =A0 qh_entry =3D hcd->periodic_sched_inactive.next;
> + =A0 =A0 =A0 while (qh_entry !=3D &hcd->periodic_sched_inactive) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh =3D list_entry(qh_entry, struct dwc_qh, =
qh_list_entry);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh_entry =3D qh_entry->next;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* If needed, move QH to the ready list t=
o be executed next
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* (micro)frame.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (dwc_frame_num_le(qh->sched_frame, hcd->=
frame_number))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_move(&qh->qh_list_entr=
y,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &hcd->p=
eriodic_sched_ready);
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 tr_type =3D dwc_otg_hcd_select_transactions(hcd);
> + =A0 =A0 =A0 if (tr_type !=3D DWC_OTG_TRANSACTION_NONE)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_hcd_queue_transactions(hcd, tr_type=
);
> +
> + =A0 =A0 =A0 /* Clear interrupt */
> + =A0 =A0 =A0 gintsts |=3D DWC_INTMSK_STRT_OF_FRM;
> + =A0 =A0 =A0 dwc_reg_write(gintsts_reg(hcd), 0, gintsts);
> + =A0 =A0 =A0 return 1;
> +}
> +
> +/**
> + * Handles the Rx Status Queue Level Interrupt, which indicates that the=
re is at
> + * least one packet in the Rx FIFO. =A0The packets are moved from the FI=
FO to
> + * memory if the DWC_otg controller is operating in Slave mode.
> + */
> +static int dwc_otg_hcd_handle_rx_status_q_level_intr(struct dwc_hcd *hcd=
)
> +{
> + =A0 =A0 =A0 u32 grxsts;
> + =A0 =A0 =A0 struct dwc_hc *hc;
> +
> + =A0 =A0 =A0 grxsts =3D dwc_reg_read(hcd->core_if->core_global_regs, DWC=
_GRXSTSP);
> + =A0 =A0 =A0 hc =3D hcd->hc_ptr_array[grxsts & DWC_HM_RXSTS_CHAN_NUM_RD(=
grxsts)];
> +
> + =A0 =A0 =A0 /* Packet Status */
> + =A0 =A0 =A0 switch (DWC_HM_RXSTS_PKT_STS_RD(grxsts)) {
> + =A0 =A0 =A0 case DWC_GRXSTS_PKTSTS_IN:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Read the data into the host buffer. */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (DWC_HM_RXSTS_BYTE_CNT_RD(grxsts) > 0) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_read_packet(hcd->co=
re_if, hc->xfer_buff,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 DWC_HM_RXSTS_BYTE_CNT_RD(grxsts));
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Update the HC fields for=
 the next packet received. */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hc->xfer_count +=3D DWC_HM_=
RXSTS_BYTE_CNT_RD(grxsts);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hc->xfer_buff +=3D DWC_HM_R=
XSTS_BYTE_CNT_RD(grxsts);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
> + =A0 =A0 =A0 case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
> + =A0 =A0 =A0 case DWC_GRXSTS_PKTSTS_CH_HALTED:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Handled in interrupt, just ignore data *=
/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 default:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("RX_STS_Q Interrupt: Unknown status =
%d\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DWC_HM_RXSTS_PKT_STS_RD(grxs=
ts));
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 return 1;
> +}
> +
> +/**
> + * This interrupt occurs when the non-periodic Tx FIFO is half-empty. Mo=
re
> + * data packets may be written to the FIFO for OUT transfers. More reque=
sts
> + * may be written to the non-periodic request queue for IN transfers. Th=
is
> + * interrupt is enabled only in Slave mode.
> + */
> +static int dwc_otg_hcd_handle_np_tx_fifo_empty_intr(struct dwc_hcd *hcd)
> +{
> + =A0 =A0 =A0 dwc_otg_hcd_queue_transactions(hcd, DWC_OTG_TRANSACTION_NON=
_PERIODIC);
> + =A0 =A0 =A0 return 1;
> +}
> +
> +/**
> + * This interrupt occurs when the periodic Tx FIFO is half-empty. More d=
ata
> + * packets may be written to the FIFO for OUT transfers. More requests m=
ay be
> + * written to the periodic request queue for IN transfers. This interrup=
t is
> + * enabled only in Slave mode.
> + */
> +static int dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(struct dwc_hcd *h=
cd)
> +{
> + =A0 =A0 =A0 dwc_otg_hcd_queue_transactions(hcd, DWC_OTG_TRANSACTION_PER=
IODIC);
> + =A0 =A0 =A0 return 1;
> +}
> +
> +/**
> + * When the port changes to enabled it may be necessary to adjust the ph=
y clock
> + * speed.
> + */
> +static int adjusted_phy_clock_speed(struct dwc_hcd *hcd, u32 hprt0)
> +{
> + =A0 =A0 =A0 int adjusted =3D 0;
> + =A0 =A0 =A0 u32 usbcfg;
> + =A0 =A0 =A0 ulong global_regs =3D hcd->core_if->core_global_regs;
> + =A0 =A0 =A0 struct core_params *params =3D hcd->core_if->core_params;
> + =A0 =A0 =A0 ulong h_regs =3D hcd->core_if->host_if->host_global_regs;
> +
> + =A0 =A0 =A0 usbcfg =3D dwc_reg_read(global_regs, DWC_GUSBCFG);
> +
> + =A0 =A0 =A0 if (DWC_HPRT0_PRT_SPD_RD(hprt0) =3D=3D DWC_HPRT0_PRTSPD_LOW=
_SPEED ||
> + =A0 =A0 =A0 =A0 =A0 DWC_HPRT0_PRT_SPD_RD(hprt0) =3D=3D DWC_HPRT0_PRTSPD=
_FULL_SPEED) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Low power */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 u32 hcfg;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!(usbcfg & DWC_USBCFG_PHYLPWRCLKSEL)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Set PHY low power clock =
select for FS/LS devices */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 usbcfg |=3D DWC_USBCFG_PHYL=
PWRCLKSEL;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_reg_write(global_regs, =
DWC_GUSBCFG, usbcfg);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 adjusted =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 hcfg =3D dwc_reg_read(h_regs, DWC_HCFG);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (DWC_HPRT0_PRT_SPD_RD(hprt0) =3D=3D DWC_=
HPRT0_PRTSPD_LOW_SPEED &&
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 params->host_ls_low_power_phy_clk =
=3D=3D
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM=
_6MHZ) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* 6 MHZ, check for 6 MHZ c=
lock select */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (DWC_HCFG_FSLSP_CLK_RD(h=
cfg) !=3D DWC_HCFG_6_MHZ) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hcfg =3D DW=
C_HCFG_FSLSP_CLK_RW(hcfg,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DWC_HCFG_6_MHZ);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_reg_wri=
te(h_regs, DWC_HCFG, hcfg);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 adjusted =
=3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else if (DWC_HCFG_FSLSP_CLK_RD(hcfg) !=3D=
 DWC_HCFG_48_MHZ) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* 48 MHZ and clock select =
is not 48 MHZ */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hcfg =3D DWC_HCFG_FSLSP_CLK=
_RW(hcfg, DWC_HCFG_48_MHZ);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_reg_write(h_regs, DWC_H=
CFG, hcfg);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 adjusted =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 } else if (usbcfg & DWC_USBCFG_PHYLPWRCLKSEL) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 usbcfg &=3D ~((u32) DWC_USBCFG_PHYLPWRCLKSE=
L);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_reg_write(global_regs, DWC_GUSBCFG, usb=
cfg);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 adjusted =3D 1;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 if (adjusted)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 schedule_work(&hcd->usb_port_reset);
> +
> + =A0 =A0 =A0 return adjusted;
> +}
> +
> +/**
> + * Helper function to handle the port enable changed interrupt when the =
port
> + * becomes enabled. =A0Checks if we need to adjust the PHY clock speed f=
or low
> + * power and =A0adjusts it if needed.
> + */
> +static void port_enabled(struct dwc_hcd *hcd, u32 hprt0)
> +{
> + =A0 =A0 =A0 if (hcd->core_if->core_params->host_support_fs_ls_low_power=
)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!adjusted_phy_clock_speed(hcd, hprt0))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hcd->flags.b.port_reset_cha=
nge =3D 1;
> +}
> +
> +/**
> + * There are multiple conditions that can cause a port interrupt. This f=
unction
> + * determines which interrupt conditions have occurred and handles them
> + * appropriately.
> + */
> +static int dwc_otg_hcd_handle_port_intr(struct dwc_hcd *hcd)
> +{
> + =A0 =A0 =A0 int retval =3D 0;
> + =A0 =A0 =A0 u32 hprt0;
> + =A0 =A0 =A0 u32 hprt0_modify;
> +
> + =A0 =A0 =A0 hprt0 =3D dwc_reg_read(hcd->core_if->host_if->hprt0, 0);
> + =A0 =A0 =A0 hprt0_modify =3D dwc_reg_read(hcd->core_if->host_if->hprt0,=
 0);
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* Clear appropriate bits in HPRT0 to clear the interrupt=
 bit in
> + =A0 =A0 =A0 =A0* GINTSTS
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 hprt0_modify =3D DWC_HPRT0_PRT_ENA_RW(hprt0_modify, 0);
> + =A0 =A0 =A0 hprt0_modify =3D DWC_HPRT0_PRT_CONN_DET_RW(hprt0_modify, 0)=
;
> + =A0 =A0 =A0 hprt0_modify =3D DWC_HPRT0_PRT_ENA_DIS_CHG_RW(hprt0_modify,=
 0);
> + =A0 =A0 =A0 hprt0_modify =3D DWC_HPRT0_PRT_OVRCURR_CHG_RW(hprt0_modify,=
 0);
> +
> + =A0 =A0 =A0 /* Port connect detected interrupt */
> + =A0 =A0 =A0 if (DWC_HPRT0_PRT_CONN_DET_RD(hprt0)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Set the status flags and clear interrupt=
 */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 hcd->flags.b.port_connect_status_change =3D=
 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 hcd->flags.b.port_connect_status =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 hprt0_modify =3D DWC_HPRT0_PRT_CONN_DET_RW(=
hprt0_modify, 1);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* B-Device has connected, Delete the conne=
ction timer. */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 del_timer_sync(&hcd->conn_timer);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* The Hub driver asserts a reset when it=
 sees port connect
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* status change flag
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval |=3D 1;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /* Port enable changed interrupt */
> + =A0 =A0 =A0 if (DWC_HPRT0_PRT_ENA_DIS_CHG_RD(hprt0)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Set the internal flag if the port was di=
sabled */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (DWC_HPRT0_PRT_ENA_RD(hprt0))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 port_enabled(hcd, hprt0);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hcd->flags.b.port_enable_ch=
ange =3D 1;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Clear the interrupt */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 hprt0_modify =3D DWC_HPRT0_PRT_ENA_DIS_CHG_=
RW(hprt0_modify, 1);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval |=3D 1;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /* Overcurrent change interrupt */
> + =A0 =A0 =A0 if (DWC_HPRT0_PRT_OVRCURR_CHG_RD(hprt0)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 hcd->flags.b.port_over_current_change =3D 1=
;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 hprt0_modify =3D DWC_HPRT0_PRT_OVRCURR_CHG_=
RW(hprt0_modify, 1);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval |=3D 1;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /* Clear the port interrupts */
> + =A0 =A0 =A0 dwc_reg_write(hcd->core_if->host_if->hprt0, 0, hprt0_modify=
);
> + =A0 =A0 =A0 return retval;
> +}
> +
> +/**
> + * Gets the actual length of a transfer after the transfer halts. halt_s=
tatus
> + * holds the reason for the halt.
> + *
> + * For IN transfers where halt_status is DWC_OTG_HC_XFER_COMPLETE, _shor=
t_read
> + * is set to 1 upon return if less than the requested number of bytes we=
re
> + * transferred. Otherwise, _short_read is set to 0 upon return. _short_r=
ead may
> + * also be NULL on entry, in which case it remains unchanged.
> + */
> +static u32 get_actual_xfer_length(struct dwc_hc *hc, ulong regs,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct =
dwc_qtd *qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 enum dw=
c_halt_status halt_status,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int *_s=
hort_read)
> +{
> + =A0 =A0 =A0 u32 hctsiz =3D 0;
> + =A0 =A0 =A0 u32 length;
> +
> + =A0 =A0 =A0 if (_short_read)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 *_short_read =3D 0;
> +
> + =A0 =A0 =A0 hctsiz =3D dwc_reg_read(regs, DWC_HCTSIZ);
> + =A0 =A0 =A0 if (halt_status =3D=3D DWC_OTG_HC_XFER_COMPLETE) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (hc->ep_is_in) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 length =3D hc->xfer_len - D=
WC_HCTSIZ_XFER_SIZE_RD(hctsiz);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (_short_read)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *_short_rea=
d =3D
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (DW=
C_HCTSIZ_XFER_SIZE_RD(hctsiz) !=3D 0);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else if (hc->qh->do_split) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 length =3D qtd->ssplit_out_=
xfer_count;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 length =3D hc->xfer_len;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Must use the hctsiz.pktcnt field to de=
termine how much data
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* has been transferred. This field refle=
cts the number of
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* packets that have been transferred via=
 the USB. This is
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* always an integral number of packets i=
f the transfer was
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* halted before its normal completion. (=
Can't use the
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* hctsiz.xfersize field because that ref=
lects the number of
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* bytes transferred via the AHB, not the=
 USB).
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 length =3D (hc->start_pkt_count - DWC_HCTSI=
Z_PKT_CNT_RD(hctsiz)) *
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hc->max_packet;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 return length;
> +}
> +
> +/**
> + * Updates the state of the URB after a Transfer Complete interrupt on t=
he
> + * host channel. Updates the actual_length field of the URB based on the
> + * number of bytes transferred via the host channel. Sets the URB status
> + * if the data transfer is finished.
> + */
> +static int update_urb_state_xfer_comp(struct dwc_hc *hc,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 ulong regs, struct urb *urb,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 struct dwc_qtd *qtd, int *status)
> +{
> + =A0 =A0 =A0 int xfer_done =3D 0;
> + =A0 =A0 =A0 int short_read =3D 0;
> +
> + =A0 =A0 =A0 urb->actual_length +=3D get_actual_xfer_length(hc, regs, qt=
d,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DWC_OTG_HC_XFER_COMPLETE,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&short_read);
> +
> + =A0 =A0 =A0 if (short_read || urb->actual_length =3D=3D urb->transfer_b=
uffer_length) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 xfer_done =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (short_read && (urb->transfer_flags & UR=
B_SHORT_NOT_OK))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *status =3D -EREMOTEIO;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *status =3D 0;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 return xfer_done;
> +}
> +
> +/*
> + * Save the starting data toggle for the next transfer. The data toggle =
is
> + * saved in the QH for non-control transfers and it's saved in the QTD f=
or
> + * control transfers.
> + */
> +static void save_data_toggle(struct dwc_hc *hc, ulong regs, struct dwc_q=
td *qtd)
> +{
> + =A0 =A0 =A0 u32 hctsiz =3D 0;
> + =A0 =A0 =A0 hctsiz =3D dwc_reg_read(regs, DWC_HCTSIZ);
> +
> + =A0 =A0 =A0 if (hc->ep_type !=3D DWC_OTG_EP_TYPE_CONTROL) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct dwc_qh *qh =3D hc->qh;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (DWC_HCTSIZ_PKT_PID_RD(hctsiz) =3D=3D DW=
C_HCTSIZ_DATA0)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->data_toggle =3D DWC_OTG=
_HC_PID_DATA0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh->data_toggle =3D DWC_OTG=
_HC_PID_DATA1;
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (DWC_HCTSIZ_PKT_PID_RD(hctsiz) =3D=3D DW=
C_HCTSIZ_DATA0)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->data_toggle =3D DWC_OT=
G_HC_PID_DATA0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->data_toggle =3D DWC_OT=
G_HC_PID_DATA1;
> + =A0 =A0 =A0 }
> +}
> +
> +/**
> + * Frees the first QTD in the QH's list if free_qtd is 1. For non-period=
ic
> + * QHs, removes the QH from the active non-periodic schedule. If any QTD=
s are
> + * still linked to the QH, the QH is added to the end of the inactive
> + * non-periodic schedule. For periodic QHs, removes the QH from the peri=
odic
> + * schedule if no more QTDs are linked to the QH.
> + */
> +static void deactivate_qh(struct dwc_hcd *hcd, struct dwc_qh *qh, int fr=
ee_qtd)
> +{
> + =A0 =A0 =A0 int continue_split =3D 0;
> + =A0 =A0 =A0 struct dwc_qtd *qtd;
> +
> + =A0 =A0 =A0 qtd =3D list_entry(qh->qtd_list.next, struct dwc_qtd, qtd_l=
ist_entry);
> + =A0 =A0 =A0 if (qtd->complete_split)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue_split =3D 1;
> + =A0 =A0 =A0 else if (qtd->isoc_split_pos =3D=3D DWC_HCSPLIT_XACTPOS_MID=
 ||
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0qtd->isoc_split_pos =3D=3D DWC_HCSPLIT_X=
ACTPOS_END)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue_split =3D 1;
> +
> + =A0 =A0 =A0 if (free_qtd) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_hcd_qtd_remove(qtd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue_split =3D 0;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 qh->channel =3D NULL;
> + =A0 =A0 =A0 qh->qtd_in_process =3D NULL;
> + =A0 =A0 =A0 dwc_otg_hcd_qh_deactivate(hcd, qh, continue_split);
> +}
> +
> +/**
> + * Updates the state of an Isochronous URB when the transfer is stopped =
for
> + * any reason. The fields of the current entry in the frame descriptor a=
rray
> + * are set based on the transfer state and the input status. Completes t=
he
> + * Isochronous URB if all the URB frames have been completed.
> + */
> +static enum dwc_halt_status update_isoc_urb_state(struct dwc_hcd *hcd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 struct dwc_hc *hc, u32 regs,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 struct dwc_qtd *qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 enum dwc_halt_status status)
> +{
> + =A0 =A0 =A0 struct urb *urb =3D qtd->urb;
> + =A0 =A0 =A0 enum dwc_halt_status ret_val =3D status;
> + =A0 =A0 =A0 struct usb_iso_packet_descriptor *frame_desc;
> + =A0 =A0 =A0 frame_desc =3D &urb->iso_frame_desc[qtd->isoc_frame_index];
> +
> + =A0 =A0 =A0 switch (status) {
> + =A0 =A0 =A0 case DWC_OTG_HC_XFER_COMPLETE:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 frame_desc->status =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 frame_desc->actual_length =3D
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 get_actual_xfer_length(hc, regs, qt=
d, status, NULL);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case DWC_OTG_HC_XFER_FRAME_OVERRUN:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 urb->error_count++;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (hc->ep_is_in)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 frame_desc->status =3D -ENO=
SR;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 frame_desc->status =3D -ECO=
MM;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 frame_desc->actual_length =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case DWC_OTG_HC_XFER_BABBLE_ERR:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Don't need to update actual_length in th=
is case. */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 urb->error_count++;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 frame_desc->status =3D -EOVERFLOW;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case DWC_OTG_HC_XFER_XACT_ERR:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 urb->error_count++;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 frame_desc->status =3D -EPROTO;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 frame_desc->actual_length =3D
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 get_actual_xfer_length(hc, regs, qt=
d, status, NULL);
> + =A0 =A0 =A0 default:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("%s: Unhandled halt_status (%d)\n", =
__func__, status);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 BUG();
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 if (++qtd->isoc_frame_index =3D=3D urb->number_of_packets) =
{
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* urb->status is not used for isoc trans=
fers.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* The individual frame_desc statuses are=
 used instead.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_hcd_complete_urb(hcd, urb, 0);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret_val =3D DWC_OTG_HC_XFER_URB_COMPLETE;
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret_val =3D DWC_OTG_HC_XFER_COMPLETE;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 return ret_val;
> +}
> +
> +/**
> + * Releases a host channel for use by other transfers. Attempts to selec=
t and
> + * queue more transactions since at least one host channel is available.
> + */
> +static void release_channel(struct dwc_hcd *hcd, struct dwc_hc *hc,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct dwc_qtd *qtd=
,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 enum dwc_halt_statu=
s halt_status, int *must_free)
> +{
> + =A0 =A0 =A0 enum dwc_transaction_type tr_type;
> + =A0 =A0 =A0 int free_qtd;
> + =A0 =A0 =A0 int deact =3D 1;
> + =A0 =A0 =A0 struct dwc_qh *qh;
> + =A0 =A0 =A0 int retry_delay =3D 1;
> +
> + =A0 =A0 =A0 switch (halt_status) {
> + =A0 =A0 =A0 case DWC_OTG_HC_XFER_NYET:
> + =A0 =A0 =A0 case DWC_OTG_HC_XFER_NAK:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (halt_status =3D=3D DWC_OTG_HC_XFER_NYET=
)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 retry_delay =3D nyet_deferr=
al_delay;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 retry_delay =3D nak_deferra=
l_delay;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_qtd =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (deferral_on && hc->do_split) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qh =3D hc->qh;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (qh)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 deact =3D d=
wc_otg_hcd_qh_deferr(hcd, qh,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 retry_delay);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case DWC_OTG_HC_XFER_URB_COMPLETE:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_qtd =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case DWC_OTG_HC_XFER_AHB_ERR:
> + =A0 =A0 =A0 case DWC_OTG_HC_XFER_STALL:
> + =A0 =A0 =A0 case DWC_OTG_HC_XFER_BABBLE_ERR:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_qtd =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case DWC_OTG_HC_XFER_XACT_ERR:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (qtd->error_count >=3D 3) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_qtd =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_hcd_complete_urb(hc=
d, qtd->urb, -EPROTO);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_qtd =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case DWC_OTG_HC_XFER_URB_DEQUEUE:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* The QTD has already been removed and t=
he QH has been
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* deactivated. Don't want to do anything=
 except release the
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* host channel and try to queue more tra=
nsfers.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto cleanup;
> + =A0 =A0 =A0 case DWC_OTG_HC_XFER_NO_HALT_STATUS:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("%s: No halt_status, channel %d\n", =
__func__,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0hc->hc_num);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_qtd =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 default:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_qtd =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 if (free_qtd)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* must_free pre-initialized to zero */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 *must_free =3D 1;
> + =A0 =A0 =A0 if (deact)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 deactivate_qh(hcd, hc->qh, free_qtd);
> +
> +cleanup:
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* Release the host channel for use by other transfers. T=
he cleanup
> + =A0 =A0 =A0 =A0* function clears the channel interrupt enables and cond=
itions, so
> + =A0 =A0 =A0 =A0* there's no need to clear the Channel Halted interrupt =
separately.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 dwc_otg_hc_cleanup(hcd->core_if, hc);
> + =A0 =A0 =A0 list_add_tail(&hc->hc_list_entry, &hcd->free_hc_list);
> + =A0 =A0 =A0 hcd->available_host_channels++;
> + =A0 =A0 =A0 /* Try to queue more transfers now that there's a free chan=
nel. */
> + =A0 =A0 =A0 if (!erratum_usb09_patched) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tr_type =3D dwc_otg_hcd_select_transactions=
(hcd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (tr_type !=3D DWC_OTG_TRANSACTION_NONE)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_hcd_queue_transacti=
ons(hcd, tr_type);
> + =A0 =A0 =A0 }
> +}
> +
> +/**
> + * Halts a host channel. If the channel cannot be halted immediately bec=
ause
> + * the request queue is full, this function ensures that the FIFO empty
> + * interrupt for the appropriate queue is enabled so that the halt reque=
st can
> + * be queued when there is space in the request queue.
> + *
> + * This function may also be called in DMA mode. In that case, the chann=
el is
> + * simply released since the core always halts the channel automatically=
 in
> + * DMA mode.
> + */
> +static void halt_channel(struct dwc_hcd *hcd, struct dwc_hc *hc,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct dwc_qtd *qtd, enu=
m dwc_halt_status halt_status,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int *must_free)
> +{
> + =A0 =A0 =A0 if (hcd->core_if->dma_enable) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 release_channel(hcd, hc, qtd, halt_status, =
must_free);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /* Slave mode processing... */
> + =A0 =A0 =A0 dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
> + =A0 =A0 =A0 if (hc->halt_on_queue) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 u32 gintmsk =3D 0;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (hc->ep_type =3D=3D DWC_OTG_EP_TYPE_CONT=
ROL ||
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hc->ep_type =3D=3D DWC_OTG_EP_TYPE_=
BULK) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Make sure the Non-peri=
odic Tx FIFO empty interrupt
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* is enabled so that the=
 non-periodic schedule will
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* be processed.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 gintmsk |=3D DWC_INTMSK_NP_=
TXFIFO_EMPT;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_reg_modify(gintmsk_reg(=
hcd), 0, 0, gintmsk);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Move the QH from the p=
eriodic queued schedule to
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* the periodic assigned =
schedule. This allows the
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* halt to be queued when=
 the periodic schedule is
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* processed.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_move(&hc->qh->qh_list_=
entry,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &hcd->p=
eriodic_sched_assigned);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Make sure the Periodic=
 Tx FIFO Empty interrupt is
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* enabled so that the pe=
riodic schedule will be
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* processed.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 gintmsk |=3D DWC_INTMSK_P_T=
XFIFO_EMPTY;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_reg_modify(gintmsk_reg(=
hcd), 0, 0, gintmsk);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> +}
> +
> +/**
> + * Performs common cleanup for non-periodic transfers after a Transfer
> + * Complete interrupt. This function should be called after any endpoint=
 type
> + * specific handling is finished to release the host channel.
> + */
> +static void complete_non_periodic_xfer(struct dwc_hcd *hcd, struct dwc_h=
c *hc,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0ulong regs, struct dwc_qtd *qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0enum dwc_halt_status halt_status,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0int *must_free)
> +{
> + =A0 =A0 =A0 u32 hcint;
> +
> + =A0 =A0 =A0 qtd->error_count =3D 0;
> + =A0 =A0 =A0 hcint =3D dwc_reg_read(regs, DWC_HCINT);
> + =A0 =A0 =A0 if (DWC_HCINT_NYET_RESP_REC_RD(hcint)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 u32 hcint_clear =3D 0;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 hcint_clear =3D DWC_HCINT_NYET_RESP_REC_RW(=
hcint_clear, 1);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Got a NYET on the last transaction of =
the transfer. This
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* means that the endpoint should be in t=
he PING state at the
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* beginning of the next transfer.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 hc->qh->ping_state =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_reg_write(regs, DWC_HCINT, hcint_clear)=
;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* Always halt and release the host channel to make it av=
ailable for
> + =A0 =A0 =A0 =A0* more transfers. There may still be more phases for a c=
ontrol
> + =A0 =A0 =A0 =A0* transfer or more data packets for a bulk transfer at t=
his point,
> + =A0 =A0 =A0 =A0* but the host channel is still halted. A channel will b=
e reassigned
> + =A0 =A0 =A0 =A0* to the transfer when the non-periodic schedule is proc=
essed after
> + =A0 =A0 =A0 =A0* the channel is released. This allows transactions to b=
e queued
> + =A0 =A0 =A0 =A0* properly via dwc_otg_hcd_queue_transactions, which als=
o enables the
> + =A0 =A0 =A0 =A0* Tx FIFO Empty interrupt if necessary.
> + =A0 =A0 =A0 =A0*
> + =A0 =A0 =A0 =A0* IN transfers in Slave mode require an explicit disable=
 to
> + =A0 =A0 =A0 =A0* halt the channel. (In DMA mode, this call simply relea=
ses
> + =A0 =A0 =A0 =A0* the channel.)
> + =A0 =A0 =A0 =A0*
> + =A0 =A0 =A0 =A0* The channel is automatically disabled by the core for =
OUT
> + =A0 =A0 =A0 =A0* transfers in Slave mode.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 if (hc->ep_is_in)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_channel(hcd, hc, qtd, halt_status, mus=
t_free);
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 release_channel(hcd, hc, qtd, halt_status, =
must_free);
> +}
> +
> +/**
> + * Performs common cleanup for periodic transfers after a Transfer Compl=
ete
> + * interrupt. This function should be called after any endpoint type spe=
cific
> + * handling is finished to release the host channel.
> + */
> +static void complete_periodic_xfer(struct dwc_hcd *hcd, struct dwc_hc *h=
c,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ulon=
g regs, struct dwc_qtd *qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0enum=
 dwc_halt_status halt_status,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int =
*must_free)
> +{
> + =A0 =A0 =A0 u32 hctsiz =3D 0;
> +
> + =A0 =A0 =A0 hctsiz =3D dwc_reg_read(regs, DWC_HCTSIZ);
> + =A0 =A0 =A0 qtd->error_count =3D 0;
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* For OUT transfers and 0 packet count, the Core halts t=
he channel,
> + =A0 =A0 =A0 =A0* otherwise, Flush any outstanding requests from the Tx =
queue.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 if (!hc->ep_is_in || (DWC_HCTSIZ_PKT_CNT_RD(hctsiz) =3D=3D =
0))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 release_channel(hcd, hc, qtd, halt_status, =
must_free);
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_channel(hcd, hc, qtd, halt_status, mus=
t_free);
> +}
> +
> +/**
> + * Handles a host channel Transfer Complete interrupt. This handler may =
be
> + * called in either DMA mode or Slave mode.
> + */
> +static int handle_hc_xfercomp_intr(struct dwc_hcd *hcd, struct dwc_hc *h=
c,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ulon=
g regs, struct dwc_qtd *qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int =
*must_free)
> +{
> + =A0 =A0 =A0 int urb_xfer_done;
> + =A0 =A0 =A0 enum dwc_halt_status halt_status =3D DWC_OTG_HC_XFER_COMPLE=
TE;
> + =A0 =A0 =A0 struct urb *urb =3D qtd->urb;
> + =A0 =A0 =A0 int pipe_type =3D usb_pipetype(urb->pipe);
> + =A0 =A0 =A0 int status =3D -EINPROGRESS;
> + =A0 =A0 =A0 u32 hcintmsk =3D 0;
> +
> + =A0 =A0 =A0 /* Handle xfer complete on CSPLIT. */
> + =A0 =A0 =A0 if (hc->qh->do_split)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->complete_split =3D 0;
> +
> + =A0 =A0 =A0 /* Update the QTD and URB states. */
> + =A0 =A0 =A0 switch (pipe_type) {
> + =A0 =A0 =A0 case PIPE_CONTROL:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 switch (qtd->control_phase) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 case DWC_OTG_CONTROL_SETUP:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (urb->transfer_buffer_le=
ngth > 0)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->contro=
l_phase =3D DWC_OTG_CONTROL_DATA;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->contro=
l_phase =3D DWC_OTG_CONTROL_STATUS;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_status =3D DWC_OTG_HC_=
XFER_COMPLETE;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 case DWC_OTG_CONTROL_DATA:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 urb_xfer_done =3D update_ur=
b_state_xfer_comp(hc, regs,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0urb, qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&status);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (urb_xfer_done)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->contro=
l_phase =3D DWC_OTG_CONTROL_STATUS;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 save_data_t=
oggle(hc, regs, qtd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_status =3D DWC_OTG_HC_=
XFER_COMPLETE;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 case DWC_OTG_CONTROL_STATUS:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (status =3D=3D -EINPROGR=
ESS)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 status =3D =
0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_hcd_complete_urb(hc=
d, urb, status);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_status =3D DWC_OTG_HC_=
XFER_URB_COMPLETE;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 complete_non_periodic_xfer(hcd, hc, regs, q=
td,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0halt_status, must_free);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case PIPE_BULK:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 urb_xfer_done =3D update_urb_state_xfer_com=
p(hc, regs, urb, qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&status);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (urb_xfer_done) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_hcd_complete_urb(hc=
d, urb, status);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_status =3D DWC_OTG_HC_=
XFER_URB_COMPLETE;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_status =3D DWC_OTG_HC_=
XFER_COMPLETE;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 save_data_toggle(hc, regs, qtd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 complete_non_periodic_xfer(hcd, hc, regs, q=
td,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0halt_status, must_free);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case PIPE_INTERRUPT:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 update_urb_state_xfer_comp(hc, regs, urb, q=
td, &status);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Interrupt URB is done on the first tra=
nsfer complete
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* interrupt.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_hcd_complete_urb(hcd, urb, status);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 save_data_toggle(hc, regs, qtd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 complete_periodic_xfer(hcd, hc, regs, qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0DWC_OTG_HC_XFER_URB_COMPLETE, must_free);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case PIPE_ISOCHRONOUS:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (qtd->isoc_split_pos =3D=3D DWC_HCSPLIT_=
XACTPOS_ALL) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_status =3D update_isoc=
_urb_state(hcd, hc, regs, qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 DWC_OTG_HC_XFER_COMPLETE);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 complete_periodic_xfer(hcd, hc, regs, qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0halt_status, must_free);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /* disable xfercompl */
> + =A0 =A0 =A0 hcintmsk =3D DWC_HCINTMSK_TXFER_CMPL_RW(hcintmsk, 1);
> + =A0 =A0 =A0 dwc_reg_modify(regs, DWC_HCINTMSK, hcintmsk, 0);
> +
> + =A0 =A0 =A0 return 1;
> +}
> +
> +/**
> + * Handles a host channel STALL interrupt. This handler may be called in
> + * either DMA mode or Slave mode.
> + */
> +static int handle_hc_stall_intr(struct dwc_hcd *hcd, struct dwc_hc *hc,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 u32 regs, s=
truct dwc_qtd *qtd, int *must_free)
> +{
> + =A0 =A0 =A0 struct urb *urb =3D qtd->urb;
> + =A0 =A0 =A0 int pipe_type =3D usb_pipetype(urb->pipe);
> + =A0 =A0 =A0 u32 hcintmsk =3D 0;
> +
> + =A0 =A0 =A0 if (pipe_type =3D=3D PIPE_CONTROL)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_hcd_complete_urb(hcd, qtd->urb, -EP=
IPE);
> +
> + =A0 =A0 =A0 if (pipe_type =3D=3D PIPE_BULK || pipe_type =3D=3D PIPE_INT=
ERRUPT) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_hcd_complete_urb(hcd, qtd->urb, -EP=
IPE);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* USB protocol requires resetting the da=
ta toggle for bulk
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* and interrupt endpoints when a CLEAR_F=
EATURE(ENDPOINT_HALT)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* setup command is issued to the endpoin=
t. Anticipate the
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* CLEAR_FEATURE command since a STALL ha=
s occurred and reset
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* the data toggle now.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 hc->qh->data_toggle =3D 0;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_STALL, must_free=
);
> + =A0 =A0 =A0 /* disable stall */
> + =A0 =A0 =A0 hcintmsk =3D DWC_HCINTMSK_STALL_RESP_REC_RW(hcintmsk, 1);
> + =A0 =A0 =A0 dwc_reg_modify(regs, DWC_HCINTMSK, hcintmsk, 0);
> +
> + =A0 =A0 =A0 return 1;
> +}
> +
> +/**
> + * Updates the state of the URB when a transfer has been stopped due to =
an
> + * abnormal condition before the transfer completes. Modifies the
> + * actual_length field of the URB to reflect the number of bytes that ha=
ve
> + * actually been transferred via the host channel.
> + */
> +static void update_urb_state_xfer_intr(struct dwc_hc *hc,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0u32 regs, struct urb *urb,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0struct dwc_qtd *qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0enum dwc_halt_status sts)
> +{
> + =A0 =A0 =A0 u32 xfr_len =3D get_actual_xfer_length(hc, regs, qtd, sts, =
NULL);
> + =A0 =A0 =A0 urb->actual_length +=3D xfr_len;
> +}
> +
> +/**
> + * Handles a host channel NAK interrupt. This handler may be called in e=
ither
> + * DMA mode or Slave mode.
> + */
> +static int handle_hc_nak_intr(struct dwc_hcd *hcd, struct dwc_hc *hc,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 u32 regs, struc=
t dwc_qtd *qtd, int *must_free)
> +{
> + =A0 =A0 =A0 u32 hcintmsk =3D 0;
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, c=
ontrol, and
> + =A0 =A0 =A0 =A0* interrupt. =A0Re-start the SSPLIT transfer.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 if (hc->do_split) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (hc->complete_split)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->error_count =3D 0;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->complete_split =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_=
NAK, must_free);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto handle_nak_done;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 switch (usb_pipetype(qtd->urb->pipe)) {
> + =A0 =A0 =A0 case PIPE_CONTROL:
> + =A0 =A0 =A0 case PIPE_BULK:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (hcd->core_if->dma_enable && hc->ep_is_i=
n) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* NAK interrupts are ena=
bled on bulk/control IN
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* transfers in DMA mode =
for the sole purpose of
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* resetting the error co=
unt after a transaction error
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* occurs. The core will =
continue transferring data.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->error_count =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto handle_nak_done;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* NAK interrupts normally occur during O=
UT transfers in DMA
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* or Slave mode. For IN transfers, more =
requests will be
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* queued as request queue space is avail=
able.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->error_count =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!hc->qh->ping_state) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 update_urb_state_xfer_intr(=
hc, regs, qtd->urb, qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0DWC_OTG_HC_XFER_NAK);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 save_data_toggle(hc, regs, =
qtd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (qtd->urb->dev->speed =
=3D=3D USB_SPEED_HIGH)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hc->qh->pin=
g_state =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Halt the channel so the transfer can b=
e re-started from
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* the appropriate point or the PING prot=
ocol will
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* start/continue.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_=
NAK, must_free);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case PIPE_INTERRUPT:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->error_count =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_=
NAK, must_free);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case PIPE_ISOCHRONOUS:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Should never get called for isochronous =
transfers. */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 BUG();
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 }
> +
> +handle_nak_done:
> + =A0 =A0 =A0 /* disable nak */
> + =A0 =A0 =A0 hcintmsk =3D DWC_HCINTMSK_NAK_RESP_REC_RW(hcintmsk, 1);
> + =A0 =A0 =A0 dwc_reg_modify(regs, DWC_HCINTMSK, hcintmsk, 0);
> +
> + =A0 =A0 =A0 return 1;
> +}
> +
> +/**
> + * Helper function for handle_hc_ack_intr(). =A0Sets the split values fo=
r an ACK
> + * on SSPLIT for ISOC OUT.
> + */
> +static void set_isoc_out_vals(struct dwc_hc *hc, struct dwc_qtd *qtd)
> +{
> + =A0 =A0 =A0 struct usb_iso_packet_descriptor *frame_desc;
> +
> + =A0 =A0 =A0 switch (hc->xact_pos) {
> + =A0 =A0 =A0 case DWC_HCSPLIT_XACTPOS_ALL:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case DWC_HCSPLIT_XACTPOS_END:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->isoc_split_pos =3D DWC_HCSPLIT_XACTPOS=
_ALL;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->isoc_split_offset =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case DWC_HCSPLIT_XACTPOS_BEGIN:
> + =A0 =A0 =A0 case DWC_HCSPLIT_XACTPOS_MID:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* For BEGIN or MID, calculate the length=
 for the next
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* microframe to determine the correct SS=
PLIT token, either MID
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* or END.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 frame_desc =3D &qtd->urb->iso_frame_desc[qt=
d->isoc_frame_index];
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->isoc_split_offset +=3D 188;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if ((frame_desc->length - qtd->isoc_split_o=
ffset) <=3D 188)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->isoc_split_pos =3D DWC=
_HCSPLIT_XACTPOS_END;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->isoc_split_pos =3D DWC=
_HCSPLIT_XACTPOS_MID;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 }
> +}
> +
> +/**
> + * Handles a host channel ACK interrupt. This interrupt is enabled when
> + * performing the PING protocol in Slave mode, when errors occur during
> + * either Slave mode or DMA mode, and during Start Split transactions.
> + */
> +static int handle_hc_ack_intr(struct dwc_hcd *hcd, struct dwc_hc *hc,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 u32 regs, struc=
t dwc_qtd *qtd, int *must_free)
> +{
> + =A0 =A0 =A0 u32 hcintmsk =3D 0;
> +
> + =A0 =A0 =A0 if (hc->do_split) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Handle ACK on SSPLIT. ACK should not occ=
ur in CSPLIT. */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!hc->ep_is_in && hc->data_pid_start !=
=3D DWC_OTG_HC_PID_SETUP)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->ssplit_out_xfer_count =
=3D hc->xfer_len;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Don't need complete for isochronous out =
transfers. */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!(hc->ep_type =3D=3D DWC_OTG_EP_TYPE_IS=
OC && !hc->ep_is_in))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->complete_split =3D 1;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (hc->ep_type =3D=3D DWC_OTG_EP_TYPE_ISOC=
 && !hc->ep_is_in)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 set_isoc_out_vals(hc, qtd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_channel(hcd, hc, qtd, =
DWC_OTG_HC_XFER_ACK,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
must_free);
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->error_count =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (hc->qh->ping_state) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hc->qh->ping_state =3D 0;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Halt the channel so th=
e transfer can be re-started
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* from the appropriate p=
oint. This only happens in
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Slave mode. In DMA mod=
e, the ping_state is cleared
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* when the transfer is s=
tarted because the core
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* automatically executes=
 the PING, then the transfer.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_channel(hcd, hc, qtd, =
DWC_OTG_HC_XFER_ACK,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
must_free);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* If the ACK occurred when _not_ in the PING state, let =
the channel
> + =A0 =A0 =A0 =A0* continue transferring data after clearing the error co=
unt.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 /* disable ack */
> + =A0 =A0 =A0 hcintmsk =3D DWC_HCINTMSK_ACK_RESP_REC_RW(hcintmsk, 1);
> + =A0 =A0 =A0 dwc_reg_modify(regs, DWC_HCINTMSK, hcintmsk, 0);
> +
> + =A0 =A0 =A0 return 1;
> +}
> +
> +/**
> + * Handles a host channel NYET interrupt. This interrupt should only occ=
ur on
> + * Bulk and Control OUT endpoints and for complete split transactions. I=
f a
> + * NYET occurs at the same time as a Transfer Complete interrupt, it is
> + * handled in the xfercomp interrupt handler, not here. This handler may=
 be
> + * called in either DMA mode or Slave mode.
> + */
> +static int handle_hc_nyet_intr(struct dwc_hcd *hcd, struct dwc_hc *hc,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u32 regs, st=
ruct dwc_qtd *qtd, int *must_free)
> +{
> + =A0 =A0 =A0 u32 hcintmsk =3D 0;
> + =A0 =A0 =A0 u32 hcint_clear =3D 0;
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* NYET on CSPLIT
> + =A0 =A0 =A0 =A0* re-do the CSPLIT immediately on non-periodic
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 if (hc->do_split && hc->complete_split) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (hc->ep_type =3D=3D DWC_OTG_EP_TYPE_INTR=
 ||
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hc->ep_type =3D=3D DWC_OTG_EP_TYPE_=
ISOC) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int frnum =3D
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_hcd_get_fra=
me_number(dwc_otg_hcd_to_hcd
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(hcd));
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (dwc_full_frame_num(frnu=
m) !=3D
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_full_frame_num(=
hc->qh->sched_frame)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->comple=
te_split =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_channe=
l(hcd, hc, qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0DWC_OTG_HC_XFER_XACT_ERR,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0must_free);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto handle=
_nyet_done;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_=
NYET, must_free);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto handle_nyet_done;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 hc->qh->ping_state =3D 1;
> + =A0 =A0 =A0 qtd->error_count =3D 0;
> + =A0 =A0 =A0 update_urb_state_xfer_intr(hc, regs, qtd->urb, qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DWC_=
OTG_HC_XFER_NYET);
> + =A0 =A0 =A0 save_data_toggle(hc, regs, qtd);
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* Halt the channel and re-start the transfer so the PING
> + =A0 =A0 =A0 =A0* protocol will start.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET, must_free)=
;
> +
> +handle_nyet_done:
> + =A0 =A0 =A0 /* disable nyet */
> + =A0 =A0 =A0 hcintmsk =3D DWC_HCINTMSK_NYET_RESP_REC_RW(hcintmsk, 1);
> + =A0 =A0 =A0 dwc_reg_modify(regs, DWC_HCINTMSK, hcintmsk, 0);
> + =A0 =A0 =A0 /* clear nyet */
> + =A0 =A0 =A0 hcint_clear =3D DWC_HCINT_NYET_RESP_REC_RW(hcint_clear, 1);
> + =A0 =A0 =A0 dwc_reg_write(regs, DWC_HCINT, hcint_clear);
> + =A0 =A0 =A0 return 1;
> +}
> +
> +/**
> + * Handles a host channel babble interrupt. This handler may be called i=
n
> + * either DMA mode or Slave mode.
> + */
> +static int handle_hc_babble_intr(struct dwc_hcd *hcd, struct dwc_hc *hc,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u32 regs=
, struct dwc_qtd *qtd, int *must_free)
> +{
> + =A0 =A0 =A0 u32 hcintmsk =3D 0;
> +
> + =A0 =A0 =A0 if (hc->ep_type !=3D DWC_OTG_EP_TYPE_ISOC) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_hcd_complete_urb(hcd, qtd->urb, -EO=
VERFLOW);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_=
BABBLE_ERR,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0must_free);
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 enum dwc_halt_status halt_status;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_status =3D update_isoc_urb_state(hcd, =
hc, regs, qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 DWC_OTG_HC_XFER_BABBLE_ERR);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_channel(hcd, hc, qtd, halt_status, mus=
t_free);
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 /* disable bblerr */
> + =A0 =A0 =A0 hcintmsk =3D DWC_HCINTMSK_BBL_ERR_RW(hcintmsk, 1);
> + =A0 =A0 =A0 dwc_reg_modify(regs, DWC_HCINTMSK, hcintmsk, 0);
> + =A0 =A0 =A0 return 1;
> +}
> +
> +/**
> + * Handles a host channel AHB error interrupt. This handler is only call=
ed in
> + * DMA mode.
> + */
> +static int handle_hc_ahberr_intr(struct dwc_hcd *hcd, struct dwc_hc *hc,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u32 regs=
, struct dwc_qtd *qtd)
> +{
> + =A0 =A0 =A0 u32 hcchar;
> + =A0 =A0 =A0 u32 hcsplt;
> + =A0 =A0 =A0 u32 hctsiz =3D 0;
> + =A0 =A0 =A0 u32 hcdma;
> + =A0 =A0 =A0 struct urb *urb =3D qtd->urb;
> + =A0 =A0 =A0 u32 hcintmsk =3D 0;
> +
> + =A0 =A0 =A0 hcchar =3D dwc_reg_read(regs, DWC_HCCHAR);
> + =A0 =A0 =A0 hcsplt =3D dwc_reg_read(regs, DWC_HCSPLT);
> + =A0 =A0 =A0 hctsiz =3D dwc_reg_read(regs, DWC_HCTSIZ);
> + =A0 =A0 =A0 hcdma =3D dwc_reg_read(regs, DWC_HCDMA);
> +
> + =A0 =A0 =A0 pr_err("AHB ERROR, Channel %d\n", hc->hc_num);
> + =A0 =A0 =A0 pr_err(" =A0hcchar 0x%08x, hcsplt 0x%08x\n", hcchar, hcsplt=
);
> + =A0 =A0 =A0 pr_err(" =A0hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz, hcdma);
> +
> + =A0 =A0 =A0 pr_err(" =A0Device address: %d\n", usb_pipedevice(urb->pipe=
));
> + =A0 =A0 =A0 pr_err(" =A0Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe=
),
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0(usb_pipein(urb->pipe) ? "IN" : "OUT"));
> +
> + =A0 =A0 =A0 pr_err(" =A0Endpoint type: %s\n", pipetype_str(urb->pipe));
> + =A0 =A0 =A0 pr_err(" =A0Speed: %s\n", dev_speed_str(urb->dev->speed));
> + =A0 =A0 =A0 pr_err(" =A0Max packet size: %d\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0usb_maxpacket(urb->dev, urb->pipe, usb_pipeo=
ut(urb->pipe)));
> + =A0 =A0 =A0 pr_err(" =A0Data buffer length: %d\n", urb->transfer_buffer=
_length);
> + =A0 =A0 =A0 pr_err(" =A0Transfer buffer: %p, Transfer DMA: %p\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0urb->transfer_buffer, (void *)(u32) urb->tra=
nsfer_dma);
> + =A0 =A0 =A0 pr_err(" =A0Setup buffer: %p, Setup DMA: %p\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0urb->setup_packet, (void *)(u32) urb->setup_=
dma);
> + =A0 =A0 =A0 pr_err(" =A0Interval: %d\n", urb->interval);
> +
> + =A0 =A0 =A0 dwc_otg_hcd_complete_urb(hcd, urb, -EIO);
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* Force a channel halt. Don't call halt_channel because =
that won't
> + =A0 =A0 =A0 =A0* write to the HCCHARn register in DMA mode to force the=
 halt.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 dwc_otg_hc_halt(hcd->core_if, hc, DWC_OTG_HC_XFER_AHB_ERR);
> + =A0 =A0 =A0 /* disable ahberr */
> + =A0 =A0 =A0 hcintmsk =3D DWC_HCINTMSK_AHB_ERR_RW(hcintmsk, 1);
> + =A0 =A0 =A0 dwc_reg_modify(regs, DWC_HCINTMSK, hcintmsk, 0);
> +
> + =A0 =A0 =A0 return 1;
> +}
> +
> +/**
> + * Handles a host channel transaction error interrupt. This handler may =
be
> + * called in either DMA mode or Slave mode.
> + */
> +static int handle_hc_xacterr_intr(struct dwc_hcd *hcd, struct dwc_hc *hc=
,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 u32 reg=
s, struct dwc_qtd *qtd, int *must_free)
> +{
> + =A0 =A0 =A0 enum dwc_halt_status status =3D DWC_OTG_HC_XFER_XACT_ERR;
> + =A0 =A0 =A0 u32 hcintmsk =3D 0;
> +
> + =A0 =A0 =A0 switch (usb_pipetype(qtd->urb->pipe)) {
> + =A0 =A0 =A0 case PIPE_CONTROL:
> + =A0 =A0 =A0 case PIPE_BULK:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->error_count++;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!hc->qh->ping_state) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 update_urb_state_xfer_intr(=
hc, regs, qtd->urb, qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0status);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 save_data_toggle(hc, regs, =
qtd);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!hc->ep_is_in && qtd->u=
rb->dev->speed =3D=3D
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 USB_SPEED_HIGH)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hc->qh->pin=
g_state =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Halt the channel so the transfer can b=
e re-started from
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* the appropriate point or the PING prot=
ocol will start.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_channel(hcd, hc, qtd, status, must_fre=
e);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case PIPE_INTERRUPT:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->error_count++;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (hc->do_split && hc->complete_split)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->complete_split =3D 0;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_channel(hcd, hc, qtd, status, must_fre=
e);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case PIPE_ISOCHRONOUS:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 status =3D update_isoc_urb_state(hcd, hc, r=
egs, qtd, status);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_channel(hcd, hc, qtd, status, must_fre=
e);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 /* Disable xacterr */
> + =A0 =A0 =A0 hcintmsk =3D DWC_HCINTMSK_TRANS_ERR_RW(hcintmsk, 1);
> + =A0 =A0 =A0 dwc_reg_modify(regs, DWC_HCINTMSK, hcintmsk, 0);
> +
> + =A0 =A0 =A0 return 1;
> +}
> +
> +/**
> + * Handles a host channel frame overrun interrupt. This handler may be c=
alled
> + * in either DMA mode or Slave mode.
> + */
> +static int handle_hc_frmovrun_intr(struct dwc_hcd *hcd, struct dwc_hc *h=
c,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u32 =
regs, struct dwc_qtd *qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int =
*must_free)
> +{
> + =A0 =A0 =A0 enum dwc_halt_status status =3D DWC_OTG_HC_XFER_FRAME_OVERR=
UN;
> + =A0 =A0 =A0 u32 hcintmsk =3D 0;
> +
> + =A0 =A0 =A0 switch (usb_pipetype(qtd->urb->pipe)) {
> + =A0 =A0 =A0 case PIPE_CONTROL:
> + =A0 =A0 =A0 case PIPE_BULK:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case PIPE_INTERRUPT:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_channel(hcd, hc, qtd, status, must_fre=
e);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case PIPE_ISOCHRONOUS:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 status =3D update_isoc_urb_state(hcd, hc, r=
egs, qtd, status);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_channel(hcd, hc, qtd, status, must_fre=
e);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 /* Disable frmovrun */
> + =A0 =A0 =A0 hcintmsk =3D DWC_HCINTMSK_FRAME_OVERN_ERR_RW(hcintmsk, 1);
> + =A0 =A0 =A0 dwc_reg_modify(regs, DWC_HCINTMSK, hcintmsk, 0);
> +
> + =A0 =A0 =A0 return 1;
> +}
> +
> +/**
> + * Handles a host channel data toggle error interrupt. This handler may =
be
> + * called in either DMA mode or Slave mode.
> + */
> +static int handle_hc_datatglerr_intr(struct dwc_hcd *hcd, struct dwc_hc =
*hc,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
u32 regs, struct dwc_qtd *qtd)
> +{
> + =A0 =A0 =A0 u32 hcintmsk =3D 0;
> +
> + =A0 =A0 =A0 if (hc->ep_is_in)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qtd->error_count =3D 0;
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("Data Toggle Error on OUT transfer, =
channel "
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"%d\n", hc->hc_num);
> +
> + =A0 =A0 =A0 /* disable datatglerr */
> + =A0 =A0 =A0 hcintmsk =3D DWC_HCINTMSK_DATA_TOG_ERR_RW(hcintmsk, 1);
> + =A0 =A0 =A0 dwc_reg_modify(regs, DWC_HCINTMSK, hcintmsk, 0);
> +
> + =A0 =A0 =A0 return 1;
> +}
> +
> +/**
> + * Handles a host Channel Halted interrupt in DMA mode. This handler
> + * determines the reason the channel halted and proceeds accordingly.
> + */
> +static void handle_hc_chhltd_intr_dma(struct dwc_hcd *hcd, struct dwc_hc=
 *hc,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 ulong regs, struct dwc_qtd *qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 int *must_free)
> +{
> + =A0 =A0 =A0 u32 hcint;
> + =A0 =A0 =A0 u32 hcintmsk =3D 0;
> +
> + =A0 =A0 =A0 if (hc->halt_status =3D=3D DWC_OTG_HC_XFER_URB_DEQUEUE ||
> + =A0 =A0 =A0 =A0 =A0 hc->halt_status =3D=3D DWC_OTG_HC_XFER_AHB_ERR) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Just release the channel. A dequeue ca=
n happen on a
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* transfer timeout. In the case of an AH=
B Error, the channel
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* was forced to halt because there's no =
way to gracefully
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* recover.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 release_channel(hcd, hc, qtd, hc->halt_stat=
us, must_free);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /* Read the HCINTn register to determine the cause for the =
halt. */
> + =A0 =A0 =A0 hcint =3D dwc_reg_read(regs, DWC_HCINT);
> + =A0 =A0 =A0 hcintmsk =3D dwc_reg_read(regs, DWC_HCINTMSK);
> + =A0 =A0 =A0 if (DWC_HCINT_TXFER_CMPL_RD(hcint)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* This is here because of a possible har=
dware bug. =A0Spec
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* says that on SPLIT-ISOC OUT transfers =
in DMA mode that a HALT
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* interrupt w/ACK bit set should occur, =
but I only see the
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* XFERCOMP bit, even with it masked out.=
 =A0This is a workaround
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* for that behavior. =A0Should fix this =
when hardware is fixed.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (hc->ep_type =3D=3D DWC_OTG_EP_TYPE_ISOC=
 && !hc->ep_is_in)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 handle_hc_ack_intr(hcd, hc,=
 regs, qtd, must_free);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 handle_hc_xfercomp_intr(hcd, hc, regs, qtd,=
 must_free);
> + =A0 =A0 =A0 } else if (DWC_HCINT_STALL_RESP_REC_RD(hcint)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 handle_hc_stall_intr(hcd, hc, regs, qtd, mu=
st_free);
> + =A0 =A0 =A0 } else if (DWC_HCINT_TRANS_ERR_RD(hcint)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Must handle xacterr before nak or ack.=
 Could get a xacterr
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* at the same time as either of these on=
 a BULK/CONTROL OUT
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* that started with a PING. The xacterr =
takes precedence.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 handle_hc_xacterr_intr(hcd, hc, regs, qtd, =
must_free);
> + =A0 =A0 =A0 } else if (DWC_HCINT_NYET_RESP_REC_RD(hcint)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Must handle nyet before nak or ack. Co=
uld get a nyet at the
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* same time as either of those on a BULK=
/CONTROL OUT that
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* started with a PING. The nyet takes pr=
ecedence.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 handle_hc_nyet_intr(hcd, hc, regs, qtd, mus=
t_free);
> + =A0 =A0 =A0 } else if (DWC_HCINT_BBL_ERR_RD(hcint)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 handle_hc_babble_intr(hcd, hc, regs, qtd, m=
ust_free);
> + =A0 =A0 =A0 } else if (DWC_HCINT_FRAME_OVERN_ERR_RD(hcint)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 handle_hc_frmovrun_intr(hcd, hc, regs, qtd,=
 must_free);
> + =A0 =A0 =A0 } else if (DWC_HCINT_DATA_TOG_ERR_RD(hcint)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 handle_hc_datatglerr_intr(hcd, hc, regs, qt=
d);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 hc->qh->data_toggle =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_channel(hcd, hc, qtd, hc->halt_status,=
 must_free);
> + =A0 =A0 =A0 } else if (DWC_HCINT_NAK_RESP_REC_RD(hcint) &&
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0!DWC_HCINTMSK_NAK_RESP_REC_RD(hcintm=
sk)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* If nak is not masked, it's because a n=
on-split IN transfer
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* is in an error state. In that case, th=
e nak is handled by
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* the nak interrupt handler, not here. H=
andle nak here for
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* BULK/CONTROL OUT transfers, which halt=
 on a NAK to allow
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* rewinding the buffer pointer.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 handle_hc_nak_intr(hcd, hc, regs, qtd, must=
_free);
> + =A0 =A0 =A0 } else if (DWC_HCINT_ACK_RESP_REC_RD(hcint) &&
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0!DWC_HCINTMSK_ACK_RESP_REC_RD(hcintm=
sk)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* If ack is not masked, it's because a n=
on-split IN transfer
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* is in an error state. In that case, th=
e ack is handled by
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* the ack interrupt handler, not here. H=
andle ack here for
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* split transfers. Start splits halt on =
ACK.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 handle_hc_ack_intr(hcd, hc, regs, qtd, must=
_free);
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (hc->ep_type =3D=3D DWC_OTG_EP_TYPE_INTR=
 ||
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hc->ep_type =3D=3D DWC_OTG_EP_TYPE_=
ISOC) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* A periodic transfer ha=
lted with no other channel
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* interrupts set. Assume=
 it was halted by the core
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* because it could not b=
e completed in its scheduled
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* (micro)frame.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 halt_channel(hcd, hc, qtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
must_free);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("%s: Channel %d, DMA=
 Mode -- ChHltd "
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"set, but re=
ason for halting is unknown, "
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"hcint 0x%08=
x, intsts 0x%08x\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0__func__, hc=
->hc_num, hcint,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dwc_reg_read=
(gintsts_reg(hcd), 0));
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> +}
> +
> +/**
> + * Handles a host channel Channel Halted interrupt.
> + *
> + * In slave mode, this handler is called only when the driver specifical=
ly
> + * requests a halt. This occurs during handling other host channel inter=
rupts
> + * (e.g. nak, xacterr, stall, nyet, etc.).
> + *
> + * In DMA mode, this is the interrupt that occurs when the core has fini=
shed
> + * processing a transfer on a channel. Other host channel interrupts (ex=
cept
> + * ahberr) are disabled in DMA mode.
> + */
> +static int handle_hc_chhltd_intr(struct dwc_hcd *hcd, struct dwc_hc *hc,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ulong regs, struct dwc_qtd *qtd, int *must_=
free)
> +{
> + =A0 =A0 =A0 if (hcd->core_if->dma_enable)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 handle_hc_chhltd_intr_dma(hcd, hc, regs, qt=
d, must_free);
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 release_channel(hcd, hc, qtd, hc->halt_stat=
us, must_free);
> +
> + =A0 =A0 =A0 return 1;
> +}
> +
> +/* Handles interrupt for a specific Host Channel */
> +static int dwc_otg_hcd_handle_hc_n_intr(struct dwc_hcd *hcd, u32 num)
> +{
> + =A0 =A0 =A0 int must_free =3D 0;
> + =A0 =A0 =A0 int retval =3D 0;
> + =A0 =A0 =A0 u32 hcint;
> + =A0 =A0 =A0 u32 hcintmsk =3D 0;
> + =A0 =A0 =A0 struct dwc_hc *hc;
> + =A0 =A0 =A0 ulong hc_regs;
> + =A0 =A0 =A0 struct dwc_qtd *qtd;
> +
> + =A0 =A0 =A0 hc =3D hcd->hc_ptr_array[num];
> + =A0 =A0 =A0 hc_regs =3D hcd->core_if->host_if->hc_regs[num];
> + =A0 =A0 =A0 qtd =3D list_entry(hc->qh->qtd_list.next, struct dwc_qtd, q=
td_list_entry);
> +
> + =A0 =A0 =A0 hcint =3D dwc_reg_read(hc_regs, DWC_HCINT);
> + =A0 =A0 =A0 hcintmsk =3D dwc_reg_read(hc_regs, DWC_HCINTMSK);
> +
> + =A0 =A0 =A0 hcint =3D hcint & hcintmsk;
> + =A0 =A0 =A0 if (!hcd->core_if->dma_enable && DWC_HCINT_CHAN_HALTED_RD(h=
cint)
> + =A0 =A0 =A0 =A0 =A0 && hcint !=3D 0x2)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 hcint =3D DWC_HCINT_CHAN_HALTED_RW(hcint, 0=
);
> +
> + =A0 =A0 =A0 if (DWC_HCINT_TXFER_CMPL_RD(hcint)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval |=3D handle_hc_xfercomp_intr(hcd, hc=
, hc_regs,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 qtd, &must_free);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* If NYET occurred at same time as Xfer =
Complete, the NYET is
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* handled by the Xfer Complete interrupt=
 handler. Don't want
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* to call the NYET interrupt handler in =
this case.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 hcint =3D DWC_HCINT_NYET_RESP_REC_RW(hcint,=
 0);
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 if (DWC_HCINT_CHAN_HALTED_RD(hcint))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval |=3D handle_hc_chhltd_intr(hcd, hc, =
hc_regs,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 qtd, &must_free);
> + =A0 =A0 =A0 if (DWC_HCINT_AHB_ERR_RD(hcint))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval |=3D handle_hc_ahberr_intr(hcd, hc, =
hc_regs, qtd);
> + =A0 =A0 =A0 if (DWC_HCINT_STALL_RESP_REC_RD(hcint))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval |=3D handle_hc_stall_intr(hcd, hc, h=
c_regs,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0qtd, &must_free);
> + =A0 =A0 =A0 if (DWC_HCINT_NAK_RESP_REC_RD(hcint))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval |=3D handle_hc_nak_intr(hcd, hc, hc_=
regs, qtd, &must_free);
> + =A0 =A0 =A0 if (DWC_HCINT_ACK_RESP_REC_RD(hcint))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval |=3D handle_hc_ack_intr(hcd, hc, hc_=
regs, qtd, &must_free);
> + =A0 =A0 =A0 if (DWC_HCINT_NYET_RESP_REC_RD(hcint))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval |=3D handle_hc_nyet_intr(hcd, hc, hc=
_regs,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 qtd, &must_free);
> + =A0 =A0 =A0 if (DWC_HCINT_TRANS_ERR_RD(hcint))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval |=3D handle_hc_xacterr_intr(hcd, hc,=
 hc_regs,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0qtd, &must_free);
> + =A0 =A0 =A0 if (DWC_HCINT_BBL_ERR_RD(hcint))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval |=3D handle_hc_babble_intr(hcd, hc, =
hc_regs,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 qtd, &must_free);
> + =A0 =A0 =A0 if (DWC_HCINT_FRAME_OVERN_ERR_RD(hcint))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval |=3D handle_hc_frmovrun_intr(hcd, hc=
, hc_regs,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 qtd, &must_free);
> + =A0 =A0 =A0 if (DWC_HCINT_DATA_TOG_ERR_RD(hcint))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval |=3D handle_hc_datatglerr_intr(hcd, =
hc, hc_regs, qtd);
> +
> + =A0 =A0 =A0 if (must_free)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Free the qtd here now that we are done u=
sing it. */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dwc_otg_hcd_qtd_free(qtd);
> + =A0 =A0 =A0 return retval;
> +}
> +
> +/**
> + * This function returns the Host All Channel Interrupt register
> + */
> +static inline u32 dwc_otg_read_host_all_channels_intr(struct core_if
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *core_if)
> +{
> + =A0 =A0 =A0 return dwc_reg_read(core_if->host_if->host_global_regs, DWC=
_HAINT);
> +}
> +
> +/**
> + * This interrupt indicates that one or more host channels has a pending
> + * interrupt. There are multiple conditions that can cause each host cha=
nnel
> + * interrupt. This function determines which conditions have occurred fo=
r each
> + * host channel interrupt and handles them appropriately.
> + */
> +static int dwc_otg_hcd_handle_hc_intr(struct dwc_hcd *hcd)
> +{
> + =A0 =A0 =A0 u32 i;
> + =A0 =A0 =A0 int retval =3D 0;
> + =A0 =A0 =A0 u32 haint;
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* Clear appropriate bits in HCINTn to clear the interrup=
t bit in
> + =A0 =A0 =A0 =A0* =A0GINTSTS
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 haint =3D dwc_otg_read_host_all_channels_intr(hcd->core_if)=
;
> + =A0 =A0 =A0 for (i =3D 0; i < hcd->core_if->core_params->host_channels;=
 i++)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (DWC_HAINT_RD(haint) & (1 << i))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval |=3D dwc_otg_hcd_han=
dle_hc_n_intr(hcd, i);
> +
> + =A0 =A0 =A0 return retval;
> +}
> +
> +/* This function handles interrupts for the HCD.*/
> +int dwc_otg_hcd_handle_intr(struct dwc_hcd *hcd)
> +{
> + =A0 =A0 =A0 int ret =3D 0;
> + =A0 =A0 =A0 struct core_if *core_if =3D hcd->core_if;
> + =A0 =A0 =A0 u32 gintsts;
> +
> + =A0 =A0 =A0 /* Check if HOST Mode */
> + =A0 =A0 =A0 if (dwc_otg_is_host_mode(core_if)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 spin_lock(&hcd->lock);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 gintsts =3D dwc_otg_read_core_intr(core_if)=
;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!gintsts) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 spin_unlock(&hcd->lock);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return IRQ_NONE;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (gintsts & DWC_INTMSK_STRT_OF_FRM)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret |=3D dwc_otg_hcd_handle=
_sof_intr(hcd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (gintsts & DWC_INTMSK_RXFIFO_NOT_EMPT)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret |=3D dwc_otg_hcd_handle=
_rx_status_q_level_intr(hcd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (gintsts & DWC_INTMSK_NP_TXFIFO_EMPT)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret |=3D dwc_otg_hcd_handle=
_np_tx_fifo_empty_intr(hcd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (gintsts & DWC_INTMSK_HST_PORT)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret |=3D dwc_otg_hcd_handle=
_port_intr(hcd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (gintsts & DWC_INTMSK_HST_CHAN)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret |=3D dwc_otg_hcd_handle=
_hc_intr(hcd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (gintsts & DWC_INTMSK_P_TXFIFO_EMPTY)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret |=3D dwc_otg_hcd_handle=
_perio_tx_fifo_empty_intr(hcd);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 spin_unlock(&hcd->lock);
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 return ret;
> +}
> --
> 1.6.1.rc3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at =A0http://vger.kernel.org/majordomo-info.html
>

Reviewed-by: Pratyush Anand <pratyush.anand@st.com>

^ permalink raw reply

* Re: [PATCH v15 04/10] USB/ppc4xx: Add Synopsys DWC OTG HCD function
From: Pratyush Anand @ 2011-10-20  9:13 UTC (permalink / raw)
  To: tmarri; +Cc: Mark Miesfeld, greg, linux-usb, linuxppc-dev, Fushen Chen
In-Reply-To: <1318630133-14264-1-git-send-email-tmarri@apm.com>

On Sat, Oct 15, 2011 at 3:38 AM,  <tmarri@apm.com> wrote:
> From: Tirumala Marri <tmarri@apm.com>
>

[...]

Everything fine in this patch, except the defines of TX
regs(DWC_RX_FIFO_DEPTH_WR) has been
kept with RX.

Regards
Pratyush

^ permalink raw reply

* Re: [PATCH v14 03/10] USB/ppc4xx: Add Synopsys DWC OTG Core Interface Layer (CIL)
From: Pratyush Anand @ 2011-10-20  9:12 UTC (permalink / raw)
  To: tmarri; +Cc: Mark Miesfeld, greg, linux-usb, linuxppc-dev, Fushen Chen
In-Reply-To: <1317954637-11802-1-git-send-email-tmarri@apm.com>

On Fri, Oct 7, 2011 at 8:00 AM,  <tmarri@apm.com> wrote:
> From: Tirumala Marri <tmarri@apm.com>
>

[...]

> + * Do core a soft reset of the core.  Be careful with this because it
> + * resets all the internal state machines of the core.
> + */
> +static void dwc_otg_core_reset(struct core_if *core_if)
> +{
> +       ulong global_regs = core_if->core_global_regs;
> +       u32 greset = 0;
> +       int count = 0;
> +
> +       /* Wait for AHB master IDLE state. */
> +       do {
> +               udelay(10);
> +               greset = dwc_reg_read(global_regs, DWC_GRSTCTL);
> +               if (++count > 100000) {
> +                       pr_warning("%s() HANG! AHB Idle GRSTCTL=%0x\n",
> +                                  __func__, greset);
> +                       return;
> +               }
> +       } while (greset & DWC_RSTCTL_AHB_IDLE);

As per sepcs:
Bit 31:  AHB Master Idle (AHBIdle): Indicates that the AHB Master State
Machine is in the IDLE condition.
So when this bit is 1 , AHB would be idle. So, what do you want here?
If AHB is idle, control wil return from above loop rather going ahead to execute
this function.

> +
> +       /* Core Soft Reset */
> +       count = 0;
> +       greset |= DWC_RSTCTL_SFT_RST;

[...]

> +       /* Rx FIFO */
> +       dwc_reg_write(regs, DWC_GRXFSIZ, params->dev_rx_fifo_size);
> +
> +       /* Set Periodic and Non-periodic Tx FIFO Mask bits to all 0 */
> +       core_if->p_tx_msk = 0;
> +       core_if->tx_msk = 0;
> +
> +       if (core_if->en_multiple_tx_fifo == 0) {
> +               /* Non-periodic Tx FIFO */
> +               nptxsize = DWC_RX_FIFO_DEPTH_WR(nptxsize,
> +                                               params->
> +                                               dev_nperio_tx_fifo_size);

So, if you will follow the commnet of patch 01 then , here two you will have to
rename as TX_FIFO.
Also, at all other occurances.

> +               nptxsize =
> +                   DWC_RX_FIFO_START_ADDR_WR(nptxsize,
> +                                             params->dev_rx_fifo_size);
> +               dwc_reg_write(regs, DWC_GNPTXFSIZ, nptxsize);
> +
> +               ptxsize = DWC_RX_FIFO_START_ADDR_WR(ptxsize,
> +                                                   (DWC_RX_FIFO_START_ADDR_RD
> +                                                    (nptxsize) +
> +                                                    DWC_RX_FIFO_DEPTH_RD
> +                                                    (nptxsize)));
> +               for (i = 0;
> +                    i < DWC_HWCFG4_NUM_DEV_PERIO_IN_EP_RD(core_if->hwcfg4);
> +                    i++) {


Reading hwcfg4 will give you maximum nuber of fifos provided by hardware.
But, a particular application (platform) may not need all those fifo. Since, you
have a vriable fifo_num in your param list, so why not use that?

> +                       ptxsize =
> +                           DWC_RX_FIFO_DEPTH_WR(ptxsize,
> +                                                params->
> +                                                dev_perio_tx_fifo_size[i]);
> +                       dwc_reg_write(regs, DWC_DPTX_FSIZ_DIPTXF(i), ptxsize);
> +                       ptxsize = DWC_RX_FIFO_START_ADDR_WR(ptxsize,
> +                                                  (DWC_RX_FIFO_START_ADDR_RD
> +                                                   (ptxsize) +
> +                                                   DWC_RX_FIFO_DEPTH_RD
> +                                                   (ptxsize)));
> +               }
> +       } else {
> +               nptxsize = DWC_RX_FIFO_DEPTH_WR(nptxsize,
> +                                               params->
> +                                               dev_nperio_tx_fifo_size);
> +               nptxsize =
> +                   DWC_RX_FIFO_START_ADDR_WR(nptxsize,
> +                                             params->dev_rx_fifo_size);
> +               dwc_reg_write(regs, DWC_GNPTXFSIZ, nptxsize);
> +
> +               txsize = DWC_RX_FIFO_START_ADDR_WR(txsize,
> +                                                  (DWC_RX_FIFO_START_ADDR_RD
> +                                                   (nptxsize) +
> +                                                   DWC_RX_FIFO_DEPTH_RD
> +                                                   (nptxsize)));
> +               for (i = 1;
> +                    i < DWC_HWCFG4_NUM_DEV_PERIO_IN_EP_RD(core_if->hwcfg4);
> +                    i++) {

Same as above

> +                       txsize =
> +                           DWC_RX_FIFO_DEPTH_WR(txsize,
> +                                                params->dev_tx_fifo_size[i]);
> +                       dwc_reg_write(regs, DWC_DPTX_FSIZ_DIPTXF(i - 1), txsize);
> +                       txsize = DWC_RX_FIFO_START_ADDR_WR(txsize,
> +                                                  (DWC_RX_FIFO_START_ADDR_RD
> +                                                   (txsize) +
> +                                                   DWC_RX_FIFO_DEPTH_RD
> +                                                   (txsize)));
> +               }
> +       }
> +}
> +

Regards
Pratyush

^ permalink raw reply

* Re: [PATCH v15 01/10] USB/ppc4xx: Add Synopsys DesignWare HS USB OTG Register definitions
From: Pratyush Anand @ 2011-10-20  8:42 UTC (permalink / raw)
  To: tmarri; +Cc: Mark Miesfeld, greg, linux-usb, linuxppc-dev, Fushen Chen
In-Reply-To: <1318630119-14165-1-git-send-email-tmarri@apm.com>

On Sat, Oct 15, 2011 at 3:38 AM,  <tmarri@apm.com> wrote:
> From: Tirumala Marri <tmarri@apm.com>
>
[...]

> +/*
> + * These Macros represents the bit fields in the FIFO Size Registers (HPTXFSIZ,
> + * GNPTXFSIZ, DPTXFSIZn). Read the register into the u32 element then
> + * read out the bits using the bit elements.
> + */
> +#define DWC_RX_FIFO_DEPTH_RD(reg)      (((reg) & ((u32)0xffff << 16)) >> 16)
> +#define DWC_RX_FIFO_DEPTH_WR(reg, x)   \
> +       (((reg) & (~((u32)0xffff << 16))) | ((x) << 16))
> +#define DWC_RX_FIFO_START_ADDR_RD(reg)         ((reg) & 0xffff)
> +#define DWC_RX_FIFO_START_ADDR_WR(reg, x)      \
> +       (((reg) & (~((u32)0xffff))) | (x))
> +

These are GNPTX  and DPTX registers.
So name should be DWC_TX_FIFO_DEPTH_RD rather than DWC_RX_FIFO_DEPTH_RD.
Same for other defines.


> +/*
> + * These Macros represents the bit fields in the Non-Periodic Tx FIFO/Queue
> +

[...]

> +#define MAX_PERIO_FIFOS                        15      /* Max periodic FIFOs */
> +#define MAX_TX_FIFOS                   15      /* Max non-periodic FIFOs */
> +
> +/* Maximum number of Endpoints/HostChannels */
> +#define MAX_EPS_CHANNELS 12    /* This come from device tree or defconfig */

There could be some platform even with 16 channels (as specs permits it.)
So, please make it 16.

^ permalink raw reply

* [RFC][PATCH 2/2] powerpc/85xx: Introduce a P1020 SoC device tree
From: Kumar Gala @ 2011-10-20  7:24 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: devicetree-discuss
In-Reply-To: <1319095467-6229-1-git-send-email-galak@kernel.crashing.org>

Create a P1020 SoC dts stub that can be included by a board that
utilizes the P1020 SoC.  The board can amend any board specific
configuration or paramaters (like locaation of CCSRBAR, PCIe
controllers, I2C components, ethernet PHY information, etc.)

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/boot/dts/p1020soc.dtsi |  262 +++++++++++++++++++++++++++++++++++
 1 files changed, 262 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/boot/dts/p1020soc.dtsi

diff --git a/arch/powerpc/boot/dts/p1020soc.dtsi b/arch/powerpc/boot/dts/p1020soc.dtsi
new file mode 100644
index 0000000..0abc015
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1020soc.dtsi
@@ -0,0 +1,262 @@
+&lbc {
+	#address-cells = <2>;
+	#size-cells = <1>;
+	compatible = "fsl,p1020-elbc", "fsl,elbc", "simple-bus";
+	interrupts = <19 2 0 0>;
+};
+
+&pci0 {
+	compatible = "fsl,mpc8548-pcie";
+	device_type = "pci";
+	#size-cells = <2>;
+	#address-cells = <3>;
+	bus-range = <0 255>;
+	clock-frequency = <33333333>;
+	interrupts = <16 2 0 0>;
+
+	pcie@0 {
+		reg = <0 0 0 0 0>;
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		device_type = "pci";
+		interrupts = <16 2 0 0>;
+		interrupt-map-mask = <0xf800 0 0 7>;
+		interrupt-map = <
+			/* IDSEL 0x0 */
+			0000 0x0 0x0 0x1 &mpic 0x4 0x1
+			0000 0x0 0x0 0x2 &mpic 0x5 0x1
+			0000 0x0 0x0 0x3 &mpic 0x6 0x1
+			0000 0x0 0x0 0x4 &mpic 0x7 0x1
+			>;
+	};
+
+};
+
+&pci1 {
+	compatible = "fsl,mpc8548-pcie";
+	device_type = "pci";
+	#size-cells = <2>;
+	#address-cells = <3>;
+	bus-range = <0 255>;
+	clock-frequency = <33333333>;
+	interrupts = <16 2 0 0>;
+
+	pcie@0 {
+		reg = <0 0 0 0 0>;
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		device_type = "pci";
+		interrupts = <16 2 0 0>;
+		interrupt-map-mask = <0xf800 0 0 7>;
+
+		interrupt-map = <
+			/* IDSEL 0x0 */
+			0000 0x0 0x0 0x1 &mpic 0x0 0x1
+			0000 0x0 0x0 0x2 &mpic 0x1 0x1
+			0000 0x0 0x0 0x3 &mpic 0x2 0x1
+			0000 0x0 0x0 0x4 &mpic 0x3 0x1
+			>;
+	};
+};
+
+
+
+&soc {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	device_type = "soc";
+	compatible = "fsl,p1020-immr", "simple-bus";
+	bus-frequency = <0>;		// Filled out by uboot.
+
+	ecm-law@0 {
+		compatible = "fsl,ecm-law";
+		reg = <0x0 0x1000>;
+		fsl,num-laws = <12>;
+	};
+
+	ecm@1000 {
+		compatible = "fsl,p1020-ecm", "fsl,ecm";
+		reg = <0x1000 0x1000>;
+		interrupts = <16 2 0 0>;
+	};
+
+	memory-controller@2000 {
+		compatible = "fsl,p1020-memory-controller";
+		reg = <0x2000 0x1000>;
+		interrupts = <16 2 0 0>;
+	};
+
+	i2c0: i2c@3000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cell-index = <0>;
+		compatible = "fsl-i2c";
+		reg = <0x3000 0x100>;
+		interrupts = <43 2 0 0>;
+		dfsrr;
+	};
+
+	i2c1: i2c@3100 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cell-index = <1>;
+		compatible = "fsl-i2c";
+		reg = <0x3100 0x100>;
+		interrupts = <43 2 0 0>;
+		dfsrr;
+	};
+
+	serial0: serial@4500 {
+	};
+
+	serial1: serial@4600 {
+	};
+
+	spi@7000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "fsl,p1020-espi", "fsl,mpc8536-espi";
+		reg = <0x7000 0x1000>;
+		interrupts = <59 0x2 0 0>;
+		fsl,espi-num-chipselects = <4>;
+	};
+
+	gpio: gpio-controller@f000 {
+		#gpio-cells = <2>;
+		compatible = "fsl,mpc8572-gpio";
+		reg = <0xf000 0x100>;
+		interrupts = <47 0x2 0 0>;
+		gpio-controller;
+	};
+
+	L2: l2-cache-controller@20000 {
+		compatible = "fsl,p1020-l2-cache-controller";
+		reg = <0x20000 0x1000>;
+		cache-line-size = <32>;	// 32 bytes
+		cache-size = <0x40000>; // L2,256K
+		interrupts = <16 2 0 0>;
+	};
+
+	dma0: dma@21300 {
+	};
+
+	mdio0: mdio@24000 {
+	};
+
+	mdio1: mdio@25000 {
+	};
+
+	mdio2: mdio@26000 {
+	};
+
+	enet0: ethernet@b0000 {
+	};
+
+	enet1: ethernet@b1000 {
+	};
+
+	enet2: ethernet@b2000 {
+	};
+
+	usb@22000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "fsl-usb2-dr";
+		reg = <0x22000 0x1000>;
+		interrupts = <28 0x2 0 0>;
+	};
+
+	/* USB2 is shared with localbus, so it must be disabled
+	   by default. We can't put 'status = "disabled";' here
+	   since U-Boot doesn't clear the status property when
+	   it enables USB2. OTOH, U-Boot does create a new node
+	   when there isn't any. So, just comment it out.
+	usb@23000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "fsl-usb2-dr";
+		reg = <0x23000 0x1000>;
+		interrupts = <46 0x2 0 0>;
+		phy_type = "ulpi";
+	};
+	*/
+
+	sdhci@2e000 {
+		compatible = "fsl,p1020-esdhc", "fsl,esdhc";
+		reg = <0x2e000 0x1000>;
+		interrupts = <72 0x2 0 0>;
+		/* Filled in by U-Boot */
+		clock-frequency = <0>;
+	};
+
+	crypto@30000 {
+		compatible = "fsl,sec3.3", "fsl,sec3.1", "fsl,sec3.0",
+			     "fsl,sec2.4", "fsl,sec2.2", "fsl,sec2.1",
+			     "fsl,sec2.0";
+		reg = <0x30000 0x10000>;
+		interrupts = <45 2 0 0 58 2 0 0>;
+		fsl,num-channels = <4>;
+		fsl,channel-fifo-len = <24>;
+		fsl,exec-units-mask = <0x97c>;
+		fsl,descriptor-types-mask = <0x3a30abf>;
+	};
+
+	mpic: pic@40000 {
+		interrupt-controller;
+		#address-cells = <0>;
+		#interrupt-cells = <4>;
+		reg = <0x40000 0x40000>;
+		compatible = "chrp,open-pic";
+		device_type = "open-pic";
+	};
+
+	timer@41100 {
+		compatible = "fsl,mpic-global-timer";
+		reg = <0x41100 0x100 0x41300 4>;
+		interrupts = <0 0 3 0
+			      1 0 3 0
+			      2 0 3 0
+			      3 0 3 0>;
+	};
+
+	timer@42100 {
+		compatible = "fsl,mpic-global-timer";
+		reg = <0x42100 0x100 0x42300 4>;
+		interrupts = <4 0 3 0
+			      5 0 3 0
+			      6 0 3 0
+			      7 0 3 0>;
+	};
+
+	msi@41600 {
+		compatible = "fsl,p1020-msi", "fsl,mpic-msi";
+		reg = <0x41600 0x80>;
+		msi-available-ranges = <0 0x100>;
+		interrupts = <
+			0xe0 0 0 0
+			0xe1 0 0 0
+			0xe2 0 0 0
+			0xe3 0 0 0
+			0xe4 0 0 0
+			0xe5 0 0 0
+			0xe6 0 0 0
+			0xe7 0 0 0>;
+	};
+
+	global-utilities@e0000 {	//global utilities block
+		compatible = "fsl,p1020-guts","fsl,p2020-guts";
+		reg = <0xe0000 0x1000>;
+		fsl,has-rstcr;
+	};
+};
+
+/include/ "fsl/pq3-dma-0.dtsi"
+/include/ "fsl/pq3-duart-0.dtsi"
+/include/ "fsl/pq3-duart-1.dtsi"
+/include/ "fsl/pq3-etsec2-0.dtsi"
+/include/ "fsl/pq3-etsec2-1.dtsi"
+/include/ "fsl/pq3-etsec2-2.dtsi"
+/include/ "fsl/pq3-i2c-0.dtsi"
+/include/ "fsl/pq3-i2c-1.dtsi"
-- 
1.7.3.4

^ permalink raw reply related

* [RFC][PATCH 1/2] powerpc/85xx: create dts components to build up an SoC
From: Kumar Gala @ 2011-10-20  7:24 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: devicetree-discuss

Introduce some common components that we can utilize to build up the
various PQ3/85xx device trees.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/boot/dts/fsl/pq3-dma-0.dtsi    |   32 +++++++++++++++++++++++++++
 arch/powerpc/boot/dts/fsl/pq3-duart-0.dtsi  |    8 ++++++
 arch/powerpc/boot/dts/fsl/pq3-duart-1.dtsi  |    8 ++++++
 arch/powerpc/boot/dts/fsl/pq3-etsec2-0.dtsi |   32 +++++++++++++++++++++++++++
 arch/powerpc/boot/dts/fsl/pq3-etsec2-1.dtsi |   32 +++++++++++++++++++++++++++
 arch/powerpc/boot/dts/fsl/pq3-etsec2-2.dtsi |   32 +++++++++++++++++++++++++++
 arch/powerpc/boot/dts/fsl/pq3-i2c-0.dtsi    |    9 +++++++
 arch/powerpc/boot/dts/fsl/pq3-i2c-1.dtsi    |    9 +++++++
 8 files changed, 162 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/boot/dts/fsl/pq3-dma-0.dtsi
 create mode 100644 arch/powerpc/boot/dts/fsl/pq3-duart-0.dtsi
 create mode 100644 arch/powerpc/boot/dts/fsl/pq3-duart-1.dtsi
 create mode 100644 arch/powerpc/boot/dts/fsl/pq3-etsec2-0.dtsi
 create mode 100644 arch/powerpc/boot/dts/fsl/pq3-etsec2-1.dtsi
 create mode 100644 arch/powerpc/boot/dts/fsl/pq3-etsec2-2.dtsi
 create mode 100644 arch/powerpc/boot/dts/fsl/pq3-i2c-0.dtsi
 create mode 100644 arch/powerpc/boot/dts/fsl/pq3-i2c-1.dtsi

diff --git a/arch/powerpc/boot/dts/fsl/pq3-dma-0.dtsi b/arch/powerpc/boot/dts/fsl/pq3-dma-0.dtsi
new file mode 100644
index 0000000..60aa877
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/pq3-dma-0.dtsi
@@ -0,0 +1,32 @@
+&dma0 {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	compatible = "fsl,eloplus-dma";
+	reg = <0x21300 0x4>;
+	ranges = <0x0 0x21100 0x200>;
+	cell-index = <0>;
+	dma-channel@0 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x0 0x80>;
+		cell-index = <0>;
+		interrupts = <20 2 0 0>;
+	};
+	dma-channel@80 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x80 0x80>;
+		cell-index = <1>;
+		interrupts = <21 2 0 0>;
+	};
+	dma-channel@100 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x100 0x80>;
+		cell-index = <2>;
+		interrupts = <22 2 0 0>;
+	};
+	dma-channel@180 {
+		compatible = "fsl,eloplus-dma-channel";
+		reg = <0x180 0x80>;
+		cell-index = <3>;
+		interrupts = <23 2 0 0>;
+	};
+};
diff --git a/arch/powerpc/boot/dts/fsl/pq3-duart-0.dtsi b/arch/powerpc/boot/dts/fsl/pq3-duart-0.dtsi
new file mode 100644
index 0000000..bac1f0d
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/pq3-duart-0.dtsi
@@ -0,0 +1,8 @@
+&serial0 {
+	cell-index = <0>;
+	device_type = "serial";
+	compatible = "ns16550";
+	reg = <0x4500 0x100>;
+	clock-frequency = <0>;
+	interrupts = <42 2 0 0>;
+};
diff --git a/arch/powerpc/boot/dts/fsl/pq3-duart-1.dtsi b/arch/powerpc/boot/dts/fsl/pq3-duart-1.dtsi
new file mode 100644
index 0000000..97bbacb
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/pq3-duart-1.dtsi
@@ -0,0 +1,8 @@
+&serial1 {
+	cell-index = <1>;
+	device_type = "serial";
+	compatible = "ns16550";
+	reg = <0x4600 0x100>;
+	clock-frequency = <0>;
+	interrupts = <42 2 0 0>;
+};
diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec2-0.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec2-0.dtsi
new file mode 100644
index 0000000..73fff36
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/pq3-etsec2-0.dtsi
@@ -0,0 +1,32 @@
+&mdio0 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	compatible = "fsl,etsec2-mdio";
+	reg = <0x24000 0x1000 0xb0030 0x4>;
+};
+
+&enet0 {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	device_type = "network";
+	model = "eTSEC";
+	compatible = "fsl,etsec2";
+	fsl,num_rx_queues = <0x8>;
+	fsl,num_tx_queues = <0x8>;
+	fsl,magic-packet;
+	local-mac-address = [ 00 00 00 00 00 00 ];
+
+	queue-group@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xb0000 0x1000>;
+		interrupts = <29 2 0 0 30 2 0 0 34 2 0 0>;
+	};
+
+	queue-group@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xb4000 0x1000>;
+		interrupts = <17 2 0 0 18 2 0 0 24 2 0 0>;
+	};
+};
diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec2-1.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec2-1.dtsi
new file mode 100644
index 0000000..7ec73c4
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/pq3-etsec2-1.dtsi
@@ -0,0 +1,32 @@
+&mdio1 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	compatible = "fsl,etsec2-tbi";
+	reg = <0x25000 0x1000 0xb1030 0x4>;
+};
+
+&enet1 {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	device_type = "network";
+	model = "eTSEC";
+	compatible = "fsl,etsec2";
+	fsl,num_rx_queues = <0x8>;
+	fsl,num_tx_queues = <0x8>;
+	fsl,magic-packet;
+	local-mac-address = [ 00 00 00 00 00 00 ];
+
+	queue-group@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xb1000 0x1000>;
+		interrupts = <35 2 0 0 36 2 0 0 40 2 0 0>;
+	};
+
+	queue-group@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xb5000 0x1000>;
+		interrupts = <51 2 0 0 52 2 0 0 67 2 0 0>;
+	};
+};
diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec2-2.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec2-2.dtsi
new file mode 100644
index 0000000..50a078a
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/pq3-etsec2-2.dtsi
@@ -0,0 +1,32 @@
+&mdio2 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	compatible = "fsl,etsec2-tbi";
+	reg = <0x26000 0x1000 0xb1030 0x4>;
+};
+
+&enet2 {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	device_type = "network";
+	model = "eTSEC";
+	compatible = "fsl,etsec2";
+	fsl,num_rx_queues = <0x8>;
+	fsl,num_tx_queues = <0x8>;
+	fsl,magic-packet;
+	local-mac-address = [ 00 00 00 00 00 00 ];
+
+	queue-group@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xb2000 0x1000>;
+		interrupts = <31 2 0 0 32 2 0 0 33 2 0 0>;
+	};
+
+	queue-group@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xb6000 0x1000>;
+		interrupts = <25 2 0 0 26 2 0 0 27 2 0 0>;
+	};
+};
diff --git a/arch/powerpc/boot/dts/fsl/pq3-i2c-0.dtsi b/arch/powerpc/boot/dts/fsl/pq3-i2c-0.dtsi
new file mode 100644
index 0000000..ef75cca
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/pq3-i2c-0.dtsi
@@ -0,0 +1,9 @@
+&i2c0 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	cell-index = <0>;
+	compatible = "fsl-i2c";
+	reg = <0x3000 0x100>;
+	interrupts = <43 2 0 0>;
+	dfsrr;
+};
diff --git a/arch/powerpc/boot/dts/fsl/pq3-i2c-1.dtsi b/arch/powerpc/boot/dts/fsl/pq3-i2c-1.dtsi
new file mode 100644
index 0000000..e24043a
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/pq3-i2c-1.dtsi
@@ -0,0 +1,9 @@
+&i2c1 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	cell-index = <1>;
+	compatible = "fsl-i2c";
+	reg = <0x3100 0x100>;
+	interrupts = <43 2 0 0>;
+	dfsrr;
+};
-- 
1.7.3.4

^ permalink raw reply related

* RE: [PATCH] powerpc/85xx: Setup secondary cores PIR with hard SMP id
From: Bhushan Bharat-R65777 @ 2011-10-20  5:14 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <C79C8827-F6FE-42E0-8FAF-E62A8FFD6A1F@kernel.crashing.org>



> -----Original Message-----
> From: Kumar Gala [mailto:galak@kernel.crashing.org]
> Sent: Thursday, October 20, 2011 9:32 AM
> To: Bhushan Bharat-R65777
> Cc: linuxppc-dev@ozlabs.org
> Subject: Re: [PATCH] powerpc/85xx: Setup secondary cores PIR with hard
> SMP id
>=20
>=20
> On Oct 19, 2011, at 10:53 PM, Bhushan Bharat-R65777 wrote:
>=20
> >
> >
> >> -----Original Message-----
> >> From:
> >> linuxppc-dev-bounces+bharat.bhushan=3Dfreescale.com@lists.ozlabs.org
> >> [mailto:linuxppc-dev-
> >> bounces+bharat.bhushan=3Dfreescale.com@lists.ozlabs.org] On Behalf Of
> >> bounces+Kumar
> >> Gala
> >> Sent: Friday, October 14, 2011 1:23 PM
> >> To: linuxppc-dev@ozlabs.org
> >> Subject: [PATCH] powerpc/85xx: Setup secondary cores PIR with hard
> >> SMP id
> >>
> >> Normally logical and hard cpu ID are the same, however in same cases
> >> like on the P3060 they may differ.  Where the logical is 0..5, the
> >> hard id goes 0,1,4..7.  This can causes issues for places we utilize
> >> PIR to index into array like in debug exception handlers for finding
> >> the exception stack.
> >
> > Kumar, What should be the CONFIG_NR_CPUS for this? 8 or 6 ?
>=20
> 8.

Kumar, I am just trying to understand the impact of setting NR_CPUS =3D 8 w=
hile actual cpus are 6 only.

If I understood correctly, cpu_present, cpu_online are logical cpuid bit ma=
p. Also the PACA is allocated for nr_cpu_ids (NR_CPUS) and also indexed by =
logical cpuid. While they have knowledge of physical_cpuid.

So in this case last two entries of PACA will not be used or wasted?
I am not sure I am missing something here?

Thanks
-Bharat

^ permalink raw reply

* Re: [PATCH] powerpc/85xx: Setup secondary cores PIR with hard SMP id
From: Kumar Gala @ 2011-10-20  4:02 UTC (permalink / raw)
  To: Bhushan Bharat-R65777; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <B8D6CA50DACE9E4AAADE9A4D56FBAAE6244FDF@039-SN1MPN1-005.039d.mgd.msft.net>


On Oct 19, 2011, at 10:53 PM, Bhushan Bharat-R65777 wrote:

> 
> 
>> -----Original Message-----
>> From: linuxppc-dev-bounces+bharat.bhushan=freescale.com@lists.ozlabs.org
>> [mailto:linuxppc-dev-
>> bounces+bharat.bhushan=freescale.com@lists.ozlabs.org] On Behalf Of Kumar
>> Gala
>> Sent: Friday, October 14, 2011 1:23 PM
>> To: linuxppc-dev@ozlabs.org
>> Subject: [PATCH] powerpc/85xx: Setup secondary cores PIR with hard SMP id
>> 
>> Normally logical and hard cpu ID are the same, however in same cases like
>> on the P3060 they may differ.  Where the logical is 0..5, the hard id
>> goes 0,1,4..7.  This can causes issues for places we utilize PIR to index
>> into array like in debug exception handlers for finding the exception
>> stack.
> 
> Kumar, What should be the CONFIG_NR_CPUS for this? 8 or 6 ?

8.

- k

^ permalink raw reply

* RE: [PATCH] powerpc/85xx: Setup secondary cores PIR with hard SMP id
From: Bhushan Bharat-R65777 @ 2011-10-20  3:53 UTC (permalink / raw)
  To: Kumar Gala, linuxppc-dev@ozlabs.org
In-Reply-To: <1318578771-16865-1-git-send-email-galak@kernel.crashing.org>



> -----Original Message-----
> From: linuxppc-dev-bounces+bharat.bhushan=3Dfreescale.com@lists.ozlabs.or=
g
> [mailto:linuxppc-dev-
> bounces+bharat.bhushan=3Dfreescale.com@lists.ozlabs.org] On Behalf Of Kum=
ar
> Gala
> Sent: Friday, October 14, 2011 1:23 PM
> To: linuxppc-dev@ozlabs.org
> Subject: [PATCH] powerpc/85xx: Setup secondary cores PIR with hard SMP id
>=20
> Normally logical and hard cpu ID are the same, however in same cases like
> on the P3060 they may differ.  Where the logical is 0..5, the hard id
> goes 0,1,4..7.  This can causes issues for places we utilize PIR to index
> into array like in debug exception handlers for finding the exception
> stack.

Kumar, What should be the CONFIG_NR_CPUS for this? 8 or 6 ?

Thanks
-Bharat

>=20
> Move to setting up PIR with hard_smp_processor_id fixes the issue.
>=20
> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
> ---
>  arch/powerpc/platforms/85xx/smp.c |    9 +++++----
>  1 files changed, 5 insertions(+), 4 deletions(-)
>=20
> diff --git a/arch/powerpc/platforms/85xx/smp.c
> b/arch/powerpc/platforms/85xx/smp.c
> index d6e4746..190d111 100644
> --- a/arch/powerpc/platforms/85xx/smp.c
> +++ b/arch/powerpc/platforms/85xx/smp.c
> @@ -48,10 +48,11 @@ smp_85xx_kick_cpu(int nr)
>  	const u64 *cpu_rel_addr;
>  	__iomem u32 *bptr_vaddr;
>  	struct device_node *np;
> -	int n =3D 0;
> +	int n =3D 0, hw_cpu =3D get_hard_smp_processor_id(nr);
>  	int ioremappable;
>=20
> -	WARN_ON (nr < 0 || nr >=3D NR_CPUS);
> +	WARN_ON(nr < 0 || nr >=3D NR_CPUS);
> +	WARN_ON(hw_cpu < 0 || hw_cpu >=3D NR_CPUS);
>=20
>  	pr_debug("smp_85xx_kick_cpu: kick CPU #%d\n", nr);
>=20
> @@ -79,7 +80,7 @@ smp_85xx_kick_cpu(int nr)
>=20
>  	local_irq_save(flags);
>=20
> -	out_be32(bptr_vaddr + BOOT_ENTRY_PIR, nr);
> +	out_be32(bptr_vaddr + BOOT_ENTRY_PIR, hw_cpu);
>  #ifdef CONFIG_PPC32
>  	out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start));
>=20
> @@ -88,7 +89,7 @@ smp_85xx_kick_cpu(int nr)
>  				(ulong)(bptr_vaddr + SIZE_BOOT_ENTRY));
>=20
>  	/* Wait a bit for the CPU to ack. */
> -	while ((__secondary_hold_acknowledge !=3D nr) && (++n < 1000))
> +	while ((__secondary_hold_acknowledge !=3D hw_cpu) && (++n < 1000))
>  		mdelay(1);
>  #else
>  	smp_generic_kick_cpu(nr);
> --
> 1.7.3.4
>=20
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev

^ permalink raw reply

* RE: [PATCH 3/5][v2] fsl-rio: Add two ports and rapidio message units support
From: Bounine, Alexandre @ 2011-10-19 19:54 UTC (permalink / raw)
  To: Kumar Gala, linuxppc-dev; +Cc: Andrew Morton, Liu Gang, linux-kernel
In-Reply-To: <1318514922-12672-3-git-send-email-galak@kernel.crashing.org>

On Thu, Oct 13, 2011 at 10:09 AM, Kumar Gala wrote:
>=20
> From: Liu Gang <Gang.Liu@freescale.com>
>=20
> Usually, freescale rapidio endpoint can support one 1X or two 4X LP-
> Serial
> link interfaces, and rapidio message transactions can be implemented
by
> two

Is the number of 1x ports described correctly?
Can we have two 1x ports as well?=20

> message units. This patch adds the support of two rapidio ports and
> initializes message unit 0 and message unit 1. And these ports and
> message
... skip ...
> +
> +		/* Probe the master port phy type */
> +		ccsr =3D in_be32(priv->regs_win + RIO_CCSR + i*0x20);
> +		port->phy_type =3D (ccsr & 1) ? RIO_PHY_SERIAL :
> RIO_PHY_PARALLEL;
> +		dev_info(&dev->dev, "RapidIO PHY type: %s\n",
> +				(port->phy_type =3D=3D RIO_PHY_PARALLEL) ?
> +				"parallel" :
> +				((port->phy_type =3D=3D RIO_PHY_SERIAL) ?
"serial"
> :
> +				 "unknown"));
> +		/* Checking the port training status */
> +		if (in_be32((priv->regs_win + RIO_ESCSR + i*0x20)) & 1)
{
> +			dev_err(&dev->dev, "Port %d is not ready. "
> +				"Try to restart connection...\n", i);
> +			switch (port->phy_type) {
> +			case RIO_PHY_SERIAL:
> +				/* Disable ports */
> +				out_be32(priv->regs_win
> +					+ RIO_CCSR + i*0x20, 0);
> +				/* Set 1x lane */
> +				setbits32(priv->regs_win
> +					+ RIO_CCSR + i*0x20,
0x02000000);
> +				/* Enable ports */
> +				setbits32(priv->regs_win
> +					+ RIO_CCSR + i*0x20,
0x00600000);
> +				break;
> +			case RIO_PHY_PARALLEL:
> +				/* Disable ports */
> +				out_be32(priv->regs_win
> +					+ RIO_CCSR + i*0x20,
0x22000000);
> +				/* Enable ports */
> +				out_be32(priv->regs_win
> +					+ RIO_CCSR + i*0x20,
0x44000000);
> +				break;
> +			}

Probably this may be a good moment to drop the support for parallel
link.
Especially after you renamed controller to "srio" in the device tree.

> +			msleep(100);
> +			if (in_be32((priv->regs_win
> +					+ RIO_ESCSR + i*0x20)) & 1) {
> +				dev_err(&dev->dev,
> +					"Port %d restart failed.\n", i);
> +				release_resource(&port->iores);
> +				kfree(priv);
> +				kfree(port);
> +				continue;
> +			}
> +			dev_info(&dev->dev, "Port %d restart
success!\n", i);
> +		}
> +		fsl_rio_info(&dev->dev, ccsr);
> +
... skip ...
>=20
>  struct rio_msg_regs {
> -	u32 omr;	/* 0xD_3000 - Outbound message 0 mode register
*/
> -	u32 osr;	/* 0xD_3004 - Outbound message 0 status register
*/
> +	u32 omr;
> +	u32 osr;
>  	u32 pad1;
> -	u32 odqdpar;	/* 0xD_300C - Outbound message 0 descriptor
> queue
> -			   dequeue pointer address register */
> +	u32 odqdpar;
>  	u32 pad2;
> -	u32 osar;	/* 0xD_3014 - Outbound message 0 source address
> -			   register */
> -	u32 odpr;	/* 0xD_3018 - Outbound message 0 destination
port
> -			   register */
> -	u32 odatr;	/* 0xD_301C - Outbound message 0 destination
> attributes
> -			   Register*/
> -	u32 odcr;	/* 0xD_3020 - Outbound message 0 double-word
count
> -			   register */
> +	u32 osar;
> +	u32 odpr;
> +	u32 odatr;
> +	u32 odcr;
>  	u32 pad3;
> -	u32 odqepar;	/* 0xD_3028 - Outbound message 0 descriptor
> queue
> -			   enqueue pointer address register */
> +	u32 odqepar;
>  	u32 pad4[13];
> -	u32 imr;	/* 0xD_3060 - Inbound message 0 mode register */
> -	u32 isr;	/* 0xD_3064 - Inbound message 0 status register
*/
> +	u32 imr;
> +	u32 isr;
>  	u32 pad5;
> -	u32 ifqdpar;	/* 0xD_306C - Inbound message 0 frame queue
> dequeue
> -			   pointer address register*/
> +	u32 ifqdpar;
>  	u32 pad6;
> -	u32 ifqepar;	/* 0xD_3074 - Inbound message 0 frame queue
> enqueue
> -			   pointer address register */
> -	u32 pad7[226];
> -	u32 odmr;	/* 0xD_3400 - Outbound doorbell mode register */
> -	u32 odsr;	/* 0xD_3404 - Outbound doorbell status register
*/
> +	u32 ifqepar;
> +	u32 pad7;

Do we need pad7 here?

> +};
> +
> +struct rio_dbell_regs {
> +	u32 odmr;
> +	u32 odsr;
>  	u32 res0[4];
> -	u32 oddpr;	/* 0xD_3418 - Outbound doorbell destination port
> -			   register */

... skip ...

>=20
> @@ -340,35 +327,45 @@ fsl_rio_dbell_handler(int irq, void
> *dev_instance)
>  			" sid %2.2x tid %2.2x info %4.4x\n",
>  			DBELL_SID(dmsg), DBELL_TID(dmsg),
DBELL_INF(dmsg));
>=20
> -		list_for_each_entry(dbell, &port->dbells, node) {
> -			if ((dbell->res->start <=3D DBELL_INF(dmsg)) &&
> -				(dbell->res->end >=3D DBELL_INF(dmsg))) {
> -				found =3D 1;
> -				break;
> +		for (i =3D 0; i < MAX_PORT_NUM; i++) {
> +			if (fsl_dbell->mport[i]) {
> +				list_for_each_entry(dbell,
> +					&fsl_dbell->mport[i]->dbells,
node) {
> +					if ((dbell->res->start
> +						<=3D DBELL_INF(dmsg))
> +						&& (dbell->res->end
> +						>=3D DBELL_INF(dmsg))) {
> +						found =3D 1;
> +						break;
> +					}
> +				}
> +				if (found && dbell->dinb) {
> +					dbell->dinb(fsl_dbell->mport[i],
> +						dbell->dev_id,
DBELL_SID(dmsg),
> +						DBELL_TID(dmsg),
> +						DBELL_INF(dmsg));
> +					break;
> +				}
>  			}
>  		}

Do we need to check for matching DBELL_TID and mport destID here
and scan only doorbell list attached to the right port? Otherwise this
may call service routine associated with doorbell on a wrong port.

> -		if (found) {
> -			dbell->dinb(port, dbell->dev_id,
> -					DBELL_SID(dmsg),
> -					DBELL_TID(dmsg),
DBELL_INF(dmsg));
> -		} else {
> +
> +		if (!found) {
>  			pr_debug
>  				("RIO: spurious doorbell,"
>  				" sid %2.2x tid %2.2x info %4.4x\n",
>  				DBELL_SID(dmsg), DBELL_TID(dmsg),
>  				DBELL_INF(dmsg));
>  		}
> -		setbits32(&rmu->msg_regs->dmr, DOORBELL_DMR_DI);
> -		out_be32(&rmu->msg_regs->dsr, DOORBELL_DSR_DIQI);
> +		setbits32(&fsl_dbell->dbell_regs->dmr, DOORBELL_DMR_DI);
> +		out_be32(&fsl_dbell->dbell_regs->dsr,
DOORBELL_DSR_DIQI);
>  	}
>=20
>  out:
>  	return IRQ_HANDLED;
>  }
>=20
... skip ...

> @@ -1114,50 +1104,48 @@ int fsl_rio_setup_rmu(struct rio_mport *mport,
> struct device_node *node)
>  {
>  	struct rio_priv *priv;
>  	struct fsl_rmu *rmu;
> -	struct rio_ops *ops;
> +	u64 msg_start;
> +	const u32 *msg_addr;
> +	int mlen;
> +	int aw;
>=20
> -	if (!mport || !mport->priv || !node)
> -		return -1;
> +	if (!mport || !mport->priv)
> +		return -EFAULT;
EINVAL may be better here?

> +
> +	priv =3D mport->priv;
> +
> +	if (!node) {
> +		dev_warn(priv->dev, "Can't get %s property 'fsl,rmu'\n",
> +			priv->dev->of_node->full_name);
> +		return -EFAULT;
EINVAL as well?

> +	}

Regards,

Alex.

^ permalink raw reply

* [PATCH] powerpc/cpm: Clear muram before it is in use.
From: Kumar Gala @ 2011-10-19  7:18 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Hongjun Chen

From: Hongjun Chen <Hong-jun.Chen@freescale.com>

We need to ensure that MURAM is in a known and cleared out state before
using it as the bootloader could have utilized it from its own purposes
and left it in an unknown state.

If we don't clear it out we've seen issues with UCC ethernet:
* Multi ethernet interfaces can't work simultanously.
* Multi up/down Ethernet interfaces will halt these ports.
* UCC1 RGMII can't work when kernel boots from some hosts.

Signed-off-by: Kai.Jiang <Kai.Jiang@freescale.com>
Signed-off-by: Hongjun Chen <Hong-jun.Chen@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/sysdev/cpm_common.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c
index d55d0ad..8db10bb 100644
--- a/arch/powerpc/sysdev/cpm_common.c
+++ b/arch/powerpc/sysdev/cpm_common.c
@@ -3,7 +3,7 @@
  *
  * Author: Scott Wood <scottwood@freescale.com>
  *
- * Copyright 2007 Freescale Semiconductor, Inc.
+ * Copyright 2007-2008,2010 Freescale Semiconductor, Inc.
  *
  * Some parts derived from commproc.c/cpm2_common.c, which is:
  * Copyright (c) 1997 Dan error_act (dmalek@jlc.net)
@@ -146,6 +146,7 @@ unsigned long cpm_muram_alloc(unsigned long size, unsigned long align)
 	spin_lock_irqsave(&cpm_muram_lock, flags);
 	cpm_muram_info.alignment = align;
 	start = rh_alloc(&cpm_muram_info, size, "commproc");
+	memset(cpm_muram_addr(start), 0, size);
 	spin_unlock_irqrestore(&cpm_muram_lock, flags);
 
 	return start;
-- 
1.7.3.4

^ permalink raw reply related

* Re: FW: P4080 device tree problems with fsl dpaa ... RESOLVED.
From: Thomas De Schampheleire @ 2011-10-19  6:34 UTC (permalink / raw)
  To: Robert Sciuk; +Cc: linuxppc-dev
In-Reply-To: <2DD52030B5146141BEB762A11AE97C4CF6E5E9@SPQCEXC05.exfo.com>

Hi Robert,

On Tue, Oct 18, 2011 at 11:38 PM, Robert Sciuk <robert.sciuk@exfo.com> wrot=
e:
>
>
> [snip]
>
>>
>> How and what type of packets are you sending? Raw MAC frames, IP? Are
>> you using custom code, or can you try things like ping?
>> If you are using IP, I trust you checked the Linux configuration (like
>> assigning a valid IP address to the interface and making sure the
>> routing table is correct).
>>
>> Best regards,
>> Thomas
>
> Thomas,
>
> I would like to thank you for your very kind assistance on the DPAA probl=
em. =A0We traced the problem to the connection between MAC and PHY, and we =
have resolved it by instrumenting code and comparing the TBI and PHY initia=
lization from u-boot to the Linux DPA code, and replacing some of the "magi=
c numbers" we found in the driver with "magic numbers" we know to work. =A0=
OUCH!
>
> We spent an inordinate amount of effort in trying to understand the undoc=
umented code/tree, but I am convinced that the device-tree approach to embe=
dded boards is a very valuable approach, and will ultimately solve many mor=
e problems than it creates short term.
>
> Again, your information was of great assistance, and I look forward to be=
ing able to pay forward the same kind of assistance in the future.

I'm very glad you found the issue (I was running out of ideas ;-) and
that I was able to help you in some way.
Thanks for posting back.

Good luck with the rest of your project!

Best regards,
Thomas

>
> Cheers,
> Rob Sciuk.
>
>

^ permalink raw reply

* RE: FW: P4080 device tree problems with fsl dpaa ... RESOLVED.
From: Robert Sciuk @ 2011-10-18 21:38 UTC (permalink / raw)
  To: Thomas De Schampheleire; +Cc: linuxppc-dev
In-Reply-To: <CAAXf6LWTU_OVBLfn4Tavo6JxE5UfoN8JuCidB4fbr4-RX+XdAw@mail.gmail.com>



[snip]

>=20
> How and what type of packets are you sending? Raw MAC frames, IP? Are
> you using custom code, or can you try things like ping?
> If you are using IP, I trust you checked the Linux configuration (like
> assigning a valid IP address to the interface and making sure the
> routing table is correct).
>=20
> Best regards,
> Thomas

Thomas,

I would like to thank you for your very kind assistance on the DPAA =
problem.  We traced the problem to the connection between MAC and PHY, =
and we have resolved it by instrumenting code and comparing the TBI and =
PHY initialization from u-boot to the Linux DPA code, and replacing some =
of the "magic numbers" we found in the driver with "magic numbers" we =
know to work.  OUCH!

We spent an inordinate amount of effort in trying to understand the =
undocumented code/tree, but I am convinced that the device-tree approach =
to embedded boards is a very valuable approach, and will ultimately =
solve many more problems than it creates short term. =20

Again, your information was of great assistance, and I look forward to =
being able to pay forward the same kind of assistance in the future.

Cheers,
Rob Sciuk.

^ permalink raw reply

* RE: IRQ2 and IRQ 3
From: Bhushan Bharat-R65777 @ 2011-10-18 15:03 UTC (permalink / raw)
  To: smitha.vanga@wipro.com, Wood Scott-B07421; +Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <40631E9A2581F14BA60888C87A76A1FE016391@HYD-MKD-MBX4.wipro.com>

Hi,=20

For detail please look at ePAPR specification.

Say i2c interrupt number is 21 then you can try
"interrupts =3D <21 8>;" in device tree.

Thanks
-Bharat

> -----Original Message-----
> From: smitha.vanga@wipro.com [mailto:smitha.vanga@wipro.com]
> Sent: Tuesday, October 18, 2011 2:35 PM
> To: Bhushan Bharat-R65777; Wood Scott-B07421
> Cc: linuxppc-dev@lists.ozlabs.org
> Subject: RE: IRQ2 and IRQ 3
>=20
> Yes , there is a vector numbe defined in the specifications .
>=20
> IRQ2 - 20
> IRQ3 - 21
>=20
> But I don't know how to specify them in the .dts file .
>=20
> Regards,
> Smitha
> Please do not print this email unless it is absolutely necessary.
>=20
> The information contained in this electronic message and any attachments
> to this message are intended for the exclusive use of the addressee(s)
> and may contain proprietary, confidential or privileged information. If
> you are not the intended recipient, you should not disseminate,
> distribute or copy this e-mail. Please notify the sender immediately and
> destroy all copies of this message and any attachments.
>=20
> WARNING: Computer viruses can be transmitted via email. The recipient
> should check this email and any attachments for the presence of viruses.
> The company accepts no liability for any damage caused by any virus
> transmitted by this email.
>=20
> www.wipro.com

^ permalink raw reply

* Re: [PATCH v13 0/6] flexcan: Add support for powerpc flexcan (freescale p1010)
From: Robin Holt @ 2011-10-18 12:30 UTC (permalink / raw)
  To: Kumar Gala
  Cc: netdev, U Bhaskar-B22300, socketcan-core, Robin Holt, PPC list,
	David S. Miller
In-Reply-To: <D79CB818-C14E-4C8D-9A8D-42B39ADE20B2@kernel.crashing.org>

On Tue, Oct 18, 2011 at 06:43:13AM -0500, Kumar Gala wrote:
> 
> >> Robin,
> >> 
> >> Do you remember why we went with just 'fsl,p1010-flexcan' as the device tree compatible?  Do we feel the flex can on P1010 isn't the same as on MPC5xxx? or the ARM SoCs?
> > 
> > The decision was due to the fact there is no true "generic" fsl.flexcan
> > chip free of any SOC implementation and therefore not something which
> > could be separately defined.  That decision was made by Grant Likely.
> > I will inline that email below.
> > 
> > Robin
> 
> 
> Thanks, I'll look into this internally at FSL.  I think its confusing as hell to have "fsl,p1010-flexcan" in an ARM .dts and don't think any reasonable ARM customer of FSL would know to put a PPC SOC name in their .dts.  I'll ask the HW guys what's going on so we can come up with a bit more generic name so we don't have to constantly change this.  Even if its just:

Grants argument was that there should then be a fsl,zeba-flexcan which
would define each arm based soc.  The match string could be there and
the devicetree binding would match on each equivalent.

Robin

> 
> fsl,ppc-flexcan & fsl,arm-flexcan.
> 
> > On Mon, Aug 15, 2011 at 09:13:50AM -0600, Grant Likely wrote:
> >> On Mon, Aug 15, 2011 at 9:03 AM, Robin Holt <holt@sgi.com> wrote:
> >>> Grant,
> >>> 
> >>> Earlier, you had asked for a more specific name for the compatible
> >>> property of the Freescale flexcan device.  I still have not gotten a
> >>> more specific answer.  Hopefully Marc can give you more details about
> >>> the flexcan implementations.
> >> 
> >> If there is no ip core version, then just stick with the
> >> fsl,<soc>-flexcan name and drop "fsl,flexcan".  Marketing may say
> >> flexcan is flexcan, but hardware engineers like to change things.
> >> Trying to be too generic in compatible values will just lead to
> >> problems in the future.
> > 
> > Thanks,
> > Robin
> 
> - k

^ permalink raw reply

* Re: [PATCH v13 0/6] flexcan: Add support for powerpc flexcan (freescale p1010)
From: Marc Kleine-Budde @ 2011-10-18 11:48 UTC (permalink / raw)
  To: Kumar Gala
  Cc: netdev, U Bhaskar-B22300, linux-can, socketcan-core, Robin Holt,
	PPC list, David S. Miller
In-Reply-To: <D79CB818-C14E-4C8D-9A8D-42B39ADE20B2@kernel.crashing.org>

[-- Attachment #1: Type: text/plain, Size: 857 bytes --]

On 10/18/2011 01:43 PM, Kumar Gala wrote:
> Thanks, I'll look into this internally at FSL.  I think its confusing
> as hell to have "fsl,p1010-flexcan" in an ARM .dts and don't think
> any reasonable ARM customer of FSL would know to put a PPC SOC name
> in their .dts.  I'll ask the HW guys what's going on so we can come
> up with a bit more generic name so we don't have to constantly change
> this.  Even if its just:
> 
> fsl,ppc-flexcan & fsl,arm-flexcan.

If you talk the HW guys ask them for a name for the coldfire flexcan
core, too please ;)

cheers, Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

^ permalink raw reply

* Re: [PATCH v13 0/6] flexcan: Add support for powerpc flexcan (freescale p1010)
From: Kumar Gala @ 2011-10-18 11:43 UTC (permalink / raw)
  To: Robin Holt
  Cc: netdev, U Bhaskar-B22300, socketcan-core, PPC list,
	David S. Miller
In-Reply-To: <20111018094328.GC22814@sgi.com>


>> Robin,
>>=20
>> Do you remember why we went with just 'fsl,p1010-flexcan' as the =
device tree compatible?  Do we feel the flex can on P1010 isn't the same =
as on MPC5xxx? or the ARM SoCs?
>=20
> The decision was due to the fact there is no true "generic" =
fsl.flexcan
> chip free of any SOC implementation and therefore not something which
> could be separately defined.  That decision was made by Grant Likely.
> I will inline that email below.
>=20
> Robin


Thanks, I'll look into this internally at FSL.  I think its confusing as =
hell to have "fsl,p1010-flexcan" in an ARM .dts and don't think any =
reasonable ARM customer of FSL would know to put a PPC SOC name in their =
.dts.  I'll ask the HW guys what's going on so we can come up with a bit =
more generic name so we don't have to constantly change this.  Even if =
its just:

fsl,ppc-flexcan & fsl,arm-flexcan.

> On Mon, Aug 15, 2011 at 09:13:50AM -0600, Grant Likely wrote:
>> On Mon, Aug 15, 2011 at 9:03 AM, Robin Holt <holt@sgi.com> wrote:
>>> Grant,
>>>=20
>>> Earlier, you had asked for a more specific name for the compatible
>>> property of the Freescale flexcan device.  I still have not gotten a
>>> more specific answer.  Hopefully Marc can give you more details =
about
>>> the flexcan implementations.
>>=20
>> If there is no ip core version, then just stick with the
>> fsl,<soc>-flexcan name and drop "fsl,flexcan".  Marketing may say
>> flexcan is flexcan, but hardware engineers like to change things.
>> Trying to be too generic in compatible values will just lead to
>> problems in the future.
>=20
> Thanks,
> Robin

- k=

^ permalink raw reply

* Re: [PATCH v13 0/6] flexcan: Add support for powerpc flexcan (freescale p1010)
From: Robin Holt @ 2011-10-18  9:43 UTC (permalink / raw)
  To: Kumar Gala
  Cc: netdev, U Bhaskar-B22300, socketcan-core, Robin Holt, PPC list,
	David S. Miller
In-Reply-To: <16FBAA47-5133-43A1-80CE-C6D63B79FB5D@kernel.crashing.org>

On Tue, Oct 18, 2011 at 12:44:07AM -0500, Kumar Gala wrote:
> 
> On Aug 16, 2011, at 10:32 PM, Robin Holt wrote:
> 
> > David,
> > 
> > The following set of patches have been reviewed by the above parties and
> > all comments have been integrated.  Although the patches stray from the
> > drivers/net/can directory, the diversions are related to changes for
> > the flexcan driver.
> > 
> > The patch set is based upon your net-next-2.6 tree's commit 6c37e46.
> > 
> > Could you please queue these up for the next appropriate push to Linus'
> > tree?
> > 
> > Thanks,
> > Robin Holt
> 
> Robin,
> 
> Do you remember why we went with just 'fsl,p1010-flexcan' as the device tree compatible?  Do we feel the flex can on P1010 isn't the same as on MPC5xxx? or the ARM SoCs?

The decision was due to the fact there is no true "generic" fsl.flexcan
chip free of any SOC implementation and therefore not something which
could be separately defined.  That decision was made by Grant Likely.
I will inline that email below.

Robin


On Mon, Aug 15, 2011 at 09:13:50AM -0600, Grant Likely wrote:
> On Mon, Aug 15, 2011 at 9:03 AM, Robin Holt <holt@sgi.com> wrote:
> > Grant,
> >
> > Earlier, you had asked for a more specific name for the compatible
> > property of the Freescale flexcan device.  I still have not gotten a
> > more specific answer.  Hopefully Marc can give you more details about
> > the flexcan implementations.
> 
> If there is no ip core version, then just stick with the
> fsl,<soc>-flexcan name and drop "fsl,flexcan".  Marketing may say
> flexcan is flexcan, but hardware engineers like to change things.
> Trying to be too generic in compatible values will just lead to
> problems in the future.

Thanks,
Robin

^ permalink raw reply

* Re: IRQ2 and IRQ 3
From: Vineeth @ 2011-10-18  9:10 UTC (permalink / raw)
  To: smitha.vanga, linuxppc-dev
In-Reply-To: <40631E9A2581F14BA60888C87A76A1FE016391@HYD-MKD-MBX4.wipro.com>

[-- Attachment #1: Type: text/plain, Size: 1471 bytes --]

interrupts <IRQ_NO,POLARITY>


 i2c@3000 {
            #address-cells = <1>;
            #size-cells = <0>;
            cell-index = <0>;
            compatible = "fsl-i2c";
            reg = <0x3000 0x100>;
            interrupts = <43 2>;
            interrupt-parent = <&mpic>;
            dfsrr;
        };




On Tue, Oct 18, 2011 at 2:35 PM, <smitha.vanga@wipro.com> wrote:

> Yes , there is a vector numbe defined in the specifications .
>
> IRQ2 - 20
> IRQ3 - 21
>
> But I don't know how to specify them in the .dts file .
>
> Regards,
> Smitha
> Please do not print this email unless it is absolutely necessary.
>
> The information contained in this electronic message and any attachments to
> this message are intended for the exclusive use of the addressee(s) and may
> contain proprietary, confidential or privileged information. If you are not
> the intended recipient, you should not disseminate, distribute or copy this
> e-mail. Please notify the sender immediately and destroy all copies of this
> message and any attachments.
>
> WARNING: Computer viruses can be transmitted via email. The recipient
> should check this email and any attachments for the presence of viruses. The
> company accepts no liability for any damage caused by any virus transmitted
> by this email.
>
> www.wipro.com
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
>

[-- Attachment #2: Type: text/html, Size: 2054 bytes --]

^ permalink raw reply

* RE: IRQ2 and IRQ 3
From: smitha.vanga @ 2011-10-18  9:05 UTC (permalink / raw)
  To: R65777, B07421; +Cc: linuxppc-dev
In-Reply-To: <B8D6CA50DACE9E4AAADE9A4D56FBAAE623BEB3@039-SN1MPN1-005.039d.mgd.msft.net>

Yes , there is a vector numbe defined in the specifications .

IRQ2 - 20
IRQ3 - 21

But I don't know how to specify them in the .dts file .

Regards,
Smitha
Please do not print this email unless it is absolutely necessary. 

The information contained in this electronic message and any attachments to=
 this message are intended for the exclusive use of the addressee(s) and may=
 contain proprietary, confidential or privileged information. If you are not=
 the intended recipient, you should not disseminate, distribute or copy this=
 e-mail. Please notify the sender immediately and destroy all copies of this=
 message and any attachments. 

WARNING: Computer viruses can be transmitted via email. The recipient should=
 check this email and any attachments for the presence of viruses. The compa=
ny accepts no liability for any damage caused by any virus transmitted by th=
is email. 

www.wipro.com

^ permalink raw reply

* RE: IRQ2 and IRQ 3
From: Bhushan Bharat-R65777 @ 2011-10-18  8:58 UTC (permalink / raw)
  To: smitha.vanga@wipro.com, Wood Scott-B07421; +Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <40631E9A2581F14BA60888C87A76A1FE01637C@HYD-MKD-MBX4.wipro.com>

Hi,

Is not some interrupt vector number defined for i2c in your soc specificati=
on(IIRC mpc9247 and I do not have this).

Thanks
-Bharat


> -----Original Message-----
> From: smitha.vanga@wipro.com [mailto:smitha.vanga@wipro.com]
> Sent: Tuesday, October 18, 2011 1:36 PM
> To: Wood Scott-B07421; Bhushan Bharat-R65777
> Cc: linuxppc-dev@lists.ozlabs.org
> Subject: RE: IRQ2 and IRQ 3
>=20
>=20
>=20
> Hi ,
>=20
> I want to use IRQ2 and IRQ3 in my driver. How do I add them in the device
> tree file.
>=20
> Regard,
> Smitha
>=20
> Please do not print this email unless it is absolutely necessary.
>=20
> The information contained in this electronic message and any attachments
> to this message are intended for the exclusive use of the addressee(s)
> and may contain proprietary, confidential or privileged information. If
> you are not the intended recipient, you should not disseminate,
> distribute or copy this e-mail. Please notify the sender immediately and
> destroy all copies of this message and any attachments.
>=20
> WARNING: Computer viruses can be transmitted via email. The recipient
> should check this email and any attachments for the presence of viruses.
> The company accepts no liability for any damage caused by any virus
> transmitted by this email.
>=20
> www.wipro.com

^ permalink raw reply

* RE: IRQ2 and IRQ 3
From: smitha.vanga @ 2011-10-18  8:06 UTC (permalink / raw)
  To: B07421, R65777; +Cc: linuxppc-dev


  
Hi ,

I want to use IRQ2 and IRQ3 in my driver. How do I add them in the device tr=
ee file.

Regard,
Smitha

Please do not print this email unless it is absolutely necessary. 

The information contained in this electronic message and any attachments to=
 this message are intended for the exclusive use of the addressee(s) and may=
 contain proprietary, confidential or privileged information. If you are not=
 the intended recipient, you should not disseminate, distribute or copy this=
 e-mail. Please notify the sender immediately and destroy all copies of this=
 message and any attachments. 

WARNING: Computer viruses can be transmitted via email. The recipient should=
 check this email and any attachments for the presence of viruses. The compa=
ny accepts no liability for any damage caused by any virus transmitted by th=
is email. 

www.wipro.com

^ permalink raw reply

* IRQ2 and IRQ 3
From: smitha.vanga @ 2011-10-18  8:05 UTC (permalink / raw)
  To: B07421; +Cc: linuxppc-dev
In-Reply-To: <B8D6CA50DACE9E4AAADE9A4D56FBAAE623B55D@039-SN1MPN1-005.039d.mgd.msft.net>

 
Hi ,

I want to use IRQ2 and IRQ3 in my driver. How do I add them in the device tr=
ee file.

Regard,
Smitha

Please do not print this email unless it is absolutely necessary. 

The information contained in this electronic message and any attachments to=
 this message are intended for the exclusive use of the addressee(s) and may=
 contain proprietary, confidential or privileged information. If you are not=
 the intended recipient, you should not disseminate, distribute or copy this=
 e-mail. Please notify the sender immediately and destroy all copies of this=
 message and any attachments. 

WARNING: Computer viruses can be transmitted via email. The recipient should=
 check this email and any attachments for the presence of viruses. The compa=
ny accepts no liability for any damage caused by any virus transmitted by th=
is email. 

www.wipro.com

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox