From c552d39d41a2ca0584f0c9a98039a72ebf994e7f Mon Sep 17 00:00:00 2001 From: lipengfei28 Date: Mon, 29 Jul 2024 16:31:38 +0800 Subject: [PATCH] qemu epc add misx support Signed-off-by: lipengfei28 --- drivers/pci/pci_epf_test.c | 3 +- drivers/pci/pci_qemu_epc.c | 130 ++++++++++++++++++++++++++++++++++++- 2 files changed, 129 insertions(+), 4 deletions(-) diff --git a/drivers/pci/pci_epf_test.c b/drivers/pci/pci_epf_test.c index 60f23c9779c..1ffad352540 100644 --- a/drivers/pci/pci_epf_test.c +++ b/drivers/pci/pci_epf_test.c @@ -675,7 +675,7 @@ static int pci_epf_test_probe(FAR struct pci_epf_device_s *epf) test->header.deviceid = 0xb500; test->header.baseclass_code = PCI_CLASS_OTHERS; test->header.interrupt_pin = PCI_INTERRUPT_INTA; - test->bar_size[0] = 512; + test->bar_size[0] = 1024; test->bar_size[1] = 512; test->bar_size[2] = 1024; test->bar_size[3] = 16384; @@ -717,6 +717,7 @@ int pci_register_epf_test_device(FAR const char *epc_name) epf->name = "pci_epf_test"; epf->epc_name = epc_name; epf->msi_interrupts = 1; + epf->msix_interrupts = 32; nxmutex_init(&epf->lock); ret = pci_epf_device_register(epf); if (ret < 0) diff --git a/drivers/pci/pci_qemu_epc.c b/drivers/pci/pci_qemu_epc.c index 376138e1989..13865a75b3b 100644 --- a/drivers/pci/pci_qemu_epc.c +++ b/drivers/pci/pci_qemu_epc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "pci_drivers.h" @@ -63,6 +64,7 @@ #define QEMU_EPC_BAR_CFG_OFF_SIZE 0x10 #define QEMU_EPC_BAR_CFG_SIZE 0x18 #define QEMU_EPC_BAR_CFG_MSI 0x40 +#define QEMU_EPC_BAR_CFG_MSIX 0x60 /**************************************************************************** * Private Types @@ -78,6 +80,9 @@ struct qemu_epc_s FAR void *msi_vaddr; uintptr_t msi_paddr; uint32_t msi_data; + FAR void *msix_vaddr; + FAR void *msix_vob; + uintptr_t msix_pob; uint64_t ob_phys[32]; }; @@ -109,6 +114,10 @@ qemu_epc_get_features(FAR struct pci_epc_ctrl_s *epc, uint8_t funcno); static int qemu_epc_set_msi(FAR struct pci_epc_ctrl_s *epc, uint8_t funcno, uint8_t interrupts); static int qemu_epc_get_msi(FAR struct pci_epc_ctrl_s *epc, uint8_t funcno); +static int qemu_epc_get_msix(FAR struct pci_epc_ctrl_s *epc, uint8_t funcno); +static int +qemu_epc_set_msix(FAR struct pci_epc_ctrl_s *epc, uint8_t funcno, + uint16_t interrupts, int barno, uint32_t offset); /**************************************************************************** * Private Data @@ -131,7 +140,7 @@ static const struct pci_epc_features_s g_qemu_epc_features = .linkup_notifier = false, .core_init_notifier = false, .msi_capable = true, - .msix_capable = false, + .msix_capable = true, }; static const struct pci_epc_ops_s g_qemu_epc_ops = @@ -146,6 +155,8 @@ static const struct pci_epc_ops_s g_qemu_epc_ops = .get_features = qemu_epc_get_features, .set_msi = qemu_epc_set_msi, .get_msi = qemu_epc_get_msi, + .set_msix = qemu_epc_set_msix, + .get_msix = qemu_epc_get_msix, }; /**************************************************************************** @@ -227,6 +238,12 @@ static void qemu_epc_cfg_write16(FAR struct qemu_epc_s *qep, pci_write_mmio_word(qep->pdev, qep->cfg_base + offset, value); } +static void qemu_epc_cfg_write32(FAR struct qemu_epc_s *qep, + unsigned offset, uint32_t value) +{ + pci_write_mmio_dword(qep->pdev, qep->cfg_base + offset, value); +} + static uint8_t qemu_epc_bar_cfg_read8(FAR struct qemu_epc_s *qep, unsigned offset) { @@ -416,6 +433,23 @@ qemu_epc_unmap_addr(FAR struct pci_epc_ctrl_s *epc, uint8_t funcno, } } +FAR void * +qemu_epc_get_bar_addr_from_funcno(FAR struct pci_epc_ctrl_s *epc, + uint8_t funcno, uint8_t bar) +{ + FAR struct pci_epf_device_s *epf; + + list_for_every_entry(&epc->epf, epf, struct pci_epf_device_s, epc_node) + { + if (epf->funcno == funcno) + { + return epf->bar[bar].addr; + } + } + + return NULL; +} + /**************************************************************************** * Name: qemu_epc_raise_irq * @@ -438,6 +472,8 @@ qemu_epc_raise_irq(FAR struct pci_epc_ctrl_s *epc, uint8_t funcno, { FAR struct qemu_epc_s *qep = epc->priv; uint64_t pci_addr; + uint32_t offset; + uint32_t data; switch (type) { @@ -488,10 +524,34 @@ qemu_epc_raise_irq(FAR struct pci_epc_ctrl_s *epc, uint8_t funcno, pci_write_mmio_qword(qep->pdev, qep->msi_vaddr, qep->msi_data); return 0; case PCI_EPC_IRQ_MSIX: + if (--interrupt_num > qemu_epc_get_msix(epc, funcno)) + { + return -EINVAL; + } - /* Not support yet */ + data = qemu_epc_cfg_read32(qep, + QEMU_EPC_BAR_CFG_MSIX + + PCI_MSIX_TABLE); + offset = data & PCI_MSIX_TABLE_OFFSET; + if (qep->msix_vaddr == NULL) + { + uint8_t bar = data & PCI_MSIX_TABLE_BIR; + qep->msix_vaddr = + qemu_epc_get_bar_addr_from_funcno(epc, funcno, bar); + qep->msix_vob = + pci_epc_mem_alloc_addr(epc, &qep->msix_pob, 0x1000); + pci_read_mmio_qword(qep->pdev, qep->msix_vaddr + offset, + &pci_addr); + qemu_epc_map_addr(epc, funcno, qep->msix_pob, + pci_addr, 0x1000); + } - return -ENOTSUP; + pci_read_mmio_dword(qep->pdev, + qep->msix_vaddr + offset + + interrupt_num * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_DATA, &data); + pci_write_mmio_qword(qep->pdev, qep->msix_vob, data); + return 0; default: pcierr("Failed to raise IRQ, unknown type\n"); return -EINVAL; @@ -593,6 +653,70 @@ static int qemu_epc_set_msi(FAR struct pci_epc_ctrl_s *epc, uint8_t funcno, return 0; } +/**************************************************************************** + * Name: qemu_epc_get_msix + * + * Description: + * This function is used to get number of the supported msix. + * + * Input Parameters: + * epc - Device name of the endpoint controller + * funcno - The epc's function number + * + * Returned Value: + * Return the number of interrupts + ****************************************************************************/ + +static int qemu_epc_get_msix(FAR struct pci_epc_ctrl_s *epc, uint8_t funcno) +{ + FAR struct qemu_epc_s *qep = epc->priv; + uint16_t flags; + + flags = qemu_epc_cfg_read16(qep, QEMU_EPC_BAR_CFG_MSIX + PCI_MSIX_FLAGS); + if ((flags & PCI_MSIX_FLAGS_ENABLE) == 0) + { + return -EINVAL; + } + + return flags & PCI_MSIX_FLAGS_QSIZE; +} + +/**************************************************************************** + * Name: qemu_epc_set_msix + * + * Description: + * This function is used to set Epc msix interrupt number. + * + * Input Parameters: + * epc - Device name of the endpoint controller + * funcno - The epc's function number + * interrupts - The interrupts number + * barno - BAR where the MSI-X table resides + * offset - Offset pointing to the start of MSI-X table + * + * Returned Value: + * Return 0 + ****************************************************************************/ + +static int qemu_epc_set_msix(FAR struct pci_epc_ctrl_s *epc, uint8_t funcno, + uint16_t interrupts, int barno, uint32_t offset) +{ + FAR struct qemu_epc_s *qep = epc->priv; + uint32_t data; + uint16_t flags; + + flags = qemu_epc_cfg_read16(qep, QEMU_EPC_BAR_CFG_MSIX + PCI_MSIX_FLAGS); + flags &= ~PCI_MSIX_FLAGS_QSIZE; + flags |= interrupts; + qemu_epc_cfg_write16(qep, QEMU_EPC_BAR_CFG_MSIX + PCI_MSIX_FLAGS, flags); + data = offset | barno; + qemu_epc_cfg_write32(qep, QEMU_EPC_BAR_CFG_MSIX + PCI_MSIX_TABLE, data); + data = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | barno; + qemu_epc_cfg_write32(qep, QEMU_EPC_BAR_CFG_MSIX + PCI_MSIX_PBA, data); + + return 0; +} + static int qemu_epc_probe(FAR struct pci_device_s *dev) { FAR struct pci_epc_ctrl_s *epc;