162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Radisys 82600 Embedded chipset Memory Controller kernel module
362306a36Sopenharmony_ci * (C) 2005 EADS Astrium
462306a36Sopenharmony_ci * This file may be distributed under the terms of the
562306a36Sopenharmony_ci * GNU General Public License.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Written by Tim Small <tim@buttersideup.com>, based on work by Thayne
862306a36Sopenharmony_ci * Harbaugh, Dan Hollis <goemon at anime dot net> and others.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * $Id: edac_r82600.c,v 1.1.2.6 2005/10/05 00:43:44 dsp_llnl Exp $
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Written with reference to 82600 High Integration Dual PCI System
1362306a36Sopenharmony_ci * Controller Data Book:
1462306a36Sopenharmony_ci * www.radisys.com/files/support_downloads/007-01277-0002.82600DataBook.pdf
1562306a36Sopenharmony_ci * references to this document given in []
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/module.h>
1962306a36Sopenharmony_ci#include <linux/init.h>
2062306a36Sopenharmony_ci#include <linux/pci.h>
2162306a36Sopenharmony_ci#include <linux/pci_ids.h>
2262306a36Sopenharmony_ci#include <linux/edac.h>
2362306a36Sopenharmony_ci#include "edac_module.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define EDAC_MOD_STR	"r82600_edac"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define r82600_printk(level, fmt, arg...) \
2862306a36Sopenharmony_ci	edac_printk(level, "r82600", fmt, ##arg)
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define r82600_mc_printk(mci, level, fmt, arg...) \
3162306a36Sopenharmony_ci	edac_mc_chipset_printk(mci, level, "r82600", fmt, ##arg)
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/* Radisys say "The 82600 integrates a main memory SDRAM controller that
3462306a36Sopenharmony_ci * supports up to four banks of memory. The four banks can support a mix of
3562306a36Sopenharmony_ci * sizes of 64 bit wide (72 bits with ECC) Synchronous DRAM (SDRAM) DIMMs,
3662306a36Sopenharmony_ci * each of which can be any size from 16MB to 512MB. Both registered (control
3762306a36Sopenharmony_ci * signals buffered) and unbuffered DIMM types are supported. Mixing of
3862306a36Sopenharmony_ci * registered and unbuffered DIMMs as well as mixing of ECC and non-ECC DIMMs
3962306a36Sopenharmony_ci * is not allowed. The 82600 SDRAM interface operates at the same frequency as
4062306a36Sopenharmony_ci * the CPU bus, 66MHz, 100MHz or 133MHz."
4162306a36Sopenharmony_ci */
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define R82600_NR_CSROWS 4
4462306a36Sopenharmony_ci#define R82600_NR_CHANS  1
4562306a36Sopenharmony_ci#define R82600_NR_DIMMS  4
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define R82600_BRIDGE_ID  0x8200
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/* Radisys 82600 register addresses - device 0 function 0 - PCI bridge */
5062306a36Sopenharmony_ci#define R82600_DRAMC	0x57	/* Various SDRAM related control bits
5162306a36Sopenharmony_ci				 * all bits are R/W
5262306a36Sopenharmony_ci				 *
5362306a36Sopenharmony_ci				 * 7    SDRAM ISA Hole Enable
5462306a36Sopenharmony_ci				 * 6    Flash Page Mode Enable
5562306a36Sopenharmony_ci				 * 5    ECC Enable: 1=ECC 0=noECC
5662306a36Sopenharmony_ci				 * 4    DRAM DIMM Type: 1=
5762306a36Sopenharmony_ci				 * 3    BIOS Alias Disable
5862306a36Sopenharmony_ci				 * 2    SDRAM BIOS Flash Write Enable
5962306a36Sopenharmony_ci				 * 1:0  SDRAM Refresh Rate: 00=Disabled
6062306a36Sopenharmony_ci				 *          01=7.8usec (256Mbit SDRAMs)
6162306a36Sopenharmony_ci				 *          10=15.6us 11=125usec
6262306a36Sopenharmony_ci				 */
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define R82600_SDRAMC	0x76	/* "SDRAM Control Register"
6562306a36Sopenharmony_ci				 * More SDRAM related control bits
6662306a36Sopenharmony_ci				 * all bits are R/W
6762306a36Sopenharmony_ci				 *
6862306a36Sopenharmony_ci				 * 15:8 Reserved.
6962306a36Sopenharmony_ci				 *
7062306a36Sopenharmony_ci				 * 7:5  Special SDRAM Mode Select
7162306a36Sopenharmony_ci				 *
7262306a36Sopenharmony_ci				 * 4    Force ECC
7362306a36Sopenharmony_ci				 *
7462306a36Sopenharmony_ci				 *        1=Drive ECC bits to 0 during
7562306a36Sopenharmony_ci				 *          write cycles (i.e. ECC test mode)
7662306a36Sopenharmony_ci				 *
7762306a36Sopenharmony_ci				 *        0=Normal ECC functioning
7862306a36Sopenharmony_ci				 *
7962306a36Sopenharmony_ci				 * 3    Enhanced Paging Enable
8062306a36Sopenharmony_ci				 *
8162306a36Sopenharmony_ci				 * 2    CAS# Latency 0=3clks 1=2clks
8262306a36Sopenharmony_ci				 *
8362306a36Sopenharmony_ci				 * 1    RAS# to CAS# Delay 0=3 1=2
8462306a36Sopenharmony_ci				 *
8562306a36Sopenharmony_ci				 * 0    RAS# Precharge     0=3 1=2
8662306a36Sopenharmony_ci				 */
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci#define R82600_EAP	0x80	/* ECC Error Address Pointer Register
8962306a36Sopenharmony_ci				 *
9062306a36Sopenharmony_ci				 * 31    Disable Hardware Scrubbing (RW)
9162306a36Sopenharmony_ci				 *        0=Scrub on corrected read
9262306a36Sopenharmony_ci				 *        1=Don't scrub on corrected read
9362306a36Sopenharmony_ci				 *
9462306a36Sopenharmony_ci				 * 30:12 Error Address Pointer (RO)
9562306a36Sopenharmony_ci				 *        Upper 19 bits of error address
9662306a36Sopenharmony_ci				 *
9762306a36Sopenharmony_ci				 * 11:4  Syndrome Bits (RO)
9862306a36Sopenharmony_ci				 *
9962306a36Sopenharmony_ci				 * 3     BSERR# on multibit error (RW)
10062306a36Sopenharmony_ci				 *        1=enable 0=disable
10162306a36Sopenharmony_ci				 *
10262306a36Sopenharmony_ci				 * 2     NMI on Single Bit Eror (RW)
10362306a36Sopenharmony_ci				 *        1=NMI triggered by SBE n.b. other
10462306a36Sopenharmony_ci				 *          prerequeists
10562306a36Sopenharmony_ci				 *        0=NMI not triggered
10662306a36Sopenharmony_ci				 *
10762306a36Sopenharmony_ci				 * 1     MBE (R/WC)
10862306a36Sopenharmony_ci				 *        read 1=MBE at EAP (see above)
10962306a36Sopenharmony_ci				 *        read 0=no MBE, or SBE occurred first
11062306a36Sopenharmony_ci				 *        write 1=Clear MBE status (must also
11162306a36Sopenharmony_ci				 *          clear SBE)
11262306a36Sopenharmony_ci				 *        write 0=NOP
11362306a36Sopenharmony_ci				 *
11462306a36Sopenharmony_ci				 * 1     SBE (R/WC)
11562306a36Sopenharmony_ci				 *        read 1=SBE at EAP (see above)
11662306a36Sopenharmony_ci				 *        read 0=no SBE, or MBE occurred first
11762306a36Sopenharmony_ci				 *        write 1=Clear SBE status (must also
11862306a36Sopenharmony_ci				 *          clear MBE)
11962306a36Sopenharmony_ci				 *        write 0=NOP
12062306a36Sopenharmony_ci				 */
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci#define R82600_DRBA	0x60	/* + 0x60..0x63 SDRAM Row Boundary Address
12362306a36Sopenharmony_ci				 *  Registers
12462306a36Sopenharmony_ci				 *
12562306a36Sopenharmony_ci				 * 7:0  Address lines 30:24 - upper limit of
12662306a36Sopenharmony_ci				 * each row [p57]
12762306a36Sopenharmony_ci				 */
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistruct r82600_error_info {
13062306a36Sopenharmony_ci	u32 eapr;
13162306a36Sopenharmony_ci};
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic bool disable_hardware_scrub;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic struct edac_pci_ctl_info *r82600_pci;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic void r82600_get_error_info(struct mem_ctl_info *mci,
13862306a36Sopenharmony_ci				struct r82600_error_info *info)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	struct pci_dev *pdev;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	pdev = to_pci_dev(mci->pdev);
14362306a36Sopenharmony_ci	pci_read_config_dword(pdev, R82600_EAP, &info->eapr);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	if (info->eapr & BIT(0))
14662306a36Sopenharmony_ci		/* Clear error to allow next error to be reported [p.62] */
14762306a36Sopenharmony_ci		pci_write_bits32(pdev, R82600_EAP,
14862306a36Sopenharmony_ci				 ((u32) BIT(0) & (u32) BIT(1)),
14962306a36Sopenharmony_ci				 ((u32) BIT(0) & (u32) BIT(1)));
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	if (info->eapr & BIT(1))
15262306a36Sopenharmony_ci		/* Clear error to allow next error to be reported [p.62] */
15362306a36Sopenharmony_ci		pci_write_bits32(pdev, R82600_EAP,
15462306a36Sopenharmony_ci				 ((u32) BIT(0) & (u32) BIT(1)),
15562306a36Sopenharmony_ci				 ((u32) BIT(0) & (u32) BIT(1)));
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic int r82600_process_error_info(struct mem_ctl_info *mci,
15962306a36Sopenharmony_ci				struct r82600_error_info *info,
16062306a36Sopenharmony_ci				int handle_errors)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	int error_found;
16362306a36Sopenharmony_ci	u32 eapaddr, page;
16462306a36Sopenharmony_ci	u32 syndrome;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	error_found = 0;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	/* bits 30:12 store the upper 19 bits of the 32 bit error address */
16962306a36Sopenharmony_ci	eapaddr = ((info->eapr >> 12) & 0x7FFF) << 13;
17062306a36Sopenharmony_ci	/* Syndrome in bits 11:4 [p.62]       */
17162306a36Sopenharmony_ci	syndrome = (info->eapr >> 4) & 0xFF;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	/* the R82600 reports at less than page *
17462306a36Sopenharmony_ci	 * granularity (upper 19 bits only)     */
17562306a36Sopenharmony_ci	page = eapaddr >> PAGE_SHIFT;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	if (info->eapr & BIT(0)) {	/* CE? */
17862306a36Sopenharmony_ci		error_found = 1;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci		if (handle_errors)
18162306a36Sopenharmony_ci			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
18262306a36Sopenharmony_ci					     page, 0, syndrome,
18362306a36Sopenharmony_ci					     edac_mc_find_csrow_by_page(mci, page),
18462306a36Sopenharmony_ci					     0, -1,
18562306a36Sopenharmony_ci					     mci->ctl_name, "");
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	if (info->eapr & BIT(1)) {	/* UE? */
18962306a36Sopenharmony_ci		error_found = 1;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci		if (handle_errors)
19262306a36Sopenharmony_ci			/* 82600 doesn't give enough info */
19362306a36Sopenharmony_ci			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
19462306a36Sopenharmony_ci					     page, 0, 0,
19562306a36Sopenharmony_ci					     edac_mc_find_csrow_by_page(mci, page),
19662306a36Sopenharmony_ci					     0, -1,
19762306a36Sopenharmony_ci					     mci->ctl_name, "");
19862306a36Sopenharmony_ci	}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	return error_found;
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic void r82600_check(struct mem_ctl_info *mci)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	struct r82600_error_info info;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	r82600_get_error_info(mci, &info);
20862306a36Sopenharmony_ci	r82600_process_error_info(mci, &info, 1);
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic inline int ecc_enabled(u8 dramcr)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	return dramcr & BIT(5);
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
21762306a36Sopenharmony_ci			u8 dramcr)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	struct csrow_info *csrow;
22062306a36Sopenharmony_ci	struct dimm_info *dimm;
22162306a36Sopenharmony_ci	int index;
22262306a36Sopenharmony_ci	u8 drbar;		/* SDRAM Row Boundary Address Register */
22362306a36Sopenharmony_ci	u32 row_high_limit, row_high_limit_last;
22462306a36Sopenharmony_ci	u32 reg_sdram, ecc_on, row_base;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	ecc_on = ecc_enabled(dramcr);
22762306a36Sopenharmony_ci	reg_sdram = dramcr & BIT(4);
22862306a36Sopenharmony_ci	row_high_limit_last = 0;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	for (index = 0; index < mci->nr_csrows; index++) {
23162306a36Sopenharmony_ci		csrow = mci->csrows[index];
23262306a36Sopenharmony_ci		dimm = csrow->channels[0]->dimm;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci		/* find the DRAM Chip Select Base address and mask */
23562306a36Sopenharmony_ci		pci_read_config_byte(pdev, R82600_DRBA + index, &drbar);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci		edac_dbg(1, "Row=%d DRBA = %#0x\n", index, drbar);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci		row_high_limit = ((u32) drbar << 24);
24062306a36Sopenharmony_ci/*		row_high_limit = ((u32)drbar << 24) | 0xffffffUL; */
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci		edac_dbg(1, "Row=%d, Boundary Address=%#0x, Last = %#0x\n",
24362306a36Sopenharmony_ci			 index, row_high_limit, row_high_limit_last);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci		/* Empty row [p.57] */
24662306a36Sopenharmony_ci		if (row_high_limit == row_high_limit_last)
24762306a36Sopenharmony_ci			continue;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci		row_base = row_high_limit_last;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci		csrow->first_page = row_base >> PAGE_SHIFT;
25262306a36Sopenharmony_ci		csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci		dimm->nr_pages = csrow->last_page - csrow->first_page + 1;
25562306a36Sopenharmony_ci		/* Error address is top 19 bits - so granularity is      *
25662306a36Sopenharmony_ci		 * 14 bits                                               */
25762306a36Sopenharmony_ci		dimm->grain = 1 << 14;
25862306a36Sopenharmony_ci		dimm->mtype = reg_sdram ? MEM_RDDR : MEM_DDR;
25962306a36Sopenharmony_ci		/* FIXME - check that this is unknowable with this chipset */
26062306a36Sopenharmony_ci		dimm->dtype = DEV_UNKNOWN;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci		/* Mode is global on 82600 */
26362306a36Sopenharmony_ci		dimm->edac_mode = ecc_on ? EDAC_SECDED : EDAC_NONE;
26462306a36Sopenharmony_ci		row_high_limit_last = row_high_limit;
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic int r82600_probe1(struct pci_dev *pdev, int dev_idx)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	struct mem_ctl_info *mci;
27162306a36Sopenharmony_ci	struct edac_mc_layer layers[2];
27262306a36Sopenharmony_ci	u8 dramcr;
27362306a36Sopenharmony_ci	u32 eapr;
27462306a36Sopenharmony_ci	u32 scrub_disabled;
27562306a36Sopenharmony_ci	u32 sdram_refresh_rate;
27662306a36Sopenharmony_ci	struct r82600_error_info discard;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	edac_dbg(0, "\n");
27962306a36Sopenharmony_ci	pci_read_config_byte(pdev, R82600_DRAMC, &dramcr);
28062306a36Sopenharmony_ci	pci_read_config_dword(pdev, R82600_EAP, &eapr);
28162306a36Sopenharmony_ci	scrub_disabled = eapr & BIT(31);
28262306a36Sopenharmony_ci	sdram_refresh_rate = dramcr & (BIT(0) | BIT(1));
28362306a36Sopenharmony_ci	edac_dbg(2, "sdram refresh rate = %#0x\n", sdram_refresh_rate);
28462306a36Sopenharmony_ci	edac_dbg(2, "DRAMC register = %#0x\n", dramcr);
28562306a36Sopenharmony_ci	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
28662306a36Sopenharmony_ci	layers[0].size = R82600_NR_CSROWS;
28762306a36Sopenharmony_ci	layers[0].is_virt_csrow = true;
28862306a36Sopenharmony_ci	layers[1].type = EDAC_MC_LAYER_CHANNEL;
28962306a36Sopenharmony_ci	layers[1].size = R82600_NR_CHANS;
29062306a36Sopenharmony_ci	layers[1].is_virt_csrow = false;
29162306a36Sopenharmony_ci	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0);
29262306a36Sopenharmony_ci	if (mci == NULL)
29362306a36Sopenharmony_ci		return -ENOMEM;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	edac_dbg(0, "mci = %p\n", mci);
29662306a36Sopenharmony_ci	mci->pdev = &pdev->dev;
29762306a36Sopenharmony_ci	mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
29862306a36Sopenharmony_ci	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
29962306a36Sopenharmony_ci	/* FIXME try to work out if the chip leads have been used for COM2
30062306a36Sopenharmony_ci	 * instead on this board? [MA6?] MAYBE:
30162306a36Sopenharmony_ci	 */
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	/* On the R82600, the pins for memory bits 72:65 - i.e. the   *
30462306a36Sopenharmony_ci	 * EC bits are shared with the pins for COM2 (!), so if COM2  *
30562306a36Sopenharmony_ci	 * is enabled, we assume COM2 is wired up, and thus no EDAC   *
30662306a36Sopenharmony_ci	 * is possible.                                               */
30762306a36Sopenharmony_ci	mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	if (ecc_enabled(dramcr)) {
31062306a36Sopenharmony_ci		if (scrub_disabled)
31162306a36Sopenharmony_ci			edac_dbg(3, "mci = %p - Scrubbing disabled! EAP: %#0x\n",
31262306a36Sopenharmony_ci				 mci, eapr);
31362306a36Sopenharmony_ci	} else
31462306a36Sopenharmony_ci		mci->edac_cap = EDAC_FLAG_NONE;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	mci->mod_name = EDAC_MOD_STR;
31762306a36Sopenharmony_ci	mci->ctl_name = "R82600";
31862306a36Sopenharmony_ci	mci->dev_name = pci_name(pdev);
31962306a36Sopenharmony_ci	mci->edac_check = r82600_check;
32062306a36Sopenharmony_ci	mci->ctl_page_to_phys = NULL;
32162306a36Sopenharmony_ci	r82600_init_csrows(mci, pdev, dramcr);
32262306a36Sopenharmony_ci	r82600_get_error_info(mci, &discard);	/* clear counters */
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	/* Here we assume that we will never see multiple instances of this
32562306a36Sopenharmony_ci	 * type of memory controller.  The ID is therefore hardcoded to 0.
32662306a36Sopenharmony_ci	 */
32762306a36Sopenharmony_ci	if (edac_mc_add_mc(mci)) {
32862306a36Sopenharmony_ci		edac_dbg(3, "failed edac_mc_add_mc()\n");
32962306a36Sopenharmony_ci		goto fail;
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	/* get this far and it's successful */
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	if (disable_hardware_scrub) {
33562306a36Sopenharmony_ci		edac_dbg(3, "Disabling Hardware Scrub (scrub on error)\n");
33662306a36Sopenharmony_ci		pci_write_bits32(pdev, R82600_EAP, BIT(31), BIT(31));
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	/* allocating generic PCI control info */
34062306a36Sopenharmony_ci	r82600_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
34162306a36Sopenharmony_ci	if (!r82600_pci) {
34262306a36Sopenharmony_ci		printk(KERN_WARNING
34362306a36Sopenharmony_ci			"%s(): Unable to create PCI control\n",
34462306a36Sopenharmony_ci			__func__);
34562306a36Sopenharmony_ci		printk(KERN_WARNING
34662306a36Sopenharmony_ci			"%s(): PCI error report via EDAC not setup\n",
34762306a36Sopenharmony_ci			__func__);
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	edac_dbg(3, "success\n");
35162306a36Sopenharmony_ci	return 0;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cifail:
35462306a36Sopenharmony_ci	edac_mc_free(mci);
35562306a36Sopenharmony_ci	return -ENODEV;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci/* returns count (>= 0), or negative on error */
35962306a36Sopenharmony_cistatic int r82600_init_one(struct pci_dev *pdev,
36062306a36Sopenharmony_ci			   const struct pci_device_id *ent)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	edac_dbg(0, "\n");
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	/* don't need to call pci_enable_device() */
36562306a36Sopenharmony_ci	return r82600_probe1(pdev, ent->driver_data);
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistatic void r82600_remove_one(struct pci_dev *pdev)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct mem_ctl_info *mci;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	edac_dbg(0, "\n");
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	if (r82600_pci)
37562306a36Sopenharmony_ci		edac_pci_release_generic_ctl(r82600_pci);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
37862306a36Sopenharmony_ci		return;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	edac_mc_free(mci);
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic const struct pci_device_id r82600_pci_tbl[] = {
38462306a36Sopenharmony_ci	{
38562306a36Sopenharmony_ci	 PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)
38662306a36Sopenharmony_ci	 },
38762306a36Sopenharmony_ci	{
38862306a36Sopenharmony_ci	 0,
38962306a36Sopenharmony_ci	 }			/* 0 terminated list. */
39062306a36Sopenharmony_ci};
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, r82600_pci_tbl);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic struct pci_driver r82600_driver = {
39562306a36Sopenharmony_ci	.name = EDAC_MOD_STR,
39662306a36Sopenharmony_ci	.probe = r82600_init_one,
39762306a36Sopenharmony_ci	.remove = r82600_remove_one,
39862306a36Sopenharmony_ci	.id_table = r82600_pci_tbl,
39962306a36Sopenharmony_ci};
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_cistatic int __init r82600_init(void)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci       /* Ensure that the OPSTATE is set correctly for POLL or NMI */
40462306a36Sopenharmony_ci       opstate_init();
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	return pci_register_driver(&r82600_driver);
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic void __exit r82600_exit(void)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	pci_unregister_driver(&r82600_driver);
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cimodule_init(r82600_init);
41562306a36Sopenharmony_cimodule_exit(r82600_exit);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
41862306a36Sopenharmony_ciMODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD Ltd. on behalf of EADS Astrium");
41962306a36Sopenharmony_ciMODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers");
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cimodule_param(disable_hardware_scrub, bool, 0644);
42262306a36Sopenharmony_ciMODULE_PARM_DESC(disable_hardware_scrub,
42362306a36Sopenharmony_ci		 "If set, disable the chipset's automatic scrub for CEs");
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cimodule_param(edac_op_state, int, 0444);
42662306a36Sopenharmony_ciMODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
427