Fix PCI code.
This commit is contained in:
parent
1bc2650413
commit
4f7c5ebdd3
|
@ -45,6 +45,7 @@ ifdef X86FAMILY
|
||||||
x86-family/memorymanagement.o \
|
x86-family/memorymanagement.o \
|
||||||
$(CPU)/interrupt.o \
|
$(CPU)/interrupt.o \
|
||||||
x86-family/interrupt.o \
|
x86-family/interrupt.o \
|
||||||
|
x86-family/ioport.o \
|
||||||
x86-family/pic.o \
|
x86-family/pic.o \
|
||||||
x86-family/gdt.o \
|
x86-family/gdt.o \
|
||||||
x86-family/idt.o \
|
x86-family/idt.o \
|
||||||
|
|
|
@ -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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -55,10 +55,10 @@ typedef struct
|
||||||
uint8_t revid;
|
uint8_t revid;
|
||||||
} pcifind_t;
|
} pcifind_t;
|
||||||
|
|
||||||
const uint8_t PCIBAR_TYPE_IOSPACE = 0x0 << 1 | 0x1 << 0;
|
static const uint8_t PCIBAR_TYPE_IOSPACE = 0x0 << 1 | 0x1 << 0;
|
||||||
const uint8_t PCIBAR_TYPE_16BIT = 0x1 << 1 | 0x0 << 0;
|
static const uint8_t PCIBAR_TYPE_16BIT = 0x1 << 1 | 0x0 << 0;
|
||||||
const uint8_t PCIBAR_TYPE_32BIT = 0x0 << 1 | 0x0 << 0;
|
static 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_64BIT = 0x2 << 1 | 0x0 << 0;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -67,9 +67,12 @@ public:
|
||||||
uint64_t size_raw;
|
uint64_t size_raw;
|
||||||
|
|
||||||
public:
|
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; }
|
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; };
|
uint32_t ioaddr() const { return addr_raw & 0xFFFFFFFC; };
|
||||||
bool is_prefetchable() const { return addr_raw & 0x8; }
|
bool is_prefetchable() const { return addr_raw & 0x8; }
|
||||||
bool is_iospace() const { return type() == PCIBAR_TYPE_IOSPACE; }
|
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(); }
|
bool is_mmio() const { return is_16bit() || is_32bit() || is_64bit(); }
|
||||||
} pcibar_t;
|
} 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 {
|
namespace PCI {
|
||||||
|
|
||||||
void Init();
|
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
|
uint16_t Read16(uint32_t devaddr, uint8_t off); // Host endian
|
||||||
uint32_t Read32(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
|
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 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
|
void WriteRaw32(uint32_t devaddr, uint8_t off, uint32_t val); // PCI endian
|
||||||
pciid_t GetDeviceId(uint32_t devaddr);
|
pciid_t GetDeviceId(uint32_t devaddr);
|
||||||
|
|
|
@ -56,12 +56,14 @@ void SplitDevAddr(uint32_t devaddr, uint8_t* vals /* bus, slot, func */)
|
||||||
|
|
||||||
uint32_t ReadRaw32(uint32_t devaddr, uint8_t off)
|
uint32_t ReadRaw32(uint32_t devaddr, uint8_t off)
|
||||||
{
|
{
|
||||||
|
assert((off & 0x3) == 0);
|
||||||
outport32(CONFIG_ADDRESS, devaddr + off);
|
outport32(CONFIG_ADDRESS, devaddr + off);
|
||||||
return inport32(CONFIG_DATA);
|
return inport32(CONFIG_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteRaw32(uint32_t devaddr, uint8_t off, uint32_t val)
|
void WriteRaw32(uint32_t devaddr, uint8_t off, uint32_t val)
|
||||||
{
|
{
|
||||||
|
assert((off & 0x3) == 0);
|
||||||
outport32(CONFIG_ADDRESS, devaddr + off);
|
outport32(CONFIG_ADDRESS, devaddr + off);
|
||||||
outport32(CONFIG_DATA, val);
|
outport32(CONFIG_DATA, val);
|
||||||
}
|
}
|
||||||
|
@ -76,23 +78,42 @@ void Write32(uint32_t devaddr, uint8_t off, uint32_t val)
|
||||||
WriteRaw32(devaddr, off, htole32(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)
|
uint16_t Read16(uint32_t devaddr, uint8_t off)
|
||||||
{
|
{
|
||||||
assert((off & 0x1) == 0);
|
assert((off & 0x1) == 0);
|
||||||
uint8_t alignedoff = off & ~0x3;
|
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);
|
val32 = ReadRaw32(devaddr, alignedoff);
|
||||||
uint16_t ret = off & 0x2 ? val16[0] : val16[1];
|
return (uint16_t) val8[(off & 0x3) + 0] << 0 |
|
||||||
return le16toh(ret);
|
(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 Read8(uint32_t devaddr, uint8_t off)
|
||||||
{
|
{
|
||||||
uint8_t alignedoff = off & ~0x1;
|
uint8_t alignedoff = off & ~0x3;
|
||||||
union { uint8_t val8[2]; uint32_t val16; };
|
union { uint8_t val8[4]; uint32_t val32; };
|
||||||
val16 = htole16(Read16(devaddr, alignedoff));
|
val32 = ReadRaw32(devaddr, alignedoff);
|
||||||
uint8_t ret = off & 0x1 ? val8[0] : val8[1];
|
return val8[(off & 0x3)];
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t CheckDevice(uint8_t bus, uint8_t slot, uint8_t func)
|
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 GetDeviceId(uint32_t devaddr)
|
||||||
{
|
{
|
||||||
pciid_t ret;
|
pciid_t ret;
|
||||||
ret.deviceid = Read16(devaddr, 0x00);
|
ret.deviceid = Read16(devaddr, PCIFIELD_DEVICE_ID);
|
||||||
ret.vendorid = Read16(devaddr, 0x02);
|
ret.vendorid = Read16(devaddr, PCIFIELD_VENDOR_ID);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
pcitype_t GetDeviceType(uint32_t devaddr)
|
pcitype_t GetDeviceType(uint32_t devaddr)
|
||||||
{
|
{
|
||||||
pcitype_t ret;
|
pcitype_t ret;
|
||||||
ret.classid = Read8(devaddr, 0x08);
|
ret.classid = Read8(devaddr, PCIFIELD_CLASS);
|
||||||
ret.subclassid = Read8(devaddr, 0x09);
|
ret.subclassid = Read8(devaddr, PCIFIELD_SUBCLASS);
|
||||||
ret.progif = Read8(devaddr, 0x0A);
|
ret.progif = Read8(devaddr, PCIFIELD_PROG_IF);
|
||||||
ret.revid = Read8(devaddr, 0x0B);
|
ret.revid = Read8(devaddr, PCIFIELD_REVISION_ID);
|
||||||
return ret;
|
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) &&
|
(!found_any_device || devaddr < next_device) &&
|
||||||
MatchesSearchCriteria(devaddr, pcifind) )
|
MatchesSearchCriteria(devaddr, pcifind) )
|
||||||
next_device = devaddr, found_any_device = true;
|
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.
|
if ( header & 0x80 ) // Multi function device.
|
||||||
num_functions = 8;
|
num_functions = 8;
|
||||||
if ( (header & 0x7F) == 0x01 ) // PCI to PCI bus.
|
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);
|
uint32_t recret = SearchForDevicesOnBus(subbusid, pcifind, last);
|
||||||
if ( last < recret &&
|
if ( last < recret &&
|
||||||
(!found_any_device || recret < next_device) )
|
(!found_any_device || recret < next_device) )
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue