2020-02-10 00:15:37 +01:00
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
// GNU GPL OS/K //
|
|
|
|
// //
|
2020-02-10 00:49:35 +01:00
|
|
|
// Desc: PCI driver //
|
2020-02-10 00:15:37 +01:00
|
|
|
// //
|
|
|
|
// //
|
|
|
|
// Copyright © 2018-2020 The OS/K Team //
|
|
|
|
// //
|
|
|
|
// This file is part of OS/K. //
|
|
|
|
// //
|
|
|
|
// OS/K 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 //
|
|
|
|
// any later version. //
|
|
|
|
// //
|
|
|
|
// OS/K 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 OS/K. If not, see <https://www.gnu.org/licenses/>. //
|
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
|
|
|
|
#include <io/pci.h>
|
|
|
|
#include <io/acpi.h>
|
2020-02-11 23:47:02 +01:00
|
|
|
#include <mm/paging.h>
|
2020-02-10 00:15:37 +01:00
|
|
|
|
2020-02-13 13:40:07 +01:00
|
|
|
static void *pciConfigBaseAddress = NULL;
|
2020-02-17 19:17:52 +01:00
|
|
|
static MCFG_t *MCFG_table = NULL;
|
2020-02-10 00:15:37 +01:00
|
|
|
|
2020-02-13 13:40:07 +01:00
|
|
|
// -------------------------------------------------------------------------- //
|
2020-02-11 23:47:02 +01:00
|
|
|
|
2020-02-13 13:40:07 +01:00
|
|
|
static inline void* pciGetConfigAddr(uchar bus, uchar device,
|
2020-02-12 17:48:05 +01:00
|
|
|
uchar function, ushort offset)
|
2020-02-11 23:47:02 +01:00
|
|
|
{
|
|
|
|
if(device > 32) {
|
2020-02-13 13:06:18 +01:00
|
|
|
DebugLog("pciGetConfigAddr(): bad device ID\n");
|
2020-02-11 23:47:02 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if(function > 8) {
|
2020-02-13 13:06:18 +01:00
|
|
|
DebugLog("pciGetConfigAddr(): bad function ID\n");
|
2020-02-11 23:47:02 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if(offset > 4096) {
|
2020-02-13 13:06:18 +01:00
|
|
|
DebugLog("pciGetConfigAddr(): bad register offset\n");
|
2020-02-11 23:47:02 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2020-02-12 13:15:10 +01:00
|
|
|
|
2020-02-12 17:48:05 +01:00
|
|
|
return (void*)(bus*32*8*4096 + device*8*4096 + function*4096 +
|
|
|
|
offset + (ulong)pciConfigBaseAddress);
|
2020-02-11 23:47:02 +01:00
|
|
|
}
|
|
|
|
|
2020-02-12 17:48:05 +01:00
|
|
|
static inline uchar pciReadConfigByte(uchar bus, uchar device,
|
|
|
|
uchar function, ushort offset)
|
2020-02-11 23:47:02 +01:00
|
|
|
{
|
2020-02-12 13:15:10 +01:00
|
|
|
return *((uchar*)(pciGetConfigAddr(bus, device, function, offset)));
|
2020-02-11 23:47:02 +01:00
|
|
|
}
|
|
|
|
|
2020-02-12 17:48:05 +01:00
|
|
|
static inline ushort pciReadConfigWord(uchar bus, uchar device,
|
|
|
|
uchar function, ushort offset)
|
2020-02-11 23:47:02 +01:00
|
|
|
{
|
|
|
|
return *((ushort*)(pciGetConfigAddr(bus, device, function, offset)));
|
|
|
|
}
|
|
|
|
|
2020-02-12 17:48:05 +01:00
|
|
|
static inline uint pciReadConfigDWord(uchar bus, uchar device,
|
|
|
|
uchar function, ushort offset)
|
2020-02-11 23:47:02 +01:00
|
|
|
{
|
|
|
|
return *((uint*)(pciGetConfigAddr(bus, device, function, offset)));
|
|
|
|
}
|
|
|
|
|
2020-02-12 23:55:54 +01:00
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
|
|
|
|
uchar IoPciReadConfigByte(PciDev_t *device, ushort offset)
|
|
|
|
{
|
|
|
|
return *((uchar *)((ulong)device->configAddr + offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
ushort IoPciReadConfigWord(PciDev_t *device, ushort offset)
|
|
|
|
{
|
|
|
|
return *((ushort *)((ulong)device->configAddr + offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
uint IoPciReadConfigDWord(PciDev_t *device, ushort offset)
|
|
|
|
{
|
|
|
|
return *((uint *)((ulong)device->configAddr + offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void IoPciWriteConfigByte(PciDev_t *device, ushort offset, uchar data)
|
|
|
|
{
|
|
|
|
memmove((void *)((ulong)device->configAddr + offset), &data, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void IoPciWriteConfigWord(PciDev_t *device, ushort offset, ushort data)
|
|
|
|
{
|
|
|
|
memmove((void *)((ulong)device->configAddr + offset), &data, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void IoPciWriteConfigDWord(PciDev_t *device, ushort offset, uint data)
|
|
|
|
{
|
|
|
|
memmove((void *)((ulong)device->configAddr + offset), &data, 4);
|
|
|
|
}
|
|
|
|
|
2020-02-12 17:48:05 +01:00
|
|
|
void IoPciEnumerate()
|
2020-02-11 23:47:02 +01:00
|
|
|
{
|
|
|
|
if(pciConfigBaseAddress == NULL) {
|
2020-02-13 13:06:18 +01:00
|
|
|
KeStartPanic("Unable to access PCI configuration : MCFG table not reachable\n");
|
2020-02-11 23:47:02 +01:00
|
|
|
return;
|
|
|
|
}
|
2020-02-12 13:15:10 +01:00
|
|
|
|
2020-02-12 18:28:32 +01:00
|
|
|
for(ushort bus = 0; bus < 256; bus++) {
|
2020-02-11 23:47:02 +01:00
|
|
|
for(uchar device = 0; device < 32; device++) {
|
|
|
|
for(uchar function = 0; function < 8; function++) {
|
2020-02-12 18:28:32 +01:00
|
|
|
ushort vendor = pciReadConfigWord((uchar)bus, device, function, PCI_REG_VENDOR);
|
2020-02-17 19:17:52 +01:00
|
|
|
if(bus * device * function > MCFG_table->length) break;
|
2020-02-11 23:47:02 +01:00
|
|
|
if(vendor == 0xffff) continue;
|
2020-02-17 18:47:23 +01:00
|
|
|
DebugLog("PCI device class: %x, subclass: %x, vendor: %x, device: %x\n",
|
|
|
|
pciReadConfigByte((uchar)bus, device, function, PCI_REG_CLASS),
|
|
|
|
pciReadConfigByte((uchar)bus, device, function, PCI_REG_SUBCLASS),
|
2020-02-12 17:48:05 +01:00
|
|
|
vendor,
|
2020-02-12 18:28:32 +01:00
|
|
|
pciReadConfigWord((uchar)bus, device, function, PCI_REG_DEVICE)
|
2020-02-12 17:48:05 +01:00
|
|
|
);
|
2020-02-11 23:47:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-02-12 18:28:32 +01:00
|
|
|
}
|
|
|
|
|
2020-02-12 23:55:54 +01:00
|
|
|
PciDev_t *IoPciGetDevice(ushort vendorID, ushort deviceID)
|
2020-02-12 18:28:32 +01:00
|
|
|
{
|
|
|
|
if(pciConfigBaseAddress == NULL) {
|
2020-02-13 13:06:18 +01:00
|
|
|
KeStartPanic("Unable to access PCI configuration : MCFG table not reachable\n");
|
2020-02-12 18:28:32 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(ushort bus = 0; bus < 256; bus++) {
|
|
|
|
for(uchar device = 0; device < 32; device++) {
|
|
|
|
for(uchar function = 0; function < 8; function++) {
|
|
|
|
if(vendorID == pciReadConfigWord((uchar)bus, device, function, PCI_REG_VENDOR)
|
|
|
|
&& deviceID == pciReadConfigWord((uchar)bus, device, function, PCI_REG_DEVICE)) {
|
2020-02-17 19:17:52 +01:00
|
|
|
if(bus * device * function > MCFG_table->length) break;
|
2020-02-12 23:55:54 +01:00
|
|
|
PciDev_t *pciDevicePtr = (PciDev_t *)malloc(sizeof(PciDev_t));
|
2020-02-12 18:28:32 +01:00
|
|
|
pciDevicePtr->vendorID = vendorID;
|
|
|
|
pciDevicePtr->deviceID = deviceID;
|
2020-02-17 18:58:45 +01:00
|
|
|
pciDevicePtr->classID = pciReadConfigByte((uchar)bus, device, function, PCI_REG_CLASS);
|
|
|
|
pciDevicePtr->subclassID = pciReadConfigByte((uchar)bus, device, function, PCI_REG_SUBCLASS);
|
|
|
|
pciDevicePtr->configAddr = pciGetConfigAddr((uchar)bus, device, function, 0);
|
|
|
|
return pciDevicePtr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
PciDev_t *IoPciGetDeviceByClass(uchar classID, uchar subclassID)
|
|
|
|
{
|
|
|
|
if(pciConfigBaseAddress == NULL) {
|
|
|
|
KeStartPanic("Unable to access PCI configuration : MCFG table not reachable\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(ushort bus = 0; bus < 256; bus++) {
|
|
|
|
for(uchar device = 0; device < 32; device++) {
|
|
|
|
for(uchar function = 0; function < 8; function++) {
|
|
|
|
if(classID == pciReadConfigByte((uchar)bus, device, function, PCI_REG_CLASS)
|
|
|
|
&& subclassID == pciReadConfigByte((uchar)bus, device, function, PCI_REG_SUBCLASS)) {
|
|
|
|
PciDev_t *pciDevicePtr = (PciDev_t *)malloc(sizeof(PciDev_t));
|
|
|
|
pciDevicePtr->vendorID = pciReadConfigWord((uchar)bus, device, function, PCI_REG_VENDOR);
|
|
|
|
pciDevicePtr->deviceID = pciReadConfigWord((uchar)bus, device, function, PCI_REG_DEVICE);
|
|
|
|
pciDevicePtr->classID = classID;
|
|
|
|
pciDevicePtr->subclassID = subclassID;
|
2020-02-12 18:28:32 +01:00
|
|
|
pciDevicePtr->configAddr = pciGetConfigAddr((uchar)bus, device, function, 0);
|
|
|
|
return pciDevicePtr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
2020-02-11 23:47:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void IoInitPCI()
|
2020-02-10 00:15:37 +01:00
|
|
|
{
|
2020-02-17 19:17:52 +01:00
|
|
|
MCFG_table = (MCFG_t*)IoGetAcpiTable(SDT_MCFG);
|
2020-02-11 23:47:02 +01:00
|
|
|
if(MCFG_table == NULL) {
|
2020-02-13 13:06:18 +01:00
|
|
|
KeStartPanic("Unable to access PCI configuration : MCFG table not reachable\n");
|
2020-02-10 00:15:37 +01:00
|
|
|
}
|
2020-02-11 23:47:02 +01:00
|
|
|
pciConfigBaseAddress = MCFG_table->pciConfigBaseAddress;
|
|
|
|
DebugLog("PCI Config Base address = 0x%p\n", pciConfigBaseAddress);
|
|
|
|
|
2020-02-12 23:55:54 +01:00
|
|
|
// Give R/W access to the configuration space
|
2020-02-17 18:58:45 +01:00
|
|
|
int maxI = (MCFG_table->length) / KPAGESIZE; // More secure,
|
2020-02-13 15:32:20 +01:00
|
|
|
for(int i=0; i < maxI; i++)
|
2020-02-12 23:55:54 +01:00
|
|
|
{
|
2020-02-17 18:58:45 +01:00
|
|
|
// XXX verify that page is marked busy
|
|
|
|
|
2020-02-13 13:06:18 +01:00
|
|
|
MmMapPage((void *)((ulong)pciConfigBaseAddress + i * KPAGESIZE),
|
|
|
|
(void *)((ulong)pciConfigBaseAddress + i * KPAGESIZE),
|
|
|
|
PRESENT | READWRITE);
|
2020-02-12 23:55:54 +01:00
|
|
|
}
|
2020-02-15 11:11:49 +01:00
|
|
|
|
|
|
|
IoPciEnumerate();
|
2020-02-17 18:59:04 +01:00
|
|
|
}
|