xref: /openbmc/linux/drivers/pci/hotplug/shpchp_hpc.c (revision 87d6c559)
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);
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds /* This is the interrupt polling timeout function. */
2361da177e4SLinus Torvalds static void int_poll_timeout(unsigned long lphp_ctlr)
2371da177e4SLinus Torvalds {
2381da177e4SLinus Torvalds     struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr;
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds     DBG_ENTER_ROUTINE
2411da177e4SLinus Torvalds 
2421da177e4SLinus Torvalds     if ( !php_ctlr ) {
2431da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
2441da177e4SLinus Torvalds 		return;
2451da177e4SLinus Torvalds     }
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds     /* Poll for interrupt events.  regs == NULL => polling */
2481da177e4SLinus Torvalds     shpc_isr( 0, (void *)php_ctlr, NULL );
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds     init_timer(&php_ctlr->int_poll_timer);
2511da177e4SLinus Torvalds 	if (!shpchp_poll_time)
2521da177e4SLinus Torvalds 		shpchp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds     start_int_poll_timer(php_ctlr, shpchp_poll_time);
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds 	return;
2571da177e4SLinus Torvalds }
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds /* This function starts the interrupt polling timer. */
2601da177e4SLinus Torvalds static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
2611da177e4SLinus Torvalds {
2621da177e4SLinus Torvalds     if (!php_ctlr) {
2631da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
2641da177e4SLinus Torvalds 		return;
2651da177e4SLinus Torvalds 	}
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds     if ( ( seconds <= 0 ) || ( seconds > 60 ) )
2681da177e4SLinus Torvalds         seconds = 2;            /* Clamp to sane value */
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds     php_ctlr->int_poll_timer.function = &int_poll_timeout;
2711da177e4SLinus Torvalds     php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr;    /* Instance data */
2721da177e4SLinus Torvalds     php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ;
2731da177e4SLinus Torvalds     add_timer(&php_ctlr->int_poll_timer);
2741da177e4SLinus Torvalds 
2751da177e4SLinus Torvalds 	return;
2761da177e4SLinus Torvalds }
2771da177e4SLinus Torvalds 
2781da177e4SLinus Torvalds static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
2791da177e4SLinus Torvalds {
280ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
2811da177e4SLinus Torvalds 	u16 cmd_status;
2821da177e4SLinus Torvalds 	int retval = 0;
2831da177e4SLinus Torvalds 	u16 temp_word;
2841da177e4SLinus Torvalds 	int i;
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
2871da177e4SLinus Torvalds 
2881da177e4SLinus Torvalds 	if (!php_ctlr) {
2891da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
2901da177e4SLinus Torvalds 		return -1;
2911da177e4SLinus Torvalds 	}
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds 	for (i = 0; i < 10; i++) {
2941da177e4SLinus Torvalds 		cmd_status = readw(php_ctlr->creg + CMD_STATUS);
2951da177e4SLinus Torvalds 
2961da177e4SLinus Torvalds 		if (!(cmd_status & 0x1))
2971da177e4SLinus Torvalds 			break;
2981da177e4SLinus Torvalds 		/*  Check every 0.1 sec for a total of 1 sec*/
2991da177e4SLinus Torvalds 		msleep(100);
3001da177e4SLinus Torvalds 	}
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds 	cmd_status = readw(php_ctlr->creg + CMD_STATUS);
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds 	if (cmd_status & 0x1) {
3051da177e4SLinus Torvalds 		/* After 1 sec and and the controller is still busy */
3061da177e4SLinus Torvalds 		err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__);
3071da177e4SLinus Torvalds 		return -1;
3081da177e4SLinus Torvalds 	}
3091da177e4SLinus Torvalds 
3101da177e4SLinus Torvalds 	++t_slot;
3111da177e4SLinus Torvalds 	temp_word =  (t_slot << 8) | (cmd & 0xFF);
3121da177e4SLinus Torvalds 	dbg("%s: t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd);
3131da177e4SLinus Torvalds 
3141da177e4SLinus Torvalds 	/* To make sure the Controller Busy bit is 0 before we send out the
3151da177e4SLinus Torvalds 	 * command.
3161da177e4SLinus Torvalds 	 */
3171da177e4SLinus Torvalds 	writew(temp_word, php_ctlr->creg + CMD);
3181da177e4SLinus Torvalds 
3191da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
3201da177e4SLinus Torvalds 	return retval;
3211da177e4SLinus Torvalds }
3221da177e4SLinus Torvalds 
3231da177e4SLinus Torvalds static int hpc_check_cmd_status(struct controller *ctrl)
3241da177e4SLinus Torvalds {
325ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
3261da177e4SLinus Torvalds 	u16 cmd_status;
3271da177e4SLinus Torvalds 	int retval = 0;
3281da177e4SLinus Torvalds 
3291da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
3301da177e4SLinus Torvalds 
3311da177e4SLinus Torvalds 	if (!ctrl->hpc_ctlr_handle) {
3321da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
3331da177e4SLinus Torvalds 		return -1;
3341da177e4SLinus Torvalds 	}
3351da177e4SLinus Torvalds 
3361da177e4SLinus Torvalds 	cmd_status = readw(php_ctlr->creg + CMD_STATUS) & 0x000F;
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds 	switch (cmd_status >> 1) {
3391da177e4SLinus Torvalds 	case 0:
3401da177e4SLinus Torvalds 		retval = 0;
3411da177e4SLinus Torvalds 		break;
3421da177e4SLinus Torvalds 	case 1:
3431da177e4SLinus Torvalds 		retval = SWITCH_OPEN;
3441da177e4SLinus Torvalds 		err("%s: Switch opened!\n", __FUNCTION__);
3451da177e4SLinus Torvalds 		break;
3461da177e4SLinus Torvalds 	case 2:
3471da177e4SLinus Torvalds 		retval = INVALID_CMD;
3481da177e4SLinus Torvalds 		err("%s: Invalid HPC command!\n", __FUNCTION__);
3491da177e4SLinus Torvalds 		break;
3501da177e4SLinus Torvalds 	case 4:
3511da177e4SLinus Torvalds 		retval = INVALID_SPEED_MODE;
3521da177e4SLinus Torvalds 		err("%s: Invalid bus speed/mode!\n", __FUNCTION__);
3531da177e4SLinus Torvalds 		break;
3541da177e4SLinus Torvalds 	default:
3551da177e4SLinus Torvalds 		retval = cmd_status;
3561da177e4SLinus Torvalds 	}
3571da177e4SLinus Torvalds 
3581da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
3591da177e4SLinus Torvalds 	return retval;
3601da177e4SLinus Torvalds }
3611da177e4SLinus Torvalds 
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds static int hpc_get_attention_status(struct slot *slot, u8 *status)
3641da177e4SLinus Torvalds {
365ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
3661da177e4SLinus Torvalds 	u32 slot_reg;
3671da177e4SLinus Torvalds 	u16 slot_status;
3681da177e4SLinus Torvalds 	u8 atten_led_state;
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
3711da177e4SLinus Torvalds 
3721da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
3731da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
3741da177e4SLinus Torvalds 		return -1;
3751da177e4SLinus Torvalds 	}
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds 	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
3781da177e4SLinus Torvalds 	slot_status = (u16) slot_reg;
3791da177e4SLinus Torvalds 	atten_led_state = (slot_status & 0x0030) >> 4;
3801da177e4SLinus Torvalds 
3811da177e4SLinus Torvalds 	switch (atten_led_state) {
3821da177e4SLinus Torvalds 	case 0:
3831da177e4SLinus Torvalds 		*status = 0xFF;	/* Reserved */
3841da177e4SLinus Torvalds 		break;
3851da177e4SLinus Torvalds 	case 1:
3861da177e4SLinus Torvalds 		*status = 1;	/* On */
3871da177e4SLinus Torvalds 		break;
3881da177e4SLinus Torvalds 	case 2:
3891da177e4SLinus Torvalds 		*status = 2;	/* Blink */
3901da177e4SLinus Torvalds 		break;
3911da177e4SLinus Torvalds 	case 3:
3921da177e4SLinus Torvalds 		*status = 0;	/* Off */
3931da177e4SLinus Torvalds 		break;
3941da177e4SLinus Torvalds 	default:
3951da177e4SLinus Torvalds 		*status = 0xFF;
3961da177e4SLinus Torvalds 		break;
3971da177e4SLinus Torvalds 	}
3981da177e4SLinus Torvalds 
3991da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
4001da177e4SLinus Torvalds 	return 0;
4011da177e4SLinus Torvalds }
4021da177e4SLinus Torvalds 
4031da177e4SLinus Torvalds static int hpc_get_power_status(struct slot * slot, u8 *status)
4041da177e4SLinus Torvalds {
405ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
4061da177e4SLinus Torvalds 	u32 slot_reg;
4071da177e4SLinus Torvalds 	u16 slot_status;
4081da177e4SLinus Torvalds 	u8 slot_state;
4091da177e4SLinus Torvalds 	int	retval = 0;
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 	slot_state = (slot_status & 0x0003);
4211da177e4SLinus Torvalds 
4221da177e4SLinus Torvalds 	switch (slot_state) {
4231da177e4SLinus Torvalds 	case 0:
4241da177e4SLinus Torvalds 		*status = 0xFF;
4251da177e4SLinus Torvalds 		break;
4261da177e4SLinus Torvalds 	case 1:
4271da177e4SLinus Torvalds 		*status = 2;	/* Powered only */
4281da177e4SLinus Torvalds 		break;
4291da177e4SLinus Torvalds 	case 2:
4301da177e4SLinus Torvalds 		*status = 1;	/* Enabled */
4311da177e4SLinus Torvalds 		break;
4321da177e4SLinus Torvalds 	case 3:
4331da177e4SLinus Torvalds 		*status = 0;	/* Disabled */
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 retval;
4421da177e4SLinus Torvalds }
4431da177e4SLinus Torvalds 
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds static int hpc_get_latch_status(struct slot *slot, u8 *status)
4461da177e4SLinus Torvalds {
447ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
4481da177e4SLinus Torvalds 	u32 slot_reg;
4491da177e4SLinus Torvalds 	u16 slot_status;
4501da177e4SLinus Torvalds 
4511da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
4521da177e4SLinus Torvalds 
4531da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
4541da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
4551da177e4SLinus Torvalds 		return -1;
4561da177e4SLinus Torvalds 	}
4571da177e4SLinus Torvalds 
4581da177e4SLinus Torvalds 	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
4591da177e4SLinus Torvalds 	slot_status = (u16)slot_reg;
4601da177e4SLinus Torvalds 
4611da177e4SLinus Torvalds 	*status = ((slot_status & 0x0100) == 0) ? 0 : 1;   /* 0 -> close; 1 -> open */
4621da177e4SLinus Torvalds 
4631da177e4SLinus Torvalds 
4641da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
4651da177e4SLinus Torvalds 	return 0;
4661da177e4SLinus Torvalds }
4671da177e4SLinus Torvalds 
4681da177e4SLinus Torvalds static int hpc_get_adapter_status(struct slot *slot, u8 *status)
4691da177e4SLinus Torvalds {
470ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
4711da177e4SLinus Torvalds 	u32 slot_reg;
4721da177e4SLinus Torvalds 	u16 slot_status;
4731da177e4SLinus Torvalds 	u8 card_state;
4741da177e4SLinus Torvalds 
4751da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
4761da177e4SLinus Torvalds 
4771da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
4781da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
4791da177e4SLinus Torvalds 		return -1;
4801da177e4SLinus Torvalds 	}
4811da177e4SLinus Torvalds 
4821da177e4SLinus Torvalds 	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
4831da177e4SLinus Torvalds 	slot_status = (u16)slot_reg;
4841da177e4SLinus Torvalds 	card_state = (u8)((slot_status & 0x0C00) >> 10);
4851da177e4SLinus Torvalds 	*status = (card_state != 0x3) ? 1 : 0;
4861da177e4SLinus Torvalds 
4871da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
4881da177e4SLinus Torvalds 	return 0;
4891da177e4SLinus Torvalds }
4901da177e4SLinus Torvalds 
4911da177e4SLinus Torvalds static int hpc_get_prog_int(struct slot *slot, u8 *prog_int)
4921da177e4SLinus Torvalds {
493ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
4941da177e4SLinus Torvalds 
4951da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
4961da177e4SLinus Torvalds 
4971da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
4981da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
4991da177e4SLinus Torvalds 		return -1;
5001da177e4SLinus Torvalds 	}
5011da177e4SLinus Torvalds 
5021da177e4SLinus Torvalds 	*prog_int = readb(php_ctlr->creg + PROG_INTERFACE);
5031da177e4SLinus Torvalds 
5041da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
5051da177e4SLinus Torvalds 	return 0;
5061da177e4SLinus Torvalds }
5071da177e4SLinus Torvalds 
5081da177e4SLinus Torvalds static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
5091da177e4SLinus Torvalds {
510ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
5111da177e4SLinus Torvalds 	u32 slot_reg;
5121da177e4SLinus Torvalds 	u16 slot_status, sec_bus_status;
5131da177e4SLinus Torvalds 	u8 m66_cap, pcix_cap, pi;
5141da177e4SLinus Torvalds 	int retval = 0;
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 	if (slot->hp_slot >= php_ctlr->num_slots) {
5241da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
5251da177e4SLinus Torvalds 		return -1;
5261da177e4SLinus Torvalds 	}
5271da177e4SLinus Torvalds 
5281da177e4SLinus Torvalds 	pi = readb(php_ctlr->creg + PROG_INTERFACE);
5291da177e4SLinus Torvalds 	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
5301da177e4SLinus Torvalds 	dbg("%s: pi = %d, slot_reg = %x\n", __FUNCTION__, pi, slot_reg);
5311da177e4SLinus Torvalds 	slot_status = (u16) slot_reg;
5321da177e4SLinus Torvalds 	dbg("%s: slot_status = %x\n", __FUNCTION__, slot_status);
5331da177e4SLinus Torvalds 	sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG);
5341da177e4SLinus Torvalds 
5351da177e4SLinus Torvalds 	pcix_cap = (u8) ((slot_status & 0x3000) >> 12);
5361da177e4SLinus Torvalds 	dbg("%s:  pcix_cap = %x\n", __FUNCTION__, pcix_cap);
5371da177e4SLinus Torvalds 	m66_cap = (u8) ((slot_status & 0x0200) >> 9);
5381da177e4SLinus Torvalds 	dbg("%s:  m66_cap = %x\n", __FUNCTION__, m66_cap);
5391da177e4SLinus Torvalds 
5401da177e4SLinus Torvalds 
5411da177e4SLinus Torvalds 	if (pi == 2) {
5421da177e4SLinus Torvalds 		switch (pcix_cap) {
5431da177e4SLinus Torvalds 		case 0:
5441da177e4SLinus Torvalds 			*value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
5451da177e4SLinus Torvalds 			break;
5461da177e4SLinus Torvalds 		case 1:
5471da177e4SLinus Torvalds 			*value = PCI_SPEED_66MHz_PCIX;
5481da177e4SLinus Torvalds 			break;
5491da177e4SLinus Torvalds 		case 3:
5501da177e4SLinus Torvalds 			*value = PCI_SPEED_133MHz_PCIX;
5511da177e4SLinus Torvalds 			break;
5521da177e4SLinus Torvalds 		case 4:
5531da177e4SLinus Torvalds 			*value = PCI_SPEED_133MHz_PCIX_266;
5541da177e4SLinus Torvalds 			break;
5551da177e4SLinus Torvalds 		case 5:
5561da177e4SLinus Torvalds 			*value = PCI_SPEED_133MHz_PCIX_533;
5571da177e4SLinus Torvalds 			break;
5581da177e4SLinus Torvalds 		case 2:	/* Reserved */
5591da177e4SLinus Torvalds 		default:
5601da177e4SLinus Torvalds 			*value = PCI_SPEED_UNKNOWN;
5611da177e4SLinus Torvalds 			retval = -ENODEV;
5621da177e4SLinus Torvalds 			break;
5631da177e4SLinus Torvalds 		}
5641da177e4SLinus Torvalds 	} else {
5651da177e4SLinus Torvalds 		switch (pcix_cap) {
5661da177e4SLinus Torvalds 		case 0:
5671da177e4SLinus Torvalds 			*value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
5681da177e4SLinus Torvalds 			break;
5691da177e4SLinus Torvalds 		case 1:
5701da177e4SLinus Torvalds 			*value = PCI_SPEED_66MHz_PCIX;
5711da177e4SLinus Torvalds 			break;
5721da177e4SLinus Torvalds 		case 3:
5731da177e4SLinus Torvalds 			*value = PCI_SPEED_133MHz_PCIX;
5741da177e4SLinus Torvalds 			break;
5751da177e4SLinus Torvalds 		case 2:	/* Reserved */
5761da177e4SLinus Torvalds 		default:
5771da177e4SLinus Torvalds 			*value = PCI_SPEED_UNKNOWN;
5781da177e4SLinus Torvalds 			retval = -ENODEV;
5791da177e4SLinus Torvalds 			break;
5801da177e4SLinus Torvalds 		}
5811da177e4SLinus Torvalds 	}
5821da177e4SLinus Torvalds 
5831da177e4SLinus Torvalds 	dbg("Adapter speed = %d\n", *value);
5841da177e4SLinus Torvalds 
5851da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
5861da177e4SLinus Torvalds 	return retval;
5871da177e4SLinus Torvalds }
5881da177e4SLinus Torvalds 
5891da177e4SLinus Torvalds static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
5901da177e4SLinus Torvalds {
591ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
5921da177e4SLinus Torvalds 	u16 sec_bus_status;
5931da177e4SLinus Torvalds 	u8 pi;
5941da177e4SLinus Torvalds 	int retval = 0;
5951da177e4SLinus Torvalds 
5961da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
5971da177e4SLinus Torvalds 
5981da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
5991da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
6001da177e4SLinus Torvalds 		return -1;
6011da177e4SLinus Torvalds 	}
6021da177e4SLinus Torvalds 
6031da177e4SLinus Torvalds 	pi = readb(php_ctlr->creg + PROG_INTERFACE);
6041da177e4SLinus Torvalds 	sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG);
6051da177e4SLinus Torvalds 
6061da177e4SLinus Torvalds 	if (pi == 2) {
60787d6c559SKenji Kaneshige 		*mode = (sec_bus_status & 0x0100) >> 8;
6081da177e4SLinus Torvalds 	} else {
6091da177e4SLinus Torvalds 		retval = -1;
6101da177e4SLinus Torvalds 	}
6111da177e4SLinus Torvalds 
6121da177e4SLinus Torvalds 	dbg("Mode 1 ECC cap = %d\n", *mode);
6131da177e4SLinus Torvalds 
6141da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
6151da177e4SLinus Torvalds 	return retval;
6161da177e4SLinus Torvalds }
6171da177e4SLinus Torvalds 
6181da177e4SLinus Torvalds static int hpc_query_power_fault(struct slot * slot)
6191da177e4SLinus Torvalds {
620ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
6211da177e4SLinus Torvalds 	u32 slot_reg;
6221da177e4SLinus Torvalds 	u16 slot_status;
6231da177e4SLinus Torvalds 	u8 pwr_fault_state, status;
6241da177e4SLinus Torvalds 
6251da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
6261da177e4SLinus Torvalds 
6271da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
6281da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
6291da177e4SLinus Torvalds 		return -1;
6301da177e4SLinus Torvalds 	}
6311da177e4SLinus Torvalds 
6321da177e4SLinus Torvalds 	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
6331da177e4SLinus Torvalds 	slot_status = (u16) slot_reg;
6341da177e4SLinus Torvalds 	pwr_fault_state = (slot_status & 0x0040) >> 7;
6351da177e4SLinus Torvalds 	status = (pwr_fault_state == 1) ? 0 : 1;
6361da177e4SLinus Torvalds 
6371da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
6381da177e4SLinus Torvalds 	/* Note: Logic 0 => fault */
6391da177e4SLinus Torvalds 	return status;
6401da177e4SLinus Torvalds }
6411da177e4SLinus Torvalds 
6421da177e4SLinus Torvalds static int hpc_set_attention_status(struct slot *slot, u8 value)
6431da177e4SLinus Torvalds {
644ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
6451da177e4SLinus Torvalds 	u8 slot_cmd = 0;
6461da177e4SLinus Torvalds 	int rc = 0;
6471da177e4SLinus Torvalds 
6481da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
6491da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
6501da177e4SLinus Torvalds 		return -1;
6511da177e4SLinus Torvalds 	}
6521da177e4SLinus Torvalds 
6531da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
6541da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
6551da177e4SLinus Torvalds 		return -1;
6561da177e4SLinus Torvalds 	}
6571da177e4SLinus Torvalds 
6581da177e4SLinus Torvalds 	switch (value) {
6591da177e4SLinus Torvalds 		case 0 :
6601da177e4SLinus Torvalds 			slot_cmd = 0x30;	/* OFF */
6611da177e4SLinus Torvalds 			break;
6621da177e4SLinus Torvalds 		case 1:
6631da177e4SLinus Torvalds 			slot_cmd = 0x10;	/* ON */
6641da177e4SLinus Torvalds 			break;
6651da177e4SLinus Torvalds 		case 2:
6661da177e4SLinus Torvalds 			slot_cmd = 0x20;	/* BLINK */
6671da177e4SLinus Torvalds 			break;
6681da177e4SLinus Torvalds 		default:
6691da177e4SLinus Torvalds 			return -1;
6701da177e4SLinus Torvalds 	}
6711da177e4SLinus Torvalds 
6721da177e4SLinus Torvalds 	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
6731da177e4SLinus Torvalds 
6741da177e4SLinus Torvalds 	return rc;
6751da177e4SLinus Torvalds }
6761da177e4SLinus Torvalds 
6771da177e4SLinus Torvalds 
6781da177e4SLinus Torvalds static void hpc_set_green_led_on(struct slot *slot)
6791da177e4SLinus Torvalds {
680ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
6811da177e4SLinus Torvalds 	u8 slot_cmd;
6821da177e4SLinus Torvalds 
6831da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
6841da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
6851da177e4SLinus Torvalds 		return ;
6861da177e4SLinus Torvalds 	}
6871da177e4SLinus Torvalds 
6881da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
6891da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
6901da177e4SLinus Torvalds 		return ;
6911da177e4SLinus Torvalds 	}
6921da177e4SLinus Torvalds 
6931da177e4SLinus Torvalds 	slot_cmd = 0x04;
6941da177e4SLinus Torvalds 
6951da177e4SLinus Torvalds 	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
6961da177e4SLinus Torvalds 
6971da177e4SLinus Torvalds 	return;
6981da177e4SLinus Torvalds }
6991da177e4SLinus Torvalds 
7001da177e4SLinus Torvalds static void hpc_set_green_led_off(struct slot *slot)
7011da177e4SLinus Torvalds {
702ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
7031da177e4SLinus Torvalds 	u8 slot_cmd;
7041da177e4SLinus Torvalds 
7051da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
7061da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
7071da177e4SLinus Torvalds 		return ;
7081da177e4SLinus Torvalds 	}
7091da177e4SLinus Torvalds 
7101da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
7111da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
7121da177e4SLinus Torvalds 		return ;
7131da177e4SLinus Torvalds 	}
7141da177e4SLinus Torvalds 
7151da177e4SLinus Torvalds 	slot_cmd = 0x0C;
7161da177e4SLinus Torvalds 
7171da177e4SLinus Torvalds 	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
7181da177e4SLinus Torvalds 
7191da177e4SLinus Torvalds 	return;
7201da177e4SLinus Torvalds }
7211da177e4SLinus Torvalds 
7221da177e4SLinus Torvalds static void hpc_set_green_led_blink(struct slot *slot)
7231da177e4SLinus Torvalds {
724ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
7251da177e4SLinus Torvalds 	u8 slot_cmd;
7261da177e4SLinus Torvalds 
7271da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
7281da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
7291da177e4SLinus Torvalds 		return ;
7301da177e4SLinus Torvalds 	}
7311da177e4SLinus Torvalds 
7321da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
7331da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
7341da177e4SLinus Torvalds 		return ;
7351da177e4SLinus Torvalds 	}
7361da177e4SLinus Torvalds 
7371da177e4SLinus Torvalds 	slot_cmd = 0x08;
7381da177e4SLinus Torvalds 
7391da177e4SLinus Torvalds 	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
7401da177e4SLinus Torvalds 
7411da177e4SLinus Torvalds 	return;
7421da177e4SLinus Torvalds }
7431da177e4SLinus Torvalds 
7441da177e4SLinus Torvalds int shpc_get_ctlr_slot_config(struct controller *ctrl,
7451da177e4SLinus Torvalds 	int *num_ctlr_slots,	/* number of slots in this HPC			*/
7461da177e4SLinus Torvalds 	int *first_device_num,	/* PCI dev num of the first slot in this SHPC	*/
7471da177e4SLinus Torvalds 	int *physical_slot_num,	/* phy slot num of the first slot in this SHPC	*/
7481da177e4SLinus Torvalds 	int *updown,		/* physical_slot_num increament: 1 or -1	*/
7491da177e4SLinus Torvalds 	int *flags)
7501da177e4SLinus Torvalds {
751ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
7521da177e4SLinus Torvalds 
7531da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
7541da177e4SLinus Torvalds 
7551da177e4SLinus Torvalds 	if (!ctrl->hpc_ctlr_handle) {
7561da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
7571da177e4SLinus Torvalds 		return -1;
7581da177e4SLinus Torvalds 	}
7591da177e4SLinus Torvalds 
7601da177e4SLinus Torvalds 	*first_device_num = php_ctlr->slot_device_offset;	/* Obtained in shpc_init() */
7611da177e4SLinus Torvalds 	*num_ctlr_slots = php_ctlr->num_slots;			/* Obtained in shpc_init() */
7621da177e4SLinus Torvalds 
7631da177e4SLinus Torvalds 	*physical_slot_num = (readl(php_ctlr->creg + SLOT_CONFIG) & PSN) >> 16;
7641da177e4SLinus Torvalds 	dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num);
7651da177e4SLinus Torvalds 	*updown = ((readl(php_ctlr->creg + SLOT_CONFIG) & UPDOWN ) >> 29) ? 1 : -1;
7661da177e4SLinus Torvalds 
7671da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
7681da177e4SLinus Torvalds 	return 0;
7691da177e4SLinus Torvalds }
7701da177e4SLinus Torvalds 
7711da177e4SLinus Torvalds static void hpc_release_ctlr(struct controller *ctrl)
7721da177e4SLinus Torvalds {
773ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
7741da177e4SLinus Torvalds 	struct php_ctlr_state_s *p, *p_prev;
7751da177e4SLinus Torvalds 
7761da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
7771da177e4SLinus Torvalds 
7781da177e4SLinus Torvalds 	if (!ctrl->hpc_ctlr_handle) {
7791da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
7801da177e4SLinus Torvalds 		return ;
7811da177e4SLinus Torvalds 	}
7821da177e4SLinus Torvalds 
7831da177e4SLinus Torvalds 	if (shpchp_poll_mode) {
7841da177e4SLinus Torvalds 	    del_timer(&php_ctlr->int_poll_timer);
7851da177e4SLinus Torvalds 	} else {
7861da177e4SLinus Torvalds 		if (php_ctlr->irq) {
7871da177e4SLinus Torvalds 			free_irq(php_ctlr->irq, ctrl);
7881da177e4SLinus Torvalds 			php_ctlr->irq = 0;
7891da177e4SLinus Torvalds 			pci_disable_msi(php_ctlr->pci_dev);
7901da177e4SLinus Torvalds 		}
7911da177e4SLinus Torvalds 	}
7921da177e4SLinus Torvalds 	if (php_ctlr->pci_dev) {
7931da177e4SLinus Torvalds 		iounmap(php_ctlr->creg);
7941da177e4SLinus Torvalds 		release_mem_region(pci_resource_start(php_ctlr->pci_dev, 0), pci_resource_len(php_ctlr->pci_dev, 0));
7951da177e4SLinus Torvalds 		php_ctlr->pci_dev = NULL;
7961da177e4SLinus Torvalds 	}
7971da177e4SLinus Torvalds 
7981da177e4SLinus Torvalds 	spin_lock(&list_lock);
7991da177e4SLinus Torvalds 	p = php_ctlr_list_head;
8001da177e4SLinus Torvalds 	p_prev = NULL;
8011da177e4SLinus Torvalds 	while (p) {
8021da177e4SLinus Torvalds 		if (p == php_ctlr) {
8031da177e4SLinus Torvalds 			if (p_prev)
8041da177e4SLinus Torvalds 				p_prev->pnext = p->pnext;
8051da177e4SLinus Torvalds 			else
8061da177e4SLinus Torvalds 				php_ctlr_list_head = p->pnext;
8071da177e4SLinus Torvalds 			break;
8081da177e4SLinus Torvalds 		} else {
8091da177e4SLinus Torvalds 			p_prev = p;
8101da177e4SLinus Torvalds 			p = p->pnext;
8111da177e4SLinus Torvalds 		}
8121da177e4SLinus Torvalds 	}
8131da177e4SLinus Torvalds 	spin_unlock(&list_lock);
8141da177e4SLinus Torvalds 
8151da177e4SLinus Torvalds 	kfree(php_ctlr);
8161da177e4SLinus Torvalds 
8171da177e4SLinus Torvalds DBG_LEAVE_ROUTINE
8181da177e4SLinus Torvalds 
8191da177e4SLinus Torvalds }
8201da177e4SLinus Torvalds 
8211da177e4SLinus Torvalds static int hpc_power_on_slot(struct slot * slot)
8221da177e4SLinus Torvalds {
823ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
8241da177e4SLinus Torvalds 	u8 slot_cmd;
8251da177e4SLinus Torvalds 	int retval = 0;
8261da177e4SLinus Torvalds 
8271da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
8281da177e4SLinus Torvalds 
8291da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
8301da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
8311da177e4SLinus Torvalds 		return -1;
8321da177e4SLinus Torvalds 	}
8331da177e4SLinus Torvalds 
8341da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
8351da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
8361da177e4SLinus Torvalds 		return -1;
8371da177e4SLinus Torvalds 	}
8381da177e4SLinus Torvalds 	slot_cmd = 0x01;
8391da177e4SLinus Torvalds 
8401da177e4SLinus Torvalds 	retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
8411da177e4SLinus Torvalds 
8421da177e4SLinus Torvalds 	if (retval) {
8431da177e4SLinus Torvalds 		err("%s: Write command failed!\n", __FUNCTION__);
8441da177e4SLinus Torvalds 		return -1;
8451da177e4SLinus Torvalds 	}
8461da177e4SLinus Torvalds 
8471da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
8481da177e4SLinus Torvalds 
8491da177e4SLinus Torvalds 	return retval;
8501da177e4SLinus Torvalds }
8511da177e4SLinus Torvalds 
8521da177e4SLinus Torvalds static int hpc_slot_enable(struct slot * slot)
8531da177e4SLinus Torvalds {
854ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
8551da177e4SLinus Torvalds 	u8 slot_cmd;
8561da177e4SLinus Torvalds 	int retval = 0;
8571da177e4SLinus Torvalds 
8581da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
8591da177e4SLinus Torvalds 
8601da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
8611da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
8621da177e4SLinus Torvalds 		return -1;
8631da177e4SLinus Torvalds 	}
8641da177e4SLinus Torvalds 
8651da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
8661da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
8671da177e4SLinus Torvalds 		return -1;
8681da177e4SLinus Torvalds 	}
8691da177e4SLinus Torvalds 	/* 3A => Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */
8701da177e4SLinus Torvalds 	slot_cmd = 0x3A;
8711da177e4SLinus Torvalds 
8721da177e4SLinus Torvalds 	retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
8731da177e4SLinus Torvalds 
8741da177e4SLinus Torvalds 	if (retval) {
8751da177e4SLinus Torvalds 		err("%s: Write command failed!\n", __FUNCTION__);
8761da177e4SLinus Torvalds 		return -1;
8771da177e4SLinus Torvalds 	}
8781da177e4SLinus Torvalds 
8791da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
8801da177e4SLinus Torvalds 	return retval;
8811da177e4SLinus Torvalds }
8821da177e4SLinus Torvalds 
8831da177e4SLinus Torvalds static int hpc_slot_disable(struct slot * slot)
8841da177e4SLinus Torvalds {
885ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
8861da177e4SLinus Torvalds 	u8 slot_cmd;
8871da177e4SLinus Torvalds 	int retval = 0;
8881da177e4SLinus Torvalds 
8891da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
8901da177e4SLinus Torvalds 
8911da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
8921da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
8931da177e4SLinus Torvalds 		return -1;
8941da177e4SLinus Torvalds 	}
8951da177e4SLinus Torvalds 
8961da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
8971da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
8981da177e4SLinus Torvalds 		return -1;
8991da177e4SLinus Torvalds 	}
9001da177e4SLinus Torvalds 
9011da177e4SLinus Torvalds 	/* 1F => Slot - Disable, Power Indicator - Off, Attention Indicator - On */
9021da177e4SLinus Torvalds 	slot_cmd = 0x1F;
9031da177e4SLinus Torvalds 
9041da177e4SLinus Torvalds 	retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
9051da177e4SLinus Torvalds 
9061da177e4SLinus Torvalds 	if (retval) {
9071da177e4SLinus Torvalds 		err("%s: Write command failed!\n", __FUNCTION__);
9081da177e4SLinus Torvalds 		return -1;
9091da177e4SLinus Torvalds 	}
9101da177e4SLinus Torvalds 
9111da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
9121da177e4SLinus Torvalds 	return retval;
9131da177e4SLinus Torvalds }
9141da177e4SLinus Torvalds 
9151da177e4SLinus Torvalds static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
9161da177e4SLinus Torvalds {
9171da177e4SLinus Torvalds 	u8 slot_cmd;
9181da177e4SLinus Torvalds 	u8 pi;
9191da177e4SLinus Torvalds 	int retval = 0;
920ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
9211da177e4SLinus Torvalds 
9221da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
9231da177e4SLinus Torvalds 
9241da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
9251da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
9261da177e4SLinus Torvalds 		return -1;
9271da177e4SLinus Torvalds 	}
9281da177e4SLinus Torvalds 
9291da177e4SLinus Torvalds 	pi = readb(php_ctlr->creg + PROG_INTERFACE);
9301da177e4SLinus Torvalds 
9311da177e4SLinus Torvalds 	if (pi == 1) {
9321da177e4SLinus Torvalds 		switch (value) {
9331da177e4SLinus Torvalds 		case 0:
9341da177e4SLinus Torvalds 			slot_cmd = SETA_PCI_33MHZ;
9351da177e4SLinus Torvalds 			break;
9361da177e4SLinus Torvalds 		case 1:
9371da177e4SLinus Torvalds 			slot_cmd = SETA_PCI_66MHZ;
9381da177e4SLinus Torvalds 			break;
9391da177e4SLinus Torvalds 		case 2:
9401da177e4SLinus Torvalds 			slot_cmd = SETA_PCIX_66MHZ;
9411da177e4SLinus Torvalds 			break;
9421da177e4SLinus Torvalds 		case 3:
9431da177e4SLinus Torvalds 			slot_cmd = SETA_PCIX_100MHZ;
9441da177e4SLinus Torvalds 			break;
9451da177e4SLinus Torvalds 		case 4:
9461da177e4SLinus Torvalds 			slot_cmd = SETA_PCIX_133MHZ;
9471da177e4SLinus Torvalds 			break;
9481da177e4SLinus Torvalds 		default:
9491da177e4SLinus Torvalds 			slot_cmd = PCI_SPEED_UNKNOWN;
9501da177e4SLinus Torvalds 			retval = -ENODEV;
9511da177e4SLinus Torvalds 			return retval;
9521da177e4SLinus Torvalds 		}
9531da177e4SLinus Torvalds 	} else {
9541da177e4SLinus Torvalds 		switch (value) {
9551da177e4SLinus Torvalds 		case 0:
9561da177e4SLinus Torvalds 			slot_cmd = SETB_PCI_33MHZ;
9571da177e4SLinus Torvalds 			break;
9581da177e4SLinus Torvalds 		case 1:
9591da177e4SLinus Torvalds 			slot_cmd = SETB_PCI_66MHZ;
9601da177e4SLinus Torvalds 			break;
9611da177e4SLinus Torvalds 		case 2:
9621da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_66MHZ_PM;
9631da177e4SLinus Torvalds 			break;
9641da177e4SLinus Torvalds 		case 3:
9651da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_100MHZ_PM;
9661da177e4SLinus Torvalds 			break;
9671da177e4SLinus Torvalds 		case 4:
9681da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_133MHZ_PM;
9691da177e4SLinus Torvalds 			break;
9701da177e4SLinus Torvalds 		case 5:
9711da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_66MHZ_EM;
9721da177e4SLinus Torvalds 			break;
9731da177e4SLinus Torvalds 		case 6:
9741da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_100MHZ_EM;
9751da177e4SLinus Torvalds 			break;
9761da177e4SLinus Torvalds 		case 7:
9771da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_133MHZ_EM;
9781da177e4SLinus Torvalds 			break;
9791da177e4SLinus Torvalds 		case 8:
9801da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_66MHZ_266;
9811da177e4SLinus Torvalds 			break;
9821da177e4SLinus Torvalds 		case 0x9:
9831da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_100MHZ_266;
9841da177e4SLinus Torvalds 			break;
9851da177e4SLinus Torvalds 		case 0xa:
9861da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_133MHZ_266;
9871da177e4SLinus Torvalds 			break;
9881da177e4SLinus Torvalds 		case 0xb:
9891da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_66MHZ_533;
9901da177e4SLinus Torvalds 			break;
9911da177e4SLinus Torvalds 		case 0xc:
9921da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_100MHZ_533;
9931da177e4SLinus Torvalds 			break;
9941da177e4SLinus Torvalds 		case 0xd:
9951da177e4SLinus Torvalds 			slot_cmd = SETB_PCIX_133MHZ_533;
9961da177e4SLinus Torvalds 			break;
9971da177e4SLinus Torvalds 		default:
9981da177e4SLinus Torvalds 			slot_cmd = PCI_SPEED_UNKNOWN;
9991da177e4SLinus Torvalds 			retval = -ENODEV;
10001da177e4SLinus Torvalds 			return retval;
10011da177e4SLinus Torvalds 		}
10021da177e4SLinus Torvalds 
10031da177e4SLinus Torvalds 	}
10041da177e4SLinus Torvalds 	retval = shpc_write_cmd(slot, 0, slot_cmd);
10051da177e4SLinus Torvalds 	if (retval) {
10061da177e4SLinus Torvalds 		err("%s: Write command failed!\n", __FUNCTION__);
10071da177e4SLinus Torvalds 		return -1;
10081da177e4SLinus Torvalds 	}
10091da177e4SLinus Torvalds 
10101da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
10111da177e4SLinus Torvalds 	return retval;
10121da177e4SLinus Torvalds }
10131da177e4SLinus Torvalds 
10141da177e4SLinus Torvalds static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs)
10151da177e4SLinus Torvalds {
10161da177e4SLinus Torvalds 	struct controller *ctrl = NULL;
10171da177e4SLinus Torvalds 	struct php_ctlr_state_s *php_ctlr;
10181da177e4SLinus Torvalds 	u8 schedule_flag = 0;
10191da177e4SLinus Torvalds 	u8 temp_byte;
10201da177e4SLinus Torvalds 	u32 temp_dword, intr_loc, intr_loc2;
10211da177e4SLinus Torvalds 	int hp_slot;
10221da177e4SLinus Torvalds 
10231da177e4SLinus Torvalds 	if (!dev_id)
10241da177e4SLinus Torvalds 		return IRQ_NONE;
10251da177e4SLinus Torvalds 
10261da177e4SLinus Torvalds 	if (!shpchp_poll_mode) {
10271da177e4SLinus Torvalds 		ctrl = (struct controller *)dev_id;
10281da177e4SLinus Torvalds 		php_ctlr = ctrl->hpc_ctlr_handle;
10291da177e4SLinus Torvalds 	} else {
10301da177e4SLinus Torvalds 		php_ctlr = (struct php_ctlr_state_s *) dev_id;
10311da177e4SLinus Torvalds 		ctrl = (struct controller *)php_ctlr->callback_instance_id;
10321da177e4SLinus Torvalds 	}
10331da177e4SLinus Torvalds 
10341da177e4SLinus Torvalds 	if (!ctrl)
10351da177e4SLinus Torvalds 		return IRQ_NONE;
10361da177e4SLinus Torvalds 
10371da177e4SLinus Torvalds 	if (!php_ctlr || !php_ctlr->creg)
10381da177e4SLinus Torvalds 		return IRQ_NONE;
10391da177e4SLinus Torvalds 
10401da177e4SLinus Torvalds 	/* Check to see if it was our interrupt */
10411da177e4SLinus Torvalds 	intr_loc = readl(php_ctlr->creg + INTR_LOC);
10421da177e4SLinus Torvalds 
10431da177e4SLinus Torvalds 	if (!intr_loc)
10441da177e4SLinus Torvalds 		return IRQ_NONE;
10451da177e4SLinus Torvalds 	dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc);
10461da177e4SLinus Torvalds 
10471da177e4SLinus Torvalds 	if(!shpchp_poll_mode) {
10481da177e4SLinus Torvalds 		/* Mask Global Interrupt Mask - see implementation note on p. 139 */
10491da177e4SLinus Torvalds 		/* of SHPC spec rev 1.0*/
10501da177e4SLinus Torvalds 		temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
10511da177e4SLinus Torvalds 		temp_dword |= 0x00000001;
10521da177e4SLinus Torvalds 		writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
10531da177e4SLinus Torvalds 
10541da177e4SLinus Torvalds 		intr_loc2 = readl(php_ctlr->creg + INTR_LOC);
10551da177e4SLinus Torvalds 		dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2);
10561da177e4SLinus Torvalds 	}
10571da177e4SLinus Torvalds 
10581da177e4SLinus Torvalds 	if (intr_loc & 0x0001) {
10591da177e4SLinus Torvalds 		/*
10601da177e4SLinus Torvalds 		 * Command Complete Interrupt Pending
10611da177e4SLinus Torvalds 		 * RO only - clear by writing 0 to the Command Completion
10621da177e4SLinus Torvalds 		 * Detect bit in Controller SERR-INT register
10631da177e4SLinus Torvalds 		 */
10641da177e4SLinus Torvalds 		temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
10651da177e4SLinus Torvalds 		temp_dword &= 0xfffeffff;
10661da177e4SLinus Torvalds 		writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
10671da177e4SLinus Torvalds 		wake_up_interruptible(&ctrl->queue);
10681da177e4SLinus Torvalds 	}
10691da177e4SLinus Torvalds 
10701da177e4SLinus Torvalds 	if ((intr_loc = (intr_loc >> 1)) == 0) {
10711da177e4SLinus Torvalds 		/* Unmask Global Interrupt Mask */
10721da177e4SLinus Torvalds 		temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
10731da177e4SLinus Torvalds 		temp_dword &= 0xfffffffe;
10741da177e4SLinus Torvalds 		writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
10751da177e4SLinus Torvalds 
10761da177e4SLinus Torvalds 		return IRQ_NONE;
10771da177e4SLinus Torvalds 	}
10781da177e4SLinus Torvalds 
10791da177e4SLinus Torvalds 	for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {
10801da177e4SLinus Torvalds 	/* To find out which slot has interrupt pending */
10811da177e4SLinus Torvalds 		if ((intr_loc >> hp_slot) & 0x01) {
10821da177e4SLinus Torvalds 			temp_dword = readl(php_ctlr->creg + SLOT1 + (4*hp_slot));
10837c8942f9Srajesh.shah@intel.com 			dbg("%s: Slot %x with intr, slot register = %x\n",
10841da177e4SLinus Torvalds 				__FUNCTION__, hp_slot, temp_dword);
10851da177e4SLinus Torvalds 			temp_byte = (temp_dword >> 16) & 0xFF;
10861da177e4SLinus Torvalds 			if ((php_ctlr->switch_change_callback) && (temp_byte & 0x08))
10871da177e4SLinus Torvalds 				schedule_flag += php_ctlr->switch_change_callback(
10881da177e4SLinus Torvalds 					hp_slot, php_ctlr->callback_instance_id);
10891da177e4SLinus Torvalds 			if ((php_ctlr->attention_button_callback) && (temp_byte & 0x04))
10901da177e4SLinus Torvalds 				schedule_flag += php_ctlr->attention_button_callback(
10911da177e4SLinus Torvalds 					hp_slot, php_ctlr->callback_instance_id);
10921da177e4SLinus Torvalds 			if ((php_ctlr->presence_change_callback) && (temp_byte & 0x01))
10931da177e4SLinus Torvalds 				schedule_flag += php_ctlr->presence_change_callback(
10941da177e4SLinus Torvalds 					hp_slot , php_ctlr->callback_instance_id);
10951da177e4SLinus Torvalds 			if ((php_ctlr->power_fault_callback) && (temp_byte & 0x12))
10961da177e4SLinus Torvalds 				schedule_flag += php_ctlr->power_fault_callback(
10971da177e4SLinus Torvalds 					hp_slot, php_ctlr->callback_instance_id);
10981da177e4SLinus Torvalds 
10991da177e4SLinus Torvalds 			/* Clear all slot events */
11001da177e4SLinus Torvalds 			temp_dword = 0xe01f3fff;
11011da177e4SLinus Torvalds 			writel(temp_dword, php_ctlr->creg + SLOT1 + (4*hp_slot));
11021da177e4SLinus Torvalds 
11031da177e4SLinus Torvalds 			intr_loc2 = readl(php_ctlr->creg + INTR_LOC);
11041da177e4SLinus Torvalds 			dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2);
11051da177e4SLinus Torvalds 		}
11061da177e4SLinus Torvalds 	}
11071da177e4SLinus Torvalds 	if (!shpchp_poll_mode) {
11081da177e4SLinus Torvalds 		/* Unmask Global Interrupt Mask */
11091da177e4SLinus Torvalds 		temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
11101da177e4SLinus Torvalds 		temp_dword &= 0xfffffffe;
11111da177e4SLinus Torvalds 		writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
11121da177e4SLinus Torvalds 	}
11131da177e4SLinus Torvalds 
11141da177e4SLinus Torvalds 	return IRQ_HANDLED;
11151da177e4SLinus Torvalds }
11161da177e4SLinus Torvalds 
11171da177e4SLinus Torvalds static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
11181da177e4SLinus Torvalds {
1119ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
11201da177e4SLinus Torvalds 	enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
11211da177e4SLinus Torvalds 	int retval = 0;
11221da177e4SLinus Torvalds 	u8 pi;
11231da177e4SLinus Torvalds 	u32 slot_avail1, slot_avail2;
11241da177e4SLinus Torvalds 
11251da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
11261da177e4SLinus Torvalds 
11271da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
11281da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
11291da177e4SLinus Torvalds 		return -1;
11301da177e4SLinus Torvalds 	}
11311da177e4SLinus Torvalds 
11321da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
11331da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
11341da177e4SLinus Torvalds 		return -1;
11351da177e4SLinus Torvalds 	}
11361da177e4SLinus Torvalds 
11371da177e4SLinus Torvalds 	pi = readb(php_ctlr->creg + PROG_INTERFACE);
11381da177e4SLinus Torvalds 	slot_avail1 = readl(php_ctlr->creg + SLOT_AVAIL1);
11391da177e4SLinus Torvalds 	slot_avail2 = readl(php_ctlr->creg + SLOT_AVAIL2);
11401da177e4SLinus Torvalds 
11411da177e4SLinus Torvalds 	if (pi == 2) {
11426558b6abSKenji Kaneshige 		if (slot_avail2 & SLOT_133MHZ_PCIX_533)
11431da177e4SLinus Torvalds 			bus_speed = PCIX_133MHZ_533;
11446558b6abSKenji Kaneshige 		else if (slot_avail2 & SLOT_100MHZ_PCIX_533)
11451da177e4SLinus Torvalds 			bus_speed = PCIX_100MHZ_533;
11466558b6abSKenji Kaneshige 		else if (slot_avail2 & SLOT_66MHZ_PCIX_533)
11471da177e4SLinus Torvalds 			bus_speed = PCIX_66MHZ_533;
11486558b6abSKenji Kaneshige 		else if (slot_avail2 & SLOT_133MHZ_PCIX_266)
11491da177e4SLinus Torvalds 			bus_speed = PCIX_133MHZ_266;
11506558b6abSKenji Kaneshige 		else if (slot_avail2 & SLOT_100MHZ_PCIX_266)
11511da177e4SLinus Torvalds 			bus_speed = PCIX_100MHZ_266;
11526558b6abSKenji Kaneshige 		else if (slot_avail2 & SLOT_66MHZ_PCIX_266)
11531da177e4SLinus Torvalds 			bus_speed = PCIX_66MHZ_266;
11546558b6abSKenji Kaneshige 		else if (slot_avail1 & SLOT_133MHZ_PCIX)
11551da177e4SLinus Torvalds 			bus_speed = PCIX_133MHZ;
11566558b6abSKenji Kaneshige 		else if (slot_avail1 & SLOT_100MHZ_PCIX)
11571da177e4SLinus Torvalds 			bus_speed = PCIX_100MHZ;
11586558b6abSKenji Kaneshige 		else if (slot_avail1 & SLOT_66MHZ_PCIX)
11591da177e4SLinus Torvalds 			bus_speed = PCIX_66MHZ;
11606558b6abSKenji Kaneshige 		else if (slot_avail2 & SLOT_66MHZ)
11611da177e4SLinus Torvalds 			bus_speed = PCI_66MHZ;
11626558b6abSKenji Kaneshige 		else if (slot_avail1 & SLOT_33MHZ)
11631da177e4SLinus Torvalds 			bus_speed = PCI_33MHZ;
11641da177e4SLinus Torvalds 		else bus_speed = PCI_SPEED_UNKNOWN;
11651da177e4SLinus Torvalds 	} else {
11666558b6abSKenji Kaneshige 		if (slot_avail1 & SLOT_133MHZ_PCIX)
11671da177e4SLinus Torvalds 			bus_speed = PCIX_133MHZ;
11686558b6abSKenji Kaneshige 		else if (slot_avail1 & SLOT_100MHZ_PCIX)
11691da177e4SLinus Torvalds 			bus_speed = PCIX_100MHZ;
11706558b6abSKenji Kaneshige 		else if (slot_avail1 & SLOT_66MHZ_PCIX)
11711da177e4SLinus Torvalds 			bus_speed = PCIX_66MHZ;
11726558b6abSKenji Kaneshige 		else if (slot_avail2 & SLOT_66MHZ)
11731da177e4SLinus Torvalds 			bus_speed = PCI_66MHZ;
11746558b6abSKenji Kaneshige 		else if (slot_avail1 & SLOT_33MHZ)
11751da177e4SLinus Torvalds 			bus_speed = PCI_33MHZ;
11761da177e4SLinus Torvalds 		else bus_speed = PCI_SPEED_UNKNOWN;
11771da177e4SLinus Torvalds 	}
11781da177e4SLinus Torvalds 
11791da177e4SLinus Torvalds 	*value = bus_speed;
11801da177e4SLinus Torvalds 	dbg("Max bus speed = %d\n", bus_speed);
11811da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
11821da177e4SLinus Torvalds 	return retval;
11831da177e4SLinus Torvalds }
11841da177e4SLinus Torvalds 
11851da177e4SLinus Torvalds static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
11861da177e4SLinus Torvalds {
1187ee138334Srajesh.shah@intel.com 	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
11881da177e4SLinus Torvalds 	enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
11891da177e4SLinus Torvalds 	u16 sec_bus_status;
11901da177e4SLinus Torvalds 	int retval = 0;
11911da177e4SLinus Torvalds 	u8 pi;
11921da177e4SLinus Torvalds 
11931da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
11941da177e4SLinus Torvalds 
11951da177e4SLinus Torvalds 	if (!slot->ctrl->hpc_ctlr_handle) {
11961da177e4SLinus Torvalds 		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
11971da177e4SLinus Torvalds 		return -1;
11981da177e4SLinus Torvalds 	}
11991da177e4SLinus Torvalds 
12001da177e4SLinus Torvalds 	if (slot->hp_slot >= php_ctlr->num_slots) {
12011da177e4SLinus Torvalds 		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
12021da177e4SLinus Torvalds 		return -1;
12031da177e4SLinus Torvalds 	}
12041da177e4SLinus Torvalds 
12051da177e4SLinus Torvalds 	pi = readb(php_ctlr->creg + PROG_INTERFACE);
12061da177e4SLinus Torvalds 	sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG);
12071da177e4SLinus Torvalds 
12081da177e4SLinus Torvalds 	if (pi == 2) {
12091da177e4SLinus Torvalds 		switch (sec_bus_status & 0x000f) {
12101da177e4SLinus Torvalds 		case 0:
12111da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_33MHz;
12121da177e4SLinus Torvalds 			break;
12131da177e4SLinus Torvalds 		case 1:
12141da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_66MHz;
12151da177e4SLinus Torvalds 			break;
12161da177e4SLinus Torvalds 		case 2:
12171da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_66MHz_PCIX;
12181da177e4SLinus Torvalds 			break;
12191da177e4SLinus Torvalds 		case 3:
12201da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_100MHz_PCIX;
12211da177e4SLinus Torvalds 			break;
12221da177e4SLinus Torvalds 		case 4:
12231da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_133MHz_PCIX;
12241da177e4SLinus Torvalds 			break;
12251da177e4SLinus Torvalds 		case 5:
12261da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_66MHz_PCIX_ECC;
12271da177e4SLinus Torvalds 			break;
12281da177e4SLinus Torvalds 		case 6:
12291da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_100MHz_PCIX_ECC;
12301da177e4SLinus Torvalds 			break;
12311da177e4SLinus Torvalds 		case 7:
12321da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_133MHz_PCIX_ECC;
12331da177e4SLinus Torvalds 			break;
12341da177e4SLinus Torvalds 		case 8:
12351da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_66MHz_PCIX_266;
12361da177e4SLinus Torvalds 			break;
12371da177e4SLinus Torvalds 		case 9:
12381da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_100MHz_PCIX_266;
12391da177e4SLinus Torvalds 			break;
12401da177e4SLinus Torvalds 		case 0xa:
12411da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_133MHz_PCIX_266;
12421da177e4SLinus Torvalds 			break;
12431da177e4SLinus Torvalds 		case 0xb:
12441da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_66MHz_PCIX_533;
12451da177e4SLinus Torvalds 			break;
12461da177e4SLinus Torvalds 		case 0xc:
12471da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_100MHz_PCIX_533;
12481da177e4SLinus Torvalds 			break;
12491da177e4SLinus Torvalds 		case 0xd:
12501da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_133MHz_PCIX_533;
12511da177e4SLinus Torvalds 			break;
12521da177e4SLinus Torvalds 		case 0xe:
12531da177e4SLinus Torvalds 		case 0xf:
12541da177e4SLinus Torvalds 		default:
12551da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_UNKNOWN;
12561da177e4SLinus Torvalds 			break;
12571da177e4SLinus Torvalds 		}
12581da177e4SLinus Torvalds 	} else {
12591da177e4SLinus Torvalds 		/* In the case where pi is undefined, default it to 1 */
12601da177e4SLinus Torvalds 		switch (sec_bus_status & 0x0007) {
12611da177e4SLinus Torvalds 		case 0:
12621da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_33MHz;
12631da177e4SLinus Torvalds 			break;
12641da177e4SLinus Torvalds 		case 1:
12651da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_66MHz;
12661da177e4SLinus Torvalds 			break;
12671da177e4SLinus Torvalds 		case 2:
12681da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_66MHz_PCIX;
12691da177e4SLinus Torvalds 			break;
12701da177e4SLinus Torvalds 		case 3:
12711da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_100MHz_PCIX;
12721da177e4SLinus Torvalds 			break;
12731da177e4SLinus Torvalds 		case 4:
12741da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_133MHz_PCIX;
12751da177e4SLinus Torvalds 			break;
12761da177e4SLinus Torvalds 		case 5:
12771da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_UNKNOWN;		/*	Reserved */
12781da177e4SLinus Torvalds 			break;
12791da177e4SLinus Torvalds 		case 6:
12801da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_UNKNOWN;		/*	Reserved */
12811da177e4SLinus Torvalds 			break;
12821da177e4SLinus Torvalds 		case 7:
12831da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_UNKNOWN;		/*	Reserved */
12841da177e4SLinus Torvalds 			break;
12851da177e4SLinus Torvalds 		default:
12861da177e4SLinus Torvalds 			bus_speed = PCI_SPEED_UNKNOWN;
12871da177e4SLinus Torvalds 			break;
12881da177e4SLinus Torvalds 		}
12891da177e4SLinus Torvalds 	}
12901da177e4SLinus Torvalds 
12911da177e4SLinus Torvalds 	*value = bus_speed;
12921da177e4SLinus Torvalds 	dbg("Current bus speed = %d\n", bus_speed);
12931da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
12941da177e4SLinus Torvalds 	return retval;
12951da177e4SLinus Torvalds }
12961da177e4SLinus Torvalds 
12971da177e4SLinus Torvalds static struct hpc_ops shpchp_hpc_ops = {
12981da177e4SLinus Torvalds 	.power_on_slot			= hpc_power_on_slot,
12991da177e4SLinus Torvalds 	.slot_enable			= hpc_slot_enable,
13001da177e4SLinus Torvalds 	.slot_disable			= hpc_slot_disable,
13011da177e4SLinus Torvalds 	.set_bus_speed_mode		= hpc_set_bus_speed_mode,
13021da177e4SLinus Torvalds 	.set_attention_status	= hpc_set_attention_status,
13031da177e4SLinus Torvalds 	.get_power_status		= hpc_get_power_status,
13041da177e4SLinus Torvalds 	.get_attention_status	= hpc_get_attention_status,
13051da177e4SLinus Torvalds 	.get_latch_status		= hpc_get_latch_status,
13061da177e4SLinus Torvalds 	.get_adapter_status		= hpc_get_adapter_status,
13071da177e4SLinus Torvalds 
13081da177e4SLinus Torvalds 	.get_max_bus_speed		= hpc_get_max_bus_speed,
13091da177e4SLinus Torvalds 	.get_cur_bus_speed		= hpc_get_cur_bus_speed,
13101da177e4SLinus Torvalds 	.get_adapter_speed		= hpc_get_adapter_speed,
13111da177e4SLinus Torvalds 	.get_mode1_ECC_cap		= hpc_get_mode1_ECC_cap,
13121da177e4SLinus Torvalds 	.get_prog_int			= hpc_get_prog_int,
13131da177e4SLinus Torvalds 
13141da177e4SLinus Torvalds 	.query_power_fault		= hpc_query_power_fault,
13151da177e4SLinus Torvalds 	.green_led_on			= hpc_set_green_led_on,
13161da177e4SLinus Torvalds 	.green_led_off			= hpc_set_green_led_off,
13171da177e4SLinus Torvalds 	.green_led_blink		= hpc_set_green_led_blink,
13181da177e4SLinus Torvalds 
13191da177e4SLinus Torvalds 	.release_ctlr			= hpc_release_ctlr,
13201da177e4SLinus Torvalds 	.check_cmd_status		= hpc_check_cmd_status,
13211da177e4SLinus Torvalds };
13221da177e4SLinus Torvalds 
1323ee138334Srajesh.shah@intel.com int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
13241da177e4SLinus Torvalds {
13251da177e4SLinus Torvalds 	struct php_ctlr_state_s *php_ctlr, *p;
13261da177e4SLinus Torvalds 	void *instance_id = ctrl;
13271da177e4SLinus Torvalds 	int rc;
13281da177e4SLinus Torvalds 	u8 hp_slot;
13291da177e4SLinus Torvalds 	static int first = 1;
13301da177e4SLinus Torvalds 	u32 shpc_cap_offset, shpc_base_offset;
13311da177e4SLinus Torvalds 	u32 tempdword, slot_reg;
13321da177e4SLinus Torvalds 	u8 i;
13331da177e4SLinus Torvalds 
13341da177e4SLinus Torvalds 	DBG_ENTER_ROUTINE
13351da177e4SLinus Torvalds 
13361da177e4SLinus Torvalds 	spin_lock_init(&list_lock);
13371da177e4SLinus Torvalds 	php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
13381da177e4SLinus Torvalds 
13391da177e4SLinus Torvalds 	if (!php_ctlr) {	/* allocate controller state data */
13401da177e4SLinus Torvalds 		err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
13411da177e4SLinus Torvalds 		goto abort;
13421da177e4SLinus Torvalds 	}
13431da177e4SLinus Torvalds 
13441da177e4SLinus Torvalds 	memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s));
13451da177e4SLinus Torvalds 
13461da177e4SLinus Torvalds 	php_ctlr->pci_dev = pdev;	/* save pci_dev in context */
13471da177e4SLinus Torvalds 
1348ee138334Srajesh.shah@intel.com 	if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device ==
1349ee138334Srajesh.shah@intel.com 				PCI_DEVICE_ID_AMD_GOLAM_7450)) {
13501da177e4SLinus Torvalds 		shpc_base_offset = 0;  /* amd shpc driver doesn't use this; assume 0 */
13511da177e4SLinus Torvalds 	} else {
13521da177e4SLinus Torvalds 		if ((shpc_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC)) == 0) {
13531da177e4SLinus Torvalds 			err("%s : shpc_cap_offset == 0\n", __FUNCTION__);
13541da177e4SLinus Torvalds 			goto abort_free_ctlr;
13551da177e4SLinus Torvalds 		}
13561da177e4SLinus Torvalds 		dbg("%s: shpc_cap_offset = %x\n", __FUNCTION__, shpc_cap_offset);
13571da177e4SLinus Torvalds 
13581da177e4SLinus Torvalds 		rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset + DWORD_SELECT , BASE_OFFSET);
13591da177e4SLinus Torvalds 		if (rc) {
13601da177e4SLinus Torvalds 			err("%s : pci_word_config_byte failed\n", __FUNCTION__);
13611da177e4SLinus Torvalds 			goto abort_free_ctlr;
13621da177e4SLinus Torvalds 		}
13631da177e4SLinus Torvalds 
13641da177e4SLinus Torvalds 		rc = pci_read_config_dword(pdev, (u8)shpc_cap_offset + DWORD_DATA, &shpc_base_offset);
13651da177e4SLinus Torvalds 		if (rc) {
13661da177e4SLinus Torvalds 			err("%s : pci_read_config_dword failed\n", __FUNCTION__);
13671da177e4SLinus Torvalds 			goto abort_free_ctlr;
13681da177e4SLinus Torvalds 		}
13691da177e4SLinus Torvalds 
13701da177e4SLinus Torvalds 		for (i = 0; i <= 14; i++) {
13711da177e4SLinus Torvalds 			rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset +  DWORD_SELECT , i);
13721da177e4SLinus Torvalds 			if (rc) {
13731da177e4SLinus Torvalds 				err("%s : pci_word_config_byte failed\n", __FUNCTION__);
13741da177e4SLinus Torvalds 				goto abort_free_ctlr;
13751da177e4SLinus Torvalds 			}
13761da177e4SLinus Torvalds 
13771da177e4SLinus Torvalds 			rc = pci_read_config_dword(pdev, (u8)shpc_cap_offset + DWORD_DATA, &tempdword);
13781da177e4SLinus Torvalds 			if (rc) {
13791da177e4SLinus Torvalds 				err("%s : pci_read_config_dword failed\n", __FUNCTION__);
13801da177e4SLinus Torvalds 				goto abort_free_ctlr;
13811da177e4SLinus Torvalds 			}
13827c8942f9Srajesh.shah@intel.com 			dbg("%s: offset %d: value %x\n", __FUNCTION__,i,
13837c8942f9Srajesh.shah@intel.com 					tempdword);
13841da177e4SLinus Torvalds 		}
13851da177e4SLinus Torvalds 	}
13861da177e4SLinus Torvalds 
13871da177e4SLinus Torvalds 	if (first) {
13881da177e4SLinus Torvalds 		spin_lock_init(&hpc_event_lock);
13891da177e4SLinus Torvalds 		first = 0;
13901da177e4SLinus Torvalds 	}
13911da177e4SLinus Torvalds 
13921da177e4SLinus Torvalds 	info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor,
13931da177e4SLinus Torvalds 		pdev->subsystem_device);
13941da177e4SLinus Torvalds 
13951da177e4SLinus Torvalds 	if (pci_enable_device(pdev))
13961da177e4SLinus Torvalds 		goto abort_free_ctlr;
13971da177e4SLinus Torvalds 
13981da177e4SLinus Torvalds 	if (!request_mem_region(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0), MY_NAME)) {
13991da177e4SLinus Torvalds 		err("%s: cannot reserve MMIO region\n", __FUNCTION__);
14001da177e4SLinus Torvalds 		goto abort_free_ctlr;
14011da177e4SLinus Torvalds 	}
14021da177e4SLinus Torvalds 
14031da177e4SLinus Torvalds 	php_ctlr->creg = ioremap(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0));
14041da177e4SLinus Torvalds 	if (!php_ctlr->creg) {
14051da177e4SLinus Torvalds 		err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__, pci_resource_len(pdev, 0),
14061da177e4SLinus Torvalds 			pci_resource_start(pdev, 0) + shpc_base_offset);
14071da177e4SLinus Torvalds 		release_mem_region(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0));
14081da177e4SLinus Torvalds 		goto abort_free_ctlr;
14091da177e4SLinus Torvalds 	}
14101da177e4SLinus Torvalds 	dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg);
14111da177e4SLinus Torvalds 
14121da177e4SLinus Torvalds 	init_MUTEX(&ctrl->crit_sect);
14131da177e4SLinus Torvalds 	/* Setup wait queue */
14141da177e4SLinus Torvalds 	init_waitqueue_head(&ctrl->queue);
14151da177e4SLinus Torvalds 
14161da177e4SLinus Torvalds 	/* Find the IRQ */
14171da177e4SLinus Torvalds 	php_ctlr->irq = pdev->irq;
1418ee138334Srajesh.shah@intel.com 	php_ctlr->attention_button_callback = shpchp_handle_attention_button,
1419ee138334Srajesh.shah@intel.com 	php_ctlr->switch_change_callback = shpchp_handle_switch_change;
1420ee138334Srajesh.shah@intel.com 	php_ctlr->presence_change_callback = shpchp_handle_presence_change;
1421ee138334Srajesh.shah@intel.com 	php_ctlr->power_fault_callback = shpchp_handle_power_fault;
14221da177e4SLinus Torvalds 	php_ctlr->callback_instance_id = instance_id;
14231da177e4SLinus Torvalds 
14241da177e4SLinus Torvalds 	/* Return PCI Controller Info */
14251da177e4SLinus Torvalds 	php_ctlr->slot_device_offset = (readl(php_ctlr->creg + SLOT_CONFIG) & FIRST_DEV_NUM ) >> 8;
14261da177e4SLinus Torvalds 	php_ctlr->num_slots = readl(php_ctlr->creg + SLOT_CONFIG) & SLOT_NUM;
14271da177e4SLinus Torvalds 	dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset);
14281da177e4SLinus Torvalds 	dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots);
14291da177e4SLinus Torvalds 
14301da177e4SLinus Torvalds 	/* Mask Global Interrupt Mask & Command Complete Interrupt Mask */
14311da177e4SLinus Torvalds 	tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
14321da177e4SLinus Torvalds 	dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
14331da177e4SLinus Torvalds 	tempdword = 0x0003000f;
14341da177e4SLinus Torvalds 	writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE);
14351da177e4SLinus Torvalds 	tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
14361da177e4SLinus Torvalds 	dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
14371da177e4SLinus Torvalds 
14381da177e4SLinus Torvalds 	/* Mask the MRL sensor SERR Mask of individual slot in
14391da177e4SLinus Torvalds 	 * Slot SERR-INT Mask & clear all the existing event if any
14401da177e4SLinus Torvalds 	 */
14411da177e4SLinus Torvalds 	for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) {
14421da177e4SLinus Torvalds 		slot_reg = readl(php_ctlr->creg + SLOT1 + 4*hp_slot );
14431da177e4SLinus Torvalds 		dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
14441da177e4SLinus Torvalds 			hp_slot, slot_reg);
14451da177e4SLinus Torvalds 		tempdword = 0xffff3fff;
14461da177e4SLinus Torvalds 		writel(tempdword, php_ctlr->creg + SLOT1 + (4*hp_slot));
14471da177e4SLinus Torvalds 	}
14481da177e4SLinus Torvalds 
14491da177e4SLinus Torvalds 	if (shpchp_poll_mode)  {/* Install interrupt polling code */
14501da177e4SLinus Torvalds 		/* Install and start the interrupt polling timer */
14511da177e4SLinus Torvalds 		init_timer(&php_ctlr->int_poll_timer);
14521da177e4SLinus Torvalds 		start_int_poll_timer( php_ctlr, 10 );   /* start with 10 second delay */
14531da177e4SLinus Torvalds 	} else {
14541da177e4SLinus Torvalds 		/* Installs the interrupt handler */
14551da177e4SLinus Torvalds 		rc = pci_enable_msi(pdev);
14561da177e4SLinus Torvalds 		if (rc) {
14571da177e4SLinus Torvalds 			info("Can't get msi for the hotplug controller\n");
14581da177e4SLinus Torvalds 			info("Use INTx for the hotplug controller\n");
14591da177e4SLinus Torvalds 		} else
14601da177e4SLinus Torvalds 			php_ctlr->irq = pdev->irq;
14611da177e4SLinus Torvalds 
14621da177e4SLinus Torvalds 		rc = request_irq(php_ctlr->irq, shpc_isr, SA_SHIRQ, MY_NAME, (void *) ctrl);
14631da177e4SLinus Torvalds 		dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
14641da177e4SLinus Torvalds 		if (rc) {
14651da177e4SLinus Torvalds 			err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
14661da177e4SLinus Torvalds 			goto abort_free_ctlr;
14671da177e4SLinus Torvalds 		}
14681da177e4SLinus Torvalds 	}
14697c8942f9Srajesh.shah@intel.com 	dbg("%s: HPC at b:d:f:irq=0x%x:%x:%x:%x\n", __FUNCTION__,
14707c8942f9Srajesh.shah@intel.com 			pdev->bus->number, PCI_SLOT(pdev->devfn),
14717c8942f9Srajesh.shah@intel.com 			PCI_FUNC(pdev->devfn), pdev->irq);
1472424600f9Srajesh.shah@intel.com 	get_hp_hw_control_from_firmware(pdev);
14731da177e4SLinus Torvalds 
14741da177e4SLinus Torvalds 	/*  Add this HPC instance into the HPC list */
14751da177e4SLinus Torvalds 	spin_lock(&list_lock);
14761da177e4SLinus Torvalds 	if (php_ctlr_list_head == 0) {
14771da177e4SLinus Torvalds 		php_ctlr_list_head = php_ctlr;
14781da177e4SLinus Torvalds 		p = php_ctlr_list_head;
14791da177e4SLinus Torvalds 		p->pnext = NULL;
14801da177e4SLinus Torvalds 	} else {
14811da177e4SLinus Torvalds 		p = php_ctlr_list_head;
14821da177e4SLinus Torvalds 
14831da177e4SLinus Torvalds 		while (p->pnext)
14841da177e4SLinus Torvalds 			p = p->pnext;
14851da177e4SLinus Torvalds 
14861da177e4SLinus Torvalds 		p->pnext = php_ctlr;
14871da177e4SLinus Torvalds 	}
14881da177e4SLinus Torvalds 	spin_unlock(&list_lock);
14891da177e4SLinus Torvalds 
14901da177e4SLinus Torvalds 
14911da177e4SLinus Torvalds 	ctlr_seq_num++;
14921da177e4SLinus Torvalds 	ctrl->hpc_ctlr_handle = php_ctlr;
14931da177e4SLinus Torvalds 	ctrl->hpc_ops = &shpchp_hpc_ops;
14941da177e4SLinus Torvalds 
14951da177e4SLinus Torvalds 	for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) {
14961da177e4SLinus Torvalds 		slot_reg = readl(php_ctlr->creg + SLOT1 + 4*hp_slot );
14971da177e4SLinus Torvalds 		dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
14981da177e4SLinus Torvalds 			hp_slot, slot_reg);
14991da177e4SLinus Torvalds 		tempdword = 0xe01f3fff;
15001da177e4SLinus Torvalds 		writel(tempdword, php_ctlr->creg + SLOT1 + (4*hp_slot));
15011da177e4SLinus Torvalds 	}
15021da177e4SLinus Torvalds 	if (!shpchp_poll_mode) {
15031da177e4SLinus Torvalds 		/* Unmask all general input interrupts and SERR */
15041da177e4SLinus Torvalds 		tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
15051da177e4SLinus Torvalds 		tempdword = 0x0000000a;
15061da177e4SLinus Torvalds 		writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE);
15071da177e4SLinus Torvalds 		tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
15081da177e4SLinus Torvalds 		dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
15091da177e4SLinus Torvalds 	}
15101da177e4SLinus Torvalds 
15111da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
15121da177e4SLinus Torvalds 	return 0;
15131da177e4SLinus Torvalds 
15141da177e4SLinus Torvalds 	/* We end up here for the many possible ways to fail this API.  */
15151da177e4SLinus Torvalds abort_free_ctlr:
15161da177e4SLinus Torvalds 	kfree(php_ctlr);
15171da177e4SLinus Torvalds abort:
15181da177e4SLinus Torvalds 	DBG_LEAVE_ROUTINE
15191da177e4SLinus Torvalds 	return -1;
15201da177e4SLinus Torvalds }
1521