Commit 28d16272b12e086664a8ca30d5877274a5f944b8

Authored by Harry Ciao
Committed by Linus Torvalds
1 parent a35a281880

edac: AMD8131 driver source file

Introduce AMD8131 EDAC driver source file, which makes use of error
detections on the PCI-X Bridge Controllers on the AMD8131 HyperTransport
PCI-X Tunnel.

Signed-off-by: Harry Ciao <qingtao.cao@windriver.com>
Cc: Doug Thompson <norsk5@yahoo.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 1 changed file with 379 additions and 0 deletions Side-by-side Diff

drivers/edac/amd8131_edac.c
  1 +/*
  2 + * amd8131_edac.c, AMD8131 hypertransport chip EDAC kernel module
  3 + *
  4 + * Copyright (c) 2008 Wind River Systems, Inc.
  5 + *
  6 + * Authors: Cao Qingtao <qingtao.cao@windriver.com>
  7 + * Benjamin Walsh <benjamin.walsh@windriver.com>
  8 + * Hu Yongqi <yongqi.hu@windriver.com>
  9 + *
  10 + * This program is free software; you can redistribute it and/or modify
  11 + * it under the terms of the GNU General Public License version 2 as
  12 + * published by the Free Software Foundation.
  13 + *
  14 + * This program is distributed in the hope that it will be useful,
  15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17 + * See the GNU General Public License for more details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program; if not, write to the Free Software
  21 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  22 + */
  23 +
  24 +#include <linux/module.h>
  25 +#include <linux/init.h>
  26 +#include <linux/interrupt.h>
  27 +#include <linux/io.h>
  28 +#include <linux/bitops.h>
  29 +#include <linux/edac.h>
  30 +#include <linux/pci_ids.h>
  31 +
  32 +#include "edac_core.h"
  33 +#include "edac_module.h"
  34 +#include "amd8131_edac.h"
  35 +
  36 +#define AMD8131_EDAC_REVISION " Ver: 1.0.0 " __DATE__
  37 +#define AMD8131_EDAC_MOD_STR "amd8131_edac"
  38 +
  39 +/* Wrapper functions for accessing PCI configuration space */
  40 +static void edac_pci_read_dword(struct pci_dev *dev, int reg, u32 *val32)
  41 +{
  42 + int ret;
  43 +
  44 + ret = pci_read_config_dword(dev, reg, val32);
  45 + if (ret != 0)
  46 + printk(KERN_ERR AMD8131_EDAC_MOD_STR
  47 + " PCI Access Read Error at 0x%x\n", reg);
  48 +}
  49 +
  50 +static void edac_pci_write_dword(struct pci_dev *dev, int reg, u32 val32)
  51 +{
  52 + int ret;
  53 +
  54 + ret = pci_write_config_dword(dev, reg, val32);
  55 + if (ret != 0)
  56 + printk(KERN_ERR AMD8131_EDAC_MOD_STR
  57 + " PCI Access Write Error at 0x%x\n", reg);
  58 +}
  59 +
  60 +static char * const bridge_str[] = {
  61 + [NORTH_A] = "NORTH A",
  62 + [NORTH_B] = "NORTH B",
  63 + [SOUTH_A] = "SOUTH A",
  64 + [SOUTH_B] = "SOUTH B",
  65 + [NO_BRIDGE] = "NO BRIDGE",
  66 +};
  67 +
  68 +/* Support up to two AMD8131 chipsets on a platform */
  69 +static struct amd8131_dev_info amd8131_devices[] = {
  70 + {
  71 + .inst = NORTH_A,
  72 + .devfn = DEVFN_PCIX_BRIDGE_NORTH_A,
  73 + .ctl_name = "AMD8131_PCIX_NORTH_A",
  74 + },
  75 + {
  76 + .inst = NORTH_B,
  77 + .devfn = DEVFN_PCIX_BRIDGE_NORTH_B,
  78 + .ctl_name = "AMD8131_PCIX_NORTH_B",
  79 + },
  80 + {
  81 + .inst = SOUTH_A,
  82 + .devfn = DEVFN_PCIX_BRIDGE_SOUTH_A,
  83 + .ctl_name = "AMD8131_PCIX_SOUTH_A",
  84 + },
  85 + {
  86 + .inst = SOUTH_B,
  87 + .devfn = DEVFN_PCIX_BRIDGE_SOUTH_B,
  88 + .ctl_name = "AMD8131_PCIX_SOUTH_B",
  89 + },
  90 + {.inst = NO_BRIDGE,},
  91 +};
  92 +
  93 +static void amd8131_pcix_init(struct amd8131_dev_info *dev_info)
  94 +{
  95 + u32 val32;
  96 + struct pci_dev *dev = dev_info->dev;
  97 +
  98 + /* First clear error detection flags */
  99 + edac_pci_read_dword(dev, REG_MEM_LIM, &val32);
  100 + if (val32 & MEM_LIMIT_MASK)
  101 + edac_pci_write_dword(dev, REG_MEM_LIM, val32);
  102 +
  103 + /* Clear Discard Timer Timedout flag */
  104 + edac_pci_read_dword(dev, REG_INT_CTLR, &val32);
  105 + if (val32 & INT_CTLR_DTS)
  106 + edac_pci_write_dword(dev, REG_INT_CTLR, val32);
  107 +
  108 + /* Clear CRC Error flag on link side A */
  109 + edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32);
  110 + if (val32 & LNK_CTRL_CRCERR_A)
  111 + edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32);
  112 +
  113 + /* Clear CRC Error flag on link side B */
  114 + edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32);
  115 + if (val32 & LNK_CTRL_CRCERR_B)
  116 + edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32);
  117 +
  118 + /*
  119 + * Then enable all error detections.
  120 + *
  121 + * Setup Discard Timer Sync Flood Enable,
  122 + * System Error Enable and Parity Error Enable.
  123 + */
  124 + edac_pci_read_dword(dev, REG_INT_CTLR, &val32);
  125 + val32 |= INT_CTLR_PERR | INT_CTLR_SERR | INT_CTLR_DTSE;
  126 + edac_pci_write_dword(dev, REG_INT_CTLR, val32);
  127 +
  128 + /* Enable overall SERR Error detection */
  129 + edac_pci_read_dword(dev, REG_STS_CMD, &val32);
  130 + val32 |= STS_CMD_SERREN;
  131 + edac_pci_write_dword(dev, REG_STS_CMD, val32);
  132 +
  133 + /* Setup CRC Flood Enable for link side A */
  134 + edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32);
  135 + val32 |= LNK_CTRL_CRCFEN;
  136 + edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32);
  137 +
  138 + /* Setup CRC Flood Enable for link side B */
  139 + edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32);
  140 + val32 |= LNK_CTRL_CRCFEN;
  141 + edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32);
  142 +}
  143 +
  144 +static void amd8131_pcix_exit(struct amd8131_dev_info *dev_info)
  145 +{
  146 + u32 val32;
  147 + struct pci_dev *dev = dev_info->dev;
  148 +
  149 + /* Disable SERR, PERR and DTSE Error detection */
  150 + edac_pci_read_dword(dev, REG_INT_CTLR, &val32);
  151 + val32 &= ~(INT_CTLR_PERR | INT_CTLR_SERR | INT_CTLR_DTSE);
  152 + edac_pci_write_dword(dev, REG_INT_CTLR, val32);
  153 +
  154 + /* Disable overall System Error detection */
  155 + edac_pci_read_dword(dev, REG_STS_CMD, &val32);
  156 + val32 &= ~STS_CMD_SERREN;
  157 + edac_pci_write_dword(dev, REG_STS_CMD, val32);
  158 +
  159 + /* Disable CRC Sync Flood on link side A */
  160 + edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32);
  161 + val32 &= ~LNK_CTRL_CRCFEN;
  162 + edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32);
  163 +
  164 + /* Disable CRC Sync Flood on link side B */
  165 + edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32);
  166 + val32 &= ~LNK_CTRL_CRCFEN;
  167 + edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32);
  168 +}
  169 +
  170 +static void amd8131_pcix_check(struct edac_pci_ctl_info *edac_dev)
  171 +{
  172 + struct amd8131_dev_info *dev_info = edac_dev->pvt_info;
  173 + struct pci_dev *dev = dev_info->dev;
  174 + u32 val32;
  175 +
  176 + /* Check PCI-X Bridge Memory Base-Limit Register for errors */
  177 + edac_pci_read_dword(dev, REG_MEM_LIM, &val32);
  178 + if (val32 & MEM_LIMIT_MASK) {
  179 + printk(KERN_INFO "Error(s) in mem limit register "
  180 + "on %s bridge\n", dev_info->ctl_name);
  181 + printk(KERN_INFO "DPE: %d, RSE: %d, RMA: %d\n"
  182 + "RTA: %d, STA: %d, MDPE: %d\n",
  183 + val32 & MEM_LIMIT_DPE,
  184 + val32 & MEM_LIMIT_RSE,
  185 + val32 & MEM_LIMIT_RMA,
  186 + val32 & MEM_LIMIT_RTA,
  187 + val32 & MEM_LIMIT_STA,
  188 + val32 & MEM_LIMIT_MDPE);
  189 +
  190 + val32 |= MEM_LIMIT_MASK;
  191 + edac_pci_write_dword(dev, REG_MEM_LIM, val32);
  192 +
  193 + edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
  194 + }
  195 +
  196 + /* Check if Discard Timer timed out */
  197 + edac_pci_read_dword(dev, REG_INT_CTLR, &val32);
  198 + if (val32 & INT_CTLR_DTS) {
  199 + printk(KERN_INFO "Error(s) in interrupt and control register "
  200 + "on %s bridge\n", dev_info->ctl_name);
  201 + printk(KERN_INFO "DTS: %d\n", val32 & INT_CTLR_DTS);
  202 +
  203 + val32 |= INT_CTLR_DTS;
  204 + edac_pci_write_dword(dev, REG_INT_CTLR, val32);
  205 +
  206 + edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
  207 + }
  208 +
  209 + /* Check if CRC error happens on link side A */
  210 + edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32);
  211 + if (val32 & LNK_CTRL_CRCERR_A) {
  212 + printk(KERN_INFO "Error(s) in link conf and control register "
  213 + "on %s bridge\n", dev_info->ctl_name);
  214 + printk(KERN_INFO "CRCERR: %d\n", val32 & LNK_CTRL_CRCERR_A);
  215 +
  216 + val32 |= LNK_CTRL_CRCERR_A;
  217 + edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32);
  218 +
  219 + edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
  220 + }
  221 +
  222 + /* Check if CRC error happens on link side B */
  223 + edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32);
  224 + if (val32 & LNK_CTRL_CRCERR_B) {
  225 + printk(KERN_INFO "Error(s) in link conf and control register "
  226 + "on %s bridge\n", dev_info->ctl_name);
  227 + printk(KERN_INFO "CRCERR: %d\n", val32 & LNK_CTRL_CRCERR_B);
  228 +
  229 + val32 |= LNK_CTRL_CRCERR_B;
  230 + edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32);
  231 +
  232 + edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
  233 + }
  234 +}
  235 +
  236 +static struct amd8131_info amd8131_chipset = {
  237 + .err_dev = PCI_DEVICE_ID_AMD_8131_APIC,
  238 + .devices = amd8131_devices,
  239 + .init = amd8131_pcix_init,
  240 + .exit = amd8131_pcix_exit,
  241 + .check = amd8131_pcix_check,
  242 +};
  243 +
  244 +/*
  245 + * There are 4 PCIX Bridges on ATCA-6101 that share the same PCI Device ID,
  246 + * so amd8131_probe() would be called by kernel 4 times, with different
  247 + * address of pci_dev for each of them each time.
  248 + */
  249 +static int amd8131_probe(struct pci_dev *dev, const struct pci_device_id *id)
  250 +{
  251 + struct amd8131_dev_info *dev_info;
  252 +
  253 + for (dev_info = amd8131_chipset.devices; dev_info->inst != NO_BRIDGE;
  254 + dev_info++)
  255 + if (dev_info->devfn == dev->devfn)
  256 + break;
  257 +
  258 + if (dev_info->inst == NO_BRIDGE) /* should never happen */
  259 + return -ENODEV;
  260 +
  261 + /*
  262 + * We can't call pci_get_device() as we are used to do because
  263 + * there are 4 of them but pci_dev_get() instead.
  264 + */
  265 + dev_info->dev = pci_dev_get(dev);
  266 +
  267 + if (pci_enable_device(dev_info->dev)) {
  268 + pci_dev_put(dev_info->dev);
  269 + printk(KERN_ERR "failed to enable:"
  270 + "vendor %x, device %x, devfn %x, name %s\n",
  271 + PCI_VENDOR_ID_AMD, amd8131_chipset.err_dev,
  272 + dev_info->devfn, dev_info->ctl_name);
  273 + return -ENODEV;
  274 + }
  275 +
  276 + /*
  277 + * we do not allocate extra private structure for
  278 + * edac_pci_ctl_info, but make use of existing
  279 + * one instead.
  280 + */
  281 + dev_info->edac_idx = edac_pci_alloc_index();
  282 + dev_info->edac_dev = edac_pci_alloc_ctl_info(0, dev_info->ctl_name);
  283 + if (!dev_info->edac_dev)
  284 + return -ENOMEM;
  285 +
  286 + dev_info->edac_dev->pvt_info = dev_info;
  287 + dev_info->edac_dev->dev = &dev_info->dev->dev;
  288 + dev_info->edac_dev->mod_name = AMD8131_EDAC_MOD_STR;
  289 + dev_info->edac_dev->ctl_name = dev_info->ctl_name;
  290 + dev_info->edac_dev->dev_name = dev_info->dev->dev.bus_id;
  291 +
  292 + if (edac_op_state == EDAC_OPSTATE_POLL)
  293 + dev_info->edac_dev->edac_check = amd8131_chipset.check;
  294 +
  295 + if (amd8131_chipset.init)
  296 + amd8131_chipset.init(dev_info);
  297 +
  298 + if (edac_pci_add_device(dev_info->edac_dev, dev_info->edac_idx) > 0) {
  299 + printk(KERN_ERR "failed edac_pci_add_device() for %s\n",
  300 + dev_info->ctl_name);
  301 + edac_pci_free_ctl_info(dev_info->edac_dev);
  302 + return -ENODEV;
  303 + }
  304 +
  305 + printk(KERN_INFO "added one device on AMD8131 "
  306 + "vendor %x, device %x, devfn %x, name %s\n",
  307 + PCI_VENDOR_ID_AMD, amd8131_chipset.err_dev,
  308 + dev_info->devfn, dev_info->ctl_name);
  309 +
  310 + return 0;
  311 +}
  312 +
  313 +static void amd8131_remove(struct pci_dev *dev)
  314 +{
  315 + struct amd8131_dev_info *dev_info;
  316 +
  317 + for (dev_info = amd8131_chipset.devices; dev_info->inst != NO_BRIDGE;
  318 + dev_info++)
  319 + if (dev_info->devfn == dev->devfn)
  320 + break;
  321 +
  322 + if (dev_info->inst == NO_BRIDGE) /* should never happen */
  323 + return;
  324 +
  325 + if (dev_info->edac_dev) {
  326 + edac_pci_del_device(dev_info->edac_dev->dev);
  327 + edac_pci_free_ctl_info(dev_info->edac_dev);
  328 + }
  329 +
  330 + if (amd8131_chipset.exit)
  331 + amd8131_chipset.exit(dev_info);
  332 +
  333 + pci_dev_put(dev_info->dev);
  334 +}
  335 +
  336 +static const struct pci_device_id amd8131_edac_pci_tbl[] = {
  337 + {
  338 + PCI_VEND_DEV(AMD, 8131_BRIDGE),
  339 + .subvendor = PCI_ANY_ID,
  340 + .subdevice = PCI_ANY_ID,
  341 + .class = 0,
  342 + .class_mask = 0,
  343 + .driver_data = 0,
  344 + },
  345 + {
  346 + 0,
  347 + } /* table is NULL-terminated */
  348 +};
  349 +MODULE_DEVICE_TABLE(pci, amd8131_edac_pci_tbl);
  350 +
  351 +static struct pci_driver amd8131_edac_driver = {
  352 + .name = AMD8131_EDAC_MOD_STR,
  353 + .probe = amd8131_probe,
  354 + .remove = amd8131_remove,
  355 + .id_table = amd8131_edac_pci_tbl,
  356 +};
  357 +
  358 +static int __init amd8131_edac_init(void)
  359 +{
  360 + printk(KERN_INFO "AMD8131 EDAC driver " AMD8131_EDAC_REVISION "\n");
  361 + printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc.\n");
  362 +
  363 + /* Only POLL mode supported so far */
  364 + edac_op_state = EDAC_OPSTATE_POLL;
  365 +
  366 + return pci_register_driver(&amd8131_edac_driver);
  367 +}
  368 +
  369 +static void __exit amd8131_edac_exit(void)
  370 +{
  371 + pci_unregister_driver(&amd8131_edac_driver);
  372 +}
  373 +
  374 +module_init(amd8131_edac_init);
  375 +module_exit(amd8131_edac_exit);
  376 +
  377 +MODULE_LICENSE("GPL");
  378 +MODULE_AUTHOR("Cao Qingtao <qingtao.cao@windriver.com>\n");
  379 +MODULE_DESCRIPTION("AMD8131 HyperTransport PCI-X Tunnel EDAC kernel module");