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