pci: MSI-X support

This commit is contained in:
Matheus
2023-01-10 02:15:41 -03:00
parent 85b65fd118
commit 1fe865d141
2 changed files with 122 additions and 18 deletions
+24 -1
View File
@@ -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);
+98 -17
View File
@@ -3,6 +3,8 @@
#include <arch/io.h>
#include <kernel/alloc.h>
#include <stdio.h>
#include <assert.h>
#include <kernel/vmm.h>
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));