#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
+#include <linux/edac.h>
#include "edac_core.h"
#define I82875P_REVISION " Ver: 2.0.2 " __DATE__
static const struct i82875p_dev_info i82875p_devs[] = {
[I82875P] = {
- .ctl_name = "i82875p"},
+ .ctl_name = "i82875p"},
};
-static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code has
+static struct pci_dev *mci_pdev; /* init dev: in case that AGP code has
* already registered driver
*/
static int i82875p_registered = 1;
+static struct edac_pci_ctl_info *i82875p_pci;
+
static void i82875p_get_error_info(struct mem_ctl_info *mci,
- struct i82875p_error_info *info)
+ struct i82875p_error_info *info)
{
struct pci_dev *pdev;
* overwritten by UE.
*/
pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts);
+
+ if (!(info->errsts & 0x0081))
+ return;
+
pci_read_config_dword(pdev, I82875P_EAP, &info->eap);
pci_read_config_byte(pdev, I82875P_DES, &info->des);
pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn);
pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts2);
- pci_write_bits16(pdev, I82875P_ERRSTS, 0x0081, 0x0081);
-
/*
* If the error is the same then we can for both reads then
* the first set of reads is valid. If there is a change then
* there is a CE no info and the second set of reads is valid
* and should be UE info.
*/
- if (!(info->errsts2 & 0x0081))
- return;
-
if ((info->errsts ^ info->errsts2) & 0x0081) {
pci_read_config_dword(pdev, I82875P_EAP, &info->eap);
pci_read_config_byte(pdev, I82875P_DES, &info->des);
pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn);
}
+
+ pci_write_bits16(pdev, I82875P_ERRSTS, 0x0081, 0x0081);
}
static int i82875p_process_error_info(struct mem_ctl_info *mci,
- struct i82875p_error_info *info,
- int handle_errors)
+ struct i82875p_error_info *info,
+ int handle_errors)
{
int row, multi_chan;
multi_chan = mci->csrows[0].nr_channels - 1;
- if (!(info->errsts2 & 0x0081))
+ if (!(info->errsts & 0x0081))
return 0;
if (!handle_errors)
edac_mc_handle_ue(mci, info->eap, 0, row, "i82875p UE");
else
edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row,
- multi_chan ? (info->des & 0x1) : 0,
- "i82875p CE");
+ multi_chan ? (info->des & 0x1) : 0,
+ "i82875p CE");
return 1;
}
/* Return 0 on success or 1 on failure. */
static int i82875p_setup_overfl_dev(struct pci_dev *pdev,
- struct pci_dev **ovrfl_pdev,
- void __iomem ** ovrfl_window)
+ struct pci_dev **ovrfl_pdev,
+ void __iomem **ovrfl_window)
{
struct pci_dev *dev;
void __iomem *window;
+ int err;
*ovrfl_pdev = NULL;
*ovrfl_window = NULL;
if (dev == NULL)
return 1;
- pci_bus_add_device(dev);
+ err = pci_bus_add_device(dev);
+ if (err) {
+ i82875p_printk(KERN_ERR,
+ "%s(): pci_bus_add_device() Failed\n",
+ __func__);
+ }
+ pci_bus_assign_resources(dev->bus);
}
*ovrfl_pdev = dev;
if (pci_enable_device(dev)) {
i82875p_printk(KERN_ERR, "%s(): Failed to enable overflow "
- "device\n", __func__);
+ "device\n", __func__);
return 1;
}
if (window == NULL) {
i82875p_printk(KERN_ERR, "%s(): Failed to ioremap bar6\n",
- __func__);
+ __func__);
goto fail1;
}
*ovrfl_window = window;
return 0;
- fail1:
+fail1:
pci_release_regions(dev);
#ifdef CORRECT_BIOS
- fail0:
+fail0:
pci_disable_device(dev);
#endif
/* NOTE: the ovrfl proc entry and pci_dev are intentionally left */
struct i82875p_error_info discard;
debugf0("%s()\n", __func__);
+
ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL);
if (i82875p_setup_overfl_dev(pdev, &ovrfl_pdev, &ovrfl_window))
drc = readl(ovrfl_window + I82875P_DRC);
nr_chans = dual_channel_active(drc) + 1;
mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans),
- nr_chans);
+ nr_chans, 0);
if (!mci) {
rc = -ENOMEM;
/* 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, 0)) {
+ if (edac_mc_add_mc(mci)) {
debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
goto fail1;
}
+ /* allocating generic PCI control info */
+ i82875p_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!i82875p_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__);
+ }
+
/* get this far and it's successful */
debugf3("%s(): success\n", __func__);
return 0;
- fail1:
+fail1:
edac_mc_free(mci);
- fail0:
+fail0:
iounmap(ovrfl_window);
pci_release_regions(ovrfl_pdev);
/* returns count (>= 0), or negative on error */
static int __devinit i82875p_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
int rc;
debugf0("%s()\n", __func__);
+ if (i82875p_pci)
+ edac_pci_release_generic_ctl(i82875p_pci);
+
if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
int pci_rc;
debugf3("%s()\n", __func__);
+
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
pci_rc = pci_register_driver(&i82875p_driver);
if (pci_rc < 0)
if (mci_pdev == NULL) {
mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82875_0, NULL);
+ PCI_DEVICE_ID_INTEL_82875_0, NULL);
if (!mci_pdev) {
debugf0("875p pci_get_device fail\n");
return 0;
- fail1:
+fail1:
pci_unregister_driver(&i82875p_driver);
- fail0:
+fail0:
if (mci_pdev != NULL)
pci_dev_put(mci_pdev);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh");
MODULE_DESCRIPTION("MC support for Intel 82875 memory hub controllers");
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");