2
0

pcie_host.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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. * 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
  15. * GNU General Public License for more details.
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "qemu/osdep.h"
  20. #include "hw/pci/pci.h"
  21. #include "hw/pci/pcie_host.h"
  22. #include "qemu/module.h"
  23. #include "exec/address-spaces.h"
  24. /* a helper function to get a PCIDevice for a given mmconfig address */
  25. static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s,
  26. uint32_t mmcfg_addr)
  27. {
  28. return pci_find_device(s, PCIE_MMCFG_BUS(mmcfg_addr),
  29. PCIE_MMCFG_DEVFN(mmcfg_addr));
  30. }
  31. static void pcie_mmcfg_data_write(void *opaque, hwaddr mmcfg_addr,
  32. uint64_t val, unsigned len)
  33. {
  34. PCIExpressHost *e = opaque;
  35. PCIBus *s = e->pci.bus;
  36. PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
  37. uint32_t addr;
  38. uint32_t limit;
  39. if (!pci_dev) {
  40. return;
  41. }
  42. addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
  43. limit = pci_config_size(pci_dev);
  44. pci_host_config_write_common(pci_dev, addr, limit, val, len);
  45. }
  46. static uint64_t pcie_mmcfg_data_read(void *opaque,
  47. hwaddr mmcfg_addr,
  48. unsigned len)
  49. {
  50. PCIExpressHost *e = opaque;
  51. PCIBus *s = e->pci.bus;
  52. PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
  53. uint32_t addr;
  54. uint32_t limit;
  55. if (!pci_dev) {
  56. return ~0x0;
  57. }
  58. addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
  59. limit = pci_config_size(pci_dev);
  60. return pci_host_config_read_common(pci_dev, addr, limit, len);
  61. }
  62. static const MemoryRegionOps pcie_mmcfg_ops = {
  63. .read = pcie_mmcfg_data_read,
  64. .write = pcie_mmcfg_data_write,
  65. .endianness = DEVICE_LITTLE_ENDIAN,
  66. };
  67. static void pcie_host_init(Object *obj)
  68. {
  69. PCIExpressHost *e = PCIE_HOST_BRIDGE(obj);
  70. e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
  71. memory_region_init_io(&e->mmio, OBJECT(e), &pcie_mmcfg_ops, e, "pcie-mmcfg-mmio",
  72. PCIE_MMCFG_SIZE_MAX);
  73. }
  74. void pcie_host_mmcfg_unmap(PCIExpressHost *e)
  75. {
  76. if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) {
  77. memory_region_del_subregion(get_system_memory(), &e->mmio);
  78. e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
  79. }
  80. }
  81. void pcie_host_mmcfg_init(PCIExpressHost *e, uint32_t size)
  82. {
  83. assert(!(size & (size - 1))); /* power of 2 */
  84. assert(size >= PCIE_MMCFG_SIZE_MIN);
  85. assert(size <= PCIE_MMCFG_SIZE_MAX);
  86. e->size = size;
  87. memory_region_set_size(&e->mmio, e->size);
  88. }
  89. void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr,
  90. uint32_t size)
  91. {
  92. pcie_host_mmcfg_init(e, size);
  93. e->base_addr = addr;
  94. memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio);
  95. }
  96. void pcie_host_mmcfg_update(PCIExpressHost *e,
  97. int enable,
  98. hwaddr addr,
  99. uint32_t size)
  100. {
  101. memory_region_transaction_begin();
  102. pcie_host_mmcfg_unmap(e);
  103. if (enable) {
  104. pcie_host_mmcfg_map(e, addr, size);
  105. }
  106. memory_region_transaction_commit();
  107. }
  108. static const TypeInfo pcie_host_type_info = {
  109. .name = TYPE_PCIE_HOST_BRIDGE,
  110. .parent = TYPE_PCI_HOST_BRIDGE,
  111. .abstract = true,
  112. .instance_size = sizeof(PCIExpressHost),
  113. .instance_init = pcie_host_init,
  114. };
  115. static void pcie_host_register_types(void)
  116. {
  117. type_register_static(&pcie_host_type_info);
  118. }
  119. type_init(pcie_host_register_types)