597 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * amd8111_edac.c, AMD8111 Hyper Transport chip EDAC kernel module4 *5 * Copyright (c) 2008 Wind River Systems, Inc.6 *7 * Authors: Cao Qingtao <qingtao.cao@windriver.com>8 * Benjamin Walsh <benjamin.walsh@windriver.com>9 * Hu Yongqi <yongqi.hu@windriver.com>10 */11 12#include <linux/module.h>13#include <linux/init.h>14#include <linux/interrupt.h>15#include <linux/bitops.h>16#include <linux/edac.h>17#include <linux/pci_ids.h>18#include <asm/io.h>19 20#include "edac_module.h"21#include "amd8111_edac.h"22 23#define AMD8111_EDAC_REVISION " Ver: 1.0.0"24#define AMD8111_EDAC_MOD_STR "amd8111_edac"25 26#define PCI_DEVICE_ID_AMD_8111_PCI 0x746027 28enum amd8111_edac_devs {29 LPC_BRIDGE = 0,30};31 32enum amd8111_edac_pcis {33 PCI_BRIDGE = 0,34};35 36/* Wrapper functions for accessing PCI configuration space */37static int edac_pci_read_dword(struct pci_dev *dev, int reg, u32 *val32)38{39 int ret;40 41 ret = pci_read_config_dword(dev, reg, val32);42 if (ret != 0)43 printk(KERN_ERR AMD8111_EDAC_MOD_STR44 " PCI Access Read Error at 0x%x\n", reg);45 46 return ret;47}48 49static void edac_pci_read_byte(struct pci_dev *dev, int reg, u8 *val8)50{51 int ret;52 53 ret = pci_read_config_byte(dev, reg, val8);54 if (ret != 0)55 printk(KERN_ERR AMD8111_EDAC_MOD_STR56 " PCI Access Read Error at 0x%x\n", reg);57}58 59static void edac_pci_write_dword(struct pci_dev *dev, int reg, u32 val32)60{61 int ret;62 63 ret = pci_write_config_dword(dev, reg, val32);64 if (ret != 0)65 printk(KERN_ERR AMD8111_EDAC_MOD_STR66 " PCI Access Write Error at 0x%x\n", reg);67}68 69static void edac_pci_write_byte(struct pci_dev *dev, int reg, u8 val8)70{71 int ret;72 73 ret = pci_write_config_byte(dev, reg, val8);74 if (ret != 0)75 printk(KERN_ERR AMD8111_EDAC_MOD_STR76 " PCI Access Write Error at 0x%x\n", reg);77}78 79/*80 * device-specific methods for amd8111 PCI Bridge Controller81 *82 * Error Reporting and Handling for amd8111 chipset could be found83 * in its datasheet 3.1.2 section, P3784 */85static void amd8111_pci_bridge_init(struct amd8111_pci_info *pci_info)86{87 u32 val32;88 struct pci_dev *dev = pci_info->dev;89 90 /* First clear error detection flags on the host interface */91 92 /* Clear SSE/SMA/STA flags in the global status register*/93 edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);94 if (val32 & PCI_STSCMD_CLEAR_MASK)95 edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);96 97 /* Clear CRC and Link Fail flags in HT Link Control reg */98 edac_pci_read_dword(dev, REG_HT_LINK, &val32);99 if (val32 & HT_LINK_CLEAR_MASK)100 edac_pci_write_dword(dev, REG_HT_LINK, val32);101 102 /* Second clear all fault on the secondary interface */103 104 /* Clear error flags in the memory-base limit reg. */105 edac_pci_read_dword(dev, REG_MEM_LIM, &val32);106 if (val32 & MEM_LIMIT_CLEAR_MASK)107 edac_pci_write_dword(dev, REG_MEM_LIM, val32);108 109 /* Clear Discard Timer Expired flag in Interrupt/Bridge Control reg */110 edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);111 if (val32 & PCI_INTBRG_CTRL_CLEAR_MASK)112 edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);113 114 /* Last enable error detections */115 if (edac_op_state == EDAC_OPSTATE_POLL) {116 /* Enable System Error reporting in global status register */117 edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);118 val32 |= PCI_STSCMD_SERREN;119 edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);120 121 /* Enable CRC Sync flood packets to HyperTransport Link */122 edac_pci_read_dword(dev, REG_HT_LINK, &val32);123 val32 |= HT_LINK_CRCFEN;124 edac_pci_write_dword(dev, REG_HT_LINK, val32);125 126 /* Enable SSE reporting etc in Interrupt control reg */127 edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);128 val32 |= PCI_INTBRG_CTRL_POLL_MASK;129 edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);130 }131}132 133static void amd8111_pci_bridge_exit(struct amd8111_pci_info *pci_info)134{135 u32 val32;136 struct pci_dev *dev = pci_info->dev;137 138 if (edac_op_state == EDAC_OPSTATE_POLL) {139 /* Disable System Error reporting */140 edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);141 val32 &= ~PCI_STSCMD_SERREN;142 edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);143 144 /* Disable CRC flood packets */145 edac_pci_read_dword(dev, REG_HT_LINK, &val32);146 val32 &= ~HT_LINK_CRCFEN;147 edac_pci_write_dword(dev, REG_HT_LINK, val32);148 149 /* Disable DTSERREN/MARSP/SERREN in Interrupt Control reg */150 edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);151 val32 &= ~PCI_INTBRG_CTRL_POLL_MASK;152 edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);153 }154}155 156static void amd8111_pci_bridge_check(struct edac_pci_ctl_info *edac_dev)157{158 struct amd8111_pci_info *pci_info = edac_dev->pvt_info;159 struct pci_dev *dev = pci_info->dev;160 u32 val32;161 162 /* Check out PCI Bridge Status and Command Register */163 edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);164 if (val32 & PCI_STSCMD_CLEAR_MASK) {165 printk(KERN_INFO "Error(s) in PCI bridge status and command"166 "register on device %s\n", pci_info->ctl_name);167 printk(KERN_INFO "SSE: %d, RMA: %d, RTA: %d\n",168 (val32 & PCI_STSCMD_SSE) != 0,169 (val32 & PCI_STSCMD_RMA) != 0,170 (val32 & PCI_STSCMD_RTA) != 0);171 172 val32 |= PCI_STSCMD_CLEAR_MASK;173 edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);174 175 edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);176 }177 178 /* Check out HyperTransport Link Control Register */179 edac_pci_read_dword(dev, REG_HT_LINK, &val32);180 if (val32 & HT_LINK_LKFAIL) {181 printk(KERN_INFO "Error(s) in hypertransport link control"182 "register on device %s\n", pci_info->ctl_name);183 printk(KERN_INFO "LKFAIL: %d\n",184 (val32 & HT_LINK_LKFAIL) != 0);185 186 val32 |= HT_LINK_LKFAIL;187 edac_pci_write_dword(dev, REG_HT_LINK, val32);188 189 edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);190 }191 192 /* Check out PCI Interrupt and Bridge Control Register */193 edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);194 if (val32 & PCI_INTBRG_CTRL_DTSTAT) {195 printk(KERN_INFO "Error(s) in PCI interrupt and bridge control"196 "register on device %s\n", pci_info->ctl_name);197 printk(KERN_INFO "DTSTAT: %d\n",198 (val32 & PCI_INTBRG_CTRL_DTSTAT) != 0);199 200 val32 |= PCI_INTBRG_CTRL_DTSTAT;201 edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);202 203 edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);204 }205 206 /* Check out PCI Bridge Memory Base-Limit Register */207 edac_pci_read_dword(dev, REG_MEM_LIM, &val32);208 if (val32 & MEM_LIMIT_CLEAR_MASK) {209 printk(KERN_INFO210 "Error(s) in mem limit register on %s device\n",211 pci_info->ctl_name);212 printk(KERN_INFO "DPE: %d, RSE: %d, RMA: %d\n"213 "RTA: %d, STA: %d, MDPE: %d\n",214 (val32 & MEM_LIMIT_DPE) != 0,215 (val32 & MEM_LIMIT_RSE) != 0,216 (val32 & MEM_LIMIT_RMA) != 0,217 (val32 & MEM_LIMIT_RTA) != 0,218 (val32 & MEM_LIMIT_STA) != 0,219 (val32 & MEM_LIMIT_MDPE) != 0);220 221 val32 |= MEM_LIMIT_CLEAR_MASK;222 edac_pci_write_dword(dev, REG_MEM_LIM, val32);223 224 edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);225 }226}227 228static struct resource *legacy_io_res;229static int at_compat_reg_broken;230#define LEGACY_NR_PORTS 1231 232/* device-specific methods for amd8111 LPC Bridge device */233static void amd8111_lpc_bridge_init(struct amd8111_dev_info *dev_info)234{235 u8 val8;236 struct pci_dev *dev = dev_info->dev;237 238 /* First clear REG_AT_COMPAT[SERR, IOCHK] if necessary */239 legacy_io_res = request_region(REG_AT_COMPAT, LEGACY_NR_PORTS,240 AMD8111_EDAC_MOD_STR);241 if (!legacy_io_res)242 printk(KERN_INFO "%s: failed to request legacy I/O region "243 "start %d, len %d\n", __func__,244 REG_AT_COMPAT, LEGACY_NR_PORTS);245 else {246 val8 = __do_inb(REG_AT_COMPAT);247 if (val8 == 0xff) { /* buggy port */248 printk(KERN_INFO "%s: port %d is buggy, not supported"249 " by hardware?\n", __func__, REG_AT_COMPAT);250 at_compat_reg_broken = 1;251 release_region(REG_AT_COMPAT, LEGACY_NR_PORTS);252 legacy_io_res = NULL;253 } else {254 u8 out8 = 0;255 if (val8 & AT_COMPAT_SERR)256 out8 = AT_COMPAT_CLRSERR;257 if (val8 & AT_COMPAT_IOCHK)258 out8 |= AT_COMPAT_CLRIOCHK;259 if (out8 > 0)260 __do_outb(out8, REG_AT_COMPAT);261 }262 }263 264 /* Second clear error flags on LPC bridge */265 edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8);266 if (val8 & IO_CTRL_1_CLEAR_MASK)267 edac_pci_write_byte(dev, REG_IO_CTRL_1, val8);268}269 270static void amd8111_lpc_bridge_exit(struct amd8111_dev_info *dev_info)271{272 if (legacy_io_res)273 release_region(REG_AT_COMPAT, LEGACY_NR_PORTS);274}275 276static void amd8111_lpc_bridge_check(struct edac_device_ctl_info *edac_dev)277{278 struct amd8111_dev_info *dev_info = edac_dev->pvt_info;279 struct pci_dev *dev = dev_info->dev;280 u8 val8;281 282 edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8);283 if (val8 & IO_CTRL_1_CLEAR_MASK) {284 printk(KERN_INFO285 "Error(s) in IO control register on %s device\n",286 dev_info->ctl_name);287 printk(KERN_INFO "LPC ERR: %d, PW2LPC: %d\n",288 (val8 & IO_CTRL_1_LPC_ERR) != 0,289 (val8 & IO_CTRL_1_PW2LPC) != 0);290 291 val8 |= IO_CTRL_1_CLEAR_MASK;292 edac_pci_write_byte(dev, REG_IO_CTRL_1, val8);293 294 edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);295 }296 297 if (at_compat_reg_broken == 0) {298 u8 out8 = 0;299 val8 = __do_inb(REG_AT_COMPAT);300 if (val8 & AT_COMPAT_SERR)301 out8 = AT_COMPAT_CLRSERR;302 if (val8 & AT_COMPAT_IOCHK)303 out8 |= AT_COMPAT_CLRIOCHK;304 if (out8 > 0) {305 __do_outb(out8, REG_AT_COMPAT);306 edac_device_handle_ue(edac_dev, 0, 0,307 edac_dev->ctl_name);308 }309 }310}311 312/* General devices represented by edac_device_ctl_info */313static struct amd8111_dev_info amd8111_devices[] = {314 [LPC_BRIDGE] = {315 .err_dev = PCI_DEVICE_ID_AMD_8111_LPC,316 .ctl_name = "lpc",317 .init = amd8111_lpc_bridge_init,318 .exit = amd8111_lpc_bridge_exit,319 .check = amd8111_lpc_bridge_check,320 },321 {0},322};323 324/* PCI controllers represented by edac_pci_ctl_info */325static struct amd8111_pci_info amd8111_pcis[] = {326 [PCI_BRIDGE] = {327 .err_dev = PCI_DEVICE_ID_AMD_8111_PCI,328 .ctl_name = "AMD8111_PCI_Controller",329 .init = amd8111_pci_bridge_init,330 .exit = amd8111_pci_bridge_exit,331 .check = amd8111_pci_bridge_check,332 },333 {0},334};335 336static int amd8111_dev_probe(struct pci_dev *dev,337 const struct pci_device_id *id)338{339 struct amd8111_dev_info *dev_info = &amd8111_devices[id->driver_data];340 int ret = -ENODEV;341 342 dev_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,343 dev_info->err_dev, NULL);344 345 if (!dev_info->dev) {346 printk(KERN_ERR "EDAC device not found:"347 "vendor %x, device %x, name %s\n",348 PCI_VENDOR_ID_AMD, dev_info->err_dev,349 dev_info->ctl_name);350 goto err;351 }352 353 if (pci_enable_device(dev_info->dev)) {354 printk(KERN_ERR "failed to enable:"355 "vendor %x, device %x, name %s\n",356 PCI_VENDOR_ID_AMD, dev_info->err_dev,357 dev_info->ctl_name);358 goto err_dev_put;359 }360 361 /*362 * we do not allocate extra private structure for363 * edac_device_ctl_info, but make use of existing364 * one instead.365 */366 dev_info->edac_idx = edac_device_alloc_index();367 dev_info->edac_dev =368 edac_device_alloc_ctl_info(0, dev_info->ctl_name, 1,369 NULL, 0, 0, dev_info->edac_idx);370 if (!dev_info->edac_dev) {371 ret = -ENOMEM;372 goto err_dev_put;373 }374 375 dev_info->edac_dev->pvt_info = dev_info;376 dev_info->edac_dev->dev = &dev_info->dev->dev;377 dev_info->edac_dev->mod_name = AMD8111_EDAC_MOD_STR;378 dev_info->edac_dev->ctl_name = dev_info->ctl_name;379 dev_info->edac_dev->dev_name = dev_name(&dev_info->dev->dev);380 381 if (edac_op_state == EDAC_OPSTATE_POLL)382 dev_info->edac_dev->edac_check = dev_info->check;383 384 if (dev_info->init)385 dev_info->init(dev_info);386 387 if (edac_device_add_device(dev_info->edac_dev) > 0) {388 printk(KERN_ERR "failed to add edac_dev for %s\n",389 dev_info->ctl_name);390 goto err_edac_free_ctl;391 }392 393 printk(KERN_INFO "added one edac_dev on AMD8111 "394 "vendor %x, device %x, name %s\n",395 PCI_VENDOR_ID_AMD, dev_info->err_dev,396 dev_info->ctl_name);397 398 return 0;399 400err_edac_free_ctl:401 edac_device_free_ctl_info(dev_info->edac_dev);402err_dev_put:403 pci_dev_put(dev_info->dev);404err:405 return ret;406}407 408static void amd8111_dev_remove(struct pci_dev *dev)409{410 struct amd8111_dev_info *dev_info;411 412 for (dev_info = amd8111_devices; dev_info->err_dev; dev_info++)413 if (dev_info->dev->device == dev->device)414 break;415 416 if (!dev_info->err_dev) /* should never happen */417 return;418 419 if (dev_info->edac_dev) {420 edac_device_del_device(dev_info->edac_dev->dev);421 edac_device_free_ctl_info(dev_info->edac_dev);422 }423 424 if (dev_info->exit)425 dev_info->exit(dev_info);426 427 pci_dev_put(dev_info->dev);428}429 430static int amd8111_pci_probe(struct pci_dev *dev,431 const struct pci_device_id *id)432{433 struct amd8111_pci_info *pci_info = &amd8111_pcis[id->driver_data];434 int ret = -ENODEV;435 436 pci_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,437 pci_info->err_dev, NULL);438 439 if (!pci_info->dev) {440 printk(KERN_ERR "EDAC device not found:"441 "vendor %x, device %x, name %s\n",442 PCI_VENDOR_ID_AMD, pci_info->err_dev,443 pci_info->ctl_name);444 goto err;445 }446 447 if (pci_enable_device(pci_info->dev)) {448 printk(KERN_ERR "failed to enable:"449 "vendor %x, device %x, name %s\n",450 PCI_VENDOR_ID_AMD, pci_info->err_dev,451 pci_info->ctl_name);452 goto err_dev_put;453 }454 455 /*456 * we do not allocate extra private structure for457 * edac_pci_ctl_info, but make use of existing458 * one instead.459 */460 pci_info->edac_idx = edac_pci_alloc_index();461 pci_info->edac_dev = edac_pci_alloc_ctl_info(0, pci_info->ctl_name);462 if (!pci_info->edac_dev) {463 ret = -ENOMEM;464 goto err_dev_put;465 }466 467 pci_info->edac_dev->pvt_info = pci_info;468 pci_info->edac_dev->dev = &pci_info->dev->dev;469 pci_info->edac_dev->mod_name = AMD8111_EDAC_MOD_STR;470 pci_info->edac_dev->ctl_name = pci_info->ctl_name;471 pci_info->edac_dev->dev_name = dev_name(&pci_info->dev->dev);472 473 if (edac_op_state == EDAC_OPSTATE_POLL)474 pci_info->edac_dev->edac_check = pci_info->check;475 476 if (pci_info->init)477 pci_info->init(pci_info);478 479 if (edac_pci_add_device(pci_info->edac_dev, pci_info->edac_idx) > 0) {480 printk(KERN_ERR "failed to add edac_pci for %s\n",481 pci_info->ctl_name);482 goto err_edac_free_ctl;483 }484 485 printk(KERN_INFO "added one edac_pci on AMD8111 "486 "vendor %x, device %x, name %s\n",487 PCI_VENDOR_ID_AMD, pci_info->err_dev,488 pci_info->ctl_name);489 490 return 0;491 492err_edac_free_ctl:493 edac_pci_free_ctl_info(pci_info->edac_dev);494err_dev_put:495 pci_dev_put(pci_info->dev);496err:497 return ret;498}499 500static void amd8111_pci_remove(struct pci_dev *dev)501{502 struct amd8111_pci_info *pci_info;503 504 for (pci_info = amd8111_pcis; pci_info->err_dev; pci_info++)505 if (pci_info->dev->device == dev->device)506 break;507 508 if (!pci_info->err_dev) /* should never happen */509 return;510 511 if (pci_info->edac_dev) {512 edac_pci_del_device(pci_info->edac_dev->dev);513 edac_pci_free_ctl_info(pci_info->edac_dev);514 }515 516 if (pci_info->exit)517 pci_info->exit(pci_info);518 519 pci_dev_put(pci_info->dev);520}521 522/* PCI Device ID talbe for general EDAC device */523static const struct pci_device_id amd8111_edac_dev_tbl[] = {524 {525 PCI_VEND_DEV(AMD, 8111_LPC),526 .subvendor = PCI_ANY_ID,527 .subdevice = PCI_ANY_ID,528 .class = 0,529 .class_mask = 0,530 .driver_data = LPC_BRIDGE,531 },532 {533 0,534 } /* table is NULL-terminated */535};536MODULE_DEVICE_TABLE(pci, amd8111_edac_dev_tbl);537 538static struct pci_driver amd8111_edac_dev_driver = {539 .name = "AMD8111_EDAC_DEV",540 .probe = amd8111_dev_probe,541 .remove = amd8111_dev_remove,542 .id_table = amd8111_edac_dev_tbl,543};544 545/* PCI Device ID table for EDAC PCI controller */546static const struct pci_device_id amd8111_edac_pci_tbl[] = {547 {548 PCI_VEND_DEV(AMD, 8111_PCI),549 .subvendor = PCI_ANY_ID,550 .subdevice = PCI_ANY_ID,551 .class = 0,552 .class_mask = 0,553 .driver_data = PCI_BRIDGE,554 },555 {556 0,557 } /* table is NULL-terminated */558};559MODULE_DEVICE_TABLE(pci, amd8111_edac_pci_tbl);560 561static struct pci_driver amd8111_edac_pci_driver = {562 .name = "AMD8111_EDAC_PCI",563 .probe = amd8111_pci_probe,564 .remove = amd8111_pci_remove,565 .id_table = amd8111_edac_pci_tbl,566};567 568static int __init amd8111_edac_init(void)569{570 int val;571 572 printk(KERN_INFO "AMD8111 EDAC driver " AMD8111_EDAC_REVISION "\n");573 printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc.\n");574 575 /* Only POLL mode supported so far */576 edac_op_state = EDAC_OPSTATE_POLL;577 578 val = pci_register_driver(&amd8111_edac_dev_driver);579 val |= pci_register_driver(&amd8111_edac_pci_driver);580 581 return val;582}583 584static void __exit amd8111_edac_exit(void)585{586 pci_unregister_driver(&amd8111_edac_pci_driver);587 pci_unregister_driver(&amd8111_edac_dev_driver);588}589 590 591module_init(amd8111_edac_init);592module_exit(amd8111_edac_exit);593 594MODULE_LICENSE("GPL");595MODULE_AUTHOR("Cao Qingtao <qingtao.cao@windriver.com>");596MODULE_DESCRIPTION("AMD8111 HyperTransport I/O Hub EDAC kernel module");597