|
|
1.1 ! root 1: /* ! 2: * pcie.c ! 3: * ! 4: * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp> ! 5: * VA Linux Systems Japan K.K. ! 6: * ! 7: * This program is free software; you can redistribute it and/or modify ! 8: * it under the terms of the GNU General Public License as published by ! 9: * the Free Software Foundation; either version 2 of the License, or ! 10: * (at your option) any later version. ! 11: * ! 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: * ! 17: * You should have received a copy of the GNU General Public License along ! 18: * with this program; if not, see <http://www.gnu.org/licenses/>. ! 19: */ ! 20: ! 21: #include "sysemu.h" ! 22: #include "range.h" ! 23: #include "pci_bridge.h" ! 24: #include "pcie.h" ! 25: #include "msix.h" ! 26: #include "msi.h" ! 27: #include "pci_internals.h" ! 28: #include "pcie_regs.h" ! 29: #include "range.h" ! 30: ! 31: //#define DEBUG_PCIE ! 32: #ifdef DEBUG_PCIE ! 33: # define PCIE_DPRINTF(fmt, ...) \ ! 34: fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) ! 35: #else ! 36: # define PCIE_DPRINTF(fmt, ...) do {} while (0) ! 37: #endif ! 38: #define PCIE_DEV_PRINTF(dev, fmt, ...) \ ! 39: PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) ! 40: ! 41: ! 42: /*************************************************************************** ! 43: * pci express capability helper functions ! 44: */ ! 45: int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port) ! 46: { ! 47: int pos; ! 48: uint8_t *exp_cap; ! 49: ! 50: assert(pci_is_express(dev)); ! 51: ! 52: pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset, ! 53: PCI_EXP_VER2_SIZEOF); ! 54: if (pos < 0) { ! 55: return pos; ! 56: } ! 57: dev->exp.exp_cap = pos; ! 58: exp_cap = dev->config + pos; ! 59: ! 60: /* capability register ! 61: interrupt message number defaults to 0 */ ! 62: pci_set_word(exp_cap + PCI_EXP_FLAGS, ! 63: ((type << PCI_EXP_FLAGS_TYPE_SHIFT) & PCI_EXP_FLAGS_TYPE) | ! 64: PCI_EXP_FLAGS_VER2); ! 65: ! 66: /* device capability register ! 67: * table 7-12: ! 68: * roll based error reporting bit must be set by all ! 69: * Functions conforming to the ECN, PCI Express Base ! 70: * Specification, Revision 1.1., or subsequent PCI Express Base ! 71: * Specification revisions. ! 72: */ ! 73: pci_set_long(exp_cap + PCI_EXP_DEVCAP, PCI_EXP_DEVCAP_RBER); ! 74: ! 75: pci_set_long(exp_cap + PCI_EXP_LNKCAP, ! 76: (port << PCI_EXP_LNKCAP_PN_SHIFT) | ! 77: PCI_EXP_LNKCAP_ASPMS_0S | ! 78: PCI_EXP_LNK_MLW_1 | ! 79: PCI_EXP_LNK_LS_25); ! 80: ! 81: pci_set_word(exp_cap + PCI_EXP_LNKSTA, ! 82: PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25); ! 83: ! 84: pci_set_long(exp_cap + PCI_EXP_DEVCAP2, ! 85: PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP); ! 86: ! 87: pci_set_word(dev->wmask + pos, PCI_EXP_DEVCTL2_EETLPPB); ! 88: return pos; ! 89: } ! 90: ! 91: void pcie_cap_exit(PCIDevice *dev) ! 92: { ! 93: pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF); ! 94: } ! 95: ! 96: uint8_t pcie_cap_get_type(const PCIDevice *dev) ! 97: { ! 98: uint32_t pos = dev->exp.exp_cap; ! 99: assert(pos > 0); ! 100: return (pci_get_word(dev->config + pos + PCI_EXP_FLAGS) & ! 101: PCI_EXP_FLAGS_TYPE) >> PCI_EXP_FLAGS_TYPE_SHIFT; ! 102: } ! 103: ! 104: /* MSI/MSI-X */ ! 105: /* pci express interrupt message number */ ! 106: /* 7.8.2 PCI Express Capabilities Register: Interrupt Message Number */ ! 107: void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector) ! 108: { ! 109: uint8_t *exp_cap = dev->config + dev->exp.exp_cap; ! 110: assert(vector < 32); ! 111: pci_word_test_and_clear_mask(exp_cap + PCI_EXP_FLAGS, PCI_EXP_FLAGS_IRQ); ! 112: pci_word_test_and_set_mask(exp_cap + PCI_EXP_FLAGS, ! 113: vector << PCI_EXP_FLAGS_IRQ_SHIFT); ! 114: } ! 115: ! 116: uint8_t pcie_cap_flags_get_vector(PCIDevice *dev) ! 117: { ! 118: return (pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_FLAGS) & ! 119: PCI_EXP_FLAGS_IRQ) >> PCI_EXP_FLAGS_IRQ_SHIFT; ! 120: } ! 121: ! 122: void pcie_cap_deverr_init(PCIDevice *dev) ! 123: { ! 124: uint32_t pos = dev->exp.exp_cap; ! 125: pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP, ! 126: PCI_EXP_DEVCAP_RBER); ! 127: pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL, ! 128: PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | ! 129: PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE); ! 130: pci_long_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_DEVSTA, ! 131: PCI_EXP_DEVSTA_CED | PCI_EXP_DEVSTA_NFED | ! 132: PCI_EXP_DEVSTA_URD | PCI_EXP_DEVSTA_URD); ! 133: } ! 134: ! 135: void pcie_cap_deverr_reset(PCIDevice *dev) ! 136: { ! 137: uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL; ! 138: pci_long_test_and_clear_mask(devctl, ! 139: PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | ! 140: PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE); ! 141: } ! 142: ! 143: static void hotplug_event_update_event_status(PCIDevice *dev) ! 144: { ! 145: uint32_t pos = dev->exp.exp_cap; ! 146: uint8_t *exp_cap = dev->config + pos; ! 147: uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL); ! 148: uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); ! 149: ! 150: dev->exp.hpev_notified = (sltctl & PCI_EXP_SLTCTL_HPIE) && ! 151: (sltsta & sltctl & PCI_EXP_HP_EV_SUPPORTED); ! 152: } ! 153: ! 154: static void hotplug_event_notify(PCIDevice *dev) ! 155: { ! 156: bool prev = dev->exp.hpev_notified; ! 157: ! 158: hotplug_event_update_event_status(dev); ! 159: ! 160: if (prev == dev->exp.hpev_notified) { ! 161: return; ! 162: } ! 163: ! 164: /* Note: the logic above does not take into account whether interrupts ! 165: * are masked. The result is that interrupt will be sent when it is ! 166: * subsequently unmasked. This appears to be legal: Section 6.7.3.4: ! 167: * The Port may optionally send an MSI when there are hot-plug events that ! 168: * occur while interrupt generation is disabled, and interrupt generation is ! 169: * subsequently enabled. */ ! 170: if (msix_enabled(dev)) { ! 171: msix_notify(dev, pcie_cap_flags_get_vector(dev)); ! 172: } else if (msi_enabled(dev)) { ! 173: msi_notify(dev, pcie_cap_flags_get_vector(dev)); ! 174: } else { ! 175: qemu_set_irq(dev->irq[dev->exp.hpev_intx], dev->exp.hpev_notified); ! 176: } ! 177: } ! 178: ! 179: /* ! 180: * A PCI Express Hot-Plug Event has occured, so update slot status register ! 181: * and notify OS of the event if necessary. ! 182: * ! 183: * 6.7.3 PCI Express Hot-Plug Events ! 184: * 6.7.3.4 Software Notification of Hot-Plug Events ! 185: */ ! 186: static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event) ! 187: { ! 188: /* Minor optimization: if nothing changed - no event is needed. */ ! 189: if (pci_word_test_and_set_mask(dev->config + dev->exp.exp_cap + ! 190: PCI_EXP_SLTSTA, event)) { ! 191: return; ! 192: } ! 193: hotplug_event_notify(dev); ! 194: } ! 195: ! 196: static int pcie_cap_slot_hotplug(DeviceState *qdev, ! 197: PCIDevice *pci_dev, PCIHotplugState state) ! 198: { ! 199: PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev); ! 200: uint8_t *exp_cap = d->config + d->exp.exp_cap; ! 201: uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); ! 202: ! 203: /* Don't send event when device is enabled during qemu machine creation: ! 204: * it is present on boot, no hotplug event is necessary. We do send an ! 205: * event when the device is disabled later. */ ! 206: if (state == PCI_COLDPLUG_ENABLED) { ! 207: pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, ! 208: PCI_EXP_SLTSTA_PDS); ! 209: return 0; ! 210: } ! 211: ! 212: PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state); ! 213: if (sltsta & PCI_EXP_SLTSTA_EIS) { ! 214: /* the slot is electromechanically locked. ! 215: * This error is propagated up to qdev and then to HMP/QMP. ! 216: */ ! 217: return -EBUSY; ! 218: } ! 219: ! 220: /* TODO: multifunction hot-plug. ! 221: * Right now, only a device of function = 0 is allowed to be ! 222: * hot plugged/unplugged. ! 223: */ ! 224: assert(PCI_FUNC(pci_dev->devfn) == 0); ! 225: ! 226: if (state == PCI_HOTPLUG_ENABLED) { ! 227: pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, ! 228: PCI_EXP_SLTSTA_PDS); ! 229: pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); ! 230: } else { ! 231: qdev_free(&pci_dev->qdev); ! 232: pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA, ! 233: PCI_EXP_SLTSTA_PDS); ! 234: pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); ! 235: } ! 236: return 0; ! 237: } ! 238: ! 239: /* pci express slot for pci express root/downstream port ! 240: PCI express capability slot registers */ ! 241: void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot) ! 242: { ! 243: uint32_t pos = dev->exp.exp_cap; ! 244: ! 245: pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_FLAGS, ! 246: PCI_EXP_FLAGS_SLOT); ! 247: ! 248: pci_long_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCAP, ! 249: ~PCI_EXP_SLTCAP_PSN); ! 250: pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP, ! 251: (slot << PCI_EXP_SLTCAP_PSN_SHIFT) | ! 252: PCI_EXP_SLTCAP_EIP | ! 253: PCI_EXP_SLTCAP_HPS | ! 254: PCI_EXP_SLTCAP_HPC | ! 255: PCI_EXP_SLTCAP_PIP | ! 256: PCI_EXP_SLTCAP_AIP | ! 257: PCI_EXP_SLTCAP_ABP); ! 258: ! 259: pci_word_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCTL, ! 260: PCI_EXP_SLTCTL_PIC | ! 261: PCI_EXP_SLTCTL_AIC); ! 262: pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCTL, ! 263: PCI_EXP_SLTCTL_PIC_OFF | ! 264: PCI_EXP_SLTCTL_AIC_OFF); ! 265: pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL, ! 266: PCI_EXP_SLTCTL_PIC | ! 267: PCI_EXP_SLTCTL_AIC | ! 268: PCI_EXP_SLTCTL_HPIE | ! 269: PCI_EXP_SLTCTL_CCIE | ! 270: PCI_EXP_SLTCTL_PDCE | ! 271: PCI_EXP_SLTCTL_ABPE); ! 272: /* Although reading PCI_EXP_SLTCTL_EIC returns always 0, ! 273: * make the bit writable here in order to detect 1b is written. ! 274: * pcie_cap_slot_write_config() test-and-clear the bit, so ! 275: * this bit always returns 0 to the guest. ! 276: */ ! 277: pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL, ! 278: PCI_EXP_SLTCTL_EIC); ! 279: ! 280: pci_word_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_SLTSTA, ! 281: PCI_EXP_HP_EV_SUPPORTED); ! 282: ! 283: dev->exp.hpev_notified = false; ! 284: ! 285: pci_bus_hotplug(pci_bridge_get_sec_bus(DO_UPCAST(PCIBridge, dev, dev)), ! 286: pcie_cap_slot_hotplug, &dev->qdev); ! 287: } ! 288: ! 289: void pcie_cap_slot_reset(PCIDevice *dev) ! 290: { ! 291: uint8_t *exp_cap = dev->config + dev->exp.exp_cap; ! 292: ! 293: PCIE_DEV_PRINTF(dev, "reset\n"); ! 294: ! 295: pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL, ! 296: PCI_EXP_SLTCTL_EIC | ! 297: PCI_EXP_SLTCTL_PIC | ! 298: PCI_EXP_SLTCTL_AIC | ! 299: PCI_EXP_SLTCTL_HPIE | ! 300: PCI_EXP_SLTCTL_CCIE | ! 301: PCI_EXP_SLTCTL_PDCE | ! 302: PCI_EXP_SLTCTL_ABPE); ! 303: pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL, ! 304: PCI_EXP_SLTCTL_PIC_OFF | ! 305: PCI_EXP_SLTCTL_AIC_OFF); ! 306: ! 307: pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA, ! 308: PCI_EXP_SLTSTA_EIS |/* on reset, ! 309: the lock is released */ ! 310: PCI_EXP_SLTSTA_CC | ! 311: PCI_EXP_SLTSTA_PDC | ! 312: PCI_EXP_SLTSTA_ABP); ! 313: ! 314: hotplug_event_update_event_status(dev); ! 315: } ! 316: ! 317: void pcie_cap_slot_write_config(PCIDevice *dev, ! 318: uint32_t addr, uint32_t val, int len) ! 319: { ! 320: uint32_t pos = dev->exp.exp_cap; ! 321: uint8_t *exp_cap = dev->config + pos; ! 322: uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); ! 323: ! 324: if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) { ! 325: return; ! 326: } ! 327: ! 328: if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL, ! 329: PCI_EXP_SLTCTL_EIC)) { ! 330: sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */ ! 331: pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta); ! 332: PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: " ! 333: "sltsta -> 0x%02"PRIx16"\n", ! 334: sltsta); ! 335: } ! 336: ! 337: hotplug_event_notify(dev); ! 338: ! 339: /* ! 340: * 6.7.3.2 Command Completed Events ! 341: * ! 342: * Software issues a command to a hot-plug capable Downstream Port by ! 343: * issuing a write transaction that targets any portion of the Port’s Slot ! 344: * Control register. A single write to the Slot Control register is ! 345: * considered to be a single command, even if the write affects more than ! 346: * one field in the Slot Control register. In response to this transaction, ! 347: * the Port must carry out the requested actions and then set the ! 348: * associated status field for the command completed event. */ ! 349: ! 350: /* Real hardware might take a while to complete requested command because ! 351: * physical movement would be involved like locking the electromechanical ! 352: * lock. However in our case, command is completed instantaneously above, ! 353: * so send a command completion event right now. ! 354: */ ! 355: pcie_cap_slot_event(dev, PCI_EXP_HP_EV_CCI); ! 356: } ! 357: ! 358: int pcie_cap_slot_post_load(void *opaque, int version_id) ! 359: { ! 360: PCIDevice *dev = opaque; ! 361: hotplug_event_update_event_status(dev); ! 362: return 0; ! 363: } ! 364: ! 365: void pcie_cap_slot_push_attention_button(PCIDevice *dev) ! 366: { ! 367: pcie_cap_slot_event(dev, PCI_EXP_HP_EV_ABP); ! 368: } ! 369: ! 370: /* root control/capabilities/status. PME isn't emulated for now */ ! 371: void pcie_cap_root_init(PCIDevice *dev) ! 372: { ! 373: pci_set_word(dev->wmask + dev->exp.exp_cap + PCI_EXP_RTCTL, ! 374: PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE | ! 375: PCI_EXP_RTCTL_SEFEE); ! 376: } ! 377: ! 378: void pcie_cap_root_reset(PCIDevice *dev) ! 379: { ! 380: pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_RTCTL, 0); ! 381: } ! 382: ! 383: /* function level reset(FLR) */ ! 384: void pcie_cap_flr_init(PCIDevice *dev) ! 385: { ! 386: pci_long_test_and_set_mask(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCAP, ! 387: PCI_EXP_DEVCAP_FLR); ! 388: ! 389: /* Although reading BCR_FLR returns always 0, ! 390: * the bit is made writable here in order to detect the 1b is written ! 391: * pcie_cap_flr_write_config() test-and-clear the bit, so ! 392: * this bit always returns 0 to the guest. ! 393: */ ! 394: pci_word_test_and_set_mask(dev->wmask + dev->exp.exp_cap + PCI_EXP_DEVCTL, ! 395: PCI_EXP_DEVCTL_BCR_FLR); ! 396: } ! 397: ! 398: void pcie_cap_flr_write_config(PCIDevice *dev, ! 399: uint32_t addr, uint32_t val, int len) ! 400: { ! 401: uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL; ! 402: if (pci_get_word(devctl) & PCI_EXP_DEVCTL_BCR_FLR) { ! 403: /* Clear PCI_EXP_DEVCTL_BCR_FLR after invoking the reset handler ! 404: so the handler can detect FLR by looking at this bit. */ ! 405: pci_device_reset(dev); ! 406: pci_word_test_and_clear_mask(devctl, PCI_EXP_DEVCTL_BCR_FLR); ! 407: } ! 408: } ! 409: ! 410: /* Alternative Routing-ID Interpretation (ARI) */ ! 411: /* ari forwarding support for down stream port */ ! 412: void pcie_cap_ari_init(PCIDevice *dev) ! 413: { ! 414: uint32_t pos = dev->exp.exp_cap; ! 415: pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_DEVCAP2, ! 416: PCI_EXP_DEVCAP2_ARI); ! 417: pci_long_test_and_set_mask(dev->wmask + pos + PCI_EXP_DEVCTL2, ! 418: PCI_EXP_DEVCTL2_ARI); ! 419: } ! 420: ! 421: void pcie_cap_ari_reset(PCIDevice *dev) ! 422: { ! 423: uint8_t *devctl2 = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2; ! 424: pci_long_test_and_clear_mask(devctl2, PCI_EXP_DEVCTL2_ARI); ! 425: } ! 426: ! 427: bool pcie_cap_is_ari_enabled(const PCIDevice *dev) ! 428: { ! 429: if (!pci_is_express(dev)) { ! 430: return false; ! 431: } ! 432: if (!dev->exp.exp_cap) { ! 433: return false; ! 434: } ! 435: ! 436: return pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) & ! 437: PCI_EXP_DEVCTL2_ARI; ! 438: } ! 439: ! 440: /************************************************************************** ! 441: * pci express extended capability allocation functions ! 442: * uint16_t ext_cap_id (16 bit) ! 443: * uint8_t cap_ver (4 bit) ! 444: * uint16_t cap_offset (12 bit) ! 445: * uint16_t ext_cap_size ! 446: */ ! 447: ! 448: static uint16_t pcie_find_capability_list(PCIDevice *dev, uint16_t cap_id, ! 449: uint16_t *prev_p) ! 450: { ! 451: uint16_t prev = 0; ! 452: uint16_t next; ! 453: uint32_t header = pci_get_long(dev->config + PCI_CONFIG_SPACE_SIZE); ! 454: ! 455: if (!header) { ! 456: /* no extended capability */ ! 457: next = 0; ! 458: goto out; ! 459: } ! 460: for (next = PCI_CONFIG_SPACE_SIZE; next; ! 461: prev = next, next = PCI_EXT_CAP_NEXT(header)) { ! 462: ! 463: assert(next >= PCI_CONFIG_SPACE_SIZE); ! 464: assert(next <= PCIE_CONFIG_SPACE_SIZE - 8); ! 465: ! 466: header = pci_get_long(dev->config + next); ! 467: if (PCI_EXT_CAP_ID(header) == cap_id) { ! 468: break; ! 469: } ! 470: } ! 471: ! 472: out: ! 473: if (prev_p) { ! 474: *prev_p = prev; ! 475: } ! 476: return next; ! 477: } ! 478: ! 479: uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id) ! 480: { ! 481: return pcie_find_capability_list(dev, cap_id, NULL); ! 482: } ! 483: ! 484: static void pcie_ext_cap_set_next(PCIDevice *dev, uint16_t pos, uint16_t next) ! 485: { ! 486: uint16_t header = pci_get_long(dev->config + pos); ! 487: assert(!(next & (PCI_EXT_CAP_ALIGN - 1))); ! 488: header = (header & ~PCI_EXT_CAP_NEXT_MASK) | ! 489: ((next << PCI_EXT_CAP_NEXT_SHIFT) & PCI_EXT_CAP_NEXT_MASK); ! 490: pci_set_long(dev->config + pos, header); ! 491: } ! 492: ! 493: /* ! 494: * caller must supply valid (offset, size) * such that the range shouldn't ! 495: * overlap with other capability or other registers. ! 496: * This function doesn't check it. ! 497: */ ! 498: void pcie_add_capability(PCIDevice *dev, ! 499: uint16_t cap_id, uint8_t cap_ver, ! 500: uint16_t offset, uint16_t size) ! 501: { ! 502: uint32_t header; ! 503: uint16_t next; ! 504: ! 505: assert(offset >= PCI_CONFIG_SPACE_SIZE); ! 506: assert(offset < offset + size); ! 507: assert(offset + size < PCIE_CONFIG_SPACE_SIZE); ! 508: assert(size >= 8); ! 509: assert(pci_is_express(dev)); ! 510: ! 511: if (offset == PCI_CONFIG_SPACE_SIZE) { ! 512: header = pci_get_long(dev->config + offset); ! 513: next = PCI_EXT_CAP_NEXT(header); ! 514: } else { ! 515: uint16_t prev; ! 516: ! 517: /* 0 is reserved cap id. use internally to find the last capability ! 518: in the linked list */ ! 519: next = pcie_find_capability_list(dev, 0, &prev); ! 520: ! 521: assert(prev >= PCI_CONFIG_SPACE_SIZE); ! 522: assert(next == 0); ! 523: pcie_ext_cap_set_next(dev, prev, offset); ! 524: } ! 525: pci_set_long(dev->config + offset, PCI_EXT_CAP(cap_id, cap_ver, next)); ! 526: ! 527: /* Make capability read-only by default */ ! 528: memset(dev->wmask + offset, 0, size); ! 529: memset(dev->w1cmask + offset, 0, size); ! 530: /* Check capability by default */ ! 531: memset(dev->cmask + offset, 0xFF, size); ! 532: } ! 533: ! 534: /************************************************************************** ! 535: * pci express extended capability helper functions ! 536: */ ! 537: ! 538: /* ARI */ ! 539: void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn) ! 540: { ! 541: pcie_add_capability(dev, PCI_EXT_CAP_ID_ARI, PCI_ARI_VER, ! 542: offset, PCI_ARI_SIZEOF); ! 543: pci_set_long(dev->config + offset + PCI_ARI_CAP, PCI_ARI_CAP_NFN(nextfn)); ! 544: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.