cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

amd8111_edac.c (16310B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * amd8111_edac.c, AMD8111 Hyper Transport chip EDAC kernel module
      4 *
      5 * Copyright (c) 2008 Wind River Systems, Inc.
      6 *
      7 * Authors:	Cao Qingtao <qingtao.cao@windriver.com>
      8 * 		Benjamin Walsh <benjamin.walsh@windriver.com>
      9 * 		Hu Yongqi <yongqi.hu@windriver.com>
     10 */
     11
     12#include <linux/module.h>
     13#include <linux/init.h>
     14#include <linux/interrupt.h>
     15#include <linux/bitops.h>
     16#include <linux/edac.h>
     17#include <linux/pci_ids.h>
     18#include <asm/io.h>
     19
     20#include "edac_module.h"
     21#include "amd8111_edac.h"
     22
     23#define AMD8111_EDAC_REVISION	" Ver: 1.0.0"
     24#define AMD8111_EDAC_MOD_STR	"amd8111_edac"
     25
     26#define PCI_DEVICE_ID_AMD_8111_PCI	0x7460
     27
     28enum amd8111_edac_devs {
     29	LPC_BRIDGE = 0,
     30};
     31
     32enum amd8111_edac_pcis {
     33	PCI_BRIDGE = 0,
     34};
     35
     36/* Wrapper functions for accessing PCI configuration space */
     37static int edac_pci_read_dword(struct pci_dev *dev, int reg, u32 *val32)
     38{
     39	int ret;
     40
     41	ret = pci_read_config_dword(dev, reg, val32);
     42	if (ret != 0)
     43		printk(KERN_ERR AMD8111_EDAC_MOD_STR
     44			" PCI Access Read Error at 0x%x\n", reg);
     45
     46	return ret;
     47}
     48
     49static void edac_pci_read_byte(struct pci_dev *dev, int reg, u8 *val8)
     50{
     51	int ret;
     52
     53	ret = pci_read_config_byte(dev, reg, val8);
     54	if (ret != 0)
     55		printk(KERN_ERR AMD8111_EDAC_MOD_STR
     56			" PCI Access Read Error at 0x%x\n", reg);
     57}
     58
     59static void edac_pci_write_dword(struct pci_dev *dev, int reg, u32 val32)
     60{
     61	int ret;
     62
     63	ret = pci_write_config_dword(dev, reg, val32);
     64	if (ret != 0)
     65		printk(KERN_ERR AMD8111_EDAC_MOD_STR
     66			" PCI Access Write Error at 0x%x\n", reg);
     67}
     68
     69static void edac_pci_write_byte(struct pci_dev *dev, int reg, u8 val8)
     70{
     71	int ret;
     72
     73	ret = pci_write_config_byte(dev, reg, val8);
     74	if (ret != 0)
     75		printk(KERN_ERR AMD8111_EDAC_MOD_STR
     76			" PCI Access Write Error at 0x%x\n", reg);
     77}
     78
     79/*
     80 * device-specific methods for amd8111 PCI Bridge Controller
     81 *
     82 * Error Reporting and Handling for amd8111 chipset could be found
     83 * in its datasheet 3.1.2 section, P37
     84 */
     85static void amd8111_pci_bridge_init(struct amd8111_pci_info *pci_info)
     86{
     87	u32 val32;
     88	struct pci_dev *dev = pci_info->dev;
     89
     90	/* First clear error detection flags on the host interface */
     91
     92	/* Clear SSE/SMA/STA flags in the global status register*/
     93	edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);
     94	if (val32 & PCI_STSCMD_CLEAR_MASK)
     95		edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);
     96
     97	/* Clear CRC and Link Fail flags in HT Link Control reg */
     98	edac_pci_read_dword(dev, REG_HT_LINK, &val32);
     99	if (val32 & HT_LINK_CLEAR_MASK)
    100		edac_pci_write_dword(dev, REG_HT_LINK, val32);
    101
    102	/* Second clear all fault on the secondary interface */
    103
    104	/* Clear error flags in the memory-base limit reg. */
    105	edac_pci_read_dword(dev, REG_MEM_LIM, &val32);
    106	if (val32 & MEM_LIMIT_CLEAR_MASK)
    107		edac_pci_write_dword(dev, REG_MEM_LIM, val32);
    108
    109	/* Clear Discard Timer Expired flag in Interrupt/Bridge Control reg */
    110	edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
    111	if (val32 & PCI_INTBRG_CTRL_CLEAR_MASK)
    112		edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
    113
    114	/* Last enable error detections */
    115	if (edac_op_state == EDAC_OPSTATE_POLL) {
    116		/* Enable System Error reporting in global status register */
    117		edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);
    118		val32 |= PCI_STSCMD_SERREN;
    119		edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);
    120
    121		/* Enable CRC Sync flood packets to HyperTransport Link */
    122		edac_pci_read_dword(dev, REG_HT_LINK, &val32);
    123		val32 |= HT_LINK_CRCFEN;
    124		edac_pci_write_dword(dev, REG_HT_LINK, val32);
    125
    126		/* Enable SSE reporting etc in Interrupt control reg */
    127		edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
    128		val32 |= PCI_INTBRG_CTRL_POLL_MASK;
    129		edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
    130	}
    131}
    132
    133static void amd8111_pci_bridge_exit(struct amd8111_pci_info *pci_info)
    134{
    135	u32 val32;
    136	struct pci_dev *dev = pci_info->dev;
    137
    138	if (edac_op_state == EDAC_OPSTATE_POLL) {
    139		/* Disable System Error reporting */
    140		edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);
    141		val32 &= ~PCI_STSCMD_SERREN;
    142		edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);
    143
    144		/* Disable CRC flood packets */
    145		edac_pci_read_dword(dev, REG_HT_LINK, &val32);
    146		val32 &= ~HT_LINK_CRCFEN;
    147		edac_pci_write_dword(dev, REG_HT_LINK, val32);
    148
    149		/* Disable DTSERREN/MARSP/SERREN in Interrupt Control reg */
    150		edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
    151		val32 &= ~PCI_INTBRG_CTRL_POLL_MASK;
    152		edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
    153	}
    154}
    155
    156static void amd8111_pci_bridge_check(struct edac_pci_ctl_info *edac_dev)
    157{
    158	struct amd8111_pci_info *pci_info = edac_dev->pvt_info;
    159	struct pci_dev *dev = pci_info->dev;
    160	u32 val32;
    161
    162	/* Check out PCI Bridge Status and Command Register */
    163	edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);
    164	if (val32 & PCI_STSCMD_CLEAR_MASK) {
    165		printk(KERN_INFO "Error(s) in PCI bridge status and command"
    166			"register on device %s\n", pci_info->ctl_name);
    167		printk(KERN_INFO "SSE: %d, RMA: %d, RTA: %d\n",
    168			(val32 & PCI_STSCMD_SSE) != 0,
    169			(val32 & PCI_STSCMD_RMA) != 0,
    170			(val32 & PCI_STSCMD_RTA) != 0);
    171
    172		val32 |= PCI_STSCMD_CLEAR_MASK;
    173		edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);
    174
    175		edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
    176	}
    177
    178	/* Check out HyperTransport Link Control Register */
    179	edac_pci_read_dword(dev, REG_HT_LINK, &val32);
    180	if (val32 & HT_LINK_LKFAIL) {
    181		printk(KERN_INFO "Error(s) in hypertransport link control"
    182			"register on device %s\n", pci_info->ctl_name);
    183		printk(KERN_INFO "LKFAIL: %d\n",
    184			(val32 & HT_LINK_LKFAIL) != 0);
    185
    186		val32 |= HT_LINK_LKFAIL;
    187		edac_pci_write_dword(dev, REG_HT_LINK, val32);
    188
    189		edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
    190	}
    191
    192	/* Check out PCI Interrupt and Bridge Control Register */
    193	edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
    194	if (val32 & PCI_INTBRG_CTRL_DTSTAT) {
    195		printk(KERN_INFO "Error(s) in PCI interrupt and bridge control"
    196			"register on device %s\n", pci_info->ctl_name);
    197		printk(KERN_INFO "DTSTAT: %d\n",
    198			(val32 & PCI_INTBRG_CTRL_DTSTAT) != 0);
    199
    200		val32 |= PCI_INTBRG_CTRL_DTSTAT;
    201		edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
    202
    203		edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
    204	}
    205
    206	/* Check out PCI Bridge Memory Base-Limit Register */
    207	edac_pci_read_dword(dev, REG_MEM_LIM, &val32);
    208	if (val32 & MEM_LIMIT_CLEAR_MASK) {
    209		printk(KERN_INFO
    210			"Error(s) in mem limit register on %s device\n",
    211			pci_info->ctl_name);
    212		printk(KERN_INFO "DPE: %d, RSE: %d, RMA: %d\n"
    213			"RTA: %d, STA: %d, MDPE: %d\n",
    214			(val32 & MEM_LIMIT_DPE)  != 0,
    215			(val32 & MEM_LIMIT_RSE)  != 0,
    216			(val32 & MEM_LIMIT_RMA)  != 0,
    217			(val32 & MEM_LIMIT_RTA)  != 0,
    218			(val32 & MEM_LIMIT_STA)  != 0,
    219			(val32 & MEM_LIMIT_MDPE) != 0);
    220
    221		val32 |= MEM_LIMIT_CLEAR_MASK;
    222		edac_pci_write_dword(dev, REG_MEM_LIM, val32);
    223
    224		edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
    225	}
    226}
    227
    228static struct resource *legacy_io_res;
    229static int at_compat_reg_broken;
    230#define LEGACY_NR_PORTS	1
    231
    232/* device-specific methods for amd8111 LPC Bridge device */
    233static void amd8111_lpc_bridge_init(struct amd8111_dev_info *dev_info)
    234{
    235	u8 val8;
    236	struct pci_dev *dev = dev_info->dev;
    237
    238	/* First clear REG_AT_COMPAT[SERR, IOCHK] if necessary */
    239	legacy_io_res = request_region(REG_AT_COMPAT, LEGACY_NR_PORTS,
    240					AMD8111_EDAC_MOD_STR);
    241	if (!legacy_io_res)
    242		printk(KERN_INFO "%s: failed to request legacy I/O region "
    243			"start %d, len %d\n", __func__,
    244			REG_AT_COMPAT, LEGACY_NR_PORTS);
    245	else {
    246		val8 = __do_inb(REG_AT_COMPAT);
    247		if (val8 == 0xff) { /* buggy port */
    248			printk(KERN_INFO "%s: port %d is buggy, not supported"
    249				" by hardware?\n", __func__, REG_AT_COMPAT);
    250			at_compat_reg_broken = 1;
    251			release_region(REG_AT_COMPAT, LEGACY_NR_PORTS);
    252			legacy_io_res = NULL;
    253		} else {
    254			u8 out8 = 0;
    255			if (val8 & AT_COMPAT_SERR)
    256				out8 = AT_COMPAT_CLRSERR;
    257			if (val8 & AT_COMPAT_IOCHK)
    258				out8 |= AT_COMPAT_CLRIOCHK;
    259			if (out8 > 0)
    260				__do_outb(out8, REG_AT_COMPAT);
    261		}
    262	}
    263
    264	/* Second clear error flags on LPC bridge */
    265	edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8);
    266	if (val8 & IO_CTRL_1_CLEAR_MASK)
    267		edac_pci_write_byte(dev, REG_IO_CTRL_1, val8);
    268}
    269
    270static void amd8111_lpc_bridge_exit(struct amd8111_dev_info *dev_info)
    271{
    272	if (legacy_io_res)
    273		release_region(REG_AT_COMPAT, LEGACY_NR_PORTS);
    274}
    275
    276static void amd8111_lpc_bridge_check(struct edac_device_ctl_info *edac_dev)
    277{
    278	struct amd8111_dev_info *dev_info = edac_dev->pvt_info;
    279	struct pci_dev *dev = dev_info->dev;
    280	u8 val8;
    281
    282	edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8);
    283	if (val8 & IO_CTRL_1_CLEAR_MASK) {
    284		printk(KERN_INFO
    285			"Error(s) in IO control register on %s device\n",
    286			dev_info->ctl_name);
    287		printk(KERN_INFO "LPC ERR: %d, PW2LPC: %d\n",
    288			(val8 & IO_CTRL_1_LPC_ERR) != 0,
    289			(val8 & IO_CTRL_1_PW2LPC) != 0);
    290
    291		val8 |= IO_CTRL_1_CLEAR_MASK;
    292		edac_pci_write_byte(dev, REG_IO_CTRL_1, val8);
    293
    294		edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
    295	}
    296
    297	if (at_compat_reg_broken == 0) {
    298		u8 out8 = 0;
    299		val8 = __do_inb(REG_AT_COMPAT);
    300		if (val8 & AT_COMPAT_SERR)
    301			out8 = AT_COMPAT_CLRSERR;
    302		if (val8 & AT_COMPAT_IOCHK)
    303			out8 |= AT_COMPAT_CLRIOCHK;
    304		if (out8 > 0) {
    305			__do_outb(out8, REG_AT_COMPAT);
    306			edac_device_handle_ue(edac_dev, 0, 0,
    307						edac_dev->ctl_name);
    308		}
    309	}
    310}
    311
    312/* General devices represented by edac_device_ctl_info */
    313static struct amd8111_dev_info amd8111_devices[] = {
    314	[LPC_BRIDGE] = {
    315		.err_dev = PCI_DEVICE_ID_AMD_8111_LPC,
    316		.ctl_name = "lpc",
    317		.init = amd8111_lpc_bridge_init,
    318		.exit = amd8111_lpc_bridge_exit,
    319		.check = amd8111_lpc_bridge_check,
    320	},
    321	{0},
    322};
    323
    324/* PCI controllers represented by edac_pci_ctl_info */
    325static struct amd8111_pci_info amd8111_pcis[] = {
    326	[PCI_BRIDGE] = {
    327		.err_dev = PCI_DEVICE_ID_AMD_8111_PCI,
    328		.ctl_name = "AMD8111_PCI_Controller",
    329		.init = amd8111_pci_bridge_init,
    330		.exit = amd8111_pci_bridge_exit,
    331		.check = amd8111_pci_bridge_check,
    332	},
    333	{0},
    334};
    335
    336static int amd8111_dev_probe(struct pci_dev *dev,
    337				const struct pci_device_id *id)
    338{
    339	struct amd8111_dev_info *dev_info = &amd8111_devices[id->driver_data];
    340	int ret = -ENODEV;
    341
    342	dev_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,
    343					dev_info->err_dev, NULL);
    344
    345	if (!dev_info->dev) {
    346		printk(KERN_ERR "EDAC device not found:"
    347			"vendor %x, device %x, name %s\n",
    348			PCI_VENDOR_ID_AMD, dev_info->err_dev,
    349			dev_info->ctl_name);
    350		goto err;
    351	}
    352
    353	if (pci_enable_device(dev_info->dev)) {
    354		printk(KERN_ERR "failed to enable:"
    355			"vendor %x, device %x, name %s\n",
    356			PCI_VENDOR_ID_AMD, dev_info->err_dev,
    357			dev_info->ctl_name);
    358		goto err_dev_put;
    359	}
    360
    361	/*
    362	 * we do not allocate extra private structure for
    363	 * edac_device_ctl_info, but make use of existing
    364	 * one instead.
    365	*/
    366	dev_info->edac_idx = edac_device_alloc_index();
    367	dev_info->edac_dev =
    368		edac_device_alloc_ctl_info(0, dev_info->ctl_name, 1,
    369					   NULL, 0, 0,
    370					   NULL, 0, dev_info->edac_idx);
    371	if (!dev_info->edac_dev) {
    372		ret = -ENOMEM;
    373		goto err_dev_put;
    374	}
    375
    376	dev_info->edac_dev->pvt_info = dev_info;
    377	dev_info->edac_dev->dev = &dev_info->dev->dev;
    378	dev_info->edac_dev->mod_name = AMD8111_EDAC_MOD_STR;
    379	dev_info->edac_dev->ctl_name = dev_info->ctl_name;
    380	dev_info->edac_dev->dev_name = dev_name(&dev_info->dev->dev);
    381
    382	if (edac_op_state == EDAC_OPSTATE_POLL)
    383		dev_info->edac_dev->edac_check = dev_info->check;
    384
    385	if (dev_info->init)
    386		dev_info->init(dev_info);
    387
    388	if (edac_device_add_device(dev_info->edac_dev) > 0) {
    389		printk(KERN_ERR "failed to add edac_dev for %s\n",
    390			dev_info->ctl_name);
    391		goto err_edac_free_ctl;
    392	}
    393
    394	printk(KERN_INFO "added one edac_dev on AMD8111 "
    395		"vendor %x, device %x, name %s\n",
    396		PCI_VENDOR_ID_AMD, dev_info->err_dev,
    397		dev_info->ctl_name);
    398
    399	return 0;
    400
    401err_edac_free_ctl:
    402	edac_device_free_ctl_info(dev_info->edac_dev);
    403err_dev_put:
    404	pci_dev_put(dev_info->dev);
    405err:
    406	return ret;
    407}
    408
    409static void amd8111_dev_remove(struct pci_dev *dev)
    410{
    411	struct amd8111_dev_info *dev_info;
    412
    413	for (dev_info = amd8111_devices; dev_info->err_dev; dev_info++)
    414		if (dev_info->dev->device == dev->device)
    415			break;
    416
    417	if (!dev_info->err_dev)	/* should never happen */
    418		return;
    419
    420	if (dev_info->edac_dev) {
    421		edac_device_del_device(dev_info->edac_dev->dev);
    422		edac_device_free_ctl_info(dev_info->edac_dev);
    423	}
    424
    425	if (dev_info->exit)
    426		dev_info->exit(dev_info);
    427
    428	pci_dev_put(dev_info->dev);
    429}
    430
    431static int amd8111_pci_probe(struct pci_dev *dev,
    432				const struct pci_device_id *id)
    433{
    434	struct amd8111_pci_info *pci_info = &amd8111_pcis[id->driver_data];
    435	int ret = -ENODEV;
    436
    437	pci_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,
    438					pci_info->err_dev, NULL);
    439
    440	if (!pci_info->dev) {
    441		printk(KERN_ERR "EDAC device not found:"
    442			"vendor %x, device %x, name %s\n",
    443			PCI_VENDOR_ID_AMD, pci_info->err_dev,
    444			pci_info->ctl_name);
    445		goto err;
    446	}
    447
    448	if (pci_enable_device(pci_info->dev)) {
    449		printk(KERN_ERR "failed to enable:"
    450			"vendor %x, device %x, name %s\n",
    451			PCI_VENDOR_ID_AMD, pci_info->err_dev,
    452			pci_info->ctl_name);
    453		goto err_dev_put;
    454	}
    455
    456	/*
    457	 * we do not allocate extra private structure for
    458	 * edac_pci_ctl_info, but make use of existing
    459	 * one instead.
    460	*/
    461	pci_info->edac_idx = edac_pci_alloc_index();
    462	pci_info->edac_dev = edac_pci_alloc_ctl_info(0, pci_info->ctl_name);
    463	if (!pci_info->edac_dev) {
    464		ret = -ENOMEM;
    465		goto err_dev_put;
    466	}
    467
    468	pci_info->edac_dev->pvt_info = pci_info;
    469	pci_info->edac_dev->dev = &pci_info->dev->dev;
    470	pci_info->edac_dev->mod_name = AMD8111_EDAC_MOD_STR;
    471	pci_info->edac_dev->ctl_name = pci_info->ctl_name;
    472	pci_info->edac_dev->dev_name = dev_name(&pci_info->dev->dev);
    473
    474	if (edac_op_state == EDAC_OPSTATE_POLL)
    475		pci_info->edac_dev->edac_check = pci_info->check;
    476
    477	if (pci_info->init)
    478		pci_info->init(pci_info);
    479
    480	if (edac_pci_add_device(pci_info->edac_dev, pci_info->edac_idx) > 0) {
    481		printk(KERN_ERR "failed to add edac_pci for %s\n",
    482			pci_info->ctl_name);
    483		goto err_edac_free_ctl;
    484	}
    485
    486	printk(KERN_INFO "added one edac_pci on AMD8111 "
    487		"vendor %x, device %x, name %s\n",
    488		PCI_VENDOR_ID_AMD, pci_info->err_dev,
    489		pci_info->ctl_name);
    490
    491	return 0;
    492
    493err_edac_free_ctl:
    494	edac_pci_free_ctl_info(pci_info->edac_dev);
    495err_dev_put:
    496	pci_dev_put(pci_info->dev);
    497err:
    498	return ret;
    499}
    500
    501static void amd8111_pci_remove(struct pci_dev *dev)
    502{
    503	struct amd8111_pci_info *pci_info;
    504
    505	for (pci_info = amd8111_pcis; pci_info->err_dev; pci_info++)
    506		if (pci_info->dev->device == dev->device)
    507			break;
    508
    509	if (!pci_info->err_dev)	/* should never happen */
    510		return;
    511
    512	if (pci_info->edac_dev) {
    513		edac_pci_del_device(pci_info->edac_dev->dev);
    514		edac_pci_free_ctl_info(pci_info->edac_dev);
    515	}
    516
    517	if (pci_info->exit)
    518		pci_info->exit(pci_info);
    519
    520	pci_dev_put(pci_info->dev);
    521}
    522
    523/* PCI Device ID talbe for general EDAC device */
    524static const struct pci_device_id amd8111_edac_dev_tbl[] = {
    525	{
    526	PCI_VEND_DEV(AMD, 8111_LPC),
    527	.subvendor = PCI_ANY_ID,
    528	.subdevice = PCI_ANY_ID,
    529	.class = 0,
    530	.class_mask = 0,
    531	.driver_data = LPC_BRIDGE,
    532	},
    533	{
    534	0,
    535	}			/* table is NULL-terminated */
    536};
    537MODULE_DEVICE_TABLE(pci, amd8111_edac_dev_tbl);
    538
    539static struct pci_driver amd8111_edac_dev_driver = {
    540	.name = "AMD8111_EDAC_DEV",
    541	.probe = amd8111_dev_probe,
    542	.remove = amd8111_dev_remove,
    543	.id_table = amd8111_edac_dev_tbl,
    544};
    545
    546/* PCI Device ID table for EDAC PCI controller */
    547static const struct pci_device_id amd8111_edac_pci_tbl[] = {
    548	{
    549	PCI_VEND_DEV(AMD, 8111_PCI),
    550	.subvendor = PCI_ANY_ID,
    551	.subdevice = PCI_ANY_ID,
    552	.class = 0,
    553	.class_mask = 0,
    554	.driver_data = PCI_BRIDGE,
    555	},
    556	{
    557	0,
    558	}			/* table is NULL-terminated */
    559};
    560MODULE_DEVICE_TABLE(pci, amd8111_edac_pci_tbl);
    561
    562static struct pci_driver amd8111_edac_pci_driver = {
    563	.name = "AMD8111_EDAC_PCI",
    564	.probe = amd8111_pci_probe,
    565	.remove = amd8111_pci_remove,
    566	.id_table = amd8111_edac_pci_tbl,
    567};
    568
    569static int __init amd8111_edac_init(void)
    570{
    571	int val;
    572
    573	printk(KERN_INFO "AMD8111 EDAC driver "	AMD8111_EDAC_REVISION "\n");
    574	printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc.\n");
    575
    576	/* Only POLL mode supported so far */
    577	edac_op_state = EDAC_OPSTATE_POLL;
    578
    579	val = pci_register_driver(&amd8111_edac_dev_driver);
    580	val |= pci_register_driver(&amd8111_edac_pci_driver);
    581
    582	return val;
    583}
    584
    585static void __exit amd8111_edac_exit(void)
    586{
    587	pci_unregister_driver(&amd8111_edac_pci_driver);
    588	pci_unregister_driver(&amd8111_edac_dev_driver);
    589}
    590
    591
    592module_init(amd8111_edac_init);
    593module_exit(amd8111_edac_exit);
    594
    595MODULE_LICENSE("GPL");
    596MODULE_AUTHOR("Cao Qingtao <qingtao.cao@windriver.com>\n");
    597MODULE_DESCRIPTION("AMD8111 HyperTransport I/O Hub EDAC kernel module");