diff --git a/kernel/disk/ahci/hba.cpp b/kernel/disk/ahci/hba.cpp index e35f86da..5d4c4062 100644 --- a/kernel/disk/ahci/hba.cpp +++ b/kernel/disk/ahci/hba.cpp @@ -126,6 +126,13 @@ void HBA__OnInterrupt(struct interrupt_context*, void* context) bool HBA::Initialize(Ref dev, const char* devpath) { + interrupt_index = PCI::SetupInterruptLine(devaddr); + if ( !interrupt_index ) + { + LogF("error: cannot determine interrupt line"); + return errno = EINVAL, false; + } + pcibar_t mmio_bar = PCI::GetBAR(devaddr, 5); if ( mmio_bar.size() < sizeof(struct hba_regs) && /* or || ? */ mmio_bar.size() < 1024 ) @@ -228,8 +235,6 @@ bool HBA::Initialize(Ref dev, const char* devpath) } } - interrupt_index = - Interrupt::IRQ0 + PCI::Read8(devaddr, PCIFIELD_INTERRUPT_LINE); interrupt_registration.handler = HBA__OnInterrupt; interrupt_registration.context = this; Interrupt::RegisterHandler(interrupt_index, &interrupt_registration); diff --git a/kernel/disk/ahci/hba.h b/kernel/disk/ahci/hba.h index 6da4c5b9..e94f7550 100644 --- a/kernel/disk/ahci/hba.h +++ b/kernel/disk/ahci/hba.h @@ -56,7 +56,7 @@ private: addralloc_t mmio_alloc; volatile struct hba_regs* regs; uint32_t devaddr; - unsigned int interrupt_index; + uint8_t interrupt_index; bool interrupt_registered; bool mmio_alloced; diff --git a/kernel/disk/ata/hba.cpp b/kernel/disk/ata/hba.cpp index 62912c5c..0cb52a76 100644 --- a/kernel/disk/ata/hba.cpp +++ b/kernel/disk/ata/hba.cpp @@ -147,7 +147,7 @@ void FixDefaultDeviceBars(pcibar_t* basebar, pcibar_t* ctrlbar, uint8_t* irq, bool compatibility = interface == 0x00 || interface == 0x02; if ( compatibility ) - *irq = channel_index == 0 ? 14 : 15; + *irq = channel_index == 0 ? Interrupt::IRQ14 : Interrupt::IRQ15; if ( compatibility || basebar->addr_raw == 0 || @@ -175,8 +175,14 @@ bool Channel::Initialize(Ref dev, const char* devpath) pcibar_t basebar = PCI::GetBAR(devaddr, 2 * channel_index + 0); pcibar_t ctrlbar = PCI::GetBAR(devaddr, 2 * channel_index + 1); pcibar_t busmasterbar = PCI::GetBAR(devaddr, 4); - uint8_t irq = PCI::Read8(devaddr, PCIFIELD_INTERRUPT_LINE); - FixDefaultDeviceBars(&basebar, &ctrlbar, &irq, channel_index, interface); + interrupt_index = PCI::SetupInterruptLine(devaddr); + FixDefaultDeviceBars(&basebar, &ctrlbar, &interrupt_index, channel_index, interface); + + if ( !interrupt_index ) + { + LogF("error: cannot determine interrupt line"); + return errno = EINVAL, false; + } if ( !basebar.is_iospace() ) { @@ -255,8 +261,6 @@ bool Channel::Initialize(Ref dev, const char* devpath) } } - interrupt_index = Interrupt::IRQ0 + irq; - interrupt_registration.handler = Channel__OnInterrupt; interrupt_registration.context = this; Interrupt::RegisterHandler(interrupt_index, &interrupt_registration); diff --git a/kernel/disk/ata/hba.h b/kernel/disk/ata/hba.h index 81eaf418..c7620555 100644 --- a/kernel/disk/ata/hba.h +++ b/kernel/disk/ata/hba.h @@ -61,7 +61,7 @@ private: uint16_t port_control; uint16_t busmaster_base; Port* drives[2]; - unsigned int interrupt_index; + uint8_t interrupt_index; bool interrupt_registered; }; diff --git a/kernel/include/sortix/kernel/pci.h b/kernel/include/sortix/kernel/pci.h index 17d2e76d..edc2d034 100644 --- a/kernel/include/sortix/kernel/pci.h +++ b/kernel/include/sortix/kernel/pci.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen. + * Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -152,6 +152,7 @@ pcibar_t GetExpansionROM(uint32_t devaddr); void EnableExpansionROM(uint32_t devaddr); void DisableExpansionROM(uint32_t devaddr); bool IsExpansionROMEnabled(uint32_t devaddr); +uint8_t SetupInterruptLine(uint32_t devaddr); } // namespace PCI } // namespace Sortix diff --git a/kernel/pci.cpp b/kernel/pci.cpp index b380f5ee..758daa82 100644 --- a/kernel/pci.cpp +++ b/kernel/pci.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 2013, 2014 Jonas 'Sortie' Termansen. + * Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -31,8 +32,8 @@ namespace PCI { static kthread_mutex_t pci_lock = KTHREAD_MUTEX_INITIALIZER; -const uint16_t CONFIG_ADDRESS = 0xCF8; -const uint16_t CONFIG_DATA = 0xCFC; +static const uint16_t CONFIG_ADDRESS = 0xCF8; +static const uint16_t CONFIG_DATA = 0xCFC; uint32_t MakeDevAddr(uint8_t bus, uint8_t slot, uint8_t func) { @@ -279,6 +280,26 @@ bool IsExpansionROMEnabled(uint32_t devaddr) return PCI::Read32(devaddr, 0x30) & 0x1; } +static bool IsOkayInterruptLine(uint8_t line) +{ + if ( line == 0 ) + return false; // Conflict with PIT. + if ( line == 2 ) + return false; // Cascade, can't be received. + if ( 16 <= line ) + return false; // Not in set of valid IRQs. + return true; +} + +uint8_t SetupInterruptLine(uint32_t devaddr) +{ + ScopedLock lock(&pci_lock); + uint8_t line = Read8(devaddr, PCIFIELD_INTERRUPT_LINE); + if ( !IsOkayInterruptLine(line) ) + return 0; + return Interrupt::IRQ0 + line; +} + void Init() { }