/* * Initialize the PCI-bus. The Atari-BIOS does not do this, so.... * We only disable all devices here. Memory and I/O enabling is done * later at pcibusattach. */ void init_pci_bus(void) { pci_chipset_tag_t pc = NULL; /* XXX */ pcitag_t tag; pcireg_t csr; int device, id, maxndevs; tag = 0; id = 0; maxndevs = pci_bus_maxdevs(pc, 0); for (device = 0; device < maxndevs; device++) { tag = pci_make_tag(pc, 0, device, 0); id = pci_conf_read(pc, tag, PCI_ID_REG); if (id == 0 || id == 0xffffffff) continue; csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); csr &= ~(PCI_COMMAND_MEM_ENABLE|PCI_COMMAND_IO_ENABLE); csr &= ~PCI_COMMAND_MASTER_ENABLE; pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr); } }
int cy82c693_setup_elcr(void) { int device, maxndevs; pcitag_t tag; pcireg_t id; /* * Search PCI configuration space for a Cypress CY82C693. * * Note we can make some assumptions about our bus number * here, because: * * (1) there can be at most one ISA/EISA bridge per PCI bus, and * * (2) any ISA/EISA bridges must be attached to primary PCI * busses (i.e. bus zero). */ maxndevs = pci_bus_maxdevs(sio_pc, 0); for (device = 0; device < maxndevs; device++) { tag = pci_make_tag(sio_pc, 0, device, 0); id = pci_conf_read(sio_pc, tag, PCI_ID_REG); /* Invalid vendor ID value? */ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) continue; /* XXX Not invalid, but we've done this ~forever. */ if (PCI_VENDOR(id) == 0) continue; if (PCI_VENDOR(id) != PCI_VENDOR_CONTAQ || PCI_PRODUCT(id) != PCI_PRODUCT_CONTAQ_82C693) continue; /* * Found one! */ #if 0 printf("cy82c693_setup_elcr: found 82C693 at device %d\n", device); #endif sio_cy82c693_handle = cy82c693_init(sio_iot); sio_read_elcr = cy82c693_read_elcr; sio_write_elcr = cy82c693_write_elcr; return (0); } /* * Didn't find a CY82C693. */ return (ENODEV); }
int default_pci_bus_devorder(pci_chipset_tag_t pc, int bus, uint8_t *devs, int maxdevs) { int i, n; n = MIN(pci_bus_maxdevs(pc, bus), maxdevs); for (i = 0; i < n; i++) devs[i] = i; return n; }
void mpbios_intr_fixup(void) { const struct mpbios_icu_table *mpit = NULL; pci_chipset_tag_t pc = NULL; pcitag_t icutag; int device, maxdevs = pci_bus_maxdevs(pc, 0); /* Search configuration space for a known interrupt router. */ for (device = 0; device < maxdevs; device++) { const struct pci_quirkdata *qd; int function, nfuncs; pcireg_t icuid; pcireg_t bhlcr; icutag = pci_make_tag(pc, 0, device, 0); icuid = pci_conf_read(pc, icutag, PCI_ID_REG); /* Invalid vendor ID value? */ if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID) continue; qd = pci_lookup_quirkdata(PCI_VENDOR(icuid), PCI_PRODUCT(icuid)); bhlcr = pci_conf_read(pc, icutag, PCI_BHLC_REG); if (PCI_HDRTYPE_MULTIFN(bhlcr) || (qd != NULL && (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)) nfuncs = 8; else nfuncs = 1; for (function = 0; function < nfuncs; function++) { icutag = pci_make_tag(pc, 0, device, function); icuid = pci_conf_read(pc, icutag, PCI_ID_REG); /* Invalid vendor ID value? */ if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID) continue; if ((mpit = mpbios_icu_lookup(icuid))) break; } if (mpit != NULL) break; } if (mpit) mpit->mpit_mpbios_fixup(pc, icutag); }
void pci_device_foreach(struct shpcic_softc *sc, pci_chipset_tag_t pc, int maxbus, void (*func)(struct shpcic_softc *, pci_chipset_tag_t, pcitag_t)) { const struct pci_quirkdata *qd; int bus, device, function, maxdevs, nfuncs; pcireg_t id, bhlcr; pcitag_t tag; for (bus = 0; bus <= maxbus; bus++) { maxdevs = pci_bus_maxdevs(pc, bus); for (device = 0; device < maxdevs; device++) { tag = pci_make_tag(pc, bus, device, 0); id = pci_conf_read(pc, tag, PCI_ID_REG); /* Invalid vendor ID value? */ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) continue; /* XXX Not invalid, but we've done this ~forever. */ if (PCI_VENDOR(id) == 0) continue; qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id)); bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); if (PCI_HDRTYPE_MULTIFN(bhlcr) || (qd != NULL && (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)) nfuncs = 8; else nfuncs = 1; for (function = 0; function < nfuncs; function++) { tag = pci_make_tag(pc, bus, device, function); id = pci_conf_read(pc, tag, PCI_ID_REG); /* Invalid vendor ID value? */ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) continue; /* * XXX Not invalid, but we've done this * ~forever. */ if (PCI_VENDOR(id) == 0) continue; (*func)(sc, pc, tag); } } } }
/* * Determine which flags should be passed to the primary PCI bus's * autoconfiguration node. We use this to detect broken chipsets * which cannot safely use memory-mapped device access. */ int pci_bus_flags() { int rval = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED | PCI_FLAGS_MRL_OKAY | PCI_FLAGS_MRM_OKAY | PCI_FLAGS_MWI_OKAY; int device, maxndevs; pcitag_t tag; pcireg_t id; maxndevs = pci_bus_maxdevs(NULL, 0); for (device = 0; device < maxndevs; device++) { tag = pci_make_tag(NULL, 0, device, 0); id = pci_conf_read(NULL, tag, PCI_ID_REG); /* Invalid vendor ID value? */ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) continue; /* XXX Not invalid, but we've done this ~forever. */ if (PCI_VENDOR(id) == 0) continue; switch (PCI_VENDOR(id)) { case PCI_VENDOR_SIS: switch (PCI_PRODUCT(id)) { case PCI_PRODUCT_SIS_85C496: goto disable_mem; } break; } } return (rval); disable_mem: printf("Warning: broken PCI-Host bridge detected; " "disabling memory-mapped access\n"); rval &= ~(PCI_FLAGS_MEM_ENABLED|PCI_FLAGS_MRL_OKAY|PCI_FLAGS_MRM_OKAY| PCI_FLAGS_MWI_OKAY); return (rval); }
void lemote_pci_attach_hook(pci_chipset_tag_t pc) { pcireg_t id; pcitag_t tag; int dev; /* * Check for an AMD CS5536 chip; if one is found, register * the proper PCI configuration space hooks. */ for (dev = pci_bus_maxdevs(pc, 0); dev >= 0; dev--) { tag = pci_make_tag(pc, 0, dev, 0); id = pci_conf_read(pc, tag, PCI_ID_REG); if (id == PCI_ID_CODE(PCI_VENDOR_AMD, PCI_PRODUCT_AMD_CS5536_PCISB)) { glx_init(pc, tag, dev); break; } } }
/* * Go look for a VGA card on the PCI-bus. This search is a * stripped down version of the PCI-probe. It only looks on * bus0 for VGA cards. The first card found is used. */ int check_for_vga() { pci_chipset_tag_t pc = NULL; /* XXX */ pcitag_t tag; int device, found, id, maxndevs, i, j; volatile u_char *regs; u_char *fb; char *nbd = "NetBSD/Atari"; found = 0; tag = 0; id = 0; maxndevs = pci_bus_maxdevs(pc, 0); /* * These are setup in atari_init.c */ regs = (volatile caddr_t)pci_io_addr; fb = (caddr_t)pci_mem_addr; for (device = 0; !found && (device < maxndevs); device++) { tag = pci_make_tag(pc, 0, device, 0); id = pci_conf_read(pc, tag, PCI_ID_REG); if (id == 0 || id == 0xffffffff) continue; switch (id = PCI_PRODUCT(id)) { /* * XXX Make the inclusion of the cases dependend * on config options! */ case PCI_PRODUCT_TSENG_ET6000: case PCI_PRODUCT_TSENG_ET4000_W32P_A: case PCI_PRODUCT_TSENG_ET4000_W32P_B: case PCI_PRODUCT_TSENG_ET4000_W32P_C: case PCI_PRODUCT_TSENG_ET4000_W32P_D: tseng_init(pc, tag, id, regs, fb); found = 1; break; default: break; } } if (!found) return (0); /* * Generic parts of the initialization... */ /* B&W colors */ vgaw(regs, VDAC_ADDRESS_W, 0); for (i = 0; i < 256; i++) { j = (i & 1) ? ((i > 7) ? 2 : 1) : 0; vgaw(regs, VDAC_DATA, conscolors[j][0]); vgaw(regs, VDAC_DATA, conscolors[j][1]); vgaw(regs, VDAC_DATA, conscolors[j][2]); } loadfont(regs, fb); /* * Clear the screen and print a message. The latter * is of diagnostic/debug use only. */ for (i = 50 * 80; i >= 0; i -= 2) { fb[i] = 0x20; fb[i+1] = 0x07; } for (i = 56; *nbd; i += 2) fb[i] = *nbd++; return (1); }
void pciattach(device_t parent, device_t self, void *aux) { struct pcibus_attach_args *pba = aux; struct pci_softc *sc = device_private(self); int io_enabled, mem_enabled, mrl_enabled, mrm_enabled, mwi_enabled; const char *sep = ""; static const int wildcard[PCICF_NLOCS] = { PCICF_DEV_DEFAULT, PCICF_FUNCTION_DEFAULT }; sc->sc_dev = self; pci_attach_hook(parent, self, pba); aprint_naive("\n"); aprint_normal("\n"); io_enabled = (pba->pba_flags & PCI_FLAGS_IO_OKAY); mem_enabled = (pba->pba_flags & PCI_FLAGS_MEM_OKAY); mrl_enabled = (pba->pba_flags & PCI_FLAGS_MRL_OKAY); mrm_enabled = (pba->pba_flags & PCI_FLAGS_MRM_OKAY); mwi_enabled = (pba->pba_flags & PCI_FLAGS_MWI_OKAY); if (io_enabled == 0 && mem_enabled == 0) { aprint_error_dev(self, "no spaces enabled!\n"); goto fail; } #define PRINT(str) \ do { \ aprint_verbose("%s%s", sep, str); \ sep = ", "; \ } while (/*CONSTCOND*/0) aprint_verbose_dev(self, ""); if (io_enabled) PRINT("i/o space"); if (mem_enabled) PRINT("memory space"); aprint_verbose(" enabled"); if (mrl_enabled || mrm_enabled || mwi_enabled) { if (mrl_enabled) PRINT("rd/line"); if (mrm_enabled) PRINT("rd/mult"); if (mwi_enabled) PRINT("wr/inv"); aprint_verbose(" ok"); } aprint_verbose("\n"); #undef PRINT sc->sc_iot = pba->pba_iot; sc->sc_memt = pba->pba_memt; sc->sc_dmat = pba->pba_dmat; sc->sc_dmat64 = pba->pba_dmat64; sc->sc_pc = pba->pba_pc; sc->sc_bus = pba->pba_bus; sc->sc_bridgetag = pba->pba_bridgetag; sc->sc_maxndevs = pci_bus_maxdevs(pba->pba_pc, pba->pba_bus); sc->sc_intrswiz = pba->pba_intrswiz; sc->sc_intrtag = pba->pba_intrtag; sc->sc_flags = pba->pba_flags; device_pmf_driver_set_child_register(sc->sc_dev, pci_child_register); pcirescan(sc->sc_dev, "pci", wildcard); fail: if (!pmf_device_register(self, NULL, NULL)) aprint_error_dev(self, "couldn't establish power handler\n"); }
void ppb_alloc_resources(struct ppb_softc *sc, struct pci_attach_args *pa) { pci_chipset_tag_t pc = sc->sc_pc; pcireg_t id, busdata, blr, bhlcr, type, csr; pcireg_t addr, mask; pcitag_t tag; int bus, dev; int reg, reg_start, reg_end, reg_rom; int io_count = 0; int mem_count = 0; bus_addr_t start, end; u_long base, size; if (pa->pa_memex == NULL) return; busdata = pci_conf_read(pc, sc->sc_tag, PPB_REG_BUSINFO); bus = PPB_BUSINFO_SECONDARY(busdata); if (bus == 0) return; /* * Count number of devices. If there are no devices behind * this bridge, there's no point in allocating any address * space. */ for (dev = 0; dev < pci_bus_maxdevs(pc, bus); dev++) { tag = pci_make_tag(pc, bus, dev, 0); id = pci_conf_read(pc, tag, PCI_ID_REG); if (PCI_VENDOR(id) == PCI_VENDOR_INVALID || PCI_VENDOR(id) == 0) continue; bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); switch (PCI_HDRTYPE_TYPE(bhlcr)) { case 0: reg_start = PCI_MAPREG_START; reg_end = PCI_MAPREG_END; reg_rom = PCI_ROM_REG; break; case 1: /* PCI-PCI bridge */ reg_start = PCI_MAPREG_START; reg_end = PCI_MAPREG_PPB_END; reg_rom = 0; /* 0x38 */ break; case 2: /* PCI-Cardbus bridge */ reg_start = PCI_MAPREG_START; reg_end = PCI_MAPREG_PCB_END; reg_rom = 0; break; default: return; } for (reg = reg_start; reg < reg_end; reg += 4) { if (pci_mapreg_probe(pc, tag, reg, &type) == 0) continue; if (type == PCI_MAPREG_TYPE_IO) io_count++; else mem_count++; } if (reg_rom != 0) { addr = pci_conf_read(pc, tag, reg_rom); pci_conf_write(pc, tag, reg_rom, ~PCI_ROM_ENABLE); mask = pci_conf_read(pc, tag, reg_rom); pci_conf_write(pc, tag, reg_rom, addr); if (PCI_ROM_SIZE(mask)) mem_count++; } } csr = pci_conf_read(pc, sc->sc_tag, PCI_COMMAND_STATUS_REG); /* * Get the bridge in a consistent state. If memory mapped I/O * is disabled, disabled the associated windows as well. */ if ((csr & PCI_COMMAND_MEM_ENABLE) == 0) { pci_conf_write(pc, sc->sc_tag, PPB_REG_MEM, 0x0000ffff); pci_conf_write(pc, sc->sc_tag, PPB_REG_PREFMEM, 0x0000ffff); pci_conf_write(pc, sc->sc_tag, PPB_REG_PREFBASE_HI32, 0); pci_conf_write(pc, sc->sc_tag, PPB_REG_PREFLIM_HI32, 0); } /* Allocate I/O address space if necessary. */ if (io_count > 0 && pa->pa_ioex) { blr = pci_conf_read(pc, sc->sc_tag, PPB_REG_IOSTATUS); sc->sc_iobase = (blr << PPB_IO_SHIFT) & PPB_IO_MASK; sc->sc_iolimit = (blr & PPB_IO_MASK) | 0x00000fff; blr = pci_conf_read(pc, sc->sc_tag, PPB_REG_IO_HI); sc->sc_iobase |= (blr & 0x0000ffff) << 16; sc->sc_iolimit |= (blr & 0xffff0000); if (sc->sc_iolimit < sc->sc_iobase || sc->sc_iobase == 0) { start = max(PCI_IO_START, pa->pa_ioex->ex_start); end = min(PCI_IO_END, pa->pa_ioex->ex_end); for (size = 0x2000; size >= PPB_IO_MIN; size >>= 1) if (extent_alloc_subregion(pa->pa_ioex, start, end, size, size, 0, 0, 0, &base) == 0) break; if (size >= PPB_IO_MIN) { sc->sc_iobase = base; sc->sc_iolimit = base + size - 1; blr = pci_conf_read(pc, sc->sc_tag, PPB_REG_IOSTATUS); blr &= 0xffff0000; blr |= sc->sc_iolimit & PPB_IO_MASK; blr |= (sc->sc_iobase >> PPB_IO_SHIFT); pci_conf_write(pc, sc->sc_tag, PPB_REG_IOSTATUS, blr); blr = (sc->sc_iobase & 0xffff0000) >> 16; blr |= sc->sc_iolimit & 0xffff0000; pci_conf_write(pc, sc->sc_tag, PPB_REG_IO_HI, blr); csr |= PCI_COMMAND_IO_ENABLE; }
void gdium_attach_hook(device_t parent, device_t self, struct pcibus_attach_args *pba) { pci_chipset_tag_t pc = pba->pba_pc; pcireg_t id; pcitag_t tag; #ifdef notyet int bar; #endif #if 0 pcireg_t reg; int dev, func; #endif if (pba->pba_bus != 0) return; #ifdef notyet /* * Clear all BAR of the mini PCI slot; PMON did not initialize * it, and we do not want it to conflict with anything. */ tag = pci_make_tag(pc, 0, 13, 0); for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END; bar += 4) pci_conf_write(pc, tag, bar, 0); #else /* * Force a non conflicting BAR for the wireless controller, * until proper resource configuration code is added to * bonito (work in progress). */ tag = pci_make_tag(pc, 0, 13, 0); pci_conf_write(pc, tag, PCI_MAPREG_START, 0x06228000); #endif /* * Figure out which motherboard we are running on. * Might not be good enough... */ tag = pci_make_tag(pc, 0, 17, 0); id = pci_conf_read(pc, tag, PCI_ID_REG); if (id == PCI_ID_CODE(PCI_VENDOR_NEC, PCI_PRODUCT_NEC_USB)) gdium_revision = 1; #if 0 /* * Tweak the usb controller capabilities. */ for (dev = pci_bus_maxdevs(pc, 0); dev >= 0; dev--) { tag = pci_make_tag(pc, 0, dev, 0); id = pci_conf_read(pc, tag, PCI_ID_REG); if (id != PCI_ID_CODE(PCI_VENDOR_NEC, PCI_PRODUCT_NEC_USB)) continue; if (gdium_revision != 0) { reg = pci_conf_read(pc, tag, 0xe0); /* enable ports 1 and 2 */ reg |= 0x00000003; pci_conf_write(pc, tag, 0xe0, reg); } else { for (func = 0; func < 2; func++) { tag = pci_make_tag(pc, 0, dev, func); id = pci_conf_read(pc, tag, PCI_ID_REG); if (PCI_VENDOR(id) != PCI_VENDOR_NEC) continue; if (PCI_PRODUCT(id) != PCI_PRODUCT_NEC_USB && PCI_PRODUCT(id) != PCI_PRODUCT_NEC_USB2) continue; reg = pci_conf_read(pc, tag, 0xe0); /* enable ports 1 and 3, disable port 2 */ reg &= ~0x00000007; reg |= 0x00000005; pci_conf_write(pc, tag, 0xe0, reg); pci_conf_write(pc, tag, 0xe4, 0x00000020); } } } #endif }
/* * Set up bus common stuff, then loop over devices & functions. * If we find something, call pci_do_device_query()). */ static int probe_bus(pciconf_bus_t *pb) { int device, maxdevs; #ifdef __PCI_BUS_DEVORDER char devs[32]; int i; #endif maxdevs = pci_bus_maxdevs(pb->pc, pb->busno); pb->ndevs = 0; pb->niowin = 0; pb->nmemwin = 0; pb->freq_66 = 1; pb->fast_b2b = 1; pb->prefetch = 1; pb->max_mingnt = 0; /* we are looking for the maximum */ pb->min_maxlat = 0x100; /* we are looking for the minimum */ pb->bandwidth_used = 0; #ifdef __PCI_BUS_DEVORDER pci_bus_devorder(pb->pc, pb->busno, devs); for (i=0; (device=devs[i]) < 32 && device >= 0; i++) { #else for (device=0; device < maxdevs; device++) { #endif pcitag_t tag; pcireg_t id, bhlcr; int function, nfunction; int confmode; tag = pci_make_tag(pb->pc, pb->busno, device, 0); if (pci_conf_debug) { print_tag(pb->pc, tag); } id = pci_conf_read(pb->pc, tag, PCI_ID_REG); if (pci_conf_debug) { printf("id=%x: Vendor=%x, Product=%x\n", id, PCI_VENDOR(id),PCI_PRODUCT(id)); } /* Invalid vendor ID value? */ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) continue; bhlcr = pci_conf_read(pb->pc, tag, PCI_BHLC_REG); nfunction = PCI_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1; for (function = 0 ; function < nfunction ; function++) { tag = pci_make_tag(pb->pc, pb->busno, device, function); id = pci_conf_read(pb->pc, tag, PCI_ID_REG); if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) continue; if (pb->ndevs+1 < MAX_CONF_DEV) { if (pci_conf_debug) { print_tag(pb->pc, tag); printf("Found dev 0x%04x 0x%04x -- " "really probing.\n", PCI_VENDOR(id), PCI_PRODUCT(id)); } #ifdef __HAVE_PCI_CONF_HOOK confmode = pci_conf_hook(pb->pc, pb->busno, device, function, id); if (confmode == 0) continue; #else /* * Don't enable expansion ROMS -- some cards * share address decoders between the EXPROM * and PCI memory space, and enabling the ROM * when not needed will cause all sorts of * lossage. */ confmode = PCI_CONF_ALL & ~PCI_CONF_MAP_ROM; #endif if (pci_do_device_query(pb, tag, device, function, confmode)) return -1; pb->ndevs++; } } } return 0; } static void alloc_busno(pciconf_bus_t *parent, pciconf_bus_t *pb) { pb->busno = parent->next_busno; if (parent->next_busno + parent->busno_spacing > parent->last_busno) panic("Too many PCI busses on bus %d", parent->busno); parent->next_busno = parent->next_busno + parent->busno_spacing; pb->next_busno = pb->busno+1; pb->busno_spacing = parent->busno_spacing >> 1; if (!pb->busno_spacing) panic("PCI busses nested too deep."); pb->last_busno = parent->next_busno - 1; }
int pci_bus_fixup(pci_chipset_tag_t pc, int bus) { static int bus_total; static int bridge_cnt; int device, maxdevs, function, nfuncs, bridge, bus_max, bus_sub; const struct pci_quirkdata *qd; pcireg_t reg; pcitag_t tag; bus_max = bus; bus_sub = 0; if (++bus_total > 256) panic("pci_bus_fixup: more than 256 PCI busses?"); /* Reset bridge configuration on this bus */ pci_bridge_foreach(pc, bus, bus, pci_bridge_reset, 0); maxdevs = pci_bus_maxdevs(pc, bus); for (device = 0; device < maxdevs; device++) { tag = pci_make_tag(pc, bus, device, 0); reg = pci_conf_read(pc, tag, PCI_ID_REG); /* Invalid vendor ID value? */ if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID) continue; /* XXX Not invalid, but we've done this ~forever. */ if (PCI_VENDOR(reg) == 0) continue; qd = pci_lookup_quirkdata(PCI_VENDOR(reg), PCI_PRODUCT(reg)); reg = pci_conf_read(pc, tag, PCI_BHLC_REG); if (PCI_HDRTYPE_MULTIFN(reg) || (qd != NULL && (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)) nfuncs = 8; else nfuncs = 1; for (function = 0; function < nfuncs; function++) { tag = pci_make_tag(pc, bus, device, function); reg = pci_conf_read(pc, tag, PCI_ID_REG); /* Invalid vendor ID value? */ if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID) continue; /* XXX Not invalid, but we've done this ~forever. */ if (PCI_VENDOR(reg) == 0) continue; aprint_debug("PCI fixup examining %02x:%02x\n", PCI_VENDOR(reg), PCI_PRODUCT(reg)); reg = pci_conf_read(pc, tag, PCI_CLASS_REG); if (PCI_CLASS(reg) == PCI_CLASS_BRIDGE && (PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_PCI || PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_CARDBUS)) { /* Assign the bridge #. */ bridge = bridge_cnt++; /* Assign the bridge's secondary bus #. */ bus_max++; reg = pci_conf_read(pc, tag, PPB_REG_BUSINFO); reg &= 0xff000000; reg |= bus | (bus_max << 8) | (0xff << 16); pci_conf_write(pc, tag, PPB_REG_BUSINFO, reg); /* Scan subordinate bus. */ bus_sub = pci_bus_fixup(pc, bus_max); /* Configure the bridge. */ reg &= 0xff000000; reg |= bus | (bus_max << 8) | (bus_sub << 16); pci_conf_write(pc, tag, PPB_REG_BUSINFO, reg); /* record relationship */ pci_bus_parent[bus_max]=bus; pci_bus_tag[bus_max]=tag; aprint_debug("PCI bridge %d: primary %d, " "secondary %d, subordinate %d\n", bridge, bus, bus_max, bus_sub); /* Next bridge's secondary bus #. */ bus_max = (bus_sub > bus_max) ? bus_sub : bus_max; } } } return (bus_max); /* last # of subordinate bus */ }
/* * Enable memory and I/O on pci devices. Care about already enabled devices * (probabaly by the console driver). * * The idea behind the following code is: * We build a by sizes sorted list of the requirements of the different * pci devices. After that we choose the start addresses of that areas * in such a way that they are placed as closed as possible together. */ static void enable_pci_devices(void) { PCI_MEMREG memlist; PCI_MEMREG iolist; struct pci_memreg *p, *q; int dev, reg, id, class; pcitag_t tag; pcireg_t csr, address, mask; pci_chipset_tag_t pc; int sizecnt, membase_1m; pc = 0; csr = 0; tag = 0; LIST_INIT(&memlist); LIST_INIT(&iolist); /* * first step: go through all devices and gather memory and I/O * sizes */ for (dev = 0; dev < pci_bus_maxdevs(pc,0); dev++) { tag = pci_make_tag(pc, 0, dev, 0); id = pci_conf_read(pc, tag, PCI_ID_REG); if (id == 0 || id == 0xffffffff) continue; csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); /* * special case: if a display card is found and memory is enabled * preserve 128k at 0xa0000 as vga memory. * XXX: if a display card is found without being enabled, leave * it alone! You will usually only create conflicts by enabeling * it. */ class = pci_conf_read(pc, tag, PCI_CLASS_REG); switch (PCI_CLASS(class)) { case PCI_CLASS_PREHISTORIC: case PCI_CLASS_DISPLAY: if (csr & (PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE)) { p = (struct pci_memreg *)malloc(sizeof(struct pci_memreg), M_TEMP, M_WAITOK); memset(p, '\0', sizeof(struct pci_memreg)); p->dev = dev; p->csr = csr; p->tag = tag; p->reg = 0; /* there is no register about this */ p->size = 0x20000; /* 128kByte */ p->mask = 0xfffe0000; p->address = 0xa0000; insert_into_list(&memlist, p); } else continue; } for (reg = PCI_MAPREG_START; reg < PCI_MAPREG_END; reg += 4) { address = pci_conf_read(pc, tag, reg); pci_conf_write(pc, tag, reg, 0xffffffff); mask = pci_conf_read(pc, tag, reg); pci_conf_write(pc, tag, reg, address); if (mask == 0) continue; /* Register unused */ p = (struct pci_memreg *)malloc(sizeof(struct pci_memreg), M_TEMP, M_WAITOK); memset(p, '\0', sizeof(struct pci_memreg)); p->dev = dev; p->csr = csr; p->tag = tag; p->reg = reg; p->mask = mask; p->address = 0; if (mask & PCI_MAPREG_TYPE_IO) { p->size = PCI_MAPREG_IO_SIZE(mask); /* * Align IO if necessary */ if (p->size < PCI_MAPREG_IO_SIZE(PCI_MACHDEP_IO_ALIGN_MASK)) { p->mask = PCI_MACHDEP_IO_ALIGN_MASK; p->size = PCI_MAPREG_IO_SIZE(p->mask); } /* * if I/O is already enabled (probably by the console driver) * save the address in order to take care about it later. */ if (csr & PCI_COMMAND_IO_ENABLE) p->address = address; insert_into_list(&iolist, p); } else { p->size = PCI_MAPREG_MEM_SIZE(mask); /* * Align memory if necessary */ if (p->size < PCI_MAPREG_IO_SIZE(PCI_MACHDEP_MEM_ALIGN_MASK)) { p->mask = PCI_MACHDEP_MEM_ALIGN_MASK; p->size = PCI_MAPREG_MEM_SIZE(p->mask); } /* * if memory is already enabled (probably by the console driver) * save the address in order to take care about it later. */ if (csr & PCI_COMMAND_MEM_ENABLE) p->address = address; insert_into_list(&memlist, p); if (PCI_MAPREG_MEM_TYPE(mask) == PCI_MAPREG_MEM_TYPE_64BIT) reg++; } } #if defined(_ATARIHW_) /* * Both interrupt pin & line are set to the device (== slot) * number. This makes sense on the atari Hades because the * individual slots are hard-wired to a specific MFP-pin. */ csr = (DEV2SLOT(dev) << PCI_INTERRUPT_PIN_SHIFT); csr |= (DEV2SLOT(dev) << PCI_INTERRUPT_LINE_SHIFT); pci_conf_write(pc, tag, PCI_INTERRUPT_REG, csr); #else /* * On the Milan, we accept the BIOS's choice. */ #endif } /* * second step: calculate the memory and I/O addresses beginning from * PCI_MEM_START and PCI_IO_START. Care about already mapped areas. * * begin with memory list */ address = PCI_MEM_START; sizecnt = 0; membase_1m = 0; p = LIST_FIRST(&memlist); while (p != NULL) { if (!(p->csr & PCI_COMMAND_MEM_ENABLE)) { if (PCI_MAPREG_MEM_TYPE(p->mask) == PCI_MAPREG_MEM_TYPE_32BIT_1M) { if (p->size > membase_1m) membase_1m = p->size; do { p->address = membase_1m; membase_1m += p->size; } while (overlap_pci_areas(LIST_FIRST(&memlist), p, p->address, p->size, PCI_COMMAND_MEM_ENABLE)); if (membase_1m > 0x00100000) { /* * Should we panic here? */ printf("\npcibus0: dev %d reg %d: memory not configured", p->dev, p->reg); p->reg = 0; } } else { if (sizecnt && (p->size > sizecnt)) sizecnt = ((p->size + sizecnt) & p->mask) & PCI_MAPREG_MEM_ADDR_MASK; if (sizecnt > address) { address = sizecnt; sizecnt = 0; } do { p->address = address + sizecnt; sizecnt += p->size; } while (overlap_pci_areas(LIST_FIRST(&memlist), p, p->address, p->size, PCI_COMMAND_MEM_ENABLE)); if ((address + sizecnt) > PCI_MEM_END) { /* * Should we panic here? */ printf("\npcibus0: dev %d reg %d: memory not configured", p->dev, p->reg); p->reg = 0; } } if (p->reg > 0) { pci_conf_write(pc, p->tag, p->reg, p->address); csr = pci_conf_read(pc, p->tag, PCI_COMMAND_STATUS_REG); csr |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE; pci_conf_write(pc, p->tag, PCI_COMMAND_STATUS_REG, csr); p->csr = csr; } } p = LIST_NEXT(p, link); } /* * now the I/O list */ address = PCI_IO_START; sizecnt = 0; p = LIST_FIRST(&iolist); while (p != NULL) { if (!(p->csr & PCI_COMMAND_IO_ENABLE)) { if (sizecnt && (p->size > sizecnt)) sizecnt = ((p->size + sizecnt) & p->mask) & PCI_MAPREG_IO_ADDR_MASK; if (sizecnt > address) { address = sizecnt; sizecnt = 0; } do { p->address = address + sizecnt; sizecnt += p->size; } while (overlap_pci_areas(LIST_FIRST(&iolist), p, p->address, p->size, PCI_COMMAND_IO_ENABLE)); if ((address + sizecnt) > PCI_IO_END) { /* * Should we panic here? */ printf("\npcibus0: dev %d reg %d: io not configured", p->dev, p->reg); } else { pci_conf_write(pc, p->tag, p->reg, p->address); csr = pci_conf_read(pc, p->tag, PCI_COMMAND_STATUS_REG); csr |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE; pci_conf_write(pc, p->tag, PCI_COMMAND_STATUS_REG, csr); p->csr = csr; } } p = LIST_NEXT(p, link); } #ifdef DEBUG_PCI_MACHDEP printf("\nI/O List:\n"); p = LIST_FIRST(&iolist); while (p != NULL) { printf("\ndev: %d, reg: 0x%02x, size: 0x%08x, addr: 0x%08x", p->dev, p->reg, p->size, p->address); p = LIST_NEXT(p, link); } printf("\nMemlist:"); p = LIST_FIRST(&memlist); while (p != NULL) { printf("\ndev: %d, reg: 0x%02x, size: 0x%08x, addr: 0x%08x", p->dev, p->reg, p->size, p->address); p = LIST_NEXT(p, link); } #endif /* * Free the lists */ p = LIST_FIRST(&iolist); while (p != NULL) { q = p; LIST_REMOVE(q, link); free(p, M_WAITOK); p = LIST_FIRST(&iolist); } p = LIST_FIRST(&memlist); while (p != NULL) { q = p; LIST_REMOVE(q, link); free(p, M_WAITOK); p = LIST_FIRST(&memlist); } }