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:
parent
66c4c491d9
commit
763bf37d29
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user