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