140617Smsmith/*- 240617Smsmith * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 340617Smsmith * All rights reserved. 440617Smsmith * 540617Smsmith * Redistribution and use in source and binary forms, with or without 640617Smsmith * modification, are permitted provided that the following conditions 740617Smsmith * are met: 840617Smsmith * 1. Redistributions of source code must retain the above copyright 940617Smsmith * notice, this list of conditions and the following disclaimer. 1040617Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1140617Smsmith * notice, this list of conditions and the following disclaimer in the 1240617Smsmith * documentation and/or other materials provided with the distribution. 1340617Smsmith * 1440617Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1540617Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1640617Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1740617Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1840617Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1940617Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2040617Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2140617Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2240617Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2340617Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2440617Smsmith * SUCH DAMAGE. 2540617Smsmith */ 2640617Smsmith 27119482Sobrien#include <sys/cdefs.h> 28119482Sobrien__FBSDID("$FreeBSD$"); 29119482Sobrien 3040617Smsmith/* 3140617Smsmith * PnP enumerator using the PCI BIOS. 3240617Smsmith */ 3340617Smsmith 3440617Smsmith#include <stand.h> 3540617Smsmith#include <machine/stdarg.h> 3640617Smsmith#include <bootstrap.h> 3740617Smsmith#include <isapnp.h> 3840617Smsmith#include <btxv86.h> 39162814Sru#include "libi386.h" 4040617Smsmith 4140617Smsmith/* 4240617Smsmith * Stupid PCI BIOS interface doesn't let you simply enumerate everything 4340617Smsmith * that's there, instead you have to ask it if it has something. 4440617Smsmith * 4540617Smsmith * So we have to scan by class code, subclass code and sometimes programming 4640617Smsmith * interface. 4740617Smsmith */ 4840617Smsmith 4940617Smsmithstruct pci_progif 5040617Smsmith{ 5140617Smsmith int pi_code; 5264187Sjhb const char *pi_name; 5340617Smsmith}; 5440617Smsmith 5540617Smsmithstatic struct pci_progif progif_null[] = { 5640617Smsmith {0x0, NULL}, 5740617Smsmith {-1, NULL} 5840617Smsmith}; 5940617Smsmith 6040617Smsmithstatic struct pci_progif progif_display[] = { 6140617Smsmith {0x0, "VGA"}, 6240617Smsmith {0x1, "8514"}, 6340617Smsmith {-1, NULL} 6440617Smsmith}; 6540617Smsmith 6640617Smsmithstatic struct pci_progif progif_ide[] = { 6740617Smsmith {0x00, NULL}, 6840617Smsmith {0x01, NULL}, 6940617Smsmith {0x02, NULL}, 7040617Smsmith {0x03, NULL}, 7140617Smsmith {0x04, NULL}, 7240617Smsmith {0x05, NULL}, 7340617Smsmith {0x06, NULL}, 7440617Smsmith {0x07, NULL}, 7540617Smsmith {0x08, NULL}, 7640617Smsmith {0x09, NULL}, 7740617Smsmith {0x0a, NULL}, 7840617Smsmith {0x0b, NULL}, 7940617Smsmith {0x0c, NULL}, 8040617Smsmith {0x0d, NULL}, 8140617Smsmith {0x0e, NULL}, 8240617Smsmith {0x0f, NULL}, 8340617Smsmith {0x80, NULL}, 8440617Smsmith {0x81, NULL}, 8540617Smsmith {0x82, NULL}, 8640617Smsmith {0x83, NULL}, 8740617Smsmith {0x84, NULL}, 8840617Smsmith {0x85, NULL}, 8940617Smsmith {0x86, NULL}, 9040617Smsmith {0x87, NULL}, 9140617Smsmith {0x88, NULL}, 9240617Smsmith {0x89, NULL}, 9340617Smsmith {0x8a, NULL}, 9440617Smsmith {0x8b, NULL}, 9540617Smsmith {0x8c, NULL}, 9640617Smsmith {0x8d, NULL}, 9740617Smsmith {0x8e, NULL}, 9840617Smsmith {0x8f, NULL}, 9940617Smsmith {-1, NULL} 10040617Smsmith}; 10140617Smsmith 10240617Smsmithstatic struct pci_progif progif_serial[] = { 10340617Smsmith {0x0, "8250"}, 10440617Smsmith {0x1, "16450"}, 10540617Smsmith {0x2, "16550"}, 10640617Smsmith {-1, NULL} 10740617Smsmith}; 10840617Smsmith 10940617Smsmithstatic struct pci_progif progif_parallel[] = { 11040617Smsmith {0x0, "Standard"}, 11140617Smsmith {0x1, "Bidirectional"}, 11240617Smsmith {0x2, "ECP"}, 11340617Smsmith {-1, NULL} 11440617Smsmith}; 11540617Smsmith 116136779Ssimokawastatic struct pci_progif progif_firewire[] = { 117136779Ssimokawa {0x10, "OHCI"}, 118136779Ssimokawa {-1, NULL} 119136779Ssimokawa}; 12040617Smsmith 12140617Smsmithstruct pci_subclass 12240617Smsmith{ 12340617Smsmith int ps_subclass; 12464187Sjhb const char *ps_name; 12540617Smsmith struct pci_progif *ps_progif; /* if set, use for programming interface value(s) */ 12640617Smsmith}; 12740617Smsmith 12840617Smsmithstatic struct pci_subclass subclass_old[] = { 12940617Smsmith {0x0, "Old non-VGA", progif_null}, 13040617Smsmith {0x1, "Old VGA", progif_null}, 13140617Smsmith {-1, NULL, NULL} 13240617Smsmith}; 13340617Smsmith 13440617Smsmithstatic struct pci_subclass subclass_mass[] = { 13540617Smsmith {0x0, "SCSI", progif_null}, 13640617Smsmith {0x1, "IDE", progif_ide}, 13740617Smsmith {0x2, "Floppy disk", progif_null}, 13840617Smsmith {0x3, "IPI", progif_null}, 13940617Smsmith {0x4, "RAID", progif_null}, 14040617Smsmith {0x80, "mass storage", progif_null}, 14140617Smsmith {-1, NULL, NULL} 14240617Smsmith}; 14340617Smsmith 14440617Smsmithstatic struct pci_subclass subclass_net[] = { 14540617Smsmith {0x0, "Ethernet", progif_null}, 14640617Smsmith {0x1, "Token ring", progif_null}, 14740617Smsmith {0x2, "FDDI", progif_null}, 14840617Smsmith {0x3, "ATM", progif_null}, 14940617Smsmith {0x80, "network", progif_null}, 15040617Smsmith {-1, NULL, NULL} 15140617Smsmith}; 15240617Smsmith 15340617Smsmithstatic struct pci_subclass subclass_display[] = { 15440617Smsmith {0x0, NULL, progif_display}, 15540617Smsmith {0x1, "XGA", progif_null}, 15640617Smsmith {0x80, "other", progif_null}, 15740617Smsmith {-1, NULL, NULL} 15840617Smsmith}; 15940617Smsmith 16040617Smsmithstatic struct pci_subclass subclass_comms[] = { 16140617Smsmith {0x0, "serial", progif_serial}, 16240617Smsmith {0x1, "parallel", progif_parallel}, 16340617Smsmith {0x80, "communications", progif_null}, 16440617Smsmith {-1, NULL, NULL} 16540617Smsmith}; 16640617Smsmith 16740617Smsmithstatic struct pci_subclass subclass_serial[] = { 168136779Ssimokawa {0x0, "FireWire", progif_firewire}, 16940617Smsmith {0x1, "ACCESS.bus", progif_null}, 17040617Smsmith {0x2, "SSA", progif_null}, 17140617Smsmith {0x3, "USB", progif_null}, 17240617Smsmith {0x4, "Fibrechannel", progif_null}, 17340617Smsmith {-1, NULL, NULL} 17440617Smsmith}; 17540617Smsmith 17640617Smsmithstatic struct pci_class 17740617Smsmith{ 17840617Smsmith int pc_class; 17964187Sjhb const char *pc_name; 18040617Smsmith struct pci_subclass *pc_subclass; 18140617Smsmith} pci_classes[] = { 18240617Smsmith {0x0, "device", subclass_old}, 18340617Smsmith {0x1, "controller", subclass_mass}, 18440617Smsmith {0x2, "controller", subclass_net}, 18540617Smsmith {0x3, "display", subclass_display}, 18640617Smsmith {0x7, "controller", subclass_comms}, 18740617Smsmith {0xc, "controller", subclass_serial}, 18840617Smsmith {-1, NULL, NULL} 18940617Smsmith}; 19040617Smsmith 19140617Smsmith 19240617Smsmithstatic void biospci_enumerate(void); 19340617Smsmithstatic void biospci_addinfo(int devid, struct pci_class *pc, struct pci_subclass *psc, struct pci_progif *ppi); 19440617Smsmith 19540617Smsmithstatic int biospci_version; 19640617Smsmithstatic int biospci_hwcap; 19740617Smsmith 19840617Smsmithstruct pnphandler biospcihandler = 19940617Smsmith{ 20040617Smsmith "PCI BIOS", 20140617Smsmith biospci_enumerate 20240617Smsmith}; 20340617Smsmith 20440617Smsmithstatic void 20540617Smsmithbiospci_enumerate(void) 20640617Smsmith{ 207136779Ssimokawa int device_index, err; 208136779Ssimokawa uint32_t locator, devid; 20940617Smsmith struct pci_class *pc; 21040617Smsmith struct pci_subclass *psc; 21140617Smsmith struct pci_progif *ppi; 21240617Smsmith 21340617Smsmith /* Find the PCI BIOS */ 21440617Smsmith v86.ctl = V86_FLAGS; 21540617Smsmith v86.addr = 0x1a; 21640617Smsmith v86.eax = 0xb101; 21740617Smsmith v86.edi = 0x0; 21840617Smsmith v86int(); 21940617Smsmith 22040617Smsmith /* Check for OK response */ 221226746Sjhb if (V86_CY(v86.efl) || ((v86.eax & 0xff00) != 0) || 222226746Sjhb (v86.edx != 0x20494350)) 22340617Smsmith return; 22440617Smsmith 22540617Smsmith biospci_version = v86.ebx & 0xffff; 22640617Smsmith biospci_hwcap = v86.eax & 0xff; 22740617Smsmith#if 0 22840617Smsmith printf("PCI BIOS %d.%d%s%s\n", 22940617Smsmith bcd2bin((biospci_version >> 8) & 0xf), bcd2bin(biospci_version & 0xf), 23040617Smsmith (biospci_hwcap & 1) ? " config1" : "", (biospci_hwcap & 2) ? " config2" : ""); 23140617Smsmith#endif 23240617Smsmith /* Iterate over known classes */ 23340617Smsmith for (pc = pci_classes; pc->pc_class >= 0; pc++) { 23440617Smsmith /* Iterate over subclasses */ 23540617Smsmith for (psc = pc->pc_subclass; psc->ps_subclass >= 0; psc++) { 23640617Smsmith /* Iterate over programming interfaces */ 23740617Smsmith for (ppi = psc->ps_progif; ppi->pi_code >= 0; ppi++) { 23840617Smsmith 23940617Smsmith /* Scan for matches */ 24064187Sjhb for (device_index = 0; ; device_index++) { 24140617Smsmith /* Look for a match */ 242136779Ssimokawa err = biospci_find_devclass((pc->pc_class << 16) 243136779Ssimokawa + (psc->ps_subclass << 8) + ppi->pi_code, 244136779Ssimokawa device_index, &locator); 245136779Ssimokawa if (err != 0) 24640617Smsmith break; 24740617Smsmith 24840617Smsmith /* Read the device identifier from the nominated device */ 249136779Ssimokawa err = biospci_read_config(locator, 0, 2, &devid); 250136779Ssimokawa if (err != 0) 25140617Smsmith break; 25240617Smsmith 25340617Smsmith /* We have the device ID, create a PnP object and save everything */ 25440617Smsmith biospci_addinfo(devid, pc, psc, ppi); 25540617Smsmith } 25640617Smsmith } 25740617Smsmith } 25840617Smsmith } 25940617Smsmith} 26040617Smsmith 26140617Smsmithstatic void 26240617Smsmithbiospci_addinfo(int devid, struct pci_class *pc, struct pci_subclass *psc, struct pci_progif *ppi) 26340617Smsmith{ 26440617Smsmith struct pnpinfo *pi; 26540617Smsmith char desc[80]; 26640617Smsmith 26740617Smsmith 26840617Smsmith /* build the description */ 26940617Smsmith desc[0] = 0; 27040617Smsmith if (ppi->pi_name != NULL) { 27140617Smsmith strcat(desc, ppi->pi_name); 27240617Smsmith strcat(desc, " "); 27340617Smsmith } 27440617Smsmith if (psc->ps_name != NULL) { 27540617Smsmith strcat(desc, psc->ps_name); 27640617Smsmith strcat(desc, " "); 27740617Smsmith } 27840617Smsmith if (pc->pc_name != NULL) 27940617Smsmith strcat(desc, pc->pc_name); 28040617Smsmith 28140617Smsmith pi = pnp_allocinfo(); 28240617Smsmith pi->pi_desc = strdup(desc); 28340617Smsmith sprintf(desc,"0x%08x", devid); 28440617Smsmith pnp_addident(pi, desc); 28540617Smsmith pnp_addinfo(pi); 28640617Smsmith} 287136779Ssimokawa 288136779Ssimokawaint 289136779Ssimokawabiospci_find_devclass(uint32_t class, int index, uint32_t *locator) 290136779Ssimokawa{ 291136779Ssimokawa v86.ctl = V86_FLAGS; 292136779Ssimokawa v86.addr = 0x1a; 293136779Ssimokawa v86.eax = 0xb103; 294136779Ssimokawa v86.ecx = class; 295136779Ssimokawa v86.esi = index; 296136779Ssimokawa v86int(); 297136779Ssimokawa 298136779Ssimokawa /* error */ 299226746Sjhb if (V86_CY(v86.efl) || (v86.eax & 0xff00)) 300136779Ssimokawa return (-1); 301136779Ssimokawa 302136779Ssimokawa *locator = v86.ebx; 303136779Ssimokawa return (0); 304136779Ssimokawa} 305136779Ssimokawa/* 306136779Ssimokawa * Configuration space access methods. 307136779Ssimokawa * width = 0(byte), 1(word) or 2(dword). 308136779Ssimokawa */ 309136779Ssimokawaint 310136779Ssimokawabiospci_write_config(uint32_t locator, int offset, int width, uint32_t val) 311136779Ssimokawa{ 312136779Ssimokawa v86.ctl = V86_FLAGS; 313136779Ssimokawa v86.addr = 0x1a; 314136779Ssimokawa v86.eax = 0xb10b + width; 315136779Ssimokawa v86.ebx = locator; 316136779Ssimokawa v86.edi = offset; 317136779Ssimokawa v86.ecx = val; 318136779Ssimokawa v86int(); 319136779Ssimokawa 320136779Ssimokawa /* error */ 321226746Sjhb if (V86_CY(v86.efl) || (v86.eax & 0xff00)) 322136779Ssimokawa return (-1); 323136779Ssimokawa 324136779Ssimokawa return(0); 325136779Ssimokawa} 326136779Ssimokawa 327136779Ssimokawaint 328136779Ssimokawabiospci_read_config(uint32_t locator, int offset, int width, uint32_t *val) 329136779Ssimokawa{ 330136779Ssimokawa v86.ctl = V86_FLAGS; 331136779Ssimokawa v86.addr = 0x1a; 332136779Ssimokawa v86.eax = 0xb108 + width; 333136779Ssimokawa v86.ebx = locator; 334136779Ssimokawa v86.edi = offset; 335136779Ssimokawa v86int(); 336136779Ssimokawa 337136779Ssimokawa /* error */ 338226746Sjhb if (V86_CY(v86.efl) || (v86.eax & 0xff00)) 339136779Ssimokawa return (-1); 340136779Ssimokawa 341136779Ssimokawa *val = v86.ecx; 342136779Ssimokawa return (0); 343136779Ssimokawa} 344136779Ssimokawa 345229435Skibuint32_t 346229435Skibbiospci_locator(int8_t bus, uint8_t device, uint8_t function) 347229435Skib{ 348229435Skib 349229435Skib return ((bus << 8) | ((device & 0x1f) << 3) | (function & 0x7)); 350229435Skib} 351