cregit-Linux how code gets into the kernel

Release 4.14 drivers/edac/r82600_edac.c

Directory: drivers/edac
/*
 * Radisys 82600 Embedded chipset Memory Controller kernel module
 * (C) 2005 EADS Astrium
 * This file may be distributed under the terms of the
 * GNU General Public License.
 *
 * Written by Tim Small <tim@buttersideup.com>, based on work by Thayne
 * Harbaugh, Dan Hollis <goemon at anime dot net> and others.
 *
 * $Id: edac_r82600.c,v 1.1.2.6 2005/10/05 00:43:44 dsp_llnl Exp $
 *
 * Written with reference to 82600 High Integration Dual PCI System
 * Controller Data Book:
 * www.radisys.com/files/support_downloads/007-01277-0002.82600DataBook.pdf
 * references to this document given in []
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/edac.h>
#include "edac_module.h"


#define EDAC_MOD_STR	"r82600_edac"


#define r82600_printk(level, fmt, arg...) \
	edac_printk(level, "r82600", fmt, ##arg)


#define r82600_mc_printk(mci, level, fmt, arg...) \
	edac_mc_chipset_printk(mci, level, "r82600", fmt, ##arg)

/* Radisys say "The 82600 integrates a main memory SDRAM controller that
 * supports up to four banks of memory. The four banks can support a mix of
 * sizes of 64 bit wide (72 bits with ECC) Synchronous DRAM (SDRAM) DIMMs,
 * each of which can be any size from 16MB to 512MB. Both registered (control
 * signals buffered) and unbuffered DIMM types are supported. Mixing of
 * registered and unbuffered DIMMs as well as mixing of ECC and non-ECC DIMMs
 * is not allowed. The 82600 SDRAM interface operates at the same frequency as
 * the CPU bus, 66MHz, 100MHz or 133MHz."
 */


#define R82600_NR_CSROWS 4

#define R82600_NR_CHANS  1

#define R82600_NR_DIMMS  4


#define R82600_BRIDGE_ID  0x8200

/* Radisys 82600 register addresses - device 0 function 0 - PCI bridge */

#define R82600_DRAMC	0x57	
/* Various SDRAM related control bits
                                 * all bits are R/W
                                 *
                                 * 7    SDRAM ISA Hole Enable
                                 * 6    Flash Page Mode Enable
                                 * 5    ECC Enable: 1=ECC 0=noECC
                                 * 4    DRAM DIMM Type: 1=
                                 * 3    BIOS Alias Disable
                                 * 2    SDRAM BIOS Flash Write Enable
                                 * 1:0  SDRAM Refresh Rate: 00=Disabled
                                 *          01=7.8usec (256Mbit SDRAMs)
                                 *          10=15.6us 11=125usec
                                 */


#define R82600_SDRAMC	0x76	
/* "SDRAM Control Register"
                                 * More SDRAM related control bits
                                 * all bits are R/W
                                 *
                                 * 15:8 Reserved.
                                 *
                                 * 7:5  Special SDRAM Mode Select
                                 *
                                 * 4    Force ECC
                                 *
                                 *        1=Drive ECC bits to 0 during
                                 *          write cycles (i.e. ECC test mode)
                                 *
                                 *        0=Normal ECC functioning
                                 *
                                 * 3    Enhanced Paging Enable
                                 *
                                 * 2    CAS# Latency 0=3clks 1=2clks
                                 *
                                 * 1    RAS# to CAS# Delay 0=3 1=2
                                 *
                                 * 0    RAS# Precharge     0=3 1=2
                                 */


#define R82600_EAP	0x80	
/* ECC Error Address Pointer Register
                                 *
                                 * 31    Disable Hardware Scrubbing (RW)
                                 *        0=Scrub on corrected read
                                 *        1=Don't scrub on corrected read
                                 *
                                 * 30:12 Error Address Pointer (RO)
                                 *        Upper 19 bits of error address
                                 *
                                 * 11:4  Syndrome Bits (RO)
                                 *
                                 * 3     BSERR# on multibit error (RW)
                                 *        1=enable 0=disable
                                 *
                                 * 2     NMI on Single Bit Eror (RW)
                                 *        1=NMI triggered by SBE n.b. other
                                 *          prerequeists
                                 *        0=NMI not triggered
                                 *
                                 * 1     MBE (R/WC)
                                 *        read 1=MBE at EAP (see above)
                                 *        read 0=no MBE, or SBE occurred first
                                 *        write 1=Clear MBE status (must also
                                 *          clear SBE)
                                 *        write 0=NOP
                                 *
                                 * 1     SBE (R/WC)
                                 *        read 1=SBE at EAP (see above)
                                 *        read 0=no SBE, or MBE occurred first
                                 *        write 1=Clear SBE status (must also
                                 *          clear MBE)
                                 *        write 0=NOP
                                 */


#define R82600_DRBA	0x60	
/* + 0x60..0x63 SDRAM Row Boundary Address
                                 *  Registers
                                 *
                                 * 7:0  Address lines 30:24 - upper limit of
                                 * each row [p57]
                                 */


struct r82600_error_info {
	
u32 eapr;
};


static bool disable_hardware_scrub;


static struct edac_pci_ctl_info *r82600_pci;


static void r82600_get_error_info(struct mem_ctl_info *mci, struct r82600_error_info *info) { struct pci_dev *pdev; pdev = to_pci_dev(mci->pdev); pci_read_config_dword(pdev, R82600_EAP, &info->eapr); if (info->eapr & BIT(0)) /* Clear error to allow next error to be reported [p.62] */ pci_write_bits32(pdev, R82600_EAP, ((u32) BIT(0) & (u32) BIT(1)), ((u32) BIT(0) & (u32) BIT(1))); if (info->eapr & BIT(1)) /* Clear error to allow next error to be reported [p.62] */ pci_write_bits32(pdev, R82600_EAP, ((u32) BIT(0) & (u32) BIT(1)), ((u32) BIT(0) & (u32) BIT(1))); }

Contributors

PersonTokensPropCommitsCommitProp
Alan Cox13991.45%133.33%
Doug Thompson127.89%133.33%
Mauro Carvalho Chehab10.66%133.33%
Total152100.00%3100.00%


static int r82600_process_error_info(struct mem_ctl_info *mci, struct r82600_error_info *info, int handle_errors) { int error_found; u32 eapaddr, page; u32 syndrome; error_found = 0; /* bits 30:12 store the upper 19 bits of the 32 bit error address */ eapaddr = ((info->eapr >> 12) & 0x7FFF) << 13; /* Syndrome in bits 11:4 [p.62] */ syndrome = (info->eapr >> 4) & 0xFF; /* the R82600 reports at less than page * * granularity (upper 19 bits only) */ page = eapaddr >> PAGE_SHIFT; if (info->eapr & BIT(0)) { /* CE? */ error_found = 1; if (handle_errors) edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, page, 0, syndrome, edac_mc_find_csrow_by_page(mci, page), 0, -1, mci->ctl_name, ""); } if (info->eapr & BIT(1)) { /* UE? */ error_found = 1; if (handle_errors) /* 82600 doesn't give enough info */ edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, page, 0, 0, edac_mc_find_csrow_by_page(mci, page), 0, -1, mci->ctl_name, ""); } return error_found; }

Contributors

PersonTokensPropCommitsCommitProp
Alan Cox16187.03%133.33%
Mauro Carvalho Chehab2412.97%266.67%
Total185100.00%3100.00%


static void r82600_check(struct mem_ctl_info *mci) { struct r82600_error_info info; edac_dbg(1, "MC%d\n", mci->mc_idx); r82600_get_error_info(mci, &info); r82600_process_error_info(mci, &info, 1); }

Contributors

PersonTokensPropCommitsCommitProp
Alan Cox4090.91%133.33%
Joe Perches36.82%133.33%
Mauro Carvalho Chehab12.27%133.33%
Total44100.00%3100.00%


static inline int ecc_enabled(u8 dramcr) { return dramcr & BIT(5); }

Contributors

PersonTokensPropCommitsCommitProp
Doug Thompson1688.89%150.00%
Alan Cox211.11%150.00%
Total18100.00%2100.00%


static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, u8 dramcr) { struct csrow_info *csrow; struct dimm_info *dimm; int index; u8 drbar; /* SDRAM Row Boundary Address Register */ u32 row_high_limit, row_high_limit_last; u32 reg_sdram, ecc_on, row_base; ecc_on = ecc_enabled(dramcr); reg_sdram = dramcr & BIT(4); row_high_limit_last = 0; for (index = 0; index < mci->nr_csrows; index++) { csrow = mci->csrows[index]; dimm = csrow->channels[0]->dimm; /* find the DRAM Chip Select Base address and mask */ pci_read_config_byte(pdev, R82600_DRBA + index, &drbar); edac_dbg(1, "Row=%d DRBA = %#0x\n", index, drbar); row_high_limit = ((u32) drbar << 24); /* row_high_limit = ((u32)drbar << 24) | 0xffffffUL; */ edac_dbg(1, "Row=%d, Boundary Address=%#0x, Last = %#0x\n", index, row_high_limit, row_high_limit_last); /* Empty row [p.57] */ if (row_high_limit == row_high_limit_last) continue; row_base = row_high_limit_last; csrow->first_page = row_base >> PAGE_SHIFT; csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1; dimm->nr_pages = csrow->last_page - csrow->first_page + 1; /* Error address is top 19 bits - so granularity is * * 14 bits */ dimm->grain = 1 << 14; dimm->mtype = reg_sdram ? MEM_RDDR : MEM_DDR; /* FIXME - check that this is unknowable with this chipset */ dimm->dtype = DEV_UNKNOWN; /* Mode is global on 82600 */ dimm->edac_mode = ecc_on ? EDAC_SECDED : EDAC_NONE; row_high_limit_last = row_high_limit; } }

Contributors

PersonTokensPropCommitsCommitProp
Doug Thompson19279.67%112.50%
Mauro Carvalho Chehab239.54%450.00%
Alan Cox197.88%112.50%
Joe Perches62.49%112.50%
Lucas De Marchi10.41%112.50%
Total241100.00%8100.00%


static int r82600_probe1(struct pci_dev *pdev, int dev_idx) { struct mem_ctl_info *mci; struct edac_mc_layer layers[2]; u8 dramcr; u32 eapr; u32 scrub_disabled; u32 sdram_refresh_rate; struct r82600_error_info discard; edac_dbg(0, "\n"); pci_read_config_byte(pdev, R82600_DRAMC, &dramcr); pci_read_config_dword(pdev, R82600_EAP, &eapr); scrub_disabled = eapr & BIT(31); sdram_refresh_rate = dramcr & (BIT(0) | BIT(1)); edac_dbg(2, "sdram refresh rate = %#0x\n", sdram_refresh_rate); edac_dbg(2, "DRAMC register = %#0x\n", dramcr); layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; layers[0].size = R82600_NR_CSROWS; layers[0].is_virt_csrow = true; layers[1].type = EDAC_MC_LAYER_CHANNEL; layers[1].size = R82600_NR_CHANS; layers[1].is_virt_csrow = false; mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0); if (mci == NULL) return -ENOMEM; edac_dbg(0, "mci = %p\n", mci); mci->pdev = &pdev->dev; mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR; mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; /* FIXME try to work out if the chip leads have been used for COM2 * instead on this board? [MA6?] MAYBE: */ /* On the R82600, the pins for memory bits 72:65 - i.e. the * * EC bits are shared with the pins for COM2 (!), so if COM2 * * is enabled, we assume COM2 is wired up, and thus no EDAC * * is possible. */ mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; if (ecc_enabled(dramcr)) { if (scrub_disabled) edac_dbg(3, "mci = %p - Scrubbing disabled! EAP: %#0x\n", mci, eapr); } else mci->edac_cap = EDAC_FLAG_NONE; mci->mod_name = EDAC_MOD_STR; mci->ctl_name = "R82600"; mci->dev_name = pci_name(pdev); mci->edac_check = r82600_check; mci->ctl_page_to_phys = NULL; r82600_init_csrows(mci, pdev, dramcr); r82600_get_error_info(mci, &discard); /* clear counters */ /* Here we assume that we will never see multiple instances of this * type of memory controller. The ID is therefore hardcoded to 0. */ if (edac_mc_add_mc(mci)) { edac_dbg(3, "failed edac_mc_add_mc()\n"); goto fail; } /* get this far and it's successful */ if (disable_hardware_scrub) { edac_dbg(3, "Disabling Hardware Scrub (scrub on error)\n"); pci_write_bits32(pdev, R82600_EAP, BIT(31), BIT(31)); } /* allocating generic PCI control info */ r82600_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); if (!r82600_pci) { printk(KERN_WARNING "%s(): Unable to create PCI control\n", __func__); printk(KERN_WARNING "%s(): PCI error report via EDAC not setup\n", __func__); } edac_dbg(3, "success\n"); return 0; fail: edac_mc_free(mci); return -ENODEV; }

Contributors

PersonTokensPropCommitsCommitProp
Alan Cox22652.56%16.67%
Mauro Carvalho Chehab7517.44%426.67%
Dave Jiang4510.47%213.33%
Doug Thompson378.60%426.67%
Joe Perches255.81%16.67%
Dave Peterson225.12%320.00%
Total430100.00%15100.00%

/* returns count (>= 0), or negative on error */
static int r82600_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { edac_dbg(0, "\n"); /* don't need to call pci_enable_device() */ return r82600_probe1(pdev, ent->driver_data); }

Contributors

PersonTokensPropCommitsCommitProp
Alan Cox3085.71%125.00%
Joe Perches38.57%125.00%
Mauro Carvalho Chehab12.86%125.00%
Roman Fietze12.86%125.00%
Total35100.00%4100.00%


static void r82600_remove_one(struct pci_dev *pdev) { struct mem_ctl_info *mci; edac_dbg(0, "\n"); if (r82600_pci) edac_pci_release_generic_ctl(r82600_pci); if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) return; edac_mc_free(mci); }

Contributors

PersonTokensPropCommitsCommitProp
Alan Cox3564.81%116.67%
Dave Jiang916.67%116.67%
Joe Perches35.56%116.67%
Doug Thompson35.56%116.67%
Dave Peterson35.56%116.67%
Mauro Carvalho Chehab11.85%116.67%
Total54100.00%6100.00%

static const struct pci_device_id r82600_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID) }, { 0, } /* 0 terminated list. */ }; MODULE_DEVICE_TABLE(pci, r82600_pci_tbl); static struct pci_driver r82600_driver = { .name = EDAC_MOD_STR, .probe = r82600_init_one, .remove = r82600_remove_one, .id_table = r82600_pci_tbl, };
static int __init r82600_init(void) { /* Ensure that the OPSTATE is set correctly for POLL or NMI */ opstate_init(); return pci_register_driver(&r82600_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Alan Cox1680.00%266.67%
Hitoshi Mitake420.00%133.33%
Total20100.00%3100.00%


static void __exit r82600_exit(void) { pci_unregister_driver(&r82600_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Alan Cox15100.00%1100.00%
Total15100.00%1100.00%

module_init(r82600_init); module_exit(r82600_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD Ltd. " "on behalf of EADS Astrium"); MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers"); module_param(disable_hardware_scrub, bool, 0644); MODULE_PARM_DESC(disable_hardware_scrub, "If set, disable the chipset's automatic scrub for CEs"); module_param(edac_op_state, int, 0444); MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");

Overall Contributors

PersonTokensPropCommitsCommitProp
Alan Cox83759.07%26.67%
Doug Thompson26518.70%620.00%
Mauro Carvalho Chehab1278.96%930.00%
Dave Jiang614.30%26.67%
Dave Peterson543.81%516.67%
Joe Perches402.82%13.33%
Hitoshi Mitake231.62%13.33%
Jingoo Han60.42%13.33%
Lucas De Marchi20.14%13.33%
Roman Fietze10.07%13.33%
Rusty Russell10.07%13.33%
Lionel Debroux0.00%00.00%
Total1417100.00%30100.00%
Directory: drivers/edac
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.