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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * PCI nexus driver interface
31 */
32 #include <sys/types.h>
33 #include <sys/conf.h> /* nulldev */
34 #include <sys/stat.h> /* devctl */
35 #include <sys/kmem.h>
36 #include <sys/async.h> /* ecc_flt for pci_ecc.h */
37 #include <sys/sunddi.h>
38 #include <sys/sunndi.h>
39 #include <sys/ontrap.h>
40 #include <sys/ddi_impldefs.h>
41 #include <sys/ddi_subrdefs.h>
42 #include <sys/epm.h>
43 #include <sys/membar.h>
44 #include <sys/modctl.h>
45 #include <sys/hotplug/pci/pcihp.h>
46 #include <sys/pci/pci_obj.h>
47
48 /*LINTLIBRARY*/
49
50 static uint8_t pci_axq_hack_get8(ddi_acc_impl_t *handle, uint8_t *addr);
51 static uint16_t pci_axq_hack_get16(ddi_acc_impl_t *handle, uint16_t *addr);
52 static uint32_t pci_axq_hack_get32(ddi_acc_impl_t *handle, uint32_t *addr);
53 static uint64_t pci_axq_hack_get64(ddi_acc_impl_t *handle, uint64_t *addr);
54 static void pci_axq_hack_put8(ddi_acc_impl_t *handle, uint8_t *addr,
55 uint8_t data);
56 static void pci_axq_hack_put16(ddi_acc_impl_t *handle, uint16_t *addr,
57 uint16_t data);
58 static void pci_axq_hack_put32(ddi_acc_impl_t *handle, uint32_t *addr,
59 uint32_t data);
60 static void pci_axq_hack_put64(ddi_acc_impl_t *handle, uint64_t *addr,
61 uint64_t data);
62 static void pci_axq_hack_rep_get8(ddi_acc_impl_t *handle,
63 uint8_t *host_addr, uint8_t *dev_addr,
64 size_t repcount, uint_t flags);
65 static void pci_axq_hack_rep_get16(ddi_acc_impl_t *handle,
66 uint16_t *host_addr, uint16_t *dev_addr,
67 size_t repcount, uint_t flags);
68 static void pci_axq_hack_rep_get32(ddi_acc_impl_t *handle,
69 uint32_t *host_addr, uint32_t *dev_addr,
70 size_t repcount, uint_t flags);
71 static void pci_axq_hack_rep_get64(ddi_acc_impl_t *handle,
72 uint64_t *host_addr, uint64_t *dev_addr,
73 size_t repcount, uint_t flags);
74 static void pci_axq_hack_rep_put8(ddi_acc_impl_t *handle,
75 uint8_t *host_addr, uint8_t *dev_addr,
76 size_t repcount, uint_t flags);
77 static void pci_axq_hack_rep_put16(ddi_acc_impl_t *handle,
78 uint16_t *host_addr, uint16_t *dev_addr,
79 size_t repcount, uint_t flags);
80 static void pci_axq_hack_rep_put32(ddi_acc_impl_t *handle,
81 uint32_t *host_addr, uint32_t *dev_addr,
82 size_t repcount, uint_t flags);
83 static void pci_axq_hack_rep_put64(ddi_acc_impl_t *handle,
84 uint64_t *host_addr, uint64_t *dev_addr,
85 size_t repcount, uint_t flags);
86
87 /*
88 * On Sunfire 15k systems with AXQs less than 6.1
89 * we have to use special PIO routines that limit
90 * the number of outstanding PIOs. We setup the
91 * handle with pointers to our special functions
92 * after it has been succesfully mapped by our
93 * parent.
94 */
95
96 void
pci_axq_pio_limit(pbm_t * pbm_p)97 pci_axq_pio_limit(pbm_t *pbm_p)
98 {
99 pci_t *pci_p = pbm_p->pbm_pci_p;
100 dev_info_t *dip = pci_p->pci_dip;
101 int (*axq_pio_workaround)(dev_info_t *) = NULL;
102
103 axq_pio_workaround =
104 (int (*)(dev_info_t *)) modgetsymvalue(
105 "starcat_axq_pio_workaround", 0);
106
107 if (axq_pio_workaround) {
108 pbm_p->pbm_pio_limit = (axq_pio_workaround)(dip);
109 pbm_p->pbm_pio_counter = pbm_p->pbm_pio_limit;
110 } else
111 pbm_p->pbm_pio_limit = 0;
112 }
113
114 void
pci_axq_setup(ddi_map_req_t * mp,pbm_t * pbm_p)115 pci_axq_setup(ddi_map_req_t *mp, pbm_t *pbm_p)
116 {
117 ddi_acc_hdl_t *hp;
118 ddi_acc_impl_t *ap;
119
120 if (mp->map_op != DDI_MO_MAP_LOCKED)
121 return;
122 if (!pbm_p->pbm_pio_limit)
123 return;
124
125 hp = (ddi_acc_hdl_t *)mp->map_handlep;
126 ap = (ddi_acc_impl_t *)hp->ah_platform_private;
127
128 ap->ahi_get8 = pci_axq_hack_get8;
129 ap->ahi_get16 = pci_axq_hack_get16;
130 ap->ahi_get32 = pci_axq_hack_get32;
131 ap->ahi_get64 = pci_axq_hack_get64;
132 ap->ahi_put8 = pci_axq_hack_put8;
133 ap->ahi_put16 = pci_axq_hack_put16;
134 ap->ahi_put32 = pci_axq_hack_put32;
135 ap->ahi_put64 = pci_axq_hack_put64;
136 ap->ahi_rep_get8 = pci_axq_hack_rep_get8;
137 ap->ahi_rep_get16 = pci_axq_hack_rep_get16;
138 ap->ahi_rep_get32 = pci_axq_hack_rep_get32;
139 ap->ahi_rep_get64 = pci_axq_hack_rep_get64;
140 ap->ahi_rep_put8 = pci_axq_hack_rep_put8;
141 ap->ahi_rep_put16 = pci_axq_hack_rep_put16;
142 ap->ahi_rep_put32 = pci_axq_hack_rep_put32;
143 ap->ahi_rep_put64 = pci_axq_hack_rep_put64;
144
145 hp->ah_bus_private = (void *)pbm_p;
146 }
147
148 /*
149 * get/put routines for SunFire 15K systems that have AXQ versions
150 * less than 6.1. These routines limit the number of outsanding
151 * PIOs issues across a PCI Bus.
152 */
153 static uint8_t
pci_axq_hack_get8(ddi_acc_impl_t * handle,uint8_t * addr)154 pci_axq_hack_get8(ddi_acc_impl_t *handle, uint8_t *addr)
155 {
156 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private;
157 uint8_t data;
158 uint32_t spl;
159
160 spl = ddi_enter_critical();
161 PIO_LIMIT_ENTER(pbm_p);
162 data = i_ddi_get8(handle, addr);
163 PIO_LIMIT_EXIT(pbm_p);
164 ddi_exit_critical(spl);
165
166 return (data);
167 }
168
169 static uint16_t
pci_axq_hack_get16(ddi_acc_impl_t * handle,uint16_t * addr)170 pci_axq_hack_get16(ddi_acc_impl_t *handle, uint16_t *addr)
171 {
172 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private;
173 uint16_t data;
174 uint32_t spl;
175
176 spl = ddi_enter_critical();
177 PIO_LIMIT_ENTER(pbm_p);
178 data = i_ddi_swap_get16(handle, addr);
179 PIO_LIMIT_EXIT(pbm_p);
180 ddi_exit_critical(spl);
181
182 return (data);
183 }
184
185 static uint32_t
pci_axq_hack_get32(ddi_acc_impl_t * handle,uint32_t * addr)186 pci_axq_hack_get32(ddi_acc_impl_t *handle, uint32_t *addr)
187 {
188 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private;
189 uint32_t data;
190 uint32_t spl;
191
192 spl = ddi_enter_critical();
193 PIO_LIMIT_ENTER(pbm_p);
194 data = i_ddi_swap_get32(handle, addr);
195 PIO_LIMIT_EXIT(pbm_p);
196 ddi_exit_critical(spl);
197
198 return (data);
199 }
200
201 static uint64_t
pci_axq_hack_get64(ddi_acc_impl_t * handle,uint64_t * addr)202 pci_axq_hack_get64(ddi_acc_impl_t *handle, uint64_t *addr)
203 {
204 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private;
205 uint64_t data;
206 uint32_t spl;
207
208 spl = ddi_enter_critical();
209 PIO_LIMIT_ENTER(pbm_p);
210 data = i_ddi_swap_get64(handle, addr);
211 PIO_LIMIT_EXIT(pbm_p);
212 ddi_exit_critical(spl);
213
214 return (data);
215 }
216
217 static void
pci_axq_hack_put8(ddi_acc_impl_t * handle,uint8_t * addr,uint8_t data)218 pci_axq_hack_put8(ddi_acc_impl_t *handle, uint8_t *addr, uint8_t data)
219 {
220 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private;
221 uint32_t spl;
222
223 spl = ddi_enter_critical();
224 PIO_LIMIT_ENTER(pbm_p);
225 i_ddi_put8(handle, addr, data);
226 membar_sync();
227 PIO_LIMIT_EXIT(pbm_p);
228 ddi_exit_critical(spl);
229 }
230
231 static void
pci_axq_hack_put16(ddi_acc_impl_t * handle,uint16_t * addr,uint16_t data)232 pci_axq_hack_put16(ddi_acc_impl_t *handle, uint16_t *addr, uint16_t data)
233 {
234 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private;
235 uint32_t spl;
236
237 spl = ddi_enter_critical();
238 PIO_LIMIT_ENTER(pbm_p);
239 i_ddi_swap_put16(handle, addr, data);
240 membar_sync();
241 PIO_LIMIT_EXIT(pbm_p);
242 ddi_exit_critical(spl);
243 }
244
245 static void
pci_axq_hack_put32(ddi_acc_impl_t * handle,uint32_t * addr,uint32_t data)246 pci_axq_hack_put32(ddi_acc_impl_t *handle, uint32_t *addr, uint32_t data)
247 {
248 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private;
249 uint32_t spl;
250
251 spl = ddi_enter_critical();
252 PIO_LIMIT_ENTER(pbm_p);
253 i_ddi_swap_put32(handle, addr, data);
254 membar_sync();
255 PIO_LIMIT_EXIT(pbm_p);
256 ddi_exit_critical(spl);
257 }
258
259 static void
pci_axq_hack_put64(ddi_acc_impl_t * handle,uint64_t * addr,uint64_t data)260 pci_axq_hack_put64(ddi_acc_impl_t *handle, uint64_t *addr, uint64_t data)
261 {
262 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private;
263 uint32_t spl;
264
265 spl = ddi_enter_critical();
266 PIO_LIMIT_ENTER(pbm_p);
267 i_ddi_swap_put64(handle, addr, data);
268 membar_sync();
269 PIO_LIMIT_EXIT(pbm_p);
270 ddi_exit_critical(spl);
271 }
272
273 static void
pci_axq_hack_rep_get8(ddi_acc_impl_t * handle,uint8_t * host_addr,uint8_t * dev_addr,size_t repcount,uint_t flags)274 pci_axq_hack_rep_get8(ddi_acc_impl_t *handle, uint8_t *host_addr,
275 uint8_t *dev_addr, size_t repcount, uint_t flags)
276 {
277 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private;
278 uint32_t spl;
279
280 spl = ddi_enter_critical();
281 PIO_LIMIT_ENTER(pbm_p);
282 i_ddi_rep_get8(handle, host_addr, dev_addr, repcount, flags);
283 PIO_LIMIT_EXIT(pbm_p);
284 ddi_exit_critical(spl);
285 }
286
287 static void
pci_axq_hack_rep_get16(ddi_acc_impl_t * handle,uint16_t * host_addr,uint16_t * dev_addr,size_t repcount,uint_t flags)288 pci_axq_hack_rep_get16(ddi_acc_impl_t *handle, uint16_t *host_addr,
289 uint16_t *dev_addr, size_t repcount, uint_t flags)
290 {
291 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private;
292 uint32_t spl;
293
294 spl = ddi_enter_critical();
295 PIO_LIMIT_ENTER(pbm_p);
296 i_ddi_swap_rep_get16(handle, host_addr, dev_addr, repcount, flags);
297 PIO_LIMIT_EXIT(pbm_p);
298 ddi_exit_critical(spl);
299 }
300
301 static void
pci_axq_hack_rep_get32(ddi_acc_impl_t * handle,uint32_t * host_addr,uint32_t * dev_addr,size_t repcount,uint_t flags)302 pci_axq_hack_rep_get32(ddi_acc_impl_t *handle, uint32_t *host_addr,
303 uint32_t *dev_addr, size_t repcount, uint_t flags)
304 {
305 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private;
306 uint32_t spl;
307
308 spl = ddi_enter_critical();
309 PIO_LIMIT_ENTER(pbm_p);
310 i_ddi_swap_rep_get32(handle, host_addr, dev_addr, repcount, flags);
311 PIO_LIMIT_EXIT(pbm_p);
312 ddi_exit_critical(spl);
313 }
314
315 static void
pci_axq_hack_rep_get64(ddi_acc_impl_t * handle,uint64_t * host_addr,uint64_t * dev_addr,size_t repcount,uint_t flags)316 pci_axq_hack_rep_get64(ddi_acc_impl_t *handle, uint64_t *host_addr,
317 uint64_t *dev_addr, size_t repcount, uint_t flags)
318 {
319 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private;
320 uint32_t spl;
321
322 spl = ddi_enter_critical();
323 PIO_LIMIT_ENTER(pbm_p);
324 i_ddi_swap_rep_get64(handle, host_addr, dev_addr, repcount, flags);
325 PIO_LIMIT_EXIT(pbm_p);
326 ddi_exit_critical(spl);
327 }
328
329 static void
pci_axq_hack_rep_put8(ddi_acc_impl_t * handle,uint8_t * host_addr,uint8_t * dev_addr,size_t repcount,uint_t flags)330 pci_axq_hack_rep_put8(ddi_acc_impl_t *handle, uint8_t *host_addr,
331 uint8_t *dev_addr, size_t repcount, uint_t flags)
332 {
333 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private;
334 uint32_t spl;
335
336 spl = ddi_enter_critical();
337 PIO_LIMIT_ENTER(pbm_p);
338 while (repcount--) {
339 i_ddi_put8(handle, dev_addr, *host_addr);
340 membar_sync();
341 if (flags == DDI_DEV_AUTOINCR)
342 dev_addr++;
343 host_addr++;
344 }
345 PIO_LIMIT_EXIT(pbm_p);
346 ddi_exit_critical(spl);
347 }
348
349 static void
pci_axq_hack_rep_put16(ddi_acc_impl_t * handle,uint16_t * host_addr,uint16_t * dev_addr,size_t repcount,uint_t flags)350 pci_axq_hack_rep_put16(ddi_acc_impl_t *handle, uint16_t *host_addr,
351 uint16_t *dev_addr, size_t repcount, uint_t flags)
352 {
353 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private;
354 uint32_t spl;
355
356 spl = ddi_enter_critical();
357 PIO_LIMIT_ENTER(pbm_p);
358 while (repcount--) {
359 i_ddi_put16(handle, dev_addr, *host_addr);
360 membar_sync();
361 if (flags == DDI_DEV_AUTOINCR)
362 dev_addr++;
363 host_addr++;
364 }
365 PIO_LIMIT_EXIT(pbm_p);
366 ddi_exit_critical(spl);
367 }
368
369 static void
pci_axq_hack_rep_put32(ddi_acc_impl_t * handle,uint32_t * host_addr,uint32_t * dev_addr,size_t repcount,uint_t flags)370 pci_axq_hack_rep_put32(ddi_acc_impl_t *handle, uint32_t *host_addr,
371 uint32_t *dev_addr, size_t repcount, uint_t flags)
372 {
373 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private;
374 uint32_t spl;
375
376 spl = ddi_enter_critical();
377 PIO_LIMIT_ENTER(pbm_p);
378 while (repcount--) {
379 i_ddi_put32(handle, dev_addr, *host_addr);
380 membar_sync();
381 if (flags == DDI_DEV_AUTOINCR)
382 dev_addr++;
383 host_addr++;
384 }
385 PIO_LIMIT_EXIT(pbm_p);
386 ddi_exit_critical(spl);
387 }
388 static void
pci_axq_hack_rep_put64(ddi_acc_impl_t * handle,uint64_t * host_addr,uint64_t * dev_addr,size_t repcount,uint_t flags)389 pci_axq_hack_rep_put64(ddi_acc_impl_t *handle, uint64_t *host_addr,
390 uint64_t *dev_addr, size_t repcount, uint_t flags)
391 {
392 pbm_t *pbm_p = (pbm_t *)handle->ahi_common.ah_bus_private;
393 uint32_t spl;
394
395 spl = ddi_enter_critical();
396 PIO_LIMIT_ENTER(pbm_p);
397 while (repcount--) {
398 i_ddi_put64(handle, dev_addr, *host_addr);
399 membar_sync();
400 if (flags == DDI_DEV_AUTOINCR)
401 dev_addr++;
402 host_addr++;
403 }
404 PIO_LIMIT_EXIT(pbm_p);
405 ddi_exit_critical(spl);
406 }
407