121ff329dSWill Deacon #include "kvm/devices.h" 260742802SPekka Enberg #include "kvm/pci.h" 360742802SPekka Enberg #include "kvm/ioport.h" 4b5981636SWill Deacon #include "kvm/irq.h" 576f9c841SCyrill Gorcunov #include "kvm/util.h" 69575e724SSasha Levin #include "kvm/kvm.h" 760742802SPekka Enberg 86d987703SSasha Levin #include <linux/err.h> 96d987703SSasha Levin #include <assert.h> 106d987703SSasha Levin 11a0a7d66fSDavid Daney static u32 pci_config_address_bits; 1260742802SPekka Enberg 1340f2fd06SMatt Evans /* This is within our PCI gap - in an unused area. 1440f2fd06SMatt Evans * Note this is a PCI *bus address*, is used to assign BARs etc.! 1540f2fd06SMatt Evans * (That's why it can still 32bit even with 64bit guests-- 64bit 1640f2fd06SMatt Evans * PCI isn't currently supported.) 1740f2fd06SMatt Evans */ 1840f2fd06SMatt Evans static u32 io_space_blocks = KVM_PCI_MMIO_AREA; 199575e724SSasha Levin 20c7575d17SWill Deacon /* 21c7575d17SWill Deacon * BARs must be naturally aligned, so enforce this in the allocator. 22c7575d17SWill Deacon */ 2395d13a52SSasha Levin u32 pci_get_io_space_block(u32 size) 249575e724SSasha Levin { 25c7575d17SWill Deacon u32 block = ALIGN(io_space_blocks, size); 26c7575d17SWill Deacon io_space_blocks = block + size; 279575e724SSasha Levin return block; 289575e724SSasha Levin } 299575e724SSasha Levin 30*1a51c93dSJean-Philippe Brucker void *pci_find_cap(struct pci_device_header *hdr, u8 cap_type) 31*1a51c93dSJean-Philippe Brucker { 32*1a51c93dSJean-Philippe Brucker u8 pos; 33*1a51c93dSJean-Philippe Brucker struct pci_cap_hdr *cap; 34*1a51c93dSJean-Philippe Brucker 35*1a51c93dSJean-Philippe Brucker pci_for_each_cap(pos, cap, hdr) { 36*1a51c93dSJean-Philippe Brucker if (cap->type == cap_type) 37*1a51c93dSJean-Philippe Brucker return cap; 38*1a51c93dSJean-Philippe Brucker } 39*1a51c93dSJean-Philippe Brucker 40*1a51c93dSJean-Philippe Brucker return NULL; 41*1a51c93dSJean-Philippe Brucker } 42*1a51c93dSJean-Philippe Brucker 43b5981636SWill Deacon void pci__assign_irq(struct device_header *dev_hdr) 44b5981636SWill Deacon { 45b5981636SWill Deacon struct pci_device_header *pci_hdr = dev_hdr->data; 46b5981636SWill Deacon 47b5981636SWill Deacon /* 48b5981636SWill Deacon * PCI supports only INTA#,B#,C#,D# per device. 49b5981636SWill Deacon * 50b5981636SWill Deacon * A#,B#,C#,D# are allowed for multifunctional devices so stick 51b5981636SWill Deacon * with A# for our single function devices. 52b5981636SWill Deacon */ 53b5981636SWill Deacon pci_hdr->irq_pin = 1; 54b5981636SWill Deacon pci_hdr->irq_line = irq__alloc_line(); 55ff01b5dbSJean-Philippe Brucker 56ff01b5dbSJean-Philippe Brucker if (!pci_hdr->irq_type) 57ff01b5dbSJean-Philippe Brucker pci_hdr->irq_type = IRQ_TYPE_EDGE_RISING; 58b5981636SWill Deacon } 59b5981636SWill Deacon 603fdf659dSSasha Levin static void *pci_config_address_ptr(u16 port) 61ba824677SPekka Enberg { 62ba824677SPekka Enberg unsigned long offset; 63ba824677SPekka Enberg void *base; 64ba824677SPekka Enberg 65ba824677SPekka Enberg offset = port - PCI_CONFIG_ADDRESS; 66a0a7d66fSDavid Daney base = &pci_config_address_bits; 67ba824677SPekka Enberg 68ba824677SPekka Enberg return base + offset; 69ba824677SPekka Enberg } 70ba824677SPekka Enberg 714123ca55SMarc Zyngier static bool pci_config_address_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size) 7260742802SPekka Enberg { 73ba824677SPekka Enberg void *p = pci_config_address_ptr(port); 7460742802SPekka Enberg 75ba824677SPekka Enberg memcpy(p, data, size); 7660742802SPekka Enberg 7760742802SPekka Enberg return true; 7860742802SPekka Enberg } 7960742802SPekka Enberg 804123ca55SMarc Zyngier static bool pci_config_address_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size) 8160742802SPekka Enberg { 82ba824677SPekka Enberg void *p = pci_config_address_ptr(port); 8360742802SPekka Enberg 84ba824677SPekka Enberg memcpy(data, p, size); 8560742802SPekka Enberg 8660742802SPekka Enberg return true; 8760742802SPekka Enberg } 8860742802SPekka Enberg 89305b72ceSCyrill Gorcunov static struct ioport_operations pci_config_address_ops = { 90305b72ceSCyrill Gorcunov .io_in = pci_config_address_in, 91305b72ceSCyrill Gorcunov .io_out = pci_config_address_out, 9260742802SPekka Enberg }; 9360742802SPekka Enberg 943fdf659dSSasha Levin static bool pci_device_exists(u8 bus_number, u8 device_number, u8 function_number) 9576f9c841SCyrill Gorcunov { 96a0a7d66fSDavid Daney union pci_config_address pci_config_address; 97a0a7d66fSDavid Daney 98a0a7d66fSDavid Daney pci_config_address.w = ioport__read32(&pci_config_address_bits); 99a0a7d66fSDavid Daney 10076f9c841SCyrill Gorcunov if (pci_config_address.bus_number != bus_number) 10176f9c841SCyrill Gorcunov return false; 10276f9c841SCyrill Gorcunov 103b30d05adSPekka Enberg if (pci_config_address.function_number != function_number) 10476f9c841SCyrill Gorcunov return false; 10576f9c841SCyrill Gorcunov 10621ff329dSWill Deacon return !IS_ERR_OR_NULL(device__find_dev(DEVICE_BUS_PCI, device_number)); 10776f9c841SCyrill Gorcunov } 10876f9c841SCyrill Gorcunov 1094123ca55SMarc Zyngier static bool pci_config_data_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size) 1109575e724SSasha Levin { 111a0a7d66fSDavid Daney union pci_config_address pci_config_address; 112a0a7d66fSDavid Daney 113a0a7d66fSDavid Daney pci_config_address.w = ioport__read32(&pci_config_address_bits); 1149575e724SSasha Levin /* 1159575e724SSasha Levin * If someone accesses PCI configuration space offsets that are not 1169575e724SSasha Levin * aligned to 4 bytes, it uses ioports to signify that. 1179575e724SSasha Levin */ 118d0297a59SMatt Evans pci_config_address.reg_offset = port - PCI_CONFIG_DATA; 1199575e724SSasha Levin 1204123ca55SMarc Zyngier pci__config_wr(vcpu->kvm, pci_config_address, data, size); 121d0297a59SMatt Evans 122d0297a59SMatt Evans return true; 123d0297a59SMatt Evans } 124d0297a59SMatt Evans 1254123ca55SMarc Zyngier static bool pci_config_data_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size) 126d0297a59SMatt Evans { 127a0a7d66fSDavid Daney union pci_config_address pci_config_address; 128a0a7d66fSDavid Daney 129a0a7d66fSDavid Daney pci_config_address.w = ioport__read32(&pci_config_address_bits); 130d0297a59SMatt Evans /* 131d0297a59SMatt Evans * If someone accesses PCI configuration space offsets that are not 132d0297a59SMatt Evans * aligned to 4 bytes, it uses ioports to signify that. 133d0297a59SMatt Evans */ 134d0297a59SMatt Evans pci_config_address.reg_offset = port - PCI_CONFIG_DATA; 135d0297a59SMatt Evans 1364123ca55SMarc Zyngier pci__config_rd(vcpu->kvm, pci_config_address, data, size); 137d0297a59SMatt Evans 138d0297a59SMatt Evans return true; 139d0297a59SMatt Evans } 140d0297a59SMatt Evans 141d0297a59SMatt Evans static struct ioport_operations pci_config_data_ops = { 142d0297a59SMatt Evans .io_in = pci_config_data_in, 143d0297a59SMatt Evans .io_out = pci_config_data_out, 144d0297a59SMatt Evans }; 145d0297a59SMatt Evans 146d0297a59SMatt Evans void pci__config_wr(struct kvm *kvm, union pci_config_address addr, void *data, int size) 147d0297a59SMatt Evans { 148023fdaaeSJean-Philippe Brucker void *base; 149023fdaaeSJean-Philippe Brucker u8 bar, offset; 150023fdaaeSJean-Philippe Brucker struct pci_device_header *pci_hdr; 151023fdaaeSJean-Philippe Brucker u8 dev_num = addr.device_number; 152d0297a59SMatt Evans 153023fdaaeSJean-Philippe Brucker if (!pci_device_exists(addr.bus_number, dev_num, 0)) 154023fdaaeSJean-Philippe Brucker return; 1559575e724SSasha Levin 156023fdaaeSJean-Philippe Brucker offset = addr.w & PCI_DEV_CFG_MASK; 157023fdaaeSJean-Philippe Brucker base = pci_hdr = device__find_dev(DEVICE_BUS_PCI, dev_num)->data; 1589575e724SSasha Levin 159023fdaaeSJean-Philippe Brucker if (pci_hdr->cfg_ops.write) 160023fdaaeSJean-Philippe Brucker pci_hdr->cfg_ops.write(kvm, pci_hdr, offset, data, size); 161c64f7ff0SSasha Levin 1629575e724SSasha Levin /* 163023fdaaeSJean-Philippe Brucker * legacy hack: ignore writes to uninitialized regions (e.g. ROM BAR). 164023fdaaeSJean-Philippe Brucker * Not very nice but has been working so far. 1659575e724SSasha Levin */ 166023fdaaeSJean-Philippe Brucker if (*(u32 *)(base + offset) == 0) 167023fdaaeSJean-Philippe Brucker return; 168023fdaaeSJean-Philippe Brucker 169023fdaaeSJean-Philippe Brucker bar = (offset - PCI_BAR_OFFSET(0)) / sizeof(u32); 170023fdaaeSJean-Philippe Brucker 171023fdaaeSJean-Philippe Brucker /* 172023fdaaeSJean-Philippe Brucker * If the kernel masks the BAR it would expect to find the size of the 173023fdaaeSJean-Philippe Brucker * BAR there next time it reads from it. When the kernel got the size it 174023fdaaeSJean-Philippe Brucker * would write the address back. 175023fdaaeSJean-Philippe Brucker */ 176023fdaaeSJean-Philippe Brucker if (bar < 6 && ioport__read32(data) == 0xFFFFFFFF) { 177023fdaaeSJean-Philippe Brucker u32 sz = pci_hdr->bar_size[bar]; 178023fdaaeSJean-Philippe Brucker memcpy(base + offset, &sz, sizeof(sz)); 179023fdaaeSJean-Philippe Brucker } else { 180023fdaaeSJean-Philippe Brucker memcpy(base + offset, data, size); 1819575e724SSasha Levin } 1829575e724SSasha Levin } 1839575e724SSasha Levin 184d0297a59SMatt Evans void pci__config_rd(struct kvm *kvm, union pci_config_address addr, void *data, int size) 18560742802SPekka Enberg { 186023fdaaeSJean-Philippe Brucker u8 offset; 187023fdaaeSJean-Philippe Brucker struct pci_device_header *pci_hdr; 188023fdaaeSJean-Philippe Brucker u8 dev_num = addr.device_number; 189e4d2cea2SPekka Enberg 190023fdaaeSJean-Philippe Brucker if (pci_device_exists(addr.bus_number, dev_num, 0)) { 191023fdaaeSJean-Philippe Brucker pci_hdr = device__find_dev(DEVICE_BUS_PCI, dev_num)->data; 192023fdaaeSJean-Philippe Brucker offset = addr.w & PCI_DEV_CFG_MASK; 193b30d05adSPekka Enberg 194023fdaaeSJean-Philippe Brucker if (pci_hdr->cfg_ops.read) 195023fdaaeSJean-Philippe Brucker pci_hdr->cfg_ops.read(kvm, pci_hdr, offset, data, size); 196598419d5SPekka Enberg 197023fdaaeSJean-Philippe Brucker memcpy(data, (void *)pci_hdr + offset, size); 1983a60be06SSasha Levin } else { 199e498ea08SPekka Enberg memset(data, 0xff, size); 20060742802SPekka Enberg } 2013a60be06SSasha Levin } 20260742802SPekka Enberg 2039b735910SMarc Zyngier static void pci_config_mmio_access(struct kvm_cpu *vcpu, u64 addr, u8 *data, 2049b735910SMarc Zyngier u32 len, u8 is_write, void *kvm) 205b403f2f7SWill Deacon { 206b403f2f7SWill Deacon union pci_config_address cfg_addr; 207b403f2f7SWill Deacon 208b403f2f7SWill Deacon addr -= KVM_PCI_CFG_AREA; 209b403f2f7SWill Deacon cfg_addr.w = (u32)addr; 210b403f2f7SWill Deacon cfg_addr.enable_bit = 1; 211b403f2f7SWill Deacon 212b403f2f7SWill Deacon if (is_write) 213b403f2f7SWill Deacon pci__config_wr(kvm, cfg_addr, data, len); 214b403f2f7SWill Deacon else 215b403f2f7SWill Deacon pci__config_rd(kvm, cfg_addr, data, len); 216b403f2f7SWill Deacon } 217b403f2f7SWill Deacon 218d0297a59SMatt Evans struct pci_device_header *pci__find_dev(u8 dev_num) 219d0297a59SMatt Evans { 22021ff329dSWill Deacon struct device_header *hdr = device__find_dev(DEVICE_BUS_PCI, dev_num); 2216d987703SSasha Levin 22221ff329dSWill Deacon if (IS_ERR_OR_NULL(hdr)) 22321ff329dSWill Deacon return NULL; 22421ff329dSWill Deacon 22521ff329dSWill Deacon return hdr->data; 226d0297a59SMatt Evans } 227d0297a59SMatt Evans 2286d987703SSasha Levin int pci__init(struct kvm *kvm) 22960742802SPekka Enberg { 2306d987703SSasha Levin int r; 2316d987703SSasha Levin 2324346fd8fSSasha Levin r = ioport__register(kvm, PCI_CONFIG_DATA + 0, &pci_config_data_ops, 4, NULL); 2336d987703SSasha Levin if (r < 0) 2346d987703SSasha Levin return r; 2356d987703SSasha Levin 2364346fd8fSSasha Levin r = ioport__register(kvm, PCI_CONFIG_ADDRESS + 0, &pci_config_address_ops, 4, NULL); 237b403f2f7SWill Deacon if (r < 0) 238b403f2f7SWill Deacon goto err_unregister_data; 239b403f2f7SWill Deacon 240b403f2f7SWill Deacon r = kvm__register_mmio(kvm, KVM_PCI_CFG_AREA, PCI_CFG_SIZE, false, 241b403f2f7SWill Deacon pci_config_mmio_access, kvm); 242b403f2f7SWill Deacon if (r < 0) 243b403f2f7SWill Deacon goto err_unregister_addr; 2446d987703SSasha Levin 2456d987703SSasha Levin return 0; 246b403f2f7SWill Deacon 247b403f2f7SWill Deacon err_unregister_addr: 248b403f2f7SWill Deacon ioport__unregister(kvm, PCI_CONFIG_ADDRESS); 249b403f2f7SWill Deacon err_unregister_data: 250b403f2f7SWill Deacon ioport__unregister(kvm, PCI_CONFIG_DATA); 251b403f2f7SWill Deacon return r; 2526d987703SSasha Levin } 253bca12bf6SSasha Levin dev_base_init(pci__init); 2546d987703SSasha Levin 2556d987703SSasha Levin int pci__exit(struct kvm *kvm) 2566d987703SSasha Levin { 2574346fd8fSSasha Levin ioport__unregister(kvm, PCI_CONFIG_DATA); 2584346fd8fSSasha Levin ioport__unregister(kvm, PCI_CONFIG_ADDRESS); 2596d987703SSasha Levin 2606d987703SSasha Levin return 0; 26160742802SPekka Enberg } 262bca12bf6SSasha Levin dev_base_exit(pci__exit); 263