Print this page
acpica-unix2-20130823
PANKOVs restructure
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/i86pc/io/psm/psm_common.c
+++ new/usr/src/uts/i86pc/io/psm/psm_common.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 *
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
23 + * Copyright 2013 PALO, Richard. All rights reserved.
23 24 */
24 25
25 26 #include <sys/types.h>
26 27 #include <sys/param.h>
27 28 #include <sys/cmn_err.h>
28 29 #include <sys/promif.h>
29 -#include <sys/acpi/acpi.h>
30 +#include <acpica/include/acpi.h>
30 31 #include <sys/acpica.h>
31 32 #include <sys/sunddi.h>
32 33 #include <sys/ddi.h>
33 34 #include <sys/ddi_impldefs.h>
34 35 #include <sys/pci.h>
35 36 #include <sys/debug.h>
36 37 #include <sys/psm_common.h>
37 38 #include <sys/sunndi.h>
38 39 #include <sys/ksynch.h>
39 40
40 41 /* Global configurables */
41 42
42 43 char *psm_module_name; /* used to store name of psm module */
43 44
44 45 /*
45 46 * acpi_irq_check_elcr: when set elcr will also be consulted for building
46 47 * the reserved irq list. When 0 (false), the existing state of the ELCR
47 48 * is ignored when selecting a vector during IRQ translation, and the ELCR
48 49 * is programmed to the proper setting for the type of bus (level-triggered
49 50 * for PCI, edge-triggered for non-PCI). When non-zero (true), vectors
50 51 * set to edge-mode will not be used when in PIC-mode. The default value
51 52 * is 0 (false). Note that ACPI's SCI vector is always set to conform to
52 53 * ACPI-specification regardless of this.
53 54 *
54 55 */
55 56 int acpi_irq_check_elcr = 0;
56 57
57 58 int psm_verbose = 0;
58 59
59 60 #define PSM_VERBOSE_IRQ(fmt) \
60 61 if (psm_verbose & PSM_VERBOSE_IRQ_FLAG) \
61 62 cmn_err fmt;
62 63
63 64 #define PSM_VERBOSE_POWEROFF(fmt) \
64 65 if (psm_verbose & PSM_VERBOSE_POWEROFF_FLAG || \
65 66 psm_verbose & PSM_VERBOSE_POWEROFF_PAUSE_FLAG) \
66 67 prom_printf fmt;
67 68
68 69 #define PSM_VERBOSE_POWEROFF_PAUSE(fmt) \
69 70 if (psm_verbose & PSM_VERBOSE_POWEROFF_FLAG || \
70 71 psm_verbose & PSM_VERBOSE_POWEROFF_PAUSE_FLAG) {\
71 72 prom_printf fmt; \
72 73 if (psm_verbose & PSM_VERBOSE_POWEROFF_PAUSE_FLAG) \
73 74 (void) goany(); \
74 75 }
75 76
76 77
77 78 /* Local storage */
78 79 static ACPI_HANDLE acpi_sbobj = NULL;
79 80 static kmutex_t acpi_irq_cache_mutex;
80 81
81 82 /*
82 83 * irq_cache_table is a list that serves a two-key cache. It is used
83 84 * as a pci busid/devid/ipin <-> irq cache and also as a acpi
84 85 * interrupt lnk <-> irq cache.
85 86 */
86 87 static irq_cache_t *irq_cache_table;
87 88
88 89 #define IRQ_CACHE_INITLEN 20
89 90 static int irq_cache_len = 0;
90 91 static int irq_cache_valid = 0;
91 92
92 93 static int acpi_get_gsiv(dev_info_t *dip, ACPI_HANDLE pciobj, int devno,
93 94 int ipin, int *pci_irqp, iflag_t *iflagp, acpi_psm_lnk_t *acpipsmlnkp);
94 95
95 96 static int acpi_eval_lnk(dev_info_t *dip, char *lnkname,
96 97 int *pci_irqp, iflag_t *intr_flagp, acpi_psm_lnk_t *acpipsmlnkp);
97 98
98 99 static int acpi_get_irq_lnk_cache_ent(ACPI_HANDLE lnkobj, int *pci_irqp,
99 100 iflag_t *intr_flagp);
100 101
101 102 extern int goany(void);
102 103
103 104
104 105 #define NEXT_PRT_ITEM(p) \
105 106 (void *)(((char *)(p)) + (p)->Length)
106 107
107 108 static int
108 109 acpi_get_gsiv(dev_info_t *dip, ACPI_HANDLE pciobj, int devno, int ipin,
109 110 int *pci_irqp, iflag_t *intr_flagp, acpi_psm_lnk_t *acpipsmlnkp)
110 111 {
111 112 ACPI_BUFFER rb;
112 113 ACPI_PCI_ROUTING_TABLE *prtp;
113 114 int status;
114 115 int dev_adr;
115 116
116 117 /*
117 118 * Get the IRQ routing table
118 119 */
119 120 rb.Pointer = NULL;
120 121 rb.Length = ACPI_ALLOCATE_BUFFER;
121 122 if (AcpiGetIrqRoutingTable(pciobj, &rb) != AE_OK) {
122 123 return (ACPI_PSM_FAILURE);
123 124 }
124 125
125 126 status = ACPI_PSM_FAILURE;
126 127 dev_adr = (devno << 16 | 0xffff);
127 128 for (prtp = rb.Pointer; prtp->Length != 0; prtp = NEXT_PRT_ITEM(prtp)) {
128 129 /* look until a matching dev/pin is found */
129 130 if (dev_adr != prtp->Address || ipin != prtp->Pin)
130 131 continue;
131 132
132 133 /* NULL Source name means index is GSIV */
133 134 if (*prtp->Source == 0) {
134 135 intr_flagp->intr_el = INTR_EL_LEVEL;
135 136 intr_flagp->intr_po = INTR_PO_ACTIVE_LOW;
136 137 ASSERT(pci_irqp != NULL);
137 138 *pci_irqp = prtp->SourceIndex;
138 139 status = ACPI_PSM_SUCCESS;
139 140 } else
140 141 status = acpi_eval_lnk(dip, prtp->Source, pci_irqp,
141 142 intr_flagp, acpipsmlnkp);
142 143
143 144 break;
144 145
145 146 }
146 147
147 148 AcpiOsFree(rb.Pointer);
148 149 return (status);
149 150 }
150 151
151 152 /*
152 153 *
153 154 * If the interrupt link device is already configured,
154 155 * stores polarity and sensitivity in the structure pointed to by
155 156 * intr_flagp, and irqno in the value pointed to by pci_irqp.
156 157 *
157 158 * Returns:
158 159 * ACPI_PSM_SUCCESS if the interrupt link device is already configured.
159 160 * ACPI_PSM_PARTIAL if configuration is needed.
160 161 * ACPI_PSM_FAILURE in case of error.
161 162 *
162 163 * When two devices share the same interrupt link device, and the
163 164 * link device is already configured (i.e. found in the irq cache)
164 165 * we need to use the already configured irq instead of reconfiguring
165 166 * the link device.
166 167 */
167 168 static int
168 169 acpi_eval_lnk(dev_info_t *dip, char *lnkname, int *pci_irqp,
169 170 iflag_t *intr_flagp, acpi_psm_lnk_t *acpipsmlnkp)
170 171 {
171 172 ACPI_HANDLE tmpobj;
172 173 ACPI_HANDLE lnkobj;
173 174 int status;
174 175
175 176 /*
176 177 * Convert the passed-in link device name to a handle
177 178 */
178 179 if (AcpiGetHandle(NULL, lnkname, &lnkobj) != AE_OK) {
179 180 return (ACPI_PSM_FAILURE);
180 181 }
181 182
182 183 /*
183 184 * Assume that the link device is invalid if no _CRS method
184 185 * exists, since _CRS method is a required method
185 186 */
186 187 if (AcpiGetHandle(lnkobj, "_CRS", &tmpobj) != AE_OK) {
187 188 return (ACPI_PSM_FAILURE);
188 189 }
189 190
190 191 ASSERT(acpipsmlnkp != NULL);
191 192 acpipsmlnkp->lnkobj = lnkobj;
192 193 if ((acpi_get_irq_lnk_cache_ent(lnkobj, pci_irqp, intr_flagp)) ==
193 194 ACPI_PSM_SUCCESS) {
194 195 PSM_VERBOSE_IRQ((CE_CONT, "!psm: link object found from cache "
195 196 " for device %s, instance #%d, irq no %d\n",
196 197 ddi_get_name(dip), ddi_get_instance(dip), *pci_irqp));
197 198 return (ACPI_PSM_SUCCESS);
198 199 } else {
199 200 if (acpica_eval_int(lnkobj, "_STA", &status) == AE_OK) {
200 201 acpipsmlnkp->device_status = (uchar_t)status;
201 202 }
202 203
203 204 return (ACPI_PSM_PARTIAL);
204 205 }
205 206 }
206 207
207 208 int
208 209 acpi_psm_init(char *module_name, int verbose_flags)
209 210 {
210 211 psm_module_name = module_name;
211 212
212 213 psm_verbose = verbose_flags;
213 214
214 215 if (AcpiGetHandle(NULL, "\\_SB", &acpi_sbobj) != AE_OK) {
215 216 cmn_err(CE_WARN, "!psm: get _SB failed");
216 217 return (ACPI_PSM_FAILURE);
217 218 }
218 219
219 220 mutex_init(&acpi_irq_cache_mutex, NULL, MUTEX_DEFAULT, NULL);
220 221
221 222 return (ACPI_PSM_SUCCESS);
222 223
223 224 }
224 225
225 226 /*
226 227 * Return bus/dev/fn for PCI dip (note: not the parent "pci" node).
227 228 */
228 229
229 230 int
230 231 get_bdf(dev_info_t *dip, int *bus, int *device, int *func)
231 232 {
232 233 pci_regspec_t *pci_rp;
233 234 int len;
234 235
235 236 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
236 237 "reg", (int **)&pci_rp, (uint_t *)&len) != DDI_SUCCESS)
237 238 return (-1);
238 239
239 240 if (len < (sizeof (pci_regspec_t) / sizeof (int))) {
240 241 ddi_prop_free(pci_rp);
241 242 return (-1);
242 243 }
243 244 if (bus != NULL)
244 245 *bus = (int)PCI_REG_BUS_G(pci_rp->pci_phys_hi);
245 246 if (device != NULL)
246 247 *device = (int)PCI_REG_DEV_G(pci_rp->pci_phys_hi);
247 248 if (func != NULL)
248 249 *func = (int)PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
249 250 ddi_prop_free(pci_rp);
250 251 return (0);
251 252 }
252 253
253 254
254 255 /*
255 256 * Build the reserved ISA irq list, and store it in the table pointed to by
256 257 * reserved_irqs_table. The caller is responsible for allocating this table
257 258 * with a minimum of MAX_ISA_IRQ + 1 entries.
258 259 *
259 260 * The routine looks in the device tree at the subtree rooted at /isa
260 261 * for each of the devices under that node, if an interrupts property
261 262 * is present, its values are used to "reserve" irqs so that later ACPI
262 263 * configuration won't choose those irqs.
263 264 *
264 265 * In addition, if acpi_irq_check_elcr is set, will use ELCR register
265 266 * to identify reserved IRQs.
266 267 */
267 268 void
268 269 build_reserved_irqlist(uchar_t *reserved_irqs_table)
269 270 {
270 271 dev_info_t *isanode = ddi_find_devinfo("isa", -1, 0);
271 272 dev_info_t *isa_child = 0;
272 273 int i;
273 274 uint_t elcrval;
274 275
275 276 /* Initialize the reserved ISA IRQs: */
276 277 for (i = 0; i <= MAX_ISA_IRQ; i++)
277 278 reserved_irqs_table[i] = 0;
278 279
279 280 if (acpi_irq_check_elcr) {
280 281
281 282 elcrval = (inb(ELCR_PORT2) << 8) | (inb(ELCR_PORT1));
282 283 if (ELCR_EDGE(elcrval, 0) && ELCR_EDGE(elcrval, 1) &&
283 284 ELCR_EDGE(elcrval, 2) && ELCR_EDGE(elcrval, 8) &&
284 285 ELCR_EDGE(elcrval, 13)) {
285 286 /* valid ELCR */
286 287 for (i = 0; i <= MAX_ISA_IRQ; i++)
287 288 if (!ELCR_LEVEL(elcrval, i))
288 289 reserved_irqs_table[i] = 1;
289 290 }
290 291 }
291 292
292 293 /* always check the isa devinfo nodes */
293 294
294 295 if (isanode != 0) { /* Found ISA */
295 296 uint_t intcnt; /* Interrupt count */
296 297 int *intrs; /* Interrupt values */
297 298
298 299 /* Load first child: */
299 300 isa_child = ddi_get_child(isanode);
300 301 while (isa_child != 0) { /* Iterate over /isa children */
301 302 /* if child has any interrupts, save them */
302 303 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, isa_child,
303 304 DDI_PROP_DONTPASS, "interrupts", &intrs, &intcnt)
304 305 == DDI_PROP_SUCCESS) {
305 306 /*
306 307 * iterate over child interrupt list, adding
307 308 * them to the reserved irq list
308 309 */
309 310 while (intcnt-- > 0) {
310 311 /*
311 312 * Each value MUST be <= MAX_ISA_IRQ
312 313 */
313 314
314 315 if ((intrs[intcnt] > MAX_ISA_IRQ) ||
315 316 (intrs[intcnt] < 0))
316 317 continue;
317 318
318 319 reserved_irqs_table[intrs[intcnt]] = 1;
319 320 }
320 321 ddi_prop_free(intrs);
321 322 }
322 323 isa_child = ddi_get_next_sibling(isa_child);
323 324 }
324 325 /* The isa node was held by ddi_find_devinfo, so release it */
325 326 ndi_rele_devi(isanode);
326 327 }
327 328
328 329 /*
329 330 * Reserve IRQ14 & IRQ15 for IDE. It shouldn't be hard-coded
330 331 * here but there's no other way to find the irqs for
331 332 * legacy-mode ata (since it's hard-coded in pci-ide also).
332 333 */
333 334 reserved_irqs_table[14] = 1;
334 335 reserved_irqs_table[15] = 1;
335 336 }
336 337
337 338 /*
338 339 * Examine devinfo node to determine if it is a PCI-PCI bridge
339 340 *
340 341 * Returns:
341 342 * 0 if not a bridge or error
342 343 * 1 if a bridge
343 344 */
344 345 static int
345 346 psm_is_pci_bridge(dev_info_t *dip)
346 347 {
347 348 ddi_acc_handle_t cfg_handle;
348 349 int rv = 0;
349 350
350 351 if (pci_config_setup(dip, &cfg_handle) == DDI_SUCCESS) {
351 352 rv = ((pci_config_get8(cfg_handle, PCI_CONF_BASCLASS) ==
352 353 PCI_CLASS_BRIDGE) && (pci_config_get8(cfg_handle,
353 354 PCI_CONF_SUBCLASS) == PCI_BRIDGE_PCI));
354 355 pci_config_teardown(&cfg_handle);
355 356 }
356 357
357 358 return (rv);
358 359 }
359 360
360 361 /*
361 362 * Examines ACPI node for presence of _PRT object
362 363 * Check _STA to make sure node is present and/or enabled
363 364 *
364 365 * Returns:
365 366 * 0 if no _PRT or error
366 367 * 1 if _PRT is present
367 368 */
368 369 static int
369 370 psm_node_has_prt(ACPI_HANDLE *ah)
370 371 {
371 372 ACPI_HANDLE rh;
372 373 int sta;
373 374
374 375 /*
375 376 * Return 0 for "no _PRT" if device does not exist
376 377 * According to ACPI Spec,
377 378 * 1) setting either bit 0 or bit 3 means that device exists.
378 379 * 2) Absence of _STA method means all status bits set.
379 380 */
380 381 if (ACPI_SUCCESS(acpica_eval_int(ah, "_STA", &sta)) &&
381 382 !(sta & (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_FUNCTIONING)))
382 383 return (0);
383 384
384 385 return (AcpiGetHandle(ah, "_PRT", &rh) == AE_OK);
385 386 }
386 387
387 388
388 389 /*
389 390 * Look first for an ACPI PCI bus node matching busid, then for a _PRT on the
390 391 * parent node; then drop into the bridge-chasing code (which will also
391 392 * look for _PRTs on the way up the tree of bridges)
392 393 *
393 394 * Stores polarity and sensitivity in the structure pointed to by
394 395 * intr_flagp, and irqno in the value pointed to by pci_irqp. *
395 396 * Returns:
396 397 * ACPI_PSM_SUCCESS on success.
397 398 * ACPI_PSM_PARTIAL to indicate need to configure the interrupt
398 399 * link device.
399 400 * ACPI_PSM_FAILURE if an error prevented the system from
400 401 * obtaining irq information for dip.
401 402 */
402 403 int
403 404 acpi_translate_pci_irq(dev_info_t *dip, int ipin, int *pci_irqp,
404 405 iflag_t *intr_flagp, acpi_psm_lnk_t *acpipsmlnkp)
405 406 {
406 407 ACPI_HANDLE pciobj;
407 408 int status = AE_ERROR;
408 409 dev_info_t *curdip, *parentdip;
409 410 int curpin, curbus, curdev;
410 411
411 412
412 413 curpin = ipin;
413 414 curdip = dip;
414 415 while (curdip != ddi_root_node()) {
415 416 parentdip = ddi_get_parent(curdip);
416 417 ASSERT(parentdip != NULL);
417 418
418 419 if (get_bdf(curdip, &curbus, &curdev, NULL) != 0)
419 420 break;
420 421
421 422 status = acpica_get_handle(parentdip, &pciobj);
422 423 if ((status == AE_OK) && psm_node_has_prt(pciobj)) {
423 424 return (acpi_get_gsiv(curdip, pciobj, curdev, curpin,
424 425 pci_irqp, intr_flagp, acpipsmlnkp));
425 426 }
426 427
427 428 /* if we got here, we need to traverse a bridge upwards */
428 429 if (!psm_is_pci_bridge(parentdip))
429 430 break;
430 431
431 432 /*
432 433 * This is the rotating scheme that Compaq is using
433 434 * and documented in the PCI-PCI spec. Also, if the
434 435 * PCI-PCI bridge is behind another PCI-PCI bridge,
435 436 * then it needs to keep ascending until an interrupt
436 437 * entry is found or the top is reached
437 438 */
438 439 curpin = (curdev + curpin) % PCI_INTD;
439 440 curdip = parentdip;
440 441 }
441 442
442 443 /*
443 444 * We should never, ever get here; didn't find a _PRT
444 445 */
445 446 return (ACPI_PSM_FAILURE);
446 447 }
447 448
448 449 /*
449 450 * Sets the irq resource of the lnk object to the requested irq value.
450 451 *
451 452 * Returns ACPI_PSM_SUCCESS on success, ACPI_PSM_FAILURE upon failure.
452 453 */
453 454 int
454 455 acpi_set_irq_resource(acpi_psm_lnk_t *acpipsmlnkp, int irq)
455 456 {
456 457 ACPI_BUFFER rsb;
457 458 ACPI_RESOURCE *resp;
458 459 ACPI_RESOURCE *srsp;
459 460 ACPI_HANDLE lnkobj;
460 461 int srs_len, status;
461 462
462 463 ASSERT(acpipsmlnkp != NULL);
463 464
464 465 lnkobj = acpipsmlnkp->lnkobj;
465 466
466 467 /*
467 468 * Fetch the possible resources for the link
468 469 */
469 470
470 471 rsb.Pointer = NULL;
471 472 rsb.Length = ACPI_ALLOCATE_BUFFER;
472 473 status = AcpiGetPossibleResources(lnkobj, &rsb);
473 474 if (status != AE_OK) {
474 475 cmn_err(CE_WARN, "!psm: set_irq: _PRS failed");
475 476 return (ACPI_PSM_FAILURE);
476 477 }
477 478
478 479 /*
479 480 * Find an IRQ resource descriptor to use as template
480 481 */
↓ open down ↓ |
441 lines elided |
↑ open up ↑ |
481 482 srsp = NULL;
482 483 for (resp = rsb.Pointer; resp->Type != ACPI_RESOURCE_TYPE_END_TAG;
483 484 resp = ACPI_NEXT_RESOURCE(resp)) {
484 485 if ((resp->Type == ACPI_RESOURCE_TYPE_IRQ) ||
485 486 (resp->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ)) {
486 487 ACPI_RESOURCE *endtag;
487 488 /*
488 489 * Allocate enough room for this resource entry
489 490 * and one end tag following it
490 491 */
491 - srs_len = resp->Length + sizeof (*endtag);
492 + srs_len = resp->Length + ACPI_RS_SIZE_NO_DATA;
492 493 srsp = kmem_zalloc(srs_len, KM_SLEEP);
493 494 bcopy(resp, srsp, resp->Length);
494 495 endtag = ACPI_NEXT_RESOURCE(srsp);
495 496 endtag->Type = ACPI_RESOURCE_TYPE_END_TAG;
496 - endtag->Length = 0;
497 + endtag->Length = ACPI_RS_SIZE_NO_DATA;
497 498 break; /* drop out of the loop */
498 499 }
499 500 }
500 501
501 502 /*
502 503 * We're done with the PRS values, toss 'em lest we forget
503 504 */
504 505 AcpiOsFree(rsb.Pointer);
505 506
506 507 if (srsp == NULL)
507 508 return (ACPI_PSM_FAILURE);
508 509
509 510 /*
510 511 * The Interrupts[] array is always at least one entry
511 512 * long; see the definition of ACPI_RESOURCE.
512 513 */
513 514 switch (srsp->Type) {
514 515 case ACPI_RESOURCE_TYPE_IRQ:
515 516 srsp->Data.Irq.InterruptCount = 1;
516 517 srsp->Data.Irq.Interrupts[0] = (uint8_t)irq;
517 518 break;
518 519 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
519 520 srsp->Data.ExtendedIrq.InterruptCount = 1;
520 521 srsp->Data.ExtendedIrq.Interrupts[0] = irq;
521 522 break;
522 523 }
523 524
524 525 rsb.Pointer = srsp;
525 526 rsb.Length = srs_len;
526 527 status = AcpiSetCurrentResources(lnkobj, &rsb);
527 528 kmem_free(srsp, srs_len);
528 529 if (status != AE_OK) {
529 530 cmn_err(CE_WARN, "!psm: set_irq: _SRS failed");
530 531 return (ACPI_PSM_FAILURE);
531 532 }
532 533
533 534 if (acpica_eval_int(lnkobj, "_STA", &status) == AE_OK) {
534 535 acpipsmlnkp->device_status = (uchar_t)status;
535 536 return (ACPI_PSM_SUCCESS);
536 537 } else
537 538 return (ACPI_PSM_FAILURE);
538 539 }
539 540
540 541
541 542 /*
542 543 *
543 544 */
544 545 static int
545 546 psm_acpi_edgelevel(UINT32 el)
546 547 {
547 548 switch (el) {
548 549 case ACPI_EDGE_SENSITIVE:
549 550 return (INTR_EL_EDGE);
550 551 case ACPI_LEVEL_SENSITIVE:
551 552 return (INTR_EL_LEVEL);
552 553 default:
553 554 /* el is a single bit; should never reach here */
554 555 return (INTR_EL_CONFORM);
555 556 }
556 557 }
557 558
558 559
559 560 /*
560 561 *
561 562 */
562 563 static int
563 564 psm_acpi_po(UINT32 po)
564 565 {
565 566 switch (po) {
566 567 case ACPI_ACTIVE_HIGH:
567 568 return (INTR_PO_ACTIVE_HIGH);
568 569 case ACPI_ACTIVE_LOW:
569 570 return (INTR_PO_ACTIVE_LOW);
570 571 default:
571 572 /* po is a single bit; should never reach here */
572 573 return (INTR_PO_CONFORM);
573 574 }
574 575 }
575 576
576 577
577 578 /*
578 579 * Retrieves the current irq setting for the interrrupt link device.
579 580 *
580 581 * Stores polarity and sensitivity in the structure pointed to by
581 582 * intr_flagp, and irqno in the value pointed to by pci_irqp.
582 583 *
583 584 * Returns ACPI_PSM_SUCCESS on success, ACPI_PSM_FAILURE upon failure.
584 585 */
585 586 int
586 587 acpi_get_current_irq_resource(acpi_psm_lnk_t *acpipsmlnkp, int *pci_irqp,
587 588 iflag_t *intr_flagp)
588 589 {
589 590 ACPI_HANDLE lnkobj;
590 591 ACPI_BUFFER rb;
591 592 ACPI_RESOURCE *rp;
592 593 int irq;
593 594 int status = ACPI_PSM_FAILURE;
594 595
595 596 ASSERT(acpipsmlnkp != NULL);
596 597 lnkobj = acpipsmlnkp->lnkobj;
597 598
598 599 if (!(acpipsmlnkp->device_status & STA_PRESENT) ||
599 600 !(acpipsmlnkp->device_status & STA_ENABLE)) {
600 601 PSM_VERBOSE_IRQ((CE_WARN, "!psm: crs device either not "
601 602 "present or disabled, status 0x%x",
602 603 acpipsmlnkp->device_status));
603 604 return (ACPI_PSM_FAILURE);
604 605 }
605 606
606 607 rb.Pointer = NULL;
607 608 rb.Length = ACPI_ALLOCATE_BUFFER;
608 609 if (AcpiGetCurrentResources(lnkobj, &rb) != AE_OK) {
609 610 PSM_VERBOSE_IRQ((CE_WARN, "!psm: no crs object found or"
610 611 " evaluation failed"));
611 612 return (ACPI_PSM_FAILURE);
612 613 }
613 614
614 615 irq = -1;
615 616 for (rp = rb.Pointer; rp->Type != ACPI_RESOURCE_TYPE_END_TAG;
616 617 rp = ACPI_NEXT_RESOURCE(rp)) {
617 618 if (rp->Type == ACPI_RESOURCE_TYPE_IRQ) {
618 619 if (irq > 0) {
619 620 PSM_VERBOSE_IRQ((CE_WARN, "!psm: multiple IRQ"
620 621 " from _CRS "));
621 622 status = ACPI_PSM_FAILURE;
622 623 break;
623 624 }
624 625
625 626 if (rp->Data.Irq.InterruptCount != 1) {
626 627 PSM_VERBOSE_IRQ((CE_WARN, "!psm: <>1 interrupt"
627 628 " from _CRS "));
628 629 status = ACPI_PSM_FAILURE;
629 630 break;
630 631 }
631 632
632 633 intr_flagp->intr_el = psm_acpi_edgelevel(
633 634 rp->Data.Irq.Triggering);
634 635 intr_flagp->intr_po = psm_acpi_po(
635 636 rp->Data.Irq.Polarity);
636 637 irq = rp->Data.Irq.Interrupts[0];
637 638 status = ACPI_PSM_SUCCESS;
638 639 } else if (rp->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
639 640 if (irq > 0) {
640 641 PSM_VERBOSE_IRQ((CE_WARN, "!psm: multiple IRQ"
641 642 " from _CRS "));
642 643 status = ACPI_PSM_FAILURE;
643 644 break;
644 645 }
645 646
646 647 if (rp->Data.ExtendedIrq.InterruptCount != 1) {
647 648 PSM_VERBOSE_IRQ((CE_WARN, "!psm: <>1 interrupt"
648 649 " from _CRS "));
649 650 status = ACPI_PSM_FAILURE;
650 651 break;
651 652 }
652 653
653 654 intr_flagp->intr_el = psm_acpi_edgelevel(
654 655 rp->Data.ExtendedIrq.Triggering);
655 656 intr_flagp->intr_po = psm_acpi_po(
656 657 rp->Data.ExtendedIrq.Polarity);
657 658 irq = rp->Data.ExtendedIrq.Interrupts[0];
658 659 status = ACPI_PSM_SUCCESS;
659 660 }
660 661 }
661 662
662 663 AcpiOsFree(rb.Pointer);
663 664 if (status == ACPI_PSM_SUCCESS) {
664 665 *pci_irqp = irq;
665 666 }
666 667
667 668 return (status);
668 669 }
669 670
670 671 /*
671 672 * Searches for the given IRQ in the irqlist passed in.
672 673 *
673 674 * If multiple matches exist, this returns true on the first match.
674 675 * Returns the interrupt flags, if a match was found, in `intr_flagp' if
675 676 * it's passed in non-NULL
676 677 */
677 678 int
678 679 acpi_irqlist_find_irq(acpi_irqlist_t *irqlistp, int irq, iflag_t *intr_flagp)
679 680 {
680 681 int found = 0;
681 682 int i;
682 683
683 684 while (irqlistp != NULL && !found) {
684 685 for (i = 0; i < irqlistp->num_irqs; i++) {
685 686 if (irqlistp->irqs[i] == irq) {
686 687 if (intr_flagp)
687 688 *intr_flagp = irqlistp->intr_flags;
688 689 found = 1;
689 690 break; /* out of for() */
690 691 }
691 692 }
692 693 }
693 694
694 695 return (found ? ACPI_PSM_SUCCESS : ACPI_PSM_FAILURE);
695 696 }
696 697
697 698 /*
698 699 * Frees the irqlist allocated by acpi_get_possible_irq_resource.
699 700 * It takes a count of number of entries in the list.
700 701 */
701 702 void
702 703 acpi_free_irqlist(acpi_irqlist_t *irqlistp)
703 704 {
704 705 acpi_irqlist_t *freednode;
705 706
706 707 while (irqlistp != NULL) {
707 708 /* Free the irq list */
708 709 kmem_free(irqlistp->irqs, irqlistp->num_irqs *
709 710 sizeof (int32_t));
710 711
711 712 freednode = irqlistp;
712 713 irqlistp = irqlistp->next;
713 714 kmem_free(freednode, sizeof (acpi_irqlist_t));
714 715 }
715 716 }
716 717
717 718 /*
718 719 * Creates a new entry in the given irqlist with the information passed in.
719 720 */
720 721 static void
721 722 acpi_add_irqlist_entry(acpi_irqlist_t **irqlistp, uint32_t *irqlist,
722 723 int irqlist_len, iflag_t *intr_flagp)
723 724 {
724 725 acpi_irqlist_t *newent;
725 726
726 727 ASSERT(irqlist != NULL);
727 728 ASSERT(intr_flagp != NULL);
728 729
729 730 newent = kmem_alloc(sizeof (acpi_irqlist_t), KM_SLEEP);
730 731 newent->intr_flags = *intr_flagp;
731 732 newent->irqs = irqlist;
732 733 newent->num_irqs = irqlist_len;
733 734 newent->next = *irqlistp;
734 735
735 736 *irqlistp = newent;
736 737 }
737 738
738 739
739 740 /*
740 741 * Retrieves a list of possible interrupt settings for the interrupt link
741 742 * device.
742 743 *
743 744 * Stores polarity and sensitivity in the structure pointed to by intr_flagp.
744 745 * Updates value pointed to by irqlistp with the address of a table it
745 746 * allocates. where interrupt numbers are stored. Stores the number of entries
746 747 * in this table in the value pointed to by num_entriesp;
747 748 *
748 749 * Each element in this table is of type int32_t. The table should be later
749 750 * freed by caller via acpi_free_irq_list().
750 751 *
751 752 * Returns ACPI_PSM_SUCCESS on success and ACPI_PSM_FAILURE upon failure
752 753 */
753 754 int
754 755 acpi_get_possible_irq_resources(acpi_psm_lnk_t *acpipsmlnkp,
755 756 acpi_irqlist_t **irqlistp)
756 757 {
757 758 ACPI_HANDLE lnkobj;
758 759 ACPI_BUFFER rsb;
759 760 ACPI_RESOURCE *resp;
760 761 int status;
761 762
762 763 int i, el, po, irqlist_len;
763 764 uint32_t *irqlist;
764 765 void *tmplist;
765 766 iflag_t intr_flags;
766 767
767 768 ASSERT(acpipsmlnkp != NULL);
768 769 lnkobj = acpipsmlnkp->lnkobj;
769 770
770 771 rsb.Pointer = NULL;
771 772 rsb.Length = ACPI_ALLOCATE_BUFFER;
772 773 status = AcpiGetPossibleResources(lnkobj, &rsb);
773 774 if (status != AE_OK) {
774 775 cmn_err(CE_WARN, "!psm: get_irq: _PRS failed");
775 776 return (ACPI_PSM_FAILURE);
776 777 }
777 778
778 779 /*
779 780 * Scan the resources looking for an interrupt resource
780 781 */
781 782 *irqlistp = 0;
782 783 for (resp = rsb.Pointer; resp->Type != ACPI_RESOURCE_TYPE_END_TAG;
783 784 resp = ACPI_NEXT_RESOURCE(resp)) {
784 785 switch (resp->Type) {
785 786 case ACPI_RESOURCE_TYPE_IRQ:
786 787 irqlist_len = resp->Data.Irq.InterruptCount;
787 788 tmplist = resp->Data.Irq.Interrupts;
788 789 el = resp->Data.Irq.Triggering;
789 790 po = resp->Data.Irq.Polarity;
790 791 break;
791 792 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
792 793 irqlist_len = resp->Data.ExtendedIrq.InterruptCount;
793 794 tmplist = resp->Data.ExtendedIrq.Interrupts;
794 795 el = resp->Data.ExtendedIrq.Triggering;
795 796 po = resp->Data.ExtendedIrq.Polarity;
796 797 break;
797 798 default:
798 799 continue;
799 800 }
800 801
801 802 if (resp->Type != ACPI_RESOURCE_TYPE_IRQ &&
802 803 resp->Type != ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
803 804 cmn_err(CE_WARN, "!psm: get_irq: no IRQ resource");
804 805 return (ACPI_PSM_FAILURE);
805 806 }
806 807
807 808 /* NEEDSWORK: move this into add_irqlist_entry someday */
808 809 irqlist = kmem_zalloc(irqlist_len * sizeof (*irqlist),
809 810 KM_SLEEP);
810 811 for (i = 0; i < irqlist_len; i++)
811 812 if (resp->Type == ACPI_RESOURCE_TYPE_IRQ)
812 813 irqlist[i] = ((uint8_t *)tmplist)[i];
813 814 else
814 815 irqlist[i] = ((uint32_t *)tmplist)[i];
815 816 intr_flags.intr_el = psm_acpi_edgelevel(el);
816 817 intr_flags.intr_po = psm_acpi_po(po);
817 818 acpi_add_irqlist_entry(irqlistp, irqlist, irqlist_len,
818 819 &intr_flags);
819 820 }
820 821
821 822 AcpiOsFree(rsb.Pointer);
822 823 return (irqlistp == NULL ? ACPI_PSM_FAILURE : ACPI_PSM_SUCCESS);
823 824 }
824 825
825 826 /*
826 827 * Adds a new cache entry to the irq cache which maps an irq and
827 828 * its attributes to PCI bus/dev/ipin and optionally to its associated ACPI
828 829 * interrupt link device object.
829 830 */
830 831 void
831 832 acpi_new_irq_cache_ent(int bus, int dev, int ipin, int pci_irq,
832 833 iflag_t *intr_flagp, acpi_psm_lnk_t *acpipsmlnkp)
833 834 {
834 835 int newsize;
835 836 irq_cache_t *new_arr, *ep;
836 837
837 838 mutex_enter(&acpi_irq_cache_mutex);
838 839 if (irq_cache_valid >= irq_cache_len) {
839 840 /* initially, or re-, allocate array */
840 841
841 842 newsize = (irq_cache_len ?
842 843 irq_cache_len * 2 : IRQ_CACHE_INITLEN);
843 844 new_arr = kmem_zalloc(newsize * sizeof (irq_cache_t), KM_SLEEP);
844 845 if (irq_cache_len != 0) {
845 846 /* realloc: copy data, free old */
846 847 bcopy(irq_cache_table, new_arr,
847 848 irq_cache_len * sizeof (irq_cache_t));
848 849 kmem_free(irq_cache_table,
849 850 irq_cache_len * sizeof (irq_cache_t));
850 851 }
851 852 irq_cache_len = newsize;
852 853 irq_cache_table = new_arr;
853 854 }
854 855 ep = &irq_cache_table[irq_cache_valid++];
855 856 ep->bus = (uchar_t)bus;
856 857 ep->dev = (uchar_t)dev;
857 858 ep->ipin = (uchar_t)ipin;
858 859 ep->flags = *intr_flagp;
859 860 ep->irq = (uchar_t)pci_irq;
860 861 ASSERT(acpipsmlnkp != NULL);
861 862 ep->lnkobj = acpipsmlnkp->lnkobj;
862 863 mutex_exit(&acpi_irq_cache_mutex);
863 864 }
864 865
865 866
866 867 /*
867 868 * Searches the irq caches for the given bus/dev/ipin.
868 869 *
869 870 * If info is found, stores polarity and sensitivity in the structure
870 871 * pointed to by intr_flagp, and irqno in the value pointed to by pci_irqp,
871 872 * and returns ACPI_PSM_SUCCESS.
872 873 * Otherwise, ACPI_PSM_FAILURE is returned.
873 874 */
874 875 int
875 876 acpi_get_irq_cache_ent(uchar_t bus, uchar_t dev, int ipin,
876 877 int *pci_irqp, iflag_t *intr_flagp)
877 878 {
878 879
879 880 irq_cache_t *irqcachep;
880 881 int i;
881 882 int ret = ACPI_PSM_FAILURE;
882 883
883 884 mutex_enter(&acpi_irq_cache_mutex);
884 885 for (irqcachep = irq_cache_table, i = 0; i < irq_cache_valid;
885 886 irqcachep++, i++)
886 887 if ((irqcachep->bus == bus) &&
887 888 (irqcachep->dev == dev) &&
888 889 (irqcachep->ipin == ipin)) {
889 890 ASSERT(pci_irqp != NULL && intr_flagp != NULL);
890 891 *pci_irqp = irqcachep->irq;
891 892 *intr_flagp = irqcachep->flags;
892 893 ret = ACPI_PSM_SUCCESS;
893 894 break;
894 895 }
895 896
896 897 mutex_exit(&acpi_irq_cache_mutex);
897 898 return (ret);
898 899 }
899 900
900 901 /*
901 902 * Searches the irq caches for the given interrupt lnk device object.
902 903 *
903 904 * If info is found, stores polarity and sensitivity in the structure
904 905 * pointed to by intr_flagp, and irqno in the value pointed to by pci_irqp,
905 906 * and returns ACPI_PSM_SUCCESS.
906 907 * Otherwise, ACPI_PSM_FAILURE is returned.
907 908 */
908 909 int
909 910 acpi_get_irq_lnk_cache_ent(ACPI_HANDLE lnkobj, int *pci_irqp,
910 911 iflag_t *intr_flagp)
911 912 {
912 913
913 914 irq_cache_t *irqcachep;
914 915 int i;
915 916 int ret = ACPI_PSM_FAILURE;
916 917
917 918 if (lnkobj == NULL)
918 919 return (ACPI_PSM_FAILURE);
919 920
920 921 mutex_enter(&acpi_irq_cache_mutex);
921 922 for (irqcachep = irq_cache_table, i = 0; i < irq_cache_valid;
922 923 irqcachep++, i++)
923 924 if (irqcachep->lnkobj == lnkobj) {
924 925 ASSERT(pci_irqp != NULL);
925 926 *pci_irqp = irqcachep->irq;
926 927 ASSERT(intr_flagp != NULL);
927 928 *intr_flagp = irqcachep->flags;
928 929 ret = ACPI_PSM_SUCCESS;
929 930 break;
930 931 }
931 932 mutex_exit(&acpi_irq_cache_mutex);
932 933 return (ret);
933 934 }
934 935
935 936 /*
936 937 * Walk the irq_cache_table and re-configure the link device to
937 938 * the saved state.
938 939 */
939 940 void
940 941 acpi_restore_link_devices(void)
941 942 {
942 943 irq_cache_t *irqcachep;
943 944 acpi_psm_lnk_t psmlnk;
944 945 int i, status;
945 946
946 947 /* XXX: may not need to hold this mutex */
947 948 mutex_enter(&acpi_irq_cache_mutex);
948 949 for (irqcachep = irq_cache_table, i = 0; i < irq_cache_valid;
949 950 irqcachep++, i++) {
950 951 if (irqcachep->lnkobj != NULL) {
951 952 /* only field used from psmlnk in set_irq is lnkobj */
952 953 psmlnk.lnkobj = irqcachep->lnkobj;
953 954 status = acpi_set_irq_resource(&psmlnk, irqcachep->irq);
954 955 /* warn if set_irq failed; soldier on */
955 956 if (status != ACPI_PSM_SUCCESS)
956 957 cmn_err(CE_WARN, "Could not restore interrupt "
957 958 "link device for IRQ 0x%x: Devices using "
958 959 "this IRQ may no longer function properly."
959 960 "\n", irqcachep->irq);
960 961 }
961 962 }
962 963 mutex_exit(&acpi_irq_cache_mutex);
963 964 }
964 965
965 966 int
966 967 acpi_poweroff(void)
967 968 {
968 969 extern int acpica_use_safe_delay;
969 970 ACPI_STATUS status;
970 971
971 972 PSM_VERBOSE_POWEROFF(("acpi_poweroff: starting poweroff\n"));
972 973
973 974 acpica_use_safe_delay = 1;
974 975
975 976 status = AcpiEnterSleepStatePrep(5);
976 977 if (status != AE_OK) {
977 978 PSM_VERBOSE_POWEROFF(("acpi_poweroff: failed to prepare for "
978 979 "poweroff, status=0x%x\n", status));
979 980 return (1);
980 981 }
981 982 ACPI_DISABLE_IRQS();
982 983 status = AcpiEnterSleepState(5);
983 984 ACPI_ENABLE_IRQS();
984 985
985 986 /* we should be off; if we get here it's an error */
986 987 PSM_VERBOSE_POWEROFF(("acpi_poweroff: failed to actually power "
987 988 "off, status=0x%x\n", status));
988 989 return (1);
989 990 }
990 991
991 992
992 993 /*
993 994 * psm_set_elcr() sets ELCR bit for specified vector
994 995 */
995 996 void
996 997 psm_set_elcr(int vecno, int val)
997 998 {
998 999 int elcr_port = ELCR_PORT1 + (vecno >> 3);
999 1000 int elcr_bit = 1 << (vecno & 0x07);
1000 1001
1001 1002 ASSERT((vecno >= 0) && (vecno < 16));
1002 1003
1003 1004 if (val) {
1004 1005 /* set bit to force level-triggered mode */
1005 1006 outb(elcr_port, inb(elcr_port) | elcr_bit);
1006 1007 } else {
1007 1008 /* clear bit to force edge-triggered mode */
1008 1009 outb(elcr_port, inb(elcr_port) & ~elcr_bit);
1009 1010 }
1010 1011 }
1011 1012
1012 1013 /*
1013 1014 * psm_get_elcr() returns status of ELCR bit for specific vector
1014 1015 */
1015 1016 int
1016 1017 psm_get_elcr(int vecno)
1017 1018 {
1018 1019 int elcr_port = ELCR_PORT1 + (vecno >> 3);
1019 1020 int elcr_bit = 1 << (vecno & 0x07);
1020 1021
1021 1022 ASSERT((vecno >= 0) && (vecno < 16));
1022 1023
1023 1024 return ((inb(elcr_port) & elcr_bit) ? 1 : 0);
1024 1025 }
↓ open down ↓ |
518 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX