summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/sys/epm.h
blob: 35b656409b1064925ca3c773dedca015119c57ed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef	_SYS_EPM_H
#define	_SYS_EPM_H

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <sys/pm.h>
#include <sys/dditypes.h>
#include <sys/devops.h>
#include <sys/ddi_impldefs.h>
#include <sys/taskq.h>

/*
 * XXXX
 * Do we really need this include?  It may be leftover from early CPUPM code.
 * #include <sys/processor.h>
 */

#ifdef	__cplusplus
extern "C" {
#endif

#ifdef	_KERNEL

/*
 * epm.h:	Function prototypes and data structs for kernel pm functions.
 */

void e_pm_props(dev_info_t *);
int e_new_pm_props(dev_info_t *);

#define	PM_LEVEL_UPONLY (-2)	/* only raise power level */
#define	PM_LEVEL_DOWNONLY (-3)	/* only lower power level */
#define	PM_LEVEL_EXACT (-4)	/* wants exact power level */

/*
 * Values used by e_pm_props and friends, found in devi_pm_flags
 */
#define	PMC_NEEDS_SR		0x00001	/* do suspend/resume despite no "reg" */
#define	PMC_NO_SR		0x00002	/* don't suspend/resume despite "reg" */
#define	PMC_PARENTAL_SR		0x00004	/* call up tree to suspend/resume */
#define	PMC_WANTS_NOTIFY	0x00008	/* notify if child pwr level changes */
#define	PMC_BC			0x00010	/* no pm-components, backwards compat */
#define	PMC_COMPONENTS_DONE	0x00020 /* parsed pm-components */
#define	PMC_COMPONENTS_FAILED	0x00040 /* failed parsing pm-components */
#define	PMC_SUSPENDED		0x00080 /* device has been suspended */
#define	PMC_DEF_THRESH		0x00100 /* thresholds are default */
#define	PMC_DEV_THRESH		0x00200 /* SET_THRESHOLD ioctl seen */
#define	PMC_COMP_THRESH		0x00400 /* relative threshold set */
#define	PMC_NEXDEF_THRESH	0x00800 /* relative threshold set for nexus */
#define	PMC_NOPMKID		0x01000 /* non-pm'd child of pm'd parent */
#define	PMC_NO_INVOL		0x02000 /* no pm without driver's consent */
#define	PMC_VOLPMD		0x04000 /* went down voluntarily */
#define	PMC_SKIP_BRINGUP	0x08000 /* Skipped a dependency bringup */

/*
 * A node which is the console frame buffer, and should not be powered down
 * automatically because the OBP driver doesn't know how to power it back up
 * before using it  (can remove this when prom calls back into kernel to do
 * io to console).
 */
#define	PMC_CONSOLE_FB		0x10000	/* console framebuffer */
#define	PMC_NOINVOL_DONE	0x20000 /* processed by pm_noinvol_specd() */
#define	PMC_DRIVER_REMOVED	0x40000 /* driver is removed	*/
#define	PMC_CPU_DEVICE		0x80000 /* device is a power manageable CPU */
#define	PMC_CPU_THRESH		0x100000 /* cpu threshold set */

#define	PMC_THRESH_ALL	(PMC_DEF_THRESH | PMC_DEV_THRESH | \
    PMC_COMP_THRESH | PMC_NEXDEF_THRESH | PMC_CPU_THRESH)
#define	PMC_THRESH_NONE	~(PMC_THRESH_ALL)

/* Flags for the component */
#define	PM_POWER_OP		0x00001	/* set power in process */
#define	PM_PHC_WHILE_SET_POWER	0x00002	/* phc and set power deadlock */

/*
 * One of these is attached to each devinfo that is autopm'd.
 */
typedef struct pm_scan {
	int		ps_idle_down;	/* PMID_XXX flags */
	int		ps_scan_flags;	/* scan flags, defined below */
	timeout_id_t	ps_scan_id;	/* per dip scan timeout id */
} pm_scan_t;

/*
 * ps_scan_flags may take the following values, plus possibly
 * more defined.
 */
#define	PM_SCANNING		0x100	/* scanning: pm_scan_dev is active */
#define	PM_SCAN_AGAIN		0x200
#define	PM_SCAN_STOP		0x400
#define	PM_SCAN_DISPATCHED	0x800

#define	PM_MIN_SCAN	((clock_t)15)	/* Minimum scan interval in seconds */

/*
 * Power management component definitions, used for tracking idleness of
 * devices.  An array of these hangs off the devi_pm_components member of the
 * dev_info struct (if initialized by driver and/or auto-pm)
 * The array of these structs is followed in the same kmem_zalloc'd chunk by
 * the names pointed to by the structs.
 */

/*
 * This (sub-)struct contains all the info extracted from the pm-components
 * property for each component (name of component, names and values of power
 * levels supported).  It is in a separate structure to allow it to be handled
 * as a struct assignment.
 */
typedef struct pm_comp {
	char 	*pmc_name;		/* name of component */
	int	pmc_numlevels;		/* number of power levels supported */
	int	*pmc_lvals;		/* numerical values of levels */
	int	*pmc_thresh;		/* thresholds in secs, last INT_MAX */
	char	**pmc_lnames;		/* human readable names of levels */
	/*
	 * This part is just bookkeeping for the storage space involved above
	 * used for copying and freeing the struct members.  This because C
	 * is really an assembler at heart.
	 */
	size_t	pmc_name_sz;		/* size of name string		*/
	char	*pmc_lname_buf;		/* buffer holding *pmc_lnames	*/
	size_t	pmc_lnames_sz;		/* total size of pmc_lname_buf	*/
} pm_comp_t;

/*
 * Here we have the rest of what we need to know about a component.
 */
typedef struct pm_component {
	uint_t pmc_flags;		/* flags this component */
	uint_t pmc_busycount;		/* for nesting busy calls */
	time_t pmc_timestamp;		/* timestamp */
	uint_t pmc_norm_pwr;		/* normal power index (or value) */
	int pmc_cur_pwr;		/* current power index (or value)  */
	int pmc_phc_pwr;		/* prev. value of curpwr (deadlock) */
	pm_comp_t pmc_comp;		/* component description */
} pm_component_t;

/*
 * All members of this struct are protected by PM_LOCK_DIP(dip).
 *
 * kidsupcnt counts (the number of components of new-style children at non-zero
 * level (unknown counts as non-zero)) + (the number of old-style children with
 * component 0 at non-zero level) for parents that have not asked for
 * notifcation.  When kidsupcnt is 0 for a nexus node, then pm scans it,
 * otherwise it leaves it alone.
 * Parents that ask for notification always get get scanned,
 * so we keep their kidsupcnt at zero.
 */
typedef struct pm_info {
	uint_t		pmi_dev_pm_state; /* PM state of a device */
	int		pmi_clone;	/* owner for direct pm'd devs */
	int		pmi_levels[2];	/* storage space for 2 levels */
	int		*pmi_lp;	/* storage space for >2 levels */
	kcondvar_t	pmi_cv;		/* condvar for direct PM access */
} pm_info_t;

/*
 * Work request structure for the dependency processing thread.
 */
typedef struct pm_dep_wk {
	int		pdw_type;		/* Type of request */
	int		pdw_wait;		/* caller waits for result */
	int		pdw_done;		/* set when req is done */
	int		pdw_ret;		/* return value to caller */
	int		pdw_pwr;		/* pwr level of keeper */
	kcondvar_t	pdw_cv;			/* cv to wake up caller */
	struct		pm_dep_wk *pdw_next;	/* next element */
	char		*pdw_keeper;
	char		*pdw_kept;
} pm_dep_wk_t;

/*
 * Types of work, depends on when it gets called:
 */
#define	PM_DEP_WK_POWER_ON		1	/* power on */
#define	PM_DEP_WK_POWER_OFF		2	/* power off */
#define	PM_DEP_WK_DETACH		3	/* detach */
#define	PM_DEP_WK_REMOVE_DEP		4	/* dependency removed */
#define	PM_DEP_WK_BRINGUP_SELF		5	/* released from direct PM */
#define	PM_DEP_WK_RECORD_KEEPER		6	/* PM_ADD_DEPENDENT */
#define	PM_DEP_WK_RECORD_KEEPER_PROP	7	/* PM_ADD_DEPENDENT_PROP */
#define	PM_DEP_WK_KEPT			8	/* dep. work as a kept */
#define	PM_DEP_WK_KEEPER		9	/* dep. work as a keeper */
#define	PM_DEP_WK_ATTACH		10	/* when dip is attached */
#define	PM_DEP_WK_CHECK_KEPT		11	/* check if this is a kept */
#define	PM_DEP_WK_CPR_SUSPEND		12	/* Suspend dep. during CPR */
#define	PM_DEP_WK_CPR_RESUME		13	/* Resume dep. after CPR */

/*
 * Wait for dependency work to finish or not.
 */
#define	PM_DEP_WAIT	1
#define	PM_DEP_NOWAIT	0

typedef enum pm_canblock
{
	PM_CANBLOCK_BLOCK,	/* wait for controlling process action */
	PM_CANBLOCK_FAIL,	/* don't wait, fail request */
	PM_CANBLOCK_BYPASS	/* don't wait, ignore controlling process */
} pm_canblock_t;

typedef enum pm_cpupm
{
	PM_CPUPM_NOTSET,	/* no specific treatment of CPU devices */
	PM_CPUPM_ENABLE,	/* power manage CPU devices */
	PM_CPUPM_DISABLE	/* do not power manage CPU devices */
} pm_cpupm_t;

#define	PPM(dip) ((dev_info_t *)DEVI(dip)->devi_pm_ppm)

/*
 * The power request struct uses for the DDI_CTLOPS_POWER busctl.
 *
 * Note: When changing this enum it is necessary to maintain binary
 * compatibility with older versions.  To insure that, add new values only
 * at the end and refrain from deleting any existing values.
 */
typedef enum {
	PMR_SET_POWER = 1,		/* called ddi_power (obsolete)	*/
	PMR_SUSPEND,			/* parental suspend		*/
	PMR_RESUME,			/* parental resume		*/
	PMR_PRE_SET_POWER,		/* parent's "pre" notification	*/
	PMR_POST_SET_POWER,		/* parent's "post" notification	*/
	PMR_PPM_SET_POWER,		/* platform pm set power	*/
	PMR_PPM_ATTACH,			/* ppm attach notify - unused	*/
	PMR_PPM_DETACH,			/* ppm detach notify - unused   */
	PMR_PPM_POWER_CHANGE_NOTIFY,	/* ppm level change notify	*/
	PMR_REPORT_PMCAP,		/* report pm capability		*/
	PMR_CHANGED_POWER,		/* parent's power_has_changed notif. */
	PMR_PPM_PRE_PROBE,		/* ppm pre probe notify		*/
	PMR_PPM_POST_PROBE,		/* ppm post probe notify	*/
	PMR_PPM_PRE_ATTACH,		/* ppm pre attach notify	*/
	PMR_PPM_POST_ATTACH,		/* ppm post pm attach notify	*/
	PMR_PPM_PRE_DETACH,		/* ppm pre pm detach notify	*/
	PMR_PPM_POST_DETACH,		/* ppm post pm detach notify	*/
	PMR_PPM_UNMANAGE,		/* device being unmanaged	*/
	PMR_PPM_PRE_RESUME,		/* ppm resume notify		*/
	PMR_PPM_ALL_LOWEST,		/* ppm all lowest power notify	*/
	PMR_PPM_LOCK_POWER,		/* ppm lock power		*/
	PMR_PPM_UNLOCK_POWER,		/* ppm unlock power		*/
	PMR_PPM_TRY_LOCK_POWER,		/* ppm try lock power		*/
	PMR_PPM_INIT_CHILD,		/* ppm init child notify	*/
	PMR_PPM_UNINIT_CHILD,		/* ppm uninit child notify	*/
	PMR_PPM_POWER_LOCK_OWNER,	/* ppm power lock owner's address */
	PMR_PPM_ENTER_SX,		/* ppm: enter ACPI S[2-4] state	*/
	PMR_PPM_EXIT_SX,		/* ppm: enter ACPI S[2-4] state	*/
	PMR_PPM_SEARCH_LIST		/* ppm: search tuple list	*/
} pm_request_type;

/*
 * When changing the elements of the union below it is necessary to
 * maintain binary compatibility with older versions.  Refrain from
 * deleting existing elements of the union or modifying their contents.
 * Avoid increasing the total size of this structure if new elements
 * must be added.
 */
typedef struct power_req {
	pm_request_type request_type;
	union req {
		/*
		 * PMR_SET_POWER (obsolete)
		 */
		struct set_power_req {
			dev_info_t	*who;
			int		cmpt;
			int		level;
		} set_power_req;
		/*
		 * PMR_SUSPEND
		 */
		struct suspend_req {
			dev_info_t	*who;
			ddi_detach_cmd_t cmd;
		} suspend_req;
		/*
		 * PMR_PPM_PRE_RESUME or PMR_RESUME
		 */
		struct resume_req {
			dev_info_t	*who;
			ddi_attach_cmd_t cmd;
		} resume_req;
		/*
		 * PMR_PRE_SET_POWER
		 */
		struct pre_set_power_req {
			dev_info_t	*who;
			int		cmpt;
			int		old_level;
			int		new_level;
		} pre_set_power_req;
		/*
		 * PMR_POST_SET_POWER
		 */
		struct post_set_power_req {
			dev_info_t	*who;
			int		cmpt;
			int		old_level;
			int		new_level;
			int		result;		/* driver's return */
		} post_set_power_req;
		/*
		 * PMR_PPM_SET_POWER
		 */
		struct ppm_set_power_req {
			dev_info_t	*who;
			int		cmpt;
			int		old_level;
			int		new_level;
			pm_canblock_t	canblock;
			void		*cookie;
		} ppm_set_power_req;
		/*
		 * PMR_PPM_POWER_CHANGE_NOTIFY
		 */
		struct ppm_notify_level_req {
			dev_info_t	*who;
			int		cmpt;
			int		old_level;
			int		new_level;
		} ppm_notify_level_req;
		/*
		 * PMR_REPORT_PMCAP
		 */
		struct report_pmcap_req {
			dev_info_t	*who;
			int		cap;
			void 		*arg;
		} report_pmcap_req;
		/*
		 * PMR_CHANGED_POWER
		 */
		struct changed_power_req {
			dev_info_t	*who;
			int		cmpt;
			int		old_level;
			int		new_level;
			int		result;
		} changed_power_req;
		/*
		 * PMR_PPM_PRE_PROBE, PMR_PPM_POST_PROBE, PMR_PPM_PRE_ATTACH,
		 * PMR_PPM_POST_ATTACH, PMR_PPM_PRE_DETACH, PMR_PPM_POST_DETACH
		 * PMR_PPM_INIT_CHILD, PMR_PPM_UNINIT_CHILD, or PMR_PPM_UNMANAGE
		 */
		struct ppm_config_req {
			dev_info_t	*who;
			int		result;		/* post only */
		} ppm_config_req;
		/*
		 * PMR_PPM_ALL_LOWEST
		 */
		struct ppm_all_lowest_req {
			int		mode;
		} ppm_all_lowest_req;
		/*
		 * PMR_PPM_LOCK_POWER, PMR_PPM_TRY_LOCK_POWER
		 */
		struct ppm_lock_power_req {
			dev_info_t	*who;
			int		*circp;
		} ppm_lock_power_req;
		/*
		 * PMR_PPM_UNLOCK_POWER
		 */
		struct ppm_unlock_power_req {
			dev_info_t	*who;
			int		circ;
		} ppm_unlock_power_req;
		/*
		 * PMR_PPM_POWER_LOCK_OWNER
		 */
		struct ppm_power_lock_owner_req {
			dev_info_t	*who;
			kthread_t	*owner;
		} ppm_power_lock_owner_req;
		/*
		 * PMR_PPM_POWER_ENTER_SX
		 */
		struct ppm_power_enter_sx_req {
			int	sx_state;	/* S3, S4 */
			int	test_point;	/* test point */
			uint64_t wakephys;	/* restart vector phys addr */
			void *psr;		/* PSM (apic) state buffer */
		} ppm_power_enter_sx_req;
		/*
		 * PMR_PPM_SEARCH_LIST
		 */
		struct ppm_search_list {
			pm_searchargs_t *searchlist;
			int		result;
		} ppm_search_list_req;
	} req;
} power_req_t;

#define	S3	3
#define	S4	4

extern int cpr_test_point;
extern major_t cpr_device;

#define	LOOP_BACK_NONE	0
#define	LOOP_BACK_PASS	1
#define	LOOP_BACK_FAIL	2
#define	FORCE_SUSPEND_TO_RAM	3
#define	DEVICE_SUSPEND_TO_RAM	4

/*
 * Struct passed as arg to appm_ioctl
 */
typedef struct s3_args {
	int		s3a_state;	/* S3, S4 */
	int		s3a_test_point;	/* test point */
	uint64_t	s3a_wakephys;	/* restart vector physical addr */
	void		*s3a_psr;	/* apic state save buffer */
} s3a_t;

/*
 * Structure used by the following bus_power operations:
 *
 *	BUS_POWER_PRE_NOTIFICATION
 *	BUS_POWER_POST_NOTIFICATION
 *	BUS_POWER_CHILD_PWRCHG
 */
typedef struct pm_bp_child_pwrchg {
	dev_info_t	*bpc_dip;	/* dip of the target device */
	char		*bpc_path;	/* path to the target device */
	int		bpc_comp;	/* component changing power */
	int		bpc_olevel;	/* old power level */
	int		bpc_nlevel;	/* new power level */
	void		*bpc_private;	/* PM framework private */
} pm_bp_child_pwrchg_t;

/*
 * Structure used by the BUS_POWER_NEXUS_PWRUP operation
 */
typedef struct pm_bp_nexus_pwrup {
	dev_info_t	*bpn_dip;	/* dip of the nexus device */
	int		bpn_comp;	/* component powering up */
	int		bpn_level;	/* new power level */
	void		*bpn_private;	/* PM framework private */
} pm_bp_nexus_pwrup_t;

/*
 * Structure used by the BUS_POWER_HAS_CHANGED operation
 */
typedef struct pm_bp_has_changed {
	dev_info_t	*bphc_dip;	/* dip of the target device */
	char		*bphc_path;	/* path to the target device */
	int		bphc_comp;	/* component changing power */
	int		bphc_olevel;	/* old power level */
	int		bphc_nlevel;	/* new power level */
	void		*bphc_private;	/* PM framework private */
} pm_bp_has_changed_t;

/*
 * Commands indicating which activity is requiring an
 * update to the noinvol counters.
 */
#define	PM_BP_NOINVOL_ATTACH	1
#define	PM_BP_NOINVOL_DETACH	2
#define	PM_BP_NOINVOL_REMDRV	3
#define	PM_BP_NOINVOL_CFB	4
#define	PM_BP_NOINVOL_POWER	5

/*
 * Structure used by the BUS_POWER_NOINVOL operation.
 */
typedef struct pm_bp_noinvol {
	dev_info_t	*bpni_dip;	/* dip of the target device */
	char		*bpni_path;	/* path to the target device */
	int		bpni_cmd;	/* how to update the counters */
	int		bpni_volpmd;	/* volpmd of target device */
	int		bpni_wasvolpmd;	/* whether to update volpmd */
	void		*bpni_private;	/* PM framework private */
} pm_bp_noinvol_t;

/*
 * This struct is used by the code that makes a PMR_PPM_SET_POWER request
 * to ppm. Devices that changed power other than the primary device (which
 * was requested) are passed back to the pm framework through this
 * structure.
 */
typedef struct pm_ppm_devlist {
	dev_info_t	*ppd_who;
	int		ppd_cmpt;
	int		ppd_old_level;
	int		ppd_new_level;
	struct pm_ppm_devlist	*ppd_next;
} pm_ppm_devlist_t;

/*
 * This struct is used by the code that brings up parents and notifies
 * ppm drivers across probe/attach/detach (pm_pre/post_probe/attach/detach())
 */
typedef struct pm_ppm_cookie {
	dev_info_t		*ppc_dip;	/* dip of target node */
	dev_info_t		*ppc_pdip;	/* parent's dip */
	dev_info_t		*ppc_ppm;	/* interested ppm driver */
	int			ppc_cmd;	/* attach/detach cmd */
} pm_ppm_cookie_t;

/*
 * This struct records one dependency (a device keeps another or others up)
 * pdr_size includes size of strings.
 */
typedef struct pm_dep_rec {
	char *pdr_keeper;		/* physpath of device keeping up */
	char *pdr_kept;			/* physpath or property name */
	char **pdr_kept_paths;		/* array of kept devices' paths */
	struct pm_dep_rec *pdr_next;	/* next dependency device */
	size_t pdr_size;		/* size to kmem_free */
	major_t pdr_major;		/* major of kept driver (not props) */
	int pdr_isprop;			/* true if kept is property name */
	int pdr_kept_count;		/* how many kept altogether */
	int pdr_satisfied;		/* true if in force (not properties) */
} pm_pdr_t;


/*
 * This struct records threshold information about a single component
 */
typedef struct pm_thresh_entry {
	int pte_numthresh;
	int *pte_thresh;
} pm_pte_t;

/*
 * Note that this header and its array of entry structs with their arrays
 * of thresholds and string storage for physpath are all kmem_alloced in one
 * chunk for easy freeing ptr_size is the size of that chunk
 */
typedef struct pm_thresh_rec {
	char			*ptr_physpath;	/* identifies node */
	struct pm_thresh_rec	*ptr_next;
	int			ptr_numcomps;	/* number of components */
	size_t			ptr_size;	/* total size for kmem_free */
	pm_pte_t 		*ptr_entries;
} pm_thresh_rec_t;

/*
 * pmi_dev_pm_state state bits:
 */

/*
 * a direct-pm device, not scanned, but controlled by a process
 */
#define	PM_DIRECT	0x1
/*
 * autopm is suspended while waiting to see if detach succeeds
 */
#define	PM_DETACHING	0x2

/*
 * An all_to_normal operation for an autopm device that is detaching, is
 * deferred in case the detach fails.
 */
#define	PM_ALLNORM_DEFERRED	0x4

#define	PM_GET_PM_INFO(dip) (DEVI(dip)->devi_pm_info)
#define	PM_GET_PM_SCAN(dip) (DEVI(dip)->devi_pm_scan)

#define	PM_NUMCMPTS(dip) (DEVI(dip)->devi_pm_num_components)
#define	PM_CP(dip, comp) (&DEVI(dip)->devi_pm_components[comp])

/*
 * Returns true if the device specified by dip is directly power managed
 */
#define	PM_ISDIRECT(dip) \
	(((pm_info_t *)PM_GET_PM_INFO(dip))->pmi_dev_pm_state & PM_DIRECT)

/*
 * Returns true if the device specified by dip is an old node for which we
 * provide backwards compatible behavior (e.g. no pm-components property).
 */
#define	PM_ISBC(dip) (DEVI(dip)->devi_pm_flags & PMC_BC)

/*
 * Returns true if we have skipped a dependency bringup on this dip.
 */
#define	PM_SKBU(dip) (DEVI(dip)->devi_pm_flags & PMC_SKIP_BRINGUP)

/*
 * Returns true if device specified by dip is a power manageable CPU.
 */
#define	PM_ISCPU(dip) (DEVI(dip)->devi_pm_flags & PMC_CPU_DEVICE)

/*
 * Returns true if cpupm is enabled.
 */
#define	PM_CPUPM_ENABLED (cpupm == PM_CPUPM_ENABLE)

/*
 * Returns true if is disabled.
 */
#define	PM_CPUPM_DISABLED (cpupm == PM_CPUPM_DISABLE)

/*
 * If (autopm is enabled and
 *      (CPUs are not disabled, or it isn't a cpu)) OR
 *    (CPUs are enabled and it is one)
 */
#define	PM_SCANABLE(dip) ((autopm_enabled && \
(!PM_CPUPM_DISABLED || !PM_ISCPU(dip))) || (PM_CPUPM_ENABLED && PM_ISCPU(dip)))

#define	PM_NOT_ALL_LOWEST	0x0	/* not all components are at lowest */
#define	PM_ALL_LOWEST		0x1	/* all components are at lowest lvl */

#define	PM_ADDR(dip)	(ddi_get_name_addr(dip) ? ddi_get_name_addr(dip) : "")
#define	PM_NAME(dip)	(ddi_binding_name(dip))
#define	PM_NODE(dip)	(ddi_node_name(dip))
#define	PM_INST(dip)	(ddi_get_instance(dip))
#define	PM_DEVICE(dip)	PM_NAME(dip), PM_ADDR(dip), PM_NODE(dip), PM_INST(dip)

#ifdef	DEBUG
/*
 * Flags passed to PMD to enable debug printfs.  If the same flag is set in
 * pm_debug below then the message is printed.  The most generally useful
 * ones are the first 3 or 4.
 */
#define	PMD_ERROR	0x0000001
#define	PMD_FAIL	0x0000002
#define	PMD_IOCTL	0x0000004
#define	PMD_SCAN	0x0000008
#define	PMD_RESCAN	0x0000010
#define	PMD_REMINFO	0x0000020
#define	PMD_NAMETODIP	0x0000040
#define	PMD_CLOSE	0x0000080
#define	PMD_DIN		0x0000100	/* Dev Is Needed */
#define	PMD_PMC		0x0000200	/* for testing with sun4m pmc driver */
#define	PMD_PPM		0x0000400
#define	PMD_DEP		0x0000800	/* dependency processing */
#define	PMD_IDLEDOWN	0x0001000
#define	PMD_SET		0x0002000
#define	PMD_BRING	0x0004000
#define	PMD_ALLNORM	0x0008000
#define	PMD_REMDEV	0x0010000
#define	PMD_LEVEL	0x0020000
#define	PMD_THRESH	0x0040000
#define	PMD_DPM		0x0080000	/* Direct Power Management */
#define	PMD_NORM	0x0100000
#define	PMD_STATS	0x0200000
#define	PMD_DEREG	0x0400000
#define	PMD_KEEPS	0x0800000
#define	PMD_KIDSUP	0x1000000
#define	PMD_TCHECK	0x2000000
#define	PMD_NOINVOL	0x4000000
#define	PMD_CFB		0x8000000	/* console fb pm */
#define	PMD_DHR		0x10000000	/* driver hold/rele changes */
#define	PMD_PIL		0x20000000	/* print out PIL when calling power */
#define	PMD_PHC		0x40000000	/* pm_power_has_changed messages */
#define	PMD_LOCK	0x80000000
#define	PMD_SX		0x80000000	/* ACPI S[1234] states */
#define	PMD_PROTO	PMD_SX		/* and other Prototype stuff */

extern uint_t	pm_debug;
extern uint_t	pm_divertdebug;
/*PRINTFLIKE1*/
extern void	pm_log(const char *fmt, ...) __KPRINTFLIKE(1);

#if !defined(__sparc)
/*
 * On non-sparc machines, PMDDEBUG isn't as big a deal as Sparc, so we
 * define PMDDEUG here for use on non-sparc platforms.
 */
#define	PMDDEBUG
#endif /* !__sparc */

#ifdef PMDDEBUG
#define	PMD(level, arglist) { 			\
	if (pm_debug & (level)) {		\
		pm_log arglist;			\
	}					\
}
#else /* !PMDDEBUG */
#define	PMD(level, arglist)	((void)0);
#endif /* PMDDEBUG */
#ifndef	sparc
extern clock_t pt_sleep;
/* code is char hex number to display on POST LED */
#define	PT(code) {outb(0x80, (char)code); drv_usecwait(pt_sleep); }
#else
#define	PT(code)
#endif
#else
#define	PMD(level, arglist)
#define	PT(code)
#endif
/*
 * Code	Value	Indication
 *
 */
#define	PT_SPL7		0x01	/* pm_suspend spl7 */
#define	PT_PMSRET	0x02	/* pm_suspend returns */
#define	PT_PPMCTLOP	0x03	/* invoking ppm_ctlops */
#define	PT_ACPISDEV	0x04	/* acpi suspend devices */
#define	PT_IC		0x05	/* acpi intr_clear */
#define	PT_1to1		0x06	/* 1:1 mapping */
#define	PT_SC		0x07	/* save context */
#define	PT_SWV		0x08	/* set waking vector */
#define	PT_SWV_FAIL	0x09	/* set waking vector failed */
#define	PT_EWE		0x0a	/* enable wake events */
#define	PT_EWE_FAIL	0x0b	/* enable wake events failed */
#define	PT_RTCW		0x0c	/* setting rtc wakeup */
#define	PT_RTCW_FAIL	0x0d	/* setting rtc wakeup failed */
#define	PT_TOD		0x0e	/* setting tod */
#define	PT_SXP		0x0f	/* sx prep */
#define	PT_SXE		0x10	/* sx enter */
#define	PT_SXE_FAIL	0x11	/* sx enter failed */
#define	PT_INSOM	0x12	/* insomnia label */
#define	PT_WOKE		0x20	/* woke up */
#define	PT_UNDO1to1	0x21	/* Undo 1:1 mapping */
#define	PT_LSS		0x22	/* leave sleep state */
#define	PT_LSS_FAIL	0x23	/* leave sleep state failed */
#define	PT_DPB		0x24	/* disable power button */
#define	PT_DPB_FAIL	0x25	/* disable power button failed */
#define	PT_DRTC_FAIL	0x26	/* disable rtc fails */
#define	PT_ACPIREINIT	0x27	/* reinit apic */
#define	PT_ACPIRESTORE	0x28	/* restore apic */
#define	PT_INTRRESTORE	0x28	/* restore interrupts */
#define	PT_RESDEV	0x2a	/* ressume acpi devices */
#define	PT_CPU		0x2b	/* init_cpu_syscall */
#define	PT_PRESUME	0x30	/* pm_resume entered */
#define	PT_RSUS		0x31	/* pm_resume "suspended" */
#define	PT_RKERN	0x32	/* pm_resume "kernel" */
#define	PT_RDRV		0x33	/* pm_resume "driver" */
#define	PT_RDRV_FAIL	0x34	/* pm_resume "driver" failed */
#define	PT_RRNOINVOL	0x35	/* pm_resume "reattach_noinvol" */
#define	PT_RUSER	0x36	/* pm_resume "user" */
#define	PT_RAPMSIG	0x37	/* pm_resume APM/SRN signal */
#define	PT_RMPO		0x38	/* pm_resume "mp_online" */
#define	PT_RDONE	0x39	/* pm_resume done */

extern void	pm_detaching(dev_info_t *);
extern void	pm_detach_failed(dev_info_t *);
extern int	pm_power(dev_info_t *, int, int);
extern int	pm_unmanage(dev_info_t *);
extern void	pm_rem_info(dev_info_t *);
extern int	pm_get_norm_pwrs(dev_info_t *, int **, size_t *);
extern dev_info_t *pm_name_to_dip(char *, int);
extern int	pm_power_up(dev_info_t *, int, int, int, pm_info_t *);
extern int	pm_default_idle_threshold;
extern void	pm_set_device_threshold(dev_info_t *, int, int);
extern int	pm_valid_power(dev_info_t *, int, int);
extern void	pm_lock_power(dev_info_t *, int *);
extern void	pm_unlock_power(dev_info_t *, int);
extern int	pm_try_locking_power(dev_info_t *, int *);
extern void	pm_lock_power_single(dev_info_t *, int *);
extern void	pm_unlock_power_single(dev_info_t *, int);
extern int	pm_try_locking_power_single(dev_info_t *, int *);
extern int	pm_isbc(dev_info_t *dip);
extern int	pm_isdirect(dev_info_t *dip);
extern int	pm_ctlops(dev_info_t *d, dev_info_t *r, ddi_ctl_enum_t o,
			void *a, void *v);
extern int	pm_noinvol_detached(char *);
extern int	pm_init_child(dev_info_t *);
extern int	pm_uninit_child(dev_info_t *);

extern int	pm_all_to_normal(dev_info_t *, pm_canblock_t);
extern int	pm_set_power(dev_info_t *, int, int, int, pm_canblock_t, int,
			int *);
extern void	pm_scan_init(dev_info_t *dip);
extern void	pm_scan_fini(dev_info_t *dip);
extern void	pm_scan_stop(dev_info_t *dip);
extern int	pm_scan_stop_walk(dev_info_t *dip, void *);
extern void	pm_scan(void *);
extern time_t	pm_scan_dev(dev_info_t *dip);
extern void	pm_rescan(void *);
extern int	pm_rescan_walk(dev_info_t *, void *);
extern void	pm_forget_power_level(dev_info_t *);
extern int	pm_pre_config(dev_info_t *, char *);
extern int	pm_pre_unconfig(dev_info_t *, int, int *, char *);
extern void	pm_post_config(dev_info_t *, char *);
extern void	pm_post_unconfig(dev_info_t *, int, char *);
extern void	pm_pre_probe(dev_info_t *, pm_ppm_cookie_t *);
extern void	pm_post_probe(pm_ppm_cookie_t *, int, int);
extern void	pm_post_attach(pm_ppm_cookie_t *, int);
extern void	pm_pre_attach(dev_info_t *, pm_ppm_cookie_t *,
			ddi_attach_cmd_t);
extern void	pm_pre_detach(dev_info_t *, ddi_detach_cmd_t,
			pm_ppm_cookie_t *);
extern void	pm_post_detach(pm_ppm_cookie_t *, int);
extern int	pm_powerup(dev_info_t *);
extern int	pm_all_at_normal(dev_info_t *);
extern int	pm_busop_bus_power(dev_info_t *, void *,
		    pm_bus_power_op_t, void *, void *);
extern void	pm_hold_power(dev_info_t *);
extern void	pm_rele_power(dev_info_t *);
extern void	pm_driver_removed(major_t);
extern void	pm_borrow_lock(kthread_t *);
extern void	pm_return_lock(void);
extern int	pm_reattach_noinvol(void);
extern void	pm_reattach_noinvol_fini();
extern void	pm_restore_direct_levels(void);
extern void	pm_save_direct_levels(void);
extern void	pm_cfb_setup(const char *);
extern void	pm_proceed(dev_info_t *, int, int, int);
extern void	pm_get_timestamps(dev_info_t *, time_t *);
extern void	pm_deregister_watcher(int, dev_info_t *);
extern void	pm_dispatch_to_dep_thread(int, char *, char *, int, int *, int);
extern int	e_pm_valid_comp(dev_info_t *, int, pm_component_t **);
extern int	e_pm_valid_info(dev_info_t *, pm_info_t **);
extern int	e_pm_valid_power(dev_info_t *, int, int);
extern void	pm_init_locks(void);
extern int	pm_register_ppm(int (*)(dev_info_t *), dev_info_t *);
extern int	pm_is_cfb(dev_info_t *);
#ifdef	DEBUG
extern int	pm_cfb_is_up(void);
#endif

#ifdef DIPLOCKDEBUG
#define	PM_LOCK_DIP(dip)	{ PMD(PMD_LOCK, ("dip lock %s@%s(%s#%d) " \
				    "%s %d\n", PM_DEVICE(dip),		  \
				    __FILE__, __LINE__)) 		  \
				    mutex_enter(&DEVI(dip)->devi_pm_lock); }
#define	PM_UNLOCK_DIP(dip)	{ PMD(PMD_LOCK, ("dip unlock %s@%s(%s#%d) " \
				    "%s %d\n", PM_DEVICE(dip),		    \
				    __FILE__, __LINE__))		    \
				    mutex_exit(&DEVI(dip)->devi_pm_lock); }
#else
#define	PM_LOCK_DIP(dip)	mutex_enter(&DEVI(dip)->devi_pm_lock)
#define	PM_UNLOCK_DIP(dip)	mutex_exit(&DEVI(dip)->devi_pm_lock)
#endif

/*
 * These are the same DEBUG or not
 */
#define	PM_LOCK_BUSY(dip)	mutex_enter(&DEVI(dip)->devi_pm_busy_lock)
#define	PM_UNLOCK_BUSY(dip)	mutex_exit(&DEVI(dip)->devi_pm_busy_lock)
#define	PM_LOCK_POWER(dip, circp)	pm_lock_power(dip, circp)
#define	PM_UNLOCK_POWER(dip, circ)	pm_unlock_power(dip, circ)
#define	PM_TRY_LOCK_POWER(dip, circp)	pm_try_locking_power(dip, circp)
#define	PM_IAM_LOCKING_DIP(dip)	(mutex_owned(&DEVI(dip)->devi_pm_lock))

#define	PM_DEFAULT_SYS_IDLENESS	1800	/* 30 minutes */

/*
 * Codes put into the pr_retval field of pm_rsvp_t that tell pm_block()
 * how to proceed
 */
#define	PMP_SUCCEED	0x1	/* return success, the process did it */
#define	PMP_FAIL	0x2	/* return fail, process did something else */
#define	PMP_RELEASE	0x3	/* let it go, the process has lost interest */
				/* also arg to pm_proceed to signal this */
/*
 * Values of "style" for e_pm_manage and pm_premanage
 */
#define	PM_STYLE_NEW		0
#define	PM_STYLE_UNKNOWN	1

/*
 * Arg passed to pm_proceed that results in PMP_SUCCEED or PMP_FAIL being set
 * in pr_retval depending on what is pending
 */
#define	PMP_SETPOWER	0x4

#define	PM_MAX_CLONE	256

typedef struct pm_rsvp {
	dev_info_t	*pr_dip;
	int		pr_comp;
	int		pr_newlevel;
	int		pr_oldlevel;
	kcondvar_t	pr_cv;		/* a place to sleep */
	int		pr_retval;	/* what to do when you wake up */
	struct pm_rsvp	*pr_next;
	struct pm_rsvp	*pr_prev;
} pm_rsvp_t;

typedef struct psce {	/* pm_state_change_entries */
	struct pm_state_change		*psce_first;
	struct pm_state_change		*psce_in;
	struct pm_state_change		*psce_out;
	struct pm_state_change		*psce_last;
	int				psce_overruns;
	int				psce_references;
	kmutex_t			psce_lock;
} psce_t;

typedef struct pscc {			/* pm_state_change_control */
	int		pscc_clone;
	dev_info_t	*pscc_dip;
	psce_t		*pscc_entries;
	struct pscc	*pscc_next;
	struct pscc	*pscc_prev;
} pscc_t;

#define	PSCCOUNT 128	/* number of state change entries kept per process */

/*
 * Struct used to track the existance of devices exporting the
 * no-involuntary-power-cycles property, and remember things from their
 * devinfo node for later attach.
 */
typedef struct pm_noinvol {
	struct pm_noinvol	*ni_next;
	char			*ni_path;
	major_t			ni_major;	/* for attaching at cpr time */
	uint_t			ni_flags;	/* selected PMC_* values */
	uint_t			ni_noinvolpm;	/* saved noinvolpm count */
	uint_t			ni_volpmd;	/* saved volpmd count */
	uint_t			ni_wasvolpmd;	/* was vol pm'd at detach */
	size_t			ni_size;
	int			ni_persistent;	/* still around */
} pm_noinvol_t;

#define	PMID_IOCTIMER		0x1		/* pm_ioctl sets during timer */
#define	PMID_CFBTIMER		0x2		/* cfb sets during timer */
#define	PMID_IOCSCAN		0x4		/* pm_ioctl sets during scan */
#define	PMID_CFBSCAN		0x8		/* cfb sets during scan */

#define	PMID_IOC		(PMID_IOCTIMER | PMID_IOCSCAN)
#define	PMID_CFB		(PMID_CFBTIMER | PMID_CFBSCAN)
#define	PMID_TIMERS		(PMID_IOCTIMER | PMID_CFBTIMER)
#define	PMID_SCANS		(PMID_IOCSCAN | PMID_CFBSCAN)
#define	PMID_SCANS_SHIFT	2
#define	PMID_SET_SCANS(pmid)	(pmid) |= (((pmid) & PMID_TIMERS) <<	\
				    PMID_SCANS_SHIFT);
#define	PMID_IS_IOC(pmid)	((pmid) & PMID_IOC)
#define	PMID_IS_CFB(pmid, dip)	(((pmid) & PMID_CFB) &&			\
				    (DEVI(dip)->devi_pm_flags &		\
				    (PMC_DEF_THRESH | PMC_NEXDEF_THRESH)))
#define	PM_IS_PID(dip)	(PMID_IS_IOC(PM_GET_PM_SCAN(dip)->ps_idle_down) || \
	PMID_IS_CFB(PM_GET_PM_SCAN(dip)->ps_idle_down, dip))
#define	PM_IS_CFB(dip)		(DEVI(dip)->devi_pm_flags & PMC_CONSOLE_FB)
#define	PM_KUC(dip)		(DEVI(dip)->devi_pm_kidsupcnt)
#define	PM_CURPOWER(dip, comp)	cur_power(PM_CP(dip, comp))

#define	PM_WANTS_NOTIFICATION(dip)					\
	(DEVI(dip)->devi_pm_flags & PMC_WANTS_NOTIFY)

#define	PM_HAS_BUS_POWER(dip)						\
	((DEVI(dip)->devi_ops->devo_bus_ops != NULL) &&			\
	(DEVI(dip)->devi_ops->devo_bus_ops->busops_rev >= BUSO_REV_7) &&\
	(DEVI(dip)->devi_ops->devo_bus_ops->bus_power != NULL))

#define	PM_BUS_POWER_FUNC(dip)						\
	DEVI(dip)->devi_ops->devo_bus_ops->bus_power

/*
 * Structure used to pass down sunpm's private data variables
 * through the bus_power bus_op calls
 */
typedef struct pm_sp_misc {
	pm_canblock_t   pspm_canblock;
	int pspm_scan;
	int *pspm_errnop;
	int pspm_direction;
} pm_sp_misc_t;

/*
 * This structure is used in validating that the power level
 * of the descendents are off, while a device is powered off.
 */
typedef struct pm_desc_pwrchk {
	dev_info_t *pdpc_dip;
	int pdpc_par_involved;
} pm_desc_pwrchk_t;


/*
 * These defines are used by pm_trans_check() to calculate time.
 * Mostly copied from "tzfile.h".
 */
#define	EPOCH_YEAR		1970
#define	SECSPERMIN		60
#define	MINSPERHOUR		60
#define	HOURSPERDAY		24
#define	DAYSPERWEEK		7
#define	DAYSPERNYEAR		365
#define	SECSPERHOUR		(SECSPERMIN * MINSPERHOUR)
#define	SECSPERDAY		(SECSPERHOUR * HOURSPERDAY)
#define	DC_SPY			(SECSPERDAY * DAYSPERNYEAR)
#define	DC_SPW			(SECSPERDAY * DAYSPERWEEK)
#define	DC_SPD			SECSPERDAY

#define	DC_SCSI_YEAR_LEN	4		/* YYYY */
#define	DC_SCSI_WEEK_LEN	2		/* WW */
#define	DC_SCSI_NPY		5		/* # power-cycle years */

#endif	/* _KERNEL */

#ifdef	__cplusplus
}
#endif

#endif /* _SYS_EPM_H */