diff options
Diffstat (limited to 'arch/ia64/hp/common/sba_iommu.c')
| -rw-r--r-- | arch/ia64/hp/common/sba_iommu.c | 145 |
1 files changed, 77 insertions, 68 deletions
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index 4ce8d1358fe..344387a5540 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -37,12 +37,12 @@ #include <linux/crash_dump.h> #include <linux/iommu-helper.h> #include <linux/dma-mapping.h> +#include <linux/prefetch.h> #include <asm/delay.h> /* ia64_get_itc() */ #include <asm/io.h> #include <asm/page.h> /* PAGE_OFFSET */ #include <asm/dma.h> -#include <asm/system.h> /* wmb() */ #include <asm/acpi-ext.h> @@ -242,7 +242,7 @@ struct ioc { struct pci_dev *sac_only_dev; }; -static struct ioc *ioc_list; +static struct ioc *ioc_list, *ioc_found; static int reserve_sba_gart = 1; static SBA_INLINE void sba_mark_invalid(struct ioc *, dma_addr_t, size_t); @@ -255,7 +255,7 @@ static u64 prefetch_spill_page; #endif #ifdef CONFIG_PCI -# define GET_IOC(dev) (((dev)->bus == &pci_bus_type) \ +# define GET_IOC(dev) ((dev_is_pci(dev)) \ ? ((struct ioc *) PCI_CONTROLLER(to_pci_dev(dev))->iommu) : NULL) #else # define GET_IOC(dev) NULL @@ -914,7 +914,7 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) * @dir: R/W or both. * @attrs: optional dma attributes * - * See Documentation/PCI/PCI-DMA-mapping.txt + * See Documentation/DMA-API-HOWTO.txt */ static dma_addr_t sba_map_page(struct device *dev, struct page *page, unsigned long poff, size_t size, @@ -1043,7 +1043,7 @@ sba_mark_clean(struct ioc *ioc, dma_addr_t iova, size_t size) * @dir: R/W or both. * @attrs: optional dma attributes * - * See Documentation/PCI/PCI-DMA-mapping.txt + * See Documentation/DMA-API-HOWTO.txt */ static void sba_unmap_page(struct device *dev, dma_addr_t iova, size_t size, enum dma_data_direction dir, struct dma_attrs *attrs) @@ -1063,7 +1063,7 @@ static void sba_unmap_page(struct device *dev, dma_addr_t iova, size_t size, /* ** Address does not fall w/in IOVA, must be bypassing */ - DBG_BYPASS("sba_unmap_single_atttrs() bypass addr: 0x%lx\n", + DBG_BYPASS("sba_unmap_single_attrs() bypass addr: 0x%lx\n", iova); #ifdef ENABLE_MARK_CLEAN @@ -1126,10 +1126,11 @@ void sba_unmap_single_attrs(struct device *dev, dma_addr_t iova, size_t size, * @size: number of bytes mapped in driver buffer. * @dma_handle: IOVA of new buffer. * - * See Documentation/PCI/PCI-DMA-mapping.txt + * See Documentation/DMA-API-HOWTO.txt */ static void * -sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flags) +sba_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, + gfp_t flags, struct dma_attrs *attrs) { struct ioc *ioc; void *addr; @@ -1139,11 +1140,13 @@ sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp #ifdef CONFIG_NUMA { + int node = ioc->node; struct page *page; - page = alloc_pages_exact_node(ioc->node == MAX_NUMNODES ? - numa_node_id() : ioc->node, flags, - get_order(size)); + if (node == NUMA_NO_NODE) + node = numa_node_id(); + + page = alloc_pages_exact_node(node, flags, get_order(size)); if (unlikely(!page)) return NULL; @@ -1189,10 +1192,10 @@ sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp * @vaddr: virtual address IOVA of "consistent" buffer. * @dma_handler: IO virtual address of "consistent" buffer. * - * See Documentation/PCI/PCI-DMA-mapping.txt + * See Documentation/DMA-API-HOWTO.txt */ -static void sba_free_coherent (struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) +static void sba_free_coherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle, struct dma_attrs *attrs) { sba_unmap_single_attrs(dev, dma_handle, size, 0, NULL); free_pages((unsigned long) vaddr, get_order(size)); @@ -1452,7 +1455,7 @@ static void sba_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist, * @dir: R/W or both. * @attrs: optional dma attributes * - * See Documentation/PCI/PCI-DMA-mapping.txt + * See Documentation/DMA-API-HOWTO.txt */ static int sba_map_sg_attrs(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction dir, @@ -1548,7 +1551,7 @@ static int sba_map_sg_attrs(struct device *dev, struct scatterlist *sglist, * @dir: R/W or both. * @attrs: optional dma attributes * - * See Documentation/PCI/PCI-DMA-mapping.txt + * See Documentation/DMA-API-HOWTO.txt */ static void sba_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction dir, @@ -1595,7 +1598,7 @@ static void sba_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist, * ***************************************************************/ -static void __init +static void ioc_iova_init(struct ioc *ioc) { int tcnfg; @@ -1806,20 +1809,13 @@ static struct ioc_iommu ioc_iommu_info[] __initdata = { { SX2000_IOC_ID, "sx2000", NULL }, }; -static struct ioc * __init -ioc_init(unsigned long hpa, void *handle) +static void ioc_init(unsigned long hpa, struct ioc *ioc) { - struct ioc *ioc; struct ioc_iommu *info; - ioc = kzalloc(sizeof(*ioc), GFP_KERNEL); - if (!ioc) - return NULL; - ioc->next = ioc_list; ioc_list = ioc; - ioc->handle = handle; ioc->ioc_hpa = ioremap(hpa, 0x1000); ioc->func_id = READ_REG(ioc->ioc_hpa + IOC_FUNC_ID); @@ -1860,8 +1856,6 @@ ioc_init(unsigned long hpa, void *handle) "%s %d.%d HPA 0x%lx IOVA space %dMb at 0x%lx\n", ioc->name, (ioc->rev >> 4) & 0xF, ioc->rev & 0xF, hpa, ioc->iov_size >> 20, ioc->ibase); - - return ioc; } @@ -1913,7 +1907,7 @@ ioc_show(struct seq_file *s, void *v) seq_printf(s, "Hewlett Packard %s IOC rev %d.%d\n", ioc->name, ((ioc->rev >> 4) & 0xF), (ioc->rev & 0xF)); #ifdef CONFIG_NUMA - if (ioc->node != MAX_NUMNODES) + if (ioc->node != NUMA_NO_NODE) seq_printf(s, "NUMA node : %d\n", ioc->node); #endif seq_printf(s, "IOVA size : %ld MB\n", ((ioc->pdir_size >> 3) * iovp_size)/(1024*1024)); @@ -1991,7 +1985,7 @@ sba_connect_bus(struct pci_bus *bus) if (PCI_CONTROLLER(bus)->iommu) return; - handle = PCI_CONTROLLER(bus)->acpi_handle; + handle = acpi_device_handle(PCI_CONTROLLER(bus)->companion); if (!handle) return; @@ -2014,47 +2008,35 @@ sba_connect_bus(struct pci_bus *bus) printk(KERN_WARNING "No IOC for PCI Bus %04x:%02x in ACPI\n", pci_domain_nr(bus), bus->number); } -#ifdef CONFIG_NUMA static void __init sba_map_ioc_to_node(struct ioc *ioc, acpi_handle handle) { +#ifdef CONFIG_NUMA unsigned int node; - int pxm; - - ioc->node = MAX_NUMNODES; - pxm = acpi_get_pxm(handle); - - if (pxm < 0) - return; - - node = pxm_to_node(pxm); - - if (node >= MAX_NUMNODES || !node_online(node)) - return; + node = acpi_get_node(handle); + if (node != NUMA_NO_NODE && !node_online(node)) + node = NUMA_NO_NODE; ioc->node = node; - return; -} -#else -#define sba_map_ioc_to_node(ioc, handle) #endif +} -static int __init -acpi_sba_ioc_add(struct acpi_device *device) +static void acpi_sba_ioc_add(struct ioc *ioc) { - struct ioc *ioc; + acpi_handle handle = ioc->handle; acpi_status status; u64 hpa, length; struct acpi_device_info *adi; - status = hp_acpi_csr_space(device->handle, &hpa, &length); + ioc_found = ioc->next; + status = hp_acpi_csr_space(handle, &hpa, &length); if (ACPI_FAILURE(status)) - return 1; + goto err; - status = acpi_get_object_info(device->handle, &adi); + status = acpi_get_object_info(handle, &adi); if (ACPI_FAILURE(status)) - return 1; + goto err; /* * For HWP0001, only SBA appears in ACPI namespace. It encloses the PCI @@ -2075,13 +2057,13 @@ acpi_sba_ioc_add(struct acpi_device *device) if (!iovp_shift) iovp_shift = 12; - ioc = ioc_init(hpa, device->handle); - if (!ioc) - return 1; - + ioc_init(hpa, ioc); /* setup NUMA node association */ - sba_map_ioc_to_node(ioc, device->handle); - return 0; + sba_map_ioc_to_node(ioc, handle); + return; + + err: + kfree(ioc); } static const struct acpi_device_id hp_ioc_iommu_device_ids[] = { @@ -2089,14 +2071,35 @@ static const struct acpi_device_id hp_ioc_iommu_device_ids[] = { {"HWP0004", 0}, {"", 0}, }; -static struct acpi_driver acpi_sba_ioc_driver = { - .name = "IOC IOMMU Driver", - .ids = hp_ioc_iommu_device_ids, - .ops = { - .add = acpi_sba_ioc_add, - }, + +static int acpi_sba_ioc_attach(struct acpi_device *device, + const struct acpi_device_id *not_used) +{ + struct ioc *ioc; + + ioc = kzalloc(sizeof(*ioc), GFP_KERNEL); + if (!ioc) + return -ENOMEM; + + ioc->next = ioc_found; + ioc_found = ioc; + ioc->handle = device->handle; + return 1; +} + + +static struct acpi_scan_handler acpi_sba_ioc_handler = { + .ids = hp_ioc_iommu_device_ids, + .attach = acpi_sba_ioc_attach, }; +static int __init acpi_sba_ioc_init_acpi(void) +{ + return acpi_scan_add_handler(&acpi_sba_ioc_handler); +} +/* This has to run before acpi_scan_init(). */ +arch_initcall(acpi_sba_ioc_init_acpi); + extern struct dma_map_ops swiotlb_dma_ops; static int __init @@ -2121,7 +2124,13 @@ sba_init(void) } #endif - acpi_bus_register_driver(&acpi_sba_ioc_driver); + /* + * ioc_found should be populated by the acpi_sba_ioc_handler's .attach() + * routine, but that only happens if acpi_scan_init() has already run. + */ + while (ioc_found) + acpi_sba_ioc_add(ioc_found); + if (!ioc_list) { #ifdef CONFIG_IA64_GENERIC /* @@ -2212,8 +2221,8 @@ sba_page_override(char *str) __setup("sbapagesize=",sba_page_override); struct dma_map_ops sba_dma_ops = { - .alloc_coherent = sba_alloc_coherent, - .free_coherent = sba_free_coherent, + .alloc = sba_alloc_coherent, + .free = sba_free_coherent, .map_page = sba_map_page, .unmap_page = sba_unmap_page, .map_sg = sba_map_sg_attrs, |
