2
0

designware.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  1. /*
  2. * Copyright (c) 2018, Impinj, Inc.
  3. *
  4. * Designware PCIe IP block emulation
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, see
  18. * <http://www.gnu.org/licenses/>.
  19. */
  20. #include "qemu/osdep.h"
  21. #include "qapi/error.h"
  22. #include "qemu/module.h"
  23. #include "hw/pci/msi.h"
  24. #include "hw/pci/pci_bridge.h"
  25. #include "hw/pci/pci_host.h"
  26. #include "hw/pci/pcie_port.h"
  27. #include "hw/qdev-properties.h"
  28. #include "migration/vmstate.h"
  29. #include "hw/irq.h"
  30. #include "hw/pci-host/designware.h"
  31. #define DESIGNWARE_PCIE_PORT_LINK_CONTROL 0x710
  32. #define DESIGNWARE_PCIE_PHY_DEBUG_R1 0x72C
  33. #define DESIGNWARE_PCIE_PHY_DEBUG_R1_XMLH_LINK_UP BIT(4)
  34. #define DESIGNWARE_PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
  35. #define DESIGNWARE_PCIE_PORT_LOGIC_SPEED_CHANGE BIT(17)
  36. #define DESIGNWARE_PCIE_MSI_ADDR_LO 0x820
  37. #define DESIGNWARE_PCIE_MSI_ADDR_HI 0x824
  38. #define DESIGNWARE_PCIE_MSI_INTR0_ENABLE 0x828
  39. #define DESIGNWARE_PCIE_MSI_INTR0_MASK 0x82C
  40. #define DESIGNWARE_PCIE_MSI_INTR0_STATUS 0x830
  41. #define DESIGNWARE_PCIE_ATU_VIEWPORT 0x900
  42. #define DESIGNWARE_PCIE_ATU_REGION_INBOUND BIT(31)
  43. #define DESIGNWARE_PCIE_ATU_CR1 0x904
  44. #define DESIGNWARE_PCIE_ATU_TYPE_MEM (0x0 << 0)
  45. #define DESIGNWARE_PCIE_ATU_CR2 0x908
  46. #define DESIGNWARE_PCIE_ATU_ENABLE BIT(31)
  47. #define DESIGNWARE_PCIE_ATU_LOWER_BASE 0x90C
  48. #define DESIGNWARE_PCIE_ATU_UPPER_BASE 0x910
  49. #define DESIGNWARE_PCIE_ATU_LIMIT 0x914
  50. #define DESIGNWARE_PCIE_ATU_LOWER_TARGET 0x918
  51. #define DESIGNWARE_PCIE_ATU_BUS(x) (((x) >> 24) & 0xff)
  52. #define DESIGNWARE_PCIE_ATU_DEVFN(x) (((x) >> 16) & 0xff)
  53. #define DESIGNWARE_PCIE_ATU_UPPER_TARGET 0x91C
  54. #define DESIGNWARE_PCIE_IRQ_MSI 3
  55. static DesignwarePCIEHost *
  56. designware_pcie_root_to_host(DesignwarePCIERoot *root)
  57. {
  58. BusState *bus = qdev_get_parent_bus(DEVICE(root));
  59. return DESIGNWARE_PCIE_HOST(bus->parent);
  60. }
  61. static void designware_pcie_root_msi_write(void *opaque, hwaddr addr,
  62. uint64_t val, unsigned len)
  63. {
  64. DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(opaque);
  65. DesignwarePCIEHost *host = designware_pcie_root_to_host(root);
  66. root->msi.intr[0].status |= BIT(val) & root->msi.intr[0].enable;
  67. if (root->msi.intr[0].status & ~root->msi.intr[0].mask) {
  68. qemu_set_irq(host->pci.irqs[DESIGNWARE_PCIE_IRQ_MSI], 1);
  69. }
  70. }
  71. static const MemoryRegionOps designware_pci_host_msi_ops = {
  72. .write = designware_pcie_root_msi_write,
  73. .endianness = DEVICE_LITTLE_ENDIAN,
  74. .valid = {
  75. .min_access_size = 4,
  76. .max_access_size = 4,
  77. },
  78. };
  79. static void designware_pcie_root_update_msi_mapping(DesignwarePCIERoot *root)
  80. {
  81. MemoryRegion *mem = &root->msi.iomem;
  82. const uint64_t base = root->msi.base;
  83. const bool enable = root->msi.intr[0].enable;
  84. memory_region_set_address(mem, base);
  85. memory_region_set_enabled(mem, enable);
  86. }
  87. static DesignwarePCIEViewport *
  88. designware_pcie_root_get_current_viewport(DesignwarePCIERoot *root)
  89. {
  90. const unsigned int idx = root->atu_viewport & 0xF;
  91. const unsigned int dir =
  92. !!(root->atu_viewport & DESIGNWARE_PCIE_ATU_REGION_INBOUND);
  93. return &root->viewports[dir][idx];
  94. }
  95. static uint32_t
  96. designware_pcie_root_config_read(PCIDevice *d, uint32_t address, int len)
  97. {
  98. DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(d);
  99. DesignwarePCIEViewport *viewport =
  100. designware_pcie_root_get_current_viewport(root);
  101. uint32_t val;
  102. switch (address) {
  103. case DESIGNWARE_PCIE_PORT_LINK_CONTROL:
  104. /*
  105. * Linux guest uses this register only to configure number of
  106. * PCIE lane (which in our case is irrelevant) and doesn't
  107. * really care about the value it reads from this register
  108. */
  109. val = 0xDEADBEEF;
  110. break;
  111. case DESIGNWARE_PCIE_LINK_WIDTH_SPEED_CONTROL:
  112. /*
  113. * To make sure that any code in guest waiting for speed
  114. * change does not time out we always report
  115. * PORT_LOGIC_SPEED_CHANGE as set
  116. */
  117. val = DESIGNWARE_PCIE_PORT_LOGIC_SPEED_CHANGE;
  118. break;
  119. case DESIGNWARE_PCIE_MSI_ADDR_LO:
  120. val = root->msi.base;
  121. break;
  122. case DESIGNWARE_PCIE_MSI_ADDR_HI:
  123. val = root->msi.base >> 32;
  124. break;
  125. case DESIGNWARE_PCIE_MSI_INTR0_ENABLE:
  126. val = root->msi.intr[0].enable;
  127. break;
  128. case DESIGNWARE_PCIE_MSI_INTR0_MASK:
  129. val = root->msi.intr[0].mask;
  130. break;
  131. case DESIGNWARE_PCIE_MSI_INTR0_STATUS:
  132. val = root->msi.intr[0].status;
  133. break;
  134. case DESIGNWARE_PCIE_PHY_DEBUG_R1:
  135. val = DESIGNWARE_PCIE_PHY_DEBUG_R1_XMLH_LINK_UP;
  136. break;
  137. case DESIGNWARE_PCIE_ATU_VIEWPORT:
  138. val = root->atu_viewport;
  139. break;
  140. case DESIGNWARE_PCIE_ATU_LOWER_BASE:
  141. val = viewport->base;
  142. break;
  143. case DESIGNWARE_PCIE_ATU_UPPER_BASE:
  144. val = viewport->base >> 32;
  145. break;
  146. case DESIGNWARE_PCIE_ATU_LOWER_TARGET:
  147. val = viewport->target;
  148. break;
  149. case DESIGNWARE_PCIE_ATU_UPPER_TARGET:
  150. val = viewport->target >> 32;
  151. break;
  152. case DESIGNWARE_PCIE_ATU_LIMIT:
  153. val = viewport->limit;
  154. break;
  155. case DESIGNWARE_PCIE_ATU_CR1:
  156. case DESIGNWARE_PCIE_ATU_CR2:
  157. val = viewport->cr[(address - DESIGNWARE_PCIE_ATU_CR1) /
  158. sizeof(uint32_t)];
  159. break;
  160. default:
  161. val = pci_default_read_config(d, address, len);
  162. break;
  163. }
  164. return val;
  165. }
  166. static uint64_t designware_pcie_root_data_access(void *opaque, hwaddr addr,
  167. uint64_t *val, unsigned len)
  168. {
  169. DesignwarePCIEViewport *viewport = opaque;
  170. DesignwarePCIERoot *root = viewport->root;
  171. const uint8_t busnum = DESIGNWARE_PCIE_ATU_BUS(viewport->target);
  172. const uint8_t devfn = DESIGNWARE_PCIE_ATU_DEVFN(viewport->target);
  173. PCIBus *pcibus = pci_get_bus(PCI_DEVICE(root));
  174. PCIDevice *pcidev = pci_find_device(pcibus, busnum, devfn);
  175. if (pcidev) {
  176. addr &= pci_config_size(pcidev) - 1;
  177. if (val) {
  178. pci_host_config_write_common(pcidev, addr,
  179. pci_config_size(pcidev),
  180. *val, len);
  181. } else {
  182. return pci_host_config_read_common(pcidev, addr,
  183. pci_config_size(pcidev),
  184. len);
  185. }
  186. }
  187. return UINT64_MAX;
  188. }
  189. static uint64_t designware_pcie_root_data_read(void *opaque, hwaddr addr,
  190. unsigned len)
  191. {
  192. return designware_pcie_root_data_access(opaque, addr, NULL, len);
  193. }
  194. static void designware_pcie_root_data_write(void *opaque, hwaddr addr,
  195. uint64_t val, unsigned len)
  196. {
  197. designware_pcie_root_data_access(opaque, addr, &val, len);
  198. }
  199. static const MemoryRegionOps designware_pci_host_conf_ops = {
  200. .read = designware_pcie_root_data_read,
  201. .write = designware_pcie_root_data_write,
  202. .endianness = DEVICE_LITTLE_ENDIAN,
  203. .valid = {
  204. .min_access_size = 1,
  205. .max_access_size = 4,
  206. },
  207. };
  208. static void designware_pcie_update_viewport(DesignwarePCIERoot *root,
  209. DesignwarePCIEViewport *viewport)
  210. {
  211. const uint64_t target = viewport->target;
  212. const uint64_t base = viewport->base;
  213. const uint64_t size = (uint64_t)viewport->limit - base + 1;
  214. const bool enabled = viewport->cr[1] & DESIGNWARE_PCIE_ATU_ENABLE;
  215. MemoryRegion *current, *other;
  216. if (viewport->cr[0] == DESIGNWARE_PCIE_ATU_TYPE_MEM) {
  217. current = &viewport->mem;
  218. other = &viewport->cfg;
  219. memory_region_set_alias_offset(current, target);
  220. } else {
  221. current = &viewport->cfg;
  222. other = &viewport->mem;
  223. }
  224. /*
  225. * An outbound viewport can be reconfigure from being MEM to CFG,
  226. * to account for that we disable the "other" memory region that
  227. * becomes unused due to that fact.
  228. */
  229. memory_region_set_enabled(other, false);
  230. if (enabled) {
  231. memory_region_set_size(current, size);
  232. memory_region_set_address(current, base);
  233. }
  234. memory_region_set_enabled(current, enabled);
  235. }
  236. static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address,
  237. uint32_t val, int len)
  238. {
  239. DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(d);
  240. DesignwarePCIEHost *host = designware_pcie_root_to_host(root);
  241. DesignwarePCIEViewport *viewport =
  242. designware_pcie_root_get_current_viewport(root);
  243. switch (address) {
  244. case DESIGNWARE_PCIE_PORT_LINK_CONTROL:
  245. case DESIGNWARE_PCIE_LINK_WIDTH_SPEED_CONTROL:
  246. case DESIGNWARE_PCIE_PHY_DEBUG_R1:
  247. /* No-op */
  248. break;
  249. case DESIGNWARE_PCIE_MSI_ADDR_LO:
  250. root->msi.base &= 0xFFFFFFFF00000000ULL;
  251. root->msi.base |= val;
  252. designware_pcie_root_update_msi_mapping(root);
  253. break;
  254. case DESIGNWARE_PCIE_MSI_ADDR_HI:
  255. root->msi.base &= 0x00000000FFFFFFFFULL;
  256. root->msi.base |= (uint64_t)val << 32;
  257. designware_pcie_root_update_msi_mapping(root);
  258. break;
  259. case DESIGNWARE_PCIE_MSI_INTR0_ENABLE:
  260. root->msi.intr[0].enable = val;
  261. designware_pcie_root_update_msi_mapping(root);
  262. break;
  263. case DESIGNWARE_PCIE_MSI_INTR0_MASK:
  264. root->msi.intr[0].mask = val;
  265. break;
  266. case DESIGNWARE_PCIE_MSI_INTR0_STATUS:
  267. root->msi.intr[0].status ^= val;
  268. if (!root->msi.intr[0].status) {
  269. qemu_set_irq(host->pci.irqs[DESIGNWARE_PCIE_IRQ_MSI], 0);
  270. }
  271. break;
  272. case DESIGNWARE_PCIE_ATU_VIEWPORT:
  273. root->atu_viewport = val;
  274. break;
  275. case DESIGNWARE_PCIE_ATU_LOWER_BASE:
  276. viewport->base &= 0xFFFFFFFF00000000ULL;
  277. viewport->base |= val;
  278. break;
  279. case DESIGNWARE_PCIE_ATU_UPPER_BASE:
  280. viewport->base &= 0x00000000FFFFFFFFULL;
  281. viewport->base |= (uint64_t)val << 32;
  282. break;
  283. case DESIGNWARE_PCIE_ATU_LOWER_TARGET:
  284. viewport->target &= 0xFFFFFFFF00000000ULL;
  285. viewport->target |= val;
  286. break;
  287. case DESIGNWARE_PCIE_ATU_UPPER_TARGET:
  288. viewport->target &= 0x00000000FFFFFFFFULL;
  289. viewport->target |= val;
  290. break;
  291. case DESIGNWARE_PCIE_ATU_LIMIT:
  292. viewport->limit = val;
  293. break;
  294. case DESIGNWARE_PCIE_ATU_CR1:
  295. viewport->cr[0] = val;
  296. break;
  297. case DESIGNWARE_PCIE_ATU_CR2:
  298. viewport->cr[1] = val;
  299. designware_pcie_update_viewport(root, viewport);
  300. break;
  301. default:
  302. pci_bridge_write_config(d, address, val, len);
  303. break;
  304. }
  305. }
  306. static char *designware_pcie_viewport_name(const char *direction,
  307. unsigned int i,
  308. const char *type)
  309. {
  310. return g_strdup_printf("PCI %s Viewport %u [%s]",
  311. direction, i, type);
  312. }
  313. static void designware_pcie_root_realize(PCIDevice *dev, Error **errp)
  314. {
  315. DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(dev);
  316. DesignwarePCIEHost *host = designware_pcie_root_to_host(root);
  317. MemoryRegion *address_space = &host->pci.memory;
  318. PCIBridge *br = PCI_BRIDGE(dev);
  319. DesignwarePCIEViewport *viewport;
  320. /*
  321. * Dummy values used for initial configuration of MemoryRegions
  322. * that belong to a given viewport
  323. */
  324. const hwaddr dummy_offset = 0;
  325. const uint64_t dummy_size = 4;
  326. size_t i;
  327. br->bus_name = "dw-pcie";
  328. pci_set_word(dev->config + PCI_COMMAND,
  329. PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
  330. pci_config_set_interrupt_pin(dev->config, 1);
  331. pci_bridge_initfn(dev, TYPE_PCIE_BUS);
  332. pcie_port_init_reg(dev);
  333. pcie_cap_init(dev, 0x70, PCI_EXP_TYPE_ROOT_PORT,
  334. 0, &error_fatal);
  335. msi_nonbroken = true;
  336. msi_init(dev, 0x50, 32, true, true, &error_fatal);
  337. for (i = 0; i < DESIGNWARE_PCIE_NUM_VIEWPORTS; i++) {
  338. MemoryRegion *source, *destination, *mem;
  339. const char *direction;
  340. char *name;
  341. viewport = &root->viewports[DESIGNWARE_PCIE_VIEWPORT_INBOUND][i];
  342. viewport->inbound = true;
  343. viewport->base = 0x0000000000000000ULL;
  344. viewport->target = 0x0000000000000000ULL;
  345. viewport->limit = UINT32_MAX;
  346. viewport->cr[0] = DESIGNWARE_PCIE_ATU_TYPE_MEM;
  347. source = &host->pci.address_space_root;
  348. destination = get_system_memory();
  349. direction = "Inbound";
  350. /*
  351. * Configure MemoryRegion implementing PCI -> CPU memory
  352. * access
  353. */
  354. mem = &viewport->mem;
  355. name = designware_pcie_viewport_name(direction, i, "MEM");
  356. memory_region_init_alias(mem, OBJECT(root), name, destination,
  357. dummy_offset, dummy_size);
  358. memory_region_add_subregion_overlap(source, dummy_offset, mem, -1);
  359. memory_region_set_enabled(mem, false);
  360. g_free(name);
  361. viewport = &root->viewports[DESIGNWARE_PCIE_VIEWPORT_OUTBOUND][i];
  362. viewport->root = root;
  363. viewport->inbound = false;
  364. viewport->base = 0x0000000000000000ULL;
  365. viewport->target = 0x0000000000000000ULL;
  366. viewport->limit = UINT32_MAX;
  367. viewport->cr[0] = DESIGNWARE_PCIE_ATU_TYPE_MEM;
  368. destination = &host->pci.memory;
  369. direction = "Outbound";
  370. source = get_system_memory();
  371. /*
  372. * Configure MemoryRegion implementing CPU -> PCI memory
  373. * access
  374. */
  375. mem = &viewport->mem;
  376. name = designware_pcie_viewport_name(direction, i, "MEM");
  377. memory_region_init_alias(mem, OBJECT(root), name, destination,
  378. dummy_offset, dummy_size);
  379. memory_region_add_subregion(source, dummy_offset, mem);
  380. memory_region_set_enabled(mem, false);
  381. g_free(name);
  382. /*
  383. * Configure MemoryRegion implementing access to configuration
  384. * space
  385. */
  386. mem = &viewport->cfg;
  387. name = designware_pcie_viewport_name(direction, i, "CFG");
  388. memory_region_init_io(&viewport->cfg, OBJECT(root),
  389. &designware_pci_host_conf_ops,
  390. viewport, name, dummy_size);
  391. memory_region_add_subregion(source, dummy_offset, mem);
  392. memory_region_set_enabled(mem, false);
  393. g_free(name);
  394. }
  395. /*
  396. * If no inbound iATU windows are configured, HW defaults to
  397. * letting inbound TLPs to pass in. We emulate that by exlicitly
  398. * configuring first inbound window to cover all of target's
  399. * address space.
  400. *
  401. * NOTE: This will not work correctly for the case when first
  402. * configured inbound window is window 0
  403. */
  404. viewport = &root->viewports[DESIGNWARE_PCIE_VIEWPORT_INBOUND][0];
  405. viewport->cr[1] = DESIGNWARE_PCIE_ATU_ENABLE;
  406. designware_pcie_update_viewport(root, viewport);
  407. memory_region_init_io(&root->msi.iomem, OBJECT(root),
  408. &designware_pci_host_msi_ops,
  409. root, "pcie-msi", 0x4);
  410. /*
  411. * We initially place MSI interrupt I/O region a adress 0 and
  412. * disable it. It'll be later moved to correct offset and enabled
  413. * in designware_pcie_root_update_msi_mapping() as a part of
  414. * initialization done by guest OS
  415. */
  416. memory_region_add_subregion(address_space, dummy_offset, &root->msi.iomem);
  417. memory_region_set_enabled(&root->msi.iomem, false);
  418. }
  419. static void designware_pcie_set_irq(void *opaque, int irq_num, int level)
  420. {
  421. DesignwarePCIEHost *host = DESIGNWARE_PCIE_HOST(opaque);
  422. qemu_set_irq(host->pci.irqs[irq_num], level);
  423. }
  424. static const char *
  425. designware_pcie_host_root_bus_path(PCIHostState *host_bridge, PCIBus *rootbus)
  426. {
  427. return "0000:00";
  428. }
  429. static const VMStateDescription vmstate_designware_pcie_msi_bank = {
  430. .name = "designware-pcie-msi-bank",
  431. .version_id = 1,
  432. .minimum_version_id = 1,
  433. .fields = (VMStateField[]) {
  434. VMSTATE_UINT32(enable, DesignwarePCIEMSIBank),
  435. VMSTATE_UINT32(mask, DesignwarePCIEMSIBank),
  436. VMSTATE_UINT32(status, DesignwarePCIEMSIBank),
  437. VMSTATE_END_OF_LIST()
  438. }
  439. };
  440. static const VMStateDescription vmstate_designware_pcie_msi = {
  441. .name = "designware-pcie-msi",
  442. .version_id = 1,
  443. .minimum_version_id = 1,
  444. .fields = (VMStateField[]) {
  445. VMSTATE_UINT64(base, DesignwarePCIEMSI),
  446. VMSTATE_STRUCT_ARRAY(intr,
  447. DesignwarePCIEMSI,
  448. DESIGNWARE_PCIE_NUM_MSI_BANKS,
  449. 1,
  450. vmstate_designware_pcie_msi_bank,
  451. DesignwarePCIEMSIBank),
  452. VMSTATE_END_OF_LIST()
  453. }
  454. };
  455. static const VMStateDescription vmstate_designware_pcie_viewport = {
  456. .name = "designware-pcie-viewport",
  457. .version_id = 1,
  458. .minimum_version_id = 1,
  459. .fields = (VMStateField[]) {
  460. VMSTATE_UINT64(base, DesignwarePCIEViewport),
  461. VMSTATE_UINT64(target, DesignwarePCIEViewport),
  462. VMSTATE_UINT32(limit, DesignwarePCIEViewport),
  463. VMSTATE_UINT32_ARRAY(cr, DesignwarePCIEViewport, 2),
  464. VMSTATE_END_OF_LIST()
  465. }
  466. };
  467. static const VMStateDescription vmstate_designware_pcie_root = {
  468. .name = "designware-pcie-root",
  469. .version_id = 1,
  470. .minimum_version_id = 1,
  471. .fields = (VMStateField[]) {
  472. VMSTATE_PCI_DEVICE(parent_obj, PCIBridge),
  473. VMSTATE_UINT32(atu_viewport, DesignwarePCIERoot),
  474. VMSTATE_STRUCT_2DARRAY(viewports,
  475. DesignwarePCIERoot,
  476. 2,
  477. DESIGNWARE_PCIE_NUM_VIEWPORTS,
  478. 1,
  479. vmstate_designware_pcie_viewport,
  480. DesignwarePCIEViewport),
  481. VMSTATE_STRUCT(msi,
  482. DesignwarePCIERoot,
  483. 1,
  484. vmstate_designware_pcie_msi,
  485. DesignwarePCIEMSI),
  486. VMSTATE_END_OF_LIST()
  487. }
  488. };
  489. static void designware_pcie_root_class_init(ObjectClass *klass, void *data)
  490. {
  491. PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
  492. DeviceClass *dc = DEVICE_CLASS(klass);
  493. set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
  494. k->vendor_id = PCI_VENDOR_ID_SYNOPSYS;
  495. k->device_id = 0xABCD;
  496. k->revision = 0;
  497. k->class_id = PCI_CLASS_BRIDGE_PCI;
  498. k->is_bridge = true;
  499. k->exit = pci_bridge_exitfn;
  500. k->realize = designware_pcie_root_realize;
  501. k->config_read = designware_pcie_root_config_read;
  502. k->config_write = designware_pcie_root_config_write;
  503. dc->reset = pci_bridge_reset;
  504. /*
  505. * PCI-facing part of the host bridge, not usable without the
  506. * host-facing part, which can't be device_add'ed, yet.
  507. */
  508. dc->user_creatable = false;
  509. dc->vmsd = &vmstate_designware_pcie_root;
  510. }
  511. static uint64_t designware_pcie_host_mmio_read(void *opaque, hwaddr addr,
  512. unsigned int size)
  513. {
  514. PCIHostState *pci = PCI_HOST_BRIDGE(opaque);
  515. PCIDevice *device = pci_find_device(pci->bus, 0, 0);
  516. return pci_host_config_read_common(device,
  517. addr,
  518. pci_config_size(device),
  519. size);
  520. }
  521. static void designware_pcie_host_mmio_write(void *opaque, hwaddr addr,
  522. uint64_t val, unsigned int size)
  523. {
  524. PCIHostState *pci = PCI_HOST_BRIDGE(opaque);
  525. PCIDevice *device = pci_find_device(pci->bus, 0, 0);
  526. return pci_host_config_write_common(device,
  527. addr,
  528. pci_config_size(device),
  529. val, size);
  530. }
  531. static const MemoryRegionOps designware_pci_mmio_ops = {
  532. .read = designware_pcie_host_mmio_read,
  533. .write = designware_pcie_host_mmio_write,
  534. .endianness = DEVICE_LITTLE_ENDIAN,
  535. .impl = {
  536. /*
  537. * Our device would not work correctly if the guest was doing
  538. * unaligned access. This might not be a limitation on the real
  539. * device but in practice there is no reason for a guest to access
  540. * this device unaligned.
  541. */
  542. .min_access_size = 4,
  543. .max_access_size = 4,
  544. .unaligned = false,
  545. },
  546. };
  547. static AddressSpace *designware_pcie_host_set_iommu(PCIBus *bus, void *opaque,
  548. int devfn)
  549. {
  550. DesignwarePCIEHost *s = DESIGNWARE_PCIE_HOST(opaque);
  551. return &s->pci.address_space;
  552. }
  553. static void designware_pcie_host_realize(DeviceState *dev, Error **errp)
  554. {
  555. PCIHostState *pci = PCI_HOST_BRIDGE(dev);
  556. DesignwarePCIEHost *s = DESIGNWARE_PCIE_HOST(dev);
  557. SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
  558. size_t i;
  559. for (i = 0; i < ARRAY_SIZE(s->pci.irqs); i++) {
  560. sysbus_init_irq(sbd, &s->pci.irqs[i]);
  561. }
  562. memory_region_init_io(&s->mmio,
  563. OBJECT(s),
  564. &designware_pci_mmio_ops,
  565. s,
  566. "pcie.reg", 4 * 1024);
  567. sysbus_init_mmio(sbd, &s->mmio);
  568. memory_region_init(&s->pci.io, OBJECT(s), "pcie-pio", 16);
  569. memory_region_init(&s->pci.memory, OBJECT(s),
  570. "pcie-bus-memory",
  571. UINT64_MAX);
  572. pci->bus = pci_register_root_bus(dev, "pcie",
  573. designware_pcie_set_irq,
  574. pci_swizzle_map_irq_fn,
  575. s,
  576. &s->pci.memory,
  577. &s->pci.io,
  578. 0, 4,
  579. TYPE_PCIE_BUS);
  580. memory_region_init(&s->pci.address_space_root,
  581. OBJECT(s),
  582. "pcie-bus-address-space-root",
  583. UINT64_MAX);
  584. memory_region_add_subregion(&s->pci.address_space_root,
  585. 0x0, &s->pci.memory);
  586. address_space_init(&s->pci.address_space,
  587. &s->pci.address_space_root,
  588. "pcie-bus-address-space");
  589. pci_setup_iommu(pci->bus, designware_pcie_host_set_iommu, s);
  590. qdev_realize(DEVICE(&s->root), BUS(pci->bus), &error_fatal);
  591. }
  592. static const VMStateDescription vmstate_designware_pcie_host = {
  593. .name = "designware-pcie-host",
  594. .version_id = 1,
  595. .minimum_version_id = 1,
  596. .fields = (VMStateField[]) {
  597. VMSTATE_STRUCT(root,
  598. DesignwarePCIEHost,
  599. 1,
  600. vmstate_designware_pcie_root,
  601. DesignwarePCIERoot),
  602. VMSTATE_END_OF_LIST()
  603. }
  604. };
  605. static void designware_pcie_host_class_init(ObjectClass *klass, void *data)
  606. {
  607. DeviceClass *dc = DEVICE_CLASS(klass);
  608. PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
  609. hc->root_bus_path = designware_pcie_host_root_bus_path;
  610. dc->realize = designware_pcie_host_realize;
  611. set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
  612. dc->fw_name = "pci";
  613. dc->vmsd = &vmstate_designware_pcie_host;
  614. }
  615. static void designware_pcie_host_init(Object *obj)
  616. {
  617. DesignwarePCIEHost *s = DESIGNWARE_PCIE_HOST(obj);
  618. DesignwarePCIERoot *root = &s->root;
  619. object_initialize_child(obj, "root", root, TYPE_DESIGNWARE_PCIE_ROOT);
  620. qdev_prop_set_int32(DEVICE(root), "addr", PCI_DEVFN(0, 0));
  621. qdev_prop_set_bit(DEVICE(root), "multifunction", false);
  622. }
  623. static const TypeInfo designware_pcie_root_info = {
  624. .name = TYPE_DESIGNWARE_PCIE_ROOT,
  625. .parent = TYPE_PCI_BRIDGE,
  626. .instance_size = sizeof(DesignwarePCIERoot),
  627. .class_init = designware_pcie_root_class_init,
  628. .interfaces = (InterfaceInfo[]) {
  629. { INTERFACE_PCIE_DEVICE },
  630. { }
  631. },
  632. };
  633. static const TypeInfo designware_pcie_host_info = {
  634. .name = TYPE_DESIGNWARE_PCIE_HOST,
  635. .parent = TYPE_PCI_HOST_BRIDGE,
  636. .instance_size = sizeof(DesignwarePCIEHost),
  637. .instance_init = designware_pcie_host_init,
  638. .class_init = designware_pcie_host_class_init,
  639. };
  640. static void designware_pcie_register(void)
  641. {
  642. type_register_static(&designware_pcie_root_info);
  643. type_register_static(&designware_pcie_host_info);
  644. }
  645. type_init(designware_pcie_register)