* [PATCH 4/4] Avoid DMA exception when using axon_msi with IOMMU
2008-01-22 11:04 Michael Ellerman
@ 2008-01-22 11:04 ` Michael Ellerman
0 siblings, 0 replies; 9+ messages in thread
From: Michael Ellerman @ 2008-01-22 11:04 UTC (permalink / raw)
To: linuxppc-dev; +Cc: cbe-oss-dev
There's a brown-paper-bag bug in axon_msi, we pass the address of our
FIFO directly to the hardware, without DMA mapping it. This leads to
DMA exceptions if you enable MSI & the IOMMU.
The fix is to correctly DMA map the fifo, dma_alloc_coherent() does
what we want - and we need to track the virt & phys addresses.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/platforms/cell/axon_msi.c | 21 ++++++++++-----------
1 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
index 8de3d23..c546879 100644
--- a/arch/powerpc/platforms/cell/axon_msi.c
+++ b/arch/powerpc/platforms/cell/axon_msi.c
@@ -65,7 +65,8 @@
struct axon_msic {
struct irq_host *irq_host;
- __le32 *fifo;
+ __le32 *fifo_virt;
+ dma_addr_t fifo_phys;
dcr_host_t dcr_host;
u32 read_offset;
};
@@ -91,7 +92,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
while (msic->read_offset != write_offset) {
idx = msic->read_offset / sizeof(__le32);
- msi = le32_to_cpu(msic->fifo[idx]);
+ msi = le32_to_cpu(msic->fifo_virt[idx]);
msi &= 0xFFFF;
pr_debug("axon_msi: woff %x roff %x msi %x\n",
@@ -306,7 +307,6 @@ static int axon_msi_shutdown(struct of_device *device)
static int axon_msi_probe(struct of_device *device,
const struct of_device_id *device_id)
{
- struct page *page;
struct device_node *dn = device->node;
struct axon_msic *msic;
unsigned int virq;
@@ -338,16 +338,14 @@ static int axon_msi_probe(struct of_device *device,
goto out_free_msic;
}
- page = alloc_pages_node(of_node_to_nid(dn), GFP_KERNEL,
- get_order(MSIC_FIFO_SIZE_BYTES));
- if (!page) {
+ msic->fifo_virt = dma_alloc_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES,
+ &msic->fifo_phys, GFP_KERNEL);
+ if (!msic->fifo_virt) {
printk(KERN_ERR "axon_msi: couldn't allocate fifo for %s\n",
dn->full_name);
goto out_free_msic;
}
- msic->fifo = page_address(page);
-
msic->irq_host = irq_alloc_host(of_node_get(dn), IRQ_HOST_MAP_NOMAP,
NR_IRQS, &msic_host_ops, 0);
if (!msic->irq_host) {
@@ -370,9 +368,9 @@ static int axon_msi_probe(struct of_device *device,
pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq);
/* Enable the MSIC hardware */
- msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, (u64)msic->fifo >> 32);
+ msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, msic->fifo_phys >> 32);
msic_dcr_write(msic, MSIC_BASE_ADDR_LO_REG,
- (u64)msic->fifo & 0xFFFFFFFF);
+ msic->fifo_phys & 0xFFFFFFFF);
msic_dcr_write(msic, MSIC_CTRL_REG,
MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
MSIC_CTRL_FIFO_SIZE);
@@ -390,7 +388,8 @@ static int axon_msi_probe(struct of_device *device,
out_free_host:
kfree(msic->irq_host);
out_free_fifo:
- __free_pages(virt_to_page(msic->fifo), get_order(MSIC_FIFO_SIZE_BYTES));
+ dma_free_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES, msic->fifo_virt,
+ msic->fifo_phys);
out_free_msic:
kfree(msic);
out:
--
1.5.2.rc1.1884.g59b20
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 1/4] Search for and publish cell OF platform devices earlier
@ 2008-01-25 5:59 Michael Ellerman
2008-01-25 5:59 ` [PATCH 2/4] Create and hook up of_platform_device_shutdown Michael Ellerman
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Michael Ellerman @ 2008-01-25 5:59 UTC (permalink / raw)
To: linuxppc-dev; +Cc: cbe-oss-dev
Currently cell publishes OF devices at device_initcall() time, which
means the earliest a driver can bind to a device is also device_initcall()
time. We have a driver we want to register before other devices, so
publish the devices at subsys_initcall() time.
This should not cause any behaviour change for existing drivers, as they
are still bound at device_initcall() time.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/platforms/cell/setup.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index e6534b5..a7f609b 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -98,7 +98,7 @@ static int __init cell_publish_devices(void)
}
return 0;
}
-machine_device_initcall(cell, cell_publish_devices);
+machine_subsys_initcall(cell, cell_publish_devices);
static void cell_mpic_cascade(unsigned int irq, struct irq_desc *desc)
{
--
1.5.2.rc1.1884.g59b20
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/4] Create and hook up of_platform_device_shutdown
2008-01-25 5:59 [PATCH 1/4] Search for and publish cell OF platform devices earlier Michael Ellerman
@ 2008-01-25 5:59 ` Michael Ellerman
2008-02-05 0:19 ` Benjamin Herrenschmidt
2008-01-25 5:59 ` [PATCH 3/4] Convert axon_msi to an of_platform driver Michael Ellerman
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Michael Ellerman @ 2008-01-25 5:59 UTC (permalink / raw)
To: linuxppc-dev; +Cc: sparclinux, tnt, cbe-oss-dev, m8, davem
Although of_platform_device's can have a shutdown routine, at the moment
the bus code doesn't actually call it. So add the required glue to
hook the shutdown routine.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/of/platform.c | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
CC various folks who've written/touched of_platform_drivers which already
have shutdown routines. These routines have never been called so they're
about to get their first testing.
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index b47bb2d..ca09a63 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -85,6 +85,15 @@ static int of_platform_device_resume(struct device * dev)
return error;
}
+static void of_platform_device_shutdown(struct device *dev)
+{
+ struct of_device *of_dev = to_of_device(dev);
+ struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+
+ if (dev->driver && drv->shutdown)
+ drv->shutdown(of_dev);
+}
+
int of_bus_type_init(struct bus_type *bus, const char *name)
{
bus->name = name;
@@ -93,6 +102,7 @@ int of_bus_type_init(struct bus_type *bus, const char *name)
bus->remove = of_platform_device_remove;
bus->suspend = of_platform_device_suspend;
bus->resume = of_platform_device_resume;
+ bus->shutdown = of_platform_device_shutdown;
return bus_register(bus);
}
--
1.5.2.rc1.1884.g59b20
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/4] Convert axon_msi to an of_platform driver
2008-01-25 5:59 [PATCH 1/4] Search for and publish cell OF platform devices earlier Michael Ellerman
2008-01-25 5:59 ` [PATCH 2/4] Create and hook up of_platform_device_shutdown Michael Ellerman
@ 2008-01-25 5:59 ` Michael Ellerman
2008-02-05 0:20 ` Benjamin Herrenschmidt
2008-01-25 5:59 ` [PATCH 4/4] Avoid DMA exception when using axon_msi with IOMMU Michael Ellerman
2008-02-05 0:19 ` [PATCH 1/4] Search for and publish cell OF platform devices earlier Benjamin Herrenschmidt
3 siblings, 1 reply; 9+ messages in thread
From: Michael Ellerman @ 2008-01-25 5:59 UTC (permalink / raw)
To: linuxppc-dev; +Cc: cbe-oss-dev
Now that we create of_platform devices earlier on cell, we can make the
axon_msi driver an of_platform driver. This makes the code cleaner in
several ways, and most importantly means we have a struct device.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/platforms/cell/axon_msi.c | 76 ++++++++++++++-----------------
1 files changed, 34 insertions(+), 42 deletions(-)
diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
index 095988f..ea3dc8c 100644
--- a/arch/powerpc/platforms/cell/axon_msi.c
+++ b/arch/powerpc/platforms/cell/axon_msi.c
@@ -13,7 +13,7 @@
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/msi.h>
-#include <linux/reboot.h>
+#include <linux/of_platform.h>
#include <asm/dcr.h>
#include <asm/machdep.h>
@@ -67,12 +67,9 @@ struct axon_msic {
struct irq_host *irq_host;
__le32 *fifo;
dcr_host_t dcr_host;
- struct list_head list;
u32 read_offset;
};
-static LIST_HEAD(axon_msic_list);
-
static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
{
pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n);
@@ -292,30 +289,25 @@ static struct irq_host_ops msic_host_ops = {
.map = msic_host_map,
};
-static int axon_msi_notify_reboot(struct notifier_block *nb,
- unsigned long code, void *data)
+static int axon_msi_shutdown(struct of_device *device)
{
- struct axon_msic *msic;
+ struct axon_msic *msic = device->dev.platform_data;
u32 tmp;
- list_for_each_entry(msic, &axon_msic_list, list) {
- pr_debug("axon_msi: disabling %s\n",
- msic->irq_host->of_node->full_name);
- tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
- tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
- msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
- }
+ pr_debug("axon_msi: disabling %s\n",
+ msic->irq_host->of_node->full_name);
+ tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
+ tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
+ msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
return 0;
}
-static struct notifier_block axon_msi_reboot_notifier = {
- .notifier_call = axon_msi_notify_reboot
-};
-
-static int axon_msi_setup_one(struct device_node *dn)
+static int axon_msi_probe(struct of_device *device,
+ const struct of_device_id *device_id)
{
struct page *page;
+ struct device_node *dn = device->node;
struct axon_msic *msic;
unsigned int virq;
int dcr_base, dcr_len;
@@ -385,7 +377,11 @@ static int axon_msi_setup_one(struct device_node *dn)
MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
MSIC_CTRL_FIFO_SIZE);
- list_add(&msic->list, &axon_msic_list);
+ device->dev.platform_data = msic;
+
+ ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
+ ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
+ ppc_md.msi_check_device = axon_msi_check_device;
printk(KERN_DEBUG "axon_msi: setup MSIC on %s\n", dn->full_name);
@@ -402,28 +398,24 @@ out:
return -1;
}
-static int axon_msi_init(void)
-{
- struct device_node *dn;
- int found = 0;
-
- pr_debug("axon_msi: initialising ...\n");
-
- for_each_compatible_node(dn, NULL, "ibm,axon-msic") {
- if (axon_msi_setup_one(dn) == 0)
- found++;
- }
-
- if (found) {
- ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
- ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
- ppc_md.msi_check_device = axon_msi_check_device;
-
- register_reboot_notifier(&axon_msi_reboot_notifier);
+static const struct of_device_id axon_msi_device_id[] = {
+ {
+ .compatible = "ibm,axon-msic"
+ },
+ {}
+};
- pr_debug("axon_msi: registered callbacks!\n");
- }
+static struct of_platform_driver axon_msi_driver = {
+ .match_table = axon_msi_device_id,
+ .probe = axon_msi_probe,
+ .shutdown = axon_msi_shutdown,
+ .driver = {
+ .name = "axon-msi"
+ },
+};
- return 0;
+static int __init axon_msi_init(void)
+{
+ return of_register_platform_driver(&axon_msi_driver);
}
-arch_initcall(axon_msi_init);
+subsys_initcall(axon_msi_init);
--
1.5.2.rc1.1884.g59b20
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 4/4] Avoid DMA exception when using axon_msi with IOMMU
2008-01-25 5:59 [PATCH 1/4] Search for and publish cell OF platform devices earlier Michael Ellerman
2008-01-25 5:59 ` [PATCH 2/4] Create and hook up of_platform_device_shutdown Michael Ellerman
2008-01-25 5:59 ` [PATCH 3/4] Convert axon_msi to an of_platform driver Michael Ellerman
@ 2008-01-25 5:59 ` Michael Ellerman
2008-02-05 0:21 ` Benjamin Herrenschmidt
2008-02-05 0:19 ` [PATCH 1/4] Search for and publish cell OF platform devices earlier Benjamin Herrenschmidt
3 siblings, 1 reply; 9+ messages in thread
From: Michael Ellerman @ 2008-01-25 5:59 UTC (permalink / raw)
To: linuxppc-dev; +Cc: cbe-oss-dev
There's a brown-paper-bag bug in axon_msi, we pass the address of our
FIFO directly to the hardware, without DMA mapping it. This leads to
DMA exceptions if you enable MSI & the IOMMU.
The fix is to correctly DMA map the fifo, dma_alloc_coherent() does
what we want - and we need to track the virt & phys addresses.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/platforms/cell/axon_msi.c | 21 ++++++++++-----------
1 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
index ea3dc8c..b9a97c4 100644
--- a/arch/powerpc/platforms/cell/axon_msi.c
+++ b/arch/powerpc/platforms/cell/axon_msi.c
@@ -65,7 +65,8 @@
struct axon_msic {
struct irq_host *irq_host;
- __le32 *fifo;
+ __le32 *fifo_virt;
+ dma_addr_t fifo_phys;
dcr_host_t dcr_host;
u32 read_offset;
};
@@ -91,7 +92,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
while (msic->read_offset != write_offset) {
idx = msic->read_offset / sizeof(__le32);
- msi = le32_to_cpu(msic->fifo[idx]);
+ msi = le32_to_cpu(msic->fifo_virt[idx]);
msi &= 0xFFFF;
pr_debug("axon_msi: woff %x roff %x msi %x\n",
@@ -306,7 +307,6 @@ static int axon_msi_shutdown(struct of_device *device)
static int axon_msi_probe(struct of_device *device,
const struct of_device_id *device_id)
{
- struct page *page;
struct device_node *dn = device->node;
struct axon_msic *msic;
unsigned int virq;
@@ -338,16 +338,14 @@ static int axon_msi_probe(struct of_device *device,
goto out_free_msic;
}
- page = alloc_pages_node(of_node_to_nid(dn), GFP_KERNEL,
- get_order(MSIC_FIFO_SIZE_BYTES));
- if (!page) {
+ msic->fifo_virt = dma_alloc_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES,
+ &msic->fifo_phys, GFP_KERNEL);
+ if (!msic->fifo_virt) {
printk(KERN_ERR "axon_msi: couldn't allocate fifo for %s\n",
dn->full_name);
goto out_free_msic;
}
- msic->fifo = page_address(page);
-
msic->irq_host = irq_alloc_host(of_node_get(dn), IRQ_HOST_MAP_NOMAP,
NR_IRQS, &msic_host_ops, 0);
if (!msic->irq_host) {
@@ -370,9 +368,9 @@ static int axon_msi_probe(struct of_device *device,
pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq);
/* Enable the MSIC hardware */
- msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, (u64)msic->fifo >> 32);
+ msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, msic->fifo_phys >> 32);
msic_dcr_write(msic, MSIC_BASE_ADDR_LO_REG,
- (u64)msic->fifo & 0xFFFFFFFF);
+ msic->fifo_phys & 0xFFFFFFFF);
msic_dcr_write(msic, MSIC_CTRL_REG,
MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
MSIC_CTRL_FIFO_SIZE);
@@ -390,7 +388,8 @@ static int axon_msi_probe(struct of_device *device,
out_free_host:
kfree(msic->irq_host);
out_free_fifo:
- __free_pages(virt_to_page(msic->fifo), get_order(MSIC_FIFO_SIZE_BYTES));
+ dma_free_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES, msic->fifo_virt,
+ msic->fifo_phys);
out_free_msic:
kfree(msic);
out:
--
1.5.2.rc1.1884.g59b20
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 1/4] Search for and publish cell OF platform devices earlier
2008-01-25 5:59 [PATCH 1/4] Search for and publish cell OF platform devices earlier Michael Ellerman
` (2 preceding siblings ...)
2008-01-25 5:59 ` [PATCH 4/4] Avoid DMA exception when using axon_msi with IOMMU Michael Ellerman
@ 2008-02-05 0:19 ` Benjamin Herrenschmidt
3 siblings, 0 replies; 9+ messages in thread
From: Benjamin Herrenschmidt @ 2008-02-05 0:19 UTC (permalink / raw)
To: Michael Ellerman; +Cc: linuxppc-dev, cbe-oss-dev
On Fri, 2008-01-25 at 16:59 +1100, Michael Ellerman wrote:
> Currently cell publishes OF devices at device_initcall() time, which
> means the earliest a driver can bind to a device is also device_initcall()
> time. We have a driver we want to register before other devices, so
> publish the devices at subsys_initcall() time.
>
> This should not cause any behaviour change for existing drivers, as they
> are still bound at device_initcall() time.
>
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
> arch/powerpc/platforms/cell/setup.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
> index e6534b5..a7f609b 100644
> --- a/arch/powerpc/platforms/cell/setup.c
> +++ b/arch/powerpc/platforms/cell/setup.c
> @@ -98,7 +98,7 @@ static int __init cell_publish_devices(void)
> }
> return 0;
> }
> -machine_device_initcall(cell, cell_publish_devices);
> +machine_subsys_initcall(cell, cell_publish_devices);
>
> static void cell_mpic_cascade(unsigned int irq, struct irq_desc *desc)
> {
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 2/4] Create and hook up of_platform_device_shutdown
2008-01-25 5:59 ` [PATCH 2/4] Create and hook up of_platform_device_shutdown Michael Ellerman
@ 2008-02-05 0:19 ` Benjamin Herrenschmidt
0 siblings, 0 replies; 9+ messages in thread
From: Benjamin Herrenschmidt @ 2008-02-05 0:19 UTC (permalink / raw)
To: Michael Ellerman; +Cc: tnt, davem, linuxppc-dev, sparclinux, cbe-oss-dev, m8
On Fri, 2008-01-25 at 16:59 +1100, Michael Ellerman wrote:
> Although of_platform_device's can have a shutdown routine, at the moment
> the bus code doesn't actually call it. So add the required glue to
> hook the shutdown routine.
>
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
> drivers/of/platform.c | 10 ++++++++++
> 1 files changed, 10 insertions(+), 0 deletions(-)
>
>
> CC various folks who've written/touched of_platform_drivers which already
> have shutdown routines. These routines have never been called so they're
> about to get their first testing.
>
> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
> index b47bb2d..ca09a63 100644
> --- a/drivers/of/platform.c
> +++ b/drivers/of/platform.c
> @@ -85,6 +85,15 @@ static int of_platform_device_resume(struct device * dev)
> return error;
> }
>
> +static void of_platform_device_shutdown(struct device *dev)
> +{
> + struct of_device *of_dev = to_of_device(dev);
> + struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
> +
> + if (dev->driver && drv->shutdown)
> + drv->shutdown(of_dev);
> +}
> +
> int of_bus_type_init(struct bus_type *bus, const char *name)
> {
> bus->name = name;
> @@ -93,6 +102,7 @@ int of_bus_type_init(struct bus_type *bus, const char *name)
> bus->remove = of_platform_device_remove;
> bus->suspend = of_platform_device_suspend;
> bus->resume = of_platform_device_resume;
> + bus->shutdown = of_platform_device_shutdown;
> return bus_register(bus);
> }
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/4] Convert axon_msi to an of_platform driver
2008-01-25 5:59 ` [PATCH 3/4] Convert axon_msi to an of_platform driver Michael Ellerman
@ 2008-02-05 0:20 ` Benjamin Herrenschmidt
0 siblings, 0 replies; 9+ messages in thread
From: Benjamin Herrenschmidt @ 2008-02-05 0:20 UTC (permalink / raw)
To: Michael Ellerman; +Cc: linuxppc-dev, cbe-oss-dev
On Fri, 2008-01-25 at 16:59 +1100, Michael Ellerman wrote:
> Now that we create of_platform devices earlier on cell, we can make the
> axon_msi driver an of_platform driver. This makes the code cleaner in
> several ways, and most importantly means we have a struct device.
>
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
> arch/powerpc/platforms/cell/axon_msi.c | 76 ++++++++++++++-----------------
> 1 files changed, 34 insertions(+), 42 deletions(-)
>
> diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
> index 095988f..ea3dc8c 100644
> --- a/arch/powerpc/platforms/cell/axon_msi.c
> +++ b/arch/powerpc/platforms/cell/axon_msi.c
> @@ -13,7 +13,7 @@
> #include <linux/kernel.h>
> #include <linux/pci.h>
> #include <linux/msi.h>
> -#include <linux/reboot.h>
> +#include <linux/of_platform.h>
>
> #include <asm/dcr.h>
> #include <asm/machdep.h>
> @@ -67,12 +67,9 @@ struct axon_msic {
> struct irq_host *irq_host;
> __le32 *fifo;
> dcr_host_t dcr_host;
> - struct list_head list;
> u32 read_offset;
> };
>
> -static LIST_HEAD(axon_msic_list);
> -
> static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
> {
> pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n);
> @@ -292,30 +289,25 @@ static struct irq_host_ops msic_host_ops = {
> .map = msic_host_map,
> };
>
> -static int axon_msi_notify_reboot(struct notifier_block *nb,
> - unsigned long code, void *data)
> +static int axon_msi_shutdown(struct of_device *device)
> {
> - struct axon_msic *msic;
> + struct axon_msic *msic = device->dev.platform_data;
> u32 tmp;
>
> - list_for_each_entry(msic, &axon_msic_list, list) {
> - pr_debug("axon_msi: disabling %s\n",
> - msic->irq_host->of_node->full_name);
> - tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
> - tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
> - msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
> - }
> + pr_debug("axon_msi: disabling %s\n",
> + msic->irq_host->of_node->full_name);
> + tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
> + tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
> + msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
>
> return 0;
> }
>
> -static struct notifier_block axon_msi_reboot_notifier = {
> - .notifier_call = axon_msi_notify_reboot
> -};
> -
> -static int axon_msi_setup_one(struct device_node *dn)
> +static int axon_msi_probe(struct of_device *device,
> + const struct of_device_id *device_id)
> {
> struct page *page;
> + struct device_node *dn = device->node;
> struct axon_msic *msic;
> unsigned int virq;
> int dcr_base, dcr_len;
> @@ -385,7 +377,11 @@ static int axon_msi_setup_one(struct device_node *dn)
> MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
> MSIC_CTRL_FIFO_SIZE);
>
> - list_add(&msic->list, &axon_msic_list);
> + device->dev.platform_data = msic;
> +
> + ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
> + ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
> + ppc_md.msi_check_device = axon_msi_check_device;
>
> printk(KERN_DEBUG "axon_msi: setup MSIC on %s\n", dn->full_name);
>
> @@ -402,28 +398,24 @@ out:
> return -1;
> }
>
> -static int axon_msi_init(void)
> -{
> - struct device_node *dn;
> - int found = 0;
> -
> - pr_debug("axon_msi: initialising ...\n");
> -
> - for_each_compatible_node(dn, NULL, "ibm,axon-msic") {
> - if (axon_msi_setup_one(dn) == 0)
> - found++;
> - }
> -
> - if (found) {
> - ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
> - ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
> - ppc_md.msi_check_device = axon_msi_check_device;
> -
> - register_reboot_notifier(&axon_msi_reboot_notifier);
> +static const struct of_device_id axon_msi_device_id[] = {
> + {
> + .compatible = "ibm,axon-msic"
> + },
> + {}
> +};
>
> - pr_debug("axon_msi: registered callbacks!\n");
> - }
> +static struct of_platform_driver axon_msi_driver = {
> + .match_table = axon_msi_device_id,
> + .probe = axon_msi_probe,
> + .shutdown = axon_msi_shutdown,
> + .driver = {
> + .name = "axon-msi"
> + },
> +};
>
> - return 0;
> +static int __init axon_msi_init(void)
> +{
> + return of_register_platform_driver(&axon_msi_driver);
> }
> -arch_initcall(axon_msi_init);
> +subsys_initcall(axon_msi_init);
> --
> 1.5.2.rc1.1884.g59b20
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 4/4] Avoid DMA exception when using axon_msi with IOMMU
2008-01-25 5:59 ` [PATCH 4/4] Avoid DMA exception when using axon_msi with IOMMU Michael Ellerman
@ 2008-02-05 0:21 ` Benjamin Herrenschmidt
0 siblings, 0 replies; 9+ messages in thread
From: Benjamin Herrenschmidt @ 2008-02-05 0:21 UTC (permalink / raw)
To: Michael Ellerman; +Cc: linuxppc-dev, cbe-oss-dev
On Fri, 2008-01-25 at 16:59 +1100, Michael Ellerman wrote:
> There's a brown-paper-bag bug in axon_msi, we pass the address of our
> FIFO directly to the hardware, without DMA mapping it. This leads to
> DMA exceptions if you enable MSI & the IOMMU.
>
> The fix is to correctly DMA map the fifo, dma_alloc_coherent() does
> what we want - and we need to track the virt & phys addresses.
>
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
> arch/powerpc/platforms/cell/axon_msi.c | 21 ++++++++++-----------
> 1 files changed, 10 insertions(+), 11 deletions(-)
>
> diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
> index ea3dc8c..b9a97c4 100644
> --- a/arch/powerpc/platforms/cell/axon_msi.c
> +++ b/arch/powerpc/platforms/cell/axon_msi.c
> @@ -65,7 +65,8 @@
>
> struct axon_msic {
> struct irq_host *irq_host;
> - __le32 *fifo;
> + __le32 *fifo_virt;
> + dma_addr_t fifo_phys;
> dcr_host_t dcr_host;
> u32 read_offset;
> };
> @@ -91,7 +92,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
>
> while (msic->read_offset != write_offset) {
> idx = msic->read_offset / sizeof(__le32);
> - msi = le32_to_cpu(msic->fifo[idx]);
> + msi = le32_to_cpu(msic->fifo_virt[idx]);
> msi &= 0xFFFF;
>
> pr_debug("axon_msi: woff %x roff %x msi %x\n",
> @@ -306,7 +307,6 @@ static int axon_msi_shutdown(struct of_device *device)
> static int axon_msi_probe(struct of_device *device,
> const struct of_device_id *device_id)
> {
> - struct page *page;
> struct device_node *dn = device->node;
> struct axon_msic *msic;
> unsigned int virq;
> @@ -338,16 +338,14 @@ static int axon_msi_probe(struct of_device *device,
> goto out_free_msic;
> }
>
> - page = alloc_pages_node(of_node_to_nid(dn), GFP_KERNEL,
> - get_order(MSIC_FIFO_SIZE_BYTES));
> - if (!page) {
> + msic->fifo_virt = dma_alloc_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES,
> + &msic->fifo_phys, GFP_KERNEL);
> + if (!msic->fifo_virt) {
> printk(KERN_ERR "axon_msi: couldn't allocate fifo for %s\n",
> dn->full_name);
> goto out_free_msic;
> }
>
> - msic->fifo = page_address(page);
> -
> msic->irq_host = irq_alloc_host(of_node_get(dn), IRQ_HOST_MAP_NOMAP,
> NR_IRQS, &msic_host_ops, 0);
> if (!msic->irq_host) {
> @@ -370,9 +368,9 @@ static int axon_msi_probe(struct of_device *device,
> pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq);
>
> /* Enable the MSIC hardware */
> - msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, (u64)msic->fifo >> 32);
> + msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, msic->fifo_phys >> 32);
> msic_dcr_write(msic, MSIC_BASE_ADDR_LO_REG,
> - (u64)msic->fifo & 0xFFFFFFFF);
> + msic->fifo_phys & 0xFFFFFFFF);
> msic_dcr_write(msic, MSIC_CTRL_REG,
> MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
> MSIC_CTRL_FIFO_SIZE);
> @@ -390,7 +388,8 @@ static int axon_msi_probe(struct of_device *device,
> out_free_host:
> kfree(msic->irq_host);
> out_free_fifo:
> - __free_pages(virt_to_page(msic->fifo), get_order(MSIC_FIFO_SIZE_BYTES));
> + dma_free_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES, msic->fifo_virt,
> + msic->fifo_phys);
> out_free_msic:
> kfree(msic);
> out:
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2008-02-05 0:21 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-25 5:59 [PATCH 1/4] Search for and publish cell OF platform devices earlier Michael Ellerman
2008-01-25 5:59 ` [PATCH 2/4] Create and hook up of_platform_device_shutdown Michael Ellerman
2008-02-05 0:19 ` Benjamin Herrenschmidt
2008-01-25 5:59 ` [PATCH 3/4] Convert axon_msi to an of_platform driver Michael Ellerman
2008-02-05 0:20 ` Benjamin Herrenschmidt
2008-01-25 5:59 ` [PATCH 4/4] Avoid DMA exception when using axon_msi with IOMMU Michael Ellerman
2008-02-05 0:21 ` Benjamin Herrenschmidt
2008-02-05 0:19 ` [PATCH 1/4] Search for and publish cell OF platform devices earlier Benjamin Herrenschmidt
-- strict thread matches above, loose matches on Subject: below --
2008-01-22 11:04 Michael Ellerman
2008-01-22 11:04 ` [PATCH 4/4] Avoid DMA exception when using axon_msi with IOMMU Michael Ellerman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).