RE: [PATCH] usb:musb: Dequeue urbs on device unplug

2012-10-21 Thread Virupax SADASHIVPETIMATH


> -Original Message-
> From: Felipe Balbi [mailto:ba...@ti.com]
> Sent: Monday, October 15, 2012 5:49 PM
> To: Virupax SADASHIVPETIMATH
> Cc: ba...@ti.com; st...@rowland.harvard.edu; linux-...@vger.kernel.org;
> linux-kernel@vger.kernel.org; linus.wall...@linaro.org; Rajaram REGUPATHY;
> Praveena NADAHALLY
> Subject: Re: [PATCH] usb:musb: Dequeue urbs on device unplug
> 
> Hi,
> 
> On Wed, Oct 10, 2012 at 10:06:03AM +0530, Virupax Sadashivpetimath wrote:
> > Flush queued urbs on receiving device disconnect interrupt. This is
> > required for successful disconnect and successive enumeration of the
> > device.
> >
> > In a failure case khubd hangs on usb-storage thread for completion.
> > Seen in the below trace.
> >
> > [ 1355.764526] SysRq : Show Blocked State
> > [ 1355.768341]   taskPC stack   pid father
> > [ 1355.773620] khubd   D c06a1fbc 0   503  2 0x
> > [ 1355.780151] [] (__schedule+0x3f0/0x8ec) from []
> > (schedule+0x58/0x70) [ 1355.788330] [] (schedule+0x58/0x70)
> > from [] (schedule_timeout+0x1d8/0x31c) [ 1355.796997]
> > [] (schedule_timeout+0x1d8/0x31c) from []
> > (wait_for_common+0xd8/0x180) [ 1355.806396] []
> > (wait_for_common+0xd8/0x180) from []
> > (wait_for_completion+0x20/0x24) [ 1355.815887] []
> I would like to get some Tested-bys here.

Can you please add 

Tested-by: 

Thanks 
Virupax S 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH] usb:musb: Dequeue urbs on device unplug

2012-10-21 Thread Virupax SADASHIVPETIMATH


 -Original Message-
 From: Felipe Balbi [mailto:ba...@ti.com]
 Sent: Monday, October 15, 2012 5:49 PM
 To: Virupax SADASHIVPETIMATH
 Cc: ba...@ti.com; st...@rowland.harvard.edu; linux-...@vger.kernel.org;
 linux-kernel@vger.kernel.org; linus.wall...@linaro.org; Rajaram REGUPATHY;
 Praveena NADAHALLY
 Subject: Re: [PATCH] usb:musb: Dequeue urbs on device unplug
 
 Hi,
 
 On Wed, Oct 10, 2012 at 10:06:03AM +0530, Virupax Sadashivpetimath wrote:
  Flush queued urbs on receiving device disconnect interrupt. This is
  required for successful disconnect and successive enumeration of the
  device.
 
  In a failure case khubd hangs on usb-storage thread for completion.
  Seen in the below trace.
 
  [ 1355.764526] SysRq : Show Blocked State
  [ 1355.768341]   taskPC stack   pid father
  [ 1355.773620] khubd   D c06a1fbc 0   503  2 0x
  [ 1355.780151] [c06a1fbc] (__schedule+0x3f0/0x8ec) from [c06a26a0]
  (schedule+0x58/0x70) [ 1355.788330] [c06a26a0] (schedule+0x58/0x70)
  from [c06a2af8] (schedule_timeout+0x1d8/0x31c) [ 1355.796997]
  [c06a2af8] (schedule_timeout+0x1d8/0x31c) from [c06a1994]
  (wait_for_common+0xd8/0x180) [ 1355.806396] [c06a1994]
  (wait_for_common+0xd8/0x180) from [c06a1b14]
  (wait_for_completion+0x20/0x24) [ 1355.815887] [c06a1b14]
 I would like to get some Tested-bys here.

Can you please add 

Tested-by: shuai@stericsson.com

Thanks 
Virupax S 
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] usb:musb: Dequeue urbs on device unplug

2012-10-09 Thread Virupax Sadashivpetimath
Flush queued urbs on receiving device disconnect
interrupt. This is required for successful disconnect
and successive enumeration of the device.

In a failure case khubd hangs on usb-storage thread
for completion. Seen in the below trace.

[ 1355.764526] SysRq : Show Blocked State
[ 1355.768341]   taskPC stack   pid father
[ 1355.773620] khubd   D c06a1fbc 0   503  2 0x
[ 1355.780151] [] (__schedule+0x3f0/0x8ec) from [] 
(schedule+0x58/0x70)
[ 1355.788330] [] (schedule+0x58/0x70) from [] 
(schedule_timeout+0x1d8/0x31c)
[ 1355.796997] [] (schedule_timeout+0x1d8/0x31c) from [] 
(wait_for_common+0xd8/0x180)
[ 1355.806396] [] (wait_for_common+0xd8/0x180) from [] 
(wait_for_completion+0x20/0x24)
[ 1355.815887] [] (wait_for_completion+0x20/0x24) from [] 
(kthread_stop+0x68/0x17c)
[ 1355.825103] [] (kthread_stop+0x68/0x17c) from [] 
(release_everything+0x30/0x8c)
[ 1355.834228] [] (release_everything+0x30/0x8c) from [] 
(usb_stor_disconnect+0x2c/0x30)
[ 1355.843902] [] (usb_stor_disconnect+0x2c/0x30) from [] 
(usb_unbind_interface+0x60/0x1e0)
[ 1355.853820] [] (usb_unbind_interface+0x60/0x1e0) from [] 
(__device_release_driver+0x80/0xd0)
[ 1355.864074] [] (__device_release_driver+0x80/0xd0) from 
[] (device_release_driver+0x2c/0x38)
[ 1355.874359] [] (device_release_driver+0x2c/0x38) from [] 
(bus_remove_device+0xbc/0x10c)
[ 1355.884155] [] (bus_remove_device+0xbc/0x10c) from [] 
(device_del+0x108/0x17c)
[ 1355.893188] [] (device_del+0x108/0x17c) from [] 
(usb_disable_device+0xbc/0x200)
[ 1355.902313] [] (usb_disable_device+0xbc/0x200) from [] 
(usb_disconnect+0xb8/0x194)
[ 1355.911682] [] (usb_disconnect+0xb8/0x194) from [] 
(hub_thread+0x45c/0x14b0)
[ 1355.920562] [] (hub_thread+0x45c/0x14b0) from [] 
(kthread+0x98/0xa0)
[ 1355.928710] [] (kthread+0x98/0xa0) from [] 
(kernel_thread_exit+0x0/0x8)
[ 1356.014373] usb-storage D c06a1fbc 0  2379  2 0x
[ 1356.020843] [] (__schedule+0x3f0/0x8ec) from [] 
(schedule+0x58/0x70)
[ 1356.029022] [] (schedule+0x58/0x70) from [] 
(schedule_timeout+0x1d8/0x31c)
[ 1356.037719] [] (schedule_timeout+0x1d8/0x31c) from [] 
(wait_for_common+0xd8/0x180)
[ 1356.047088] [] (wait_for_common+0xd8/0x180) from [] 
(wait_for_completion+0x20/0x24)
[ 1356.056549] [] (wait_for_completion+0x20/0x24) from [] 
(usb_sg_wait+0x108/0x194)
[ 1356.065795] [] (usb_sg_wait+0x108/0x194) from [] 
(usb_stor_bulk_transfer_sglist+0x9c/0xf4)
[ 1356.075866] [] (usb_stor_bulk_transfer_sglist+0x9c/0xf4) from 
[] (usb_stor_bulk_srb+0x38/0x50)
[ 1356.086303] [] (usb_stor_bulk_srb+0x38/0x50) from [] 
(usb_stor_Bulk_transport+0x114/0x2d0)
[ 1356.096374] [] (usb_stor_Bulk_transport+0x114/0x2d0) from 
[] (usb_stor_invoke_transport+0x34/0x3f4)
[ 1356.107238] [] (usb_stor_invoke_transport+0x34/0x3f4) from 
[] (usb_stor_transparent_scsi_command+0x18/0x1c)
[ 1356.118804] [] (usb_stor_transparent_scsi_command+0x18/0x1c) from 
[] (usb_stor_control_thread+0x190/0x28c)
[ 1356.130279] [] (usb_stor_control_thread+0x190/0x28c) from 
[] (kthread+0x98/0xa0)
[ 1356.139465] [] (kthread+0x98/0xa0) from [] 
(kernel_thread_exit+0x0/0x8)

Signed-off-by: Virupax Sadashivpetimath 

Acked-by: Linus Walleij 
---
 drivers/usb/musb/musb_core.c |   37 +
 drivers/usb/musb/musb_host.c |3 +++
 2 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index bb56a0e..fc6e990 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -414,6 +414,41 @@ static void musb_otg_timer_func(unsigned long data)
spin_unlock_irqrestore(>lock, flags);
 }
 
+void musb_handle_disconnect(struct musb *musb)
+{
+   int epnum, i;
+   struct urb  *urb;
+   struct musb_hw_ep   *hw_ep;
+   struct musb_qh  *qh;
+   struct usb_hcd *hcd = musb_to_hcd(musb);
+
+   for (epnum = 0; epnum < musb->config->num_eps;
+   epnum++) {
+   hw_ep = musb->endpoints + epnum;
+   for (i = 0; i < 2; i++) {
+   if (hw_ep->in_qh == hw_ep->out_qh)
+   i++;
+   qh = (i == 0) ? hw_ep->in_qh : hw_ep->out_qh;
+
+   if (qh && qh->hep) {
+   qh->is_ready = 0;
+   while ((urb = next_urb(qh))) {
+   usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+   spin_unlock(>lock);
+   usb_hcd_giveback_urb(hcd, urb, 0);
+   spin_lock(>lock);
+   }
+
+   qh->hep->hcpriv = NULL;
+   list_del(>ring);
+   kfree(qh);
+   

[PATCH] usb:musb: Dequeue urbs on device unplug

2012-10-09 Thread Virupax Sadashivpetimath
Flush queued urbs on receiving device disconnect
interrupt. This is required for successful disconnect
and successive enumeration of the device.

In a failure case khubd hangs on usb-storage thread
for completion. Seen in the below trace.

[ 1355.764526] SysRq : Show Blocked State
[ 1355.768341]   taskPC stack   pid father
[ 1355.773620] khubd   D c06a1fbc 0   503  2 0x
[ 1355.780151] [c06a1fbc] (__schedule+0x3f0/0x8ec) from [c06a26a0] 
(schedule+0x58/0x70)
[ 1355.788330] [c06a26a0] (schedule+0x58/0x70) from [c06a2af8] 
(schedule_timeout+0x1d8/0x31c)
[ 1355.796997] [c06a2af8] (schedule_timeout+0x1d8/0x31c) from [c06a1994] 
(wait_for_common+0xd8/0x180)
[ 1355.806396] [c06a1994] (wait_for_common+0xd8/0x180) from [c06a1b14] 
(wait_for_completion+0x20/0x24)
[ 1355.815887] [c06a1b14] (wait_for_completion+0x20/0x24) from [c00b9998] 
(kthread_stop+0x68/0x17c)
[ 1355.825103] [c00b9998] (kthread_stop+0x68/0x17c) from [c039e0e0] 
(release_everything+0x30/0x8c)
[ 1355.834228] [c039e0e0] (release_everything+0x30/0x8c) from [c039e168] 
(usb_stor_disconnect+0x2c/0x30)
[ 1355.843902] [c039e168] (usb_stor_disconnect+0x2c/0x30) from [c038e3a8] 
(usb_unbind_interface+0x60/0x1e0)
[ 1355.853820] [c038e3a8] (usb_unbind_interface+0x60/0x1e0) from [c031dcc0] 
(__device_release_driver+0x80/0xd0)
[ 1355.864074] [c031dcc0] (__device_release_driver+0x80/0xd0) from 
[c031ddfc] (device_release_driver+0x2c/0x38)
[ 1355.874359] [c031ddfc] (device_release_driver+0x2c/0x38) from [c031d0d8] 
(bus_remove_device+0xbc/0x10c)
[ 1355.884155] [c031d0d8] (bus_remove_device+0xbc/0x10c) from [c031b63c] 
(device_del+0x108/0x17c)
[ 1355.893188] [c031b63c] (device_del+0x108/0x17c) from [c038afe8] 
(usb_disable_device+0xbc/0x200)
[ 1355.902313] [c038afe8] (usb_disable_device+0xbc/0x200) from [c0384c58] 
(usb_disconnect+0xb8/0x194)
[ 1355.911682] [c0384c58] (usb_disconnect+0xb8/0x194) from [c0385e58] 
(hub_thread+0x45c/0x14b0)
[ 1355.920562] [c0385e58] (hub_thread+0x45c/0x14b0) from [c00b97e0] 
(kthread+0x98/0xa0)
[ 1355.928710] [c00b97e0] (kthread+0x98/0xa0) from [c0064834] 
(kernel_thread_exit+0x0/0x8)
[ 1356.014373] usb-storage D c06a1fbc 0  2379  2 0x
[ 1356.020843] [c06a1fbc] (__schedule+0x3f0/0x8ec) from [c06a26a0] 
(schedule+0x58/0x70)
[ 1356.029022] [c06a26a0] (schedule+0x58/0x70) from [c06a2af8] 
(schedule_timeout+0x1d8/0x31c)
[ 1356.037719] [c06a2af8] (schedule_timeout+0x1d8/0x31c) from [c06a1994] 
(wait_for_common+0xd8/0x180)
[ 1356.047088] [c06a1994] (wait_for_common+0xd8/0x180) from [c06a1b14] 
(wait_for_completion+0x20/0x24)
[ 1356.056549] [c06a1b14] (wait_for_completion+0x20/0x24) from [c038b5dc] 
(usb_sg_wait+0x108/0x194)
[ 1356.065795] [c038b5dc] (usb_sg_wait+0x108/0x194) from [c039d6dc] 
(usb_stor_bulk_transfer_sglist+0x9c/0xf4)
[ 1356.075866] [c039d6dc] (usb_stor_bulk_transfer_sglist+0x9c/0xf4) from 
[c039d76c] (usb_stor_bulk_srb+0x38/0x50)
[ 1356.086303] [c039d76c] (usb_stor_bulk_srb+0x38/0x50) from [c039d92c] 
(usb_stor_Bulk_transport+0x114/0x2d0)
[ 1356.096374] [c039d92c] (usb_stor_Bulk_transport+0x114/0x2d0) from 
[c039d190] (usb_stor_invoke_transport+0x34/0x3f4)
[ 1356.107238] [c039d190] (usb_stor_invoke_transport+0x34/0x3f4) from 
[c039cc0c] (usb_stor_transparent_scsi_command+0x18/0x1c)
[ 1356.118804] [c039cc0c] (usb_stor_transparent_scsi_command+0x18/0x1c) from 
[c039f144] (usb_stor_control_thread+0x190/0x28c)
[ 1356.130279] [c039f144] (usb_stor_control_thread+0x190/0x28c) from 
[c00b97e0] (kthread+0x98/0xa0)
[ 1356.139465] [c00b97e0] (kthread+0x98/0xa0) from [c0064834] 
(kernel_thread_exit+0x0/0x8)

Signed-off-by: Virupax Sadashivpetimath 
virupax.sadashivpetim...@stericsson.com
Acked-by: Linus Walleij linus.wall...@linaro.org
---
 drivers/usb/musb/musb_core.c |   37 +
 drivers/usb/musb/musb_host.c |3 +++
 2 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index bb56a0e..fc6e990 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -414,6 +414,41 @@ static void musb_otg_timer_func(unsigned long data)
spin_unlock_irqrestore(musb-lock, flags);
 }
 
+void musb_handle_disconnect(struct musb *musb)
+{
+   int epnum, i;
+   struct urb  *urb;
+   struct musb_hw_ep   *hw_ep;
+   struct musb_qh  *qh;
+   struct usb_hcd *hcd = musb_to_hcd(musb);
+
+   for (epnum = 0; epnum  musb-config-num_eps;
+   epnum++) {
+   hw_ep = musb-endpoints + epnum;
+   for (i = 0; i  2; i++) {
+   if (hw_ep-in_qh == hw_ep-out_qh)
+   i++;
+   qh = (i == 0) ? hw_ep-in_qh : hw_ep-out_qh;
+
+   if (qh  qh-hep) {
+   qh-is_ready = 0;
+   while ((urb = next_urb(qh

[PATCH v3] usb:musb:musb_host: Handle highmem in PIO mode

2012-08-08 Thread Virupax Sadashivpetimath
In case of USB bulk transfer, when himem page
is received, the usb_sg_init function sets the
urb transfer buffer to NULL. When such URB
transfer is handled, kernel crashes in PIO mode.
Handle this by mapping the highmem buffer in PIO mode.

Signed-off-by: Virupax Sadashivpetimath 

Signed-off-by: Praveena NADAHALLY 
Acked-by: Linus Walleij 
---
 drivers/usb/musb/musb_host.c |   97 +++--
 drivers/usb/musb/musb_host.h |3 +
 2 files changed, 95 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 4bb717d..3ba9a4b 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -813,9 +813,28 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
if (load_count) {
/* PIO to load FIFO */
qh->segsize = load_count;
-   musb_write_fifo(hw_ep, load_count, buf);
+   if (!buf) {
+   sg_miter_start(>sg_miter, urb->sg, 1,
+   SG_MITER_ATOMIC
+   | SG_MITER_FROM_SG);
+   if (!sg_miter_next(>sg_miter)) {
+   dev_err(musb->controller,
+   "error: sg"
+   "list empty\n");
+   sg_miter_stop(>sg_miter);
+   goto finish;
+   }
+   buf = qh->sg_miter.addr + urb->sg->offset +
+   urb->actual_length;
+   load_count = min_t(u32, load_count,
+   qh->sg_miter.length);
+   musb_write_fifo(hw_ep, load_count, buf);
+   qh->sg_miter.consumed = load_count;
+   sg_miter_stop(>sg_miter);
+   } else
+   musb_write_fifo(hw_ep, load_count, buf);
}
-
+finish:
/* re-enable interrupt */
musb_writew(mbase, MUSB_INTRTXE, int_txe);
 
@@ -1116,6 +1135,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
void __iomem*mbase = musb->mregs;
struct dma_channel  *dma;
booltransfer_pending = false;
+   static bool use_sg;
 
musb_ep_select(mbase, epnum);
tx_csr = musb_readw(epio, MUSB_TXCSR);
@@ -1163,6 +1183,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
return;
}
 
+done:
if (status) {
if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
dma->status = MUSB_DMA_STATUS_CORE_ABORT;
@@ -1332,9 +1353,37 @@ void musb_host_tx(struct musb *musb, u8 epnum)
length = qh->maxpacket;
/* Unmap the buffer so that CPU can use it */
usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb);
-   musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset);
+
+   /*
+* We need to map sg if the transfer_buffer is
+* NULL.
+*/
+   if (!use_sg && !urb->transfer_buffer)
+   use_sg = true;
+
+   if (use_sg) {
+   /* sg_miter_start is already done in musb_ep_program */
+   if (!sg_miter_next(>sg_miter)) {
+   dev_err(musb->controller, "error: sg list empty\n");
+   sg_miter_stop(>sg_miter);
+   status = -EINVAL;
+   goto done;
+   }
+   length = min_t(u32, length, qh->sg_miter.length);
+   musb_write_fifo(hw_ep, length, qh->sg_miter.addr);
+   qh->sg_miter.consumed = length;
+   sg_miter_stop(>sg_miter);
+   } else {
+   musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset);
+   }
+
qh->segsize = length;
 
+   if (use_sg) {
+   if (offset + length >= urb->transfer_buffer_length)
+   use_sg = false;
+   }
+
musb_ep_select(mbase, epnum);
musb_writew(epio, MUSB_TXCSR,
MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
@@ -1442,6 +1491,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
booldone = false;
u32 status;
struct dma_channel  *dma;
+   static bool use_sg;
+   unsigned int sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG;
 
musb_ep_select(mbase, epnum);
 
@@ -1756,10 +1807,43 @@ void musb_host_rx(struct musb *musb, u8 epnum)
 #endif /* Mentor DMA */
 
   

RE: [PATCH v2] usb:musb:musb_host: Handle highmem in PIO mode

2012-08-08 Thread Virupax SADASHIVPETIMATH


> -Original Message-
> From: Alan Stern [mailto:st...@rowland.harvard.edu]
> Sent: Tuesday, August 07, 2012 11:17 PM
> To: Virupax SADASHIVPETIMATH
> Cc: ba...@ti.com; gre...@linuxfoundation.org; linux-...@vger.kernel.org; 
> linux-
> ker...@vger.kernel.org; linus.wall...@linaro.org; Praveena NADAHALLY; Rajaram
> REGUPATHY; Vikrant BAPAT
> Subject: Re: [PATCH v2] usb:musb:musb_host: Handle highmem in PIO mode
> 
> 
> > +*/
> > +   if (!urb->transfer_buffer)
> > +   use_sg = true;
> 
> Here you test urb->transfer_buffer.

I will make the test as 
if (!use_sg && !urb->transfer_buffer)
use_sg = true;

> > +   if (use_sg) {
> > +   /* sg_miter_start is already done in musb_ep_program */
> > +   if (!sg_miter_next(>sg_miter)) {
> > +   dev_err(musb->controller, "error: sg list empty\n");
> > +   sg_miter_stop(>sg_miter);
> > +   status = -EINVAL;
> > +   goto done;
> > +   }
> > +   urb->transfer_buffer = qh->sg_miter.addr;
> 
> And here you set it.  As a result, on the next iteration of this
> routine the test above won't work right.  (This function gets invoked
> once for each entry in the sg list, right?)
> 
> Is there any reason to set urb->transfer_buffer here?  You could just
> use qh->sg_miter.addr directly in the musb_write_fifo() call two lines
> below.

I will change it. 

Thanks 
Virupax S 


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH v2] usb:musb:musb_host: Handle highmem in PIO mode

2012-08-08 Thread Virupax SADASHIVPETIMATH


 -Original Message-
 From: Alan Stern [mailto:st...@rowland.harvard.edu]
 Sent: Tuesday, August 07, 2012 11:17 PM
 To: Virupax SADASHIVPETIMATH
 Cc: ba...@ti.com; gre...@linuxfoundation.org; linux-...@vger.kernel.org; 
 linux-
 ker...@vger.kernel.org; linus.wall...@linaro.org; Praveena NADAHALLY; Rajaram
 REGUPATHY; Vikrant BAPAT
 Subject: Re: [PATCH v2] usb:musb:musb_host: Handle highmem in PIO mode
 
 
  +*/
  +   if (!urb-transfer_buffer)
  +   use_sg = true;
 
 Here you test urb-transfer_buffer.

I will make the test as 
if (!use_sg  !urb-transfer_buffer)
use_sg = true;

  +   if (use_sg) {
  +   /* sg_miter_start is already done in musb_ep_program */
  +   if (!sg_miter_next(qh-sg_miter)) {
  +   dev_err(musb-controller, error: sg list empty\n);
  +   sg_miter_stop(qh-sg_miter);
  +   status = -EINVAL;
  +   goto done;
  +   }
  +   urb-transfer_buffer = qh-sg_miter.addr;
 
 And here you set it.  As a result, on the next iteration of this
 routine the test above won't work right.  (This function gets invoked
 once for each entry in the sg list, right?)
 
 Is there any reason to set urb-transfer_buffer here?  You could just
 use qh-sg_miter.addr directly in the musb_write_fifo() call two lines
 below.

I will change it. 

Thanks 
Virupax S 


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v3] usb:musb:musb_host: Handle highmem in PIO mode

2012-08-08 Thread Virupax Sadashivpetimath
In case of USB bulk transfer, when himem page
is received, the usb_sg_init function sets the
urb transfer buffer to NULL. When such URB
transfer is handled, kernel crashes in PIO mode.
Handle this by mapping the highmem buffer in PIO mode.

Signed-off-by: Virupax Sadashivpetimath 
virupax.sadashivpetim...@stericsson.com
Signed-off-by: Praveena NADAHALLY praveen.nadaha...@stericsson.com
Acked-by: Linus Walleij linus.wall...@linaro.org
---
 drivers/usb/musb/musb_host.c |   97 +++--
 drivers/usb/musb/musb_host.h |3 +
 2 files changed, 95 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 4bb717d..3ba9a4b 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -813,9 +813,28 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
if (load_count) {
/* PIO to load FIFO */
qh-segsize = load_count;
-   musb_write_fifo(hw_ep, load_count, buf);
+   if (!buf) {
+   sg_miter_start(qh-sg_miter, urb-sg, 1,
+   SG_MITER_ATOMIC
+   | SG_MITER_FROM_SG);
+   if (!sg_miter_next(qh-sg_miter)) {
+   dev_err(musb-controller,
+   error: sg
+   list empty\n);
+   sg_miter_stop(qh-sg_miter);
+   goto finish;
+   }
+   buf = qh-sg_miter.addr + urb-sg-offset +
+   urb-actual_length;
+   load_count = min_t(u32, load_count,
+   qh-sg_miter.length);
+   musb_write_fifo(hw_ep, load_count, buf);
+   qh-sg_miter.consumed = load_count;
+   sg_miter_stop(qh-sg_miter);
+   } else
+   musb_write_fifo(hw_ep, load_count, buf);
}
-
+finish:
/* re-enable interrupt */
musb_writew(mbase, MUSB_INTRTXE, int_txe);
 
@@ -1116,6 +1135,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
void __iomem*mbase = musb-mregs;
struct dma_channel  *dma;
booltransfer_pending = false;
+   static bool use_sg;
 
musb_ep_select(mbase, epnum);
tx_csr = musb_readw(epio, MUSB_TXCSR);
@@ -1163,6 +1183,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
return;
}
 
+done:
if (status) {
if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
dma-status = MUSB_DMA_STATUS_CORE_ABORT;
@@ -1332,9 +1353,37 @@ void musb_host_tx(struct musb *musb, u8 epnum)
length = qh-maxpacket;
/* Unmap the buffer so that CPU can use it */
usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb);
-   musb_write_fifo(hw_ep, length, urb-transfer_buffer + offset);
+
+   /*
+* We need to map sg if the transfer_buffer is
+* NULL.
+*/
+   if (!use_sg  !urb-transfer_buffer)
+   use_sg = true;
+
+   if (use_sg) {
+   /* sg_miter_start is already done in musb_ep_program */
+   if (!sg_miter_next(qh-sg_miter)) {
+   dev_err(musb-controller, error: sg list empty\n);
+   sg_miter_stop(qh-sg_miter);
+   status = -EINVAL;
+   goto done;
+   }
+   length = min_t(u32, length, qh-sg_miter.length);
+   musb_write_fifo(hw_ep, length, qh-sg_miter.addr);
+   qh-sg_miter.consumed = length;
+   sg_miter_stop(qh-sg_miter);
+   } else {
+   musb_write_fifo(hw_ep, length, urb-transfer_buffer + offset);
+   }
+
qh-segsize = length;
 
+   if (use_sg) {
+   if (offset + length = urb-transfer_buffer_length)
+   use_sg = false;
+   }
+
musb_ep_select(mbase, epnum);
musb_writew(epio, MUSB_TXCSR,
MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
@@ -1442,6 +1491,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
booldone = false;
u32 status;
struct dma_channel  *dma;
+   static bool use_sg;
+   unsigned int sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG;
 
musb_ep_select(mbase, epnum);
 
@@ -1756,10 +1807,43 @@ void musb_host_rx(struct musb *musb, u8 epnum)
 #endif /* Mentor DMA */
 
if (!dma) {
+   unsigned int

[PATCH v2] usb:musb:musb_host: Handle highmem in PIO mode

2012-08-07 Thread Virupax Sadashivpetimath
In case of USB bulk transfer, when himem page
is received, the usb_sg_init function sets the
urb transfer buffer to NULL. When such URB
transfer is handled, kernel crashes in PIO mode.
Handle this by mapping the highmem buffer in PIO mode.

Signed-off-by: Virupax Sadashivpetimath 

Signed-off-by: Praveena NADAHALLY 
Acked-by: Linus Walleij 
---
 drivers/usb/musb/musb_host.c |   98 +++--
 drivers/usb/musb/musb_host.h |3 +
 2 files changed, 96 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 4bb717d..199bf1a 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -813,9 +813,28 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
if (load_count) {
/* PIO to load FIFO */
qh->segsize = load_count;
-   musb_write_fifo(hw_ep, load_count, buf);
+   if (!buf) {
+   sg_miter_start(>sg_miter, urb->sg, 1,
+   SG_MITER_ATOMIC
+   | SG_MITER_FROM_SG);
+   if (!sg_miter_next(>sg_miter)) {
+   dev_err(musb->controller,
+   "error: sg"
+   "list empty\n");
+   sg_miter_stop(>sg_miter);
+   goto finish;
+   }
+   buf = qh->sg_miter.addr + urb->sg->offset +
+   urb->actual_length;
+   load_count = min_t(u32, load_count,
+   qh->sg_miter.length);
+   musb_write_fifo(hw_ep, load_count, buf);
+   qh->sg_miter.consumed = load_count;
+   sg_miter_stop(>sg_miter);
+   } else
+   musb_write_fifo(hw_ep, load_count, buf);
}
-
+finish:
/* re-enable interrupt */
musb_writew(mbase, MUSB_INTRTXE, int_txe);
 
@@ -1116,6 +1135,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
void __iomem*mbase = musb->mregs;
struct dma_channel  *dma;
booltransfer_pending = false;
+   static bool use_sg;
 
musb_ep_select(mbase, epnum);
tx_csr = musb_readw(epio, MUSB_TXCSR);
@@ -1163,6 +1183,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
return;
}
 
+done:
if (status) {
if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
dma->status = MUSB_DMA_STATUS_CORE_ABORT;
@@ -1332,9 +1353,38 @@ void musb_host_tx(struct musb *musb, u8 epnum)
length = qh->maxpacket;
/* Unmap the buffer so that CPU can use it */
usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb);
-   musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset);
+
+   /*
+* We need to map sg if the transfer_buffer is
+* NULL.
+*/
+   if (!urb->transfer_buffer)
+   use_sg = true;
+
+   if (use_sg) {
+   /* sg_miter_start is already done in musb_ep_program */
+   if (!sg_miter_next(>sg_miter)) {
+   dev_err(musb->controller, "error: sg list empty\n");
+   sg_miter_stop(>sg_miter);
+   status = -EINVAL;
+   goto done;
+   }
+   urb->transfer_buffer = qh->sg_miter.addr;
+   length = min_t(u32, length, qh->sg_miter.length);
+   musb_write_fifo(hw_ep, length, urb->transfer_buffer);
+   qh->sg_miter.consumed = length;
+   sg_miter_stop(>sg_miter);
+   } else {
+   musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset);
+   }
+
qh->segsize = length;
 
+   if (use_sg) {
+   if (offset + length >= urb->transfer_buffer_length)
+   use_sg = false;
+   }
+
musb_ep_select(mbase, epnum);
musb_writew(epio, MUSB_TXCSR,
MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
@@ -1442,6 +1492,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
booldone = false;
u32 status;
struct dma_channel  *dma;
+   static bool use_sg;
+   unsigned int sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG;
 
musb_ep_select(mbase, epnum);
 
@@ -1756,10 +1808,43 @@ void musb_host_rx(struct mus

[PATCH v2] usb:musb:musb_host: Handle highmem in PIO mode

2012-08-07 Thread Virupax Sadashivpetimath
In case of USB bulk transfer, when himem page
is received, the usb_sg_init function sets the
urb transfer buffer to NULL. When such URB
transfer is handled, kernel crashes in PIO mode.
Handle this by mapping the highmem buffer in PIO mode.

Signed-off-by: Virupax Sadashivpetimath 
virupax.sadashivpetim...@stericsson.com
Signed-off-by: Praveena NADAHALLY praveen.nadaha...@stericsson.com
Acked-by: Linus Walleij linus.wall...@linaro.org
---
 drivers/usb/musb/musb_host.c |   98 +++--
 drivers/usb/musb/musb_host.h |3 +
 2 files changed, 96 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 4bb717d..199bf1a 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -813,9 +813,28 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
if (load_count) {
/* PIO to load FIFO */
qh-segsize = load_count;
-   musb_write_fifo(hw_ep, load_count, buf);
+   if (!buf) {
+   sg_miter_start(qh-sg_miter, urb-sg, 1,
+   SG_MITER_ATOMIC
+   | SG_MITER_FROM_SG);
+   if (!sg_miter_next(qh-sg_miter)) {
+   dev_err(musb-controller,
+   error: sg
+   list empty\n);
+   sg_miter_stop(qh-sg_miter);
+   goto finish;
+   }
+   buf = qh-sg_miter.addr + urb-sg-offset +
+   urb-actual_length;
+   load_count = min_t(u32, load_count,
+   qh-sg_miter.length);
+   musb_write_fifo(hw_ep, load_count, buf);
+   qh-sg_miter.consumed = load_count;
+   sg_miter_stop(qh-sg_miter);
+   } else
+   musb_write_fifo(hw_ep, load_count, buf);
}
-
+finish:
/* re-enable interrupt */
musb_writew(mbase, MUSB_INTRTXE, int_txe);
 
@@ -1116,6 +1135,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
void __iomem*mbase = musb-mregs;
struct dma_channel  *dma;
booltransfer_pending = false;
+   static bool use_sg;
 
musb_ep_select(mbase, epnum);
tx_csr = musb_readw(epio, MUSB_TXCSR);
@@ -1163,6 +1183,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
return;
}
 
+done:
if (status) {
if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
dma-status = MUSB_DMA_STATUS_CORE_ABORT;
@@ -1332,9 +1353,38 @@ void musb_host_tx(struct musb *musb, u8 epnum)
length = qh-maxpacket;
/* Unmap the buffer so that CPU can use it */
usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb);
-   musb_write_fifo(hw_ep, length, urb-transfer_buffer + offset);
+
+   /*
+* We need to map sg if the transfer_buffer is
+* NULL.
+*/
+   if (!urb-transfer_buffer)
+   use_sg = true;
+
+   if (use_sg) {
+   /* sg_miter_start is already done in musb_ep_program */
+   if (!sg_miter_next(qh-sg_miter)) {
+   dev_err(musb-controller, error: sg list empty\n);
+   sg_miter_stop(qh-sg_miter);
+   status = -EINVAL;
+   goto done;
+   }
+   urb-transfer_buffer = qh-sg_miter.addr;
+   length = min_t(u32, length, qh-sg_miter.length);
+   musb_write_fifo(hw_ep, length, urb-transfer_buffer);
+   qh-sg_miter.consumed = length;
+   sg_miter_stop(qh-sg_miter);
+   } else {
+   musb_write_fifo(hw_ep, length, urb-transfer_buffer + offset);
+   }
+
qh-segsize = length;
 
+   if (use_sg) {
+   if (offset + length = urb-transfer_buffer_length)
+   use_sg = false;
+   }
+
musb_ep_select(mbase, epnum);
musb_writew(epio, MUSB_TXCSR,
MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
@@ -1442,6 +1492,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
booldone = false;
u32 status;
struct dma_channel  *dma;
+   static bool use_sg;
+   unsigned int sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG;
 
musb_ep_select(mbase, epnum);
 
@@ -1756,10 +1808,43 @@ void musb_host_rx(struct musb *musb, u8 epnum)
 #endif /* Mentor DMA

RE: [PATCH] usb:musb:musb_host: Handle highmem in PIO mode

2012-08-03 Thread Virupax SADASHIVPETIMATH


> -Original Message-
> From: Alan Stern [mailto:st...@rowland.harvard.edu]
> Sent: Thursday, August 02, 2012 8:18 PM
> To: Virupax SADASHIVPETIMATH
> Cc: ba...@ti.com; gre...@linuxfoundation.org; linux-...@vger.kernel.org; 
> linux-
> ker...@vger.kernel.org; Praveena NADAHALLY
> Subject: Re: [PATCH] usb:musb:musb_host: Handle highmem in PIO mode
> 
 
> > --- a/include/linux/usb.h
> > +++ b/include/linux/usb.h
> > @@ -21,6 +21,7 @@
> >  #include/* for current && schedule_timeout */
> >  #include/* for struct mutex */
> >  #include   /* for runtime PM */
> > +#include 
> >
> >  struct usb_device;
> >  struct usb_driver;
> > @@ -1309,6 +1310,7 @@ struct urb {
> > usb_complete_t complete;/* (in) completion routine */
> > struct usb_iso_packet_descriptor iso_frame_desc[0];
> > /* (in) ISO ONLY */
> > +   struct sg_mapping_iter sg_miter; /* handling highmem data in PIO mode */
> >  };
> 
> This is unacceptable.  Fields like this should be stored in the
> URB's hcpriv structure, not in the URB itself.

Ok I will add it in the hcpriv structure. Can you please comment on other
 part of the code also, so that all the changes can be done together. 

Thanks 
Virupax S 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH] usb:musb:musb_host: Handle highmem in PIO mode

2012-08-03 Thread Virupax SADASHIVPETIMATH


 -Original Message-
 From: Alan Stern [mailto:st...@rowland.harvard.edu]
 Sent: Thursday, August 02, 2012 8:18 PM
 To: Virupax SADASHIVPETIMATH
 Cc: ba...@ti.com; gre...@linuxfoundation.org; linux-...@vger.kernel.org; 
 linux-
 ker...@vger.kernel.org; Praveena NADAHALLY
 Subject: Re: [PATCH] usb:musb:musb_host: Handle highmem in PIO mode
 
 
  --- a/include/linux/usb.h
  +++ b/include/linux/usb.h
  @@ -21,6 +21,7 @@
   #include linux/sched.h   /* for current  schedule_timeout */
   #include linux/mutex.h   /* for struct mutex */
   #include linux/pm_runtime.h  /* for runtime PM */
  +#include linux/scatterlist.h
 
   struct usb_device;
   struct usb_driver;
  @@ -1309,6 +1310,7 @@ struct urb {
  usb_complete_t complete;/* (in) completion routine */
  struct usb_iso_packet_descriptor iso_frame_desc[0];
  /* (in) ISO ONLY */
  +   struct sg_mapping_iter sg_miter; /* handling highmem data in PIO mode */
   };
 
 This is unacceptable.  Fields like this should be stored in the
 URB's hcpriv structure, not in the URB itself.

Ok I will add it in the hcpriv structure. Can you please comment on other
 part of the code also, so that all the changes can be done together. 

Thanks 
Virupax S 
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH] usb:musb:musb_host: Handle highmem in PIO mode

2012-08-02 Thread Virupax SADASHIVPETIMATH


> -Original Message-
> From: Virupax SADASHIVPETIMATH
> Sent: Thursday, August 02, 2012 5:35 PM
> To: 'Greg KH'
> Cc: ba...@ti.com; linux-...@vger.kernel.org; linux-kernel@vger.kernel.org; 
> Praveena
> NADAHALLY
> Subject: RE: [PATCH] usb:musb:musb_host: Handle highmem in PIO mode
> 
> 
> > -Original Message-
> > From: Greg KH [mailto:gre...@linuxfoundation.org]
> > Sent: Thursday, August 02, 2012 4:30 PM
> > To: Virupax SADASHIVPETIMATH
> > Cc: ba...@ti.com; linux-...@vger.kernel.org; linux-kernel@vger.kernel.org; 
> > Praveena
> > NADAHALLY
> > Subject: Re: [PATCH] usb:musb:musb_host: Handle highmem in PIO mode
> >
> > On Thu, Aug 02, 2012 at 12:06:42PM +0530, Virupax Sadashivpetimath wrote:
> > > In case of USB bulk transfer, when himem page
> > > is received, the usb_sg_init function sets the
> > > urb transfer buffer to NULL. When such URB
> > > transfer is handled, kernel crashes in PIO mode.
> > > Handle this by mapping the highmem buffer in PIO mode.
> > >
> > > Signed-off-by: Virupax Sadashivpetimath 
> > > 
> >
> > Why is this not a problem in any other host controller?
> 
> Problem is seen only when the RAM on the board is 1GB or more. When the urb 
> sg is in
> highmem.

And also many of the host controllers are using the DMA mode for all sizes
 of urb transfer, because of which the problem is not seen in those 
controllers. 

Thanks 
Virupax S 
 




--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH] usb:musb:musb_host: Handle highmem in PIO mode

2012-08-02 Thread Virupax SADASHIVPETIMATH

> -Original Message-
> From: Greg KH [mailto:gre...@linuxfoundation.org]
> Sent: Thursday, August 02, 2012 4:30 PM
> To: Virupax SADASHIVPETIMATH
> Cc: ba...@ti.com; linux-...@vger.kernel.org; linux-kernel@vger.kernel.org; 
> Praveena
> NADAHALLY
> Subject: Re: [PATCH] usb:musb:musb_host: Handle highmem in PIO mode
> 
> On Thu, Aug 02, 2012 at 12:06:42PM +0530, Virupax Sadashivpetimath wrote:
> > In case of USB bulk transfer, when himem page
> > is received, the usb_sg_init function sets the
> > urb transfer buffer to NULL. When such URB
> > transfer is handled, kernel crashes in PIO mode.
> > Handle this by mapping the highmem buffer in PIO mode.
> >
> > Signed-off-by: Virupax Sadashivpetimath 
> > 
> 
> Why is this not a problem in any other host controller? 

Problem is seen only when the RAM on the board is 1GB or more. When the urb sg 
is in highmem. 

Below crash is seen without the patch

[   50.467529] Unable to handle kernel NULL pointer dereference at virtual 
address 
[   50.475616] pgd = c0004000
[   50.478302] [] *pgd=
[   50.481872] Internal error: Oops: 817 [#1] PREEMPT SMP ARM
[   50.546630] CPU: 0Tainted: G   O  (3.4.0+ #1)
[   50.552062] PC is at __raw_readsl+0x30/0x100
[   50.556304] LR is at 0x0
[   50.558837] pc : []lr : [<>]psr: 2193
[   50.558837] sp : c09b5c80  ip :   fp : c09b5cb4
[   50.570312] r10: db9a46c0  r9 : c0a45538  r8 : 
[   50.575531] r7 : 0002  r6 : df860028  r5 : 0200  r4 : 00010101
[   50.582031] r3 : 464c457f  r2 : 0078  r1 :   r0 : df860028
[   50.588562] Flags: nzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment 
kernel
[   50.595947] Control: 10c5787d  Table: 1bf0c04a  DAC: 0015

> Are you sure this fix is correct?

I have tested the patch on the board with the issue and it seems to work.

>  Why do you need to modify the struct urb for this?

The URB transfer may take more than 1 interrupt for the complete transfer
to store the state of sg_miter specific to urb, struct urb is used.

Thanks 
Virupax S 



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] usb:musb:musb_host: Handle highmem in PIO mode

2012-08-02 Thread Virupax Sadashivpetimath
In case of USB bulk transfer, when himem page
is received, the usb_sg_init function sets the
urb transfer buffer to NULL. When such URB
transfer is handled, kernel crashes in PIO mode.
Handle this by mapping the highmem buffer in PIO mode.

Signed-off-by: Virupax Sadashivpetimath 

---
 drivers/usb/musb/musb_host.c |   98 +++--
 include/linux/usb.h  |2 +
 2 files changed, 95 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 4bb717d..ff1af0a 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -813,9 +813,28 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
if (load_count) {
/* PIO to load FIFO */
qh->segsize = load_count;
-   musb_write_fifo(hw_ep, load_count, buf);
+   if (!buf) {
+   sg_miter_start(>sg_miter, urb->sg, 1,
+   SG_MITER_ATOMIC
+   | SG_MITER_FROM_SG);
+   if (!sg_miter_next(>sg_miter)) {
+   dev_err(musb->controller,
+   "error: sg"
+   "list empty\n");
+   sg_miter_stop(>sg_miter);
+   goto finish;
+   }
+   buf = urb->sg_miter.addr + urb->sg->offset +
+   urb->actual_length;
+   load_count = min_t(u32, load_count,
+   urb->sg_miter.length);
+   musb_write_fifo(hw_ep, load_count, buf);
+   urb->sg_miter.consumed = load_count;
+   sg_miter_stop(>sg_miter);
+   } else
+   musb_write_fifo(hw_ep, load_count, buf);
}
-
+finish:
/* re-enable interrupt */
musb_writew(mbase, MUSB_INTRTXE, int_txe);
 
@@ -1116,6 +1135,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
void __iomem*mbase = musb->mregs;
struct dma_channel  *dma;
booltransfer_pending = false;
+   static bool use_sg;
 
musb_ep_select(mbase, epnum);
tx_csr = musb_readw(epio, MUSB_TXCSR);
@@ -1163,6 +1183,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
return;
}
 
+done:
if (status) {
if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
dma->status = MUSB_DMA_STATUS_CORE_ABORT;
@@ -1332,9 +1353,38 @@ void musb_host_tx(struct musb *musb, u8 epnum)
length = qh->maxpacket;
/* Unmap the buffer so that CPU can use it */
usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb);
-   musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset);
+
+   /*
+* We need to map sg if the transfer_buffer is
+* NULL.
+*/
+   if (!urb->transfer_buffer)
+   use_sg = true;
+
+   if (use_sg) {
+   /* sg_miter_start is already done in musb_ep_program */
+   if (!sg_miter_next(>sg_miter)) {
+   dev_err(musb->controller, "error: sg list empty\n");
+   sg_miter_stop(>sg_miter);
+   status = -EINVAL;
+   goto done;
+   }
+   urb->transfer_buffer = urb->sg_miter.addr;
+   length = min_t(u32, length, urb->sg_miter.length);
+   musb_write_fifo(hw_ep, length, urb->transfer_buffer);
+   urb->sg_miter.consumed = length;
+   sg_miter_stop(>sg_miter);
+   } else {
+   musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset);
+   }
+
qh->segsize = length;
 
+   if (use_sg) {
+   if (offset + length >= urb->transfer_buffer_length)
+   use_sg = false;
+   }
+
musb_ep_select(mbase, epnum);
musb_writew(epio, MUSB_TXCSR,
MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
@@ -1442,6 +1492,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
booldone = false;
u32 status;
struct dma_channel  *dma;
+   static bool use_sg;
+   unsigned int sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG;
 
musb_ep_select(mbase, epnum);
 
@@ -1756,10 +1808,43 @@ void musb_host_rx(struct musb *musb, u8 epnum)
 #endif /* Mentor DMA */
 
if (!

[PATCH] usb:musb:musb_host: Handle highmem in PIO mode

2012-08-02 Thread Virupax Sadashivpetimath
In case of USB bulk transfer, when himem page
is received, the usb_sg_init function sets the
urb transfer buffer to NULL. When such URB
transfer is handled, kernel crashes in PIO mode.
Handle this by mapping the highmem buffer in PIO mode.

Signed-off-by: Virupax Sadashivpetimath 
virupax.sadashivpetim...@stericsson.com
---
 drivers/usb/musb/musb_host.c |   98 +++--
 include/linux/usb.h  |2 +
 2 files changed, 95 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 4bb717d..ff1af0a 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -813,9 +813,28 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
if (load_count) {
/* PIO to load FIFO */
qh-segsize = load_count;
-   musb_write_fifo(hw_ep, load_count, buf);
+   if (!buf) {
+   sg_miter_start(urb-sg_miter, urb-sg, 1,
+   SG_MITER_ATOMIC
+   | SG_MITER_FROM_SG);
+   if (!sg_miter_next(urb-sg_miter)) {
+   dev_err(musb-controller,
+   error: sg
+   list empty\n);
+   sg_miter_stop(urb-sg_miter);
+   goto finish;
+   }
+   buf = urb-sg_miter.addr + urb-sg-offset +
+   urb-actual_length;
+   load_count = min_t(u32, load_count,
+   urb-sg_miter.length);
+   musb_write_fifo(hw_ep, load_count, buf);
+   urb-sg_miter.consumed = load_count;
+   sg_miter_stop(urb-sg_miter);
+   } else
+   musb_write_fifo(hw_ep, load_count, buf);
}
-
+finish:
/* re-enable interrupt */
musb_writew(mbase, MUSB_INTRTXE, int_txe);
 
@@ -1116,6 +1135,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
void __iomem*mbase = musb-mregs;
struct dma_channel  *dma;
booltransfer_pending = false;
+   static bool use_sg;
 
musb_ep_select(mbase, epnum);
tx_csr = musb_readw(epio, MUSB_TXCSR);
@@ -1163,6 +1183,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
return;
}
 
+done:
if (status) {
if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
dma-status = MUSB_DMA_STATUS_CORE_ABORT;
@@ -1332,9 +1353,38 @@ void musb_host_tx(struct musb *musb, u8 epnum)
length = qh-maxpacket;
/* Unmap the buffer so that CPU can use it */
usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb);
-   musb_write_fifo(hw_ep, length, urb-transfer_buffer + offset);
+
+   /*
+* We need to map sg if the transfer_buffer is
+* NULL.
+*/
+   if (!urb-transfer_buffer)
+   use_sg = true;
+
+   if (use_sg) {
+   /* sg_miter_start is already done in musb_ep_program */
+   if (!sg_miter_next(urb-sg_miter)) {
+   dev_err(musb-controller, error: sg list empty\n);
+   sg_miter_stop(urb-sg_miter);
+   status = -EINVAL;
+   goto done;
+   }
+   urb-transfer_buffer = urb-sg_miter.addr;
+   length = min_t(u32, length, urb-sg_miter.length);
+   musb_write_fifo(hw_ep, length, urb-transfer_buffer);
+   urb-sg_miter.consumed = length;
+   sg_miter_stop(urb-sg_miter);
+   } else {
+   musb_write_fifo(hw_ep, length, urb-transfer_buffer + offset);
+   }
+
qh-segsize = length;
 
+   if (use_sg) {
+   if (offset + length = urb-transfer_buffer_length)
+   use_sg = false;
+   }
+
musb_ep_select(mbase, epnum);
musb_writew(epio, MUSB_TXCSR,
MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
@@ -1442,6 +1492,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
booldone = false;
u32 status;
struct dma_channel  *dma;
+   static bool use_sg;
+   unsigned int sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG;
 
musb_ep_select(mbase, epnum);
 
@@ -1756,10 +1808,43 @@ void musb_host_rx(struct musb *musb, u8 epnum)
 #endif /* Mentor DMA */
 
if (!dma) {
+   unsigned int received_len;
+
/* Unmap

RE: [PATCH] usb:musb:musb_host: Handle highmem in PIO mode

2012-08-02 Thread Virupax SADASHIVPETIMATH

 -Original Message-
 From: Greg KH [mailto:gre...@linuxfoundation.org]
 Sent: Thursday, August 02, 2012 4:30 PM
 To: Virupax SADASHIVPETIMATH
 Cc: ba...@ti.com; linux-...@vger.kernel.org; linux-kernel@vger.kernel.org; 
 Praveena
 NADAHALLY
 Subject: Re: [PATCH] usb:musb:musb_host: Handle highmem in PIO mode
 
 On Thu, Aug 02, 2012 at 12:06:42PM +0530, Virupax Sadashivpetimath wrote:
  In case of USB bulk transfer, when himem page
  is received, the usb_sg_init function sets the
  urb transfer buffer to NULL. When such URB
  transfer is handled, kernel crashes in PIO mode.
  Handle this by mapping the highmem buffer in PIO mode.
 
  Signed-off-by: Virupax Sadashivpetimath 
  virupax.sadashivpetim...@stericsson.com
 
 Why is this not a problem in any other host controller? 

Problem is seen only when the RAM on the board is 1GB or more. When the urb sg 
is in highmem. 

Below crash is seen without the patch

[   50.467529] Unable to handle kernel NULL pointer dereference at virtual 
address 
[   50.475616] pgd = c0004000
[   50.478302] [] *pgd=
[   50.481872] Internal error: Oops: 817 [#1] PREEMPT SMP ARM
[   50.546630] CPU: 0Tainted: G   O  (3.4.0+ #1)
[   50.552062] PC is at __raw_readsl+0x30/0x100
[   50.556304] LR is at 0x0
[   50.558837] pc : [c028b500]lr : []psr: 2193
[   50.558837] sp : c09b5c80  ip :   fp : c09b5cb4
[   50.570312] r10: db9a46c0  r9 : c0a45538  r8 : 
[   50.575531] r7 : 0002  r6 : df860028  r5 : 0200  r4 : 00010101
[   50.582031] r3 : 464c457f  r2 : 0078  r1 :   r0 : df860028
[   50.588562] Flags: nzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment 
kernel
[   50.595947] Control: 10c5787d  Table: 1bf0c04a  DAC: 0015

 Are you sure this fix is correct?

I have tested the patch on the board with the issue and it seems to work.

  Why do you need to modify the struct urb for this?

The URB transfer may take more than 1 interrupt for the complete transfer
to store the state of sg_miter specific to urb, struct urb is used.

Thanks 
Virupax S 



--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH] usb:musb:musb_host: Handle highmem in PIO mode

2012-08-02 Thread Virupax SADASHIVPETIMATH


 -Original Message-
 From: Virupax SADASHIVPETIMATH
 Sent: Thursday, August 02, 2012 5:35 PM
 To: 'Greg KH'
 Cc: ba...@ti.com; linux-...@vger.kernel.org; linux-kernel@vger.kernel.org; 
 Praveena
 NADAHALLY
 Subject: RE: [PATCH] usb:musb:musb_host: Handle highmem in PIO mode
 
 
  -Original Message-
  From: Greg KH [mailto:gre...@linuxfoundation.org]
  Sent: Thursday, August 02, 2012 4:30 PM
  To: Virupax SADASHIVPETIMATH
  Cc: ba...@ti.com; linux-...@vger.kernel.org; linux-kernel@vger.kernel.org; 
  Praveena
  NADAHALLY
  Subject: Re: [PATCH] usb:musb:musb_host: Handle highmem in PIO mode
 
  On Thu, Aug 02, 2012 at 12:06:42PM +0530, Virupax Sadashivpetimath wrote:
   In case of USB bulk transfer, when himem page
   is received, the usb_sg_init function sets the
   urb transfer buffer to NULL. When such URB
   transfer is handled, kernel crashes in PIO mode.
   Handle this by mapping the highmem buffer in PIO mode.
  
   Signed-off-by: Virupax Sadashivpetimath 
   virupax.sadashivpetim...@stericsson.com
 
  Why is this not a problem in any other host controller?
 
 Problem is seen only when the RAM on the board is 1GB or more. When the urb 
 sg is in
 highmem.

And also many of the host controllers are using the DMA mode for all sizes
 of urb transfer, because of which the problem is not seen in those 
controllers. 

Thanks 
Virupax S 
 




--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/