1697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao/* 2697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * amd8111_edac.c, AMD8111 Hyper Transport chip EDAC kernel module 3697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * 4697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * Copyright (c) 2008 Wind River Systems, Inc. 5697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * 6697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * Authors: Cao Qingtao <qingtao.cao@windriver.com> 7697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * Benjamin Walsh <benjamin.walsh@windriver.com> 8697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * Hu Yongqi <yongqi.hu@windriver.com> 9697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * 10697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * This program is free software; you can redistribute it and/or modify 11697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * it under the terms of the GNU General Public License version 2 as 12697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * published by the Free Software Foundation. 13697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * 14697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * This program is distributed in the hope that it will be useful, 15697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * but WITHOUT ANY WARRANTY; without even the implied warranty of 16697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 17697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * See the GNU General Public License for more details. 18697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * 19697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * You should have received a copy of the GNU General Public License 20697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * along with this program; if not, write to the Free Software 21697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao */ 23697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 24697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao#include <linux/module.h> 25697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao#include <linux/init.h> 26697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao#include <linux/interrupt.h> 27697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao#include <linux/bitops.h> 28697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao#include <linux/edac.h> 29697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao#include <linux/pci_ids.h> 30697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao#include <asm/io.h> 31697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 32697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao#include "edac_core.h" 33697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao#include "edac_module.h" 34697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao#include "amd8111_edac.h" 35697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 36152ba3942276c2a240703669ae4a3099e0a79451Michal Marek#define AMD8111_EDAC_REVISION " Ver: 1.0.0" 37697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao#define AMD8111_EDAC_MOD_STR "amd8111_edac" 38697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 39697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao#define PCI_DEVICE_ID_AMD_8111_PCI 0x7460 40697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 41697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaoenum amd8111_edac_devs { 42697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao LPC_BRIDGE = 0, 43697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao}; 44697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 45697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaoenum amd8111_edac_pcis { 46697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao PCI_BRIDGE = 0, 47697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao}; 48697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 49697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao/* Wrapper functions for accessing PCI configuration space */ 50697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic int edac_pci_read_dword(struct pci_dev *dev, int reg, u32 *val32) 51697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao{ 52697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao int ret; 53697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 54697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao ret = pci_read_config_dword(dev, reg, val32); 55697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (ret != 0) 56697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_ERR AMD8111_EDAC_MOD_STR 57697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao " PCI Access Read Error at 0x%x\n", reg); 58697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 59697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao return ret; 60697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao} 61697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 62697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic void edac_pci_read_byte(struct pci_dev *dev, int reg, u8 *val8) 63697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao{ 64697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao int ret; 65697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 66697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao ret = pci_read_config_byte(dev, reg, val8); 67697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (ret != 0) 68697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_ERR AMD8111_EDAC_MOD_STR 69697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao " PCI Access Read Error at 0x%x\n", reg); 70697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao} 71697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 72697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic void edac_pci_write_dword(struct pci_dev *dev, int reg, u32 val32) 73697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao{ 74697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao int ret; 75697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 76697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao ret = pci_write_config_dword(dev, reg, val32); 77697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (ret != 0) 78697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_ERR AMD8111_EDAC_MOD_STR 79697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao " PCI Access Write Error at 0x%x\n", reg); 80697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao} 81697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 82697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic void edac_pci_write_byte(struct pci_dev *dev, int reg, u8 val8) 83697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao{ 84697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao int ret; 85697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 86697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao ret = pci_write_config_byte(dev, reg, val8); 87697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (ret != 0) 88697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_ERR AMD8111_EDAC_MOD_STR 89697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao " PCI Access Write Error at 0x%x\n", reg); 90697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao} 91697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 92697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao/* 93697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * device-specific methods for amd8111 PCI Bridge Controller 94697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * 95697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * Error Reporting and Handling for amd8111 chipset could be found 96697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * in its datasheet 3.1.2 section, P37 97697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao */ 98697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic void amd8111_pci_bridge_init(struct amd8111_pci_info *pci_info) 99697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao{ 100697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao u32 val32; 101697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao struct pci_dev *dev = pci_info->dev; 102697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 103697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* First clear error detection flags on the host interface */ 104697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 105697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* Clear SSE/SMA/STA flags in the global status register*/ 106697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32); 107697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (val32 & PCI_STSCMD_CLEAR_MASK) 108697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_write_dword(dev, REG_PCI_STSCMD, val32); 109697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 110697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* Clear CRC and Link Fail flags in HT Link Control reg */ 111697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_read_dword(dev, REG_HT_LINK, &val32); 112697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (val32 & HT_LINK_CLEAR_MASK) 113697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_write_dword(dev, REG_HT_LINK, val32); 114697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 115697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* Second clear all fault on the secondary interface */ 116697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 117697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* Clear error flags in the memory-base limit reg. */ 118697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_read_dword(dev, REG_MEM_LIM, &val32); 119697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (val32 & MEM_LIMIT_CLEAR_MASK) 120697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_write_dword(dev, REG_MEM_LIM, val32); 121697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 122697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* Clear Discard Timer Expired flag in Interrupt/Bridge Control reg */ 123697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32); 124697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (val32 & PCI_INTBRG_CTRL_CLEAR_MASK) 125697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32); 126697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 127697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* Last enable error detections */ 128697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (edac_op_state == EDAC_OPSTATE_POLL) { 129697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* Enable System Error reporting in global status register */ 130697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32); 131697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao val32 |= PCI_STSCMD_SERREN; 132697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_write_dword(dev, REG_PCI_STSCMD, val32); 133697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 134697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* Enable CRC Sync flood packets to HyperTransport Link */ 135697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_read_dword(dev, REG_HT_LINK, &val32); 136697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao val32 |= HT_LINK_CRCFEN; 137697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_write_dword(dev, REG_HT_LINK, val32); 138697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 139697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* Enable SSE reporting etc in Interrupt control reg */ 140697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32); 141697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao val32 |= PCI_INTBRG_CTRL_POLL_MASK; 142697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32); 143697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 144697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao} 145697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 146697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic void amd8111_pci_bridge_exit(struct amd8111_pci_info *pci_info) 147697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao{ 148697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao u32 val32; 149697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao struct pci_dev *dev = pci_info->dev; 150697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 151697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (edac_op_state == EDAC_OPSTATE_POLL) { 152697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* Disable System Error reporting */ 153697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32); 154697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao val32 &= ~PCI_STSCMD_SERREN; 155697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_write_dword(dev, REG_PCI_STSCMD, val32); 156697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 157697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* Disable CRC flood packets */ 158697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_read_dword(dev, REG_HT_LINK, &val32); 159697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao val32 &= ~HT_LINK_CRCFEN; 160697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_write_dword(dev, REG_HT_LINK, val32); 161697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 162697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* Disable DTSERREN/MARSP/SERREN in Interrupt Control reg */ 163697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32); 164697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao val32 &= ~PCI_INTBRG_CTRL_POLL_MASK; 165697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32); 166697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 167697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao} 168697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 169697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic void amd8111_pci_bridge_check(struct edac_pci_ctl_info *edac_dev) 170697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao{ 171697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao struct amd8111_pci_info *pci_info = edac_dev->pvt_info; 172697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao struct pci_dev *dev = pci_info->dev; 173697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao u32 val32; 174697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 175697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* Check out PCI Bridge Status and Command Register */ 176697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32); 177697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (val32 & PCI_STSCMD_CLEAR_MASK) { 178697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_INFO "Error(s) in PCI bridge status and command" 179697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao "register on device %s\n", pci_info->ctl_name); 180697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_INFO "SSE: %d, RMA: %d, RTA: %d\n", 181697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao (val32 & PCI_STSCMD_SSE) != 0, 182697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao (val32 & PCI_STSCMD_RMA) != 0, 183697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao (val32 & PCI_STSCMD_RTA) != 0); 184697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 185697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao val32 |= PCI_STSCMD_CLEAR_MASK; 186697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_write_dword(dev, REG_PCI_STSCMD, val32); 187697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 188697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); 189697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 190697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 191697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* Check out HyperTransport Link Control Register */ 192697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_read_dword(dev, REG_HT_LINK, &val32); 193697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (val32 & HT_LINK_LKFAIL) { 194697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_INFO "Error(s) in hypertransport link control" 195697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao "register on device %s\n", pci_info->ctl_name); 196697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_INFO "LKFAIL: %d\n", 197697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao (val32 & HT_LINK_LKFAIL) != 0); 198697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 199697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao val32 |= HT_LINK_LKFAIL; 200697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_write_dword(dev, REG_HT_LINK, val32); 201697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 202697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); 203697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 204697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 205697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* Check out PCI Interrupt and Bridge Control Register */ 206697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32); 207697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (val32 & PCI_INTBRG_CTRL_DTSTAT) { 208697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_INFO "Error(s) in PCI interrupt and bridge control" 209697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao "register on device %s\n", pci_info->ctl_name); 210697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_INFO "DTSTAT: %d\n", 211697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao (val32 & PCI_INTBRG_CTRL_DTSTAT) != 0); 212697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 213697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao val32 |= PCI_INTBRG_CTRL_DTSTAT; 214697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32); 215697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 216697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); 217697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 218697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 219697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* Check out PCI Bridge Memory Base-Limit Register */ 220697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_read_dword(dev, REG_MEM_LIM, &val32); 221697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (val32 & MEM_LIMIT_CLEAR_MASK) { 222697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_INFO 223697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao "Error(s) in mem limit register on %s device\n", 224697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_info->ctl_name); 225697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_INFO "DPE: %d, RSE: %d, RMA: %d\n" 226697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao "RTA: %d, STA: %d, MDPE: %d\n", 227697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao (val32 & MEM_LIMIT_DPE) != 0, 228697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao (val32 & MEM_LIMIT_RSE) != 0, 229697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao (val32 & MEM_LIMIT_RMA) != 0, 230697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao (val32 & MEM_LIMIT_RTA) != 0, 231697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao (val32 & MEM_LIMIT_STA) != 0, 232697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao (val32 & MEM_LIMIT_MDPE) != 0); 233697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 234697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao val32 |= MEM_LIMIT_CLEAR_MASK; 235697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_write_dword(dev, REG_MEM_LIM, val32); 236697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 237697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); 238697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 239697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao} 240697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 241697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic struct resource *legacy_io_res; 242697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic int at_compat_reg_broken; 243697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao#define LEGACY_NR_PORTS 1 244697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 245697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao/* device-specific methods for amd8111 LPC Bridge device */ 246697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic void amd8111_lpc_bridge_init(struct amd8111_dev_info *dev_info) 247697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao{ 248697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao u8 val8; 249697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao struct pci_dev *dev = dev_info->dev; 250697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 251697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* First clear REG_AT_COMPAT[SERR, IOCHK] if necessary */ 252697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao legacy_io_res = request_region(REG_AT_COMPAT, LEGACY_NR_PORTS, 253697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao AMD8111_EDAC_MOD_STR); 254697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (!legacy_io_res) 255697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_INFO "%s: failed to request legacy I/O region " 256697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao "start %d, len %d\n", __func__, 257697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao REG_AT_COMPAT, LEGACY_NR_PORTS); 258697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao else { 259697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao val8 = __do_inb(REG_AT_COMPAT); 260697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (val8 == 0xff) { /* buggy port */ 261697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_INFO "%s: port %d is buggy, not supported" 262697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao " by hardware?\n", __func__, REG_AT_COMPAT); 263697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao at_compat_reg_broken = 1; 264697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao release_region(REG_AT_COMPAT, LEGACY_NR_PORTS); 265697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao legacy_io_res = NULL; 266697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } else { 267697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao u8 out8 = 0; 268697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (val8 & AT_COMPAT_SERR) 269697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao out8 = AT_COMPAT_CLRSERR; 270697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (val8 & AT_COMPAT_IOCHK) 271697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao out8 |= AT_COMPAT_CLRIOCHK; 272697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (out8 > 0) 273697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao __do_outb(out8, REG_AT_COMPAT); 274697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 275697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 276697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 277697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* Second clear error flags on LPC bridge */ 278697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8); 279697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (val8 & IO_CTRL_1_CLEAR_MASK) 280697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_write_byte(dev, REG_IO_CTRL_1, val8); 281697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao} 282697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 283697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic void amd8111_lpc_bridge_exit(struct amd8111_dev_info *dev_info) 284697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao{ 285697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (legacy_io_res) 286697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao release_region(REG_AT_COMPAT, LEGACY_NR_PORTS); 287697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao} 288697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 289697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic void amd8111_lpc_bridge_check(struct edac_device_ctl_info *edac_dev) 290697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao{ 291697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao struct amd8111_dev_info *dev_info = edac_dev->pvt_info; 292697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao struct pci_dev *dev = dev_info->dev; 293697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao u8 val8; 294697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 295697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8); 296697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (val8 & IO_CTRL_1_CLEAR_MASK) { 297697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_INFO 298697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao "Error(s) in IO control register on %s device\n", 299697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao dev_info->ctl_name); 300697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_INFO "LPC ERR: %d, PW2LPC: %d\n", 301697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao (val8 & IO_CTRL_1_LPC_ERR) != 0, 302697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao (val8 & IO_CTRL_1_PW2LPC) != 0); 303697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 304697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao val8 |= IO_CTRL_1_CLEAR_MASK; 305697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_write_byte(dev, REG_IO_CTRL_1, val8); 306697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 307697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name); 308697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 309697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 310697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (at_compat_reg_broken == 0) { 311697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao u8 out8 = 0; 312697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao val8 = __do_inb(REG_AT_COMPAT); 313697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (val8 & AT_COMPAT_SERR) 314697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao out8 = AT_COMPAT_CLRSERR; 315697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (val8 & AT_COMPAT_IOCHK) 316697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao out8 |= AT_COMPAT_CLRIOCHK; 317697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (out8 > 0) { 318697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao __do_outb(out8, REG_AT_COMPAT); 319697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_device_handle_ue(edac_dev, 0, 0, 320697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_dev->ctl_name); 321697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 322697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 323697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao} 324697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 325697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao/* General devices represented by edac_device_ctl_info */ 326697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic struct amd8111_dev_info amd8111_devices[] = { 327697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao [LPC_BRIDGE] = { 328697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .err_dev = PCI_DEVICE_ID_AMD_8111_LPC, 329697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .ctl_name = "lpc", 330697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .init = amd8111_lpc_bridge_init, 331697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .exit = amd8111_lpc_bridge_exit, 332697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .check = amd8111_lpc_bridge_check, 333697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao }, 334697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao {0}, 335697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao}; 336697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 337697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao/* PCI controllers represented by edac_pci_ctl_info */ 338697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic struct amd8111_pci_info amd8111_pcis[] = { 339697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao [PCI_BRIDGE] = { 340697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .err_dev = PCI_DEVICE_ID_AMD_8111_PCI, 341697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .ctl_name = "AMD8111_PCI_Controller", 342697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .init = amd8111_pci_bridge_init, 343697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .exit = amd8111_pci_bridge_exit, 344697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .check = amd8111_pci_bridge_check, 345697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao }, 346697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao {0}, 347697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao}; 348697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 349697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic int amd8111_dev_probe(struct pci_dev *dev, 350697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao const struct pci_device_id *id) 351697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao{ 352697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao struct amd8111_dev_info *dev_info = &amd8111_devices[id->driver_data]; 3535576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare int ret = -ENODEV; 354697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 355697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao dev_info->dev = pci_get_device(PCI_VENDOR_ID_AMD, 356697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao dev_info->err_dev, NULL); 357697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 358697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (!dev_info->dev) { 359697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_ERR "EDAC device not found:" 360697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao "vendor %x, device %x, name %s\n", 361697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao PCI_VENDOR_ID_AMD, dev_info->err_dev, 362697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao dev_info->ctl_name); 3635576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare goto err; 364697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 365697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 366697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (pci_enable_device(dev_info->dev)) { 367697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_ERR "failed to enable:" 368697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao "vendor %x, device %x, name %s\n", 369697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao PCI_VENDOR_ID_AMD, dev_info->err_dev, 370697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao dev_info->ctl_name); 3715576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare goto err_dev_put; 372697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 373697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 374697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* 375697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * we do not allocate extra private structure for 376697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * edac_device_ctl_info, but make use of existing 377697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * one instead. 378697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao */ 3791dc9b70d7d48abd8a5c6f83021f38992f3b5a77fHarry Ciao dev_info->edac_idx = edac_device_alloc_index(); 380697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao dev_info->edac_dev = 381697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_device_alloc_ctl_info(0, dev_info->ctl_name, 1, 382697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao NULL, 0, 0, 383697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao NULL, 0, dev_info->edac_idx); 3845576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare if (!dev_info->edac_dev) { 3855576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare ret = -ENOMEM; 3865576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare goto err_dev_put; 3875576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare } 388697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 389697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao dev_info->edac_dev->pvt_info = dev_info; 390697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao dev_info->edac_dev->dev = &dev_info->dev->dev; 391697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao dev_info->edac_dev->mod_name = AMD8111_EDAC_MOD_STR; 392697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao dev_info->edac_dev->ctl_name = dev_info->ctl_name; 39356ec0c7b88c6eb17733e5015f31302f6312511edHarry Ciao dev_info->edac_dev->dev_name = dev_name(&dev_info->dev->dev); 394697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 395697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (edac_op_state == EDAC_OPSTATE_POLL) 396697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao dev_info->edac_dev->edac_check = dev_info->check; 397697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 398697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (dev_info->init) 399697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao dev_info->init(dev_info); 400697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 401697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (edac_device_add_device(dev_info->edac_dev) > 0) { 402697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_ERR "failed to add edac_dev for %s\n", 403697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao dev_info->ctl_name); 4045576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare goto err_edac_free_ctl; 405697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 406697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 407697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_INFO "added one edac_dev on AMD8111 " 408697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao "vendor %x, device %x, name %s\n", 409697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao PCI_VENDOR_ID_AMD, dev_info->err_dev, 410697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao dev_info->ctl_name); 411697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 412697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao return 0; 4135576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare 4145576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvareerr_edac_free_ctl: 4155576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare edac_device_free_ctl_info(dev_info->edac_dev); 4165576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvareerr_dev_put: 4175576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare pci_dev_put(dev_info->dev); 4185576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvareerr: 4195576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare return ret; 420697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao} 421697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 422697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic void amd8111_dev_remove(struct pci_dev *dev) 423697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao{ 424697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao struct amd8111_dev_info *dev_info; 425697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 426697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao for (dev_info = amd8111_devices; dev_info->err_dev; dev_info++) 427697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (dev_info->dev->device == dev->device) 428697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao break; 429697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 430697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (!dev_info->err_dev) /* should never happen */ 431697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao return; 432697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 433697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (dev_info->edac_dev) { 434697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_device_del_device(dev_info->edac_dev->dev); 435697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_device_free_ctl_info(dev_info->edac_dev); 436697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 437697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 438697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (dev_info->exit) 439697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao dev_info->exit(dev_info); 440697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 441697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_dev_put(dev_info->dev); 442697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao} 443697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 444697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic int amd8111_pci_probe(struct pci_dev *dev, 445697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao const struct pci_device_id *id) 446697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao{ 447697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao struct amd8111_pci_info *pci_info = &amd8111_pcis[id->driver_data]; 4485576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare int ret = -ENODEV; 449697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 450697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_info->dev = pci_get_device(PCI_VENDOR_ID_AMD, 451697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_info->err_dev, NULL); 452697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 453697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (!pci_info->dev) { 454697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_ERR "EDAC device not found:" 455697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao "vendor %x, device %x, name %s\n", 456697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao PCI_VENDOR_ID_AMD, pci_info->err_dev, 457697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_info->ctl_name); 4585576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare goto err; 459697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 460697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 461697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (pci_enable_device(pci_info->dev)) { 462697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_ERR "failed to enable:" 463697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao "vendor %x, device %x, name %s\n", 464697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao PCI_VENDOR_ID_AMD, pci_info->err_dev, 465697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_info->ctl_name); 4665576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare goto err_dev_put; 467697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 468697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 469697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* 470697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * we do not allocate extra private structure for 471697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * edac_pci_ctl_info, but make use of existing 472697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao * one instead. 473697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao */ 474697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_info->edac_idx = edac_pci_alloc_index(); 475697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_info->edac_dev = edac_pci_alloc_ctl_info(0, pci_info->ctl_name); 4765576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare if (!pci_info->edac_dev) { 4775576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare ret = -ENOMEM; 4785576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare goto err_dev_put; 4795576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare } 480697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 481697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_info->edac_dev->pvt_info = pci_info; 482697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_info->edac_dev->dev = &pci_info->dev->dev; 483697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_info->edac_dev->mod_name = AMD8111_EDAC_MOD_STR; 484697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_info->edac_dev->ctl_name = pci_info->ctl_name; 48556ec0c7b88c6eb17733e5015f31302f6312511edHarry Ciao pci_info->edac_dev->dev_name = dev_name(&pci_info->dev->dev); 486697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 487697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (edac_op_state == EDAC_OPSTATE_POLL) 488697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_info->edac_dev->edac_check = pci_info->check; 489697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 490697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (pci_info->init) 491697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_info->init(pci_info); 492697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 493697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (edac_pci_add_device(pci_info->edac_dev, pci_info->edac_idx) > 0) { 494697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_ERR "failed to add edac_pci for %s\n", 495697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_info->ctl_name); 4965576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare goto err_edac_free_ctl; 497697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 498697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 499697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_INFO "added one edac_pci on AMD8111 " 500697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao "vendor %x, device %x, name %s\n", 501697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao PCI_VENDOR_ID_AMD, pci_info->err_dev, 502697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_info->ctl_name); 503697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 504697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao return 0; 5055576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare 5065576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvareerr_edac_free_ctl: 5075576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare edac_pci_free_ctl_info(pci_info->edac_dev); 5085576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvareerr_dev_put: 5095576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare pci_dev_put(pci_info->dev); 5105576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvareerr: 5115576fb8696bf8d8ae60278c2aa4dc23eae9eb86eJean Delvare return ret; 512697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao} 513697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 514697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic void amd8111_pci_remove(struct pci_dev *dev) 515697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao{ 516697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao struct amd8111_pci_info *pci_info; 517697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 518697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao for (pci_info = amd8111_pcis; pci_info->err_dev; pci_info++) 519697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (pci_info->dev->device == dev->device) 520697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao break; 521697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 522697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (!pci_info->err_dev) /* should never happen */ 523697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao return; 524697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 525697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (pci_info->edac_dev) { 526697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_del_device(pci_info->edac_dev->dev); 527697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_pci_free_ctl_info(pci_info->edac_dev); 528697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } 529697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 530697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao if (pci_info->exit) 531697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_info->exit(pci_info); 532697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 533697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_dev_put(pci_info->dev); 534697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao} 535697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 536697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao/* PCI Device ID talbe for general EDAC device */ 537697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic const struct pci_device_id amd8111_edac_dev_tbl[] = { 538697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao { 539697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao PCI_VEND_DEV(AMD, 8111_LPC), 540697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .subvendor = PCI_ANY_ID, 541697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .subdevice = PCI_ANY_ID, 542697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .class = 0, 543697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .class_mask = 0, 544697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .driver_data = LPC_BRIDGE, 545697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao }, 546697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao { 547697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 0, 548697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } /* table is NULL-terminated */ 549697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao}; 550697dab6484fad0e636b0677c010b15cc449d1b9bHarry CiaoMODULE_DEVICE_TABLE(pci, amd8111_edac_dev_tbl); 551697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 552697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic struct pci_driver amd8111_edac_dev_driver = { 553697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .name = "AMD8111_EDAC_DEV", 554697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .probe = amd8111_dev_probe, 555697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .remove = amd8111_dev_remove, 556697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .id_table = amd8111_edac_dev_tbl, 557697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao}; 558697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 559697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao/* PCI Device ID table for EDAC PCI controller */ 560697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic const struct pci_device_id amd8111_edac_pci_tbl[] = { 561697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao { 562697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao PCI_VEND_DEV(AMD, 8111_PCI), 563697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .subvendor = PCI_ANY_ID, 564697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .subdevice = PCI_ANY_ID, 565697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .class = 0, 566697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .class_mask = 0, 567697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .driver_data = PCI_BRIDGE, 568697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao }, 569697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao { 570697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 0, 571697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao } /* table is NULL-terminated */ 572697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao}; 573697dab6484fad0e636b0677c010b15cc449d1b9bHarry CiaoMODULE_DEVICE_TABLE(pci, amd8111_edac_pci_tbl); 574697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 575697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic struct pci_driver amd8111_edac_pci_driver = { 576697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .name = "AMD8111_EDAC_PCI", 577697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .probe = amd8111_pci_probe, 578697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .remove = amd8111_pci_remove, 579697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao .id_table = amd8111_edac_pci_tbl, 580697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao}; 581697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 582697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic int __init amd8111_edac_init(void) 583697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao{ 584697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao int val; 585697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 586697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_INFO "AMD8111 EDAC driver " AMD8111_EDAC_REVISION "\n"); 587697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc.\n"); 588697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 589697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao /* Only POLL mode supported so far */ 590697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao edac_op_state = EDAC_OPSTATE_POLL; 591697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 592697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao val = pci_register_driver(&amd8111_edac_dev_driver); 593697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao val |= pci_register_driver(&amd8111_edac_pci_driver); 594697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 595697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao return val; 596697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao} 597697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 598697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaostatic void __exit amd8111_edac_exit(void) 599697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao{ 600697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_unregister_driver(&amd8111_edac_pci_driver); 601697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao pci_unregister_driver(&amd8111_edac_dev_driver); 602697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao} 603697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 604697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 605697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaomodule_init(amd8111_edac_init); 606697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciaomodule_exit(amd8111_edac_exit); 607697dab6484fad0e636b0677c010b15cc449d1b9bHarry Ciao 608697dab6484fad0e636b0677c010b15cc449d1b9bHarry CiaoMODULE_LICENSE("GPL"); 609697dab6484fad0e636b0677c010b15cc449d1b9bHarry CiaoMODULE_AUTHOR("Cao Qingtao <qingtao.cao@windriver.com>\n"); 610697dab6484fad0e636b0677c010b15cc449d1b9bHarry CiaoMODULE_DESCRIPTION("AMD8111 HyperTransport I/O Hub EDAC kernel module"); 611