LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [async_tx-next PATCH v2 1/2] fsldma: Fix cookie issues
From: Steven J. Magnani @ 2010-02-25 19:39 UTC (permalink / raw)
  To: Li Yang
  Cc: Ira W. Snyder, linux-kernel, linuxppc-dev, Zhang Wei,
	Steven J. Magnani, Dan Williams

fsl_dma_tx_submit() only sets the cookie on the first descriptor of a
transaction. It should set the cookie on all.

Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
---
diff -uprN a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
--- a/drivers/dma/fsldma.c	2010-02-22 11:16:36.000000000 -0600
+++ b/drivers/dma/fsldma.c	2010-02-22 11:24:01.000000000 -0600
@@ -362,7 +362,7 @@ static dma_cookie_t fsl_dma_tx_submit(st
 		if (cookie < 0)
 			cookie = 1;
 
-		desc->async_tx.cookie = cookie;
+		child->async_tx.cookie = cookie;
 	}
 
 	chan->common.cookie = cookie;

^ permalink raw reply

* [async_tx-next PATCH v2 2/2] fsldma: Fix cookie issues
From: Steven J. Magnani @ 2010-02-25 19:39 UTC (permalink / raw)
  To: Li Yang
  Cc: Ira W. Snyder, linux-kernel, linuxppc-dev, Zhang Wei,
	Steven J. Magnani, Dan Williams

fsl_dma_update_completed_cookie() appears to calculate the last completed
cookie incorrectly in the corner case where DMA on cookie 1 is in progress
just following a cookie wrap.

Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
---
diff -uprN a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
--- a/drivers/dma/fsldma.c	2010-02-22 11:16:36.000000000 -0600
+++ b/drivers/dma/fsldma.c	2010-02-22 11:08:41.000000000 -0600
@@ -819,8 +819,11 @@ static void fsl_dma_update_completed_coo
 	desc = to_fsl_desc(chan->ld_running.prev);
 	if (dma_is_idle(chan))
 		cookie = desc->async_tx.cookie;
-	else
+	else {
 		cookie = desc->async_tx.cookie - 1;
+		if (unlikely(cookie < DMA_MIN_COOKIE))
+			cookie = DMA_MAX_COOKIE;
+	}
 
 	chan->completed_cookie = cookie;
 
diff -uprN a/include/linux/dmaengine.h b/include/linux/dmaengine.h
--- a/include/linux/dmaengine.h	2010-02-22 11:18:11.000000000 -0600
+++ b/include/linux/dmaengine.h	2010-02-22 11:18:30.000000000 -0600
@@ -31,6 +31,8 @@
  * if dma_cookie_t is >0 it's a DMA request cookie, <0 it's an error code
  */
 typedef s32 dma_cookie_t;
+#define DMA_MIN_COOKIE	1
+#define DMA_MAX_COOKIE	((1 << 31) - 1)
 
 #define dma_submit_error(cookie) ((cookie) < 0 ? 1 : 0)
 

^ permalink raw reply

* RE: [PATCH 3/7] RapidIO: Add Port-Write handling for EM
From: Bounine, Alexandre @ 2010-02-25 20:30 UTC (permalink / raw)
  To: Micha Nelissen
  Cc: Alexandre Bounine, linux-kernel, thomas.moll, linuxppc-dev,
	thomas.moll.ext
In-Reply-To: <4B85894A.6040406@neli.hopto.org>

Micha Nelissen wrote:
>=20
> Alexandre Bounine wrote:
> >  /**
> > + * rio_em_set_ops- Sets Error Managment operations for a particular
vendor switch
> > + * @rdev: RIO device
> > + *
> > + * Searches the RIO EM ops table for known switch types. If the vid
> > + * and did match a switch table entry, then set the em_init() and
> > + * em_handle() ops to the table entry values.
>=20
> Shouldn't any RIO device be able to support error management, not just
> switches?

Only if a device reports this capability by having Error Management
Extended Features block.
Ideally, we have to provide default handler for every such device (I am
planning it for some future updates). It should be the same as for
routing operations - if the standard feature exists, it has to be used
unless something else takes over.

For now I keep all port-write messages from end-points serviced by their
individual drivers. One of reasons for this: the EM PW message format
definitions lacks any hint that allows to identify type of the message.
In theory endpoints may send port-writes of any format (up to max size
of 64 bytes), what makes unifying handling of endpoints more difficult
(at least at this stage of SRIO evolution).    =20
=20
> > +/**
> > + * rio_pw_enable - Enables/disables port-write handling by a master
port
> > + * @port: Master port associated with port-write handling
> > + * @enable:  1=3Denable,  0=3Ddisable
> > + */
> > +static void rio_pw_enable(struct rio_mport *port, int enable)
> > +{
> > +	if (port->ops->pwenable)
> > +		port->ops->pwenable(port, enable);
> > +}
> > +
>=20
> Maybe this can be done by switch->init function?

This is not per-switch function. This function enables mport to receive
incoming PW messages. Per-switch PW enable is done in switch->init as
for Tsi57x.=20

>=20
> > +/**
> > + * rio_inb_pwrite_handler - process inbound port-write message
> > + * @pw_msg: pointer to inbound port-write message
> > + *
> > + * Processes an inbound port-write message. Returns 0 if the
request
> > + * has been satisfied.
> > + */
> > +int rio_inb_pwrite_handler(u32 *pw_msg)
> > +{
>=20
> Perhaps map this pw_msg to a struct? Or read it into named variables?

Agree - this is not nice. The best way may be defining it as a union
which combines different message formats (EM at this point) and raw
array. Will change for next update.

>=20
> > +	/* Clear Port Errors */
> > +	rio_mport_write_config_32(mport, destid, hopcount,
> > +			rdev->phys_efptr +
RIO_PORT_N_ERR_STS_CSR(portnum),
> > +			err_status & 0x07120204);
>=20
> Hardcoded value!

Agree. Tagged for next drop.

>=20
> > +
> > +	if (rdev->rswitch->port_ok & (1 << portnum)) {
> > +		if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) {
> > +			rdev->rswitch->port_ok &=3D ~(1 << portnum);
> > +			rio_mport_read_config_32(mport, destid,
hopcount,
> > +				rdev->phys_efptr +
RIO_PORT_N_CTL_CSR(portnum),
> > +				&regval);
> > +			rio_mport_write_config_32(mport, destid,
hopcount,
> > +				rdev->phys_efptr +
RIO_PORT_N_CTL_CSR(portnum),
> > +				regval | RIO_PORT_N_CTL_LOCKOUT);
>=20
> You have a function for this?

Yes, I do. Will be fixed for the next drop.

>=20
> > +			rio_mport_write_config_32(mport, destid,
hopcount,
> > +				rdev->phys_efptr +
> > +					RIO_PORT_N_ACK_STS_CSR(portnum),
> > +				RIO_PORT_N_ACK_CLEAR);
>=20
> This doesn't work for the 568; but the 568 has no special handling?

Tsi568 will not send EM PW message. Tsi568 PWs are disabled in its
em_init().

>=20
> > +	/* Clear Port-Write Pending bit */
> > +	rio_mport_write_config_32(mport, destid, hopcount,
> > +			rdev->phys_efptr +
RIO_PORT_N_ERR_STS_CSR(portnum),
> > +			RIO_PORT_N_ERR_STS_PW_PEND);
> > +DECLARE_RIO_EM_OPS(RIO_VID_TUNDRA, RIO_DID_TSI572, tsi57x_em_init,
tsi57x_em_handler);
> > +DECLARE_RIO_EM_OPS(RIO_VID_TUNDRA, RIO_DID_TSI574, tsi57x_em_init,
tsi57x_em_handler);
> > +DECLARE_RIO_EM_OPS(RIO_VID_TUNDRA, RIO_DID_TSI577, tsi57x_em_init,
tsi57x_em_handler);
> > +DECLARE_RIO_EM_OPS(RIO_VID_TUNDRA, RIO_DID_TSI578, tsi57x_em_init,
tsi57x_em_handler);
>=20
> Why not declare these along with the other ops?

Because the EM extensions is a separate capability. It is not guaranteed
to be in every switch.

Alex.

^ permalink raw reply

* CONFIG_ISA_DMA_API without CONFIG_GENERIC_ISA_DMA
From: Scott Wood @ 2010-02-25 20:40 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev@ozlabs.org list

I tried building a kernel using mpc85xx_smp_defconfig, but with all 
platforms but p4080ds removed.  This was the result:

>   LD      .tmp_vmlinux1
> sound/built-in.o: In function `claim_dma_lock':
> /home/scott/git/fsl/linux/upstream/arch/powerpc/include/asm/dma.h:179: undefined reference to `dma_spin_lock'
> /home/scott/git/fsl/linux/upstream/arch/powerpc/include/asm/dma.h:179: undefined reference to `dma_spin_lock'
> /home/scott/git/fsl/linux/upstream/arch/powerpc/include/asm/dma.h:179: undefined reference to `dma_spin_lock'
> /home/scott/git/fsl/linux/upstream/arch/powerpc/include/asm/dma.h:179: undefined reference to `dma_spin_lock'
> /home/scott/git/fsl/linux/upstream/arch/powerpc/include/asm/dma.h:179: undefined reference to `dma_spin_lock'
> sound/built-in.o:/home/scott/git/fsl/linux/upstream/arch/powerpc/include/asm/dma.h:179: more undefined references to `dma_spin_lock' follow
> make: *** [.tmp_vmlinux1] Error 1

Commit fb4f0e8832e0075849b41b65f6bb9fdfa7593b99 (Enable GENERIC_ISA_DMA 
if FSL_ULI1575 to fix compile issue) tries to deal with this, but it 
ties it to CONFIG_FSL_ULI1575, which is not selected in a p4080ds-only 
config.

It seems that ULI isn't really relevant to the actual problem, which is 
that we enable ISA DMA API support without selecting an implementation. 
  Whether a certain chip is on the board that has an actual ISA 
interface is irrelevant to the build breakage.

Where did the dependency list for GENERIC_ISA_DMA come from?  Are there 
any legitimate cases on powerpc where we want to select ISA_DMA_API but 
not GENERIC_ISA_DMA (i.e. we have an alternate implementation)?

-Scott

^ permalink raw reply

* Re: PCI on 834x
From: Benjamin Herrenschmidt @ 2010-02-25 20:49 UTC (permalink / raw)
  To: Gary Thomas; +Cc: Scott Wood, linuxppc-dev, avorontsov
In-Reply-To: <4B86886B.5000304@mlbassoc.com>

On Thu, 2010-02-25 at 07:25 -0700, Gary Thomas wrote:
> I may have been too hasty pronouncing this fixed.  Indeed, the
> SATA interface now works, but my video card (Fujitsu Coral-P)
> does not work when it's mapped at the bottom of the PCI space :-(
> 
> With the bridge mapped, the video ends up at a non-zero address
> (0xC8000000..0xCFFFFFFF).  If it gets mapped to 0xC0000000, it
> fails to respond to MMIO accesses.
> 
> Any ideas how I might get around this?  Is there a way to force
> the PCI allocator to start somewhere other than [relative] zero?

I'm not familiar with the way the FSL bridge works, but it would
be possible to invert MMIO and DMA on your PCI bus. IE. Have MMIO go
from 0....2G and DMA from 2G..4G for example. Provided the FSL bridge
can offset the DMA back down to 0 (memory). Can it ?

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH 3/7] RapidIO: Add Port-Write handling for EM
From: Micha Nelissen @ 2010-02-25 21:02 UTC (permalink / raw)
  To: Bounine, Alexandre
  Cc: Alexandre Bounine, linux-kernel, thomas.moll, linuxppc-dev,
	thomas.moll.ext
In-Reply-To: <0CE8B6BE3C4AD74AB97D9D29BD24E552A5508A@CORPEXCH1.na.ads.idt.com>

Bounine, Alexandre wrote:
> Micha Nelissen wrote:
>> Alexandre Bounine wrote:
>>>  /**
>>> + * rio_em_set_ops- Sets Error Managment operations for a particular
> vendor switch
>>> + * @rdev: RIO device
>>> + *
>>> + * Searches the RIO EM ops table for known switch types. If the vid
>>> + * and did match a switch table entry, then set the em_init() and
>>> + * em_handle() ops to the table entry values.
>> Shouldn't any RIO device be able to support error management, not just
>> switches?
> 
> Only if a device reports this capability by having Error Management
> Extended Features block.
> Ideally, we have to provide default handler for every such device (I am
> planning it for some future updates). It should be the same as for
> routing operations - if the standard feature exists, it has to be used
> unless something else takes over.

Yes, therefore I thought that: or the EM_OPS are per driver, or they can 
be integrated in the switch hooks list.

> For now I keep all port-write messages from end-points serviced by their
> individual drivers. One of reasons for this: the EM PW message format

Maybe have a generic rio function that can be called by any driver that 
knows a particular port-write was due to error management causes? This 
function would read the standard defined EF block registers. Then the 
driver part can be quite small.

>>> +	if (port->ops->pwenable)
>>> +		port->ops->pwenable(port, enable);
>>> +}
>>> +
>> Maybe this can be done by switch->init function?
> 
> This is not per-switch function. This function enables mport to receive
> incoming PW messages. Per-switch PW enable is done in switch->init as
> for Tsi57x. 

Oops, I meant this comment for the em_init function call.

>>> +			rio_mport_write_config_32(mport, destid,
> hopcount,
>>> +				rdev->phys_efptr +
>>> +					RIO_PORT_N_ACK_STS_CSR(portnum),
>>> +				RIO_PORT_N_ACK_CLEAR);
>> This doesn't work for the 568; but the 568 has no special handling?
> 
> Tsi568 will not send EM PW message. Tsi568 PWs are disabled in its
> em_init().

Why?

>>> +DECLARE_RIO_EM_OPS(RIO_VID_TUNDRA, RIO_DID_TSI578, tsi57x_em_init,
> tsi57x_em_handler);
>> Why not declare these along with the other ops?
> 
> Because the EM extensions is a separate capability. It is not guaranteed
> to be in every switch.

They might initialize them with NULL to indicate they don't support it?

Micha

^ permalink raw reply

* Re: PCI on 834x
From: Scott Wood @ 2010-02-25 21:03 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, avorontsov, Gary Thomas
In-Reply-To: <1267130982.23523.1728.camel@pasglop>

Benjamin Herrenschmidt wrote:
> On Thu, 2010-02-25 at 07:25 -0700, Gary Thomas wrote:
>> I may have been too hasty pronouncing this fixed.  Indeed, the
>> SATA interface now works, but my video card (Fujitsu Coral-P)
>> does not work when it's mapped at the bottom of the PCI space :-(
>>
>> With the bridge mapped, the video ends up at a non-zero address
>> (0xC8000000..0xCFFFFFFF).  If it gets mapped to 0xC0000000, it
>> fails to respond to MMIO accesses.
>>
>> Any ideas how I might get around this?  Is there a way to force
>> the PCI allocator to start somewhere other than [relative] zero?
> 
> I'm not familiar with the way the FSL bridge works, but it would
> be possible to invert MMIO and DMA on your PCI bus. IE. Have MMIO go
> from 0....2G and DMA from 2G..4G for example. Provided the FSL bridge
> can offset the DMA back down to 0 (memory). Can it ?

It can, but I don't see how that would help, if the problem is that the 
video card doesn't like the low 30 bits of its MMIO address being zero.

Gary, can you check that the MMIO addresses are going to the PCI bus 
as-is, and aren't being translated down to zero?  I.e. POTARn should 
equal POBARn, and likewise in the device tree's pci node's ranges.

-Scott

^ permalink raw reply

* Re: PCI on 834x
From: Gary Thomas @ 2010-02-25 21:11 UTC (permalink / raw)
  To: Scott Wood; +Cc: avorontsov, linuxppc-dev
In-Reply-To: <4B86E5A7.9090607@freescale.com>

On 02/25/2010 02:03 PM, Scott Wood wrote:
> Benjamin Herrenschmidt wrote:
>> On Thu, 2010-02-25 at 07:25 -0700, Gary Thomas wrote:
>>> I may have been too hasty pronouncing this fixed. Indeed, the
>>> SATA interface now works, but my video card (Fujitsu Coral-P)
>>> does not work when it's mapped at the bottom of the PCI space :-(
>>>
>>> With the bridge mapped, the video ends up at a non-zero address
>>> (0xC8000000..0xCFFFFFFF). If it gets mapped to 0xC0000000, it
>>> fails to respond to MMIO accesses.
>>>
>>> Any ideas how I might get around this? Is there a way to force
>>> the PCI allocator to start somewhere other than [relative] zero?
>>
>> I'm not familiar with the way the FSL bridge works, but it would
>> be possible to invert MMIO and DMA on your PCI bus. IE. Have MMIO go
>> from 0....2G and DMA from 2G..4G for example. Provided the FSL bridge
>> can offset the DMA back down to 0 (memory). Can it ?
>
> It can, but I don't see how that would help, if the problem is that the video card doesn't like the low 30 bits of its MMIO address being zero.
>
> Gary, can you check that the MMIO addresses are going to the PCI bus as-is, and aren't being translated down to zero? I.e. POTARn should equal POBARn, and likewise in the device
> tree's pci node's ranges.

Hmm, that doesn't match with how I've always had this setup.  I have:
   POTAR0 = 0x00000000
   POTBR0 = 0x000C0000        (0xC0000000 >> 12)

My device tree mappings are:
   ranges = <0x02000000 0x0 0xC0000000 0xC0000000 0x0 0x10000000
             0x01000000 0x0 0x00000000 0xB8000000 0x0 0x00100000>

n.b. I don't run U-Boot on these platforms (being the author
of RedBoot and all... :-)

-- 
------------------------------------------------------------
Gary Thomas                 |  Consulting for the
MLB Associates              |    Embedded world
------------------------------------------------------------

^ permalink raw reply

* Re: PCI on 834x
From: Scott Wood @ 2010-02-25 21:24 UTC (permalink / raw)
  To: Gary Thomas; +Cc: avorontsov, linuxppc-dev
In-Reply-To: <4B86E794.6020403@mlbassoc.com>

Gary Thomas wrote:
> On 02/25/2010 02:03 PM, Scott Wood wrote:
>> Gary, can you check that the MMIO addresses are going to the PCI bus 
>> as-is, and aren't being translated down to zero? I.e. POTARn should 
>> equal POBARn, and likewise in the device
>> tree's pci node's ranges.
> 
> Hmm, that doesn't match with how I've always had this setup.  I have:
>   POTAR0 = 0x00000000
>   POTBR0 = 0x000C0000        (0xC0000000 >> 12)
> 
> My device tree mappings are:
>   ranges = <0x02000000 0x0 0xC0000000 0xC0000000 0x0 0x10000000
>             0x01000000 0x0 0x00000000 0xB8000000 0x0 0x00100000>

That ranges property says that host address 0xc0000000 maps to PCI 
address 0xc0000000, so Linux will program the BAR to 0xc0000000, but the 
actual accesses will go elsewhere because POTAR0 is zero.

Setting POTAR to zero is also a bad idea because it's aliasing your DMA 
window (it may work in certain situations based on who's initiating the 
transaction, but it seems like it's asking for trouble), plus it seems 
some cards just don't like address zero.

Try setting POTAR0 to 0x000c0000 and see what happens.

-Scott

^ permalink raw reply

* Re: PCI on 834x
From: Benjamin Herrenschmidt @ 2010-02-25 22:36 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev, avorontsov, Gary Thomas
In-Reply-To: <4B86E5A7.9090607@freescale.com>

On Thu, 2010-02-25 at 15:03 -0600, Scott Wood wrote:
> 
> It can, but I don't see how that would help, if the problem is that the 
> video card doesn't like the low 30 bits of its MMIO address being zero.

My idea was the video card, if it's an old piece of shit, may not be
decoding all address bits.

> Gary, can you check that the MMIO addresses are going to the PCI bus 
> as-is, and aren't being translated down to zero?  I.e. POTARn should 
> equal POBARn, and likewise in the device tree's pci node's ranges.

Cheers,
Ben.

^ permalink raw reply

* Re: PCI on 834x
From: Gary Thomas @ 2010-02-25 23:43 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev, avorontsov
In-Reply-To: <4B86EAA3.8000301@freescale.com>

On 02/25/2010 02:24 PM, Scott Wood wrote:
> Gary Thomas wrote:
>> On 02/25/2010 02:03 PM, Scott Wood wrote:
>>> Gary, can you check that the MMIO addresses are going to the PCI bus as-is, and aren't being translated down to zero? I.e. POTARn should equal POBARn, and likewise in the device
>>> tree's pci node's ranges.
>>
>> Hmm, that doesn't match with how I've always had this setup. I have:
>> POTAR0 = 0x00000000
>> POTBR0 = 0x000C0000 (0xC0000000 >> 12)
>>
>> My device tree mappings are:
>> ranges = <0x02000000 0x0 0xC0000000 0xC0000000 0x0 0x10000000
>> 0x01000000 0x0 0x00000000 0xB8000000 0x0 0x00100000>
>
> That ranges property says that host address 0xc0000000 maps to PCI address 0xc0000000, so Linux will program the BAR to 0xc0000000, but the actual accesses will go elsewhere
> because POTAR0 is zero.
>
> Setting POTAR to zero is also a bad idea because it's aliasing your DMA window (it may work in certain situations based on who's initiating the transaction, but it seems like it's
> asking for trouble), plus it seems some cards just don't like address zero.
>
> Try setting POTAR0 to 0x000c0000 and see what happens.

Sadly, that doesn't work at all - neither RedBoot nor Linux
can talk to any of the PCI devices.

-- 
------------------------------------------------------------
Gary Thomas                 |  Consulting for the
MLB Associates              |    Embedded world
------------------------------------------------------------

^ permalink raw reply

* Re: PCI on 834x
From: Scott Wood @ 2010-02-25 23:49 UTC (permalink / raw)
  To: Gary Thomas; +Cc: linuxppc-dev, avorontsov
In-Reply-To: <4B870B17.7080701@mlbassoc.com>

Gary Thomas wrote:
> On 02/25/2010 02:24 PM, Scott Wood wrote:
>> Gary Thomas wrote:
>>> On 02/25/2010 02:03 PM, Scott Wood wrote:
>>>> Gary, can you check that the MMIO addresses are going to the PCI bus 
>>>> as-is, and aren't being translated down to zero? I.e. POTARn should 
>>>> equal POBARn, and likewise in the device
>>>> tree's pci node's ranges.
>>>
>>> Hmm, that doesn't match with how I've always had this setup. I have:
>>> POTAR0 = 0x00000000
>>> POTBR0 = 0x000C0000 (0xC0000000 >> 12)
>>>
>>> My device tree mappings are:
>>> ranges = <0x02000000 0x0 0xC0000000 0xC0000000 0x0 0x10000000
>>> 0x01000000 0x0 0x00000000 0xB8000000 0x0 0x00100000>
>>
>> That ranges property says that host address 0xc0000000 maps to PCI 
>> address 0xc0000000, so Linux will program the BAR to 0xc0000000, but 
>> the actual accesses will go elsewhere
>> because POTAR0 is zero.
>>
>> Setting POTAR to zero is also a bad idea because it's aliasing your 
>> DMA window (it may work in certain situations based on who's 
>> initiating the transaction, but it seems like it's
>> asking for trouble), plus it seems some cards just don't like address 
>> zero.
>>
>> Try setting POTAR0 to 0x000c0000 and see what happens.
> 
> Sadly, that doesn't work at all - neither RedBoot nor Linux
> can talk to any of the PCI devices.

Make sure that whatever is doing the PCI enumeration is allocating MMIO 
addresses starting at 0xc0000000.  That anything worked at all before 
indicates that something was probably allocating from zero, despite 
what's in the device tree.

-Scott

^ permalink raw reply

* [PATCH 1/2] perf_event: Build callchain code regardless of hardware event support.
From: Scott Wood @ 2010-02-26  0:04 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: paulus

It's also useful for software events, as well as future support for
other types of hardware counters.

Signed-off-by: Scott Wood <scottwood@freescale.com>
---
 arch/powerpc/kernel/Makefile |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index c002b04..93fd162 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -98,7 +98,8 @@ obj64-$(CONFIG_AUDIT)		+= compat_audit.o
 
 obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o
-obj-$(CONFIG_PPC_PERF_CTRS)	+= perf_event.o perf_callchain.o
+obj-$(CONFIG_PERF_EVENTS)	+= perf_callchain.o
+obj-$(CONFIG_PPC_PERF_CTRS)	+= perf_event.o
 obj64-$(CONFIG_PPC_PERF_CTRS)	+= power4-pmu.o ppc970-pmu.o power5-pmu.o \
 				   power5+-pmu.o power6-pmu.o power7-pmu.o
 obj32-$(CONFIG_PPC_PERF_CTRS)	+= mpc7450-pmu.o
-- 
1.6.4.4

^ permalink raw reply related

* Re: [PATCH 1/2] perf_event: Build callchain code regardless of hardware event support.
From: Paul Mackerras @ 2010-02-26  0:09 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev
In-Reply-To: <20100226000433.GA17033@loki.buserror.net>

On Thu, Feb 25, 2010 at 06:04:33PM -0600, Scott Wood wrote:
> It's also useful for software events, as well as future support for
> other types of hardware counters.
> 
> Signed-off-by: Scott Wood <scottwood@freescale.com>

Acked-by: Paul Mackerras <paulus@samba.org>

^ permalink raw reply

* [PATCH 2/2] perf_event: e500 support
From: Scott Wood @ 2010-02-26  0:09 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: paulus

This implements perf_event support for the Freescale embedded performance
monitor, based on the existing perf_event.c that supports server/classic
chips.

Some limitations:
- Performance monitor interrupts are regular EE interrupts, and thus you
  can't profile places with interrupts disabled.  We may want to implement
  soft IRQ-disabling, with perfmon interrupts exempted and treated as NMIs.
- When trying to schedule multiple event groups at once, and using
  restricted events, situations could arise where scheduling fails even
  though it would be possible.  Consider three groups, each with two events.
  One group has restricted events, the others don't.  The two non-restricted
  groups are scheduled, then one is removed, which happens to occupy the two
  counters that can't do restricted events.  The remaining non-restricted
  group will not be moved to the non-restricted-capable counters to make
  room if the restricted group tries to be scheduled.

Signed-off-by: Scott Wood <scottwood@freescale.com>
---
Changes from previous version:
- Factored out callchain makefile patch
- Split up header files
- Renamed pmu struct
- Added threshold support

 arch/powerpc/include/asm/perf_event.h              |  133 +----
 arch/powerpc/include/asm/perf_event_fsl_emb.h      |   50 ++
 .../asm/{perf_event.h => perf_event_server.h}      |    4 +-
 arch/powerpc/include/asm/reg_fsl_emb.h             |    2 +-
 arch/powerpc/kernel/Makefile                       |    4 +
 arch/powerpc/kernel/cputable.c                     |    2 +-
 arch/powerpc/kernel/e500-pmu.c                     |  129 ++++
 arch/powerpc/kernel/perf_event_fsl_emb.c           |  654 ++++++++++++++++++++
 arch/powerpc/platforms/Kconfig.cputype             |   10 +
 9 files changed, 874 insertions(+), 114 deletions(-)
 rewrite arch/powerpc/include/asm/perf_event.h (92%)
 create mode 100644 arch/powerpc/include/asm/perf_event_fsl_emb.h
 rename arch/powerpc/include/asm/{perf_event.h => perf_event_server.h} (98%)
 create mode 100644 arch/powerpc/kernel/e500-pmu.c
 create mode 100644 arch/powerpc/kernel/perf_event_fsl_emb.c

diff --git a/arch/powerpc/include/asm/perf_event.h b/arch/powerpc/include/asm/perf_event.h
dissimilarity index 92%
index 3288ce3..e6d4ce6 100644
--- a/arch/powerpc/include/asm/perf_event.h
+++ b/arch/powerpc/include/asm/perf_event.h
@@ -1,110 +1,23 @@
-/*
- * Performance event support - PowerPC-specific definitions.
- *
- * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/types.h>
-
-#include <asm/hw_irq.h>
-
-#define MAX_HWEVENTS		8
-#define MAX_EVENT_ALTERNATIVES	8
-#define MAX_LIMITED_HWCOUNTERS	2
-
-/*
- * This struct provides the constants and functions needed to
- * describe the PMU on a particular POWER-family CPU.
- */
-struct power_pmu {
-	const char	*name;
-	int		n_counter;
-	int		max_alternatives;
-	unsigned long	add_fields;
-	unsigned long	test_adder;
-	int		(*compute_mmcr)(u64 events[], int n_ev,
-				unsigned int hwc[], unsigned long mmcr[]);
-	int		(*get_constraint)(u64 event_id, unsigned long *mskp,
-				unsigned long *valp);
-	int		(*get_alternatives)(u64 event_id, unsigned int flags,
-				u64 alt[]);
-	void		(*disable_pmc)(unsigned int pmc, unsigned long mmcr[]);
-	int		(*limited_pmc_event)(u64 event_id);
-	u32		flags;
-	int		n_generic;
-	int		*generic_events;
-	int		(*cache_events)[PERF_COUNT_HW_CACHE_MAX]
-			       [PERF_COUNT_HW_CACHE_OP_MAX]
-			       [PERF_COUNT_HW_CACHE_RESULT_MAX];
-};
-
-/*
- * Values for power_pmu.flags
- */
-#define PPMU_LIMITED_PMC5_6	1	/* PMC5/6 have limited function */
-#define PPMU_ALT_SIPR		2	/* uses alternate posn for SIPR/HV */
-
-/*
- * Values for flags to get_alternatives()
- */
-#define PPMU_LIMITED_PMC_OK	1	/* can put this on a limited PMC */
-#define PPMU_LIMITED_PMC_REQD	2	/* have to put this on a limited PMC */
-#define PPMU_ONLY_COUNT_RUN	4	/* only counting in run state */
-
-extern int register_power_pmu(struct power_pmu *);
-
-struct pt_regs;
-extern unsigned long perf_misc_flags(struct pt_regs *regs);
-extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
-
-#define PERF_EVENT_INDEX_OFFSET	1
-
-/*
- * Only override the default definitions in include/linux/perf_event.h
- * if we have hardware PMU support.
- */
-#ifdef CONFIG_PPC_PERF_CTRS
-#define perf_misc_flags(regs)	perf_misc_flags(regs)
-#endif
-
-/*
- * The power_pmu.get_constraint function returns a 32/64-bit value and
- * a 32/64-bit mask that express the constraints between this event_id and
- * other events.
- *
- * The value and mask are divided up into (non-overlapping) bitfields
- * of three different types:
- *
- * Select field: this expresses the constraint that some set of bits
- * in MMCR* needs to be set to a specific value for this event_id.  For a
- * select field, the mask contains 1s in every bit of the field, and
- * the value contains a unique value for each possible setting of the
- * MMCR* bits.  The constraint checking code will ensure that two events
- * that set the same field in their masks have the same value in their
- * value dwords.
- *
- * Add field: this expresses the constraint that there can be at most
- * N events in a particular class.  A field of k bits can be used for
- * N <= 2^(k-1) - 1.  The mask has the most significant bit of the field
- * set (and the other bits 0), and the value has only the least significant
- * bit of the field set.  In addition, the 'add_fields' and 'test_adder'
- * in the struct power_pmu for this processor come into play.  The
- * add_fields value contains 1 in the LSB of the field, and the
- * test_adder contains 2^(k-1) - 1 - N in the field.
- *
- * NAND field: this expresses the constraint that you may not have events
- * in all of a set of classes.  (For example, on PPC970, you can't select
- * events from the FPU, ISU and IDU simultaneously, although any two are
- * possible.)  For N classes, the field is N+1 bits wide, and each class
- * is assigned one bit from the least-significant N bits.  The mask has
- * only the most-significant bit set, and the value has only the bit
- * for the event_id's class set.  The test_adder has the least significant
- * bit set in the field.
- *
- * If an event_id is not subject to the constraint expressed by a particular
- * field, then it will have 0 in both the mask and value for that field.
- */
+/*
+ * Performance event support - hardware-specific disambiguation
+ *
+ * For now this is a compile-time decision, but eventually it should be
+ * runtime.  This would allow multiplatform perf event support for e300 (fsl
+ * embedded perf counters) plus server/classic, and would accommodate
+ * devices other than the core which provide their own performance counters.
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifdef CONFIG_PPC_PERF_CTRS
+#include <asm/perf_event_server.h>
+#endif
+
+#ifdef CONFIG_FSL_EMB_PERF_EVENT
+#include <asm/perf_event_fsl_emb.h>
+#endif
diff --git a/arch/powerpc/include/asm/perf_event_fsl_emb.h b/arch/powerpc/include/asm/perf_event_fsl_emb.h
new file mode 100644
index 0000000..718a9fa
--- /dev/null
+++ b/arch/powerpc/include/asm/perf_event_fsl_emb.h
@@ -0,0 +1,50 @@
+/*
+ * Performance event support - Freescale embedded specific definitions.
+ *
+ * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/types.h>
+#include <asm/hw_irq.h>
+
+#define MAX_HWEVENTS 4
+
+/* event flags */
+#define FSL_EMB_EVENT_VALID      1
+#define FSL_EMB_EVENT_RESTRICTED 2
+
+/* upper half of event flags is PMLCb */
+#define FSL_EMB_EVENT_THRESHMUL  0x0000070000000000ULL
+#define FSL_EMB_EVENT_THRESH     0x0000003f00000000ULL
+
+struct fsl_emb_pmu {
+	const char	*name;
+	int		n_counter; /* total number of counters */
+
+	/*
+	 * The number of contiguous counters starting at zero that
+	 * can hold restricted events, or zero if there are no
+	 * restricted events.
+	 *
+	 * This isn't a very flexible method of expressing constraints,
+	 * but it's very simple and is adequate for existing chips.
+	 */
+	int		n_restricted;
+
+	/* Returns event flags and PMLCb (FSL_EMB_EVENT_*) */
+	u64		(*xlate_event)(u64 event_id);
+
+	int		n_generic;
+	int		*generic_events;
+	int		(*cache_events)[PERF_COUNT_HW_CACHE_MAX]
+			       [PERF_COUNT_HW_CACHE_OP_MAX]
+			       [PERF_COUNT_HW_CACHE_RESULT_MAX];
+};
+
+int register_fsl_emb_pmu(struct fsl_emb_pmu *);
diff --git a/arch/powerpc/include/asm/perf_event.h b/arch/powerpc/include/asm/perf_event_server.h
similarity index 98%
rename from arch/powerpc/include/asm/perf_event.h
rename to arch/powerpc/include/asm/perf_event_server.h
index 3288ce3..8f1df12 100644
--- a/arch/powerpc/include/asm/perf_event.h
+++ b/arch/powerpc/include/asm/perf_event_server.h
@@ -1,5 +1,5 @@
 /*
- * Performance event support - PowerPC-specific definitions.
+ * Performance event support - PowerPC classic/server specific definitions.
  *
  * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
  *
@@ -8,8 +8,8 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-#include <linux/types.h>
 
+#include <linux/types.h>
 #include <asm/hw_irq.h>
 
 #define MAX_HWEVENTS		8
diff --git a/arch/powerpc/include/asm/reg_fsl_emb.h b/arch/powerpc/include/asm/reg_fsl_emb.h
index 0de404d..77bb71c 100644
--- a/arch/powerpc/include/asm/reg_fsl_emb.h
+++ b/arch/powerpc/include/asm/reg_fsl_emb.h
@@ -31,7 +31,7 @@
 #define PMLCA_FCM0	0x08000000	/* Freeze when PMM==0 */
 #define PMLCA_CE	0x04000000	/* Condition Enable */
 
-#define PMLCA_EVENT_MASK 0x007f0000	/* Event field */
+#define PMLCA_EVENT_MASK 0x00ff0000	/* Event field */
 #define PMLCA_EVENT_SHIFT	16
 
 #define PMRN_PMLCB0	0x110	/* PM Local Control B0 */
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 93fd162..8773263 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -99,11 +99,15 @@ obj64-$(CONFIG_AUDIT)		+= compat_audit.o
 obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o
 obj-$(CONFIG_PERF_EVENTS)	+= perf_callchain.o
+
 obj-$(CONFIG_PPC_PERF_CTRS)	+= perf_event.o
 obj64-$(CONFIG_PPC_PERF_CTRS)	+= power4-pmu.o ppc970-pmu.o power5-pmu.o \
 				   power5+-pmu.o power6-pmu.o power7-pmu.o
 obj32-$(CONFIG_PPC_PERF_CTRS)	+= mpc7450-pmu.o
 
+obj-$(CONFIG_FSL_EMB_PERF_EVENT) += perf_event_fsl_emb.o
+obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o
+
 obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o
 
 ifneq ($(CONFIG_PPC_INDIRECT_IO),y)
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 2fc82ba..8af4949 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -1808,7 +1808,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.icache_bsize		= 64,
 		.dcache_bsize		= 64,
 		.num_pmcs		= 4,
-		.oprofile_cpu_type	= "ppc/e500", /* xxx - galak, e500mc? */
+		.oprofile_cpu_type	= "ppc/e500mc",
 		.oprofile_type		= PPC_OPROFILE_FSL_EMB,
 		.cpu_setup		= __setup_cpu_e500mc,
 		.machine_check		= machine_check_e500,
diff --git a/arch/powerpc/kernel/e500-pmu.c b/arch/powerpc/kernel/e500-pmu.c
new file mode 100644
index 0000000..7c07de0
--- /dev/null
+++ b/arch/powerpc/kernel/e500-pmu.c
@@ -0,0 +1,129 @@
+/*
+ * Performance counter support for e500 family processors.
+ *
+ * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/string.h>
+#include <linux/perf_event.h>
+#include <asm/reg.h>
+#include <asm/cputable.h>
+
+/*
+ * Map of generic hardware event types to hardware events
+ * Zero if unsupported
+ */
+static int e500_generic_events[] = {
+	[PERF_COUNT_HW_CPU_CYCLES] = 1,
+	[PERF_COUNT_HW_INSTRUCTIONS] = 2,
+	[PERF_COUNT_HW_CACHE_MISSES] = 41, /* Data L1 cache reloads */
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 12,
+	[PERF_COUNT_HW_BRANCH_MISSES] = 15,
+};
+
+#define C(x)	PERF_COUNT_HW_CACHE_##x
+
+/*
+ * Table of generalized cache-related events.
+ * 0 means not supported, -1 means nonsensical, other values
+ * are event codes.
+ */
+static int e500_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+	/*
+	 * D-cache misses are not split into read/write/prefetch;
+	 * use raw event 41.
+	 */
+	[C(L1D)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	27,		0	},
+		[C(OP_WRITE)] = {	28,		0	},
+		[C(OP_PREFETCH)] = {	29,		0	},
+	},
+	[C(L1I)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	2,		60	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	0,		0	},
+	},
+	/*
+	 * Assuming LL means L2, it's not a good match for this model.
+	 * It allocates only on L1 castout or explicit prefetch, and
+	 * does not have separate read/write events (but it does have
+	 * separate instruction/data events).
+	 */
+	[C(LL)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	0,		0	},
+		[C(OP_WRITE)] = {	0,		0	},
+		[C(OP_PREFETCH)] = {	0,		0	},
+	},
+	/*
+	 * There are data/instruction MMU misses, but that's a miss on
+	 * the chip's internal level-one TLB which is probably not
+	 * what the user wants.  Instead, unified level-two TLB misses
+	 * are reported here.
+	 */
+	[C(DTLB)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	26,		66	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	-1,		-1	},
+	},
+	[C(BPU)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	12,		15 	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	-1,		-1	},
+	},
+};
+
+static int num_events = 128;
+
+/* Upper half of event id is PMLCb, for threshold events */
+static u64 e500_xlate_event(u64 event_id)
+{
+	u32 event_low = (u32)event_id;
+	u64 ret;
+
+	if (event_low >= num_events)
+		return 0;
+
+	ret = FSL_EMB_EVENT_VALID;
+
+	if (event_low >= 76 && event_low <= 81) {
+		ret |= FSL_EMB_EVENT_RESTRICTED;
+		ret |= event_id &
+		       (FSL_EMB_EVENT_THRESHMUL | FSL_EMB_EVENT_THRESH);
+	} else if (event_id &
+	           (FSL_EMB_EVENT_THRESHMUL | FSL_EMB_EVENT_THRESH)) {
+		/* Threshold requested on non-threshold event */
+		return 0;
+	}
+
+	return ret;
+}
+
+static struct fsl_emb_pmu e500_pmu = {
+	.name			= "e500 family",
+	.n_counter		= 4,
+	.n_restricted		= 2,
+	.xlate_event		= e500_xlate_event,
+	.n_generic		= ARRAY_SIZE(e500_generic_events),
+	.generic_events		= e500_generic_events,
+	.cache_events		= &e500_cache_events,
+};
+
+static int init_e500_pmu(void)
+{
+	if (!cur_cpu_spec->oprofile_cpu_type)
+		return -ENODEV;
+
+	if (!strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/e500mc"))
+		num_events = 256;
+	else if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/e500"))
+		return -ENODEV;
+
+	return register_fsl_emb_pmu(&e500_pmu);
+}
+
+arch_initcall(init_e500_pmu);
diff --git a/arch/powerpc/kernel/perf_event_fsl_emb.c b/arch/powerpc/kernel/perf_event_fsl_emb.c
new file mode 100644
index 0000000..369872f
--- /dev/null
+++ b/arch/powerpc/kernel/perf_event_fsl_emb.c
@@ -0,0 +1,654 @@
+/*
+ * Performance event support - Freescale Embedded Performance Monitor
+ *
+ * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/perf_event.h>
+#include <linux/percpu.h>
+#include <linux/hardirq.h>
+#include <asm/reg_fsl_emb.h>
+#include <asm/pmc.h>
+#include <asm/machdep.h>
+#include <asm/firmware.h>
+#include <asm/ptrace.h>
+
+struct cpu_hw_events {
+	int n_events;
+	int disabled;
+	u8  pmcs_enabled;
+	struct perf_event *event[MAX_HWEVENTS];
+};
+static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
+
+static struct fsl_emb_pmu *ppmu;
+
+/* Number of perf_events counting hardware events */
+static atomic_t num_events;
+/* Used to avoid races in calling reserve/release_pmc_hardware */
+static DEFINE_MUTEX(pmc_reserve_mutex);
+
+/*
+ * If interrupts were soft-disabled when a PMU interrupt occurs, treat
+ * it as an NMI.
+ */
+static inline int perf_intr_is_nmi(struct pt_regs *regs)
+{
+#ifdef __powerpc64__
+	return !regs->softe;
+#else
+	return 0;
+#endif
+}
+
+static void perf_event_interrupt(struct pt_regs *regs);
+
+/*
+ * Read one performance monitor counter (PMC).
+ */
+static unsigned long read_pmc(int idx)
+{
+	unsigned long val;
+
+	switch (idx) {
+	case 0:
+		val = mfpmr(PMRN_PMC0);
+		break;
+	case 1:
+		val = mfpmr(PMRN_PMC1);
+		break;
+	case 2:
+		val = mfpmr(PMRN_PMC2);
+		break;
+	case 3:
+		val = mfpmr(PMRN_PMC3);
+		break;
+	default:
+		printk(KERN_ERR "oops trying to read PMC%d\n", idx);
+		val = 0;
+	}
+	return val;
+}
+
+/*
+ * Write one PMC.
+ */
+static void write_pmc(int idx, unsigned long val)
+{
+	switch (idx) {
+	case 0:
+		mtpmr(PMRN_PMC0, val);
+		break;
+	case 1:
+		mtpmr(PMRN_PMC1, val);
+		break;
+	case 2:
+		mtpmr(PMRN_PMC2, val);
+		break;
+	case 3:
+		mtpmr(PMRN_PMC3, val);
+		break;
+	default:
+		printk(KERN_ERR "oops trying to write PMC%d\n", idx);
+	}
+
+	isync();
+}
+
+/*
+ * Write one local control A register
+ */
+static void write_pmlca(int idx, unsigned long val)
+{
+	switch (idx) {
+	case 0:
+		mtpmr(PMRN_PMLCA0, val);
+		break;
+	case 1:
+		mtpmr(PMRN_PMLCA1, val);
+		break;
+	case 2:
+		mtpmr(PMRN_PMLCA2, val);
+		break;
+	case 3:
+		mtpmr(PMRN_PMLCA3, val);
+		break;
+	default:
+		printk(KERN_ERR "oops trying to write PMLCA%d\n", idx);
+	}
+
+	isync();
+}
+
+/*
+ * Write one local control B register
+ */
+static void write_pmlcb(int idx, unsigned long val)
+{
+	switch (idx) {
+	case 0:
+		mtpmr(PMRN_PMLCB0, val);
+		break;
+	case 1:
+		mtpmr(PMRN_PMLCB1, val);
+		break;
+	case 2:
+		mtpmr(PMRN_PMLCB2, val);
+		break;
+	case 3:
+		mtpmr(PMRN_PMLCB3, val);
+		break;
+	default:
+		printk(KERN_ERR "oops trying to write PMLCB%d\n", idx);
+	}
+
+	isync();
+}
+
+static void fsl_emb_pmu_read(struct perf_event *event)
+{
+	s64 val, delta, prev;
+
+	/*
+	 * Performance monitor interrupts come even when interrupts
+	 * are soft-disabled, as long as interrupts are hard-enabled.
+	 * Therefore we treat them like NMIs.
+	 */
+	do {
+		prev = atomic64_read(&event->hw.prev_count);
+		barrier();
+		val = read_pmc(event->hw.idx);
+	} while (atomic64_cmpxchg(&event->hw.prev_count, prev, val) != prev);
+
+	/* The counters are only 32 bits wide */
+	delta = (val - prev) & 0xfffffffful;
+	atomic64_add(delta, &event->count);
+	atomic64_sub(delta, &event->hw.period_left);
+}
+
+/*
+ * Disable all events to prevent PMU interrupts and to allow
+ * events to be added or removed.
+ */
+void hw_perf_disable(void)
+{
+	struct cpu_hw_events *cpuhw;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	cpuhw = &__get_cpu_var(cpu_hw_events);
+
+	if (!cpuhw->disabled) {
+		cpuhw->disabled = 1;
+
+		/*
+		 * Check if we ever enabled the PMU on this cpu.
+		 */
+		if (!cpuhw->pmcs_enabled) {
+			ppc_enable_pmcs();
+			cpuhw->pmcs_enabled = 1;
+		}
+
+		if (atomic_read(&num_events)) {
+			/*
+			 * Set the 'freeze all counters' bit, and disable
+			 * interrupts.  The barrier is to make sure the
+			 * mtpmr has been executed and the PMU has frozen
+			 * the events before we return.
+			 */
+
+			mtpmr(PMRN_PMGC0, PMGC0_FAC);
+			isync();
+		}
+	}
+	local_irq_restore(flags);
+}
+
+/*
+ * Re-enable all events if disable == 0.
+ * If we were previously disabled and events were added, then
+ * put the new config on the PMU.
+ */
+void hw_perf_enable(void)
+{
+	struct cpu_hw_events *cpuhw;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	cpuhw = &__get_cpu_var(cpu_hw_events);
+	if (!cpuhw->disabled)
+		goto out;
+
+	cpuhw->disabled = 0;
+	ppc_set_pmu_inuse(cpuhw->n_events != 0);
+
+	if (cpuhw->n_events > 0) {
+		mtpmr(PMRN_PMGC0, PMGC0_PMIE | PMGC0_FCECE);
+		isync();
+	}
+
+ out:
+	local_irq_restore(flags);
+}
+
+static int collect_events(struct perf_event *group, int max_count,
+			  struct perf_event *ctrs[])
+{
+	int n = 0;
+	struct perf_event *event;
+
+	if (!is_software_event(group)) {
+		if (n >= max_count)
+			return -1;
+		ctrs[n] = group;
+		n++;
+	}
+	list_for_each_entry(event, &group->sibling_list, group_entry) {
+		if (!is_software_event(event) &&
+		    event->state != PERF_EVENT_STATE_OFF) {
+			if (n >= max_count)
+				return -1;
+			ctrs[n] = event;
+			n++;
+		}
+	}
+	return n;
+}
+
+/* perf must be disabled, context locked on entry */
+static int fsl_emb_pmu_enable(struct perf_event *event)
+{
+	struct cpu_hw_events *cpuhw;
+	int ret = -EAGAIN;
+	int num_counters = ppmu->n_counter;
+	u64 val;
+	int i;
+
+	cpuhw = &get_cpu_var(cpu_hw_events);
+
+	if (event->hw.config & FSL_EMB_EVENT_RESTRICTED)
+		num_counters = ppmu->n_restricted;
+
+	/*
+	 * Allocate counters from top-down, so that restricted-capable
+	 * counters are kept free as long as possible.
+	 */
+	for (i = num_counters - 1; i >= 0; i--) {
+		if (cpuhw->event[i])
+			continue;
+
+		break;
+	}
+
+	if (i < 0)
+		goto out;
+
+	event->hw.idx = i;
+	cpuhw->event[i] = event;
+	++cpuhw->n_events;
+
+	val = 0;
+	if (event->hw.sample_period) {
+		s64 left = atomic64_read(&event->hw.period_left);
+		if (left < 0x80000000L)
+			val = 0x80000000L - left;
+	}
+	atomic64_set(&event->hw.prev_count, val);
+	write_pmc(i, val);
+	perf_event_update_userpage(event);
+
+	write_pmlcb(i, event->hw.config >> 32);
+	write_pmlca(i, event->hw.config_base);
+
+	ret = 0;
+ out:
+	put_cpu_var(cpu_hw_events);
+	return ret;
+}
+
+/* perf must be disabled, context locked on entry */
+static void fsl_emb_pmu_disable(struct perf_event *event)
+{
+	struct cpu_hw_events *cpuhw;
+	int i = event->hw.idx;
+
+	if (i < 0)
+		goto out;
+
+	fsl_emb_pmu_read(event);
+
+	cpuhw = &get_cpu_var(cpu_hw_events);
+
+	WARN_ON(event != cpuhw->event[event->hw.idx]);
+
+	write_pmlca(i, 0);
+	write_pmlcb(i, 0);
+	write_pmc(i, 0);
+
+	cpuhw->event[i] = NULL;
+	event->hw.idx = -1;
+
+	/*
+	 * TODO: if at least one restricted event exists, and we
+	 * just freed up a non-restricted-capable counter, and
+	 * there is a restricted-capable counter occupied by
+	 * a non-restricted event, migrate that event to the
+	 * vacated counter.
+	 */
+
+	cpuhw->n_events--;
+
+ out:
+	put_cpu_var(cpu_hw_events);
+}
+
+/*
+ * Re-enable interrupts on a event after they were throttled
+ * because they were coming too fast.
+ *
+ * Context is locked on entry, but perf is not disabled.
+ */
+static void fsl_emb_pmu_unthrottle(struct perf_event *event)
+{
+	s64 val, left;
+	unsigned long flags;
+
+	if (event->hw.idx < 0 || !event->hw.sample_period)
+		return;
+	local_irq_save(flags);
+	perf_disable();
+	fsl_emb_pmu_read(event);
+	left = event->hw.sample_period;
+	event->hw.last_period = left;
+	val = 0;
+	if (left < 0x80000000L)
+		val = 0x80000000L - left;
+	write_pmc(event->hw.idx, val);
+	atomic64_set(&event->hw.prev_count, val);
+	atomic64_set(&event->hw.period_left, left);
+	perf_event_update_userpage(event);
+	perf_enable();
+	local_irq_restore(flags);
+}
+
+static struct pmu fsl_emb_pmu = {
+	.enable		= fsl_emb_pmu_enable,
+	.disable	= fsl_emb_pmu_disable,
+	.read		= fsl_emb_pmu_read,
+	.unthrottle	= fsl_emb_pmu_unthrottle,
+};
+
+/*
+ * Release the PMU if this is the last perf_event.
+ */
+static void hw_perf_event_destroy(struct perf_event *event)
+{
+	if (!atomic_add_unless(&num_events, -1, 1)) {
+		mutex_lock(&pmc_reserve_mutex);
+		if (atomic_dec_return(&num_events) == 0)
+			release_pmc_hardware();
+		mutex_unlock(&pmc_reserve_mutex);
+	}
+}
+
+/*
+ * Translate a generic cache event_id config to a raw event_id code.
+ */
+static int hw_perf_cache_event(u64 config, u64 *eventp)
+{
+	unsigned long type, op, result;
+	int ev;
+
+	if (!ppmu->cache_events)
+		return -EINVAL;
+
+	/* unpack config */
+	type = config & 0xff;
+	op = (config >> 8) & 0xff;
+	result = (config >> 16) & 0xff;
+
+	if (type >= PERF_COUNT_HW_CACHE_MAX ||
+	    op >= PERF_COUNT_HW_CACHE_OP_MAX ||
+	    result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+		return -EINVAL;
+
+	ev = (*ppmu->cache_events)[type][op][result];
+	if (ev == 0)
+		return -EOPNOTSUPP;
+	if (ev == -1)
+		return -EINVAL;
+	*eventp = ev;
+	return 0;
+}
+
+const struct pmu *hw_perf_event_init(struct perf_event *event)
+{
+	u64 ev;
+	struct perf_event *events[MAX_HWEVENTS];
+	int n;
+	int err;
+	int num_restricted;
+	int i;
+
+	switch (event->attr.type) {
+	case PERF_TYPE_HARDWARE:
+		ev = event->attr.config;
+		if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0)
+			return ERR_PTR(-EOPNOTSUPP);
+		ev = ppmu->generic_events[ev];
+		break;
+
+	case PERF_TYPE_HW_CACHE:
+		err = hw_perf_cache_event(event->attr.config, &ev);
+		if (err)
+			return ERR_PTR(err);
+		break;
+
+	case PERF_TYPE_RAW:
+		ev = event->attr.config;
+		break;
+
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+
+	event->hw.config = ppmu->xlate_event(ev);
+	if (!(event->hw.config & FSL_EMB_EVENT_VALID))
+		return ERR_PTR(-EINVAL);
+
+	/*
+	 * If this is in a group, check if it can go on with all the
+	 * other hardware events in the group.  We assume the event
+	 * hasn't been linked into its leader's sibling list at this point.
+	 */
+	n = 0;
+	if (event->group_leader != event) {
+		n = collect_events(event->group_leader,
+		                   ppmu->n_counter - 1, events);
+		if (n < 0)
+			return ERR_PTR(-EINVAL);
+	}
+
+	if (event->hw.config & FSL_EMB_EVENT_RESTRICTED) {
+		num_restricted = 0;
+		for (i = 0; i < n; i++) {
+			if (events[i]->hw.config & FSL_EMB_EVENT_RESTRICTED)
+				num_restricted++;
+		}
+
+		if (num_restricted >= ppmu->n_restricted)
+			return ERR_PTR(-EINVAL);
+	}
+
+	event->hw.idx = -1;
+
+	event->hw.config_base = PMLCA_CE | PMLCA_FCM1 |
+	                        (u32)((ev << 16) & PMLCA_EVENT_MASK);
+
+	if (event->attr.exclude_user)
+		event->hw.config_base |= PMLCA_FCU;
+	if (event->attr.exclude_kernel)
+		event->hw.config_base |= PMLCA_FCS;
+	if (event->attr.exclude_idle)
+		return ERR_PTR(-ENOTSUPP);
+
+	event->hw.last_period = event->hw.sample_period;
+	atomic64_set(&event->hw.period_left, event->hw.last_period);
+
+	/*
+	 * See if we need to reserve the PMU.
+	 * If no events are currently in use, then we have to take a
+	 * mutex to ensure that we don't race with another task doing
+	 * reserve_pmc_hardware or release_pmc_hardware.
+	 */
+	err = 0;
+	if (!atomic_inc_not_zero(&num_events)) {
+		mutex_lock(&pmc_reserve_mutex);
+		if (atomic_read(&num_events) == 0 &&
+		    reserve_pmc_hardware(perf_event_interrupt))
+			err = -EBUSY;
+		else
+			atomic_inc(&num_events);
+		mutex_unlock(&pmc_reserve_mutex);
+
+		mtpmr(PMRN_PMGC0, PMGC0_FAC);
+		isync();
+	}
+	event->destroy = hw_perf_event_destroy;
+
+	if (err)
+		return ERR_PTR(err);
+	return &fsl_emb_pmu;
+}
+
+/*
+ * A counter has overflowed; update its count and record
+ * things if requested.  Note that interrupts are hard-disabled
+ * here so there is no possibility of being interrupted.
+ */
+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;
+	int record = 0;
+
+	/* we don't have to worry about interrupts here */
+	prev = atomic64_read(&event->hw.prev_count);
+	delta = (val - prev) & 0xfffffffful;
+	atomic64_add(delta, &event->count);
+
+	/*
+	 * See if the total period for this event has expired,
+	 * and update for the next period.
+	 */
+	val = 0;
+	left = atomic64_read(&event->hw.period_left) - delta;
+	if (period) {
+		if (left <= 0) {
+			left += period;
+			if (left <= 0)
+				left = period;
+			record = 1;
+		}
+		if (left < 0x80000000LL)
+			val = 0x80000000LL - left;
+	}
+
+	/*
+	 * Finally record data if requested.
+	 */
+	if (record) {
+		struct perf_sample_data data = {
+			.period	= event->hw.last_period,
+		};
+
+		if (perf_event_overflow(event, nmi, &data, regs)) {
+			/*
+			 * Interrupts are coming too fast - throttle them
+			 * by setting the event to 0, so it will be
+			 * at least 2^30 cycles until the next interrupt
+			 * (assuming each event counts at most 2 counts
+			 * per cycle).
+			 */
+			val = 0;
+			left = ~0ULL >> 1;
+		}
+	}
+
+	write_pmc(event->hw.idx, val);
+	atomic64_set(&event->hw.prev_count, val);
+	atomic64_set(&event->hw.period_left, left);
+	perf_event_update_userpage(event);
+}
+
+static void perf_event_interrupt(struct pt_regs *regs)
+{
+	int i;
+	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+	struct perf_event *event;
+	unsigned long val;
+	int found = 0;
+	int nmi;
+
+	nmi = perf_intr_is_nmi(regs);
+	if (nmi)
+		nmi_enter();
+	else
+		irq_enter();
+
+	for (i = 0; i < ppmu->n_counter; ++i) {
+		event = cpuhw->event[i];
+
+		val = read_pmc(i);
+		if ((int)val < 0) {
+			if (event) {
+				/* event has overflowed */
+				found = 1;
+				record_and_restart(event, val, regs, nmi);
+			} else {
+				/*
+				 * Disabled counter is negative,
+				 * reset it just in case.
+				 */
+				write_pmc(i, 0);
+			}
+		}
+	}
+
+	/* PMM will keep counters frozen until we return from the interrupt. */
+	mtmsr(mfmsr() | MSR_PMM);
+	mtpmr(PMRN_PMGC0, PMGC0_PMIE | PMGC0_FCECE);
+	isync();
+
+	if (nmi)
+		nmi_exit();
+	else
+		irq_exit();
+}
+
+void hw_perf_event_setup(int cpu)
+{
+	struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
+
+	memset(cpuhw, 0, sizeof(*cpuhw));
+}
+
+int register_fsl_emb_pmu(struct fsl_emb_pmu *pmu)
+{
+	if (ppmu)
+		return -EBUSY;		/* something's already registered */
+
+	ppmu = pmu;
+	pr_info("%s performance monitor hardware support registered\n",
+		pmu->name);
+
+	return 0;
+}
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index fa0f690..a8aae0b 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -144,6 +144,16 @@ config FSL_EMB_PERFMON
 	  and some e300 cores (c3 and c4).  Select this only if your
 	  core supports the Embedded Performance Monitor APU
 
+config FSL_EMB_PERF_EVENT
+	bool
+	depends on FSL_EMB_PERFMON && PERF_EVENTS && !PPC_PERF_CTRS
+	default y
+
+config FSL_EMB_PERF_EVENT_E500
+	bool
+	depends on FSL_EMB_PERF_EVENT && E500
+	default y
+
 config 4xx
 	bool
 	depends on 40x || 44x
-- 
1.6.4.4

^ permalink raw reply related

* Re: Gianfar driver failing on MPC8641D based board
From: Paul Gortmaker @ 2010-02-26  0:53 UTC (permalink / raw)
  To: avorontsov
  Cc: netdev, linux-kernel, Martyn Welch, linuxppc-dev list,
	Sandeep Gopalpet, davem
In-Reply-To: <20100225174935.GA32370@oksana.dev.rtsoft.ru>

On Thu, Feb 25, 2010 at 12:49 PM, Anton Vorontsov
<avorontsov@ru.mvista.com> wrote:
> On Thu, Feb 25, 2010 at 07:51:41PM +0300, Anton Vorontsov wrote:
>> On Thu, Feb 25, 2010 at 04:46:54PM +0000, Martyn Welch wrote:
>> [...]
>> > > nfs: server 192.168.0.1 not responding, still trying
>> > >
>> >
>> > Further testing has shown that this isn't restricted to warm reboots, it
>> > happens from cold as well. In addition, the exact timing of the failure
>> > seems to vary, some boots have got further before failing.
>>
>> Unfortunately I don't have any 8641 boards near me, so I can't
>> debug this myself. Though, I tested gianfar on MPC8568E-MDS with
>> 2.6.33 kernel, and it seems to work just fine.
>>
>> I see you use SMP. Can you try to turn it off? If that will fix
>> the issue, then it'll be a good data point.
>>
>> Meanwhile, I'll try SMP kernel on MPC8568 (UP), and let you
>> know the results.
>
> Nope, no luck. Can't trigger the issue. :-/
> Tested with NFS boot, TCP and UDP netperf tests.

I was able to reproduce it on an 8641D and bisected it down to this:

-----------
commit a3bc1f11e9b867a4f49505ecac486a33af248b2e
Author: Anton Vorontsov <avorontsov@ru.mvista.com>
Date:   Tue Nov 10 14:11:10 2009 +0000

    gianfar: Revive SKB recycling

    Before calling gfar_clean_tx_ring() the driver grabs an irqsave
    spinlock, and then tries to recycle skbs. But since
    skb_recycle_check() returns 0 with IRQs disabled, we'll never
    recycle any skbs.

    It appears that gfar_clean_tx_ring() and gfar_start_xmit() are
    mostly idependent and can work in parallel, except when they
    modify num_txbdfree.

    So we can drop the lock from most sections and thus fix the skb
    recycling.
-----------

...which probably explains why you weren't seeing it on non-SMP.
I'd imagine it would show up on any of the e500mc boards too.

I'd done a rev-list on gianfar.[ch] from 32 to 33-rc1, and then
cherry-picked those onto a 32 baseline to reduce the scale of
the bisection, but I don't think that should impact the final
result I got in any meaningful way.

Paul.

^ permalink raw reply

* Re: [Patch 1/1] PPC64-HWBKPT: Implement hw-breakpoints for PPC64
From: Frederic Weisbecker @ 2010-02-26  1:58 UTC (permalink / raw)
  To: K.Prasad
  Cc: Michael Neuling, Benjamin Herrenschmidt, shaggy,
	Mahesh Salgaonkar, Will Deacon, David Gibson, linuxppc-dev,
	Alan Stern, paulus, Roland McGrath
In-Reply-To: <20100222131746.GA3228@in.ibm.com>

On Mon, Feb 22, 2010 at 06:47:46PM +0530, K.Prasad wrote:
> The 'name' field here is actually a legacy inherited from x86 code. It
> is part of x86's arch-specific hw-breakpoint structure since:
> - inspired by the kprobe implementation which accepts symbol name as
>   input.
> - kallsyms_lookup_name() was 'unexported' and a module could not resolve
>   symbol names externally, so the core-infrastructure had to provide
>   such facilities.
> - I wasn't sure about the discussions behind 'unexporting' of
>   kallsyms_lookup_name(), so did not venture to export them again (which
>   you rightfully did :-)
> 
> Having said that, I'll be glad to remove this field (along with that in
> x86),



Cool, I'll integrate the x86 name field removal to the .24 series



> provided we know that there's a way for the user to resolve symbol
> names on its own i.e. routines like kallsyms_lookup_name() will remain
> exported.


Yeah, I guess it's fine to keep kallsyms_lookup_name() exported.


 
> > Also, do you think addr/len/type is enough to abstract out
> > any ppc breakpoints?
> > 
> > This looks enough to me to express range breakpoints and
> > simple breakpoints. But what about value comparison?
> > (And still, there may be other trickier implementations
> > I don't know in ppc).
> > 
> 
> The above implementation is for PPC64 architecture that supports only
> 'simple' breakpoints of fixed length (no range breakpoints, no value
> comparison). More on that below.


Ok. I was just a bit confused in the middle of the several PPC breakpoint
implementations :)



> > > +	/*
> > > +	 * As a policy, the callback is invoked in a 'trigger-after-execute'
> > > +	 * fashion
> > > +	 */
> > > +	(bp->overflow_handler)(bp, 0, NULL, regs);
> > 
> > 
> > Why are you calling this explicitly instead of using the perf_bp_event()
> > thing? This looks like it won't work with perf as the event won't
> > be recorded by perf.
> > 
> 
> Yes, should have invoked perf_bp_event() for perf to work well (on a
> side note, it makes me wonder at the amount of 'extra' code that each
> breakpoint exception would execute if it were not called through perf
> sys-call...well, the costs of integrating with a generic infrastructure!)


It has the benefit of not adding extra checks in the breakpoint handler,
like checking the callback. Every breakpoint is treated the same way, which
makes the code more simple.


 
> > > +void ptrace_triggered(struct perf_event *bp, int nmi,
> > > +		      struct perf_sample_data *data, struct pt_regs *regs)
> > > +{
> > > +	struct perf_event_attr attr;
> > > +
> > > +	/*
> > > +	 * Disable the breakpoint request here since ptrace has defined a
> > > +	 * one-shot behaviour for breakpoint exceptions in PPC64.
> > > +	 * The SIGTRAP signal is generated automatically for us in do_dabr().
> > > +	 * We don't have to do anything about that here
> > > +	 */
> > 
> > 
> > Oh, why does ptrace use a one-shot behaviour in ppc? Breakpoints
> > only trigger once?
> > 
> 
> Yes, ptrace breakpoints on PPC64 are designed to trigger once and this
> patch retains that behaviour. It is very convenient to use one-shot
> behaviour on archs where exceptions are triggered-before-execute.


Ah, Why?



> > This looks fine for basic breakpoints. And this can probably be
> > improved to integrate ranges.
> > 
> > But I think we did something wrong with the generic breakpoint
> > interface. We are translating the arch values to generic
> > attributes. Then this all will be translated back to arch
> > values.
> > 
> > Having generic attributes is necessary for any perf event
> > use from userspace. But it looks like a waste for ptrace
> > that already gives us arch values. And the problem
> > is the same for x86.
> > 
> > So I think we should implement a register_ptrace_breakpoint()
> > that doesn't take perf_event_attr but specific arch informations,
> > so that we don't need to pass through a generic conversion, which:
> > 
> 
> I agree that the layers of conversion from generic to arch-specific
> breakpoint constants is wasteful.
> Can't the arch_bp_generic_fields() function be moved to
> arch/x86/kernel/ptrace.c instead of a new interface?


I'll answer in your subsequent mail :)


 
> > - is wasteful
> > - won't be able to express 100% of any arch capabilities. We
> >   can certainly express most arch breakpoints features through
> >   the generic interface, but not all of them (given how tricky
> >   the data value comparison features can be)
> > 
> > I will rework that during the next cycle.
> > 
> > Thanks.
> >
> 
> Thank you for the comments. I will re-send a new version of the patch
> with the perf_bp_event() substitution.


Thanks.

^ permalink raw reply

* Does Linux 2.6.32 support NAND flash connect with MPC8247 through localbus with GPCM mode?
From: Peter Pan @ 2010-02-26  2:08 UTC (permalink / raw)
  To: linuxppc-dev

I'm recently porting Linux 2.6.32 to our custom board with MPC8247. We have a
NAND flash connected using GPCM mode of local bus. But after I search
through the Linux
source, there is no compatible like "fsl,gpcm-nand". And I can not
find any driver
that seems works for our scene.

Does Linux 2.6.32 has the support for such nand device or I need to
construct my own
NAND driver using generic platform NAND driver?

^ permalink raw reply

* Re: Gianfar driver failing on MPC8641D based board
From: Anton Vorontsov @ 2010-02-26  3:14 UTC (permalink / raw)
  To: Paul Gortmaker
  Cc: netdev, linux-kernel, Martyn Welch, linuxppc-dev list,
	Sandeep Gopalpet, davem
In-Reply-To: <7d1d9c251002251653n6473f01ex2d43933ec6aa010b@mail.gmail.com>

On Thu, Feb 25, 2010 at 07:53:30PM -0500, Paul Gortmaker wrote:
[...]
> I was able to reproduce it on an 8641D and bisected it down to this:
> 
> -----------
> commit a3bc1f11e9b867a4f49505ecac486a33af248b2e
> Author: Anton Vorontsov <avorontsov@ru.mvista.com>
> Date:   Tue Nov 10 14:11:10 2009 +0000
> 
>     gianfar: Revive SKB recycling

Thanks for the bisect. I have a guess why tx hangs in
SMP case. Could anyone try the patch down below?

[...]
> ...which probably explains why you weren't seeing it on non-SMP.
> I'd imagine it would show up on any of the e500mc boards too.

Yeah.. Pity, I don't have SMP boards anymore. I'll try
to get one though.


diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 8bd3c9f..3ff3bd0 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -2614,6 +2614,8 @@ static int gfar_poll(struct napi_struct *napi, int budget)
 			tx_queue = priv->tx_queue[rx_queue->qindex];
 
 			tx_cleaned += gfar_clean_tx_ring(tx_queue);
+			if (!tx_cleaned && !tx_queue->num_txbdfree)
+				tx_cleaned += 1; /* don't complete napi */
 			rx_cleaned_per_queue = gfar_clean_rx_ring(rx_queue,
 							budget_per_queue);
 			rx_cleaned += rx_cleaned_per_queue;

^ permalink raw reply related

* RE: Gianfar driver failing on MPC8641D based board
From: Kumar Gopalpet-B05799 @ 2010-02-26  4:58 UTC (permalink / raw)
  To: avorontsov, Paul Gortmaker
  Cc: netdev, linux-kernel, Martyn Welch, linuxppc-dev list, davem
In-Reply-To: <20100226031452.GA11319@oksana.dev.rtsoft.ru>

=20

>-----Original Message-----
>From: Anton Vorontsov [mailto:avorontsov@ru.mvista.com]=20
>Sent: Friday, February 26, 2010 8:45 AM
>To: Paul Gortmaker
>Cc: Martyn Welch; linuxppc-dev list; netdev@vger.kernel.org;=20
>linux-kernel@vger.kernel.org; Kumar Gopalpet-B05799;=20
>davem@davemloft.net; Kumar Gala
>Subject: Re: Gianfar driver failing on MPC8641D based board
>
>On Thu, Feb 25, 2010 at 07:53:30PM -0500, Paul Gortmaker wrote:
>[...]
>> I was able to reproduce it on an 8641D and bisected it down to this:
>>=20
>> -----------
>> commit a3bc1f11e9b867a4f49505ecac486a33af248b2e
>> Author: Anton Vorontsov <avorontsov@ru.mvista.com>
>> Date:   Tue Nov 10 14:11:10 2009 +0000
>>=20
>>     gianfar: Revive SKB recycling
>
>Thanks for the bisect. I have a guess why tx hangs in SMP=20
>case. Could anyone try the patch down below?
>
>[...]
>> ...which probably explains why you weren't seeing it on non-SMP.
>> I'd imagine it would show up on any of the e500mc boards too.
>
>Yeah.. Pity, I don't have SMP boards anymore. I'll try to get=20
>one though.
>
>
>diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c=20
>index 8bd3c9f..3ff3bd0 100644
>--- a/drivers/net/gianfar.c
>+++ b/drivers/net/gianfar.c
>@@ -2614,6 +2614,8 @@ static int gfar_poll(struct napi_struct=20
>*napi, int budget)
> 			tx_queue =3D priv->tx_queue[rx_queue->qindex];
>=20
> 			tx_cleaned +=3D gfar_clean_tx_ring(tx_queue);
>+			if (!tx_cleaned && !tx_queue->num_txbdfree)
>+				tx_cleaned +=3D 1; /* don't=20
>complete napi */
> 			rx_cleaned_per_queue =3D=20
>gfar_clean_rx_ring(rx_queue,
> 						=09
>budget_per_queue);
> 			rx_cleaned +=3D rx_cleaned_per_queue;
>

Anton,=20

There is also one more issue that I have been observing with the patch
"gianfar: Revive SKB recycling".
The issue is when I do a IPV4 forwarding test scenario with
bidirectional flows (SMP environment). I am using Spirent smart bits
(smartflow) for automation testing and I frequently observe smart flow
reporting "Rx packet counte greater than Tx packet count. Duplicate
packets might have been received".

To just get over the issue I have removed this patch and I didn't see
the issue.

To a certain extent I could get over the problem by using atomic_t for
num_txbdfree (atomic_add and atomic_dec instructions for updating the
num_txbdfree) and completely removing the spin_locks in the tx routines.

Also, I feel we might want to make some more changes to the
gfar_clean_tx_ring( ) and gfar_start_xmit() routines so that they can
operate parallely.=20

I am really sorry for not posting it a bit earlier as I am caught up
with some urgent issues.

--

Thanks
Sandeep

^ permalink raw reply

* [PATCH] powerpc: export data from new hcall H_EM_GET_PARMS
From: Vaidyanathan Srinivasan @ 2010-02-26  6:05 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Paul Mackerras, Anton Blanchard; +Cc: linuxppc-dev

Hi,

A new hcall H_EM_GET_PARMS as been added to obtain power mode data
from the platform.  This data can be used by user space administrative
tools for better power management.

The following patch add data from this new hcall into the lparcfg
driver and exports to user space along with other existing lpar data
in /proc/powerpc/lparcfg

Please review and include in powerpc tree.

Thanks,
Vaidy

---
    	powerpc: export data from new hcall H_EM_GET_PARMS
    
        Add support for H_EM_GET_PARM hcall that will return data
        related to power modes from the platform.  Export the data
        directly to user space for administrative tools to interpret
        and use.
    
    	cat /proc/powerpc/lparcfg will export power mode data
    
Signed-off-by: Vaidyanathan Srinivasan <svaidy@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/hvcall.h |    1 +
 arch/powerpc/kernel/lparcfg.c     |   19 ++++++++++++++++++-
 2 files changed, 19 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index f027581..ebe7493 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -228,6 +228,7 @@
 #define H_JOIN			0x298
 #define H_VASI_STATE            0x2A4
 #define H_ENABLE_CRQ		0x2B0
+#define H_GET_EM_PARMS		0x2B8
 #define H_SET_MPP		0x2D0
 #define H_GET_MPP		0x2D4
 #define MAX_HCALL_OPCODE	H_GET_MPP
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index 79a00bb..2e7dd7e 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -37,7 +37,7 @@
 #include <asm/vio.h>
 #include <asm/mmu.h>
 
-#define MODULE_VERS "1.8"
+#define MODULE_VERS "1.9"
 #define MODULE_NAME "lparcfg"
 
 /* #define LPARCFG_DEBUG */
@@ -486,6 +486,21 @@ static void splpar_dispatch_data(struct seq_file *m)
 	seq_printf(m, "dispatch_dispersions=%lu\n", dispatch_dispersions);
 }
 
+
+static void parse_em_data(struct seq_file *m)
+{
+	int rc;
+	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+	rc = plpar_hcall(H_GET_EM_PARMS, retbuf);
+
+	if (rc != H_SUCCESS)
+		return;
+
+	seq_printf(m, "power_mode_data=%016lx\n", retbuf[0]);
+	return;
+
+}
 static int pseries_lparcfg_data(struct seq_file *m, void *v)
 {
 	int partition_potential_processors;
@@ -540,6 +555,8 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v)
 
 	seq_printf(m, "slb_size=%d\n", mmu_slb_size);
 
+	parse_em_data(m);
+
 	return 0;
 }

^ permalink raw reply related

* powerpc: bump SECTION_SIZE_BITS from 16MB to 256MB
From: Anton Blanchard @ 2010-02-26  6:18 UTC (permalink / raw)
  To: benh; +Cc: linuxppc-dev


The current setting for SECTION_SIZE_BITS is quite small compared to
everyone else:

arch/powerpc/include/asm/sparsemem.h:#define SECTION_SIZE_BITS  24

arch/sparc/include/asm/sparsemem.h:#define SECTION_SIZE_BITS    30
arch/ia64/include/asm/sparsemem.h:#define SECTION_SIZE_BITS     (30)
arch/s390/include/asm/sparsemem.h:#define SECTION_SIZE_BITS     28
arch/x86/include/asm/sparsemem.h:# define SECTION_SIZE_BITS     27 

And it has proven to be an issue during boot on very large machines.
If hotplug memory is enabled, drivers/base/memory.c does this:

       for (i = 0; i < NR_MEM_SECTIONS; i++) {
                if (!present_section_nr(i))
                        continue;
                err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE,
                                        0, BOOT);
                if (!ret)
                        ret = err;
        }

Which creates a sysfs directory for every 16MB of memory. As a result
I'm seeing up to 30 minutes spent here during boot:

c000000000248ee0 .__sysfs_add_one+0x28/0x128
c0000000002492a8 .sysfs_add_one+0x38/0x188
c000000000249c88 .create_dir+0x70/0x138
c000000000249d98 .sysfs_create_dir+0x48/0x78
c00000000032bad8 .kobject_add_internal+0x140/0x308
c00000000032beb4 .kobject_init_and_add+0x4c/0x68
c00000000046c2c0 .sysdev_register+0xa0/0x220
c00000000047b1dc .add_memory_block+0x124/0x1e8
c0000000008d1f28 .memory_dev_init+0xf4/0x168
c0000000008d1b64 .driver_init+0x50/0x64
c000000000890378 .do_basic_setup+0x40/0xd4

I assume there are some O(n^2) issues in sysfs as we add all the memory
nodes. Bumping SECTION_SIZE_BITS to 256 MB drops the time to about 10
seconds and results in a much smaller /sys.

Signed-off-by: Anton Blanchard <anton@samba.org>
---

--- linux-2.6.33/arch/powerpc/include/asm/sparsemem.h~	2010-02-25 22:53:54.000000000 -0600
+++ linux-2.6.33/arch/powerpc/include/asm/sparsemem.h	2010-02-25 22:54:06.000000000 -0600
@@ -8,7 +8,7 @@
  * MAX_PHYSADDR_BITS		2^N: how much physical address space we have
  * MAX_PHYSMEM_BITS		2^N: how much memory we can have in that space
  */
-#define SECTION_SIZE_BITS       24
+#define SECTION_SIZE_BITS       28
 
 #define MAX_PHYSADDR_BITS       44
 #define MAX_PHYSMEM_BITS        44

^ permalink raw reply

* [PATCH] powerpc: Fix lwsync feature fixup vs. modules on 64-bit
From: Benjamin Herrenschmidt @ 2010-02-26  7:30 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Anton Blanchard

Anton's commit enabling the use of the lwsync fixup mechanism on 64-bit
breaks modules. The lwsync fixup section uses .long instead of the
FTR_ENTRY_OFFSET macro used by other fixups sections, and thus will
generate 32-bit relocations that our module loader cannot resolve.

This changes it to use the same type as other feature sections.

Note however that we might want to consider using 32-bit for all the
feature fixup offsets and add support for R_PPC_REL32 to module_64.c
instead as that would reduce the size of the kernel image. I'll leave
that as an exercise for the reader for now...

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 arch/powerpc/include/asm/feature-fixups.h |    2 +-
 arch/powerpc/lib/feature-fixups.c         |    3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h
index cbd4dfa..96a7d06 100644
--- a/arch/powerpc/include/asm/feature-fixups.h
+++ b/arch/powerpc/include/asm/feature-fixups.h
@@ -165,7 +165,7 @@ label##2:						\
 	.pushsection sect,"a";				\
 	.align 2;					\
 label##3:					       	\
-	.long label##1b-label##3b;			\
+	FTR_ENTRY_OFFSET label##1b-label##3b;		\
 	.popsection;
 
 #endif /* __ASM_POWERPC_FEATURE_FIXUPS_H */
diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
index 4dee652..e640175 100644
--- a/arch/powerpc/lib/feature-fixups.c
+++ b/arch/powerpc/lib/feature-fixups.c
@@ -112,7 +112,8 @@ void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
 
 void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
 {
-	int *start, *end, *dest;
+	long *start, *end;
+	unsigned int *dest;
 
 	if (!(value & CPU_FTR_LWSYNC))
 		return ;

^ permalink raw reply related

* [PATCH 1/4] 8xx: Optimze TLB Miss handlers
From: Joakim Tjernlund @ 2010-02-26  8:29 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <1267172983-28721-1-git-send-email-Joakim.Tjernlund@transmode.se>

This removes a couple of insn's from the TLB Miss
handlers whithout changing functionality.
---
 arch/powerpc/kernel/head_8xx.S |   11 +++--------
 1 files changed, 3 insertions(+), 8 deletions(-)

diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index 3ef743f..ecc4a02 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -343,17 +343,14 @@ InstructionTLBMiss:
 	cmpwi	cr0, r11, _PAGE_ACCESSED | _PAGE_PRESENT
 	bne-	cr0, 2f
 
-	/* Clear PP lsb, 0x400 */
-	rlwinm 	r10, r10, 0, 22, 20
-
 	/* The Linux PTE won't go exactly into the MMU TLB.
-	 * Software indicator bits 22 and 28 must be clear.
+	 * Software indicator bits 21 and 28 must be clear.
 	 * Software indicator bits 24, 25, 26, and 27 must be
 	 * set.  All other Linux PTE bits control the behavior
 	 * of the MMU.
 	 */
 	li	r11, 0x00f0
-	rlwimi	r10, r11, 0, 24, 28	/* Set 24-27, clear 28 */
+	rlwimi	r10, r11, 0, 0x07f8	/* Set 24-27, clear 21-23,28 */
 	DO_8xx_CPU6(0x2d80, r3)
 	mtspr	SPRN_MI_RPN, r10	/* Update TLB entry */
 
@@ -444,9 +441,7 @@ DataStoreTLBMiss:
 
 	/* Honour kernel RO, User NA */
 	/* 0x200 == Extended encoding, bit 22 */
-	/* r11 =  (r10 & _PAGE_USER) >> 2 */
-	rlwinm	r11, r10, 32-2, 0x200
-	or	r10, r11, r10
+	rlwimi	r10, r10, 32-2, 0x200 /* Copy USER to bit 22, 0x200 */
 	/* r11 =  (r10 & _PAGE_RW) >> 1 */
 	rlwinm	r11, r10, 32-1, 0x200
 	or	r10, r11, r10
-- 
1.6.4.4

^ permalink raw reply related

* [PATCH 0/4] 8xx: Optimize TLB Miss code.
From: Joakim Tjernlund @ 2010-02-26  8:29 UTC (permalink / raw)
  To: linuxppc-dev

This set of tries to optimize the TLB code on 8xx even
more. If they work, it should be a noticable performance
boost.

I would be very happy if you could test them for me.

Joakim Tjernlund (4):
  8xx: Optimze TLB Miss handlers
  8xx: Avoid testing for kernel space in ITLB Miss.
  8xx: Don't touch ACCESSED when no SWAP.
  8xx: Use SPRG2 and DAR registers to stash r11 and cr.

 arch/powerpc/kernel/head_8xx.S |   70 +++++++++++++++++++++++++++-------------
 1 files changed, 47 insertions(+), 23 deletions(-)

^ 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