More fully support 64-bit bars. Prior to this commit, we supported

only those bars that had addresses assigned by the BIOS and where the
bridges were properly programmed.  Now even unprogrammed ones work.
This was needed for sun4v.  We still only implement up to 2GB memory
ranges, even for 64-bit bars.  PCI standards at least through 2.2 say
that this is the max (or 1GB is, I only know it is < 32bits).

o Always define pci_addr_t as uint64_t.  A pci address is always 64-bits,
  but some hosts can't address all of them.
o Preserve the upper half of the 64-bit word during resource probing.
o Test to make sure that 64-bit values can fit in a u_long (true on some
  platforms, but not others).  Don't use those that can't.
o minor pedantry about data sizes.
o Better bridge resource reporting in bootverbose case.
o Minor formatting changes to cope with different data types on different
  platforms.

Submitted by: jmg, with many changes by me to fully support 64-bit
addresses.
This commit is contained in:
Warner Losh 2006-10-30 19:18:46 +00:00
parent a930f272de
commit b0a2d4b8a9
3 changed files with 69 additions and 58 deletions

View File

@ -245,7 +245,7 @@ pci_find_device(uint16_t vendor, uint16_t device)
/* return base address of memory or port map */ /* return base address of memory or port map */
static uint32_t static uint32_t
pci_mapbase(unsigned mapreg) pci_mapbase(uint32_t mapreg)
{ {
int mask = 0x03; int mask = 0x03;
if ((mapreg & 0x01) == 0) if ((mapreg & 0x01) == 0)
@ -275,7 +275,7 @@ pci_maptype(unsigned mapreg)
/* return log2 of map size decoded for memory or port map */ /* return log2 of map size decoded for memory or port map */
static int static int
pci_mapsize(unsigned testval) pci_mapsize(uint32_t testval)
{ {
int ln2size; int ln2size;
@ -1211,8 +1211,8 @@ pci_add_map(device_t pcib, device_t bus, device_t dev,
int prefetch) int prefetch)
{ {
uint32_t map; uint32_t map;
uint64_t base; pci_addr_t base;
uint64_t start, end, count; pci_addr_t start, end, count;
uint8_t ln2size; uint8_t ln2size;
uint8_t ln2range; uint8_t ln2range;
uint32_t testval; uint32_t testval;
@ -1252,11 +1252,9 @@ pci_add_map(device_t pcib, device_t bus, device_t dev,
if (ln2range == 64) if (ln2range == 64)
/* Read the other half of a 64bit map register */ /* Read the other half of a 64bit map register */
base |= (uint64_t) PCIB_READ_CONFIG(pcib, b, s, f, reg + 4, 4) << 32; base |= (uint64_t) PCIB_READ_CONFIG(pcib, b, s, f, reg + 4, 4) << 32;
if (bootverbose) { if (bootverbose) {
printf("\tmap[%02x]: type %x, range %2d, base %08x, size %2d", printf("\tmap[%02x]: type %x, range %2d, base %#jx, size %2d",
reg, pci_maptype(map), ln2range, reg, pci_maptype(map), ln2range, (uintmax_t)base, ln2size);
(unsigned int) base, ln2size);
if (type == SYS_RES_IOPORT && !pci_porten(pcib, b, s, f)) if (type == SYS_RES_IOPORT && !pci_porten(pcib, b, s, f))
printf(", port disabled\n"); printf(", port disabled\n");
else if (type == SYS_RES_MEMORY && !pci_memen(pcib, b, s, f)) else if (type == SYS_RES_MEMORY && !pci_memen(pcib, b, s, f))
@ -1278,7 +1276,11 @@ pci_add_map(device_t pcib, device_t bus, device_t dev,
*/ */
if (!force && (base == 0 || map == testval)) if (!force && (base == 0 || map == testval))
return (barlen); return (barlen);
if ((u_long)base != base) {
device_printf(bus,
"pci%d:%d:%d bar %#x too many address bits", b, s, f, reg);
return (barlen);
}
/* /*
* This code theoretically does the right thing, but has * This code theoretically does the right thing, but has
* undesirable side effects in some cases where peripherals * undesirable side effects in some cases where peripherals
@ -1313,6 +1315,13 @@ pci_add_map(device_t pcib, device_t bus, device_t dev,
start = base; start = base;
end = base + (1 << ln2size) - 1; end = base + (1 << ln2size) - 1;
} }
if ((u_long)start != start) {
/* Wait a minute! this platform can't do this address. */
device_printf(bus,
"pci%d.%d.%x bar %#x start %#jx, too many bits.",
b, s, f, reg, (uintmax_t)start);
return (barlen);
}
resource_list_add(rl, type, reg, start, end, count); resource_list_add(rl, type, reg, start, end, count);
/* /*
@ -1321,8 +1330,12 @@ pci_add_map(device_t pcib, device_t bus, device_t dev,
*/ */
res = resource_list_alloc(rl, bus, dev, type, &reg, start, end, count, res = resource_list_alloc(rl, bus, dev, type, &reg, start, end, count,
prefetch ? RF_PREFETCHABLE : 0); prefetch ? RF_PREFETCHABLE : 0);
if (res != NULL) if (res != NULL) {
pci_write_config(dev, reg, rman_get_start(res), 4); pci_write_config(dev, reg, rman_get_start(res), 4);
if (ln2range == 64)
pci_write_config(dev, reg + 4,
rman_get_start(res) >> 32, 4);
}
return (barlen); return (barlen);
} }
@ -2139,7 +2152,7 @@ pci_alloc_map(device_t dev, device_t child, int type, int *rid,
struct resource_list *rl = &dinfo->resources; struct resource_list *rl = &dinfo->resources;
struct resource_list_entry *rle; struct resource_list_entry *rle;
struct resource *res; struct resource *res;
uint32_t map, testval; pci_addr_t map, testval;
int mapsize; int mapsize;
/* /*
@ -2153,6 +2166,8 @@ pci_alloc_map(device_t dev, device_t child, int type, int *rid,
map = pci_read_config(child, *rid, 4); map = pci_read_config(child, *rid, 4);
pci_write_config(child, *rid, 0xffffffff, 4); pci_write_config(child, *rid, 0xffffffff, 4);
testval = pci_read_config(child, *rid, 4); testval = pci_read_config(child, *rid, 4);
if (pci_maprange(testval) == 64)
map |= (pci_addr_t)pci_read_config(child, *rid + 4, 4) << 32;
if (pci_mapbase(testval) == 0) if (pci_mapbase(testval) == 0)
goto out; goto out;
if (pci_maptype(testval) & PCI_MAPMEM) { if (pci_maptype(testval) & PCI_MAPMEM) {
@ -2182,7 +2197,7 @@ pci_alloc_map(device_t dev, device_t child, int type, int *rid,
* another driver, which won't work. * another driver, which won't work.
*/ */
mapsize = pci_mapsize(testval); mapsize = pci_mapsize(testval);
count = 1 << mapsize; count = 1UL << mapsize;
if (RF_ALIGNMENT(flags) < mapsize) if (RF_ALIGNMENT(flags) < mapsize)
flags = (flags & ~RF_ALIGNMENT_MASK) | RF_ALIGNMENT_LOG2(mapsize); flags = (flags & ~RF_ALIGNMENT_MASK) | RF_ALIGNMENT_LOG2(mapsize);
@ -2213,6 +2228,8 @@ pci_alloc_map(device_t dev, device_t child, int type, int *rid,
map = rman_get_start(res); map = rman_get_start(res);
out:; out:;
pci_write_config(child, *rid, map, 4); pci_write_config(child, *rid, map, 4);
if (pci_maprange(testval) == 64)
pci_write_config(child, *rid + 4, map >> 32, 4);
return (res); return (res);
} }

View File

@ -88,6 +88,33 @@ static devclass_t pcib_devclass;
DEFINE_CLASS_0(pcib, pcib_driver, pcib_methods, sizeof(struct pcib_softc)); DEFINE_CLASS_0(pcib, pcib_driver, pcib_methods, sizeof(struct pcib_softc));
DRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, 0, 0); DRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, 0, 0);
/*
* Is the prefetch window open (eg, can we allocate memory in it?)
*/
static int
pcib_is_prefetch_open(struct pcib_softc *sc)
{
return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit);
}
/*
* Is the nonprefetch window open (eg, can we allocate memory in it?)
*/
static int
pcib_is_nonprefetch_open(struct pcib_softc *sc)
{
return (sc->membase > 0 && sc->membase < sc->memlimit);
}
/*
* Is the io window open (eg, can we allocate ports in it?)
*/
static int
pcib_is_io_open(struct pcib_softc *sc)
{
return (sc->iobase > 0 && sc->iobase < sc->iolimit);
}
/* /*
* Generic device interface * Generic device interface
*/ */
@ -225,8 +252,14 @@ pcib_attach_common(device_t dev)
device_printf(dev, " secondary bus %d\n", sc->secbus); device_printf(dev, " secondary bus %d\n", sc->secbus);
device_printf(dev, " subordinate bus %d\n", sc->subbus); device_printf(dev, " subordinate bus %d\n", sc->subbus);
device_printf(dev, " I/O decode 0x%x-0x%x\n", sc->iobase, sc->iolimit); device_printf(dev, " I/O decode 0x%x-0x%x\n", sc->iobase, sc->iolimit);
device_printf(dev, " memory decode 0x%x-0x%x\n", sc->membase, sc->memlimit); if (pcib_is_nonprefetch_open(sc))
device_printf(dev, " prefetched decode 0x%x-0x%x\n", sc->pmembase, sc->pmemlimit); device_printf(dev, " memory decode 0x%jx-0x%jx\n",
(uintmax_t)sc->membase, (uintmax_t)sc->memlimit);
if (pcib_is_prefetch_open(sc))
device_printf(dev, " prefetched decode 0x%jx-0x%jx\n",
(uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit);
else
device_printf(dev, " no prefetched decode\n");
if (sc->flags & PCIB_SUBTRACTIVE) if (sc->flags & PCIB_SUBTRACTIVE)
device_printf(dev, " Subtractively decoded bridge.\n"); device_printf(dev, " Subtractively decoded bridge.\n");
} }
@ -288,33 +321,6 @@ pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
return(ENOENT); return(ENOENT);
} }
/*
* Is the prefetch window open (eg, can we allocate memory in it?)
*/
static int
pcib_is_prefetch_open(struct pcib_softc *sc)
{
return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit);
}
/*
* Is the nonprefetch window open (eg, can we allocate memory in it?)
*/
static int
pcib_is_nonprefetch_open(struct pcib_softc *sc)
{
return (sc->membase > 0 && sc->membase < sc->memlimit);
}
/*
* Is the io window open (eg, can we allocate ports in it?)
*/
static int
pcib_is_io_open(struct pcib_softc *sc)
{
return (sc->iobase > 0 && sc->iobase < sc->iolimit);
}
/* /*
* We have to trap resource allocation requests and ensure that the bridge * We have to trap resource allocation requests and ensure that the bridge
* is set up to, or capable of handling them. * is set up to, or capable of handling them.
@ -444,11 +450,11 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
} }
if (!ok && bootverbose) if (!ok && bootverbose)
device_printf(dev, device_printf(dev,
"%s requested unsupported memory range " "%s requested unsupported memory range %#lx-%#lx "
"0x%lx-0x%lx (decoding 0x%x-0x%x, 0x%x-0x%x)\n", "(decoding %#jx-%#jx, %#jx-%#jx)\n",
device_get_nameunit(child), start, end, device_get_nameunit(child), start, end,
sc->membase, sc->memlimit, sc->pmembase, (uintmax_t)sc->membase, (uintmax_t)sc->memlimit,
sc->pmemlimit); (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit);
if (!ok) if (!ok)
return (NULL); return (NULL);
if (bootverbose) if (bootverbose)

View File

@ -43,13 +43,7 @@
#define PCI_MAXMAPS_1 2 /* max. no. of maps for PCI to PCI bridge */ #define PCI_MAXMAPS_1 2 /* max. no. of maps for PCI to PCI bridge */
#define PCI_MAXMAPS_2 1 /* max. no. of maps for CardBus bridge */ #define PCI_MAXMAPS_2 1 /* max. no. of maps for CardBus bridge */
/* pci_addr_t covers this system's PCI bus address space: 32 or 64 bit */ typedef uint64_t pci_addr_t;
#ifdef PCI_A64
typedef uint64_t pci_addr_t; /* uint64_t for system with 64bit addresses */
#else
typedef uint32_t pci_addr_t; /* uint64_t for system with 64bit addresses */
#endif
/* Interesting values for PCI power management */ /* Interesting values for PCI power management */
struct pcicfg_pp { struct pcicfg_pp {
@ -130,14 +124,8 @@ typedef struct pcicfg {
/* additional type 1 device config header information (PCI to PCI bridge) */ /* additional type 1 device config header information (PCI to PCI bridge) */
#ifdef PCI_A64
#define PCI_PPBMEMBASE(h,l) ((((pci_addr_t)(h) << 32) + ((l)<<16)) & ~0xfffff) #define PCI_PPBMEMBASE(h,l) ((((pci_addr_t)(h) << 32) + ((l)<<16)) & ~0xfffff)
#define PCI_PPBMEMLIMIT(h,l) ((((pci_addr_t)(h) << 32) + ((l)<<16)) | 0xfffff) #define PCI_PPBMEMLIMIT(h,l) ((((pci_addr_t)(h) << 32) + ((l)<<16)) | 0xfffff)
#else
#define PCI_PPBMEMBASE(h,l) (((l)<<16) & ~0xfffff)
#define PCI_PPBMEMLIMIT(h,l) (((l)<<16) | 0xfffff)
#endif /* PCI_A64 */
#define PCI_PPBIOBASE(h,l) ((((h)<<16) + ((l)<<8)) & ~0xfff) #define PCI_PPBIOBASE(h,l) ((((h)<<16) + ((l)<<8)) & ~0xfff)
#define PCI_PPBIOLIMIT(h,l) ((((h)<<16) + ((l)<<8)) | 0xfff) #define PCI_PPBIOLIMIT(h,l) ((((h)<<16) + ((l)<<8)) | 0xfff)