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
startup_pci_bios(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
pci_bios_get_irq_routing(pci_irq_route_t * routes,int nroutes,int * nneededp)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
pci_get_irq_routing_table(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
pci_slot_names_prop(int bus,char * buf,int len)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
pci_bios_bus_iter(pci_prd_root_complex_f cbfunc,void * arg)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