Re: [PATCH v5] usb: gadget: mv: Add USB 3.0 device driver for Marvell PXA2128 chip.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Balbi,

2012/6/6 Felipe Balbi <balbi@xxxxxx>:
> Hi,
>
> On Wed, Jun 06, 2012 at 10:10:28AM +0800, Yu Xu wrote:
>> >> +                     _ep->maxburst = maxburst = 1;
>> >
>> > we generally avoid multiple assignments in one line. We also avoid magic
>> > constants. Why is this always 1 and why do you overwrite ep->maxburst ?
>> >
>> I'll separate the line.
>> For the maxburst value, if the code run here, it means the
>> _ep->maxburst is wrong,
>> so we need to handle it and set it to one to make it according to the SPEC.
>> And we also handle other type of endpoint like this.
>> But actually, the function driver should ensure the _ep->maxburst is correct,
>> the code should not be touch in the normal case.
>>
>> >> +             }
>> >> +             dev_dbg(u3d->dev,
>> >> +                     "maxburst: %d on bulk %s\n", maxburst, ep->name);
>> >> +             break;
>> >> +     case USB_ENDPOINT_XFER_CONTROL:
>> >> +             if (maxburst != 1) {
>> >> +                     dev_err(u3d->dev,
>> >> +                             "max burst should be 1 on control ep\n");
>> >> +                     _ep->maxburst = maxburst = 1;
>> >
>> > if any gadget driver puts MaxBurst to anything other than zero, you
>> > should have a big giant warning about it...
>> >
>> Control transfer has the fixed max burst size of one. So we check it here.
>> Do you mean that?
>
> yes I mean that. Look at composite.c:
>
>>       if (g->speed == USB_SPEED_SUPER) {
>>               switch (usb_endpoint_type(_ep->desc)) {
>>               case USB_ENDPOINT_XFER_ISOC:
>>                       /* mult: bits 1:0 of bmAttributes */
>>                       _ep->mult = comp_desc->bmAttributes & 0x3;
>>               case USB_ENDPOINT_XFER_BULK:
>>               case USB_ENDPOINT_XFER_INT:
>>                       _ep->maxburst = comp_desc->bMaxBurst;
>>                       break;
>>               default:
>>                       /* Do nothing for control endpoints */
>>                       break;
>>               }
>>       }
>
> as you can see, control endpoint's maxburst won't even be initialized.
> In fact, I can see a bug on this code. This should read as:
>
>        if (g->speed == USB_SPEED_SUPER) {
>                switch (usb_endpoint_type(_ep->desc)) {
>                case USB_ENDPOINT_XFER_ISOC:
>                        /* mult: bits 1:0 of bmAttributes */
>                        _ep->mult = comp_desc->bmAttributes & 0x3;
>                case USB_ENDPOINT_XFER_BULK:
>                case USB_ENDPOINT_XFER_INT:
>                        _ep->maxburst = comp_desc->bMaxBurst + 1;
>                        break;
>                default:
>                        /* Do nothing for control endpoints */
>                        if (comp_desc->bMaxBurst != 0)
>                                ERROR(cdev, "ep0 bMaxBurst must be zero\n");
>                        _ep->maxburst = 1;
>                        break;
>                }
>        }
>
> I will fix that and push to v3.6 merge window.
>
What do you suggest? So I do not check it here, but set the maxburst
as 1, right?

>> >> +             return -EINVAL;
>> >> +
>> >> +     u3d = ep->u3d;
>> >> +
>> >> +     /* Get the endpoint context address */
>> >> +     ep_context = ep->ep_context;
>> >> +
>> >> +     direction = mv_u3d_ep_dir(ep);
>> >> +
>> >> +     /* nuke all pending requests (does flush) */
>> >> +     mv_u3d_nuke(ep, -ESHUTDOWN);
>> >> +
>> >> +     /* Disable the endpoint for Rx or Tx and reset the endpoint type */
>> >> +     if (direction == MV_U3D_EP_DIR_OUT) {
>> >> +             epxcr = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxoutcr1);
>> >> +             epxcr &= ~((1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT)
>> >> +                   | USB_ENDPOINT_XFERTYPE_MASK);
>> >> +             iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr1);
>> >> +     } else {
>> >> +             epxcr = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxincr1);
>> >> +             epxcr &= ~((1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT)
>> >> +                   | USB_ENDPOINT_XFERTYPE_MASK);
>> >> +             iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxincr1);
>> >> +     }
>> >> +
>> >> +     ep->enabled = 0;
>> >> +
>> >> +     ep->ep.desc = NULL;
>> >> +     return 0;
>> >> +}
>> >> +
>> >> +static struct usb_request *
>> >> +mv_u3d_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
>> >> +{
>> >> +     struct mv_u3d_req *req = NULL;
>> >> +
>> >> +     req = kzalloc(sizeof *req, gfp_flags);
>> >> +     if (!req)
>> >> +             return NULL;
>> >> +
>> >> +     INIT_LIST_HEAD(&req->queue);
>> >> +
>> >> +     return &req->req;
>> >> +}
>> >> +
>> >> +static void mv_u3d_free_request(struct usb_ep *_ep, struct usb_request *_req)
>> >> +{
>> >> +     struct mv_u3d_req *req = container_of(_req, struct mv_u3d_req, req);
>> >> +
>> >> +     kfree(req);
>> >> +}
>> >> +
>> >> +static void mv_u3d_ep_fifo_flush(struct usb_ep *_ep)
>> >> +{
>> >> +     struct mv_u3d *u3d;
>> >> +     u32 direction;
>> >> +     struct mv_u3d_ep *ep = container_of(_ep, struct mv_u3d_ep, ep);
>> >> +     unsigned int loops;
>> >> +     u32 tmp;
>> >> +
>> >> +     /* if endpoint is not enabled, cannot flush endpoint */
>> >> +     if (!ep->enabled)
>> >> +             return;
>> >> +
>> >> +     u3d = ep->u3d;
>> >> +     direction = mv_u3d_ep_dir(ep);
>> >> +
>> >> +     /* ep0 need clear bit after flushing fifo. */
>> >> +     if (!ep->ep_num) {
>> >> +             if (direction == MV_U3D_EP_DIR_OUT) {
>> >> +                     tmp = ioread32(&u3d->vuc_regs->epcr[0].epxoutcr0);
>> >> +                     tmp |= MV_U3D_EPXCR_EP_FLUSH;
>> >> +                     iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxoutcr0);
>> >> +                     udelay(10);
>> >> +                     tmp &= ~MV_U3D_EPXCR_EP_FLUSH;
>> >> +                     iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxoutcr0);
>> >> +             } else {
>> >> +                     tmp = ioread32(&u3d->vuc_regs->epcr[0].epxincr0);
>> >> +                     tmp |= MV_U3D_EPXCR_EP_FLUSH;
>> >> +                     iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxincr0);
>> >> +                     udelay(10);
>> >> +                     tmp &= ~MV_U3D_EPXCR_EP_FLUSH;
>> >> +                     iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxincr0);
>> >> +             }
>> >> +             return;
>> >> +     }
>> >> +
>> >> +     if (direction == MV_U3D_EP_DIR_OUT) {
>> >> +             tmp = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0);
>> >> +             tmp |= MV_U3D_EPXCR_EP_FLUSH;
>> >> +             iowrite32(tmp, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0);
>> >> +
>> >> +             /* Wait until flushing completed */
>> >> +             loops = LOOPS(MV_U3D_FLUSH_TIMEOUT);
>> >> +             while (ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0) &
>> >> +                     MV_U3D_EPXCR_EP_FLUSH) {
>> >> +                     /*
>> >> +                      * EP_FLUSH bit should be cleared to indicate this
>> >> +                      * operation is complete
>> >> +                      */
>> >> +                     if (loops == 0) {
>> >> +                             dev_dbg(u3d->dev,
>> >> +                                 "EP FLUSH TIMEOUT for ep%d%s\n", ep->ep_num,
>> >> +                                 direction ? "in" : "out");
>> >> +                             return;
>> >> +                     }
>> >> +                     loops--;
>> >> +                     udelay(LOOPS_USEC);
>> >> +             }
>> >> +     } else {        /* EP_DIR_IN */
>> >> +             tmp = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxincr0);
>> >> +             tmp |= MV_U3D_EPXCR_EP_FLUSH;
>> >> +             iowrite32(tmp, &u3d->vuc_regs->epcr[ep->ep_num].epxincr0);
>> >> +
>> >> +             /* Wait until flushing completed */
>> >> +             loops = LOOPS(MV_U3D_FLUSH_TIMEOUT);
>> >> +             while (ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxincr0) &
>> >> +                     MV_U3D_EPXCR_EP_FLUSH) {
>> >> +                     /*
>> >> +                     * EP_FLUSH bit should be cleared to indicate this
>> >> +                     * operation is complete
>> >> +                     */
>> >> +                     if (loops == 0) {
>> >> +                             dev_dbg(u3d->dev,
>> >> +                                 "EP FLUSH TIMEOUT for ep%d%s\n", ep->ep_num,
>> >> +                                 direction ? "in" : "out");
>> >> +                             return;
>> >> +                     }
>> >> +                     loops--;
>> >> +                     udelay(LOOPS_USEC);
>> >> +             }
>> >> +     }
>> >> +}
>> >> +
>> >> +/* queues (submits) an I/O request to an endpoint */
>> >> +static int
>> >> +mv_u3d_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
>> >> +{
>> >> +     struct mv_u3d_ep *ep = container_of(_ep, struct mv_u3d_ep, ep);
>> >> +     struct mv_u3d_req *req = container_of(_req, struct mv_u3d_req, req);
>> >> +     struct mv_u3d *u3d = ep->u3d;
>> >> +     unsigned long flags;
>> >> +     int is_first_req = 0;
>> >> +
>> >> +     if (!ep->ep_num
>> >> +             && u3d->ep0_state == MV_U3D_STATUS_STAGE
>> >> +             && !_req->length) {
>> >> +             dev_dbg(u3d->dev, "ep0 status stage\n");
>> >> +             u3d->ep0_state = MV_U3D_WAIT_FOR_SETUP;
>> >> +             return 0;
>> >> +     }
>> >> +
>> >> +     dev_dbg(u3d->dev, "%s: %s, req: 0x%x\n",
>> >> +                     __func__, _ep->name, (u32)req);
>> >> +     /* catch various bogus parameters */
>> >> +     if (!_req || !req->req.complete || !req->req.buf
>> >> +                     || !list_empty(&req->queue)) {
>> >> +             dev_err(u3d->dev,
>> >> +                     "%s, bad params, _req: 0x%x,"
>> >> +                     "req->req.complete: 0x%x, req->req.buf: 0x%x,"
>> >> +                     "list_empty: 0x%x\n",
>> >> +                     __func__, (u32)_req,
>> >> +                     (u32)req->req.complete, (u32)req->req.buf,
>> >> +                     (u32)list_empty(&req->queue));
>> >> +             return -EINVAL;
>> >> +     }
>> >> +     if (unlikely(!_ep || !ep->ep.desc)) {
>> >> +             dev_err(u3d->dev, "%s, bad ep\n", __func__);
>> >> +             return -EINVAL;
>> >> +     }
>> >> +     if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
>> >> +             if (req->req.length > ep->ep.maxpacket)
>> >> +                     return -EMSGSIZE;
>> >> +     }
>> >> +
>> >> +     if (!u3d->driver || u3d->gadget.speed == USB_SPEED_UNKNOWN) {
>> >> +             dev_err(u3d->dev,
>> >> +                     "%s, bad params of driver/speed\n", __func__);
>> >
>> > do you really need the function name here ??
>> >
>> It can help to locate the error point if error occurs. What do you think?
>
> it might... but OTOH, this is the only place on the driver where you
> print the function name and also the only place which prints "bad params
> of driver/speed". So it should be very easy to find with grep, right ?
>
HEHE, no problem, I can remove it:)

> --
> balbi

Thanks,
Yu Xu
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux