Print this page
const-ify make segment ops structures
There is no reason to keep the segment ops structures writable.
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/sun4/io/rootnex.c
+++ new/usr/src/uts/sun4/io/rootnex.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 /*
23 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27
28 28 /*
29 29 * sun4 root nexus driver
30 30 */
31 31
32 32 #include <sys/conf.h>
33 33 #include <sys/modctl.h>
34 34 #include <sys/ddi_subrdefs.h>
35 35 #include <sys/sunndi.h>
36 36 #include <sys/vmsystm.h>
37 37 #include <sys/async.h>
38 38 #include <sys/intr.h>
39 39 #include <sys/ndifm.h>
40 40 #include <vm/seg_dev.h>
41 41 #include <vm/seg_kmem.h>
42 42 #include <sys/ontrap.h>
43 43
44 44 /* Useful debugging Stuff */
45 45 #include <sys/nexusdebug.h>
46 46 #define ROOTNEX_MAP_DEBUG 0x1
47 47 #define ROOTNEX_INTR_DEBUG 0x2
48 48
49 49 /*
50 50 * config information
51 51 */
52 52
53 53 static int
54 54 rootnex_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
55 55 off_t offset, off_t len, caddr_t *vaddrp);
56 56
57 57 static int
58 58 rootnex_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t,
59 59 ddi_intr_handle_impl_t *, void *);
60 60
61 61 static int
62 62 rootnex_map_fault(dev_info_t *dip, dev_info_t *rdip,
63 63 struct hat *hat, struct seg *seg, caddr_t addr,
64 64 struct devpage *dp, pfn_t pfn, uint_t prot, uint_t lock);
65 65
66 66 static int
67 67 rootnex_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *);
68 68
69 69 static int
70 70 rootnex_busop_fminit(dev_info_t *dip, dev_info_t *tdip, int tcap,
71 71 ddi_iblock_cookie_t *ibc);
72 72
73 73 static void
74 74 rootnex_fm_init(dev_info_t *);
75 75
76 76 static int
77 77 rootnex_ctlops_peekpoke(ddi_ctl_enum_t, peekpoke_ctlops_t *, void *result);
78 78
79 79 /*
80 80 * Defined in $KARCH/io/mach_rootnex.c
81 81 */
82 82 int rootnex_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
83 83 ddi_intr_handle_impl_t *hdlp);
84 84 #pragma weak rootnex_add_intr_impl
85 85
86 86 int rootnex_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
87 87 ddi_intr_handle_impl_t *hdlp);
88 88 #pragma weak rootnex_remove_intr_impl
89 89
90 90 int rootnex_get_intr_pri(dev_info_t *dip, dev_info_t *rdip,
91 91 ddi_intr_handle_impl_t *hdlp);
92 92 #pragma weak rootnex_get_intr_pri
93 93
94 94 int rootnex_name_child_impl(dev_info_t *child, char *name, int namelen);
95 95 #pragma weak rootnex_name_child_impl
96 96
97 97 int rootnex_ctl_initchild_impl(dev_info_t *dip);
98 98 #pragma weak rootnex_initchild_impl
99 99
100 100 void rootnex_ctl_uninitchild_impl(dev_info_t *dip);
101 101 #pragma weak rootnex_uninitchild_impl
102 102
103 103 int rootnex_ctl_reportdev_impl(dev_info_t *dev);
104 104 #pragma weak rootnex_reportdev_impl
105 105
106 106 static struct cb_ops rootnex_cb_ops = {
107 107 nodev, /* open */
108 108 nodev, /* close */
109 109 nodev, /* strategy */
110 110 nodev, /* print */
111 111 nodev, /* dump */
112 112 nodev, /* read */
113 113 nodev, /* write */
114 114 nodev, /* ioctl */
115 115 nodev, /* devmap */
116 116 nodev, /* mmap */
117 117 nodev, /* segmap */
118 118 nochpoll, /* chpoll */
119 119 ddi_prop_op, /* cb_prop_op */
120 120 NULL, /* struct streamtab */
121 121 D_NEW | D_MP | D_HOTPLUG, /* compatibility flags */
122 122 CB_REV, /* Rev */
123 123 nodev, /* cb_aread */
124 124 nodev /* cb_awrite */
125 125 };
126 126
127 127 static struct bus_ops rootnex_bus_ops = {
128 128 BUSO_REV,
129 129 rootnex_map,
130 130 NULL,
131 131 NULL,
132 132 NULL,
133 133 rootnex_map_fault,
134 134 ddi_no_dma_map, /* no rootnex_dma_map- now in sysio nexus */
135 135 ddi_no_dma_allochdl,
136 136 ddi_no_dma_freehdl,
137 137 ddi_no_dma_bindhdl,
138 138 ddi_no_dma_unbindhdl,
139 139 ddi_no_dma_flush,
140 140 ddi_no_dma_win,
141 141 ddi_no_dma_mctl, /* no rootnex_dma_mctl- now in sysio nexus */
142 142 rootnex_ctlops,
143 143 ddi_bus_prop_op,
144 144 i_ddi_rootnex_get_eventcookie,
145 145 i_ddi_rootnex_add_eventcall,
146 146 i_ddi_rootnex_remove_eventcall,
147 147 i_ddi_rootnex_post_event,
148 148 NULL, /* bus_intr_ctl */
149 149 NULL, /* bus_config */
150 150 NULL, /* bus_unconfig */
151 151 rootnex_busop_fminit, /* bus_fm_init */
152 152 NULL, /* bus_fm_fini */
153 153 NULL, /* bus_fm_access_enter */
154 154 NULL, /* bus_fm_access_fini */
155 155 NULL, /* bus_power */
156 156 rootnex_intr_ops /* bus_intr_op */
157 157 };
158 158
159 159 static int rootnex_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
160 160 static int rootnex_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
161 161
162 162 static struct dev_ops rootnex_ops = {
163 163 DEVO_REV,
164 164 0, /* refcnt */
165 165 ddi_no_info, /* info */
166 166 nulldev,
167 167 nulldev, /* probe */
168 168 rootnex_attach,
169 169 rootnex_detach,
170 170 nodev, /* reset */
171 171 &rootnex_cb_ops,
172 172 &rootnex_bus_ops,
173 173 NULL, /* power */
174 174 ddi_quiesce_not_needed, /* quiesce */
175 175 };
176 176
177 177
178 178 extern uint_t root_phys_addr_lo_mask;
179 179 extern uint_t root_phys_addr_hi_mask;
180 180 extern struct mod_ops mod_driverops;
181 181 extern struct dev_ops rootnex_ops;
182 182 extern struct cpu cpu0;
183 183 extern ddi_iblock_cookie_t rootnex_err_ibc;
184 184
185 185
186 186 /*
187 187 * Add statically defined root properties to this list...
188 188 */
189 189 static const int pagesize = PAGESIZE;
190 190 static const int mmu_pagesize = MMU_PAGESIZE;
191 191 static const int mmu_pageoffset = MMU_PAGEOFFSET;
192 192
193 193 struct prop_def {
194 194 char *prop_name;
195 195 caddr_t prop_value;
196 196 };
197 197
198 198 static struct prop_def root_props[] = {
199 199 { "PAGESIZE", (caddr_t)&pagesize },
200 200 { "MMU_PAGESIZE", (caddr_t)&mmu_pagesize},
201 201 { "MMU_PAGEOFFSET", (caddr_t)&mmu_pageoffset},
202 202 };
203 203
204 204 static vmem_t *rootnex_regspec_arena;
205 205
206 206 #define NROOT_PROPS (sizeof (root_props) / sizeof (struct prop_def))
207 207
208 208
209 209
210 210 /*
211 211 * Module linkage information for the kernel.
212 212 */
213 213
214 214 static struct modldrv modldrv = {
215 215 &mod_driverops, /* Type of module. This one is a nexus driver */
216 216 "sun4 root nexus",
217 217 &rootnex_ops, /* Driver ops */
218 218 };
219 219
220 220 static struct modlinkage modlinkage = {
221 221 MODREV_1, (void *)&modldrv, NULL
222 222 };
223 223
224 224 int
225 225 _init(void)
226 226 {
227 227 return (mod_install(&modlinkage));
228 228 }
229 229
230 230 int
231 231 _fini(void)
232 232 {
233 233 return (EBUSY);
234 234 }
235 235
236 236 int
237 237 _info(struct modinfo *modinfop)
238 238 {
239 239 return (mod_info(&modlinkage, modinfop));
240 240 }
241 241
242 242 /*
243 243 * rootnex_attach:
244 244 *
245 245 * attach the root nexus.
246 246 */
247 247 static void add_root_props(dev_info_t *);
248 248
249 249 /*ARGSUSED*/
250 250 static int
251 251 rootnex_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
252 252 {
253 253 int length;
254 254 char *valuep = NULL;
255 255
256 256 /*
257 257 * Only do these functions when the driver is acting as the
258 258 * root nexus, not when it is driving a memory controller.
259 259 */
260 260 if (ddi_root_node() == devi) {
261 261 rootnex_fm_init(devi);
262 262 add_root_props(devi);
263 263 i_ddi_rootnex_init_events(devi);
264 264 rootnex_regspec_arena = vmem_create("regspec",
265 265 (void *)PIOMAPBASE, PIOMAPSIZE, MMU_PAGESIZE, NULL, NULL,
266 266 NULL, 0, VM_SLEEP);
267 267 }
268 268
269 269 if (ddi_prop_op(DDI_DEV_T_ANY, devi, PROP_LEN_AND_VAL_ALLOC,
270 270 DDI_PROP_DONTPASS, "banner-name", (caddr_t)&valuep,
271 271 &length) == DDI_PROP_SUCCESS) {
272 272 cmn_err(CE_CONT, "?root nexus = %s\n", valuep);
273 273 kmem_free(valuep, length);
274 274 }
275 275 /*
276 276 * Add a no-suspend-resume property so that NDI
277 277 * does not attempt to suspend/resume the rootnex
278 278 * (or any of its aliases) node.
279 279 */
280 280 (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
281 281 "pm-hardware-state", "no-suspend-resume");
282 282
283 283 return (DDI_SUCCESS);
284 284 }
285 285
286 286 /*ARGSUSED*/
287 287 static int
288 288 rootnex_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
289 289 {
290 290 return (DDI_SUCCESS);
291 291 }
292 292
293 293 static void
294 294 add_root_props(dev_info_t *devi)
295 295 {
296 296 int i;
297 297 struct prop_def *rpp;
298 298
299 299 /*
300 300 * Note that this for loop works because all of the
301 301 * properties in root_prop are integers
302 302 */
303 303 for (i = 0, rpp = root_props; i < NROOT_PROPS; ++i, ++rpp) {
304 304 (void) e_ddi_prop_update_int(DDI_DEV_T_NONE, devi,
305 305 rpp->prop_name, *((int *)rpp->prop_value));
306 306 }
307 307
308 308 /*
309 309 * Create the root node "boolean" property
310 310 * corresponding to addressing type supported in the root node:
311 311 *
312 312 * Choices are:
313 313 * "relative-addressing" (OBP PROMS)
314 314 * "generic-addressing" (SunMon -- pseudo OBP/DDI)
315 315 */
316 316
317 317 (void) e_ddi_prop_update_int(DDI_DEV_T_NONE, devi,
318 318 DDI_RELATIVE_ADDRESSING, 1);
319 319
320 320 /*
321 321 * Create fault management capability property
322 322 */
323 323 (void) e_ddi_prop_update_int(DDI_DEV_T_NONE, devi, "fm-capable",
324 324 ddi_fm_capable(devi));
325 325 }
326 326
327 327 static int
328 328 rootnex_map_regspec(ddi_map_req_t *mp, caddr_t *vaddrp, uint_t mapping_attr)
329 329 {
330 330 uint64_t base;
331 331 caddr_t kaddr;
332 332 pgcnt_t npages;
333 333 pfn_t pfn;
334 334 uint_t pgoffset;
335 335 struct regspec *rp = mp->map_obj.rp;
336 336 ddi_acc_hdl_t *hp;
337 337
338 338 base = (uint64_t)rp->regspec_addr & (~MMU_PAGEOFFSET); /* base addr */
339 339
340 340 /*
341 341 * Take the bustype and addr and convert it to a
342 342 * page frame number.
343 343 */
344 344 pfn = mmu_btop(((uint64_t)(rp->regspec_bustype &
345 345 root_phys_addr_hi_mask) << 32) | base);
346 346
347 347 /*
348 348 * Do a quick sanity check to make sure we are in I/O space.
349 349 */
350 350 if (pf_is_memory(pfn))
351 351 return (DDI_ME_INVAL);
352 352
353 353 if (rp->regspec_size == 0) {
354 354 DPRINTF(ROOTNEX_MAP_DEBUG, ("rootnex_map_regspec: zero "
355 355 "regspec_size\n"));
356 356 return (DDI_ME_INVAL);
357 357 }
358 358
359 359 if (mp->map_flags & DDI_MF_DEVICE_MAPPING)
360 360 *vaddrp = (caddr_t)pfn;
361 361 else {
362 362 pgoffset = (ulong_t)rp->regspec_addr & MMU_PAGEOFFSET;
363 363 npages = mmu_btopr(rp->regspec_size + pgoffset);
364 364
365 365 DPRINTF(ROOTNEX_MAP_DEBUG, ("rootnex_map_regspec: Mapping "
366 366 "%lu pages physical %x.%lx ", npages, rp->regspec_bustype,
367 367 base));
368 368
369 369 if ((kaddr = vmem_alloc(rootnex_regspec_arena,
370 370 ptob(npages), VM_NOSLEEP)) == NULL)
371 371 return (DDI_ME_NORESOURCES);
372 372
373 373 /*
374 374 * Now map in the pages we've allocated...
375 375 */
376 376 hat_devload(kas.a_hat, kaddr, ptob(npages), pfn,
377 377 mp->map_prot | mapping_attr, HAT_LOAD_LOCK);
378 378
379 379 *vaddrp = kaddr + pgoffset;
380 380
381 381 hp = mp->map_handlep;
382 382 if (hp) {
383 383 hp->ah_pfn = pfn;
384 384 hp->ah_pnum = npages;
385 385 }
386 386 }
387 387
388 388 DPRINTF(ROOTNEX_MAP_DEBUG, ("at virtual 0x%p\n", (void *)*vaddrp));
389 389 return (0);
390 390 }
391 391
392 392 static int
393 393 rootnex_unmap_regspec(ddi_map_req_t *mp, caddr_t *vaddrp)
394 394 {
395 395 caddr_t addr = *vaddrp;
396 396 pgcnt_t npages;
397 397 uint_t pgoffset;
398 398 caddr_t base;
399 399 struct regspec *rp;
400 400
401 401 if (mp->map_flags & DDI_MF_DEVICE_MAPPING)
402 402 return (0);
403 403
404 404 rp = mp->map_obj.rp;
405 405 pgoffset = (uintptr_t)addr & MMU_PAGEOFFSET;
406 406
407 407 if (rp->regspec_size == 0) {
408 408 DPRINTF(ROOTNEX_MAP_DEBUG, ("rootnex_unmap_regspec: "
409 409 "zero regspec_size\n"));
410 410 return (DDI_ME_INVAL);
411 411 }
412 412
413 413 base = addr - pgoffset;
414 414 npages = mmu_btopr(rp->regspec_size + pgoffset);
415 415 hat_unload(kas.a_hat, base, ptob(npages), HAT_UNLOAD_UNLOCK);
416 416 vmem_free(rootnex_regspec_arena, base, ptob(npages));
417 417
418 418 /*
419 419 * Destroy the pointer - the mapping has logically gone
420 420 */
421 421 *vaddrp = (caddr_t)0;
422 422
423 423 return (0);
424 424 }
425 425
426 426 static int
427 427 rootnex_map_handle(ddi_map_req_t *mp)
428 428 {
429 429 ddi_acc_hdl_t *hp;
430 430 uint_t hat_flags;
431 431 register struct regspec *rp;
432 432
433 433 /*
434 434 * Set up the hat_flags for the mapping.
435 435 */
436 436 hp = mp->map_handlep;
437 437
438 438 switch (hp->ah_acc.devacc_attr_endian_flags) {
439 439 case DDI_NEVERSWAP_ACC:
440 440 hat_flags = HAT_NEVERSWAP | HAT_STRICTORDER;
441 441 break;
442 442 case DDI_STRUCTURE_BE_ACC:
443 443 hat_flags = HAT_STRUCTURE_BE;
444 444 break;
445 445 case DDI_STRUCTURE_LE_ACC:
446 446 hat_flags = HAT_STRUCTURE_LE;
447 447 break;
448 448 default:
449 449 return (DDI_REGS_ACC_CONFLICT);
450 450 }
451 451
452 452 switch (hp->ah_acc.devacc_attr_dataorder) {
453 453 case DDI_STRICTORDER_ACC:
454 454 break;
455 455 case DDI_UNORDERED_OK_ACC:
456 456 hat_flags |= HAT_UNORDERED_OK;
457 457 break;
458 458 case DDI_MERGING_OK_ACC:
459 459 hat_flags |= HAT_MERGING_OK;
460 460 break;
461 461 case DDI_LOADCACHING_OK_ACC:
462 462 hat_flags |= HAT_LOADCACHING_OK;
463 463 break;
464 464 case DDI_STORECACHING_OK_ACC:
465 465 hat_flags |= HAT_STORECACHING_OK;
466 466 break;
467 467 default:
468 468 return (DDI_FAILURE);
469 469 }
470 470
471 471 rp = mp->map_obj.rp;
472 472 if (rp->regspec_size == 0)
473 473 return (DDI_ME_INVAL);
474 474
475 475 hp->ah_hat_flags = hat_flags;
476 476 hp->ah_pfn = mmu_btop((ulong_t)rp->regspec_addr & (~MMU_PAGEOFFSET));
477 477 hp->ah_pnum = mmu_btopr(rp->regspec_size +
478 478 (ulong_t)rp->regspec_addr & MMU_PAGEOFFSET);
479 479 return (DDI_SUCCESS);
480 480 }
481 481
482 482 static int
483 483 rootnex_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
484 484 off_t offset, off_t len, caddr_t *vaddrp)
485 485 {
486 486 struct regspec *rp, tmp_reg;
487 487 ddi_map_req_t mr = *mp; /* Get private copy of request */
488 488 int error;
489 489 uint_t mapping_attr;
490 490 ddi_acc_hdl_t *hp = NULL;
491 491
492 492 mp = &mr;
493 493
494 494 switch (mp->map_op) {
495 495 case DDI_MO_MAP_LOCKED:
496 496 case DDI_MO_UNMAP:
497 497 case DDI_MO_MAP_HANDLE:
498 498 break;
499 499 default:
500 500 DPRINTF(ROOTNEX_MAP_DEBUG, ("rootnex_map: unimplemented map "
501 501 "op %d.", mp->map_op));
502 502 return (DDI_ME_UNIMPLEMENTED);
503 503 }
504 504
505 505 if (mp->map_flags & DDI_MF_USER_MAPPING) {
506 506 DPRINTF(ROOTNEX_MAP_DEBUG, ("rootnex_map: unimplemented map "
507 507 "type: user."));
508 508 return (DDI_ME_UNIMPLEMENTED);
509 509 }
510 510
511 511 /*
512 512 * First, if given an rnumber, convert it to a regspec...
513 513 * (Presumably, this is on behalf of a child of the root node?)
514 514 */
515 515
516 516 if (mp->map_type == DDI_MT_RNUMBER) {
517 517
518 518 int rnumber = mp->map_obj.rnumber;
519 519
520 520 rp = i_ddi_rnumber_to_regspec(rdip, rnumber);
521 521 if (rp == (struct regspec *)0) {
522 522 DPRINTF(ROOTNEX_MAP_DEBUG, ("rootnex_map: Out of "
523 523 "range rnumber <%d>, device <%s>", rnumber,
524 524 ddi_get_name(rdip)));
525 525 return (DDI_ME_RNUMBER_RANGE);
526 526 }
527 527
528 528 /*
529 529 * Convert the given ddi_map_req_t from rnumber to regspec...
530 530 */
531 531
532 532 mp->map_type = DDI_MT_REGSPEC;
533 533 mp->map_obj.rp = rp;
534 534 }
535 535
536 536 /*
537 537 * Adjust offset and length corresponding to called values...
538 538 * XXX: A non-zero length means override the one in the regspec
539 539 * XXX: regardless of what's in the parent's range?.
540 540 */
541 541
542 542 tmp_reg = *(mp->map_obj.rp); /* Preserve underlying data */
543 543 rp = mp->map_obj.rp = &tmp_reg; /* Use tmp_reg in request */
544 544
545 545 rp->regspec_addr += (uint_t)offset;
546 546 if (len != 0)
547 547 rp->regspec_size = (uint_t)len;
548 548
549 549 /*
550 550 * Apply any parent ranges at this level, if applicable.
551 551 * (This is where nexus specific regspec translation takes place.
552 552 * Use of this function is implicit agreement that translation is
553 553 * provided via ddi_apply_range.)
554 554 */
555 555
556 556 DPRINTF(ROOTNEX_MAP_DEBUG, ("rootnex_map: applying range of parent "
557 557 "<%s> to child <%s>...\n", ddi_get_name(dip), ddi_get_name(rdip)));
558 558
559 559 if ((error = i_ddi_apply_range(dip, rdip, mp->map_obj.rp)) != 0)
560 560 return (error);
561 561
562 562 switch (mp->map_op) {
563 563 case DDI_MO_MAP_LOCKED:
564 564
565 565 /*
566 566 * Set up the locked down kernel mapping to the regspec...
567 567 */
568 568
569 569 /*
570 570 * If we were passed an access handle we need to determine
571 571 * the "endian-ness" of the mapping and fill in the handle.
572 572 */
573 573 if (mp->map_handlep) {
574 574 hp = mp->map_handlep;
575 575 switch (hp->ah_acc.devacc_attr_endian_flags) {
576 576 case DDI_NEVERSWAP_ACC:
577 577 mapping_attr = HAT_NEVERSWAP | HAT_STRICTORDER;
578 578 break;
579 579 case DDI_STRUCTURE_BE_ACC:
580 580 mapping_attr = HAT_STRUCTURE_BE;
581 581 break;
582 582 case DDI_STRUCTURE_LE_ACC:
583 583 mapping_attr = HAT_STRUCTURE_LE;
584 584 break;
585 585 default:
586 586 return (DDI_REGS_ACC_CONFLICT);
587 587 }
588 588
589 589 switch (hp->ah_acc.devacc_attr_dataorder) {
590 590 case DDI_STRICTORDER_ACC:
591 591 break;
592 592 case DDI_UNORDERED_OK_ACC:
593 593 mapping_attr |= HAT_UNORDERED_OK;
594 594 break;
595 595 case DDI_MERGING_OK_ACC:
596 596 mapping_attr |= HAT_MERGING_OK;
597 597 break;
598 598 case DDI_LOADCACHING_OK_ACC:
599 599 mapping_attr |= HAT_LOADCACHING_OK;
600 600 break;
601 601 case DDI_STORECACHING_OK_ACC:
602 602 mapping_attr |= HAT_STORECACHING_OK;
603 603 break;
604 604 default:
605 605 return (DDI_REGS_ACC_CONFLICT);
606 606 }
607 607 } else {
608 608 mapping_attr = HAT_NEVERSWAP | HAT_STRICTORDER;
609 609 }
610 610
611 611 /*
612 612 * Set up the mapping.
613 613 */
614 614 error = rootnex_map_regspec(mp, vaddrp, mapping_attr);
615 615
616 616 /*
617 617 * Fill in the access handle if needed.
618 618 */
619 619 if (hp) {
620 620 hp->ah_addr = *vaddrp;
621 621 hp->ah_hat_flags = mapping_attr;
622 622 if (error == 0)
623 623 impl_acc_hdl_init(hp);
624 624 }
625 625 return (error);
626 626
627 627 case DDI_MO_UNMAP:
628 628
629 629 /*
630 630 * Release mapping...
631 631 */
632 632
633 633 return (rootnex_unmap_regspec(mp, vaddrp));
634 634
635 635 case DDI_MO_MAP_HANDLE:
636 636 return (rootnex_map_handle(mp));
637 637
638 638 }
639 639
640 640 return (DDI_ME_UNIMPLEMENTED);
641 641 }
642 642
643 643 static int
644 644 rootnex_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
645 645 ddi_intr_handle_impl_t *hdlp, void *result)
646 646 {
647 647 int ret = DDI_SUCCESS;
648 648
649 649 DPRINTF(ROOTNEX_INTR_DEBUG, ("rootnex_intr_ops: rdip=%s%d "
650 650 "intr_op 0x%x hdlp 0x%p\n", ddi_driver_name(rdip),
651 651 ddi_get_instance(rdip), intr_op, (void *)hdlp));
652 652
653 653 switch (intr_op) {
654 654 case DDI_INTROP_GETCAP:
655 655 *(int *)result = DDI_INTR_FLAG_LEVEL;
656 656 break;
657 657 case DDI_INTROP_SETCAP:
658 658 ret = DDI_ENOTSUP;
659 659 break;
660 660 case DDI_INTROP_ALLOC:
661 661 *(int *)result = hdlp->ih_scratch1;
662 662 break;
663 663 case DDI_INTROP_FREE:
664 664 break;
665 665 case DDI_INTROP_GETPRI:
666 666 *(int *)result = rootnex_get_intr_pri(dip, rdip, hdlp);
667 667 break;
668 668 case DDI_INTROP_SETPRI:
669 669 break;
670 670 case DDI_INTROP_ADDISR:
671 671 ret = rootnex_add_intr_impl(dip, rdip, hdlp);
672 672 break;
673 673 case DDI_INTROP_REMISR:
674 674 ret = rootnex_remove_intr_impl(dip, rdip, hdlp);
675 675 break;
676 676 case DDI_INTROP_ENABLE:
677 677 case DDI_INTROP_DISABLE:
678 678 break;
679 679 case DDI_INTROP_NINTRS:
680 680 case DDI_INTROP_NAVAIL:
681 681 *(int *)result = i_ddi_get_intx_nintrs(rdip);
682 682 break;
683 683 case DDI_INTROP_SUPPORTED_TYPES:
684 684 /* Root nexus driver supports only fixed interrupts */
685 685 *(int *)result = i_ddi_get_intx_nintrs(rdip) ?
686 686 DDI_INTR_TYPE_FIXED : 0;
687 687 break;
688 688 default:
689 689 ret = DDI_ENOTSUP;
690 690 break;
691 691 }
692 692
693 693 return (ret);
694 694 }
695 695
696 696
697 697 /*
698 698 * Shorthand defines
699 699 */
700 700
701 701 #define DMAOBJ_PP_PP dmao_obj.pp_obj.pp_pp
702 702 #define DMAOBJ_PP_OFF dmao_ogj.pp_obj.pp_offset
703 703 #define ALO dma_lim->dlim_addr_lo
704 704 #define AHI dma_lim->dlim_addr_hi
705 705 #define OBJSIZE dmareq->dmar_object.dmao_size
706 706 #define ORIGVADDR dmareq->dmar_object.dmao_obj.virt_obj.v_addr
707 707 #define RED ((mp->dmai_rflags & DDI_DMA_REDZONE)? 1 : 0)
708 708 #define DIRECTION (mp->dmai_rflags & DDI_DMA_RDWR)
709 709
710 710 /*
711 711 * rootnex_map_fault:
↓ open down ↓ |
711 lines elided |
↑ open up ↑ |
712 712 *
713 713 * fault in mappings for requestors
714 714 */
715 715
716 716 /*ARGSUSED*/
717 717 static int
718 718 rootnex_map_fault(dev_info_t *dip, dev_info_t *rdip,
719 719 struct hat *hat, struct seg *seg, caddr_t addr,
720 720 struct devpage *dp, pfn_t pfn, uint_t prot, uint_t lock)
721 721 {
722 - extern struct seg_ops segdev_ops;
722 + extern const struct seg_ops segdev_ops;
723 723
724 724 DPRINTF(ROOTNEX_MAP_DEBUG, ("rootnex_map_fault: address <%p> "
725 725 "pfn <%lx>", (void *)addr, pfn));
726 726 DPRINTF(ROOTNEX_MAP_DEBUG, (" Seg <%s>\n",
727 727 seg->s_ops == &segdev_ops ? "segdev" :
728 728 seg == &kvseg ? "segkmem" : "NONE!"));
729 729
730 730 /*
731 731 * This is all terribly broken, but it is a start
732 732 *
733 733 * XXX Note that this test means that segdev_ops
734 734 * must be exported from seg_dev.c.
735 735 * XXX What about devices with their own segment drivers?
736 736 */
737 737 if (seg->s_ops == &segdev_ops) {
738 738 register struct segdev_data *sdp =
739 739 (struct segdev_data *)seg->s_data;
740 740
741 741 if (hat == NULL) {
742 742 /*
743 743 * This is one plausible interpretation of
744 744 * a null hat i.e. use the first hat on the
745 745 * address space hat list which by convention is
746 746 * the hat of the system MMU. At alternative
747 747 * would be to panic .. this might well be better ..
748 748 */
749 749 ASSERT(AS_READ_HELD(seg->s_as, &seg->s_as->a_lock));
750 750 hat = seg->s_as->a_hat;
751 751 cmn_err(CE_NOTE, "rootnex_map_fault: nil hat");
752 752 }
753 753 hat_devload(hat, addr, MMU_PAGESIZE, pfn, prot | sdp->hat_attr,
754 754 (lock ? HAT_LOAD_LOCK : HAT_LOAD));
755 755 } else if (seg == &kvseg && dp == (struct devpage *)0) {
756 756 hat_devload(kas.a_hat, addr, MMU_PAGESIZE, pfn, prot,
757 757 HAT_LOAD_LOCK);
758 758 } else
759 759 return (DDI_FAILURE);
760 760 return (DDI_SUCCESS);
761 761 }
762 762
763 763 /*
764 764 * Name a child of rootnex
765 765 *
766 766 * This may be called multiple times, independent of initchild calls.
767 767 */
768 768 int
769 769 rootnex_name_child(dev_info_t *child, char *name, int namelen)
770 770 {
771 771 return (rootnex_name_child_impl(child, name, namelen));
772 772 }
773 773
774 774
775 775 static int
776 776 rootnex_ctl_initchild(dev_info_t *dip)
777 777 {
778 778 return (rootnex_ctl_initchild_impl(dip));
779 779 }
780 780
781 781
782 782 int
783 783 rootnex_ctl_uninitchild(dev_info_t *dip)
784 784 {
785 785 extern void impl_free_ddi_ppd(dev_info_t *);
786 786
787 787 rootnex_ctl_uninitchild_impl(dip);
788 788
789 789 /*
790 790 * strip properties and convert node to prototype form
791 791 */
792 792 impl_free_ddi_ppd(dip);
793 793 ddi_set_name_addr(dip, NULL);
794 794 impl_rem_dev_props(dip);
795 795 return (DDI_SUCCESS);
796 796 }
797 797
798 798
799 799 static int
800 800 rootnex_ctl_reportdev(dev_info_t *dev)
801 801 {
802 802 return (rootnex_ctl_reportdev_impl(dev));
803 803 }
804 804
805 805
806 806 static int
807 807 rootnex_ctlops_peekpoke(ddi_ctl_enum_t cmd, peekpoke_ctlops_t *in_args,
808 808 void *result)
809 809 {
810 810 int err = DDI_SUCCESS;
811 811 on_trap_data_t otd;
812 812
813 813 /* No safe access except for peek/poke is supported. */
814 814 if (in_args->handle != NULL)
815 815 return (DDI_FAILURE);
816 816
817 817 /* Set up protected environment. */
818 818 if (!on_trap(&otd, OT_DATA_ACCESS)) {
819 819 uintptr_t tramp = otd.ot_trampoline;
820 820
821 821 if (cmd == DDI_CTLOPS_POKE) {
822 822 otd.ot_trampoline = (uintptr_t)&poke_fault;
823 823 err = do_poke(in_args->size, (void *)in_args->dev_addr,
824 824 (void *)in_args->host_addr);
825 825 } else {
826 826 otd.ot_trampoline = (uintptr_t)&peek_fault;
827 827 err = do_peek(in_args->size, (void *)in_args->dev_addr,
828 828 (void *)in_args->host_addr);
829 829 result = (void *)in_args->host_addr;
830 830 }
831 831 otd.ot_trampoline = tramp;
832 832 } else
833 833 err = DDI_FAILURE;
834 834
835 835 /* Take down protected environment. */
836 836 no_trap();
837 837
838 838 return (err);
839 839 }
840 840
841 841 /*ARGSUSED*/
842 842 static int
843 843 rootnex_ctlops(dev_info_t *dip, dev_info_t *rdip,
844 844 ddi_ctl_enum_t ctlop, void *arg, void *result)
845 845 {
846 846 register int n, *ptr;
847 847 register struct ddi_parent_private_data *pdp;
848 848
849 849 static boolean_t reserved_msg_printed = B_FALSE;
850 850
851 851 switch (ctlop) {
852 852 case DDI_CTLOPS_DMAPMAPC:
853 853 return (DDI_FAILURE);
854 854
855 855 case DDI_CTLOPS_BTOP:
856 856 /*
857 857 * Convert byte count input to physical page units.
858 858 * (byte counts that are not a page-size multiple
859 859 * are rounded down)
860 860 */
861 861 *(ulong_t *)result = btop(*(ulong_t *)arg);
862 862 return (DDI_SUCCESS);
863 863
864 864 case DDI_CTLOPS_PTOB:
865 865 /*
866 866 * Convert size in physical pages to bytes
867 867 */
868 868 *(ulong_t *)result = ptob(*(ulong_t *)arg);
869 869 return (DDI_SUCCESS);
870 870
871 871 case DDI_CTLOPS_BTOPR:
872 872 /*
873 873 * Convert byte count input to physical page units
874 874 * (byte counts that are not a page-size multiple
875 875 * are rounded up)
876 876 */
877 877 *(ulong_t *)result = btopr(*(ulong_t *)arg);
878 878 return (DDI_SUCCESS);
879 879
880 880 case DDI_CTLOPS_INITCHILD:
881 881 return (rootnex_ctl_initchild((dev_info_t *)arg));
882 882
883 883 case DDI_CTLOPS_UNINITCHILD:
884 884 return (rootnex_ctl_uninitchild((dev_info_t *)arg));
885 885
886 886 case DDI_CTLOPS_REPORTDEV:
887 887 return (rootnex_ctl_reportdev(rdip));
888 888
889 889 case DDI_CTLOPS_IOMIN:
890 890 /*
891 891 * Nothing to do here but reflect back..
892 892 */
893 893 return (DDI_SUCCESS);
894 894
895 895 case DDI_CTLOPS_REGSIZE:
896 896 case DDI_CTLOPS_NREGS:
897 897 break;
898 898
899 899 case DDI_CTLOPS_SIDDEV:
900 900 if (ndi_dev_is_prom_node(rdip))
901 901 return (DDI_SUCCESS);
902 902 if (ndi_dev_is_persistent_node(rdip))
903 903 return (DDI_SUCCESS);
904 904 return (DDI_FAILURE);
905 905
906 906 case DDI_CTLOPS_POWER: {
907 907 return ((*pm_platform_power)((power_req_t *)arg));
908 908 }
909 909
910 910 case DDI_CTLOPS_RESERVED0: /* Was DDI_CTLOPS_NINTRS, obsolete */
911 911 case DDI_CTLOPS_RESERVED1: /* Was DDI_CTLOPS_POKE_INIT, obsolete */
912 912 case DDI_CTLOPS_RESERVED2: /* Was DDI_CTLOPS_POKE_FLUSH, obsolete */
913 913 case DDI_CTLOPS_RESERVED3: /* Was DDI_CTLOPS_POKE_FINI, obsolete */
914 914 case DDI_CTLOPS_RESERVED4: /* Was DDI_CTLOPS_INTR_HILEVEL, obsolete */
915 915 case DDI_CTLOPS_RESERVED5: /* Was DDI_CTLOPS_XLATE_INTRS, obsolete */
916 916 if (!reserved_msg_printed) {
917 917 reserved_msg_printed = B_TRUE;
918 918 cmn_err(CE_WARN, "Failing ddi_ctlops call(s) for "
919 919 "1 or more reserved/obsolete operations.");
920 920 }
921 921 return (DDI_FAILURE);
922 922
923 923 case DDI_CTLOPS_POKE:
924 924 case DDI_CTLOPS_PEEK:
925 925 return (rootnex_ctlops_peekpoke(ctlop, (peekpoke_ctlops_t *)arg,
926 926 result));
927 927
928 928 default:
929 929 return (DDI_FAILURE);
930 930 }
931 931
932 932 /*
933 933 * The rest are for "hardware" properties
934 934 */
935 935 if ((pdp = ddi_get_parent_data(rdip)) == NULL)
936 936 return (DDI_FAILURE);
937 937
938 938 if (ctlop == DDI_CTLOPS_NREGS) {
939 939 ptr = (int *)result;
940 940 *ptr = pdp->par_nreg;
941 941 } else { /* ctlop == DDI_CTLOPS_REGSIZE */
942 942 off_t *size = (off_t *)result;
943 943
944 944 ptr = (int *)arg;
945 945 n = *ptr;
946 946 if (n >= pdp->par_nreg) {
947 947 return (DDI_FAILURE);
948 948 }
949 949 *size = (off_t)pdp->par_reg[n].regspec_size;
950 950 }
951 951 return (DDI_SUCCESS);
952 952 }
953 953
954 954 /* ARGSUSED */
955 955 int
956 956 rootnex_busop_fminit(dev_info_t *dip, dev_info_t *tdip, int cap,
957 957 ddi_iblock_cookie_t *ibc)
958 958 {
959 959 *ibc = rootnex_err_ibc;
960 960 return (ddi_system_fmcap | DDI_FM_ACCCHK_CAPABLE |
961 961 DDI_FM_DMACHK_CAPABLE);
962 962 }
963 963
964 964 static void
965 965 rootnex_fm_init(dev_info_t *dip)
966 966 {
967 967 int fmcap;
968 968
969 969 /* Minimum fm capability level for sun4u platforms */
970 970 ddi_system_fmcap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE;
971 971
972 972 fmcap = ddi_system_fmcap;
973 973
974 974 /*
975 975 * Initialize ECC error handling
976 976 */
977 977 rootnex_err_ibc = (ddi_iblock_cookie_t)PIL_15;
978 978 ddi_fm_init(dip, &fmcap, &rootnex_err_ibc);
979 979 }
↓ open down ↓ |
247 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX