mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 23:18:21 +00:00
pci: MSI-X support
This commit is contained in:
@@ -43,12 +43,30 @@ typedef struct{
|
|||||||
uint8_t maxgrant;
|
uint8_t maxgrant;
|
||||||
} __attribute__((packed)) pci_deviceheader;
|
} __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{
|
typedef struct _pci_enumeration{
|
||||||
struct pci_enumeration* next;
|
struct pci_enumeration* next;
|
||||||
uint8_t bus;
|
uint8_t bus;
|
||||||
uint8_t device;
|
uint8_t device;
|
||||||
uint8_t function;
|
uint8_t function;
|
||||||
pci_common* header;
|
pci_common* header;
|
||||||
|
union{
|
||||||
|
struct{
|
||||||
|
int offset;
|
||||||
|
} msi;
|
||||||
|
struct{
|
||||||
|
int offset;
|
||||||
|
msixmsg_t* table;
|
||||||
|
int entrycount;
|
||||||
|
} msix;
|
||||||
|
}
|
||||||
|
|
||||||
} pci_enumeration;
|
} pci_enumeration;
|
||||||
|
|
||||||
#define PCI_TYPE_MEM 1
|
#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_IO 1
|
||||||
#define PCI_COMMAND_MEMORY 2
|
#define PCI_COMMAND_MEMORY 2
|
||||||
#define PCI_COMMAND_MASTER 4
|
#define PCI_COMMAND_MASTER 4
|
||||||
|
#define PCI_COMMAND_INTDISABLE 1024
|
||||||
|
|
||||||
bool pci_msisupport(pci_enumeration* e);
|
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_msimask(pci_enumeration* e, int which, int val);
|
||||||
void pci_msimaskall(pci_enumeration* e, 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);
|
void pci_setcommand(pci_enumeration* e, int which, int val);
|
||||||
pci_enumeration* pci_getdevicecs(int class, int subclass, int n);
|
pci_enumeration* pci_getdevicecs(int class, int subclass, int n);
|
||||||
|
|||||||
+97
-16
@@ -3,6 +3,8 @@
|
|||||||
#include <arch/io.h>
|
#include <arch/io.h>
|
||||||
#include <kernel/alloc.h>
|
#include <kernel/alloc.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <kernel/vmm.h>
|
||||||
|
|
||||||
pci_enumeration* enumerations;
|
pci_enumeration* enumerations;
|
||||||
|
|
||||||
@@ -11,6 +13,7 @@ pci_enumeration* enumerations;
|
|||||||
|
|
||||||
#define COMMAND_REG 1
|
#define COMMAND_REG 1
|
||||||
#define CAP_MSI 5
|
#define CAP_MSI 5
|
||||||
|
#define CAP_MSIX 0x11
|
||||||
|
|
||||||
pci_enumeration* pci_getdevicecs(int class, int subclass, int n){
|
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){
|
bool pci_msisupport(pci_enumeration* e){
|
||||||
if(!legacy_getcapabilityoffset(CAP_MSI, e))
|
if(!legacy_getcapabilityoffset(CAP_MSI, e))
|
||||||
return false;
|
return false;
|
||||||
@@ -186,36 +196,72 @@ bool pci_msisupport(pci_enumeration* e){
|
|||||||
return true;
|
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);
|
int offset = legacy_getcapabilityoffset(CAP_MSI, e);
|
||||||
|
|
||||||
if(!offset)
|
__assert(offset);
|
||||||
return;
|
|
||||||
|
e->msi.offset = offset;
|
||||||
|
|
||||||
uint32_t currval = legacy_readdata(e->bus, e->device, e->function, offset);
|
uint32_t currval = legacy_readdata(e->bus, e->device, e->function, offset);
|
||||||
|
|
||||||
if((currval & 1 << 23) == 0)
|
if((currval & 1 << 23) == 0)
|
||||||
_panic("32 bit MSI not supported!");
|
_panic("32 bit MSI not supported!", NULL);
|
||||||
|
|
||||||
if(enable){
|
currval |= 1 << 16;
|
||||||
currval |= 1 << 16;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
currval &= ~(1 << 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
legacy_writedata(e->bus, e->device, e->function, offset, currval);
|
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){
|
void pci_msimask(pci_enumeration* e, int which, int val){
|
||||||
int offset = legacy_getcapabilityoffset(CAP_MSI, e);
|
int offset = legacy_getcapabilityoffset(CAP_MSI, e);
|
||||||
|
|
||||||
if(!offset)
|
__assert(offset);
|
||||||
return;
|
|
||||||
|
|
||||||
offset += 2;
|
offset += 3;
|
||||||
|
|
||||||
uint32_t currval = legacy_readdata(e->bus, e->device, e->function, offset);
|
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);
|
int offset = legacy_getcapabilityoffset(CAP_MSI, e);
|
||||||
|
|
||||||
if(!offset)
|
__assert(offset);
|
||||||
return;
|
|
||||||
|
|
||||||
offset += 2;
|
offset += 3;
|
||||||
|
|
||||||
uint32_t currval = legacy_readdata(e->bus, e->device, e->function, offset);
|
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){
|
static void legacy_enumeratedevice(int bus, int device){
|
||||||
|
|
||||||
// if the device is multifunction, scan and enumerate all 8. else, only one
|
// 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){
|
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);
|
*data = vector | (edgetrigger << 15) | (deassert << 14);
|
||||||
return (0xFEE00000 | (processor << 12));
|
return (0xFEE00000 | (processor << 12));
|
||||||
|
|||||||
Reference in New Issue
Block a user