diff options
Diffstat (limited to 'drivers/pci/hotplug/shpchp_hpc.c')
-rw-r--r-- | drivers/pci/hotplug/shpchp_hpc.c | 861 |
1 files changed, 378 insertions, 483 deletions
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 66123cf4dea..45facaad39b 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c | |||
@@ -90,77 +90,94 @@ | |||
90 | #define MRLSENSOR 0x40000000 | 90 | #define MRLSENSOR 0x40000000 |
91 | #define ATTN_BUTTON 0x80000000 | 91 | #define ATTN_BUTTON 0x80000000 |
92 | 92 | ||
93 | /* Slot Status Field Definitions */ | 93 | /* |
94 | /* Slot State */ | 94 | * Interrupt Locator Register definitions |
95 | #define PWR_ONLY 0x0001 | 95 | */ |
96 | #define ENABLED 0x0002 | 96 | #define CMD_INTR_PENDING (1 << 0) |
97 | #define DISABLED 0x0003 | 97 | #define SLOT_INTR_PENDING(i) (1 << (i + 1)) |
98 | |||
99 | /* Power Indicator State */ | ||
100 | #define PWR_LED_ON 0x0004 | ||
101 | #define PWR_LED_BLINK 0x0008 | ||
102 | #define PWR_LED_OFF 0x000c | ||
103 | |||
104 | /* Attention Indicator State */ | ||
105 | #define ATTEN_LED_ON 0x0010 | ||
106 | #define ATTEN_LED_BLINK 0x0020 | ||
107 | #define ATTEN_LED_OFF 0x0030 | ||
108 | |||
109 | /* Power Fault */ | ||
110 | #define pwr_fault 0x0040 | ||
111 | |||
112 | /* Attention Button */ | ||
113 | #define ATTEN_BUTTON 0x0080 | ||
114 | |||
115 | /* MRL Sensor */ | ||
116 | #define MRL_SENSOR 0x0100 | ||
117 | |||
118 | /* 66 MHz Capable */ | ||
119 | #define IS_66MHZ_CAP 0x0200 | ||
120 | |||
121 | /* PRSNT1#/PRSNT2# */ | ||
122 | #define SLOT_EMP 0x0c00 | ||
123 | |||
124 | /* PCI-X Capability */ | ||
125 | #define NON_PCIX 0x0000 | ||
126 | #define PCIX_66 0x1000 | ||
127 | #define PCIX_133 0x3000 | ||
128 | #define PCIX_266 0x4000 /* For PI = 2 only */ | ||
129 | #define PCIX_533 0x5000 /* For PI = 2 only */ | ||
130 | |||
131 | /* SHPC 'write' operations/commands */ | ||
132 | |||
133 | /* Slot operation - 0x00h to 0x3Fh */ | ||
134 | |||
135 | #define NO_CHANGE 0x00 | ||
136 | |||
137 | /* Slot state - Bits 0 & 1 of controller command register */ | ||
138 | #define SET_SLOT_PWR 0x01 | ||
139 | #define SET_SLOT_ENABLE 0x02 | ||
140 | #define SET_SLOT_DISABLE 0x03 | ||
141 | 98 | ||
142 | /* Power indicator state - Bits 2 & 3 of controller command register*/ | 99 | /* |
143 | #define SET_PWR_ON 0x04 | 100 | * Controller SERR-INT Register |
144 | #define SET_PWR_BLINK 0x08 | 101 | */ |
145 | #define SET_PWR_OFF 0x0C | 102 | #define GLOBAL_INTR_MASK (1 << 0) |
103 | #define GLOBAL_SERR_MASK (1 << 1) | ||
104 | #define COMMAND_INTR_MASK (1 << 2) | ||
105 | #define ARBITER_SERR_MASK (1 << 3) | ||
106 | #define COMMAND_DETECTED (1 << 16) | ||
107 | #define ARBITER_DETECTED (1 << 17) | ||
108 | #define SERR_INTR_RSVDZ_MASK 0xfffc0000 | ||
146 | 109 | ||
147 | /* Attention indicator state - Bits 4 & 5 of controller command register*/ | 110 | /* |
148 | #define SET_ATTN_ON 0x010 | 111 | * Logical Slot Register definitions |
149 | #define SET_ATTN_BLINK 0x020 | 112 | */ |
150 | #define SET_ATTN_OFF 0x030 | 113 | #define SLOT_REG(i) (SLOT1 + (4 * i)) |
114 | |||
115 | #define SLOT_STATE_SHIFT (0) | ||
116 | #define SLOT_STATE_MASK (3 << 0) | ||
117 | #define SLOT_STATE_PWRONLY (1) | ||
118 | #define SLOT_STATE_ENABLED (2) | ||
119 | #define SLOT_STATE_DISABLED (3) | ||
120 | #define PWR_LED_STATE_SHIFT (2) | ||
121 | #define PWR_LED_STATE_MASK (3 << 2) | ||
122 | #define ATN_LED_STATE_SHIFT (4) | ||
123 | #define ATN_LED_STATE_MASK (3 << 4) | ||
124 | #define ATN_LED_STATE_ON (1) | ||
125 | #define ATN_LED_STATE_BLINK (2) | ||
126 | #define ATN_LED_STATE_OFF (3) | ||
127 | #define POWER_FAULT (1 << 6) | ||
128 | #define ATN_BUTTON (1 << 7) | ||
129 | #define MRL_SENSOR (1 << 8) | ||
130 | #define MHZ66_CAP (1 << 9) | ||
131 | #define PRSNT_SHIFT (10) | ||
132 | #define PRSNT_MASK (3 << 10) | ||
133 | #define PCIX_CAP_SHIFT (12) | ||
134 | #define PCIX_CAP_MASK_PI1 (3 << 12) | ||
135 | #define PCIX_CAP_MASK_PI2 (7 << 12) | ||
136 | #define PRSNT_CHANGE_DETECTED (1 << 16) | ||
137 | #define ISO_PFAULT_DETECTED (1 << 17) | ||
138 | #define BUTTON_PRESS_DETECTED (1 << 18) | ||
139 | #define MRL_CHANGE_DETECTED (1 << 19) | ||
140 | #define CON_PFAULT_DETECTED (1 << 20) | ||
141 | #define PRSNT_CHANGE_INTR_MASK (1 << 24) | ||
142 | #define ISO_PFAULT_INTR_MASK (1 << 25) | ||
143 | #define BUTTON_PRESS_INTR_MASK (1 << 26) | ||
144 | #define MRL_CHANGE_INTR_MASK (1 << 27) | ||
145 | #define CON_PFAULT_INTR_MASK (1 << 28) | ||
146 | #define MRL_CHANGE_SERR_MASK (1 << 29) | ||
147 | #define CON_PFAULT_SERR_MASK (1 << 30) | ||
148 | #define SLOT_REG_RSVDZ_MASK (1 << 15) | (7 << 21) | ||
151 | 149 | ||
152 | /* Set bus speed/mode A - 0x40h to 0x47h */ | 150 | /* |
153 | #define SETA_PCI_33MHZ 0x40 | 151 | * SHPC Command Code definitnions |
152 | * | ||
153 | * Slot Operation 00h - 3Fh | ||
154 | * Set Bus Segment Speed/Mode A 40h - 47h | ||
155 | * Power-Only All Slots 48h | ||
156 | * Enable All Slots 49h | ||
157 | * Set Bus Segment Speed/Mode B (PI=2) 50h - 5Fh | ||
158 | * Reserved Command Codes 60h - BFh | ||
159 | * Vendor Specific Commands C0h - FFh | ||
160 | */ | ||
161 | #define SET_SLOT_PWR 0x01 /* Slot Operation */ | ||
162 | #define SET_SLOT_ENABLE 0x02 | ||
163 | #define SET_SLOT_DISABLE 0x03 | ||
164 | #define SET_PWR_ON 0x04 | ||
165 | #define SET_PWR_BLINK 0x08 | ||
166 | #define SET_PWR_OFF 0x0c | ||
167 | #define SET_ATTN_ON 0x10 | ||
168 | #define SET_ATTN_BLINK 0x20 | ||
169 | #define SET_ATTN_OFF 0x30 | ||
170 | #define SETA_PCI_33MHZ 0x40 /* Set Bus Segment Speed/Mode A */ | ||
154 | #define SETA_PCI_66MHZ 0x41 | 171 | #define SETA_PCI_66MHZ 0x41 |
155 | #define SETA_PCIX_66MHZ 0x42 | 172 | #define SETA_PCIX_66MHZ 0x42 |
156 | #define SETA_PCIX_100MHZ 0x43 | 173 | #define SETA_PCIX_100MHZ 0x43 |
157 | #define SETA_PCIX_133MHZ 0x44 | 174 | #define SETA_PCIX_133MHZ 0x44 |
158 | #define RESERV_1 0x45 | 175 | #define SETA_RESERVED1 0x45 |
159 | #define RESERV_2 0x46 | 176 | #define SETA_RESERVED2 0x46 |
160 | #define RESERV_3 0x47 | 177 | #define SETA_RESERVED3 0x47 |
161 | 178 | #define SET_PWR_ONLY_ALL 0x48 /* Power-Only All Slots */ | |
162 | /* Set bus speed/mode B - 0x50h to 0x5fh */ | 179 | #define SET_ENABLE_ALL 0x49 /* Enable All Slots */ |
163 | #define SETB_PCI_33MHZ 0x50 | 180 | #define SETB_PCI_33MHZ 0x50 /* Set Bus Segment Speed/Mode B */ |
164 | #define SETB_PCI_66MHZ 0x51 | 181 | #define SETB_PCI_66MHZ 0x51 |
165 | #define SETB_PCIX_66MHZ_PM 0x52 | 182 | #define SETB_PCIX_66MHZ_PM 0x52 |
166 | #define SETB_PCIX_100MHZ_PM 0x53 | 183 | #define SETB_PCIX_100MHZ_PM 0x53 |
@@ -174,81 +191,115 @@ | |||
174 | #define SETB_PCIX_66MHZ_533 0x5b | 191 | #define SETB_PCIX_66MHZ_533 0x5b |
175 | #define SETB_PCIX_100MHZ_533 0x5c | 192 | #define SETB_PCIX_100MHZ_533 0x5c |
176 | #define SETB_PCIX_133MHZ_533 0x5d | 193 | #define SETB_PCIX_133MHZ_533 0x5d |
194 | #define SETB_RESERVED1 0x5e | ||
195 | #define SETB_RESERVED2 0x5f | ||
177 | 196 | ||
178 | 197 | /* | |
179 | /* Power-on all slots - 0x48h */ | 198 | * SHPC controller command error code |
180 | #define SET_PWR_ON_ALL 0x48 | 199 | */ |
181 | |||
182 | /* Enable all slots - 0x49h */ | ||
183 | #define SET_ENABLE_ALL 0x49 | ||
184 | |||
185 | /* SHPC controller command error code */ | ||
186 | #define SWITCH_OPEN 0x1 | 200 | #define SWITCH_OPEN 0x1 |
187 | #define INVALID_CMD 0x2 | 201 | #define INVALID_CMD 0x2 |
188 | #define INVALID_SPEED_MODE 0x4 | 202 | #define INVALID_SPEED_MODE 0x4 |
189 | 203 | ||
190 | /* For accessing SHPC Working Register Set */ | 204 | /* |
205 | * For accessing SHPC Working Register Set via PCI Configuration Space | ||
206 | */ | ||
191 | #define DWORD_SELECT 0x2 | 207 | #define DWORD_SELECT 0x2 |
192 | #define DWORD_DATA 0x4 | 208 | #define DWORD_DATA 0x4 |
193 | #define BASE_OFFSET 0x0 | ||
194 | 209 | ||
195 | /* Field Offset in Logical Slot Register - byte boundary */ | 210 | /* Field Offset in Logical Slot Register - byte boundary */ |
196 | #define SLOT_EVENT_LATCH 0x2 | 211 | #define SLOT_EVENT_LATCH 0x2 |
197 | #define SLOT_SERR_INT_MASK 0x3 | 212 | #define SLOT_SERR_INT_MASK 0x3 |
198 | 213 | ||
199 | static spinlock_t hpc_event_lock; | ||
200 | |||
201 | DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ | 214 | DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ |
202 | static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */ | 215 | static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */ |
203 | static int ctlr_seq_num = 0; /* Controller sequenc # */ | 216 | static int ctlr_seq_num = 0; /* Controller sequenc # */ |
204 | static spinlock_t list_lock; | 217 | static spinlock_t list_lock; |
205 | 218 | ||
206 | static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs); | 219 | static atomic_t shpchp_num_controllers = ATOMIC_INIT(0); |
207 | 220 | ||
208 | static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds); | 221 | static irqreturn_t shpc_isr(int irq, void *dev_id, struct pt_regs *regs); |
222 | static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec); | ||
209 | static int hpc_check_cmd_status(struct controller *ctrl); | 223 | static int hpc_check_cmd_status(struct controller *ctrl); |
210 | 224 | ||
211 | /* This is the interrupt polling timeout function. */ | 225 | static inline u8 shpc_readb(struct controller *ctrl, int reg) |
212 | static void int_poll_timeout(unsigned long lphp_ctlr) | ||
213 | { | 226 | { |
214 | struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr; | 227 | return readb(ctrl->hpc_ctlr_handle->creg + reg); |
228 | } | ||
215 | 229 | ||
216 | DBG_ENTER_ROUTINE | 230 | static inline void shpc_writeb(struct controller *ctrl, int reg, u8 val) |
231 | { | ||
232 | writeb(val, ctrl->hpc_ctlr_handle->creg + reg); | ||
233 | } | ||
217 | 234 | ||
218 | if ( !php_ctlr ) { | 235 | static inline u16 shpc_readw(struct controller *ctrl, int reg) |
219 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 236 | { |
220 | return; | 237 | return readw(ctrl->hpc_ctlr_handle->creg + reg); |
221 | } | 238 | } |
222 | 239 | ||
223 | /* Poll for interrupt events. regs == NULL => polling */ | 240 | static inline void shpc_writew(struct controller *ctrl, int reg, u16 val) |
224 | shpc_isr( 0, (void *)php_ctlr, NULL ); | 241 | { |
242 | writew(val, ctrl->hpc_ctlr_handle->creg + reg); | ||
243 | } | ||
225 | 244 | ||
226 | init_timer(&php_ctlr->int_poll_timer); | 245 | static inline u32 shpc_readl(struct controller *ctrl, int reg) |
227 | if (!shpchp_poll_time) | 246 | { |
228 | shpchp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/ | 247 | return readl(ctrl->hpc_ctlr_handle->creg + reg); |
248 | } | ||
229 | 249 | ||
230 | start_int_poll_timer(php_ctlr, shpchp_poll_time); | 250 | static inline void shpc_writel(struct controller *ctrl, int reg, u32 val) |
231 | 251 | { | |
232 | return; | 252 | writel(val, ctrl->hpc_ctlr_handle->creg + reg); |
233 | } | 253 | } |
234 | 254 | ||
235 | /* This function starts the interrupt polling timer. */ | 255 | static inline int shpc_indirect_read(struct controller *ctrl, int index, |
236 | static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds) | 256 | u32 *value) |
237 | { | 257 | { |
238 | if (!php_ctlr) { | 258 | int rc; |
239 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 259 | u32 cap_offset = ctrl->cap_offset; |
240 | return; | 260 | struct pci_dev *pdev = ctrl->pci_dev; |
241 | } | 261 | |
262 | rc = pci_write_config_byte(pdev, cap_offset + DWORD_SELECT, index); | ||
263 | if (rc) | ||
264 | return rc; | ||
265 | return pci_read_config_dword(pdev, cap_offset + DWORD_DATA, value); | ||
266 | } | ||
267 | |||
268 | /* | ||
269 | * This is the interrupt polling timeout function. | ||
270 | */ | ||
271 | static void int_poll_timeout(unsigned long lphp_ctlr) | ||
272 | { | ||
273 | struct php_ctlr_state_s *php_ctlr = | ||
274 | (struct php_ctlr_state_s *)lphp_ctlr; | ||
275 | |||
276 | DBG_ENTER_ROUTINE | ||
277 | |||
278 | /* Poll for interrupt events. regs == NULL => polling */ | ||
279 | shpc_isr(0, php_ctlr->callback_instance_id, NULL); | ||
280 | |||
281 | init_timer(&php_ctlr->int_poll_timer); | ||
282 | if (!shpchp_poll_time) | ||
283 | shpchp_poll_time = 2; /* default polling interval is 2 sec */ | ||
242 | 284 | ||
243 | if ( ( seconds <= 0 ) || ( seconds > 60 ) ) | 285 | start_int_poll_timer(php_ctlr, shpchp_poll_time); |
244 | seconds = 2; /* Clamp to sane value */ | ||
245 | 286 | ||
246 | php_ctlr->int_poll_timer.function = &int_poll_timeout; | 287 | DBG_LEAVE_ROUTINE |
247 | php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr; /* Instance data */ | 288 | } |
248 | php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ; | ||
249 | add_timer(&php_ctlr->int_poll_timer); | ||
250 | 289 | ||
251 | return; | 290 | /* |
291 | * This function starts the interrupt polling timer. | ||
292 | */ | ||
293 | static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec) | ||
294 | { | ||
295 | /* Clamp to sane value */ | ||
296 | if ((sec <= 0) || (sec > 60)) | ||
297 | sec = 2; | ||
298 | |||
299 | php_ctlr->int_poll_timer.function = &int_poll_timeout; | ||
300 | php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr; | ||
301 | php_ctlr->int_poll_timer.expires = jiffies + sec * HZ; | ||
302 | add_timer(&php_ctlr->int_poll_timer); | ||
252 | } | 303 | } |
253 | 304 | ||
254 | static inline int shpc_wait_cmd(struct controller *ctrl) | 305 | static inline int shpc_wait_cmd(struct controller *ctrl) |
@@ -272,7 +323,7 @@ static inline int shpc_wait_cmd(struct controller *ctrl) | |||
272 | 323 | ||
273 | static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) | 324 | static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) |
274 | { | 325 | { |
275 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 326 | struct controller *ctrl = slot->ctrl; |
276 | u16 cmd_status; | 327 | u16 cmd_status; |
277 | int retval = 0; | 328 | int retval = 0; |
278 | u16 temp_word; | 329 | u16 temp_word; |
@@ -282,14 +333,8 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) | |||
282 | 333 | ||
283 | mutex_lock(&slot->ctrl->cmd_lock); | 334 | mutex_lock(&slot->ctrl->cmd_lock); |
284 | 335 | ||
285 | if (!php_ctlr) { | ||
286 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
287 | retval = -EINVAL; | ||
288 | goto out; | ||
289 | } | ||
290 | |||
291 | for (i = 0; i < 10; i++) { | 336 | for (i = 0; i < 10; i++) { |
292 | cmd_status = readw(php_ctlr->creg + CMD_STATUS); | 337 | cmd_status = shpc_readw(ctrl, CMD_STATUS); |
293 | 338 | ||
294 | if (!(cmd_status & 0x1)) | 339 | if (!(cmd_status & 0x1)) |
295 | break; | 340 | break; |
@@ -297,7 +342,7 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) | |||
297 | msleep(100); | 342 | msleep(100); |
298 | } | 343 | } |
299 | 344 | ||
300 | cmd_status = readw(php_ctlr->creg + CMD_STATUS); | 345 | cmd_status = shpc_readw(ctrl, CMD_STATUS); |
301 | 346 | ||
302 | if (cmd_status & 0x1) { | 347 | if (cmd_status & 0x1) { |
303 | /* After 1 sec and and the controller is still busy */ | 348 | /* After 1 sec and and the controller is still busy */ |
@@ -314,7 +359,7 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) | |||
314 | * command. | 359 | * command. |
315 | */ | 360 | */ |
316 | slot->ctrl->cmd_busy = 1; | 361 | slot->ctrl->cmd_busy = 1; |
317 | writew(temp_word, php_ctlr->creg + CMD); | 362 | shpc_writew(ctrl, CMD, temp_word); |
318 | 363 | ||
319 | /* | 364 | /* |
320 | * Wait for command completion. | 365 | * Wait for command completion. |
@@ -338,18 +383,12 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) | |||
338 | 383 | ||
339 | static int hpc_check_cmd_status(struct controller *ctrl) | 384 | static int hpc_check_cmd_status(struct controller *ctrl) |
340 | { | 385 | { |
341 | struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; | ||
342 | u16 cmd_status; | 386 | u16 cmd_status; |
343 | int retval = 0; | 387 | int retval = 0; |
344 | 388 | ||
345 | DBG_ENTER_ROUTINE | 389 | DBG_ENTER_ROUTINE |
346 | |||
347 | if (!ctrl->hpc_ctlr_handle) { | ||
348 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
349 | return -1; | ||
350 | } | ||
351 | 390 | ||
352 | cmd_status = readw(php_ctlr->creg + CMD_STATUS) & 0x000F; | 391 | cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F; |
353 | 392 | ||
354 | switch (cmd_status >> 1) { | 393 | switch (cmd_status >> 1) { |
355 | case 0: | 394 | case 0: |
@@ -378,37 +417,27 @@ static int hpc_check_cmd_status(struct controller *ctrl) | |||
378 | 417 | ||
379 | static int hpc_get_attention_status(struct slot *slot, u8 *status) | 418 | static int hpc_get_attention_status(struct slot *slot, u8 *status) |
380 | { | 419 | { |
381 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 420 | struct controller *ctrl = slot->ctrl; |
382 | u32 slot_reg; | 421 | u32 slot_reg; |
383 | u16 slot_status; | 422 | u8 state; |
384 | u8 atten_led_state; | ||
385 | 423 | ||
386 | DBG_ENTER_ROUTINE | 424 | DBG_ENTER_ROUTINE |
387 | 425 | ||
388 | if (!slot->ctrl->hpc_ctlr_handle) { | 426 | slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); |
389 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 427 | state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT; |
390 | return -1; | ||
391 | } | ||
392 | |||
393 | slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); | ||
394 | slot_status = (u16) slot_reg; | ||
395 | atten_led_state = (slot_status & 0x0030) >> 4; | ||
396 | 428 | ||
397 | switch (atten_led_state) { | 429 | switch (state) { |
398 | case 0: | 430 | case ATN_LED_STATE_ON: |
399 | *status = 0xFF; /* Reserved */ | ||
400 | break; | ||
401 | case 1: | ||
402 | *status = 1; /* On */ | 431 | *status = 1; /* On */ |
403 | break; | 432 | break; |
404 | case 2: | 433 | case ATN_LED_STATE_BLINK: |
405 | *status = 2; /* Blink */ | 434 | *status = 2; /* Blink */ |
406 | break; | 435 | break; |
407 | case 3: | 436 | case ATN_LED_STATE_OFF: |
408 | *status = 0; /* Off */ | 437 | *status = 0; /* Off */ |
409 | break; | 438 | break; |
410 | default: | 439 | default: |
411 | *status = 0xFF; | 440 | *status = 0xFF; /* Reserved */ |
412 | break; | 441 | break; |
413 | } | 442 | } |
414 | 443 | ||
@@ -418,64 +447,44 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) | |||
418 | 447 | ||
419 | static int hpc_get_power_status(struct slot * slot, u8 *status) | 448 | static int hpc_get_power_status(struct slot * slot, u8 *status) |
420 | { | 449 | { |
421 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 450 | struct controller *ctrl = slot->ctrl; |
422 | u32 slot_reg; | 451 | u32 slot_reg; |
423 | u16 slot_status; | 452 | u8 state; |
424 | u8 slot_state; | ||
425 | int retval = 0; | ||
426 | 453 | ||
427 | DBG_ENTER_ROUTINE | 454 | DBG_ENTER_ROUTINE |
428 | 455 | ||
429 | if (!slot->ctrl->hpc_ctlr_handle) { | 456 | slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); |
430 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 457 | state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT; |
431 | return -1; | ||
432 | } | ||
433 | |||
434 | slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); | ||
435 | slot_status = (u16) slot_reg; | ||
436 | slot_state = (slot_status & 0x0003); | ||
437 | 458 | ||
438 | switch (slot_state) { | 459 | switch (state) { |
439 | case 0: | 460 | case SLOT_STATE_PWRONLY: |
440 | *status = 0xFF; | ||
441 | break; | ||
442 | case 1: | ||
443 | *status = 2; /* Powered only */ | 461 | *status = 2; /* Powered only */ |
444 | break; | 462 | break; |
445 | case 2: | 463 | case SLOT_STATE_ENABLED: |
446 | *status = 1; /* Enabled */ | 464 | *status = 1; /* Enabled */ |
447 | break; | 465 | break; |
448 | case 3: | 466 | case SLOT_STATE_DISABLED: |
449 | *status = 0; /* Disabled */ | 467 | *status = 0; /* Disabled */ |
450 | break; | 468 | break; |
451 | default: | 469 | default: |
452 | *status = 0xFF; | 470 | *status = 0xFF; /* Reserved */ |
453 | break; | 471 | break; |
454 | } | 472 | } |
455 | 473 | ||
456 | DBG_LEAVE_ROUTINE | 474 | DBG_LEAVE_ROUTINE |
457 | return retval; | 475 | return 0; |
458 | } | 476 | } |
459 | 477 | ||
460 | 478 | ||
461 | static int hpc_get_latch_status(struct slot *slot, u8 *status) | 479 | static int hpc_get_latch_status(struct slot *slot, u8 *status) |
462 | { | 480 | { |
463 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 481 | struct controller *ctrl = slot->ctrl; |
464 | u32 slot_reg; | 482 | u32 slot_reg; |
465 | u16 slot_status; | ||
466 | 483 | ||
467 | DBG_ENTER_ROUTINE | 484 | DBG_ENTER_ROUTINE |
468 | 485 | ||
469 | if (!slot->ctrl->hpc_ctlr_handle) { | 486 | slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); |
470 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 487 | *status = !!(slot_reg & MRL_SENSOR); /* 0 -> close; 1 -> open */ |
471 | return -1; | ||
472 | } | ||
473 | |||
474 | slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); | ||
475 | slot_status = (u16)slot_reg; | ||
476 | |||
477 | *status = ((slot_status & 0x0100) == 0) ? 0 : 1; /* 0 -> close; 1 -> open */ | ||
478 | |||
479 | 488 | ||
480 | DBG_LEAVE_ROUTINE | 489 | DBG_LEAVE_ROUTINE |
481 | return 0; | 490 | return 0; |
@@ -483,22 +492,15 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) | |||
483 | 492 | ||
484 | static int hpc_get_adapter_status(struct slot *slot, u8 *status) | 493 | static int hpc_get_adapter_status(struct slot *slot, u8 *status) |
485 | { | 494 | { |
486 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 495 | struct controller *ctrl = slot->ctrl; |
487 | u32 slot_reg; | 496 | u32 slot_reg; |
488 | u16 slot_status; | 497 | u8 state; |
489 | u8 card_state; | ||
490 | 498 | ||
491 | DBG_ENTER_ROUTINE | 499 | DBG_ENTER_ROUTINE |
492 | 500 | ||
493 | if (!slot->ctrl->hpc_ctlr_handle) { | 501 | slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); |
494 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 502 | state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT; |
495 | return -1; | 503 | *status = (state != 0x3) ? 1 : 0; |
496 | } | ||
497 | |||
498 | slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); | ||
499 | slot_status = (u16)slot_reg; | ||
500 | card_state = (u8)((slot_status & 0x0C00) >> 10); | ||
501 | *status = (card_state != 0x3) ? 1 : 0; | ||
502 | 504 | ||
503 | DBG_LEAVE_ROUTINE | 505 | DBG_LEAVE_ROUTINE |
504 | return 0; | 506 | return 0; |
@@ -506,16 +508,11 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) | |||
506 | 508 | ||
507 | static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) | 509 | static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) |
508 | { | 510 | { |
509 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 511 | struct controller *ctrl = slot->ctrl; |
510 | 512 | ||
511 | DBG_ENTER_ROUTINE | 513 | DBG_ENTER_ROUTINE |
512 | |||
513 | if (!slot->ctrl->hpc_ctlr_handle) { | ||
514 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
515 | return -1; | ||
516 | } | ||
517 | 514 | ||
518 | *prog_int = readb(php_ctlr->creg + PROG_INTERFACE); | 515 | *prog_int = shpc_readb(ctrl, PROG_INTERFACE); |
519 | 516 | ||
520 | DBG_LEAVE_ROUTINE | 517 | DBG_LEAVE_ROUTINE |
521 | return 0; | 518 | return 0; |
@@ -524,13 +521,27 @@ static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) | |||
524 | static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) | 521 | static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) |
525 | { | 522 | { |
526 | int retval = 0; | 523 | int retval = 0; |
527 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 524 | struct controller *ctrl = slot->ctrl; |
528 | u32 slot_reg = readl(php_ctlr->creg + SLOT1 + 4 * slot->hp_slot); | 525 | u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); |
529 | u8 pcix_cap = (slot_reg >> 12) & 7; | 526 | u8 m66_cap = !!(slot_reg & MHZ66_CAP); |
530 | u8 m66_cap = (slot_reg >> 9) & 1; | 527 | u8 pi, pcix_cap; |
531 | 528 | ||
532 | DBG_ENTER_ROUTINE | 529 | DBG_ENTER_ROUTINE |
533 | 530 | ||
531 | if ((retval = hpc_get_prog_int(slot, &pi))) | ||
532 | return retval; | ||
533 | |||
534 | switch (pi) { | ||
535 | case 1: | ||
536 | pcix_cap = (slot_reg & PCIX_CAP_MASK_PI1) >> PCIX_CAP_SHIFT; | ||
537 | break; | ||
538 | case 2: | ||
539 | pcix_cap = (slot_reg & PCIX_CAP_MASK_PI2) >> PCIX_CAP_SHIFT; | ||
540 | break; | ||
541 | default: | ||
542 | return -ENODEV; | ||
543 | } | ||
544 | |||
534 | dbg("%s: slot_reg = %x, pcix_cap = %x, m66_cap = %x\n", | 545 | dbg("%s: slot_reg = %x, pcix_cap = %x, m66_cap = %x\n", |
535 | __FUNCTION__, slot_reg, pcix_cap, m66_cap); | 546 | __FUNCTION__, slot_reg, pcix_cap, m66_cap); |
536 | 547 | ||
@@ -564,20 +575,15 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) | |||
564 | 575 | ||
565 | static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) | 576 | static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) |
566 | { | 577 | { |
567 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 578 | struct controller *ctrl = slot->ctrl; |
568 | u16 sec_bus_status; | 579 | u16 sec_bus_status; |
569 | u8 pi; | 580 | u8 pi; |
570 | int retval = 0; | 581 | int retval = 0; |
571 | 582 | ||
572 | DBG_ENTER_ROUTINE | 583 | DBG_ENTER_ROUTINE |
573 | 584 | ||
574 | if (!slot->ctrl->hpc_ctlr_handle) { | 585 | pi = shpc_readb(ctrl, PROG_INTERFACE); |
575 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 586 | sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG); |
576 | return -1; | ||
577 | } | ||
578 | |||
579 | pi = readb(php_ctlr->creg + PROG_INTERFACE); | ||
580 | sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG); | ||
581 | 587 | ||
582 | if (pi == 2) { | 588 | if (pi == 2) { |
583 | *mode = (sec_bus_status & 0x0100) >> 8; | 589 | *mode = (sec_bus_status & 0x0100) >> 8; |
@@ -593,128 +599,53 @@ static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) | |||
593 | 599 | ||
594 | static int hpc_query_power_fault(struct slot * slot) | 600 | static int hpc_query_power_fault(struct slot * slot) |
595 | { | 601 | { |
596 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 602 | struct controller *ctrl = slot->ctrl; |
597 | u32 slot_reg; | 603 | u32 slot_reg; |
598 | u16 slot_status; | ||
599 | u8 pwr_fault_state, status; | ||
600 | 604 | ||
601 | DBG_ENTER_ROUTINE | 605 | DBG_ENTER_ROUTINE |
602 | 606 | ||
603 | if (!slot->ctrl->hpc_ctlr_handle) { | 607 | slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); |
604 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
605 | return -1; | ||
606 | } | ||
607 | |||
608 | slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); | ||
609 | slot_status = (u16) slot_reg; | ||
610 | pwr_fault_state = (slot_status & 0x0040) >> 7; | ||
611 | status = (pwr_fault_state == 1) ? 0 : 1; | ||
612 | 608 | ||
613 | DBG_LEAVE_ROUTINE | 609 | DBG_LEAVE_ROUTINE |
614 | /* Note: Logic 0 => fault */ | 610 | /* Note: Logic 0 => fault */ |
615 | return status; | 611 | return !(slot_reg & POWER_FAULT); |
616 | } | 612 | } |
617 | 613 | ||
618 | static int hpc_set_attention_status(struct slot *slot, u8 value) | 614 | static int hpc_set_attention_status(struct slot *slot, u8 value) |
619 | { | 615 | { |
620 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | ||
621 | u8 slot_cmd = 0; | 616 | u8 slot_cmd = 0; |
622 | int rc = 0; | ||
623 | |||
624 | if (!slot->ctrl->hpc_ctlr_handle) { | ||
625 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
626 | return -1; | ||
627 | } | ||
628 | |||
629 | if (slot->hp_slot >= php_ctlr->num_slots) { | ||
630 | err("%s: Invalid HPC slot number!\n", __FUNCTION__); | ||
631 | return -1; | ||
632 | } | ||
633 | 617 | ||
634 | switch (value) { | 618 | switch (value) { |
635 | case 0 : | 619 | case 0 : |
636 | slot_cmd = 0x30; /* OFF */ | 620 | slot_cmd = SET_ATTN_OFF; /* OFF */ |
637 | break; | 621 | break; |
638 | case 1: | 622 | case 1: |
639 | slot_cmd = 0x10; /* ON */ | 623 | slot_cmd = SET_ATTN_ON; /* ON */ |
640 | break; | 624 | break; |
641 | case 2: | 625 | case 2: |
642 | slot_cmd = 0x20; /* BLINK */ | 626 | slot_cmd = SET_ATTN_BLINK; /* BLINK */ |
643 | break; | 627 | break; |
644 | default: | 628 | default: |
645 | return -1; | 629 | return -1; |
646 | } | 630 | } |
647 | 631 | ||
648 | shpc_write_cmd(slot, slot->hp_slot, slot_cmd); | 632 | return shpc_write_cmd(slot, slot->hp_slot, slot_cmd); |
649 | |||
650 | return rc; | ||
651 | } | 633 | } |
652 | 634 | ||
653 | 635 | ||
654 | static void hpc_set_green_led_on(struct slot *slot) | 636 | static void hpc_set_green_led_on(struct slot *slot) |
655 | { | 637 | { |
656 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 638 | shpc_write_cmd(slot, slot->hp_slot, SET_PWR_ON); |
657 | u8 slot_cmd; | ||
658 | |||
659 | if (!slot->ctrl->hpc_ctlr_handle) { | ||
660 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
661 | return ; | ||
662 | } | ||
663 | |||
664 | if (slot->hp_slot >= php_ctlr->num_slots) { | ||
665 | err("%s: Invalid HPC slot number!\n", __FUNCTION__); | ||
666 | return ; | ||
667 | } | ||
668 | |||
669 | slot_cmd = 0x04; | ||
670 | |||
671 | shpc_write_cmd(slot, slot->hp_slot, slot_cmd); | ||
672 | |||
673 | return; | ||
674 | } | 639 | } |
675 | 640 | ||
676 | static void hpc_set_green_led_off(struct slot *slot) | 641 | static void hpc_set_green_led_off(struct slot *slot) |
677 | { | 642 | { |
678 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 643 | shpc_write_cmd(slot, slot->hp_slot, SET_PWR_OFF); |
679 | u8 slot_cmd; | ||
680 | |||
681 | if (!slot->ctrl->hpc_ctlr_handle) { | ||
682 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
683 | return ; | ||
684 | } | ||
685 | |||
686 | if (slot->hp_slot >= php_ctlr->num_slots) { | ||
687 | err("%s: Invalid HPC slot number!\n", __FUNCTION__); | ||
688 | return ; | ||
689 | } | ||
690 | |||
691 | slot_cmd = 0x0C; | ||
692 | |||
693 | shpc_write_cmd(slot, slot->hp_slot, slot_cmd); | ||
694 | |||
695 | return; | ||
696 | } | 644 | } |
697 | 645 | ||
698 | static void hpc_set_green_led_blink(struct slot *slot) | 646 | static void hpc_set_green_led_blink(struct slot *slot) |
699 | { | 647 | { |
700 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 648 | shpc_write_cmd(slot, slot->hp_slot, SET_PWR_BLINK); |
701 | u8 slot_cmd; | ||
702 | |||
703 | if (!slot->ctrl->hpc_ctlr_handle) { | ||
704 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
705 | return ; | ||
706 | } | ||
707 | |||
708 | if (slot->hp_slot >= php_ctlr->num_slots) { | ||
709 | err("%s: Invalid HPC slot number!\n", __FUNCTION__); | ||
710 | return ; | ||
711 | } | ||
712 | |||
713 | slot_cmd = 0x08; | ||
714 | |||
715 | shpc_write_cmd(slot, slot->hp_slot, slot_cmd); | ||
716 | |||
717 | return; | ||
718 | } | 649 | } |
719 | 650 | ||
720 | int shpc_get_ctlr_slot_config(struct controller *ctrl, | 651 | int shpc_get_ctlr_slot_config(struct controller *ctrl, |
@@ -724,21 +655,17 @@ int shpc_get_ctlr_slot_config(struct controller *ctrl, | |||
724 | int *updown, /* physical_slot_num increament: 1 or -1 */ | 655 | int *updown, /* physical_slot_num increament: 1 or -1 */ |
725 | int *flags) | 656 | int *flags) |
726 | { | 657 | { |
727 | struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; | 658 | u32 slot_config; |
728 | 659 | ||
729 | DBG_ENTER_ROUTINE | 660 | DBG_ENTER_ROUTINE |
730 | 661 | ||
731 | if (!ctrl->hpc_ctlr_handle) { | 662 | slot_config = shpc_readl(ctrl, SLOT_CONFIG); |
732 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 663 | *first_device_num = (slot_config & FIRST_DEV_NUM) >> 8; |
733 | return -1; | 664 | *num_ctlr_slots = slot_config & SLOT_NUM; |
734 | } | 665 | *physical_slot_num = (slot_config & PSN) >> 16; |
735 | 666 | *updown = ((slot_config & UPDOWN) >> 29) ? 1 : -1; | |
736 | *first_device_num = php_ctlr->slot_device_offset; /* Obtained in shpc_init() */ | ||
737 | *num_ctlr_slots = php_ctlr->num_slots; /* Obtained in shpc_init() */ | ||
738 | 667 | ||
739 | *physical_slot_num = (readl(php_ctlr->creg + SLOT_CONFIG) & PSN) >> 16; | ||
740 | dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num); | 668 | dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num); |
741 | *updown = ((readl(php_ctlr->creg + SLOT_CONFIG) & UPDOWN ) >> 29) ? 1 : -1; | ||
742 | 669 | ||
743 | DBG_LEAVE_ROUTINE | 670 | DBG_LEAVE_ROUTINE |
744 | return 0; | 671 | return 0; |
@@ -749,22 +676,34 @@ static void hpc_release_ctlr(struct controller *ctrl) | |||
749 | struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; | 676 | struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; |
750 | struct php_ctlr_state_s *p, *p_prev; | 677 | struct php_ctlr_state_s *p, *p_prev; |
751 | int i; | 678 | int i; |
679 | u32 slot_reg, serr_int; | ||
752 | 680 | ||
753 | DBG_ENTER_ROUTINE | 681 | DBG_ENTER_ROUTINE |
754 | 682 | ||
755 | if (!ctrl->hpc_ctlr_handle) { | ||
756 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
757 | return ; | ||
758 | } | ||
759 | |||
760 | /* | 683 | /* |
761 | * Mask all slot event interrupts | 684 | * Mask event interrupts and SERRs of all slots |
762 | */ | 685 | */ |
763 | for (i = 0; i < ctrl->num_slots; i++) | 686 | for (i = 0; i < ctrl->num_slots; i++) { |
764 | writel(0xffff3fff, php_ctlr->creg + SLOT1 + (4 * i)); | 687 | slot_reg = shpc_readl(ctrl, SLOT_REG(i)); |
688 | slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | | ||
689 | BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | | ||
690 | CON_PFAULT_INTR_MASK | MRL_CHANGE_SERR_MASK | | ||
691 | CON_PFAULT_SERR_MASK); | ||
692 | slot_reg &= ~SLOT_REG_RSVDZ_MASK; | ||
693 | shpc_writel(ctrl, SLOT_REG(i), slot_reg); | ||
694 | } | ||
765 | 695 | ||
766 | cleanup_slots(ctrl); | 696 | cleanup_slots(ctrl); |
767 | 697 | ||
698 | /* | ||
699 | * Mask SERR and System Interrut generation | ||
700 | */ | ||
701 | serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); | ||
702 | serr_int |= (GLOBAL_INTR_MASK | GLOBAL_SERR_MASK | | ||
703 | COMMAND_INTR_MASK | ARBITER_SERR_MASK); | ||
704 | serr_int &= ~SERR_INTR_RSVDZ_MASK; | ||
705 | shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); | ||
706 | |||
768 | if (shpchp_poll_mode) { | 707 | if (shpchp_poll_mode) { |
769 | del_timer(&php_ctlr->int_poll_timer); | 708 | del_timer(&php_ctlr->int_poll_timer); |
770 | } else { | 709 | } else { |
@@ -800,113 +739,79 @@ static void hpc_release_ctlr(struct controller *ctrl) | |||
800 | 739 | ||
801 | kfree(php_ctlr); | 740 | kfree(php_ctlr); |
802 | 741 | ||
742 | /* | ||
743 | * If this is the last controller to be released, destroy the | ||
744 | * shpchpd work queue | ||
745 | */ | ||
746 | if (atomic_dec_and_test(&shpchp_num_controllers)) | ||
747 | destroy_workqueue(shpchp_wq); | ||
748 | |||
803 | DBG_LEAVE_ROUTINE | 749 | DBG_LEAVE_ROUTINE |
804 | 750 | ||
805 | } | 751 | } |
806 | 752 | ||
807 | static int hpc_power_on_slot(struct slot * slot) | 753 | static int hpc_power_on_slot(struct slot * slot) |
808 | { | 754 | { |
809 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 755 | int retval; |
810 | u8 slot_cmd; | ||
811 | int retval = 0; | ||
812 | 756 | ||
813 | DBG_ENTER_ROUTINE | 757 | DBG_ENTER_ROUTINE |
814 | 758 | ||
815 | if (!slot->ctrl->hpc_ctlr_handle) { | 759 | retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_PWR); |
816 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
817 | return -1; | ||
818 | } | ||
819 | |||
820 | if (slot->hp_slot >= php_ctlr->num_slots) { | ||
821 | err("%s: Invalid HPC slot number!\n", __FUNCTION__); | ||
822 | return -1; | ||
823 | } | ||
824 | slot_cmd = 0x01; | ||
825 | |||
826 | retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd); | ||
827 | |||
828 | if (retval) { | 760 | if (retval) { |
829 | err("%s: Write command failed!\n", __FUNCTION__); | 761 | err("%s: Write command failed!\n", __FUNCTION__); |
830 | return -1; | 762 | return retval; |
831 | } | 763 | } |
832 | 764 | ||
833 | DBG_LEAVE_ROUTINE | 765 | DBG_LEAVE_ROUTINE |
834 | 766 | ||
835 | return retval; | 767 | return 0; |
836 | } | 768 | } |
837 | 769 | ||
838 | static int hpc_slot_enable(struct slot * slot) | 770 | static int hpc_slot_enable(struct slot * slot) |
839 | { | 771 | { |
840 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 772 | int retval; |
841 | u8 slot_cmd; | ||
842 | int retval = 0; | ||
843 | 773 | ||
844 | DBG_ENTER_ROUTINE | 774 | DBG_ENTER_ROUTINE |
845 | 775 | ||
846 | if (!slot->ctrl->hpc_ctlr_handle) { | 776 | /* Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */ |
847 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 777 | retval = shpc_write_cmd(slot, slot->hp_slot, |
848 | return -1; | 778 | SET_SLOT_ENABLE | SET_PWR_BLINK | SET_ATTN_OFF); |
849 | } | ||
850 | |||
851 | if (slot->hp_slot >= php_ctlr->num_slots) { | ||
852 | err("%s: Invalid HPC slot number!\n", __FUNCTION__); | ||
853 | return -1; | ||
854 | } | ||
855 | /* 3A => Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */ | ||
856 | slot_cmd = 0x3A; | ||
857 | |||
858 | retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd); | ||
859 | |||
860 | if (retval) { | 779 | if (retval) { |
861 | err("%s: Write command failed!\n", __FUNCTION__); | 780 | err("%s: Write command failed!\n", __FUNCTION__); |
862 | return -1; | 781 | return retval; |
863 | } | 782 | } |
864 | 783 | ||
865 | DBG_LEAVE_ROUTINE | 784 | DBG_LEAVE_ROUTINE |
866 | return retval; | 785 | return 0; |
867 | } | 786 | } |
868 | 787 | ||
869 | static int hpc_slot_disable(struct slot * slot) | 788 | static int hpc_slot_disable(struct slot * slot) |
870 | { | 789 | { |
871 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 790 | int retval; |
872 | u8 slot_cmd; | ||
873 | int retval = 0; | ||
874 | 791 | ||
875 | DBG_ENTER_ROUTINE | 792 | DBG_ENTER_ROUTINE |
876 | 793 | ||
877 | if (!slot->ctrl->hpc_ctlr_handle) { | 794 | /* Slot - Disable, Power Indicator - Off, Attention Indicator - On */ |
878 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 795 | retval = shpc_write_cmd(slot, slot->hp_slot, |
879 | return -1; | 796 | SET_SLOT_DISABLE | SET_PWR_OFF | SET_ATTN_ON); |
880 | } | ||
881 | |||
882 | if (slot->hp_slot >= php_ctlr->num_slots) { | ||
883 | err("%s: Invalid HPC slot number!\n", __FUNCTION__); | ||
884 | return -1; | ||
885 | } | ||
886 | |||
887 | /* 1F => Slot - Disable, Power Indicator - Off, Attention Indicator - On */ | ||
888 | slot_cmd = 0x1F; | ||
889 | |||
890 | retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd); | ||
891 | |||
892 | if (retval) { | 797 | if (retval) { |
893 | err("%s: Write command failed!\n", __FUNCTION__); | 798 | err("%s: Write command failed!\n", __FUNCTION__); |
894 | return -1; | 799 | return retval; |
895 | } | 800 | } |
896 | 801 | ||
897 | DBG_LEAVE_ROUTINE | 802 | DBG_LEAVE_ROUTINE |
898 | return retval; | 803 | return 0; |
899 | } | 804 | } |
900 | 805 | ||
901 | static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) | 806 | static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) |
902 | { | 807 | { |
903 | int retval; | 808 | int retval; |
904 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 809 | struct controller *ctrl = slot->ctrl; |
905 | u8 pi, cmd; | 810 | u8 pi, cmd; |
906 | 811 | ||
907 | DBG_ENTER_ROUTINE | 812 | DBG_ENTER_ROUTINE |
908 | 813 | ||
909 | pi = readb(php_ctlr->creg + PROG_INTERFACE); | 814 | pi = shpc_readb(ctrl, PROG_INTERFACE); |
910 | if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX)) | 815 | if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX)) |
911 | return -EINVAL; | 816 | return -EINVAL; |
912 | 817 | ||
@@ -965,100 +870,86 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) | |||
965 | return retval; | 870 | return retval; |
966 | } | 871 | } |
967 | 872 | ||
968 | static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) | 873 | static irqreturn_t shpc_isr(int irq, void *dev_id, struct pt_regs *regs) |
969 | { | 874 | { |
970 | struct controller *ctrl = NULL; | 875 | struct controller *ctrl = (struct controller *)dev_id; |
971 | struct php_ctlr_state_s *php_ctlr; | 876 | struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; |
972 | u8 schedule_flag = 0; | 877 | u32 serr_int, slot_reg, intr_loc, intr_loc2; |
973 | u8 temp_byte; | ||
974 | u32 temp_dword, intr_loc, intr_loc2; | ||
975 | int hp_slot; | 878 | int hp_slot; |
976 | 879 | ||
977 | if (!dev_id) | ||
978 | return IRQ_NONE; | ||
979 | |||
980 | if (!shpchp_poll_mode) { | ||
981 | ctrl = (struct controller *)dev_id; | ||
982 | php_ctlr = ctrl->hpc_ctlr_handle; | ||
983 | } else { | ||
984 | php_ctlr = (struct php_ctlr_state_s *) dev_id; | ||
985 | ctrl = (struct controller *)php_ctlr->callback_instance_id; | ||
986 | } | ||
987 | |||
988 | if (!ctrl) | ||
989 | return IRQ_NONE; | ||
990 | |||
991 | if (!php_ctlr || !php_ctlr->creg) | ||
992 | return IRQ_NONE; | ||
993 | |||
994 | /* Check to see if it was our interrupt */ | 880 | /* Check to see if it was our interrupt */ |
995 | intr_loc = readl(php_ctlr->creg + INTR_LOC); | 881 | intr_loc = shpc_readl(ctrl, INTR_LOC); |
996 | |||
997 | if (!intr_loc) | 882 | if (!intr_loc) |
998 | return IRQ_NONE; | 883 | return IRQ_NONE; |
884 | |||
999 | dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); | 885 | dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); |
1000 | 886 | ||
1001 | if(!shpchp_poll_mode) { | 887 | if(!shpchp_poll_mode) { |
1002 | /* Mask Global Interrupt Mask - see implementation note on p. 139 */ | 888 | /* |
1003 | /* of SHPC spec rev 1.0*/ | 889 | * Mask Global Interrupt Mask - see implementation |
1004 | temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); | 890 | * note on p. 139 of SHPC spec rev 1.0 |
1005 | temp_dword |= 0x00000001; | 891 | */ |
1006 | writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); | 892 | serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); |
893 | serr_int |= GLOBAL_INTR_MASK; | ||
894 | serr_int &= ~SERR_INTR_RSVDZ_MASK; | ||
895 | shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); | ||
1007 | 896 | ||
1008 | intr_loc2 = readl(php_ctlr->creg + INTR_LOC); | 897 | intr_loc2 = shpc_readl(ctrl, INTR_LOC); |
1009 | dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); | 898 | dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); |
1010 | } | 899 | } |
1011 | 900 | ||
1012 | if (intr_loc & 0x0001) { | 901 | if (intr_loc & CMD_INTR_PENDING) { |
1013 | /* | 902 | /* |
1014 | * Command Complete Interrupt Pending | 903 | * Command Complete Interrupt Pending |
1015 | * RO only - clear by writing 1 to the Command Completion | 904 | * RO only - clear by writing 1 to the Command Completion |
1016 | * Detect bit in Controller SERR-INT register | 905 | * Detect bit in Controller SERR-INT register |
1017 | */ | 906 | */ |
1018 | temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); | 907 | serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); |
1019 | temp_dword &= 0xfffdffff; | 908 | serr_int &= ~SERR_INTR_RSVDZ_MASK; |
1020 | writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); | 909 | shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); |
910 | |||
1021 | ctrl->cmd_busy = 0; | 911 | ctrl->cmd_busy = 0; |
1022 | wake_up_interruptible(&ctrl->queue); | 912 | wake_up_interruptible(&ctrl->queue); |
1023 | } | 913 | } |
1024 | 914 | ||
1025 | if ((intr_loc = (intr_loc >> 1)) == 0) | 915 | if (!(intr_loc & ~CMD_INTR_PENDING)) |
1026 | goto out; | 916 | goto out; |
1027 | 917 | ||
1028 | for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { | 918 | for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { |
1029 | /* To find out which slot has interrupt pending */ | 919 | /* To find out which slot has interrupt pending */ |
1030 | if ((intr_loc >> hp_slot) & 0x01) { | 920 | if (!(intr_loc & SLOT_INTR_PENDING(hp_slot))) |
1031 | temp_dword = readl(php_ctlr->creg + SLOT1 + (4*hp_slot)); | 921 | continue; |
1032 | dbg("%s: Slot %x with intr, slot register = %x\n", | 922 | |
1033 | __FUNCTION__, hp_slot, temp_dword); | 923 | slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); |
1034 | temp_byte = (temp_dword >> 16) & 0xFF; | 924 | dbg("%s: Slot %x with intr, slot register = %x\n", |
1035 | if ((php_ctlr->switch_change_callback) && (temp_byte & 0x08)) | 925 | __FUNCTION__, hp_slot, slot_reg); |
1036 | schedule_flag += php_ctlr->switch_change_callback( | 926 | |
1037 | hp_slot, php_ctlr->callback_instance_id); | 927 | if (slot_reg & MRL_CHANGE_DETECTED) |
1038 | if ((php_ctlr->attention_button_callback) && (temp_byte & 0x04)) | 928 | php_ctlr->switch_change_callback( |
1039 | schedule_flag += php_ctlr->attention_button_callback( | 929 | hp_slot, php_ctlr->callback_instance_id); |
1040 | hp_slot, php_ctlr->callback_instance_id); | 930 | |
1041 | if ((php_ctlr->presence_change_callback) && (temp_byte & 0x01)) | 931 | if (slot_reg & BUTTON_PRESS_DETECTED) |
1042 | schedule_flag += php_ctlr->presence_change_callback( | 932 | php_ctlr->attention_button_callback( |
1043 | hp_slot , php_ctlr->callback_instance_id); | 933 | hp_slot, php_ctlr->callback_instance_id); |
1044 | if ((php_ctlr->power_fault_callback) && (temp_byte & 0x12)) | 934 | |
1045 | schedule_flag += php_ctlr->power_fault_callback( | 935 | if (slot_reg & PRSNT_CHANGE_DETECTED) |
1046 | hp_slot, php_ctlr->callback_instance_id); | 936 | php_ctlr->presence_change_callback( |
1047 | 937 | hp_slot , php_ctlr->callback_instance_id); | |
1048 | /* Clear all slot events */ | 938 | |
1049 | temp_dword = 0xe01f3fff; | 939 | if (slot_reg & (ISO_PFAULT_DETECTED | CON_PFAULT_DETECTED)) |
1050 | writel(temp_dword, php_ctlr->creg + SLOT1 + (4*hp_slot)); | 940 | php_ctlr->power_fault_callback( |
1051 | 941 | hp_slot, php_ctlr->callback_instance_id); | |
1052 | intr_loc2 = readl(php_ctlr->creg + INTR_LOC); | 942 | |
1053 | dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); | 943 | /* Clear all slot events */ |
1054 | } | 944 | slot_reg &= ~SLOT_REG_RSVDZ_MASK; |
945 | shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); | ||
1055 | } | 946 | } |
1056 | out: | 947 | out: |
1057 | if (!shpchp_poll_mode) { | 948 | if (!shpchp_poll_mode) { |
1058 | /* Unmask Global Interrupt Mask */ | 949 | /* Unmask Global Interrupt Mask */ |
1059 | temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); | 950 | serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); |
1060 | temp_dword &= 0xfffffffe; | 951 | serr_int &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK); |
1061 | writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); | 952 | shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); |
1062 | } | 953 | } |
1063 | 954 | ||
1064 | return IRQ_HANDLED; | 955 | return IRQ_HANDLED; |
@@ -1067,11 +958,11 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) | |||
1067 | static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) | 958 | static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) |
1068 | { | 959 | { |
1069 | int retval = 0; | 960 | int retval = 0; |
1070 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 961 | struct controller *ctrl = slot->ctrl; |
1071 | enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; | 962 | enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; |
1072 | u8 pi = readb(php_ctlr->creg + PROG_INTERFACE); | 963 | u8 pi = shpc_readb(ctrl, PROG_INTERFACE); |
1073 | u32 slot_avail1 = readl(php_ctlr->creg + SLOT_AVAIL1); | 964 | u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1); |
1074 | u32 slot_avail2 = readl(php_ctlr->creg + SLOT_AVAIL2); | 965 | u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2); |
1075 | 966 | ||
1076 | DBG_ENTER_ROUTINE | 967 | DBG_ENTER_ROUTINE |
1077 | 968 | ||
@@ -1114,10 +1005,10 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) | |||
1114 | static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value) | 1005 | static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value) |
1115 | { | 1006 | { |
1116 | int retval = 0; | 1007 | int retval = 0; |
1117 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 1008 | struct controller *ctrl = slot->ctrl; |
1118 | enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; | 1009 | enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; |
1119 | u16 sec_bus_reg = readw(php_ctlr->creg + SEC_BUS_CONFIG); | 1010 | u16 sec_bus_reg = shpc_readw(ctrl, SEC_BUS_CONFIG); |
1120 | u8 pi = readb(php_ctlr->creg + PROG_INTERFACE); | 1011 | u8 pi = shpc_readb(ctrl, PROG_INTERFACE); |
1121 | u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7); | 1012 | u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7); |
1122 | 1013 | ||
1123 | DBG_ENTER_ROUTINE | 1014 | DBG_ENTER_ROUTINE |
@@ -1206,28 +1097,14 @@ static struct hpc_ops shpchp_hpc_ops = { | |||
1206 | .release_ctlr = hpc_release_ctlr, | 1097 | .release_ctlr = hpc_release_ctlr, |
1207 | }; | 1098 | }; |
1208 | 1099 | ||
1209 | inline static int shpc_indirect_creg_read(struct controller *ctrl, int index, | ||
1210 | u32 *value) | ||
1211 | { | ||
1212 | int rc; | ||
1213 | u32 cap_offset = ctrl->cap_offset; | ||
1214 | struct pci_dev *pdev = ctrl->pci_dev; | ||
1215 | |||
1216 | rc = pci_write_config_byte(pdev, cap_offset + DWORD_SELECT, index); | ||
1217 | if (rc) | ||
1218 | return rc; | ||
1219 | return pci_read_config_dword(pdev, cap_offset + DWORD_DATA, value); | ||
1220 | } | ||
1221 | |||
1222 | int shpc_init(struct controller * ctrl, struct pci_dev * pdev) | 1100 | int shpc_init(struct controller * ctrl, struct pci_dev * pdev) |
1223 | { | 1101 | { |
1224 | struct php_ctlr_state_s *php_ctlr, *p; | 1102 | struct php_ctlr_state_s *php_ctlr, *p; |
1225 | void *instance_id = ctrl; | 1103 | void *instance_id = ctrl; |
1226 | int rc, num_slots = 0; | 1104 | int rc, num_slots = 0; |
1227 | u8 hp_slot; | 1105 | u8 hp_slot; |
1228 | static int first = 1; | ||
1229 | u32 shpc_base_offset; | 1106 | u32 shpc_base_offset; |
1230 | u32 tempdword, slot_reg; | 1107 | u32 tempdword, slot_reg, slot_config; |
1231 | u8 i; | 1108 | u8 i; |
1232 | 1109 | ||
1233 | DBG_ENTER_ROUTINE | 1110 | DBG_ENTER_ROUTINE |
@@ -1257,13 +1134,13 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) | |||
1257 | } | 1134 | } |
1258 | dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset); | 1135 | dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset); |
1259 | 1136 | ||
1260 | rc = shpc_indirect_creg_read(ctrl, 0, &shpc_base_offset); | 1137 | rc = shpc_indirect_read(ctrl, 0, &shpc_base_offset); |
1261 | if (rc) { | 1138 | if (rc) { |
1262 | err("%s: cannot read base_offset\n", __FUNCTION__); | 1139 | err("%s: cannot read base_offset\n", __FUNCTION__); |
1263 | goto abort_free_ctlr; | 1140 | goto abort_free_ctlr; |
1264 | } | 1141 | } |
1265 | 1142 | ||
1266 | rc = shpc_indirect_creg_read(ctrl, 3, &tempdword); | 1143 | rc = shpc_indirect_read(ctrl, 3, &tempdword); |
1267 | if (rc) { | 1144 | if (rc) { |
1268 | err("%s: cannot read slot config\n", __FUNCTION__); | 1145 | err("%s: cannot read slot config\n", __FUNCTION__); |
1269 | goto abort_free_ctlr; | 1146 | goto abort_free_ctlr; |
@@ -1272,7 +1149,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) | |||
1272 | dbg("%s: num_slots (indirect) %x\n", __FUNCTION__, num_slots); | 1149 | dbg("%s: num_slots (indirect) %x\n", __FUNCTION__, num_slots); |
1273 | 1150 | ||
1274 | for (i = 0; i < 9 + num_slots; i++) { | 1151 | for (i = 0; i < 9 + num_slots; i++) { |
1275 | rc = shpc_indirect_creg_read(ctrl, i, &tempdword); | 1152 | rc = shpc_indirect_read(ctrl, i, &tempdword); |
1276 | if (rc) { | 1153 | if (rc) { |
1277 | err("%s: cannot read creg (index = %d)\n", | 1154 | err("%s: cannot read creg (index = %d)\n", |
1278 | __FUNCTION__, i); | 1155 | __FUNCTION__, i); |
@@ -1287,11 +1164,6 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) | |||
1287 | ctrl->mmio_size = 0x24 + 0x4 * num_slots; | 1164 | ctrl->mmio_size = 0x24 + 0x4 * num_slots; |
1288 | } | 1165 | } |
1289 | 1166 | ||
1290 | if (first) { | ||
1291 | spin_lock_init(&hpc_event_lock); | ||
1292 | first = 0; | ||
1293 | } | ||
1294 | |||
1295 | info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, | 1167 | info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, |
1296 | pdev->subsystem_device); | 1168 | pdev->subsystem_device); |
1297 | 1169 | ||
@@ -1326,29 +1198,39 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) | |||
1326 | php_ctlr->power_fault_callback = shpchp_handle_power_fault; | 1198 | php_ctlr->power_fault_callback = shpchp_handle_power_fault; |
1327 | php_ctlr->callback_instance_id = instance_id; | 1199 | php_ctlr->callback_instance_id = instance_id; |
1328 | 1200 | ||
1201 | ctrl->hpc_ctlr_handle = php_ctlr; | ||
1202 | ctrl->hpc_ops = &shpchp_hpc_ops; | ||
1203 | |||
1329 | /* Return PCI Controller Info */ | 1204 | /* Return PCI Controller Info */ |
1330 | php_ctlr->slot_device_offset = (readl(php_ctlr->creg + SLOT_CONFIG) & FIRST_DEV_NUM ) >> 8; | 1205 | slot_config = shpc_readl(ctrl, SLOT_CONFIG); |
1331 | php_ctlr->num_slots = readl(php_ctlr->creg + SLOT_CONFIG) & SLOT_NUM; | 1206 | php_ctlr->slot_device_offset = (slot_config & FIRST_DEV_NUM) >> 8; |
1207 | php_ctlr->num_slots = slot_config & SLOT_NUM; | ||
1332 | dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset); | 1208 | dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset); |
1333 | dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots); | 1209 | dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots); |
1334 | 1210 | ||
1335 | /* Mask Global Interrupt Mask & Command Complete Interrupt Mask */ | 1211 | /* Mask Global Interrupt Mask & Command Complete Interrupt Mask */ |
1336 | tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); | 1212 | tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); |
1337 | dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); | 1213 | dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); |
1338 | tempdword = 0x0003000f; | 1214 | tempdword |= (GLOBAL_INTR_MASK | GLOBAL_SERR_MASK | |
1339 | writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE); | 1215 | COMMAND_INTR_MASK | ARBITER_SERR_MASK); |
1340 | tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); | 1216 | tempdword &= ~SERR_INTR_RSVDZ_MASK; |
1217 | shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword); | ||
1218 | tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); | ||
1341 | dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); | 1219 | dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); |
1342 | 1220 | ||
1343 | /* Mask the MRL sensor SERR Mask of individual slot in | 1221 | /* Mask the MRL sensor SERR Mask of individual slot in |
1344 | * Slot SERR-INT Mask & clear all the existing event if any | 1222 | * Slot SERR-INT Mask & clear all the existing event if any |
1345 | */ | 1223 | */ |
1346 | for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { | 1224 | for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { |
1347 | slot_reg = readl(php_ctlr->creg + SLOT1 + 4*hp_slot ); | 1225 | slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); |
1348 | dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, | 1226 | dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, |
1349 | hp_slot, slot_reg); | 1227 | hp_slot, slot_reg); |
1350 | tempdword = 0xffff3fff; | 1228 | slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | |
1351 | writel(tempdword, php_ctlr->creg + SLOT1 + (4*hp_slot)); | 1229 | BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | |
1230 | CON_PFAULT_INTR_MASK | MRL_CHANGE_SERR_MASK | | ||
1231 | CON_PFAULT_SERR_MASK); | ||
1232 | slot_reg &= ~SLOT_REG_RSVDZ_MASK; | ||
1233 | shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); | ||
1352 | } | 1234 | } |
1353 | 1235 | ||
1354 | if (shpchp_poll_mode) {/* Install interrupt polling code */ | 1236 | if (shpchp_poll_mode) {/* Install interrupt polling code */ |
@@ -1392,24 +1274,37 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) | |||
1392 | } | 1274 | } |
1393 | spin_unlock(&list_lock); | 1275 | spin_unlock(&list_lock); |
1394 | 1276 | ||
1395 | |||
1396 | ctlr_seq_num++; | 1277 | ctlr_seq_num++; |
1397 | ctrl->hpc_ctlr_handle = php_ctlr; | ||
1398 | ctrl->hpc_ops = &shpchp_hpc_ops; | ||
1399 | 1278 | ||
1279 | /* | ||
1280 | * If this is the first controller to be initialized, | ||
1281 | * initialize the shpchpd work queue | ||
1282 | */ | ||
1283 | if (atomic_add_return(1, &shpchp_num_controllers) == 1) { | ||
1284 | shpchp_wq = create_singlethread_workqueue("shpchpd"); | ||
1285 | if (!shpchp_wq) | ||
1286 | return -ENOMEM; | ||
1287 | } | ||
1288 | |||
1289 | /* | ||
1290 | * Unmask all event interrupts of all slots | ||
1291 | */ | ||
1400 | for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { | 1292 | for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { |
1401 | slot_reg = readl(php_ctlr->creg + SLOT1 + 4*hp_slot ); | 1293 | slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); |
1402 | dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, | 1294 | dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, |
1403 | hp_slot, slot_reg); | 1295 | hp_slot, slot_reg); |
1404 | tempdword = 0xe01f3fff; | 1296 | slot_reg &= ~(PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | |
1405 | writel(tempdword, php_ctlr->creg + SLOT1 + (4*hp_slot)); | 1297 | BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | |
1298 | CON_PFAULT_INTR_MASK | SLOT_REG_RSVDZ_MASK); | ||
1299 | shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); | ||
1406 | } | 1300 | } |
1407 | if (!shpchp_poll_mode) { | 1301 | if (!shpchp_poll_mode) { |
1408 | /* Unmask all general input interrupts and SERR */ | 1302 | /* Unmask all general input interrupts and SERR */ |
1409 | tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); | 1303 | tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); |
1410 | tempdword = 0x0000000a; | 1304 | tempdword &= ~(GLOBAL_INTR_MASK | COMMAND_INTR_MASK | |
1411 | writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE); | 1305 | SERR_INTR_RSVDZ_MASK); |
1412 | tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); | 1306 | shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword); |
1307 | tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); | ||
1413 | dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); | 1308 | dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); |
1414 | } | 1309 | } |
1415 | 1310 | ||