s390/pci: PCI support on System z
Subsystems (10)
cover s390/pci: PCI support on System z
Hi,
this patchset based on 3.7-rc4 aims at adding PCI(e) support to the System z (s390) architecture. PCI is currently not available on s390, so this is early prototype code.
I'm posting in the hope to get some feedback and direction on the more humble aspects of it.
Patches 01-05 are only split to ease the review, they belong functional together and don't make much sense without each other.
PCI on the mainframe differs in some aspects from PCI on other platforms.
The most notable difference is the use of instructions for memory mapped IO. So on s390 the BAR spaces cannot be mapped to memory. To access the BAR spaces privileged instructions must be used (how that will be addressed for user-space is not part of this patchset). See patch 01 for how the read/write pci primitives are mapped to the s390 instructions.
Another difference is that the addresses of BARs from two different PCI functions may be identical. That means we can't distinguish from an iomem address which PCI device the address belongs to. Therefore s390 needs a custom implementation of pci_iomap to remap iomem addresses using the bar and device information provided by pci_iomap.
Device naming - the topology on System z is that every PCI function is attached directly to a PCI root complex. Therefore we decided to use a domain number per function and leave the bus, slot and function 0.
Next one - IRQs. s390 will use its existing adapter interrupt infrastructure to deliver MSI/MSI-X interrupts. Legacy INTs are _not_ supported at all. The only thing that s390 needs is to close the gap between adapter interrupts and MSI, in other words to locate a struct msi_desc from an IRQ number. For that I've implemented a simple hash, see patch 04.
Then there is Kconfig, see patch 09, which gives s390 a bunch of options that we would rather avoid. Like VGA support, sound subsystem, etc. I do not have a solution how to disable these subsystems. We would like to limit the subsystems that become available on s390 because the usable PCI hardware will be limited to a small number of hand-picked and supported PCI cards.
There are several options I can imagine:
a) Don't disable anything - that would result in lots of drivers builtable on s390 that are not supported and weird error reports
b) Introduce negative options for whole subsystems like we have already with NO_IOPORT, so maybe NO_USB, NO_SOUND, ...
c) Introduce a special CONFIG_PCI_S390 and add that explicitely to all subsystems that we want to enable on s390
None of the above looks like the obvious winner to me.
Hope to get some feedback,
TIA, Jan
Jan Glauber (10):
s390/pci: base support
s390/pci: CLP interface
s390/bitops: find leftmost bit instruction support s390/pci: PCI adapter interrupts for MSI/MSI-X s390/pci: DMA support
s390/pci: CHSC PCI support for error and availability events s390/pci: PCI hotplug support via SCLP
s390/pci: s390 specific PCI sysfs attributes s390/pci: add PCI Kconfig options
vga: compile fix, disable vga for s390
arch/s390/Kbuild | 1 + arch/s390/Kconfig | 56 +- arch/s390/include/asm/bitops.h | 81 +++ arch/s390/include/asm/clp.h | 28 + arch/s390/include/asm/dma-mapping.h | 76 +++ arch/s390/include/asm/dma.h | 19 +- arch/s390/include/asm/hw_irq.h | 22 + arch/s390/include/asm/io.h | 55 +- arch/s390/include/asm/irq.h | 12 + arch/s390/include/asm/isc.h | 1 + arch/s390/include/asm/pci.h | 156 ++++- arch/s390/include/asm/pci_clp.h | 182 ++++++ arch/s390/include/asm/pci_dma.h | 196 +++++++ arch/s390/include/asm/pci_insn.h | 280 +++++++++ arch/s390/include/asm/pci_io.h | 194 +++++++ arch/s390/include/asm/sclp.h | 2 + arch/s390/kernel/dis.c | 15 + arch/s390/kernel/irq.c | 2 + arch/s390/pci/Makefile | 6 + arch/s390/pci/pci.c | 1098 +++++++++++++++++++++++++++++++++++ arch/s390/pci/pci_clp.c | 324 +++++++++++ arch/s390/pci/pci_dma.c | 505 ++++++++++++++++ arch/s390/pci/pci_event.c | 93 +++ arch/s390/pci/pci_msi.c | 141 +++++ arch/s390/pci/pci_sysfs.c | 86 +++ drivers/gpu/vga/Kconfig | 2 +- drivers/pci/hotplug/Kconfig | 11 + drivers/pci/hotplug/Makefile | 1 + drivers/pci/hotplug/s390_pci_hpc.c | 252 ++++++++ drivers/pci/msi.c | 10 +- drivers/s390/char/sclp.h | 3 +- drivers/s390/char/sclp_cmd.c | 64 +- drivers/s390/cio/chsc.c | 156 +++-- include/asm-generic/io.h | 21 +- include/linux/irq.h | 10 +- include/video/vga.h | 2 + 36 files changed, 4084 insertions(+), 79 deletions(-) create mode 100644 arch/s390/include/asm/clp.h create mode 100644 arch/s390/include/asm/dma-mapping.h create mode 100644 arch/s390/include/asm/hw_irq.h create mode 100644 arch/s390/include/asm/pci_clp.h create mode 100644 arch/s390/include/asm/pci_dma.h create mode 100644 arch/s390/include/asm/pci_insn.h create mode 100644 arch/s390/include/asm/pci_io.h create mode 100644 arch/s390/pci/Makefile create mode 100644 arch/s390/pci/pci.c create mode 100644 arch/s390/pci/pci_clp.c create mode 100644 arch/s390/pci/pci_dma.c create mode 100644 arch/s390/pci/pci_event.c create mode 100644 arch/s390/pci/pci_msi.c create mode 100644 arch/s390/pci/pci_sysfs.c create mode 100644 drivers/pci/hotplug/s390_pci_hpc.c
Signature · 1 line
1.7.12.4
RFC PATCH 1/10 s390/pci: base support
Add PCI support for s390, (only 64 bit mode is supported by hardware):
- PCI facility tests
- PCI instructions: pcilg, pcistg, pcistb, stpcifc, mpcifc, rpcit
- map readb/w/l/q and writeb/w/l/q to pcilg and pcistg instructions
- pci_iomap implementation
- memcpy_fromio/toio
- pci_root_ops using special pcilg/pcistg
- device, bus and domain allocation
--- arch/s390/Kbuild | 1 + arch/s390/include/asm/io.h | 55 +++- arch/s390/include/asm/pci.h | 82 +++++- arch/s390/include/asm/pci_insn.h | 280 ++++++++++++++++++++ arch/s390/include/asm/pci_io.h | 194 ++++++++++++++ arch/s390/kernel/dis.c | 15 ++ arch/s390/pci/Makefile | 5 + arch/s390/pci/pci.c | 557 +++++++++++++++++++++++++++++++++++++++ include/asm-generic/io.h | 21 +- 9 files changed, 1201 insertions(+), 9 deletions(-) create mode 100644 arch/s390/include/asm/pci_insn.h create mode 100644 arch/s390/include/asm/pci_io.h create mode 100644 arch/s390/pci/Makefile create mode 100644 arch/s390/pci/pci.c
arch/s390/Kbuild +1 -0
@@ -6,3 +6,4 @@ obj-$(CONFIG_S390_HYPFS_FS) += hypfs/ obj-$(CONFIG_APPLDATA_BASE) += appldata/ obj-$(CONFIG_MATHEMU) += math-emu/ obj-y += net/ +obj-$(CONFIG_PCI) += pci/
arch/s390/include/asm/io.h +51 -4
74 lines not on this page · raw message
arch/s390/include/asm/pci.h +78 -4
88 lines not on this page · raw message
arch/s390/include/asm/pci_insn.h new file +280 -0
280 lines not on this page · raw message
arch/s390/include/asm/pci_io.h new file +194 -0
194 lines not on this page · raw message
arch/s390/kernel/dis.c +15 -0
@@ -320,6 +320,10 @@ enum {LONG_INSN_TABORT ,LONG_INSN_TBEGIN ,LONG_INSN_TBEGINC , +LONG_INSN_PCISTG , +LONG_INSN_MPCIFC , +LONG_INSN_STPCIFC , + LONG_INSN_PCISTB, }; static char *long_insn_name[] = {
@@ -340,6 +344,10 @@ static char *long_insn_name[] = { [LONG_INSN_TABORT] = "tabort", [LONG_INSN_TBEGIN] = "tbegin", [LONG_INSN_TBEGINC] = "tbeginc", + [LONG_INSN_PCISTG] = "pcistg", + [LONG_INSN_MPCIFC] = "mpcifc", + [LONG_INSN_STPCIFC] = "stpcifc", + [LONG_INSN_PCISTB] = "pcistb", };static struct insn opcode[] = {
@@ -946,6 +954,9 @@ static struct insn opcode_b9[] = { { "slhhh", 0xcb, INSTR_RRF_R0RR2 }, { "chhr ", 0xcd, INSTR_RRE_RR }, { "clhhr", 0xcf, INSTR_RRE_RR }, + { { 0, LONG_INSN_PCISTG }, 0xd0, INSTR_RRE_RR }, + { "pcilg", 0xd2, INSTR_RRE_RR }, + { "rpcit", 0xd3, INSTR_RRE_RR }, { "ahhlr", 0xd8, INSTR_RRF_R0RR2 }, { "shhlr", 0xd9, INSTR_RRF_R0RR2 }, { "slhhl", 0xdb, INSTR_RRF_R0RR2 },
@@ -1175,6 +1186,8 @@ static struct insn opcode_e3[] = { { "chf", 0xcd, INSTR_RXY_RRRD }, { "clhf", 0xcf, INSTR_RXY_RRRD }, { "ntstg", 0x25, INSTR_RXY_RRRD }, + { { 0, LONG_INSN_MPCIFC }, 0xd0, INSTR_RXY_RRRD }, + { { 0, LONG_INSN_STPCIFC }, 0xd4, INSTR_RXY_RRRD }, #endif { "lrv", 0x1e, INSTR_RXY_RRRD }, { "lrvh", 0x1f, INSTR_RXY_RRRD },
@@ -1254,6 +1267,8 @@ static struct insn opcode_eb[] = { { "alsi", 0x6e, INSTR_SIY_IRD }, { "algsi", 0x7e, INSTR_SIY_IRD }, { "ecag", 0x4c, INSTR_RSY_RRRD }, + { { 0, LONG_INSN_PCISTB }, 0xd0, INSTR_RSY_RRRD }, + { "sic", 0xd1, INSTR_RSY_RRRD }, { "srak", 0xdc, INSTR_RSY_RRRD }, { "slak", 0xdd, INSTR_RSY_RRRD }, { "srlk", 0xde, INSTR_RSY_RRRD },
arch/s390/pci/Makefile new file +5 -0
@@ -0,0 +1,5 @@ +# +# Makefile for the s390 PCI subsystem. +# + +obj-$(CONFIG_PCI) += pci.o
arch/s390/pci/pci.c new file +557 -0
557 lines not on this page · raw message
include/asm-generic/io.h +20 -1
@@ -83,19 +83,25 @@ static inline void __raw_writel(u32 b, volatile void __iomem *addr)#define writel (b,addr) __raw_writel(__cpu_to_le32(b),addr)#ifdef CONFIG_64BIT +#ifndef __raw_readqstatic inline u64 __raw_readq (const volatile void __iomem *addr) {return *(const volatile u64 __force *) addr; } +#endif +#define readq (addr) __le64_to_cpu(__raw_readq(addr)) +#ifndef __raw_writeqstatic inline void __raw_writeq (u64 b,volatile void __iomem *addr) { *(volatile u64 __force *) addr = b; } -#define writeq (b,addr) __raw_writeq(__cpu_to_le64(b),addr)#endif +#define writeq (b, addr) __raw_writeq(__cpu_to_le64(b), addr) +#endif /* CONFIG_64BIT */ +#ifndef PCI_IOBASE #define PCI_IOBASE ((void __iomem *) 0)#endif
@@ -286,15 +292,20 @@ static inline void writesb(const void __iomem *addr, const void *buf, int len)#ifndef CONFIG_GENERIC_IOMAP struct pci_dev ; +extern void __iomem *pci_iomap (struct pci_dev *dev,int bar,unsigned long max); + +#ifndef pci_iounmapstatic inline void pci_iounmap (struct pci_dev *dev,void __iomem *p) { } +#endif #endif /* CONFIG_GENERIC_IOMAP */ /* * Change virtual addresses to physical addresses and vv. * These are pretty trivial */ +#ifndef virt_to_physstatic inline unsigned long virt_to_phys (volatile void *address) {return __pa ((unsigned long )address);
@@ -304,6 +315,7 @@ static inline void *phys_to_virt(unsigned long address) {return __va (address); } +#endif /* * Change "struct page" to physical address.
@@ -363,9 +375,16 @@ static inline void *bus_to_virt(unsigned long address) }#endif +#ifndef memset_io#define memset_io (a, b, c) memset(__io_virt(a), (b), (c)) +#endif + +#ifndef memcpy_fromio#define memcpy_fromio (a, b, c) memcpy((a), __io_virt(b), (c)) +#endif +#ifndef memcpy_toio#define memcpy_toio (a, b, c) memcpy(__io_virt(a), (b), (c)) +#endif #endif /* __KERNEL__ */
Signature · 1 line
1.7.12.4
Bjorn Helgaas
maintainerRe: [RFC PATCH 01/10] s390/pci: base support
Quoted 10 lines · Jan Glauber
Add PCI support for s390, (only 64 bit mode is supported by hardware):
- PCI facility tests
- PCI instructions: pcilg, pcistg, pcistb, stpcifc, mpcifc, rpcit
- map readb/w/l/q and writeb/w/l/q to pcilg and pcistg instructions
-pci_iomapimplementation
- memcpy_fromio/toio
-pci_root_opsusing special pcilg/pcistg
- device, bus and domain allocationSigned-off-by Jan Glauber <[email protected]>
I think these patches are in -next already, so I just have some general comments & questions.
My overall impression is that these are exceptionally well done. They're easy to read, well organized, and well documented. It's a refreshing change from a lot of the stuff that's posted.
As with other arches that run on top of hypervisors, you have arch-specific code that enumerates PCI devices using hypervisor calls, and you hook into the PCI core at a lower level than pci_scan_root_bus(). That is, you call pci_create_root_bus(), pci_scan_single_device(), pci_bus_add_devices(), etc., directly from the arch code. This is the typical approach, but it does make more dependencies between the arch code and the PCI core than I'd like.
Did you consider hiding any of the hypervisor details behind the PCI config accessor interface? If that could be done, the overall structure might be more similar to other architectures.
The current config accessors only work for dev/fn 00.0 (they fail when "devfn != ZPCI_DEVFN"). Why is that? It looks like it precludes multi-function devices and basically prevents you from building an arbitrary PCI hierarchy.
zpci_map_resources() is very unusual. The struct pci_dev resource[] table normally contains CPU physical addresses, but zpci_map_resources() fills it with virtual addresses. I suspect this has something to do with the "BAR spaces are not disjunctive on s390" comment. It almost sounds like that's describing host bridges where the PCI bus address is not equal to the CPU physical address -- in that case, device A and device B may have the same values in their BARs, but they can still be distinct if they're under host bridges that apply different CPU-to-bus address translations.
Bjorn
Re: [RFC PATCH 01/10] s390/pci: base support
Quoted 10 lines · Bjorn Helgaas
Quoted 9 lines · Jan Glauber
Add PCI support for s390, (only 64 bit mode is supported by hardware):
- PCI facility tests
- PCI instructions: pcilg, pcistg, pcistb, stpcifc, mpcifc, rpcit
- map readb/w/l/q and writeb/w/l/q to pcilg and pcistg instructions
-pci_iomapimplementation
- memcpy_fromio/toio
-pci_root_opsusing special pcilg/pcistg
- device, bus and domain allocation
Quoted 4 lines
Quoted 1 line
Signed-off-by Jan Glauber <[email protected]>I think these patches are in -next already, so I just have some general comments & questions.
Yes, since the feedback was manageable we decided to give the patches some exposure in -next and if no one complains we'll just go for the next merge window. BTW, Sebastian & Gerald (on CC:) will continue the work on the PCI code.
Quoted 3 lines
My overall impression is that these are exceptionally well done. They're easy to read, well organized, and well documented. It's a refreshing change from a lot of the stuff that's posted.
Thanks Björn!
Quoted 11 lines
As with other arches that run on top of hypervisors, you have arch-specific code that enumerates PCI devices using hypervisor calls, and you hook into the PCI core at a lower level than
pci_scan_root_bus(). That is, you callpci_create_root_bus(),pci_scan_single_device(),pci_bus_add_devices(), etc., directly from the arch code. This is the typical approach, but it does make more dependencies between the arch code and the PCI core than I'd like.Did you consider hiding any of the hypervisor details behind the PCI config accessor interface? If that could be done, the overall structure might be more similar to other architectures.
You mean pci_root_ops? I'm not sure I understand how that can be used to hide hipervisor details. One reason why we use the lower level functions is that we need to create the root bus (and its resources) much earlier then the pci_dev. For instance pci_hp_register wants a pci_bus to create the PCI slot and the slot can exist without a pci_dev.
Quoted 4 lines
The current config accessors only work for dev/fn 00.0 (they fail when "devfn !=
ZPCI_DEVFN"). Why is that? It looks like it precludes multi-function devices and basically prevents you from building an arbitrary PCI hierarchy.
Our hypervisor does not support multi-function devices. In fact the hypervisor will limit the reported PCI devices to a hand-picked selection so we can be sure that there will be no unsupported devices. The PCI hierarchy is hidden by the hipervisor. We only use the PCI domain number, bus and devfn are always zero. So it looks like every function is directly attached to a PCI root complex.
That was the reason for the sanity check, but thinking about it I could remove it since although we don't support multi-function devices I think the s390 code should be more agnostic to these limitations.
Quoted 9 lines
zpci_map_resources()is very unusual. The structpci_devresource[] table normally contains CPU physical addresses, butzpci_map_resources()fills it with virtual addresses. I suspect this has something to do with the "BAR spaces are not disjunctive on s390" comment. It almost sounds like that's describing host bridges where the PCI bus address is not equal to the CPU physical address -- in that case, device A and device B may have the same values in their BARs, but they can still be distinct if they're under host bridges that apply different CPU-to-bus address translations.
Yeah, you've found it... I've had 3 or 4 tries on different implementations but all failed. If we use the resources as they are we cannot map them to the instructions (and ioremap does not help because there we cannot find out which device the resource belongs to). If we change the BARs on the card MMIO stops to work. I don't know about host bridges - if we would use a host bridge at which point in the translation process would it kick in?
Jan
Quoted 2 lines
Bjorn
Bjorn Helgaas
maintainerRe: [RFC PATCH 01/10] s390/pci: base support
Quoted 35 lines · Jan Glauber
Quoted 10 lines · Bjorn Helgaas
Quoted 9 lines · Jan Glauber
Add PCI support for s390, (only 64 bit mode is supported by hardware):
- PCI facility tests
- PCI instructions: pcilg, pcistg, pcistb, stpcifc, mpcifc, rpcit
- map readb/w/l/q and writeb/w/l/q to pcilg and pcistg instructions
-pci_iomapimplementation
- memcpy_fromio/toio
-pci_root_opsusing special pcilg/pcistg
- device, bus and domain allocationQuoted 4 lines
Quoted 1 line
Signed-off-by Jan Glauber <[email protected]>I think these patches are in -next already, so I just have some general comments & questions.
Yes, since the feedback was manageable we decided to give the patches some exposure in -next and if no one complains we'll just go for the next merge window. BTW, Sebastian & Gerald (on CC:) will continue the work on the PCI code.
Quoted 3 lines
My overall impression is that these are exceptionally well done. They're easy to read, well organized, and well documented. It's a refreshing change from a lot of the stuff that's posted.
Thanks Björn!
Quoted 8 lines
As with other arches that run on top of hypervisors, you have arch-specific code that enumerates PCI devices using hypervisor calls, and you hook into the PCI core at a lower level than
pci_scan_root_bus(). That is, you callpci_create_root_bus(),pci_scan_single_device(),pci_bus_add_devices(), etc., directly from the arch code. This is the typical approach, but it does make more dependencies between the arch code and the PCI core than I'd like.
Quoted 6 lines
Quoted 3 lines
Did you consider hiding any of the hypervisor details behind the PCI config accessor interface? If that could be done, the overall structure might be more similar to other architectures.
You mean
pci_root_ops? I'm not sure I understand how that can be used to hide hipervisor details.
The object of doing this would be to let you use pci_scan_root_bus(), so you wouldn't have to call pci_scan_single_device() and pci_bus_add_resources() directly. The idea is to make pci_read() and pci_write() smart enough that the PCI core can use them as though you have a normal PCI implementation. When pci_scan_root_bus() enumerates devices on the root bus using pci_scan_child_bus(), it does config reads on the VENDOR_ID of bb:00.0, bb:01.0, ..., bb:1f.0. Your pci_read() would return error or 0xffffffff data for everything except bb:00.0 (I guess it actually already does that).
Then some of the other init, e.g., zpci_enable_device(), could be done by the standard pcibios hooks such as pcibios_add_device() and pcibios_enable_device(), which would remove some of the PCI grunge from zpci_scan_devices() and the s390 hotplug driver.
Quoted 4 lines
One reason why we use the lower level
functions is that we need to create the root bus (and its resources) much earlier then thepci_dev. For instancepci_hp_registerwants apci_busto create the PCI slot and the slot can exist without apci_dev.
There must be something else going on here; a bus is *always* created before any of the pci_devs on the bus.
One thing that looks a little strange is that zpci_list seems to be sort of a cross between a list of PCI host bridges and a list of PCI devices. Understandable, since you usually have a one-to-one correspondence between them, but for your hotplug stuff, you can have the host bridge and slot without the pci_dev.
The hotplug slot support is really a function of the host bridge support, so it doesn't seem quite right to me to split it into a separate module (although that is the way most PCI hotplug drivers are currently structured). One reason is that it makes hot-add of a host bridge awkward: you have to have the "if (hotplug_ops.create_slot)" test in zpci_create_device().
Quoted 12 lines
Quoted 4 lines
The current config accessors only work for dev/fn 00.0 (they fail when "devfn !=
ZPCI_DEVFN"). Why is that? It looks like it precludes multi-function devices and basically prevents you from building an arbitrary PCI hierarchy.Our hypervisor does not support multi-function devices. In fact the hypervisor will limit the reported PCI devices to a hand-picked selection so we can be sure that there will be no unsupported devices. The PCI hierarchy is hidden by the hipervisor. We only use the PCI domain number, bus and devfn are always zero. So it looks like every function is directly attached to a PCI root complex.
Quoted 3 lines
That was the reason for the sanity check, but thinking about it I could remove it since although we don't support multi-function devices I think the s390 code should be more agnostic to these limitations.
The config accessor interface should be defined so it works for all PCI devices that exist, and fails for devices that do not exist. The approach you've taken so far is to prevent the PCI core from even attempting access to non-existent devices, which requires you to use some lower-level PCI interfaces. The alternative I'm raising as a possibility is to allow the PCI core to attempt accesses to non-existent devices, but have the accessor be smart enough to use the hypervisor or other arch-specific data to determine whether the device exists or not, and act accordingly.
Basically the idea is that if we put more smarts in the config accessors, we can make the interface between the PCI core and the architecture thinner.
Quoted 10 lines
Quoted 9 lines
zpci_map_resources()is very unusual. The structpci_devresource[] table normally contains CPU physical addresses, butzpci_map_resources()fills it with virtual addresses. I suspect this has something to do with the "BAR spaces are not disjunctive on s390" comment. It almost sounds like that's describing host bridges where the PCI bus address is not equal to the CPU physical address -- in that case, device A and device B may have the same values in their BARs, but they can still be distinct if they're under host bridges that apply different CPU-to-bus address translations.
Quoted 7 lines
Yeah, you've found it... I've had 3 or 4 tries on different implementations but all failed. If we use the resources as they are we cannot map them to the instructions (and ioremap does not help because there we cannot find out which device the resource belongs to). If we change the BARs on the card MMIO stops to work. I don't know about host bridges - if we would use a host bridge at which point in the translation process would it kick in?
Here's how it works. The PCI host bridge claims regions of the CPU physical address space and forwards transactions in those regions to the PCI root bus. Some host bridges can apply an offset when forwarding, so the address on the bus may be different from the address from the CPU. The bus address is what matches a PCI BAR.
You can tell the PCI core about this translation by using pci_add_resource_offset() instead of pci_add_resource(). When the PCI core reads a BAR, it applies the offset to convert the BAR value into a CPU physical address.
For example, let's say you have two host bridges:
PCI host bridge to bus 0000:00pci_bus 0000:00: root bus resource [mem 0x100000000-0x1ffffffff] (bus address [0x00000000-0xffffffff])
PCI host bridge to bus 0001:00pci_bus 0001:00: root bus resource [mem 0x200000000-0x2ffffffff] (bus address [0x00000000-0xffffffff])
Both bridges use the same bus address range, and BARs of devices on bus 0000:00 can have the same values as those of devices on bus 0001:00. But there's no ambiguity because a CPU access to 0x1_0000_0000 will be claimed by the first bridge and translated to bus address 0x0 on bus 0000:00, while a CPU access to 0x2_0000_0000 will be claimed by the second bridge and translated to bus address 0x0 on bus 0001:00.
The pci_dev resources will contain CPU physical addresses, not the BAR values themselves. These addresses implicitly identify the host bridge (and, in your case, the pci_dev, since you have at most one pci_dev per host bridge).
Bjorn
Re: [RFC PATCH 01/10] s390/pci: base support
Quoted 155 lines · Bjorn Helgaas
Quoted 35 lines · Jan Glauber
Quoted 10 lines · Bjorn Helgaas
Quoted 9 lines · Jan Glauber
Add PCI support for s390, (only 64 bit mode is supported by hardware):
- PCI facility tests
- PCI instructions: pcilg, pcistg, pcistb, stpcifc, mpcifc, rpcit
- map readb/w/l/q and writeb/w/l/q to pcilg and pcistg instructions
-pci_iomapimplementation
- memcpy_fromio/toio
-pci_root_opsusing special pcilg/pcistg
- device, bus and domain allocationQuoted 4 lines
Quoted 1 line
Signed-off-by Jan Glauber <[email protected]>I think these patches are in -next already, so I just have some general comments & questions.
Yes, since the feedback was manageable we decided to give the patches some exposure in -next and if no one complains we'll just go for the next merge window. BTW, Sebastian & Gerald (on CC:) will continue the work on the PCI code.
Quoted 3 lines
My overall impression is that these are exceptionally well done. They're easy to read, well organized, and well documented. It's a refreshing change from a lot of the stuff that's posted.
Thanks Björn!
Quoted 8 lines
As with other arches that run on top of hypervisors, you have arch-specific code that enumerates PCI devices using hypervisor calls, and you hook into the PCI core at a lower level than
pci_scan_root_bus(). That is, you callpci_create_root_bus(),pci_scan_single_device(),pci_bus_add_devices(), etc., directly from the arch code. This is the typical approach, but it does make more dependencies between the arch code and the PCI core than I'd like.Quoted 6 lines
Quoted 3 lines
Did you consider hiding any of the hypervisor details behind the PCI config accessor interface? If that could be done, the overall structure might be more similar to other architectures.
You mean
pci_root_ops? I'm not sure I understand how that can be used to hide hipervisor details.The object of doing this would be to let you use
pci_scan_root_bus(), so you wouldn't have to callpci_scan_single_device()andpci_bus_add_resources()directly. The idea is to makepci_read()andpci_write()smart enough that the PCI core can use them as though you have a normal PCI implementation. Whenpci_scan_root_bus()enumerates devices on the root bus usingpci_scan_child_bus(), it does config reads on theVENDOR_IDof bb:00.0, bb:01.0, ..., bb:1f.0. Yourpci_read()would return error or0xffffffffdata for everything except bb:00.0 (I guess it actually already does that).Then some of the other init, e.g.,
zpci_enable_device(), could be done by the standard pcibios hooks such aspcibios_add_device()andpcibios_enable_device(), which would remove some of the PCI grunge fromzpci_scan_devices()and the s390 hotplug driver.Quoted 4 lines
One reason why we use the lower level
functions is that we need to create the root bus (and its resources) much earlier then thepci_dev. For instancepci_hp_registerwants apci_busto create the PCI slot and the slot can exist without apci_dev.There must be something else going on here; a bus is *always* created before any of the
pci_devson the bus.One thing that looks a little strange is that
zpci_listseems to be sort of a cross between a list of PCI host bridges and a list of PCI devices. Understandable, since you usually have a one-to-one correspondence between them, but for your hotplug stuff, you can have the host bridge and slot without thepci_dev.The hotplug slot support is really a function of the host bridge support, so it doesn't seem quite right to me to split it into a separate module (although that is the way most PCI hotplug drivers are currently structured). One reason is that it makes hot-add of a host bridge awkward: you have to have the "if (hotplug_ops.create_slot)" test in
zpci_create_device().Quoted 12 lines
Quoted 4 lines
The current config accessors only work for dev/fn 00.0 (they fail when "devfn !=
ZPCI_DEVFN"). Why is that? It looks like it precludes multi-function devices and basically prevents you from building an arbitrary PCI hierarchy.Our hypervisor does not support multi-function devices. In fact the hypervisor will limit the reported PCI devices to a hand-picked selection so we can be sure that there will be no unsupported devices. The PCI hierarchy is hidden by the hipervisor. We only use the PCI domain number, bus and devfn are always zero. So it looks like every function is directly attached to a PCI root complex.
Quoted 3 lines
That was the reason for the sanity check, but thinking about it I could remove it since although we don't support multi-function devices I think the s390 code should be more agnostic to these limitations.
The config accessor interface should be defined so it works for all PCI devices that exist, and fails for devices that do not exist. The approach you've taken so far is to prevent the PCI core from even attempting access to non-existent devices, which requires you to use some lower-level PCI interfaces. The alternative I'm raising as a possibility is to allow the PCI core to attempt accesses to non-existent devices, but have the accessor be smart enough to use the hypervisor or other arch-specific data to determine whether the device exists or not, and act accordingly.
Basically the idea is that if we put more smarts in the config accessors, we can make the interface between the PCI core and the architecture thinner.
Quoted 10 lines
Quoted 9 lines
zpci_map_resources()is very unusual. The structpci_devresource[] table normally contains CPU physical addresses, butzpci_map_resources()fills it with virtual addresses. I suspect this has something to do with the "BAR spaces are not disjunctive on s390" comment. It almost sounds like that's describing host bridges where the PCI bus address is not equal to the CPU physical address -- in that case, device A and device B may have the same values in their BARs, but they can still be distinct if they're under host bridges that apply different CPU-to-bus address translations.Quoted 7 lines
Yeah, you've found it... I've had 3 or 4 tries on different implementations but all failed. If we use the resources as they are we cannot map them to the instructions (and ioremap does not help because there we cannot find out which device the resource belongs to). If we change the BARs on the card MMIO stops to work. I don't know about host bridges - if we would use a host bridge at which point in the translation process would it kick in?
Here's how it works. The PCI host bridge claims regions of the CPU physical address space and forwards transactions in those regions to the PCI root bus. Some host bridges can apply an offset when forwarding, so the address on the bus may be different from the address from the CPU. The bus address is what matches a PCI BAR.
You can tell the PCI core about this translation by using
pci_add_resource_offset()instead ofpci_add_resource(). When the PCI core reads a BAR, it applies the offset to convert the BAR value into a CPU physical address.For example, let's say you have two host bridges:
PCI host bridge to bus 0000:00
pci_bus0000:00: root bus resource [mem 0x100000000-0x1ffffffff] (bus address [0x00000000-0xffffffff])
PCI host bridge to bus 0001:00pci_bus0001:00: root bus resource [mem 0x200000000-0x2ffffffff] (bus address [0x00000000-0xffffffff])Both bridges use the same bus address range, and BARs of devices on bus 0000:00 can have the same values as those of devices on bus 0001:00. But there's no ambiguity because a CPU access to 0x1_0000_0000 will be claimed by the first bridge and translated to bus address
0x0on bus 0000:00, while a CPU access to 0x2_0000_0000 will be claimed by the second bridge and translated to bus address0x0on bus 0001:00.
Quoted 4 lines
The
pci_devresources will contain CPU physical addresses, not the BAR values themselves. These addresses implicitly identify the host bridge (and, in your case, thepci_dev, since you have at most onepci_devper host bridge).
Hi Bjorn,
thanks for the explanation. I'll look into it.
Regards,
Sebastian
RFC PATCH 2/10 s390/pci: CLP interface
In reply to Jan GlauberCLP instructions are used to query the firmware about detected PCI functions, the attributes of those functions and to enable or disable a PCI function. The CLP interface is the equivalent to a PCI bus scan.
--- arch/s390/include/asm/clp.h | 28 ++++ arch/s390/include/asm/pci.h | 7 + arch/s390/include/asm/pci_clp.h | 182 +++++++++++++++++++++++ arch/s390/pci/Makefile | 2 +- arch/s390/pci/pci.c | 28 ++++ arch/s390/pci/pci_clp.c | 317 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 563 insertions(+), 1 deletion(-) create mode 100644 arch/s390/include/asm/clp.h create mode 100644 arch/s390/include/asm/pci_clp.h create mode 100644 arch/s390/pci/pci_clp.c
arch/s390/include/asm/clp.h new file +28 -0
@@ -0,0 +1,28 @@ +#ifndef _ASM_S390_CLP_H +#define _ASM_S390_CLP_H + +/* CLP common request & response block size */ +#define CLP_BLK_SIZE (PAGE_SIZE * 2) + +struct clp_req_hdr { +u16 len; +u16 cmd; +} __packed; + +struct clp_rsp_hdr { +u16 len; +u16 rsp; +} __packed; + +/* CLP Response Codes */ +#define CLP_RC_OK 0x0010/* Command request successfully */ +#define CLP_RC_CMD 0x0020/* Command code not recognized */ +#define CLP_RC_PERM 0x0030/* Command not authorized */ +#define CLP_RC_FMT 0x0040/* Invalid command request format */ +#define CLP_RC_LEN 0x0050/* Invalid command request length */ +#define CLP_RC_8K 0x0060/* Command requires 8K LPCB */ +#define CLP_RC_RESNOT0 0x0070/* Reserved field not zero */ +#define CLP_RC_NODATA 0x0080/* No data available */ +#define CLP_RC_FC_UNKNOWN 0x0100/* Function code not recognized */ + +#endif
arch/s390/include/asm/pci.h +7 -0
@@ -8,6 +8,7 @@#include <asm-generic/pci.h> #include <asm-generic/pci-dma-compat.h> +#include <asm/pci_clp.h> #define PCIBIOS_MIN_IO 0x1000#define PCIBIOS_MIN_MEM 0x10000000
@@ -76,6 +77,12 @@ void zpci_stop_device(struct zpci_dev *);void zpci_free_device (struct zpci_dev *);int zpci_scan_device (struct zpci_dev *); +/* CLP */ +int clp_find_pci_devices (void ); +int clp_add_pci_device (u32 ,u32 ,int ); +int clp_enable_fh (struct zpci_dev *,u8 ); +int clp_disable_fh (struct zpci_dev *); +/* Helpers */ struct zpci_dev *get_zdev (struct pci_dev *);struct zpci_dev *get_zdev_by_fid (u32 );
arch/s390/include/asm/pci_clp.h new file +182 -0
182 lines not on this page · raw message
arch/s390/pci/Makefile +1 -1
@@ -2,4 +2,4 @@ # Makefile for the s390 PCI subsystem. # -obj-$(CONFIG_PCI) += pci.o +obj-$(CONFIG_PCI) += pci.o pci_clp.o
arch/s390/pci/pci.c +28 -0
@@ -29,6 +29,7 @@#include <asm/facility.h> #include <asm/pci_insn.h> +#include <asm/pci_clp.h> #define DEBUG /* enable pr_debug */
@@ -436,6 +437,20 @@ static void zpci_free_domain(struct zpci_dev *zdev)spin_unlock (&zpci_domain_lock); } +int zpci_enable_device (struct zpci_dev *zdev) +{ +int rc; + + rc =clp_enable_fh (zdev,ZPCI_NR_DMA_SPACES ); +if (rc) + goto out; +pr_info ("Enabled fh: 0x%x fid: 0x%x\n" , zdev->fh, zdev->fid); +return 0 ; +out: +return rc; +} +EXPORT_SYMBOL_GPL (zpci_enable_device); +int zpci_create_device (struct zpci_dev *zdev) {int rc;
@@ -455,8 +470,15 @@ int zpci_create_device(struct zpci_dev *zdev)if (zdev->state ==ZPCI_FN_STATE_STANDBY )return 0 ; + rc =zpci_enable_device (zdev); +if (rc) + goto out_start;return 0 ; +out_start: +mutex_lock (&zpci_list_lock); +list_del (&zdev->entry); +mutex_unlock (&zpci_list_lock); out_bus:zpci_free_domain (zdev); out:
@@ -489,6 +511,7 @@ int zpci_scan_device(struct zpci_dev *zdev)return 0 ; out: +clp_disable_fh (zdev);return -EIO ; }EXPORT_SYMBOL_GPL (zpci_scan_device);
@@ -547,9 +570,14 @@ static int __init pci_base_init(void)if (rc) goto out_mem; + rc =clp_find_pci_devices (); +if (rc) + goto out_find; +zpci_scan_devices ();return 0 ; +out_find:zpci_mem_exit (); out_mem:return rc;
arch/s390/pci/pci_clp.c new file +317 -0
317 lines not on this page · raw message
Signature · 1 line
1.7.12.4
RFC PATCH 3/10 s390/bitops: find leftmost bit instruction support
In reply to Jan GlauberThe flogr instruction scans a bitmap starting from the leftmost bit. Implement support for these bitops. This could be useful to scan bitmaps like an interrupt vector set by the hardware starting at the leftmost bit.
--- arch/s390/include/asm/bitops.h | 81 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+)
arch/s390/include/asm/bitops.h +81 -0
@@ -640,6 +640,87 @@ static inline unsigned long find_first_bit(const unsigned long * addr, }#define find_first_bit find_first_bit +/* +* Big endian variant whichs starts bit counting from left using +* the flogr (find leftmost one) instruction. +*/ +static inline unsigned long __flo_word (unsigned long nr,unsigned long val) +{ + register unsigned long bit asm("2") = val; + registerunsigned long out asm("3" ); + + asmvolatile ( +" .insn rre,0xb9830000,%[bit],%[bit]\n" + : [bit]"+d" (bit), [out]"=d" (out) : :"cc" ); +return nr + bit; +} + +/* +* 64 bit special left bitops format: +* order in memory: +* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f +* 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f +* 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f +* 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f +* after that follows the next long with bit numbers +* 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f +* 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f +* 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f +* 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f +* The reason for this bit ordering is the fact that +* the hardware sets bits in a bitmap starting at bit 0 +* and we don't want to scan the bitmap from the 'wrong +* end'. +*/ +static inline unsigned long find_first_bit_left (const unsigned long *addr, +unsigned long size) +{ +unsigned long bytes, bits; + +if (!size) +return 0 ; + bytes =__ffs_word_loop (addr, size); + bits =__flo_word (bytes *8 ,__load_ulong_be (addr, bytes)); +return (bits < size) ? bits : size; +} + +static inline int find_next_bit_left (const unsigned long *addr, +unsigned long size, +unsigned long offset) +{ +const unsigned long *p; +unsigned long bit, set; + +if (offset >= size) +return size; + bit = offset & (__BITOPS_WORDSIZE -1 ); + offset -= bit; + size -= offset; + p = addr + offset / __BITOPS_WORDSIZE; +if (bit) { + set =__flo_word (0 , *p & (~0UL << bit)); +if (set >= size) +return size + offset; +if (set < __BITOPS_WORDSIZE) +return set + offset; + offset += __BITOPS_WORDSIZE; + size -= __BITOPS_WORDSIZE; + p++; + } +return offset +find_first_bit_left (p, size); +} + +#define for_each_set_bit_left (bit, addr, size) \ + for ((bit) = find_first_bit_left((addr), (size)); \ + (bit) < (size); \ + (bit) = find_next_bit_left((addr), (size), (bit) + 1)) + +/* same as for_each_set_bit() but use bit as value to start with */ +#define for_each_set_bit_left_cont (bit, addr, size) \ + for ((bit) = find_next_bit_left((addr), (size), (bit)); \ + (bit) < (size); \ + (bit) = find_next_bit_left((addr), (size), (bit) + 1)) +/** * find_next_zero_bit - find the first zero bit in a memory region * @addr: The address to base the search on
Signature · 1 line
1.7.12.4
RFC PATCH 4/10 s390/pci: PCI adapter interrupts for MSI/MSI-X
In reply to Jan GlauberSupport PCI adapter interrupts using the Single-IRQ-mode. Single-IRQ-mode disables an adapter IRQ automatically after delivering it until the SIC instruction enables it again. This is used to reduce the number of IRQs for streaming workloads.
Up to 64 MSI handlers can be registered per PCI function. A hash table is used to map interrupt numbers to MSI descriptors. The interrupt vector is scanned using the flogr instruction. Only MSI/MSI-X interrupts are supported, no legacy INTs.
--- arch/s390/include/asm/hw_irq.h | 22 ++ arch/s390/include/asm/irq.h | 12 ++ arch/s390/include/asm/isc.h | 1 + arch/s390/include/asm/pci.h | 27 +++ arch/s390/kernel/irq.c | 2 + arch/s390/pci/Makefile | 2 +- arch/s390/pci/pci.c | 464 ++++++++++++++++++++++++++++++++++++++++- arch/s390/pci/pci_clp.c | 3 + arch/s390/pci/pci_msi.c | 141 +++++++++++++ drivers/pci/msi.c | 10 +- include/linux/irq.h | 10 +- 11 files changed, 685 insertions(+), 9 deletions(-) create mode 100644 arch/s390/include/asm/hw_irq.h create mode 100644 arch/s390/pci/pci_msi.c
arch/s390/include/asm/hw_irq.h new file +22 -0
@@ -0,0 +1,22 @@ +#ifndef _HW_IRQ_H +#define _HW_IRQ_H + +#include <linux/msi.h> +#include <linux/pci.h> + +static inline struct msi_desc *irq_get_msi_desc (unsigned int irq) +{ +return __irq_get_msi_desc (irq); +} + +/* Must be called with msi map lock held */ +static inline int irq_set_msi_desc (unsigned int irq,struct msi_desc *msi) +{ +if (!msi) +return -EINVAL ; + + msi->irq = irq; +return 0 ; +} + +#endif
arch/s390/include/asm/irq.h +12 -0
@@ -33,6 +33,8 @@ enum interruption_class {IOINT_APB ,IOINT_ADM ,IOINT_CSC , +IOINT_PCI , +IOINT_MSI ,NMI_NMI , NR_IRQS, };
@@ -51,4 +53,14 @@ void service_subclass_irq_unregister(void);void measurement_alert_subclass_register (void );void measurement_alert_subclass_unregister (void ); +#ifdef CONFIG_LOCKDEP +# define disable_irq_nosync_lockdep (irq) disable_irq_nosync(irq) +# define disable_irq_nosync_lockdep_irqsave (irq, flags) \ + disable_irq_nosync(irq) +# define disable_irq_lockdep (irq) disable_irq(irq) +# define enable_irq_lockdep (irq) enable_irq(irq) +# define enable_irq_lockdep_irqrestore (irq, flags) \ + enable_irq(irq) +#endif +#endif /* _ASM_IRQ_H */
arch/s390/include/asm/isc.h +1 -0
@@ -18,6 +18,7 @@#define CHSC_SCH_ISC 7/* CHSC subchannels */ /* Adapter interrupts. */ #define QDIO_AIRQ_ISC IO_SCH_ISC/* I/O subchannel in qdio mode */ +#define PCI_ISC 2/* PCI I/O subchannels */ #define AP_ISC 6/* adjunct processor (crypto) devices */ /* Functions for registration of I/O interruption subclasses */
arch/s390/include/asm/pci.h +27 -0
@@ -20,6 +20,10 @@ void pci_iounmap(struct pci_dev *, void __iomem *);int pci_domain_nr (struct pci_bus *);int pci_proc_domain (struct pci_bus *); +/* MSI arch hooks */ +#define arch_setup_msi_irqs arch_setup_msi_irqs +#define arch_teardown_msi_irqs arch_teardown_msi_irqs +#define ZPCI_BUS_NR 0/* default bus number */ #define ZPCI_DEVFN 0/* default device number */
@@ -29,6 +33,15 @@ int pci_proc_domain(struct pci_bus *);#define ZPCI_FC_BLOCKED 0x20#define ZPCI_FC_DMA_ENABLED 0x10 +struct msi_map { +unsigned long irq; +struct msi_desc *msi; +struct hlist_node msi_chain; +}; + +#define ZPCI_NR_MSI_VECS 64 +#define ZPCI_MSI_MASK (ZPCI_NR_MSI_VECS - 1) +enum zpci_state {ZPCI_FN_STATE_RESERVED ,ZPCI_FN_STATE_STANDBY ,
@@ -56,6 +69,12 @@ struct zpci_dev {u8 pfgid;/* function group ID */ u16 domain; +/* IRQ stuff */ +u64 msi_addr;/* MSI address */ +struct zdev_irq_map *irq_map; +struct msi_map *msi_map[ZPCI_NR_MSI_VECS ]; +unsigned int aisb;/* number of the summary bit */ +struct zpci_bar_struct bars[PCI_BAR_COUNT ];enum pci_bus_speed max_bus_speed;
@@ -83,6 +102,14 @@ int clp_add_pci_device(u32, u32, int);int clp_enable_fh (struct zpci_dev *,u8 );int clp_disable_fh (struct zpci_dev *); +/* MSI */ +struct msi_desc *__irq_get_msi_desc (unsigned int ); +int zpci_msi_set_mask_bits (struct msi_desc *,u32 ,u32 ); +int zpci_setup_msi_irq (struct zpci_dev *,struct msi_desc *,unsigned int ,int ); +void zpci_teardown_msi_irq (struct zpci_dev *,struct msi_desc *); +int zpci_msihash_init (void ); +void zpci_msihash_exit (void ); +/* Helpers */ struct zpci_dev *get_zdev (struct pci_dev *);struct zpci_dev *get_zdev_by_fid (u32 );
arch/s390/kernel/irq.c +2 -0
@@ -58,6 +58,8 @@ static const struct irq_class intrclass_names[] = { [IOINT_APB] = {.name = "APB", .desc = "[I/O] AP Bus"}, [IOINT_ADM] = {.name = "ADM", .desc = "[I/O] EADM Subchannel"}, [IOINT_CSC] = {.name = "CSC", .desc = "[I/O] CHSC Subchannel"}, + [IOINT_PCI] = {.name = "PCI", .desc = "[I/O] PCI Interrupt" }, + [IOINT_MSI] = {.name = "MSI", .desc = "[I/O] MSI Interrupt" }, [NMI_NMI] = {.name = "NMI", .desc = "[NMI] Machine Check"}, };
arch/s390/pci/Makefile +1 -1
@@ -2,4 +2,4 @@ # Makefile for the s390 PCI subsystem. # -obj-$(CONFIG_PCI) += pci.o pci_clp.o +obj-$(CONFIG_PCI) += pci.o pci_clp.o pci_msi.o
arch/s390/pci/pci.c +463 -1
558 lines not on this page · raw message
arch/s390/pci/pci_clp.c +3 -0
@@ -48,6 +48,9 @@ static void clp_free_block(void *ptr)static void clp_store_query_pci_fngrp (struct zpci_dev *zdev,struct clp_rsp_query_pci_grp *response) { + zdev->msi_addr = response->msia; + +pr_debug ("Supported number of MSI vectors: %u\n" , response->noi);switch (response->version) {case 1 : zdev->max_bus_speed =PCIE_SPEED_5_0GT ;
arch/s390/pci/pci_msi.c new file +141 -0
141 lines not on this page · raw message
drivers/pci/msi.c +8 -2
@@ -207,6 +207,8 @@ static void msix_mask_irq(struct msi_desc *desc, u32 flag) desc->masked =__msix_mask_irq (desc, flag); } +#ifdef CONFIG_GENERIC_HARDIRQS +static void msi_set_mask_bit (struct irq_data *data,u32 flag) {struct msi_desc *desc =irq_data_get_msi (data);
@@ -230,6 +232,8 @@ void unmask_msi_irq(struct irq_data *data) msi_set_mask_bit(data, 0); } +#endif /* CONFIG_GENERIC_HARDIRQS */ +void __read_msi_msg (struct msi_desc *entry,struct msi_msg *msg) {BUG_ON (entry->dev->current_state !=PCI_D0 );
@@ -333,12 +337,14 @@ static void free_msi_irqs(struct pci_dev *dev)struct msi_desc *entry, *tmp;list_for_each_entry (entry, &dev->msi_list, list) { -int i, nvec; +int nvec;if (!entry->irq)continue ; nvec =1 << entry->msi_attrib.multiple; -for (i =0 ; i < nvec; i++) +#ifdef CONFIG_GENERIC_HARDIRQS +for (int i =0 ; i < nvec; i++)BUG_ON (irq_has_action (entry->irq + i)); +#endif }arch_teardown_msi_irqs (dev);
include/linux/irq.h +5 -5
@@ -10,9 +10,6 @@*/ #include <linux/smp.h> - -#ifndef CONFIG_S390 -#include <linux/linkage.h> #include <linux/cache.h> #include <linux/spinlock.h>
@@ -737,8 +734,11 @@ static inline void irq_gc_lock(struct irq_chip_generic *gc) { }static inline void irq_gc_unlock (struct irq_chip_generic *gc) { }#endif -#endif /* CONFIG_GENERIC_HARDIRQS */ +#else /* !CONFIG_GENERIC_HARDIRQS */ -#endif /* !CONFIG_S390 */ +extern struct msi_desc *irq_get_msi_desc (unsigned int irq); +extern int irq_set_msi_desc (unsigned int irq,struct msi_desc *entry); + +#endif /* CONFIG_GENERIC_HARDIRQS */ #endif /* _LINUX_IRQ_H */
Signature · 1 line
1.7.12.4
RFC PATCH 5/10 s390/pci: DMA support
In reply to Jan GlauberAdd DMA IOMMU support using 4K page table entries. Implement dma_map_ops.
--- arch/s390/include/asm/dma-mapping.h | 76 ++++++ arch/s390/include/asm/dma.h | 19 +- arch/s390/include/asm/pci.h | 21 ++ arch/s390/include/asm/pci_dma.h | 196 ++++++++++++++ arch/s390/pci/Makefile | 2 +- arch/s390/pci/pci.c | 36 +++ arch/s390/pci/pci_clp.c | 4 + arch/s390/pci/pci_dma.c | 505 ++++++++++++++++++++++++++++++++++++ 8 files changed, 848 insertions(+), 11 deletions(-) create mode 100644 arch/s390/include/asm/dma-mapping.h create mode 100644 arch/s390/include/asm/pci_dma.h create mode 100644 arch/s390/pci/pci_dma.c
arch/s390/include/asm/dma-mapping.h new file +76 -0
@@ -0,0 +1,76 @@ +#ifndef _ASM_S390_DMA_MAPPING_H +#define _ASM_S390_DMA_MAPPING_H + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/scatterlist.h> +#include <linux/dma-attrs.h> +#include <linux/dma-debug.h> +#include <linux/io.h> + +#define DMA_ERROR_CODE (~(dma_addr_t) 0x0) + +extern struct dma_map_ops s390_dma_ops; + +static inline struct dma_map_ops *get_dma_ops (struct device *dev) +{ +return &s390_dma_ops; +} + +extern int dma_set_mask (struct device *dev,u64 mask); +extern int dma_is_consistent (struct device *dev,dma_addr_t dma_handle); +extern void dma_cache_sync (struct device *dev,void *vaddr,size_t size, +enum dma_data_direction direction); + +#define dma_alloc_noncoherent (d, s, h, f) dma_alloc_coherent(d, s, h, f) +#define dma_free_noncoherent (d, s, v, h) dma_free_coherent(d, s, v, h) + +#include <asm-generic/dma-mapping-common.h> + +static inline int dma_supported (struct device *dev,u64 mask) +{ +struct dma_map_ops *dma_ops =get_dma_ops (dev); + +if (dma_ops->dma_supported ==NULL ) +return 1 ; +return dma_ops->dma_supported (dev, mask); +} + +static inline bool dma_capable (struct device *dev,dma_addr_t addr,size_t size) +{ +if (!dev->dma_mask) +return 0 ; +return addr + size -1 <= *dev->dma_mask; +} + +static inline int dma_mapping_error (struct device *dev,dma_addr_t dma_addr) +{ +struct dma_map_ops *dma_ops =get_dma_ops (dev); + +if (dma_ops->mapping_error) +return dma_ops->mapping_error (dev, dma_addr); +return (dma_addr ==0UL ); +} + +static inline void *dma_alloc_coherent (struct device *dev,size_t size, +dma_addr_t *dma_handle,gfp_t flag) +{ +struct dma_map_ops *ops =get_dma_ops (dev); +void *ret; + + ret = ops->alloc (dev, size, dma_handle, flag,NULL ); +debug_dma_alloc_coherent (dev, size, *dma_handle, ret); +return ret; +} + +static inline void dma_free_coherent (struct device *dev,size_t size, +void *cpu_addr,dma_addr_t dma_handle) +{ +struct dma_map_ops *dma_ops =get_dma_ops (dev); + + dma_ops->free (dev, size, cpu_addr, dma_handle,NULL ); +debug_dma_free_coherent (dev, size, cpu_addr, dma_handle); +} + +#endif /* _ASM_S390_DMA_MAPPING_H */
arch/s390/include/asm/dma.h +9 -10
@@ -1,14 +1,13 @@ -/* -* S390 version -*/ - -#ifndef _ASM_DMA_H -#define _ASM_DMA_H +#ifndef _ASM_S390_DMA_H +#define _ASM_S390_DMA_H -#include <asm/io.h> /* need byte IO */ +#include <asm/io.h> +/* +* MAX_DMA_ADDRESS is ambiguous because on s390 its completely unrelated +* to DMA. It _is_ used for the s390 memory zone split at 2GB caused +* by the 31 bit heritage. +*/ #define MAX_DMA_ADDRESS 0x80000000 -#define free_dma (x) do { } while (0) - -#endif /* _ASM_DMA_H */ +#endif /* _ASM_S390_DMA_H */
arch/s390/include/asm/pci.h +21 -0
@@ -75,8 +75,23 @@ struct zpci_dev {struct msi_map *msi_map[ZPCI_NR_MSI_VECS ];unsigned int aisb;/* number of the summary bit */ +/* DMA stuff */ +unsigned long *dma_table; +spinlock_t dma_table_lock; +int tlb_refresh; + +spinlock_t iommu_bitmap_lock; +unsigned long *iommu_bitmap; +unsigned long iommu_size; +unsigned long iommu_pages; +unsigned int next_bit; +struct zpci_bar_struct bars[PCI_BAR_COUNT ]; +u64 start_dma;/* Start of available DMA addresses */ +u64 end_dma;/* End of available DMA addresses */ +u64 dma_mask;/* DMA address space mask */ +enum pci_bus_speed max_bus_speed; };
@@ -95,6 +110,8 @@ int zpci_enable_device(struct zpci_dev *);void zpci_stop_device (struct zpci_dev *);void zpci_free_device (struct zpci_dev *);int zpci_scan_device (struct zpci_dev *); +int zpci_register_ioat (struct zpci_dev *,u8 ,u64 ,u64 ,u64 ); +int zpci_unregister_ioat (struct zpci_dev *,u8 );/* CLP */ int clp_find_pci_devices (void );
@@ -115,4 +132,8 @@ struct zpci_dev *get_zdev(struct pci_dev *);struct zpci_dev *get_zdev_by_fid (u32 );bool zpci_fid_present (u32 ); +/* DMA */ +int zpci_dma_init (void ); +void zpci_dma_exit (void ); +#endif
arch/s390/include/asm/pci_dma.h new file +196 -0
196 lines not on this page · raw message
arch/s390/pci/Makefile +1 -1
@@ -2,4 +2,4 @@ # Makefile for the s390 PCI subsystem. # -obj-$(CONFIG_PCI) += pci.o pci_clp.o pci_msi.o +obj-$(CONFIG_PCI) += pci.o pci_dma.o pci_clp.o pci_msi.o
arch/s390/pci/pci.c +36 -0
@@ -34,6 +34,7 @@#include <asm/facility.h> #include <asm/pci_insn.h> #include <asm/pci_clp.h> +#include <asm/pci_dma.h> #define DEBUG /* enable pr_debug */
@@ -232,6 +233,25 @@ static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_argsreturn rc; } +/* Modify PCI: Register I/O address translation parameters */ +int zpci_register_ioat (struct zpci_dev *zdev,u8 dmaas, +u64 base,u64 limit,u64 iota) +{ +struct mod_pci_args args = { base, limit, iota }; + +WARN_ON_ONCE (iota &0x3fff ); + args.iota |=ZPCI_IOTA_RTTO_FLAG ; +return mod_pci (zdev,ZPCI_MOD_FC_REG_IOAT , dmaas, &args); +} + +/* Modify PCI: Unregister I/O address translation parameters */ +int zpci_unregister_ioat (struct zpci_dev *zdev,u8 dmaas) +{ +struct mod_pci_args args = {0 ,0 ,0 }; + +return mod_pci (zdev,ZPCI_MOD_FC_DEREG_IOAT , dmaas, &args); +} +/* Modify PCI: Unregister adapter interruptions */ static int zpci_unregister_airq (struct zpci_dev *zdev) {
@@ -602,6 +622,7 @@ static void zpci_remove_device(struct pci_dev *pdev)dev_info (&pdev->dev,"Removing device %u\n" , zdev->domain); zdev->state =ZPCI_FN_STATE_CONFIGURED ; +zpci_dma_exit_device (zdev);zpci_unmap_resources (pdev);list_del (&zdev->entry);/* can be called from init */ zdev->pdev =NULL ;
@@ -887,7 +908,14 @@ int zpci_enable_device(struct zpci_dev *zdev)if (rc) goto out;pr_info ("Enabled fh: 0x%x fid: 0x%x\n" , zdev->fh, zdev->fid); + + rc =zpci_dma_init_device (zdev); +if (rc) + goto out_dma;return 0 ; + +out_dma: +clp_disable_fh (zdev); out:return rc; }
@@ -929,6 +957,7 @@ out:void zpci_stop_device (struct zpci_dev *zdev) { +zpci_dma_exit_device (zdev);/* * Note: SCLP disables fh via set-pci-fn so don't * do that here.
@@ -953,6 +982,7 @@ int zpci_scan_device(struct zpci_dev *zdev)return 0 ; out: +zpci_dma_exit_device (zdev);clp_disable_fh (zdev);return -EIO ; }
@@ -1028,6 +1058,10 @@ static int __init pci_base_init(void)if (rc) goto out_irq; + rc =zpci_dma_init (); +if (rc) + goto out_dma; + rc =clp_find_pci_devices ();if (rc) goto out_find;
@@ -1036,6 +1070,8 @@ static int __init pci_base_init(void)return 0 ; out_find: +zpci_dma_exit (); +out_dma:zpci_irq_exit (); out_irq:zpci_msihash_exit ();
arch/s390/pci/pci_clp.c +4 -0
@@ -48,6 +48,8 @@ static void clp_free_block(void *ptr)static void clp_store_query_pci_fngrp (struct zpci_dev *zdev,struct clp_rsp_query_pci_grp *response) { + zdev->tlb_refresh = response->refresh; + zdev->dma_mask = response->dasm; zdev->msi_addr = response->msia;pr_debug ("Supported number of MSI vectors: %u\n" , response->noi);
@@ -97,6 +99,8 @@ static int clp_store_query_pci_fn(struct zpci_dev *zdev, zdev->bars[i].val =le32_to_cpu (response->bar[i]); zdev->bars[i].size = response->bar_size[i]; } + zdev->start_dma = response->sdma; + zdev->end_dma = response->edma; zdev->pchid = response->pchid; zdev->pfgid = response->pfgid;return 0 ;
arch/s390/pci/pci_dma.c new file +505 -0
505 lines not on this page · raw message
Signature · 1 line
1.7.12.4
RFC PATCH 6/10 s390/pci: CHSC PCI support for error and availability events
In reply to Jan GlauberAdd CHSC store-event-information support for PCI (notfication type 2) and report error and availability events to the PCI architecture layer.
--- arch/s390/include/asm/pci.h | 4 ++ arch/s390/pci/Makefile | 3 +- arch/s390/pci/pci_event.c | 93 ++++++++++++++++++++++++++ drivers/s390/cio/chsc.c | 156 +++++++++++++++++++++++++++++++------------- 4 files changed, 211 insertions(+), 45 deletions(-) create mode 100644 arch/s390/pci/pci_event.c
arch/s390/include/asm/pci.h +4 -0
@@ -127,6 +127,10 @@ void zpci_teardown_msi_irq(struct zpci_dev *, struct msi_desc *);int zpci_msihash_init (void );void zpci_msihash_exit (void ); +/* Error handling and recovery */ +void zpci_event_error (void *); +void zpci_event_availability (void *); +/* Helpers */ struct zpci_dev *get_zdev (struct pci_dev *);struct zpci_dev *get_zdev_by_fid (u32 );
arch/s390/pci/Makefile +2 -1
@@ -2,4 +2,5 @@ # Makefile for the s390 PCI subsystem. # -obj-$(CONFIG_PCI) += pci.o pci_dma.o pci_clp.o pci_msi.o +obj-$(CONFIG_PCI) += pci.o pci_dma.o pci_clp.o pci_msi.o \ + pci_event.o
arch/s390/pci/pci_event.c new file +93 -0
93 lines not on this page · raw message
drivers/s390/cio/chsc.c +112 -44
226 lines not on this page · raw message
Signature · 1 line
1.7.12.4
RFC PATCH 7/10 s390/pci: PCI hotplug support via SCLP
In reply to Jan GlauberAdd SCLP PCI configure/deconfigure and implement a PCI hotplug controller (s390_pci_hpc). The hotplug controller creates a slot for every PCI function in stand-by or configured state. The PCI functions are named after the PCI function ID (fid). By writing to the power attribute in /sys/bus/pci/slots/<fid>/power the PCI function is moved to stand-by or configured state. If moved to the configured state the device is automatically scanned by the s390 PCI layer.
--- arch/s390/include/asm/pci.h | 11 ++ arch/s390/include/asm/sclp.h | 2 + arch/s390/pci/pci.c | 9 ++ drivers/pci/hotplug/Kconfig | 11 ++ drivers/pci/hotplug/Makefile | 1 + drivers/pci/hotplug/s390_pci_hpc.c | 252 +++++++++++++++++++++++++++++++++++++ drivers/s390/char/sclp.h | 3 +- drivers/s390/char/sclp_cmd.c | 64 +++++++++- 8 files changed, 351 insertions(+), 2 deletions(-) create mode 100644 drivers/pci/hotplug/s390_pci_hpc.c
arch/s390/include/asm/pci.h +11 -0
@@ -95,6 +95,11 @@ struct zpci_dev {enum pci_bus_speed max_bus_speed; }; +struct pci_hp_callback_ops { +int (*create_slot) (struct zpci_dev *zdev); +void (*remove_slot) (struct zpci_dev *zdev); +}; +static inline bool zdev_enabled (struct zpci_dev *zdev) {return (zdev->fh & (1UL <<31 )) ? true : false;
@@ -140,4 +145,10 @@ bool zpci_fid_present(u32);int zpci_dma_init (void );void zpci_dma_exit (void ); +/* Hotplug */ +extern struct mutex zpci_list_lock; +extern struct list_head zpci_list; +extern struct pci_hp_callback_ops hotplug_ops; +extern unsigned int pci_probe; +#endif
arch/s390/include/asm/sclp.h +2 -0
@@ -55,5 +55,7 @@ int sclp_chp_read_info(struct sclp_chp_info *info);void sclp_get_ipl_info (struct sclp_ipl_info *info);bool sclp_has_linemode (void );bool sclp_has_vt220 (void ); +int sclp_pci_configure (u32 fid); +int sclp_pci_deconfigure (u32 fid);#endif /* _ASM_S390_SCLP_H */
arch/s390/pci/pci.c +9 -0
@@ -47,7 +47,12 @@/* list of all detected zpci devices */ LIST_HEAD (zpci_list); +EXPORT_SYMBOL_GPL (zpci_list);DEFINE_MUTEX (zpci_list_lock); +EXPORT_SYMBOL_GPL (zpci_list_lock); + +struct pci_hp_callback_ops hotplug_ops; +EXPORT_SYMBOL_GPL (hotplug_ops); static DECLARE_BITMAP(zpci_domain, ZPCI_NR_DEVICES);static DEFINE_SPINLOCK (zpci_domain_lock);
@@ -935,6 +940,8 @@ int zpci_create_device(struct zpci_dev *zdev)mutex_lock (&zpci_list_lock);list_add_tail (&zdev->entry, &zpci_list); +if (hotplug_ops.create_slot) + hotplug_ops.create_slot (zdev);mutex_unlock (&zpci_list_lock);if (zdev->state ==ZPCI_FN_STATE_STANDBY )
@@ -948,6 +955,8 @@ int zpci_create_device(struct zpci_dev *zdev) out_start:mutex_lock (&zpci_list_lock);list_del (&zdev->entry); +if (hotplug_ops.remove_slot) + hotplug_ops.remove_slot (zdev);mutex_unlock (&zpci_list_lock); out_bus:zpci_free_domain (zdev);
drivers/pci/hotplug/Kconfig +11 -0
@@ -151,4 +151,15 @@ config HOTPLUG_PCI_SGI When in doubt, say N. +config HOTPLUG_PCI_S390 + tristate "System z PCI Hotplug Support" + depends on S390 && 64BIT + help + Say Y here if you want to use the System z PCI Hotplug + driver for PCI devices. Without this driver it is not + possible to access stand-by PCI functions nor to deconfigure + PCI functions. + + When in doubt, say Y. + endif # HOTPLUG_PCI
drivers/pci/hotplug/Makefile +1 -0
@@ -18,6 +18,7 @@ obj-$(CONFIG_HOTPLUG_PCI_RPA) += rpaphp.o obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o obj-$(CONFIG_HOTPLUG_PCI_SGI) += sgi_hotplug.o obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o +obj-$(CONFIG_HOTPLUG_PCI_S390) += s390_pci_hpc.o # acpiphp_ibm extends acpiphp, so should be linked afterwards.
drivers/pci/hotplug/s390_pci_hpc.c new file +252 -0
252 lines not on this page · raw message
drivers/s390/char/sclp.h +2 -1
@@ -1,5 +1,5 @@/* -* Copyright IBM Corp. 1999, 2009 +* Copyright IBM Corp. 1999,2012 * * Author(s): Martin Peschke <[email protected]> * Martin Schwidefsky <[email protected]>
@@ -103,6 +103,7 @@ extern u64 sclp_facilities;#define SCLP_HAS_CHP_RECONFIG (sclp_facilities & 0x2000000000000000ULL)#define SCLP_HAS_CPU_INFO (sclp_facilities & 0x0800000000000000ULL)#define SCLP_HAS_CPU_RECONFIG (sclp_facilities & 0x0400000000000000ULL) +#define SCLP_HAS_PCI_RECONFIG (sclp_facilities & 0x0000000040000000ULL)struct gds_subvector {
drivers/s390/char/sclp_cmd.c +63 -1
80 lines not on this page · raw message
Signature · 1 line
1.7.12.4
RFC PATCH 8/10 s390/pci: s390 specific PCI sysfs attributes
In reply to Jan GlauberAdd some s390 specific sysfs attributes to the PCI device directory. The following attributes are introduced:
- function_id (PCI function ID)
- function_handle (PCI function handle)
- pchid (PCI channel ID)
- pfgid (PCI function group ID aka PCI root complex)
--- arch/s390/include/asm/pci.h | 4 +++ arch/s390/pci/Makefile | 2 +- arch/s390/pci/pci.c | 6 ++++ arch/s390/pci/pci_sysfs.c | 86 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 arch/s390/pci/pci_sysfs.c
arch/s390/include/asm/pci.h +4 -0
@@ -141,6 +141,10 @@ struct zpci_dev *get_zdev(struct pci_dev *);struct zpci_dev *get_zdev_by_fid (u32 );bool zpci_fid_present (u32 ); +/* sysfs */ +int zpci_sysfs_add_device (struct device *); +void zpci_sysfs_remove_device (struct device *); +/* DMA */ int zpci_dma_init (void );void zpci_dma_exit (void );
arch/s390/pci/Makefile +1 -1
@@ -3,4 +3,4 @@ # obj-$(CONFIG_PCI) += pci.o pci_dma.o pci_clp.o pci_msi.o \ - pci_event.o + pci_sysfs.o pci_event.o
arch/s390/pci/pci.c +6 -0
@@ -628,6 +628,7 @@ static void zpci_remove_device(struct pci_dev *pdev)dev_info (&pdev->dev,"Removing device %u\n" , zdev->domain); zdev->state =ZPCI_FN_STATE_CONFIGURED ;zpci_dma_exit_device (zdev); +zpci_sysfs_remove_device (&pdev->dev);zpci_unmap_resources (pdev);list_del (&zdev->entry);/* can be called from init */ zdev->pdev =NULL ;
@@ -676,6 +677,11 @@ void pcibios_disable_device(struct pci_dev *pdev) pdev->sysdata =NULL ; } +int pcibios_add_platform_entries (struct pci_dev *pdev) +{ +return zpci_sysfs_add_device (&pdev->dev); +} +int zpci_request_irq (unsigned int irq,irq_handler_t handler,void *data) {int msi_nr =irq_to_msi_nr (irq);
arch/s390/pci/pci_sysfs.c new file +86 -0
86 lines not on this page · raw message
Signature · 1 line
1.7.12.4
RFC PATCH 9/10 s390/pci: add PCI Kconfig options
In reply to Jan Glauber--- arch/s390/Kconfig | 56 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 6 deletions(-)
arch/s390/Kconfig +50 -6
@@ -34,12 +34,6 @@ config GENERIC_BUG config GENERIC_BUG_RELATIVE_POINTERS def_bool y -config NO_IOMEM - def_bool y - -config NO_DMA - def_bool y - config ARCH_DMA_ADDR_T_64BIT def_bool 64BIT
@@ -58,6 +52,12 @@ config KEXEC config AUDIT_ARCH def_bool y +config NO_IOPORT + def_bool y + +config PCI_QUIRKS + def_bool n + config S390 def_bool y select USE_GENERIC_SMP_HELPERS if SMP
@@ -423,6 +423,50 @@ config QDIO If unsure, say Y. +menuconfig PCI + bool "PCI support" + default y + depends on 64BIT + select ARCH_SUPPORTS_MSI + select PCI_MSI + help + Enable PCI support. + +if PCI + +config PCI_NR_FUNCTIONS + int "Maximum number of PCI functions (1-4096)" + range 1 4096 + default "64" + help + This allows you to specify the maximum number of PCI functions which + this kernel will support. + +source "drivers/pci/Kconfig" +source "drivers/pci/pcie/Kconfig" +source "drivers/pci/hotplug/Kconfig" + +endif # PCI + +config PCI_DOMAINS + def_bool PCI + +config HAS_IOMEM + def_bool PCI + +config IOMMU_HELPER + def_bool PCI + +config HAS_DMA + def_bool PCI + select HAVE_DMA_API_DEBUG + +config NEED_SG_DMA_LENGTH + def_bool PCI + +config HAVE_DMA_ATTRS + def_bool PCI + config CHSC_SCH def_tristate m prompt "Support for CHSC subchannels"
Signature · 1 line
1.7.12.4
RFC PATCH 10/10 vga: compile fix, disable vga for s390
In reply to Jan Glauber--- drivers/gpu/vga/Kconfig | 2 +- include/video/vga.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/vga/Kconfig +1 -1
@@ -1,7 +1,7 @@ config VGA_ARB bool "VGA Arbitration" if EXPERT default y - depends on PCI + depends on (PCI && !S390) help Some "legacy" VGA devices implemented on PCI typically have the same hard-decoded addresses as they did on ISA. When multiple PCI devices
include/video/vga.h +2 -0
@@ -19,7 +19,9 @@#include <linux/types.h> #include <asm/io.h> +#ifndef __s390x__#include <asm/vga.h> +#endif #include <asm/byteorder.h>
Signature · 1 line
1.7.12.4