int pci_func_configure(struct pci_func *f) { uint32_t bar_width; uint32_t bar; for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END; bar += bar_width) { uint32_t oldv = pci_conf_read(f, bar); bar_width = 4; pci_conf_write(f, bar, 0xffffffff); uint32_t rv = pci_conf_read(f, bar); if (rv == 0) continue; int regnum = PCI_MAPREG_NUM(bar); uint32_t base, size; if (PCI_MAPREG_TYPE(rv) == PCI_MAPREG_TYPE_MEM) { if (PCI_MAPREG_MEM_TYPE(rv) == PCI_MAPREG_MEM_TYPE_64BIT) bar_width = 8; size = PCI_MAPREG_MEM_SIZE(rv); base = PCI_MAPREG_MEM_ADDR(oldv); if (!base) { /* device is not properly configured, allocate mmio address for it */ base = pci_allocate_memory(size); if (!base) return ENOMEM; oldv = base; } #ifdef SHOW_PCI_VERBOSE_INFO printf("pci: allocated mem region %d: %d bytes at 0x%x\n", regnum, size, base); #endif } else { #ifdef CONFIG_ARCH_HAS_IO_SPACE /* TODO handle IO region */ #endif } pci_conf_write(f, bar, oldv); f->reg_base[regnum] = base; f->reg_size[regnum] = size; } f->irq_line = pci_allocate_irqline(); /* FIXME */ f->irq_pin = PCI_INTERRUPT_PIN_C; pci_conf_write(f, PCI_INTERRUPT_REG, PCI_INTERRUPT_LINE(f->irq_line) | PCI_INTERRUPT_PIN(f->irq_pin)); printf("pci: function %02x:%02x.%d (%04x:%04x) configured\n", f->bus->busno, f->dev, f->func, PCI_VENDOR(f->dev_id), PCI_PRODUCT(f->dev_id)); return 0; }
int apic_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) { pci_chipset_tag_t pc = pa->pa_pc; struct elroy_softc *sc = pc->_cookie; pcitag_t tag = pa->pa_tag; hppa_hpa_t hpa = cpu_gethpa(0); pcireg_t reg; reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); printf(" pin=%d line=%d ", PCI_INTERRUPT_PIN(reg), PCI_INTERRUPT_LINE(reg)); apic_write(sc->sc_regs, APIC_ENT0(PCI_INTERRUPT_PIN(reg)), PCI_INTERRUPT_LINE(reg)); apic_write(sc->sc_regs, APIC_ENT1(PCI_INTERRUPT_PIN(reg)), ((hpa & 0x0ff00000) >> 4) | ((hpa & 0x000ff000) << 12)); *ihp = PCI_INTERRUPT_LINE(reg) + 1; return (*ihp == 0); }
int apic_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) { struct elroy_softc *sc = pa->pa_pc->_cookie; pci_chipset_tag_t pc = pa->pa_pc; pcitag_t tag = pa->pa_tag; pcireg_t reg; int line; reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); #ifdef DEBUG printf(" pin=%d line=%d ", PCI_INTERRUPT_PIN(reg), PCI_INTERRUPT_LINE(reg)); #endif line = PCI_INTERRUPT_LINE(reg); if (sc->sc_irq[line] == 0) sc->sc_irq[line] = cpu_intr_findirq(); *ihp = (line << APIC_INT_LINE_SHIFT) | sc->sc_irq[line]; return (APIC_INT_IRQ(*ihp) == 0); }
static int pci_scan_bus(struct pci_bus *bus) { int totaldev = 0; struct pci_func df; memset(&df, 0, sizeof(df)); df.bus = bus; for (df.dev = 0; df.dev < 32; df.dev++) { uint32_t bhlc = pci_conf_read(&df, PCI_BHLC_REG); struct pci_func f; if (PCI_HDRTYPE_TYPE(bhlc) > 1) /* Unsupported or no device */ continue; /* found a device */ totaldev++; f = df; for (f.func = 0; f.func < (PCI_HDRTYPE_MULTIFN(bhlc) ? 8 : 1); f.func++) { struct pci_func *af; uint32_t dev_id; uint32_t intr; dev_id = pci_conf_read(&f, PCI_ID_REG); if (PCI_VENDOR(dev_id) == 0xffff) continue; /* found a function */ af = kmem_alloc(sizeof(*af)); *af = f; list_init(&af->link); list_insert(&pci_func_list, &af->link); af->dev_id = dev_id; intr = pci_conf_read(af, PCI_INTERRUPT_REG); af->irq_line = PCI_INTERRUPT_LINE(intr); af->dev_class = pci_conf_read(af, PCI_CLASS_REG); #ifdef SHOW_PCI_VERBOSE_INFO pci_print_func(af); #endif } } return totaldev; }
int pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) { pcireg_t intr; int pin; int line; intr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_INTERRUPT_REG); pin = pa->pa_intrpin; pa->pa_intrline = line = PCI_INTERRUPT_LINE(intr); #if 0 /* XXXX why is it always 0 ? */ if (pin == 0) { /* No IRQ used */ goto bad; } #endif if (pin > PCI_INTERRUPT_PIN_MAX) { printf("pci_intr_map: bad interrupt pin %d\n", pin); goto bad; } if (line == 0 || line == X86_PCI_INTERRUPT_LINE_NO_CONNECTION) { printf("pci_intr_map: no mapping for pin %c (line=%02x)\n", '@' + pin, line); goto bad; } ihp->pirq = line; ihp->evtch = bind_pirq_to_evtch(ihp->pirq); if (ihp->evtch == -1) goto bad; return 0; bad: ihp->pirq = -1; ihp->evtch = -1; return 1; }
void kauaiataattach(struct device *parent, struct device *self, void *aux) { int node; struct confargs ca; int namelen; u_int32_t reg[20]; char name[32]; int32_t intr[8]; struct kauaiata_softc *sc = (struct kauaiata_softc *)self; struct pci_attach_args *pa = aux; pci_chipset_tag_t pc = pa->pa_pc; /* XXX assumes that this is /pci@f400000/ata-6 */ /* vendor 0x106b product 0x003b (class undefined unknown subclass 0x00, rev 0x00) at pci2 dev 13 function 0 not configured */ node = OF_finddevice("/pci@f4000000/ata-6"); /* * XXX - need to compare node and PCI id to verify this is the * correct device. */ ca.ca_nreg = OF_getprop(node, "reg", reg, sizeof(reg)); intr[0] = PCI_INTERRUPT_LINE(pci_conf_read(pc, pa->pa_tag, PCI_INTERRUPT_REG)); ca.ca_nintr = 4; /* claim to have 4 bytes of interrupt info */ /* This needs to come from INTERRUPT REG above, but is not filled out */ intr[0] = 0x27; namelen = OF_getprop(node, "name", name, sizeof(name)); if ((namelen < 0) || (namelen >= sizeof(name))) { printf(" bad name prop len %x\n", namelen); return; } name[namelen] = 0; /* name property may not be null terminated */ /* config read */ sc->sc_membus_space.bus_base = pci_conf_read(pc, pa->pa_tag, PCI_MAPREG_START); #if 0 pci_conf_write(pc, pa->pa_tag, PCI_MAPREG_START, 0xffffffff); size = ~(pci_conf_read(pc, pa->pa_tag, PCI_MAPREG_START)); pci_conf_write(pc, pa->pa_tag, PCI_MAPREG_START, sc->sc_membus_space.bus_base); #endif ca.ca_baseaddr = sc->sc_membus_space.bus_base; sc->sc_membus_space.bus_reverse = 1; ca.ca_name = name; ca.ca_iot = &sc->sc_membus_space; ca.ca_dmat = pa->pa_dmat; ca.ca_reg = reg; reg[0] = 0x2000; /* offset to wdc registers */ reg[1] = reg[9] - 0x2000; /* map size of wdc registers */ reg[2] = 0x1000; /* offset to dbdma registers */ reg[3] = 0x1000; /* map size of dbdma registers */ ca.ca_intr = intr; printf("\n"); config_found(self, &ca, kauaiata_print); }
int pci_probe_device(struct pci_softc *sc, pcitag_t tag, int (*match)(const struct pci_attach_args *), struct pci_attach_args *pap) { pci_chipset_tag_t pc = sc->sc_pc; struct pci_attach_args pa; pcireg_t id, /* csr, */ pciclass, intr, bhlcr, bar, endbar; #ifdef __HAVE_PCI_MSI_MSIX pcireg_t cap; int off; #endif int ret, pin, bus, device, function, i, width; int locs[PCICF_NLOCS]; pci_decompose_tag(pc, tag, &bus, &device, &function); /* a driver already attached? */ if (sc->PCI_SC_DEVICESC(device, function).c_dev != NULL && !match) return 0; bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); if (PCI_HDRTYPE_TYPE(bhlcr) > 2) return 0; id = pci_conf_read(pc, tag, PCI_ID_REG); /* csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); */ pciclass = pci_conf_read(pc, tag, PCI_CLASS_REG); /* Invalid vendor ID value? */ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) return 0; /* XXX Not invalid, but we've done this ~forever. */ if (PCI_VENDOR(id) == 0) return 0; /* Collect memory range info */ memset(sc->PCI_SC_DEVICESC(device, function).c_range, 0, sizeof(sc->PCI_SC_DEVICESC(device, function).c_range)); i = 0; switch (PCI_HDRTYPE_TYPE(bhlcr)) { case PCI_HDRTYPE_PPB: endbar = PCI_MAPREG_PPB_END; break; case PCI_HDRTYPE_PCB: endbar = PCI_MAPREG_PCB_END; break; default: endbar = PCI_MAPREG_END; break; } for (bar = PCI_MAPREG_START; bar < endbar; bar += width) { struct pci_range *r; pcireg_t type; width = 4; if (pci_mapreg_probe(pc, tag, bar, &type) == 0) continue; if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_MEM) { if (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT) width = 8; r = &sc->PCI_SC_DEVICESC(device, function).c_range[i++]; if (pci_mapreg_info(pc, tag, bar, type, &r->r_offset, &r->r_size, &r->r_flags) != 0) break; if ((PCI_VENDOR(id) == PCI_VENDOR_ATI) && (bar == 0x10) && (r->r_size == 0x1000000)) { struct pci_range *nr; /* * this has to be a mach64 * split things up so each half-aperture can * be mapped PREFETCHABLE except the last page * which may contain registers */ r->r_size = 0x7ff000; r->r_flags = BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE; nr = &sc->PCI_SC_DEVICESC(device, function).c_range[i++]; nr->r_offset = r->r_offset + 0x800000; nr->r_size = 0x7ff000; nr->r_flags = BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE; } } } pa.pa_iot = sc->sc_iot; pa.pa_memt = sc->sc_memt; pa.pa_dmat = sc->sc_dmat; pa.pa_dmat64 = sc->sc_dmat64; pa.pa_pc = pc; pa.pa_bus = bus; pa.pa_device = device; pa.pa_function = function; pa.pa_tag = tag; pa.pa_id = id; pa.pa_class = pciclass; /* * Set up memory, I/O enable, and PCI command flags * as appropriate. */ pa.pa_flags = sc->sc_flags; /* * If the cache line size is not configured, then * clear the MRL/MRM/MWI command-ok flags. */ if (PCI_CACHELINE(bhlcr) == 0) { pa.pa_flags &= ~(PCI_FLAGS_MRL_OKAY| PCI_FLAGS_MRM_OKAY|PCI_FLAGS_MWI_OKAY); } if (sc->sc_bridgetag == NULL) { pa.pa_intrswiz = 0; pa.pa_intrtag = tag; } else { pa.pa_intrswiz = sc->sc_intrswiz + device; pa.pa_intrtag = sc->sc_intrtag; } intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); pin = PCI_INTERRUPT_PIN(intr); pa.pa_rawintrpin = pin; if (pin == PCI_INTERRUPT_PIN_NONE) { /* no interrupt */ pa.pa_intrpin = 0; } else { /* * swizzle it based on the number of busses we're * behind and our device number. */ pa.pa_intrpin = /* XXX */ ((pin + pa.pa_intrswiz - 1) % 4) + 1; } pa.pa_intrline = PCI_INTERRUPT_LINE(intr); #ifdef __HAVE_PCI_MSI_MSIX if (pci_get_ht_capability(pc, tag, PCI_HT_CAP_MSIMAP, &off, &cap)) { /* * XXX Should we enable MSI mapping ourselves on * systems that have it disabled? */ if (cap & PCI_HT_MSI_ENABLED) { uint64_t addr; if ((cap & PCI_HT_MSI_FIXED) == 0) { addr = pci_conf_read(pc, tag, off + PCI_HT_MSI_ADDR_LO); addr |= (uint64_t)pci_conf_read(pc, tag, off + PCI_HT_MSI_ADDR_HI) << 32; } else addr = PCI_HT_MSI_FIXED_ADDR; /* * XXX This will fail to enable MSI on systems * that don't use the canonical address. */ if (addr == PCI_HT_MSI_FIXED_ADDR) { pa.pa_flags |= PCI_FLAGS_MSI_OKAY; pa.pa_flags |= PCI_FLAGS_MSIX_OKAY; } } } #endif if (match != NULL) { ret = (*match)(&pa); if (ret != 0 && pap != NULL) *pap = pa; } else { struct pci_child *c; locs[PCICF_DEV] = device; locs[PCICF_FUNCTION] = function; c = &sc->PCI_SC_DEVICESC(device, function); pci_conf_capture(pc, tag, &c->c_conf); if (pci_get_powerstate(pc, tag, &c->c_powerstate) == 0) c->c_psok = true; else c->c_psok = false; c->c_dev = config_found_sm_loc(sc->sc_dev, "pci", locs, &pa, pciprint, config_stdsubmatch); ret = (c->c_dev != NULL); } return ret; }