summaryrefslogtreecommitdiffstats
path: root/sys/dev/pci
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2006-10-30 19:18:46 +0000
committerimp <imp@FreeBSD.org>2006-10-30 19:18:46 +0000
commit4bea281f9ade627bae92397e800c3f3b5a307283 (patch)
tree4fd056502338d70664fa352221552819df190c2c /sys/dev/pci
parent95289e010fb3674d4ab102b64dcae134233b1b1c (diff)
downloadFreeBSD-src-4bea281f9ade627bae92397e800c3f3b5a307283.zip
FreeBSD-src-4bea281f9ade627bae92397e800c3f3b5a307283.tar.gz
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.
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/pci.c41
-rw-r--r--sys/dev/pci/pci_pci.c72
-rw-r--r--sys/dev/pci/pcivar.h14
3 files changed, 69 insertions, 58 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index e534548..bbdff0f 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -245,7 +245,7 @@ pci_find_device(uint16_t vendor, uint16_t device)
/* return base address of memory or port map */
static uint32_t
-pci_mapbase(unsigned mapreg)
+pci_mapbase(uint32_t mapreg)
{
int mask = 0x03;
if ((mapreg & 0x01) == 0)
@@ -275,7 +275,7 @@ pci_maptype(unsigned mapreg)
/* return log2 of map size decoded for memory or port map */
static int
-pci_mapsize(unsigned testval)
+pci_mapsize(uint32_t testval)
{
int ln2size;
@@ -1211,8 +1211,8 @@ pci_add_map(device_t pcib, device_t bus, device_t dev,
int prefetch)
{
uint32_t map;
- uint64_t base;
- uint64_t start, end, count;
+ pci_addr_t base;
+ pci_addr_t start, end, count;
uint8_t ln2size;
uint8_t ln2range;
uint32_t testval;
@@ -1252,11 +1252,9 @@ pci_add_map(device_t pcib, device_t bus, device_t dev,
if (ln2range == 64)
/* Read the other half of a 64bit map register */
base |= (uint64_t) PCIB_READ_CONFIG(pcib, b, s, f, reg + 4, 4) << 32;
-
if (bootverbose) {
- printf("\tmap[%02x]: type %x, range %2d, base %08x, size %2d",
- reg, pci_maptype(map), ln2range,
- (unsigned int) base, ln2size);
+ printf("\tmap[%02x]: type %x, range %2d, base %#jx, size %2d",
+ reg, pci_maptype(map), ln2range, (uintmax_t)base, ln2size);
if (type == SYS_RES_IOPORT && !pci_porten(pcib, b, s, f))
printf(", port disabled\n");
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))
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
* 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;
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);
/*
@@ -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,
prefetch ? RF_PREFETCHABLE : 0);
- if (res != NULL)
+ if (res != NULL) {
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);
}
@@ -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_entry *rle;
struct resource *res;
- uint32_t map, testval;
+ pci_addr_t map, testval;
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);
pci_write_config(child, *rid, 0xffffffff, 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)
goto out;
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.
*/
mapsize = pci_mapsize(testval);
- count = 1 << mapsize;
+ count = 1UL << mapsize;
if (RF_ALIGNMENT(flags) < 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);
out:;
pci_write_config(child, *rid, map, 4);
+ if (pci_maprange(testval) == 64)
+ pci_write_config(child, *rid + 4, map >> 32, 4);
return (res);
}
diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c
index b883e2c..50b64f7 100644
--- a/sys/dev/pci/pci_pci.c
+++ b/sys/dev/pci/pci_pci.c
@@ -89,6 +89,33 @@ DEFINE_CLASS_0(pcib, pcib_driver, pcib_methods, sizeof(struct pcib_softc));
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
*/
static int
@@ -225,8 +252,14 @@ pcib_attach_common(device_t dev)
device_printf(dev, " secondary bus %d\n", sc->secbus);
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, " memory decode 0x%x-0x%x\n", sc->membase, sc->memlimit);
- device_printf(dev, " prefetched decode 0x%x-0x%x\n", sc->pmembase, sc->pmemlimit);
+ if (pcib_is_nonprefetch_open(sc))
+ 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)
device_printf(dev, " Subtractively decoded bridge.\n");
}
@@ -289,33 +322,6 @@ pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
}
/*
- * 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
* 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)
device_printf(dev,
- "%s requested unsupported memory range "
- "0x%lx-0x%lx (decoding 0x%x-0x%x, 0x%x-0x%x)\n",
+ "%s requested unsupported memory range %#lx-%#lx "
+ "(decoding %#jx-%#jx, %#jx-%#jx)\n",
device_get_nameunit(child), start, end,
- sc->membase, sc->memlimit, sc->pmembase,
- sc->pmemlimit);
+ (uintmax_t)sc->membase, (uintmax_t)sc->memlimit,
+ (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit);
if (!ok)
return (NULL);
if (bootverbose)
diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h
index fc37941..1c026c9 100644
--- a/sys/dev/pci/pcivar.h
+++ b/sys/dev/pci/pcivar.h
@@ -43,13 +43,7 @@
#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 */
-/* pci_addr_t covers this system's PCI bus address space: 32 or 64 bit */
-
-#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
+typedef uint64_t pci_addr_t;
/* Interesting values for PCI power management */
struct pcicfg_pp {
@@ -130,14 +124,8 @@ typedef struct pcicfg {
/* 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_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_PPBIOLIMIT(h,l) ((((h)<<16) + ((l)<<8)) | 0xfff)
OpenPOWER on IntegriCloud