blob: 3abeb54964ae5ecca6db65a7f39423eb858c5483 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Standard PCI Hot Plug Driver
3 *
4 * Copyright (C) 1995,2001 Compaq Computer Corporation
5 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
6 * Copyright (C) 2001 IBM Corp.
7 * Copyright (C) 2003-2004 Intel Corporation
8 *
9 * All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or (at
14 * your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
19 * NON INFRINGEMENT. See the GNU General Public License for more
20 * details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
Kristen Accardi8cf4c192005-08-16 15:16:10 -070026 * Send feedback to <greg@kroah.com>,<kristen.c.accardi@intel.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027 *
28 */
29
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/kernel.h>
31#include <linux/module.h>
32#include <linux/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/pci.h>
Andrew Mortond4d28dd2005-11-13 16:06:40 -080034#include <linux/interrupt.h>
35
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include "shpchp.h"
37
38#ifdef DEBUG
39#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */
40#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */
41#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */
42#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */
43#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
44#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
45/* Redefine this flagword to set debug level */
46#define DEBUG_LEVEL DBG_K_STANDARD
47
48#define DEFINE_DBG_BUFFER char __dbg_str_buf[256];
49
50#define DBG_PRINT( dbg_flags, args... ) \
51 do { \
52 if ( DEBUG_LEVEL & ( dbg_flags ) ) \
53 { \
54 int len; \
55 len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
56 __FILE__, __LINE__, __FUNCTION__ ); \
57 sprintf( __dbg_str_buf + len, args ); \
58 printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
59 } \
60 } while (0)
61
62#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
63#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
64#else
65#define DEFINE_DBG_BUFFER
66#define DBG_ENTER_ROUTINE
67#define DBG_LEAVE_ROUTINE
68#endif /* DEBUG */
69
70/* Slot Available Register I field definition */
71#define SLOT_33MHZ 0x0000001f
72#define SLOT_66MHZ_PCIX 0x00001f00
73#define SLOT_100MHZ_PCIX 0x001f0000
74#define SLOT_133MHZ_PCIX 0x1f000000
75
76/* Slot Available Register II field definition */
77#define SLOT_66MHZ 0x0000001f
78#define SLOT_66MHZ_PCIX_266 0x00000f00
79#define SLOT_100MHZ_PCIX_266 0x0000f000
80#define SLOT_133MHZ_PCIX_266 0x000f0000
81#define SLOT_66MHZ_PCIX_533 0x00f00000
82#define SLOT_100MHZ_PCIX_533 0x0f000000
83#define SLOT_133MHZ_PCIX_533 0xf0000000
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085/* Slot Configuration */
86#define SLOT_NUM 0x0000001F
87#define FIRST_DEV_NUM 0x00001F00
88#define PSN 0x07FF0000
89#define UPDOWN 0x20000000
90#define MRLSENSOR 0x40000000
91#define ATTN_BUTTON 0x80000000
92
93/* Slot Status Field Definitions */
94/* Slot State */
95#define PWR_ONLY 0x0001
96#define ENABLED 0x0002
97#define DISABLED 0x0003
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
142/* Power indicator state - Bits 2 & 3 of controller command register*/
143#define SET_PWR_ON 0x04
144#define SET_PWR_BLINK 0x08
145#define SET_PWR_OFF 0x0C
146
147/* Attention indicator state - Bits 4 & 5 of controller command register*/
148#define SET_ATTN_ON 0x010
149#define SET_ATTN_BLINK 0x020
150#define SET_ATTN_OFF 0x030
151
152/* Set bus speed/mode A - 0x40h to 0x47h */
153#define SETA_PCI_33MHZ 0x40
154#define SETA_PCI_66MHZ 0x41
155#define SETA_PCIX_66MHZ 0x42
156#define SETA_PCIX_100MHZ 0x43
157#define SETA_PCIX_133MHZ 0x44
158#define RESERV_1 0x45
159#define RESERV_2 0x46
160#define RESERV_3 0x47
161
162/* Set bus speed/mode B - 0x50h to 0x5fh */
163#define SETB_PCI_33MHZ 0x50
164#define SETB_PCI_66MHZ 0x51
165#define SETB_PCIX_66MHZ_PM 0x52
166#define SETB_PCIX_100MHZ_PM 0x53
167#define SETB_PCIX_133MHZ_PM 0x54
168#define SETB_PCIX_66MHZ_EM 0x55
169#define SETB_PCIX_100MHZ_EM 0x56
170#define SETB_PCIX_133MHZ_EM 0x57
171#define SETB_PCIX_66MHZ_266 0x58
172#define SETB_PCIX_100MHZ_266 0x59
173#define SETB_PCIX_133MHZ_266 0x5a
174#define SETB_PCIX_66MHZ_533 0x5b
175#define SETB_PCIX_100MHZ_533 0x5c
176#define SETB_PCIX_133MHZ_533 0x5d
177
178
179/* Power-on all slots - 0x48h */
180#define SET_PWR_ON_ALL 0x48
181
182/* Enable all slots - 0x49h */
183#define SET_ENABLE_ALL 0x49
184
185/* SHPC controller command error code */
186#define SWITCH_OPEN 0x1
187#define INVALID_CMD 0x2
188#define INVALID_SPEED_MODE 0x4
189
190/* For accessing SHPC Working Register Set */
191#define DWORD_SELECT 0x2
192#define DWORD_DATA 0x4
193#define BASE_OFFSET 0x0
194
195/* Field Offset in Logical Slot Register - byte boundary */
196#define SLOT_EVENT_LATCH 0x2
197#define SLOT_SERR_INT_MASK 0x3
198
199static spinlock_t hpc_event_lock;
200
201DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */
202static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */
203static int ctlr_seq_num = 0; /* Controller sequenc # */
204static spinlock_t list_lock;
205
206static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs);
207
208static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
Kenji Kaneshiged29aadd2006-01-26 09:59:24 +0900209static int hpc_check_cmd_status(struct controller *ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900211static inline u8 shpc_readb(struct controller *ctrl, int reg)
212{
213 return readb(ctrl->hpc_ctlr_handle->creg + reg);
214}
215
216static inline void shpc_writeb(struct controller *ctrl, int reg, u8 val)
217{
218 writeb(val, ctrl->hpc_ctlr_handle->creg + reg);
219}
220
221static inline u16 shpc_readw(struct controller *ctrl, int reg)
222{
223 return readw(ctrl->hpc_ctlr_handle->creg + reg);
224}
225
226static inline void shpc_writew(struct controller *ctrl, int reg, u16 val)
227{
228 writew(val, ctrl->hpc_ctlr_handle->creg + reg);
229}
230
231static inline u32 shpc_readl(struct controller *ctrl, int reg)
232{
233 return readl(ctrl->hpc_ctlr_handle->creg + reg);
234}
235
236static inline void shpc_writel(struct controller *ctrl, int reg, u32 val)
237{
238 writel(val, ctrl->hpc_ctlr_handle->creg + reg);
239}
240
241static inline int shpc_indirect_read(struct controller *ctrl, int index,
242 u32 *value)
243{
244 int rc;
245 u32 cap_offset = ctrl->cap_offset;
246 struct pci_dev *pdev = ctrl->pci_dev;
247
248 rc = pci_write_config_byte(pdev, cap_offset + DWORD_SELECT, index);
249 if (rc)
250 return rc;
251 return pci_read_config_dword(pdev, cap_offset + DWORD_DATA, value);
252}
253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254/* This is the interrupt polling timeout function. */
255static void int_poll_timeout(unsigned long lphp_ctlr)
256{
257 struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr;
258
259 DBG_ENTER_ROUTINE
260
261 if ( !php_ctlr ) {
262 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
263 return;
264 }
265
266 /* Poll for interrupt events. regs == NULL => polling */
267 shpc_isr( 0, (void *)php_ctlr, NULL );
268
269 init_timer(&php_ctlr->int_poll_timer);
270 if (!shpchp_poll_time)
271 shpchp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
272
273 start_int_poll_timer(php_ctlr, shpchp_poll_time);
274
275 return;
276}
277
278/* This function starts the interrupt polling timer. */
279static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
280{
281 if (!php_ctlr) {
282 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
283 return;
284 }
285
286 if ( ( seconds <= 0 ) || ( seconds > 60 ) )
287 seconds = 2; /* Clamp to sane value */
288
289 php_ctlr->int_poll_timer.function = &int_poll_timeout;
290 php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr; /* Instance data */
291 php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ;
292 add_timer(&php_ctlr->int_poll_timer);
293
294 return;
295}
296
Kenji Kaneshigebd62e272005-11-25 12:28:53 +0900297static inline int shpc_wait_cmd(struct controller *ctrl)
298{
299 int retval = 0;
300 unsigned int timeout_msec = shpchp_poll_mode ? 2000 : 1000;
301 unsigned long timeout = msecs_to_jiffies(timeout_msec);
302 int rc = wait_event_interruptible_timeout(ctrl->queue,
303 !ctrl->cmd_busy, timeout);
304 if (!rc) {
305 retval = -EIO;
306 err("Command not completed in %d msec\n", timeout_msec);
307 } else if (rc < 0) {
308 retval = -EINTR;
309 info("Command was interrupted by a signal\n");
310 }
311 ctrl->cmd_busy = 0;
312
313 return retval;
314}
315
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
317{
rajesh.shah@intel.comee138332005-10-13 12:05:42 -0700318 struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900319 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 u16 cmd_status;
321 int retval = 0;
322 u16 temp_word;
323 int i;
324
325 DBG_ENTER_ROUTINE
Kenji Kaneshiged29aadd2006-01-26 09:59:24 +0900326
327 mutex_lock(&slot->ctrl->cmd_lock);
328
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 if (!php_ctlr) {
330 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
Kenji Kaneshiged29aadd2006-01-26 09:59:24 +0900331 retval = -EINVAL;
332 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 }
334
335 for (i = 0; i < 10; i++) {
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900336 cmd_status = shpc_readw(ctrl, CMD_STATUS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
338 if (!(cmd_status & 0x1))
339 break;
340 /* Check every 0.1 sec for a total of 1 sec*/
341 msleep(100);
342 }
343
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900344 cmd_status = shpc_readw(ctrl, CMD_STATUS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
346 if (cmd_status & 0x1) {
347 /* After 1 sec and and the controller is still busy */
348 err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__);
Kenji Kaneshiged29aadd2006-01-26 09:59:24 +0900349 retval = -EBUSY;
350 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 }
352
353 ++t_slot;
354 temp_word = (t_slot << 8) | (cmd & 0xFF);
355 dbg("%s: t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd);
356
357 /* To make sure the Controller Busy bit is 0 before we send out the
358 * command.
359 */
Kenji Kaneshigebd62e272005-11-25 12:28:53 +0900360 slot->ctrl->cmd_busy = 1;
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900361 shpc_writew(ctrl, CMD, temp_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
Kenji Kaneshigebd62e272005-11-25 12:28:53 +0900363 /*
364 * Wait for command completion.
365 */
366 retval = shpc_wait_cmd(slot->ctrl);
Kenji Kaneshiged29aadd2006-01-26 09:59:24 +0900367 if (retval)
368 goto out;
369
370 cmd_status = hpc_check_cmd_status(slot->ctrl);
371 if (cmd_status) {
372 err("%s: Failed to issued command 0x%x (error code = %d)\n",
373 __FUNCTION__, cmd, cmd_status);
374 retval = -EIO;
375 }
376 out:
377 mutex_unlock(&slot->ctrl->cmd_lock);
Kenji Kaneshigebd62e272005-11-25 12:28:53 +0900378
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 DBG_LEAVE_ROUTINE
380 return retval;
381}
382
383static int hpc_check_cmd_status(struct controller *ctrl)
384{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 u16 cmd_status;
386 int retval = 0;
387
388 DBG_ENTER_ROUTINE
389
390 if (!ctrl->hpc_ctlr_handle) {
391 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
392 return -1;
393 }
394
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900395 cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
397 switch (cmd_status >> 1) {
398 case 0:
399 retval = 0;
400 break;
401 case 1:
402 retval = SWITCH_OPEN;
403 err("%s: Switch opened!\n", __FUNCTION__);
404 break;
405 case 2:
406 retval = INVALID_CMD;
407 err("%s: Invalid HPC command!\n", __FUNCTION__);
408 break;
409 case 4:
410 retval = INVALID_SPEED_MODE;
411 err("%s: Invalid bus speed/mode!\n", __FUNCTION__);
412 break;
413 default:
414 retval = cmd_status;
415 }
416
417 DBG_LEAVE_ROUTINE
418 return retval;
419}
420
421
422static int hpc_get_attention_status(struct slot *slot, u8 *status)
423{
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900424 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 u32 slot_reg;
426 u16 slot_status;
427 u8 atten_led_state;
428
429 DBG_ENTER_ROUTINE
430
431 if (!slot->ctrl->hpc_ctlr_handle) {
432 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
433 return -1;
434 }
435
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900436 slot_reg = shpc_readl(ctrl, SLOT1 + 4*(slot->hp_slot));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 slot_status = (u16) slot_reg;
438 atten_led_state = (slot_status & 0x0030) >> 4;
439
440 switch (atten_led_state) {
441 case 0:
442 *status = 0xFF; /* Reserved */
443 break;
444 case 1:
445 *status = 1; /* On */
446 break;
447 case 2:
448 *status = 2; /* Blink */
449 break;
450 case 3:
451 *status = 0; /* Off */
452 break;
453 default:
454 *status = 0xFF;
455 break;
456 }
457
458 DBG_LEAVE_ROUTINE
459 return 0;
460}
461
462static int hpc_get_power_status(struct slot * slot, u8 *status)
463{
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900464 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 u32 slot_reg;
466 u16 slot_status;
467 u8 slot_state;
468 int retval = 0;
469
470 DBG_ENTER_ROUTINE
471
472 if (!slot->ctrl->hpc_ctlr_handle) {
473 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
474 return -1;
475 }
476
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900477 slot_reg = shpc_readl(ctrl, SLOT1 + 4*(slot->hp_slot));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 slot_status = (u16) slot_reg;
479 slot_state = (slot_status & 0x0003);
480
481 switch (slot_state) {
482 case 0:
483 *status = 0xFF;
484 break;
485 case 1:
486 *status = 2; /* Powered only */
487 break;
488 case 2:
489 *status = 1; /* Enabled */
490 break;
491 case 3:
492 *status = 0; /* Disabled */
493 break;
494 default:
495 *status = 0xFF;
496 break;
497 }
498
499 DBG_LEAVE_ROUTINE
500 return retval;
501}
502
503
504static int hpc_get_latch_status(struct slot *slot, u8 *status)
505{
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900506 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 u32 slot_reg;
508 u16 slot_status;
509
510 DBG_ENTER_ROUTINE
511
512 if (!slot->ctrl->hpc_ctlr_handle) {
513 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
514 return -1;
515 }
516
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900517 slot_reg = shpc_readl(ctrl, SLOT1 + 4*(slot->hp_slot));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 slot_status = (u16)slot_reg;
519
520 *status = ((slot_status & 0x0100) == 0) ? 0 : 1; /* 0 -> close; 1 -> open */
521
522
523 DBG_LEAVE_ROUTINE
524 return 0;
525}
526
527static int hpc_get_adapter_status(struct slot *slot, u8 *status)
528{
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900529 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 u32 slot_reg;
531 u16 slot_status;
532 u8 card_state;
533
534 DBG_ENTER_ROUTINE
535
536 if (!slot->ctrl->hpc_ctlr_handle) {
537 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
538 return -1;
539 }
540
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900541 slot_reg = shpc_readl(ctrl, SLOT1 + 4*(slot->hp_slot));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 slot_status = (u16)slot_reg;
543 card_state = (u8)((slot_status & 0x0C00) >> 10);
544 *status = (card_state != 0x3) ? 1 : 0;
545
546 DBG_LEAVE_ROUTINE
547 return 0;
548}
549
550static int hpc_get_prog_int(struct slot *slot, u8 *prog_int)
551{
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900552 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
554 DBG_ENTER_ROUTINE
555
556 if (!slot->ctrl->hpc_ctlr_handle) {
557 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
558 return -1;
559 }
560
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900561 *prog_int = shpc_readb(ctrl, PROG_INTERFACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
563 DBG_LEAVE_ROUTINE
564 return 0;
565}
566
567static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
568{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 int retval = 0;
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900570 struct controller *ctrl = slot->ctrl;
571 u32 slot_reg = shpc_readl(ctrl, SLOT1 + 4 * slot->hp_slot);
Kenji Kaneshige0afabe92006-03-01 14:55:11 +0900572 u8 pcix_cap = (slot_reg >> 12) & 7;
573 u8 m66_cap = (slot_reg >> 9) & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
575 DBG_ENTER_ROUTINE
576
Kenji Kaneshige0afabe92006-03-01 14:55:11 +0900577 dbg("%s: slot_reg = %x, pcix_cap = %x, m66_cap = %x\n",
578 __FUNCTION__, slot_reg, pcix_cap, m66_cap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
Kenji Kaneshige0afabe92006-03-01 14:55:11 +0900580 switch (pcix_cap) {
581 case 0x0:
582 *value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
583 break;
584 case 0x1:
585 *value = PCI_SPEED_66MHz_PCIX;
586 break;
587 case 0x3:
588 *value = PCI_SPEED_133MHz_PCIX;
589 break;
590 case 0x4:
591 *value = PCI_SPEED_133MHz_PCIX_266;
592 break;
593 case 0x5:
594 *value = PCI_SPEED_133MHz_PCIX_533;
595 break;
596 case 0x2:
597 default:
598 *value = PCI_SPEED_UNKNOWN;
599 retval = -ENODEV;
600 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 }
602
603 dbg("Adapter speed = %d\n", *value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 DBG_LEAVE_ROUTINE
605 return retval;
606}
607
608static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
609{
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900610 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 u16 sec_bus_status;
612 u8 pi;
613 int retval = 0;
614
615 DBG_ENTER_ROUTINE
616
617 if (!slot->ctrl->hpc_ctlr_handle) {
618 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
619 return -1;
620 }
621
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900622 pi = shpc_readb(ctrl, PROG_INTERFACE);
623 sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
625 if (pi == 2) {
Kenji Kaneshige87d6c552005-11-24 11:35:05 +0900626 *mode = (sec_bus_status & 0x0100) >> 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 } else {
628 retval = -1;
629 }
630
631 dbg("Mode 1 ECC cap = %d\n", *mode);
632
633 DBG_LEAVE_ROUTINE
634 return retval;
635}
636
637static int hpc_query_power_fault(struct slot * slot)
638{
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900639 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 u32 slot_reg;
641 u16 slot_status;
642 u8 pwr_fault_state, status;
643
644 DBG_ENTER_ROUTINE
645
646 if (!slot->ctrl->hpc_ctlr_handle) {
647 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
648 return -1;
649 }
650
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900651 slot_reg = shpc_readl(ctrl, SLOT1 + 4*(slot->hp_slot));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 slot_status = (u16) slot_reg;
653 pwr_fault_state = (slot_status & 0x0040) >> 7;
654 status = (pwr_fault_state == 1) ? 0 : 1;
655
656 DBG_LEAVE_ROUTINE
657 /* Note: Logic 0 => fault */
658 return status;
659}
660
661static int hpc_set_attention_status(struct slot *slot, u8 value)
662{
rajesh.shah@intel.comee138332005-10-13 12:05:42 -0700663 struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 u8 slot_cmd = 0;
665 int rc = 0;
666
667 if (!slot->ctrl->hpc_ctlr_handle) {
668 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
669 return -1;
670 }
671
672 if (slot->hp_slot >= php_ctlr->num_slots) {
673 err("%s: Invalid HPC slot number!\n", __FUNCTION__);
674 return -1;
675 }
676
677 switch (value) {
678 case 0 :
679 slot_cmd = 0x30; /* OFF */
680 break;
681 case 1:
682 slot_cmd = 0x10; /* ON */
683 break;
684 case 2:
685 slot_cmd = 0x20; /* BLINK */
686 break;
687 default:
688 return -1;
689 }
690
691 shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
692
693 return rc;
694}
695
696
697static void hpc_set_green_led_on(struct slot *slot)
698{
rajesh.shah@intel.comee138332005-10-13 12:05:42 -0700699 struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 u8 slot_cmd;
701
702 if (!slot->ctrl->hpc_ctlr_handle) {
703 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
704 return ;
705 }
706
707 if (slot->hp_slot >= php_ctlr->num_slots) {
708 err("%s: Invalid HPC slot number!\n", __FUNCTION__);
709 return ;
710 }
711
712 slot_cmd = 0x04;
713
714 shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
715
716 return;
717}
718
719static void hpc_set_green_led_off(struct slot *slot)
720{
rajesh.shah@intel.comee138332005-10-13 12:05:42 -0700721 struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 u8 slot_cmd;
723
724 if (!slot->ctrl->hpc_ctlr_handle) {
725 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
726 return ;
727 }
728
729 if (slot->hp_slot >= php_ctlr->num_slots) {
730 err("%s: Invalid HPC slot number!\n", __FUNCTION__);
731 return ;
732 }
733
734 slot_cmd = 0x0C;
735
736 shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
737
738 return;
739}
740
741static void hpc_set_green_led_blink(struct slot *slot)
742{
rajesh.shah@intel.comee138332005-10-13 12:05:42 -0700743 struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 u8 slot_cmd;
745
746 if (!slot->ctrl->hpc_ctlr_handle) {
747 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
748 return ;
749 }
750
751 if (slot->hp_slot >= php_ctlr->num_slots) {
752 err("%s: Invalid HPC slot number!\n", __FUNCTION__);
753 return ;
754 }
755
756 slot_cmd = 0x08;
757
758 shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
759
760 return;
761}
762
763int shpc_get_ctlr_slot_config(struct controller *ctrl,
764 int *num_ctlr_slots, /* number of slots in this HPC */
765 int *first_device_num, /* PCI dev num of the first slot in this SHPC */
766 int *physical_slot_num, /* phy slot num of the first slot in this SHPC */
767 int *updown, /* physical_slot_num increament: 1 or -1 */
768 int *flags)
769{
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900770 u32 slot_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
772 DBG_ENTER_ROUTINE
773
774 if (!ctrl->hpc_ctlr_handle) {
775 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
776 return -1;
777 }
778
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900779 slot_config = shpc_readl(ctrl, SLOT_CONFIG);
780 *first_device_num = (slot_config & FIRST_DEV_NUM) >> 8;
781 *num_ctlr_slots = slot_config & SLOT_NUM;
782 *physical_slot_num = (slot_config & PSN) >> 16;
783 *updown = ((slot_config & UPDOWN) >> 29) ? 1 : -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
787 DBG_LEAVE_ROUTINE
788 return 0;
789}
790
791static void hpc_release_ctlr(struct controller *ctrl)
792{
rajesh.shah@intel.comee138332005-10-13 12:05:42 -0700793 struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 struct php_ctlr_state_s *p, *p_prev;
Kenji Kaneshigef7391f52006-02-21 15:45:45 -0800795 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
797 DBG_ENTER_ROUTINE
798
799 if (!ctrl->hpc_ctlr_handle) {
800 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
801 return ;
802 }
803
Kenji Kaneshigef7391f52006-02-21 15:45:45 -0800804 /*
805 * Mask all slot event interrupts
806 */
807 for (i = 0; i < ctrl->num_slots; i++)
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900808 shpc_writel(ctrl, SLOT1 + (4 * i), 0xffff3fff);
Kenji Kaneshigef7391f52006-02-21 15:45:45 -0800809
810 cleanup_slots(ctrl);
811
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 if (shpchp_poll_mode) {
813 del_timer(&php_ctlr->int_poll_timer);
814 } else {
815 if (php_ctlr->irq) {
816 free_irq(php_ctlr->irq, ctrl);
817 php_ctlr->irq = 0;
818 pci_disable_msi(php_ctlr->pci_dev);
819 }
820 }
Kenji Kaneshigef7391f52006-02-21 15:45:45 -0800821
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 if (php_ctlr->pci_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 iounmap(php_ctlr->creg);
Kenji Kaneshige04559862005-11-24 11:36:59 +0900824 release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 php_ctlr->pci_dev = NULL;
826 }
827
828 spin_lock(&list_lock);
829 p = php_ctlr_list_head;
830 p_prev = NULL;
831 while (p) {
832 if (p == php_ctlr) {
833 if (p_prev)
834 p_prev->pnext = p->pnext;
835 else
836 php_ctlr_list_head = p->pnext;
837 break;
838 } else {
839 p_prev = p;
840 p = p->pnext;
841 }
842 }
843 spin_unlock(&list_lock);
844
845 kfree(php_ctlr);
846
847DBG_LEAVE_ROUTINE
848
849}
850
851static int hpc_power_on_slot(struct slot * slot)
852{
rajesh.shah@intel.comee138332005-10-13 12:05:42 -0700853 struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 u8 slot_cmd;
855 int retval = 0;
856
857 DBG_ENTER_ROUTINE
858
859 if (!slot->ctrl->hpc_ctlr_handle) {
860 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
861 return -1;
862 }
863
864 if (slot->hp_slot >= php_ctlr->num_slots) {
865 err("%s: Invalid HPC slot number!\n", __FUNCTION__);
866 return -1;
867 }
868 slot_cmd = 0x01;
869
870 retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
871
872 if (retval) {
873 err("%s: Write command failed!\n", __FUNCTION__);
874 return -1;
875 }
876
877 DBG_LEAVE_ROUTINE
878
879 return retval;
880}
881
882static int hpc_slot_enable(struct slot * slot)
883{
rajesh.shah@intel.comee138332005-10-13 12:05:42 -0700884 struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 u8 slot_cmd;
886 int retval = 0;
887
888 DBG_ENTER_ROUTINE
889
890 if (!slot->ctrl->hpc_ctlr_handle) {
891 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
892 return -1;
893 }
894
895 if (slot->hp_slot >= php_ctlr->num_slots) {
896 err("%s: Invalid HPC slot number!\n", __FUNCTION__);
897 return -1;
898 }
899 /* 3A => Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */
900 slot_cmd = 0x3A;
901
902 retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
903
904 if (retval) {
905 err("%s: Write command failed!\n", __FUNCTION__);
906 return -1;
907 }
908
909 DBG_LEAVE_ROUTINE
910 return retval;
911}
912
913static int hpc_slot_disable(struct slot * slot)
914{
rajesh.shah@intel.comee138332005-10-13 12:05:42 -0700915 struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 u8 slot_cmd;
917 int retval = 0;
918
919 DBG_ENTER_ROUTINE
920
921 if (!slot->ctrl->hpc_ctlr_handle) {
922 err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
923 return -1;
924 }
925
926 if (slot->hp_slot >= php_ctlr->num_slots) {
927 err("%s: Invalid HPC slot number!\n", __FUNCTION__);
928 return -1;
929 }
930
931 /* 1F => Slot - Disable, Power Indicator - Off, Attention Indicator - On */
932 slot_cmd = 0x1F;
933
934 retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
935
936 if (retval) {
937 err("%s: Write command failed!\n", __FUNCTION__);
938 return -1;
939 }
940
941 DBG_LEAVE_ROUTINE
942 return retval;
943}
944
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
946{
Kenji Kaneshige0afabe92006-03-01 14:55:11 +0900947 int retval;
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900948 struct controller *ctrl = slot->ctrl;
Kenji Kaneshige0afabe92006-03-01 14:55:11 +0900949 u8 pi, cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
951 DBG_ENTER_ROUTINE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Kenji Kaneshige75d97c52006-05-02 11:08:42 +0900953 pi = shpc_readb(ctrl, PROG_INTERFACE);
Kenji Kaneshige0afabe92006-03-01 14:55:11 +0900954 if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX))
955 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
Kenji Kaneshige0afabe92006-03-01 14:55:11 +0900957 switch (value) {
958 case PCI_SPEED_33MHz:
959 cmd = SETA_PCI_33MHZ;
960 break;
961 case PCI_SPEED_66MHz:
962 cmd = SETA_PCI_66MHZ;
963 break;
964 case PCI_SPEED_66MHz_PCIX:
965 cmd = SETA_PCIX_66MHZ;
966 break;
967 case PCI_SPEED_100MHz_PCIX:
968 cmd = SETA_PCIX_100MHZ;
969 break;
970 case PCI_SPEED_133MHz_PCIX:
971 cmd = SETA_PCIX_133MHZ;
972 break;
973 case PCI_SPEED_66MHz_PCIX_ECC:
974 cmd = SETB_PCIX_66MHZ_EM;
975 break;
976 case PCI_SPEED_100MHz_PCIX_ECC:
977 cmd = SETB_PCIX_100MHZ_EM;
978 break;
979 case PCI_SPEED_133MHz_PCIX_ECC:
980 cmd = SETB_PCIX_133MHZ_EM;
981 break;
982 case PCI_SPEED_66MHz_PCIX_266:
983 cmd = SETB_PCIX_66MHZ_266;
984 break;
985 case PCI_SPEED_100MHz_PCIX_266:
986 cmd = SETB_PCIX_100MHZ_266;
987 break;
988 case PCI_SPEED_133MHz_PCIX_266:
989 cmd = SETB_PCIX_133MHZ_266;
990 break;
991 case PCI_SPEED_66MHz_PCIX_533:
992 cmd = SETB_PCIX_66MHZ_533;
993 break;
994 case PCI_SPEED_100MHz_PCIX_533:
995 cmd = SETB_PCIX_100MHZ_533;
996 break;
997 case PCI_SPEED_133MHz_PCIX_533:
998 cmd = SETB_PCIX_133MHZ_533;
999 break;
1000 default:
1001 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 }
Kenji Kaneshige0afabe92006-03-01 14:55:11 +09001003
1004 retval = shpc_write_cmd(slot, 0, cmd);
1005 if (retval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 err("%s: Write command failed!\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
1008 DBG_LEAVE_ROUTINE
1009 return retval;
1010}
1011
1012static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs)
1013{
1014 struct controller *ctrl = NULL;
1015 struct php_ctlr_state_s *php_ctlr;
1016 u8 schedule_flag = 0;
1017 u8 temp_byte;
1018 u32 temp_dword, intr_loc, intr_loc2;
1019 int hp_slot;
1020
1021 if (!dev_id)
1022 return IRQ_NONE;
1023
1024 if (!shpchp_poll_mode) {
1025 ctrl = (struct controller *)dev_id;
1026 php_ctlr = ctrl->hpc_ctlr_handle;
1027 } else {
1028 php_ctlr = (struct php_ctlr_state_s *) dev_id;
1029 ctrl = (struct controller *)php_ctlr->callback_instance_id;
1030 }
1031
1032 if (!ctrl)
1033 return IRQ_NONE;
1034
1035 if (!php_ctlr || !php_ctlr->creg)
1036 return IRQ_NONE;
1037
1038 /* Check to see if it was our interrupt */
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001039 intr_loc = shpc_readl(ctrl, INTR_LOC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
1041 if (!intr_loc)
1042 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc);
1044
1045 if(!shpchp_poll_mode) {
1046 /* Mask Global Interrupt Mask - see implementation note on p. 139 */
1047 /* of SHPC spec rev 1.0*/
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001048 temp_dword = shpc_readl(ctrl, SERR_INTR_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 temp_dword |= 0x00000001;
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001050 shpc_writel(ctrl, SERR_INTR_ENABLE, temp_dword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001052 intr_loc2 = shpc_readl(ctrl, INTR_LOC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2);
1054 }
1055
1056 if (intr_loc & 0x0001) {
1057 /*
1058 * Command Complete Interrupt Pending
Kenji Kaneshigef467f612005-11-24 11:39:29 +09001059 * RO only - clear by writing 1 to the Command Completion
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 * Detect bit in Controller SERR-INT register
1061 */
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001062 temp_dword = shpc_readl(ctrl, SERR_INTR_ENABLE);
Kenji Kaneshigef467f612005-11-24 11:39:29 +09001063 temp_dword &= 0xfffdffff;
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001064 shpc_writel(ctrl, SERR_INTR_ENABLE, temp_dword);
Kenji Kaneshigebd62e272005-11-25 12:28:53 +09001065 ctrl->cmd_busy = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 wake_up_interruptible(&ctrl->queue);
1067 }
1068
Kenji Kaneshigee4e73042006-01-26 10:05:57 +09001069 if ((intr_loc = (intr_loc >> 1)) == 0)
1070 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
1072 for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {
1073 /* To find out which slot has interrupt pending */
1074 if ((intr_loc >> hp_slot) & 0x01) {
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001075 temp_dword = shpc_readl(ctrl, SLOT1 + (4*hp_slot));
rajesh.shah@intel.com7c8942f2005-10-13 12:05:43 -07001076 dbg("%s: Slot %x with intr, slot register = %x\n",
1077 __FUNCTION__, hp_slot, temp_dword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 temp_byte = (temp_dword >> 16) & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 if ((php_ctlr->switch_change_callback) && (temp_byte & 0x08))
1080 schedule_flag += php_ctlr->switch_change_callback(
1081 hp_slot, php_ctlr->callback_instance_id);
1082 if ((php_ctlr->attention_button_callback) && (temp_byte & 0x04))
1083 schedule_flag += php_ctlr->attention_button_callback(
1084 hp_slot, php_ctlr->callback_instance_id);
1085 if ((php_ctlr->presence_change_callback) && (temp_byte & 0x01))
1086 schedule_flag += php_ctlr->presence_change_callback(
1087 hp_slot , php_ctlr->callback_instance_id);
1088 if ((php_ctlr->power_fault_callback) && (temp_byte & 0x12))
1089 schedule_flag += php_ctlr->power_fault_callback(
1090 hp_slot, php_ctlr->callback_instance_id);
1091
1092 /* Clear all slot events */
1093 temp_dword = 0xe01f3fff;
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001094 shpc_writel(ctrl, SLOT1 + (4*hp_slot), temp_dword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001096 intr_loc2 = shpc_readl(ctrl, INTR_LOC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2);
1098 }
1099 }
Kenji Kaneshigee4e73042006-01-26 10:05:57 +09001100 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 if (!shpchp_poll_mode) {
1102 /* Unmask Global Interrupt Mask */
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001103 temp_dword = shpc_readl(ctrl, SERR_INTR_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 temp_dword &= 0xfffffffe;
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001105 shpc_writel(ctrl, SERR_INTR_ENABLE, temp_dword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 }
1107
1108 return IRQ_HANDLED;
1109}
1110
1111static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
1112{
Kenji Kaneshige0afabe92006-03-01 14:55:11 +09001113 int retval = 0;
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001114 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001116 u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
1117 u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1);
1118 u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
1120 DBG_ENTER_ROUTINE
1121
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 if (pi == 2) {
Kenji Kaneshige6558b6a2005-11-24 13:44:01 +09001123 if (slot_avail2 & SLOT_133MHZ_PCIX_533)
Kenji Kaneshige0afabe92006-03-01 14:55:11 +09001124 bus_speed = PCI_SPEED_133MHz_PCIX_533;
Kenji Kaneshige6558b6a2005-11-24 13:44:01 +09001125 else if (slot_avail2 & SLOT_100MHZ_PCIX_533)
Kenji Kaneshige0afabe92006-03-01 14:55:11 +09001126 bus_speed = PCI_SPEED_100MHz_PCIX_533;
Kenji Kaneshige6558b6a2005-11-24 13:44:01 +09001127 else if (slot_avail2 & SLOT_66MHZ_PCIX_533)
Kenji Kaneshige0afabe92006-03-01 14:55:11 +09001128 bus_speed = PCI_SPEED_66MHz_PCIX_533;
Kenji Kaneshige6558b6a2005-11-24 13:44:01 +09001129 else if (slot_avail2 & SLOT_133MHZ_PCIX_266)
Kenji Kaneshige0afabe92006-03-01 14:55:11 +09001130 bus_speed = PCI_SPEED_133MHz_PCIX_266;
Kenji Kaneshige6558b6a2005-11-24 13:44:01 +09001131 else if (slot_avail2 & SLOT_100MHZ_PCIX_266)
Kenji Kaneshige0afabe92006-03-01 14:55:11 +09001132 bus_speed = PCI_SPEED_100MHz_PCIX_266;
Kenji Kaneshige6558b6a2005-11-24 13:44:01 +09001133 else if (slot_avail2 & SLOT_66MHZ_PCIX_266)
Kenji Kaneshige0afabe92006-03-01 14:55:11 +09001134 bus_speed = PCI_SPEED_66MHz_PCIX_266;
1135 }
1136
1137 if (bus_speed == PCI_SPEED_UNKNOWN) {
Kenji Kaneshige6558b6a2005-11-24 13:44:01 +09001138 if (slot_avail1 & SLOT_133MHZ_PCIX)
Kenji Kaneshige0afabe92006-03-01 14:55:11 +09001139 bus_speed = PCI_SPEED_133MHz_PCIX;
Kenji Kaneshige6558b6a2005-11-24 13:44:01 +09001140 else if (slot_avail1 & SLOT_100MHZ_PCIX)
Kenji Kaneshige0afabe92006-03-01 14:55:11 +09001141 bus_speed = PCI_SPEED_100MHz_PCIX;
Kenji Kaneshige6558b6a2005-11-24 13:44:01 +09001142 else if (slot_avail1 & SLOT_66MHZ_PCIX)
Kenji Kaneshige0afabe92006-03-01 14:55:11 +09001143 bus_speed = PCI_SPEED_66MHz_PCIX;
Kenji Kaneshige6558b6a2005-11-24 13:44:01 +09001144 else if (slot_avail2 & SLOT_66MHZ)
Kenji Kaneshige0afabe92006-03-01 14:55:11 +09001145 bus_speed = PCI_SPEED_66MHz;
Kenji Kaneshige6558b6a2005-11-24 13:44:01 +09001146 else if (slot_avail1 & SLOT_33MHZ)
Kenji Kaneshige0afabe92006-03-01 14:55:11 +09001147 bus_speed = PCI_SPEED_33MHz;
1148 else
1149 retval = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 }
1151
1152 *value = bus_speed;
1153 dbg("Max bus speed = %d\n", bus_speed);
1154 DBG_LEAVE_ROUTINE
1155 return retval;
1156}
1157
1158static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
1159{
Kenji Kaneshige0afabe92006-03-01 14:55:11 +09001160 int retval = 0;
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001161 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001163 u16 sec_bus_reg = shpc_readw(ctrl, SEC_BUS_CONFIG);
1164 u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
Kenji Kaneshige0afabe92006-03-01 14:55:11 +09001165 u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
1167 DBG_ENTER_ROUTINE
1168
Kenji Kaneshige0afabe92006-03-01 14:55:11 +09001169 if ((pi == 1) && (speed_mode > 4)) {
1170 *value = PCI_SPEED_UNKNOWN;
1171 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 }
1173
Kenji Kaneshige0afabe92006-03-01 14:55:11 +09001174 switch (speed_mode) {
1175 case 0x0:
1176 *value = PCI_SPEED_33MHz;
1177 break;
1178 case 0x1:
1179 *value = PCI_SPEED_66MHz;
1180 break;
1181 case 0x2:
1182 *value = PCI_SPEED_66MHz_PCIX;
1183 break;
1184 case 0x3:
1185 *value = PCI_SPEED_100MHz_PCIX;
1186 break;
1187 case 0x4:
1188 *value = PCI_SPEED_133MHz_PCIX;
1189 break;
1190 case 0x5:
1191 *value = PCI_SPEED_66MHz_PCIX_ECC;
1192 break;
1193 case 0x6:
1194 *value = PCI_SPEED_100MHz_PCIX_ECC;
1195 break;
1196 case 0x7:
1197 *value = PCI_SPEED_133MHz_PCIX_ECC;
1198 break;
1199 case 0x8:
1200 *value = PCI_SPEED_66MHz_PCIX_266;
1201 break;
1202 case 0x9:
1203 *value = PCI_SPEED_100MHz_PCIX_266;
1204 break;
1205 case 0xa:
1206 *value = PCI_SPEED_133MHz_PCIX_266;
1207 break;
1208 case 0xb:
1209 *value = PCI_SPEED_66MHz_PCIX_533;
1210 break;
1211 case 0xc:
1212 *value = PCI_SPEED_100MHz_PCIX_533;
1213 break;
1214 case 0xd:
1215 *value = PCI_SPEED_133MHz_PCIX_533;
1216 break;
1217 default:
1218 *value = PCI_SPEED_UNKNOWN;
1219 retval = -ENODEV;
1220 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 }
1222
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 dbg("Current bus speed = %d\n", bus_speed);
1224 DBG_LEAVE_ROUTINE
1225 return retval;
1226}
1227
1228static struct hpc_ops shpchp_hpc_ops = {
1229 .power_on_slot = hpc_power_on_slot,
1230 .slot_enable = hpc_slot_enable,
1231 .slot_disable = hpc_slot_disable,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 .set_bus_speed_mode = hpc_set_bus_speed_mode,
1233 .set_attention_status = hpc_set_attention_status,
1234 .get_power_status = hpc_get_power_status,
1235 .get_attention_status = hpc_get_attention_status,
1236 .get_latch_status = hpc_get_latch_status,
1237 .get_adapter_status = hpc_get_adapter_status,
1238
1239 .get_max_bus_speed = hpc_get_max_bus_speed,
1240 .get_cur_bus_speed = hpc_get_cur_bus_speed,
1241 .get_adapter_speed = hpc_get_adapter_speed,
1242 .get_mode1_ECC_cap = hpc_get_mode1_ECC_cap,
1243 .get_prog_int = hpc_get_prog_int,
1244
1245 .query_power_fault = hpc_query_power_fault,
1246 .green_led_on = hpc_set_green_led_on,
1247 .green_led_off = hpc_set_green_led_off,
1248 .green_led_blink = hpc_set_green_led_blink,
1249
1250 .release_ctlr = hpc_release_ctlr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251};
1252
rajesh.shah@intel.comee138332005-10-13 12:05:42 -07001253int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254{
1255 struct php_ctlr_state_s *php_ctlr, *p;
1256 void *instance_id = ctrl;
Kenji Kaneshige04559862005-11-24 11:36:59 +09001257 int rc, num_slots = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 u8 hp_slot;
1259 static int first = 1;
Kenji Kaneshige04559862005-11-24 11:36:59 +09001260 u32 shpc_base_offset;
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001261 u32 tempdword, slot_reg, slot_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 u8 i;
1263
1264 DBG_ENTER_ROUTINE
1265
Kenji Kaneshige04559862005-11-24 11:36:59 +09001266 ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */
1267
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 spin_lock_init(&list_lock);
Kenji Kaneshige57c95c02006-01-26 10:02:41 +09001269 php_ctlr = kzalloc(sizeof(*php_ctlr), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270
1271 if (!php_ctlr) { /* allocate controller state data */
1272 err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
1273 goto abort;
1274 }
1275
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 php_ctlr->pci_dev = pdev; /* save pci_dev in context */
1277
rajesh.shah@intel.comee138332005-10-13 12:05:42 -07001278 if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device ==
1279 PCI_DEVICE_ID_AMD_GOLAM_7450)) {
Kenji Kaneshige04559862005-11-24 11:36:59 +09001280 /* amd shpc driver doesn't use Base Offset; assume 0 */
1281 ctrl->mmio_base = pci_resource_start(pdev, 0);
1282 ctrl->mmio_size = pci_resource_len(pdev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 } else {
Kenji Kaneshige04559862005-11-24 11:36:59 +09001284 ctrl->cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC);
1285 if (!ctrl->cap_offset) {
1286 err("%s : cap_offset == 0\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 goto abort_free_ctlr;
1288 }
Kenji Kaneshige04559862005-11-24 11:36:59 +09001289 dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset);
1290
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001291 rc = shpc_indirect_read(ctrl, 0, &shpc_base_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 if (rc) {
Kenji Kaneshige04559862005-11-24 11:36:59 +09001293 err("%s: cannot read base_offset\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 goto abort_free_ctlr;
1295 }
1296
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001297 rc = shpc_indirect_read(ctrl, 3, &tempdword);
Kenji Kaneshige04559862005-11-24 11:36:59 +09001298 if (rc) {
1299 err("%s: cannot read slot config\n", __FUNCTION__);
1300 goto abort_free_ctlr;
1301 }
1302 num_slots = tempdword & SLOT_NUM;
1303 dbg("%s: num_slots (indirect) %x\n", __FUNCTION__, num_slots);
1304
1305 for (i = 0; i < 9 + num_slots; i++) {
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001306 rc = shpc_indirect_read(ctrl, i, &tempdword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 if (rc) {
Kenji Kaneshige04559862005-11-24 11:36:59 +09001308 err("%s: cannot read creg (index = %d)\n",
1309 __FUNCTION__, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 goto abort_free_ctlr;
1311 }
rajesh.shah@intel.com7c8942f2005-10-13 12:05:43 -07001312 dbg("%s: offset %d: value %x\n", __FUNCTION__,i,
1313 tempdword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 }
Kenji Kaneshige04559862005-11-24 11:36:59 +09001315
1316 ctrl->mmio_base =
1317 pci_resource_start(pdev, 0) + shpc_base_offset;
1318 ctrl->mmio_size = 0x24 + 0x4 * num_slots;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 }
1320
1321 if (first) {
1322 spin_lock_init(&hpc_event_lock);
1323 first = 0;
1324 }
1325
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor,
1327 pdev->subsystem_device);
1328
1329 if (pci_enable_device(pdev))
1330 goto abort_free_ctlr;
1331
Kenji Kaneshige04559862005-11-24 11:36:59 +09001332 if (!request_mem_region(ctrl->mmio_base, ctrl->mmio_size, MY_NAME)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 err("%s: cannot reserve MMIO region\n", __FUNCTION__);
1334 goto abort_free_ctlr;
1335 }
1336
Kenji Kaneshige04559862005-11-24 11:36:59 +09001337 php_ctlr->creg = ioremap(ctrl->mmio_base, ctrl->mmio_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 if (!php_ctlr->creg) {
Kenji Kaneshige04559862005-11-24 11:36:59 +09001339 err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__,
1340 ctrl->mmio_size, ctrl->mmio_base);
1341 release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 goto abort_free_ctlr;
1343 }
1344 dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
Ingo Molnar6aa4cdd2006-01-13 16:02:15 +01001346 mutex_init(&ctrl->crit_sect);
Kenji Kaneshiged29aadd2006-01-26 09:59:24 +09001347 mutex_init(&ctrl->cmd_lock);
1348
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 /* Setup wait queue */
1350 init_waitqueue_head(&ctrl->queue);
1351
1352 /* Find the IRQ */
1353 php_ctlr->irq = pdev->irq;
rajesh.shah@intel.comee138332005-10-13 12:05:42 -07001354 php_ctlr->attention_button_callback = shpchp_handle_attention_button,
1355 php_ctlr->switch_change_callback = shpchp_handle_switch_change;
1356 php_ctlr->presence_change_callback = shpchp_handle_presence_change;
1357 php_ctlr->power_fault_callback = shpchp_handle_power_fault;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 php_ctlr->callback_instance_id = instance_id;
1359
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001360 ctrl->hpc_ctlr_handle = php_ctlr;
1361 ctrl->hpc_ops = &shpchp_hpc_ops;
1362
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 /* Return PCI Controller Info */
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001364 slot_config = shpc_readl(ctrl, SLOT_CONFIG);
1365 php_ctlr->slot_device_offset = (slot_config & FIRST_DEV_NUM) >> 8;
1366 php_ctlr->num_slots = slot_config & SLOT_NUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset);
1368 dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots);
1369
1370 /* Mask Global Interrupt Mask & Command Complete Interrupt Mask */
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001371 tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
1373 tempdword = 0x0003000f;
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001374 shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword);
1375 tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
1377
1378 /* Mask the MRL sensor SERR Mask of individual slot in
1379 * Slot SERR-INT Mask & clear all the existing event if any
1380 */
1381 for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) {
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001382 slot_reg = shpc_readl(ctrl, SLOT1 + 4*hp_slot );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
1384 hp_slot, slot_reg);
1385 tempdword = 0xffff3fff;
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001386 shpc_writel(ctrl, SLOT1 + (4*hp_slot), tempdword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 }
1388
1389 if (shpchp_poll_mode) {/* Install interrupt polling code */
1390 /* Install and start the interrupt polling timer */
1391 init_timer(&php_ctlr->int_poll_timer);
1392 start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */
1393 } else {
1394 /* Installs the interrupt handler */
1395 rc = pci_enable_msi(pdev);
1396 if (rc) {
1397 info("Can't get msi for the hotplug controller\n");
1398 info("Use INTx for the hotplug controller\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 } else
1400 php_ctlr->irq = pdev->irq;
1401
1402 rc = request_irq(php_ctlr->irq, shpc_isr, SA_SHIRQ, MY_NAME, (void *) ctrl);
1403 dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
1404 if (rc) {
1405 err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
1406 goto abort_free_ctlr;
1407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 }
rajesh.shah@intel.com7c8942f2005-10-13 12:05:43 -07001409 dbg("%s: HPC at b:d:f:irq=0x%x:%x:%x:%x\n", __FUNCTION__,
1410 pdev->bus->number, PCI_SLOT(pdev->devfn),
1411 PCI_FUNC(pdev->devfn), pdev->irq);
rajesh.shah@intel.com424600f2005-10-13 12:05:38 -07001412 get_hp_hw_control_from_firmware(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413
1414 /* Add this HPC instance into the HPC list */
1415 spin_lock(&list_lock);
1416 if (php_ctlr_list_head == 0) {
1417 php_ctlr_list_head = php_ctlr;
1418 p = php_ctlr_list_head;
1419 p->pnext = NULL;
1420 } else {
1421 p = php_ctlr_list_head;
1422
1423 while (p->pnext)
1424 p = p->pnext;
1425
1426 p->pnext = php_ctlr;
1427 }
1428 spin_unlock(&list_lock);
1429
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 ctlr_seq_num++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431
1432 for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) {
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001433 slot_reg = shpc_readl(ctrl, SLOT1 + 4*hp_slot );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
1435 hp_slot, slot_reg);
1436 tempdword = 0xe01f3fff;
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001437 shpc_writel(ctrl, SLOT1 + (4*hp_slot), tempdword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 }
1439 if (!shpchp_poll_mode) {
1440 /* Unmask all general input interrupts and SERR */
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001441 tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 tempdword = 0x0000000a;
Kenji Kaneshige75d97c52006-05-02 11:08:42 +09001443 shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword);
1444 tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
1446 }
1447
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 DBG_LEAVE_ROUTINE
1449 return 0;
1450
1451 /* We end up here for the many possible ways to fail this API. */
1452abort_free_ctlr:
1453 kfree(php_ctlr);
1454abort:
1455 DBG_LEAVE_ROUTINE
1456 return -1;
1457}