Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/ppm/ppm_subr.c
+++ new/usr/src/uts/common/io/ppm/ppm_subr.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 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * ppm driver subroutines
28 28 */
29 29
30 30 #include <sys/open.h>
31 31 #include <sys/file.h>
32 32 #include <sys/conf.h>
33 33 #include <sys/epm.h>
34 34 #include <sys/sunldi.h>
35 35 #include <sys/ppmvar.h>
36 36 #include <sys/ppmio.h>
37 37 #include <sys/promif.h>
38 38 #include <sys/ddi_impldefs.h>
39 39 #include <sys/ddi.h>
40 40 #include <sys/sunddi.h>
41 41 /*
42 42 * Append address to the device path, if it is set. Routine
43 43 * ddi_pathname does not look for device address if the node is in
44 44 * DS_INITIALIZED state.
45 45 */
46 46 #define PPM_GET_PATHNAME(dip, path) \
47 47 (void) ddi_pathname((dip), (path)); \
48 48 if ((i_ddi_node_state((dip)) < DS_INITIALIZED) && \
49 49 (ddi_get_name_addr((dip)) != NULL)) { \
50 50 (void) strcat((path), "@"); \
51 51 (void) strcat((path), ddi_get_name_addr((dip)));\
52 52 }
53 53
54 54 int ppm_parse_dc(char **, ppm_dc_t *);
55 55 int ppm_match_devs(char *, ppm_db_t *);
56 56 ppm_db_t *ppm_parse_pattern(struct ppm_db **, char *);
57 57 int ppm_count_char(char *, char);
58 58 int ppm_stoi(char *, uint_t *);
59 59 int ppm_convert(char *, uint_t *);
60 60 void ppm_prop_free(struct ppm_cdata **);
61 61
62 62 /*
63 63 * lookup string property from configuration file ppm.conf
64 64 */
65 65 static int
66 66 ppm_get_confdata(struct ppm_cdata **cdp, dev_info_t *dip)
67 67 {
68 68 #ifdef DEBUG
69 69 char *str = "ppm_get_confdata";
70 70 #endif
71 71 struct ppm_cdata *cinfo;
72 72 int err;
73 73
74 74 for (; (cinfo = *cdp) != NULL; cdp++) {
75 75 err = ddi_prop_lookup_string_array(
76 76 DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
77 77 cinfo->name, &cinfo->strings, &cinfo->cnt);
78 78 if (err != DDI_PROP_SUCCESS) {
79 79 PPMD(D_ERROR, ("%s: no %s found, err(%d)\n",
80 80 str, cinfo->name, err))
81 81 break;
82 82 }
83 83 }
84 84 return (err);
85 85 }
86 86
87 87 void
88 88 ppm_prop_free(struct ppm_cdata **cdp)
89 89 {
90 90 if (cdp) {
91 91 for (; *cdp; cdp++) {
92 92 if ((*cdp)->name) {
93 93 kmem_free((*cdp)->name,
94 94 strlen((*cdp)->name) + 1);
95 95 (*cdp)->name = NULL;
96 96 }
97 97 if ((*cdp)->strings) {
98 98 ddi_prop_free((*cdp)->strings);
99 99 (*cdp)->strings = NULL;
100 100 }
101 101 }
102 102 }
103 103 }
104 104
105 105
106 106 /*
107 107 * free ddi prop strings. Under error condition, free ppm_db_t lists as well.
108 108 */
109 109 static int
110 110 ppm_attach_err(struct ppm_cdata **cdp, int err)
111 111 {
112 112 ppm_domain_t *domp;
113 113 ppm_db_t *db, *tmp;
114 114
115 115 ppm_prop_free(cdp);
116 116 if (err != DDI_SUCCESS) {
117 117 for (domp = ppm_domain_p; domp; domp = domp->next) {
118 118 for (db = domp->conflist; (tmp = db) != NULL; ) {
119 119 db = db->next;
120 120 kmem_free(tmp->name, strlen(tmp->name) + 1);
121 121 kmem_free(tmp, sizeof (*tmp));
122 122 }
123 123 domp->conflist = NULL;
124 124 }
125 125 err = DDI_FAILURE;
126 126 }
127 127
128 128 return (err);
129 129 }
130 130
131 131
132 132 ppm_domain_t *
133 133 ppm_lookup_domain(char *dname)
134 134 {
135 135 ppm_domain_t *domp;
136 136
137 137 for (domp = ppm_domain_p; domp; domp = domp->next) {
138 138 if (strcmp(dname, domp->name) == 0)
139 139 break;
140 140 }
141 141 return (domp);
142 142 }
143 143
144 144
145 145 /*
146 146 * for the purpose of optimizing we search for identical dc->path
147 147 * that has been opened per previous visit here. If search results
148 148 * in a hit, copy the device handle, else open the device.
149 149 */
150 150 ppm_dc_t *
151 151 ppm_lookup_hndl(int model, ppm_dc_t *key_dc)
152 152 {
153 153 #ifdef DEBUG
154 154 char *str = "ppm_lookup_hndl";
155 155 #endif
156 156 char *key_path = key_dc->path;
157 157 ppm_domain_t *domp;
158 158 ppm_dc_t *dc;
159 159
160 160 /* search domain by domain.model */
161 161 for (domp = ppm_domain_p; domp; domp = domp->next) {
162 162 if (domp->model == model)
163 163 break;
164 164 }
165 165
166 166 /* lookup hndl from same domain model */
167 167 if (domp && PPM_DOMAIN_UP(domp)) {
168 168 for (dc = domp->dc; dc; dc = dc->next) {
169 169 if ((strcmp(dc->path, key_path) == 0) &&
170 170 (dc->lh != NULL)) {
171 171 PPMD(D_PPMDC, ("%s: Hit(dc_path:%s) from SAME "
172 172 "domain %s.\n", str, key_path, domp->name))
173 173 key_dc->lh = dc->lh;
174 174 return (key_dc);
175 175 }
176 176 }
177 177 }
178 178
179 179 /* otherwise, check other domains */
180 180 for (domp = ppm_domain_p;
181 181 domp && (domp->model != model); domp = domp->next) {
182 182 if (PPM_DOMAIN_UP(domp)) {
183 183 for (dc = domp->dc; dc; dc = dc->next) {
184 184 if ((strcmp(dc->path, key_path) == 0) &&
185 185 (dc->lh != NULL)) {
186 186 PPMD(D_PPMDC, ("%s: Hit(dc_path:%s) "
187 187 "from domain %s\n",
188 188 str, key_path, domp->name))
189 189 key_dc->lh = dc->lh;
190 190 return (key_dc);
191 191 }
192 192 }
193 193 }
194 194 }
195 195
196 196 PPMD(D_PPMDC, ("%s: Miss(dc_path:%s)\n", str, key_path))
197 197 return (NULL);
↓ open down ↓ |
197 lines elided |
↑ open up ↑ |
198 198 }
199 199
200 200
201 201 #define PPM_DOMAIN_PROP "ppm-domains"
202 202 #define PPM_DEV_PROP_SUFFIX "-devices"
203 203 #define PPM_MODEL_PROP_SUFFIX "-model"
204 204 #define PPM_PROPNAME_PROP_SUFFIX "-propname"
205 205 #define PPM_CTRL_PROP_SUFFIX "-control"
206 206
207 207 struct ppm_domit ppm_domit_data[] = {
208 - "SX", PPMD_SX, 0, PPMD_ON,
209 - "CPU", PPMD_CPU, PPMD_LOCK_ALL, PPMD_ON,
210 - "FET", PPMD_FET, PPMD_LOCK_ONE, PPMD_ON,
211 - "PCI", PPMD_PCI, PPMD_LOCK_ONE, PPMD_ON,
212 - "PCI_PROP", PPMD_PCI_PROP, PPMD_LOCK_ONE, PPMD_ON,
213 - "LED", PPMD_LED, 0, PPMD_ON,
214 - "PCIE", PPMD_PCIE, PPMD_LOCK_ONE, PPMD_ON,
215 - NULL
208 + { "SX", PPMD_SX, 0, PPMD_ON },
209 + { "CPU", PPMD_CPU, PPMD_LOCK_ALL, PPMD_ON },
210 + { "FET", PPMD_FET, PPMD_LOCK_ONE, PPMD_ON },
211 + { "PCI", PPMD_PCI, PPMD_LOCK_ONE, PPMD_ON },
212 + { "PCI_PROP", PPMD_PCI_PROP, PPMD_LOCK_ONE, PPMD_ON },
213 + { "LED", PPMD_LED, 0, PPMD_ON },
214 + { "PCIE", PPMD_PCIE, PPMD_LOCK_ONE, PPMD_ON },
215 + { NULL }
216 216 };
217 217
218 218 /*
219 219 * store up platform dependent information provided by ppm.conf file
220 220 * into private data base
221 221 */
222 222 int
223 223 ppm_create_db(dev_info_t *dip)
224 224 {
225 225 #ifdef DEBUG
226 226 char *str = "ppm_create_db";
227 227 #endif
228 228 ppm_domain_t *domp;
229 229 ppm_db_t *db;
230 230 ppm_dc_t *dc;
231 231 struct ppm_cdata domdata; /* hold "ppm-domains" property */
232 232 struct ppm_cdata modeldata; /* hold "domain_xy-model" property */
233 233 struct ppm_cdata propnamedata; /* hold "domain_xy-propname" property */
234 234 struct ppm_cdata devdata; /* hold "domain_xy-devices" property */
235 235 struct ppm_cdata dcdata; /* hold "domain_xy-control" property */
236 236 struct ppm_cdata *cdata[2];
237 237 char **dom_namep, **model_namep, **dev_namep, **dc_namep;
238 238 struct ppm_domit *domit_p;
239 239 int err;
240 240
241 241 /*
242 242 * get "ppm-domains" property
243 243 */
244 244 bzero(&domdata, sizeof (domdata));
245 245 domdata.name = kmem_zalloc(strlen(PPM_DOMAIN_PROP) + 1, KM_SLEEP);
246 246 (void) strcpy(domdata.name, PPM_DOMAIN_PROP);
247 247 cdata[0] = &domdata;
248 248 cdata[1] = NULL;
249 249 if (err = ppm_get_confdata(cdata, dip)) {
250 250 PPMD(D_CREATEDB, ("%s: failed to get prop \"%s\"!\n",
251 251 str, PPM_DOMAIN_PROP))
252 252 return (ppm_attach_err(cdata, err));
253 253 }
254 254
255 255 for (dom_namep = domdata.strings; *dom_namep; dom_namep++) {
256 256 domp = kmem_zalloc(sizeof (*domp), KM_SLEEP);
257 257 domp->name = kmem_zalloc(strlen(*dom_namep) + 1, KM_SLEEP);
258 258 (void) strcpy(domp->name, *dom_namep);
259 259 mutex_init(&domp->lock, NULL, MUTEX_DRIVER, NULL);
260 260 if (ppm_domain_p == NULL)
261 261 ppm_domain_p = domp;
262 262 else {
263 263 domp->next = ppm_domain_p;
264 264 ppm_domain_p = domp;
265 265 }
266 266 }
267 267 ppm_prop_free(cdata);
268 268
269 269 /*
270 270 * more per domain property strings in ppm.conf file tell us
271 271 * what the nature of domain, how to performe domain control, etc.
272 272 * Even the property names of those per domain properties are
273 273 * formed consisting its domain name string.
274 274 * Here we walk through our domain list, and fullfill the details.
275 275 */
276 276 for (domp = ppm_domain_p; domp; domp = domp->next) {
277 277 size_t plen;
278 278
279 279 /*
280 280 * get "domain_xy-model" property
281 281 */
282 282 bzero(&modeldata, sizeof (modeldata));
283 283 plen = strlen(domp->name) + strlen(PPM_MODEL_PROP_SUFFIX) + 1;
284 284 modeldata.name = kmem_zalloc(plen, KM_SLEEP);
285 285 (void) sprintf(modeldata.name, "%s%s",
286 286 domp->name, PPM_MODEL_PROP_SUFFIX);
287 287
288 288 cdata[0] = &modeldata;
289 289 cdata[1] = NULL;
290 290 if (err = ppm_get_confdata(cdata, dip)) {
291 291 PPMD(D_CREATEDB, ("%s: Can't read property %s!\n",
292 292 str, modeldata.name))
293 293 return (ppm_attach_err(cdata, err));
294 294 }
295 295
296 296 model_namep = modeldata.strings;
297 297 for (domit_p = ppm_domit_data; domit_p->name; domit_p++) {
298 298 if (strcmp(domit_p->name, *model_namep) == 0) {
299 299 domp->model = domit_p->model;
300 300 domp->dflags = domit_p->dflags;
301 301 domp->status = domit_p->status;
302 302 break;
303 303 }
304 304 }
305 305 ASSERT(domit_p);
306 306
307 307 ppm_prop_free(cdata);
308 308
309 309
310 310 /* get "domain_xy-propname" property */
311 311 bzero(&propnamedata, sizeof (propnamedata));
312 312 plen = strlen(domp->name) +
313 313 strlen(PPM_PROPNAME_PROP_SUFFIX) + 1;
314 314 propnamedata.name = kmem_zalloc(plen, KM_SLEEP);
315 315 (void) sprintf(propnamedata.name, "%s%s",
316 316 domp->name, PPM_PROPNAME_PROP_SUFFIX);
317 317
318 318 cdata[0] = &propnamedata;
319 319 cdata[1] = NULL;
320 320 if (ppm_get_confdata(cdata, dip) == DDI_PROP_SUCCESS) {
321 321 domp->propname = kmem_zalloc(
322 322 (strlen(*propnamedata.strings) + 1), KM_SLEEP);
323 323 (void) strcpy(domp->propname, *propnamedata.strings);
324 324 PPMD(D_CREATEDB, ("%s: %s has property name: %s\n",
325 325 str, domp->name, domp->propname))
326 326 }
327 327 ppm_prop_free(cdata);
328 328
329 329
330 330 /* get "domain_xy-devices" property */
331 331 bzero(&devdata, sizeof (devdata));
332 332 plen = strlen(domp->name) + strlen(PPM_DEV_PROP_SUFFIX) + 1;
333 333 devdata.name = kmem_zalloc(plen, KM_SLEEP);
334 334 (void) sprintf(devdata.name, "%s%s",
335 335 domp->name, PPM_DEV_PROP_SUFFIX);
336 336
337 337 cdata[0] = &devdata;
338 338 cdata[1] = NULL;
339 339 if (err = ppm_get_confdata(cdata, dip)) {
340 340 PPMD(D_CREATEDB, ("%s: Can't read property %s!\n",
341 341 str, devdata.name))
342 342 return (ppm_attach_err(cdata, err));
343 343 }
344 344
345 345 for (dev_namep = devdata.strings; *dev_namep; dev_namep++) {
346 346 if (!ppm_parse_pattern(&db, *dev_namep))
347 347 return (ppm_attach_err(cdata, err));
348 348 db->next = domp->conflist;
349 349 domp->conflist = db;
350 350 PPMD(D_CREATEDB, ("%s: %s add pattern: %s \n",
351 351 str, devdata.name, db->name))
352 352 }
353 353 PPMD(D_CREATEDB, ("\n"))
354 354 ppm_prop_free(cdata);
355 355
356 356
357 357 /* get "domain_xy-control" property */
358 358 bzero(&dcdata, sizeof (dcdata));
359 359 plen = strlen(domp->name) + strlen(PPM_CTRL_PROP_SUFFIX) + 1;
360 360 dcdata.name = kmem_zalloc(plen, KM_SLEEP);
361 361 (void) sprintf(dcdata.name, "%s%s",
362 362 domp->name, PPM_CTRL_PROP_SUFFIX);
363 363
364 364 cdata[0] = &dcdata;
365 365 cdata[1] = NULL;
366 366 if (ppm_get_confdata(cdata, dip) == DDI_PROP_SUCCESS) {
367 367 for (dc_namep = dcdata.strings; *dc_namep;
368 368 dc_namep++) {
369 369 dc = kmem_zalloc(sizeof (*dc), KM_SLEEP);
370 370 dc->next = domp->dc;
371 371 domp->dc = dc;
372 372 err = ppm_parse_dc(dc_namep, domp->dc);
373 373 if (err != DDI_SUCCESS)
374 374 return (ppm_attach_err(cdata, err));
375 375 }
376 376 }
377 377 ppm_prop_free(cdata);
378 378 #ifdef DEBUG
379 379 dc = domp->dc;
380 380 while (dc) {
381 381 ppm_print_dc(dc);
382 382 dc = dc->next;
383 383 }
384 384 #endif
385 385 }
386 386
387 387 return (DDI_SUCCESS);
388 388 }
389 389
390 390
391 391 /*
392 392 * scan conf devices within each domain for a matching device name
393 393 */
394 394 ppm_domain_t *
395 395 ppm_lookup_dev(dev_info_t *dip)
396 396 {
397 397 char path[MAXNAMELEN];
398 398 ppm_domain_t *domp;
399 399 ppm_db_t *dbp;
400 400 #ifdef __x86
401 401 char *devtype = NULL;
402 402 #endif /* __x86 */
403 403
404 404 PPM_GET_PATHNAME(dip, path);
405 405 for (domp = ppm_domain_p; domp; domp = domp->next) {
406 406 if (PPM_DOMAIN_UP(domp)) {
407 407 for (dbp = domp->conflist; dbp; dbp = dbp->next) {
408 408 /*
409 409 * allow claiming root without knowing
410 410 * its full name
411 411 */
412 412 if (dip == ddi_root_node() &&
413 413 strcmp(dbp->name, "/") == 0)
414 414 return (domp);
415 415
416 416 #ifdef __x86
417 417 /*
418 418 * Special rule to catch all CPU devices on x86.
419 419 */
420 420 if (domp->model == PPMD_CPU &&
421 421 strcmp(dbp->name, "/") == 0 &&
422 422 ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
423 423 DDI_PROP_DONTPASS, "device_type",
424 424 &devtype) == DDI_SUCCESS) {
425 425 if (strcmp(devtype, "cpu") == 0) {
426 426 ddi_prop_free(devtype);
427 427 return (domp);
428 428 } else {
429 429 ddi_prop_free(devtype);
430 430 }
431 431 }
432 432 #endif /* __x86 */
433 433
434 434 if (ppm_match_devs(path, dbp) == 0)
435 435 return (domp);
436 436 }
437 437 }
438 438 }
439 439
440 440 return (NULL);
441 441 }
442 442
443 443
444 444 /*
445 445 * check ppm.conf file domain device pathname syntax, if correct,
446 446 * create device match pattern.
447 447 * return 1 for good, -1 for bad.
448 448 */
449 449 ppm_db_t *
450 450 ppm_parse_pattern(struct ppm_db **dbpp, char *dev_path)
451 451 {
452 452 char path[MAXNAMELEN];
453 453 int wccnt, i;
454 454 int wcpos[2];
455 455 int pos;
456 456 char *cp;
457 457 ppm_db_t *dbp;
458 458
459 459 (void) strcpy(path, dev_path);
460 460 if ((wccnt = ppm_count_char(path, '*')) > 2)
461 461 return (NULL);
462 462
463 463 for (i = 0, cp = path, pos = 0; i < wccnt; i++, cp++, pos++) {
464 464 for (; *cp; cp++, pos++)
465 465 if (*cp == '*')
466 466 break;
467 467 wcpos[i] = pos;
468 468 PPMD(D_CREATEDB, (" wildcard #%d, pos %d\n",
469 469 (i + 1), wcpos[i]))
470 470 }
471 471
472 472 #ifdef DEBUG
473 473 /* first '*', if exists, don't go beyond the string */
474 474 if (wccnt > 0)
475 475 ASSERT(wcpos[0] < strlen(path));
476 476
477 477 /* second '*', if exists, better be the last character */
478 478 if (wccnt == 2)
479 479 ASSERT(wcpos[1] == (strlen(path) - 1));
480 480 #endif
481 481
482 482 /*
483 483 * first '*', if followed by any char, must be immediately
484 484 * followed by '@' and the rest better be bound by
485 485 * ['0-9', 'a-f', A-F'] until ended '0' or second '*''0'.
486 486 */
487 487 if ((wccnt > 0) && (wcpos[0] < (strlen(path) - 1))) {
488 488 cp = path + wcpos[0] + 1;
489 489 if (*cp != '@')
490 490 return (NULL);
491 491
492 492 if (!(((*(++cp) > '0') && (*cp < '9')) ||
493 493 ((*cp > 'a') && (*cp < 'f')) ||
494 494 ((*cp > 'A') && (*cp < 'F'))))
495 495 return (NULL);
496 496 }
497 497
498 498 dbp = kmem_zalloc(sizeof (struct ppm_db), KM_SLEEP);
499 499 dbp->name = kmem_zalloc((strlen(path) + 1), KM_SLEEP);
500 500 (void) strcpy(dbp->name, path);
501 501 dbp->wccnt = wccnt;
502 502 dbp->wcpos[0] = (wccnt > 0) ? wcpos[0] : -1;
503 503 dbp->wcpos[1] = (wccnt == 2) ? wcpos[1] : -1;
504 504
505 505 return (*dbpp = dbp);
506 506 }
507 507
508 508
509 509 /*
510 510 * match given device "path" to domain device pathname
511 511 * pattern dbp->name that contains one or two '*' character(s).
512 512 * Matching policy:
513 513 * 1). If one wildcard terminates match pattern, need exact match
514 514 * up to (but exclude) the wildcard;
515 515 * 2). If one wildcard does not terminate match pattern, it is to
516 516 * match driver name (terminates with '@') and must be followed
517 517 * by exact match of rest of pattern;
518 518 * 3). If two wildcards, first is to match driver name as in 2),
519 519 * second is to match fcnid (terminates with '/' or '\0') and
520 520 * must the last char of pattern.
521 521 *
522 522 * return 0 if match, and
523 523 * non 0 if mismatch
524 524 */
525 525 int
526 526 ppm_match_devs(char *dev_path, ppm_db_t *dbp)
527 527 {
528 528 char path[MAXNAMELEN];
529 529 char *cp; /* points into "path", real device pathname */
530 530 char *np; /* points into "dbp->name", the pattern */
531 531 int len;
532 532
533 533 if (dbp->wccnt == 0)
534 534 return (strcmp(dev_path, dbp->name));
535 535
536 536 (void) strcpy(path, dev_path);
537 537
538 538 /* match upto the first '*' regardless */
539 539 if (strncmp(path, dbp->name, dbp->wcpos[0]) != 0)
540 540 return (-1);
541 541
542 542
543 543 /* "<exact match>*" */
544 544 if (dbp->name[dbp->wcpos[0] + 1] == 0) {
545 545 cp = path + dbp->wcpos[0];
546 546 while (*cp && (*cp++ != '/'))
547 547 ;
548 548 return ((*cp == 0) ? 0 : -1);
549 549 }
550 550
551 551
552 552 /* locate '@' */
553 553 cp = path + dbp->wcpos[0] + 1;
554 554 while (*cp && *cp != '@')
555 555 cp++;
556 556
557 557 np = dbp->name + dbp->wcpos[0] + 1;
558 558
559 559 /* if one wildcard, match the rest in the pattern */
560 560 if (dbp->wccnt == 1)
561 561 return ((strcmp(cp, np) == 0) ? 0 : (-1));
562 562
563 563
564 564 /* must have exact match after first wildcard up to second */
565 565 ASSERT(dbp->wccnt == 2);
566 566 len = dbp->wcpos[1] - dbp->wcpos[0] - 1;
567 567 if (strncmp(cp, np, len) != 0)
568 568 return (-1);
569 569
570 570 /* second wildcard match terminates with '/' or '\0' */
571 571 /* but only termination with '\0' is a successful match */
572 572 cp += len;
573 573 while (*cp && (*cp != '/'))
574 574 cp++;
575 575 return ((*cp == 0) ? 0 : -1);
576 576 }
577 577
578 578
579 579 /*
580 580 * By claiming a device, ppm gets involved in its power change
581 581 * process: handles additional issues prior and/or post its
582 582 * power(9e) call.
583 583 *
584 584 * If 'dip' is a PCI device, this is the time to ask its parent
585 585 * what PCI bus speed it is running.
586 586 *
587 587 * returns 1 (claimed), 0 (not claimed)
588 588 */
589 589 int
590 590 ppm_claim_dev(dev_info_t *dip)
591 591 {
592 592 ppm_domain_t *domp;
593 593 dev_info_t *pdip;
594 594 uint_t pciclk;
595 595 int claimed = -1;
596 596
597 597 domp = ppm_lookup_dev(dip);
598 598 if (!domp)
599 599 claimed = 0;
600 600
601 601 if (domp && PPMD_IS_PCI(domp->model) &&
602 602 ! (domp->dflags & (PPMD_PCI33MHZ | PPMD_PCI66MHZ))) {
603 603 pdip = ddi_get_parent(dip);
604 604 ASSERT(pdip);
605 605 pciclk = ddi_prop_get_int(DDI_DEV_T_ANY, pdip,
606 606 DDI_PROP_DONTPASS, "clock-frequency", -1);
607 607
608 608 switch (pciclk) {
609 609 case 33000000:
610 610 domp->dflags |= PPMD_PCI33MHZ;
611 611 claimed = 1;
612 612 break;
613 613 case 66000000:
614 614 domp->dflags |= PPMD_PCI66MHZ;
615 615 claimed = 1;
616 616 break;
617 617 default:
618 618 claimed = 0;
619 619 break;
620 620 }
621 621 }
622 622
623 623 if (domp && (claimed == -1))
624 624 claimed = 1;
625 625
626 626 #ifdef DEBUG
627 627 if (claimed) {
628 628 char path[MAXNAMELEN];
629 629 PPMD(D_CLAIMDEV, ("ppm_claim_dev: %s into domain %s\n",
630 630 ddi_pathname(dip, path), domp->name))
631 631 }
632 632
633 633 #endif
634 634
635 635 return (claimed);
636 636 }
637 637
638 638 /*
639 639 * add a device to the list of domain's owned devices (if it is not already
640 640 * on the list).
641 641 */
642 642 ppm_owned_t *
643 643 ppm_add_owned(dev_info_t *dip, ppm_domain_t *domp)
644 644 {
645 645 char path[MAXNAMELEN];
646 646 ppm_owned_t *owned, *new_owned;
647 647
648 648 ASSERT(MUTEX_HELD(&domp->lock));
649 649 PPM_GET_PATHNAME(dip, path);
650 650 for (owned = domp->owned; owned; owned = owned->next)
651 651 if (strcmp(path, owned->path) == 0)
652 652 return (owned);
653 653
654 654 new_owned = kmem_zalloc(sizeof (*new_owned), KM_SLEEP);
655 655 new_owned->path = kmem_zalloc(strlen(path) + 1, KM_SLEEP);
656 656 (void) strcpy(new_owned->path, path);
657 657 new_owned->next = domp->owned;
658 658 domp->owned = new_owned;
659 659
660 660 return (domp->owned);
661 661 }
662 662
663 663 /*
664 664 * create/init a new ppm device and link into the domain
665 665 */
666 666 ppm_dev_t *
667 667 ppm_add_dev(dev_info_t *dip, ppm_domain_t *domp)
668 668 {
669 669 char path[MAXNAMELEN];
670 670 ppm_dev_t *new = NULL;
671 671 int cmpt;
672 672 ppm_owned_t *owned;
673 673
674 674 ASSERT(MUTEX_HELD(&domp->lock));
675 675 (void) ddi_pathname(dip, path);
676 676 /*
677 677 * For devs which have exported "pm-components" we want to create
678 678 * a data structure for each component. When a driver chooses not
679 679 * to export the prop we treat its device as having a single
680 680 * component and build a structure for it anyway. All other ppm
681 681 * logic will act as if this device were always up and can thus
682 682 * make correct decisions about it in relation to other devices
683 683 * in its domain.
684 684 */
685 685 for (cmpt = PM_GET_PM_INFO(dip) ? PM_NUMCMPTS(dip) : 1; cmpt--; ) {
686 686 new = kmem_zalloc(sizeof (*new), KM_SLEEP);
687 687 new->path = kmem_zalloc(strlen(path) + 1, KM_SLEEP);
688 688 (void) strcpy(new->path, path);
689 689 new->domp = domp;
690 690 new->dip = dip;
691 691 new->cmpt = cmpt;
692 692 ppm_dev_init(new);
693 693 new->next = domp->devlist;
694 694 domp->devlist = new;
695 695 PPMD(D_ADDDEV,
696 696 ("ppm_add_dev: %s to domain %s: ppm_dev(0x%p)\n",
697 697 new->path, domp->name, (void *)new))
698 698 }
699 699
700 700 ASSERT(new != NULL);
701 701 /*
702 702 * devi_pm_ppm_private should be set only after all
703 703 * ppm_dev s related to all components have been
704 704 * initialized and domain's pwr_cnt is incremented
705 705 * for each of them.
706 706 */
707 707 PPM_SET_PRIVATE(dip, new);
708 708
709 709 /* remember this device forever */
710 710 owned = ppm_add_owned(dip, domp);
711 711
712 712 /*
713 713 * Initializing flag is set for devices which have gone through
714 714 * PPM_PMR_INIT_CHILD ctlop. By this point, these devices have
715 715 * been added to ppm structures and could participate in pm
716 716 * decision making, so clear the initializing flag.
717 717 */
718 718 if (owned->initializing) {
719 719 owned->initializing = 0;
720 720 PPMD(D_ADDDEV, ("ppm_add_dev: cleared initializing flag "
721 721 "for %s@%s\n", PM_NAME(dip),
722 722 (PM_ADDR(dip) == NULL) ? "" : PM_ADDR(dip)))
723 723 }
724 724
725 725 return (new);
726 726 }
727 727
728 728
729 729 /*
730 730 * returns an existing or newly created ppm device reference
731 731 */
732 732 ppm_dev_t *
733 733 ppm_get_dev(dev_info_t *dip, ppm_domain_t *domp)
734 734 {
735 735 ppm_dev_t *pdp;
736 736
737 737 mutex_enter(&domp->lock);
738 738 pdp = PPM_GET_PRIVATE(dip);
739 739 if (pdp == NULL)
740 740 pdp = ppm_add_dev(dip, domp);
741 741 mutex_exit(&domp->lock);
742 742
743 743 return (pdp);
744 744 }
745 745
746 746
747 747 /*
748 748 * scan a domain's device list and remove those with .dip
749 749 * matching the arg *dip; we need to scan the entire list
750 750 * for the case of devices with multiple components
751 751 */
752 752 void
753 753 ppm_rem_dev(dev_info_t *dip)
754 754 {
755 755 ppm_dev_t *pdp, **devpp;
756 756 ppm_domain_t *domp;
757 757
758 758 pdp = PPM_GET_PRIVATE(dip);
759 759 ASSERT(pdp);
760 760 domp = pdp->domp;
761 761 ASSERT(domp);
762 762
763 763 mutex_enter(&domp->lock);
764 764 for (devpp = &domp->devlist; (pdp = *devpp) != NULL; ) {
765 765 if (pdp->dip != dip) {
766 766 devpp = &pdp->next;
767 767 continue;
768 768 }
769 769
770 770 PPMD(D_REMDEV, ("ppm_rem_dev: path \"%s\", ppm_dev 0x%p\n",
771 771 pdp->path, (void *)pdp))
772 772
773 773 PPM_SET_PRIVATE(dip, NULL);
774 774 *devpp = pdp->next;
775 775 ppm_dev_fini(pdp);
776 776 kmem_free(pdp->path, strlen(pdp->path) + 1);
777 777 kmem_free(pdp, sizeof (*pdp));
778 778 }
779 779 mutex_exit(&domp->lock);
780 780 }
781 781
782 782 /*
783 783 * prepare kernel ioctl calls:
784 784 */
785 785 void
786 786 ppm_init_cb(dev_info_t *dip)
787 787 {
788 788 char *str = "ppm_init_cb";
789 789 ppm_domain_t *domp;
790 790 ppm_dc_t *dc;
791 791
792 792 for (domp = ppm_domain_p; domp != NULL; domp = domp->next) {
793 793 for (dc = domp->dc; dc; dc = dc->next) {
794 794 /*
795 795 * Warning: This code is rather confusing.
796 796 *
797 797 * It intends to ensure that ppm_init_lyr() is only
798 798 * called ONCE for a device that may be associated
799 799 * with more than one domain control.
800 800 * So, what it does is first to check to see if
801 801 * there is a handle, and then if not it goes on
802 802 * to call the init_lyr() routine.
803 803 *
804 804 * The non-obvious thing is that the ppm_init_lyr()
805 805 * routine, in addition to opening the device
806 806 * associated with the dc (domain control) in
807 807 * question, has the side-effect of creating the
808 808 * handle for that dc as well.
809 809 */
810 810 if (ppm_lookup_hndl(domp->model, dc) != NULL)
811 811 continue;
812 812
813 813 if (ppm_init_lyr(dc, dip) != DDI_SUCCESS) {
814 814 domp->dflags |= PPMD_OFFLINE;
815 815 cmn_err(CE_WARN, "%s: ppm domain %s will "
816 816 "be offline.", str, domp->name);
817 817 break;
818 818 }
819 819 }
820 820 }
821 821 }
822 822
823 823
824 824 /*
825 825 * ppm_init_lyr - initializing layered ioctl
826 826 * Return:
827 827 * DDI_SUCCESS - succeeded
828 828 * DDI_FAILURE - failed
829 829 *
830 830 */
831 831 int
832 832 ppm_init_lyr(ppm_dc_t *dc, dev_info_t *dip)
833 833 {
834 834 char *str = "ppm_init_lyr";
835 835 int err = 0;
836 836 ldi_ident_t li;
837 837
838 838 ASSERT(dc && dc->path);
839 839
840 840 if (err = ldi_ident_from_dip(dip, &li)) {
841 841 cmn_err(CE_WARN, "%s: get ldi identifier "
842 842 "failed (err=%d)", str, err);
843 843 }
844 844
845 845 err = ldi_open_by_name(dc->path, FWRITE|FREAD, kcred, &(dc->lh), li);
846 846
847 847 (void) ldi_ident_release(li);
848 848
849 849 if (err != 0) {
850 850 cmn_err(CE_WARN, "Failed to open device(%s), rv(%d)",
851 851 dc->path, err);
852 852 return (err);
853 853 }
854 854
855 855 return (DDI_SUCCESS);
856 856 }
857 857
858 858 /*
859 859 * lock, unlock, or trylock for one power mutex
860 860 */
861 861 void
862 862 ppm_lock_one(ppm_dev_t *ppmd, power_req_t *reqp, int *iresp)
863 863 {
864 864 switch (reqp->request_type) {
865 865 case PMR_PPM_LOCK_POWER:
866 866 pm_lock_power_single(ppmd->dip,
867 867 reqp->req.ppm_lock_power_req.circp);
868 868 break;
869 869
870 870 case PMR_PPM_UNLOCK_POWER:
871 871 pm_unlock_power_single(ppmd->dip,
872 872 reqp->req.ppm_unlock_power_req.circ);
873 873 break;
874 874
875 875 case PMR_PPM_TRY_LOCK_POWER:
876 876 *iresp = pm_try_locking_power_single(ppmd->dip,
877 877 reqp->req.ppm_lock_power_req.circp);
878 878 break;
879 879 }
880 880 }
881 881
882 882
883 883 /*
884 884 * lock, unlock, or trylock for all power mutexes within a domain
885 885 */
886 886 void
887 887 ppm_lock_all(ppm_domain_t *domp, power_req_t *reqp, int *iresp)
888 888 {
889 889 /*
890 890 * To simplify the implementation we let all the devices
891 891 * in the domain be represented by a single device (dip).
892 892 * We use the first device in the domain's devlist. This
893 893 * is safe because we return with the domain lock held
894 894 * which prevents the list from changing.
895 895 */
896 896 if (reqp->request_type == PMR_PPM_LOCK_POWER) {
897 897 if (!MUTEX_HELD(&domp->lock))
898 898 mutex_enter(&domp->lock);
899 899 domp->refcnt++;
900 900 ASSERT(domp->devlist != NULL);
901 901 pm_lock_power_single(domp->devlist->dip,
902 902 reqp->req.ppm_lock_power_req.circp);
903 903 /* domain lock remains held */
904 904 return;
905 905 } else if (reqp->request_type == PMR_PPM_UNLOCK_POWER) {
906 906 ASSERT(MUTEX_HELD(&domp->lock));
907 907 ASSERT(domp->devlist != NULL);
908 908 pm_unlock_power_single(domp->devlist->dip,
909 909 reqp->req.ppm_unlock_power_req.circ);
910 910 if (--domp->refcnt == 0)
911 911 mutex_exit(&domp->lock);
912 912 return;
913 913 }
914 914
915 915 ASSERT(reqp->request_type == PMR_PPM_TRY_LOCK_POWER);
916 916 if (!MUTEX_HELD(&domp->lock))
917 917 if (!mutex_tryenter(&domp->lock)) {
918 918 *iresp = 0;
919 919 return;
920 920 }
921 921 *iresp = pm_try_locking_power_single(domp->devlist->dip,
922 922 reqp->req.ppm_lock_power_req.circp);
923 923 if (*iresp)
924 924 domp->refcnt++;
925 925 else
926 926 mutex_exit(&domp->lock);
927 927 }
928 928
929 929
930 930 /*
931 931 * return FALSE: if any detached device during its previous life exported
932 932 * the "no-involuntary-power-cycles" property and detached with its
933 933 * power level not at its lowest, or there is a device in the process
934 934 * of being installed/attached; if a PCI domain has devices that have not
935 935 * exported a property that it can tolerate clock off while bus is not
936 936 * quiescent; if a 66mhz PCI domain has devices that do not support stopping
937 937 * clock at D3; either one would count as a power holder.
938 938 * return TRUE: otherwise.
939 939 */
940 940 boolean_t
941 941 ppm_none_else_holds_power(ppm_domain_t *domp)
942 942 {
943 943 ppm_dev_t *ppmd;
944 944 ppm_owned_t *owned;
945 945 int i = 0;
946 946
947 947 if (PPMD_IS_PCI(domp->model)) {
948 948 for (ppmd = domp->devlist; ppmd; ppmd = ppmd->next) {
949 949 if ((domp->model == PPMD_PCI_PROP) &&
950 950 !(ppmd->flags & PPMDEV_PCI_PROP_CLKPM))
951 951 return (B_FALSE);
952 952 if ((domp->dflags & PPMD_PCI66MHZ) &&
953 953 !(ppmd->flags & PPMDEV_PCI66_D2))
954 954 return (B_FALSE);
955 955 }
956 956 }
957 957
958 958 for (owned = domp->owned; owned; owned = owned->next)
959 959 if (pm_noinvol_detached(owned->path) || owned->initializing)
960 960 i++;
961 961 return (i == 0);
962 962 }
963 963
964 964
965 965 /*
966 966 * return the number of char 'c' occurrences in string s
967 967 */
968 968 int
969 969 ppm_count_char(char *s, char c)
970 970 {
971 971 int i = 0;
972 972 char *cp = s;
973 973
974 974 while (*cp) {
975 975 if (*cp == c)
976 976 i++;
977 977 cp++;
978 978 }
979 979
980 980 return (i);
981 981 }
982 982
983 983
984 984 /*
985 985 * extract and convert a substring from input string "ss" in form of
986 986 * "name=value" into an hex or decimal integer
987 987 */
988 988 #define X_BASE 16
989 989 #define D_BASE 10
990 990 int
991 991 ppm_stoi(char *ss, uint_t *val)
992 992 {
993 993 char *cp;
994 994 int hex_ = 0, base = D_BASE;
995 995 int digit;
996 996
997 997 if ((cp = strchr(ss, '=')) == NULL)
998 998 return (*val = (uint_t)-1);
999 999
1000 1000 cp++;
1001 1001 if ((*cp == '0') && (*++cp == 'x')) {
1002 1002 hex_++;
1003 1003 cp++;
1004 1004 base = X_BASE;
1005 1005 }
1006 1006
1007 1007 for (digit = 0; *cp; cp++) {
1008 1008 if (hex_ && ((*cp >= 'A') && (*cp <= 'F')))
1009 1009 digit = (digit * base) + ((*cp - 'A') + D_BASE);
1010 1010 else if (hex_ && ((*cp >= 'a') && (*cp <= 'f')))
1011 1011 digit = (digit * base) + ((*cp - 'a') + D_BASE);
1012 1012 else
1013 1013 digit = (digit * base) + (*cp - '0');
1014 1014 }
1015 1015
1016 1016 return (*val = digit);
1017 1017 }
↓ open down ↓ |
792 lines elided |
↑ open up ↑ |
1018 1018
1019 1019 /*
1020 1020 * ppm_convert - convert a #define symbol to its integer value,
1021 1021 * only the #defines for ppm_dc.cmd and ppm_dc.method fields in
1022 1022 * ppmvar.h file are recognized.
1023 1023 */
1024 1024 struct ppm_confdefs {
1025 1025 char *sym;
1026 1026 int val;
1027 1027 } ppm_confdefs_table[] = {
1028 - "ENTER_S3", PPMDC_ENTER_S3,
1029 - "EXIT_S3", PPMDC_EXIT_S3,
1030 - "CPU_NEXT", PPMDC_CPU_NEXT,
1031 - "PRE_CHNG", PPMDC_PRE_CHNG,
1032 - "CPU_GO", PPMDC_CPU_GO,
1033 - "POST_CHNG", PPMDC_POST_CHNG,
1034 - "FET_ON", PPMDC_FET_ON,
1035 - "FET_OFF", PPMDC_FET_OFF,
1036 - "CLK_OFF", PPMDC_CLK_OFF,
1037 - "CLK_ON", PPMDC_CLK_ON,
1038 - "LED_ON", PPMDC_LED_ON,
1039 - "LED_OFF", PPMDC_LED_OFF,
1040 - "KIO", PPMDC_KIO,
1041 - "VCORE", PPMDC_VCORE,
1028 + { "ENTER_S3", PPMDC_ENTER_S3 },
1029 + { "EXIT_S3", PPMDC_EXIT_S3 },
1030 + { "CPU_NEXT", PPMDC_CPU_NEXT },
1031 + { "PRE_CHNG", PPMDC_PRE_CHNG },
1032 + { "CPU_GO", PPMDC_CPU_GO },
1033 + { "POST_CHNG", PPMDC_POST_CHNG },
1034 + { "FET_ON", PPMDC_FET_ON },
1035 + { "FET_OFF", PPMDC_FET_OFF },
1036 + { "CLK_OFF", PPMDC_CLK_OFF },
1037 + { "CLK_ON", PPMDC_CLK_ON },
1038 + { "LED_ON", PPMDC_LED_ON },
1039 + { "LED_OFF", PPMDC_LED_OFF },
1040 + { "KIO", PPMDC_KIO },
1041 + { "VCORE", PPMDC_VCORE },
1042 1042 #ifdef sun4u
1043 - "I2CKIO", PPMDC_I2CKIO,
1043 + { "I2CKIO", PPMDC_I2CKIO },
1044 1044 #endif
1045 - "CPUSPEEDKIO", PPMDC_CPUSPEEDKIO,
1046 - "PRE_PWR_OFF", PPMDC_PRE_PWR_OFF,
1047 - "PRE_PWR_ON", PPMDC_PRE_PWR_ON,
1048 - "POST_PWR_ON", PPMDC_POST_PWR_ON,
1049 - "PWR_OFF", PPMDC_PWR_OFF,
1050 - "PWR_ON", PPMDC_PWR_ON,
1051 - "RESET_OFF", PPMDC_RESET_OFF,
1052 - "RESET_ON", PPMDC_RESET_ON,
1053 - NULL
1045 + { "CPUSPEEDKIO", PPMDC_CPUSPEEDKIO },
1046 + { "PRE_PWR_OFF", PPMDC_PRE_PWR_OFF },
1047 + { "PRE_PWR_ON", PPMDC_PRE_PWR_ON },
1048 + { "POST_PWR_ON", PPMDC_POST_PWR_ON },
1049 + { "PWR_OFF", PPMDC_PWR_OFF },
1050 + { "PWR_ON", PPMDC_PWR_ON },
1051 + { "RESET_OFF", PPMDC_RESET_OFF },
1052 + { "RESET_ON", PPMDC_RESET_ON },
1053 + { NULL }
1054 1054 };
1055 1055
1056 1056
1057 1057 /*
1058 1058 * convert a #define'd symbol to its integer value where
1059 1059 * input "symbol" is expected to be in form of "SYMBOL=value"
1060 1060 */
1061 1061 int
1062 1062 ppm_convert(char *symbol, uint_t *val)
1063 1063 {
1064 1064 char *s;
1065 1065 struct ppm_confdefs *pcfp;
1066 1066
1067 1067 if ((s = strchr(symbol, '=')) == NULL) {
1068 1068 cmn_err(CE_WARN, "ppm_convert: token \"%s\" syntax error in "
1069 1069 "ppm.conf file", symbol);
1070 1070 return (*val = (uint_t)-1);
1071 1071 }
1072 1072 s++;
1073 1073
1074 1074 for (pcfp = ppm_confdefs_table; (pcfp->sym != NULL); pcfp++) {
1075 1075 if (strcmp(s, pcfp->sym) == 0)
1076 1076 return (*val = pcfp->val);
1077 1077 }
1078 1078
1079 1079 cmn_err(CE_WARN, "ppm_convert: Unrecognizable token \"%s\" "
1080 1080 "in ppm.conf file", symbol);
1081 1081 return (*val = (uint_t)-1);
1082 1082 }
1083 1083
1084 1084
1085 1085 /*
1086 1086 * parse a domain control property string into data structure struct ppm_dc
1087 1087 */
1088 1088 int
1089 1089 ppm_parse_dc(char **dc_namep, ppm_dc_t *dc)
1090 1090 {
1091 1091 char *str = "ppm_parse_dc";
1092 1092 char *line;
1093 1093 char *f, *b;
1094 1094 char **dclist; /* list of ppm_dc_t fields */
1095 1095 int count; /* the # of '=' indicates the # of items */
1096 1096 size_t len; /* length of line being parsed */
1097 1097 boolean_t done;
1098 1098 int i;
1099 1099 int err;
1100 1100
1101 1101 len = strlen(*dc_namep);
1102 1102 line = kmem_alloc(len + 1, KM_SLEEP);
1103 1103 (void) strcpy(line, *dc_namep);
1104 1104
1105 1105 count = ppm_count_char(line, '=');
1106 1106 ASSERT((count - ppm_count_char(line, ' ')) == 1);
1107 1107
1108 1108 dclist = (char **)
1109 1109 kmem_zalloc((sizeof (char *) * (count + 1)), KM_SLEEP);
1110 1110 for (i = 0, f = b = line, done = B_FALSE; !done; i++, f = ++b) {
1111 1111 while (*b != ' ' && *b != 0)
1112 1112 b++;
1113 1113 if (*b == 0)
1114 1114 done = B_TRUE;
1115 1115 else
1116 1116 *b = 0;
1117 1117 dclist[i] = f;
1118 1118 }
1119 1119
1120 1120 for (i = 0; i < count; i++) {
1121 1121 if (strstr(dclist[i], "cmd=")) {
1122 1122 err = ppm_convert(dclist[i], &dc->cmd);
1123 1123 if (err == -1)
1124 1124 return (err);
1125 1125 continue;
1126 1126 }
1127 1127 if ((f = strstr(dclist[i], "path=")) != NULL) {
1128 1128 f += strlen("path=");
1129 1129 dc->path = kmem_zalloc((strlen(f) + 1), KM_SLEEP);
1130 1130 (void) strcpy(dc->path, f);
1131 1131 continue;
1132 1132 }
1133 1133 if (strstr(dclist[i], "method=")) {
1134 1134 err = ppm_convert(dclist[i], &dc->method);
1135 1135 if (err == -1)
1136 1136 return (err);
1137 1137 continue;
1138 1138 }
1139 1139 if (strstr(dclist[i], "iowr=")) {
1140 1140 (void) ppm_stoi(dclist[i], &dc->m_un.kio.iowr);
1141 1141 continue;
1142 1142 }
1143 1143 if (strstr(dclist[i], "iord=")) {
1144 1144 (void) ppm_stoi(dclist[i], &dc->m_un.kio.iord);
1145 1145 continue;
1146 1146 }
1147 1147 if (strstr(dclist[i], "val=")) {
1148 1148 (void) ppm_stoi(dclist[i], &dc->m_un.kio.val);
1149 1149 continue;
1150 1150 }
1151 1151 if (strstr(dclist[i], "speeds=")) {
1152 1152 ASSERT(dc->method == PPMDC_CPUSPEEDKIO);
1153 1153 (void) ppm_stoi(dclist[i], &dc->m_un.cpu.speeds);
1154 1154 continue;
1155 1155 }
1156 1156 #ifdef sun4u
1157 1157 if (strstr(dclist[i], "mask=")) {
1158 1158 (void) ppm_stoi(dclist[i], &dc->m_un.i2c.mask);
1159 1159 continue;
1160 1160 }
1161 1161 #endif
1162 1162 /* This must be before the if statement for delay */
1163 1163 if (strstr(dclist[i], "post_delay=")) {
1164 1164 #ifdef sun4u
1165 1165 ASSERT(dc->method == PPMDC_KIO ||
1166 1166 dc->method == PPMDC_I2CKIO);
1167 1167 #else
1168 1168 ASSERT(dc->method == PPMDC_KIO);
1169 1169 #endif
1170 1170 /*
1171 1171 * all delays are uint_t type instead of clock_t.
1172 1172 * If the delay is too long, it might get truncated.
1173 1173 * But, we don't expect delay to be too long.
1174 1174 */
1175 1175 switch (dc->method) {
1176 1176 case PPMDC_KIO:
1177 1177 (void) ppm_stoi(dclist[i],
1178 1178 &dc->m_un.kio.post_delay);
1179 1179 break;
1180 1180
1181 1181 #ifdef sun4u
1182 1182 case PPMDC_I2CKIO:
1183 1183 (void) ppm_stoi(dclist[i],
1184 1184 &dc->m_un.i2c.post_delay);
1185 1185 break;
1186 1186 #endif
1187 1187
1188 1188 default:
1189 1189 break;
1190 1190 }
1191 1191 continue;
1192 1192 }
1193 1193 if (strstr(dclist[i], "delay=")) {
1194 1194 #ifdef sun4u
1195 1195 ASSERT(dc->method == PPMDC_VCORE ||
1196 1196 dc->method == PPMDC_KIO ||
1197 1197 dc->method == PPMDC_I2CKIO);
1198 1198 #else
1199 1199 ASSERT(dc->method == PPMDC_VCORE ||
1200 1200 dc->method == PPMDC_KIO);
1201 1201 #endif
1202 1202
1203 1203 /*
1204 1204 * all delays are uint_t type instead of clock_t.
1205 1205 * If the delay is too long, it might get truncated.
1206 1206 * But, we don't expect delay to be too long.
1207 1207 */
1208 1208
1209 1209 switch (dc->method) {
1210 1210 case PPMDC_KIO:
1211 1211 (void) ppm_stoi(dclist[i], &dc->m_un.kio.delay);
1212 1212 break;
1213 1213
1214 1214 #ifdef sun4u
1215 1215 case PPMDC_I2CKIO:
1216 1216 (void) ppm_stoi(dclist[i], &dc->m_un.i2c.delay);
1217 1217 break;
1218 1218 #endif
1219 1219
1220 1220 case PPMDC_VCORE:
1221 1221 (void) ppm_stoi(dclist[i], &dc->m_un.cpu.delay);
1222 1222 break;
1223 1223
1224 1224 default:
1225 1225 break;
1226 1226 }
1227 1227 continue;
1228 1228 }
1229 1229
1230 1230 /* we encounted unrecognized field, flag error */
1231 1231 cmn_err(CE_WARN, "%s: Unrecognized token \"%s\" in ppm.conf "
1232 1232 "file!", str, dclist[i]);
1233 1233 return (-1);
1234 1234 }
1235 1235
1236 1236 kmem_free(dclist, sizeof (char *) * (count + 1));
1237 1237 kmem_free(line, len + 1);
1238 1238
1239 1239 return (DDI_SUCCESS);
1240 1240 }
1241 1241
1242 1242
1243 1243 /*
1244 1244 * search for domain control handle for a claimed device coupled with a
1245 1245 * domain control command. NULL device may indicate LED domain.
1246 1246 */
1247 1247 ppm_dc_t *
1248 1248 ppm_lookup_dc(ppm_domain_t *domp, int cmd)
1249 1249 {
1250 1250 #ifdef DEBUG
1251 1251 char *str = "ppm_lookup_dc";
1252 1252 #endif
1253 1253 ppm_dc_t *dc;
1254 1254
1255 1255 /*
1256 1256 * For convenience, we accept 'domp' as NULL for searching
1257 1257 * LED domain control operation.
1258 1258 */
1259 1259 if ((cmd == PPMDC_LED_OFF) || (cmd == PPMDC_LED_ON)) {
1260 1260 for (domp = ppm_domain_p; domp; domp = domp->next)
1261 1261 if (domp->model == PPMD_LED)
1262 1262 break;
1263 1263 if (!domp || !domp->dc || !domp->dc->lh || !domp->dc->next) {
1264 1264 PPMD(D_LED, ("\tinsufficient led domain control "
1265 1265 "information.\n"))
1266 1266 return (NULL);
1267 1267 }
1268 1268 if (cmd == domp->dc->cmd)
1269 1269 return (domp->dc);
1270 1270 else
1271 1271 return (domp->dc->next);
1272 1272 }
1273 1273
1274 1274
1275 1275 /*
1276 1276 * for the rest of ppm domains, lookup ppm_dc starting from domp
1277 1277 */
1278 1278 ASSERT(domp != NULL);
1279 1279 switch (cmd) {
1280 1280 case PPMDC_CPU_NEXT:
1281 1281 case PPMDC_PRE_CHNG:
1282 1282 case PPMDC_CPU_GO:
1283 1283 case PPMDC_POST_CHNG:
1284 1284 case PPMDC_FET_OFF:
1285 1285 case PPMDC_FET_ON:
1286 1286 case PPMDC_CLK_OFF:
1287 1287 case PPMDC_CLK_ON:
1288 1288 case PPMDC_PRE_PWR_OFF:
1289 1289 case PPMDC_PRE_PWR_ON:
1290 1290 case PPMDC_POST_PWR_ON:
1291 1291 case PPMDC_PWR_OFF:
1292 1292 case PPMDC_PWR_ON:
1293 1293 case PPMDC_RESET_OFF:
1294 1294 case PPMDC_RESET_ON:
1295 1295 case PPMDC_ENTER_S3:
1296 1296 case PPMDC_EXIT_S3:
1297 1297 break;
1298 1298 default:
1299 1299 PPMD(D_PPMDC, ("%s: cmd(%d) unrecognized\n", str, cmd))
1300 1300 return (NULL);
1301 1301 }
1302 1302
1303 1303 for (dc = domp->dc; dc; dc = dc->next) {
1304 1304 if (dc->cmd == cmd) {
1305 1305 return (dc);
1306 1306 }
1307 1307 }
1308 1308
1309 1309 return (NULL);
1310 1310 }
1311 1311
1312 1312 #include <sys/esunddi.h>
1313 1313
1314 1314 ppm_domain_t *
1315 1315 ppm_get_domain_by_dev(const char *p)
1316 1316 {
1317 1317 dev_info_t *dip;
1318 1318 ppm_domain_t *domp;
1319 1319 ppm_dev_t *pdev;
1320 1320 boolean_t found = B_FALSE;
1321 1321
1322 1322 if ((dip = e_ddi_hold_devi_by_path((char *)p, 0)) == NULL)
1323 1323 return (NULL);
1324 1324
1325 1325 for (domp = ppm_domain_p; domp; domp = domp->next) {
1326 1326 for (pdev = domp->devlist; pdev; pdev = pdev->next) {
1327 1327 if (pdev->dip == dip) {
1328 1328 found = B_TRUE;
1329 1329 break;
1330 1330 }
1331 1331 }
1332 1332 if (found)
1333 1333 break;
1334 1334 }
1335 1335 ddi_release_devi(dip);
1336 1336 return (domp);
1337 1337 }
1338 1338
1339 1339
1340 1340 #ifdef DEBUG
1341 1341 #define FLINTSTR(flags, sym) { flags, sym, #sym }
1342 1342 #define PMR_UNKNOWN -1
1343 1343 /*
1344 1344 * convert a ctlop integer to a char string. this helps printing
1345 1345 * meaningful info when cltops are received from the pm framework.
1346 1346 * since some ctlops are so frequent, we use mask to limit output:
1347 1347 * a valid string is returned when ctlop is found and when
1348 1348 * (cmd.flags & mask) is true; otherwise NULL is returned.
1349 1349 */
1350 1350 char *
1351 1351 ppm_get_ctlstr(int ctlop, uint_t mask)
1352 1352 {
1353 1353 struct ctlop_cmd {
1354 1354 uint_t flags;
1355 1355 int ctlop;
1356 1356 char *str;
1357 1357 };
1358 1358
1359 1359 struct ctlop_cmd *ccp;
1360 1360 static struct ctlop_cmd cmds[] = {
1361 1361 FLINTSTR(D_SETPWR, PMR_SET_POWER),
1362 1362 FLINTSTR(D_CTLOPS2, PMR_SUSPEND),
1363 1363 FLINTSTR(D_CTLOPS2, PMR_RESUME),
1364 1364 FLINTSTR(D_CTLOPS2, PMR_PRE_SET_POWER),
1365 1365 FLINTSTR(D_CTLOPS2, PMR_POST_SET_POWER),
1366 1366 FLINTSTR(D_CTLOPS2, PMR_PPM_SET_POWER),
1367 1367 FLINTSTR(0, PMR_PPM_ATTACH),
1368 1368 FLINTSTR(0, PMR_PPM_DETACH),
1369 1369 FLINTSTR(D_CTLOPS1, PMR_PPM_POWER_CHANGE_NOTIFY),
1370 1370 FLINTSTR(D_CTLOPS1, PMR_REPORT_PMCAP),
1371 1371 FLINTSTR(D_CTLOPS1, PMR_CHANGED_POWER),
1372 1372 FLINTSTR(D_CTLOPS2, PMR_PPM_INIT_CHILD),
1373 1373 FLINTSTR(D_CTLOPS2, PMR_PPM_UNINIT_CHILD),
1374 1374 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_PROBE),
1375 1375 FLINTSTR(D_CTLOPS2, PMR_PPM_POST_PROBE),
1376 1376 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_ATTACH),
1377 1377 FLINTSTR(D_CTLOPS2, PMR_PPM_POST_ATTACH),
1378 1378 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_DETACH),
1379 1379 FLINTSTR(D_CTLOPS2, PMR_PPM_POST_DETACH),
1380 1380 FLINTSTR(D_CTLOPS1, PMR_PPM_UNMANAGE),
1381 1381 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_RESUME),
1382 1382 FLINTSTR(D_CTLOPS1, PMR_PPM_ALL_LOWEST),
1383 1383 FLINTSTR(D_LOCKS, PMR_PPM_LOCK_POWER),
1384 1384 FLINTSTR(D_LOCKS, PMR_PPM_UNLOCK_POWER),
1385 1385 FLINTSTR(D_LOCKS, PMR_PPM_TRY_LOCK_POWER),
1386 1386 FLINTSTR(D_LOCKS, PMR_PPM_POWER_LOCK_OWNER),
1387 1387 FLINTSTR(D_CTLOPS1 | D_CTLOPS2, PMR_PPM_ENTER_SX),
1388 1388 FLINTSTR(D_CTLOPS1 | D_CTLOPS2, PMR_UNKNOWN),
1389 1389 };
1390 1390
1391 1391 for (ccp = cmds; ccp->ctlop != PMR_UNKNOWN; ccp++)
1392 1392 if (ctlop == ccp->ctlop)
1393 1393 break;
1394 1394
1395 1395 if (ccp->flags & mask)
1396 1396 return (ccp->str);
1397 1397 return (NULL);
1398 1398 }
1399 1399
1400 1400 void
1401 1401 ppm_print_dc(ppm_dc_t *dc)
1402 1402 {
1403 1403 ppm_dc_t *d = dc;
1404 1404
1405 1405 PPMD(D_PPMDC, ("\nAdds ppm_dc: path(%s),\n cmd(%x), "
1406 1406 "method(%x), ", d->path, d->cmd, d->method))
1407 1407 if (d->method == PPMDC_KIO) {
1408 1408 PPMD(D_PPMDC, ("kio.iowr(%x), kio.val(0x%X)",
1409 1409 d->m_un.kio.iowr, d->m_un.kio.val))
1410 1410 #ifdef sun4u
1411 1411 } else if (d->method == PPMDC_I2CKIO) {
1412 1412 PPMD(D_PPMDC, ("i2c.iowr(%x), i2c.val(0x%X), "
1413 1413 "i2c.mask(0x%X)", d->m_un.i2c.iowr,
1414 1414 d->m_un.i2c.val, d->m_un.i2c.mask))
1415 1415 #endif
1416 1416 } else if (d->method == PPMDC_VCORE) {
1417 1417 PPMD(D_PPMDC, ("cpu: .iord(%x), .iowr(%x), .val(0x%X), "
1418 1418 ".delay(0x%x)",
1419 1419 d->m_un.cpu.iord, d->m_un.cpu.iowr, d->m_un.cpu.val,
1420 1420 d->m_un.cpu.delay))
1421 1421 } else if (d->method == PPMDC_CPUSPEEDKIO) {
1422 1422 PPMD(D_PPMDC, ("cpu.iowr(%x), cpu.speeds(0x%X)",
1423 1423 d->m_un.cpu.iowr, d->m_un.cpu.speeds))
1424 1424 }
1425 1425 PPMD(D_PPMDC, ("\n"))
1426 1426 }
1427 1427 #endif /* DEBUG */
↓ open down ↓ |
364 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX