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