summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/sys/pcie_pwr.h
blob: db2aade2297d6a5347ee9e9f8ef33bf4c9155814 (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
/*
 * 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 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _SYS_PCIE_PWR_H
#define	_SYS_PCIE_PWR_H

#ifdef	__cplusplus
extern "C" {
#endif

/* index of counters for each level */
#define	PCIE_D3_INDEX		PM_LEVEL_D3
#define	PCIE_D2_INDEX 		PM_LEVEL_D2
#define	PCIE_D1_INDEX		PM_LEVEL_D1
#define	PCIE_D0_INDEX		PM_LEVEL_D0
#define	PCIE_UNKNOWN_INDEX	PM_LEVEL_D0 + 1
#define	PCIE_MAX_PWR_LEVELS 	5

/*
 * PCIe nexus power management data structure
 */
typedef struct pcie_pwr {
	/*
	 * general data structure fields
	 */
	kmutex_t	pwr_lock;	/* to protect the counters and  */
					/* power level change		*/
	int		pwr_pmcaps;	/* pm capability */
	ddi_acc_handle_t pwr_conf_hdl;	/* for config access */
	uint8_t		pwr_pmcsr_offset; /* PMCSR offset */
	int		pwr_link_lvl;	/* link level. Currently not used */
	int		pwr_func_lvl;	/* function power level */
	int		pwr_flags;	/* flags */
	int		pwr_hold;	/* for temporarily keeping busy */
	/*
	 * counters to keep track of child's power level.
	 * D3,D2,D1,D0 and unknown respectively.
	 */
	int		pwr_counters[PCIE_MAX_PWR_LEVELS];

} pcie_pwr_t;

typedef struct pcie_pwr_child {
	/*
	 * Per child dip counters decsribing
	 * a child's components
	 */
	int	pwr_child_counters[PCIE_MAX_PWR_LEVELS];
} pcie_pwr_child_t;

typedef struct pcie_pm {
	pcie_pwr_t	*pcie_pwr_p;	/* nexus PM info */
	pcie_pwr_child_t *pcie_par_pminfo; /* PM info created by the parent */
} pcie_pm_t;

#define	PCIE_PMINFO(dip)	\
	((pcie_pm_t *)(DEVI(dip)->devi_nex_pm))

#define	PCIE_NEXUS_PMINFO(dip)	\
	(PCIE_PMINFO(dip)->pcie_pwr_p)

#define	PCIE_PAR_PMINFO(dip)	\
	(PCIE_PMINFO(dip)->pcie_par_pminfo)

#define	PCIE_CHILD_COUNTERS(cdip)	\
	(PCIE_PAR_PMINFO(cdip)->pwr_child_counters)

#define	PCIE_SET_PMINFO(dip, pminfo_p)	\
	(DEVI(dip)->devi_nex_pm = (pminfo_p))

#define	PCIE_RESET_PMINFO(dip)	\
	(DEVI(dip)->devi_nex_pm = NULL)

#define	PCIE_IS_COMPS_COUNTED(cdip)	\
	(PCIE_PMINFO(cdip) && PCIE_PAR_PMINFO(cdip))

/*
 * pmcap field: device power management capability.
 * First 4 bits must indicate support for D3, D2, D1 and D0
 * respectively. Their bit position matches with their index
 * into the counters array.
 */
#define	PCIE_SUPPORTS_D3	0x01 /* Supports D1 */
#define	PCIE_SUPPORTS_D2	0x02 /* Supports D2 */
#define	PCIE_SUPPORTS_D1	0x04 /* Supports D2 */
#define	PCIE_SUPPORTS_D0	0x08 /* Supports D2 */
#define	PCIE_L2_CAP		0x10 /* if with Vaux, optional */
#define	PCIE_L0s_L1_CAP		0x20 /* ASPM, L0s must, L1 optional */

#define	PCIE_DEFAULT_LEVEL_SUPPORTED	(PCIE_SUPPORTS_D3 | PCIE_SUPPORTS_D0)

#define	PCIE_LEVEL_SUPPORTED(pmcaps, level)	\
	((pmcaps) & (1 << (level)))

#define	PCIE_SUPPORTS_DEVICE_PM(dip)	\
	(ddi_prop_exists(DDI_DEV_T_ANY, (dip),	\
	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "pm-components") == 1)
/*
 * flags field
 */
#define	PCIE_ASPM_ENABLED		0x01
#define	PCIE_SLOT_LOADED		0x02
#define	PCIE_PM_BUSY			0x04
#define	PCIE_NO_CHILD_PM		0x08

#define	PM_LEVEL_L3	0
#define	PM_LEVEL_L2	1
#define	PM_LEVEL_L1	2
#define	PM_LEVEL_L0	3

/* ioctl definitions for ppm drivers */
#define	PPMREQ			(('P' << 24) | ('M' << 16))
#define	PPMREQ_MASK		0xffff
#define	PPMREQ_PRE_PWR_OFF	(PPMREQ | 1)
#define	PPMREQ_PRE_PWR_ON	(PPMREQ | 2)
#define	PPMREQ_POST_PWR_ON	(PPMREQ | 3)

/* settle time in microseconds before PCI operation */
#define	PCI_CLK_SETTLE_TIME	10000

/*
 * Interface with other parts of the driver(s) code
 */

/*
 * We link pcie_pwr.o into several drivers (px, pcieb, pcieb_bcm, pcieb_plx),
 * which causes the symbols below to be duplicated.  This isn't an issue in
 * practice, since they aren't used from outside the module that they're
 * part of.  However, lint does not know this, and when it does global
 * crosschecks for the kernel, it complains.  To prevent this, we rename the
 * symbols to driver-specific names when we're doing a lint run.
 */

#if defined(lint)
#if defined(PX_MOD_NAME)
#define	pwr_common_setup	PX_MOD_NAME##_pwr_common_setup
#define	pwr_common_teardown	PX_MOD_NAME##_pwr_common_teardown
#define	pcie_bus_power		PX_MOD_NAME##_pcie_bus_power
#define	pcie_power		PX_MOD_NAME##_pcie_power
#define	pcie_pm_add_child	PX_MOD_NAME##_pcie_pm_add_child
#define	pcie_pm_remove_child	PX_MOD_NAME##_pcie_pm_remove_child
#define	pcie_pwr_suspend	PX_MOD_NAME##_pcie_pwr_suspend
#define	pcie_pwr_resume		PX_MOD_NAME##_pcie_pwr_resume
#define	pcie_pm_hold		PX_MOD_NAME##_pcie_pm_hold
#define	pcie_pm_release		PX_MOD_NAME##_pcie_pm_release
#endif /* PX_MOD_NAME */

#if defined(PX_PLX)
#define	pwr_common_setup	PX_PLX##_pwr_common_setup
#define	pwr_common_teardown	PX_PLX##_pwr_common_teardown
#define	pcie_bus_power		PX_PLX##_pcie_bus_power
#define	pcie_power		PX_PLX##_pcie_power
#define	pcie_pm_add_child	PX_PLX##_pcie_pm_add_child
#define	pcie_pm_remove_child	PX_PLX##_pcie_pm_remove_child
#define	pcie_pwr_suspend	PX_PLX##_pcie_pwr_suspend
#define	pcie_pwr_resume		PX_PLX##_pcie_pwr_resume
#define	pcie_pm_hold		PX_PLX##_pcie_pm_hold
#define	pcie_pm_release		PX_PLX##_pcie_pm_release
#endif /* PX_PLX */
#endif /* lint */

extern int pcie_plat_pwr_setup(dev_info_t *dip);
extern void pcie_plat_pwr_teardown(dev_info_t *dip);
extern int pwr_common_setup(dev_info_t *dip);
extern void pwr_common_teardown(dev_info_t *dip);
extern int pcie_bus_power(dev_info_t *dip, void *impl_arg, pm_bus_power_op_t op,
    void *arg, void *result);
extern int pcie_power(dev_info_t *dip, int component, int level);

extern int pcie_pm_add_child(dev_info_t *dip, dev_info_t *cdip);
extern int pcie_pm_remove_child(dev_info_t *dip, dev_info_t *cdip);
extern int pcie_pwr_suspend(dev_info_t *dip);
extern int pcie_pwr_resume(dev_info_t *dip);
extern int pcie_pm_hold(dev_info_t *dip);
extern void pcie_pm_release(dev_info_t *dip);

#ifdef	__cplusplus
}
#endif

#endif	/* _SYS_PCIE_PWR_H */