The Pedigree Project  0.1
modules/drivers/x86/pci/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/machine/Pci.h"
21 #include "modules/Module.h"
22 #include "pci_list.h"
23 #include "pedigree/kernel/Log.h"
24 #include "pedigree/kernel/machine/Bus.h"
25 #include "pedigree/kernel/machine/Device.h"
26 #include "pedigree/kernel/processor/IoPort.h"
27 #include "pedigree/kernel/processor/types.h"
28 #include "pedigree/kernel/utilities/String.h"
29 #include "pedigree/kernel/utilities/Vector.h"
30 #include "pedigree/kernel/utilities/utility.h"
31 
32 #define CONFIG_ADDRESS 0
33 #define CONFIG_DATA 4
34 
35 #define MAX_BUS 4
36 
37 static IoPort configSpace("PCI config space");
38 
40 {
41  struct
42  {
43  uint32_t always0 : 2;
44  uint32_t offset : 6;
45  uint32_t function : 3;
46  uint32_t device : 5;
47  uint32_t bus : 8;
48  uint32_t reserved : 7;
49  uint32_t enable : 1;
50  } __attribute__((packed));
51  uint32_t raw;
52 };
53 
54 static void readConfigSpace(Device *pDev, PciBus::ConfigSpace *pCs)
55 {
56  uint32_t *pCs32 = reinterpret_cast<uint32_t *>(pCs);
57  for (unsigned int i = 0; i < sizeof(PciBus::ConfigSpace) / 4; i++)
58  {
59  pCs32[i] = PciBus::instance().readConfigSpace(pDev, i);
60  }
61 }
62 
63 static const char *getVendor(uint16_t vendor)
64 {
65  for (unsigned int i = 0; i < PCI_VENTABLE_LEN; i++)
66  {
67  if (PciVenTable[i].VenId == vendor)
68  return PciVenTable[i].VenShort;
69  }
70  return "";
71 }
72 
73 static const char *getDevice(uint16_t vendor, uint16_t device)
74 {
75  for (unsigned int i = 0; i < PCI_DEVTABLE_LEN; i++)
76  {
77  if (PciDevTable[i].VenId == vendor && PciDevTable[i].DevId == device)
78  return PciDevTable[i].ChipDesc;
79  }
80  return "";
81 }
82 
83 static bool entry()
84 {
85  for (int iBus = 0; iBus < MAX_BUS; iBus++)
86  {
87  // Firstly add the ISA bus.
88  char *str = new char[256];
89  StringFormat(str, "PCI #%d", iBus);
90  Bus *pBus = new Bus(str);
91  pBus->setSpecificType(String("pci"));
92 
93  for (int iDevice = 0; iDevice < 32; iDevice++)
94  {
95  bool bIsMultifunc = false;
96  for (int iFunc = 0; iFunc < 8; iFunc++)
97  {
98  if (iFunc > 0 && !bIsMultifunc)
99  break;
100 
101  Device *pDevice = new Device();
102  pDevice->setPciPosition(iBus, iDevice, iFunc);
103 
104  uint32_t vendorAndDeviceId =
105  PciBus::instance().readConfigSpace(pDevice, 0);
106  if ((vendorAndDeviceId & 0xFFFF) == 0xFFFF ||
107  (vendorAndDeviceId & 0xFFFF) == 0)
108  {
109  delete pDevice;
113  continue;
114  // break;
115  }
116 
118  readConfigSpace(pDevice, &cs);
119 
120  if (cs.header_type & 0x80)
121  bIsMultifunc = true;
122 
123  NOTICE(
124  "PCI: " << Dec << iBus << ":" << iDevice << ":" << iFunc
125  << "\t Vendor:" << Hex << cs.vendor
126  << " Device:" << cs.device);
127 
128  char c[256];
129  StringFormat(
130  c, "%s - %s", getDevice(cs.vendor, cs.device),
131  getVendor(cs.vendor));
132  pDevice->setSpecificType(String(c));
133  NOTICE("PCI: " << c);
134  pDevice->setPciIdentifiers(
135  cs.class_code, cs.subclass, cs.vendor, cs.device,
136  cs.progif);
137  NOTICE(
138  "PCI: Class: " << cs.class_code
139  << " Subclass: " << cs.subclass
140  << " ProgIF: " << cs.progif);
141 
142  for (int l = 0; l < 6; l++)
143  {
144  // PCI-PCI bridges have a different layout for the last 4
145  // BARs: they hold extra data.
146  if ((cs.header_type & 0x7F) == 0x1 && l >= 2)
147  {
148  break;
149  }
150 
151  if (cs.bar[l] == 0)
152  continue;
153 
154  // Write the BAR with FFFFFFFF to discover the size of
155  // mapping that the device requires.
156  uint8_t offset = (0x10 + l * 4) >> 2;
157  PciBus::instance().writeConfigSpace(
158  pDevice, offset, 0xFFFFFFFF);
159  uint32_t mask =
160  PciBus::instance().readConfigSpace(pDevice, offset);
161  PciBus::instance().writeConfigSpace(
162  pDevice, offset, cs.bar[l]);
163 
164  // Now work out how much space is required to fill that
165  // mask. Assume it doesn't need 4GB of space...
166  uint32_t size = ~(mask & 0xFFFFFFF0) +
167  1; // AND with ~0xF to get rid of the flags
168  // field in the bottom 4 bits.
169 
170  bool io = (cs.bar[l] & 0x1);
171  if (io)
172  // IO space is only 64K in size.
173  size &= 0xFFFF;
174 
175  StringFormat(c, "bar%d", l);
176  uintptr_t s = (cs.bar[l] & 0xFFFFFFF0);
177 
178  NOTICE(
179  "PCI: BAR" << Dec << l << Hex << ": " << s << ".."
180  << (s + size) << " (" << io << ")");
181  Device::Address *pAddress = new Device::Address(
182  String(c), cs.bar[l] & 0xFFFFFFF0, size,
183  (cs.bar[l] & 0x1) == 0x1);
184  pDevice->addresses().pushBack(pAddress);
185  }
186 
187  NOTICE(
188  "PCI: IRQ: L" << cs.interrupt_line << " P"
189  << cs.interrupt_pin);
190  pDevice->setInterruptNumber(cs.interrupt_line);
191  pBus->addChild(pDevice);
192  pDevice->setParent(pBus);
193 
194  pDevice->setPciConfigHeader(cs);
195  }
196  }
197 
198  // If the bus was actually populated...
199  if (pBus->getNumChildren() > 0)
200  {
201  Device::addToRoot(pBus);
202  }
203  else
204  {
205  delete pBus;
206  }
207  }
208 
209  return true;
210 }
211 
212 static void exit()
213 {
214 }
215 
216 MODULE_INFO("pci", &entry, &exit);
size_t getNumChildren()
Definition: Device.cc:137
virtual void setInterruptNumber(uintptr_t n)
Definition: Device.h:268
virtual Vector< Address * > & addresses()
Definition: Device.h:256
static void addToRoot(Device *device)
Definition: Device.cc:102
Definition: String.h:49
Definition: Device.h:43
Definition: Bus.h:31
I/O port range.
Definition: IoPort.h:34
virtual void setSpecificType(String str)
Definition: Device.h:174
#define NOTICE(text)
Definition: Log.h:74
uint32_t readConfigSpace(Device *pDev, uint8_t offset)
Definition: Pci.cc:75
void addChild(Device *pDevice)
Definition: Device.cc:127
Definition: Log.h:136
void setPciPosition(uint32_t bus, uint32_t device, uint32_t func)
Definition: Device.h:180
void setParent(Device *p)
Definition: Device.h:154
void setPciIdentifiers(uint8_t classCode, uint8_t subclassCode, uint16_t vendorId, uint16_t deviceId, uint8_t progIf)
Definition: Device.h:188
void setPciConfigHeader(const PciBus::ConfigSpace &space)
Definition: Device.h:199
Definition: Log.h:138
void writeConfigSpace(Device *pDev, uint8_t offset, uint32_t data)
Definition: Pci.cc:104