ia64/linux-2.6.18-xen.hg

changeset 733:30524c484bbb

PCI-Express AER implemetation: AER core and aerdriver

Signed-off-by: Zhang Yanmin <yanmin.zhang@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Nov 24 11:02:14 2008 +0000 (2008-11-24)
parents 5f10331cb88b
children df84c4c22a0a
files drivers/pci/pcie/Kconfig drivers/pci/pcie/Makefile drivers/pci/pcie/aer/Kconfig drivers/pci/pcie/aer/Makefile drivers/pci/pcie/aer/aerdrv.c drivers/pci/pcie/aer/aerdrv.h drivers/pci/pcie/aer/aerdrv_acpi.c drivers/pci/pcie/aer/aerdrv_core.c drivers/pci/pcie/aer/aerdrv_errprint.c include/linux/aer.h include/linux/pcieport_if.h
line diff
     1.1 --- a/drivers/pci/pcie/Kconfig	Mon Nov 24 11:01:21 2008 +0000
     1.2 +++ b/drivers/pci/pcie/Kconfig	Mon Nov 24 11:02:14 2008 +0000
     1.3 @@ -34,3 +34,4 @@ config HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
     1.4  	   
     1.5  	  When in doubt, say N.
     1.6  
     1.7 +source "drivers/pci/pcie/aer/Kconfig"
     2.1 --- a/drivers/pci/pcie/Makefile	Mon Nov 24 11:01:21 2008 +0000
     2.2 +++ b/drivers/pci/pcie/Makefile	Mon Nov 24 11:02:14 2008 +0000
     2.3 @@ -5,3 +5,6 @@
     2.4  pcieportdrv-y			:= portdrv_core.o portdrv_pci.o portdrv_bus.o
     2.5  
     2.6  obj-$(CONFIG_PCIEPORTBUS)	+= pcieportdrv.o
     2.7 +
     2.8 +# Build PCI Express AER if needed
     2.9 +obj-$(CONFIG_PCIEAER)		+= aer/
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/drivers/pci/pcie/aer/Kconfig	Mon Nov 24 11:02:14 2008 +0000
     3.3 @@ -0,0 +1,12 @@
     3.4 +#
     3.5 +# PCI Express Root Port Device AER Configuration
     3.6 +#
     3.7 +
     3.8 +config PCIEAER
     3.9 +	boolean "Root Port Advanced Error Reporting support"
    3.10 +	depends on PCIEPORTBUS && ACPI
    3.11 +	default y
    3.12 +	help
    3.13 +	  This enables PCI Express Root Port Advanced Error Reporting
    3.14 +	  (AER) driver support. Error reporting messages sent to Root
    3.15 +	  Port will be handled by PCI Express AER driver.
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/drivers/pci/pcie/aer/Makefile	Mon Nov 24 11:02:14 2008 +0000
     4.3 @@ -0,0 +1,8 @@
     4.4 +#
     4.5 +# Makefile for PCI-Express Root Port Advanced Error Reporting Driver
     4.6 +#
     4.7 +
     4.8 +obj-$(CONFIG_PCIEAER) += aerdriver.o
     4.9 +
    4.10 +aerdriver-objs := aerdrv_errprint.o aerdrv_core.o aerdrv.o aerdrv_acpi.o
    4.11 +
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/drivers/pci/pcie/aer/aerdrv.c	Mon Nov 24 11:02:14 2008 +0000
     5.3 @@ -0,0 +1,346 @@
     5.4 +/*
     5.5 + * drivers/pci/pcie/aer/aerdrv.c
     5.6 + *
     5.7 + * This file is subject to the terms and conditions of the GNU General Public
     5.8 + * License.  See the file "COPYING" in the main directory of this archive
     5.9 + * for more details.
    5.10 + *
    5.11 + * This file implements the AER root port service driver. The driver will
    5.12 + * register an irq handler. When root port triggers an AER interrupt, the irq
    5.13 + * handler will collect root port status and schedule a work.
    5.14 + *
    5.15 + * Copyright (C) 2006 Intel Corp.
    5.16 + *	Tom Long Nguyen (tom.l.nguyen@intel.com)
    5.17 + *	Zhang Yanmin (yanmin.zhang@intel.com)
    5.18 + *
    5.19 + */
    5.20 +
    5.21 +#include <linux/module.h>
    5.22 +#include <linux/pci.h>
    5.23 +#include <linux/kernel.h>
    5.24 +#include <linux/errno.h>
    5.25 +#include <linux/pm.h>
    5.26 +#include <linux/init.h>
    5.27 +#include <linux/interrupt.h>
    5.28 +#include <linux/delay.h>
    5.29 +#include <linux/pcieport_if.h>
    5.30 +
    5.31 +#include "aerdrv.h"
    5.32 +
    5.33 +/*
    5.34 + * Version Information
    5.35 + */
    5.36 +#define DRIVER_VERSION "v1.0"
    5.37 +#define DRIVER_AUTHOR "tom.l.nguyen@intel.com"
    5.38 +#define DRIVER_DESC "Root Port Advanced Error Reporting Driver"
    5.39 +MODULE_AUTHOR(DRIVER_AUTHOR);
    5.40 +MODULE_DESCRIPTION(DRIVER_DESC);
    5.41 +MODULE_LICENSE("GPL");
    5.42 +
    5.43 +static int __devinit aer_probe (struct pcie_device *dev,
    5.44 +	const struct pcie_port_service_id *id );
    5.45 +static void aer_remove(struct pcie_device *dev);
    5.46 +static int aer_suspend(struct pcie_device *dev, pm_message_t state)
    5.47 +{return 0;}
    5.48 +static int aer_resume(struct pcie_device *dev) {return 0;}
    5.49 +static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
    5.50 +	enum pci_channel_state error);
    5.51 +static void aer_error_resume(struct pci_dev *dev);
    5.52 +static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
    5.53 +
    5.54 +/*
    5.55 + * PCI Express bus's AER Root service driver data structure
    5.56 + */
    5.57 +static struct pcie_port_service_id aer_id[] = {
    5.58 +	{
    5.59 +	.vendor 	= PCI_ANY_ID,
    5.60 +	.device 	= PCI_ANY_ID,
    5.61 +	.port_type 	= PCIE_RC_PORT,
    5.62 +	.service_type 	= PCIE_PORT_SERVICE_AER,
    5.63 +	},
    5.64 +	{ /* end: all zeroes */ }
    5.65 +};
    5.66 +
    5.67 +static struct pci_error_handlers aer_error_handlers = {
    5.68 +	.error_detected = aer_error_detected,
    5.69 +	.resume = aer_error_resume,
    5.70 +};
    5.71 +
    5.72 +static struct pcie_port_service_driver aerdrv = {
    5.73 +	.name		= "aer",
    5.74 +	.id_table	= &aer_id[0],
    5.75 +
    5.76 +	.probe		= aer_probe,
    5.77 +	.remove		= aer_remove,
    5.78 +
    5.79 +	.suspend	= aer_suspend,
    5.80 +	.resume		= aer_resume,
    5.81 +
    5.82 +	.err_handler	= &aer_error_handlers,
    5.83 +
    5.84 +	.reset_link	= aer_root_reset,
    5.85 +};
    5.86 +
    5.87 +/**
    5.88 + * aer_irq - Root Port's ISR
    5.89 + * @irq: IRQ assigned to Root Port
    5.90 + * @context: pointer to Root Port data structure
    5.91 + * @r: pointer struct pt_regs
    5.92 + *
    5.93 + * Invoked when Root Port detects AER messages.
    5.94 + **/
    5.95 +static irqreturn_t aer_irq(int irq, void *context, struct pt_regs * r)
    5.96 +{
    5.97 +	unsigned int status, id;
    5.98 +	struct pcie_device *pdev = (struct pcie_device *)context;
    5.99 +	struct aer_rpc *rpc = get_service_data(pdev);
   5.100 +	int next_prod_idx;
   5.101 +	unsigned long flags;
   5.102 +	int pos;
   5.103 +
   5.104 +	pos = pci_find_aer_capability(pdev->port);
   5.105 +	/*
   5.106 +	 * Must lock access to Root Error Status Reg, Root Error ID Reg,
   5.107 +	 * and Root error producer/consumer index
   5.108 +	 */
   5.109 +	spin_lock_irqsave(&rpc->e_lock, flags);
   5.110 +
   5.111 +	/* Read error status */
   5.112 +	pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status);
   5.113 +	if (!(status & ROOT_ERR_STATUS_MASKS)) {
   5.114 +		spin_unlock_irqrestore(&rpc->e_lock, flags);
   5.115 +		return IRQ_NONE;
   5.116 +	}
   5.117 +
   5.118 +	/* Read error source and clear error status */
   5.119 +	pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_COR_SRC, &id);
   5.120 +	pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status);
   5.121 +
   5.122 +	/* Store error source for later DPC handler */
   5.123 +	next_prod_idx = rpc->prod_idx + 1;
   5.124 +	if (next_prod_idx == AER_ERROR_SOURCES_MAX)
   5.125 +		next_prod_idx = 0;
   5.126 +	if (next_prod_idx == rpc->cons_idx) {
   5.127 +		/*
   5.128 +		 * Error Storm Condition - possibly the same error occurred.
   5.129 +		 * Drop the error.
   5.130 +		 */
   5.131 +		spin_unlock_irqrestore(&rpc->e_lock, flags);
   5.132 +		return IRQ_HANDLED;
   5.133 +	}
   5.134 +	rpc->e_sources[rpc->prod_idx].status =  status;
   5.135 +	rpc->e_sources[rpc->prod_idx].id = id;
   5.136 +	rpc->prod_idx = next_prod_idx;
   5.137 +	spin_unlock_irqrestore(&rpc->e_lock, flags);
   5.138 +
   5.139 +	/*  Invoke DPC handler */
   5.140 +	schedule_work(&rpc->dpc_handler);
   5.141 +
   5.142 +	return IRQ_HANDLED;
   5.143 +}
   5.144 +
   5.145 +/**
   5.146 + * aer_alloc_rpc - allocate Root Port data structure
   5.147 + * @dev: pointer to the pcie_dev data structure
   5.148 + *
   5.149 + * Invoked when Root Port's AER service is loaded.
   5.150 + **/
   5.151 +static struct aer_rpc* aer_alloc_rpc(struct pcie_device *dev)
   5.152 +{
   5.153 +	struct aer_rpc *rpc;
   5.154 +
   5.155 +	if (!(rpc = (struct aer_rpc *)kmalloc(sizeof(struct aer_rpc),
   5.156 +		GFP_KERNEL)))
   5.157 +		return NULL;
   5.158 +
   5.159 +	memset(rpc, 0, sizeof(struct aer_rpc));
   5.160 +	/*
   5.161 +	 * Initialize Root lock access, e_lock, to Root Error Status Reg,
   5.162 +	 * Root Error ID Reg, and Root error producer/consumer index.
   5.163 +	 */
   5.164 +	rpc->e_lock = SPIN_LOCK_UNLOCKED;
   5.165 +
   5.166 +	rpc->rpd = dev;
   5.167 +	INIT_WORK(&rpc->dpc_handler, aer_isr, (void *)dev);
   5.168 +	rpc->prod_idx = rpc->cons_idx = 0;
   5.169 +	mutex_init(&rpc->rpc_mutex);
   5.170 +	init_waitqueue_head(&rpc->wait_release);
   5.171 +
   5.172 +	/* Use PCIE bus function to store rpc into PCIE device */
   5.173 +	set_service_data(dev, rpc);
   5.174 +
   5.175 +	return rpc;
   5.176 +}
   5.177 +
   5.178 +/**
   5.179 + * aer_remove - clean up resources
   5.180 + * @dev: pointer to the pcie_dev data structure
   5.181 + *
   5.182 + * Invoked when PCI Express bus unloads or AER probe fails.
   5.183 + **/
   5.184 +static void aer_remove(struct pcie_device *dev)
   5.185 +{
   5.186 +	struct aer_rpc *rpc = get_service_data(dev);
   5.187 +
   5.188 +	if (rpc) {
   5.189 +		/* If register interrupt service, it must be free. */
   5.190 +		if (rpc->isr)
   5.191 +			free_irq(dev->irq, dev);
   5.192 +
   5.193 +		wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx);
   5.194 +
   5.195 +		aer_delete_rootport(rpc);
   5.196 +		set_service_data(dev, NULL);
   5.197 +	}
   5.198 +}
   5.199 +
   5.200 +/**
   5.201 + * aer_probe - initialize resources
   5.202 + * @dev: pointer to the pcie_dev data structure
   5.203 + * @id: pointer to the service id data structure
   5.204 + *
   5.205 + * Invoked when PCI Express bus loads AER service driver.
   5.206 + **/
   5.207 +static int __devinit aer_probe (struct pcie_device *dev,
   5.208 +				const struct pcie_port_service_id *id )
   5.209 +{
   5.210 +	int status;
   5.211 +	struct aer_rpc *rpc;
   5.212 +	struct device *device = &dev->device;
   5.213 +
   5.214 +	/* Init */
   5.215 +	if ((status = aer_init(dev)))
   5.216 +		return status;
   5.217 +
   5.218 +	/* Alloc rpc data structure */
   5.219 +	if (!(rpc = aer_alloc_rpc(dev))) {
   5.220 +		printk(KERN_DEBUG "%s: Alloc rpc fails on PCIE device[%s]\n",
   5.221 +			__FUNCTION__, device->bus_id);
   5.222 +		aer_remove(dev);
   5.223 +		return -ENOMEM;
   5.224 +	}
   5.225 +
   5.226 +	/* Request IRQ ISR */
   5.227 +	if ((status = request_irq(dev->irq, aer_irq, SA_SHIRQ, "aerdrv",
   5.228 +				dev))) {
   5.229 +		printk(KERN_DEBUG "%s: Request ISR fails on PCIE device[%s]\n",
   5.230 +			__FUNCTION__, device->bus_id);
   5.231 +		aer_remove(dev);
   5.232 +		return status;
   5.233 +	}
   5.234 +
   5.235 +	rpc->isr = 1;
   5.236 +
   5.237 +	aer_enable_rootport(rpc);
   5.238 +
   5.239 +	return status;
   5.240 +}
   5.241 +
   5.242 +/**
   5.243 + * aer_root_reset - reset link on Root Port
   5.244 + * @dev: pointer to Root Port's pci_dev data structure
   5.245 + *
   5.246 + * Invoked by Port Bus driver when performing link reset at Root Port.
   5.247 + **/
   5.248 +static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
   5.249 +{
   5.250 +	u16 p2p_ctrl;
   5.251 +	u32 status;
   5.252 +	int pos;
   5.253 +
   5.254 +	pos = pci_find_aer_capability(dev);
   5.255 +
   5.256 +	/* Disable Root's interrupt in response to error messages */
   5.257 +	pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, 0);
   5.258 +
   5.259 +	/* Assert Secondary Bus Reset */
   5.260 +	pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl);
   5.261 +	p2p_ctrl |= PCI_CB_BRIDGE_CTL_CB_RESET;
   5.262 +	pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
   5.263 +
   5.264 +	/* De-assert Secondary Bus Reset */
   5.265 +	p2p_ctrl &= ~PCI_CB_BRIDGE_CTL_CB_RESET;
   5.266 +	pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
   5.267 +
   5.268 +	/*
   5.269 +	 * System software must wait for at least 100ms from the end
   5.270 +	 * of a reset of one or more device before it is permitted
   5.271 +	 * to issue Configuration Requests to those devices.
   5.272 +	 */
   5.273 +	msleep(200);
   5.274 +	printk(KERN_DEBUG "Complete link reset at Root[%s]\n", dev->dev.bus_id);
   5.275 +
   5.276 +	/* Enable Root Port's interrupt in response to error messages */
   5.277 +	pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &status);
   5.278 +	pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, status);
   5.279 +	pci_write_config_dword(dev,
   5.280 +		pos + PCI_ERR_ROOT_COMMAND,
   5.281 +		ROOT_PORT_INTR_ON_MESG_MASK);
   5.282 +
   5.283 +	return PCI_ERS_RESULT_RECOVERED;
   5.284 +}
   5.285 +
   5.286 +/**
   5.287 + * aer_error_detected - update severity status
   5.288 + * @dev: pointer to Root Port's pci_dev data structure
   5.289 + * @error: error severity being notified by port bus
   5.290 + *
   5.291 + * Invoked by Port Bus driver during error recovery.
   5.292 + **/
   5.293 +static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
   5.294 +			enum pci_channel_state error)
   5.295 +{
   5.296 +	/* Root Port has no impact. Always recovers. */
   5.297 +	return PCI_ERS_RESULT_CAN_RECOVER;
   5.298 +}
   5.299 +
   5.300 +/**
   5.301 + * aer_error_resume - clean up corresponding error status bits
   5.302 + * @dev: pointer to Root Port's pci_dev data structure
   5.303 + *
   5.304 + * Invoked by Port Bus driver during nonfatal recovery.
   5.305 + **/
   5.306 +static void aer_error_resume(struct pci_dev *dev)
   5.307 +{
   5.308 +	int pos;
   5.309 +	u32 status, mask;
   5.310 +	u16 reg16;
   5.311 +
   5.312 +	/* Clean up Root device status */
   5.313 +	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
   5.314 +	pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &reg16);
   5.315 +	pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16);
   5.316 +
   5.317 +	/* Clean AER Root Error Status */
   5.318 +	pos = pci_find_aer_capability(dev);
   5.319 +	pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
   5.320 +	pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
   5.321 +	if (dev->error_state == pci_channel_io_normal)
   5.322 +		status &= ~mask; /* Clear corresponding nonfatal bits */
   5.323 +	else
   5.324 +		status &= mask; /* Clear corresponding fatal bits */
   5.325 +	pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
   5.326 +}
   5.327 +
   5.328 +/**
   5.329 + * aer_service_init - register AER root service driver
   5.330 + *
   5.331 + * Invoked when AER root service driver is loaded.
   5.332 + **/
   5.333 +static int __init aer_service_init(void)
   5.334 +{
   5.335 +	return pcie_port_service_register(&aerdrv);
   5.336 +}
   5.337 +
   5.338 +/**
   5.339 + * aer_service_exit - unregister AER root service driver
   5.340 + *
   5.341 + * Invoked when AER root service driver is unloaded.
   5.342 + **/
   5.343 +static void __exit aer_service_exit(void)
   5.344 +{
   5.345 +	pcie_port_service_unregister(&aerdrv);
   5.346 +}
   5.347 +
   5.348 +module_init(aer_service_init);
   5.349 +module_exit(aer_service_exit);
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/drivers/pci/pcie/aer/aerdrv.h	Mon Nov 24 11:02:14 2008 +0000
     6.3 @@ -0,0 +1,125 @@
     6.4 +/*
     6.5 + * Copyright (C) 2006 Intel Corp.
     6.6 + *	Tom Long Nguyen (tom.l.nguyen@intel.com)
     6.7 + *	Zhang Yanmin (yanmin.zhang@intel.com)
     6.8 + *
     6.9 + */
    6.10 +
    6.11 +#ifndef _AERDRV_H_
    6.12 +#define _AERDRV_H_
    6.13 +
    6.14 +#include <linux/pcieport_if.h>
    6.15 +#include <linux/aer.h>
    6.16 +
    6.17 +#define AER_NONFATAL			0
    6.18 +#define AER_FATAL			1
    6.19 +#define AER_CORRECTABLE			2
    6.20 +#define AER_UNCORRECTABLE		4
    6.21 +#define AER_ERROR_MASK			0x001fffff
    6.22 +#define AER_ERROR(d)			(d & AER_ERROR_MASK)
    6.23 +
    6.24 +#define OSC_METHOD_RUN_SUCCESS		0
    6.25 +#define OSC_METHOD_NOT_SUPPORTED	1
    6.26 +#define OSC_METHOD_RUN_FAILURE		2
    6.27 +
    6.28 +/* Root Error Status Register Bits */
    6.29 +#define ROOT_ERR_STATUS_MASKS			0x0f
    6.30 +
    6.31 +#define SYSTEM_ERROR_INTR_ON_MESG_MASK	(PCI_EXP_RTCTL_SECEE|	\
    6.32 +					PCI_EXP_RTCTL_SENFEE|	\
    6.33 +					PCI_EXP_RTCTL_SEFEE)
    6.34 +#define ROOT_PORT_INTR_ON_MESG_MASK	(PCI_ERR_ROOT_CMD_COR_EN|	\
    6.35 +					PCI_ERR_ROOT_CMD_NONFATAL_EN|	\
    6.36 +					PCI_ERR_ROOT_CMD_FATAL_EN)
    6.37 +#define ERR_COR_ID(d)			(d & 0xffff)
    6.38 +#define ERR_UNCOR_ID(d)			(d >> 16)
    6.39 +
    6.40 +#define AER_SUCCESS			0
    6.41 +#define AER_UNSUCCESS			1
    6.42 +#define AER_ERROR_SOURCES_MAX		100
    6.43 +
    6.44 +#define AER_LOG_TLP_MASKS		(PCI_ERR_UNC_POISON_TLP|	\
    6.45 +					PCI_ERR_UNC_ECRC|		\
    6.46 +					PCI_ERR_UNC_UNSUP|		\
    6.47 +					PCI_ERR_UNC_COMP_ABORT|		\
    6.48 +					PCI_ERR_UNC_UNX_COMP|		\
    6.49 +					PCI_ERR_UNC_MALF_TLP)
    6.50 +
    6.51 +/* AER Error Info Flags */
    6.52 +#define AER_TLP_HEADER_VALID_FLAG	0x00000001
    6.53 +#define AER_MULTI_ERROR_VALID_FLAG	0x00000002
    6.54 +
    6.55 +#define ERR_CORRECTABLE_ERROR_MASK	0x000031c1
    6.56 +#define ERR_UNCORRECTABLE_ERROR_MASK	0x001ff010
    6.57 +
    6.58 +struct header_log_regs {
    6.59 +	unsigned int dw0;
    6.60 +	unsigned int dw1;
    6.61 +	unsigned int dw2;
    6.62 +	unsigned int dw3;
    6.63 +};
    6.64 +
    6.65 +struct aer_err_info {
    6.66 +	int severity;			/* 0:NONFATAL | 1:FATAL | 2:COR */
    6.67 +	int flags;
    6.68 +	unsigned int status;		/* COR/UNCOR Error Status */
    6.69 +	struct header_log_regs tlp; 	/* TLP Header */
    6.70 +};
    6.71 +
    6.72 +struct aer_err_source {
    6.73 +	unsigned int status;
    6.74 +	unsigned int id;
    6.75 +};
    6.76 +
    6.77 +struct aer_rpc {
    6.78 +	struct pcie_device *rpd;	/* Root Port device */
    6.79 +	struct work_struct dpc_handler;
    6.80 +	struct aer_err_source e_sources[AER_ERROR_SOURCES_MAX];
    6.81 +	unsigned short prod_idx;	/* Error Producer Index */
    6.82 +	unsigned short cons_idx;	/* Error Consumer Index */
    6.83 +	int isr;
    6.84 +	spinlock_t e_lock;		/*
    6.85 +					 * Lock access to Error Status/ID Regs
    6.86 +					 * and error producer/consumer index
    6.87 +					 */
    6.88 +	struct mutex rpc_mutex;		/*
    6.89 +					 * only one thread could do
    6.90 +					 * recovery on the same
    6.91 +					 * root port hierachy
    6.92 +					 */
    6.93 +	wait_queue_head_t wait_release;
    6.94 +};
    6.95 +
    6.96 +struct aer_broadcast_data {
    6.97 +	enum pci_channel_state state;
    6.98 +	enum pci_ers_result result;
    6.99 +};
   6.100 +
   6.101 +static inline pci_ers_result_t merge_result(enum pci_ers_result orig,
   6.102 +		enum pci_ers_result new)
   6.103 +{
   6.104 +	switch (orig) {
   6.105 +	case PCI_ERS_RESULT_CAN_RECOVER:
   6.106 +	case PCI_ERS_RESULT_RECOVERED:
   6.107 +		orig = new;
   6.108 +		break;
   6.109 +	case PCI_ERS_RESULT_DISCONNECT:
   6.110 +		if (new == PCI_ERS_RESULT_NEED_RESET)
   6.111 +			orig = new;
   6.112 +		break;
   6.113 +	default:
   6.114 +		break;
   6.115 +	}
   6.116 +
   6.117 +	return orig;
   6.118 +}
   6.119 +
   6.120 +extern struct bus_type pcie_port_bus_type;
   6.121 +extern void aer_enable_rootport(struct aer_rpc *rpc);
   6.122 +extern void aer_delete_rootport(struct aer_rpc *rpc);
   6.123 +extern int aer_init(struct pcie_device *dev);
   6.124 +extern void aer_isr(void *context);
   6.125 +extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
   6.126 +extern int aer_osc_setup(struct pci_dev *dev);
   6.127 +
   6.128 +#endif //_AERDRV_H_
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c	Mon Nov 24 11:02:14 2008 +0000
     7.3 @@ -0,0 +1,68 @@
     7.4 +/*
     7.5 + * Access ACPI _OSC method
     7.6 + *
     7.7 + * Copyright (C) 2006 Intel Corp.
     7.8 + *	Tom Long Nguyen (tom.l.nguyen@intel.com)
     7.9 + *	Zhang Yanmin (yanmin.zhang@intel.com)
    7.10 + *
    7.11 + */
    7.12 +
    7.13 +#include <linux/module.h>
    7.14 +#include <linux/pci.h>
    7.15 +#include <linux/kernel.h>
    7.16 +#include <linux/errno.h>
    7.17 +#include <linux/pm.h>
    7.18 +#include <linux/suspend.h>
    7.19 +#include <linux/acpi.h>
    7.20 +#include <linux/pci-acpi.h>
    7.21 +#include <linux/delay.h>
    7.22 +#include "aerdrv.h"
    7.23 +
    7.24 +/**
    7.25 + * aer_osc_setup - run ACPI _OSC method
    7.26 + *
    7.27 + * Return:
    7.28 + *	Zero if success. Nonzero for otherwise.
    7.29 + *
    7.30 + * Invoked when PCIE bus loads AER service driver. To avoid conflict with
    7.31 + * BIOS AER support requires BIOS to yield AER control to OS native driver.
    7.32 + **/
    7.33 +int aer_osc_setup(struct pci_dev *dev)
    7.34 +{
    7.35 +	int retval = OSC_METHOD_RUN_SUCCESS;
    7.36 +	acpi_status status;
    7.37 +	acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
    7.38 +	struct pci_dev *pdev = dev;
    7.39 +	struct pci_bus *parent;
    7.40 +
    7.41 +	while (!handle) {
    7.42 +		if (!pdev || !pdev->bus->parent)
    7.43 +			break;
    7.44 +		parent = pdev->bus->parent;
    7.45 +		if (!parent->self)
    7.46 +			/* Parent must be a host bridge */
    7.47 +			handle = acpi_get_pci_rootbridge_handle(
    7.48 +					pci_domain_nr(parent),
    7.49 +					parent->number);
    7.50 +		else
    7.51 +			handle = DEVICE_ACPI_HANDLE(
    7.52 +					&(parent->self->dev));
    7.53 +		pdev = parent->self;
    7.54 +	}
    7.55 +
    7.56 +	if (!handle)
    7.57 +		return OSC_METHOD_NOT_SUPPORTED;
    7.58 +
    7.59 +	pci_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT);
    7.60 +	status = pci_osc_control_set(handle, OSC_PCI_EXPRESS_AER_CONTROL |
    7.61 +		OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
    7.62 +	if (ACPI_FAILURE(status)) {
    7.63 +		if (status == AE_SUPPORT)
    7.64 +			retval = OSC_METHOD_NOT_SUPPORTED;
    7.65 +	 	else
    7.66 +			retval = OSC_METHOD_RUN_FAILURE;
    7.67 +	}
    7.68 +
    7.69 +	return retval;
    7.70 +}
    7.71 +
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/drivers/pci/pcie/aer/aerdrv_core.c	Mon Nov 24 11:02:14 2008 +0000
     8.3 @@ -0,0 +1,757 @@
     8.4 +/*
     8.5 + * drivers/pci/pcie/aer/aerdrv_core.c
     8.6 + *
     8.7 + * This file is subject to the terms and conditions of the GNU General Public
     8.8 + * License.  See the file "COPYING" in the main directory of this archive
     8.9 + * for more details.
    8.10 + *
    8.11 + * This file implements the core part of PCI-Express AER. When an pci-express
    8.12 + * error is delivered, an error message will be collected and printed to
    8.13 + * console, then, an error recovery procedure will be executed by following
    8.14 + * the pci error recovery rules.
    8.15 + *
    8.16 + * Copyright (C) 2006 Intel Corp.
    8.17 + *	Tom Long Nguyen (tom.l.nguyen@intel.com)
    8.18 + *	Zhang Yanmin (yanmin.zhang@intel.com)
    8.19 + *
    8.20 + */
    8.21 +
    8.22 +#include <linux/module.h>
    8.23 +#include <linux/pci.h>
    8.24 +#include <linux/kernel.h>
    8.25 +#include <linux/errno.h>
    8.26 +#include <linux/pm.h>
    8.27 +#include <linux/suspend.h>
    8.28 +#include <linux/acpi.h>
    8.29 +#include <linux/pci-acpi.h>
    8.30 +#include <linux/delay.h>
    8.31 +#include "aerdrv.h"
    8.32 +
    8.33 +static int forceload;
    8.34 +module_param(forceload, bool, 0);
    8.35 +
    8.36 +#define PCI_CFG_SPACE_SIZE	(0x100)
    8.37 +int pci_find_aer_capability(struct pci_dev *dev)
    8.38 +{
    8.39 +	int pos;
    8.40 +	u32 reg32 = 0;
    8.41 +
    8.42 +	/* Check if it's a pci-express device */
    8.43 +	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
    8.44 +	if (!pos)
    8.45 +		return 0;
    8.46 +
    8.47 +	/* Check if it supports pci-express AER */
    8.48 +	pos = PCI_CFG_SPACE_SIZE;
    8.49 +	while (pos) {
    8.50 +		if (pci_read_config_dword(dev, pos, &reg32))
    8.51 +			return 0;
    8.52 +
    8.53 +		/* some broken boards return ~0 */
    8.54 +		if (reg32 == 0xffffffff)
    8.55 +			return 0;
    8.56 +
    8.57 +		if (PCI_EXT_CAP_ID(reg32) == PCI_EXT_CAP_ID_ERR)
    8.58 +			break;
    8.59 +
    8.60 +		pos = reg32 >> 20;
    8.61 +	}
    8.62 +
    8.63 +	return pos;
    8.64 +}
    8.65 +
    8.66 +int pci_enable_pcie_error_reporting(struct pci_dev *dev)
    8.67 +{
    8.68 +	u16 reg16 = 0;
    8.69 +	int pos;
    8.70 +
    8.71 +	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
    8.72 +	if (!pos)
    8.73 +		return -EIO;
    8.74 +
    8.75 +	pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, &reg16);
    8.76 +	reg16 = reg16 |
    8.77 +		PCI_EXP_DEVCTL_CERE |
    8.78 +		PCI_EXP_DEVCTL_NFERE |
    8.79 +		PCI_EXP_DEVCTL_FERE |
    8.80 +		PCI_EXP_DEVCTL_URRE;
    8.81 +	pci_write_config_word(dev, pos+PCI_EXP_DEVCTL,
    8.82 +			reg16);
    8.83 +	return 0;
    8.84 +}
    8.85 +
    8.86 +int pci_disable_pcie_error_reporting(struct pci_dev *dev)
    8.87 +{
    8.88 +	u16 reg16 = 0;
    8.89 +	int pos;
    8.90 +
    8.91 +	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
    8.92 +	if (!pos)
    8.93 +		return -EIO;
    8.94 +
    8.95 +	pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, &reg16);
    8.96 +	reg16 = reg16 & ~(PCI_EXP_DEVCTL_CERE |
    8.97 +			PCI_EXP_DEVCTL_NFERE |
    8.98 +			PCI_EXP_DEVCTL_FERE |
    8.99 +			PCI_EXP_DEVCTL_URRE);
   8.100 +	pci_write_config_word(dev, pos+PCI_EXP_DEVCTL,
   8.101 +			reg16);
   8.102 +	return 0;
   8.103 +}
   8.104 +
   8.105 +int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
   8.106 +{
   8.107 +	int pos;
   8.108 +	u32 status, mask;
   8.109 +
   8.110 +	pos = pci_find_aer_capability(dev);
   8.111 +	if (!pos)
   8.112 +		return -EIO;
   8.113 +
   8.114 +	pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
   8.115 +	pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
   8.116 +	if (dev->error_state == pci_channel_io_normal)
   8.117 +		status &= ~mask; /* Clear corresponding nonfatal bits */
   8.118 +	else
   8.119 +		status &= mask; /* Clear corresponding fatal bits */
   8.120 +	pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
   8.121 +
   8.122 +	return 0;
   8.123 +}
   8.124 +
   8.125 +static int find_device_iter(struct device *device, void *data)
   8.126 +{
   8.127 +	struct pci_dev *dev;
   8.128 +	u16 id = *(unsigned long *)data;
   8.129 +	u8 secondary, subordinate, d_bus = id >> 8;
   8.130 +
   8.131 +	if (device->bus == &pci_bus_type) {
   8.132 +		dev = to_pci_dev(device);
   8.133 +		if (id == ((dev->bus->number << 8) | dev->devfn)) {
   8.134 +			/*
   8.135 +			 * Device ID match
   8.136 +			 */
   8.137 +			*(unsigned long*)data = (unsigned long)device;
   8.138 +			return 1;
   8.139 +		}
   8.140 +
   8.141 +		/*
   8.142 +		 * If device is P2P, check if it is an upstream?
   8.143 +		 */
   8.144 +		if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) {
   8.145 +			pci_read_config_byte(dev, PCI_SECONDARY_BUS,
   8.146 +				&secondary);
   8.147 +			pci_read_config_byte(dev, PCI_SUBORDINATE_BUS,
   8.148 +				&subordinate);
   8.149 +			if (d_bus >= secondary && d_bus <= subordinate) {
   8.150 +				*(unsigned long*)data = (unsigned long)device;
   8.151 +				return 1;
   8.152 +			}
   8.153 +		}
   8.154 +	}
   8.155 +
   8.156 +	return 0;
   8.157 +}
   8.158 +
   8.159 +/**
   8.160 + * find_source_device - search through device hierarchy for source device
   8.161 + * @p_dev: pointer to Root Port pci_dev data structure
   8.162 + * @id: device ID of agent who sends an error message to this Root Port
   8.163 + *
   8.164 + * Invoked when error is detected at the Root Port.
   8.165 + **/
   8.166 +static struct device* find_source_device(struct pci_dev *parent, u16 id)
   8.167 +{
   8.168 +	struct pci_dev *dev = parent;
   8.169 +	struct device *device;
   8.170 +	unsigned long device_addr;
   8.171 +	int status;
   8.172 +
   8.173 +	/* Is Root Port an agent that sends error message? */
   8.174 +	if (id == ((dev->bus->number << 8) | dev->devfn))
   8.175 +		return &dev->dev;
   8.176 +
   8.177 +	do {
   8.178 +		device_addr = id;
   8.179 + 		if ((status = device_for_each_child(&dev->dev,
   8.180 +			&device_addr, find_device_iter))) {
   8.181 +			device = (struct device*)device_addr;
   8.182 +			dev = to_pci_dev(device);
   8.183 +			if (id == ((dev->bus->number << 8) | dev->devfn))
   8.184 +				return device;
   8.185 +		}
   8.186 + 	}while (status);
   8.187 +
   8.188 +	return NULL;
   8.189 +}
   8.190 +
   8.191 +static void report_error_detected(struct pci_dev *dev, void *data)
   8.192 +{
   8.193 +	pci_ers_result_t vote;
   8.194 +	struct pci_error_handlers *err_handler;
   8.195 +	struct aer_broadcast_data *result_data;
   8.196 +	result_data = (struct aer_broadcast_data *) data;
   8.197 +
   8.198 +	dev->error_state = result_data->state;
   8.199 +
   8.200 +	if (!dev->driver ||
   8.201 +		!dev->driver->err_handler ||
   8.202 +		!dev->driver->err_handler->error_detected) {
   8.203 +		if (result_data->state == pci_channel_io_frozen &&
   8.204 +			!(dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)) {
   8.205 +			/*
   8.206 +			 * In case of fatal recovery, if one of down-
   8.207 +			 * stream device has no driver. We might be
   8.208 +			 * unable to recover because a later insmod
   8.209 +			 * of a driver for this device is unaware of
   8.210 +			 * its hw state.
   8.211 +			 */
   8.212 +			printk(KERN_DEBUG "Device ID[%s] has %s\n",
   8.213 +					dev->dev.bus_id, (dev->driver) ?
   8.214 +					"no AER-aware driver" : "no driver");
   8.215 +		}
   8.216 +		return;
   8.217 +	}
   8.218 +
   8.219 +	err_handler = dev->driver->err_handler;
   8.220 +	vote = err_handler->error_detected(dev, result_data->state);
   8.221 +	result_data->result = merge_result(result_data->result, vote);
   8.222 +	return;
   8.223 +}
   8.224 +
   8.225 +static void report_mmio_enabled(struct pci_dev *dev, void *data)
   8.226 +{
   8.227 +	pci_ers_result_t vote;
   8.228 +	struct pci_error_handlers *err_handler;
   8.229 +	struct aer_broadcast_data *result_data;
   8.230 +	result_data = (struct aer_broadcast_data *) data;
   8.231 +
   8.232 +	if (!dev->driver ||
   8.233 +		!dev->driver->err_handler ||
   8.234 +		!dev->driver->err_handler->mmio_enabled)
   8.235 +		return;
   8.236 +
   8.237 +	err_handler = dev->driver->err_handler;
   8.238 +	vote = err_handler->mmio_enabled(dev);
   8.239 +	result_data->result = merge_result(result_data->result, vote);
   8.240 +	return;
   8.241 +}
   8.242 +
   8.243 +static void report_slot_reset(struct pci_dev *dev, void *data)
   8.244 +{
   8.245 +	pci_ers_result_t vote;
   8.246 +	struct pci_error_handlers *err_handler;
   8.247 +	struct aer_broadcast_data *result_data;
   8.248 +	result_data = (struct aer_broadcast_data *) data;
   8.249 +
   8.250 +	if (!dev->driver ||
   8.251 +		!dev->driver->err_handler ||
   8.252 +		!dev->driver->err_handler->slot_reset)
   8.253 +		return;
   8.254 +
   8.255 +	err_handler = dev->driver->err_handler;
   8.256 +	vote = err_handler->slot_reset(dev);
   8.257 +	result_data->result = merge_result(result_data->result, vote);
   8.258 +	return;
   8.259 +}
   8.260 +
   8.261 +static void report_resume(struct pci_dev *dev, void *data)
   8.262 +{
   8.263 +	struct pci_error_handlers *err_handler;
   8.264 +
   8.265 +	dev->error_state = pci_channel_io_normal;
   8.266 +
   8.267 +	if (!dev->driver ||
   8.268 +		!dev->driver->err_handler ||
   8.269 +		!dev->driver->err_handler->slot_reset)
   8.270 +		return;
   8.271 +
   8.272 +	err_handler = dev->driver->err_handler;
   8.273 +	err_handler->resume(dev);
   8.274 +	return;
   8.275 +}
   8.276 +
   8.277 +/**
   8.278 + * broadcast_error_message - handle message broadcast to downstream drivers
   8.279 + * @device: pointer to from where in a hierarchy message is broadcasted down
   8.280 + * @api: callback to be broadcasted
   8.281 + * @state: error state
   8.282 + *
   8.283 + * Invoked during error recovery process. Once being invoked, the content
   8.284 + * of error severity will be broadcasted to all downstream drivers in a
   8.285 + * hierarchy in question.
   8.286 + **/
   8.287 +static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
   8.288 +	enum pci_channel_state state,
   8.289 +	char *error_mesg,
   8.290 +	void (*cb)(struct pci_dev *, void *))
   8.291 +{
   8.292 +	struct aer_broadcast_data result_data;
   8.293 +
   8.294 +	printk(KERN_DEBUG "Broadcast %s message\n", error_mesg);
   8.295 +	result_data.state = state;
   8.296 +	if (cb == report_error_detected)
   8.297 +		result_data.result = PCI_ERS_RESULT_CAN_RECOVER;
   8.298 +	else
   8.299 +		result_data.result = PCI_ERS_RESULT_RECOVERED;
   8.300 +
   8.301 +	if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) {
   8.302 +		/*
   8.303 +		 * If the error is reported by a bridge, we think this error
   8.304 +		 * is related to the downstream link of the bridge, so we
   8.305 +		 * do error recovery on all subordinates of the bridge instead
   8.306 +		 * of the bridge and clear the error status of the bridge.
   8.307 +		 */
   8.308 +		if (cb == report_error_detected)
   8.309 +			dev->error_state = state;
   8.310 +		pci_walk_bus(dev->subordinate, cb, &result_data);
   8.311 +		if (cb == report_resume) {
   8.312 +			pci_cleanup_aer_uncorrect_error_status(dev);
   8.313 +			dev->error_state = pci_channel_io_normal;
   8.314 +		}
   8.315 +	}
   8.316 +	else {
   8.317 +		/*
   8.318 +		 * If the error is reported by an end point, we think this
   8.319 +		 * error is related to the upstream link of the end point.
   8.320 +		 */
   8.321 +		pci_walk_bus(dev->bus, cb, &result_data);
   8.322 +	}
   8.323 +
   8.324 +	return result_data.result;
   8.325 +}
   8.326 +
   8.327 +struct find_aer_service_data {
   8.328 +	struct pcie_port_service_driver *aer_driver;
   8.329 +	int is_downstream;
   8.330 +};
   8.331 +
   8.332 +static int find_aer_service_iter(struct device *device, void *data)
   8.333 +{
   8.334 +	struct device_driver *driver;
   8.335 +	struct pcie_port_service_driver *service_driver;
   8.336 +	struct pcie_device *pcie_dev;
   8.337 +	struct find_aer_service_data *result;
   8.338 +
   8.339 +	result = (struct find_aer_service_data *) data;
   8.340 +
   8.341 +	if (device->bus == &pcie_port_bus_type) {
   8.342 +		pcie_dev = to_pcie_device(device);
   8.343 +		if (pcie_dev->id.port_type == PCIE_SW_DOWNSTREAM_PORT)
   8.344 +			result->is_downstream = 1;
   8.345 +
   8.346 +		driver = device->driver;
   8.347 +		if (driver) {
   8.348 +			service_driver = to_service_driver(driver);
   8.349 +			if (service_driver->id_table->service_type ==
   8.350 +					PCIE_PORT_SERVICE_AER) {
   8.351 +				result->aer_driver = service_driver;
   8.352 +				return 1;
   8.353 +			}
   8.354 +		}
   8.355 +	}
   8.356 +
   8.357 +	return 0;
   8.358 +}
   8.359 +
   8.360 +static void find_aer_service(struct pci_dev *dev,
   8.361 +		struct find_aer_service_data *data)
   8.362 +{
   8.363 +	device_for_each_child(&dev->dev, data, find_aer_service_iter);
   8.364 +}
   8.365 +
   8.366 +static pci_ers_result_t reset_link(struct pcie_device *aerdev,
   8.367 +		struct pci_dev *dev)
   8.368 +{
   8.369 +	struct pci_dev *udev;
   8.370 +	pci_ers_result_t status;
   8.371 +	struct find_aer_service_data data;
   8.372 +
   8.373 +	if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)
   8.374 +		udev = dev;
   8.375 +	else
   8.376 +		udev= dev->bus->self;
   8.377 +
   8.378 +	data.is_downstream = 0;
   8.379 +	data.aer_driver = NULL;
   8.380 +	find_aer_service(udev, &data);
   8.381 +
   8.382 +	/*
   8.383 +	 * Use the aer driver of the error agent firstly.
   8.384 +	 * If it hasn't the aer driver, use the root port's
   8.385 +	 */
   8.386 +	if (!data.aer_driver || !data.aer_driver->reset_link) {
   8.387 +		if (data.is_downstream &&
   8.388 +			aerdev->device.driver &&
   8.389 +			to_service_driver(aerdev->device.driver)->reset_link) {
   8.390 +			data.aer_driver =
   8.391 +				to_service_driver(aerdev->device.driver);
   8.392 +		} else {
   8.393 +			printk(KERN_DEBUG "No link-reset support to Device ID"
   8.394 +				"[%s]\n",
   8.395 +				dev->dev.bus_id);
   8.396 +			return PCI_ERS_RESULT_DISCONNECT;
   8.397 +		}
   8.398 +	}
   8.399 +
   8.400 +	status = data.aer_driver->reset_link(udev);
   8.401 +	if (status != PCI_ERS_RESULT_RECOVERED) {
   8.402 +		printk(KERN_DEBUG "Link reset at upstream Device ID"
   8.403 +			"[%s] failed\n",
   8.404 +			udev->dev.bus_id);
   8.405 +		return PCI_ERS_RESULT_DISCONNECT;
   8.406 +	}
   8.407 +
   8.408 +	return status;
   8.409 +}
   8.410 +
   8.411 +/**
   8.412 + * do_recovery - handle nonfatal/fatal error recovery process
   8.413 + * @aerdev: pointer to a pcie_device data structure of root port
   8.414 + * @dev: pointer to a pci_dev data structure of agent detecting an error
   8.415 + * @severity: error severity type
   8.416 + *
   8.417 + * Invoked when an error is nonfatal/fatal. Once being invoked, broadcast
   8.418 + * error detected message to all downstream drivers within a hierarchy in
   8.419 + * question and return the returned code.
   8.420 + **/
   8.421 +static pci_ers_result_t do_recovery(struct pcie_device *aerdev,
   8.422 +		struct pci_dev *dev,
   8.423 +		int severity)
   8.424 +{
   8.425 +	pci_ers_result_t status, result = PCI_ERS_RESULT_RECOVERED;
   8.426 +	enum pci_channel_state state;
   8.427 +
   8.428 +	if (severity == AER_FATAL)
   8.429 +		state = pci_channel_io_frozen;
   8.430 +	else
   8.431 +		state = pci_channel_io_normal;
   8.432 +
   8.433 +	status = broadcast_error_message(dev,
   8.434 +			state,
   8.435 +			"error_detected",
   8.436 +			report_error_detected);
   8.437 +
   8.438 +	if (severity == AER_FATAL) {
   8.439 +		result = reset_link(aerdev, dev);
   8.440 +		if (result != PCI_ERS_RESULT_RECOVERED) {
   8.441 +			/* TODO: Should panic here? */
   8.442 +			return result;
   8.443 +		}
   8.444 +	}
   8.445 +
   8.446 +	if (status == PCI_ERS_RESULT_CAN_RECOVER)
   8.447 +		status = broadcast_error_message(dev,
   8.448 +				state,
   8.449 +				"mmio_enabled",
   8.450 +				report_mmio_enabled);
   8.451 +
   8.452 +	if (status == PCI_ERS_RESULT_NEED_RESET) {
   8.453 +		/*
   8.454 +		 * TODO: Should call platform-specific
   8.455 +		 * functions to reset slot before calling
   8.456 +		 * drivers' slot_reset callbacks?
   8.457 +		 */
   8.458 +		status = broadcast_error_message(dev,
   8.459 +				state,
   8.460 +				"slot_reset",
   8.461 +				report_slot_reset);
   8.462 +	}
   8.463 +
   8.464 +	if (status == PCI_ERS_RESULT_RECOVERED)
   8.465 +		broadcast_error_message(dev,
   8.466 +				state,
   8.467 +				"resume",
   8.468 +				report_resume);
   8.469 +
   8.470 +	return status;
   8.471 +}
   8.472 +
   8.473 +/**
   8.474 + * handle_error_source - handle logging error into an event log
   8.475 + * @aerdev: pointer to pcie_device data structure of the root port
   8.476 + * @dev: pointer to pci_dev data structure of error source device
   8.477 + * @info: comprehensive error information
   8.478 + *
   8.479 + * Invoked when an error being detected by Root Port.
   8.480 + **/
   8.481 +static void handle_error_source(struct pcie_device * aerdev,
   8.482 +	struct pci_dev *dev,
   8.483 +	struct aer_err_info info)
   8.484 +{
   8.485 +	pci_ers_result_t status = 0;
   8.486 +	int pos;
   8.487 +
   8.488 +	if (info.severity == AER_CORRECTABLE) {
   8.489 +		/*
   8.490 +		 * Correctable error does not need software intevention.
   8.491 +		 * No need to go through error recovery process.
   8.492 +		 */
   8.493 +		pos = pci_find_aer_capability(dev);
   8.494 +		if (pos)
   8.495 +			pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS,
   8.496 +					info.status);
   8.497 +	} else {
   8.498 +		status = do_recovery(aerdev, dev, info.severity);
   8.499 +		if (status == PCI_ERS_RESULT_RECOVERED) {
   8.500 +			printk(KERN_DEBUG "AER driver successfully recovered\n");
   8.501 +		} else {
   8.502 +			/* TODO: Should kernel panic here? */
   8.503 +			printk(KERN_DEBUG "AER driver didn't recover\n");
   8.504 +		}
   8.505 +	}
   8.506 +}
   8.507 +
   8.508 +/**
   8.509 + * aer_enable_rootport - enable Root Port's interrupts when receiving messages
   8.510 + * @rpc: pointer to a Root Port data structure
   8.511 + *
   8.512 + * Invoked when PCIE bus loads AER service driver.
   8.513 + **/
   8.514 +void aer_enable_rootport(struct aer_rpc *rpc)
   8.515 +{
   8.516 +	struct pci_dev *pdev = rpc->rpd->port;
   8.517 +	int pos, aer_pos;
   8.518 +	u16 reg16;
   8.519 +	u32 reg32;
   8.520 +
   8.521 +	pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
   8.522 +	/* Clear PCIE Capability's Device Status */
   8.523 +	pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, &reg16);
   8.524 +	pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16);
   8.525 +
   8.526 +	/* Disable system error generation in response to error messages */
   8.527 +	pci_read_config_word(pdev, pos + PCI_EXP_RTCTL, &reg16);
   8.528 +	reg16 &= ~(SYSTEM_ERROR_INTR_ON_MESG_MASK);
   8.529 +	pci_write_config_word(pdev, pos + PCI_EXP_RTCTL, reg16);
   8.530 +
   8.531 +	aer_pos = pci_find_aer_capability(pdev);
   8.532 +	/* Clear error status */
   8.533 +	pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, &reg32);
   8.534 +	pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32);
   8.535 +	pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, &reg32);
   8.536 +	pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32);
   8.537 +	pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, &reg32);
   8.538 +	pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32);
   8.539 +
   8.540 +	/* Enable Root Port device reporting error itself */
   8.541 +	pci_read_config_word(pdev, pos+PCI_EXP_DEVCTL, &reg16);
   8.542 +	reg16 = reg16 |
   8.543 +		PCI_EXP_DEVCTL_CERE |
   8.544 +		PCI_EXP_DEVCTL_NFERE |
   8.545 +		PCI_EXP_DEVCTL_FERE |
   8.546 +		PCI_EXP_DEVCTL_URRE;
   8.547 +	pci_write_config_word(pdev, pos+PCI_EXP_DEVCTL,
   8.548 +		reg16);
   8.549 +
   8.550 +	/* Enable Root Port's interrupt in response to error messages */
   8.551 +	pci_write_config_dword(pdev,
   8.552 +		aer_pos + PCI_ERR_ROOT_COMMAND,
   8.553 +		ROOT_PORT_INTR_ON_MESG_MASK);
   8.554 +}
   8.555 +
   8.556 +/**
   8.557 + * disable_root_aer - disable Root Port's interrupts when receiving messages
   8.558 + * @rpc: pointer to a Root Port data structure
   8.559 + *
   8.560 + * Invoked when PCIE bus unloads AER service driver.
   8.561 + **/
   8.562 +static void disable_root_aer(struct aer_rpc *rpc)
   8.563 +{
   8.564 +	struct pci_dev *pdev = rpc->rpd->port;
   8.565 +	u32 reg32;
   8.566 +	int pos;
   8.567 +
   8.568 +	pos = pci_find_aer_capability(pdev);
   8.569 +	/* Disable Root's interrupt in response to error messages */
   8.570 +	pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, 0);
   8.571 +
   8.572 +	/* Clear Root's error status reg */
   8.573 +	pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, &reg32);
   8.574 +	pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32);
   8.575 +}
   8.576 +
   8.577 +/**
   8.578 + * get_e_source - retrieve an error source
   8.579 + * @rpc: pointer to the root port which holds an error
   8.580 + *
   8.581 + * Invoked by DPC handler to consume an error.
   8.582 + **/
   8.583 +static struct aer_err_source* get_e_source(struct aer_rpc *rpc)
   8.584 +{
   8.585 +	struct aer_err_source *e_source;
   8.586 +	unsigned long flags;
   8.587 +
   8.588 +	/* Lock access to Root error producer/consumer index */
   8.589 +	spin_lock_irqsave(&rpc->e_lock, flags);
   8.590 +	if (rpc->prod_idx == rpc->cons_idx) {
   8.591 +		spin_unlock_irqrestore(&rpc->e_lock, flags);
   8.592 +		return NULL;
   8.593 +	}
   8.594 +	e_source = &rpc->e_sources[rpc->cons_idx];
   8.595 +	rpc->cons_idx++;
   8.596 +	if (rpc->cons_idx == AER_ERROR_SOURCES_MAX)
   8.597 +		rpc->cons_idx = 0;
   8.598 +	spin_unlock_irqrestore(&rpc->e_lock, flags);
   8.599 +
   8.600 +	return e_source;
   8.601 +}
   8.602 +
   8.603 +static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
   8.604 +{
   8.605 +	int pos;
   8.606 +
   8.607 +	pos = pci_find_aer_capability(dev);
   8.608 +
   8.609 +	/* The device might not support AER */
   8.610 +	if (!pos)
   8.611 +		return AER_SUCCESS;
   8.612 +
   8.613 +	if (info->severity == AER_CORRECTABLE) {
   8.614 +		pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS,
   8.615 +			&info->status);
   8.616 +		if (!(info->status & ERR_CORRECTABLE_ERROR_MASK))
   8.617 +			return AER_UNSUCCESS;
   8.618 +	} else if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE ||
   8.619 +		info->severity == AER_NONFATAL) {
   8.620 +
   8.621 +		/* Link is still healthy for IO reads */
   8.622 +		pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
   8.623 +			&info->status);
   8.624 +		if (!(info->status & ERR_UNCORRECTABLE_ERROR_MASK))
   8.625 +			return AER_UNSUCCESS;
   8.626 +
   8.627 +		if (info->status & AER_LOG_TLP_MASKS) {
   8.628 +			info->flags |= AER_TLP_HEADER_VALID_FLAG;
   8.629 +			pci_read_config_dword(dev,
   8.630 +				pos + PCI_ERR_HEADER_LOG, &info->tlp.dw0);
   8.631 +			pci_read_config_dword(dev,
   8.632 +				pos + PCI_ERR_HEADER_LOG + 4, &info->tlp.dw1);
   8.633 +			pci_read_config_dword(dev,
   8.634 +				pos + PCI_ERR_HEADER_LOG + 8, &info->tlp.dw2);
   8.635 +			pci_read_config_dword(dev,
   8.636 +				pos + PCI_ERR_HEADER_LOG + 12, &info->tlp.dw3);
   8.637 +		}
   8.638 +	}
   8.639 +
   8.640 +	return AER_SUCCESS;
   8.641 +}
   8.642 +
   8.643 +/**
   8.644 + * aer_isr_one_error - consume an error detected by root port
   8.645 + * @p_device: pointer to error root port service device
   8.646 + * @e_src: pointer to an error source
   8.647 + **/
   8.648 +static void aer_isr_one_error(struct pcie_device *p_device,
   8.649 +		struct aer_err_source *e_src)
   8.650 +{
   8.651 +	struct device *s_device;
   8.652 +	struct aer_err_info e_info = {0, 0, 0,};
   8.653 +	int i;
   8.654 +	u16 id;
   8.655 +
   8.656 +	/*
   8.657 +	 * There is a possibility that both correctable error and
   8.658 +	 * uncorrectable error being logged. Report correctable error first.
   8.659 +	 */
   8.660 +	for (i = 1; i & ROOT_ERR_STATUS_MASKS ; i <<= 2) {
   8.661 +		if (i > 4)
   8.662 +			break;
   8.663 +		if (!(e_src->status & i))
   8.664 +			continue;
   8.665 +
   8.666 +		/* Init comprehensive error information */
   8.667 +		if (i & PCI_ERR_ROOT_COR_RCV) {
   8.668 +			id = ERR_COR_ID(e_src->id);
   8.669 +			e_info.severity = AER_CORRECTABLE;
   8.670 +		} else {
   8.671 +			id = ERR_UNCOR_ID(e_src->id);
   8.672 +			e_info.severity = ((e_src->status >> 6) & 1);
   8.673 +		}
   8.674 +		if (e_src->status &
   8.675 +			(PCI_ERR_ROOT_MULTI_COR_RCV |
   8.676 +			 PCI_ERR_ROOT_MULTI_UNCOR_RCV))
   8.677 +			e_info.flags |= AER_MULTI_ERROR_VALID_FLAG;
   8.678 +		if (!(s_device = find_source_device(p_device->port, id))) {
   8.679 +			printk(KERN_DEBUG "%s->can't find device of ID%04x\n",
   8.680 +				__FUNCTION__, id);
   8.681 +			continue;
   8.682 +		}
   8.683 +		if (get_device_error_info(to_pci_dev(s_device), &e_info) ==
   8.684 +				AER_SUCCESS) {
   8.685 +			aer_print_error(to_pci_dev(s_device), &e_info);
   8.686 +			handle_error_source(p_device,
   8.687 +				to_pci_dev(s_device),
   8.688 +				e_info);
   8.689 +		}
   8.690 +	}
   8.691 +}
   8.692 +
   8.693 +/**
   8.694 + * aer_isr - consume errors detected by root port
   8.695 + * @context: pointer to a private data of pcie device
   8.696 + *
   8.697 + * Invoked, as DPC, when root port records new detected error
   8.698 + **/
   8.699 +void aer_isr(void *context)
   8.700 +{
   8.701 +	struct pcie_device *p_device = (struct pcie_device *) context;
   8.702 +	struct aer_rpc *rpc = get_service_data(p_device);
   8.703 +	struct aer_err_source *e_src;
   8.704 +
   8.705 +	mutex_lock(&rpc->rpc_mutex);
   8.706 +	e_src = get_e_source(rpc);
   8.707 +	while (e_src) {
   8.708 +		aer_isr_one_error(p_device, e_src);
   8.709 +		e_src = get_e_source(rpc);
   8.710 +	}
   8.711 +	mutex_unlock(&rpc->rpc_mutex);
   8.712 +
   8.713 +	wake_up(&rpc->wait_release);
   8.714 +}
   8.715 +
   8.716 +/**
   8.717 + * aer_delete_rootport - disable root port aer and delete service data
   8.718 + * @rpc: pointer to a root port device being deleted
   8.719 + *
   8.720 + * Invoked when AER service unloaded on a specific Root Port
   8.721 + **/
   8.722 +void aer_delete_rootport(struct aer_rpc *rpc)
   8.723 +{
   8.724 +	/* Disable root port AER itself */
   8.725 +	disable_root_aer(rpc);
   8.726 +
   8.727 +	kfree(rpc);
   8.728 +}
   8.729 +
   8.730 +/**
   8.731 + * aer_init - provide AER initialization
   8.732 + * @dev: pointer to AER pcie device
   8.733 + *
   8.734 + * Invoked when AER service driver is loaded.
   8.735 + **/
   8.736 +int aer_init(struct pcie_device *dev)
   8.737 +{
   8.738 +	int status;
   8.739 +
   8.740 +	/* Run _OSC Method */
   8.741 +	status = aer_osc_setup(dev->port);
   8.742 +
   8.743 +	if(status != OSC_METHOD_RUN_SUCCESS) {
   8.744 +		printk(KERN_DEBUG "%s: AER service init fails - %s\n",
   8.745 +		__FUNCTION__,
   8.746 +		(status == OSC_METHOD_NOT_SUPPORTED) ?
   8.747 +			"No ACPI _OSC support" : "Run ACPI _OSC fails");
   8.748 +
   8.749 +		if (!forceload)
   8.750 +			return status;
   8.751 +	}
   8.752 +
   8.753 +	return AER_SUCCESS;
   8.754 +}
   8.755 +
   8.756 +EXPORT_SYMBOL_GPL(pci_find_aer_capability);
   8.757 +EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting);
   8.758 +EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting);
   8.759 +EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status);
   8.760 +
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/drivers/pci/pcie/aer/aerdrv_errprint.c	Mon Nov 24 11:02:14 2008 +0000
     9.3 @@ -0,0 +1,248 @@
     9.4 +/*
     9.5 + * drivers/pci/pcie/aer/aerdrv_errprint.c
     9.6 + *
     9.7 + * This file is subject to the terms and conditions of the GNU General Public
     9.8 + * License.  See the file "COPYING" in the main directory of this archive
     9.9 + * for more details.
    9.10 + *
    9.11 + * Format error messages and print them to console.
    9.12 + *
    9.13 + * Copyright (C) 2006 Intel Corp.
    9.14 + *	Tom Long Nguyen (tom.l.nguyen@intel.com)
    9.15 + *	Zhang Yanmin (yanmin.zhang@intel.com)
    9.16 + *
    9.17 + */
    9.18 +
    9.19 +#include <linux/module.h>
    9.20 +#include <linux/pci.h>
    9.21 +#include <linux/kernel.h>
    9.22 +#include <linux/errno.h>
    9.23 +#include <linux/pm.h>
    9.24 +#include <linux/suspend.h>
    9.25 +
    9.26 +#include "aerdrv.h"
    9.27 +
    9.28 +#define AER_AGENT_RECEIVER		0
    9.29 +#define AER_AGENT_REQUESTER		1
    9.30 +#define AER_AGENT_COMPLETER		2
    9.31 +#define AER_AGENT_TRANSMITTER		3
    9.32 +
    9.33 +#define AER_AGENT_REQUESTER_MASK	(PCI_ERR_UNC_COMP_TIME|	\
    9.34 +					PCI_ERR_UNC_UNSUP)
    9.35 +
    9.36 +#define AER_AGENT_COMPLETER_MASK	PCI_ERR_UNC_COMP_ABORT
    9.37 +
    9.38 +#define AER_AGENT_TRANSMITTER_MASK(t, e) (e & (PCI_ERR_COR_REP_ROLL| \
    9.39 +	((t == AER_CORRECTABLE) ? PCI_ERR_COR_REP_TIMER: 0)))
    9.40 +
    9.41 +#define AER_GET_AGENT(t, e)						\
    9.42 +	((e & AER_AGENT_COMPLETER_MASK) ? AER_AGENT_COMPLETER :		\
    9.43 +	(e & AER_AGENT_REQUESTER_MASK) ? AER_AGENT_REQUESTER :		\
    9.44 +	(AER_AGENT_TRANSMITTER_MASK(t, e)) ? AER_AGENT_TRANSMITTER :	\
    9.45 +	AER_AGENT_RECEIVER)
    9.46 +
    9.47 +#define AER_PHYSICAL_LAYER_ERROR_MASK	PCI_ERR_COR_RCVR
    9.48 +#define AER_DATA_LINK_LAYER_ERROR_MASK(t, e)	\
    9.49 +		(PCI_ERR_UNC_DLP|		\
    9.50 +		PCI_ERR_COR_BAD_TLP| 		\
    9.51 +		PCI_ERR_COR_BAD_DLLP|		\
    9.52 +		PCI_ERR_COR_REP_ROLL| 		\
    9.53 +		((t == AER_CORRECTABLE) ?	\
    9.54 +		PCI_ERR_COR_REP_TIMER: 0))
    9.55 +
    9.56 +#define AER_PHYSICAL_LAYER_ERROR	0
    9.57 +#define AER_DATA_LINK_LAYER_ERROR	1
    9.58 +#define AER_TRANSACTION_LAYER_ERROR	2
    9.59 +
    9.60 +#define AER_GET_LAYER_ERROR(t, e)				\
    9.61 +	((e & AER_PHYSICAL_LAYER_ERROR_MASK) ?			\
    9.62 +	AER_PHYSICAL_LAYER_ERROR :				\
    9.63 +	(e & AER_DATA_LINK_LAYER_ERROR_MASK(t, e)) ?		\
    9.64 +		AER_DATA_LINK_LAYER_ERROR : 			\
    9.65 +		AER_TRANSACTION_LAYER_ERROR)
    9.66 +
    9.67 +/*
    9.68 + * AER error strings
    9.69 + */
    9.70 +static char* aer_error_severity_string[] = {
    9.71 +	"Uncorrected (Non-Fatal)",
    9.72 +	"Uncorrected (Fatal)",
    9.73 +	"Corrected"
    9.74 +};
    9.75 +
    9.76 +static char* aer_error_layer[] = {
    9.77 +	"Physical Layer",
    9.78 +	"Data Link Layer",
    9.79 +	"Transaction Layer"
    9.80 +};
    9.81 +static char* aer_correctable_error_string[] = {
    9.82 +	"Receiver Error        ",	/* Bit Position 0 	*/
    9.83 +	NULL,
    9.84 +	NULL,
    9.85 +	NULL,
    9.86 +	NULL,
    9.87 +	NULL,
    9.88 +	"Bad TLP               ",	/* Bit Position 6 	*/
    9.89 +	"Bad DLLP              ",	/* Bit Position 7 	*/
    9.90 +	"RELAY_NUM Rollover    ",	/* Bit Position 8 	*/
    9.91 +	NULL,
    9.92 +	NULL,
    9.93 +	NULL,
    9.94 +	"Replay Timer Timeout  ",	/* Bit Position 12 	*/
    9.95 +	"Advisory Non-Fatal    ", 	/* Bit Position 13	*/
    9.96 +	NULL,
    9.97 +	NULL,
    9.98 +	NULL,
    9.99 +	NULL,
   9.100 +	NULL,
   9.101 +	NULL,
   9.102 +	NULL,
   9.103 +	NULL,
   9.104 +	NULL,
   9.105 +	NULL,
   9.106 +	NULL,
   9.107 +	NULL,
   9.108 +	NULL,
   9.109 +	NULL,
   9.110 +	NULL,
   9.111 +	NULL,
   9.112 +	NULL,
   9.113 +	NULL,
   9.114 +};
   9.115 +
   9.116 +static char* aer_uncorrectable_error_string[] = {
   9.117 +	NULL,
   9.118 +	NULL,
   9.119 +	NULL,
   9.120 +	NULL,
   9.121 +	"Data Link Protocol    ",	/* Bit Position 4	*/
   9.122 +	NULL,
   9.123 +	NULL,
   9.124 +	NULL,
   9.125 +	NULL,
   9.126 +	NULL,
   9.127 +	NULL,
   9.128 +	NULL,
   9.129 +	"Poisoned TLP          ",	/* Bit Position 12 	*/
   9.130 +	"Flow Control Protocol ",	/* Bit Position 13	*/
   9.131 +	"Completion Timeout    ",	/* Bit Position 14 	*/
   9.132 +	"Completer Abort       ",	/* Bit Position 15 	*/
   9.133 +	"Unexpected Completion ",	/* Bit Position 16	*/
   9.134 +	"Receiver Overflow     ",	/* Bit Position 17	*/
   9.135 +	"Malformed TLP         ",	/* Bit Position 18	*/
   9.136 +	"ECRC                  ",	/* Bit Position 19	*/
   9.137 +	"Unsupported Request   ",	/* Bit Position 20	*/
   9.138 +	NULL,
   9.139 +	NULL,
   9.140 +	NULL,
   9.141 +	NULL,
   9.142 +	NULL,
   9.143 +	NULL,
   9.144 +	NULL,
   9.145 +	NULL,
   9.146 +	NULL,
   9.147 +	NULL,
   9.148 +	NULL,
   9.149 +};
   9.150 +
   9.151 +static char* aer_agent_string[] = {
   9.152 +	"Receiver ID",
   9.153 +	"Requester ID",
   9.154 +	"Completer ID",
   9.155 +	"Transmitter ID"
   9.156 +};
   9.157 +
   9.158 +static char * aer_get_error_source_name(int severity,
   9.159 +			unsigned int status,
   9.160 +			char errmsg_buff[])
   9.161 +{
   9.162 +	int i;
   9.163 +	char * errmsg = NULL;
   9.164 +
   9.165 +	for (i = 0; i < 32; i++) {
   9.166 +		if (!(status & (1 << i)))
   9.167 +			continue;
   9.168 +
   9.169 +		if (severity == AER_CORRECTABLE)
   9.170 +			errmsg = aer_correctable_error_string[i];
   9.171 +		else
   9.172 +			errmsg = aer_uncorrectable_error_string[i];
   9.173 +
   9.174 +		if (!errmsg) {
   9.175 +			sprintf(errmsg_buff, "Unknown Error Bit %2d  ", i);
   9.176 +			errmsg = errmsg_buff;
   9.177 +		}
   9.178 +
   9.179 +		break;
   9.180 +	}
   9.181 +
   9.182 +	return errmsg;
   9.183 +}
   9.184 +
   9.185 +static DEFINE_SPINLOCK(logbuf_lock);
   9.186 +static char errmsg_buff[100];
   9.187 +void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
   9.188 +{
   9.189 +	char * errmsg;
   9.190 +	int err_layer, agent;
   9.191 +	char * loglevel;
   9.192 +
   9.193 +	if (info->severity == AER_CORRECTABLE)
   9.194 +		loglevel = KERN_WARNING;
   9.195 +	else
   9.196 +		loglevel = KERN_ERR;
   9.197 +
   9.198 +	printk("%s+------ PCI-Express Device Error ------+\n", loglevel);
   9.199 +	printk("%sError Severity\t\t: %s\n", loglevel,
   9.200 +		aer_error_severity_string[info->severity]);
   9.201 +
   9.202 +	if ( info->status == 0) {
   9.203 +		printk("%sPCIE Bus Error type\t: (Unaccessible)\n", loglevel);
   9.204 +		printk("%sUnaccessible Received\t: %s\n", loglevel,
   9.205 +			info->flags & AER_MULTI_ERROR_VALID_FLAG ?
   9.206 +				"Multiple" : "First");
   9.207 +		printk("%sUnregistered Agent ID\t: %04x\n", loglevel,
   9.208 +			(dev->bus->number << 8) | dev->devfn);
   9.209 +	} else {
   9.210 +		err_layer = AER_GET_LAYER_ERROR(info->severity, info->status);
   9.211 +		printk("%sPCIE Bus Error type\t: %s\n", loglevel,
   9.212 +			aer_error_layer[err_layer]);
   9.213 +
   9.214 +		spin_lock(&logbuf_lock);
   9.215 +		errmsg = aer_get_error_source_name(info->severity,
   9.216 +				info->status,
   9.217 +				errmsg_buff);
   9.218 +		printk("%s%s\t: %s\n", loglevel, errmsg,
   9.219 +			info->flags & AER_MULTI_ERROR_VALID_FLAG ?
   9.220 +				"Multiple" : "First");
   9.221 +		spin_unlock(&logbuf_lock);
   9.222 +
   9.223 +		agent = AER_GET_AGENT(info->severity, info->status);
   9.224 +		printk("%s%s\t\t: %04x\n", loglevel,
   9.225 +			aer_agent_string[agent],
   9.226 +			(dev->bus->number << 8) | dev->devfn);
   9.227 +
   9.228 +		printk("%sVendorID=%04xh, DeviceID=%04xh,"
   9.229 +			" Bus=%02xh, Device=%02xh, Function=%02xh\n",
   9.230 +			loglevel,
   9.231 +			dev->vendor,
   9.232 +			dev->device,
   9.233 +			dev->bus->number,
   9.234 +			PCI_SLOT(dev->devfn),
   9.235 +			PCI_FUNC(dev->devfn));
   9.236 +
   9.237 +		if (info->flags & AER_TLP_HEADER_VALID_FLAG) {
   9.238 +			unsigned char *tlp = (unsigned char *) &info->tlp;
   9.239 +			printk("%sTLB Header:\n", loglevel);
   9.240 +			printk("%s%02x%02x%02x%02x %02x%02x%02x%02x"
   9.241 +				" %02x%02x%02x%02x %02x%02x%02x%02x\n",
   9.242 +				loglevel,
   9.243 +				*(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
   9.244 +				*(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4),
   9.245 +				*(tlp + 11), *(tlp + 10), *(tlp + 9),
   9.246 +				*(tlp + 8), *(tlp + 15), *(tlp + 14),
   9.247 +				*(tlp + 13), *(tlp + 12));
   9.248 +		}
   9.249 +	}
   9.250 +}
   9.251 +
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/include/linux/aer.h	Mon Nov 24 11:02:14 2008 +0000
    10.3 @@ -0,0 +1,24 @@
    10.4 +/*
    10.5 + * Copyright (C) 2006 Intel Corp.
    10.6 + *     Tom Long Nguyen (tom.l.nguyen@intel.com)
    10.7 + *     Zhang Yanmin (yanmin.zhang@intel.com)
    10.8 + */
    10.9 +
   10.10 +#ifndef _AER_H_
   10.11 +#define _AER_H_
   10.12 +
   10.13 +#if defined(CONFIG_PCIEAER)
   10.14 +/* pci-e port driver needs this function to enable aer */
   10.15 +extern int pci_enable_pcie_error_reporting(struct pci_dev *dev);
   10.16 +extern int pci_find_aer_capability(struct pci_dev *dev);
   10.17 +extern int pci_disable_pcie_error_reporting(struct pci_dev *dev);
   10.18 +extern int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev);
   10.19 +#else
   10.20 +#define pci_enable_pcie_error_reporting(dev)		do { } while (0)
   10.21 +#define pci_find_aer_capability(dev)			do { } while (0)
   10.22 +#define pci_disable_pcie_error_reporting(dev)		do { } while (0)
   10.23 +#define pci_cleanup_aer_uncorrect_error_status(dev)	do { } while (0)
   10.24 +#endif
   10.25 +
   10.26 +#endif //_AER_H_
   10.27 +
    11.1 --- a/include/linux/pcieport_if.h	Mon Nov 24 11:01:21 2008 +0000
    11.2 +++ b/include/linux/pcieport_if.h	Mon Nov 24 11:02:14 2008 +0000
    11.3 @@ -62,6 +62,12 @@ struct pcie_port_service_driver {
    11.4  	int (*suspend) (struct pcie_device *dev, pm_message_t state);
    11.5  	int (*resume) (struct pcie_device *dev);
    11.6  
    11.7 +	/* Service Error Recovery Handler */
    11.8 +	struct pci_error_handlers *err_handler;
    11.9 +
   11.10 +	/* Link Reset Capability - AER service driver specific */
   11.11 +	pci_ers_result_t (*reset_link) (struct pci_dev *dev);
   11.12 +
   11.13  	const struct pcie_port_service_id *id_table;
   11.14  	struct device_driver driver;
   11.15  };