summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2004-04-13 19:31:57 +0000
committerimp <imp@FreeBSD.org>2004-04-13 19:31:57 +0000
commitb471e537624cbd601f007979b7ccbfd941d9d9c9 (patch)
treef7009049ccb5be55fbb5a937d88cbdd0ea71840d
parent942f7be747ecf578aee72ff9efbf45221b6ca95e (diff)
downloadFreeBSD-src-b471e537624cbd601f007979b7ccbfd941d9d9c9.zip
FreeBSD-src-b471e537624cbd601f007979b7ccbfd941d9d9c9.tar.gz
Some devices have what appear to be invalid BARs. They are invalid in
the sense that any write to them reads back as a 0. This presents a problem to our resource allocation scheme. If we encounter such vars, the code now treats them as special, allowing any allocation against them to succeed. I've not seen anything in the standard to clearify what host software should do when it encounters these sorts of BARs. Also cleaned up some output while I'm here and add commmented out bootverbose lines until I'm ready to reduce the verbosity of boot messages. This gets a number of south bridges and ata controllers made mostly by VIA, AMD and nVidia working again. Thanks to Soren Schmidt for his help in coming up with this patch.
-rw-r--r--sys/dev/pci/pci.c77
1 files changed, 51 insertions, 26 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 63ae28b..c82d1d1 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -1446,9 +1446,6 @@ DB_SHOW_COMMAND(pciregs, db_pci_dump)
}
#endif /* DDB */
-/*
- * XXX I'm not sure the following is good for 64-bit bars.
- */
static struct resource *
pci_alloc_map(device_t dev, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
@@ -1461,48 +1458,72 @@ pci_alloc_map(device_t dev, device_t child, int type, int *rid,
int mapsize;
/*
- * Weed out the bogons, and figure out how large the BAR/map is.
+ * Weed out the bogons, and figure out how large the BAR/map
+ * is. Note: some devices have been found that are '0' after
+ * a write of 0xffffffff. We view these as 'special' and
+ * allow drivers to allocate whatever they want with them. So
+ * far, these BARs have only appeared in certain south bridges
+ * and ata controllers made by VIA, nVidia and AMD.
*/
+ res = NULL;
map = pci_read_config(child, *rid, 4);
- if (pci_maptype(map) & PCI_MAPMEM) {
- if (type != SYS_RES_MEMORY) {
- device_printf(child, "rid %#x says memory, driver wants %d failed.\n", *rid, type);
- return (NULL);
- }
- } else {
- if (type != SYS_RES_IOPORT) {
- device_printf(child, "rid %#x says ioport, driver wants %d failed.\n", *rid, type);
- return (NULL);
- }
- }
pci_write_config(child, *rid, 0xffffffff, 4);
testval = pci_read_config(child, *rid, 4);
-
+ if (testval != 0) {
+ if (pci_maptype(testval) & PCI_MAPMEM) {
+ if (type != SYS_RES_MEMORY) {
+ device_printf(child,
+ "failed: rid %#x is memory, requested %d\n",
+ *rid, type);
+ goto out;
+ }
+ } else {
+ if (type != SYS_RES_IOPORT) {
+ device_printf(child,
+ "failed: rid %#x is ioport, requested %d\n",
+ *rid, type);
+ goto out;
+ }
+ }
+ /*
+ * For real BARs, we need to override the size that
+ * the driver requests, because that's what the BAR
+ * actually uses and we would otherwise have a
+ * situation where we might allocate the excess to
+ * another driver, which won't work.
+ */
+ mapsize = pci_mapsize(testval);
+ count = 1 << mapsize;
+ if (RF_ALIGNMENT(flags) < mapsize)
+ flags = (flags & ~RF_ALIGNMENT_MASK) | RF_ALIGNMENT_LOG2(mapsize);
+ }
+ else {
+ /* if (bootverbose) */
+ device_printf(child, "BAD BAR: skipping checks\n");
+ }
+
/*
* Allocate enough resource, and then write back the
- * appropriate bar for that resource (this is the part
- * I'm not sure is good for 64-bit bars).
+ * appropriate bar for that resource.
*/
- mapsize = pci_mapsize(testval);
- count = 1 << mapsize;
- if (RF_ALIGNMENT(flags) < mapsize)
- flags = (flags & ~RF_ALIGNMENT_MASK) | RF_ALIGNMENT_LOG2(mapsize);
res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, type, rid,
start, end, count, flags);
if (res == NULL) {
device_printf(child, "%#lx bytes of rid %#x res %d failed.\n",
count, *rid, type);
- pci_write_config(child, *rid, map, 4);
- return (NULL);
+ goto out;
}
resource_list_add(rl, type, *rid, start, end, count);
rle = resource_list_find(rl, type, *rid);
if (rle == NULL)
panic("pci_alloc_map: unexpedly can't find resource.");
rle->res = res;
+ /* if (bootverbose) */
device_printf(child, "Lazy allocation of %#lx bytes rid %#x type %d at %#lx\n",
count, *rid, type, rman_get_start(res));
- pci_write_config(child, *rid, rman_get_start(res), 4);
+ map = rman_get_start(res);
+out:;
+ pci_write_config(child, *rid, map, 4);
return (res);
}
@@ -1568,7 +1589,11 @@ pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
*/
rle = resource_list_find(rl, type, *rid);
if (rle != NULL && rle->res != NULL) {
- device_printf(child, "Bus reserved %#lx bytes for rid %#x type %d at %#lx\n", rman_get_size(rle->res), *rid, type, rman_get_start(rle->res));
+ /* if (bootverbose) */
+ device_printf(child,
+ "Reserved %#lx bytes for rid %#x type %d at %#lx\n",
+ rman_get_size(rle->res), *rid, type,
+ rman_get_start(rle->res));
if ((flags & RF_ACTIVE) &&
bus_generic_activate_resource(dev, child, type,
*rid, rle->res) != 0)
OpenPOWER on IntegriCloud