xref: /openbmc/linux/drivers/pci/hotplug/shpchp_hpc.c (revision 57c95c0d)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Standard PCI Hot Plug Driver
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (C) 1995,2001 Compaq Computer Corporation
51da177e4SLinus Torvalds  * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
61da177e4SLinus Torvalds  * Copyright (C) 2001 IBM Corp.
71da177e4SLinus Torvalds  * Copyright (C) 2003-2004 Intel Corporation
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  * All rights reserved.
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify
121da177e4SLinus Torvalds  * it under the terms of the GNU General Public License as published by
131da177e4SLinus Torvalds  * the Free Software Foundation; either version 2 of the License, or (at
141da177e4SLinus Torvalds  * your option) any later version.
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  * This program is distributed in the hope that it will be useful, but
171da177e4SLinus Torvalds  * WITHOUT ANY WARRANTY; without even the implied warranty of
181da177e4SLinus Torvalds  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
191da177e4SLinus Torvalds  * NON INFRINGEMENT.  See the GNU General Public License for more
201da177e4SLinus Torvalds  * details.
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  * You should have received a copy of the GNU General Public License
231da177e4SLinus Torvalds  * along with this program; if not, write to the Free Software
241da177e4SLinus Torvalds  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
251da177e4SLinus Torvalds  *
268cf4c195SKristen Accardi  * Send feedback to <greg@kroah.com>,<kristen.c.accardi@intel.com>
271da177e4SLinus Torvalds  *
281da177e4SLinus Torvalds  */
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds #include <linux/kernel.h>
311da177e4SLinus Torvalds #include <linux/module.h>
321da177e4SLinus Torvalds #include <linux/types.h>
331da177e4SLinus Torvalds #include <linux/pci.h>
34d4d28dd4SAndrew Morton #include <linux/interrupt.h>
35d4d28dd4SAndrew Morton 
361da177e4SLinus Torvalds #include "shpchp.h"
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds #ifdef DEBUG
391da177e4SLinus Torvalds #define DBG_K_TRACE_ENTRY      ((unsigned int)0x00000001)	/* On function entry */
401da177e4SLinus Torvalds #define DBG_K_TRACE_EXIT       ((unsigned int)0x00000002)	/* On function exit */
411da177e4SLinus Torvalds #define DBG_K_INFO             ((unsigned int)0x00000004)	/* Info messages */
421da177e4SLinus Torvalds #define DBG_K_ERROR            ((unsigned int)0x00000008)	/* Error messages */
431da177e4SLinus Torvalds #define DBG_K_TRACE            (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
441da177e4SLinus Torvalds #define DBG_K_STANDARD         (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
451da177e4SLinus Torvalds /* Redefine this flagword to set debug level */
461da177e4SLinus Torvalds #define DEBUG_LEVEL            DBG_K_STANDARD
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds #define DEFINE_DBG_BUFFER     char __dbg_str_buf[256];
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds #define DBG_PRINT( dbg_flags, args... )              \
511da177e4SLinus Torvalds 	do {                                             \
521da177e4SLinus Torvalds 	  if ( DEBUG_LEVEL & ( dbg_flags ) )             \
531da177e4SLinus Torvalds 	  {                                              \
541da177e4SLinus Torvalds 	    int len;                                     \
551da177e4SLinus Torvalds 	    len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
561da177e4SLinus Torvalds 		  __FILE__, __LINE__, __FUNCTION__ );    \
571da177e4SLinus Torvalds 	    sprintf( __dbg_str_buf + len, args );        \
581da177e4SLinus Torvalds 	    printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
591da177e4SLinus Torvalds 	  }                                              \
601da177e4SLinus Torvalds 	} while (0)
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds #define DBG_ENTER_ROUTINE	DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
631da177e4SLinus Torvalds #define DBG_LEAVE_ROUTINE	DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
641da177e4SLinus Torvalds #else
651da177e4SLinus Torvalds #define DEFINE_DBG_BUFFER
661da177e4SLinus Torvalds #define DBG_ENTER_ROUTINE
671da177e4SLinus Torvalds #define DBG_LEAVE_ROUTINE
681da177e4SLinus Torvalds #endif				/* DEBUG */
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds /* Slot Available Register I field definition */
711da177e4SLinus Torvalds #define SLOT_33MHZ		0x0000001f
721da177e4SLinus Torvalds #define SLOT_66MHZ_PCIX		0x00001f00
731da177e4SLinus Torvalds #define SLOT_100MHZ_PCIX	0x001f0000
741da177e4SLinus Torvalds #define SLOT_133MHZ_PCIX	0x1f000000
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds /* Slot Available Register II field definition */
771da177e4SLinus Torvalds #define SLOT_66MHZ		0x0000001f
781da177e4SLinus Torvalds #define SLOT_66MHZ_PCIX_266	0x00000f00
791da177e4SLinus Torvalds #define SLOT_100MHZ_PCIX_266	0x0000f000
801da177e4SLinus Torvalds #define SLOT_133MHZ_PCIX_266	0x000f0000
811da177e4SLinus Torvalds #define SLOT_66MHZ_PCIX_533	0x00f00000
821da177e4SLinus Torvalds #define SLOT_100MHZ_PCIX_533	0x0f000000
831da177e4SLinus Torvalds #define SLOT_133MHZ_PCIX_533	0xf0000000
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds /* Secondary Bus Configuration Register */
871da177e4SLinus Torvalds /* For PI = 1, Bits 0 to 2 have been encoded as follows to show current bus speed/mode */
881da177e4SLinus Torvalds #define PCI_33MHZ		0x0
891da177e4SLinus Torvalds #define PCI_66MHZ		0x1
901da177e4SLinus Torvalds #define PCIX_66MHZ		0x2
911da177e4SLinus Torvalds #define PCIX_100MHZ		0x3
921da177e4SLinus Torvalds #define PCIX_133MHZ		0x4
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds /* For PI = 2, Bits 0 to 3 have been encoded as follows to show current bus speed/mode */
951da177e4SLinus Torvalds #define PCI_33MHZ		0x0
961da177e4SLinus Torvalds #define PCI_66MHZ		0x1
971da177e4SLinus Torvalds #define PCIX_66MHZ		0x2
981da177e4SLinus Torvalds #define PCIX_100MHZ		0x3
991da177e4SLinus Torvalds #define PCIX_133MHZ		0x4
1001da177e4SLinus Torvalds #define PCIX_66MHZ_ECC		0x5
1011da177e4SLinus Torvalds #define PCIX_100MHZ_ECC		0x6
1021da177e4SLinus Torvalds #define PCIX_133MHZ_ECC		0x7
1031da177e4SLinus Torvalds #define PCIX_66MHZ_266		0x9
1041da177e4SLinus Torvalds #define PCIX_100MHZ_266		0xa
1051da177e4SLinus Torvalds #define PCIX_133MHZ_266		0xb
1061da177e4SLinus Torvalds #define PCIX_66MHZ_533		0x11
1071da177e4SLinus Torvalds #define PCIX_100MHZ_533		0x12
1081da177e4SLinus Torvalds #define PCIX_133MHZ_533		0x13
1091da177e4SLinus Torvalds 
1101da177e4SLinus Torvalds /* Slot Configuration */
1111da177e4SLinus Torvalds #define SLOT_NUM		0x0000001F
1121da177e4SLinus Torvalds #define	FIRST_DEV_NUM		0x00001F00
1131da177e4SLinus Torvalds #define PSN			0x07FF0000
1141da177e4SLinus Torvalds #define	UPDOWN			0x20000000
1151da177e4SLinus Torvalds #define	MRLSENSOR		0x40000000
1161da177e4SLinus Torvalds #define ATTN_BUTTON		0x80000000
1171da177e4SLinus Torvalds 
1181da177e4SLinus Torvalds /* Slot Status Field Definitions */
1191da177e4SLinus Torvalds /* Slot State */
1201da177e4SLinus Torvalds #define PWR_ONLY		0x0001
1211da177e4SLinus Torvalds #define ENABLED			0x0002
1221da177e4SLinus Torvalds #define DISABLED		0x0003
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds /* Power Indicator State */
1251da177e4SLinus Torvalds #define PWR_LED_ON		0x0004
1261da177e4SLinus Torvalds #define PWR_LED_BLINK		0x0008
1271da177e4SLinus Torvalds #define PWR_LED_OFF		0x000c
1281da177e4SLinus Torvalds 
1291da177e4SLinus Torvalds /* Attention Indicator State */
1301da177e4SLinus Torvalds #define ATTEN_LED_ON		0x0010
1311da177e4SLinus Torvalds #define	ATTEN_LED_BLINK		0x0020
1321da177e4SLinus Torvalds #define ATTEN_LED_OFF		0x0030
1331da177e4SLinus Torvalds 
1341da177e4SLinus Torvalds /* Power Fault */
1351da177e4SLinus Torvalds #define pwr_fault		0x0040
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds /* Attention Button */
1381da177e4SLinus Torvalds #define ATTEN_BUTTON		0x0080
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds /* MRL Sensor */
1411da177e4SLinus Torvalds #define MRL_SENSOR		0x0100
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds /* 66 MHz Capable */
1441da177e4SLinus Torvalds #define IS_66MHZ_CAP		0x0200
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds /* PRSNT1#/PRSNT2# */
1471da177e4SLinus Torvalds #define SLOT_EMP		0x0c00
1481da177e4SLinus Torvalds 
1491da177e4SLinus Torvalds /* PCI-X Capability */
1501da177e4SLinus Torvalds #define NON_PCIX		0x0000
1511da177e4SLinus Torvalds #define PCIX_66			0x1000
1521da177e4SLinus Torvalds #define PCIX_133		0x3000
1531da177e4SLinus Torvalds #define PCIX_266		0x4000  /* For PI = 2 only */
1541da177e4SLinus Torvalds #define PCIX_533		0x5000	/* For PI = 2 only */
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds /* SHPC 'write' operations/commands */
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds /* Slot operation - 0x00h to 0x3Fh */
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds #define NO_CHANGE		0x00
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds /* Slot state - Bits 0 & 1 of controller command register */
1631da177e4SLinus Torvalds #define SET_SLOT_PWR		0x01
1641da177e4SLinus Torvalds #define SET_SLOT_ENABLE		0x02
1651da177e4SLinus Torvalds #define SET_SLOT_DISABLE	0x03
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds /* Power indicator state - Bits 2 & 3 of controller command register*/
1681da177e4SLinus Torvalds #define SET_PWR_ON		0x04
1691da177e4SLinus Torvalds #define SET_PWR_BLINK		0x08
1701da177e4SLinus Torvalds #define SET_PWR_OFF		0x0C
1711da177e4SLinus Torvalds 
1721da177e4SLinus Torvalds /* Attention indicator state - Bits 4 & 5 of controller command register*/
1731da177e4SLinus Torvalds #define SET_ATTN_ON		0x010
1741da177e4SLinus Torvalds #define SET_ATTN_BLINK		0x020
1751da177e4SLinus Torvalds #define SET_ATTN_OFF		0x030
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds /* Set bus speed/mode A - 0x40h to 0x47h */
1781da177e4SLinus Torvalds #define SETA_PCI_33MHZ		0x40
1791da177e4SLinus Torvalds #define SETA_PCI_66MHZ		0x41
1801da177e4SLinus Torvalds #define SETA_PCIX_66MHZ		0x42
1811da177e4SLinus Torvalds #define SETA_PCIX_100MHZ	0x43
1821da177e4SLinus Torvalds #define SETA_PCIX_133MHZ	0x44
1831da177e4SLinus Torvalds #define RESERV_1		0x45
1841da177e4SLinus Torvalds #define RESERV_2		0x46
1851da177e4SLinus Torvalds #define RESERV_3		0x47
1861da177e4SLinus Torvalds 
1871da177e4SLinus Torvalds /* Set bus speed/mode B - 0x50h to 0x5fh */
1881da177e4SLinus Torvalds #define	SETB_PCI_33MHZ		0x50
1891da177e4SLinus Torvalds #define SETB_PCI_66MHZ		0x51
1901da177e4SLinus Torvalds #define SETB_PCIX_66MHZ_PM	0x52
1911da177e4SLinus Torvalds #define SETB_PCIX_100MHZ_PM	0x53
1921da177e4SLinus Torvalds #define SETB_PCIX_133MHZ_PM	0x54
1931da177e4SLinus Torvalds #define SETB_PCIX_66MHZ_EM	0x55
1941da177e4SLinus Torvalds #define SETB_PCIX_100MHZ_EM	0x56
1951da177e4SLinus Torvalds #define SETB_PCIX_133MHZ_EM	0x57
1961da177e4SLinus Torvalds #define SETB_PCIX_66MHZ_266	0x58
1971da177e4SLinus Torvalds #define SETB_PCIX_100MHZ_266	0x59
1981da177e4SLinus Torvalds #define SETB_PCIX_133MHZ_266	0x5a
1991da177e4SLinus Torvalds #define SETB_PCIX_66MHZ_533	0x5b
2001da177e4SLinus Torvalds #define SETB_PCIX_100MHZ_533	0x5c
2011da177e4SLinus Torvalds #define SETB_PCIX_133MHZ_533	0x5d
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds /* Power-on all slots - 0x48h */
2051da177e4SLinus Torvalds #define SET_PWR_ON_ALL		0x48
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds /* Enable all slots	- 0x49h */
2081da177e4SLinus Torvalds #define SET_ENABLE_ALL		0x49
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds /*  SHPC controller command error code */
2111da177e4SLinus Torvalds #define SWITCH_OPEN		0x1
2121da177e4SLinus Torvalds #define INVALID_CMD		0x2
2131da177e4SLinus Torvalds #define INVALID_SPEED_MODE	0x4
2141da177e4SLinus Torvalds 
2151da177e4SLinus Torvalds /* For accessing SHPC Working Register Set */
2161da177e4SLinus Torvalds #define DWORD_SELECT		0x2
2171da177e4SLinus Torvalds #define DWORD_DATA		0x4
2181da177e4SLinus Torvalds #define BASE_OFFSET		0x0
2191da177e4SLinus Torvalds 
2201da177e4SLinus Torvalds /* Field Offset in Logical Slot Register - byte boundary */
2211da177e4SLinus Torvalds #define SLOT_EVENT_LATCH	0x2
2221da177e4SLinus Torvalds #define SLOT_SERR_INT_MASK	0x3
2231da177e4SLinus Torvalds 
2241da177e4SLinus Torvalds static spinlock_t hpc_event_lock;
2251da177e4SLinus Torvalds 
2261da177e4SLinus Torvalds DEFINE_DBG_BUFFER		/* Debug string buffer for entire HPC defined here */
2271da177e4SLinus Torvalds static struct php_ctlr_state_s *php_ctlr_list_head;	/* HPC state linked list */
2281da177e4SLinus Torvalds static int ctlr_seq_num = 0;	/* Controller sequenc # */
2291da177e4SLinus Torvalds static spinlock_t list_lock;
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs);
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
234d29aaddaSKenji Kaneshige static int hpc_check_cmd_status(struct controller *ctrl);
2351da177e4SLinus Torvalds 
2361da177e4SLinus Torvalds /* This is the interrupt polling timeout function. */
2371da177e4SLinus Torvalds static void int_poll_timeout(unsigned long lphp_ctlr)
2381da177e4SLinus Torvalds {
2391da177e4SLinus Torvalds     struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr;
2401da177e4SLinus Torvalds 
2411da177e4SLinus Torvalds     DBG_ENTER_ROUTINE
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds     if ( !php_ctlr ) {
2441da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
2451da177e4SLinus Torvalds 		return;
2461da177e4SLinus Torvalds     }
2471da177e4SLinus Torvalds 
2481da177e4SLinus Torvalds     /* Poll for interrupt events.  regs == NULL => polling */
2491da177e4SLinus Torvalds     shpc_isr( 0, (void *)php_ctlr, NULL );
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds     init_timer(&php_ctlr->int_poll_timer);
2521da177e4SLinus Torvalds 	if (!shpchp_poll_time)
2531da177e4SLinus Torvalds 		shpchp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
2541da177e4SLinus Torvalds 
2551da177e4SLinus Torvalds     start_int_poll_timer(php_ctlr, shpchp_poll_time);
2561da177e4SLinus Torvalds 
2571da177e4SLinus Torvalds 	return;
2581da177e4SLinus Torvalds }
2591da177e4SLinus Torvalds 
2601da177e4SLinus Torvalds /* This function starts the interrupt polling timer. */
2611da177e4SLinus Torvalds static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
2621da177e4SLinus Torvalds {
2631da177e4SLinus Torvalds     if (!php_ctlr) {
2641da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
2651da177e4SLinus Torvalds 		return;
2661da177e4SLinus Torvalds 	}
2671da177e4SLinus Torvalds 
2681da177e4SLinus Torvalds     if ( ( seconds <= 0 ) || ( seconds > 60 ) )
2691da177e4SLinus Torvalds         seconds = 2;            /* Clamp to sane value */
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds     php_ctlr->int_poll_timer.function = &int_poll_timeout;
2721da177e4SLinus Torvalds     php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr;    /* Instance data */
2731da177e4SLinus Torvalds     php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ;
2741da177e4SLinus Torvalds     add_timer(&php_ctlr->int_poll_timer);
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds 	return;
2771da177e4SLinus Torvalds }
2781da177e4SLinus Torvalds 
279bd62e271SKenji Kaneshige static inline int shpc_wait_cmd(struct controller *ctrl)
280bd62e271SKenji Kaneshige {
281bd62e271SKenji Kaneshige 	int retval = 0;
282bd62e271SKenji Kaneshige 	unsigned int timeout_msec = shpchp_poll_mode ? 2000 : 1000;
283bd62e271SKenji Kaneshige 	unsigned long timeout = msecs_to_jiffies(timeout_msec);
284bd62e271SKenji Kaneshige 	int rc = wait_event_interruptible_timeout(ctrl->queue,
285bd62e271SKenji Kaneshige 						  !ctrl->cmd_busy, timeout);
286bd62e271SKenji Kaneshige 	if (!rc) {
287bd62e271SKenji Kaneshige 		retval = -EIO;
288bd62e271SKenji Kaneshige 		err("Command not completed in %d msec\n", timeout_msec);
289bd62e271SKenji Kaneshige 	} else if (rc < 0) {
290bd62e271SKenji Kaneshige 		retval = -EINTR;
291bd62e271SKenji Kaneshige 		info("Command was interrupted by a signal\n");
292bd62e271SKenji Kaneshige 	}
293bd62e271SKenji Kaneshige 	ctrl->cmd_busy = 0;
294bd62e271SKenji Kaneshige 
295bd62e271SKenji Kaneshige 	return retval;
296bd62e271SKenji Kaneshige }
297bd62e271SKenji Kaneshige 
2981da177e4SLinus Torvalds static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
2991da177e4SLinus Torvalds {
300ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
3011da177e4SLinus Torvalds 	u16 cmd_status;
3021da177e4SLinus Torvalds 	int retval = 0;
3031da177e4SLinus Torvalds 	u16 temp_word;
3041da177e4SLinus Torvalds 	int i;
3051da177e4SLinus Torvalds 
3061da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
3071da177e4SLinus Torvalds 
308d29aaddaSKenji Kaneshige 	mutex_lock(&slot->ctrl->cmd_lock);
309d29aaddaSKenji Kaneshige 
3101da177e4SLinus Torvalds 	if (!php_ctlr) {
3111da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
312d29aaddaSKenji Kaneshige 		retval = -EINVAL;
313d29aaddaSKenji Kaneshige 		goto out;
3141da177e4SLinus Torvalds 	}
3151da177e4SLinus Torvalds 
3161da177e4SLinus Torvalds 	for (i = 0; i < 10; i++) {
3171da177e4SLinus Torvalds 		cmd_status = readw(php_ctlr->creg + CMD_STATUS);
3181da177e4SLinus Torvalds 
3191da177e4SLinus Torvalds 		if (!(cmd_status & 0x1))
3201da177e4SLinus Torvalds 			break;
3211da177e4SLinus Torvalds 		/*  Check every 0.1 sec for a total of 1 sec*/
3221da177e4SLinus Torvalds 		msleep(100);
3231da177e4SLinus Torvalds 	}
3241da177e4SLinus Torvalds 
3251da177e4SLinus Torvalds 	cmd_status = readw(php_ctlr->creg + CMD_STATUS);
3261da177e4SLinus Torvalds 
3271da177e4SLinus Torvalds 	if (cmd_status & 0x1) {
3281da177e4SLinus Torvalds 		/* After 1 sec and and the controller is still busy */
3291da177e4SLinus Torvalds 		err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__);
330d29aaddaSKenji Kaneshige 		retval = -EBUSY;
331d29aaddaSKenji Kaneshige 		goto out;
3321da177e4SLinus Torvalds 	}
3331da177e4SLinus Torvalds 
3341da177e4SLinus Torvalds 	++t_slot;
3351da177e4SLinus Torvalds 	temp_word =  (t_slot << 8) | (cmd & 0xFF);
3361da177e4SLinus Torvalds 	dbg("%s: t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd);
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds 	/* To make sure the Controller Busy bit is 0 before we send out the
3391da177e4SLinus Torvalds 	 * command.
3401da177e4SLinus Torvalds 	 */
341bd62e271SKenji Kaneshige 	slot->ctrl->cmd_busy = 1;
3421da177e4SLinus Torvalds 	writew(temp_word, php_ctlr->creg + CMD);
3431da177e4SLinus Torvalds 
344bd62e271SKenji Kaneshige 	/*
345bd62e271SKenji Kaneshige 	 * Wait for command completion.
346bd62e271SKenji Kaneshige 	 */
347bd62e271SKenji Kaneshige 	retval = shpc_wait_cmd(slot->ctrl);
348d29aaddaSKenji Kaneshige 	if (retval)
349d29aaddaSKenji Kaneshige 		goto out;
350d29aaddaSKenji Kaneshige 
351d29aaddaSKenji Kaneshige 	cmd_status = hpc_check_cmd_status(slot->ctrl);
352d29aaddaSKenji Kaneshige 	if (cmd_status) {
353d29aaddaSKenji Kaneshige 		err("%s: Failed to issued command 0x%x (error code = %d)\n",
354d29aaddaSKenji Kaneshige 		    __FUNCTION__, cmd, cmd_status);
355d29aaddaSKenji Kaneshige 		retval = -EIO;
356d29aaddaSKenji Kaneshige 	}
357d29aaddaSKenji Kaneshige  out:
358d29aaddaSKenji Kaneshige 	mutex_unlock(&slot->ctrl->cmd_lock);
359bd62e271SKenji Kaneshige 
3601da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
3611da177e4SLinus Torvalds 	return retval;
3621da177e4SLinus Torvalds }
3631da177e4SLinus Torvalds 
3641da177e4SLinus Torvalds static int hpc_check_cmd_status(struct controller *ctrl)
3651da177e4SLinus Torvalds {
366ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
3671da177e4SLinus Torvalds 	u16 cmd_status;
3681da177e4SLinus Torvalds 	int retval = 0;
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
3711da177e4SLinus Torvalds 
3721da177e4SLinus Torvalds 	if (!ctrl->hpc_ctlr_handle) {
3731da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
3741da177e4SLinus Torvalds 		return -1;
3751da177e4SLinus Torvalds 	}
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds 	cmd_status = readw(php_ctlr->creg + CMD_STATUS) & 0x000F;
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds 	switch (cmd_status >> 1) {
3801da177e4SLinus Torvalds 	case 0:
3811da177e4SLinus Torvalds 		retval = 0;
3821da177e4SLinus Torvalds 		break;
3831da177e4SLinus Torvalds 	case 1:
3841da177e4SLinus Torvalds 		retval = SWITCH_OPEN;
3851da177e4SLinus Torvalds 		err("%s: Switch opened!\n", __FUNCTION__);
3861da177e4SLinus Torvalds 		break;
3871da177e4SLinus Torvalds 	case 2:
3881da177e4SLinus Torvalds 		retval = INVALID_CMD;
3891da177e4SLinus Torvalds 		err("%s: Invalid HPC command!\n", __FUNCTION__);
3901da177e4SLinus Torvalds 		break;
3911da177e4SLinus Torvalds 	case 4:
3921da177e4SLinus Torvalds 		retval = INVALID_SPEED_MODE;
3931da177e4SLinus Torvalds 		err("%s: Invalid bus speed/mode!\n", __FUNCTION__);
3941da177e4SLinus Torvalds 		break;
3951da177e4SLinus Torvalds 	default:
3961da177e4SLinus Torvalds 		retval = cmd_status;
3971da177e4SLinus Torvalds 	}
3981da177e4SLinus Torvalds 
3991da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
4001da177e4SLinus Torvalds 	return retval;
4011da177e4SLinus Torvalds }
4021da177e4SLinus Torvalds 
4031da177e4SLinus Torvalds 
4041da177e4SLinus Torvalds static int hpc_get_attention_status(struct slot *slot, u8 *status)
4051da177e4SLinus Torvalds {
406ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
4071da177e4SLinus Torvalds 	u32 slot_reg;
4081da177e4SLinus Torvalds 	u16 slot_status;
4091da177e4SLinus Torvalds 	u8 atten_led_state;
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
4121da177e4SLinus Torvalds 
4131da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
4141da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
4151da177e4SLinus Torvalds 		return -1;
4161da177e4SLinus Torvalds 	}
4171da177e4SLinus Torvalds 
4181da177e4SLinus Torvalds 	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
4191da177e4SLinus Torvalds 	slot_status = (u16) slot_reg;
4201da177e4SLinus Torvalds 	atten_led_state = (slot_status & 0x0030) >> 4;
4211da177e4SLinus Torvalds 
4221da177e4SLinus Torvalds 	switch (atten_led_state) {
4231da177e4SLinus Torvalds 	case 0:
4241da177e4SLinus Torvalds 		*status = 0xFF;	/* Reserved */
4251da177e4SLinus Torvalds 		break;
4261da177e4SLinus Torvalds 	case 1:
4271da177e4SLinus Torvalds 		*status = 1;	/* On */
4281da177e4SLinus Torvalds 		break;
4291da177e4SLinus Torvalds 	case 2:
4301da177e4SLinus Torvalds 		*status = 2;	/* Blink */
4311da177e4SLinus Torvalds 		break;
4321da177e4SLinus Torvalds 	case 3:
4331da177e4SLinus Torvalds 		*status = 0;	/* Off */
4341da177e4SLinus Torvalds 		break;
4351da177e4SLinus Torvalds 	default:
4361da177e4SLinus Torvalds 		*status = 0xFF;
4371da177e4SLinus Torvalds 		break;
4381da177e4SLinus Torvalds 	}
4391da177e4SLinus Torvalds 
4401da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
4411da177e4SLinus Torvalds 	return 0;
4421da177e4SLinus Torvalds }
4431da177e4SLinus Torvalds 
4441da177e4SLinus Torvalds static int hpc_get_power_status(struct slot * slot, u8 *status)
4451da177e4SLinus Torvalds {
446ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
4471da177e4SLinus Torvalds 	u32 slot_reg;
4481da177e4SLinus Torvalds 	u16 slot_status;
4491da177e4SLinus Torvalds 	u8 slot_state;
4501da177e4SLinus Torvalds 	int	retval = 0;
4511da177e4SLinus Torvalds 
4521da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
4531da177e4SLinus Torvalds 
4541da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
4551da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
4561da177e4SLinus Torvalds 		return -1;
4571da177e4SLinus Torvalds 	}
4581da177e4SLinus Torvalds 
4591da177e4SLinus Torvalds 	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
4601da177e4SLinus Torvalds 	slot_status = (u16) slot_reg;
4611da177e4SLinus Torvalds 	slot_state = (slot_status & 0x0003);
4621da177e4SLinus Torvalds 
4631da177e4SLinus Torvalds 	switch (slot_state) {
4641da177e4SLinus Torvalds 	case 0:
4651da177e4SLinus Torvalds 		*status = 0xFF;
4661da177e4SLinus Torvalds 		break;
4671da177e4SLinus Torvalds 	case 1:
4681da177e4SLinus Torvalds 		*status = 2;	/* Powered only */
4691da177e4SLinus Torvalds 		break;
4701da177e4SLinus Torvalds 	case 2:
4711da177e4SLinus Torvalds 		*status = 1;	/* Enabled */
4721da177e4SLinus Torvalds 		break;
4731da177e4SLinus Torvalds 	case 3:
4741da177e4SLinus Torvalds 		*status = 0;	/* Disabled */
4751da177e4SLinus Torvalds 		break;
4761da177e4SLinus Torvalds 	default:
4771da177e4SLinus Torvalds 		*status = 0xFF;
4781da177e4SLinus Torvalds 		break;
4791da177e4SLinus Torvalds 	}
4801da177e4SLinus Torvalds 
4811da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
4821da177e4SLinus Torvalds 	return retval;
4831da177e4SLinus Torvalds }
4841da177e4SLinus Torvalds 
4851da177e4SLinus Torvalds 
4861da177e4SLinus Torvalds static int hpc_get_latch_status(struct slot *slot, u8 *status)
4871da177e4SLinus Torvalds {
488ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
4891da177e4SLinus Torvalds 	u32 slot_reg;
4901da177e4SLinus Torvalds 	u16 slot_status;
4911da177e4SLinus Torvalds 
4921da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
4931da177e4SLinus Torvalds 
4941da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
4951da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
4961da177e4SLinus Torvalds 		return -1;
4971da177e4SLinus Torvalds 	}
4981da177e4SLinus Torvalds 
4991da177e4SLinus Torvalds 	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
5001da177e4SLinus Torvalds 	slot_status = (u16)slot_reg;
5011da177e4SLinus Torvalds 
5021da177e4SLinus Torvalds 	*status = ((slot_status & 0x0100) == 0) ? 0 : 1;   /* 0 -> close; 1 -> open */
5031da177e4SLinus Torvalds 
5041da177e4SLinus Torvalds 
5051da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
5061da177e4SLinus Torvalds 	return 0;
5071da177e4SLinus Torvalds }
5081da177e4SLinus Torvalds 
5091da177e4SLinus Torvalds static int hpc_get_adapter_status(struct slot *slot, u8 *status)
5101da177e4SLinus Torvalds {
511ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
5121da177e4SLinus Torvalds 	u32 slot_reg;
5131da177e4SLinus Torvalds 	u16 slot_status;
5141da177e4SLinus Torvalds 	u8 card_state;
5151da177e4SLinus Torvalds 
5161da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
5171da177e4SLinus Torvalds 
5181da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
5191da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
5201da177e4SLinus Torvalds 		return -1;
5211da177e4SLinus Torvalds 	}
5221da177e4SLinus Torvalds 
5231da177e4SLinus Torvalds 	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
5241da177e4SLinus Torvalds 	slot_status = (u16)slot_reg;
5251da177e4SLinus Torvalds 	card_state = (u8)((slot_status & 0x0C00) >> 10);
5261da177e4SLinus Torvalds 	*status = (card_state != 0x3) ? 1 : 0;
5271da177e4SLinus Torvalds 
5281da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
5291da177e4SLinus Torvalds 	return 0;
5301da177e4SLinus Torvalds }
5311da177e4SLinus Torvalds 
5321da177e4SLinus Torvalds static int hpc_get_prog_int(struct slot *slot, u8 *prog_int)
5331da177e4SLinus Torvalds {
534ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
5351da177e4SLinus Torvalds 
5361da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
5371da177e4SLinus Torvalds 
5381da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
5391da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
5401da177e4SLinus Torvalds 		return -1;
5411da177e4SLinus Torvalds 	}
5421da177e4SLinus Torvalds 
5431da177e4SLinus Torvalds 	*prog_int = readb(php_ctlr->creg + PROG_INTERFACE);
5441da177e4SLinus Torvalds 
5451da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
5461da177e4SLinus Torvalds 	return 0;
5471da177e4SLinus Torvalds }
5481da177e4SLinus Torvalds 
5491da177e4SLinus Torvalds static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
5501da177e4SLinus Torvalds {
551ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
5521da177e4SLinus Torvalds 	u32 slot_reg;
5531da177e4SLinus Torvalds 	u16 slot_status, sec_bus_status;
5541da177e4SLinus Torvalds 	u8 m66_cap, pcix_cap, pi;
5551da177e4SLinus Torvalds 	int retval = 0;
5561da177e4SLinus Torvalds 
5571da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
5581da177e4SLinus Torvalds 
5591da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
5601da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
5611da177e4SLinus Torvalds 		return -1;
5621da177e4SLinus Torvalds 	}
5631da177e4SLinus Torvalds 
5641da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
5651da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
5661da177e4SLinus Torvalds 		return -1;
5671da177e4SLinus Torvalds 	}
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds 	pi = readb(php_ctlr->creg + PROG_INTERFACE);
5701da177e4SLinus Torvalds 	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
5711da177e4SLinus Torvalds 	dbg("%s: pi = %d, slot_reg = %x\n", __FUNCTION__, pi, slot_reg);
5721da177e4SLinus Torvalds 	slot_status = (u16) slot_reg;
5731da177e4SLinus Torvalds 	dbg("%s: slot_status = %x\n", __FUNCTION__, slot_status);
5741da177e4SLinus Torvalds 	sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG);
5751da177e4SLinus Torvalds 
5761da177e4SLinus Torvalds 	pcix_cap = (u8) ((slot_status & 0x3000) >> 12);
5771da177e4SLinus Torvalds 	dbg("%s:  pcix_cap = %x\n", __FUNCTION__, pcix_cap);
5781da177e4SLinus Torvalds 	m66_cap = (u8) ((slot_status & 0x0200) >> 9);
5791da177e4SLinus Torvalds 	dbg("%s:  m66_cap = %x\n", __FUNCTION__, m66_cap);
5801da177e4SLinus Torvalds 
5811da177e4SLinus Torvalds 
5821da177e4SLinus Torvalds 	if (pi == 2) {
5831da177e4SLinus Torvalds 		switch (pcix_cap) {
5841da177e4SLinus Torvalds 		case 0:
5851da177e4SLinus Torvalds 			*value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
5861da177e4SLinus Torvalds 			break;
5871da177e4SLinus Torvalds 		case 1:
5881da177e4SLinus Torvalds 			*value = PCI_SPEED_66MHz_PCIX;
5891da177e4SLinus Torvalds 			break;
5901da177e4SLinus Torvalds 		case 3:
5911da177e4SLinus Torvalds 			*value = PCI_SPEED_133MHz_PCIX;
5921da177e4SLinus Torvalds 			break;
5931da177e4SLinus Torvalds 		case 4:
5941da177e4SLinus Torvalds 			*value = PCI_SPEED_133MHz_PCIX_266;
5951da177e4SLinus Torvalds 			break;
5961da177e4SLinus Torvalds 		case 5:
5971da177e4SLinus Torvalds 			*value = PCI_SPEED_133MHz_PCIX_533;
5981da177e4SLinus Torvalds 			break;
5991da177e4SLinus Torvalds 		case 2:	/* Reserved */
6001da177e4SLinus Torvalds 		default:
6011da177e4SLinus Torvalds 			*value = PCI_SPEED_UNKNOWN;
6021da177e4SLinus Torvalds 			retval = -ENODEV;
6031da177e4SLinus Torvalds 			break;
6041da177e4SLinus Torvalds 		}
6051da177e4SLinus Torvalds 	} else {
6061da177e4SLinus Torvalds 		switch (pcix_cap) {
6071da177e4SLinus Torvalds 		case 0:
6081da177e4SLinus Torvalds 			*value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
6091da177e4SLinus Torvalds 			break;
6101da177e4SLinus Torvalds 		case 1:
6111da177e4SLinus Torvalds 			*value = PCI_SPEED_66MHz_PCIX;
6121da177e4SLinus Torvalds 			break;
6131da177e4SLinus Torvalds 		case 3:
6141da177e4SLinus Torvalds 			*value = PCI_SPEED_133MHz_PCIX;
6151da177e4SLinus Torvalds 			break;
6161da177e4SLinus Torvalds 		case 2:	/* Reserved */
6171da177e4SLinus Torvalds 		default:
6181da177e4SLinus Torvalds 			*value = PCI_SPEED_UNKNOWN;
6191da177e4SLinus Torvalds 			retval = -ENODEV;
6201da177e4SLinus Torvalds 			break;
6211da177e4SLinus Torvalds 		}
6221da177e4SLinus Torvalds 	}
6231da177e4SLinus Torvalds 
6241da177e4SLinus Torvalds 	dbg("Adapter speed = %d\n", *value);
6251da177e4SLinus Torvalds 
6261da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
6271da177e4SLinus Torvalds 	return retval;
6281da177e4SLinus Torvalds }
6291da177e4SLinus Torvalds 
6301da177e4SLinus Torvalds static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
6311da177e4SLinus Torvalds {
632ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
6331da177e4SLinus Torvalds 	u16 sec_bus_status;
6341da177e4SLinus Torvalds 	u8 pi;
6351da177e4SLinus Torvalds 	int retval = 0;
6361da177e4SLinus Torvalds 
6371da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
6381da177e4SLinus Torvalds 
6391da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
6401da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
6411da177e4SLinus Torvalds 		return -1;
6421da177e4SLinus Torvalds 	}
6431da177e4SLinus Torvalds 
6441da177e4SLinus Torvalds 	pi = readb(php_ctlr->creg + PROG_INTERFACE);
6451da177e4SLinus Torvalds 	sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG);
6461da177e4SLinus Torvalds 
6471da177e4SLinus Torvalds 	if (pi == 2) {
64887d6c559SKenji Kaneshige 		*mode = (sec_bus_status & 0x0100) >> 8;
6491da177e4SLinus Torvalds 	} else {
6501da177e4SLinus Torvalds 		retval = -1;
6511da177e4SLinus Torvalds 	}
6521da177e4SLinus Torvalds 
6531da177e4SLinus Torvalds 	dbg("Mode 1 ECC cap = %d\n", *mode);
6541da177e4SLinus Torvalds 
6551da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
6561da177e4SLinus Torvalds 	return retval;
6571da177e4SLinus Torvalds }
6581da177e4SLinus Torvalds 
6591da177e4SLinus Torvalds static int hpc_query_power_fault(struct slot * slot)
6601da177e4SLinus Torvalds {
661ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
6621da177e4SLinus Torvalds 	u32 slot_reg;
6631da177e4SLinus Torvalds 	u16 slot_status;
6641da177e4SLinus Torvalds 	u8 pwr_fault_state, status;
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
6671da177e4SLinus Torvalds 
6681da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
6691da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
6701da177e4SLinus Torvalds 		return -1;
6711da177e4SLinus Torvalds 	}
6721da177e4SLinus Torvalds 
6731da177e4SLinus Torvalds 	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
6741da177e4SLinus Torvalds 	slot_status = (u16) slot_reg;
6751da177e4SLinus Torvalds 	pwr_fault_state = (slot_status & 0x0040) >> 7;
6761da177e4SLinus Torvalds 	status = (pwr_fault_state == 1) ? 0 : 1;
6771da177e4SLinus Torvalds 
6781da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
6791da177e4SLinus Torvalds 	/* Note: Logic 0 => fault */
6801da177e4SLinus Torvalds 	return status;
6811da177e4SLinus Torvalds }
6821da177e4SLinus Torvalds 
6831da177e4SLinus Torvalds static int hpc_set_attention_status(struct slot *slot, u8 value)
6841da177e4SLinus Torvalds {
685ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
6861da177e4SLinus Torvalds 	u8 slot_cmd = 0;
6871da177e4SLinus Torvalds 	int rc = 0;
6881da177e4SLinus Torvalds 
6891da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
6901da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
6911da177e4SLinus Torvalds 		return -1;
6921da177e4SLinus Torvalds 	}
6931da177e4SLinus Torvalds 
6941da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
6951da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
6961da177e4SLinus Torvalds 		return -1;
6971da177e4SLinus Torvalds 	}
6981da177e4SLinus Torvalds 
6991da177e4SLinus Torvalds 	switch (value) {
7001da177e4SLinus Torvalds 		case 0 :
7011da177e4SLinus Torvalds 			slot_cmd = 0x30;	/* OFF */
7021da177e4SLinus Torvalds 			break;
7031da177e4SLinus Torvalds 		case 1:
7041da177e4SLinus Torvalds 			slot_cmd = 0x10;	/* ON */
7051da177e4SLinus Torvalds 			break;
7061da177e4SLinus Torvalds 		case 2:
7071da177e4SLinus Torvalds 			slot_cmd = 0x20;	/* BLINK */
7081da177e4SLinus Torvalds 			break;
7091da177e4SLinus Torvalds 		default:
7101da177e4SLinus Torvalds 			return -1;
7111da177e4SLinus Torvalds 	}
7121da177e4SLinus Torvalds 
7131da177e4SLinus Torvalds 	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
7141da177e4SLinus Torvalds 
7151da177e4SLinus Torvalds 	return rc;
7161da177e4SLinus Torvalds }
7171da177e4SLinus Torvalds 
7181da177e4SLinus Torvalds 
7191da177e4SLinus Torvalds static void hpc_set_green_led_on(struct slot *slot)
7201da177e4SLinus Torvalds {
721ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
7221da177e4SLinus Torvalds 	u8 slot_cmd;
7231da177e4SLinus Torvalds 
7241da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
7251da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
7261da177e4SLinus Torvalds 		return ;
7271da177e4SLinus Torvalds 	}
7281da177e4SLinus Torvalds 
7291da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
7301da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
7311da177e4SLinus Torvalds 		return ;
7321da177e4SLinus Torvalds 	}
7331da177e4SLinus Torvalds 
7341da177e4SLinus Torvalds 	slot_cmd = 0x04;
7351da177e4SLinus Torvalds 
7361da177e4SLinus Torvalds 	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
7371da177e4SLinus Torvalds 
7381da177e4SLinus Torvalds 	return;
7391da177e4SLinus Torvalds }
7401da177e4SLinus Torvalds 
7411da177e4SLinus Torvalds static void hpc_set_green_led_off(struct slot *slot)
7421da177e4SLinus Torvalds {
743ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
7441da177e4SLinus Torvalds 	u8 slot_cmd;
7451da177e4SLinus Torvalds 
7461da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
7471da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
7481da177e4SLinus Torvalds 		return ;
7491da177e4SLinus Torvalds 	}
7501da177e4SLinus Torvalds 
7511da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
7521da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
7531da177e4SLinus Torvalds 		return ;
7541da177e4SLinus Torvalds 	}
7551da177e4SLinus Torvalds 
7561da177e4SLinus Torvalds 	slot_cmd = 0x0C;
7571da177e4SLinus Torvalds 
7581da177e4SLinus Torvalds 	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
7591da177e4SLinus Torvalds 
7601da177e4SLinus Torvalds 	return;
7611da177e4SLinus Torvalds }
7621da177e4SLinus Torvalds 
7631da177e4SLinus Torvalds static void hpc_set_green_led_blink(struct slot *slot)
7641da177e4SLinus Torvalds {
765ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
7661da177e4SLinus Torvalds 	u8 slot_cmd;
7671da177e4SLinus Torvalds 
7681da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
7691da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
7701da177e4SLinus Torvalds 		return ;
7711da177e4SLinus Torvalds 	}
7721da177e4SLinus Torvalds 
7731da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
7741da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
7751da177e4SLinus Torvalds 		return ;
7761da177e4SLinus Torvalds 	}
7771da177e4SLinus Torvalds 
7781da177e4SLinus Torvalds 	slot_cmd = 0x08;
7791da177e4SLinus Torvalds 
7801da177e4SLinus Torvalds 	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
7811da177e4SLinus Torvalds 
7821da177e4SLinus Torvalds 	return;
7831da177e4SLinus Torvalds }
7841da177e4SLinus Torvalds 
7851da177e4SLinus Torvalds int shpc_get_ctlr_slot_config(struct controller *ctrl,
7861da177e4SLinus Torvalds 	int *num_ctlr_slots,	/* number of slots in this HPC			*/
7871da177e4SLinus Torvalds 	int *first_device_num,	/* PCI dev num of the first slot in this SHPC	*/
7881da177e4SLinus Torvalds 	int *physical_slot_num,	/* phy slot num of the first slot in this SHPC	*/
7891da177e4SLinus Torvalds 	int *updown,		/* physical_slot_num increament: 1 or -1	*/
7901da177e4SLinus Torvalds 	int *flags)
7911da177e4SLinus Torvalds {
792ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
7931da177e4SLinus Torvalds 
7941da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
7951da177e4SLinus Torvalds 
7961da177e4SLinus Torvalds 	if (!ctrl->hpc_ctlr_handle) {
7971da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
7981da177e4SLinus Torvalds 		return -1;
7991da177e4SLinus Torvalds 	}
8001da177e4SLinus Torvalds 
8011da177e4SLinus Torvalds 	*first_device_num = php_ctlr->slot_device_offset;	/* Obtained in shpc_init() */
8021da177e4SLinus Torvalds 	*num_ctlr_slots = php_ctlr->num_slots;			/* Obtained in shpc_init() */
8031da177e4SLinus Torvalds 
8041da177e4SLinus Torvalds 	*physical_slot_num = (readl(php_ctlr->creg + SLOT_CONFIG) & PSN) >> 16;
8051da177e4SLinus Torvalds 	dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num);
8061da177e4SLinus Torvalds 	*updown = ((readl(php_ctlr->creg + SLOT_CONFIG) & UPDOWN ) >> 29) ? 1 : -1;
8071da177e4SLinus Torvalds 
8081da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
8091da177e4SLinus Torvalds 	return 0;
8101da177e4SLinus Torvalds }
8111da177e4SLinus Torvalds 
8121da177e4SLinus Torvalds static void hpc_release_ctlr(struct controller *ctrl)
8131da177e4SLinus Torvalds {
814ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
8151da177e4SLinus Torvalds 	struct php_ctlr_state_s *p, *p_prev;
8161da177e4SLinus Torvalds 
8171da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
8181da177e4SLinus Torvalds 
8191da177e4SLinus Torvalds 	if (!ctrl->hpc_ctlr_handle) {
8201da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
8211da177e4SLinus Torvalds 		return ;
8221da177e4SLinus Torvalds 	}
8231da177e4SLinus Torvalds 
8241da177e4SLinus Torvalds 	if (shpchp_poll_mode) {
8251da177e4SLinus Torvalds 	    del_timer(&php_ctlr->int_poll_timer);
8261da177e4SLinus Torvalds 	} else {
8271da177e4SLinus Torvalds 		if (php_ctlr->irq) {
8281da177e4SLinus Torvalds 			free_irq(php_ctlr->irq, ctrl);
8291da177e4SLinus Torvalds 			php_ctlr->irq = 0;
8301da177e4SLinus Torvalds 			pci_disable_msi(php_ctlr->pci_dev);
8311da177e4SLinus Torvalds 		}
8321da177e4SLinus Torvalds 	}
8331da177e4SLinus Torvalds 	if (php_ctlr->pci_dev) {
8341da177e4SLinus Torvalds 		iounmap(php_ctlr->creg);
8350455986cSKenji Kaneshige 		release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
8361da177e4SLinus Torvalds 		php_ctlr->pci_dev = NULL;
8371da177e4SLinus Torvalds 	}
8381da177e4SLinus Torvalds 
8391da177e4SLinus Torvalds 	spin_lock(&list_lock);
8401da177e4SLinus Torvalds 	p = php_ctlr_list_head;
8411da177e4SLinus Torvalds 	p_prev = NULL;
8421da177e4SLinus Torvalds 	while (p) {
8431da177e4SLinus Torvalds 		if (p == php_ctlr) {
8441da177e4SLinus Torvalds 			if (p_prev)
8451da177e4SLinus Torvalds 				p_prev->pnext = p->pnext;
8461da177e4SLinus Torvalds 			else
8471da177e4SLinus Torvalds 				php_ctlr_list_head = p->pnext;
8481da177e4SLinus Torvalds 			break;
8491da177e4SLinus Torvalds 		} else {
8501da177e4SLinus Torvalds 			p_prev = p;
8511da177e4SLinus Torvalds 			p = p->pnext;
8521da177e4SLinus Torvalds 		}
8531da177e4SLinus Torvalds 	}
8541da177e4SLinus Torvalds 	spin_unlock(&list_lock);
8551da177e4SLinus Torvalds 
8561da177e4SLinus Torvalds 	kfree(php_ctlr);
8571da177e4SLinus Torvalds 
8581da177e4SLinus Torvalds DBG_LEAVE_ROUTINE
8591da177e4SLinus Torvalds 
8601da177e4SLinus Torvalds }
8611da177e4SLinus Torvalds 
8621da177e4SLinus Torvalds static int hpc_power_on_slot(struct slot * slot)
8631da177e4SLinus Torvalds {
864ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
8651da177e4SLinus Torvalds 	u8 slot_cmd;
8661da177e4SLinus Torvalds 	int retval = 0;
8671da177e4SLinus Torvalds 
8681da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
8691da177e4SLinus Torvalds 
8701da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
8711da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
8721da177e4SLinus Torvalds 		return -1;
8731da177e4SLinus Torvalds 	}
8741da177e4SLinus Torvalds 
8751da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
8761da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
8771da177e4SLinus Torvalds 		return -1;
8781da177e4SLinus Torvalds 	}
8791da177e4SLinus Torvalds 	slot_cmd = 0x01;
8801da177e4SLinus Torvalds 
8811da177e4SLinus Torvalds 	retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
8821da177e4SLinus Torvalds 
8831da177e4SLinus Torvalds 	if (retval) {
8841da177e4SLinus Torvalds 		err("%s: Write command failed!\n", __FUNCTION__);
8851da177e4SLinus Torvalds 		return -1;
8861da177e4SLinus Torvalds 	}
8871da177e4SLinus Torvalds 
8881da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
8891da177e4SLinus Torvalds 
8901da177e4SLinus Torvalds 	return retval;
8911da177e4SLinus Torvalds }
8921da177e4SLinus Torvalds 
8931da177e4SLinus Torvalds static int hpc_slot_enable(struct slot * slot)
8941da177e4SLinus Torvalds {
895ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
8961da177e4SLinus Torvalds 	u8 slot_cmd;
8971da177e4SLinus Torvalds 	int retval = 0;
8981da177e4SLinus Torvalds 
8991da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
9001da177e4SLinus Torvalds 
9011da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
9021da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
9031da177e4SLinus Torvalds 		return -1;
9041da177e4SLinus Torvalds 	}
9051da177e4SLinus Torvalds 
9061da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
9071da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
9081da177e4SLinus Torvalds 		return -1;
9091da177e4SLinus Torvalds 	}
9101da177e4SLinus Torvalds 	/* 3A => Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */
9111da177e4SLinus Torvalds 	slot_cmd = 0x3A;
9121da177e4SLinus Torvalds 
9131da177e4SLinus Torvalds 	retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
9141da177e4SLinus Torvalds 
9151da177e4SLinus Torvalds 	if (retval) {
9161da177e4SLinus Torvalds 		err("%s: Write command failed!\n", __FUNCTION__);
9171da177e4SLinus Torvalds 		return -1;
9181da177e4SLinus Torvalds 	}
9191da177e4SLinus Torvalds 
9201da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
9211da177e4SLinus Torvalds 	return retval;
9221da177e4SLinus Torvalds }
9231da177e4SLinus Torvalds 
9241da177e4SLinus Torvalds static int hpc_slot_disable(struct slot * slot)
9251da177e4SLinus Torvalds {
926ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
9271da177e4SLinus Torvalds 	u8 slot_cmd;
9281da177e4SLinus Torvalds 	int retval = 0;
9291da177e4SLinus Torvalds 
9301da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
9311da177e4SLinus Torvalds 
9321da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
9331da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
9341da177e4SLinus Torvalds 		return -1;
9351da177e4SLinus Torvalds 	}
9361da177e4SLinus Torvalds 
9371da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
9381da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
9391da177e4SLinus Torvalds 		return -1;
9401da177e4SLinus Torvalds 	}
9411da177e4SLinus Torvalds 
9421da177e4SLinus Torvalds 	/* 1F => Slot - Disable, Power Indicator - Off, Attention Indicator - On */
9431da177e4SLinus Torvalds 	slot_cmd = 0x1F;
9441da177e4SLinus Torvalds 
9451da177e4SLinus Torvalds 	retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
9461da177e4SLinus Torvalds 
9471da177e4SLinus Torvalds 	if (retval) {
9481da177e4SLinus Torvalds 		err("%s: Write command failed!\n", __FUNCTION__);
9491da177e4SLinus Torvalds 		return -1;
9501da177e4SLinus Torvalds 	}
9511da177e4SLinus Torvalds 
9521da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
9531da177e4SLinus Torvalds 	return retval;
9541da177e4SLinus Torvalds }
9551da177e4SLinus Torvalds 
9561da177e4SLinus Torvalds static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
9571da177e4SLinus Torvalds {
9581da177e4SLinus Torvalds 	u8 slot_cmd;
9591da177e4SLinus Torvalds 	u8 pi;
9601da177e4SLinus Torvalds 	int retval = 0;
961ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
9621da177e4SLinus Torvalds 
9631da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
9641da177e4SLinus Torvalds 
9651da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
9661da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
9671da177e4SLinus Torvalds 		return -1;
9681da177e4SLinus Torvalds 	}
9691da177e4SLinus Torvalds 
9701da177e4SLinus Torvalds 	pi = readb(php_ctlr->creg + PROG_INTERFACE);
9711da177e4SLinus Torvalds 
9721da177e4SLinus Torvalds 	if (pi == 1) {
9731da177e4SLinus Torvalds 		switch (value) {
9741da177e4SLinus Torvalds 		case 0:
9751da177e4SLinus Torvalds 			slot_cmd = SETA_PCI_33MHZ;
9761da177e4SLinus Torvalds 			break;
9771da177e4SLinus Torvalds 		case 1:
9781da177e4SLinus Torvalds 			slot_cmd = SETA_PCI_66MHZ;
9791da177e4SLinus Torvalds 			break;
9801da177e4SLinus Torvalds 		case 2:
9811da177e4SLinus Torvalds 			slot_cmd = SETA_PCIX_66MHZ;
9821da177e4SLinus Torvalds 			break;
9831da177e4SLinus Torvalds 		case 3:
9841da177e4SLinus Torvalds 			slot_cmd = SETA_PCIX_100MHZ;
9851da177e4SLinus Torvalds 			break;
9861da177e4SLinus Torvalds 		case 4:
9871da177e4SLinus Torvalds 			slot_cmd = SETA_PCIX_133MHZ;
9881da177e4SLinus Torvalds 			break;
9891da177e4SLinus Torvalds 		default:
9901da177e4SLinus Torvalds 			slot_cmd = PCI_SPEED_UNKNOWN;
9911da177e4SLinus Torvalds 			retval = -ENODEV;
9921da177e4SLinus Torvalds 			return retval;
9931da177e4SLinus Torvalds 		}
9941da177e4SLinus Torvalds 	} else {
9951da177e4SLinus Torvalds 		switch (value) {
9961da177e4SLinus Torvalds 		case 0:
9971da177e4SLinus Torvalds 			slot_cmd = SETB_PCI_33MHZ;
9981da177e4SLinus Torvalds 			break;
9991da177e4SLinus Torvalds 		case 1:
10001da177e4SLinus Torvalds 			slot_cmd = SETB_PCI_66MHZ;
10011da177e4SLinus Torvalds 			break;
10021da177e4SLinus Torvalds 		case 2:
10031da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_66MHZ_PM;
10041da177e4SLinus Torvalds 			break;
10051da177e4SLinus Torvalds 		case 3:
10061da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_100MHZ_PM;
10071da177e4SLinus Torvalds 			break;
10081da177e4SLinus Torvalds 		case 4:
10091da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_133MHZ_PM;
10101da177e4SLinus Torvalds 			break;
10111da177e4SLinus Torvalds 		case 5:
10121da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_66MHZ_EM;
10131da177e4SLinus Torvalds 			break;
10141da177e4SLinus Torvalds 		case 6:
10151da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_100MHZ_EM;
10161da177e4SLinus Torvalds 			break;
10171da177e4SLinus Torvalds 		case 7:
10181da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_133MHZ_EM;
10191da177e4SLinus Torvalds 			break;
10201da177e4SLinus Torvalds 		case 8:
10211da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_66MHZ_266;
10221da177e4SLinus Torvalds 			break;
10231da177e4SLinus Torvalds 		case 0x9:
10241da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_100MHZ_266;
10251da177e4SLinus Torvalds 			break;
10261da177e4SLinus Torvalds 		case 0xa:
10271da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_133MHZ_266;
10281da177e4SLinus Torvalds 			break;
10291da177e4SLinus Torvalds 		case 0xb:
10301da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_66MHZ_533;
10311da177e4SLinus Torvalds 			break;
10321da177e4SLinus Torvalds 		case 0xc:
10331da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_100MHZ_533;
10341da177e4SLinus Torvalds 			break;
10351da177e4SLinus Torvalds 		case 0xd:
10361da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_133MHZ_533;
10371da177e4SLinus Torvalds 			break;
10381da177e4SLinus Torvalds 		default:
10391da177e4SLinus Torvalds 			slot_cmd = PCI_SPEED_UNKNOWN;
10401da177e4SLinus Torvalds 			retval = -ENODEV;
10411da177e4SLinus Torvalds 			return retval;
10421da177e4SLinus Torvalds 		}
10431da177e4SLinus Torvalds 
10441da177e4SLinus Torvalds 	}
10451da177e4SLinus Torvalds 	retval = shpc_write_cmd(slot, 0, slot_cmd);
10461da177e4SLinus Torvalds 	if (retval) {
10471da177e4SLinus Torvalds 		err("%s: Write command failed!\n", __FUNCTION__);
10481da177e4SLinus Torvalds 		return -1;
10491da177e4SLinus Torvalds 	}
10501da177e4SLinus Torvalds 
10511da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
10521da177e4SLinus Torvalds 	return retval;
10531da177e4SLinus Torvalds }
10541da177e4SLinus Torvalds 
10551da177e4SLinus Torvalds static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs)
10561da177e4SLinus Torvalds {
10571da177e4SLinus Torvalds 	struct controller *ctrl = NULL;
10581da177e4SLinus Torvalds 	struct php_ctlr_state_s *php_ctlr;
10591da177e4SLinus Torvalds 	u8 schedule_flag = 0;
10601da177e4SLinus Torvalds 	u8 temp_byte;
10611da177e4SLinus Torvalds 	u32 temp_dword, intr_loc, intr_loc2;
10621da177e4SLinus Torvalds 	int hp_slot;
10631da177e4SLinus Torvalds 
10641da177e4SLinus Torvalds 	if (!dev_id)
10651da177e4SLinus Torvalds 		return IRQ_NONE;
10661da177e4SLinus Torvalds 
10671da177e4SLinus Torvalds 	if (!shpchp_poll_mode) {
10681da177e4SLinus Torvalds 		ctrl = (struct controller *)dev_id;
10691da177e4SLinus Torvalds 		php_ctlr = ctrl->hpc_ctlr_handle;
10701da177e4SLinus Torvalds 	} else {
10711da177e4SLinus Torvalds 		php_ctlr = (struct php_ctlr_state_s *) dev_id;
10721da177e4SLinus Torvalds 		ctrl = (struct controller *)php_ctlr->callback_instance_id;
10731da177e4SLinus Torvalds 	}
10741da177e4SLinus Torvalds 
10751da177e4SLinus Torvalds 	if (!ctrl)
10761da177e4SLinus Torvalds 		return IRQ_NONE;
10771da177e4SLinus Torvalds 
10781da177e4SLinus Torvalds 	if (!php_ctlr || !php_ctlr->creg)
10791da177e4SLinus Torvalds 		return IRQ_NONE;
10801da177e4SLinus Torvalds 
10811da177e4SLinus Torvalds 	/* Check to see if it was our interrupt */
10821da177e4SLinus Torvalds 	intr_loc = readl(php_ctlr->creg + INTR_LOC);
10831da177e4SLinus Torvalds 
10841da177e4SLinus Torvalds 	if (!intr_loc)
10851da177e4SLinus Torvalds 		return IRQ_NONE;
10861da177e4SLinus Torvalds 	dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc);
10871da177e4SLinus Torvalds 
10881da177e4SLinus Torvalds 	if(!shpchp_poll_mode) {
10891da177e4SLinus Torvalds 		/* Mask Global Interrupt Mask - see implementation note on p. 139 */
10901da177e4SLinus Torvalds 		/* of SHPC spec rev 1.0*/
10911da177e4SLinus Torvalds 		temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
10921da177e4SLinus Torvalds 		temp_dword |= 0x00000001;
10931da177e4SLinus Torvalds 		writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
10941da177e4SLinus Torvalds 
10951da177e4SLinus Torvalds 		intr_loc2 = readl(php_ctlr->creg + INTR_LOC);
10961da177e4SLinus Torvalds 		dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2);
10971da177e4SLinus Torvalds 	}
10981da177e4SLinus Torvalds 
10991da177e4SLinus Torvalds 	if (intr_loc & 0x0001) {
11001da177e4SLinus Torvalds 		/*
11011da177e4SLinus Torvalds 		 * Command Complete Interrupt Pending
1102f467f618SKenji Kaneshige 		 * RO only - clear by writing 1 to the Command Completion
11031da177e4SLinus Torvalds 		 * Detect bit in Controller SERR-INT register
11041da177e4SLinus Torvalds 		 */
11051da177e4SLinus Torvalds 		temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
1106f467f618SKenji Kaneshige 		temp_dword &= 0xfffdffff;
11071da177e4SLinus Torvalds 		writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
1108bd62e271SKenji Kaneshige 		ctrl->cmd_busy = 0;
11091da177e4SLinus Torvalds 		wake_up_interruptible(&ctrl->queue);
11101da177e4SLinus Torvalds 	}
11111da177e4SLinus Torvalds 
11121da177e4SLinus Torvalds 	if ((intr_loc = (intr_loc >> 1)) == 0) {
11131da177e4SLinus Torvalds 		/* Unmask Global Interrupt Mask */
11141da177e4SLinus Torvalds 		temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
11151da177e4SLinus Torvalds 		temp_dword &= 0xfffffffe;
11161da177e4SLinus Torvalds 		writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
11171da177e4SLinus Torvalds 
11181da177e4SLinus Torvalds 		return IRQ_NONE;
11191da177e4SLinus Torvalds 	}
11201da177e4SLinus Torvalds 
11211da177e4SLinus Torvalds 	for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {
11221da177e4SLinus Torvalds 	/* To find out which slot has interrupt pending */
11231da177e4SLinus Torvalds 		if ((intr_loc >> hp_slot) & 0x01) {
11241da177e4SLinus Torvalds 			temp_dword = readl(php_ctlr->creg + SLOT1 + (4*hp_slot));
11257c8942f9Srajesh.shah@intel.com 			dbg("%s: Slot %x with intr, slot register = %x\n",
11261da177e4SLinus Torvalds 				__FUNCTION__, hp_slot, temp_dword);
11271da177e4SLinus Torvalds 			temp_byte = (temp_dword >> 16) & 0xFF;
11281da177e4SLinus Torvalds 			if ((php_ctlr->switch_change_callback) && (temp_byte & 0x08))
11291da177e4SLinus Torvalds 				schedule_flag += php_ctlr->switch_change_callback(
11301da177e4SLinus Torvalds 					hp_slot, php_ctlr->callback_instance_id);
11311da177e4SLinus Torvalds 			if ((php_ctlr->attention_button_callback) && (temp_byte & 0x04))
11321da177e4SLinus Torvalds 				schedule_flag += php_ctlr->attention_button_callback(
11331da177e4SLinus Torvalds 					hp_slot, php_ctlr->callback_instance_id);
11341da177e4SLinus Torvalds 			if ((php_ctlr->presence_change_callback) && (temp_byte & 0x01))
11351da177e4SLinus Torvalds 				schedule_flag += php_ctlr->presence_change_callback(
11361da177e4SLinus Torvalds 					hp_slot , php_ctlr->callback_instance_id);
11371da177e4SLinus Torvalds 			if ((php_ctlr->power_fault_callback) && (temp_byte & 0x12))
11381da177e4SLinus Torvalds 				schedule_flag += php_ctlr->power_fault_callback(
11391da177e4SLinus Torvalds 					hp_slot, php_ctlr->callback_instance_id);
11401da177e4SLinus Torvalds 
11411da177e4SLinus Torvalds 			/* Clear all slot events */
11421da177e4SLinus Torvalds 			temp_dword = 0xe01f3fff;
11431da177e4SLinus Torvalds 			writel(temp_dword, php_ctlr->creg + SLOT1 + (4*hp_slot));
11441da177e4SLinus Torvalds 
11451da177e4SLinus Torvalds 			intr_loc2 = readl(php_ctlr->creg + INTR_LOC);
11461da177e4SLinus Torvalds 			dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2);
11471da177e4SLinus Torvalds 		}
11481da177e4SLinus Torvalds 	}
11491da177e4SLinus Torvalds 	if (!shpchp_poll_mode) {
11501da177e4SLinus Torvalds 		/* Unmask Global Interrupt Mask */
11511da177e4SLinus Torvalds 		temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
11521da177e4SLinus Torvalds 		temp_dword &= 0xfffffffe;
11531da177e4SLinus Torvalds 		writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
11541da177e4SLinus Torvalds 	}
11551da177e4SLinus Torvalds 
11561da177e4SLinus Torvalds 	return IRQ_HANDLED;
11571da177e4SLinus Torvalds }
11581da177e4SLinus Torvalds 
11591da177e4SLinus Torvalds static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
11601da177e4SLinus Torvalds {
1161ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
11621da177e4SLinus Torvalds 	enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
11631da177e4SLinus Torvalds 	int retval = 0;
11641da177e4SLinus Torvalds 	u8 pi;
11651da177e4SLinus Torvalds 	u32 slot_avail1, slot_avail2;
11661da177e4SLinus Torvalds 
11671da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
11681da177e4SLinus Torvalds 
11691da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
11701da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
11711da177e4SLinus Torvalds 		return -1;
11721da177e4SLinus Torvalds 	}
11731da177e4SLinus Torvalds 
11741da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
11751da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
11761da177e4SLinus Torvalds 		return -1;
11771da177e4SLinus Torvalds 	}
11781da177e4SLinus Torvalds 
11791da177e4SLinus Torvalds 	pi = readb(php_ctlr->creg + PROG_INTERFACE);
11801da177e4SLinus Torvalds 	slot_avail1 = readl(php_ctlr->creg + SLOT_AVAIL1);
11811da177e4SLinus Torvalds 	slot_avail2 = readl(php_ctlr->creg + SLOT_AVAIL2);
11821da177e4SLinus Torvalds 
11831da177e4SLinus Torvalds 	if (pi == 2) {
11846558b6abSKenji Kaneshige 		if (slot_avail2 & SLOT_133MHZ_PCIX_533)
11851da177e4SLinus Torvalds 			bus_speed = PCIX_133MHZ_533;
11866558b6abSKenji Kaneshige 		else if (slot_avail2 & SLOT_100MHZ_PCIX_533)
11871da177e4SLinus Torvalds 			bus_speed = PCIX_100MHZ_533;
11886558b6abSKenji Kaneshige 		else if (slot_avail2 & SLOT_66MHZ_PCIX_533)
11891da177e4SLinus Torvalds 			bus_speed = PCIX_66MHZ_533;
11906558b6abSKenji Kaneshige 		else if (slot_avail2 & SLOT_133MHZ_PCIX_266)
11911da177e4SLinus Torvalds 			bus_speed = PCIX_133MHZ_266;
11926558b6abSKenji Kaneshige 		else if (slot_avail2 & SLOT_100MHZ_PCIX_266)
11931da177e4SLinus Torvalds 			bus_speed = PCIX_100MHZ_266;
11946558b6abSKenji Kaneshige 		else if (slot_avail2 & SLOT_66MHZ_PCIX_266)
11951da177e4SLinus Torvalds 			bus_speed = PCIX_66MHZ_266;
11966558b6abSKenji Kaneshige 		else if (slot_avail1 & SLOT_133MHZ_PCIX)
11971da177e4SLinus Torvalds 			bus_speed = PCIX_133MHZ;
11986558b6abSKenji Kaneshige 		else if (slot_avail1 & SLOT_100MHZ_PCIX)
11991da177e4SLinus Torvalds 			bus_speed = PCIX_100MHZ;
12006558b6abSKenji Kaneshige 		else if (slot_avail1 & SLOT_66MHZ_PCIX)
12011da177e4SLinus Torvalds 			bus_speed = PCIX_66MHZ;
12026558b6abSKenji Kaneshige 		else if (slot_avail2 & SLOT_66MHZ)
12031da177e4SLinus Torvalds 			bus_speed = PCI_66MHZ;
12046558b6abSKenji Kaneshige 		else if (slot_avail1 & SLOT_33MHZ)
12051da177e4SLinus Torvalds 			bus_speed = PCI_33MHZ;
12061da177e4SLinus Torvalds 		else bus_speed = PCI_SPEED_UNKNOWN;
12071da177e4SLinus Torvalds 	} else {
12086558b6abSKenji Kaneshige 		if (slot_avail1 & SLOT_133MHZ_PCIX)
12091da177e4SLinus Torvalds 			bus_speed = PCIX_133MHZ;
12106558b6abSKenji Kaneshige 		else if (slot_avail1 & SLOT_100MHZ_PCIX)
12111da177e4SLinus Torvalds 			bus_speed = PCIX_100MHZ;
12126558b6abSKenji Kaneshige 		else if (slot_avail1 & SLOT_66MHZ_PCIX)
12131da177e4SLinus Torvalds 			bus_speed = PCIX_66MHZ;
12146558b6abSKenji Kaneshige 		else if (slot_avail2 & SLOT_66MHZ)
12151da177e4SLinus Torvalds 			bus_speed = PCI_66MHZ;
12166558b6abSKenji Kaneshige 		else if (slot_avail1 & SLOT_33MHZ)
12171da177e4SLinus Torvalds 			bus_speed = PCI_33MHZ;
12181da177e4SLinus Torvalds 		else bus_speed = PCI_SPEED_UNKNOWN;
12191da177e4SLinus Torvalds 	}
12201da177e4SLinus Torvalds 
12211da177e4SLinus Torvalds 	*value = bus_speed;
12221da177e4SLinus Torvalds 	dbg("Max bus speed = %d\n", bus_speed);
12231da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
12241da177e4SLinus Torvalds 	return retval;
12251da177e4SLinus Torvalds }
12261da177e4SLinus Torvalds 
12271da177e4SLinus Torvalds static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
12281da177e4SLinus Torvalds {
1229ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
12301da177e4SLinus Torvalds 	enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
12311da177e4SLinus Torvalds 	u16 sec_bus_status;
12321da177e4SLinus Torvalds 	int retval = 0;
12331da177e4SLinus Torvalds 	u8 pi;
12341da177e4SLinus Torvalds 
12351da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
12361da177e4SLinus Torvalds 
12371da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
12381da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
12391da177e4SLinus Torvalds 		return -1;
12401da177e4SLinus Torvalds 	}
12411da177e4SLinus Torvalds 
12421da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
12431da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
12441da177e4SLinus Torvalds 		return -1;
12451da177e4SLinus Torvalds 	}
12461da177e4SLinus Torvalds 
12471da177e4SLinus Torvalds 	pi = readb(php_ctlr->creg + PROG_INTERFACE);
12481da177e4SLinus Torvalds 	sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG);
12491da177e4SLinus Torvalds 
12501da177e4SLinus Torvalds 	if (pi == 2) {
12511da177e4SLinus Torvalds 		switch (sec_bus_status & 0x000f) {
12521da177e4SLinus Torvalds 		case 0:
12531da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_33MHz;
12541da177e4SLinus Torvalds 			break;
12551da177e4SLinus Torvalds 		case 1:
12561da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_66MHz;
12571da177e4SLinus Torvalds 			break;
12581da177e4SLinus Torvalds 		case 2:
12591da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_66MHz_PCIX;
12601da177e4SLinus Torvalds 			break;
12611da177e4SLinus Torvalds 		case 3:
12621da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_100MHz_PCIX;
12631da177e4SLinus Torvalds 			break;
12641da177e4SLinus Torvalds 		case 4:
12651da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_133MHz_PCIX;
12661da177e4SLinus Torvalds 			break;
12671da177e4SLinus Torvalds 		case 5:
12681da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_66MHz_PCIX_ECC;
12691da177e4SLinus Torvalds 			break;
12701da177e4SLinus Torvalds 		case 6:
12711da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_100MHz_PCIX_ECC;
12721da177e4SLinus Torvalds 			break;
12731da177e4SLinus Torvalds 		case 7:
12741da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_133MHz_PCIX_ECC;
12751da177e4SLinus Torvalds 			break;
12761da177e4SLinus Torvalds 		case 8:
12771da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_66MHz_PCIX_266;
12781da177e4SLinus Torvalds 			break;
12791da177e4SLinus Torvalds 		case 9:
12801da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_100MHz_PCIX_266;
12811da177e4SLinus Torvalds 			break;
12821da177e4SLinus Torvalds 		case 0xa:
12831da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_133MHz_PCIX_266;
12841da177e4SLinus Torvalds 			break;
12851da177e4SLinus Torvalds 		case 0xb:
12861da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_66MHz_PCIX_533;
12871da177e4SLinus Torvalds 			break;
12881da177e4SLinus Torvalds 		case 0xc:
12891da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_100MHz_PCIX_533;
12901da177e4SLinus Torvalds 			break;
12911da177e4SLinus Torvalds 		case 0xd:
12921da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_133MHz_PCIX_533;
12931da177e4SLinus Torvalds 			break;
12941da177e4SLinus Torvalds 		case 0xe:
12951da177e4SLinus Torvalds 		case 0xf:
12961da177e4SLinus Torvalds 		default:
12971da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_UNKNOWN;
12981da177e4SLinus Torvalds 			break;
12991da177e4SLinus Torvalds 		}
13001da177e4SLinus Torvalds 	} else {
13011da177e4SLinus Torvalds 		/* In the case where pi is undefined, default it to 1 */
13021da177e4SLinus Torvalds 		switch (sec_bus_status & 0x0007) {
13031da177e4SLinus Torvalds 		case 0:
13041da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_33MHz;
13051da177e4SLinus Torvalds 			break;
13061da177e4SLinus Torvalds 		case 1:
13071da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_66MHz;
13081da177e4SLinus Torvalds 			break;
13091da177e4SLinus Torvalds 		case 2:
13101da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_66MHz_PCIX;
13111da177e4SLinus Torvalds 			break;
13121da177e4SLinus Torvalds 		case 3:
13131da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_100MHz_PCIX;
13141da177e4SLinus Torvalds 			break;
13151da177e4SLinus Torvalds 		case 4:
13161da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_133MHz_PCIX;
13171da177e4SLinus Torvalds 			break;
13181da177e4SLinus Torvalds 		case 5:
13191da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_UNKNOWN;		/*	Reserved */
13201da177e4SLinus Torvalds 			break;
13211da177e4SLinus Torvalds 		case 6:
13221da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_UNKNOWN;		/*	Reserved */
13231da177e4SLinus Torvalds 			break;
13241da177e4SLinus Torvalds 		case 7:
13251da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_UNKNOWN;		/*	Reserved */
13261da177e4SLinus Torvalds 			break;
13271da177e4SLinus Torvalds 		default:
13281da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_UNKNOWN;
13291da177e4SLinus Torvalds 			break;
13301da177e4SLinus Torvalds 		}
13311da177e4SLinus Torvalds 	}
13321da177e4SLinus Torvalds 
13331da177e4SLinus Torvalds 	*value = bus_speed;
13341da177e4SLinus Torvalds 	dbg("Current bus speed = %d\n", bus_speed);
13351da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
13361da177e4SLinus Torvalds 	return retval;
13371da177e4SLinus Torvalds }
13381da177e4SLinus Torvalds 
13391da177e4SLinus Torvalds static struct hpc_ops shpchp_hpc_ops = {
13401da177e4SLinus Torvalds 	.power_on_slot			= hpc_power_on_slot,
13411da177e4SLinus Torvalds 	.slot_enable			= hpc_slot_enable,
13421da177e4SLinus Torvalds 	.slot_disable			= hpc_slot_disable,
13431da177e4SLinus Torvalds 	.set_bus_speed_mode		= hpc_set_bus_speed_mode,
13441da177e4SLinus Torvalds 	.set_attention_status	= hpc_set_attention_status,
13451da177e4SLinus Torvalds 	.get_power_status		= hpc_get_power_status,
13461da177e4SLinus Torvalds 	.get_attention_status	= hpc_get_attention_status,
13471da177e4SLinus Torvalds 	.get_latch_status		= hpc_get_latch_status,
13481da177e4SLinus Torvalds 	.get_adapter_status		= hpc_get_adapter_status,
13491da177e4SLinus Torvalds 
13501da177e4SLinus Torvalds 	.get_max_bus_speed		= hpc_get_max_bus_speed,
13511da177e4SLinus Torvalds 	.get_cur_bus_speed		= hpc_get_cur_bus_speed,
13521da177e4SLinus Torvalds 	.get_adapter_speed		= hpc_get_adapter_speed,
13531da177e4SLinus Torvalds 	.get_mode1_ECC_cap		= hpc_get_mode1_ECC_cap,
13541da177e4SLinus Torvalds 	.get_prog_int			= hpc_get_prog_int,
13551da177e4SLinus Torvalds 
13561da177e4SLinus Torvalds 	.query_power_fault		= hpc_query_power_fault,
13571da177e4SLinus Torvalds 	.green_led_on			= hpc_set_green_led_on,
13581da177e4SLinus Torvalds 	.green_led_off			= hpc_set_green_led_off,
13591da177e4SLinus Torvalds 	.green_led_blink		= hpc_set_green_led_blink,
13601da177e4SLinus Torvalds 
13611da177e4SLinus Torvalds 	.release_ctlr			= hpc_release_ctlr,
13621da177e4SLinus Torvalds };
13631da177e4SLinus Torvalds 
13640455986cSKenji Kaneshige inline static int shpc_indirect_creg_read(struct controller *ctrl, int index,
13650455986cSKenji Kaneshige 					  u32 *value)
13660455986cSKenji Kaneshige {
13670455986cSKenji Kaneshige 	int rc;
13680455986cSKenji Kaneshige 	u32 cap_offset = ctrl->cap_offset;
13690455986cSKenji Kaneshige 	struct pci_dev *pdev = ctrl->pci_dev;
13700455986cSKenji Kaneshige 
13710455986cSKenji Kaneshige 	rc = pci_write_config_byte(pdev, cap_offset + DWORD_SELECT, index);
13720455986cSKenji Kaneshige 	if (rc)
13730455986cSKenji Kaneshige 		return rc;
13740455986cSKenji Kaneshige 	return pci_read_config_dword(pdev, cap_offset + DWORD_DATA, value);
13750455986cSKenji Kaneshige }
13760455986cSKenji Kaneshige 
1377ee138334Srajesh.shah@intel.com int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
13781da177e4SLinus Torvalds {
13791da177e4SLinus Torvalds 	struct php_ctlr_state_s *php_ctlr, *p;
13801da177e4SLinus Torvalds 	void *instance_id = ctrl;
13810455986cSKenji Kaneshige 	int rc, num_slots = 0;
13821da177e4SLinus Torvalds 	u8 hp_slot;
13831da177e4SLinus Torvalds 	static int first = 1;
13840455986cSKenji Kaneshige 	u32 shpc_base_offset;
13851da177e4SLinus Torvalds 	u32 tempdword, slot_reg;
13861da177e4SLinus Torvalds 	u8 i;
13871da177e4SLinus Torvalds 
13881da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
13891da177e4SLinus Torvalds 
13900455986cSKenji Kaneshige 	ctrl->pci_dev = pdev;  /* pci_dev of the P2P bridge */
13910455986cSKenji Kaneshige 
13921da177e4SLinus Torvalds 	spin_lock_init(&list_lock);
139357c95c0dSKenji Kaneshige 	php_ctlr = kzalloc(sizeof(*php_ctlr), GFP_KERNEL);
13941da177e4SLinus Torvalds 
13951da177e4SLinus Torvalds 	if (!php_ctlr) {	/* allocate controller state data */
13961da177e4SLinus Torvalds 		err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
13971da177e4SLinus Torvalds 		goto abort;
13981da177e4SLinus Torvalds 	}
13991da177e4SLinus Torvalds 
14001da177e4SLinus Torvalds 	php_ctlr->pci_dev = pdev;	/* save pci_dev in context */
14011da177e4SLinus Torvalds 
1402ee138334Srajesh.shah@intel.com 	if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device ==
1403ee138334Srajesh.shah@intel.com 				PCI_DEVICE_ID_AMD_GOLAM_7450)) {
14040455986cSKenji Kaneshige 		/* amd shpc driver doesn't use Base Offset; assume 0 */
14050455986cSKenji Kaneshige 		ctrl->mmio_base = pci_resource_start(pdev, 0);
14060455986cSKenji Kaneshige 		ctrl->mmio_size = pci_resource_len(pdev, 0);
14071da177e4SLinus Torvalds 	} else {
14080455986cSKenji Kaneshige 		ctrl->cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC);
14090455986cSKenji Kaneshige 		if (!ctrl->cap_offset) {
14100455986cSKenji Kaneshige 			err("%s : cap_offset == 0\n", __FUNCTION__);
14111da177e4SLinus Torvalds 			goto abort_free_ctlr;
14121da177e4SLinus Torvalds 		}
14130455986cSKenji Kaneshige 		dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset);
14141da177e4SLinus Torvalds 
14150455986cSKenji Kaneshige 		rc = shpc_indirect_creg_read(ctrl, 0, &shpc_base_offset);
14161da177e4SLinus Torvalds 		if (rc) {
14170455986cSKenji Kaneshige 			err("%s: cannot read base_offset\n", __FUNCTION__);
14181da177e4SLinus Torvalds 			goto abort_free_ctlr;
14191da177e4SLinus Torvalds 		}
14201da177e4SLinus Torvalds 
14210455986cSKenji Kaneshige 		rc = shpc_indirect_creg_read(ctrl, 3, &tempdword);
14221da177e4SLinus Torvalds 		if (rc) {
14230455986cSKenji Kaneshige 			err("%s: cannot read slot config\n", __FUNCTION__);
14241da177e4SLinus Torvalds 			goto abort_free_ctlr;
14251da177e4SLinus Torvalds 		}
14260455986cSKenji Kaneshige 		num_slots = tempdword & SLOT_NUM;
14270455986cSKenji Kaneshige 		dbg("%s: num_slots (indirect) %x\n", __FUNCTION__, num_slots);
14281da177e4SLinus Torvalds 
14290455986cSKenji Kaneshige 		for (i = 0; i < 9 + num_slots; i++) {
14300455986cSKenji Kaneshige 			rc = shpc_indirect_creg_read(ctrl, i, &tempdword);
14311da177e4SLinus Torvalds 			if (rc) {
14320455986cSKenji Kaneshige 				err("%s: cannot read creg (index = %d)\n",
14330455986cSKenji Kaneshige 				    __FUNCTION__, i);
14341da177e4SLinus Torvalds 				goto abort_free_ctlr;
14351da177e4SLinus Torvalds 			}
14367c8942f9Srajesh.shah@intel.com 			dbg("%s: offset %d: value %x\n", __FUNCTION__,i,
14377c8942f9Srajesh.shah@intel.com 					tempdword);
14381da177e4SLinus Torvalds 		}
14390455986cSKenji Kaneshige 
14400455986cSKenji Kaneshige 		ctrl->mmio_base =
14410455986cSKenji Kaneshige 			pci_resource_start(pdev, 0) + shpc_base_offset;
14420455986cSKenji Kaneshige 		ctrl->mmio_size = 0x24 + 0x4 * num_slots;
14431da177e4SLinus Torvalds 	}
14441da177e4SLinus Torvalds 
14451da177e4SLinus Torvalds 	if (first) {
14461da177e4SLinus Torvalds 		spin_lock_init(&hpc_event_lock);
14471da177e4SLinus Torvalds 		first = 0;
14481da177e4SLinus Torvalds 	}
14491da177e4SLinus Torvalds 
14501da177e4SLinus Torvalds 	info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor,
14511da177e4SLinus Torvalds 		pdev->subsystem_device);
14521da177e4SLinus Torvalds 
14531da177e4SLinus Torvalds 	if (pci_enable_device(pdev))
14541da177e4SLinus Torvalds 		goto abort_free_ctlr;
14551da177e4SLinus Torvalds 
14560455986cSKenji Kaneshige 	if (!request_mem_region(ctrl->mmio_base, ctrl->mmio_size, MY_NAME)) {
14571da177e4SLinus Torvalds 		err("%s: cannot reserve MMIO region\n", __FUNCTION__);
14581da177e4SLinus Torvalds 		goto abort_free_ctlr;
14591da177e4SLinus Torvalds 	}
14601da177e4SLinus Torvalds 
14610455986cSKenji Kaneshige 	php_ctlr->creg = ioremap(ctrl->mmio_base, ctrl->mmio_size);
14621da177e4SLinus Torvalds 	if (!php_ctlr->creg) {
14630455986cSKenji Kaneshige 		err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__,
14640455986cSKenji Kaneshige 		    ctrl->mmio_size, ctrl->mmio_base);
14650455986cSKenji Kaneshige 		release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
14661da177e4SLinus Torvalds 		goto abort_free_ctlr;
14671da177e4SLinus Torvalds 	}
14681da177e4SLinus Torvalds 	dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg);
14691da177e4SLinus Torvalds 
14706aa4cdd0SIngo Molnar 	mutex_init(&ctrl->crit_sect);
1471d29aaddaSKenji Kaneshige 	mutex_init(&ctrl->cmd_lock);
1472d29aaddaSKenji Kaneshige 
14731da177e4SLinus Torvalds 	/* Setup wait queue */
14741da177e4SLinus Torvalds 	init_waitqueue_head(&ctrl->queue);
14751da177e4SLinus Torvalds 
14761da177e4SLinus Torvalds 	/* Find the IRQ */
14771da177e4SLinus Torvalds 	php_ctlr->irq = pdev->irq;
1478ee138334Srajesh.shah@intel.com 	php_ctlr->attention_button_callback = shpchp_handle_attention_button,
1479ee138334Srajesh.shah@intel.com 	php_ctlr->switch_change_callback = shpchp_handle_switch_change;
1480ee138334Srajesh.shah@intel.com 	php_ctlr->presence_change_callback = shpchp_handle_presence_change;
1481ee138334Srajesh.shah@intel.com 	php_ctlr->power_fault_callback = shpchp_handle_power_fault;
14821da177e4SLinus Torvalds 	php_ctlr->callback_instance_id = instance_id;
14831da177e4SLinus Torvalds 
14841da177e4SLinus Torvalds 	/* Return PCI Controller Info */
14851da177e4SLinus Torvalds 	php_ctlr->slot_device_offset = (readl(php_ctlr->creg + SLOT_CONFIG) & FIRST_DEV_NUM ) >> 8;
14861da177e4SLinus Torvalds 	php_ctlr->num_slots = readl(php_ctlr->creg + SLOT_CONFIG) & SLOT_NUM;
14871da177e4SLinus Torvalds 	dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset);
14881da177e4SLinus Torvalds 	dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots);
14891da177e4SLinus Torvalds 
14901da177e4SLinus Torvalds 	/* Mask Global Interrupt Mask & Command Complete Interrupt Mask */
14911da177e4SLinus Torvalds 	tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
14921da177e4SLinus Torvalds 	dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
14931da177e4SLinus Torvalds 	tempdword = 0x0003000f;
14941da177e4SLinus Torvalds 	writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE);
14951da177e4SLinus Torvalds 	tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
14961da177e4SLinus Torvalds 	dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
14971da177e4SLinus Torvalds 
14981da177e4SLinus Torvalds 	/* Mask the MRL sensor SERR Mask of individual slot in
14991da177e4SLinus Torvalds 	 * Slot SERR-INT Mask & clear all the existing event if any
15001da177e4SLinus Torvalds 	 */
15011da177e4SLinus Torvalds 	for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) {
15021da177e4SLinus Torvalds 		slot_reg = readl(php_ctlr->creg + SLOT1 + 4*hp_slot );
15031da177e4SLinus Torvalds 		dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
15041da177e4SLinus Torvalds 			hp_slot, slot_reg);
15051da177e4SLinus Torvalds 		tempdword = 0xffff3fff;
15061da177e4SLinus Torvalds 		writel(tempdword, php_ctlr->creg + SLOT1 + (4*hp_slot));
15071da177e4SLinus Torvalds 	}
15081da177e4SLinus Torvalds 
15091da177e4SLinus Torvalds 	if (shpchp_poll_mode)  {/* Install interrupt polling code */
15101da177e4SLinus Torvalds 		/* Install and start the interrupt polling timer */
15111da177e4SLinus Torvalds 		init_timer(&php_ctlr->int_poll_timer);
15121da177e4SLinus Torvalds 		start_int_poll_timer( php_ctlr, 10 );   /* start with 10 second delay */
15131da177e4SLinus Torvalds 	} else {
15141da177e4SLinus Torvalds 		/* Installs the interrupt handler */
15151da177e4SLinus Torvalds 		rc = pci_enable_msi(pdev);
15161da177e4SLinus Torvalds 		if (rc) {
15171da177e4SLinus Torvalds 			info("Can't get msi for the hotplug controller\n");
15181da177e4SLinus Torvalds 			info("Use INTx for the hotplug controller\n");
15191da177e4SLinus Torvalds 		} else
15201da177e4SLinus Torvalds 			php_ctlr->irq = pdev->irq;
15211da177e4SLinus Torvalds 
15221da177e4SLinus Torvalds 		rc = request_irq(php_ctlr->irq, shpc_isr, SA_SHIRQ, MY_NAME, (void *) ctrl);
15231da177e4SLinus Torvalds 		dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
15241da177e4SLinus Torvalds 		if (rc) {
15251da177e4SLinus Torvalds 			err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
15261da177e4SLinus Torvalds 			goto abort_free_ctlr;
15271da177e4SLinus Torvalds 		}
15281da177e4SLinus Torvalds 	}
15297c8942f9Srajesh.shah@intel.com 	dbg("%s: HPC at b:d:f:irq=0x%x:%x:%x:%x\n", __FUNCTION__,
15307c8942f9Srajesh.shah@intel.com 			pdev->bus->number, PCI_SLOT(pdev->devfn),
15317c8942f9Srajesh.shah@intel.com 			PCI_FUNC(pdev->devfn), pdev->irq);
1532424600f9Srajesh.shah@intel.com 	get_hp_hw_control_from_firmware(pdev);
15331da177e4SLinus Torvalds 
15341da177e4SLinus Torvalds 	/*  Add this HPC instance into the HPC list */
15351da177e4SLinus Torvalds 	spin_lock(&list_lock);
15361da177e4SLinus Torvalds 	if (php_ctlr_list_head == 0) {
15371da177e4SLinus Torvalds 		php_ctlr_list_head = php_ctlr;
15381da177e4SLinus Torvalds 		p = php_ctlr_list_head;
15391da177e4SLinus Torvalds 		p->pnext = NULL;
15401da177e4SLinus Torvalds 	} else {
15411da177e4SLinus Torvalds 		p = php_ctlr_list_head;
15421da177e4SLinus Torvalds 
15431da177e4SLinus Torvalds 		while (p->pnext)
15441da177e4SLinus Torvalds 			p = p->pnext;
15451da177e4SLinus Torvalds 
15461da177e4SLinus Torvalds 		p->pnext = php_ctlr;
15471da177e4SLinus Torvalds 	}
15481da177e4SLinus Torvalds 	spin_unlock(&list_lock);
15491da177e4SLinus Torvalds 
15501da177e4SLinus Torvalds 
15511da177e4SLinus Torvalds 	ctlr_seq_num++;
15521da177e4SLinus Torvalds 	ctrl->hpc_ctlr_handle = php_ctlr;
15531da177e4SLinus Torvalds 	ctrl->hpc_ops = &shpchp_hpc_ops;
15541da177e4SLinus Torvalds 
15551da177e4SLinus Torvalds 	for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) {
15561da177e4SLinus Torvalds 		slot_reg = readl(php_ctlr->creg + SLOT1 + 4*hp_slot );
15571da177e4SLinus Torvalds 		dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
15581da177e4SLinus Torvalds 			hp_slot, slot_reg);
15591da177e4SLinus Torvalds 		tempdword = 0xe01f3fff;
15601da177e4SLinus Torvalds 		writel(tempdword, php_ctlr->creg + SLOT1 + (4*hp_slot));
15611da177e4SLinus Torvalds 	}
15621da177e4SLinus Torvalds 	if (!shpchp_poll_mode) {
15631da177e4SLinus Torvalds 		/* Unmask all general input interrupts and SERR */
15641da177e4SLinus Torvalds 		tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
15651da177e4SLinus Torvalds 		tempdword = 0x0000000a;
15661da177e4SLinus Torvalds 		writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE);
15671da177e4SLinus Torvalds 		tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
15681da177e4SLinus Torvalds 		dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
15691da177e4SLinus Torvalds 	}
15701da177e4SLinus Torvalds 
15711da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
15721da177e4SLinus Torvalds 	return 0;
15731da177e4SLinus Torvalds 
15741da177e4SLinus Torvalds 	/* We end up here for the many possible ways to fail this API.  */
15751da177e4SLinus Torvalds abort_free_ctlr:
15761da177e4SLinus Torvalds 	kfree(php_ctlr);
15771da177e4SLinus Torvalds abort:
15781da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
15791da177e4SLinus Torvalds 	return -1;
15801da177e4SLinus Torvalds }
1581