** FIXME: add DMA hint support programming in both sba and lba modules.
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <asm/hardware.h> /* for register_parisc_driver() stuff */
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include <asm/ropes.h>
+#include <asm/mckinley.h> /* for proc_mckinley_root */
#include <asm/runway.h> /* for proc_runway_root */
#include <asm/pdc.h> /* for PDC_MODEL_* */
#include <asm/pdcpat.h> /* for is_pdc_pat() */
#include <asm/parisc-device.h>
-
-/* declared in arch/parisc/kernel/setup.c */
-extern struct proc_dir_entry * proc_mckinley_root;
-
#define MODULE_NAME "SBA"
-#ifdef CONFIG_PROC_FS
-/* depends on proc fs support. But costs CPU performance */
-#undef SBA_COLLECT_STATS
-#endif
-
/*
** The number of debug flags is a clue - this code is fragile.
** Don't even think about messing with it unless you have
#define DBG_RES(x...)
#endif
-#if defined(__LP64__) && !defined(CONFIG_PDC_NARROW)
-/* "low end" PA8800 machines use ZX1 chipset */
-#define ZX1_SUPPORT
-#endif
-
#define SBA_INLINE __inline__
-
-/*
-** The number of pdir entries to "free" before issueing
-** a read to PCOM register to flush out PCOM writes.
-** Interacts with allocation granularity (ie 4 or 8 entries
-** allocated and free'd/purged at a time might make this
-** less interesting).
-*/
-#define DELAYED_RESOURCE_CNT 16
-
#define DEFAULT_DMA_HINT_REG 0
-#define ASTRO_RUNWAY_PORT 0x582
-#define IKE_MERCED_PORT 0x803
-#define REO_MERCED_PORT 0x804
-#define REOG_MERCED_PORT 0x805
-#define PLUTO_MCKINLEY_PORT 0x880
-
-#define SBA_FUNC_ID 0x0000 /* function id */
-#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */
-
-#define IS_ASTRO(id) ((id)->hversion == ASTRO_RUNWAY_PORT)
-#define IS_IKE(id) ((id)->hversion == IKE_MERCED_PORT)
-#define IS_PLUTO(id) ((id)->hversion == PLUTO_MCKINLEY_PORT)
-
-#define SBA_FUNC_SIZE 4096 /* SBA configuration function reg set */
-
-#define ASTRO_IOC_OFFSET (32 * SBA_FUNC_SIZE)
-#define PLUTO_IOC_OFFSET (1 * SBA_FUNC_SIZE)
-/* Ike's IOC's occupy functions 2 and 3 */
-#define IKE_IOC_OFFSET(p) ((p+2) * SBA_FUNC_SIZE)
-
-#define IOC_CTRL 0x8 /* IOC_CTRL offset */
-#define IOC_CTRL_TC (1 << 0) /* TOC Enable */
-#define IOC_CTRL_CE (1 << 1) /* Coalesce Enable */
-#define IOC_CTRL_DE (1 << 2) /* Dillon Enable */
-#define IOC_CTRL_RM (1 << 8) /* Real Mode */
-#define IOC_CTRL_NC (1 << 9) /* Non Coherent Mode */
-#define IOC_CTRL_D4 (1 << 11) /* Disable 4-byte coalescing */
-#define IOC_CTRL_DD (1 << 13) /* Disable distr. LMMIO range coalescing */
-
-#define MAX_IOC 2 /* per Ike. Pluto/Astro only have 1. */
-
-#define ROPES_PER_IOC 8 /* per Ike half or Pluto/Astro */
-
-
-/*
-** Offsets into MBIB (Function 0 on Ike and hopefully Astro)
-** Firmware programs this stuff. Don't touch it.
-*/
-#define LMMIO_DIRECT0_BASE 0x300
-#define LMMIO_DIRECT0_MASK 0x308
-#define LMMIO_DIRECT0_ROUTE 0x310
-
-#define LMMIO_DIST_BASE 0x360
-#define LMMIO_DIST_MASK 0x368
-#define LMMIO_DIST_ROUTE 0x370
-
-#define IOS_DIST_BASE 0x390
-#define IOS_DIST_MASK 0x398
-#define IOS_DIST_ROUTE 0x3A0
-
-#define IOS_DIRECT_BASE 0x3C0
-#define IOS_DIRECT_MASK 0x3C8
-#define IOS_DIRECT_ROUTE 0x3D0
-
-/*
-** Offsets into I/O TLB (Function 2 and 3 on Ike)
-*/
-#define ROPE0_CTL 0x200 /* "regbus pci0" */
-#define ROPE1_CTL 0x208
-#define ROPE2_CTL 0x210
-#define ROPE3_CTL 0x218
-#define ROPE4_CTL 0x220
-#define ROPE5_CTL 0x228
-#define ROPE6_CTL 0x230
-#define ROPE7_CTL 0x238
-
-#define HF_ENABLE 0x40
-
-
-#define IOC_IBASE 0x300 /* IO TLB */
-#define IOC_IMASK 0x308
-#define IOC_PCOM 0x310
-#define IOC_TCNFG 0x318
-#define IOC_PDIR_BASE 0x320
-
-/* AGP GART driver looks for this */
-#define SBA_IOMMU_COOKIE 0x0000badbadc0ffeeUL
-
-
-/*
-** IOC supports 4/8/16/64KB page sizes (see TCNFG register)
-** It's safer (avoid memory corruption) to keep DMA page mappings
-** equivalently sized to VM PAGE_SIZE.
-**
-** We really can't avoid generating a new mapping for each
-** page since the Virtual Coherence Index has to be generated
-** and updated for each page.
-**
-** PAGE_SIZE could be greater than IOVP_SIZE. But not the inverse.
-*/
-#define IOVP_SIZE PAGE_SIZE
-#define IOVP_SHIFT PAGE_SHIFT
-#define IOVP_MASK PAGE_MASK
-
-#define SBA_PERF_CFG 0x708 /* Performance Counter stuff */
-#define SBA_PERF_MASK1 0x718
-#define SBA_PERF_MASK2 0x730
-
-
-/*
-** Offsets into PCI Performance Counters (functions 12 and 13)
-** Controlled by PERF registers in function 2 & 3 respectively.
-*/
-#define SBA_PERF_CNT1 0x200
-#define SBA_PERF_CNT2 0x208
-#define SBA_PERF_CNT3 0x210
-
-
-struct ioc {
- void __iomem *ioc_hpa; /* I/O MMU base address */
- char *res_map; /* resource map, bit == pdir entry */
- u64 *pdir_base; /* physical base address */
- unsigned long ibase; /* pdir IOV Space base - shared w/lba_pci */
- unsigned long imask; /* pdir IOV Space mask - shared w/lba_pci */
-#ifdef ZX1_SUPPORT
- unsigned long iovp_mask; /* help convert IOVA to IOVP */
-#endif
- unsigned long *res_hint; /* next avail IOVP - circular search */
- spinlock_t res_lock;
- unsigned int res_bitshift; /* from the LEFT! */
- unsigned int res_size; /* size of resource map in bytes */
-#if SBA_HINT_SUPPORT
-/* FIXME : DMA HINTs not used */
- unsigned long hint_mask_pdir; /* bits used for DMA hints */
- unsigned int hint_shift_pdir;
-#endif
-#if DELAYED_RESOURCE_CNT > 0
- int saved_cnt;
- struct sba_dma_pair {
- dma_addr_t iova;
- size_t size;
- } saved[DELAYED_RESOURCE_CNT];
-#endif
-
-#ifdef SBA_COLLECT_STATS
-#define SBA_SEARCH_SAMPLE 0x100
- unsigned long avg_search[SBA_SEARCH_SAMPLE];
- unsigned long avg_idx; /* current index into avg_search */
- unsigned long used_pages;
- unsigned long msingle_calls;
- unsigned long msingle_pages;
- unsigned long msg_calls;
- unsigned long msg_pages;
- unsigned long usingle_calls;
- unsigned long usingle_pages;
- unsigned long usg_calls;
- unsigned long usg_pages;
-#endif
-
- /* STUFF We don't need in performance path */
- unsigned int pdir_size; /* in bytes, determined by IOV Space size */
-};
-
-struct sba_device {
- struct sba_device *next; /* list of SBA's in system */
- struct parisc_device *dev; /* dev found in bus walk */
- struct parisc_device_id *iodc; /* data about dev from firmware */
- const char *name;
- void __iomem *sba_hpa; /* base address */
- spinlock_t sba_lock;
- unsigned int flags; /* state/functionality enabled */
- unsigned int hw_rev; /* HW revision of chip */
-
- struct resource chip_resv; /* MMIO reserved for chip */
- struct resource iommu_resv; /* MMIO reserved for iommu */
-
- unsigned int num_ioc; /* number of on-board IOC's */
- struct ioc ioc[MAX_IOC];
-};
-
-
-static struct sba_device *sba_list;
+struct sba_device *sba_list;
+EXPORT_SYMBOL_GPL(sba_list);
static unsigned long ioc_needs_fdc = 0;
/* Looks nice and keeps the compiler happy */
#define SBA_DEV(d) ((struct sba_device *) (d))
-#if SBA_AGP_SUPPORT
-static int reserve_sba_gart = 1;
+#ifdef CONFIG_AGP_PARISC
+#define SBA_AGP_SUPPORT
+#endif /*CONFIG_AGP_PARISC*/
+
+#ifdef SBA_AGP_SUPPORT
+static int sba_reserve_agpgart = 1;
+module_param(sba_reserve_agpgart, int, 1);
+MODULE_PARM_DESC(sba_reserve_agpgart, "Reserve half of IO pdir as AGPGART");
#endif
#define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1))
**
** Superdome (in particular, REO) allows only 64-bit CSR accesses.
*/
-#define READ_REG32(addr) le32_to_cpu(__raw_readl(addr))
-#define READ_REG64(addr) le64_to_cpu(__raw_readq(addr))
-#define WRITE_REG32(val, addr) __raw_writel(cpu_to_le32(val), addr)
-#define WRITE_REG64(val, addr) __raw_writeq(cpu_to_le64(val), addr)
+#define READ_REG32(addr) readl(addr)
+#define READ_REG64(addr) readq(addr)
+#define WRITE_REG32(val, addr) writel((val), (addr))
+#define WRITE_REG64(val, addr) writeq((val), (addr))
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
#define READ_REG(addr) READ_REG64(addr)
#define WRITE_REG(value, addr) WRITE_REG64(value, addr)
#else
#ifdef DEBUG_SBA_INIT
-/* NOTE: When __LP64__ isn't defined, READ_REG64() is two 32-bit reads */
+/* NOTE: When CONFIG_64BIT isn't defined, READ_REG64() is two 32-bit reads */
/**
* sba_dump_ranges - debugging only - print ranges assigned to this IOA
#else
#define sba_dump_ranges(x)
#define sba_dump_tlb(x)
-#endif
+#endif /* DEBUG_SBA_INIT */
#ifdef ASSERT_PDIR_SANITY
*
***************************************************************/
-#if SBA_HINT_SUPPORT
+#ifdef SBA_HINT_SUPPORT
#define SBA_DMA_HINT(ioc, val) ((val) << (ioc)->hint_shift_pdir)
#endif
asm("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba));
pa |= (ci >> 12) & 0xff; /* move CI (8 bits) into lowest byte */
- pa |= 0x8000000000000000ULL; /* set "valid" bit */
+ pa |= SBA_PDIR_VALID_BIT; /* set "valid" bit */
*pdir_ptr = cpu_to_le64(pa); /* swap and store into I/O Pdir */
/*
* (bit #61, big endian), we have to flush and sync every time
* IO-PDIR is changed in Ike/Astro.
*/
- if (ioc_needs_fdc) {
- asm volatile("fdc 0(%%sr1,%0)\n\tsync" : : "r" (pdir_ptr));
- }
+ if (ioc_needs_fdc)
+ asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr));
}
sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
{
u32 iovp = (u32) SBA_IOVP(ioc,iova);
-
- /* Even though this is a big-endian machine, the entries
- ** in the iopdir are little endian. That's why we clear the byte
- ** at +7 instead of at +0.
- */
- int off = PDIR_INDEX(iovp)*sizeof(u64)+7;
+ u64 *pdir_ptr = &ioc->pdir_base[PDIR_INDEX(iovp)];
#ifdef ASSERT_PDIR_SANITY
- /* Assert first pdir entry is set */
- if (0x80 != (((u8 *) ioc->pdir_base)[off])) {
+ /* Assert first pdir entry is set.
+ **
+ ** Even though this is a big-endian machine, the entries
+ ** in the iopdir are little endian. That's why we look at
+ ** the byte at +7 instead of at +0.
+ */
+ if (0x80 != (((u8 *) pdir_ptr)[7])) {
sba_dump_pdir_entry(ioc,"sba_mark_invalid()", PDIR_INDEX(iovp));
}
#endif
- if (byte_cnt <= IOVP_SIZE)
+ if (byte_cnt > IOVP_SIZE)
{
- iovp |= IOVP_SHIFT; /* set "size" field for PCOM */
+#if 0
+ unsigned long entries_per_cacheline = ioc_needs_fdc ?
+ L1_CACHE_ALIGN(((unsigned long) pdir_ptr))
+ - (unsigned long) pdir_ptr;
+ : 262144;
+#endif
- /*
- ** clear I/O PDIR entry "valid" bit
- ** Do NOT clear the rest - save it for debugging.
- ** We should only clear bits that have previously
- ** been enabled.
- */
- ((u8 *)(ioc->pdir_base))[off] = 0;
- } else {
- u32 t = get_order(byte_cnt) + PAGE_SHIFT;
+ /* set "size" field for PCOM */
+ iovp |= get_order(byte_cnt) + PAGE_SHIFT;
- iovp |= t;
do {
/* clear I/O Pdir entry "valid" bit first */
- ((u8 *)(ioc->pdir_base))[off] = 0;
- off += sizeof(u64);
+ ((u8 *) pdir_ptr)[7] = 0;
+ if (ioc_needs_fdc) {
+ asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr));
+#if 0
+ entries_per_cacheline = L1_CACHE_SHIFT - 3;
+#endif
+ }
+ pdir_ptr++;
byte_cnt -= IOVP_SIZE;
- } while (byte_cnt > 0);
- }
+ } while (byte_cnt > IOVP_SIZE);
+ } else
+ iovp |= IOVP_SHIFT; /* set "size" field for PCOM */
+
+ /*
+ ** 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.
+ */
+ ((u8 *) pdir_ptr)[7] = 0;
+ if (ioc_needs_fdc)
+ asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr));
WRITE_REG( SBA_IOVA(ioc, iovp, 0, 0), ioc->ioc_hpa+IOC_PCOM);
}
static int sba_dma_supported( struct device *dev, u64 mask)
{
struct ioc *ioc;
+
if (dev == NULL) {
printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n");
BUG();
return(0);
}
- ioc = GET_IOC(dev);
+ /* Documentation/DMA-mapping.txt tells drivers to try 64-bit first,
+ * then fall back to 32-bit if that fails.
+ * We are just "encouraging" 32-bit DMA masks here since we can
+ * never allow IOMMU bypass unless we add special support for ZX1.
+ */
+ if (mask > ~0U)
+ return 0;
- /* check if mask is > than the largest IO Virt Address */
+ ioc = GET_IOC(dev);
- return((int) (mask >= (ioc->ibase +
- (ioc->pdir_size / sizeof(u64) * IOVP_SIZE) )));
+ /*
+ * check if mask is >= than the current max IO Virt Address
+ * The max IO Virt address will *always* < 30 bits.
+ */
+ return((int)(mask >= (ioc->ibase - 1 +
+ (ioc->pdir_size / sizeof(u64) * IOVP_SIZE) )));
}
size -= IOVP_SIZE;
pdir_start++;
}
- /* form complete address */
+
+ /* force FDC ops in io_pdir_entry() to be visible to IOMMU */
+ if (ioc_needs_fdc)
+ asm volatile("sync" : : );
+
#ifdef ASSERT_PDIR_SANITY
sba_check_pdir(ioc,"Check after sba_map_single()");
#endif
spin_unlock_irqrestore(&ioc->res_lock, flags);
+
+ /* form complete address */
return SBA_IOVA(ioc, iovp, offset, DEFAULT_DMA_HINT_REG);
}
d--;
}
ioc->saved_cnt = 0;
+
READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */
}
#else /* DELAYED_RESOURCE_CNT == 0 */
sba_free_range(ioc, iova, size);
+
+ /* If fdc's were issued, force fdc's to be visible now */
+ if (ioc_needs_fdc)
+ asm volatile("sync" : : );
+
READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */
#endif /* DELAYED_RESOURCE_CNT == 0 */
+
spin_unlock_irqrestore(&ioc->res_lock, flags);
/* XXX REVISIT for 2.5 Linux - need syncdma for zero-copy support.
* See Documentation/DMA-mapping.txt
*/
static void *sba_alloc_consistent(struct device *hwdev, size_t size,
- dma_addr_t *dma_handle, int gfp)
+ dma_addr_t *dma_handle, gfp_t gfp)
{
void *ret;
*/
filled = iommu_fill_pdir(ioc, sglist, nents, 0, sba_io_pdir_entry);
+ /* force FDC ops in io_pdir_entry() to be visible to IOMMU */
+ if (ioc_needs_fdc)
+ asm volatile("sync" : : );
+
#ifdef ASSERT_PDIR_SANITY
if (sba_check_pdir(ioc,"Check after sba_map_sg()"))
{
unsigned long pdir_order = get_order(pdir_size);
pdir_base = __get_free_pages(GFP_KERNEL, pdir_order);
- if (NULL == (void *) pdir_base)
- panic("sba_ioc_init() could not allocate I/O Page Table\n");
+ if (NULL == (void *) pdir_base) {
+ panic("%s() could not allocate I/O Page Table\n",
+ __FUNCTION__);
+ }
/* If this is not PA8700 (PCX-W2)
** OR newer than ver 2.2
return (void *) pdir_base;
}
+static struct device *next_device(struct klist_iter *i)
+{
+ struct klist_node * n = klist_next(i);
+ return n ? container_of(n, struct device, knode_parent) : NULL;
+}
+
/* setup Mercury or Elroy IBASE/IMASK registers. */
-static void setup_ibase_imask(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
+static void
+setup_ibase_imask(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
{
- /* lba_set_iregs() is in drivers/parisc/lba_pci.c */
+ /* lba_set_iregs() is in drivers/parisc/lba_pci.c */
extern void lba_set_iregs(struct parisc_device *, u32, u32);
struct device *dev;
+ struct klist_iter i;
- list_for_each_entry(dev, &sba->dev.children, node) {
+ klist_iter_init(&sba->dev.klist_children, &i);
+ while ((dev = next_device(&i))) {
struct parisc_device *lba = to_parisc_device(dev);
- int rope_num = (lba->hpa >> 13) & 0xf;
+ int rope_num = (lba->hpa.start >> 13) & 0xf;
if (rope_num >> 3 == ioc_num)
lba_set_iregs(lba, ioc->ibase, ioc->imask);
}
+ klist_iter_exit(&i);
}
static void
u32 iova_space_mask;
u32 iova_space_size;
int iov_order, tcnfg;
-#if SBA_AGP_SUPPORT
+#ifdef SBA_AGP_SUPPORT
int agp_found = 0;
#endif
/*
iov_order = get_order(iova_space_size >> (IOVP_SHIFT - PAGE_SHIFT));
ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64);
- DBG_INIT("%s() hpa 0x%lx IOV %dMB (%d bits)\n",
+ DBG_INIT("%s() hpa 0x%p IOV %dMB (%d bits)\n",
__FUNCTION__, ioc->ioc_hpa, iova_space_size >> 20,
iov_order + PAGE_SHIFT);
DBG_INIT("%s() pdir %p size %x\n",
__FUNCTION__, ioc->pdir_base, ioc->pdir_size);
-#if SBA_HINT_SUPPORT
+#ifdef SBA_HINT_SUPPORT
ioc->hint_shift_pdir = iov_order + PAGE_SHIFT;
ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT));
WRITE_REG(ioc->imask, ioc->ioc_hpa + IOC_IMASK);
-#ifdef __LP64__
+#ifdef CONFIG_64BIT
/*
** Setting the upper bits makes checking for bypass addresses
** a little faster later on.
*/
WRITE_REG(ioc->ibase | 31, ioc->ioc_hpa + IOC_PCOM);
-#if SBA_AGP_SUPPORT
+#ifdef SBA_AGP_SUPPORT
+{
+ struct klist_iter i;
+ struct device *dev = NULL;
+
/*
** If an AGP device is present, only use half of the IOV space
** for PCI DMA. Unfortunately we can't know ahead of time
** We program the next pdir index after we stop w/ a key for
** the GART code to handshake on.
*/
- device=NULL;
- for (lba = sba->child; lba; lba = lba->sibling) {
+ klist_iter_init(&sba->dev.klist_children, &i);
+ while ((dev = next_device(&i))) {
+ struct parisc_device *lba = to_parisc_device(dev);
if (IS_QUICKSILVER(lba))
- break;
+ agp_found = 1;
}
+ klist_iter_exit(&i);
- if (lba) {
- DBG_INIT("%s: Reserving half of IOVA space for AGP GART support\n", __FUNCTION__);
+ if (agp_found && sba_reserve_agpgart) {
+ printk(KERN_INFO "%s: reserving %dMb of IOVA space for agpgart\n",
+ __FUNCTION__, (iova_space_size/2) >> 20);
ioc->pdir_size /= 2;
- ((u64 *)ioc->pdir_base)[PDIR_INDEX(iova_space_size/2)] = SBA_IOMMU_COOKIE;
- } else {
- DBG_INIT("%s: No GART needed - no AGP controller found\n", __FUNCTION__);
+ ioc->pdir_base[PDIR_INDEX(iova_space_size/2)] = SBA_AGPGART_COOKIE;
}
-#endif /* 0 */
+}
+#endif /*SBA_AGP_SUPPORT*/
}
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
/*
** iova space must be log2() in size.
DBG_INIT("%s() pdir %p size %x\n",
__FUNCTION__, ioc->pdir_base, pdir_size);
-#if SBA_HINT_SUPPORT
+#ifdef SBA_HINT_SUPPORT
/* FIXME : DMA HINTs not used */
ioc->hint_shift_pdir = iov_order + PAGE_SHIFT;
ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT));
**
**************************************************************************/
-static void __iomem *ioc_remap(struct sba_device *sba_dev, int offset)
+static void __iomem *ioc_remap(struct sba_device *sba_dev, unsigned int offset)
{
- return ioremap(sba_dev->dev->hpa + offset, SBA_FUNC_SIZE);
+ return ioremap_nocache(sba_dev->dev->hpa.start + offset, SBA_FUNC_SIZE);
}
static void sba_hw_init(struct sba_device *sba_dev)
}
#endif
- if (!IS_PLUTO(sba_dev->iodc)) {
+ if (!IS_PLUTO(sba_dev->dev)) {
ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL);
DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->",
__FUNCTION__, sba_dev->sba_hpa, ioc_ctl);
#endif
} /* if !PLUTO */
- if (IS_ASTRO(sba_dev->iodc)) {
+ if (IS_ASTRO(sba_dev->dev)) {
int err;
- /* PAT_PDC (L-class) also reports the same goofy base */
sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, ASTRO_IOC_OFFSET);
num_ioc = 1;
sba_dev->chip_resv.start = PCI_F_EXTEND | 0xfef00000UL;
sba_dev->chip_resv.end = PCI_F_EXTEND | (0xff000000UL - 1) ;
err = request_resource(&iomem_resource, &(sba_dev->chip_resv));
- if (err < 0) {
- BUG();
- }
+ BUG_ON(err < 0);
- } else if (IS_PLUTO(sba_dev->iodc)) {
+ } else if (IS_PLUTO(sba_dev->dev)) {
int err;
- /* We use a negative value for IOC HPA so it gets
- * corrected when we add it with IKE's IOC offset.
- * Doesnt look clean, but fewer code.
- */
sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, PLUTO_IOC_OFFSET);
num_ioc = 1;
err = request_resource(&iomem_resource, &(sba_dev->iommu_resv));
WARN_ON(err < 0);
} else {
- /* IS_IKE (ie N-class, L3000, L1500) */
+ /* IKE, REO */
sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(0));
sba_dev->ioc[1].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(1));
num_ioc = 2;
/* TODO - LOOKUP Ike/Stretch chipset mem map */
}
- /* XXX: What about Reo? */
+ /* XXX: What about Reo Grande? */
sba_dev->num_ioc = num_ioc;
for (i = 0; i < num_ioc; i++) {
- /*
- ** Make sure the box crashes if we get any errors on a rope.
- */
- WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE0_CTL);
- WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE1_CTL);
- WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE2_CTL);
- WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE3_CTL);
- WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE4_CTL);
- WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE5_CTL);
- WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE6_CTL);
- WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);
-
- /* flush out the writes */
+ void __iomem *ioc_hpa = sba_dev->ioc[i].ioc_hpa;
+ unsigned int j;
+
+ for (j=0; j < sizeof(u64) * ROPES_PER_IOC; j+=sizeof(u64)) {
+
+ /*
+ * Clear ROPE(N)_CONFIG AO bit.
+ * Disables "NT Ordering" (~= !"Relaxed Ordering")
+ * Overrides bit 1 in DMA Hint Sets.
+ * Improves netperf UDP_STREAM by ~10% for bcm5701.
+ */
+ if (IS_PLUTO(sba_dev->dev)) {
+ void __iomem *rope_cfg;
+ unsigned long cfg_val;
+
+ rope_cfg = ioc_hpa + IOC_ROPE0_CFG + j;
+ cfg_val = READ_REG(rope_cfg);
+ cfg_val &= ~IOC_ROPE_AO;
+ WRITE_REG(cfg_val, rope_cfg);
+ }
+
+ /*
+ ** Make sure the box crashes on rope errors.
+ */
+ WRITE_REG(HF_ENABLE, ioc_hpa + ROPE0_CTL + j);
+ }
+
+ /* flush out the last writes */
READ_REG(sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);
DBG_INIT(" ioc[%d] ROPE_CFG 0x%Lx ROPE_DBG 0x%Lx\n",
READ_REG(sba_dev->ioc[i].ioc_hpa + 0x400)
);
- if (IS_PLUTO(sba_dev->iodc)) {
+ if (IS_PLUTO(sba_dev->dev)) {
sba_ioc_init_pluto(sba_dev->dev, &(sba_dev->ioc[i]), i);
} else {
sba_ioc_init(sba_dev->dev, &(sba_dev->ioc[i]), i);
* (bit #61, big endian), we have to flush and sync every time
* IO-PDIR is changed in Ike/Astro.
*/
- if (boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC) {
+ if (ioc_needs_fdc) {
printk(KERN_INFO MODULE_NAME " FDC/SYNC required.\n");
} else {
printk(KERN_INFO MODULE_NAME " IOC has cache coherent PDIR.\n");
}
#ifdef CONFIG_PROC_FS
-static int sba_proc_info(char *buf, char **start, off_t offset, int len)
+static int sba_proc_info(struct seq_file *m, void *p)
{
struct sba_device *sba_dev = sba_list;
struct ioc *ioc = &sba_dev->ioc[0]; /* FIXME: Multi-IOC support! */
int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */
- unsigned long i;
#ifdef SBA_COLLECT_STATS
unsigned long avg = 0, min, max;
#endif
+ int i, len = 0;
- sprintf(buf, "%s rev %d.%d\n",
+ len += seq_printf(m, "%s rev %d.%d\n",
sba_dev->name,
(sba_dev->hw_rev & 0x7) + 1,
(sba_dev->hw_rev & 0x18) >> 3
);
- sprintf(buf, "%sIO PDIR size : %d bytes (%d entries)\n",
- buf,
+ len += seq_printf(m, "IO PDIR size : %d bytes (%d entries)\n",
(int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */
total_pages);
- sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n",
- buf, ioc->res_size, ioc->res_size << 3); /* 8 bits per byte */
+ len += seq_printf(m, "Resource bitmap : %d bytes (%d pages)\n",
+ ioc->res_size, ioc->res_size << 3); /* 8 bits per byte */
- sprintf(buf, "%sLMMIO_BASE/MASK/ROUTE %08x %08x %08x\n",
- buf,
+ len += seq_printf(m, "LMMIO_BASE/MASK/ROUTE %08x %08x %08x\n",
READ_REG32(sba_dev->sba_hpa + LMMIO_DIST_BASE),
READ_REG32(sba_dev->sba_hpa + LMMIO_DIST_MASK),
READ_REG32(sba_dev->sba_hpa + LMMIO_DIST_ROUTE)
);
for (i=0; i<4; i++)
- sprintf(buf, "%sDIR%ld_BASE/MASK/ROUTE %08x %08x %08x\n",
- buf, i,
+ len += seq_printf(m, "DIR%d_BASE/MASK/ROUTE %08x %08x %08x\n", i,
READ_REG32(sba_dev->sba_hpa + LMMIO_DIRECT0_BASE + i*0x18),
READ_REG32(sba_dev->sba_hpa + LMMIO_DIRECT0_MASK + i*0x18),
READ_REG32(sba_dev->sba_hpa + LMMIO_DIRECT0_ROUTE + i*0x18)
);
#ifdef SBA_COLLECT_STATS
- sprintf(buf, "%sIO PDIR entries : %ld free %ld used (%d%%)\n", buf,
+ len += seq_printf(m, "IO PDIR entries : %ld free %ld used (%d%%)\n",
total_pages - ioc->used_pages, ioc->used_pages,
(int) (ioc->used_pages * 100 / total_pages));
if (ioc->avg_search[i] < min) min = ioc->avg_search[i];
}
avg /= SBA_SEARCH_SAMPLE;
- sprintf(buf, "%s Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
- buf, min, avg, max);
+ len += seq_printf(m, " Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
+ min, avg, max);
- sprintf(buf, "%spci_map_single(): %12ld calls %12ld pages (avg %d/1000)\n",
- buf, ioc->msingle_calls, ioc->msingle_pages,
+ len += seq_printf(m, "pci_map_single(): %12ld calls %12ld pages (avg %d/1000)\n",
+ ioc->msingle_calls, ioc->msingle_pages,
(int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls));
/* KLUGE - unmap_sg calls unmap_single for each mapped page */
min = ioc->usingle_calls;
max = ioc->usingle_pages - ioc->usg_pages;
- sprintf(buf, "%spci_unmap_single: %12ld calls %12ld pages (avg %d/1000)\n",
- buf, min, max,
- (int) ((max * 1000)/min));
+ len += seq_printf(m, "pci_unmap_single: %12ld calls %12ld pages (avg %d/1000)\n",
+ min, max, (int) ((max * 1000)/min));
- sprintf(buf, "%spci_map_sg() : %12ld calls %12ld pages (avg %d/1000)\n",
- buf, ioc->msg_calls, ioc->msg_pages,
+ len += seq_printf(m, "pci_map_sg() : %12ld calls %12ld pages (avg %d/1000)\n",
+ ioc->msg_calls, ioc->msg_pages,
(int) ((ioc->msg_pages * 1000)/ioc->msg_calls));
- sprintf(buf, "%spci_unmap_sg() : %12ld calls %12ld pages (avg %d/1000)\n",
- buf, ioc->usg_calls, ioc->usg_pages,
+ len += seq_printf(m, "pci_unmap_sg() : %12ld calls %12ld pages (avg %d/1000)\n",
+ ioc->usg_calls, ioc->usg_pages,
(int) ((ioc->usg_pages * 1000)/ioc->usg_calls));
#endif
- return strlen(buf);
+ return 0;
}
-#if 0
-/* XXX too much output - exceeds 4k limit and needs to be re-written */
static int
-sba_resource_map(char *buf, char **start, off_t offset, int len)
+sba_proc_open(struct inode *i, struct file *f)
+{
+ return single_open(f, &sba_proc_info, NULL);
+}
+
+static struct file_operations sba_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = sba_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int
+sba_proc_bitmap_info(struct seq_file *m, void *p)
{
struct sba_device *sba_dev = sba_list;
- struct ioc *ioc = &sba_dev->ioc[0]; /* FIXME: Mutli-IOC suppoer! */
+ struct ioc *ioc = &sba_dev->ioc[0]; /* FIXME: Multi-IOC support! */
unsigned int *res_ptr = (unsigned int *)ioc->res_map;
- int i;
+ int i, len = 0;
- buf[0] = '\0';
- for(i = 0; i < (ioc->res_size / sizeof(unsigned int)); ++i, ++res_ptr) {
+ for (i = 0; i < (ioc->res_size/sizeof(unsigned int)); ++i, ++res_ptr) {
if ((i & 7) == 0)
- strcat(buf,"\n ");
- sprintf(buf, "%s %08x", buf, *res_ptr);
+ len += seq_printf(m, "\n ");
+ len += seq_printf(m, " %08x", *res_ptr);
}
- strcat(buf, "\n");
+ len += seq_printf(m, "\n");
- return strlen(buf);
+ return 0;
}
-#endif /* 0 */
+
+static int
+sba_proc_bitmap_open(struct inode *i, struct file *f)
+{
+ return single_open(f, &sba_proc_bitmap_info, NULL);
+}
+
+static struct file_operations sba_proc_bitmap_fops = {
+ .owner = THIS_MODULE,
+ .open = sba_proc_bitmap_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif /* CONFIG_PROC_FS */
static struct parisc_device_id sba_tbl[] = {
u32 func_class;
int i;
char *version;
- void __iomem *sba_addr = ioremap(dev->hpa, SBA_FUNC_SIZE);
+ void __iomem *sba_addr = ioremap_nocache(dev->hpa.start, SBA_FUNC_SIZE);
+ struct proc_dir_entry *info_entry, *bitmap_entry, *root;
sba_dump_ranges(sba_addr);
/* Read HW Rev First */
func_class = READ_REG(sba_addr + SBA_FCLASS);
- if (IS_ASTRO(&dev->id)) {
+ if (IS_ASTRO(dev)) {
unsigned long fclass;
static char astro_rev[]="Astro ?.?";
astro_rev[8] = '0' + (char) ((fclass & 0x18) >> 3);
version = astro_rev;
- } else if (IS_IKE(&dev->id)) {
+ } else if (IS_IKE(dev)) {
static char ike_rev[] = "Ike rev ?";
ike_rev[8] = '0' + (char) (func_class & 0xff);
version = ike_rev;
- } else if (IS_PLUTO(&dev->id)) {
+ } else if (IS_PLUTO(dev)) {
static char pluto_rev[]="Pluto ?.?";
pluto_rev[6] = '0' + (char) ((func_class & 0xf0) >> 4);
pluto_rev[8] = '0' + (char) (func_class & 0x0f);
global_ioc_cnt = count_parisc_driver(&sba_driver);
/* Astro and Pluto have one IOC per SBA */
- if ((!IS_ASTRO(&dev->id)) || (!IS_PLUTO(&dev->id)))
+ if ((!IS_ASTRO(dev)) || (!IS_PLUTO(dev)))
global_ioc_cnt *= 2;
}
printk(KERN_INFO "%s found %s at 0x%lx\n",
- MODULE_NAME, version, dev->hpa);
+ MODULE_NAME, version, dev->hpa.start);
- sba_dev = kmalloc(sizeof(struct sba_device), GFP_KERNEL);
+ sba_dev = kzalloc(sizeof(struct sba_device), GFP_KERNEL);
if (!sba_dev) {
printk(KERN_ERR MODULE_NAME " - couldn't alloc sba_device\n");
return -ENOMEM;
}
parisc_set_drvdata(dev, 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->dev = dev;
sba_dev->hw_rev = func_class;
- sba_dev->iodc = &dev->id;
sba_dev->name = dev->name;
sba_dev->sba_hpa = sba_addr;
hppa_dma_ops = &sba_ops;
#ifdef CONFIG_PROC_FS
- if (IS_ASTRO(&dev->id)) {
- create_proc_info_entry("Astro", 0, proc_runway_root, sba_proc_info);
- } else if (IS_IKE(&dev->id)) {
- create_proc_info_entry("Ike", 0, proc_runway_root, sba_proc_info);
- } else if (IS_PLUTO(&dev->id)) {
- create_proc_info_entry("Pluto", 0, proc_mckinley_root, sba_proc_info);
- } else {
- create_proc_info_entry("Reo", 0, proc_runway_root, sba_proc_info);
+ switch (dev->id.hversion) {
+ case PLUTO_MCKINLEY_PORT:
+ root = proc_mckinley_root;
+ break;
+ case ASTRO_RUNWAY_PORT:
+ case IKE_MERCED_PORT:
+ default:
+ root = proc_runway_root;
+ break;
}
-#if 0
- create_proc_info_entry("bitmap", 0, proc_runway_root, sba_resource_map);
-#endif
+
+ info_entry = create_proc_entry("sba_iommu", 0, root);
+ bitmap_entry = create_proc_entry("sba_iommu-bitmap", 0, root);
+
+ if (info_entry)
+ info_entry->proc_fops = &sba_proc_fops;
+
+ if (bitmap_entry)
+ bitmap_entry->proc_fops = &sba_proc_bitmap_fops;
#endif
+
parisc_vmerge_boundary = IOVP_SIZE;
parisc_vmerge_max_size = IOVP_SIZE * BITS_PER_LONG;
parisc_has_iommu();
int i;
int rope = (pci_hba->hw_path & (ROPES_PER_IOC-1)); /* rope # */
- if ((t!=HPHW_IOA) && (t!=HPHW_BCPORT))
- BUG();
+ BUG_ON((t!=HPHW_IOA) && (t!=HPHW_BCPORT));
r->start = r->end = 0;
int base, size;
int rope = (pci_hba->hw_path & (ROPES_PER_IOC-1)); /* rope # */
- if ((t!=HPHW_IOA) && (t!=HPHW_BCPORT))
- BUG();
+ BUG_ON((t!=HPHW_IOA) && (t!=HPHW_BCPORT));
r->start = r->end = 0;