mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
pci: MSI-X support
This commit is contained in:
@@ -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
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user