Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/pci-ide/pci-ide.c
+++ new/usr/src/uts/common/io/pci-ide/pci-ide.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 (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24 /*
25 25 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
26 26 */
27 27
28 28 /*
29 29 * PCI-IDE bus nexus driver
30 30 */
31 31
32 32 #include <sys/types.h>
33 33 #include <sys/cmn_err.h>
34 34 #include <sys/conf.h>
35 35 #include <sys/errno.h>
36 36 #include <sys/debug.h>
37 37 #include <sys/ddidmareq.h>
38 38 #include <sys/ddi_impldefs.h>
39 39 #include <sys/dma_engine.h>
40 40 #include <sys/modctl.h>
41 41 #include <sys/ddi.h>
42 42 #include <sys/sunddi.h>
43 43 #include <sys/sunndi.h>
44 44 #include <sys/mach_intr.h>
45 45 #include <sys/kmem.h>
46 46 #include <sys/pci.h>
47 47 #include <sys/promif.h>
48 48 #include <sys/pci_intr_lib.h>
49 49 #include <sys/apic.h>
50 50
51 51 int pciide_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
52 52 int pciide_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
53 53
54 54 #define PCIIDE_NATIVE_MODE(dip) \
55 55 (!ddi_prop_exists(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \
56 56 "compatibility-mode"))
57 57
58 58 #define PCIIDE_PRE26(dip) \
59 59 ddi_prop_exists(DDI_DEV_T_ANY, (dip), 0, "ignore-hardware-nodes")
60 60
61 61 #define PCI_IDE_IF_BM_CAP_MASK 0x80
62 62
63 63 #define PCIIDE_PDSIZE (sizeof (struct ddi_parent_private_data) + \
64 64 sizeof (struct intrspec))
65 65
66 66 #ifdef DEBUG
67 67 static int pci_ide_debug = 0;
68 68 #define PDBG(fmt) \
69 69 if (pci_ide_debug) { \
70 70 prom_printf fmt; \
71 71 }
72 72 #else
73 73 #define PDBG(fmt)
74 74 #endif
75 75
76 76 #ifndef TRUE
77 77 #define TRUE 1
78 78 #endif
79 79 #ifndef FALSE
80 80 #define FALSE 0
81 81 #endif
82 82
83 83 /*
84 84 * bus_ops functions
85 85 */
86 86
87 87 static int pciide_bus_map(dev_info_t *dip, dev_info_t *rdip,
88 88 ddi_map_req_t *mp, off_t offset, off_t len,
89 89 caddr_t *vaddrp);
90 90
91 91 static int pciide_ddi_ctlops(dev_info_t *dip, dev_info_t *rdip,
92 92 ddi_ctl_enum_t ctlop, void *arg,
93 93 void *result);
94 94
95 95 static int pciide_get_pri(dev_info_t *dip, dev_info_t *rdip,
96 96 ddi_intr_handle_impl_t *hdlp, int *pri);
97 97
98 98 static int pciide_intr_ops(dev_info_t *dip, dev_info_t *rdip,
99 99 ddi_intr_op_t intr_op,
100 100 ddi_intr_handle_impl_t *hdlp, void *result);
101 101
102 102 static struct intrspec *pciide_get_ispec(dev_info_t *dip, dev_info_t *rdip,
103 103 int inum);
104 104
105 105 /*
106 106 * Local Functions
107 107 */
108 108 static int pciide_initchild(dev_info_t *mydip, dev_info_t *cdip);
109 109
110 110 static void pciide_compat_setup(dev_info_t *mydip, dev_info_t *cdip,
111 111 int dev);
112 112 static int pciide_pre26_rnumber_map(dev_info_t *mydip, int rnumber);
113 113 static int pciide_map_rnumber(int canonical_rnumber, int pri_native,
114 114 int sec_native);
115 115 static int pciide_alloc_intr(dev_info_t *, dev_info_t *,
116 116 ddi_intr_handle_impl_t *, void *);
117 117 static int pciide_free_intr(dev_info_t *, dev_info_t *,
118 118 ddi_intr_handle_impl_t *);
119 119
120 120 extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
121 121 psm_intr_op_t, int *);
122 122
123 123 /*
124 124 * Config information
125 125 */
126 126
127 127 struct bus_ops pciide_bus_ops = {
128 128 BUSO_REV,
129 129 pciide_bus_map,
130 130 0,
131 131 0,
132 132 0,
133 133 i_ddi_map_fault,
134 134 0,
135 135 ddi_dma_allochdl,
136 136 ddi_dma_freehdl,
137 137 ddi_dma_bindhdl,
138 138 ddi_dma_unbindhdl,
139 139 ddi_dma_flush,
140 140 ddi_dma_win,
141 141 ddi_dma_mctl,
142 142 pciide_ddi_ctlops,
143 143 ddi_bus_prop_op,
144 144 0, /* (*bus_get_eventcookie)(); */
145 145 0, /* (*bus_add_eventcall)(); */
146 146 0, /* (*bus_remove_eventcall)(); */
147 147 0, /* (*bus_post_event)(); */
148 148 0,
149 149 0,
150 150 0,
151 151 0,
152 152 0,
153 153 0,
154 154 0,
155 155 0,
156 156 pciide_intr_ops
157 157 };
158 158
159 159 struct dev_ops pciide_ops = {
160 160 DEVO_REV, /* devo_rev, */
161 161 0, /* refcnt */
162 162 ddi_no_info, /* info */
163 163 nulldev, /* identify */
164 164 nulldev, /* probe */
165 165 pciide_attach, /* attach */
166 166 pciide_detach, /* detach */
167 167 nodev, /* reset */
168 168 (struct cb_ops *)0, /* driver operations */
169 169 &pciide_bus_ops, /* bus operations */
170 170 NULL, /* power */
171 171 ddi_quiesce_not_needed, /* quiesce */
172 172 };
173 173
174 174 /*
175 175 * Module linkage information for the kernel.
↓ open down ↓ |
175 lines elided |
↑ open up ↑ |
176 176 */
177 177
178 178 static struct modldrv modldrv = {
179 179 &mod_driverops, /* Type of module. This is PCI-IDE bus driver */
180 180 "pciide nexus driver for 'PCI-IDE' 1.26",
181 181 &pciide_ops, /* driver ops */
182 182 };
183 183
184 184 static struct modlinkage modlinkage = {
185 185 MODREV_1,
186 - &modldrv,
187 - NULL
186 + { &modldrv, NULL }
188 187 };
189 188
190 189
191 190 int
192 191 _init(void)
193 192 {
194 193 return (mod_install(&modlinkage));
195 194 }
196 195
197 196 int
198 197 _fini(void)
199 198 {
200 199 return (mod_remove(&modlinkage));
201 200 }
202 201
203 202 int
204 203 _info(struct modinfo *modinfop)
205 204 {
206 205 return (mod_info(&modlinkage, modinfop));
207 206 }
208 207
209 208 int
210 209 pciide_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
211 210 {
212 211 uint16_t cmdreg;
213 212 ddi_acc_handle_t conf_hdl = NULL;
214 213 int rc;
215 214
216 215 switch (cmd) {
217 216 case DDI_ATTACH:
218 217 /*
219 218 * Make sure bus-mastering is enabled, even if
220 219 * BIOS didn't.
221 220 */
222 221 rc = pci_config_setup(dip, &conf_hdl);
223 222
224 223 /*
225 224 * In case of error, return SUCCESS. This is because
226 225 * bus-mastering could be already enabled by BIOS.
227 226 */
228 227 if (rc != DDI_SUCCESS)
229 228 return (DDI_SUCCESS);
230 229
231 230 cmdreg = pci_config_get16(conf_hdl, PCI_CONF_COMM);
232 231 if ((cmdreg & PCI_COMM_ME) == 0) {
233 232 pci_config_put16(conf_hdl, PCI_CONF_COMM,
234 233 cmdreg | PCI_COMM_ME);
235 234 }
236 235 pci_config_teardown(&conf_hdl);
237 236 return (DDI_SUCCESS);
238 237
239 238 case DDI_RESUME:
240 239 /* Restore our PCI configuration header */
241 240 if (pci_restore_config_regs(dip) != DDI_SUCCESS) {
242 241 /*
243 242 * XXXX
244 243 * This is a pretty bad thing. However, for some
245 244 * reason it always happens. To further complicate
246 245 * things, it appears if we just ignore this, we
247 246 * properly resume. For now, all I want to do is
248 247 * to generate this message so that it doesn't get
249 248 * forgotten.
250 249 */
251 250 cmn_err(CE_WARN,
252 251 "Couldn't restore PCI config regs for %s(%p)",
253 252 ddi_node_name(dip), (void *) dip);
254 253 }
255 254 #ifdef DEBUG
256 255 /* Bus mastering should still be enabled */
257 256 if (pci_config_setup(dip, &conf_hdl) != DDI_SUCCESS)
258 257 return (DDI_FAILURE);
259 258 cmdreg = pci_config_get16(conf_hdl, PCI_CONF_COMM);
260 259 ASSERT((cmdreg & PCI_COMM_ME) != 0);
261 260 pci_config_teardown(&conf_hdl);
262 261 #endif
263 262 return (DDI_SUCCESS);
264 263 }
265 264
266 265 return (DDI_FAILURE);
267 266 }
268 267
269 268 /*ARGSUSED*/
270 269 int
271 270 pciide_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
272 271 {
273 272 switch (cmd) {
274 273 case DDI_DETACH:
275 274 return (DDI_SUCCESS);
276 275 case DDI_SUSPEND:
277 276 /* Save our PCI configuration header */
278 277 if (pci_save_config_regs(dip) != DDI_SUCCESS) {
279 278 /* Don't suspend if we cannot save config regs */
280 279 return (DDI_FAILURE);
281 280 }
282 281 return (DDI_SUCCESS);
283 282 }
284 283 return (DDI_FAILURE);
285 284 }
286 285
287 286 /*ARGSUSED*/
288 287 static int
289 288 pciide_ddi_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
290 289 void *arg, void *result)
291 290 {
292 291 dev_info_t *cdip;
293 292 int controller;
294 293 void *pdptr;
295 294 int rnumber;
296 295 off_t tmp;
297 296 int rc;
298 297
299 298 PDBG(("pciide_bus_ctl\n"));
300 299
301 300 switch (ctlop) {
302 301 case DDI_CTLOPS_INITCHILD:
303 302 cdip = (dev_info_t *)arg;
304 303 return (pciide_initchild(dip, cdip));
305 304
306 305 case DDI_CTLOPS_UNINITCHILD:
307 306 cdip = (dev_info_t *)arg;
308 307 pdptr = ddi_get_parent_data(cdip);
309 308 ddi_set_parent_data(cdip, NULL);
310 309 ddi_set_name_addr(cdip, NULL);
311 310 kmem_free(pdptr, PCIIDE_PDSIZE);
312 311 return (DDI_SUCCESS);
313 312
314 313 case DDI_CTLOPS_NREGS:
315 314 *(int *)result = 3;
316 315 return (DDI_SUCCESS);
317 316
318 317 case DDI_CTLOPS_REGSIZE:
319 318 /*
320 319 * Adjust the rnumbers based on which controller instance
321 320 * is requested; adjust for the 2 tuples per controller.
322 321 */
323 322 if (strcmp("0", ddi_get_name_addr(rdip)) == 0)
324 323 controller = 0;
325 324 else
326 325 controller = 1;
327 326
328 327
329 328 switch (rnumber = *(int *)arg) {
330 329 case 0:
331 330 case 1:
332 331 rnumber += (2 * controller);
333 332 break;
334 333 case 2:
335 334 rnumber = 4;
336 335 break;
337 336 default:
338 337 PDBG(("pciide_ctlops invalid rnumber\n"));
339 338 return (DDI_FAILURE);
340 339 }
341 340
342 341
343 342 if (PCIIDE_PRE26(dip)) {
344 343 int old_rnumber;
345 344 int new_rnumber;
346 345
347 346 old_rnumber = rnumber;
348 347 new_rnumber
349 348 = pciide_pre26_rnumber_map(dip, old_rnumber);
350 349 PDBG(("pciide rnumber old %d new %d\n",
351 350 old_rnumber, new_rnumber));
352 351 rnumber = new_rnumber;
353 352 }
354 353
355 354 /*
356 355 * Add 1 to skip over the PCI config space tuple
357 356 */
358 357 rnumber++;
359 358
360 359 /*
361 360 * If it's not tuple #2 pass the adjusted request to my parent
362 361 */
363 362 if (*(int *)arg != 2) {
364 363 return (ddi_ctlops(dip, dip, ctlop, &rnumber, result));
365 364 }
366 365
367 366 /*
368 367 * Handle my child's reg-tuple #2 here by splitting my 16 byte
369 368 * reg-tuple #4 into two 8 byte ranges based on the
370 369 * the child's controller #.
371 370 */
372 371
373 372 tmp = 8;
374 373 rc = ddi_ctlops(dip, dip, ctlop, &rnumber, &tmp);
375 374
376 375 /*
377 376 * Allow for the possibility of less than 16 bytes by
378 377 * by checking what's actually returned for my reg-tuple #4.
379 378 */
380 379 if (controller == 1) {
381 380 if (tmp < 8)
382 381 tmp = 0;
383 382 else
384 383 tmp -= 8;
385 384 }
386 385 if (tmp > 8)
387 386 tmp = 8;
388 387 *(off_t *)result = tmp;
389 388
390 389 return (rc);
391 390
392 391 case DDI_CTLOPS_ATTACH:
393 392 case DDI_CTLOPS_DETACH:
394 393 /*
395 394 * Don't pass child ide ATTACH/DETACH to parent
396 395 */
397 396 return (DDI_SUCCESS);
398 397
399 398 default:
400 399 return (ddi_ctlops(dip, rdip, ctlop, arg, result));
401 400 }
402 401 }
403 402
404 403 /*
405 404 * IEEE 1275 Working Group Proposal #414 says that the Primary
406 405 * controller is "ata@0" and the Secondary controller "ata@1".
407 406 *
408 407 * By the time we get here, boot Bootconf (2.6+) has created devinfo
409 408 * nodes with the appropriate "reg", "assigned-addresses" and "interrupts"
410 409 * properites on the pci-ide node and both ide child nodes.
411 410 *
412 411 * In compatibility mode the "reg" and "assigned-addresses" properties
413 412 * of the pci-ide node are set up like this:
414 413 *
415 414 * 1. PCI-IDE Nexus
416 415 *
417 416 * interrupts=0
418 417 * (addr-hi addr-mid addr-low size-hi size-low)
419 418 * reg= assigned-addresses=00000000.00000000.00000000.00000000.00000000
420 419 * 81000000.00000000.000001f0.00000000.00000008
421 420 * 81000000.00000000.000003f4.00000000.00000004
422 421 * 81000000.00000000,00000170.00000000.00000008
423 422 * 81000000.00000000,00000374.00000000.00000004
424 423 * 01000020.00000000,-[BAR4]-.00000000.00000010
425 424 *
426 425 * In native PCI mode the "reg" and "assigned-addresses" properties
427 426 * would be set up like this:
428 427 *
429 428 * 2. PCI-IDE Nexus
430 429 *
431 430 * interrupts=0
432 431 * reg= assigned-addresses=00000000.00000000.00000000.00000000.00000000
433 432 * 01000010.00000000.-[BAR0]-.00000000.00000008
434 433 * 01000014,00000000.-[BAR1]-.00000000.00000004
435 434 * 01000018.00000000.-[BAR2]-.00000000.00000008
436 435 * 0100001c.00000000.-[BAR3]-.00000000.00000004
437 436 * 01000020.00000000.-[BAR4]-.00000000.00000010
438 437 *
439 438 *
440 439 * In both modes the child nodes simply have the following:
441 440 *
442 441 * 2. primary controller (compatibility mode)
443 442 *
444 443 * interrupts=14
445 444 * reg=00000000
446 445 *
447 446 * 3. secondary controller
448 447 *
449 448 * interrupts=15
450 449 * reg=00000001
451 450 *
452 451 * The pciide_bus_map() function is responsible for turning requests
453 452 * to map primary or secondary controller rnumbers into mapping requests
454 453 * of the appropriate regspec on the pci-ide node.
455 454 *
456 455 */
457 456
458 457 static int
459 458 pciide_initchild(dev_info_t *mydip, dev_info_t *cdip)
460 459 {
461 460 struct ddi_parent_private_data *pdptr;
462 461 struct intrspec *ispecp;
463 462 int vec;
464 463 int *rp;
465 464 uint_t proplen;
466 465 char name[80];
467 466 int dev;
468 467
469 468 PDBG(("pciide_initchild\n"));
470 469
471 470 /*
472 471 * Set the address portion of the node name based on
473 472 * the controller number (0 or 1) from the 'reg' property.
474 473 */
475 474 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
476 475 "reg", &rp, (uint_t *)&proplen) != DDI_PROP_SUCCESS) {
477 476 PDBG(("pciide_intchild prop error\n"));
478 477 return (DDI_NOT_WELL_FORMED);
479 478 }
480 479
481 480 /*
482 481 * copy the controller number and
483 482 * free the memory allocated by ddi_prop_lookup_int_array
484 483 */
485 484 dev = *rp;
486 485 ddi_prop_free(rp);
487 486
488 487 /*
489 488 * I only support two controllers per device, determine
490 489 * which this one is and set its unit address.
491 490 */
492 491 if (dev > 1) {
493 492 PDBG(("pciide_initchild bad dev\n"));
494 493 return (DDI_NOT_WELL_FORMED);
495 494 }
496 495 (void) sprintf(name, "%d", dev);
497 496 ddi_set_name_addr(cdip, name);
498 497
499 498 /*
500 499 * determine if this instance is running in native or compat mode
501 500 */
502 501 pciide_compat_setup(mydip, cdip, dev);
503 502
504 503 /* interrupts property is required */
505 504 if (PCIIDE_NATIVE_MODE(cdip)) {
506 505 vec = 1;
507 506 } else {
508 507 /*
509 508 * In compatibility mode, dev 0 should always be
510 509 * IRQ 14 and dev 1 is IRQ 15. If for some reason
511 510 * this needs to be changed, do it via the interrupts
512 511 * property in the ata.conf file.
513 512 */
514 513 vec = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
515 514 "interrupts", -1);
516 515 if (vec == -1) {
517 516 /* setup compatibility mode interrupts */
518 517 if (dev == 0) {
519 518 vec = 14;
520 519 } else if (dev == 1) {
521 520 vec = 15;
522 521 } else {
523 522 PDBG(("pciide_initchild bad intr\n"));
524 523 return (DDI_NOT_WELL_FORMED);
525 524 }
526 525 }
527 526 }
528 527
529 528 pdptr = kmem_zalloc(PCIIDE_PDSIZE, KM_SLEEP);
530 529 ispecp = (struct intrspec *)(pdptr + 1);
531 530 pdptr->par_nintr = 1;
532 531 pdptr->par_intr = ispecp;
533 532 ispecp->intrspec_vec = vec;
534 533 ddi_set_parent_data(cdip, pdptr);
535 534
536 535 PDBG(("pciide_initchild okay\n"));
537 536 return (DDI_SUCCESS);
538 537 }
539 538
540 539 static int
541 540 pciide_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
542 541 off_t offset, off_t len, caddr_t *vaddrp)
543 542 {
544 543 dev_info_t *pdip;
545 544 int rnumber = mp->map_obj.rnumber;
546 545 int controller;
547 546 int rc;
548 547
549 548 PDBG(("pciide_bus_map\n"));
550 549
551 550 if (strcmp("0", ddi_get_name_addr(rdip)) == 0)
552 551 controller = 0;
553 552 else
554 553 controller = 1;
555 554
556 555 /*
557 556 * Adjust the rnumbers based on which controller instance
558 557 * is being mapped; adjust for the 2 tuples per controller.
559 558 */
560 559
561 560 switch (rnumber) {
562 561 case 0:
563 562 case 1:
564 563 mp->map_obj.rnumber += (controller * 2);
565 564 break;
566 565 case 2:
567 566 /*
568 567 * split the 16 I/O ports into two 8 port ranges
569 568 */
570 569 mp->map_obj.rnumber = 4;
571 570 if (offset + len > 8) {
572 571 PDBG(("pciide_bus_map offset\n"));
573 572 return (DDI_FAILURE);
574 573 }
575 574 if (len == 0)
576 575 len = 8 - offset;
577 576 offset += 8 * controller;
578 577 break;
579 578 default:
580 579 PDBG(("pciide_bus_map default\n"));
581 580 return (DDI_FAILURE);
582 581 }
583 582
584 583 if (PCIIDE_PRE26(dip)) {
585 584 int old_rnumber;
586 585 int new_rnumber;
587 586
588 587 old_rnumber = mp->map_obj.rnumber;
589 588 new_rnumber = pciide_pre26_rnumber_map(dip, old_rnumber);
590 589 PDBG(("pciide rnumber old %d new %d\n",
591 590 old_rnumber, new_rnumber));
592 591 mp->map_obj.rnumber = new_rnumber;
593 592 }
594 593
595 594 /*
596 595 * Add 1 to skip over the PCI config space tuple
597 596 */
598 597 mp->map_obj.rnumber++;
599 598
600 599
601 600 /*
602 601 * pass the adjusted request to my parent
603 602 */
604 603 pdip = ddi_get_parent(dip);
605 604 rc = ((*(DEVI(pdip)->devi_ops->devo_bus_ops->bus_map))
606 605 (pdip, dip, mp, offset, len, vaddrp));
607 606
608 607 PDBG(("pciide_bus_map %s\n", rc == DDI_SUCCESS ? "okay" : "!ok"));
609 608
610 609 return (rc);
611 610 }
612 611
613 612
614 613 static struct intrspec *
615 614 pciide_get_ispec(dev_info_t *dip, dev_info_t *rdip, int inumber)
616 615 {
617 616 struct ddi_parent_private_data *ppdptr;
618 617
619 618 PDBG(("pciide_get_ispec\n"));
620 619
621 620 /*
622 621 * Native mode PCI-IDE controllers share the parent's
623 622 * PCI interrupt line.
624 623 *
625 624 * Compatibility mode PCI-IDE controllers have their
626 625 * own intrspec which specifies ISA IRQ 14 or 15.
627 626 *
628 627 */
629 628 if (PCIIDE_NATIVE_MODE(rdip)) {
630 629 ddi_intrspec_t is;
631 630
632 631 is = pci_intx_get_ispec(dip, dip, inumber);
633 632 PDBG(("pciide_get_ispec okay\n"));
634 633 return ((struct intrspec *)is);
635 634 }
636 635
637 636 /* Else compatibility mode, use the ISA IRQ */
638 637 if ((ppdptr = ddi_get_parent_data(rdip)) == NULL) {
639 638 PDBG(("pciide_get_ispec null\n"));
640 639 return (NULL);
641 640 }
642 641
643 642 /* validate the interrupt number */
644 643 if (inumber >= ppdptr->par_nintr) {
645 644 PDBG(("pciide_get_inum\n"));
646 645 return (NULL);
647 646 }
648 647
649 648 PDBG(("pciide_get_ispec ok\n"));
650 649
651 650 return ((struct intrspec *)&ppdptr->par_intr[inumber]);
652 651 }
653 652
654 653 static int
655 654 pciide_get_pri(dev_info_t *dip, dev_info_t *rdip,
656 655 ddi_intr_handle_impl_t *hdlp, int *pri)
657 656 {
658 657 struct intrspec *ispecp;
659 658 int *intpriorities;
660 659 uint_t num_intpriorities;
661 660
662 661 PDBG(("pciide_get_pri\n"));
663 662
664 663 if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) == NULL) {
665 664 PDBG(("pciide_get_pri null\n"));
666 665 return (DDI_FAILURE);
667 666 }
668 667
669 668 if (PCIIDE_NATIVE_MODE(rdip)) {
670 669 *pri = ispecp->intrspec_pri;
671 670 PDBG(("pciide_get_pri ok\n"));
672 671 return (DDI_SUCCESS);
673 672 }
674 673
675 674 /* check if the intrspec has been initialized */
676 675 if (ispecp->intrspec_pri != 0) {
677 676 *pri = ispecp->intrspec_pri;
678 677 PDBG(("pciide_get_pri ok2\n"));
679 678 return (DDI_SUCCESS);
680 679 }
681 680
682 681 /* Use a default of level 5 */
683 682 ispecp->intrspec_pri = 5;
684 683
685 684 /*
686 685 * If there's an interrupt-priorities property, use it to
687 686 * over-ride the default interrupt priority.
688 687 */
689 688 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
690 689 "interrupt-priorities", &intpriorities, &num_intpriorities) ==
691 690 DDI_PROP_SUCCESS) {
692 691 if (hdlp->ih_inum < num_intpriorities)
693 692 ispecp->intrspec_pri = intpriorities[hdlp->ih_inum];
694 693 ddi_prop_free(intpriorities);
695 694 }
696 695 *pri = ispecp->intrspec_pri;
697 696
698 697 PDBG(("pciide_get_pri ok3\n"));
699 698
700 699 return (DDI_SUCCESS);
701 700 }
702 701
703 702 static int
704 703 pciide_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
705 704 ddi_intr_handle_impl_t *hdlp, void *result)
706 705 {
707 706 struct intrspec *ispecp;
708 707 int rc;
709 708 int pri = 0;
710 709
711 710 PDBG(("pciide_intr_ops: dip %p rdip %p op %x hdlp %p\n",
712 711 (void *)dip, (void *)rdip, intr_op, (void *)hdlp));
713 712
714 713 switch (intr_op) {
715 714 case DDI_INTROP_SUPPORTED_TYPES:
716 715 *(int *)result = DDI_INTR_TYPE_FIXED;
717 716 break;
718 717 case DDI_INTROP_GETCAP:
719 718 *(int *)result = DDI_INTR_FLAG_LEVEL;
720 719 break;
721 720 case DDI_INTROP_NINTRS:
722 721 case DDI_INTROP_NAVAIL:
723 722 *(int *)result = (!PCIIDE_NATIVE_MODE(rdip)) ?
724 723 i_ddi_get_intx_nintrs(rdip) : 1;
725 724 break;
726 725 case DDI_INTROP_ALLOC:
727 726 return (pciide_alloc_intr(dip, rdip, hdlp, result));
728 727 case DDI_INTROP_FREE:
729 728 return (pciide_free_intr(dip, rdip, hdlp));
730 729 case DDI_INTROP_GETPRI:
731 730 if (pciide_get_pri(dip, rdip, hdlp, &pri) != DDI_SUCCESS) {
732 731 *(int *)result = 0;
733 732 return (DDI_FAILURE);
734 733 }
735 734 *(int *)result = pri;
736 735 break;
737 736 case DDI_INTROP_ADDISR:
738 737 if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) ==
739 738 NULL)
740 739 return (DDI_FAILURE);
741 740 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispecp;
742 741 ispecp->intrspec_func = hdlp->ih_cb_func;
743 742 break;
744 743 case DDI_INTROP_REMISR:
745 744 if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) ==
746 745 NULL)
747 746 return (DDI_FAILURE);
748 747 ispecp->intrspec_func = (uint_t (*)()) 0;
749 748 break;
750 749 case DDI_INTROP_ENABLE:
751 750 /* FALLTHRU */
752 751 case DDI_INTROP_DISABLE:
753 752 if (PCIIDE_NATIVE_MODE(rdip)) {
754 753 rdip = dip;
755 754 dip = ddi_get_parent(dip);
756 755 } else { /* get ptr to the root node */
757 756 dip = ddi_root_node();
758 757 }
759 758
760 759 rc = (*(DEVI(dip)->devi_ops->devo_bus_ops->bus_intr_op))(dip,
761 760 rdip, intr_op, hdlp, result);
762 761
763 762 #ifdef DEBUG
764 763 if (intr_op == DDI_INTROP_ENABLE) {
765 764 PDBG(("pciide_enable rc=%d", rc));
766 765 } else
767 766 PDBG(("pciide_disable rc=%d", rc));
768 767 #endif /* DEBUG */
769 768 return (rc);
770 769 default:
771 770 return (DDI_FAILURE);
772 771 }
773 772
774 773 return (DDI_SUCCESS);
775 774 }
776 775
777 776 int
778 777 pciide_alloc_intr(dev_info_t *dip, dev_info_t *rdip,
779 778 ddi_intr_handle_impl_t *hdlp, void *result)
780 779 {
781 780 struct intrspec *ispec;
782 781 ddi_intr_handle_impl_t info_hdl;
783 782 int ret;
784 783 int free_phdl = 0;
785 784 apic_get_type_t type_info;
786 785
787 786 if (psm_intr_ops == NULL)
788 787 return (DDI_FAILURE);
789 788
790 789 if ((ispec = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) == NULL)
791 790 return (DDI_FAILURE);
792 791
793 792 /*
794 793 * If the PSM module is "APIX" then pass the request for it
795 794 * to allocate the vector now.
796 795 */
797 796 bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
798 797 info_hdl.ih_private = &type_info;
799 798 if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
800 799 PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
801 800 if (hdlp->ih_private == NULL) { /* allocate phdl structure */
802 801 free_phdl = 1;
803 802 i_ddi_alloc_intr_phdl(hdlp);
804 803 }
805 804 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
806 805 if (PCIIDE_NATIVE_MODE(rdip)) {
807 806 rdip = dip;
808 807 dip = ddi_get_parent(dip);
809 808 } else { /* get ptr to the root node */
810 809 dip = ddi_root_node();
811 810 }
812 811 ret = (*psm_intr_ops)(rdip, hdlp,
813 812 PSM_INTR_OP_ALLOC_VECTORS, result);
814 813 if (free_phdl) { /* free up the phdl structure */
815 814 free_phdl = 0;
816 815 i_ddi_free_intr_phdl(hdlp);
817 816 }
818 817 } else {
819 818 /*
820 819 * No APIX module; fall back to the old scheme where the
821 820 * interrupt vector is allocated during ddi_enable_intr() call.
822 821 */
823 822 *(int *)result = hdlp->ih_scratch1;
824 823 ret = DDI_SUCCESS;
825 824 }
826 825
827 826 return (ret);
828 827 }
829 828
830 829 int
831 830 pciide_free_intr(dev_info_t *dip, dev_info_t *rdip,
832 831 ddi_intr_handle_impl_t *hdlp)
833 832 {
834 833 struct intrspec *ispec;
835 834 ddi_intr_handle_impl_t info_hdl;
836 835 apic_get_type_t type_info;
837 836
838 837 if (psm_intr_ops == NULL)
839 838 return (DDI_FAILURE);
840 839
841 840 /*
842 841 * If the PSM module is "APIX" then pass the request for it
843 842 * to free up the vector now.
844 843 */
845 844 bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
846 845 info_hdl.ih_private = &type_info;
847 846 if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
848 847 PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
849 848 if ((ispec = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) ==
850 849 NULL)
851 850 return (DDI_FAILURE);
852 851 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
853 852 if (PCIIDE_NATIVE_MODE(rdip)) {
854 853 rdip = dip;
855 854 dip = ddi_get_parent(dip);
856 855 } else { /* get ptr to the root node */
857 856 dip = ddi_root_node();
858 857 }
859 858 return ((*psm_intr_ops)(rdip, hdlp,
860 859 PSM_INTR_OP_FREE_VECTORS, NULL));
861 860 }
862 861
863 862 /*
864 863 * No APIX module; fall back to the old scheme where
865 864 * the interrupt vector was already freed during
866 865 * ddi_disable_intr() call.
867 866 */
868 867 return (DDI_SUCCESS);
869 868 }
870 869
871 870 /*
872 871 * This is one of the places where controller specific setup needs to be
873 872 * considered.
874 873 * At this point the controller was already pre-qualified as a known and
875 874 * supported pciide controller.
876 875 * Some controllers do not provide PCI_MASS_IDE sub-class code and IDE
877 876 * programming interface code but rather PCI_MASS_OTHER sub-class code
878 877 * without any additional data.
879 878 * For those controllers IDE programming interface cannot be extracted
880 879 * from PCI class - we assume that they are pci-native type and we fix
881 880 * the programming interface used by other functions.
882 881 * The programming interface byte is set to indicate pci-native mode
883 882 * for both controllers and the Bus Master DMA capabilitiy of the controller.
884 883 */
885 884 static void
886 885 pciide_compat_setup(dev_info_t *mydip, dev_info_t *cdip, int dev)
887 886 {
888 887 int class_code;
889 888 int rc = DDI_PROP_SUCCESS;
890 889
891 890 class_code = ddi_prop_get_int(DDI_DEV_T_ANY, mydip,
892 891 DDI_PROP_DONTPASS, "class-code", 0);
893 892
894 893 if (((class_code & 0x00FF00) >> 8) == PCI_MASS_IDE) {
895 894 /*
896 895 * Controller provides PCI_MASS_IDE sub-class code first
897 896 * (implied IDE programming interface)
898 897 */
899 898 if ((dev == 0 && !(class_code & PCI_IDE_IF_NATIVE_PRI)) ||
900 899 (dev == 1 && !(class_code & PCI_IDE_IF_NATIVE_SEC))) {
901 900 rc = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
902 901 "compatibility-mode", 1);
903 902 if (rc != DDI_PROP_SUCCESS)
904 903 cmn_err(CE_WARN,
905 904 "pciide prop error %d compat-mode", rc);
906 905 }
907 906 } else {
908 907 /*
909 908 * Pci-ide controllers not providing PCI_MASS_IDE sub-class are
910 909 * assumed to be of pci-native type and bus master DMA capable.
911 910 * Programming interface part of the class-code property is
912 911 * fixed here.
913 912 */
914 913 class_code &= 0x00ffff00;
915 914 class_code |= PCI_IDE_IF_BM_CAP_MASK |
916 915 PCI_IDE_IF_NATIVE_PRI | PCI_IDE_IF_NATIVE_SEC;
917 916 rc = ddi_prop_update_int(DDI_DEV_T_NONE, mydip,
918 917 "class-code", class_code);
919 918 if (rc != DDI_PROP_SUCCESS)
920 919 cmn_err(CE_WARN,
921 920 "pciide prop error %d class-code", rc);
922 921 }
923 922 }
924 923
925 924
926 925 static int
927 926 pciide_pre26_rnumber_map(dev_info_t *mydip, int rnumber)
928 927 {
929 928 int pri_native;
930 929 int sec_native;
931 930 int class_code;
932 931
933 932 class_code = ddi_prop_get_int(DDI_DEV_T_ANY, mydip, DDI_PROP_DONTPASS,
934 933 "class-code", 0);
935 934
936 935 pri_native = (class_code & PCI_IDE_IF_NATIVE_PRI) ? TRUE : FALSE;
937 936 sec_native = (class_code & PCI_IDE_IF_NATIVE_SEC) ? TRUE : FALSE;
938 937
939 938 return (pciide_map_rnumber(rnumber, pri_native, sec_native));
940 939
941 940 }
942 941
943 942 /*
944 943 * The canonical order of the reg property tuples for the
945 944 * Base Address Registers is supposed to be:
946 945 *
947 946 * primary controller (BAR 0)
948 947 * primary controller (BAR 1)
949 948 * secondary controller (BAR 2)
950 949 * secondary controller (BAR 3)
951 950 * bus mastering regs (BAR 4)
952 951 *
953 952 * For 2.6, bootconf has been fixed to always generate the
954 953 * reg property (and assigned-addresses property) tuples
955 954 * in the above order.
956 955 *
957 956 * But in releases prior to 2.6 the order varies depending
958 957 * on whether compatibility or native mode is being used for
959 958 * each controller. There ends up being four possible
960 959 * orders:
961 960 *
962 961 * BM, P0, P1, S0, S1 primary compatible, secondary compatible
963 962 * S0, S1, BM, P0, P1 primary compatible, secondary native
964 963 * P0, P1, BM, S0, S1 primary native, secondary compatible
965 964 * P0, P1, S0, S1, BM primary native, secondary native
966 965 *
967 966 * where: Px is the primary tuples, Sx the secondary tuples, and
968 967 * B the Bus Master tuple.
969 968 *
970 969 * Here's the results for each of the four states:
971 970 *
972 971 * 0, 1, 2, 3, 4
973 972 *
974 973 * CC 1, 2, 3, 4, 0
975 974 * CN 3, 4, 0, 1, 2
976 975 * NC 0, 1, 3, 4, 2
↓ open down ↓ |
779 lines elided |
↑ open up ↑ |
977 976 * NN 0, 1, 2, 3, 4
978 977 *
979 978 * C = compatible(!native) == 0
980 979 * N = native == 1
981 980 *
982 981 * Here's the transformation matrix:
983 982 */
984 983
985 984 static int pciide_transform[2][2][5] = {
986 985 /* P S */
987 -/* [C][C] */ +1, +1, +1, +1, -4,
988 -/* [C][N] */ +3, +3, -2, -2, -2,
989 -/* [N][C] */ +0, +0, +1, +1, -2,
990 -/* [N][N] */ +0, +0, +0, +0, +0
986 +/* [C][C] */ { { +1, +1, +1, +1, -4 },
987 +/* [C][N] */ { +3, +3, -2, -2, -2 } },
988 +/* [N][C] */ { { +0, +0, +1, +1, -2 },
989 +/* [N][N] */ { +0, +0, +0, +0, +0 } }
991 990 };
992 991
993 992
994 993 static int
995 994 pciide_map_rnumber(int rnumber, int pri_native, int sec_native)
996 995 {
997 996 /* transform flags into indexes */
998 997 pri_native = pri_native ? 1 : 0;
999 998 sec_native = sec_native ? 1 : 0;
1000 999
1001 1000 rnumber += pciide_transform[pri_native][sec_native][rnumber];
1002 1001 return (rnumber);
1003 1002 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX