The Pedigree Project 0.1
mach_pc/Pci.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/LockGuard.h"
21#include "pedigree/kernel/Log.h"
22#include "pedigree/kernel/Spinlock.h"
23#include "pedigree/kernel/machine/Device.h"
24#include "pedigree/kernel/machine/Machine.h"
25#include "pedigree/kernel/machine/Pci.h"
26#include "pedigree/kernel/machine/PciConfigAccess.h"
27#include "pedigree/kernel/processor/IoPort.h"
28
29#include "Pic.h"
30
31namespace {
32IoPort configSpace("PCI config space");
33Spinlock configLock(false);
34bool configAvailable = false;
35PciConfigAccess<IoPort, Spinlock> config(configSpace, configLock);
36
37struct FunctionConfig {
38 Device* device;
39 bool read8(uint16_t offset, uint8_t& value) {
40 return PciBus::instance().readConfig8(device, offset, value);
41 }
42 bool read16(uint16_t offset, uint16_t& value) {
43 return PciBus::instance().readConfig16(device, offset, value);
44 }
45 bool read32(uint16_t offset, uint32_t& value) {
46 return PciBus::instance().readConfig32(device, offset, value);
47 }
48 bool write16(uint16_t offset, uint16_t value) {
49 return PciBus::instance().writeConfig16(device, offset, value);
50 }
51};
52
53bool readFunction(Device* device, uint16_t offset, uint8_t width, uint32_t& value) {
54 return configAvailable && device &&
55 config.read(device->getPciBusPosition(), device->getPciDevicePosition(),
56 device->getPciFunctionNumber(), offset, width, value);
57}
58bool writeFunction(Device* device, uint16_t offset, uint8_t width, uint32_t value) {
59 return configAvailable && device &&
60 config.write(device->getPciBusPosition(), device->getPciDevicePosition(),
61 device->getPciFunctionNumber(), offset, width, value);
62}
63} // namespace
64
65PciBus PciBus::m_Instance;
66PciBus::PciBus() {}
67PciBus::~PciBus() {}
68
70 if (!configSpace.allocate(0xCF8, 8)) {
71 ERROR("PCI: Config space - unable to allocate IO port!");
72 return;
73 }
74 {
75 LockGuard<Spinlock> guard(configLock);
76 configSpace.write32(0x80000000, 0);
77 configAvailable = configSpace.read32(0) == 0x80000000;
78 }
79 if (!configAvailable)
80 ERROR("PCI: Controller not detected.");
81}
82
83uint32_t PciBus::readConfigSpace(Device* device, uint8_t offset) {
84 uint32_t value = 0xffffffffU;
85 readConfig32(device, uint16_t{offset} * 4, value);
86 return value;
87}
88uint32_t PciBus::readConfigSpace(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset) {
89 uint32_t value = 0xffffffffU;
90 if (configAvailable)
91 config.read(bus, device, function, uint16_t{offset} * 4, 4, value);
92 return value;
93}
94void PciBus::writeConfigSpace(Device* device, uint8_t offset, uint32_t value) {
95 writeConfig32(device, uint16_t{offset} * 4, value);
96}
97void PciBus::writeConfigSpace(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset,
98 uint32_t value) {
99 if (configAvailable)
100 config.write(bus, device, function, uint16_t{offset} * 4, 4, value);
101}
102bool PciBus::readConfig8(Device* device, uint16_t offset, uint8_t& value) {
103 uint32_t data = 0;
104 if (!readFunction(device, offset, 1, data))
105 return false;
106 value = data;
107 return true;
108}
109bool PciBus::readConfig16(Device* device, uint16_t offset, uint16_t& value) {
110 uint32_t data = 0;
111 if (!readFunction(device, offset, 2, data))
112 return false;
113 value = data;
114 return true;
115}
116bool PciBus::readConfig32(Device* device, uint16_t offset, uint32_t& value) {
117 return readFunction(device, offset, 4, value);
118}
119bool PciBus::writeConfig8(Device* device, uint16_t offset, uint8_t value) {
120 return writeFunction(device, offset, 1, value);
121}
122bool PciBus::writeConfig16(Device* device, uint16_t offset, uint16_t value) {
123 return writeFunction(device, offset, 2, value);
124}
125bool PciBus::writeConfig32(Device* device, uint16_t offset, uint32_t value) {
126 return writeFunction(device, offset, 4, value);
127}
128bool PciBus::updateCommand(Device* device, uint16_t clearBits, uint16_t setBits) {
129 return configAvailable && device &&
130 config.updateCommand(device->getPciBusPosition(), device->getPciDevicePosition(),
131 device->getPciFunctionNumber(), clearBits, setBits);
132}
133bool PciBus::inspectFunction(Device* device, PciFunctionState::State& state) {
134 FunctionConfig function{device};
135 return PciFunctionState::inspect(function, state) &&
136 state.interruptLine == device->getInterruptNumber();
137}
138bool PciBus::disableMessageInterrupts(Device* device, const PciFunctionState::State& state) {
139 FunctionConfig function{device};
140 return PciFunctionState::disableMessageInterrupts(function, state);
141}
142bool PciBus::resourcesUnchanged(Device* device, const PciFunctionState::State& state) {
143 FunctionConfig function{device};
144 return PciFunctionState::resourcesUnchanged(function, state);
145}
146
147bool PciBus::translateAddress(uint64_t pciAddress, uint64_t, bool, uint64_t& cpuPhysical) {
148 cpuPhysical = pciAddress;
149 return true;
150}
151
152bool PciBus::busRange(uint8_t& first, uint8_t& last) {
153 first = 0;
154 last = 3;
155 return true;
156}
157
158uint32_t PciBus::interruptRoute(uint8_t, uint8_t, uint8_t, uint8_t) {
159 return 0;
160}
161
162bool PciBus::assignBar(Device*, uint8_t, uint32_t, uint32_t, uint32_t, uint32_t) {
163 return true;
164}
165
166bool PciBus::reserveLegacyInterrupt(uint8_t irq) {
167 return Machine::instance().getIrqManager() == &Pic::instance() &&
169}
I/O port range.
Definition IoPort.h:33
Definition Pci.h:30
uint32_t readConfigSpace(Device *pDev, uint8_t offset)
bool translateAddress(uint64_t pciAddress, uint64_t bytes, bool io, uint64_t &cpuPhysical)
bool busRange(uint8_t &first, uint8_t &last)
void writeConfigSpace(Device *pDev, uint8_t offset, uint32_t data)
bool assignBar(Device *device, uint8_t index, uint32_t low, uint32_t high, uint32_t maskLow, uint32_t maskHigh)
void initialise()
static Pic & instance()
Definition Pic.h:54
bool reservePciRoute(uint8_t irq)
Definition Pic.cc:226