LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] eeh: Fixing a bug when pci structure is null
From: Mike Mason @ 2010-02-24 22:13 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, Linas Vepstas, Breno Leitao
In-Reply-To: <1266616485.23523.1026.camel@pasglop>

On 2/19/2010 1:54 PM, Benjamin Herrenschmidt wrote:
> On Fri, 2010-02-19 at 14:43 -0200, Breno Leitao wrote:
>> Hi Ben,
>>
>> I'd like to ask about this patch ? Should I re-submit ?
>>
>> Thanks,
>>
>> Breno Leitao wrote:
>>> During a EEH recover, the pci_dev structure can be null, mainly if an
>>> eeh event is detected during cpi config operation. In this case, the
>>> pci_dev will not be known (and will be null) the kernel will crash
>>> with the following message:
>
> It should be in -next, can you dbl check ?

I just confirmed the patch is in the -next tree.

Mike

>
> Cheers,
> Ben.
>
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev

^ permalink raw reply

* Re: PCI on 834x
From: Gary Thomas @ 2010-02-24 22:14 UTC (permalink / raw)
  To: avorontsov; +Cc: Scott Wood, linuxppc-dev
In-Reply-To: <20100224205159.GA6555@oksana.dev.rtsoft.ru>

On 02/24/2010 01:51 PM, Anton Vorontsov wrote:
> On Wed, Feb 24, 2010 at 02:26:20PM -0600, Scott Wood wrote:
>> Gary Thomas wrote:
>>> Yes, I'm using the exact same kernel with these two different PCI
>>> setups (done by the boot loader).
>>>
>>> Restricting the memory via mem=128M has no effect - the PCI layout
>>> is the same.
>>>
>>> I think the outbound window size is required because of how the Linux PCI
>>> remaps the space (note in my dumps that it put the MMIO of the
>>> boards starting
>>> at 0xD0000000 when the inbound window is 0x10000000)
>>
>> I see where the amount of RAM is mattering -- Linux is assigning
>> outbound I/O space to the PCI controller itself (device 00:00.0) and
>> the amount that it asks for seems to differ based on memory size.
>> Linux ought to skip that device when assigning resources.  Some
>> platforms do this (search for pci_exclude_device), but it seems to
>> be missing on 83xx.
>
> Actually, 83xx had these exclude_device hooks, but they were removed:
>
> commit d8f1324a5063c833862328ceafabc53ac3cc4f71
> Author: Kumar Gala<galak@kernel.crashing.org>
> Date:   Wed Sep 12 22:14:10 2007 -0500
>
>      [POWERPC] 83xx: Removed PCI exclude of PHB
>
>      Now that the generic code doesn't assign resources for Freescale
>      PHBs we dont have to explicitly exclude it.
>
>      Signed-off-by: Kumar Gala<galak@kernel.crashing.org>
>
>
> May be the generic code started to assign the resources again?
>

That cracked it; I re-enabled the exclusion of the bridge and now
it's all working fine.

Thanks for the help

Note: I'm working with a fairly old kernel, so these results would
have to be reworked against the latest.

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

^ permalink raw reply

* [PATCH v2] powerpc: Add hibernation support for FSL BookE processors
From: Anton Vorontsov @ 2010-02-24 21:38 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev

This is started as swsusp_32.S modifications, but the amount of #ifdefs
made the whole file horribly unreadable, so let's put the support into
its own separate file.

The code should be relatively easy to modify to support 44x BookEs as
well, but since I don't have any 44x to test, let's confine the code to
FSL BookE. (The only FSL-specific parts are 'flush_dcache_L1' and TLB
invalidation code).

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---

Sorry for the delayed response...

On Tue, Jan 12, 2010 at 01:34:08PM +1100, Benjamin Herrenschmidt wrote:
[...]
> Here's a quick review. Looks good but two things:
> 
>  - Please make it swsusp_booke.c, 44x support is trivial and I don't
> want to rename the file :-)

Done.

>  - Is there really an SDR1 register on FSL BookE ? It's supposed to be
> the pointer to the hash table on server ...

Thanks, fixed.

>  - You probably should save/restore the TCR and ack pending crap DEC or
> FIT interrupts in the TSR right before you kick the decrementer

Done.

>  - Nowadays, we still assume that the "loader" kernel is exactly the
> same as the "loaded" kernel on resume ?

I'm pretty sure today we do rely on this, yes. This is not some
generic code limitation though, it's just hard to test the case
when loader != loaded. In most cases it will work fine since the
loader kernel wouldn't differ a lot from the loaded kernel, so
it'll setup the low level stuff the same way.

We may try to link the loader kernel to a different address
(relocate it as in kdump case), and hope that it'll trigger
all sort of problems so that we could fix them.

Though, the better test case would be to resume the hibernated
kernel directly from the bootloader.

Thanks,

 arch/powerpc/kernel/Makefile       |    8 +-
 arch/powerpc/kernel/swsusp_booke.S |  200 ++++++++++++++++++++++++++++++++++++
 2 files changed, 206 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/kernel/swsusp_booke.S

diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index c002b04..33d9dda 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -57,8 +57,12 @@ obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
 obj-$(CONFIG_E500)		+= idle_e500.o
 obj-$(CONFIG_6xx)		+= idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o
 obj-$(CONFIG_TAU)		+= tau_6xx.o
-obj-$(CONFIG_HIBERNATION)	+= swsusp.o suspend.o \
-				   swsusp_$(CONFIG_WORD_SIZE).o
+obj-$(CONFIG_HIBERNATION)	+= swsusp.o suspend.o
+ifeq ($(CONFIG_FSL_BOOKE),y)
+obj-$(CONFIG_HIBERNATION)	+= swsusp_booke.o
+else
+obj-$(CONFIG_HIBERNATION)	+= swsusp_$(CONFIG_WORD_SIZE).o
+endif
 obj64-$(CONFIG_HIBERNATION)	+= swsusp_asm64.o
 obj-$(CONFIG_MODULES)		+= module.o module_$(CONFIG_WORD_SIZE).o
 obj-$(CONFIG_44x)		+= cpu_setup_44x.o
diff --git a/arch/powerpc/kernel/swsusp_booke.S b/arch/powerpc/kernel/swsusp_booke.S
new file mode 100644
index 0000000..dbffad2
--- /dev/null
+++ b/arch/powerpc/kernel/swsusp_booke.S
@@ -0,0 +1,200 @@
+/*
+ * Based on swsusp_32.S, modified for FSL BookE by
+ * Anton Vorontsov <avorontsov@ru.mvista.com>
+ * Copyright (c) 2009-2010 MontaVista Software, LLC.
+ */
+
+#include <linux/threads.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/cputable.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/mmu.h>
+
+/*
+ * Structure for storing CPU registers on the save area.
+ */
+#define SL_SP		0
+#define SL_PC		4
+#define SL_MSR		8
+#define SL_TCR		0xc
+#define SL_SPRG0	0x10
+#define SL_SPRG1	0x14
+#define SL_SPRG2	0x18
+#define SL_SPRG3	0x1c
+#define SL_SPRG4	0x20
+#define SL_SPRG5	0x24
+#define SL_SPRG6	0x28
+#define SL_SPRG7	0x2c
+#define SL_TBU		0x30
+#define SL_TBL		0x34
+#define SL_R2		0x38
+#define SL_CR		0x3c
+#define SL_LR		0x40
+#define SL_R12		0x44	/* r12 to r31 */
+#define SL_SIZE		(SL_R12 + 80)
+
+	.section .data
+	.align	5
+
+_GLOBAL(swsusp_save_area)
+	.space	SL_SIZE
+
+
+	.section .text
+	.align	5
+
+_GLOBAL(swsusp_arch_suspend)
+	lis	r11,swsusp_save_area@h
+	ori	r11,r11,swsusp_save_area@l
+
+	mflr	r0
+	stw	r0,SL_LR(r11)
+	mfcr	r0
+	stw	r0,SL_CR(r11)
+	stw	r1,SL_SP(r11)
+	stw	r2,SL_R2(r11)
+	stmw	r12,SL_R12(r11)
+
+	/* Save MSR & TCR */
+	mfmsr	r4
+	stw	r4,SL_MSR(r11)
+	mfspr	r4,SPRN_TCR
+	stw	r4,SL_TCR(r11)
+
+	/* Get a stable timebase and save it */
+1:	mftbu	r4
+	stw	r4,SL_TBU(r11)
+	mftb	r5
+	stw	r5,SL_TBL(r11)
+	mftbu	r3
+	cmpw	r3,r4
+	bne	1b
+
+	/* Save SPRGs */
+	mfsprg	r4,0
+	stw	r4,SL_SPRG0(r11)
+	mfsprg	r4,1
+	stw	r4,SL_SPRG1(r11)
+	mfsprg	r4,2
+	stw	r4,SL_SPRG2(r11)
+	mfsprg	r4,3
+	stw	r4,SL_SPRG3(r11)
+	mfsprg	r4,4
+	stw	r4,SL_SPRG4(r11)
+	mfsprg	r4,5
+	stw	r4,SL_SPRG5(r11)
+	mfsprg	r4,6
+	stw	r4,SL_SPRG6(r11)
+	mfsprg	r4,7
+	stw	r4,SL_SPRG7(r11)
+
+	/* Call the low level suspend stuff (we should probably have made
+	 * a stackframe...
+	 */
+	bl	swsusp_save
+
+	/* Restore LR from the save area */
+	lis	r11,swsusp_save_area@h
+	ori	r11,r11,swsusp_save_area@l
+	lwz	r0,SL_LR(r11)
+	mtlr	r0
+
+	blr
+
+_GLOBAL(swsusp_arch_resume)
+ 	sync
+
+	/* Load ptr the list of pages to copy in r3 */
+	lis	r11,(restore_pblist)@h
+	ori	r11,r11,restore_pblist@l
+	lwz	r3,0(r11)
+
+	/* Copy the pages. This is a very basic implementation, to
+	 * be replaced by something more cache efficient */
+1:
+	li	r0,256
+	mtctr	r0
+	lwz	r5,pbe_address(r3)	/* source */
+	lwz	r6,pbe_orig_address(r3)	/* destination */
+2:
+	lwz	r8,0(r5)
+	lwz	r9,4(r5)
+	lwz	r10,8(r5)
+	lwz	r11,12(r5)
+	addi	r5,r5,16
+	stw	r8,0(r6)
+	stw	r9,4(r6)
+	stw	r10,8(r6)
+	stw	r11,12(r6)
+	addi	r6,r6,16
+	bdnz	2b
+	lwz	r3,pbe_next(r3)
+	cmpwi	0,r3,0
+	bne	1b
+
+	bl flush_dcache_L1
+	bl flush_instruction_cache
+
+	lis	r11,swsusp_save_area@h
+	ori	r11,r11,swsusp_save_area@l
+
+	lwz	r4,SL_SPRG0(r11)
+	mtsprg	0,r4
+	lwz	r4,SL_SPRG1(r11)
+	mtsprg	1,r4
+	lwz	r4,SL_SPRG2(r11)
+	mtsprg	2,r4
+	lwz	r4,SL_SPRG3(r11)
+	mtsprg	3,r4
+	lwz	r4,SL_SPRG4(r11)
+	mtsprg	4,r4
+	lwz	r4,SL_SPRG5(r11)
+	mtsprg	5,r4
+	lwz	r4,SL_SPRG6(r11)
+	mtsprg	6,r4
+	lwz	r4,SL_SPRG7(r11)
+	mtsprg	7,r4
+
+	/* Invalidate TLB0 & TLB1 */
+	li	r6,0x04
+	tlbivax 0,r6
+	TLBSYNC
+	li	r6,0x0c
+	tlbivax 0,r6
+	TLBSYNC
+
+	/* restore the MSR */
+	lwz	r3,SL_MSR(r11)
+
+	/* Restore TB */
+	li	r3,0
+	mttbl	r3
+	lwz	r3,SL_TBU(r11)
+	lwz	r4,SL_TBL(r11)
+	mttbu	r3
+	mttbl	r4
+
+	/* Restore TCR and clear any pending bits in TSR. */
+	lwz	r4,SL_TCR(r11)
+	mtspr	SPRN_TCR,r4
+	lis	r4, (TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS)@h
+	mtspr	SPRN_TSR,r4
+
+	/* Kick decrementer */
+	li	r0,1
+	mtdec	r0
+
+	/* Restore the callee-saved registers and return */
+	lwz	r0,SL_CR(r11)
+	mtcr	r0
+	lwz	r2,SL_R2(r11)
+	lmw	r12,SL_R12(r11)
+	lwz	r1,SL_SP(r11)
+	lwz	r0,SL_LR(r11)
+	mtlr	r0
+
+	li	r3,0
+	blr
-- 
1.7.0

^ permalink raw reply related

* Re: PCI on 834x
From: Anton Vorontsov @ 2010-02-24 20:51 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev, Gary Thomas
In-Reply-To: <4B858B6C.4020809@freescale.com>

On Wed, Feb 24, 2010 at 02:26:20PM -0600, Scott Wood wrote:
> Gary Thomas wrote:
> >Yes, I'm using the exact same kernel with these two different PCI
> >setups (done by the boot loader).
> >
> >Restricting the memory via mem=128M has no effect - the PCI layout
> >is the same.
> >
> >I think the outbound window size is required because of how the Linux PCI
> >remaps the space (note in my dumps that it put the MMIO of the
> >boards starting
> >at 0xD0000000 when the inbound window is 0x10000000)
> 
> I see where the amount of RAM is mattering -- Linux is assigning
> outbound I/O space to the PCI controller itself (device 00:00.0) and
> the amount that it asks for seems to differ based on memory size.
> Linux ought to skip that device when assigning resources.  Some
> platforms do this (search for pci_exclude_device), but it seems to
> be missing on 83xx.

Actually, 83xx had these exclude_device hooks, but they were removed:

commit d8f1324a5063c833862328ceafabc53ac3cc4f71
Author: Kumar Gala <galak@kernel.crashing.org>
Date:   Wed Sep 12 22:14:10 2007 -0500

    [POWERPC] 83xx: Removed PCI exclude of PHB

    Now that the generic code doesn't assign resources for Freescale
    PHBs we dont have to explicitly exclude it.

    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>


May be the generic code started to assign the resources again?

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

^ permalink raw reply

* Re: PCI on 834x
From: Scott Wood @ 2010-02-24 20:26 UTC (permalink / raw)
  To: Gary Thomas; +Cc: linuxppc-dev
In-Reply-To: <4B858243.8010908@mlbassoc.com>

Gary Thomas wrote:
> Yes, I'm using the exact same kernel with these two different PCI
> setups (done by the boot loader).
> 
> Restricting the memory via mem=128M has no effect - the PCI layout is 
> the same.
> 
> I think the outbound window size is required because of how the Linux PCI
> remaps the space (note in my dumps that it put the MMIO of the boards 
> starting
> at 0xD0000000 when the inbound window is 0x10000000)

I see where the amount of RAM is mattering -- Linux is assigning 
outbound I/O space to the PCI controller itself (device 00:00.0) and the 
amount that it asks for seems to differ based on memory size.  Linux 
ought to skip that device when assigning resources.  Some platforms do 
this (search for pci_exclude_device), but it seems to be missing on 83xx.

>> Are there any errors indicated in the device, the PCI controller, the 
>> arbiter, etc?
> 
> None that are obvious to me.
> 
> To be clear, here are my observations:
> 
> * total memory 128MB (or less), inbound window 128MB, outbound window 128MB
>   ==> device is happy
> * total memory 256MB, inbound window 128MB, outbound window 128MB
>   ==> device hangs, unable to access RAM (Linux handed it something 
> higher than 128MB)

Linux gets its idea of how much space there is to allocate from the 
ranges property of the pci node in the device tree -- this should be 
made to match what u-boot configures in PIWARn.

> * total memory 256MB, inbound window 256MB, outbound window 128MB
>   ==> segmentation violation when accessing device MMIO space
> * total memory 256MB, inbound window 256MB, outbound window 256MB
>   ==> access to MMIO space fails (Linux can't find device).  In this 
> case, the SATA_SIL reports
>          ata1: SATA link down (SStatus FFFFFFFF SControl FFFFFFFF)
>          ata2: SATA link down (SStatus FFFFFFFF SControl FFFFFFFF)
>       which implies that the driver get's junk when accessing the device 
> MMIO space

Are there any other relevant messages earlier in boot, perhaps from the 
PCI code failing to assign a resource?

-Scott

^ permalink raw reply

* Re: [PATCH 3/7] RapidIO: Add Port-Write handling for EM
From: Micha Nelissen @ 2010-02-24 20:17 UTC (permalink / raw)
  To: Alexandre Bounine
  Cc: linuxppc-dev, linux-kernel, thomas.moll.ext, thomas.moll
In-Reply-To: <20100224152401.GC13661@kaneng01.tundra.com>

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?

> +/**
> + * rio_pw_enable - Enables/disables port-write handling by a master port
> + * @port: Master port associated with port-write handling
> + * @enable:  1=enable,  0=disable
> + */
> +static void rio_pw_enable(struct rio_mport *port, int enable)
> +{
> +	if (port->ops->pwenable)
> +		port->ops->pwenable(port, enable);
> +}
> +

Maybe this can be done by switch->init function?

> +/**
> + * 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)
> +{

Perhaps map this pw_msg to a struct? Or read it into named variables?

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

Hardcoded value!

> +
> +	if (rdev->rswitch->port_ok & (1 << portnum)) {
> +		if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) {
> +			rdev->rswitch->port_ok &= ~(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);

You have a function for this?

> +			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?

> +	/* 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);

Why not declare these along with the other ops?

Micha

^ permalink raw reply

* Re: [PATCH 1/7] RapidIO: Add IDT CPS/TSI switches
From: Micha Nelissen @ 2010-02-24 20:02 UTC (permalink / raw)
  To: Alexandre Bounine
  Cc: linux-kernel, thomas.moll, linuxppc-dev, alexandreb,
	thomas.moll.ext
In-Reply-To: <20100224151447.GA13661@kaneng01.tundra.com>

Alexandre Bounine wrote:
> @@ -369,6 +380,10 @@ static struct rio_dev __devinit *rio_set
>  			     rdev->rswitch->switchid);
>  		rio_route_set_ops(rdev);
>  
> +		if (do_enum && rdev->rswitch->clr_table)
> +			rdev->rswitch->clr_table(port, destid, hopcount,
> +						 RIO_GLOBAL_TABLE);
> +
>  		list_add_tail(&rswitch->node, &rio_switches);
>  
>  	} else

Why clear the tables here, why not in rio_enum_peer?

> +DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI572, tsi57x_route_add_entry, tsi57x_route_get_entry, tsi57x_route_clr_table);
> +DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI574, tsi57x_route_add_entry, tsi57x_route_get_entry, tsi57x_route_clr_table);
> +DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI577, tsi57x_route_add_entry, tsi57x_route_get_entry, tsi57x_route_clr_table);
> +DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI578, tsi57x_route_add_entry, tsi57x_route_get_entry, tsi57x_route_clr_table);

Can the 568 and 578 driver be shared? Have a 5xx driver?

Micha

^ permalink raw reply

* Re: PCI on 834x
From: Gary Thomas @ 2010-02-24 19:47 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev
In-Reply-To: <4B857EA1.6030605@freescale.com>

On 02/24/2010 12:31 PM, Scott Wood wrote:
> Gary Thomas wrote:
>> On 02/24/2010 11:48 AM, Scott Wood wrote:
>>> Gary Thomas wrote:
>>>> Does anyone have experience setting up the PCI controller on
>>>> the MPC8349? I have it running fine when my system has 128MB
>>>> or less of main memory, but when I have 256MB or more, it all
>>>> falls apart :-(
>>>>
>>>> Any indication of the pertinent settings would be appreciated.
>>>
>>> Check the inbound PCI translation registers, especially PIWARn.
>>
>> Yes, I set it to 256MB (the size of RAM).
>> I also set PCI_AR0 to a 512MB window (when it's set to 256, I
>> get address [segmentation violation] errors when accessing my
>> devices that end up at the high end of the logical address space)
>> Finally, I set POCMR0 to a 512MB window (corresponding to PCI_AR0)
>
> I don't see what the outbound window size has to do with RAM size... are there any other differences between the 128MiB and 256MiB setups? Same exact software? What happens if you
> take the 256MiB setup and restrict the kernel to using the lower 128MiB ("mem=128M" on the kernel bootargs), with no other changes? What happens if you use a 512MiB outbound window
> on the 128MiB setup?

Yes, I'm using the exact same kernel with these two different PCI
setups (done by the boot loader).

Restricting the memory via mem=128M has no effect - the PCI layout is the same.

I think the outbound window size is required because of how the Linux PCI
remaps the space (note in my dumps that it put the MMIO of the boards starting
at 0xD0000000 when the inbound window is 0x10000000)

> Is this behavior consistent across multiple boards (i.e. could there be a hardware problem)?

I've had this same problem on many platforms before (834x and 8248 as well).  In the
past, I didn't have the time to spend fixing it, so I just worked around it by limiting
the system to 128MB  in the boot loader + PCI setup)

> Are there any errors indicated in the device, the PCI controller, the arbiter, etc?

None that are obvious to me.

To be clear, here are my observations:

* total memory 128MB (or less), inbound window 128MB, outbound window 128MB
   ==> device is happy
* total memory 256MB, inbound window 128MB, outbound window 128MB
   ==> device hangs, unable to access RAM (Linux handed it something higher than 128MB)
* total memory 256MB, inbound window 256MB, outbound window 128MB
   ==> segmentation violation when accessing device MMIO space
* total memory 256MB, inbound window 256MB, outbound window 256MB
   ==> access to MMIO space fails (Linux can't find device).  In this case, the SATA_SIL reports
          ata1: SATA link down (SStatus FFFFFFFF SControl FFFFFFFF)
          ata2: SATA link down (SStatus FFFFFFFF SControl FFFFFFFF)
       which implies that the driver get's junk when accessing the device MMIO space

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

^ permalink raw reply

* Re: [PATCH 2/7] RapidIO: Add switch locking during discovery
From: Micha Nelissen @ 2010-02-24 19:15 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <20100224152050.GB13661@kaneng01.tundra.com>

Alexandre Bounine wrote:
> +				/* Attempt to acquire device lock */
> +				rio_mport_write_config_32(port, destid,
> +							  hopcount,
> +							  RIO_HOST_DID_LOCK_CSR,
> +							  port->host_deviceid);
> +				rio_mport_read_config_32(port, destid, hopcount,
> +					RIO_HOST_DID_LOCK_CSR, &result);
> +				while (result != port->host_deviceid) {

It's better to abstract the locking of a device into a new function,
rio_lock_device / rio_unlock_device.

Then you can use those in rio_get_route_entry and rio_add_route_entry.

> @@ -1027,6 +1090,13 @@ int __devinit rio_disc_mport(struct rio_
> +
> +		/* Read DestID assigned by enumerator */
> +		rio_local_read_config_32(mport, RIO_DID_CSR,
> +					 &mport->host_deviceid);
> +		mport->host_deviceid = RIO_GET_DID(mport->sys_size,
> +						   mport->host_deviceid);
> +

This fixes something else, should be a separate patch.

Regards, Micha

^ permalink raw reply

* Re: PCI on 834x
From: Scott Wood @ 2010-02-24 19:31 UTC (permalink / raw)
  To: Gary Thomas; +Cc: linuxppc-dev
In-Reply-To: <4B857AA8.9000208@mlbassoc.com>

Gary Thomas wrote:
> On 02/24/2010 11:48 AM, Scott Wood wrote:
>> Gary Thomas wrote:
>>> Does anyone have experience setting up the PCI controller on
>>> the MPC8349? I have it running fine when my system has 128MB
>>> or less of main memory, but when I have 256MB or more, it all
>>> falls apart :-(
>>>
>>> Any indication of the pertinent settings would be appreciated.
>>
>> Check the inbound PCI translation registers, especially PIWARn.
> 
> Yes, I set it to 256MB (the size of RAM).
> I also set PCI_AR0 to a 512MB window (when it's set to 256, I
> get address [segmentation violation] errors when accessing my
> devices that end up at the high end of the logical address space)
> Finally, I set POCMR0 to a 512MB window (corresponding to PCI_AR0)

I don't see what the outbound window size has to do with RAM size... are 
there any other differences between the 128MiB and 256MiB setups?  Same 
exact software?  What happens if you take the 256MiB setup and restrict 
the kernel to using the lower 128MiB ("mem=128M" on the kernel 
bootargs), with no other changes?  What happens if you use a 512MiB 
outbound window on the 128MiB setup?

Is this behavior consistent across multiple boards (i.e. could there be 
a hardware problem)?

Are there any errors indicated in the device, the PCI controller, the 
arbiter, etc?

-Scott

^ permalink raw reply

* Re: PCI on 834x
From: Gary Thomas @ 2010-02-24 19:14 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev
In-Reply-To: <4B85746F.3020200@freescale.com>

On 02/24/2010 11:48 AM, Scott Wood wrote:
> Gary Thomas wrote:
>> Does anyone have experience setting up the PCI controller on
>> the MPC8349? I have it running fine when my system has 128MB
>> or less of main memory, but when I have 256MB or more, it all
>> falls apart :-(
>>
>> Any indication of the pertinent settings would be appreciated.
>
> Check the inbound PCI translation registers, especially PIWARn.

Yes, I set it to 256MB (the size of RAM).
I also set PCI_AR0 to a 512MB window (when it's set to 256, I
get address [segmentation violation] errors when accessing my
devices that end up at the high end of the logical address space)
Finally, I set POCMR0 to a 512MB window (corresponding to PCI_AR0)

In this configuration, my device doesn't seem to be able to
access RAM.  If PIWAR1 is too small, the device just hangs.

=============================== 128MB setup =========================
PIWAR1 = 0xA0055000 | (27-1)
POCMR0 = 0x800F0000
PCIAR0 = 0x80000000 | (28-1)
00:00.0 Power PC: Unknown device 1957:0082 (rev 30)
         Flags: bus master, 66MHz, fast devsel, latency 0
         Memory at cc000000 (32-bit, non-prefetchable) [size=1M]
         Memory at c0000000 (64-bit, prefetchable) [size=128M]
         Memory at <unassigned> (64-bit, non-prefetchable)
         Capabilities: [48] #06 [0000]

00:0b.0 Mass storage controller: Silicon Image, Inc. SiI 3512 [SATALink/SATARaid] Serial ATA Controller (rev 01)
         Subsystem: Silicon Image, Inc. SiI 3512 SATALink Controller
         Flags: bus master, 66MHz, medium devsel, latency 0, IRQ 22
         I/O ports at 1000 [size=8]
         I/O ports at 1008 [size=4]
         I/O ports at 1010 [size=8]
         I/O ports at 1018 [size=4]
         I/O ports at 1020 [size=16]
         Memory at cc180000 (32-bit, non-prefetchable) [size=512]
         [virtual] Expansion ROM at cc100000 [disabled] [size=512K]
         Capabilities: [60] Power Management version 2

00:0c.0 Display controller: Fujitsu Limited. Unknown device 2019 (rev 01)
         Flags: bus master, medium devsel, latency 0, IRQ 19
         Memory at c8000000 (32-bit, non-prefetchable) [size=64M]
=====================================================================

=============================== 256MB setup =========================
PIWAR1 = 0xA0055000 | (28-1)
POCMR0 = 0x800E0000
PCIAR0 = 0x80000000 | (29-1)
00:00.0 Power PC: Unknown device 1957:0082 (rev 30)
         Flags: bus master, 66MHz, fast devsel, latency 0
         Memory at d4000000 (32-bit, non-prefetchable) [size=1M]
         Memory at c0000000 (64-bit, prefetchable) [size=256M]
         Memory at <unassigned> (64-bit, non-prefetchable)
         Capabilities: [48] #06 [0000]

00:0b.0 Mass storage controller: Silicon Image, Inc. SiI 3512 [SATALink/SATARaid] Serial ATA Controller (rev 01)
         Subsystem: Silicon Image, Inc. SiI 3512 SATALink Controller
         Flags: bus master, 66MHz, medium devsel, latency 0, IRQ 22
         I/O ports at 1000 [size=8]
         I/O ports at 1008 [size=4]
         I/O ports at 1010 [size=8]
         I/O ports at 1018 [size=4]
         I/O ports at 1020 [size=16]
         Memory at d4180000 (32-bit, non-prefetchable) [size=512]
         [virtual] Expansion ROM at d4100000 [disabled] [size=512K]
         Capabilities: [60] Power Management version 2

00:0c.0 Display controller: Fujitsu Limited. Unknown device 2019 (rev 01)
         Flags: bus master, medium devsel, latency 0, IRQ 19
         [virtual] Memory at d0000000 (32-bit, non-prefetchable) [size=64M]
=====================================================================

Any ideas what I might be missing?

Thanks

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

^ permalink raw reply

* MPC8313 and IO mapping a localbus space.
From: Mike Williamson @ 2010-02-24 19:12 UTC (permalink / raw)
  To: linuxppc-dev

Hi,

I'm working on implementing a linux 2.6.23 kernel for a machine based
on the MPC8313. It's
basically a clone of the Freescale ERDB dev kit module with the
addition of an FPGA on CS3 of the localbus.
(it also has NAND and a FLASH NOR part on the localbus as well).

All of the code is based off of the ltib BSP kit provided by
Freescale's 2008-12-22 release.

I am able to address the FPGA in u-boot using "md.w" as well as all
the other localbus devices.

However, when I load up linux, I can't seem to map in the FPGA and
read or write to it.  I don't bus error,
I just get zeros.

The driver code is pretty basic (below), and I've verified that the
LBLAWARx and LBLAWBARx registers
match what was set in u-boot.  I've also verified that the eLBC ORx
and BRx registers match.
The only thing that seems to be missing is that there aren't entries
in the BATs for anything
but the SDRAM.  This is a bit confusing because I seem to be able to
read from NAND and NOR
mtd devices without any issues.

Is there more that I need to do beyond an ioremap() to map in the address space?

Thanks.

-Mike


#define HW_FPGA 0xfa000000
#define HW_FPGA_SIZE 32768

static int __init mapfpga_load(void)
{
        u16 tmp;
        int res = 0;

        printk(KERN_ALERT "%s: loading\n", dev_name);
        mapfpga_dev.fpgaimg_res = request_mem_region(HW_FPGA,
HW_FPGA_SIZE, dev_name);
        if (mapfpga_dev.fpgaimg_res == NULL) {
                printk(KERN_ALERT "%s: could not request memory region"
                                " 0x%08x\n", dev_name, HW_FPGA);
                res = -EINVAL;
                goto out;
        }

        mapfpga_dev.fpgaimg = ioremap_nocache(HW_FPGA, HW_FPGA_SIZE);
        if (mapfpga_dev.fpgaimg == NULL) {
                printk(KERN_ALERT "%s: could not map i/o region"
                                " 0x%08x\n", dev_name, HW_FPGA);
                res = -EINVAL;
                goto out;
        }

        /* this should generate a non-zero number, it's a version register */
        tmp = ioread16(mapfpga_dev.fpgaimg); /* always zero... */
        ...
}



-- 
Michael Williamson
315-425-4045x230
www.criticallink.com

^ permalink raw reply

* Re: PCI on 834x
From: Scott Wood @ 2010-02-24 18:48 UTC (permalink / raw)
  To: Gary Thomas; +Cc: linuxppc-dev
In-Reply-To: <4B854A93.7030405@mlbassoc.com>

Gary Thomas wrote:
> Does anyone have experience setting up the PCI controller on
> the MPC8349?  I have it running fine when my system has 128MB
> or less of main memory, but when I have 256MB or more, it all
> falls apart :-(
> 
> Any indication of the pertinent settings would be appreciated.

Check the inbound PCI translation registers, especially PIWARn.

-Scott

^ permalink raw reply

* PCI on 834x
From: Gary Thomas @ 2010-02-24 15:49 UTC (permalink / raw)
  To: linuxppc-dev

Does anyone have experience setting up the PCI controller on
the MPC8349?  I have it running fine when my system has 128MB
or less of main memory, but when I have 256MB or more, it all
falls apart :-(

Any indication of the pertinent settings would be appreciated.

Thanks

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

^ permalink raw reply

* Re: [PATCH] powerpc: Set a smaller value for RECLAIM_DISTANCE to enable zone reclaim
From: Christoph Lameter @ 2010-02-24 15:43 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: Mel Gorman, linuxppc-dev
In-Reply-To: <20100223015551.GG31681@kryten>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1244 bytes --]

On Tue, 23 Feb 2010, Anton Blanchard wrote:

> zone_reclaim_mode.txt
> Now we set zone_reclaim_mode = 1. On each iteration we continue to improve,
> but even after 10 runs of stream we have > 10% remote node memory usage.

The intend of zone reclaim was never to allocate all memory from on node.
You should not expect all memory to come from the node even if zone
reclaim works.

> reclaim_4096_pages.txt
> Instead of reclaiming 32 pages at a time, we try for a much larger batch
> of 4096. The slope is much steeper but it still takes around 6 iterations
> to get almost all local node memory.

"almost all"? How much do you want?

> wait_on_busy_flag.txt
> Here we busy wait if the ZONE_RECLAIM_LOCKED flag is set. As you suggest
> we would need to check the GFP flags etc, but so far it looks the most
> promising. We only get a few percent of remote node memory on the first
> iteration and get all local node by the second.

This would significantly impact performance. Zone reclaim should reclaim
with minimal overhead. If zone reclaim is running on another processor
then the OS already takes measures against the shortage of node local
memory. The right thing to do is to take what is currently available which
may be off node memory.

[-- Attachment #2: Type: IMAGE/PNG, Size: 34767 bytes --]

[-- Attachment #3: Type: TEXT/X-DIFF, Size: 387 bytes --]

--- mm/vmscan.c~	2010-02-21 23:47:14.000000000 -0600

+++ mm/vmscan.c	2010-02-22 03:22:01.000000000 -0600

@@ -2534,7 +2534,7 @@

 		.may_unmap = !!(zone_reclaim_mode & RECLAIM_SWAP),

 		.may_swap = 1,

 		.nr_to_reclaim = max_t(unsigned long, nr_pages,

-				       SWAP_CLUSTER_MAX),

+				       4096),

 		.gfp_mask = gfp_mask,

 		.swappiness = vm_swappiness,

 		.order = order,


[-- Attachment #4: Type: TEXT/X-DIFF, Size: 495 bytes --]

--- mm/vmscan.c~	2010-02-21 23:47:14.000000000 -0600

+++ mm/vmscan.c	2010-02-21 23:47:31.000000000 -0600

@@ -2634,8 +2634,8 @@

 	if (node_state(node_id, N_CPU) && node_id != numa_node_id())

 		return ZONE_RECLAIM_NOSCAN;

 

-	if (zone_test_and_set_flag(zone, ZONE_RECLAIM_LOCKED))

-		return ZONE_RECLAIM_NOSCAN;

+	while (zone_test_and_set_flag(zone, ZONE_RECLAIM_LOCKED))

+		cpu_relax();

 

 	ret = __zone_reclaim(zone, gfp_mask, order);

 	zone_clear_flag(zone, ZONE_RECLAIM_LOCKED);


^ permalink raw reply

* [PATCH 7/7] powerpc/85xx: Fix the RapidIO maintenance access functions
From: Alexandre Bounine @ 2010-02-24 15:37 UTC (permalink / raw)
  To: mporter; +Cc: abounine, linuxppc-dev, linux-kernel, thomas.moll.ext,
	thomas.moll


From: Thomas Moll <thomas.moll@sysgo.com>

Fix the maintenance access functions to farend RapidIO devices.
1. Fixed shift of the given offset, to open the maintenance window
2. Mask offset to limit access to the opened maintenance window
3. Added extended destid part to rowtear register, required for 16bit mode

For easier handling of the access routines, the access was limited to aligned
memory regions. This should be no problem because all registers are 32bit
wide.

Signed-off-by: Thomas Moll <thomas.moll@sysgo.com>
---

 fsl_rio.c |   34 ++++++++++++++++++++++++++++------
 1 file changed, 28 insertions(+), 6 deletions(-)

diff -purN linux-base/arch/powerpc/sysdev/fsl_rio.c linux-new/arch/powerpc/sysdev/fsl_rio.c
--- linux-base/arch/powerpc/sysdev/fsl_rio.c	2010-02-24 08:37:05.000000000 +0100
+++ linux-new/arch/powerpc/sysdev/fsl_rio.c	2010-02-24 08:45:27.000000000 +0100
@@ -1,6 +1,10 @@
 /*
  * Freescale MPC85xx/MPC86xx RapidIO support
  *
+ * Copyright 2009 Sysgo AG
+ * Thomas Moll <thomas.moll@sysgo.com>
+ * - fixed maintenance access routines, check for aligned access
+ *
  * Copyright 2009 Integrated Device Technology, Inc.
  * Alex Bounine <alexandre.bounine@idt.com>
  * - Added Port-Write message handling
@@ -370,10 +374,17 @@ fsl_rio_config_read(struct rio_mport *mp
 	pr_debug
 	    ("fsl_rio_config_read: index %d destid %d hopcount %d offset %8.8x len %d\n",
 	     index, destid, hopcount, offset, len);
+
+	/* 16MB maintenance window possible */
+	/* allow only aligned access to maintenance registers */
+	if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len))
+		return -EINVAL;
+
 	out_be32(&priv->maint_atmu_regs->rowtar,
-		 (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9));
+		 (destid << 22) | (hopcount << 12) | (offset >> 12));
+	out_be32(&priv->maint_atmu_regs->rowtear,  (destid >> 10));
 
-	data = (u8 *) priv->maint_win + offset;
+	data = (u8 *) priv->maint_win + (offset & 0x3FFFFF);
 	switch (len) {
 	case 1:
 		__fsl_read_rio_config(rval, data, err, "lbz");
@@ -381,9 +392,11 @@ fsl_rio_config_read(struct rio_mport *mp
 	case 2:
 		__fsl_read_rio_config(rval, data, err, "lhz");
 		break;
-	default:
+	case 4:
 		__fsl_read_rio_config(rval, data, err, "lwz");
 		break;
+	default:
+		return -EINVAL;
 	}
 
 	if (err) {
@@ -418,10 +431,17 @@ fsl_rio_config_write(struct rio_mport *m
 	pr_debug
 	    ("fsl_rio_config_write: index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n",
 	     index, destid, hopcount, offset, len, val);
+
+	/* 16MB maintenance windows possible */
+	/* allow only aligned access to maintenance registers */
+	if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len))
+		return -EINVAL;
+
 	out_be32(&priv->maint_atmu_regs->rowtar,
-		 (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9));
+		 (destid << 22) | (hopcount << 12) | (offset >> 12));
+	out_be32(&priv->maint_atmu_regs->rowtear,  (destid >> 10));
 
-	data = (u8 *) priv->maint_win + offset;
+	data = (u8 *) priv->maint_win + (offset & 0x3FFFFF);
 	switch (len) {
 	case 1:
 		out_8((u8 *) data, val);
@@ -429,9 +449,11 @@ fsl_rio_config_write(struct rio_mport *m
 	case 2:
 		out_be16((u16 *) data, val);
 		break;
-	default:
+	case 4:
 		out_be32((u32 *) data, val);
 		break;
+	default:
+		return -EINVAL;
 	}
 
 	return 0;

---

Important Notice: This message is intended for the use of the individual to whom it is addressed and may contain information which is privileged, confidential and/or exempt from disclosure under applicable law. If the reader of this message is not the intended recipient, or is not the employee or agent responsible for delivering the message to the intended recipient, you are hereby notified that any dissemination, distribution, or copying of this communication is strictly prohibited. If you have received this communication in error, please notify the sender immediately by telephone or return e-mail and delete the original message from your systems. Thank you. 

^ permalink raw reply

* [PATCH 1/7] RapidIO: Add IDT CPS/TSI switches
From: Alexandre Bounine @ 2010-02-24 15:14 UTC (permalink / raw)
  To: mporter
  Cc: alexandreb, linuxppc-dev, linux-kernel, thomas.moll.ext,
	thomas.moll


From: Alexandre Bounine <alexandre.bounine@idt.com>

Extentions to RapidIO switch support:
1. modify switch route operation declarations to allow using single
   switch-specific file for family of switches that share the same route
   table operations.
2. add standard route table operations for switches that that support
   route table manipulation registers as defined in the Rev.1.3 of RapidIO
   specification.
3. add clear-route-table operation for switches
4. add CPSxx and TSIxxx families of RapidIO switches 

Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com>
Tested-by: Thomas Moll <thomas.moll@sysgo.com>
---

 drivers/rapidio/rio-scan.c        |   17 +++++-
 drivers/rapidio/rio.c             |  104 +++++++++++++++++++++++++++++++++++++
 drivers/rapidio/rio.h             |   20 +++++--
 drivers/rapidio/switches/Makefile |    2 
 drivers/rapidio/switches/idtcps.c |   84 ++++++++++++++++++++++++++++++
 drivers/rapidio/switches/tsi500.c |    2 
 drivers/rapidio/switches/tsi568.c |  106 ++++++++++++++++++++++++++++++++++++++
 drivers/rapidio/switches/tsi57x.c |  106 ++++++++++++++++++++++++++++++++++++++
 include/linux/rio.h               |    6 ++
 include/linux/rio_ids.h           |   14 +++++
 include/linux/rio_regs.h          |   14 ++++-
 11 files changed, 464 insertions(+), 11 deletions(-)

diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7c/drivers/rapidio/rio-scan.c w33r7d/drivers/rapidio/rio-scan.c
--- w33r7c/drivers/rapidio/rio-scan.c	2010-02-06 17:17:12.000000000 -0500
+++ w33r7d/drivers/rapidio/rio-scan.c	2010-02-22 11:06:23.913470000 -0500
@@ -55,6 +55,7 @@ static int rio_mport_phys_table[] = {
 static int rio_sport_phys_table[] = {
 	RIO_EFB_PAR_EP_FREE_ID,
 	RIO_EFB_SER_EP_FREE_ID,
+	RIO_EFB_SER_EP_FREC_ID,
 	-1,
 };
 
@@ -246,10 +247,20 @@ static void rio_route_set_ops(struct rio
 			pr_debug("RIO: adding routing ops for %s\n", rio_name(rdev));
 			rdev->rswitch->add_entry = cur->add_hook;
 			rdev->rswitch->get_entry = cur->get_hook;
+			rdev->rswitch->clr_table = cur->clr_hook;
+			break;
 		}
 		cur++;
 	}
 
+	if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) {
+		pr_debug("RIO: adding STD routing ops for %s\n",
+			rio_name(rdev));
+		rdev->rswitch->add_entry = rio_std_route_add_entry;
+		rdev->rswitch->get_entry = rio_std_route_get_entry;
+		rdev->rswitch->clr_table = rio_std_route_clr_table;
+	}
+
 	if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry)
 		printk(KERN_ERR "RIO: missing routing ops for %s\n",
 		       rio_name(rdev));
@@ -349,7 +360,7 @@ static struct rio_dev __devinit *rio_set
 	if (rio_is_switch(rdev)) {
 		rio_mport_read_config_32(port, destid, hopcount,
 					 RIO_SWP_INFO_CAR, &rdev->swpinfo);
-		rswitch = kmalloc(sizeof(struct rio_switch), GFP_KERNEL);
+		rswitch = kzalloc(sizeof(struct rio_switch), GFP_KERNEL);
 		if (!rswitch)
 			goto cleanup;
 		rswitch->switchid = next_switchid;
@@ -369,6 +380,10 @@ static struct rio_dev __devinit *rio_set
 			     rdev->rswitch->switchid);
 		rio_route_set_ops(rdev);
 
+		if (do_enum && rdev->rswitch->clr_table)
+			rdev->rswitch->clr_table(port, destid, hopcount,
+						 RIO_GLOBAL_TABLE);
+
 		list_add_tail(&rswitch->node, &rio_switches);
 
 	} else
diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7c/drivers/rapidio/rio.c w33r7d/drivers/rapidio/rio.c
--- w33r7c/drivers/rapidio/rio.c	2010-02-06 17:17:12.000000000 -0500
+++ w33r7d/drivers/rapidio/rio.c	2010-02-22 11:06:23.937564000 -0500
@@ -451,6 +451,110 @@ struct rio_dev *rio_get_device(u16 vid, 
 	return rio_get_asm(vid, did, RIO_ANY_ID, RIO_ANY_ID, from);
 }
 
+/**
+ * rio_std_route_add_entry - Add switch route table entry using standard
+ *   registers defined in RIO specification rev.1.3
+ * @mport: Master port to issue transaction
+ * @destid: Destination ID of the device
+ * @hopcount: Number of switch hops to the device
+ * @table: routing table ID (global or port-specific)
+ * @route_destid: destID entry in the RT
+ * @route_port: destination port for specified destID
+ */
+int rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+		       u16 table, u16 route_destid, u8 route_port)
+{
+	if (table == RIO_GLOBAL_TABLE) {
+		rio_mport_write_config_32(mport, destid, hopcount,
+				RIO_STD_RTE_CONF_DESTID_SEL_CSR,
+				(u32)route_destid);
+		rio_mport_write_config_32(mport, destid, hopcount,
+				RIO_STD_RTE_CONF_PORT_SEL_CSR,
+				(u32)route_port);
+	}
+	udelay(10);
+	return 0;
+}
+
+/**
+ * rio_std_route_get_entry - Read switch route table entry (port number)
+ *   assosiated with specified destID using standard registers defined in RIO
+ *   specification rev.1.3
+ * @mport: Master port to issue transaction
+ * @destid: Destination ID of the device
+ * @hopcount: Number of switch hops to the device
+ * @table: routing table ID (global or port-specific)
+ * @route_destid: destID entry in the RT
+ * @route_port: returned destination port for specified destID
+ */
+int rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+		       u16 table, u16 route_destid, u8 *route_port)
+{
+	u32 result;
+
+	if (table == RIO_GLOBAL_TABLE) {
+		rio_mport_write_config_32(mport, destid, hopcount,
+				RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid);
+		rio_mport_read_config_32(mport, destid, hopcount,
+				RIO_STD_RTE_CONF_PORT_SEL_CSR, &result);
+
+		*route_port = (u8)result;
+	}
+
+	return 0;
+}
+
+/**
+ * rio_std_route_clr_table - Clear swotch route table using standard registers
+ *   defined in RIO specification rev.1.3.
+ * @mport: Master port to issue transaction
+ * @local: Indicate a local master port or remote device access
+ * @destid: Destination ID of the device
+ * @hopcount: Number of switch hops to the device
+ * @table: routing table ID (global or port-specific)
+ */
+int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
+		       u16 table)
+{
+	u32 max_destid = 0xff;
+	u32 i, pef, id_inc = 1, ext_cfg = 0;
+	u32 port_sel = RIO_INVALID_ROUTE;
+
+	if (table == RIO_GLOBAL_TABLE) {
+		rio_mport_read_config_32(mport, destid, hopcount,
+					 RIO_PEF_CAR, &pef);
+
+		if (mport->sys_size) {
+			rio_mport_read_config_32(mport, destid, hopcount,
+						 RIO_SWITCH_RT_LIMIT,
+						 &max_destid);
+			max_destid &= RIO_RT_MAX_DESTID;
+		}
+
+		if (pef & RIO_PEF_EXT_RT) {
+			ext_cfg = 0x80000000;
+			id_inc = 4;
+			port_sel = (RIO_INVALID_ROUTE << 24) |
+				   (RIO_INVALID_ROUTE << 16) |
+				   (RIO_INVALID_ROUTE << 8) |
+				   RIO_INVALID_ROUTE;
+		}
+
+		for (i = 0; i <= max_destid;) {
+			rio_mport_write_config_32(mport, destid, hopcount,
+					RIO_STD_RTE_CONF_DESTID_SEL_CSR,
+					ext_cfg | i);
+			rio_mport_write_config_32(mport, destid, hopcount,
+					RIO_STD_RTE_CONF_PORT_SEL_CSR,
+					port_sel);
+			i += id_inc;
+		}
+	}
+
+	udelay(10);
+	return 0;
+}
+
 static void rio_fixup_device(struct rio_dev *dev)
 {
 }
diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7c/drivers/rapidio/rio.h w33r7d/drivers/rapidio/rio.h
--- w33r7c/drivers/rapidio/rio.h	2010-02-06 17:17:12.000000000 -0500
+++ w33r7d/drivers/rapidio/rio.h	2010-02-22 11:06:24.035348000 -0500
@@ -21,6 +21,14 @@ extern u32 rio_mport_get_feature(struct 
 extern int rio_create_sysfs_dev_files(struct rio_dev *rdev);
 extern int rio_enum_mport(struct rio_mport *mport);
 extern int rio_disc_mport(struct rio_mport *mport);
+extern int rio_std_route_add_entry(struct rio_mport *mport, u16 destid,
+				   u8 hopcount, u16 table, u16 route_destid,
+				   u8 route_port);
+extern int rio_std_route_get_entry(struct rio_mport *mport, u16 destid,
+				   u8 hopcount, u16 table, u16 route_destid,
+				   u8 *route_port);
+extern int rio_std_route_clr_table(struct rio_mport *mport, u16 destid,
+				   u8 hopcount, u16 table);
 
 /* Structures internal to the RIO core code */
 extern struct device_attribute rio_dev_attrs[];
@@ -30,9 +38,9 @@ extern struct rio_route_ops __start_rio_
 extern struct rio_route_ops __end_rio_route_ops[];
 
 /* Helpers internal to the RIO core code */
-#define DECLARE_RIO_ROUTE_SECTION(section, vid, did, add_hook, get_hook)  \
-	static struct rio_route_ops __rio_route_ops __used   \
-	__section(section)= { vid, did, add_hook, get_hook };
+#define DECLARE_RIO_ROUTE_SECTION(section, name, vid, did, add_hook, get_hook, clr_hook) \
+	static const struct rio_route_ops __rio_route_##name __used \
+	__section(section) = { vid, did, add_hook, get_hook, clr_hook };
 
 /**
  * DECLARE_RIO_ROUTE_OPS - Registers switch routing operations
@@ -47,9 +55,9 @@ extern struct rio_route_ops __end_rio_ro
  * rio_route_ops is initialized with the ops and placed into a
  * RIO-specific kernel section.
  */
-#define DECLARE_RIO_ROUTE_OPS(vid, did, add_hook, get_hook)		\
-	DECLARE_RIO_ROUTE_SECTION(.rio_route_ops,			\
-			vid, did, add_hook, get_hook)
+#define DECLARE_RIO_ROUTE_OPS(vid, did, add_hook, get_hook, clr_hook)	\
+	DECLARE_RIO_ROUTE_SECTION(.rio_route_ops, vid##did,		\
+			vid, did, add_hook, get_hook, clr_hook)
 
 #define RIO_GET_DID(size, x)	(size ? (x & 0xffff) : ((x & 0x00ff0000) >> 16))
 #define RIO_SET_DID(size, x)	(size ? (x & 0xffff) : ((x & 0x000000ff) << 16))
diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7c/drivers/rapidio/switches/Makefile w33r7d/drivers/rapidio/switches/Makefile
--- w33r7c/drivers/rapidio/switches/Makefile	2010-02-06 17:17:12.000000000 -0500
+++ w33r7d/drivers/rapidio/switches/Makefile	2010-02-22 11:06:24.065326000 -0500
@@ -2,4 +2,4 @@
 # Makefile for RIO switches
 #
 
-obj-$(CONFIG_RAPIDIO)	+= tsi500.o
+obj-$(CONFIG_RAPIDIO)	+= tsi500.o tsi568.o tsi57x.o idtcps.o
diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7c/drivers/rapidio/switches/idtcps.c w33r7d/drivers/rapidio/switches/idtcps.c
--- w33r7c/drivers/rapidio/switches/idtcps.c	1969-12-31 19:00:00.000000000 -0500
+++ w33r7d/drivers/rapidio/switches/idtcps.c	2010-02-22 11:06:24.069310000 -0500
@@ -0,0 +1,84 @@
+/*
+ * IDT CPS RapidIO switches support
+ *
+ * Copyright 2009 Integrated Device Technology, 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/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/rio_ids.h>
+#include "../rio.h"
+
+static int
+idtcps_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+		       u16 table, u16 route_destid, u8 route_port)
+{
+	u32 result;
+
+	if (table == RIO_GLOBAL_TABLE) {
+		rio_mport_write_config_32(mport, destid, hopcount,
+				RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid);
+
+		rio_mport_read_config_32(mport, destid, hopcount,
+				RIO_STD_RTE_CONF_PORT_SEL_CSR, &result);
+
+		result = (0xffffff00 & result) | (u32)route_port;
+		rio_mport_write_config_32(mport, destid, hopcount,
+				RIO_STD_RTE_CONF_PORT_SEL_CSR, result);
+	}
+
+	return 0;
+}
+
+static int
+idtcps_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+		       u16 table, u16 route_destid, u8 *route_port)
+{
+	u32 result;
+
+	if (table == RIO_GLOBAL_TABLE) {
+		rio_mport_write_config_32(mport, destid, hopcount,
+				RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid);
+
+		rio_mport_read_config_32(mport, destid, hopcount,
+				RIO_STD_RTE_CONF_PORT_SEL_CSR, &result);
+
+		*route_port = (u8)result;
+	}
+
+	return 0;
+}
+
+static int
+idtcps_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
+		       u16 table)
+{
+	u32 i;
+
+	if (table == RIO_GLOBAL_TABLE) {
+		for (i = 0x80000000; i <= 0x800000ff;) {
+			rio_mport_write_config_32(mport, destid, hopcount,
+				RIO_STD_RTE_CONF_DESTID_SEL_CSR, i);
+			rio_mport_write_config_32(mport, destid, hopcount,
+				RIO_STD_RTE_CONF_PORT_SEL_CSR,
+				(RIO_INVALID_ROUTE << 24) |
+				(RIO_INVALID_ROUTE << 16) |
+				(RIO_INVALID_ROUTE << 8) | RIO_INVALID_ROUTE);
+			i += 4;
+		}
+	}
+
+	return 0;
+}
+
+DECLARE_RIO_ROUTE_OPS(RIO_VID_IDT, RIO_DID_IDTCPS6Q, idtcps_route_add_entry, idtcps_route_get_entry, idtcps_route_clr_table);
+DECLARE_RIO_ROUTE_OPS(RIO_VID_IDT, RIO_DID_IDTCPS8, idtcps_route_add_entry, idtcps_route_get_entry, idtcps_route_clr_table);
+DECLARE_RIO_ROUTE_OPS(RIO_VID_IDT, RIO_DID_IDTCPS10Q, idtcps_route_add_entry, idtcps_route_get_entry, idtcps_route_clr_table);
+DECLARE_RIO_ROUTE_OPS(RIO_VID_IDT, RIO_DID_IDTCPS12, idtcps_route_add_entry, idtcps_route_get_entry, idtcps_route_clr_table);
+DECLARE_RIO_ROUTE_OPS(RIO_VID_IDT, RIO_DID_IDTCPS16, idtcps_route_add_entry, idtcps_route_get_entry, idtcps_route_clr_table);
+DECLARE_RIO_ROUTE_OPS(RIO_VID_IDT, RIO_DID_IDT70K200, idtcps_route_add_entry, idtcps_route_get_entry, idtcps_route_clr_table);
diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7c/drivers/rapidio/switches/tsi500.c w33r7d/drivers/rapidio/switches/tsi500.c
--- w33r7c/drivers/rapidio/switches/tsi500.c	2010-02-06 17:17:12.000000000 -0500
+++ w33r7d/drivers/rapidio/switches/tsi500.c	2010-02-22 11:06:24.070325000 -0500
@@ -57,4 +57,4 @@ tsi500_route_get_entry(struct rio_mport 
 	return ret;
 }
 
-DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI500, tsi500_route_add_entry, tsi500_route_get_entry);
+DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI500, tsi500_route_add_entry, tsi500_route_get_entry, NULL);
diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7c/drivers/rapidio/switches/tsi568.c w33r7d/drivers/rapidio/switches/tsi568.c
--- w33r7c/drivers/rapidio/switches/tsi568.c	1969-12-31 19:00:00.000000000 -0500
+++ w33r7d/drivers/rapidio/switches/tsi568.c	2010-02-22 11:06:24.072314000 -0500
@@ -0,0 +1,106 @@
+/*
+ * RapidIO Tsi568 switch support
+ *
+ * Copyright 2009-2010 Integrated Device Technology, Inc.
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/rio_ids.h>
+#include <linux/delay.h>
+#include "../rio.h"
+
+/* Global (broadcast) route registers */
+#define SPBC_ROUTE_CFG_DESTID	0x10070
+#define SPBC_ROUTE_CFG_PORT	0x10074
+
+/* Per port route registers */
+#define SPP_ROUTE_CFG_DESTID(n)	(0x11070 + 0x100*n)
+#define SPP_ROUTE_CFG_PORT(n)	(0x11074 + 0x100*n)
+
+static int
+tsi568_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+		       u16 table, u16 route_destid, u8 route_port)
+{
+	if (table == RIO_GLOBAL_TABLE) {
+		rio_mport_write_config_32(mport, destid, hopcount,
+					SPBC_ROUTE_CFG_DESTID, route_destid);
+		rio_mport_write_config_32(mport, destid, hopcount,
+					SPBC_ROUTE_CFG_PORT, route_port);
+	} else {
+		rio_mport_write_config_32(mport, destid, hopcount,
+					SPP_ROUTE_CFG_DESTID(table),
+					route_destid);
+		rio_mport_write_config_32(mport, destid, hopcount,
+					SPP_ROUTE_CFG_PORT(table), route_port);
+	}
+
+	udelay(10);
+
+	return 0;
+}
+
+static int
+tsi568_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+		       u16 table, u16 route_destid, u8 *route_port)
+{
+	int ret = 0;
+	u32 result;
+
+	if (table == RIO_GLOBAL_TABLE) {
+		rio_mport_write_config_32(mport, destid, hopcount,
+					SPBC_ROUTE_CFG_DESTID, route_destid);
+		rio_mport_read_config_32(mport, destid, hopcount,
+					SPBC_ROUTE_CFG_PORT, &result);
+	} else {
+		rio_mport_write_config_32(mport, destid, hopcount,
+					SPP_ROUTE_CFG_DESTID(table),
+					route_destid);
+		rio_mport_read_config_32(mport, destid, hopcount,
+					SPP_ROUTE_CFG_PORT(table), &result);
+	}
+
+	*route_port = result;
+	if (*route_port > 15)
+		ret = -1;
+
+	return ret;
+}
+
+static int
+tsi568_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
+		       u16 table)
+{
+	u32 route_idx;
+	u32 lut_size;
+
+	lut_size = (mport->sys_size) ? 0x1ff : 0xff;
+
+	if (table == RIO_GLOBAL_TABLE) {
+		rio_mport_write_config_32(mport, destid, hopcount,
+					SPBC_ROUTE_CFG_DESTID, 0x80000000);
+		for (route_idx = 0; route_idx <= lut_size; route_idx++)
+			rio_mport_write_config_32(mport, destid, hopcount,
+						SPBC_ROUTE_CFG_PORT,
+						RIO_INVALID_ROUTE);
+	} else {
+		rio_mport_write_config_32(mport, destid, hopcount,
+					SPP_ROUTE_CFG_DESTID(table),
+					0x80000000);
+		for (route_idx = 0; route_idx <= lut_size; route_idx++)
+			rio_mport_write_config_32(mport, destid, hopcount,
+						SPP_ROUTE_CFG_PORT(table),
+						RIO_INVALID_ROUTE);
+	}
+
+	return 0;
+}
+
+DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI568, tsi568_route_add_entry, tsi568_route_get_entry, tsi568_route_clr_table);
diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7c/drivers/rapidio/switches/tsi57x.c w33r7d/drivers/rapidio/switches/tsi57x.c
--- w33r7c/drivers/rapidio/switches/tsi57x.c	1969-12-31 19:00:00.000000000 -0500
+++ w33r7d/drivers/rapidio/switches/tsi57x.c	2010-02-22 11:06:24.074316000 -0500
@@ -0,0 +1,106 @@
+/*
+ * RapidIO Tsi57x switch family support
+ *
+ * Copyright 2009 Integrated Device Technology, Inc.
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/rio_ids.h>
+#include <linux/delay.h>
+#include "../rio.h"
+
+/* Global (broadcast) route registers */
+#define SPBC_ROUTE_CFG_DESTID	0x10070
+#define SPBC_ROUTE_CFG_PORT	0x10074
+
+/* Per port route registers */
+#define SPP_ROUTE_CFG_DESTID(n)	(0x11070 + 0x100*n)
+#define SPP_ROUTE_CFG_PORT(n)	(0x11074 + 0x100*n)
+
+static int
+tsi57x_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+		       u16 table, u16 route_destid, u8 route_port)
+{
+	if (table == RIO_GLOBAL_TABLE) {
+		rio_mport_write_config_32(mport, destid, hopcount,
+					  SPBC_ROUTE_CFG_DESTID, route_destid);
+		rio_mport_write_config_32(mport, destid, hopcount,
+					  SPBC_ROUTE_CFG_PORT, route_port);
+	} else {
+		rio_mport_write_config_32(mport, destid, hopcount,
+				SPP_ROUTE_CFG_DESTID(table), route_destid);
+		rio_mport_write_config_32(mport, destid, hopcount,
+				SPP_ROUTE_CFG_PORT(table), route_port);
+	}
+
+	udelay(10);
+
+	return 0;
+}
+
+static int
+tsi57x_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+		       u16 table, u16 route_destid, u8 *route_port)
+{
+	int ret = 0;
+	u32 result;
+
+	if (table == RIO_GLOBAL_TABLE) {
+		/* Use local RT of the ingress port to avoid possible
+		   race condition */
+		rio_mport_read_config_32(mport, destid, hopcount,
+			RIO_SWP_INFO_CAR, &result);
+		table = (result & RIO_SWP_INFO_PORT_NUM_MASK);
+	}
+
+	rio_mport_write_config_32(mport, destid, hopcount,
+				SPP_ROUTE_CFG_DESTID(table), route_destid);
+	rio_mport_read_config_32(mport, destid, hopcount,
+				SPP_ROUTE_CFG_PORT(table), &result);
+
+	*route_port = (u8)result;
+	if (*route_port > 15)
+		ret = -1;
+
+	return ret;
+}
+
+static int
+tsi57x_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
+		       u16 table)
+{
+	u32 route_idx;
+	u32 lut_size;
+
+	lut_size = (mport->sys_size) ? 0x1ff : 0xff;
+
+	if (table == RIO_GLOBAL_TABLE) {
+		rio_mport_write_config_32(mport, destid, hopcount,
+					  SPBC_ROUTE_CFG_DESTID, 0x80000000);
+		for (route_idx = 0; route_idx <= lut_size; route_idx++)
+			rio_mport_write_config_32(mport, destid, hopcount,
+						  SPBC_ROUTE_CFG_PORT,
+						  RIO_INVALID_ROUTE);
+	} else {
+		rio_mport_write_config_32(mport, destid, hopcount,
+				SPP_ROUTE_CFG_DESTID(table), 0x80000000);
+		for (route_idx = 0; route_idx <= lut_size; route_idx++)
+			rio_mport_write_config_32(mport, destid, hopcount,
+				SPP_ROUTE_CFG_PORT(table) , RIO_INVALID_ROUTE);
+	}
+
+	return 0;
+}
+
+DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI572, tsi57x_route_add_entry, tsi57x_route_get_entry, tsi57x_route_clr_table);
+DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI574, tsi57x_route_add_entry, tsi57x_route_get_entry, tsi57x_route_clr_table);
+DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI577, tsi57x_route_add_entry, tsi57x_route_get_entry, tsi57x_route_clr_table);
+DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI578, tsi57x_route_add_entry, tsi57x_route_get_entry, tsi57x_route_clr_table);
diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7c/include/linux/rio.h w33r7d/include/linux/rio.h
--- w33r7c/include/linux/rio.h	2010-02-06 17:17:12.000000000 -0500
+++ w33r7d/include/linux/rio.h	2010-02-22 11:06:24.105282000 -0500
@@ -213,6 +213,7 @@ struct rio_net {
  * @route_table: Copy of switch routing table
  * @add_entry: Callback for switch-specific route add function
  * @get_entry: Callback for switch-specific route get function
+ * @clr_table: Callback for switch-specific clear route table function
  */
 struct rio_switch {
 	struct list_head node;
@@ -224,6 +225,8 @@ struct rio_switch {
 			  u16 table, u16 route_destid, u8 route_port);
 	int (*get_entry) (struct rio_mport * mport, u16 destid, u8 hopcount,
 			  u16 table, u16 route_destid, u8 * route_port);
+	int (*clr_table) (struct rio_mport *mport, u16 destid, u8 hopcount,
+			  u16 table);
 };
 
 /* Low-level architecture-dependent routines */
@@ -307,6 +310,7 @@ struct rio_device_id {
  * @did: RIO device ID
  * @add_hook: Callback that adds a route entry
  * @get_hook: Callback that gets a route entry
+ * @clr_hook: Callback that clears a switch route table (may be NULL)
  *
  * Defines the operations that are necessary to manipulate the route
  * tables for a particular RIO switch device.
@@ -317,6 +321,8 @@ struct rio_route_ops {
 			 u16 table, u16 route_destid, u8 route_port);
 	int (*get_hook) (struct rio_mport * mport, u16 destid, u8 hopcount,
 			 u16 table, u16 route_destid, u8 * route_port);
+	int (*clr_hook) (struct rio_mport *mport, u16 destid, u8 hopcount,
+			 u16 table);
 };
 
 /* Architecture and hardware-specific functions */
diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7c/include/linux/rio_ids.h w33r7d/include/linux/rio_ids.h
--- w33r7c/include/linux/rio_ids.h	2010-02-06 17:17:12.000000000 -0500
+++ w33r7d/include/linux/rio_ids.h	2010-02-22 11:06:24.241142000 -0500
@@ -20,5 +20,19 @@
 
 #define RIO_VID_TUNDRA			0x000d
 #define RIO_DID_TSI500			0x0500
+#define RIO_DID_TSI568			0x0568
+#define RIO_DID_TSI572			0x0572
+#define RIO_DID_TSI574			0x0574
+#define RIO_DID_TSI576			0x0578 /* Same ID as Tsi578 */
+#define RIO_DID_TSI577			0x0577
+#define RIO_DID_TSI578			0x0578
+
+#define RIO_VID_IDT			0x0038
+#define RIO_DID_IDT70K200		0x0310
+#define RIO_DID_IDTCPS8			0x035c
+#define RIO_DID_IDTCPS12		0x035d
+#define RIO_DID_IDTCPS16		0x035b
+#define RIO_DID_IDTCPS6Q		0x035f
+#define RIO_DID_IDTCPS10Q		0x035e
 
 #endif				/* LINUX_RIO_IDS_H */
diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7c/include/linux/rio_regs.h w33r7d/include/linux/rio_regs.h
--- w33r7c/include/linux/rio_regs.h	2010-02-06 17:17:12.000000000 -0500
+++ w33r7d/include/linux/rio_regs.h	2010-02-22 11:06:24.248134000 -0500
@@ -39,6 +39,8 @@
 #define  RIO_PEF_INB_MBOX2		0x00200000	/* [II] Mailbox 2 */
 #define  RIO_PEF_INB_MBOX3		0x00100000	/* [II] Mailbox 3 */
 #define  RIO_PEF_INB_DOORBELL		0x00080000	/* [II] Doorbells */
+#define  RIO_PEF_EXT_RT			0x00000200	/* [III, 1.3] Extended route table support */
+#define  RIO_PEF_STD_RT			0x00000100	/* [III, 1.3] Standard route table support */
 #define  RIO_PEF_CTLS			0x00000010	/* [III] CTLS */
 #define  RIO_PEF_EXT_FEATURES		0x00000008	/* [I] EFT_PTR valid */
 #define  RIO_PEF_ADDR_66		0x00000004	/* [I] 66 bits */
@@ -91,7 +93,10 @@
 #define  RIO_OPS_ATOMIC_CLR		0x00000010	/* [I] Atomic clr op */
 #define  RIO_OPS_PORT_WRITE		0x00000004	/* [I] Port-write op */
 
-					/* 0x20-0x3c *//* Reserved */
+					/* 0x20-0x30 *//* Reserved */
+
+#define	RIO_SWITCH_RT_LIMIT	0x34	/* [III, 1.3] Switch Route Table Destination ID Limit CAR */
+#define	 RIO_RT_MAX_DESTID		0x0000ffff
 
 #define RIO_MBOX_CSR		0x40	/* [II] Mailbox CSR */
 #define  RIO_MBOX0_AVAIL		0x80000000	/* [II] Mbox 0 avail */
@@ -153,7 +158,11 @@
 #define RIO_HOST_DID_LOCK_CSR	0x68	/* [III] Host Base Device ID Lock CSR */
 #define RIO_COMPONENT_TAG_CSR	0x6c	/* [III] Component Tag CSR */
 
-					/* 0x70-0xf8 *//* Reserved */
+#define RIO_STD_RTE_CONF_DESTID_SEL_CSR	0x70
+#define RIO_STD_RTE_CONF_PORT_SEL_CSR	0x74
+#define RIO_STD_RTE_DEFAULT_PORT	0x78
+
+					/* 0x7c-0xf8 *//* Reserved */
 					/* 0x100-0xfff8 *//* [I] Extended Features Space */
 					/* 0x10000-0xfffff8 *//* [I] Implementation-defined Space */
 
@@ -186,6 +195,7 @@
 #define RIO_EFB_SER_EP_ID	0x0004	/* [VI] LP/Serial EP Devices */
 #define RIO_EFB_SER_EP_REC_ID	0x0005	/* [VI] LP/Serial EP Recovery Devices */
 #define RIO_EFB_SER_EP_FREE_ID	0x0006	/* [VI] LP/Serial EP Free Devices */
+#define RIO_EFB_SER_EP_FREC_ID	0x0009  /* [VI] LP/Serial EP Free Recovery Devices */
 
 /*
  * Physical 8/16 LP-LVDS

---

Important Notice: This message is intended for the use of the individual to whom it is addressed and may contain information which is privileged, confidential and/or exempt from disclosure under applicable law. If the reader of this message is not the intended recipient, or is not the employee or agent responsible for delivering the message to the intended recipient, you are hereby notified that any dissemination, distribution, or copying of this communication is strictly prohibited. If you have received this communication in error, please notify the sender immediately by telephone or return e-mail and delete the original message from your systems. Thank you. 

^ permalink raw reply

* [PATCH 6/7] RapidIO: Add RX/TX enable for SRIO port
From: Alexandre Bounine @ 2010-02-24 15:34 UTC (permalink / raw)
  To: mporter; +Cc: abounine, linuxppc-dev, linux-kernel, thomas.moll.ext,
	thomas.moll


From: Thomas Moll <thomas.moll@sysgo.com>

Add the functionality to enable Input receiver and Output
transmitter of every port, to allow non-maintenance traffic.

Signed-off-by: Thomas Moll <thomas.moll@sysgo.com>
---

 drivers/rapidio/Kconfig    |   11 ++++++
 drivers/rapidio/rio-scan.c |   79 ++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/rio_regs.h   |    5 ++
 3 files changed, 94 insertions(+), 1 deletion(-)

diff -purN linux-base/drivers/rapidio/Kconfig linux-new/drivers/rapidio/Kconfig
--- linux-base/drivers/rapidio/Kconfig	2010-02-22 10:44:47.000000000 +0100
+++ linux-new/drivers/rapidio/Kconfig	2010-02-22 12:36:20.000000000 +0100
@@ -8,3 +8,14 @@ config RAPIDIO_DISC_TIMEOUT
 	---help---
 	  Amount of time a discovery node waits for a host to complete
 	  enumeration before giving up.
+
+config RAPIDIO_ENABLE_RX_TX_PORTS
+	bool "Enable RapidIO Input/Output Ports"
+	depends on RAPIDIO
+	---help---
+	  The RapidIO specification describes a Output port transmit
+	  enable and a Input port receive enable. The recommended state
+	  for Input ports and Output ports should be disabled. When
+	  this switch is set the RapidIO subsystem will enable all
+	  ports for Input/Output direction to allow other traffic
+	  than Maintenance transfers.
diff -purN linux-base/drivers/rapidio/rio-scan.c linux-new/drivers/rapidio/rio-scan.c
--- linux-base/drivers/rapidio/rio-scan.c	2010-02-22 10:48:15.000000000 +0100
+++ linux-new/drivers/rapidio/rio-scan.c	2010-02-22 13:42:08.000000000 +0100
@@ -8,6 +8,10 @@
  * Alex Bounine <alexandre.bounine@idt.com>
  * - Added Port-Write/Error Management initialization and handling
  *
+ * Copyright 2009 Sysgo AG
+ * Thomas Moll <thomas.moll@sysgo.com>
+ * - Added Input- Output- enable functionality, to allow full communication
+ *
  * 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
@@ -328,6 +332,65 @@ static int __devinit rio_add_device(stru
 }
 
 /**
+ * rio_enable_rx_tx_port - enable input reciever and output transmitter of
+ * given port
+ * @port: Master port associated with the RIO network
+ * @local: local=1 select local port otherwise a far device is reached
+ * @destid: Destination ID of the device to check host bit
+ * @hopcount: Number of hops to reach the target
+ * @port_num: Port (-number on switch) to enable on a far end device
+ *
+ * Returns 0 or 1 from on General Control Command and Status Register
+ * (EXT_PTR+0x3C)
+ */
+inline int rio_enable_rx_tx_port(struct rio_mport *port,
+				 int local, u16 destid,
+				 u8 hopcount, u8 port_num) {
+#ifdef CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS
+	u32 regval;
+	u32 ext_ftr_ptr;
+
+	/*
+	* enable rx input tx output port
+	*/
+	pr_debug("rio_enable_rx_tx_port(local = %d, destid = %d, hopcount = "
+		 "%d, port_num = %d)\n", local, destid, hopcount, port_num);
+
+	ext_ftr_ptr = rio_mport_get_physefb(port, local, destid, hopcount);
+
+	if (local) {
+		rio_local_read_config_32(port, ext_ftr_ptr +
+				RIO_PORT_N_CTL_CSR(0),
+				&regval);
+	} else {
+		if (rio_mport_read_config_32(port, destid, hopcount,
+		ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), &regval) < 0)
+			return -EIO;
+	}
+
+	if (regval & RIO_PORT_N_CTL_P_TYP_SER) {
+		/* serial */
+		regval = regval | RIO_PORT_N_CTL_EN_RX_SER
+				| RIO_PORT_N_CTL_EN_TX_SER;
+	} else {
+		/* parallel */
+		regval = regval | RIO_PORT_N_CTL_EN_RX_PAR
+				| RIO_PORT_N_CTL_EN_TX_PAR;
+	}
+
+	if (local) {
+		rio_local_write_config_32(port, ext_ftr_ptr +
+					  RIO_PORT_N_CTL_CSR(0), regval);
+	} else {
+		if (rio_mport_write_config_32(port, destid, hopcount,
+		    ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), regval) < 0)
+			return -EIO;
+	}
+#endif
+	return 0;
+}
+
+/**
  * rio_setup_device- Allocates and sets up a RIO device
  * @net: RIO network
  * @port: Master port to send transactions
@@ -430,9 +493,14 @@ static struct rio_dev __devinit *rio_set
 
 		list_add_tail(&rswitch->node, &rio_switches);
 
-	} else
+	} else {
+		if (do_enum)
+			/*Enable Input Output Port (transmitter reviever)*/
+			rio_enable_rx_tx_port(port, 0, destid, hopcount, 0);
+
 		dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->net->id,
 			     rdev->destid);
+	}
 
 	rdev->dev.bus = &rio_bus_type;
 
@@ -740,6 +808,11 @@ static int __devinit rio_enum_peer(struc
 		    rio_name(rdev), rdev->vid, rdev->did, num_ports);
 		sw_destid = next_destid;
 		for (port_num = 0; port_num < num_ports; port_num++) {
+			/*Enable Input Output Port (transmitter reviever)*/
+			rio_enable_rx_tx_port(port, 0,
+					      RIO_ANY_DESTID(port->sys_size),
+					      hopcount, port_num);
+
 			if (sw_inport == port_num) {
 				rdev->rswitch->port_ok |= (1 << port_num);
 				continue;
@@ -1085,6 +1158,10 @@ int __devinit rio_enum_mport(struct rio_
 			rc = -ENOMEM;
 			goto out;
 		}
+
+		/* Enable Input Output Port (transmitter reviever) */
+		rio_enable_rx_tx_port(mport, 1, 0, 0, 0);
+
 		if (rio_enum_peer(net, mport, 0) < 0) {
 			/* A higher priority host won enumeration, bail. */
 			printk(KERN_INFO
diff -purN linux-base/include/linux/rio_regs.h linux-new/include/linux/rio_regs.h
--- linux-base/include/linux/rio_regs.h	2010-02-22 10:48:15.000000000 +0100
+++ linux-new/include/linux/rio_regs.h	2010-02-22 12:38:57.000000000 +0100
@@ -242,7 +242,12 @@
 #define  RIO_PORT_N_CTL_PWIDTH		0xc0000000
 #define  RIO_PORT_N_CTL_PWIDTH_1	0x00000000
 #define  RIO_PORT_N_CTL_PWIDTH_4	0x40000000
+#define  RIO_PORT_N_CTL_P_TYP_SER	0x00000001
 #define  RIO_PORT_N_CTL_LOCKOUT		0x00000002
+#define  RIO_PORT_N_CTL_EN_RX_SER	0x00200000
+#define  RIO_PORT_N_CTL_EN_TX_SER	0x00400000
+#define  RIO_PORT_N_CTL_EN_RX_PAR	0x08000000
+#define  RIO_PORT_N_CTL_EN_TX_PAR	0x40000000
 
 /*
  * Error Management Extensions (RapidIO 1.3+, Part 8)

---

Important Notice: This message is intended for the use of the individual to whom it is addressed and may contain information which is privileged, confidential and/or exempt from disclosure under applicable law. If the reader of this message is not the intended recipient, or is not the employee or agent responsible for delivering the message to the intended recipient, you are hereby notified that any dissemination, distribution, or copying of this communication is strictly prohibited. If you have received this communication in error, please notify the sender immediately by telephone or return e-mail and delete the original message from your systems. Thank you. 

^ permalink raw reply

* [PATCH 5/7] powerpc/85xx: Add MChk handler for SRIO port
From: Alexandre Bounine @ 2010-02-24 15:30 UTC (permalink / raw)
  To: mporter; +Cc: abounine, linuxppc-dev, linux-kernel, thomas.moll.ext,
	thomas.moll


From: Alexandre Bounine <alexandre.bounine@idt.com>

Add Machine Check exception handling into RapidIO port driver
for Freescale SoCs (MPC85xx).

Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com>
Tested-by: Thomas Moll <thomas.moll@sysgo.com>
---

 fsl_rio.c |   74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 70 insertions(+), 4 deletions(-)

diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7a/arch/powerpc/sysdev/fsl_rio.c w33r7b/arch/powerpc/sysdev/fsl_rio.c
--- w33r7a/arch/powerpc/sysdev/fsl_rio.c	2010-02-12 11:03:23.425826000 -0500
+++ w33r7b/arch/powerpc/sysdev/fsl_rio.c	2010-02-12 13:46:57.558951000 -0500
@@ -31,6 +31,8 @@
 #include <linux/kfifo.h>
 
 #include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/uaccess.h>
 
 #undef DEBUG_PW	/* Port-Write debugging */
 
@@ -46,6 +48,8 @@
 #define RIO_ESCSR		0x158
 #define RIO_CCSR		0x15c
 #define RIO_LTLEDCSR		0x0608
+#define  RIO_LTLEDCSR_IER	0x80000000
+#define  RIO_LTLEDCSR_PRT	0x01000000
 #define RIO_LTLEECSR		0x060c
 #define RIO_EPWISR		0x10010
 #define RIO_ISR_AACR		0x10120
@@ -213,6 +217,54 @@ struct rio_priv {
 	spinlock_t pw_fifo_lock;
 };
 
+#define __fsl_read_rio_config(x, addr, err, op)		\
+	__asm__ __volatile__(				\
+		"1:	"op" %1,0(%2)\n"		\
+		"	eieio\n"			\
+		"2:\n"					\
+		".section .fixup,\"ax\"\n"		\
+		"3:	li %1,-1\n"			\
+		"	li %0,%3\n"			\
+		"	b 2b\n"				\
+		".section __ex_table,\"a\"\n"		\
+		"	.align 2\n"			\
+		"	.long 1b,3b\n"			\
+		".text"					\
+		: "=r" (err), "=r" (x)			\
+		: "b" (addr), "i" (-EFAULT), "0" (err))
+
+static void __iomem *rio_regs_win;
+
+static int (*saved_mcheck_exception)(struct pt_regs *regs);
+
+static int fsl_rio_mcheck_exception(struct pt_regs *regs)
+{
+	const struct exception_table_entry *entry = NULL;
+	unsigned long reason = (mfspr(SPRN_MCSR) & MCSR_MASK);
+
+	if (reason & MCSR_BUS_RBERR) {
+		reason = in_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR));
+		if (reason & (RIO_LTLEDCSR_IER | RIO_LTLEDCSR_PRT)) {
+			/* Check if we are prepared to handle this fault */
+			entry = search_exception_tables(regs->nip);
+			if (entry) {
+				pr_debug("RIO: %s - MC Exception handled\n",
+					 __func__);
+				out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR),
+					 0);
+				regs->msr |= MSR_RI;
+				regs->nip = entry->fixup;
+				return 1;
+			}
+		}
+	}
+
+	if (saved_mcheck_exception)
+		return saved_mcheck_exception(regs);
+	else
+		return cur_cpu_spec->machine_check(regs);
+}
+
 /**
  * fsl_rio_doorbell_send - Send a MPC85xx doorbell message
  * @mport: RapidIO master port info
@@ -313,6 +365,7 @@ fsl_rio_config_read(struct rio_mport *mp
 {
 	struct rio_priv *priv = mport->priv;
 	u8 *data;
+	u32 rval, err = 0;
 
 	pr_debug
 	    ("fsl_rio_config_read: index %d destid %d hopcount %d offset %8.8x len %d\n",
@@ -323,17 +376,24 @@ fsl_rio_config_read(struct rio_mport *mp
 	data = (u8 *) priv->maint_win + offset;
 	switch (len) {
 	case 1:
-		*val = in_8((u8 *) data);
+		__fsl_read_rio_config(rval, data, err, "lbz");
 		break;
 	case 2:
-		*val = in_be16((u16 *) data);
+		__fsl_read_rio_config(rval, data, err, "lhz");
 		break;
 	default:
-		*val = in_be32((u32 *) data);
+		__fsl_read_rio_config(rval, data, err, "lwz");
 		break;
 	}
 
-	return 0;
+	if (err) {
+		pr_debug("RIO: cfg_read error %d for %x:%x:%x\n",
+			 err, destid, hopcount, offset);
+	}
+
+	*val = rval;
+
+	return err;
 }
 
 /**
@@ -1364,6 +1424,7 @@ int fsl_rio_setup(struct of_device *dev)
 	rio_register_mport(port);
 
 	priv->regs_win = ioremap(regs.start, regs.end - regs.start + 1);
+	rio_regs_win = priv->regs_win;
 
 	/* Probe the master port phy type */
 	ccsr = in_be32(priv->regs_win + RIO_CCSR);
@@ -1432,6 +1493,11 @@ int fsl_rio_setup(struct of_device *dev)
 	fsl_rio_doorbell_init(port);
 	fsl_rio_port_write_init(port);
 
+	saved_mcheck_exception = ppc_md.machine_check_exception;
+	ppc_md.machine_check_exception = fsl_rio_mcheck_exception;
+	/* Ensure that RFXE is set */
+	mtspr(SPRN_HID1, (mfspr(SPRN_HID1) | 0x20000));
+
 	return 0;
 err:
 	iounmap(priv->regs_win);

---

Important Notice: This message is intended for the use of the individual to whom it is addressed and may contain information which is privileged, confidential and/or exempt from disclosure under applicable law. If the reader of this message is not the intended recipient, or is not the employee or agent responsible for delivering the message to the intended recipient, you are hereby notified that any dissemination, distribution, or copying of this communication is strictly prohibited. If you have received this communication in error, please notify the sender immediately by telephone or return e-mail and delete the original message from your systems. Thank you. 

^ permalink raw reply

* [PATCH 4/7] powerpc/85xx: Add Port-Write message handler for SRIO port
From: Alexandre Bounine @ 2010-02-24 15:27 UTC (permalink / raw)
  To: mporter; +Cc: linuxppc-dev, linux-kernel, thomas.moll.ext, thomas.moll


From: Alexandre Bounine <alexandre.bounine@idt.com>

Add RapidIO Port-Write message handler for Freescale SoCs with RapidIO port.

Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com>
Tested-by: Thomas Moll <thomas.moll@sysgo.com>
---

 fsl_rio.c |  263 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 260 insertions(+), 3 deletions(-)

diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7a/arch/powerpc/sysdev/fsl_rio.c w33r7b/arch/powerpc/sysdev/fsl_rio.c
--- w33r7a/arch/powerpc/sysdev/fsl_rio.c	2010-02-06 17:17:12.000000000 -0500
+++ w33r7b/arch/powerpc/sysdev/fsl_rio.c	2010-02-12 10:43:03.297481000 -0500
@@ -1,6 +1,11 @@
 /*
  * Freescale MPC85xx/MPC86xx RapidIO support
  *
+ * Copyright 2009 Integrated Device Technology, Inc.
+ * Alex Bounine <alexandre.bounine@idt.com>
+ * - Added Port-Write message handling
+ * - Added Machine Check exception handling
+ *
  * Copyright (C) 2007, 2008 Freescale Semiconductor, Inc.
  * Zhang Wei <wei.zhang@freescale.com>
  *
@@ -23,19 +28,26 @@
 #include <linux/rio_drv.h>
 #include <linux/of_platform.h>
 #include <linux/delay.h>
+#include <linux/kfifo.h>
 
 #include <asm/io.h>
 
+#undef DEBUG_PW	/* Port-Write debugging */
+
 /* RapidIO definition irq, which read from OF-tree */
 #define IRQ_RIO_BELL(m)		(((struct rio_priv *)(m->priv))->bellirq)
 #define IRQ_RIO_TX(m)		(((struct rio_priv *)(m->priv))->txirq)
 #define IRQ_RIO_RX(m)		(((struct rio_priv *)(m->priv))->rxirq)
+#define IRQ_RIO_PW(m)		(((struct rio_priv *)(m->priv))->pwirq)
 
 #define RIO_ATMU_REGS_OFFSET	0x10c00
 #define RIO_P_MSG_REGS_OFFSET	0x11000
 #define RIO_S_MSG_REGS_OFFSET	0x13000
 #define RIO_ESCSR		0x158
 #define RIO_CCSR		0x15c
+#define RIO_LTLEDCSR		0x0608
+#define RIO_LTLEECSR		0x060c
+#define RIO_EPWISR		0x10010
 #define RIO_ISR_AACR		0x10120
 #define RIO_ISR_AACR_AA		0x1	/* Accept All ID */
 #define RIO_MAINT_WIN_SIZE	0x400000
@@ -54,6 +66,18 @@
 #define RIO_MSG_ISR_QFI		0x00000010
 #define RIO_MSG_ISR_DIQI	0x00000001
 
+#define RIO_IPWMR_SEN		0x00100000
+#define RIO_IPWMR_QFIE		0x00000100
+#define RIO_IPWMR_EIE		0x00000020
+#define RIO_IPWMR_CQ		0x00000002
+#define RIO_IPWMR_PWE		0x00000001
+
+#define RIO_IPWSR_QF		0x00100000
+#define RIO_IPWSR_TE		0x00000080
+#define RIO_IPWSR_QFI		0x00000010
+#define RIO_IPWSR_PWD		0x00000008
+#define RIO_IPWSR_PWB		0x00000004
+
 #define RIO_MSG_DESC_SIZE	32
 #define RIO_MSG_BUFFER_SIZE	4096
 #define RIO_MIN_TX_RING_SIZE	2
@@ -120,7 +144,7 @@ struct rio_msg_regs {
 	u32 pad10[26];
 	u32 pwmr;
 	u32 pwsr;
-	u32 pad11;
+	u32 epwqbar;
 	u32 pwqbar;
 };
 
@@ -159,6 +183,14 @@ struct rio_msg_rx_ring {
 	void *dev_id;
 };
 
+struct rio_port_write_msg {
+	void *virt;
+	dma_addr_t phys;
+	u32 msg_count;
+	u32 err_count;
+	u32 discard_count;
+};
+
 struct rio_priv {
 	struct device *dev;
 	void __iomem *regs_win;
@@ -171,9 +203,14 @@ struct rio_priv {
 	struct rio_dbell_ring dbell_ring;
 	struct rio_msg_tx_ring msg_tx_ring;
 	struct rio_msg_rx_ring msg_rx_ring;
+	struct rio_port_write_msg port_write_msg;
 	int bellirq;
 	int txirq;
 	int rxirq;
+	int pwirq;
+	struct work_struct pw_work;
+	struct kfifo pw_fifo;
+	spinlock_t pw_fifo_lock;
 };
 
 /**
@@ -929,6 +966,223 @@ static int fsl_rio_doorbell_init(struct 
 	return rc;
 }
 
+/**
+ * fsl_rio_port_write_handler - MPC85xx port write interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ *
+ * Handles port write interrupts. Parses a list of registered
+ * port write event handlers and executes a matching event handler.
+ */
+static irqreturn_t
+fsl_rio_port_write_handler(int irq, void *dev_instance)
+{
+	u32 ipwmr, ipwsr;
+	struct rio_mport *port = (struct rio_mport *)dev_instance;
+	struct rio_priv *priv = port->priv;
+	u32 epwisr, tmp;
+
+	ipwmr = in_be32(&priv->msg_regs->pwmr);
+	ipwsr = in_be32(&priv->msg_regs->pwsr);
+
+	epwisr = in_be32(priv->regs_win + RIO_EPWISR);
+	if (epwisr & 0x80000000) {
+		tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
+		pr_info("RIO_LTLEDCSR = 0x%x\n", tmp);
+		out_be32(priv->regs_win + RIO_LTLEDCSR, 0);
+	}
+
+	if (!(epwisr & 0x00000001))
+		return IRQ_HANDLED;
+
+#ifdef DEBUG_PW
+	pr_debug("PW Int->IPWMR: 0x%08x IPWSR: 0x%08x (", ipwmr, ipwsr);
+	if (ipwsr & RIO_IPWSR_QF)
+		pr_debug(" QF");
+	if (ipwsr & RIO_IPWSR_TE)
+		pr_debug(" TE");
+	if (ipwsr & RIO_IPWSR_QFI)
+		pr_debug(" QFI");
+	if (ipwsr & RIO_IPWSR_PWD)
+		pr_debug(" PWD");
+	if (ipwsr & RIO_IPWSR_PWB)
+		pr_debug(" PWB");
+	pr_debug(" )\n");
+#endif
+	out_be32(&priv->msg_regs->pwsr,
+		 ipwsr & (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD));
+
+	if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) {
+		priv->port_write_msg.err_count++;
+		pr_info("RIO: Port-Write Transaction Err (%d)\n",
+			 priv->port_write_msg.err_count);
+	}
+	if (ipwsr & RIO_IPWSR_PWD) {
+		priv->port_write_msg.discard_count++;
+		pr_info("RIO: Port Discarded Port-Write Msg(s) (%d)\n",
+			 priv->port_write_msg.discard_count);
+	}
+
+	/* Schedule deferred processing if PW was received */
+	if (ipwsr & RIO_IPWSR_QFI) {
+		/* Save PW message (if there is room in FIFO),
+		 * otherwise discard it.
+		 */
+		if (kfifo_avail(&priv->pw_fifo) >= RIO_PW_MSG_SIZE) {
+			priv->port_write_msg.msg_count++;
+			kfifo_in(&priv->pw_fifo, priv->port_write_msg.virt,
+				 RIO_PW_MSG_SIZE);
+		} else {
+			priv->port_write_msg.discard_count++;
+			pr_info("RIO: ISR Discarded Port-Write Msg(s) (%d)\n",
+				 priv->port_write_msg.discard_count);
+		}
+		schedule_work(&priv->pw_work);
+	}
+
+	/* Issue Clear Queue command. This allows another
+	 * port-write to be received.
+	 */
+	out_be32(&priv->msg_regs->pwmr, ipwmr | RIO_IPWMR_CQ);
+
+	return IRQ_HANDLED;
+}
+
+static void fsl_pw_dpc(struct work_struct *work)
+{
+	struct rio_priv *priv = container_of(work, struct rio_priv, pw_work);
+	unsigned long flags;
+	u32 msg_buffer[RIO_PW_MSG_SIZE/sizeof(u32)];
+
+	/*
+	 * Process port-write messages
+	 */
+	spin_lock_irqsave(&priv->pw_fifo_lock, flags);
+	while (kfifo_out(&priv->pw_fifo, (unsigned char *)msg_buffer,
+			 RIO_PW_MSG_SIZE)) {
+		/* Process one message */
+		spin_unlock_irqrestore(&priv->pw_fifo_lock, flags);
+#ifdef DEBUG_PW
+		{
+		u32 i;
+		pr_debug("%s : Port-Write Message:", __func__);
+		for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32); i++) {
+			if ((i%4) == 0)
+				pr_debug("\n0x%02x: 0x%08x", i*4,
+					 msg_buffer[i]);
+			else
+				pr_debug(" 0x%08x", msg_buffer[i]);
+		}
+		pr_debug("\n");
+		}
+#endif
+		/* Pass the port-write message to RIO core for processing */
+		rio_inb_pwrite_handler(msg_buffer);
+		spin_lock_irqsave(&priv->pw_fifo_lock, flags);
+	}
+	spin_unlock_irqrestore(&priv->pw_fifo_lock, flags);
+}
+
+/**
+ * fsl_rio_pw_enable - enable/disable port-write interface init
+ * @mport: Master port implementing the port write unit
+ * @enable:    1=enable; 0=disable port-write message handling
+ */
+static int fsl_rio_pw_enable(struct rio_mport *mport, int enable)
+{
+	struct rio_priv *priv = mport->priv;
+	u32 rval;
+
+	rval = in_be32(&priv->msg_regs->pwmr);
+
+	if (enable)
+		rval |= RIO_IPWMR_PWE;
+	else
+		rval &= ~RIO_IPWMR_PWE;
+
+	out_be32(&priv->msg_regs->pwmr, rval);
+
+	return 0;
+}
+
+/**
+ * fsl_rio_port_write_init - MPC85xx port write interface init
+ * @mport: Master port implementing the port write unit
+ *
+ * Initializes port write unit hardware and DMA buffer
+ * ring. Called from fsl_rio_setup(). Returns %0 on success
+ * or %-ENOMEM on failure.
+ */
+static int fsl_rio_port_write_init(struct rio_mport *mport)
+{
+	struct rio_priv *priv = mport->priv;
+	int rc = 0;
+
+	/* Following configurations require a disabled port write controller */
+	out_be32(&priv->msg_regs->pwmr,
+		 in_be32(&priv->msg_regs->pwmr) & ~RIO_IPWMR_PWE);
+
+	/* Initialize port write */
+	priv->port_write_msg.virt = dma_alloc_coherent(priv->dev,
+					RIO_PW_MSG_SIZE,
+					&priv->port_write_msg.phys, GFP_KERNEL);
+	if (!priv->port_write_msg.virt) {
+		pr_err("RIO: unable allocate port write queue\n");
+		return -ENOMEM;
+	}
+
+	priv->port_write_msg.err_count = 0;
+	priv->port_write_msg.discard_count = 0;
+
+	/* Point dequeue/enqueue pointers at first entry */
+	out_be32(&priv->msg_regs->epwqbar, 0);
+	out_be32(&priv->msg_regs->pwqbar, (u32) priv->port_write_msg.phys);
+
+	pr_debug("EIPWQBAR: 0x%08x IPWQBAR: 0x%08x\n",
+		 in_be32(&priv->msg_regs->epwqbar),
+		 in_be32(&priv->msg_regs->pwqbar));
+
+	/* Clear interrupt status IPWSR */
+	out_be32(&priv->msg_regs->pwsr,
+		 (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD));
+
+	/* Configure port write contoller for snooping enable all reporting,
+	   clear queue full */
+	out_be32(&priv->msg_regs->pwmr,
+		 RIO_IPWMR_SEN | RIO_IPWMR_QFIE | RIO_IPWMR_EIE | RIO_IPWMR_CQ);
+
+
+	/* Hook up port-write handler */
+	rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler, 0,
+			 "port-write", (void *)mport);
+	if (rc < 0) {
+		pr_err("MPC85xx RIO: unable to request inbound doorbell irq");
+		goto err_out;
+	}
+
+	INIT_WORK(&priv->pw_work, fsl_pw_dpc);
+	spin_lock_init(&priv->pw_fifo_lock);
+	if (kfifo_alloc(&priv->pw_fifo, RIO_PW_MSG_SIZE * 32, GFP_KERNEL)) {
+		pr_err("FIFO allocation failed\n");
+		rc = -ENOMEM;
+		goto err_out_irq;
+	}
+
+	pr_debug("IPWMR: 0x%08x IPWSR: 0x%08x\n",
+		 in_be32(&priv->msg_regs->pwmr),
+		 in_be32(&priv->msg_regs->pwsr));
+
+	return rc;
+
+err_out_irq:
+	free_irq(IRQ_RIO_PW(mport), (void *)mport);
+err_out:
+	dma_free_coherent(priv->dev, RIO_PW_MSG_SIZE,
+			  priv->port_write_msg.virt,
+			  priv->port_write_msg.phys);
+	return rc;
+}
+
 static char *cmdline = NULL;
 
 static int fsl_rio_get_hdid(int index)
@@ -1066,6 +1320,7 @@ int fsl_rio_setup(struct of_device *dev)
 	ops->cread = fsl_rio_config_read;
 	ops->cwrite = fsl_rio_config_write;
 	ops->dsend = fsl_rio_doorbell_send;
+	ops->pwenable = fsl_rio_pw_enable;
 
 	port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL);
 	if (!port) {
@@ -1088,11 +1343,12 @@ int fsl_rio_setup(struct of_device *dev)
 	port->iores.flags = IORESOURCE_MEM;
 	port->iores.name = "rio_io_win";
 
+	priv->pwirq   = irq_of_parse_and_map(dev->node, 0);
 	priv->bellirq = irq_of_parse_and_map(dev->node, 2);
 	priv->txirq = irq_of_parse_and_map(dev->node, 3);
 	priv->rxirq = irq_of_parse_and_map(dev->node, 4);
-	dev_info(&dev->dev, "bellirq: %d, txirq: %d, rxirq %d\n", priv->bellirq,
-				priv->txirq, priv->rxirq);
+	dev_info(&dev->dev, "pwirq: %d, bellirq: %d, txirq: %d, rxirq %d\n",
+		 priv->pwirq, priv->bellirq, priv->txirq, priv->rxirq);
 
 	rio_init_dbell_res(&port->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
 	rio_init_mbox_res(&port->riores[RIO_INB_MBOX_RESOURCE], 0, 0);
@@ -1174,6 +1430,7 @@ int fsl_rio_setup(struct of_device *dev)
 			(law_start + RIO_MAINT_WIN_SIZE) >> 12);
 	out_be32(&priv->dbell_atmu_regs->rowar, 0x8004200b);	/* 4k */
 	fsl_rio_doorbell_init(port);
+	fsl_rio_port_write_init(port);
 
 	return 0;
 err:

---

Important Notice: This message is intended for the use of the individual to whom it is addressed and may contain information which is privileged, confidential and/or exempt from disclosure under applicable law. If the reader of this message is not the intended recipient, or is not the employee or agent responsible for delivering the message to the intended recipient, you are hereby notified that any dissemination, distribution, or copying of this communication is strictly prohibited. If you have received this communication in error, please notify the sender immediately by telephone or return e-mail and delete the original message from your systems. Thank you. 

^ permalink raw reply

* [PATCH 3/7] RapidIO: Add Port-Write handling for EM
From: Alexandre Bounine @ 2010-02-24 15:24 UTC (permalink / raw)
  To: mporter; +Cc: linuxppc-dev, linux-kernel, thomas.moll.ext, thomas.moll


From: Alexandre Bounine <alexandre.bounine@idt.com>

Add RapidIO Port-Write message handling in the context
of Error Management Extensions Specification Rev.1.3.

Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com>
Tested-by: Thomas Moll <thomas.moll@sysgo.com>
---

 drivers/rapidio/rio-scan.c        |  197 +++++++++++++++++++-----
 drivers/rapidio/rio.c             |  307 ++++++++++++++++++++++++++++++++++++++
 drivers/rapidio/rio.h             |   29 +++
 drivers/rapidio/switches/tsi568.c |   24 ++
 drivers/rapidio/switches/tsi57x.c |  153 ++++++++++++++++++
 include/asm-generic/vmlinux.lds.h |    5 
 include/linux/rio.h               |   30 +++
 include/linux/rio_drv.h           |    6 
 include/linux/rio_regs.h          |   60 +++++++
 9 files changed, 771 insertions(+), 40 deletions(-)

diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7a/drivers/rapidio/rio-scan.c w33r7b/drivers/rapidio/rio-scan.c
--- w33r7a/drivers/rapidio/rio-scan.c	2010-02-10 16:25:31.950433000 -0500
+++ w33r7b/drivers/rapidio/rio-scan.c	2010-02-11 14:33:44.796825000 -0500
@@ -4,6 +4,10 @@
  * Copyright 2005 MontaVista Software, Inc.
  * Matt Porter <mporter@kernel.crashing.org>
  *
+ * Copyright 2009 Integrated Device Technology, Inc.
+ * Alex Bounine <alexandre.bounine@idt.com>
+ * - Added Port-Write/Error Management initialization and handling
+ *
  * 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
@@ -31,15 +35,16 @@
 LIST_HEAD(rio_devices);
 static LIST_HEAD(rio_switches);
 
-#define RIO_ENUM_CMPL_MAGIC	0xdeadbeef
-
 static void rio_enum_timeout(unsigned long);
 
+static void rio_init_em(struct rio_dev *rdev);
+
 DEFINE_SPINLOCK(rio_global_list_lock);
 
 static int next_destid = 0;
 static int next_switchid = 0;
 static int next_net = 0;
+static int next_comptag;
 
 static struct timer_list rio_enum_timer =
 TIMER_INITIALIZER(rio_enum_timeout, 0, 0);
@@ -52,13 +57,6 @@ static int rio_mport_phys_table[] = {
 	-1,
 };
 
-static int rio_sport_phys_table[] = {
-	RIO_EFB_PAR_EP_FREE_ID,
-	RIO_EFB_SER_EP_FREE_ID,
-	RIO_EFB_SER_EP_FREC_ID,
-	-1,
-};
-
 /**
  * rio_get_device_id - Get the base/extended device id for a device
  * @port: RIO master port
@@ -119,12 +117,26 @@ static int rio_clear_locks(struct rio_mp
 	u32 result;
 	int ret = 0;
 
-	/* Write component tag CSR magic complete value */
-	rio_local_write_config_32(port, RIO_COMPONENT_TAG_CSR,
-				  RIO_ENUM_CMPL_MAGIC);
-	list_for_each_entry(rdev, &rio_devices, global_list)
-	    rio_write_config_32(rdev, RIO_COMPONENT_TAG_CSR,
-				RIO_ENUM_CMPL_MAGIC);
+	/* Assign component tag to all devices */
+	next_comptag = 1;
+	rio_local_write_config_32(port, RIO_COMPONENT_TAG_CSR, next_comptag++);
+
+	list_for_each_entry(rdev, &rio_devices, global_list) {
+		/* Mark device as discovered */
+		rio_read_config_32(rdev,
+				   rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
+				   &result);
+		rio_write_config_32(rdev,
+				    rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
+				    result | RIO_PORT_GEN_DISCOVERED);
+
+		rio_write_config_32(rdev, RIO_COMPONENT_TAG_CSR, next_comptag);
+		rdev->comp_tag = next_comptag++;
+		if (next_comptag >= 0x10000) {
+			pr_err("RIO: Component Tag Counter Overflow\n");
+			break;
+		}
+	}
 
 	/* Release host device id locks */
 	rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR,
@@ -267,6 +279,30 @@ static void rio_route_set_ops(struct rio
 }
 
 /**
+ * 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.
+ */
+static void rio_em_set_ops(struct rio_dev *rdev)
+{
+	struct rio_em_ops *cur = __start_rio_em_ops;
+	struct rio_em_ops *end = __end_rio_em_ops;
+
+	while (cur < end) {
+		if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) {
+			pr_debug("RIO: adding EM ops for %s\n", rio_name(rdev));
+			rdev->rswitch->em_init = cur->init_hook;
+			rdev->rswitch->em_handle = cur->handler_hook;
+			break;
+		}
+		cur++;
+	}
+}
+
+/**
  * rio_add_device- Adds a RIO device to the device model
  * @rdev: RIO device
  *
@@ -336,8 +372,14 @@ static struct rio_dev __devinit *rio_set
 	rdev->asm_rev = result >> 16;
 	rio_mport_read_config_32(port, destid, hopcount, RIO_PEF_CAR,
 				 &rdev->pef);
-	if (rdev->pef & RIO_PEF_EXT_FEATURES)
+	if (rdev->pef & RIO_PEF_EXT_FEATURES) {
 		rdev->efptr = result & 0xffff;
+		rdev->phys_efptr = rio_mport_get_physefb(port, 0, destid,
+							 hopcount);
+
+		rdev->em_efptr = rio_mport_get_feature(port, 0, destid,
+						hopcount, RIO_EFB_ERR_MGMNT);
+	}
 
 	rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR,
 				 &rdev->src_ops);
@@ -366,6 +408,7 @@ static struct rio_dev __devinit *rio_set
 		rswitch->switchid = next_switchid;
 		rswitch->hopcount = hopcount;
 		rswitch->destid = destid;
+		rswitch->port_ok = 0;
 		rswitch->route_table = kzalloc(sizeof(u8)*
 					RIO_MAX_ROUTE_ENTRIES(port->sys_size),
 					GFP_KERNEL);
@@ -379,6 +422,7 @@ static struct rio_dev __devinit *rio_set
 		dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id,
 			     rdev->rswitch->switchid);
 		rio_route_set_ops(rdev);
+		rio_em_set_ops(rdev);
 
 		if (do_enum && rdev->rswitch->clr_table)
 			rdev->rswitch->clr_table(port, destid, hopcount,
@@ -429,23 +473,29 @@ cleanup:
  *
  * Reads the port error status CSR for a particular switch port to
  * determine if the port has an active link.  Returns
- * %PORT_N_ERR_STS_PORT_OK if the port is active or %0 if it is
+ * %RIO_PORT_N_ERR_STS_PORT_OK if the port is active or %0 if it is
  * inactive.
  */
 static int
 rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
 {
-	u32 result;
+	u32 result = 0;
 	u32 ext_ftr_ptr;
 
-	int *entry = rio_sport_phys_table;
-
-	do {
-		if ((ext_ftr_ptr =
-		     rio_mport_get_feature(port, 0, destid, hopcount, *entry)))
+	ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount, 0);
 
+	while (ext_ftr_ptr) {
+		rio_mport_read_config_32(port, destid, hopcount,
+					 ext_ftr_ptr, &result);
+		result = RIO_GET_BLOCK_ID(result);
+		if ((result == RIO_EFB_SER_EP_FREE_ID) ||
+		    (result == RIO_EFB_SER_EP_FREE_ID_V13P) ||
+		    (result == RIO_EFB_SER_EP_FREC_ID))
 			break;
-	} while (*++entry >= 0);
+
+		ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount,
+						ext_ftr_ptr);
+	}
 
 	if (ext_ftr_ptr)
 		rio_mport_read_config_32(port, destid, hopcount,
@@ -453,7 +503,38 @@ rio_sport_is_active(struct rio_mport *po
 					 RIO_PORT_N_ERR_STS_CSR(sport),
 					 &result);
 
-	return (result & PORT_N_ERR_STS_PORT_OK);
+	return result & RIO_PORT_N_ERR_STS_PORT_OK;
+}
+
+/**
+ * rio_set_port_lockout - Sets/clears LOCKOUT bit (RIO EM 1.3) for a switch port.
+ * @rdev: Pointer to RIO device control structure
+ * @pnum: Switch port number to set LOCKOUT bit
+ * @lock: Operation : set (=1) or clear (=0)
+ */
+static int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock)
+{
+	u8 hopcount = 0xff;
+	u16 destid = rdev->destid;
+	u32 regval;
+
+	if (rdev->rswitch) {
+		destid = rdev->rswitch->destid;
+		hopcount = rdev->rswitch->hopcount;
+	}
+
+	rio_mport_read_config_32(rdev->net->hport, destid, hopcount,
+				 rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum),
+				 &regval);
+	if (lock)
+		regval |= RIO_PORT_N_CTL_LOCKOUT;
+	else
+		regval &= ~RIO_PORT_N_CTL_LOCKOUT;
+
+	rio_mport_write_config_32(rdev->net->hport, destid, hopcount,
+				  rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum),
+				  regval);
+	return 0;
 }
 
 /**
@@ -659,8 +740,10 @@ static int __devinit rio_enum_peer(struc
 		    rio_name(rdev), rdev->vid, rdev->did, num_ports);
 		sw_destid = next_destid;
 		for (port_num = 0; port_num < num_ports; port_num++) {
-			if (sw_inport == port_num)
+			if (sw_inport == port_num) {
+				rdev->rswitch->port_ok |= (1 << port_num);
 				continue;
+			}
 
 			cur_destid = next_destid;
 
@@ -670,6 +753,7 @@ static int __devinit rio_enum_peer(struc
 				pr_debug(
 				    "RIO: scanning device on port %d\n",
 				    port_num);
+				rdev->rswitch->port_ok |= (1 << port_num);
 				rio_route_add_entry(port, rdev->rswitch,
 						RIO_GLOBAL_TABLE,
 						RIO_ANY_DESTID(port->sys_size),
@@ -693,9 +777,28 @@ static int __devinit rio_enum_peer(struc
 						    port_num;
 					}
 				}
+			} else {
+				/* If switch supports Error Management,
+				 * set PORT_LOCKOUT bit for unused port
+				 */
+				if (rdev->em_efptr)
+					rio_set_port_lockout(rdev, port_num, 1);
+
+				rdev->rswitch->port_ok &= ~(1 << port_num);
 			}
 		}
 
+		/* Direct Port-write messages to the enumeratiing host */
+		if ((rdev->src_ops & RIO_SRC_OPS_PORT_WRITE) &&
+		    (rdev->em_efptr)) {
+			rio_write_config_32(rdev,
+					rdev->em_efptr + RIO_EM_PW_TGT_DEVID,
+					(port->host_deviceid << 16) |
+					(port->sys_size << 15));
+		}
+
+		rio_init_em(rdev);
+
 		/* Check for empty switch */
 		if (next_destid == sw_destid) {
 			next_destid++;
@@ -715,21 +818,16 @@ static int __devinit rio_enum_peer(struc
  * rio_enum_complete- Tests if enumeration of a network is complete
  * @port: Master port to send transaction
  *
- * Tests the Component Tag CSR for presence of the magic enumeration
- * complete flag. Return %1 if enumeration is complete or %0 if
+ * Tests the Component Tag CSR for non-zero value (enumeration
+ * complete flag). Return %1 if enumeration is complete or %0 if
  * enumeration is incomplete.
  */
 static int rio_enum_complete(struct rio_mport *port)
 {
 	u32 tag_csr;
-	int ret = 0;
 
 	rio_local_read_config_32(port, RIO_COMPONENT_TAG_CSR, &tag_csr);
-
-	if (tag_csr == RIO_ENUM_CMPL_MAGIC)
-		ret = 1;
-
-	return ret;
+	return (tag_csr & 0xffff) ? 1 : 0;
 }
 
 /**
@@ -842,7 +940,7 @@ rio_disc_peer(struct rio_net *net, struc
  *
  * Reads the port error status CSR for the master port to
  * determine if the port has an active link.  Returns
- * %PORT_N_ERR_STS_PORT_OK if the  master port is active
+ * %RIO_PORT_N_ERR_STS_PORT_OK if the  master port is active
  * or %0 if it is inactive.
  */
 static int rio_mport_is_active(struct rio_mport *port)
@@ -863,7 +961,7 @@ static int rio_mport_is_active(struct ri
 					 RIO_PORT_N_ERR_STS_CSR(port->index),
 					 &result);
 
-	return (result & PORT_N_ERR_STS_PORT_OK);
+	return result & RIO_PORT_N_ERR_STS_PORT_OK;
 }
 
 /**
@@ -930,6 +1028,32 @@ static void rio_update_route_tables(stru
 }
 
 /**
+ * rio_init_em - Initializes RIO Error Management (for switches)
+ * @port: Master port associated with the RIO network
+ *
+ * For each enumerated switch, call device-specific error management
+ * initialization routine (if supplied by the switch driver).
+ */
+static void rio_init_em(struct rio_dev *rdev)
+{
+	if (rio_is_switch(rdev) && (rdev->em_efptr) &&
+	    (rdev->rswitch->em_init)) {
+		rdev->rswitch->em_init(rdev);
+	}
+}
+
+/**
+ * rio_pw_enable - Enables/disables port-write handling by a master port
+ * @port: Master port associated with port-write handling
+ * @enable:  1=enable,  0=disable
+ */
+static void rio_pw_enable(struct rio_mport *port, int enable)
+{
+	if (port->ops->pwenable)
+		port->ops->pwenable(port, enable);
+}
+
+/**
  * rio_enum_mport- Start enumeration through a master port
  * @mport: Master port to send transactions
  *
@@ -972,6 +1096,7 @@ int __devinit rio_enum_mport(struct rio_
 		}
 		rio_update_route_tables(mport);
 		rio_clear_locks(mport);
+		rio_pw_enable(mport, 1);
 	} else {
 		printk(KERN_INFO "RIO: master port %d link inactive\n",
 		       mport->id);
diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7a/drivers/rapidio/rio.c w33r7b/drivers/rapidio/rio.c
--- w33r7a/drivers/rapidio/rio.c	2010-02-09 15:11:09.147959000 -0500
+++ w33r7b/drivers/rapidio/rio.c	2010-02-11 15:04:35.829619000 -0500
@@ -5,6 +5,10 @@
  * Copyright 2005 MontaVista Software, Inc.
  * Matt Porter <mporter@kernel.crashing.org>
  *
+ * Copyright 2009 Integrated Device Technology, Inc.
+ * Alex Bounine <alexandre.bounine@idt.com>
+ * - Added Port-Write/Error Management initialization and handling
+ *
  * 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
@@ -333,6 +337,308 @@ int rio_release_outb_dbell(struct rio_de
 }
 
 /**
+ * rio_request_inb_pwrite - request inbound port-write message service
+ * @mport: RIO device to which register inbound port-write callback routine
+ * @pwcback: Callback routine to execute when port-write is received
+ *
+ * Binds a port-write callback function to the RapidIO device.
+ * Returns 0 if the request has been satisfied.
+ */
+int rio_request_inb_pwrite(struct rio_dev *rdev,
+		int (*pwcback)(struct rio_dev *rdev, u32* msg, int step))
+{
+	int rc = 0;
+
+	spin_lock(&rio_global_list_lock);
+	if (rdev->pwcback != NULL)
+		rc = -ENOMEM;
+	else
+		rdev->pwcback = pwcback;
+
+	spin_unlock(&rio_global_list_lock);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(rio_request_inb_pwrite);
+
+/**
+ * rio_release_inb_pwrite - release inbound port-write message service
+ * @rdev: RIO device which registered for inbound port-write callback
+ *
+ * Removes callback from the rio_dev structure. Returns 0 if the request
+ * has been satisfied.
+ */
+int rio_release_inb_pwrite(struct rio_dev *rdev)
+{
+	int rc = -ENOMEM;
+
+	spin_lock(&rio_global_list_lock);
+	if (rdev->pwcback) {
+		rdev->pwcback = NULL;
+		rc = 0;
+	}
+
+	spin_unlock(&rio_global_list_lock);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(rio_release_inb_pwrite);
+
+/**
+ * rio_mport_get_physefb - Helper function that returns register offset
+ *                      for Physical Layer Extended Features Block.
+ * @rdev: RIO device
+ */
+u32
+rio_mport_get_physefb(struct rio_mport *port, int local,
+		      u16 destid, u8 hopcount)
+{
+	u32 ext_ftr_ptr;
+	u32 ftr_header;
+
+	ext_ftr_ptr = rio_mport_get_efb(port, local, destid, hopcount, 0);
+
+	while (ext_ftr_ptr)  {
+		if (local)
+			rio_local_read_config_32(port, ext_ftr_ptr,
+						 &ftr_header);
+		else
+			rio_mport_read_config_32(port, destid, hopcount,
+						 ext_ftr_ptr, &ftr_header);
+
+		ftr_header = RIO_GET_BLOCK_ID(ftr_header);
+		switch (ftr_header) {
+
+		case RIO_EFB_SER_EP_ID_V13P:
+		case RIO_EFB_SER_EP_REC_ID_V13P:
+		case RIO_EFB_SER_EP_FREE_ID_V13P:
+		case RIO_EFB_SER_EP_ID:
+		case RIO_EFB_SER_EP_REC_ID:
+		case RIO_EFB_SER_EP_FREE_ID:
+		case RIO_EFB_SER_EP_FREC_ID:
+
+			return ext_ftr_ptr;
+
+		default:
+			break;
+		}
+
+		ext_ftr_ptr = rio_mport_get_efb(port, local, destid,
+						hopcount, ext_ftr_ptr);
+	}
+
+	return ext_ftr_ptr;
+}
+
+/**
+ * rio_get_comptag - Begin or continue searching for a RIO device by component tag
+ * @comp_tag: RIO component tad to match
+ * @from: Previous RIO device found in search, or %NULL for new search
+ *
+ * Iterates through the list of known RIO devices. If a RIO device is
+ * found with a matching @comp_tag, a pointer to its device
+ * structure is returned. Otherwise, %NULL is returned. A new search
+ * is initiated by passing %NULL to the @from argument. Otherwise, if
+ * @from is not %NULL, searches continue from next device on the global
+ * list.
+ */
+static struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from)
+{
+	struct list_head *n;
+	struct rio_dev *rdev;
+
+	WARN_ON(in_interrupt());
+	spin_lock(&rio_global_list_lock);
+	n = from ? from->global_list.next : rio_devices.next;
+
+	while (n && (n != &rio_devices)) {
+		rdev = rio_dev_g(n);
+		if (rdev->comp_tag == comp_tag)
+			goto exit;
+		n = n->next;
+	}
+	rdev = NULL;
+exit:
+	spin_unlock(&rio_global_list_lock);
+	return rdev;
+}
+
+/**
+ * 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)
+{
+	struct rio_dev *rdev;
+	struct rio_mport *mport;
+	u8 hopcount;
+	u16 destid;
+	u32 regval, err_status;
+	int rc, portnum;
+
+	rdev = rio_get_comptag(pw_msg[0], NULL);
+	if (rdev == NULL) {
+		/* Someting bad here (probably enumeration error) */
+		pr_err("RIO: %s No matching device for CTag 0x%08x\n",
+			__func__, pw_msg[0]);
+		return -EIO;
+	}
+
+	pr_debug("RIO: Port-Write message from %s\n", rio_name(rdev));
+
+#ifdef DEBUG_PW
+	{
+	u32 i;
+	pr_debug("%s : Port-Write Message:", __func__);
+	for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32); i++) {
+		if ((i%4) == 0)
+			pr_debug("\n0x%02x: 0x%08x", i, pw_msg[i]);
+		else
+			pr_debug(" 0x%08x", pw_msg[i]);
+	}
+	pr_debug("\n");
+	}
+#endif
+
+	/* Call an external service function (if such is registered
+	 * for this device). This may be the service for endpoints that send
+	 * device-specific port-write messages. End-point messages expected
+	 * to be handled completely by EP specific device driver.
+	 * For switches rc==0 signals that no standard processing required.
+	 */
+	if (rdev->pwcback != NULL) {
+		rc = rdev->pwcback(rdev, pw_msg, 0);
+		if (rc == 0)
+			return 0;
+	}
+
+	/* For End-point devices processing stops here */
+	if (!(rdev->pef & RIO_PEF_SWITCH))
+		return 0;
+
+	if (rdev->phys_efptr == 0) {
+		pr_err("RIO_PW: Bad switch initialization for %s\n",
+			rio_name(rdev));
+		return 0;
+	}
+
+	mport = rdev->net->hport;
+	destid = rdev->rswitch->destid;
+	hopcount = rdev->rswitch->hopcount;
+
+	/*
+	 * Process the port-write notification from switch
+	 */
+
+	portnum = pw_msg[2] & 0xFF;
+
+	if (rdev->rswitch->em_handle)
+		rdev->rswitch->em_handle(rdev, portnum);
+
+	rio_mport_read_config_32(mport, destid, hopcount,
+			rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
+			&err_status);
+	pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status);
+
+	if (pw_msg[1]) {
+		pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n",
+			 portnum, pw_msg[1]);
+		/* Clear EM Port N Error Detect CSR */
+		rio_mport_write_config_32(mport, destid, hopcount,
+			rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0);
+	}
+
+	if (pw_msg[3]) {
+		pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n", pw_msg[3]);
+		/* Clear EM L/T Layer Error Detect CSR */
+		rio_mport_write_config_32(mport, destid, hopcount,
+			rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0);
+	}
+
+	/* Clear Port Errors */
+	rio_mport_write_config_32(mport, destid, hopcount,
+			rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
+			err_status & 0x07120204);
+
+	if (rdev->rswitch->port_ok & (1 << portnum)) {
+		if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) {
+			rdev->rswitch->port_ok &= ~(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);
+
+			rio_mport_write_config_32(mport, destid, hopcount,
+				rdev->phys_efptr +
+					RIO_PORT_N_ACK_STS_CSR(portnum),
+				RIO_PORT_N_ACK_CLEAR);
+
+			/* Schedule Extraction Service */
+			pr_debug("RIO_PW: Device Extraction on [%s]-P%d\n",
+			       rio_name(rdev), portnum);
+		}
+	} else {
+		if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) {
+			rdev->rswitch->port_ok |= (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);
+
+			/* Schedule Insertion Service */
+			pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n",
+			       rio_name(rdev), portnum);
+		}
+	}
+
+	/* 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);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rio_inb_pwrite_handler);
+
+/**
+ * rio_mport_get_efb - get pointer to next extended features block
+ * @port: Master port to issue transaction
+ * @local: Indicate a local master port or remote device access
+ * @destid: Destination ID of the device
+ * @hopcount: Number of switch hops to the device
+ * @from: Offset of  current Extended Feature block header (if 0 starts
+ * from	ExtFeaturePtr)
+ */
+u32
+rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
+		      u8 hopcount, u32 from)
+{
+	u32 reg_val;
+
+	if (from == 0) {
+		if (local)
+			rio_local_read_config_32(port, RIO_ASM_INFO_CAR,
+						 &reg_val);
+		else
+			rio_mport_read_config_32(port, destid, hopcount,
+						 RIO_ASM_INFO_CAR, &reg_val);
+		return reg_val & RIO_EXT_FTR_PTR_MASK;
+	} else {
+		if (local)
+			rio_local_read_config_32(port, from, &reg_val);
+		else
+			rio_mport_read_config_32(port, destid, hopcount,
+						 from, &reg_val);
+		return RIO_GET_BLOCK_ID(reg_val);
+	}
+}
+
+/**
  * rio_mport_get_feature - query for devices' extended features
  * @port: Master port to issue transaction
  * @local: Indicate a local master port or remote device access
@@ -472,6 +778,7 @@ int rio_std_route_add_entry(struct rio_m
 				RIO_STD_RTE_CONF_PORT_SEL_CSR,
 				(u32)route_port);
 	}
+
 	udelay(10);
 	return 0;
 }
diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7a/drivers/rapidio/rio.h w33r7b/drivers/rapidio/rio.h
--- w33r7a/drivers/rapidio/rio.h	2010-02-09 15:11:09.150956000 -0500
+++ w33r7b/drivers/rapidio/rio.h	2010-02-11 15:07:47.861045000 -0500
@@ -18,6 +18,10 @@
 
 extern u32 rio_mport_get_feature(struct rio_mport *mport, int local, u16 destid,
 				 u8 hopcount, int ftr);
+extern u32 rio_mport_get_physefb(struct rio_mport *port, int local,
+				 u16 destid, u8 hopcount);
+extern u32 rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
+			     u8 hopcount, u32 from);
 extern int rio_create_sysfs_dev_files(struct rio_dev *rdev);
 extern int rio_enum_mport(struct rio_mport *mport);
 extern int rio_disc_mport(struct rio_mport *mport);
@@ -61,3 +65,28 @@ extern struct rio_route_ops __end_rio_ro
 
 #define RIO_GET_DID(size, x)	(size ? (x & 0xffff) : ((x & 0x00ff0000) >> 16))
 #define RIO_SET_DID(size, x)	(size ? (x & 0xffff) : ((x & 0x000000ff) << 16))
+
+/*
+ *   RapidIO Error Management
+ */
+extern struct rio_em_ops __start_rio_em_ops[];
+extern struct rio_em_ops __end_rio_em_ops[];
+
+/* Helpers internal to the RIO core code */
+#define DECLARE_RIO_EM_SECTION(section, name, vid, did, init_hook, em_hook)  \
+	static const struct rio_em_ops __rio_em_##name __used   \
+	__section(section) = { vid, did, init_hook, em_hook };
+
+/**
+ * DECLARE_RIO_EM_OPS - Registers switch EM operations
+ * @vid: RIO vendor ID
+ * @did: RIO device ID
+ * @init_hook: Callback that initializes device specific EM
+ * @em_hook: Callback that handles device specific EM
+ *
+ * A &struct rio_em_ops is initialized with the ops and placed into a
+ * RIO-specific kernel section.
+ */
+#define DECLARE_RIO_EM_OPS(vid, did, init_hook, em_hook)	\
+	DECLARE_RIO_EM_SECTION(.rio_em_ops, vid##did,		\
+			vid, did, init_hook, em_hook)
diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7a/drivers/rapidio/switches/tsi568.c w33r7b/drivers/rapidio/switches/tsi568.c
--- w33r7a/drivers/rapidio/switches/tsi568.c	2010-02-09 15:11:09.201908000 -0500
+++ w33r7b/drivers/rapidio/switches/tsi568.c	2010-02-11 11:04:15.904955000 -0500
@@ -25,6 +25,9 @@
 #define SPP_ROUTE_CFG_DESTID(n)	(0x11070 + 0x100*n)
 #define SPP_ROUTE_CFG_PORT(n)	(0x11074 + 0x100*n)
 
+#define TSI568_SP_MODE_BC	0x10004
+#define  TSI568_SP_MODE_PW_DIS	0x08000000
+
 static int
 tsi568_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
 		       u16 table, u16 route_destid, u8 route_port)
@@ -104,3 +107,24 @@ tsi568_route_clr_table(struct rio_mport 
 }
 
 DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI568, tsi568_route_add_entry, tsi568_route_get_entry, tsi568_route_clr_table);
+
+static int
+tsi568_em_init(struct rio_dev *rdev)
+{
+	struct rio_mport *mport = rdev->net->hport;
+	u16 destid = rdev->rswitch->destid;
+	u8 hopcount = rdev->rswitch->hopcount;
+	u32 regval;
+
+	pr_debug("TSI568 %s [%d:%d]\n", __func__, destid, hopcount);
+
+	/* Make sure that Port-Writes are disabled (for all ports) */
+	rio_mport_read_config_32(mport, destid, hopcount,
+			TSI568_SP_MODE_BC, &regval);
+	rio_mport_write_config_32(mport, destid, hopcount,
+			TSI568_SP_MODE_BC, regval | TSI568_SP_MODE_PW_DIS);
+
+	return 0;
+}
+
+DECLARE_RIO_EM_OPS(RIO_VID_TUNDRA, RIO_DID_TSI568, tsi568_em_init, NULL);
diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7a/drivers/rapidio/switches/tsi57x.c w33r7b/drivers/rapidio/switches/tsi57x.c
--- w33r7a/drivers/rapidio/switches/tsi57x.c	2010-02-09 15:11:09.207894000 -0500
+++ w33r7b/drivers/rapidio/switches/tsi57x.c	2010-02-11 15:17:26.949248000 -0500
@@ -25,6 +25,14 @@
 #define SPP_ROUTE_CFG_DESTID(n)	(0x11070 + 0x100*n)
 #define SPP_ROUTE_CFG_PORT(n)	(0x11074 + 0x100*n)
 
+#define TSI578_SP_MODE(n)	(0x11004 + n*0x100)
+#define  TSI578_SP_MODE_PW_DIS	0x08000000
+
+#define TSI578_SP_CTL_INDEP(n)	(0x13004 + n*0x100)
+#define TSI578_SP_LUT_PEINF(n)	(0x13010 + n*0x100)
+#define TSI578_SP_CS_TX(n)	(0x13014 + n*0x100)
+#define TSI578_SP_INT_STATUS(n) (0x13018 + n*0x100)
+
 static int
 tsi57x_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
 		       u16 table, u16 route_destid, u8 route_port)
@@ -104,3 +112,148 @@ DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RI
 DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI574, tsi57x_route_add_entry, tsi57x_route_get_entry, tsi57x_route_clr_table);
 DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI577, tsi57x_route_add_entry, tsi57x_route_get_entry, tsi57x_route_clr_table);
 DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI578, tsi57x_route_add_entry, tsi57x_route_get_entry, tsi57x_route_clr_table);
+
+static int
+tsi57x_em_init(struct rio_dev *rdev)
+{
+	struct rio_mport *mport = rdev->net->hport;
+	u16 destid = rdev->rswitch->destid;
+	u8 hopcount = rdev->rswitch->hopcount;
+	u32 regval;
+	int portnum;
+
+	pr_debug("TSI578 %s [%d:%d]\n", __func__, destid, hopcount);
+
+	for (portnum = 0; portnum < 16; portnum++) {
+		/* Make sure that Port-Writes are enabled (for all ports) */
+		rio_mport_read_config_32(mport, destid, hopcount,
+				TSI578_SP_MODE(portnum), &regval);
+		rio_mport_write_config_32(mport, destid, hopcount,
+				TSI578_SP_MODE(portnum),
+				regval & ~TSI578_SP_MODE_PW_DIS);
+
+		/* Clear all pending interrupts */
+		rio_mport_read_config_32(mport, destid, hopcount,
+				rdev->phys_efptr +
+					RIO_PORT_N_ERR_STS_CSR(portnum),
+				&regval);
+		rio_mport_write_config_32(mport, destid, hopcount,
+				rdev->phys_efptr +
+					RIO_PORT_N_ERR_STS_CSR(portnum),
+				regval & 0x07120214);
+
+		rio_mport_read_config_32(mport, destid, hopcount,
+				TSI578_SP_INT_STATUS(portnum), &regval);
+		rio_mport_write_config_32(mport, destid, hopcount,
+				TSI578_SP_INT_STATUS(portnum),
+				regval & 0x000700bd);
+
+		/* Enable all interrupts to allow ports to send a port-write */
+		rio_mport_read_config_32(mport, destid, hopcount,
+				TSI578_SP_CTL_INDEP(portnum), &regval);
+		rio_mport_write_config_32(mport, destid, hopcount,
+				TSI578_SP_CTL_INDEP(portnum),
+				regval | 0x000b0000);
+
+		/* Skip next (odd) port if the current port is in x4 mode */
+		rio_mport_read_config_32(mport, destid, hopcount,
+				rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
+				&regval);
+		if ((regval & RIO_PORT_N_CTL_PWIDTH) == RIO_PORT_N_CTL_PWIDTH_4)
+			portnum++;
+	}
+
+	return 0;
+}
+
+static int
+tsi57x_em_handler(struct rio_dev *rdev, u8 portnum)
+{
+	struct rio_mport *mport = rdev->net->hport;
+	u16 destid = rdev->rswitch->destid;
+	u8 hopcount = rdev->rswitch->hopcount;
+	u32 intstat, err_status;
+	int sendcount, checkcount;
+	u8 route_port;
+	u32 regval;
+
+	rio_mport_read_config_32(mport, destid, hopcount,
+			rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
+			&err_status);
+
+	if ((err_status & RIO_PORT_N_ERR_STS_PORT_OK) &&
+	    (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
+			  RIO_PORT_N_ERR_STS_PW_INP_ES))) {
+		/* Remove any queued packets by locking/unlocking port */
+		rio_mport_read_config_32(mport, destid, hopcount,
+			rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
+			&regval);
+		if (!(regval & RIO_PORT_N_CTL_LOCKOUT)) {
+			rio_mport_write_config_32(mport, destid, hopcount,
+				rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
+				regval | RIO_PORT_N_CTL_LOCKOUT);
+			udelay(50);
+			rio_mport_write_config_32(mport, destid, hopcount,
+				rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
+				regval);
+		}
+
+		/* Read from link maintenance response register to clear
+		 * valid bit
+		 */
+		rio_mport_read_config_32(mport, destid, hopcount,
+			rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(portnum),
+			&regval);
+
+		/* Send a Packet-Not-Accepted/Link-Request-Input-Status control
+		 * symbol to recover from IES/OES
+		 */
+		sendcount = 3;
+		while (sendcount) {
+			rio_mport_write_config_32(mport, destid, hopcount,
+					  TSI578_SP_CS_TX(portnum), 0x40fc8000);
+			checkcount = 3;
+			while (checkcount--) {
+				udelay(50);
+				rio_mport_read_config_32(
+					mport, destid, hopcount,
+					rdev->phys_efptr +
+						RIO_PORT_N_MNT_RSP_CSR(portnum),
+					&regval);
+				if (regval & RIO_PORT_N_MNT_RSP_RVAL)
+					goto exit_es;
+			}
+
+			sendcount--;
+		}
+	}
+
+exit_es:
+	/* Clear implementation specific error status bits */
+	rio_mport_read_config_32(mport, destid, hopcount,
+				 TSI578_SP_INT_STATUS(portnum), &intstat);
+	pr_debug("TSI578[%x:%x] SP%d_INT_STATUS=0x%08x\n",
+		 destid, hopcount, portnum, intstat);
+
+	if (intstat & 0x10000) {
+		rio_mport_read_config_32(mport, destid, hopcount,
+				TSI578_SP_LUT_PEINF(portnum), &regval);
+		regval = (mport->sys_size) ? (regval >> 16) : (regval >> 24);
+		route_port = rdev->rswitch->route_table[regval];
+		pr_debug("RIO: TSI578[%s] P%d LUT Parity Error (destID=%d)\n",
+			rio_name(rdev), portnum, regval);
+		tsi57x_route_add_entry(mport, destid, hopcount,
+				RIO_GLOBAL_TABLE, regval, route_port);
+	}
+
+	rio_mport_write_config_32(mport, destid, hopcount,
+				  TSI578_SP_INT_STATUS(portnum),
+				  intstat & 0x000700bd);
+
+	return 0;
+}
+
+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);
diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7a/include/asm-generic/vmlinux.lds.h w33r7b/include/asm-generic/vmlinux.lds.h
--- w33r7a/include/asm-generic/vmlinux.lds.h	2010-02-06 17:17:12.000000000 -0500
+++ w33r7b/include/asm-generic/vmlinux.lds.h	2010-02-10 17:02:30.541567000 -0500
@@ -247,10 +247,13 @@
 	}								\
 									\
 	/* RapidIO route ops */						\
-	.rio_route        : AT(ADDR(.rio_route) - LOAD_OFFSET) {	\
+	.rio_ops        : AT(ADDR(.rio_ops) - LOAD_OFFSET) {		\
 		VMLINUX_SYMBOL(__start_rio_route_ops) = .;		\
 		*(.rio_route_ops)					\
 		VMLINUX_SYMBOL(__end_rio_route_ops) = .;		\
+		VMLINUX_SYMBOL(__start_rio_em_ops) = .;			\
+		*(.rio_em_ops)						\
+		VMLINUX_SYMBOL(__end_rio_em_ops) = .;			\
 	}								\
 									\
 	TRACEDATA							\
diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7a/include/linux/rio.h w33r7b/include/linux/rio.h
--- w33r7a/include/linux/rio.h	2010-02-09 15:11:09.280832000 -0500
+++ w33r7b/include/linux/rio.h	2010-02-11 13:07:33.147325000 -0500
@@ -64,6 +64,8 @@
 #define RIO_INB_MBOX_RESOURCE	1
 #define RIO_OUTB_MBOX_RESOURCE	2
 
+#define RIO_PW_MSG_SIZE		64
+
 extern struct bus_type rio_bus_type;
 extern struct list_head rio_devices;	/* list of all devices */
 
@@ -107,11 +109,15 @@ struct rio_dev {
 	u32 swpinfo;		/* Only used for switches */
 	u32 src_ops;
 	u32 dst_ops;
+	u32 comp_tag;
+	u32 phys_efptr;
+	u32 em_efptr;
 	u64 dma_mask;
 	struct rio_switch *rswitch;	/* RIO switch info */
 	struct rio_driver *driver;	/* RIO driver claiming this device */
 	struct device dev;	/* LDM device structure */
 	struct resource riores[RIO_MAX_DEV_RESOURCES];
+	int (*pwcback) (struct rio_dev *rdev, u32* msg, int step);
 	u16 destid;
 };
 
@@ -211,9 +217,12 @@ struct rio_net {
  * @hopcount: Hopcount to this switch
  * @destid: Associated destid in the path
  * @route_table: Copy of switch routing table
+ * @port_ok: Status of each port (one bit per port) - OK=1 or UNINIT=0
  * @add_entry: Callback for switch-specific route add function
  * @get_entry: Callback for switch-specific route get function
  * @clr_table: Callback for switch-specific clear route table function
+ * @em_init: Callback for switch-specific error management initialization function
+ * @em_handle: Callback for switch-specific error management handler function
  */
 struct rio_switch {
 	struct list_head node;
@@ -221,12 +230,15 @@ struct rio_switch {
 	u16 hopcount;
 	u16 destid;
 	u8 *route_table;
+	u32 port_ok;
 	int (*add_entry) (struct rio_mport * mport, u16 destid, u8 hopcount,
 			  u16 table, u16 route_destid, u8 route_port);
 	int (*get_entry) (struct rio_mport * mport, u16 destid, u8 hopcount,
 			  u16 table, u16 route_destid, u8 * route_port);
 	int (*clr_table) (struct rio_mport *mport, u16 destid, u8 hopcount,
 			  u16 table);
+	int (*em_init) (struct rio_dev *dev);
+	int (*em_handle) (struct rio_dev *dev, u8 swport);
 };
 
 /* Low-level architecture-dependent routines */
@@ -238,6 +250,7 @@ struct rio_switch {
  * @cread: Callback to perform network read of config space.
  * @cwrite: Callback to perform network write of config space.
  * @dsend: Callback to send a doorbell message.
+ * @pwenable: Callback to enable/disable port-write message handling.
  */
 struct rio_ops {
 	int (*lcread) (struct rio_mport *mport, int index, u32 offset, int len,
@@ -249,6 +262,7 @@ struct rio_ops {
 	int (*cwrite) (struct rio_mport *mport, int index, u16 destid,
 			u8 hopcount, u32 offset, int len, u32 data);
 	int (*dsend) (struct rio_mport *mport, int index, u16 destid, u16 data);
+	int (*pwenable) (struct rio_mport *mport, int enable);
 };
 
 #define RIO_RESOURCE_MEM	0x00000100
@@ -325,6 +339,22 @@ struct rio_route_ops {
 			 u16 table);
 };
 
+/**
+ * struct rio_em_ops - Per-switch error management operations
+ * @vid: RIO vendor ID
+ * @did: RIO device ID
+ * @init_hook: Switch specific error management initialization (may be NULL)
+ * @handler_hook: Switch specific error management handler (may be NULL)
+ *
+ * Defines the operations that are necessary to initialize and handle
+ * error management events for a particular RIO switch device.
+ */
+struct rio_em_ops {
+	u16 vid, did;
+	int (*init_hook) (struct rio_dev *dev);
+	int (*handler_hook) (struct rio_dev *dev, u8 swport);
+};
+
 /* Architecture and hardware-specific functions */
 extern int rio_init_mports(void);
 extern void rio_register_mport(struct rio_mport *);
diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7a/include/linux/rio_drv.h w33r7b/include/linux/rio_drv.h
--- w33r7a/include/linux/rio_drv.h	2010-02-06 17:17:12.000000000 -0500
+++ w33r7b/include/linux/rio_drv.h	2010-02-10 17:02:30.630559000 -0500
@@ -413,6 +413,12 @@ void rio_release_regions(struct rio_dev 
 int rio_request_region(struct rio_dev *, int, char *);
 void rio_release_region(struct rio_dev *, int);
 
+/* Port-Write management */
+extern int rio_request_inb_pwrite(struct rio_dev *,
+				  int (*)(struct rio_dev *, u32*, int));
+extern int rio_release_inb_pwrite(struct rio_dev *);
+extern int rio_inb_pwrite_handler(u32 *pw_msg);
+
 /* LDM support */
 int rio_register_driver(struct rio_driver *);
 void rio_unregister_driver(struct rio_driver *);
diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7a/include/linux/rio_regs.h w33r7b/include/linux/rio_regs.h
--- w33r7a/include/linux/rio_regs.h	2010-02-09 15:11:09.318794000 -0500
+++ w33r7b/include/linux/rio_regs.h	2010-02-11 13:11:02.420875000 -0500
@@ -192,10 +192,14 @@
 #define RIO_EFB_PAR_EP_ID	0x0001	/* [IV] LP/LVDS EP Devices */
 #define RIO_EFB_PAR_EP_REC_ID	0x0002	/* [IV] LP/LVDS EP Recovery Devices */
 #define RIO_EFB_PAR_EP_FREE_ID	0x0003	/* [IV] LP/LVDS EP Free Devices */
+#define RIO_EFB_SER_EP_ID_V13P	0x0001	/* [VI] LP/Serial EP Devices, RapidIO Spec ver 1.3 and above */
+#define RIO_EFB_SER_EP_REC_ID_V13P	0x0002	/* [VI] LP/Serial EP Recovery Devices, RapidIO Spec ver 1.3 and above */
+#define RIO_EFB_SER_EP_FREE_ID_V13P	0x0003	/* [VI] LP/Serial EP Free Devices, RapidIO Spec ver 1.3 and above */
 #define RIO_EFB_SER_EP_ID	0x0004	/* [VI] LP/Serial EP Devices */
 #define RIO_EFB_SER_EP_REC_ID	0x0005	/* [VI] LP/Serial EP Recovery Devices */
 #define RIO_EFB_SER_EP_FREE_ID	0x0006	/* [VI] LP/Serial EP Free Devices */
 #define RIO_EFB_SER_EP_FREC_ID	0x0009  /* [VI] LP/Serial EP Free Recovery Devices */
+#define RIO_EFB_ERR_MGMNT	0x0007  /* [VIII] Error Management Extensions */
 
 /*
  * Physical 8/16 LP-LVDS
@@ -211,15 +215,65 @@
 #define RIO_PORT_MNT_HEADER		0x0000
 #define RIO_PORT_REQ_CTL_CSR		0x0020
 #define RIO_PORT_RSP_CTL_CSR		0x0024	/* 0x0001/0x0002 */
+#define RIO_PORT_LINKTO_CTL_CSR		0x0020	/* Serial */
+#define RIO_PORT_RSPTO_CTL_CSR		0x0024	/* Serial */
 #define RIO_PORT_GEN_CTL_CSR		0x003c
 #define  RIO_PORT_GEN_HOST		0x80000000
 #define  RIO_PORT_GEN_MASTER		0x40000000
 #define  RIO_PORT_GEN_DISCOVERED	0x20000000
 #define RIO_PORT_N_MNT_REQ_CSR(x)	(0x0040 + x*0x20)	/* 0x0002 */
 #define RIO_PORT_N_MNT_RSP_CSR(x)	(0x0044 + x*0x20)	/* 0x0002 */
+#define  RIO_PORT_N_MNT_RSP_RVAL	0x80000000 /* Response Valid */
+#define  RIO_PORT_N_MNT_RSP_ASTAT	0x000003e0 /* ackID Status */
+#define  RIO_PORT_N_MNT_RSP_LSTAT	0x0000001f /* Link Status */
 #define RIO_PORT_N_ACK_STS_CSR(x)	(0x0048 + x*0x20)	/* 0x0002 */
-#define RIO_PORT_N_ERR_STS_CSR(x)	(0x58 + x*0x20)
-#define PORT_N_ERR_STS_PORT_OK	0x00000002
-#define RIO_PORT_N_CTL_CSR(x)		(0x5c + x*0x20)
+#define  RIO_PORT_N_ACK_CLEAR		0x80000000
+#define  RIO_PORT_N_ACK_INBOUND		0x1f000000
+#define  RIO_PORT_N_ACK_OUTSTAND	0x00001f00
+#define  RIO_PORT_N_ACK_OUTBOUND	0x0000001f
+#define RIO_PORT_N_ERR_STS_CSR(x)	(0x0058 + x*0x20)
+#define  RIO_PORT_N_ERR_STS_PW_OUT_ES	0x00010000 /* Output Error-stopped */
+#define  RIO_PORT_N_ERR_STS_PW_INP_ES	0x00000100 /* Input Error-stopped */
+#define  RIO_PORT_N_ERR_STS_PW_PEND	0x00000010 /* Port-Write Pending */
+#define  RIO_PORT_N_ERR_STS_PORT_ERR	0x00000004
+#define  RIO_PORT_N_ERR_STS_PORT_OK	0x00000002
+#define  RIO_PORT_N_ERR_STS_PORT_UNINIT	0x00000001
+#define RIO_PORT_N_CTL_CSR(x)		(0x005c + x*0x20)
+#define  RIO_PORT_N_CTL_PWIDTH		0xc0000000
+#define  RIO_PORT_N_CTL_PWIDTH_1	0x00000000
+#define  RIO_PORT_N_CTL_PWIDTH_4	0x40000000
+#define  RIO_PORT_N_CTL_LOCKOUT		0x00000002
+
+/*
+ * Error Management Extensions (RapidIO 1.3+, Part 8)
+ *
+ * Extended Features Block ID=0x0007
+ */
+
+/* General EM Registers (Common for all Ports) */
+
+#define RIO_EM_EFB_HEADER	0x000	/* Error Management Extensions Block Header */
+#define RIO_EM_LTL_ERR_DETECT	0x008	/* Logical/Transport Layer Error Detect CSR */
+#define RIO_EM_LTL_ERR_EN	0x00c	/* Logical/Transport Layer Error Enable CSR */
+#define RIO_EM_LTL_HIADDR_CAP	0x010	/* Logical/Transport Layer High Address Capture CSR */
+#define RIO_EM_LTL_ADDR_CAP	0x014	/* Logical/Transport Layer Address Capture CSR */
+#define RIO_EM_LTL_DEVID_CAP	0x018	/* Logical/Transport Layer Device ID Capture CSR */
+#define RIO_EM_LTL_CTRL_CAP	0x01c	/* Logical/Transport Layer Control Capture CSR */
+#define RIO_EM_PW_TGT_DEVID	0x028	/* Port-write Target deviceID CSR */
+#define RIO_EM_PKT_TTL		0x02c	/* Packet Time-to-live CSR */
+
+/* Per-Port EM Registers */
+
+#define RIO_EM_PN_ERR_DETECT(x)	(0x040 + x*0x40) /* Port N Error Detect CSR */
+#define  REM_PED_IMPL_SPEC		0x80000000
+#define  REM_PED_LINK_TO		0x00000001
+#define RIO_EM_PN_ERRRATE_EN(x) (0x044 + x*0x40) /* Port N Error Rate Enable CSR */
+#define RIO_EM_PN_ATTRIB_CAP(x)	(0x048 + x*0x40) /* Port N Attributes Capture CSR */
+#define RIO_EM_PN_PKT_CAP_0(x)	(0x04c + x*0x40) /* Port N Packet/Control Symbol Capture 0 CSR */
+#define RIO_EM_PN_PKT_CAP_1(x)	(0x050 + x*0x40) /* Port N Packet Capture 1 CSR */
+#define RIO_EM_PN_PKT_CAP_2(x)	(0x054 + x*0x40) /* Port N Packet Capture 2 CSR */
+#define RIO_EM_PN_PKT_CAP_3(x)	(0x058 + x*0x40) /* Port N Packet Capture 3 CSR */
+#define RIO_EM_PN_ERRRATE(x)	(0x068 + x*0x40) /* Port N Error Rate CSR */
+#define RIO_EM_PN_ERRRATE_TR(x) (0x06c + x*0x40) /* Port N Error Rate Threshold CSR */
 
 #endif				/* LINUX_RIO_REGS_H */

---

Important Notice: This message is intended for the use of the individual to whom it is addressed and may contain information which is privileged, confidential and/or exempt from disclosure under applicable law. If the reader of this message is not the intended recipient, or is not the employee or agent responsible for delivering the message to the intended recipient, you are hereby notified that any dissemination, distribution, or copying of this communication is strictly prohibited. If you have received this communication in error, please notify the sender immediately by telephone or return e-mail and delete the original message from your systems. Thank you. 

^ permalink raw reply

* Re: Please pull mpc5xxx support for -next
From: Grant Likely @ 2010-02-24 15:21 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, linuxppc-dev; +Cc: Ernst Schwab, Anatolij Gustschin
In-Reply-To: <fa686aa41002172237l1d3976avc7f88fd38755ca5e@mail.gmail.com>

Hi Ben,

Just sending a reminder on this pull request.  I haven't seen these
commits show up in your -next branch yet.

Thanks,
g.

On Wed, Feb 17, 2010 at 11:37 PM, Grant Likely
<grant.likely@secretlab.ca> wrote:
> Hi Ben,
>
> Here's all the stuff I've got queued up for 2.6.34. =A0Mostly mpc5121
> support, but some 5200 stuff too. =A0These commits have already had some
> time in linux-next.
>
> Cheers,
> g.
>
> The following changes since commit 724e6d3fe8003c3f60bf404bf22e4e331327c5=
96:
> =A0Linus Torvalds (1):
> =A0 =A0 =A0 =A0Linux 2.6.33-rc8
>
> are available in the git repository at:
>
> =A0git://git.secretlab.ca/git/linux-2.6.git next
>
> Anatolij Gustschin (10):
> =A0 =A0 =A0powerpc/mpc5121: avoid using arch_initcall for clock init
> =A0 =A0 =A0powerpc/mpc5121: Add machine restart support
> =A0 =A0 =A0rtc: Add MPC5121 Real time clock driver
> =A0 =A0 =A0powerpc/mpc5121: create and register NFC device
> =A0 =A0 =A0powerpc/mpc5121: update mpc5121ads DTS
> =A0 =A0 =A0powerpc/mpc5121: Add default config for MPC5121
> =A0 =A0 =A0serial: mpc52xx_uart: re-enable mpc5121 PSC UART support
> =A0 =A0 =A0powerpc: doc/dts-bindings: document mpc5121 psc uart dts-bindi=
ngs
> =A0 =A0 =A0powerpc/mpc5121: enable support for more PSC UARTs
> =A0 =A0 =A0powerpc/mpc5121: correct DIU compatible property
>
> Ernst Schwab (1):
> =A0 =A0 =A0powerpc/of: added documentation for spi chipselects
>
> =A0.../powerpc/dts-bindings/fsl/mpc5121-psc.txt =A0 =A0 =A0 | =A0 70 +
> =A0Documentation/powerpc/dts-bindings/fsl/spi.txt =A0 =A0 | =A0 =A07 +
> =A0arch/powerpc/boot/dts/mpc5121ads.dts =A0 =A0 =A0 =A0 =A0 =A0 =A0 | =A0=
 55 +-
> =A0arch/powerpc/configs/mpc512x_defconfig =A0 =A0 =A0 =A0 =A0 =A0 | 1694 =
++++++++++++++++++++
> =A0arch/powerpc/include/asm/mpc5121.h =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 | =
=A0 24 +
> =A0arch/powerpc/include/asm/mpc52xx_psc.h =A0 =A0 =A0 =A0 =A0 =A0 | =A0 =
=A04 +
> =A0arch/powerpc/platforms/512x/clock.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| =
=A0 =A06 +-
> =A0arch/powerpc/platforms/512x/mpc5121_ads.c =A0 =A0 =A0 =A0 =A0| =A0 =A0=
3 +-
> =A0arch/powerpc/platforms/512x/mpc5121_generic.c =A0 =A0 =A0| =A0 =A03 +-
> =A0arch/powerpc/platforms/512x/mpc512x.h =A0 =A0 =A0 =A0 =A0 =A0 =A0| =A0=
 =A03 +
> =A0arch/powerpc/platforms/512x/mpc512x_shared.c =A0 =A0 =A0 | =A0 43 +
> =A0drivers/rtc/Kconfig =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0| =A0 10 +
> =A0drivers/rtc/Makefile =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 | =A0 =A01 +
> =A0drivers/rtc/rtc-mpc5121.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0| =A0387 +++++
> =A0drivers/serial/mpc52xx_uart.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0| =A0251 +++-
> =A0drivers/video/fsl-diu-fb.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 | =A0 =A05 +
> =A016 files changed, 2522 insertions(+), 44 deletions(-)
> =A0create mode 100644 Documentation/powerpc/dts-bindings/fsl/mpc5121-psc.=
txt
> =A0create mode 100644 arch/powerpc/configs/mpc512x_defconfig
> =A0create mode 100644 arch/powerpc/include/asm/mpc5121.h
> =A0create mode 100644 drivers/rtc/rtc-mpc5121.c
>
>
> --
> Grant Likely, B.Sc., P.Eng.
> Secret Lab Technologies Ltd.
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* [PATCH 2/7] RapidIO: Add switch locking during discovery
From: Alexandre Bounine @ 2010-02-24 15:20 UTC (permalink / raw)
  To: mporter; +Cc: abounine, linuxppc-dev, linux-kernel, thomas.moll.ext,
	thomas.moll


From: Alexandre Bounine <alexandre.bounine@idt.com>

Add switch access locking during RapidIO discovery. Access lock is
required when reading switch routing table contents due to indexed mechanism
of RT addressing.

Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com>
Tested-by: Thomas Moll <thomas.moll@sysgo.com>
---

 rio-scan.c |   88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 79 insertions(+), 9 deletions(-)

diff -x '*.pj' -X dontdiff_2.6.32-rc5 -pNur w33r7a/drivers/rapidio/rio-scan.c w33r7b/drivers/rapidio/rio-scan.c
--- w33r7a/drivers/rapidio/rio-scan.c	2010-02-09 15:11:09.141972000 -0500
+++ w33r7b/drivers/rapidio/rio-scan.c	2010-02-10 16:13:56.382802000 -0500
@@ -750,6 +750,7 @@ rio_disc_peer(struct rio_net *net, struc
 	int num_ports;
 	struct rio_dev *rdev;
 	u16 ndestid;
+	u32 result;
 
 	/* Setup new RIO device */
 	if ((rdev = rio_setup_device(net, port, destid, hopcount, 0))) {
@@ -778,6 +779,27 @@ rio_disc_peer(struct rio_net *net, struc
 				pr_debug(
 				    "RIO: scanning device on port %d\n",
 				    port_num);
+
+				/* Attempt to acquire device lock */
+				rio_mport_write_config_32(port, destid,
+							  hopcount,
+							  RIO_HOST_DID_LOCK_CSR,
+							  port->host_deviceid);
+				rio_mport_read_config_32(port, destid, hopcount,
+					RIO_HOST_DID_LOCK_CSR, &result);
+				while (result != port->host_deviceid) {
+					/* Delay a bit */
+					mdelay(1);
+					/* Try to acquire device lock again */
+					rio_mport_write_config_32(port, destid,
+						hopcount,
+						RIO_HOST_DID_LOCK_CSR,
+						port->host_deviceid);
+					rio_mport_read_config_32(port, destid,
+						hopcount,
+						RIO_HOST_DID_LOCK_CSR, &result);
+				}
+
 				for (ndestid = 0;
 				     ndestid < RIO_ANY_DESTID(port->sys_size);
 				     ndestid++) {
@@ -789,6 +811,19 @@ rio_disc_peer(struct rio_net *net, struc
 						break;
 				}
 
+				/* Release device lock */
+				rio_mport_write_config_32(port, destid,
+							  hopcount,
+							  RIO_HOST_DID_LOCK_CSR,
+							  port->host_deviceid);
+				rio_mport_read_config_32(port, destid, hopcount,
+					RIO_HOST_DID_LOCK_CSR, &result);
+				if ((result & 0xffff) != 0xffff) {
+					pr_info("RIO: badness when releasing " \
+						"host lock on %s\n",
+						rio_name(rdev));
+				}
+
 				if (rio_disc_peer
 				    (net, port, ndestid, hopcount + 1) < 0)
 					return -1;
@@ -958,17 +993,45 @@ static void rio_build_route_tables(void)
 	struct rio_dev *rdev;
 	int i;
 	u8 sport;
+	u32 result;
 
 	list_for_each_entry(rdev, &rio_devices, global_list)
-	    if (rio_is_switch(rdev))
-		for (i = 0;
-		     i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
-		     i++) {
-			if (rio_route_get_entry
-			    (rdev->net->hport, rdev->rswitch, RIO_GLOBAL_TABLE,
-			     i, &sport) < 0)
-				continue;
-			rdev->rswitch->route_table[i] = sport;
+		if (rio_is_switch(rdev)) {
+			/* Attempt to acquire device lock */
+			rio_write_config_32(rdev, RIO_HOST_DID_LOCK_CSR,
+					rdev->net->hport->host_deviceid);
+			rio_read_config_32(rdev,
+					RIO_HOST_DID_LOCK_CSR, &result);
+			while (result != rdev->net->hport->host_deviceid) {
+				/* Delay a bit */
+				mdelay(1);
+				/* Attempt to acquire device lock again */
+				rio_write_config_32(rdev, RIO_HOST_DID_LOCK_CSR,
+					rdev->net->hport->host_deviceid);
+				rio_read_config_32(rdev,
+					RIO_HOST_DID_LOCK_CSR, &result);
+			}
+
+			for (i = 0;
+			     i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
+			     i++) {
+				if (rio_route_get_entry
+				    (rdev->net->hport, rdev->rswitch,
+				     RIO_GLOBAL_TABLE, i, &sport) < 0)
+					continue;
+				rdev->rswitch->route_table[i] = sport;
+			}
+
+			/* Release device lock */
+			rio_write_config_32(rdev, RIO_HOST_DID_LOCK_CSR,
+					rdev->net->hport->host_deviceid);
+			rio_read_config_32(rdev,
+					RIO_HOST_DID_LOCK_CSR, &result);
+			if ((result & 0xffff) != 0xffff) {
+				pr_info("RIO: badness when releasing " \
+					"host lock on %s\n", rio_name(rdev));
+			}
+
 		}
 }
 
@@ -1027,6 +1090,13 @@ int __devinit rio_disc_mport(struct rio_
 		del_timer_sync(&rio_enum_timer);
 
 		pr_debug("done\n");
+
+		/* Read DestID assigned by enumerator */
+		rio_local_read_config_32(mport, RIO_DID_CSR,
+					 &mport->host_deviceid);
+		mport->host_deviceid = RIO_GET_DID(mport->sys_size,
+						   mport->host_deviceid);
+
 		if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size),
 					0) < 0) {
 			printk(KERN_INFO

---

Important Notice: This message is intended for the use of the individual to whom it is addressed and may contain information which is privileged, confidential and/or exempt from disclosure under applicable law. If the reader of this message is not the intended recipient, or is not the employee or agent responsible for delivering the message to the intended recipient, you are hereby notified that any dissemination, distribution, or copying of this communication is strictly prohibited. If you have received this communication in error, please notify the sender immediately by telephone or return e-mail and delete the original message from your systems. Thank you. 

^ permalink raw reply

* Re: [PATCH] Fixed statement without effect by using a correct empty instruction
From: Marcus Meissner @ 2010-02-24 13:43 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, albrecht.dress
In-Reply-To: <fa686aa41002240540s2044ecaaj3ce04021719a51ef@mail.gmail.com>

On Wed, Feb 24, 2010 at 06:40:37AM -0700, Grant Likely wrote:
> On Wed, Feb 24, 2010 at 1:51 AM, Marcus Meissner <meissner@suse.de> wrote:
> > This fixes this build failure:
> > cc1: warnings being treated as errors
> > /usr/src/packages/BUILD/kernel-default-2.6.33/linux-2.6.32/arch/powerpc/platforms/52xx/mpc52xx_gpt.c: In function 'mpc52xx_gpt_probe':
> > /usr/src/packages/BUILD/kernel-default-2.6.33/linux-2.6.32/arch/powerpc/platforms/52xx/mpc52xx_gpt.c:761:3: error: statement with no effect
> >
> > Signed-off-by: Marcus Meissner <meissner@suse.de>
> 
> Hi Marcus, thanks for the patch.  One comment below...
> 
> > ---
> >  arch/powerpc/platforms/52xx/mpc52xx_gpt.c |    2 +-
> >  1 files changed, 1 insertions(+), 1 deletions(-)
> >
> > diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
> > index 6f8ebe1..88231d8 100644
> > --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
> > +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
> > @@ -711,7 +711,7 @@ static int __devinit mpc52xx_gpt_wdt_init(void)
> >        return 0;
> >  }
> >
> > -#define mpc52xx_gpt_wdt_setup(x, y)            (0)
> > +#define mpc52xx_gpt_wdt_setup(x, y)            do { } while (0)
> 
> As Andrew likes to say, we should be programming in C instead of preprocessor.
> 
> -#define mpc52xx_gpt_wdt_setup(x, y)            (0)
> +static inline void mpc52xx_gpt_wdt_setup(struct mpc52xx_gpt_priv
> *gpt, const u32 *period) { }

Sounds good to me too. :)

Ciao, Marcus

^ permalink raw reply

* Re: [PATCH] Fixed statement without effect by using a correct empty instruction
From: Grant Likely @ 2010-02-24 13:40 UTC (permalink / raw)
  To: Marcus Meissner; +Cc: linuxppc-dev, albrecht.dress
In-Reply-To: <20100224085137.GA25801@suse.de>

On Wed, Feb 24, 2010 at 1:51 AM, Marcus Meissner <meissner@suse.de> wrote:
> This fixes this build failure:
> cc1: warnings being treated as errors
> /usr/src/packages/BUILD/kernel-default-2.6.33/linux-2.6.32/arch/powerpc/p=
latforms/52xx/mpc52xx_gpt.c: In function 'mpc52xx_gpt_probe':
> /usr/src/packages/BUILD/kernel-default-2.6.33/linux-2.6.32/arch/powerpc/p=
latforms/52xx/mpc52xx_gpt.c:761:3: error: statement with no effect
>
> Signed-off-by: Marcus Meissner <meissner@suse.de>

Hi Marcus, thanks for the patch.  One comment below...

> ---
> =A0arch/powerpc/platforms/52xx/mpc52xx_gpt.c | =A0 =A02 +-
> =A01 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/pla=
tforms/52xx/mpc52xx_gpt.c
> index 6f8ebe1..88231d8 100644
> --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
> +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
> @@ -711,7 +711,7 @@ static int __devinit mpc52xx_gpt_wdt_init(void)
> =A0 =A0 =A0 =A0return 0;
> =A0}
>
> -#define mpc52xx_gpt_wdt_setup(x, y) =A0 =A0 =A0 =A0 =A0 =A0(0)
> +#define mpc52xx_gpt_wdt_setup(x, y) =A0 =A0 =A0 =A0 =A0 =A0do { } while =
(0)

As Andrew likes to say, we should be programming in C instead of preprocess=
or.

-#define mpc52xx_gpt_wdt_setup(x, y)            (0)
+static inline void mpc52xx_gpt_wdt_setup(struct mpc52xx_gpt_priv
*gpt, const u32 *period) { }

^ 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