Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/i86pc/io/isa.c
+++ new/usr/src/uts/i86pc/io/isa.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 2014 Garrett D'Amore <garrett@damore.org>
23 23 * Copyright (c) 2012 Gary Mills
24 24 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
25 25 */
26 26
27 27 /*
28 28 * ISA bus nexus driver
29 29 */
30 30
31 31 #include <sys/types.h>
32 32 #include <sys/cmn_err.h>
33 33 #include <sys/conf.h>
34 34 #include <sys/modctl.h>
35 35 #include <sys/autoconf.h>
36 36 #include <sys/errno.h>
37 37 #include <sys/debug.h>
38 38 #include <sys/kmem.h>
39 39 #include <sys/psm.h>
40 40 #include <sys/ddidmareq.h>
41 41 #include <sys/ddi_impldefs.h>
42 42 #include <sys/ddi_subrdefs.h>
43 43 #include <sys/dma_engine.h>
44 44 #include <sys/ddi.h>
45 45 #include <sys/sunddi.h>
46 46 #include <sys/sunndi.h>
47 47 #include <sys/acpi/acpi_enum.h>
48 48 #include <sys/mach_intr.h>
49 49 #include <sys/pci.h>
50 50 #include <sys/note.h>
51 51 #include <sys/boot_console.h>
52 52 #include <sys/apic.h>
53 53 #if defined(__xpv)
54 54 #include <sys/hypervisor.h>
55 55 #include <sys/evtchn_impl.h>
56 56
57 57 extern int console_hypervisor_dev_type(int *);
58 58 #endif
59 59
60 60
61 61 extern int pseudo_isa;
62 62 extern int isa_resource_setup(void);
63 63 extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
64 64 psm_intr_op_t, int *);
65 65 extern void pci_register_isa_resources(int, uint32_t, uint32_t);
66 66 static void isa_enumerate(int);
67 67 static void enumerate_BIOS_serial(dev_info_t *);
68 68 static void adjust_prtsz(dev_info_t *isa_dip);
69 69 static void isa_create_ranges_prop(dev_info_t *);
70 70
71 71 #define USED_RESOURCES "used-resources"
72 72
73 73 /*
74 74 * The following typedef is used to represent an entry in the "ranges"
75 75 * property of a pci-isa bridge device node.
76 76 */
77 77 typedef struct {
78 78 uint32_t child_high;
79 79 uint32_t child_low;
80 80 uint32_t parent_high;
81 81 uint32_t parent_mid;
82 82 uint32_t parent_low;
83 83 uint32_t size;
84 84 } pib_ranges_t;
85 85
86 86 typedef struct {
87 87 uint32_t base;
88 88 uint32_t len;
89 89 } used_ranges_t;
90 90
91 91 #define USED_CELL_SIZE 2 /* 1 byte addr, 1 byte size */
92 92 #define ISA_ADDR_IO 1 /* IO address space */
93 93 #define ISA_ADDR_MEM 0 /* memory adress space */
94 94
95 95 /*
96 96 * #define ISA_DEBUG 1
97 97 */
98 98
99 99 #define num_BIOS_serial 4 /* number of BIOS serial ports to look at */
100 100 #define min_BIOS_serial 2 /* minimum number of BIOS serial ports */
101 101 #define COM_ISR 2 /* 16550 intr status register */
102 102 #define COM_SCR 7 /* 16550 scratch register */
103 103
104 104 /*
105 105 * For serial ports not enumerated by ACPI, and parallel ports with
106 106 * illegal size. Typically, a system can have as many as 4 serial
107 107 * ports and 3 parallel ports.
108 108 */
109 109 #define MAX_EXTRA_RESOURCE 7
110 110 static struct regspec isa_extra_resource[MAX_EXTRA_RESOURCE];
111 111 static int isa_extra_count = 0;
112 112
113 113 /* Register definitions for COM1 to COM4. */
114 114 static struct regspec asy_regs[] = {
115 115 {1, 0x3f8, 0x8},
116 116 {1, 0x2f8, 0x8},
117 117 {1, 0x3e8, 0x8},
118 118 {1, 0x2e8, 0x8}
119 119 };
120 120
121 121 /* Serial port interrupt vectors for COM1 to COM4. */
122 122 static int asy_intrs[] = {0x4, 0x3, 0x4, 0x3};
123 123 /* Bitfield indicating which interrupts are overridden by eeprom config */
124 124 static uchar_t asy_intr_override = 0;
125 125
126 126 /*
127 127 * Local data
128 128 */
129 129
130 130 static ddi_dma_attr_t ISA_dma_attr = {
131 131 DMA_ATTR_V0,
132 132 (unsigned long long)0,
133 133 (unsigned long long)0x00ffffff,
134 134 0x0000ffff,
135 135 1,
136 136 1,
137 137 1,
138 138 (unsigned long long)0xffffffff,
139 139 (unsigned long long)0x0000ffff,
140 140 1,
141 141 1,
142 142 0
143 143 };
144 144
145 145
146 146 /*
147 147 * Config information
148 148 */
149 149
150 150 static int
151 151 isa_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
152 152 off_t offset, off_t len, caddr_t *vaddrp);
153 153
154 154 static int
155 155 isa_dma_allochdl(dev_info_t *, dev_info_t *, ddi_dma_attr_t *,
156 156 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *);
157 157
158 158 static int
159 159 isa_dma_mctl(dev_info_t *, dev_info_t *, ddi_dma_handle_t, enum ddi_dma_ctlops,
160 160 off_t *, size_t *, caddr_t *, uint_t);
161 161
162 162 static int
163 163 isa_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *);
164 164
165 165 static int
166 166 isa_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
167 167 ddi_intr_handle_impl_t *hdlp, void *result);
168 168 static int isa_alloc_intr_fixed(dev_info_t *, ddi_intr_handle_impl_t *, void *);
169 169 static int isa_free_intr_fixed(dev_info_t *, ddi_intr_handle_impl_t *);
170 170
171 171 struct bus_ops isa_bus_ops = {
172 172 BUSO_REV,
173 173 isa_bus_map,
174 174 NULL,
175 175 NULL,
176 176 NULL,
177 177 i_ddi_map_fault,
178 178 NULL,
179 179 isa_dma_allochdl,
180 180 ddi_dma_freehdl,
181 181 ddi_dma_bindhdl,
182 182 ddi_dma_unbindhdl,
183 183 ddi_dma_flush,
184 184 ddi_dma_win,
185 185 isa_dma_mctl,
186 186 isa_ctlops,
187 187 ddi_bus_prop_op,
188 188 NULL, /* (*bus_get_eventcookie)(); */
189 189 NULL, /* (*bus_add_eventcall)(); */
190 190 NULL, /* (*bus_remove_eventcall)(); */
191 191 NULL, /* (*bus_post_event)(); */
192 192 NULL, /* (*bus_intr_ctl)(); */
193 193 NULL, /* (*bus_config)(); */
194 194 NULL, /* (*bus_unconfig)(); */
195 195 NULL, /* (*bus_fm_init)(); */
196 196 NULL, /* (*bus_fm_fini)(); */
197 197 NULL, /* (*bus_fm_access_enter)(); */
198 198 NULL, /* (*bus_fm_access_exit)(); */
199 199 NULL, /* (*bus_power)(); */
200 200 isa_intr_ops /* (*bus_intr_op)(); */
201 201 };
202 202
203 203
204 204 static int isa_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
205 205
206 206 /*
207 207 * Internal isa ctlops support routines
208 208 */
209 209 static int isa_initchild(dev_info_t *child);
210 210
211 211 struct dev_ops isa_ops = {
212 212 DEVO_REV, /* devo_rev, */
213 213 0, /* refcnt */
214 214 ddi_no_info, /* info */
215 215 nulldev, /* identify */
216 216 nulldev, /* probe */
217 217 isa_attach, /* attach */
218 218 nulldev, /* detach */
219 219 nodev, /* reset */
220 220 (struct cb_ops *)0, /* driver operations */
221 221 &isa_bus_ops, /* bus operations */
222 222 NULL, /* power */
223 223 ddi_quiesce_not_needed, /* quiesce */
224 224 };
225 225
226 226 /*
227 227 * Module linkage information for the kernel.
↓ open down ↓ |
227 lines elided |
↑ open up ↑ |
228 228 */
229 229
230 230 static struct modldrv modldrv = {
231 231 &mod_driverops, /* Type of module. This is ISA bus driver */
232 232 "isa nexus driver for 'ISA'",
233 233 &isa_ops, /* driver ops */
234 234 };
235 235
236 236 static struct modlinkage modlinkage = {
237 237 MODREV_1,
238 - &modldrv,
239 - NULL
238 + { &modldrv, NULL }
240 239 };
241 240
242 241 int
243 242 _init(void)
244 243 {
245 244 int err;
246 245 char tty_irq_param[9] = "ttyX-irq";
247 246 char *tty_irq;
248 247 int i;
249 248
250 249 if ((err = mod_install(&modlinkage)) != 0)
251 250 return (err);
252 251
253 252 /* Check if any tty irqs are overridden by eeprom config */
254 253 for (i = 0; i < num_BIOS_serial; i++) {
255 254 tty_irq_param[3] = 'a' + i;
256 255 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
257 256 DDI_PROP_DONTPASS, tty_irq_param, &tty_irq)
258 257 == DDI_PROP_SUCCESS) {
259 258 long data;
260 259
261 260 if (ddi_strtol(tty_irq, NULL, 0, &data) == 0) {
262 261 asy_intrs[i] = (int)data;
263 262 asy_intr_override |= 1<<i;
264 263 }
265 264
266 265 ddi_prop_free(tty_irq);
267 266 }
268 267 }
269 268
270 269 impl_bus_add_probe(isa_enumerate);
271 270 return (0);
272 271 }
273 272
274 273 int
275 274 _fini(void)
276 275 {
277 276 int err;
278 277
279 278 impl_bus_delete_probe(isa_enumerate);
280 279
281 280 if ((err = mod_remove(&modlinkage)) != 0)
282 281 return (err);
283 282
284 283 return (0);
285 284 }
286 285
287 286 int
288 287 _info(struct modinfo *modinfop)
289 288 {
290 289 return (mod_info(&modlinkage, modinfop));
291 290 }
292 291
293 292 static int
294 293 isa_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
295 294 {
296 295 int rval;
297 296
298 297 #if defined(__xpv)
299 298 /*
300 299 * don't allow isa to attach in domU. this can happen if someone sets
301 300 * the console wrong, etc. ISA devices assume the H/W is there and
302 301 * will cause the domU to panic.
303 302 */
304 303 if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
305 304 return (DDI_FAILURE);
306 305 }
307 306 #endif
308 307
309 308 switch (cmd) {
310 309 case DDI_ATTACH:
311 310 break;
312 311 case DDI_RESUME:
313 312 return (DDI_SUCCESS);
314 313 default:
315 314 return (DDI_FAILURE);
316 315 }
317 316
318 317 if ((rval = i_dmae_init(devi)) == DDI_SUCCESS)
319 318 ddi_report_dev(devi);
320 319
321 320 return (rval);
322 321 }
323 322
324 323 #define SET_RNGS(rng_p, used_p, ctyp, ptyp) do { \
325 324 (rng_p)->child_high = (ctyp); \
326 325 (rng_p)->child_low = (rng_p)->parent_low = (used_p)->base; \
327 326 (rng_p)->parent_high = (ptyp); \
328 327 (rng_p)->parent_mid = 0; \
329 328 (rng_p)->size = (used_p)->len; \
330 329 _NOTE(CONSTCOND) } while (0)
331 330 static uint_t
332 331 isa_used_to_ranges(int ctype, int *array, uint_t size, pib_ranges_t *ranges)
333 332 {
334 333 used_ranges_t *used_p;
335 334 pib_ranges_t *rng_p = ranges;
336 335 uint_t i, ptype;
337 336
338 337 ptype = (ctype == ISA_ADDR_IO) ? PCI_ADDR_IO : PCI_ADDR_MEM32;
339 338 ptype |= PCI_REG_REL_M;
340 339 size /= USED_CELL_SIZE;
341 340 used_p = (used_ranges_t *)array;
342 341 SET_RNGS(rng_p, used_p, ctype, ptype);
343 342 for (i = 1, used_p++; i < size; i++, used_p++) {
344 343 /* merge ranges record if applicable */
345 344 if (rng_p->child_low + rng_p->size == used_p->base)
346 345 rng_p->size += used_p->len;
347 346 else {
348 347 rng_p++;
349 348 SET_RNGS(rng_p, used_p, ctype, ptype);
350 349 }
351 350 }
352 351 return (rng_p - ranges + 1);
353 352 }
354 353
355 354 void
356 355 isa_remove_res_from_pci(int type, int *array, uint_t size)
357 356 {
358 357 int i;
359 358 used_ranges_t *used_p;
360 359
361 360 size /= USED_CELL_SIZE;
362 361 used_p = (used_ranges_t *)array;
363 362 for (i = 0; i < size; i++, used_p++)
364 363 pci_register_isa_resources(type, used_p->base, used_p->len);
365 364 }
366 365
367 366 static void
368 367 isa_create_ranges_prop(dev_info_t *dip)
369 368 {
370 369 dev_info_t *used;
371 370 int *ioarray, *memarray, status;
372 371 uint_t nio = 0, nmem = 0, nrng = 0, n;
373 372 pib_ranges_t *ranges;
374 373
375 374 used = ddi_find_devinfo(USED_RESOURCES, -1, 0);
376 375 if (used == NULL) {
377 376 cmn_err(CE_WARN, "Failed to find used-resources <%s>\n",
378 377 ddi_get_name(dip));
379 378 return;
380 379 }
381 380 status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, used,
382 381 DDI_PROP_DONTPASS, "io-space", &ioarray, &nio);
383 382 if (status != DDI_PROP_SUCCESS && status != DDI_PROP_NOT_FOUND) {
384 383 cmn_err(CE_WARN, "io-space property failure for %s (%x)\n",
385 384 ddi_get_name(used), status);
386 385 return;
387 386 }
388 387 status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, used,
389 388 DDI_PROP_DONTPASS, "device-memory", &memarray, &nmem);
390 389 if (status != DDI_PROP_SUCCESS && status != DDI_PROP_NOT_FOUND) {
391 390 cmn_err(CE_WARN, "device-memory property failure for %s (%x)\n",
392 391 ddi_get_name(used), status);
393 392 return;
394 393 }
395 394 n = (nio + nmem) / USED_CELL_SIZE;
396 395 ranges = (pib_ranges_t *)kmem_zalloc(sizeof (pib_ranges_t) * n,
397 396 KM_SLEEP);
398 397
399 398 if (nio != 0) {
400 399 nrng = isa_used_to_ranges(ISA_ADDR_IO, ioarray, nio, ranges);
401 400 isa_remove_res_from_pci(ISA_ADDR_IO, ioarray, nio);
402 401 ddi_prop_free(ioarray);
403 402 }
404 403 if (nmem != 0) {
405 404 nrng += isa_used_to_ranges(ISA_ADDR_MEM, memarray, nmem,
406 405 ranges + nrng);
407 406 isa_remove_res_from_pci(ISA_ADDR_MEM, memarray, nmem);
408 407 ddi_prop_free(memarray);
409 408 }
410 409
411 410 if (!pseudo_isa)
412 411 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
413 412 (int *)ranges, nrng * sizeof (pib_ranges_t) / sizeof (int));
414 413 kmem_free(ranges, sizeof (pib_ranges_t) * n);
415 414 }
416 415
417 416 /*ARGSUSED*/
418 417 static int
419 418 isa_apply_range(dev_info_t *dip, struct regspec *isa_reg_p,
420 419 pci_regspec_t *pci_reg_p)
421 420 {
422 421 pib_ranges_t *ranges, *rng_p;
423 422 int len, i, offset, nrange;
424 423
425 424 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
426 425 "ranges", (caddr_t)&ranges, &len) != DDI_SUCCESS) {
427 426 cmn_err(CE_WARN, "Can't get %s ranges property",
428 427 ddi_get_name(dip));
429 428 return (DDI_ME_REGSPEC_RANGE);
430 429 }
431 430 nrange = len / sizeof (pib_ranges_t);
432 431 rng_p = ranges;
433 432 for (i = 0; i < nrange; i++, rng_p++) {
434 433 /* Check for correct space */
435 434 if (isa_reg_p->regspec_bustype != rng_p->child_high)
436 435 continue;
437 436
438 437 /* Detect whether request entirely fits within a range */
439 438 if (isa_reg_p->regspec_addr < rng_p->child_low)
440 439 continue;
441 440 if ((isa_reg_p->regspec_addr + isa_reg_p->regspec_size - 1) >
442 441 (rng_p->child_low + rng_p->size - 1))
443 442 continue;
444 443
445 444 offset = isa_reg_p->regspec_addr - rng_p->child_low;
446 445
447 446 pci_reg_p->pci_phys_hi = rng_p->parent_high;
448 447 pci_reg_p->pci_phys_mid = 0;
449 448 pci_reg_p->pci_phys_low = rng_p->parent_low + offset;
450 449 pci_reg_p->pci_size_hi = 0;
451 450 pci_reg_p->pci_size_low = isa_reg_p->regspec_size;
452 451
453 452 break;
454 453 }
455 454 kmem_free(ranges, len);
456 455
457 456 if (i < nrange)
458 457 return (DDI_SUCCESS);
459 458
460 459 /*
461 460 * Check extra resource range specially for serial and parallel
462 461 * devices, which are treated differently from all other ISA
463 462 * devices. On some machines, serial ports are not enumerated
464 463 * by ACPI but by BIOS, with io base addresses noted in legacy
465 464 * BIOS data area. Parallel port on some machines comes with
466 465 * illegal size.
467 466 */
468 467 if (isa_reg_p->regspec_bustype != ISA_ADDR_IO) {
469 468 cmn_err(CE_WARN, "Bus type not ISA I/O\n");
470 469 return (DDI_ME_REGSPEC_RANGE);
471 470 }
472 471
473 472 for (i = 0; i < isa_extra_count; i++) {
474 473 struct regspec *reg_p = &isa_extra_resource[i];
475 474
476 475 if (isa_reg_p->regspec_addr < reg_p->regspec_addr)
477 476 continue;
478 477 if ((isa_reg_p->regspec_addr + isa_reg_p->regspec_size) >
479 478 (reg_p->regspec_addr + reg_p->regspec_size))
480 479 continue;
481 480
482 481 pci_reg_p->pci_phys_hi = PCI_ADDR_IO | PCI_REG_REL_M;
483 482 pci_reg_p->pci_phys_mid = 0;
484 483 pci_reg_p->pci_phys_low = isa_reg_p->regspec_addr;
485 484 pci_reg_p->pci_size_hi = 0;
486 485 pci_reg_p->pci_size_low = isa_reg_p->regspec_size;
487 486 break;
488 487 }
489 488 if (i < isa_extra_count)
490 489 return (DDI_SUCCESS);
491 490
492 491 cmn_err(CE_WARN, "isa_apply_range: Out of range base <0x%x>, size <%d>",
493 492 isa_reg_p->regspec_addr, isa_reg_p->regspec_size);
494 493 return (DDI_ME_REGSPEC_RANGE);
495 494 }
496 495
497 496 static int
498 497 isa_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
499 498 off_t offset, off_t len, caddr_t *vaddrp)
500 499 {
501 500 struct regspec tmp_reg, *rp;
502 501 pci_regspec_t vreg;
503 502 ddi_map_req_t mr = *mp; /* Get private copy of request */
504 503 int error;
505 504
506 505 if (pseudo_isa)
507 506 return (i_ddi_bus_map(dip, rdip, mp, offset, len, vaddrp));
508 507
509 508 mp = &mr;
510 509
511 510 /*
512 511 * First, if given an rnumber, convert it to a regspec...
513 512 */
514 513 if (mp->map_type == DDI_MT_RNUMBER) {
515 514
516 515 int rnumber = mp->map_obj.rnumber;
517 516
518 517 rp = i_ddi_rnumber_to_regspec(rdip, rnumber);
519 518 if (rp == (struct regspec *)0)
520 519 return (DDI_ME_RNUMBER_RANGE);
521 520
522 521 /*
523 522 * Convert the given ddi_map_req_t from rnumber to regspec...
524 523 */
525 524 mp->map_type = DDI_MT_REGSPEC;
526 525 mp->map_obj.rp = rp;
527 526 }
528 527
529 528 /*
530 529 * Adjust offset and length correspnding to called values...
531 530 * XXX: A non-zero length means override the one in the regspec.
532 531 * XXX: (Regardless of what's in the parent's range)
533 532 */
534 533
535 534 tmp_reg = *(mp->map_obj.rp); /* Preserve underlying data */
536 535 rp = mp->map_obj.rp = &tmp_reg; /* Use tmp_reg in request */
537 536
538 537 rp->regspec_addr += (uint_t)offset;
539 538 if (len != 0)
540 539 rp->regspec_size = (uint_t)len;
541 540
542 541 if ((error = isa_apply_range(dip, rp, &vreg)) != 0)
543 542 return (error);
544 543 mp->map_obj.rp = (struct regspec *)&vreg;
545 544
546 545 /*
547 546 * Call my parents bus_map function with modified values...
548 547 */
549 548
550 549 return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp));
551 550 }
552 551
553 552 static int
554 553 isa_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *dma_attr,
555 554 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
556 555 {
557 556 ddi_dma_attr_merge(dma_attr, &ISA_dma_attr);
558 557 return (ddi_dma_allochdl(dip, rdip, dma_attr, waitfp, arg, handlep));
559 558 }
560 559
561 560 static int
562 561 isa_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
563 562 ddi_dma_handle_t handle, enum ddi_dma_ctlops request,
564 563 off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags)
565 564 {
566 565 int rval;
567 566 int arg = (int)(uintptr_t)objp;
568 567
569 568 switch (request) {
570 569
571 570 case DDI_DMA_E_PROG:
572 571 return (i_dmae_prog(rdip, (struct ddi_dmae_req *)offp,
573 572 (ddi_dma_cookie_t *)lenp, arg));
574 573
575 574 case DDI_DMA_E_ACQUIRE:
576 575 return (i_dmae_acquire(rdip, arg, (int(*)(caddr_t))offp,
577 576 (caddr_t)lenp));
578 577
579 578 case DDI_DMA_E_FREE:
580 579 return (i_dmae_free(rdip, arg));
581 580
582 581 case DDI_DMA_E_STOP:
583 582 i_dmae_stop(rdip, arg);
584 583 return (DDI_SUCCESS);
585 584
586 585 case DDI_DMA_E_ENABLE:
587 586 i_dmae_enable(rdip, arg);
588 587 return (DDI_SUCCESS);
589 588
590 589 case DDI_DMA_E_DISABLE:
591 590 i_dmae_disable(rdip, arg);
592 591 return (DDI_SUCCESS);
593 592
594 593 case DDI_DMA_E_GETCNT:
595 594 i_dmae_get_chan_stat(rdip, arg, NULL, (int *)lenp);
596 595 return (DDI_SUCCESS);
597 596
598 597 case DDI_DMA_E_SWSETUP:
599 598 return (i_dmae_swsetup(rdip, (struct ddi_dmae_req *)offp,
600 599 (ddi_dma_cookie_t *)lenp, arg));
601 600
602 601 case DDI_DMA_E_SWSTART:
603 602 i_dmae_swstart(rdip, arg);
604 603 return (DDI_SUCCESS);
605 604
606 605 case DDI_DMA_E_GETATTR:
607 606 bcopy(&ISA_dma_attr, objp, sizeof (ddi_dma_attr_t));
608 607 return (DDI_SUCCESS);
609 608
610 609 case DDI_DMA_E_1STPTY:
611 610 {
612 611 struct ddi_dmae_req req1stpty =
613 612 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
614 613 if (arg == 0) {
615 614 req1stpty.der_command = DMAE_CMD_TRAN;
616 615 req1stpty.der_trans = DMAE_TRANS_DMND;
617 616 } else {
618 617 req1stpty.der_trans = DMAE_TRANS_CSCD;
619 618 }
620 619 return (i_dmae_prog(rdip, &req1stpty, NULL, arg));
621 620 }
622 621
623 622 default:
624 623 /*
625 624 * We pass to rootnex, but it turns out that rootnex will just
626 625 * return failure, as we don't use ddi_dma_mctl() except
627 626 * for DMA engine (ISA) and DVMA (SPARC). Arguably we could
628 627 * just return an error direclty here, instead.
629 628 */
630 629 rval = ddi_dma_mctl(dip, rdip, handle, request, offp,
631 630 lenp, objp, flags);
632 631 }
633 632 return (rval);
634 633 }
635 634
636 635 /*
637 636 * Check if driver should be treated as an old pre 2.6 driver
638 637 */
639 638 static int
640 639 old_driver(dev_info_t *dip)
641 640 {
642 641 extern int ignore_hardware_nodes; /* force flag from ddi_impl.c */
643 642
644 643 if (ndi_dev_is_persistent_node(dip)) {
645 644 if (ignore_hardware_nodes)
646 645 return (1);
647 646 if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
648 647 "ignore-hardware-nodes", -1) != -1)
649 648 return (1);
650 649 }
651 650 return (0);
652 651 }
653 652
654 653 typedef struct {
655 654 uint32_t phys_hi;
656 655 uint32_t phys_lo;
657 656 uint32_t size;
658 657 } isa_regs_t;
659 658
660 659 /*
661 660 * Return non-zero if device in tree is a PnP isa device
662 661 */
663 662 static int
664 663 is_pnpisa(dev_info_t *dip)
665 664 {
666 665 isa_regs_t *isa_regs;
667 666 int proplen, pnpisa;
668 667
669 668 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
670 669 (caddr_t)&isa_regs, &proplen) != DDI_PROP_SUCCESS) {
671 670 return (0);
672 671 }
673 672 pnpisa = isa_regs[0].phys_hi & 0x80000000;
674 673 /*
675 674 * free the memory allocated by ddi_getlongprop().
676 675 */
677 676 kmem_free(isa_regs, proplen);
678 677 if (pnpisa)
679 678 return (1);
680 679 else
681 680 return (0);
682 681 }
683 682
684 683 /*ARGSUSED*/
685 684 static int
686 685 isa_ctlops(dev_info_t *dip, dev_info_t *rdip,
687 686 ddi_ctl_enum_t ctlop, void *arg, void *result)
688 687 {
689 688 int rn;
690 689 struct ddi_parent_private_data *pdp;
691 690
692 691 switch (ctlop) {
693 692 case DDI_CTLOPS_REPORTDEV:
694 693 if (rdip == (dev_info_t *)0)
695 694 return (DDI_FAILURE);
696 695 cmn_err(CE_CONT, "?ISA-device: %s%d\n",
697 696 ddi_driver_name(rdip), ddi_get_instance(rdip));
698 697 return (DDI_SUCCESS);
699 698
700 699 case DDI_CTLOPS_INITCHILD:
701 700 /*
702 701 * older drivers aren't expecting the "standard" device
703 702 * node format used by the hardware nodes. these drivers
704 703 * only expect their own properties set in their driver.conf
705 704 * files. so they tell us not to call them with hardware
706 705 * nodes by setting the property "ignore-hardware-nodes".
707 706 */
708 707 if (old_driver((dev_info_t *)arg)) {
709 708 return (DDI_NOT_WELL_FORMED);
710 709 }
711 710
712 711 return (isa_initchild((dev_info_t *)arg));
713 712
714 713 case DDI_CTLOPS_UNINITCHILD:
715 714 impl_ddi_sunbus_removechild((dev_info_t *)arg);
716 715 return (DDI_SUCCESS);
717 716
718 717 case DDI_CTLOPS_SIDDEV:
719 718 if (ndi_dev_is_persistent_node(rdip))
720 719 return (DDI_SUCCESS);
721 720 /*
722 721 * All ISA devices need to do confirming probes
723 722 * unless they are PnP ISA.
724 723 */
725 724 if (is_pnpisa(rdip))
726 725 return (DDI_SUCCESS);
727 726 else
728 727 return (DDI_FAILURE);
729 728
730 729 case DDI_CTLOPS_REGSIZE:
731 730 case DDI_CTLOPS_NREGS:
732 731 if (rdip == (dev_info_t *)0)
733 732 return (DDI_FAILURE);
734 733
735 734 if ((pdp = ddi_get_parent_data(rdip)) == NULL)
736 735 return (DDI_FAILURE);
737 736
738 737 if (ctlop == DDI_CTLOPS_NREGS) {
739 738 *(int *)result = pdp->par_nreg;
740 739 } else {
741 740 rn = *(int *)arg;
742 741 if (rn >= pdp->par_nreg)
743 742 return (DDI_FAILURE);
744 743 *(off_t *)result = (off_t)pdp->par_reg[rn].regspec_size;
745 744 }
746 745 return (DDI_SUCCESS);
747 746
748 747 case DDI_CTLOPS_ATTACH:
749 748 case DDI_CTLOPS_DETACH:
750 749 case DDI_CTLOPS_PEEK:
751 750 case DDI_CTLOPS_POKE:
752 751 return (DDI_FAILURE);
753 752
754 753 default:
755 754 return (ddi_ctlops(dip, rdip, ctlop, arg, result));
756 755 }
757 756 }
758 757
759 758 static struct intrspec *
760 759 isa_get_ispec(dev_info_t *rdip, int inum)
761 760 {
762 761 struct ddi_parent_private_data *pdp = ddi_get_parent_data(rdip);
763 762
764 763 /* Validate the interrupt number */
765 764 if (inum >= pdp->par_nintr)
766 765 return (NULL);
767 766
768 767 /* Get the interrupt structure pointer and return that */
769 768 return ((struct intrspec *)&pdp->par_intr[inum]);
770 769 }
771 770
772 771 static int
773 772 isa_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
774 773 ddi_intr_handle_impl_t *hdlp, void *result)
775 774 {
776 775 struct intrspec *ispec;
777 776 #if defined(__xpv)
778 777 int cons, ttyn;
779 778
780 779 cons = console_hypervisor_dev_type(&ttyn);
781 780 #endif
782 781 if (pseudo_isa)
783 782 return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
784 783
785 784
786 785 /* Process the interrupt operation */
787 786 switch (intr_op) {
788 787 case DDI_INTROP_GETCAP:
789 788 /* First check with pcplusmp */
790 789 if (psm_intr_ops == NULL)
791 790 return (DDI_FAILURE);
792 791
793 792 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_GET_CAP, result)) {
794 793 *(int *)result = 0;
795 794 return (DDI_FAILURE);
796 795 }
797 796 break;
798 797 case DDI_INTROP_SETCAP:
799 798 if (psm_intr_ops == NULL)
800 799 return (DDI_FAILURE);
801 800
802 801 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result))
803 802 return (DDI_FAILURE);
804 803 break;
805 804 case DDI_INTROP_ALLOC:
806 805 ASSERT(hdlp->ih_type == DDI_INTR_TYPE_FIXED);
807 806 return (isa_alloc_intr_fixed(rdip, hdlp, result));
808 807 case DDI_INTROP_FREE:
809 808 ASSERT(hdlp->ih_type == DDI_INTR_TYPE_FIXED);
810 809 return (isa_free_intr_fixed(rdip, hdlp));
811 810 case DDI_INTROP_GETPRI:
812 811 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
813 812 return (DDI_FAILURE);
814 813 *(int *)result = ispec->intrspec_pri;
815 814 break;
816 815 case DDI_INTROP_SETPRI:
817 816 /* Validate the interrupt priority passed to us */
818 817 if (*(int *)result > LOCK_LEVEL)
819 818 return (DDI_FAILURE);
820 819
821 820 /* Ensure that PSM is all initialized and ispec is ok */
822 821 if ((psm_intr_ops == NULL) ||
823 822 ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL))
824 823 return (DDI_FAILURE);
825 824
826 825 /* update the ispec with the new priority */
827 826 ispec->intrspec_pri = *(int *)result;
828 827 break;
829 828 case DDI_INTROP_ADDISR:
830 829 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
831 830 return (DDI_FAILURE);
832 831 ispec->intrspec_func = hdlp->ih_cb_func;
833 832 break;
834 833 case DDI_INTROP_REMISR:
835 834 if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
836 835 return (DDI_FAILURE);
837 836 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
838 837 return (DDI_FAILURE);
839 838 ispec->intrspec_func = (uint_t (*)()) 0;
840 839 break;
841 840 case DDI_INTROP_ENABLE:
842 841 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
843 842 return (DDI_FAILURE);
844 843
845 844 /* Call psmi to translate irq with the dip */
846 845 if (psm_intr_ops == NULL)
847 846 return (DDI_FAILURE);
848 847
849 848 #if defined(__xpv)
850 849 /*
851 850 * if the hypervisor is using an isa serial port for the
852 851 * console, make sure we don't try to use that interrupt as
853 852 * it will cause us to panic when xen_bind_pirq() fails.
854 853 */
855 854 if (cons == CONS_TTY && ispec->intrspec_vec == asy_intrs[ttyn])
856 855 return (DDI_FAILURE);
857 856 #endif
858 857 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
859 858 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR,
860 859 (int *)&hdlp->ih_vector) == PSM_FAILURE)
861 860 return (DDI_FAILURE);
862 861
863 862 /* Add the interrupt handler */
864 863 if (!add_avintr((void *)hdlp, ispec->intrspec_pri,
865 864 hdlp->ih_cb_func, DEVI(rdip)->devi_name, hdlp->ih_vector,
866 865 hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, NULL, rdip))
867 866 return (DDI_FAILURE);
868 867 break;
869 868 case DDI_INTROP_DISABLE:
870 869 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
871 870 return (DDI_FAILURE);
872 871
873 872 /* Call psm_ops() to translate irq with the dip */
874 873 if (psm_intr_ops == NULL)
875 874 return (DDI_FAILURE);
876 875
877 876 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
878 877 (void) (*psm_intr_ops)(rdip, hdlp,
879 878 PSM_INTR_OP_XLATE_VECTOR, (int *)&hdlp->ih_vector);
880 879
881 880 /* Remove the interrupt handler */
882 881 rem_avintr((void *)hdlp, ispec->intrspec_pri,
883 882 hdlp->ih_cb_func, hdlp->ih_vector);
884 883 break;
885 884 case DDI_INTROP_SETMASK:
886 885 if (psm_intr_ops == NULL)
887 886 return (DDI_FAILURE);
888 887
889 888 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_MASK, NULL))
890 889 return (DDI_FAILURE);
891 890 break;
892 891 case DDI_INTROP_CLRMASK:
893 892 if (psm_intr_ops == NULL)
894 893 return (DDI_FAILURE);
895 894
896 895 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_CLEAR_MASK, NULL))
897 896 return (DDI_FAILURE);
898 897 break;
899 898 case DDI_INTROP_GETPENDING:
900 899 if (psm_intr_ops == NULL)
901 900 return (DDI_FAILURE);
902 901
903 902 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_GET_PENDING,
904 903 result)) {
905 904 *(int *)result = 0;
906 905 return (DDI_FAILURE);
907 906 }
908 907 break;
909 908 case DDI_INTROP_NAVAIL:
910 909 case DDI_INTROP_NINTRS:
911 910 *(int *)result = i_ddi_get_intx_nintrs(rdip);
912 911 if (*(int *)result == 0) {
913 912 return (DDI_FAILURE);
914 913 }
915 914 break;
916 915 case DDI_INTROP_SUPPORTED_TYPES:
917 916 *(int *)result = DDI_INTR_TYPE_FIXED; /* Always ... */
918 917 break;
919 918 default:
920 919 return (DDI_FAILURE);
921 920 }
922 921
923 922 return (DDI_SUCCESS);
924 923 }
925 924
926 925 /*
927 926 * Allocate interrupt vector for FIXED (legacy) type.
928 927 */
929 928 static int
930 929 isa_alloc_intr_fixed(dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp,
931 930 void *result)
932 931 {
933 932 struct intrspec *ispec;
934 933 ddi_intr_handle_impl_t info_hdl;
935 934 int ret;
936 935 int free_phdl = 0;
937 936 apic_get_type_t type_info;
938 937
939 938 if (psm_intr_ops == NULL)
940 939 return (DDI_FAILURE);
941 940
942 941 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
943 942 return (DDI_FAILURE);
944 943
945 944 /*
946 945 * If the PSM module is "APIX" then pass the request for it
947 946 * to allocate the vector now.
948 947 */
949 948 bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
950 949 info_hdl.ih_private = &type_info;
951 950 if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
952 951 PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
953 952 if (hdlp->ih_private == NULL) { /* allocate phdl structure */
954 953 free_phdl = 1;
955 954 i_ddi_alloc_intr_phdl(hdlp);
956 955 }
957 956 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
958 957 ret = (*psm_intr_ops)(rdip, hdlp,
959 958 PSM_INTR_OP_ALLOC_VECTORS, result);
960 959 if (free_phdl) { /* free up the phdl structure */
961 960 free_phdl = 0;
962 961 i_ddi_free_intr_phdl(hdlp);
963 962 hdlp->ih_private = NULL;
964 963 }
965 964 } else {
966 965 /*
967 966 * No APIX module; fall back to the old scheme where the
968 967 * interrupt vector is allocated during ddi_enable_intr() call.
969 968 */
970 969 hdlp->ih_pri = ispec->intrspec_pri;
971 970 *(int *)result = hdlp->ih_scratch1;
972 971 ret = DDI_SUCCESS;
973 972 }
974 973
975 974 return (ret);
976 975 }
977 976
978 977 /*
979 978 * Free up interrupt vector for FIXED (legacy) type.
980 979 */
981 980 static int
982 981 isa_free_intr_fixed(dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp)
983 982 {
984 983 struct intrspec *ispec;
985 984 ddi_intr_handle_impl_t info_hdl;
986 985 int ret;
987 986 apic_get_type_t type_info;
988 987
989 988 if (psm_intr_ops == NULL)
990 989 return (DDI_FAILURE);
991 990
992 991 /*
993 992 * If the PSM module is "APIX" then pass the request for it
994 993 * to free up the vector now.
995 994 */
996 995 bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
997 996 info_hdl.ih_private = &type_info;
998 997 if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
999 998 PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
1000 999 if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
1001 1000 return (DDI_FAILURE);
1002 1001 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
1003 1002 ret = (*psm_intr_ops)(rdip, hdlp,
1004 1003 PSM_INTR_OP_FREE_VECTORS, NULL);
1005 1004 } else {
1006 1005 /*
1007 1006 * No APIX module; fall back to the old scheme where
1008 1007 * the interrupt vector was already freed during
1009 1008 * ddi_disable_intr() call.
1010 1009 */
1011 1010 ret = DDI_SUCCESS;
1012 1011 }
1013 1012
1014 1013 return (ret);
1015 1014 }
1016 1015
1017 1016 static void
1018 1017 isa_vendor(uint32_t id, char *vendor)
1019 1018 {
1020 1019 vendor[0] = '@' + ((id >> 26) & 0x1f);
1021 1020 vendor[1] = '@' + ((id >> 21) & 0x1f);
1022 1021 vendor[2] = '@' + ((id >> 16) & 0x1f);
1023 1022 vendor[3] = 0;
1024 1023 }
1025 1024
1026 1025 /*
1027 1026 * Name a child
1028 1027 */
1029 1028 static int
1030 1029 isa_name_child(dev_info_t *child, char *name, int namelen)
1031 1030 {
1032 1031 char vendor[8];
1033 1032 int device;
1034 1033 uint32_t serial;
1035 1034 int func;
1036 1035 int bustype;
1037 1036 uint32_t base;
1038 1037 int proplen;
1039 1038 int pnpisa = 0;
1040 1039 isa_regs_t *isa_regs;
1041 1040
1042 1041 void make_ddi_ppd(dev_info_t *, struct ddi_parent_private_data **);
1043 1042
1044 1043 /*
1045 1044 * older drivers aren't expecting the "standard" device
1046 1045 * node format used by the hardware nodes. these drivers
1047 1046 * only expect their own properties set in their driver.conf
1048 1047 * files. so they tell us not to call them with hardware
1049 1048 * nodes by setting the property "ignore-hardware-nodes".
1050 1049 */
1051 1050 if (old_driver(child))
1052 1051 return (DDI_FAILURE);
1053 1052
1054 1053 /*
1055 1054 * Fill in parent-private data
1056 1055 */
1057 1056 if (ddi_get_parent_data(child) == NULL) {
1058 1057 struct ddi_parent_private_data *pdptr;
1059 1058 make_ddi_ppd(child, &pdptr);
1060 1059 ddi_set_parent_data(child, pdptr);
1061 1060 }
1062 1061
1063 1062 if (ndi_dev_is_persistent_node(child) == 0) {
1064 1063 /*
1065 1064 * For .conf nodes, generate name from parent private data
1066 1065 */
1067 1066 name[0] = '\0';
1068 1067 if (sparc_pd_getnreg(child) > 0) {
1069 1068 (void) snprintf(name, namelen, "%x,%x",
1070 1069 (uint_t)sparc_pd_getreg(child, 0)->regspec_bustype,
1071 1070 (uint_t)sparc_pd_getreg(child, 0)->regspec_addr);
1072 1071 }
1073 1072 return (DDI_SUCCESS);
1074 1073 }
1075 1074
1076 1075 /*
1077 1076 * For hw nodes, look up "reg" property
1078 1077 */
1079 1078 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
1080 1079 (caddr_t)&isa_regs, &proplen) != DDI_PROP_SUCCESS) {
1081 1080 return (DDI_FAILURE);
1082 1081 }
1083 1082
1084 1083 /*
1085 1084 * extract the device identifications
1086 1085 */
1087 1086 pnpisa = isa_regs[0].phys_hi & 0x80000000;
1088 1087 if (pnpisa) {
1089 1088 isa_vendor(isa_regs[0].phys_hi, vendor);
1090 1089 device = isa_regs[0].phys_hi & 0xffff;
1091 1090 serial = isa_regs[0].phys_lo;
1092 1091 func = (isa_regs[0].size >> 24) & 0xff;
1093 1092 if (func != 0)
1094 1093 (void) snprintf(name, namelen, "pnp%s,%04x,%x,%x",
1095 1094 vendor, device, serial, func);
1096 1095 else
1097 1096 (void) snprintf(name, namelen, "pnp%s,%04x,%x",
1098 1097 vendor, device, serial);
1099 1098 } else {
1100 1099 bustype = isa_regs[0].phys_hi;
1101 1100 base = isa_regs[0].phys_lo;
1102 1101 (void) sprintf(name, "%x,%x", bustype, base);
1103 1102 }
1104 1103
1105 1104 /*
1106 1105 * free the memory allocated by ddi_getlongprop().
1107 1106 */
1108 1107 kmem_free(isa_regs, proplen);
1109 1108
1110 1109 return (DDI_SUCCESS);
1111 1110 }
1112 1111
1113 1112 static int
1114 1113 isa_initchild(dev_info_t *child)
1115 1114 {
1116 1115 char name[80];
1117 1116
1118 1117 if (isa_name_child(child, name, 80) != DDI_SUCCESS)
1119 1118 return (DDI_FAILURE);
1120 1119 ddi_set_name_addr(child, name);
1121 1120
1122 1121 if (ndi_dev_is_persistent_node(child) != 0)
1123 1122 return (DDI_SUCCESS);
1124 1123
1125 1124 /*
1126 1125 * This is a .conf node, try merge properties onto a
1127 1126 * hw node with the same name.
1128 1127 */
1129 1128 if (ndi_merge_node(child, isa_name_child) == DDI_SUCCESS) {
1130 1129 /*
1131 1130 * Return failure to remove node
1132 1131 */
1133 1132 impl_ddi_sunbus_removechild(child);
1134 1133 return (DDI_FAILURE);
1135 1134 }
1136 1135 /*
1137 1136 * Cannot merge node, permit pseudo children
1138 1137 */
1139 1138 return (DDI_SUCCESS);
1140 1139 }
1141 1140
1142 1141 /*
1143 1142 * called when ACPI enumeration is not used
1144 1143 */
1145 1144 static void
1146 1145 add_known_used_resources(void)
1147 1146 {
1148 1147 /* needs to be in increasing order */
1149 1148 int intr[] = {0x1, 0x3, 0x4, 0x6, 0x7, 0xc};
1150 1149 int dma[] = {0x2};
1151 1150 int io[] = {0x60, 0x1, 0x64, 0x1, 0x2f8, 0x8, 0x378, 0x8, 0x3f0, 0x10,
1152 1151 0x778, 0x4};
1153 1152 dev_info_t *usedrdip;
1154 1153
1155 1154 usedrdip = ddi_find_devinfo(USED_RESOURCES, -1, 0);
1156 1155
1157 1156 if (usedrdip == NULL) {
1158 1157 (void) ndi_devi_alloc_sleep(ddi_root_node(), USED_RESOURCES,
1159 1158 (pnode_t)DEVI_SID_NODEID, &usedrdip);
1160 1159 }
1161 1160
1162 1161 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
1163 1162 "interrupts", (int *)intr, (int)(sizeof (intr) / sizeof (int)));
1164 1163 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
1165 1164 "io-space", (int *)io, (int)(sizeof (io) / sizeof (int)));
1166 1165 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
1167 1166 "dma-channels", (int *)dma, (int)(sizeof (dma) / sizeof (int)));
1168 1167 (void) ndi_devi_bind_driver(usedrdip, 0);
1169 1168
1170 1169 }
1171 1170
1172 1171 /*
1173 1172 * Return non-zero if UART device exists.
1174 1173 */
1175 1174 static int
1176 1175 uart_exists(ushort_t port)
1177 1176 {
1178 1177 outb(port + COM_SCR, (char)0x5a);
1179 1178 outb(port + COM_ISR, (char)0x00);
1180 1179 return (inb(port + COM_SCR) == (char)0x5a);
1181 1180 }
1182 1181
1183 1182 static void
1184 1183 isa_enumerate(int reprogram)
1185 1184 {
1186 1185 int circ, i;
1187 1186 dev_info_t *xdip;
1188 1187 dev_info_t *isa_dip = ddi_find_devinfo("isa", -1, 0);
1189 1188
1190 1189 struct regspec i8042_regs[] = {
1191 1190 {1, 0x60, 0x1},
1192 1191 {1, 0x64, 0x1}
1193 1192 };
1194 1193 int i8042_intrs[] = {0x1, 0xc};
1195 1194 char *acpi_prop;
1196 1195 int acpi_enum = 1; /* ACPI is default to be on */
1197 1196 #if defined(__xpv)
1198 1197 int cons, ttyn;
1199 1198
1200 1199 cons = console_hypervisor_dev_type(&ttyn);
1201 1200 #endif
1202 1201 if (reprogram || !isa_dip)
1203 1202 return;
1204 1203
1205 1204 bzero(isa_extra_resource, MAX_EXTRA_RESOURCE * sizeof (struct regspec));
1206 1205
1207 1206 ndi_devi_enter(isa_dip, &circ);
1208 1207
1209 1208 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1210 1209 DDI_PROP_DONTPASS, "acpi-enum", &acpi_prop) == DDI_PROP_SUCCESS) {
1211 1210 acpi_enum = strcmp("off", acpi_prop);
1212 1211 ddi_prop_free(acpi_prop);
1213 1212 }
1214 1213
1215 1214 if (acpi_enum) {
1216 1215 if (acpi_isa_device_enum(isa_dip)) {
1217 1216 ndi_devi_exit(isa_dip, circ);
1218 1217 if (isa_resource_setup() != NDI_SUCCESS) {
1219 1218 cmn_err(CE_WARN, "isa nexus: isa "
1220 1219 "resource setup failed");
1221 1220 }
1222 1221
1223 1222 /* serial ports? */
1224 1223 enumerate_BIOS_serial(isa_dip);
1225 1224
1226 1225 /* adjust parallel port size */
1227 1226 adjust_prtsz(isa_dip);
1228 1227
1229 1228 isa_create_ranges_prop(isa_dip);
1230 1229 return;
1231 1230 }
1232 1231 cmn_err(CE_NOTE, "!Solaris did not detect ACPI BIOS");
1233 1232 }
1234 1233 cmn_err(CE_NOTE, "!ACPI is off");
1235 1234
1236 1235 /* serial ports */
1237 1236 for (i = 0; i < min_BIOS_serial; i++) {
1238 1237 ushort_t addr = asy_regs[i].regspec_addr;
1239 1238 if (!uart_exists(addr))
1240 1239 continue;
1241 1240 #if defined(__xpv)
1242 1241 if (cons == CONS_TTY && ttyn == i)
1243 1242 continue;
1244 1243 #endif
1245 1244 ndi_devi_alloc_sleep(isa_dip, "asy",
1246 1245 (pnode_t)DEVI_SID_NODEID, &xdip);
1247 1246 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
1248 1247 "compatible", "PNP0500");
1249 1248 /* This should be gotten from master file: */
1250 1249 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
1251 1250 "model", "Standard PC COM port");
1252 1251 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
1253 1252 "reg", (int *)&asy_regs[i], 3);
1254 1253 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip,
1255 1254 "interrupts", asy_intrs[i]);
1256 1255 (void) ndi_devi_bind_driver(xdip, 0);
1257 1256 /* Adjusting isa_extra here causes a kernel dump later. */
1258 1257 }
1259 1258
1260 1259 /* i8042 node */
1261 1260 ndi_devi_alloc_sleep(isa_dip, "i8042",
1262 1261 (pnode_t)DEVI_SID_NODEID, &xdip);
1263 1262 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
1264 1263 "reg", (int *)i8042_regs, 6);
1265 1264 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
1266 1265 "interrupts", (int *)i8042_intrs, 2);
1267 1266 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
1268 1267 "unit-address", "1,60");
1269 1268 (void) ndi_devi_bind_driver(xdip, 0);
1270 1269
1271 1270 add_known_used_resources();
1272 1271
1273 1272 ndi_devi_exit(isa_dip, circ);
1274 1273
1275 1274 isa_create_ranges_prop(isa_dip);
1276 1275 }
1277 1276
1278 1277 /*
1279 1278 * On some machines, serial port 2 isn't listed in the ACPI table.
1280 1279 * This function goes through the base I/O addresses and makes sure all
1281 1280 * the serial ports there are in the dev_info tree. If any are missing,
1282 1281 * this function will add them.
1283 1282 */
1284 1283
1285 1284 static void
1286 1285 enumerate_BIOS_serial(dev_info_t *isa_dip)
1287 1286 {
1288 1287 int i;
1289 1288 dev_info_t *xdip;
1290 1289 int found;
1291 1290 int ret;
1292 1291 struct regspec *tmpregs;
1293 1292 int tmpregs_len;
1294 1293 #if defined(__xpv)
1295 1294 int cons, ttyn;
1296 1295
1297 1296 cons = console_hypervisor_dev_type(&ttyn);
1298 1297 #endif
1299 1298
1300 1299 /*
1301 1300 * Scan the base I/O addresses of the first four serial ports.
1302 1301 */
1303 1302 for (i = 0; i < num_BIOS_serial; i++) {
1304 1303 ushort_t addr = asy_regs[i].regspec_addr;
1305 1304
1306 1305 /* Look for it in the dev_info tree */
1307 1306 found = 0;
1308 1307 for (xdip = ddi_get_child(isa_dip); xdip != NULL;
1309 1308 xdip = ddi_get_next_sibling(xdip)) {
1310 1309 if (strncmp(ddi_node_name(xdip), "asy", 3) != 0) {
1311 1310 /* skip non asy */
1312 1311 continue;
1313 1312 }
1314 1313
1315 1314 /* Match by addr */
1316 1315 ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, xdip,
1317 1316 DDI_PROP_DONTPASS, "reg", (int **)&tmpregs,
1318 1317 (uint_t *)&tmpregs_len);
1319 1318 if (ret != DDI_PROP_SUCCESS) {
1320 1319 /* error */
1321 1320 continue;
1322 1321 }
1323 1322
1324 1323 if (tmpregs->regspec_addr == addr)
1325 1324 found = 1;
1326 1325
1327 1326 /*
1328 1327 * Free the memory allocated by
1329 1328 * ddi_prop_lookup_int_array().
1330 1329 */
1331 1330 ddi_prop_free(tmpregs);
1332 1331
1333 1332 if (found) {
1334 1333 if (asy_intr_override & 1<<i) {
1335 1334 (void) ndi_prop_update_int(
1336 1335 DDI_DEV_T_NONE, xdip,
1337 1336 "interrupts", asy_intrs[i]);
1338 1337 }
1339 1338
1340 1339 break;
1341 1340 }
1342 1341 }
1343 1342
1344 1343 /* If not found, then add it */
1345 1344 if (!found && uart_exists(addr)) {
1346 1345 ndi_devi_alloc_sleep(isa_dip, "asy",
1347 1346 (pnode_t)DEVI_SID_NODEID, &xdip);
1348 1347 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
1349 1348 "compatible", "PNP0500");
1350 1349 /* This should be gotten from master file: */
1351 1350 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
1352 1351 "model", "Standard PC COM port");
1353 1352 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
1354 1353 "reg", (int *)&asy_regs[i], 3);
1355 1354 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip,
1356 1355 "interrupts", asy_intrs[i]);
1357 1356 (void) ndi_devi_bind_driver(xdip, 0);
1358 1357
1359 1358 ASSERT(isa_extra_count < MAX_EXTRA_RESOURCE);
1360 1359 bcopy(&asy_regs[i],
1361 1360 isa_extra_resource + isa_extra_count,
1362 1361 sizeof (struct regspec));
1363 1362 isa_extra_count++;
1364 1363 }
1365 1364 }
1366 1365
1367 1366 /*
1368 1367 * An asy node may have been attached via ACPI enumeration, or
1369 1368 * directly from this file. Check each serial port to see if it
1370 1369 * is in use by the hypervisor. If it is in use, then remove
1371 1370 * the node from the device tree.
1372 1371 */
1373 1372 #if defined(__xpv)
1374 1373 i = 0;
1375 1374
1376 1375 for (xdip = ddi_get_child(isa_dip); xdip != NULL; ) {
1377 1376 dev_info_t *curdip;
1378 1377
1379 1378 curdip = xdip;
1380 1379 xdip = ddi_get_next_sibling(xdip);
1381 1380
1382 1381 if (strncmp(ddi_node_name(curdip), "asy", 3) != 0)
1383 1382 continue;
1384 1383
1385 1384 if (cons == CONS_TTY && ttyn == i) {
1386 1385 ret = ndi_devi_free(curdip);
1387 1386 if (ret != DDI_SUCCESS) {
1388 1387 cmn_err(CE_WARN,
1389 1388 "could not remove asy%d node", i);
1390 1389 }
1391 1390
1392 1391 cmn_err(CE_NOTE, "!asy%d unavailable, reserved"
1393 1392 " to hypervisor", i);
1394 1393 }
1395 1394
1396 1395 i++;
1397 1396 }
1398 1397 #endif
1399 1398
1400 1399 }
1401 1400
1402 1401 /*
1403 1402 * Some machine comes with an illegal parallel port size of 3
1404 1403 * bytes in ACPI, even parallel port mode is ECP.
1405 1404 */
1406 1405 #define DEFAULT_PRT_SIZE 8
1407 1406 static void
1408 1407 adjust_prtsz(dev_info_t *isa_dip)
1409 1408 {
1410 1409 dev_info_t *cdip;
1411 1410 struct regspec *regs_p, *extreg_p;
1412 1411 int regs_len, nreg, i;
1413 1412 char *name;
1414 1413
1415 1414 for (cdip = ddi_get_child(isa_dip); cdip != NULL;
1416 1415 cdip = ddi_get_next_sibling(cdip)) {
1417 1416 name = ddi_node_name(cdip);
1418 1417 if ((strncmp(name, "lp", 2) != 0) || (strnlen(name, 3) != 2))
1419 1418 continue; /* skip non parallel */
1420 1419
1421 1420 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
1422 1421 DDI_PROP_DONTPASS, "reg", (int **)®s_p,
1423 1422 (uint_t *)®s_len) != DDI_PROP_SUCCESS)
1424 1423 continue;
1425 1424
1426 1425 nreg = regs_len / (sizeof (struct regspec) / sizeof (int));
1427 1426 for (i = 0; i < nreg; i++) {
1428 1427 if (regs_p[i].regspec_size == DEFAULT_PRT_SIZE)
1429 1428 continue;
1430 1429
1431 1430 ASSERT(isa_extra_count < MAX_EXTRA_RESOURCE);
1432 1431 extreg_p = &isa_extra_resource[isa_extra_count++];
1433 1432 extreg_p->regspec_bustype = ISA_ADDR_IO;
1434 1433 extreg_p->regspec_addr = regs_p[i].regspec_addr;
1435 1434 extreg_p->regspec_size = DEFAULT_PRT_SIZE;
1436 1435 }
1437 1436
1438 1437 ddi_prop_free(regs_p);
1439 1438 }
1440 1439 }
↓ open down ↓ |
1191 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX