Re: [PATCH v3] USB device driver of Topcliff PCH

From: MichaÅ Nazarewicz
Date: Mon Sep 20 2010 - 04:43:10 EST


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-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/