[patch 2/2] backport of sba sg list management to ccio-dma

Joel Soete <[email protected]> Tue, 16 Oct 2007 16:34:08 +0000
Newsgroups gmane.linux.ports.hppa
Message-ID <[email protected]>
This is a multi-part message in MIME format.
--------------060309050404030803040800
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

And here is the main hunk:

This consist of 'backporting' to ccio of the most of Grant's work on sg list
management of sba-iommu.

According to some stress test on d380 it makes ncr driver more stable; improve
network perf on my d380 (from 110 to 430 kb/s);
(would allow in a next step merge some hunk of sba code in iommu-helper.h)

Tia,
J.

--------------060309050404030803040800
Content-Type: text/x-patch;
 name="bp-sba_sg-2-ccio-dma.c.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="bp-sba_sg-2-ccio-dma.c.patch"

Index: linux-current/drivers/parisc/ccio-dma.c
===================================================================
--- linux-current.orig/drivers/parisc/ccio-dma.c	2007-10-15 10:48:27.000000000 +0000
+++ linux-current/drivers/parisc/ccio-dma.c	2007-10-15 14:15:03.000000000 +0000
@@ -51,6 +51,7 @@
 #include <asm/io.h>
 #include <asm/hardware.h>       /* for register_module() */
 #include <asm/parisc-device.h>
+#include <asm/delay.h>
 
 /*
 ** Choose "ccio" since that's what HP-UX calls it.
@@ -102,7 +103,11 @@
 #define DBG_RUN_SG(x...)
 #endif
 
-#define CCIO_INLINE		inline
+#undef DMA_CHUNK_SIZE
+#define DMA_CHUNK_SIZE		(BITS_PER_LONG * IOVP_SIZE)
+#define DELAYED_RESOURCE_CNT	16
+
+#define CCIO_INLINE		__inline__
 #define WRITE_U32(value, addr)	__raw_writel(value, addr)
 #define READ_U32(addr)		__raw_readl(addr)
 
@@ -134,7 +139,7 @@
 	uint32_t	io_pdir_base;	/* Offset  7 */
 	uint32_t	io_io_low_hv;	/* Offset  8 */
 	uint32_t	io_io_high_hv;	/* Offset  9 */
-        uint32_t unused4[1];
+	uint32_t unused4[1];
 	uint32_t	io_chain_id_mask;/* Offset 11 */
 	uint32_t unused5[2];
 	uint32_t	io_io_low;	/* Offset 14 */
@@ -227,16 +232,28 @@
 ** returns before issuing subsequent writes.
 */
 
+typedef unsigned long	address_t;
+
 struct ioc {
 	struct ioa_registers __iomem *ioc_regs;	/* I/O MMU base address */
 	u8		*res_map;		/* resource map, bit == pdir entry */
 	u64		*pdir_base;		/* physical base address */
 	u32		pdir_size; 		/* bytes, function of IOV Space size */
-	u32		res_hint;		/* next available IOVP -
+	address_t	*res_hint;		/* next available IOVP -
 						   circular search */
-	u32		res_size;		/* size of resource map in bytes */
 	spinlock_t	res_lock;
 
+	uint32_t	res_bitshift;		/* from the LEFT! */
+	u32		res_size;		/* size of resource map in bytes */
+
+#if DELAYED_RESOURCE_CNT > 0
+	int             saved_cnt;
+	struct ioc_dma_pair {
+		dma_addr_t      iova;
+		size_t          size;
+	} saved[DELAYED_RESOURCE_CNT];
+#endif
+
 #ifdef CCIO_SEARCH_TIME
 #define CCIO_SEARCH_SAMPLE 0x100
 	unsigned long	avg_search[CCIO_SEARCH_SAMPLE];
@@ -259,7 +276,7 @@
 	u32		chainid_shift;	/* specify bit location of chain_id */
 	struct ioc	*next;		/* Linked list of discovered iocs */
 	const char	*name;		/* device name from firmware */
-	unsigned int	hw_path;	/* the hardware path this ioc is associatd with */
+	uint32_t	hw_path;	/* the hardware path this ioc is associatd with */
 	struct pci_dev	*fake_pci_dev;	/* the fake pci_dev for non-pci devs */
 	struct resource	mmio_region[2];	/* The "routed" MMIO regions */
 };
@@ -290,45 +307,115 @@
 #define CCIO_IOVA(iovp,offset)	((iovp) | (offset))
 #define CCIO_IOVP(iova)		((iova) & IOVP_MASK)
 
+#define PDIR_ENTRY_SIZE		sizeof(u64)
 #define PDIR_INDEX(iovp)	((iovp)>>IOVP_SHIFT)
+
+#define RESMAP_MASK(n)		(~0UL << (BITS_PER_LONG - (n)))
+#define RESMAP_IDX_MASK		(sizeof(unsigned long) - 1)
+
+/**
+ * For most cases the normal get_order is sufficient, however it limits us
+ * to PAGE_SIZE being the minimum mapping alignment and TC flush granularity.
+ * It only incurs about 1 clock cycle to use this one with the static variable
+ * and makes the code more intuitive.
+ */
+static CCIO_INLINE int
+get_iovp_order(unsigned long size)
+{
+	int order;
+
+	size = (size - 1) >> (IOVP_SHIFT - 1);
+	order = -1;
+	do {
+		size >>= 1;
+		order++;
+	} while (size);
+	return order;
+}
+
 #define MKIOVP(pdir_idx)	((long)(pdir_idx) << IOVP_SHIFT)
-#define MKIOVA(iovp,offset)	(dma_addr_t)((long)iovp | (long)offset)
+#define MKIOVA(iovp, offset)	(dma_addr_t)((long)iovp | (long)offset)
+#define ROUNDUP(x, y)		((x + ((y)-1)) & ~((y)-1))
 
-/*
-** Don't worry about the 150% average search length on a miss.
-** If the search wraps around, and passes the res_hint, it will
-** cause the kernel to panic anyhow.
-*/
-#define CCIO_SEARCH_LOOP(ioc, res_idx, mask, size)  \
-       for(; res_ptr < res_end; ++res_ptr) { \
-               if(0 == (*res_ptr & mask)) { \
-                       *res_ptr |= mask; \
-                       res_idx = (unsigned int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \
-                       ioc->res_hint = res_idx + (size >> 3); \
-                       goto resource_found; \
-               } \
-       }
-
-#define CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, size) \
-       u##size *res_ptr = (u##size *)&((ioc)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \
-       u##size *res_end = (u##size *)&(ioc)->res_map[ioa->res_size]; \
-       CCIO_SEARCH_LOOP(ioc, res_idx, mask, size); \
-       res_ptr = (u##size *)&(ioc)->res_map[0]; \
-       CCIO_SEARCH_LOOP(ioa, res_idx, mask, size);
+/**
+ * ccio_search_bitmap - find free space in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @pages_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 CCIO_INLINE address_t
+ccio_search_bitmap(struct ioc *ioc, unsigned long pages_wanted)
+{
+	address_t *res_ptr = ioc->res_hint;
+	address_t *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]);
+	address_t pide = ~0UL;
+
+	if (pages_wanted > (BITS_PER_LONG/2)) {
+		/* Search word at a time - no mask needed */
+		for(; res_ptr < res_end; ++res_ptr) {
+			if (*res_ptr == 0) {
+				*res_ptr = RESMAP_MASK(pages_wanted);
+				pide = ((address_t)res_ptr - (address_t)ioc->res_map);
+				pide <<= 3;     /* convert to bit address */
+				break;
+			}
+		}
+		/* point to the next word on next pass */
+		res_ptr++;
+		ioc->res_bitshift = 0;
+	} else {
+		/*
+		** Search the resource bit map on well-aligned values.
+		** "o" is the alignment.
+		** We need the alignment to invalidate I/O TLB using
+		** xxx HW features in the unmap path.
+		*/
+		unsigned long o = 1 << get_iovp_order(pages_wanted << IOVP_SHIFT);
+		uint bitshiftcnt = ROUNDUP(ioc->res_bitshift, o);
+		unsigned long mask;
 
-/*
-** Find available bit in this ioa's resource map.
-** Use a "circular" search:
-**   o Most IOVA's are "temporary" - avg search time should be small.
-** o keep a history of what happened for debugging
-** o KISS.
-**
-** Perf optimizations:
-** o search for log2(size) bits at a time.
-** o search for available resource bits using byte/word/whatever.
-** o use different search for "large" (eg > 4 pages) or "very large"
-**   (eg > 16 pages) mappings.
-*/
+		if (bitshiftcnt >= BITS_PER_LONG) {
+			bitshiftcnt = 0;
+			res_ptr++;
+		}
+		mask = RESMAP_MASK(pages_wanted) >> bitshiftcnt;
+
+		DBG_RES("%s() o %ld %p", __FUNCTION__, o, res_ptr);
+		while(res_ptr < res_end)
+		{
+			DBG_RES("    %p %lx %lx\n", res_ptr, mask, *res_ptr);
+			WARN_ON(mask == 0);
+			if(((*res_ptr) & mask) == 0) {
+				*res_ptr |= mask;     /* mark resources busy! */
+				pide = ((address_t)res_ptr - (address_t)ioc->res_map);
+				pide <<= 3;     /* convert to bit address */
+				pide += bitshiftcnt;
+				break;
+			}
+			mask >>= o;
+			bitshiftcnt += o;
+			if (mask == 0) {
+				mask = RESMAP_MASK(pages_wanted);
+				bitshiftcnt=0;
+				res_ptr++;
+			}
+		}
+		/* look in the same word on the next pass */
+		ioc->res_bitshift = bitshiftcnt + pages_wanted;
+	}
+
+	/* wrapped ? */
+	if (res_end <= res_ptr) {
+		ioc->res_hint = (address_t *) ioc->res_map;
+		ioc->res_bitshift = 0;
+	} else {
+		ioc->res_hint = res_ptr;
+	}
+	return (pide);
+}
 
 /**
  * ccio_alloc_range - Allocate pages in the ioc's resource map.
@@ -347,7 +434,9 @@
 #ifdef CCIO_SEARCH_TIME
 	unsigned long cr_start = mfctl(16);
 #endif
-	
+
+	unsigned long	pide;
+
 	BUG_ON(pages_needed == 0);
 	BUG_ON((pages_needed * IOVP_SIZE) > DMA_CHUNK_SIZE);
 
@@ -359,44 +448,19 @@
 	** ggg sacrifices another 710 to the computer gods.
 	*/
 
-	if (pages_needed <= 8) {
-		/*
-		 * LAN traffic will not thrash the TLB IFF the same NIC
-		 * uses 8 adjacent pages to map seperate payload data.
-		 * ie the same byte in the resource bit map.
-		 */
-#if 0
-		/* FIXME: bit search should shift it's way through
-		 * an unsigned long - not byte at a time. As it is now,
-		 * we effectively allocate this byte to this mapping.
-		 */
-		unsigned long mask = ~(~0UL >> pages_needed);
-		CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 8);
-#else
-		CCIO_FIND_FREE_MAPPING(ioc, res_idx, 0xff, 8);
-#endif
-	} else if (pages_needed <= 16) {
-		CCIO_FIND_FREE_MAPPING(ioc, res_idx, 0xffff, 16);
-	} else if (pages_needed <= 32) {
-		CCIO_FIND_FREE_MAPPING(ioc, res_idx, ~(unsigned int)0, 32);
-#ifdef __LP64__
-	} else if (pages_needed <= 64) {
-		CCIO_FIND_FREE_MAPPING(ioc, res_idx, ~0UL, 64);
-#endif
-	} else {
-		panic("%s: %s() Too many pages to map. pages_needed: %u\n",
-		       __FILE__,  __FUNCTION__, pages_needed);
+	pide = ccio_search_bitmap(ioc, pages_needed);
+	if (pide >= (ioc->res_size << 3)) {
+		pide = ccio_search_bitmap(ioc, pages_needed);
+		if (pide >= (ioc->res_size << 3))
+			panic("%s: %s() I/O MMU is out of mapping resources.\n", __FILE__,
+				__FUNCTION__);
 	}
 
-	panic("%s: %s() I/O MMU is out of mapping resources.\n", __FILE__,
-	      __FUNCTION__);
-	
-resource_found:
-	
 	DBG_RES("%s() res_idx %d res_hint: %d\n",
 		__FUNCTION__, res_idx, ioc->res_hint);
 
 #ifdef CCIO_SEARCH_TIME
+	udelay(100);
 	{
 		unsigned long cr_end = mfctl(16);
 		unsigned long tmp = cr_end - cr_start;
@@ -412,14 +476,9 @@
 	/*
 	** return the bit address.
 	*/
-	return res_idx << 3;
+	return (pide);
 }
 
-#define CCIO_FREE_MAPPINGS(ioc, res_idx, mask, size) \
-        u##size *res_ptr = (u##size *)&((ioc)->res_map[res_idx]); \
-        BUG_ON((*res_ptr & mask) != mask); \
-        *res_ptr &= ~(mask);
-
 /**
  * ccio_free_range - Free pages from the ioc's resource map.
  * @ioc: The I/O Controller.
@@ -430,42 +489,33 @@
  * This function frees the resouces allocated for the iova.
  */
 static void
-ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped)
+ccio_free_range(struct ioc *ioc, dma_addr_t iova, size_t size)
 {
 	unsigned long iovp = CCIO_IOVP(iova);
-	unsigned int res_idx = PDIR_INDEX(iovp) >> 3;
-
-	BUG_ON(pages_mapped == 0);
-	BUG_ON((pages_mapped * IOVP_SIZE) > DMA_CHUNK_SIZE);
-	BUG_ON(pages_mapped > BITS_PER_LONG);
 
-	DBG_RES("%s():  res_idx: %d pages_mapped %d\n",
-		__FUNCTION__, res_idx, pages_mapped);
+	unsigned int pide = PDIR_INDEX(iovp);
+	unsigned int ridx = pide >> 3;
+	unsigned long *res_ptr = (unsigned long *) &((ioc)->res_map[ridx & ~RESMAP_IDX_MASK]);
+
+	/* was: unsigned int pages_mapped = size >> IOVP_SHIFT; */
+	int bits_not_wanted = size >> IOVP_SHIFT;
+
+	/* 3-bits "bit" address plus 2 (or 3) bits for "byte" == bit in word */
+	unsigned long m = RESMAP_MASK(bits_not_wanted) >> (pide & (BITS_PER_LONG - 1));
+
+	BUG_ON(size == 0);
+	BUG_ON(size > DMA_CHUNK_SIZE);
+	BUG_ON(bits_not_wanted > BITS_PER_LONG);
+
+	DBG_RES("%s( ,%x,%x) %x/%lx %x %p %lx\n",
+		__FUNCTION__, (uint) iova, size,
+		bits_not_wanted, m, pide, res_ptr, *res_ptr);
 
 #ifdef CCIO_MAP_STATS
-	ioc->used_pages -= pages_mapped;
+	ioc->used_pages -= bits_not_wanted;
 #endif
 
-	if(pages_mapped <= 8) {
-#if 0
-		/* see matching comments in alloc_range */
-		unsigned long mask = ~(~0UL >> pages_mapped);
-		CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 8);
-#else
-		CCIO_FREE_MAPPINGS(ioc, res_idx, 0xff, 8);
-#endif
-	} else if(pages_mapped <= 16) {
-		CCIO_FREE_MAPPINGS(ioc, res_idx, 0xffff, 16);
-	} else if(pages_mapped <= 32) {
-		CCIO_FREE_MAPPINGS(ioc, res_idx, ~(unsigned int)0, 32);
-#ifdef __LP64__
-	} else if(pages_mapped <= 64) {
-		CCIO_FREE_MAPPINGS(ioc, res_idx, ~0UL, 64);
-#endif
-	} else {
-		panic("%s:%s() Too many pages to unmap.\n", __FILE__,
-		      __FUNCTION__);
-	}
+	*res_ptr &= ~m;
 }
 
 /****************************************************************
@@ -664,32 +714,45 @@
 static CCIO_INLINE void
 ccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
 {
-	u32 iovp = (u32)CCIO_IOVP(iova);
+	uint32_t iovp = (uint32_t)CCIO_IOVP(iova);
+	u64 *pdir_ptr = &ioc->pdir_base[PDIR_INDEX(iovp)];
 	size_t saved_byte_cnt;
 
 	/* round up to nearest page size */
 	saved_byte_cnt = byte_cnt = ALIGN(byte_cnt, IOVP_SIZE);
 
-	while(byte_cnt > 0) {
-		/* invalidate one page at a time */
-		unsigned int idx = PDIR_INDEX(iovp);
-		char *pdir_ptr = (char *) &(ioc->pdir_base[idx]);
+	if (byte_cnt > IOVP_SIZE)
+	{
+		/* set "size" field for PCOM */
+		iovp |= get_iovp_order(byte_cnt) + IOVP_SHIFT;
 
-		BUG_ON(idx >= (ioc->pdir_size / sizeof(u64)));
-		pdir_ptr[7] = 0;	/* clear only VALID bit */
-		/*
-		** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360)
-		**   PCX-U/U+ do. (eg C200/C240)
-		** See PDC_MODEL/option 0/SW_CAP for "Non-coherent IO-PDIR bit".
-		**
-		** Hopefully someone figures out how to patch (NOP) the
-		** FDC/SYNC out at boot time.
-		*/
-		asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr[7]));
+		do {
+			/* clear I/O Pdir entry "valid" bit first */
+			((unsigned char *) pdir_ptr)[7] = 0;
+			/*
+			** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360)
+			**   PCX-U/U+ do. (eg C200/C240)
+			** See PDC_MODEL/option 0/SW_CAP for "Non-coherent IO-PDIR bit".
+			**
+			** Hopefully someone figures out how to patch (NOP) the
+			** FDC/SYNC out at boot time.
+			*/
+			asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr[7]));
+
+			pdir_ptr++;
+			byte_cnt -= IOVP_SIZE;
+		} while (byte_cnt > IOVP_SIZE);
+	} else
+		iovp |= IOVP_SHIFT;     /* set "size" field for PCOM */
 
-		iovp     += IOVP_SIZE;
-		byte_cnt -= IOVP_SIZE;
-	}
+	/*
+	** clear I/O PDIR entry "valid" bit.
+	** We have to R/M/W the cacheline regardless how much of the
+	** pdir entry that we clobber.
+	** The rest of the entry would be useful for debugging if we
+	** could dump core on HPMC.
+	*/
+	((unsigned char *) pdir_ptr)[7] = 0;
 
 	asm volatile("sync");
 	ccio_clear_io_tlb(ioc, CCIO_IOVP(iova), saved_byte_cnt);
@@ -711,7 +774,7 @@
 static int
 ccio_dma_supported(struct device *dev, u64 mask)
 {
-	if(dev == NULL) {
+	if(!dev) {
 		printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n");
 		BUG();
 		return 0;
@@ -783,6 +846,9 @@
 		size -= IOVP_SIZE;
 	}
 
+	/* force FDC ops in io_pdir_entry() to be visible to IOMMU */
+	asm volatile("sync" :: );
+
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
 
 	/* form complete address */
@@ -803,6 +869,9 @@
 		  enum dma_data_direction direction)
 {
 	struct ioc *ioc;
+#if DELAYED_RESOURCE_CNT > 0
+	struct ioc_dma_pair *d;
+#endif
 	unsigned long flags;
 	dma_addr_t offset = iova & ~IOVP_MASK;
 	
@@ -824,7 +893,30 @@
 #endif
 
 	ccio_mark_invalid(ioc, iova, size);
-	ccio_free_range(ioc, iova, (size >> IOVP_SHIFT));
+#if DELAYED_RESOURCE_CNT > 0
+	/* Delaying when we re-use a IO Pdir entry reduces the number
+	 * of MMIO reads needed to flush writes to the PCOM register.
+	 */
+	d = &(ioc->saved[ioc->saved_cnt]);
+	d->iova = iova;
+	d->size = size;
+	if (++(ioc->saved_cnt) >= DELAYED_RESOURCE_CNT) {
+		int cnt = ioc->saved_cnt;
+		while (cnt--) {
+			ccio_free_range(ioc, d->iova, d->size);
+			d--;
+		}
+		ioc->saved_cnt = 0;
+	}
+#else /* DELAYED_RESOURCE_CNT == 0 */
+
+	ccio_free_range(ioc, iova, size);
+
+	/* force fdc's to be visible now */
+	asm volatile("sync" :: );
+
+#endif /* DELAYED_RESOURCE_CNT == 0 */
+
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
 }
 
@@ -952,6 +1044,9 @@
 	*/
 	filled = iommu_fill_pdir(ioc, sglist, nents, hint, ccio_io_pdir_entry);
 
+	/* force FDC ops in io_pdir_entry() to be visible to IOMMU */
+	asm volatile("sync" :: );
+
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
 
 	BUG_ON(coalesced != filled);
@@ -993,11 +1088,12 @@
 
 	while(sg_dma_len(sglist) && nents--) {
 
-#ifdef CCIO_MAP_STATS
-		ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT;
-#endif
 		ccio_unmap_single(dev, sg_dma_address(sglist),
 				  sg_dma_len(sglist), direction);
+#ifdef CCIO_MAP_STATS
+		ioc->usg_pages += sg_dma_len(sglist) >> IOVP_SHIFT;
+		ioc->usingle_calls--;   /* kluge since call is unmap_sg() */
+#endif
 		++sglist;
 	}
 
@@ -1025,16 +1121,12 @@
 	int len = 0;
 	struct ioc *ioc = ioc_list;
 
-	while (ioc != NULL) {
+	while (ioc) {
 		unsigned int total_pages = ioc->res_size << 3;
-		unsigned long avg = 0, min, max;
-		int j;
 
-		len += seq_printf(m, "%s\n", ioc->name);
-		
-		len += seq_printf(m, "Cujo 2.0 bug    : %s\n",
-				  (ioc->cujo20_bug ? "yes" : "no"));
-		
+		len += seq_printf(m, "%s%s\n", ioc->name,
+			(ioc->cujo20_bug ? " (Cujo 2.0 bug)" : ""));
+
 		len += seq_printf(m, "IO PDIR size    : %d bytes (%d entries)\n",
 			       total_pages * 8, total_pages);
 
@@ -1048,6 +1140,8 @@
 				  ioc->res_size, total_pages);
 
 #ifdef CCIO_SEARCH_TIME
+		unsigned long avg = 0, min, max;
+		int j;
 		min = max = ioc->avg_search[0];
 		for(j = 0; j < CCIO_SEARCH_SAMPLE; ++j) {
 			avg += ioc->avg_search[j];
@@ -1104,7 +1198,7 @@
 	int len = 0;
 	struct ioc *ioc = ioc_list;
 
-	while (ioc != NULL) {
+	while (ioc) {
 		u32 *res_ptr = (u32 *)ioc->res_map;
 		int j;
 
@@ -1252,9 +1346,12 @@
 static void
 ccio_ioc_init(struct ioc *ioc)
 {
-	int i;
-	unsigned int iov_order;
-	u32 iova_space_size;
+	int		i;
+	uint32_t	iov_order,
+			num_iommu_pages,
+			iova_space_size;
+
+	uint32_t	IO_ChainIdMask;
 
 	/*
 	** Determine IOVA Space size from memory size.
@@ -1267,16 +1364,15 @@
 	** Hot-Plug/Removal of PCI cards. (aka PCI OLARD).
 	*/
 
-	iova_space_size = (u32) (num_physpages / count_parisc_driver(&ccio_driver));
+	unsigned long phys_mem = num_physpages << PAGE_SHIFT;
+	iova_space_size = (u_int32_t) (phys_mem  / count_parisc_driver(&ccio_driver));
 
 	/* limit IOVA space size to 1MB-1GB */
 
-	if (iova_space_size < (1 << (20 - PAGE_SHIFT))) {
-		iova_space_size =  1 << (20 - PAGE_SHIFT);
-#ifdef __LP64__
-	} else if (iova_space_size > (1 << (30 - PAGE_SHIFT))) {
-		iova_space_size =  1 << (30 - PAGE_SHIFT);
-#endif
+	if (iova_space_size < (1 << 20)) {
+		iova_space_size =  1 << 20;
+	} else if (iova_space_size > (1 << 30)) {
+		iova_space_size =  1 << 30;
 	}
 
 	/*
@@ -1292,27 +1388,27 @@
 	**   this is the case under linux."
 	*/
 
-	iov_order = get_order(iova_space_size << PAGE_SHIFT);
+	iov_order = get_iovp_order(iova_space_size);
 
-	/* iova_space_size is now bytes, not pages */
-	iova_space_size = 1 << (iov_order + PAGE_SHIFT);
+	iova_space_size = 1 << (iov_order + IOVP_SHIFT);
 
-	ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64);
+	num_iommu_pages = iova_space_size >> IOVP_SHIFT;
+	ioc->pdir_size = num_iommu_pages * PDIR_ENTRY_SIZE;
+
+	DBG_INIT("%s() hpa 0x%p mem %luMb IOV %uMb (%d bits)\n",
+			__FUNCTION__, ioc->ioc_regs,
+			phys_mem >> 20,
+			iova_space_size >> 20,
+			iov_order + IOVP_SHIFT);
 
 	BUG_ON(ioc->pdir_size > 8 * 1024 * 1024);   /* max pdir size <= 8MB */
 
 	/* Verify it's a power of two */
 	BUG_ON((1 << get_order(ioc->pdir_size)) != (ioc->pdir_size >> PAGE_SHIFT));
 
-	DBG_INIT("%s() hpa 0x%p mem %luMB IOV %dMB (%d bits)\n",
-			__FUNCTION__, ioc->ioc_regs,
-			(unsigned long) num_physpages >> (20 - PAGE_SHIFT),
-			iova_space_size>>20,
-			iov_order + PAGE_SHIFT);
-
 	ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL,
 						 get_order(ioc->pdir_size));
-	if(NULL == ioc->pdir_base) {
+	if(!(ioc->pdir_base)) {
 		panic("%s() could not allocate I/O Page Table\n", __FUNCTION__);
 	}
 	memset(ioc->pdir_base, 0, ioc->pdir_size);
@@ -1321,27 +1417,31 @@
 	DBG_INIT(" base %p\n", ioc->pdir_base);
 
 	/* resource map size dictated by pdir_size */
- 	ioc->res_size = (ioc->pdir_size / sizeof(u64)) >> 3;
+ 	ioc->res_size = num_iommu_pages >> 3;
 	DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, ioc->res_size);
 	
 	ioc->res_map = (u8 *)__get_free_pages(GFP_KERNEL,
 					      get_order(ioc->res_size));
-	if(NULL == ioc->res_map) {
+	if(!(ioc->res_map)) {
 		panic("%s() could not allocate resource map\n", __FUNCTION__);
 	}
 	memset(ioc->res_map, 0, ioc->res_size);
 
-	/* Initialize the res_hint to 16 */
-	ioc->res_hint = 16;
+	/* next available IOVP - circular search */
+	ioc->res_hint = (unsigned long *)
+		&(ioc->res_map[L1_CACHE_BYTES]);
 
 	/* Initialize the spinlock */
 	spin_lock_init(&ioc->res_lock);
 
+	IO_ChainIdMask = READ_U32(&ioc->ioc_regs->io_chain_id_mask);
+	DBG_INIT(" Default io_chain_id_mask 0x%x\n", IO_ChainIdMask);
+
 	/*
 	** Chainid is the upper most bits of an IOVP used to determine
 	** which TLB entry an IOVP will use.
 	*/
-	ioc->chainid_shift = get_order(iova_space_size) + PAGE_SHIFT - CCIO_CHAINID_SHIFT;
+	ioc->chainid_shift = iov_order + IOVP_SHIFT - CCIO_CHAINID_SHIFT;
 	DBG_INIT(" chainid_shift 0x%x\n", ioc->chainid_shift);
 
 	/*
@@ -1485,15 +1585,15 @@
 		return 0;
 
 	if (!expand_ioc_area(parent, size, min, max, align)) {
-		__raw_writel(((parent->start)>>16) | 0xffff0000,
+		WRITE_U32(((parent->start)>>16) | 0xffff0000,
 			     &ioc->ioc_regs->io_io_low);
-		__raw_writel(((parent->end)>>16) | 0xffff0000,
+		WRITE_U32(((parent->end)>>16) | 0xffff0000,
 			     &ioc->ioc_regs->io_io_high);
 	} else if (!expand_ioc_area(parent + 1, size, min, max, align)) {
 		parent++;
-		__raw_writel(((parent->start)>>16) | 0xffff0000,
+		WRITE_U32(((parent->start)>>16) | 0xffff0000,
 			     &ioc->ioc_regs->io_io_low_hv);
-		__raw_writel(((parent->end)>>16) | 0xffff0000,
+		WRITE_U32(((parent->end)>>16) | 0xffff0000,
 			     &ioc->ioc_regs->io_io_high_hv);
 	} else {
 		return -EBUSY;
@@ -1543,8 +1643,8 @@
 	struct ioc *ioc, **ioc_p = &ioc_list;
 	struct proc_dir_entry *info_entry, *bitmap_entry;
 	
-	ioc = kzalloc(sizeof(struct ioc), GFP_KERNEL);
-	if (ioc == NULL) {
+	ioc = kzalloc(sizeof(*ioc), GFP_KERNEL);
+	if (!ioc) {
 		printk(KERN_ERR MODULE_NAME ": memory allocation failure\n");
 		return 1;
 	}
@@ -1566,7 +1666,7 @@
 	dev->dev.platform_data = kzalloc(sizeof(struct pci_hba_data), GFP_KERNEL);
 
 	/* if this fails, no I/O cards will work, so may as well bug */
-	BUG_ON(dev->dev.platform_data == NULL);
+	BUG_ON(!(dev->dev.platform_data));
 	HBA_DATA(dev->dev.platform_data)->iommu = ioc;
 	
 	if (ioc_count == 0) {

--------------060309050404030803040800
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
--------------060309050404030803040800--