brintos

brintos / linux-shallow public Read only

0
0
Text · 15.9 KiB · a6d3013 Raw
597 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * amd8111_edac.c, AMD8111 Hyper Transport chip EDAC kernel module4 *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	0x746027 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_STR44			" 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_STR56			" 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_STR66			" 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_STR76			" PCI Access Write Error at 0x%x\n", reg);77}78 79/*80 * device-specific methods for amd8111 PCI Bridge Controller81 *82 * Error Reporting and Handling for amd8111 chipset could be found83 * in its datasheet 3.1.2 section, P3784 */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_INFO210			"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	1231 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_INFO285			"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 for363	 * edac_device_ctl_info, but make use of existing364	 * 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, dev_info->edac_idx);370	if (!dev_info->edac_dev) {371		ret = -ENOMEM;372		goto err_dev_put;373	}374 375	dev_info->edac_dev->pvt_info = dev_info;376	dev_info->edac_dev->dev = &dev_info->dev->dev;377	dev_info->edac_dev->mod_name = AMD8111_EDAC_MOD_STR;378	dev_info->edac_dev->ctl_name = dev_info->ctl_name;379	dev_info->edac_dev->dev_name = dev_name(&dev_info->dev->dev);380 381	if (edac_op_state == EDAC_OPSTATE_POLL)382		dev_info->edac_dev->edac_check = dev_info->check;383 384	if (dev_info->init)385		dev_info->init(dev_info);386 387	if (edac_device_add_device(dev_info->edac_dev) > 0) {388		printk(KERN_ERR "failed to add edac_dev for %s\n",389			dev_info->ctl_name);390		goto err_edac_free_ctl;391	}392 393	printk(KERN_INFO "added one edac_dev on AMD8111 "394		"vendor %x, device %x, name %s\n",395		PCI_VENDOR_ID_AMD, dev_info->err_dev,396		dev_info->ctl_name);397 398	return 0;399 400err_edac_free_ctl:401	edac_device_free_ctl_info(dev_info->edac_dev);402err_dev_put:403	pci_dev_put(dev_info->dev);404err:405	return ret;406}407 408static void amd8111_dev_remove(struct pci_dev *dev)409{410	struct amd8111_dev_info *dev_info;411 412	for (dev_info = amd8111_devices; dev_info->err_dev; dev_info++)413		if (dev_info->dev->device == dev->device)414			break;415 416	if (!dev_info->err_dev)	/* should never happen */417		return;418 419	if (dev_info->edac_dev) {420		edac_device_del_device(dev_info->edac_dev->dev);421		edac_device_free_ctl_info(dev_info->edac_dev);422	}423 424	if (dev_info->exit)425		dev_info->exit(dev_info);426 427	pci_dev_put(dev_info->dev);428}429 430static int amd8111_pci_probe(struct pci_dev *dev,431				const struct pci_device_id *id)432{433	struct amd8111_pci_info *pci_info = &amd8111_pcis[id->driver_data];434	int ret = -ENODEV;435 436	pci_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,437					pci_info->err_dev, NULL);438 439	if (!pci_info->dev) {440		printk(KERN_ERR "EDAC device not found:"441			"vendor %x, device %x, name %s\n",442			PCI_VENDOR_ID_AMD, pci_info->err_dev,443			pci_info->ctl_name);444		goto err;445	}446 447	if (pci_enable_device(pci_info->dev)) {448		printk(KERN_ERR "failed to enable:"449			"vendor %x, device %x, name %s\n",450			PCI_VENDOR_ID_AMD, pci_info->err_dev,451			pci_info->ctl_name);452		goto err_dev_put;453	}454 455	/*456	 * we do not allocate extra private structure for457	 * edac_pci_ctl_info, but make use of existing458	 * one instead.459	*/460	pci_info->edac_idx = edac_pci_alloc_index();461	pci_info->edac_dev = edac_pci_alloc_ctl_info(0, pci_info->ctl_name);462	if (!pci_info->edac_dev) {463		ret = -ENOMEM;464		goto err_dev_put;465	}466 467	pci_info->edac_dev->pvt_info = pci_info;468	pci_info->edac_dev->dev = &pci_info->dev->dev;469	pci_info->edac_dev->mod_name = AMD8111_EDAC_MOD_STR;470	pci_info->edac_dev->ctl_name = pci_info->ctl_name;471	pci_info->edac_dev->dev_name = dev_name(&pci_info->dev->dev);472 473	if (edac_op_state == EDAC_OPSTATE_POLL)474		pci_info->edac_dev->edac_check = pci_info->check;475 476	if (pci_info->init)477		pci_info->init(pci_info);478 479	if (edac_pci_add_device(pci_info->edac_dev, pci_info->edac_idx) > 0) {480		printk(KERN_ERR "failed to add edac_pci for %s\n",481			pci_info->ctl_name);482		goto err_edac_free_ctl;483	}484 485	printk(KERN_INFO "added one edac_pci on AMD8111 "486		"vendor %x, device %x, name %s\n",487		PCI_VENDOR_ID_AMD, pci_info->err_dev,488		pci_info->ctl_name);489 490	return 0;491 492err_edac_free_ctl:493	edac_pci_free_ctl_info(pci_info->edac_dev);494err_dev_put:495	pci_dev_put(pci_info->dev);496err:497	return ret;498}499 500static void amd8111_pci_remove(struct pci_dev *dev)501{502	struct amd8111_pci_info *pci_info;503 504	for (pci_info = amd8111_pcis; pci_info->err_dev; pci_info++)505		if (pci_info->dev->device == dev->device)506			break;507 508	if (!pci_info->err_dev)	/* should never happen */509		return;510 511	if (pci_info->edac_dev) {512		edac_pci_del_device(pci_info->edac_dev->dev);513		edac_pci_free_ctl_info(pci_info->edac_dev);514	}515 516	if (pci_info->exit)517		pci_info->exit(pci_info);518 519	pci_dev_put(pci_info->dev);520}521 522/* PCI Device ID talbe for general EDAC device */523static const struct pci_device_id amd8111_edac_dev_tbl[] = {524	{525	PCI_VEND_DEV(AMD, 8111_LPC),526	.subvendor = PCI_ANY_ID,527	.subdevice = PCI_ANY_ID,528	.class = 0,529	.class_mask = 0,530	.driver_data = LPC_BRIDGE,531	},532	{533	0,534	}			/* table is NULL-terminated */535};536MODULE_DEVICE_TABLE(pci, amd8111_edac_dev_tbl);537 538static struct pci_driver amd8111_edac_dev_driver = {539	.name = "AMD8111_EDAC_DEV",540	.probe = amd8111_dev_probe,541	.remove = amd8111_dev_remove,542	.id_table = amd8111_edac_dev_tbl,543};544 545/* PCI Device ID table for EDAC PCI controller */546static const struct pci_device_id amd8111_edac_pci_tbl[] = {547	{548	PCI_VEND_DEV(AMD, 8111_PCI),549	.subvendor = PCI_ANY_ID,550	.subdevice = PCI_ANY_ID,551	.class = 0,552	.class_mask = 0,553	.driver_data = PCI_BRIDGE,554	},555	{556	0,557	}			/* table is NULL-terminated */558};559MODULE_DEVICE_TABLE(pci, amd8111_edac_pci_tbl);560 561static struct pci_driver amd8111_edac_pci_driver = {562	.name = "AMD8111_EDAC_PCI",563	.probe = amd8111_pci_probe,564	.remove = amd8111_pci_remove,565	.id_table = amd8111_edac_pci_tbl,566};567 568static int __init amd8111_edac_init(void)569{570	int val;571 572	printk(KERN_INFO "AMD8111 EDAC driver "	AMD8111_EDAC_REVISION "\n");573	printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc.\n");574 575	/* Only POLL mode supported so far */576	edac_op_state = EDAC_OPSTATE_POLL;577 578	val = pci_register_driver(&amd8111_edac_dev_driver);579	val |= pci_register_driver(&amd8111_edac_pci_driver);580 581	return val;582}583 584static void __exit amd8111_edac_exit(void)585{586	pci_unregister_driver(&amd8111_edac_pci_driver);587	pci_unregister_driver(&amd8111_edac_dev_driver);588}589 590 591module_init(amd8111_edac_init);592module_exit(amd8111_edac_exit);593 594MODULE_LICENSE("GPL");595MODULE_AUTHOR("Cao Qingtao <qingtao.cao@windriver.com>");596MODULE_DESCRIPTION("AMD8111 HyperTransport I/O Hub EDAC kernel module");597