Annotation of qemu/hw/pcie_host.c, revision 1.1.1.5

1.1       root        1: /*
                      2:  * pcie_host.c
                      3:  * utility functions for pci express host bridge.
                      4:  *
                      5:  * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
                      6:  *                    VA Linux Systems Japan K.K.
                      7:  *
                      8:  * This program is free software; you can redistribute it and/or modify
                      9:  * it under the terms of the GNU General Public License as published by
                     10:  * the Free Software Foundation; either version 2 of the License, or
                     11:  * (at your option) any later version.
                     12: 
                     13:  * This program is distributed in the hope that it will be useful,
                     14:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                     15:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     16:  * GNU General Public License for more details.
                     17: 
                     18:  * You should have received a copy of the GNU General Public License along
1.1.1.2   root       19:  * with this program; if not, see <http://www.gnu.org/licenses/>.
1.1       root       20:  */
                     21: 
                     22: #include "hw.h"
                     23: #include "pci.h"
                     24: #include "pcie_host.h"
1.1.1.5 ! root       25: #include "exec-memory.h"
1.1       root       26: 
                     27: /*
                     28:  * PCI express mmcfig address
                     29:  * bit 20 - 28: bus number
                     30:  * bit 15 - 19: device number
                     31:  * bit 12 - 14: function number
                     32:  * bit  0 - 11: offset in configuration space of a given device
                     33:  */
                     34: #define PCIE_MMCFG_SIZE_MAX             (1ULL << 28)
                     35: #define PCIE_MMCFG_SIZE_MIN             (1ULL << 20)
                     36: #define PCIE_MMCFG_BUS_BIT              20
                     37: #define PCIE_MMCFG_BUS_MASK             0x1ff
                     38: #define PCIE_MMCFG_DEVFN_BIT            12
                     39: #define PCIE_MMCFG_DEVFN_MASK           0xff
                     40: #define PCIE_MMCFG_CONFOFFSET_MASK      0xfff
                     41: #define PCIE_MMCFG_BUS(addr)            (((addr) >> PCIE_MMCFG_BUS_BIT) & \
                     42:                                          PCIE_MMCFG_BUS_MASK)
                     43: #define PCIE_MMCFG_DEVFN(addr)          (((addr) >> PCIE_MMCFG_DEVFN_BIT) & \
                     44:                                          PCIE_MMCFG_DEVFN_MASK)
                     45: #define PCIE_MMCFG_CONFOFFSET(addr)     ((addr) & PCIE_MMCFG_CONFOFFSET_MASK)
                     46: 
                     47: 
                     48: /* a helper function to get a PCIDevice for a given mmconfig address */
                     49: static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s,
                     50:                                                      uint32_t mmcfg_addr)
                     51: {
                     52:     return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr),
1.1.1.4   root       53:                            PCIE_MMCFG_DEVFN(mmcfg_addr));
1.1       root       54: }
                     55: 
1.1.1.5 ! root       56: static void pcie_mmcfg_data_write(void *opaque, target_phys_addr_t mmcfg_addr,
        !            57:                                   uint64_t val, unsigned len)
1.1       root       58: {
1.1.1.5 ! root       59:     PCIExpressHost *e = opaque;
        !            60:     PCIBus *s = e->pci.bus;
1.1       root       61:     PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
1.1.1.5 ! root       62:     uint32_t addr;
        !            63:     uint32_t limit;
1.1       root       64: 
1.1.1.5 ! root       65:     if (!pci_dev) {
1.1       root       66:         return;
1.1.1.5 ! root       67:     }
        !            68:     addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
        !            69:     limit = pci_config_size(pci_dev);
        !            70:     if (limit <= addr) {
        !            71:         /* conventional pci device can be behind pcie-to-pci bridge.
        !            72:            256 <= addr < 4K has no effects. */
        !            73:         return;
        !            74:     }
        !            75:     pci_host_config_write_common(pci_dev, addr, limit, val, len);
1.1       root       76: }
                     77: 
1.1.1.5 ! root       78: static uint64_t pcie_mmcfg_data_read(void *opaque,
        !            79:                                      target_phys_addr_t mmcfg_addr,
        !            80:                                      unsigned len)
1.1       root       81: {
1.1.1.5 ! root       82:     PCIExpressHost *e = opaque;
        !            83:     PCIBus *s = e->pci.bus;
        !            84:     PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
        !            85:     uint32_t addr;
        !            86:     uint32_t limit;
1.1       root       87: 
                     88:     if (!pci_dev) {
                     89:         return ~0x0;
                     90:     }
1.1.1.5 ! root       91:     addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
        !            92:     limit = pci_config_size(pci_dev);
        !            93:     if (limit <= addr) {
        !            94:         /* conventional pci device can be behind pcie-to-pci bridge.
        !            95:            256 <= addr < 4K has no effects. */
        !            96:         return ~0x0;
        !            97:     }
        !            98:     return pci_host_config_read_common(pci_dev, addr, limit, len);
1.1       root       99: }
                    100: 
1.1.1.5 ! root      101: static const MemoryRegionOps pcie_mmcfg_ops = {
        !           102:     .read = pcie_mmcfg_data_read,
        !           103:     .write = pcie_mmcfg_data_write,
        !           104:     .endianness = DEVICE_NATIVE_ENDIAN,
1.1       root      105: };
                    106: 
                    107: /* pcie_host::base_addr == PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. */
                    108: #define PCIE_BASE_ADDR_UNMAPPED  ((target_phys_addr_t)-1ULL)
                    109: 
1.1.1.5 ! root      110: int pcie_host_init(PCIExpressHost *e, uint32_t size)
1.1       root      111: {
1.1.1.5 ! root      112:     assert(!(size & (size - 1)));       /* power of 2 */
        !           113:     assert(size >= PCIE_MMCFG_SIZE_MIN);
        !           114:     assert(size <= PCIE_MMCFG_SIZE_MAX);
1.1       root      115:     e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
1.1.1.5 ! root      116:     e->size = size;
        !           117:     memory_region_init_io(&e->mmio, &pcie_mmcfg_ops, e, "pcie-mmcfg", e->size);
1.1       root      118: 
                    119:     return 0;
                    120: }
                    121: 
                    122: void pcie_host_mmcfg_unmap(PCIExpressHost *e)
                    123: {
                    124:     if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) {
1.1.1.5 ! root      125:         memory_region_del_subregion(get_system_memory(), &e->mmio);
1.1       root      126:         e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
                    127:     }
                    128: }
                    129: 
1.1.1.5 ! root      130: void pcie_host_mmcfg_map(PCIExpressHost *e, target_phys_addr_t addr)
1.1       root      131: {
                    132:     e->base_addr = addr;
1.1.1.5 ! root      133:     memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio);
1.1       root      134: }
                    135: 
                    136: void pcie_host_mmcfg_update(PCIExpressHost *e,
                    137:                             int enable,
1.1.1.5 ! root      138:                             target_phys_addr_t addr)
1.1       root      139: {
                    140:     pcie_host_mmcfg_unmap(e);
                    141:     if (enable) {
1.1.1.5 ! root      142:         pcie_host_mmcfg_map(e, addr);
1.1       root      143:     }
                    144: }

unix.superglobalmegacorp.com