1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. 24 * Copyright 2022 Oxide Computer Company 25 */ 26 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <sys/sunndi.h> 30 #include <sys/pci.h> 31 #include <sys/pci_impl.h> 32 #include <sys/pci_cfgspace.h> 33 #include <sys/pci_cfgspace_impl.h> 34 #include <sys/memlist.h> 35 #include <sys/bootconf.h> 36 #include <sys/psw.h> 37 38 /* 39 * pci irq routing information table 40 */ 41 int pci_irq_nroutes; 42 static pci_irq_route_t *pci_irq_routes; 43 44 45 static int pci_bios_get_irq_routing(pci_irq_route_t *, int, int *); 46 static void pci_get_irq_routing_table(void); 47 48 49 /* 50 * Retrieve information from the bios needed for system 51 * configuration early during startup. 52 */ 53 void 54 startup_pci_bios(void) 55 { 56 pci_get_irq_routing_table(); 57 } 58 59 60 /* 61 * Issue the bios get irq routing information table interrupt 62 * 63 * Despite the name, the information in the table is only 64 * used to derive slot names for some named pci hot-plug slots. 65 * 66 * Returns the number of irq routing table entries returned 67 * by the bios, or 0 and optionally, the number of entries required. 68 */ 69 static int 70 pci_bios_get_irq_routing(pci_irq_route_t *routes, int nroutes, int *nneededp) 71 { 72 struct bop_regs regs; 73 uchar_t *hdrp; 74 uchar_t *bufp; 75 int i, n; 76 int rval = 0; 77 78 if (nneededp) 79 *nneededp = 0; 80 81 /* in UEFI system, there is no BIOS data */ 82 if (BOP_GETPROPLEN(bootops, "efi-systab") > 0) 83 return (0); 84 85 /* 86 * Set up irq routing header with the size and address 87 * of some useable low-memory data addresses. Initalize 88 * data area to zero, avoiding memcpy/bzero. 89 */ 90 hdrp = (uchar_t *)BIOS_IRQ_ROUTING_HDR; 91 bufp = (uchar_t *)BIOS_IRQ_ROUTING_DATA; 92 93 n = nroutes * sizeof (pci_irq_route_t); 94 for (i = 0; i < n; i++) 95 bufp[i] = 0; 96 ((pci_irq_route_hdr_t *)hdrp)->pir_size = n; 97 ((pci_irq_route_hdr_t *)hdrp)->pir_addr = (uint32_t)(uintptr_t)bufp; 98 99 bzero(®s, sizeof (regs)); 100 regs.eax.word.ax = (PCI_FUNCTION_ID << 8) | PCI_GET_IRQ_ROUTING; 101 102 regs.ds = 0xf000; 103 regs.es = FP_SEG((uint_t)(uintptr_t)hdrp); 104 regs.edi.word.di = FP_OFF((uint_t)(uintptr_t)hdrp); 105 106 BOP_DOINT(bootops, 0x1a, ®s); 107 108 n = (int)(((pci_irq_route_hdr_t *)hdrp)->pir_size / 109 sizeof (pci_irq_route_t)); 110 111 if ((regs.eflags & PS_C) != 0) { 112 if (nneededp) 113 *nneededp = n; 114 } else { 115 /* 116 * Copy resulting irq routing data from low memory up to 117 * the kernel address space, avoiding memcpy as usual. 118 */ 119 if (n <= nroutes) { 120 for (i = 0; i < n * sizeof (pci_irq_route_t); i++) 121 ((uchar_t *)routes)[i] = bufp[i]; 122 rval = n; 123 } 124 } 125 return (rval); 126 } 127 128 static void 129 pci_get_irq_routing_table(void) 130 { 131 pci_irq_route_t *routes; 132 int n = N_PCI_IRQ_ROUTES; 133 int nneeded = 0; 134 int nroutes; 135 136 /* 137 * Get irq routing table information. 138 * Allocate a buffer for an initial default number of entries. 139 * If the bios indicates it needs a larger buffer, try it again. 140 * Drive on if it still won't cooperate and play nice after that. 141 */ 142 routes = kmem_zalloc(n * sizeof (pci_irq_route_t), KM_SLEEP); 143 nroutes = pci_bios_get_irq_routing(routes, n, &nneeded); 144 if (nroutes == 0 && nneeded > n) { 145 kmem_free(routes, n * sizeof (pci_irq_route_t)); 146 if (nneeded > N_PCI_IRQ_ROUTES_MAX) { 147 cmn_err(CE_CONT, 148 "pci: unable to get IRQ routing information, " 149 "required buffer space of %d entries exceeds max\n", 150 nneeded); 151 return; 152 } 153 n = nneeded; 154 routes = kmem_zalloc(n * sizeof (pci_irq_route_t), KM_SLEEP); 155 nroutes = pci_bios_get_irq_routing(routes, n, NULL); 156 if (nroutes == 0) { 157 cmn_err(CE_CONT, 158 "pci: unable to get IRQ routing information, " 159 "required buffer space for %d entries\n", n); 160 } 161 } 162 163 if (nroutes > 0) { 164 pci_irq_routes = routes; 165 pci_irq_nroutes = nroutes; 166 } else { 167 kmem_free(routes, n * sizeof (pci_irq_route_t)); 168 } 169 } 170 171 /* 172 * Use the results of the PCI BIOS call that returned the routing tables 173 * to build the 1275 slot-names property for the indicated bus. 174 * Results are returned in buf. Length is return value, -1 is returned on 175 * overflow and zero is returned if no data exists to build a property. 176 */ 177 int 178 pci_slot_names_prop(int bus, char *buf, int len) 179 { 180 uchar_t dev; 181 uchar_t slot[N_PCI_IRQ_ROUTES_MAX+1]; 182 uint32_t mask; 183 int i, nnames, plen; 184 185 ASSERT(pci_irq_nroutes <= N_PCI_IRQ_ROUTES_MAX); 186 187 if (pci_irq_nroutes == 0) 188 return (0); 189 nnames = 0; 190 mask = 0; 191 for (i = 0; i < pci_irq_nroutes; i++) 192 slot[i] = 0xff; 193 for (i = 0; i < pci_irq_nroutes; i++) { 194 if (pci_irq_routes[i].pir_bus != bus) 195 continue; 196 if (pci_irq_routes[i].pir_slot != 0) { 197 dev = (pci_irq_routes[i].pir_dev & 0xf8) >> 3; 198 slot[dev] = pci_irq_routes[i].pir_slot; 199 mask |= (1 << dev); 200 nnames++; 201 } 202 } 203 204 if (nnames == 0) 205 return (0); 206 207 if (len < (4 + nnames * 8)) 208 return (-1); 209 *(uint32_t *)buf = mask; 210 plen = 4; 211 for (i = 0; i < pci_irq_nroutes; i++) { 212 if (slot[i] == 0xff) 213 continue; 214 (void) sprintf(buf + plen, "Slot%d", slot[i]); 215 plen += strlen(buf+plen) + 1; 216 *(buf + plen) = 0; 217 } 218 for (; plen % 4; plen++) 219 *(buf + plen) = 0; 220 return (plen); 221 } 222 223 /* 224 * This is used to discover additional PCI buses that may exist in the system in 225 * addition to the ACPI _BBN method. Historically these were discovered by 226 * asking if there was a valid slot property, e.g. pci_slot_names_prop() 227 * returned valid data. In this case we return any entry that has a bus number 228 * and a non-zero slot value. We rely on the core PCI code to do dedup for us. 229 */ 230 void 231 pci_bios_bus_iter(pci_prd_root_complex_f cbfunc, void *arg) 232 { 233 int i; 234 for (i = 0; i < pci_irq_nroutes; i++) { 235 if (pci_irq_routes[i].pir_slot != 0) { 236 if (!cbfunc(pci_irq_routes[i].pir_bus, arg)) { 237 return; 238 } 239 } 240 } 241 } 242