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 /* Slot Configuration */ 861da177e4SLinus Torvalds #define SLOT_NUM 0x0000001F 871da177e4SLinus Torvalds #define FIRST_DEV_NUM 0x00001F00 881da177e4SLinus Torvalds #define PSN 0x07FF0000 891da177e4SLinus Torvalds #define UPDOWN 0x20000000 901da177e4SLinus Torvalds #define MRLSENSOR 0x40000000 911da177e4SLinus Torvalds #define ATTN_BUTTON 0x80000000 921da177e4SLinus Torvalds 932b34da7eSKenji Kaneshige /* 94e7138723SKenji Kaneshige * Controller SERR-INT Register 95e7138723SKenji Kaneshige */ 96e7138723SKenji Kaneshige #define GLOBAL_INTR_MASK (1 << 0) 97e7138723SKenji Kaneshige #define GLOBAL_SERR_MASK (1 << 1) 98e7138723SKenji Kaneshige #define COMMAND_INTR_MASK (1 << 2) 99e7138723SKenji Kaneshige #define ARBITER_SERR_MASK (1 << 3) 100e7138723SKenji Kaneshige #define COMMAND_DETECTED (1 << 16) 101e7138723SKenji Kaneshige #define ARBITER_DETECTED (1 << 17) 102e7138723SKenji Kaneshige #define SERR_INTR_RSVDZ_MASK 0xfffc0000 103e7138723SKenji Kaneshige 104e7138723SKenji Kaneshige /* 1052b34da7eSKenji Kaneshige * Logical Slot Register definitions 1062b34da7eSKenji Kaneshige */ 1072b34da7eSKenji Kaneshige #define SLOT_REG(i) (SLOT1 + (4 * i)) 1082b34da7eSKenji Kaneshige 1095858759cSKenji Kaneshige #define SLOT_STATE_SHIFT (0) 1105858759cSKenji Kaneshige #define SLOT_STATE_MASK (3 << 0) 1115858759cSKenji Kaneshige #define SLOT_STATE_PWRONLY (1) 1125858759cSKenji Kaneshige #define SLOT_STATE_ENABLED (2) 1135858759cSKenji Kaneshige #define SLOT_STATE_DISABLED (3) 1145858759cSKenji Kaneshige #define PWR_LED_STATE_SHIFT (2) 1155858759cSKenji Kaneshige #define PWR_LED_STATE_MASK (3 << 2) 1165858759cSKenji Kaneshige #define ATN_LED_STATE_SHIFT (4) 1175858759cSKenji Kaneshige #define ATN_LED_STATE_MASK (3 << 4) 1185858759cSKenji Kaneshige #define ATN_LED_STATE_ON (1) 1195858759cSKenji Kaneshige #define ATN_LED_STATE_BLINK (2) 1205858759cSKenji Kaneshige #define ATN_LED_STATE_OFF (3) 1215858759cSKenji Kaneshige #define POWER_FAULT (1 << 6) 1225858759cSKenji Kaneshige #define ATN_BUTTON (1 << 7) 1235858759cSKenji Kaneshige #define MRL_SENSOR (1 << 8) 1245858759cSKenji Kaneshige #define MHZ66_CAP (1 << 9) 1255858759cSKenji Kaneshige #define PRSNT_SHIFT (10) 1265858759cSKenji Kaneshige #define PRSNT_MASK (3 << 10) 1275858759cSKenji Kaneshige #define PCIX_CAP_SHIFT (12) 1285858759cSKenji Kaneshige #define PCIX_CAP_MASK_PI1 (3 << 12) 1295858759cSKenji Kaneshige #define PCIX_CAP_MASK_PI2 (7 << 12) 1305858759cSKenji Kaneshige #define PRSNT_CHANGE_DETECTED (1 << 16) 1315858759cSKenji Kaneshige #define ISO_PFAULT_DETECTED (1 << 17) 1325858759cSKenji Kaneshige #define BUTTON_PRESS_DETECTED (1 << 18) 1335858759cSKenji Kaneshige #define MRL_CHANGE_DETECTED (1 << 19) 1345858759cSKenji Kaneshige #define CON_PFAULT_DETECTED (1 << 20) 1355858759cSKenji Kaneshige #define PRSNT_CHANGE_INTR_MASK (1 << 24) 1365858759cSKenji Kaneshige #define ISO_PFAULT_INTR_MASK (1 << 25) 1375858759cSKenji Kaneshige #define BUTTON_PRESS_INTR_MASK (1 << 26) 1385858759cSKenji Kaneshige #define MRL_CHANGE_INTR_MASK (1 << 27) 1395858759cSKenji Kaneshige #define CON_PFAULT_INTR_MASK (1 << 28) 1405858759cSKenji Kaneshige #define MRL_CHANGE_SERR_MASK (1 << 29) 1415858759cSKenji Kaneshige #define CON_PFAULT_SERR_MASK (1 << 30) 1425858759cSKenji Kaneshige #define SLOT_REG_RSVDZ_MASK (1 << 15) | (7 << 21) 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds /* SHPC 'write' operations/commands */ 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds /* Slot operation - 0x00h to 0x3Fh */ 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds #define NO_CHANGE 0x00 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds /* Slot state - Bits 0 & 1 of controller command register */ 1511da177e4SLinus Torvalds #define SET_SLOT_PWR 0x01 1521da177e4SLinus Torvalds #define SET_SLOT_ENABLE 0x02 1531da177e4SLinus Torvalds #define SET_SLOT_DISABLE 0x03 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds /* Power indicator state - Bits 2 & 3 of controller command register*/ 1561da177e4SLinus Torvalds #define SET_PWR_ON 0x04 1571da177e4SLinus Torvalds #define SET_PWR_BLINK 0x08 1581da177e4SLinus Torvalds #define SET_PWR_OFF 0x0C 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds /* Attention indicator state - Bits 4 & 5 of controller command register*/ 1611da177e4SLinus Torvalds #define SET_ATTN_ON 0x010 1621da177e4SLinus Torvalds #define SET_ATTN_BLINK 0x020 1631da177e4SLinus Torvalds #define SET_ATTN_OFF 0x030 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds /* Set bus speed/mode A - 0x40h to 0x47h */ 1661da177e4SLinus Torvalds #define SETA_PCI_33MHZ 0x40 1671da177e4SLinus Torvalds #define SETA_PCI_66MHZ 0x41 1681da177e4SLinus Torvalds #define SETA_PCIX_66MHZ 0x42 1691da177e4SLinus Torvalds #define SETA_PCIX_100MHZ 0x43 1701da177e4SLinus Torvalds #define SETA_PCIX_133MHZ 0x44 1711da177e4SLinus Torvalds #define RESERV_1 0x45 1721da177e4SLinus Torvalds #define RESERV_2 0x46 1731da177e4SLinus Torvalds #define RESERV_3 0x47 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds /* Set bus speed/mode B - 0x50h to 0x5fh */ 1761da177e4SLinus Torvalds #define SETB_PCI_33MHZ 0x50 1771da177e4SLinus Torvalds #define SETB_PCI_66MHZ 0x51 1781da177e4SLinus Torvalds #define SETB_PCIX_66MHZ_PM 0x52 1791da177e4SLinus Torvalds #define SETB_PCIX_100MHZ_PM 0x53 1801da177e4SLinus Torvalds #define SETB_PCIX_133MHZ_PM 0x54 1811da177e4SLinus Torvalds #define SETB_PCIX_66MHZ_EM 0x55 1821da177e4SLinus Torvalds #define SETB_PCIX_100MHZ_EM 0x56 1831da177e4SLinus Torvalds #define SETB_PCIX_133MHZ_EM 0x57 1841da177e4SLinus Torvalds #define SETB_PCIX_66MHZ_266 0x58 1851da177e4SLinus Torvalds #define SETB_PCIX_100MHZ_266 0x59 1861da177e4SLinus Torvalds #define SETB_PCIX_133MHZ_266 0x5a 1871da177e4SLinus Torvalds #define SETB_PCIX_66MHZ_533 0x5b 1881da177e4SLinus Torvalds #define SETB_PCIX_100MHZ_533 0x5c 1891da177e4SLinus Torvalds #define SETB_PCIX_133MHZ_533 0x5d 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds /* Power-on all slots - 0x48h */ 1931da177e4SLinus Torvalds #define SET_PWR_ON_ALL 0x48 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds /* Enable all slots - 0x49h */ 1961da177e4SLinus Torvalds #define SET_ENABLE_ALL 0x49 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds /* SHPC controller command error code */ 1991da177e4SLinus Torvalds #define SWITCH_OPEN 0x1 2001da177e4SLinus Torvalds #define INVALID_CMD 0x2 2011da177e4SLinus Torvalds #define INVALID_SPEED_MODE 0x4 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds /* For accessing SHPC Working Register Set */ 2041da177e4SLinus Torvalds #define DWORD_SELECT 0x2 2051da177e4SLinus Torvalds #define DWORD_DATA 0x4 2061da177e4SLinus Torvalds #define BASE_OFFSET 0x0 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds /* Field Offset in Logical Slot Register - byte boundary */ 2091da177e4SLinus Torvalds #define SLOT_EVENT_LATCH 0x2 2101da177e4SLinus Torvalds #define SLOT_SERR_INT_MASK 0x3 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds static spinlock_t hpc_event_lock; 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ 2151da177e4SLinus Torvalds static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */ 2161da177e4SLinus Torvalds static int ctlr_seq_num = 0; /* Controller sequenc # */ 2171da177e4SLinus Torvalds static spinlock_t list_lock; 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs); 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds); 222d29aaddaSKenji Kaneshige static int hpc_check_cmd_status(struct controller *ctrl); 2231da177e4SLinus Torvalds 22475d97c59SKenji Kaneshige static inline u8 shpc_readb(struct controller *ctrl, int reg) 22575d97c59SKenji Kaneshige { 22675d97c59SKenji Kaneshige return readb(ctrl->hpc_ctlr_handle->creg + reg); 22775d97c59SKenji Kaneshige } 22875d97c59SKenji Kaneshige 22975d97c59SKenji Kaneshige static inline void shpc_writeb(struct controller *ctrl, int reg, u8 val) 23075d97c59SKenji Kaneshige { 23175d97c59SKenji Kaneshige writeb(val, ctrl->hpc_ctlr_handle->creg + reg); 23275d97c59SKenji Kaneshige } 23375d97c59SKenji Kaneshige 23475d97c59SKenji Kaneshige static inline u16 shpc_readw(struct controller *ctrl, int reg) 23575d97c59SKenji Kaneshige { 23675d97c59SKenji Kaneshige return readw(ctrl->hpc_ctlr_handle->creg + reg); 23775d97c59SKenji Kaneshige } 23875d97c59SKenji Kaneshige 23975d97c59SKenji Kaneshige static inline void shpc_writew(struct controller *ctrl, int reg, u16 val) 24075d97c59SKenji Kaneshige { 24175d97c59SKenji Kaneshige writew(val, ctrl->hpc_ctlr_handle->creg + reg); 24275d97c59SKenji Kaneshige } 24375d97c59SKenji Kaneshige 24475d97c59SKenji Kaneshige static inline u32 shpc_readl(struct controller *ctrl, int reg) 24575d97c59SKenji Kaneshige { 24675d97c59SKenji Kaneshige return readl(ctrl->hpc_ctlr_handle->creg + reg); 24775d97c59SKenji Kaneshige } 24875d97c59SKenji Kaneshige 24975d97c59SKenji Kaneshige static inline void shpc_writel(struct controller *ctrl, int reg, u32 val) 25075d97c59SKenji Kaneshige { 25175d97c59SKenji Kaneshige writel(val, ctrl->hpc_ctlr_handle->creg + reg); 25275d97c59SKenji Kaneshige } 25375d97c59SKenji Kaneshige 25475d97c59SKenji Kaneshige static inline int shpc_indirect_read(struct controller *ctrl, int index, 25575d97c59SKenji Kaneshige u32 *value) 25675d97c59SKenji Kaneshige { 25775d97c59SKenji Kaneshige int rc; 25875d97c59SKenji Kaneshige u32 cap_offset = ctrl->cap_offset; 25975d97c59SKenji Kaneshige struct pci_dev *pdev = ctrl->pci_dev; 26075d97c59SKenji Kaneshige 26175d97c59SKenji Kaneshige rc = pci_write_config_byte(pdev, cap_offset + DWORD_SELECT, index); 26275d97c59SKenji Kaneshige if (rc) 26375d97c59SKenji Kaneshige return rc; 26475d97c59SKenji Kaneshige return pci_read_config_dword(pdev, cap_offset + DWORD_DATA, value); 26575d97c59SKenji Kaneshige } 26675d97c59SKenji Kaneshige 2671da177e4SLinus Torvalds /* This is the interrupt polling timeout function. */ 2681da177e4SLinus Torvalds static void int_poll_timeout(unsigned long lphp_ctlr) 2691da177e4SLinus Torvalds { 2701da177e4SLinus Torvalds struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr; 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds DBG_ENTER_ROUTINE 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds if ( !php_ctlr ) { 2751da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 2761da177e4SLinus Torvalds return; 2771da177e4SLinus Torvalds } 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds /* Poll for interrupt events. regs == NULL => polling */ 2801da177e4SLinus Torvalds shpc_isr( 0, (void *)php_ctlr, NULL ); 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds init_timer(&php_ctlr->int_poll_timer); 2831da177e4SLinus Torvalds if (!shpchp_poll_time) 2841da177e4SLinus Torvalds shpchp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/ 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds start_int_poll_timer(php_ctlr, shpchp_poll_time); 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds return; 2891da177e4SLinus Torvalds } 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds /* This function starts the interrupt polling timer. */ 2921da177e4SLinus Torvalds static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds) 2931da177e4SLinus Torvalds { 2941da177e4SLinus Torvalds if (!php_ctlr) { 2951da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 2961da177e4SLinus Torvalds return; 2971da177e4SLinus Torvalds } 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds if ( ( seconds <= 0 ) || ( seconds > 60 ) ) 3001da177e4SLinus Torvalds seconds = 2; /* Clamp to sane value */ 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds php_ctlr->int_poll_timer.function = &int_poll_timeout; 3031da177e4SLinus Torvalds php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr; /* Instance data */ 3041da177e4SLinus Torvalds php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ; 3051da177e4SLinus Torvalds add_timer(&php_ctlr->int_poll_timer); 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds return; 3081da177e4SLinus Torvalds } 3091da177e4SLinus Torvalds 310bd62e271SKenji Kaneshige static inline int shpc_wait_cmd(struct controller *ctrl) 311bd62e271SKenji Kaneshige { 312bd62e271SKenji Kaneshige int retval = 0; 313bd62e271SKenji Kaneshige unsigned int timeout_msec = shpchp_poll_mode ? 2000 : 1000; 314bd62e271SKenji Kaneshige unsigned long timeout = msecs_to_jiffies(timeout_msec); 315bd62e271SKenji Kaneshige int rc = wait_event_interruptible_timeout(ctrl->queue, 316bd62e271SKenji Kaneshige !ctrl->cmd_busy, timeout); 317bd62e271SKenji Kaneshige if (!rc) { 318bd62e271SKenji Kaneshige retval = -EIO; 319bd62e271SKenji Kaneshige err("Command not completed in %d msec\n", timeout_msec); 320bd62e271SKenji Kaneshige } else if (rc < 0) { 321bd62e271SKenji Kaneshige retval = -EINTR; 322bd62e271SKenji Kaneshige info("Command was interrupted by a signal\n"); 323bd62e271SKenji Kaneshige } 324bd62e271SKenji Kaneshige ctrl->cmd_busy = 0; 325bd62e271SKenji Kaneshige 326bd62e271SKenji Kaneshige return retval; 327bd62e271SKenji Kaneshige } 328bd62e271SKenji Kaneshige 3291da177e4SLinus Torvalds static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) 3301da177e4SLinus Torvalds { 331ee138334Srajesh.shah@intel.com struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; 33275d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 3331da177e4SLinus Torvalds u16 cmd_status; 3341da177e4SLinus Torvalds int retval = 0; 3351da177e4SLinus Torvalds u16 temp_word; 3361da177e4SLinus Torvalds int i; 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds DBG_ENTER_ROUTINE 3391da177e4SLinus Torvalds 340d29aaddaSKenji Kaneshige mutex_lock(&slot->ctrl->cmd_lock); 341d29aaddaSKenji Kaneshige 3421da177e4SLinus Torvalds if (!php_ctlr) { 3431da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 344d29aaddaSKenji Kaneshige retval = -EINVAL; 345d29aaddaSKenji Kaneshige goto out; 3461da177e4SLinus Torvalds } 3471da177e4SLinus Torvalds 3481da177e4SLinus Torvalds for (i = 0; i < 10; i++) { 34975d97c59SKenji Kaneshige cmd_status = shpc_readw(ctrl, CMD_STATUS); 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds if (!(cmd_status & 0x1)) 3521da177e4SLinus Torvalds break; 3531da177e4SLinus Torvalds /* Check every 0.1 sec for a total of 1 sec*/ 3541da177e4SLinus Torvalds msleep(100); 3551da177e4SLinus Torvalds } 3561da177e4SLinus Torvalds 35775d97c59SKenji Kaneshige cmd_status = shpc_readw(ctrl, CMD_STATUS); 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds if (cmd_status & 0x1) { 3601da177e4SLinus Torvalds /* After 1 sec and and the controller is still busy */ 3611da177e4SLinus Torvalds err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__); 362d29aaddaSKenji Kaneshige retval = -EBUSY; 363d29aaddaSKenji Kaneshige goto out; 3641da177e4SLinus Torvalds } 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds ++t_slot; 3671da177e4SLinus Torvalds temp_word = (t_slot << 8) | (cmd & 0xFF); 3681da177e4SLinus Torvalds dbg("%s: t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd); 3691da177e4SLinus Torvalds 3701da177e4SLinus Torvalds /* To make sure the Controller Busy bit is 0 before we send out the 3711da177e4SLinus Torvalds * command. 3721da177e4SLinus Torvalds */ 373bd62e271SKenji Kaneshige slot->ctrl->cmd_busy = 1; 37475d97c59SKenji Kaneshige shpc_writew(ctrl, CMD, temp_word); 3751da177e4SLinus Torvalds 376bd62e271SKenji Kaneshige /* 377bd62e271SKenji Kaneshige * Wait for command completion. 378bd62e271SKenji Kaneshige */ 379bd62e271SKenji Kaneshige retval = shpc_wait_cmd(slot->ctrl); 380d29aaddaSKenji Kaneshige if (retval) 381d29aaddaSKenji Kaneshige goto out; 382d29aaddaSKenji Kaneshige 383d29aaddaSKenji Kaneshige cmd_status = hpc_check_cmd_status(slot->ctrl); 384d29aaddaSKenji Kaneshige if (cmd_status) { 385d29aaddaSKenji Kaneshige err("%s: Failed to issued command 0x%x (error code = %d)\n", 386d29aaddaSKenji Kaneshige __FUNCTION__, cmd, cmd_status); 387d29aaddaSKenji Kaneshige retval = -EIO; 388d29aaddaSKenji Kaneshige } 389d29aaddaSKenji Kaneshige out: 390d29aaddaSKenji Kaneshige mutex_unlock(&slot->ctrl->cmd_lock); 391bd62e271SKenji Kaneshige 3921da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 3931da177e4SLinus Torvalds return retval; 3941da177e4SLinus Torvalds } 3951da177e4SLinus Torvalds 3961da177e4SLinus Torvalds static int hpc_check_cmd_status(struct controller *ctrl) 3971da177e4SLinus Torvalds { 3981da177e4SLinus Torvalds u16 cmd_status; 3991da177e4SLinus Torvalds int retval = 0; 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds DBG_ENTER_ROUTINE 4021da177e4SLinus Torvalds 4031da177e4SLinus Torvalds if (!ctrl->hpc_ctlr_handle) { 4041da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 4051da177e4SLinus Torvalds return -1; 4061da177e4SLinus Torvalds } 4071da177e4SLinus Torvalds 40875d97c59SKenji Kaneshige cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F; 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds switch (cmd_status >> 1) { 4111da177e4SLinus Torvalds case 0: 4121da177e4SLinus Torvalds retval = 0; 4131da177e4SLinus Torvalds break; 4141da177e4SLinus Torvalds case 1: 4151da177e4SLinus Torvalds retval = SWITCH_OPEN; 4161da177e4SLinus Torvalds err("%s: Switch opened!\n", __FUNCTION__); 4171da177e4SLinus Torvalds break; 4181da177e4SLinus Torvalds case 2: 4191da177e4SLinus Torvalds retval = INVALID_CMD; 4201da177e4SLinus Torvalds err("%s: Invalid HPC command!\n", __FUNCTION__); 4211da177e4SLinus Torvalds break; 4221da177e4SLinus Torvalds case 4: 4231da177e4SLinus Torvalds retval = INVALID_SPEED_MODE; 4241da177e4SLinus Torvalds err("%s: Invalid bus speed/mode!\n", __FUNCTION__); 4251da177e4SLinus Torvalds break; 4261da177e4SLinus Torvalds default: 4271da177e4SLinus Torvalds retval = cmd_status; 4281da177e4SLinus Torvalds } 4291da177e4SLinus Torvalds 4301da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 4311da177e4SLinus Torvalds return retval; 4321da177e4SLinus Torvalds } 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds 4351da177e4SLinus Torvalds static int hpc_get_attention_status(struct slot *slot, u8 *status) 4361da177e4SLinus Torvalds { 43775d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 4381da177e4SLinus Torvalds u32 slot_reg; 4395858759cSKenji Kaneshige u8 state; 4401da177e4SLinus Torvalds 4411da177e4SLinus Torvalds DBG_ENTER_ROUTINE 4421da177e4SLinus Torvalds 4431da177e4SLinus Torvalds if (!slot->ctrl->hpc_ctlr_handle) { 4441da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 4451da177e4SLinus Torvalds return -1; 4461da177e4SLinus Torvalds } 4471da177e4SLinus Torvalds 4482b34da7eSKenji Kaneshige slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); 4495858759cSKenji Kaneshige state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT; 4501da177e4SLinus Torvalds 4515858759cSKenji Kaneshige switch (state) { 4525858759cSKenji Kaneshige case ATN_LED_STATE_ON: 4531da177e4SLinus Torvalds *status = 1; /* On */ 4541da177e4SLinus Torvalds break; 4555858759cSKenji Kaneshige case ATN_LED_STATE_BLINK: 4561da177e4SLinus Torvalds *status = 2; /* Blink */ 4571da177e4SLinus Torvalds break; 4585858759cSKenji Kaneshige case ATN_LED_STATE_OFF: 4591da177e4SLinus Torvalds *status = 0; /* Off */ 4601da177e4SLinus Torvalds break; 4611da177e4SLinus Torvalds default: 4625858759cSKenji Kaneshige *status = 0xFF; /* Reserved */ 4631da177e4SLinus Torvalds break; 4641da177e4SLinus Torvalds } 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 4671da177e4SLinus Torvalds return 0; 4681da177e4SLinus Torvalds } 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds static int hpc_get_power_status(struct slot * slot, u8 *status) 4711da177e4SLinus Torvalds { 47275d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 4731da177e4SLinus Torvalds u32 slot_reg; 4745858759cSKenji Kaneshige u8 state; 4751da177e4SLinus Torvalds 4761da177e4SLinus Torvalds DBG_ENTER_ROUTINE 4771da177e4SLinus Torvalds 4781da177e4SLinus Torvalds if (!slot->ctrl->hpc_ctlr_handle) { 4791da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 4801da177e4SLinus Torvalds return -1; 4811da177e4SLinus Torvalds } 4821da177e4SLinus Torvalds 4832b34da7eSKenji Kaneshige slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); 4845858759cSKenji Kaneshige state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT; 4851da177e4SLinus Torvalds 4865858759cSKenji Kaneshige switch (state) { 4875858759cSKenji Kaneshige case SLOT_STATE_PWRONLY: 4881da177e4SLinus Torvalds *status = 2; /* Powered only */ 4891da177e4SLinus Torvalds break; 4905858759cSKenji Kaneshige case SLOT_STATE_ENABLED: 4911da177e4SLinus Torvalds *status = 1; /* Enabled */ 4921da177e4SLinus Torvalds break; 4935858759cSKenji Kaneshige case SLOT_STATE_DISABLED: 4941da177e4SLinus Torvalds *status = 0; /* Disabled */ 4951da177e4SLinus Torvalds break; 4961da177e4SLinus Torvalds default: 4975858759cSKenji Kaneshige *status = 0xFF; /* Reserved */ 4981da177e4SLinus Torvalds break; 4991da177e4SLinus Torvalds } 5001da177e4SLinus Torvalds 5011da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 5025858759cSKenji Kaneshige return 0; 5031da177e4SLinus Torvalds } 5041da177e4SLinus Torvalds 5051da177e4SLinus Torvalds 5061da177e4SLinus Torvalds static int hpc_get_latch_status(struct slot *slot, u8 *status) 5071da177e4SLinus Torvalds { 50875d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 5091da177e4SLinus Torvalds u32 slot_reg; 5101da177e4SLinus Torvalds 5111da177e4SLinus Torvalds DBG_ENTER_ROUTINE 5121da177e4SLinus Torvalds 5131da177e4SLinus Torvalds if (!slot->ctrl->hpc_ctlr_handle) { 5141da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 5151da177e4SLinus Torvalds return -1; 5161da177e4SLinus Torvalds } 5171da177e4SLinus Torvalds 5182b34da7eSKenji Kaneshige slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); 5195858759cSKenji Kaneshige *status = !!(slot_reg & MRL_SENSOR); /* 0 -> close; 1 -> open */ 5201da177e4SLinus Torvalds 5211da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 5221da177e4SLinus Torvalds return 0; 5231da177e4SLinus Torvalds } 5241da177e4SLinus Torvalds 5251da177e4SLinus Torvalds static int hpc_get_adapter_status(struct slot *slot, u8 *status) 5261da177e4SLinus Torvalds { 52775d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 5281da177e4SLinus Torvalds u32 slot_reg; 5295858759cSKenji Kaneshige u8 state; 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds DBG_ENTER_ROUTINE 5321da177e4SLinus Torvalds 5331da177e4SLinus Torvalds if (!slot->ctrl->hpc_ctlr_handle) { 5341da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 5351da177e4SLinus Torvalds return -1; 5361da177e4SLinus Torvalds } 5371da177e4SLinus Torvalds 5382b34da7eSKenji Kaneshige slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); 5395858759cSKenji Kaneshige state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT; 5405858759cSKenji Kaneshige *status = (state != 0x3) ? 1 : 0; 5411da177e4SLinus Torvalds 5421da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 5431da177e4SLinus Torvalds return 0; 5441da177e4SLinus Torvalds } 5451da177e4SLinus Torvalds 5461da177e4SLinus Torvalds static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) 5471da177e4SLinus Torvalds { 54875d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 5491da177e4SLinus Torvalds 5501da177e4SLinus Torvalds DBG_ENTER_ROUTINE 5511da177e4SLinus Torvalds 5521da177e4SLinus Torvalds if (!slot->ctrl->hpc_ctlr_handle) { 5531da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 5541da177e4SLinus Torvalds return -1; 5551da177e4SLinus Torvalds } 5561da177e4SLinus Torvalds 55775d97c59SKenji Kaneshige *prog_int = shpc_readb(ctrl, PROG_INTERFACE); 5581da177e4SLinus Torvalds 5591da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 5601da177e4SLinus Torvalds return 0; 5611da177e4SLinus Torvalds } 5621da177e4SLinus Torvalds 5631da177e4SLinus Torvalds static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) 5641da177e4SLinus Torvalds { 5651da177e4SLinus Torvalds int retval = 0; 56675d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 5672b34da7eSKenji Kaneshige u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); 5685858759cSKenji Kaneshige u8 m66_cap = !!(slot_reg & MHZ66_CAP); 569795eb5c4SKenji Kaneshige u8 pi, pcix_cap; 5701da177e4SLinus Torvalds 5711da177e4SLinus Torvalds DBG_ENTER_ROUTINE 5721da177e4SLinus Torvalds 573795eb5c4SKenji Kaneshige if ((retval = hpc_get_prog_int(slot, &pi))) 574795eb5c4SKenji Kaneshige return retval; 575795eb5c4SKenji Kaneshige 576795eb5c4SKenji Kaneshige switch (pi) { 577795eb5c4SKenji Kaneshige case 1: 578795eb5c4SKenji Kaneshige pcix_cap = (slot_reg & PCIX_CAP_MASK_PI1) >> PCIX_CAP_SHIFT; 579795eb5c4SKenji Kaneshige break; 580795eb5c4SKenji Kaneshige case 2: 581795eb5c4SKenji Kaneshige pcix_cap = (slot_reg & PCIX_CAP_MASK_PI2) >> PCIX_CAP_SHIFT; 582795eb5c4SKenji Kaneshige break; 583795eb5c4SKenji Kaneshige default: 584795eb5c4SKenji Kaneshige return -ENODEV; 585795eb5c4SKenji Kaneshige } 586795eb5c4SKenji Kaneshige 5870afabe90SKenji Kaneshige dbg("%s: slot_reg = %x, pcix_cap = %x, m66_cap = %x\n", 5880afabe90SKenji Kaneshige __FUNCTION__, slot_reg, pcix_cap, m66_cap); 5891da177e4SLinus Torvalds 5901da177e4SLinus Torvalds switch (pcix_cap) { 5910afabe90SKenji Kaneshige case 0x0: 5921da177e4SLinus Torvalds *value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; 5931da177e4SLinus Torvalds break; 5940afabe90SKenji Kaneshige case 0x1: 5951da177e4SLinus Torvalds *value = PCI_SPEED_66MHz_PCIX; 5961da177e4SLinus Torvalds break; 5970afabe90SKenji Kaneshige case 0x3: 5981da177e4SLinus Torvalds *value = PCI_SPEED_133MHz_PCIX; 5991da177e4SLinus Torvalds break; 6000afabe90SKenji Kaneshige case 0x4: 6011da177e4SLinus Torvalds *value = PCI_SPEED_133MHz_PCIX_266; 6021da177e4SLinus Torvalds break; 6030afabe90SKenji Kaneshige case 0x5: 6041da177e4SLinus Torvalds *value = PCI_SPEED_133MHz_PCIX_533; 6051da177e4SLinus Torvalds break; 6060afabe90SKenji Kaneshige case 0x2: 6071da177e4SLinus Torvalds default: 6081da177e4SLinus Torvalds *value = PCI_SPEED_UNKNOWN; 6091da177e4SLinus Torvalds retval = -ENODEV; 6101da177e4SLinus Torvalds break; 6111da177e4SLinus Torvalds } 6121da177e4SLinus Torvalds 6131da177e4SLinus Torvalds dbg("Adapter speed = %d\n", *value); 6141da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 6151da177e4SLinus Torvalds return retval; 6161da177e4SLinus Torvalds } 6171da177e4SLinus Torvalds 6181da177e4SLinus Torvalds static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) 6191da177e4SLinus Torvalds { 62075d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 6211da177e4SLinus Torvalds u16 sec_bus_status; 6221da177e4SLinus Torvalds u8 pi; 6231da177e4SLinus Torvalds int retval = 0; 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 63275d97c59SKenji Kaneshige pi = shpc_readb(ctrl, PROG_INTERFACE); 63375d97c59SKenji Kaneshige sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG); 6341da177e4SLinus Torvalds 6351da177e4SLinus Torvalds if (pi == 2) { 63687d6c559SKenji Kaneshige *mode = (sec_bus_status & 0x0100) >> 8; 6371da177e4SLinus Torvalds } else { 6381da177e4SLinus Torvalds retval = -1; 6391da177e4SLinus Torvalds } 6401da177e4SLinus Torvalds 6411da177e4SLinus Torvalds dbg("Mode 1 ECC cap = %d\n", *mode); 6421da177e4SLinus Torvalds 6431da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 6441da177e4SLinus Torvalds return retval; 6451da177e4SLinus Torvalds } 6461da177e4SLinus Torvalds 6471da177e4SLinus Torvalds static int hpc_query_power_fault(struct slot * slot) 6481da177e4SLinus Torvalds { 64975d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 6501da177e4SLinus Torvalds u32 slot_reg; 6511da177e4SLinus Torvalds 6521da177e4SLinus Torvalds DBG_ENTER_ROUTINE 6531da177e4SLinus Torvalds 6541da177e4SLinus Torvalds if (!slot->ctrl->hpc_ctlr_handle) { 6551da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 6561da177e4SLinus Torvalds return -1; 6571da177e4SLinus Torvalds } 6581da177e4SLinus Torvalds 6592b34da7eSKenji Kaneshige slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); 6601da177e4SLinus Torvalds 6611da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 6621da177e4SLinus Torvalds /* Note: Logic 0 => fault */ 6635858759cSKenji Kaneshige return !(slot_reg & POWER_FAULT); 6641da177e4SLinus Torvalds } 6651da177e4SLinus Torvalds 6661da177e4SLinus Torvalds static int hpc_set_attention_status(struct slot *slot, u8 value) 6671da177e4SLinus Torvalds { 668ee138334Srajesh.shah@intel.com struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; 6691da177e4SLinus Torvalds u8 slot_cmd = 0; 6701da177e4SLinus Torvalds int rc = 0; 6711da177e4SLinus Torvalds 6721da177e4SLinus Torvalds if (!slot->ctrl->hpc_ctlr_handle) { 6731da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 6741da177e4SLinus Torvalds return -1; 6751da177e4SLinus Torvalds } 6761da177e4SLinus Torvalds 6771da177e4SLinus Torvalds if (slot->hp_slot >= php_ctlr->num_slots) { 6781da177e4SLinus Torvalds err("%s: Invalid HPC slot number!\n", __FUNCTION__); 6791da177e4SLinus Torvalds return -1; 6801da177e4SLinus Torvalds } 6811da177e4SLinus Torvalds 6821da177e4SLinus Torvalds switch (value) { 6831da177e4SLinus Torvalds case 0 : 6841da177e4SLinus Torvalds slot_cmd = 0x30; /* OFF */ 6851da177e4SLinus Torvalds break; 6861da177e4SLinus Torvalds case 1: 6871da177e4SLinus Torvalds slot_cmd = 0x10; /* ON */ 6881da177e4SLinus Torvalds break; 6891da177e4SLinus Torvalds case 2: 6901da177e4SLinus Torvalds slot_cmd = 0x20; /* BLINK */ 6911da177e4SLinus Torvalds break; 6921da177e4SLinus Torvalds default: 6931da177e4SLinus Torvalds return -1; 6941da177e4SLinus Torvalds } 6951da177e4SLinus Torvalds 6961da177e4SLinus Torvalds shpc_write_cmd(slot, slot->hp_slot, slot_cmd); 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds return rc; 6991da177e4SLinus Torvalds } 7001da177e4SLinus Torvalds 7011da177e4SLinus Torvalds 7021da177e4SLinus Torvalds static void hpc_set_green_led_on(struct slot *slot) 7031da177e4SLinus Torvalds { 704ee138334Srajesh.shah@intel.com struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; 7051da177e4SLinus Torvalds u8 slot_cmd; 7061da177e4SLinus Torvalds 7071da177e4SLinus Torvalds if (!slot->ctrl->hpc_ctlr_handle) { 7081da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 7091da177e4SLinus Torvalds return ; 7101da177e4SLinus Torvalds } 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds if (slot->hp_slot >= php_ctlr->num_slots) { 7131da177e4SLinus Torvalds err("%s: Invalid HPC slot number!\n", __FUNCTION__); 7141da177e4SLinus Torvalds return ; 7151da177e4SLinus Torvalds } 7161da177e4SLinus Torvalds 7171da177e4SLinus Torvalds slot_cmd = 0x04; 7181da177e4SLinus Torvalds 7191da177e4SLinus Torvalds shpc_write_cmd(slot, slot->hp_slot, slot_cmd); 7201da177e4SLinus Torvalds 7211da177e4SLinus Torvalds return; 7221da177e4SLinus Torvalds } 7231da177e4SLinus Torvalds 7241da177e4SLinus Torvalds static void hpc_set_green_led_off(struct slot *slot) 7251da177e4SLinus Torvalds { 726ee138334Srajesh.shah@intel.com struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; 7271da177e4SLinus Torvalds u8 slot_cmd; 7281da177e4SLinus Torvalds 7291da177e4SLinus Torvalds if (!slot->ctrl->hpc_ctlr_handle) { 7301da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 7311da177e4SLinus Torvalds return ; 7321da177e4SLinus Torvalds } 7331da177e4SLinus Torvalds 7341da177e4SLinus Torvalds if (slot->hp_slot >= php_ctlr->num_slots) { 7351da177e4SLinus Torvalds err("%s: Invalid HPC slot number!\n", __FUNCTION__); 7361da177e4SLinus Torvalds return ; 7371da177e4SLinus Torvalds } 7381da177e4SLinus Torvalds 7391da177e4SLinus Torvalds slot_cmd = 0x0C; 7401da177e4SLinus Torvalds 7411da177e4SLinus Torvalds shpc_write_cmd(slot, slot->hp_slot, slot_cmd); 7421da177e4SLinus Torvalds 7431da177e4SLinus Torvalds return; 7441da177e4SLinus Torvalds } 7451da177e4SLinus Torvalds 7461da177e4SLinus Torvalds static void hpc_set_green_led_blink(struct slot *slot) 7471da177e4SLinus Torvalds { 748ee138334Srajesh.shah@intel.com struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; 7491da177e4SLinus Torvalds u8 slot_cmd; 7501da177e4SLinus Torvalds 7511da177e4SLinus Torvalds if (!slot->ctrl->hpc_ctlr_handle) { 7521da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 7531da177e4SLinus Torvalds return ; 7541da177e4SLinus Torvalds } 7551da177e4SLinus Torvalds 7561da177e4SLinus Torvalds if (slot->hp_slot >= php_ctlr->num_slots) { 7571da177e4SLinus Torvalds err("%s: Invalid HPC slot number!\n", __FUNCTION__); 7581da177e4SLinus Torvalds return ; 7591da177e4SLinus Torvalds } 7601da177e4SLinus Torvalds 7611da177e4SLinus Torvalds slot_cmd = 0x08; 7621da177e4SLinus Torvalds 7631da177e4SLinus Torvalds shpc_write_cmd(slot, slot->hp_slot, slot_cmd); 7641da177e4SLinus Torvalds 7651da177e4SLinus Torvalds return; 7661da177e4SLinus Torvalds } 7671da177e4SLinus Torvalds 7681da177e4SLinus Torvalds int shpc_get_ctlr_slot_config(struct controller *ctrl, 7691da177e4SLinus Torvalds int *num_ctlr_slots, /* number of slots in this HPC */ 7701da177e4SLinus Torvalds int *first_device_num, /* PCI dev num of the first slot in this SHPC */ 7711da177e4SLinus Torvalds int *physical_slot_num, /* phy slot num of the first slot in this SHPC */ 7721da177e4SLinus Torvalds int *updown, /* physical_slot_num increament: 1 or -1 */ 7731da177e4SLinus Torvalds int *flags) 7741da177e4SLinus Torvalds { 77575d97c59SKenji Kaneshige u32 slot_config; 7761da177e4SLinus Torvalds 7771da177e4SLinus Torvalds DBG_ENTER_ROUTINE 7781da177e4SLinus Torvalds 7791da177e4SLinus Torvalds if (!ctrl->hpc_ctlr_handle) { 7801da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 7811da177e4SLinus Torvalds return -1; 7821da177e4SLinus Torvalds } 7831da177e4SLinus Torvalds 78475d97c59SKenji Kaneshige slot_config = shpc_readl(ctrl, SLOT_CONFIG); 78575d97c59SKenji Kaneshige *first_device_num = (slot_config & FIRST_DEV_NUM) >> 8; 78675d97c59SKenji Kaneshige *num_ctlr_slots = slot_config & SLOT_NUM; 78775d97c59SKenji Kaneshige *physical_slot_num = (slot_config & PSN) >> 16; 78875d97c59SKenji Kaneshige *updown = ((slot_config & UPDOWN) >> 29) ? 1 : -1; 7891da177e4SLinus Torvalds 7901da177e4SLinus Torvalds dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num); 7911da177e4SLinus Torvalds 7921da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 7931da177e4SLinus Torvalds return 0; 7941da177e4SLinus Torvalds } 7951da177e4SLinus Torvalds 7961da177e4SLinus Torvalds static void hpc_release_ctlr(struct controller *ctrl) 7971da177e4SLinus Torvalds { 798ee138334Srajesh.shah@intel.com struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; 7991da177e4SLinus Torvalds struct php_ctlr_state_s *p, *p_prev; 800f7391f53SKenji Kaneshige int i; 801795eb5c4SKenji Kaneshige u32 slot_reg; 8021da177e4SLinus Torvalds 8031da177e4SLinus Torvalds DBG_ENTER_ROUTINE 8041da177e4SLinus Torvalds 8051da177e4SLinus Torvalds if (!ctrl->hpc_ctlr_handle) { 8061da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 8071da177e4SLinus Torvalds return ; 8081da177e4SLinus Torvalds } 8091da177e4SLinus Torvalds 810f7391f53SKenji Kaneshige /* 811795eb5c4SKenji Kaneshige * Mask event interrupts and SERRs of all slots 812f7391f53SKenji Kaneshige */ 813795eb5c4SKenji Kaneshige for (i = 0; i < ctrl->num_slots; i++) { 814795eb5c4SKenji Kaneshige slot_reg = shpc_readl(ctrl, SLOT_REG(i)); 815795eb5c4SKenji Kaneshige slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | 816795eb5c4SKenji Kaneshige BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | 817795eb5c4SKenji Kaneshige CON_PFAULT_INTR_MASK | MRL_CHANGE_SERR_MASK | 818795eb5c4SKenji Kaneshige CON_PFAULT_SERR_MASK); 819795eb5c4SKenji Kaneshige slot_reg &= ~SLOT_REG_RSVDZ_MASK; 820795eb5c4SKenji Kaneshige shpc_writel(ctrl, SLOT_REG(i), slot_reg); 821795eb5c4SKenji Kaneshige } 822f7391f53SKenji Kaneshige 823f7391f53SKenji Kaneshige cleanup_slots(ctrl); 824f7391f53SKenji Kaneshige 8251da177e4SLinus Torvalds if (shpchp_poll_mode) { 8261da177e4SLinus Torvalds del_timer(&php_ctlr->int_poll_timer); 8271da177e4SLinus Torvalds } else { 8281da177e4SLinus Torvalds if (php_ctlr->irq) { 8291da177e4SLinus Torvalds free_irq(php_ctlr->irq, ctrl); 8301da177e4SLinus Torvalds php_ctlr->irq = 0; 8311da177e4SLinus Torvalds pci_disable_msi(php_ctlr->pci_dev); 8321da177e4SLinus Torvalds } 8331da177e4SLinus Torvalds } 834f7391f53SKenji Kaneshige 8351da177e4SLinus Torvalds if (php_ctlr->pci_dev) { 8361da177e4SLinus Torvalds iounmap(php_ctlr->creg); 8370455986cSKenji Kaneshige release_mem_region(ctrl->mmio_base, ctrl->mmio_size); 8381da177e4SLinus Torvalds php_ctlr->pci_dev = NULL; 8391da177e4SLinus Torvalds } 8401da177e4SLinus Torvalds 8411da177e4SLinus Torvalds spin_lock(&list_lock); 8421da177e4SLinus Torvalds p = php_ctlr_list_head; 8431da177e4SLinus Torvalds p_prev = NULL; 8441da177e4SLinus Torvalds while (p) { 8451da177e4SLinus Torvalds if (p == php_ctlr) { 8461da177e4SLinus Torvalds if (p_prev) 8471da177e4SLinus Torvalds p_prev->pnext = p->pnext; 8481da177e4SLinus Torvalds else 8491da177e4SLinus Torvalds php_ctlr_list_head = p->pnext; 8501da177e4SLinus Torvalds break; 8511da177e4SLinus Torvalds } else { 8521da177e4SLinus Torvalds p_prev = p; 8531da177e4SLinus Torvalds p = p->pnext; 8541da177e4SLinus Torvalds } 8551da177e4SLinus Torvalds } 8561da177e4SLinus Torvalds spin_unlock(&list_lock); 8571da177e4SLinus Torvalds 8581da177e4SLinus Torvalds kfree(php_ctlr); 8591da177e4SLinus Torvalds 8601da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 8611da177e4SLinus Torvalds 8621da177e4SLinus Torvalds } 8631da177e4SLinus Torvalds 8641da177e4SLinus Torvalds static int hpc_power_on_slot(struct slot * slot) 8651da177e4SLinus Torvalds { 866ee138334Srajesh.shah@intel.com struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; 8671da177e4SLinus Torvalds u8 slot_cmd; 8681da177e4SLinus Torvalds int retval = 0; 8691da177e4SLinus Torvalds 8701da177e4SLinus Torvalds DBG_ENTER_ROUTINE 8711da177e4SLinus Torvalds 8721da177e4SLinus Torvalds if (!slot->ctrl->hpc_ctlr_handle) { 8731da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 8741da177e4SLinus Torvalds return -1; 8751da177e4SLinus Torvalds } 8761da177e4SLinus Torvalds 8771da177e4SLinus Torvalds if (slot->hp_slot >= php_ctlr->num_slots) { 8781da177e4SLinus Torvalds err("%s: Invalid HPC slot number!\n", __FUNCTION__); 8791da177e4SLinus Torvalds return -1; 8801da177e4SLinus Torvalds } 8811da177e4SLinus Torvalds slot_cmd = 0x01; 8821da177e4SLinus Torvalds 8831da177e4SLinus Torvalds retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd); 8841da177e4SLinus Torvalds 8851da177e4SLinus Torvalds if (retval) { 8861da177e4SLinus Torvalds err("%s: Write command failed!\n", __FUNCTION__); 8871da177e4SLinus Torvalds return -1; 8881da177e4SLinus Torvalds } 8891da177e4SLinus Torvalds 8901da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 8911da177e4SLinus Torvalds 8921da177e4SLinus Torvalds return retval; 8931da177e4SLinus Torvalds } 8941da177e4SLinus Torvalds 8951da177e4SLinus Torvalds static int hpc_slot_enable(struct slot * slot) 8961da177e4SLinus Torvalds { 897ee138334Srajesh.shah@intel.com struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; 8981da177e4SLinus Torvalds u8 slot_cmd; 8991da177e4SLinus Torvalds int retval = 0; 9001da177e4SLinus Torvalds 9011da177e4SLinus Torvalds DBG_ENTER_ROUTINE 9021da177e4SLinus Torvalds 9031da177e4SLinus Torvalds if (!slot->ctrl->hpc_ctlr_handle) { 9041da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 9051da177e4SLinus Torvalds return -1; 9061da177e4SLinus Torvalds } 9071da177e4SLinus Torvalds 9081da177e4SLinus Torvalds if (slot->hp_slot >= php_ctlr->num_slots) { 9091da177e4SLinus Torvalds err("%s: Invalid HPC slot number!\n", __FUNCTION__); 9101da177e4SLinus Torvalds return -1; 9111da177e4SLinus Torvalds } 9121da177e4SLinus Torvalds /* 3A => Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */ 9131da177e4SLinus Torvalds slot_cmd = 0x3A; 9141da177e4SLinus Torvalds 9151da177e4SLinus Torvalds retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd); 9161da177e4SLinus Torvalds 9171da177e4SLinus Torvalds if (retval) { 9181da177e4SLinus Torvalds err("%s: Write command failed!\n", __FUNCTION__); 9191da177e4SLinus Torvalds return -1; 9201da177e4SLinus Torvalds } 9211da177e4SLinus Torvalds 9221da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 9231da177e4SLinus Torvalds return retval; 9241da177e4SLinus Torvalds } 9251da177e4SLinus Torvalds 9261da177e4SLinus Torvalds static int hpc_slot_disable(struct slot * slot) 9271da177e4SLinus Torvalds { 928ee138334Srajesh.shah@intel.com struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; 9291da177e4SLinus Torvalds u8 slot_cmd; 9301da177e4SLinus Torvalds int retval = 0; 9311da177e4SLinus Torvalds 9321da177e4SLinus Torvalds DBG_ENTER_ROUTINE 9331da177e4SLinus Torvalds 9341da177e4SLinus Torvalds if (!slot->ctrl->hpc_ctlr_handle) { 9351da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 9361da177e4SLinus Torvalds return -1; 9371da177e4SLinus Torvalds } 9381da177e4SLinus Torvalds 9391da177e4SLinus Torvalds if (slot->hp_slot >= php_ctlr->num_slots) { 9401da177e4SLinus Torvalds err("%s: Invalid HPC slot number!\n", __FUNCTION__); 9411da177e4SLinus Torvalds return -1; 9421da177e4SLinus Torvalds } 9431da177e4SLinus Torvalds 9441da177e4SLinus Torvalds /* 1F => Slot - Disable, Power Indicator - Off, Attention Indicator - On */ 9451da177e4SLinus Torvalds slot_cmd = 0x1F; 9461da177e4SLinus Torvalds 9471da177e4SLinus Torvalds retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd); 9481da177e4SLinus Torvalds 9491da177e4SLinus Torvalds if (retval) { 9501da177e4SLinus Torvalds err("%s: Write command failed!\n", __FUNCTION__); 9511da177e4SLinus Torvalds return -1; 9521da177e4SLinus Torvalds } 9531da177e4SLinus Torvalds 9541da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 9551da177e4SLinus Torvalds return retval; 9561da177e4SLinus Torvalds } 9571da177e4SLinus Torvalds 9581da177e4SLinus Torvalds static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) 9591da177e4SLinus Torvalds { 9600afabe90SKenji Kaneshige int retval; 96175d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 9620afabe90SKenji Kaneshige u8 pi, cmd; 9631da177e4SLinus Torvalds 9641da177e4SLinus Torvalds DBG_ENTER_ROUTINE 9651da177e4SLinus Torvalds 96675d97c59SKenji Kaneshige pi = shpc_readb(ctrl, PROG_INTERFACE); 9670afabe90SKenji Kaneshige if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX)) 9680afabe90SKenji Kaneshige return -EINVAL; 9691da177e4SLinus Torvalds 9701da177e4SLinus Torvalds switch (value) { 9710afabe90SKenji Kaneshige case PCI_SPEED_33MHz: 9720afabe90SKenji Kaneshige cmd = SETA_PCI_33MHZ; 9731da177e4SLinus Torvalds break; 9740afabe90SKenji Kaneshige case PCI_SPEED_66MHz: 9750afabe90SKenji Kaneshige cmd = SETA_PCI_66MHZ; 9761da177e4SLinus Torvalds break; 9770afabe90SKenji Kaneshige case PCI_SPEED_66MHz_PCIX: 9780afabe90SKenji Kaneshige cmd = SETA_PCIX_66MHZ; 9791da177e4SLinus Torvalds break; 9800afabe90SKenji Kaneshige case PCI_SPEED_100MHz_PCIX: 9810afabe90SKenji Kaneshige cmd = SETA_PCIX_100MHZ; 9821da177e4SLinus Torvalds break; 9830afabe90SKenji Kaneshige case PCI_SPEED_133MHz_PCIX: 9840afabe90SKenji Kaneshige cmd = SETA_PCIX_133MHZ; 9850afabe90SKenji Kaneshige break; 9860afabe90SKenji Kaneshige case PCI_SPEED_66MHz_PCIX_ECC: 9870afabe90SKenji Kaneshige cmd = SETB_PCIX_66MHZ_EM; 9880afabe90SKenji Kaneshige break; 9890afabe90SKenji Kaneshige case PCI_SPEED_100MHz_PCIX_ECC: 9900afabe90SKenji Kaneshige cmd = SETB_PCIX_100MHZ_EM; 9910afabe90SKenji Kaneshige break; 9920afabe90SKenji Kaneshige case PCI_SPEED_133MHz_PCIX_ECC: 9930afabe90SKenji Kaneshige cmd = SETB_PCIX_133MHZ_EM; 9940afabe90SKenji Kaneshige break; 9950afabe90SKenji Kaneshige case PCI_SPEED_66MHz_PCIX_266: 9960afabe90SKenji Kaneshige cmd = SETB_PCIX_66MHZ_266; 9970afabe90SKenji Kaneshige break; 9980afabe90SKenji Kaneshige case PCI_SPEED_100MHz_PCIX_266: 9990afabe90SKenji Kaneshige cmd = SETB_PCIX_100MHZ_266; 10000afabe90SKenji Kaneshige break; 10010afabe90SKenji Kaneshige case PCI_SPEED_133MHz_PCIX_266: 10020afabe90SKenji Kaneshige cmd = SETB_PCIX_133MHZ_266; 10030afabe90SKenji Kaneshige break; 10040afabe90SKenji Kaneshige case PCI_SPEED_66MHz_PCIX_533: 10050afabe90SKenji Kaneshige cmd = SETB_PCIX_66MHZ_533; 10060afabe90SKenji Kaneshige break; 10070afabe90SKenji Kaneshige case PCI_SPEED_100MHz_PCIX_533: 10080afabe90SKenji Kaneshige cmd = SETB_PCIX_100MHZ_533; 10090afabe90SKenji Kaneshige break; 10100afabe90SKenji Kaneshige case PCI_SPEED_133MHz_PCIX_533: 10110afabe90SKenji Kaneshige cmd = SETB_PCIX_133MHZ_533; 10121da177e4SLinus Torvalds break; 10131da177e4SLinus Torvalds default: 10140afabe90SKenji Kaneshige return -EINVAL; 10151da177e4SLinus Torvalds } 10161da177e4SLinus Torvalds 10170afabe90SKenji Kaneshige retval = shpc_write_cmd(slot, 0, cmd); 10180afabe90SKenji Kaneshige if (retval) 10191da177e4SLinus Torvalds err("%s: Write command failed!\n", __FUNCTION__); 10201da177e4SLinus Torvalds 10211da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 10221da177e4SLinus Torvalds return retval; 10231da177e4SLinus Torvalds } 10241da177e4SLinus Torvalds 10251da177e4SLinus Torvalds static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) 10261da177e4SLinus Torvalds { 10271da177e4SLinus Torvalds struct controller *ctrl = NULL; 10281da177e4SLinus Torvalds struct php_ctlr_state_s *php_ctlr; 10291da177e4SLinus Torvalds u8 schedule_flag = 0; 10301da177e4SLinus Torvalds u32 temp_dword, intr_loc, intr_loc2; 10311da177e4SLinus Torvalds int hp_slot; 10321da177e4SLinus Torvalds 10331da177e4SLinus Torvalds if (!dev_id) 10341da177e4SLinus Torvalds return IRQ_NONE; 10351da177e4SLinus Torvalds 10361da177e4SLinus Torvalds if (!shpchp_poll_mode) { 10371da177e4SLinus Torvalds ctrl = (struct controller *)dev_id; 10381da177e4SLinus Torvalds php_ctlr = ctrl->hpc_ctlr_handle; 10391da177e4SLinus Torvalds } else { 10401da177e4SLinus Torvalds php_ctlr = (struct php_ctlr_state_s *) dev_id; 10411da177e4SLinus Torvalds ctrl = (struct controller *)php_ctlr->callback_instance_id; 10421da177e4SLinus Torvalds } 10431da177e4SLinus Torvalds 10441da177e4SLinus Torvalds if (!ctrl) 10451da177e4SLinus Torvalds return IRQ_NONE; 10461da177e4SLinus Torvalds 10471da177e4SLinus Torvalds if (!php_ctlr || !php_ctlr->creg) 10481da177e4SLinus Torvalds return IRQ_NONE; 10491da177e4SLinus Torvalds 10501da177e4SLinus Torvalds /* Check to see if it was our interrupt */ 105175d97c59SKenji Kaneshige intr_loc = shpc_readl(ctrl, INTR_LOC); 10521da177e4SLinus Torvalds 10531da177e4SLinus Torvalds if (!intr_loc) 10541da177e4SLinus Torvalds return IRQ_NONE; 10551da177e4SLinus Torvalds dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); 10561da177e4SLinus Torvalds 10571da177e4SLinus Torvalds if(!shpchp_poll_mode) { 10581da177e4SLinus Torvalds /* Mask Global Interrupt Mask - see implementation note on p. 139 */ 10591da177e4SLinus Torvalds /* of SHPC spec rev 1.0*/ 106075d97c59SKenji Kaneshige temp_dword = shpc_readl(ctrl, SERR_INTR_ENABLE); 1061e7138723SKenji Kaneshige temp_dword |= GLOBAL_INTR_MASK; 1062e7138723SKenji Kaneshige temp_dword &= ~SERR_INTR_RSVDZ_MASK; 106375d97c59SKenji Kaneshige shpc_writel(ctrl, SERR_INTR_ENABLE, temp_dword); 10641da177e4SLinus Torvalds 106575d97c59SKenji Kaneshige intr_loc2 = shpc_readl(ctrl, INTR_LOC); 10661da177e4SLinus Torvalds dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); 10671da177e4SLinus Torvalds } 10681da177e4SLinus Torvalds 10691da177e4SLinus Torvalds if (intr_loc & 0x0001) { 10701da177e4SLinus Torvalds /* 10711da177e4SLinus Torvalds * Command Complete Interrupt Pending 1072f467f618SKenji Kaneshige * RO only - clear by writing 1 to the Command Completion 10731da177e4SLinus Torvalds * Detect bit in Controller SERR-INT register 10741da177e4SLinus Torvalds */ 107575d97c59SKenji Kaneshige temp_dword = shpc_readl(ctrl, SERR_INTR_ENABLE); 1076e7138723SKenji Kaneshige temp_dword &= ~SERR_INTR_RSVDZ_MASK; 107775d97c59SKenji Kaneshige shpc_writel(ctrl, SERR_INTR_ENABLE, temp_dword); 1078bd62e271SKenji Kaneshige ctrl->cmd_busy = 0; 10791da177e4SLinus Torvalds wake_up_interruptible(&ctrl->queue); 10801da177e4SLinus Torvalds } 10811da177e4SLinus Torvalds 1082e4e73041SKenji Kaneshige if ((intr_loc = (intr_loc >> 1)) == 0) 1083e4e73041SKenji Kaneshige goto out; 10841da177e4SLinus Torvalds 10851da177e4SLinus Torvalds for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { 10861da177e4SLinus Torvalds /* To find out which slot has interrupt pending */ 10871da177e4SLinus Torvalds if ((intr_loc >> hp_slot) & 0x01) { 10882b34da7eSKenji Kaneshige temp_dword = shpc_readl(ctrl, SLOT_REG(hp_slot)); 10897c8942f9Srajesh.shah@intel.com dbg("%s: Slot %x with intr, slot register = %x\n", 10901da177e4SLinus Torvalds __FUNCTION__, hp_slot, temp_dword); 10915858759cSKenji Kaneshige if ((php_ctlr->switch_change_callback) && 10925858759cSKenji Kaneshige (temp_dword & MRL_CHANGE_DETECTED)) 10931da177e4SLinus Torvalds schedule_flag += php_ctlr->switch_change_callback( 10941da177e4SLinus Torvalds hp_slot, php_ctlr->callback_instance_id); 10955858759cSKenji Kaneshige if ((php_ctlr->attention_button_callback) && 10965858759cSKenji Kaneshige (temp_dword & BUTTON_PRESS_DETECTED)) 10971da177e4SLinus Torvalds schedule_flag += php_ctlr->attention_button_callback( 10981da177e4SLinus Torvalds hp_slot, php_ctlr->callback_instance_id); 10995858759cSKenji Kaneshige if ((php_ctlr->presence_change_callback) && 11005858759cSKenji Kaneshige (temp_dword & PRSNT_CHANGE_DETECTED)) 11011da177e4SLinus Torvalds schedule_flag += php_ctlr->presence_change_callback( 11021da177e4SLinus Torvalds hp_slot , php_ctlr->callback_instance_id); 11035858759cSKenji Kaneshige if ((php_ctlr->power_fault_callback) && 11045858759cSKenji Kaneshige (temp_dword & (ISO_PFAULT_DETECTED | CON_PFAULT_DETECTED))) 11051da177e4SLinus Torvalds schedule_flag += php_ctlr->power_fault_callback( 11061da177e4SLinus Torvalds hp_slot, php_ctlr->callback_instance_id); 11071da177e4SLinus Torvalds 11081da177e4SLinus Torvalds /* Clear all slot events */ 1109795eb5c4SKenji Kaneshige temp_dword &= ~SLOT_REG_RSVDZ_MASK; 11102b34da7eSKenji Kaneshige shpc_writel(ctrl, SLOT_REG(hp_slot), temp_dword); 11111da177e4SLinus Torvalds 111275d97c59SKenji Kaneshige intr_loc2 = shpc_readl(ctrl, INTR_LOC); 11131da177e4SLinus Torvalds dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); 11141da177e4SLinus Torvalds } 11151da177e4SLinus Torvalds } 1116e4e73041SKenji Kaneshige out: 11171da177e4SLinus Torvalds if (!shpchp_poll_mode) { 11181da177e4SLinus Torvalds /* Unmask Global Interrupt Mask */ 111975d97c59SKenji Kaneshige temp_dword = shpc_readl(ctrl, SERR_INTR_ENABLE); 1120e7138723SKenji Kaneshige temp_dword &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK); 112175d97c59SKenji Kaneshige shpc_writel(ctrl, SERR_INTR_ENABLE, temp_dword); 11221da177e4SLinus Torvalds } 11231da177e4SLinus Torvalds 11241da177e4SLinus Torvalds return IRQ_HANDLED; 11251da177e4SLinus Torvalds } 11261da177e4SLinus Torvalds 11271da177e4SLinus Torvalds static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) 11281da177e4SLinus Torvalds { 11290afabe90SKenji Kaneshige int retval = 0; 113075d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 11311da177e4SLinus Torvalds enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; 113275d97c59SKenji Kaneshige u8 pi = shpc_readb(ctrl, PROG_INTERFACE); 113375d97c59SKenji Kaneshige u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1); 113475d97c59SKenji Kaneshige u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2); 11351da177e4SLinus Torvalds 11361da177e4SLinus Torvalds DBG_ENTER_ROUTINE 11371da177e4SLinus Torvalds 11381da177e4SLinus Torvalds if (pi == 2) { 11396558b6abSKenji Kaneshige if (slot_avail2 & SLOT_133MHZ_PCIX_533) 11400afabe90SKenji Kaneshige bus_speed = PCI_SPEED_133MHz_PCIX_533; 11416558b6abSKenji Kaneshige else if (slot_avail2 & SLOT_100MHZ_PCIX_533) 11420afabe90SKenji Kaneshige bus_speed = PCI_SPEED_100MHz_PCIX_533; 11436558b6abSKenji Kaneshige else if (slot_avail2 & SLOT_66MHZ_PCIX_533) 11440afabe90SKenji Kaneshige bus_speed = PCI_SPEED_66MHz_PCIX_533; 11456558b6abSKenji Kaneshige else if (slot_avail2 & SLOT_133MHZ_PCIX_266) 11460afabe90SKenji Kaneshige bus_speed = PCI_SPEED_133MHz_PCIX_266; 11476558b6abSKenji Kaneshige else if (slot_avail2 & SLOT_100MHZ_PCIX_266) 11480afabe90SKenji Kaneshige bus_speed = PCI_SPEED_100MHz_PCIX_266; 11496558b6abSKenji Kaneshige else if (slot_avail2 & SLOT_66MHZ_PCIX_266) 11500afabe90SKenji Kaneshige bus_speed = PCI_SPEED_66MHz_PCIX_266; 11510afabe90SKenji Kaneshige } 11520afabe90SKenji Kaneshige 11530afabe90SKenji Kaneshige if (bus_speed == PCI_SPEED_UNKNOWN) { 11546558b6abSKenji Kaneshige if (slot_avail1 & SLOT_133MHZ_PCIX) 11550afabe90SKenji Kaneshige bus_speed = PCI_SPEED_133MHz_PCIX; 11566558b6abSKenji Kaneshige else if (slot_avail1 & SLOT_100MHZ_PCIX) 11570afabe90SKenji Kaneshige bus_speed = PCI_SPEED_100MHz_PCIX; 11586558b6abSKenji Kaneshige else if (slot_avail1 & SLOT_66MHZ_PCIX) 11590afabe90SKenji Kaneshige bus_speed = PCI_SPEED_66MHz_PCIX; 11606558b6abSKenji Kaneshige else if (slot_avail2 & SLOT_66MHZ) 11610afabe90SKenji Kaneshige bus_speed = PCI_SPEED_66MHz; 11626558b6abSKenji Kaneshige else if (slot_avail1 & SLOT_33MHZ) 11630afabe90SKenji Kaneshige bus_speed = PCI_SPEED_33MHz; 11640afabe90SKenji Kaneshige else 11650afabe90SKenji Kaneshige retval = -ENODEV; 11661da177e4SLinus Torvalds } 11671da177e4SLinus Torvalds 11681da177e4SLinus Torvalds *value = bus_speed; 11691da177e4SLinus Torvalds dbg("Max bus speed = %d\n", bus_speed); 11701da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 11711da177e4SLinus Torvalds return retval; 11721da177e4SLinus Torvalds } 11731da177e4SLinus Torvalds 11741da177e4SLinus Torvalds static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value) 11751da177e4SLinus Torvalds { 11760afabe90SKenji Kaneshige int retval = 0; 117775d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 11781da177e4SLinus Torvalds enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; 117975d97c59SKenji Kaneshige u16 sec_bus_reg = shpc_readw(ctrl, SEC_BUS_CONFIG); 118075d97c59SKenji Kaneshige u8 pi = shpc_readb(ctrl, PROG_INTERFACE); 11810afabe90SKenji Kaneshige u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7); 11821da177e4SLinus Torvalds 11831da177e4SLinus Torvalds DBG_ENTER_ROUTINE 11841da177e4SLinus Torvalds 11850afabe90SKenji Kaneshige if ((pi == 1) && (speed_mode > 4)) { 11860afabe90SKenji Kaneshige *value = PCI_SPEED_UNKNOWN; 11870afabe90SKenji Kaneshige return -ENODEV; 11881da177e4SLinus Torvalds } 11891da177e4SLinus Torvalds 11900afabe90SKenji Kaneshige switch (speed_mode) { 11910afabe90SKenji Kaneshige case 0x0: 11920afabe90SKenji Kaneshige *value = PCI_SPEED_33MHz; 11931da177e4SLinus Torvalds break; 11940afabe90SKenji Kaneshige case 0x1: 11950afabe90SKenji Kaneshige *value = PCI_SPEED_66MHz; 11961da177e4SLinus Torvalds break; 11970afabe90SKenji Kaneshige case 0x2: 11980afabe90SKenji Kaneshige *value = PCI_SPEED_66MHz_PCIX; 11991da177e4SLinus Torvalds break; 12000afabe90SKenji Kaneshige case 0x3: 12010afabe90SKenji Kaneshige *value = PCI_SPEED_100MHz_PCIX; 12021da177e4SLinus Torvalds break; 12030afabe90SKenji Kaneshige case 0x4: 12040afabe90SKenji Kaneshige *value = PCI_SPEED_133MHz_PCIX; 12051da177e4SLinus Torvalds break; 12060afabe90SKenji Kaneshige case 0x5: 12070afabe90SKenji Kaneshige *value = PCI_SPEED_66MHz_PCIX_ECC; 12081da177e4SLinus Torvalds break; 12090afabe90SKenji Kaneshige case 0x6: 12100afabe90SKenji Kaneshige *value = PCI_SPEED_100MHz_PCIX_ECC; 12111da177e4SLinus Torvalds break; 12120afabe90SKenji Kaneshige case 0x7: 12130afabe90SKenji Kaneshige *value = PCI_SPEED_133MHz_PCIX_ECC; 12141da177e4SLinus Torvalds break; 12150afabe90SKenji Kaneshige case 0x8: 12160afabe90SKenji Kaneshige *value = PCI_SPEED_66MHz_PCIX_266; 12171da177e4SLinus Torvalds break; 12180afabe90SKenji Kaneshige case 0x9: 12190afabe90SKenji Kaneshige *value = PCI_SPEED_100MHz_PCIX_266; 12201da177e4SLinus Torvalds break; 12211da177e4SLinus Torvalds case 0xa: 12220afabe90SKenji Kaneshige *value = PCI_SPEED_133MHz_PCIX_266; 12231da177e4SLinus Torvalds break; 12241da177e4SLinus Torvalds case 0xb: 12250afabe90SKenji Kaneshige *value = PCI_SPEED_66MHz_PCIX_533; 12261da177e4SLinus Torvalds break; 12271da177e4SLinus Torvalds case 0xc: 12280afabe90SKenji Kaneshige *value = PCI_SPEED_100MHz_PCIX_533; 12291da177e4SLinus Torvalds break; 12301da177e4SLinus Torvalds case 0xd: 12310afabe90SKenji Kaneshige *value = PCI_SPEED_133MHz_PCIX_533; 12321da177e4SLinus Torvalds break; 12331da177e4SLinus Torvalds default: 12340afabe90SKenji Kaneshige *value = PCI_SPEED_UNKNOWN; 12350afabe90SKenji Kaneshige retval = -ENODEV; 12361da177e4SLinus Torvalds break; 12371da177e4SLinus Torvalds } 12381da177e4SLinus Torvalds 12391da177e4SLinus Torvalds dbg("Current bus speed = %d\n", bus_speed); 12401da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 12411da177e4SLinus Torvalds return retval; 12421da177e4SLinus Torvalds } 12431da177e4SLinus Torvalds 12441da177e4SLinus Torvalds static struct hpc_ops shpchp_hpc_ops = { 12451da177e4SLinus Torvalds .power_on_slot = hpc_power_on_slot, 12461da177e4SLinus Torvalds .slot_enable = hpc_slot_enable, 12471da177e4SLinus Torvalds .slot_disable = hpc_slot_disable, 12481da177e4SLinus Torvalds .set_bus_speed_mode = hpc_set_bus_speed_mode, 12491da177e4SLinus Torvalds .set_attention_status = hpc_set_attention_status, 12501da177e4SLinus Torvalds .get_power_status = hpc_get_power_status, 12511da177e4SLinus Torvalds .get_attention_status = hpc_get_attention_status, 12521da177e4SLinus Torvalds .get_latch_status = hpc_get_latch_status, 12531da177e4SLinus Torvalds .get_adapter_status = hpc_get_adapter_status, 12541da177e4SLinus Torvalds 12551da177e4SLinus Torvalds .get_max_bus_speed = hpc_get_max_bus_speed, 12561da177e4SLinus Torvalds .get_cur_bus_speed = hpc_get_cur_bus_speed, 12571da177e4SLinus Torvalds .get_adapter_speed = hpc_get_adapter_speed, 12581da177e4SLinus Torvalds .get_mode1_ECC_cap = hpc_get_mode1_ECC_cap, 12591da177e4SLinus Torvalds .get_prog_int = hpc_get_prog_int, 12601da177e4SLinus Torvalds 12611da177e4SLinus Torvalds .query_power_fault = hpc_query_power_fault, 12621da177e4SLinus Torvalds .green_led_on = hpc_set_green_led_on, 12631da177e4SLinus Torvalds .green_led_off = hpc_set_green_led_off, 12641da177e4SLinus Torvalds .green_led_blink = hpc_set_green_led_blink, 12651da177e4SLinus Torvalds 12661da177e4SLinus Torvalds .release_ctlr = hpc_release_ctlr, 12671da177e4SLinus Torvalds }; 12681da177e4SLinus Torvalds 1269ee138334Srajesh.shah@intel.com int shpc_init(struct controller * ctrl, struct pci_dev * pdev) 12701da177e4SLinus Torvalds { 12711da177e4SLinus Torvalds struct php_ctlr_state_s *php_ctlr, *p; 12721da177e4SLinus Torvalds void *instance_id = ctrl; 12730455986cSKenji Kaneshige int rc, num_slots = 0; 12741da177e4SLinus Torvalds u8 hp_slot; 12751da177e4SLinus Torvalds static int first = 1; 12760455986cSKenji Kaneshige u32 shpc_base_offset; 127775d97c59SKenji Kaneshige u32 tempdword, slot_reg, slot_config; 12781da177e4SLinus Torvalds u8 i; 12791da177e4SLinus Torvalds 12801da177e4SLinus Torvalds DBG_ENTER_ROUTINE 12811da177e4SLinus Torvalds 12820455986cSKenji Kaneshige ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */ 12830455986cSKenji Kaneshige 12841da177e4SLinus Torvalds spin_lock_init(&list_lock); 128557c95c0dSKenji Kaneshige php_ctlr = kzalloc(sizeof(*php_ctlr), GFP_KERNEL); 12861da177e4SLinus Torvalds 12871da177e4SLinus Torvalds if (!php_ctlr) { /* allocate controller state data */ 12881da177e4SLinus Torvalds err("%s: HPC controller memory allocation error!\n", __FUNCTION__); 12891da177e4SLinus Torvalds goto abort; 12901da177e4SLinus Torvalds } 12911da177e4SLinus Torvalds 12921da177e4SLinus Torvalds php_ctlr->pci_dev = pdev; /* save pci_dev in context */ 12931da177e4SLinus Torvalds 1294ee138334Srajesh.shah@intel.com if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device == 1295ee138334Srajesh.shah@intel.com PCI_DEVICE_ID_AMD_GOLAM_7450)) { 12960455986cSKenji Kaneshige /* amd shpc driver doesn't use Base Offset; assume 0 */ 12970455986cSKenji Kaneshige ctrl->mmio_base = pci_resource_start(pdev, 0); 12980455986cSKenji Kaneshige ctrl->mmio_size = pci_resource_len(pdev, 0); 12991da177e4SLinus Torvalds } else { 13000455986cSKenji Kaneshige ctrl->cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC); 13010455986cSKenji Kaneshige if (!ctrl->cap_offset) { 13020455986cSKenji Kaneshige err("%s : cap_offset == 0\n", __FUNCTION__); 13031da177e4SLinus Torvalds goto abort_free_ctlr; 13041da177e4SLinus Torvalds } 13050455986cSKenji Kaneshige dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset); 13061da177e4SLinus Torvalds 130775d97c59SKenji Kaneshige rc = shpc_indirect_read(ctrl, 0, &shpc_base_offset); 13081da177e4SLinus Torvalds if (rc) { 13090455986cSKenji Kaneshige err("%s: cannot read base_offset\n", __FUNCTION__); 13101da177e4SLinus Torvalds goto abort_free_ctlr; 13111da177e4SLinus Torvalds } 13121da177e4SLinus Torvalds 131375d97c59SKenji Kaneshige rc = shpc_indirect_read(ctrl, 3, &tempdword); 13141da177e4SLinus Torvalds if (rc) { 13150455986cSKenji Kaneshige err("%s: cannot read slot config\n", __FUNCTION__); 13161da177e4SLinus Torvalds goto abort_free_ctlr; 13171da177e4SLinus Torvalds } 13180455986cSKenji Kaneshige num_slots = tempdword & SLOT_NUM; 13190455986cSKenji Kaneshige dbg("%s: num_slots (indirect) %x\n", __FUNCTION__, num_slots); 13201da177e4SLinus Torvalds 13210455986cSKenji Kaneshige for (i = 0; i < 9 + num_slots; i++) { 132275d97c59SKenji Kaneshige rc = shpc_indirect_read(ctrl, i, &tempdword); 13231da177e4SLinus Torvalds if (rc) { 13240455986cSKenji Kaneshige err("%s: cannot read creg (index = %d)\n", 13250455986cSKenji Kaneshige __FUNCTION__, i); 13261da177e4SLinus Torvalds goto abort_free_ctlr; 13271da177e4SLinus Torvalds } 13287c8942f9Srajesh.shah@intel.com dbg("%s: offset %d: value %x\n", __FUNCTION__,i, 13297c8942f9Srajesh.shah@intel.com tempdword); 13301da177e4SLinus Torvalds } 13310455986cSKenji Kaneshige 13320455986cSKenji Kaneshige ctrl->mmio_base = 13330455986cSKenji Kaneshige pci_resource_start(pdev, 0) + shpc_base_offset; 13340455986cSKenji Kaneshige ctrl->mmio_size = 0x24 + 0x4 * num_slots; 13351da177e4SLinus Torvalds } 13361da177e4SLinus Torvalds 13371da177e4SLinus Torvalds if (first) { 13381da177e4SLinus Torvalds spin_lock_init(&hpc_event_lock); 13391da177e4SLinus Torvalds first = 0; 13401da177e4SLinus Torvalds } 13411da177e4SLinus Torvalds 13421da177e4SLinus Torvalds info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, 13431da177e4SLinus Torvalds pdev->subsystem_device); 13441da177e4SLinus Torvalds 13451da177e4SLinus Torvalds if (pci_enable_device(pdev)) 13461da177e4SLinus Torvalds goto abort_free_ctlr; 13471da177e4SLinus Torvalds 13480455986cSKenji Kaneshige if (!request_mem_region(ctrl->mmio_base, ctrl->mmio_size, MY_NAME)) { 13491da177e4SLinus Torvalds err("%s: cannot reserve MMIO region\n", __FUNCTION__); 13501da177e4SLinus Torvalds goto abort_free_ctlr; 13511da177e4SLinus Torvalds } 13521da177e4SLinus Torvalds 13530455986cSKenji Kaneshige php_ctlr->creg = ioremap(ctrl->mmio_base, ctrl->mmio_size); 13541da177e4SLinus Torvalds if (!php_ctlr->creg) { 13550455986cSKenji Kaneshige err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__, 13560455986cSKenji Kaneshige ctrl->mmio_size, ctrl->mmio_base); 13570455986cSKenji Kaneshige release_mem_region(ctrl->mmio_base, ctrl->mmio_size); 13581da177e4SLinus Torvalds goto abort_free_ctlr; 13591da177e4SLinus Torvalds } 13601da177e4SLinus Torvalds dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg); 13611da177e4SLinus Torvalds 13626aa4cdd0SIngo Molnar mutex_init(&ctrl->crit_sect); 1363d29aaddaSKenji Kaneshige mutex_init(&ctrl->cmd_lock); 1364d29aaddaSKenji Kaneshige 13651da177e4SLinus Torvalds /* Setup wait queue */ 13661da177e4SLinus Torvalds init_waitqueue_head(&ctrl->queue); 13671da177e4SLinus Torvalds 13681da177e4SLinus Torvalds /* Find the IRQ */ 13691da177e4SLinus Torvalds php_ctlr->irq = pdev->irq; 1370ee138334Srajesh.shah@intel.com php_ctlr->attention_button_callback = shpchp_handle_attention_button, 1371ee138334Srajesh.shah@intel.com php_ctlr->switch_change_callback = shpchp_handle_switch_change; 1372ee138334Srajesh.shah@intel.com php_ctlr->presence_change_callback = shpchp_handle_presence_change; 1373ee138334Srajesh.shah@intel.com php_ctlr->power_fault_callback = shpchp_handle_power_fault; 13741da177e4SLinus Torvalds php_ctlr->callback_instance_id = instance_id; 13751da177e4SLinus Torvalds 137675d97c59SKenji Kaneshige ctrl->hpc_ctlr_handle = php_ctlr; 137775d97c59SKenji Kaneshige ctrl->hpc_ops = &shpchp_hpc_ops; 137875d97c59SKenji Kaneshige 13791da177e4SLinus Torvalds /* Return PCI Controller Info */ 138075d97c59SKenji Kaneshige slot_config = shpc_readl(ctrl, SLOT_CONFIG); 138175d97c59SKenji Kaneshige php_ctlr->slot_device_offset = (slot_config & FIRST_DEV_NUM) >> 8; 138275d97c59SKenji Kaneshige php_ctlr->num_slots = slot_config & SLOT_NUM; 13831da177e4SLinus Torvalds dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset); 13841da177e4SLinus Torvalds dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots); 13851da177e4SLinus Torvalds 13861da177e4SLinus Torvalds /* Mask Global Interrupt Mask & Command Complete Interrupt Mask */ 138775d97c59SKenji Kaneshige tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); 13881da177e4SLinus Torvalds dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); 1389e7138723SKenji Kaneshige tempdword |= (GLOBAL_INTR_MASK | GLOBAL_SERR_MASK | 1390e7138723SKenji Kaneshige COMMAND_INTR_MASK | ARBITER_SERR_MASK); 1391e7138723SKenji Kaneshige tempdword &= ~SERR_INTR_RSVDZ_MASK; 139275d97c59SKenji Kaneshige shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword); 139375d97c59SKenji Kaneshige tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); 13941da177e4SLinus Torvalds dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); 13951da177e4SLinus Torvalds 13961da177e4SLinus Torvalds /* Mask the MRL sensor SERR Mask of individual slot in 13971da177e4SLinus Torvalds * Slot SERR-INT Mask & clear all the existing event if any 13981da177e4SLinus Torvalds */ 13991da177e4SLinus Torvalds for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { 14002b34da7eSKenji Kaneshige slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); 14011da177e4SLinus Torvalds dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, 14021da177e4SLinus Torvalds hp_slot, slot_reg); 1403795eb5c4SKenji Kaneshige slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | 1404795eb5c4SKenji Kaneshige BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | 1405795eb5c4SKenji Kaneshige CON_PFAULT_INTR_MASK | MRL_CHANGE_SERR_MASK | 1406795eb5c4SKenji Kaneshige CON_PFAULT_SERR_MASK); 1407795eb5c4SKenji Kaneshige slot_reg &= ~SLOT_REG_RSVDZ_MASK; 1408795eb5c4SKenji Kaneshige shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); 14091da177e4SLinus Torvalds } 14101da177e4SLinus Torvalds 14111da177e4SLinus Torvalds if (shpchp_poll_mode) {/* Install interrupt polling code */ 14121da177e4SLinus Torvalds /* Install and start the interrupt polling timer */ 14131da177e4SLinus Torvalds init_timer(&php_ctlr->int_poll_timer); 14141da177e4SLinus Torvalds start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */ 14151da177e4SLinus Torvalds } else { 14161da177e4SLinus Torvalds /* Installs the interrupt handler */ 14171da177e4SLinus Torvalds rc = pci_enable_msi(pdev); 14181da177e4SLinus Torvalds if (rc) { 14191da177e4SLinus Torvalds info("Can't get msi for the hotplug controller\n"); 14201da177e4SLinus Torvalds info("Use INTx for the hotplug controller\n"); 14211da177e4SLinus Torvalds } else 14221da177e4SLinus Torvalds php_ctlr->irq = pdev->irq; 14231da177e4SLinus Torvalds 14241da177e4SLinus Torvalds rc = request_irq(php_ctlr->irq, shpc_isr, SA_SHIRQ, MY_NAME, (void *) ctrl); 14251da177e4SLinus Torvalds dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc); 14261da177e4SLinus Torvalds if (rc) { 14271da177e4SLinus Torvalds err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq); 14281da177e4SLinus Torvalds goto abort_free_ctlr; 14291da177e4SLinus Torvalds } 14301da177e4SLinus Torvalds } 14317c8942f9Srajesh.shah@intel.com dbg("%s: HPC at b:d:f:irq=0x%x:%x:%x:%x\n", __FUNCTION__, 14327c8942f9Srajesh.shah@intel.com pdev->bus->number, PCI_SLOT(pdev->devfn), 14337c8942f9Srajesh.shah@intel.com PCI_FUNC(pdev->devfn), pdev->irq); 1434424600f9Srajesh.shah@intel.com get_hp_hw_control_from_firmware(pdev); 14351da177e4SLinus Torvalds 14361da177e4SLinus Torvalds /* Add this HPC instance into the HPC list */ 14371da177e4SLinus Torvalds spin_lock(&list_lock); 14381da177e4SLinus Torvalds if (php_ctlr_list_head == 0) { 14391da177e4SLinus Torvalds php_ctlr_list_head = php_ctlr; 14401da177e4SLinus Torvalds p = php_ctlr_list_head; 14411da177e4SLinus Torvalds p->pnext = NULL; 14421da177e4SLinus Torvalds } else { 14431da177e4SLinus Torvalds p = php_ctlr_list_head; 14441da177e4SLinus Torvalds 14451da177e4SLinus Torvalds while (p->pnext) 14461da177e4SLinus Torvalds p = p->pnext; 14471da177e4SLinus Torvalds 14481da177e4SLinus Torvalds p->pnext = php_ctlr; 14491da177e4SLinus Torvalds } 14501da177e4SLinus Torvalds spin_unlock(&list_lock); 14511da177e4SLinus Torvalds 14521da177e4SLinus Torvalds ctlr_seq_num++; 14531da177e4SLinus Torvalds 1454795eb5c4SKenji Kaneshige /* 1455795eb5c4SKenji Kaneshige * Unmask all event interrupts of all slots 1456795eb5c4SKenji Kaneshige */ 14571da177e4SLinus Torvalds for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { 14582b34da7eSKenji Kaneshige slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); 14591da177e4SLinus Torvalds dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, 14601da177e4SLinus Torvalds hp_slot, slot_reg); 1461795eb5c4SKenji Kaneshige slot_reg &= ~(PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | 1462795eb5c4SKenji Kaneshige BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | 1463795eb5c4SKenji Kaneshige CON_PFAULT_INTR_MASK | SLOT_REG_RSVDZ_MASK); 1464795eb5c4SKenji Kaneshige shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); 14651da177e4SLinus Torvalds } 14661da177e4SLinus Torvalds if (!shpchp_poll_mode) { 14671da177e4SLinus Torvalds /* Unmask all general input interrupts and SERR */ 146875d97c59SKenji Kaneshige tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); 1469e7138723SKenji Kaneshige tempdword &= ~(GLOBAL_INTR_MASK | COMMAND_INTR_MASK | 1470e7138723SKenji Kaneshige SERR_INTR_RSVDZ_MASK); 147175d97c59SKenji Kaneshige shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword); 147275d97c59SKenji Kaneshige tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); 14731da177e4SLinus Torvalds dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); 14741da177e4SLinus Torvalds } 14751da177e4SLinus Torvalds 14761da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 14771da177e4SLinus Torvalds return 0; 14781da177e4SLinus Torvalds 14791da177e4SLinus Torvalds /* We end up here for the many possible ways to fail this API. */ 14801da177e4SLinus Torvalds abort_free_ctlr: 14811da177e4SLinus Torvalds kfree(php_ctlr); 14821da177e4SLinus Torvalds abort: 14831da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 14841da177e4SLinus Torvalds return -1; 14851da177e4SLinus Torvalds } 1486