Just a few things I've noticed. Do not consider it a proper review: On Thu, 16 Sep 2010 15:39:37 +0200, Masayuki Ohtake <masa-korg@xxxxxxxxxxxxxxx> wrote:
+struct pch_udc_stp_dma_desc { + u32 status; + u32 reserved; + u32 data12; + u32 data34; +};
From what I've seen, there is no reason why not make the above: struct pch_udc_stp_dma_desc { u32 status; u32 reserved; struct usb_ctrlrequest request; } __attribute((packed));
+struct pch_udc_ep { + struct usb_ep ep; + dma_addr_t td_stp_phys; + dma_addr_t td_data_phys; + struct pch_udc_stp_dma_desc *td_stp; + struct pch_udc_data_dma_desc *td_data; + struct pch_udc_dev *dev; + unsigned long offset_addr; + const struct usb_endpoint_descriptor *desc; + struct list_head queue; + unsigned num:5; + unsigned in:1; + unsigned halted;
Can't this be made into bitfield as well?
+ unsigned long epsts; +};
+union pch_udc_setup_data { + u32 data[2]; + struct usb_ctrlrequest request; +};
This should not be needed. Just use struct pch_udc_stp_dma_desc as described above.
+static void pch_udc_csr_busy(struct pch_udc_dev *dev) +{ + unsigned int count = MAX_LOOP;
At this point, I would start wondering whether the MAX_LOOP macro is really needed. I'd remove the #define and just put a plain number here.
+ + /* Wait till idle */ + while ((pch_udc_readl(dev, UDC_CSR_BUSY_ADDR) & UDC_CSR_BUSY) + && --count) + cpu_relax(); + if (!count) + dev_err(&dev->pdev->dev, "%s: wait error", __func__); +}
+static inline void pch_udc_vbus_session(struct pch_udc_dev *dev, + int is_active) +{ + if (is_active) + pch_udc_clear_disconnect(dev); + else + pch_udc_set_disconnect(dev); +}
+/** + * pch_udc_ep_clear_nak() - Set the bit 8 (CNAK field) + * of the endpoint control register + * @ep: reference to structure of type pch_udc_ep_regs + */ +static void pch_udc_ep_clear_nak(struct pch_udc_ep *ep) +{ + unsigned int loopcnt = 0; + struct pch_udc_dev *dev = ep->dev; + + if (!(pch_udc_ep_readl(ep, UDC_EPCTL_ADDR) & UDC_EPCTL_NAK)) + return; + if (!ep->in) { + loopcnt = 100000; + while (!(pch_udc_read_ep_status(ep) & UDC_EPSTS_MRXFIFO_EMP) && + --loopcnt) + udelay(100);
This loop can take up to 10 seconds. Is it desired?
+ if (!loopcnt) + dev_dbg(&dev->pdev->dev, "%s: RxFIFO not Empty " + "loop count = %d", __func__, loopcnt);
Shouldn't that be dev_err()?
+ } + loopcnt = 100000; + while ((pch_udc_read_ep_control(ep) & UDC_EPCTL_NAK) && --loopcnt) { + pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_CNAK); + udelay(5); + }
This loop can take up to half a second. Is it desired?
+ if (!loopcnt) + dev_dbg(&dev->pdev->dev, + "%s: Clear NAK not set for ep%d%s: counter=%d", + __func__, ep->num, (ep->in ? "in" : "out"), loopcnt);
Shouldn't that be dev_err()?
+}
+static void pch_udc_ep_fifo_flush(struct pch_udc_ep *ep, int dir) +{ + unsigned int loopcnt = 0; + struct pch_udc_dev *dev = ep->dev; + + dev_dbg(&dev->pdev->dev, "%s: ep%d%s", __func__, ep->num, + (ep->in ? "in" : "out")); + if (dir) { /* IN ep */ + pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_F); + return; + } + + if (pch_udc_read_ep_status(ep) & UDC_EPSTS_MRXFIFO_EMP) + return; + pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_MRXFLUSH); + /* Wait for RxFIFO Empty */ + loopcnt = 1000000; + while (!(pch_udc_read_ep_status(ep) & UDC_EPSTS_MRXFIFO_EMP) && + --loopcnt) + udelay(100); + if (!loopcnt) + dev_dbg(&dev->pdev->dev, "RxFIFO not Empty");
Same as in function above. The loop can take up to 10 seconds plus if loopcnt reaches zero error should be printed (IMO).
+ pch_udc_ep_bit_clr(ep, UDC_EPCTL_ADDR, UDC_EPCTL_MRXFLUSH); +}
+static int pch_udc_free_dma_chain(struct pch_udc_dev *dev, + struct pch_udc_request *req) +{ + struct pch_udc_data_dma_desc *td; + struct pch_udc_data_dma_desc *td_last; + u32 i;
Why u32? Why not plain unsigned?
+ + /* do not free first desc., will be done by free for request */ + td_last = req->td_data; + td = phys_to_virt(td_last->next); + + for (i = 1; i < req->chain_len; i++) { + pci_pool_free(dev->data_requests, td, + (dma_addr_t) td_last->next); + td_last = td; + td = phys_to_virt(td_last->next); + } + return 0; +}
If I'm not mistaken, this can be refactored as: static void pch_udc_free_dma_chain(struct pch_udc_dev *dev, struct pch_udc_request *req) { struct pch_udc_data_dma_desc *td = req->td_data; unsigned i = req->chain_len; for (; i > 1; --i) { dma_addr_t addr = (dma_addr_t)td->next; /* do not free first desc., will be done by free for request */ td = phys_to_virt(addr); pci_pool_free(dev->data_requests, td, addr); } }
+static int pch_udc_create_dma_chain(struct pch_udc_ep *ep, + struct pch_udc_request *req, + unsigned long buf_len, + gfp_t gfp_flags) +{ + unsigned long bytes = req->req.length; + unsigned int i;
If bytes and buf_len is unsigned long why i is unsigned int?
+ dma_addr_t dma_addr; + struct pch_udc_data_dma_desc *td = NULL; + struct pch_udc_data_dma_desc *last = NULL; + unsigned long txbytes; + unsigned len; + + pr_debug("%s: enter bytes = %ld buf_len = %ld", __func__, bytes, + buf_len); + /* unset L bit in first desc for OUT */ + if (!ep->in) + req->td_data->status = PCH_UDC_BS_HST_BSY; + + /* alloc only new desc's if not already available */ + len = req->req.length / buf_len; + if (req->req.length % buf_len) + len++;
len = (bytes + buf_len - 1) / buf_len;
+ + /* shorter chain already allocated before */ + if (req->chain_len > 1) + pch_udc_free_dma_chain(ep->dev, req); + + req->chain_len = len; + + td = req->td_data; + /* gen. required number of descriptors and buffers */ + for (i = buf_len; i < bytes; i += buf_len) { + dma_addr = DMA_ADDR_INVALID;
No use to set.
+ /* create or determine next desc. */ + td = pci_pool_alloc(ep->dev->data_requests, gfp_flags, + &dma_addr); + if (!td) + return -ENOMEM; + + td->status = 0;
No use to set.
+ td->dataptr = req->req.dma + i; /* assign buffer */ + + if ((bytes - i) >= buf_len) + txbytes = buf_len; + else /* short packet */ + txbytes = bytes - i; + /* link td and assign tx bytes */ + if (i == buf_len) { + req->td_data->next = dma_addr; + /* set the count bytes */ + if (ep->in) { + req->td_data->status = PCH_UDC_BS_HST_BSY | + buf_len; + /* second desc */ + td->status = PCH_UDC_BS_HST_BSY | txbytes; + } else { + td->status = PCH_UDC_BS_HST_BSY; + } + } else { + last->next = dma_addr; + if (ep->in) + td->status = PCH_UDC_BS_HST_BSY | txbytes; + else + td->status = PCH_UDC_BS_HST_BSY; + + } + last = td; + } + /* set last bit */ + if (td) {
This is always true.
+ td->status |= PCH_UDC_DMA_LAST; + /* last desc. points to itself */ + req->td_data_last = td; + td->next = req->td_data_phys; + } + return 0; +}
The above function can (at least I think it can) be changed to a shorter version with no memory error recovery: static int pch_udc_create_dma_chain(struct pch_udc_ep *ep, struct pch_udc_request *req, unsigned long buf_len, gfp_t gfp_flags) { struct pch_udc_data_dma_desc *td = req->td_data, *last; unsigned long bytes = req->req.length, i = 0; dma_addr_t dma_addr; unsigned len = 1; pr_debug("%s: enter bytes = %ld buf_len = %ld", __func__, bytes, buf_len); if (req->chain_len > 1) pch_udc_free_dma_chain(ep->dev, req); for (; ; bytes -= buf_len, i += buf_len, ++len) { if (ep->in) td->status = PCH_UDC_BS_HST_BSY | min(buf_len, bytes); else td->status = PCH_UDC_BS_HST_BSY; if (bytes <= buf_len) break; last = td; td = pci_pool_alloc(ep->dev->data_requests, gfp_flags, &dma_addr); if (!td) goto nomem; i += buf_len; td->dataptr = req->req.dma + i; last->next = dma_addr; } req->td_data_last = td; td->status |= PCH_UDC_DMA_LAST; td->next = req->td_data_phys; req->chain_len = len; return 0; nomem: if (len > 1) { req->chain_len = len; pch_udc_free_dma_chain(ep->dev, req); } req->chain_len = 1; return -ENOMEM; }
+static int prepare_dma(struct pch_udc_ep *ep, struct pch_udc_request *req, + gfp_t gfp) +{ + int retval = 0;
Actually, what's the use of initialising?
+ + pr_debug("%s: enter req->req.dma=0x%08x", __func__, req->req.dma); + /* set buffer pointer */ + req->td_data->dataptr = req->req.dma; + /* set last bit */ + req->td_data->status |= PCH_UDC_DMA_LAST; + + /* Allocate and create a DMA chain */ + retval = pch_udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp); + if (retval) { + if (retval == -ENOMEM) + pr_err("%s: Out of DMA memory", __func__);
I'd change this to a simple pr_err() without if (retval == -ENOMEM). Eg.: pr_err("%s: could not create DMA chain: %d\n", __func__, retval); Also, you've forgotten about \n at the end.
+ return retval; + } + if (!ep->in) + return retval;
Just "return 0;".
+ + if (req->req.length <= ep->ep.maxpacket) + /* write tx bytes */ + req->td_data->status = PCH_UDC_DMA_LAST | PCH_UDC_BS_HST_BSY | + req->req.length; + /* if bytes < max packet then tx bytes must + * be written in packet per buffer mode + */ + if ((req->req.length < ep->ep.maxpacket) || !ep->num) + /* write the count */ + req->td_data->status = (req->td_data->status & + ~PCH_UDC_RXTX_BYTES) | req->req.length; + /* set HOST BUSY */ + req->td_data->status = (req->td_data->status & + ~PCH_UDC_BUFF_STS) | PCH_UDC_BS_HST_BSY; + return retval;
Just "return 0;".
+}
+static int pch_udc_pcd_ep_enable(struct usb_ep *usbep, + const struct usb_endpoint_descriptor *desc) +{ + struct pch_udc_ep *ep; + struct pch_udc_dev *dev; + unsigned long iflags; + + if (!usbep || (usbep->name == ep0_string) || !desc || + (desc->bDescriptorType != USB_DT_ENDPOINT) || !desc->wMaxPacketSize) + return -EINVAL; + + ep = container_of(usbep, struct pch_udc_ep, ep); + dev = ep->dev; + + dev_dbg(&dev->pdev->dev, "%s: ep %d", __func__, ep->num); + if (!dev->driver || (dev->gadget.speed == USB_SPEED_UNKNOWN)) + return -ESHUTDOWN; + + spin_lock_irqsave(&dev->lock, iflags); + ep->desc = desc; + ep->halted = 0; + pch_udc_ep_enable(ep, &ep->dev->cfg_data, desc); + ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize); + pch_udc_enable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num)); + dev_dbg(&dev->pdev->dev, "%s: %s enabled", __func__, usbep->name); + + spin_unlock_irqrestore(&dev->lock, iflags);
Move the empty line from before unlock to after unlock, please.
+ return 0; +}
+/** + * pch_udc_free_request() - This function frees request structure. + * It is called by gadget driver + * @usbep: Reference to the USB endpoint structure + * @usbreq: Reference to the USB request + */ +static void pch_udc_free_request(struct usb_ep *usbep, + struct usb_request *usbreq) +{ + struct pch_udc_ep *ep; + struct pch_udc_request *req; + struct pch_udc_dev *dev; + + if (!usbep || !usbreq) + return; + + ep = container_of(usbep, struct pch_udc_ep, ep); + req = container_of(usbreq, struct pch_udc_request, req); + dev = ep->dev; + dev_dbg(&dev->pdev->dev, "%s: %s req = 0x%p", __func__, usbep->name, + req); + + if (!list_empty(&req->queue)) + dev_err(&dev->pdev->dev, "%s: %s req = 0x%p queue not empty", + __func__, usbep->name, req); + + if (req->td_data != NULL) { + if (req->chain_len > 1) + pch_udc_free_dma_chain(ep->dev, req); + else + pci_pool_free(ep->dev->data_requests, req->td_data, + req->td_data_phys);
The first td_data is never freed? Or am I missing something? I think the "else" should be dropped and the second part should be done unconditionally.
+ } + kfree(req); +}
+ /* + * For IN trfr the descriptors will be programmed and + * P bit will be set when + * we get an IN token + */ + + while (pch_udc_read_ep_control(ep) & UDC_EPCTL_S) + udelay(100);
Some kind of limit should be used here IMO. What if hardware malfunctions and the condition is never met?
+ pch_udc_ep_clear_nak(ep); + pch_udc_enable_ep_interrupts(ep->dev, + (1 << ep->num)); + /* enable DMA */ + pch_udc_set_dma(dev, DMA_DIR_TX);
+/** + * pch_udc_pcd_dequeue() - This function de-queues a request packet. + * It is called by gadget driver + * @usbep: Reference to the USB endpoint structure + * @usbreq: Reference to the USB request + * Returns + * 0: Success + * linux error number: Failure + */ +static int pch_udc_pcd_dequeue(struct usb_ep *usbep, + struct usb_request *usbreq) +{ + struct pch_udc_ep *ep; + struct pch_udc_request *req; + struct pch_udc_dev *dev; + unsigned long flags;
I would add "int ret = -EINVAL;" here,
+ + ep = container_of(usbep, struct pch_udc_ep, ep); + dev = ep->dev; + if (!usbep || !usbreq || (!ep->desc && ep->num)) + return -EINVAL; + dev_dbg(&dev->pdev->dev, "%s: enter ep%d%s", __func__, ep->num, + (ep->in ? "in" : "out")); + req = container_of(usbreq, struct pch_udc_request, req); + spin_lock_irqsave(&ep->dev->lock, flags); + /* make sure it's still queued on this endpoint */ + list_for_each_entry(req, &ep->queue, queue) { + if (&req->req == usbreq) + break;
replace the above "if" with: if (&req->req == usbreq) { pch_udc_ep_set_nak(ep); if (!list_empty(&req->queue)) complete_req(ep, req, -ECONNRESET); ret = 0; break; }
+ } + + if (&req->req != usbreq) { + spin_unlock_irqrestore(&ep->dev->lock, flags); + return -EINVAL; + } + pch_udc_ep_set_nak(ep); + if (!list_empty(&req->queue)) + complete_req(ep, req, -ECONNRESET); + + spin_unlock_irqrestore(&ep->dev->lock, flags); + return 0;
And then, replace the whole section after the loop with: spin_unlock_irqrestore(&ep->dev->lock, flags); return ret;
+}
+static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt) +{ + struct pch_udc_ep *ep; + struct pch_udc_dev *dev; + unsigned long iflags; + + if (!usbep) + return -EINVAL; + + pr_debug("%s: %s: halt=%d", __func__, usbep->name, halt); + ep = container_of(usbep, struct pch_udc_ep, ep); + dev = ep->dev; + if (!ep->desc && !ep->num) { + dev_dbg(&dev->pdev->dev, "%s: ep->desc = 0x%x: ep->num = 0x%x", + __func__, (u32)(ep->desc), ep->num); + return -EINVAL; + } + if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN)) { + dev_dbg(&dev->pdev->dev, "%s: ep->dev->driver = 0x%x:" + " ep->dev->gadget.speed = 0x%x", + __func__, (u32)(ep->dev->driver), + ep->dev->gadget.speed); + return -ESHUTDOWN; + } + + spin_lock_irqsave(&udc_stall_spinlock, iflags); + + if (!list_empty(&ep->queue)) { + dev_dbg(&dev->pdev->dev, "%s: list not empty", __func__); + spin_unlock_irqrestore(&udc_stall_spinlock, iflags); + return -EAGAIN;
Similarly as above, I don't like when a lock has two different unlocks. It's better to use a "int ret;" above and a goto. Even better, here you can just use a chain if-else-if-...-else.
+ } + /* halt or clear halt */ + if (!halt) { + pch_udc_ep_clear_stall(ep); + } else { + if (ep->num == PCH_UDC_EP0) + ep->dev->stall = 1; + + pch_udc_ep_set_stall(ep); + pch_udc_enable_ep_interrupts(ep->dev, + PCH_UDC_EPINT(ep->in, ep->num)); + } + spin_unlock_irqrestore(&udc_stall_spinlock, iflags); + return 0;
Like so: spin_lock_irqsave(&udc_stall_spinlock, iflags); if (!list_empty(&ep->queue)) { dev_dbg(&dev->pdev->dev, "%s: list not empty", __func__); ret = -EAGAIN; } else if (!halt) { /* halt or clear halt */ pch_udc_ep_clear_stall(ep); ret = 0; } else { if (ep->num == PCH_UDC_EP0) ep->dev->stall = 1; pch_udc_ep_set_stall(ep); pch_udc_enable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num)); ret = 0; } spin_unlock_irqrestore(&udc_stall_spinlock, iflags); return ret;
+}
+static int pch_udc_pcd_set_wedge(struct usb_ep *usbep) +{ + struct pch_udc_ep *ep; + struct pch_udc_dev *dev; + unsigned long iflags; + + if (!usbep) + return -EINVAL; + + pr_debug("%s: %s:", __func__, usbep->name); + ep = container_of(usbep, struct pch_udc_ep, ep); + dev = ep->dev; + if (!ep->desc && !ep->num) { + dev_dbg(&dev->pdev->dev, "%s: ep->desc = 0x%x: ep->num = 0x%x", + __func__, (u32)(ep->desc), ep->num); + return -EINVAL; + } + if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN)) { + dev_dbg(&dev->pdev->dev, "%s: ep->dev->driver = 0x%x: " + "ep->dev->gadget.speed = 0x%x", __func__, + (u32)(ep->dev->driver), ep->dev->gadget.speed); + return -ESHUTDOWN; + } + + spin_lock_irqsave(&udc_stall_spinlock, iflags); + + if (!list_empty(&ep->queue)) { + dev_dbg(&dev->pdev->dev, "%s: list not empty", __func__); + spin_unlock_irqrestore(&udc_stall_spinlock, iflags); + return -EAGAIN;
Like above, please add an "else" section and use an "int ret" to hold exit status. This will again allow to have only one "unlock".
+ } + /* halt */ + if (ep->num == PCH_UDC_EP0) + ep->dev->stall = 1; + + pch_udc_ep_set_stall(ep); + pch_udc_enable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num)); + + ep->dev->prot_stall = 1; + spin_unlock_irqrestore(&udc_stall_spinlock, iflags); + return 0; +}
+static void pch_udc_pcd_fifo_flush(struct usb_ep *usbep) +{ + struct pch_udc_ep *ep ; + + if (!usbep) + return; + + pr_debug("%s: %s", __func__, usbep->name); + ep = container_of(usbep, struct pch_udc_ep, ep); + if (!ep->desc && ep->num) + return; + pch_udc_ep_fifo_flush(ep, ep->in);
A matter of taste I think, but why not: if (ep->desc || !ep->num) pch_udc_ep_fifo_flush(ep, ep->in);
+}
+static void pch_udc_start_next_txrequest(struct pch_udc_ep *ep) +{ + struct pch_udc_request *req; + struct pch_udc_data_dma_desc *td_data; + struct pch_udc_dev *dev = ep->dev; + + if (pch_udc_read_ep_control(ep) & UDC_EPCTL_P) + return; + + if (list_empty(&ep->queue)) + return; + + /* next request */ + req = list_entry(ep->queue.next, struct pch_udc_request, queue); + if (req->dma_going) + return; + + dev_dbg(&dev->pdev->dev, "%s: Set request: req=%p req->td_data=%p", + __func__, req, req->td_data); + if (!req->td_data) + return; + + while (pch_udc_read_ep_control(ep) & UDC_EPCTL_S) + udelay(100);
Again. What if condition never gets true?
+ req->dma_going = 1; + /* Clear the descriptor pointer */ + pch_udc_ep_set_ddptr(ep, 0); + + td_data = req->td_data; + while (1) { + td_data->status = (td_data->status & ~PCH_UDC_BUFF_STS) | + PCH_UDC_BS_HST_RDY; + if ((td_data->status & PCH_UDC_DMA_LAST) == PCH_UDC_DMA_LAST) + break; + td_data = phys_to_virt(td_data->next); + } + /* Write the descriptor pointer */ + pch_udc_ep_set_ddptr(ep, req->td_data_phys); + pch_udc_set_dma(ep->dev, DMA_DIR_TX); + /* Set the poll demand bit */ + pch_udc_ep_set_pd(ep); + pch_udc_enable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num)); + pch_udc_ep_clear_nak(ep); +}
+/** + * pch_udc_pcd_reinit() - This API initializes the endpoint structures + * @dev: Reference to the driver structure + */ +static void pch_udc_pcd_reinit(struct pch_udc_dev *dev) +{ + const char *const ep_string[] = { + ep0_string, "ep0out", "ep1in", "ep1out", "ep2in", "ep2out", + "ep3in", "ep3out", "ep4in", "ep4out", "ep5in", "ep5out", + "ep6in", "ep6out", "ep7in", "ep7out", "ep8in", "ep8out", + "ep9in", "ep9out", "ep10in", "ep10out", "ep11in", "ep11out", + "ep12in", "ep12out", "ep13in", "ep13out", "ep14in", "ep14out", + "ep15in", "ep15out", + }; + int i; + + dev->gadget.speed = USB_SPEED_UNKNOWN; + INIT_LIST_HEAD(&dev->gadget.ep_list); + + /* Initialize the endpoints structures */ + for (i = 0; i < PCH_UDC_EP_NUM; i++) { + struct pch_udc_ep *ep = &dev->ep[i]; + memset(ep, 0, sizeof(*ep));
Why not just "memset(dev->ep, 0, sizeof dev->ep);" before the loop?
+ + ep->desc = NULL;
Useless. This has already been set by memset().
+ ep->dev = dev; + ep->halted = 1; + ep->num = i / 2; + ep->in = ((i & 1) == 0) ? 1 : 0;
Or "ep->in = ~i & 1;".
+ + ep->ep.name = ep_string[i]; + ep->ep.ops = &pch_udc_ep_ops; + if (ep->in) + ep->offset_addr = ep->num * UDC_EP_REG_OFS; + else + ep->offset_addr = (UDC_EPINT_OUT_OFS + ep->num) * + UDC_EP_REG_OFS; + /* need to set ep->ep.maxpacket and set Default Configuration?*/ + ep->ep.maxpacket = UDC_BULK_MAX_PKT_SIZE; + list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); + INIT_LIST_HEAD(&ep->queue); + } + dev->ep[UDC_EP0IN_IDX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE; + dev->ep[UDC_EP0OUT_IDX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE; + + dev->dma_addr = pci_map_single(dev->pdev, dev->ep0out_buf, 256, + PCI_DMA_FROMDEVICE); + + /* remove ep0 in and out from the list. They have own pointer */ + list_del_init(&dev->ep[UDC_EP0IN_IDX].ep.ep_list); + list_del_init(&dev->ep[UDC_EP0OUT_IDX].ep.ep_list); + + dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IDX].ep; + INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); +}
+static int init_dma_pools(struct pch_udc_dev *dev) +{ + struct pch_udc_stp_dma_desc *td_stp; + struct pch_udc_data_dma_desc *td_data; + + /* DMA setup */ + dev->data_requests = pci_pool_create("data_requests", dev->pdev, + sizeof(struct pch_udc_data_dma_desc), 0, 0); + if (!dev->data_requests) { + dev_err(&dev->pdev->dev, "%s: can't get request data pool", + __func__); + return -ENOMEM; + } + + /* dma desc for setup data */ + dev->stp_requests = pci_pool_create("setup requests", dev->pdev, + sizeof(struct pch_udc_stp_dma_desc), 0, 0); + if (!dev->stp_requests) {
Why dev->data_requests? Something that has been created needs to be destroyed during error recovery.
+ dev_err(&dev->pdev->dev, "%s: can't get setup request pool", + __func__); + return -ENOMEM; + } + /* setup */ + td_stp = pci_pool_alloc(dev->stp_requests, GFP_KERNEL, + &dev->ep[UDC_EP0OUT_IDX].td_stp_phys); + if (!td_stp) { + dev_err(&dev->pdev->dev, + "%s: can't allocate setup dma descriptor", __func__);
Same here.
+ return -ENOMEM; + } + dev->ep[UDC_EP0OUT_IDX].td_stp = td_stp; + + /* data: 0 packets !? */ + td_data = pci_pool_alloc(dev->data_requests, GFP_KERNEL, + &dev->ep[UDC_EP0OUT_IDX].td_data_phys); + if (!td_data) {
And here.
+ dev_err(&dev->pdev->dev, + "%s: can't allocate data dma descriptor", __func__); + return -ENOMEM; + } + dev->ep[UDC_EP0OUT_IDX].td_data = td_data; + dev->ep[UDC_EP0IN_IDX].td_stp = NULL; + dev->ep[UDC_EP0IN_IDX].td_stp_phys = 0; + dev->ep[UDC_EP0IN_IDX].td_data = NULL; + dev->ep[UDC_EP0IN_IDX].td_data_phys = 0; + return 0; +} +
+static void pch_udc_remove(struct pci_dev *pdev) +{ + struct pch_udc_dev *dev = pci_get_drvdata(pdev); + + dev_dbg(&pdev->dev, "%s: enter", __func__); + /* gadget driver must not be registered */ + if (dev->driver) + dev_err(&pdev->dev, + "%s: gadget driver still bound!!!", __func__); + /* dma pool cleanup */ + if (dev->data_requests) + pci_pool_destroy(dev->data_requests); + + if (dev->stp_requests) { + /* cleanup DMA desc's for ep0in */ + if (dev->ep[UDC_EP0OUT_IDX].td_stp) { + pci_pool_free(dev->stp_requests, + dev->ep[UDC_EP0OUT_IDX].td_stp, + dev->ep[UDC_EP0OUT_IDX].td_stp_phys); + } + if (dev->ep[UDC_EP0OUT_IDX].td_data) { + pci_pool_free(dev->stp_requests, + dev->ep[UDC_EP0OUT_IDX].td_data, + dev->ep[UDC_EP0OUT_IDX].td_data_phys); + } + pci_pool_destroy(dev->stp_requests); + } + + pch_udc_exit(dev); + + if (dev->irq_registered) + free_irq(pdev->irq, dev); + if (dev->base_addr) + iounmap(dev->base_addr); + if (dev->mem_region) + release_mem_region(dev->phys_addr, + pci_resource_len(pdev, PCH_UDC_PCI_BAR)); + if (dev->active) + pci_disable_device(pdev); + if (dev->registered) + device_unregister(&dev->gadget.dev); + else + kfree(dev);
Really? kfree(dev) in "else" clause?
+ + pci_set_drvdata(pdev, NULL); +}
-- Best regards, _ _ | Humble Liege of Serenely Enlightened Majesty of o' \,=./ `o | Computer Science, MichaÅ "mina86" Nazarewicz (o o) +----[mina86*mina86.com]---[mina86*jabber.org]----ooO--(_)--Ooo-- -- 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