Date: Fri, 4 Mar 2011 04:13:12 GMT From: John Baldwin <jhb@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 189478 for review Message-ID: <201103040413.p244DCU9073396@skunkworks.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@189478?ac=10 Change 189478 by jhb@jhb_kavik on 2011/03/04 04:12:13 Checkpoint work to track BARs explicitly so we can report all BARs to userland. There is room here for consolidating some more duplicated code. This isn't quite finished as pm_enabled isn't correct yet for "lazy" allocations. Affected files ... .. //depot/projects/pci/sys/dev/pci/pci.c#2 edit .. //depot/projects/pci/sys/dev/pci/pci_private.h#2 edit .. //depot/projects/pci/sys/dev/pci/pci_user.c#2 edit .. //depot/projects/pci/sys/dev/pci/pcivar.h#2 edit Differences ... ==== //depot/projects/pci/sys/dev/pci/pci.c#2 (text+ko) ==== @@ -531,6 +531,7 @@ cfg->mfdev = (cfg->hdrtype & PCIM_MFDEV) != 0; cfg->hdrtype &= ~PCIM_MFDEV; + STAILQ_INIT(&cfg->maps); pci_fixancient(cfg); pci_hdrtypedata(pcib, b, s, f, cfg); @@ -2084,6 +2085,7 @@ pci_freecfg(struct pci_devinfo *dinfo) { struct devlist *devlist_head; + struct pci_map *pm, *next; int i; devlist_head = &pci_devq; @@ -2097,6 +2099,9 @@ free(dinfo->cfg.vpd.vpd_w[i].value, M_DEVBUF); free(dinfo->cfg.vpd.vpd_w, M_DEVBUF); } + STAILQ_FOREACH_SAFE(pm, &dinfo->cfg.maps, pm_link, next) { + free(pm, M_DEVBUF); + } STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links); free(dinfo, M_DEVBUF); @@ -2368,8 +2373,25 @@ return (pci_read_config(dev, PCIR_COMMAND, 2) & PCIM_CMD_MEMEN) != 0; } +static pci_addr_t +pci_read_bar(device_t dev, int reg) +{ + pci_addr_t map; + int ln2range; + + /* The device ROM BAR is always a 32-bit memory BAR. */ + if (reg == PCIR_BIOS) + return (pci_read_config(dev, PCIR_BIOS, 4)); + + map = pci_read_config(dev, reg, 4); + ln2range = pci_maprange(map); + if (ln2range == 64) + map |= (pci_addr_t)pci_read_config(dev, reg + 4, 4) << 32; + return (map); +} + static void -pci_read_bar(device_t dev, int reg, pci_addr_t *mapp, pci_addr_t *testvalp) +pci_size_bar(device_t dev, int reg, pci_addr_t *mapp, pci_addr_t *testvalp) { pci_addr_t map, testval; int ln2range; @@ -2447,6 +2469,43 @@ pci_write_config(dev, reg + 4, base >> 32, 4); } +struct pci_map * +pci_find_bar(device_t dev, int reg) +{ + struct pci_devinfo *dinfo; + struct pci_map *pm; + + dinfo = device_get_ivars(dev); + STAILQ_FOREACH(pm, &dinfo->cfg.maps, pm_link) { + if (pm->pm_reg == bio->pbi_reg) + return (pm); + } + return (NULL); +} + +struct pci_map * +pci_add_bar(device_t dev, int reg) +{ + struct pci_devinfo *dinfo; + struct pci_map *pm, *prev; + + dinfo = device_get_ivars(dev); + pm = malloc(sizeof(*pm), M_DEVBUF, M_WAITOK | M_ZERO); + pm->pm_reg = reg; + STAILQ_FOREACH(prev, &dinfo->cfg.maps, pm_link) { + KASSERT(prev->pm_reg != pm->pm_reg, ("duplicate map %02x", + reg)); + if (STAILQ_NEXT(prev) == NULL || STAILQ_NEXT(prev)->pm_reg > + pm->pm_reg) + break; + } + if (prev != NULL) + STAILQ_INSERT_AFTER(&dinfo->cfg.maps, prev, pm, pm_link); + else + STAILQ_INSERT_TAIL(&dinfo->cfg.maps, pm, pm_link); + return (pm); +} + /* * Add a resource based on a pci map register. Return 1 if the map * register is a 32bit map register or 2 if it is a 64bit register. @@ -2455,13 +2514,14 @@ pci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl, int force, int prefetch) { + struct pci_map *pm; pci_addr_t base, map, testval; pci_addr_t start, end, count; int barlen, basezero, maprange, mapsize, type; uint16_t cmd; struct resource *res; - pci_read_bar(dev, reg, &map, &testval); + pci_size_bar(dev, reg, &map, &testval); if (PCI_BAR_MEM(map)) { type = SYS_RES_MEMORY; if (map & PCIM_BAR_MEM_PREFETCH) @@ -2491,6 +2551,10 @@ (type == SYS_RES_IOPORT && mapsize < 2)) return (barlen); + /* Save a record of this BAR. */ + pm = pci_add_bar(dev, reg); + pm->pm_value = map; + pm->pm_size = mapsize; if (bootverbose) { printf("\tmap[%02x]: type %s, range %2d, base %#jx, size %2d", reg, pci_maptype(map), maprange, (uintmax_t)base, mapsize); @@ -2576,9 +2640,12 @@ */ resource_list_delete(rl, type, reg); start = 0; - } else + } else { start = rman_get_start(res); + pm->pm_enabled = 1; + } pci_write_bar(dev, reg, start); + pm->pm_value = pm_read_bar(dev, reg); return (barlen); } @@ -3713,31 +3780,44 @@ struct resource_list *rl = &dinfo->resources; struct resource_list_entry *rle; struct resource *res; + struct pci_map *pm; pci_addr_t map, testval; int mapsize; - /* - * Weed out the bogons, and figure out how large the BAR/map - * is. Bars that read back 0 here are bogus and unimplemented. - * Note: atapci in legacy mode are special and handled elsewhere - * in the code. If you have a atapci device in legacy mode and - * it fails here, that other code is broken. - */ res = NULL; - pci_read_bar(child, *rid, &map, &testval); + + pm = pci_find_bar(dev, *rid); + if (pm != NULL) { + /* This is a BAR that we failed to allocate earlier. */ + mapsize = pm->pm_size; + map = pci_read_bar(child, *rid); + } else { + /* + * Weed out the bogons, and figure out how large the + * BAR/map is. BARs that read back 0 here are bogus + * and unimplemented. Note: atapci in legacy mode are + * special and handled elsewhere in the code. If you + * have a atapci device in legacy mode and it fails + * here, that other code is broken. + */ + pci_size_bar(child, *rid, &map, &testval); - /* - * Determine the size of the BAR and ignore BARs with a size - * of 0. Device ROM BARs use a different mask value. - */ - if (*rid == PCIR_BIOS) - mapsize = pci_romsize(testval); - else - mapsize = pci_mapsize(testval); - if (mapsize == 0) - goto out; + /* + * Determine the size of the BAR and ignore BARs with a size + * of 0. Device ROM BARs use a different mask value. + */ + if (*rid == PCIR_BIOS) + mapsize = pci_romsize(testval); + else + mapsize = pci_mapsize(testval); + if (mapsize == 0) + goto out; + pm = pci_add_bar(child, *rid); + pm->pm_value = map; + pm->pm_size = mapsize; + } - if (PCI_BAR_MEM(testval) || *rid == PCIR_BIOS) { + if (PCI_BAR_MEM(map) || *rid == PCIR_BIOS) { if (type != SYS_RES_MEMORY) { if (bootverbose) device_printf(dev, @@ -3767,12 +3847,12 @@ count = (pci_addr_t)1 << mapsize; if (RF_ALIGNMENT(flags) < mapsize) flags = (flags & ~RF_ALIGNMENT_MASK) | RF_ALIGNMENT_LOG2(mapsize); - if (PCI_BAR_MEM(testval) && (testval & PCIM_BAR_MEM_PREFETCH)) + if (PCI_BAR_MEM(map) && (map & PCIM_BAR_MEM_PREFETCH)) flags |= RF_PREFETCHABLE; /* * Allocate enough resource, and then write back the - * appropriate bar for that resource. + * appropriate BAR for that resource. */ res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, type, rid, start, end, count, flags & ~RF_ACTIVE); @@ -3797,6 +3877,7 @@ count, *rid, type, rman_get_start(res)); map = rman_get_start(res); pci_write_bar(child, *rid, map); + pm->pm_value = pci_read_bar(child, *rid); out:; return (res); } ==== //depot/projects/pci/sys/dev/pci/pci_private.h#2 (text+ko) ==== @@ -104,6 +104,7 @@ int pci_assign_interrupt_method(device_t dev, device_t child); int pci_resume(device_t dev); int pci_suspend(device_t dev); +struct pci_map *pci_find_bar(device_t dev, int reg); /** Restore the config register state. The state must be previously * saved with pci_cfg_save. However, the pci bus driver takes care of ==== //depot/projects/pci/sys/dev/pci/pci_user.c#2 (text+ko) ==== @@ -310,7 +310,7 @@ struct pci_bar_io *bio; struct pci_match_conf *pattern_buf; struct resource_list_entry *rle; - uint32_t value; + struct pci_map *pm; size_t confsz, iolen, pbufsz; int error, ionum, i, num_patterns; #ifdef PRE7_COMPAT @@ -685,54 +685,14 @@ error = ENODEV; break; } - dinfo = device_get_ivars(pcidev); - - /* - * Look for a resource list entry matching the requested BAR. - * - * XXX: This will not find BARs that are not initialized, but - * maybe that is ok? - */ - rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY, - bio->pbi_reg); - if (rle == NULL) - rle = resource_list_find(&dinfo->resources, - SYS_RES_IOPORT, bio->pbi_reg); - if (rle == NULL || rle->res == NULL) { + pm = pci_find_bar(pcidev, reg); + if (pm == NULL) { error = EINVAL; break; } - - /* - * Ok, we have a resource for this BAR. Read the lower - * 32 bits to get any flags. - */ - value = pci_read_config(pcidev, bio->pbi_reg, 4); - if (PCI_BAR_MEM(value)) { - if (rle->type != SYS_RES_MEMORY) { - error = EINVAL; - break; - } - value &= ~PCIM_BAR_MEM_BASE; - } else { - if (rle->type != SYS_RES_IOPORT) { - error = EINVAL; - break; - } - value &= ~PCIM_BAR_IO_BASE; - } - bio->pbi_base = rman_get_start(rle->res) | value; - bio->pbi_length = rman_get_size(rle->res); - - /* - * Check the command register to determine if this BAR - * is enabled. - */ - value = pci_read_config(pcidev, PCIR_COMMAND, 2); - if (rle->type == SYS_RES_MEMORY) - bio->pbi_enabled = (value & PCIM_CMD_MEMEN) != 0; - else - bio->pbi_enabled = (value & PCIM_CMD_PORTEN) != 0; + bio->pbi_base = pm->pm_value; + bio->pbi_length = (pci_addr_t)1 << pm->pm_size; + bio->pbi_enabled = pm->pm_enabled; error = 0; break; case PCIOCATTACHED: ==== //depot/projects/pci/sys/dev/pci/pcivar.h#2 (text+ko) ==== @@ -46,7 +46,15 @@ uint8_t pp_bse; /* conf. space addr. of PM BSE reg */ uint8_t pp_data; /* conf. space addr. of PM data reg */ }; - + +struct pci_map { + pci_addr_t pm_value; /* Raw BAR value */ + pci_addr_t pm_size; + uint8_t pm_reg; + uint8_t pm_enabled; + STAILQ_ENTRY(pci_map) pm_link; +}; + struct vpd_readonly { char keyword[2]; char *value; @@ -119,8 +127,7 @@ typedef struct pcicfg { struct device *dev; /* device which owns this */ - uint32_t bar[PCI_MAXMAPS_0]; /* BARs */ - uint32_t bios; /* BIOS mapping */ + STAILQ_HEAD(, pci_map) maps; /* BARs */ uint16_t subvendor; /* card vendor ID */ uint16_t subdevice; /* card device ID, assigned by card vendor */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201103040413.p244DCU9073396>