Skip to content

Commit 5845b5b

Browse files
author
Di Ferrari
authored
Merge pull request #6 from Totto16/msix_support
Fix: fix PCI MSI-X support
2 parents 2afd352 + f006054 commit 5845b5b

4 files changed

Lines changed: 88 additions & 24 deletions

File tree

kernel/input/xhci.c

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,22 +93,53 @@ void make_ring_link(trb* ring, bool cycle){
9393
make_ring_link_control(ring, cycle);
9494
}
9595

96+
97+
uint8_t xhci_init_interrupts(uint64_t pci_addr){
98+
bool msi_ok = pci_setup_msi(pci_addr, XHCI_IRQ);
99+
100+
if(msi_ok){
101+
return 1;
102+
}
103+
104+
#define MSIX_IRQ_LENGTH 1
105+
106+
msix_irq_line irq_lines[MSIX_IRQ_LENGTH] = {(msix_irq_line){.addr_offset=0,.irq_num=XHCI_IRQ}};
107+
108+
bool msix_ok = pci_setup_msix(pci_addr, irq_lines, MSIX_IRQ_LENGTH);
109+
if(msix_ok){
110+
return 2;
111+
}
112+
113+
return 0;
114+
}
115+
96116
bool xhci_init(xhci_device *xhci, uint64_t pci_addr) {
97117
kprintfv("[xHCI] init");
98118
if (!(read16(pci_addr + 0x06) & (1 << 4))){
99119
kprintfv("[xHCI] Wrong capabilities list");
100120
return false;
101121
}
102122

103-
pci_setup_msi(pci_addr, XHCI_IRQ);
104-
105123
if (!pci_setup_bar(pci_addr, 0, &xhci->mmio, &xhci->mmio_size)){
106124
kprintfv("[xHCI] BARs not set up");
107125
return false;
108126
}
109127

110128
pci_register(xhci->mmio, xhci->mmio_size);
111129

130+
uint8_t interrupts_ok = xhci_init_interrupts(pci_addr);
131+
switch(interrupts_ok){
132+
case 0:
133+
kprintf_raw("[xHCI] Failed to setup interrupts\n");
134+
return false;
135+
case 2:
136+
kprintf_raw("[xHCI] Interrupts setup with MSI-X");
137+
break;
138+
default:
139+
kprintf_raw("[xHCI] Interrupts setup with MSI");
140+
break;
141+
}
142+
112143
pci_enable_device(pci_addr);
113144

114145
kprintfv("[xHCI] BARs set up @ %x (%x)",xhci->mmio,xhci->mmio_size);

kernel/pci.c

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717
#define PCI_COMMAND_MEMORY 0x2
1818
#define PCI_COMMAND_BUS 0x4
1919

20+
#define PCI_BAR_BASE_OFFSET 0x10
21+
22+
#define PCI_CAPABILITY_MSI 0x05
23+
#define PCI_CAPABILITY_PCIE 0x10
24+
#define PCI_CAPABILITY_MSIX 0x11
25+
2026
static uint64_t pci_base;
2127

2228
#define NINIT pci_base == 0x0
@@ -198,25 +204,19 @@ uint64_t pci_get_bar_address(uint64_t base, uint8_t offset, uint8_t index){
198204
}
199205

200206
uint64_t pci_read_address_bar(uintptr_t pci_addr, uint32_t bar_index){
201-
uint64_t bar_addr = pci_get_bar_address(pci_addr, 0x10, bar_index);
207+
uint64_t bar_addr = pci_get_bar_address(pci_addr, PCI_BAR_BASE_OFFSET, bar_index);
202208
uint32_t original = read32(bar_addr);
203209
uint64_t full = original;
204210
if ((original & 0x6) == 0x4) {
205-
uint64_t bar_addr_hi = pci_get_bar_address(pci_addr, 0x10, bar_index+1);
211+
uint64_t bar_addr_hi = pci_get_bar_address(pci_addr, PCI_BAR_BASE_OFFSET, bar_index+1);
206212
uint64_t original_hi = read32(bar_addr_hi);
207213
full |= original_hi << 32;
208214
}
209215
return full & ~0xF;
210216
}
211217

212-
void debug_read_bar(uint64_t base, uint8_t offset, uint8_t index){
213-
uint64_t addr = pci_get_bar_address(base, offset, index);
214-
uint64_t val = read32(addr);
215-
kprintf("[PCI] Reading@%x (%i) content: ", addr, index, val);
216-
}
217-
218218
uint64_t pci_setup_bar(uint64_t pci_addr, uint32_t bar_index, uint64_t *mmio_start, uint64_t *mmio_size) {
219-
uint64_t bar_addr = pci_get_bar_address(pci_addr, 0x10, bar_index);
219+
uint64_t bar_addr = pci_get_bar_address(pci_addr, PCI_BAR_BASE_OFFSET, bar_index);
220220
uint32_t original = read32(bar_addr);
221221

222222
write32(bar_addr, 0xFFFFFFFF);
@@ -225,7 +225,7 @@ uint64_t pci_setup_bar(uint64_t pci_addr, uint32_t bar_index, uint64_t *mmio_sta
225225

226226
uint64_t size;
227227
if ((original & 0x6) == 0x4) {
228-
uint64_t bar_addr_hi = pci_get_bar_address(pci_addr, 0x10, bar_index+1);
228+
uint64_t bar_addr_hi = pci_get_bar_address(pci_addr, PCI_BAR_BASE_OFFSET, bar_index+1);
229229
uint32_t original_hi = read32(bar_addr_hi);
230230

231231
kprintfv("[PCI] Original second bar %x",original_hi);
@@ -314,7 +314,7 @@ bool pci_setup_msi(uint64_t pci_addr, uint8_t irq_line) {
314314
uint8_t cap_ptr = read8(pci_addr + 0x34);
315315
while (cap_ptr) {
316316
uint8_t cap_id = read8(pci_addr + cap_ptr);
317-
if (cap_id == 0x05) { // MSI
317+
if (cap_id == PCI_CAPABILITY_MSI) { // MSI
318318
uint16_t msg_ctrl = read16(pci_addr + cap_ptr + 0x2);
319319
bool is_64bit = msg_ctrl & (1 << 7);
320320

@@ -325,7 +325,7 @@ bool pci_setup_msi(uint64_t pci_addr, uint8_t irq_line) {
325325
offset += 4;
326326
}
327327

328-
write16(pci_addr + cap_ptr + offset, 50 + irq_line);
328+
write16(pci_addr + cap_ptr + offset, MSI_OFFSET + irq_line);
329329
msg_ctrl |= 1; // enable MSI
330330
write16(pci_addr + cap_ptr + 0x2, msg_ctrl);
331331
return true;
@@ -342,27 +342,46 @@ typedef struct {
342342
uint32_t vector_control;
343343
} msix_table_entry;
344344

345-
bool pci_setup_msix(uint64_t pci_addr, uint8_t irq_line) {
345+
bool pci_setup_msix(uint64_t pci_addr, msix_irq_line* irq_lines, uint8_t line_size) {
346346

347347
uint8_t cap_ptr = read8(pci_addr + 0x34);
348348
while (cap_ptr) {
349349
uint8_t cap_id = read8(pci_addr + cap_ptr);
350-
if (cap_id == 0x11) { // MSI-X
350+
if (cap_id == PCI_CAPABILITY_MSIX) { // MSI-X
351351
uint16_t msg_ctrl = read16(pci_addr + cap_ptr + 0x2);
352352
msg_ctrl &= ~(1 << 15); // Clear MSI-X Enable bit
353353
write16(pci_addr + cap_ptr + 0x2, msg_ctrl);
354+
uint16_t table_size = (msg_ctrl & 0x07FF) +1; // takes the 11 rightmost bits, its value is N-1, so add 1 to it for the full size
355+
356+
if(line_size > table_size){
357+
kprintf_raw("[PCI] MSI-X only supports %i interrupts, but you tried to add %i interrupts", table_size, line_size);
358+
return false;
359+
}
360+
354361
uint32_t table_offset = read32(pci_addr + cap_ptr + 0x4);
355362
uint8_t bir = table_offset & 0x7;
356363
uint32_t table_addr_offset = table_offset & ~0x7;
357364

358365
uint64_t table_addr = pci_read_address_bar(pci_addr, bir);
366+
367+
if(!table_addr){
368+
kprintf_raw("[PCI] MSI-X setup error: Table address is null. Did you setup the bar memory before calling this function?");
369+
return false;
370+
}
359371

360-
msix_table_entry *msix_entry = (msix_table_entry *)(uintptr_t)(table_addr + table_addr_offset);
361-
362-
msix_entry->msg_addr_low = 0x8020040;
363-
msix_entry->msg_addr_high = 0;
364-
msix_entry->msg_data = 50 + irq_line;
365-
msix_entry->vector_control = 0;
372+
msix_table_entry *msix_start = (msix_table_entry *)(uintptr_t)(table_addr + table_addr_offset);
373+
374+
for (uint32_t i = 0; i < line_size; i++){
375+
msix_table_entry *msix_entry = msix_start + i;
376+
377+
msix_irq_line irq_line = irq_lines[i];
378+
uint64_t addr_full = 0x8020040 + irq_line.addr_offset;
379+
380+
msix_entry->msg_addr_low = addr_full & 0xFFFFFFFF;
381+
msix_entry->msg_addr_high = addr_full >> 32;
382+
msix_entry->msg_data = MSI_OFFSET + irq_line.irq_num;
383+
msix_entry->vector_control = msix_entry->vector_control & ~0x1; // all bits other then the last one are reserved, so don't chnage it, just set the last bit to 0
384+
}
366385

367386
msg_ctrl |= (1 << 15); // MSI-X Enable
368387
msg_ctrl &= ~(1 << 14); // Clear Function Mask

kernel/pci.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,13 @@ void pci_register(uint64_t mmio_addr, uint64_t mmio_size);
2323
void pci_enable_verbose();
2424

2525
bool pci_setup_msi(uint64_t pci_addr, uint8_t irq_vector);
26-
bool pci_setup_msix(uint64_t pci_addr, uint8_t irq_line);
26+
27+
typedef struct {
28+
uint32_t addr_offset;
29+
uint8_t irq_num;
30+
} msix_irq_line;
31+
32+
bool pci_setup_msix(uint64_t pci_addr, msix_irq_line* irq_lines, uint8_t line_size);
2733

2834
#ifdef __cplusplus
2935
}

run

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ if [ "$1" = "debug" ]; then
77
ARGS="-monitor unix:/tmp/qemu-monitor-socket,server,nowait -s -S"
88
fi
99

10+
MSI_CAPABILITIES=""
11+
12+
XHCI_CAPABILITIES="$(qemu-system-aarch64 -device qemu-xhci,help)"
13+
14+
if echo "$XHCI_CAPABILITIES" | grep -q "msi "; then
15+
MSI_CAPABILITIES="msi=on,msix=off,"
16+
fi
17+
1018
qemu-system-aarch64 \
1119
-M virt \
1220
-cpu cortex-a72 \
@@ -17,7 +25,7 @@ qemu-system-aarch64 \
1725
-serial mon:stdio \
1826
-drive file=disk.img,if=none,format=raw,id=hd0 \
1927
-device virtio-blk-pci,drive=hd0 \
20-
-device qemu-xhci,msi=on,msix=off,id=usb \
28+
-device qemu-xhci,${MSI_CAPABILITIES}id=usb \
2129
-device usb-kbd,bus=usb.0 \
2230
-d guest_errors \
2331
$ARGS

0 commit comments

Comments
 (0)