/* Return the mapping of a cc3 device/function interrupt to an interrupt line. For the SB-1250, return 1-4 to indicate the pci_inta - pci_intd inputs to the interrupt mapper, respectively, or 0 if there is no mapping. */ uint8_t pci_int_map_0(pcitag_t tag) { #ifdef _C3H_ pcireg_t data; int pin, bus, device; data = pci_conf_read(tag, PCI_BPARAM_INTERRUPT_REG); pin = PCI_INTERRUPT_PIN(data); if (pin == 0) { /* No IRQ used. */ return 0; } if (pin > 4) { if (_pciverbose >= 1) pci_tagprintf(tag, "pci_map_int: bad interrupt pin %d\n", pin); return 0; } pci_break_tag(tag, NULL, &bus, &device, NULL); return (bus == 0) ? pin : 0; #else return 0; #endif }
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); }
void netwinder_pci_attach_hook (struct device *parent, struct device *self, struct pcibus_attach_args *pba) { pcireg_t regval; pcireg_t intreg; pcitag_t tag; /* * Initialize the TULIP */ tag = pci_make_tag(pba->pba_pc, pba->pba_bus, 9, 0); pci_conf_write(pba->pba_pc, tag, PCI_COMMAND_STATUS_REG, PCI_COMMAND_IO_ENABLE| PCI_COMMAND_MEM_ENABLE| PCI_COMMAND_MASTER_ENABLE); intreg = pci_conf_read(pba->pba_pc, tag, PCI_INTERRUPT_REG); intreg = PCI_INTERRUPT_CODE( PCI_INTERRUPT_LATENCY(intreg), PCI_INTERRUPT_GRANT(intreg), PCI_INTERRUPT_PIN(intreg), 0x40|IRQ_IN_L1); pci_conf_write(pba->pba_pc, tag, PCI_INTERRUPT_REG, intreg); pci_conf_write(pba->pba_pc, tag, 0x10, 0x400 | PCI_MAPREG_TYPE_IO); pci_conf_write(pba->pba_pc, tag, 0x14, 0x00800000); /* * Initialize the PCI NE2000 */ tag = pci_make_tag(pba->pba_pc, pba->pba_bus, 12, 0); pci_conf_write(pba->pba_pc, tag, PCI_COMMAND_STATUS_REG, PCI_COMMAND_IO_ENABLE| PCI_COMMAND_MASTER_ENABLE); intreg = pci_conf_read(pba->pba_pc, tag, PCI_INTERRUPT_REG); intreg = PCI_INTERRUPT_CODE( PCI_INTERRUPT_LATENCY(intreg), PCI_INTERRUPT_GRANT(intreg), PCI_INTERRUPT_PIN(intreg), 0x40|IRQ_IN_L0); pci_conf_write(pba->pba_pc, tag, PCI_INTERRUPT_REG, intreg); pci_conf_write(pba->pba_pc, tag, 0x10, 0x300 | PCI_MAPREG_TYPE_IO); #if 0 /* * Initialize the PCI-ISA Bridge */ tag = pci_make_tag(pba->pba_pc, pba->pba_bus, 11, 0); pci_conf_write(pba->pba_pc, tag, PCI_COMMAND_STATUS_REG, PCI_COMMAND_IO_ENABLE| PCI_COMMAND_MEM_ENABLE| PCI_COMMAND_MASTER_ENABLE); pci_conf_write(pba->pba_pc, tag, 0x10, 0); pci_conf_write(pba->pba_pc, tag, 0x48, pci_conf_read(pba->pba_pc, tag, 0x48)|0xff); regval = pci_conf_read(pba->pba_pc, tag, 0x40); regval &= 0xff00ff00; regval |= 0x00000022; pci_conf_write(pba->pba_pc, tag, 0x40, regval); regval = pci_conf_read(pba->pba_pc, tag, 0x80); regval &= 0x0000ff00; regval |= 0xe0010002; pci_conf_write(pba->pba_pc, tag, 0x80, regval); #endif /* * Initialize the PCIIDE Controller */ tag = pci_make_tag(pba->pba_pc, pba->pba_bus, 11, 1); pci_conf_write(pba->pba_pc, tag, PCI_COMMAND_STATUS_REG, PCI_COMMAND_IO_ENABLE| PCI_COMMAND_MASTER_ENABLE); regval = pci_conf_read(pba->pba_pc, tag, PCI_CLASS_REG); regval = PCI_CLASS_CODE(PCI_CLASS(regval), PCI_SUBCLASS(regval), 0x8A); pci_conf_write(pba->pba_pc, tag, PCI_CLASS_REG, regval); regval = pci_conf_read(pba->pba_pc, tag, 0x40); regval &= ~0x10; /* disable secondary port */ pci_conf_write(pba->pba_pc, tag, 0x40, regval); pci_conf_write(pba->pba_pc, tag, 0x10, 0x01f0 | PCI_MAPREG_TYPE_IO); pci_conf_write(pba->pba_pc, tag, 0x14, 0x03f4 | PCI_MAPREG_TYPE_IO); pci_conf_write(pba->pba_pc, tag, 0x18, 0x0170 | PCI_MAPREG_TYPE_IO); pci_conf_write(pba->pba_pc, tag, 0x1c, 0x0374 | PCI_MAPREG_TYPE_IO); pci_conf_write(pba->pba_pc, tag, 0x20, 0xe800 | PCI_MAPREG_TYPE_IO); intreg = pci_conf_read(pba->pba_pc, tag, PCI_INTERRUPT_REG); intreg = PCI_INTERRUPT_CODE( PCI_INTERRUPT_LATENCY(intreg), PCI_INTERRUPT_GRANT(intreg), PCI_INTERRUPT_PIN(intreg), 0x8e); pci_conf_write(pba->pba_pc, tag, PCI_INTERRUPT_REG, intreg); /* * Make sure we are in legacy mode */ regval = pci_conf_read(pba->pba_pc, tag, 0x40); regval &= ~0x800; pci_conf_write(pba->pba_pc, tag, 0x40, regval); }
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; }