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

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
        !            19:  * with this program; if not, write to the Free Software Foundation, Inc.,
        !            20:  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
        !            21:  */
        !            22: 
        !            23: #include "hw.h"
        !            24: #include "pci.h"
        !            25: #include "pcie_host.h"
        !            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),
        !            53:                            PCI_SLOT(PCIE_MMCFG_DEVFN(mmcfg_addr)),
        !            54:                            PCI_FUNC(PCIE_MMCFG_DEVFN(mmcfg_addr)));
        !            55: }
        !            56: 
        !            57: static void pcie_mmcfg_data_write(PCIBus *s,
        !            58:                                   uint32_t mmcfg_addr, uint32_t val, int len)
        !            59: {
        !            60:     PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
        !            61: 
        !            62:     if (!pci_dev)
        !            63:         return;
        !            64: 
        !            65:     pci_dev->config_write(pci_dev,
        !            66:                           PCIE_MMCFG_CONFOFFSET(mmcfg_addr), val, len);
        !            67: }
        !            68: 
        !            69: static uint32_t pcie_mmcfg_data_read(PCIBus *s, uint32_t addr, int len)
        !            70: {
        !            71:     PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, addr);
        !            72: 
        !            73:     assert(len == 1 || len == 2 || len == 4);
        !            74:     if (!pci_dev) {
        !            75:         return ~0x0;
        !            76:     }
        !            77:     return pci_dev->config_read(pci_dev, PCIE_MMCFG_CONFOFFSET(addr), len);
        !            78: }
        !            79: 
        !            80: static void pcie_mmcfg_data_writeb(void *opaque,
        !            81:                                    target_phys_addr_t addr, uint32_t value)
        !            82: {
        !            83:     PCIExpressHost *e = opaque;
        !            84:     pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 1);
        !            85: }
        !            86: 
        !            87: static void pcie_mmcfg_data_writew(void *opaque,
        !            88:                                    target_phys_addr_t addr, uint32_t value)
        !            89: {
        !            90:     PCIExpressHost *e = opaque;
        !            91:     pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 2);
        !            92: }
        !            93: 
        !            94: static void pcie_mmcfg_data_writel(void *opaque,
        !            95:                                    target_phys_addr_t addr, uint32_t value)
        !            96: {
        !            97:     PCIExpressHost *e = opaque;
        !            98:     pcie_mmcfg_data_write(e->pci.bus, addr - e->base_addr, value, 4);
        !            99: }
        !           100: 
        !           101: static uint32_t pcie_mmcfg_data_readb(void *opaque, target_phys_addr_t addr)
        !           102: {
        !           103:     PCIExpressHost *e = opaque;
        !           104:     return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 1);
        !           105: }
        !           106: 
        !           107: static uint32_t pcie_mmcfg_data_readw(void *opaque, target_phys_addr_t addr)
        !           108: {
        !           109:     PCIExpressHost *e = opaque;
        !           110:     return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 2);
        !           111: }
        !           112: 
        !           113: static uint32_t pcie_mmcfg_data_readl(void *opaque, target_phys_addr_t addr)
        !           114: {
        !           115:     PCIExpressHost *e = opaque;
        !           116:     return pcie_mmcfg_data_read(e->pci.bus, addr - e->base_addr, 4);
        !           117: }
        !           118: 
        !           119: 
        !           120: static CPUWriteMemoryFunc * const pcie_mmcfg_write[] =
        !           121: {
        !           122:     pcie_mmcfg_data_writeb,
        !           123:     pcie_mmcfg_data_writew,
        !           124:     pcie_mmcfg_data_writel,
        !           125: };
        !           126: 
        !           127: static CPUReadMemoryFunc * const pcie_mmcfg_read[] =
        !           128: {
        !           129:     pcie_mmcfg_data_readb,
        !           130:     pcie_mmcfg_data_readw,
        !           131:     pcie_mmcfg_data_readl,
        !           132: };
        !           133: 
        !           134: /* pcie_host::base_addr == PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. */
        !           135: #define PCIE_BASE_ADDR_UNMAPPED  ((target_phys_addr_t)-1ULL)
        !           136: 
        !           137: int pcie_host_init(PCIExpressHost *e)
        !           138: {
        !           139:     e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
        !           140:     e->mmio_index =
        !           141:         cpu_register_io_memory(pcie_mmcfg_read, pcie_mmcfg_write, e);
        !           142:     if (e->mmio_index < 0) {
        !           143:         return -1;
        !           144:     }
        !           145: 
        !           146:     return 0;
        !           147: }
        !           148: 
        !           149: void pcie_host_mmcfg_unmap(PCIExpressHost *e)
        !           150: {
        !           151:     if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) {
        !           152:         cpu_register_physical_memory(e->base_addr, e->size, IO_MEM_UNASSIGNED);
        !           153:         e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
        !           154:     }
        !           155: }
        !           156: 
        !           157: void pcie_host_mmcfg_map(PCIExpressHost *e,
        !           158:                          target_phys_addr_t addr, uint32_t size)
        !           159: {
        !           160:     assert(!(size & (size - 1)));       /* power of 2 */
        !           161:     assert(size >= PCIE_MMCFG_SIZE_MIN);
        !           162:     assert(size <= PCIE_MMCFG_SIZE_MAX);
        !           163: 
        !           164:     e->base_addr = addr;
        !           165:     e->size = size;
        !           166:     cpu_register_physical_memory(e->base_addr, e->size, e->mmio_index);
        !           167: }
        !           168: 
        !           169: void pcie_host_mmcfg_update(PCIExpressHost *e,
        !           170:                             int enable,
        !           171:                             target_phys_addr_t addr, uint32_t size)
        !           172: {
        !           173:     pcie_host_mmcfg_unmap(e);
        !           174:     if (enable) {
        !           175:         pcie_host_mmcfg_map(e, addr, size);
        !           176:     }
        !           177: }

unix.superglobalmegacorp.com