2
0
mirror of https://git.missingno.dev/kolibrios-nvme-driver/ synced 2024-12-22 22:08:47 +01:00

fix(regression): freeze with multiple NVMe devices

Removing the PCI status bit check in the interrupt handler caused the
code to break and not work if there was more than one NVMe device
successfully attached. Not only does this commit fix this issue, but
this also adds a proper check to see if the device generated an
interrupt by checking if any commands have been posted to the completion
queue.
This commit is contained in:
Abdur-Rahman Mansoor 2024-08-23 12:08:00 -04:00
parent 66c4c491d9
commit 763bf37d29
Signed by: ramenu
GPG Key ID: 8D15FCF6795779C8

View File

@ -76,7 +76,7 @@ local AnythingLoadedSuccessfully db 0
test eax, eax test eax, eax
setne [AnythingLoadedSuccessfully] setne [AnythingLoadedSuccessfully]
inc ebx inc ebx
cmp ebx, dword [pcidevs_len] cmp ebx, dword [num_pcidevs]
jne .loop jne .loop
cmp [AnythingLoadedSuccessfully], 0 cmp [AnythingLoadedSuccessfully], 0
jz .err jz .err
@ -536,7 +536,7 @@ proc nvme_readwrite stdcall, ns:dword, buf:dword, start_sector:qword, numsectors
endp endp
; Detects NVMe devices on the PCI bus and stores them into ; Detects NVMe devices on the PCI bus and stores them into
; [p_nvme_devices] and sets [pcidevs_len] to the appropriate ; [p_nvme_devices] and sets [num_pcidevs] to the appropriate
; size based off how many NVMe devices there are. ; size based off how many NVMe devices there are.
proc detect_nvme proc detect_nvme
@ -571,13 +571,14 @@ proc detect_nvme
jnz .err jnz .err
@@: @@:
cmp dword [pcidevs_len], TOTAL_PCIDEVS cmp dword [num_pcidevs], TOTAL_PCIDEVS
jne @f jne @f
DEBUGF DBG_INFO, "Can't add any more NVMe devices...\n" DEBUGF DBG_INFO, "Can't add any more NVMe devices...\n"
jmp .exit_success jmp .exit_success
@@: @@:
inc dword [pcidevs_len] inc dword [num_pcidevs]
add dword [num_pcidevs_sz], sizeof.pcidev
cmp dword [p_nvme_devices], 0 cmp dword [p_nvme_devices], 0
jnz @f ; was the pointer already allocated? jnz @f ; was the pointer already allocated?
invoke KernelAlloc, sizeof.pcidev * TOTAL_PCIDEVS invoke KernelAlloc, sizeof.pcidev * TOTAL_PCIDEVS
@ -588,7 +589,7 @@ proc detect_nvme
DEBUGF DBG_INFO, "nvme: Allocated memory for PCI devices at: 0x%x\n", eax DEBUGF DBG_INFO, "nvme: Allocated memory for PCI devices at: 0x%x\n", eax
@@: @@:
mov ecx, dword [pcidevs_len] mov ecx, dword [num_pcidevs]
dec ecx dec ecx
mov edi, dword [p_nvme_devices] mov edi, dword [p_nvme_devices]
mov edx, ecx mov edx, ecx
@ -1281,19 +1282,24 @@ endp
proc irq_handler proc irq_handler
push ebx esi edi push ebx esi edi
mov edi, dword [p_nvme_devices] mov esi, dword [p_nvme_devices]
mov esi, edi mov ebx, dword [num_pcidevs_sz]
sub esi, sizeof.pcidev add ebx, esi
mov ebx, dword [pcidevs_len]
xor ecx, ecx
.check_who_raised_irq: .check_who_raised_irq:
stdcall device_generated_interrupt, esi
test eax, eax
jnz @f
add esi, sizeof.pcidev add esi, sizeof.pcidev
inc ecx cmp esi, ebx
cmp ecx, ebx jbe .check_who_raised_irq
; TODO: Apply solution given by @punk_joker of checking which device
; generated an interrupt. ; Interrupt not handled by driver, return 0
ja .not_our_irq pop edi esi ebx
xor eax, eax
ret
@@:
mov edi, dword [esi + pcidev.io_addr] mov edi, dword [esi + pcidev.io_addr]
mov dword [edi + NVME_MMIO.INTMS], 0x3 mov dword [edi + NVME_MMIO.INTMS], 0x3
stdcall consume_cq_entries, esi, ADMIN_QUEUE stdcall consume_cq_entries, esi, ADMIN_QUEUE
@ -1307,12 +1313,28 @@ proc irq_handler
mov eax, 1 mov eax, 1
ret ret
.not_our_irq: endp
; Interrupt not handled by driver, return 0
pop edi esi ebx proc device_generated_interrupt stdcall, pci:dword
mov edx, [pci]
mov edx, dword [edx + pcidev.queue_entries]
xor ecx, ecx
@@:
mov ax, word [edx + ecx + NVM_QUEUE_ENTRY.head]
cmp ax, word [edx + ecx + NVM_QUEUE_ENTRY.tail]
jne @f
add ecx, sizeof.NVM_QUEUE_ENTRY
cmp ecx, LAST_QUEUE_ID * sizeof.NVM_QUEUE_ENTRY
jbe @b
xor eax, eax xor eax, eax
ret ret
@@:
mov eax, 1
ret
endp endp
; Deletes the allocated I/O queues for all of the NVMe devices, ; Deletes the allocated I/O queues for all of the NVMe devices,
@ -1363,7 +1385,7 @@ proc nvme_cleanup
jbe .get_queue jbe .get_queue
pop ebx pop ebx
inc ebx inc ebx
cmp ebx, dword [pcidevs_len] cmp ebx, dword [num_pcidevs]
jne .get_pcidev jne .get_pcidev
; NOTE: This code has a bug! It only shuts down the last ; NOTE: This code has a bug! It only shuts down the last
@ -1390,8 +1412,9 @@ endp
;all initialized data place here ;all initialized data place here
align 4 align 4
p_nvme_devices dd 0 p_nvme_devices dd 0 ; Pointer to array of NVMe devices
pcidevs_len dd 0 num_pcidevs dd 0 ; Number of NVMe devices
num_pcidevs_sz dd 0 ; Size in bytes
my_service db "nvme",0 ;max 16 chars include zero my_service db "nvme",0 ;max 16 chars include zero
disk_functions: disk_functions:
dd disk_functions.end - disk_functions dd disk_functions.end - disk_functions