1 /* 2 * Copyright 2022, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "DWPCIController.h" 8 9 #include <int.h> 10 11 12 status_t 13 MsiInterruptCtrlDW::Init(PciDbiRegs volatile* dbiRegs, int32 msiIrq) 14 { 15 dprintf("MsiInterruptCtrlDW::Init()\n"); 16 dprintf(" msiIrq: %" B_PRId32 "\n", msiIrq); 17 18 fDbiRegs = dbiRegs; 19 20 physical_entry pe; 21 status_t result = get_memory_map(&fMsiData, sizeof(fMsiData), &pe, 1); 22 if (result != B_OK) { 23 dprintf(" unable to get MSI Memory map!\n"); 24 return result; 25 } 26 27 fMsiPhysAddr = pe.address; 28 dprintf(" fMsiPhysAddr: %#" B_PRIxADDR "\n", fMsiPhysAddr); 29 fDbiRegs->msiAddrLo = (uint32)fMsiPhysAddr; 30 fDbiRegs->msiAddrHi = (uint32)(fMsiPhysAddr >> 32); 31 32 fDbiRegs->msiIntr[0].enable = 0xffffffff; 33 fDbiRegs->msiIntr[0].mask = 0xffffffff; 34 35 result = install_io_interrupt_handler(msiIrq, InterruptReceived, this, 0); 36 if (result != B_OK) { 37 dprintf(" unable to attach MSI irq handler!\n"); 38 return result; 39 } 40 result = allocate_io_interrupt_vectors(32, &fMsiStartIrq, INTERRUPT_TYPE_IRQ); 41 42 if (result != B_OK) { 43 dprintf(" unable to attach MSI irq handler!\n"); 44 return result; 45 } 46 47 msi_set_interface(static_cast<MSIInterface*>(this)); 48 49 dprintf(" fMsiStartIrq: %" B_PRId32 "\n", fMsiStartIrq); 50 51 return B_OK; 52 } 53 54 55 status_t 56 MsiInterruptCtrlDW::AllocateVectors(uint32 count, uint32& startVector, uint64& address, 57 uint32& data) 58 { 59 if (count != 1) 60 return B_ERROR; 61 62 for (int i = 0; i < 32; i++) { 63 if (((1 << i) & fAllocatedMsiIrqs[0]) == 0) { 64 fAllocatedMsiIrqs[0] |= (1 << i); 65 fDbiRegs->msiIntr[0].mask &= ~(1 << i); 66 67 startVector = fMsiStartIrq + i; 68 address = fMsiPhysAddr; 69 data = i; 70 return B_OK; 71 } 72 } 73 return B_ERROR; 74 } 75 76 77 void 78 MsiInterruptCtrlDW::FreeVectors(uint32 count, uint32 startVector) 79 { 80 int32 irq = (int32)startVector - fMsiStartIrq; 81 while (count > 0) { 82 if (irq >= 0 && irq < 32 && ((1 << irq) & fAllocatedMsiIrqs[0]) != 0) { 83 fDbiRegs->msiIntr[0].mask |= (1 << (uint32)irq); 84 fAllocatedMsiIrqs[0] &= ~(1 << (uint32)irq); 85 } 86 irq++; 87 count--; 88 } 89 } 90 91 92 int32 93 MsiInterruptCtrlDW::InterruptReceived(void* arg) 94 { 95 return static_cast<MsiInterruptCtrlDW*>(arg)->InterruptReceivedInt(); 96 } 97 98 99 int32 100 MsiInterruptCtrlDW::InterruptReceivedInt() 101 { 102 // dprintf("MsiInterruptCtrlDW::InterruptReceivedInt()\n"); 103 uint32 status = fDbiRegs->msiIntr[0].status; 104 for (int i = 0; i < 32; i++) { 105 if (((1 << i) & status) != 0) { 106 // dprintf("MSI IRQ: %d (%ld)\n", i, fStartMsiIrq + i); 107 int_io_interrupt_handler(fMsiStartIrq + i, false); 108 fDbiRegs->msiIntr[0].status = (1 << i); 109 } 110 } 111 return B_HANDLED_INTERRUPT; 112 } 113