blob: 016eea94a8a5729d1cf6e5908a2c6a205d4b6149 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * PCI Express 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>
Tim Schmielaude259682006-01-08 01:02:05 -080033#include <linux/signal.h>
34#include <linux/jiffies.h>
35#include <linux/timer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/pci.h>
Andrew Morton5d1b8c92005-11-13 16:06:39 -080037#include <linux/interrupt.h>
Kristen Carlson Accardi34d03412007-01-09 13:02:36 -080038#include <linux/time.h>
Andrew Morton5d1b8c92005-11-13 16:06:39 -080039
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include "../pci.h"
41#include "pciehp.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#ifdef DEBUG
43#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */
44#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */
45#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */
46#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */
47#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
48#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
49/* Redefine this flagword to set debug level */
50#define DEBUG_LEVEL DBG_K_STANDARD
51
52#define DEFINE_DBG_BUFFER char __dbg_str_buf[256];
53
54#define DBG_PRINT( dbg_flags, args... ) \
55 do { \
56 if ( DEBUG_LEVEL & ( dbg_flags ) ) \
57 { \
58 int len; \
59 len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
60 __FILE__, __LINE__, __FUNCTION__ ); \
61 sprintf( __dbg_str_buf + len, args ); \
62 printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
63 } \
64 } while (0)
65
66#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
67#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
68#else
69#define DEFINE_DBG_BUFFER
70#define DBG_ENTER_ROUTINE
71#define DBG_LEAVE_ROUTINE
72#endif /* DEBUG */
73
Kenji Kaneshige5d386e12007-03-06 15:02:26 -080074static atomic_t pciehp_num_controllers = ATOMIC_INIT(0);
75
Linus Torvalds1da177e2005-04-16 15:20:36 -070076struct ctrl_reg {
77 u8 cap_id;
78 u8 nxt_ptr;
79 u16 cap_reg;
80 u32 dev_cap;
81 u16 dev_ctrl;
82 u16 dev_status;
83 u32 lnk_cap;
84 u16 lnk_ctrl;
85 u16 lnk_status;
86 u32 slot_cap;
87 u16 slot_ctrl;
88 u16 slot_status;
89 u16 root_ctrl;
90 u16 rsvp;
91 u32 root_status;
92} __attribute__ ((packed));
93
94/* offsets to the controller registers based on the above structure layout */
95enum ctrl_offsets {
96 PCIECAPID = offsetof(struct ctrl_reg, cap_id),
97 NXTCAPPTR = offsetof(struct ctrl_reg, nxt_ptr),
98 CAPREG = offsetof(struct ctrl_reg, cap_reg),
99 DEVCAP = offsetof(struct ctrl_reg, dev_cap),
100 DEVCTRL = offsetof(struct ctrl_reg, dev_ctrl),
101 DEVSTATUS = offsetof(struct ctrl_reg, dev_status),
102 LNKCAP = offsetof(struct ctrl_reg, lnk_cap),
103 LNKCTRL = offsetof(struct ctrl_reg, lnk_ctrl),
104 LNKSTATUS = offsetof(struct ctrl_reg, lnk_status),
105 SLOTCAP = offsetof(struct ctrl_reg, slot_cap),
106 SLOTCTRL = offsetof(struct ctrl_reg, slot_ctrl),
107 SLOTSTATUS = offsetof(struct ctrl_reg, slot_status),
108 ROOTCTRL = offsetof(struct ctrl_reg, root_ctrl),
109 ROOTSTATUS = offsetof(struct ctrl_reg, root_status),
110};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800112static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value)
113{
114 struct pci_dev *dev = ctrl->pci_dev;
115 return pci_read_config_word(dev, ctrl->cap_base + reg, value);
116}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800118static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value)
119{
120 struct pci_dev *dev = ctrl->pci_dev;
121 return pci_read_config_dword(dev, ctrl->cap_base + reg, value);
122}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800124static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value)
125{
126 struct pci_dev *dev = ctrl->pci_dev;
127 return pci_write_config_word(dev, ctrl->cap_base + reg, value);
128}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800130static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
131{
132 struct pci_dev *dev = ctrl->pci_dev;
133 return pci_write_config_dword(dev, ctrl->cap_base + reg, value);
134}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
136/* Field definitions in PCI Express Capabilities Register */
137#define CAP_VER 0x000F
138#define DEV_PORT_TYPE 0x00F0
139#define SLOT_IMPL 0x0100
140#define MSG_NUM 0x3E00
141
142/* Device or Port Type */
143#define NAT_ENDPT 0x00
144#define LEG_ENDPT 0x01
145#define ROOT_PORT 0x04
146#define UP_STREAM 0x05
147#define DN_STREAM 0x06
148#define PCIE_PCI_BRDG 0x07
149#define PCI_PCIE_BRDG 0x10
150
151/* Field definitions in Device Capabilities Register */
152#define DATTN_BUTTN_PRSN 0x1000
153#define DATTN_LED_PRSN 0x2000
154#define DPWR_LED_PRSN 0x4000
155
156/* Field definitions in Link Capabilities Register */
157#define MAX_LNK_SPEED 0x000F
158#define MAX_LNK_WIDTH 0x03F0
159
160/* Link Width Encoding */
161#define LNK_X1 0x01
162#define LNK_X2 0x02
163#define LNK_X4 0x04
164#define LNK_X8 0x08
165#define LNK_X12 0x0C
166#define LNK_X16 0x10
167#define LNK_X32 0x20
168
169/*Field definitions of Link Status Register */
170#define LNK_SPEED 0x000F
171#define NEG_LINK_WD 0x03F0
172#define LNK_TRN_ERR 0x0400
173#define LNK_TRN 0x0800
174#define SLOT_CLK_CONF 0x1000
175
176/* Field definitions in Slot Capabilities Register */
177#define ATTN_BUTTN_PRSN 0x00000001
178#define PWR_CTRL_PRSN 0x00000002
179#define MRL_SENS_PRSN 0x00000004
180#define ATTN_LED_PRSN 0x00000008
181#define PWR_LED_PRSN 0x00000010
182#define HP_SUPR_RM_SUP 0x00000020
183#define HP_CAP 0x00000040
184#define SLOT_PWR_VALUE 0x000003F8
185#define SLOT_PWR_LIMIT 0x00000C00
186#define PSN 0xFFF80000 /* PSN: Physical Slot Number */
187
188/* Field definitions in Slot Control Register */
189#define ATTN_BUTTN_ENABLE 0x0001
190#define PWR_FAULT_DETECT_ENABLE 0x0002
191#define MRL_DETECT_ENABLE 0x0004
192#define PRSN_DETECT_ENABLE 0x0008
193#define CMD_CMPL_INTR_ENABLE 0x0010
194#define HP_INTR_ENABLE 0x0020
195#define ATTN_LED_CTRL 0x00C0
196#define PWR_LED_CTRL 0x0300
197#define PWR_CTRL 0x0400
Kristen Carlson Accardi34d03412007-01-09 13:02:36 -0800198#define EMI_CTRL 0x0800
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
200/* Attention indicator and Power indicator states */
201#define LED_ON 0x01
202#define LED_BLINK 0x10
203#define LED_OFF 0x11
204
205/* Power Control Command */
206#define POWER_ON 0
207#define POWER_OFF 0x0400
208
Kristen Carlson Accardi34d03412007-01-09 13:02:36 -0800209/* EMI Status defines */
210#define EMI_DISENGAGED 0
211#define EMI_ENGAGED 1
212
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213/* Field definitions in Slot Status Register */
214#define ATTN_BUTTN_PRESSED 0x0001
215#define PWR_FAULT_DETECTED 0x0002
216#define MRL_SENS_CHANGED 0x0004
217#define PRSN_DETECT_CHANGED 0x0008
218#define CMD_COMPLETED 0x0010
219#define MRL_STATE 0x0020
220#define PRSN_STATE 0x0040
Kristen Carlson Accardi34d03412007-01-09 13:02:36 -0800221#define EMI_STATE 0x0080
222#define EMI_STATUS_BIT 7
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800226static irqreturn_t pcie_isr(int irq, void *dev_id);
227static void start_int_poll_timer(struct controller *ctrl, int sec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
229/* This is the interrupt polling timeout function. */
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800230static void int_poll_timeout(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800232 struct controller *ctrl = (struct controller *)data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
234 DBG_ENTER_ROUTINE
235
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 /* Poll for interrupt events. regs == NULL => polling */
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800237 pcie_isr(0, ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800239 init_timer(&ctrl->poll_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 if (!pciehp_poll_time)
241 pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
242
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800243 start_int_poll_timer(ctrl, pciehp_poll_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244}
245
246/* This function starts the interrupt polling timer. */
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800247static void start_int_poll_timer(struct controller *ctrl, int sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800249 /* Clamp to sane value */
250 if ((sec <= 0) || (sec > 60))
251 sec = 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800253 ctrl->poll_timer.function = &int_poll_timeout;
254 ctrl->poll_timer.data = (unsigned long)ctrl;
255 ctrl->poll_timer.expires = jiffies + sec * HZ;
256 add_timer(&ctrl->poll_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257}
258
Kenji Kaneshige44ef4ce2006-12-21 17:01:09 -0800259static inline int pcie_wait_cmd(struct controller *ctrl)
260{
Kenji Kaneshige262303fe2006-12-21 17:01:10 -0800261 int retval = 0;
262 unsigned int msecs = pciehp_poll_mode ? 2500 : 1000;
263 unsigned long timeout = msecs_to_jiffies(msecs);
264 int rc;
Kenji Kaneshige44ef4ce2006-12-21 17:01:09 -0800265
Kenji Kaneshige262303fe2006-12-21 17:01:10 -0800266 rc = wait_event_interruptible_timeout(ctrl->queue,
267 !ctrl->cmd_busy, timeout);
268 if (!rc)
269 dbg("Command not completed in 1000 msec\n");
270 else if (rc < 0) {
271 retval = -EINTR;
272 info("Command was interrupted by a signal\n");
273 }
Kenji Kaneshige44ef4ce2006-12-21 17:01:09 -0800274
Kenji Kaneshige262303fe2006-12-21 17:01:10 -0800275 return retval;
Kenji Kaneshige44ef4ce2006-12-21 17:01:09 -0800276}
277
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700278/**
279 * pcie_write_cmd - Issue controller command
280 * @slot: slot to which the command is issued
281 * @cmd: command value written to slot control register
282 * @mask: bitmask of slot control register to be modified
283 */
284static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800286 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 int retval = 0;
288 u16 slot_status;
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700289 u16 slot_ctrl;
290 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
292 DBG_ENTER_ROUTINE
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800293
Kenji Kaneshige44ef4ce2006-12-21 17:01:09 -0800294 mutex_lock(&ctrl->ctrl_lock);
295
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800296 retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 if (retval) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800298 err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
Kenji Kaneshige44ef4ce2006-12-21 17:01:09 -0800299 goto out;
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800300 }
301
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) {
Kenji Kaneshige44ef4ce2006-12-21 17:01:09 -0800303 /* After 1 sec and CMD_COMPLETED still not set, just
304 proceed forward to issue the next command according
305 to spec. Just print out the error message */
306 dbg("%s: CMD_COMPLETED not clear after 1 sec.\n",
307 __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 }
309
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700310 spin_lock_irqsave(&ctrl->lock, flags);
311 retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 if (retval) {
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700313 err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
314 goto out_spin_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700317 slot_ctrl &= ~mask;
318 slot_ctrl |= ((cmd & mask) | CMD_CMPL_INTR_ENABLE);
319
320 ctrl->cmd_busy = 1;
321 retval = pciehp_writew(ctrl, SLOTCTRL, slot_ctrl);
322 if (retval)
323 err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
324
325 out_spin_unlock:
326 spin_unlock_irqrestore(&ctrl->lock, flags);
327
Kenji Kaneshige44ef4ce2006-12-21 17:01:09 -0800328 /*
329 * Wait for command completion.
330 */
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700331 if (!retval)
332 retval = pcie_wait_cmd(ctrl);
Kenji Kaneshige44ef4ce2006-12-21 17:01:09 -0800333 out:
334 mutex_unlock(&ctrl->ctrl_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 DBG_LEAVE_ROUTINE
336 return retval;
337}
338
339static int hpc_check_lnk_status(struct controller *ctrl)
340{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 u16 lnk_status;
342 int retval = 0;
343
344 DBG_ENTER_ROUTINE
345
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800346 retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 if (retval) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800348 err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 return retval;
350 }
351
352 dbg("%s: lnk_status = %x\n", __FUNCTION__, lnk_status);
353 if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) ||
354 !(lnk_status & NEG_LINK_WD)) {
355 err("%s : Link Training Error occurs \n", __FUNCTION__);
356 retval = -1;
357 return retval;
358 }
359
360 DBG_LEAVE_ROUTINE
361 return retval;
362}
363
364
365static int hpc_get_attention_status(struct slot *slot, u8 *status)
366{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800367 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 u16 slot_ctrl;
369 u8 atten_led_state;
370 int retval = 0;
371
372 DBG_ENTER_ROUTINE
373
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800374 retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 if (retval) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800376 err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 return retval;
378 }
379
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800380 dbg("%s: SLOTCTRL %x, value read %x\n",
381 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
383 atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6;
384
385 switch (atten_led_state) {
386 case 0:
387 *status = 0xFF; /* Reserved */
388 break;
389 case 1:
390 *status = 1; /* On */
391 break;
392 case 2:
393 *status = 2; /* Blink */
394 break;
395 case 3:
396 *status = 0; /* Off */
397 break;
398 default:
399 *status = 0xFF;
400 break;
401 }
402
403 DBG_LEAVE_ROUTINE
404 return 0;
405}
406
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800407static int hpc_get_power_status(struct slot *slot, u8 *status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800409 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 u16 slot_ctrl;
411 u8 pwr_state;
412 int retval = 0;
413
414 DBG_ENTER_ROUTINE
415
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800416 retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 if (retval) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800418 err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 return retval;
420 }
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800421 dbg("%s: SLOTCTRL %x value read %x\n",
422 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
424 pwr_state = (slot_ctrl & PWR_CTRL) >> 10;
425
426 switch (pwr_state) {
427 case 0:
428 *status = 1;
429 break;
430 case 1:
431 *status = 0;
432 break;
433 default:
434 *status = 0xFF;
435 break;
436 }
437
438 DBG_LEAVE_ROUTINE
439 return retval;
440}
441
442
443static int hpc_get_latch_status(struct slot *slot, u8 *status)
444{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800445 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 u16 slot_status;
447 int retval = 0;
448
449 DBG_ENTER_ROUTINE
450
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800451 retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 if (retval) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800453 err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 return retval;
455 }
456
457 *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1;
458
459 DBG_LEAVE_ROUTINE
460 return 0;
461}
462
463static int hpc_get_adapter_status(struct slot *slot, u8 *status)
464{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800465 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 u16 slot_status;
467 u8 card_state;
468 int retval = 0;
469
470 DBG_ENTER_ROUTINE
471
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800472 retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 if (retval) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800474 err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 return retval;
476 }
477 card_state = (u8)((slot_status & PRSN_STATE) >> 6);
478 *status = (card_state == 1) ? 1 : 0;
479
480 DBG_LEAVE_ROUTINE
481 return 0;
482}
483
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800484static int hpc_query_power_fault(struct slot *slot)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800486 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 u16 slot_status;
488 u8 pwr_fault;
489 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
491 DBG_ENTER_ROUTINE
492
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800493 retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 if (retval) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800495 err("%s: Cannot check for power fault\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 return retval;
497 }
498 pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
500 DBG_LEAVE_ROUTINE
rajesh.shah@intel.com8239def2005-10-31 16:20:13 -0800501 return pwr_fault;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502}
503
Kristen Carlson Accardi34d03412007-01-09 13:02:36 -0800504static int hpc_get_emi_status(struct slot *slot, u8 *status)
505{
506 struct controller *ctrl = slot->ctrl;
507 u16 slot_status;
508 int retval = 0;
509
510 DBG_ENTER_ROUTINE
511
512 retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
513 if (retval) {
514 err("%s : Cannot check EMI status\n", __FUNCTION__);
515 return retval;
516 }
517 *status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT;
518
519 DBG_LEAVE_ROUTINE
520 return retval;
521}
522
523static int hpc_toggle_emi(struct slot *slot)
524{
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700525 u16 slot_cmd;
526 u16 cmd_mask;
527 int rc;
Kristen Carlson Accardi34d03412007-01-09 13:02:36 -0800528
529 DBG_ENTER_ROUTINE
530
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700531 slot_cmd = EMI_CTRL;
532 cmd_mask = EMI_CTRL;
533 if (!pciehp_poll_mode) {
534 slot_cmd = slot_cmd | HP_INTR_ENABLE;
535 cmd_mask = cmd_mask | HP_INTR_ENABLE;
Kristen Carlson Accardi34d03412007-01-09 13:02:36 -0800536 }
537
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700538 rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
Kristen Carlson Accardi34d03412007-01-09 13:02:36 -0800539 slot->last_emi_toggle = get_seconds();
540 DBG_LEAVE_ROUTINE
541 return rc;
542}
543
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544static int hpc_set_attention_status(struct slot *slot, u8 value)
545{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800546 struct controller *ctrl = slot->ctrl;
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700547 u16 slot_cmd;
548 u16 cmd_mask;
549 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
rajesh.shah@intel.com1a9ed1b2005-10-31 16:20:10 -0800551 DBG_ENTER_ROUTINE
552
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700553 cmd_mask = ATTN_LED_CTRL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 switch (value) {
555 case 0 : /* turn off */
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700556 slot_cmd = 0x00C0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 break;
558 case 1: /* turn on */
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700559 slot_cmd = 0x0040;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 break;
561 case 2: /* turn blink */
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700562 slot_cmd = 0x0080;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 break;
564 default:
565 return -1;
566 }
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700567 if (!pciehp_poll_mode) {
568 slot_cmd = slot_cmd | HP_INTR_ENABLE;
569 cmd_mask = cmd_mask | HP_INTR_ENABLE;
570 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700572 rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800573 dbg("%s: SLOTCTRL %x write cmd %x\n",
574 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
rajesh.shah@intel.com1a9ed1b2005-10-31 16:20:10 -0800576 DBG_LEAVE_ROUTINE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 return rc;
578}
579
580
581static void hpc_set_green_led_on(struct slot *slot)
582{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800583 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 u16 slot_cmd;
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700585 u16 cmd_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
rajesh.shah@intel.com1a9ed1b2005-10-31 16:20:10 -0800587 DBG_ENTER_ROUTINE
588
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700589 slot_cmd = 0x0100;
590 cmd_mask = PWR_LED_CTRL;
591 if (!pciehp_poll_mode) {
592 slot_cmd = slot_cmd | HP_INTR_ENABLE;
593 cmd_mask = cmd_mask | HP_INTR_ENABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700596 pcie_write_cmd(slot, slot_cmd, cmd_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800598 dbg("%s: SLOTCTRL %x write cmd %x\n",
599 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
rajesh.shah@intel.com1a9ed1b2005-10-31 16:20:10 -0800600 DBG_LEAVE_ROUTINE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 return;
602}
603
604static void hpc_set_green_led_off(struct slot *slot)
605{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800606 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 u16 slot_cmd;
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700608 u16 cmd_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
rajesh.shah@intel.com1a9ed1b2005-10-31 16:20:10 -0800610 DBG_ENTER_ROUTINE
611
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700612 slot_cmd = 0x0300;
613 cmd_mask = PWR_LED_CTRL;
614 if (!pciehp_poll_mode) {
615 slot_cmd = slot_cmd | HP_INTR_ENABLE;
616 cmd_mask = cmd_mask | HP_INTR_ENABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700619 pcie_write_cmd(slot, slot_cmd, cmd_mask);
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800620 dbg("%s: SLOTCTRL %x write cmd %x\n",
621 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622
rajesh.shah@intel.com1a9ed1b2005-10-31 16:20:10 -0800623 DBG_LEAVE_ROUTINE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 return;
625}
626
627static void hpc_set_green_led_blink(struct slot *slot)
628{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800629 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 u16 slot_cmd;
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700631 u16 cmd_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
rajesh.shah@intel.com1a9ed1b2005-10-31 16:20:10 -0800633 DBG_ENTER_ROUTINE
634
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700635 slot_cmd = 0x0200;
636 cmd_mask = PWR_LED_CTRL;
637 if (!pciehp_poll_mode) {
638 slot_cmd = slot_cmd | HP_INTR_ENABLE;
639 cmd_mask = cmd_mask | HP_INTR_ENABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700642 pcie_write_cmd(slot, slot_cmd, cmd_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800644 dbg("%s: SLOTCTRL %x write cmd %x\n",
645 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
rajesh.shah@intel.com1a9ed1b2005-10-31 16:20:10 -0800646 DBG_LEAVE_ROUTINE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 return;
648}
649
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650static void hpc_release_ctlr(struct controller *ctrl)
651{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 DBG_ENTER_ROUTINE
653
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800654 if (pciehp_poll_mode)
655 del_timer(&ctrl->poll_timer);
656 else
657 free_irq(ctrl->pci_dev->irq, ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Kenji Kaneshige5d386e12007-03-06 15:02:26 -0800659 /*
660 * If this is the last controller to be released, destroy the
661 * pciehp work queue
662 */
663 if (atomic_dec_and_test(&pciehp_num_controllers))
664 destroy_workqueue(pciehp_wq);
665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 DBG_LEAVE_ROUTINE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667}
668
669static int hpc_power_on_slot(struct slot * slot)
670{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800671 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 u16 slot_cmd;
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700673 u16 cmd_mask;
674 u16 slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 int retval = 0;
676
677 DBG_ENTER_ROUTINE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
Rajesh Shah5a49f202005-11-23 15:44:54 -0800681 /* Clear sticky power-fault bit from previous power failures */
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800682 retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 if (retval) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800684 err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
685 return retval;
686 }
687 slot_status &= PWR_FAULT_DETECTED;
688 if (slot_status) {
689 retval = pciehp_writew(ctrl, SLOTSTATUS, slot_status);
690 if (retval) {
691 err("%s: Cannot write to SLOTSTATUS register\n",
692 __FUNCTION__);
693 return retval;
694 }
695 }
696
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700697 slot_cmd = POWER_ON;
698 cmd_mask = PWR_CTRL;
Thomas Schaeferc7ab3372005-12-08 11:55:57 -0800699 /* Enable detection that we turned off at slot power-off time */
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700700 if (!pciehp_poll_mode) {
Thomas Schaeferc7ab3372005-12-08 11:55:57 -0800701 slot_cmd = slot_cmd |
702 PWR_FAULT_DETECT_ENABLE |
703 MRL_DETECT_ENABLE |
704 PRSN_DETECT_ENABLE |
705 HP_INTR_ENABLE;
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700706 cmd_mask = cmd_mask |
707 PWR_FAULT_DETECT_ENABLE |
708 MRL_DETECT_ENABLE |
709 PRSN_DETECT_ENABLE |
710 HP_INTR_ENABLE;
711 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700713 retval = pcie_write_cmd(slot, slot_cmd, cmd_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
715 if (retval) {
716 err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd);
717 return -1;
718 }
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800719 dbg("%s: SLOTCTRL %x write cmd %x\n",
720 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
722 DBG_LEAVE_ROUTINE
723
724 return retval;
725}
726
727static int hpc_power_off_slot(struct slot * slot)
728{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800729 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 u16 slot_cmd;
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700731 u16 cmd_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 int retval = 0;
733
734 DBG_ENTER_ROUTINE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700738 slot_cmd = POWER_OFF;
739 cmd_mask = PWR_CTRL;
Thomas Schaeferc7ab3372005-12-08 11:55:57 -0800740 /*
741 * If we get MRL or presence detect interrupts now, the isr
742 * will notice the sticky power-fault bit too and issue power
743 * indicator change commands. This will lead to an endless loop
744 * of command completions, since the power-fault bit remains on
745 * till the slot is powered on again.
746 */
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700747 if (!pciehp_poll_mode) {
Thomas Schaeferc7ab3372005-12-08 11:55:57 -0800748 slot_cmd = (slot_cmd &
749 ~PWR_FAULT_DETECT_ENABLE &
750 ~MRL_DETECT_ENABLE &
751 ~PRSN_DETECT_ENABLE) | HP_INTR_ENABLE;
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700752 cmd_mask = cmd_mask |
753 PWR_FAULT_DETECT_ENABLE |
754 MRL_DETECT_ENABLE |
755 PRSN_DETECT_ENABLE |
756 HP_INTR_ENABLE;
757 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700759 retval = pcie_write_cmd(slot, slot_cmd, cmd_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 if (retval) {
761 err("%s: Write command failed!\n", __FUNCTION__);
762 return -1;
763 }
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800764 dbg("%s: SLOTCTRL %x write cmd %x\n",
765 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
767 DBG_LEAVE_ROUTINE
768
769 return retval;
770}
771
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800772static irqreturn_t pcie_isr(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800774 struct controller *ctrl = (struct controller *)dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 u16 slot_status, intr_detect, intr_loc;
776 u16 temp_word;
777 int hp_slot = 0; /* only 1 slot per PCI Express port */
778 int rc = 0;
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700779 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800781 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800783 err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 return IRQ_NONE;
785 }
786
787 intr_detect = ( ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | MRL_SENS_CHANGED |
788 PRSN_DETECT_CHANGED | CMD_COMPLETED );
789
790 intr_loc = slot_status & intr_detect;
791
792 /* Check to see if it was our interrupt */
793 if ( !intr_loc )
794 return IRQ_NONE;
795
796 dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc);
797 /* Mask Hot-plug Interrupt Enable */
798 if (!pciehp_poll_mode) {
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700799 spin_lock_irqsave(&ctrl->lock, flags);
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800800 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800802 err("%s: Cannot read SLOT_CTRL register\n",
803 __FUNCTION__);
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700804 spin_unlock_irqrestore(&ctrl->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 return IRQ_NONE;
806 }
807
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800808 dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n",
809 __FUNCTION__, temp_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800811 rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
812 if (rc) {
813 err("%s: Cannot write to SLOTCTRL register\n",
814 __FUNCTION__);
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700815 spin_unlock_irqrestore(&ctrl->lock, flags);
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800816 return IRQ_NONE;
817 }
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700818 spin_unlock_irqrestore(&ctrl->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800820 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800822 err("%s: Cannot read SLOT_STATUS register\n",
823 __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 return IRQ_NONE;
825 }
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800826 dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n",
827 __FUNCTION__, slot_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
829 /* Clear command complete interrupt caused by this write */
830 temp_word = 0x1f;
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800831 rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800833 err("%s: Cannot write to SLOTSTATUS register\n",
834 __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 return IRQ_NONE;
836 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 }
838
839 if (intr_loc & CMD_COMPLETED) {
840 /*
841 * Command Complete Interrupt Pending
842 */
Kenji Kaneshige262303fe2006-12-21 17:01:10 -0800843 ctrl->cmd_busy = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 wake_up_interruptible(&ctrl->queue);
845 }
846
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800847 if (intr_loc & MRL_SENS_CHANGED)
848 pciehp_handle_switch_change(hp_slot, ctrl);
849
850 if (intr_loc & ATTN_BUTTN_PRESSED)
851 pciehp_handle_attention_button(hp_slot, ctrl);
852
853 if (intr_loc & PRSN_DETECT_CHANGED)
854 pciehp_handle_presence_change(hp_slot, ctrl);
855
856 if (intr_loc & PWR_FAULT_DETECTED)
857 pciehp_handle_power_fault(hp_slot, ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858
859 /* Clear all events after serving them */
860 temp_word = 0x1F;
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800861 rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800863 err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 return IRQ_NONE;
865 }
866 /* Unmask Hot-plug Interrupt Enable */
867 if (!pciehp_poll_mode) {
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700868 spin_lock_irqsave(&ctrl->lock, flags);
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800869 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800871 err("%s: Cannot read SLOTCTRL register\n",
872 __FUNCTION__);
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700873 spin_unlock_irqrestore(&ctrl->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 return IRQ_NONE;
875 }
876
877 dbg("%s: Unmask Hot-plug Interrupt Enable\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
879
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800880 rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800882 err("%s: Cannot write to SLOTCTRL register\n",
883 __FUNCTION__);
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700884 spin_unlock_irqrestore(&ctrl->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 return IRQ_NONE;
886 }
Kenji Kaneshigef4778362007-05-31 09:43:34 -0700887 spin_unlock_irqrestore(&ctrl->lock, flags);
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800888
889 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800891 err("%s: Cannot read SLOT_STATUS register\n",
892 __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 return IRQ_NONE;
894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
896 /* Clear command complete interrupt caused by this write */
897 temp_word = 0x1F;
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800898 rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800900 err("%s: Cannot write to SLOTSTATUS failed\n",
901 __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 return IRQ_NONE;
903 }
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800904 dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n",
905 __FUNCTION__, temp_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 }
907
908 return IRQ_HANDLED;
909}
910
911static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
912{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800913 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 enum pcie_link_speed lnk_speed;
915 u32 lnk_cap;
916 int retval = 0;
917
918 DBG_ENTER_ROUTINE
919
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800920 retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 if (retval) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800922 err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 return retval;
924 }
925
926 switch (lnk_cap & 0x000F) {
927 case 1:
928 lnk_speed = PCIE_2PT5GB;
929 break;
930 default:
931 lnk_speed = PCIE_LNK_SPEED_UNKNOWN;
932 break;
933 }
934
935 *value = lnk_speed;
936 dbg("Max link speed = %d\n", lnk_speed);
937 DBG_LEAVE_ROUTINE
938 return retval;
939}
940
941static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value)
942{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800943 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 enum pcie_link_width lnk_wdth;
945 u32 lnk_cap;
946 int retval = 0;
947
948 DBG_ENTER_ROUTINE
949
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800950 retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 if (retval) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -0800952 err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 return retval;
954 }
955
956 switch ((lnk_cap & 0x03F0) >> 4){
957 case 0:
958 lnk_wdth = PCIE_LNK_WIDTH_RESRV;
959 break;
960 case 1:
961 lnk_wdth = PCIE_LNK_X1;
962 break;
963 case 2:
964 lnk_wdth = PCIE_LNK_X2;
965 break;
966 case 4:
967 lnk_wdth = PCIE_LNK_X4;
968 break;
969 case 8:
970 lnk_wdth = PCIE_LNK_X8;
971 break;
972 case 12:
973 lnk_wdth = PCIE_LNK_X12;
974 break;
975 case 16:
976 lnk_wdth = PCIE_LNK_X16;
977 break;
978 case 32:
979 lnk_wdth = PCIE_LNK_X32;
980 break;
981 default:
982 lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
983 break;
984 }
985
986 *value = lnk_wdth;
987 dbg("Max link width = %d\n", lnk_wdth);
988 DBG_LEAVE_ROUTINE
989 return retval;
990}
991
992static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
993{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -0800994 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN;
996 int retval = 0;
997 u16 lnk_status;
998
999 DBG_ENTER_ROUTINE
1000
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001001 retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 if (retval) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001003 err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 return retval;
1005 }
1006
1007 switch (lnk_status & 0x0F) {
1008 case 1:
1009 lnk_speed = PCIE_2PT5GB;
1010 break;
1011 default:
1012 lnk_speed = PCIE_LNK_SPEED_UNKNOWN;
1013 break;
1014 }
1015
1016 *value = lnk_speed;
1017 dbg("Current link speed = %d\n", lnk_speed);
1018 DBG_LEAVE_ROUTINE
1019 return retval;
1020}
1021
1022static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value)
1023{
Kenji Kaneshige48fe3912006-12-21 17:01:04 -08001024 struct controller *ctrl = slot->ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
1026 int retval = 0;
1027 u16 lnk_status;
1028
1029 DBG_ENTER_ROUTINE
1030
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001031 retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 if (retval) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001033 err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 return retval;
1035 }
1036
1037 switch ((lnk_status & 0x03F0) >> 4){
1038 case 0:
1039 lnk_wdth = PCIE_LNK_WIDTH_RESRV;
1040 break;
1041 case 1:
1042 lnk_wdth = PCIE_LNK_X1;
1043 break;
1044 case 2:
1045 lnk_wdth = PCIE_LNK_X2;
1046 break;
1047 case 4:
1048 lnk_wdth = PCIE_LNK_X4;
1049 break;
1050 case 8:
1051 lnk_wdth = PCIE_LNK_X8;
1052 break;
1053 case 12:
1054 lnk_wdth = PCIE_LNK_X12;
1055 break;
1056 case 16:
1057 lnk_wdth = PCIE_LNK_X16;
1058 break;
1059 case 32:
1060 lnk_wdth = PCIE_LNK_X32;
1061 break;
1062 default:
1063 lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
1064 break;
1065 }
1066
1067 *value = lnk_wdth;
1068 dbg("Current link width = %d\n", lnk_wdth);
1069 DBG_LEAVE_ROUTINE
1070 return retval;
1071}
1072
1073static struct hpc_ops pciehp_hpc_ops = {
1074 .power_on_slot = hpc_power_on_slot,
1075 .power_off_slot = hpc_power_off_slot,
1076 .set_attention_status = hpc_set_attention_status,
1077 .get_power_status = hpc_get_power_status,
1078 .get_attention_status = hpc_get_attention_status,
1079 .get_latch_status = hpc_get_latch_status,
1080 .get_adapter_status = hpc_get_adapter_status,
Kristen Carlson Accardi34d03412007-01-09 13:02:36 -08001081 .get_emi_status = hpc_get_emi_status,
1082 .toggle_emi = hpc_toggle_emi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083
1084 .get_max_bus_speed = hpc_get_max_lnk_speed,
1085 .get_cur_bus_speed = hpc_get_cur_lnk_speed,
1086 .get_max_lnk_width = hpc_get_max_lnk_width,
1087 .get_cur_lnk_width = hpc_get_cur_lnk_width,
1088
1089 .query_power_fault = hpc_query_power_fault,
1090 .green_led_on = hpc_set_green_led_on,
1091 .green_led_off = hpc_set_green_led_off,
1092 .green_led_blink = hpc_set_green_led_blink,
1093
1094 .release_ctlr = hpc_release_ctlr,
1095 .check_lnk_status = hpc_check_lnk_status,
1096};
1097
Kristen Accardi783c49f2006-03-03 10:16:05 -08001098#ifdef CONFIG_ACPI
1099int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
1100{
1101 acpi_status status;
1102 acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev));
1103 struct pci_dev *pdev = dev;
1104 struct pci_bus *parent;
MUNEDA Takahirob2e6e3b2006-03-17 09:18:39 +09001105 struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };
Kristen Accardi783c49f2006-03-03 10:16:05 -08001106
1107 /*
1108 * Per PCI firmware specification, we should run the ACPI _OSC
1109 * method to get control of hotplug hardware before using it.
1110 * If an _OSC is missing, we look for an OSHP to do the same thing.
1111 * To handle different BIOS behavior, we look for _OSC and OSHP
1112 * within the scope of the hotplug controller and its parents, upto
1113 * the host bridge under which this controller exists.
1114 */
1115 while (!handle) {
1116 /*
1117 * This hotplug controller was not listed in the ACPI name
1118 * space at all. Try to get acpi handle of parent pci bus.
1119 */
1120 if (!pdev || !pdev->bus->parent)
1121 break;
1122 parent = pdev->bus->parent;
1123 dbg("Could not find %s in acpi namespace, trying parent\n",
1124 pci_name(pdev));
1125 if (!parent->self)
1126 /* Parent must be a host bridge */
1127 handle = acpi_get_pci_rootbridge_handle(
1128 pci_domain_nr(parent),
1129 parent->number);
1130 else
1131 handle = DEVICE_ACPI_HANDLE(
1132 &(parent->self->dev));
1133 pdev = parent->self;
1134 }
1135
1136 while (handle) {
MUNEDA Takahirob2e6e3b2006-03-17 09:18:39 +09001137 acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
1138 dbg("Trying to get hotplug control for %s \n",
1139 (char *)string.pointer);
Kristen Accardi783c49f2006-03-03 10:16:05 -08001140 status = pci_osc_control_set(handle,
1141 OSC_PCI_EXPRESS_NATIVE_HP_CONTROL);
1142 if (status == AE_NOT_FOUND)
1143 status = acpi_run_oshp(handle);
1144 if (ACPI_SUCCESS(status)) {
1145 dbg("Gained control for hotplug HW for pci %s (%s)\n",
MUNEDA Takahirob2e6e3b2006-03-17 09:18:39 +09001146 pci_name(dev), (char *)string.pointer);
Kristen Accardi81b26bc2006-04-18 14:36:43 -07001147 kfree(string.pointer);
Kristen Accardi783c49f2006-03-03 10:16:05 -08001148 return 0;
1149 }
1150 if (acpi_root_bridge(handle))
1151 break;
1152 chandle = handle;
1153 status = acpi_get_parent(chandle, &handle);
1154 if (ACPI_FAILURE(status))
1155 break;
1156 }
1157
1158 err("Cannot get control of hotplug hardware for pci %s\n",
1159 pci_name(dev));
MUNEDA Takahirob2e6e3b2006-03-17 09:18:39 +09001160
Kristen Accardi81b26bc2006-04-18 14:36:43 -07001161 kfree(string.pointer);
Kristen Accardi783c49f2006-03-03 10:16:05 -08001162 return -1;
1163}
1164#endif
1165
1166
1167
rajesh.shah@intel.comed6cbcf2005-10-31 16:20:09 -08001168int pcie_init(struct controller * ctrl, struct pcie_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 u16 temp_word;
1172 u16 cap_reg;
1173 u16 intr_enable = 0;
1174 u32 slot_cap;
Kenji Kaneshige75e13172006-12-21 17:01:08 -08001175 int cap_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 u16 slot_status, slot_ctrl;
1177 struct pci_dev *pdev;
1178
1179 DBG_ENTER_ROUTINE
1180
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 pdev = dev->port;
Kenji Kaneshige48fe3912006-12-21 17:01:04 -08001182 ctrl->pci_dev = pdev; /* save pci_dev in context */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183
rajesh.shah@intel.com1a9ed1b2005-10-31 16:20:10 -08001184 dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n",
1185 __FUNCTION__, pdev->vendor, pdev->device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) {
1188 dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__);
1189 goto abort_free_ctlr;
1190 }
1191
Dely Sy8b245e42005-05-06 17:19:09 -07001192 ctrl->cap_base = cap_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193
Kenji Kaneshige75e13172006-12-21 17:01:08 -08001194 dbg("%s: pcie_cap_base %x\n", __FUNCTION__, cap_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001196 rc = pciehp_readw(ctrl, CAPREG, &cap_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001198 err("%s: Cannot read CAPREG register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 goto abort_free_ctlr;
1200 }
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001201 dbg("%s: CAPREG offset %x cap_reg %x\n",
1202 __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
Dely Sy8b245e42005-05-06 17:19:09 -07001204 if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040)
1205 && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 dbg("%s : This is not a root port or the port is not connected to a slot\n", __FUNCTION__);
1207 goto abort_free_ctlr;
1208 }
1209
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001210 rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001212 err("%s: Cannot read SLOTCAP register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 goto abort_free_ctlr;
1214 }
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001215 dbg("%s: SLOTCAP offset %x slot_cap %x\n",
1216 __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217
1218 if (!(slot_cap & HP_CAP)) {
1219 dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__);
1220 goto abort_free_ctlr;
1221 }
1222 /* For debugging purpose */
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001223 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001225 err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 goto abort_free_ctlr;
1227 }
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001228 dbg("%s: SLOTSTATUS offset %x slot_status %x\n",
1229 __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001231 rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001233 err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 goto abort_free_ctlr;
1235 }
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001236 dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
1237 __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
1240 if (pci_resource_len(pdev, rc) > 0)
Greg Kroah-Hartman1396a8c2006-06-12 15:14:29 -07001241 dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc,
1242 (unsigned long long)pci_resource_start(pdev, rc),
1243 (unsigned long long)pci_resource_len(pdev, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
1245 info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device,
1246 pdev->subsystem_vendor, pdev->subsystem_device);
1247
Ingo Molnar6aa4cdd2006-01-13 16:02:15 +01001248 mutex_init(&ctrl->crit_sect);
Kenji Kaneshigedd5619c2006-09-22 10:17:29 -07001249 mutex_init(&ctrl->ctrl_lock);
Kenji Kaneshigef4778362007-05-31 09:43:34 -07001250 spin_lock_init(&ctrl->lock);
Kenji Kaneshigedd5619c2006-09-22 10:17:29 -07001251
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 /* setup wait queue */
1253 init_waitqueue_head(&ctrl->queue);
1254
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 /* return PCI Controller Info */
Kenji Kaneshige48fe3912006-12-21 17:01:04 -08001256 ctrl->slot_device_offset = 0;
1257 ctrl->num_slots = 1;
1258 ctrl->first_slot = slot_cap >> 19;
1259 ctrl->ctrlcap = slot_cap & 0x0000007f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260
1261 /* Mask Hot-plug Interrupt Enable */
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001262 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001264 err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 goto abort_free_ctlr;
1266 }
1267
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001268 dbg("%s: SLOTCTRL %x value read %x\n",
1269 __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
1271
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001272 rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001274 err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 goto abort_free_ctlr;
1276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001278 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001280 err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 goto abort_free_ctlr;
1282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283
1284 temp_word = 0x1F; /* Clear all events */
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001285 rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001287 err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 goto abort_free_ctlr;
1289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
Kenji Kaneshige48fe3912006-12-21 17:01:04 -08001291 if (pciehp_poll_mode) {
1292 /* Install interrupt polling timer. Start with 10 sec delay */
1293 init_timer(&ctrl->poll_timer);
1294 start_int_poll_timer(ctrl, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 } else {
1296 /* Installs the interrupt handler */
Kenji Kaneshige48fe3912006-12-21 17:01:04 -08001297 rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED,
1298 MY_NAME, (void *)ctrl);
1299 dbg("%s: request_irq %d for hpc%d (returns %d)\n",
Kenji Kaneshige5d386e12007-03-06 15:02:26 -08001300 __FUNCTION__, ctrl->pci_dev->irq,
1301 atomic_read(&pciehp_num_controllers), rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 if (rc) {
Kenji Kaneshige48fe3912006-12-21 17:01:04 -08001303 err("Can't get irq %d for the hotplug controller\n",
1304 ctrl->pci_dev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 goto abort_free_ctlr;
1306 }
1307 }
rajesh.shah@intel.com1a9ed1b2005-10-31 16:20:10 -08001308 dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number,
1309 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq);
1310
Kenji Kaneshige5d386e12007-03-06 15:02:26 -08001311 /*
1312 * If this is the first controller to be initialized,
1313 * initialize the pciehp work queue
1314 */
1315 if (atomic_add_return(1, &pciehp_num_controllers) == 1) {
1316 pciehp_wq = create_singlethread_workqueue("pciehpd");
1317 if (!pciehp_wq) {
1318 rc = -ENOMEM;
1319 goto abort_free_irq;
1320 }
1321 }
1322
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001323 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001325 err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
Jan Beulich9c64f972006-05-09 00:50:31 -07001326 goto abort_free_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
1329 intr_enable = intr_enable | PRSN_DETECT_ENABLE;
1330
1331 if (ATTN_BUTTN(slot_cap))
1332 intr_enable = intr_enable | ATTN_BUTTN_ENABLE;
1333
1334 if (POWER_CTRL(slot_cap))
1335 intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE;
1336
1337 if (MRL_SENS(slot_cap))
1338 intr_enable = intr_enable | MRL_DETECT_ENABLE;
1339
1340 temp_word = (temp_word & ~intr_enable) | intr_enable;
1341
1342 if (pciehp_poll_mode) {
1343 temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0;
1344 } else {
1345 temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
1346 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
1348 /* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001349 rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001351 err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
Jan Beulich9c64f972006-05-09 00:50:31 -07001352 goto abort_free_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 }
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001354 rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001356 err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
Jan Beulich9c64f972006-05-09 00:50:31 -07001357 goto abort_disable_intr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359
1360 temp_word = 0x1F; /* Clear all events */
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001361 rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 if (rc) {
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001363 err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
Jan Beulich9c64f972006-05-09 00:50:31 -07001364 goto abort_disable_intr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366
rajesh.shah@intel.coma3a45ec2005-10-31 16:20:12 -08001367 if (pciehp_force) {
1368 dbg("Bypassing BIOS check for pciehp use on %s\n",
1369 pci_name(ctrl->pci_dev));
1370 } else {
Rajesh Shah6560aa52005-11-07 13:37:36 -08001371 rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev);
rajesh.shah@intel.coma3a45ec2005-10-31 16:20:12 -08001372 if (rc)
Jan Beulich9c64f972006-05-09 00:50:31 -07001373 goto abort_disable_intr;
rajesh.shah@intel.coma3a45ec2005-10-31 16:20:12 -08001374 }
rajesh.shah@intel.coma8a2be92005-10-31 16:20:07 -08001375
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 ctrl->hpc_ops = &pciehp_hpc_ops;
1377
1378 DBG_LEAVE_ROUTINE
1379 return 0;
1380
1381 /* We end up here for the many possible ways to fail this API. */
Jan Beulich9c64f972006-05-09 00:50:31 -07001382abort_disable_intr:
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001383 rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
Jan Beulich9c64f972006-05-09 00:50:31 -07001384 if (!rc) {
1385 temp_word &= ~(intr_enable | HP_INTR_ENABLE);
Kenji Kaneshigea0f018d2006-12-21 17:01:06 -08001386 rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
Jan Beulich9c64f972006-05-09 00:50:31 -07001387 }
1388 if (rc)
1389 err("%s : disabling interrupts failed\n", __FUNCTION__);
1390
1391abort_free_irq:
1392 if (pciehp_poll_mode)
Kenji Kaneshige48fe3912006-12-21 17:01:04 -08001393 del_timer_sync(&ctrl->poll_timer);
Jan Beulich9c64f972006-05-09 00:50:31 -07001394 else
Kenji Kaneshige48fe3912006-12-21 17:01:04 -08001395 free_irq(ctrl->pci_dev->irq, ctrl);
Jan Beulich9c64f972006-05-09 00:50:31 -07001396
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397abort_free_ctlr:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 DBG_LEAVE_ROUTINE
1399 return -1;
1400}