📄 hw_phb.c
字号:
if (isxdigit(*chp)) { set_ss(address, ss_config_code); } else { /* non-relocatable? */ if (*chp == 'n') { set_n(address); chp++; } /* address-space? */ if (*chp == 'i') { set_ss(address, ss_io_code); chp++; } else if (*chp == 'm') { set_ss(address, ss_32bit_memory_code); chp++; } else if (*chp == 'x') { set_ss(address, ss_64bit_memory_code); chp++; } else device_error(me, "Problem parsing PCI address %s", unit); /* possible alias */ if (*chp == 't') { if (extract_ss(address) == ss_64bit_memory_code) device_error(me, "Invalid alias bit in PCI address %s", unit); set_t(address); chp++; } /* possible p */ if (*chp == 'p') { if (extract_ss(address) != ss_32bit_memory_code) device_error(me, "Invalid prefetchable bit (p) in PCI address %s", unit); set_p(address); chp++; } } /* required DD */ if (!isxdigit(*chp)) device_error(me, "Missing device number in PCI address %s", unit); val = strtoul(chp, &end, 16); if (chp == end) device_error(me, "Problem parsing device number in PCI address %s", unit); if ((val & 0x1f) != val) device_error(me, "Device number (0x%lx) out of range (0..0x1f) in PCI address %s", val, unit); set_ddddd(address, val); chp = end; /* For config space, the F is optional */ if (extract_ss(address) == ss_config_code && (isspace(*chp) || *chp == '\0')) return chp - unit; /* function number F */ if (*chp != ',') device_error(me, "Missing function number in PCI address %s", unit); chp++; val = strtoul(chp, &end, 10); if (chp == end) device_error(me, "Problem parsing function number in PCI address %s", unit); if ((val & 7) != val) device_error(me, "Function number (%ld) out of range (0..7) in PCI address %s", (long)val, unit); set_fff(address, val); chp = end; /* for config space, must be end */ if (extract_ss(address) == ss_config_code) { if (!isspace(*chp) && *chp != '\0') device_error(me, "Problem parsing PCI config address %s", unit); return chp - unit; } /* register number RR */ if (*chp != ',') device_error(me, "Missing register number in PCI address %s", unit); chp++; val = strtoul(chp, &end, 16); if (chp == end) device_error(me, "Problem parsing register number in PCI address %s", unit); switch (extract_ss(address)) { case ss_io_code:#if 0 if (extract_n(address) && val != 0) device_error(me, "non-relocatable I/O register must be zero in PCI address %s", unit); else if (!extract_n(address) && val != 0x10 && val != 0x14 && val != 0x18 && val != 0x1c && val != 0x20 && val != 0x24) device_error(me, "I/O register invalid in PCI address %s", unit);#endif break; case ss_32bit_memory_code:#if 0 if (extract_n(address) && val != 0) device_error(me, "non-relocatable memory register must be zero in PCI address %s", unit); else if (!extract_n(address) && val != 0x10 && val != 0x14 && val != 0x18 && val != 0x1c && val != 0x20 && val != 0x24 && val != 0x30) device_error(me, "I/O register (0x%lx) invalid in PCI address %s", val, unit);#endif break; case ss_64bit_memory_code: if (extract_n(address) && val != 0) device_error(me, "non-relocatable 32bit memory register must be zero in PCI address %s", unit); else if (!extract_n(address) && val != 0x10 && val != 0x18 && val != 0x20) device_error(me, "Register number (0x%lx) invalid in 64bit PCI address %s", val, unit); case ss_config_code: device_error(me, "internal error"); } if ((val & 0xff) != val) device_error(me, "Register number (0x%lx) out of range (0..0xff) in PCI address %s", val, unit); set_rrrrrrrr(address, val); chp = end; /* address */ if (*chp != ',') device_error(me, "Missing address in PCI address %s", unit); chp++; switch (extract_ss(address)) { case ss_io_code: case ss_32bit_memory_code: val = strtoul(chp, &end, 16); if (chp == end) device_error(me, "Problem parsing address in PCI address %s", unit); switch (extract_ss(address)) { case ss_io_code: if (extract_n(address) && extract_t(address) && (val & 1024) != val) device_error(me, "10bit aliased non-relocatable address (0x%lx) out of range in PCI address %s", val, unit); if (!extract_n(address) && extract_t(address) && (val & 0xffff) != val) device_error(me, "64k relocatable address (0x%lx) out of range in PCI address %s", val, unit); break; case ss_32bit_memory_code: if (extract_t(address) && (val & 0xfffff) != val) device_error(me, "1mb memory address (0x%lx) out of range in PCI address %s", val, unit); if (!extract_t(address) && (val & 0xffffffff) != val) device_error(me, "32bit memory address (0x%lx) out of range in PCI address %s", val, unit); break; case ss_64bit_memory_code: case ss_config_code: device_error(me, "internal error"); } set_ll_ll(address, val); chp = end; break; case ss_64bit_memory_code: device_error(me, "64bit addresses unimplemented"); set_hh_hh(address, val); set_ll_ll(address, val); break; case ss_config_code: device_error(me, "internal error"); break; } /* finished? */ if (!isspace(*chp) && *chp != '\0') device_error(me, "Problem parsing PCI address %s", unit); return chp - unit;}/* Convert PCI device unit into its corresponding textual representation */static inthw_phb_unit_encode(device *me, const device_unit *unit_address, char *buf, int sizeof_buf){ if (unit_address->nr_cells != 3) device_error(me, "Incorrect number of cells in PCI unit address"); if (device_nr_address_cells(me) != 3) device_error(me, "PCI bus should have #address-cells == 3"); if (extract_ss(unit_address) == ss_config_code && extract_fff(unit_address) == 0 && extract_rrrrrrrr(unit_address) == 0 && extract_hh_hh(unit_address) == 0 && extract_ll_ll(unit_address) == 0) { /* DD - Configuration Space address */ sprintf(buf, "%x", extract_ddddd(unit_address)); } else if (extract_ss(unit_address) == ss_config_code && extract_fff(unit_address) != 0 && extract_rrrrrrrr(unit_address) == 0 && extract_hh_hh(unit_address) == 0 && extract_ll_ll(unit_address) == 0) { /* DD,F - Configuration Space */ sprintf(buf, "%x,%d", extract_ddddd(unit_address), extract_fff(unit_address)); } else if (extract_ss(unit_address) == ss_io_code && extract_hh_hh(unit_address) == 0) { /* [n]i[t]DD,F,RR,NNNNNNNN - 32bit I/O space */ sprintf(buf, "%si%s%x,%d,%x,%x", extract_n(unit_address) ? "n" : "", extract_t(unit_address) ? "t" : "", extract_ddddd(unit_address), extract_fff(unit_address), extract_rrrrrrrr(unit_address), extract_ll_ll(unit_address)); } else if (extract_ss(unit_address) == ss_32bit_memory_code && extract_hh_hh(unit_address) == 0) { /* [n]m[t][p]DD,F,RR,NNNNNNNN - 32bit memory space */ sprintf(buf, "%sm%s%s%x,%d,%x,%x", extract_n(unit_address) ? "n" : "", extract_t(unit_address) ? "t" : "", extract_p(unit_address) ? "p" : "", extract_ddddd(unit_address), extract_fff(unit_address), extract_rrrrrrrr(unit_address), extract_ll_ll(unit_address)); } else if (extract_ss(unit_address) == ss_32bit_memory_code) { /* [n]x[p]DD,F,RR,NNNNNNNNNNNNNNNN - 64bit memory space */ sprintf(buf, "%sx%s%x,%d,%x,%x%08x", extract_n(unit_address) ? "n" : "", extract_p(unit_address) ? "p" : "", extract_ddddd(unit_address), extract_fff(unit_address), extract_rrrrrrrr(unit_address), extract_hh_hh(unit_address), extract_ll_ll(unit_address)); } else { device_error(me, "Invalid PCI unit address 0x%08lx 0x%08lx 0x%08lx", (unsigned long)unit_address->cells[0], (unsigned long)unit_address->cells[1], (unsigned long)unit_address->cells[2]); } if (strlen(buf) > sizeof_buf) error("buffer overflow"); return strlen(buf);}static inthw_phb_address_to_attach_address(device *me, const device_unit *address, int *attach_space, unsigned_word *attach_address, device *client){ if (address->nr_cells != 3) device_error(me, "attach address has incorrect number of cells"); if (address->cells[1] != 0) device_error(me, "64bit attach address unsupported"); /* directly decode the address/space */ *attach_address = address->cells[2]; switch (extract_ss(address)) { case ss_config_code: *attach_space = hw_phb_config_space; break; case ss_io_code: *attach_space = hw_phb_io_space; break; case ss_32bit_memory_code: case ss_64bit_memory_code: *attach_space = hw_phb_memory_space; break; } /* if non-relocatable finished */ if (extract_n(address)) return 1; /* make memory and I/O addresses absolute */ if (*attach_space == hw_phb_io_space || *attach_space == hw_phb_memory_space) { int reg_nr; reg_property_spec assigned; if (extract_ss(address) == ss_64bit_memory_code) device_error(me, "64bit memory address not unsuported"); for (reg_nr = 0; device_find_reg_array_property(client, "assigned-addresses", reg_nr, &assigned); reg_nr++) { if (!extract_n(&assigned.address) || extract_rrrrrrrr(&assigned.address) == 0) device_error(me, "client %s has invalid assigned-address property", device_path(client)); if (extract_rrrrrrrr(address) == extract_rrrrrrrr(&assigned.address)) { /* corresponding base register */ if (extract_ss(address) != extract_ss(&assigned.address)) device_error(me, "client %s has conflicting types for base register 0x%lx", device_path(client), (unsigned long)extract_rrrrrrrr(address)); *attach_address += assigned.address.cells[2]; return 0; } } device_error(me, "client %s missing base address register 0x%lx in assigned-addresses property", device_path(client), (unsigned long)extract_rrrrrrrr(address)); } return 0;}static inthw_phb_size_to_attach_size(device *me, const device_unit *size, unsigned *nr_bytes, device *client){ if (size->nr_cells != 2) device_error(me, "size has incorrect number of cells"); if (size->cells[0] != 0) device_error(me, "64bit size unsupported"); *nr_bytes = size->cells[1]; return size->cells[1];}static const phb_space *find_phb_space(hw_phb_device *phb, unsigned_word addr, unsigned nr_bytes){ hw_phb_spaces space; /* find the space that matches the address */ for (space = 0; space < nr_hw_phb_spaces; space++) { phb_space *pci_space = &phb->space[space]; if (addr >= pci_space->parent_base && (addr + nr_bytes) <= (pci_space->parent_base + pci_space->size)) { return pci_space; } } return NULL;}static unsigned_wordmap_phb_addr(const phb_space *space, unsigned_word addr){ return addr - space->parent_base + space->my_base;}static unsignedhw_phb_io_read_buffer(device *me, void *dest, int space, unsigned_word addr, unsigned nr_bytes, cpu *processor, unsigned_word cia){ hw_phb_device *phb = (hw_phb_device*)device_data(me); const phb_space *pci_space = find_phb_space(phb, addr, nr_bytes); unsigned_word bus_addr; if (pci_space == NULL) return 0; bus_addr = map_phb_addr(pci_space, addr); DTRACE(phb, ("io read - %d:0x%lx -> %s:0x%lx (%u bytes)\n", space, (unsigned long)addr, pci_space->name, (unsigned long)bus_addr, nr_bytes)); return core_map_read_buffer(pci_space->readable, dest, bus_addr, nr_bytes);}static unsignedhw_phb_io_write_buffer(device *me, const void *source, int space, unsigned_word addr, unsigned nr_bytes, cpu *processor, unsigned_word cia){ hw_phb_device *phb = (hw_phb_device*)device_data(me); const phb_space *pci_space = find_phb_space(phb, addr, nr_bytes); unsigned_word bus_addr; if (pci_space == NULL) return 0; bus_addr = map_phb_addr(pci_space, addr); DTRACE(phb, ("io write - %d:0x%lx -> %s:0x%lx (%u bytes)\n", space, (unsigned long)addr, pci_space->name, (unsigned long)bus_addr, nr_bytes)); return core_map_write_buffer(pci_space->writeable, source, bus_addr, nr_bytes);}static unsignedhw_phb_dma_read_buffer(device *me, void *dest, int space, unsigned_word addr, unsigned nr_bytes){ hw_phb_device *phb = (hw_phb_device*)device_data(me); const phb_space *pci_space; /* find the space */ if (space != hw_phb_memory_space) device_error(me, "invalid dma address space %d", space); pci_space = &phb->space[space]; /* check out the address */ if ((addr >= pci_space->my_base && addr <= pci_space->my_base + pci_space->size) || (addr + nr_bytes >= pci_space->my_base && addr + nr_bytes <= pci_space->my_base + pci_space->size)) device_error(me, "Do not support DMA into own bus"); /* do it */ DTRACE(phb, ("dma read - %s:0x%lx (%d bytes)\n", pci_space->name, addr, nr_bytes)); return device_dma_read_buffer(device_parent(me), dest, pci_space->parent_space, addr, nr_bytes);}static unsignedhw_phb_dma_write_buffer(device *me, const void *source, int space, unsigned_word addr, unsigned nr_bytes, int violate_read_only_section){ hw_phb_device *phb = (hw_phb_device*)device_data(me); const phb_space *pci_space; /* find the space */ if (space != hw_phb_memory_space) device_error(me, "invalid dma address space %d", space); pci_space = &phb->space[space]; /* check out the address */ if ((addr >= pci_space->my_base && addr <= pci_space->my_base + pci_space->size) || (addr + nr_bytes >= pci_space->my_base && addr + nr_bytes <= pci_space->my_base + pci_space->size)) device_error(me, "Do not support DMA into own bus"); /* do it */ DTRACE(phb, ("dma write - %s:0x%lx (%d bytes)\n", pci_space->name, addr, nr_bytes)); return device_dma_write_buffer(device_parent(me), source, pci_space->parent_space, addr, nr_bytes, violate_read_only_section);}static device_callbacks const hw_phb_callbacks = { { hw_phb_init_address, }, { hw_phb_attach_address, }, { hw_phb_io_read_buffer, hw_phb_io_write_buffer }, { hw_phb_dma_read_buffer, hw_phb_dma_write_buffer }, { NULL, }, /* interrupt */ { hw_phb_unit_decode, hw_phb_unit_encode, hw_phb_address_to_attach_address, hw_phb_size_to_attach_size }};static void *hw_phb_create(const char *name, const device_unit *unit_address, const char *args){ /* create the descriptor */ hw_phb_device *phb = ZALLOC(hw_phb_device); /* create the core maps now */ hw_phb_spaces space_nr; for (space_nr = 0; space_nr < nr_hw_phb_spaces; space_nr++) { phb_space *pci_space = &phb->space[space_nr]; pci_space->map = core_create(); pci_space->readable = core_readable(pci_space->map); pci_space->writeable = core_writeable(pci_space->map); switch (space_nr) { case hw_phb_memory_space: pci_space->name = "memory"; break; case hw_phb_io_space: pci_space->name = "I/O"; break; case hw_phb_config_space: pci_space->name = "config"; break; case hw_phb_special_space: pci_space->name = "special"; break; default: error ("internal error"); break; } } return phb;}const device_descriptor hw_phb_device_descriptor[] = { { "phb", hw_phb_create, &hw_phb_callbacks }, { "pci", NULL, &hw_phb_callbacks }, { NULL, },};#endif /* _HW_PHB_ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -