[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-id: <op.vjbo81dq7p4s8u@pikus>
Date: Mon, 20 Sep 2010 10:44:51 +0200
From: Michał Nazarewicz <m.nazarewicz@...sung.com>
To: Maurus Cuelenaere <mcuelenaere@...il.com>,
linux-usb <linux-usb@...r.kernel.org>,
Masayuki Ohtake <masa-korg@....okisemi.com>
Cc: Toshiharu Okada <okada533@....okisemi.com>,
Takahiro Shimizu <shimizu394@....okisemi.com>,
Tomoya Morinaga <morinaga526@....okisemi.com>,
MeeGo <meego-dev@...go.com>, LKML <linux-kernel@...r.kernel.org>,
"Wang, Qi" <qi.wang@...el.com>,
"Wang, Yong Y" <yong.y.wang@...el.com>,
Andrew <andrew.chih.howe.khor@...el.com>,
Intel OTC <joel.clark@...el.com>,
"Foster, Margie" <margie.foster@...el.com>,
Arjan <arjan@...ux.intel.com>
Subject: Re: [PATCH v3] USB device driver of Topcliff PCH
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@....okisemi.com> 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@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists