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