patch-2.4.20 linux-2.4.20/arch/parisc/kernel/lba_pci.c
Next file: linux-2.4.20/arch/parisc/kernel/led.c
Previous file: linux-2.4.20/arch/parisc/kernel/keyboard.c
Back to the patch index
Back to the overall index
- Lines: 1064
- Date:
Thu Nov 28 15:53:10 2002
- Orig file:
linux-2.4.19/arch/parisc/kernel/lba_pci.c
- Orig date:
Fri Feb 9 11:29:44 2001
diff -urN linux-2.4.19/arch/parisc/kernel/lba_pci.c linux-2.4.20/arch/parisc/kernel/lba_pci.c
@@ -34,6 +34,7 @@
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/init.h> /* for __init and __devinit */
+/* #define PCI_DEBUG enable ASSERT */
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/slab.h>
@@ -42,15 +43,13 @@
#include <asm/byteorder.h>
#include <asm/irq.h> /* for struct irq_region support */
#include <asm/pdc.h>
-#include <asm/pdcpat.h>
#include <asm/page.h>
#include <asm/segment.h>
#include <asm/system.h>
-#include <asm/hardware.h> /* for register_driver() stuff */
+#include <asm/hardware.h> /* for register_parisc_driver() stuff */
#include <asm/iosapic.h> /* for iosapic_register() */
-#include <asm/gsc.h> /* gsc_read/write stuff */
-
+#include <asm/io.h> /* read/write stuff */
#ifndef TRUE
#define TRUE (1 == 1)
@@ -62,6 +61,9 @@
#undef DEBUG_LBA_CFG /* debug Config Space Access (ie PCI Bus walk) */
#undef DEBUG_LBA_PAT /* debug PCI Resource Mgt code - PDC PAT only */
+#undef FBB_SUPPORT /* Fast Back-Back xfers - NOT READY YET */
+
+
#ifdef DEBUG_LBA
#define DBG(x...) printk(x)
#else
@@ -102,22 +104,6 @@
#define MODULE_NAME "lba"
-static int lba_driver_callback(struct hp_device *, struct pa_iodc_driver *);
-
-
-static struct pa_iodc_driver lba_drivers_for[]= {
-
- {HPHW_BRIDGE, 0x782, 0x0, 0xa, 0,0,
- DRIVER_CHECK_HVERSION +
- DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
- MODULE_NAME, "tbd", (void *) lba_driver_callback},
-
- {0,0,0,0,0,0,
- 0,
- (char *) NULL, (char *) NULL, (void *) NULL}
-};
-
-
#define LBA_FUNC_ID 0x0000 /* function id */
#define LBA_FCLASS 0x0008 /* function class, bist, header, rev... */
#define LBA_CAPABLE 0x0030 /* capabilities register */
@@ -137,6 +123,9 @@
#define LBA_MOD_ID 0x0100 /* Module ID. PDC_PAT_CELL reports 4 */
#define LBA_STAT_CTL 0x0108 /* Status & Control */
+#define LBA_BUS_RESET 0x01 /* Deassert PCI Bus Reset Signal */
+#define CLEAR_ERRLOG 0x10 /* "Clear Error Log" cmd */
+#define CLEAR_ERRLOG_ENABLE 0x20 /* "Clear Error Log" Enable */
#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */
#define LBA_LMMIO_BASE 0x0200 /* < 4GB I/O address range */
@@ -162,15 +151,18 @@
#define LBA_DMA_CTL 0x0278 /* firmware sets this */
-/* RESET: ignore DMA stuff until we can measure performance */
-#define LBA_IBASE 0x0300 /* DMA support */
+#define LBA_IBASE 0x0300 /* SBA DMA support */
#define LBA_IMASK 0x0308
+
+/* FIXME: ignore DMA Hint stuff until we can measure performance */
#define LBA_HINT_CFG 0x0310
#define LBA_HINT_BASE 0x0380 /* 14 registers at every 8 bytes. */
/* ERROR regs are needed for config cycle kluges */
#define LBA_ERROR_CONFIG 0x0680
+#define LBA_SMART_MODE 0x20
#define LBA_ERROR_STATUS 0x0688
+#define LBA_ROPE_CTL 0x06A0
#define LBA_IOSAPIC_BASE 0x800 /* Offset of IRQ logic */
@@ -232,19 +224,20 @@
* BE WARNED: register writes are posted.
* (ie follow writes which must reach HW with a read)
*/
-#define READ_U8(addr) gsc_readb(addr)
-#define READ_U16(addr) gsc_readw((u16 *) (addr))
-#define READ_U32(addr) gsc_readl((u32 *) (addr))
-#define WRITE_U8(value, addr) gsc_writeb(value, addr)
-#define WRITE_U16(value, addr) gsc_writew(value, (u16 *) (addr))
-#define WRITE_U32(value, addr) gsc_writel(value, (u32 *) (addr))
-
-#define READ_REG8(addr) gsc_readb(addr)
-#define READ_REG16(addr) le16_to_cpu(gsc_readw((u16 *) (addr)))
-#define READ_REG32(addr) le32_to_cpu(gsc_readl((u32 *) (addr)))
-#define WRITE_REG8(value, addr) gsc_writeb(value, addr)
-#define WRITE_REG16(value, addr) gsc_writew(cpu_to_le16(value), (u16 *) (addr))
-#define WRITE_REG32(value, addr) gsc_writel(cpu_to_le32(value), (u32 *) (addr))
+#define READ_U8(addr) __raw_readb(addr)
+#define READ_U16(addr) __raw_readw(addr)
+#define READ_U32(addr) __raw_readl(addr)
+#define WRITE_U8(value, addr) __raw_writeb(value, addr)
+#define WRITE_U16(value, addr) __raw_writew(value, addr)
+#define WRITE_U32(value, addr) __raw_writel(value, addr)
+
+#define READ_REG8(addr) readb(addr)
+#define READ_REG16(addr) readw(addr)
+#define READ_REG32(addr) readl(addr)
+#define READ_REG64(addr) readq(addr)
+#define WRITE_REG8(value, addr) writeb(value, addr)
+#define WRITE_REG16(value, addr) writew(value, addr)
+#define WRITE_REG32(value, addr) writel(value, addr)
#define LBA_CFG_TOK(bus,dfn) ((u32) ((bus)<<16 | (dfn)<<8))
@@ -253,25 +246,12 @@
#define LBA_CFG_FUNC(tok) ((u8) ((tok)>>8 ) & 0x7)
-#ifdef DEBUG_LBA
-/* Extract LBA (Rope) number from HPA */
-#define LBA_NUM(x) ((((uintptr_t) x) >> 13) & 0xf)
-#endif /* DEBUG_LBA */
-
-#ifdef __LP64__
-/* PDC_PAT */
-static unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0};
-#endif
-
/*
-** One time initialization to let the world know the LBA was found.
-** This is the only routine which is NOT static.
-** Must be called exactly once before pci_init().
+** Extract LBA (Rope) number from HPA
+** REVISIT: 16 ropes for Stretch/Ike?
*/
-void __init lba_init(void)
-{
- register_driver(lba_drivers_for);
-}
+#define ROPES_PER_SBA 8
+#define LBA_NUM(x) ((((unsigned long) x) >> 13) & (ROPES_PER_SBA-1))
static void
@@ -282,9 +262,9 @@
if (NULL == r)
return;
- printk("(%p)", r->parent);
+ printk(KERN_DEBUG "(%p)", r->parent);
for (i = d; i ; --i) printk(" ");
- printk("%p [%lx,%lx]/%x\n", r, r->start, r->end, (int) r->flags);
+ printk(KERN_DEBUG "%p [%lx,%lx]/%x\n", r, r->start, r->end, (int) r->flags);
lba_dump_res(r->child, d+2);
lba_dump_res(r->sibling, d);
}
@@ -369,7 +349,7 @@
* Set the smart mode bit so that master aborts don't cause \
* LBA to go into PCI fatal mode (required). \
*/ \
- WRITE_REG32(error_config | 0x20, d->hba.base_addr + LBA_ERROR_CONFIG); \
+ WRITE_REG32(error_config | LBA_SMART_MODE, d->hba.base_addr + LBA_ERROR_CONFIG); \
}
@@ -414,9 +394,9 @@
*
* Actually, there is still a race in which
* we could be clearing a fatal error. We will
- * live with this during our real mode bus walk
+ * live with this during our initial bus walk
* until rev 4.0 (no driver activity during
- * real mode bus walk). The real mode bus walk
+ * initial bus walk). The initial bus walk
* has race conditions concerning the use of
* smart mode as well.
*/
@@ -430,7 +410,7 @@
* Set clear enable (CE) bit. Unset by HW when new \
* errors are logged -- LBA HW ERS section 14.3.3). \
*/ \
- WRITE_REG32(status_control | 0x20, base + LBA_STAT_CTL); \
+ WRITE_REG32(status_control | CLEAR_ERRLOG_ENABLE, base + LBA_STAT_CTL); \
error_status = READ_REG32(base + LBA_ERROR_STATUS); \
if ((error_status & 0x1f) != 0) { \
/* \
@@ -442,7 +422,7 @@
* Clear error status (if fatal bit not set) by setting \
* clear error log bit (CL). \
*/ \
- WRITE_REG32(status_control | 0x10, base + LBA_STAT_CTL); \
+ WRITE_REG32(status_control | CLEAR_ERRLOG, base + LBA_STAT_CTL); \
} \
} \
}
@@ -483,7 +463,7 @@
static unsigned int
-lba_rd_cfg( struct lba_device *d, u32 tok, u8 reg, u32 size)
+lba_rd_cfg(struct lba_device *d, u32 tok, u8 reg, u32 size)
{
u32 data = ~0;
int error = 0;
@@ -525,7 +505,6 @@
}
-
#define LBA_CFG_RD(size, mask) \
static int lba_cfg_read##size (struct pci_dev *dev, int pos, u##size *data) \
{ \
@@ -533,17 +512,18 @@
u32 local_bus = (dev->bus->parent == NULL) ? 0 : dev->bus->secondary; \
u32 tok = LBA_CFG_TOK(local_bus,dev->devfn); \
\
- if ((!LBA_TR4PLUS(d)) && (!LBA_SKIP_PROBE(d))) { \
+/* FIXME: B2K/C3600 workaround is always use old method... */ \
+ /* if (!LBA_TR4PLUS(d) && !LBA_SKIP_PROBE(d)) */ { \
/* original - Generate config cycle on broken elroy \
with risk we will miss PCI bus errors. */ \
*data = (u##size) lba_rd_cfg(d, tok, pos, sizeof(u##size)); \
- DBG_CFG(KERN_DEBUG "%s(%s+%2x) -> 0x%x (a)\n", __FUNCTION__, dev->slot_name, pos, *data); \
+ DBG_CFG("%s(%s+%2x) -> 0x%x (a)\n", __FUNCTION__, dev->slot_name, pos, *data); \
return(*data == (u##size) -1); \
} \
\
if (LBA_SKIP_PROBE(d) && (!lba_device_present(dev->bus->secondary, dev->devfn, d))) \
{ \
- DBG_CFG(KERN_DEBUG "%s(%s+%2x) -> -1 (b)\n", __FUNCTION__, dev->slot_name, pos, *data); \
+ DBG_CFG("%s(%s+%2x) -> -1 (b)\n", __FUNCTION__, dev->slot_name, pos); \
/* either don't want to look or know device isn't present. */ \
*data = (u##size) -1; \
return(0); \
@@ -555,7 +535,7 @@
*/ \
LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); \
*data = READ_REG##size(d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & mask));\
- DBG_CFG(KERN_DEBUG "%s(%s+%2x) -> 0x%x (c)\n", __FUNCTION__, dev->slot_name, pos, *data);\
+ DBG_CFG("%s(%s+%2x) -> 0x%x (c)\n", __FUNCTION__, dev->slot_name, pos, *data);\
return(*data == (u##size) -1); \
}
@@ -618,19 +598,19 @@
ASSERT((tok & 0xff) == 0); \
ASSERT(pos < 0x100); \
\
- if ((!LBA_TR4PLUS(d)) && (!LBA_SKIP_PROBE(d))) { \
+ if (!LBA_TR4PLUS(d) && !LBA_SKIP_PROBE(d)) { \
/* Original Workaround */ \
lba_wr_cfg(d, tok, pos, (u32) data, sizeof(u##size)); \
- DBG_CFG(KERN_DEBUG "%s(%s+%2x) = 0x%x (a)\n", __FUNCTION__, dev->slot_name, pos, data); \
+ DBG_CFG("%s(%s+%2x) = 0x%x (a)\n", __FUNCTION__, dev->slot_name, pos, data); \
return 0; \
} \
\
if (LBA_SKIP_PROBE(d) && (!lba_device_present(dev->bus->secondary, dev->devfn, d))) { \
- DBG_CFG(KERN_DEBUG "%s(%s+%2x) = 0x%x (b)\n", __FUNCTION__, dev->slot_name, pos, data); \
+ DBG_CFG("%s(%s+%2x) = 0x%x (b)\n", __FUNCTION__, dev->slot_name, pos, data); \
return 1; /* New Workaround */ \
} \
\
- DBG_CFG(KERN_DEBUG "%s(%s+%2x) = 0x%x (c)\n", __FUNCTION__, dev->slot_name, pos, data); \
+ DBG_CFG("%s(%s+%2x) = 0x%x (c)\n", __FUNCTION__, dev->slot_name, pos, data); \
/* Basic Algorithm */ \
LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); \
WRITE_REG##size(data, d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & mask)); \
@@ -644,9 +624,12 @@
LBA_CFG_WR(32, 0)
static struct pci_ops lba_cfg_ops = {
- lba_cfg_read8, lba_cfg_read16, lba_cfg_read32,
- lba_cfg_write8, lba_cfg_write16, lba_cfg_write32
-
+ read_byte: lba_cfg_read8,
+ read_word: lba_cfg_read16,
+ read_dword: lba_cfg_read32,
+ write_byte: lba_cfg_write8,
+ write_word: lba_cfg_write16,
+ write_dword: lba_cfg_write32
};
@@ -654,7 +637,7 @@
static void
lba_bios_init(void)
{
- DBG(KERN_DEBUG MODULE_NAME ": lba_bios_init\n");
+ DBG(MODULE_NAME ": lba_bios_init\n");
}
@@ -712,15 +695,15 @@
lba_fixup_bus(struct pci_bus *bus)
{
struct list_head *ln;
- struct pci_dev *dev;
+#ifdef FBB_SUPPORT
u16 fbb_enable = PCI_STATUS_FAST_BACK;
u16 status;
- struct lba_device *ldev = LBA_DEV(bus->sysdata);
-#ifdef __LP64__
- int i;
#endif
+ struct lba_device *ldev = LBA_DEV(bus->sysdata);
+ int lba_portbase = HBA_PORT_BASE(ldev->hba.hba_num);
+
DBG("lba_fixup_bus(0x%p) bus %d sysdata 0x%p\n",
- bus, bus->secondary, bus->sysdata);
+ bus, bus->secondary, bus->sysdata);
/*
** Properly Setup MMIO resources for this bus.
@@ -731,63 +714,119 @@
DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n",
ldev->hba.io_space.name,
- ldev->hba.io_space.start,
- ldev->hba.io_space.end,
+ ldev->hba.io_space.start, ldev->hba.io_space.end,
(int) ldev->hba.io_space.flags);
DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n",
- ldev->hba.mem_space.name,
- ldev->hba.mem_space.start,
- ldev->hba.mem_space.end,
- (int) ldev->hba.mem_space.flags);
+ ldev->hba.lmmio_space.name,
+ ldev->hba.lmmio_space.start, ldev->hba.lmmio_space.end,
+ (int) ldev->hba.lmmio_space.flags);
err = request_resource(&ioport_resource, &(ldev->hba.io_space));
if (err < 0) {
BUG();
lba_dump_res(&ioport_resource, 2);
}
- err = request_resource(&iomem_resource, &(ldev->hba.mem_space));
+ err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space));
if (err < 0) {
BUG();
lba_dump_res(&iomem_resource, 2);
}
bus->resource[0] = &(ldev->hba.io_space);
- bus->resource[1] = &(ldev->hba.mem_space);
+ bus->resource[1] = &(ldev->hba.lmmio_space);
+ } else {
+ /* KLUGE ALERT!
+ ** PCI-PCI Bridge resource munging.
+ ** This hack should go away in the near future.
+ ** It's based on the Alpha port.
+ */
+ int i;
+ u16 cmd;
+
+ for (i = 0; i < 4; i++) {
+ bus->resource[i] =
+ &bus->self->resource[PCI_BRIDGE_RESOURCES+i];
+ bus->resource[i]->name = bus->name;
+ }
+#if 0
+ bus->resource[0]->flags |= pci_bridge_check_io(bus->self);
+#else
+ bus->resource[0]->flags |= IORESOURCE_IO;
+#endif
+ bus->resource[1]->flags |= IORESOURCE_MEM;
+ bus->resource[2]->flags = 0; /* Don't support prefetchable */
+ bus->resource[3]->flags = 0; /* not used */
+
+ /*
+ ** If the PPB is enabled (ie already configured) then
+ ** just read those values.
+ */
+ (void) lba_cfg_read16(bus->self, PCI_COMMAND, &cmd);
+ if (cmd & (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)) {
+ pci_read_bridge_bases(bus);
+ } else {
+ /* Not configured.
+ ** For now, propogate HBA limits to the bus;
+ ** PCI will adjust them later.
+ */
+ bus->resource[0]->end = ldev->hba.io_space.end;
+ bus->resource[1]->end = ldev->hba.lmmio_space.end;
+ }
+
+ /* Turn off downstream PF memory address range by default */
+ bus->resource[2]->start = 1024*1024;
+ bus->resource[2]->end = bus->resource[2]->start - 1;
}
- list_for_each(ln, &bus->devices) {
- dev = pci_dev_b(ln);
+ list_for_each(ln, &bus->devices) {
+ int i;
+ struct pci_dev *dev = pci_dev_b(ln);
-#ifdef __LP64__
- /*
- ** 0-5 are the "standard PCI regions"
- ** (see comments near PCI_NUM_RESOURCES in include/linux/pci.h)
- */
- for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
- struct resource *res = &(dev->resource[i]);
+ DBG("lba_fixup_bus() %s\n", dev->name);
- if (res->flags & IORESOURCE_MEM) {
- /* "Globalize" PCI address */
- res->start |= ldev->lmmio_base;
- res->end |= ldev->lmmio_base;
+ /* Virtualize Device/Bridge Resources. */
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ struct resource *res = &dev->resource[i];
+
+ /* If resource not allocated - skip it */
+ if (!res->start)
+ continue;
+
+ if (res->flags & IORESOURCE_IO) {
+ DBG("lba_fixup_bus() I/O Ports [%lx/%lx] -> ",
+ res->start, res->end);
+ res->start |= lba_portbase;
+ res->end |= lba_portbase;
+ DBG("[%lx/%lx]\n", res->start, res->end);
+ } else if (res->flags & IORESOURCE_MEM) {
+ /*
+ ** Convert PCI (IO_VIEW) addresses to
+ ** processor (PA_VIEW) addresses
+ */
+ DBG("lba_fixup_bus() MMIO [%lx/%lx] -> ",
+ res->start, res->end);
+ res->start = PCI_HOST_ADDR(HBA_DATA(ldev), res->start);
+ res->end = PCI_HOST_ADDR(HBA_DATA(ldev), res->end);
+ DBG("[%lx/%lx]\n", res->start, res->end);
}
}
-#endif
+#ifdef FBB_SUPPORT
/*
** If one device does not support FBB transfers,
** No one on the bus can be allowed to use them.
*/
(void) lba_cfg_read16(dev, PCI_STATUS, &status);
fbb_enable &= status;
+#endif
#ifdef __LP64__
- if (pdc_pat) {
+ if (is_pdc_pat()) {
/* Claim resources for PDC's devices */
lba_claim_dev_resources(dev);
}
-#endif /* __LP64__ */
+#endif
/*
** P2PB's have no IRQs. ignore them.
@@ -796,12 +835,12 @@
continue;
/* Adjust INTERRUPT_LINE for this dev */
- iosapic_fixup_irq(LBA_DEV(bus->sysdata)->iosapic_obj, dev);
+ iosapic_fixup_irq(ldev->iosapic_obj, dev);
}
-#if 0
+#ifdef FBB_SUPPORT
/* FIXME/REVISIT - finish figuring out to set FBB on both
-** pbus_set_ranges() clobbers PCI_BRIDGE_CONTROL.
+** pci_setup_bridge() clobbers PCI_BRIDGE_CONTROL.
** Can't fixup here anyway....garr...
*/
if (fbb_enable) {
@@ -828,8 +867,8 @@
struct pci_bios_ops lba_bios_ops = {
- lba_bios_init,
- lba_fixup_bus /* void lba_fixup_bus(struct pci_bus *bus) */
+ init: lba_bios_init,
+ fixup_bus: lba_fixup_bus,
};
@@ -853,8 +892,6 @@
static u##size lba_astro_in##size (struct pci_hba_data *d, u16 addr) \
{ \
u##size t; \
- ASSERT(bus != NULL); \
- DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x) ->", __FUNCTION__, bus, addr); \
t = READ_REG##size(LBA_ASTRO_PORT_BASE + addr); \
DBG_PORT(" 0x%x\n", t); \
return (t); \
@@ -895,8 +932,8 @@
#define LBA_PORT_OUT(size, mask) \
static void lba_astro_out##size (struct pci_hba_data *d, u16 addr, u##size val) \
{ \
- ASSERT(bus != NULL); \
- DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, d, addr, val); \
+ ASSERT(d != NULL); \
+ DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, d, addr, val); \
WRITE_REG##size(val, LBA_ASTRO_PORT_BASE + addr); \
if (LBA_DEV(d)->hw_rev < 3) \
lba_t32 = READ_U32(d->base_addr + LBA_FUNC_ID); \
@@ -908,13 +945,16 @@
static struct pci_port_ops lba_astro_port_ops = {
- lba_astro_in8, lba_astro_in16, lba_astro_in32,
- lba_astro_out8, lba_astro_out16, lba_astro_out32
+ inb: lba_astro_in8,
+ inw: lba_astro_in16,
+ inl: lba_astro_in32,
+ outb: lba_astro_out8,
+ outw: lba_astro_out16,
+ outl: lba_astro_out32
};
#ifdef __LP64__
-
#define PIOP_TO_GMMIO(lba, addr) \
((lba)->iop_base + (((addr)&0xFFFC)<<10) + ((addr)&3))
@@ -936,7 +976,7 @@
{ \
u##size t; \
ASSERT(bus != NULL); \
- DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x) ->", __FUNCTION__, l, addr); \
+ DBG_PORT("%s(0x%p, 0x%x) ->", __FUNCTION__, l, addr); \
t = READ_REG##size(PIOP_TO_GMMIO(LBA_DEV(l), addr)); \
DBG_PORT(" 0x%x\n", t); \
return (t); \
@@ -953,7 +993,7 @@
{ \
void *where = (void *) PIOP_TO_GMMIO(LBA_DEV(l), addr); \
ASSERT(bus != NULL); \
- DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, l, addr, val); \
+ DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, l, addr, val); \
WRITE_REG##size(val, where); \
/* flush the I/O down to the elroy at least */ \
lba_t32 = READ_U32(l->base_addr + LBA_FUNC_ID); \
@@ -965,8 +1005,12 @@
static struct pci_port_ops lba_pat_port_ops = {
- lba_pat_in8, lba_pat_in16, lba_pat_in32,
- lba_pat_out8, lba_pat_out16, lba_pat_out32
+ inb: lba_pat_in8,
+ inw: lba_pat_in16,
+ inl: lba_pat_in32,
+ outb: lba_pat_out8,
+ outw: lba_pat_out16,
+ outl: lba_pat_out32
};
@@ -978,30 +1022,27 @@
** We don't have a struct pci_bus assigned to us yet.
*/
static void
-lba_pat_resources( struct hp_device *d, struct lba_device *lba_dev)
+lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
{
+ unsigned long bytecnt;
pdc_pat_cell_mod_maddr_block_t pa_pdc_cell; /* PA_VIEW */
-#ifdef DONT_NEED_THIS_FOR_ASTRO
pdc_pat_cell_mod_maddr_block_t io_pdc_cell; /* IO_VIEW */
long io_count;
-#endif
long status; /* PDC return status */
long pa_count;
int i;
/* return cell module (IO view) */
- status = pdc_pat_cell_module(& pdc_result, d->pcell_loc, d->mod_index,
+ status = pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index,
PA_VIEW, & pa_pdc_cell);
pa_count = pa_pdc_cell.mod[1];
-#ifdef DONT_NEED_THIS_FOR_ASTRO
- status |= pdc_pat_cell_module(& pdc_result, d->pcell_loc, d->mod_index,
- IO_VIEW, & io_pdc_cell);
+ status |= pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index,
+ IO_VIEW, &io_pdc_cell);
io_count = io_pdc_cell.mod[1];
-#endif
/* We've already done this once for device discovery...*/
- if (status != PDC_RET_OK) {
+ if (status != PDC_OK) {
panic("pdc_pat_cell_module() call failed for LBA!\n");
}
@@ -1017,10 +1058,11 @@
unsigned long type;
unsigned long start;
unsigned long end; /* aka finish */
- } *p;
+ } *p, *io;
struct resource *r;
p = (void *) &(pa_pdc_cell.mod[2+i*3]);
+ io = (void *) &(io_pdc_cell.mod[2+i*3]);
/* Convert the PAT range data to PCI "struct resource" */
switch(p->type & 0xff) {
@@ -1030,9 +1072,9 @@
break;
case PAT_LMMIO:
/* used to fix up pre-initialized MEM BARs */
- lba_dev->lmmio_base = p->start;
+ lba_dev->hba.lmmio_space_offset = p->start - io->start;
- r = &(lba_dev->hba.mem_space);
+ r = &(lba_dev->hba.lmmio_space);
r->name = "LBA LMMIO";
r->start = p->start;
r->end = p->end;
@@ -1060,8 +1102,8 @@
r = &(lba_dev->hba.io_space);
r->name = "LBA I/O Port";
- r->start = lba_dev->hba.hba_num << 16;
- r->end = r->start + 0xffffUL;
+ r->start = HBA_PORT_BASE(lba_dev->hba.hba_num);
+ r->end = r->start + HBA_PORT_SPACE_SIZE - 1;
r->flags = IORESOURCE_IO;
r->parent = r->sibling = r->child = NULL;
break;
@@ -1077,17 +1119,22 @@
static void
-lba_legacy_resources( struct hp_device *d, struct lba_device *lba_dev)
+lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
{
- int lba_num;
struct resource *r;
+ unsigned long rsize;
+ int lba_num;
+
#ifdef __LP64__
/*
- ** Used to sign extend instead BAR values are only 32-bit.
- ** 64-bit BARs have the upper 32-bit's zero'd by firmware.
- ** "Sprockets" PDC initializes for 32-bit OS.
+ ** Sign extend all BAR values on "legacy" platforms.
+ ** "Sprockets" PDC (Forte/Allegro) initializes everything
+ ** for "legacy" 32-bit OS (HPUX 10.20).
+ ** Upper 32-bits of 64-bit BAR will be zero too.
*/
- lba_dev->lmmio_base = 0xffffffff00000000UL;
+ lba_dev->hba.lmmio_space_offset = 0xffffffff00000000UL;
+#else
+ lba_dev->hba.lmmio_space_offset = 0UL;
#endif
/*
@@ -1097,7 +1144,7 @@
** PCI bus walk *should* end up with the same result.
** FIXME: But we don't have sanity checks in PCI or LBA.
*/
- lba_num = READ_REG32(d->hpa + LBA_FW_SCRATCH);
+ lba_num = READ_REG32(pa_dev->hpa + LBA_FW_SCRATCH);
r = &(lba_dev->hba.bus_num);
r->name = "LBA PCI Busses";
r->start = lba_num & 0xff;
@@ -1106,19 +1153,67 @@
/* Set up local PCI Bus resources - we don't really need
** them for Legacy boxes but it's nice to see in /proc.
*/
- r = &(lba_dev->hba.mem_space);
+ r = &(lba_dev->hba.lmmio_space);
r->name = "LBA PCI LMMIO";
r->flags = IORESOURCE_MEM;
- r->start = READ_REG32(d->hpa + LBA_LMMIO_BASE);
- r->end = r->start + ~ (READ_REG32(d->hpa + LBA_LMMIO_MASK));
+ /* Ignore "Range Enable" bit in the BASE register */
+ r->start = PCI_HOST_ADDR(HBA_DATA(lba_dev),
+ ((long) READ_REG32(pa_dev->hpa + LBA_LMMIO_BASE)) & ~1UL);
+ rsize = ~READ_REG32(pa_dev->hpa + LBA_LMMIO_MASK) + 1;
+
+ /*
+ ** Each rope only gets part of the distributed range.
+ ** Adjust "window" for this rope
+ */
+ rsize /= ROPES_PER_SBA;
+ r->start += rsize * LBA_NUM(pa_dev->hpa);
+ r->end = r->start + rsize - 1 ;
+
+ /*
+ ** XXX FIXME - ignore LBA_ELMMIO_BASE for now
+ ** "Directed" ranges are used when the "distributed range" isn't
+ ** sufficient for all devices below a given LBA. Typically devices
+ ** like graphics cards or X25 may need a directed range when the
+ ** bus has multiple slots (ie multiple devices) or the device
+ ** needs more than the typical 4 or 8MB a distributed range offers.
+ **
+ ** The main reason for ignoring it now frigging complications.
+ ** Directed ranges may overlap (and have precedence) over
+ ** distributed ranges. Ie a distributed range assigned to a unused
+ ** rope may be used by a directed range on a different rope.
+ ** Support for graphics devices may require fixing this
+ ** since they may be assigned a directed range which overlaps
+ ** an existing (but unused portion of) distributed range.
+ */
+ r = &(lba_dev->hba.elmmio_space);
+ r->name = "extra LBA PCI LMMIO";
+ r->flags = IORESOURCE_MEM;
+ r->start = READ_REG32(pa_dev->hpa + LBA_ELMMIO_BASE);
+ r->end = 0;
+
+ /* check Range Enable bit */
+ if (r->start & 1) {
+ /* First baby step to getting Direct Ranges listed in /proc.
+ ** AFAIK, only Sprockets PDC will setup a directed Range.
+ */
+
+ r->start &= ~1;
+ r->end = r->start;
+ r->end += ~READ_REG32(pa_dev->hpa + LBA_ELMMIO_MASK);
+ printk(KERN_DEBUG "WARNING: Ignoring enabled ELMMIO BASE 0x%0lx SIZE 0x%lx\n",
+ r->start,
+ r->end + 1);
+
+ }
r = &(lba_dev->hba.io_space);
r->name = "LBA PCI I/O Ports";
r->flags = IORESOURCE_IO;
- r->start = READ_REG32(d->hpa + LBA_IOS_BASE);
- r->end = r->start + (READ_REG32(d->hpa + LBA_IOS_MASK) ^ 0xffff);
+ r->start = READ_REG32(pa_dev->hpa + LBA_IOS_BASE) & ~1L;
+ r->end = r->start + (READ_REG32(pa_dev->hpa + LBA_IOS_MASK) ^ (HBA_PORT_SPACE_SIZE - 1));
- lba_num = lba_dev->hba.hba_num << 16;
+ /* Virtualize the I/O Port space ranges */
+ lba_num = HBA_PORT_BASE(lba_dev->hba.hba_num);
r->start |= lba_num;
r->end |= lba_num;
}
@@ -1136,29 +1231,92 @@
**
**************************************************************************/
-static void
+static int __init
lba_hw_init(struct lba_device *d)
{
u32 stat;
+ u32 bus_reset; /* PDC_PAT_BUG */
+
+#if 0
+ printk(KERN_DEBUG "LBA %lx STAT_CTL %Lx ERROR_CFG %Lx STATUS %Lx DMA_CTL %Lx\n",
+ d->hba.base_addr,
+ READ_REG64(d->hba.base_addr + LBA_STAT_CTL),
+ READ_REG64(d->hba.base_addr + LBA_ERROR_CONFIG),
+ READ_REG64(d->hba.base_addr + LBA_ERROR_STATUS),
+ READ_REG64(d->hba.base_addr + LBA_DMA_CTL) );
+ printk(KERN_DEBUG " ARB mask %Lx pri %Lx mode %Lx mtlt %Lx\n",
+ READ_REG64(d->hba.base_addr + LBA_ARB_MASK),
+ READ_REG64(d->hba.base_addr + LBA_ARB_PRI),
+ READ_REG64(d->hba.base_addr + LBA_ARB_MODE),
+ READ_REG64(d->hba.base_addr + LBA_ARB_MTLT) );
+ printk(KERN_DEBUG " HINT cfg 0x%Lx\n",
+ READ_REG64(d->hba.base_addr + LBA_HINT_CFG));
+ printk(KERN_DEBUG " HINT reg ");
+ { int i;
+ for (i=LBA_HINT_BASE; i< (14*8 + LBA_HINT_BASE); i+=8)
+ printk(" %Lx", READ_REG64(d->hba.base_addr + i));
+ }
+ printk("\n");
+#endif /* DEBUG_LBA_PAT */
+
+#ifdef __LP64__
+#warning FIXME add support for PDC_PAT_IO "Get slot status" - OLAR support
+#endif
+
+ /* PDC_PAT_BUG: exhibited in rev 40.48 on L2000 */
+ bus_reset = READ_REG32(d->hba.base_addr + LBA_STAT_CTL + 4) & 1;
+ if (bus_reset) {
+ printk(KERN_DEBUG "NOTICE: PCI bus reset still asserted! (clearing)\n");
+ }
+
+ stat = READ_REG32(d->hba.base_addr + LBA_ERROR_CONFIG);
+ if (stat & LBA_SMART_MODE) {
+ printk(KERN_DEBUG "NOTICE: LBA in SMART mode! (cleared)\n");
+ stat &= ~LBA_SMART_MODE;
+ WRITE_REG32(stat, d->hba.base_addr + LBA_ERROR_CONFIG);
+ }
/* Set HF mode as the default (vs. -1 mode). */
stat = READ_REG32(d->hba.base_addr + LBA_STAT_CTL);
WRITE_REG32(stat | HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL);
/*
+ ** Writing a zero to STAT_CTL.rf (bit 0) will clear reset signal
+ ** if it's not already set. If we just cleared the PCI Bus Reset
+ ** signal, wait a bit for the PCI devices to recover and setup.
+ */
+ if (bus_reset)
+ mdelay(pci_post_reset_delay);
+
+ if (0 == READ_REG32(d->hba.base_addr + LBA_ARB_MASK)) {
+ /*
+ ** PDC_PAT_BUG: PDC rev 40.48 on L2000.
+ ** B2000/C3600/J6000 also have this problem?
+ **
+ ** Elroys with hot pluggable slots don't get configured
+ ** correctly if the slot is empty. ARB_MASK is set to 0
+ ** and we can't master transactions on the bus if it's
+ ** not at least one. 0x3 enables elroy and first slot.
+ */
+ printk(KERN_DEBUG "NOTICE: Enabling PCI Arbitration\n");
+ WRITE_REG32(0x3, d->hba.base_addr + LBA_ARB_MASK);
+ }
+
+ /*
** FIXME: Hint registers are programmed with default hint
** values by firmware. Hints should be sane even if we
** can't reprogram them the way drivers want.
*/
+ return 0;
}
-static void
+static void __init
lba_common_init(struct lba_device *lba_dev)
{
pci_bios = &lba_bios_ops;
- pcibios_register_hba((struct pci_hba_data *)lba_dev);
+ pcibios_register_hba(HBA_DATA(lba_dev));
lba_dev->lba_lock = SPIN_LOCK_UNLOCKED;
/*
@@ -1176,32 +1334,31 @@
** If so, initialize the chip and tell other partners in crime they
** have work to do.
*/
-static __init int
-lba_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri)
+static int __init
+lba_driver_callback(struct parisc_device *dev)
{
struct lba_device *lba_dev;
struct pci_bus *lba_bus;
u32 func_class;
void *tmp_obj;
-
- /* from drivers/pci/setup-bus.c */
- extern void __init pbus_set_ranges(struct pci_bus *, struct pbus_set_ranges_data *);
+ char *version;
/* Read HW Rev First */
- func_class = READ_REG32(d->hpa + LBA_FCLASS);
+ func_class = READ_REG32(dev->hpa + LBA_FCLASS);
func_class &= 0xf;
switch (func_class) {
- case 0: dri->version = "TR1.0"; break;
- case 1: dri->version = "TR2.0"; break;
- case 2: dri->version = "TR2.1"; break;
- case 3: dri->version = "TR2.2"; break;
- case 4: dri->version = "TR3.0"; break;
- case 5: dri->version = "TR4.0"; break;
- default: dri->version = "TR4+";
+ case 0: version = "TR1.0"; break;
+ case 1: version = "TR2.0"; break;
+ case 2: version = "TR2.1"; break;
+ case 3: version = "TR2.2"; break;
+ case 4: version = "TR3.0"; break;
+ case 5: version = "TR4.0"; break;
+ default: version = "TR4+";
}
- printk("%s version %s (0x%x) found at 0x%p\n", dri->name, dri->version, func_class & 0xf, d->hpa);
+ printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n",
+ MODULE_NAME, version, func_class & 0xf, dev->hpa);
/* Just in case we find some prototypes... */
if (func_class < 2) {
@@ -1212,22 +1369,16 @@
/*
** Tell I/O SAPIC driver we have a IRQ handler/region.
*/
- tmp_obj = iosapic_register(d->hpa+LBA_IOSAPIC_BASE);
- 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 says not used\n");
- return (1);
- }
+ tmp_obj = iosapic_register(dev->hpa + LBA_IOSAPIC_BASE);
+ /* 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)
{
- printk("lba_init_chip - couldn't alloc lba_device\n");
+ printk(KERN_ERR "lba_init_chip - couldn't alloc lba_device\n");
return(1);
}
@@ -1242,48 +1393,45 @@
*/
lba_dev->hw_rev = func_class;
- lba_dev->hba.base_addr = d->hpa; /* faster access */
+ lba_dev->hba.base_addr = dev->hpa; /* faster access */
+ lba_dev->hba.dev = dev;
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);
- lba_hw_init(lba_dev);
+
+ if (lba_hw_init(lba_dev))
+ return(1);
/* ---------- Third : setup I/O Port and MMIO resources --------- */
-#ifdef __LP64__
- if (pdc_pat) {
+#ifdef __LP64__
+ if (is_pdc_pat()) {
/* PDC PAT firmware uses PIOP region of GMMIO space. */
pci_port = &lba_pat_port_ops;
/* Go ask PDC PAT what resources this LBA has */
- lba_pat_resources(d, lba_dev);
-
- } else {
+ lba_pat_resources(dev, lba_dev);
+ } else
#endif
+ {
/* Sprockets PDC uses NPIOP region */
pci_port = &lba_astro_port_ops;
/* Poke the chip a bit for /proc output */
- lba_legacy_resources(d, lba_dev);
-#ifdef __LP64__
+ lba_legacy_resources(dev, lba_dev);
}
-#endif
/*
** Tell PCI support another PCI bus was found.
** Walks PCI bus for us too.
*/
lba_bus = lba_dev->hba.hba_bus =
- pci_scan_bus( lba_dev->hba.bus_num.start, &lba_cfg_ops, (void *) lba_dev);
+ pci_scan_bus(lba_dev->hba.bus_num.start, &lba_cfg_ops, (void *) lba_dev);
#ifdef __LP64__
- if (pdc_pat) {
-
- /* determine window sizes needed by PCI-PCI bridges */
- DBG_PAT("LBA pcibios_size_bridge()\n");
- pcibios_size_bridge(lba_bus, NULL);
-
+ if (is_pdc_pat()) {
/* assign resources to un-initialized devices */
DBG_PAT("LBA pcibios_assign_unassigned_resources()\n");
pcibios_assign_unassigned_resources(lba_bus);
@@ -1292,14 +1440,10 @@
DBG_PAT("\nLBA PIOP resource tree\n");
lba_dump_res(&lba_dev->hba.io_space, 2);
DBG_PAT("\nLBA LMMIO resource tree\n");
- lba_dump_res(&lba_dev->hba.mem_space, 2);
+ lba_dump_res(&lba_dev->hba.lmmio_space, 2);
#endif
-
- /* program *all* PCI-PCI bridge range registers */
- DBG_PAT("LBA pbus_set_ranges()\n");
- pbus_set_ranges(lba_bus, NULL);
}
-#endif /* __LP64__ */
+#endif
/*
** Once PCI register ops has walked the bus, access to config
@@ -1314,33 +1458,43 @@
return 0;
}
+static struct parisc_device_id lba_tbl[] = {
+ { HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x782, 0xa },
+ { 0, }
+};
+
+static struct parisc_driver lba_driver = {
+ name: MODULE_NAME,
+ id_table: lba_tbl,
+ probe: lba_driver_callback
+};
+
+/*
+** One time initialization to let the world know the LBA was found.
+** Must be called exactly once before pci_init().
+*/
+void __init lba_init(void)
+{
+ register_parisc_driver(&lba_driver);
+}
/*
** Initialize the IBASE/IMASK registers for LBA (Elroy).
-** Only called from sba_iommu.c initialization sequence.
+** Only called from sba_iommu.c in order to route ranges (MMIO vs DMA).
+** sba_iommu is responsible for locking (none needed at init time).
*/
-void lba_init_iregs(void *sba_hpa, u32 ibase, u32 imask)
+void
+lba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask)
{
- extern struct pci_hba_data *hba_list; /* arch/parisc/kernel/pci.c */
- struct pci_hba_data *lba;
+ unsigned long base_addr = lba->hpa;
imask <<= 2; /* adjust for hints - 2 more bits */
ASSERT((ibase & 0x003fffff) == 0);
ASSERT((imask & 0x003fffff) == 0);
- /* FIXME: sba_hpa is intended to search some table to
- ** determine which LBA's belong to the caller's SBA.
- ** IS_ASTRO: just assume only one SBA for now.
- */
- ASSERT(NULL != hba_list);
- DBG(KERN_DEBUG "%s() ibase 0x%x imask 0x%x\n", __FUNCTION__, ibase, imask);
-
- for (lba = hba_list; NULL != lba; lba = lba->next) {
- DBG(KERN_DEBUG "%s() base_addr %p\n", __FUNCTION__, lba->base_addr);
- WRITE_REG32( imask, lba->base_addr + LBA_IMASK);
- WRITE_REG32( ibase, lba->base_addr + LBA_IBASE);
- }
- DBG(KERN_DEBUG "%s() done\n", __FUNCTION__);
+ DBG("%s() ibase 0x%x imask 0x%x\n", __FUNCTION__, ibase, imask);
+ WRITE_REG32( imask, base_addr + LBA_IMASK);
+ WRITE_REG32( ibase, base_addr + LBA_IBASE);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)