diff options
author | dfr <dfr@FreeBSD.org> | 1999-10-14 21:38:33 +0000 |
---|---|---|
committer | dfr <dfr@FreeBSD.org> | 1999-10-14 21:38:33 +0000 |
commit | 37ab4f7a31956a5d39e3eb1f74da3865b7d0fd3e (patch) | |
tree | 368f670667f06e1028edad29b2c6720ab1c3532d /sys/dev/pci | |
parent | 22acf6986dd3517e491a4d9e4deee1109e4ee940 (diff) | |
download | FreeBSD-src-37ab4f7a31956a5d39e3eb1f74da3865b7d0fd3e.zip FreeBSD-src-37ab4f7a31956a5d39e3eb1f74da3865b7d0fd3e.tar.gz |
* Implement bus_set/get/delete_resource for pci.
* Change the hack used on the alpha for mapping devices into DENSE or
BWX memory spaces to a simpler one. Its still a hack and should be
a seperate api to explicitly map the resource.
* Add $FreeBSD$ as necessary.
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/pci.c | 397 | ||||
-rw-r--r-- | sys/dev/pci/pcivar.h | 30 |
2 files changed, 148 insertions, 279 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index bfdf9d0..f5da2d8 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -60,13 +60,25 @@ #include <machine/smp.h> #endif /* APIC_IO */ +/* map register information */ +#define PCI_MAPMEM 0x01 /* memory map */ +#define PCI_MAPMEMP 0x02 /* prefetchable memory map */ +#define PCI_MAPPORT 0x04 /* port map */ + +struct pci_devinfo { + STAILQ_ENTRY(pci_devinfo) pci_links; + struct resource_list resources; + pcicfgregs cfg; + struct pci_conf conf; +}; + static STAILQ_HEAD(devlist, pci_devinfo) pci_devq; u_int32_t pci_numdevs = 0; static u_int32_t pci_generation = 0; /* return base address of memory or port map */ -static int +static u_int32_t pci_mapbase(unsigned mapreg) { int mask = 0x03; @@ -135,91 +147,6 @@ pci_maprange(unsigned mapreg) return (ln2range); } -/* extract map parameters into newly allocated array of pcimap structures */ - -static pcimap * -pci_readmaps(pcicfgregs *cfg, int maxmaps) -{ - int i, j = 0; - pcimap *map; - int map64 = 0; - int reg = PCIR_MAPS; - - for (i = 0; i < maxmaps; i++) { - int reg = PCIR_MAPS + i*4; - u_int32_t base; - u_int32_t ln2range; - - base = pci_cfgread(cfg, reg, 4); - ln2range = pci_maprange(base); - - if (base == 0 || ln2range == 0 || base == 0xffffffff) - continue; /* skip invalid entry */ - else { - j++; - if (ln2range > 32) { - i++; - j++; - } - } - } - - map = malloc(j * sizeof (pcimap), M_DEVBUF, M_WAITOK); - if (map != NULL) { - bzero(map, sizeof(pcimap) * j); - cfg->nummaps = j; - - for (i = 0, j = 0; i < maxmaps; i++, reg += 4) { - u_int32_t base; - u_int32_t testval; - - base = pci_cfgread(cfg, reg, 4); - - if (map64 == 0) { - if (base == 0 || base == 0xffffffff) - continue; /* skip invalid entry */ - - pci_cfgwrite(cfg, reg, 0xffffffff, 4); - testval = pci_cfgread(cfg, reg, 4); - pci_cfgwrite(cfg, reg, base, 4); - - map[j].reg = reg; - map[j].base = pci_mapbase(base); - map[j].type = pci_maptype(base); - map[j].ln2size = pci_mapsize(testval); - map[j].ln2range = pci_maprange(testval); - map64 = map[j].ln2range == 64; - } else { - /* only fill in base, other fields are 0 */ - map[j].base = base; - map64 = 0; - } -#ifdef __alpha__ - /* - * XXX: encode hose number in the base addr, - * This will go away once the bus_space functions - * can deal with multiple hoses - */ - - if(cfg->hose){ - if(map[j].base & 0x80000000){ - printf("base addr = 0x%x\n", map[j].base); - printf("hacked addr = 0x%x\n", - map[j].base | (cfg->hose << 31)); - - panic("hose encoding hack would clobber base addr"); - } - if(cfg->hose > 1 ) - panic("only one hose supported!"); - map[j].base |= (cfg->hose << 31); - } -#endif - j++; - } - } - return (map); -} - /* adjust some values from PCI 1.0 devices to match 2.0 standards ... */ static void @@ -312,14 +239,14 @@ pci_hdrtypedata(pcicfgregs *cfg) case 0: cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_0, 2); cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_0, 2); - cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_0); + cfg->nummaps = PCI_MAXMAPS_0; break; case 1: cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_1, 2); cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_1, 2); cfg->secondarybus = pci_cfgread(cfg, PCIR_SECBUS_1, 1); cfg->subordinatebus = pci_cfgread(cfg, PCIR_SUBBUS_1, 1); - cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_1); + cfg->nummaps = PCI_MAXMAPS_1; cfg->hdrspec = pci_readppb(cfg); break; case 2: @@ -327,7 +254,7 @@ pci_hdrtypedata(pcicfgregs *cfg) cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_2, 2); cfg->secondarybus = pci_cfgread(cfg, PCIR_SECBUS_2, 1); cfg->subordinatebus = pci_cfgread(cfg, PCIR_SUBBUS_2, 1); - cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_2); + cfg->nummaps = PCI_MAXMAPS_2; cfg->hdrspec = pci_readpcb(cfg); break; } @@ -1010,7 +937,6 @@ static void pci_print_verbose(struct pci_devinfo *dinfo) { if (bootverbose) { - int i; pcicfgregs *cfg = &dinfo->cfg; printf("found->\tvendor=0x%04x, dev=0x%04x, revid=0x%02x\n", @@ -1029,20 +955,105 @@ pci_print_verbose(struct pci_devinfo *dinfo) #endif /* PCI_DEBUG */ if (cfg->intpin > 0) printf("\tintpin=%c, irq=%d\n", cfg->intpin +'a' -1, cfg->intline); + } +} + +static int +pci_porten(pcicfgregs *cfg) +{ + return ((cfg->cmdreg & PCIM_CMD_PORTEN) != 0); +} + +static int +pci_memen(pcicfgregs *cfg) +{ + return ((cfg->cmdreg & PCIM_CMD_MEMEN) != 0); +} + +static void +pci_add_resources(device_t dev, pcicfgregs* cfg) +{ + + struct pci_devinfo *dinfo = device_get_ivars(dev); + struct resource_list *rl = &dinfo->resources; + int i; + + for (i = 0; i < cfg->nummaps; i++) { + int reg = PCIR_MAPS + i*4; + u_int32_t map; + u_int64_t base; + u_int8_t ln2size; + u_int8_t ln2range; + u_int32_t testval; + + int type; + + map = pci_cfgread(cfg, reg, 4); + + if (map == 0 || map == 0xffffffff) + continue; /* skip invalid entry */ + + pci_cfgwrite(cfg, reg, 0xffffffff, 4); + testval = pci_cfgread(cfg, reg, 4); + pci_cfgwrite(cfg, reg, map, 4); - for (i = 0; i < cfg->nummaps; i++) { - pcimap *m = &cfg->map[i]; + base = pci_mapbase(map); + if (pci_maptype(map) & PCI_MAPMEM) + type = SYS_RES_MEMORY; + else + type = SYS_RES_IOPORT; + ln2size = pci_mapsize(testval); + ln2range = pci_maprange(testval); + if (ln2range == 64) { + /* Read the other half of a 64bit map register */ + base |= (u_int64_t) pci_cfgread(cfg, reg + 4, 4) << 32; + i++; + } + +#ifdef __alpha__ + /* + * XXX: encode hose number in the base addr, + * This will go away once the bus_space functions + * can deal with multiple hoses + */ + + if(cfg->hose){ + if (base & 0x80000000) { + printf("base addr = 0x%x\n", base); + printf("hacked addr = 0x%x\n", + base | (cfg->hose << 31)); + + panic("hose encoding hack would clobber base addr"); + } + if (cfg->hose > 1) + panic("only one hose supported!"); + base |= (cfg->hose << 31); + } +#endif + if (type == SYS_RES_IOPORT && !pci_porten(cfg)) + continue; + if (type == SYS_RES_IOPORT && !pci_memen(cfg)) + continue; + + resource_list_add(rl, type, reg, + base, base + (1 << ln2size) - 1, + (1 << ln2size)); + + if (bootverbose) { printf("\tmap[%d]: type %x, range %2d, base %08x, size %2d\n", - i, m->type, m->ln2range, m->base, m->ln2size); + i, pci_maptype(base), ln2range, + (unsigned int) base, ln2size); } } + if (cfg->intline) + resource_list_add(rl, SYS_RES_IRQ, 0, + cfg->intline, cfg->intline, 1); } -static int +static void pci_add_children(device_t dev, int busno) { pcicfgregs probe; - int bushigh = busno; #ifdef SIMOS #undef PCI_SLOTMAX @@ -1069,16 +1080,10 @@ pci_add_children(device_t dev, int busno) pci_print_verbose(dinfo); dinfo->cfg.dev = device_add_child(dev, NULL, -1, dinfo); - - if (bushigh < dinfo->cfg.subordinatebus) - bushigh = dinfo->cfg.subordinatebus; - if (bushigh < dinfo->cfg.secondarybus) - bushigh = dinfo->cfg.secondarybus; + pci_add_resources(dinfo->cfg.dev, &dinfo->cfg); } } } - - return bushigh; } static int @@ -1248,181 +1253,58 @@ pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value) return 0; } -static int -pci_mapno(pcicfgregs *cfg, int reg) +static 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) { - int i, nummaps; - pcimap *map; - - nummaps = cfg->nummaps; - map = cfg->map; + struct pci_devinfo *dinfo = device_get_ivars(child); + struct resource_list *rl = &dinfo->resources; - for (i = 0; i < nummaps; i++) - if (map[i].reg == reg) - return (i); - return (-1); + return resource_list_alloc(rl, dev, child, type, rid, + start, end, count, flags); } static int -pci_porten(pcicfgregs *cfg) +pci_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) { - return ((cfg->cmdreg & PCIM_CMD_PORTEN) != 0); -} - -static int -pci_isportmap(pcicfgregs *cfg, int map) + struct pci_devinfo *dinfo = device_get_ivars(child); + struct resource_list *rl = &dinfo->resources; -{ - return ((unsigned)map < cfg->nummaps - && (cfg->map[map].type & PCI_MAPPORT) != 0); + return resource_list_release(rl, dev, child, type, rid, r); } static int -pci_memen(pcicfgregs *cfg) +pci_set_resource(device_t dev, device_t child, int type, int rid, + u_long start, u_long count) { - return ((cfg->cmdreg & PCIM_CMD_MEMEN) != 0); + printf("pci_set_resource: PCI resources can not be changed\n"); + return EINVAL; } static int -pci_ismemmap(pcicfgregs *cfg, int map) +pci_get_resource(device_t dev, device_t child, int type, int rid, + u_long *startp, u_long *countp) { - return ((unsigned)map < cfg->nummaps - && (cfg->map[map].type & PCI_MAPMEM) != 0); -} - -static 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) -{ - int isdefault; struct pci_devinfo *dinfo = device_get_ivars(child); - pcicfgregs *cfg = &dinfo->cfg; - struct resource *rv, **rvp = 0; - int map; - - isdefault = (device_get_parent(child) == dev - && start == 0UL && end == ~0UL); - - switch (type) { - case SYS_RES_IRQ: - if (*rid != 0) - return 0; - if (isdefault && cfg->intline != 255) { - start = cfg->intline; - end = cfg->intline; - count = 1; - } - break; - - case SYS_RES_DRQ: /* passthru for child isa */ - break; - -#ifdef __alpha__ - case SYS_RES_DENSE: - case SYS_RES_BWX: -#endif - case SYS_RES_MEMORY: - if (isdefault) { - map = pci_mapno(cfg, *rid); - if (pci_memen(cfg) && pci_ismemmap(cfg, map)) { - start = cfg->map[map].base; - count = 1 << cfg->map[map].ln2size; - end = start + count; - rvp = &cfg->map[map].res; - } else - return 0; - } - break; - - case SYS_RES_IOPORT: - if (isdefault) { - map = pci_mapno(cfg, *rid); - if (pci_porten(cfg) && pci_isportmap(cfg, map)) { - start = cfg->map[map].base; - count = 1 << cfg->map[map].ln2size; - end = start + count; - rvp = &cfg->map[map].res; - } else - return 0; - } - break; - - default: - return 0; - } + struct resource_list *rl = &dinfo->resources; + struct resource_list_entry *rle; - rv = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, - type, rid, start, end, count, flags); - if (rvp) - *rvp = rv; + rle = resource_list_find(rl, type, rid); + if (!rle) + return ENOENT; + + *startp = rle->start; + *countp = rle->count; - return rv; + return 0; } -static int -pci_release_resource(device_t dev, device_t child, int type, int rid, - struct resource *r) +static void +pci_delete_resource(device_t dev, device_t child, int type, int rid) { - int rv; - struct pci_devinfo *dinfo = device_get_ivars(child); - pcicfgregs *cfg = &dinfo->cfg; - int map = 0; - int passthrough = (device_get_parent(child) != dev); - - switch (type) { - case SYS_RES_IRQ: - if (rid != 0) - return EINVAL; - break; - - case SYS_RES_DRQ: /* passthru for child isa */ - break; - -#ifdef __alpha__ - case SYS_RES_DENSE: - case SYS_RES_BWX: -#endif - case SYS_RES_MEMORY: - case SYS_RES_IOPORT: - /* - * Only check the map registers if this is a direct - * descendant. - */ - map = passthrough ? -1 : pci_mapno(cfg, rid); - break; - - default: - return (ENOENT); - } - - rv = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, rid, r); - - if (rv == 0) { - switch (type) { - case SYS_RES_IRQ: - if (!passthrough) - cfg->irqres = 0; - break; - - case SYS_RES_DRQ: /* passthru for child isa */ - break; - -#ifdef __alpha__ - case SYS_RES_DENSE: - case SYS_RES_BWX: -#endif - case SYS_RES_MEMORY: - case SYS_RES_IOPORT: - if (map != -1) - cfg->map[map].res = 0; - break; - - default: - return ENOENT; - } - } - - return rv; + printf("pci_set_resource: PCI resources can not be deleted\n"); + return EINVAL; } static u_int32_t @@ -1477,6 +1359,9 @@ static device_method_t pci_methods[] = { DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + DEVMETHOD(bus_set_resource, pci_set_resource), + DEVMETHOD(bus_get_resource, pci_get_resource), + DEVMETHOD(bus_delete_resource, pci_delete_resource), /* PCI interface */ DEVMETHOD(pci_read_config, pci_read_config_method), diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h index ae4958d..31cea00 100644 --- a/sys/dev/pci/pcivar.h +++ b/sys/dev/pci/pcivar.h @@ -56,28 +56,11 @@ typedef u_int64_t pci_addr_t; /* u_int64_t for system with 64bit addresses */ typedef u_int32_t pci_addr_t; /* u_int64_t for system with 64bit addresses */ #endif -/* map register information */ - -typedef struct { - u_int32_t base; - u_int8_t type; -#define PCI_MAPMEM 0x01 /* memory map */ -#define PCI_MAPMEMP 0x02 /* prefetchable memory map */ -#define PCI_MAPPORT 0x04 /* port map */ - u_int8_t ln2size; - u_int8_t ln2range; - u_int8_t reg; /* offset of map register in config space */ -/* u_int8_t dummy;*/ - struct resource *res; /* handle from resource manager */ -} pcimap; - /* config header information common to all header types */ typedef struct pcicfg { struct device *dev; /* device which owns this */ - pcimap *map; /* pointer to array of PCI maps */ void *hdrspec; /* pointer to header type specific data */ - struct resource *irqres; /* resource descriptor for interrupt mapping */ u_int16_t subvendor; /* card vendor ID */ u_int16_t subdevice; /* card device ID, assigned by card vendor */ @@ -163,12 +146,6 @@ typedef struct pciattach { struct pciattach *next; } pciattach; -struct pci_devinfo { - STAILQ_ENTRY(pci_devinfo) pci_links; - pcicfgregs cfg; - struct pci_conf conf; -}; - extern u_int32_t pci_numdevs; @@ -192,6 +169,13 @@ pcicfgregs * pci_devlist_get_parent(pcicfgregs *cfg); #include "pci_if.h" +/* + * Define pci-specific resource flags for accessing memory via dense + * or bwx memory spaces. These flags are ignored on i386. + */ +#define PCI_RF_DENSE 0x10000 +#define PCI_RF_BWX 0x20000 + enum pci_device_ivars { PCI_IVAR_SUBVENDOR, PCI_IVAR_SUBDEVICE, |