From b471e537624cbd601f007979b7ccbfd941d9d9c9 Mon Sep 17 00:00:00 2001 From: imp Date: Tue, 13 Apr 2004 19:31:57 +0000 Subject: 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. --- sys/dev/pci/pci.c | 77 ++++++++++++++++++++++++++++++++++++------------------- 1 file 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) -- cgit v1.1