5 #include "devices/pci.h"
6 #include "threads/io.h"
7 #include "threads/malloc.h"
9 struct list pci_dev_list;
11 static void scan_bus(uint8_t bus);
14 pci_read_config (unsigned bus, unsigned dev, unsigned func, unsigned reg)
22 0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg << 2));
27 pci_write_config (unsigned bus, unsigned dev, unsigned func, unsigned reg,
36 0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg << 2));
41 pci_dump_dev (struct pci_dev *dev)
45 printf ("PCI: Device %04x:%02x:%02x.%x %04x:%04x\n",
46 0, dev->bus_id, dev->devfn >> 4, dev->devfn & 0xf,
47 dev->ven_id, dev->dev_id);
48 printf ("PCI: Class %02x:%02x:%02x\n",
49 dev->base_class, dev->sub_class, dev->interface);
51 for (bar = 0; bar < PCI_NUM_BARS; bar++)
53 if (dev->resources[bar].start != 0 ||
54 dev->resources[bar].end != 0)
57 dev->resources[bar].type == PCI_BAR_TYPE_MEM
59 printf ("range %d: %08x-%08x\n",
60 bar, dev->resources[bar].start, dev->resources[bar].end);
66 pci_setup_bases (struct pci_dev *dev)
73 for (bar = 0; bar < PCI_NUM_BARS; bar++)
75 bar_reg = PCI_REGNUM_BASE_ADDRESS + bar;
77 res = &dev->resources[bar];
81 /* Get the base address out of the BAR */
82 base = pci_read_config(dev->bus_id,
87 /* Write 1's and get the size from the BAR */
88 pci_write_config(dev->bus_id,
93 size = pci_read_config(dev->bus_id,
98 /* Put the base address back in the BAR */
99 pci_write_config(dev->bus_id,
105 /* If the size is unreasonable, skip this BAR.
106 Is this redundant for Pintos? */
107 if (!size || size == 0xffffffff) {
111 /* Broken hardware that requests a base at the end?
112 Maybe redundant for Pintos? */
113 if (base == 0xffffffff) {
117 /* Make a new resource, tag it for I/O vs. memory */
118 res->type = base & PCI_BAR_TYPE_MASK;
119 if (res->type == PCI_BAR_TYPE_MEM)
121 res->start = base & PCI_BAR_MASK_MEM;
122 size = size & PCI_BAR_MASK_MEM;
126 res->start = base & PCI_BAR_MASK_IO;
127 size = size & PCI_BAR_MASK_IO;
129 res->end = res->start + size;
134 scan_device (uint8_t bus, uint8_t dev, uint8_t func)
138 int dev_id, vendor_id;
141 struct pci_dev *new_pci_dev;
143 byte_cfg = (uint8_t *) cfg;
145 /* Read configuration space header */
146 for (reg = 0; reg < 16; reg++)
147 cfg[reg] = pci_read_config (bus, dev, func, reg);
149 /* Get vendor and device ID */
150 dev_id = cfg[0] >> 16;
151 vendor_id = cfg[0] & 0xffff;
153 if (dev_id == 0 || dev_id == PCI_BAD_DEVICE ||
154 vendor_id == 0 || vendor_id == PCI_BAD_DEVICE)
157 /* We have a valid PCI device, set it up */
158 new_pci_dev = malloc (sizeof *new_pci_dev);
160 PANIC ("couldn't allocate memory for PCI device");
162 new_pci_dev->bus_id = bus;
163 new_pci_dev->devfn = (dev << 4) | func;
164 new_pci_dev->ven_id = vendor_id;
165 new_pci_dev->dev_id = dev_id;
166 new_pci_dev->base_class = byte_cfg[PCI_REG_CLASS_BASE];
167 new_pci_dev->sub_class = byte_cfg[PCI_REG_CLASS_SUB];
168 new_pci_dev->interface = byte_cfg[PCI_REG_CLASS_INTERFACE];
169 list_push_front (&pci_dev_list, &new_pci_dev->elem);
171 /* If device is PCI-to-PCI bridge, scan the bus behind it */
172 if (new_pci_dev->base_class == PCI_BRIDGE_BASE_CLASS &&
173 new_pci_dev->sub_class == PCI_BRIDGE_SUB_CLASS &&
174 (byte_cfg[PCI_REG_HEADER_TYPE] & 0x3f) == PCI_BRIDGE_HEADER_TYPE)
176 scan_bus(byte_cfg[PCI_BRIDGE_REG_SBUS]);
179 /* For normal devices, set up the BARs */
182 pci_setup_bases (new_pci_dev);
185 /* Debugging output */
186 pci_dump_dev(new_pci_dev);
187 /*for (line = 0; line < 16; line++)
191 printf ("PCI: %02x:", line * 4);
192 for (byte = 3; byte >= 0; byte--)
193 printf (" %02x", byte_cfg[line * 4 + byte]);
199 /* Return if we're a multifunction device */
200 return byte_cfg[PCI_REG_HEADER_TYPE] & 0x80;
204 scan_bus(uint8_t bus)
208 printf ("PCI: Scanning bus (%u)\n", bus);
211 for (dev = 0; dev < 32; dev++)
213 /* Returns true if device is multi-function */
214 if (scan_device (bus, dev, 0))
218 for (func = 1; func < 8; func++)
219 scan_device (bus, dev, func);
222 printf ("PCI: Done (%u)\n", bus);
230 printf ("PCI: Initializating\n");
231 list_init (&pci_dev_list);
233 printf ("PCI: Initialization done\n");
241 for (e = list_begin (&pci_dev_list); e != list_end (&pci_dev_list);
244 struct pci_dev *dev = list_entry (e, struct pci_dev, elem);