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: %ld\n", fMsiStartIrq); 50 51 return B_OK; 52 } 53 54 55 status_t 56 MsiInterruptCtrlDW::AllocateVectors(uint8 count, uint8& startVector, uint64& address, uint16& data) 57 { 58 if (count != 1) 59 return B_ERROR; 60 61 for (int i = 0; i < 32; i++) { 62 if (((1 << i) & fAllocatedMsiIrqs[0]) == 0) { 63 fAllocatedMsiIrqs[0] |= (1 << i); 64 fDbiRegs->msiIntr[0].mask &= ~(1 << i); 65 66 startVector = fMsiStartIrq + i; 67 address = fMsiPhysAddr; 68 data = i; 69 return B_OK; 70 } 71 } 72 return B_ERROR; 73 } 74 75 76 void 77 MsiInterruptCtrlDW::FreeVectors(uint8 count, uint8 startVector) 78 { 79 int32 irq = (int32)startVector - fMsiStartIrq; 80 while (count > 0) { 81 if (irq >= 0 && irq < 32 && ((1 << irq) & fAllocatedMsiIrqs[0]) != 0) { 82 fDbiRegs->msiIntr[0].mask |= (1 << (uint32)irq); 83 fAllocatedMsiIrqs[0] &= ~(1 << (uint32)irq); 84 } 85 irq++; 86 count--; 87 } 88 } 89 90 91 int32 92 MsiInterruptCtrlDW::InterruptReceived(void* arg) 93 { 94 return static_cast<MsiInterruptCtrlDW*>(arg)->InterruptReceivedInt(); 95 } 96 97 98 int32 99 MsiInterruptCtrlDW::InterruptReceivedInt() 100 { 101 // dprintf("MsiInterruptCtrlDW::InterruptReceivedInt()\n"); 102 uint32 status = fDbiRegs->msiIntr[0].status; 103 for (int i = 0; i < 32; i++) { 104 if (((1 << i) & status) != 0) { 105 // dprintf("MSI IRQ: %d (%ld)\n", i, fStartMsiIrq + i); 106 int_io_interrupt_handler(fMsiStartIrq + i, false); 107 fDbiRegs->msiIntr[0].status = (1 << i); 108 } 109 } 110 return B_HANDLED_INTERRUPT; 111 } 112