[parisc-linux-cvs] [PATCH] PCI LMMIO mapping

Bjorn Helgaas bjorn_helgaas@hp.com
Wed, 12 Sep 2001 17:15:08 -0600


This is an aged, somewhat better tested, and somewhat cleaned up version 
of the patch I posted earlier (5/21/01).  It is most of what is required 
to run on Superdome and should help on N-class as well.

I'd like to commit these changes soon, and I'd appreciate any comments.

  - clean up CPU physical <-> PCI address mapping
  - use current cell for iosapic_load_irt (allows non-zero cell number)
  - rename mem_space to lmmio_space
  - handle initrd loaded above mem= limit
  - new map_pages() to unify page table setup
  - new hardware HVERSIONs (Caribe W2, Caribe DNA, Allegro W+, Keystone & 
Caribe memory)
  - fix link errors when CONFIG_VT not defined
  - correct a few typos (REDICULOUSLY_VERBOSE, Priviledged)

The first one is most important.  For boxes with PAT firmware, we
previously did not ask firmware what the IO_VIEW range for a module
was, we could support only trivial mappings between the CPU physical
address range and the PCI address range.  Larger machines like N-class
and Superdome use non-trivial mappings, and this limitation is a big
reason why we can't run on them yet.

The mapping is always linear (on 32-bit boxes, 64-bit boxes with
legacy firmware, and 64-bit boxes with PAT firmware), so I just added
an offset between the CPU view and the PCI view.  For PAT firmware,
the offset is gotten from firmware; for others, it is hard-coded as it
was before.  The new PCI_BUS_ADDR() and PCI_HOST_ADDR() macros apply
the offset to convert from CPU to PCI addresses and PCI to CPU
addresses, respectively.

Tested platforms:
    Superdome (requires additional patches not included here)
    A500
    C3000 32-bit kernel
    C3000 64-bit kernel
    C3600 64-bit kernel (also requires add'l patches)



Index: arch/parisc/kernel/hardware.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/hardware.c,v
retrieving revision 1.25
diff -u -p -r1.25 hardware.c
--- hardware.c	2001/09/05 12:46:45	1.25
+++ hardware.c	2001/09/12 22:35:43
@@ -206,7 +206,7 @@ static struct hp_hardware hp_hardware_li
 	{HPHW_NPROC,0x5B8,0x4,0x91,"SPP2250 240 MHz"},
 	{HPHW_NPROC,0x5B9,0x4,0x81,"UL 1w U+/240 (350/550)"},
 	{HPHW_NPROC,0x5BA,0x4,0x91,"UL 2w U+/240 (350/550)"},
-	{HPHW_NPROC,0x5BB,0x4,0x81,"AllegroHigh W "},
+	{HPHW_NPROC,0x5BB,0x4,0x81,"AllegroHigh W"},
 	{HPHW_NPROC,0x5BC,0x4,0x91,"AllegroLow W"},
 	{HPHW_NPROC,0x5BD,0x4,0x91,"Forte W 2-way"},
 	{HPHW_NPROC,0x5BE,0x4,0x91,"Prelude W"},
@@ -240,6 +240,7 @@ static struct hp_hardware hp_hardware_li
 	{HPHW_NPROC,0x5DA,0x4,0x91,"Marcato W+ DC-"},
 	{HPHW_NPROC,0x5DB,0x4,0x91,"Marcato W+"},
 	{HPHW_NPROC,0x5DE,0x4,0x81,"Piccolo W+"},
+	{HPHW_NPROC,0x5E7,0x4,0x91,"Caribe W2 800"},
 	{HPHW_NPROC,0x5FF,0x4,0x91,"Hitachi W"},
 	{HPHW_NPROC,0x600,0x4,0x81,"Gecko (712/60)"},
 	{HPHW_NPROC,0x601,0x4,0x81,"Gecko 80 (712/80)"},
@@ -574,6 +575,7 @@ static struct hp_hardware hp_hardware_li
 	{HPHW_CONSOLE, 0x01A, 0x0001F, 0x00, "Jason/Anole 64 Null Console"}, 
 	{HPHW_CONSOLE, 0x01B, 0x0001F, 0x00, "Jason/Anole 100 Null Console"}, 
 	{HPHW_FABRIC, 0x004, 0x000AA, 0x80, "Halfdome DNA Central Agent"}, 
+	{HPHW_FABRIC, 0x007, 0x000AA, 0x80, "Caribe DNA Central Agent"}, 
 	{HPHW_FABRIC, 0x004, 0x000AB, 0x00, "Halfdome TOGO Fabric Crossbar"}, 
 	{HPHW_FABRIC, 0x004, 0x000AC, 0x00, "Halfdome Sakura Fabric Router"}, 
 	{HPHW_FIO, 0x025, 0x0002E, 0x80, "Armyknife Optional X.25"}, 
@@ -1313,6 +1315,7 @@ static struct hp_hardware hp_hardware_li
 	{HPHW_MEMORY, 0x08B, 0x00009, 0x00, "Staccato L2 180 Memory"}, 
 	{HPHW_MEMORY, 0x090, 0x00009, 0x00, "Prelude SMC Memory"}, 
 	{HPHW_MEMORY, 0x091, 0x00009, 0x00, "Lego 360 Memory"}, 
+	{HPHW_MEMORY, 0x09C, 0x00009, 0x00, "Allegro W+ Memory"}, 
 	{HPHW_MEMORY, 0x7FF, 0x00009, 0x00, "NEC Aska memory"}, 
 	{HPHW_MEMORY, 0x800, 0x00009, 0x00, "Hitachi Tiny 64"}, 
 	{HPHW_MEMORY, 0x801, 0x00009, 0x00, "Hitachi Tiny 80"}, 
@@ -1324,10 +1327,12 @@ static struct hp_hardware hp_hardware_li
 	{HPHW_MEMORY, 0x095, 0x00009, 0x00, "Rhapsody 440 Memory"}, 
 	{HPHW_MEMORY, 0x096, 0x00009, 0x00, "Rhapsody 360 Memory"}, 
 	{HPHW_MEMORY, 0x097, 0x00009, 0x00, "Raven W 360 Memory"}, 
-	{HPHW_MEMORY, 0x098, 0x00009, 0x00, "Halfdome W 440 Memory"}, 
+	{HPHW_MEMORY, 0x098, 0x00009, 0x00, "Halfdome W+ 552 Memory"}, 
 	{HPHW_MEMORY, 0x099, 0x00009, 0x00, "Rhapsody DC- 440 Memory"}, 
 	{HPHW_MEMORY, 0x09A, 0x00009, 0x00, "Rhapsody DC- 360 Memory"}, 
 	{HPHW_MEMORY, 0x09B, 0x00009, 0x00, "Crescendo Memory"}, 
+	{HPHW_MEMORY, 0x0A1, 0x00009, 0x00, "Keystone Memory"}, 
+	{HPHW_MEMORY, 0x0A8, 0x00009, 0x00, "Caribe W2 Memory"}, 
 	{HPHW_OTHER, 0x004, 0x00030, 0x00, "Master"}, 
 	{HPHW_OTHER, 0x004, 0x00034, 0x00, "Slave"}, 
 	{HPHW_OTHER, 0x004, 0x00038, 0x00, "EDU"}, 
Index: arch/parisc/kernel/inventory.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/inventory.c,v
retrieving revision 1.33
diff -u -p -r1.33 inventory.c
--- inventory.c	2001/08/30 16:48:58	1.33
+++ inventory.c	2001/09/12 22:35:43
@@ -171,6 +171,7 @@ void do_pagezero_memconfig(void)
 static int pat_query_module(ulong pcell_loc, ulong mod_index)
 {
 	pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;
+	pdc_pat_cell_mod_maddr_block_t io_pdc_cell;
 	unsigned long bytecnt;
 	unsigned long temp;	/* 64-bit scratch value */
 	long status;		/* PDC return value status */
@@ -187,6 +188,9 @@ static int pat_query_module(ulong pcell_
 
 	temp = pa_pdc_cell.cba;
 	dev = alloc_pa_dev(PAT_GET_CBA(temp));	/* sets dev->hpa */
+	if (!dev) {
+		return PDC_RET_NE_MOD;
+	}
 
 	/*
 	** save parameters in the hp_device
@@ -236,13 +240,20 @@ static int pat_query_module(ulong pcell_
 		printk(KERN_DEBUG "PAT_ENTITY_LBA: ");
 
 	      print_ranges:
+		pdc_pat_cell_module(&bytecnt, pcell_loc, mod_index,
+				    IO_VIEW, &io_pdc_cell);
 		printk(KERN_DEBUG "ranges %ld\n", pa_pdc_cell.mod[1]);
 		for (i = 0; i < pa_pdc_cell.mod[1]; i++) {
 			printk(KERN_DEBUG 
-				"	%ld: 0x%016lx 0x%016lx 0x%016lx\n", 
+				"  PA_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n", 
 				i, pa_pdc_cell.mod[2 + i * 3],	/* type */
 				pa_pdc_cell.mod[3 + i * 3],	/* start */
 				pa_pdc_cell.mod[4 + i * 3]);	/* finish (ie end) */
+			printk(KERN_DEBUG 
+				"  IO_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n", 
+				i, io_pdc_cell.mod[2 + i * 3],	/* type */
+				io_pdc_cell.mod[3 + i * 3],	/* start */
+				io_pdc_cell.mod[4 + i * 3]);	/* finish (ie end) */
 		}
 		printk(KERN_DEBUG "\n");
 		break;
Index: arch/parisc/kernel/ioctl32.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/ioctl32.c,v
retrieving revision 1.6
diff -u -p -r1.6 ioctl32.c
--- ioctl32.c	2001/07/14 21:17:01	1.6
+++ ioctl32.c	2001/09/12 22:35:43
@@ -1395,6 +1395,7 @@ static int loop_status(unsigned int fd, 
 	return err;
 }
 
+#ifdef CONFIG_VT
 extern int tty_ioctl(struct inode * inode, struct file * file, unsigned 
int cmd, unsigned long arg);
 
 static int vt_check(struct file *file)
@@ -1527,6 +1528,7 @@ static int do_unimap_ioctl(unsigned int 
 	}
 	return 0;
 }
+#endif
 
 #if 0
 static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned 
long arg)
@@ -3382,11 +3384,13 @@ HANDLE_IOCTL(LOOP_SET_STATUS, loop_statu
 HANDLE_IOCTL(LOOP_GET_STATUS, loop_status)
 #define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int)
 HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout)
+#ifdef CONFIG_VT
 HANDLE_IOCTL(PIO_FONTX, do_fontx_ioctl)
 HANDLE_IOCTL(GIO_FONTX, do_fontx_ioctl)
 HANDLE_IOCTL(PIO_UNIMAP, do_unimap_ioctl)
 HANDLE_IOCTL(GIO_UNIMAP, do_unimap_ioctl)
 HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl)
+#endif
 HANDLE_IOCTL(EXT2_IOC32_GETFLAGS, do_ext2_ioctl)
 HANDLE_IOCTL(EXT2_IOC32_SETFLAGS, do_ext2_ioctl)
 HANDLE_IOCTL(EXT2_IOC32_GETVERSION, do_ext2_ioctl)
Index: arch/parisc/kernel/iosapic.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/iosapic.c,v
retrieving revision 1.28
diff -u -p -r1.28 iosapic.c
--- iosapic.c	2001/08/14 16:54:52	1.28
+++ iosapic.c	2001/09/12 22:35:44
@@ -338,7 +338,7 @@ iosapic_load_irt(unsigned long cell_num,
 	if (is_pdc_pat()) {
 
 		/* Use pat pdc routine to get interrupt routing table size */
-		DBG("calling get_irt_size\n");
+		DBG("calling get_irt_size (cell %ld)\n", cell_num);
 		status = pdc_pat_get_irt_size(&num_entries, cell_num);
 		DBG("get_irt_size: %ld\n", status);
 
@@ -436,6 +436,8 @@ got_irt:
 void __init
 iosapic_init(void)
 {
+	unsigned long cell = 0;
+
 	/* init global data */
 	iosapic_lock = SPIN_LOCK_UNLOCKED;
         iosapic_list = (struct iosapic_info *) NULL;
@@ -443,10 +445,22 @@ iosapic_init(void)
 
 	DBG("iosapic_init()\n");
 
+#ifdef __LP64__
+	if (is_pdc_pat()) {
+		int status;
+		struct pdc_pat_cell_num cell_info;
+
+		status = pdc_pat_cell_get_number(&cell_info);
+		if (status == PDC_RET_OK) {
+			cell = cell_info.cell_num;
+		}
+	}
+#endif
+
 	/*
 	**  get IRT for this cell.
 	*/
-	irt_num_entry =  iosapic_load_irt(0L, &irt_cell);
+	irt_num_entry =  iosapic_load_irt(cell, &irt_cell);
 	if (0 == irt_num_entry)
 		irt_cell = NULL;	/* old PDC w/o iosapic */
 }
Index: arch/parisc/kernel/lba_pci.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/lba_pci.c,v
retrieving revision 1.35
diff -u -p -r1.35 lba_pci.c
--- lba_pci.c	2001/09/03 22:09:46	1.35
+++ lba_pci.c	2001/09/12 22:35:44
@@ -470,7 +470,7 @@ lba_device_present( u8 bus, u8 dfn, stru
 
 
 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;
@@ -530,7 +530,7 @@ static int lba_cfg_read##size (struct pc
  \
 	if (LBA_SKIP_PROBE(d) && (!lba_device_present(dev->bus->secondary, 
dev->devfn, d))) \
 	{ \
-		DBG_CFG("%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); \
@@ -724,23 +724,23 @@ lba_fixup_bus(struct pci_bus *bus)
 			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.
@@ -750,7 +750,7 @@ lba_fixup_bus(struct pci_bus *bus)
 		int i;
 		u16 cmd;
 
-		for(i=0; i<4; i++) {
+		for (i = 0; i < 4; i++) {
 			bus->resource[i] =
 				&bus->self->resource[PCI_BRIDGE_RESOURCES+i];
 			bus->resource[i]->name = bus->name;
@@ -777,7 +777,7 @@ lba_fixup_bus(struct pci_bus *bus)
 			**	PCI will adjust them later.
 			*/
 			bus->resource[0]->end = ldev->hba.io_space.end;
-			bus->resource[1]->end = ldev->hba.mem_space.end;
+			bus->resource[1]->end = ldev->hba.lmmio_space.end;
 		}
 
 		/* Turn off downstream PF memory address range by default */
@@ -790,6 +790,8 @@ lba_fixup_bus(struct pci_bus *bus)
 		int i;
 		struct pci_dev *dev = pci_dev_b(ln);
 
+		DBG("lba_fixup_bus() %s\n", dev->name);
+
 		/* Virtualize Device/Bridge Resources. */
 		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
 			struct resource *res = &dev->resource[i];
@@ -799,14 +801,21 @@ lba_fixup_bus(struct pci_bus *bus)
 				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;
-#ifdef __LP64__
+				DBG("[%lx/%lx]\n", res->start, res->end);
 			} else if (res->flags & IORESOURCE_MEM) {
-				/* "Globalize" PCI address */
-				res->start |= ldev->lmmio_base;
-				res->end   |= ldev->lmmio_base;
-#endif
+				/*
+				** 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);
 			}
 		}
 
@@ -833,7 +842,7 @@ lba_fixup_bus(struct pci_bus *bus)
 			continue;
 
 		/* Adjust INTERRUPT_LINE for this dev */
-		iosapic_fixup_irq(LBA_DEV(bus->sysdata)->iosapic_obj, dev);
+		iosapic_fixup_irq(ldev->iosapic_obj, dev);
 	}
 
 #ifdef FBB_SUPPORT
@@ -890,8 +899,6 @@ struct pci_bios_ops lba_bios_ops = {
 static u##size lba_astro_in##size (struct pci_hba_data *d, u16 addr) \
 { \
 	u##size t; \
-	ASSERT(bus != NULL); \
-	DBG_PORT("%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); \
@@ -1026,10 +1033,8 @@ lba_pat_resources(struct parisc_device *
 {
 	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;
@@ -1039,11 +1044,9 @@ lba_pat_resources(struct parisc_device *
 				PA_VIEW, & pa_pdc_cell);
 	pa_count = pa_pdc_cell.mod[1];
 
-#ifdef DONT_NEED_THIS_FOR_ASTRO
 	status |= pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, 
pa_dev->mod_index,
-				IO_VIEW, & io_pdc_cell);
+				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) {
@@ -1062,10 +1065,11 @@ lba_pat_resources(struct parisc_device *
 			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) {
@@ -1075,9 +1079,9 @@ lba_pat_resources(struct parisc_device *
 			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;
@@ -1127,13 +1131,17 @@ lba_legacy_resources(struct parisc_devic
 	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
 
 	/*
@@ -1152,14 +1160,12 @@ lba_legacy_resources(struct parisc_devic
 	/* 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;
 	/* Ignore "Range Enable" bit in the BASE register */
-	r->start = ((long) READ_REG32(pa_dev->hpa + LBA_LMMIO_BASE)) & ~1UL;
-#ifdef __LP64__
-	r->start |= 0xffffffff00000000UL; /* sign extend f-space */
-#endif
+	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;
 
 	/*
@@ -1172,8 +1178,8 @@ lba_legacy_resources(struct parisc_devic
 
 	/*
 	** XXX FIXME - ignore LBA_ELMMIO_BASE for now
-	** "Directed" ranges are used when the "distrubuted range" isn't
-	** sufficient for all devices below  given LBA.  Typically devices
+	** "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).
 	**
@@ -1292,7 +1298,7 @@ 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;	
 
 	/*
@@ -1395,7 +1401,6 @@ lba_driver_callback(struct parisc_device
 
 		/* Go ask PDC PAT what resources this LBA has */
 		lba_pat_resources(dev, lba_dev);
-
 	} else
 #endif
 	{
@@ -1411,7 +1416,7 @@ lba_driver_callback(struct parisc_device
 	** 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 (is_pdc_pat()) {
@@ -1423,7 +1428,7 @@ lba_driver_callback(struct parisc_device
 		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
 	}
 #endif
Index: arch/parisc/kernel/pci.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/pci.c,v
retrieving revision 1.26
diff -u -p -r1.26 pci.c
--- pci.c	2001/08/24 15:02:39	1.26
+++ pci.c	2001/09/12 22:35:44
@@ -227,8 +227,7 @@ pcibios_update_resource(
 	if (res->flags & IORESOURCE_IO) {
 		barval = PCI_PORT_ADDR(res->start);
 	} else if (res->flags & IORESOURCE_MEM) {
-		/* This should work for VCLASS too */
-		barval = res->start & 0xffffffffUL;
+		barval = PCI_BUS_ADDR(HBA_DATA(dev->bus->sysdata), res->start);
 	} else {
 		panic("pcibios_update_resource() WTF? flags not IO or MEM");
 	}
@@ -339,6 +338,7 @@ void pcibios_fixup_pbus_ranges(
 	struct pbus_set_ranges_data *ranges
 	)
 {
+	struct pci_hba_data *hba = HBA_DATA(bus->sysdata);
 
 	/*
 	** I/O space may see busnumbers here. Something
@@ -350,11 +350,9 @@ void pcibios_fixup_pbus_ranges(
 	ranges->io_start = PCI_PORT_ADDR(ranges->io_start);
 	ranges->io_end   = PCI_PORT_ADDR(ranges->io_end);
 
-#ifdef __LP64__
 	/* Convert MMIO addr to PCI addr (undo global virtualization) */
-	ranges->mem_start &= 0xffffffffUL;
-	ranges->mem_end   &= 0xffffffffUL;
-#endif
+	ranges->mem_start = PCI_BUS_ADDR(hba, ranges->mem_start);
+	ranges->mem_end   = PCI_BUS_ADDR(hba, ranges->mem_end);
 
 	DBG_RES("pcibios_fixup_pbus_ranges(%02x, [%lx,%lx %lx,%lx])\n", 
bus->number,
 		ranges->io_start, ranges->io_end,
@@ -364,9 +362,8 @@ void pcibios_fixup_pbus_ranges(
 	** if this resource isn't linked to a "parent", then it seems
 	** to be a child of the HBA - lets link it in.
 	*/
-	pcibios_link_hba_resources(&((struct pci_hba_data 
*)bus->sysdata)->io_space, bus->resource[0]);
-
-	pcibios_link_hba_resources(&((struct pci_hba_data 
*)bus->sysdata)->mem_space, bus->resource[1]);
+	pcibios_link_hba_resources(&hba->io_space, bus->resource[0]);
+	pcibios_link_hba_resources(&hba->lmmio_space, bus->resource[1]);
 }
 
 #define MAX(val1, val2)   ((val1) > (val2) ? (val1) : (val2))
Index: arch/parisc/kernel/traps.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/traps.c,v
retrieving revision 1.52
diff -u -p -r1.52 traps.c
--- traps.c	2001/09/06 09:44:07	1.52
+++ traps.c	2001/09/12 22:35:44
@@ -102,7 +102,7 @@ void show_regs(struct pt_regs *regs)
 		printk("%s\n", buf);
 	}
 
-#if REDICULOUSLY_VERBOSE
+#if RIDICULOUSLY_VERBOSE
 	for (i = 0; i < 32; i += 2)
 		printk("%sFR%2d : %016lx  FR%2d : %016lx", level, i,
 				regs->fr[i], i+1, regs->fr[i+1]);
@@ -359,11 +359,11 @@ void handle_interruption(int code, struc
 		goto give_sigill;
 
 	case 10:
-		die_if_kernel("Priviledged operation - shouldn't happen!", regs, code);
+		die_if_kernel("Privileged operation - shouldn't happen!", regs, code);
 		si.si_code = ILL_PRVOPC;
 		goto give_sigill;
 	case 11:
-		die_if_kernel("Priviledged register - shouldn't happen!", regs, code);
+		die_if_kernel("Privileged register - shouldn't happen!", regs, code);
 		si.si_code = ILL_PRVREG;
 	give_sigill:
 		si.si_signo = SIGILL;
Index: arch/parisc/mm/init.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/mm/init.c,v
retrieving revision 1.37
diff -u -p -r1.37 init.c
--- init.c	2001/09/06 09:44:09	1.37
+++ init.c	2001/09/12 22:35:44
@@ -336,10 +336,21 @@ static void __init setup_bootmem(void)
 #endif
 
 #ifdef CONFIG_BLK_DEV_INITRD
-	if (initrd_end != 0) {
-		printk(KERN_INFO "initrd: %08x-%08x\n", (int) initrd_start, (int) 
initrd_end);
-		initrd_below_start_ok = 1;
-		reserve_bootmem_node(NODE_DATA(0),__pa(initrd_start), initrd_end - 
initrd_start);
+	if (initrd_start) {
+		printk(KERN_INFO "initrd: %08x-%08x\n", initrd_start, initrd_end);
+		if (__pa(initrd_start) < mem_max) {
+			unsigned long initrd_reserve;
+
+			if (__pa(initrd_end) > mem_max) {
+				initrd_reserve = mem_max - __pa(initrd_start);
+			} else {
+				initrd_reserve = initrd_end - initrd_start;
+			}
+			initrd_below_start_ok = 1;
+			printk(KERN_INFO "initrd: reserving %08lx-%08lx (mem_max %08lx)\n", 
__pa(initrd_start), __pa(initrd_start) + initrd_reserve, mem_max);
+
+			reserve_bootmem_node(NODE_DATA(0),__pa(initrd_start), initrd_reserve);
+		}
 	}
 #endif
 
@@ -451,95 +462,86 @@ void set_pte_phys (unsigned long vaddr, 
 {
 }
 
-/*
- * pagetable_init() sets up the page tables
- *
- * Note that gateway_init() places the Linux gateway page at page 0.
- * Since gateway pages cannot be dereferenced this has the desirable
- * side effect of trapping those pesky NULL-reference errors in the
- * kernel.
- */
-static void __init pagetable_init(void)
+static void __init map_pages(unsigned long start_vaddr, unsigned long 
start_paddr, unsigned long size, pgprot_t pgprot)
 {
 	pgd_t *pg_dir;
 	pmd_t *pmd;
 	pte_t *pg_table;
+	unsigned long end_paddr;
 	unsigned long start_pmd;
+	unsigned long start_pte;
 	unsigned long tmp1;
 	unsigned long tmp2;
 	unsigned long address;
 	unsigned long ro_start;
 	unsigned long ro_end;
 	unsigned long fv_addr;
+	unsigned long gw_addr;
 	int range;
-	extern  const unsigned long fault_vector_20;
+	extern const unsigned long fault_vector_20;
+	extern void * const linux_gateway_page;
 
 	ro_start = __pa((unsigned long)&_text);
 	ro_end   = __pa((unsigned long)&data_start);
 	fv_addr  = __pa((unsigned long)&fault_vector_20) & PAGE_MASK;
-
-	/* Map each physical memory range to its kernel vaddr */
+	gw_addr  = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK;
 
-	for (range = 0; range < npmem_ranges; range++) {
-		unsigned long start_paddr;
-		unsigned long end_paddr;
+	end_paddr = start_paddr + size;
 
-		start_paddr = pmem_ranges[range].start_pfn << PAGE_SHIFT;
-		end_paddr = start_paddr + (pmem_ranges[range].pages << PAGE_SHIFT);
+	pg_dir = pgd_offset_k(start_vaddr);
 
-		pg_dir = pgd_offset_k(start_paddr + PAGE_OFFSET);
-
 #if PTRS_PER_PMD == 1
-		start_pmd = 0;
+	start_pmd = 0;
 #else
-		start_pmd = (((start_paddr + PAGE_OFFSET) >> PMD_SHIFT) & (PTRS_PER_PMD 
- 1));
+	start_pmd = ((start_vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1));
 #endif
+	start_pte = ((start_vaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
 
-		address = start_paddr;
-		while (address < end_paddr) {
+	address = start_paddr;
+	while (address < end_paddr) {
 #if PTRS_PER_PMD == 1
-			pmd = (pmd_t *)__pa(pg_dir);
+		pmd = (pmd_t *)__pa(pg_dir);
 #else
-			pmd = (pmd_t *) (PAGE_MASK & pgd_val(*pg_dir));
+		pmd = (pmd_t *) (PAGE_MASK & pgd_val(*pg_dir));
+
+		/*
+		 * pmd is physical at this point
+		 */
+
+		if (!pmd) {
+			pmd = (pmd_t *) alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE);
+			pmd = (pmd_t *) __pa(pmd);
+		}
+
+		pgd_val(*pg_dir) = _PAGE_TABLE | (unsigned long) pmd;
+#endif
+		pg_dir++;
+
+		/* now change pmd to kernel virtual addresses */
+
+		pmd = (pmd_t *)__va(pmd) + start_pmd;
+		for (tmp1 = start_pmd; tmp1 < PTRS_PER_PMD; tmp1++,pmd++) {
 
 			/*
-			 * pmd is physical at this point
+			 * pg_table is physical at this point
 			 */
 
-			if (!pmd) {
-				pmd = (pmd_t *) alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE);
-				pmd = (pmd_t *) __pa(pmd);
+			pg_table = (pte_t *) (PAGE_MASK & pmd_val(*pmd));
+			if (!pg_table) {
+				pg_table = (pte_t *)
+					alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE);
+				pg_table = (pte_t *) __pa(pg_table);
 			}
 
-			pgd_val(*pg_dir) = _PAGE_TABLE | (unsigned long) pmd;
-#endif
-			pg_dir++;
+			pmd_val(*pmd) = _PAGE_TABLE |
+					   (unsigned long) pg_table;
 
-			/* now change pmd to kernel virtual addresses */
+			/* now change pg_table to kernel virtual addresses */
 
-			pmd = (pmd_t *)__va(pmd) + start_pmd;
-			for (tmp1 = start_pmd; tmp1 < PTRS_PER_PMD; tmp1++,pmd++) {
+			pg_table = (pte_t *) __va(pg_table) + start_pte;
+			for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++,pg_table++) {
+				pte_t pte;
 
-				/*
-				 * pg_table is physical at this point
-				 */
-
-				pg_table = (pte_t *) (PAGE_MASK & pmd_val(*pmd));
-				if (!pg_table) {
-					pg_table = (pte_t *)
-						alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE);
-					pg_table = (pte_t *) __pa(pg_table);
-				}
-
-				pmd_val(*pmd) = _PAGE_TABLE |
-						   (unsigned long) pg_table;
-
-				/* now change pg_table to kernel virtual addresses */
-
-				pg_table = (pte_t *) __va(pg_table);
-				for (tmp2=0; tmp2 < PTRS_PER_PTE; tmp2++,pg_table++) {
-					pte_t pte;
-
 #if !defined(CONFIG_KWDB) && !defined(CONFIG_STI_CONSOLE)
 #warning STI console should explicitly allocate executable pages but does 
not
 /* KWDB needs to write kernel text when setting break points.
@@ -547,28 +549,70 @@ static void __init pagetable_init(void)
 ** The right thing to do seems like KWDB modify only the pte which
 ** has a break point on it...otherwise we might mask worse bugs.
 */
-					if (address >= ro_start && address < ro_end
-								&& address != fv_addr)
-					    pte = __mk_pte(address, PAGE_KERNEL_RO);
-					else
+				/*
+				 * Map the fault vector writable so we can
+				 * write the HPMC checksum.
+				 */
+				if (address >= ro_start && address < ro_end
+							&& address != fv_addr
+							&& address != gw_addr)
+				    pte = __mk_pte(address, PAGE_KERNEL_RO);
+				else
 #endif
-					    pte = __mk_pte(address, PAGE_KERNEL);
+				    pte = __mk_pte(address, pgprot);
 
-					if (address >= end_paddr)
-						pte_val(pte) = 0;
-
-					set_pte(pg_table, pte);
+				if (address >= end_paddr)
+					pte_val(pte) = 0;
 
-					address += PAGE_SIZE;
-				}
+				set_pte(pg_table, pte);
 
-				if (address >= end_paddr)
-				    break;
+				address += PAGE_SIZE;
 			}
-			start_pmd = 0;
+			start_pte = 0;
+
+			if (address >= end_paddr)
+			    break;
 		}
+		start_pmd = 0;
 	}
+}
+
+/*
+ * pagetable_init() sets up the page tables
+ *
+ * Note that gateway_init() places the Linux gateway page at page 0.
+ * Since gateway pages cannot be dereferenced this has the desirable
+ * side effect of trapping those pesky NULL-reference errors in the
+ * kernel.
+ */
+static void __init pagetable_init(void)
+{
+	int range;
+
+	printk("pagetable_init\n");
 
+	/* Map each physical memory range to its kernel vaddr */
+
+	for (range = 0; range < npmem_ranges; range++) {
+		unsigned long start_paddr;
+		unsigned long end_paddr;
+		unsigned long size;
+
+		start_paddr = pmem_ranges[range].start_pfn << PAGE_SHIFT;
+		end_paddr = start_paddr + (pmem_ranges[range].pages << PAGE_SHIFT);
+		size = pmem_ranges[range].pages << PAGE_SHIFT;
+
+		map_pages(__va(start_paddr), start_paddr, size, PAGE_KERNEL);
+	}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_end && initrd_end > mem_limit) {
+		printk("initrd: mapping %08lx-%08lx\n", initrd_start, initrd_end);
+		map_pages(initrd_start, __pa(initrd_start),
+			initrd_end - initrd_start, PAGE_KERNEL);
+	}
+#endif
+
 	empty_zero_page = alloc_bootmem_pages(PAGE_SIZE);
 	memset(empty_zero_page, 0, PAGE_SIZE);
 }
@@ -576,14 +620,9 @@ static void __init pagetable_init(void)
 static void __init gateway_init(void)
 {
 	unsigned long linux_gateway_page_addr;
-	pgd_t *pg_dir;
-	pmd_t *pmd;
-	pte_t *pg_table_base;
-	pte_t *pg_table;
 	/* FIXME: This is 'const' in order to trick the compiler
 	   into not treating it as DP-relative data. */
 	extern void * const linux_gateway_page;
-	pte_t pte;
 
 	linux_gateway_page_addr = LINUX_GATEWAY_ADDR & PAGE_MASK;
 
@@ -593,28 +632,9 @@ static void __init gateway_init(void)
 	 * The Linux gateway page will reside in kernel space (on virtual
 	 * page 0), so it doesn't need to be aliased into user space.
 	 */
-
-	pg_dir = pgd_offset_k(linux_gateway_page_addr);
-
-#if (PTRS_PER_PMD != 1)
-	if (pgd_none(*pg_dir)) {
-		pmd_t *pmd_base;
-		pmd_base = (pmd_t *) alloc_bootmem_pages(PAGE_SIZE);
-		pgd_val(*pg_dir) = _PAGE_TABLE | __pa(pmd_base);
-	}
-#endif
-
-	pmd = pmd_offset(pg_dir,linux_gateway_page_addr);
-	if (pmd_none(*pmd)) {
-		pg_table_base = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
-		pmd_val(*pmd) = _PAGE_TABLE | __pa(pg_table_base);
-	}
-
-	pg_table = pte_offset(pmd,linux_gateway_page_addr);
-	pte = __mk_pte(__pa(&linux_gateway_page), PAGE_GATEWAY);
-	set_pte(pg_table,pte);
 
-	return;
+	map_pages(linux_gateway_page_addr, __pa(&linux_gateway_page),
+		PAGE_SIZE, PAGE_GATEWAY);
 }
 
 extern void flush_tlb_all_local(void);
Index: drivers/gsc/dino.c
===================================================================
RCS file: /home/cvs/parisc/linux/drivers/gsc/dino.c,v
retrieving revision 1.38
diff -u -p -r1.38 dino.c
--- dino.c	2001/08/31 06:02:17	1.38
+++ dino.c	2001/09/12 22:35:44
@@ -666,6 +666,7 @@ dino_card_init(struct dino_device *dino_
 
 	dino_dev->ioport_addr =  0x00001000;	/* Make believe */
 	dino_dev->mmio_addr   =  0xf0800000;	/* FIXME: Make believe */
+	dino_dev->hba.lmmio_space_offset = 0;	/* CPU addrs == bus addrs */
 
 	gsc_writel(0x00000000, dino_dev->hba.base_addr+DINO_DAMODE);
 	gsc_writel(0x00222222, dino_dev->hba.base_addr+DINO_PCIROR);
@@ -723,6 +724,7 @@ dino_bridge_init(struct dino_device *din
 	*/
 	dino_dev->mmio_addr = 0xf0000000 + (bpos << 23); /* bpos x 8MB */
 	dino_dev->ioport_addr =  0;	/* not used for bridge mode */
+	dino_dev->hba.lmmio_space_offset = 0;	/* CPU addrs == bus addrs */
 }
 
 static int __init
Index: include/asm-parisc/pci.h
===================================================================
RCS file: /home/cvs/parisc/linux/include/asm-parisc/pci.h,v
retrieving revision 1.29
diff -u -p -r1.29 pci.h
--- pci.h	2001/08/14 16:55:00	1.29
+++ pci.h	2001/09/12 22:35:45
@@ -3,9 +3,6 @@
 
 #include <asm/scatterlist.h>
 
-#define MIN_PCI_PORT 0x000000
-#define MAX_PCI_PORT 0xffffff
-
 /*
 ** HP PCI platforms generally support multiple bus adapters.
 **    (workstations 1-~4, servers 2-~32)
@@ -19,7 +16,7 @@
 #define PCI_MAX_BUSSES	256
 
 /* [soapbox on]
-** Who the hell can develope stuff without ASSERT or VASSERT?
+** Who the hell can develop stuff without ASSERT or VASSERT?
 ** No one understands all the modules across all platforms.
 ** For linux add another dimension - processor architectures.
 **
@@ -56,11 +53,13 @@ struct pci_hba_data {
 	int		hba_num;	/* I/O port space access "key" */
 	struct resource bus_num;	/* PCI bus numbers */
 	struct resource io_space;	/* PIOP */
-	struct resource mem_space;	/* LMMIO */
-	unsigned long   mem_space_offset;  /* VCLASS support */
+	struct resource lmmio_space;	/* bus addresses < 4Gb */
+	unsigned long   lmmio_space_offset;  /* CPU view - PCI view */
 	/* REVISIT - spinlock to protect resources? */
 };
 
+#define HBA_DATA(d)		((struct pci_hba_data *) (d))
+
 /* 
 ** We support 2^16 I/O ports per HBA.  These are set up in the form
 ** 0xbbxxxx, where bb is the bus number and xxxx is the I/O port
@@ -73,6 +72,13 @@ struct pci_hba_data {
 
 #define PCI_PORT_HBA(a)		((a) >> HBA_PORT_SPACE_BITS)
 #define PCI_PORT_ADDR(a)	((a) & (HBA_PORT_SPACE_SIZE - 1))
+
+/*
+** Convert between PCI (IO_VIEW) addresses and processor (PA_VIEW) 
addresses.
+** Note that we currently support only LMMIO.
+*/
+#define PCI_BUS_ADDR(hba,a)	((a) - hba->lmmio_space_offset)
+#define PCI_HOST_ADDR(hba,a)	((a) + hba->lmmio_space_offset)
 
 /*
 ** KLUGE: linux/pci.h include asm/pci.h BEFORE declaring struct pci_bus