/* * Copyright 2022, Haiku, Inc. * Distributed under the terms of the MIT License. */ #include "DWPCIController.h" #include status_t MsiInterruptCtrlDW::Init(PciDbiRegs volatile* dbiRegs, int32 msiIrq) { dprintf("MsiInterruptCtrlDW::Init()\n"); dprintf(" msiIrq: %" B_PRId32 "\n", msiIrq); fDbiRegs = dbiRegs; physical_entry pe; status_t result = get_memory_map(&fMsiData, sizeof(fMsiData), &pe, 1); if (result != B_OK) { dprintf(" unable to get MSI Memory map!\n"); return result; } fMsiPhysAddr = pe.address; dprintf(" fMsiPhysAddr: %#" B_PRIxADDR "\n", fMsiPhysAddr); fDbiRegs->msiAddrLo = (uint32)fMsiPhysAddr; fDbiRegs->msiAddrHi = (uint32)(fMsiPhysAddr >> 32); fDbiRegs->msiIntr[0].enable = 0xffffffff; fDbiRegs->msiIntr[0].mask = 0xffffffff; result = install_io_interrupt_handler(msiIrq, InterruptReceived, this, 0); if (result != B_OK) { dprintf(" unable to attach MSI irq handler!\n"); return result; } result = allocate_io_interrupt_vectors(32, &fMsiStartIrq, INTERRUPT_TYPE_IRQ); if (result != B_OK) { dprintf(" unable to attach MSI irq handler!\n"); return result; } msi_set_interface(static_cast(this)); dprintf(" fMsiStartIrq: %ld\n", fMsiStartIrq); return B_OK; } status_t MsiInterruptCtrlDW::AllocateVectors(uint8 count, uint8& startVector, uint64& address, uint16& data) { if (count != 1) return B_ERROR; for (int i = 0; i < 32; i++) { if (((1 << i) & fAllocatedMsiIrqs[0]) == 0) { fAllocatedMsiIrqs[0] |= (1 << i); fDbiRegs->msiIntr[0].mask &= ~(1 << i); startVector = fMsiStartIrq + i; address = fMsiPhysAddr; data = i; return B_OK; } } return B_ERROR; } void MsiInterruptCtrlDW::FreeVectors(uint8 count, uint8 startVector) { int32 irq = (int32)startVector - fMsiStartIrq; while (count > 0) { if (irq >= 0 && irq < 32 && ((1 << irq) & fAllocatedMsiIrqs[0]) != 0) { fDbiRegs->msiIntr[0].mask |= (1 << (uint32)irq); fAllocatedMsiIrqs[0] &= ~(1 << (uint32)irq); } irq++; count--; } } int32 MsiInterruptCtrlDW::InterruptReceived(void* arg) { return static_cast(arg)->InterruptReceivedInt(); } int32 MsiInterruptCtrlDW::InterruptReceivedInt() { // dprintf("MsiInterruptCtrlDW::InterruptReceivedInt()\n"); uint32 status = fDbiRegs->msiIntr[0].status; for (int i = 0; i < 32; i++) { if (((1 << i) & status) != 0) { // dprintf("MSI IRQ: %d (%ld)\n", i, fStartMsiIrq + i); int_io_interrupt_handler(fMsiStartIrq + i, false); fDbiRegs->msiIntr[0].status = (1 << i); } } return B_HANDLED_INTERRUPT; }