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 /* 94c4cecc19SKenji Kaneshige * Interrupt Locator Register definitions 95c4cecc19SKenji Kaneshige */ 96c4cecc19SKenji Kaneshige #define CMD_INTR_PENDING (1 << 0) 97c4cecc19SKenji Kaneshige #define SLOT_INTR_PENDING(i) (1 << (i + 1)) 98c4cecc19SKenji Kaneshige 99c4cecc19SKenji Kaneshige /* 100e7138723SKenji Kaneshige * Controller SERR-INT Register 101e7138723SKenji Kaneshige */ 102e7138723SKenji Kaneshige #define GLOBAL_INTR_MASK (1 << 0) 103e7138723SKenji Kaneshige #define GLOBAL_SERR_MASK (1 << 1) 104e7138723SKenji Kaneshige #define COMMAND_INTR_MASK (1 << 2) 105e7138723SKenji Kaneshige #define ARBITER_SERR_MASK (1 << 3) 106e7138723SKenji Kaneshige #define COMMAND_DETECTED (1 << 16) 107e7138723SKenji Kaneshige #define ARBITER_DETECTED (1 << 17) 108e7138723SKenji Kaneshige #define SERR_INTR_RSVDZ_MASK 0xfffc0000 109e7138723SKenji Kaneshige 110e7138723SKenji Kaneshige /* 1112b34da7eSKenji Kaneshige * Logical Slot Register definitions 1122b34da7eSKenji Kaneshige */ 1132b34da7eSKenji Kaneshige #define SLOT_REG(i) (SLOT1 + (4 * i)) 1142b34da7eSKenji Kaneshige 1155858759cSKenji Kaneshige #define SLOT_STATE_SHIFT (0) 1165858759cSKenji Kaneshige #define SLOT_STATE_MASK (3 << 0) 1175858759cSKenji Kaneshige #define SLOT_STATE_PWRONLY (1) 1185858759cSKenji Kaneshige #define SLOT_STATE_ENABLED (2) 1195858759cSKenji Kaneshige #define SLOT_STATE_DISABLED (3) 1205858759cSKenji Kaneshige #define PWR_LED_STATE_SHIFT (2) 1215858759cSKenji Kaneshige #define PWR_LED_STATE_MASK (3 << 2) 1225858759cSKenji Kaneshige #define ATN_LED_STATE_SHIFT (4) 1235858759cSKenji Kaneshige #define ATN_LED_STATE_MASK (3 << 4) 1245858759cSKenji Kaneshige #define ATN_LED_STATE_ON (1) 1255858759cSKenji Kaneshige #define ATN_LED_STATE_BLINK (2) 1265858759cSKenji Kaneshige #define ATN_LED_STATE_OFF (3) 1275858759cSKenji Kaneshige #define POWER_FAULT (1 << 6) 1285858759cSKenji Kaneshige #define ATN_BUTTON (1 << 7) 1295858759cSKenji Kaneshige #define MRL_SENSOR (1 << 8) 1305858759cSKenji Kaneshige #define MHZ66_CAP (1 << 9) 1315858759cSKenji Kaneshige #define PRSNT_SHIFT (10) 1325858759cSKenji Kaneshige #define PRSNT_MASK (3 << 10) 1335858759cSKenji Kaneshige #define PCIX_CAP_SHIFT (12) 1345858759cSKenji Kaneshige #define PCIX_CAP_MASK_PI1 (3 << 12) 1355858759cSKenji Kaneshige #define PCIX_CAP_MASK_PI2 (7 << 12) 1365858759cSKenji Kaneshige #define PRSNT_CHANGE_DETECTED (1 << 16) 1375858759cSKenji Kaneshige #define ISO_PFAULT_DETECTED (1 << 17) 1385858759cSKenji Kaneshige #define BUTTON_PRESS_DETECTED (1 << 18) 1395858759cSKenji Kaneshige #define MRL_CHANGE_DETECTED (1 << 19) 1405858759cSKenji Kaneshige #define CON_PFAULT_DETECTED (1 << 20) 1415858759cSKenji Kaneshige #define PRSNT_CHANGE_INTR_MASK (1 << 24) 1425858759cSKenji Kaneshige #define ISO_PFAULT_INTR_MASK (1 << 25) 1435858759cSKenji Kaneshige #define BUTTON_PRESS_INTR_MASK (1 << 26) 1445858759cSKenji Kaneshige #define MRL_CHANGE_INTR_MASK (1 << 27) 1455858759cSKenji Kaneshige #define CON_PFAULT_INTR_MASK (1 << 28) 1465858759cSKenji Kaneshige #define MRL_CHANGE_SERR_MASK (1 << 29) 1475858759cSKenji Kaneshige #define CON_PFAULT_SERR_MASK (1 << 30) 1485858759cSKenji Kaneshige #define SLOT_REG_RSVDZ_MASK (1 << 15) | (7 << 21) 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds /* SHPC 'write' operations/commands */ 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds /* Slot operation - 0x00h to 0x3Fh */ 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds #define NO_CHANGE 0x00 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds /* Slot state - Bits 0 & 1 of controller command register */ 1571da177e4SLinus Torvalds #define SET_SLOT_PWR 0x01 1581da177e4SLinus Torvalds #define SET_SLOT_ENABLE 0x02 1591da177e4SLinus Torvalds #define SET_SLOT_DISABLE 0x03 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds /* Power indicator state - Bits 2 & 3 of controller command register*/ 1621da177e4SLinus Torvalds #define SET_PWR_ON 0x04 1631da177e4SLinus Torvalds #define SET_PWR_BLINK 0x08 1641da177e4SLinus Torvalds #define SET_PWR_OFF 0x0C 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds /* Attention indicator state - Bits 4 & 5 of controller command register*/ 1671da177e4SLinus Torvalds #define SET_ATTN_ON 0x010 1681da177e4SLinus Torvalds #define SET_ATTN_BLINK 0x020 1691da177e4SLinus Torvalds #define SET_ATTN_OFF 0x030 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds /* Set bus speed/mode A - 0x40h to 0x47h */ 1721da177e4SLinus Torvalds #define SETA_PCI_33MHZ 0x40 1731da177e4SLinus Torvalds #define SETA_PCI_66MHZ 0x41 1741da177e4SLinus Torvalds #define SETA_PCIX_66MHZ 0x42 1751da177e4SLinus Torvalds #define SETA_PCIX_100MHZ 0x43 1761da177e4SLinus Torvalds #define SETA_PCIX_133MHZ 0x44 1771da177e4SLinus Torvalds #define RESERV_1 0x45 1781da177e4SLinus Torvalds #define RESERV_2 0x46 1791da177e4SLinus Torvalds #define RESERV_3 0x47 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds /* Set bus speed/mode B - 0x50h to 0x5fh */ 1821da177e4SLinus Torvalds #define SETB_PCI_33MHZ 0x50 1831da177e4SLinus Torvalds #define SETB_PCI_66MHZ 0x51 1841da177e4SLinus Torvalds #define SETB_PCIX_66MHZ_PM 0x52 1851da177e4SLinus Torvalds #define SETB_PCIX_100MHZ_PM 0x53 1861da177e4SLinus Torvalds #define SETB_PCIX_133MHZ_PM 0x54 1871da177e4SLinus Torvalds #define SETB_PCIX_66MHZ_EM 0x55 1881da177e4SLinus Torvalds #define SETB_PCIX_100MHZ_EM 0x56 1891da177e4SLinus Torvalds #define SETB_PCIX_133MHZ_EM 0x57 1901da177e4SLinus Torvalds #define SETB_PCIX_66MHZ_266 0x58 1911da177e4SLinus Torvalds #define SETB_PCIX_100MHZ_266 0x59 1921da177e4SLinus Torvalds #define SETB_PCIX_133MHZ_266 0x5a 1931da177e4SLinus Torvalds #define SETB_PCIX_66MHZ_533 0x5b 1941da177e4SLinus Torvalds #define SETB_PCIX_100MHZ_533 0x5c 1951da177e4SLinus Torvalds #define SETB_PCIX_133MHZ_533 0x5d 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds /* Power-on all slots - 0x48h */ 1991da177e4SLinus Torvalds #define SET_PWR_ON_ALL 0x48 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds /* Enable all slots - 0x49h */ 2021da177e4SLinus Torvalds #define SET_ENABLE_ALL 0x49 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds /* SHPC controller command error code */ 2051da177e4SLinus Torvalds #define SWITCH_OPEN 0x1 2061da177e4SLinus Torvalds #define INVALID_CMD 0x2 2071da177e4SLinus Torvalds #define INVALID_SPEED_MODE 0x4 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds /* For accessing SHPC Working Register Set */ 2101da177e4SLinus Torvalds #define DWORD_SELECT 0x2 2111da177e4SLinus Torvalds #define DWORD_DATA 0x4 2121da177e4SLinus Torvalds #define BASE_OFFSET 0x0 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds /* Field Offset in Logical Slot Register - byte boundary */ 2151da177e4SLinus Torvalds #define SLOT_EVENT_LATCH 0x2 2161da177e4SLinus Torvalds #define SLOT_SERR_INT_MASK 0x3 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds static spinlock_t hpc_event_lock; 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ 2211da177e4SLinus Torvalds static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */ 2221da177e4SLinus Torvalds static int ctlr_seq_num = 0; /* Controller sequenc # */ 2231da177e4SLinus Torvalds static spinlock_t list_lock; 2241da177e4SLinus Torvalds 22582d5f4aaSKenji Kaneshige static atomic_t shpchp_num_controllers = ATOMIC_INIT(0); 22682d5f4aaSKenji Kaneshige 227c4cecc19SKenji Kaneshige static irqreturn_t shpc_isr(int irq, void *dev_id, struct pt_regs *regs); 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds); 230d29aaddaSKenji Kaneshige static int hpc_check_cmd_status(struct controller *ctrl); 2311da177e4SLinus Torvalds 23275d97c59SKenji Kaneshige static inline u8 shpc_readb(struct controller *ctrl, int reg) 23375d97c59SKenji Kaneshige { 23475d97c59SKenji Kaneshige return readb(ctrl->hpc_ctlr_handle->creg + reg); 23575d97c59SKenji Kaneshige } 23675d97c59SKenji Kaneshige 23775d97c59SKenji Kaneshige static inline void shpc_writeb(struct controller *ctrl, int reg, u8 val) 23875d97c59SKenji Kaneshige { 23975d97c59SKenji Kaneshige writeb(val, ctrl->hpc_ctlr_handle->creg + reg); 24075d97c59SKenji Kaneshige } 24175d97c59SKenji Kaneshige 24275d97c59SKenji Kaneshige static inline u16 shpc_readw(struct controller *ctrl, int reg) 24375d97c59SKenji Kaneshige { 24475d97c59SKenji Kaneshige return readw(ctrl->hpc_ctlr_handle->creg + reg); 24575d97c59SKenji Kaneshige } 24675d97c59SKenji Kaneshige 24775d97c59SKenji Kaneshige static inline void shpc_writew(struct controller *ctrl, int reg, u16 val) 24875d97c59SKenji Kaneshige { 24975d97c59SKenji Kaneshige writew(val, ctrl->hpc_ctlr_handle->creg + reg); 25075d97c59SKenji Kaneshige } 25175d97c59SKenji Kaneshige 25275d97c59SKenji Kaneshige static inline u32 shpc_readl(struct controller *ctrl, int reg) 25375d97c59SKenji Kaneshige { 25475d97c59SKenji Kaneshige return readl(ctrl->hpc_ctlr_handle->creg + reg); 25575d97c59SKenji Kaneshige } 25675d97c59SKenji Kaneshige 25775d97c59SKenji Kaneshige static inline void shpc_writel(struct controller *ctrl, int reg, u32 val) 25875d97c59SKenji Kaneshige { 25975d97c59SKenji Kaneshige writel(val, ctrl->hpc_ctlr_handle->creg + reg); 26075d97c59SKenji Kaneshige } 26175d97c59SKenji Kaneshige 26275d97c59SKenji Kaneshige static inline int shpc_indirect_read(struct controller *ctrl, int index, 26375d97c59SKenji Kaneshige u32 *value) 26475d97c59SKenji Kaneshige { 26575d97c59SKenji Kaneshige int rc; 26675d97c59SKenji Kaneshige u32 cap_offset = ctrl->cap_offset; 26775d97c59SKenji Kaneshige struct pci_dev *pdev = ctrl->pci_dev; 26875d97c59SKenji Kaneshige 26975d97c59SKenji Kaneshige rc = pci_write_config_byte(pdev, cap_offset + DWORD_SELECT, index); 27075d97c59SKenji Kaneshige if (rc) 27175d97c59SKenji Kaneshige return rc; 27275d97c59SKenji Kaneshige return pci_read_config_dword(pdev, cap_offset + DWORD_DATA, value); 27375d97c59SKenji Kaneshige } 27475d97c59SKenji Kaneshige 2751da177e4SLinus Torvalds /* This is the interrupt polling timeout function. */ 2761da177e4SLinus Torvalds static void int_poll_timeout(unsigned long lphp_ctlr) 2771da177e4SLinus Torvalds { 2781da177e4SLinus Torvalds struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr; 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds DBG_ENTER_ROUTINE 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds if ( !php_ctlr ) { 2831da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 2841da177e4SLinus Torvalds return; 2851da177e4SLinus Torvalds } 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds /* Poll for interrupt events. regs == NULL => polling */ 288c4cecc19SKenji Kaneshige shpc_isr(0, php_ctlr->callback_instance_id, NULL ); 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds init_timer(&php_ctlr->int_poll_timer); 2911da177e4SLinus Torvalds if (!shpchp_poll_time) 2921da177e4SLinus Torvalds shpchp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/ 2931da177e4SLinus Torvalds 2941da177e4SLinus Torvalds start_int_poll_timer(php_ctlr, shpchp_poll_time); 2951da177e4SLinus Torvalds 2961da177e4SLinus Torvalds return; 2971da177e4SLinus Torvalds } 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds /* This function starts the interrupt polling timer. */ 3001da177e4SLinus Torvalds static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds) 3011da177e4SLinus Torvalds { 3021da177e4SLinus Torvalds if (!php_ctlr) { 3031da177e4SLinus Torvalds err("%s: Invalid HPC controller handle!\n", __FUNCTION__); 3041da177e4SLinus Torvalds return; 3051da177e4SLinus Torvalds } 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds if ( ( seconds <= 0 ) || ( seconds > 60 ) ) 3081da177e4SLinus Torvalds seconds = 2; /* Clamp to sane value */ 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds php_ctlr->int_poll_timer.function = &int_poll_timeout; 3111da177e4SLinus Torvalds php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr; /* Instance data */ 3121da177e4SLinus Torvalds php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ; 3131da177e4SLinus Torvalds add_timer(&php_ctlr->int_poll_timer); 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds return; 3161da177e4SLinus Torvalds } 3171da177e4SLinus Torvalds 318bd62e271SKenji Kaneshige static inline int shpc_wait_cmd(struct controller *ctrl) 319bd62e271SKenji Kaneshige { 320bd62e271SKenji Kaneshige int retval = 0; 321bd62e271SKenji Kaneshige unsigned int timeout_msec = shpchp_poll_mode ? 2000 : 1000; 322bd62e271SKenji Kaneshige unsigned long timeout = msecs_to_jiffies(timeout_msec); 323bd62e271SKenji Kaneshige int rc = wait_event_interruptible_timeout(ctrl->queue, 324bd62e271SKenji Kaneshige !ctrl->cmd_busy, timeout); 325bd62e271SKenji Kaneshige if (!rc) { 326bd62e271SKenji Kaneshige retval = -EIO; 327bd62e271SKenji Kaneshige err("Command not completed in %d msec\n", timeout_msec); 328bd62e271SKenji Kaneshige } else if (rc < 0) { 329bd62e271SKenji Kaneshige retval = -EINTR; 330bd62e271SKenji Kaneshige info("Command was interrupted by a signal\n"); 331bd62e271SKenji Kaneshige } 332bd62e271SKenji Kaneshige ctrl->cmd_busy = 0; 333bd62e271SKenji Kaneshige 334bd62e271SKenji Kaneshige return retval; 335bd62e271SKenji Kaneshige } 336bd62e271SKenji Kaneshige 3371da177e4SLinus Torvalds static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) 3381da177e4SLinus Torvalds { 33975d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 3401da177e4SLinus Torvalds u16 cmd_status; 3411da177e4SLinus Torvalds int retval = 0; 3421da177e4SLinus Torvalds u16 temp_word; 3431da177e4SLinus Torvalds int i; 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds DBG_ENTER_ROUTINE 3461da177e4SLinus Torvalds 347d29aaddaSKenji Kaneshige mutex_lock(&slot->ctrl->cmd_lock); 348d29aaddaSKenji Kaneshige 3491da177e4SLinus Torvalds for (i = 0; i < 10; i++) { 35075d97c59SKenji Kaneshige cmd_status = shpc_readw(ctrl, CMD_STATUS); 3511da177e4SLinus Torvalds 3521da177e4SLinus Torvalds if (!(cmd_status & 0x1)) 3531da177e4SLinus Torvalds break; 3541da177e4SLinus Torvalds /* Check every 0.1 sec for a total of 1 sec*/ 3551da177e4SLinus Torvalds msleep(100); 3561da177e4SLinus Torvalds } 3571da177e4SLinus Torvalds 35875d97c59SKenji Kaneshige cmd_status = shpc_readw(ctrl, CMD_STATUS); 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds if (cmd_status & 0x1) { 3611da177e4SLinus Torvalds /* After 1 sec and and the controller is still busy */ 3621da177e4SLinus Torvalds err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__); 363d29aaddaSKenji Kaneshige retval = -EBUSY; 364d29aaddaSKenji Kaneshige goto out; 3651da177e4SLinus Torvalds } 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds ++t_slot; 3681da177e4SLinus Torvalds temp_word = (t_slot << 8) | (cmd & 0xFF); 3691da177e4SLinus Torvalds dbg("%s: t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd); 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds /* To make sure the Controller Busy bit is 0 before we send out the 3721da177e4SLinus Torvalds * command. 3731da177e4SLinus Torvalds */ 374bd62e271SKenji Kaneshige slot->ctrl->cmd_busy = 1; 37575d97c59SKenji Kaneshige shpc_writew(ctrl, CMD, temp_word); 3761da177e4SLinus Torvalds 377bd62e271SKenji Kaneshige /* 378bd62e271SKenji Kaneshige * Wait for command completion. 379bd62e271SKenji Kaneshige */ 380bd62e271SKenji Kaneshige retval = shpc_wait_cmd(slot->ctrl); 381d29aaddaSKenji Kaneshige if (retval) 382d29aaddaSKenji Kaneshige goto out; 383d29aaddaSKenji Kaneshige 384d29aaddaSKenji Kaneshige cmd_status = hpc_check_cmd_status(slot->ctrl); 385d29aaddaSKenji Kaneshige if (cmd_status) { 386d29aaddaSKenji Kaneshige err("%s: Failed to issued command 0x%x (error code = %d)\n", 387d29aaddaSKenji Kaneshige __FUNCTION__, cmd, cmd_status); 388d29aaddaSKenji Kaneshige retval = -EIO; 389d29aaddaSKenji Kaneshige } 390d29aaddaSKenji Kaneshige out: 391d29aaddaSKenji Kaneshige mutex_unlock(&slot->ctrl->cmd_lock); 392bd62e271SKenji Kaneshige 3931da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 3941da177e4SLinus Torvalds return retval; 3951da177e4SLinus Torvalds } 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds static int hpc_check_cmd_status(struct controller *ctrl) 3981da177e4SLinus Torvalds { 3991da177e4SLinus Torvalds u16 cmd_status; 4001da177e4SLinus Torvalds int retval = 0; 4011da177e4SLinus Torvalds 4021da177e4SLinus Torvalds DBG_ENTER_ROUTINE 4031da177e4SLinus Torvalds 40475d97c59SKenji Kaneshige cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F; 4051da177e4SLinus Torvalds 4061da177e4SLinus Torvalds switch (cmd_status >> 1) { 4071da177e4SLinus Torvalds case 0: 4081da177e4SLinus Torvalds retval = 0; 4091da177e4SLinus Torvalds break; 4101da177e4SLinus Torvalds case 1: 4111da177e4SLinus Torvalds retval = SWITCH_OPEN; 4121da177e4SLinus Torvalds err("%s: Switch opened!\n", __FUNCTION__); 4131da177e4SLinus Torvalds break; 4141da177e4SLinus Torvalds case 2: 4151da177e4SLinus Torvalds retval = INVALID_CMD; 4161da177e4SLinus Torvalds err("%s: Invalid HPC command!\n", __FUNCTION__); 4171da177e4SLinus Torvalds break; 4181da177e4SLinus Torvalds case 4: 4191da177e4SLinus Torvalds retval = INVALID_SPEED_MODE; 4201da177e4SLinus Torvalds err("%s: Invalid bus speed/mode!\n", __FUNCTION__); 4211da177e4SLinus Torvalds break; 4221da177e4SLinus Torvalds default: 4231da177e4SLinus Torvalds retval = cmd_status; 4241da177e4SLinus Torvalds } 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 4271da177e4SLinus Torvalds return retval; 4281da177e4SLinus Torvalds } 4291da177e4SLinus Torvalds 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds static int hpc_get_attention_status(struct slot *slot, u8 *status) 4321da177e4SLinus Torvalds { 43375d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 4341da177e4SLinus Torvalds u32 slot_reg; 4355858759cSKenji Kaneshige u8 state; 4361da177e4SLinus Torvalds 4371da177e4SLinus Torvalds DBG_ENTER_ROUTINE 4381da177e4SLinus Torvalds 4392b34da7eSKenji Kaneshige slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); 4405858759cSKenji Kaneshige state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT; 4411da177e4SLinus Torvalds 4425858759cSKenji Kaneshige switch (state) { 4435858759cSKenji Kaneshige case ATN_LED_STATE_ON: 4441da177e4SLinus Torvalds *status = 1; /* On */ 4451da177e4SLinus Torvalds break; 4465858759cSKenji Kaneshige case ATN_LED_STATE_BLINK: 4471da177e4SLinus Torvalds *status = 2; /* Blink */ 4481da177e4SLinus Torvalds break; 4495858759cSKenji Kaneshige case ATN_LED_STATE_OFF: 4501da177e4SLinus Torvalds *status = 0; /* Off */ 4511da177e4SLinus Torvalds break; 4521da177e4SLinus Torvalds default: 4535858759cSKenji Kaneshige *status = 0xFF; /* Reserved */ 4541da177e4SLinus Torvalds break; 4551da177e4SLinus Torvalds } 4561da177e4SLinus Torvalds 4571da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 4581da177e4SLinus Torvalds return 0; 4591da177e4SLinus Torvalds } 4601da177e4SLinus Torvalds 4611da177e4SLinus Torvalds static int hpc_get_power_status(struct slot * slot, u8 *status) 4621da177e4SLinus Torvalds { 46375d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 4641da177e4SLinus Torvalds u32 slot_reg; 4655858759cSKenji Kaneshige u8 state; 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds DBG_ENTER_ROUTINE 4681da177e4SLinus Torvalds 4692b34da7eSKenji Kaneshige slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); 4705858759cSKenji Kaneshige state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT; 4711da177e4SLinus Torvalds 4725858759cSKenji Kaneshige switch (state) { 4735858759cSKenji Kaneshige case SLOT_STATE_PWRONLY: 4741da177e4SLinus Torvalds *status = 2; /* Powered only */ 4751da177e4SLinus Torvalds break; 4765858759cSKenji Kaneshige case SLOT_STATE_ENABLED: 4771da177e4SLinus Torvalds *status = 1; /* Enabled */ 4781da177e4SLinus Torvalds break; 4795858759cSKenji Kaneshige case SLOT_STATE_DISABLED: 4801da177e4SLinus Torvalds *status = 0; /* Disabled */ 4811da177e4SLinus Torvalds break; 4821da177e4SLinus Torvalds default: 4835858759cSKenji Kaneshige *status = 0xFF; /* Reserved */ 4841da177e4SLinus Torvalds break; 4851da177e4SLinus Torvalds } 4861da177e4SLinus Torvalds 4871da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 4885858759cSKenji Kaneshige return 0; 4891da177e4SLinus Torvalds } 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds static int hpc_get_latch_status(struct slot *slot, u8 *status) 4931da177e4SLinus Torvalds { 49475d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 4951da177e4SLinus Torvalds u32 slot_reg; 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds DBG_ENTER_ROUTINE 4981da177e4SLinus Torvalds 4992b34da7eSKenji Kaneshige slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); 5005858759cSKenji Kaneshige *status = !!(slot_reg & MRL_SENSOR); /* 0 -> close; 1 -> open */ 5011da177e4SLinus Torvalds 5021da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 5031da177e4SLinus Torvalds return 0; 5041da177e4SLinus Torvalds } 5051da177e4SLinus Torvalds 5061da177e4SLinus Torvalds static int hpc_get_adapter_status(struct slot *slot, u8 *status) 5071da177e4SLinus Torvalds { 50875d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 5091da177e4SLinus Torvalds u32 slot_reg; 5105858759cSKenji Kaneshige u8 state; 5111da177e4SLinus Torvalds 5121da177e4SLinus Torvalds DBG_ENTER_ROUTINE 5131da177e4SLinus Torvalds 5142b34da7eSKenji Kaneshige slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); 5155858759cSKenji Kaneshige state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT; 5165858759cSKenji Kaneshige *status = (state != 0x3) ? 1 : 0; 5171da177e4SLinus Torvalds 5181da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 5191da177e4SLinus Torvalds return 0; 5201da177e4SLinus Torvalds } 5211da177e4SLinus Torvalds 5221da177e4SLinus Torvalds static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) 5231da177e4SLinus Torvalds { 52475d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 5251da177e4SLinus Torvalds 5261da177e4SLinus Torvalds DBG_ENTER_ROUTINE 5271da177e4SLinus Torvalds 52875d97c59SKenji Kaneshige *prog_int = shpc_readb(ctrl, PROG_INTERFACE); 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 5311da177e4SLinus Torvalds return 0; 5321da177e4SLinus Torvalds } 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) 5351da177e4SLinus Torvalds { 5361da177e4SLinus Torvalds int retval = 0; 53775d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 5382b34da7eSKenji Kaneshige u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); 5395858759cSKenji Kaneshige u8 m66_cap = !!(slot_reg & MHZ66_CAP); 540795eb5c4SKenji Kaneshige u8 pi, pcix_cap; 5411da177e4SLinus Torvalds 5421da177e4SLinus Torvalds DBG_ENTER_ROUTINE 5431da177e4SLinus Torvalds 544795eb5c4SKenji Kaneshige if ((retval = hpc_get_prog_int(slot, &pi))) 545795eb5c4SKenji Kaneshige return retval; 546795eb5c4SKenji Kaneshige 547795eb5c4SKenji Kaneshige switch (pi) { 548795eb5c4SKenji Kaneshige case 1: 549795eb5c4SKenji Kaneshige pcix_cap = (slot_reg & PCIX_CAP_MASK_PI1) >> PCIX_CAP_SHIFT; 550795eb5c4SKenji Kaneshige break; 551795eb5c4SKenji Kaneshige case 2: 552795eb5c4SKenji Kaneshige pcix_cap = (slot_reg & PCIX_CAP_MASK_PI2) >> PCIX_CAP_SHIFT; 553795eb5c4SKenji Kaneshige break; 554795eb5c4SKenji Kaneshige default: 555795eb5c4SKenji Kaneshige return -ENODEV; 556795eb5c4SKenji Kaneshige } 557795eb5c4SKenji Kaneshige 5580afabe90SKenji Kaneshige dbg("%s: slot_reg = %x, pcix_cap = %x, m66_cap = %x\n", 5590afabe90SKenji Kaneshige __FUNCTION__, slot_reg, pcix_cap, m66_cap); 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds switch (pcix_cap) { 5620afabe90SKenji Kaneshige case 0x0: 5631da177e4SLinus Torvalds *value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; 5641da177e4SLinus Torvalds break; 5650afabe90SKenji Kaneshige case 0x1: 5661da177e4SLinus Torvalds *value = PCI_SPEED_66MHz_PCIX; 5671da177e4SLinus Torvalds break; 5680afabe90SKenji Kaneshige case 0x3: 5691da177e4SLinus Torvalds *value = PCI_SPEED_133MHz_PCIX; 5701da177e4SLinus Torvalds break; 5710afabe90SKenji Kaneshige case 0x4: 5721da177e4SLinus Torvalds *value = PCI_SPEED_133MHz_PCIX_266; 5731da177e4SLinus Torvalds break; 5740afabe90SKenji Kaneshige case 0x5: 5751da177e4SLinus Torvalds *value = PCI_SPEED_133MHz_PCIX_533; 5761da177e4SLinus Torvalds break; 5770afabe90SKenji Kaneshige case 0x2: 5781da177e4SLinus Torvalds default: 5791da177e4SLinus Torvalds *value = PCI_SPEED_UNKNOWN; 5801da177e4SLinus Torvalds retval = -ENODEV; 5811da177e4SLinus Torvalds break; 5821da177e4SLinus Torvalds } 5831da177e4SLinus Torvalds 5841da177e4SLinus Torvalds dbg("Adapter speed = %d\n", *value); 5851da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 5861da177e4SLinus Torvalds return retval; 5871da177e4SLinus Torvalds } 5881da177e4SLinus Torvalds 5891da177e4SLinus Torvalds static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) 5901da177e4SLinus Torvalds { 59175d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 5921da177e4SLinus Torvalds u16 sec_bus_status; 5931da177e4SLinus Torvalds u8 pi; 5941da177e4SLinus Torvalds int retval = 0; 5951da177e4SLinus Torvalds 5961da177e4SLinus Torvalds DBG_ENTER_ROUTINE 5971da177e4SLinus Torvalds 59875d97c59SKenji Kaneshige pi = shpc_readb(ctrl, PROG_INTERFACE); 59975d97c59SKenji Kaneshige sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG); 6001da177e4SLinus Torvalds 6011da177e4SLinus Torvalds if (pi == 2) { 60287d6c559SKenji Kaneshige *mode = (sec_bus_status & 0x0100) >> 8; 6031da177e4SLinus Torvalds } else { 6041da177e4SLinus Torvalds retval = -1; 6051da177e4SLinus Torvalds } 6061da177e4SLinus Torvalds 6071da177e4SLinus Torvalds dbg("Mode 1 ECC cap = %d\n", *mode); 6081da177e4SLinus Torvalds 6091da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 6101da177e4SLinus Torvalds return retval; 6111da177e4SLinus Torvalds } 6121da177e4SLinus Torvalds 6131da177e4SLinus Torvalds static int hpc_query_power_fault(struct slot * slot) 6141da177e4SLinus Torvalds { 61575d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 6161da177e4SLinus Torvalds u32 slot_reg; 6171da177e4SLinus Torvalds 6181da177e4SLinus Torvalds DBG_ENTER_ROUTINE 6191da177e4SLinus Torvalds 6202b34da7eSKenji Kaneshige slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); 6211da177e4SLinus Torvalds 6221da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 6231da177e4SLinus Torvalds /* Note: Logic 0 => fault */ 6245858759cSKenji Kaneshige return !(slot_reg & POWER_FAULT); 6251da177e4SLinus Torvalds } 6261da177e4SLinus Torvalds 6271da177e4SLinus Torvalds static int hpc_set_attention_status(struct slot *slot, u8 value) 6281da177e4SLinus Torvalds { 6291da177e4SLinus Torvalds u8 slot_cmd = 0; 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds switch (value) { 6321da177e4SLinus Torvalds case 0 : 6331da177e4SLinus Torvalds slot_cmd = 0x30; /* OFF */ 6341da177e4SLinus Torvalds break; 6351da177e4SLinus Torvalds case 1: 6361da177e4SLinus Torvalds slot_cmd = 0x10; /* ON */ 6371da177e4SLinus Torvalds break; 6381da177e4SLinus Torvalds case 2: 6391da177e4SLinus Torvalds slot_cmd = 0x20; /* BLINK */ 6401da177e4SLinus Torvalds break; 6411da177e4SLinus Torvalds default: 6421da177e4SLinus Torvalds return -1; 6431da177e4SLinus Torvalds } 6441da177e4SLinus Torvalds 645d4fbf600SKenji Kaneshige return shpc_write_cmd(slot, slot->hp_slot, slot_cmd); 6461da177e4SLinus Torvalds } 6471da177e4SLinus Torvalds 6481da177e4SLinus Torvalds 6491da177e4SLinus Torvalds static void hpc_set_green_led_on(struct slot *slot) 6501da177e4SLinus Torvalds { 651d4fbf600SKenji Kaneshige shpc_write_cmd(slot, slot->hp_slot, 0x04); 6521da177e4SLinus Torvalds } 6531da177e4SLinus Torvalds 6541da177e4SLinus Torvalds static void hpc_set_green_led_off(struct slot *slot) 6551da177e4SLinus Torvalds { 656d4fbf600SKenji Kaneshige shpc_write_cmd(slot, slot->hp_slot, 0x0c); 6571da177e4SLinus Torvalds } 6581da177e4SLinus Torvalds 6591da177e4SLinus Torvalds static void hpc_set_green_led_blink(struct slot *slot) 6601da177e4SLinus Torvalds { 661d4fbf600SKenji Kaneshige shpc_write_cmd(slot, slot->hp_slot, 0x08); 6621da177e4SLinus Torvalds } 6631da177e4SLinus Torvalds 6641da177e4SLinus Torvalds int shpc_get_ctlr_slot_config(struct controller *ctrl, 6651da177e4SLinus Torvalds int *num_ctlr_slots, /* number of slots in this HPC */ 6661da177e4SLinus Torvalds int *first_device_num, /* PCI dev num of the first slot in this SHPC */ 6671da177e4SLinus Torvalds int *physical_slot_num, /* phy slot num of the first slot in this SHPC */ 6681da177e4SLinus Torvalds int *updown, /* physical_slot_num increament: 1 or -1 */ 6691da177e4SLinus Torvalds int *flags) 6701da177e4SLinus Torvalds { 67175d97c59SKenji Kaneshige u32 slot_config; 6721da177e4SLinus Torvalds 6731da177e4SLinus Torvalds DBG_ENTER_ROUTINE 6741da177e4SLinus Torvalds 67575d97c59SKenji Kaneshige slot_config = shpc_readl(ctrl, SLOT_CONFIG); 67675d97c59SKenji Kaneshige *first_device_num = (slot_config & FIRST_DEV_NUM) >> 8; 67775d97c59SKenji Kaneshige *num_ctlr_slots = slot_config & SLOT_NUM; 67875d97c59SKenji Kaneshige *physical_slot_num = (slot_config & PSN) >> 16; 67975d97c59SKenji Kaneshige *updown = ((slot_config & UPDOWN) >> 29) ? 1 : -1; 6801da177e4SLinus Torvalds 6811da177e4SLinus Torvalds dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num); 6821da177e4SLinus Torvalds 6831da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 6841da177e4SLinus Torvalds return 0; 6851da177e4SLinus Torvalds } 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds static void hpc_release_ctlr(struct controller *ctrl) 6881da177e4SLinus Torvalds { 689ee138334Srajesh.shah@intel.com struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; 6901da177e4SLinus Torvalds struct php_ctlr_state_s *p, *p_prev; 691f7391f53SKenji Kaneshige int i; 692d49f2c49SKenji Kaneshige u32 slot_reg, serr_int; 6931da177e4SLinus Torvalds 6941da177e4SLinus Torvalds DBG_ENTER_ROUTINE 6951da177e4SLinus Torvalds 696f7391f53SKenji Kaneshige /* 697795eb5c4SKenji Kaneshige * Mask event interrupts and SERRs of all slots 698f7391f53SKenji Kaneshige */ 699795eb5c4SKenji Kaneshige for (i = 0; i < ctrl->num_slots; i++) { 700795eb5c4SKenji Kaneshige slot_reg = shpc_readl(ctrl, SLOT_REG(i)); 701795eb5c4SKenji Kaneshige slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | 702795eb5c4SKenji Kaneshige BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | 703795eb5c4SKenji Kaneshige CON_PFAULT_INTR_MASK | MRL_CHANGE_SERR_MASK | 704795eb5c4SKenji Kaneshige CON_PFAULT_SERR_MASK); 705795eb5c4SKenji Kaneshige slot_reg &= ~SLOT_REG_RSVDZ_MASK; 706795eb5c4SKenji Kaneshige shpc_writel(ctrl, SLOT_REG(i), slot_reg); 707795eb5c4SKenji Kaneshige } 708f7391f53SKenji Kaneshige 709f7391f53SKenji Kaneshige cleanup_slots(ctrl); 710f7391f53SKenji Kaneshige 711d49f2c49SKenji Kaneshige /* 712d49f2c49SKenji Kaneshige * Mask SERR and System Interrut generation 713d49f2c49SKenji Kaneshige */ 714d49f2c49SKenji Kaneshige serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); 715d49f2c49SKenji Kaneshige serr_int |= (GLOBAL_INTR_MASK | GLOBAL_SERR_MASK | 716d49f2c49SKenji Kaneshige COMMAND_INTR_MASK | ARBITER_SERR_MASK); 717d49f2c49SKenji Kaneshige serr_int &= ~SERR_INTR_RSVDZ_MASK; 718d49f2c49SKenji Kaneshige shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); 719d49f2c49SKenji Kaneshige 7201da177e4SLinus Torvalds if (shpchp_poll_mode) { 7211da177e4SLinus Torvalds del_timer(&php_ctlr->int_poll_timer); 7221da177e4SLinus Torvalds } else { 7231da177e4SLinus Torvalds if (php_ctlr->irq) { 7241da177e4SLinus Torvalds free_irq(php_ctlr->irq, ctrl); 7251da177e4SLinus Torvalds php_ctlr->irq = 0; 7261da177e4SLinus Torvalds pci_disable_msi(php_ctlr->pci_dev); 7271da177e4SLinus Torvalds } 7281da177e4SLinus Torvalds } 729f7391f53SKenji Kaneshige 7301da177e4SLinus Torvalds if (php_ctlr->pci_dev) { 7311da177e4SLinus Torvalds iounmap(php_ctlr->creg); 7320455986cSKenji Kaneshige release_mem_region(ctrl->mmio_base, ctrl->mmio_size); 7331da177e4SLinus Torvalds php_ctlr->pci_dev = NULL; 7341da177e4SLinus Torvalds } 7351da177e4SLinus Torvalds 7361da177e4SLinus Torvalds spin_lock(&list_lock); 7371da177e4SLinus Torvalds p = php_ctlr_list_head; 7381da177e4SLinus Torvalds p_prev = NULL; 7391da177e4SLinus Torvalds while (p) { 7401da177e4SLinus Torvalds if (p == php_ctlr) { 7411da177e4SLinus Torvalds if (p_prev) 7421da177e4SLinus Torvalds p_prev->pnext = p->pnext; 7431da177e4SLinus Torvalds else 7441da177e4SLinus Torvalds php_ctlr_list_head = p->pnext; 7451da177e4SLinus Torvalds break; 7461da177e4SLinus Torvalds } else { 7471da177e4SLinus Torvalds p_prev = p; 7481da177e4SLinus Torvalds p = p->pnext; 7491da177e4SLinus Torvalds } 7501da177e4SLinus Torvalds } 7511da177e4SLinus Torvalds spin_unlock(&list_lock); 7521da177e4SLinus Torvalds 7531da177e4SLinus Torvalds kfree(php_ctlr); 7541da177e4SLinus Torvalds 75582d5f4aaSKenji Kaneshige /* 75682d5f4aaSKenji Kaneshige * If this is the last controller to be released, destroy the 75782d5f4aaSKenji Kaneshige * shpchpd work queue 75882d5f4aaSKenji Kaneshige */ 75982d5f4aaSKenji Kaneshige if (atomic_dec_and_test(&shpchp_num_controllers)) 76082d5f4aaSKenji Kaneshige destroy_workqueue(shpchp_wq); 76182d5f4aaSKenji Kaneshige 7621da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 7631da177e4SLinus Torvalds 7641da177e4SLinus Torvalds } 7651da177e4SLinus Torvalds 7661da177e4SLinus Torvalds static int hpc_power_on_slot(struct slot * slot) 7671da177e4SLinus Torvalds { 768d4fbf600SKenji Kaneshige int retval; 7691da177e4SLinus Torvalds 7701da177e4SLinus Torvalds DBG_ENTER_ROUTINE 7711da177e4SLinus Torvalds 772d4fbf600SKenji Kaneshige retval = shpc_write_cmd(slot, slot->hp_slot, 0x01); 7731da177e4SLinus Torvalds if (retval) { 7741da177e4SLinus Torvalds err("%s: Write command failed!\n", __FUNCTION__); 775d4fbf600SKenji Kaneshige return retval; 7761da177e4SLinus Torvalds } 7771da177e4SLinus Torvalds 7781da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 7791da177e4SLinus Torvalds 780d4fbf600SKenji Kaneshige return 0; 7811da177e4SLinus Torvalds } 7821da177e4SLinus Torvalds 7831da177e4SLinus Torvalds static int hpc_slot_enable(struct slot * slot) 7841da177e4SLinus Torvalds { 785d4fbf600SKenji Kaneshige int retval; 7861da177e4SLinus Torvalds 7871da177e4SLinus Torvalds DBG_ENTER_ROUTINE 7881da177e4SLinus Torvalds 7891da177e4SLinus Torvalds /* 3A => Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */ 790d4fbf600SKenji Kaneshige retval = shpc_write_cmd(slot, slot->hp_slot, 0x3a); 7911da177e4SLinus Torvalds if (retval) { 7921da177e4SLinus Torvalds err("%s: Write command failed!\n", __FUNCTION__); 793d4fbf600SKenji Kaneshige return retval; 7941da177e4SLinus Torvalds } 7951da177e4SLinus Torvalds 7961da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 797d4fbf600SKenji Kaneshige return 0; 7981da177e4SLinus Torvalds } 7991da177e4SLinus Torvalds 8001da177e4SLinus Torvalds static int hpc_slot_disable(struct slot * slot) 8011da177e4SLinus Torvalds { 802d4fbf600SKenji Kaneshige int retval; 8031da177e4SLinus Torvalds 8041da177e4SLinus Torvalds DBG_ENTER_ROUTINE 8051da177e4SLinus Torvalds 8061da177e4SLinus Torvalds /* 1F => Slot - Disable, Power Indicator - Off, Attention Indicator - On */ 807d4fbf600SKenji Kaneshige retval = shpc_write_cmd(slot, slot->hp_slot, 0x1f); 8081da177e4SLinus Torvalds if (retval) { 8091da177e4SLinus Torvalds err("%s: Write command failed!\n", __FUNCTION__); 810d4fbf600SKenji Kaneshige return retval; 8111da177e4SLinus Torvalds } 8121da177e4SLinus Torvalds 8131da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 814d4fbf600SKenji Kaneshige return 0; 8151da177e4SLinus Torvalds } 8161da177e4SLinus Torvalds 8171da177e4SLinus Torvalds static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) 8181da177e4SLinus Torvalds { 8190afabe90SKenji Kaneshige int retval; 82075d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 8210afabe90SKenji Kaneshige u8 pi, cmd; 8221da177e4SLinus Torvalds 8231da177e4SLinus Torvalds DBG_ENTER_ROUTINE 8241da177e4SLinus Torvalds 82575d97c59SKenji Kaneshige pi = shpc_readb(ctrl, PROG_INTERFACE); 8260afabe90SKenji Kaneshige if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX)) 8270afabe90SKenji Kaneshige return -EINVAL; 8281da177e4SLinus Torvalds 8291da177e4SLinus Torvalds switch (value) { 8300afabe90SKenji Kaneshige case PCI_SPEED_33MHz: 8310afabe90SKenji Kaneshige cmd = SETA_PCI_33MHZ; 8321da177e4SLinus Torvalds break; 8330afabe90SKenji Kaneshige case PCI_SPEED_66MHz: 8340afabe90SKenji Kaneshige cmd = SETA_PCI_66MHZ; 8351da177e4SLinus Torvalds break; 8360afabe90SKenji Kaneshige case PCI_SPEED_66MHz_PCIX: 8370afabe90SKenji Kaneshige cmd = SETA_PCIX_66MHZ; 8381da177e4SLinus Torvalds break; 8390afabe90SKenji Kaneshige case PCI_SPEED_100MHz_PCIX: 8400afabe90SKenji Kaneshige cmd = SETA_PCIX_100MHZ; 8411da177e4SLinus Torvalds break; 8420afabe90SKenji Kaneshige case PCI_SPEED_133MHz_PCIX: 8430afabe90SKenji Kaneshige cmd = SETA_PCIX_133MHZ; 8440afabe90SKenji Kaneshige break; 8450afabe90SKenji Kaneshige case PCI_SPEED_66MHz_PCIX_ECC: 8460afabe90SKenji Kaneshige cmd = SETB_PCIX_66MHZ_EM; 8470afabe90SKenji Kaneshige break; 8480afabe90SKenji Kaneshige case PCI_SPEED_100MHz_PCIX_ECC: 8490afabe90SKenji Kaneshige cmd = SETB_PCIX_100MHZ_EM; 8500afabe90SKenji Kaneshige break; 8510afabe90SKenji Kaneshige case PCI_SPEED_133MHz_PCIX_ECC: 8520afabe90SKenji Kaneshige cmd = SETB_PCIX_133MHZ_EM; 8530afabe90SKenji Kaneshige break; 8540afabe90SKenji Kaneshige case PCI_SPEED_66MHz_PCIX_266: 8550afabe90SKenji Kaneshige cmd = SETB_PCIX_66MHZ_266; 8560afabe90SKenji Kaneshige break; 8570afabe90SKenji Kaneshige case PCI_SPEED_100MHz_PCIX_266: 8580afabe90SKenji Kaneshige cmd = SETB_PCIX_100MHZ_266; 8590afabe90SKenji Kaneshige break; 8600afabe90SKenji Kaneshige case PCI_SPEED_133MHz_PCIX_266: 8610afabe90SKenji Kaneshige cmd = SETB_PCIX_133MHZ_266; 8620afabe90SKenji Kaneshige break; 8630afabe90SKenji Kaneshige case PCI_SPEED_66MHz_PCIX_533: 8640afabe90SKenji Kaneshige cmd = SETB_PCIX_66MHZ_533; 8650afabe90SKenji Kaneshige break; 8660afabe90SKenji Kaneshige case PCI_SPEED_100MHz_PCIX_533: 8670afabe90SKenji Kaneshige cmd = SETB_PCIX_100MHZ_533; 8680afabe90SKenji Kaneshige break; 8690afabe90SKenji Kaneshige case PCI_SPEED_133MHz_PCIX_533: 8700afabe90SKenji Kaneshige cmd = SETB_PCIX_133MHZ_533; 8711da177e4SLinus Torvalds break; 8721da177e4SLinus Torvalds default: 8730afabe90SKenji Kaneshige return -EINVAL; 8741da177e4SLinus Torvalds } 8751da177e4SLinus Torvalds 8760afabe90SKenji Kaneshige retval = shpc_write_cmd(slot, 0, cmd); 8770afabe90SKenji Kaneshige if (retval) 8781da177e4SLinus Torvalds err("%s: Write command failed!\n", __FUNCTION__); 8791da177e4SLinus Torvalds 8801da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 8811da177e4SLinus Torvalds return retval; 8821da177e4SLinus Torvalds } 8831da177e4SLinus Torvalds 884c4cecc19SKenji Kaneshige static irqreturn_t shpc_isr(int irq, void *dev_id, struct pt_regs *regs) 8851da177e4SLinus Torvalds { 886c4cecc19SKenji Kaneshige struct controller *ctrl = (struct controller *)dev_id; 887c4cecc19SKenji Kaneshige struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; 888c4cecc19SKenji Kaneshige u32 serr_int, slot_reg, intr_loc, intr_loc2; 8891da177e4SLinus Torvalds int hp_slot; 8901da177e4SLinus Torvalds 8911da177e4SLinus Torvalds /* Check to see if it was our interrupt */ 89275d97c59SKenji Kaneshige intr_loc = shpc_readl(ctrl, INTR_LOC); 8931da177e4SLinus Torvalds if (!intr_loc) 8941da177e4SLinus Torvalds return IRQ_NONE; 895c4cecc19SKenji Kaneshige 8961da177e4SLinus Torvalds dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); 8971da177e4SLinus Torvalds 8981da177e4SLinus Torvalds if(!shpchp_poll_mode) { 899c4cecc19SKenji Kaneshige /* 900c4cecc19SKenji Kaneshige * Mask Global Interrupt Mask - see implementation 901c4cecc19SKenji Kaneshige * note on p. 139 of SHPC spec rev 1.0 902c4cecc19SKenji Kaneshige */ 903c4cecc19SKenji Kaneshige serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); 904c4cecc19SKenji Kaneshige serr_int |= GLOBAL_INTR_MASK; 905c4cecc19SKenji Kaneshige serr_int &= ~SERR_INTR_RSVDZ_MASK; 906c4cecc19SKenji Kaneshige shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); 9071da177e4SLinus Torvalds 90875d97c59SKenji Kaneshige intr_loc2 = shpc_readl(ctrl, INTR_LOC); 9091da177e4SLinus Torvalds dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); 9101da177e4SLinus Torvalds } 9111da177e4SLinus Torvalds 912c4cecc19SKenji Kaneshige if (intr_loc & CMD_INTR_PENDING) { 9131da177e4SLinus Torvalds /* 9141da177e4SLinus Torvalds * Command Complete Interrupt Pending 915f467f618SKenji Kaneshige * RO only - clear by writing 1 to the Command Completion 9161da177e4SLinus Torvalds * Detect bit in Controller SERR-INT register 9171da177e4SLinus Torvalds */ 918c4cecc19SKenji Kaneshige serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); 919c4cecc19SKenji Kaneshige serr_int &= ~SERR_INTR_RSVDZ_MASK; 920c4cecc19SKenji Kaneshige shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); 921c4cecc19SKenji Kaneshige 922bd62e271SKenji Kaneshige ctrl->cmd_busy = 0; 9231da177e4SLinus Torvalds wake_up_interruptible(&ctrl->queue); 9241da177e4SLinus Torvalds } 9251da177e4SLinus Torvalds 926c4cecc19SKenji Kaneshige if (!(intr_loc & ~CMD_INTR_PENDING)) 927e4e73041SKenji Kaneshige goto out; 9281da177e4SLinus Torvalds 9291da177e4SLinus Torvalds for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { 9301da177e4SLinus Torvalds /* To find out which slot has interrupt pending */ 931c4cecc19SKenji Kaneshige if (!(intr_loc & SLOT_INTR_PENDING(hp_slot))) 932c4cecc19SKenji Kaneshige continue; 933c4cecc19SKenji Kaneshige 934c4cecc19SKenji Kaneshige slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); 9357c8942f9Srajesh.shah@intel.com dbg("%s: Slot %x with intr, slot register = %x\n", 936c4cecc19SKenji Kaneshige __FUNCTION__, hp_slot, slot_reg); 937c4cecc19SKenji Kaneshige 938c4cecc19SKenji Kaneshige if (slot_reg & MRL_CHANGE_DETECTED) 939c4cecc19SKenji Kaneshige php_ctlr->switch_change_callback( 9401da177e4SLinus Torvalds hp_slot, php_ctlr->callback_instance_id); 941c4cecc19SKenji Kaneshige 942c4cecc19SKenji Kaneshige if (slot_reg & BUTTON_PRESS_DETECTED) 943c4cecc19SKenji Kaneshige php_ctlr->attention_button_callback( 9441da177e4SLinus Torvalds hp_slot, php_ctlr->callback_instance_id); 945c4cecc19SKenji Kaneshige 946c4cecc19SKenji Kaneshige if (slot_reg & PRSNT_CHANGE_DETECTED) 947c4cecc19SKenji Kaneshige php_ctlr->presence_change_callback( 9481da177e4SLinus Torvalds hp_slot , php_ctlr->callback_instance_id); 949c4cecc19SKenji Kaneshige 950c4cecc19SKenji Kaneshige if (slot_reg & (ISO_PFAULT_DETECTED | CON_PFAULT_DETECTED)) 951c4cecc19SKenji Kaneshige php_ctlr->power_fault_callback( 9521da177e4SLinus Torvalds hp_slot, php_ctlr->callback_instance_id); 9531da177e4SLinus Torvalds 9541da177e4SLinus Torvalds /* Clear all slot events */ 955c4cecc19SKenji Kaneshige slot_reg &= ~SLOT_REG_RSVDZ_MASK; 956c4cecc19SKenji Kaneshige shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); 9571da177e4SLinus Torvalds } 958e4e73041SKenji Kaneshige out: 9591da177e4SLinus Torvalds if (!shpchp_poll_mode) { 9601da177e4SLinus Torvalds /* Unmask Global Interrupt Mask */ 961c4cecc19SKenji Kaneshige serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); 962c4cecc19SKenji Kaneshige serr_int &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK); 963c4cecc19SKenji Kaneshige shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); 9641da177e4SLinus Torvalds } 9651da177e4SLinus Torvalds 9661da177e4SLinus Torvalds return IRQ_HANDLED; 9671da177e4SLinus Torvalds } 9681da177e4SLinus Torvalds 9691da177e4SLinus Torvalds static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) 9701da177e4SLinus Torvalds { 9710afabe90SKenji Kaneshige int retval = 0; 97275d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 9731da177e4SLinus Torvalds enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; 97475d97c59SKenji Kaneshige u8 pi = shpc_readb(ctrl, PROG_INTERFACE); 97575d97c59SKenji Kaneshige u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1); 97675d97c59SKenji Kaneshige u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2); 9771da177e4SLinus Torvalds 9781da177e4SLinus Torvalds DBG_ENTER_ROUTINE 9791da177e4SLinus Torvalds 9801da177e4SLinus Torvalds if (pi == 2) { 9816558b6abSKenji Kaneshige if (slot_avail2 & SLOT_133MHZ_PCIX_533) 9820afabe90SKenji Kaneshige bus_speed = PCI_SPEED_133MHz_PCIX_533; 9836558b6abSKenji Kaneshige else if (slot_avail2 & SLOT_100MHZ_PCIX_533) 9840afabe90SKenji Kaneshige bus_speed = PCI_SPEED_100MHz_PCIX_533; 9856558b6abSKenji Kaneshige else if (slot_avail2 & SLOT_66MHZ_PCIX_533) 9860afabe90SKenji Kaneshige bus_speed = PCI_SPEED_66MHz_PCIX_533; 9876558b6abSKenji Kaneshige else if (slot_avail2 & SLOT_133MHZ_PCIX_266) 9880afabe90SKenji Kaneshige bus_speed = PCI_SPEED_133MHz_PCIX_266; 9896558b6abSKenji Kaneshige else if (slot_avail2 & SLOT_100MHZ_PCIX_266) 9900afabe90SKenji Kaneshige bus_speed = PCI_SPEED_100MHz_PCIX_266; 9916558b6abSKenji Kaneshige else if (slot_avail2 & SLOT_66MHZ_PCIX_266) 9920afabe90SKenji Kaneshige bus_speed = PCI_SPEED_66MHz_PCIX_266; 9930afabe90SKenji Kaneshige } 9940afabe90SKenji Kaneshige 9950afabe90SKenji Kaneshige if (bus_speed == PCI_SPEED_UNKNOWN) { 9966558b6abSKenji Kaneshige if (slot_avail1 & SLOT_133MHZ_PCIX) 9970afabe90SKenji Kaneshige bus_speed = PCI_SPEED_133MHz_PCIX; 9986558b6abSKenji Kaneshige else if (slot_avail1 & SLOT_100MHZ_PCIX) 9990afabe90SKenji Kaneshige bus_speed = PCI_SPEED_100MHz_PCIX; 10006558b6abSKenji Kaneshige else if (slot_avail1 & SLOT_66MHZ_PCIX) 10010afabe90SKenji Kaneshige bus_speed = PCI_SPEED_66MHz_PCIX; 10026558b6abSKenji Kaneshige else if (slot_avail2 & SLOT_66MHZ) 10030afabe90SKenji Kaneshige bus_speed = PCI_SPEED_66MHz; 10046558b6abSKenji Kaneshige else if (slot_avail1 & SLOT_33MHZ) 10050afabe90SKenji Kaneshige bus_speed = PCI_SPEED_33MHz; 10060afabe90SKenji Kaneshige else 10070afabe90SKenji Kaneshige retval = -ENODEV; 10081da177e4SLinus Torvalds } 10091da177e4SLinus Torvalds 10101da177e4SLinus Torvalds *value = bus_speed; 10111da177e4SLinus Torvalds dbg("Max bus speed = %d\n", bus_speed); 10121da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 10131da177e4SLinus Torvalds return retval; 10141da177e4SLinus Torvalds } 10151da177e4SLinus Torvalds 10161da177e4SLinus Torvalds static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value) 10171da177e4SLinus Torvalds { 10180afabe90SKenji Kaneshige int retval = 0; 101975d97c59SKenji Kaneshige struct controller *ctrl = slot->ctrl; 10201da177e4SLinus Torvalds enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; 102175d97c59SKenji Kaneshige u16 sec_bus_reg = shpc_readw(ctrl, SEC_BUS_CONFIG); 102275d97c59SKenji Kaneshige u8 pi = shpc_readb(ctrl, PROG_INTERFACE); 10230afabe90SKenji Kaneshige u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7); 10241da177e4SLinus Torvalds 10251da177e4SLinus Torvalds DBG_ENTER_ROUTINE 10261da177e4SLinus Torvalds 10270afabe90SKenji Kaneshige if ((pi == 1) && (speed_mode > 4)) { 10280afabe90SKenji Kaneshige *value = PCI_SPEED_UNKNOWN; 10290afabe90SKenji Kaneshige return -ENODEV; 10301da177e4SLinus Torvalds } 10311da177e4SLinus Torvalds 10320afabe90SKenji Kaneshige switch (speed_mode) { 10330afabe90SKenji Kaneshige case 0x0: 10340afabe90SKenji Kaneshige *value = PCI_SPEED_33MHz; 10351da177e4SLinus Torvalds break; 10360afabe90SKenji Kaneshige case 0x1: 10370afabe90SKenji Kaneshige *value = PCI_SPEED_66MHz; 10381da177e4SLinus Torvalds break; 10390afabe90SKenji Kaneshige case 0x2: 10400afabe90SKenji Kaneshige *value = PCI_SPEED_66MHz_PCIX; 10411da177e4SLinus Torvalds break; 10420afabe90SKenji Kaneshige case 0x3: 10430afabe90SKenji Kaneshige *value = PCI_SPEED_100MHz_PCIX; 10441da177e4SLinus Torvalds break; 10450afabe90SKenji Kaneshige case 0x4: 10460afabe90SKenji Kaneshige *value = PCI_SPEED_133MHz_PCIX; 10471da177e4SLinus Torvalds break; 10480afabe90SKenji Kaneshige case 0x5: 10490afabe90SKenji Kaneshige *value = PCI_SPEED_66MHz_PCIX_ECC; 10501da177e4SLinus Torvalds break; 10510afabe90SKenji Kaneshige case 0x6: 10520afabe90SKenji Kaneshige *value = PCI_SPEED_100MHz_PCIX_ECC; 10531da177e4SLinus Torvalds break; 10540afabe90SKenji Kaneshige case 0x7: 10550afabe90SKenji Kaneshige *value = PCI_SPEED_133MHz_PCIX_ECC; 10561da177e4SLinus Torvalds break; 10570afabe90SKenji Kaneshige case 0x8: 10580afabe90SKenji Kaneshige *value = PCI_SPEED_66MHz_PCIX_266; 10591da177e4SLinus Torvalds break; 10600afabe90SKenji Kaneshige case 0x9: 10610afabe90SKenji Kaneshige *value = PCI_SPEED_100MHz_PCIX_266; 10621da177e4SLinus Torvalds break; 10631da177e4SLinus Torvalds case 0xa: 10640afabe90SKenji Kaneshige *value = PCI_SPEED_133MHz_PCIX_266; 10651da177e4SLinus Torvalds break; 10661da177e4SLinus Torvalds case 0xb: 10670afabe90SKenji Kaneshige *value = PCI_SPEED_66MHz_PCIX_533; 10681da177e4SLinus Torvalds break; 10691da177e4SLinus Torvalds case 0xc: 10700afabe90SKenji Kaneshige *value = PCI_SPEED_100MHz_PCIX_533; 10711da177e4SLinus Torvalds break; 10721da177e4SLinus Torvalds case 0xd: 10730afabe90SKenji Kaneshige *value = PCI_SPEED_133MHz_PCIX_533; 10741da177e4SLinus Torvalds break; 10751da177e4SLinus Torvalds default: 10760afabe90SKenji Kaneshige *value = PCI_SPEED_UNKNOWN; 10770afabe90SKenji Kaneshige retval = -ENODEV; 10781da177e4SLinus Torvalds break; 10791da177e4SLinus Torvalds } 10801da177e4SLinus Torvalds 10811da177e4SLinus Torvalds dbg("Current bus speed = %d\n", bus_speed); 10821da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 10831da177e4SLinus Torvalds return retval; 10841da177e4SLinus Torvalds } 10851da177e4SLinus Torvalds 10861da177e4SLinus Torvalds static struct hpc_ops shpchp_hpc_ops = { 10871da177e4SLinus Torvalds .power_on_slot = hpc_power_on_slot, 10881da177e4SLinus Torvalds .slot_enable = hpc_slot_enable, 10891da177e4SLinus Torvalds .slot_disable = hpc_slot_disable, 10901da177e4SLinus Torvalds .set_bus_speed_mode = hpc_set_bus_speed_mode, 10911da177e4SLinus Torvalds .set_attention_status = hpc_set_attention_status, 10921da177e4SLinus Torvalds .get_power_status = hpc_get_power_status, 10931da177e4SLinus Torvalds .get_attention_status = hpc_get_attention_status, 10941da177e4SLinus Torvalds .get_latch_status = hpc_get_latch_status, 10951da177e4SLinus Torvalds .get_adapter_status = hpc_get_adapter_status, 10961da177e4SLinus Torvalds 10971da177e4SLinus Torvalds .get_max_bus_speed = hpc_get_max_bus_speed, 10981da177e4SLinus Torvalds .get_cur_bus_speed = hpc_get_cur_bus_speed, 10991da177e4SLinus Torvalds .get_adapter_speed = hpc_get_adapter_speed, 11001da177e4SLinus Torvalds .get_mode1_ECC_cap = hpc_get_mode1_ECC_cap, 11011da177e4SLinus Torvalds .get_prog_int = hpc_get_prog_int, 11021da177e4SLinus Torvalds 11031da177e4SLinus Torvalds .query_power_fault = hpc_query_power_fault, 11041da177e4SLinus Torvalds .green_led_on = hpc_set_green_led_on, 11051da177e4SLinus Torvalds .green_led_off = hpc_set_green_led_off, 11061da177e4SLinus Torvalds .green_led_blink = hpc_set_green_led_blink, 11071da177e4SLinus Torvalds 11081da177e4SLinus Torvalds .release_ctlr = hpc_release_ctlr, 11091da177e4SLinus Torvalds }; 11101da177e4SLinus Torvalds 1111ee138334Srajesh.shah@intel.com int shpc_init(struct controller * ctrl, struct pci_dev * pdev) 11121da177e4SLinus Torvalds { 11131da177e4SLinus Torvalds struct php_ctlr_state_s *php_ctlr, *p; 11141da177e4SLinus Torvalds void *instance_id = ctrl; 11150455986cSKenji Kaneshige int rc, num_slots = 0; 11161da177e4SLinus Torvalds u8 hp_slot; 11171da177e4SLinus Torvalds static int first = 1; 11180455986cSKenji Kaneshige u32 shpc_base_offset; 111975d97c59SKenji Kaneshige u32 tempdword, slot_reg, slot_config; 11201da177e4SLinus Torvalds u8 i; 11211da177e4SLinus Torvalds 11221da177e4SLinus Torvalds DBG_ENTER_ROUTINE 11231da177e4SLinus Torvalds 11240455986cSKenji Kaneshige ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */ 11250455986cSKenji Kaneshige 11261da177e4SLinus Torvalds spin_lock_init(&list_lock); 112757c95c0dSKenji Kaneshige php_ctlr = kzalloc(sizeof(*php_ctlr), GFP_KERNEL); 11281da177e4SLinus Torvalds 11291da177e4SLinus Torvalds if (!php_ctlr) { /* allocate controller state data */ 11301da177e4SLinus Torvalds err("%s: HPC controller memory allocation error!\n", __FUNCTION__); 11311da177e4SLinus Torvalds goto abort; 11321da177e4SLinus Torvalds } 11331da177e4SLinus Torvalds 11341da177e4SLinus Torvalds php_ctlr->pci_dev = pdev; /* save pci_dev in context */ 11351da177e4SLinus Torvalds 1136ee138334Srajesh.shah@intel.com if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device == 1137ee138334Srajesh.shah@intel.com PCI_DEVICE_ID_AMD_GOLAM_7450)) { 11380455986cSKenji Kaneshige /* amd shpc driver doesn't use Base Offset; assume 0 */ 11390455986cSKenji Kaneshige ctrl->mmio_base = pci_resource_start(pdev, 0); 11400455986cSKenji Kaneshige ctrl->mmio_size = pci_resource_len(pdev, 0); 11411da177e4SLinus Torvalds } else { 11420455986cSKenji Kaneshige ctrl->cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC); 11430455986cSKenji Kaneshige if (!ctrl->cap_offset) { 11440455986cSKenji Kaneshige err("%s : cap_offset == 0\n", __FUNCTION__); 11451da177e4SLinus Torvalds goto abort_free_ctlr; 11461da177e4SLinus Torvalds } 11470455986cSKenji Kaneshige dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset); 11481da177e4SLinus Torvalds 114975d97c59SKenji Kaneshige rc = shpc_indirect_read(ctrl, 0, &shpc_base_offset); 11501da177e4SLinus Torvalds if (rc) { 11510455986cSKenji Kaneshige err("%s: cannot read base_offset\n", __FUNCTION__); 11521da177e4SLinus Torvalds goto abort_free_ctlr; 11531da177e4SLinus Torvalds } 11541da177e4SLinus Torvalds 115575d97c59SKenji Kaneshige rc = shpc_indirect_read(ctrl, 3, &tempdword); 11561da177e4SLinus Torvalds if (rc) { 11570455986cSKenji Kaneshige err("%s: cannot read slot config\n", __FUNCTION__); 11581da177e4SLinus Torvalds goto abort_free_ctlr; 11591da177e4SLinus Torvalds } 11600455986cSKenji Kaneshige num_slots = tempdword & SLOT_NUM; 11610455986cSKenji Kaneshige dbg("%s: num_slots (indirect) %x\n", __FUNCTION__, num_slots); 11621da177e4SLinus Torvalds 11630455986cSKenji Kaneshige for (i = 0; i < 9 + num_slots; i++) { 116475d97c59SKenji Kaneshige rc = shpc_indirect_read(ctrl, i, &tempdword); 11651da177e4SLinus Torvalds if (rc) { 11660455986cSKenji Kaneshige err("%s: cannot read creg (index = %d)\n", 11670455986cSKenji Kaneshige __FUNCTION__, i); 11681da177e4SLinus Torvalds goto abort_free_ctlr; 11691da177e4SLinus Torvalds } 11707c8942f9Srajesh.shah@intel.com dbg("%s: offset %d: value %x\n", __FUNCTION__,i, 11717c8942f9Srajesh.shah@intel.com tempdword); 11721da177e4SLinus Torvalds } 11730455986cSKenji Kaneshige 11740455986cSKenji Kaneshige ctrl->mmio_base = 11750455986cSKenji Kaneshige pci_resource_start(pdev, 0) + shpc_base_offset; 11760455986cSKenji Kaneshige ctrl->mmio_size = 0x24 + 0x4 * num_slots; 11771da177e4SLinus Torvalds } 11781da177e4SLinus Torvalds 11791da177e4SLinus Torvalds if (first) { 11801da177e4SLinus Torvalds spin_lock_init(&hpc_event_lock); 11811da177e4SLinus Torvalds first = 0; 11821da177e4SLinus Torvalds } 11831da177e4SLinus Torvalds 11841da177e4SLinus Torvalds info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, 11851da177e4SLinus Torvalds pdev->subsystem_device); 11861da177e4SLinus Torvalds 11871da177e4SLinus Torvalds if (pci_enable_device(pdev)) 11881da177e4SLinus Torvalds goto abort_free_ctlr; 11891da177e4SLinus Torvalds 11900455986cSKenji Kaneshige if (!request_mem_region(ctrl->mmio_base, ctrl->mmio_size, MY_NAME)) { 11911da177e4SLinus Torvalds err("%s: cannot reserve MMIO region\n", __FUNCTION__); 11921da177e4SLinus Torvalds goto abort_free_ctlr; 11931da177e4SLinus Torvalds } 11941da177e4SLinus Torvalds 11950455986cSKenji Kaneshige php_ctlr->creg = ioremap(ctrl->mmio_base, ctrl->mmio_size); 11961da177e4SLinus Torvalds if (!php_ctlr->creg) { 11970455986cSKenji Kaneshige err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__, 11980455986cSKenji Kaneshige ctrl->mmio_size, ctrl->mmio_base); 11990455986cSKenji Kaneshige release_mem_region(ctrl->mmio_base, ctrl->mmio_size); 12001da177e4SLinus Torvalds goto abort_free_ctlr; 12011da177e4SLinus Torvalds } 12021da177e4SLinus Torvalds dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg); 12031da177e4SLinus Torvalds 12046aa4cdd0SIngo Molnar mutex_init(&ctrl->crit_sect); 1205d29aaddaSKenji Kaneshige mutex_init(&ctrl->cmd_lock); 1206d29aaddaSKenji Kaneshige 12071da177e4SLinus Torvalds /* Setup wait queue */ 12081da177e4SLinus Torvalds init_waitqueue_head(&ctrl->queue); 12091da177e4SLinus Torvalds 12101da177e4SLinus Torvalds /* Find the IRQ */ 12111da177e4SLinus Torvalds php_ctlr->irq = pdev->irq; 1212ee138334Srajesh.shah@intel.com php_ctlr->attention_button_callback = shpchp_handle_attention_button, 1213ee138334Srajesh.shah@intel.com php_ctlr->switch_change_callback = shpchp_handle_switch_change; 1214ee138334Srajesh.shah@intel.com php_ctlr->presence_change_callback = shpchp_handle_presence_change; 1215ee138334Srajesh.shah@intel.com php_ctlr->power_fault_callback = shpchp_handle_power_fault; 12161da177e4SLinus Torvalds php_ctlr->callback_instance_id = instance_id; 12171da177e4SLinus Torvalds 121875d97c59SKenji Kaneshige ctrl->hpc_ctlr_handle = php_ctlr; 121975d97c59SKenji Kaneshige ctrl->hpc_ops = &shpchp_hpc_ops; 122075d97c59SKenji Kaneshige 12211da177e4SLinus Torvalds /* Return PCI Controller Info */ 122275d97c59SKenji Kaneshige slot_config = shpc_readl(ctrl, SLOT_CONFIG); 122375d97c59SKenji Kaneshige php_ctlr->slot_device_offset = (slot_config & FIRST_DEV_NUM) >> 8; 122475d97c59SKenji Kaneshige php_ctlr->num_slots = slot_config & SLOT_NUM; 12251da177e4SLinus Torvalds dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset); 12261da177e4SLinus Torvalds dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots); 12271da177e4SLinus Torvalds 12281da177e4SLinus Torvalds /* Mask Global Interrupt Mask & Command Complete Interrupt Mask */ 122975d97c59SKenji Kaneshige tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); 12301da177e4SLinus Torvalds dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); 1231e7138723SKenji Kaneshige tempdword |= (GLOBAL_INTR_MASK | GLOBAL_SERR_MASK | 1232e7138723SKenji Kaneshige COMMAND_INTR_MASK | ARBITER_SERR_MASK); 1233e7138723SKenji Kaneshige tempdword &= ~SERR_INTR_RSVDZ_MASK; 123475d97c59SKenji Kaneshige shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword); 123575d97c59SKenji Kaneshige tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); 12361da177e4SLinus Torvalds dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); 12371da177e4SLinus Torvalds 12381da177e4SLinus Torvalds /* Mask the MRL sensor SERR Mask of individual slot in 12391da177e4SLinus Torvalds * Slot SERR-INT Mask & clear all the existing event if any 12401da177e4SLinus Torvalds */ 12411da177e4SLinus Torvalds for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { 12422b34da7eSKenji Kaneshige slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); 12431da177e4SLinus Torvalds dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, 12441da177e4SLinus Torvalds hp_slot, slot_reg); 1245795eb5c4SKenji Kaneshige slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | 1246795eb5c4SKenji Kaneshige BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | 1247795eb5c4SKenji Kaneshige CON_PFAULT_INTR_MASK | MRL_CHANGE_SERR_MASK | 1248795eb5c4SKenji Kaneshige CON_PFAULT_SERR_MASK); 1249795eb5c4SKenji Kaneshige slot_reg &= ~SLOT_REG_RSVDZ_MASK; 1250795eb5c4SKenji Kaneshige shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); 12511da177e4SLinus Torvalds } 12521da177e4SLinus Torvalds 12531da177e4SLinus Torvalds if (shpchp_poll_mode) {/* Install interrupt polling code */ 12541da177e4SLinus Torvalds /* Install and start the interrupt polling timer */ 12551da177e4SLinus Torvalds init_timer(&php_ctlr->int_poll_timer); 12561da177e4SLinus Torvalds start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */ 12571da177e4SLinus Torvalds } else { 12581da177e4SLinus Torvalds /* Installs the interrupt handler */ 12591da177e4SLinus Torvalds rc = pci_enable_msi(pdev); 12601da177e4SLinus Torvalds if (rc) { 12611da177e4SLinus Torvalds info("Can't get msi for the hotplug controller\n"); 12621da177e4SLinus Torvalds info("Use INTx for the hotplug controller\n"); 12631da177e4SLinus Torvalds } else 12641da177e4SLinus Torvalds php_ctlr->irq = pdev->irq; 12651da177e4SLinus Torvalds 12661da177e4SLinus Torvalds rc = request_irq(php_ctlr->irq, shpc_isr, SA_SHIRQ, MY_NAME, (void *) ctrl); 12671da177e4SLinus Torvalds dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc); 12681da177e4SLinus Torvalds if (rc) { 12691da177e4SLinus Torvalds err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq); 12701da177e4SLinus Torvalds goto abort_free_ctlr; 12711da177e4SLinus Torvalds } 12721da177e4SLinus Torvalds } 12737c8942f9Srajesh.shah@intel.com dbg("%s: HPC at b:d:f:irq=0x%x:%x:%x:%x\n", __FUNCTION__, 12747c8942f9Srajesh.shah@intel.com pdev->bus->number, PCI_SLOT(pdev->devfn), 12757c8942f9Srajesh.shah@intel.com PCI_FUNC(pdev->devfn), pdev->irq); 1276424600f9Srajesh.shah@intel.com get_hp_hw_control_from_firmware(pdev); 12771da177e4SLinus Torvalds 12781da177e4SLinus Torvalds /* Add this HPC instance into the HPC list */ 12791da177e4SLinus Torvalds spin_lock(&list_lock); 12801da177e4SLinus Torvalds if (php_ctlr_list_head == 0) { 12811da177e4SLinus Torvalds php_ctlr_list_head = php_ctlr; 12821da177e4SLinus Torvalds p = php_ctlr_list_head; 12831da177e4SLinus Torvalds p->pnext = NULL; 12841da177e4SLinus Torvalds } else { 12851da177e4SLinus Torvalds p = php_ctlr_list_head; 12861da177e4SLinus Torvalds 12871da177e4SLinus Torvalds while (p->pnext) 12881da177e4SLinus Torvalds p = p->pnext; 12891da177e4SLinus Torvalds 12901da177e4SLinus Torvalds p->pnext = php_ctlr; 12911da177e4SLinus Torvalds } 12921da177e4SLinus Torvalds spin_unlock(&list_lock); 12931da177e4SLinus Torvalds 12941da177e4SLinus Torvalds ctlr_seq_num++; 12951da177e4SLinus Torvalds 1296795eb5c4SKenji Kaneshige /* 129782d5f4aaSKenji Kaneshige * If this is the first controller to be initialized, 129882d5f4aaSKenji Kaneshige * initialize the shpchpd work queue 129982d5f4aaSKenji Kaneshige */ 130082d5f4aaSKenji Kaneshige if (atomic_add_return(1, &shpchp_num_controllers) == 1) { 130182d5f4aaSKenji Kaneshige shpchp_wq = create_singlethread_workqueue("shpchpd"); 130282d5f4aaSKenji Kaneshige if (!shpchp_wq) 130382d5f4aaSKenji Kaneshige return -ENOMEM; 130482d5f4aaSKenji Kaneshige } 130582d5f4aaSKenji Kaneshige 130682d5f4aaSKenji Kaneshige /* 1307795eb5c4SKenji Kaneshige * Unmask all event interrupts of all slots 1308795eb5c4SKenji Kaneshige */ 13091da177e4SLinus Torvalds for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { 13102b34da7eSKenji Kaneshige slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); 13111da177e4SLinus Torvalds dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, 13121da177e4SLinus Torvalds hp_slot, slot_reg); 1313795eb5c4SKenji Kaneshige slot_reg &= ~(PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | 1314795eb5c4SKenji Kaneshige BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | 1315795eb5c4SKenji Kaneshige CON_PFAULT_INTR_MASK | SLOT_REG_RSVDZ_MASK); 1316795eb5c4SKenji Kaneshige shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); 13171da177e4SLinus Torvalds } 13181da177e4SLinus Torvalds if (!shpchp_poll_mode) { 13191da177e4SLinus Torvalds /* Unmask all general input interrupts and SERR */ 132075d97c59SKenji Kaneshige tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); 1321e7138723SKenji Kaneshige tempdword &= ~(GLOBAL_INTR_MASK | COMMAND_INTR_MASK | 1322e7138723SKenji Kaneshige SERR_INTR_RSVDZ_MASK); 132375d97c59SKenji Kaneshige shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword); 132475d97c59SKenji Kaneshige tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); 13251da177e4SLinus Torvalds dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); 13261da177e4SLinus Torvalds } 13271da177e4SLinus Torvalds 13281da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 13291da177e4SLinus Torvalds return 0; 13301da177e4SLinus Torvalds 13311da177e4SLinus Torvalds /* We end up here for the many possible ways to fail this API. */ 13321da177e4SLinus Torvalds abort_free_ctlr: 13331da177e4SLinus Torvalds kfree(php_ctlr); 13341da177e4SLinus Torvalds abort: 13351da177e4SLinus Torvalds DBG_LEAVE_ROUTINE 13361da177e4SLinus Torvalds return -1; 13371da177e4SLinus Torvalds } 1338