LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: checking status semantics with compatible functions
From: Kumar Gala @ 2011-03-30  8:26 UTC (permalink / raw)
  To: Kumar Gala; +Cc: Linuxppc-dev list, devicetree-discuss, Prabhakar Kushwaha
In-Reply-To: <9BC4C90E-090F-4961-A242-10D769C08738@kernel.crashing.org>

[Adding proper lists on CC]

- k

On Mar 30, 2011, at 3:07 AM, Kumar Gala wrote:

> Grant,
>=20
> We have a few helper functions like:
>=20
> drivers/of/base.c:EXPORT_SYMBOL(of_device_is_compatible);
> drivers/of/base.c:EXPORT_SYMBOL(of_find_compatible_node);
>=20
> That we use in places like arch/powerpc/platform/85xx/mpc85xx_ds.c:
>=20
>        for_each_node_by_type(np, "pci") {
>                if (of_device_is_compatible(np, "fsl,mpc8540-pci") ||
>                    of_device_is_compatible(np, "fsl,mpc8548-pcie") ||
>                    of_device_is_compatible(np, "fsl,p2020-pcie")) {
>=20
> It seems like we should check 'status' in these cases with =
'of_device_is_available'.  I'm thinking that we should have versions of =
the helpers that also do the 'of_device_is_available' checking.  Or =
should we just change the helpers to call of_device_is_available?
>=20
> - k
> _______________________________________________
> devicetree-discuss mailing list
> devicetree-discuss@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/devicetree-discuss

^ permalink raw reply

* Re: [PATCH] powerpc: dtc: remove obsolete .gitignore entries
From: Wolfram Sang @ 2011-03-30  8:05 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <1299948250-32084-1-git-send-email-w.sang@pengutronix.de>

[-- Attachment #1: Type: text/plain, Size: 1312 bytes --]

On Sat, Mar 12, 2011 at 05:44:10PM +0100, Wolfram Sang wrote:
> dtc was moved and .gitignores have been added to the new location. So, we can
> delete the old, forgotten ones.
> 
> Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Ping. Is this one more for Ben or more for Grant?

> ---
>  arch/powerpc/boot/.gitignore         |    1 -
>  arch/powerpc/boot/dtc-src/.gitignore |    3 ---
>  2 files changed, 0 insertions(+), 4 deletions(-)
>  delete mode 100644 arch/powerpc/boot/dtc-src/.gitignore
> 
> diff --git a/arch/powerpc/boot/.gitignore b/arch/powerpc/boot/.gitignore
> index 3d80c3e..12da77e 100644
> --- a/arch/powerpc/boot/.gitignore
> +++ b/arch/powerpc/boot/.gitignore
> @@ -1,5 +1,4 @@
>  addnote
> -dtc
>  empty.c
>  hack-coff
>  infblock.c
> diff --git a/arch/powerpc/boot/dtc-src/.gitignore b/arch/powerpc/boot/dtc-src/.gitignore
> deleted file mode 100644
> index a7c3f94..0000000
> --- a/arch/powerpc/boot/dtc-src/.gitignore
> +++ /dev/null
> @@ -1,3 +0,0 @@
> -dtc-lexer.lex.c
> -dtc-parser.tab.c
> -dtc-parser.tab.h
> -- 
> 1.7.2.3
> 

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* RE: [PATCH v2 5/5] xhci: Remove recursive call to xhci_handle_event
From: David Laight @ 2011-03-30  7:51 UTC (permalink / raw)
  To: Dmitry Torokhov, Matt Evans
  Cc: sarah.a.sharp, linuxppc-dev, linux-usb, Sergei Shtylyov
In-Reply-To: <20110329200017.GA25480@dtor-ws.eng.vmware.com>

=20
> > -	xhci_handle_event(xhci);
> > +	while (xhci_handle_event(xhci)) {}
> >=20
>=20
> I must admit I dislike the style with empty loop bodies...

I would use an explicit 'continue;' for the body
of an otherwise empty loop.

	David

^ permalink raw reply

* [git pull] Please pull powerpc.git merge branch
From: Benjamin Herrenschmidt @ 2011-03-30  2:08 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linuxppc-dev list, Andrew Morton, Linux Kernel list

Hi Linus !

Here are a few post -rc1 fixes for powerpc.

Mostly some more fallout from the irq core rework, new syscalls wireup,
defconfig fixes and minor bits. The only feature-esque thing in there
would be me adding dma_mmap_coherent(), it fixes various audio devices
on our older non cache-coherent embedded platforms.

Freescale folks: I've manually added two patches to fix some FSL 8xx and
QE irq build problems caused by the upstream irq rework to the branch.
Please verify that it's all correct and if not send followup patches.

Linus: I didn't wait for hera to sync to the mirrors before sending this
email (I usually do but I have to run and it's very slow today).

The following changes since commit 0ce790e7d736cedc563e1fb4e998babf5a4dbc3d:

  Linux 2.6.39-rc1 (2011-03-29 12:09:47 -0700)

are available in the git repository at:
  git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git ..BRANCH.NOT.VERIFIED..

Anton Blanchard (2):
      powerpc: Fix accounting of softirq time when idle
      powerpc/pseries: Enable Chelsio network and iWARP drivers

Benjamin Herrenschmidt (4):
      powerpc: Implement dma_mmap_coherent()
      powerpc/mm: Move the STAB0 location to 0x8000 to make room in low memory
      powerpc/8xx: Fix another breakage from the irq_data conversion
      powerpc/qe_ic: Fix another breakage from the irq_data conversion

Jim Keniston (1):
      powerpc/nvram: Don't overwrite oops/panic report on normal shutdown

Milton Miller (3):
      powerpc/xics: Fix numberspace mismatch from irq_desc conversion
      powerpc/xics: Use hwirq for xics domain irq number
      powerpc/pseries/smp: query-cpu-stopped-state support won't change

Scott Wood (1):
      powerpc: ARCH_PFN_OFFSET should be unsigned long

Stephen Rothwell (2):
      powerpc: Restore some misc devices to our configs
      powerpc: Wire up new syscalls

Thomas Gleixner (1):
      powerpc/cell: Use handle_edge_eoi_irq for real

Varun Sethi (1):
      powerpc/booke: Correct the SPRN_MAS5 definition.

 arch/powerpc/configs/44x/warp_defconfig          |    1 +
 arch/powerpc/configs/52xx/motionpro_defconfig    |    1 +
 arch/powerpc/configs/86xx/gef_ppc9a_defconfig    |    1 +
 arch/powerpc/configs/86xx/gef_sbc310_defconfig   |    1 +
 arch/powerpc/configs/86xx/gef_sbc610_defconfig   |    1 +
 arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig |    1 +
 arch/powerpc/configs/e55xx_smp_defconfig         |    1 +
 arch/powerpc/configs/linkstation_defconfig       |    1 +
 arch/powerpc/configs/mpc512x_defconfig           |    1 +
 arch/powerpc/configs/mpc5200_defconfig           |    1 +
 arch/powerpc/configs/mpc85xx_defconfig           |    1 +
 arch/powerpc/configs/mpc85xx_smp_defconfig       |    1 +
 arch/powerpc/configs/mpc86xx_defconfig           |    1 +
 arch/powerpc/configs/pasemi_defconfig            |    1 +
 arch/powerpc/configs/ppc6xx_defconfig            |    1 +
 arch/powerpc/configs/pseries_defconfig           |    3 +
 arch/powerpc/include/asm/dma-mapping.h           |    6 ++
 arch/powerpc/include/asm/mmu-hash64.h            |    2 +-
 arch/powerpc/include/asm/page.h                  |    2 +-
 arch/powerpc/include/asm/qe_ic.h                 |   16 +++---
 arch/powerpc/include/asm/reg_booke.h             |    2 +-
 arch/powerpc/include/asm/systbl.h                |    4 +
 arch/powerpc/include/asm/unistd.h                |    6 ++-
 arch/powerpc/kernel/dma.c                        |   18 ++++++
 arch/powerpc/kernel/exceptions-64s.S             |   28 ++++----
 arch/powerpc/kernel/time.c                       |    2 +-
 arch/powerpc/mm/dma-noncoherent.c                |   20 ++++++
 arch/powerpc/platforms/cell/interrupt.c          |    2 +-
 arch/powerpc/platforms/pseries/nvram.c           |   24 +++++++
 arch/powerpc/platforms/pseries/smp.c             |    4 +-
 arch/powerpc/platforms/pseries/xics.c            |   71 +++++++++++-----------
 arch/powerpc/sysdev/mpc8xx_pic.c                 |    2 +-
 32 files changed, 161 insertions(+), 66 deletions(-)

Cheers,
Ben.


 

^ permalink raw reply

* Re: linux-next: build failure after merge of the Linus' tree
From: Benjamin Herrenschmidt @ 2011-03-30  1:56 UTC (permalink / raw)
  To: Stephen Rothwell
  Cc: ppc-dev, Thomas Gleixner, linux-next, Linus, linux-kernel
In-Reply-To: <20110330110027.b83a1d20.sfr@canb.auug.org.au>

On Wed, 2011-03-30 at 11:00 +1100, Stephen Rothwell wrote:
> Hi all,
> 
> After merging the Linus' tree, today's linux-next build (powerpc
> ppc64_defconfig) failed like this:
> 
> kernel/irq/chip.c: In function 'handle_edge_eoi_irq':
> kernel/irq/chip.c:517: warning: label 'out_unlock' defined but not used
> kernel/irq/chip.c:503: error: label 'out_eoi' used but not defined

There's a fix in tip/irq/urgent ...

Cheers,
Ben.

> Caused by commit 0521c8fbb3da ("genirq: Provide edge_eoi flow handler")
> which was clearly not even built with CONFIG_IRQ_EDGE_EOI_HANDLER defined.
> 
> I applied this fixup patch:
> 
> From: Stephen Rothwell <sfr@canb.auug.org.au>
> Date: Wed, 30 Mar 2011 10:55:12 +1100
> Subject: [PATCH] genirq: fix CONFIG_IRQ_EDGE_EOI_HANDLER build
> 
> Fixes these errors:
> 
> kernel/irq/chip.c: In function 'handle_edge_eoi_irq':
> kernel/irq/chip.c:517: warning: label 'out_unlock' defined but not used
> kernel/irq/chip.c:503: error: label 'out_eoi' used but not defined
> 
> Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
> ---
>  kernel/irq/chip.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
> index 616ec1c..1dafc86 100644
> --- a/kernel/irq/chip.c
> +++ b/kernel/irq/chip.c
> @@ -514,7 +514,7 @@ void handle_edge_eoi_irq(unsigned int irq, struct irq_desc *desc)
>  	} while ((desc->istate & IRQS_PENDING) &&
>  		 !irqd_irq_disabled(&desc->irq_data));
>  
> -out_unlock:
> +out_eoi:
>  	chip->irq_eoi(&desc->irq_data);
>  	raw_spin_unlock(&desc->lock);
>  }
> -- 
> 1.7.4.1
> 
> 

^ permalink raw reply

* Re: linux-next: build failure after merge of the Linus' tree
From: Benjamin Herrenschmidt @ 2011-03-30  1:57 UTC (permalink / raw)
  To: Stephen Rothwell
  Cc: ppc-dev, Thomas Gleixner, linux-next, Linus, linux-kernel
In-Reply-To: <20110330110045.48fb0ccf.sfr@canb.auug.org.au>

On Wed, 2011-03-30 at 11:00 +1100, Stephen Rothwell wrote:
> Hi all,
> 
> After merging the Linus' tree, today's linux-next build (powerpc
> ppc64_defconfig) failed like this:
> 
> arch/powerpc/platforms/cell/interrupt.c: In function 'iic_host_map':
> arch/powerpc/platforms/cell/interrupt.c:247: error: 'handle_iic_irq' undeclared (first use in this function)

There's a fix in powerpc "merge" for which I'm about to send Linus a
pull request :-)

Cheers,
Ben.

> Caused by commit f9ba4475f95b ("powerpc: cell: Use the core flow handler").
> 
> I applied the following patch:
> 
> From: Stephen Rothwell <sfr@canb.auug.org.au>
> Date: Wed, 30 Mar 2011 10:48:28 +1100
> Subject: [PATCH] powerpc/cell: fixup for removal of handle_iic_irq
> 
> Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
> ---
>  arch/powerpc/platforms/cell/interrupt.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
> index a19bec0..44cfd1b 100644
> --- a/arch/powerpc/platforms/cell/interrupt.c
> +++ b/arch/powerpc/platforms/cell/interrupt.c
> @@ -244,7 +244,7 @@ static int iic_host_map(struct irq_host *h, unsigned int virq,
>  		break;
>  	case IIC_IRQ_TYPE_IOEXC:
>  		irq_set_chip_and_handler(virq, &iic_ioexc_chip,
> -					 handle_iic_irq);
> +					 handle_edge_eoi_irq);
>  		break;
>  	default:
>  		irq_set_chip_and_handler(virq, &iic_chip, handle_edge_eoi_irq);
> -- 
> 1.7.4.1
> 

^ permalink raw reply

* linux-next: build failure after merge of the Linus' tree
From: Stephen Rothwell @ 2011-03-30  0:00 UTC (permalink / raw)
  To: Linus; +Cc: Thomas Gleixner, linux-next, ppc-dev, linux-kernel

Hi all,

After merging the Linus' tree, today's linux-next build (powerpc
ppc64_defconfig) failed like this:

arch/powerpc/platforms/cell/interrupt.c: In function 'iic_host_map':
arch/powerpc/platforms/cell/interrupt.c:247: error: 'handle_iic_irq' undeclared (first use in this function)

Caused by commit f9ba4475f95b ("powerpc: cell: Use the core flow handler").

I applied the following patch:

From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Wed, 30 Mar 2011 10:48:28 +1100
Subject: [PATCH] powerpc/cell: fixup for removal of handle_iic_irq

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
 arch/powerpc/platforms/cell/interrupt.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index a19bec0..44cfd1b 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -244,7 +244,7 @@ static int iic_host_map(struct irq_host *h, unsigned int virq,
 		break;
 	case IIC_IRQ_TYPE_IOEXC:
 		irq_set_chip_and_handler(virq, &iic_ioexc_chip,
-					 handle_iic_irq);
+					 handle_edge_eoi_irq);
 		break;
 	default:
 		irq_set_chip_and_handler(virq, &iic_chip, handle_edge_eoi_irq);
-- 
1.7.4.1

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

^ permalink raw reply related

* linux-next: build failure after merge of the Linus' tree
From: Stephen Rothwell @ 2011-03-30  0:00 UTC (permalink / raw)
  To: Linus; +Cc: Thomas Gleixner, linux-next, ppc-dev, linux-kernel

Hi all,

After merging the Linus' tree, today's linux-next build (powerpc
ppc64_defconfig) failed like this:

kernel/irq/chip.c: In function 'handle_edge_eoi_irq':
kernel/irq/chip.c:517: warning: label 'out_unlock' defined but not used
kernel/irq/chip.c:503: error: label 'out_eoi' used but not defined

Caused by commit 0521c8fbb3da ("genirq: Provide edge_eoi flow handler")
which was clearly not even built with CONFIG_IRQ_EDGE_EOI_HANDLER defined.

I applied this fixup patch:

From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Wed, 30 Mar 2011 10:55:12 +1100
Subject: [PATCH] genirq: fix CONFIG_IRQ_EDGE_EOI_HANDLER build

Fixes these errors:

kernel/irq/chip.c: In function 'handle_edge_eoi_irq':
kernel/irq/chip.c:517: warning: label 'out_unlock' defined but not used
kernel/irq/chip.c:503: error: label 'out_eoi' used but not defined

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
 kernel/irq/chip.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 616ec1c..1dafc86 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -514,7 +514,7 @@ void handle_edge_eoi_irq(unsigned int irq, struct irq_desc *desc)
 	} while ((desc->istate & IRQS_PENDING) &&
 		 !irqd_irq_disabled(&desc->irq_data));
 
-out_unlock:
+out_eoi:
 	chip->irq_eoi(&desc->irq_data);
 	raw_spin_unlock(&desc->lock);
 }
-- 
1.7.4.1


-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

^ permalink raw reply related

* Re: [PATCH v2 3/5] xhci: Add rmb() between reading event validity & event data access.
From: Benjamin Herrenschmidt @ 2011-03-29 21:23 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: sarah.a.sharp, linuxppc-dev, linux-usb, Matt Evans
In-Reply-To: <201103291156.47822.dmitry.torokhov@gmail.com>

On Tue, 2011-03-29 at 11:56 -0700, Dmitry Torokhov wrote:
> > +     /*
> > +      * Barrier between reading the TRB_CYCLE (valid) flag above
> and any
> > +      * speculative reads of the event's flags/data below.
> > +      */
> > +     rmb();
> >       /* FIXME: Handle more event types. */
> >       switch ((le32_to_cpu(event->event_cmd.flags) &
> TRB_TYPE_BITMASK)) {
> 
> Isn't it the same memory that is being read the first time around? How
> reordering could happen here? 

We don't try to enforce ordering specifically with the subsequent read
of the flags that is visible in the snipped above (indeed that's the
same address and so hopefully should be in program order), but all
subsequent reads which could have been performed speculatively such as
the rest of the event and including whatever other in memory information
the chip might have updated prior to sending the event.

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH V2] POWER: perf_event: Skip updating kernel counters if register value shrinks
From: Benjamin Herrenschmidt @ 2011-03-29 21:14 UTC (permalink / raw)
  To: Eric B Munson
  Cc: a.p.zijlstra, linux-kernel, paulus, anton, acme, mingo,
	linuxppc-dev, stable
In-Reply-To: <1301410302-7270-1-git-send-email-emunson@mgebm.net>

\
> diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/kernel/perf_event.c
> index 97e0ae4..0a5178f 100644
> --- a/arch/powerpc/kernel/perf_event.c
> +++ b/arch/powerpc/kernel/perf_event.c
> @@ -416,6 +416,15 @@ static void power_pmu_read(struct perf_event *event)
>  		prev = local64_read(&event->hw.prev_count);
>  		barrier();
>  		val = read_pmc(event->hw.idx);
> +		/*
> +		 * POWER7 can roll back counter values, if the new value is
> +		 * smaller than the previous value it will cause the delta
> +		 * and the counter to have bogus values.  If this is the
> +		 * case skip updating anything until the counter grows again.
> +		 * This can lead to a small lack of precision in the counters.
> +		 */
> +		if (val < prev)
> +			return;
>  	} while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev);

So if the counters can rollover, the above is still wrong... prev could
be ffffffff and val could be 1 ... for example. In this case you really
need to substract and get the sign of the result I'd think...

Cheers,
Ben.

>  	/* The counters are only 32 bits wide */
> @@ -439,7 +448,8 @@ static void freeze_limited_counters(struct cpu_hw_events *cpuhw,
>  				    unsigned long pmc5, unsigned long pmc6)
>  {
>  	struct perf_event *event;
> -	u64 val, prev, delta;
> +	u64 val, prev;
> +	s32 delta;
>  	int i;
>  
>  	for (i = 0; i < cpuhw->n_limited; ++i) {
> @@ -449,8 +459,13 @@ static void freeze_limited_counters(struct cpu_hw_events *cpuhw,
>  		val = (event->hw.idx == 5) ? pmc5 : pmc6;
>  		prev = local64_read(&event->hw.prev_count);
>  		event->hw.idx = 0;
> -		delta = (val - prev) & 0xfffffffful;
> -		local64_add(delta, &event->count);
> +		/*
> +		 * The PerfMon registers are only 32 bits wide so the
> +		 * delta should not overflow.
> +		 */
> +		delta = val - prev;
> +		if (delta > 0)
> +			local64_add(delta, &event->count);
>  	}
>  }
>  
> @@ -458,14 +473,16 @@ static void thaw_limited_counters(struct cpu_hw_events *cpuhw,
>  				  unsigned long pmc5, unsigned long pmc6)
>  {
>  	struct perf_event *event;
> -	u64 val;
> +	u64 val, prev;
>  	int i;
>  
>  	for (i = 0; i < cpuhw->n_limited; ++i) {
>  		event = cpuhw->limited_counter[i];
>  		event->hw.idx = cpuhw->limited_hwidx[i];
>  		val = (event->hw.idx == 5) ? pmc5 : pmc6;
> -		local64_set(&event->hw.prev_count, val);
> +		prev = local64_read(&event->hw.prev_count);
> +		if (val > prev)
> +			local64_set(&event->hw.prev_count, val);
>  		perf_event_update_userpage(event);
>  	}
>  }
> @@ -1187,7 +1204,8 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
>  			       struct pt_regs *regs, int nmi)
>  {
>  	u64 period = event->hw.sample_period;
> -	s64 prev, delta, left;
> +	s64 prev, left;
> +	s32 delta;
>  	int record = 0;
>  
>  	if (event->hw.state & PERF_HES_STOPPED) {
> @@ -1197,7 +1215,9 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
>  
>  	/* we don't have to worry about interrupts here */
>  	prev = local64_read(&event->hw.prev_count);
> -	delta = (val - prev) & 0xfffffffful;
> +	delta = val - prev;
> +	if (delta < 0)
> +		delta = 0;
>  	local64_add(delta, &event->count);
>  
>  	/*

^ permalink raw reply

* Re: [PATCH] POWER: perf_event: Skip updating kernel counters if register value shrinks
From: Benjamin Herrenschmidt @ 2011-03-29 21:12 UTC (permalink / raw)
  To: Eric B Munson
  Cc: a.p.zijlstra, linux-kernel, paulus, anton, acme, mingo,
	linuxppc-dev
In-Reply-To: <20110329142519.GA3527@mgebm.net>

On Tue, 2011-03-29 at 10:25 -0400, Eric B Munson wrote:
> Here I made the assumption that the hardware would never remove more events in
> a speculative roll back than it had added.  This is not a situation I
> encoutered in my limited testing, so I didn't think underflow was possible.  I
> will send out a V2 using the signed 32 bit delta and remeber to CC stable
> this time. 

I'm not thinking about underflow but rollover... or that isn't possible
with those counters ? IE. They don't wrap back to 0 after hitting
ffffffff ?

Cheers,
Ben.

^ permalink raw reply

* [patch 1/1] powerpc: cell: Use handle_edge_eoi_irq for real
From: Thomas Gleixner @ 2011-03-29 20:37 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: mingo

Missed one instance when moving that to the core code.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: linuxppc-dev@lists.ozlabs.org
Cc: michael@ellerman.id.au
Cc: mingo@elte.hu
---
 arch/powerpc/platforms/cell/interrupt.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Index: linux-2.6-tip/arch/powerpc/platforms/cell/interrupt.c
===================================================================
--- linux-2.6-tip.orig/arch/powerpc/platforms/cell/interrupt.c
+++ linux-2.6-tip/arch/powerpc/platforms/cell/interrupt.c
@@ -244,7 +244,7 @@ static int iic_host_map(struct irq_host 
 		break;
 	case IIC_IRQ_TYPE_IOEXC:
 		irq_set_chip_and_handler(virq, &iic_ioexc_chip,
-					 handle_iic_irq);
+					 handle_edge_eoi_irq);
 		break;
 	default:
 		irq_set_chip_and_handler(virq, &iic_chip, handle_edge_eoi_irq);

^ permalink raw reply

* Re: [PATCH v2 5/5] xhci: Remove recursive call to xhci_handle_event
From: Dmitry Torokhov @ 2011-03-29 20:00 UTC (permalink / raw)
  To: Matt Evans; +Cc: sarah.a.sharp, linuxppc-dev, linux-usb, Sergei Shtylyov
In-Reply-To: <4D90142C.4050206@ozlabs.org>

On Sunday, March 27, 2011 09:53:00 pm Matt Evans wrote:
> @@ -2282,7 +2284,7 @@ hw_died:
>  	/* FIXME this should be a delayed service routine
>  	 * that clears the EHB.
>  	 */
> -	xhci_handle_event(xhci);
> +	while (xhci_handle_event(xhci)) {}
> 

I must admit I dislike the style with empty loop bodies, do you think
we could have something like below instead?

Thanks!

-- 
Dmitry

From: Dmitry Torokhov <dtor@vmware.com>
Subject: [PATCH] USB: xhci: avoid recursion in xhci_handle_event

Instead of having xhci_handle_event call itself if there are more
outstanding TRBs push the loop logic up one level, into xhci_irq().

xchI_handle_event() does not check for presence of event_ring
anymore since the ring is always allocated. Also, encountering
a TRB that does not belong to OS is a normal condition that
causes us to stop processing and exit ISR and so is not reported
in xhci->error_bitmask.

Also consolidate handling of the event handler busy flag in
xhci_irq().

Reported-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Dmitry Torokhov <dtor@vmware.com>
---
 drivers/usb/host/xhci-ring.c |   77 +++++++++++++++---------------------------
 1 files changed, 27 insertions(+), 50 deletions(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 0e30281..8e6d8fa 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2131,26 +2131,12 @@ cleanup:
  * This function handles all OS-owned events on the event ring.  It may drop
  * xhci->lock between event processing (e.g. to pass up port status changes).
  */
-static void xhci_handle_event(struct xhci_hcd *xhci)
+static void xhci_handle_event(struct xhci_hcd *xhci, union xhci_trb *event)
 {
-	union xhci_trb *event;
-	int update_ptrs = 1;
+	bool update_ptrs = true;
 	int ret;
 
 	xhci_dbg(xhci, "In %s\n", __func__);
-	if (!xhci->event_ring || !xhci->event_ring->dequeue) {
-		xhci->error_bitmask |= 1 << 1;
-		return;
-	}
-
-	event = xhci->event_ring->dequeue;
-	/* Does the HC or OS own the TRB? */
-	if ((event->event_cmd.flags & TRB_CYCLE) !=
-			xhci->event_ring->cycle_state) {
-		xhci->error_bitmask |= 1 << 2;
-		return;
-	}
-	xhci_dbg(xhci, "%s - OS owns TRB\n", __func__);
 
 	/* FIXME: Handle more event types. */
 	switch ((event->event_cmd.flags & TRB_TYPE_BITMASK)) {
@@ -2163,7 +2149,7 @@ static void xhci_handle_event(struct xhci_hcd *xhci)
 		xhci_dbg(xhci, "%s - calling handle_port_status\n", __func__);
 		handle_port_status(xhci, event);
 		xhci_dbg(xhci, "%s - returned from handle_port_status\n", __func__);
-		update_ptrs = 0;
+		update_ptrs = false;
 		break;
 	case TRB_TYPE(TRB_TRANSFER):
 		xhci_dbg(xhci, "%s - calling handle_tx_event\n", __func__);
@@ -2172,7 +2158,7 @@ static void xhci_handle_event(struct xhci_hcd *xhci)
 		if (ret < 0)
 			xhci->error_bitmask |= 1 << 9;
 		else
-			update_ptrs = 0;
+			update_ptrs = false;
 		break;
 	default:
 		if ((event->event_cmd.flags & TRB_TYPE_BITMASK) >= TRB_TYPE(48))
@@ -2180,21 +2166,9 @@ static void xhci_handle_event(struct xhci_hcd *xhci)
 		else
 			xhci->error_bitmask |= 1 << 3;
 	}
-	/* Any of the above functions may drop and re-acquire the lock, so check
-	 * to make sure a watchdog timer didn't mark the host as non-responsive.
-	 */
-	if (xhci->xhc_state & XHCI_STATE_DYING) {
-		xhci_dbg(xhci, "xHCI host dying, returning from "
-				"event handler.\n");
-		return;
-	}
 
 	if (update_ptrs)
-		/* Update SW event ring dequeue pointer */
 		inc_deq(xhci, xhci->event_ring, true);
-
-	/* Are there more items on the event ring? */
-	xhci_handle_event(xhci);
 }
 
 /*
@@ -2258,34 +2232,37 @@ hw_died:
 		xhci_writel(xhci, irq_pending, &xhci->ir_set->irq_pending);
 	}
 
-	if (xhci->xhc_state & XHCI_STATE_DYING) {
-		xhci_dbg(xhci, "xHCI dying, ignoring interrupt. "
-				"Shouldn't IRQs be disabled?\n");
-		/* Clear the event handler busy flag (RW1C);
-		 * the event ring should be empty.
-		 */
-		temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
-		xhci_write_64(xhci, temp_64 | ERST_EHB,
-				&xhci->ir_set->erst_dequeue);
-		spin_unlock(&xhci->lock);
-
-		return IRQ_HANDLED;
-	}
-
 	event_ring_deq = xhci->event_ring->dequeue;
+
 	/* FIXME this should be a delayed service routine
 	 * that clears the EHB.
 	 */
-	xhci_handle_event(xhci);
+	xhci_dbg(xhci, "%s - Begin processing TRBs\n", __func__);
+
+	while (!(xhci->xhc_state & XHCI_STATE_DYING)) {
+		union xhci_trb *event = xhci->event_ring->dequeue;
+
+		/* Does the HC or OS own the TRB? */
+		if ((event->event_cmd.flags & TRB_CYCLE) !=
+				xhci->event_ring->cycle_state) {
+			break;
+		}
+
+		xhci_dbg(xhci, "%s - OS owns TRB\n", __func__);
+		xhci_handle_event(xhci, event);
+	}
 
 	temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
-	/* If necessary, update the HW's version of the event ring deq ptr. */
-	if (event_ring_deq != xhci->event_ring->dequeue) {
+
+	if (unlikely(xhci->xhc_state & XHCI_STATE_DYING)) {
+		xhci_dbg(xhci, "%s: xHCI is dying, exiting ISR\n", __func__);
+	} else if (event_ring_deq != xhci->event_ring->dequeue) {
+		/* Update the HW's version of the event ring deq ptr. */
 		deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
-				xhci->event_ring->dequeue);
+					xhci->event_ring->dequeue);
 		if (deq == 0)
-			xhci_warn(xhci, "WARN something wrong with SW event "
-					"ring dequeue ptr.\n");
+			xhci_warn(xhci,
+				  "WARN something wrong with SW event ring dequeue ptr.\n");
 		/* Update HC event ring dequeue pointer */
 		temp_64 &= ERST_PTR_MASK;
 		temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK);
-- 
1.7.4.1

^ permalink raw reply related

* Re: [PATCH v2 3/5] xhci: Add rmb() between reading event validity & event data access.
From: Dmitry Torokhov @ 2011-03-29 18:56 UTC (permalink / raw)
  To: Matt Evans; +Cc: sarah.a.sharp, linuxppc-dev, linux-usb
In-Reply-To: <4D901429.5010807@ozlabs.org>

On Sunday, March 27, 2011 09:52:57 pm Matt Evans wrote:
> On weakly-ordered systems, the reading of an event's content must occur
> after reading the event's validity.
> 
> Signed-off-by: Matt Evans <matt@ozlabs.org>
> ---
> Segher, thanks for the comment; explanation added.
> 
>  drivers/usb/host/xhci-ring.c |    5 +++++
>  1 files changed, 5 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
> index 45f3b77..d6aa880 100644
> --- a/drivers/usb/host/xhci-ring.c
> +++ b/drivers/usb/host/xhci-ring.c
> @@ -2152,6 +2152,11 @@ static void xhci_handle_event(struct xhci_hcd
> *xhci) }
>  	xhci_dbg(xhci, "%s - OS owns TRB\n", __func__);
> 
> +	/*
> +	 * Barrier between reading the TRB_CYCLE (valid) flag above and any
> +	 * speculative reads of the event's flags/data below.
> +	 */
> +	rmb();
>  	/* FIXME: Handle more event types. */
>  	switch ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK)) {

Isn't it the same memory that is being read the first time around? How 
reordering could happen here?

Thanks.


-- 
Dmitry

^ permalink raw reply

* Re: [PATCH v2 5/5] xhci: Remove recursive call to xhci_handle_event
From: Sarah Sharp @ 2011-03-29 18:34 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: linuxppc-dev, linux-usb, Sergei Shtylyov, Matt Evans
In-Reply-To: <1301356734.2402.657.camel@pasglop>

On Tue, Mar 29, 2011 at 10:58:54AM +1100, Benjamin Herrenschmidt wrote:
> On Mon, 2011-03-28 at 15:34 -0700, Sarah Sharp wrote:
> > 
> > What I'd like to do is take out the read of the status register out of
> > the interrupt handler (which is killing performance), and make it only
> > check the status register when xhci_handle_event() returns a negative
> > error status.  If the status register shows the host controller has a
> > critical error, the driver should call usb_hcd_died().
> 
> Be careful with removing that read...
> 
> Without MSIs, that read is what guarantees that all pending DMA writes
> by the xHCI have been "flushed" before you start poking at memory.
> 
> IE. If the chip writes an event and sends an LSI, without that read, you
> might get the interrupt before the writes to memory have completed and
> your driver will "miss" the event.
> 
> With MSIs (provided they are not broken on your PCI host bridge of
> course, this is typically the #1 cause of MSI breakage), you don't need
> that as the MSI itself is a DMA store by the device which is ordered
> after the stores done to update the event. So by the time you get the
> MSI interrupt, you -should- have all the updates visible in memory.
> 
> But that means that your PCI host bridge is doing the right thing, by
> ensuring whatever queues to the coherency domain it has have been
> properly flushed before it signals the interrupts caused by the MSI to
> the processors. Hopefully most systems get that right nowadays.
> 
> Point is: you need to keep that read if MSIs aren't enabled.

Sorry for the sloppy language, yes, I understand I still need the status
register read if only legacy IRQs are enabled.

Sarah Sharp

^ permalink raw reply

* Re: [PATCH 3/4] KVM: PPC: e500: Introduce msr_block for e500v2
From: Scott Wood @ 2011-03-29 17:26 UTC (permalink / raw)
  To: Alexander Graf; +Cc: linuxppc-dev
In-Reply-To: <76DF6B63-BCFC-4B8D-80A8-6C1578C6A22C@suse.de>

On Tue, 29 Mar 2011 11:37:44 +0200
Alexander Graf <agraf@suse.de> wrote:

> 
> On 28.03.2011, at 21:25, Scott Wood wrote:
> 
> > From: yu liu <yu.liu@freescale.com>
> > 
> > In order to use lazy SPE register save/restore, we need to
> > know when the guest is using MSR[SPE].  In order to do that, we
> > need to control the actual MSR[SPE] separately from the guest's
> > notion of MSR[SPE].
> 
> Please make this generic for BookE. There's no reason to have FSL ifdefs in the code.

Yeah, I was wondering about that too.  Will respin.

-Scott

^ permalink raw reply

* Re: [PATCH 4/4] KVM: PPC: e500: SPE switch between guest and host
From: Scott Wood @ 2011-03-29 17:25 UTC (permalink / raw)
  To: Alexander Graf; +Cc: linuxppc-dev
In-Reply-To: <6785E5D0-DEE9-4661-88A4-B35A99DB3C66@suse.de>

On Tue, 29 Mar 2011 11:47:51 +0200
Alexander Graf <agraf@suse.de> wrote:

> On 28.03.2011, at 21:25, Scott Wood wrote:
> 
> > @@ -344,10 +345,19 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
> > 		r = RESUME_GUEST;
> > 		break;
> > 
> > -	case BOOKE_INTERRUPT_SPE_UNAVAIL:
> > -		kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_UNAVAIL);
> > +#ifdef CONFIG_SPE
> > +	case BOOKE_INTERRUPT_SPE_UNAVAIL: {
> 
> This means that on non-SPE enabled host kernels you'll get a KVM fatal error when the guest triggers SPE_UNAVAIL, as the exit simply isn't handled and triggers:
> 
>         default:
>                 printk(KERN_EMERG "exit_nr %d\n", exit_nr);
>                 BUG();

Right, thanks for spotting -- will have it send an illegal instruction trap
to the guest in that case.

-Scott

^ permalink raw reply

* Re: How to define an I2C-to-SPI bridge device ?
From: Andre Schwarz @ 2011-03-29 16:21 UTC (permalink / raw)
  To: Grant Likely; +Cc: LinuxPPC List
In-Reply-To: <4D8C603F.6060501@matrix-vision.de>

On 03/25/2011 10:28 AM, Andre Schwarz wrote:
> Grant, Anton,

got it.
providing modalis = "spidev" within spi_board_info works like a charme ...

Cheers,
André

>
>>>> we're about to get new MPC8377 based hardware with various 
>>>> peripherals.
>>>>> There are two I2C-to-SPI bridge devices (NXP SC18IS602) and I'm 
>>>>> not sure
>>>>> how to define a proper dts...
>>>>>
>>>>> Of course it's an easy thing creating 2 child nodes on the CPU's I2C
>>>>> device - but how can I represent the created SPI bus ?
>>>> Um.. the same as the other SPI buses? I.e.
>>>>
>>>> i2c-controller {  /* SOC I2C controller */
>>>>     spi-controller {  /* The I2C-to-SPI bridge */
>>>>         spi-device@0 {
>>>>         };
>>>>         spi-device@1 {
>>>>         };
>>>>     };
>>>> };
>>>>
>>> ok , thanks - looks straight forward.
>>> Is this any more than plain definition, i.e. will this trigger any I2C
>>> or SPI device registration/linking ?
>>>>> Is the (possibly) required driver (of_sc18is60x_spi ?) supposed to 
>>>>> be an
>>>>> I2C slave or an SPI host driver ?
>>>> It should be an I2C driver that registers an SPI master (i.e.
>>>> calls spi_alloc_master() and spi_register_master()).
>>> hmm - ok. Will have to do it manually then ...
>> Yes, but this is the case for non-of drivers too.  The i2c to spi 
>> device driver must always create (and trigger population of) the spi 
>> bus instance.
>>
>
> I've kicked that I2C-to-SPI stuff completely because it's been too slow.
> We've connected the SPI busses to the FPGA controlling almost 
> everything now.
>
> Unfortunately there are some questions left :
>
> Following Anton's suggestion I've had a look at /drivers/mfd (sm501.c) 
> and implemented a pci driver for the FPGA using
> subdevices for additional functionality it exports - besides others we 
> now have 2 SPI masters.
>
> For both SPI masters I have created and registered a platform_device.
> pdev->dev is then fed into spi_alloc_master() and the resulting master 
> goes into spi_register_master().
>
> master->bus_num is set to 0 and 1, i.e. no dynamic numbering.
> master->chipselect = 8;
>
> Since I can probe the SPI device using FPGA intrinsic information I 
> decided to register the client
> devices on runtime using a "struct spi_board_info" which is fed into 
> spi_new_device().
>
> The current design has 2 clients on SPI-0 and 5 clients on SPI-1.
>
> static struct spi_board_info mergerbox_spi_boardinfo[] = {
>         {       .bus_num = 0,
>                 .chip_select = 0,
>                 .max_speed_hz = 4<<20, },
>         {       .bus_num = 0,
>                 .chip_select = 1,
>                 .max_speed_hz = 4<<20, },
>         {       .bus_num = 1,
>                 .chip_select = 0,
>                 .max_speed_hz = 4<<20, },
> .....
>
>
> After loading my module I get :
>
> #> ls /sys/devices/platform/AlteraSPI.0/
> /sys/devices/platform/AlteraSPI.0/modalias
> /sys/devices/platform/AlteraSPI.0/spi0.0/
> /sys/devices/platform/AlteraSPI.0/spi0.1/
> /sys/devices/platform/AlteraSPI.0/spi_master/
> /sys/devices/platform/AlteraSPI.0/subsystem/
> /sys/devices/platform/AlteraSPI.0/uevent
>
> #> ls /sys/devices/platform/AlteraSPI.1/
> /sys/devices/platform/AlteraSPI.1/modalias
> /sys/devices/platform/AlteraSPI.1/spi1.0/
> /sys/devices/platform/AlteraSPI.1/spi1.1/
> /sys/devices/platform/AlteraSPI.1/spi1.2/
> /sys/devices/platform/AlteraSPI.1/spi1.3/
> /sys/devices/platform/AlteraSPI.1/spi1.4/
> /sys/devices/platform/AlteraSPI.1/spi_master/
> /sys/devices/platform/AlteraSPI.1/subsystem/
> /sys/devices/platform/AlteraSPI.1/uevent
>
> What I'm missing are the /dev/spi* entries.
>
> There's also a spi_mpc8xxx driver using the CPU's SPI controller.
> It is configured by dts (2 devices) and uses dynamic bus numbering:
>
> #> ls /sys/bus/spi/devices/
> spi0.0      spi1.0      spi1.2      spi1.4      spi32766.1
> spi0.1      spi1.1      spi1.3      spi32766.0
>
> This devices are processed by spidev and proper entries are created 
> ready for use :
>
> #> ls /dev/spi*
> /dev/spidev32766.0  /dev/spidev32766.1
>
>
> Am I missing somehting obvious ?
>
> Since there's no driver registration we don't have a probe function - 
> is this a problem regarding device binding ?
>
> Do I need to use the .modalias in "struct spi_board_info" ?
>
>
> Any help is welcome.
>
> Regards,
> André


MATRIX VISION GmbH, Talstrasse 16, DE-71570 Oppenweiler
Registergericht: Amtsgericht Stuttgart, HRB 271090
Geschaeftsfuehrer: Gerhard Thullner, Werner Armingeon, Uwe Furtner

^ permalink raw reply

* [PATCH V2] POWER: perf_event: Skip updating kernel counters if register value shrinks
From: Eric B Munson @ 2011-03-29 14:51 UTC (permalink / raw)
  To: benh
  Cc: a.p.zijlstra, linux-kernel, paulus, anton, acme, mingo,
	linuxppc-dev, stable, Eric B Munson

Because of speculative event roll back, it is possible for some event coutners
to decrease between reads on POWER7.  This causes a problem with the way that
counters are updated.  Delta calues are calculated in a 64 bit value and the
top 32 bits are masked.  If the register value has decreased, this leaves us
with a very large positive value added to the kernel counters.  This patch
protects against this by skipping the update if the delta would be negative.
This can lead to a lack of precision in the coutner values, but from my testing
the value is typcially fewer than 10 samples at a time.

Signed-off-by: Eric B Munson <emunson@mgebm.net>
Cc: stable@kernel.org
---
Changes from V1:
 Updated patch leader
 Added stable CC
 Use an s32 to hold delta values and discard any values that are less than 0

 arch/powerpc/kernel/perf_event.c |   34 +++++++++++++++++++++++++++-------
 1 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/kernel/perf_event.c
index 97e0ae4..0a5178f 100644
--- a/arch/powerpc/kernel/perf_event.c
+++ b/arch/powerpc/kernel/perf_event.c
@@ -416,6 +416,15 @@ static void power_pmu_read(struct perf_event *event)
 		prev = local64_read(&event->hw.prev_count);
 		barrier();
 		val = read_pmc(event->hw.idx);
+		/*
+		 * POWER7 can roll back counter values, if the new value is
+		 * smaller than the previous value it will cause the delta
+		 * and the counter to have bogus values.  If this is the
+		 * case skip updating anything until the counter grows again.
+		 * This can lead to a small lack of precision in the counters.
+		 */
+		if (val < prev)
+			return;
 	} while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev);
 
 	/* The counters are only 32 bits wide */
@@ -439,7 +448,8 @@ static void freeze_limited_counters(struct cpu_hw_events *cpuhw,
 				    unsigned long pmc5, unsigned long pmc6)
 {
 	struct perf_event *event;
-	u64 val, prev, delta;
+	u64 val, prev;
+	s32 delta;
 	int i;
 
 	for (i = 0; i < cpuhw->n_limited; ++i) {
@@ -449,8 +459,13 @@ static void freeze_limited_counters(struct cpu_hw_events *cpuhw,
 		val = (event->hw.idx == 5) ? pmc5 : pmc6;
 		prev = local64_read(&event->hw.prev_count);
 		event->hw.idx = 0;
-		delta = (val - prev) & 0xfffffffful;
-		local64_add(delta, &event->count);
+		/*
+		 * The PerfMon registers are only 32 bits wide so the
+		 * delta should not overflow.
+		 */
+		delta = val - prev;
+		if (delta > 0)
+			local64_add(delta, &event->count);
 	}
 }
 
@@ -458,14 +473,16 @@ static void thaw_limited_counters(struct cpu_hw_events *cpuhw,
 				  unsigned long pmc5, unsigned long pmc6)
 {
 	struct perf_event *event;
-	u64 val;
+	u64 val, prev;
 	int i;
 
 	for (i = 0; i < cpuhw->n_limited; ++i) {
 		event = cpuhw->limited_counter[i];
 		event->hw.idx = cpuhw->limited_hwidx[i];
 		val = (event->hw.idx == 5) ? pmc5 : pmc6;
-		local64_set(&event->hw.prev_count, val);
+		prev = local64_read(&event->hw.prev_count);
+		if (val > prev)
+			local64_set(&event->hw.prev_count, val);
 		perf_event_update_userpage(event);
 	}
 }
@@ -1187,7 +1204,8 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
 			       struct pt_regs *regs, int nmi)
 {
 	u64 period = event->hw.sample_period;
-	s64 prev, delta, left;
+	s64 prev, left;
+	s32 delta;
 	int record = 0;
 
 	if (event->hw.state & PERF_HES_STOPPED) {
@@ -1197,7 +1215,9 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
 
 	/* we don't have to worry about interrupts here */
 	prev = local64_read(&event->hw.prev_count);
-	delta = (val - prev) & 0xfffffffful;
+	delta = val - prev;
+	if (delta < 0)
+		delta = 0;
 	local64_add(delta, &event->count);
 
 	/*
-- 
1.7.1

^ permalink raw reply related

* Re: [PATCH] POWER: perf_event: Skip updating kernel counters if register value shrinks
From: Eric B Munson @ 2011-03-29 14:25 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: a.p.zijlstra, linux-kernel, paulus, anton, acme, mingo,
	linuxppc-dev
In-Reply-To: <1301378637.2402.671.camel@pasglop>

[-- Attachment #1: Type: text/plain, Size: 2077 bytes --]

On Tue, 29 Mar 2011, Benjamin Herrenschmidt wrote:

> On Fri, 2011-03-25 at 09:28 -0400, Eric B Munson wrote:
> > It is possible on POWER7 for some perf events to have values decrease.  This
> > causes a problem with the way the kernel counters are updated.  Deltas are
> > computed and then stored in a 64 bit value while the registers are 32 bits
> > wide so if new value is smaller than previous value, the delta is a very
> > large positive value.  As a work around this patch skips updating the kernel
> > counter in when the new value is smaller than the previous.  This can lead to
> > a lack of precision in the coutner values, but from my testing the value is
> > typcially fewer than 10 samples at a time.
> 
> Unfortunately the patch isn't 100% correct I believe:
> 
> I think you don't deal with the rollover of the counters. The new value
> could be smaller than the previous one simply because the counter just
> rolled over.
> 
> In cases like this:
> 
> > @@ -449,8 +458,10 @@ static void freeze_limited_counters(struct cpu_hw_events *cpuhw,
> >  		val = (event->hw.idx == 5) ? pmc5 : pmc6;
> >  		prev = local64_read(&event->hw.prev_count);
> >  		event->hw.idx = 0;
> > -		delta = (val - prev) & 0xfffffffful;
> > -		local64_add(delta, &event->count);
> > +		if (val >= prev) {
> > +			delta = (val - prev) & 0xfffffffful;
> > +			local64_add(delta, &event->count);
> > +		}
> >  	}
> >  }
> 
> I wonder if it isn't easier to just define delta to be a s32, get rid
> of the mask and test if delta is positive, something like:
> 
> 		delta =  val - prev;
> 		if (delta > 0)
> 			local64_add(delta, &event->count);
> 
> Wouldn't that be simpler ? Or do I miss a reason why it wouldn't work ?

Here I made the assumption that the hardware would never remove more events in
a speculative roll back than it had added.  This is not a situation I
encoutered in my limited testing, so I didn't think underflow was possible.  I
will send out a V2 using the signed 32 bit delta and remeber to CC stable
this time.

Eric

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

^ permalink raw reply

* Re: [PATCH v10 10/10] USB ppc4xx: Add Synopsys DWC OTG driver kernel configuration and Makefile
From: Sergei Shtylyov @ 2011-03-29 12:01 UTC (permalink / raw)
  To: tmarri; +Cc: Mark Miesfeld, greg, linux-usb, linuxppc-dev, Fushen Chen
In-Reply-To: <1301336896-2300-1-git-send-email-tmarri@apm.com>

Hello.

On 28-03-2011 22:28, tmarri@apm.com wrote:

> From: Tirumala Marri <tmarri@apm.com>

> Add Synopsys DesignWare HS USB OTG driver kernel configuration.
> Synopsys OTG driver may operate in  host only, device only, or OTG mode.
> The driver also allows user configure the core to use its internal DMA
> or Slave (PIO) mode.

> Signed-off-by: Tirumala R Marri <tmarri@apm.com>
> Signed-off-by: Fushen Chen <fchen@apm.com>
> Signed-off-by: Mark Miesfeld <mmiesfeld@apm.com>

    This patch should precede patch 9 as patch 9 uses config. options defined 
here.

> diff --git a/drivers/usb/otg/dwc/Kconfig b/drivers/usb/otg/dwc/Kconfig
> new file mode 100644
> index 0000000..a8f22cb
> --- /dev/null
> +++ b/drivers/usb/otg/dwc/Kconfig
> @@ -0,0 +1,88 @@
> +#
> +# USB Dual Role (OTG-ready) Controller Drivers
> +# for silicon based on Synopsys DesignWare IP
> +#
[...]
> +# enable peripheral support (including with OTG)
> +config USB_GADGET_DWC_HDRC
> +	bool
> +	depends on USB_DWC_OTG && (DWC_DEVICE_ONLY || USB_DWC_OTG)

    Haven't we just defined this in patch 9? Redefinition of options isn't 
correct.

> +config DWC_OTG_REG_LE
> +	bool "DWC Little Endian Register"

    This should preferrably be passed via the platform data, I think.

> +	depends on USB_DWC_OTG
> +	default y
> +	help
> +	  OTG core register access is Little-Endian.
> +
> +config DWC_OTG_FIFO_LE
> +	bool "DWC FIFO Little Endian"

    This too.

> +	depends on USB_DWC_OTG
> +	default n

    "default n" not needed.

> +	help
> +	  OTG core FIFO access is Little-Endian.

    Little endian registers and big endian FIFO by default?

> +
> +config DWC_LIMITED_XFER_SIZE
> +	bool "DWC Endpoint Limited Xfer Size"
> +	depends on USB_GADGET_DWC_HDRC
> +	default n

    Not needed.

> +	help
> +	  Bit fields in the Device EP Transfer Size Register is 11 bits.

WBR, Sergei

^ permalink raw reply

* Re: [PATCH v10 09/10] USB/ppc4xx:Synopsys DWC OTG driver enable gadget support
From: Sergei Shtylyov @ 2011-03-29 11:53 UTC (permalink / raw)
  To: tmarri; +Cc: Mark Miesfeld, greg, linux-usb, linuxppc-dev, Fushen Chen
In-Reply-To: <1301336892-2268-1-git-send-email-tmarri@apm.com>

Hello.

On 28-03-2011 22:28, tmarri@apm.com wrote:

> From: Tirumala Marri <tmarri@apm.com>

> Enable gadget support

> Signed-off-by: Tirumala R Marri <tmarri@apm.com>
> Signed-off-by: Fushen Chen <fchen@apm.com>
> Signed-off-by: Mark Miesfeld <mmiesfeld@apm.com>
[...]

> diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
> index bc5123c..61aca75 100644
> --- a/drivers/usb/gadget/Kconfig
> +++ b/drivers/usb/gadget/Kconfig
> @@ -365,6 +365,28 @@ config USB_GADGET_MUSB_HDRC
>   	  This OTG-capable silicon IP is used in dual designs including
>   	  the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin
>
> +# dwc_otg builds in ../dwc_otg along with host support

    There's no ../dwc_otg any longer.

> +config USB_GADGET_DWC_HDRC
> +	boolean "DesignWare USB Peripheral"
> +	depends on DWC_OTG_MODE || DWC_DEVICE_ONLY
> +	select USB_GADGET_DUALSPEED
> +	select USB_GADGET_SELECTED
> +	select USB_GADGET_DWC_OTG
> +	help
> +	This OTG-capable Designware USB IP
> +
> +config USB_GADGET_DWC_OTG
> +	boolean "OTG Support"
> +	depends on USB_GADGET_DWC_HDRC

    Not on DWC_OTG_MODE? How this option is different from DWC_OTG_MODE?

> +	help
> +	The most notable feature of USB OTG is support for a
> +	"Dual-Role" device, which can act as either a device
> +	or a host.  The initial role choice can be changed
> +	later, when two dual-role devices talk to each other.
> +	Select this only if your board has a Mini-AB connector.
> +
> +
> +

     Too many empty lines.

>   config USB_GADGET_M66592
>   	boolean "Renesas M66592 USB Peripheral Controller"
>   	select USB_GADGET_DUALSPEED

WBR, Sergei

^ permalink raw reply

* RE: [PATCH v10 00/10] Add-Synopsys-DesignWare-HS-USB-OTG-driver
From: Keshava Munegowda @ 2011-03-29 10:58 UTC (permalink / raw)
  To: tmarri, linux-usb, linuxppc-dev; +Cc: greg
In-Reply-To: <1301336856-1802-1-git-send-email-tmarri@apm.com>

> -----Original Message-----
> From: linux-usb-owner@vger.kernel.org
[mailto:linux-usb-owner@vger.kernel.org] On Behalf Of
> tmarri@apm.com
> Sent: Monday, March 28, 2011 11:58 PM
> To: linux-usb@vger.kernel.org; linuxppc-dev@lists.ozlabs.org
> Cc: greg@kroah.com; tmarri@apm.com
> Subject: [PATCH v10 00/10] Add-Synopsys-DesignWare-HS-USB-OTG-driver
>
> From: Tirumala Marri <tmarri@apm.com>
>
> v10:
>  1. Change address argument type from u32 to ulong to
>     make it arch independent.
>  2. Cleaning un-necasary changes from Kconfig.
>
> v9:
>  1. Move the source under usb/otg/dwc.
>  2. Rename the source files with out dwc_otg prefix.
>  3. Remove unused read/write modify functions.
>  4. Including changes related to register base print.
>
> Tirumala Marri (10):
>   USB/ppc4xx: Add Synopsys DWC OTG Register definitions
>   USB/ppc4xx: Add Synopsys DWC OTG driver framework
>   USB/ppc4xx: Add Synopsys DWC OTG Core Interface Layer (CIL)
>   USB/ppc4xx: Add Synopsys DWC OTG HCD function
>   USB/ppc4xx: Add Synopsys DWC OTG HCD interrupt function
>   USB/ppc4xx: Add Synopsys DWC OTG HCD queue function
>   USB/ppc4xx: Add Synopsys DWC OTG PCD function
>   USB ppc4xx: Add Synopsys DWC OTG PCD interrupt function
>   USB/ppc4xx:Synopsys DWC OTG driver enable gadget support
>   USB ppc4xx: Add Synopsys DWC OTG driver kernel configuration and
>     Makefile
>
>  drivers/Makefile                  |    1 +
>  drivers/usb/Kconfig               |    2 +
>  drivers/usb/gadget/Kconfig        |   22 +
>  drivers/usb/gadget/gadget_chips.h |    9 +
>  drivers/usb/otg/dwc/Kconfig       |   88 ++
>  drivers/usb/otg/dwc/Makefile      |   19 +
>  drivers/usb/otg/dwc/apmppc.c      |  414 +++++++
>  drivers/usb/otg/dwc/cil.c         |  972 +++++++++++++++
>  drivers/usb/otg/dwc/cil.h         | 1177 ++++++++++++++++++
>  drivers/usb/otg/dwc/cil_intr.c    |  616 +++++++++
>  drivers/usb/otg/dwc/driver.h      |   76 ++
>  drivers/usb/otg/dwc/hcd.c         | 2465
+++++++++++++++++++++++++++++++++++++
>  drivers/usb/otg/dwc/hcd.h         |  416 +++++++
>  drivers/usb/otg/dwc/hcd_intr.c    | 1477 ++++++++++++++++++++++
>  drivers/usb/otg/dwc/hcd_queue.c   |  696 +++++++++++
>  drivers/usb/otg/dwc/param.c       |  180 +++
>  drivers/usb/otg/dwc/pcd.c         | 1766 ++++++++++++++++++++++++++
>  drivers/usb/otg/dwc/pcd.h         |  139 +++
>  drivers/usb/otg/dwc/pcd_intr.c    | 2311
++++++++++++++++++++++++++++++++++
>  drivers/usb/otg/dwc/regs.h        | 1326 ++++++++++++++++++++
>  20 files changed, 14172 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/usb/otg/dwc/Kconfig
>  create mode 100644 drivers/usb/otg/dwc/Makefile
>  create mode 100644 drivers/usb/otg/dwc/apmppc.c
>  create mode 100644 drivers/usb/otg/dwc/cil.c
>  create mode 100644 drivers/usb/otg/dwc/cil.h
>  create mode 100644 drivers/usb/otg/dwc/cil_intr.c
>  create mode 100644 drivers/usb/otg/dwc/driver.h
>  create mode 100644 drivers/usb/otg/dwc/hcd.c
>  create mode 100644 drivers/usb/otg/dwc/hcd.h
>  create mode 100644 drivers/usb/otg/dwc/hcd_intr.c
>  create mode 100644 drivers/usb/otg/dwc/hcd_queue.c
>  create mode 100644 drivers/usb/otg/dwc/param.c
>  create mode 100644 drivers/usb/otg/dwc/pcd.c
>  create mode 100644 drivers/usb/otg/dwc/pcd.h
>  create mode 100644 drivers/usb/otg/dwc/pcd_intr.c
>  create mode 100644 drivers/usb/otg/dwc/regs.h
>
> --

Just a cosmetic review comment: you need to Tabify the declarations of in
the functions, at least when you are declaring variable of different data
types


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

^ permalink raw reply

* RE: [PATCH v10 04/10] USB/ppc4xx: Add Synopsys DWC OTG HCD function
From: Keshava Munegowda @ 2011-03-29 10:55 UTC (permalink / raw)
  To: tmarri, linux-usb, linuxppc-dev; +Cc: greg, Mark Miesfeld, Fushen Chen
In-Reply-To: <1301336869-1944-1-git-send-email-tmarri@apm.com>

> -----Original Message-----
> From: linux-usb-owner@vger.kernel.org
[mailto:linux-usb-owner@vger.kernel.org] On Behalf Of
> tmarri@apm.com
> Sent: Monday, March 28, 2011 11:58 PM
> To: linux-usb@vger.kernel.org; linuxppc-dev@lists.ozlabs.org
> Cc: greg@kroah.com; tmarri@apm.com; Fushen Chen; Mark Miesfeld
> Subject: [PATCH v10 04/10] USB/ppc4xx: Add Synopsys DWC OTG HCD function
>
> From: Tirumala Marri <tmarri@apm.com>
>
> Implements DWC OTG USB Host Controller Driver (HCD) and interface to
> USB Host controller Driver framework.
>
> Signed-off-by: Tirumala R Marri <tmarri@apm.com>
> Signed-off-by: Fushen Chen <fchen@apm.com>
> Signed-off-by: Mark Miesfeld <mmiesfeld@apm.com>
> ---
>  drivers/usb/otg/dwc/hcd.c | 2465
+++++++++++++++++++++++++++++++++++++++++++++
>  drivers/usb/otg/dwc/hcd.h |  416 ++++++++
>  2 files changed, 2881 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/usb/otg/dwc/hcd.c
>  create mode 100644 drivers/usb/otg/dwc/hcd.h
>
> diff --git a/drivers/usb/otg/dwc/hcd.c b/drivers/usb/otg/dwc/hcd.c
> new file mode 100644
> index 0000000..884bf31
> --- /dev/null
> +++ b/drivers/usb/otg/dwc/hcd.c
> @@ -0,0 +1,2465 @@
> +/*
> + * DesignWare HS OTG controller driver
> + * Copyright (C) 2006 Synopsys, Inc.
> + * Portions Copyright (C) 2010 Applied Micro Circuits Corporation.
> + *
> + * This program is free software: you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License version 2 for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see http://www.gnu.org/licenses
> + * or write to the Free Software Foundation, Inc., 51 Franklin Street,
> + * Suite 500, Boston, MA 02110-1335 USA.
> + *
> + * Based on Synopsys driver version 2.60a
> + * Modified by Mark Miesfeld <mmiesfeld@apm.com>
> + * Modified by Stefan Roese <sr@denx.de>, DENX Software Engineering
> + * Modified by Chuck Meade <chuck@theptrgroup.com>
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS"
> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO
THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE
> + * ARE DISCLAIMED. IN NO EVENT SHALL SYNOPSYS, INC. BE LIABLE FOR ANY
DIRECT,
> + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES
> + * (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES;
> + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND
> + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + */
> +
> +/*
> + * This file contains the implementation of the HCD. In Linux, the HCD
> + * implements the hc_driver API.
> + */
> +
> +#include <asm/unaligned.h>
> +#include <linux/dma-mapping.h>
> +
> +#include "hcd.h"
> +
> +static const char dwc_otg_hcd_name[] = "dwc_otg_hcd";
> +
> +/**
> + * Clears the transfer state for a host channel. This function is
normally
> + * called after a transfer is done and the host channel is being
released. It
> + * clears the channel interrupt enables and any unhandled channel
interrupt
> + * conditions.
> + */
> +void dwc_otg_hc_cleanup(struct core_if *core_if, struct dwc_hc *hc)
> +{
> +	ulong regs;
> +
> +	hc->xfer_started = 0;
> +	regs = core_if->host_if->hc_regs[hc->hc_num];
> +	dwc_write32(regs + DWC_HCINTMSK, 0);
> +	dwc_write32(regs + DWC_HCINT, 0xFFFFFFFF);
> +}
> +
> +/**
> + * This function enables the Host mode interrupts.
> + */
> +static void dwc_otg_enable_host_interrupts(struct core_if *core_if)
> +{
> +	ulong global_regs = core_if->core_global_regs;
> +	u32 intr_mask = 0;
> +
> +	/* Disable all interrupts. */
> +	dwc_write32(global_regs + DWC_GINTMSK, 0);
> +
> +	/* Clear any pending interrupts. */
> +	dwc_write32(global_regs + DWC_GINTSTS, 0xFFFFFFFF);
> +
> +	/* Enable the common interrupts */
> +	dwc_otg_enable_common_interrupts(core_if);
> +
> +	/*
> +	 * Enable host mode interrupts without disturbing common
> +	 * interrupts.
> +	 */
> +	intr_mask |= DWC_INTMSK_STRT_OF_FRM;
> +	intr_mask |= DWC_INTMSK_HST_PORT;
> +	intr_mask |= DWC_INTMSK_HST_CHAN;
> +	dwc_modify32(global_regs + DWC_GINTMSK, intr_mask, intr_mask);
> +}
> +
> +/**
> + * This function initializes the DWC_otg controller registers for
> + * host mode.
> + *
> + * This function flushes the Tx and Rx FIFOs and it flushes any entries
in the
> + * request queues. Host channels are reset to ensure that they are
ready for
> + * performing transfers.
> + */
> +static void dwc_otg_core_host_init(struct core_if *core_if)
> +{
> +	ulong global_regs = core_if->core_global_regs;
> +	struct dwc_host_if *host_if = core_if->host_if;
> +	struct core_params *params = core_if->core_params;
> +	u32 hprt0 = 0;
> +	u32 nptxfifosize = 0;
> +	u32 ptxfifosize = 0;
> +	u32 i;
> +	u32 hcchar;
> +	ulong hcfg;
> +	ulong hc_regs;
> +	int num_channels;
> +	u32 gotgctl = 0;

Tabify the declarations ;


> +
> +	/* Restart the Phy Clock */
> +	dwc_write32(core_if->pcgcctl, 0);
> +
> +	/* Initialize Host Configuration Register */
> +	init_fslspclksel(core_if);
> +	if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
> +		hcfg = dwc_read32(host_if->host_global_regs + DWC_HCFG);
> +		hcfg = DWC_HCFG_FSLSUPP_RW(hcfg, 1);
> +		dwc_write32(host_if->host_global_regs + DWC_HCFG, hcfg);
> +	}
> +
> +	/* Configure data FIFO sizes */
> +	if (DWC_HWCFG2_DYN_FIFO_RD(core_if->hwcfg2)
> +	    && params->enable_dynamic_fifo) {
> +		/* Rx FIFO */
> +		dwc_write32(global_regs + DWC_GRXFSIZ,
> +			    params->host_rx_fifo_size);
> +
> +		/* Non-periodic Tx FIFO */
> +		nptxfifosize = DWC_RX_FIFO_DEPTH_WR(nptxfifosize,
> +						    params->
> +
host_nperio_tx_fifo_size);
> +		nptxfifosize =
> +		    DWC_RX_FIFO_START_ADDR_WR(nptxfifosize,
> +					      params->host_rx_fifo_size);
> +		dwc_write32(global_regs + DWC_GNPTXFSIZ, nptxfifosize);
> +
> +		/* Periodic Tx FIFO */
> +		ptxfifosize = DWC_RX_FIFO_DEPTH_WR(ptxfifosize,
> +						   params->
> +
host_perio_tx_fifo_size);
> +		ptxfifosize =
> +		    DWC_RX_FIFO_START_ADDR_WR(ptxfifosize,
> +					      (DWC_RX_FIFO_START_ADDR_RD
> +					       (nptxfifosize) +
> +					       DWC_RX_FIFO_DEPTH_RD
> +					       (nptxfifosize)));
> +		dwc_write32(global_regs + DWC_HPTXFSIZ, ptxfifosize);
> +	}
> +
> +	/* Clear Host Set HNP Enable in the OTG Control Register */
> +	gotgctl |= DWC_GCTL_HOST_HNP_ENA;
> +	dwc_modify32(global_regs + DWC_GOTGCTL, gotgctl, 0);
> +
> +	/* Make sure the FIFOs are flushed. */
> +	dwc_otg_flush_tx_fifo(core_if, DWC_GRSTCTL_TXFNUM_ALL);
> +	dwc_otg_flush_rx_fifo(core_if);
> +
> +	/* Flush out any leftover queued requests. */
> +	num_channels = core_if->core_params->host_channels;
> +	for (i = 0; i < num_channels; i++) {
> +		hc_regs = core_if->host_if->hc_regs[i];
> +		hcchar = dwc_read32(hc_regs + DWC_HCCHAR);
> +		hcchar = DWC_HCCHAR_ENA_RW(hcchar, 0);
> +		hcchar = DWC_HCCHAR_DIS_RW(hcchar, 1);
> +		hcchar = DWC_HCCHAR_EPDIR_RW(hcchar, 0);
> +		dwc_write32(hc_regs + DWC_HCCHAR, hcchar);
> +	}
> +
> +	/* Halt all channels to put them into a known state. */
> +	for (i = 0; i < num_channels; i++) {
> +		int count = 0;
> +
> +		hc_regs = core_if->host_if->hc_regs[i];
> +		hcchar = dwc_read32(hc_regs + DWC_HCCHAR);
> +		hcchar = DWC_HCCHAR_ENA_RW(hcchar, 1);
> +		hcchar = DWC_HCCHAR_DIS_RW(hcchar, 1);
> +		hcchar = DWC_HCCHAR_EPDIR_RW(hcchar, 0);
> +		dwc_write32(hc_regs + DWC_HCCHAR, hcchar);
> +
> +		do {
> +			hcchar = dwc_read32(hc_regs + DWC_HCCHAR);
> +			if (++count > 200) {
> +				pr_err("%s: Unable to clear halt on "
> +				       "channel %d\n", __func__, i);
> +				break;
> +			}
> +			udelay(100);
> +		} while (DWC_HCCHAR_ENA_RD(hcchar));
> +	}
> +
> +	/* Turn on the vbus power. */
> +	pr_info("Init: Port Power? op_state=%s\n",
> +		op_state_str(core_if->xceiv->state));
> +
> +	if (core_if->xceiv->state == OTG_STATE_A_HOST) {
> +		hprt0 = dwc_otg_read_hprt0(core_if);
> +		pr_info("Init: Power Port (%d)\n",
DWC_HPRT0_PRT_PWR_RD(hprt0));
> +		if (DWC_HPRT0_PRT_PWR_RD(hprt0) == 0) {
> +			hprt0 = DWC_HPRT0_PRT_PWR_RW(hprt0, 1);
> +			dwc_write32(host_if->hprt0, hprt0);
> +		}
> +	}
> +	dwc_otg_enable_host_interrupts(core_if);
> +}
> +
> +/**
> + * Initializes dynamic portions of the DWC_otg HCD state.
> + */
> +static void hcd_reinit(struct dwc_hcd *hcd)
> +{
> +	struct list_head *item;
> +	int num_channels;
> +	u32 i;
> +	struct dwc_hc *channel;

Tabify the declarations ;

> +
> +	hcd->flags.d32 = 0;
> +	hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active;
> +	hcd->available_host_channels =
hcd->core_if->core_params->host_channels;
> +
> +	/*
> +	 * Put all channels in the free channel list and clean up channel
> +	 * states.
> +	 */
> +	item = hcd->free_hc_list.next;
> +	while (item != &hcd->free_hc_list) {
> +		list_del(item);
> +		item = hcd->free_hc_list.next;
> +	}
> +
> +	num_channels = hcd->core_if->core_params->host_channels;
> +	for (i = 0; i < num_channels; i++) {
> +		channel = hcd->hc_ptr_array[i];
> +		list_add_tail(&channel->hc_list_entry,
&hcd->free_hc_list);
> +		dwc_otg_hc_cleanup(hcd->core_if, channel);
> +	}
> +
> +	/* Initialize the DWC core for host mode operation. */
> +	dwc_otg_core_host_init(hcd->core_if);
> +}
> +
> +/* Gets the dwc_hcd from a struct usb_hcd */
> +static inline struct dwc_hcd *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd)
> +{
> +	return (struct dwc_hcd *)hcd->hcd_priv;
> +}
> +
> +/**
> + * Initializes the DWC_otg controller and its root hub and prepares it
for host
> + * mode operation. Activates the root port. Returns 0 on success and a
negative
> + * error code on failure.
> +*/
> +static int dwc_otg_hcd_start(struct usb_hcd *hcd)
> +{
> +	struct dwc_hcd *dwc_hcd = hcd_to_dwc_otg_hcd(hcd);
> +	struct usb_bus *bus = hcd_to_bus(hcd);
> +
> +	hcd->state = HC_STATE_RUNNING;
> +
> +	/* Inform the HUB driver to resume. */
> +	if (bus->root_hub)
> +		usb_hcd_resume_root_hub(hcd);
> +
> +	hcd_reinit(dwc_hcd);
> +	return 0;
> +}
> +
> +/**
> + * Work queue function for starting the HCD when A-Cable is connected.
> + * The dwc_otg_hcd_start() must be called in a process context.
> + */
> +static void hcd_start_func(struct work_struct *work)
> +{
> +	struct dwc_hcd *priv = container_of(work, struct dwc_hcd,
start_work);
> +	struct usb_hcd *usb_hcd = (struct usb_hcd *)priv->_p;
> +
> +	if (usb_hcd)
> +		dwc_otg_hcd_start(usb_hcd);
> +}
> +
> +/**
> + * HCD Callback function for starting the HCD when A-Cable is
> + * connected.
> + */
> +static int dwc_otg_hcd_start_cb(void *_p)
> +{
> +	struct dwc_hcd *dwc_hcd = hcd_to_dwc_otg_hcd(_p);
> +	struct core_if *core_if = dwc_hcd->core_if;
> +	u32 hprt0;

Tabify the declarations ;

> +
> +	if (core_if->xceiv->state == OTG_STATE_B_HOST) {
> +		/*
> +		 * Reset the port.  During a HNP mode switch the reset
> +		 * needs to occur within 1ms and have a duration of at
> +		 * least 50ms.
> +		 */
> +		hprt0 = dwc_otg_read_hprt0(core_if);
> +		hprt0 = DWC_HPRT0_PRT_RST_RW(hprt0, 1);
> +		dwc_write32(core_if->host_if->hprt0, hprt0);
> +		((struct usb_hcd *)_p)->self.is_b_host = 1;
> +	} else {
> +		((struct usb_hcd *)_p)->self.is_b_host = 0;
> +	}
> +
> +	/* Need to start the HCD in a non-interrupt context. */
> +	dwc_hcd->_p = _p;
> +	schedule_work(&dwc_hcd->start_work);
> +	return 1;
> +}
> +
> +/**
> + * This function disables the Host Mode interrupts.
> + */
> +static void dwc_otg_disable_host_interrupts(struct core_if *core_if)
> +{
> +	u32 global_regs = core_if->core_global_regs;
> +	u32 intr_mask = 0;
> +
> +	/*
> +	 * Disable host mode interrupts without disturbing common
> +	 * interrupts.
> +	 */
> +	intr_mask |= DWC_INTMSK_STRT_OF_FRM;
> +	intr_mask |= DWC_INTMSK_HST_PORT;
> +	intr_mask |= DWC_INTMSK_HST_CHAN;
> +	intr_mask |= DWC_INTMSK_P_TXFIFO_EMPTY;
> +	intr_mask |= DWC_INTMSK_NP_TXFIFO_EMPT;
> +	dwc_modify32(global_regs + DWC_GINTMSK, intr_mask, 0);
> +}
> +
> +/**
> + * Halts the DWC_otg host mode operations in a clean manner. USB
transfers are
> + * stopped.
> + */
> +static void dwc_otg_hcd_stop(struct usb_hcd *hcd)
> +{
> +	struct dwc_hcd *dwc_hcd = hcd_to_dwc_otg_hcd(hcd);
> +	u32 hprt0 = 0;
> +
> +	/* Turn off all host-specific interrupts. */
> +	dwc_otg_disable_host_interrupts(dwc_hcd->core_if);
> +
> +	/*
> +	 * The root hub should be disconnected before this function is
called.
> +	 * The disconnect will clear the QTD lists (via
..._hcd_urb_dequeue)
> +	 * and the QH lists (via ..._hcd_endpoint_disable).
> +	 */
> +
> +	/* Turn off the vbus power */
> +	pr_info("PortPower off\n");
> +	hprt0 = DWC_HPRT0_PRT_PWR_RW(hprt0, 0);
> +	dwc_write32(dwc_hcd->core_if->host_if->hprt0, hprt0);
> +}
> +
> +/**
> + * HCD Callback function for stopping the HCD.
> + */
> +static int dwc_otg_hcd_stop_cb(void *_p)
> +{
> +	struct usb_hcd *usb_hcd = (struct usb_hcd *)_p;
> +
> +	dwc_otg_hcd_stop(usb_hcd);
> +	return 1;
> +}
> +
> +static void del_timers(struct dwc_hcd *hcd)
> +{
> +	del_timer_sync(&hcd->conn_timer);
> +}
> +
> +/**
> + * Processes all the URBs in a single list of QHs. Completes them with
> + * -ETIMEDOUT and frees the QTD.
> + */
> +static void kill_urbs_in_qh_list(struct dwc_hcd *hcd, struct list_head
*qh_list)
> +{
> +	struct list_head *qh_item, *q;
> +
> +	qh_item = qh_list->next;
> +	list_for_each_safe(qh_item, q, qh_list) {
> +		struct dwc_qh *qh;
> +		struct list_head *qtd_item;
> +		struct dwc_qtd *qtd;
> +
> +		qh = list_entry(qh_item, struct dwc_qh, qh_list_entry);
> +		qtd_item = qh->qtd_list.next;
> +		qtd = list_entry(qtd_item, struct dwc_qtd,
qtd_list_entry);
> +		if (qtd->urb != NULL) {
> +			spin_lock(&hcd->lock);
> +			dwc_otg_hcd_complete_urb(hcd, qtd->urb,
-ETIMEDOUT);
> +			dwc_otg_hcd_qtd_remove_and_free(qtd);
> +			spin_unlock(&hcd->lock);
> +		}
> +	}
> +}
> +
> +/**
> + * Responds with an error status of ETIMEDOUT to all URBs in the
non-periodic
> + * and periodic schedules. The QTD associated with each URB is removed
from
> + * the schedule and freed. This function may be called when a
disconnect is
> + * detected or when the HCD is being stopped.
> + */
> +static void kill_all_urbs(struct dwc_hcd *hcd)
> +{
> +	kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_deferred);
> +	kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_inactive);
> +	kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_active);
> +	kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_inactive);
> +	kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_ready);
> +	kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_assigned);
> +	kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_queued);
> +}
> +
> +/**
> + * HCD Callback function for disconnect of the HCD.
> + */
> +static int dwc_otg_hcd_disconnect_cb(void *_p)
> +{
> +	u32 intr;
> +	struct dwc_hcd *hcd = hcd_to_dwc_otg_hcd(_p);
> +	struct core_if *core_if = hcd->core_if;
> +
> +	/* Set status flags for the hub driver. */
> +	hcd->flags.b.port_connect_status_change = 1;
> +	hcd->flags.b.port_connect_status = 0;
> +
> +	/*
> +	 * Shutdown any transfers in process by clearing the Tx FIFO Empty
> +	 * interrupt mask and status bits and disabling subsequent host
> +	 * channel interrupts.
> +	 */
> +	intr = 0;
> +	intr |= DWC_INTMSK_NP_TXFIFO_EMPT;
> +	intr |= DWC_INTMSK_P_TXFIFO_EMPTY;
> +	intr |= DWC_INTMSK_HST_CHAN;
> +	dwc_modify32(gintmsk_reg(hcd), intr, 0);
> +	dwc_modify32(gintsts_reg(hcd), intr, 0);
> +
> +	del_timers(hcd);
> +
> +	/*
> +	 * Turn off the vbus power only if the core has transitioned to
device
> +	 * mode. If still in host mode, need to keep power on to detect a
> +	 * reconnection.
> +	 */
> +	if (dwc_otg_is_device_mode(core_if)) {
> +		if (core_if->xceiv->state != OTG_STATE_A_SUSPEND) {
> +			u32 hprt0 = 0;
> +
> +			pr_info("Disconnect: PortPower off\n");
> +			hprt0 = DWC_HPRT0_PRT_PWR_RW(hprt0, 0);
> +			dwc_write32(core_if->host_if->hprt0, hprt0);
> +		}
> +		dwc_otg_disable_host_interrupts(core_if);
> +	}
> +
> +	/* Respond with an error status to all URBs in the schedule. */
> +	kill_all_urbs(hcd);
> +	if (dwc_otg_is_host_mode(core_if)) {
> +		/* Clean up any host channels that were in use. */
> +		int num_channels;
> +		u32 i;
> +		struct dwc_hc *channel;
> +		ulong regs;
> +		u32 hcchar;
> +
> +		num_channels = core_if->core_params->host_channels;
> +		if (!core_if->dma_enable) {
> +			/* Flush out any channel requests in slave mode.
*/
> +			for (i = 0; i < num_channels; i++) {
> +				channel = hcd->hc_ptr_array[i];
> +				if (list_empty(&channel->hc_list_entry)) {
> +					regs =
> +					    core_if->host_if->hc_regs[i];
> +					hcchar = dwc_read32(regs +
DWC_HCCHAR);
> +
> +					if (DWC_HCCHAR_ENA_RD(hcchar)) {
> +						hcchar =
> +
DWC_HCCHAR_ENA_RW(hcchar,
> +								      0);
> +						hcchar =
> +
DWC_HCCHAR_DIS_RW(hcchar,
> +								      1);
> +						hcchar =
> +
DWC_HCCHAR_EPDIR_RW(hcchar,
> +
0);
> +						dwc_write32(regs +
DWC_HCCHAR,
> +							    hcchar);
> +					}
> +				}
> +			}
> +		}
> +
> +		for (i = 0; i < num_channels; i++) {
> +			channel = hcd->hc_ptr_array[i];
> +			if (list_empty(&channel->hc_list_entry)) {
> +				regs = core_if->host_if->hc_regs[i];
> +				hcchar = dwc_read32(regs + DWC_HCCHAR);
> +
> +				if (DWC_HCCHAR_ENA_RD(hcchar)) {
> +					/* Halt the channel. */
> +					hcchar = DWC_HCCHAR_DIS_RW(hcchar,
1);
> +					dwc_write32(regs + DWC_HCCHAR,
hcchar);
> +				}
> +				dwc_otg_hc_cleanup(core_if, channel);
> +				list_add_tail(&channel->hc_list_entry,
> +					      &hcd->free_hc_list);
> +			}
> +		}
> +	}
> +
> +	/*
> +	 * A disconnect will end the session so the B-Device is no
> +	 * longer a B-host.
> +	 */
> +	((struct usb_hcd *)_p)->self.is_b_host = 0;
> +	return 1;
> +}
> +
> +/**
> + * Connection timeout function.  An OTG host is required to display a
> + * message if the device does not connect within 10 seconds.
> + */
> +static void dwc_otg_hcd_connect_timeout(unsigned long _ptr)
> +{
> +	pr_info("Connect Timeout\n");
> +	pr_err("Device Not Connected/Responding\n");
> +}
> +
> +/**
> + * Start the connection timer.  An OTG host is required to display a
> + * message if the device does not connect within 10 seconds.  The
> + * timer is deleted if a port connect interrupt occurs before the
> + * timer expires.
> + */
> +static void dwc_otg_hcd_start_connect_timer(struct dwc_hcd *hcd)
> +{
> +	init_timer(&hcd->conn_timer);
> +	hcd->conn_timer.function = dwc_otg_hcd_connect_timeout;
> +	hcd->conn_timer.data = (unsigned long)0;
> +	hcd->conn_timer.expires = jiffies + (HZ * 10);
> +	add_timer(&hcd->conn_timer);
> +}
> +
> +/**
> + * HCD Callback function for disconnect of the HCD.
> + */
> +static int dwc_otg_hcd_session_start_cb(void *_p)
> +{
> +	struct dwc_hcd *hcd = hcd_to_dwc_otg_hcd(_p);
> +
> +	dwc_otg_hcd_start_connect_timer(hcd);
> +	return 1;
> +}
> +
> +/* HCD Callback structure for handling mode switching. */
> +static struct cil_callbacks hcd_cil_callbacks = {
> +	.start = dwc_otg_hcd_start_cb,
> +	.stop = dwc_otg_hcd_stop_cb,
> +	.disconnect = dwc_otg_hcd_disconnect_cb,
> +	.session_start = dwc_otg_hcd_session_start_cb,
> +	.p = NULL,
> +};
> +
> +/*
> + * Reset Workqueue implementation
> + */
> +static void port_reset_wqfunc(struct work_struct *work)
> +{
> +	struct dwc_hcd *hcd = container_of(work, struct dwc_hcd,
> +					   usb_port_reset);
> +	struct core_if *core_if = hcd->core_if;
> +	u32 hprt0 = 0;
> +	unsigned long flags;
> +
> +	pr_info("%s\n", __func__);
> +	spin_lock_irqsave(&hcd->lock, flags);
> +	hprt0 = dwc_otg_read_hprt0(core_if);
> +	hprt0 = DWC_HPRT0_PRT_RST_RW(hprt0, 1);
> +	dwc_write32(core_if->host_if->hprt0, hprt0);
> +	spin_unlock_irqrestore(&hcd->lock, flags);
> +	msleep(60);
> +	spin_lock_irqsave(&hcd->lock, flags);
> +	hprt0 = DWC_HPRT0_PRT_RST_RW(hprt0, 0);
> +	dwc_write32(core_if->host_if->hprt0, hprt0);
> +	hcd->flags.b.port_reset_change = 1;
> +	spin_unlock_irqrestore(&hcd->lock, flags);
> +}
> +
> +/*
> + * Wakeup Workqueue implementation
> + */
> +static void port_wakeup_wqfunc(struct work_struct *work)
> +{
> +	struct core_if *core_if = container_of(to_delayed_work(work),
> +					       struct core_if,
usb_port_wakeup);
> +	u32 hprt0;
> +
> +	pr_info("%s\n", __func__);
> +	/* Now wait for 70 ms. */
> +	hprt0 = dwc_otg_read_hprt0(core_if);
> +	msleep(70);
> +	hprt0 = DWC_HPRT0_PRT_RES_RW(hprt0, 0);
> +	dwc_write32(core_if->host_if->hprt0, hprt0);
> +}
> +
> +/**
> + * Starts processing a USB transfer request specified by a USB Request
Block
> + * (URB). mem_flags indicates the type of memory allocation to use
while
> + * processing this URB.
> + */
> +static int dwc_otg_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb
*urb,
> +				   gfp_t _mem_flags)
> +{
> +	int retval;
> +	unsigned long flags;
> +	struct dwc_hcd *dwc_hcd = hcd_to_dwc_otg_hcd(hcd);
> +	struct dwc_qtd *qtd;
> +
> +	if (!dwc_hcd->flags.b.port_connect_status) {
> +		/* No longer connected. */
> +		retval = -ENODEV;
> +		goto err_enq;
> +	}
> +
> +	qtd = dwc_otg_hcd_qtd_create(urb, _mem_flags);
> +	if (!qtd) {
> +		pr_err("DWC OTG HCD URB Enqueue failed creating "
"QTD\n");
> +		retval = -ENOMEM;
> +		goto err_enq;
> +	}
> +
> +	spin_lock_irqsave(&dwc_hcd->lock, flags);
> +	retval = usb_hcd_link_urb_to_ep(hcd, urb);
> +	if (unlikely(retval))
> +		goto fail;
> +
> +	retval = dwc_otg_hcd_qtd_add(qtd, dwc_hcd);
> +	if (retval < 0) {
> +		pr_err("DWC OTG HCD URB Enqueue failed adding QTD. "
> +		       "Error status %d\n", retval);
> +		usb_hcd_unlink_urb_from_ep(hcd, urb);
> +		goto fail;
> +	}
> +
> +fail:
> +	if (retval)
> +		dwc_otg_hcd_qtd_free(qtd);
> +
> +	spin_unlock_irqrestore(&dwc_hcd->lock, flags);
> +err_enq:
> +
> +	return retval;
> +}
> +
> +/**
> + * Attempts to halt a host channel. This function should only be called
in
> + * Slave mode or to abort a transfer in either Slave mode or DMA mode.
Under
> + * normal circumstances in DMA mode, the controller halts the channel
when the
> + * transfer is complete or a condition occurs that requires application
> + * intervention.
> + *
> + * In slave mode, checks for a free request queue entry, then sets the
Channel
> + * Enable and Channel Disable bits of the Host Channel Characteristics
> + * register of the specified channel to intiate the halt. If there is
no free
> + * request queue entry, sets only the Channel Disable bit of the
HCCHARn
> + * register to flush requests for this channel. In the latter case,
sets a
> + * flag to indicate that the host channel needs to be halted when a
request
> + * queue slot is open.
> + *
> + * In DMA mode, always sets the Channel Enable and Channel Disable bits
of the
> + * HCCHARn register. The controller ensures there is space in the
request
> + * queue before submitting the halt request.
> + *
> + * Some time may elapse before the core flushes any posted requests for
this
> + * host channel and halts. The Channel Halted interrupt handler
completes the
> + * deactivation of the host channel.
> + */
> +void dwc_otg_hc_halt(struct core_if *core_if, struct dwc_hc *hc,
> +		     enum dwc_halt_status hlt_sts)
> +{
> +	u32 nptxsts;
> +	u32 hptxsts = 0;
> +	u32 hcchar;
> +	ulong hc_regs;
> +	ulong global_regs = core_if->core_global_regs;
> +	ulong host_global_regs;
> +
> +	hc_regs = core_if->host_if->hc_regs[hc->hc_num];
> +	host_global_regs = core_if->host_if->host_global_regs;
> +
> +	WARN_ON(hlt_sts == DWC_OTG_HC_XFER_NO_HALT_STATUS);
> +
> +	if (hlt_sts == DWC_OTG_HC_XFER_URB_DEQUEUE ||
> +	    hlt_sts == DWC_OTG_HC_XFER_AHB_ERR) {
> +		/*
> +		 * Disable all channel interrupts except Ch Halted. The
QTD
> +		 * and QH state associated with this transfer has been
cleared
> +		 * (in the case of URB_DEQUEUE), so the channel needs to
be
> +		 * shut down carefully to prevent crashes.
> +		 */
> +		u32 hcintmsk;
> +		hcintmsk = 0;
> +		hcintmsk = DWC_HCINTMSK_CHAN_HALTED_RW(hcintmsk, 1);
> +		dwc_write32(hc_regs + DWC_HCINTMSK, hcintmsk);
> +
> +		/*
> +		 * Make sure no other interrupts besides halt are
currently
> +		 * pending. Handling another interrupt could cause a crash
due
> +		 * to the QTD and QH state.
> +		 */
> +		dwc_write32(hc_regs + DWC_HCINT, ~hcintmsk);
> +
> +		/*
> +		 * Make sure the halt status is set to URB_DEQUEUE or
AHB_ERR
> +		 * even if the channel was already halted for some other
reason.
> +		 */
> +		hc->halt_status = hlt_sts;
> +
> +		/*
> +		 * If the channel is not enabled, the channel is either
already
> +		 * halted or it hasn't started yet. In DMA mode, the
transfer
> +		 * may halt if it finishes normally or a condition occurs
that
> +		 * requires driver intervention. Don't want to halt the
channel
> +		 * again. In either Slave or DMA mode, it's possible that
the
> +		 * transfer has been assigned to a channel, but not
started yet
> +		 * when an URB is dequeued. Don't want to halt a channel
that
> +		 * hasn't started yet.
> +		 */
> +		hcchar = dwc_read32(hc_regs + DWC_HCCHAR);
> +		if (!DWC_HCCHAR_ENA_RD(hcchar))
> +			return;
> +	}
> +
> +	if (hc->halt_pending)
> +		/*
> +		 * A halt has already been issued for this channel. This
might
> +		 * happen when a transfer is aborted by a higher level in
> +		 * the stack.
> +		 */
> +		return;
> +
> +	hcchar = dwc_read32(hc_regs + DWC_HCCHAR);
> +	hcchar = DWC_HCCHAR_ENA_RW(hcchar, 1);
> +	hcchar = DWC_HCCHAR_DIS_RW(hcchar, 1);
> +	if (!core_if->dma_enable) {
> +		/* Check for space in the request queue to issue the halt.
*/
> +		if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
> +		    hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
> +			nptxsts = dwc_read32(global_regs + DWC_GNPTXSTS);
> +
> +			if (!DWC_GNPTXSTS_NPTXQSPCAVAIL_RD(nptxsts))
> +				hcchar = DWC_HCCHAR_ENA_RW(hcchar, 0);
> +		} else {
> +			hptxsts =
> +			    dwc_read32(host_global_regs + DWC_HPTXSTS);
> +
> +			if (!DWC_HPTXSTS_PTXSPC_AVAIL_RD(hptxsts) ||
> +			    core_if->queuing_high_bandwidth)
> +				hcchar = DWC_HCCHAR_ENA_RW(hcchar, 0);
> +		}
> +	}
> +	dwc_write32(hc_regs + DWC_HCCHAR, hcchar);
> +
> +	hc->halt_status = hlt_sts;
> +	if (DWC_HCCHAR_ENA_RD(hcchar)) {
> +		hc->halt_pending = 1;
> +		hc->halt_on_queue = 0;
> +	} else {
> +		hc->halt_on_queue = 1;
> +	}
> +}
> +
> +/**
> + * Aborts/cancels a USB transfer request. Always returns 0 to indicate
> + * success.
> + */
> +static int dwc_otg_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb
*urb,
> +				   int status)
> +{
> +	unsigned long flags;
> +	struct dwc_hcd *dwc_hcd;
> +	struct dwc_qtd *urb_qtd;
> +	struct dwc_qh *qh;
> +	int retval;
> +
> +	urb_qtd = (struct dwc_qtd *)urb->hcpriv;
> +	if (!urb_qtd)
> +		return -EINVAL;
> +	qh = (struct dwc_qh *)urb_qtd->qtd_qh_ptr;
> +	if (!qh)
> +		return -EINVAL;
> +
> +	dwc_hcd = hcd_to_dwc_otg_hcd(hcd);
> +	spin_lock_irqsave(&dwc_hcd->lock, flags);
> +
> +	retval = usb_hcd_check_unlink_urb(hcd, urb, status);
> +	if (retval) {
> +		spin_unlock_irqrestore(&dwc_hcd->lock, flags);
> +		return retval;
> +	}
> +
> +	if (urb_qtd == qh->qtd_in_process) {
> +		/* The QTD is in process (it has been assigned to a
channel). */
> +		if (dwc_hcd->flags.b.port_connect_status) {
> +			/*
> +			 * If still connected (i.e. in host mode), halt
the
> +			 * channel so it can be used for other transfers.
If
> +			 * no longer connected, the host registers can't
be
> +			 * written to halt the channel since the core is
in
> +			 * device mode.
> +			 */
> +			dwc_otg_hc_halt(dwc_hcd->core_if, qh->channel,
> +					DWC_OTG_HC_XFER_URB_DEQUEUE);
> +		}
> +	}
> +
> +	/*
> +	 * Free the QTD and clean up the associated QH. Leave the QH in
the
> +	 * schedule if it has any remaining QTDs.
> +	 */
> +	dwc_otg_hcd_qtd_remove_and_free(urb_qtd);
> +	if (qh && urb_qtd == qh->qtd_in_process) {
> +		dwc_otg_hcd_qh_deactivate(dwc_hcd, qh, 0);
> +		qh->channel = NULL;
> +		qh->qtd_in_process = NULL;
> +	} else if (qh && list_empty(&qh->qtd_list)) {
> +		dwc_otg_hcd_qh_remove(dwc_hcd, qh);
> +	}
> +
> +	urb->hcpriv = NULL;
> +	usb_hcd_unlink_urb_from_ep(hcd, urb);
> +	spin_unlock_irqrestore(&dwc_hcd->lock, flags);
> +
> +	/* Higher layer software sets URB status. */
> +	usb_hcd_giveback_urb(hcd, urb, status);
> +
> +	return 0;
> +}
> +
> +/* Remove and free a QH */
> +static inline void dwc_otg_hcd_qh_remove_and_free(struct dwc_hcd *hcd,
> +						  struct dwc_qh *qh)
> +{
> +	dwc_otg_hcd_qh_remove(hcd, qh);
> +	dwc_otg_hcd_qh_free(qh);
> +}
> +
> +static void qh_list_free(struct dwc_hcd *hcd, struct list_head
*_qh_list)
> +{
> +	struct list_head *item, *tmp;
> +	struct dwc_qh *qh;
> +
> +	/* If the list hasn't been initialized yet, return. */
> +	if (_qh_list->next == NULL)
> +		return;
> +
> +	/* Ensure there are no QTDs or URBs left. */
> +	kill_urbs_in_qh_list(hcd, _qh_list);
> +
> +	list_for_each_safe(item, tmp, _qh_list) {
> +		qh = list_entry(item, struct dwc_qh, qh_list_entry);
> +		dwc_otg_hcd_qh_remove_and_free(hcd, qh);
> +	}
> +}
> +
> +/**
> + * Frees resources in the DWC_otg controller related to a given
endpoint. Also
> + * clears state in the HCD related to the endpoint. Any URBs for the
endpoint
> + * must already be dequeued.
> + */
> +static void dwc_otg_hcd_endpoint_disable(struct usb_hcd *hcd,
> +					 struct usb_host_endpoint *ep)
> +{
> +	struct dwc_qh *qh;
> +	struct dwc_hcd *dwc_hcd = hcd_to_dwc_otg_hcd(hcd);
> +	unsigned long flags;

Tabify the declarations ;

> +
> +	spin_lock_irqsave(&dwc_hcd->lock, flags);
> +	qh = (struct dwc_qh *)ep->hcpriv;
> +	if (qh) {
> +		dwc_otg_hcd_qh_remove_and_free(dwc_hcd, qh);
> +		ep->hcpriv = NULL;
> +	}
> +	spin_unlock_irqrestore(&dwc_hcd->lock, flags);
> +}
> +
> +/**
> + * Creates Status Change bitmap for the root hub and root port. The
bitmap is
> + * returned in buf. Bit 0 is the status change indicator for the root
hub. Bit 1
> + * is the status change indicator for the single root port. Returns 1
if either
> + * change indicator is 1, otherwise returns 0.
> + */
> +static int dwc_otg_hcd_hub_status_data(struct usb_hcd *_hcd, char *buf)
> +{
> +	struct dwc_hcd *hcd = hcd_to_dwc_otg_hcd(_hcd);
> +
> +	buf[0] = 0;
> +	buf[0] |= (hcd->flags.b.port_connect_status_change
> +		   || hcd->flags.b.port_reset_change
> +		   || hcd->flags.b.port_enable_change
> +		   || hcd->flags.b.port_suspend_change
> +		   || hcd->flags.b.port_over_current_change) << 1;
> +
> +	return (buf[0] != 0);
> +}
> +
> +/* Handles the hub class-specific ClearPortFeature request.*/
> +static int do_clear_port_feature(struct dwc_hcd *hcd, u16 val)
> +{
> +	struct core_if *core_if = hcd->core_if;
> +	u32 hprt0 = 0;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&hcd->lock, flags);
> +	switch (val) {
> +	case USB_PORT_FEAT_ENABLE:
> +		hprt0 = dwc_otg_read_hprt0(core_if);
> +		hprt0 = DWC_HPRT0_PRT_ENA_RW(hprt0, 1);
> +		dwc_write32(core_if->host_if->hprt0, hprt0);
> +		break;
> +	case USB_PORT_FEAT_SUSPEND:
> +		hprt0 = dwc_otg_read_hprt0(core_if);
> +		hprt0 = DWC_HPRT0_PRT_RES_RW(hprt0, 1);
> +		dwc_write32(core_if->host_if->hprt0, hprt0);
> +
> +		/* Clear Resume bit */
> +		spin_unlock_irqrestore(&hcd->lock, flags);
> +		msleep(100);
> +		spin_lock_irqsave(&hcd->lock, flags);
> +		hprt0 = DWC_HPRT0_PRT_RES_RW(hprt0, 0);
> +		dwc_write32(core_if->host_if->hprt0, hprt0);
> +		break;
> +	case USB_PORT_FEAT_POWER:
> +		hprt0 = dwc_otg_read_hprt0(core_if);
> +		hprt0 = DWC_HPRT0_PRT_PWR_RW(hprt0, 0);
> +		dwc_write32(core_if->host_if->hprt0, hprt0);
> +		break;
> +	case USB_PORT_FEAT_INDICATOR:
> +		/* Port inidicator not supported */
> +		break;
> +	case USB_PORT_FEAT_C_CONNECTION:
> +		/* Clears drivers internal connect status change flag */
> +		hcd->flags.b.port_connect_status_change = 0;
> +		break;
> +	case USB_PORT_FEAT_C_RESET:
> +		/* Clears driver's internal Port Reset Change flag */
> +		hcd->flags.b.port_reset_change = 0;
> +		break;
> +	case USB_PORT_FEAT_C_ENABLE:
> +		/* Clears driver's internal Port Enable/Disable Change
flag  */
> +		hcd->flags.b.port_enable_change = 0;
> +		break;
> +	case USB_PORT_FEAT_C_SUSPEND:
> +		/*
> +		 * Clears the driver's internal Port Suspend
> +		 * Change flag, which is set when resume signaling on
> +		 * the host port is complete
> +		 */
> +		hcd->flags.b.port_suspend_change = 0;
> +		break;
> +	case USB_PORT_FEAT_C_OVER_CURRENT:
> +		hcd->flags.b.port_over_current_change = 0;
> +		break;
> +	default:
> +		pr_err("DWC OTG HCD - ClearPortFeature request %xh "
> +		       "unknown or unsupported\n", val);
> +		spin_unlock_irqrestore(&hcd->lock, flags);
> +		return -EINVAL;
> +	}
> +	spin_unlock_irqrestore(&hcd->lock, flags);
> +	return 0;
> +}
> +
> +/* Handles the hub class-specific SetPortFeature request.*/
> +static int do_set_port_feature(struct usb_hcd *hcd, u16 val, u16 index)
> +{
> +	struct core_if *core_if = hcd_to_dwc_otg_hcd(hcd)->core_if;
> +	u32 hprt0 = 0;
> +	struct dwc_hcd *dwc_hcd = hcd_to_dwc_otg_hcd(hcd);
> +	unsigned long flags;
> +	u32 pcgcctl = 0;

Tabify the declarations ;

> +
> +	spin_lock_irqsave(&dwc_hcd->lock, flags);
> +
> +	switch (val) {
> +	case USB_PORT_FEAT_SUSPEND:
> +		if (hcd->self.otg_port == index && hcd->self.b_hnp_enable)
{
> +			u32 gotgctl = 0;
> +			gotgctl |= DWC_GCTL_HOST_HNP_ENA;
> +			dwc_modify32(core_if->core_global_regs +
> +				     DWC_GOTGCTL, 0, gotgctl);
> +			core_if->xceiv->state = OTG_STATE_A_SUSPEND;
> +		}
> +
> +		hprt0 = dwc_otg_read_hprt0(core_if);
> +		hprt0 = DWC_HPRT0_PRT_SUS_RW(hprt0, 1);
> +		dwc_write32(core_if->host_if->hprt0, hprt0);
> +
> +		/* Suspend the Phy Clock */
> +		pcgcctl = DWC_PCGCCTL_STOP_CLK_SET(pcgcctl);
> +		dwc_write32(core_if->pcgcctl, pcgcctl);
> +
> +		/* For HNP the bus must be suspended for at least 200ms.
*/
> +		if (hcd->self.b_hnp_enable) {
> +			spin_unlock_irqrestore(&dwc_hcd->lock, flags);
> +			msleep(200);
> +			spin_lock_irqsave(&dwc_hcd->lock, flags);
> +		}
> +		break;
> +	case USB_PORT_FEAT_POWER:
> +		hprt0 = dwc_otg_read_hprt0(core_if);
> +		hprt0 = DWC_HPRT0_PRT_PWR_RW(hprt0, 1);
> +		dwc_write32(core_if->host_if->hprt0, hprt0);
> +		break;
> +	case USB_PORT_FEAT_RESET:
> +		hprt0 = dwc_otg_read_hprt0(core_if);
> +
> +		/*
> +		 * When B-Host the Port reset bit is set in the Start HCD
> +		 * Callback function, so that the reset is started within
1ms
> +		 * of the HNP success interrupt.
> +		 */
> +		if (!hcd->self.is_b_host) {
> +			hprt0 = DWC_HPRT0_PRT_RST_RW(hprt0, 1);
> +			dwc_write32(core_if->host_if->hprt0, hprt0);
> +		}
> +
> +		/* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
> +		spin_unlock_irqrestore(&dwc_hcd->lock, flags);
> +		msleep(60);
> +		spin_lock_irqsave(&dwc_hcd->lock, flags);
> +		hprt0 = DWC_HPRT0_PRT_RST_RW(hprt0, 0);
> +		dwc_write32(core_if->host_if->hprt0, hprt0);
> +		break;
> +	case USB_PORT_FEAT_INDICATOR:
> +		/* Not supported */
> +		break;
> +	default:
> +		pr_err("DWC OTG HCD - "
> +		       "SetPortFeature request %xh "
> +		       "unknown or unsupported\n", val);
> +		spin_unlock_irqrestore(&dwc_hcd->lock, flags);
> +		return -EINVAL;
> +	}
> +	spin_unlock_irqrestore(&dwc_hcd->lock, flags);
> +	return 0;
> +}
> +
> +/* Handles hub class-specific requests.*/
> +static int dwc_otg_hcd_hub_control(struct usb_hcd *hcd, u16 req_type,
u16 val,
> +				   u16 index, char *buf, u16 len)
> +{
> +	int retval = 0;
> +	struct dwc_hcd *dwc_hcd = hcd_to_dwc_otg_hcd(hcd);
> +	struct core_if *core_if = hcd_to_dwc_otg_hcd(hcd)->core_if;
> +	struct usb_hub_descriptor *desc;
> +	u32 hprt0 = 0;
> +	u32 port_status;
> +	unsigned long flags;

Tabify the declarations ;

> +
> +	spin_lock_irqsave(&dwc_hcd->lock, flags);
> +	switch (req_type) {
> +	case ClearHubFeature:
> +		switch (val) {
> +		case C_HUB_LOCAL_POWER:
> +		case C_HUB_OVER_CURRENT:
> +			/* Nothing required here */
> +			break;
> +		default:
> +			retval = -EINVAL;
> +			pr_err("DWC OTG HCD - ClearHubFeature request"
> +			       " %xh unknown\n", val);
> +		}
> +		break;
> +	case ClearPortFeature:
> +		if (!index || index > 1)
> +			goto error;
> +		spin_unlock_irqrestore(&dwc_hcd->lock, flags);
> +		retval = do_clear_port_feature(dwc_hcd, val);
> +		spin_lock_irqsave(&dwc_hcd->lock, flags);
> +		break;
> +	case GetHubDescriptor:
> +		desc = (struct usb_hub_descriptor *)buf;
> +		desc->bDescLength = 9;
> +		desc->bDescriptorType = 0x29;
> +		desc->bNbrPorts = 1;
> +		desc->wHubCharacteristics = 0x08;
> +		desc->bPwrOn2PwrGood = 1;
> +		desc->bHubContrCurrent = 0;
> +		break;
> +	case GetHubStatus:
> +		memset(buf, 0, 4);
> +		break;
> +	case GetPortStatus:
> +		if (!index || index > 1)
> +			goto error;
> +
> +		port_status = 0;
> +		if (dwc_hcd->flags.b.port_connect_status_change)
> +			port_status |= (1 << USB_PORT_FEAT_C_CONNECTION);
> +		if (dwc_hcd->flags.b.port_enable_change)
> +			port_status |= (1 << USB_PORT_FEAT_C_ENABLE);
> +		if (dwc_hcd->flags.b.port_suspend_change)
> +			port_status |= (1 << USB_PORT_FEAT_C_SUSPEND);
> +		if (dwc_hcd->flags.b.port_reset_change)
> +			port_status |= (1 << USB_PORT_FEAT_C_RESET);
> +		if (dwc_hcd->flags.b.port_over_current_change) {
> +			pr_err("Device Not Supported\n");
> +			port_status |= (1 <<
USB_PORT_FEAT_C_OVER_CURRENT);
> +		}
> +		if (!dwc_hcd->flags.b.port_connect_status) {
> +			/*
> +			 * The port is disconnected, which means the core
is
> +			 * either in device mode or it soon will be. Just
> +			 * return 0's for the remainder of the port status
> +			 * since the port register can't be read if the
core
> +			 * is in device mode.
> +			 */
> +			*((__le32 *) buf) = cpu_to_le32(port_status);
> +			break;
> +		}
> +
> +		hprt0 = dwc_read32(core_if->host_if->hprt0);
> +
> +		if (DWC_HPRT0_PRT_STS_RD(hprt0))
> +			port_status |= USB_PORT_STAT_CONNECTION;
> +		if (DWC_HPRT0_PRT_ENA_RD(hprt0))
> +			port_status |= USB_PORT_STAT_ENABLE;
> +		if (DWC_HPRT0_PRT_SUS_RD(hprt0))
> +			port_status |= USB_PORT_STAT_SUSPEND;
> +		if (DWC_HPRT0_PRT_OVRCURR_ACT_RD(hprt0))
> +			port_status |= USB_PORT_STAT_OVERCURRENT;
> +		if (DWC_HPRT0_PRT_RST_RD(hprt0))
> +			port_status |= USB_PORT_STAT_RESET;
> +		if (DWC_HPRT0_PRT_PWR_RD(hprt0))
> +			port_status |= USB_PORT_STAT_POWER;
> +
> +		if (DWC_HPRT0_PRT_SPD_RD(hprt0) ==
DWC_HPRT0_PRTSPD_HIGH_SPEED)
> +			port_status |= USB_PORT_STAT_HIGH_SPEED;
> +		else if (DWC_HPRT0_PRT_SPD_RD(hprt0) ==
> +			 DWC_HPRT0_PRTSPD_LOW_SPEED)
> +			port_status |= USB_PORT_STAT_LOW_SPEED;
> +
> +		if (DWC_HPRT0_PRT_TST_CTL_RD(hprt0))
> +			port_status |= (1 << USB_PORT_FEAT_TEST);
> +
> +		/* USB_PORT_FEAT_INDICATOR unsupported always 0 */
> +		*((__le32 *) buf) = cpu_to_le32(port_status);
> +		break;
> +	case SetHubFeature:
> +		/* No HUB features supported */
> +		break;
> +	case SetPortFeature:
> +		if (val != USB_PORT_FEAT_TEST && (!index || index > 1))
> +			goto error;
> +
> +		if (!dwc_hcd->flags.b.port_connect_status) {
> +			/*
> +			 * The port is disconnected, which means the core
is
> +			 * either in device mode or it soon will be. Just
> +			 * return without doing anything since the port
> +			 * register can't be written if the core is in
device
> +			 * mode.
> +			 */
> +			break;
> +		}
> +		spin_unlock_irqrestore(&dwc_hcd->lock, flags);
> +		retval = do_set_port_feature(hcd, val, index);
> +		spin_lock_irqsave(&dwc_hcd->lock, flags);
> +		break;
> +	default:
> +error:
> +		retval = -EINVAL;
> +		pr_warning("DWC OTG HCD - Unknown hub control request"
> +			   " type or invalid req_type: %xh index: %xh "
> +			   "val: %xh\n", req_type, index, val);
> +		break;
> +	}
> +	spin_unlock_irqrestore(&dwc_hcd->lock, flags);
> +	return retval;
> +}
> +
> +/**
> + * Handles host mode interrupts for the DWC_otg controller. Returns
IRQ_NONE if
> + * there was no interrupt to handle. Returns IRQ_HANDLED if there was a
valid
> + * interrupt.
> + *
> + * This function is called by the USB core when an interrupt occurs
> + */
> +static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd)
> +{
> +	struct dwc_hcd *dwc_hcd = hcd_to_dwc_otg_hcd(hcd);
> +
> +	return IRQ_RETVAL(dwc_otg_hcd_handle_intr(dwc_hcd));
> +}
> +
> +static const struct hc_driver dwc_otg_hc_driver = {
> +	.description = dwc_otg_hcd_name,
> +	.product_desc = "DWC OTG Controller",
> +	.hcd_priv_size = sizeof(struct dwc_hcd),
> +	.irq = dwc_otg_hcd_irq,
> +	.flags = HCD_MEMORY | HCD_USB2,
> +	.start = dwc_otg_hcd_start,
> +	.stop = dwc_otg_hcd_stop,
> +	.urb_enqueue = dwc_otg_hcd_urb_enqueue,
> +	.urb_dequeue = dwc_otg_hcd_urb_dequeue,
> +	.endpoint_disable = dwc_otg_hcd_endpoint_disable,
> +	.get_frame_number = dwc_otg_hcd_get_frame_number,
> +	.hub_status_data = dwc_otg_hcd_hub_status_data,
> +	.hub_control = dwc_otg_hcd_hub_control,
> +};
> +
> +/**
> + * Frees secondary storage associated with the dwc_hcd structure
contained
> + * in the struct usb_hcd field.
> + */
> +static void dwc_otg_hcd_free(struct usb_hcd *hcd)
> +{
> +	struct dwc_hcd *dwc_hcd = hcd_to_dwc_otg_hcd(hcd);
> +	u32 i;
> +
> +	del_timers(dwc_hcd);
> +
> +	/* Free memory for QH/QTD lists */
> +	qh_list_free(dwc_hcd, &dwc_hcd->non_periodic_sched_inactive);
> +	qh_list_free(dwc_hcd, &dwc_hcd->non_periodic_sched_deferred);
> +	qh_list_free(dwc_hcd, &dwc_hcd->non_periodic_sched_active);
> +	qh_list_free(dwc_hcd, &dwc_hcd->periodic_sched_inactive);
> +	qh_list_free(dwc_hcd, &dwc_hcd->periodic_sched_ready);
> +	qh_list_free(dwc_hcd, &dwc_hcd->periodic_sched_assigned);
> +	qh_list_free(dwc_hcd, &dwc_hcd->periodic_sched_queued);
> +
> +	/* Free memory for the host channels. */
> +	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
> +		struct dwc_hc *hc = dwc_hcd->hc_ptr_array[i];
> +
> +		kfree(hc);
> +	}
> +	if (dwc_hcd->core_if->dma_enable) {
> +		if (dwc_hcd->status_buf_dma)
> +			dma_free_coherent(hcd->self.controller,
> +					  DWC_OTG_HCD_STATUS_BUF_SIZE,
> +					  dwc_hcd->status_buf,
> +					  dwc_hcd->status_buf_dma);
> +	} else {
> +		kfree(dwc_hcd->status_buf);
> +	}
> +
> +}
> +
> +/**
> + * Initializes the HCD. This function allocates memory for and
initializes the
> + * static parts of the usb_hcd and dwc_hcd structures. It also
registers the
> + * USB bus with the core and calls the hc_driver->start() function. It
returns
> + * a negative error on failure.
> + */
> +int __devinit dwc_otg_hcd_init(struct device *_dev,
> +			       struct dwc_otg_device *dwc_otg_device)
> +{
> +	struct usb_hcd *hcd;
> +	struct dwc_hcd *dwc_hcd;
> +	struct dwc_otg_device *otg_dev = dev_get_drvdata(_dev);
> +	int num_channels;
> +	u32 i;
> +	struct dwc_hc *channel;
> +	int retval = 0;

Tabify the declarations ;

> +
> +	/*
> +	 * Allocate memory for the base HCD plus the DWC OTG HCD.
> +	 * Initialize the base HCD.
> +	 */
> +	hcd = usb_create_hcd(&dwc_otg_hc_driver, _dev, dwc_otg_hcd_name);
> +	if (!hcd) {
> +		retval = -ENOMEM;
> +		goto error1;
> +	}
> +	dev_set_drvdata(_dev, dwc_otg_device);
> +	hcd->regs = otg_dev->base;
> +	hcd->rsrc_start = otg_dev->phys_addr;
> +	hcd->rsrc_len = otg_dev->base_len;
> +	hcd->self.otg_port = 1;
> +
> +	/* Initialize the DWC OTG HCD. */
> +	dwc_hcd = hcd_to_dwc_otg_hcd(hcd);
> +	dwc_hcd->core_if = otg_dev->core_if;
> +	spin_lock_init(&dwc_hcd->lock);
> +	otg_dev->hcd = dwc_hcd;
> +
> +	/* Register the HCD CIL Callbacks */
> +	dwc_otg_cil_register_hcd_callbacks(otg_dev->core_if,
&hcd_cil_callbacks,
> +					   hcd);
> +
> +	/* Initialize the non-periodic schedule. */
> +	INIT_LIST_HEAD(&dwc_hcd->non_periodic_sched_inactive);
> +	INIT_LIST_HEAD(&dwc_hcd->non_periodic_sched_active);
> +	INIT_LIST_HEAD(&dwc_hcd->non_periodic_sched_deferred);
> +
> +	/* Initialize the periodic schedule. */
> +	INIT_LIST_HEAD(&dwc_hcd->periodic_sched_inactive);
> +	INIT_LIST_HEAD(&dwc_hcd->periodic_sched_ready);
> +	INIT_LIST_HEAD(&dwc_hcd->periodic_sched_assigned);
> +	INIT_LIST_HEAD(&dwc_hcd->periodic_sched_queued);
> +
> +	/*
> +	 * Create a host channel descriptor for each host channel
implemented
> +	 * in the controller. Initialize the channel descriptor array.
> +	 */
> +	INIT_LIST_HEAD(&dwc_hcd->free_hc_list);
> +	num_channels = dwc_hcd->core_if->core_params->host_channels;
> +
> +	for (i = 0; i < num_channels; i++) {
> +		channel = kzalloc(sizeof(struct dwc_hc), GFP_KERNEL);
> +		if (!channel) {
> +			retval = -ENOMEM;
> +			pr_err("%s: host channel allocation failed\n",
> +			       __func__);
> +			goto error2;
> +		}
> +
> +		channel->hc_num = i;
> +		dwc_hcd->hc_ptr_array[i] = channel;
> +	}
> +
> +	/* Initialize the Connection timeout timer. */
> +	init_timer(&dwc_hcd->conn_timer);
> +
> +	/* Initialize workqueue */
> +	INIT_WORK(&dwc_hcd->usb_port_reset, port_reset_wqfunc);
> +	INIT_WORK(&dwc_hcd->start_work, hcd_start_func);
> +	INIT_WORK(&dwc_hcd->core_if->usb_port_otg, NULL);
> +	INIT_DELAYED_WORK(&dwc_hcd->core_if->usb_port_wakeup,
> +			  port_wakeup_wqfunc);
> +
> +	/* Set device flags indicating whether the HCD supports DMA. */
> +	if (otg_dev->core_if->dma_enable) {
> +		static u64 dummy_mask = DMA_BIT_MASK(32);
> +
> +		pr_info("Using DMA mode\n");
> +		_dev->dma_mask = (void *)&dummy_mask;
> +		_dev->coherent_dma_mask = ~0;
> +	} else {
> +		pr_info("Using Slave mode\n");
> +		_dev->dma_mask = (void *)0;
> +		_dev->coherent_dma_mask = 0;
> +	}
> +
> +	init_hcd_usecs(dwc_hcd);
> +	/*
> +	 * Finish generic HCD initialization and start the HCD. This
function
> +	 * allocates the DMA buffer pool, registers the USB bus, requests
the
> +	 * IRQ line, and calls dwc_otg_hcd_start method.
> +	 */
> +	retval = usb_add_hcd(hcd, otg_dev->irq, IRQF_SHARED);
> +	if (retval < 0)
> +		goto error2;
> +	hcd->rsrc_start = otg_dev->phys_addr;
> +	hcd->rsrc_len = otg_dev->base_len;
> +
> +	/*
> +	 * Allocate space for storing data on status transactions.
Normally no
> +	 * data is sent, but this space acts as a bit bucket. This must be
> +	 * done after usb_add_hcd since that function allocates the DMA
buffer
> +	 * pool.
> +	 */
> +	if (otg_dev->core_if->dma_enable) {
> +		dwc_hcd->status_buf =
> +		    dma_alloc_coherent(_dev, DWC_OTG_HCD_STATUS_BUF_SIZE,
> +				       &dwc_hcd->status_buf_dma,
> +				       GFP_KERNEL | GFP_DMA);
> +	} else {
> +		dwc_hcd->status_buf = kmalloc(DWC_OTG_HCD_STATUS_BUF_SIZE,
> +					      GFP_KERNEL);
> +	}
> +	if (!dwc_hcd->status_buf) {
> +		retval = -ENOMEM;
> +		pr_err("%s: status_buf allocation failed\n", __func__);
> +		goto error3;
> +	}
> +	return 0;
> +
> +error3:
> +	usb_remove_hcd(hcd);
> +error2:
> +	dwc_otg_hcd_free(hcd);
> +	usb_put_hcd(hcd);
> +error1:
> +	return retval;
> +}
> +
> +/**
> + * Removes the HCD.
> + * Frees memory and resources associated with the HCD and deregisters
the bus.
> + */
> +void __devexit dwc_otg_hcd_remove(struct device *_dev)
> +{
> +	struct dwc_otg_device *otg_dev = dev_get_drvdata(_dev);
> +	struct dwc_hcd *dwc_hcd = otg_dev->hcd;
> +	struct usb_hcd *hcd = dwc_otg_hcd_to_hcd(dwc_hcd);
> +
> +	/* Turn off all interrupts */
> +	dwc_write32(gintmsk_reg(dwc_hcd), 0);
> +	dwc_modify32(gahbcfg_reg(dwc_hcd), 1, 0);
> +
> +	cancel_work_sync(&dwc_hcd->start_work);
> +	cancel_work_sync(&dwc_hcd->usb_port_reset);
> +	cancel_work_sync(&dwc_hcd->core_if->usb_port_otg);
> +
> +	usb_remove_hcd(hcd);
> +	dwc_otg_hcd_free(hcd);
> +	usb_put_hcd(hcd);
> +}
> +
> +/** Returns the current frame number. */
> +int dwc_otg_hcd_get_frame_number(struct usb_hcd *hcd)
> +{
> +	struct dwc_hcd *dwc_hcd = hcd_to_dwc_otg_hcd(hcd);
> +	u32 hfnum = 0;
> +
> +	hfnum = dwc_read32(dwc_hcd->core_if->host_if->
> +			   host_global_regs + DWC_HFNUM);
> +
> +	return DWC_HFNUM_FRNUM_RD(hfnum);
> +}
> +
> +/**
> + * Prepares a host channel for transferring packets to/from a specific
> + * endpoint. The HCCHARn register is set up with the characteristics
specified
> + * in _hc. Host channel interrupts that may need to be serviced while
this
> + * transfer is in progress are enabled.
> + */
> +static void dwc_otg_hc_init(struct core_if *core_if, struct dwc_hc *hc)
> +{
> +	u32 intr_enable;
> +	ulong global_regs = core_if->core_global_regs;
> +	u32 hc_intr_mask = 0;
> +	u32 gintmsk = 0;
> +	u32 hcchar;
> +	u32 hcsplt;
> +	u8 hc_num = hc->hc_num;
> +	struct dwc_host_if *host_if = core_if->host_if;
> +	ulong hc_regs = host_if->hc_regs[hc_num];

Tabify the declarations ;

> +
> +	/* Clear old interrupt conditions for this host channel. */
> +	hc_intr_mask = 0x3FF;
> +	dwc_write32(hc_regs + DWC_HCINT, hc_intr_mask);
> +
> +	/* Enable channel interrupts required for this transfer. */
> +	hc_intr_mask = 0;
> +	hc_intr_mask = DWC_HCINTMSK_CHAN_HALTED_RW(hc_intr_mask, 1);
> +	if (core_if->dma_enable) {
> +		hc_intr_mask = DWC_HCINTMSK_AHB_ERR_RW(hc_intr_mask, 1);
> +
> +		if (hc->error_state && !hc->do_split &&
> +		    hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
> +			hc_intr_mask =
> +			    DWC_HCINTMSK_ACK_RESP_REC_RW(hc_intr_mask, 1);
> +			if (hc->ep_is_in) {
> +				hc_intr_mask =
> +
DWC_HCINTMSK_DATA_TOG_ERR_RW(hc_intr_mask,
> +								 1);
> +				if (hc->ep_type != DWC_OTG_EP_TYPE_INTR)
> +					hc_intr_mask =
> +					    DWC_HCINTMSK_NAK_RESP_REC_RW
> +					    (hc_intr_mask, 1);
> +			}
> +		}
> +	} else {
> +		switch (hc->ep_type) {
> +		case DWC_OTG_EP_TYPE_CONTROL:
> +		case DWC_OTG_EP_TYPE_BULK:
> +			hc_intr_mask =
> +			    DWC_HCINTMSK_TXFER_CMPL_RW(hc_intr_mask, 1);
> +			hc_intr_mask =
> +			    DWC_HCINTMSK_STALL_RESP_REC_RW(hc_intr_mask,
1);
> +			hc_intr_mask =
> +			    DWC_HCINTMSK_TRANS_ERR_RW(hc_intr_mask, 1);
> +			hc_intr_mask =
> +			    DWC_HCINTMSK_DATA_TOG_ERR_RW(hc_intr_mask, 1);
> +
> +			if (hc->ep_is_in) {
> +				hc_intr_mask =
> +				    DWC_HCINTMSK_BBL_ERR_RW(hc_intr_mask,
1);
> +			} else {
> +				hc_intr_mask =
> +
DWC_HCINTMSK_NAK_RESP_REC_RW(hc_intr_mask,
> +								 1);
> +				hc_intr_mask =
> +
DWC_HCINTMSK_NYET_RESP_REC_RW(hc_intr_mask,
> +								  1);
> +				if (hc->do_ping)
> +					hc_intr_mask =
> +					    DWC_HCINTMSK_ACK_RESP_REC_RW
> +					    (hc_intr_mask, 1);
> +			}
> +
> +			if (hc->do_split) {
> +				hc_intr_mask =
> +
DWC_HCINTMSK_NAK_RESP_REC_RW(hc_intr_mask,
> +								 1);
> +				if (hc->complete_split)
> +					hc_intr_mask =
> +					    DWC_HCINTMSK_NYET_RESP_REC_RW
> +					    (hc_intr_mask, 1);
> +				else
> +					hc_intr_mask =
> +					    DWC_HCINTMSK_ACK_RESP_REC_RW
> +					    (hc_intr_mask, 1);
> +			}
> +
> +			if (hc->error_state)
> +				hc_intr_mask =
> +
DWC_HCINTMSK_ACK_RESP_REC_RW(hc_intr_mask,
> +								 1);
> +			break;
> +		case DWC_OTG_EP_TYPE_INTR:
> +			hc_intr_mask =
> +			    DWC_HCINTMSK_TXFER_CMPL_RW(hc_intr_mask, 1);
> +			hc_intr_mask =
> +			    DWC_HCINTMSK_NAK_RESP_REC_RW(hc_intr_mask, 1);
> +			hc_intr_mask =
> +			    DWC_HCINTMSK_STALL_RESP_REC_RW(hc_intr_mask,
1);
> +			hc_intr_mask =
> +			    DWC_HCINTMSK_TRANS_ERR_RW(hc_intr_mask, 1);
> +			hc_intr_mask =
> +			    DWC_HCINTMSK_DATA_TOG_ERR_RW(hc_intr_mask, 1);
> +			hc_intr_mask =
> +			    DWC_HCINTMSK_FRAME_OVERN_ERR_RW(hc_intr_mask,
1);
> +
> +			if (hc->ep_is_in)
> +				hc_intr_mask =
> +				    DWC_HCINTMSK_BBL_ERR_RW(hc_intr_mask,
1);
> +			if (hc->error_state)
> +				hc_intr_mask =
> +
DWC_HCINTMSK_ACK_RESP_REC_RW(hc_intr_mask,
> +								 1);
> +
> +			if (hc->do_split) {
> +				if (hc->complete_split)
> +					hc_intr_mask =
> +					    DWC_HCINTMSK_NYET_RESP_REC_RW
> +					    (hc_intr_mask, 1);
> +				else
> +					hc_intr_mask =
> +					    DWC_HCINTMSK_ACK_RESP_REC_RW
> +					    (hc_intr_mask, 1);
> +			}
> +			break;
> +		case DWC_OTG_EP_TYPE_ISOC:
> +			hc_intr_mask =
> +			    DWC_HCINTMSK_TXFER_CMPL_RW(hc_intr_mask, 1);
> +			hc_intr_mask =
> +			    DWC_HCINTMSK_FRAME_OVERN_ERR_RW(hc_intr_mask,
1);
> +			hc_intr_mask =
> +			    DWC_HCINTMSK_ACK_RESP_REC_RW(hc_intr_mask, 1);
> +
> +			if (hc->ep_is_in) {
> +				hc_intr_mask =
> +
DWC_HCINTMSK_TRANS_ERR_RW(hc_intr_mask, 1);
> +				hc_intr_mask =
> +				    DWC_HCINTMSK_BBL_ERR_RW(hc_intr_mask,
1);
> +			}
> +			break;
> +		}
> +	}
> +	dwc_write32(hc_regs + DWC_HCINTMSK, hc_intr_mask);
> +
> +	/* Enable the top level host channel interrupt. */
> +	intr_enable = (1 << hc_num);
> +	dwc_modify32(host_if->host_global_regs + DWC_HAINTMSK, 0,
> +		     intr_enable);
> +
> +	/* Make sure host channel interrupts are enabled. */
> +	gintmsk |= DWC_INTMSK_HST_CHAN;
> +	dwc_modify32(global_regs + DWC_GINTMSK, 0, gintmsk);
> +
> +	/*
> +	 * Program the HCCHARn register with the endpoint characteristics
for
> +	 * the current transfer.
> +	 */
> +	hcchar = 0;
> +	hcchar = DWC_HCCHAR_DEV_ADDR_RW(hcchar, hc->dev_addr);
> +	hcchar = DWC_HCCHAR_EP_NUM_RW(hcchar, hc->ep_num);
> +	hcchar = DWC_HCCHAR_EPDIR_RW(hcchar, hc->ep_is_in);
> +	hcchar = DWC_HCCHAR_LSP_DEV_RW(hcchar, (hc->speed ==
> +						DWC_OTG_EP_SPEED_LOW));
> +	hcchar = DWC_HCCHAR_EPTYPE_RW(hcchar, hc->ep_type);
> +	hcchar = DWC_HCCHAR_MPS_RW(hcchar, hc->max_packet);
> +	dwc_write32(host_if->hc_regs[hc_num] + DWC_HCCHAR, hcchar);
> +
> +	/* Program the HCSPLIT register for SPLITs */
> +	hcsplt = 0;
> +	if (hc->do_split) {
> +		hcsplt = DWC_HCSPLT_COMP_SPLT_RW(hcsplt,
hc->complete_split);
> +		hcsplt = DWC_HCSPLT_TRANS_POS_RW(hcsplt, hc->xact_pos);
> +		hcsplt = DWC_HCSPLT_HUB_ADDR_RW(hcsplt, hc->hub_addr);
> +		hcsplt = DWC_HCSPLT_PRT_ADDR_RW(hcsplt, hc->port_addr);
> +	}
> +	dwc_write32(host_if->hc_regs[hc_num] + DWC_HCSPLT, hcsplt);
> +}
> +
> +/**
> + * Assigns transactions from a QTD to a free host channel and
initializes the
> + * host channel to perform the transactions. The host channel is
removed from
> + * the free list.
> + */
> +static void assign_and_init_hc(struct dwc_hcd *hcd, struct dwc_qh *qh)
> +{
> +	struct dwc_hc *hc;
> +	struct dwc_qtd *qtd;
> +	struct urb *urb;
> +	struct usb_iso_packet_descriptor *frame_desc;
> +
> +	hc = list_entry(hcd->free_hc_list.next, struct dwc_hc,
hc_list_entry);
> +
> +	/* Remove the host channel from the free list. */
> +	list_del_init(&hc->hc_list_entry);
> +	qtd = list_entry(qh->qtd_list.next, struct dwc_qtd,
qtd_list_entry);
> +	urb = qtd->urb;
> +	qh->channel = hc;
> +	qh->qtd_in_process = qtd;
> +
> +	/*
> +	 * Use usb_pipedevice to determine device address. This address is
> +	 * 0 before the SET_ADDRESS command and the correct address
afterward.
> +	 */
> +	hc->dev_addr = usb_pipedevice(urb->pipe);
> +	hc->ep_num = usb_pipeendpoint(urb->pipe);
> +
> +	if (urb->dev->speed == USB_SPEED_LOW)
> +		hc->speed = DWC_OTG_EP_SPEED_LOW;
> +	else if (urb->dev->speed == USB_SPEED_FULL)
> +		hc->speed = DWC_OTG_EP_SPEED_FULL;
> +	else
> +		hc->speed = DWC_OTG_EP_SPEED_HIGH;
> +
> +	hc->max_packet = dwc_max_packet(qh->maxp);
> +	hc->xfer_started = 0;
> +	hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS;
> +	hc->error_state = (qtd->error_count > 0);
> +	hc->halt_on_queue = 0;
> +	hc->halt_pending = 0;
> +	hc->requests = 0;
> +
> +	/*
> +	 * The following values may be modified in the transfer type
section
> +	 * below. The xfer_len value may be reduced when the transfer is
> +	 * started to accommodate the max widths of the XferSize and
PktCnt
> +	 * fields in the HCTSIZn register.
> +	 */
> +	hc->do_ping = qh->ping_state;
> +	hc->ep_is_in = (usb_pipein(urb->pipe) != 0);
> +	hc->data_pid_start = qh->data_toggle;
> +	hc->multi_count = 1;
> +
> +	if (hcd->core_if->dma_enable)
> +		hc->xfer_buff = urb->transfer_dma + (u8 *)
urb->actual_length;
> +	else
> +		hc->xfer_buff = (u8 *) urb->transfer_buffer +
> +		    urb->actual_length;
> +
> +	hc->xfer_len = urb->transfer_buffer_length - urb->actual_length;
> +	hc->xfer_count = 0;
> +
> +	/*
> +	 * Set the split attributes
> +	 */
> +	hc->do_split = 0;
> +	if (qh->do_split) {
> +		hc->do_split = 1;
> +		hc->xact_pos = qtd->isoc_split_pos;
> +		hc->complete_split = qtd->complete_split;
> +		hc->hub_addr = urb->dev->tt->hub->devnum;
> +		hc->port_addr = urb->dev->ttport;
> +	}
> +
> +	switch (usb_pipetype(urb->pipe)) {
> +	case PIPE_CONTROL:
> +		hc->ep_type = DWC_OTG_EP_TYPE_CONTROL;
> +
> +		switch (qtd->control_phase) {
> +		case DWC_OTG_CONTROL_SETUP:
> +			hc->do_ping = 0;
> +			hc->ep_is_in = 0;
> +			hc->data_pid_start = DWC_OTG_HC_PID_SETUP;
> +
> +			if (hcd->core_if->dma_enable)
> +				hc->xfer_buff = (u8 *) (u32)
urb->setup_dma;
> +			else
> +				hc->xfer_buff = (u8 *) urb->setup_packet;
> +
> +			hc->xfer_len = 8;
> +			break;
> +		case DWC_OTG_CONTROL_DATA:
> +			hc->data_pid_start = qtd->data_toggle;
> +			break;
> +		case DWC_OTG_CONTROL_STATUS:
> +			/*
> +			 * Direction is opposite of data direction or IN
if no
> +			 * data.
> +			 */
> +			if (urb->transfer_buffer_length == 0)
> +				hc->ep_is_in = 1;
> +			else
> +				hc->ep_is_in = (usb_pipein(urb->pipe) !=
> +						USB_DIR_IN);
> +
> +			if (hc->ep_is_in)
> +				hc->do_ping = 0;
> +
> +			hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
> +			hc->xfer_len = 0;
> +			if (hcd->core_if->dma_enable)
> +				hc->xfer_buff =
> +				    (u8 *) (u32) hcd->status_buf_dma;
> +			else
> +				hc->xfer_buff = (u8 *) hcd->status_buf;
> +			break;
> +		}
> +		break;
> +	case PIPE_BULK:
> +		hc->ep_type = DWC_OTG_EP_TYPE_BULK;
> +		break;
> +	case PIPE_INTERRUPT:
> +		hc->ep_type = DWC_OTG_EP_TYPE_INTR;
> +		break;
> +	case PIPE_ISOCHRONOUS:
> +		frame_desc = &urb->iso_frame_desc[qtd->isoc_frame_index];
> +		hc->ep_type = DWC_OTG_EP_TYPE_ISOC;
> +
> +		if (hcd->core_if->dma_enable)
> +			hc->xfer_buff = (u8 *) (u32) urb->transfer_dma;
> +		else
> +			hc->xfer_buff = (u8 *) urb->transfer_buffer;
> +
> +		hc->xfer_buff += frame_desc->offset +
qtd->isoc_split_offset;
> +		hc->xfer_len = frame_desc->length -
qtd->isoc_split_offset;
> +
> +		if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) {
> +			if (hc->xfer_len <= 188)
> +				hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL;
> +			else
> +				hc->xact_pos = DWC_HCSPLIT_XACTPOS_BEGIN;
> +		}
> +		break;
> +	}
> +
> +	if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
> +	    hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
> +		/*
> +		 * This value may be modified when the transfer is started
to
> +		 * reflect the actual transfer length.
> +		 */
> +		hc->multi_count = dwc_hb_mult(qh->maxp);
> +
> +	dwc_otg_hc_init(hcd->core_if, hc);
> +	hc->qh = qh;
> +}
> +
> +/**
> + * This function selects transactions from the HCD transfer schedule
and
> + * assigns them to available host channels. It is called from HCD
interrupt
> + * handler functions.
> + */
> +enum dwc_transaction_type dwc_otg_hcd_select_transactions(struct
dwc_hcd *hcd)
> +{
> +	struct list_head *qh_ptr;
> +	struct dwc_qh *qh;
> +	int num_channels;
> +	enum dwc_transaction_type ret_val = DWC_OTG_TRANSACTION_NONE;
> +
> +	/* Process entries in the periodic ready list. */
> +	num_channels = hcd->core_if->core_params->host_channels;
> +	qh_ptr = hcd->periodic_sched_ready.next;
> +	while (qh_ptr != &hcd->periodic_sched_ready &&
> +	       !list_empty(&hcd->free_hc_list)) {
> +		/* Leave one channel for non periodic transactions. */
> +		if (hcd->available_host_channels <= 1)
> +			break;
> +		hcd->available_host_channels--;
> +		qh = list_entry(qh_ptr, struct dwc_qh, qh_list_entry);
> +		assign_and_init_hc(hcd, qh);
> +		/*
> +		 * Move the QH from the periodic ready schedule to the
> +		 * periodic assigned schedule.
> +		 */
> +		qh_ptr = qh_ptr->next;
> +		list_move(&qh->qh_list_entry,
&hcd->periodic_sched_assigned);
> +		ret_val = DWC_OTG_TRANSACTION_PERIODIC;
> +	}
> +
> +	/*
> +	 * Process entries in the deferred portion of the non-periodic
list.
> +	 * A NAK put them here and, at the right time, they need to be
> +	 * placed on the sched_inactive list.
> +	 */
> +	qh_ptr = hcd->non_periodic_sched_deferred.next;
> +	while (qh_ptr != &hcd->non_periodic_sched_deferred) {
> +		u16 frame_number =
> +		    dwc_otg_hcd_get_frame_number(dwc_otg_hcd_to_hcd(hcd));
> +		qh = list_entry(qh_ptr, struct dwc_qh, qh_list_entry);
> +		qh_ptr = qh_ptr->next;
> +
> +		if (dwc_frame_num_le(qh->sched_frame, frame_number))
> +			/*
> +			 * Move the QH from the non periodic deferred
schedule
> +			 * to the non periodic inactive schedule.
> +			 */
> +			list_move(&qh->qh_list_entry,
> +				  &hcd->non_periodic_sched_inactive);
> +	}
> +
> +	/*
> +	 * Process entries in the inactive portion of the non-periodic
> +	 * schedule. Some free host channels may not be used if they are
> +	 * reserved for periodic transfers.
> +	 */
> +	qh_ptr = hcd->non_periodic_sched_inactive.next;
> +	num_channels = hcd->core_if->core_params->host_channels;
> +
> +	while (qh_ptr != &hcd->non_periodic_sched_inactive
> +	       && !list_empty(&hcd->free_hc_list)) {
> +		if (hcd->available_host_channels < 1)
> +			break;
> +		hcd->available_host_channels--;
> +		qh = list_entry(qh_ptr, struct dwc_qh, qh_list_entry);
> +		assign_and_init_hc(hcd, qh);
> +		/*
> +		 * Move the QH from the non-periodic inactive schedule to
the
> +		 * non-periodic active schedule.
> +		 */
> +		qh_ptr = qh_ptr->next;
> +		list_move(&qh->qh_list_entry,
&hcd->non_periodic_sched_active);
> +		if (ret_val == DWC_OTG_TRANSACTION_NONE)
> +			ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC;
> +		else
> +			ret_val = DWC_OTG_TRANSACTION_ALL;
> +
> +	}
> +	return ret_val;
> +}
> +
> +/**
> + * Sets the channel property that indicates in which frame a periodic
transfer
> + * should occur. This is always set to the _next_ frame. This function
has no
> + * effect on non-periodic transfers.
> + */
> +static inline void hc_set_even_odd_frame(struct core_if *core_if,
> +					 struct dwc_hc *hc, u32 * hcchar)
> +{
> +	if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
> +	    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
> +		u32 hfnum = 0;
> +
> +		hfnum = dwc_read32(core_if->host_if->host_global_regs +
> +				   DWC_HFNUM);
> +
> +		/* 1 if _next_ frame is odd, 0 if it's even */
> +		*hcchar = DWC_HCCHAR_ODD_FRAME_RW(*hcchar,
> +
((DWC_HFNUM_FRNUM_RD(hfnum) &
> +						    0x1) ? 0 : 1));
> +	}
> +}
> +
> +static void set_initial_xfer_pid(struct dwc_hc *hc)
> +{
> +	if (hc->speed == DWC_OTG_EP_SPEED_HIGH) {
> +		if (hc->ep_is_in) {
> +			if (hc->multi_count == 1)
> +				hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
> +			else if (hc->multi_count == 2)
> +				hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
> +			else
> +				hc->data_pid_start = DWC_OTG_HC_PID_DATA2;
> +		} else {
> +			if (hc->multi_count == 1)
> +				hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
> +			else
> +				hc->data_pid_start = DWC_OTG_HC_PID_MDATA;
> +		}
> +	} else {
> +		hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
> +	}
> +}
> +
> +/**
> + * Starts a PING transfer. This function should only be called in Slave
mode.
> + * The Do Ping bit is set in the HCTSIZ register, then the channel is
enabled.
> + */
> +static void dwc_otg_hc_do_ping(struct core_if *core_if, struct dwc_hc
*hc)
> +{
> +	u32 hcchar;
> +	u32 hctsiz = 0;
> +
> +	ulong hc_regs = core_if->host_if->hc_regs[hc->hc_num];
> +
> +	hctsiz = 0;
> +	hctsiz = DWC_HCTSIZ_DO_PING_PROTO_RW(hctsiz, 1);
> +	hctsiz = DWC_HCTSIZ_PKT_CNT_RW(hctsiz, 1);
> +	dwc_write32(hc_regs + DWC_HCTSIZ, hctsiz);
> +
> +	hcchar = dwc_read32(hc_regs + DWC_HCCHAR);
> +	hcchar = DWC_HCCHAR_ENA_RW(hcchar, 1);
> +	hcchar = DWC_HCCHAR_DIS_RW(hcchar, 0);
> +	dwc_write32(hc_regs + DWC_HCCHAR, hcchar);
> +}
> +
> +/**
> + * This function writes a packet into the Tx FIFO associated with the
Host
> + * Channel. For a channel associated with a non-periodic EP, the
non-periodic
> + * Tx FIFO is written. For a channel associated with a periodic EP, the
> + * periodic Tx FIFO is written. This function should only be called in
Slave
> + * mode.
> + *
> + * Upon return the xfer_buff and xfer_count fields in hc are
incremented by
> + * then number of bytes written to the Tx FIFO.
> + */
> +static void dwc_otg_hc_write_packet(struct core_if *core_if, struct
dwc_hc *hc)
> +{
> +	u32 i;
> +	u32 remaining_count;
> +	u32 byte_count;
> +	u32 dword_count;
> +	u32 *data_buff = (u32 *) (hc->xfer_buff);
> +	u32 data_fifo = core_if->data_fifo[hc->hc_num];
> +
> +	remaining_count = hc->xfer_len - hc->xfer_count;
> +	if (remaining_count > hc->max_packet)
> +		byte_count = hc->max_packet;
> +	else
> +		byte_count = remaining_count;
> +
> +	dword_count = (byte_count + 3) / 4;
> +
> +	if (((unsigned long)data_buff) & 0x3)
> +		/* xfer_buff is not DWORD aligned. */
> +		for (i = 0; i < dword_count; i++, data_buff++)
> +			dwc_write_fifo32(data_fifo,
> +					     get_unaligned(data_buff));
> +	else
> +		/* xfer_buff is DWORD aligned. */
> +		for (i = 0; i < dword_count; i++, data_buff++)
> +			dwc_write_fifo32(data_fifo, *data_buff);
> +
> +	hc->xfer_count += byte_count;
> +	hc->xfer_buff += byte_count;
> +}
> +
> +/**
> + * This function does the setup for a data transfer for a host channel
and
> + * starts the transfer. May be called in either Slave mode or DMA mode.
In
> + * Slave mode, the caller must ensure that there is sufficient space in
the
> + * request queue and Tx Data FIFO.
> + *
> + * For an OUT transfer in Slave mode, it loads a data packet into the
> + * appropriate FIFO. If necessary, additional data packets will be
loaded in
> + * the Host ISR.
> + *
> + * For an IN transfer in Slave mode, a data packet is requested. The
data
> + * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
> + * additional data packets are requested in the Host ISR.
> + *
> + * For a PING transfer in Slave mode, the Do Ping bit is set in the
HCTSIZ
> + * register along with a packet count of 1 and the channel is enabled.
This
> + * causes a single PING transaction to occur. Other fields in HCTSIZ
are
> + * simply set to 0 since no data transfer occurs in this case.
> + *
> + * For a PING transfer in DMA mode, the HCTSIZ register is initialized
with
> + * all the information required to perform the subsequent data
transfer. In
> + * addition, the Do Ping bit is set in the HCTSIZ register. In this
case, the
> + * controller performs the entire PING protocol, then starts the data
> + * transfer.
> + */
> +static void dwc_otg_hc_start_transfer(struct core_if *core_if,
> +				      struct dwc_hc *hc)
> +{
> +	u32 hcchar;
> +	u32 hctsiz = 0;
> +	u16 num_packets;
> +	u32 max_hc_xfer_size = core_if->core_params->max_transfer_size;
> +	u16 max_hc_pkt_count = core_if->core_params->max_packet_count;
> +	ulong hc_regs = core_if->host_if->hc_regs[hc->hc_num];
> +	hctsiz = 0;
> +
> +	if (hc->do_ping) {
> +		if (!core_if->dma_enable) {
> +			dwc_otg_hc_do_ping(core_if, hc);
> +			hc->xfer_started = 1;
> +			return;
> +		} else {
> +			hctsiz = DWC_HCTSIZ_DO_PING_PROTO_RW(hctsiz, 1);
> +		}
> +	}
> +
> +	if (hc->do_split) {
> +		num_packets = 1;
> +
> +		if (hc->complete_split && !hc->ep_is_in)
> +			/*
> +			 * For CSPLIT OUT Transfer, set the size to 0 so
the
> +			 * core doesn't expect any data written to the
FIFO
> +			 */
> +			hc->xfer_len = 0;
> +		else if (hc->ep_is_in || (hc->xfer_len > hc->max_packet))
> +			hc->xfer_len = hc->max_packet;
> +		else if (!hc->ep_is_in && (hc->xfer_len > 188))
> +			hc->xfer_len = 188;
> +
> +		hctsiz = DWC_HCTSIZ_XFER_SIZE_RW(hctsiz, hc->xfer_len);
> +	} else {
> +		/*
> +		 * Ensure that the transfer length and packet count will
fit
> +		 * in the widths allocated for them in the HCTSIZn
register.
> +		 */
> +		if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
> +		    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
> +			u32 max_len = hc->multi_count * hc->max_packet;
> +
> +			/*
> +			 * Make sure the transfer size is no larger than
one
> +			 * (micro)frame's worth of data. (A check was done
> +			 * when the periodic transfer was accepted to
ensure
> +			 * that a (micro)frame's worth of data can be
> +			 * programmed into a channel.)
> +			 */
> +			if (hc->xfer_len > max_len)
> +				hc->xfer_len = max_len;
> +		} else if (hc->xfer_len > max_hc_xfer_size) {
> +			/*
> +			 * Make sure that xfer_len is a multiple of max
packet
> +			 * size.
> +			 */
> +			hc->xfer_len = max_hc_xfer_size - hc->max_packet +
1;
> +		}
> +		if (hc->xfer_len > 0) {
> +			num_packets = (hc->xfer_len + hc->max_packet - 1)
/
> +			    hc->max_packet;
> +			if (num_packets > max_hc_pkt_count) {
> +				num_packets = max_hc_pkt_count;
> +				hc->xfer_len = num_packets *
hc->max_packet;
> +			}
> +		} else {
> +			/* Need 1 packet for transfer length of 0. */
> +			num_packets = 1;
> +		}
> +
> +		if (hc->ep_is_in)
> +			/*
> +			 * Always program an integral # of max packets for
IN
> +			 * transfers.
> +			 */
> +			hc->xfer_len = num_packets * hc->max_packet;
> +
> +		if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
> +		    hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
> +			/*
> +			 * Make sure that the multi_count field matches
the
> +			 * actual transfer length.
> +			 */
> +			hc->multi_count = num_packets;
> +
> +		/* Set up the initial PID for the transfer. */
> +		if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
> +			set_initial_xfer_pid(hc);
> +
> +		hctsiz = DWC_HCTSIZ_XFER_SIZE_RW(hctsiz, hc->xfer_len);
> +	}
> +
> +	hc->start_pkt_count = num_packets;
> +	hctsiz = DWC_HCTSIZ_PKT_CNT_RW(hctsiz, num_packets);
> +	hctsiz = DWC_HCTSIZ_PKT_PID_RW(hctsiz, hc->data_pid_start);
> +	dwc_write32(hc_regs + DWC_HCTSIZ, hctsiz);
> +
> +	if (core_if->dma_enable)
> +		dwc_write32(hc_regs + DWC_HCDMA, (u32) hc->xfer_buff);
> +
> +	/* Start the split */
> +	if (hc->do_split) {
> +		u32 hcsplt;
> +
> +		hcsplt = dwc_read32(hc_regs + DWC_HCSPLT);
> +		hcsplt = DWC_HCSPLT_COMP_SPLT_RW(hcsplt, 1);
> +		dwc_write32(hc_regs + DWC_HCSPLT, hcsplt);
> +	}
> +
> +	hcchar = dwc_read32(hc_regs + DWC_HCCHAR);
> +	hcchar = DWC_HCCHAR_MULTI_CNT_RW(hcchar, hc->multi_count);
> +	hc_set_even_odd_frame(core_if, hc, &hcchar);
> +
> +	/* Set host channel enable after all other setup is complete. */
> +	hcchar = DWC_HCCHAR_ENA_RW(hcchar, 1);
> +	hcchar = DWC_HCCHAR_DIS_RW(hcchar, 0);
> +	dwc_write32(hc_regs + DWC_HCCHAR, hcchar);
> +
> +	hc->xfer_started = 1;
> +	hc->requests++;
> +	if (!core_if->dma_enable && !hc->ep_is_in && hc->xfer_len > 0)
> +		/* Load OUT packet into the appropriate Tx FIFO. */
> +		dwc_otg_hc_write_packet(core_if, hc);
> +}
> +
> +/**
> + * This function continues a data transfer that was started by previous
call
> + * to dwc_otg_hc_start_transfer</code>. The caller must ensure there is
> + * sufficient space in the request queue and Tx Data FIFO. This
function
> + * should only be called in Slave mode. In DMA mode, the controller
acts
> + * autonomously to complete transfers programmed to a host channel.
> + *
> + * For an OUT transfer, a new data packet is loaded into the
appropriate FIFO
> + * if there is any data remaining to be queued. For an IN transfer,
another
> + * data packet is always requested. For the SETUP phase of a control
transfer,
> + * this function does nothing.
> + */
> +static int dwc_otg_hc_continue_transfer(struct core_if *core_if,
> +					struct dwc_hc *hc)
> +{
> +	if (hc->do_split) {
> +		/* SPLITs always queue just once per channel */
> +		return 0;
> +	} else if (hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
> +		/* SETUPs are queued only once since they can't be NAKed.
*/
> +		return 0;
> +	} else if (hc->ep_is_in) {
> +		/*
> +		 * Always queue another request for other IN transfers. If
> +		 * back-to-back INs are issued and NAKs are received for
both,
> +		 * the driver may still be processing the first NAK when
the
> +		 * second NAK is received. When the interrupt handler
clears
> +		 * the NAK interrupt for the first NAK, the second NAK
will
> +		 * not be seen. So we can't depend on the NAK interrupt
> +		 * handler to requeue a NAKed request. Instead, IN
requests
> +		 * are issued each time this function is called. When the
> +		 * transfer completes, the extra requests for the channel
will
> +		 * be flushed.
> +		 */
> +		u32 hcchar;
> +		ulong hc_regs = core_if->host_if->hc_regs[hc->hc_num];
> +
> +		hcchar = dwc_read32(hc_regs + DWC_HCCHAR);
> +		hc_set_even_odd_frame(core_if, hc, &hcchar);
> +
> +		hcchar = DWC_HCCHAR_ENA_RW(hcchar, 1);
> +		hcchar = DWC_HCCHAR_DIS_RW(hcchar, 0);
> +		dwc_write32(hc_regs + DWC_HCCHAR, hcchar);
> +
> +		hc->requests++;
> +		return 1;
> +	} else {
> +		/* OUT transfers. */
> +		if (hc->xfer_count < hc->xfer_len) {
> +			if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
> +			    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
> +				u32 hcchar;
> +				u32 hc_regs;
> +
> +				hc_regs =
> +				    core_if->host_if->hc_regs[hc->hc_num];
> +				hcchar = dwc_read32(hc_regs + DWC_HCCHAR);
> +				hc_set_even_odd_frame(core_if, hc,
&hcchar);
> +			}
> +
> +			/* Load OUT packet into the appropriate Tx FIFO.
*/
> +			dwc_otg_hc_write_packet(core_if, hc);
> +			hc->requests++;
> +			return 1;
> +		} else {
> +			return 0;
> +		}
> +	}
> +}
> +
> +/**
> + * This function writes a packet into the Tx FIFO associated with the
Host
> + * Channel. For a channel associated with a non-periodic EP, the
non-periodic
> + * Tx FIFO is written. For a channel associated with a periodic EP, the
> + * periodic Tx FIFO is written. This function should only be called in
Slave
> + * mode.
> + *
> + * Upon return the xfer_buff and xfer_count fields in hc are
incremented by
> + * then number of bytes written to the Tx FIFO.
> + */
> +
> +/**
> + * Attempts to queue a single transaction request for a host channel
> + * associated with either a periodic or non-periodic transfer. This
function
> + * assumes that there is space available in the appropriate request
queue. For
> + * an OUT transfer or SETUP transaction in Slave mode, it checks
whether space
> + * is available in the appropriate Tx FIFO.
> + */
> +static int queue_transaction(struct dwc_hcd *hcd, struct dwc_hc *hc,
> +			     u16 _fifo_dwords_avail)
> +{
> +	int retval;
> +
> +	if (hcd->core_if->dma_enable) {
> +		if (!hc->xfer_started) {
> +			dwc_otg_hc_start_transfer(hcd->core_if, hc);
> +			hc->qh->ping_state = 0;
> +		}
> +		retval = 0;
> +	} else if (hc->halt_pending) {
> +		/* Don't queue a request if the channel has been halted.
*/
> +		retval = 0;
> +	} else if (hc->halt_on_queue) {
> +		dwc_otg_hc_halt(hcd->core_if, hc, hc->halt_status);
> +		retval = 0;
> +	} else if (hc->do_ping) {
> +		if (!hc->xfer_started)
> +			dwc_otg_hc_start_transfer(hcd->core_if, hc);
> +		retval = 0;
> +	} else if (!hc->ep_is_in || hc->data_pid_start ==
> +			DWC_OTG_HC_PID_SETUP) {
> +		if ((_fifo_dwords_avail * 4) >= hc->max_packet) {
> +			if (!hc->xfer_started) {
> +				dwc_otg_hc_start_transfer(hcd->core_if,
hc);
> +				retval = 1;
> +			} else {
> +				retval =
> +
dwc_otg_hc_continue_transfer(hcd->core_if,
> +								 hc);
> +			}
> +		} else {
> +			retval = -1;
> +		}
> +	} else {
> +		if (!hc->xfer_started) {
> +			dwc_otg_hc_start_transfer(hcd->core_if, hc);
> +			retval = 1;
> +		} else {
> +			retval =
dwc_otg_hc_continue_transfer(hcd->core_if, hc);
> +		}
> +	}
> +	return retval;
> +}
> +
> +/**
> + * Processes active non-periodic channels and queues transactions for
these
> + * channels to the DWC_otg controller. After queueing transactions, the
NP Tx
> + * FIFO Empty interrupt is enabled if there are more transactions to
queue as
> + * NP Tx FIFO or request queue space becomes available. Otherwise, the
NP Tx
> + * FIFO Empty interrupt is disabled.
> + */
> +static void process_non_periodic_channels(struct dwc_hcd *hcd)
> +{
> +	u32 tx_status = 0;
> +	struct list_head *orig_qh_ptr;
> +	struct dwc_qh *qh;
> +	int status;
> +	int no_queue_space = 0;
> +	int no_fifo_space = 0;
> +	int more_to_do = 0;
> +	ulong regs = hcd->core_if->core_global_regs;
> +
> +	/*
> +	 * Keep track of the starting point. Skip over the start-of-list
> +	 * entry.
> +	 */
> +	if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active)
> +		hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
> +	orig_qh_ptr = hcd->non_periodic_qh_ptr;
> +
> +	/*
> +	 * Process once through the active list or until no more space is
> +	 * available in the request queue or the Tx FIFO.
> +	 */
> +	do {
> +		tx_status = dwc_read32(regs + DWC_GNPTXSTS);
> +		if (!hcd->core_if->dma_enable &&
> +		    DWC_GNPTXSTS_NPTXQSPCAVAIL_RD(tx_status) == 0) {
> +			no_queue_space = 1;
> +			break;
> +		}
> +
> +		qh = list_entry(hcd->non_periodic_qh_ptr, struct dwc_qh,
> +				qh_list_entry);
> +		status = queue_transaction(hcd, qh->channel,
> +					   DWC_GNPTXSTS_NPTXFSPCAVAIL_RD
> +					   (tx_status));
> +
> +		if (status > 0) {
> +			more_to_do = 1;
> +		} else if (status < 0) {
> +			no_fifo_space = 1;
> +			break;
> +		}
> +
> +		/* Advance to next QH, skipping start-of-list entry. */
> +		hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
> +		if (hcd->non_periodic_qh_ptr ==
&hcd->non_periodic_sched_active)
> +			hcd->non_periodic_qh_ptr =
> +			    hcd->non_periodic_qh_ptr->next;
> +	} while (hcd->non_periodic_qh_ptr != orig_qh_ptr);
> +
> +	if (!hcd->core_if->dma_enable) {
> +		u32 intr_mask = 0;
> +
> +		intr_mask |= DWC_INTMSK_NP_TXFIFO_EMPT;
> +		if (more_to_do || no_queue_space || no_fifo_space) {
> +			/*
> +			 * May need to queue more transactions as the
request
> +			 * queue or Tx FIFO empties. Enable the
non-periodic
> +			 * Tx FIFO empty interrupt. (Always use the
half-empty
> +			 * level to ensure that new requests are loaded as
> +			 * soon as possible.)
> +			 */
> +			dwc_modify32(gintmsk_reg(hcd), 0, intr_mask);
> +		} else {
> +			/*
> +			 * Disable the Tx FIFO empty interrupt since there
are
> +			 * no more transactions that need to be queued
right
> +			 * now. This function is called from interrupt
> +			 * handlers to queue more transactions as transfer
> +			 * states change.
> +			 */
> +			dwc_modify32(gintmsk_reg(hcd), intr_mask, 0);
> +		}
> +	}
> +}
> +
> +/**
> + * Processes periodic channels for the next frame and queues
transactions for
> + * these channels to the DWC_otg controller. After queueing
transactions, the
> + * Periodic Tx FIFO Empty interrupt is enabled if there are more
transactions
> + * to queue as Periodic Tx FIFO or request queue space becomes
available.
> + * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled.
> + */
> +static void process_periodic_channels(struct dwc_hcd *hcd)
> +{
> +	u32 tx_status = 0;
> +	struct list_head *qh_ptr;
> +	struct dwc_qh *qh;
> +	int status;
> +	int no_queue_space = 0;
> +	int no_fifo_space = 0;
> +	ulong host_regs;

Tabify the declarations ;

> +
> +	host_regs = hcd->core_if->host_if->host_global_regs;
> +
> +	qh_ptr = hcd->periodic_sched_assigned.next;
> +	while (qh_ptr != &hcd->periodic_sched_assigned) {
> +		tx_status = dwc_read32(host_regs + DWC_HPTXSTS);
> +		if (DWC_HPTXSTS_PTXSPC_AVAIL_RD(tx_status) == 0) {
> +			no_queue_space = 1;
> +			break;
> +		}
> +
> +		qh = list_entry(qh_ptr, struct dwc_qh, qh_list_entry);
> +
> +		/*
> +		 * Set a flag if we're queuing high-bandwidth in slave
mode.
> +		 * The flag prevents any halts to get into the request
queue in
> +		 * the middle of multiple high-bandwidth packets getting
queued.
> +		 */
> +		if (!hcd->core_if->dma_enable && qh->channel->multi_count
> 1)
> +			hcd->core_if->queuing_high_bandwidth = 1;
> +
> +		status = queue_transaction(hcd, qh->channel,
> +					   DWC_HPTXSTS_PTXFSPC_AVAIL_RD
> +					   (tx_status));
> +		if (status < 0) {
> +			no_fifo_space = 1;
> +			break;
> +		}
> +
> +		/*
> +		 * In Slave mode, stay on the current transfer until there
is
> +		 * nothing more to do or the high-bandwidth request count
is
> +		 * reached. In DMA mode, only need to queue one request.
The
> +		 * controller automatically handles multiple packets for
> +		 * high-bandwidth transfers.
> +		 */
> +		if (hcd->core_if->dma_enable || (status == 0 ||
> +						 qh->channel->requests ==
> +
qh->channel->multi_count)) {
> +			qh_ptr = qh_ptr->next;
> +
> +			/*
> +			 * Move the QH from the periodic assigned schedule
to
> +			 * the periodic queued schedule.
> +			 */
> +			list_move(&qh->qh_list_entry,
> +				  &hcd->periodic_sched_queued);
> +
> +			/* done queuing high bandwidth */
> +			hcd->core_if->queuing_high_bandwidth = 0;
> +		}
> +	}
> +
> +	if (!hcd->core_if->dma_enable) {
> +		u32 intr_mask = 0;
> +
> +		intr_mask |= DWC_INTMSK_NP_TXFIFO_EMPT;
> +
> +		if (!list_empty(&hcd->periodic_sched_assigned) ||
> +		    no_queue_space || no_fifo_space)
> +			/*
> +			 * May need to queue more transactions as the
request
> +			 * queue or Tx FIFO empties. Enable the periodic
Tx
> +			 * FIFO empty interrupt. (Always use the
half-empty
> +			 * level to ensure that new requests are loaded as
> +			 * soon as possible.)
> +			 */
> +			dwc_modify32(gintmsk_reg(hcd), 0, intr_mask);
> +		else
> +			/*
> +			 * Disable the Tx FIFO empty interrupt since there
are
> +			 * no more transactions that need to be queued
right
> +			 * now. This function is called from interrupt
> +			 * handlers to queue more transactions as transfer
> +			 * states change.
> +			 */
> +			dwc_modify32(gintmsk_reg(hcd), intr_mask, 0);
> +	}
> +}
> +
> +/**
> + * This function processes the currently active host channels and
queues
> + * transactions for these channels to the DWC_otg controller. It is
called
> + * from HCD interrupt handler functions.
> + */
> +void dwc_otg_hcd_queue_transactions(struct dwc_hcd *hcd,
> +				    enum dwc_transaction_type tr_type)
> +{
> +	/* Process host channels associated with periodic transfers. */
> +	if ((tr_type == DWC_OTG_TRANSACTION_PERIODIC ||
> +	     tr_type == DWC_OTG_TRANSACTION_ALL) &&
> +	    !list_empty(&hcd->periodic_sched_assigned))
> +		process_periodic_channels(hcd);
> +
> +	/* Process host channels associated with non-periodic transfers.
*/
> +	if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC ||
> +	    tr_type == DWC_OTG_TRANSACTION_ALL) {
> +		if (!list_empty(&hcd->non_periodic_sched_active)) {
> +			process_non_periodic_channels(hcd);
> +		} else {
> +			/*
> +			 * Ensure NP Tx FIFO empty interrupt is disabled
when
> +			 * there are no non-periodic transfers to process.
> +			 */
> +			u32 gintmsk = 0;
> +			gintmsk |= DWC_INTMSK_NP_TXFIFO_EMPT;
> +			dwc_modify32(gintmsk_reg(hcd), gintmsk, 0);
> +		}
> +	}
> +}
> +
> +/**
> + * Sets the final status of an URB and returns it to the device driver.
Any
> + * required cleanup of the URB is performed.
> + */
> +void dwc_otg_hcd_complete_urb(struct dwc_hcd *hcd, struct urb *urb, int
status)
> +__releases(hcd->lock) __acquires(hcd->lock)
> +{
> +	urb->hcpriv = NULL;
> +	usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
> +
> +	spin_unlock(&hcd->lock);
> +	usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status);
> +	spin_lock(&hcd->lock);
> +}
> diff --git a/drivers/usb/otg/dwc/hcd.h b/drivers/usb/otg/dwc/hcd.h
> new file mode 100644
> index 0000000..c3d86e4
> --- /dev/null
> +++ b/drivers/usb/otg/dwc/hcd.h
> @@ -0,0 +1,416 @@
> +/*
> + * DesignWare HS OTG controller driver
> + * Copyright (C) 2006 Synopsys, Inc.
> + * Portions Copyright (C) 2010 Applied Micro Circuits Corporation.
> + *
> + * This program is free software: you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License version 2 for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see http://www.gnu.org/licenses
> + * or write to the Free Software Foundation, Inc., 51 Franklin Street,
> + * Suite 500, Boston, MA 02110-1335 USA.
> + *
> + * Based on Synopsys driver version 2.60a
> + * Modified by Mark Miesfeld <mmiesfeld@apm.com>
> + * Modified by Stefan Roese <sr@denx.de>, DENX Software Engineering
> + * Modified by Chuck Meade <chuck@theptrgroup.com>
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS"
> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO
THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE
> + * ARE DISCLAIMED. IN NO EVENT SHALL SYNOPSYS, INC. BE LIABLE FOR ANY
DIRECT,
> + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES
> + * (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES;
> + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND
> + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + */
> +
> +#if !defined(__DWC_HCD_H__)
> +#define __DWC_HCD_H__
> +
> +#include <linux/usb.h>
> +#include <linux/usb/hcd.h>
> +
> +#include "driver.h"
> +
> +/*
> + * This file contains the structures, constants, and interfaces for
> + * the Host Contoller Driver (HCD).
> + *
> + * The Host Controller Driver (HCD) is responsible for translating
requests
> + * from the USB Driver into the appropriate actions on the DWC_otg
controller.
> + * It isolates the USBD from the specifics of the controller by
providing an
> + * API to the USBD.
> + */
> +
> +/* Phases for control transfers. */
> +enum dwc_control_phase {
> +	DWC_OTG_CONTROL_SETUP,
> +	DWC_OTG_CONTROL_DATA,
> +	DWC_OTG_CONTROL_STATUS
> +};
> +
> +/* Transaction types. */
> +enum dwc_transaction_type {
> +	DWC_OTG_TRANSACTION_NONE,
> +	DWC_OTG_TRANSACTION_PERIODIC,
> +	DWC_OTG_TRANSACTION_NON_PERIODIC,
> +	DWC_OTG_TRANSACTION_ALL
> +};
> +
> +/*
> + * A Queue Transfer Descriptor (QTD) holds the state of a bulk,
control,
> + * interrupt, or isochronous transfer. A single QTD is created for each
URB
> + * (of one of these types) submitted to the HCD. The transfer
associated with
> + * a QTD may require one or multiple transactions.
> + *
> + * A QTD is linked to a Queue Head, which is entered in either the
> + * non-periodic or periodic schedule for execution. When a QTD is
chosen for
> + * execution, some or all of its transactions may be executed. After
> + * execution, the state of the QTD is updated. The QTD may be retired
if all
> + * its transactions are complete or if an error occurred. Otherwise, it
> + * remains in the schedule so more transactions can be executed later.
> + */
> +struct dwc_qtd {
> +	/*
> +	 * Determines the PID of the next data packet for the data phase
of
> +	 * control transfers. Ignored for other transfer types.
> +	 * One of the following values:
> +	 *      - DWC_OTG_HC_PID_DATA0
> +	 *      - DWC_OTG_HC_PID_DATA1
> +	 */
> +	u8 data_toggle;
> +
> +	/* Current phase for control transfers (Setup, Data, or Status).
*/
> +	enum dwc_control_phase control_phase;
> +
> +	/*
> +	 * Keep track of the current split type
> +	 * for FS/LS endpoints on a HS Hub
> +	 */
> +	u8 complete_split;
> +
> +	/* How many bytes transferred during SSPLIT OUT */
> +	u32 ssplit_out_xfer_count;
> +
> +	/*
> +	 * Holds the number of bus errors that have occurred for a
transaction
> +	 * within this transfer.
> +	 */
> +	u8 error_count;
> +
> +	/*
> +	 * Index of the next frame descriptor for an isochronous transfer.
A
> +	 * frame descriptor describes the buffer position and length of
the
> +	 * data to be transferred in the next scheduled (micro)frame of an
> +	 * isochronous transfer. It also holds status for that
transaction.
> +	 * The frame index starts at 0.
> +	 */
> +	int isoc_frame_index;
> +
> +	/* Position of the ISOC split on full/low speed */
> +	u8 isoc_split_pos;
> +
> +	/* Position of the ISOC split in the buffer for the current frame
*/
> +	u16 isoc_split_offset;
> +
> +	/* URB for this transfer */
> +	struct urb *urb;
> +
> +	/* This list of QTDs */
> +	struct list_head qtd_list_entry;
> +
> +	/* Field to track the qh pointer */
> +	struct dwc_qh *qtd_qh_ptr;
> +};
> +
> +/*
> + * A Queue Head (QH) holds the static characteristics of an endpoint
and
> + * maintains a list of transfers (QTDs) for that endpoint. A QH
structure may
> + * be entered in either the non-periodic or periodic schedule.
> + */
> +struct dwc_qh {
> +	/*
> +	 * Endpoint type.
> +	 * One of the following values:
> +	 *      - USB_ENDPOINT_XFER_CONTROL
> +	 *      - USB_ENDPOINT_XFER_ISOC
> +	 *      - USB_ENDPOINT_XFER_BULK
> +	 *      - USB_ENDPOINT_XFER_INT
> +	 */
> +	u8 ep_type;
> +	u8 ep_is_in;
> +
> +	/* wMaxPacketSize Field of Endpoint Descriptor. */
> +	u16 maxp;
> +
> +	/*
> +	 * Determines the PID of the next data packet for non-control
> +	 * transfers. Ignored for control transfers.
> +	 * One of the following values:
> +	 *      - DWC_OTG_HC_PID_DATA0
> +	 *      - DWC_OTG_HC_PID_DATA1
> +	 */
> +	u8 data_toggle;
> +
> +	/* Ping state if 1. */
> +	u8 ping_state;
> +
> +	/* List of QTDs for this QH. */
> +	struct list_head qtd_list;
> +
> +	/* Host channel currently processing transfers for this QH. */
> +	struct dwc_hc *channel;
> +
> +	/* QTD currently assigned to a host channel for this QH. */
> +	struct dwc_qtd *qtd_in_process;
> +
> +	/* Full/low speed endpoint on high-speed hub requires split. */
> +	u8 do_split;
> +
> +	/* Periodic schedule information */
> +
> +	/* Bandwidth in microseconds per (micro)frame. */
> +	u8 usecs;
> +
> +	/* Interval between transfers in (micro)frames. */
> +	u16 interval;
> +
> +	/*
> +	 * (micro)frame to initialize a periodic transfer. The transfer
> +	 * executes in the following (micro)frame.
> +	 */
> +	u16 sched_frame;
> +
> +	/* (micro)frame at which last start split was initialized. */
> +	u16 start_split_frame;
> +
> +	u16 speed;
> +	u16 frame_usecs[8];
> +
> +	/* Entry for QH in either the periodic or non-periodic schedule.
*/
> +	struct list_head qh_list_entry;
> +};
> +
> +/* Gets the struct usb_hcd that contains a struct dwc_hcd. */
> +static inline struct usb_hcd *dwc_otg_hcd_to_hcd(struct dwc_hcd
*dwc_hcd)
> +{
> +	return container_of((void *)dwc_hcd, struct usb_hcd, hcd_priv);
> +}
> +
> +/* HCD Create/Destroy Functions */
> +extern int __init dwc_otg_hcd_init(struct device *_dev,
> +				   struct dwc_otg_device *dwc_dev);
> +extern void dwc_otg_hcd_remove(struct device *_dev);
> +
> +/*
> + * The following functions support managing the DWC_otg controller in
host
> + * mode.
> + */
> +extern int dwc_otg_hcd_get_frame_number(struct usb_hcd *hcd);
> +extern void dwc_otg_hc_cleanup(struct core_if *core_if, struct dwc_hc
*hc);
> +extern void dwc_otg_hc_halt(struct core_if *core_if, struct dwc_hc *hc,
> +			    enum dwc_halt_status _halt_status);
> +
> +/* Transaction Execution Functions */
> +extern enum dwc_transaction_type dwc_otg_hcd_select_transactions(struct
dwc_hcd
> +								 *hcd);
> +extern void dwc_otg_hcd_queue_transactions(struct dwc_hcd *hcd,
> +					   enum dwc_transaction_type
tr_type);
> +extern void dwc_otg_hcd_complete_urb(struct dwc_hcd *_hcd, struct urb
*urb,
> +				     int status);
> +
> +/* Interrupt Handler Functions */
> +extern int dwc_otg_hcd_handle_intr(struct dwc_hcd *hcd);
> +
> +/* Schedule Queue Functions */
> +extern int init_hcd_usecs(struct dwc_hcd *hcd);
> +extern void dwc_otg_hcd_qh_free(struct dwc_qh *qh);
> +extern void dwc_otg_hcd_qh_remove(struct dwc_hcd *hcd, struct dwc_qh
*qh);
> +extern void dwc_otg_hcd_qh_deactivate(struct dwc_hcd *hcd, struct
dwc_qh *qh,
> +				      int sched_csplit);
> +extern int dwc_otg_hcd_qh_deferr(struct dwc_hcd *hcd, struct dwc_qh
*qh,
> +				 int delay);
> +extern struct dwc_qtd *dwc_otg_hcd_qtd_create(struct urb *urb,
> +					      gfp_t _mem_flags);
> +extern int dwc_otg_hcd_qtd_add(struct dwc_qtd *qtd, struct dwc_hcd
*dwc_hcd);
> +
> +/*
> + * Frees the memory for a QTD structure.  QTD should already be removed
from
> + * list.
> + */
> +static inline void dwc_otg_hcd_qtd_free(struct dwc_qtd *_qtd)
> +{
> +	kfree(_qtd);
> +}
> +
> +/* Removes a QTD from list. */
> +static inline void dwc_otg_hcd_qtd_remove(struct dwc_qtd *_qtd)
> +{
> +	list_del(&_qtd->qtd_list_entry);
> +}
> +
> +/* Remove and free a QTD */
> +static inline void dwc_otg_hcd_qtd_remove_and_free(struct dwc_qtd
*_qtd)
> +{
> +	dwc_otg_hcd_qtd_remove(_qtd);
> +	dwc_otg_hcd_qtd_free(_qtd);
> +}
> +
> +struct dwc_qh *dwc_urb_to_qh(struct urb *_urb);
> +
> +/* Gets the usb_host_endpoint associated with an URB. */
> +static inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb
*_urb)
> +{
> +	struct usb_device *dev = _urb->dev;
> +	int ep_num = usb_pipeendpoint(_urb->pipe);
> +
> +	if (usb_pipein(_urb->pipe))
> +		return dev->ep_in[ep_num];
> +	else
> +		return dev->ep_out[ep_num];
> +}
> +
> +/*
> + * Gets the endpoint number from a _bEndpointAddress argument. The
endpoint is
> + * qualified with its direction (possible 32 endpoints per device).
> + */
> +#define dwc_ep_addr_to_endpoint(_bEndpointAddress_) \
> +		((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \
> +		((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4)
> +
> +/* Gets the QH that contains the list_head */
> +#define dwc_list_to_qh(_list_head_ptr_) \
> +		(container_of(_list_head_ptr_, struct dwc_qh,
qh_list_entry))
> +
> +/* Gets the QTD that contains the list_head */
> +#define dwc_list_to_qtd(_list_head_ptr_) \
> +		(container_of(_list_head_ptr_, struct dwc_qtd,
qtd_list_entry))
> +
> +/* Check if QH is non-periodic  */
> +#define dwc_qh_is_non_per(_qh_ptr_) \
> +		((_qh_ptr_->ep_type == USB_ENDPOINT_XFER_BULK) || \
> +		(_qh_ptr_->ep_type == USB_ENDPOINT_XFER_CONTROL))
> +
> +/* High bandwidth multiplier as encoded in highspeed endpoint
descriptors */
> +#define dwc_hb_mult(wMaxPacketSize)	(1 + (((wMaxPacketSize) >> 11) &
0x03))
> +
> +/* Packet size for any kind of endpoint descriptor */
> +#define dwc_max_packet(wMaxPacketSize)	((wMaxPacketSize) &
0x07ff)
> +
> +/*
> + * Returns true if _frame1 is less than or equal to _frame2. The
comparison is
> + * done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of
the
> + * frame number when the max frame number is reached.
> + */
> +static inline int dwc_frame_num_le(u16 _frame1, u16 _frame2)
> +{
> +	return ((_frame2 - _frame1) & DWC_HFNUM_MAX_FRNUM) <=
> +	    (DWC_HFNUM_MAX_FRNUM >> 1);
> +}
> +
> +/*
> + * Returns true if _frame1 is greater than _frame2. The comparison is
done
> + * modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the
frame
> + * number when the max frame number is reached.
> + */
> +static inline int dwc_frame_num_gt(u16 _frame1, u16 _frame2)
> +{
> +	return (_frame1 != _frame2) &&
> +	    (((_frame1 - _frame2) &
> +	      DWC_HFNUM_MAX_FRNUM) < (DWC_HFNUM_MAX_FRNUM >> 1));
> +}
> +
> +/*
> + * Increments _frame by the amount specified by _inc. The addition is
done
> + * modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value.
> + */
> +static inline u16 dwc_frame_num_inc(u16 _frame, u16 _inc)
> +{
> +	return (_frame + _inc) & DWC_HFNUM_MAX_FRNUM;
> +}
> +
> +static inline u16 dwc_full_frame_num(u16 _frame)
> +{
> +	return ((_frame) & DWC_HFNUM_MAX_FRNUM) >> 3;
> +}
> +
> +static inline u16 dwc_micro_frame_num(u16 _frame)
> +{
> +	return (_frame) & 0x7;
> +}
> +
> +static inline ulong gintsts_reg(struct dwc_hcd *hcd)
> +{
> +	ulong global_regs = hcd->core_if->core_global_regs;
> +	return global_regs + DWC_GINTSTS;
> +}
> +
> +static inline ulong gintmsk_reg(struct dwc_hcd *hcd)
> +{
> +	ulong global_regs = hcd->core_if->core_global_regs;
> +	return global_regs + DWC_GINTMSK;
> +}
> +
> +static inline ulong gahbcfg_reg(struct dwc_hcd *hcd)
> +{
> +	ulong global_regs = hcd->core_if->core_global_regs;
> +	return global_regs + DWC_GAHBCFG;
> +}
> +
> +static inline const char *pipetype_str(unsigned int pipe)
> +{
> +	switch (usb_pipetype(pipe)) {
> +	case PIPE_CONTROL:
> +		return "control";
> +	case PIPE_BULK:
> +		return "bulk";
> +	case PIPE_INTERRUPT:
> +		return "interrupt";
> +	case PIPE_ISOCHRONOUS:
> +		return "isochronous";
> +	default:
> +		return "unknown";
> +	}
> +}
> +
> +static inline const char *dev_speed_str(enum usb_device_speed speed)
> +{
> +	switch (speed) {
> +	case USB_SPEED_HIGH:
> +		return "high";
> +	case USB_SPEED_FULL:
> +		return "full";
> +	case USB_SPEED_LOW:
> +		return "low";
> +	default:
> +		return "unknown";
> +	}
> +}
> +
> +static inline const char *ep_type_str(u8 type)
> +{
> +	switch (type) {
> +	case USB_ENDPOINT_XFER_ISOC:
> +		return "isochronous";
> +	case USB_ENDPOINT_XFER_INT:
> +		return "interrupt";
> +	case USB_ENDPOINT_XFER_CONTROL:
> +		return "control";
> +	case USB_ENDPOINT_XFER_BULK:
> +		return "bulk";
> +	default:
> +		return "?";
> +	}
> +}
> +#endif
> --
> 1.6.1.rc3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* RE: [PATCH v10 02/10] USB/ppc4xx: Add Synopsys DWC OTG driver framework
From: Keshava Munegowda @ 2011-03-29 10:46 UTC (permalink / raw)
  To: tmarri, linux-usb, linuxppc-dev; +Cc: greg, Mark Miesfeld, Fushen Chen
In-Reply-To: <1301336863-1886-1-git-send-email-tmarri@apm.com>

> +static irqreturn_t dwc_otg_common_irq(int _irq, void *dev)
> +{
> +	struct dwc_otg_device *dwc_dev = dev;
> +	int retval;

Tabify the declarations;


> +
> +	retval = dwc_otg_handle_common_intr(dwc_dev->core_if);
> +	return IRQ_RETVAL(retval);
> +}
> +
> +/**
> + * This function is the interrupt handler for the OverCurrent condition
> + * from the external charge pump (if enabled)
> + */
> +static irqreturn_t dwc_otg_externalchgpump_irq(int _irq, void *dev)
> +{
> +	struct dwc_otg_device *dwc_dev = dev;
> +
> +	if (dwc_otg_is_host_mode(dwc_dev->core_if)) {
> +		struct dwc_hcd *dwc_hcd;
> +		u32 hprt0 = 0;
> +
> +		dwc_hcd = dwc_dev->hcd;
> +		spin_lock(&dwc_hcd->lock);
> +		dwc_hcd->flags.b.port_over_current_change = 1;
> +
> +		hprt0 = DWC_HPRT0_PRT_PWR_RW(hprt0, 0);
> +		dwc_write32(dwc_dev->core_if->host_if->hprt0, hprt0);
> +		spin_unlock(&dwc_hcd->lock);
> +	} else {
> +		/* Device mode - This int is n/a for device mode */
> +		dev_dbg(dev, "DeviceMode: OTG OverCurrent Detected\n");
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +/**
> + * This function is called when a device is unregistered with the
> + * dwc_otg_driver. This happens, for example, when the rmmod command is
> + * executed. The device may or may not be electrically present. If it
is
> + * present, the driver stops device processing. Any resources used on
behalf
> + * of this device are freed.
> + */
> +static int __devexit dwc_otg_driver_remove(struct platform_device
*ofdev)
> +{
> +	struct device *dev = &ofdev->dev;
> +	struct dwc_otg_device *dwc_dev = dev_get_drvdata(dev);

Tabify the declarations ;

> +
> +	/* Memory allocation for dwc_otg_device may have failed. */
> +	if (!dwc_dev)
> +		return 0;
> +
> +	/* Free the IRQ */
> +	if (dwc_dev->common_irq_installed)
> +		free_irq(dwc_dev->irq, dwc_dev);
> +
> +	if (!dwc_has_feature(dwc_dev->core_if, DWC_DEVICE_ONLY)) {
> +		if (dwc_dev->hcd) {
> +			if (dwc_dev->hcd->cp_irq_installed)
> +				free_irq(dwc_dev->hcd->cp_irq, dwc_dev);
> +			dwc_otg_hcd_remove(dev);
> +		}
> +	}
> +
> +	if (!dwc_has_feature(dwc_dev->core_if, DWC_HOST_ONLY)) {
> +		if (dwc_dev->pcd)
> +			dwc_otg_pcd_remove(dev);
> +	}
> +
> +	if (dwc_dev->core_if)
> +		dwc_otg_cil_remove(dwc_dev->core_if);
> +
> +	/* Return the memory. */
> +	if (dwc_dev->base)
> +		iounmap(dwc_dev->base);
> +
> +	if (dwc_dev->phys_addr)
> +		release_mem_region(dwc_dev->phys_addr, dwc_dev->base_len);
> +
> +	if (dwc_dev->core_if->xceiv) {
> +		otg_put_transceiver(dwc_dev->core_if->xceiv);
> +		dwc_dev->core_if->xceiv = NULL;
> +		usb_nop_xceiv_unregister();
> +	}
> +
> +	kfree(dwc_dev);
> +
> +	/* Clear the drvdata pointer. */
> +	dev_set_drvdata(dev, NULL);
> +	return 0;
> +}
> +
> +/**
> + * This function is called when an device is bound to a
> + * dwc_otg_driver. It creates the driver components required to
> + * control the device (CIL, HCD, and PCD) and it initializes the
> + * device. The driver components are stored in a dwc_otg_device
> + * structure. A reference to the dwc_otg_device is saved in the
> + * device. This allows the driver to access the dwc_otg_device
> + * structure on subsequent calls to driver methods for this device.
> + */
> +static int __devinit dwc_otg_driver_probe(struct platform_device
*ofdev)
> +{
> +	int retval;
> +	struct dwc_otg_device *dwc_dev;
> +	struct device *dev = &ofdev->dev;
> +	struct resource res;
> +	ulong gusbcfg_addr;
> +	u32 usbcfg = 0;

Tabify the declarations; so that it looks clean.


> +
> +	dev_dbg(dev, "dwc_otg_driver_probe(%p)\n", dev);
> +
> +	dwc_dev = kzalloc(sizeof(*dwc_dev), GFP_KERNEL);
> +	if (!dwc_dev) {
> +		dev_err(dev, "kmalloc of dwc_otg_device failed\n");
> +		retval = -ENOMEM;
> +		goto fail_dwc_dev;
> +	}
> +
> +	/* Retrieve the memory and IRQ resources. */
> +	dwc_dev->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
> +	if (dwc_dev->irq == NO_IRQ) {
> +		dev_err(dev, "no device irq\n");
> +		retval = -ENODEV;
> +		goto fail_of_irq;
> +	}
> +	dev_dbg(dev, "OTG - device irq: %d\n", dwc_dev->irq);
> +
> +	if (of_address_to_resource(ofdev->dev.of_node, 0, &res)) {
> +		dev_err(dev, "%s: Can't get USB-OTG register address\n",
> +			__func__);
> +		retval = -ENOMEM;
> +		goto fail_of_irq;
> +	}
> +	dev_dbg(dev, "OTG - ioresource_mem start0x%llx: end:0x%llx\n",
> +		(unsigned long long)res.start, (unsigned long
long)res.end);
> +
> +	dwc_dev->phys_addr = res.start;
> +	dwc_dev->base_len = res.end - res.start + 1;
> +	if (!request_mem_region(dwc_dev->phys_addr,
> +				dwc_dev->base_len, dwc_driver_name)) {
> +		dev_err(dev, "request_mem_region failed\n");
> +		retval = -EBUSY;
> +		goto fail_of_irq;
> +	}
> +
> +	/* Map the DWC_otg Core memory into virtual address space. */
> +	dwc_dev->base = ioremap(dwc_dev->phys_addr, dwc_dev->base_len);
> +	if (!dwc_dev->base) {
> +		dev_err(dev, "ioremap() failed\n");
> +		retval = -ENOMEM;
> +		goto fail_ioremap;
> +	}
> +	dev_dbg(dev, "mapped base=0x%08x\n", (__force u32)dwc_dev->base);
> +
> +	/*
> +	 * Initialize driver data to point to the global DWC_otg
> +	 * Device structure.
> +	 */
> +	dev_set_drvdata(dev, dwc_dev);
> +
> +	dwc_dev->core_if =
> +	    dwc_otg_cil_init(dwc_dev->base, &dwc_otg_module_params);
> +	if (!dwc_dev->core_if) {
> +		dev_err(dev, "CIL initialization failed!\n");
> +		retval = -ENOMEM;
> +		goto fail_cil_init;
> +	}
> +
> +	/*
> +	 * Validate parameter values after dwc_otg_cil_init.
> +	 */
> +	if (check_parameters(dwc_dev->core_if)) {
> +		retval = -EINVAL;
> +		goto fail_check_param;
> +	}
> +
> +	usb_nop_xceiv_register();
> +	dwc_dev->core_if->xceiv = otg_get_transceiver();
> +	if (!dwc_dev->core_if->xceiv) {
> +		retval = -ENODEV;
> +		goto fail_xceiv;
> +	}
> +	dwc_set_feature(dwc_dev->core_if);
> +
> +	/* Initialize the DWC_otg core. */
> +	dwc_otg_core_init(dwc_dev->core_if);
> +
> +	/*
> +	 * Disable the global interrupt until all the interrupt
> +	 * handlers are installed.
> +	 */
> +	dwc_otg_disable_global_interrupts(dwc_dev->core_if);
> +
> +	/*
> +	 * Install the interrupt handler for the common interrupts before
> +	 * enabling common interrupts in core_init below.
> +	 */
> +	retval = request_irq(dwc_dev->irq, dwc_otg_common_irq,
> +			     IRQF_SHARED, "dwc_otg", dwc_dev);
> +	if (retval) {
> +		dev_err(dev, "request of irq%d failed retval: %d\n",
> +			dwc_dev->irq, retval);
> +		retval = -EBUSY;
> +		goto fail_req_irq;
> +	} else {
> +		dwc_dev->common_irq_installed = 1;
> +	}
> +
> +	if (!dwc_has_feature(dwc_dev->core_if, DWC_HOST_ONLY)) {
> +		/* Initialize the PCD */
> +		retval = dwc_otg_pcd_init(dev);
> +		if (retval) {
> +			dev_err(dev, "dwc_otg_pcd_init failed\n");
> +			dwc_dev->pcd = NULL;
> +			goto fail_req_irq;
> +		}
> +	}
> +
> +	gusbcfg_addr = (ulong) (dwc_dev->core_if->core_global_regs)
> +		+ DWC_GUSBCFG;
> +	if (!dwc_has_feature(dwc_dev->core_if, DWC_DEVICE_ONLY)) {
> +		/* Initialize the HCD and force_host_mode */
> +		usbcfg = dwc_read32(gusbcfg_addr);
> +		usbcfg |= DWC_USBCFG_FRC_HST_MODE;
> +		dwc_write32(gusbcfg_addr, usbcfg);
> +
> +		retval = dwc_otg_hcd_init(dev, dwc_dev);
> +		if (retval) {
> +			dev_err(dev, "dwc_otg_hcd_init failed\n");
> +			dwc_dev->hcd = NULL;
> +			goto fail_hcd;
> +		}
> +		/* configure chargepump interrupt */
> +		dwc_dev->hcd->cp_irq =
irq_of_parse_and_map(ofdev->dev.of_node,
> +							    3);
> +		if (dwc_dev->hcd->cp_irq) {
> +			retval = request_irq(dwc_dev->hcd->cp_irq,
> +					     dwc_otg_externalchgpump_irq,
> +					     IRQF_SHARED,
> +					     "dwc_otg_ext_chg_pump",
dwc_dev);
> +			if (retval) {
> +				dev_err(dev,
> +					"request of irq failed retval:
%d\n",
> +					retval);
> +				retval = -EBUSY;
> +				goto fail_hcd;
> +			} else {
> +				dev_dbg(dev, "%s: ExtChgPump Detection "
> +					"IRQ registered\n",
dwc_driver_name);
> +				dwc_dev->hcd->cp_irq_installed = 1;
> +			}
> +		}
> +	}
> +	/*
> +	 * Enable the global interrupt after all the interrupt
> +	 * handlers are installed.
> +	 */
> +	dwc_otg_enable_global_interrupts(dwc_dev->core_if);
> +
> +	usbcfg = dwc_read32(gusbcfg_addr);
> +	usbcfg &= ~DWC_USBCFG_FRC_HST_MODE;
> +	dwc_write32(gusbcfg_addr, usbcfg);
> +
> +	return 0;
> +fail_hcd:
> +	free_irq(dwc_dev->irq, dwc_dev);
> +	if (!dwc_has_feature(dwc_dev->core_if, DWC_HOST_ONLY)) {
> +		if (dwc_dev->pcd)
> +			dwc_otg_pcd_remove(dev);
> +	}
> +fail_req_irq:
> +	otg_put_transceiver(dwc_dev->core_if->xceiv);
> +fail_xceiv:
> +	usb_nop_xceiv_unregister();
> +fail_check_param:
> +	dwc_otg_cil_remove(dwc_dev->core_if);
> +fail_cil_init:
> +	dev_set_drvdata(dev, NULL);
> +	iounmap(dwc_dev->base);
> +fail_ioremap:
> +	release_mem_region(dwc_dev->phys_addr, dwc_dev->base_len);
> +fail_of_irq:
> +	kfree(dwc_dev);
> +fail_dwc_dev:
> +	return retval;
> +}
> +
> +/*
> + * This structure defines the methods to be called by a bus driver
> + * during the lifecycle of a device on that bus. Both drivers and
> + * devices are registered with a bus driver. The bus driver matches
> + * devices to drivers based on information in the device and driver
> + * structures.
> + *
> + * The probe function is called when the bus driver matches a device
> + * to this driver. The remove function is called when a device is
> + * unregistered with the bus driver.
> + */
> +static const struct of_device_id dwc_otg_match[] = {
> +	{.compatible = "amcc,dwc-otg",},
> +	{}
Do you need this line?


> +};
> +
> +MODULE_DEVICE_TABLE(of, dwc_otg_match);
> +
> +static struct platform_driver dwc_otg_driver = {
> +	.probe = dwc_otg_driver_probe,
> +	.remove = __devexit_p(dwc_otg_driver_remove),
> +	.driver = {
> +		   .name = "dwc_otg",
> +		   .owner = THIS_MODULE,
> +		   .of_match_table = dwc_otg_match,
> +		   },
> +};
> +
> +/**
> + * This function is called when the dwc_otg_driver is installed with
the
> + * insmod command. It registers the dwc_otg_driver structure with the
> + * appropriate bus driver. This will cause the dwc_otg_driver_probe
function
> + * to be called. In addition, the bus driver will automatically expose
> + * attributes defined for the device and driver in the special sysfs
file
> + * system.
> + */
> +static int __init dwc_otg_driver_init(void)
> +{
> +
> +	pr_info("%s: version %s\n", dwc_driver_name, DWC_DRIVER_VERSION);
> +	return platform_driver_register(&dwc_otg_driver);
> +}
> +
> +module_init(dwc_otg_driver_init);
> +
> +/**
> + * This function is called when the driver is removed from the kernel
> + * with the rmmod command. The driver unregisters itself with its bus
> + * driver.
> + *
> + */
> +static void __exit dwc_otg_driver_cleanup(void)
> +{
> +	platform_driver_unregister(&dwc_otg_driver);
> +}
> +
> +module_exit(dwc_otg_driver_cleanup);
> +
> +MODULE_DESCRIPTION(DWC_DRIVER_DESC);
> +MODULE_AUTHOR("Mark Miesfeld <mmiesfeld@apm.com");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/usb/otg/dwc/driver.h b/drivers/usb/otg/dwc/driver.h
> new file mode 100644
> index 0000000..a86532b
> --- /dev/null
> +++ b/drivers/usb/otg/dwc/driver.h
> @@ -0,0 +1,76 @@
> +/*
> + * DesignWare HS OTG controller driver
> + * Copyright (C) 2006 Synopsys, Inc.
> + * Portions Copyright (C) 2010 Applied Micro Circuits Corporation.
> + *
> + * This program is free software: you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License version 2 for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see http://www.gnu.org/licenses
> + * or write to the Free Software Foundation, Inc., 51 Franklin Street,
> + * Suite 500, Boston, MA 02110-1335 USA.
> + *
> + * Based on Synopsys driver version 2.60a
> + * Modified by Mark Miesfeld <mmiesfeld@apm.com>
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS"
> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO
THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE
> + * ARE DISCLAIMED. IN NO EVENT SHALL SYNOPSYS, INC. BE LIABLE FOR ANY
DIRECT,
> + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES
> + * (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES;
> + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND
> + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + */
> +
> +#if !defined(__DWC_OTG_DRIVER_H__)
> +#define __DWC_OTG_DRIVER_H__
> +
> +/*
> + * This file contains the interface to the Linux driver.
> + */
> +#include "cil.h"
> +
> +/*
> + * This structure is a wrapper that encapsulates the driver components
used to
> + * manage a single DWC_otg controller.
> + */
> +struct dwc_otg_device {
> +	/* Base address returned from ioremap() */
> +	__iomem void *base;
> +
> +	/* Pointer to the core interface structure. */
> +	struct core_if *core_if;
> +
> +	/* Pointer to the PCD structure. */
> +	struct dwc_pcd *pcd;
> +
> +	/* Pointer to the HCD structure. */
> +	struct dwc_hcd *hcd;
> +
> +	/* Flag to indicate whether the common IRQ handler is installed.
*/
> +	u8 common_irq_installed;
> +
> +	/* Interrupt request number. */
> +	unsigned int irq;
> +
> +	/*
> +	 * Physical address of Control and Status registers, used by
> +	 * release_mem_region().
> +	 */
> +	resource_size_t phys_addr;
> +
> +	/* Length of memory region, used by release_mem_region(). */
> +	unsigned long base_len;
> +};
> +#endif
> diff --git a/drivers/usb/otg/dwc/param.c b/drivers/usb/otg/dwc/param.c
> new file mode 100644
> index 0000000..523f0db
> --- /dev/null
> +++ b/drivers/usb/otg/dwc/param.c
> @@ -0,0 +1,180 @@
> +/*
> + * DesignWare HS OTG controller driver
> + * Copyright (C) 2006 Synopsys, Inc.
> + * Portions Copyright (C) 2010 Applied Micro Circuits Corporation.
> + *
> + * This program is free software: you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License version 2 for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see http://www.gnu.org/licenses
> + * or write to the Free Software Foundation, Inc., 51 Franklin Street,
> + * Suite 500, Boston, MA 02110-1335 USA.
> + *
> + * Based on Synopsys driver version 2.60a
> + * Modified by Mark Miesfeld <mmiesfeld@apm.com>
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS"
> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO
THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE
> + * ARE DISCLAIMED. IN NO EVENT SHALL SYNOPSYS, INC. BE LIABLE FOR ANY
DIRECT,
> + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES
> + * (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES;
> + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND
> + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + */
> +
> +/*
> + * This file provides dwc_otg driver parameter and parameter checking.
> + */
> +
> +#include "cil.h"
> +
> +/*
> + * Encapsulate the module parameter settings
> + */
> +struct core_params dwc_otg_module_params = {
> +	.otg_cap = -1,
> +	.dma_enable = -1,
> +	.dma_burst_size = -1,
> +	.speed = -1,
> +	.host_support_fs_ls_low_power = -1,
> +	.host_ls_low_power_phy_clk = -1,
> +	.enable_dynamic_fifo = -1,
> +	.dev_rx_fifo_size = -1,
> +	.dev_nperio_tx_fifo_size = -1,
> +	.dev_perio_tx_fifo_size = {-1, -1, -1, -1, -1, -1, -1, -1,
> +		-1, -1, -1, -1, -1, -1, -1},	/* 15 */
> +	.host_rx_fifo_size = -1,
> +	.host_nperio_tx_fifo_size = -1,
> +	.host_perio_tx_fifo_size = -1,
> +	.max_transfer_size = -1,
> +	.max_packet_count = -1,
> +	.host_channels = -1,
> +	.dev_endpoints = -1,
> +	.phy_type = -1,
> +	.phy_utmi_width = -1,
> +	.phy_ulpi_ddr = -1,
> +	.phy_ulpi_ext_vbus = -1,
> +	.i2c_enable = -1,
> +	.ulpi_fs_ls = -1,
> +	.ts_dline = -1,
> +	.en_multiple_tx_fifo = -1,
> +	.dev_tx_fifo_size = {-1, -1, -1, -1, -1, -1, -1, -1, -1,
> +		-1, -1, -1, -1, -1, -1},	/* 15 */
> +	.thr_ctl = -1,
> +	.tx_thr_length = -1,
> +	.rx_thr_length = -1,
> +};
> +
> +/**
> + * Checks that parameter settings for the periodic Tx FIFO sizes are
correct
> + * according to the hardware configuration. Sets the size to the
hardware
> + * configuration if an incorrect size is detected.
> + */
> +static int set_valid_perio_tx_fifo_sizes(struct core_if *core_if)
> +{
> +	ulong regs = (u32) core_if->core_global_regs;
> +	u32 *param_size =
&dwc_otg_module_params.dev_perio_tx_fifo_size[0];
> +	u32 i, size;

Tabify the declarations;

> +
> +	for (i = 0; i < MAX_PERIO_FIFOS; i++, param_size++) {
> +		size = dwc_read32(regs + DWC_DPTX_FSIZ_DIPTXF(i));
> +		*param_size = size;
> +	}
> +	return 0;
> +}
> +
> +/**
> + * Checks that parameter settings for the Tx FIFO sizes are correct
according to
> + * the hardware configuration.  Sets the size to the hardware
configuration if
> + * an incorrect size is detected.
> + */
> +static int set_valid_tx_fifo_sizes(struct core_if *core_if)
> +{
> +	ulong regs = (u32) core_if->core_global_regs;
> +	u32 *param_size = &dwc_otg_module_params.dev_tx_fifo_size[0];
> +	u32 i, size;

Tabify the declarations ;


> +
> +	for (i = 0; i < MAX_TX_FIFOS; i++, param_size) {
> +		size = dwc_read32(regs + DWC_DPTX_FSIZ_DIPTXF(i));
> +		*param_size = size;
> +	}
> +	return 0;
> +}
> +
> +/**
> + * This function is called during module intialization to verify that
> + * the module parameters are in a valid state.
> + */
> +int __devinit check_parameters(struct core_if *core_if)
> +{
> +	/* Default values */
> +	dwc_otg_module_params.otg_cap = dwc_param_otg_cap_default;
> +	dwc_otg_module_params.dma_enable = dwc_param_dma_enable_default;
> +	dwc_otg_module_params.speed = dwc_param_speed_default;
> +	dwc_otg_module_params.host_support_fs_ls_low_power =
> +	    dwc_param_host_support_fs_ls_low_power_default;
> +	dwc_otg_module_params.host_ls_low_power_phy_clk =
> +	    dwc_param_host_ls_low_power_phy_clk_default;
> +	dwc_otg_module_params.phy_type = dwc_param_phy_type_default;
> +	dwc_otg_module_params.phy_ulpi_ddr =
dwc_param_phy_ulpi_ddr_default;
> +	dwc_otg_module_params.phy_ulpi_ext_vbus =
> +	    dwc_param_phy_ulpi_ext_vbus_default;
> +	dwc_otg_module_params.i2c_enable = dwc_param_i2c_enable_default;
> +	dwc_otg_module_params.ulpi_fs_ls = dwc_param_ulpi_fs_ls_default;
> +	dwc_otg_module_params.ts_dline = dwc_param_ts_dline_default;
> +
> +	dwc_otg_module_params.dma_burst_size =
dwc_param_dma_burst_size_default;
> +	dwc_otg_module_params.phy_utmi_width =
dwc_param_phy_utmi_width_default;
> +	dwc_otg_module_params.thr_ctl = dwc_param_thr_ctl_default;
> +	dwc_otg_module_params.tx_thr_length =
dwc_param_tx_thr_length_default;
> +	dwc_otg_module_params.rx_thr_length =
dwc_param_rx_thr_length_default;
> +
> +	/*
> +	 * Hardware configurations of the OTG core.
> +	 */
> +	dwc_otg_module_params.enable_dynamic_fifo =
> +	    DWC_HWCFG2_DYN_FIFO_RD(core_if->hwcfg2);
> +	dwc_otg_module_params.dev_rx_fifo_size =
> +	    dwc_read32(core_if->core_global_regs + DWC_GRXFSIZ);
> +	dwc_otg_module_params.dev_nperio_tx_fifo_size =
> +	    dwc_read32(core_if->core_global_regs + DWC_GNPTXFSIZ) >> 16;
> +
> +	dwc_otg_module_params.host_rx_fifo_size =
> +	    dwc_read32(core_if->core_global_regs + DWC_GRXFSIZ);
> +	dwc_otg_module_params.host_nperio_tx_fifo_size =
> +	    dwc_read32(core_if->core_global_regs + DWC_GNPTXFSIZ) >> 16;
> +	dwc_otg_module_params.host_perio_tx_fifo_size =
> +	    dwc_read32(core_if->core_global_regs + DWC_HPTXFSIZ) >> 16;
> +	dwc_otg_module_params.max_transfer_size =
> +	    (1 << (DWC_HWCFG3_XFERSIZE_CTR_WIDTH_RD(core_if->hwcfg3) +
11))
> +	    - 1;
> +	dwc_otg_module_params.max_packet_count =
> +	    (1 << (DWC_HWCFG3_PKTSIZE_CTR_WIDTH_RD(core_if->hwcfg3) + 4))
> +	    - 1;
> +
> +	dwc_otg_module_params.host_channels =
> +	    DWC_HWCFG2_NO_HST_CHAN_RD(core_if->hwcfg2) + 1;
> +	dwc_otg_module_params.dev_endpoints =
> +	    DWC_HWCFG2_NO_DEV_EP_RD(core_if->hwcfg2);
> +	dwc_otg_module_params.en_multiple_tx_fifo =
> +	    (DWC_HWCFG4_DED_FIFO_ENA_RD(core_if->hwcfg4) == 0)
> +	    ? 0 : 1, 0;
> +	set_valid_perio_tx_fifo_sizes(core_if);
> +	set_valid_tx_fifo_sizes(core_if);
> +
> +	return 0;
> +}
> +
> +module_param_named(dma_enable, dwc_otg_module_params.dma_enable, bool,
0444);
> +MODULE_PARM_DESC(dma_enable, "DMA Mode 0=Slave 1=DMA enabled");
> --
> 1.6.1.rc3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox