No consensus yet but I’d suggest that we’ll do the QEMU work and Jonathan focuses on the linux kernel and UEFI/edk2 and CXL SSWG efforts. Seems like a way to maximize resources and everyone’s contribution and expertise. QEMU part requires the least expertise which is why we’re best suited for it compared to other areas ;)
Review comments will be folded into next patch. > On Feb 9, 2021, at 4:42 PM, Ben Widawsky <b...@bwidawsk.net> wrote: > > Have you/Jonathan come to consensus about which implementation is going > forward? > I'd rather not have to review two :D > > On 21-02-09 15:35:49, Chris Browy wrote: >> --- >> MAINTAINERS | 7 + >> hw/pci/meson.build | 1 + >> hw/pci/pcie.c | 2 +- >> hw/pci/pcie_doe.c | 414 >> ++++++++++++++++++++++++++++++ >> include/hw/pci/pci_ids.h | 2 + >> include/hw/pci/pcie.h | 1 + >> include/hw/pci/pcie_doe.h | 166 ++++++++++++ >> include/hw/pci/pcie_regs.h | 4 + >> include/standard-headers/linux/pci_regs.h | 3 +- >> 9 files changed, 598 insertions(+), 2 deletions(-) >> create mode 100644 hw/pci/pcie_doe.c >> create mode 100644 include/hw/pci/pcie_doe.h >> >> diff --git a/MAINTAINERS b/MAINTAINERS >> index 981dc92..4fb865e 100644 >> --- a/MAINTAINERS >> +++ b/MAINTAINERS >> @@ -1655,6 +1655,13 @@ F: docs/pci* >> F: docs/specs/*pci* >> F: default-configs/pci.mak >> >> +PCIE DOE >> +M: Huai-Cheng Kuo <hch...@avery-design.com.tw> >> +M: Chris Browy <cbr...@avery-design.com> >> +S: Supported >> +F: include/hw/pci/pcie_doe.h >> +F: hw/pci/pcie_doe.c >> + >> ACPI/SMBIOS >> M: Michael S. Tsirkin <m...@redhat.com> >> M: Igor Mammedov <imamm...@redhat.com> >> diff --git a/hw/pci/meson.build b/hw/pci/meson.build >> index 5c4bbac..115e502 100644 >> --- a/hw/pci/meson.build >> +++ b/hw/pci/meson.build >> @@ -12,6 +12,7 @@ pci_ss.add(files( >> # allow plugging PCIe devices into PCI buses, include them even if >> # CONFIG_PCI_EXPRESS=n. >> pci_ss.add(files('pcie.c', 'pcie_aer.c')) >> +pci_ss.add(files('pcie_doe.c')) > > It looks like this should be like the below line: > softmmu_ss.add(when: 'CONFIG_PCI_EXPRESS', if_true: pci_doe.c)) > >> softmmu_ss.add(when: 'CONFIG_PCI_EXPRESS', if_true: files('pcie_port.c', >> 'pcie_host.c')) >> softmmu_ss.add_all(when: 'CONFIG_PCI', if_true: pci_ss) >> >> diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c >> index 1ecf6f6..f7516c4 100644 >> --- a/hw/pci/pcie.c >> +++ b/hw/pci/pcie.c >> @@ -735,7 +735,7 @@ void pcie_cap_slot_write_config(PCIDevice *dev, >> >> hotplug_event_notify(dev); >> >> - /* >> + /* > > Please drop this. > >> * 6.7.3.2 Command Completed Events >> * >> * Software issues a command to a hot-plug capable Downstream Port by >> diff --git a/hw/pci/pcie_doe.c b/hw/pci/pcie_doe.c >> new file mode 100644 >> index 0000000..df8e92e >> --- /dev/null >> +++ b/hw/pci/pcie_doe.c >> @@ -0,0 +1,414 @@ >> +#include "qemu/osdep.h" >> +#include "qemu/log.h" >> +#include "qemu/error-report.h" >> +#include "qapi/error.h" >> +#include "qemu/range.h" >> +#include "hw/pci/pci.h" >> +#include "hw/pci/pcie.h" >> +#include "hw/pci/pcie_doe.h" >> +#include "hw/pci/msi.h" >> +#include "hw/pci/msix.h" >> + >> +/* >> + * DOE Default Protocols (Discovery, CMA) >> + */ >> +/* Discovery Request Object */ >> +struct doe_discovery { >> + DOEHeader header; >> + uint8_t index; >> + uint8_t reserved[3]; >> +} QEMU_PACKED; >> + >> +/* Discovery Response Object */ >> +struct doe_discovery_rsp { >> + DOEHeader header; >> + uint16_t vendor_id; >> + uint8_t doe_type; >> + uint8_t next_index; >> +} QEMU_PACKED; >> + >> +/* Callback for Discovery */ >> +static bool pcie_doe_discovery_rsp(DOECap *doe_cap) >> +{ >> + PCIEDOE *doe = doe_cap->doe; >> + struct doe_discovery *req = pcie_doe_get_req(doe_cap); >> + uint8_t index = req->index; >> + DOEProtocol *prot = NULL; >> + >> + /* Request length mismatch, discard */ >> + if (req->header.length < dwsizeof(struct doe_discovery)) { > > Use DIV_ROUND_UP instead of rolling your own thing. > >> + return DOE_DISCARD; >> + } >> + >> + /* Point to the requested protocol */ >> + if (index < doe->protocol_num) { >> + prot = &doe->protocols[index]; >> + } > > What happens on else, should that still return DOE_SUCCESS? > >> + >> + struct doe_discovery_rsp rsp = { >> + .header = { >> + .vendor_id = PCI_VENDOR_ID_PCI_SIG, >> + .doe_type = PCI_SIG_DOE_DISCOVERY, >> + .reserved = 0x0, >> + .length = dwsizeof(struct doe_discovery_rsp), >> + }, > > mixed declarations are not allowed. > DIV_ROUND_UP > >> + .vendor_id = (prot) ? prot->vendor_id : 0xFFFF, >> + .doe_type = (prot) ? prot->doe_type : 0xFF, >> + .next_index = (index + 1) < doe->protocol_num ? >> + (index + 1) : 0, >> + }; > > I prefer: > next_index = (index + 1) % doe->protocol_num > >> + >> + pcie_doe_set_rsp(doe_cap, &rsp); >> + >> + return DOE_SUCCESS; >> +} >> + >> +/* Callback for CMA */ >> +static bool pcie_doe_cma_rsp(DOECap *doe_cap) >> +{ >> + doe_cap->status.error = 1; >> + >> + memset(doe_cap->read_mbox, 0, >> + PCI_DOE_MAX_DW_SIZE * sizeof(uint32_t)); >> + >> + doe_cap->write_mbox_len = 0; >> + >> + return DOE_DISCARD; >> +} >> + >> +/* >> + * DOE Utilities >> + */ >> +static void pcie_doe_reset_mbox(DOECap *st) >> +{ >> + st->read_mbox_idx = 0; >> + >> + st->read_mbox_len = 0; >> + st->write_mbox_len = 0; >> + >> + memset(st->read_mbox, 0, PCI_DOE_MAX_DW_SIZE * sizeof(uint32_t)); >> + memset(st->write_mbox, 0, PCI_DOE_MAX_DW_SIZE * sizeof(uint32_t)); >> +} >> + >> +/* >> + * Initialize the list and protocol for a device. >> + * This function won't add the DOE capabitity to your PCIe device. >> + */ >> +void pcie_doe_init(PCIDevice *dev, PCIEDOE *doe) >> +{ >> + doe->pdev = dev; >> + doe->head = NULL; >> + doe->protocol_num = 0; >> + >> + /* Register two default protocol */ >> + //TODO : LINK LIST > > Please do this for next rev of the patches. > >> + pcie_doe_register_protocol(doe, PCI_VENDOR_ID_PCI_SIG, >> + PCI_SIG_DOE_DISCOVERY, pcie_doe_discovery_rsp); >> + pcie_doe_register_protocol(doe, PCI_VENDOR_ID_PCI_SIG, >> + PCI_SIG_DOE_CMA, pcie_doe_cma_rsp); >> +} >> + >> +int pcie_cap_doe_add(PCIEDOE *doe, uint16_t offset, bool intr, uint16_t >> vec) { >> + DOECap *new_cap, **ptr; >> + PCIDevice *dev = doe->pdev; >> + >> + pcie_add_capability(dev, PCI_EXT_CAP_ID_DOE, PCI_DOE_VER, offset, >> + PCI_DOE_SIZEOF); >> + >> + ptr = &doe->head; >> + /* Insert the new DOE at the end of linked list */ >> + while (*ptr) { >> + if (range_covers_byte((*ptr)->offset, PCI_DOE_SIZEOF, offset) || >> + (*ptr)->cap.vec == vec) { >> + return -EINVAL; >> + } >> + >> + ptr = &(*ptr)->next; >> + } >> + new_cap = g_malloc0(sizeof(DOECap)); >> + *ptr = new_cap; >> + >> + new_cap->doe = doe; >> + new_cap->offset = offset; >> + new_cap->next = NULL; >> + >> + /* Configure MSI/MSI-X */ >> + if (intr && (msi_present(dev) || msix_present(dev))) { >> + new_cap->cap.intr = intr; >> + new_cap->cap.vec = vec; >> + } >> + >> + /* Set up W/R Mailbox buffer */ >> + new_cap->write_mbox = g_malloc0(PCI_DOE_MAX_DW_SIZE * sizeof(uint32_t)); >> + new_cap->read_mbox = g_malloc0(PCI_DOE_MAX_DW_SIZE * sizeof(uint32_t)); >> + >> + pcie_doe_reset_mbox(new_cap); >> + >> + return 0; >> +} >> + >> +void pcie_doe_uninit(PCIEDOE *doe) { > > fini is the more idiomatically unix name for de/un init. >> + PCIDevice *dev = doe->pdev; >> + DOECap *cap; >> + >> + pci_del_capability(dev, PCI_EXT_CAP_ID_DOE, PCI_DOE_SIZEOF); >> + >> + cap = doe->head; >> + while (cap) { >> + doe->head = doe->head->next; >> + >> + g_free(cap->read_mbox); >> + g_free(cap->write_mbox); >> + cap->read_mbox = NULL; >> + cap->write_mbox = NULL; >> + g_free(cap); >> + cap = doe->head; >> + } >> +} >> + >> +void pcie_doe_register_protocol(PCIEDOE *doe, uint16_t vendor_id, >> + uint8_t doe_type, bool (*set_rsp)(DOECap *)) >> +{ >> + /* Protocol num should not exceed 256 */ >> + assert(doe->protocol_num < PCI_DOE_PROTOCOL_MAX); >> + >> + doe->protocols[doe->protocol_num].vendor_id = vendor_id; >> + doe->protocols[doe->protocol_num].doe_type = doe_type; >> + doe->protocols[doe->protocol_num].set_rsp = set_rsp; >> + >> + doe->protocol_num++; >> +} >> + >> +uint32_t pcie_doe_build_protocol(DOEProtocol *p) >> +{ >> + return DATA_OBJ_BUILD_HEADER1(p->vendor_id, p->doe_type); >> +} >> + >> +/* Return the pointer of DOE request in write mailbox buffer */ >> +void *pcie_doe_get_req(DOECap *doe_cap) >> +{ >> + return doe_cap->write_mbox; >> +} >> + >> +/* Copy the response to read mailbox buffer */ >> +void pcie_doe_set_rsp(DOECap *doe_cap, void *rsp) >> +{ >> + uint32_t len = pcie_doe_object_len(rsp); >> + >> + memcpy(doe_cap->read_mbox + doe_cap->read_mbox_len, >> + rsp, len * sizeof(uint32_t)); >> + doe_cap->read_mbox_len += len; >> +} >> + >> +/* Get Data Object length */ >> +uint32_t pcie_doe_object_len(void *obj) >> +{ >> + return (obj)? ((DOEHeader *)obj)->length : 0; >> +} >> + >> +static void pcie_doe_write_mbox(DOECap *doe_cap, uint32_t val) >> +{ >> + memcpy(doe_cap->write_mbox + doe_cap->write_mbox_len, &val, >> sizeof(uint32_t)); > > doe_cap->write_mbox[doe_cap->write_mbox_len] = val? > >> + >> + if (doe_cap->write_mbox_len == 1) { >> + DOE_DBG(" Capture DOE request DO length = %d\n", val & 0x0003ffff); >> + } > > I don't have the spec in front of me, but this is begging for a comment on > why 1 > is special. > >> + >> + doe_cap->write_mbox_len++; >> +} >> + >> +static void pcie_doe_irq_assert(DOECap *doe_cap) >> +{ >> + PCIDevice *dev = doe_cap->doe->pdev; >> + >> + if (doe_cap->cap.intr && doe_cap->ctrl.intr) { >> + /* Interrupt notify */ >> + if (msix_enabled(dev)) { >> + msix_notify(dev, doe_cap->cap.vec); >> + } else if (msi_enabled(dev)) { >> + msi_notify(dev, doe_cap->cap.vec); >> + } >> + /* Not support legacy IRQ */ >> + } >> +} >> + >> +static void pcie_doe_set_ready(DOECap *doe_cap, bool rdy) >> +{ >> + doe_cap->status.ready = rdy; >> + >> + if (rdy) { >> + pcie_doe_irq_assert(doe_cap); >> + } >> +} >> + >> +static void pcie_doe_set_error(DOECap *doe_cap, bool err) >> +{ >> + doe_cap->status.error = err; >> + >> + if (err) { >> + pcie_doe_irq_assert(doe_cap); >> + } >> +} >> + >> +DOECap *pcie_doe_covers_addr(PCIEDOE *doe, uint32_t addr) >> +{ >> + DOECap *ptr = doe->head; >> + >> + /* If overlaps DOE range. PCIe Capability Header won't be included. */ >> + while (ptr && >> + !range_covers_byte(ptr->offset + PCI_EXP_DOE_CAP, PCI_DOE_SIZEOF >> - 4, addr)) { >> + ptr = ptr->next; >> + } >> + >> + return ptr; >> +} >> + >> +uint32_t pcie_doe_read_config(DOECap *doe_cap, >> + uint32_t addr, int size) >> +{ >> + uint32_t ret = 0, shift, mask = 0xFFFFFFFF; >> + uint16_t doe_offset = doe_cap->offset; >> + >> + /* If overlaps DOE range. PCIe Capability Header won't be included. */ >> + if (range_covers_byte(doe_offset + PCI_EXP_DOE_CAP, PCI_DOE_SIZEOF - 4, >> addr)) { >> + addr -= doe_offset; >> + >> + if (range_covers_byte(PCI_EXP_DOE_CAP, sizeof(uint32_t), addr)) { >> + ret = FIELD_DP32(ret, PCI_DOE_CAP_REG, INTR_SUPP, >> + doe_cap->cap.intr); >> + ret = FIELD_DP32(ret, PCI_DOE_CAP_REG, DOE_INTR_MSG_NUM, >> + doe_cap->cap.vec); >> + } else if (range_covers_byte(PCI_EXP_DOE_CTRL, sizeof(uint32_t), >> addr)) { >> + /* Must return ABORT=0 and GO=0 */ >> + ret = FIELD_DP32(ret, PCI_DOE_CAP_CONTROL, DOE_INTR_EN, >> + doe_cap->ctrl.intr); >> + DOE_DBG(" CONTROL REG=%x\n", ret); >> + } else if (range_covers_byte(PCI_EXP_DOE_STATUS, sizeof(uint32_t), >> addr)) { >> + ret = FIELD_DP32(ret, PCI_DOE_CAP_STATUS, DOE_BUSY, >> + doe_cap->status.busy); >> + ret = FIELD_DP32(ret, PCI_DOE_CAP_STATUS, DOE_INTR_STATUS, >> + doe_cap->status.intr); >> + ret = FIELD_DP32(ret, PCI_DOE_CAP_STATUS, DOE_ERROR, >> + doe_cap->status.error); >> + ret = FIELD_DP32(ret, PCI_DOE_CAP_STATUS, DATA_OBJ_RDY, >> + doe_cap->status.ready); >> + } else if (range_covers_byte(PCI_EXP_DOE_RD_DATA_MBOX, >> sizeof(uint32_t), addr)) { >> + /* Check that READY is set */ >> + if (!doe_cap->status.ready) { >> + /* Return 0 if not ready */ >> + DOE_DBG(" RD MBOX RETURN=%x\n", ret); >> + } else { >> + /* Deposit next DO DW into read mbox */ >> + DOE_DBG(" RD MBOX, DATA OBJECT READY," >> + " CURRENT DO DW OFFSET=%x\n", >> + doe_cap->read_mbox_idx); >> + >> + ret = doe_cap->read_mbox[doe_cap->read_mbox_idx]; >> + >> + DOE_DBG(" RD MBOX DW=%x\n", ret); >> + DOE_DBG(" RD MBOX DW OFFSET=%d, RD MBOX LENGTH=%d\n", >> + doe_cap->read_mbox_idx, doe_cap->read_mbox_len); >> + } >> + } else if (range_covers_byte(PCI_EXP_DOE_WR_DATA_MBOX, >> sizeof(uint32_t), addr)) { >> + DOE_DBG(" WR MBOX, local_val =%x\n", ret); >> + } >> + } >> + >> + /* Alignment */ >> + shift = addr % sizeof(uint32_t); > > Can these actually be unaligned? The whole range_covers_byte() stuff could go > away if not. > >> + if (shift) { >> + ret >>= shift * 8; >> + } >> + mask >>= (sizeof(uint32_t) - size) * 8; >> + >> + return ret & mask; >> +} >> + >> +void pcie_doe_write_config(DOECap *doe_cap, >> + uint32_t addr, uint32_t val, int size) >> +{ >> + PCIEDOE *doe = doe_cap->doe; >> + uint16_t doe_offset = doe_cap->offset; >> + int p; >> + bool discard; >> + uint32_t shift; >> + >> + DOE_DBG(" addr=%x, val=%x, size=%x\n", addr, val, size); >> + >> + /* If overlaps DOE range. PCIe Capability Header won't be included. */ >> + if (range_covers_byte(doe_offset + PCI_EXP_DOE_CAP, PCI_DOE_SIZEOF - 4, >> addr)) { >> + /* Alignment */ >> + shift = addr % sizeof(uint32_t); >> + addr -= (doe_offset - shift); >> + val <<= shift * 8; >> + >> + switch (addr) { >> + case PCI_EXP_DOE_CTRL: >> + DOE_DBG(" CONTROL=%x\n", val); >> + if (FIELD_EX32(val, PCI_DOE_CAP_CONTROL, DOE_ABORT)) { >> + /* If ABORT, clear status reg DOE Error and DOE Ready */ >> + DOE_DBG(" Setting ABORT\n"); >> + pcie_doe_set_ready(doe_cap, 0); >> + pcie_doe_set_error(doe_cap, 0); >> + pcie_doe_reset_mbox(doe_cap); >> + } else if (FIELD_EX32(val, PCI_DOE_CAP_CONTROL, DOE_GO)) { >> + DOE_DBG(" CONTROL GO=%x\n", val); >> + /* >> + * Check protocol the incoming request in write_mbox and >> + * memcpy the corresponding response to read_mbox. >> + * >> + * "discard" should be set up if the response callback >> + * function could not deal with request (e.g. length >> + * mismatch) or the protocol of request was not found. >> + */ >> + discard = DOE_DISCARD; >> + for (p = 0; p < doe->protocol_num; p++) { >> + if (doe_cap->write_mbox[0] == >> + pcie_doe_build_protocol(&doe->protocols[p])) { >> + /* Found */ >> + DOE_DBG(" DOE PROTOCOL=%x\n", >> doe_cap->write_mbox[0]); >> + /* >> + * Spec: >> + * If the number of DW transferred does not match >> the >> + * indicated Length for a data object, then the >> + * data object must be silently discarded. >> + */ >> + if (doe_cap->write_mbox_len == >> + pcie_doe_object_len(pcie_doe_get_req(doe_cap))) >> + discard = doe->protocols[p].set_rsp(doe_cap); >> + break; >> + } >> + } >> + >> + /* Set DOE Ready */ >> + if (!discard) { >> + pcie_doe_set_ready(doe_cap, 1); >> + } else { >> + pcie_doe_reset_mbox(doe_cap); >> + } >> + } else if (FIELD_EX32(val, PCI_DOE_CAP_CONTROL, DOE_INTR_EN)) { >> + doe_cap->ctrl.intr = 1; >> + } >> + break; >> + case PCI_EXP_DOE_RD_DATA_MBOX: >> + /* Read MBOX */ >> + DOE_DBG(" INCR RD MBOX DO DW OFFSET=%d\n", >> doe_cap->read_mbox_idx); >> + doe_cap->read_mbox_idx += 1; >> + /* Last DW */ >> + if (doe_cap->read_mbox_idx >= doe_cap->read_mbox_len) { >> + pcie_doe_reset_mbox(doe_cap); >> + pcie_doe_set_ready(doe_cap, 0); >> + } >> + break; >> + case PCI_EXP_DOE_WR_DATA_MBOX: >> + /* Write MBOX */ >> + DOE_DBG(" WR MBOX=%x, DW OFFSET = %d\n", val, >> doe_cap->write_mbox_len); >> + pcie_doe_write_mbox(doe_cap, val); >> + break; >> + case PCI_EXP_DOE_STATUS: >> + case PCI_EXP_DOE_CAP: >> + default: >> + break; >> + } >> + } >> +} >> diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h >> index 76bf3ed..636b2e8 100644 >> --- a/include/hw/pci/pci_ids.h >> +++ b/include/hw/pci/pci_ids.h >> @@ -157,6 +157,8 @@ >> >> /* Vendors and devices. Sort key: vendor first, device next. */ >> >> +#define PCI_VENDOR_ID_PCI_SIG 0x0001 >> + >> #define PCI_VENDOR_ID_LSI_LOGIC 0x1000 >> #define PCI_DEVICE_ID_LSI_53C810 0x0001 >> #define PCI_DEVICE_ID_LSI_53C895A 0x0012 >> diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h >> index 14c58eb..47d6f66 100644 >> --- a/include/hw/pci/pcie.h >> +++ b/include/hw/pci/pcie.h >> @@ -25,6 +25,7 @@ >> #include "hw/pci/pcie_regs.h" >> #include "hw/pci/pcie_aer.h" >> #include "hw/hotplug.h" >> +#include "hw/pci/pcie_doe.h" >> >> typedef enum { >> /* for attention and power indicator */ >> diff --git a/include/hw/pci/pcie_doe.h b/include/hw/pci/pcie_doe.h >> new file mode 100644 >> index 0000000..f497075 >> --- /dev/null >> +++ b/include/hw/pci/pcie_doe.h >> @@ -0,0 +1,166 @@ >> +#ifndef PCIE_DOE_H >> +#define PCIE_DOE_H >> + >> +#include "qemu/range.h" >> +#include "qemu/typedefs.h" >> +#include "hw/register.h" >> + >> +/* >> + * PCI DOE register defines 7.9.xx >> + */ > > Whitespace issues > >> +/* DOE Capabilities Register */ >> +#define PCI_EXP_DOE_CAP 0x04 >> +REG32(PCI_DOE_CAP_REG, 0) >> + FIELD(PCI_DOE_CAP_REG, INTR_SUPP, 0, 1) >> + FIELD(PCI_DOE_CAP_REG, DOE_INTR_MSG_NUM, 1, 11) >> + >> +/* DOE Control Register */ >> +#define PCI_EXP_DOE_CTRL 0x08 >> +REG32(PCI_DOE_CAP_CONTROL, 0) >> + FIELD(PCI_DOE_CAP_CONTROL, DOE_ABORT, 0, 1) >> + FIELD(PCI_DOE_CAP_CONTROL, DOE_INTR_EN, 1, 1) >> + FIELD(PCI_DOE_CAP_CONTROL, DOE_GO, 31, 1) >> + >> +/* DOE Status Register */ >> +#define PCI_EXP_DOE_STATUS 0x0c >> +REG32(PCI_DOE_CAP_STATUS, 0) >> + FIELD(PCI_DOE_CAP_STATUS, DOE_BUSY, 0, 1) >> + FIELD(PCI_DOE_CAP_STATUS, DOE_INTR_STATUS, 1, 1) >> + FIELD(PCI_DOE_CAP_STATUS, DOE_ERROR, 2, 1) >> + FIELD(PCI_DOE_CAP_STATUS, DATA_OBJ_RDY, 31, 1) >> + >> +/* DOE Write Data Mailbox Register */ >> +#define PCI_EXP_DOE_WR_DATA_MBOX 0x10 >> + >> +/* DOE Read Data Mailbox Register */ >> +#define PCI_EXP_DOE_RD_DATA_MBOX 0x14 >> + >> +/* >> + * PCI DOE register defines 7.9.xx >> + */ > > Is this duplicated on purpose? > >> +/* Table 7-x2 */ >> +#define PCI_SIG_DOE_DISCOVERY 0x00 >> +#define PCI_SIG_DOE_CMA 0x01 >> + >> +#define DATA_OBJ_BUILD_HEADER1(v, p) ((p << 16) | v) >> + >> +/* Figure 6-x1 */ >> +#define DATA_OBJECT_HEADER1_OFFSET 0 >> +#define DATA_OBJECT_HEADER2_OFFSET 1 >> +#define DATA_OBJECT_CONTENT_OFFSET 2 >> + >> +#define PCI_DOE_MAX_DW_SIZE (1 << 18) >> +#define PCI_DOE_PROTOCOL_MAX 256 >> + >> +/* >> + * Self-defined Marco >> + */ >> +/* Request/Response State */ >> +#define DOE_SUCCESS 0 >> +#define DOE_DISCARD 1 >> + >> +/* An invalid vector number for MSI/MSI-x */ >> +#define DOE_NO_INTR (~0) >> + >> +/* >> + * DOE Protocol - Data Object >> + */ >> +typedef struct DOEHeader DOEHeader; >> +typedef struct DOEProtocol DOEProtocol; >> +typedef struct PCIEDOE PCIEDOE; >> +typedef struct DOECap DOECap; >> + >> +struct DOEHeader { >> + uint16_t vendor_id; >> + uint8_t doe_type; >> + uint8_t reserved; >> + struct { >> + uint32_t length:18; >> + uint32_t reserved2:14; >> + }; >> +} QEMU_PACKED; >> + >> +/* Protocol infos and rsp function callback */ >> +struct DOEProtocol { >> + uint16_t vendor_id; >> + uint8_t doe_type; >> + >> + bool (*set_rsp)(DOECap *); >> +}; >> + >> +struct PCIEDOE { >> + PCIDevice *pdev; >> + DOECap *head; >> + >> + /* Protocols and its callback response */ >> + DOEProtocol protocols[PCI_DOE_PROTOCOL_MAX]; >> + uint32_t protocol_num; >> +}; >> + >> +struct DOECap { >> + PCIEDOE *doe; >> + >> + /* Capability offset */ >> + uint16_t offset; >> + >> + /* Next DOE capability */ >> + DOECap *next; >> + >> + /* Capability */ >> + struct { >> + bool intr; >> + uint16_t vec; >> + } cap; >> + >> + /* Control */ >> + struct { >> + bool abort; >> + bool intr; >> + bool go; >> + } ctrl; >> + >> + /* Status */ >> + struct { >> + bool busy; >> + bool intr; >> + bool error; >> + bool ready; >> + } status; >> + >> + /* Mailbox buffer for device */ >> + uint32_t *write_mbox; >> + uint32_t *read_mbox; >> + >> + /* Mailbox position indicator */ >> + uint32_t read_mbox_idx; >> + uint32_t read_mbox_len; >> + uint32_t write_mbox_len; >> +}; >> + >> +void pcie_doe_init(PCIDevice *dev, PCIEDOE *doe); >> +int pcie_cap_doe_add(PCIEDOE *doe, uint16_t offset, bool intr, uint16_t >> vec); >> +void pcie_doe_uninit(PCIEDOE *doe); >> +void pcie_doe_register_protocol(PCIEDOE *doe, uint16_t vendor_id, >> + uint8_t doe_type, >> + bool (*set_rsp)(DOECap *)); >> +uint32_t pcie_doe_build_protocol(DOEProtocol *p); >> +DOECap *pcie_doe_covers_addr(PCIEDOE *doe, uint32_t addr); >> +uint32_t pcie_doe_read_config(DOECap *doe_cap, uint32_t addr, int size); >> +void pcie_doe_write_config(DOECap *doe_cap, uint32_t addr, >> + uint32_t val, int size); >> + >> +/* Utility functions for set_rsp in DOEProtocol */ >> +void *pcie_doe_get_req(DOECap *doe_cap); >> +void pcie_doe_set_rsp(DOECap *doe_cap, void *rsp); >> +uint32_t pcie_doe_object_len(void *obj); >> + >> +#define DOE_DEBUG >> +#ifdef DOE_DEBUG >> +#define DOE_DBG(...) printf(__VA_ARGS__) >> +#else >> +#define DOE_DBG(...) {} >> +#endif >> + >> +#define dwsizeof(s) ((sizeof(s) + 4 - 1) / 4) >> + >> +#endif /* PCIE_DOE_H */ >> diff --git a/include/hw/pci/pcie_regs.h b/include/hw/pci/pcie_regs.h >> index 1db86b0..963dc2e 100644 >> --- a/include/hw/pci/pcie_regs.h >> +++ b/include/hw/pci/pcie_regs.h >> @@ -179,4 +179,8 @@ typedef enum PCIExpLinkWidth { >> #define PCI_ACS_VER 0x1 >> #define PCI_ACS_SIZEOF 8 >>> +/* DOE Capability Register Fields */ >> +#define PCI_DOE_VER 0x1 >> +#define PCI_DOE_SIZEOF 24 >> + >> #endif /* QEMU_PCIE_REGS_H */ >> diff --git a/include/standard-headers/linux/pci_regs.h >> b/include/standard-headers/linux/pci_regs.h >> index e709ae8..4a7b7a4 100644 >> --- a/include/standard-headers/linux/pci_regs.h >> +++ b/include/standard-headers/linux/pci_regs.h >> @@ -730,7 +730,8 @@ >> #define PCI_EXT_CAP_ID_DVSEC 0x23 /* Designated Vendor-Specific */ >> #define PCI_EXT_CAP_ID_DLF 0x25 /* Data Link Feature */ >> #define PCI_EXT_CAP_ID_PL_16GT 0x26 /* Physical Layer 16.0 GT/s */ >> -#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PL_16GT >> +#define PCI_EXT_CAP_ID_DOE 0x2E /* Data Object Exchange */ >> +#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_DOE >> >> #define PCI_EXT_CAP_DSN_SIZEOF 12 >> #define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40 > > I haven't reviewed the spec stuff, but I assume Jonathan is familiar with that > and probably knows it almost by heart already. > >> -- >> 1.8.3.1 >> >>