📄 sb1250_pci_machdep.c
字号:
mips_wbflush(); addrp = (physaddr_t) SB1250_CFG_ADDR(tag, reg, width); switch (width) { case 1: data = (pcireg_t) phys_read8(addrp); break; case 2: data = (pcireg_t) phys_read16(addrp); break; default: case 4: data = (pcireg_t) phys_read32(addrp); break; } mips_wbflush(); return data;}pcireg_tpci_conf_read8(pcitag_t tag, int reg){ return pci_conf_readn(tag, reg, 1);}pcireg_tpci_conf_read16(pcitag_t tag, int reg){ return pci_conf_readn(tag, reg, 2);}pcireg_tpci_conf_read(pcitag_t tag, int reg){ return pci_conf_readn(tag, reg, 4);}static voidpci_conf_writen(pcitag_t tag, int reg, pcireg_t data, int width){ physaddr_t addrp;#if (PCI_DEBUG != 0) int port, bus, device, function; if (reg & (width-1) || reg < 0 || reg > PCI_REGMAX) { if (_pciverbose != 0) pci_tagprintf(tag, "pci_conf_writen: bad reg 0x%x\n", reg); return; } pci_break_tag(tag, &port, &bus, &device, &function); if (bus > PCI_BUSMAX || device > PCI_DEVMAX || function > PCI_FUNCMAX) { if (_pciverbose != 0) pci_tagprintf(tag, "pci_conf_writen: bad tag 0x%x\n", tag); return; }#endif /* PCI_DEBUG */ mips_wbflush(); addrp = (physaddr_t) SB1250_CFG_ADDR(tag, reg, width); switch (width) { case 1: phys_write8(addrp, data); break; case 2: phys_write16(addrp, data); break; default: case 4: phys_write32(addrp, data); break; } mips_wbflush();}voidpci_conf_write8(pcitag_t tag, int reg, pcireg_t data){ pci_conf_writen(tag, reg, data, 1);}voidpci_conf_write16(pcitag_t tag, int reg, pcireg_t data){ pci_conf_writen(tag, reg, data, 2);}voidpci_conf_write(pcitag_t tag, int reg, pcireg_t data){ pci_conf_writen(tag, reg, data, 4);}/* Acked writes are intended primarily for updating the unitID field during HT fabric initialization. The write changes the address of the target, so further accesses should be avoided until the write completes or times out. */intpci_conf_write_acked(pcitag_t tag, int reg, pcireg_t data){ int done; if (sb1250_ldt_init) { int port, bus; pcireg_t bus_info, cr; int i; pci_break_tag(tag, &port, &bus, NULL, NULL); bus_info = pci_conf_read(SB1250_LDT_BRIDGE, PPB_BUSINFO_REG); if (bus >= PPB_BUSINFO_SECONDARY(bus_info) && bus <= PPB_BUSINFO_SUBORD(bus_info)) { /* Write through the LDT host bridge. An HT configuration write is non-posted, but the ZBbus write completes as if it were posted. The following code assumes there are no overlapping non-posted HT writes. */ cr = pci_conf_read(SB1250_LDT_BRIDGE, PCI_CLASS_REG); if (PCI_REVISION(cr) >= 2) { /* Current parts can count tgt_done responses. */ unsigned int count, prev_count; prev_count = pci_conf_read(SB1250_LDT_BRIDGE, LHB_ASTAT_REG); prev_count &= LHB_ASTAT_TGTDONE_MASK; pci_conf_write(tag, reg, data); for (i = 0; i < 1000; i++) { count = pci_conf_read(SB1250_LDT_BRIDGE, LHB_ASTAT_REG); count &= LHB_ASTAT_TGTDONE_MASK; if (count != prev_count) break; } done = (count != prev_count); } else { /* For pass 1, a couple of innocuous writes seems the best we can do (a read with the new tag could hang) */ pci_conf_write(tag, reg, data); for (i = 0; i < 10; i++) pci_conf_write(tag, PCI_ID_REG, 0); done = 1; } } else { /* Write through the PCI host bridge. Just read it back. */ pci_conf_write(tag, reg, data); (void) pci_conf_read(tag, reg); /* Push the write */ done = 1; } } else { /* No LDT. Write and read back. */ pci_conf_write(tag, reg, data); (void) pci_conf_read(tag, reg); done = 1; } return done;}intpci_map_io(pcitag_t tag, int reg, pci_endian_t endian, phys_addr_t *pap){ pcireg_t address; phys_addr_t pa; if (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3)) { if (_pciverbose != 0) pci_tagprintf(tag, "pci_map_io: bad request\n"); return -1; } address = pci_conf_read(tag, reg); if ((address & PCI_MAPREG_TYPE_IO) == 0) { if (_pciverbose != 0) pci_tagprintf(tag, "pci_map_io: attempt to i/o map a memory region\n"); return -1; } pa = ((address & PCI_MAPREG_IO_ADDR_MASK) - Q.pci_io_base) + Q.io_space; if (endian == PCI_MATCH_BITS) pa |= Q.io_bit_endian; *pap = pa; return 0;}intpci_map_mem(pcitag_t tag, int reg, pci_endian_t endian, phys_addr_t *pap){ pcireg_t address; phys_addr_t pa; if (reg == PCI_MAPREG_ROM) { /* expansion ROM */ address = pci_conf_read(tag, reg); if ((address & PCI_MAPREG_ROM_ENABLE) == 0) { pci_tagprintf(tag, "pci_map_mem: attempt to map missing rom\n"); return -1; } pa = address & PCI_MAPREG_ROM_ADDR_MASK; } else { if (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3)) { if (_pciverbose != 0) pci_tagprintf(tag, "pci_map_mem: bad request\n"); return -1; } address = pci_conf_read(tag, reg); if ((address & PCI_MAPREG_TYPE_IO) != 0) { if (_pciverbose != 0) pci_tagprintf(tag, "pci_map_mem: attempt to memory map an I/O region\n"); return -1; } pa = address & PCI_MAPREG_MEM_ADDR_MASK; switch (address & PCI_MAPREG_MEM_TYPE_MASK) { case PCI_MAPREG_MEM_TYPE_32BIT: case PCI_MAPREG_MEM_TYPE_32BIT_1M: break; case PCI_MAPREG_MEM_TYPE_64BIT: if (reg + 4 < PCI_MAPREG_END) pa |= ((phys_addr_t)pci_conf_read(tag, reg+4) << 32); else { if (_pciverbose != 0) pci_tagprintf(tag, "pci_map_mem: bad 64-bit reguest\n"); return -1; } break; default: if (_pciverbose != 0) pci_tagprintf(tag, "pci_map_mem: reserved mapping type\n"); return -1; } } pa = (pa - Q.pci_mem_base) + Q.mem_space; if (endian == PCI_MATCH_BITS) pa |= Q.mem_bit_endian; *pap = pa; return 0;}#define ISAPORT_BASE(x) (Q.io_space + (x))uint8_tinb (unsigned int port){ return phys_read8(ISAPORT_BASE(port));}uint16_tinw (unsigned int port){ return phys_read16(ISAPORT_BASE(port));}uint32_tinl (unsigned int port){ return phys_read32(ISAPORT_BASE(port));}voidoutb (unsigned int port, uint8_t val){ phys_write8(ISAPORT_BASE(port), val); mips_wbflush();}voidoutw (unsigned int port, uint16_t val){ phys_write16(ISAPORT_BASE(port), val); mips_wbflush();}voidoutl (unsigned int port, uint32_t val){ phys_write32(ISAPORT_BASE(port), val); mips_wbflush();}/* Management of MAP table */intpci_map_window(phys_addr_t pa, unsigned int offset, unsigned int len, int l2ca, int endian){ unsigned int first, last; unsigned int i; uint32_t addr; uint32_t entry; if (len == 0) return 0; /* XXX Perhaps check for 1M multiples on offset and len? */ first = offset / PHB_MAP_ENTRY_SPAN; last = (offset + (len-1)) / PHB_MAP_ENTRY_SPAN; if (last >= PHB_MAP_N_ENTRIES) return -1; addr = (pa / PHB_MAP_ENTRY_SPAN) << PHB_MAP_ADDR_SHIFT; for (i = first; i <= last; i++) { entry = (addr & PHB_MAP_ADDR_MASK) | PHB_MAP_ENABLE; if (l2ca) entry |= PHB_MAP_L2CA; if (endian) entry |= PHB_MAP_ENDIAN; pci_conf_write32(SB1250_PCI_BRIDGE, PHB_MAP_REG_BASE + 4*i, entry); addr += (1 << PHB_MAP_ADDR_SHIFT); } return 0;}intpci_unmap_window(unsigned int offset, unsigned int len){ unsigned int first, last; unsigned int i; if (len == 0) return 0; /* XXX Perhaps check for 1M multiples on offset and len? */ first = offset / PHB_MAP_ENTRY_SPAN; if (first >= PHB_MAP_N_ENTRIES) return 0; last = (offset + (len-1)) / PHB_MAP_ENTRY_SPAN; if (last >= PHB_MAP_N_ENTRIES) last = PHB_MAP_N_ENTRIES - 1; for (i = first; i <= last; i++) pci_conf_write32(SB1250_PCI_BRIDGE, PHB_MAP_REG_BASE + 4*i, 0); return 0;}/* Map PCI interrupts A, B, C, D into a value for the IntLine register. For SB1250, return the source number used by the interrupt mapper, or 0xff if none. */uint8_tpci_int_line(uint8_t pci_int){ return (pci_int == 0) ? 0xFF : (56 + (pci_int-1));}/* Assign and map MSI messages and addresses. */static unsigned int next_msi = 0;unsigned intpci_msi_index(void){ unsigned int index = next_msi; next_msi = (next_msi + 1) % 32; return index;}voidpci_msi_encode(unsigned int index, uint64_t *msg_addr, uint16_t *msg_data){ *msg_addr = (Q.msi_set_base | Q.msi_bit_endian) + ((index / 16) << 2); *msg_data = 0x8000 >> (index % 16);}phys_addr_tpci_msi_clear_addr(uint64_t msg_addr){ return Q.msi_clear_base + (msg_addr & (1 << 2));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -