⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shpchp_hpc.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Standard PCI Hot Plug Driver * * Copyright (C) 1995,2001 Compaq Computer Corporation * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2001 IBM Corp. * Copyright (C) 2003-2004 Intel Corporation * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or * NON INFRINGEMENT.  See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Send feedback to <greg@kroah.com>,<kristen.c.accardi@intel.com> * */#include <linux/kernel.h>#include <linux/module.h>#include <linux/types.h>#include <linux/pci.h>#include <linux/interrupt.h>#include "shpchp.h"#ifdef DEBUG#define DBG_K_TRACE_ENTRY      ((unsigned int)0x00000001)	/* On function entry */#define DBG_K_TRACE_EXIT       ((unsigned int)0x00000002)	/* On function exit */#define DBG_K_INFO             ((unsigned int)0x00000004)	/* Info messages */#define DBG_K_ERROR            ((unsigned int)0x00000008)	/* Error messages */#define DBG_K_TRACE            (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)#define DBG_K_STANDARD         (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)/* Redefine this flagword to set debug level */#define DEBUG_LEVEL            DBG_K_STANDARD#define DEFINE_DBG_BUFFER     char __dbg_str_buf[256];#define DBG_PRINT( dbg_flags, args... )              \	do {                                             \	  if ( DEBUG_LEVEL & ( dbg_flags ) )             \	  {                                              \	    int len;                                     \	    len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \		  __FILE__, __LINE__, __FUNCTION__ );    \	    sprintf( __dbg_str_buf + len, args );        \	    printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \	  }                                              \	} while (0)#define DBG_ENTER_ROUTINE	DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");#define DBG_LEAVE_ROUTINE	DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");#else#define DEFINE_DBG_BUFFER#define DBG_ENTER_ROUTINE#define DBG_LEAVE_ROUTINE#endif				/* DEBUG *//* Slot Available Register I field definition */#define SLOT_33MHZ		0x0000001f#define SLOT_66MHZ_PCIX		0x00001f00#define SLOT_100MHZ_PCIX	0x001f0000#define SLOT_133MHZ_PCIX	0x1f000000/* Slot Available Register II field definition */#define SLOT_66MHZ		0x0000001f#define SLOT_66MHZ_PCIX_266	0x00000f00#define SLOT_100MHZ_PCIX_266	0x0000f000#define SLOT_133MHZ_PCIX_266	0x000f0000#define SLOT_66MHZ_PCIX_533	0x00f00000#define SLOT_100MHZ_PCIX_533	0x0f000000#define SLOT_133MHZ_PCIX_533	0xf0000000/* Slot Configuration */#define SLOT_NUM		0x0000001F#define	FIRST_DEV_NUM		0x00001F00#define PSN			0x07FF0000#define	UPDOWN			0x20000000#define	MRLSENSOR		0x40000000#define ATTN_BUTTON		0x80000000/* Slot Status Field Definitions *//* Slot State */#define PWR_ONLY		0x0001#define ENABLED			0x0002#define DISABLED		0x0003/* Power Indicator State */#define PWR_LED_ON		0x0004#define PWR_LED_BLINK		0x0008#define PWR_LED_OFF		0x000c/* Attention Indicator State */#define ATTEN_LED_ON		0x0010#define	ATTEN_LED_BLINK		0x0020#define ATTEN_LED_OFF		0x0030/* Power Fault */#define pwr_fault		0x0040/* Attention Button */#define ATTEN_BUTTON		0x0080/* MRL Sensor */#define MRL_SENSOR		0x0100/* 66 MHz Capable */#define IS_66MHZ_CAP		0x0200/* PRSNT1#/PRSNT2# */#define SLOT_EMP		0x0c00/* PCI-X Capability */#define NON_PCIX		0x0000#define PCIX_66			0x1000#define PCIX_133		0x3000#define PCIX_266		0x4000  /* For PI = 2 only */#define PCIX_533		0x5000	/* For PI = 2 only *//* SHPC 'write' operations/commands *//* Slot operation - 0x00h to 0x3Fh */#define NO_CHANGE		0x00/* Slot state - Bits 0 & 1 of controller command register */#define SET_SLOT_PWR		0x01	#define SET_SLOT_ENABLE		0x02	#define SET_SLOT_DISABLE	0x03	/* Power indicator state - Bits 2 & 3 of controller command register*/#define SET_PWR_ON		0x04	#define SET_PWR_BLINK		0x08	#define SET_PWR_OFF		0x0C	/* Attention indicator state - Bits 4 & 5 of controller command register*/#define SET_ATTN_ON		0x010	#define SET_ATTN_BLINK		0x020#define SET_ATTN_OFF		0x030	/* Set bus speed/mode A - 0x40h to 0x47h */#define SETA_PCI_33MHZ		0x40#define SETA_PCI_66MHZ		0x41#define SETA_PCIX_66MHZ		0x42#define SETA_PCIX_100MHZ	0x43#define SETA_PCIX_133MHZ	0x44#define RESERV_1		0x45#define RESERV_2		0x46#define RESERV_3		0x47/* Set bus speed/mode B - 0x50h to 0x5fh */#define	SETB_PCI_33MHZ		0x50#define SETB_PCI_66MHZ		0x51#define SETB_PCIX_66MHZ_PM	0x52#define SETB_PCIX_100MHZ_PM	0x53#define SETB_PCIX_133MHZ_PM	0x54#define SETB_PCIX_66MHZ_EM	0x55#define SETB_PCIX_100MHZ_EM	0x56#define SETB_PCIX_133MHZ_EM	0x57#define SETB_PCIX_66MHZ_266	0x58#define SETB_PCIX_100MHZ_266	0x59#define SETB_PCIX_133MHZ_266	0x5a#define SETB_PCIX_66MHZ_533	0x5b#define SETB_PCIX_100MHZ_533	0x5c#define SETB_PCIX_133MHZ_533	0x5d/* Power-on all slots - 0x48h */#define SET_PWR_ON_ALL		0x48/* Enable all slots	- 0x49h */#define SET_ENABLE_ALL		0x49/*  SHPC controller command error code */#define SWITCH_OPEN		0x1#define INVALID_CMD		0x2#define INVALID_SPEED_MODE	0x4/* For accessing SHPC Working Register Set */#define DWORD_SELECT		0x2#define DWORD_DATA		0x4#define BASE_OFFSET		0x0/* Field Offset in Logical Slot Register - byte boundary */#define SLOT_EVENT_LATCH	0x2#define SLOT_SERR_INT_MASK	0x3static spinlock_t hpc_event_lock;DEFINE_DBG_BUFFER		/* Debug string buffer for entire HPC defined here */static struct php_ctlr_state_s *php_ctlr_list_head;	/* HPC state linked list */static int ctlr_seq_num = 0;	/* Controller sequenc # */static spinlock_t list_lock;static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs);static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);static int hpc_check_cmd_status(struct controller *ctrl);/* This is the interrupt polling timeout function. */static void int_poll_timeout(unsigned long lphp_ctlr){    struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr;    DBG_ENTER_ROUTINE    if ( !php_ctlr ) {		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);		return;    }    /* Poll for interrupt events.  regs == NULL => polling */    shpc_isr( 0, (void *)php_ctlr, NULL );    init_timer(&php_ctlr->int_poll_timer);	if (!shpchp_poll_time)		shpchp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/    start_int_poll_timer(php_ctlr, shpchp_poll_time);  		return;}/* This function starts the interrupt polling timer. */static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds){    if (!php_ctlr) {		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);		return;	}    if ( ( seconds <= 0 ) || ( seconds > 60 ) )        seconds = 2;            /* Clamp to sane value */    php_ctlr->int_poll_timer.function = &int_poll_timeout;    php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr;    /* Instance data */    php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ;    add_timer(&php_ctlr->int_poll_timer);	return;}static inline int shpc_wait_cmd(struct controller *ctrl){	int retval = 0;	unsigned int timeout_msec = shpchp_poll_mode ? 2000 : 1000;	unsigned long timeout = msecs_to_jiffies(timeout_msec);	int rc = wait_event_interruptible_timeout(ctrl->queue,						  !ctrl->cmd_busy, timeout);	if (!rc) {		retval = -EIO;		err("Command not completed in %d msec\n", timeout_msec);	} else if (rc < 0) {		retval = -EINTR;		info("Command was interrupted by a signal\n");	}	ctrl->cmd_busy = 0;	return retval;}static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd){	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;	u16 cmd_status;	int retval = 0;	u16 temp_word;	int i;	DBG_ENTER_ROUTINE 	mutex_lock(&slot->ctrl->cmd_lock);	if (!php_ctlr) {		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);		retval = -EINVAL;		goto out;	}	for (i = 0; i < 10; i++) {		cmd_status = readw(php_ctlr->creg + CMD_STATUS);				if (!(cmd_status & 0x1))			break;		/*  Check every 0.1 sec for a total of 1 sec*/		msleep(100);	}	cmd_status = readw(php_ctlr->creg + CMD_STATUS);		if (cmd_status & 0x1) { 		/* After 1 sec and and the controller is still busy */		err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__);		retval = -EBUSY;		goto out;	}	++t_slot;	temp_word =  (t_slot << 8) | (cmd & 0xFF);	dbg("%s: t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd);		/* To make sure the Controller Busy bit is 0 before we send out the	 * command. 	 */	slot->ctrl->cmd_busy = 1;	writew(temp_word, php_ctlr->creg + CMD);	/*	 * Wait for command completion.	 */	retval = shpc_wait_cmd(slot->ctrl);	if (retval)		goto out;	cmd_status = hpc_check_cmd_status(slot->ctrl);	if (cmd_status) {		err("%s: Failed to issued command 0x%x (error code = %d)\n",		    __FUNCTION__, cmd, cmd_status);		retval = -EIO;	} out:	mutex_unlock(&slot->ctrl->cmd_lock);	DBG_LEAVE_ROUTINE 	return retval;}static int hpc_check_cmd_status(struct controller *ctrl){	struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;	u16 cmd_status;	int retval = 0;	DBG_ENTER_ROUTINE 		if (!ctrl->hpc_ctlr_handle) {		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);		return -1;	}	cmd_status = readw(php_ctlr->creg + CMD_STATUS) & 0x000F;		switch (cmd_status >> 1) {	case 0:		retval = 0;		break;	case 1:		retval = SWITCH_OPEN;		err("%s: Switch opened!\n", __FUNCTION__);		break;	case 2:		retval = INVALID_CMD;		err("%s: Invalid HPC command!\n", __FUNCTION__);		break;	case 4:		retval = INVALID_SPEED_MODE;		err("%s: Invalid bus speed/mode!\n", __FUNCTION__);		break;	default:		retval = cmd_status;	}	DBG_LEAVE_ROUTINE 	return retval;}static int hpc_get_attention_status(struct slot *slot, u8 *status){	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;	u32 slot_reg;	u16 slot_status;	u8 atten_led_state;		DBG_ENTER_ROUTINE 	if (!slot->ctrl->hpc_ctlr_handle) {		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);		return -1;	}	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));	slot_status = (u16) slot_reg;	atten_led_state = (slot_status & 0x0030) >> 4;	switch (atten_led_state) {	case 0:		*status = 0xFF;	/* Reserved */		break;	case 1:		*status = 1;	/* On */		break;	case 2:		*status = 2;	/* Blink */		break;	case 3:		*status = 0;	/* Off */		break;	default:		*status = 0xFF;		break;	}	DBG_LEAVE_ROUTINE 	return 0;}static int hpc_get_power_status(struct slot * slot, u8 *status){	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;	u32 slot_reg;	u16 slot_status;	u8 slot_state;	int	retval = 0;		DBG_ENTER_ROUTINE 	if (!slot->ctrl->hpc_ctlr_handle) {		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);		return -1;	}	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));	slot_status = (u16) slot_reg;	slot_state = (slot_status & 0x0003);	switch (slot_state) {	case 0:		*status = 0xFF;		break;	case 1:		*status = 2;	/* Powered only */		break;	case 2:		*status = 1;	/* Enabled */		break;	case 3:		*status = 0;	/* Disabled */		break;	default:		*status = 0xFF;		break;	}	DBG_LEAVE_ROUTINE 	return retval;}static int hpc_get_latch_status(struct slot *slot, u8 *status){	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;	u32 slot_reg;	u16 slot_status;	DBG_ENTER_ROUTINE 	if (!slot->ctrl->hpc_ctlr_handle) {		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);		return -1;	}	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));	slot_status = (u16)slot_reg;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -