Fix drivers not detecting PCI devices without an interrupt line.

This commit is contained in:
Jonas 'Sortie' Termansen 2016-07-29 23:15:31 +02:00
parent da89dec2e2
commit 2b6463aa95
6 changed files with 44 additions and 13 deletions

View File

@ -126,6 +126,13 @@ void HBA__OnInterrupt(struct interrupt_context*, void* context)
bool HBA::Initialize(Ref<Descriptor> 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<Descriptor> 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);

View File

@ -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;

View File

@ -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<Descriptor> 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<Descriptor> dev, const char* devpath)
}
}
interrupt_index = Interrupt::IRQ0 + irq;
interrupt_registration.handler = Channel__OnInterrupt;
interrupt_registration.context = this;
Interrupt::RegisterHandler(interrupt_index, &interrupt_registration);

View File

@ -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;
};

View File

@ -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

View File

@ -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 <endian.h>
#include <sortix/kernel/cpu.h>
#include <sortix/kernel/interrupt.h>
#include <sortix/kernel/ioport.h>
#include <sortix/kernel/kernel.h>
#include <sortix/kernel/kthread.h>
@ -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()
{
}