Fix PCI code.

This commit is contained in:
Jonas 'Sortie' Termansen 2015-01-16 01:19:05 +01:00
parent 1bc2650413
commit 4f7c5ebdd3
4 changed files with 184 additions and 23 deletions

View File

@ -45,6 +45,7 @@ ifdef X86FAMILY
x86-family/memorymanagement.o \
$(CPU)/interrupt.o \
x86-family/interrupt.o \
x86-family/ioport.o \
x86-family/pic.o \
x86-family/gdt.o \
x86-family/idt.o \

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015.
This file is part of Sortix.
@ -55,10 +55,10 @@ typedef struct
uint8_t revid;
} pcifind_t;
const uint8_t PCIBAR_TYPE_IOSPACE = 0x0 << 1 | 0x1 << 0;
const uint8_t PCIBAR_TYPE_16BIT = 0x1 << 1 | 0x0 << 0;
const uint8_t PCIBAR_TYPE_32BIT = 0x0 << 1 | 0x0 << 0;
const uint8_t PCIBAR_TYPE_64BIT = 0x2 << 1 | 0x0 << 0;
static const uint8_t PCIBAR_TYPE_IOSPACE = 0x0 << 1 | 0x1 << 0;
static const uint8_t PCIBAR_TYPE_16BIT = 0x1 << 1 | 0x0 << 0;
static const uint8_t PCIBAR_TYPE_32BIT = 0x0 << 1 | 0x0 << 0;
static const uint8_t PCIBAR_TYPE_64BIT = 0x2 << 1 | 0x0 << 0;
typedef struct
{
@ -67,9 +67,12 @@ public:
uint64_t size_raw;
public:
uint64_t addr() const { return addr_raw & 0xFFFFFFFFFFFFFFF0; }
uint64_t addr() const { return is_iospace() ?
addr_raw & 0xFFFFFFFFFFFFFFFC :
addr_raw & 0xFFFFFFFFFFFFFFF0; }
uint64_t size() const { return size_raw & 0xFFFFFFFFFFFFFFFF; }
uint8_t type() const { return addr_raw & 0x7; }
uint8_t type() const { return (addr_raw & 3) == PCIBAR_TYPE_IOSPACE ?
(addr_raw & 3) : (addr_raw & 0x7); }
uint32_t ioaddr() const { return addr_raw & 0xFFFFFFFC; };
bool is_prefetchable() const { return addr_raw & 0x8; }
bool is_iospace() const { return type() == PCIBAR_TYPE_IOSPACE; }
@ -79,6 +82,60 @@ public:
bool is_mmio() const { return is_16bit() || is_32bit() || is_64bit(); }
} pcibar_t;
static const uint8_t PCIFIELD_VENDOR_ID = 0x00;
static const uint8_t PCIFIELD_DEVICE_ID = 0x02;
static const uint8_t PCIFIELD_COMMAND = 0x04;
static const uint8_t PCIFIELD_STATUS = 0x06;
static const uint8_t PCIFIELD_REVISION_ID = 0x08;
static const uint8_t PCIFIELD_PROG_IF = 0x09;
static const uint8_t PCIFIELD_SUBCLASS = 0x0A;
static const uint8_t PCIFIELD_CLASS = 0x0B;
static const uint8_t PCIFIELD_CACHE_LINE_SIZE = 0x0C;
static const uint8_t PCIFIELD_LATENCY_TIMER = 0x0D;
static const uint8_t PCIFIELD_HEADER_TYPE = 0x0E;
static const uint8_t PCIFIELD_BIST = 0x0F;
static const uint8_t PCIFIELD_RAW_BAR0 = 0x10;
static const uint8_t PCIFIELD_RAW_BAR1 = 0x14;
static const uint8_t PCIFIELD_RAW_BAR2 = 0x18;
static const uint8_t PCIFIELD_PRIMARY_BUS_NUMBER = 0x18;
static const uint8_t PCIFIELD_SECONDARY_BUS_NUMBER = 0x19;
static const uint8_t PCIFIELD_SUBORDINATE_BUS_NUMBER = 0x1A;
static const uint8_t PCIFIELD_SECONDARY_LATENCY_TIMER = 0x1B;
static const uint8_t PCIFIELD_RAW_BAR3 = 0x1C;
static const uint8_t PCIFIELD_IO_BASE = 0x1C;
static const uint8_t PCIFIELD_IO_LIMIT = 0x1D;
static const uint8_t PCIFIELD_SECONDARY_STATUS = 0x1E;
static const uint8_t PCIFIELD_RAW_BAR4 = 0x20;
static const uint8_t PCIFIELD_MEMORY_BASE = 0x20;
static const uint8_t PCIFIELD_MEMORY_LIMIT = 0x22;
static const uint8_t PCIFIELD_RAW_BAR5 = 0x24;
static const uint8_t PCIFIELD_PREFETCHABLE_MEMORY_BASE = 0x24;
static const uint8_t PCIFIELD_PREFETCHABLE_MEMORY_LIMIT = 0x26;
static const uint8_t PCIFIELD_CARDBUS_CIS_POINTER = 0x28;
static const uint8_t PCIFIELD_PREFETCHABLE_BASE_UPPER_BITS = 0x28;
static const uint8_t PCIFIELD_SUBSYSTEM_VENDOR_ID = 0x2C;
static const uint8_t PCIFIELD_PREFETCHABLE_LIMIT_UPPER_BITS = 0x2C;
static const uint8_t PCIFIELD_SUBSYSTEM_ID = 0x2E;
static const uint8_t PCIFIELD_EXPANSION_ROM_BASE_ADDRESS = 0x30;
static const uint8_t PCIFIELD_CAPABILITIES = 0x34;
static const uint8_t PCIFIELD_EXPANSION_ROM_BASE_ADDRESS_PCI_BRIDGE = 0x38;
static const uint8_t PCIFIELD_INTERRUPT_LINE = 0x3C;
static const uint8_t PCIFIELD_INTERRUPT_PIN = 0x3D;
static const uint8_t PCIFIELD_MIN_GRANT = 0x3E;
static const uint8_t PCIFIELD_MAX_LATENCY = 0x3F;
static const uint8_t PCIFIELD_BRIDGE_CONTROL = 0x3E;
static const uint16_t PCIFIELD_COMMAND_IO_SPACE = 1 << 0;
static const uint16_t PCIFIELD_COMMAND_MEMORY_SPACE = 1 << 1;
static const uint16_t PCIFIELD_COMMAND_BUS_MASTER = 1 << 2;
static const uint16_t PCIFIELD_COMMAND_SPECIAL_CYCLES = 1 << 3;
static const uint16_t PCIFIELD_COMMAND_MEMORY_WRITE_AND_INVALIDATE = 1 << 4;
static const uint16_t PCIFIELD_COMMAND_VGA_PALETTE_SNOOP = 1 << 5;
static const uint16_t PCIFIELD_COMMAND_PARITY_ERROR_RESPONSE = 1 << 6;
static const uint16_t PCIFIELD_COMMAND_SERR = 1 << 8;
static const uint16_t PCIFIELD_COMMAND_FAST_BACK_TO_BACK = 1 << 9;
static const uint16_t PCIFIELD_COMMAND_INTERRUPT_DISABLE = 1 << 10;
namespace PCI {
void Init();
@ -88,6 +145,8 @@ uint8_t Read8(uint32_t devaddr, uint8_t off); // Host endian
uint16_t Read16(uint32_t devaddr, uint8_t off); // Host endian
uint32_t Read32(uint32_t devaddr, uint8_t off); // Host endian
uint32_t ReadRaw32(uint32_t devaddr, uint8_t off); // PCI endian
void Write8(uint32_t devaddr, uint8_t off, uint8_t val); // Host endian
void Write16(uint32_t devaddr, uint8_t off, uint16_t val); // Host endian
void Write32(uint32_t devaddr, uint8_t off, uint32_t val); // Host endian
void WriteRaw32(uint32_t devaddr, uint8_t off, uint32_t val); // PCI endian
pciid_t GetDeviceId(uint32_t devaddr);

View File

@ -56,12 +56,14 @@ void SplitDevAddr(uint32_t devaddr, uint8_t* vals /* bus, slot, func */)
uint32_t ReadRaw32(uint32_t devaddr, uint8_t off)
{
assert((off & 0x3) == 0);
outport32(CONFIG_ADDRESS, devaddr + off);
return inport32(CONFIG_DATA);
}
void WriteRaw32(uint32_t devaddr, uint8_t off, uint32_t val)
{
assert((off & 0x3) == 0);
outport32(CONFIG_ADDRESS, devaddr + off);
outport32(CONFIG_DATA, val);
}
@ -76,23 +78,42 @@ void Write32(uint32_t devaddr, uint8_t off, uint32_t val)
WriteRaw32(devaddr, off, htole32(val));
}
void Write16(uint32_t devaddr, uint8_t off, uint16_t val)
{
assert((off & 0x1) == 0);
uint8_t alignedoff = off & ~0x3;
union { uint8_t val8[4]; uint32_t val32; };
val32 = ReadRaw32(devaddr, alignedoff);
val8[(off & 0x3) + 0] = val >> 0 & 0xFF;
val8[(off & 0x3) + 1] = val >> 8 & 0xFF;
WriteRaw32(devaddr, alignedoff, val32);
}
uint16_t Read16(uint32_t devaddr, uint8_t off)
{
assert((off & 0x1) == 0);
uint8_t alignedoff = off & ~0x3;
union { uint16_t val16[2]; uint32_t val32; };
union { uint8_t val8[4]; uint32_t val32; };
val32 = ReadRaw32(devaddr, alignedoff);
uint16_t ret = off & 0x2 ? val16[0] : val16[1];
return le16toh(ret);
return (uint16_t) val8[(off & 0x3) + 0] << 0 |
(uint16_t) val8[(off & 0x3) + 1] << 8;
}
void Write8(uint32_t devaddr, uint8_t off, uint8_t val)
{
uint8_t alignedoff = off & ~0x3;
union { uint8_t val8[4]; uint32_t val32; };
val32 = ReadRaw32(devaddr, alignedoff);
val8[(off & 0x3)] = val;
WriteRaw32(devaddr, alignedoff, val32);
}
uint8_t Read8(uint32_t devaddr, uint8_t off)
{
uint8_t alignedoff = off & ~0x1;
union { uint8_t val8[2]; uint32_t val16; };
val16 = htole16(Read16(devaddr, alignedoff));
uint8_t ret = off & 0x1 ? val8[0] : val8[1];
return ret;
uint8_t alignedoff = off & ~0x3;
union { uint8_t val8[4]; uint32_t val32; };
val32 = ReadRaw32(devaddr, alignedoff);
return val8[(off & 0x3)];
}
uint32_t CheckDevice(uint8_t bus, uint8_t slot, uint8_t func)
@ -103,18 +124,18 @@ uint32_t CheckDevice(uint8_t bus, uint8_t slot, uint8_t func)
pciid_t GetDeviceId(uint32_t devaddr)
{
pciid_t ret;
ret.deviceid = Read16(devaddr, 0x00);
ret.vendorid = Read16(devaddr, 0x02);
ret.deviceid = Read16(devaddr, PCIFIELD_DEVICE_ID);
ret.vendorid = Read16(devaddr, PCIFIELD_VENDOR_ID);
return ret;
}
pcitype_t GetDeviceType(uint32_t devaddr)
{
pcitype_t ret;
ret.classid = Read8(devaddr, 0x08);
ret.subclassid = Read8(devaddr, 0x09);
ret.progif = Read8(devaddr, 0x0A);
ret.revid = Read8(devaddr, 0x0B);
ret.classid = Read8(devaddr, PCIFIELD_CLASS);
ret.subclassid = Read8(devaddr, PCIFIELD_SUBCLASS);
ret.progif = Read8(devaddr, PCIFIELD_PROG_IF);
ret.revid = Read8(devaddr, PCIFIELD_REVISION_ID);
return ret;
}
@ -155,12 +176,12 @@ static uint32_t SearchForDevicesOnBus(uint8_t bus, pcifind_t pcifind, uint32_t l
(!found_any_device || devaddr < next_device) &&
MatchesSearchCriteria(devaddr, pcifind) )
next_device = devaddr, found_any_device = true;
uint8_t header = Read8(devaddr, 0x0D); // Secondary Bus Number.
uint8_t header = Read8(devaddr, PCIFIELD_HEADER_TYPE);
if ( header & 0x80 ) // Multi function device.
num_functions = 8;
if ( (header & 0x7F) == 0x01 ) // PCI to PCI bus.
{
uint8_t subbusid = Read8(devaddr, 0x1A);
uint8_t subbusid = Read8(devaddr, PCIFIELD_SECONDARY_BUS_NUMBER);
uint32_t recret = SearchForDevicesOnBus(subbusid, pcifind, last);
if ( last < recret &&
(!found_any_device || recret < next_device) )

View File

@ -0,0 +1,80 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2014, 2015.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
x86-family/ioport.cpp
IO ports.
*******************************************************************************/
#include <errno.h>
#include <timespec.h>
#include <sortix/clock.h>
#include <sortix/kernel/clock.h>
#include <sortix/kernel/ioport.h>
#include <sortix/kernel/time.h>
namespace Sortix {
bool wait_inport8_clear(uint16_t ioport, uint8_t bits, bool any, unsigned int msecs)
{
struct timespec timeout = timespec_make(msecs / 1000, (msecs % 1000) * 1000000L);
Clock* clock = Time::GetClock(CLOCK_BOOT);
struct timespec begun;
clock->Get(&begun, NULL);
while ( true )
{
struct timespec now;
clock->Get(&now, NULL);
uint8_t reg_snapshop = inport8(ioport);
if ( !any && (reg_snapshop & bits) == 0 )
return true;
if ( any && (reg_snapshop & bits) != bits )
return true;
struct timespec elapsed = timespec_sub(now, begun);
if ( timespec_le(timeout, elapsed) )
return errno = ETIMEDOUT, false;
kthread_yield();
}
}
bool wait_inport8_set(uint16_t ioport, uint8_t bits, bool any, unsigned int msecs)
{
struct timespec timeout = timespec_make(msecs / 1000, (msecs % 1000) * 1000000L);
Clock* clock = Time::GetClock(CLOCK_BOOT);
struct timespec begun;
clock->Get(&begun, NULL);
while ( true )
{
struct timespec now;
clock->Get(&now, NULL);
uint8_t reg_snapshop = inport8(ioport);
if ( !any && (reg_snapshop & bits) == bits )
return true;
if ( any && (reg_snapshop & bits) != 0 )
return true;
struct timespec elapsed = timespec_sub(now, begun);
if ( timespec_le(timeout, elapsed) )
return errno = ETIMEDOUT, false;
kthread_yield();
}
}
} // namespace Sortix