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 */
|