📄 pci.c
字号:
#include <bios/types.h>#include <bios/dec21285.h>#include <bios/debug.h>#include <bios/pci.h>#include <bios/machine.h>#include <bios/malloc.h>#include <bios/stdio.h>#include <bios/string.h>#include <bios/x86.h>static unsigned long pci_io_free;static unsigned long pci_mem_free;static struct pci_dev * pci_root_dev;extern unsigned int ram_size;#ifndef DEBUG#define debug_printf(x...)#endifstatic inline unsigned long pci_alloc(unsigned long *resource, unsigned long size){ unsigned long base; *resource += size - 1; *resource &= ~(size - 1); base = *resource; *resource += size; return base;}static unsigned long pci_alloc_io(unsigned long size){ unsigned long res = pci_io_free; /* * Align resource to the requested size */ res += size - 1; res &= ~(size - 1); /* * Check for overlap with an ISA region */ if (res & 0x300) res = (res + 0x400) & ~0x3ff; pci_io_free = res + size; return res;}static unsigned long pci_alloc_mem(unsigned long size){ return pci_alloc(&pci_mem_free, size);}struct pci_dev *pci_lookupclass(struct pci_dev *dev, unsigned short class){ if (!dev) dev = pci_root_dev; else dev = dev->next; while (dev) { if (dev->class == class && dev->command & (PCI_COMMAND_MEM_SPACE|PCI_COMMAND_IO_SPACE)) break; dev = dev->next; } return dev;}struct pci_dev *pci_lookup_vendor_device(struct pci_dev *dev, unsigned short vendor_id, unsigned short device_id){ if (!dev) dev = pci_root_dev; else dev = dev->next; while (dev) { if (dev->vendor == vendor_id && dev->device == device_id) break; dev = dev->next; } return dev;}struct pci_dev *pci_dev_next(struct pci_dev *dev){ if (!dev) dev = pci_root_dev; else dev = dev->next; return dev;}/* * Enable busmaster mode on the specified device. We also set up * the cache line size and latency timer here. */int pci_set_master(struct pci_dev *dev){ u16 oldcmd = dev->command; dev->command |= PCI_COMMAND_BUS_MASTER; debug_printf("%d.%d: enabling busmaster; 0x%04x to 0x%04x\n", SLOT(dev->dev), FUNC(dev->dev), oldcmd, dev->command); pci_write_config_byte(dev->pci_base, PCI_CACHELINESIZE, 8); pci_write_config_byte(dev->pci_base, PCI_LATENCY_TIMER, 32); pci_write_config_word(dev->pci_base, PCI_COMMAND, dev->command); return 0;}/* * Enable a PCI device. The MEM_SPACE and IO_SPACE bits are set * according to the requirements of the PCI device. */int pci_enable(struct pci_dev *dev){ u16 oldcmd = dev->command; int i; for (i = 0; i < 6; i++) { if (dev->bar[i]) { if (dev->bar[i] & 1) dev->command |= PCI_COMMAND_IO_SPACE; else dev->command |= PCI_COMMAND_MEM_SPACE; } } switch (dev->class >> 8) { case PCI_CLASS_NOT_DEFINED: case PCI_BASE_CLASS_DISPLAY: case PCI_BASE_CLASS_STORAGE: dev->command |= PCI_COMMAND_IO_SPACE; break; } if (dev->bar[7]) dev->command |= PCI_COMMAND_MEM_SPACE; debug_printf("%d.%d: enabling device; 0x%04x to 0x%04x\n", SLOT(dev->dev), FUNC(dev->dev), oldcmd, dev->command); pci_write_config_word(dev->pci_base, PCI_COMMAND, dev->command); return 0;}/* * Disable all accesses to the PCI device */int pci_disable(struct pci_dev *dev){ u16 oldcmd = dev->command; dev->command &= ~(PCI_COMMAND_IO_SPACE | PCI_COMMAND_MEM_SPACE); debug_printf("%d.%d: disabling device; 0x%04x to 0x%04x\n", SLOT(dev->dev), FUNC(dev->dev), oldcmd, dev->command); pci_write_config_word(dev->pci_base, PCI_COMMAND, dev->command); return 0;}static int pci_init_hw(void){ unsigned int ctrl = csr_read_long(CSR_CTRL); unsigned int rsz, sz; csr_write_long(0, CSR_PCIEXTN); /* * Set up the mask registers */ csr_write_long(12, CSR_OIMR); csr_write_long(0, CSR_DPMR); csr_write_long(0, CSR_DSMR); /* * Calculate the size of the SDRAM (for the base address mask * register) */ rsz = (ram_size - 1) >> 19; for (sz = 0x00040000; rsz; rsz >>= 1, sz = sz | sz << 1); /* * Set up the PCI -> Host mappings */ csr_write_long(sz, CSR_SDRAMBASEADDRMASK); csr_write_long(0, CSR_SDRAMBASEOFF); csr_write_long(0, CSR_CSRBASEADDRMASK); /* 128bytes */ csr_write_long(0, CSR_CSRBASEADDR); csr_write_long(0x80f00000, CSR_ROMBASEADDRMASK); /* disabled */ csr_write_long(0, CSR_ROMBASEADDR); if (ctrl & CSR_CTRL_PCICFN) { /* * Disable PCI reset */ ctrl |= CSR_CTRL_PCINRST; csr_write_long(ctrl, CSR_CTRL); /* * Disable our PCI interface */ csr_write_word(0, CSR_PCI_CMD); csr_write_word(8, CSR_PCI_CACHELINESZ); csr_write_word(32, CSR_PCI_LATENCY_TIMER); /* * Disable prefetchable memory region. * (might use this some day) */ csr_write_long(CSR_PREFETCHRANGE_LEN8, CSR_PREFETCHRANGE); /* * SDRAM is mapped at PCI space address 0x10000000 */ csr_write_long(0x10000000, CSR_SDRAMBASE); csr_write_long(0xf0000000, CSR_CSRMEMBASE); csr_write_long(0x0000f000, CSR_CSRIOBASE); /* * Now enable memwinv, master, memory, but not IO */ csr_write_word(0x16, CSR_PCI_CMD); } else { /* * Add-in peripheral board initialisation */ csr_write_long(0, CSR_PREFETCHRANGE); } /* * Set Init Complete. If we are an add-in board, this * will allow the host POST to continue. */ csr_write_long(ctrl | CSR_CTRL_INITCOMPLETE, CSR_CTRL); return ctrl & CSR_CTRL_PCICFN;}/* * Scan the PCI bus looking for devices, and * add them to our "pci_root_dev" list. */static void pci_scan_bus(void){ struct pci_dev *pdev, **p; int dev, multi = 0; for (dev = 0; dev < MAX_DEV; dev++) { unsigned long pci_base; u32 vendor, device; if (FUNC(dev) && !multi) continue; pci_base = pci_config_addr(SLOT(dev), FUNC(dev)); vendor = pci_read_config_word(pci_base, PCI_VENDOR_ID); device = pci_read_config_word(pci_base, PCI_DEVICE_ID); if (vendor == 0xffff || vendor == 0x0000 || device == 0xffff || device == 0x0000) continue; pdev = malloc(sizeof(*pdev)); memset(pdev, 0, sizeof(*pdev)); pdev->vendor = vendor; pdev->device = device; pdev->pci_base = pci_base; pdev->header = pci_read_config_byte(pci_base, PCI_HEADER_TYPE); pdev->command = pci_read_config_word(pci_base, PCI_COMMAND); pdev->class = pci_read_config_word(pci_base, PCI_CLASS_CODE + 2); pdev->progif = pci_read_config_byte(pci_base, PCI_CLASS_CODE + 1); pdev->dev = dev; multi = pdev->header & 0x80; /* * Add this device to the list */ for (p = &pci_root_dev; *p; p = &(*p)->next); *p = pdev; }}static void pci_setup_cards_0(struct pci_dev *dev){ unsigned long pci_base = dev->pci_base; unsigned long base, size; unsigned int i; for (i = 0; i < 6; i ++) { dev->bar[i] = 0; pci_write_config_long(pci_base, PCI_BASE0 + i * 4, 0xffffffff); base = pci_read_config_long(pci_base, PCI_BASE0 + i * 4); if (base == 0) continue; if (base & 1) { /* IO space */ size = -(base & ~3); size &= 0xffff; base = pci_alloc_io(size) | 1; dev->command |= PCI_COMMAND_IO_SPACE; } else { /* MEM space */ size = -(base & ~15); base = pci_alloc_mem(size); dev->command |= PCI_COMMAND_MEM_SPACE; } dev->bar[i] = base; pci_write_config_long(pci_base, PCI_BASE0 + i * 4, base); if (pci_read_config_long(pci_base, PCI_BASE0 + i * 4) != base) debug_printf("Unable to set base\n"); } /* * If this device has a BIOS rom, allocate space for it, * but leave the ROM disabled. We don't want to go around * enabling all the ROMs needlessly. */ pci_write_config_long(pci_base, PCI_BIOSROMCONTROL, -2); base = pci_read_config_long(pci_base, PCI_BIOSROMCONTROL); if (base) { size = -(base & ~1); dev->bar[7] = pci_alloc_mem(size); pci_write_config_long(pci_base, PCI_BIOSROMCONTROL, dev->bar[7]); dev->command |= PCI_COMMAND_MEM_SPACE; } switch (dev->class >> 8) { case PCI_CLASS_NOT_DEFINED: case PCI_BASE_CLASS_DISPLAY: case PCI_BASE_CLASS_STORAGE: dev->command |= PCI_COMMAND_IO_SPACE; break; case PCI_BASE_CLASS_BRIDGE: dev->command |= PCI_COMMAND_IO_SPACE | PCI_COMMAND_MEM_SPACE | PCI_COMMAND_BUS_MASTER; break; }}static void pci_setup_cards(void){ struct pci_dev *dev; for (dev = pci_root_dev; dev; dev = dev->next) { dev->command &= ~(PCI_COMMAND_BUS_MASTER | PCI_COMMAND_MEM_SPACE | PCI_COMMAND_IO_SPACE); if ((dev->header & 0x7f) == 0) pci_setup_cards_0(dev); debug_printf("%d.%d: command = %04X\n", SLOT(dev->dev), FUNC(dev->dev), dev->command); pci_write_config_word(dev->pci_base, PCI_COMMAND, dev->command); }}static int__pci_exec_bios(struct pci_dev *dev, struct pci_data *data, unsigned int base){ struct rom_header rom; memcpy(&rom, (void *)base, sizeof(rom)); if (rom.magic != ROM_MAGIC) { debug_printf("%d.%d: bad rom magic\n", SLOT(dev->dev), FUNC(dev->dev)); return 0; } memcpy(data, (void *)(base + rom.pci_off), sizeof(*data)); if (data->pcir_magic != PCIR_MAGIC) { debug_printf("%d.%d: bad pcir magic (0x%08x != 0x%08x) - " "rom.pci_off = %d\n", SLOT(dev->dev), FUNC(dev->dev), data->pcir_magic, PCIR_MAGIC, rom.pci_off); return 0; } if (dev->vendor != data->vendor_id || dev->device != data->device_id) { debug_printf("%d.%d: wrong rom image: device = %04x:%04x, rom = %04x:%04x\n", SLOT(dev->dev), FUNC(dev->dev), dev->vendor, dev->device, data->vendor_id, data->device_id); return 0; } return 1;}void pci_exec_bios(struct pci_dev *dev){ unsigned int base = 0x80000000 + (dev->bar[7] & ~1); unsigned int x86_base = 0xc0000; struct pci_data data; int ret; /* * Enable the ROM */ pci_write_config_long(dev->pci_base, PCI_BIOSROMCONTROL, dev->bar[7] | 1); ret = __pci_exec_bios(dev, &data, base); if (ret) { switch (data.type) { case TYPE_X86: /* * Copy the ROM image into the emulator. */ x86_copy_in(x86_base, (void *)base, data.img_len * 512); /* * Disable the PCI BIOS before calling * the 'shadow' version */ pci_write_config_long(dev->pci_base, PCI_BIOSROMCONTROL, dev->bar[7]); /* * Call code at base+3, AH = busnr, * AL7:3 = slot, AL2:0 = func */ x86_call(x86_base + 3, dev->dev); return; default: debug_printf("%d.%d: unknown data type %d\n", SLOT(dev->dev), FUNC(dev->dev), data.type); } } pci_write_config_long(dev->pci_base, PCI_BIOSROMCONTROL, dev->bar[7]);}void pci_print_config(void){ struct pci_dev *dev; int i, nr_addr = 4; printf("---------------------- PCI Configuration -----------------------\n"); printf("Slot Vendor Device Class BMI "); for (i = 0; i < nr_addr; i++) printf(i == 6 ? "Bios" : "Address%d ", i); printf("\n"); for (dev = pci_root_dev; dev; dev = dev->next) { int i; printf("%2d.%d", SLOT(dev->dev), FUNC(dev->dev)); printf(" %04X %04X %04X %c%c%c", dev->vendor, dev->device, dev->class, dev->command & PCI_COMMAND_BUS_MASTER ? '*' : ' ', dev->command & PCI_COMMAND_MEM_SPACE ? '*' : ' ', dev->command & PCI_COMMAND_IO_SPACE ? '*' : ' '); for (i = 0; i < nr_addr; i++) if (dev->bar[i]) printf(" %08x", dev->bar[i]); else printf(" "); printf("\n"); } printf("----------------------------------------------------------------\n");}void pci_init(void){ int host; /* * Initialise the PCI hardware (DC21285) */ host = pci_init_hw(); /* * We only scan the PCI bus if we were in host mode. * If we were in add-in mode, chances are that the host BIOS * hasn't set anything up yet. */ if (host) { pci_io_free = 0x6000; pci_mem_free = PCIMEM_BASE; pci_scan_bus(); pci_setup_cards(); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -