From 8eb6c6e3b9c8bfed3d75536ab142d7694627c2e5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Jun 2006 16:11:35 +0200 Subject: [PATCH] powerpc: node-aware dma allocations Make sure dma_alloc_coherent allocates memory from the local node. This is important on Cell where we avoid going through the slow cpu interconnect. Note: I could only test this patch on Cell, it should be verified on some pseries machine by those that have the hardware. Signed-off-by: Christoph Hellwig Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/iommu.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'arch/powerpc/kernel/iommu.c') diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index 4eba60a3289..cbb794556d0 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -536,11 +536,12 @@ void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle, * to the dma address (mapping) of the first page. */ void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size, - dma_addr_t *dma_handle, unsigned long mask, gfp_t flag) + dma_addr_t *dma_handle, unsigned long mask, gfp_t flag, int node) { void *ret = NULL; dma_addr_t mapping; unsigned int npages, order; + struct page *page; size = PAGE_ALIGN(size); npages = size >> PAGE_SHIFT; @@ -560,9 +561,10 @@ void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size, return NULL; /* Alloc enough pages (and possibly more) */ - ret = (void *)__get_free_pages(flag, order); - if (!ret) + page = alloc_pages_node(flag, order, node); + if (!page) return NULL; + ret = page_address(page); memset(ret, 0, size); /* Set up tces to cover the allocated range */ @@ -570,9 +572,9 @@ void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size, mask >> PAGE_SHIFT, order); if (mapping == DMA_ERROR_CODE) { free_pages((unsigned long)ret, order); - ret = NULL; - } else - *dma_handle = mapping; + return NULL; + } + *dma_handle = mapping; return ret; } -- cgit v1.2.3-70-g09d2 From 050613545b389825c1f5beb67fa2667b727f866d Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 10 Jun 2006 18:17:35 +1000 Subject: powerpc: Fix bug in iommu_alloc_coherent causing hang during boot In commit 8eb6c6e3b9c8bfed3d75536ab142d7694627c2e5, Christoph Hellwig made iommu_alloc_coherent able to do node-local allocations, but unfortunately got the order of the arguments to alloc_pages_node wrong. This fixes it. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/kernel/iommu.c') diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index cbb794556d0..cef8cba8329 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -561,7 +561,7 @@ void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size, return NULL; /* Alloc enough pages (and possibly more) */ - page = alloc_pages_node(flag, order, node); + page = alloc_pages_node(node, flag, order); if (!page) return NULL; ret = page_address(page); -- cgit v1.2.3-70-g09d2 From ca1588e71b70534e18368a46a3aad9b25dff941d Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sat, 10 Jun 2006 20:58:08 +1000 Subject: [POWERPC] node local IOMMU tables Allocate IOMMU tables local to the relevant node. Signed-off-by: Anton Blanchard Acked-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/iommu.c | 9 +++++---- arch/powerpc/kernel/vio.c | 6 +++--- arch/powerpc/platforms/iseries/iommu.c | 2 +- arch/powerpc/platforms/pseries/iommu.c | 23 +++++++++++++---------- arch/powerpc/sysdev/dart_iommu.c | 2 +- include/asm-powerpc/iommu.h | 3 ++- 6 files changed, 25 insertions(+), 20 deletions(-) (limited to 'arch/powerpc/kernel/iommu.c') diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index cef8cba8329..7cb77c20fc5 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -418,10 +418,11 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, * Build a iommu_table structure. This contains a bit map which * is used to manage allocation of the tce space. */ -struct iommu_table *iommu_init_table(struct iommu_table *tbl) +struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) { unsigned long sz; static int welcomed = 0; + struct page *page; /* Set aside 1/4 of the table for large allocations. */ tbl->it_halfpoint = tbl->it_size * 3 / 4; @@ -429,10 +430,10 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl) /* number of bytes needed for the bitmap */ sz = (tbl->it_size + 7) >> 3; - tbl->it_map = (unsigned long *)__get_free_pages(GFP_ATOMIC, get_order(sz)); - if (!tbl->it_map) + page = alloc_pages_node(nid, GFP_ATOMIC, get_order(sz)); + if (!page) panic("iommu_init_table: Can't allocate %ld bytes\n", sz); - + tbl->it_map = page_address(page); memset(tbl->it_map, 0, sz); tbl->it_hint = 0; diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index e746686d48b..cdf5867838a 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -60,9 +60,9 @@ static void __init iommu_vio_init(void) vio_iommu_table = veth_iommu_table; vio_iommu_table.it_offset += veth_iommu_table.it_size; - if (!iommu_init_table(&veth_iommu_table)) + if (!iommu_init_table(&veth_iommu_table, -1)) printk("Virtual Bus VETH TCE table failed.\n"); - if (!iommu_init_table(&vio_iommu_table)) + if (!iommu_init_table(&vio_iommu_table, -1)) printk("Virtual Bus VIO TCE table failed.\n"); } #endif @@ -98,7 +98,7 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) tbl->it_busno = 0; tbl->it_type = TCE_VB; - return iommu_init_table(tbl); + return iommu_init_table(tbl, -1); } } diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index a992f6af249..e3bd2015f2c 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -173,7 +173,7 @@ void iommu_devnode_init_iSeries(struct device_node *dn) /* Look for existing tce table */ pdn->iommu_table = iommu_table_find(tbl); if (pdn->iommu_table == NULL) - pdn->iommu_table = iommu_init_table(tbl); + pdn->iommu_table = iommu_init_table(tbl, -1); else kfree(tbl); } diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 44a507e6fb3..2f66dc6503f 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -368,10 +368,11 @@ static void iommu_bus_setup_pSeries(struct pci_bus *bus) pci->phb->dma_window_size = 0x8000000ul; pci->phb->dma_window_base_cur = 0x8000000ul; - tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); + tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + pci->phb->node); iommu_table_setparms(pci->phb, dn, tbl); - pci->iommu_table = iommu_init_table(tbl); + pci->iommu_table = iommu_init_table(tbl, pci->phb->node); /* Divide the rest (1.75GB) among the children */ pci->phb->dma_window_size = 0x80000000ul; @@ -414,12 +415,12 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus) ppci->bussubno = bus->number; - tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table), - GFP_KERNEL); + tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + ppci->phb->node); iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window); - ppci->iommu_table = iommu_init_table(tbl); + ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node); } if (pdn != dn) @@ -442,9 +443,11 @@ static void iommu_dev_setup_pSeries(struct pci_dev *dev) */ if (!dev->bus->self) { DBG(" --> first child, no bridge. Allocating iommu table.\n"); - tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); + tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + PCI_DN(dn)->phb->node); iommu_table_setparms(PCI_DN(dn)->phb, dn, tbl); - PCI_DN(mydn)->iommu_table = iommu_init_table(tbl); + PCI_DN(dn)->iommu_table = iommu_init_table(tbl, + PCI_DN(dn)->phb->node); return; } @@ -526,12 +529,12 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev) /* iommu_table_setparms_lpar needs bussubno. */ pci->bussubno = pci->phb->bus->number; - tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table), - GFP_KERNEL); + tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + pci->phb->node); iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window); - pci->iommu_table = iommu_init_table(tbl); + pci->iommu_table = iommu_init_table(tbl, pci->phb->node); } if (pdn != dn) diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c index 38087bd6e3c..6232091cc72 100644 --- a/arch/powerpc/sysdev/dart_iommu.c +++ b/arch/powerpc/sysdev/dart_iommu.c @@ -246,7 +246,7 @@ static void iommu_table_dart_setup(void) iommu_table_dart.it_base = (unsigned long)dart_vbase; iommu_table_dart.it_index = 0; iommu_table_dart.it_blocksize = 1; - iommu_init_table(&iommu_table_dart); + iommu_init_table(&iommu_table_dart, -1); /* Reserve the last page of the DART to avoid possible prefetch * past the DART mapped area diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h index 9065f6c972a..32dac0ac683 100644 --- a/include/asm-powerpc/iommu.h +++ b/include/asm-powerpc/iommu.h @@ -67,7 +67,8 @@ extern void iommu_free_table(struct device_node *dn); /* Initializes an iommu_table based in values set in the passed-in * structure */ -extern struct iommu_table *iommu_init_table(struct iommu_table * tbl); +extern struct iommu_table *iommu_init_table(struct iommu_table * tbl, + int nid); extern int iommu_map_sg(struct device *dev, struct iommu_table *tbl, struct scatterlist *sglist, int nelems, unsigned long mask, -- cgit v1.2.3-70-g09d2