R-Car Gen2 PCIe host driver
Subsystems (8)
v7 cover R-Car Gen2 PCIe host driver
This is version 7 of a PCIe Host driver for the R-Car Gen2 devices, i.e. R-Car H2 (r8a7790) and R-Car M2 (r8a7791).
v7:
- Change binding description of clocks to 'clock specifiers'
v6:
- Correct DT bindings description for reg and clocks
- Split device and board DT changes
- Add shmobile to subject for shmobile DT patches
- Don't check MSI irq number is valid, as upper level checks this
- Change "Unexpected MSI" msg to debug level
- Reword "Unexpected MSI" comment so that it's one line
- Remove patch that adds HAVE_ARM_ARCH_TIMER to koelsch defconfig as not needed
v5:
- Use module_platform_driver instead of subsys_initcall
- Use the of_device_id data field for HW init function
- Init hw_pci struct in declaration
- Renesas SoC compatible string has peripheral before device name
- Add PCIe bus clock reference
- Use dma-ranges property to specify inbound memory regions
- Support multiple IO windows and correct resources
- Return IRQ_NONE from MSI isr when there is no pending MSI
- Add additional interrupt bindings
v4:
- Use runtime PM properly
Phil Edworthy (10):
PCI: host: rcar: Add Renesas R-Car PCIe driver
PCI: host: rcar: Add MSI support
ARM: shmobile: r8a7790: Add PCIe clock device tree nodes
ARM: shmobile: r8a7791: Add PCIe clock device tree nodes
dt-bindings: pci: rcar pcie device tree bindings
ARM: shmobile: r8a7790: Add PCIe device nodes
ARM: shmobile: lager: Add PCIe device nodes
ARM: shmobile: r8a7791: Add PCIe device nodes
ARM: shmobile: koelsch: Add PCIe device nodes
ARM: shmobile: koelsch: Add PCIe to defconfig
Documentation/devicetree/bindings/pci/rcar-pci.txt | 45 + arch/arm/boot/dts/r8a7790-lager.dts | 10 + arch/arm/boot/dts/r8a7790.dtsi | 31 +- arch/arm/boot/dts/r8a7791-koelsch.dts | 14 + arch/arm/boot/dts/r8a7791.dtsi | 31 +- arch/arm/configs/koelsch_defconfig | 3 + drivers/pci/host/Kconfig | 6 + drivers/pci/host/Makefile | 1 + drivers/pci/host/pcie-rcar.c | 929 +++++++++++++++++++++ drivers/pci/host/pcie-rcar.h | 87 ++ include/dt-bindings/clock/r8a7790-clock.h | 1 + include/dt-bindings/clock/r8a7791-clock.h | 1 + 12 files changed, 1154 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/pci/rcar-pci.txt create mode 100644 drivers/pci/host/pcie-rcar.c create mode 100644 drivers/pci/host/pcie-rcar.h
Signature · 1 line
1.9.0
PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver
This PCIe Host driver currently does not support MSI, so cards fall back to INTx interrupts.
v5:
- Use module_platform_driver instead of subsys_initcall
- Use the of_device_id data field for HW init function
- Init hw_pci struct in declaration
- Renesas SoC compatible string has peripheral before device name
- Add PCIe bus clock reference
- Use dma-ranges property to specify inbound memory regions
- Support multiple IO windows and correct resources
v4:
- Use runtime PM properly
v3:
- Add DT support
- Use 'of_irq_parse_and_map_pci' for '.map_irq'
- Use pm ops to enable clocks
- Fix checkpatch errors
- Use subsys_initcall to overcome issues with port bus driver
- Adjust Kconfig to match other R-Car drivers
v2:
- Use msleep instead of udelay when waiting for the link
- Use pm_runtime
- Removed unused definition
- Also replaced call to devm_request_and_ioremap with devm_ioremap_resource and fixed a bug with this when reporting errors.
--- drivers/pci/host/Kconfig | 6 + drivers/pci/host/Makefile | 1 + drivers/pci/host/pcie-rcar.c | 693 +++++++++++++++++++++++++++++++++++++++++++ drivers/pci/host/pcie-rcar.h | 82 +++++ 4 files changed, 782 insertions(+) create mode 100644 drivers/pci/host/pcie-rcar.c create mode 100644 drivers/pci/host/pcie-rcar.h
drivers/pci/host/Kconfig +6 -0
@@ -33,4 +33,10 @@ config PCI_RCAR_GEN2 There are 3 internal PCI controllers available with a single built-in EHCI/OHCI host controller present on each one. +config PCI_RCAR_GEN2_PCIE + bool "Renesas R-Car PCIe controller" + depends on ARCH_SHMOBILE || (ARM && COMPILE_TEST) + help + Say Y here if you want PCIe controller support on R-Car Gen2 SoCs. + endmenu
drivers/pci/host/Makefile +1 -0
@@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_IMX6) += pci-imx6.o obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o +obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
drivers/pci/host/pcie-rcar.c new file +693 -0
693 lines not on this page · raw message
drivers/pci/host/pcie-rcar.h new file +82 -0
82 lines not on this page · raw message
Signature · 1 line
1.9.0
Bjorn Helgaas
maintainerPATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver
drivers/pci/host/pcie-rcar.c line 27
Quoted 12 lines · Phil Edworthy
This PCIe Host driver currently does not support MSI, so cards fall back to INTx interrupts.
Signed-off-by Phil Edworthy <[email protected]>...
drivers/pci/host/pcie-rcar.c new file +2
-0@@ -0,0 +1,693 @@ +#include <linux/slab.h> +#include "pcie-rcar.h"
It looks like the things in pcie-rcar.h are used only in this file (pcie-rcar.c), so you might as well just put the contents here and not have a pcie-rcar.h at all. Of course, if there are things needed by more than one file, they should stay in pcie-rcar.h.
Quoted 10 lines
drivers/pci/host/pcie-rcar.c new file +10
-0+#define DRV_NAME "rcar-pcie" + +#define RCONF (x) (PCICONF(0)+(x)) +#define RPMCAP (x) (PMCAP(0)+(x)) +#define REXPCAP (x) (EXPCAP(0)+(x)) +#define RVCCAP (x) (VCCAP(0)+(x)) + +#define PCIE_CONF_BUS (b) (((b) & 0xff) << 24) +#define PCIE_CONF_DEV (d) (((d) & 0x1f) << 19) +#define PCIE_CONF_FUNC (f) (((f) & 0x7) << 16)
drivers/pci/host/pcie-rcar.c line 48
Quoted 10 lines
drivers/pci/host/pcie-rcar.c new file +10
-0+ +#define PCI_MAX_RESOURCES 4 +#define MAX_NR_INBOUND_MAPS 6 + +/* Structure representing the PCIe interface */ +struct rcar_pcie { +struct device *dev; +void __iomem *base; +struct resource res[PCI_MAX_RESOURCES ]; +u8 root_bus_nr;
I don't understand how root_bus_nr works. From its name, it sounds like it's the bus number of the PCI bus on the downstream side of the host bridge. That bus number should be a property of the host bridge, i.e., it's either hard-wired into the bridge, or it's programmable somewhere. But root_bus_nr comes from sys->busnr, which is apparently from some generic code that knows nothing about this particular host bridge.
drivers/pci/host/pcie-rcar.c line 59
Quoted 11 lines
drivers/pci/host/pcie-rcar.c new file +11
-0+struct clk *clk; +struct clk *bus_clk; +}; + +static inline struct rcar_pcie *sys_to_pcie (struct pci_sys_data *sys) +{ +return sys->private_data; +} + +static void +pci_write_reg (struct rcar_pcie *pcie,unsigned long val,unsigned long reg)
Use this indentation style:
static void pci_write_reg(struct rcar_pcie *pcie, unsigned long val,
and wrap the args as necessary (as you already did with rcar_pcie_read_conf() below).
Quoted 7 lines
drivers/pci/host/pcie-rcar.c new file +7
-0+{ +writel (val, pcie->base + reg); +} + +static unsigned long +pci_read_reg (struct rcar_pcie *pcie,unsigned long reg) +{
drivers/pci/host/pcie-rcar.c line 76
Quoted 10 lines
drivers/pci/host/pcie-rcar.c new file +10
-0+return readl (pcie->base + reg); +} + +enum { +PCI_ACCESS_READ , +PCI_ACCESS_WRITE , +}; + +static void rcar_rmw32 (struct rcar_pcie *pcie, +int where,u32 mask,u32 data)
No wrapping necessary here.
drivers/pci/host/pcie-rcar.c line 79
Quoted 3 lines
drivers/pci/host/pcie-rcar.c new file +3
-0+{ +int shift =8 * (where &3 ); +u32 val =pci_read_reg (pcie, where & ~3 );
A blank line is typical here (after the local variables).
drivers/pci/host/pcie-rcar.c line 88
Quoted 9 lines
drivers/pci/host/pcie-rcar.c new file +9
-0+ val &= ~(mask << shift); + val |= data << shift; +pci_write_reg (pcie, val, where & ~3 ); +} + +static u32 rcar_read_conf (struct rcar_pcie *pcie,int where) +{ +int shift =8 * (where &3 ); +u32 val =pci_read_reg (pcie, where & ~3 );
And here.
Quoted 6 lines
drivers/pci/host/pcie-rcar.c new file +6
-0+return val >> shift; +} + +static int rcar_pcie_config_access (struct rcar_pcie *pcie, +unsigned char access_type,struct pci_bus *bus, +unsigned int devfn,int where,u32 *data)
drivers/pci/host/pcie-rcar.c line 104
Quoted 10 lines
drivers/pci/host/pcie-rcar.c new file +10
-0+{ +int dev, func, reg, index; + + dev =PCI_SLOT (devfn); + func =PCI_FUNC (devfn); + reg = where & ~3 ; + index = reg /4 ; + +if (bus->number >255 || dev >31 || func >7 ) +return PCIBIOS_FUNC_NOT_SUPPORTED ;
I do see one other place in the tree (sh7786_pcie_config_access()) where we test all these, but I don't think it's really necessary. It's actually impossible to satisfy this condition, given the definitions of bus->number, PCI_SLOT(), and PCI_FUNC().
Quoted 20 lines
...
drivers/pci/host/pcie-rcar.c new file +19
-0+/* Clear errors */ +pci_write_reg (pcie,pci_read_reg (pcie,PCIEERRFR ),PCIEERRFR ); + +/* Set the PIO address */ +pci_write_reg (pcie,PCIE_CONF_BUS (bus->number) |PCIE_CONF_DEV (dev) | +PCIE_CONF_FUNC (func) | reg,PCIECAR ); + +/* Enable the configuration access */ +if (bus->parent->number == pcie->root_bus_nr) +pci_write_reg (pcie,CONFIG_SEND_ENABLE |TYPE0 ,PCIECCTLR ); +else +pci_write_reg (pcie,CONFIG_SEND_ENABLE |TYPE1 ,PCIECCTLR ); + +/* Check for errors */ +if (pci_read_reg (pcie,PCIEERRFR ) &UNSUPPORTED_REQUEST ) +return PCIBIOS_DEVICE_NOT_FOUND ; + +/* Check for master and target aborts */ + if (rcar_read_conf(pcie, RCONF(PCI_STATUS)) &
drivers/pci/host/pcie-rcar.c line 161
Quoted 10 lines
drivers/pci/host/pcie-rcar.c new file +10
-0+ (PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT)) +return PCIBIOS_DEVICE_NOT_FOUND ; + +if (access_type ==PCI_ACCESS_READ ) + *data =pci_read_reg (pcie,PCIECDR ); +else +pci_write_reg (pcie, *data,PCIECDR ); + +/* Disable the configuration access */ +pci_write_reg (pcie,0 ,PCIECCTLR );
It looks like the above all needs to be atomic, so I suppose you're relying on higher-level locking to ensure that. It might be worth a mention of the lock you rely on, just in case that ever changes (I doubt it would, but it's conceivable).
Quoted 19 lines
...
drivers/pci/host/pcie-rcar.c new file +18
-0+static int rcar_pcie_setup_window (int win,struct resource *res, +struct rcar_pcie *pcie) +{ +/* Setup PCIe address space mappings for each resource */ +resource_size_t size; +u32 mask; + +pci_write_reg (pcie,0x00000000 ,PCIEPTCTLR (win)); + +/* +* The PAMR mask is calculated in units of 128Bytes, which +* keeps things pretty simple. +*/ + size =resource_size (res); + mask = (roundup_pow_of_two (size) /SZ_128 ) -1 ; +pci_write_reg (pcie, mask <<7 ,PCIEPAMR (win)); + +pci_write_reg (pcie,upper_32_bits (res->start),PCIEPARH (win));
drivers/pci/host/pcie-rcar.c line 266
Quoted 10 lines
drivers/pci/host/pcie-rcar.c new file +10
-0+pci_write_reg (pcie,lower_32_bits (res->start),PCIEPARL (win)); + +/* First resource is for IO */ + mask =PAR_ENABLE ; +if (res->flags &IORESOURCE_IO ) + mask |=IO_SPACE ; + +pci_write_reg (pcie, mask,PCIEPTCTLR (win)); + +return 0 ;
Maybe could be a void function, since no error is possible?
drivers/pci/host/pcie-rcar.c line 472
Quoted 10 lines
...
drivers/pci/host/pcie-rcar.c new file +9
-0+static int __init rcar_pcie_get_resources (struct platform_device *pdev, +struct rcar_pcie *pcie) +{ +struct resource res; +int err; + + err =of_address_to_resource (pdev->dev.of_node,0 , &res); +if (err) +return err;
I don't see anywhere that figures out the bus number range behind this host bridge. The PCI core needs to know this. I know the core assumes 00-ff if it's not supplied, but that's just to deal with the legacy situation where we assumed one host bridge was all anybody would ever need.
For new code, we should be explicit about the range.
Bjorn
PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver
Hi Bjorn,
Thanks for the review.
Quoted 7 lines · Bjorn
Quoted 5 lines · Phil Edworthy
This PCIe Host driver currently does not support MSI, so cards fall back to INTx interrupts.
Signed-off-by Phil Edworthy <[email protected]>...
Quoted 11 lines
drivers/pci/host/pcie-rcar.c line 27
Quoted 6 lines
drivers/pci/host/pcie-rcar.c new file +2
-0@@ -0,0 +1,693 @@ +#include <linux/slab.h> +#include "pcie-rcar.h" It looks like the things in
pcie-rcar.hare used only in this file (pcie-rcar.c), so you might as well just put the contents here and not have apcie-rcar.hat all. Of course, if there are things needed by more than one file, they should stay inpcie-rcar.h.
Nothing else uses them so I'll put in the c file.
Quoted 16 lines
Quoted 16 lines
drivers/pci/host/pcie-rcar.c new file +16
-0+#define DRV_NAME "rcar-pcie" + +#define RCONF (x) (PCICONF(0)+(x)) +#define RPMCAP (x) (PMCAP(0)+(x)) +#define REXPCAP (x) (EXPCAP(0)+(x)) +#define RVCCAP (x) (VCCAP(0)+(x)) + +#define PCIE_CONF_BUS (b) (((b) & 0xff) << 24) +#define PCIE_CONF_DEV (d) (((d) & 0x1f) << 19) +#define PCIE_CONF_FUNC (f) (((f) & 0x7) << 16) + +#define PCI_MAX_RESOURCES 4 +#define MAX_NR_INBOUND_MAPS 6 + +/* Structure representing the PCIe interface */ +struct rcar_pcie {
Quoted 8 lines
drivers/pci/host/pcie-rcar.c line 48
Quoted 4 lines
drivers/pci/host/pcie-rcar.c new file +4
-0+struct device *dev; +void __iomem *base; +struct resource res[PCI_MAX_RESOURCES ]; +u8 root_bus_nr;I don't understand how
root_bus_nrworks. From its name, it sounds like it's the bus number of the PCI bus on the downstream side of the host bridge.
That's correct.
Quoted 4 lines
That bus number should be a property of the host bridge, i.e., it's either hard-wired into the bridge, or it's programmable somewhere. But
root_bus_nrcomes fromsys->busnr, which is apparently from some generic code that knows nothing about this particular host bridge.
The manual for this hardware says that the HW doesn't care what the bus number is set to. The only thing the HW needs to know is that when sending config accesses, we need to indicate whether it's a TYPE0 or TYPE1 header; so we use root_bus_nr to determine this. The generic code that sets up sys->busnr (ARM bios32 in this case), just increments bus number for each controller.
This is very similar to the pcie-designware driver, in dw_pcie_scan_bus().
Quoted 13 lines
drivers/pci/host/pcie-rcar.c
Quoted 11 lines
drivers/pci/host/pcie-rcar.c new file +11
-0+struct clk *clk; +struct clk *bus_clk; +}; + +static inline struct rcar_pcie *sys_to_pcie (struct pci_sys_data *sys) +{ +return sys->private_data; +} + +static void +pci_write_reg(struct rcar_pcie *pcie, unsigned long val, unsigned longreg)
Quoted 6 lines
Use this indentation style:
static void pci_write_reg(struct
rcar_pcie*pcie, unsigned long val,and wrap the args as necessary (as you already did with
rcar_pcie_read_conf()below).
Ok
Quoted 11 lines
Quoted 11 lines
drivers/pci/host/pcie-rcar.c new file +11
-0+{ +writel (val, pcie->base + reg); +} + +static unsigned long +pci_read_reg (struct rcar_pcie *pcie,unsigned long reg) +{ +return readl (pcie->base + reg); +} + +enum {
Quoted 8 lines
drivers/pci/host/pcie-rcar.c line 76
Quoted 6 lines
drivers/pci/host/pcie-rcar.c new file +6
-0+PCI_ACCESS_READ , + PCI_ACCESS_WRITE, +}; + +static void rcar_rmw32 (struct rcar_pcie *pcie, +int where,u32 mask,u32 data)No wrapping necessary here.
Sure
Quoted 5 lines
drivers/pci/host/pcie-rcar.c line 79
Quoted 3 lines
drivers/pci/host/pcie-rcar.c new file +3
-0+{ +int shift =8 * (where &3 ); +u32 val =pci_read_reg (pcie, where & ~3 );A blank line is typical here (after the local variables).
Ok
Quoted 11 lines
drivers/pci/host/pcie-rcar.c line 88
Quoted 9 lines
drivers/pci/host/pcie-rcar.c new file +9
-0+ val &= ~(mask << shift); + val |= data << shift; +pci_write_reg (pcie, val, where & ~3 ); +} + +static u32 rcar_read_conf (struct rcar_pcie *pcie,int where) +{ +int shift =8 * (where &3 ); +u32 val =pci_read_reg (pcie, where & ~3 );And here.
Ok
Quoted 13 lines
Quoted 13 lines
drivers/pci/host/pcie-rcar.c new file +13
-0+return val >> shift; +} + +static int rcar_pcie_config_access (struct rcar_pcie *pcie, +unsigned char access_type,struct pci_bus *bus, +unsigned int devfn,int where,u32 *data) +{ +int dev, func, reg, index; + + dev =PCI_SLOT (devfn); + func =PCI_FUNC (devfn); + reg = where & ~3 ; + index = reg /4 ;
Quoted 8 lines
drivers/pci/host/pcie-rcar.c line 104
Quoted 3 lines
drivers/pci/host/pcie-rcar.c new file +3
-0+ +if (bus->number >255 || dev >31 || func >7 ) +return PCIBIOS_FUNC_NOT_SUPPORTED ;I do see one other place in the tree (
sh7786_pcie_config_access()) where we test all these, but I don't think it's really necessary. It's actually impossible to satisfy this condition, given the definitions ofbus->number,PCI_SLOT(), andPCI_FUNC().
Ok, I'll remove them. They were simply copied over from the sh7786 driver.
Quoted 25 lines
drivers/pci/host/pcie-rcar.c
Quoted 6 lines
...
drivers/pci/host/pcie-rcar.c new file +5
-0+/* Clear errors */ +pci_write_reg (pcie,pci_read_reg (pcie,PCIEERRFR ),PCIEERRFR ); + +/* Set the PIO address */ + pci_write_reg(pcie, PCIE_CONF_BUS(bus->number) |
PCIE_CONF_DEV(dev)|drivers/pci/host/pcie-rcar.c
Quoted 5 lines
drivers/pci/host/pcie-rcar.c new file +5
-0+ PCIE_CONF_FUNC(func) | reg, PCIECAR); + +/* Enable the configuration access */ +if (bus->parent->number == pcie->root_bus_nr) + pci_write_reg(pcie, CONFIG_SEND_ENABLE | TYPE0,PCIECCTLR);
drivers/pci/host/pcie-rcar.c
Quoted 2 lines
drivers/pci/host/pcie-rcar.c new file +2
-0+else + pci_write_reg(pcie, CONFIG_SEND_ENABLE | TYPE1,PCIECCTLR);
drivers/pci/host/pcie-rcar.c
Quoted 8 lines
drivers/pci/host/pcie-rcar.c new file +8
-0+ +/* Check for errors */ +if (pci_read_reg (pcie,PCIEERRFR ) &UNSUPPORTED_REQUEST ) +return PCIBIOS_DEVICE_NOT_FOUND ; + +/* Check for master and target aborts */ + if (rcar_read_conf(pcie, RCONF(PCI_STATUS)) & + (PCI_STATUS_REC_MASTER_ABORT |
PCI_STATUS_REC_TARGET_ABORT))
Quoted 14 lines
drivers/pci/host/pcie-rcar.c line 161
Quoted 9 lines
drivers/pci/host/pcie-rcar.c new file +9
-0+return PCIBIOS_DEVICE_NOT_FOUND ; + +if (access_type ==PCI_ACCESS_READ ) + *data =pci_read_reg (pcie,PCIECDR ); +else +pci_write_reg (pcie, *data,PCIECDR ); + +/* Disable the configuration access */ +pci_write_reg (pcie,0 ,PCIECCTLR );It looks like the above all needs to be atomic, so I suppose you're relying on higher-level locking to ensure that. It might be worth a mention of the lock you rely on, just in case that ever changes (I doubt it would, but it's conceivable).
Yes, the locking is done at a higher level; I'll add comment for this.
Quoted 23 lines
Quoted 23 lines
...
drivers/pci/host/pcie-rcar.c new file +22
-0+static int rcar_pcie_setup_window (int win,struct resource *res, +struct rcar_pcie *pcie) +{ +/* Setup PCIe address space mappings for each resource */ +resource_size_t size; +u32 mask; + +pci_write_reg (pcie,0x00000000 ,PCIEPTCTLR (win)); + +/* +* The PAMR mask is calculated in units of 128Bytes, which +* keeps things pretty simple. +*/ + size =resource_size (res); + mask = (roundup_pow_of_two (size) /SZ_128 ) -1 ; +pci_write_reg (pcie, mask <<7 ,PCIEPAMR (win)); + +pci_write_reg (pcie,upper_32_bits (res->start),PCIEPARH (win)); +pci_write_reg (pcie,lower_32_bits (res->start),PCIEPARL (win)); + +/* First resource is for IO */ + mask =PAR_ENABLE ;
Quoted 8 lines
drivers/pci/host/pcie-rcar.c line 266
Quoted 6 lines
drivers/pci/host/pcie-rcar.c new file +6
-0+if (res->flags &IORESOURCE_IO ) + mask |=IO_SPACE ; + +pci_write_reg (pcie, mask,PCIEPTCTLR (win)); + +return 0 ;Maybe could be a void function, since no error is possible?
Sure
Quoted 16 lines
drivers/pci/host/pcie-rcar.c line 472
Quoted 10 lines
...
drivers/pci/host/pcie-rcar.c new file +9
-0+static int __init rcar_pcie_get_resources (struct platform_device *pdev, +struct rcar_pcie *pcie) +{ +struct resource res; +int err; + + err =of_address_to_resource (pdev->dev.of_node,0 , &res); +if (err) +return err;I don't see anywhere that figures out the bus number range behind this host bridge. The PCI core needs to know this. I know the core assumes 00-ff if it's not supplied, but that's just to deal with the legacy situation where we assumed one host bridge was all anybody would ever need.
Quoted 1 line
For new code, we should be explicit about the range.
This means add a DT entry for bus-range, and simply calling pci_add_resource for the range, right? If so, ok.
Thanks
Phil
Bjorn Helgaas
maintainerPATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver
Quoted 55 lines · Phil Edworthy
Hi Bjorn,
Thanks for the review.
Quoted 7 lines · Bjorn
Quoted 5 lines · Phil Edworthy
This PCIe Host driver currently does not support MSI, so cards fall back to INTx interrupts.
Signed-off-by Phil Edworthy <[email protected]>...
Quoted 11 lines
drivers/pci/host/pcie-rcar.c line 27
Quoted 6 lines
drivers/pci/host/pcie-rcar.c new file +2
-0@@ -0,0 +1,693 @@ +#include <linux/slab.h> +#include "pcie-rcar.h" It looks like the things in
pcie-rcar.hare used only in this file (pcie-rcar.c), so you might as well just put the contents here and not have apcie-rcar.hat all. Of course, if there are things needed by more than one file, they should stay inpcie-rcar.h.Nothing else uses them so I'll put in the c file.
Quoted 16 lines
Quoted 16 lines
drivers/pci/host/pcie-rcar.c new file +16
-0+#define DRV_NAME "rcar-pcie" + +#define RCONF (x) (PCICONF(0)+(x)) +#define RPMCAP (x) (PMCAP(0)+(x)) +#define REXPCAP (x) (EXPCAP(0)+(x)) +#define RVCCAP (x) (VCCAP(0)+(x)) + +#define PCIE_CONF_BUS (b) (((b) & 0xff) << 24) +#define PCIE_CONF_DEV (d) (((d) & 0x1f) << 19) +#define PCIE_CONF_FUNC (f) (((f) & 0x7) << 16) + +#define PCI_MAX_RESOURCES 4 +#define MAX_NR_INBOUND_MAPS 6 + +/* Structure representing the PCIe interface */ +struct rcar_pcie {Quoted 8 lines
drivers/pci/host/pcie-rcar.c line 48
Quoted 4 lines
drivers/pci/host/pcie-rcar.c new file +4
-0+struct device *dev; +void __iomem *base; +struct resource res[PCI_MAX_RESOURCES ]; +u8 root_bus_nr;I don't understand how
root_bus_nrworks. From its name, it sounds like it's the bus number of the PCI bus on the downstream side of the host bridge.That's correct.
Quoted 4 lines
That bus number should be a property of the host bridge, i.e., it's either hard-wired into the bridge, or it's programmable somewhere. But
root_bus_nrcomes fromsys->busnr, which is apparently from some generic code that knows nothing about this particular host bridge.
Quoted 7 lines
The manual for this hardware says that the HW doesn't care what the bus number is set to. The only thing the HW needs to know is that when sending config accesses, we need to indicate whether it's a TYPE0 or TYPE1 header; so we use
root_bus_nrto determine this. The generic code that sets upsys->busnr(ARM bios32 in this case), just increments bus number for each controller.This is very similar to the pcie-designware driver, in
dw_pcie_scan_bus().
OK. From what you said below, it sounds like you would add a DT entry for the bus range you want to have below this bridge, and use TYPE0 accesses for the base of that range.
I'm not sure how you reconcile this with the idea that the bios32 code just increments a bus number for each controller.
Quoted 15 lines
Quoted 15 lines
drivers/pci/host/pcie-rcar.c line 472
Quoted 9 lines
drivers/pci/host/pcie-rcar.c new file +9
-0+static int __init rcar_pcie_get_resources (struct platform_device *pdev, +struct rcar_pcie *pcie) +{ +struct resource res; +int err; + + err =of_address_to_resource (pdev->dev.of_node,0 , &res); +if (err) +return err;I don't see anywhere that figures out the bus number range behind this host bridge. The PCI core needs to know this. I know the core assumes 00-ff if it's not supplied, but that's just to deal with the legacy situation where we assumed one host bridge was all anybody would ever need.
Quoted 3 lines
Quoted 1 line
For new code, we should be explicit about the range.
This means add a DT entry for bus-range, and simply calling
pci_add_resourcefor the range, right? If so, ok.
Yeah, I guess. If the HW really doesn't look at the bus number at all, it sounds like the range is effectively 00-ff, and each host bridge should be in its own domain.
Bjorn
PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver
Quoted 10 lines · Bjorn Helgaas
Quoted 10 lines
Quoted 4 lines
That bus number should be a property of the host bridge, i.e., it's either hard-wired into the bridge, or it's programmable somewhere. But
root_bus_nrcomes fromsys->busnr, which is apparently from some generic code that knows nothing about this particular host bridge.The manual for this hardware says that the HW doesn't care what the bus number is set to. The only thing the HW needs to know is that when sending config accesses, we need to indicate whether it's a TYPE0 or TYPE1 header; so we use
root_bus_nrto determine this. The generic code that sets upsys->busnr(ARM bios32 in this case), just increments bus number for each controller.
I went back and looked at the lspci posted for this hardware and this use of busnr is kinda sketch..
You should use use bus 0 as the root complex integrated bus number and ensure every instance of your driver creates a new PCI domain, and generally use 0-> FF as the subordinate bus number range.
FWIW, your HW does care, and does have a programmable field for this.
You set the value of the integrated bus based on the bus number in the TYPE0 accesses the driver performs and it shows up in the PCI config space of the root port bridge:
root at koelsch:~# lspci -vv
00:00.0 PCI bridge: Renesas Technology Corp. Device 001f (prog-if 00 [Normal decode])
Bus: primary=00, secondary=01, subordinate=01, sec-latency=0
The value here will be also be exported on-the-wire in certain PCI-E TLPs.
So it is important, and must be set properly.
Quoted 3 lines
Yeah, I guess. If the HW really doesn't look at the bus number at all, it sounds like the range is effectively 00-ff, and each host bridge should be in its own domain.
This is where some of the other implementations have used some SW to route config space in a single domain to the proper controller per-port register set.
But, IMHO, that is mainly worth doing if the HW can implement the PCI bridge windows according to the spec, and it looks like rcar requires a 128MB alignment on the bridge windows, which makes it fairly pointless.
Jason
PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver
Hi Jason,
Quoted 35 lines · Jason
Quoted 3 lines · Bjorn Helgaas
Quoted 3 lines
Quoted 3 lines
That bus number should be a property of the host bridge, i.e., it's either hard-wired into the bridge, or it's programmable somewhere. But
root_bus_nrcomes fromsys->busnr, which is apparently fromsome
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
generic code that knows nothing about this particular host bridge.
The manual for this hardware says that the HW doesn't care what the bus
number
Quoted 1 line
Quoted 1 line
is set to. The only thing the HW needs to know is that when sending
config
Quoted 1 line
Quoted 1 line
accesses, we need to indicate whether it's a TYPE0 or TYPE1 header; so
we use
Quoted 1 line
Quoted 1 line
root_bus_nrto determine this. The generic code that sets upsys->busnr(ARM
Quoted 1 line
Quoted 1 line
bios32 in this case), just increments bus number for each controller.
I went back and looked at the lspci posted for this hardware and this use of busnr is kinda sketch..
You should use use bus 0 as the root complex integrated bus number and ensure every instance of your driver creates a new PCI domain, and generally use 0-> FF as the subordinate bus number range.
FWIW, your HW does care, and does have a programmable field for this.
You set the value of the integrated bus based on the bus number in the TYPE0 accesses the driver performs and it shows up in the PCI config space of the root port bridge:
root at koelsch:~# lspci -vv
00:00.0 PCI bridge: Renesas Technology Corp. Device 001f (prog-if 00 [Normal decode])
Quoted 6 lines
Bus: primary=00, secondary=01, subordinate=01, sec-latency=0The value here will be also be exported on-the-wire in certain PCI-E TLPs.
So it is important, and must be set properly.
I am not so sure about this...
There are three things we need to consider:
1) talking to the host bridge itself
2) talking to immediate device (connected directly to host bridge)
3) talking to other devices
The PCI standard tells us we use type 1's for 3) and type 0's for 2). The driver uses root_bus_nr to make this decision.
For 1), there is a note in the driver that the hardware cannot target itself. The driver has code in rcar_pcie_config_access() to check if it's an access to the host bridge, and if so, use I/O (readl/writel) to perform the config access.
Quoted 8 lines
Quoted 3 lines
Yeah, I guess. If the HW really doesn't look at the bus number at all, it sounds like the range is effectively 00-ff, and each host bridge should be in its own domain.
This is where some of the other implementations have used some SW to route config space in a single domain to the proper controller per-port register set.
Quoted 6 lines
But, IMHO, that is mainly worth doing if the HW can implement the PCI bridge windows according to the spec, and it looks like rcar requires a 128MB alignment on the bridge windows, which makes it fairly pointless.
Jason
Thanks
Phil
PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver
Quoted 20 lines · Phil Edworthy
Quoted 7 lines
You set the value of the integrated bus based on the bus number in the TYPE0 accesses the driver performs and it shows up in the PCI config space of the root port bridge:
root at koelsch:~# lspci -vv
00:00.0 PCI bridge: Renesas Technology Corp. Device 001f (prog-if 00 [Normal decode])Quoted 6 lines
Bus: primary=00, secondary=01, subordinate=01, sec-latency=0The value here will be also be exported on-the-wire in certain PCI-E TLPs.
So it is important, and must be set properly.
I am not so sure about this...
There are three things we need to consider:
1) talking to the host bridge itself
2) talking to immediate device (connected directly to host bridge)
3) talking to other devices
Quoted 6 lines
The PCI standard tells us we use type 1's for 3) and type 0's for 2). The driver uses
root_bus_nrto make this decision. For 1), there is a note in the driver that the hardware cannot target itself. The driver has code inrcar_pcie_config_access()to check if it's an access to the host bridge, and if so, use I/O (readl/writel) to perform the config access.
The logic should be:
if (bus == primary)
do io access to host bridge
else if (bus == secondary)
issue type 0 TLP on the wire
else if (bus > secondary && bus <= subordinate)
issue type 1 TLP on the wire
else
fail, invalid bus number
Where the three values come from the register in the PCI host bridge's configuration space, and are kept in sync with the programming from the Linux PCI core.
It is just a happy hapenstance that root_bus_nr equals the value the PCI core programmed into secondary - that is not guarenteed, you must use the primary value directly.
I recommend capturing it on write to the host bridge config space.
Jason
PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver
Hi Jason,
Quoted 42 lines · Jason
Quoted 20 lines · Phil Edworthy
Quoted 7 lines
You set the value of the integrated bus based on the bus number in the TYPE0 accesses the driver performs and it shows up in the PCI config space of the root port bridge:
root at koelsch:~# lspci -vv
00:00.0 PCI bridge: Renesas Technology Corp. Device 001f (prog-if 00 [Normal decode])Quoted 6 lines
Bus: primary=00, secondary=01, subordinate=01, sec-latency=0The value here will be also be exported on-the-wire in certain PCI-E TLPs.
So it is important, and must be set properly.
I am not so sure about this...
There are three things we need to consider:
1) talking to the host bridge itself
2) talking to immediate device (connected directly to host bridge)
3) talking to other devicesQuoted 6 lines
The PCI standard tells us we use type 1's for 3) and type 0's for 2). The driver uses
root_bus_nrto make this decision. For 1), there is a note in the driver that the hardware cannot target itself. The driver has code inrcar_pcie_config_access()to check if it's an access to the host bridge, and if so, use I/O (readl/writel) to perform the config access.The logic should be:
if (bus == primary)
do io access to host bridge
else if (bus == secondary)
issue type 0 TLP on the wire
else if (bus > secondary && bus <= subordinate)
issue type 1 TLP on the wire
else
fail, invalid bus number
Where the three values come from the register in the PCI host bridge's configuration space, and are kept in sync with the programming from the Linux PCI core.
Quoted 3 lines
It is just a happy hapenstance that
root_bus_nrequals the value the PCI core programmed into secondary - that is not guarenteed, you must use the primary value directly.
For type0 TLPs, we are not checking that root_bus_nr equals the value the PCI core programmed into secondary, we are checking that the (root_bus_nr == bus->parent->number). The only way this wouldn't work is if root_bus_nr was not the root bus number.
Since the Synopsys DW driver also saves off sys->busnr and later uses this to determine if accesses are for the host bridge, I guess that means it won't always work either, right? Or is it ok because the DW driver saves sys->busnr in its .scan function?
When would the PCI core change the root bus number to something other than set in sys->busnr?
Quoted 2 lines
I recommend capturing it on write to the host bridge config space.
Thanks
Phil
PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver
Quoted 13 lines · Phil Edworthy
Quoted 13 lines
The logic should be:
if (bus == primary)
do io access to host bridge
else if (bus == secondary)
issue type 0 TLP on the wire
else if (bus > secondary && bus <= subordinate)
issue type 1 TLP on the wire
else
fail, invalid bus number
Where the three values come from the register in the PCI host bridge's configuration space, and are kept in sync with the programming from the Linux PCI core.
Quoted 8 lines
Quoted 3 lines
It is just a happy hapenstance that
root_bus_nrequals the value the PCI core programmed into secondary - that is not guarenteed, you must use the primary value directly.For type0 TLPs, we are not checking that
root_bus_nrequals the value the PCI core programmed into secondary, we are checking that the (root_bus_nr==bus->parent->number). The only way this wouldn't work is ifroot_bus_nrwas not the root bus number.
Okay, that isn't as sketchy, but that process still ignores the subordinate bus number and the failure case as required by PCI.
The goal here is to have the stuff below the drivers implement the PCI spec so that the core code can assume everything below is conformant. Drivers should not introduce gratuitous differences 'just because'
There is no reason drivers should be using PCI core structures to make decisions when the spec says those decisions are driven by config space fields.
This way the PCI core code doesn't have to be aware of any weird non-standard edge cases.. Such as not failing bus numbers beyond the subordinate bus number.
Quoted 4 lines
Since the Synopsys DW driver also saves off
sys->busnrand later uses this to determine if accesses are for the host bridge, I guess that means it won't always work either, right? Or is it ok because the DW driver savessys->busnrin its .scan function?
Sounds like it is making the same mistake, and nobody noticed. This is another reason why it is important to implement correctly so people copying copy the right stuff :)
Quoted 2 lines
When would the PCI core change the root bus number to something other than set in
sys->busnr?
I think the more likely scenario is that 'sys' in general is architecture specific and its use is being discouraged so that host drivers are not arch specific.
A domain driver like rcar should always place the root complex integrated bus as bus 0 in the domain.
Jason
PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver
Hi Jason,
Quoted 52 lines · Jason
Quoted 13 lines · Phil Edworthy
Quoted 13 lines
The logic should be:
if (bus == primary)
do io access to host bridge
else if (bus == secondary)
issue type 0 TLP on the wire
else if (bus > secondary && bus <= subordinate)
issue type 1 TLP on the wire
else
fail, invalid bus number
Where the three values come from the register in the PCI host bridge's configuration space, and are kept in sync with the programming from the Linux PCI core.Quoted 8 lines
Quoted 3 lines
It is just a happy hapenstance that
root_bus_nrequals the value the PCI core programmed into secondary - that is not guarenteed, you must use the primary value directly.For type0 TLPs, we are not checking that
root_bus_nrequals the value the PCI core programmed into secondary, we are checking that the (root_bus_nr==bus->parent->number). The only way this wouldn't work is ifroot_bus_nrwas not the root bus number.Okay, that isn't as sketchy, but that process still ignores the subordinate bus number and the failure case as required by PCI.
The goal here is to have the stuff below the drivers implement the PCI spec so that the core code can assume everything below is conformant. Drivers should not introduce gratuitous differences 'just because'
There is no reason drivers should be using PCI core structures to make decisions when the spec says those decisions are driven by config space fields.
This way the PCI core code doesn't have to be aware of any weird non-standard edge cases.. Such as not failing bus numbers beyond the subordinate bus number.
Quoted 4 lines
Since the Synopsys DW driver also saves off
sys->busnrand later uses this to determine if accesses are for the host bridge, I guess that means it won't always work either, right? Or is it ok because the DW driver savessys->busnrin its .scan function?Sounds like it is making the same mistake, and nobody noticed. This is another reason why it is important to implement correctly so people copying copy the right stuff :)
Quoted 2 lines
When would the PCI core change the root bus number to something other than set in
sys->busnr?
Quoted 6 lines
I think the more likely scenario is that 'sys' in general is architecture specific and its use is being discouraged so that host drivers are not arch specific.
A domain driver like rcar should always place the root complex integrated bus as bus 0 in the domain.
Ok, I now understand the reason for removing the dependency on sys->busnr. That makes sense & I'll update the driver for this.
Thanks for your patience :)
Phil
Bjorn Helgaas
maintainerPATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver
In reply to Phil Edworthy[+cc Srikanth, Michal, Grant because we're having the same discussion about root bus numbers in the Xilinx host bridge driver]
Quoted 1 line · Phil Edworthy
When would the PCI core change the root bus number to something other than set in
sys->busnr?
The PCI core never changes the root bus number of a host bridge, but it's important for the core to know exactly what bus numbers are behind each host bridge so we can correctly assign bus numbers, MMIO, and I/O port resources.
The reason is that when we enumerate a PCI-to-PCI bridge, we have to know whether bus numbers are available for the secondary bus. For example, assume two host bridges configured (or wired) as follows:
A leads to [bus 00-1f], with aperture [mem 0x80000000-0x8fffffff] B leads to [bus 20-ff], with aperture [mem 0x90000000-0x9fffffff]
Further, assume a PCI-to-PCI bridge at 1f:00.0. If the host bridge driver doesn't tell us the [bus 00-1f] range for host bridge A, the PCI core will assume [bus 00-ff]. When the core enumerates the 1f:00.0 bridge, it will assign bus number 20 to its secondary bus. Now it enumerates devices on bus 20. The core expects this to be done via host bridge A, but enumeration uses ID-routed config transactions, so they are claimed by host bridge B instead. If we find a device 20:00.0, the core thinks it is below A, but it is really below B.
Now we assign resources to 20:00.0, and since we think it's below A, we assign them from the [mem 0x80000000-0x8fffffff] aperture. This obviously doesn't work, because when the driver performs MMIO accesses, which are address-routed, they are claimed by host bridge A, not B, so the 20:00.0 device never sees them.
If your host bridge really claims ALL bus numbers (00-ff), that's fine, and you can tell the PCI core that. But if you have several such bridges, they should be placed in separate domains.
This is probably more detail than you wanted, and maybe you don't ever expect to have multiple host bridges or complicated hierarchies of devices. But the PCI core has to deal with these issues on other systems, so it's important to get these details right.
Bjorn
PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver
Hi Bjorn,
Quoted 30 lines · Bjorn
[+cc Srikanth, Michal, Grant because we're having the same discussion about root bus numbers in the Xilinx host bridge driver]
Quoted 1 line · Phil Edworthy
When would the PCI core change the root bus number to something other
than set in
sys->busnr?The PCI core never changes the root bus number of a host bridge, but it's important for the core to know exactly what bus numbers are behind each host bridge so we can correctly assign bus numbers, MMIO, and I/O port resources.
The reason is that when we enumerate a PCI-to-PCI bridge, we have to know whether bus numbers are available for the secondary bus. For example, assume two host bridges configured (or wired) as follows:
A leads to [bus 00-1f], with aperture [mem 0x80000000-0x8fffffff] B leads to [bus 20-ff], with aperture [mem 0x90000000-0x9fffffff]
Further, assume a PCI-to-PCI bridge at 1f:00.0. If the host bridge driver doesn't tell us the [bus 00-1f] range for host bridge A, the PCI core will assume [bus 00-ff]. When the core enumerates the 1f:00.0 bridge, it will assign bus number 20 to its secondary bus. Now it enumerates devices on bus 20. The core expects this to be done via host bridge A, but enumeration uses ID-routed config transactions, so they are claimed by host bridge B instead. If we find a device 20:00.0, the core thinks it is below A, but it is really below B.
Quoted 5 lines
Now we assign resources to 20:00.0, and since we think it's below A, we assign them from the [mem 0x80000000-0x8fffffff] aperture. This obviously doesn't work, because when the driver performs MMIO accesses, which are address-routed, they are claimed by host bridge A, not B, so the 20:00.0 device never sees them.
Thanks for the clear explanation.
Quoted 3 lines
If your host bridge really claims ALL bus numbers (00-ff), that's fine, and you can tell the PCI core that. But if you have several such bridges, they should be placed in separate domains.
That makes sense.
In the case of the R-Car PCIe host bridge, as far as I can tell, the hardware doesn?t care about bus numbers at all, with the exception that the driver uses one bus number to target the bridge itself. We can use as many or as few bus numbers for the secondary bus as you like.
So, the R-Car PCIe driver should implement bus ranges, but should it also use separate PCI domains for multiple controllers?
Quoted 4 lines
This is probably more detail than you wanted, and maybe you don't ever expect to have multiple host bridges or complicated hierarchies of devices. But the PCI core has to deal with these issues on other systems, so it's important to get these details right.
Thanks
Phil
PATCH v7 1/10 PCI: host: rcar: Add Renesas R-Car PCIe driver
In reply to Bjorn HelgaasHi Bjorn,
Quoted 63 lines · Bjorn
Quoted 49 lines · Phil Edworthy
Hi Bjorn,
Thanks for the review.
Quoted 7 lines · Bjorn
Quoted 5 lines · Phil Edworthy
This PCIe Host driver currently does not support MSI, so cards fall back to INTx interrupts.
Signed-off-by Phil Edworthy <[email protected]>...
Quoted 11 lines
drivers/pci/host/pcie-rcar.c line 27
Quoted 6 lines
drivers/pci/host/pcie-rcar.c new file +2
-0@@ -0,0 +1,693 @@ +#include <linux/slab.h> +#include "pcie-rcar.h" It looks like the things in
pcie-rcar.hare used only in this file (pcie-rcar.c), so you might as well just put the contents here and not have apcie-rcar.hat all. Of course, if there are things needed by more than one file, they should stay inpcie-rcar.h.Nothing else uses them so I'll put in the c file.
Quoted 16 lines
Quoted 16 lines
drivers/pci/host/pcie-rcar.c new file +16
-0+#define DRV_NAME "rcar-pcie" + +#define RCONF (x) (PCICONF(0)+(x)) +#define RPMCAP (x) (PMCAP(0)+(x)) +#define REXPCAP (x) (EXPCAP(0)+(x)) +#define RVCCAP (x) (VCCAP(0)+(x)) + +#define PCIE_CONF_BUS (b) (((b) & 0xff) << 24) +#define PCIE_CONF_DEV (d) (((d) & 0x1f) << 19) +#define PCIE_CONF_FUNC (f) (((f) & 0x7) << 16) + +#define PCI_MAX_RESOURCES 4 +#define MAX_NR_INBOUND_MAPS 6 + +/* Structure representing the PCIe interface */ +struct rcar_pcie {Quoted 8 lines
drivers/pci/host/pcie-rcar.c line 48
Quoted 4 lines
drivers/pci/host/pcie-rcar.c new file +4
-0+struct device *dev; +void __iomem *base; +struct resource res[PCI_MAX_RESOURCES ]; +u8 root_bus_nr;I don't understand how
root_bus_nrworks. From its name, it sounds like it's the bus number of the PCI bus on the downstream side of the host bridge.Quoted 7 lines
That's correct.
Quoted 4 lines
That bus number should be a property of the host bridge, i.e., it's either hard-wired into the bridge, or it's programmable somewhere. But
root_bus_nrcomes fromsys->busnr, which is apparently from some generic code that knows nothing about this particular host bridge.The manual for this hardware says that the HW doesn't care what the bus
number
Quoted 2 lines
is set to. The only thing the HW needs to know is that when sending config accesses, we need to indicate whether it's a TYPE0 or TYPE1 header; so we
use
Quoted 1 line
root_bus_nrto determine this. The generic code that sets upsys->busnr
Quoted 8 lines
(ARM
Quoted 3 lines
bios32 in this case), just increments bus number for each controller.
This is very similar to the pcie-designware driver, in
dw_pcie_scan_bus().OK. From what you said below, it sounds like you would add a DT entry for the bus range you want to have below this bridge, and use TYPE0 accesses for the base of that range.
Ok. The driver already uses TYPE0 for the base, i.e. that's what root_bus_nr is used for. I'll add the ranges ability.
Quoted 2 lines
I'm not sure how you reconcile this with the idea that the bios32 code just increments a bus number for each controller.
I looked at the bios32 code again. I was wrong to say that it just increments a bus number for each controller. The first controller always starts with busnr=0, and subsequent controllers get the next available bus number after scanning the bus.
Quoted 17 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
+static int
__initrcar_pcie_get_resources(structplatform_device*pdev,
Quoted 10 lines
Quoted 10 lines
drivers/pci/host/pcie-rcar.c line 472
Quoted 8 lines
drivers/pci/host/pcie-rcar.c new file +8
-0+ struct rcar_pcie *pcie) +{ +struct resource res; +int err; + + err =of_address_to_resource (pdev->dev.of_node,0 , &res); +if (err) +return err;I don't see anywhere that figures out the bus number range behind this
host
Quoted 4 lines
Quoted 4 lines
bridge. The PCI core needs to know this. I know the core assumes 00-ff if it's not supplied, but that's just to deal with the legacy situation where we assumed one host bridge was all anybody would ever need.
Quoted 8 lines
Quoted 2 lines
Quoted 1 line
For new code, we should be explicit about the range.
This means add a DT entry for bus-range, and simply calling
pci_add_resourceforQuoted 1 line
the range, right? If so, ok.
Yeah, I guess. If the HW really doesn't look at the bus number at all, it sounds like the range is effectively 00-ff, and each host bridge should be in its own domain.
Ok.
Thanks
Phil
PATCH v7 2/10 PCI: host: rcar: Add MSI support
In reply to Phil Edworthyv6:
- Don't check MSI irq number is valid, as upper level checks this
- Change "Unexpected MSI" msg to debug level
- Reword "Unexpected MSI" comment so that it's one line
v5:
- Return IRQ_NONE from MSI isr when there is no pending MSI
- Add additional interrupt bindings
--- drivers/pci/host/pcie-rcar.c | 238 ++++++++++++++++++++++++++++++++++++++++++- drivers/pci/host/pcie-rcar.h | 5 + 2 files changed, 242 insertions(+), 1 deletion(-)
drivers/pci/host/pcie-rcar.c +237 -1
@@ -15,8 +15,11 @@#include <linux/clk.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/msi.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_pci.h>
@@ -28,6 +31,8 @@#define DRV_NAME "rcar-pcie" +#define INT_PCI_MSI_NR 32 +#define RCONF (x) (PCICONF(0)+(x))#define RPMCAP (x) (PMCAP(0)+(x))#define REXPCAP (x) (EXPCAP(0)+(x))
@@ -40,6 +45,21 @@#define PCI_MAX_RESOURCES 4#define MAX_NR_INBOUND_MAPS 6 +struct rcar_msi { + DECLARE_BITMAP(used, INT_PCI_MSI_NR); +struct irq_domain *domain; +struct msi_chip chip; +unsigned long pages; +struct mutex lock; +int irq1; +int irq2; +}; + +static inline struct rcar_msi *to_rcar_msi (struct msi_chip *chip) +{ + return container_of(chip, struct rcar_msi, chip); +} +/* Structure representing the PCIe interface */ struct rcar_pcie {struct device *dev;
@@ -48,6 +68,7 @@ struct rcar_pcie {u8 root_bus_nr;struct clk *clk;struct clk *bus_clk; +struct rcar_msi msi; };static inline struct rcar_pcie *sys_to_pcie (struct pci_sys_data *sys)
@@ -292,6 +313,15 @@ static int rcar_pcie_setup(int nr, struct pci_sys_data *sys)return 1 ; } +static void rcar_pcie_add_bus (struct pci_bus *bus) +{ +if (IS_ENABLED (CONFIG_PCI_MSI )) { +struct rcar_pcie *pcie =sys_to_pcie (bus->sysdata); + + bus->msi = &pcie->msi.chip; + } +} +static void __init rcar_pcie_enable (struct rcar_pcie *pcie) {struct platform_device *pdev =to_platform_device (pcie->dev);
@@ -301,6 +331,7 @@ static void __init rcar_pcie_enable(struct rcar_pcie *pcie) .setup = rcar_pcie_setup, .map_irq = of_irq_parse_and_map_pci, .ops = &rcar_pcie_ops, + .add_bus = rcar_pcie_add_bus, };pci_common_init_dev (&pdev->dev, &hw);
@@ -408,6 +439,10 @@ static int __init rcar_pcie_hw_init(struct rcar_pcie *pcie)/* Enable MAC data scrambling. */ rcar_rmw32 (pcie,MACCTLR ,SCRAMBLE_DISABLE ,0 ); +/* Enable MSI */ +if (IS_ENABLED (CONFIG_PCI_MSI )) +pci_write_reg (pcie,0x101f0000 ,PCIEMSITXR ); +/* Finish initialization - establish a PCI Express link */ pci_write_reg (pcie,CFINIT ,PCIETCTLR );
@@ -461,11 +496,186 @@ static int __init rcar_pcie_hw_init_h1(struct rcar_pcie *pcie)return -ETIMEDOUT ; } +static int rcar_msi_alloc (struct rcar_msi *chip) +{ +int msi; + +mutex_lock (&chip->lock); + + msi =find_first_zero_bit (chip->used,INT_PCI_MSI_NR ); +if (msi <INT_PCI_MSI_NR ) +set_bit (msi, chip->used); +else + msi = -ENOSPC ; + +mutex_unlock (&chip->lock); + +return msi; +} + +static void rcar_msi_free (struct rcar_msi *chip,unsigned long irq) +{ +struct device *dev = chip->chip.dev; + +mutex_lock (&chip->lock); +clear_bit (irq, chip->used); +mutex_unlock (&chip->lock); +} + +static irqreturn_t rcar_pcie_msi_irq (int irq,void *data) +{ +struct rcar_pcie *pcie = data; +struct rcar_msi *msi = &pcie->msi; +unsigned long reg; + + reg =pci_read_reg (pcie,PCIEMSIFR ); + +/* MSI & INTx share an interrupt - we only handle MSI here */ +if (!reg) +return IRQ_NONE ; + +while (reg) { +unsigned int index =find_first_bit (®,32 ); +unsigned int irq; + +/* clear the interrupt */ +pci_write_reg (pcie,1 << index,PCIEMSIFR ); + + irq =irq_find_mapping (msi->domain, index); +if (irq) { +if (test_bit (index, msi->used)) +generic_handle_irq (irq); +else +dev_info (pcie->dev,"unhandled MSI\n" ); + }else { +/* Unknown MSI, just clear it */ +dev_dbg (pcie->dev,"unexpected MSI\n" ); + } + +/* see if there's any more pending in this vector */ + reg =pci_read_reg (pcie,PCIEMSIFR ); + } + +return IRQ_HANDLED ; +} + +static int rcar_msi_setup_irq (struct msi_chip *chip,struct pci_dev *pdev, +struct msi_desc *desc) +{ +struct rcar_msi *msi =to_rcar_msi (chip); + struct rcar_pcie *pcie = container_of(chip, struct rcar_pcie, msi.chip); +struct msi_msg msg; +unsigned int irq; +int hwirq; + + hwirq =rcar_msi_alloc (msi); +if (hwirq <0 ) +return hwirq; + + irq =irq_create_mapping (msi->domain, hwirq); +if (!irq) { +rcar_msi_free (msi, hwirq); +return -EINVAL ; + } + +irq_set_msi_desc (irq, desc); + + msg.address_lo =pci_read_reg (pcie,PCIEMSIALR ) & ~MSIFE ; + msg.address_hi =pci_read_reg (pcie,PCIEMSIAUR ); + msg.data = hwirq; + +write_msi_msg (irq, &msg); + +return 0 ; +} + +static void rcar_msi_teardown_irq (struct msi_chip *chip,unsigned int irq) +{ +struct rcar_msi *msi =to_rcar_msi (chip); +struct irq_data *d =irq_get_irq_data (irq); + +rcar_msi_free (msi, d->hwirq); +} + +static struct irq_chip rcar_msi_irq_chip = { + .name ="R-Car PCIe MSI" , + .irq_enable = unmask_msi_irq, + .irq_disable = mask_msi_irq, + .irq_mask = mask_msi_irq, + .irq_unmask = unmask_msi_irq, +}; + +static int rcar_msi_map (struct irq_domain *domain,unsigned int irq, +irq_hw_number_t hwirq) +{ +irq_set_chip_and_handler (irq, &rcar_msi_irq_chip, handle_simple_irq); +irq_set_chip_data (irq, domain->host_data); +set_irq_flags (irq,IRQF_VALID ); + +return 0 ; +} + +static const struct irq_domain_ops msi_domain_ops = { + .map = rcar_msi_map, +}; + +static int rcar_pcie_enable_msi (struct rcar_pcie *pcie) +{ +struct platform_device *pdev =to_platform_device (pcie->dev); +struct rcar_msi *msi = &pcie->msi; +unsigned long base; +int err; + +mutex_init (&msi->lock); + + msi->chip.dev = pcie->dev; + msi->chip.setup_irq = rcar_msi_setup_irq; + msi->chip.teardown_irq = rcar_msi_teardown_irq; + + msi->domain =irq_domain_add_linear (pcie->dev->of_node,INT_PCI_MSI_NR , + &msi_domain_ops, &msi->chip); +if (!msi->domain) { +dev_err (&pdev->dev,"failed to create IRQ domain\n" ); +return -ENOMEM ; + } + +/* Two irqs are for MSI, but they are also used for non-MSI irqs */ + err =devm_request_irq (&pdev->dev, msi->irq1, rcar_pcie_msi_irq, +IRQF_SHARED , rcar_msi_irq_chip.name, pcie); +if (err <0 ) { +dev_err (&pdev->dev,"failed to request IRQ: %d\n" , err); + goto err; + } + + err =devm_request_irq (&pdev->dev, msi->irq2, rcar_pcie_msi_irq, +IRQF_SHARED , rcar_msi_irq_chip.name, pcie); +if (err <0 ) { +dev_err (&pdev->dev,"failed to request IRQ: %d\n" , err); + goto err; + } + +/* setup MSI data target */ + msi->pages =__get_free_pages (GFP_KERNEL ,0 ); + base =virt_to_phys ((void *)msi->pages); + +pci_write_reg (pcie, base |MSIFE ,PCIEMSIALR ); +pci_write_reg (pcie,0 ,PCIEMSIAUR ); + +/* enable all MSI interrupts */ +pci_write_reg (pcie,0xffffffff ,PCIEMSIIER ); + +return 0 ; + +err: +irq_domain_remove (msi->domain); +return err; +} +static int __init rcar_pcie_get_resources (struct platform_device *pdev,struct rcar_pcie *pcie) {struct resource res; -int err; +int err, i; err =of_address_to_resource (pdev->dev.of_node,0 , &res);if (err)
@@ -490,6 +700,22 @@ static int __init rcar_pcie_get_resources(struct platform_device *pdev,if (err) goto err_map_reg; + i =irq_of_parse_and_map (pdev->dev.of_node,0 ); +if (i <0 ) { +dev_err (pcie->dev,"cannot get platform resources for msi interrupt\n" ); + err = -ENOENT ; + goto err_map_reg; + } + pcie->msi.irq1 = i; + + i =irq_of_parse_and_map (pdev->dev.of_node,1 ); +if (i <0 ) { +dev_err (pcie->dev,"cannot get platform resources for msi interrupt\n" ); + err = -ENOENT ; + goto err_map_reg; + } + pcie->msi.irq2 = i; + pcie->base =devm_ioremap_resource (&pdev->dev, &res);if (IS_ERR (pcie->base)) { err =PTR_ERR (pcie->base);
@@ -657,6 +883,16 @@ static int __init rcar_pcie_probe(struct platform_device *pdev)if (err)return err; +if (IS_ENABLED (CONFIG_PCI_MSI )) { + err =rcar_pcie_enable_msi (pcie); +if (err <0 ) { +dev_err (&pdev->dev, +"failed to enable MSI support: %d\n" , + err); +return err; + } + } + of_id =of_match_device (rcar_pcie_of_match, pcie->dev);if (!of_id || !of_id->data)return -EINVAL ;
drivers/pci/host/pcie-rcar.h +5 -0
@@ -13,6 +13,7 @@#define PCIEMSR 0x000028#define PCIEINTXR 0x000400#define PCIEPHYSR 0x0007f0 +#define PCIEMSITXR 0x000840/* Transfer control */ #define PCIETCTLR 0x02000
@@ -28,6 +29,10 @@#define PCIEPMSR 0x02034#define PCIEPMSCIER 0x02038#define PCIEMSIFR 0x02044 +#define PCIEMSIALR 0x02048 +#define MSIFE 1 +#define PCIEMSIAUR 0x0204c +#define PCIEMSIIER 0x02050/* root port address */ #define PCIEPRAR (x) (0x02080 + ((x) * 0x4))
Signature · 1 line
1.9.0
PATCH v7 2/10 PCI: host: rcar: Add MSI support
Am Montag, den 31.03.2014, 11:30 +0100 schrieb Phil Edworthy:
Quoted 2 lines
Signed-off-by Phil Edworthy <[email protected]>
Quoted 354 lines
v6:
- Don't check MSI irq number is valid, as upper level checks this
- Change "Unexpected MSI" msg to debug level
- Reword "Unexpected MSI" comment so that it's one linev5:
- ReturnIRQ_NONEfrom MSI isr when there is no pending MSI
- Add additional interrupt bindings--- drivers/pci/host/pcie-rcar.c | 238 ++++++++++++++++++++++++++++++++++++++++++- drivers/pci/host/pcie-rcar.h | 5 + 2 files changed, 242 insertions(+), 1 deletion(-)drivers/pci/host/pcie-rcar.c +237
-1@@ -15,8 +15,11 @@#include <linux/clk.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/msi.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_pci.h> @@ -28,6 +31,8 @@#define DRV_NAME "rcar-pcie" +#define INT_PCI_MSI_NR 32 +#define RCONF (x) (PCICONF(0)+(x))#define RPMCAP (x) (PMCAP(0)+(x))#define REXPCAP (x) (EXPCAP(0)+(x))@@ -40,6 +45,21 @@#define PCI_MAX_RESOURCES 4#define MAX_NR_INBOUND_MAPS 6 +struct rcar_msi { + DECLARE_BITMAP(used, INT_PCI_MSI_NR); +struct irq_domain *domain; +struct msi_chip chip; +unsigned long pages; +struct mutex lock; +int irq1; +int irq2; +}; + +static inline struct rcar_msi *to_rcar_msi (struct msi_chip *chip) +{ + return container_of(chip, struct rcar_msi, chip); +} +/* Structure representing the PCIe interface */ struct rcar_pcie {struct device *dev;@@ -48,6 +68,7 @@ struct rcar_pcie {u8 root_bus_nr;struct clk *clk;struct clk *bus_clk; +struct rcar_msi msi; };static inline struct rcar_pcie *sys_to_pcie (struct pci_sys_data *sys)@@ -292,6 +313,15 @@ static int rcar_pcie_setup(int nr, struct pci_sys_data *sys)return 1 ; } +static void rcar_pcie_add_bus (struct pci_bus *bus) +{ +if (IS_ENABLED (CONFIG_PCI_MSI )) { +struct rcar_pcie *pcie =sys_to_pcie (bus->sysdata); + + bus->msi = &pcie->msi.chip; + } +} +static void __init rcar_pcie_enable (struct rcar_pcie *pcie) {struct platform_device *pdev =to_platform_device (pcie->dev);@@ -301,6 +331,7 @@ static void __init rcar_pcie_enable(struct rcar_pcie *pcie) .setup = rcar_pcie_setup, .map_irq = of_irq_parse_and_map_pci, .ops = &rcar_pcie_ops, + .add_bus = rcar_pcie_add_bus, };pci_common_init_dev (&pdev->dev, &hw);@@ -408,6 +439,10 @@ static int __init rcar_pcie_hw_init(struct rcar_pcie *pcie)/* Enable MAC data scrambling. */ rcar_rmw32 (pcie,MACCTLR ,SCRAMBLE_DISABLE ,0 ); +/* Enable MSI */ +if (IS_ENABLED (CONFIG_PCI_MSI )) +pci_write_reg (pcie,0x101f0000 ,PCIEMSITXR ); +/* Finish initialization - establish a PCI Express link */ pci_write_reg (pcie,CFINIT ,PCIETCTLR );@@ -461,11 +496,186 @@ static int __init rcar_pcie_hw_init_h1(struct rcar_pcie *pcie)return -ETIMEDOUT ; } +static int rcar_msi_alloc (struct rcar_msi *chip) +{ +int msi; + +mutex_lock (&chip->lock); + + msi =find_first_zero_bit (chip->used,INT_PCI_MSI_NR ); +if (msi <INT_PCI_MSI_NR ) +set_bit (msi, chip->used); +else + msi = -ENOSPC ; + +mutex_unlock (&chip->lock); + +return msi; +} + +static void rcar_msi_free (struct rcar_msi *chip,unsigned long irq) +{ +struct device *dev = chip->chip.dev; + +mutex_lock (&chip->lock); +clear_bit (irq, chip->used); +mutex_unlock (&chip->lock); +} + +static irqreturn_t rcar_pcie_msi_irq (int irq,void *data) +{ +struct rcar_pcie *pcie = data; +struct rcar_msi *msi = &pcie->msi; +unsigned long reg; + + reg =pci_read_reg (pcie,PCIEMSIFR ); + +/* MSI & INTx share an interrupt - we only handle MSI here */ +if (!reg) +return IRQ_NONE ; + +while (reg) { +unsigned int index =find_first_bit (®,32 ); +unsigned int irq; + +/* clear the interrupt */ +pci_write_reg (pcie,1 << index,PCIEMSIFR ); + + irq =irq_find_mapping (msi->domain, index); +if (irq) { +if (test_bit (index, msi->used)) +generic_handle_irq (irq); +else +dev_info (pcie->dev,"unhandled MSI\n" ); + }else { +/* Unknown MSI, just clear it */ +dev_dbg (pcie->dev,"unexpected MSI\n" ); + } + +/* see if there's any more pending in this vector */ + reg =pci_read_reg (pcie,PCIEMSIFR ); + } + +return IRQ_HANDLED ; +} + +static int rcar_msi_setup_irq (struct msi_chip *chip,struct pci_dev *pdev, +struct msi_desc *desc) +{ +struct rcar_msi *msi =to_rcar_msi (chip); + struct rcar_pcie *pcie = container_of(chip, struct rcar_pcie, msi.chip); +struct msi_msg msg; +unsigned int irq; +int hwirq; + + hwirq =rcar_msi_alloc (msi); +if (hwirq <0 ) +return hwirq; + + irq =irq_create_mapping (msi->domain, hwirq); +if (!irq) { +rcar_msi_free (msi, hwirq); +return -EINVAL ; + } + +irq_set_msi_desc (irq, desc); + + msg.address_lo =pci_read_reg (pcie,PCIEMSIALR ) & ~MSIFE ; + msg.address_hi =pci_read_reg (pcie,PCIEMSIAUR ); + msg.data = hwirq; + +write_msi_msg (irq, &msg); + +return 0 ; +} + +static void rcar_msi_teardown_irq (struct msi_chip *chip,unsigned int irq) +{ +struct rcar_msi *msi =to_rcar_msi (chip); +struct irq_data *d =irq_get_irq_data (irq); + +rcar_msi_free (msi, d->hwirq); +} + +static struct irq_chip rcar_msi_irq_chip = { + .name ="R-Car PCIe MSI" , + .irq_enable = unmask_msi_irq, + .irq_disable = mask_msi_irq, + .irq_mask = mask_msi_irq, + .irq_unmask = unmask_msi_irq, +}; + +static int rcar_msi_map (struct irq_domain *domain,unsigned int irq, +irq_hw_number_t hwirq) +{ +irq_set_chip_and_handler (irq, &rcar_msi_irq_chip, handle_simple_irq); +irq_set_chip_data (irq, domain->host_data); +set_irq_flags (irq,IRQF_VALID ); + +return 0 ; +} + +static const struct irq_domain_ops msi_domain_ops = { + .map = rcar_msi_map, +}; + +static int rcar_pcie_enable_msi (struct rcar_pcie *pcie) +{ +struct platform_device *pdev =to_platform_device (pcie->dev); +struct rcar_msi *msi = &pcie->msi; +unsigned long base; +int err; + +mutex_init (&msi->lock); + + msi->chip.dev = pcie->dev; + msi->chip.setup_irq = rcar_msi_setup_irq; + msi->chip.teardown_irq = rcar_msi_teardown_irq; + + msi->domain =irq_domain_add_linear (pcie->dev->of_node,INT_PCI_MSI_NR , + &msi_domain_ops, &msi->chip); +if (!msi->domain) { +dev_err (&pdev->dev,"failed to create IRQ domain\n" ); +return -ENOMEM ; + } + +/* Two irqs are for MSI, but they are also used for non-MSI irqs */ + err =devm_request_irq (&pdev->dev, msi->irq1, rcar_pcie_msi_irq, +IRQF_SHARED , rcar_msi_irq_chip.name, pcie); +if (err <0 ) { +dev_err (&pdev->dev,"failed to request IRQ: %d\n" , err); + goto err; + } + + err =devm_request_irq (&pdev->dev, msi->irq2, rcar_pcie_msi_irq, +IRQF_SHARED , rcar_msi_irq_chip.name, pcie); +if (err <0 ) { +dev_err (&pdev->dev,"failed to request IRQ: %d\n" , err); + goto err; + } + +/* setup MSI data target */ + msi->pages =__get_free_pages (GFP_KERNEL ,0 ); + base =virt_to_phys ((void *)msi->pages); + +pci_write_reg (pcie, base |MSIFE ,PCIEMSIALR ); +pci_write_reg (pcie,0 ,PCIEMSIAUR ); + +/* enable all MSI interrupts */ +pci_write_reg (pcie,0xffffffff ,PCIEMSIIER ); + +return 0 ; + +err: +irq_domain_remove (msi->domain); +return err; +} +static int __init rcar_pcie_get_resources (struct platform_device *pdev,struct rcar_pcie *pcie) {struct resource res; -int err; +int err, i; err =of_address_to_resource (pdev->dev.of_node,0 , &res);if (err)@@ -490,6 +700,22 @@ static int __init rcar_pcie_get_resources(struct platform_device *pdev,if (err) goto err_map_reg; + i =irq_of_parse_and_map (pdev->dev.of_node,0 ); +if (i <0 ) { +dev_err (pcie->dev,"cannot get platform resources for msi interrupt\n" ); + err = -ENOENT ; + goto err_map_reg; + } + pcie->msi.irq1 = i; + + i =irq_of_parse_and_map (pdev->dev.of_node,1 ); +if (i <0 ) { +dev_err (pcie->dev,"cannot get platform resources for msi interrupt\n" ); + err = -ENOENT ; + goto err_map_reg; + } + pcie->msi.irq2 = i; + pcie->base =devm_ioremap_resource (&pdev->dev, &res);if (IS_ERR (pcie->base)) { err =PTR_ERR (pcie->base);@@ -657,6 +883,16 @@ static int __init rcar_pcie_probe(struct platform_device *pdev)if (err)return err; +if (IS_ENABLED (CONFIG_PCI_MSI )) { + err =rcar_pcie_enable_msi (pcie); +if (err <0 ) { +dev_err (&pdev->dev, +"failed to enable MSI support: %d\n" , + err); +return err; + } + } + of_id =of_match_device (rcar_pcie_of_match, pcie->dev);if (!of_id || !of_id->data)return -EINVAL ;drivers/pci/host/pcie-rcar.h +5
-0@@ -13,6 +13,7 @@#define PCIEMSR 0x000028#define PCIEINTXR 0x000400#define PCIEPHYSR 0x0007f0 +#define PCIEMSITXR 0x000840/* Transfer control */ #define PCIETCTLR 0x02000@@ -28,6 +29,10 @@#define PCIEPMSR 0x02034#define PCIEPMSCIER 0x02038#define PCIEMSIFR 0x02044 +#define PCIEMSIALR 0x02048 +#define MSIFE 1 +#define PCIEMSIAUR 0x0204c +#define PCIEMSIIER 0x02050/* root port address */ #define PCIEPRAR (x) (0x02080 + ((x) * 0x4))
Signature · 4 lines
Pengutronix e.K. | Lucas Stach | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-5076 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
PATCH v7 3/10 ARM: shmobile: r8a7790: Add PCIe clock device tree nodes
In reply to Phil EdworthyThis patch adds the device tree clock nodes for PCIe
--- arch/arm/boot/dts/r8a7790.dtsi | 7 ++++--- include/dt-bindings/clock/r8a7790-clock.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-)
arch/arm/boot/dts/r8a7790.dtsi +4 -3
@@ -704,16 +704,17 @@ reg = <0 0xe615013c 0 4>, <0 0xe6150048 0 4>; clocks = <&cp_clk>, <&mmc1_clk>, <&sd3_clk>, <&sd2_clk>, <&cpg_clocks R8A7790_CLK_SD1>, <&cpg_clocks R8A7790_CLK_SD0>, - <&mmc0_clk>, <&rclk_clk>; + <&mmc0_clk>, <&rclk_clk>, <&mp_clk>; #clock-cells = <1>; renesas,clock-indices = < R8A7790_CLK_TPU0 R8A7790_CLK_MMCIF1 R8A7790_CLK_SDHI3 R8A7790_CLK_SDHI2 R8A7790_CLK_SDHI1 R8A7790_CLK_SDHI0 - R8A7790_CLK_MMCIF0 R8A7790_CLK_CMT1 + R8A7790_CLK_MMCIF0 R8A7790_CLK_CMT1 R8A7790_CLK_PCIE >; clock-output-names = "tpu0", "mmcif1", "sdhi3", "sdhi2", - "sdhi1", "sdhi0", "mmcif0", "cmt1"; + "sdhi1", "sdhi0", "mmcif0", "cmt1", + "pcie"; }; mstp5_clks: mstp5_clks at e6150144 { compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks";
include/dt-bindings/clock/r8a7790-clock.h +1 -0
@@ -57,6 +57,7 @@#define R8A7790_CLK_SDHI1 13#define R8A7790_CLK_SDHI0 14#define R8A7790_CLK_MMCIF0 15 +#define R8A7790_CLK_PCIE 19#define R8A7790_CLK_SSUSB 28#define R8A7790_CLK_CMT1 29#define R8A7790_CLK_USBDMAC0 30
Signature · 1 line
1.9.0
PATCH v7 4/10 ARM: shmobile: r8a7791: Add PCIe clock device tree nodes
In reply to Phil EdworthyThis patch adds the device tree clock nodes for PCIe
--- arch/arm/boot/dts/r8a7791.dtsi | 7 +++++-- include/dt-bindings/clock/r8a7791-clock.h | 1 + 2 files changed, 6 insertions(+), 2 deletions(-)
arch/arm/boot/dts/r8a7791.dtsi +5 -2
@@ -717,14 +717,17 @@ compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe615013c 0 4>, <0 0xe6150048 0 4>; clocks = <&cp_clk>, <&sd2_clk>, <&sd1_clk>, - <&cpg_clocks R8A7791_CLK_SD0>, <&mmc0_clk>, <&rclk_clk>; + <&cpg_clocks R8A7791_CLK_SD0>, <&mmc0_clk>, <&rclk_clk>, + <&mp_clk>; #clock-cells = <1>; renesas,clock-indices = < R8A7791_CLK_TPU0 R8A7791_CLK_SDHI2 R8A7791_CLK_SDHI1 R8A7791_CLK_SDHI0 R8A7791_CLK_MMCIF0 R8A7791_CLK_CMT1 + R8A7791_CLK_PCIE >; clock-output-names = - "tpu0", "sdhi2", "sdhi1", "sdhi0", "mmcif0", "cmt1"; + "tpu0", "sdhi2", "sdhi1", "sdhi0", "mmcif0", "cmt1", + "pcie"; }; mstp5_clks: mstp5_clks at e6150144 { compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
include/dt-bindings/clock/r8a7791-clock.h +1 -0
@@ -51,6 +51,7 @@#define R8A7791_CLK_SDHI1 12#define R8A7791_CLK_SDHI0 14#define R8A7791_CLK_MMCIF0 15 +#define R8A7791_CLK_PCIE 19#define R8A7791_CLK_SSUSB 28#define R8A7791_CLK_CMT1 29#define R8A7791_CLK_USBDMAC0 30
Signature · 1 line
1.9.0
PATCH v7 5/10 dt-bindings: pci: rcar pcie device tree bindings
In reply to Phil EdworthyThis patch adds the bindings for the R-Car PCIe driver. The driver resides under drivers/pci/host/pcie-rcar.c
v7:
- Change binding description of clocks to 'clock specifiers'
v6:
- Correct DT bindings description for reg and clocks
v5:
- Add PCIe bus clock reference
- Add additional interrupt bindings
- Use dma-ranges property to specify inbound memory regions
--- Documentation/devicetree/bindings/pci/rcar-pci.txt | 45 ++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/rcar-pci.txt
Documentation/devicetree/bindings/pci/rcar-pci.txt new file +45 -0
@@ -0,0 +1,45 @@ +* Renesas RCar PCIe interface + +Required properties: +- compatible: should contain one of the following + "renesas,pcie-r8a7779", "renesas,pcie-r8a7790", "renesas,pcie-r8a7791" +- reg: base address and length of the pcie controller registers. +- #address-cells: set to <3> +- #size-cells: set to <2> +- device_type: set to "pci" +- ranges: ranges for the PCI memory and I/O regions. +- dma-ranges: ranges for the inbound memory regions. +- interrupts: two interrupt sources for MSI interrupts, followed by interrupt + source for hardware related interrupts (e.g. link speed change). +- #interrupt-cells: set to <1> +- interrupt-map-mask and interrupt-map: standard PCI properties + to define the mapping of the PCIe interface to interrupt + numbers. +- clocks: from common clock binding: clock specifiers for the PCIe controller + and PCIe bus clocks. +- clock-names: from common clock binding: should be "pcie" and "pcie_bus". + +Example: + +SoC specific DT Entry: + + pcie: pcie at fe000000 { + compatible = "renesas,pcie-r8a7791"; + reg = <0 0xfe000000 0 0x80000>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000 + 0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000 + 0x02000000 0 0x30000000 0 0x30000000 0 0x08000000 + 0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>; + dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x40000000 + 0x42000000 2 0x00000000 2 0x00000000 0 0x40000000>; + interrupts = <0 116 4 0 117 4 0 118 4>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic 0 116 4>; + clocks = <&mstp3_clks R8A7791_CLK_PCIE>, <&pcie_bus_clk>; + clock-names = "pcie", "pcie_bus"; + status = "disabled"; + };
Signature · 1 line
1.9.0
PATCH v7 5/10 dt-bindings: pci: rcar pcie device tree bindings
Am Montag, den 31.03.2014, 11:30 +0100 schrieb Phil Edworthy:
Quoted 4 lines
This patch adds the bindings for the R-Car PCIe driver. The driver resides under
drivers/pci/host/pcie-rcar.cSigned-off-by Phil Edworthy <[email protected]>
Another nitpick below, otherwise:
If you decide to roll another version with just this changed, feel free to carry over the my tag.
Quoted 50 lines
v7:
- Change binding description of clocks to 'clock specifiers'v6:
- Correct DT bindings description for reg and clocksv5:
- Add PCIe bus clock reference
- Add additional interrupt bindings
- Use dma-ranges property to specify inbound memory regions--- Documentation/devicetree/bindings/pci/rcar-pci.txt | 45 ++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/rcar-pci.txtDocumentation/devicetree/bindings/pci/rcar-pci.txt new file +28
-0@@ -0,0 +1,45 @@ +* Renesas RCar PCIe interface + +Required properties: +- compatible: should contain one of the following + "renesas,pcie-r8a7779", "renesas,pcie-r8a7790", "renesas,pcie-r8a7791" +- reg: base address and length of the pcie controller registers. +- #address-cells: set to <3> +- #size-cells: set to <2> +- device_type: set to "pci" +- ranges: ranges for the PCI memory and I/O regions. +- dma-ranges: ranges for the inbound memory regions. +- interrupts: two interrupt sources for MSI interrupts, followed by interrupt + source for hardware related interrupts (e.g. link speed change). +- #interrupt-cells: set to <1> +- interrupt-map-mask and interrupt-map: standard PCI properties + to define the mapping of the PCIe interface to interrupt + numbers. +- clocks: from common clock binding: clock specifiers for the PCIe controller + and PCIe bus clocks. +- clock-names: from common clock binding: should be "pcie" and "pcie_bus". + +Example: + +SoC specific DT Entry: + + pcie: pcie at fe000000 { + compatible = "renesas,pcie-r8a7791"; + reg = <0 0xfe000000 0 0x80000>;
Documentation/devicetree/bindings/pci/rcar-pci.txt line 38
Quoted 10 lines
Documentation/devicetree/bindings/pci/rcar-pci.txt new file +10
-0+ #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000 + 0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000 + 0x02000000 0 0x30000000 0 0x30000000 0 0x08000000 + 0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>; + dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x40000000 + 0x42000000 2 0x00000000 2 0x00000000 0 0x40000000>; + interrupts = <0 116 4 0 117 4 0 118 4>;
I think this is confusing, I would rather like to see them in separate cells, like
interrupts = <0 116 4>, <0 117 4>, <0 118 4>;
Same would be true for the ranges properties, but there it isn't as confusing, so I don't really care.
Quoted 7 lines
Documentation/devicetree/bindings/pci/rcar-pci.txt new file +7
-0+ #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic 0 116 4>; + clocks = <&mstp3_clks R8A7791_CLK_PCIE>, <&pcie_bus_clk>; + clock-names = "pcie", "pcie_bus"; + status = "disabled"; + };
Signature · 4 lines
Pengutronix e.K. | Lucas Stach | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-5076 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
PATCH v7 6/10 ARM: shmobile: r8a7790: Add PCIe device nodes
In reply to Phil Edworthyv6:
- Split device and board DT changes
--- arch/arm/boot/dts/r8a7790.dtsi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
arch/arm/boot/dts/r8a7790.dtsi +24 -0
@@ -821,4 +821,28 @@ #size-cells = <0>; status = "disabled"; }; + + pcie: pcie at fe000000 { + compatible = "renesas,pcie-r8a7790"; + reg = <0 0xfe000000 0 0x80000>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000 + 0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000 + 0x02000000 0 0x30000000 0 0x30000000 0 0x08000000 + 0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>; + /* Map all possible DDR as inbound ranges */ + dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x80000000 + 0x43000000 1 0x80000000 1 0x80000000 0 0x80000000>; + interrupts = <0 116 IRQ_TYPE_LEVEL_HIGH + 0 117 IRQ_TYPE_LEVEL_HIGH + 0 118 IRQ_TYPE_LEVEL_HIGH>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic 0 116 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp3_clks R8A7790_CLK_PCIE>, <&pcie_bus_clk>; + clock-names = "pcie", "pcie_bus"; + status = "disabled"; + }; };
Signature · 1 line
1.9.0
PATCH v7 7/10 ARM: shmobile: lager: Add PCIe device nodes
In reply to Phil Edworthyv6:
- Split device and board DT changes
--- arch/arm/boot/dts/r8a7790-lager.dts | 10 ++++++++++ 1 file changed, 10 insertions(+)
arch/arm/boot/dts/r8a7790-lager.dts +10 -0
@@ -139,6 +139,16 @@ states = <3300000 1 1800000 0>; }; + + clocks { + /* External PCIe bus clock - not used */ + pcie_bus_clk: pcie_bus_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "pcie_bus"; + }; + }; }; &extal_clk {
Signature · 1 line
1.9.0
PATCH v7 8/10 ARM: shmobile: r8a7791: Add PCIe device nodes
In reply to Phil Edworthyv6:
- Split device and board DT changes
--- arch/arm/boot/dts/r8a7791.dtsi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
arch/arm/boot/dts/r8a7791.dtsi +24 -0
@@ -836,4 +836,28 @@ #size-cells = <0>; status = "disabled"; }; + + pcie: pcie at fe000000 { + compatible = "renesas,pcie-r8a7791"; + reg = <0 0xfe000000 0 0x80000>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000 + 0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000 + 0x02000000 0 0x30000000 0 0x30000000 0 0x08000000 + 0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>; + /* Map all possible DDR as inbound ranges */ + dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x80000000 + 0x43000000 2 0x00000000 2 0x00000000 1 0x00000000>; + interrupts = <0 116 IRQ_TYPE_LEVEL_HIGH + 0 117 IRQ_TYPE_LEVEL_HIGH + 0 118 IRQ_TYPE_LEVEL_HIGH>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic 0 116 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp3_clks R8A7791_CLK_PCIE>, <&pcie_bus_clk>; + clock-names = "pcie", "pcie_bus"; + status = "disabled"; + }; };
Signature · 1 line
1.9.0
PATCH v7 9/10 ARM: shmobile: koelsch: Add PCIe device nodes
In reply to Phil Edworthyv6:
- Split device and board DT changes
--- arch/arm/boot/dts/r8a7791-koelsch.dts | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
arch/arm/boot/dts/r8a7791-koelsch.dts +14 -0
@@ -204,6 +204,16 @@ states = <3300000 1 1800000 0>; }; + + clocks { + /* External PCIe bus clock */ + pcie_bus_clk: pcie_bus_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "pcie_bus"; + }; + }; }; &extal_clk {
@@ -382,3 +392,7 @@ spi-cpha; }; }; + +&pcie { + status = "okay"; +};
Signature · 1 line
1.9.0
PATCH v7 10/10 ARM: shmobile: koelsch: Add PCIe to defconfig
In reply to Phil Edworthyv6:
- Add shmobile to subject
--- arch/arm/configs/koelsch_defconfig | 3 +++ 1 file changed, 3 insertions(+)
arch/arm/configs/koelsch_defconfig +3 -0
@@ -15,6 +15,9 @@ CONFIG_MACH_KOELSCH=y CONFIG_CPU_BPREDICT_DISABLE=y CONFIG_PL310_ERRATA_588369=y CONFIG_ARM_ERRATA_754322=y +CONFIG_PCI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_RCAR_GEN2_PCIE=y CONFIG_SMP=y CONFIG_SCHED_MC=y CONFIG_NR_CPUS=8
Signature · 1 line
1.9.0
v7 cover R-Car Gen2 PCIe host driver
In reply to Phil EdworthyHi Arnd, Ben, Sergei, Simon, Lucas, Geert, Jason,
Thank you for all your comments - is there anything else, or can I get your reviewed-by on these patches (or at least those that you have looked at)?
Thanks
Phil
Quoted 68 lines · Phil
Subject: [PATCH v7 00/10] R-Car Gen2 PCIe host driver
This is version 7 of a PCIe Host driver for the R-Car Gen2 devices, i.e. R-Car H2 (r8a7790) and R-Car M2 (r8a7791).
v7:
- Change binding description of clocks to 'clock specifiers'v6:
- Correct DT bindings description for reg and clocks
- Split device and board DT changes
- Add shmobile to subject for shmobile DT patches
- Don't check MSI irq number is valid, as upper level checks this
- Change "Unexpected MSI" msg to debug level
- Reword "Unexpected MSI" comment so that it's one line
- Remove patch that addsHAVE_ARM_ARCH_TIMERto koelsch defconfig as
not neededv5:
- Usemodule_platform_driverinstead ofsubsys_initcall
- Use theof_device_iddata field for HW init function
- Inithw_pcistruct in declaration
- Renesas SoC compatible string has peripheral before device name
- Add PCIe bus clock reference
- Use dma-ranges property to specify inbound memory regions
- Support multiple IO windows and correct resources
- ReturnIRQ_NONEfrom MSI isr when there is no pending MSI
- Add additional interrupt bindingsv4:
- Use runtime PM properlyPhil Edworthy (10):
PCI: host: rcar: Add Renesas R-Car PCIe driver
PCI: host: rcar: Add MSI support
ARM: shmobile: r8a7790: Add PCIe clock device tree nodes
ARM: shmobile: r8a7791: Add PCIe clock device tree nodes
dt-bindings: pci: rcar pcie device tree bindings
ARM: shmobile: r8a7790: Add PCIe device nodes
ARM: shmobile: lager: Add PCIe device nodes
ARM: shmobile: r8a7791: Add PCIe device nodes
ARM: shmobile: koelsch: Add PCIe device nodes
ARM: shmobile: koelsch: Add PCIe to defconfigDocumentation/devicetree/bindings/pci/rcar-pci.txt | 45 + arch/arm/boot/dts/r8a7790-lager.dts | 10 + arch/arm/boot/dts/r8a7790.dtsi | 31 +- arch/arm/boot/dts/r8a7791-koelsch.dts | 14 + arch/arm/boot/dts/r8a7791.dtsi | 31 +- arch/arm/configs/koelsch_defconfig | 3 + drivers/pci/host/Kconfig | 6 + drivers/pci/host/Makefile | 1 + drivers/pci/host/pcie-rcar.c | 929 +++++++++++++++++++++ drivers/pci/host/pcie-rcar.h | 87 ++ include/dt-bindings/clock/r8a7790-clock.h | 1 + include/dt-bindings/clock/r8a7791-clock.h | 1 + 12 files changed, 1154 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/pci/rcar-pci.txt create mode 100644 drivers/pci/host/pcie-rcar.c create mode 100644
drivers/pci/host/pcie-rcar.h--
1.9.0--
To unsubscribe from this list: send the line "unsubscribe linux-sh" in the body of a message to majordomo at vger.kernel.org More majordomo info at
http://vger.kernel.org/majordomo-info.html
v7 cover R-Car Gen2 PCIe host driver
In reply to Phil EdworthyHi Bjorn,
I assume that you'll take the PCI driver patches (0001, 0002 & 0005) through your tree and that the rest are platform specific patches that will go via Simon Horman. Would you like me to split this into two separate patch sets?
Thanks
Phil
Quoted 75 lines
-----Original Message-----
From: linux-sh-owner at vger.kernel.org [mailto:linux-sh- owner at vger.kernel.org] On Behalf Of Phil Edworthy
Sent: 31 March 2014 11:31
To: linux-pci at vger.kernel.org
Cc: linux-sh at vger.kernel.org; LAKML; Bjorn Helgaas; Valentine Barshak; Simon Horman; Magnus Damm; Ben Dooks; Phil Edworthy
Subject: [PATCH v7 00/10] R-Car Gen2 PCIe host driverThis is version 7 of a PCIe Host driver for the R-Car Gen2 devices, i.e. R-Car H2 (r8a7790) and R-Car M2 (r8a7791).
v7:
- Change binding description of clocks to 'clock specifiers'v6:
- Correct DT bindings description for reg and clocks
- Split device and board DT changes
- Add shmobile to subject for shmobile DT patches
- Don't check MSI irq number is valid, as upper level checks this
- Change "Unexpected MSI" msg to debug level
- Reword "Unexpected MSI" comment so that it's one line
- Remove patch that addsHAVE_ARM_ARCH_TIMERto koelsch defconfig as
not neededv5:
- Usemodule_platform_driverinstead ofsubsys_initcall
- Use theof_device_iddata field for HW init function
- Inithw_pcistruct in declaration
- Renesas SoC compatible string has peripheral before device name
- Add PCIe bus clock reference
- Use dma-ranges property to specify inbound memory regions
- Support multiple IO windows and correct resources
- ReturnIRQ_NONEfrom MSI isr when there is no pending MSI
- Add additional interrupt bindingsv4:
- Use runtime PM properlyPhil Edworthy (10):
PCI: host: rcar: Add Renesas R-Car PCIe driver
PCI: host: rcar: Add MSI support
ARM: shmobile: r8a7790: Add PCIe clock device tree nodes
ARM: shmobile: r8a7791: Add PCIe clock device tree nodes
dt-bindings: pci: rcar pcie device tree bindings
ARM: shmobile: r8a7790: Add PCIe device nodes
ARM: shmobile: lager: Add PCIe device nodes
ARM: shmobile: r8a7791: Add PCIe device nodes
ARM: shmobile: koelsch: Add PCIe device nodes
ARM: shmobile: koelsch: Add PCIe to defconfigDocumentation/devicetree/bindings/pci/rcar-pci.txt | 45 + arch/arm/boot/dts/r8a7790-lager.dts | 10 + arch/arm/boot/dts/r8a7790.dtsi | 31 +- arch/arm/boot/dts/r8a7791-koelsch.dts | 14 + arch/arm/boot/dts/r8a7791.dtsi | 31 +- arch/arm/configs/koelsch_defconfig | 3 + drivers/pci/host/Kconfig | 6 + drivers/pci/host/Makefile | 1 + drivers/pci/host/pcie-rcar.c | 929 +++++++++++++++++++++ drivers/pci/host/pcie-rcar.h | 87 ++ include/dt-bindings/clock/r8a7790-clock.h | 1 + include/dt-bindings/clock/r8a7791-clock.h | 1 + 12 files changed, 1154 insertions(+), 5 deletions(-) create mode 100644 Documentation/devicetree/bindings/pci/rcar-pci.txt create mode 100644 drivers/pci/host/pcie-rcar.c create mode 100644
drivers/pci/host/pcie-rcar.h--
1.9.0--
To unsubscribe from this list: send the line "unsubscribe linux-sh" in the body of a message to majordomo at vger.kernel.org More majordomo info at
http://vger.kernel.org/majordomo-info.html