10d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox/*
20d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox * Intel 82860 Memory Controller kernel module
30d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox * (C) 2005 Red Hat (http://www.redhat.com)
40d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox * This file may be distributed under the terms of the
50d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox * GNU General Public License.
60d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox *
70d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox * Written by Ben Woodard <woodard@redhat.com>
80d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox * shamelessly copied from and based upon the edac_i82875 driver
90d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox * by Thayne Harbaugh of Linux Networx. (http://lnxi.com)
100d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox */
110d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
120d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox#include <linux/module.h>
130d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox#include <linux/init.h>
140d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox#include <linux/pci.h>
150d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox#include <linux/pci_ids.h>
16c3c52bce6993c6d37af2c2de9b482a7013d646a7Hitoshi Mitake#include <linux/edac.h>
1720bcb7a81dee21bfa3408f03f46b2891c9b5c84bDouglas Thompson#include "edac_core.h"
180d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
19152ba3942276c2a240703669ae4a3099e0a79451Michal Marek#define  I82860_REVISION " Ver: 2.0.2"
20929a40ec324e947d4ad14cc1ced785c104c560e2Doug Thompson#define EDAC_MOD_STR	"i82860_edac"
2137f04581abac20444e5b7106c1e1f28bec5b989cDoug Thompson
22537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson#define i82860_printk(level, fmt, arg...) \
23e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson	edac_printk(level, "i82860", fmt, ##arg)
24537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson
25537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson#define i82860_mc_printk(mci, level, fmt, arg...) \
26e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson	edac_mc_chipset_printk(mci, level, "i82860", fmt, ##arg)
27537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson
280d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox#ifndef PCI_DEVICE_ID_INTEL_82860_0
290d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox#define PCI_DEVICE_ID_INTEL_82860_0	0x2531
300d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox#endif				/* PCI_DEVICE_ID_INTEL_82860_0 */
310d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
320d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox#define I82860_MCHCFG 0x50
330d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox#define I82860_GBA 0x60
340d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox#define I82860_GBA_MASK 0x7FF
350d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox#define I82860_GBA_SHIFT 24
360d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox#define I82860_ERRSTS 0xC8
370d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox#define I82860_EAP 0xE4
380d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox#define I82860_DERRCTL_STS 0xE2
390d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
400d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Coxenum i82860_chips {
410d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	I82860 = 0,
420d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox};
430d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
440d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Coxstruct i82860_dev_info {
450d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	const char *ctl_name;
460d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox};
470d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
480d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Coxstruct i82860_error_info {
490d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	u16 errsts;
500d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	u32 eap;
510d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	u16 derrsyn;
520d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	u16 errsts2;
530d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox};
540d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
550d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Coxstatic const struct i82860_dev_info i82860_devs[] = {
560d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	[I82860] = {
57052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson		.ctl_name = "i82860"},
580d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox};
590d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
60f044091ca4c0b05be8f83748d76d4fbba4fc74cfDouglas Thompsonstatic struct pci_dev *mci_pdev;	/* init dev: in case that AGP code
61e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson					 * has already registered driver
62e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson					 */
63456a2f9552e7849475f4aea1a9aa4c0e54b3dddaDave Jiangstatic struct edac_pci_ctl_info *i82860_pci;
640d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
65e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonstatic void i82860_get_error_info(struct mem_ctl_info *mci,
66052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson				struct i82860_error_info *info)
670d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox{
6837f04581abac20444e5b7106c1e1f28bec5b989cDoug Thompson	struct pci_dev *pdev;
6937f04581abac20444e5b7106c1e1f28bec5b989cDoug Thompson
7037f04581abac20444e5b7106c1e1f28bec5b989cDoug Thompson	pdev = to_pci_dev(mci->dev);
7137f04581abac20444e5b7106c1e1f28bec5b989cDoug Thompson
720d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	/*
730d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	 * This is a mess because there is no atomic way to read all the
740d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	 * registers at once and the registers can transition from CE being
750d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	 * overwritten by UE.
760d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	 */
7737f04581abac20444e5b7106c1e1f28bec5b989cDoug Thompson	pci_read_config_word(pdev, I82860_ERRSTS, &info->errsts);
7837f04581abac20444e5b7106c1e1f28bec5b989cDoug Thompson	pci_read_config_dword(pdev, I82860_EAP, &info->eap);
7937f04581abac20444e5b7106c1e1f28bec5b989cDoug Thompson	pci_read_config_word(pdev, I82860_DERRCTL_STS, &info->derrsyn);
8037f04581abac20444e5b7106c1e1f28bec5b989cDoug Thompson	pci_read_config_word(pdev, I82860_ERRSTS, &info->errsts2);
810d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
8237f04581abac20444e5b7106c1e1f28bec5b989cDoug Thompson	pci_write_bits16(pdev, I82860_ERRSTS, 0x0003, 0x0003);
830d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
840d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	/*
850d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	 * If the error is the same for both reads then the first set of reads
860d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	 * is valid.  If there is a change then there is a CE no info and the
870d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	 * second set of reads is valid and should be UE info.
880d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	 */
890d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	if (!(info->errsts2 & 0x0003))
900d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox		return;
91e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson
920d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	if ((info->errsts ^ info->errsts2) & 0x0003) {
9337f04581abac20444e5b7106c1e1f28bec5b989cDoug Thompson		pci_read_config_dword(pdev, I82860_EAP, &info->eap);
94b4e8b37201d647e4b4abb89d57ebdb8c739d5405Dave Jiang		pci_read_config_word(pdev, I82860_DERRCTL_STS, &info->derrsyn);
950d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	}
960d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox}
970d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
98e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Petersonstatic int i82860_process_error_info(struct mem_ctl_info *mci,
99052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson				struct i82860_error_info *info,
100052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson				int handle_errors)
1010d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox{
1020d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	int row;
1030d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
1040d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	if (!(info->errsts2 & 0x0003))
1050d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox		return 0;
1060d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
1070d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	if (!handle_errors)
1080d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox		return 1;
1090d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
1100d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	if ((info->errsts ^ info->errsts2) & 0x0003) {
1110d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox		edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
1120d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox		info->errsts = info->errsts2;
1130d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	}
1140d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
1150d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	info->eap >>= PAGE_SHIFT;
1160d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	row = edac_mc_find_csrow_by_page(mci, info->eap);
1170d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
1180d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	if (info->errsts & 0x0002)
1190d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox		edac_mc_handle_ue(mci, info->eap, 0, row, "i82860 UE");
1200d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	else
121e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson		edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row, 0,
122052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson				"i82860 UE");
1230d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
1240d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	return 1;
1250d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox}
1260d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
1270d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Coxstatic void i82860_check(struct mem_ctl_info *mci)
1280d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox{
1290d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	struct i82860_error_info info;
1300d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
131537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson	debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
1320d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	i82860_get_error_info(mci, &info);
1330d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	i82860_process_error_info(mci, &info, 1);
1340d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox}
1350d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
1361318952514d5651c453d89989595a9df3b37267bDoug Thompsonstatic void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
1370d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox{
1380d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	unsigned long last_cumul_size;
139b4e8b37201d647e4b4abb89d57ebdb8c739d5405Dave Jiang	u16 mchcfg_ddim;	/* DRAM Data Integrity Mode 0=none, 2=edac */
1401318952514d5651c453d89989595a9df3b37267bDoug Thompson	u16 value;
1411318952514d5651c453d89989595a9df3b37267bDoug Thompson	u32 cumul_size;
1421318952514d5651c453d89989595a9df3b37267bDoug Thompson	struct csrow_info *csrow;
1431318952514d5651c453d89989595a9df3b37267bDoug Thompson	int index;
1441318952514d5651c453d89989595a9df3b37267bDoug Thompson
1451318952514d5651c453d89989595a9df3b37267bDoug Thompson	pci_read_config_word(pdev, I82860_MCHCFG, &mchcfg_ddim);
1461318952514d5651c453d89989595a9df3b37267bDoug Thompson	mchcfg_ddim = mchcfg_ddim & 0x180;
1471318952514d5651c453d89989595a9df3b37267bDoug Thompson	last_cumul_size = 0;
1481318952514d5651c453d89989595a9df3b37267bDoug Thompson
1491318952514d5651c453d89989595a9df3b37267bDoug Thompson	/* The group row boundary (GRA) reg values are boundary address
1501318952514d5651c453d89989595a9df3b37267bDoug Thompson	 * for each DRAM row with a granularity of 16MB.  GRA regs are
1511318952514d5651c453d89989595a9df3b37267bDoug Thompson	 * cumulative; therefore GRA15 will contain the total memory contained
1521318952514d5651c453d89989595a9df3b37267bDoug Thompson	 * in all eight rows.
1531318952514d5651c453d89989595a9df3b37267bDoug Thompson	 */
1541318952514d5651c453d89989595a9df3b37267bDoug Thompson	for (index = 0; index < mci->nr_csrows; index++) {
1551318952514d5651c453d89989595a9df3b37267bDoug Thompson		csrow = &mci->csrows[index];
1561318952514d5651c453d89989595a9df3b37267bDoug Thompson		pci_read_config_word(pdev, I82860_GBA + index * 2, &value);
1571318952514d5651c453d89989595a9df3b37267bDoug Thompson		cumul_size = (value & I82860_GBA_MASK) <<
158052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson			(I82860_GBA_SHIFT - PAGE_SHIFT);
1591318952514d5651c453d89989595a9df3b37267bDoug Thompson		debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
1601318952514d5651c453d89989595a9df3b37267bDoug Thompson			cumul_size);
1610d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
1621318952514d5651c453d89989595a9df3b37267bDoug Thompson		if (cumul_size == last_cumul_size)
1631318952514d5651c453d89989595a9df3b37267bDoug Thompson			continue;	/* not populated */
1641318952514d5651c453d89989595a9df3b37267bDoug Thompson
1651318952514d5651c453d89989595a9df3b37267bDoug Thompson		csrow->first_page = last_cumul_size;
1661318952514d5651c453d89989595a9df3b37267bDoug Thompson		csrow->last_page = cumul_size - 1;
1671318952514d5651c453d89989595a9df3b37267bDoug Thompson		csrow->nr_pages = cumul_size - last_cumul_size;
1681318952514d5651c453d89989595a9df3b37267bDoug Thompson		last_cumul_size = cumul_size;
1691318952514d5651c453d89989595a9df3b37267bDoug Thompson		csrow->grain = 1 << 12;	/* I82860_EAP has 4KiB reolution */
1701318952514d5651c453d89989595a9df3b37267bDoug Thompson		csrow->mtype = MEM_RMBS;
1711318952514d5651c453d89989595a9df3b37267bDoug Thompson		csrow->dtype = DEV_UNKNOWN;
1721318952514d5651c453d89989595a9df3b37267bDoug Thompson		csrow->edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE;
1731318952514d5651c453d89989595a9df3b37267bDoug Thompson	}
1741318952514d5651c453d89989595a9df3b37267bDoug Thompson}
1751318952514d5651c453d89989595a9df3b37267bDoug Thompson
1761318952514d5651c453d89989595a9df3b37267bDoug Thompsonstatic int i82860_probe1(struct pci_dev *pdev, int dev_idx)
1771318952514d5651c453d89989595a9df3b37267bDoug Thompson{
1781318952514d5651c453d89989595a9df3b37267bDoug Thompson	struct mem_ctl_info *mci;
1791318952514d5651c453d89989595a9df3b37267bDoug Thompson	struct i82860_error_info discard;
1800d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
1810d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	/* RDRAM has channels but these don't map onto the abstractions that
1820d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	   edac uses.
1830d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	   The device groups from the GRA registers seem to map reasonably
1840d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	   well onto the notion of a chip select row.
1850d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	   There are 16 GRA registers and since the name is associated with
1860d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	   the channel and the GRA registers map to physical devices so we are
1870d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	   going to make 1 channel for group.
1880d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	 */
189b8f6f9755248026f21282e25cac49a1af698056cDoug Thompson	mci = edac_mc_alloc(0, 16, 1, 0);
190e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson
1910d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	if (!mci)
1920d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox		return -ENOMEM;
1930d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
194537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson	debugf3("%s(): init mci\n", __func__);
19537f04581abac20444e5b7106c1e1f28bec5b989cDoug Thompson	mci->dev = &pdev->dev;
1960d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	mci->mtype_cap = MEM_FLAG_DDR;
1970d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
1980d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	/* I"m not sure about this but I think that all RDRAM is SECDED */
1990d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	mci->edac_cap = EDAC_FLAG_SECDED;
200680cbbbb0e336b04b74be48b8ddd870537f1e226Dave Peterson	mci->mod_name = EDAC_MOD_STR;
20137f04581abac20444e5b7106c1e1f28bec5b989cDoug Thompson	mci->mod_ver = I82860_REVISION;
2020d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	mci->ctl_name = i82860_devs[dev_idx].ctl_name;
203c4192705fec85219086231a1c0fa61e8776e2c3bDave Jiang	mci->dev_name = pci_name(pdev);
2040d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	mci->edac_check = i82860_check;
2050d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	mci->ctl_page_to_phys = NULL;
2061318952514d5651c453d89989595a9df3b37267bDoug Thompson	i82860_init_csrows(mci, pdev);
207b4e8b37201d647e4b4abb89d57ebdb8c739d5405Dave Jiang	i82860_get_error_info(mci, &discard);	/* clear counters */
2080d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
2092d7bbb91c8df26c60d223205a087507430024177Doug Thompson	/* Here we assume that we will never see multiple instances of this
2102d7bbb91c8df26c60d223205a087507430024177Doug Thompson	 * type of memory controller.  The ID is therefore hardcoded to 0.
2112d7bbb91c8df26c60d223205a087507430024177Doug Thompson	 */
212b8f6f9755248026f21282e25cac49a1af698056cDoug Thompson	if (edac_mc_add_mc(mci)) {
213537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
2141318952514d5651c453d89989595a9df3b37267bDoug Thompson		goto fail;
2150d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	}
216e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson
217456a2f9552e7849475f4aea1a9aa4c0e54b3dddaDave Jiang	/* allocating generic PCI control info */
218456a2f9552e7849475f4aea1a9aa4c0e54b3dddaDave Jiang	i82860_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
219456a2f9552e7849475f4aea1a9aa4c0e54b3dddaDave Jiang	if (!i82860_pci) {
220456a2f9552e7849475f4aea1a9aa4c0e54b3dddaDave Jiang		printk(KERN_WARNING
221456a2f9552e7849475f4aea1a9aa4c0e54b3dddaDave Jiang			"%s(): Unable to create PCI control\n",
222456a2f9552e7849475f4aea1a9aa4c0e54b3dddaDave Jiang			__func__);
223456a2f9552e7849475f4aea1a9aa4c0e54b3dddaDave Jiang		printk(KERN_WARNING
224456a2f9552e7849475f4aea1a9aa4c0e54b3dddaDave Jiang			"%s(): PCI error report via EDAC not setup\n",
225456a2f9552e7849475f4aea1a9aa4c0e54b3dddaDave Jiang			__func__);
226456a2f9552e7849475f4aea1a9aa4c0e54b3dddaDave Jiang	}
227456a2f9552e7849475f4aea1a9aa4c0e54b3dddaDave Jiang
2281318952514d5651c453d89989595a9df3b37267bDoug Thompson	/* get this far and it's successful */
2291318952514d5651c453d89989595a9df3b37267bDoug Thompson	debugf3("%s(): success\n", __func__);
2301318952514d5651c453d89989595a9df3b37267bDoug Thompson
2311318952514d5651c453d89989595a9df3b37267bDoug Thompson	return 0;
2321318952514d5651c453d89989595a9df3b37267bDoug Thompson
233052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompsonfail:
2341318952514d5651c453d89989595a9df3b37267bDoug Thompson	edac_mc_free(mci);
2351318952514d5651c453d89989595a9df3b37267bDoug Thompson	return -ENODEV;
2360d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox}
2370d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
2380d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox/* returns count (>= 0), or negative on error */
2390d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Coxstatic int __devinit i82860_init_one(struct pci_dev *pdev,
240052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson				const struct pci_device_id *ent)
2410d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox{
2420d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	int rc;
2430d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
244537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson	debugf0("%s()\n", __func__);
245537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson	i82860_printk(KERN_INFO, "i82860 init one\n");
246e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson
247e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson	if (pci_enable_device(pdev) < 0)
2480d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox		return -EIO;
249e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson
2500d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	rc = i82860_probe1(pdev, ent->driver_data);
251e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson
252e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson	if (rc == 0)
2530d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox		mci_pdev = pci_dev_get(pdev);
254e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson
2550d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	return rc;
2560d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox}
2570d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
2580d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Coxstatic void __devexit i82860_remove_one(struct pci_dev *pdev)
2590d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox{
2600d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	struct mem_ctl_info *mci;
2610d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
262537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson	debugf0("%s()\n", __func__);
2630d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
264456a2f9552e7849475f4aea1a9aa4c0e54b3dddaDave Jiang	if (i82860_pci)
265456a2f9552e7849475f4aea1a9aa4c0e54b3dddaDave Jiang		edac_pci_release_generic_ctl(i82860_pci);
266456a2f9552e7849475f4aea1a9aa4c0e54b3dddaDave Jiang
26737f04581abac20444e5b7106c1e1f28bec5b989cDoug Thompson	if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
26818dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson		return;
26918dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson
27018dbc337af5d6efd30cb9291e74722c8ad134fd3Dave Peterson	edac_mc_free(mci);
2710d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox}
2720d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
27336c46f31df910b092aaaed27c7c616bb8e2302a1Lionel Debrouxstatic DEFINE_PCI_DEVICE_TABLE(i82860_pci_tbl) = {
274e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson	{
275b4e8b37201d647e4b4abb89d57ebdb8c739d5405Dave Jiang	 PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
276b4e8b37201d647e4b4abb89d57ebdb8c739d5405Dave Jiang	 I82860},
277e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson	{
278b4e8b37201d647e4b4abb89d57ebdb8c739d5405Dave Jiang	 0,
279b4e8b37201d647e4b4abb89d57ebdb8c739d5405Dave Jiang	 }			/* 0 terminated list. */
2800d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox};
2810d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
2820d88a10e566d46bffc214c974e5cf5abe38d8da8Alan CoxMODULE_DEVICE_TABLE(pci, i82860_pci_tbl);
2830d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
2840d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Coxstatic struct pci_driver i82860_driver = {
285680cbbbb0e336b04b74be48b8ddd870537f1e226Dave Peterson	.name = EDAC_MOD_STR,
2860d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	.probe = i82860_init_one,
2870d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	.remove = __devexit_p(i82860_remove_one),
2880d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	.id_table = i82860_pci_tbl,
2890d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox};
2900d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
291da9bb1d27b21cb24cbb6a2efb5d3c464d357a01eAlan Coxstatic int __init i82860_init(void)
2920d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox{
2930d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	int pci_rc;
2940d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
295537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson	debugf3("%s()\n", __func__);
296e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson
297c3c52bce6993c6d37af2c2de9b482a7013d646a7Hitoshi Mitake       /* Ensure that the OPSTATE is set correctly for POLL or NMI */
298c3c52bce6993c6d37af2c2de9b482a7013d646a7Hitoshi Mitake       opstate_init();
299c3c52bce6993c6d37af2c2de9b482a7013d646a7Hitoshi Mitake
3000d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	if ((pci_rc = pci_register_driver(&i82860_driver)) < 0)
301e8a491b401dbbc5af9fe6483dc558d76343bfbb3Dave Peterson		goto fail0;
3020d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
3030d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	if (!mci_pdev) {
3040d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox		mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
305052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson					PCI_DEVICE_ID_INTEL_82860_0, NULL);
306e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson
3070d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox		if (mci_pdev == NULL) {
3080d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox			debugf0("860 pci_get_device fail\n");
309e8a491b401dbbc5af9fe6483dc558d76343bfbb3Dave Peterson			pci_rc = -ENODEV;
310e8a491b401dbbc5af9fe6483dc558d76343bfbb3Dave Peterson			goto fail1;
3110d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox		}
312e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson
3130d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox		pci_rc = i82860_init_one(mci_pdev, i82860_pci_tbl);
314e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson
3150d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox		if (pci_rc < 0) {
3160d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox			debugf0("860 init fail\n");
317e8a491b401dbbc5af9fe6483dc558d76343bfbb3Dave Peterson			pci_rc = -ENODEV;
318e8a491b401dbbc5af9fe6483dc558d76343bfbb3Dave Peterson			goto fail1;
3190d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox		}
3200d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	}
321e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave Peterson
3220d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	return 0;
323e8a491b401dbbc5af9fe6483dc558d76343bfbb3Dave Peterson
324052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompsonfail1:
325e8a491b401dbbc5af9fe6483dc558d76343bfbb3Dave Peterson	pci_unregister_driver(&i82860_driver);
326e8a491b401dbbc5af9fe6483dc558d76343bfbb3Dave Peterson
327052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompsonfail0:
328e8a491b401dbbc5af9fe6483dc558d76343bfbb3Dave Peterson	if (mci_pdev != NULL)
329e8a491b401dbbc5af9fe6483dc558d76343bfbb3Dave Peterson		pci_dev_put(mci_pdev);
330e8a491b401dbbc5af9fe6483dc558d76343bfbb3Dave Peterson
331e8a491b401dbbc5af9fe6483dc558d76343bfbb3Dave Peterson	return pci_rc;
3320d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox}
3330d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
3340d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Coxstatic void __exit i82860_exit(void)
3350d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox{
336537fba28928c01b7db1580627450691a4bb0b9b3Dave Peterson	debugf3("%s()\n", __func__);
3370d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
3380d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox	pci_unregister_driver(&i82860_driver);
339e8a491b401dbbc5af9fe6483dc558d76343bfbb3Dave Peterson
340e8a491b401dbbc5af9fe6483dc558d76343bfbb3Dave Peterson	if (mci_pdev != NULL)
3410d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox		pci_dev_put(mci_pdev);
3420d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox}
3430d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
3440d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Coxmodule_init(i82860_init);
3450d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Coxmodule_exit(i82860_exit);
3460d88a10e566d46bffc214c974e5cf5abe38d8da8Alan Cox
3470d88a10e566d46bffc214c974e5cf5abe38d8da8Alan CoxMODULE_LICENSE("GPL");
348e7ecd8910293564d357dbaf18eb179e06fa35fd0Dave PetersonMODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) "
349052dfb45ccb5ea354a426b52556bcfee75b9d2f5Douglas Thompson		"Ben Woodard <woodard@redhat.com>");
3500d88a10e566d46bffc214c974e5cf5abe38d8da8Alan CoxMODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers");
351c3c52bce6993c6d37af2c2de9b482a7013d646a7Hitoshi Mitake
352c3c52bce6993c6d37af2c2de9b482a7013d646a7Hitoshi Mitakemodule_param(edac_op_state, int, 0444);
353c3c52bce6993c6d37af2c2de9b482a7013d646a7Hitoshi MitakeMODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
354