Date: Thu, 1 Jan 2004 21:53:47 -0800 (PST) From: Warner Losh <imp@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 44670 for review Message-ID: <200401020553.i025rlX0074518@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=44670 Change 44670 by imp@imp_pacopaco on 2004/01/01 21:53:31 Integrate from newcard to get imp's power/resource stuff. Affected files ... .. //depot/projects/power/sys/dev/pci/pci.c#7 integrate .. //depot/projects/power/sys/dev/pci/pci_pci.c#4 integrate .. //depot/projects/power/sys/dev/pci/pci_private.h#5 integrate .. //depot/projects/power/sys/dev/pci/pci_user.c#4 integrate .. //depot/projects/power/sys/dev/pci/pcireg.h#4 integrate .. //depot/projects/power/sys/dev/pci/pcivar.h#4 integrate Differences ... ==== //depot/projects/power/sys/dev/pci/pci.c#7 (text+ko) ==== @@ -68,8 +68,9 @@ static int pci_porten(device_t pcib, int b, int s, int f); static int pci_memen(device_t pcib, int b, int s, int f); -static int pci_add_map(device_t pcib, int b, int s, int f, - int reg, struct resource_list *rl); +static int pci_add_map(device_t pcib, device_t bus, device_t dev, + int b, int s, int f, int reg, + struct resource_list *rl); static void pci_add_resources(device_t pcib, device_t bus, device_t dev); static int pci_probe(device_t dev); @@ -615,6 +616,7 @@ return (EINVAL); } pci_set_command_bit(dev, child, bit); + /* Some devices seem to need a brief stall here, what do to? */ command = PCI_READ_CONFIG(dev, child, PCIR_COMMAND, 2); if (command & bit) return (0); @@ -721,11 +723,12 @@ * register is a 32bit map register or 2 if it is a 64bit register. */ static int -pci_add_map(device_t pcib, int b, int s, int f, int reg, - struct resource_list *rl) +pci_add_map(device_t pcib, device_t bus, device_t dev, + int b, int s, int f, int reg, struct resource_list *rl) { uint32_t map; uint64_t base; + uint64_t start, end, count; uint8_t ln2size; uint8_t ln2range; uint32_t testval; @@ -733,7 +736,6 @@ int type; map = PCIB_READ_CONFIG(pcib, b, s, f, reg, 4); - PCIB_WRITE_CONFIG(pcib, b, s, f, reg, 0xffffffff, 4); testval = PCIB_READ_CONFIG(pcib, b, s, f, reg, 4); PCIB_WRITE_CONFIG(pcib, b, s, f, reg, map, 4); @@ -759,10 +761,9 @@ (type == SYS_RES_IOPORT && ln2size < 3)) return (1); - if (ln2range == 64) { + 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", @@ -778,9 +779,10 @@ /* * This code theoretically does the right thing, but has - * undesirable side effects in some cases where - * peripherals respond oddly to having these bits - * enabled. Leave them alone by default. + * undesirable side effects in some cases where peripherals + * respond oddly to having these bits enabled. Let the user + * be able to turn them off (since pci_enable_io_modes is 1 by + * default). */ if (pci_enable_io_modes) { /* Turn on resources that have been left off by a lazy BIOS */ @@ -802,13 +804,21 @@ } /* * If base is 0, then we have problems. It is best to ignore - * such entires for the moment. XXX + * such entires for the moment. These will be allocated later if + * the driver specifically requests them. */ if (base == 0) return 1; - resource_list_add(rl, type, reg, base, base + (1 << ln2size) - 1, - (1 << ln2size)); + start = base; + end = base + (1 << ln2size) - 1; + count = 1 << ln2size; + resource_list_add(rl, type, reg, start, end, count); + /* + * Not quite sure what to do on failure of allocating the resource + * since I can postulate several right answers. + */ + resource_list_alloc(rl, bus, dev, type, ®, start, end, count, 0); return ((ln2range == 64) ? 2 : 1); } @@ -824,14 +834,13 @@ b = cfg->bus; s = cfg->slot; f = cfg->func; - for (i = 0; i < cfg->nummaps;) { - i += pci_add_map(pcib, b, s, f, PCIR_BAR(i), rl); - } + for (i = 0; i < cfg->nummaps;) + i += pci_add_map(pcib, bus, dev, b, s, f, PCIR_BAR(i), rl); for (q = &pci_quirks[0]; q->devid; q++) { if (q->devid == ((cfg->device << 16) | cfg->vendor) && q->type == PCI_QUIRK_MAP_REG) - pci_add_map(pcib, b, s, f, q->arg1, rl); + pci_add_map(pcib, bus, dev, b, s, f, q->arg1, rl); } if (cfg->intpin > 0 && PCI_INTERRUPT_VALID(cfg->intline)) { @@ -892,6 +901,7 @@ pcib = device_get_parent(bus); dinfo->cfg.dev = device_add_child(bus, NULL, -1); device_set_ivars(dinfo->cfg.dev, dinfo); + pci_cfg_save(dinfo->cfg.dev, dinfo, 0); pci_cfg_restore(dinfo->cfg.dev, dinfo); pci_add_resources(pcib, bus, dinfo->cfg.dev); pci_print_verbose(dinfo); @@ -1421,18 +1431,74 @@ } #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) +{ + struct pci_devinfo *dinfo = device_get_ivars(child); + struct resource_list *rl = &dinfo->resources; + struct resource_list_entry *rle; + struct resource *res; + uint32_t map, testval; + + /* + * Weed out the bogons, and figure out how large the BAR/map is. + */ + 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); + + /* + * 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). + */ + count = 1 << pci_mapsize(testval); + 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); + } + 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; + 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); + return (res); +} + + struct resource * pci_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct pci_devinfo *dinfo = device_get_ivars(child); struct resource_list *rl = &dinfo->resources; + struct resource_list_entry *rle; pcicfgregs *cfg = &dinfo->cfg; /* * Perform lazy resource allocation - * - * XXX add support here for SYS_RES_IOPORT and SYS_RES_MEMORY */ if (device_get_parent(child) == dev) { switch (type) { @@ -1458,16 +1524,39 @@ if (*rid < PCIR_BAR(cfg->nummaps)) { /* * Enable the I/O mode. We should - * also be allocating resources - * too. XXX + * also be assigning resources too + * when none are present. The + * resource_list_alloc kind of sorta does + * this... */ if (PCI_ENABLE_IO(dev, child, type)) return (NULL); } + rle = resource_list_find(rl, type, *rid); + if (rle == NULL) + return (pci_alloc_map(dev, child, type, rid, + start, end, count, flags)); break; } + /* + * If we've already allocated the resource, then + * return it now. But first we may need to activate + * it, since we don't allocate the resource as active + * above. Normally this would be done down in the + * nexus, but since we short-circuit that path we have + * to do its job here. Not sure if we should free the + * resource if it fails to activate. + */ + 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 ((flags & RF_ACTIVE) && + bus_generic_activate_resource(dev, child, type, + *rid, rle->res) != 0) + return NULL; + return (rle->res); + } } - return (resource_list_alloc(rl, dev, child, type, rid, start, end, count, flags)); } @@ -1511,13 +1600,9 @@ struct resource_list * pci_get_resource_list (device_t dev, device_t child) { - struct pci_devinfo * dinfo = device_get_ivars(child); - struct resource_list * rl = &dinfo->resources; + struct pci_devinfo *dinfo = device_get_ivars(child); - if (!rl) - return (NULL); - - return (rl); + return (&dinfo->resources); } uint32_t @@ -1604,35 +1689,77 @@ static void pci_cfg_restore(device_t dev, struct pci_devinfo *dinfo) { -#define NBAR 7 int i; - uint32_t bar[NBAR]; + /* + * Only do header type 0 devices. Type 1 devices are bridges, which + * we know need special treatment. Type 2 devices are cardbus bridges + * which also require special treatment. Other types are unknown, and + * we err on the side of safety by ignoring them. + */ if (dinfo->cfg.hdrtype != 0) return; - for (i = 0; i < NBAR; i++) - bar[i] = pci_read_config(dev, PCIR_MAPS + i * 4, 4); printf("pci%d:%d:%d: setting power state D0\n", dinfo->cfg.bus, dinfo->cfg.slot, dinfo->cfg.func); pci_set_powerstate(dev, PCI_POWERSTATE_D0); - for (i = 0; i < NBAR; i++) - pci_write_config(dev, PCIR_MAPS + i * 4, bar[i], 4); + for (i = 0; i < dinfo->cfg.nummaps; i++) + pci_write_config(dev, PCIR_MAPS + i * 4, dinfo->cfg.bar[i], 4); + pci_write_config(dev, PCIR_COMMAND, dinfo->cfg.cmdreg, 2); + pci_write_config(dev, PCIR_INTLINE, dinfo->cfg.intline, 1); + pci_write_config(dev, PCIR_INTPIN, dinfo->cfg.intpin, 1); pci_write_config(dev, PCIR_MINGNT, dinfo->cfg.mingnt, 1); pci_write_config(dev, PCIR_MAXLAT, dinfo->cfg.maxlat, 1); - if (dinfo->cfg.intpin > 0 && PCI_INTERRUPT_VALID(dinfo->cfg.intline)) - dinfo->cfg.intline = PCI_ASSIGN_INTERRUPT( - device_get_parent(dev), dev); - pci_write_config(dev, PCIR_INTLINE, dinfo->cfg.intline, 1); - pci_write_config(dev, PCIR_INTPIN, dinfo->cfg.intpin, 1); + pci_write_config(dev, PCIR_CACHELNSZ, dinfo->cfg.cachelnsz, 1); + pci_write_config(dev, PCIR_LATTIMER, dinfo->cfg.lattimer, 1); } static void pci_cfg_save(device_t dev, struct pci_devinfo *dinfo, int setstate) { + int i; uint32_t cls; + /* + * Only do header type 0 devices. Type 1 devices are bridges, which + * we know need special treatment. Type 2 devices are cardbus bridges + * which also require special treatment. Other types are unknown, and + * we err on the side of safety by ignoring them. Powering down + * bridges should not be undertaken lightly. + */ if (dinfo->cfg.hdrtype != 0) return; + for (i = 0; i < dinfo->cfg.nummaps; i++) + dinfo->cfg.bar[i] = pci_read_config(dev, PCIR_MAPS + i * 4, 4); + + /* + * Some drivers apparently write to these registers w/o + * updating our cahced copy. No harm happens if we update the + * copy, so do so here so we can restore them. The COMMAND + * register is modified by the bus w/o updating the cache. This + * should represent the normally writable portion of the 'defined' + * part of type 0 headers. In theory we also need to save/restore + * the PCI capability structures we know about, but apart from power + * we don't know any that are writable. + */ + dinfo->cfg.cmdreg = pci_read_config(dev, PCIR_COMMAND, 2); + dinfo->cfg.intline = pci_read_config(dev, PCIR_INTLINE, 1); + dinfo->cfg.intpin = pci_read_config(dev, PCIR_INTPIN, 1); + dinfo->cfg.mingnt = pci_read_config(dev, PCIR_MINGNT, 1); + dinfo->cfg.maxlat = pci_read_config(dev, PCIR_MAXLAT, 1); + dinfo->cfg.cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1); + dinfo->cfg.lattimer = pci_read_config(dev, PCIR_LATTIMER, 1); + + /* + * don't set the state for display devices and for memory devices + * since bad things happen. we should (a) have drivers that can easily + * detach and (b) use generic drivers for these devices so that some + * device actually attaches. We need to make sure that when we + * implement (a) we don't power the device down on a reattach. + * + * John and Nate also tell me that we should be running the power up + * and power down hooks when we change power state for those nodes + * that have ACPI hooks in the tree. + */ cls = pci_get_class(dev); if (setstate && cls != PCIC_DISPLAY && cls != PCIC_MEMORY) { pci_set_powerstate(dev, PCI_POWERSTATE_D3); ==== //depot/projects/power/sys/dev/pci/pci_pci.c#4 (text+ko) ==== @@ -311,144 +311,133 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { - struct pcib_softc *sc = device_get_softc(dev); - int ok; + struct pcib_softc *sc = device_get_softc(dev); + int ok; - /* - * If this is a "default" allocation against this rid, we can't work - * out where it's coming from (we should actually never see these) so we - * just have to punt. - */ - if ((start == 0) && (end == ~0)) { - device_printf(dev, "can't decode default resource id %d for %s%d, bypassing\n", - *rid, device_get_name(child), device_get_unit(child)); - } else { /* * Fail the allocation for this range if it's not supported. */ switch (type) { case SYS_RES_IOPORT: - ok = 1; - if (!pcib_is_isa_io(start)) { - ok = 0; - if (pcib_is_io_open(sc)) - ok = (start >= sc->iobase && end <= sc->iolimit); - if (!pci_allow_unsupported_io_range) { - if (!ok) { - if (start < sc->iobase) - start = sc->iobase; - if (end > sc->iolimit) - end = sc->iolimit; - } - } else { - if (start < sc->iobase) - printf("start (%lx) < sc->iobase (%x)\n", start, - sc->iobase); - if (end > sc->iolimit) - printf("end (%lx) > sc->iolimit (%x)\n", - end, sc->iolimit); - if (end < start) - printf("end (%lx) < start (%lx)\n", end, start); + ok = 1; + if (!pcib_is_isa_io(start)) { + ok = 0; + if (pcib_is_io_open(sc)) + ok = (start >= sc->iobase && end <= sc->iolimit); + if (!pci_allow_unsupported_io_range) { + if (!ok) { + if (start < sc->iobase) + start = sc->iobase; + if (end > sc->iolimit) + end = sc->iolimit; + } + } else { + if (start < sc->iobase) + printf("start (%lx) < sc->iobase (%x)\n", start, + sc->iobase); + if (end > sc->iolimit) + printf("end (%lx) > sc->iolimit (%x)\n", + end, sc->iolimit); + if (end < start) + printf("end (%lx) < start (%lx)\n", end, start); + } + } + if (end < start) { + start = 0; + end = 0; + ok = 0; + } + if (!ok) { + device_printf(dev, "device %s%d requested unsupported I/O " + "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n", + device_get_name(child), device_get_unit(child), start, end, + sc->iobase, sc->iolimit); + return (NULL); } - } - if (end < start) { - start = 0; - end = 0; - ok = 0; - } - if (!ok) { - device_printf(dev, "device %s%d requested unsupported I/O " - "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n", - device_get_name(child), device_get_unit(child), start, end, - sc->iobase, sc->iolimit); - return (NULL); - } - if (bootverbose) - device_printf(sc->dev, "device %s%d requested decoded I/O range 0x%lx-0x%lx\n", - device_get_name(child), device_get_unit(child), start, end); - break; + if (bootverbose) + device_printf(sc->dev, "device %s%d requested decoded I/O range 0x%lx-0x%lx\n", + device_get_name(child), device_get_unit(child), start, end); + break; case SYS_RES_MEMORY: - ok = 1; - if (!pcib_is_isa_mem(start)) { - ok = 0; - if (pcib_is_nonprefetch_open(sc)) - ok = ok || (start >= sc->membase && end <= sc->memlimit); - if (pcib_is_prefetch_open(sc)) - ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit); - if (!pci_allow_unsupported_io_range) { - if (!ok) { - ok = 1; - if (flags & RF_PREFETCHABLE) { - if (pcib_is_prefetch_open(sc)) { - if (start < sc->pmembase) - start = sc->pmembase; - if (end > sc->pmemlimit) - end = sc->pmemlimit; - } else { - ok = 0; - } - } else { /* non-prefetchable */ - if (pcib_is_nonprefetch_open(sc)) { - if (start < sc->membase) - start = sc->membase; - if (end > sc->memlimit) - end = sc->memlimit; - } else { - ok = 0; - } + ok = 1; + if (!pcib_is_isa_mem(start)) { + ok = 0; + if (pcib_is_nonprefetch_open(sc)) + ok = ok || (start >= sc->membase && end <= sc->memlimit); + if (pcib_is_prefetch_open(sc)) + ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit); + if (!pci_allow_unsupported_io_range) { + if (!ok) { + ok = 1; + if (flags & RF_PREFETCHABLE) { + if (pcib_is_prefetch_open(sc)) { + if (start < sc->pmembase) + start = sc->pmembase; + if (end > sc->pmemlimit) + end = sc->pmemlimit; + } else { + ok = 0; + } + } else { /* non-prefetchable */ + if (pcib_is_nonprefetch_open(sc)) { + if (start < sc->membase) + start = sc->membase; + if (end > sc->memlimit) + end = sc->memlimit; + } else { + ok = 0; + } + } + } + } else if (!ok) { + ok = 1; /* pci_allow_unsupported_ranges -> always ok */ + if (pcib_is_nonprefetch_open(sc)) { + if (start < sc->membase) + printf("start (%lx) < sc->membase (%x)\n", + start, sc->membase); + if (end > sc->memlimit) + printf("end (%lx) > sc->memlimit (%x)\n", + end, sc->memlimit); + } + if (pcib_is_prefetch_open(sc)) { + if (start < sc->pmembase) + printf("start (%lx) < sc->pmembase (%x)\n", + start, sc->pmembase); + if (end > sc->pmemlimit) + printf("end (%lx) > sc->pmemlimit (%x)\n", + end, sc->memlimit); + } + if (end < start) + printf("end (%lx) < start (%lx)\n", end, start); } - } - } else if (!ok) { - ok = 1; /* pci_allow_unsupported_ranges -> always ok */ - if (pcib_is_nonprefetch_open(sc)) { - if (start < sc->membase) - printf("start (%lx) < sc->membase (%x)\n", - start, sc->membase); - if (end > sc->memlimit) - printf("end (%lx) > sc->memlimit (%x)\n", - end, sc->memlimit); - } - if (pcib_is_prefetch_open(sc)) { - if (start < sc->pmembase) - printf("start (%lx) < sc->pmembase (%x)\n", - start, sc->pmembase); - if (end > sc->pmemlimit) - printf("end (%lx) > sc->pmemlimit (%x)\n", - end, sc->memlimit); - } - if (end < start) - printf("end (%lx) < start (%lx)\n", end, start); + } + if (end < start) { + start = 0; + end = 0; + ok = 0; } - } - if (end < start) { - start = 0; - end = 0; - ok = 0; - } - if (!ok && bootverbose) - device_printf(dev, - "device %s%d requested unsupported memory range " - "0x%lx-0x%lx (decoding 0x%x-0x%x, 0x%x-0x%x)\n", - device_get_name(child), device_get_unit(child), start, - end, sc->membase, sc->memlimit, sc->pmembase, - sc->pmemlimit); - if (!ok) - return (NULL); - if (bootverbose) - device_printf(sc->dev, "device %s%d requested decoded memory range 0x%lx-0x%lx\n", - device_get_name(child), device_get_unit(child), start, end); - break; + if (!ok && bootverbose) + device_printf(dev, + "device %s%d requested unsupported memory range " + "0x%lx-0x%lx (decoding 0x%x-0x%x, 0x%x-0x%x)\n", + device_get_name(child), device_get_unit(child), start, + end, sc->membase, sc->memlimit, sc->pmembase, + sc->pmemlimit); + if (!ok) + return (NULL); + if (bootverbose) + device_printf(sc->dev,"device %s%d requested decoded memory range 0x%lx-0x%lx\n", + device_get_name(child), device_get_unit(child), start, end); + break; default: - break; + break; } - } - - /* - * Bridge is OK decoding this resource, so pass it up. - */ - return(bus_generic_alloc_resource(dev, child, type, rid, start, end, count, flags)); + /* + * Bridge is OK decoding this resource, so pass it up. + */ + return (bus_generic_alloc_resource(dev, child, type, rid, start, end, count, flags)); } /* ==== //depot/projects/power/sys/dev/pci/pci_private.h#5 (text+ko) ==== ==== //depot/projects/power/sys/dev/pci/pci_user.c#4 (text+ko) ==== @@ -429,4 +429,3 @@ return (error); } - ==== //depot/projects/power/sys/dev/pci/pcireg.h#4 (text+ko) ==== ==== //depot/projects/power/sys/dev/pci/pcivar.h#4 (text+ko) ==== @@ -66,16 +66,12 @@ uint16_t msi_data; /* Location of MSI data word */ }; -/* Additional data saved on power events */ -struct pci_save -{ - uint32_t bar[7]; /* 7 bars to save */ -}; - /* config header information common to all header types */ typedef struct pcicfg { struct device *dev; /* device which owns this */ + uint32_t bar[PCI_MAXMAPS_0]; /* BARs */ + uint16_t subvendor; /* card vendor ID */ uint16_t subdevice; /* card device ID, assigned by card vendor */ uint16_t vendor; /* chip vendor ID */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200401020553.i025rlX0074518>
