2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * Copyright (c) 2016 Netflix, Inc
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
31 * PnP enumerator using the PCI BIOS.
35 #include <machine/stdarg.h>
36 #include <bootstrap.h>
43 * Stupid PCI BIOS interface doesn't let you simply enumerate everything
44 * that's there, instead you have to ask it if it has something.
46 * So we have to scan by class code, subclass code and sometimes programming
56 static struct pci_progif progif_null
[] = {
61 static struct pci_progif progif_display
[] = {
67 static struct pci_progif progif_ide
[] = {
103 static struct pci_progif progif_serial
[] = {
110 static struct pci_progif progif_parallel
[] = {
112 {0x1, "Bidirectional"},
117 static struct pci_progif progif_firewire
[] = {
126 struct pci_progif
*ps_progif
; /* if set, use for programming interface value(s) */
129 static struct pci_subclass subclass_old
[] = {
130 {0x0, "Old non-VGA", progif_null
},
131 {0x1, "Old VGA", progif_null
},
135 static struct pci_subclass subclass_mass
[] = {
136 {0x0, "SCSI", progif_null
},
137 {0x1, "IDE", progif_ide
},
138 {0x2, "Floppy disk", progif_null
},
139 {0x3, "IPI", progif_null
},
140 {0x4, "RAID", progif_null
},
141 {0x80, "mass storage", progif_null
},
145 static struct pci_subclass subclass_net
[] = {
146 {0x0, "Ethernet", progif_null
},
147 {0x1, "Token ring", progif_null
},
148 {0x2, "FDDI", progif_null
},
149 {0x3, "ATM", progif_null
},
150 {0x80, "network", progif_null
},
154 static struct pci_subclass subclass_display
[] = {
155 {0x0, NULL
, progif_display
},
156 {0x1, "XGA", progif_null
},
157 {0x80, "other", progif_null
},
161 static struct pci_subclass subclass_comms
[] = {
162 {0x0, "serial", progif_serial
},
163 {0x1, "parallel", progif_parallel
},
164 {0x80, "communications", progif_null
},
168 static struct pci_subclass subclass_serial
[] = {
169 {0x0, "FireWire", progif_firewire
},
170 {0x1, "ACCESS.bus", progif_null
},
171 {0x2, "SSA", progif_null
},
172 {0x3, "USB", progif_null
},
173 {0x4, "Fibrechannel", progif_null
},
177 static struct pci_class
181 struct pci_subclass
*pc_subclass
;
183 {0x0, "device", subclass_old
},
184 {0x1, "controller", subclass_mass
},
185 {0x2, "controller", subclass_net
},
186 {0x3, "display", subclass_display
},
187 {0x7, "controller", subclass_comms
},
188 {0xc, "controller", subclass_serial
},
193 static void biospci_enumerate(void);
194 static void biospci_addinfo(int devid
, struct pci_class
*pc
, struct pci_subclass
*psc
, struct pci_progif
*ppi
);
196 struct pnphandler biospcihandler
=
202 #define PCI_BIOS_PRESENT 0xb101
203 #define FIND_PCI_DEVICE 0xb102
204 #define FIND_PCI_CLASS_CODE 0xb103
205 #define GENERATE_SPECIAL_CYCLE 0xb106
206 #define READ_CONFIG_BYTE 0xb108
207 #define READ_CONFIG_WORD 0xb109
208 #define READ_CONFIG_DWORD 0xb10a
209 #define WRITE_CONFIG_BYTE 0xb10b
210 #define WRITE_CONFIG_WORD 0xb10c
211 #define WRITE_CONFIG_DWORD 0xb10d
212 #define GET_IRQ_ROUTING_OPTIONS 0xb10e
213 #define SET_PCI_IRQ 0xb10f
217 #define PCI_SIGNATURE 0x20494350 /* AKA "PCI " */
222 uint16_t version
, hwcap
, maxbus
;
225 /* Find the PCI BIOS */
228 v86
.eax
= PCI_BIOS_PRESENT
;
232 /* Check for OK response */
233 if (V86_CY(v86
.efl
) || ((v86
.eax
& 0xff00) != 0) ||
234 (v86
.edx
!= PCI_SIGNATURE
))
237 version
= v86
.ebx
& 0xffff;
238 hwcap
= v86
.eax
& 0xff;
239 maxbus
= v86
.ecx
& 0xff;
241 printf("PCI BIOS %d.%d%s%s maxbus %d\n",
242 bcd2bin((version
>> 8) & 0xf), bcd2bin(version
& 0xf),
243 (hwcap
& 1) ? " config1" : "", (hwcap
& 2) ? " config2" : "",
246 sprintf(buf
, "%d", bcd2bin((version
>> 8) & 0xf));
247 setenv("pcibios.major", buf
, 1);
248 sprintf(buf
, "%d", bcd2bin(version
& 0xf));
249 setenv("pcibios.minor", buf
, 1);
250 sprintf(buf
, "%d", !!(hwcap
& 1));
251 setenv("pcibios.config1", buf
, 1);
252 sprintf(buf
, "%d", !!(hwcap
& 2));
253 setenv("pcibios.config2", buf
, 1);
254 sprintf(buf
, "%d", maxbus
);
255 setenv("pcibios.maxbus", buf
, 1);
260 biospci_enumerate(void)
262 int device_index
, err
;
263 uint32_t locator
, devid
;
264 struct pci_class
*pc
;
265 struct pci_subclass
*psc
;
266 struct pci_progif
*ppi
;
268 /* Iterate over known classes */
269 for (pc
= pci_classes
; pc
->pc_class
>= 0; pc
++) {
270 /* Iterate over subclasses */
271 for (psc
= pc
->pc_subclass
; psc
->ps_subclass
>= 0; psc
++) {
272 /* Iterate over programming interfaces */
273 for (ppi
= psc
->ps_progif
; ppi
->pi_code
>= 0; ppi
++) {
275 /* Scan for matches */
276 for (device_index
= 0; ; device_index
++) {
277 /* Look for a match */
278 err
= biospci_find_devclass((pc
->pc_class
<< 16)
279 + (psc
->ps_subclass
<< 8) + ppi
->pi_code
,
280 device_index
, &locator
);
284 /* Read the device identifier from the nominated device */
285 err
= biospci_read_config(locator
, 0, 2, &devid
);
289 /* We have the device ID, create a PnP object and save everything */
290 biospci_addinfo(devid
, pc
, psc
, ppi
);
298 biospci_addinfo(int devid
, struct pci_class
*pc
, struct pci_subclass
*psc
, struct pci_progif
*ppi
)
304 /* build the description */
306 if (ppi
->pi_name
!= NULL
) {
307 strcat(desc
, ppi
->pi_name
);
310 if (psc
->ps_name
!= NULL
) {
311 strcat(desc
, psc
->ps_name
);
314 if (pc
->pc_name
!= NULL
)
315 strcat(desc
, pc
->pc_name
);
317 pi
= pnp_allocinfo();
318 pi
->pi_desc
= strdup(desc
);
319 sprintf(desc
,"0x%08x", devid
);
320 pnp_addident(pi
, desc
);
325 biospci_find_devclass(uint32_t class, int index
, uint32_t *locator
)
329 v86
.eax
= FIND_PCI_CLASS_CODE
;
335 if (V86_CY(v86
.efl
) || (v86
.eax
& 0xff00))
343 biospci_find_device(uint32_t devid
, int index
, uint32_t *locator
)
347 v86
.eax
= FIND_PCI_DEVICE
;
348 v86
.edx
= devid
& 0xffff; /* EDX - Vendor ID */
349 v86
.ecx
= (devid
>> 16) & 0xffff; /* ECX - Device ID */
354 if (V86_CY(v86
.efl
) || (v86
.eax
& 0xff00))
361 * Configuration space access methods.
362 * width = 0(byte), 1(word) or 2(dword).
365 biospci_write_config(uint32_t locator
, int offset
, int width
, uint32_t val
)
369 v86
.eax
= WRITE_CONFIG_BYTE
+ width
;
376 if (V86_CY(v86
.efl
) || (v86
.eax
& 0xff00))
383 biospci_read_config(uint32_t locator
, int offset
, int width
, uint32_t *val
)
387 v86
.eax
= READ_CONFIG_BYTE
+ width
;
393 if (V86_CY(v86
.efl
) || (v86
.eax
& 0xff00))
401 biospci_locator(int8_t bus
, uint8_t device
, uint8_t function
)
404 return ((bus
<< 8) | ((device
& 0x1f) << 3) | (function
& 0x7));
408 * Counts the number of instances of devid we have in the system, as least as
409 * far as the PCI BIOS is able to tell.
412 biospci_count_device_type(uint32_t devid
)
416 for (i
= 0; 1; i
++) {
419 v86
.eax
= FIND_PCI_DEVICE
;
420 v86
.edx
= devid
& 0xffff; /* EDX - Vendor ID */
421 v86
.ecx
= (devid
>> 16) & 0xffff; /* ECX - Device ID */
424 if (V86_CY(v86
.efl
) || (v86
.eax
& 0xff00))
432 * pcibios-device-count (devid -- count)
434 * Returns the PCI BIOS' count of how many devices matching devid are
435 * in the system. devid is the 32-bit vendor + device.
438 ficlPciBiosCountDevices(ficlVm
*pVM
)
443 FICL_STACK_CHECK(ficlVmGetDataStack(pVM
), 1, 1);
445 devid
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
447 i
= biospci_count_device_type(devid
);
449 ficlStackPushInteger(ficlVmGetDataStack(pVM
), i
);
453 * pcibios-write-config (locator offset width value -- )
455 * Writes the specified config register.
456 * Locator is bus << 8 | device << 3 | fuction
457 * offset is the pci config register
458 * width is 0 for byte, 1 for word, 2 for dword
459 * value is the value to write
462 ficlPciBiosWriteConfig(ficlVm
*pVM
)
464 uint32_t value
, width
, offset
, locator
;
466 FICL_STACK_CHECK(ficlVmGetDataStack(pVM
), 4, 0);
468 value
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
469 width
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
470 offset
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
471 locator
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
473 biospci_write_config(locator
, offset
, width
, value
);
477 * pcibios-read-config (locator offset width -- value)
479 * Reads the specified config register.
480 * Locator is bus << 8 | device << 3 | fuction
481 * offset is the pci config register
482 * width is 0 for byte, 1 for word, 2 for dword
483 * value is the value to read from the register
486 ficlPciBiosReadConfig(ficlVm
*pVM
)
488 uint32_t value
, width
, offset
, locator
;
490 FICL_STACK_CHECK(ficlVmGetDataStack(pVM
), 3, 1);
492 width
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
493 offset
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
494 locator
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
496 biospci_read_config(locator
, offset
, width
, &value
);
498 ficlStackPushInteger(ficlVmGetDataStack(pVM
), value
);
502 * pcibios-find-devclass (class index -- locator)
504 * Finds the index'th instance of class in the pci tree.
505 * must be an exact match.
506 * class is the class to search for.
507 * index 0..N (set to 0, increment until error)
509 * Locator is bus << 8 | device << 3 | fuction (or -1 on error)
512 ficlPciBiosFindDevclass(ficlVm
*pVM
)
514 uint32_t index
, class, locator
;
516 FICL_STACK_CHECK(ficlVmGetDataStack(pVM
), 2, 1);
518 index
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
519 class = ficlStackPopInteger(ficlVmGetDataStack(pVM
));
521 if (biospci_find_devclass(class, index
, &locator
))
522 locator
= 0xffffffff;
524 ficlStackPushInteger(ficlVmGetDataStack(pVM
), locator
);
528 * pcibios-find-device(devid index -- locator)
530 * Finds the index'th instance of devid in the pci tree.
531 * must be an exact match.
532 * class is the class to search for.
533 * index 0..N (set to 0, increment until error)
535 * Locator is bus << 8 | device << 3 | fuction (or -1 on error)
538 ficlPciBiosFindDevice(ficlVm
*pVM
)
540 uint32_t index
, devid
, locator
;
542 FICL_STACK_CHECK(ficlVmGetDataStack(pVM
), 2, 1);
544 index
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
545 devid
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
547 if (biospci_find_device(devid
, index
, &locator
))
548 locator
= 0xffffffff;
550 ficlStackPushInteger(ficlVmGetDataStack(pVM
), locator
);
554 * pcibios-locator(bus device function -- locator)
556 * converts bus, device, function to locator.
558 * Locator is bus << 8 | device << 3 | fuction
561 ficlPciBiosLocator(ficlVm
*pVM
)
563 uint32_t bus
, device
, function
, locator
;
565 FICL_STACK_CHECK(ficlVmGetDataStack(pVM
), 3, 1);
567 function
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
568 device
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
569 bus
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
571 locator
= biospci_locator(bus
, device
, function
);
573 ficlStackPushInteger(ficlVmGetDataStack(pVM
), locator
);
577 * Glue function to add the appropriate forth words to access pci bios
581 ficlCompilePciBios(ficlSystem
*pSys
)
583 ficlDictionary
*dp
= ficlSystemGetDictionary(pSys
);
585 FICL_SYSTEM_ASSERT(pSys
, dp
);
587 ficlDictionarySetPrimitive(dp
, "pcibios-device-count",
588 ficlPciBiosCountDevices
, FICL_WORD_DEFAULT
);
589 ficlDictionarySetPrimitive(dp
, "pcibios-read-config",
590 ficlPciBiosReadConfig
, FICL_WORD_DEFAULT
);
591 ficlDictionarySetPrimitive(dp
, "pcibios-write-config",
592 ficlPciBiosWriteConfig
, FICL_WORD_DEFAULT
);
593 ficlDictionarySetPrimitive(dp
, "pcibios-find-devclass",
594 ficlPciBiosFindDevclass
, FICL_WORD_DEFAULT
);
595 ficlDictionarySetPrimitive(dp
, "pcibios-find-device",
596 ficlPciBiosFindDevice
, FICL_WORD_DEFAULT
);
597 ficlDictionarySetPrimitive(dp
, "pcibios-locator", ficlPciBiosLocator
,
601 FICL_COMPILE_SET(ficlCompilePciBios
);