qemu epc add misx support
Signed-off-by: lipengfei28 <lipengfei28@xiaomi.com>
This commit is contained in:
parent
57d736b149
commit
c552d39d41
2 changed files with 129 additions and 4 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/pci/pci.h>
|
||||
#include <nuttx/pci/pci_epc.h>
|
||||
#include <nuttx/pci/pci_epf.h>
|
||||
|
||||
#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;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue