This patch adds support for legacy_io and legacy_mem files in
bus class directories in sysfs for powerpc
Signed-off-by: Benjamin Herrenschmidt [EMAIL PROTECTED]
---
This is version 3, this time after doing a quilt ref and thus
getting a patch that actually useful. Sorry about the mishap.
arch/powerpc/include/asm/pci-bridge.h |7 +
arch/powerpc/include/asm/pci.h| 11 ++
arch/powerpc/kernel/pci-common.c | 136 +-
3 files changed, 153 insertions(+), 1 deletion(-)
--- linux-work.orig/arch/powerpc/include/asm/pci.h 2008-10-03
19:47:08.0 +1000
+++ linux-work/arch/powerpc/include/asm/pci.h 2008-10-10 10:50:46.0
+1100
@@ -123,6 +123,16 @@ int pci_mmap_page_range(struct pci_dev *
/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
#define HAVE_PCI_MMAP 1
+extern int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val,
+ size_t count);
+extern int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val,
+ size_t count);
+extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
+ struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state);
+
+#define HAVE_PCI_LEGACY1
+
#if defined(CONFIG_PPC64) || defined(CONFIG_NOT_COHERENT_CACHE)
/*
* For 64-bit kernels, pci_unmap_{single,page} is not a nop.
@@ -226,5 +236,6 @@ extern void pci_resource_to_user(const s
extern void pcibios_do_bus_setup(struct pci_bus *bus);
extern void pcibios_fixup_of_probed_bus(struct pci_bus *bus);
+
#endif /* __KERNEL__ */
#endif /* __ASM_POWERPC_PCI_H */
Index: linux-work/arch/powerpc/kernel/pci-common.c
===
--- linux-work.orig/arch/powerpc/kernel/pci-common.c2008-10-03
19:47:08.0 +1000
+++ linux-work/arch/powerpc/kernel/pci-common.c 2008-10-14 11:32:38.0
+1100
@@ -452,7 +452,8 @@ pgprot_t pci_phys_mem_access_prot(struct
pci_dev_put(pdev);
}
- DBG(non-PCI map for %lx, prot: %lx\n, offset, prot);
+ DBG(non-PCI map for %llx, prot: %lx\n,
+ (unsigned long long)offset, prot);
return __pgprot(prot);
}
@@ -491,6 +492,131 @@ int pci_mmap_page_range(struct pci_dev *
return ret;
}
+/* This provides legacy IO read access on a bus */
+int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val, size_t size)
+{
+ unsigned long offset;
+ struct pci_controller *hose = pci_bus_to_host(bus);
+ struct resource *rp = hose-io_resource;
+ void __iomem *addr;
+
+ /* Check if port can be supported by that bus. We only check
+* the ranges of the PHB though, not the bus itself as the rules
+* for forwarding legacy cycles down bridges are not our problem
+* here. So if the host bridge supports it, we do it.
+*/
+ offset = (unsigned long)hose-io_base_virt - _IO_BASE;
+ offset += port;
+
+ if (!(rp-flags IORESOURCE_IO))
+ return -ENXIO;
+ if (offset rp-start || (offset + size) rp-end)
+ return -ENXIO;
+ addr = hose-io_base_virt + port;
+
+ switch(size) {
+ case 1:
+ *((u8 *)val) = in_8(addr);
+ return 1;
+ case 2:
+ if (port 1)
+ return -EINVAL;
+ *((u16 *)val) = in_le16(addr);
+ return 2;
+ case 4:
+ if (port 3)
+ return -EINVAL;
+ *((u32 *)val) = in_le32(addr);
+ return 4;
+ }
+ return -EINVAL;
+}
+
+/* This provides legacy IO write access on a bus */
+int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, size_t size)
+{
+ unsigned long offset;
+ struct pci_controller *hose = pci_bus_to_host(bus);
+ struct resource *rp = hose-io_resource;
+ void __iomem *addr;
+
+ /* Check if port can be supported by that bus. We only check
+* the ranges of the PHB though, not the bus itself as the rules
+* for forwarding legacy cycles down bridges are not our problem
+* here. So if the host bridge supports it, we do it.
+*/
+ offset = (unsigned long)hose-io_base_virt - _IO_BASE;
+ offset += port;
+
+ if (!(rp-flags IORESOURCE_IO))
+ return -ENXIO;
+ if (offset rp-start || (offset + size) rp-end)
+ return -ENXIO;
+ addr = hose-io_base_virt + port;
+
+ /* WARNING: The generic code is idiotic. It gets passed a pointer
+* to what can be a 1, 2 or 4 byte quantity and always reads that
+* as a u32, which means that we have to correct the location of
+* the data read within those 32 bits for size 1 and 2
+*/
+ switch(size) {
+ case 1:
+ out_8(addr, val 24);
+ return