diff options
author | Jesse Barnes <jbarnes@sgi.com> | 2005-01-09 22:23:32 -0800 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2005-01-09 22:23:32 -0800 |
commit | 872a9465d098476c5cf2e21c53deb70be31b3270 (patch) | |
tree | a69d807544be95bae6d5fcc1556863f9ea461151 /arch | |
parent | a5bd8684a39833f6bb1599744300e3dac442040e (diff) | |
download | history-872a9465d098476c5cf2e21c53deb70be31b3270.tar.gz |
[IA64] implements the features required for the HAVE_PCI_LEGACY code in sysfs
This patch implements the features required for the HAVE_PCI_LEGACY code in
sysfs. It allows userspace applications to access legacy I/O ports an memory
space using files in sysfs on a per-bus basis. Tested on sn2, but it
*should* work on other ia64 platforms as well (though zx1 will probably need
machine vectors to do routing of non-base busses).
Signed-off-by: Jesse Barnes <jbarnes@sgi.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/ia64/pci/pci.c | 114 | ||||
-rw-r--r-- | arch/ia64/sn/pci/pci_dma.c | 64 |
2 files changed, 177 insertions, 1 deletions
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 01f8eabf3636be..edc8915bb4159b 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -6,6 +6,7 @@ * Copyright (C) 2002 Hewlett-Packard Co * David Mosberger-Tang <davidm@hpl.hp.com> * Bjorn Helgaas <bjorn_helgaas@hp.com> + * Copyright (C) 2004 Silicon Graphics, Inc. * * Note: Above list of copyright holders is incomplete... */ @@ -526,7 +527,7 @@ pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma, * Leave vm_pgoff as-is, the PCI space address is the physical * address on this platform. */ - vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO); + vma->vm_flags |= (VM_SHM | VM_RESERVED | VM_IO); if (write_combine) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); @@ -541,6 +542,117 @@ pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma, } /** + * pci_mmap_legacy_page_range - map legacy memory space to userland + * @bus: bus whose legacy space we're mapping + * @vma: vma passed in by mmap + * + * Map legacy memory space for this device back to userspace using a machine + * vector to get the base address. + */ +int +pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma) +{ + char *addr; + + addr = pci_get_legacy_mem(bus); + if (IS_ERR(addr)) + return PTR_ERR(addr); + + vma->vm_pgoff += (unsigned long)addr >> PAGE_SHIFT; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= (VM_SHM | VM_RESERVED | VM_IO); + + if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} + +/** + * ia64_pci_get_legacy_mem - generic legacy mem routine + * @bus: bus to get legacy memory base address for + * + * Find the base of legacy memory for @bus. This is typically the first + * megabyte of bus address space for @bus or is simply 0 on platforms whose + * chipsets support legacy I/O and memory routing. Returns the base address + * or an error pointer if an error occurred. + * + * This is the ia64 generic version of this routine. Other platforms + * are free to override it with a machine vector. + */ +char *ia64_pci_get_legacy_mem(struct pci_bus *bus) +{ + return (char *)__IA64_UNCACHED_OFFSET; +} + +/** + * ia64_pci_legacy_read - read from legacy I/O space + * @bus: bus to read + * @port: legacy port value + * @val: caller allocated storage for returned value + * @size: number of bytes to read + * + * Simply reads @size bytes from @port and puts the result in @val. + * + * Again, this (and the write routine) are generic versions that can be + * overridden by the platform. This is necessary on platforms that don't + * support legacy I/O routing or that hard fail on legacy I/O timeouts. + */ +int ia64_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size) +{ + int ret = size; + + switch (size) { + case 1: + *val = inb(port); + break; + case 2: + *val = inw(port); + break; + case 4: + *val = inl(port); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * ia64_pci_legacy_write - perform a legacy I/O write + * @bus: bus pointer + * @port: port to write + * @val: value to write + * @size: number of bytes to write from @val + * + * Simply writes @size bytes of @val to @port. + */ +int ia64_pci_legacy_write(struct pci_dev *bus, u16 port, u32 val, u8 size) +{ + int ret = 0; + + switch (size) { + case 1: + outb(val, port); + break; + case 2: + outw(val, port); + break; + case 4: + outl(val, port); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** * pci_cacheline_size - determine cacheline size for PCI devices * @dev: void * diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c index 71f311dc04c3bd..4187f920d26d17 100644 --- a/arch/ia64/sn/pci/pci_dma.c +++ b/arch/ia64/sn/pci/pci_dma.c @@ -475,3 +475,67 @@ EXPORT_SYMBOL(sn_pci_alloc_consistent); EXPORT_SYMBOL(sn_pci_free_consistent); EXPORT_SYMBOL(sn_pci_dma_supported); EXPORT_SYMBOL(sn_dma_mapping_error); + +char *sn_pci_get_legacy_mem(struct pci_bus *bus) +{ + if (!SN_PCIBUS_BUSSOFT(bus)) + return ERR_PTR(-ENODEV); + + return (char *)(SN_PCIBUS_BUSSOFT(bus)->bs_legacy_mem | __IA64_UNCACHED_OFFSET); +} + +int sn_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size) +{ + unsigned long addr; + int ret; + + if (!SN_PCIBUS_BUSSOFT(bus)) + return -ENODEV; + + addr = SN_PCIBUS_BUSSOFT(bus)->bs_legacy_io | __IA64_UNCACHED_OFFSET; + addr += port; + + ret = ia64_sn_probe_mem(addr, (long)size, (void *)val); + + if (ret == 2) + return -EINVAL; + + if (ret == 1) + *val = -1; + + return size; +} + +int sn_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size) +{ + int ret = size; + unsigned long paddr; + unsigned long *addr; + + if (!SN_PCIBUS_BUSSOFT(bus)) { + ret = -ENODEV; + goto out; + } + + /* Put the phys addr in uncached space */ + paddr = SN_PCIBUS_BUSSOFT(bus)->bs_legacy_io | __IA64_UNCACHED_OFFSET; + paddr += port; + addr = (unsigned long *)paddr; + + switch (size) { + case 1: + *(volatile u8 *)(addr) = (u8)(val); + break; + case 2: + *(volatile u16 *)(addr) = (u16)(val); + break; + case 4: + *(volatile u32 *)(addr) = (u32)(val); + break; + default: + ret = -EINVAL; + break; + } + out: + return ret; +} |