|
|
1.1 ! root 1: /* Simplistic PCI support. ! 2: ! 3: Copyright (C) 2011 Richard Henderson ! 4: ! 5: This file is part of QEMU PALcode. ! 6: ! 7: This program is free software; you can redistribute it and/or modify ! 8: it under the terms of the GNU General Public License as published by ! 9: the Free Software Foundation; either version 2 of the License or ! 10: (at your option) any later version. ! 11: ! 12: This program is distributed in the hope that it will be useful, ! 13: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the text ! 15: of the GNU General Public License for more details. ! 16: ! 17: You should have received a copy of the GNU General Public License ! 18: along with this program; see the file COPYING. If not see ! 19: <http://www.gnu.org/licenses/>. */ ! 20: ! 21: /* We don't bother supporting PCI bridges, because the device model we're ! 22: currently using for QEMU doesn't build any. ! 23: ! 24: We don't bother to build real datastructures in memory, because it's ! 25: fairly quick under emulation simply to access configuration space again. ! 26: This helps when running kernels under the emulator that might have ! 27: re-organized the BARs out from under us. */ ! 28: ! 29: #include "protos.h" ! 30: #include "pci.h" ! 31: #include "pci_regs.h" ! 32: ! 33: ! 34: #define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) ! 35: #define PCI_BUS(devfn) ((devfn) >> 8) ! 36: #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) ! 37: #define PCI_FUNC(devfn) ((devfn) & 0x07) ! 38: #define PCI_SLOT_MAX 32 ! 39: #define PCI_FUNC_MAX 8 ! 40: #define PCI_REGION_ROM 6 ! 41: #define PCI_REGIONS_MAX 7 ! 42: ! 43: ! 44: void ! 45: pci_config_maskw(int bdf, int addr, uint16_t off, uint16_t on) ! 46: { ! 47: uint16_t val = pci_config_readw(bdf, addr); ! 48: val = (val & ~off) | on; ! 49: pci_config_writew(bdf, addr, val); ! 50: } ! 51: ! 52: int ! 53: pci_next(int bdf, int *pmax) ! 54: { ! 55: int max; ! 56: ! 57: if (PCI_FUNC(bdf) == 1) ! 58: { ! 59: /* If the last device was not a multi-function device, skip to next. */ ! 60: if ((pci_config_readb(bdf-1, PCI_HEADER_TYPE) & 0x80) == 0) ! 61: bdf += 7; ! 62: } ! 63: ! 64: max = *pmax; ! 65: while (1) ! 66: { ! 67: uint16_t vendor; ! 68: ! 69: /* ??? Support multiple PCI busses here at some point. */ ! 70: if (bdf >= max) ! 71: return -1; ! 72: ! 73: /* Check if there is a device present at the location. */ ! 74: vendor = pci_config_readw(bdf, PCI_VENDOR_ID); ! 75: if (vendor != 0x0000 && vendor != 0xffff) ! 76: return bdf; ! 77: ! 78: bdf += (PCI_FUNC(bdf) == 0 ? 8 : 1); ! 79: } ! 80: } ! 81: ! 82: static void ! 83: pci_setup_device(int bdf, uint32_t *p_io_base, uint32_t *p_mem_base) ! 84: { ! 85: int vendor_id, device_id, class_id, region; ! 86: ! 87: vendor_id = pci_config_readw(bdf, PCI_VENDOR_ID); ! 88: device_id = pci_config_readw(bdf, PCI_DEVICE_ID); ! 89: class_id = pci_config_readw(bdf, PCI_CLASS_DEVICE); ! 90: ! 91: printf("PCI: %02x:%02x:%x class %04x id %04x:%04x\r\n", ! 92: PCI_BUS(bdf), PCI_SLOT(bdf), PCI_FUNC(bdf), ! 93: class_id, vendor_id, device_id); ! 94: ! 95: for (region = 0; region < PCI_REGION_ROM; region++) ! 96: { ! 97: int ofs = PCI_BASE_ADDRESS_0 + region * 4; ! 98: uint32_t old, mask, val, size, align; ! 99: uint32_t *p_base; ! 100: ! 101: old = pci_config_readl(bdf, ofs); ! 102: if (old & PCI_BASE_ADDRESS_SPACE_IO) ! 103: { ! 104: mask = PCI_BASE_ADDRESS_IO_MASK; ! 105: p_base = p_io_base; ! 106: } ! 107: else ! 108: { ! 109: mask = PCI_BASE_ADDRESS_MEM_MASK; ! 110: p_base = p_mem_base; ! 111: } ! 112: ! 113: pci_config_writel(bdf, ofs, -1); ! 114: val = pci_config_readl(bdf, ofs); ! 115: pci_config_writel(bdf, ofs, old); ! 116: ! 117: align = size = ~(val & mask) + 1; ! 118: if (val != 0) ! 119: { ! 120: uint32_t addr = *p_base; ! 121: addr = (addr + align - 1) & ~(align - 1); ! 122: *p_base = addr + size; ! 123: pci_config_writel(bdf, ofs, addr); ! 124: ! 125: printf("PCI: region %d: %08x\r\n", region, addr); ! 126: ! 127: if ((val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ! 128: == PCI_BASE_ADDRESS_MEM_TYPE_64) ! 129: { ! 130: pci_config_writel(bdf, ofs + 4, 0); ! 131: region++; ! 132: } ! 133: } ! 134: } ! 135: ! 136: pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_IO | PCI_COMMAND_MEMORY); ! 137: ! 138: /* Map the interrupt. */ ! 139: } ! 140: ! 141: void ! 142: pci_setup(void) ! 143: { ! 144: uint32_t io_base = 0xc000; ! 145: uint32_t mem_base = 256 * 1024 * 1024; ! 146: int bdf, max; ! 147: ! 148: foreachpci (bdf, max) ! 149: pci_setup_device(bdf, &io_base, &mem_base); ! 150: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.