From 1fe865d1418a026e1a0bafa264b91416f7ae97da Mon Sep 17 00:00:00 2001 From: Matheus Date: Tue, 10 Jan 2023 02:15:41 -0300 Subject: [PATCH] pci: MSI-X support --- src/arch/x86_64/include/arch/pci.h | 25 ++++++- src/arch/x86_64/pci.c | 115 ++++++++++++++++++++++++----- 2 files changed, 122 insertions(+), 18 deletions(-) diff --git a/src/arch/x86_64/include/arch/pci.h b/src/arch/x86_64/include/arch/pci.h index 7952812f..9c708d6a 100644 --- a/src/arch/x86_64/include/arch/pci.h +++ b/src/arch/x86_64/include/arch/pci.h @@ -43,12 +43,30 @@ typedef struct{ uint8_t maxgrant; } __attribute__((packed)) pci_deviceheader; +typedef struct{ + uint32_t mlow; + uint32_t mhi; + uint32_t data; + uint32_t ctrl; +} __attribute__((packed)) msixmsg_t; + typedef struct _pci_enumeration{ struct pci_enumeration* next; uint8_t bus; uint8_t device; uint8_t function; pci_common* header; + union{ + struct{ + int offset; + } msi; + struct{ + int offset; + msixmsg_t* table; + int entrycount; + } msix; + } + } pci_enumeration; #define PCI_TYPE_MEM 1 @@ -85,11 +103,16 @@ static inline void* getbarmemaddr(pci_deviceheader* e, int bar){ #define PCI_COMMAND_IO 1 #define PCI_COMMAND_MEMORY 2 #define PCI_COMMAND_MASTER 4 +#define PCI_COMMAND_INTDISABLE 1024 bool pci_msisupport(pci_enumeration* e); -void pci_msienable(pci_enumeration* e, bool enable); +void pci_msienable(pci_enumeration* e); +bool pci_msixsupport(pci_enumeration* e); +void pci_msixenable(pci_enumeration* e); void pci_msimask(pci_enumeration* e, int which, int val); void pci_msimaskall(pci_enumeration* e, int val); +void pci_msiadd(pci_enumeration* e, int cpu, int vec, bool edgetrigger, bool deassert); +void pci_msixadd(pci_enumeration* e, int msixvec, int cpu, int vec, bool edgetrigger, bool deassert); void pci_setcommand(pci_enumeration* e, int which, int val); pci_enumeration* pci_getdevicecs(int class, int subclass, int n); diff --git a/src/arch/x86_64/pci.c b/src/arch/x86_64/pci.c index f4be4551..d29f7dd8 100644 --- a/src/arch/x86_64/pci.c +++ b/src/arch/x86_64/pci.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include pci_enumeration* enumerations; @@ -11,6 +13,7 @@ pci_enumeration* enumerations; #define COMMAND_REG 1 #define CAP_MSI 5 +#define CAP_MSIX 0x11 pci_enumeration* pci_getdevicecs(int class, int subclass, int n){ @@ -179,6 +182,13 @@ static size_t legacy_getcapabilityoffset(size_t id, pci_enumeration* enumeration } +bool pci_msixsupport(pci_enumeration* e){ + if(!legacy_getcapabilityoffset(CAP_MSIX, e)) + return false; + + return true; +} + bool pci_msisupport(pci_enumeration* e){ if(!legacy_getcapabilityoffset(CAP_MSI, e)) return false; @@ -186,36 +196,72 @@ bool pci_msisupport(pci_enumeration* e){ return true; } -void pci_msienable(pci_enumeration* e, bool enable){ +void pci_msixenable(pci_enumeration* e){ + int offset = legacy_getcapabilityoffset(CAP_MSIX, e); + + __assert(offset); + + e->msix.offset = offset; + + uint32_t currval = legacy_readdata(e->bus, e->device, e->function, offset); + + currval |= 1 << 31; // enable MSIX + + e->msix.entrycount = currval >> 16; + e->msix.entrycount &= 0x7FF; + ++e->msix.entrycount; + + legacy_writedata(e->bus, e->device, e->function, offset, currval); + + uint32_t biroffset = legacy_readdata(e->bus, e->device, e->function, offset+1); + + e->msix.table = getbarmemaddr((void*)e->header, biroffset & 0x7); + + __assert(e->msix.table); + + e->msix.table = (void*)((uintptr_t)e->msix.table + (biroffset & (~0x7))); + + size_t pagec = e->msix.entrycount*sizeof(msixmsg_t)/PAGE_SIZE+1; + + void* vaddr = vmm_alloc(pagec, ARCH_MMU_MAP_READ | ARCH_MMU_MAP_WRITE); + + __assert(vaddr); + + __assert(vmm_map(e->msix.table, vaddr, pagec, ARCH_MMU_MAP_READ | ARCH_MMU_MAP_WRITE)); + + e->msix.table = vaddr; + + pci_setcommand(e, PCI_COMMAND_INTDISABLE, 1); + +} + +void pci_msienable(pci_enumeration* e){ int offset = legacy_getcapabilityoffset(CAP_MSI, e); + + __assert(offset); - if(!offset) - return; + e->msi.offset = offset; uint32_t currval = legacy_readdata(e->bus, e->device, e->function, offset); if((currval & 1 << 23) == 0) - _panic("32 bit MSI not supported!"); + _panic("32 bit MSI not supported!", NULL); - if(enable){ - currval |= 1 << 16; - } - else{ - currval &= ~(1 << 16); - } + currval |= 1 << 16; legacy_writedata(e->bus, e->device, e->function, offset, currval); + + pci_setcommand(e, PCI_COMMAND_INTDISABLE, 1); } void pci_msimask(pci_enumeration* e, int which, int val){ int offset = legacy_getcapabilityoffset(CAP_MSI, e); - if(!offset) - return; + __assert(offset); - offset += 2; + offset += 3; uint32_t currval = legacy_readdata(e->bus, e->device, e->function, offset); @@ -234,10 +280,9 @@ void pci_msimaskall(pci_enumeration* e, int val){ int offset = legacy_getcapabilityoffset(CAP_MSI, e); - if(!offset) - return; - - offset += 2; + __assert(offset); + + offset += 3; uint32_t currval = legacy_readdata(e->bus, e->device, e->function, offset); @@ -252,6 +297,41 @@ void pci_msimaskall(pci_enumeration* e, int val){ } +void pci_msiadd(pci_enumeration* e, int cpu, int vec, bool edgetrigger, bool deassert){ + + int offset = legacy_getcapabilityoffset(CAP_MSI, e); + + __assert(offset); + + uint64_t data; + + uint64_t maddr = pci_msi_build(&data, vec, cpu, edgetrigger, deassert); + + legacy_writedata(e->bus, e->device, e->function, offset + 1, maddr); + legacy_writedata(e->bus, e->device, e->function, offset + 2, 0); + legacy_writedata(e->bus, e->device, e->function, offset + 3, data); + + +} + +void pci_msixadd(pci_enumeration* e, int msixvec, int cpu, int vec, bool edgetrigger, bool deassert){ + + int offset = legacy_getcapabilityoffset(CAP_MSIX, e); + + __assert(offset); + + uint64_t data; + uint64_t addr = pci_msi_build(&data, vec, cpu, edgetrigger, deassert); + + __assert(msixvec < e->msix.entrycount); + + e->msix.table[msixvec].mlow = addr & 0xFFFFFFFF; + e->msix.table[msixvec].mhi = (addr >> 32) & 0xFFFFFFFF; + e->msix.table[msixvec].data = data; + e->msix.table[msixvec].ctrl = 0; + +} + static void legacy_enumeratedevice(int bus, int device){ // if the device is multifunction, scan and enumerate all 8. else, only one @@ -293,6 +373,7 @@ static void legacy_enumeration(){ } + uint64_t pci_msi_build(uint64_t* data, uint8_t vector, uint8_t processor, uint8_t edgetrigger, uint8_t deassert){ *data = vector | (edgetrigger << 15) | (deassert << 14); return (0xFEE00000 | (processor << 12));