[parisc-linux-cvs] [PATCH] PCI MMIO mapping
Bjorn Helgaas
bjorn_helgaas@hp.com
Mon, 21 May 2001 15:08:50 -0600
I don't plan to commit this patch until after the end-of-May release, but
I want to get Grant's comments before he disappears, so here it is.
The idea is to clean up the conversions between CPU (host) and PCI (bus)
addresses for LMMIO space. The code in the current tree assumes that for
narrow kernels (i.e., #ifndef __LP64__), the host and bus addresses are
identical. For wide kernels (#ifdef __LP64__), we assume that host and
bus addresses are identical in the low 32 bits, and the upper 32 bits are
either 0xffffffff (for legacy, non-PAT boxes), or the "lmmio_base" value
returned by pdc_pat_cell_module().
These assumptions are invalid for systems with REO, so this patch
introduces PCI_BUS_ADDR(hba,a) and PCI_HOST_ADDR(hba,a) to convert from
host to bus addresses and vice versa, using a per-hpa mem_space_offset.
It also fills in the correct cell for iosapic_load_irt(). There may be
other cell dependencies, but this at least allows me to boot on a cell
other than zero.
Any comments appreciated!
Bjorn
Index: arch/parisc/kernel/inventory.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/inventory.c,v
retrieving revision 1.28
diff -u -p -r1.28 inventory.c
--- inventory.c 2001/04/06 05:10:54 1.28
+++ inventory.c 2001/05/21 18:17:50
@@ -14,7 +14,7 @@
** Debug options
** DEBUG_PAT Dump details which PDC PAT provides about ranges/devices.
*/
-#undef DEBUG_PAT
+#define DEBUG_PAT
int pdc_type = PDC_TYPE_ILLEGAL;
@@ -161,6 +161,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 */
@@ -177,6 +178,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
@@ -225,11 +229,17 @@ static int pat_query_module(ulong pcell_
printk("PAT_ENTITY_LBA: ");
print_ranges:
+ pdc_pat_cell_module(&bytecnt, pcell_loc, mod_index,
+ IO_VIEW, &io_pdc_cell);
+
printk("ranges %ld\n", pa_pdc_cell.mod[1]);
for (i = 0; i < pa_pdc_cell.mod[1]; i++) {
- printk(" %ld: 0x%016lx 0x%016lx 0x%016lx\n", i, pa_pdc_cell.mod[2 + i
* 3], /* type */
+ printk(" 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(" 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("\n");
break;
Index: arch/parisc/kernel/iosapic.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/iosapic.c,v
retrieving revision 1.24
diff -u -p -r1.24 iosapic.c
--- iosapic.c 2001/04/06 05:10:54 1.24
+++ iosapic.c 2001/05/21 18:17:50
@@ -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(KERN_DEBUG "calling get_irt_size\n");
+ DBG(KERN_DEBUG "calling get_irt_size (cell %ld)\n", cell_num);
status = pdc_pat_get_irt_size(&num_entries, cell_num);
DBG(KERN_DEBUG "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()) {
+ struct pdc_pat_cell_num cell_info;
+ int status;
+
+ 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 */
}
@@ -884,7 +898,6 @@ iosapic_enable_irq(void *dev, int irq)
/* data is initialized by fixup_irq */
ASSERT(0 < vi->vi_txn_irq);
- ASSERT(0UL != vi->vi_txn_addr);
ASSERT(0UL != vi->vi_txn_data);
iosapic_set_irt_data(vi, &d0, &d1);
Index: arch/parisc/kernel/lba_pci.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/lba_pci.c,v
retrieving revision 1.26
diff -u -p -r1.26 lba_pci.c
--- lba_pci.c 2001/05/16 21:00:13 1.26
+++ lba_pci.c 2001/05/21 18:17:50
@@ -205,9 +205,9 @@ struct lba_device {
void *iosapic_obj;
#ifdef __LP64__
- unsigned long lmmio_base; /* PA_VIEW - fixup MEM addresses */
- unsigned long gmmio_base; /* PA_VIEW - Not used (yet) */
- unsigned long iop_base; /* PA_VIEW - for IO port accessor funcs */
+ unsigned long lmmio_base; /* PA_VIEW - fixup MEM addresses */
+ unsigned long gmmio_base; /* PA_VIEW - Not used (yet) */
+ unsigned long iop_base; /* PA_VIEW - for IO port accessor funcs */
#endif
int flags; /* state/functionality enabled */
@@ -556,7 +556,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(KERN_DEBUG "%s(%s+%2x) -> -1 (b)\n", __FUNCTION__,
dev->slot_name, pos, *data); \
+ DBG_CFG(KERN_DEBUG "%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); \
@@ -730,9 +730,8 @@ lba_fixup_bus(struct pci_bus *bus)
u16 status;
#endif
struct lba_device *ldev = LBA_DEV(bus->sysdata);
-#ifdef __LP64__
int i;
-#endif
+
DBG("lba_fixup_bus(0x%p) bus %d sysdata 0x%p\n",
bus, bus->secondary, bus->sysdata);
@@ -771,10 +770,9 @@ lba_fixup_bus(struct pci_bus *bus)
** 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++) {
+ for (i = 0; i < 4; i++) {
bus->resource[i] =
&bus->self->resource[PCI_BRIDGE_RESOURCES+i];
bus->resource[i]->name = bus->name;
@@ -809,7 +807,6 @@ lba_fixup_bus(struct pci_bus *bus)
list_for_each(ln, &bus->devices) {
struct pci_dev *dev = pci_dev_b(ln);
-#ifdef __LP64__
/*
** Virtualize Device/Bridge Resources.
*/
@@ -821,12 +818,14 @@ lba_fixup_bus(struct pci_bus *bus)
continue;
if (res->flags & IORESOURCE_MEM) {
- /* "Globalize" PCI address */
- res->start |= ldev->lmmio_base;
- res->end |= ldev->lmmio_base;
+ /*
+ ** Convert PCI (IO_VIEW) addresses to
+ ** processor (PA_VIEW) addresses
+ */
+ res->start = PCI_HOST_ADDR(HBA_DATA(ldev), res->start);
+ res->end = PCI_HOST_ADDR(HBA_DATA(ldev), res->end);
}
}
-#endif
#ifdef FBB_SUPPORT
/*
@@ -851,7 +850,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
@@ -908,8 +907,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(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); \
@@ -1032,28 +1029,24 @@ static struct pci_port_ops lba_pat_port_
** 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 hp_device *d, 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(&bytecnt, d->pcell_loc, d->mod_index,
- PA_VIEW, & pa_pdc_cell);
+ PA_VIEW, &pa_pdc_cell);
pa_count = pa_pdc_cell.mod[1];
-#ifdef DONT_NEED_THIS_FOR_ASTRO
status |= pdc_pat_cell_module(&bytecnt, d->pcell_loc, d->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) {
@@ -1072,10 +1065,11 @@ lba_pat_resources( struct hp_device *d,
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) {
@@ -1085,7 +1079,7 @@ lba_pat_resources( struct hp_device *d,
break;
case PAT_LMMIO:
/* used to fix up pre-initialized MEM BARs */
- lba_dev->lmmio_base = p->start;
+ lba_dev->hba.mem_space_offset = p->start - io->start;
r = &(lba_dev->hba.mem_space);
r->name = "LBA LMMIO";
@@ -1132,18 +1126,22 @@ lba_pat_resources( struct hp_device *d,
static void
-lba_legacy_resources( struct hp_device *d, struct lba_device *lba_dev)
+lba_legacy_resources(struct hp_device *d, struct lba_device *lba_dev)
{
struct resource *r;
unsigned long rsize;
int lba_num;
+
#ifdef __LP64__
/*
+ ** FIXME I can't parse this comment.
** 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.
*/
- lba_dev->lmmio_base = 0xffffffff00000000UL;
+ lba_dev->hba.mem_space_offset = 0xffffffff00000000UL;
+#else
+ lba_dev->hba.mem_space_offset = 0UL;
#endif
/*
@@ -1166,10 +1164,8 @@ lba_legacy_resources( struct hp_device *
r->name = "LBA PCI LMMIO";
r->flags = IORESOURCE_MEM;
/* Ignore "Range Enable" bit in the BASE register */
- r->start = ((long) READ_REG32(d->hpa + LBA_LMMIO_BASE)) & ~1UL;
-#ifdef __LP64__
- r->start |= 0xffffffff00000000UL; /* sign extend f-space */
-#endif
+ r->start = PCI_HOST_ADDR(HBA_DATA(lba_dev),
+ ((unsigned long) READ_REG32(d->hpa + LBA_LMMIO_BASE)) & ~1UL);
rsize = ~READ_REG32(d->hpa + LBA_LMMIO_MASK) + 1;
/*
@@ -1181,7 +1177,7 @@ lba_legacy_resources( struct hp_device *
r->end = r->start + rsize - 1 ;
/*
- ** XXX FIXME - ignore LBA_ELMMIO_BASE for now
+ ** XXX FIXME - ignore LBA_LMMIO_BASE for now
** "Directed" ranges are used when the "distrubuted range" isn't
** sufficient for all devices below given LBA. Typically devices
** like graphics cards or X25 may need a directed range when the
@@ -1304,7 +1300,7 @@ static void
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;
/*
@@ -1403,7 +1399,6 @@ lba_driver_callback(struct hp_device *d,
/* Go ask PDC PAT what resources this LBA has */
lba_pat_resources(d, lba_dev);
-
} else
#endif
{
Index: arch/parisc/kernel/pci.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/pci.c,v
retrieving revision 1.21
diff -u -p -r1.21 pci.c
--- pci.c 2001/05/16 21:00:13 1.21
+++ pci.c 2001/05/21 18:17:50
@@ -22,7 +22,7 @@
#ifdef CONFIG_PCI
-#undef DEBUG_RESOURCES
+#define DEBUG_RESOURCES
#ifdef DEBUG_RESOURCES
#define DBG_RES(x...) printk(x)
@@ -231,8 +231,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");
}
@@ -316,6 +315,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
@@ -327,11 +327,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,
@@ -341,9 +339,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->mem_space, bus->resource[1]);
}
#define MAX(val1, val2) ((val1) > (val2) ? (val1) : (val2))
@@ -467,4 +464,16 @@ void pcibios_register_hba(struct pci_hba
*/
parisc_pci_hba[hba_count] = hba;
hba->hba_num = hba_count++;
+}
+
+unsigned long
+pcibios_host_to_bus(unsigned long addr)
+{
+ struct pci_hba_data *hba;
+
+ for (hba = hba_list; NULL != hba; hba = hba->next)
+ if (hba->mem_space.start <= addr && addr <= hba->mem_space.end)
+ return PCI_BUS_ADDR(hba, addr);
+
+ panic("Invalid MMIO address 0x%lx", addr);
}
Index: drivers/gsc/dino.c
===================================================================
RCS file: /home/cvs/parisc/linux/drivers/gsc/dino.c,v
retrieving revision 1.27
diff -u -p -r1.27 dino.c
--- dino.c 2001/05/16 21:00:13 1.27
+++ dino.c 2001/05/21 18:17:51
@@ -744,6 +744,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.mem_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);
@@ -801,6 +802,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.mem_space_offset = 0; /* CPU addrs == bus addrs */
}
static int __init
@@ -811,7 +813,7 @@ dino_common_init(struct dino_device *din
struct gsc_irq gsc_irq;
struct resource *res;
- pcibios_register_hba((struct pci_hba_data *) dino_dev);
+ pcibios_register_hba(HBA_DATA(dino_dev));
pci_bios = &dino_bios_ops; /* used by pci_scan_bus() */
pci_port = &dino_port_ops;
Index: drivers/scsi/sym53c8xx.c
===================================================================
RCS file: /home/cvs/parisc/linux/drivers/scsi/sym53c8xx.c,v
retrieving revision 1.11
diff -u -p -r1.11 sym53c8xx.c
--- sym53c8xx.c 2001/01/25 00:01:46 1.11
+++ sym53c8xx.c 2001/05/21 18:17:51
@@ -699,11 +699,8 @@ spinlock_t sym53c8xx_lock = SPIN_LOCK_UN
#elif defined(__alpha__)
# define pcivtobus(p) ((p) & 0xfffffffful)
# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c))
-#elif defined(__hppa__) && defined(__LP64__)
- /* <ggg> For most PA-RISC, I think dropping upper bits would be ok for
now
- * (VCLASS is the exception)
- */
-# define pcivtobus(p) ((p) & 0xfffffffful)
+#elif defined(__hppa__)
+# define pcivtobus(p) pcibios_host_to_bus(p)
# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c))
#elif defined(CONFIG_PPC)
# define pcivtobus(p) phys_to_bus(p)
Index: include/asm-parisc/pci.h
===================================================================
RCS file: /home/cvs/parisc/linux/include/asm-parisc/pci.h,v
retrieving revision 1.26
diff -u -p -r1.26 pci.h
--- pci.h 2001/05/16 21:00:14 1.26
+++ pci.h 2001/05/21 18:17:51
@@ -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.
**
@@ -57,10 +54,12 @@ struct pci_hba_data {
struct resource bus_num; /* PCI bus numbers */
struct resource io_space; /* PIOP */
struct resource mem_space; /* LMMIO */
- unsigned long mem_space_offset; /* VCLASS support */
+ unsigned long mem_space_offset; /* LMMIO: 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
@@ -75,6 +74,12 @@ struct pci_hba_data {
#define PCI_PORT_ADDR(a) ((a) & (HBA_PORT_SPACE_SIZE - 1))
/*
+** Convert between PCI (IO_VIEW) addresses and processor (PA_VIEW)
addresses.
+*/
+#define PCI_BUS_ADDR(hba,a) ((a) - hba->mem_space_offset)
+#define PCI_HOST_ADDR(hba,a) ((a) + hba->mem_space_offset)
+
+/*
** KLUGE: linux/pci.h include asm/pci.h BEFORE declaring struct pci_bus
** (This eliminates some of the warnings).
*/
@@ -205,6 +210,7 @@ extern int pci_post_reset_delay; /* dela
extern void pcibios_register_hba(struct pci_hba_data *);
extern void pcibios_set_master(struct pci_dev *);
+extern unsigned long pcibios_host_to_bus(unsigned long addr);
#ifdef __LP64__
extern void pcibios_assign_unassigned_resources(struct pci_bus *);
#endif
p