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

📄 pciehp_hpc.c

📁 audio driver for hotplug pci on linux 2.6.27
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * PCI Express 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/signal.h>#include <linux/jiffies.h>#include <linux/timer.h>#include <linux/pci.h>#include <linux/interrupt.h>#include <linux/time.h>#include "../pci.h"#include "pciehp.h"static atomic_t pciehp_num_controllers = ATOMIC_INIT(0);struct ctrl_reg {	u8 cap_id;	u8 nxt_ptr;	u16 cap_reg;	u32 dev_cap;	u16 dev_ctrl;	u16 dev_status;	u32 lnk_cap;	u16 lnk_ctrl;	u16 lnk_status;	u32 slot_cap;	u16 slot_ctrl;	u16 slot_status;	u16 root_ctrl;	u16 rsvp;	u32 root_status;} __attribute__ ((packed));/* offsets to the controller registers based on the above structure layout */enum ctrl_offsets {	PCIECAPID	=	offsetof(struct ctrl_reg, cap_id),	NXTCAPPTR	=	offsetof(struct ctrl_reg, nxt_ptr),	CAPREG		=	offsetof(struct ctrl_reg, cap_reg),	DEVCAP		=	offsetof(struct ctrl_reg, dev_cap),	DEVCTRL		=	offsetof(struct ctrl_reg, dev_ctrl),	DEVSTATUS	=	offsetof(struct ctrl_reg, dev_status),	LNKCAP		=	offsetof(struct ctrl_reg, lnk_cap),	LNKCTRL		=	offsetof(struct ctrl_reg, lnk_ctrl),	LNKSTATUS	=	offsetof(struct ctrl_reg, lnk_status),	SLOTCAP		=	offsetof(struct ctrl_reg, slot_cap),	SLOTCTRL	=	offsetof(struct ctrl_reg, slot_ctrl),	SLOTSTATUS	=	offsetof(struct ctrl_reg, slot_status),	ROOTCTRL	=	offsetof(struct ctrl_reg, root_ctrl),	ROOTSTATUS	=	offsetof(struct ctrl_reg, root_status),};static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value){	struct pci_dev *dev = ctrl->pci_dev;	return pci_read_config_word(dev, ctrl->cap_base + reg, value);}static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value){	struct pci_dev *dev = ctrl->pci_dev;	return pci_read_config_dword(dev, ctrl->cap_base + reg, value);}static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value){	struct pci_dev *dev = ctrl->pci_dev;	return pci_write_config_word(dev, ctrl->cap_base + reg, value);}static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value){	struct pci_dev *dev = ctrl->pci_dev;	return pci_write_config_dword(dev, ctrl->cap_base + reg, value);}/* Field definitions in PCI Express Capabilities Register */#define CAP_VER			0x000F#define DEV_PORT_TYPE		0x00F0#define SLOT_IMPL		0x0100#define MSG_NUM			0x3E00/* Device or Port Type */#define NAT_ENDPT		0x00#define LEG_ENDPT		0x01#define ROOT_PORT		0x04#define UP_STREAM		0x05#define	DN_STREAM		0x06#define PCIE_PCI_BRDG		0x07#define PCI_PCIE_BRDG		0x10/* Field definitions in Device Capabilities Register */#define DATTN_BUTTN_PRSN	0x1000#define DATTN_LED_PRSN		0x2000#define DPWR_LED_PRSN		0x4000/* Field definitions in Link Capabilities Register */#define MAX_LNK_SPEED		0x000F#define MAX_LNK_WIDTH		0x03F0/* Link Width Encoding */#define LNK_X1		0x01#define LNK_X2		0x02#define LNK_X4		0x04#define LNK_X8		0x08#define LNK_X12		0x0C#define LNK_X16		0x10#define LNK_X32		0x20/*Field definitions of Link Status Register */#define LNK_SPEED	0x000F#define NEG_LINK_WD	0x03F0#define LNK_TRN_ERR	0x0400#define	LNK_TRN		0x0800#define SLOT_CLK_CONF	0x1000/* Field definitions in Slot Capabilities Register */#define ATTN_BUTTN_PRSN	0x00000001#define	PWR_CTRL_PRSN	0x00000002#define MRL_SENS_PRSN	0x00000004#define ATTN_LED_PRSN	0x00000008#define PWR_LED_PRSN	0x00000010#define HP_SUPR_RM_SUP	0x00000020#define HP_CAP		0x00000040#define SLOT_PWR_VALUE	0x000003F8#define SLOT_PWR_LIMIT	0x00000C00#define PSN		0xFFF80000	/* PSN: Physical Slot Number *//* Field definitions in Slot Control Register */#define ATTN_BUTTN_ENABLE		0x0001#define PWR_FAULT_DETECT_ENABLE		0x0002#define MRL_DETECT_ENABLE		0x0004#define PRSN_DETECT_ENABLE		0x0008#define CMD_CMPL_INTR_ENABLE		0x0010#define HP_INTR_ENABLE			0x0020#define ATTN_LED_CTRL			0x00C0#define PWR_LED_CTRL			0x0300#define PWR_CTRL			0x0400#define EMI_CTRL			0x0800/* Attention indicator and Power indicator states */#define LED_ON		0x01#define LED_BLINK	0x10#define LED_OFF		0x11/* Power Control Command */#define POWER_ON	0#define POWER_OFF	0x0400/* EMI Status defines */#define EMI_DISENGAGED	0#define EMI_ENGAGED	1/* Field definitions in Slot Status Register */#define ATTN_BUTTN_PRESSED	0x0001#define PWR_FAULT_DETECTED	0x0002#define MRL_SENS_CHANGED	0x0004#define PRSN_DETECT_CHANGED	0x0008#define CMD_COMPLETED		0x0010#define MRL_STATE		0x0020#define PRSN_STATE		0x0040#define EMI_STATE		0x0080#define EMI_STATUS_BIT		7static irqreturn_t pcie_isr(int irq, void *dev_id);static void start_int_poll_timer(struct controller *ctrl, int sec);/* This is the interrupt polling timeout function. */static void int_poll_timeout(unsigned long data){	struct controller *ctrl = (struct controller *)data;	/* Poll for interrupt events.  regs == NULL => polling */	pcie_isr(0, ctrl);	init_timer(&ctrl->poll_timer);	if (!pciehp_poll_time)		pciehp_poll_time = 2; /* default polling interval is 2 sec */	start_int_poll_timer(ctrl, pciehp_poll_time);}/* This function starts the interrupt polling timer. */static void start_int_poll_timer(struct controller *ctrl, int sec){	/* Clamp to sane value */	if ((sec <= 0) || (sec > 60))        	sec = 2;	ctrl->poll_timer.function = &int_poll_timeout;	ctrl->poll_timer.data = (unsigned long)ctrl;	ctrl->poll_timer.expires = jiffies + sec * HZ;	add_timer(&ctrl->poll_timer);}static inline int pciehp_request_irq(struct controller *ctrl){	int retval, irq = ctrl->pci_dev->irq;	/* Install interrupt polling timer. Start with 10 sec delay */	if (pciehp_poll_mode) {		init_timer(&ctrl->poll_timer);		start_int_poll_timer(ctrl, 10);		return 0;	}	/* Installs the interrupt handler */	retval = request_irq(irq, pcie_isr, IRQF_SHARED, MY_NAME, ctrl);	if (retval)		err("Cannot get irq %d for the hotplug controller\n", irq);	return retval;}static inline void pciehp_free_irq(struct controller *ctrl){	if (pciehp_poll_mode)		del_timer_sync(&ctrl->poll_timer);	else		free_irq(ctrl->pci_dev->irq, ctrl);}static int pcie_poll_cmd(struct controller *ctrl){	u16 slot_status;	int timeout = 1000;	if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status)) {		if (slot_status & CMD_COMPLETED) {			pciehp_writew(ctrl, SLOTSTATUS, CMD_COMPLETED);			return 1;		}	}	while (timeout > 0) {		msleep(10);		timeout -= 10;		if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status)) {			if (slot_status & CMD_COMPLETED) {				pciehp_writew(ctrl, SLOTSTATUS, CMD_COMPLETED);				return 1;			}		}	}	return 0;	/* timeout */}static void pcie_wait_cmd(struct controller *ctrl, int poll){	unsigned int msecs = pciehp_poll_mode ? 2500 : 1000;	unsigned long timeout = msecs_to_jiffies(msecs);	int rc;	if (poll)		rc = pcie_poll_cmd(ctrl);	else		rc = wait_event_timeout(ctrl->queue, !ctrl->cmd_busy, timeout);	if (!rc)		dbg("Command not completed in 1000 msec\n");}/** * pcie_write_cmd - Issue controller command * @ctrl: controller to which the command is issued * @cmd:  command value written to slot control register * @mask: bitmask of slot control register to be modified */static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask){	int retval = 0;	u16 slot_status;	u16 slot_ctrl;	mutex_lock(&ctrl->ctrl_lock);	retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);	if (retval) {		err("%s: Cannot read SLOTSTATUS register\n", __func__);		goto out;	}	if (slot_status & CMD_COMPLETED) {		if (!ctrl->no_cmd_complete) {			/*			 * After 1 sec and CMD_COMPLETED still not set, just			 * proceed forward to issue the next command according			 * to spec. Just print out the error message.			 */			dbg("%s: CMD_COMPLETED not clear after 1 sec.\n",			    __func__);		} else if (!NO_CMD_CMPL(ctrl)) {			/*			 * This controller semms to notify of command completed			 * event even though it supports none of power			 * controller, attention led, power led and EMI.			 */			dbg("%s: Unexpected CMD_COMPLETED. Need to wait for "			    "command completed event.\n", __func__);			ctrl->no_cmd_complete = 0;		} else {			dbg("%s: Unexpected CMD_COMPLETED. Maybe the "			    "controller is broken.\n", __func__);		}	}	retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);	if (retval) {		err("%s: Cannot read SLOTCTRL register\n", __func__);		goto out;	}	slot_ctrl &= ~mask;	slot_ctrl |= (cmd & mask);	ctrl->cmd_busy = 1;	smp_mb();	retval = pciehp_writew(ctrl, SLOTCTRL, slot_ctrl);	if (retval)		err("%s: Cannot write to SLOTCTRL register\n", __func__);	/*	 * Wait for command completion.	 */	if (!retval && !ctrl->no_cmd_complete) {		int poll = 0;		/*		 * if hotplug interrupt is not enabled or command		 * completed interrupt is not enabled, we need to poll		 * command completed event.		 */		if (!(slot_ctrl & HP_INTR_ENABLE) ||		    !(slot_ctrl & CMD_CMPL_INTR_ENABLE))			poll = 1;                pcie_wait_cmd(ctrl, poll);	} out:	mutex_unlock(&ctrl->ctrl_lock);	return retval;}static int hpc_check_lnk_status(struct controller *ctrl){	u16 lnk_status;	int retval = 0;	retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);	if (retval) {		err("%s: Cannot read LNKSTATUS register\n", __func__);		return retval;	}	dbg("%s: lnk_status = %x\n", __func__, lnk_status);	if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) ||		!(lnk_status & NEG_LINK_WD)) {		err("%s : Link Training Error occurs \n", __func__);		retval = -1;		return retval;	}	return retval;}static int hpc_get_attention_status(struct slot *slot, u8 *status){	struct controller *ctrl = slot->ctrl;	u16 slot_ctrl;	u8 atten_led_state;	int retval = 0;	retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);	if (retval) {		err("%s: Cannot read SLOTCTRL register\n", __func__);		return retval;	}	dbg("%s: SLOTCTRL %x, value read %x\n",	    __func__, ctrl->cap_base + SLOTCTRL, slot_ctrl);	atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6;	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;	}	return 0;}static int hpc_get_power_status(struct slot *slot, u8 *status){	struct controller *ctrl = slot->ctrl;	u16 slot_ctrl;	u8 pwr_state;	int	retval = 0;	retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);	if (retval) {		err("%s: Cannot read SLOTCTRL register\n", __func__);		return retval;	}	dbg("%s: SLOTCTRL %x value read %x\n",	    __func__, ctrl->cap_base + SLOTCTRL, slot_ctrl);	pwr_state = (slot_ctrl & PWR_CTRL) >> 10;	switch (pwr_state) {	case 0:		*status = 1;		break;	case 1:		*status = 0;		break;	default:		*status = 0xFF;		break;	}	return retval;}static int hpc_get_latch_status(struct slot *slot, u8 *status){	struct controller *ctrl = slot->ctrl;	u16 slot_status;	int retval = 0;	retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);	if (retval) {		err("%s: Cannot read SLOTSTATUS register\n", __func__);		return retval;	}	*status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1;	return 0;}static int hpc_get_adapter_status(struct slot *slot, u8 *status){	struct controller *ctrl = slot->ctrl;	u16 slot_status;	u8 card_state;	int retval = 0;	retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);	if (retval) {		err("%s: Cannot read SLOTSTATUS register\n", __func__);		return retval;	}	card_state = (u8)((slot_status & PRSN_STATE) >> 6);	*status = (card_state == 1) ? 1 : 0;	return 0;}static int hpc_query_power_fault(struct slot *slot){	struct controller *ctrl = slot->ctrl;	u16 slot_status;	u8 pwr_fault;	int retval = 0;	retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);	if (retval) {		err("%s: Cannot check for power fault\n", __func__);		return retval;	}	pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);	return pwr_fault;}static int hpc_get_emi_status(struct slot *slot, u8 *status){	struct controller *ctrl = slot->ctrl;	u16 slot_status;	int retval = 0;	retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);	if (retval) {		err("%s : Cannot check EMI status\n", __func__);		return retval;	}	*status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT;	return retval;}static int hpc_toggle_emi(struct slot *slot){	u16 slot_cmd;	u16 cmd_mask;	int rc;	slot_cmd = EMI_CTRL;	cmd_mask = EMI_CTRL;	rc = pcie_write_cmd(slot->ctrl, slot_cmd, cmd_mask);	slot->last_emi_toggle = get_seconds();	return rc;}static int hpc_set_attention_status(struct slot *slot, u8 value){	struct controller *ctrl = slot->ctrl;	u16 slot_cmd;	u16 cmd_mask;	int rc;	cmd_mask = ATTN_LED_CTRL;	switch (value) {		case 0 :	/* turn off */			slot_cmd = 0x00C0;			break;		case 1:		/* turn on */			slot_cmd = 0x0040;			break;		case 2:		/* turn blink */			slot_cmd = 0x0080;			break;		default:			return -1;	}	rc = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);	dbg("%s: SLOTCTRL %x write cmd %x\n",	    __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);	return rc;}static void hpc_set_green_led_on(struct slot *slot){	struct controller *ctrl = slot->ctrl;	u16 slot_cmd;	u16 cmd_mask;	slot_cmd = 0x0100;	cmd_mask = PWR_LED_CTRL;	pcie_write_cmd(ctrl, slot_cmd, cmd_mask);	dbg("%s: SLOTCTRL %x write cmd %x\n",	    __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);}static void hpc_set_green_led_off(struct slot *slot){	struct controller *ctrl = slot->ctrl;	u16 slot_cmd;	u16 cmd_mask;	slot_cmd = 0x0300;	cmd_mask = PWR_LED_CTRL;	pcie_write_cmd(ctrl, slot_cmd, cmd_mask);	dbg("%s: SLOTCTRL %x write cmd %x\n",	    __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);}static void hpc_set_green_led_blink(struct slot *slot){	struct controller *ctrl = slot->ctrl;	u16 slot_cmd;

⌨️ 快捷键说明

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