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