Commit 8277a1fa authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] ppc64: change the iSeries virtual device drivers to use the vio...

[PATCH] ppc64: change the iSeries virtual device drivers to use the vio infrastructure for DMA mapping

From: Stephen Rothwell <sfr@canb.auug.org.au>

This patch changes the iSeries virtual device drivers to use the
vio infrastructure for DMA mapping instead of the PCI infrastructure.
This is a step along the way to integrating them correctly into the
driver model.
parent e1df56ff
......@@ -11,7 +11,7 @@ obj-y := setup.o entry.o traps.o irq.o idle.o dma.o \
udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \
ptrace32.o signal32.o rtc.o init_task.o \
lmb.o cputable.o cpu_setup_power4.o idle_power4.o \
iommu.o sysfs.o
iommu.o sysfs.o vio.o
obj-$(CONFIG_PPC_OF) += of_device.o
......@@ -34,7 +34,7 @@ obj-$(CONFIG_PPC_ISERIES) += iSeries_irq.o \
obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \
eeh.o nvram.o pSeries_nvram.o rtasd.o ras.o \
open_pic.o xics.o pSeries_htab.o rtas.o \
chrp_setup.o i8259.o prom.o vio.o pSeries_iommu.o
chrp_setup.o i8259.o prom.o pSeries_iommu.o
obj-$(CONFIG_PROC_FS) += proc_ppc64.o
obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o
......
......@@ -5,14 +5,11 @@
* the pci and vio busses
*/
#include <linux/config.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
/* Include the busses we support */
#include <linux/pci.h>
#ifdef CONFIG_PPC_PSERIES
#include <asm/vio.h>
#endif
#include <asm/scatterlist.h>
#include <asm/bug.h>
......@@ -20,10 +17,8 @@ int dma_supported(struct device *dev, u64 mask)
{
if (dev->bus == &pci_bus_type)
return pci_dma_supported(to_pci_dev(dev), mask);
#ifdef CONFIG_PPC_PSERIES
if (dev->bus == &vio_bus_type)
return vio_dma_supported(to_vio_dev(dev), mask);
#endif
BUG();
return 0;
}
......@@ -33,10 +28,8 @@ int dma_set_mask(struct device *dev, u64 dma_mask)
{
if (dev->bus == &pci_bus_type)
return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
#ifdef CONFIG_PPC_PSERIES
if (dev->bus == &vio_bus_type)
return vio_set_dma_mask(to_vio_dev(dev), dma_mask);
#endif
BUG();
return 0;
}
......@@ -47,10 +40,8 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
{
if (dev->bus == &pci_bus_type)
return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle);
#ifdef CONFIG_PPC_PSERIES
if (dev->bus == &vio_bus_type)
return vio_alloc_consistent(to_vio_dev(dev), size, dma_handle);
#endif
BUG();
return 0;
}
......@@ -61,10 +52,8 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
{
if (dev->bus == &pci_bus_type)
pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle);
#ifdef CONFIG_PPC_PSERIES
else if (dev->bus == &vio_bus_type)
vio_free_consistent(to_vio_dev(dev), size, cpu_addr, dma_handle);
#endif
else
BUG();
}
......@@ -75,10 +64,8 @@ dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size,
{
if (dev->bus == &pci_bus_type)
return pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction);
#ifdef CONFIG_PPC_PSERIES
if (dev->bus == &vio_bus_type)
return vio_map_single(to_vio_dev(dev), cpu_addr, size, direction);
#endif
BUG();
return (dma_addr_t)0;
}
......@@ -89,10 +76,8 @@ void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
{
if (dev->bus == &pci_bus_type)
pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction);
#ifdef CONFIG_PPC_PSERIES
else if (dev->bus == &vio_bus_type)
vio_unmap_single(to_vio_dev(dev), dma_addr, size, direction);
#endif
else
BUG();
}
......@@ -104,10 +89,8 @@ dma_addr_t dma_map_page(struct device *dev, struct page *page,
{
if (dev->bus == &pci_bus_type)
return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction);
#ifdef CONFIG_PPC_PSERIES
if (dev->bus == &vio_bus_type)
return vio_map_page(to_vio_dev(dev), page, offset, size, direction);
#endif
BUG();
return (dma_addr_t)0;
}
......@@ -118,10 +101,8 @@ void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
{
if (dev->bus == &pci_bus_type)
pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction);
#ifdef CONFIG_PPC_PSERIES
else if (dev->bus == &vio_bus_type)
vio_unmap_page(to_vio_dev(dev), dma_address, size, direction);
#endif
else
BUG();
}
......@@ -132,10 +113,8 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
{
if (dev->bus == &pci_bus_type)
return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction);
#ifdef CONFIG_PPC_PSERIES
if (dev->bus == &vio_bus_type)
return vio_map_sg(to_vio_dev(dev), sg, nents, direction);
#endif
BUG();
return 0;
}
......@@ -146,10 +125,8 @@ void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
{
if (dev->bus == &pci_bus_type)
pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction);
#ifdef CONFIG_PPC_PSERIES
else if (dev->bus == &vio_bus_type)
vio_unmap_sg(to_vio_dev(dev), sg, nhwentries, direction);
#endif
else
BUG();
}
......@@ -160,10 +137,8 @@ void dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size,
{
if (dev->bus == &pci_bus_type)
pci_dma_sync_single(to_pci_dev(dev), dma_handle, size, (int)direction);
#ifdef CONFIG_PPC_PSERIES
else if (dev->bus == &vio_bus_type)
vio_dma_sync_single(to_vio_dev(dev), dma_handle, size, direction);
#endif
else
BUG();
}
......@@ -174,10 +149,8 @@ void dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems,
{
if (dev->bus == &pci_bus_type)
pci_dma_sync_sg(to_pci_dev(dev), sg, nelems, (int)direction);
#ifdef CONFIG_PPC_PSERIES
else if (dev->bus == &vio_bus_type)
vio_dma_sync_sg(to_vio_dev(dev), sg, nelems, direction);
#endif
else
BUG();
}
......
......@@ -2,24 +2,24 @@
* arch/ppc64/kernel/iSeries_iommu.c
*
* Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
*
* Rewrite, cleanup:
*
* Rewrite, cleanup:
*
* Copyright (C) 2004 Olof Johansson <olof@austin.ibm.com>, IBM Corporation
*
* Dynamic DMA mapping support, iSeries-specific parts.
*
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
......@@ -44,28 +44,12 @@
#include <asm/iommu.h>
#include <asm/pci-bridge.h>
#include <asm/iSeries/iSeries_pci.h>
#include <asm/iSeries/vio.h>
#include <asm/machdep.h>
#include "pci.h"
static struct iommu_table veth_iommu_table; /* Tce table for virtual ethernet */
static struct iommu_table vio_iommu_table; /* Tce table for virtual I/O */
static struct iSeries_Device_Node veth_dev_node = { .LogicalSlot = 0xFF, .iommu_table = &veth_iommu_table };
static struct iSeries_Device_Node vio_dev_node = { .LogicalSlot = 0xFF, .iommu_table = &vio_iommu_table };
static struct pci_dev _veth_dev = { .sysdata = &veth_dev_node };
static struct pci_dev _vio_dev = { .sysdata = &vio_dev_node, .dev.bus = &pci_bus_type };
struct pci_dev *iSeries_veth_dev = &_veth_dev;
struct device *iSeries_vio_dev = &_vio_dev.dev;
EXPORT_SYMBOL(iSeries_veth_dev);
EXPORT_SYMBOL(iSeries_vio_dev);
extern struct list_head iSeries_Global_Device_List;
......@@ -74,7 +58,7 @@ static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages,
{
u64 rc;
union tce_entry tce;
while (npages--) {
tce.te_word = 0;
tce.te_bits.tb_rpn = virt_to_abs(uaddr) >> PAGE_SHIFT;
......@@ -91,9 +75,9 @@ static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages,
if (direction != DMA_TO_DEVICE)
tce.te_bits.tb_pciwr = 1;
}
rc = HvCallXm_setTce((u64)tbl->it_index,
(u64)index,
rc = HvCallXm_setTce((u64)tbl->it_index,
(u64)index,
tce.te_word);
if (rc)
panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", rc);
......@@ -114,7 +98,7 @@ static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages)
(u64)index,
tce.te_word);
if (rc)
if (rc)
panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", rc);
index++;
......@@ -122,50 +106,10 @@ static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages)
}
void __init iommu_vio_init(void)
{
struct iommu_table *t;
struct iommu_table_cb cb;
unsigned long cbp;
cb.itc_busno = 255; /* Bus 255 is the virtual bus */
cb.itc_virtbus = 0xff; /* Ask for virtual bus */
cbp = virt_to_abs(&cb);
HvCallXm_getTceTableParms(cbp);
veth_iommu_table.it_size = cb.itc_size / 2;
veth_iommu_table.it_busno = cb.itc_busno;
veth_iommu_table.it_offset = cb.itc_offset;
veth_iommu_table.it_index = cb.itc_index;
veth_iommu_table.it_type = TCE_VB;
veth_iommu_table.it_entrysize = sizeof(union tce_entry);
veth_iommu_table.it_blocksize = 1;
t = iommu_init_table(&veth_iommu_table);
if (!t)
printk("Virtual Bus VETH TCE table failed.\n");
vio_iommu_table.it_size = cb.itc_size - veth_iommu_table.it_size;
vio_iommu_table.it_busno = cb.itc_busno;
vio_iommu_table.it_offset = cb.itc_offset +
veth_iommu_table.it_size * (PAGE_SIZE/sizeof(union tce_entry));
vio_iommu_table.it_index = cb.itc_index;
vio_iommu_table.it_type = TCE_VB;
vio_iommu_table.it_entrysize = sizeof(union tce_entry);
vio_iommu_table.it_blocksize = 1;
t = iommu_init_table(&vio_iommu_table);
if (!t)
printk("Virtual Bus VIO TCE table failed.\n");
}
/*
* This function compares the known tables to find an iommu_table
* that has already been built for hardware TCEs.
* that has already been built for hardware TCEs.
*/
static struct iommu_table *iommu_table_find(struct iommu_table * tbl)
{
......@@ -173,26 +117,26 @@ static struct iommu_table *iommu_table_find(struct iommu_table * tbl)
for (dp = (struct iSeries_Device_Node *)iSeries_Global_Device_List.next;
dp != (struct iSeries_Device_Node *)&iSeries_Global_Device_List;
dp = (struct iSeries_Device_Node *)dp->Device_List.next)
dp = (struct iSeries_Device_Node *)dp->Device_List.next)
if (dp->iommu_table != NULL &&
dp->iommu_table->it_type == TCE_PCI &&
dp->iommu_table->it_offset == tbl->it_offset &&
dp->iommu_table->it_index == tbl->it_index &&
dp->iommu_table->it_size == tbl->it_size)
dp->iommu_table->it_size == tbl->it_size)
return dp->iommu_table;
return NULL;
}
/*
* Call Hv with the architected data structure to get TCE table info.
* info. Put the returned data into the Linux representation of the
* TCE table data.
* The Hardware Tce table comes in three flavors.
* 1. TCE table shared between Buses.
* 2. TCE table per Bus.
* 3. TCE Table per IOA.
* info. Put the returned data into the Linux representation of the
* TCE table data.
* The Hardware Tce table comes in three flavors.
* 1. TCE table shared between Buses.
* 2. TCE table per Bus.
* 3. TCE Table per IOA.
*/
static void iommu_table_getparms(struct iSeries_Device_Node* dn,
struct iommu_table* tbl)
......@@ -201,7 +145,7 @@ static void iommu_table_getparms(struct iSeries_Device_Node* dn,
parms = (struct iommu_table_cb*)kmalloc(sizeof(*parms), GFP_KERNEL);
if (parms == NULL)
if (parms == NULL)
panic("PCI_DMA: TCE Table Allocation failed.");
memset(parms, 0, sizeof(*parms));
......
......@@ -25,6 +25,8 @@
#include <asm/ppcdebug.h>
#include <asm/vio.h>
#include <asm/hvcall.h>
#include <asm/iSeries/vio.h>
#include <asm/iSeries/HvCallXm.h>
#define DBGENTER() pr_debug("%s entered\n", __FUNCTION__)
......@@ -32,9 +34,31 @@ extern struct subsystem devices_subsys; /* needed for vio_find_name() */
struct iommu_table *vio_build_iommu_table(struct vio_dev *dev);
#ifdef CONFIG_PPC_PSERIES
static int vio_num_address_cells;
#endif
static struct vio_dev *vio_bus_device; /* fake "parent" device */
#ifdef CONFIG_PPC_ISERIES
static struct iommu_table veth_iommu_table;
static struct iommu_table vio_iommu_table;
static struct vio_dev _veth_dev = {
.iommu_table = &veth_iommu_table,
.dev.bus = &vio_bus_type
};
static struct vio_dev _vio_dev = {
.iommu_table = &vio_iommu_table,
.dev.bus = &vio_bus_type
};
struct vio_dev *iSeries_veth_dev = &_veth_dev;
struct device *iSeries_vio_dev = &_vio_dev.dev;
EXPORT_SYMBOL(iSeries_veth_dev);
EXPORT_SYMBOL(iSeries_vio_dev);
#endif
/* convert from struct device to struct vio_dev and pass to driver.
* dev->driver has already been set by generic code because vio_bus_match
* succeeded. */
......@@ -117,21 +141,67 @@ const struct vio_device_id * vio_match_device(const struct vio_device_id *ids,
{
DBGENTER();
#ifdef CONFIG_PPC_PSERIES
while (ids->type) {
if ((strncmp(dev->archdata->type, ids->type, strlen(ids->type)) == 0) &&
device_is_compatible((struct device_node*)dev->archdata, ids->compat))
return ids;
ids++;
}
#endif
return NULL;
}
#ifdef CONFIG_PPC_ISERIES
void __init iommu_vio_init(void)
{
struct iommu_table *t;
struct iommu_table_cb cb;
unsigned long cbp;
cb.itc_busno = 255; /* Bus 255 is the virtual bus */
cb.itc_virtbus = 0xff; /* Ask for virtual bus */
cbp = virt_to_abs(&cb);
HvCallXm_getTceTableParms(cbp);
veth_iommu_table.it_size = cb.itc_size / 2;
veth_iommu_table.it_busno = cb.itc_busno;
veth_iommu_table.it_offset = cb.itc_offset;
veth_iommu_table.it_index = cb.itc_index;
veth_iommu_table.it_type = TCE_VB;
veth_iommu_table.it_entrysize = sizeof(union tce_entry);
veth_iommu_table.it_blocksize = 1;
t = iommu_init_table(&veth_iommu_table);
if (!t)
printk("Virtual Bus VETH TCE table failed.\n");
vio_iommu_table.it_size = cb.itc_size - veth_iommu_table.it_size;
vio_iommu_table.it_busno = cb.itc_busno;
vio_iommu_table.it_offset = cb.itc_offset +
veth_iommu_table.it_size * (PAGE_SIZE/sizeof(union tce_entry));
vio_iommu_table.it_index = cb.itc_index;
vio_iommu_table.it_type = TCE_VB;
vio_iommu_table.it_entrysize = sizeof(union tce_entry);
vio_iommu_table.it_blocksize = 1;
t = iommu_init_table(&vio_iommu_table);
if (!t)
printk("Virtual Bus VIO TCE table failed.\n");
}
#endif
/**
* vio_bus_init: - Initialize the virtual IO bus
*/
static int __init vio_bus_init(void)
{
#ifdef CONFIG_PPC_PSERIES
struct device_node *node_vroot, *of_node;
#endif
int err;
err = bus_register(&vio_bus_type);
......@@ -156,6 +226,7 @@ static int __init vio_bus_init(void)
return err;
}
#ifdef CONFIG_PPC_PSERIES
node_vroot = find_devices("vdevice");
if ((node_vroot == NULL) || (node_vroot->child == NULL)) {
/* this machine doesn't do virtual IO, and that's ok */
......@@ -175,6 +246,7 @@ static int __init vio_bus_init(void)
vio_register_device(of_node);
}
#endif
return 0;
}
......@@ -182,6 +254,7 @@ static int __init vio_bus_init(void)
__initcall(vio_bus_init);
#ifdef CONFIG_PPC_PSERIES
/* vio_dev refcount hit 0 */
static void __devinit vio_dev_release(struct device *dev)
{
......@@ -412,6 +485,7 @@ int vio_disable_interrupts(struct vio_dev *dev)
return rc;
}
EXPORT_SYMBOL(vio_disable_interrupts);
#endif
dma_addr_t vio_map_single(struct vio_dev *dev, void *vaddr,
size_t size, enum dma_data_direction direction)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment