18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * amd8131_edac.c, AMD8131 hypertransport chip EDAC kernel module 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2008 Wind River Systems, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: Cao Qingtao <qingtao.cao@windriver.com> 88c2ecf20Sopenharmony_ci * Benjamin Walsh <benjamin.walsh@windriver.com> 98c2ecf20Sopenharmony_ci * Hu Yongqi <yongqi.hu@windriver.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 158c2ecf20Sopenharmony_ci#include <linux/io.h> 168c2ecf20Sopenharmony_ci#include <linux/bitops.h> 178c2ecf20Sopenharmony_ci#include <linux/edac.h> 188c2ecf20Sopenharmony_ci#include <linux/pci_ids.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "edac_module.h" 218c2ecf20Sopenharmony_ci#include "amd8131_edac.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define AMD8131_EDAC_REVISION " Ver: 1.0.0" 248c2ecf20Sopenharmony_ci#define AMD8131_EDAC_MOD_STR "amd8131_edac" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* Wrapper functions for accessing PCI configuration space */ 278c2ecf20Sopenharmony_cistatic void edac_pci_read_dword(struct pci_dev *dev, int reg, u32 *val32) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci int ret; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci ret = pci_read_config_dword(dev, reg, val32); 328c2ecf20Sopenharmony_ci if (ret != 0) 338c2ecf20Sopenharmony_ci printk(KERN_ERR AMD8131_EDAC_MOD_STR 348c2ecf20Sopenharmony_ci " PCI Access Read Error at 0x%x\n", reg); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic void edac_pci_write_dword(struct pci_dev *dev, int reg, u32 val32) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci int ret; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci ret = pci_write_config_dword(dev, reg, val32); 428c2ecf20Sopenharmony_ci if (ret != 0) 438c2ecf20Sopenharmony_ci printk(KERN_ERR AMD8131_EDAC_MOD_STR 448c2ecf20Sopenharmony_ci " PCI Access Write Error at 0x%x\n", reg); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* Support up to two AMD8131 chipsets on a platform */ 488c2ecf20Sopenharmony_cistatic struct amd8131_dev_info amd8131_devices[] = { 498c2ecf20Sopenharmony_ci { 508c2ecf20Sopenharmony_ci .inst = NORTH_A, 518c2ecf20Sopenharmony_ci .devfn = DEVFN_PCIX_BRIDGE_NORTH_A, 528c2ecf20Sopenharmony_ci .ctl_name = "AMD8131_PCIX_NORTH_A", 538c2ecf20Sopenharmony_ci }, 548c2ecf20Sopenharmony_ci { 558c2ecf20Sopenharmony_ci .inst = NORTH_B, 568c2ecf20Sopenharmony_ci .devfn = DEVFN_PCIX_BRIDGE_NORTH_B, 578c2ecf20Sopenharmony_ci .ctl_name = "AMD8131_PCIX_NORTH_B", 588c2ecf20Sopenharmony_ci }, 598c2ecf20Sopenharmony_ci { 608c2ecf20Sopenharmony_ci .inst = SOUTH_A, 618c2ecf20Sopenharmony_ci .devfn = DEVFN_PCIX_BRIDGE_SOUTH_A, 628c2ecf20Sopenharmony_ci .ctl_name = "AMD8131_PCIX_SOUTH_A", 638c2ecf20Sopenharmony_ci }, 648c2ecf20Sopenharmony_ci { 658c2ecf20Sopenharmony_ci .inst = SOUTH_B, 668c2ecf20Sopenharmony_ci .devfn = DEVFN_PCIX_BRIDGE_SOUTH_B, 678c2ecf20Sopenharmony_ci .ctl_name = "AMD8131_PCIX_SOUTH_B", 688c2ecf20Sopenharmony_ci }, 698c2ecf20Sopenharmony_ci {.inst = NO_BRIDGE,}, 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void amd8131_pcix_init(struct amd8131_dev_info *dev_info) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci u32 val32; 758c2ecf20Sopenharmony_ci struct pci_dev *dev = dev_info->dev; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* First clear error detection flags */ 788c2ecf20Sopenharmony_ci edac_pci_read_dword(dev, REG_MEM_LIM, &val32); 798c2ecf20Sopenharmony_ci if (val32 & MEM_LIMIT_MASK) 808c2ecf20Sopenharmony_ci edac_pci_write_dword(dev, REG_MEM_LIM, val32); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* Clear Discard Timer Timedout flag */ 838c2ecf20Sopenharmony_ci edac_pci_read_dword(dev, REG_INT_CTLR, &val32); 848c2ecf20Sopenharmony_ci if (val32 & INT_CTLR_DTS) 858c2ecf20Sopenharmony_ci edac_pci_write_dword(dev, REG_INT_CTLR, val32); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* Clear CRC Error flag on link side A */ 888c2ecf20Sopenharmony_ci edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32); 898c2ecf20Sopenharmony_ci if (val32 & LNK_CTRL_CRCERR_A) 908c2ecf20Sopenharmony_ci edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci /* Clear CRC Error flag on link side B */ 938c2ecf20Sopenharmony_ci edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32); 948c2ecf20Sopenharmony_ci if (val32 & LNK_CTRL_CRCERR_B) 958c2ecf20Sopenharmony_ci edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* 988c2ecf20Sopenharmony_ci * Then enable all error detections. 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * Setup Discard Timer Sync Flood Enable, 1018c2ecf20Sopenharmony_ci * System Error Enable and Parity Error Enable. 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_ci edac_pci_read_dword(dev, REG_INT_CTLR, &val32); 1048c2ecf20Sopenharmony_ci val32 |= INT_CTLR_PERR | INT_CTLR_SERR | INT_CTLR_DTSE; 1058c2ecf20Sopenharmony_ci edac_pci_write_dword(dev, REG_INT_CTLR, val32); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* Enable overall SERR Error detection */ 1088c2ecf20Sopenharmony_ci edac_pci_read_dword(dev, REG_STS_CMD, &val32); 1098c2ecf20Sopenharmony_ci val32 |= STS_CMD_SERREN; 1108c2ecf20Sopenharmony_ci edac_pci_write_dword(dev, REG_STS_CMD, val32); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* Setup CRC Flood Enable for link side A */ 1138c2ecf20Sopenharmony_ci edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32); 1148c2ecf20Sopenharmony_ci val32 |= LNK_CTRL_CRCFEN; 1158c2ecf20Sopenharmony_ci edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* Setup CRC Flood Enable for link side B */ 1188c2ecf20Sopenharmony_ci edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32); 1198c2ecf20Sopenharmony_ci val32 |= LNK_CTRL_CRCFEN; 1208c2ecf20Sopenharmony_ci edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic void amd8131_pcix_exit(struct amd8131_dev_info *dev_info) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci u32 val32; 1268c2ecf20Sopenharmony_ci struct pci_dev *dev = dev_info->dev; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci /* Disable SERR, PERR and DTSE Error detection */ 1298c2ecf20Sopenharmony_ci edac_pci_read_dword(dev, REG_INT_CTLR, &val32); 1308c2ecf20Sopenharmony_ci val32 &= ~(INT_CTLR_PERR | INT_CTLR_SERR | INT_CTLR_DTSE); 1318c2ecf20Sopenharmony_ci edac_pci_write_dword(dev, REG_INT_CTLR, val32); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* Disable overall System Error detection */ 1348c2ecf20Sopenharmony_ci edac_pci_read_dword(dev, REG_STS_CMD, &val32); 1358c2ecf20Sopenharmony_ci val32 &= ~STS_CMD_SERREN; 1368c2ecf20Sopenharmony_ci edac_pci_write_dword(dev, REG_STS_CMD, val32); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* Disable CRC Sync Flood on link side A */ 1398c2ecf20Sopenharmony_ci edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32); 1408c2ecf20Sopenharmony_ci val32 &= ~LNK_CTRL_CRCFEN; 1418c2ecf20Sopenharmony_ci edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* Disable CRC Sync Flood on link side B */ 1448c2ecf20Sopenharmony_ci edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32); 1458c2ecf20Sopenharmony_ci val32 &= ~LNK_CTRL_CRCFEN; 1468c2ecf20Sopenharmony_ci edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32); 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic void amd8131_pcix_check(struct edac_pci_ctl_info *edac_dev) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct amd8131_dev_info *dev_info = edac_dev->pvt_info; 1528c2ecf20Sopenharmony_ci struct pci_dev *dev = dev_info->dev; 1538c2ecf20Sopenharmony_ci u32 val32; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* Check PCI-X Bridge Memory Base-Limit Register for errors */ 1568c2ecf20Sopenharmony_ci edac_pci_read_dword(dev, REG_MEM_LIM, &val32); 1578c2ecf20Sopenharmony_ci if (val32 & MEM_LIMIT_MASK) { 1588c2ecf20Sopenharmony_ci printk(KERN_INFO "Error(s) in mem limit register " 1598c2ecf20Sopenharmony_ci "on %s bridge\n", dev_info->ctl_name); 1608c2ecf20Sopenharmony_ci printk(KERN_INFO "DPE: %d, RSE: %d, RMA: %d\n" 1618c2ecf20Sopenharmony_ci "RTA: %d, STA: %d, MDPE: %d\n", 1628c2ecf20Sopenharmony_ci val32 & MEM_LIMIT_DPE, 1638c2ecf20Sopenharmony_ci val32 & MEM_LIMIT_RSE, 1648c2ecf20Sopenharmony_ci val32 & MEM_LIMIT_RMA, 1658c2ecf20Sopenharmony_ci val32 & MEM_LIMIT_RTA, 1668c2ecf20Sopenharmony_ci val32 & MEM_LIMIT_STA, 1678c2ecf20Sopenharmony_ci val32 & MEM_LIMIT_MDPE); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci val32 |= MEM_LIMIT_MASK; 1708c2ecf20Sopenharmony_ci edac_pci_write_dword(dev, REG_MEM_LIM, val32); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* Check if Discard Timer timed out */ 1768c2ecf20Sopenharmony_ci edac_pci_read_dword(dev, REG_INT_CTLR, &val32); 1778c2ecf20Sopenharmony_ci if (val32 & INT_CTLR_DTS) { 1788c2ecf20Sopenharmony_ci printk(KERN_INFO "Error(s) in interrupt and control register " 1798c2ecf20Sopenharmony_ci "on %s bridge\n", dev_info->ctl_name); 1808c2ecf20Sopenharmony_ci printk(KERN_INFO "DTS: %d\n", val32 & INT_CTLR_DTS); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci val32 |= INT_CTLR_DTS; 1838c2ecf20Sopenharmony_ci edac_pci_write_dword(dev, REG_INT_CTLR, val32); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* Check if CRC error happens on link side A */ 1898c2ecf20Sopenharmony_ci edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32); 1908c2ecf20Sopenharmony_ci if (val32 & LNK_CTRL_CRCERR_A) { 1918c2ecf20Sopenharmony_ci printk(KERN_INFO "Error(s) in link conf and control register " 1928c2ecf20Sopenharmony_ci "on %s bridge\n", dev_info->ctl_name); 1938c2ecf20Sopenharmony_ci printk(KERN_INFO "CRCERR: %d\n", val32 & LNK_CTRL_CRCERR_A); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci val32 |= LNK_CTRL_CRCERR_A; 1968c2ecf20Sopenharmony_ci edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* Check if CRC error happens on link side B */ 2028c2ecf20Sopenharmony_ci edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32); 2038c2ecf20Sopenharmony_ci if (val32 & LNK_CTRL_CRCERR_B) { 2048c2ecf20Sopenharmony_ci printk(KERN_INFO "Error(s) in link conf and control register " 2058c2ecf20Sopenharmony_ci "on %s bridge\n", dev_info->ctl_name); 2068c2ecf20Sopenharmony_ci printk(KERN_INFO "CRCERR: %d\n", val32 & LNK_CTRL_CRCERR_B); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci val32 |= LNK_CTRL_CRCERR_B; 2098c2ecf20Sopenharmony_ci edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic struct amd8131_info amd8131_chipset = { 2168c2ecf20Sopenharmony_ci .err_dev = PCI_DEVICE_ID_AMD_8131_APIC, 2178c2ecf20Sopenharmony_ci .devices = amd8131_devices, 2188c2ecf20Sopenharmony_ci .init = amd8131_pcix_init, 2198c2ecf20Sopenharmony_ci .exit = amd8131_pcix_exit, 2208c2ecf20Sopenharmony_ci .check = amd8131_pcix_check, 2218c2ecf20Sopenharmony_ci}; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/* 2248c2ecf20Sopenharmony_ci * There are 4 PCIX Bridges on ATCA-6101 that share the same PCI Device ID, 2258c2ecf20Sopenharmony_ci * so amd8131_probe() would be called by kernel 4 times, with different 2268c2ecf20Sopenharmony_ci * address of pci_dev for each of them each time. 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_cistatic int amd8131_probe(struct pci_dev *dev, const struct pci_device_id *id) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct amd8131_dev_info *dev_info; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci for (dev_info = amd8131_chipset.devices; dev_info->inst != NO_BRIDGE; 2338c2ecf20Sopenharmony_ci dev_info++) 2348c2ecf20Sopenharmony_ci if (dev_info->devfn == dev->devfn) 2358c2ecf20Sopenharmony_ci break; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (dev_info->inst == NO_BRIDGE) /* should never happen */ 2388c2ecf20Sopenharmony_ci return -ENODEV; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* 2418c2ecf20Sopenharmony_ci * We can't call pci_get_device() as we are used to do because 2428c2ecf20Sopenharmony_ci * there are 4 of them but pci_dev_get() instead. 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_ci dev_info->dev = pci_dev_get(dev); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (pci_enable_device(dev_info->dev)) { 2478c2ecf20Sopenharmony_ci pci_dev_put(dev_info->dev); 2488c2ecf20Sopenharmony_ci printk(KERN_ERR "failed to enable:" 2498c2ecf20Sopenharmony_ci "vendor %x, device %x, devfn %x, name %s\n", 2508c2ecf20Sopenharmony_ci PCI_VENDOR_ID_AMD, amd8131_chipset.err_dev, 2518c2ecf20Sopenharmony_ci dev_info->devfn, dev_info->ctl_name); 2528c2ecf20Sopenharmony_ci return -ENODEV; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* 2568c2ecf20Sopenharmony_ci * we do not allocate extra private structure for 2578c2ecf20Sopenharmony_ci * edac_pci_ctl_info, but make use of existing 2588c2ecf20Sopenharmony_ci * one instead. 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ci dev_info->edac_idx = edac_pci_alloc_index(); 2618c2ecf20Sopenharmony_ci dev_info->edac_dev = edac_pci_alloc_ctl_info(0, dev_info->ctl_name); 2628c2ecf20Sopenharmony_ci if (!dev_info->edac_dev) 2638c2ecf20Sopenharmony_ci return -ENOMEM; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci dev_info->edac_dev->pvt_info = dev_info; 2668c2ecf20Sopenharmony_ci dev_info->edac_dev->dev = &dev_info->dev->dev; 2678c2ecf20Sopenharmony_ci dev_info->edac_dev->mod_name = AMD8131_EDAC_MOD_STR; 2688c2ecf20Sopenharmony_ci dev_info->edac_dev->ctl_name = dev_info->ctl_name; 2698c2ecf20Sopenharmony_ci dev_info->edac_dev->dev_name = dev_name(&dev_info->dev->dev); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (edac_op_state == EDAC_OPSTATE_POLL) 2728c2ecf20Sopenharmony_ci dev_info->edac_dev->edac_check = amd8131_chipset.check; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (amd8131_chipset.init) 2758c2ecf20Sopenharmony_ci amd8131_chipset.init(dev_info); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (edac_pci_add_device(dev_info->edac_dev, dev_info->edac_idx) > 0) { 2788c2ecf20Sopenharmony_ci printk(KERN_ERR "failed edac_pci_add_device() for %s\n", 2798c2ecf20Sopenharmony_ci dev_info->ctl_name); 2808c2ecf20Sopenharmony_ci edac_pci_free_ctl_info(dev_info->edac_dev); 2818c2ecf20Sopenharmony_ci return -ENODEV; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci printk(KERN_INFO "added one device on AMD8131 " 2858c2ecf20Sopenharmony_ci "vendor %x, device %x, devfn %x, name %s\n", 2868c2ecf20Sopenharmony_ci PCI_VENDOR_ID_AMD, amd8131_chipset.err_dev, 2878c2ecf20Sopenharmony_ci dev_info->devfn, dev_info->ctl_name); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return 0; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic void amd8131_remove(struct pci_dev *dev) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct amd8131_dev_info *dev_info; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci for (dev_info = amd8131_chipset.devices; dev_info->inst != NO_BRIDGE; 2978c2ecf20Sopenharmony_ci dev_info++) 2988c2ecf20Sopenharmony_ci if (dev_info->devfn == dev->devfn) 2998c2ecf20Sopenharmony_ci break; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (dev_info->inst == NO_BRIDGE) /* should never happen */ 3028c2ecf20Sopenharmony_ci return; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (dev_info->edac_dev) { 3058c2ecf20Sopenharmony_ci edac_pci_del_device(dev_info->edac_dev->dev); 3068c2ecf20Sopenharmony_ci edac_pci_free_ctl_info(dev_info->edac_dev); 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (amd8131_chipset.exit) 3108c2ecf20Sopenharmony_ci amd8131_chipset.exit(dev_info); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci pci_dev_put(dev_info->dev); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic const struct pci_device_id amd8131_edac_pci_tbl[] = { 3168c2ecf20Sopenharmony_ci { 3178c2ecf20Sopenharmony_ci PCI_VEND_DEV(AMD, 8131_BRIDGE), 3188c2ecf20Sopenharmony_ci .subvendor = PCI_ANY_ID, 3198c2ecf20Sopenharmony_ci .subdevice = PCI_ANY_ID, 3208c2ecf20Sopenharmony_ci .class = 0, 3218c2ecf20Sopenharmony_ci .class_mask = 0, 3228c2ecf20Sopenharmony_ci .driver_data = 0, 3238c2ecf20Sopenharmony_ci }, 3248c2ecf20Sopenharmony_ci { 3258c2ecf20Sopenharmony_ci 0, 3268c2ecf20Sopenharmony_ci } /* table is NULL-terminated */ 3278c2ecf20Sopenharmony_ci}; 3288c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, amd8131_edac_pci_tbl); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic struct pci_driver amd8131_edac_driver = { 3318c2ecf20Sopenharmony_ci .name = AMD8131_EDAC_MOD_STR, 3328c2ecf20Sopenharmony_ci .probe = amd8131_probe, 3338c2ecf20Sopenharmony_ci .remove = amd8131_remove, 3348c2ecf20Sopenharmony_ci .id_table = amd8131_edac_pci_tbl, 3358c2ecf20Sopenharmony_ci}; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic int __init amd8131_edac_init(void) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci printk(KERN_INFO "AMD8131 EDAC driver " AMD8131_EDAC_REVISION "\n"); 3408c2ecf20Sopenharmony_ci printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc.\n"); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* Only POLL mode supported so far */ 3438c2ecf20Sopenharmony_ci edac_op_state = EDAC_OPSTATE_POLL; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci return pci_register_driver(&amd8131_edac_driver); 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic void __exit amd8131_edac_exit(void) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci pci_unregister_driver(&amd8131_edac_driver); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cimodule_init(amd8131_edac_init); 3548c2ecf20Sopenharmony_cimodule_exit(amd8131_edac_exit); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3578c2ecf20Sopenharmony_ciMODULE_AUTHOR("Cao Qingtao <qingtao.cao@windriver.com>\n"); 3588c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AMD8131 HyperTransport PCI-X Tunnel EDAC kernel module"); 359