Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/busra.c
+++ new/usr/src/uts/common/io/busra.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 * Copyright 2012 Milan Jurik. All rights reserved.
25 25 */
26 26
27 27 #if defined(DEBUG)
28 28 #define BUSRA_DEBUG
29 29 #endif
30 30
31 31 /*
32 32 * This module provides a set of resource management interfaces
33 33 * to manage bus resources globally in the system.
34 34 *
35 35 * The bus nexus drivers are typically responsible to setup resource
36 36 * maps for the bus resources available for a bus instance. However
37 37 * this module also provides resource setup functions for PCI bus
38 38 * (used by both SPARC and X86 platforms) and ISA bus instances (used
39 39 * only for X86 platforms).
40 40 */
41 41
42 42 #include <sys/types.h>
43 43 #include <sys/systm.h>
44 44 #include <sys/ddi.h>
45 45 #include <sys/sunddi.h>
46 46 #include <sys/sunndi.h>
47 47 #include <sys/ddi_impldefs.h>
48 48 #include <sys/ndi_impldefs.h>
49 49 #include <sys/kmem.h>
50 50 #include <sys/pctypes.h>
51 51 #include <sys/modctl.h>
52 52 #include <sys/debug.h>
53 53 #include <sys/spl.h>
54 54 #include <sys/pci.h>
55 55 #include <sys/autoconf.h>
56 56
57 57 #if defined(BUSRA_DEBUG)
58 58 int busra_debug = 0;
59 59 #define DEBUGPRT \
60 60 if (busra_debug) cmn_err
61 61
62 62 #else
63 63 #define DEBUGPRT \
64 64 if (0) cmn_err
65 65 #endif
66 66
67 67
68 68 /*
69 69 * global mutex that protects the global list of resource maps.
70 70 */
71 71 kmutex_t ra_lock;
72 72
73 73 /*
74 74 * basic resource element
75 75 */
76 76 struct ra_resource {
77 77 struct ra_resource *ra_next;
78 78 uint64_t ra_base;
79 79 uint64_t ra_len;
80 80 };
81 81
82 82 /*
83 83 * link list element for the list of dips (and their resource ranges)
84 84 * for a particular resource type.
85 85 * ra_rangeset points to the list of resources available
86 86 * for this type and this dip.
87 87 */
88 88 struct ra_dip_type {
89 89 struct ra_dip_type *ra_next;
90 90 struct ra_resource *ra_rangeset;
91 91 dev_info_t *ra_dip;
92 92 };
93 93
94 94
95 95 /*
96 96 * link list element for list of types resources. Each element
97 97 * has all resources for a particular type.
98 98 */
99 99 struct ra_type_map {
100 100 struct ra_type_map *ra_next;
101 101 struct ra_dip_type *ra_dip_list;
102 102 char *type;
103 103 };
104 104
105 105
106 106 /*
107 107 * place holder to keep the head of the whole global list.
108 108 * the address of the first typemap would be stored in it.
109 109 */
110 110 static struct ra_type_map *ra_map_list_head = NULL;
111 111
112 112
113 113 /*
114 114 * This is the loadable module wrapper.
115 115 * It is essentially boilerplate so isn't documented
116 116 */
117 117 extern struct mod_ops mod_miscops;
118 118
119 119 #ifdef BUSRA_DEBUG
120 120 void ra_dump_all(char *, dev_info_t *);
121 121 #endif
122 122
123 123 /* internal function prototypes */
124 124 static struct ra_dip_type *find_dip_map_resources(dev_info_t *dip, char *type,
125 125 struct ra_dip_type ***backdip, struct ra_type_map ***backtype,
126 126 uint32_t flag);
127 127 static int isnot_pow2(uint64_t value);
128 128 static int claim_pci_busnum(dev_info_t *dip, void *arg);
129 129 static int ra_map_exist(dev_info_t *dip, char *type);
130 130
131 131 static int pci_get_available_prop(dev_info_t *dip, uint64_t base,
132 132 uint64_t len, char *busra_type);
133 133 static int pci_put_available_prop(dev_info_t *dip, uint64_t base,
134 134 uint64_t len, char *busra_type);
135 135 static uint32_t pci_type_ra2pci(char *type);
136 136 static boolean_t is_pcie_fabric(dev_info_t *dip);
137 137
138 138 #define PCI_ADDR_TYPE_MASK (PCI_REG_ADDR_M | PCI_REG_PF_M)
139 139 #define PCI_ADDR_TYPE_INVAL 0xffffffff
140 140
141 141 #define RA_INSERT(prev, el) \
142 142 el->ra_next = *prev; \
143 143 *prev = el;
144 144
↓ open down ↓ |
144 lines elided |
↑ open up ↑ |
145 145 #define RA_REMOVE(prev, el) \
146 146 *prev = el->ra_next;
147 147
148 148
149 149 static struct modlmisc modlmisc = {
150 150 &mod_miscops, /* Type of module. This one is a module */
151 151 "Bus Resource Allocator (BUSRA)", /* Name of the module. */
152 152 };
153 153
154 154 static struct modlinkage modlinkage = {
155 - MODREV_1, (void *)&modlmisc, NULL
155 + MODREV_1, { (void *)&modlmisc, NULL }
156 156 };
157 157
158 158 int
159 159 _init()
160 160 {
161 161 int ret;
162 162
163 163 mutex_init(&ra_lock, NULL, MUTEX_DRIVER,
164 164 (void *)(intptr_t)__ipltospl(SPL7 - 1));
165 165 if ((ret = mod_install(&modlinkage)) != 0) {
166 166 mutex_destroy(&ra_lock);
167 167 }
168 168 return (ret);
169 169 }
170 170
171 171 int
172 172 _fini()
173 173 {
174 174 int ret;
175 175
176 176 mutex_enter(&ra_lock);
177 177
178 178 if (ra_map_list_head != NULL) {
179 179 mutex_exit(&ra_lock);
180 180 return (EBUSY);
181 181 }
182 182
183 183 ret = mod_remove(&modlinkage);
184 184
185 185 mutex_exit(&ra_lock);
186 186
187 187 if (ret == 0)
188 188 mutex_destroy(&ra_lock);
189 189
190 190 return (ret);
191 191 }
192 192
193 193 int
194 194 _info(struct modinfo *modinfop)
195 195
196 196 {
197 197 return (mod_info(&modlinkage, modinfop));
198 198 }
199 199
200 200 /*
201 201 * set up an empty resource map for a given type and dip
202 202 */
203 203 int
204 204 ndi_ra_map_setup(dev_info_t *dip, char *type)
205 205 {
206 206 struct ra_type_map *typemapp;
207 207 struct ra_dip_type *dipmap;
208 208 struct ra_dip_type **backdip;
209 209 struct ra_type_map **backtype;
210 210
211 211
212 212 mutex_enter(&ra_lock);
213 213
214 214 dipmap = find_dip_map_resources(dip, type, &backdip, &backtype, 0);
215 215
216 216 if (dipmap == NULL) {
217 217 if (backtype == NULL) {
218 218 typemapp = (struct ra_type_map *)
219 219 kmem_zalloc(sizeof (*typemapp), KM_SLEEP);
220 220 typemapp->type = (char *)kmem_zalloc(strlen(type) + 1,
221 221 KM_SLEEP);
222 222 (void) strcpy(typemapp->type, type);
223 223 RA_INSERT(&ra_map_list_head, typemapp);
224 224 } else {
225 225 typemapp = *backtype;
226 226 }
227 227 if (backdip == NULL) {
228 228 /* allocate and insert in list of dips for this type */
229 229 dipmap = (struct ra_dip_type *)
230 230 kmem_zalloc(sizeof (*dipmap), KM_SLEEP);
231 231 dipmap->ra_dip = dip;
232 232 RA_INSERT(&typemapp->ra_dip_list, dipmap);
233 233 }
234 234 }
235 235
236 236 mutex_exit(&ra_lock);
237 237 return (NDI_SUCCESS);
238 238 }
239 239
240 240 /*
241 241 * destroys a resource map for a given dip and type
242 242 */
243 243 int
244 244 ndi_ra_map_destroy(dev_info_t *dip, char *type)
245 245 {
246 246 struct ra_dip_type *dipmap;
247 247 struct ra_dip_type **backdip;
248 248 struct ra_type_map **backtype, *typemap;
249 249 struct ra_resource *range;
250 250
251 251 mutex_enter(&ra_lock);
252 252 dipmap = find_dip_map_resources(dip, type, &backdip, &backtype, 0);
253 253
254 254 if (dipmap == NULL) {
255 255 mutex_exit(&ra_lock);
256 256 return (NDI_FAILURE);
257 257 }
258 258
259 259 /*
260 260 * destroy all resources for this dip
261 261 * remove dip from type list
262 262 */
263 263 ASSERT((backdip != NULL) && (backtype != NULL));
264 264 while (dipmap->ra_rangeset != NULL) {
265 265 range = dipmap->ra_rangeset;
266 266 RA_REMOVE(&dipmap->ra_rangeset, range);
267 267 kmem_free((caddr_t)range, sizeof (*range));
268 268 }
269 269 /* remove from dip list */
270 270 RA_REMOVE(backdip, dipmap);
271 271 kmem_free((caddr_t)dipmap, sizeof (*dipmap));
272 272 if ((*backtype)->ra_dip_list == NULL) {
273 273 /*
274 274 * This was the last dip with this resource type.
275 275 * Remove the type from the global list.
276 276 */
277 277 typemap = *backtype;
278 278 RA_REMOVE(backtype, (*backtype));
279 279 kmem_free((caddr_t)typemap->type, strlen(typemap->type) + 1);
280 280 kmem_free((caddr_t)typemap, sizeof (*typemap));
281 281 }
282 282
283 283 mutex_exit(&ra_lock);
284 284 return (NDI_SUCCESS);
285 285 }
286 286
287 287 static int
288 288 ra_map_exist(dev_info_t *dip, char *type)
289 289 {
290 290 struct ra_dip_type **backdip;
291 291 struct ra_type_map **backtype;
292 292
293 293 mutex_enter(&ra_lock);
294 294 if (find_dip_map_resources(dip, type, &backdip, &backtype, 0) == NULL) {
295 295 mutex_exit(&ra_lock);
296 296 return (NDI_FAILURE);
297 297 }
298 298
299 299 mutex_exit(&ra_lock);
300 300 return (NDI_SUCCESS);
301 301 }
302 302 /*
303 303 * Find a dip map for the specified type, if NDI_RA_PASS will go up on dev tree
304 304 * if found, backdip and backtype will be updated to point to the previous
305 305 * dip in the list and previous type for this dip in the list.
306 306 * If no such type at all in the resource list both backdip and backtype
307 307 * will be null. If the type found but no dip, back dip will be null.
308 308 */
309 309
310 310 static struct ra_dip_type *
311 311 find_dip_map_resources(dev_info_t *dip, char *type,
312 312 struct ra_dip_type ***backdip, struct ra_type_map ***backtype,
313 313 uint32_t flag)
314 314 {
315 315 struct ra_type_map **prevmap;
316 316 struct ra_dip_type *dipmap, **prevdip;
317 317
318 318 ASSERT(mutex_owned(&ra_lock));
319 319 prevdip = NULL;
320 320 dipmap = NULL;
321 321 prevmap = &ra_map_list_head;
322 322
323 323 while (*prevmap) {
324 324 if (strcmp((*prevmap)->type, type) == 0)
325 325 break;
326 326 prevmap = &(*prevmap)->ra_next;
327 327 }
328 328
329 329 if (*prevmap) {
330 330 for (; dip != NULL; dip = ddi_get_parent(dip)) {
331 331 prevdip = &(*prevmap)->ra_dip_list;
332 332 dipmap = *prevdip;
333 333
334 334 while (dipmap) {
335 335 if (dipmap->ra_dip == dip)
336 336 break;
337 337 prevdip = &dipmap->ra_next;
338 338 dipmap = dipmap->ra_next;
339 339 }
340 340
341 341 if (dipmap != NULL) {
342 342 /* found it */
343 343 break;
344 344 }
345 345
346 346 if (!(flag & NDI_RA_PASS)) {
347 347 break;
348 348 }
349 349 }
350 350 }
351 351
352 352 *backtype = (*prevmap == NULL) ? NULL: prevmap;
353 353 *backdip = (dipmap == NULL) ? NULL: prevdip;
354 354
355 355 return (dipmap);
356 356 }
357 357
358 358 int
359 359 ndi_ra_free(dev_info_t *dip, uint64_t base, uint64_t len, char *type,
360 360 uint32_t flag)
361 361 {
362 362 struct ra_dip_type *dipmap;
363 363 struct ra_resource *newmap, *overlapmap, *oldmap = NULL;
364 364 struct ra_resource *mapp, **backp;
365 365 uint64_t newend, mapend;
366 366 struct ra_dip_type **backdip;
367 367 struct ra_type_map **backtype;
368 368
369 369 if (len == 0) {
370 370 return (NDI_SUCCESS);
371 371 }
372 372
373 373 mutex_enter(&ra_lock);
374 374
375 375 if ((dipmap = find_dip_map_resources(dip, type, &backdip, &backtype,
376 376 flag)) == NULL) {
377 377 mutex_exit(&ra_lock);
378 378 return (NDI_FAILURE);
379 379 }
380 380
381 381 mapp = dipmap->ra_rangeset;
382 382 backp = &dipmap->ra_rangeset;
383 383
384 384 /* now find where range lies and fix things up */
385 385 newend = base + len;
386 386 for (; mapp != NULL; backp = &(mapp->ra_next), mapp = mapp->ra_next) {
387 387 mapend = mapp->ra_base + mapp->ra_len;
388 388
389 389 /* check for overlap first */
390 390 if ((base <= mapp->ra_base && newend > mapp->ra_base) ||
391 391 (base > mapp->ra_base && base < mapend)) {
392 392 /* overlap with mapp */
393 393 overlapmap = mapp;
394 394 goto overlap;
395 395 } else if ((base == mapend && mapp->ra_next) &&
396 396 (newend > mapp->ra_next->ra_base)) {
397 397 /* overlap with mapp->ra_next */
398 398 overlapmap = mapp->ra_next;
399 399 goto overlap;
400 400 }
401 401
402 402 if (newend == mapp->ra_base) {
403 403 /* simple - on front */
404 404 mapp->ra_base = base;
405 405 mapp->ra_len += len;
406 406 /*
407 407 * don't need to check if it merges with
408 408 * previous since that would match on on end
409 409 */
410 410 break;
411 411 } else if (base == mapend) {
412 412 /* simple - on end */
413 413 mapp->ra_len += len;
414 414 if (mapp->ra_next &&
415 415 (newend == mapp->ra_next->ra_base)) {
416 416 /* merge with next node */
417 417 oldmap = mapp->ra_next;
418 418 mapp->ra_len += oldmap->ra_len;
419 419 RA_REMOVE(&mapp->ra_next, oldmap);
420 420 kmem_free((caddr_t)oldmap, sizeof (*oldmap));
421 421 }
422 422 break;
423 423 } else if (base < mapp->ra_base) {
424 424 /* somewhere in between so just an insert */
425 425 newmap = (struct ra_resource *)
426 426 kmem_zalloc(sizeof (*newmap), KM_SLEEP);
427 427 newmap->ra_base = base;
428 428 newmap->ra_len = len;
429 429 RA_INSERT(backp, newmap);
430 430 break;
431 431 }
432 432 }
433 433 if (mapp == NULL) {
434 434 /* stick on end */
435 435 newmap = (struct ra_resource *)
436 436 kmem_zalloc(sizeof (*newmap), KM_SLEEP);
437 437 newmap->ra_base = base;
438 438 newmap->ra_len = len;
439 439 RA_INSERT(backp, newmap);
440 440 }
441 441
442 442 mutex_exit(&ra_lock);
443 443
444 444 /*
445 445 * Update dip's "available" property, adding this piece of
446 446 * resource to the pool.
447 447 */
448 448 (void) pci_put_available_prop(dipmap->ra_dip, base, len, type);
449 449 done:
450 450 return (NDI_SUCCESS);
451 451
452 452 overlap:
453 453 /*
454 454 * Bad free may happen on some x86 platforms with BIOS exporting
455 455 * incorrect resource maps. The system is otherwise functioning
456 456 * normally. We send such messages to syslog only.
457 457 */
458 458 cmn_err(CE_NOTE, "!ndi_ra_free: bad free, dip %p, resource type %s \n",
459 459 (void *)dip, type);
460 460 cmn_err(CE_NOTE, "!ndi_ra_free: freeing base 0x%" PRIx64 ", len 0x%"
461 461 PRIX64 " overlaps with existing resource base 0x%" PRIx64
462 462 ", len 0x%" PRIx64 "\n", base, len, overlapmap->ra_base,
463 463 overlapmap->ra_len);
464 464
465 465 mutex_exit(&ra_lock);
466 466 return (NDI_FAILURE);
467 467 }
468 468
469 469 /* check to see if value is power of 2 or not. */
470 470 static int
471 471 isnot_pow2(uint64_t value)
472 472 {
473 473 uint32_t low;
474 474 uint32_t hi;
475 475
476 476 low = value & 0xffffffff;
477 477 hi = value >> 32;
478 478
479 479 /*
480 480 * ddi_ffs and ddi_fls gets long values, so in 32bit environment
481 481 * won't work correctly for 64bit values
482 482 */
483 483 if ((ddi_ffs(low) == ddi_fls(low)) &&
484 484 (ddi_ffs(hi) == ddi_fls(hi)))
485 485 return (0);
486 486 return (1);
487 487 }
488 488
489 489 static void
490 490 adjust_link(struct ra_resource **backp, struct ra_resource *mapp,
491 491 uint64_t base, uint64_t len)
492 492 {
493 493 struct ra_resource *newmap;
494 494 uint64_t newlen;
495 495
496 496 if (base != mapp->ra_base) {
497 497 /* in the middle or end */
498 498 newlen = base - mapp->ra_base;
499 499 if ((mapp->ra_len - newlen) == len) {
500 500 /* on the end */
501 501 mapp->ra_len = newlen;
502 502 } else {
503 503 /* in the middle */
504 504 newmap = (struct ra_resource *)
505 505 kmem_zalloc(sizeof (*newmap), KM_SLEEP);
506 506 newmap->ra_base = base + len;
507 507 newmap->ra_len = mapp->ra_len - (len + newlen);
508 508 mapp->ra_len = newlen;
509 509 RA_INSERT(&(mapp->ra_next), newmap);
510 510 }
511 511 } else {
512 512 /* at the beginning */
513 513 mapp->ra_base += len;
514 514 mapp->ra_len -= len;
515 515 if (mapp->ra_len == 0) {
516 516 /* remove the whole node */
517 517 RA_REMOVE(backp, mapp);
518 518 kmem_free((caddr_t)mapp, sizeof (*mapp));
519 519 }
520 520 }
521 521 }
522 522
523 523 int
524 524 ndi_ra_alloc(dev_info_t *dip, ndi_ra_request_t *req, uint64_t *retbasep,
525 525 uint64_t *retlenp, char *type, uint32_t flag)
526 526 {
527 527 struct ra_dip_type *dipmap;
528 528 struct ra_resource *mapp, **backp, **backlargestp;
529 529 uint64_t mask = 0;
530 530 uint64_t len, remlen, largestbase, largestlen;
531 531 uint64_t base, oldbase, lower, upper;
532 532 struct ra_dip_type **backdip;
533 533 struct ra_type_map **backtype;
534 534 int rval = NDI_FAILURE;
535 535
536 536
537 537 len = req->ra_len;
538 538
539 539 if (req->ra_flags & NDI_RA_ALIGN_SIZE) {
540 540 if (isnot_pow2(req->ra_len)) {
541 541 DEBUGPRT(CE_WARN, "ndi_ra_alloc: bad length(pow2) 0x%"
542 542 PRIx64, req->ra_len);
543 543 *retbasep = 0;
544 544 *retlenp = 0;
545 545 return (NDI_FAILURE);
546 546 }
547 547 }
548 548
549 549 mask = (req->ra_flags & NDI_RA_ALIGN_SIZE) ? (len - 1) :
550 550 req->ra_align_mask;
551 551
552 552
553 553 mutex_enter(&ra_lock);
554 554 dipmap = find_dip_map_resources(dip, type, &backdip, &backtype, flag);
555 555 if ((dipmap == NULL) || ((mapp = dipmap->ra_rangeset) == NULL)) {
556 556 mutex_exit(&ra_lock);
557 557 DEBUGPRT(CE_CONT, "ndi_ra_alloc no map found for this type\n");
558 558 return (NDI_FAILURE);
559 559 }
560 560
561 561 DEBUGPRT(CE_CONT, "ndi_ra_alloc: mapp = %p len=%" PRIx64 ", mask=%"
562 562 PRIx64 "\n", (void *)mapp, len, mask);
563 563
564 564 backp = &(dipmap->ra_rangeset);
565 565 backlargestp = NULL;
566 566 largestbase = 0;
567 567 largestlen = 0;
568 568
569 569 lower = 0;
570 570 upper = ~(uint64_t)0;
571 571
572 572 if (req->ra_flags & NDI_RA_ALLOC_BOUNDED) {
573 573 /* bounded so skip to first possible */
574 574 lower = req->ra_boundbase;
575 575 upper = req->ra_boundlen + lower;
576 576 if ((upper == 0) || (upper < req->ra_boundlen))
577 577 upper = ~(uint64_t)0;
578 578 DEBUGPRT(CE_CONT, "ndi_ra_alloc: ra_len = %" PRIx64 ", len = %"
579 579 PRIx64 " ra_base=%" PRIx64 ", mask=%" PRIx64
580 580 "\n", mapp->ra_len, len, mapp->ra_base, mask);
581 581 for (; mapp != NULL && (mapp->ra_base + mapp->ra_len) < lower;
582 582 backp = &(mapp->ra_next), mapp = mapp->ra_next) {
583 583 if (((mapp->ra_len + mapp->ra_base) == 0) ||
584 584 ((mapp->ra_len + mapp->ra_base) < mapp->ra_len))
585 585 /*
586 586 * This elements end goes beyond max uint64_t.
587 587 * potential candidate, check end against lower
588 588 * would not be precise.
589 589 */
590 590 break;
591 591
592 592 DEBUGPRT(CE_CONT, " ra_len = %" PRIx64 ", ra_base=%"
593 593 PRIx64 "\n", mapp->ra_len, mapp->ra_base);
594 594 }
595 595
596 596 }
597 597
598 598 if (!(req->ra_flags & NDI_RA_ALLOC_SPECIFIED)) {
599 599 /* first fit - not user specified */
600 600 DEBUGPRT(CE_CONT, "ndi_ra_alloc(unspecified request)"
601 601 "lower=%" PRIx64 ", upper=%" PRIx64 "\n", lower, upper);
602 602 for (; mapp != NULL && mapp->ra_base <= upper;
603 603 backp = &(mapp->ra_next), mapp = mapp->ra_next) {
604 604
605 605 DEBUGPRT(CE_CONT, "ndi_ra_alloc: ra_len = %" PRIx64
606 606 ", len = %" PRIx64 "", mapp->ra_len, len);
607 607 base = mapp->ra_base;
608 608 if (base < lower) {
609 609 base = lower;
610 610 DEBUGPRT(CE_CONT, "\tbase=%" PRIx64
611 611 ", ra_base=%" PRIx64 ", mask=%" PRIx64,
612 612 base, mapp->ra_base, mask);
613 613 }
614 614
615 615 if ((base & mask) != 0) {
616 616 oldbase = base;
617 617 /*
618 618 * failed a critical constraint
619 619 * adjust and see if it still fits
620 620 */
621 621 base = base & ~mask;
622 622 base += (mask + 1);
623 623 DEBUGPRT(CE_CONT, "\tnew base=%" PRIx64 "\n",
624 624 base);
625 625
626 626 /*
627 627 * Check to see if the new base is past
628 628 * the end of the resource.
629 629 */
630 630 if (base >= (oldbase + mapp->ra_len + 1)) {
631 631 continue;
632 632 }
633 633 }
634 634
635 635 if (req->ra_flags & NDI_RA_ALLOC_PARTIAL_OK) {
636 636 if ((upper - mapp->ra_base) < mapp->ra_len)
637 637 remlen = upper - base;
638 638 else
639 639 remlen = mapp->ra_len -
640 640 (base - mapp->ra_base);
641 641
642 642 if ((backlargestp == NULL) ||
643 643 (largestlen < remlen)) {
644 644
645 645 backlargestp = backp;
646 646 largestbase = base;
647 647 largestlen = remlen;
648 648 }
649 649 }
650 650
651 651 if (mapp->ra_len >= len) {
652 652 /* a candidate -- apply constraints */
653 653 if ((len > (mapp->ra_len -
654 654 (base - mapp->ra_base))) ||
655 655 ((len - 1 + base) > upper)) {
656 656 continue;
657 657 }
658 658
659 659 /* we have a fit */
660 660
661 661 DEBUGPRT(CE_CONT, "\thave a fit\n");
662 662
663 663 adjust_link(backp, mapp, base, len);
664 664 rval = NDI_SUCCESS;
665 665 break;
666 666
667 667 }
668 668 }
669 669 } else {
670 670 /* want an exact value/fit */
671 671 base = req->ra_addr;
672 672 len = req->ra_len;
673 673 for (; mapp != NULL && mapp->ra_base <= upper;
674 674 backp = &(mapp->ra_next), mapp = mapp->ra_next) {
675 675 if (base >= mapp->ra_base &&
676 676 ((base - mapp->ra_base) < mapp->ra_len)) {
677 677 /*
678 678 * This is the node with he requested base in
679 679 * its range
680 680 */
681 681 if ((len > mapp->ra_len) ||
682 682 (base - mapp->ra_base >
683 683 mapp->ra_len - len)) {
684 684 /* length requirement not satisfied */
685 685 if (req->ra_flags &
686 686 NDI_RA_ALLOC_PARTIAL_OK) {
687 687 if ((upper - mapp->ra_base)
688 688 < mapp->ra_len)
689 689 remlen = upper - base;
690 690 else
691 691 remlen =
692 692 mapp->ra_len -
693 693 (base -
694 694 mapp->ra_base);
695 695 }
696 696 backlargestp = backp;
697 697 largestbase = base;
698 698 largestlen = remlen;
699 699 base = 0;
700 700 } else {
701 701 /* We have a match */
702 702 adjust_link(backp, mapp, base, len);
703 703 rval = NDI_SUCCESS;
704 704 }
705 705 break;
706 706 }
707 707 }
708 708 }
709 709
710 710 if ((rval != NDI_SUCCESS) &&
711 711 (req->ra_flags & NDI_RA_ALLOC_PARTIAL_OK) &&
712 712 (backlargestp != NULL)) {
713 713 adjust_link(backlargestp, *backlargestp, largestbase,
714 714 largestlen);
715 715
716 716 base = largestbase;
717 717 len = largestlen;
718 718 rval = NDI_RA_PARTIAL_REQ;
719 719 }
720 720
721 721 mutex_exit(&ra_lock);
722 722
723 723 if (rval == NDI_FAILURE) {
724 724 *retbasep = 0;
725 725 *retlenp = 0;
726 726 } else {
727 727 *retbasep = base;
728 728 *retlenp = len;
729 729 }
730 730
731 731 /*
732 732 * Update dip's "available" property, substract this piece of
733 733 * resource from the pool.
734 734 */
735 735 if ((rval == NDI_SUCCESS) || (rval == NDI_RA_PARTIAL_REQ))
736 736 (void) pci_get_available_prop(dipmap->ra_dip,
737 737 *retbasep, *retlenp, type);
738 738
739 739 return (rval);
740 740 }
741 741
742 742 /*
743 743 * isa_resource_setup
744 744 * check for /used-resources and initialize
745 745 * based on info there. If no /used-resources,
746 746 * fail.
747 747 */
748 748 int
749 749 isa_resource_setup()
750 750 {
751 751 dev_info_t *used, *usedpdip;
752 752 /*
753 753 * note that at this time bootconf creates 32 bit properties for
754 754 * io-space and device-memory
755 755 */
756 756 struct iorange {
757 757 uint32_t base;
758 758 uint32_t len;
759 759 } *iorange;
760 760 struct memrange {
761 761 uint32_t base;
762 762 uint32_t len;
763 763 } *memrange;
764 764 uint32_t *irq;
765 765 int proplen;
766 766 int i, len;
767 767 int maxrange;
768 768 ndi_ra_request_t req;
769 769 uint64_t retbase;
770 770 uint64_t retlen;
771 771
772 772 used = ddi_find_devinfo("used-resources", -1, 0);
773 773 if (used == NULL) {
774 774 DEBUGPRT(CE_CONT,
775 775 "isa_resource_setup: used-resources not found");
776 776 return (NDI_FAILURE);
777 777 }
778 778
779 779 /*
780 780 * initialize to all resources being present
781 781 * and then remove the ones in use.
782 782 */
783 783
784 784 usedpdip = ddi_root_node();
785 785
786 786 DEBUGPRT(CE_CONT, "isa_resource_setup: used = %p usedpdip = %p\n",
787 787 (void *)used, (void *)usedpdip);
788 788
789 789 if (ndi_ra_map_setup(usedpdip, NDI_RA_TYPE_IO) == NDI_FAILURE) {
790 790 return (NDI_FAILURE);
791 791 }
792 792
793 793 /* initialize io space, highest end base is 0xffff */
794 794 /* note that length is highest addr + 1 since starts from 0 */
795 795
796 796 (void) ndi_ra_free(usedpdip, 0, 0xffff + 1, NDI_RA_TYPE_IO, 0);
797 797
798 798 if (ddi_getlongprop(DDI_DEV_T_ANY, used, DDI_PROP_DONTPASS,
799 799 "io-space", (caddr_t)&iorange, &proplen) == DDI_SUCCESS) {
800 800 maxrange = proplen / sizeof (struct iorange);
801 801 /* remove the "used" I/O resources */
802 802 for (i = 0; i < maxrange; i++) {
803 803 bzero((caddr_t)&req, sizeof (req));
804 804 req.ra_addr = (uint64_t)iorange[i].base;
805 805 req.ra_len = (uint64_t)iorange[i].len;
806 806 req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
807 807 (void) ndi_ra_alloc(usedpdip, &req, &retbase, &retlen,
808 808 NDI_RA_TYPE_IO, 0);
809 809 }
810 810
811 811 kmem_free((caddr_t)iorange, proplen);
812 812 }
813 813
814 814 if (ndi_ra_map_setup(usedpdip, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
815 815 return (NDI_FAILURE);
816 816 }
817 817 /* initialize memory space where highest end base is 0xffffffff */
818 818 /* note that length is highest addr + 1 since starts from 0 */
819 819 (void) ndi_ra_free(usedpdip, 0, ((uint64_t)((uint32_t)~0)) + 1,
820 820 NDI_RA_TYPE_MEM, 0);
821 821
822 822 if (ddi_getlongprop(DDI_DEV_T_ANY, used, DDI_PROP_DONTPASS,
823 823 "device-memory", (caddr_t)&memrange, &proplen) == DDI_SUCCESS) {
824 824 maxrange = proplen / sizeof (struct memrange);
825 825 /* remove the "used" memory resources */
826 826 for (i = 0; i < maxrange; i++) {
827 827 bzero((caddr_t)&req, sizeof (req));
828 828 req.ra_addr = (uint64_t)memrange[i].base;
829 829 req.ra_len = (uint64_t)memrange[i].len;
830 830 req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
831 831 (void) ndi_ra_alloc(usedpdip, &req, &retbase, &retlen,
832 832 NDI_RA_TYPE_MEM, 0);
833 833 }
834 834
835 835 kmem_free((caddr_t)memrange, proplen);
836 836 }
837 837
838 838 if (ndi_ra_map_setup(usedpdip, NDI_RA_TYPE_INTR) == NDI_FAILURE) {
839 839 return (NDI_FAILURE);
840 840 }
841 841
842 842 /* initialize the interrupt space */
843 843 (void) ndi_ra_free(usedpdip, 0, 16, NDI_RA_TYPE_INTR, 0);
844 844
845 845 #if defined(__i386) || defined(__amd64)
846 846 bzero(&req, sizeof (req));
847 847 req.ra_addr = 2; /* 2 == 9 so never allow */
848 848 req.ra_len = 1;
849 849 req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
850 850 (void) ndi_ra_alloc(usedpdip, &req, &retbase, &retlen,
851 851 NDI_RA_TYPE_INTR, 0);
852 852 #endif
853 853
854 854 if (ddi_getlongprop(DDI_DEV_T_ANY, used, DDI_PROP_DONTPASS,
855 855 "interrupts", (caddr_t)&irq, &proplen) == DDI_SUCCESS) {
856 856 /* Initialize available interrupts by negating the used */
857 857 len = (proplen / sizeof (uint32_t));
858 858 for (i = 0; i < len; i++) {
859 859 bzero((caddr_t)&req, sizeof (req));
860 860 req.ra_addr = (uint64_t)irq[i];
861 861 req.ra_len = 1;
862 862 req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
863 863 (void) ndi_ra_alloc(usedpdip, &req, &retbase, &retlen,
864 864 NDI_RA_TYPE_INTR, 0);
865 865 }
866 866 kmem_free((caddr_t)irq, proplen);
867 867 }
868 868
869 869 #ifdef BUSRA_DEBUG
870 870 if (busra_debug) {
871 871 (void) ra_dump_all(NULL, usedpdip);
872 872 }
873 873 #endif
874 874 return (NDI_SUCCESS);
875 875
876 876 }
877 877
878 878 #ifdef BUSRA_DEBUG
879 879 void
880 880 ra_dump_all(char *type, dev_info_t *dip)
881 881 {
882 882
883 883 struct ra_type_map *typemap;
884 884 struct ra_dip_type *dipmap;
885 885 struct ra_resource *res;
886 886
887 887 typemap = (struct ra_type_map *)ra_map_list_head;
888 888
889 889 for (; typemap != NULL; typemap = typemap->ra_next) {
890 890 if (type != NULL) {
891 891 if (strcmp(typemap->type, type) != 0)
892 892 continue;
893 893 }
894 894 cmn_err(CE_CONT, "type is %s\n", typemap->type);
895 895 for (dipmap = typemap->ra_dip_list; dipmap != NULL;
896 896 dipmap = dipmap->ra_next) {
897 897 if (dip != NULL) {
898 898 if ((dipmap->ra_dip) != dip)
899 899 continue;
900 900 }
901 901 cmn_err(CE_CONT, " dip is %p\n",
902 902 (void *)dipmap->ra_dip);
903 903 for (res = dipmap->ra_rangeset; res != NULL;
904 904 res = res->ra_next) {
905 905 cmn_err(CE_CONT, "\t range is %" PRIx64
906 906 " %" PRIx64 "\n", res->ra_base,
907 907 res->ra_len);
908 908 }
909 909 if (dip != NULL)
910 910 break;
911 911 }
912 912 if (type != NULL)
913 913 break;
914 914 }
915 915 }
916 916 #endif
917 917
918 918 struct bus_range { /* 1275 "bus-range" property definition */
919 919 uint32_t lo;
920 920 uint32_t hi;
921 921 } pci_bus_range;
922 922
923 923 struct busnum_ctrl {
924 924 int rv;
925 925 dev_info_t *dip;
926 926 struct bus_range *range;
927 927 };
928 928
929 929
930 930 /*
931 931 * Setup resource map for the pci bus node based on the "available"
932 932 * property and "bus-range" property.
933 933 */
934 934 int
935 935 pci_resource_setup(dev_info_t *dip)
936 936 {
937 937 pci_regspec_t *regs;
938 938 int rlen, rcount, i;
939 939 char bus_type[16] = "(unknown)";
940 940 int len;
941 941 struct busnum_ctrl ctrl;
942 942 int circular_count;
943 943 int rval = NDI_SUCCESS;
944 944
945 945 /*
946 946 * If this is a pci bus node then look for "available" property
947 947 * to find the available resources on this bus.
948 948 */
949 949 len = sizeof (bus_type);
950 950 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
951 951 DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "device_type",
952 952 (caddr_t)&bus_type, &len) != DDI_SUCCESS)
953 953 return (NDI_FAILURE);
954 954
955 955 /* it is not a pci/pci-ex bus type */
956 956 if ((strcmp(bus_type, "pci") != 0) && (strcmp(bus_type, "pciex") != 0))
957 957 return (NDI_FAILURE);
958 958
959 959 /*
960 960 * The pci-hotplug project addresses adding the call
961 961 * to pci_resource_setup from pci nexus driver.
962 962 * However that project would initially be only for x86,
963 963 * so for sparc pcmcia-pci support we still need to call
964 964 * pci_resource_setup in pcic driver. Once all pci nexus drivers
965 965 * are updated to call pci_resource_setup this portion of the
966 966 * code would really become an assert to make sure this
967 967 * function is not called for the same dip twice.
968 968 */
969 969 /*
970 970 * Another user for the check below is hotplug PCI/PCIe bridges.
971 971 *
972 972 * For PCI/PCIE devices under a PCIE hierarchy, ndi_ra_alloc/free
973 973 * will update the devinfo node's "available" property, to reflect
974 974 * the fact that a piece of resource has been removed/added to
975 975 * a devinfo node.
976 976 * During probe of a new PCI bridge in the hotplug case, PCI
977 977 * configurator firstly allocates maximum MEM/IO from its parent,
978 978 * then calls ndi_ra_free() to use these resources to setup busra
979 979 * pool for the new bridge, as well as adding these resources to
980 980 * the "available" property of the new devinfo node. Then configu-
981 981 * rator will attach driver for the bridge before probing its
982 982 * children, and the bridge driver will then initialize its hotplug
983 983 * contollers (if it supports hotplug) and HPC driver will call
984 984 * this function to setup the busra pool, but the resource pool
985 985 * has already been setup at the first of pcicfg_probe_bridge(),
986 986 * thus we need the check below to return directly in this case.
987 987 * Otherwise the ndi_ra_free() below will see overlapping resources.
988 988 */
989 989 {
990 990 if (ra_map_exist(dip, NDI_RA_TYPE_MEM) == NDI_SUCCESS) {
991 991 return (NDI_FAILURE);
992 992 }
993 993 }
994 994
995 995
996 996 /*
997 997 * Create empty resource maps first.
998 998 *
999 999 * NOTE: If all the allocated resources are already assigned to
1000 1000 * device(s) in the hot plug slot then "available" property may not
1001 1001 * be present. But, subsequent hot plug operation may unconfigure
1002 1002 * the device in the slot and try to free up it's resources. So,
1003 1003 * at the minimum we should create empty maps here.
1004 1004 */
1005 1005 if (ndi_ra_map_setup(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) {
1006 1006 return (NDI_FAILURE);
1007 1007 }
1008 1008
1009 1009 if (ndi_ra_map_setup(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) {
1010 1010 return (NDI_FAILURE);
1011 1011 }
1012 1012
1013 1013 if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_BUSNUM) == NDI_FAILURE) {
1014 1014 return (NDI_FAILURE);
1015 1015 }
1016 1016
1017 1017 if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_PREFETCH_MEM) ==
1018 1018 NDI_FAILURE) {
1019 1019 return (NDI_FAILURE);
1020 1020 }
1021 1021
1022 1022 /* read the "available" property if it is available */
1023 1023 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1024 1024 "available", (caddr_t)®s, &rlen) == DDI_SUCCESS) {
1025 1025 /*
1026 1026 * Remove "available" property as the entries will be
1027 1027 * re-created in ndi_ra_free() below, note prom based
1028 1028 * property will not be removed. But in ndi_ra_free()
1029 1029 * we'll be creating non prom based property entries.
1030 1030 */
1031 1031 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "available");
1032 1032 /*
1033 1033 * create the available resource list for both memory and
1034 1034 * io space
1035 1035 */
1036 1036 rcount = rlen / sizeof (pci_regspec_t);
1037 1037 for (i = 0; i < rcount; i++) {
1038 1038 switch (PCI_REG_ADDR_G(regs[i].pci_phys_hi)) {
1039 1039 case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
1040 1040 (void) ndi_ra_free(dip,
1041 1041 (uint64_t)regs[i].pci_phys_low,
1042 1042 (uint64_t)regs[i].pci_size_low,
1043 1043 (regs[i].pci_phys_hi & PCI_REG_PF_M) ?
1044 1044 NDI_RA_TYPE_PCI_PREFETCH_MEM :
1045 1045 NDI_RA_TYPE_MEM,
1046 1046 0);
1047 1047 break;
1048 1048 case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
1049 1049 (void) ndi_ra_free(dip,
1050 1050 ((uint64_t)(regs[i].pci_phys_mid) << 32) |
1051 1051 ((uint64_t)(regs[i].pci_phys_low)),
1052 1052 ((uint64_t)(regs[i].pci_size_hi) << 32) |
1053 1053 ((uint64_t)(regs[i].pci_size_low)),
1054 1054 (regs[i].pci_phys_hi & PCI_REG_PF_M) ?
1055 1055 NDI_RA_TYPE_PCI_PREFETCH_MEM :
1056 1056 NDI_RA_TYPE_MEM,
1057 1057 0);
1058 1058 break;
1059 1059 case PCI_REG_ADDR_G(PCI_ADDR_IO):
1060 1060 (void) ndi_ra_free(dip,
1061 1061 (uint64_t)regs[i].pci_phys_low,
1062 1062 (uint64_t)regs[i].pci_size_low,
1063 1063 NDI_RA_TYPE_IO,
1064 1064 0);
1065 1065 break;
1066 1066 case PCI_REG_ADDR_G(PCI_ADDR_CONFIG):
1067 1067 break;
1068 1068 default:
1069 1069 cmn_err(CE_WARN,
1070 1070 "pci_resource_setup: bad addr type: %x\n",
1071 1071 PCI_REG_ADDR_G(regs[i].pci_phys_hi));
1072 1072 break;
1073 1073 }
1074 1074 }
1075 1075 kmem_free(regs, rlen);
1076 1076 }
1077 1077
1078 1078 /*
1079 1079 * update resource map for available bus numbers if the node
1080 1080 * has available-bus-range or bus-range property.
1081 1081 */
1082 1082 len = sizeof (struct bus_range);
1083 1083 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1084 1084 "available-bus-range", (caddr_t)&pci_bus_range, &len) ==
1085 1085 DDI_SUCCESS) {
1086 1086 /*
1087 1087 * Add bus numbers in the range to the free list.
1088 1088 */
1089 1089 (void) ndi_ra_free(dip, (uint64_t)pci_bus_range.lo,
1090 1090 (uint64_t)pci_bus_range.hi - (uint64_t)pci_bus_range.lo +
1091 1091 1, NDI_RA_TYPE_PCI_BUSNUM, 0);
1092 1092 } else {
1093 1093 /*
1094 1094 * We don't have an available-bus-range property. If, instead,
1095 1095 * we have a bus-range property we add all the bus numbers
1096 1096 * in that range to the free list but we must then scan
1097 1097 * for pci-pci bridges on this bus to find out the if there
1098 1098 * are any of those bus numbers already in use. If so, we can
1099 1099 * reclaim them.
1100 1100 */
1101 1101 len = sizeof (struct bus_range);
1102 1102 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
1103 1103 DDI_PROP_DONTPASS, "bus-range", (caddr_t)&pci_bus_range,
1104 1104 &len) == DDI_SUCCESS) {
1105 1105 if (pci_bus_range.lo != pci_bus_range.hi) {
1106 1106 /*
1107 1107 * Add bus numbers other than the secondary
1108 1108 * bus number to the free list.
1109 1109 */
1110 1110 (void) ndi_ra_free(dip,
1111 1111 (uint64_t)pci_bus_range.lo + 1,
1112 1112 (uint64_t)pci_bus_range.hi -
1113 1113 (uint64_t)pci_bus_range.lo,
1114 1114 NDI_RA_TYPE_PCI_BUSNUM, 0);
1115 1115
1116 1116 /* scan for pci-pci bridges */
1117 1117 ctrl.rv = DDI_SUCCESS;
1118 1118 ctrl.dip = dip;
1119 1119 ctrl.range = &pci_bus_range;
1120 1120 ndi_devi_enter(dip, &circular_count);
1121 1121 ddi_walk_devs(ddi_get_child(dip),
1122 1122 claim_pci_busnum, (void *)&ctrl);
1123 1123 ndi_devi_exit(dip, circular_count);
1124 1124 if (ctrl.rv != DDI_SUCCESS) {
1125 1125 /* failed to create the map */
1126 1126 (void) ndi_ra_map_destroy(dip,
1127 1127 NDI_RA_TYPE_PCI_BUSNUM);
1128 1128 rval = NDI_FAILURE;
1129 1129 }
1130 1130 }
1131 1131 }
1132 1132 }
1133 1133
1134 1134 #ifdef BUSRA_DEBUG
1135 1135 if (busra_debug) {
1136 1136 (void) ra_dump_all(NULL, dip);
1137 1137 }
1138 1138 #endif
1139 1139
1140 1140 return (rval);
1141 1141 }
1142 1142
1143 1143 /*
1144 1144 * If the device is a PCI bus device (i.e bus-range property exists) then
1145 1145 * claim the bus numbers used by the device from the specified bus
1146 1146 * resource map.
1147 1147 */
1148 1148 static int
1149 1149 claim_pci_busnum(dev_info_t *dip, void *arg)
1150 1150 {
1151 1151 struct bus_range pci_bus_range;
1152 1152 struct busnum_ctrl *ctrl;
1153 1153 ndi_ra_request_t req;
1154 1154 char bus_type[16] = "(unknown)";
1155 1155 int len;
1156 1156 uint64_t base;
1157 1157 uint64_t retlen;
1158 1158
1159 1159 ctrl = (struct busnum_ctrl *)arg;
1160 1160
1161 1161 /* check if this is a PCI bus node */
1162 1162 len = sizeof (bus_type);
1163 1163 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
1164 1164 DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "device_type",
1165 1165 (caddr_t)&bus_type, &len) != DDI_SUCCESS)
1166 1166 return (DDI_WALK_PRUNECHILD);
1167 1167
1168 1168 /* it is not a pci/pci-ex bus type */
1169 1169 if ((strcmp(bus_type, "pci") != 0) && (strcmp(bus_type, "pciex") != 0))
1170 1170 return (DDI_WALK_PRUNECHILD);
1171 1171
1172 1172 /* look for the bus-range property */
1173 1173 len = sizeof (struct bus_range);
1174 1174 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1175 1175 "bus-range", (caddr_t)&pci_bus_range, &len) == DDI_SUCCESS) {
1176 1176 if ((pci_bus_range.lo >= ctrl->range->lo) &&
1177 1177 (pci_bus_range.hi <= ctrl->range->hi)) {
1178 1178
1179 1179 /* claim the bus range from the bus resource map */
1180 1180 bzero((caddr_t)&req, sizeof (req));
1181 1181 req.ra_addr = (uint64_t)pci_bus_range.lo;
1182 1182 req.ra_flags |= NDI_RA_ALLOC_SPECIFIED;
1183 1183 req.ra_len = (uint64_t)pci_bus_range.hi -
1184 1184 (uint64_t)pci_bus_range.lo + 1;
1185 1185 if (ndi_ra_alloc(ctrl->dip, &req, &base, &retlen,
1186 1186 NDI_RA_TYPE_PCI_BUSNUM, 0) == NDI_SUCCESS)
1187 1187 return (DDI_WALK_PRUNECHILD);
1188 1188 }
1189 1189 }
1190 1190
1191 1191 /*
1192 1192 * Error return.
1193 1193 */
1194 1194 ctrl->rv = DDI_FAILURE;
1195 1195 return (DDI_WALK_TERMINATE);
1196 1196 }
1197 1197
1198 1198 void
1199 1199 pci_resource_destroy(dev_info_t *dip)
1200 1200 {
1201 1201 (void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_IO);
1202 1202
1203 1203 (void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_MEM);
1204 1204
1205 1205 (void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_PCI_BUSNUM);
1206 1206
1207 1207 (void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_PCI_PREFETCH_MEM);
1208 1208 }
1209 1209
1210 1210
1211 1211 int
1212 1212 pci_resource_setup_avail(dev_info_t *dip, pci_regspec_t *avail_p, int entries)
1213 1213 {
1214 1214 int i;
1215 1215
1216 1216 if (ndi_ra_map_setup(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE)
1217 1217 return (NDI_FAILURE);
1218 1218 if (ndi_ra_map_setup(dip, NDI_RA_TYPE_IO) == NDI_FAILURE)
1219 1219 return (NDI_FAILURE);
1220 1220 if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_PREFETCH_MEM) == NDI_FAILURE)
1221 1221 return (NDI_FAILURE);
1222 1222
1223 1223 /* for each entry in the PCI "available" property */
1224 1224 for (i = 0; i < entries; i++, avail_p++) {
1225 1225 if (avail_p->pci_phys_hi == -1u)
1226 1226 goto err;
1227 1227
1228 1228 switch (PCI_REG_ADDR_G(avail_p->pci_phys_hi)) {
1229 1229 case PCI_REG_ADDR_G(PCI_ADDR_MEM32): {
1230 1230 (void) ndi_ra_free(dip, (uint64_t)avail_p->pci_phys_low,
1231 1231 (uint64_t)avail_p->pci_size_low,
1232 1232 (avail_p->pci_phys_hi & PCI_REG_PF_M) ?
1233 1233 NDI_RA_TYPE_PCI_PREFETCH_MEM : NDI_RA_TYPE_MEM,
1234 1234 0);
1235 1235 }
1236 1236 break;
1237 1237 case PCI_REG_ADDR_G(PCI_ADDR_IO):
1238 1238 (void) ndi_ra_free(dip, (uint64_t)avail_p->pci_phys_low,
1239 1239 (uint64_t)avail_p->pci_size_low, NDI_RA_TYPE_IO, 0);
1240 1240 break;
1241 1241 default:
1242 1242 goto err;
1243 1243 }
1244 1244 }
1245 1245 #ifdef BUSRA_DEBUG
1246 1246 if (busra_debug) {
1247 1247 (void) ra_dump_all(NULL, dip);
1248 1248 }
1249 1249 #endif
1250 1250 return (NDI_SUCCESS);
1251 1251
1252 1252 err:
1253 1253 cmn_err(CE_WARN, "pci_resource_setup_avail: bad entry[%d]=%x\n",
1254 1254 i, avail_p->pci_phys_hi);
1255 1255 return (NDI_FAILURE);
1256 1256 }
1257 1257
1258 1258 /*
1259 1259 * Return true if the devinfo node resides on PCI or PCI Express bus,
1260 1260 * sitting in a PCI Express hierarchy.
1261 1261 */
1262 1262 static boolean_t
1263 1263 is_pcie_fabric(dev_info_t *dip)
1264 1264 {
1265 1265 dev_info_t *root = ddi_root_node();
1266 1266 dev_info_t *pdip;
1267 1267 boolean_t found = B_FALSE;
1268 1268 char *bus;
1269 1269
1270 1270 /*
1271 1271 * Is this pci/pcie ?
1272 1272 */
1273 1273 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
1274 1274 DDI_PROP_DONTPASS, "device_type", &bus) !=
1275 1275 DDI_PROP_SUCCESS) {
1276 1276 DEBUGPRT(CE_WARN, "is_pcie_fabric: cannot find "
1277 1277 "\"device_type\" property for dip %p\n", (void *)dip);
1278 1278 return (B_FALSE);
1279 1279 }
1280 1280
1281 1281 if (strcmp(bus, "pciex") == 0) {
1282 1282 /* pcie bus, done */
1283 1283 ddi_prop_free(bus);
1284 1284 return (B_TRUE);
1285 1285 } else if (strcmp(bus, "pci") == 0) {
1286 1286 /*
1287 1287 * pci bus, fall through to check if it resides in
1288 1288 * a pcie hierarchy.
1289 1289 */
1290 1290 ddi_prop_free(bus);
1291 1291 } else {
1292 1292 /* other bus, return failure */
1293 1293 ddi_prop_free(bus);
1294 1294 return (B_FALSE);
1295 1295 }
1296 1296
1297 1297 /*
1298 1298 * Does this device reside in a pcie fabric ?
1299 1299 */
1300 1300 for (pdip = ddi_get_parent(dip); pdip && (pdip != root) &&
1301 1301 !found; pdip = ddi_get_parent(pdip)) {
1302 1302 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
1303 1303 DDI_PROP_DONTPASS, "device_type", &bus) !=
1304 1304 DDI_PROP_SUCCESS)
1305 1305 break;
1306 1306
1307 1307 if (strcmp(bus, "pciex") == 0)
1308 1308 found = B_TRUE;
1309 1309
1310 1310 ddi_prop_free(bus);
1311 1311 }
1312 1312
1313 1313 return (found);
1314 1314 }
1315 1315
1316 1316 /*
1317 1317 * Remove a piece of IO/MEM resource from "available" property of 'dip'.
1318 1318 */
1319 1319 static int
1320 1320 pci_get_available_prop(dev_info_t *dip, uint64_t base, uint64_t len,
1321 1321 char *busra_type)
1322 1322 {
1323 1323 pci_regspec_t *regs, *newregs;
1324 1324 uint_t status;
1325 1325 int rlen, rcount;
1326 1326 int i, j, k;
1327 1327 uint64_t dlen;
1328 1328 boolean_t found = B_FALSE;
1329 1329 uint32_t type;
1330 1330
1331 1331 /* check if we're manipulating MEM/IO resource */
1332 1332 if ((type = pci_type_ra2pci(busra_type)) == PCI_ADDR_TYPE_INVAL)
1333 1333 return (DDI_SUCCESS);
1334 1334
1335 1335 /* check if dip is a pci/pcie device resides in a pcie fabric */
1336 1336 if (!is_pcie_fabric(dip))
1337 1337 return (DDI_SUCCESS);
1338 1338
1339 1339 status = ddi_getlongprop(DDI_DEV_T_ANY, dip,
1340 1340 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1341 1341 "available", (caddr_t)®s, &rlen);
1342 1342
1343 1343 ASSERT(status == DDI_SUCCESS);
1344 1344 if (status != DDI_SUCCESS)
1345 1345 return (status);
1346 1346
1347 1347 /*
1348 1348 * The updated "available" property will at most have one more entry
1349 1349 * than existing one (when the requested range is in the middle of
1350 1350 * the matched property entry)
1351 1351 */
1352 1352 newregs = kmem_alloc(rlen + sizeof (pci_regspec_t), KM_SLEEP);
1353 1353
1354 1354 rcount = rlen / sizeof (pci_regspec_t);
1355 1355 for (i = 0, j = 0; i < rcount; i++) {
1356 1356 if (type == (regs[i].pci_phys_hi & PCI_ADDR_TYPE_MASK)) {
1357 1357 uint64_t range_base, range_len;
1358 1358
1359 1359 range_base = ((uint64_t)(regs[i].pci_phys_mid) << 32) |
1360 1360 ((uint64_t)(regs[i].pci_phys_low));
1361 1361 range_len = ((uint64_t)(regs[i].pci_size_hi) << 32) |
1362 1362 ((uint64_t)(regs[i].pci_size_low));
1363 1363
1364 1364 if ((base < range_base) ||
1365 1365 (base + len > range_base + range_len)) {
1366 1366 /*
1367 1367 * not a match, copy the entry
1368 1368 */
1369 1369 goto copy_entry;
1370 1370 }
1371 1371
1372 1372 /*
1373 1373 * range_base base base+len range_base
1374 1374 * +range_len
1375 1375 * +------------+-----------+----------+
1376 1376 * | |///////////| |
1377 1377 * +------------+-----------+----------+
1378 1378 */
1379 1379 /*
1380 1380 * Found a match, remove the range out of this entry.
1381 1381 */
1382 1382 found = B_TRUE;
1383 1383
1384 1384 dlen = base - range_base;
1385 1385 if (dlen != 0) {
1386 1386 newregs[j].pci_phys_hi = regs[i].pci_phys_hi;
1387 1387 newregs[j].pci_phys_mid =
1388 1388 (uint32_t)(range_base >> 32);
1389 1389 newregs[j].pci_phys_low =
1390 1390 (uint32_t)(range_base);
1391 1391 newregs[j].pci_size_hi = (uint32_t)(dlen >> 32);
1392 1392 newregs[j].pci_size_low = (uint32_t)dlen;
1393 1393 j++;
1394 1394 }
1395 1395
1396 1396 dlen = (range_base + range_len) - (base + len);
1397 1397 if (dlen != 0) {
1398 1398 newregs[j].pci_phys_hi = regs[i].pci_phys_hi;
1399 1399 newregs[j].pci_phys_mid =
1400 1400 (uint32_t)((base + len)>> 32);
1401 1401 newregs[j].pci_phys_low =
1402 1402 (uint32_t)(base + len);
1403 1403 newregs[j].pci_size_hi = (uint32_t)(dlen >> 32);
1404 1404 newregs[j].pci_size_low = (uint32_t)dlen;
1405 1405 j++;
1406 1406 }
1407 1407
1408 1408 /*
1409 1409 * We've allocated the resource from the matched
1410 1410 * entry, almost finished but still need to copy
1411 1411 * the rest entries from the original property
1412 1412 * array.
1413 1413 */
1414 1414 for (k = i + 1; k < rcount; k++) {
1415 1415 newregs[j] = regs[k];
1416 1416 j++;
1417 1417 }
1418 1418
1419 1419 goto done;
1420 1420
1421 1421 } else {
1422 1422 copy_entry:
1423 1423 newregs[j] = regs[i];
1424 1424 j++;
1425 1425 }
1426 1426 }
1427 1427
1428 1428 done:
1429 1429 /*
1430 1430 * This should not fail so assert it. For non-debug kernel we don't
1431 1431 * want to panic thus only logging a warning message.
1432 1432 */
1433 1433 ASSERT(found == B_TRUE);
1434 1434 if (!found) {
1435 1435 cmn_err(CE_WARN, "pci_get_available_prop: failed to remove "
1436 1436 "resource from dip %p : base 0x%" PRIx64 ", len 0x%" PRIX64
1437 1437 ", type 0x%x\n", (void *)dip, base, len, type);
1438 1438 kmem_free(newregs, rlen + sizeof (pci_regspec_t));
1439 1439 kmem_free(regs, rlen);
1440 1440
1441 1441 return (DDI_FAILURE);
1442 1442 }
1443 1443
1444 1444 /*
1445 1445 * Found the resources from parent, update the "available"
1446 1446 * property.
1447 1447 */
1448 1448 if (j == 0) {
1449 1449 /* all the resources are consumed, remove the property */
1450 1450 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "available");
1451 1451 } else {
1452 1452 /*
1453 1453 * There are still resource available in the parent dip,
1454 1454 * update with the remaining resources.
1455 1455 */
1456 1456 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
1457 1457 "available", (int *)newregs,
1458 1458 (j * sizeof (pci_regspec_t)) / sizeof (int));
1459 1459 }
1460 1460
1461 1461 kmem_free(newregs, rlen + sizeof (pci_regspec_t));
1462 1462 kmem_free(regs, rlen);
1463 1463
1464 1464 return (DDI_SUCCESS);
1465 1465 }
1466 1466
1467 1467 /*
1468 1468 * Add a piece of IO/MEM resource to "available" property of 'dip'.
1469 1469 */
1470 1470 static int
1471 1471 pci_put_available_prop(dev_info_t *dip, uint64_t base, uint64_t len,
1472 1472 char *busra_type)
1473 1473 {
1474 1474 pci_regspec_t *regs, *newregs;
1475 1475 uint_t status;
1476 1476 int rlen, rcount;
1477 1477 int i, j, k;
1478 1478 int matched = 0;
1479 1479 uint64_t orig_base = base;
1480 1480 uint64_t orig_len = len;
1481 1481 uint32_t type;
1482 1482
1483 1483 /* check if we're manipulating MEM/IO resource */
1484 1484 if ((type = pci_type_ra2pci(busra_type)) == PCI_ADDR_TYPE_INVAL)
1485 1485 return (DDI_SUCCESS);
1486 1486
1487 1487 /* check if dip is a pci/pcie device resides in a pcie fabric */
1488 1488 if (!is_pcie_fabric(dip))
1489 1489 return (DDI_SUCCESS);
1490 1490
1491 1491 status = ddi_getlongprop(DDI_DEV_T_ANY, dip,
1492 1492 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1493 1493 "available", (caddr_t)®s, &rlen);
1494 1494
1495 1495 switch (status) {
1496 1496 case DDI_PROP_NOT_FOUND:
1497 1497 goto not_found;
1498 1498
1499 1499 case DDI_PROP_SUCCESS:
1500 1500 break;
1501 1501
1502 1502 default:
1503 1503 return (status);
1504 1504 }
1505 1505
1506 1506 /*
1507 1507 * The "available" property exist on the node, try to put this
1508 1508 * resource back, merge if there are adjacent resources.
1509 1509 *
1510 1510 * The updated "available" property will at most have one more entry
1511 1511 * than existing one (when there is no adjacent entries thus the new
1512 1512 * resource is appended at the end)
1513 1513 */
1514 1514 newregs = kmem_alloc(rlen + sizeof (pci_regspec_t), KM_SLEEP);
1515 1515
1516 1516 rcount = rlen / sizeof (pci_regspec_t);
1517 1517 for (i = 0, j = 0; i < rcount; i++) {
1518 1518 if (type == (regs[i].pci_phys_hi & PCI_ADDR_TYPE_MASK)) {
1519 1519 uint64_t range_base, range_len;
1520 1520
1521 1521 range_base = ((uint64_t)(regs[i].pci_phys_mid) << 32) |
1522 1522 ((uint64_t)(regs[i].pci_phys_low));
1523 1523 range_len = ((uint64_t)(regs[i].pci_size_hi) << 32) |
1524 1524 ((uint64_t)(regs[i].pci_size_low));
1525 1525
1526 1526 if ((base + len < range_base) ||
1527 1527 (base > range_base + range_len)) {
1528 1528 /*
1529 1529 * Not adjacent, copy the entry and contiue
1530 1530 */
1531 1531 goto copy_entry;
1532 1532 }
1533 1533
1534 1534 /*
1535 1535 * Adjacent or overlap?
1536 1536 *
1537 1537 * Should not have overlapping resources so assert it.
1538 1538 * For non-debug kernel we don't want to panic thus
1539 1539 * only logging a warning message.
1540 1540 */
1541 1541 #if 0
1542 1542 ASSERT((base + len == range_base) ||
1543 1543 (base == range_base + range_len));
1544 1544 #endif
1545 1545 if ((base + len != range_base) &&
1546 1546 (base != range_base + range_len)) {
1547 1547 cmn_err(CE_WARN, "pci_put_available_prop: "
1548 1548 "failed to add resource to dip %p : "
1549 1549 "base 0x%" PRIx64 ", len 0x%" PRIx64 " "
1550 1550 "overlaps with existing resource "
1551 1551 "base 0x%" PRIx64 ", len 0x%" PRIx64 "\n",
1552 1552 (void *)dip, orig_base, orig_len,
1553 1553 range_base, range_len);
1554 1554
1555 1555 goto failure;
1556 1556 }
1557 1557
1558 1558 /*
1559 1559 * On the left:
1560 1560 *
1561 1561 * base range_base
1562 1562 * +-------------+-------------+
1563 1563 * |/////////////| |
1564 1564 * +-------------+-------------+
1565 1565 * len range_len
1566 1566 *
1567 1567 * On the right:
1568 1568 *
1569 1569 * range_base base
1570 1570 * +-------------+-------------+
1571 1571 * | |/////////////|
1572 1572 * +-------------+-------------+
1573 1573 * range_len len
1574 1574 */
1575 1575 /*
1576 1576 * There are at most two piece of resources adjacent
1577 1577 * with this resource, assert it.
1578 1578 */
1579 1579 ASSERT(matched < 2);
1580 1580
1581 1581 if (!(matched < 2)) {
1582 1582 cmn_err(CE_WARN, "pci_put_available_prop: "
1583 1583 "failed to add resource to dip %p : "
1584 1584 "base 0x%" PRIx64 ", len 0x%" PRIx64 " "
1585 1585 "found overlaps in existing resources\n",
1586 1586 (void *)dip, orig_base, orig_len);
1587 1587
1588 1588 goto failure;
1589 1589 }
1590 1590
1591 1591 /* setup base & len to refer to the merged range */
1592 1592 len += range_len;
1593 1593 if (base == range_base + range_len)
1594 1594 base = range_base;
1595 1595
1596 1596 if (matched == 0) {
1597 1597 /*
1598 1598 * One adjacent entry, add this resource in
1599 1599 */
1600 1600 newregs[j].pci_phys_hi = regs[i].pci_phys_hi;
1601 1601 newregs[j].pci_phys_mid =
1602 1602 (uint32_t)(base >> 32);
1603 1603 newregs[j].pci_phys_low = (uint32_t)(base);
1604 1604 newregs[j].pci_size_hi = (uint32_t)(len >> 32);
1605 1605 newregs[j].pci_size_low = (uint32_t)len;
1606 1606
1607 1607 matched = 1;
1608 1608 k = j;
1609 1609 j++;
1610 1610 } else { /* matched == 1 */
1611 1611 /*
1612 1612 * Two adjacent entries, merge them together
1613 1613 */
1614 1614 newregs[k].pci_phys_hi = regs[i].pci_phys_hi;
1615 1615 newregs[k].pci_phys_mid =
1616 1616 (uint32_t)(base >> 32);
1617 1617 newregs[k].pci_phys_low = (uint32_t)(base);
1618 1618 newregs[k].pci_size_hi = (uint32_t)(len >> 32);
1619 1619 newregs[k].pci_size_low = (uint32_t)len;
1620 1620
1621 1621 matched = 2;
1622 1622 }
1623 1623 } else {
1624 1624 copy_entry:
1625 1625 newregs[j] = regs[i];
1626 1626 j++;
1627 1627 }
1628 1628 }
1629 1629
1630 1630 if (matched == 0) {
1631 1631 /* No adjacent entries, append at end */
1632 1632 ASSERT(j == rcount);
1633 1633
1634 1634 /*
1635 1635 * According to page 15 of 1275 spec, bit "n" of "available"
1636 1636 * should be set to 1.
1637 1637 */
1638 1638 newregs[j].pci_phys_hi = type;
1639 1639 newregs[j].pci_phys_hi |= PCI_REG_REL_M;
1640 1640
1641 1641 newregs[j].pci_phys_mid = (uint32_t)(base >> 32);
1642 1642 newregs[j].pci_phys_low = (uint32_t)base;
1643 1643 newregs[j].pci_size_hi = (uint32_t)(len >> 32);
1644 1644 newregs[j].pci_size_low = (uint32_t)len;
1645 1645
1646 1646 j++;
1647 1647 }
1648 1648
1649 1649 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
1650 1650 "available", (int *)newregs,
1651 1651 (j * sizeof (pci_regspec_t)) / sizeof (int));
1652 1652
1653 1653 kmem_free(newregs, rlen + sizeof (pci_regspec_t));
1654 1654 kmem_free(regs, rlen);
1655 1655 return (DDI_SUCCESS);
1656 1656
1657 1657 not_found:
1658 1658 /*
1659 1659 * There is no "available" property on the parent node, create it.
1660 1660 */
1661 1661 newregs = kmem_alloc(sizeof (pci_regspec_t), KM_SLEEP);
1662 1662
1663 1663 /*
1664 1664 * According to page 15 of 1275 spec, bit "n" of "available" should
1665 1665 * be set to 1.
1666 1666 */
1667 1667 newregs[0].pci_phys_hi = type;
1668 1668 newregs[0].pci_phys_hi |= PCI_REG_REL_M;
1669 1669
1670 1670 newregs[0].pci_phys_mid = (uint32_t)(base >> 32);
1671 1671 newregs[0].pci_phys_low = (uint32_t)base;
1672 1672 newregs[0].pci_size_hi = (uint32_t)(len >> 32);
1673 1673 newregs[0].pci_size_low = (uint32_t)len;
1674 1674
1675 1675 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
1676 1676 "available", (int *)newregs,
1677 1677 sizeof (pci_regspec_t) / sizeof (int));
1678 1678 kmem_free(newregs, sizeof (pci_regspec_t));
1679 1679 return (DDI_SUCCESS);
1680 1680
1681 1681 failure:
1682 1682 kmem_free(newregs, rlen + sizeof (pci_regspec_t));
1683 1683 kmem_free(regs, rlen);
1684 1684 return (DDI_FAILURE);
1685 1685 }
1686 1686
1687 1687 static uint32_t
1688 1688 pci_type_ra2pci(char *type)
1689 1689 {
1690 1690 uint32_t pci_type = PCI_ADDR_TYPE_INVAL;
1691 1691
1692 1692 /*
1693 1693 * No 64 bit mem support for now
1694 1694 */
1695 1695 if (strcmp(type, NDI_RA_TYPE_IO) == 0) {
1696 1696 pci_type = PCI_ADDR_IO;
1697 1697
1698 1698 } else if (strcmp(type, NDI_RA_TYPE_MEM) == 0) {
1699 1699 pci_type = PCI_ADDR_MEM32;
1700 1700
1701 1701 } else if (strcmp(type, NDI_RA_TYPE_PCI_PREFETCH_MEM) == 0) {
1702 1702 pci_type = PCI_ADDR_MEM32;
1703 1703 pci_type |= PCI_REG_PF_M;
1704 1704 }
1705 1705
1706 1706 return (pci_type);
1707 1707 }
↓ open down ↓ |
1542 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX