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 <machine/cpufunc.h>
37 #include <bootstrap.h>
44 * Stupid PCI BIOS interface doesn't let you simply enumerate everything
45 * that's there, instead you have to ask it if it has something.
47 * So we have to scan by class code, subclass code and sometimes programming
57 static struct pci_progif progif_null
[] = {
62 static struct pci_progif progif_display
[] = {
68 static struct pci_progif progif_ide
[] = {
104 static struct pci_progif progif_serial
[] = {
111 static struct pci_progif progif_parallel
[] = {
113 {0x1, "Bidirectional"},
118 static struct pci_progif progif_firewire
[] = {
127 struct pci_progif
*ps_progif
; /* if set, use for programming interface value(s) */
130 static struct pci_subclass subclass_old
[] = {
131 {0x0, "Old non-VGA", progif_null
},
132 {0x1, "Old VGA", progif_null
},
136 static struct pci_subclass subclass_mass
[] = {
137 {0x0, "SCSI", progif_null
},
138 {0x1, "IDE", progif_ide
},
139 {0x2, "Floppy disk", progif_null
},
140 {0x3, "IPI", progif_null
},
141 {0x4, "RAID", progif_null
},
142 {0x80, "mass storage", progif_null
},
146 static struct pci_subclass subclass_net
[] = {
147 {0x0, "Ethernet", progif_null
},
148 {0x1, "Token ring", progif_null
},
149 {0x2, "FDDI", progif_null
},
150 {0x3, "ATM", progif_null
},
151 {0x80, "network", progif_null
},
155 static struct pci_subclass subclass_display
[] = {
156 {0x0, NULL
, progif_display
},
157 {0x1, "XGA", progif_null
},
158 {0x80, "other", progif_null
},
162 static struct pci_subclass subclass_comms
[] = {
163 {0x0, "serial", progif_serial
},
164 {0x1, "parallel", progif_parallel
},
165 {0x80, "communications", progif_null
},
169 static struct pci_subclass subclass_serial
[] = {
170 {0x0, "FireWire", progif_firewire
},
171 {0x1, "ACCESS.bus", progif_null
},
172 {0x2, "SSA", progif_null
},
173 {0x3, "USB", progif_null
},
174 {0x4, "Fibrechannel", progif_null
},
178 static struct pci_class
182 struct pci_subclass
*pc_subclass
;
184 {0x0, "device", subclass_old
},
185 {0x1, "controller", subclass_mass
},
186 {0x2, "controller", subclass_net
},
187 {0x3, "display", subclass_display
},
188 {0x7, "controller", subclass_comms
},
189 {0xc, "controller", subclass_serial
},
194 static void biospci_enumerate(void);
195 static void biospci_addinfo(int devid
, struct pci_class
*pc
, struct pci_subclass
*psc
, struct pci_progif
*ppi
);
197 struct pnphandler biospcihandler
=
203 #define PCI_BIOS_PRESENT 0xb101
204 #define FIND_PCI_DEVICE 0xb102
205 #define FIND_PCI_CLASS_CODE 0xb103
206 #define GENERATE_SPECIAL_CYCLE 0xb106
207 #define READ_CONFIG_BYTE 0xb108
208 #define READ_CONFIG_WORD 0xb109
209 #define READ_CONFIG_DWORD 0xb10a
210 #define WRITE_CONFIG_BYTE 0xb10b
211 #define WRITE_CONFIG_WORD 0xb10c
212 #define WRITE_CONFIG_DWORD 0xb10d
213 #define GET_IRQ_ROUTING_OPTIONS 0xb10e
214 #define SET_PCI_IRQ 0xb10f
218 #define PCI_SIGNATURE 0x20494350 /* AKA "PCI " */
223 uint16_t version
, hwcap
, maxbus
;
226 /* Find the PCI BIOS */
229 v86
.eax
= PCI_BIOS_PRESENT
;
233 /* Check for OK response */
234 if (V86_CY(v86
.efl
) || ((v86
.eax
& 0xff00) != 0) ||
235 (v86
.edx
!= PCI_SIGNATURE
))
238 version
= v86
.ebx
& 0xffff;
239 hwcap
= v86
.eax
& 0xff;
240 maxbus
= v86
.ecx
& 0xff;
242 printf("PCI BIOS %d.%d%s%s maxbus %d\n",
243 bcd2bin((version
>> 8) & 0xf), bcd2bin(version
& 0xf),
244 (hwcap
& 1) ? " config1" : "", (hwcap
& 2) ? " config2" : "",
247 sprintf(buf
, "%d", bcd2bin((version
>> 8) & 0xf));
248 setenv("pcibios.major", buf
, 1);
249 sprintf(buf
, "%d", bcd2bin(version
& 0xf));
250 setenv("pcibios.minor", buf
, 1);
251 sprintf(buf
, "%d", !!(hwcap
& 1));
252 setenv("pcibios.config1", buf
, 1);
253 sprintf(buf
, "%d", !!(hwcap
& 2));
254 setenv("pcibios.config2", buf
, 1);
255 sprintf(buf
, "%d", maxbus
);
256 setenv("pcibios.maxbus", buf
, 1);
261 biospci_enumerate(void)
263 int device_index
, err
;
264 uint32_t locator
, devid
;
265 struct pci_class
*pc
;
266 struct pci_subclass
*psc
;
267 struct pci_progif
*ppi
;
269 /* Iterate over known classes */
270 for (pc
= pci_classes
; pc
->pc_class
>= 0; pc
++) {
271 /* Iterate over subclasses */
272 for (psc
= pc
->pc_subclass
; psc
->ps_subclass
>= 0; psc
++) {
273 /* Iterate over programming interfaces */
274 for (ppi
= psc
->ps_progif
; ppi
->pi_code
>= 0; ppi
++) {
276 /* Scan for matches */
277 for (device_index
= 0; ; device_index
++) {
278 /* Look for a match */
279 err
= biospci_find_devclass((pc
->pc_class
<< 16)
280 + (psc
->ps_subclass
<< 8) + ppi
->pi_code
,
281 device_index
, &locator
);
285 /* Read the device identifier from the nominated device */
286 err
= biospci_read_config(locator
, 0, 2, &devid
);
290 /* We have the device ID, create a PnP object and save everything */
291 biospci_addinfo(devid
, pc
, psc
, ppi
);
299 biospci_addinfo(int devid
, struct pci_class
*pc
, struct pci_subclass
*psc
, struct pci_progif
*ppi
)
305 /* build the description */
307 if (ppi
->pi_name
!= NULL
) {
308 strcat(desc
, ppi
->pi_name
);
311 if (psc
->ps_name
!= NULL
) {
312 strcat(desc
, psc
->ps_name
);
315 if (pc
->pc_name
!= NULL
)
316 strcat(desc
, pc
->pc_name
);
318 pi
= pnp_allocinfo();
319 pi
->pi_desc
= strdup(desc
);
320 sprintf(desc
,"0x%08x", devid
);
321 pnp_addident(pi
, desc
);
326 biospci_find_devclass(uint32_t class, int index
, uint32_t *locator
)
330 v86
.eax
= FIND_PCI_CLASS_CODE
;
336 if (V86_CY(v86
.efl
) || (v86
.eax
& 0xff00))
344 biospci_find_device(uint32_t devid
, int index
, uint32_t *locator
)
348 v86
.eax
= FIND_PCI_DEVICE
;
349 v86
.edx
= devid
& 0xffff; /* EDX - Vendor ID */
350 v86
.ecx
= (devid
>> 16) & 0xffff; /* ECX - Device ID */
355 if (V86_CY(v86
.efl
) || (v86
.eax
& 0xff00))
362 * Configuration space access methods.
363 * width = 0(byte), 1(word) or 2(dword).
366 biospci_write_config(uint32_t locator
, int offset
, int width
, uint32_t val
)
370 v86
.eax
= WRITE_CONFIG_BYTE
+ width
;
377 if (V86_CY(v86
.efl
) || (v86
.eax
& 0xff00))
384 biospci_read_config(uint32_t locator
, int offset
, int width
, uint32_t *val
)
388 v86
.eax
= READ_CONFIG_BYTE
+ width
;
394 if (V86_CY(v86
.efl
) || (v86
.eax
& 0xff00))
402 biospci_locator(int8_t bus
, uint8_t device
, uint8_t function
)
405 return ((bus
<< 8) | ((device
& 0x1f) << 3) | (function
& 0x7));
409 * Counts the number of instances of devid we have in the system, as least as
410 * far as the PCI BIOS is able to tell.
413 biospci_count_device_type(uint32_t devid
)
417 for (i
= 0; 1; i
++) {
420 v86
.eax
= FIND_PCI_DEVICE
;
421 v86
.edx
= devid
& 0xffff; /* EDX - Vendor ID */
422 v86
.ecx
= (devid
>> 16) & 0xffff; /* ECX - Device ID */
425 if (V86_CY(v86
.efl
) || (v86
.eax
& 0xff00))
433 * pcibios-device-count (devid -- count)
435 * Returns the PCI BIOS' count of how many devices matching devid are
436 * in the system. devid is the 32-bit vendor + device.
439 ficlPciBiosCountDevices(ficlVm
*pVM
)
444 FICL_STACK_CHECK(ficlVmGetDataStack(pVM
), 1, 1);
446 devid
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
448 i
= biospci_count_device_type(devid
);
450 ficlStackPushInteger(ficlVmGetDataStack(pVM
), i
);
454 * pcibios-write-config (locator offset width value -- )
456 * Writes the specified config register.
457 * Locator is bus << 8 | device << 3 | fuction
458 * offset is the pci config register
459 * width is 0 for byte, 1 for word, 2 for dword
460 * value is the value to write
463 ficlPciBiosWriteConfig(ficlVm
*pVM
)
465 uint32_t value
, width
, offset
, locator
;
467 FICL_STACK_CHECK(ficlVmGetDataStack(pVM
), 4, 0);
469 value
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
470 width
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
471 offset
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
472 locator
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
474 biospci_write_config(locator
, offset
, width
, value
);
478 * pcibios-read-config (locator offset width -- value)
480 * Reads the specified config register.
481 * Locator is bus << 8 | device << 3 | fuction
482 * offset is the pci config register
483 * width is 0 for byte, 1 for word, 2 for dword
484 * value is the value to read from the register
487 ficlPciBiosReadConfig(ficlVm
*pVM
)
489 uint32_t value
, width
, offset
, locator
;
491 FICL_STACK_CHECK(ficlVmGetDataStack(pVM
), 3, 1);
493 width
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
494 offset
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
495 locator
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
497 biospci_read_config(locator
, offset
, width
, &value
);
499 ficlStackPushInteger(ficlVmGetDataStack(pVM
), value
);
503 * pcibios-find-devclass (class index -- locator)
505 * Finds the index'th instance of class in the pci tree.
506 * must be an exact match.
507 * class is the class to search for.
508 * index 0..N (set to 0, increment until error)
510 * Locator is bus << 8 | device << 3 | fuction (or -1 on error)
513 ficlPciBiosFindDevclass(ficlVm
*pVM
)
515 uint32_t index
, class, locator
;
517 FICL_STACK_CHECK(ficlVmGetDataStack(pVM
), 2, 1);
519 index
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
520 class = ficlStackPopInteger(ficlVmGetDataStack(pVM
));
522 if (biospci_find_devclass(class, index
, &locator
))
523 locator
= 0xffffffff;
525 ficlStackPushInteger(ficlVmGetDataStack(pVM
), locator
);
529 * pcibios-find-device(devid index -- locator)
531 * Finds the index'th instance of devid in the pci tree.
532 * must be an exact match.
533 * class is the class to search for.
534 * index 0..N (set to 0, increment until error)
536 * Locator is bus << 8 | device << 3 | fuction (or -1 on error)
539 ficlPciBiosFindDevice(ficlVm
*pVM
)
541 uint32_t index
, devid
, locator
;
543 FICL_STACK_CHECK(ficlVmGetDataStack(pVM
), 2, 1);
545 index
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
546 devid
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
548 if (biospci_find_device(devid
, index
, &locator
))
549 locator
= 0xffffffff;
551 ficlStackPushInteger(ficlVmGetDataStack(pVM
), locator
);
555 * pcibios-locator(bus device function -- locator)
557 * converts bus, device, function to locator.
559 * Locator is bus << 8 | device << 3 | fuction
562 ficlPciBiosLocator(ficlVm
*pVM
)
564 uint32_t bus
, device
, function
, locator
;
566 FICL_STACK_CHECK(ficlVmGetDataStack(pVM
), 3, 1);
568 function
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
569 device
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
570 bus
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
572 locator
= biospci_locator(bus
, device
, function
);
574 ficlStackPushInteger(ficlVmGetDataStack(pVM
), locator
);
578 * Glue function to add the appropriate forth words to access pci bios
582 ficlCompilePciBios(ficlSystem
*pSys
)
584 ficlDictionary
*dp
= ficlSystemGetDictionary(pSys
);
586 FICL_SYSTEM_ASSERT(pSys
, dp
);
588 ficlDictionarySetPrimitive(dp
, "pcibios-device-count",
589 ficlPciBiosCountDevices
, FICL_WORD_DEFAULT
);
590 ficlDictionarySetPrimitive(dp
, "pcibios-read-config",
591 ficlPciBiosReadConfig
, FICL_WORD_DEFAULT
);
592 ficlDictionarySetPrimitive(dp
, "pcibios-write-config",
593 ficlPciBiosWriteConfig
, FICL_WORD_DEFAULT
);
594 ficlDictionarySetPrimitive(dp
, "pcibios-find-devclass",
595 ficlPciBiosFindDevclass
, FICL_WORD_DEFAULT
);
596 ficlDictionarySetPrimitive(dp
, "pcibios-find-device",
597 ficlPciBiosFindDevice
, FICL_WORD_DEFAULT
);
598 ficlDictionarySetPrimitive(dp
, "pcibios-locator", ficlPciBiosLocator
,
602 FICL_COMPILE_SET(ficlCompilePciBios
);
605 * outb ( port# c -- )
606 * Store a byte to I/O port number port#
609 ficlOutb(ficlVm
*pVM
)
614 port
= ficlStackPopUnsigned(ficlVmGetDataStack(pVM
));
615 c
= ficlStackPopInteger(ficlVmGetDataStack(pVM
));
621 * Fetch a byte from I/O port number port#
629 port
= ficlStackPopUnsigned(ficlVmGetDataStack(pVM
));
631 ficlStackPushInteger(ficlVmGetDataStack(pVM
), c
);
635 ficlCompileCpufunc(ficlSystem
*pSys
)
637 ficlDictionary
*dp
= ficlSystemGetDictionary(pSys
);
639 FICL_SYSTEM_ASSERT(pSys
, dp
);
641 ficlDictionarySetPrimitive(dp
, "outb", ficlOutb
, FICL_WORD_DEFAULT
);
642 ficlDictionarySetPrimitive(dp
, "inb", ficlInb
, FICL_WORD_DEFAULT
);
645 FICL_COMPILE_SET(ficlCompileCpufunc
);