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) 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); pcibar_t mmio_bar = PCI::GetBAR(devaddr, 5);
if ( mmio_bar.size() < sizeof(struct hba_regs) && /* or || ? */ if ( mmio_bar.size() < sizeof(struct hba_regs) && /* or || ? */
mmio_bar.size() < 1024 ) 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.handler = HBA__OnInterrupt;
interrupt_registration.context = this; interrupt_registration.context = this;
Interrupt::RegisterHandler(interrupt_index, &interrupt_registration); Interrupt::RegisterHandler(interrupt_index, &interrupt_registration);

View File

@ -56,7 +56,7 @@ private:
addralloc_t mmio_alloc; addralloc_t mmio_alloc;
volatile struct hba_regs* regs; volatile struct hba_regs* regs;
uint32_t devaddr; uint32_t devaddr;
unsigned int interrupt_index; uint8_t interrupt_index;
bool interrupt_registered; bool interrupt_registered;
bool mmio_alloced; 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; bool compatibility = interface == 0x00 || interface == 0x02;
if ( compatibility ) if ( compatibility )
*irq = channel_index == 0 ? 14 : 15; *irq = channel_index == 0 ? Interrupt::IRQ14 : Interrupt::IRQ15;
if ( compatibility || if ( compatibility ||
basebar->addr_raw == 0 || 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 basebar = PCI::GetBAR(devaddr, 2 * channel_index + 0);
pcibar_t ctrlbar = PCI::GetBAR(devaddr, 2 * channel_index + 1); pcibar_t ctrlbar = PCI::GetBAR(devaddr, 2 * channel_index + 1);
pcibar_t busmasterbar = PCI::GetBAR(devaddr, 4); pcibar_t busmasterbar = PCI::GetBAR(devaddr, 4);
uint8_t irq = PCI::Read8(devaddr, PCIFIELD_INTERRUPT_LINE); interrupt_index = PCI::SetupInterruptLine(devaddr);
FixDefaultDeviceBars(&basebar, &ctrlbar, &irq, channel_index, interface); 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() ) 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.handler = Channel__OnInterrupt;
interrupt_registration.context = this; interrupt_registration.context = this;
Interrupt::RegisterHandler(interrupt_index, &interrupt_registration); Interrupt::RegisterHandler(interrupt_index, &interrupt_registration);

View File

@ -61,7 +61,7 @@ private:
uint16_t port_control; uint16_t port_control;
uint16_t busmaster_base; uint16_t busmaster_base;
Port* drives[2]; Port* drives[2];
unsigned int interrupt_index; uint8_t interrupt_index;
bool interrupt_registered; 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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 EnableExpansionROM(uint32_t devaddr);
void DisableExpansionROM(uint32_t devaddr); void DisableExpansionROM(uint32_t devaddr);
bool IsExpansionROMEnabled(uint32_t devaddr); bool IsExpansionROMEnabled(uint32_t devaddr);
uint8_t SetupInterruptLine(uint32_t devaddr);
} // namespace PCI } // namespace PCI
} // namespace Sortix } // 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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -21,6 +21,7 @@
#include <endian.h> #include <endian.h>
#include <sortix/kernel/cpu.h> #include <sortix/kernel/cpu.h>
#include <sortix/kernel/interrupt.h>
#include <sortix/kernel/ioport.h> #include <sortix/kernel/ioport.h>
#include <sortix/kernel/kernel.h> #include <sortix/kernel/kernel.h>
#include <sortix/kernel/kthread.h> #include <sortix/kernel/kthread.h>
@ -31,8 +32,8 @@ namespace PCI {
static kthread_mutex_t pci_lock = KTHREAD_MUTEX_INITIALIZER; static kthread_mutex_t pci_lock = KTHREAD_MUTEX_INITIALIZER;
const uint16_t CONFIG_ADDRESS = 0xCF8; static const uint16_t CONFIG_ADDRESS = 0xCF8;
const uint16_t CONFIG_DATA = 0xCFC; static const uint16_t CONFIG_DATA = 0xCFC;
uint32_t MakeDevAddr(uint8_t bus, uint8_t slot, uint8_t func) 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; 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() void Init()
{ {
} }