[parisc-linux-cvs] DIFF -pa67 (Multi-IOMMU for SBA)
Grant Grundler
grundler@puffin.external.hp.com
Tue, 23 Oct 2001 10:17:43 -0600
Sorry...forgot to post the diff for -pa67 *and* I forgot
to include the -pa## in the commit comments. *sigh*
grant
Index: Makefile
===================================================================
RCS file: /home/cvs/parisc/linux/Makefile,v
retrieving revision 1.178
diff -u -p -r1.178 Makefile
--- Makefile 2001/10/22 21:41:02 1.178
+++ Makefile 2001/10/23 05:59:33
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 9
-EXTRAVERSION = -pa66
+EXTRAVERSION = -pa67
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
Index: arch/parisc/kernel/lba_pci.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/lba_pci.c,v
retrieving revision 1.40
diff -u -p -r1.40 lba_pci.c
--- lba_pci.c 2001/10/17 14:14:12 1.40
+++ lba_pci.c 2001/10/23 05:59:34
@@ -1352,18 +1352,10 @@ lba_driver_callback(struct parisc_device
** Tell I/O SAPIC driver we have a IRQ handler/region.
*/
tmp_obj = iosapic_register(dev->hpa + LBA_IOSAPIC_BASE);
-#if 0 /* FIXME: some graphic cards (e.g. 103c:1005) don't have an IRT. */
- if (NULL == tmp_obj) {
- /* iosapic may have failed. But more likely the
- ** slot isn't occupied and thus has no IRT entries.
- ** iosapic_register looks for this iosapic in the IRT
- ** before bothering to allocating data structures
- ** we don't need.
- */
- DBG(KERN_WARNING MODULE_NAME ": iosapic_register found no IRT entries for this HBA\n");
- return (1);
- }
-#endif
+
+ /* NOTE: PCI devices (e.g. 103c:1005 graphics card) which don't
+ ** have an IRT entry will get NULL back from iosapic code.
+ */
lba_dev = kmalloc(sizeof(struct lba_device), GFP_KERNEL);
if (NULL == lba_dev)
@@ -1385,6 +1377,7 @@ lba_driver_callback(struct parisc_device
lba_dev->hba.base_addr = dev->hpa; /* faster access */
lba_dev->iosapic_obj = tmp_obj; /* save interrupt handle */
+ lba_dev->hba.iommu = sba_get_iommu(dev); /* get iommu data */
/* ------------ Second : initialize common stuff ---------- */
lba_common_init(lba_dev);
Index: arch/parisc/kernel/sba_iommu.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/sba_iommu.c,v
retrieving revision 1.52
diff -u -p -r1.52 sba_iommu.c
--- sba_iommu.c 2001/09/20 18:20:13 1.52
+++ sba_iommu.c 2001/10/23 05:59:34
@@ -15,7 +15,6 @@
** This module initializes the IOC (I/O Controller) found on B1000/C3000/
** J5000/J7000/N-class/L-class machines and their successors.
**
-** FIXME: Multi-IOC support missing - depends on hp_device data
** FIXME: add DMA hint support programming in both sba and lba modules.
*/
@@ -292,7 +291,15 @@ static unsigned long sba_mem_ratio = 4;
#ifdef DEBUG_SBA_INIT
-/* When __LP64__ isn't defined, READ_REG64() is two 32-bit reads */
+/* NOTE: When __LP64__ isn't defined, READ_REG64() is two 32-bit reads */
+
+/**
+ * sba_dump_ranges - debugging only - print ranges assigned to this IOA
+ * @hpa: base address of the sba
+ *
+ * Print the MMIO and IO Port address ranges forwarded by an Astro/Ike/RIO
+ * IO Adapter (aka Bus Converter).
+ */
static void
sba_dump_ranges(char *hpa)
{
@@ -306,6 +313,12 @@ sba_dump_ranges(char *hpa)
DBG_INIT("IOS_DIRECT_ROUTE: %016lx\n", READ_REG64(hpa+IOS_DIRECT_ROUTE));
}
+/**
+ * sba_dump_tlb - debugging only - print IOMMU operating parameters
+ * @hpa: base address of the IOMMU
+ *
+ * Print the size/location of the IO MMU PDIR.
+ */
static void
sba_dump_tlb(char *hpa)
{
@@ -321,6 +334,14 @@ sba_dump_tlb(char *hpa)
#ifdef ASSERT_PDIR_SANITY
+/**
+ * sba_dump_pdir_entry - debugging only - print one IOMMU PDIR entry
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @msg: text to print ont the output line.
+ * @pide: pdir index.
+ *
+ * Print one entry of the IO MMU PDIR in human readable form.
+ */
static void
sba_dump_pdir_entry(struct ioc *ioc, char *msg, uint pide)
{
@@ -346,7 +367,13 @@ sba_dump_pdir_entry(struct ioc *ioc, cha
}
-/* Verify the resource map and pdir state is consistent */
+/**
+ * sba_check_pdir - debugging only - consistency checker
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @msg: text to print ont the output line.
+ *
+ * Verify the resource map and pdir state is consistent
+ */
static int
sba_check_pdir(struct ioc *ioc, char *msg)
{
@@ -383,6 +410,14 @@ sba_check_pdir(struct ioc *ioc, char *ms
}
+/**
+ * sba_dump_sg - debugging only - print Scatter-Gather list
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg: head of the SG list
+ * @nents: number of entries in SG list
+ *
+ * print the SG list so we can verify it's correct by hand.
+ */
static void
sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents)
{
@@ -424,14 +459,16 @@ sba_dump_sg( struct ioc *ioc, struct sca
#define RESMAP_MASK(n) (~0UL << (BITS_PER_LONG - (n)))
#define RESMAP_IDX_MASK (sizeof(unsigned long) - 1)
-
-/*
-** Perf optimizations:
-** o search for log2(size) bits at a time.
-**
-** Search should use register width as "stride" to search the res_map.
-*/
+/**
+ * sba_search_bitmap - find free space in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @bits_wanted: number of entries we need.
+ *
+ * Find consecutive free bits in resource bitmap.
+ * Each bit represents one entry in the IO Pdir.
+ * Cool perf optimization: search for log2(size) bits at a time.
+ */
static SBA_INLINE unsigned long
sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted)
{
@@ -506,6 +543,14 @@ sba_search_bitmap(struct ioc *ioc, unsig
}
+/**
+ * sba_alloc_range - find free bits and mark them in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @size: number of bytes to create a mapping for
+ *
+ * Given a size, find consecutive unmarked and then mark those bits in the
+ * resource bit map.
+ */
static int
sba_alloc_range(struct ioc *ioc, size_t size)
{
@@ -561,9 +606,14 @@ sba_alloc_range(struct ioc *ioc, size_t
}
-/*
-** clear bits in the ioc's resource map
-*/
+/**
+ * sba_free_range - unmark bits in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @iova: IO virtual address which was previously allocated.
+ * @size: number of bytes to create a mapping for
+ *
+ * clear bits in the ioc's resource map
+ */
static SBA_INLINE void
sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size)
{
@@ -606,31 +656,36 @@ sba_free_range(struct ioc *ioc, dma_addr
typedef unsigned long space_t;
#define KERNEL_SPACE 0
-/*
-* SBA Mapping Routine
-*
-* Given a virtual address (vba, arg2) and space id, (sid, arg1)
-* sba_io_pdir_entry() loads the I/O PDIR entry pointed to by
-* pdir_ptr (arg0). Each IO Pdir entry consists of 8 bytes as
-* shown below (MSB == bit 0):
-*
-* 0 19 51 55 63
-* +-+---------------------+----------------------------------+----+--------+
-* |V| U | PPN[43:12] | U | VI |
-* +-+---------------------+----------------------------------+----+--------+
-*
-* V == Valid Bit
-* U == Unused
-* PPN == Physical Page Number
-* VI == Virtual Index (aka Coherent Index)
-*
-* The physical address fields are filled with the results of the LPA
-* instruction. The virtual index field is filled with the results of
-* of the LCI (Load Coherence Index) instruction. The 8 bits used for
-* the virtual index are bits 12:19 of the value returned by LCI.
-*
-* We need to pre-swap the bytes since PCX-W is Big Endian.
-*/
+/**
+ * sba_io_pdir_entry - fill in one IO PDIR entry
+ * @pdir_ptr: pointer to IO PDIR entry
+ * @sid: process Space ID
+ * @vba: Virtual CPU address of buffer to map
+ *
+ * SBA Mapping Routine
+ *
+ * Given a virtual address (vba, arg2) and space id, (sid, arg1)
+ * sba_io_pdir_entry() loads the I/O PDIR entry pointed to by
+ * pdir_ptr (arg0). Each IO Pdir entry consists of 8 bytes as
+ * shown below (MSB == bit 0):
+ *
+ * 0 19 51 55 63
+ * +-+---------------------+----------------------------------+----+--------+
+ * |V| U | PPN[43:12] | U | VI |
+ * +-+---------------------+----------------------------------+----+--------+
+ *
+ * V == Valid Bit
+ * U == Unused
+ * PPN == Physical Page Number
+ * VI == Virtual Index (aka Coherent Index)
+ *
+ * The physical address fields are filled with the results of the LPA
+ * instruction. The virtual index field is filled with the results of
+ * of the LCI (Load Coherence Index) instruction. The 8 bits used for
+ * the virtual index are bits 12:19 of the value returned by LCI.
+ *
+ * We need to pre-swap the bytes since PCX-W is Big Endian.
+ */
void SBA_INLINE
sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba)
@@ -653,15 +708,22 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t
}
-/***********************************************************
- * The Ike PCOM (Purge Command Register) is to purge
- * stale entries in the IO TLB when unmapping entries.
+/**
+ * sba_mark_invalid - invalidate one or more IO PDIR entries
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @iova: IO Virtual Address mapped earlier
+ * @byte_cnt: number of bytes this mapping covers.
*
+ * Marking the IO PDIR entry(ies) as Invalid and invalidate
+ * corresponding IO TLB entry. The Ike PCOM (Purge Command Register)
+ * is to purge stale entries in the IO TLB when unmapping entries.
+ *
* The PCOM register supports purging of multiple pages, with a minium
* of 1 page and a maximum of 2GB. Hardware requires the address be
* aligned to the size of the range being purged. The size of the range
- * must be a power of 2.
- ***********************************************************/
+ * must be a power of 2. The "Cool perf optimization" in the
+ * allocation routine helps keep that true.
+ */
static SBA_INLINE void
sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
{
@@ -716,6 +778,13 @@ sba_mark_invalid(struct ioc *ioc, dma_ad
WRITE_REG(iovp, ioc->ioc_hpa+IOC_PCOM);
}
+/**
+ * sba_dma_supported - PCI driver can query DMA support
+ * @dev: instance of PCI owned by the driver that's asking
+ * @mask: number of address bits this PCI device can handle
+ *
+ * See Documentation/DMA-mapping.txt
+ */
static int
sba_dma_supported( struct pci_dev *dev, dma_addr_t mask)
{
@@ -732,13 +801,19 @@ sba_dma_supported( struct pci_dev *dev,
}
-/*
-** map_single returns a fully formed IOVA
-*/
+/**
+ * sba_map_single - map one buffer and return IOVA for DMA
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @addr: driver buffer to map.
+ * @size: number of bytes to map in driver buffer.
+ * @direction: R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
static dma_addr_t
sba_map_single(struct pci_dev *dev, void *addr, size_t size, int direction)
{
- struct ioc *ioc = &sba_list->ioc[0]; /* FIXME : see Multi-IOC below */
+ struct ioc *ioc;
unsigned long flags;
dma_addr_t iovp;
dma_addr_t offset;
@@ -747,6 +822,10 @@ sba_map_single(struct pci_dev *dev, void
ASSERT(size > 0);
+ ASSERT(dev->sysdata);
+ ioc = GET_IOC(dev);
+ ASSERT(ioc);
+
/* save offset bits */
offset = ((dma_addr_t) (long) addr) & ~IOVP_MASK;
@@ -799,32 +878,33 @@ sba_map_single(struct pci_dev *dev, void
}
+/**
+ * sba_unmap_single - unmap one IOVA and free resources
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @iova: IOVA of driver buffer previously mapped.
+ * @size: number of bytes mapped in driver buffer.
+ * @direction: R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
static void
sba_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, int direction)
{
-#ifdef FIXME
-/* Multi-IOC (ie N-class) : need to lookup IOC from dev
-** o If we can't know about lba PCI data structs, that eliminates ->sysdata.
-** o walking up pcidev->parent dead ends at elroy too
-** o leaves hashing dev->bus->number into some lookup.
-** (may only work for N-class)
-** o use (struct pci_hba) and put fields in there for DMA.
-** (ioc and per device dma_hint.)
-**
-** Last one seems the clearest and most promising.
-** sba_dma_supported() fill in those fields when the driver queries
-** the system for support.
-*/
- struct ioc *ioc = (struct ioc *) ((struct pci_hba *) (dev->sysdata))->dma_data;
-#else
- struct ioc *ioc = &sba_list->ioc[0];
-#endif
+ struct ioc *ioc;
#ifdef DELAYED_RESOURCE_CNT
- struct sba_dma_pair *d = &(ioc->saved[ioc->saved_cnt]);
+ struct sba_dma_pair *d;
#endif
-
unsigned long flags;
dma_addr_t offset;
+
+ ASSERT(dev->sysdata);
+ ioc = GET_IOC(dev);
+ ASSERT(ioc);
+
+#ifdef DELAYED_RESOURCE_CNT
+ *d = &(ioc->saved[ioc->saved_cnt]);
+#endif
+
offset = iova & ~IOVP_MASK;
DBG_RUN("%s() iovp 0x%lx/%x\n",
@@ -874,6 +954,14 @@ sba_unmap_single(struct pci_dev *dev, dm
}
+/**
+ * sba_alloc_consistent - allocate/map shared mem for DMA
+ * @hwdev: instance of PCI owned by the driver that's asking.
+ * @size: number of bytes mapped in driver buffer.
+ * @dma_handle: IOVA of new buffer.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
static void *
sba_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
{
@@ -896,6 +984,15 @@ sba_alloc_consistent(struct pci_dev *hwd
}
+/**
+ * sba_free_consistent - free/unmap shared mem for DMA
+ * @hwdev: instance of PCI owned by the driver that's asking.
+ * @size: number of bytes mapped in driver buffer.
+ * @vaddr: virtual address IOVA of "consistent" buffer.
+ * @dma_handler: IO virtual address of "consistent" buffer.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
static void
sba_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
{
@@ -915,6 +1012,17 @@ sba_free_consistent(struct pci_dev *hwde
int dump_run_sg = 0;
#endif
+
+/**
+ * sba_fill_pdir - write allocated SG entries into IO PDIR
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg: list of IOVA/size pairs
+ * @nents: number of entries in startsg list
+ *
+ * Take preprocessed SG list and write corresponding entries
+ * in the IO PDIR.
+ */
+
static SBA_INLINE int
sba_fill_pdir(
struct ioc *ioc,
@@ -1001,15 +1109,20 @@ sba_fill_pdir(
(((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL)
-/*
-** First pass is to walk the SG list and determine where the breaks are
-** in the DMA stream. Allocates PDIR entries but does not fill them.
-** Returns the number of DMA chunks.
-**
-** Doing the fill seperate from the coalescing/allocation keeps the
-** code simpler. Future enhancement could make one pass through
-** the sglist do both.
-*/
+/**
+ * sba_coalesce_chunks - preprocess the SG list
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg: list of IOVA/size pairs
+ * @nents: number of entries in startsg list
+ *
+ * First pass is to walk the SG list and determine where the breaks are
+ * in the DMA stream. Allocates PDIR entries but does not fill them.
+ * Returns the number of DMA chunks.
+ *
+ * Doing the fill seperate from the coalescing/allocation keeps the
+ * code simpler. Future enhancement could make one pass through
+ * the sglist do both.
+ */
static SBA_INLINE int
sba_coalesce_chunks( struct ioc *ioc,
struct scatterlist *startsg,
@@ -1125,19 +1238,28 @@ sba_coalesce_chunks( struct ioc *ioc,
}
-/*
-** And this algorithm still generally only ends up coalescing entries
-** that happens to be on the same page due to how sglists are assembled.
-*/
+/**
+ * sba_map_sg - map Scatter/Gather list
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @sglist: array of buffer/length pairs
+ * @nents: number of entries in list
+ * @direction: R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
static int
sba_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
{
- struct ioc *ioc = &sba_list->ioc[0]; /* FIXME : see Multi-IOC below */
+ struct ioc *ioc;
int coalesced, filled = 0;
unsigned long flags;
DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents);
+ ASSERT(dev->sysdata);
+ ioc = GET_IOC(dev);
+ ASSERT(ioc);
+
/* Fast path single entry scatterlists. */
if (nents == 1) {
sg_dma_address(sglist)= sba_map_single(dev, sglist->address,
@@ -1197,10 +1319,19 @@ sba_map_sg(struct pci_dev *dev, struct s
}
+/**
+ * sba_unmap_sg - unmap Scatter/Gather list
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @sglist: array of buffer/length pairs
+ * @nents: number of entries in list
+ * @direction: R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
static void
sba_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
{
- struct ioc *ioc = &sba_list->ioc[0]; /* FIXME : see Multi-IOC below */
+ struct ioc *ioc;
#ifdef ASSERT_PDIR_SANITY
unsigned long flags;
#endif
@@ -1208,6 +1339,10 @@ sba_unmap_sg(struct pci_dev *dev, struct
DBG_RUN_SG("%s() START %d entries, %p,%x\n",
__FUNCTION__, nents, sglist->address, sglist->length);
+ ASSERT(dev->sysdata);
+ ioc = GET_IOC(dev);
+ ASSERT(ioc);
+
#ifdef CONFIG_PROC_FS
ioc->usg_calls++;
#endif
@@ -1666,11 +1801,13 @@ sba_driver_callback(struct parisc_device
printk(KERN_ERR MODULE_NAME " - couldn't alloc sba_device\n");
return(1);
}
+
+ dev->sysdata = (void *) sba_dev;
memset(sba_dev, 0, sizeof(struct sba_device));
+
for(i=0; i<MAX_IOC; i++)
spin_lock_init(&(sba_dev->ioc[i].res_lock));
-
sba_dev->hw_rev = func_class;
sba_dev->iodc = &dev->id;
sba_dev->name = dev->name;
@@ -1700,10 +1837,8 @@ static struct parisc_device_id sba_tbl[]
{ HPHW_IOA, HVERSION_REV_ANY_ID, ASTRO_RUNWAY_PORT, 0xb },
{ HPHW_BCPORT, HVERSION_REV_ANY_ID, ASTRO_ROPES_PORT, 0xb },
{ HPHW_BCPORT, HVERSION_REV_ANY_ID, REO_MERCED_PORT, 0xc },
-#if 0
{ HPHW_BCPORT, HVERSION_REV_ANY_ID, IKE_MERCED_PORT, 0xb },
{ HPHW_BCPORT, HVERSION_REV_ANY_ID, IKE_ROPES_PORT, 0xb },
-#endif
{ 0, }
};
@@ -1721,4 +1856,24 @@ static struct parisc_driver sba_driver =
void __init sba_init(void)
{
register_parisc_driver(&sba_driver);
+}
+
+
+/**
+ * sba_get_iommu - Assign the iommu pointer for the pci bus controller.
+ * @dev: The parisc device.
+ *
+ * This function searches through the registerd IOMMU's and returns the
+ * appropriate IOMMU data for the given parisc PCI controller.
+ */
+void * sba_get_iommu(struct parisc_device *pci_hba)
+{
+ struct sba_device *sba = (struct sba_device *) pci_hba->parent->sysdata;
+ char t = pci_hba->parent->id.hw_type;
+ int iocnum = (pci_hba->hw_path >> 3); /* rope # */
+
+ if ((t!=HPHW_IOA) && (t!=HPHW_BCPORT))
+ BUG();
+
+ return &(sba->ioc[iocnum]);
}
Index: arch/parisc/kernel/setup.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/setup.c,v
retrieving revision 1.93
diff -u -p -r1.93 setup.c
--- setup.c 2001/10/11 23:43:27 1.93
+++ setup.c 2001/10/23 05:59:34
@@ -195,15 +195,15 @@ void __init parisc_init(void)
boot_cpu_data.cpu_hz / 1000000,
boot_cpu_data.cpu_hz % 1000000 );
+ /* These are in a non-obvious order, will fix when we have an iotree */
#if defined(CONFIG_IOSAPIC)
iosapic_init();
#endif
- /* These are in a non-obvious order, will fix when we have an iotree */
-#if defined(CONFIG_PCI_LBA)
- lba_init();
-#endif
#if defined(CONFIG_IOMMU_SBA)
sba_init();
+#endif
+#if defined(CONFIG_PCI_LBA)
+ lba_init();
#endif
#if defined(CONFIG_IOMMU_CCIO)
ccio_init();
Index: include/asm-parisc/hardware.h
===================================================================
RCS file: /home/cvs/parisc/linux/include/asm-parisc/hardware.h,v
retrieving revision 1.26
diff -u -p -r1.26 hardware.h
--- hardware.h 2001/10/22 21:38:06 1.26
+++ hardware.h 2001/10/23 05:59:35
@@ -30,6 +30,7 @@ struct parisc_device {
struct parisc_device *sibling;
struct parisc_device *child;
struct parisc_driver *driver; /* Driver for this device */
+ void *sysdata; /* Driver instance private data */
char name[80]; /* The hardware description */
int irq;
Index: include/asm-parisc/pci.h
===================================================================
RCS file: /home/cvs/parisc/linux/include/asm-parisc/pci.h,v
retrieving revision 1.32
diff -u -p -r1.32 pci.h
--- pci.h 2001/10/22 05:10:05 1.32
+++ pci.h 2001/10/23 05:59:35
@@ -240,4 +240,8 @@ struct pci_dev * ccio_get_fake(struct pa
#define ccio_get_fake(dev) (NULL)
#endif /* !CONFIG_IOMMU_CCIO */
+#ifdef CONFIG_IOMMU_SBA
+void * sba_get_iommu(struct parisc_device *dev);
+#endif
+
#endif /* __ASM_PARISC_PCI_H */