diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2006-01-27 06:33:43 +0300 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2006-01-27 06:33:43 +0300 |
commit | 71e834f563799e09c6bd7d6638993b464fac26f5 (patch) | |
tree | 3a35643ddc54e7217ec000eb415cc79a65cdcac1 /drivers | |
parent | ff0fc1467f8189c8e2340b91161c97138a75e484 (diff) | |
parent | 3ee68c4af3fd7228c1be63254b9f884614f9ebb2 (diff) | |
download | linux-71e834f563799e09c6bd7d6638993b464fac26f5.tar.xz |
Merge branch 'master'
Diffstat (limited to 'drivers')
30 files changed, 6890 insertions, 645 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 283c089537bc..bddf431bbb72 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -68,4 +68,6 @@ source "drivers/infiniband/Kconfig" source "drivers/sn/Kconfig" +source "drivers/edac/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 7c45050ecd03..619dd964c51c 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_PHONE) += telephony/ obj-$(CONFIG_MD) += md/ obj-$(CONFIG_BT) += bluetooth/ obj-$(CONFIG_ISDN) += isdn/ +obj-$(CONFIG_EDAC) += edac/ obj-$(CONFIG_MCA) += mca/ obj-$(CONFIG_EISA) += eisa/ obj-$(CONFIG_CPU_FREQ) += cpufreq/ diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 07c9be6a6bbf..a85a60a93deb 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -2630,7 +2630,7 @@ static int get_interface(struct slgt_info *info, int __user *if_mode) static int set_interface(struct slgt_info *info, int if_mode) { unsigned long flags; - unsigned char val; + unsigned short val; DBGINFO(("%s set_interface=%x)\n", info->device_name, if_mode)); spin_lock_irqsave(&info->lock,flags); diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c index bc56df8a3474..4c272189cd42 100644 --- a/drivers/char/tlclk.c +++ b/drivers/char/tlclk.c @@ -34,7 +34,6 @@ #include <linux/kernel.h> /* printk() */ #include <linux/fs.h> /* everything... */ #include <linux/errno.h> /* error codes */ -#include <linux/delay.h> /* udelay */ #include <linux/slab.h> #include <linux/ioport.h> #include <linux/interrupt.h> @@ -156,6 +155,8 @@ This directory exports the following interfaces. There operation is documented in the MCPBL0010 TPS under the Telecom Clock API section, 11.4. alarms : current_ref : +received_ref_clk3a : +received_ref_clk3b : enable_clk3a_output : enable_clk3b_output : enable_clka0_output : @@ -165,7 +166,7 @@ enable_clkb1_output : filter_select : hardware_switching : hardware_switching_mode : -interrupt_switch : +telclock_version : mode_select : refalign : reset : @@ -173,7 +174,6 @@ select_amcb1_transmit_clock : select_amcb2_transmit_clock : select_redundant_clock : select_ref_frequency : -test_mode : All sysfs interfaces are integers in hex format, i.e echo 99 > refalign has the same effect as echo 0x99 > refalign. @@ -226,7 +226,7 @@ static int tlclk_release(struct inode *inode, struct file *filp) return 0; } -ssize_t tlclk_read(struct file *filp, char __user *buf, size_t count, +static ssize_t tlclk_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { if (count < sizeof(struct tlclk_alarms)) @@ -242,7 +242,7 @@ ssize_t tlclk_read(struct file *filp, char __user *buf, size_t count, return sizeof(struct tlclk_alarms); } -ssize_t tlclk_write(struct file *filp, const char __user *buf, size_t count, +static ssize_t tlclk_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { return 0; @@ -278,21 +278,21 @@ static ssize_t show_current_ref(struct device *d, static DEVICE_ATTR(current_ref, S_IRUGO, show_current_ref, NULL); -static ssize_t show_interrupt_switch(struct device *d, +static ssize_t show_telclock_version(struct device *d, struct device_attribute *attr, char *buf) { unsigned long ret_val; unsigned long flags; spin_lock_irqsave(&event_lock, flags); - ret_val = inb(TLCLK_REG6); + ret_val = inb(TLCLK_REG5); spin_unlock_irqrestore(&event_lock, flags); return sprintf(buf, "0x%lX\n", ret_val); } -static DEVICE_ATTR(interrupt_switch, S_IRUGO, - show_interrupt_switch, NULL); +static DEVICE_ATTR(telclock_version, S_IRUGO, + show_telclock_version, NULL); static ssize_t show_alarms(struct device *d, struct device_attribute *attr, char *buf) @@ -309,6 +309,50 @@ static ssize_t show_alarms(struct device *d, static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static ssize_t store_received_ref_clk3a(struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long tmp; + unsigned char val; + unsigned long flags; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, ": tmp = 0x%lX\n", tmp); + + val = (unsigned char)tmp; + spin_lock_irqsave(&event_lock, flags); + SET_PORT_BITS(TLCLK_REG1, 0xef, val); + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(received_ref_clk3a, S_IWUGO, NULL, + store_received_ref_clk3a); + + +static ssize_t store_received_ref_clk3b(struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long tmp; + unsigned char val; + unsigned long flags; + + sscanf(buf, "%lX", &tmp); + dev_dbg(d, ": tmp = 0x%lX\n", tmp); + + val = (unsigned char)tmp; + spin_lock_irqsave(&event_lock, flags); + SET_PORT_BITS(TLCLK_REG1, 0xef, val << 1); + spin_unlock_irqrestore(&event_lock, flags); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(received_ref_clk3b, S_IWUGO, NULL, + store_received_ref_clk3b); + + static ssize_t store_enable_clk3b_output(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { @@ -436,26 +480,6 @@ static ssize_t store_enable_clka0_output(struct device *d, static DEVICE_ATTR(enable_clka0_output, S_IWUGO, NULL, store_enable_clka0_output); -static ssize_t store_test_mode(struct device *d, - struct device_attribute *attr, const char *buf, size_t count) -{ - unsigned long flags; - unsigned long tmp; - unsigned char val; - - sscanf(buf, "%lX", &tmp); - dev_dbg(d, "tmp = 0x%lX\n", tmp); - - val = (unsigned char)tmp; - spin_lock_irqsave(&event_lock, flags); - SET_PORT_BITS(TLCLK_REG4, 0xfd, 2); - spin_unlock_irqrestore(&event_lock, flags); - - return strnlen(buf, count); -} - -static DEVICE_ATTR(test_mode, S_IWUGO, NULL, store_test_mode); - static ssize_t store_select_amcb2_transmit_clock(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { @@ -475,7 +499,7 @@ static ssize_t store_select_amcb2_transmit_clock(struct device *d, SET_PORT_BITS(TLCLK_REG3, 0xc7, 0x38); switch (val) { case CLK_8_592MHz: - SET_PORT_BITS(TLCLK_REG0, 0xfc, 1); + SET_PORT_BITS(TLCLK_REG0, 0xfc, 2); break; case CLK_11_184MHz: SET_PORT_BITS(TLCLK_REG0, 0xfc, 0); @@ -484,7 +508,7 @@ static ssize_t store_select_amcb2_transmit_clock(struct device *d, SET_PORT_BITS(TLCLK_REG0, 0xfc, 3); break; case CLK_44_736MHz: - SET_PORT_BITS(TLCLK_REG0, 0xfc, 2); + SET_PORT_BITS(TLCLK_REG0, 0xfc, 1); break; } } else @@ -653,9 +677,7 @@ static ssize_t store_refalign (struct device *d, dev_dbg(d, "tmp = 0x%lX\n", tmp); spin_lock_irqsave(&event_lock, flags); SET_PORT_BITS(TLCLK_REG0, 0xf7, 0); - udelay(2); SET_PORT_BITS(TLCLK_REG0, 0xf7, 0x08); - udelay(2); SET_PORT_BITS(TLCLK_REG0, 0xf7, 0); spin_unlock_irqrestore(&event_lock, flags); @@ -706,15 +728,16 @@ static DEVICE_ATTR(reset, S_IWUGO, NULL, store_reset); static struct attribute *tlclk_sysfs_entries[] = { &dev_attr_current_ref.attr, - &dev_attr_interrupt_switch.attr, + &dev_attr_telclock_version.attr, &dev_attr_alarms.attr, + &dev_attr_received_ref_clk3a.attr, + &dev_attr_received_ref_clk3b.attr, &dev_attr_enable_clk3a_output.attr, &dev_attr_enable_clk3b_output.attr, &dev_attr_enable_clkb1_output.attr, &dev_attr_enable_clka1_output.attr, &dev_attr_enable_clkb0_output.attr, &dev_attr_enable_clka0_output.attr, - &dev_attr_test_mode.attr, &dev_attr_select_amcb1_transmit_clock.attr, &dev_attr_select_amcb2_transmit_clock.attr, &dev_attr_select_redundant_clock.attr, diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig new file mode 100644 index 000000000000..4819e7fc00dd --- /dev/null +++ b/drivers/edac/Kconfig @@ -0,0 +1,102 @@ +# +# EDAC Kconfig +# Copyright (c) 2003 Linux Networx +# Licensed and distributed under the GPL +# +# $Id: Kconfig,v 1.4.2.7 2005/07/08 22:05:38 dsp_llnl Exp $ +# + +menu 'EDAC - error detection and reporting (RAS)' + +config EDAC + tristate "EDAC core system error reporting" + depends on X86 + default y + help + EDAC is designed to report errors in the core system. + These are low-level errors that are reported in the CPU or + supporting chipset: memory errors, cache errors, PCI errors, + thermal throttling, etc.. If unsure, select 'Y'. + + +comment "Reporting subsystems" + depends on EDAC + +config EDAC_DEBUG + bool "Debugging" + depends on EDAC + help + This turns on debugging information for the entire EDAC + sub-system. You can insert module with "debug_level=x", current + there're four debug levels (x=0,1,2,3 from low to high). + Usually you should select 'N'. + +config EDAC_MM_EDAC + tristate "Main Memory EDAC (Error Detection And Correction) reporting" + depends on EDAC + default y + help + Some systems are able to detect and correct errors in main + memory. EDAC can report statistics on memory error + detection and correction (EDAC - or commonly referred to ECC + errors). EDAC will also try to decode where these errors + occurred so that a particular failing memory module can be + replaced. If unsure, select 'Y'. + + +config EDAC_AMD76X + tristate "AMD 76x (760, 762, 768)" + depends on EDAC_MM_EDAC && PCI + help + Support for error detection and correction on the AMD 76x + series of chipsets used with the Athlon processor. + +config EDAC_E7XXX + tristate "Intel e7xxx (e7205, e7500, e7501, e7505)" + depends on EDAC_MM_EDAC && PCI + help + Support for error detection and correction on the Intel + E7205, E7500, E7501 and E7505 server chipsets. + +config EDAC_E752X + tristate "Intel e752x (e7520, e7525, e7320)" + depends on EDAC_MM_EDAC && PCI + help + Support for error detection and correction on the Intel + E7520, E7525, E7320 server chipsets. + +config EDAC_I82875P + tristate "Intel 82875p (D82875P, E7210)" + depends on EDAC_MM_EDAC && PCI + help + Support for error detection and correction on the Intel + DP82785P and E7210 server chipsets. + +config EDAC_I82860 + tristate "Intel 82860" + depends on EDAC_MM_EDAC && PCI + help + Support for error detection and correction on the Intel + 82860 chipset. + +config EDAC_R82600 + tristate "Radisys 82600 embedded chipset" + depends on EDAC_MM_EDAC + help + Support for error detection and correction on the Radisys + 82600 embedded chipset. + +choice + prompt "Error detecting method" + depends on EDAC + default EDAC_POLL + +config EDAC_POLL + bool "Poll for errors" + depends on EDAC + help + Poll the chipset periodically to detect errors. + +endchoice + +endmenu diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile new file mode 100644 index 000000000000..93137fdab4b3 --- /dev/null +++ b/drivers/edac/Makefile @@ -0,0 +1,18 @@ +# +# Makefile for the Linux kernel EDAC drivers. +# +# Copyright 02 Jul 2003, Linux Networx (http://lnxi.com) +# This file may be distributed under the terms of the +# GNU General Public License. +# +# $Id: Makefile,v 1.4.2.3 2005/07/08 22:05:38 dsp_llnl Exp $ + + +obj-$(CONFIG_EDAC_MM_EDAC) += edac_mc.o +obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o +obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o +obj-$(CONFIG_EDAC_E752X) += e752x_edac.o +obj-$(CONFIG_EDAC_I82875P) += i82875p_edac.o +obj-$(CONFIG_EDAC_I82860) += i82860_edac.o +obj-$(CONFIG_EDAC_R82600) += r82600_edac.o + diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c new file mode 100644 index 000000000000..2fcc8120b53c --- /dev/null +++ b/drivers/edac/amd76x_edac.c @@ -0,0 +1,356 @@ +/* + * AMD 76x Memory Controller kernel module + * (C) 2003 Linux Networx (http://lnxi.com) + * This file may be distributed under the terms of the + * GNU General Public License. + * + * Written by Thayne Harbaugh + * Based on work by Dan Hollis <goemon at anime dot net> and others. + * http://www.anime.net/~goemon/linux-ecc/ + * + * $Id: edac_amd76x.c,v 1.4.2.5 2005/10/05 00:43:44 dsp_llnl Exp $ + * + */ + + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> + +#include <linux/pci.h> +#include <linux/pci_ids.h> + +#include <linux/slab.h> + +#include "edac_mc.h" + + +#define AMD76X_NR_CSROWS 8 +#define AMD76X_NR_CHANS 1 +#define AMD76X_NR_DIMMS 4 + + +/* AMD 76x register addresses - device 0 function 0 - PCI bridge */ +#define AMD76X_ECC_MODE_STATUS 0x48 /* Mode and status of ECC (32b) + * + * 31:16 reserved + * 15:14 SERR enabled: x1=ue 1x=ce + * 13 reserved + * 12 diag: disabled, enabled + * 11:10 mode: dis, EC, ECC, ECC+scrub + * 9:8 status: x1=ue 1x=ce + * 7:4 UE cs row + * 3:0 CE cs row + */ +#define AMD76X_DRAM_MODE_STATUS 0x58 /* DRAM Mode and status (32b) + * + * 31:26 clock disable 5 - 0 + * 25 SDRAM init + * 24 reserved + * 23 mode register service + * 22:21 suspend to RAM + * 20 burst refresh enable + * 19 refresh disable + * 18 reserved + * 17:16 cycles-per-refresh + * 15:8 reserved + * 7:0 x4 mode enable 7 - 0 + */ +#define AMD76X_MEM_BASE_ADDR 0xC0 /* Memory base address (8 x 32b) + * + * 31:23 chip-select base + * 22:16 reserved + * 15:7 chip-select mask + * 6:3 reserved + * 2:1 address mode + * 0 chip-select enable + */ + + +struct amd76x_error_info { + u32 ecc_mode_status; +}; + + +enum amd76x_chips { + AMD761 = 0, + AMD762 +}; + + +struct amd76x_dev_info { + const char *ctl_name; +}; + + +static const struct amd76x_dev_info amd76x_devs[] = { + [AMD761] = {.ctl_name = "AMD761"}, + [AMD762] = {.ctl_name = "AMD762"}, +}; + + +/** + * amd76x_get_error_info - fetch error information + * @mci: Memory controller + * @info: Info to fill in + * + * Fetch and store the AMD76x ECC status. Clear pending status + * on the chip so that further errors will be reported + */ + +static void amd76x_get_error_info (struct mem_ctl_info *mci, + struct amd76x_error_info *info) +{ + pci_read_config_dword(mci->pdev, AMD76X_ECC_MODE_STATUS, + &info->ecc_mode_status); + + if (info->ecc_mode_status & BIT(8)) + pci_write_bits32(mci->pdev, AMD76X_ECC_MODE_STATUS, + (u32) BIT(8), (u32) BIT(8)); + + if (info->ecc_mode_status & BIT(9)) + pci_write_bits32(mci->pdev, AMD76X_ECC_MODE_STATUS, + (u32) BIT(9), (u32) BIT(9)); +} + + +/** + * amd76x_process_error_info - Error check + * @mci: Memory controller + * @info: Previously fetched information from chip + * @handle_errors: 1 if we should do recovery + * + * Process the chip state and decide if an error has occurred. + * A return of 1 indicates an error. Also if handle_errors is true + * then attempt to handle and clean up after the error + */ + +static int amd76x_process_error_info (struct mem_ctl_info *mci, + struct amd76x_error_info *info, int handle_errors) +{ + int error_found; + u32 row; + + error_found = 0; + + /* + * Check for an uncorrectable error + */ + if (info->ecc_mode_status & BIT(8)) { + error_found = 1; + + if (handle_errors) { + row = (info->ecc_mode_status >> 4) & 0xf; + edac_mc_handle_ue(mci, + mci->csrows[row].first_page, 0, row, + mci->ctl_name); + } + } + + /* + * Check for a correctable error + */ + if (info->ecc_mode_status & BIT(9)) { + error_found = 1; + + if (handle_errors) { + row = info->ecc_mode_status & 0xf; + edac_mc_handle_ce(mci, + mci->csrows[row].first_page, 0, 0, row, 0, + mci->ctl_name); + } + } + return error_found; +} + +/** + * amd76x_check - Poll the controller + * @mci: Memory controller + * + * Called by the poll handlers this function reads the status + * from the controller and checks for errors. + */ + +static void amd76x_check(struct mem_ctl_info *mci) +{ + struct amd76x_error_info info; + debugf3("MC: " __FILE__ ": %s()\n", __func__); + amd76x_get_error_info(mci, &info); + amd76x_process_error_info(mci, &info, 1); +} + + +/** + * amd76x_probe1 - Perform set up for detected device + * @pdev; PCI device detected + * @dev_idx: Device type index + * + * We have found an AMD76x and now need to set up the memory + * controller status reporting. We configure and set up the + * memory controller reporting and claim the device. + */ + +static int amd76x_probe1(struct pci_dev *pdev, int dev_idx) +{ + int rc = -ENODEV; + int index; + struct mem_ctl_info *mci = NULL; + enum edac_type ems_modes[] = { + EDAC_NONE, + EDAC_EC, + EDAC_SECDED, + EDAC_SECDED + }; + u32 ems; + u32 ems_mode; + + debugf0("MC: " __FILE__ ": %s()\n", __func__); + + pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems); + ems_mode = (ems >> 10) & 0x3; + + mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS); + + if (mci == NULL) { + rc = -ENOMEM; + goto fail; + } + + debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); + + mci->pdev = pci_dev_get(pdev); + mci->mtype_cap = MEM_FLAG_RDDR; + + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; + mci->edac_cap = ems_mode ? + (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_NONE; + + mci->mod_name = BS_MOD_STR; + mci->mod_ver = "$Revision: 1.4.2.5 $"; + mci->ctl_name = amd76x_devs[dev_idx].ctl_name; + mci->edac_check = amd76x_check; + mci->ctl_page_to_phys = NULL; + + for (index = 0; index < mci->nr_csrows; index++) { + struct csrow_info *csrow = &mci->csrows[index]; + u32 mba; + u32 mba_base; + u32 mba_mask; + u32 dms; + + /* find the DRAM Chip Select Base address and mask */ + pci_read_config_dword(mci->pdev, + AMD76X_MEM_BASE_ADDR + (index * 4), + &mba); + + if (!(mba & BIT(0))) + continue; + + mba_base = mba & 0xff800000UL; + mba_mask = ((mba & 0xff80) << 16) | 0x7fffffUL; + + pci_read_config_dword(mci->pdev, AMD76X_DRAM_MODE_STATUS, + &dms); + + csrow->first_page = mba_base >> PAGE_SHIFT; + csrow->nr_pages = (mba_mask + 1) >> PAGE_SHIFT; + csrow->last_page = csrow->first_page + csrow->nr_pages - 1; + csrow->page_mask = mba_mask >> PAGE_SHIFT; + csrow->grain = csrow->nr_pages << PAGE_SHIFT; + csrow->mtype = MEM_RDDR; + csrow->dtype = ((dms >> index) & 0x1) ? DEV_X4 : DEV_UNKNOWN; + csrow->edac_mode = ems_modes[ems_mode]; + } + + /* clear counters */ + pci_write_bits32(mci->pdev, AMD76X_ECC_MODE_STATUS, (u32) (0x3 << 8), + (u32) (0x3 << 8)); + + if (edac_mc_add_mc(mci)) { + debugf3("MC: " __FILE__ + ": %s(): failed edac_mc_add_mc()\n", __func__); + goto fail; + } + + /* get this far and it's successful */ + debugf3("MC: " __FILE__ ": %s(): success\n", __func__); + return 0; + +fail: + if (mci) { + if(mci->pdev) + pci_dev_put(mci->pdev); + edac_mc_free(mci); + } + return rc; +} + +/* returns count (>= 0), or negative on error */ +static int __devinit amd76x_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + debugf0("MC: " __FILE__ ": %s()\n", __func__); + + /* don't need to call pci_device_enable() */ + return amd76x_probe1(pdev, ent->driver_data); +} + + +/** + * amd76x_remove_one - driver shutdown + * @pdev: PCI device being handed back + * + * Called when the driver is unloaded. Find the matching mci + * structure for the device then delete the mci and free the + * resources. + */ + +static void __devexit amd76x_remove_one(struct pci_dev *pdev) +{ + struct mem_ctl_info *mci; + + debugf0(__FILE__ ": %s()\n", __func__); + + if ((mci = edac_mc_find_mci_by_pdev(pdev)) == NULL) + return; + if (edac_mc_del_mc(mci)) + return; + pci_dev_put(mci->pdev); + edac_mc_free(mci); +} + + +static const struct pci_device_id amd76x_pci_tbl[] __devinitdata = { + {PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0, + AMD762}, + {PCI_VEND_DEV(AMD, FE_GATE_700E), PCI_ANY_ID, PCI_ANY_ID, 0, 0, + AMD761}, + {0,} /* 0 terminated list. */ +}; + +MODULE_DEVICE_TABLE(pci, amd76x_pci_tbl); + + +static struct pci_driver amd76x_driver = { + .name = BS_MOD_STR, + .probe = amd76x_init_one, + .remove = __devexit_p(amd76x_remove_one), + .id_table = amd76x_pci_tbl, +}; + +static int __init amd76x_init(void) +{ + return pci_register_driver(&amd76x_driver); +} + +static void __exit amd76x_exit(void) +{ + pci_unregister_driver(&amd76x_driver); +} + +module_init(amd76x_init); +module_exit(amd76x_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh"); +MODULE_DESCRIPTION("MC support for AMD 76x memory controllers"); diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c new file mode 100644 index 000000000000..770a5a633079 --- /dev/null +++ b/drivers/edac/e752x_edac.c @@ -0,0 +1,1071 @@ +/* + * Intel e752x Memory Controller kernel module + * (C) 2004 Linux Networx (http://lnxi.com) + * This file may be distributed under the terms of the + * GNU General Public License. + * + * See "enum e752x_chips" below for supported chipsets + * + * Written by Tom Zimmerman + * + * Contributors: + * Thayne Harbaugh at realmsys.com (?) + * Wang Zhenyu at intel.com + * Dave Jiang at mvista.com + * + * $Id: edac_e752x.c,v 1.5.2.11 2005/10/05 00:43:44 dsp_llnl Exp $ + * + */ + + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> + +#include <linux/pci.h> +#include <linux/pci_ids.h> + +#include <linux/slab.h> + +#include "edac_mc.h" + + +#ifndef PCI_DEVICE_ID_INTEL_7520_0 +#define PCI_DEVICE_ID_INTEL_7520_0 0x3590 +#endif /* PCI_DEVICE_ID_INTEL_7520_0 */ + +#ifndef PCI_DEVICE_ID_INTEL_7520_1_ERR +#define PCI_DEVICE_ID_INTEL_7520_1_ERR 0x3591 +#endif /* PCI_DEVICE_ID_INTEL_7520_1_ERR */ + +#ifndef PCI_DEVICE_ID_INTEL_7525_0 +#define PCI_DEVICE_ID_INTEL_7525_0 0x359E +#endif /* PCI_DEVICE_ID_INTEL_7525_0 */ + +#ifndef PCI_DEVICE_ID_INTEL_7525_1_ERR +#define PCI_DEVICE_ID_INTEL_7525_1_ERR 0x3593 +#endif /* PCI_DEVICE_ID_INTEL_7525_1_ERR */ + +#ifndef PCI_DEVICE_ID_INTEL_7320_0 +#define PCI_DEVICE_ID_INTEL_7320_0 0x3592 +#endif /* PCI_DEVICE_ID_INTEL_7320_0 */ + +#ifndef PCI_DEVICE_ID_INTEL_7320_1_ERR +#define PCI_DEVICE_ID_INTEL_7320_1_ERR 0x3593 +#endif /* PCI_DEVICE_ID_INTEL_7320_1_ERR */ + +#define E752X_NR_CSROWS 8 /* number of csrows */ + + +/* E752X register addresses - device 0 function 0 */ +#define E752X_DRB 0x60 /* DRAM row boundary register (8b) */ +#define E752X_DRA 0x70 /* DRAM row attribute register (8b) */ + /* + * 31:30 Device width row 7 + * 01=x8 10=x4 11=x8 DDR2 + * 27:26 Device width row 6 + * 23:22 Device width row 5 + * 19:20 Device width row 4 + * 15:14 Device width row 3 + * 11:10 Device width row 2 + * 7:6 Device width row 1 + * 3:2 Device width row 0 + */ +#define E752X_DRC 0x7C /* DRAM controller mode reg (32b) */ + /* FIXME:IS THIS RIGHT? */ + /* + * 22 Number channels 0=1,1=2 + * 19:18 DRB Granularity 32/64MB + */ +#define E752X_DRM 0x80 /* Dimm mapping register */ +#define E752X_DDRCSR 0x9A /* DDR control and status reg (16b) */ + /* + * 14:12 1 single A, 2 single B, 3 dual + */ +#define E752X_TOLM 0xC4 /* DRAM top of low memory reg (16b) */ +#define E752X_REMAPBASE 0xC6 /* DRAM remap base address reg (16b) */ +#define E752X_REMAPLIMIT 0xC8 /* DRAM remap limit address reg (16b) */ +#define E752X_REMAPOFFSET 0xCA /* DRAM remap limit offset reg (16b) */ + +/* E752X register addresses - device 0 function 1 */ +#define E752X_FERR_GLOBAL 0x40 /* Global first error register (32b) */ +#define E752X_NERR_GLOBAL 0x44 /* Global next error register (32b) */ +#define E752X_HI_FERR 0x50 /* Hub interface first error reg (8b) */ +#define E752X_HI_NERR 0x52 /* Hub interface next error reg (8b) */ +#define E752X_HI_ERRMASK 0x54 /* Hub interface error mask reg (8b) */ +#define E752X_HI_SMICMD 0x5A /* Hub interface SMI command reg (8b) */ +#define E752X_SYSBUS_FERR 0x60 /* System buss first error reg (16b) */ +#define E752X_SYSBUS_NERR 0x62 /* System buss next error reg (16b) */ +#define E752X_SYSBUS_ERRMASK 0x64 /* System buss error mask reg (16b) */ +#define E752X_SYSBUS_SMICMD 0x6A /* System buss SMI command reg (16b) */ +#define E752X_BUF_FERR 0x70 /* Memory buffer first error reg (8b) */ +#define E752X_BUF_NERR 0x72 /* Memory buffer next error reg (8b) */ +#define E752X_BUF_ERRMASK 0x74 /* Memory buffer error mask reg (8b) */ +#define E752X_BUF_SMICMD 0x7A /* Memory buffer SMI command reg (8b) */ +#define E752X_DRAM_FERR 0x80 /* DRAM first error register (16b) */ +#define E752X_DRAM_NERR 0x82 /* DRAM next error register (16b) */ +#define E752X_DRAM_ERRMASK 0x84 /* DRAM error mask register (8b) */ +#define E752X_DRAM_SMICMD 0x8A /* DRAM SMI command register (8b) */ +#define E752X_DRAM_RETR_ADD 0xAC /* DRAM Retry address register (32b) */ +#define E752X_DRAM_SEC1_ADD 0xA0 /* DRAM first correctable memory */ + /* error address register (32b) */ + /* + * 31 Reserved + * 30:2 CE address (64 byte block 34:6) + * 1 Reserved + * 0 HiLoCS + */ +#define E752X_DRAM_SEC2_ADD 0xC8 /* DRAM first correctable memory */ + /* error address register (32b) */ + /* + * 31 Reserved + * 30:2 CE address (64 byte block 34:6) + * 1 Reserved + * 0 HiLoCS + */ +#define E752X_DRAM_DED_ADD 0xA4 /* DRAM first uncorrectable memory */ + /* error address register (32b) */ + /* + * 31 Reserved + * 30:2 CE address (64 byte block 34:6) + * 1 Reserved + * 0 HiLoCS + */ +#define E752X_DRAM_SCRB_ADD 0xA8 /* DRAM first uncorrectable scrub memory */ + /* error address register (32b) */ + /* + * 31 Reserved + * 30:2 CE address (64 byte block 34:6) + * 1 Reserved + * 0 HiLoCS + */ +#define E752X_DRAM_SEC1_SYNDROME 0xC4 /* DRAM first correctable memory */ + /* error syndrome register (16b) */ +#define E752X_DRAM_SEC2_SYNDROME 0xC6 /* DRAM second correctable memory */ + /* error syndrome register (16b) */ +#define E752X_DEVPRES1 0xF4 /* Device Present 1 register (8b) */ + +/* ICH5R register addresses - device 30 function 0 */ +#define ICH5R_PCI_STAT 0x06 /* PCI status register (16b) */ +#define ICH5R_PCI_2ND_STAT 0x1E /* PCI status secondary reg (16b) */ +#define ICH5R_PCI_BRIDGE_CTL 0x3E /* PCI bridge control register (16b) */ + +enum e752x_chips { + E7520 = 0, + E7525 = 1, + E7320 = 2 +}; + + +struct e752x_pvt { + struct pci_dev *bridge_ck; + struct pci_dev *dev_d0f0; + struct pci_dev *dev_d0f1; + u32 tolm; + u32 remapbase; + u32 remaplimit; + int mc_symmetric; + u8 map[8]; + int map_type; + const struct e752x_dev_info *dev_info; +}; + + +struct e752x_dev_info { + u16 err_dev; + const char *ctl_name; +}; + +struct e752x_error_info { + u32 ferr_global; + u32 nerr_global; + u8 hi_ferr; + u8 hi_nerr; + u16 sysbus_ferr; + u16 sysbus_nerr; + u8 buf_ferr; + u8 buf_nerr; + u16 dram_ferr; + u16 dram_nerr; + u32 dram_sec1_add; + u32 dram_sec2_add; + u16 dram_sec1_syndrome; + u16 dram_sec2_syndrome; + u32 dram_ded_add; + u32 dram_scrb_add; + u32 dram_retr_add; +}; + +static const struct e752x_dev_info e752x_devs[] = { + [E7520] = { + .err_dev = PCI_DEVICE_ID_INTEL_7520_1_ERR, + .ctl_name = "E7520"}, + [E7525] = { + .err_dev = PCI_DEVICE_ID_INTEL_7525_1_ERR, + .ctl_name = "E7525"}, + [E7320] = { + .err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR, + .ctl_name = "E7320"}, +}; + + +static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, + unsigned long page) +{ + u32 remap; + struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; + + debugf3("MC: " __FILE__ ": %s()\n", __func__); + + if (page < pvt->tolm) + return page; + if ((page >= 0x100000) && (page < pvt->remapbase)) + return page; + remap = (page - pvt->tolm) + pvt->remapbase; + if (remap < pvt->remaplimit) + return remap; + printk(KERN_ERR "Invalid page %lx - out of range\n", page); + return pvt->tolm - 1; +} + +static void do_process_ce(struct mem_ctl_info *mci, u16 error_one, + u32 sec1_add, u16 sec1_syndrome) +{ + u32 page; + int row; + int channel; + int i; + struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; + + debugf3("MC: " __FILE__ ": %s()\n", __func__); + + /* convert the addr to 4k page */ + page = sec1_add >> (PAGE_SHIFT - 4); + + /* FIXME - check for -1 */ + if (pvt->mc_symmetric) { + /* chip select are bits 14 & 13 */ + row = ((page >> 1) & 3); + printk(KERN_WARNING + "Test row %d Table %d %d %d %d %d %d %d %d\n", + row, pvt->map[0], pvt->map[1], pvt->map[2], + pvt->map[3], pvt->map[4], pvt->map[5], + pvt->map[6], pvt->map[7]); + + /* test for channel remapping */ + for (i = 0; i < 8; i++) { + if (pvt->map[i] == row) + break; + } + printk(KERN_WARNING "Test computed row %d\n", i); + if (i < 8) + row = i; + else + printk(KERN_WARNING + "MC%d: row %d not found in remap table\n", + mci->mc_idx, row); + } else + row = edac_mc_find_csrow_by_page(mci, page); + /* 0 = channel A, 1 = channel B */ + channel = !(error_one & 1); + + if (!pvt->map_type) + row = 7 - row; + edac_mc_handle_ce(mci, page, 0, sec1_syndrome, row, channel, + "e752x CE"); +} + + +static inline void process_ce(struct mem_ctl_info *mci, u16 error_one, + u32 sec1_add, u16 sec1_syndrome, int *error_found, + int handle_error) +{ + *error_found = 1; + + if (handle_error) + do_process_ce(mci, error_one, sec1_add, sec1_syndrome); +} + +static void do_process_ue(struct mem_ctl_info *mci, u16 error_one, u32 ded_add, + u32 scrb_add) +{ + u32 error_2b, block_page; + int row; + struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; + + debugf3("MC: " __FILE__ ": %s()\n", __func__); + + if (error_one & 0x0202) { + error_2b = ded_add; + /* convert to 4k address */ + block_page = error_2b >> (PAGE_SHIFT - 4); + row = pvt->mc_symmetric ? + /* chip select are bits 14 & 13 */ + ((block_page >> 1) & 3) : + edac_mc_find_csrow_by_page(mci, block_page); + edac_mc_handle_ue(mci, block_page, 0, row, + "e752x UE from Read"); + } + if (error_one & 0x0404) { + error_2b = scrb_add; + /* convert to 4k address */ + block_page = error_2b >> (PAGE_SHIFT - 4); + row = pvt->mc_symmetric ? + /* chip select are bits 14 & 13 */ + ((block_page >> 1) & 3) : + edac_mc_find_csrow_by_page(mci, block_page); + edac_mc_handle_ue(mci, block_page, 0, row, + "e752x UE from Scruber"); + } +} + +static inline void process_ue(struct mem_ctl_info *mci, u16 error_one, + u32 ded_add, u32 scrb_add, int *error_found, int handle_error) +{ + *error_found = 1; + + if (handle_error) + do_process_ue(mci, error_one, ded_add, scrb_add); +} + +static inline void process_ue_no_info_wr(struct mem_ctl_info *mci, + int *error_found, int handle_error) +{ + *error_found = 1; + + if (!handle_error) + return; + + debugf3("MC: " __FILE__ ": %s()\n", __func__); + edac_mc_handle_ue_no_info(mci, "e752x UE log memory write"); +} + +static void do_process_ded_retry(struct mem_ctl_info *mci, u16 error, + u32 retry_add) +{ + u32 error_1b, page; + int row; + struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; + + error_1b = retry_add; + page = error_1b >> (PAGE_SHIFT - 4); /* convert the addr to 4k page */ + row = pvt->mc_symmetric ? + ((page >> 1) & 3) : /* chip select are bits 14 & 13 */ + edac_mc_find_csrow_by_page(mci, page); + printk(KERN_WARNING + "MC%d: CE page 0x%lx, row %d : Memory read retry\n", + mci->mc_idx, (long unsigned int) page, row); +} + +static inline void process_ded_retry(struct mem_ctl_info *mci, u16 error, + u32 retry_add, int *error_found, int handle_error) +{ + *error_found = 1; + + if (handle_error) + do_process_ded_retry(mci, error, retry_add); +} + +static inline void process_threshold_ce(struct mem_ctl_info *mci, u16 error, + int *error_found, int handle_error) +{ + *error_found = 1; + + if (handle_error) + printk(KERN_WARNING "MC%d: Memory threshold CE\n", + mci->mc_idx); +} + +static char *global_message[11] = { + "PCI Express C1", "PCI Express C", "PCI Express B1", + "PCI Express B", "PCI Express A1", "PCI Express A", + "DMA Controler", "HUB Interface", "System Bus", + "DRAM Controler", "Internal Buffer" +}; + +static char *fatal_message[2] = { "Non-Fatal ", "Fatal " }; + +static void do_global_error(int fatal, u32 errors) +{ + int i; + + for (i = 0; i < 11; i++) { + if (errors & (1 << i)) + printk(KERN_WARNING "%sError %s\n", + fatal_message[fatal], global_message[i]); + } +} + +static inline void global_error(int fatal, u32 errors, int *error_found, + int handle_error) +{ + *error_found = 1; + + if (handle_error) + do_global_error(fatal, errors); +} + +static char *hub_message[7] = { + "HI Address or Command Parity", "HI Illegal Access", + "HI Internal Parity", "Out of Range Access", + "HI Data Parity", "Enhanced Config Access", + "Hub Interface Target Abort" +}; + +static void do_hub_error(int fatal, u8 errors) +{ + int i; + + for (i = 0; i < 7; i++) { + if (errors & (1 << i)) + printk(KERN_WARNING "%sError %s\n", + fatal_message[fatal], hub_message[i]); + } +} + +static inline void hub_error(int fatal, u8 errors, int *error_found, + int handle_error) +{ + *error_found = 1; + + if (handle_error) + do_hub_error(fatal, errors); +} + +static char *membuf_message[4] = { + "Internal PMWB to DRAM parity", + "Internal PMWB to System Bus Parity", + "Internal System Bus or IO to PMWB Parity", + "Internal DRAM to PMWB Parity" +}; + +static void do_membuf_error(u8 errors) +{ + int i; + + for (i = 0; i < 4; i++) { + if (errors & (1 << i)) + printk(KERN_WARNING "Non-Fatal Error %s\n", + membuf_message[i]); + } +} + +static inline void membuf_error(u8 errors, int *error_found, int handle_error) +{ + *error_found = 1; + + if (handle_error) + do_membuf_error(errors); +} + +#if 0 +char *sysbus_message[10] = { + "Addr or Request Parity", + "Data Strobe Glitch", + "Addr Strobe Glitch", + "Data Parity", + "Addr Above TOM", + "Non DRAM Lock Error", + "MCERR", "BINIT", + "Memory Parity", + "IO Subsystem Parity" +}; +#endif /* 0 */ + +static void do_sysbus_error(int fatal, u32 errors) +{ + int i; + + for (i = 0; i < 10; i++) { + if (errors & (1 << i)) + printk(KERN_WARNING "%sError System Bus %s\n", + fatal_message[fatal], global_message[i]); + } +} + +static inline void sysbus_error(int fatal, u32 errors, int *error_found, + int handle_error) +{ + *error_found = 1; + + if (handle_error) + do_sysbus_error(fatal, errors); +} + +static void e752x_check_hub_interface (struct e752x_error_info *info, + int *error_found, int handle_error) +{ + u8 stat8; + + //pci_read_config_byte(dev,E752X_HI_FERR,&stat8); + stat8 = info->hi_ferr; + if(stat8 & 0x7f) { /* Error, so process */ + stat8 &= 0x7f; + if(stat8 & 0x2b) + hub_error(1, stat8 & 0x2b, error_found, handle_error); + if(stat8 & 0x54) + hub_error(0, stat8 & 0x54, error_found, handle_error); + } + //pci_read_config_byte(dev,E752X_HI_NERR,&stat8); + stat8 = info->hi_nerr; + if(stat8 & 0x7f) { /* Error, so process */ + stat8 &= 0x7f; + if (stat8 & 0x2b) + hub_error(1, stat8 & 0x2b, error_found, handle_error); + if(stat8 & 0x54) + hub_error(0, stat8 & 0x54, error_found, handle_error); + } +} + +static void e752x_check_sysbus (struct e752x_error_info *info, int *error_found, + int handle_error) +{ + u32 stat32, error32; + + //pci_read_config_dword(dev,E752X_SYSBUS_FERR,&stat32); + stat32 = info->sysbus_ferr + (info->sysbus_nerr << 16); + + if (stat32 == 0) + return; /* no errors */ + + error32 = (stat32 >> 16) & 0x3ff; + stat32 = stat32 & 0x3ff; + if(stat32 & 0x083) + sysbus_error(1, stat32 & 0x083, error_found, handle_error); + if(stat32 & 0x37c) + sysbus_error(0, stat32 & 0x37c, error_found, handle_error); + if(error32 & 0x083) + sysbus_error(1, error32 & 0x083, error_found, handle_error); + if(error32 & 0x37c) + sysbus_error(0, error32 & 0x37c, error_found, handle_error); +} + +static void e752x_check_membuf (struct e752x_error_info *info, int *error_found, + int handle_error) +{ + u8 stat8; + + stat8 = info->buf_ferr; + if (stat8 & 0x0f) { /* Error, so process */ + stat8 &= 0x0f; + membuf_error(stat8, error_found, handle_error); + } + stat8 = info->buf_nerr; + if (stat8 & 0x0f) { /* Error, so process */ + stat8 &= 0x0f; + membuf_error(stat8, error_found, handle_error); + } +} + +static void e752x_check_dram (struct mem_ctl_info *mci, + struct e752x_error_info *info, int *error_found, int handle_error) +{ + u16 error_one, error_next; + + error_one = info->dram_ferr; + error_next = info->dram_nerr; + + /* decode and report errors */ + if(error_one & 0x0101) /* check first error correctable */ + process_ce(mci, error_one, info->dram_sec1_add, + info->dram_sec1_syndrome, error_found, + handle_error); + + if(error_next & 0x0101) /* check next error correctable */ + process_ce(mci, error_next, info->dram_sec2_add, + info->dram_sec2_syndrome, error_found, + handle_error); + + if(error_one & 0x4040) + process_ue_no_info_wr(mci, error_found, handle_error); + + if(error_next & 0x4040) + process_ue_no_info_wr(mci, error_found, handle_error); + + if(error_one & 0x2020) + process_ded_retry(mci, error_one, info->dram_retr_add, + error_found, handle_error); + + if(error_next & 0x2020) + process_ded_retry(mci, error_next, info->dram_retr_add, + error_found, handle_error); + + if(error_one & 0x0808) + process_threshold_ce(mci, error_one, error_found, + handle_error); + + if(error_next & 0x0808) + process_threshold_ce(mci, error_next, error_found, + handle_error); + + if(error_one & 0x0606) + process_ue(mci, error_one, info->dram_ded_add, + info->dram_scrb_add, error_found, handle_error); + + if(error_next & 0x0606) + process_ue(mci, error_next, info->dram_ded_add, + info->dram_scrb_add, error_found, handle_error); +} + +static void e752x_get_error_info (struct mem_ctl_info *mci, + struct e752x_error_info *info) +{ + struct pci_dev *dev; + struct e752x_pvt *pvt; + + memset(info, 0, sizeof(*info)); + pvt = (struct e752x_pvt *) mci->pvt_info; + dev = pvt->dev_d0f1; + + pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global); + + if (info->ferr_global) { + pci_read_config_byte(dev, E752X_HI_FERR, &info->hi_ferr); + pci_read_config_word(dev, E752X_SYSBUS_FERR, + &info->sysbus_ferr); + pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr); + pci_read_config_word(dev, E752X_DRAM_FERR, + &info->dram_ferr); + pci_read_config_dword(dev, E752X_DRAM_SEC1_ADD, + &info->dram_sec1_add); + pci_read_config_word(dev, E752X_DRAM_SEC1_SYNDROME, + &info->dram_sec1_syndrome); + pci_read_config_dword(dev, E752X_DRAM_DED_ADD, + &info->dram_ded_add); + pci_read_config_dword(dev, E752X_DRAM_SCRB_ADD, + &info->dram_scrb_add); + pci_read_config_dword(dev, E752X_DRAM_RETR_ADD, + &info->dram_retr_add); + + if (info->hi_ferr & 0x7f) + pci_write_config_byte(dev, E752X_HI_FERR, + info->hi_ferr); + + if (info->sysbus_ferr) + pci_write_config_word(dev, E752X_SYSBUS_FERR, + info->sysbus_ferr); + + if (info->buf_ferr & 0x0f) + pci_write_config_byte(dev, E752X_BUF_FERR, + info->buf_ferr); + + if (info->dram_ferr) + pci_write_bits16(pvt->bridge_ck, E752X_DRAM_FERR, + info->dram_ferr, info->dram_ferr); + + pci_write_config_dword(dev, E752X_FERR_GLOBAL, + info->ferr_global); + } + + pci_read_config_dword(dev, E752X_NERR_GLOBAL, &info->nerr_global); + + if (info->nerr_global) { + pci_read_config_byte(dev, E752X_HI_NERR, &info->hi_nerr); + pci_read_config_word(dev, E752X_SYSBUS_NERR, + &info->sysbus_nerr); + pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr); + pci_read_config_word(dev, E752X_DRAM_NERR, + &info->dram_nerr); + pci_read_config_dword(dev, E752X_DRAM_SEC2_ADD, + &info->dram_sec2_add); + pci_read_config_word(dev, E752X_DRAM_SEC2_SYNDROME, + &info->dram_sec2_syndrome); + + if (info->hi_nerr & 0x7f) + pci_write_config_byte(dev, E752X_HI_NERR, + info->hi_nerr); + + if (info->sysbus_nerr) + pci_write_config_word(dev, E752X_SYSBUS_NERR, + info->sysbus_nerr); + + if (info->buf_nerr & 0x0f) + pci_write_config_byte(dev, E752X_BUF_NERR, + info->buf_nerr); + + if (info->dram_nerr) + pci_write_bits16(pvt->bridge_ck, E752X_DRAM_NERR, + info->dram_nerr, info->dram_nerr); + + pci_write_config_dword(dev, E752X_NERR_GLOBAL, + info->nerr_global); + } +} + +static int e752x_process_error_info (struct mem_ctl_info *mci, + struct e752x_error_info *info, int handle_errors) +{ + u32 error32, stat32; + int error_found; + + error_found = 0; + error32 = (info->ferr_global >> 18) & 0x3ff; + stat32 = (info->ferr_global >> 4) & 0x7ff; + + if (error32) + global_error(1, error32, &error_found, handle_errors); + + if (stat32) + global_error(0, stat32, &error_found, handle_errors); + + error32 = (info->nerr_global >> 18) & 0x3ff; + stat32 = (info->nerr_global >> 4) & 0x7ff; + + if (error32) + global_error(1, error32, &error_found, handle_errors); + + if (stat32) + global_error(0, stat32, &error_found, handle_errors); + + e752x_check_hub_interface(info, &error_found, handle_errors); + e752x_check_sysbus(info, &error_found, handle_errors); + e752x_check_membuf(info, &error_found, handle_errors); + e752x_check_dram(mci, info, &error_found, handle_errors); + return error_found; +} + +static void e752x_check(struct mem_ctl_info *mci) +{ + struct e752x_error_info info; + debugf3("MC: " __FILE__ ": %s()\n", __func__); + e752x_get_error_info(mci, &info); + e752x_process_error_info(mci, &info, 1); +} + +static int e752x_probe1(struct pci_dev *pdev, int dev_idx) +{ + int rc = -ENODEV; + int index; + u16 pci_data, stat; + u32 stat32; + u16 stat16; + u8 stat8; + struct mem_ctl_info *mci = NULL; + struct e752x_pvt *pvt = NULL; + u16 ddrcsr; + u32 drc; + int drc_chan; /* Number of channels 0=1chan,1=2chan */ + int drc_drbg; /* DRB granularity 0=64mb,1=128mb */ + int drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ + u32 dra; + unsigned long last_cumul_size; + struct pci_dev *pres_dev; + struct pci_dev *dev = NULL; + + debugf0("MC: " __FILE__ ": %s(): mci\n", __func__); + debugf0("Starting Probe1\n"); + + /* enable device 0 function 1 */ + pci_read_config_byte(pdev, E752X_DEVPRES1, &stat8); + stat8 |= (1 << 5); + pci_write_config_byte(pdev, E752X_DEVPRES1, stat8); + + /* need to find out the number of channels */ + pci_read_config_dword(pdev, E752X_DRC, &drc); + pci_read_config_word(pdev, E752X_DDRCSR, &ddrcsr); + /* FIXME: should check >>12 or 0xf, true for all? */ + /* Dual channel = 1, Single channel = 0 */ + drc_chan = (((ddrcsr >> 12) & 3) == 3); + drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */ + drc_ddim = (drc >> 20) & 0x3; + + mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1); + + if (mci == NULL) { + rc = -ENOMEM; + goto fail; + } + + debugf3("MC: " __FILE__ ": %s(): init mci\n", __func__); + + mci->mtype_cap = MEM_FLAG_RDDR; + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | + EDAC_FLAG_S4ECD4ED; + /* FIXME - what if different memory types are in different csrows? */ + mci->mod_name = BS_MOD_STR; + mci->mod_ver = "$Revision: 1.5.2.11 $"; + mci->pdev = pdev; + + debugf3("MC: " __FILE__ ": %s(): init pvt\n", __func__); + pvt = (struct e752x_pvt *) mci->pvt_info; + pvt->dev_info = &e752x_devs[dev_idx]; + pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, + pvt->dev_info->err_dev, + pvt->bridge_ck); + if (pvt->bridge_ck == NULL) + pvt->bridge_ck = pci_scan_single_device(pdev->bus, + PCI_DEVFN(0, 1)); + if (pvt->bridge_ck == NULL) { + printk(KERN_ERR "MC: error reporting device not found:" + "vendor %x device 0x%x (broken BIOS?)\n", + PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev); + goto fail; + } + pvt->mc_symmetric = ((ddrcsr & 0x10) != 0); + + debugf3("MC: " __FILE__ ": %s(): more mci init\n", __func__); + mci->ctl_name = pvt->dev_info->ctl_name; + mci->edac_check = e752x_check; + mci->ctl_page_to_phys = ctl_page_to_phys; + + /* find out the device types */ + pci_read_config_dword(pdev, E752X_DRA, &dra); + + /* + * The dram row boundary (DRB) reg values are boundary address for + * each DRAM row with a granularity of 64 or 128MB (single/dual + * channel operation). DRB regs are cumulative; therefore DRB7 will + * contain the total memory contained in all eight rows. + */ + for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { + u8 value; + u32 cumul_size; + /* mem_dev 0=x8, 1=x4 */ + int mem_dev = (dra >> (index * 4 + 2)) & 0x3; + struct csrow_info *csrow = &mci->csrows[index]; + + mem_dev = (mem_dev == 2); + pci_read_config_byte(mci->pdev, E752X_DRB + index, &value); + /* convert a 128 or 64 MiB DRB to a page size. */ + cumul_size = value << (25 + drc_drbg - PAGE_SHIFT); + debugf3("MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n", + __func__, index, cumul_size); + if (cumul_size == last_cumul_size) + continue; /* not populated */ + + csrow->first_page = last_cumul_size; + csrow->last_page = cumul_size - 1; + csrow->nr_pages = cumul_size - last_cumul_size; + last_cumul_size = cumul_size; + csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ + csrow->mtype = MEM_RDDR; /* only one type supported */ + csrow->dtype = mem_dev ? DEV_X4 : DEV_X8; + + /* + * if single channel or x8 devices then SECDED + * if dual channel and x4 then S4ECD4ED + */ + if (drc_ddim) { + if (drc_chan && mem_dev) { + csrow->edac_mode = EDAC_S4ECD4ED; + mci->edac_cap |= EDAC_FLAG_S4ECD4ED; + } else { + csrow->edac_mode = EDAC_SECDED; + mci->edac_cap |= EDAC_FLAG_SECDED; + } + } else + csrow->edac_mode = EDAC_NONE; + } + + /* Fill in the memory map table */ + { + u8 value; + u8 last = 0; + u8 row = 0; + for (index = 0; index < 8; index += 2) { + + pci_read_config_byte(mci->pdev, E752X_DRB + index, + &value); + /* test if there is a dimm in this slot */ + if (value == last) { + /* no dimm in the slot, so flag it as empty */ + pvt->map[index] = 0xff; + pvt->map[index + 1] = 0xff; + } else { /* there is a dimm in the slot */ + pvt->map[index] = row; + row++; + last = value; + /* test the next value to see if the dimm is + double sided */ + pci_read_config_byte(mci->pdev, + E752X_DRB + index + 1, + &value); + pvt->map[index + 1] = (value == last) ? + 0xff : /* the dimm is single sided, + so flag as empty */ + row; /* this is a double sided dimm + to save the next row # */ + row++; + last = value; + } + } + } + + /* set the map type. 1 = normal, 0 = reversed */ + pci_read_config_byte(mci->pdev, E752X_DRM, &stat8); + pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f)); + + mci->edac_cap |= EDAC_FLAG_NONE; + + debugf3("MC: " __FILE__ ": %s(): tolm, remapbase, remaplimit\n", + __func__); + /* load the top of low memory, remap base, and remap limit vars */ + pci_read_config_word(mci->pdev, E752X_TOLM, &pci_data); + pvt->tolm = ((u32) pci_data) << 4; + pci_read_config_word(mci->pdev, E752X_REMAPBASE, &pci_data); + pvt->remapbase = ((u32) pci_data) << 14; + pci_read_config_word(mci->pdev, E752X_REMAPLIMIT, &pci_data); + pvt->remaplimit = ((u32) pci_data) << 14; + printk("tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm, + pvt->remapbase, pvt->remaplimit); + + if (edac_mc_add_mc(mci)) { + debugf3("MC: " __FILE__ + ": %s(): failed edac_mc_add_mc()\n", + __func__); + goto fail; + } + + /* Walk through the PCI table and clear errors */ + switch (dev_idx) { + case E7520: + dev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_7520_0, NULL); + break; + case E7525: + dev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_7525_0, NULL); + break; + case E7320: + dev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_7320_0, NULL); + break; + } + + + pvt->dev_d0f0 = dev; + for (pres_dev = dev; + ((struct pci_dev *) pres_dev->global_list.next != dev); + pres_dev = (struct pci_dev *) pres_dev->global_list.next) { + pci_read_config_dword(pres_dev, PCI_COMMAND, &stat32); + stat = (u16) (stat32 >> 16); + /* clear any error bits */ + if (stat32 & ((1 << 6) + (1 << 8))) + pci_write_config_word(pres_dev, PCI_STATUS, stat); + } + /* find the error reporting device and clear errors */ + dev = pvt->dev_d0f1 = pci_dev_get(pvt->bridge_ck); + /* Turn off error disable & SMI in case the BIOS turned it on */ + pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00); + pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00); + pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x00); + pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00); + pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00); + pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00); + pci_write_config_byte(dev, E752X_DRAM_ERRMASK, 0x00); + pci_write_config_byte(dev, E752X_DRAM_SMICMD, 0x00); + /* clear other MCH errors */ + pci_read_config_dword(dev, E752X_FERR_GLOBAL, &stat32); + pci_write_config_dword(dev, E752X_FERR_GLOBAL, stat32); + pci_read_config_dword(dev, E752X_NERR_GLOBAL, &stat32); + pci_write_config_dword(dev, E752X_NERR_GLOBAL, stat32); + pci_read_config_byte(dev, E752X_HI_FERR, &stat8); + pci_write_config_byte(dev, E752X_HI_FERR, stat8); + pci_read_config_byte(dev, E752X_HI_NERR, &stat8); + pci_write_config_byte(dev, E752X_HI_NERR, stat8); + pci_read_config_dword(dev, E752X_SYSBUS_FERR, &stat32); + pci_write_config_dword(dev, E752X_SYSBUS_FERR, stat32); + pci_read_config_byte(dev, E752X_BUF_FERR, &stat8); + pci_write_config_byte(dev, E752X_BUF_FERR, stat8); + pci_read_config_byte(dev, E752X_BUF_NERR, &stat8); + pci_write_config_byte(dev, E752X_BUF_NERR, stat8); + pci_read_config_word(dev, E752X_DRAM_FERR, &stat16); + pci_write_config_word(dev, E752X_DRAM_FERR, stat16); + pci_read_config_word(dev, E752X_DRAM_NERR, &stat16); + pci_write_config_word(dev, E752X_DRAM_NERR, stat16); + + /* get this far and it's successful */ + debugf3("MC: " __FILE__ ": %s(): success\n", __func__); + return 0; + +fail: + if (mci) { + if (pvt->dev_d0f0) + pci_dev_put(pvt->dev_d0f0); + if (pvt->dev_d0f1) + pci_dev_put(pvt->dev_d0f1); + if (pvt->bridge_ck) + pci_dev_put(pvt->bridge_ck); + edac_mc_free(mci); + } + return rc; +} + +/* returns count (>= 0), or negative on error */ +static int __devinit e752x_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + debugf0("MC: " __FILE__ ": %s()\n", __func__); + + /* wake up and enable device */ + if(pci_enable_device(pdev) < 0) + return -EIO; + return e752x_probe1(pdev, ent->driver_data); +} + + +static void __devexit e752x_remove_one(struct pci_dev *pdev) +{ + struct mem_ctl_info *mci; + struct e752x_pvt *pvt; + + debugf0(__FILE__ ": %s()\n", __func__); + + if ((mci = edac_mc_find_mci_by_pdev(pdev)) == NULL) + return; + + if (edac_mc_del_mc(mci)) + return; + + pvt = (struct e752x_pvt *) mci->pvt_info; + pci_dev_put(pvt->dev_d0f0); + pci_dev_put(pvt->dev_d0f1); + pci_dev_put(pvt->bridge_ck); + edac_mc_free(mci); +} + + +static const struct pci_device_id e752x_pci_tbl[] __devinitdata = { + {PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, + E7520}, + {PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, + E7525}, + {PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, + E7320}, + {0,} /* 0 terminated list. */ +}; + +MODULE_DEVICE_TABLE(pci, e752x_pci_tbl); + + +static struct pci_driver e752x_driver = { + name: BS_MOD_STR, + probe: e752x_init_one, + remove: __devexit_p(e752x_remove_one), + id_table: e752x_pci_tbl, +}; + + +static int __init e752x_init(void) +{ + int pci_rc; + + debugf3("MC: " __FILE__ ": %s()\n", __func__); + pci_rc = pci_register_driver(&e752x_driver); + return (pci_rc < 0) ? pci_rc : 0; +} + + +static void __exit e752x_exit(void) +{ + debugf3("MC: " __FILE__ ": %s()\n", __func__); + pci_unregister_driver(&e752x_driver); +} + + +module_init(e752x_init); +module_exit(e752x_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n"); +MODULE_DESCRIPTION("MC support for Intel e752x memory controllers"); diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c new file mode 100644 index 000000000000..d5e320dfc66f --- /dev/null +++ b/drivers/edac/e7xxx_edac.c @@ -0,0 +1,558 @@ +/* + * Intel e7xxx Memory Controller kernel module + * (C) 2003 Linux Networx (http://lnxi.com) + * This file may be distributed under the terms of the + * GNU General Public License. + * + * See "enum e7xxx_chips" below for supported chipsets + * + * Written by Thayne Harbaugh + * Based on work by Dan Hollis <goemon at anime dot net> and others. + * http://www.anime.net/~goemon/linux-ecc/ + * + * Contributors: + * Eric Biederman (Linux Networx) + * Tom Zimmerman (Linux Networx) + * Jim Garlick (Lawrence Livermore National Labs) + * Dave Peterson (Lawrence Livermore National Labs) + * That One Guy (Some other place) + * Wang Zhenyu (intel.com) + * + * $Id: edac_e7xxx.c,v 1.5.2.9 2005/10/05 00:43:44 dsp_llnl Exp $ + * + */ + + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> +#include <linux/slab.h> +#include "edac_mc.h" + + +#ifndef PCI_DEVICE_ID_INTEL_7205_0 +#define PCI_DEVICE_ID_INTEL_7205_0 0x255d +#endif /* PCI_DEVICE_ID_INTEL_7205_0 */ + +#ifndef PCI_DEVICE_ID_INTEL_7205_1_ERR +#define PCI_DEVICE_ID_INTEL_7205_1_ERR 0x2551 +#endif /* PCI_DEVICE_ID_INTEL_7205_1_ERR */ + +#ifndef PCI_DEVICE_ID_INTEL_7500_0 +#define PCI_DEVICE_ID_INTEL_7500_0 0x2540 +#endif /* PCI_DEVICE_ID_INTEL_7500_0 */ + +#ifndef PCI_DEVICE_ID_INTEL_7500_1_ERR +#define PCI_DEVICE_ID_INTEL_7500_1_ERR 0x2541 +#endif /* PCI_DEVICE_ID_INTEL_7500_1_ERR */ + +#ifndef PCI_DEVICE_ID_INTEL_7501_0 +#define PCI_DEVICE_ID_INTEL_7501_0 0x254c +#endif /* PCI_DEVICE_ID_INTEL_7501_0 */ + +#ifndef PCI_DEVICE_ID_INTEL_7501_1_ERR +#define PCI_DEVICE_ID_INTEL_7501_1_ERR 0x2541 +#endif /* PCI_DEVICE_ID_INTEL_7501_1_ERR */ + +#ifndef PCI_DEVICE_ID_INTEL_7505_0 +#define PCI_DEVICE_ID_INTEL_7505_0 0x2550 +#endif /* PCI_DEVICE_ID_INTEL_7505_0 */ + +#ifndef PCI_DEVICE_ID_INTEL_7505_1_ERR +#define PCI_DEVICE_ID_INTEL_7505_1_ERR 0x2551 +#endif /* PCI_DEVICE_ID_INTEL_7505_1_ERR */ + + +#define E7XXX_NR_CSROWS 8 /* number of csrows */ +#define E7XXX_NR_DIMMS 8 /* FIXME - is this correct? */ + + +/* E7XXX register addresses - device 0 function 0 */ +#define E7XXX_DRB 0x60 /* DRAM row boundary register (8b) */ +#define E7XXX_DRA 0x70 /* DRAM row attribute register (8b) */ + /* + * 31 Device width row 7 0=x8 1=x4 + * 27 Device width row 6 + * 23 Device width row 5 + * 19 Device width row 4 + * 15 Device width row 3 + * 11 Device width row 2 + * 7 Device width row 1 + * 3 Device width row 0 + */ +#define E7XXX_DRC 0x7C /* DRAM controller mode reg (32b) */ + /* + * 22 Number channels 0=1,1=2 + * 19:18 DRB Granularity 32/64MB + */ +#define E7XXX_TOLM 0xC4 /* DRAM top of low memory reg (16b) */ +#define E7XXX_REMAPBASE 0xC6 /* DRAM remap base address reg (16b) */ +#define E7XXX_REMAPLIMIT 0xC8 /* DRAM remap limit address reg (16b) */ + +/* E7XXX register addresses - device 0 function 1 */ +#define E7XXX_DRAM_FERR 0x80 /* DRAM first error register (8b) */ +#define E7XXX_DRAM_NERR 0x82 /* DRAM next error register (8b) */ +#define E7XXX_DRAM_CELOG_ADD 0xA0 /* DRAM first correctable memory */ + /* error address register (32b) */ + /* + * 31:28 Reserved + * 27:6 CE address (4k block 33:12) + * 5:0 Reserved + */ +#define E7XXX_DRAM_UELOG_ADD 0xB0 /* DRAM first uncorrectable memory */ + /* error address register (32b) */ + /* + * 31:28 Reserved + * 27:6 CE address (4k block 33:12) + * 5:0 Reserved + */ +#define E7XXX_DRAM_CELOG_SYNDROME 0xD0 /* DRAM first correctable memory */ + /* error syndrome register (16b) */ + +enum e7xxx_chips { + E7500 = 0, + E7501, + E7505, + E7205, +}; + + +struct e7xxx_pvt { + struct pci_dev *bridge_ck; + u32 tolm; + u32 remapbase; + u32 remaplimit; + const struct e7xxx_dev_info *dev_info; +}; + + +struct e7xxx_dev_info { + u16 err_dev; + const char *ctl_name; +}; + + +struct e7xxx_error_info { + u8 dram_ferr; + u8 dram_nerr; + u32 dram_celog_add; + u16 dram_celog_syndrome; + u32 dram_uelog_add; +}; + +static const struct e7xxx_dev_info e7xxx_devs[] = { + [E7500] = { + .err_dev = PCI_DEVICE_ID_INTEL_7500_1_ERR, + .ctl_name = "E7500"}, + [E7501] = { + .err_dev = PCI_DEVICE_ID_INTEL_7501_1_ERR, + .ctl_name = "E7501"}, + [E7505] = { + .err_dev = PCI_DEVICE_ID_INTEL_7505_1_ERR, + .ctl_name = "E7505"}, + [E7205] = { + .err_dev = PCI_DEVICE_ID_INTEL_7205_1_ERR, + .ctl_name = "E7205"}, +}; + + +/* FIXME - is this valid for both SECDED and S4ECD4ED? */ +static inline int e7xxx_find_channel(u16 syndrome) +{ + debugf3("MC: " __FILE__ ": %s()\n", __func__); + + if ((syndrome & 0xff00) == 0) + return 0; + if ((syndrome & 0x00ff) == 0) + return 1; + if ((syndrome & 0xf000) == 0 || (syndrome & 0x0f00) == 0) + return 0; + return 1; +} + + +static unsigned long +ctl_page_to_phys(struct mem_ctl_info *mci, unsigned long page) +{ + u32 remap; + struct e7xxx_pvt *pvt = (struct e7xxx_pvt *) mci->pvt_info; + + debugf3("MC: " __FILE__ ": %s()\n", __func__); + + if ((page < pvt->tolm) || + ((page >= 0x100000) && (page < pvt->remapbase))) + return page; + remap = (page - pvt->tolm) + pvt->remapbase; + if (remap < pvt->remaplimit) + return remap; + printk(KERN_ERR "Invalid page %lx - out of range\n", page); + return pvt->tolm - 1; +} + + +static void process_ce(struct mem_ctl_info *mci, struct e7xxx_error_info *info) +{ + u32 error_1b, page; + u16 syndrome; + int row; + int channel; + + debugf3("MC: " __FILE__ ": %s()\n", __func__); + + /* read the error address */ + error_1b = info->dram_celog_add; + /* FIXME - should use PAGE_SHIFT */ + page = error_1b >> 6; /* convert the address to 4k page */ + /* read the syndrome */ + syndrome = info->dram_celog_syndrome; + /* FIXME - check for -1 */ + row = edac_mc_find_csrow_by_page(mci, page); + /* convert syndrome to channel */ + channel = e7xxx_find_channel(syndrome); + edac_mc_handle_ce(mci, page, 0, syndrome, row, channel, + "e7xxx CE"); +} + + +static void process_ce_no_info(struct mem_ctl_info *mci) +{ + debugf3("MC: " __FILE__ ": %s()\n", __func__); + edac_mc_handle_ce_no_info(mci, "e7xxx CE log register overflow"); +} + + +static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info) +{ + u32 error_2b, block_page; + int row; + + debugf3("MC: " __FILE__ ": %s()\n", __func__); + + /* read the error address */ + error_2b = info->dram_uelog_add; + /* FIXME - should use PAGE_SHIFT */ + block_page = error_2b >> 6; /* convert to 4k address */ + row = edac_mc_find_csrow_by_page(mci, block_page); + edac_mc_handle_ue(mci, block_page, 0, row, "e7xxx UE"); +} + + +static void process_ue_no_info(struct mem_ctl_info *mci) +{ + debugf3("MC: " __FILE__ ": %s()\n", __func__); + edac_mc_handle_ue_no_info(mci, "e7xxx UE log register overflow"); +} + + +static void e7xxx_get_error_info (struct mem_ctl_info *mci, + struct e7xxx_error_info *info) +{ + struct e7xxx_pvt *pvt; + + pvt = (struct e7xxx_pvt *) mci->pvt_info; + pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_FERR, + &info->dram_ferr); + pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_NERR, + &info->dram_nerr); + + if ((info->dram_ferr & 1) || (info->dram_nerr & 1)) { + pci_read_config_dword(pvt->bridge_ck, E7XXX_DRAM_CELOG_ADD, + &info->dram_celog_add); + pci_read_config_word(pvt->bridge_ck, + E7XXX_DRAM_CELOG_SYNDROME, &info->dram_celog_syndrome); + } + + if ((info->dram_ferr & 2) || (info->dram_nerr & 2)) + pci_read_config_dword(pvt->bridge_ck, E7XXX_DRAM_UELOG_ADD, + &info->dram_uelog_add); + + if (info->dram_ferr & 3) + pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_FERR, 0x03, + 0x03); + + if (info->dram_nerr & 3) + pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, + 0x03); +} + + +static int e7xxx_process_error_info (struct mem_ctl_info *mci, + struct e7xxx_error_info *info, int handle_errors) +{ + int error_found; + + error_found = 0; + + /* decode and report errors */ + if (info->dram_ferr & 1) { /* check first error correctable */ + error_found = 1; + + if (handle_errors) + process_ce(mci, info); + } + + if (info->dram_ferr & 2) { /* check first error uncorrectable */ + error_found = 1; + + if (handle_errors) + process_ue(mci, info); + } + + if (info->dram_nerr & 1) { /* check next error correctable */ + error_found = 1; + + if (handle_errors) { + if (info->dram_ferr & 1) + process_ce_no_info(mci); + else + process_ce(mci, info); + } + } + + if (info->dram_nerr & 2) { /* check next error uncorrectable */ + error_found = 1; + + if (handle_errors) { + if (info->dram_ferr & 2) + process_ue_no_info(mci); + else + process_ue(mci, info); + } + } + + return error_found; +} + + +static void e7xxx_check(struct mem_ctl_info *mci) +{ + struct e7xxx_error_info info; + + debugf3("MC: " __FILE__ ": %s()\n", __func__); + e7xxx_get_error_info(mci, &info); + e7xxx_process_error_info(mci, &info, 1); +} + + +static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) +{ + int rc = -ENODEV; + int index; + u16 pci_data; + struct mem_ctl_info *mci = NULL; + struct e7xxx_pvt *pvt = NULL; + u32 drc; + int drc_chan = 1; /* Number of channels 0=1chan,1=2chan */ + int drc_drbg = 1; /* DRB granularity 0=32mb,1=64mb */ + int drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ + u32 dra; + unsigned long last_cumul_size; + + + debugf0("MC: " __FILE__ ": %s(): mci\n", __func__); + + /* need to find out the number of channels */ + pci_read_config_dword(pdev, E7XXX_DRC, &drc); + /* only e7501 can be single channel */ + if (dev_idx == E7501) { + drc_chan = ((drc >> 22) & 0x1); + drc_drbg = (drc >> 18) & 0x3; + } + drc_ddim = (drc >> 20) & 0x3; + + mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1); + + if (mci == NULL) { + rc = -ENOMEM; + goto fail; + } + + debugf3("MC: " __FILE__ ": %s(): init mci\n", __func__); + + mci->mtype_cap = MEM_FLAG_RDDR; + mci->edac_ctl_cap = + EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED; + /* FIXME - what if different memory types are in different csrows? */ + mci->mod_name = BS_MOD_STR; + mci->mod_ver = "$Revision: 1.5.2.9 $"; + mci->pdev = pdev; + + debugf3("MC: " __FILE__ ": %s(): init pvt\n", __func__); + pvt = (struct e7xxx_pvt *) mci->pvt_info; + pvt->dev_info = &e7xxx_devs[dev_idx]; + pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, + pvt->dev_info->err_dev, + pvt->bridge_ck); + if (!pvt->bridge_ck) { + printk(KERN_ERR + "MC: error reporting device not found:" + "vendor %x device 0x%x (broken BIOS?)\n", + PCI_VENDOR_ID_INTEL, e7xxx_devs[dev_idx].err_dev); + goto fail; + } + + debugf3("MC: " __FILE__ ": %s(): more mci init\n", __func__); + mci->ctl_name = pvt->dev_info->ctl_name; + + mci->edac_check = e7xxx_check; + mci->ctl_page_to_phys = ctl_page_to_phys; + + /* find out the device types */ + pci_read_config_dword(pdev, E7XXX_DRA, &dra); + + /* + * The dram row boundary (DRB) reg values are boundary address + * for each DRAM row with a granularity of 32 or 64MB (single/dual + * channel operation). DRB regs are cumulative; therefore DRB7 will + * contain the total memory contained in all eight rows. + */ + for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { + u8 value; + u32 cumul_size; + /* mem_dev 0=x8, 1=x4 */ + int mem_dev = (dra >> (index * 4 + 3)) & 0x1; + struct csrow_info *csrow = &mci->csrows[index]; + + pci_read_config_byte(mci->pdev, E7XXX_DRB + index, &value); + /* convert a 64 or 32 MiB DRB to a page size. */ + cumul_size = value << (25 + drc_drbg - PAGE_SHIFT); + debugf3("MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n", + __func__, index, cumul_size); + if (cumul_size == last_cumul_size) + continue; /* not populated */ + + csrow->first_page = last_cumul_size; + csrow->last_page = cumul_size - 1; + csrow->nr_pages = cumul_size - last_cumul_size; + last_cumul_size = cumul_size; + csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ + csrow->mtype = MEM_RDDR; /* only one type supported */ + csrow->dtype = mem_dev ? DEV_X4 : DEV_X8; + + /* + * if single channel or x8 devices then SECDED + * if dual channel and x4 then S4ECD4ED + */ + if (drc_ddim) { + if (drc_chan && mem_dev) { + csrow->edac_mode = EDAC_S4ECD4ED; + mci->edac_cap |= EDAC_FLAG_S4ECD4ED; + } else { + csrow->edac_mode = EDAC_SECDED; + mci->edac_cap |= EDAC_FLAG_SECDED; + } + } else + csrow->edac_mode = EDAC_NONE; + } + + mci->edac_cap |= EDAC_FLAG_NONE; + + debugf3("MC: " __FILE__ ": %s(): tolm, remapbase, remaplimit\n", + __func__); + /* load the top of low memory, remap base, and remap limit vars */ + pci_read_config_word(mci->pdev, E7XXX_TOLM, &pci_data); + pvt->tolm = ((u32) pci_data) << 4; + pci_read_config_word(mci->pdev, E7XXX_REMAPBASE, &pci_data); + pvt->remapbase = ((u32) pci_data) << 14; + pci_read_config_word(mci->pdev, E7XXX_REMAPLIMIT, &pci_data); + pvt->remaplimit = ((u32) pci_data) << 14; + printk("tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm, + pvt->remapbase, pvt->remaplimit); + + /* clear any pending errors, or initial state bits */ + pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_FERR, 0x03, 0x03); + pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03); + + if (edac_mc_add_mc(mci) != 0) { + debugf3("MC: " __FILE__ + ": %s(): failed edac_mc_add_mc()\n", + __func__); + goto fail; + } + + /* get this far and it's successful */ + debugf3("MC: " __FILE__ ": %s(): success\n", __func__); + return 0; + +fail: + if (mci != NULL) { + if(pvt != NULL && pvt->bridge_ck) + pci_dev_put(pvt->bridge_ck); + edac_mc_free(mci); + } + + return rc; +} + +/* returns count (>= 0), or negative on error */ +static int __devinit +e7xxx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + debugf0("MC: " __FILE__ ": %s()\n", __func__); + + /* wake up and enable device */ + return pci_enable_device(pdev) ? + -EIO : e7xxx_probe1(pdev, ent->driver_data); +} + + +static void __devexit e7xxx_remove_one(struct pci_dev *pdev) +{ + struct mem_ctl_info *mci; + struct e7xxx_pvt *pvt; + + debugf0(__FILE__ ": %s()\n", __func__); + + if (((mci = edac_mc_find_mci_by_pdev(pdev)) != 0) && + edac_mc_del_mc(mci)) { + pvt = (struct e7xxx_pvt *) mci->pvt_info; + pci_dev_put(pvt->bridge_ck); + edac_mc_free(mci); + } +} + + +static const struct pci_device_id e7xxx_pci_tbl[] __devinitdata = { + {PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, + E7205}, + {PCI_VEND_DEV(INTEL, 7500_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, + E7500}, + {PCI_VEND_DEV(INTEL, 7501_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, + E7501}, + {PCI_VEND_DEV(INTEL, 7505_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, + E7505}, + {0,} /* 0 terminated list. */ +}; + +MODULE_DEVICE_TABLE(pci, e7xxx_pci_tbl); + + +static struct pci_driver e7xxx_driver = { + .name = BS_MOD_STR, + .probe = e7xxx_init_one, + .remove = __devexit_p(e7xxx_remove_one), + .id_table = e7xxx_pci_tbl, +}; + + +static int __init e7xxx_init(void) +{ + return pci_register_driver(&e7xxx_driver); +} + + +static void __exit e7xxx_exit(void) +{ + pci_unregister_driver(&e7xxx_driver); +} + +module_init(e7xxx_init); +module_exit(e7xxx_exit); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n" + "Based on.work by Dan Hollis et al"); +MODULE_DESCRIPTION("MC support for Intel e7xxx memory controllers"); diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c new file mode 100644 index 000000000000..4be9bd0a1267 --- /dev/null +++ b/drivers/edac/edac_mc.c @@ -0,0 +1,2209 @@ +/* + * edac_mc kernel module + * (C) 2005 Linux Networx (http://lnxi.com) + * This file may be distributed under the terms of the + * GNU General Public License. + * + * Written by Thayne Harbaugh + * Based on work by Dan Hollis <goemon at anime dot net> and others. + * http://www.anime.net/~goemon/linux-ecc/ + * + * Modified by Dave Peterson and Doug Thompson + * + */ + + +#include <linux/config.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/proc_fs.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/smp.h> +#include <linux/init.h> +#include <linux/sysctl.h> +#include <linux/highmem.h> +#include <linux/timer.h> +#include <linux/slab.h> +#include <linux/jiffies.h> +#include <linux/spinlock.h> +#include <linux/list.h> +#include <linux/sysdev.h> +#include <linux/ctype.h> + +#include <asm/uaccess.h> +#include <asm/page.h> +#include <asm/edac.h> + +#include "edac_mc.h" + +#define EDAC_MC_VERSION "edac_mc Ver: 2.0.0 " __DATE__ + +#ifdef CONFIG_EDAC_DEBUG +/* Values of 0 to 4 will generate output */ +int edac_debug_level = 1; +EXPORT_SYMBOL(edac_debug_level); +#endif + +/* EDAC Controls, setable by module parameter, and sysfs */ +static int log_ue = 1; +static int log_ce = 1; +static int panic_on_ue = 1; +static int poll_msec = 1000; + +static int check_pci_parity = 0; /* default YES check PCI parity */ +static int panic_on_pci_parity; /* default no panic on PCI Parity */ +static atomic_t pci_parity_count = ATOMIC_INIT(0); + +/* lock to memory controller's control array */ +static DECLARE_MUTEX(mem_ctls_mutex); +static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices); + +/* Structure of the whitelist and blacklist arrays */ +struct edac_pci_device_list { + unsigned int vendor; /* Vendor ID */ + unsigned int device; /* Deviice ID */ +}; + + +#define MAX_LISTED_PCI_DEVICES 32 + +/* List of PCI devices (vendor-id:device-id) that should be skipped */ +static struct edac_pci_device_list pci_blacklist[MAX_LISTED_PCI_DEVICES]; +static int pci_blacklist_count; + +/* List of PCI devices (vendor-id:device-id) that should be scanned */ +static struct edac_pci_device_list pci_whitelist[MAX_LISTED_PCI_DEVICES]; +static int pci_whitelist_count ; + +/* START sysfs data and methods */ + +static const char *mem_types[] = { + [MEM_EMPTY] = "Empty", + [MEM_RESERVED] = "Reserved", + [MEM_UNKNOWN] = "Unknown", + [MEM_FPM] = "FPM", + [MEM_EDO] = "EDO", + [MEM_BEDO] = "BEDO", + [MEM_SDR] = "Unbuffered-SDR", + [MEM_RDR] = "Registered-SDR", + [MEM_DDR] = "Unbuffered-DDR", + [MEM_RDDR] = "Registered-DDR", + [MEM_RMBS] = "RMBS" +}; + +static const char *dev_types[] = { + [DEV_UNKNOWN] = "Unknown", + [DEV_X1] = "x1", + [DEV_X2] = "x2", + [DEV_X4] = "x4", + [DEV_X8] = "x8", + [DEV_X16] = "x16", + [DEV_X32] = "x32", + [DEV_X64] = "x64" +}; + +static const char *edac_caps[] = { + [EDAC_UNKNOWN] = "Unknown", + [EDAC_NONE] = "None", + [EDAC_RESERVED] = "Reserved", + [EDAC_PARITY] = "PARITY", + [EDAC_EC] = "EC", + [EDAC_SECDED] = "SECDED", + [EDAC_S2ECD2ED] = "S2ECD2ED", + [EDAC_S4ECD4ED] = "S4ECD4ED", + [EDAC_S8ECD8ED] = "S8ECD8ED", + [EDAC_S16ECD16ED] = "S16ECD16ED" +}; + + +/* sysfs object: /sys/devices/system/edac */ +static struct sysdev_class edac_class = { + set_kset_name("edac"), +}; + +/* sysfs objects: + * /sys/devices/system/edac/mc + * /sys/devices/system/edac/pci + */ +static struct kobject edac_memctrl_kobj; +static struct kobject edac_pci_kobj; + +/* + * /sys/devices/system/edac/mc; + * data structures and methods + */ +static ssize_t memctrl_string_show(void *ptr, char *buffer) +{ + char *value = (char*) ptr; + return sprintf(buffer, "%s\n", value); +} + +static ssize_t memctrl_int_show(void *ptr, char *buffer) +{ + int *value = (int*) ptr; + return sprintf(buffer, "%d\n", *value); +} + +static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count) +{ + int *value = (int*) ptr; + + if (isdigit(*buffer)) + *value = simple_strtoul(buffer, NULL, 0); + + return count; +} + +struct memctrl_dev_attribute { + struct attribute attr; + void *value; + ssize_t (*show)(void *,char *); + ssize_t (*store)(void *, const char *, size_t); +}; + +/* Set of show/store abstract level functions for memory control object */ +static ssize_t +memctrl_dev_show(struct kobject *kobj, struct attribute *attr, char *buffer) +{ + struct memctrl_dev_attribute *memctrl_dev; + memctrl_dev = (struct memctrl_dev_attribute*)attr; + + if (memctrl_dev->show) + return memctrl_dev->show(memctrl_dev->value, buffer); + return -EIO; +} + +static ssize_t +memctrl_dev_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count) +{ + struct memctrl_dev_attribute *memctrl_dev; + memctrl_dev = (struct memctrl_dev_attribute*)attr; + + if (memctrl_dev->store) + return memctrl_dev->store(memctrl_dev->value, buffer, count); + return -EIO; +} + +static struct sysfs_ops memctrlfs_ops = { + .show = memctrl_dev_show, + .store = memctrl_dev_store +}; + +#define MEMCTRL_ATTR(_name,_mode,_show,_store) \ +struct memctrl_dev_attribute attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ + .value = &_name, \ + .show = _show, \ + .store = _store, \ +}; + +#define MEMCTRL_STRING_ATTR(_name,_data,_mode,_show,_store) \ +struct memctrl_dev_attribute attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ + .value = _data, \ + .show = _show, \ + .store = _store, \ +}; + +/* cwrow<id> attribute f*/ +MEMCTRL_STRING_ATTR(mc_version,EDAC_MC_VERSION,S_IRUGO,memctrl_string_show,NULL); + +/* csrow<id> control files */ +MEMCTRL_ATTR(panic_on_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); +MEMCTRL_ATTR(log_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); +MEMCTRL_ATTR(log_ce,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); +MEMCTRL_ATTR(poll_msec,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); + + +/* Base Attributes of the memory ECC object */ +static struct memctrl_dev_attribute *memctrl_attr[] = { + &attr_panic_on_ue, + &attr_log_ue, + &attr_log_ce, + &attr_poll_msec, + &attr_mc_version, + NULL, +}; + +/* Main MC kobject release() function */ +static void edac_memctrl_master_release(struct kobject *kobj) +{ + debugf1("EDAC MC: " __FILE__ ": %s()\n", __func__); +} + +static struct kobj_type ktype_memctrl = { + .release = edac_memctrl_master_release, + .sysfs_ops = &memctrlfs_ops, + .default_attrs = (struct attribute **) memctrl_attr, +}; + + +/* Initialize the main sysfs entries for edac: + * /sys/devices/system/edac + * + * and children + * + * Return: 0 SUCCESS + * !0 FAILURE + */ +static int edac_sysfs_memctrl_setup(void) +{ + int err=0; + + debugf1("MC: " __FILE__ ": %s()\n", __func__); + + /* create the /sys/devices/system/edac directory */ + err = sysdev_class_register(&edac_class); + if (!err) { + /* Init the MC's kobject */ + memset(&edac_memctrl_kobj, 0, sizeof (edac_memctrl_kobj)); + kobject_init(&edac_memctrl_kobj); + + edac_memctrl_kobj.parent = &edac_class.kset.kobj; + edac_memctrl_kobj.ktype = &ktype_memctrl; + + /* generate sysfs "..../edac/mc" */ + err = kobject_set_name(&edac_memctrl_kobj,"mc"); + if (!err) { + /* FIXME: maybe new sysdev_create_subdir() */ + err = kobject_register(&edac_memctrl_kobj); + if (err) { + debugf1("Failed to register '.../edac/mc'\n"); + } else { + debugf1("Registered '.../edac/mc' kobject\n"); + } + } + } else { + debugf1(KERN_WARNING "__FILE__ %s() error=%d\n", __func__,err); + } + + return err; +} + +/* + * MC teardown: + * the '..../edac/mc' kobject followed by '..../edac' itself + */ +static void edac_sysfs_memctrl_teardown(void) +{ + debugf0("MC: " __FILE__ ": %s()\n", __func__); + + /* Unregister the MC's kobject */ + kobject_unregister(&edac_memctrl_kobj); + + /* release the master edac mc kobject */ + kobject_put(&edac_memctrl_kobj); + + /* Unregister the 'edac' object */ + sysdev_class_unregister(&edac_class); +} + +/* + * /sys/devices/system/edac/pci; + * data structures and methods + */ + +struct list_control { + struct edac_pci_device_list *list; + int *count; +}; + +/* Output the list as: vendor_id:device:id<,vendor_id:device_id> */ +static ssize_t edac_pci_list_string_show(void *ptr, char *buffer) +{ + struct list_control *listctl; + struct edac_pci_device_list *list; + char *p = buffer; + int len=0; + int i; + + listctl = ptr; + list = listctl->list; + + for (i = 0; i < *(listctl->count); i++, list++ ) { + if (len > 0) + len += snprintf(p + len, (PAGE_SIZE-len), ","); + + len += snprintf(p + len, + (PAGE_SIZE-len), + "%x:%x", + list->vendor,list->device); + } + + len += snprintf(p + len,(PAGE_SIZE-len), "\n"); + + return (ssize_t) len; +} + +/** + * + * Scan string from **s to **e looking for one 'vendor:device' tuple + * where each field is a hex value + * + * return 0 if an entry is NOT found + * return 1 if an entry is found + * fill in *vendor_id and *device_id with values found + * + * In both cases, make sure *s has been moved forward toward *e + */ +static int parse_one_device(const char **s,const char **e, + unsigned int *vendor_id, unsigned int *device_id) +{ + const char *runner, *p; + + /* if null byte, we are done */ + if (!**s) { + (*s)++; /* keep *s moving */ + return 0; + } + + /* skip over newlines & whitespace */ + if ((**s == '\n') || isspace(**s)) { + (*s)++; + return 0; + } + + if (!isxdigit(**s)) { + (*s)++; + return 0; + } + + /* parse vendor_id */ + runner = *s; + while (runner < *e) { + /* scan for vendor:device delimiter */ + if (*runner == ':') { + *vendor_id = simple_strtol((char*) *s, (char**) &p, 16); + runner = p + 1; + break; + } + runner++; + } + + if (!isxdigit(*runner)) { + *s = ++runner; + return 0; + } + + /* parse device_id */ + if (runner < *e) { + *device_id = simple_strtol((char*)runner, (char**)&p, 16); + runner = p; + } + + *s = runner; + + return 1; +} + +static ssize_t edac_pci_list_string_store(void *ptr, const char *buffer, + size_t count) +{ + struct list_control *listctl; + struct edac_pci_device_list *list; + unsigned int vendor_id, device_id; + const char *s, *e; + int *index; + + s = (char*)buffer; + e = s + count; + + listctl = ptr; + list = listctl->list; + index = listctl->count; + + *index = 0; + while (*index < MAX_LISTED_PCI_DEVICES) { + + if (parse_one_device(&s,&e,&vendor_id,&device_id)) { + list[ *index ].vendor = vendor_id; + list[ *index ].device = device_id; + (*index)++; + } + + /* check for all data consume */ + if (s >= e) + break; + } + + return count; +} + +static ssize_t edac_pci_int_show(void *ptr, char *buffer) +{ + int *value = ptr; + return sprintf(buffer,"%d\n",*value); +} + +static ssize_t edac_pci_int_store(void *ptr, const char *buffer, size_t count) +{ + int *value = ptr; + + if (isdigit(*buffer)) + *value = simple_strtoul(buffer,NULL,0); + + return count; +} + +struct edac_pci_dev_attribute { + struct attribute attr; + void *value; + ssize_t (*show)(void *,char *); + ssize_t (*store)(void *, const char *,size_t); +}; + +/* Set of show/store abstract level functions for PCI Parity object */ +static ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr, + char *buffer) +{ + struct edac_pci_dev_attribute *edac_pci_dev; + edac_pci_dev= (struct edac_pci_dev_attribute*)attr; + + if (edac_pci_dev->show) + return edac_pci_dev->show(edac_pci_dev->value, buffer); + return -EIO; +} + +static ssize_t edac_pci_dev_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count) +{ + struct edac_pci_dev_attribute *edac_pci_dev; + edac_pci_dev= (struct edac_pci_dev_attribute*)attr; + + if (edac_pci_dev->show) + return edac_pci_dev->store(edac_pci_dev->value, buffer, count); + return -EIO; +} + +static struct sysfs_ops edac_pci_sysfs_ops = { + .show = edac_pci_dev_show, + .store = edac_pci_dev_store +}; + + +#define EDAC_PCI_ATTR(_name,_mode,_show,_store) \ +struct edac_pci_dev_attribute edac_pci_attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ + .value = &_name, \ + .show = _show, \ + .store = _store, \ +}; + +#define EDAC_PCI_STRING_ATTR(_name,_data,_mode,_show,_store) \ +struct edac_pci_dev_attribute edac_pci_attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ + .value = _data, \ + .show = _show, \ + .store = _store, \ +}; + +static struct list_control pci_whitelist_control = { + .list = pci_whitelist, + .count = &pci_whitelist_count +}; + +static struct list_control pci_blacklist_control = { + .list = pci_blacklist, + .count = &pci_blacklist_count +}; + +/* whitelist attribute */ +EDAC_PCI_STRING_ATTR(pci_parity_whitelist, + &pci_whitelist_control, + S_IRUGO|S_IWUSR, + edac_pci_list_string_show, + edac_pci_list_string_store); + +EDAC_PCI_STRING_ATTR(pci_parity_blacklist, + &pci_blacklist_control, + S_IRUGO|S_IWUSR, + edac_pci_list_string_show, + edac_pci_list_string_store); + +/* PCI Parity control files */ +EDAC_PCI_ATTR(check_pci_parity,S_IRUGO|S_IWUSR,edac_pci_int_show,edac_pci_int_store); +EDAC_PCI_ATTR(panic_on_pci_parity,S_IRUGO|S_IWUSR,edac_pci_int_show,edac_pci_int_store); +EDAC_PCI_ATTR(pci_parity_count,S_IRUGO,edac_pci_int_show,NULL); + +/* Base Attributes of the memory ECC object */ +static struct edac_pci_dev_attribute *edac_pci_attr[] = { + &edac_pci_attr_check_pci_parity, + &edac_pci_attr_panic_on_pci_parity, + &edac_pci_attr_pci_parity_count, + &edac_pci_attr_pci_parity_whitelist, + &edac_pci_attr_pci_parity_blacklist, + NULL, +}; + +/* No memory to release */ +static void edac_pci_release(struct kobject *kobj) +{ + debugf1("EDAC PCI: " __FILE__ ": %s()\n", __func__); +} + +static struct kobj_type ktype_edac_pci = { + .release = edac_pci_release, + .sysfs_ops = &edac_pci_sysfs_ops, + .default_attrs = (struct attribute **) edac_pci_attr, +}; + +/** + * edac_sysfs_pci_setup() + * + */ +static int edac_sysfs_pci_setup(void) +{ + int err; + + debugf1("MC: " __FILE__ ": %s()\n", __func__); + + memset(&edac_pci_kobj, 0, sizeof(edac_pci_kobj)); + + kobject_init(&edac_pci_kobj); + edac_pci_kobj.parent = &edac_class.kset.kobj; + edac_pci_kobj.ktype = &ktype_edac_pci; + + err = kobject_set_name(&edac_pci_kobj, "pci"); + if (!err) { + /* Instanstiate the csrow object */ + /* FIXME: maybe new sysdev_create_subdir() */ + err = kobject_register(&edac_pci_kobj); + if (err) + debugf1("Failed to register '.../edac/pci'\n"); + else + debugf1("Registered '.../edac/pci' kobject\n"); + } + return err; +} + + +static void edac_sysfs_pci_teardown(void) +{ + debugf0("MC: " __FILE__ ": %s()\n", __func__); + + kobject_unregister(&edac_pci_kobj); + kobject_put(&edac_pci_kobj); +} + +/* EDAC sysfs CSROW data structures and methods */ + +/* Set of more detailed csrow<id> attribute show/store functions */ +static ssize_t csrow_ch0_dimm_label_show(struct csrow_info *csrow, char *data) +{ + ssize_t size = 0; + + if (csrow->nr_channels > 0) { + size = snprintf(data, EDAC_MC_LABEL_LEN,"%s\n", + csrow->channels[0].label); + } + return size; +} + +static ssize_t csrow_ch1_dimm_label_show(struct csrow_info *csrow, char *data) +{ + ssize_t size = 0; + + if (csrow->nr_channels > 0) { + size = snprintf(data, EDAC_MC_LABEL_LEN, "%s\n", + csrow->channels[1].label); + } + return size; +} + +static ssize_t csrow_ch0_dimm_label_store(struct csrow_info *csrow, + const char *data, size_t size) +{ + ssize_t max_size = 0; + + if (csrow->nr_channels > 0) { + max_size = min((ssize_t)size,(ssize_t)EDAC_MC_LABEL_LEN-1); + strncpy(csrow->channels[0].label, data, max_size); + csrow->channels[0].label[max_size] = '\0'; + } + return size; +} + +static ssize_t csrow_ch1_dimm_label_store(struct csrow_info *csrow, + const char *data, size_t size) +{ + ssize_t max_size = 0; + + if (csrow->nr_channels > 1) { + max_size = min((ssize_t)size,(ssize_t)EDAC_MC_LABEL_LEN-1); + strncpy(csrow->channels[1].label, data, max_size); + csrow->channels[1].label[max_size] = '\0'; + } + return max_size; +} + +static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data) +{ + return sprintf(data,"%u\n", csrow->ue_count); +} + +static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data) +{ + return sprintf(data,"%u\n", csrow->ce_count); +} + +static ssize_t csrow_ch0_ce_count_show(struct csrow_info *csrow, char *data) +{ + ssize_t size = 0; + + if (csrow->nr_channels > 0) { + size = sprintf(data,"%u\n", csrow->channels[0].ce_count); + } + return size; +} + +static ssize_t csrow_ch1_ce_count_show(struct csrow_info *csrow, char *data) +{ + ssize_t size = 0; + + if (csrow->nr_channels > 1) { + size = sprintf(data,"%u\n", csrow->channels[1].ce_count); + } + return size; +} + +static ssize_t csrow_size_show(struct csrow_info *csrow, char *data) +{ + return sprintf(data,"%u\n", PAGES_TO_MiB(csrow->nr_pages)); +} + +static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data) +{ + return sprintf(data,"%s\n", mem_types[csrow->mtype]); +} + +static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data) +{ + return sprintf(data,"%s\n", dev_types[csrow->dtype]); +} + +static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data) +{ + return sprintf(data,"%s\n", edac_caps[csrow->edac_mode]); +} + +struct csrowdev_attribute { + struct attribute attr; + ssize_t (*show)(struct csrow_info *,char *); + ssize_t (*store)(struct csrow_info *, const char *,size_t); +}; + +#define to_csrow(k) container_of(k, struct csrow_info, kobj) +#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr) + +/* Set of show/store higher level functions for csrow objects */ +static ssize_t csrowdev_show(struct kobject *kobj, struct attribute *attr, + char *buffer) +{ + struct csrow_info *csrow = to_csrow(kobj); + struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr); + + if (csrowdev_attr->show) + return csrowdev_attr->show(csrow, buffer); + return -EIO; +} + +static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count) +{ + struct csrow_info *csrow = to_csrow(kobj); + struct csrowdev_attribute * csrowdev_attr = to_csrowdev_attr(attr); + + if (csrowdev_attr->store) + return csrowdev_attr->store(csrow, buffer, count); + return -EIO; +} + +static struct sysfs_ops csrowfs_ops = { + .show = csrowdev_show, + .store = csrowdev_store +}; + +#define CSROWDEV_ATTR(_name,_mode,_show,_store) \ +struct csrowdev_attribute attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ + .show = _show, \ + .store = _store, \ +}; + +/* cwrow<id>/attribute files */ +CSROWDEV_ATTR(size_mb,S_IRUGO,csrow_size_show,NULL); +CSROWDEV_ATTR(dev_type,S_IRUGO,csrow_dev_type_show,NULL); +CSROWDEV_ATTR(mem_type,S_IRUGO,csrow_mem_type_show,NULL); +CSROWDEV_ATTR(edac_mode,S_IRUGO,csrow_edac_mode_show,NULL); +CSROWDEV_ATTR(ue_count,S_IRUGO,csrow_ue_count_show,NULL); +CSROWDEV_ATTR(ce_count,S_IRUGO,csrow_ce_count_show,NULL); +CSROWDEV_ATTR(ch0_ce_count,S_IRUGO,csrow_ch0_ce_count_show,NULL); +CSROWDEV_ATTR(ch1_ce_count,S_IRUGO,csrow_ch1_ce_count_show,NULL); + +/* control/attribute files */ +CSROWDEV_ATTR(ch0_dimm_label,S_IRUGO|S_IWUSR, + csrow_ch0_dimm_label_show, + csrow_ch0_dimm_label_store); +CSROWDEV_ATTR(ch1_dimm_label,S_IRUGO|S_IWUSR, + csrow_ch1_dimm_label_show, + csrow_ch1_dimm_label_store); + + +/* Attributes of the CSROW<id> object */ +static struct csrowdev_attribute *csrow_attr[] = { + &attr_dev_type, + &attr_mem_type, + &attr_edac_mode, + &attr_size_mb, + &attr_ue_count, + &attr_ce_count, + &attr_ch0_ce_count, + &attr_ch1_ce_count, + &attr_ch0_dimm_label, + &attr_ch1_dimm_label, + NULL, +}; + + +/* No memory to release */ +static void edac_csrow_instance_release(struct kobject *kobj) +{ + debugf1("EDAC MC: " __FILE__ ": %s()\n", __func__); +} + +static struct kobj_type ktype_csrow = { + .release = edac_csrow_instance_release, + .sysfs_ops = &csrowfs_ops, + .default_attrs = (struct attribute **) csrow_attr, +}; + +/* Create a CSROW object under specifed edac_mc_device */ +static int edac_create_csrow_object(struct kobject *edac_mci_kobj, + struct csrow_info *csrow, int index ) +{ + int err = 0; + + debugf0("MC: " __FILE__ ": %s()\n", __func__); + + memset(&csrow->kobj, 0, sizeof(csrow->kobj)); + + /* generate ..../edac/mc/mc<id>/csrow<index> */ + + kobject_init(&csrow->kobj); + csrow->kobj.parent = edac_mci_kobj; + csrow->kobj.ktype = &ktype_csrow; + + /* name this instance of csrow<id> */ + err = kobject_set_name(&csrow->kobj,"csrow%d",index); + if (!err) { + /* Instanstiate the csrow object */ + err = kobject_register(&csrow->kobj); + if (err) + debugf0("Failed to register CSROW%d\n",index); + else + debugf0("Registered CSROW%d\n",index); + } + + return err; +} + +/* sysfs data structures and methods for the MCI kobjects */ + +static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci, + const char *data, size_t count ) +{ + int row, chan; + + mci->ue_noinfo_count = 0; + mci->ce_noinfo_count = 0; + mci->ue_count = 0; + mci->ce_count = 0; + for (row = 0; row < mci->nr_csrows; row++) { + struct csrow_info *ri = &mci->csrows[row]; + + ri->ue_count = 0; + ri->ce_count = 0; + for (chan = 0; chan < ri->nr_channels; chan++) + ri->channels[chan].ce_count = 0; + } + mci->start_time = jiffies; + + return count; +} + +static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data) +{ + return sprintf(data,"%d\n", mci->ue_count); +} + +static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data) +{ + return sprintf(data,"%d\n", mci->ce_count); +} + +static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data) +{ + return sprintf(data,"%d\n", mci->ce_noinfo_count); +} + +static ssize_t mci_ue_noinfo_show(struct mem_ctl_info *mci, char *data) +{ + return sprintf(data,"%d\n", mci->ue_noinfo_count); +} + +static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data) +{ + return sprintf(data,"%ld\n", (jiffies - mci->start_time) / HZ); +} + +static ssize_t mci_mod_name_show(struct mem_ctl_info *mci, char *data) +{ + return sprintf(data,"%s %s\n", mci->mod_name, mci->mod_ver); +} + +static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data) +{ + return sprintf(data,"%s\n", mci->ctl_name); +} + +static int mci_output_edac_cap(char *buf, unsigned long edac_cap) +{ + char *p = buf; + int bit_idx; + + for (bit_idx = 0; bit_idx < 8 * sizeof(edac_cap); bit_idx++) { + if ((edac_cap >> bit_idx) & 0x1) + p += sprintf(p, "%s ", edac_caps[bit_idx]); + } + + return p - buf; +} + +static ssize_t mci_edac_capability_show(struct mem_ctl_info *mci, char *data) +{ + char *p = data; + + p += mci_output_edac_cap(p,mci->edac_ctl_cap); + p += sprintf(p, "\n"); + + return p - data; +} + +static ssize_t mci_edac_current_capability_show(struct mem_ctl_info *mci, + char *data) +{ + char *p = data; + + p += mci_output_edac_cap(p,mci->edac_cap); + p += sprintf(p, "\n"); + + return p - data; +} + +static int mci_output_mtype_cap(char *buf, unsigned long mtype_cap) +{ + char *p = buf; + int bit_idx; + + for (bit_idx = 0; bit_idx < 8 * sizeof(mtype_cap); bit_idx++) { + if ((mtype_cap >> bit_idx) & 0x1) + p += sprintf(p, "%s ", mem_types[bit_idx]); + } + + return p - buf; +} + +static ssize_t mci_supported_mem_type_show(struct mem_ctl_info *mci, char *data) +{ + char *p = data; + + p += mci_output_mtype_cap(p,mci->mtype_cap); + p += sprintf(p, "\n"); + + return p - data; +} + +static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data) +{ + int total_pages, csrow_idx; + + for (total_pages = csrow_idx = 0; csrow_idx < mci->nr_csrows; + csrow_idx++) { + struct csrow_info *csrow = &mci->csrows[csrow_idx]; + + if (!csrow->nr_pages) + continue; + total_pages += csrow->nr_pages; + } + + return sprintf(data,"%u\n", PAGES_TO_MiB(total_pages)); +} + +struct mcidev_attribute { + struct attribute attr; + ssize_t (*show)(struct mem_ctl_info *,char *); + ssize_t (*store)(struct mem_ctl_info *, const char *,size_t); +}; + +#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj) +#define to_mcidev_attr(a) container_of(a, struct mcidev_attribute, attr) + +static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr, + char *buffer) +{ + struct mem_ctl_info *mem_ctl_info = to_mci(kobj); + struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr); + + if (mcidev_attr->show) + return mcidev_attr->show(mem_ctl_info, buffer); + return -EIO; +} + +static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count) +{ + struct mem_ctl_info *mem_ctl_info = to_mci(kobj); + struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr); + + if (mcidev_attr->store) + return mcidev_attr->store(mem_ctl_info, buffer, count); + return -EIO; +} + +static struct sysfs_ops mci_ops = { + .show = mcidev_show, + .store = mcidev_store +}; + +#define MCIDEV_ATTR(_name,_mode,_show,_store) \ +struct mcidev_attribute mci_attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ + .show = _show, \ + .store = _store, \ +}; + +/* Control file */ +MCIDEV_ATTR(reset_counters,S_IWUSR,NULL,mci_reset_counters_store); + +/* Attribute files */ +MCIDEV_ATTR(mc_name,S_IRUGO,mci_ctl_name_show,NULL); +MCIDEV_ATTR(module_name,S_IRUGO,mci_mod_name_show,NULL); +MCIDEV_ATTR(edac_capability,S_IRUGO,mci_edac_capability_show,NULL); +MCIDEV_ATTR(size_mb,S_IRUGO,mci_size_mb_show,NULL); +MCIDEV_ATTR(seconds_since_reset,S_IRUGO,mci_seconds_show,NULL); +MCIDEV_ATTR(ue_noinfo_count,S_IRUGO,mci_ue_noinfo_show,NULL); +MCIDEV_ATTR(ce_noinfo_count,S_IRUGO,mci_ce_noinfo_show,NULL); +MCIDEV_ATTR(ue_count,S_IRUGO,mci_ue_count_show,NULL); +MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL); +MCIDEV_ATTR(edac_current_capability,S_IRUGO, + mci_edac_current_capability_show,NULL); +MCIDEV_ATTR(supported_mem_type,S_IRUGO, + mci_supported_mem_type_show,NULL); + + +static struct mcidev_attribute *mci_attr[] = { + &mci_attr_reset_counters, + &mci_attr_module_name, + &mci_attr_mc_name, + &mci_attr_edac_capability, + &mci_attr_edac_current_capability, + &mci_attr_supported_mem_type, + &mci_attr_size_mb, + &mci_attr_seconds_since_reset, + &mci_attr_ue_noinfo_count, + &mci_attr_ce_noinfo_count, + &mci_attr_ue_count, + &mci_attr_ce_count, + NULL +}; + + +/* + * Release of a MC controlling instance + */ +static void edac_mci_instance_release(struct kobject *kobj) +{ + struct mem_ctl_info *mci; + mci = container_of(kobj,struct mem_ctl_info,edac_mci_kobj); + + debugf0("MC: " __FILE__ ": %s() idx=%d calling kfree\n", + __func__, mci->mc_idx); + + kfree(mci); +} + +static struct kobj_type ktype_mci = { + .release = edac_mci_instance_release, + .sysfs_ops = &mci_ops, + .default_attrs = (struct attribute **) mci_attr, +}; + +#define EDAC_DEVICE_SYMLINK "device" + +/* + * Create a new Memory Controller kobject instance, + * mc<id> under the 'mc' directory + * + * Return: + * 0 Success + * !0 Failure + */ +static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) +{ + int i; + int err; + struct csrow_info *csrow; + struct kobject *edac_mci_kobj=&mci->edac_mci_kobj; + + debugf0("MC: " __FILE__ ": %s() idx=%d\n", __func__, mci->mc_idx); + + memset(edac_mci_kobj, 0, sizeof(*edac_mci_kobj)); + kobject_init(edac_mci_kobj); + + /* set the name of the mc<id> object */ + err = kobject_set_name(edac_mci_kobj,"mc%d",mci->mc_idx); + if (err) + return err; + + /* link to our parent the '..../edac/mc' object */ + edac_mci_kobj->parent = &edac_memctrl_kobj; + edac_mci_kobj->ktype = &ktype_mci; + + /* register the mc<id> kobject */ + err = kobject_register(edac_mci_kobj); + if (err) + return err; + + /* create a symlink for the device */ + err = sysfs_create_link(edac_mci_kobj, &mci->pdev->dev.kobj, + EDAC_DEVICE_SYMLINK); + if (err) { + kobject_unregister(edac_mci_kobj); + return err; + } + + /* Make directories for each CSROW object + * under the mc<id> kobject + */ + for (i = 0; i < mci->nr_csrows; i++) { + + csrow = &mci->csrows[i]; + + /* Only expose populated CSROWs */ + if (csrow->nr_pages > 0) { + err = edac_create_csrow_object(edac_mci_kobj,csrow,i); + if (err) + goto fail; + } + } + + /* Mark this MCI instance as having sysfs entries */ + mci->sysfs_active = MCI_SYSFS_ACTIVE; + + return 0; + + + /* CSROW error: backout what has already been registered, */ +fail: + for ( i--; i >= 0; i--) { + if (csrow->nr_pages > 0) { + kobject_unregister(&mci->csrows[i].kobj); + kobject_put(&mci->csrows[i].kobj); + } + } + + kobject_unregister(edac_mci_kobj); + kobject_put(edac_mci_kobj); + + return err; +} + +/* + * remove a Memory Controller instance + */ +static void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) +{ + int i; + + debugf0("MC: " __FILE__ ": %s()\n", __func__); + + /* remove all csrow kobjects */ + for (i = 0; i < mci->nr_csrows; i++) { + if (mci->csrows[i].nr_pages > 0) { + kobject_unregister(&mci->csrows[i].kobj); + kobject_put(&mci->csrows[i].kobj); + } + } + + sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK); + + kobject_unregister(&mci->edac_mci_kobj); + kobject_put(&mci->edac_mci_kobj); +} + +/* END OF sysfs data and methods */ + +#ifdef CONFIG_EDAC_DEBUG + +EXPORT_SYMBOL(edac_mc_dump_channel); + +void edac_mc_dump_channel(struct channel_info *chan) +{ + debugf4("\tchannel = %p\n", chan); + debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx); + debugf4("\tchannel->ce_count = %d\n", chan->ce_count); + debugf4("\tchannel->label = '%s'\n", chan->label); + debugf4("\tchannel->csrow = %p\n\n", chan->csrow); +} + + +EXPORT_SYMBOL(edac_mc_dump_csrow); + +void edac_mc_dump_csrow(struct csrow_info *csrow) +{ + debugf4("\tcsrow = %p\n", csrow); + debugf4("\tcsrow->csrow_idx = %d\n", csrow->csrow_idx); + debugf4("\tcsrow->first_page = 0x%lx\n", + csrow->first_page); + debugf4("\tcsrow->last_page = 0x%lx\n", csrow->last_page); + debugf4("\tcsrow->page_mask = 0x%lx\n", csrow->page_mask); + debugf4("\tcsrow->nr_pages = 0x%x\n", csrow->nr_pages); + debugf4("\tcsrow->nr_channels = %d\n", + csrow->nr_channels); + debugf4("\tcsrow->channels = %p\n", csrow->channels); + debugf4("\tcsrow->mci = %p\n\n", csrow->mci); +} + + +EXPORT_SYMBOL(edac_mc_dump_mci); + +void edac_mc_dump_mci(struct mem_ctl_info *mci) +{ + debugf3("\tmci = %p\n", mci); + debugf3("\tmci->mtype_cap = %lx\n", mci->mtype_cap); + debugf3("\tmci->edac_ctl_cap = %lx\n", mci->edac_ctl_cap); + debugf3("\tmci->edac_cap = %lx\n", mci->edac_cap); + debugf4("\tmci->edac_check = %p\n", mci->edac_check); + debugf3("\tmci->nr_csrows = %d, csrows = %p\n", + mci->nr_csrows, mci->csrows); + debugf3("\tpdev = %p\n", mci->pdev); + debugf3("\tmod_name:ctl_name = %s:%s\n", + mci->mod_name, mci->ctl_name); + debugf3("\tpvt_info = %p\n\n", mci->pvt_info); +} + + +#endif /* CONFIG_EDAC_DEBUG */ + +/* 'ptr' points to a possibly unaligned item X such that sizeof(X) is 'size'. + * Adjust 'ptr' so that its alignment is at least as stringent as what the + * compiler would provide for X and return the aligned result. + * + * If 'size' is a constant, the compiler will optimize this whole function + * down to either a no-op or the addition of a constant to the value of 'ptr'. + */ +static inline char * align_ptr (void *ptr, unsigned size) +{ + unsigned align, r; + + /* Here we assume that the alignment of a "long long" is the most + * stringent alignment that the compiler will ever provide by default. + * As far as I know, this is a reasonable assumption. + */ + if (size > sizeof(long)) + align = sizeof(long long); + else if (size > sizeof(int)) + align = sizeof(long); + else if (size > sizeof(short)) + align = sizeof(int); + else if (size > sizeof(char)) + align = sizeof(short); + else + return (char *) ptr; + + r = size % align; + + if (r == 0) + return (char *) ptr; + + return (char *) (((unsigned long) ptr) + align - r); +} + + +EXPORT_SYMBOL(edac_mc_alloc); + +/** + * edac_mc_alloc: Allocate a struct mem_ctl_info structure + * @size_pvt: size of private storage needed + * @nr_csrows: Number of CWROWS needed for this MC + * @nr_chans: Number of channels for the MC + * + * Everything is kmalloc'ed as one big chunk - more efficient. + * Only can be used if all structures have the same lifetime - otherwise + * you have to allocate and initialize your own structures. + * + * Use edac_mc_free() to free mc structures allocated by this function. + * + * Returns: + * NULL allocation failed + * struct mem_ctl_info pointer + */ +struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, + unsigned nr_chans) +{ + struct mem_ctl_info *mci; + struct csrow_info *csi, *csrow; + struct channel_info *chi, *chp, *chan; + void *pvt; + unsigned size; + int row, chn; + + /* Figure out the offsets of the various items from the start of an mc + * structure. We want the alignment of each item to be at least as + * stringent as what the compiler would provide if we could simply + * hardcode everything into a single struct. + */ + mci = (struct mem_ctl_info *) 0; + csi = (struct csrow_info *)align_ptr(&mci[1], sizeof(*csi)); + chi = (struct channel_info *) + align_ptr(&csi[nr_csrows], sizeof(*chi)); + pvt = align_ptr(&chi[nr_chans * nr_csrows], sz_pvt); + size = ((unsigned long) pvt) + sz_pvt; + + if ((mci = kmalloc(size, GFP_KERNEL)) == NULL) + return NULL; + + /* Adjust pointers so they point within the memory we just allocated + * rather than an imaginary chunk of memory located at address 0. + */ + csi = (struct csrow_info *) (((char *) mci) + ((unsigned long) csi)); + chi = (struct channel_info *) (((char *) mci) + ((unsigned long) chi)); + pvt = sz_pvt ? (((char *) mci) + ((unsigned long) pvt)) : NULL; + + memset(mci, 0, size); /* clear all fields */ + + mci->csrows = csi; + mci->pvt_info = pvt; + mci->nr_csrows = nr_csrows; + + for (row = 0; row < nr_csrows; row++) { + csrow = &csi[row]; + csrow->csrow_idx = row; + csrow->mci = mci; + csrow->nr_channels = nr_chans; + chp = &chi[row * nr_chans]; + csrow->channels = chp; + + for (chn = 0; chn < nr_chans; chn++) { + chan = &chp[chn]; + chan->chan_idx = chn; + chan->csrow = csrow; + } + } + + return mci; +} + + +EXPORT_SYMBOL(edac_mc_free); + +/** + * edac_mc_free: Free a previously allocated 'mci' structure + * @mci: pointer to a struct mem_ctl_info structure + * + * Free up a previously allocated mci structure + * A MCI structure can be in 2 states after being allocated + * by edac_mc_alloc(). + * 1) Allocated in a MC driver's probe, but not yet committed + * 2) Allocated and committed, by a call to edac_mc_add_mc() + * edac_mc_add_mc() is the function that adds the sysfs entries + * thus, this free function must determine which state the 'mci' + * structure is in, then either free it directly or + * perform kobject cleanup by calling edac_remove_sysfs_mci_device(). + * + * VOID Return + */ +void edac_mc_free(struct mem_ctl_info *mci) +{ + /* only if sysfs entries for this mci instance exist + * do we remove them and defer the actual kfree via + * the kobject 'release()' callback. + * + * Otherwise, do a straight kfree now. + */ + if (mci->sysfs_active == MCI_SYSFS_ACTIVE) + edac_remove_sysfs_mci_device(mci); + else + kfree(mci); +} + + + +EXPORT_SYMBOL(edac_mc_find_mci_by_pdev); + +struct mem_ctl_info *edac_mc_find_mci_by_pdev(struct pci_dev *pdev) +{ + struct mem_ctl_info *mci; + struct list_head *item; + + debugf3("MC: " __FILE__ ": %s()\n", __func__); + + list_for_each(item, &mc_devices) { + mci = list_entry(item, struct mem_ctl_info, link); + + if (mci->pdev == pdev) + return mci; + } + + return NULL; +} + +static int add_mc_to_global_list (struct mem_ctl_info *mci) +{ + struct list_head *item, *insert_before; + struct mem_ctl_info *p; + int i; + + if (list_empty(&mc_devices)) { + mci->mc_idx = 0; + insert_before = &mc_devices; + } else { + if (edac_mc_find_mci_by_pdev(mci->pdev)) { + printk(KERN_WARNING + "EDAC MC: %s (%s) %s %s already assigned %d\n", + mci->pdev->dev.bus_id, pci_name(mci->pdev), + mci->mod_name, mci->ctl_name, mci->mc_idx); + return 1; + } + + insert_before = NULL; + i = 0; + + list_for_each(item, &mc_devices) { + p = list_entry(item, struct mem_ctl_info, link); + + if (p->mc_idx != i) { + insert_before = item; + break; + } + + i++; + } + + mci->mc_idx = i; + + if (insert_before == NULL) + insert_before = &mc_devices; + } + + list_add_tail_rcu(&mci->link, insert_before); + return 0; +} + + + +EXPORT_SYMBOL(edac_mc_add_mc); + +/** + * edac_mc_add_mc: Insert the 'mci' structure into the mci global list + * @mci: pointer to the mci structure to be added to the list + * + * Return: + * 0 Success + * !0 Failure + */ + +/* FIXME - should a warning be printed if no error detection? correction? */ +int edac_mc_add_mc(struct mem_ctl_info *mci) +{ + int rc = 1; + + debugf0("MC: " __FILE__ ": %s()\n", __func__); +#ifdef CONFIG_EDAC_DEBUG + if (edac_debug_level >= 3) + edac_mc_dump_mci(mci); + if (edac_debug_level >= 4) { + int i; + + for (i = 0; i < mci->nr_csrows; i++) { + int j; + edac_mc_dump_csrow(&mci->csrows[i]); + for (j = 0; j < mci->csrows[i].nr_channels; j++) + edac_mc_dump_channel(&mci->csrows[i]. + channels[j]); + } + } +#endif + down(&mem_ctls_mutex); + + if (add_mc_to_global_list(mci)) + goto finish; + + /* set load time so that error rate can be tracked */ + mci->start_time = jiffies; + + if (edac_create_sysfs_mci_device(mci)) { + printk(KERN_WARNING + "EDAC MC%d: failed to create sysfs device\n", + mci->mc_idx); + /* FIXME - should there be an error code and unwind? */ + goto finish; + } + + /* Report action taken */ + printk(KERN_INFO + "EDAC MC%d: Giving out device to %s %s: PCI %s\n", + mci->mc_idx, mci->mod_name, mci->ctl_name, + pci_name(mci->pdev)); + + + rc = 0; + +finish: + up(&mem_ctls_mutex); + return rc; +} + + + +static void complete_mc_list_del (struct rcu_head *head) +{ + struct mem_ctl_info *mci; + + mci = container_of(head, struct mem_ctl_info, rcu); + INIT_LIST_HEAD(&mci->link); + complete(&mci->complete); +} + +static void del_mc_from_global_list (struct mem_ctl_info *mci) +{ + list_del_rcu(&mci->link); + init_completion(&mci->complete); + call_rcu(&mci->rcu, complete_mc_list_del); + wait_for_completion(&mci->complete); +} + +EXPORT_SYMBOL(edac_mc_del_mc); + +/** + * edac_mc_del_mc: Remove the specified mci structure from global list + * @mci: Pointer to struct mem_ctl_info structure + * + * Returns: + * 0 Success + * 1 Failure + */ +int edac_mc_del_mc(struct mem_ctl_info *mci) +{ + int rc = 1; + + debugf0("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__); + down(&mem_ctls_mutex); + del_mc_from_global_list(mci); + printk(KERN_INFO + "EDAC MC%d: Removed device %d for %s %s: PCI %s\n", + mci->mc_idx, mci->mc_idx, mci->mod_name, mci->ctl_name, + pci_name(mci->pdev)); + rc = 0; + up(&mem_ctls_mutex); + + return rc; +} + + +EXPORT_SYMBOL(edac_mc_scrub_block); + +void edac_mc_scrub_block(unsigned long page, unsigned long offset, + u32 size) +{ + struct page *pg; + void *virt_addr; + unsigned long flags = 0; + + debugf3("MC: " __FILE__ ": %s()\n", __func__); + + /* ECC error page was not in our memory. Ignore it. */ + if(!pfn_valid(page)) + return; + + /* Find the actual page structure then map it and fix */ + pg = pfn_to_page(page); + + if (PageHighMem(pg)) + local_irq_save(flags); + + virt_addr = kmap_atomic(pg, KM_BOUNCE_READ); + + /* Perform architecture specific atomic scrub operation */ + atomic_scrub(virt_addr + offset, size); + + /* Unmap and complete */ + kunmap_atomic(virt_addr, KM_BOUNCE_READ); + + if (PageHighMem(pg)) + local_irq_restore(flags); +} + + +/* FIXME - should return -1 */ +EXPORT_SYMBOL(edac_mc_find_csrow_by_page); + +int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, + unsigned long page) +{ + struct csrow_info *csrows = mci->csrows; + int row, i; + + debugf1("MC%d: " __FILE__ ": %s(): 0x%lx\n", mci->mc_idx, __func__, + page); + row = -1; + + for (i = 0; i < mci->nr_csrows; i++) { + struct csrow_info *csrow = &csrows[i]; + + if (csrow->nr_pages == 0) + continue; + + debugf3("MC%d: " __FILE__ + ": %s(): first(0x%lx) page(0x%lx)" + " last(0x%lx) mask(0x%lx)\n", mci->mc_idx, + __func__, csrow->first_page, page, + csrow->last_page, csrow->page_mask); + + if ((page >= csrow->first_page) && + (page <= csrow->last_page) && + ((page & csrow->page_mask) == + (csrow->first_page & csrow->page_mask))) { + row = i; + break; + } + } + + if (row == -1) + printk(KERN_ERR + "EDAC MC%d: could not look up page error address %lx\n", + mci->mc_idx, (unsigned long) page); + + return row; +} + + +EXPORT_SYMBOL(edac_mc_handle_ce); + +/* FIXME - setable log (warning/emerg) levels */ +/* FIXME - integrate with evlog: http://evlog.sourceforge.net/ */ +void edac_mc_handle_ce(struct mem_ctl_info *mci, + unsigned long page_frame_number, + unsigned long offset_in_page, + unsigned long syndrome, int row, int channel, + const char *msg) +{ + unsigned long remapped_page; + + debugf3("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__); + + /* FIXME - maybe make panic on INTERNAL ERROR an option */ + if (row >= mci->nr_csrows || row < 0) { + /* something is wrong */ + printk(KERN_ERR + "EDAC MC%d: INTERNAL ERROR: row out of range (%d >= %d)\n", + mci->mc_idx, row, mci->nr_csrows); + edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); + return; + } + if (channel >= mci->csrows[row].nr_channels || channel < 0) { + /* something is wrong */ + printk(KERN_ERR + "EDAC MC%d: INTERNAL ERROR: channel out of range " + "(%d >= %d)\n", + mci->mc_idx, channel, mci->csrows[row].nr_channels); + edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); + return; + } + + if (log_ce) + /* FIXME - put in DIMM location */ + printk(KERN_WARNING + "EDAC MC%d: CE page 0x%lx, offset 0x%lx," + " grain %d, syndrome 0x%lx, row %d, channel %d," + " label \"%s\": %s\n", mci->mc_idx, + page_frame_number, offset_in_page, + mci->csrows[row].grain, syndrome, row, channel, + mci->csrows[row].channels[channel].label, msg); + + mci->ce_count++; + mci->csrows[row].ce_count++; + mci->csrows[row].channels[channel].ce_count++; + + if (mci->scrub_mode & SCRUB_SW_SRC) { + /* + * Some MC's can remap memory so that it is still available + * at a different address when PCI devices map into memory. + * MC's that can't do this lose the memory where PCI devices + * are mapped. This mapping is MC dependant and so we call + * back into the MC driver for it to map the MC page to + * a physical (CPU) page which can then be mapped to a virtual + * page - which can then be scrubbed. + */ + remapped_page = mci->ctl_page_to_phys ? + mci->ctl_page_to_phys(mci, page_frame_number) : + page_frame_number; + + edac_mc_scrub_block(remapped_page, offset_in_page, + mci->csrows[row].grain); + } +} + + +EXPORT_SYMBOL(edac_mc_handle_ce_no_info); + +void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, + const char *msg) +{ + if (log_ce) + printk(KERN_WARNING + "EDAC MC%d: CE - no information available: %s\n", + mci->mc_idx, msg); + mci->ce_noinfo_count++; + mci->ce_count++; +} + + +EXPORT_SYMBOL(edac_mc_handle_ue); + +void edac_mc_handle_ue(struct mem_ctl_info *mci, + unsigned long page_frame_number, + unsigned long offset_in_page, int row, + const char *msg) +{ + int len = EDAC_MC_LABEL_LEN * 4; + char labels[len + 1]; + char *pos = labels; + int chan; + int chars; + + debugf3("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__); + + /* FIXME - maybe make panic on INTERNAL ERROR an option */ + if (row >= mci->nr_csrows || row < 0) { + /* something is wrong */ + printk(KERN_ERR + "EDAC MC%d: INTERNAL ERROR: row out of range (%d >= %d)\n", + mci->mc_idx, row, mci->nr_csrows); + edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR"); + return; + } + + chars = snprintf(pos, len + 1, "%s", + mci->csrows[row].channels[0].label); + len -= chars; + pos += chars; + for (chan = 1; (chan < mci->csrows[row].nr_channels) && (len > 0); + chan++) { + chars = snprintf(pos, len + 1, ":%s", + mci->csrows[row].channels[chan].label); + len -= chars; + pos += chars; + } + + if (log_ue) + printk(KERN_EMERG + "EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, row %d," + " labels \"%s\": %s\n", mci->mc_idx, + page_frame_number, offset_in_page, + mci->csrows[row].grain, row, labels, msg); + + if (panic_on_ue) + panic + ("EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, row %d," + " labels \"%s\": %s\n", mci->mc_idx, + page_frame_number, offset_in_page, + mci->csrows[row].grain, row, labels, msg); + + mci->ue_count++; + mci->csrows[row].ue_count++; +} + + +EXPORT_SYMBOL(edac_mc_handle_ue_no_info); + +void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, + const char *msg) +{ + if (panic_on_ue) + panic("EDAC MC%d: Uncorrected Error", mci->mc_idx); + + if (log_ue) + printk(KERN_WARNING + "EDAC MC%d: UE - no information available: %s\n", + mci->mc_idx, msg); + mci->ue_noinfo_count++; + mci->ue_count++; +} + + +#ifdef CONFIG_PCI + +static u16 get_pci_parity_status(struct pci_dev *dev, int secondary) +{ + int where; + u16 status; + + where = secondary ? PCI_SEC_STATUS : PCI_STATUS; + pci_read_config_word(dev, where, &status); + + /* If we get back 0xFFFF then we must suspect that the card has been pulled but + the Linux PCI layer has not yet finished cleaning up. We don't want to report + on such devices */ + + if (status == 0xFFFF) { + u32 sanity; + pci_read_config_dword(dev, 0, &sanity); + if (sanity == 0xFFFFFFFF) + return 0; + } + status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR | + PCI_STATUS_PARITY; + + if (status) + /* reset only the bits we are interested in */ + pci_write_config_word(dev, where, status); + + return status; +} + +typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev); + +/* Clear any PCI parity errors logged by this device. */ +static void edac_pci_dev_parity_clear( struct pci_dev *dev ) +{ + u8 header_type; + + get_pci_parity_status(dev, 0); + + /* read the device TYPE, looking for bridges */ + pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) + get_pci_parity_status(dev, 1); +} + +/* + * PCI Parity polling + * + */ +static void edac_pci_dev_parity_test(struct pci_dev *dev) +{ + u16 status; + u8 header_type; + + /* read the STATUS register on this device + */ + status = get_pci_parity_status(dev, 0); + + debugf2("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id ); + + /* check the status reg for errors */ + if (status) { + if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) + printk(KERN_CRIT + "EDAC PCI- " + "Signaled System Error on %s\n", + pci_name (dev)); + + if (status & (PCI_STATUS_PARITY)) { + printk(KERN_CRIT + "EDAC PCI- " + "Master Data Parity Error on %s\n", + pci_name (dev)); + + atomic_inc(&pci_parity_count); + } + + if (status & (PCI_STATUS_DETECTED_PARITY)) { + printk(KERN_CRIT + "EDAC PCI- " + "Detected Parity Error on %s\n", + pci_name (dev)); + + atomic_inc(&pci_parity_count); + } + } + + /* read the device TYPE, looking for bridges */ + pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type); + + debugf2("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id ); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + /* On bridges, need to examine secondary status register */ + status = get_pci_parity_status(dev, 1); + + debugf2("PCI SEC_STATUS= 0x%04x %s\n", + status, dev->dev.bus_id ); + + /* check the secondary status reg for errors */ + if (status) { + if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) + printk(KERN_CRIT + "EDAC PCI-Bridge- " + "Signaled System Error on %s\n", + pci_name (dev)); + + if (status & (PCI_STATUS_PARITY)) { + printk(KERN_CRIT + "EDAC PCI-Bridge- " + "Master Data Parity Error on %s\n", + pci_name (dev)); + + atomic_inc(&pci_parity_count); + } + + if (status & (PCI_STATUS_DETECTED_PARITY)) { + printk(KERN_CRIT + "EDAC PCI-Bridge- " + "Detected Parity Error on %s\n", + pci_name (dev)); + + atomic_inc(&pci_parity_count); + } + } + } +} + +/* + * check_dev_on_list: Scan for a PCI device on a white/black list + * @list: an EDAC &edac_pci_device_list white/black list pointer + * @free_index: index of next free entry on the list + * @pci_dev: PCI Device pointer + * + * see if list contains the device. + * + * Returns: 0 not found + * 1 found on list + */ +static int check_dev_on_list(struct edac_pci_device_list *list, int free_index, + struct pci_dev *dev) +{ + int i; + int rc = 0; /* Assume not found */ + unsigned short vendor=dev->vendor; + unsigned short device=dev->device; + + /* Scan the list, looking for a vendor/device match + */ + for (i = 0; i < free_index; i++, list++ ) { + if ( (list->vendor == vendor ) && + (list->device == device )) { + rc = 1; + break; + } + } + + return rc; +} + +/* + * pci_dev parity list iterator + * Scan the PCI device list for one iteration, looking for SERRORs + * Master Parity ERRORS or Parity ERRORs on primary or secondary devices + */ +static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn) +{ + struct pci_dev *dev=NULL; + + /* request for kernel access to the next PCI device, if any, + * and while we are looking at it have its reference count + * bumped until we are done with it + */ + while((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + + /* if whitelist exists then it has priority, so only scan those + * devices on the whitelist + */ + if (pci_whitelist_count > 0 ) { + if (check_dev_on_list(pci_whitelist, + pci_whitelist_count, dev)) + fn(dev); + } else { + /* + * if no whitelist, then check if this devices is + * blacklisted + */ + if (!check_dev_on_list(pci_blacklist, + pci_blacklist_count, dev)) + fn(dev); + } + } +} + +static void do_pci_parity_check(void) +{ + unsigned long flags; + int before_count; + + debugf3("MC: " __FILE__ ": %s()\n", __func__); + + if (!check_pci_parity) + return; + + before_count = atomic_read(&pci_parity_count); + + /* scan all PCI devices looking for a Parity Error on devices and + * bridges + */ + local_irq_save(flags); + edac_pci_dev_parity_iterator(edac_pci_dev_parity_test); + local_irq_restore(flags); + + /* Only if operator has selected panic on PCI Error */ + if (panic_on_pci_parity) { + /* If the count is different 'after' from 'before' */ + if (before_count != atomic_read(&pci_parity_count)) + panic("EDAC: PCI Parity Error"); + } +} + + +static inline void clear_pci_parity_errors(void) +{ + /* Clear any PCI bus parity errors that devices initially have logged + * in their registers. + */ + edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear); +} + + +#else /* CONFIG_PCI */ + + +static inline void do_pci_parity_check(void) +{ + /* no-op */ +} + + +static inline void clear_pci_parity_errors(void) +{ + /* no-op */ +} + + +#endif /* CONFIG_PCI */ + +/* + * Iterate over all MC instances and check for ECC, et al, errors + */ +static inline void check_mc_devices (void) +{ + unsigned long flags; + struct list_head *item; + struct mem_ctl_info *mci; + + debugf3("MC: " __FILE__ ": %s()\n", __func__); + + /* during poll, have interrupts off */ + local_irq_save(flags); + + list_for_each(item, &mc_devices) { + mci = list_entry(item, struct mem_ctl_info, link); + + if (mci->edac_check != NULL) + mci->edac_check(mci); + } + + local_irq_restore(flags); +} + + +/* + * Check MC status every poll_msec. + * Check PCI status every poll_msec as well. + * + * This where the work gets done for edac. + * + * SMP safe, doesn't use NMI, and auto-rate-limits. + */ +static void do_edac_check(void) +{ + + debugf3("MC: " __FILE__ ": %s()\n", __func__); + + check_mc_devices(); + + do_pci_parity_check(); +} + + +/* + * EDAC thread state information + */ +struct bs_thread_info +{ + struct task_struct *task; + struct completion *event; + char *name; + void (*run)(void); +}; + +static struct bs_thread_info bs_thread; + +/* + * edac_kernel_thread + * This the kernel thread that processes edac operations + * in a normal thread environment + */ +static int edac_kernel_thread(void *arg) +{ + struct bs_thread_info *thread = (struct bs_thread_info *) arg; + + /* detach thread */ + daemonize(thread->name); + + current->exit_signal = SIGCHLD; + allow_signal(SIGKILL); + thread->task = current; + + /* indicate to starting task we have started */ + complete(thread->event); + + /* loop forever, until we are told to stop */ + while(thread->run != NULL) { + void (*run)(void); + + /* call the function to check the memory controllers */ + run = thread->run; + if (run) + run(); + + if (signal_pending(current)) + flush_signals(current); + + /* ensure we are interruptable */ + set_current_state(TASK_INTERRUPTIBLE); + + /* goto sleep for the interval */ + schedule_timeout((HZ * poll_msec) / 1000); + try_to_freeze(); + } + + /* notify waiter that we are exiting */ + complete(thread->event); + + return 0; +} + +/* + * edac_mc_init + * module initialization entry point + */ +static int __init edac_mc_init(void) +{ + int ret; + struct completion event; + + printk(KERN_INFO "MC: " __FILE__ " version " EDAC_MC_VERSION "\n"); + + /* + * Harvest and clear any boot/initialization PCI parity errors + * + * FIXME: This only clears errors logged by devices present at time of + * module initialization. We should also do an initial clear + * of each newly hotplugged device. + */ + clear_pci_parity_errors(); + + /* perform check for first time to harvest boot leftovers */ + do_edac_check(); + + /* Create the MC sysfs entires */ + if (edac_sysfs_memctrl_setup()) { + printk(KERN_ERR "EDAC MC: Error initializing sysfs code\n"); + return -ENODEV; + } + + /* Create the PCI parity sysfs entries */ + if (edac_sysfs_pci_setup()) { + edac_sysfs_memctrl_teardown(); + printk(KERN_ERR "EDAC PCI: Error initializing sysfs code\n"); + return -ENODEV; + } + + /* Create our kernel thread */ + init_completion(&event); + bs_thread.event = &event; + bs_thread.name = "kedac"; + bs_thread.run = do_edac_check; + + /* create our kernel thread */ + ret = kernel_thread(edac_kernel_thread, &bs_thread, CLONE_KERNEL); + if (ret < 0) { + /* remove the sysfs entries */ + edac_sysfs_memctrl_teardown(); + edac_sysfs_pci_teardown(); + return -ENOMEM; + } + + /* wait for our kernel theard ack that it is up and running */ + wait_for_completion(&event); + + return 0; +} + + +/* + * edac_mc_exit() + * module exit/termination functioni + */ +static void __exit edac_mc_exit(void) +{ + struct completion event; + + debugf0("MC: " __FILE__ ": %s()\n", __func__); + + init_completion(&event); + bs_thread.event = &event; + + /* As soon as ->run is set to NULL, the task could disappear, + * so we need to hold tasklist_lock until we have sent the signal + */ + read_lock(&tasklist_lock); + bs_thread.run = NULL; + send_sig(SIGKILL, bs_thread.task, 1); + read_unlock(&tasklist_lock); + wait_for_completion(&event); + + /* tear down the sysfs device */ + edac_sysfs_memctrl_teardown(); + edac_sysfs_pci_teardown(); +} + + + + +module_init(edac_mc_init); +module_exit(edac_mc_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n" + "Based on.work by Dan Hollis et al"); +MODULE_DESCRIPTION("Core library routines for MC reporting"); + +module_param(panic_on_ue, int, 0644); +MODULE_PARM_DESC(panic_on_ue, "Panic on uncorrected error: 0=off 1=on"); +module_param(check_pci_parity, int, 0644); +MODULE_PARM_DESC(check_pci_parity, "Check for PCI bus parity errors: 0=off 1=on"); +module_param(panic_on_pci_parity, int, 0644); +MODULE_PARM_DESC(panic_on_pci_parity, "Panic on PCI Bus Parity error: 0=off 1=on"); +module_param(log_ue, int, 0644); +MODULE_PARM_DESC(log_ue, "Log uncorrectable error to console: 0=off 1=on"); +module_param(log_ce, int, 0644); +MODULE_PARM_DESC(log_ce, "Log correctable error to console: 0=off 1=on"); +module_param(poll_msec, int, 0644); +MODULE_PARM_DESC(poll_msec, "Polling period in milliseconds"); +#ifdef CONFIG_EDAC_DEBUG +module_param(edac_debug_level, int, 0644); +MODULE_PARM_DESC(edac_debug_level, "Debug level"); +#endif diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h new file mode 100644 index 000000000000..75ecf484a43a --- /dev/null +++ b/drivers/edac/edac_mc.h @@ -0,0 +1,448 @@ +/* + * MC kernel module + * (C) 2003 Linux Networx (http://lnxi.com) + * This file may be distributed under the terms of the + * GNU General Public License. + * + * Written by Thayne Harbaugh + * Based on work by Dan Hollis <goemon at anime dot net> and others. + * http://www.anime.net/~goemon/linux-ecc/ + * + * NMI handling support added by + * Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com> + * + * $Id: edac_mc.h,v 1.4.2.10 2005/10/05 00:43:44 dsp_llnl Exp $ + * + */ + + +#ifndef _EDAC_MC_H_ +#define _EDAC_MC_H_ + + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/smp.h> +#include <linux/pci.h> +#include <linux/time.h> +#include <linux/nmi.h> +#include <linux/rcupdate.h> +#include <linux/completion.h> +#include <linux/kobject.h> + + +#define EDAC_MC_LABEL_LEN 31 +#define MC_PROC_NAME_MAX_LEN 7 + +#if PAGE_SHIFT < 20 +#define PAGES_TO_MiB( pages ) ( ( pages ) >> ( 20 - PAGE_SHIFT ) ) +#else /* PAGE_SHIFT > 20 */ +#define PAGES_TO_MiB( pages ) ( ( pages ) << ( PAGE_SHIFT - 20 ) ) +#endif + +#ifdef CONFIG_EDAC_DEBUG +extern int edac_debug_level; +#define edac_debug_printk(level, fmt, args...) \ +do { if (level <= edac_debug_level) printk(KERN_DEBUG fmt, ##args); } while(0) +#define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ ) +#define debugf1( ... ) edac_debug_printk(1, __VA_ARGS__ ) +#define debugf2( ... ) edac_debug_printk(2, __VA_ARGS__ ) +#define debugf3( ... ) edac_debug_printk(3, __VA_ARGS__ ) +#define debugf4( ... ) edac_debug_printk(4, __VA_ARGS__ ) +#else /* !CONFIG_EDAC_DEBUG */ +#define debugf0( ... ) +#define debugf1( ... ) +#define debugf2( ... ) +#define debugf3( ... ) +#define debugf4( ... ) +#endif /* !CONFIG_EDAC_DEBUG */ + + +#define bs_xstr(s) bs_str(s) +#define bs_str(s) #s +#define BS_MOD_STR bs_xstr(KBUILD_BASENAME) + +#define BIT(x) (1 << (x)) + +#define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, PCI_DEVICE_ID_ ## vend ## _ ## dev + +/* memory devices */ +enum dev_type { + DEV_UNKNOWN = 0, + DEV_X1, + DEV_X2, + DEV_X4, + DEV_X8, + DEV_X16, + DEV_X32, /* Do these parts exist? */ + DEV_X64 /* Do these parts exist? */ +}; + +#define DEV_FLAG_UNKNOWN BIT(DEV_UNKNOWN) +#define DEV_FLAG_X1 BIT(DEV_X1) +#define DEV_FLAG_X2 BIT(DEV_X2) +#define DEV_FLAG_X4 BIT(DEV_X4) +#define DEV_FLAG_X8 BIT(DEV_X8) +#define DEV_FLAG_X16 BIT(DEV_X16) +#define DEV_FLAG_X32 BIT(DEV_X32) +#define DEV_FLAG_X64 BIT(DEV_X64) + +/* memory types */ +enum mem_type { + MEM_EMPTY = 0, /* Empty csrow */ + MEM_RESERVED, /* Reserved csrow type */ + MEM_UNKNOWN, /* Unknown csrow type */ + MEM_FPM, /* Fast page mode */ + MEM_EDO, /* Extended data out */ + MEM_BEDO, /* Burst Extended data out */ + MEM_SDR, /* Single data rate SDRAM */ + MEM_RDR, /* Registered single data rate SDRAM */ + MEM_DDR, /* Double data rate SDRAM */ + MEM_RDDR, /* Registered Double data rate SDRAM */ + MEM_RMBS /* Rambus DRAM */ +}; + +#define MEM_FLAG_EMPTY BIT(MEM_EMPTY) +#define MEM_FLAG_RESERVED BIT(MEM_RESERVED) +#define MEM_FLAG_UNKNOWN BIT(MEM_UNKNOWN) +#define MEM_FLAG_FPM BIT(MEM_FPM) +#define MEM_FLAG_EDO BIT(MEM_EDO) +#define MEM_FLAG_BEDO BIT(MEM_BEDO) +#define MEM_FLAG_SDR BIT(MEM_SDR) +#define MEM_FLAG_RDR BIT(MEM_RDR) +#define MEM_FLAG_DDR BIT(MEM_DDR) +#define MEM_FLAG_RDDR BIT(MEM_RDDR) +#define MEM_FLAG_RMBS BIT(MEM_RMBS) + + +/* chipset Error Detection and Correction capabilities and mode */ +enum edac_type { + EDAC_UNKNOWN = 0, /* Unknown if ECC is available */ + EDAC_NONE, /* Doesnt support ECC */ + EDAC_RESERVED, /* Reserved ECC type */ + EDAC_PARITY, /* Detects parity errors */ + EDAC_EC, /* Error Checking - no correction */ + EDAC_SECDED, /* Single bit error correction, Double detection */ + EDAC_S2ECD2ED, /* Chipkill x2 devices - do these exist? */ + EDAC_S4ECD4ED, /* Chipkill x4 devices */ + EDAC_S8ECD8ED, /* Chipkill x8 devices */ + EDAC_S16ECD16ED, /* Chipkill x16 devices */ +}; + +#define EDAC_FLAG_UNKNOWN BIT(EDAC_UNKNOWN) +#define EDAC_FLAG_NONE BIT(EDAC_NONE) +#define EDAC_FLAG_PARITY BIT(EDAC_PARITY) +#define EDAC_FLAG_EC BIT(EDAC_EC) +#define EDAC_FLAG_SECDED BIT(EDAC_SECDED) +#define EDAC_FLAG_S2ECD2ED BIT(EDAC_S2ECD2ED) +#define EDAC_FLAG_S4ECD4ED BIT(EDAC_S4ECD4ED) +#define EDAC_FLAG_S8ECD8ED BIT(EDAC_S8ECD8ED) +#define EDAC_FLAG_S16ECD16ED BIT(EDAC_S16ECD16ED) + + +/* scrubbing capabilities */ +enum scrub_type { + SCRUB_UNKNOWN = 0, /* Unknown if scrubber is available */ + SCRUB_NONE, /* No scrubber */ + SCRUB_SW_PROG, /* SW progressive (sequential) scrubbing */ + SCRUB_SW_SRC, /* Software scrub only errors */ + SCRUB_SW_PROG_SRC, /* Progressive software scrub from an error */ + SCRUB_SW_TUNABLE, /* Software scrub frequency is tunable */ + SCRUB_HW_PROG, /* HW progressive (sequential) scrubbing */ + SCRUB_HW_SRC, /* Hardware scrub only errors */ + SCRUB_HW_PROG_SRC, /* Progressive hardware scrub from an error */ + SCRUB_HW_TUNABLE /* Hardware scrub frequency is tunable */ +}; + +#define SCRUB_FLAG_SW_PROG BIT(SCRUB_SW_PROG) +#define SCRUB_FLAG_SW_SRC BIT(SCRUB_SW_SRC_CORR) +#define SCRUB_FLAG_SW_PROG_SRC BIT(SCRUB_SW_PROG_SRC_CORR) +#define SCRUB_FLAG_SW_TUN BIT(SCRUB_SW_SCRUB_TUNABLE) +#define SCRUB_FLAG_HW_PROG BIT(SCRUB_HW_PROG) +#define SCRUB_FLAG_HW_SRC BIT(SCRUB_HW_SRC_CORR) +#define SCRUB_FLAG_HW_PROG_SRC BIT(SCRUB_HW_PROG_SRC_CORR) +#define SCRUB_FLAG_HW_TUN BIT(SCRUB_HW_TUNABLE) + +enum mci_sysfs_status { + MCI_SYSFS_INACTIVE = 0, /* sysfs entries NOT registered */ + MCI_SYSFS_ACTIVE /* sysfs entries ARE registered */ +}; + +/* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */ + +/* + * There are several things to be aware of that aren't at all obvious: + * + * + * SOCKETS, SOCKET SETS, BANKS, ROWS, CHIP-SELECT ROWS, CHANNELS, etc.. + * + * These are some of the many terms that are thrown about that don't always + * mean what people think they mean (Inconceivable!). In the interest of + * creating a common ground for discussion, terms and their definitions + * will be established. + * + * Memory devices: The individual chip on a memory stick. These devices + * commonly output 4 and 8 bits each. Grouping several + * of these in parallel provides 64 bits which is common + * for a memory stick. + * + * Memory Stick: A printed circuit board that agregates multiple + * memory devices in parallel. This is the atomic + * memory component that is purchaseable by Joe consumer + * and loaded into a memory socket. + * + * Socket: A physical connector on the motherboard that accepts + * a single memory stick. + * + * Channel: Set of memory devices on a memory stick that must be + * grouped in parallel with one or more additional + * channels from other memory sticks. This parallel + * grouping of the output from multiple channels are + * necessary for the smallest granularity of memory access. + * Some memory controllers are capable of single channel - + * which means that memory sticks can be loaded + * individually. Other memory controllers are only + * capable of dual channel - which means that memory + * sticks must be loaded as pairs (see "socket set"). + * + * Chip-select row: All of the memory devices that are selected together. + * for a single, minimum grain of memory access. + * This selects all of the parallel memory devices across + * all of the parallel channels. Common chip-select rows + * for single channel are 64 bits, for dual channel 128 + * bits. + * + * Single-Ranked stick: A Single-ranked stick has 1 chip-select row of memmory. + * Motherboards commonly drive two chip-select pins to + * a memory stick. A single-ranked stick, will occupy + * only one of those rows. The other will be unused. + * + * Double-Ranked stick: A double-ranked stick has two chip-select rows which + * access different sets of memory devices. The two + * rows cannot be accessed concurrently. + * + * Double-sided stick: DEPRECATED TERM, see Double-Ranked stick. + * A double-sided stick has two chip-select rows which + * access different sets of memory devices. The two + * rows cannot be accessed concurrently. "Double-sided" + * is irrespective of the memory devices being mounted + * on both sides of the memory stick. + * + * Socket set: All of the memory sticks that are required for for + * a single memory access or all of the memory sticks + * spanned by a chip-select row. A single socket set + * has two chip-select rows and if double-sided sticks + * are used these will occupy those chip-select rows. + * + * Bank: This term is avoided because it is unclear when + * needing to distinguish between chip-select rows and + * socket sets. + * + * Controller pages: + * + * Physical pages: + * + * Virtual pages: + * + * + * STRUCTURE ORGANIZATION AND CHOICES + * + * + * + * PS - I enjoyed writing all that about as much as you enjoyed reading it. + */ + + +struct channel_info { + int chan_idx; /* channel index */ + u32 ce_count; /* Correctable Errors for this CHANNEL */ + char label[EDAC_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */ + struct csrow_info *csrow; /* the parent */ +}; + + +struct csrow_info { + unsigned long first_page; /* first page number in dimm */ + unsigned long last_page; /* last page number in dimm */ + unsigned long page_mask; /* used for interleaving - + 0UL for non intlv */ + u32 nr_pages; /* number of pages in csrow */ + u32 grain; /* granularity of reported error in bytes */ + int csrow_idx; /* the chip-select row */ + enum dev_type dtype; /* memory device type */ + u32 ue_count; /* Uncorrectable Errors for this csrow */ + u32 ce_count; /* Correctable Errors for this csrow */ + enum mem_type mtype; /* memory csrow type */ + enum edac_type edac_mode; /* EDAC mode for this csrow */ + struct mem_ctl_info *mci; /* the parent */ + + struct kobject kobj; /* sysfs kobject for this csrow */ + + /* FIXME the number of CHANNELs might need to become dynamic */ + u32 nr_channels; + struct channel_info *channels; +}; + + +struct mem_ctl_info { + struct list_head link; /* for global list of mem_ctl_info structs */ + unsigned long mtype_cap; /* memory types supported by mc */ + unsigned long edac_ctl_cap; /* Mem controller EDAC capabilities */ + unsigned long edac_cap; /* configuration capabilities - this is + closely related to edac_ctl_cap. The + difference is that the controller + may be capable of s4ecd4ed which would + be listed in edac_ctl_cap, but if + channels aren't capable of s4ecd4ed then the + edac_cap would not have that capability. */ + unsigned long scrub_cap; /* chipset scrub capabilities */ + enum scrub_type scrub_mode; /* current scrub mode */ + + enum mci_sysfs_status sysfs_active; /* status of sysfs */ + + /* pointer to edac checking routine */ + void (*edac_check) (struct mem_ctl_info * mci); + /* + * Remaps memory pages: controller pages to physical pages. + * For most MC's, this will be NULL. + */ + /* FIXME - why not send the phys page to begin with? */ + unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci, + unsigned long page); + int mc_idx; + int nr_csrows; + struct csrow_info *csrows; + /* + * FIXME - what about controllers on other busses? - IDs must be + * unique. pdev pointer should be sufficiently unique, but + * BUS:SLOT.FUNC numbers may not be unique. + */ + struct pci_dev *pdev; + const char *mod_name; + const char *mod_ver; + const char *ctl_name; + char proc_name[MC_PROC_NAME_MAX_LEN + 1]; + void *pvt_info; + u32 ue_noinfo_count; /* Uncorrectable Errors w/o info */ + u32 ce_noinfo_count; /* Correctable Errors w/o info */ + u32 ue_count; /* Total Uncorrectable Errors for this MC */ + u32 ce_count; /* Total Correctable Errors for this MC */ + unsigned long start_time; /* mci load start time (in jiffies) */ + + /* this stuff is for safe removal of mc devices from global list while + * NMI handlers may be traversing list + */ + struct rcu_head rcu; + struct completion complete; + + /* edac sysfs device control */ + struct kobject edac_mci_kobj; +}; + + + +/* write all or some bits in a byte-register*/ +static inline void pci_write_bits8(struct pci_dev *pdev, int offset, + u8 value, u8 mask) +{ + if (mask != 0xff) { + u8 buf; + pci_read_config_byte(pdev, offset, &buf); + value &= mask; + buf &= ~mask; + value |= buf; + } + pci_write_config_byte(pdev, offset, value); +} + + +/* write all or some bits in a word-register*/ +static inline void pci_write_bits16(struct pci_dev *pdev, int offset, + u16 value, u16 mask) +{ + if (mask != 0xffff) { + u16 buf; + pci_read_config_word(pdev, offset, &buf); + value &= mask; + buf &= ~mask; + value |= buf; + } + pci_write_config_word(pdev, offset, value); +} + + +/* write all or some bits in a dword-register*/ +static inline void pci_write_bits32(struct pci_dev *pdev, int offset, + u32 value, u32 mask) +{ + if (mask != 0xffff) { + u32 buf; + pci_read_config_dword(pdev, offset, &buf); + value &= mask; + buf &= ~mask; + value |= buf; + } + pci_write_config_dword(pdev, offset, value); +} + + +#ifdef CONFIG_EDAC_DEBUG +void edac_mc_dump_channel(struct channel_info *chan); +void edac_mc_dump_mci(struct mem_ctl_info *mci); +void edac_mc_dump_csrow(struct csrow_info *csrow); +#endif /* CONFIG_EDAC_DEBUG */ + +extern int edac_mc_add_mc(struct mem_ctl_info *mci); +extern int edac_mc_del_mc(struct mem_ctl_info *mci); + +extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, + unsigned long page); + +extern struct mem_ctl_info *edac_mc_find_mci_by_pdev(struct pci_dev + *pdev); + +extern void edac_mc_scrub_block(unsigned long page, + unsigned long offset, u32 size); + +/* + * The no info errors are used when error overflows are reported. + * There are a limited number of error logging registers that can + * be exausted. When all registers are exhausted and an additional + * error occurs then an error overflow register records that an + * error occured and the type of error, but doesn't have any + * further information. The ce/ue versions make for cleaner + * reporting logic and function interface - reduces conditional + * statement clutter and extra function arguments. + */ +extern void edac_mc_handle_ce(struct mem_ctl_info *mci, + unsigned long page_frame_number, + unsigned long offset_in_page, + unsigned long syndrome, + int row, int channel, const char *msg); + +extern void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, + const char *msg); + +extern void edac_mc_handle_ue(struct mem_ctl_info *mci, + unsigned long page_frame_number, + unsigned long offset_in_page, + int row, const char *msg); + +extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, + const char *msg); + +/* + * This kmalloc's and initializes all the structures. + * Can't be used if all structures don't have the same lifetime. + */ +extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, + unsigned nr_csrows, unsigned nr_chans); + +/* Free an mc previously allocated by edac_mc_alloc() */ +extern void edac_mc_free(struct mem_ctl_info *mci); + + +#endif /* _EDAC_MC_H_ */ diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c new file mode 100644 index 000000000000..52596e75f9c2 --- /dev/null +++ b/drivers/edac/i82860_edac.c @@ -0,0 +1,299 @@ +/* + * Intel 82860 Memory Controller kernel module + * (C) 2005 Red Hat (http://www.redhat.com) + * This file may be distributed under the terms of the + * GNU General Public License. + * + * Written by Ben Woodard <woodard@redhat.com> + * shamelessly copied from and based upon the edac_i82875 driver + * by Thayne Harbaugh of Linux Networx. (http://lnxi.com) + */ + + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> +#include <linux/slab.h> +#include "edac_mc.h" + + +#ifndef PCI_DEVICE_ID_INTEL_82860_0 +#define PCI_DEVICE_ID_INTEL_82860_0 0x2531 +#endif /* PCI_DEVICE_ID_INTEL_82860_0 */ + +#define I82860_MCHCFG 0x50 +#define I82860_GBA 0x60 +#define I82860_GBA_MASK 0x7FF +#define I82860_GBA_SHIFT 24 +#define I82860_ERRSTS 0xC8 +#define I82860_EAP 0xE4 +#define I82860_DERRCTL_STS 0xE2 + +enum i82860_chips { + I82860 = 0, +}; + +struct i82860_dev_info { + const char *ctl_name; +}; + +struct i82860_error_info { + u16 errsts; + u32 eap; + u16 derrsyn; + u16 errsts2; +}; + +static const struct i82860_dev_info i82860_devs[] = { + [I82860] = { + .ctl_name = "i82860"}, +}; + +static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code + has already registered driver */ + +static int i82860_registered = 1; + +static void i82860_get_error_info (struct mem_ctl_info *mci, + struct i82860_error_info *info) +{ + /* + * This is a mess because there is no atomic way to read all the + * registers at once and the registers can transition from CE being + * overwritten by UE. + */ + pci_read_config_word(mci->pdev, I82860_ERRSTS, &info->errsts); + pci_read_config_dword(mci->pdev, I82860_EAP, &info->eap); + pci_read_config_word(mci->pdev, I82860_DERRCTL_STS, &info->derrsyn); + pci_read_config_word(mci->pdev, I82860_ERRSTS, &info->errsts2); + + pci_write_bits16(mci->pdev, I82860_ERRSTS, 0x0003, 0x0003); + + /* + * If the error is the same 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 & 0x0003)) + return; + if ((info->errsts ^ info->errsts2) & 0x0003) { + pci_read_config_dword(mci->pdev, I82860_EAP, &info->eap); + pci_read_config_word(mci->pdev, I82860_DERRCTL_STS, + &info->derrsyn); + } +} + +static int i82860_process_error_info (struct mem_ctl_info *mci, + struct i82860_error_info *info, int handle_errors) +{ + int row; + + if (!(info->errsts2 & 0x0003)) + return 0; + + if (!handle_errors) + return 1; + + if ((info->errsts ^ info->errsts2) & 0x0003) { + edac_mc_handle_ce_no_info(mci, "UE overwrote CE"); + info->errsts = info->errsts2; + } + + info->eap >>= PAGE_SHIFT; + row = edac_mc_find_csrow_by_page(mci, info->eap); + + if (info->errsts & 0x0002) + edac_mc_handle_ue(mci, info->eap, 0, row, "i82860 UE"); + else + edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row, + 0, "i82860 UE"); + + return 1; +} + +static void i82860_check(struct mem_ctl_info *mci) +{ + struct i82860_error_info info; + + debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__); + i82860_get_error_info(mci, &info); + i82860_process_error_info(mci, &info, 1); +} + +static int i82860_probe1(struct pci_dev *pdev, int dev_idx) +{ + int rc = -ENODEV; + int index; + struct mem_ctl_info *mci = NULL; + unsigned long last_cumul_size; + + u16 mchcfg_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ + + /* RDRAM has channels but these don't map onto the abstractions that + edac uses. + The device groups from the GRA registers seem to map reasonably + well onto the notion of a chip select row. + There are 16 GRA registers and since the name is associated with + the channel and the GRA registers map to physical devices so we are + going to make 1 channel for group. + */ + mci = edac_mc_alloc(0, 16, 1); + if (!mci) + return -ENOMEM; + + debugf3("MC: " __FILE__ ": %s(): init mci\n", __func__); + + mci->pdev = pdev; + mci->mtype_cap = MEM_FLAG_DDR; + + + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; + /* I"m not sure about this but I think that all RDRAM is SECDED */ + mci->edac_cap = EDAC_FLAG_SECDED; + /* adjust FLAGS */ + + mci->mod_name = BS_MOD_STR; + mci->mod_ver = "$Revision: 1.1.2.6 $"; + mci->ctl_name = i82860_devs[dev_idx].ctl_name; + mci->edac_check = i82860_check; + mci->ctl_page_to_phys = NULL; + + pci_read_config_word(mci->pdev, I82860_MCHCFG, &mchcfg_ddim); + mchcfg_ddim = mchcfg_ddim & 0x180; + + /* + * The group row boundary (GRA) reg values are boundary address + * for each DRAM row with a granularity of 16MB. GRA regs are + * cumulative; therefore GRA15 will contain the total memory contained + * in all eight rows. + */ + for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { + u16 value; + u32 cumul_size; + struct csrow_info *csrow = &mci->csrows[index]; + + pci_read_config_word(mci->pdev, I82860_GBA + index * 2, + &value); + + cumul_size = (value & I82860_GBA_MASK) << + (I82860_GBA_SHIFT - PAGE_SHIFT); + debugf3("MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n", + __func__, index, cumul_size); + if (cumul_size == last_cumul_size) + continue; /* not populated */ + + csrow->first_page = last_cumul_size; + csrow->last_page = cumul_size - 1; + csrow->nr_pages = cumul_size - last_cumul_size; + last_cumul_size = cumul_size; + csrow->grain = 1 << 12; /* I82860_EAP has 4KiB reolution */ + csrow->mtype = MEM_RMBS; + csrow->dtype = DEV_UNKNOWN; + csrow->edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE; + } + + /* clear counters */ + pci_write_bits16(mci->pdev, I82860_ERRSTS, 0x0003, 0x0003); + + if (edac_mc_add_mc(mci)) { + debugf3("MC: " __FILE__ + ": %s(): failed edac_mc_add_mc()\n", + __func__); + edac_mc_free(mci); + } else { + /* get this far and it's successful */ + debugf3("MC: " __FILE__ ": %s(): success\n", __func__); + rc = 0; + } + return rc; +} + +/* returns count (>= 0), or negative on error */ +static int __devinit i82860_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int rc; + + debugf0("MC: " __FILE__ ": %s()\n", __func__); + + printk(KERN_INFO "i82860 init one\n"); + if(pci_enable_device(pdev) < 0) + return -EIO; + rc = i82860_probe1(pdev, ent->driver_data); + if(rc == 0) + mci_pdev = pci_dev_get(pdev); + return rc; +} + +static void __devexit i82860_remove_one(struct pci_dev *pdev) +{ + struct mem_ctl_info *mci; + + debugf0(__FILE__ ": %s()\n", __func__); + + mci = edac_mc_find_mci_by_pdev(pdev); + if ((mci != NULL) && (edac_mc_del_mc(mci) == 0)) + edac_mc_free(mci); +} + +static const struct pci_device_id i82860_pci_tbl[] __devinitdata = { + {PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, + I82860}, + {0,} /* 0 terminated list. */ +}; + +MODULE_DEVICE_TABLE(pci, i82860_pci_tbl); + +static struct pci_driver i82860_driver = { + .name = BS_MOD_STR, + .probe = i82860_init_one, + .remove = __devexit_p(i82860_remove_one), + .id_table = i82860_pci_tbl, +}; + +static int __init i82860_init(void) +{ + int pci_rc; + + debugf3("MC: " __FILE__ ": %s()\n", __func__); + if ((pci_rc = pci_register_driver(&i82860_driver)) < 0) + return pci_rc; + + if (!mci_pdev) { + i82860_registered = 0; + mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82860_0, NULL); + if (mci_pdev == NULL) { + debugf0("860 pci_get_device fail\n"); + return -ENODEV; + } + pci_rc = i82860_init_one(mci_pdev, i82860_pci_tbl); + if (pci_rc < 0) { + debugf0("860 init fail\n"); + pci_dev_put(mci_pdev); + return -ENODEV; + } + } + return 0; +} + +static void __exit i82860_exit(void) +{ + debugf3("MC: " __FILE__ ": %s()\n", __func__); + + pci_unregister_driver(&i82860_driver); + if (!i82860_registered) { + i82860_remove_one(mci_pdev); + pci_dev_put(mci_pdev); + } +} + +module_init(i82860_init); +module_exit(i82860_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR + ("Red Hat Inc. (http://www.redhat.com.com) Ben Woodard <woodard@redhat.com>"); +MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers"); diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c new file mode 100644 index 000000000000..009c08fe5d69 --- /dev/null +++ b/drivers/edac/i82875p_edac.c @@ -0,0 +1,532 @@ +/* + * Intel D82875P Memory Controller kernel module + * (C) 2003 Linux Networx (http://lnxi.com) + * This file may be distributed under the terms of the + * GNU General Public License. + * + * Written by Thayne Harbaugh + * Contributors: + * Wang Zhenyu at intel.com + * + * $Id: edac_i82875p.c,v 1.5.2.11 2005/10/05 00:43:44 dsp_llnl Exp $ + * + * Note: E7210 appears same as D82875P - zhenyu.z.wang at intel.com + */ + + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> + +#include <linux/pci.h> +#include <linux/pci_ids.h> + +#include <linux/slab.h> + +#include "edac_mc.h" + + +#ifndef PCI_DEVICE_ID_INTEL_82875_0 +#define PCI_DEVICE_ID_INTEL_82875_0 0x2578 +#endif /* PCI_DEVICE_ID_INTEL_82875_0 */ + +#ifndef PCI_DEVICE_ID_INTEL_82875_6 +#define PCI_DEVICE_ID_INTEL_82875_6 0x257e +#endif /* PCI_DEVICE_ID_INTEL_82875_6 */ + + +/* four csrows in dual channel, eight in single channel */ +#define I82875P_NR_CSROWS(nr_chans) (8/(nr_chans)) + + +/* Intel 82875p register addresses - device 0 function 0 - DRAM Controller */ +#define I82875P_EAP 0x58 /* Error Address Pointer (32b) + * + * 31:12 block address + * 11:0 reserved + */ + +#define I82875P_DERRSYN 0x5c /* DRAM Error Syndrome (8b) + * + * 7:0 DRAM ECC Syndrome + */ + +#define I82875P_DES 0x5d /* DRAM Error Status (8b) + * + * 7:1 reserved + * 0 Error channel 0/1 + */ + +#define I82875P_ERRSTS 0xc8 /* Error Status Register (16b) + * + * 15:10 reserved + * 9 non-DRAM lock error (ndlock) + * 8 Sftwr Generated SMI + * 7 ECC UE + * 6 reserved + * 5 MCH detects unimplemented cycle + * 4 AGP access outside GA + * 3 Invalid AGP access + * 2 Invalid GA translation table + * 1 Unsupported AGP command + * 0 ECC CE + */ + +#define I82875P_ERRCMD 0xca /* Error Command (16b) + * + * 15:10 reserved + * 9 SERR on non-DRAM lock + * 8 SERR on ECC UE + * 7 SERR on ECC CE + * 6 target abort on high exception + * 5 detect unimplemented cyc + * 4 AGP access outside of GA + * 3 SERR on invalid AGP access + * 2 invalid translation table + * 1 SERR on unsupported AGP command + * 0 reserved + */ + + +/* Intel 82875p register addresses - device 6 function 0 - DRAM Controller */ +#define I82875P_PCICMD6 0x04 /* PCI Command Register (16b) + * + * 15:10 reserved + * 9 fast back-to-back - ro 0 + * 8 SERR enable - ro 0 + * 7 addr/data stepping - ro 0 + * 6 parity err enable - ro 0 + * 5 VGA palette snoop - ro 0 + * 4 mem wr & invalidate - ro 0 + * 3 special cycle - ro 0 + * 2 bus master - ro 0 + * 1 mem access dev6 - 0(dis),1(en) + * 0 IO access dev3 - 0(dis),1(en) + */ + +#define I82875P_BAR6 0x10 /* Mem Delays Base ADDR Reg (32b) + * + * 31:12 mem base addr [31:12] + * 11:4 address mask - ro 0 + * 3 prefetchable - ro 0(non),1(pre) + * 2:1 mem type - ro 0 + * 0 mem space - ro 0 + */ + +/* Intel 82875p MMIO register space - device 0 function 0 - MMR space */ + +#define I82875P_DRB_SHIFT 26 /* 64MiB grain */ +#define I82875P_DRB 0x00 /* DRAM Row Boundary (8b x 8) + * + * 7 reserved + * 6:0 64MiB row boundary addr + */ + +#define I82875P_DRA 0x10 /* DRAM Row Attribute (4b x 8) + * + * 7 reserved + * 6:4 row attr row 1 + * 3 reserved + * 2:0 row attr row 0 + * + * 000 = 4KiB + * 001 = 8KiB + * 010 = 16KiB + * 011 = 32KiB + */ + +#define I82875P_DRC 0x68 /* DRAM Controller Mode (32b) + * + * 31:30 reserved + * 29 init complete + * 28:23 reserved + * 22:21 nr chan 00=1,01=2 + * 20 reserved + * 19:18 Data Integ Mode 00=none,01=ecc + * 17:11 reserved + * 10:8 refresh mode + * 7 reserved + * 6:4 mode select + * 3:2 reserved + * 1:0 DRAM type 01=DDR + */ + + +enum i82875p_chips { + I82875P = 0, +}; + + +struct i82875p_pvt { + struct pci_dev *ovrfl_pdev; + void *ovrfl_window; +}; + + +struct i82875p_dev_info { + const char *ctl_name; +}; + + +struct i82875p_error_info { + u16 errsts; + u32 eap; + u8 des; + u8 derrsyn; + u16 errsts2; +}; + + +static const struct i82875p_dev_info i82875p_devs[] = { + [I82875P] = { + .ctl_name = "i82875p"}, +}; + +static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code + has already registered driver */ +static int i82875p_registered = 1; + +static void i82875p_get_error_info (struct mem_ctl_info *mci, + struct i82875p_error_info *info) +{ + /* + * This is a mess because there is no atomic way to read all the + * registers at once and the registers can transition from CE being + * overwritten by UE. + */ + pci_read_config_word(mci->pdev, I82875P_ERRSTS, &info->errsts); + pci_read_config_dword(mci->pdev, I82875P_EAP, &info->eap); + pci_read_config_byte(mci->pdev, I82875P_DES, &info->des); + pci_read_config_byte(mci->pdev, I82875P_DERRSYN, &info->derrsyn); + pci_read_config_word(mci->pdev, I82875P_ERRSTS, &info->errsts2); + + pci_write_bits16(mci->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(mci->pdev, I82875P_EAP, &info->eap); + pci_read_config_byte(mci->pdev, I82875P_DES, &info->des); + pci_read_config_byte(mci->pdev, I82875P_DERRSYN, + &info->derrsyn); + } +} + +static int i82875p_process_error_info (struct mem_ctl_info *mci, + struct i82875p_error_info *info, int handle_errors) +{ + int row, multi_chan; + + multi_chan = mci->csrows[0].nr_channels - 1; + + if (!(info->errsts2 & 0x0081)) + return 0; + + if (!handle_errors) + return 1; + + if ((info->errsts ^ info->errsts2) & 0x0081) { + edac_mc_handle_ce_no_info(mci, "UE overwrote CE"); + info->errsts = info->errsts2; + } + + info->eap >>= PAGE_SHIFT; + row = edac_mc_find_csrow_by_page(mci, info->eap); + + if (info->errsts & 0x0080) + 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"); + + return 1; +} + + +static void i82875p_check(struct mem_ctl_info *mci) +{ + struct i82875p_error_info info; + + debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__); + i82875p_get_error_info(mci, &info); + i82875p_process_error_info(mci, &info, 1); +} + + +#ifdef CONFIG_PROC_FS +extern int pci_proc_attach_device(struct pci_dev *); +#endif + +static int i82875p_probe1(struct pci_dev *pdev, int dev_idx) +{ + int rc = -ENODEV; + int index; + struct mem_ctl_info *mci = NULL; + struct i82875p_pvt *pvt = NULL; + unsigned long last_cumul_size; + struct pci_dev *ovrfl_pdev; + void __iomem *ovrfl_window = NULL; + + u32 drc; + u32 drc_chan; /* Number of channels 0=1chan,1=2chan */ + u32 nr_chans; + u32 drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ + + debugf0("MC: " __FILE__ ": %s()\n", __func__); + + ovrfl_pdev = pci_find_device(PCI_VEND_DEV(INTEL, 82875_6), NULL); + + if (!ovrfl_pdev) { + /* + * Intel tells BIOS developers to hide device 6 which + * configures the overflow device access containing + * the DRBs - this is where we expose device 6. + * http://www.x86-secret.com/articles/tweak/pat/patsecrets-2.htm + */ + pci_write_bits8(pdev, 0xf4, 0x2, 0x2); + ovrfl_pdev = + pci_scan_single_device(pdev->bus, PCI_DEVFN(6, 0)); + if (!ovrfl_pdev) + goto fail; + } +#ifdef CONFIG_PROC_FS + if (!ovrfl_pdev->procent && pci_proc_attach_device(ovrfl_pdev)) { + printk(KERN_ERR "MC: " __FILE__ + ": %s(): Failed to attach overflow device\n", + __func__); + goto fail; + } +#endif /* CONFIG_PROC_FS */ + if (pci_enable_device(ovrfl_pdev)) { + printk(KERN_ERR "MC: " __FILE__ + ": %s(): Failed to enable overflow device\n", + __func__); + goto fail; + } + + if (pci_request_regions(ovrfl_pdev, pci_name(ovrfl_pdev))) { +#ifdef CORRECT_BIOS + goto fail; +#endif + } + /* cache is irrelevant for PCI bus reads/writes */ + ovrfl_window = ioremap_nocache(pci_resource_start(ovrfl_pdev, 0), + pci_resource_len(ovrfl_pdev, 0)); + + if (!ovrfl_window) { + printk(KERN_ERR "MC: " __FILE__ + ": %s(): Failed to ioremap bar6\n", __func__); + goto fail; + } + + /* need to find out the number of channels */ + drc = readl(ovrfl_window + I82875P_DRC); + drc_chan = ((drc >> 21) & 0x1); + nr_chans = drc_chan + 1; + drc_ddim = (drc >> 18) & 0x1; + + mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans), + nr_chans); + + if (!mci) { + rc = -ENOMEM; + goto fail; + } + + debugf3("MC: " __FILE__ ": %s(): init mci\n", __func__); + + mci->pdev = pdev; + mci->mtype_cap = MEM_FLAG_DDR; + + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; + mci->edac_cap = EDAC_FLAG_UNKNOWN; + /* adjust FLAGS */ + + mci->mod_name = BS_MOD_STR; + mci->mod_ver = "$Revision: 1.5.2.11 $"; + mci->ctl_name = i82875p_devs[dev_idx].ctl_name; + mci->edac_check = i82875p_check; + mci->ctl_page_to_phys = NULL; + + debugf3("MC: " __FILE__ ": %s(): init pvt\n", __func__); + + pvt = (struct i82875p_pvt *) mci->pvt_info; + pvt->ovrfl_pdev = ovrfl_pdev; + pvt->ovrfl_window = ovrfl_window; + + /* + * The dram row boundary (DRB) reg values are boundary address + * for each DRAM row with a granularity of 32 or 64MB (single/dual + * channel operation). DRB regs are cumulative; therefore DRB7 will + * contain the total memory contained in all eight rows. + */ + for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { + u8 value; + u32 cumul_size; + struct csrow_info *csrow = &mci->csrows[index]; + + value = readb(ovrfl_window + I82875P_DRB + index); + cumul_size = value << (I82875P_DRB_SHIFT - PAGE_SHIFT); + debugf3("MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n", + __func__, index, cumul_size); + if (cumul_size == last_cumul_size) + continue; /* not populated */ + + csrow->first_page = last_cumul_size; + csrow->last_page = cumul_size - 1; + csrow->nr_pages = cumul_size - last_cumul_size; + last_cumul_size = cumul_size; + csrow->grain = 1 << 12; /* I82875P_EAP has 4KiB reolution */ + csrow->mtype = MEM_DDR; + csrow->dtype = DEV_UNKNOWN; + csrow->edac_mode = drc_ddim ? EDAC_SECDED : EDAC_NONE; + } + + /* clear counters */ + pci_write_bits16(mci->pdev, I82875P_ERRSTS, 0x0081, 0x0081); + + if (edac_mc_add_mc(mci)) { + debugf3("MC: " __FILE__ + ": %s(): failed edac_mc_add_mc()\n", __func__); + goto fail; + } + + /* get this far and it's successful */ + debugf3("MC: " __FILE__ ": %s(): success\n", __func__); + return 0; + + fail: + if (mci) + edac_mc_free(mci); + + if (ovrfl_window) + iounmap(ovrfl_window); + + if (ovrfl_pdev) { + pci_release_regions(ovrfl_pdev); + pci_disable_device(ovrfl_pdev); + } + + /* NOTE: the ovrfl proc entry and pci_dev are intentionally left */ + return rc; +} + + +/* returns count (>= 0), or negative on error */ +static int __devinit i82875p_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int rc; + + debugf0("MC: " __FILE__ ": %s()\n", __func__); + + printk(KERN_INFO "i82875p init one\n"); + if(pci_enable_device(pdev) < 0) + return -EIO; + rc = i82875p_probe1(pdev, ent->driver_data); + if (mci_pdev == NULL) + mci_pdev = pci_dev_get(pdev); + return rc; +} + + +static void __devexit i82875p_remove_one(struct pci_dev *pdev) +{ + struct mem_ctl_info *mci; + struct i82875p_pvt *pvt = NULL; + + debugf0(__FILE__ ": %s()\n", __func__); + + if ((mci = edac_mc_find_mci_by_pdev(pdev)) == NULL) + return; + + pvt = (struct i82875p_pvt *) mci->pvt_info; + if (pvt->ovrfl_window) + iounmap(pvt->ovrfl_window); + + if (pvt->ovrfl_pdev) { +#ifdef CORRECT_BIOS + pci_release_regions(pvt->ovrfl_pdev); +#endif /*CORRECT_BIOS */ + pci_disable_device(pvt->ovrfl_pdev); + pci_dev_put(pvt->ovrfl_pdev); + } + + if (edac_mc_del_mc(mci)) + return; + + edac_mc_free(mci); +} + + +static const struct pci_device_id i82875p_pci_tbl[] __devinitdata = { + {PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, + I82875P}, + {0,} /* 0 terminated list. */ +}; + +MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl); + + +static struct pci_driver i82875p_driver = { + .name = BS_MOD_STR, + .probe = i82875p_init_one, + .remove = __devexit_p(i82875p_remove_one), + .id_table = i82875p_pci_tbl, +}; + + +static int __init i82875p_init(void) +{ + int pci_rc; + + debugf3("MC: " __FILE__ ": %s()\n", __func__); + pci_rc = pci_register_driver(&i82875p_driver); + if (pci_rc < 0) + return pci_rc; + if (mci_pdev == NULL) { + i82875p_registered = 0; + mci_pdev = + pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82875_0, NULL); + if (!mci_pdev) { + debugf0("875p pci_get_device fail\n"); + return -ENODEV; + } + pci_rc = i82875p_init_one(mci_pdev, i82875p_pci_tbl); + if (pci_rc < 0) { + debugf0("875p init fail\n"); + pci_dev_put(mci_pdev); + return -ENODEV; + } + } + return 0; +} + + +static void __exit i82875p_exit(void) +{ + debugf3("MC: " __FILE__ ": %s()\n", __func__); + + pci_unregister_driver(&i82875p_driver); + if (!i82875p_registered) { + i82875p_remove_one(mci_pdev); + pci_dev_put(mci_pdev); + } +} + + +module_init(i82875p_init); +module_exit(i82875p_exit); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh"); +MODULE_DESCRIPTION("MC support for Intel 82875 memory hub controllers"); diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c new file mode 100644 index 000000000000..e90892831b90 --- /dev/null +++ b/drivers/edac/r82600_edac.c @@ -0,0 +1,407 @@ +/* + * 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: + * http://www.radisys.com/files/support_downloads/007-01277-0002.82600DataBook.pdf + * references to this document given in [] + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> + +#include <linux/pci.h> +#include <linux/pci_ids.h> + +#include <linux/slab.h> + +#include "edac_mc.h" + +/* 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 Boundry Address + * Registers + * + * 7:0 Address lines 30:24 - upper limit of + * each row [p57] + */ + +struct r82600_error_info { + u32 eapr; +}; + + +static unsigned int disable_hardware_scrub = 0; + + +static void r82600_get_error_info (struct mem_ctl_info *mci, + struct r82600_error_info *info) +{ + pci_read_config_dword(mci->pdev, R82600_EAP, &info->eapr); + + if (info->eapr & BIT(0)) + /* Clear error to allow next error to be reported [p.62] */ + pci_write_bits32(mci->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(mci->pdev, R82600_EAP, + ((u32) BIT(0) & (u32) BIT(1)), + ((u32) BIT(0) & (u32) BIT(1))); +} + + +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_ce( + mci, page, 0, /* not avail */ + syndrome, + edac_mc_find_csrow_by_page(mci, page), + 0, /* channel */ + mci->ctl_name); + } + + if (info->eapr & BIT(1)) { /* UE? */ + error_found = 1; + + if (handle_errors) + /* 82600 doesn't give enough info */ + edac_mc_handle_ue(mci, page, 0, + edac_mc_find_csrow_by_page(mci, page), + mci->ctl_name); + } + + return error_found; +} + +static void r82600_check(struct mem_ctl_info *mci) +{ + struct r82600_error_info info; + + debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__); + r82600_get_error_info(mci, &info); + r82600_process_error_info(mci, &info, 1); +} + +static int r82600_probe1(struct pci_dev *pdev, int dev_idx) +{ + int rc = -ENODEV; + int index; + struct mem_ctl_info *mci = NULL; + u8 dramcr; + u32 ecc_on; + u32 reg_sdram; + u32 eapr; + u32 scrub_disabled; + u32 sdram_refresh_rate; + u32 row_high_limit_last = 0; + u32 eap_init_bits; + + debugf0("MC: " __FILE__ ": %s()\n", __func__); + + + pci_read_config_byte(pdev, R82600_DRAMC, &dramcr); + pci_read_config_dword(pdev, R82600_EAP, &eapr); + + ecc_on = dramcr & BIT(5); + reg_sdram = dramcr & BIT(4); + scrub_disabled = eapr & BIT(31); + sdram_refresh_rate = dramcr & (BIT(0) | BIT(1)); + + debugf2("MC: " __FILE__ ": %s(): sdram refresh rate = %#0x\n", + __func__, sdram_refresh_rate); + + debugf2("MC: " __FILE__ ": %s(): DRAMC register = %#0x\n", __func__, + dramcr); + + mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS); + + if (mci == NULL) { + rc = -ENOMEM; + goto fail; + } + + debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); + + mci->pdev = pdev; + 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_on) { + if (scrub_disabled) + debugf3("MC: " __FILE__ ": %s(): mci = %p - " + "Scrubbing disabled! EAP: %#0x\n", __func__, + mci, eapr); + } else + mci->edac_cap = EDAC_FLAG_NONE; + + mci->mod_name = BS_MOD_STR; + mci->mod_ver = "$Revision: 1.1.2.6 $"; + mci->ctl_name = "R82600"; + mci->edac_check = r82600_check; + mci->ctl_page_to_phys = NULL; + + for (index = 0; index < mci->nr_csrows; index++) { + struct csrow_info *csrow = &mci->csrows[index]; + u8 drbar; /* sDram Row Boundry Address Register */ + u32 row_high_limit; + u32 row_base; + + /* find the DRAM Chip Select Base address and mask */ + pci_read_config_byte(mci->pdev, R82600_DRBA + index, &drbar); + + debugf1("MC%d: " __FILE__ ": %s() Row=%d DRBA = %#0x\n", + mci->mc_idx, __func__, index, drbar); + + row_high_limit = ((u32) drbar << 24); +/* row_high_limit = ((u32)drbar << 24) | 0xffffffUL; */ + + debugf1("MC%d: " __FILE__ ": %s() Row=%d, " + "Boundry Address=%#0x, Last = %#0x \n", + mci->mc_idx, __func__, 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; + csrow->nr_pages = csrow->last_page - csrow->first_page + 1; + /* Error address is top 19 bits - so granularity is * + * 14 bits */ + csrow->grain = 1 << 14; + csrow->mtype = reg_sdram ? MEM_RDDR : MEM_DDR; + /* FIXME - check that this is unknowable with this chipset */ + csrow->dtype = DEV_UNKNOWN; + + /* Mode is global on 82600 */ + csrow->edac_mode = ecc_on ? EDAC_SECDED : EDAC_NONE; + row_high_limit_last = row_high_limit; + } + + /* clear counters */ + /* FIXME should we? */ + + if (edac_mc_add_mc(mci)) { + debugf3("MC: " __FILE__ + ": %s(): failed edac_mc_add_mc()\n", __func__); + goto fail; + } + + /* get this far and it's successful */ + + /* Clear error flags to allow next error to be reported [p.62] */ + /* Test systems seem to always have the UE flag raised on boot */ + + eap_init_bits = BIT(0) & BIT(1); + if (disable_hardware_scrub) { + eap_init_bits |= BIT(31); + debugf3("MC: " __FILE__ ": %s(): Disabling Hardware Scrub " + "(scrub on error)\n", __func__); + } + + pci_write_bits32(mci->pdev, R82600_EAP, eap_init_bits, + eap_init_bits); + + debugf3("MC: " __FILE__ ": %s(): success\n", __func__); + return 0; + +fail: + if (mci) + edac_mc_free(mci); + + return rc; +} + +/* returns count (>= 0), or negative on error */ +static int __devinit r82600_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + debugf0("MC: " __FILE__ ": %s()\n", __func__); + + /* don't need to call pci_device_enable() */ + return r82600_probe1(pdev, ent->driver_data); +} + + +static void __devexit r82600_remove_one(struct pci_dev *pdev) +{ + struct mem_ctl_info *mci; + + debugf0(__FILE__ ": %s()\n", __func__); + + if (((mci = edac_mc_find_mci_by_pdev(pdev)) != NULL) && + !edac_mc_del_mc(mci)) + edac_mc_free(mci); +} + + +static const struct pci_device_id r82600_pci_tbl[] __devinitdata = { + {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 = BS_MOD_STR, + .probe = r82600_init_one, + .remove = __devexit_p(r82600_remove_one), + .id_table = r82600_pci_tbl, +}; + + +static int __init r82600_init(void) +{ + return pci_register_driver(&r82600_driver); +} + + +static void __exit r82600_exit(void) +{ + pci_unregister_driver(&r82600_driver); +} + + +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"); diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c index ca99979c868a..8b3515f394a6 100644 --- a/drivers/md/kcopyd.c +++ b/drivers/md/kcopyd.c @@ -8,6 +8,7 @@ * completion notification. */ +#include <asm/types.h> #include <asm/atomic.h> #include <linux/blkdev.h> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 1421941487c4..626508afe1b1 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -7,6 +7,7 @@ menu "Network device support" config NETDEVICES depends on NET + default y if UML bool "Network device support" ---help--- You can say N here if you don't intend to connect your Linux box to @@ -1914,6 +1915,15 @@ config E1000_NAPI If in doubt, say N. +config E1000_DISABLE_PACKET_SPLIT + bool "Disable Packet Split for PCI express adapters" + depends on E1000 + help + Say Y here if you want to use the legacy receive path for PCI express + hadware. + + If in doubt, say N. + source "drivers/net/ixp2000/Kconfig" config MYRI_SBUS diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index dde631f8f685..6e295fce5c6f 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -335,6 +335,30 @@ static inline void cas_mask_intr(struct cas *cp) cas_disable_irq(cp, i); } +static inline void cas_buffer_init(cas_page_t *cp) +{ + struct page *page = cp->buffer; + atomic_set((atomic_t *)&page->lru.next, 1); +} + +static inline int cas_buffer_count(cas_page_t *cp) +{ + struct page *page = cp->buffer; + return atomic_read((atomic_t *)&page->lru.next); +} + +static inline void cas_buffer_inc(cas_page_t *cp) +{ + struct page *page = cp->buffer; + atomic_inc((atomic_t *)&page->lru.next); +} + +static inline void cas_buffer_dec(cas_page_t *cp) +{ + struct page *page = cp->buffer; + atomic_dec((atomic_t *)&page->lru.next); +} + static void cas_enable_irq(struct cas *cp, const int ring) { if (ring == 0) { /* all but TX_DONE */ @@ -472,6 +496,7 @@ static int cas_page_free(struct cas *cp, cas_page_t *page) { pci_unmap_page(cp->pdev, page->dma_addr, cp->page_size, PCI_DMA_FROMDEVICE); + cas_buffer_dec(page); __free_pages(page->buffer, cp->page_order); kfree(page); return 0; @@ -501,6 +526,7 @@ static cas_page_t *cas_page_alloc(struct cas *cp, const gfp_t flags) page->buffer = alloc_pages(flags, cp->page_order); if (!page->buffer) goto page_err; + cas_buffer_init(page); page->dma_addr = pci_map_page(cp->pdev, page->buffer, 0, cp->page_size, PCI_DMA_FROMDEVICE); return page; @@ -579,7 +605,7 @@ static void cas_spare_recover(struct cas *cp, const gfp_t flags) list_for_each_safe(elem, tmp, &list) { cas_page_t *page = list_entry(elem, cas_page_t, list); - if (page_count(page->buffer) > 1) + if (cas_buffer_count(page) > 1) continue; list_del(elem); @@ -1347,7 +1373,7 @@ static inline cas_page_t *cas_page_spare(struct cas *cp, const int index) cas_page_t *page = cp->rx_pages[1][index]; cas_page_t *new; - if (page_count(page->buffer) == 1) + if (cas_buffer_count(page) == 1) return page; new = cas_page_dequeue(cp); @@ -1367,7 +1393,7 @@ static cas_page_t *cas_page_swap(struct cas *cp, const int ring, cas_page_t **page1 = cp->rx_pages[1]; /* swap if buffer is in use */ - if (page_count(page0[index]->buffer) > 1) { + if (cas_buffer_count(page0[index]) > 1) { cas_page_t *new = cas_page_spare(cp, index); if (new) { page1[index] = page0[index]; @@ -2039,6 +2065,7 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc, skb->len += hlen - swivel; get_page(page->buffer); + cas_buffer_inc(page); frag->page = page->buffer; frag->page_offset = off; frag->size = hlen - swivel; @@ -2063,6 +2090,7 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc, frag++; get_page(page->buffer); + cas_buffer_inc(page); frag->page = page->buffer; frag->page_offset = 0; frag->size = hlen; @@ -2225,7 +2253,7 @@ static int cas_post_rxds_ringN(struct cas *cp, int ring, int num) released = 0; while (entry != last) { /* make a new buffer if it's still in use */ - if (page_count(page[entry]->buffer) > 1) { + if (cas_buffer_count(page[entry]) > 1) { cas_page_t *new = cas_page_dequeue(cp); if (!new) { /* let the timer know that we need to diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index d252297e4db0..5cedc81786e3 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -121,7 +121,7 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - if(hw->media_type == e1000_media_type_copper) { + if (hw->media_type == e1000_media_type_copper) { ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | @@ -133,7 +133,7 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ecmd->advertising = ADVERTISED_TP; - if(hw->autoneg == 1) { + if (hw->autoneg == 1) { ecmd->advertising |= ADVERTISED_Autoneg; /* the e1000 autoneg seems to match ethtool nicely */ @@ -144,7 +144,7 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ecmd->port = PORT_TP; ecmd->phy_address = hw->phy_addr; - if(hw->mac_type == e1000_82543) + if (hw->mac_type == e1000_82543) ecmd->transceiver = XCVR_EXTERNAL; else ecmd->transceiver = XCVR_INTERNAL; @@ -160,13 +160,13 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ecmd->port = PORT_FIBRE; - if(hw->mac_type >= e1000_82545) + if (hw->mac_type >= e1000_82545) ecmd->transceiver = XCVR_INTERNAL; else ecmd->transceiver = XCVR_EXTERNAL; } - if(netif_carrier_ok(adapter->netdev)) { + if (netif_carrier_ok(adapter->netdev)) { e1000_get_speed_and_duplex(hw, &adapter->link_speed, &adapter->link_duplex); @@ -175,7 +175,7 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) /* unfortunatly FULL_DUPLEX != DUPLEX_FULL * and HALF_DUPLEX != DUPLEX_HALF */ - if(adapter->link_duplex == FULL_DUPLEX) + if (adapter->link_duplex == FULL_DUPLEX) ecmd->duplex = DUPLEX_FULL; else ecmd->duplex = DUPLEX_HALF; @@ -205,11 +205,11 @@ e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) if (ecmd->autoneg == AUTONEG_ENABLE) { hw->autoneg = 1; - if(hw->media_type == e1000_media_type_fiber) + if (hw->media_type == e1000_media_type_fiber) hw->autoneg_advertised = ADVERTISED_1000baseT_Full | ADVERTISED_FIBRE | ADVERTISED_Autoneg; - else + else hw->autoneg_advertised = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | @@ -219,12 +219,12 @@ e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ADVERTISED_TP; ecmd->advertising = hw->autoneg_advertised; } else - if(e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) + if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) return -EINVAL; /* reset the link */ - if(netif_running(adapter->netdev)) { + if (netif_running(adapter->netdev)) { e1000_down(adapter); e1000_reset(adapter); e1000_up(adapter); @@ -241,14 +241,14 @@ e1000_get_pauseparam(struct net_device *netdev, struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - pause->autoneg = + pause->autoneg = (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); - - if(hw->fc == e1000_fc_rx_pause) + + if (hw->fc == e1000_fc_rx_pause) pause->rx_pause = 1; - else if(hw->fc == e1000_fc_tx_pause) + else if (hw->fc == e1000_fc_tx_pause) pause->tx_pause = 1; - else if(hw->fc == e1000_fc_full) { + else if (hw->fc == e1000_fc_full) { pause->rx_pause = 1; pause->tx_pause = 1; } @@ -260,31 +260,30 @@ e1000_set_pauseparam(struct net_device *netdev, { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - + adapter->fc_autoneg = pause->autoneg; - if(pause->rx_pause && pause->tx_pause) + if (pause->rx_pause && pause->tx_pause) hw->fc = e1000_fc_full; - else if(pause->rx_pause && !pause->tx_pause) + else if (pause->rx_pause && !pause->tx_pause) hw->fc = e1000_fc_rx_pause; - else if(!pause->rx_pause && pause->tx_pause) + else if (!pause->rx_pause && pause->tx_pause) hw->fc = e1000_fc_tx_pause; - else if(!pause->rx_pause && !pause->tx_pause) + else if (!pause->rx_pause && !pause->tx_pause) hw->fc = e1000_fc_none; hw->original_fc = hw->fc; - if(adapter->fc_autoneg == AUTONEG_ENABLE) { - if(netif_running(adapter->netdev)) { + if (adapter->fc_autoneg == AUTONEG_ENABLE) { + if (netif_running(adapter->netdev)) { e1000_down(adapter); e1000_up(adapter); } else e1000_reset(adapter); - } - else + } else return ((hw->media_type == e1000_media_type_fiber) ? e1000_setup_link(hw) : e1000_force_mac_fc(hw)); - + return 0; } @@ -301,14 +300,14 @@ e1000_set_rx_csum(struct net_device *netdev, uint32_t data) struct e1000_adapter *adapter = netdev_priv(netdev); adapter->rx_csum = data; - if(netif_running(netdev)) { + if (netif_running(netdev)) { e1000_down(adapter); e1000_up(adapter); } else e1000_reset(adapter); return 0; } - + static uint32_t e1000_get_tx_csum(struct net_device *netdev) { @@ -320,7 +319,7 @@ e1000_set_tx_csum(struct net_device *netdev, uint32_t data) { struct e1000_adapter *adapter = netdev_priv(netdev); - if(adapter->hw.mac_type < e1000_82543) { + if (adapter->hw.mac_type < e1000_82543) { if (!data) return -EINVAL; return 0; @@ -339,8 +338,8 @@ static int e1000_set_tso(struct net_device *netdev, uint32_t data) { struct e1000_adapter *adapter = netdev_priv(netdev); - if((adapter->hw.mac_type < e1000_82544) || - (adapter->hw.mac_type == e1000_82547)) + if ((adapter->hw.mac_type < e1000_82544) || + (adapter->hw.mac_type == e1000_82547)) return data ? -EINVAL : 0; if (data) @@ -348,7 +347,7 @@ e1000_set_tso(struct net_device *netdev, uint32_t data) else netdev->features &= ~NETIF_F_TSO; return 0; -} +} #endif /* NETIF_F_TSO */ static uint32_t @@ -365,7 +364,7 @@ e1000_set_msglevel(struct net_device *netdev, uint32_t data) adapter->msg_enable = data; } -static int +static int e1000_get_regs_len(struct net_device *netdev) { #define E1000_REGS_LEN 32 @@ -401,7 +400,7 @@ e1000_get_regs(struct net_device *netdev, regs_buff[11] = E1000_READ_REG(hw, TIDV); regs_buff[12] = adapter->hw.phy_type; /* PHY type (IGP=1, M88=0) */ - if(hw->phy_type == e1000_phy_igp) { + if (hw->phy_type == e1000_phy_igp) { e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, IGP01E1000_PHY_AGC_A); e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_A & @@ -455,7 +454,7 @@ e1000_get_regs(struct net_device *netdev, e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data); regs_buff[24] = (uint32_t)phy_data; /* phy local receiver status */ regs_buff[25] = regs_buff[24]; /* phy remote receiver status */ - if(hw->mac_type >= e1000_82540 && + if (hw->mac_type >= e1000_82540 && hw->media_type == e1000_media_type_copper) { regs_buff[26] = E1000_READ_REG(hw, MANC); } @@ -479,7 +478,7 @@ e1000_get_eeprom(struct net_device *netdev, int ret_val = 0; uint16_t i; - if(eeprom->len == 0) + if (eeprom->len == 0) return -EINVAL; eeprom->magic = hw->vendor_id | (hw->device_id << 16); @@ -489,16 +488,16 @@ e1000_get_eeprom(struct net_device *netdev, eeprom_buff = kmalloc(sizeof(uint16_t) * (last_word - first_word + 1), GFP_KERNEL); - if(!eeprom_buff) + if (!eeprom_buff) return -ENOMEM; - if(hw->eeprom.type == e1000_eeprom_spi) + if (hw->eeprom.type == e1000_eeprom_spi) ret_val = e1000_read_eeprom(hw, first_word, last_word - first_word + 1, eeprom_buff); else { for (i = 0; i < last_word - first_word + 1; i++) - if((ret_val = e1000_read_eeprom(hw, first_word + i, 1, + if ((ret_val = e1000_read_eeprom(hw, first_word + i, 1, &eeprom_buff[i]))) break; } @@ -525,10 +524,10 @@ e1000_set_eeprom(struct net_device *netdev, int max_len, first_word, last_word, ret_val = 0; uint16_t i; - if(eeprom->len == 0) + if (eeprom->len == 0) return -EOPNOTSUPP; - if(eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) + if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) return -EFAULT; max_len = hw->eeprom.word_size * 2; @@ -536,19 +535,19 @@ e1000_set_eeprom(struct net_device *netdev, first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; eeprom_buff = kmalloc(max_len, GFP_KERNEL); - if(!eeprom_buff) + if (!eeprom_buff) return -ENOMEM; ptr = (void *)eeprom_buff; - if(eeprom->offset & 1) { + if (eeprom->offset & 1) { /* need read/modify/write of first changed EEPROM word */ /* only the second byte of the word is being modified */ ret_val = e1000_read_eeprom(hw, first_word, 1, &eeprom_buff[0]); ptr++; } - if(((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) { + if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) { /* need read/modify/write of last changed EEPROM word */ /* only the first byte of the word is being modified */ ret_val = e1000_read_eeprom(hw, last_word, 1, @@ -567,9 +566,9 @@ e1000_set_eeprom(struct net_device *netdev, ret_val = e1000_write_eeprom(hw, first_word, last_word - first_word + 1, eeprom_buff); - /* Update the checksum over the first part of the EEPROM if needed + /* Update the checksum over the first part of the EEPROM if needed * and flush shadow RAM for 82573 conrollers */ - if((ret_val == 0) && ((first_word <= EEPROM_CHECKSUM_REG) || + if ((ret_val == 0) && ((first_word <= EEPROM_CHECKSUM_REG) || (hw->mac_type == e1000_82573))) e1000_update_eeprom_checksum(hw); @@ -633,7 +632,7 @@ e1000_get_ringparam(struct net_device *netdev, ring->rx_jumbo_pending = 0; } -static int +static int e1000_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { @@ -670,25 +669,25 @@ e1000_set_ringparam(struct net_device *netdev, txdr = adapter->tx_ring; rxdr = adapter->rx_ring; - if((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) + if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD); rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD)); - E1000_ROUNDUP(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE); + E1000_ROUNDUP(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE); txdr->count = max(ring->tx_pending,(uint32_t)E1000_MIN_TXD); txdr->count = min(txdr->count,(uint32_t)(mac_type < e1000_82544 ? E1000_MAX_TXD : E1000_MAX_82544_TXD)); - E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); + E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); for (i = 0; i < adapter->num_tx_queues; i++) txdr[i].count = txdr->count; for (i = 0; i < adapter->num_rx_queues; i++) rxdr[i].count = rxdr->count; - if(netif_running(adapter->netdev)) { + if (netif_running(adapter->netdev)) { /* Try to get new resources before deleting old */ if ((err = e1000_setup_all_rx_resources(adapter))) goto err_setup_rx; @@ -708,7 +707,7 @@ e1000_set_ringparam(struct net_device *netdev, kfree(rx_old); adapter->rx_ring = rx_new; adapter->tx_ring = tx_new; - if((err = e1000_up(adapter))) + if ((err = e1000_up(adapter))) return err; } @@ -727,10 +726,10 @@ err_setup_rx: uint32_t pat, value; \ uint32_t test[] = \ {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \ - for(pat = 0; pat < sizeof(test)/sizeof(test[0]); pat++) { \ + for (pat = 0; pat < sizeof(test)/sizeof(test[0]); pat++) { \ E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W)); \ value = E1000_READ_REG(&adapter->hw, R); \ - if(value != (test[pat] & W & M)) { \ + if (value != (test[pat] & W & M)) { \ DPRINTK(DRV, ERR, "pattern test reg %04X failed: got " \ "0x%08X expected 0x%08X\n", \ E1000_##R, value, (test[pat] & W & M)); \ @@ -746,7 +745,7 @@ err_setup_rx: uint32_t value; \ E1000_WRITE_REG(&adapter->hw, R, W & M); \ value = E1000_READ_REG(&adapter->hw, R); \ - if((W & M) != (value & M)) { \ + if ((W & M) != (value & M)) { \ DPRINTK(DRV, ERR, "set/check reg %04X test failed: got 0x%08X "\ "expected 0x%08X\n", E1000_##R, (value & M), (W & M)); \ *data = (adapter->hw.mac_type < e1000_82543) ? \ @@ -782,7 +781,7 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data) value = (E1000_READ_REG(&adapter->hw, STATUS) & toggle); E1000_WRITE_REG(&adapter->hw, STATUS, toggle); after = E1000_READ_REG(&adapter->hw, STATUS) & toggle; - if(value != after) { + if (value != after) { DPRINTK(DRV, ERR, "failed STATUS register test got: " "0x%08X expected: 0x%08X\n", after, value); *data = 1; @@ -810,7 +809,7 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data) REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0x003FFFFB); REG_SET_AND_CHECK(TCTL, 0xFFFFFFFF, 0x00000000); - if(adapter->hw.mac_type >= e1000_82543) { + if (adapter->hw.mac_type >= e1000_82543) { REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0xFFFFFFFF); REG_PATTERN_TEST(RDBAL, 0xFFFFFFF0, 0xFFFFFFFF); @@ -818,7 +817,7 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data) REG_PATTERN_TEST(TDBAL, 0xFFFFFFF0, 0xFFFFFFFF); REG_PATTERN_TEST(TIDV, 0x0000FFFF, 0x0000FFFF); - for(i = 0; i < E1000_RAR_ENTRIES; i++) { + for (i = 0; i < E1000_RAR_ENTRIES; i++) { REG_PATTERN_TEST(RA + ((i << 1) << 2), 0xFFFFFFFF, 0xFFFFFFFF); REG_PATTERN_TEST(RA + (((i << 1) + 1) << 2), 0x8003FFFF, @@ -834,7 +833,7 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data) } - for(i = 0; i < E1000_MC_TBL_SIZE; i++) + for (i = 0; i < E1000_MC_TBL_SIZE; i++) REG_PATTERN_TEST(MTA + (i << 2), 0xFFFFFFFF, 0xFFFFFFFF); *data = 0; @@ -850,8 +849,8 @@ e1000_eeprom_test(struct e1000_adapter *adapter, uint64_t *data) *data = 0; /* Read and add up the contents of the EEPROM */ - for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) { - if((e1000_read_eeprom(&adapter->hw, i, 1, &temp)) < 0) { + for (i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) { + if ((e1000_read_eeprom(&adapter->hw, i, 1, &temp)) < 0) { *data = 1; break; } @@ -859,7 +858,7 @@ e1000_eeprom_test(struct e1000_adapter *adapter, uint64_t *data) } /* If Checksum is not Correct return error else test passed */ - if((checksum != (uint16_t) EEPROM_SUM) && !(*data)) + if ((checksum != (uint16_t) EEPROM_SUM) && !(*data)) *data = 2; return *data; @@ -888,9 +887,9 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) *data = 0; /* Hook up test interrupt handler just for this test */ - if(!request_irq(irq, &e1000_test_intr, 0, netdev->name, netdev)) { + if (!request_irq(irq, &e1000_test_intr, 0, netdev->name, netdev)) { shared_int = FALSE; - } else if(request_irq(irq, &e1000_test_intr, SA_SHIRQ, + } else if (request_irq(irq, &e1000_test_intr, SA_SHIRQ, netdev->name, netdev)){ *data = 1; return -1; @@ -901,12 +900,12 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) msec_delay(10); /* Test each interrupt */ - for(; i < 10; i++) { + for (; i < 10; i++) { /* Interrupt to test */ mask = 1 << i; - if(!shared_int) { + if (!shared_int) { /* Disable the interrupt to be reported in * the cause register and then force the same * interrupt and see if one gets posted. If @@ -917,8 +916,8 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) E1000_WRITE_REG(&adapter->hw, IMC, mask); E1000_WRITE_REG(&adapter->hw, ICS, mask); msec_delay(10); - - if(adapter->test_icr & mask) { + + if (adapter->test_icr & mask) { *data = 3; break; } @@ -935,12 +934,12 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) E1000_WRITE_REG(&adapter->hw, ICS, mask); msec_delay(10); - if(!(adapter->test_icr & mask)) { + if (!(adapter->test_icr & mask)) { *data = 4; break; } - if(!shared_int) { + if (!shared_int) { /* Disable the other interrupts to be reported in * the cause register and then force the other * interrupts and see if any get posted. If @@ -952,7 +951,7 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) E1000_WRITE_REG(&adapter->hw, ICS, ~mask & 0x00007FFF); msec_delay(10); - if(adapter->test_icr) { + if (adapter->test_icr) { *data = 5; break; } @@ -977,24 +976,24 @@ e1000_free_desc_rings(struct e1000_adapter *adapter) struct pci_dev *pdev = adapter->pdev; int i; - if(txdr->desc && txdr->buffer_info) { - for(i = 0; i < txdr->count; i++) { - if(txdr->buffer_info[i].dma) + if (txdr->desc && txdr->buffer_info) { + for (i = 0; i < txdr->count; i++) { + if (txdr->buffer_info[i].dma) pci_unmap_single(pdev, txdr->buffer_info[i].dma, txdr->buffer_info[i].length, PCI_DMA_TODEVICE); - if(txdr->buffer_info[i].skb) + if (txdr->buffer_info[i].skb) dev_kfree_skb(txdr->buffer_info[i].skb); } } - if(rxdr->desc && rxdr->buffer_info) { - for(i = 0; i < rxdr->count; i++) { - if(rxdr->buffer_info[i].dma) + if (rxdr->desc && rxdr->buffer_info) { + for (i = 0; i < rxdr->count; i++) { + if (rxdr->buffer_info[i].dma) pci_unmap_single(pdev, rxdr->buffer_info[i].dma, rxdr->buffer_info[i].length, PCI_DMA_FROMDEVICE); - if(rxdr->buffer_info[i].skb) + if (rxdr->buffer_info[i].skb) dev_kfree_skb(rxdr->buffer_info[i].skb); } } @@ -1027,11 +1026,11 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter) /* Setup Tx descriptor ring and Tx buffers */ - if(!txdr->count) - txdr->count = E1000_DEFAULT_TXD; + if (!txdr->count) + txdr->count = E1000_DEFAULT_TXD; size = txdr->count * sizeof(struct e1000_buffer); - if(!(txdr->buffer_info = kmalloc(size, GFP_KERNEL))) { + if (!(txdr->buffer_info = kmalloc(size, GFP_KERNEL))) { ret_val = 1; goto err_nomem; } @@ -1039,7 +1038,7 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter) txdr->size = txdr->count * sizeof(struct e1000_tx_desc); E1000_ROUNDUP(txdr->size, 4096); - if(!(txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma))) { + if (!(txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma))) { ret_val = 2; goto err_nomem; } @@ -1058,12 +1057,12 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter) E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT | E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT); - for(i = 0; i < txdr->count; i++) { + for (i = 0; i < txdr->count; i++) { struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*txdr, i); struct sk_buff *skb; unsigned int size = 1024; - if(!(skb = alloc_skb(size, GFP_KERNEL))) { + if (!(skb = alloc_skb(size, GFP_KERNEL))) { ret_val = 3; goto err_nomem; } @@ -1083,18 +1082,18 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter) /* Setup Rx descriptor ring and Rx buffers */ - if(!rxdr->count) - rxdr->count = E1000_DEFAULT_RXD; + if (!rxdr->count) + rxdr->count = E1000_DEFAULT_RXD; size = rxdr->count * sizeof(struct e1000_buffer); - if(!(rxdr->buffer_info = kmalloc(size, GFP_KERNEL))) { + if (!(rxdr->buffer_info = kmalloc(size, GFP_KERNEL))) { ret_val = 4; goto err_nomem; } memset(rxdr->buffer_info, 0, size); rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc); - if(!(rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma))) { + if (!(rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma))) { ret_val = 5; goto err_nomem; } @@ -1114,11 +1113,11 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter) (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT); E1000_WRITE_REG(&adapter->hw, RCTL, rctl); - for(i = 0; i < rxdr->count; i++) { + for (i = 0; i < rxdr->count; i++) { struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rxdr, i); struct sk_buff *skb; - if(!(skb = alloc_skb(E1000_RXBUFFER_2048 + NET_IP_ALIGN, + if (!(skb = alloc_skb(E1000_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL))) { ret_val = 6; goto err_nomem; @@ -1227,15 +1226,15 @@ e1000_nonintegrated_phy_loopback(struct e1000_adapter *adapter) /* Check Phy Configuration */ e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg); - if(phy_reg != 0x4100) + if (phy_reg != 0x4100) return 9; e1000_read_phy_reg(&adapter->hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_reg); - if(phy_reg != 0x0070) + if (phy_reg != 0x0070) return 10; e1000_read_phy_reg(&adapter->hw, 29, &phy_reg); - if(phy_reg != 0x001A) + if (phy_reg != 0x001A) return 11; return 0; @@ -1249,7 +1248,7 @@ e1000_integrated_phy_loopback(struct e1000_adapter *adapter) adapter->hw.autoneg = FALSE; - if(adapter->hw.phy_type == e1000_phy_m88) { + if (adapter->hw.phy_type == e1000_phy_m88) { /* Auto-MDI/MDIX Off */ e1000_write_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, 0x0808); @@ -1269,14 +1268,14 @@ e1000_integrated_phy_loopback(struct e1000_adapter *adapter) E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */ E1000_CTRL_FD); /* Force Duplex to FULL */ - if(adapter->hw.media_type == e1000_media_type_copper && + if (adapter->hw.media_type == e1000_media_type_copper && adapter->hw.phy_type == e1000_phy_m88) { ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */ } else { /* Set the ILOS bit on the fiber Nic is half * duplex link is detected. */ stat_reg = E1000_READ_REG(&adapter->hw, STATUS); - if((stat_reg & E1000_STATUS_FD) == 0) + if ((stat_reg & E1000_STATUS_FD) == 0) ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); } @@ -1285,7 +1284,7 @@ e1000_integrated_phy_loopback(struct e1000_adapter *adapter) /* Disable the receiver on the PHY so when a cable is plugged in, the * PHY does not begin to autoneg when a cable is reconnected to the NIC. */ - if(adapter->hw.phy_type == e1000_phy_m88) + if (adapter->hw.phy_type == e1000_phy_m88) e1000_phy_disable_receiver(adapter); udelay(500); @@ -1301,14 +1300,14 @@ e1000_set_phy_loopback(struct e1000_adapter *adapter) switch (adapter->hw.mac_type) { case e1000_82543: - if(adapter->hw.media_type == e1000_media_type_copper) { + if (adapter->hw.media_type == e1000_media_type_copper) { /* Attempt to setup Loopback mode on Non-integrated PHY. * Some PHY registers get corrupted at random, so * attempt this 10 times. */ - while(e1000_nonintegrated_phy_loopback(adapter) && + while (e1000_nonintegrated_phy_loopback(adapter) && count++ < 10); - if(count < 11) + if (count < 11) return 0; } break; @@ -1430,8 +1429,8 @@ static int e1000_check_lbtest_frame(struct sk_buff *skb, unsigned int frame_size) { frame_size &= ~1; - if(*(skb->data + 3) == 0xFF) { - if((*(skb->data + frame_size / 2 + 10) == 0xBE) && + if (*(skb->data + 3) == 0xFF) { + if ((*(skb->data + frame_size / 2 + 10) == 0xBE) && (*(skb->data + frame_size / 2 + 12) == 0xAF)) { return 0; } @@ -1450,53 +1449,53 @@ e1000_run_loopback_test(struct e1000_adapter *adapter) E1000_WRITE_REG(&adapter->hw, RDT, rxdr->count - 1); - /* Calculate the loop count based on the largest descriptor ring + /* Calculate the loop count based on the largest descriptor ring * The idea is to wrap the largest ring a number of times using 64 * send/receive pairs during each loop */ - if(rxdr->count <= txdr->count) + if (rxdr->count <= txdr->count) lc = ((txdr->count / 64) * 2) + 1; else lc = ((rxdr->count / 64) * 2) + 1; k = l = 0; - for(j = 0; j <= lc; j++) { /* loop count loop */ - for(i = 0; i < 64; i++) { /* send the packets */ - e1000_create_lbtest_frame(txdr->buffer_info[i].skb, + for (j = 0; j <= lc; j++) { /* loop count loop */ + for (i = 0; i < 64; i++) { /* send the packets */ + e1000_create_lbtest_frame(txdr->buffer_info[i].skb, 1024); - pci_dma_sync_single_for_device(pdev, + pci_dma_sync_single_for_device(pdev, txdr->buffer_info[k].dma, txdr->buffer_info[k].length, PCI_DMA_TODEVICE); - if(unlikely(++k == txdr->count)) k = 0; + if (unlikely(++k == txdr->count)) k = 0; } E1000_WRITE_REG(&adapter->hw, TDT, k); msec_delay(200); time = jiffies; /* set the start time for the receive */ good_cnt = 0; do { /* receive the sent packets */ - pci_dma_sync_single_for_cpu(pdev, + pci_dma_sync_single_for_cpu(pdev, rxdr->buffer_info[l].dma, rxdr->buffer_info[l].length, PCI_DMA_FROMDEVICE); - + ret_val = e1000_check_lbtest_frame( rxdr->buffer_info[l].skb, 1024); - if(!ret_val) + if (!ret_val) good_cnt++; - if(unlikely(++l == rxdr->count)) l = 0; - /* time + 20 msecs (200 msecs on 2.4) is more than - * enough time to complete the receives, if it's + if (unlikely(++l == rxdr->count)) l = 0; + /* time + 20 msecs (200 msecs on 2.4) is more than + * enough time to complete the receives, if it's * exceeded, break and error off */ } while (good_cnt < 64 && jiffies < (time + 20)); - if(good_cnt != 64) { + if (good_cnt != 64) { ret_val = 13; /* ret_val is the same as mis-compare */ - break; + break; } - if(jiffies >= (time + 2)) { + if (jiffies >= (time + 2)) { ret_val = 14; /* error code for time out error */ break; } @@ -1549,17 +1548,17 @@ e1000_link_test(struct e1000_adapter *adapter, uint64_t *data) *data = 1; } else { e1000_check_for_link(&adapter->hw); - if(adapter->hw.autoneg) /* if auto_neg is set wait for it */ + if (adapter->hw.autoneg) /* if auto_neg is set wait for it */ msec_delay(4000); - if(!(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) { + if (!(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) { *data = 1; } } return *data; } -static int +static int e1000_diag_test_count(struct net_device *netdev) { return E1000_TEST_LEN; @@ -1572,7 +1571,7 @@ e1000_diag_test(struct net_device *netdev, struct e1000_adapter *adapter = netdev_priv(netdev); boolean_t if_running = netif_running(netdev); - if(eth_test->flags == ETH_TEST_FL_OFFLINE) { + if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* Offline tests */ /* save speed, duplex, autoneg settings */ @@ -1582,27 +1581,27 @@ e1000_diag_test(struct net_device *netdev, /* Link test performed before hardware reset so autoneg doesn't * interfere with test result */ - if(e1000_link_test(adapter, &data[4])) + if (e1000_link_test(adapter, &data[4])) eth_test->flags |= ETH_TEST_FL_FAILED; - if(if_running) + if (if_running) e1000_down(adapter); else e1000_reset(adapter); - if(e1000_reg_test(adapter, &data[0])) + if (e1000_reg_test(adapter, &data[0])) eth_test->flags |= ETH_TEST_FL_FAILED; e1000_reset(adapter); - if(e1000_eeprom_test(adapter, &data[1])) + if (e1000_eeprom_test(adapter, &data[1])) eth_test->flags |= ETH_TEST_FL_FAILED; e1000_reset(adapter); - if(e1000_intr_test(adapter, &data[2])) + if (e1000_intr_test(adapter, &data[2])) eth_test->flags |= ETH_TEST_FL_FAILED; e1000_reset(adapter); - if(e1000_loopback_test(adapter, &data[3])) + if (e1000_loopback_test(adapter, &data[3])) eth_test->flags |= ETH_TEST_FL_FAILED; /* restore speed, duplex, autoneg settings */ @@ -1611,11 +1610,11 @@ e1000_diag_test(struct net_device *netdev, adapter->hw.autoneg = autoneg; e1000_reset(adapter); - if(if_running) + if (if_running) e1000_up(adapter); } else { /* Online tests */ - if(e1000_link_test(adapter, &data[4])) + if (e1000_link_test(adapter, &data[4])) eth_test->flags |= ETH_TEST_FL_FAILED; /* Offline tests aren't run; pass by default */ @@ -1633,7 +1632,7 @@ e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - switch(adapter->hw.device_id) { + switch (adapter->hw.device_id) { case E1000_DEV_ID_82542: case E1000_DEV_ID_82543GC_FIBER: case E1000_DEV_ID_82543GC_COPPER: @@ -1649,7 +1648,7 @@ e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) case E1000_DEV_ID_82546GB_FIBER: case E1000_DEV_ID_82571EB_FIBER: /* Wake events only supported on port A for dual fiber */ - if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) { + if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) { wol->supported = 0; wol->wolopts = 0; return; @@ -1661,13 +1660,13 @@ e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) WAKE_BCAST | WAKE_MAGIC; wol->wolopts = 0; - if(adapter->wol & E1000_WUFC_EX) + if (adapter->wol & E1000_WUFC_EX) wol->wolopts |= WAKE_UCAST; - if(adapter->wol & E1000_WUFC_MC) + if (adapter->wol & E1000_WUFC_MC) wol->wolopts |= WAKE_MCAST; - if(adapter->wol & E1000_WUFC_BC) + if (adapter->wol & E1000_WUFC_BC) wol->wolopts |= WAKE_BCAST; - if(adapter->wol & E1000_WUFC_MAG) + if (adapter->wol & E1000_WUFC_MAG) wol->wolopts |= WAKE_MAGIC; return; } @@ -1679,7 +1678,7 @@ e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - switch(adapter->hw.device_id) { + switch (adapter->hw.device_id) { case E1000_DEV_ID_82542: case E1000_DEV_ID_82543GC_FIBER: case E1000_DEV_ID_82543GC_COPPER: @@ -1693,23 +1692,23 @@ e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) case E1000_DEV_ID_82546GB_FIBER: case E1000_DEV_ID_82571EB_FIBER: /* Wake events only supported on port A for dual fiber */ - if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) + if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) return wol->wolopts ? -EOPNOTSUPP : 0; /* Fall Through */ default: - if(wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)) + if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)) return -EOPNOTSUPP; adapter->wol = 0; - if(wol->wolopts & WAKE_UCAST) + if (wol->wolopts & WAKE_UCAST) adapter->wol |= E1000_WUFC_EX; - if(wol->wolopts & WAKE_MCAST) + if (wol->wolopts & WAKE_MCAST) adapter->wol |= E1000_WUFC_MC; - if(wol->wolopts & WAKE_BCAST) + if (wol->wolopts & WAKE_BCAST) adapter->wol |= E1000_WUFC_BC; - if(wol->wolopts & WAKE_MAGIC) + if (wol->wolopts & WAKE_MAGIC) adapter->wol |= E1000_WUFC_MAG; } @@ -1727,7 +1726,7 @@ e1000_led_blink_callback(unsigned long data) { struct e1000_adapter *adapter = (struct e1000_adapter *) data; - if(test_and_change_bit(E1000_LED_ON, &adapter->led_status)) + if (test_and_change_bit(E1000_LED_ON, &adapter->led_status)) e1000_led_off(&adapter->hw); else e1000_led_on(&adapter->hw); @@ -1740,11 +1739,11 @@ e1000_phys_id(struct net_device *netdev, uint32_t data) { struct e1000_adapter *adapter = netdev_priv(netdev); - if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ)) + if (!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ)) data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ); - if(adapter->hw.mac_type < e1000_82571) { - if(!adapter->blink_timer.function) { + if (adapter->hw.mac_type < e1000_82571) { + if (!adapter->blink_timer.function) { init_timer(&adapter->blink_timer); adapter->blink_timer.function = e1000_led_blink_callback; adapter->blink_timer.data = (unsigned long) adapter; @@ -1782,21 +1781,21 @@ static int e1000_nway_reset(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); - if(netif_running(netdev)) { + if (netif_running(netdev)) { e1000_down(adapter); e1000_up(adapter); } return 0; } -static int +static int e1000_get_stats_count(struct net_device *netdev) { return E1000_STATS_LEN; } -static void -e1000_get_ethtool_stats(struct net_device *netdev, +static void +e1000_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, uint64_t *data) { struct e1000_adapter *adapter = netdev_priv(netdev); @@ -1830,7 +1829,7 @@ e1000_get_ethtool_stats(struct net_device *netdev, /* BUG_ON(i != E1000_STATS_LEN); */ } -static void +static void e1000_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data) { #ifdef CONFIG_E1000_MQ @@ -1839,9 +1838,9 @@ e1000_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data) uint8_t *p = data; int i; - switch(stringset) { + switch (stringset) { case ETH_SS_TEST: - memcpy(data, *e1000_gstrings_test, + memcpy(data, *e1000_gstrings_test, E1000_TEST_LEN*ETH_GSTRING_LEN); break; case ETH_SS_STATS: diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 2437d362ff63..beeec0fbbeac 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -1600,10 +1600,10 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw) if(ret_val) return ret_val; - /* Read the MII 1000Base-T Control Register (Address 9). */ - ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg); - if(ret_val) - return ret_val; + /* Read the MII 1000Base-T Control Register (Address 9). */ + ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg); + if(ret_val) + return ret_val; /* Need to parse both autoneg_advertised and fc and set up * the appropriate PHY registers. First we will parse for @@ -3916,7 +3916,7 @@ e1000_read_eeprom(struct e1000_hw *hw, } } - if(eeprom->use_eerd == TRUE) { + if (eeprom->use_eerd == TRUE) { ret_val = e1000_read_eeprom_eerd(hw, offset, words, data); if ((e1000_is_onboard_nvm_eeprom(hw) == TRUE) || (hw->mac_type != e1000_82573)) @@ -4423,7 +4423,7 @@ e1000_commit_shadow_ram(struct e1000_hw *hw) return -E1000_ERR_EEPROM; } - /* If STM opcode located in bits 15:8 of flop, reset firmware */ + /* If STM opcode located in bits 15:8 of flop, reset firmware */ if ((flop & 0xFF00) == E1000_STM_OPCODE) { E1000_WRITE_REG(hw, HICR, E1000_HICR_FW_RESET); } @@ -4431,7 +4431,7 @@ e1000_commit_shadow_ram(struct e1000_hw *hw) /* Perform the flash update */ E1000_WRITE_REG(hw, EECD, eecd | E1000_EECD_FLUPD); - for (i=0; i < attempts; i++) { + for (i=0; i < attempts; i++) { eecd = E1000_READ_REG(hw, EECD); if ((eecd & E1000_EECD_FLUPD) == 0) { break; @@ -4504,6 +4504,7 @@ e1000_read_mac_addr(struct e1000_hw * hw) hw->perm_mac_addr[i] = (uint8_t) (eeprom_data & 0x00FF); hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8); } + switch (hw->mac_type) { default: break; @@ -6840,7 +6841,8 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw) { uint32_t manc = 0; - if(hw->mac_type > e1000_82547_rev_2) + + if (hw->mac_type > e1000_82547_rev_2) manc = E1000_READ_REG(hw, MANC); return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ? E1000_BLK_PHY_RESET : E1000_SUCCESS; diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 0b8f6f2b774b..f1219dd9dbac 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -377,6 +377,7 @@ int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask); void e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask); /* Filters (multicast, vlan, receive) */ +void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad, uint32_t rar_used_count); uint32_t e1000_hash_mc_addr(struct e1000_hw *hw, uint8_t * mc_addr); void e1000_mta_set(struct e1000_hw *hw, uint32_t hash_value); void e1000_rar_set(struct e1000_hw *hw, uint8_t * mc_addr, uint32_t rar_index); @@ -401,7 +402,9 @@ void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); /* Port I/O is only supported on 82544 and newer */ uint32_t e1000_io_read(struct e1000_hw *hw, unsigned long port); +uint32_t e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset); void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value); +void e1000_enable_pciex_master(struct e1000_hw *hw); int32_t e1000_disable_pciex_master(struct e1000_hw *hw); int32_t e1000_get_software_semaphore(struct e1000_hw *hw); void e1000_release_software_semaphore(struct e1000_hw *hw); @@ -899,14 +902,14 @@ struct e1000_ffvt_entry { #define E1000_TXDCTL 0x03828 /* TX Descriptor Control - RW */ #define E1000_TADV 0x0382C /* TX Interrupt Absolute Delay Val - RW */ #define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */ -#define E1000_TARC0 0x03840 /* TX Arbitration Count (0) */ -#define E1000_TDBAL1 0x03900 /* TX Desc Base Address Low (1) - RW */ -#define E1000_TDBAH1 0x03904 /* TX Desc Base Address High (1) - RW */ -#define E1000_TDLEN1 0x03908 /* TX Desc Length (1) - RW */ -#define E1000_TDH1 0x03910 /* TX Desc Head (1) - RW */ -#define E1000_TDT1 0x03918 /* TX Desc Tail (1) - RW */ -#define E1000_TXDCTL1 0x03928 /* TX Descriptor Control (1) - RW */ -#define E1000_TARC1 0x03940 /* TX Arbitration Count (1) */ +#define E1000_TARC0 0x03840 /* TX Arbitration Count (0) */ +#define E1000_TDBAL1 0x03900 /* TX Desc Base Address Low (1) - RW */ +#define E1000_TDBAH1 0x03904 /* TX Desc Base Address High (1) - RW */ +#define E1000_TDLEN1 0x03908 /* TX Desc Length (1) - RW */ +#define E1000_TDH1 0x03910 /* TX Desc Head (1) - RW */ +#define E1000_TDT1 0x03918 /* TX Desc Tail (1) - RW */ +#define E1000_TXDCTL1 0x03928 /* TX Descriptor Control (1) - RW */ +#define E1000_TARC1 0x03940 /* TX Arbitration Count (1) */ #define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */ #define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ #define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ @@ -1761,7 +1764,6 @@ struct e1000_hw { #define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */ #define E1000_TXDCTL_COUNT_DESC 0x00400000 /* Enable the counting of desc. still to be processed. */ - /* Transmit Configuration Word */ #define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */ #define E1000_TXCW_HD 0x00000040 /* TXCW half duplex */ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index d0a5d1656c5f..31e332935e5a 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -29,11 +29,71 @@ #include "e1000.h" /* Change Log - * 6.0.58 4/20/05 - * o Accepted ethtool cleanup patch from Stephen Hemminger - * 6.0.44+ 2/15/05 - * o applied Anton's patch to resolve tx hang in hardware - * o Applied Andrew Mortons patch - e1000 stops working after resume + * 6.3.9 12/16/2005 + * o incorporate fix for recycled skbs from IBM LTC + * 6.3.7 11/18/2005 + * o Honor eeprom setting for enabling/disabling Wake On Lan + * 6.3.5 11/17/2005 + * o Fix memory leak in rx ring handling for PCI Express adapters + * 6.3.4 11/8/05 + * o Patch from Jesper Juhl to remove redundant NULL checks for kfree + * 6.3.2 9/20/05 + * o Render logic that sets/resets DRV_LOAD as inline functions to + * avoid code replication. If f/w is AMT then set DRV_LOAD only when + * network interface is open. + * o Handle DRV_LOAD set/reset in cases where AMT uses VLANs. + * o Adjust PBA partioning for Jumbo frames using MTU size and not + * rx_buffer_len + * 6.3.1 9/19/05 + * o Use adapter->tx_timeout_factor in Tx Hung Detect logic + (e1000_clean_tx_irq) + * o Support for 8086:10B5 device (Quad Port) + * 6.2.14 9/15/05 + * o In AMT enabled configurations, set/reset DRV_LOAD bit on interface + * open/close + * 6.2.13 9/14/05 + * o Invoke e1000_check_mng_mode only for 8257x controllers since it + * accesses the FWSM that is not supported in other controllers + * 6.2.12 9/9/05 + * o Add support for device id E1000_DEV_ID_82546GB_QUAD_COPPER + * o set RCTL:SECRC only for controllers newer than 82543. + * o When the n/w interface comes down reset DRV_LOAD bit to notify f/w. + * This code was moved from e1000_remove to e1000_close + * 6.2.10 9/6/05 + * o Fix error in updating RDT in el1000_alloc_rx_buffers[_ps] -- one off. + * o Enable fc by default on 82573 controllers (do not read eeprom) + * o Fix rx_errors statistic not to include missed_packet_count + * o Fix rx_dropped statistic not to include missed_packet_count + (Padraig Brady) + * 6.2.9 8/30/05 + * o Remove call to update statistics from the controller ib e1000_get_stats + * 6.2.8 8/30/05 + * o Improved algorithm for rx buffer allocation/rdt update + * o Flow control watermarks relative to rx PBA size + * o Simplified 'Tx Hung' detect logic + * 6.2.7 8/17/05 + * o Report rx buffer allocation failures and tx timeout counts in stats + * 6.2.6 8/16/05 + * o Implement workaround for controller erratum -- linear non-tso packet + * following a TSO gets written back prematurely + * 6.2.5 8/15/05 + * o Set netdev->tx_queue_len based on link speed/duplex settings. + * o Fix net_stats.rx_fifo_errors <p@draigBrady.com> + * o Do not power off PHY if SoL/IDER session is active + * 6.2.4 8/10/05 + * o Fix loopback test setup/cleanup for 82571/3 controllers + * o Fix parsing of outgoing packets (e1000_transfer_dhcp_info) to treat + * all packets as raw + * o Prevent operations that will cause the PHY to be reset if SoL/IDER + * sessions are active and log a message + * 6.2.2 7/21/05 + * o used fixed size descriptors for all MTU sizes, reduces memory load + * 6.1.2 4/13/05 + * o Fixed ethtool diagnostics + * o Enabled flow control to take default eeprom settings + * o Added stats_lock around e1000_read_phy_reg commands to avoid concurrent + * calls, one from mii_ioctl and other from within update_stats while + * processing MIIREG ioctl. */ char e1000_driver_name[] = "e1000"; @@ -295,7 +355,7 @@ e1000_irq_disable(struct e1000_adapter *adapter) static inline void e1000_irq_enable(struct e1000_adapter *adapter) { - if(likely(atomic_dec_and_test(&adapter->irq_sem))) { + if (likely(atomic_dec_and_test(&adapter->irq_sem))) { E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK); E1000_WRITE_FLUSH(&adapter->hw); } @@ -307,17 +367,17 @@ e1000_update_mng_vlan(struct e1000_adapter *adapter) struct net_device *netdev = adapter->netdev; uint16_t vid = adapter->hw.mng_cookie.vlan_id; uint16_t old_vid = adapter->mng_vlan_id; - if(adapter->vlgrp) { - if(!adapter->vlgrp->vlan_devices[vid]) { - if(adapter->hw.mng_cookie.status & + if (adapter->vlgrp) { + if (!adapter->vlgrp->vlan_devices[vid]) { + if (adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) { e1000_vlan_rx_add_vid(netdev, vid); adapter->mng_vlan_id = vid; } else adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; - - if((old_vid != (uint16_t)E1000_MNG_VLAN_NONE) && - (vid != old_vid) && + + if ((old_vid != (uint16_t)E1000_MNG_VLAN_NONE) && + (vid != old_vid) && !adapter->vlgrp->vlan_devices[old_vid]) e1000_vlan_rx_kill_vid(netdev, old_vid); } @@ -401,10 +461,10 @@ e1000_up(struct e1000_adapter *adapter) /* hardware has been reset, we need to reload some things */ /* Reset the PHY if it was previously powered down */ - if(adapter->hw.media_type == e1000_media_type_copper) { + if (adapter->hw.media_type == e1000_media_type_copper) { uint16_t mii_reg; e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg); - if(mii_reg & MII_CR_POWER_DOWN) + if (mii_reg & MII_CR_POWER_DOWN) e1000_phy_reset(&adapter->hw); } @@ -425,16 +485,16 @@ e1000_up(struct e1000_adapter *adapter) } #ifdef CONFIG_PCI_MSI - if(adapter->hw.mac_type > e1000_82547_rev_2) { + if (adapter->hw.mac_type > e1000_82547_rev_2) { adapter->have_msi = TRUE; - if((err = pci_enable_msi(adapter->pdev))) { + if ((err = pci_enable_msi(adapter->pdev))) { DPRINTK(PROBE, ERR, "Unable to allocate MSI interrupt Error: %d\n", err); adapter->have_msi = FALSE; } } #endif - if((err = request_irq(adapter->pdev->irq, &e1000_intr, + if ((err = request_irq(adapter->pdev->irq, &e1000_intr, SA_SHIRQ | SA_SAMPLE_RANDOM, netdev->name, netdev))) { DPRINTK(PROBE, ERR, @@ -471,7 +531,7 @@ e1000_down(struct e1000_adapter *adapter) #endif free_irq(adapter->pdev->irq, netdev); #ifdef CONFIG_PCI_MSI - if(adapter->hw.mac_type > e1000_82547_rev_2 && + if (adapter->hw.mac_type > e1000_82547_rev_2 && adapter->have_msi == TRUE) pci_disable_msi(adapter->pdev); #endif @@ -537,12 +597,12 @@ e1000_reset(struct e1000_adapter *adapter) break; } - if((adapter->hw.mac_type != e1000_82573) && + if ((adapter->hw.mac_type != e1000_82573) && (adapter->netdev->mtu > E1000_RXBUFFER_8192)) pba -= 8; /* allocate more FIFO for Tx */ - if(adapter->hw.mac_type == e1000_82547) { + if (adapter->hw.mac_type == e1000_82547) { adapter->tx_fifo_head = 0; adapter->tx_head_addr = pba << E1000_TX_HEAD_ADDR_SHIFT; adapter->tx_fifo_size = @@ -565,9 +625,9 @@ e1000_reset(struct e1000_adapter *adapter) /* Allow time for pending master requests to run */ e1000_reset_hw(&adapter->hw); - if(adapter->hw.mac_type >= e1000_82544) + if (adapter->hw.mac_type >= e1000_82544) E1000_WRITE_REG(&adapter->hw, WUC, 0); - if(e1000_init_hw(&adapter->hw)) + if (e1000_init_hw(&adapter->hw)) DPRINTK(PROBE, ERR, "Hardware Error\n"); e1000_update_mng_vlan(adapter); /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */ @@ -606,26 +666,26 @@ e1000_probe(struct pci_dev *pdev, int i, err, pci_using_dac; uint16_t eeprom_data; uint16_t eeprom_apme_mask = E1000_EEPROM_APME; - if((err = pci_enable_device(pdev))) + if ((err = pci_enable_device(pdev))) return err; - if(!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) { + if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) { pci_using_dac = 1; } else { - if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) { + if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) { E1000_ERR("No usable DMA configuration, aborting\n"); return err; } pci_using_dac = 0; } - if((err = pci_request_regions(pdev, e1000_driver_name))) + if ((err = pci_request_regions(pdev, e1000_driver_name))) return err; pci_set_master(pdev); netdev = alloc_etherdev(sizeof(struct e1000_adapter)); - if(!netdev) { + if (!netdev) { err = -ENOMEM; goto err_alloc_etherdev; } @@ -644,15 +704,15 @@ e1000_probe(struct pci_dev *pdev, mmio_len = pci_resource_len(pdev, BAR_0); adapter->hw.hw_addr = ioremap(mmio_start, mmio_len); - if(!adapter->hw.hw_addr) { + if (!adapter->hw.hw_addr) { err = -EIO; goto err_ioremap; } - for(i = BAR_1; i <= BAR_5; i++) { - if(pci_resource_len(pdev, i) == 0) + for (i = BAR_1; i <= BAR_5; i++) { + if (pci_resource_len(pdev, i) == 0) continue; - if(pci_resource_flags(pdev, i) & IORESOURCE_IO) { + if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { adapter->hw.io_base = pci_resource_start(pdev, i); break; } @@ -689,13 +749,13 @@ e1000_probe(struct pci_dev *pdev, /* setup the private structure */ - if((err = e1000_sw_init(adapter))) + if ((err = e1000_sw_init(adapter))) goto err_sw_init; - if((err = e1000_check_phy_reset_block(&adapter->hw))) + if ((err = e1000_check_phy_reset_block(&adapter->hw))) DPRINTK(PROBE, INFO, "PHY reset is blocked due to SOL/IDER session.\n"); - if(adapter->hw.mac_type >= e1000_82543) { + if (adapter->hw.mac_type >= e1000_82543) { netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_TX | @@ -704,16 +764,16 @@ e1000_probe(struct pci_dev *pdev, } #ifdef NETIF_F_TSO - if((adapter->hw.mac_type >= e1000_82544) && + if ((adapter->hw.mac_type >= e1000_82544) && (adapter->hw.mac_type != e1000_82547)) netdev->features |= NETIF_F_TSO; #ifdef NETIF_F_TSO_IPV6 - if(adapter->hw.mac_type > e1000_82547_rev_2) + if (adapter->hw.mac_type > e1000_82547_rev_2) netdev->features |= NETIF_F_TSO_IPV6; #endif #endif - if(pci_using_dac) + if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; /* hard_start_xmit is safe against parallel locking */ @@ -721,14 +781,14 @@ e1000_probe(struct pci_dev *pdev, adapter->en_mng_pt = e1000_enable_mng_pass_thru(&adapter->hw); - /* before reading the EEPROM, reset the controller to + /* before reading the EEPROM, reset the controller to * put the device in a known good starting state */ - + e1000_reset_hw(&adapter->hw); /* make sure the EEPROM is good */ - if(e1000_validate_eeprom_checksum(&adapter->hw) < 0) { + if (e1000_validate_eeprom_checksum(&adapter->hw) < 0) { DPRINTK(PROBE, ERR, "The EEPROM Checksum Is Not Valid\n"); err = -EIO; goto err_eeprom; @@ -736,12 +796,12 @@ e1000_probe(struct pci_dev *pdev, /* copy the MAC address out of the EEPROM */ - if(e1000_read_mac_addr(&adapter->hw)) + if (e1000_read_mac_addr(&adapter->hw)) DPRINTK(PROBE, ERR, "EEPROM Read Error\n"); memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len); - if(!is_valid_ether_addr(netdev->perm_addr)) { + if (!is_valid_ether_addr(netdev->perm_addr)) { DPRINTK(PROBE, ERR, "Invalid MAC Address\n"); err = -EIO; goto err_eeprom; @@ -781,7 +841,7 @@ e1000_probe(struct pci_dev *pdev, * enable the ACPI Magic Packet filter */ - switch(adapter->hw.mac_type) { + switch (adapter->hw.mac_type) { case e1000_82542_rev2_0: case e1000_82542_rev2_1: case e1000_82543: @@ -794,7 +854,7 @@ e1000_probe(struct pci_dev *pdev, case e1000_82546: case e1000_82546_rev_3: case e1000_82571: - if(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_FUNC_1){ + if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_FUNC_1){ e1000_read_eeprom(&adapter->hw, EEPROM_INIT_CONTROL3_PORT_B, 1, &eeprom_data); break; @@ -805,7 +865,7 @@ e1000_probe(struct pci_dev *pdev, EEPROM_INIT_CONTROL3_PORT_A, 1, &eeprom_data); break; } - if(eeprom_data & eeprom_apme_mask) + if (eeprom_data & eeprom_apme_mask) adapter->wol |= E1000_WUFC_MAG; /* print bus type/speed/width info */ @@ -840,7 +900,7 @@ e1000_probe(struct pci_dev *pdev, e1000_get_hw_control(adapter); strcpy(netdev->name, "eth%d"); - if((err = register_netdev(netdev))) + if ((err = register_netdev(netdev))) goto err_register; DPRINTK(PROBE, INFO, "Intel(R) PRO/1000 Network Connection\n"); @@ -881,10 +941,10 @@ e1000_remove(struct pci_dev *pdev) flush_scheduled_work(); - if(adapter->hw.mac_type >= e1000_82540 && + if (adapter->hw.mac_type >= e1000_82540 && adapter->hw.media_type == e1000_media_type_copper) { manc = E1000_READ_REG(&adapter->hw, MANC); - if(manc & E1000_MANC_SMBUS_EN) { + if (manc & E1000_MANC_SMBUS_EN) { manc |= E1000_MANC_ARP_EN; E1000_WRITE_REG(&adapter->hw, MANC, manc); } @@ -900,7 +960,7 @@ e1000_remove(struct pci_dev *pdev) __dev_put(&adapter->polling_netdev[i]); #endif - if(!e1000_check_phy_reset_block(&adapter->hw)) + if (!e1000_check_phy_reset_block(&adapter->hw)) e1000_phy_hw_reset(&adapter->hw); kfree(adapter->tx_ring); @@ -959,19 +1019,19 @@ e1000_sw_init(struct e1000_adapter *adapter) /* identify the MAC */ - if(e1000_set_mac_type(hw)) { + if (e1000_set_mac_type(hw)) { DPRINTK(PROBE, ERR, "Unknown MAC Type\n"); return -EIO; } /* initialize eeprom parameters */ - if(e1000_init_eeprom_params(hw)) { + if (e1000_init_eeprom_params(hw)) { E1000_ERR("EEPROM initialization failed\n"); return -EIO; } - switch(hw->mac_type) { + switch (hw->mac_type) { default: break; case e1000_82541: @@ -990,7 +1050,7 @@ e1000_sw_init(struct e1000_adapter *adapter) /* Copper options */ - if(hw->media_type == e1000_media_type_copper) { + if (hw->media_type == e1000_media_type_copper) { hw->mdix = AUTO_ALL_MODES; hw->disable_polarity_correction = FALSE; hw->master_slave = E1000_MASTER_SLAVE; @@ -1166,10 +1226,10 @@ e1000_open(struct net_device *netdev) if ((err = e1000_setup_all_rx_resources(adapter))) goto err_setup_rx; - if((err = e1000_up(adapter))) + if ((err = e1000_up(adapter))) goto err_up; adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; - if((adapter->hw.mng_cookie.status & + if ((adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) { e1000_update_mng_vlan(adapter); } @@ -1214,7 +1274,7 @@ e1000_close(struct net_device *netdev) e1000_free_all_tx_resources(adapter); e1000_free_all_rx_resources(adapter); - if((adapter->hw.mng_cookie.status & + if ((adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) { e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); } @@ -1269,7 +1329,7 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter, size = sizeof(struct e1000_buffer) * txdr->count; txdr->buffer_info = vmalloc_node(size, pcibus_to_node(pdev->bus)); - if(!txdr->buffer_info) { + if (!txdr->buffer_info) { DPRINTK(PROBE, ERR, "Unable to allocate memory for the transmit descriptor ring\n"); return -ENOMEM; @@ -1282,7 +1342,7 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter, E1000_ROUNDUP(txdr->size, 4096); txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); - if(!txdr->desc) { + if (!txdr->desc) { setup_tx_desc_die: vfree(txdr->buffer_info); DPRINTK(PROBE, ERR, @@ -1298,8 +1358,8 @@ setup_tx_desc_die: "at %p\n", txdr->size, txdr->desc); /* Try again, without freeing the previous */ txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); - if(!txdr->desc) { /* Failed allocation, critical failure */ + if (!txdr->desc) { pci_free_consistent(pdev, txdr->size, olddesc, olddma); goto setup_tx_desc_die; } @@ -1499,7 +1559,7 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter, size = sizeof(struct e1000_ps_page) * rxdr->count; rxdr->ps_page = kmalloc(size, GFP_KERNEL); - if(!rxdr->ps_page) { + if (!rxdr->ps_page) { vfree(rxdr->buffer_info); DPRINTK(PROBE, ERR, "Unable to allocate memory for the receive descriptor ring\n"); @@ -1509,7 +1569,7 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter, size = sizeof(struct e1000_ps_page_dma) * rxdr->count; rxdr->ps_page_dma = kmalloc(size, GFP_KERNEL); - if(!rxdr->ps_page_dma) { + if (!rxdr->ps_page_dma) { vfree(rxdr->buffer_info); kfree(rxdr->ps_page); DPRINTK(PROBE, ERR, @@ -1518,7 +1578,7 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter, } memset(rxdr->ps_page_dma, 0, size); - if(adapter->hw.mac_type <= e1000_82547_rev_2) + if (adapter->hw.mac_type <= e1000_82547_rev_2) desc_len = sizeof(struct e1000_rx_desc); else desc_len = sizeof(union e1000_rx_desc_packet_split); @@ -1621,7 +1681,7 @@ e1000_setup_rctl(struct e1000_adapter *adapter) { uint32_t rctl, rfctl; uint32_t psrctl = 0; -#ifdef CONFIG_E1000_PACKET_SPLIT +#ifndef CONFIG_E1000_DISABLE_PACKET_SPLIT uint32_t pages = 0; #endif @@ -1647,32 +1707,17 @@ e1000_setup_rctl(struct e1000_adapter *adapter) rctl |= E1000_RCTL_LPE; /* Setup buffer sizes */ - if(adapter->hw.mac_type >= e1000_82571) { + if (adapter->hw.mac_type >= e1000_82571) { /* We can now specify buffers in 1K increments. * BSIZE and BSEX are ignored in this case. */ rctl |= adapter->rx_buffer_len << 0x11; } else { rctl &= ~E1000_RCTL_SZ_4096; - rctl |= E1000_RCTL_BSEX; - switch (adapter->rx_buffer_len) { - case E1000_RXBUFFER_2048: - default: - rctl |= E1000_RCTL_SZ_2048; - rctl &= ~E1000_RCTL_BSEX; - break; - case E1000_RXBUFFER_4096: - rctl |= E1000_RCTL_SZ_4096; - break; - case E1000_RXBUFFER_8192: - rctl |= E1000_RCTL_SZ_8192; - break; - case E1000_RXBUFFER_16384: - rctl |= E1000_RCTL_SZ_16384; - break; - } + rctl &= ~E1000_RCTL_BSEX; + rctl |= E1000_RCTL_SZ_2048; } -#ifdef CONFIG_E1000_PACKET_SPLIT +#ifndef CONFIG_E1000_DISABLE_PACKET_SPLIT /* 82571 and greater support packet-split where the protocol * header is placed in skb->data and the packet data is * placed in pages hanging off of skb_shinfo(skb)->nr_frags. @@ -1696,7 +1741,7 @@ e1000_setup_rctl(struct e1000_adapter *adapter) E1000_WRITE_REG(&adapter->hw, RFCTL, rfctl); rctl |= E1000_RCTL_DTYP_PS | E1000_RCTL_SECRC; - + psrctl |= adapter->rx_ps_bsize0 >> E1000_PSRCTL_BSIZE0_SHIFT; @@ -1758,7 +1803,7 @@ e1000_configure_rx(struct e1000_adapter *adapter) if (hw->mac_type >= e1000_82540) { E1000_WRITE_REG(hw, RADV, adapter->rx_abs_int_delay); - if(adapter->itr > 1) + if (adapter->itr > 1) E1000_WRITE_REG(hw, ITR, 1000000000 / (adapter->itr * 256)); } @@ -1847,13 +1892,13 @@ e1000_configure_rx(struct e1000_adapter *adapter) /* Enable 82543 Receive Checksum Offload for TCP and UDP */ if (hw->mac_type >= e1000_82543) { rxcsum = E1000_READ_REG(hw, RXCSUM); - if(adapter->rx_csum == TRUE) { + if (adapter->rx_csum == TRUE) { rxcsum |= E1000_RXCSUM_TUOFL; /* Enable 82571 IPv4 payload checksum for UDP fragments * Must be used in conjunction with packet-split. */ - if ((hw->mac_type >= e1000_82571) && - (adapter->rx_ps_pages)) { + if ((hw->mac_type >= e1000_82571) && + (adapter->rx_ps_pages)) { rxcsum |= E1000_RXCSUM_IPPCSE; } } else { @@ -1915,7 +1960,7 @@ static inline void e1000_unmap_and_free_tx_resource(struct e1000_adapter *adapter, struct e1000_buffer *buffer_info) { - if(buffer_info->dma) { + if (buffer_info->dma) { pci_unmap_page(adapter->pdev, buffer_info->dma, buffer_info->length, @@ -1942,7 +1987,7 @@ e1000_clean_tx_ring(struct e1000_adapter *adapter, /* Free all the Tx ring sk_buffs */ - for(i = 0; i < tx_ring->count; i++) { + for (i = 0; i < tx_ring->count; i++) { buffer_info = &tx_ring->buffer_info[i]; e1000_unmap_and_free_tx_resource(adapter, buffer_info); } @@ -2038,10 +2083,9 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter, unsigned int i, j; /* Free all the Rx ring sk_buffs */ - - for(i = 0; i < rx_ring->count; i++) { + for (i = 0; i < rx_ring->count; i++) { buffer_info = &rx_ring->buffer_info[i]; - if(buffer_info->skb) { + if (buffer_info->skb) { pci_unmap_single(pdev, buffer_info->dma, buffer_info->length, @@ -2122,7 +2166,7 @@ e1000_enter_82542_rst(struct e1000_adapter *adapter) E1000_WRITE_FLUSH(&adapter->hw); mdelay(5); - if(netif_running(netdev)) + if (netif_running(netdev)) e1000_clean_all_rx_rings(adapter); } @@ -2138,13 +2182,13 @@ e1000_leave_82542_rst(struct e1000_adapter *adapter) E1000_WRITE_FLUSH(&adapter->hw); mdelay(5); - if(adapter->hw.pci_cmd_word & PCI_COMMAND_INVALIDATE) + if (adapter->hw.pci_cmd_word & PCI_COMMAND_INVALIDATE) e1000_pci_set_mwi(&adapter->hw); - if(netif_running(netdev)) { - e1000_configure_rx(adapter); + if (netif_running(netdev)) { /* No need to loop, because 82542 supports only 1 queue */ struct e1000_rx_ring *ring = &adapter->rx_ring[0]; + e1000_configure_rx(adapter); adapter->alloc_rx_buf(adapter, ring, E1000_DESC_UNUSED(ring)); } } @@ -2163,12 +2207,12 @@ e1000_set_mac(struct net_device *netdev, void *p) struct e1000_adapter *adapter = netdev_priv(netdev); struct sockaddr *addr = p; - if(!is_valid_ether_addr(addr->sa_data)) + if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; /* 82542 2.0 needs to be in reset to write receive address registers */ - if(adapter->hw.mac_type == e1000_82542_rev2_0) + if (adapter->hw.mac_type == e1000_82542_rev2_0) e1000_enter_82542_rst(adapter); memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); @@ -2182,17 +2226,17 @@ e1000_set_mac(struct net_device *netdev, void *p) /* activate the work around */ adapter->hw.laa_is_present = 1; - /* Hold a copy of the LAA in RAR[14] This is done so that - * between the time RAR[0] gets clobbered and the time it - * gets fixed (in e1000_watchdog), the actual LAA is in one + /* Hold a copy of the LAA in RAR[14] This is done so that + * between the time RAR[0] gets clobbered and the time it + * gets fixed (in e1000_watchdog), the actual LAA is in one * of the RARs and no incoming packets directed to this port - * are dropped. Eventaully the LAA will be in RAR[0] and + * are dropped. Eventaully the LAA will be in RAR[0] and * RAR[14] */ - e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, + e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, E1000_RAR_ENTRIES - 1); } - if(adapter->hw.mac_type == e1000_82542_rev2_0) + if (adapter->hw.mac_type == e1000_82542_rev2_0) e1000_leave_82542_rst(adapter); return 0; @@ -2226,9 +2270,9 @@ e1000_set_multi(struct net_device *netdev) rctl = E1000_READ_REG(hw, RCTL); - if(netdev->flags & IFF_PROMISC) { + if (netdev->flags & IFF_PROMISC) { rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); - } else if(netdev->flags & IFF_ALLMULTI) { + } else if (netdev->flags & IFF_ALLMULTI) { rctl |= E1000_RCTL_MPE; rctl &= ~E1000_RCTL_UPE; } else { @@ -2239,7 +2283,7 @@ e1000_set_multi(struct net_device *netdev) /* 82542 2.0 needs to be in reset to write receive address registers */ - if(hw->mac_type == e1000_82542_rev2_0) + if (hw->mac_type == e1000_82542_rev2_0) e1000_enter_82542_rst(adapter); /* load the first 14 multicast address into the exact filters 1-14 @@ -2249,7 +2293,7 @@ e1000_set_multi(struct net_device *netdev) */ mc_ptr = netdev->mc_list; - for(i = 1; i < rar_entries; i++) { + for (i = 1; i < rar_entries; i++) { if (mc_ptr) { e1000_rar_set(hw, mc_ptr->dmi_addr, i); mc_ptr = mc_ptr->next; @@ -2261,17 +2305,17 @@ e1000_set_multi(struct net_device *netdev) /* clear the old settings from the multicast hash table */ - for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) + for (i = 0; i < E1000_NUM_MTA_REGISTERS; i++) E1000_WRITE_REG_ARRAY(hw, MTA, i, 0); /* load any remaining addresses into the hash table */ - for(; mc_ptr; mc_ptr = mc_ptr->next) { + for (; mc_ptr; mc_ptr = mc_ptr->next) { hash_value = e1000_hash_mc_addr(hw, mc_ptr->dmi_addr); e1000_mta_set(hw, hash_value); } - if(hw->mac_type == e1000_82542_rev2_0) + if (hw->mac_type == e1000_82542_rev2_0) e1000_leave_82542_rst(adapter); } @@ -2297,8 +2341,8 @@ e1000_82547_tx_fifo_stall(unsigned long data) struct net_device *netdev = adapter->netdev; uint32_t tctl; - if(atomic_read(&adapter->tx_fifo_stall)) { - if((E1000_READ_REG(&adapter->hw, TDT) == + if (atomic_read(&adapter->tx_fifo_stall)) { + if ((E1000_READ_REG(&adapter->hw, TDT) == E1000_READ_REG(&adapter->hw, TDH)) && (E1000_READ_REG(&adapter->hw, TDFT) == E1000_READ_REG(&adapter->hw, TDFH)) && @@ -2350,18 +2394,18 @@ e1000_watchdog_task(struct e1000_adapter *adapter) e1000_check_for_link(&adapter->hw); if (adapter->hw.mac_type == e1000_82573) { e1000_enable_tx_pkt_filtering(&adapter->hw); - if(adapter->mng_vlan_id != adapter->hw.mng_cookie.vlan_id) + if (adapter->mng_vlan_id != adapter->hw.mng_cookie.vlan_id) e1000_update_mng_vlan(adapter); - } + } - if((adapter->hw.media_type == e1000_media_type_internal_serdes) && + if ((adapter->hw.media_type == e1000_media_type_internal_serdes) && !(E1000_READ_REG(&adapter->hw, TXCW) & E1000_TXCW_ANE)) link = !adapter->hw.serdes_link_down; else link = E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU; - if(link) { - if(!netif_carrier_ok(netdev)) { + if (link) { + if (!netif_carrier_ok(netdev)) { e1000_get_speed_and_duplex(&adapter->hw, &adapter->link_speed, &adapter->link_duplex); @@ -2392,7 +2436,7 @@ e1000_watchdog_task(struct e1000_adapter *adapter) adapter->smartspeed = 0; } } else { - if(netif_carrier_ok(netdev)) { + if (netif_carrier_ok(netdev)) { adapter->link_speed = 0; adapter->link_duplex = 0; DPRINTK(LINK, INFO, "NIC Link is Down\n"); @@ -2432,12 +2476,12 @@ e1000_watchdog_task(struct e1000_adapter *adapter) } /* Dynamic mode for Interrupt Throttle Rate (ITR) */ - if(adapter->hw.mac_type >= e1000_82540 && adapter->itr == 1) { + if (adapter->hw.mac_type >= e1000_82540 && adapter->itr == 1) { /* Symmetric Tx/Rx gets a reduced ITR=2000; Total * asymmetrical Tx or Rx gets ITR=8000; everyone * else is between 2000-8000. */ uint32_t goc = (adapter->gotcl + adapter->gorcl) / 10000; - uint32_t dif = (adapter->gotcl > adapter->gorcl ? + uint32_t dif = (adapter->gotcl > adapter->gorcl ? adapter->gotcl - adapter->gorcl : adapter->gorcl - adapter->gotcl) / 10000; uint32_t itr = goc > 0 ? (dif * 6000 / goc + 2000) : 8000; @@ -2450,7 +2494,7 @@ e1000_watchdog_task(struct e1000_adapter *adapter) /* Force detection of hung controller every watchdog period */ adapter->detect_tx_hung = TRUE; - /* With 82571 controllers, LAA may be overwritten due to controller + /* With 82571 controllers, LAA may be overwritten due to controller * reset from the other port. Set the appropriate LAA in RAR[0] */ if (adapter->hw.mac_type == e1000_82571 && adapter->hw.laa_is_present) e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0); @@ -2479,7 +2523,7 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, uint8_t ipcss, ipcso, tucss, tucso, hdr_len; int err; - if(skb_shinfo(skb)->tso_size) { + if (skb_shinfo(skb)->tso_size) { if (skb_header_cloned(skb)) { err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); if (err) @@ -2488,7 +2532,7 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); mss = skb_shinfo(skb)->tso_size; - if(skb->protocol == ntohs(ETH_P_IP)) { + if (skb->protocol == ntohs(ETH_P_IP)) { skb->nh.iph->tot_len = 0; skb->nh.iph->check = 0; skb->h.th->check = @@ -2500,7 +2544,7 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, cmd_length = E1000_TXD_CMD_IP; ipcse = skb->h.raw - skb->data - 1; #ifdef NETIF_F_TSO_IPV6 - } else if(skb->protocol == ntohs(ETH_P_IPV6)) { + } else if (skb->protocol == ntohs(ETH_P_IPV6)) { skb->nh.ipv6h->payload_len = 0; skb->h.th->check = ~csum_ipv6_magic(&skb->nh.ipv6h->saddr, @@ -2555,7 +2599,7 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, unsigned int i; uint8_t css; - if(likely(skb->ip_summed == CHECKSUM_HW)) { + if (likely(skb->ip_summed == CHECKSUM_HW)) { css = skb->h.raw - skb->data; i = tx_ring->next_to_use; @@ -2595,7 +2639,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, i = tx_ring->next_to_use; - while(len) { + while (len) { buffer_info = &tx_ring->buffer_info[i]; size = min(len, max_per_txd); #ifdef NETIF_F_TSO @@ -2611,7 +2655,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, /* Workaround for premature desc write-backs * in TSO mode. Append 4-byte sentinel desc */ - if(unlikely(mss && !nr_frags && size == len && size > 8)) + if (unlikely(mss && !nr_frags && size == len && size > 8)) size -= 4; #endif /* work-around for errata 10 and it applies @@ -2619,13 +2663,13 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, * The fix is to make sure that the first descriptor of a * packet is smaller than 2048 - 16 - 16 (or 2016) bytes */ - if(unlikely((adapter->hw.bus_type == e1000_bus_type_pcix) && + if (unlikely((adapter->hw.bus_type == e1000_bus_type_pcix) && (size > 2015) && count == 0)) size = 2015; - + /* Workaround for potential 82544 hang in PCI-X. Avoid * terminating buffers within evenly-aligned dwords. */ - if(unlikely(adapter->pcix_82544 && + if (unlikely(adapter->pcix_82544 && !((unsigned long)(skb->data + offset + size - 1) & 4) && size > 4)) size -= 4; @@ -2641,29 +2685,29 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, len -= size; offset += size; count++; - if(unlikely(++i == tx_ring->count)) i = 0; + if (unlikely(++i == tx_ring->count)) i = 0; } - for(f = 0; f < nr_frags; f++) { + for (f = 0; f < nr_frags; f++) { struct skb_frag_struct *frag; frag = &skb_shinfo(skb)->frags[f]; len = frag->size; offset = frag->page_offset; - while(len) { + while (len) { buffer_info = &tx_ring->buffer_info[i]; size = min(len, max_per_txd); #ifdef NETIF_F_TSO /* Workaround for premature desc write-backs * in TSO mode. Append 4-byte sentinel desc */ - if(unlikely(mss && f == (nr_frags-1) && size == len && size > 8)) + if (unlikely(mss && f == (nr_frags-1) && size == len && size > 8)) size -= 4; #endif /* Workaround for potential 82544 hang in PCI-X. * Avoid terminating buffers within evenly-aligned * dwords. */ - if(unlikely(adapter->pcix_82544 && + if (unlikely(adapter->pcix_82544 && !((unsigned long)(frag->page+offset+size-1) & 4) && size > 4)) size -= 4; @@ -2680,7 +2724,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, len -= size; offset += size; count++; - if(unlikely(++i == tx_ring->count)) i = 0; + if (unlikely(++i == tx_ring->count)) i = 0; } } @@ -2700,35 +2744,35 @@ e1000_tx_queue(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; unsigned int i; - if(likely(tx_flags & E1000_TX_FLAGS_TSO)) { + if (likely(tx_flags & E1000_TX_FLAGS_TSO)) { txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D | E1000_TXD_CMD_TSE; txd_upper |= E1000_TXD_POPTS_TXSM << 8; - if(likely(tx_flags & E1000_TX_FLAGS_IPV4)) + if (likely(tx_flags & E1000_TX_FLAGS_IPV4)) txd_upper |= E1000_TXD_POPTS_IXSM << 8; } - if(likely(tx_flags & E1000_TX_FLAGS_CSUM)) { + if (likely(tx_flags & E1000_TX_FLAGS_CSUM)) { txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; txd_upper |= E1000_TXD_POPTS_TXSM << 8; } - if(unlikely(tx_flags & E1000_TX_FLAGS_VLAN)) { + if (unlikely(tx_flags & E1000_TX_FLAGS_VLAN)) { txd_lower |= E1000_TXD_CMD_VLE; txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK); } i = tx_ring->next_to_use; - while(count--) { + while (count--) { buffer_info = &tx_ring->buffer_info[i]; tx_desc = E1000_TX_DESC(*tx_ring, i); tx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); tx_desc->lower.data = cpu_to_le32(txd_lower | buffer_info->length); tx_desc->upper.data = cpu_to_le32(txd_upper); - if(unlikely(++i == tx_ring->count)) i = 0; + if (unlikely(++i == tx_ring->count)) i = 0; } tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd); @@ -2763,20 +2807,20 @@ e1000_82547_fifo_workaround(struct e1000_adapter *adapter, struct sk_buff *skb) E1000_ROUNDUP(skb_fifo_len, E1000_FIFO_HDR); - if(adapter->link_duplex != HALF_DUPLEX) + if (adapter->link_duplex != HALF_DUPLEX) goto no_fifo_stall_required; - if(atomic_read(&adapter->tx_fifo_stall)) + if (atomic_read(&adapter->tx_fifo_stall)) return 1; - if(skb_fifo_len >= (E1000_82547_PAD_LEN + fifo_space)) { + if (skb_fifo_len >= (E1000_82547_PAD_LEN + fifo_space)) { atomic_set(&adapter->tx_fifo_stall, 1); return 1; } no_fifo_stall_required: adapter->tx_fifo_head += skb_fifo_len; - if(adapter->tx_fifo_head >= adapter->tx_fifo_size) + if (adapter->tx_fifo_head >= adapter->tx_fifo_size) adapter->tx_fifo_head -= adapter->tx_fifo_size; return 0; } @@ -2787,27 +2831,27 @@ e1000_transfer_dhcp_info(struct e1000_adapter *adapter, struct sk_buff *skb) { struct e1000_hw *hw = &adapter->hw; uint16_t length, offset; - if(vlan_tx_tag_present(skb)) { - if(!((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) && + if (vlan_tx_tag_present(skb)) { + if (!((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) && ( adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) ) return 0; } - if ((skb->len > MINIMUM_DHCP_PACKET_SIZE) && (!skb->protocol)) { + if ((skb->len > MINIMUM_DHCP_PACKET_SIZE) && (!skb->protocol)) { struct ethhdr *eth = (struct ethhdr *) skb->data; - if((htons(ETH_P_IP) == eth->h_proto)) { - const struct iphdr *ip = + if ((htons(ETH_P_IP) == eth->h_proto)) { + const struct iphdr *ip = (struct iphdr *)((uint8_t *)skb->data+14); - if(IPPROTO_UDP == ip->protocol) { - struct udphdr *udp = - (struct udphdr *)((uint8_t *)ip + + if (IPPROTO_UDP == ip->protocol) { + struct udphdr *udp = + (struct udphdr *)((uint8_t *)ip + (ip->ihl << 2)); - if(ntohs(udp->dest) == 67) { + if (ntohs(udp->dest) == 67) { offset = (uint8_t *)udp + 8 - skb->data; length = skb->len - offset; return e1000_mng_write_dhcp_info(hw, - (uint8_t *)udp + 8, + (uint8_t *)udp + 8, length); } } @@ -2830,7 +2874,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) unsigned int nr_frags = 0; unsigned int mss = 0; int count = 0; - int tso; + int tso; unsigned int f; len -= skb->data_len; @@ -2853,7 +2897,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) * 4 = ceil(buffer len/mss). To make sure we don't * overrun the FIFO, adjust the max buffer len if mss * drops. */ - if(mss) { + if (mss) { uint8_t hdr_len; max_per_txd = min(mss << 2, max_per_txd); max_txd_pwr = fls(max_per_txd) - 1; @@ -2876,12 +2920,12 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } } - if((mss) || (skb->ip_summed == CHECKSUM_HW)) /* reserve a descriptor for the offload context */ + if ((mss) || (skb->ip_summed == CHECKSUM_HW)) count++; count++; #else - if(skb->ip_summed == CHECKSUM_HW) + if (skb->ip_summed == CHECKSUM_HW) count++; #endif @@ -2894,24 +2938,24 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) count += TXD_USE_COUNT(len, max_txd_pwr); - if(adapter->pcix_82544) + if (adapter->pcix_82544) count++; - /* work-around for errata 10 and it applies to all controllers + /* work-around for errata 10 and it applies to all controllers * in PCI-X mode, so add one more descriptor to the count */ - if(unlikely((adapter->hw.bus_type == e1000_bus_type_pcix) && + if (unlikely((adapter->hw.bus_type == e1000_bus_type_pcix) && (len > 2015))) count++; nr_frags = skb_shinfo(skb)->nr_frags; - for(f = 0; f < nr_frags; f++) + for (f = 0; f < nr_frags; f++) count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size, max_txd_pwr); - if(adapter->pcix_82544) + if (adapter->pcix_82544) count += nr_frags; - if(adapter->hw.tx_pkt_filtering && (adapter->hw.mac_type == e1000_82573) ) + if (adapter->hw.tx_pkt_filtering && (adapter->hw.mac_type == e1000_82573) ) e1000_transfer_dhcp_info(adapter, skb); local_irq_save(flags); @@ -2929,8 +2973,8 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_BUSY; } - if(unlikely(adapter->hw.mac_type == e1000_82547)) { - if(unlikely(e1000_82547_fifo_workaround(adapter, skb))) { + if (unlikely(adapter->hw.mac_type == e1000_82547)) { + if (unlikely(e1000_82547_fifo_workaround(adapter, skb))) { netif_stop_queue(netdev); mod_timer(&adapter->tx_fifo_stall_timer, jiffies); spin_unlock_irqrestore(&tx_ring->tx_lock, flags); @@ -2938,13 +2982,13 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } } - if(unlikely(adapter->vlgrp && vlan_tx_tag_present(skb))) { + if (unlikely(adapter->vlgrp && vlan_tx_tag_present(skb))) { tx_flags |= E1000_TX_FLAGS_VLAN; tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); } first = tx_ring->next_to_use; - + tso = e1000_tso(adapter, tx_ring, skb); if (tso < 0) { dev_kfree_skb_any(skb); @@ -3033,9 +3077,9 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu) struct e1000_adapter *adapter = netdev_priv(netdev); int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; - if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) || - (max_frame > MAX_JUMBO_FRAME_SIZE)) { - DPRINTK(PROBE, ERR, "Invalid MTU setting\n"); + if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) || + (max_frame > MAX_JUMBO_FRAME_SIZE)) { + DPRINTK(PROBE, ERR, "Invalid MTU setting\n"); return -EINVAL; } @@ -3083,7 +3127,7 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu) netdev->mtu = new_mtu; - if(netif_running(netdev)) { + if (netif_running(netdev)) { e1000_down(adapter); e1000_up(adapter); } @@ -3170,7 +3214,7 @@ e1000_update_stats(struct e1000_adapter *adapter) hw->collision_delta = E1000_READ_REG(hw, COLC); adapter->stats.colc += hw->collision_delta; - if(hw->mac_type >= e1000_82543) { + if (hw->mac_type >= e1000_82543) { adapter->stats.algnerrc += E1000_READ_REG(hw, ALGNERRC); adapter->stats.rxerrc += E1000_READ_REG(hw, RXERRC); adapter->stats.tncrs += E1000_READ_REG(hw, TNCRS); @@ -3178,7 +3222,7 @@ e1000_update_stats(struct e1000_adapter *adapter) adapter->stats.tsctc += E1000_READ_REG(hw, TSCTC); adapter->stats.tsctfc += E1000_READ_REG(hw, TSCTFC); } - if(hw->mac_type > e1000_82547_rev_2) { + if (hw->mac_type > e1000_82547_rev_2) { adapter->stats.iac += E1000_READ_REG(hw, IAC); adapter->stats.icrxoc += E1000_READ_REG(hw, ICRXOC); adapter->stats.icrxptc += E1000_READ_REG(hw, ICRXPTC); @@ -3222,14 +3266,14 @@ e1000_update_stats(struct e1000_adapter *adapter) /* Phy Stats */ - if(hw->media_type == e1000_media_type_copper) { - if((adapter->link_speed == SPEED_1000) && + if (hw->media_type == e1000_media_type_copper) { + if ((adapter->link_speed == SPEED_1000) && (!e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) { phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK; adapter->phy_stats.idle_errors += phy_tmp; } - if((hw->mac_type <= e1000_82546) && + if ((hw->mac_type <= e1000_82546) && (hw->phy_type == e1000_phy_m88) && !e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp)) adapter->phy_stats.receive_errors += phy_tmp; @@ -3294,7 +3338,7 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) return IRQ_NONE; /* Not our interrupt */ } - if(unlikely(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))) { + if (unlikely(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))) { hw->get_link_status = 1; mod_timer(&adapter->watchdog_timer, jiffies); } @@ -3326,26 +3370,26 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) #else /* if !CONFIG_E1000_NAPI */ /* Writing IMC and IMS is needed for 82547. - Due to Hub Link bus being occupied, an interrupt - de-assertion message is not able to be sent. - When an interrupt assertion message is generated later, - two messages are re-ordered and sent out. - That causes APIC to think 82547 is in de-assertion - state, while 82547 is in assertion state, resulting - in dead lock. Writing IMC forces 82547 into - de-assertion state. - */ - if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2){ + * Due to Hub Link bus being occupied, an interrupt + * de-assertion message is not able to be sent. + * When an interrupt assertion message is generated later, + * two messages are re-ordered and sent out. + * That causes APIC to think 82547 is in de-assertion + * state, while 82547 is in assertion state, resulting + * in dead lock. Writing IMC forces 82547 into + * de-assertion state. + */ + if (hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2) { atomic_inc(&adapter->irq_sem); E1000_WRITE_REG(hw, IMC, ~0); } - for(i = 0; i < E1000_MAX_INTR; i++) - if(unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) & + for (i = 0; i < E1000_MAX_INTR; i++) + if (unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) & !e1000_clean_tx_irq(adapter, adapter->tx_ring))) break; - if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2) + if (hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2) e1000_irq_enable(adapter); #endif /* CONFIG_E1000_NAPI */ @@ -3397,9 +3441,9 @@ e1000_clean(struct net_device *poll_dev, int *budget) *budget -= work_done; poll_dev->quota -= work_done; - + /* If no Tx and not enough Rx work done, exit the polling mode */ - if((!tx_cleaned && (work_done == 0)) || + if ((!tx_cleaned && (work_done == 0)) || !netif_running(adapter->netdev)) { quit_polling: netif_rx_complete(poll_dev); @@ -3431,7 +3475,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, eop_desc = E1000_TX_DESC(*tx_ring, eop); while (eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { - for(cleaned = FALSE; !cleaned; ) { + for (cleaned = FALSE; !cleaned; ) { tx_desc = E1000_TX_DESC(*tx_ring, i); buffer_info = &tx_ring->buffer_info[i]; cleaned = (i == eop); @@ -3442,7 +3486,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, e1000_unmap_and_free_tx_resource(adapter, buffer_info); memset(tx_desc, 0, sizeof(struct e1000_tx_desc)); - if(unlikely(++i == tx_ring->count)) i = 0; + if (unlikely(++i == tx_ring->count)) i = 0; } #ifdef CONFIG_E1000_MQ @@ -3457,7 +3501,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, spin_lock(&tx_ring->tx_lock); - if(unlikely(cleaned && netif_queue_stopped(netdev) && + if (unlikely(cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev))) netif_wake_queue(netdev); @@ -3519,21 +3563,21 @@ e1000_rx_checksum(struct e1000_adapter *adapter, skb->ip_summed = CHECKSUM_NONE; /* 82543 or newer only */ - if(unlikely(adapter->hw.mac_type < e1000_82543)) return; + if (unlikely(adapter->hw.mac_type < e1000_82543)) return; /* Ignore Checksum bit is set */ - if(unlikely(status & E1000_RXD_STAT_IXSM)) return; + if (unlikely(status & E1000_RXD_STAT_IXSM)) return; /* TCP/UDP checksum error bit is set */ - if(unlikely(errors & E1000_RXD_ERR_TCPE)) { + if (unlikely(errors & E1000_RXD_ERR_TCPE)) { /* let the stack verify checksum errors */ adapter->hw_csum_err++; return; } /* TCP/UDP Checksum has not been calculated */ - if(adapter->hw.mac_type <= e1000_82547_rev_2) { - if(!(status & E1000_RXD_STAT_TCPCS)) + if (adapter->hw.mac_type <= e1000_82547_rev_2) { + if (!(status & E1000_RXD_STAT_TCPCS)) return; } else { - if(!(status & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS))) + if (!(status & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS))) return; } /* It must be a TCP or UDP packet with a valid checksum */ @@ -3569,9 +3613,8 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, { struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; - struct e1000_rx_desc *rx_desc; - struct e1000_buffer *buffer_info; - struct sk_buff *skb; + struct e1000_rx_desc *rx_desc, *next_rxd; + struct e1000_buffer *buffer_info, *next_buffer; unsigned long flags; uint32_t length; uint8_t last_byte; @@ -3581,16 +3624,25 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, i = rx_ring->next_to_clean; rx_desc = E1000_RX_DESC(*rx_ring, i); + buffer_info = &rx_ring->buffer_info[i]; - while(rx_desc->status & E1000_RXD_STAT_DD) { - buffer_info = &rx_ring->buffer_info[i]; + while (rx_desc->status & E1000_RXD_STAT_DD) { + struct sk_buff *skb, *next_skb; u8 status; #ifdef CONFIG_E1000_NAPI - if(*work_done >= work_to_do) + if (*work_done >= work_to_do) break; (*work_done)++; #endif status = rx_desc->status; + skb = buffer_info->skb; + buffer_info->skb = NULL; + + if (++i == rx_ring->count) i = 0; + next_rxd = E1000_RX_DESC(*rx_ring, i); + next_buffer = &rx_ring->buffer_info[i]; + next_skb = next_buffer->skb; + cleaned = TRUE; cleaned_count++; pci_unmap_single(pdev, @@ -3598,20 +3650,50 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, buffer_info->length, PCI_DMA_FROMDEVICE); - skb = buffer_info->skb; length = le16_to_cpu(rx_desc->length); - if(unlikely(!(rx_desc->status & E1000_RXD_STAT_EOP))) { - /* All receives must fit into a single buffer */ - E1000_DBG("%s: Receive packet consumed multiple" - " buffers\n", netdev->name); - dev_kfree_skb_irq(skb); + skb_put(skb, length); + + if (!(status & E1000_RXD_STAT_EOP)) { + if (!rx_ring->rx_skb_top) { + rx_ring->rx_skb_top = skb; + rx_ring->rx_skb_top->len = length; + rx_ring->rx_skb_prev = skb; + } else { + if (skb_shinfo(rx_ring->rx_skb_top)->frag_list) { + rx_ring->rx_skb_prev->next = skb; + skb->prev = rx_ring->rx_skb_prev; + } else { + skb_shinfo(rx_ring->rx_skb_top)->frag_list = skb; + } + rx_ring->rx_skb_prev = skb; + rx_ring->rx_skb_top->data_len += length; + } goto next_desc; + } else { + if (rx_ring->rx_skb_top) { + if (skb_shinfo(rx_ring->rx_skb_top) + ->frag_list) { + rx_ring->rx_skb_prev->next = skb; + skb->prev = rx_ring->rx_skb_prev; + } else + skb_shinfo(rx_ring->rx_skb_top) + ->frag_list = skb; + + rx_ring->rx_skb_top->data_len += length; + rx_ring->rx_skb_top->len += + rx_ring->rx_skb_top->data_len; + + skb = rx_ring->rx_skb_top; + multi_descriptor = TRUE; + rx_ring->rx_skb_top = NULL; + rx_ring->rx_skb_prev = NULL; + } } - if(unlikely(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) { + if (unlikely(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) { last_byte = *(skb->data + length - 1); - if(TBI_ACCEPT(&adapter->hw, rx_desc->status, + if (TBI_ACCEPT(&adapter->hw, status, rx_desc->errors, length, last_byte)) { spin_lock_irqsave(&adapter->stats_lock, flags); e1000_tbi_adjust_stats(&adapter->hw, @@ -3656,9 +3738,10 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, (uint32_t)(status) | ((uint32_t)(rx_desc->errors) << 24), rx_desc->csum, skb); + skb->protocol = eth_type_trans(skb, netdev); #ifdef CONFIG_E1000_NAPI - if(unlikely(adapter->vlgrp && + if (unlikely(adapter->vlgrp && (status & E1000_RXD_STAT_VP))) { vlan_hwaccel_receive_skb(skb, adapter->vlgrp, le16_to_cpu(rx_desc->special) & @@ -3667,8 +3750,8 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, netif_receive_skb(skb); } #else /* CONFIG_E1000_NAPI */ - if(unlikely(adapter->vlgrp && - (rx_desc->status & E1000_RXD_STAT_VP))) { + if (unlikely(adapter->vlgrp && + (status & E1000_RXD_STAT_VP))) { vlan_hwaccel_rx(skb, adapter->vlgrp, le16_to_cpu(rx_desc->special) & E1000_RXD_SPC_VLAN_MASK); @@ -3691,6 +3774,8 @@ next_desc: cleaned_count = 0; } + rx_desc = next_rxd; + buffer_info = next_buffer; } rx_ring->next_to_clean = i; @@ -3716,13 +3801,13 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring) #endif { - union e1000_rx_desc_packet_split *rx_desc; + union e1000_rx_desc_packet_split *rx_desc, *next_rxd; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; - struct e1000_buffer *buffer_info; + struct e1000_buffer *buffer_info, *next_buffer; struct e1000_ps_page *ps_page; struct e1000_ps_page_dma *ps_page_dma; - struct sk_buff *skb; + struct sk_buff *skb, *next_skb; unsigned int i, j; uint32_t length, staterr; int cleaned_count = 0; @@ -3731,39 +3816,44 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, i = rx_ring->next_to_clean; rx_desc = E1000_RX_DESC_PS(*rx_ring, i); staterr = le32_to_cpu(rx_desc->wb.middle.status_error); + buffer_info = &rx_ring->buffer_info[i]; - while(staterr & E1000_RXD_STAT_DD) { - buffer_info = &rx_ring->buffer_info[i]; + while (staterr & E1000_RXD_STAT_DD) { ps_page = &rx_ring->ps_page[i]; ps_page_dma = &rx_ring->ps_page_dma[i]; #ifdef CONFIG_E1000_NAPI - if(unlikely(*work_done >= work_to_do)) + if (unlikely(*work_done >= work_to_do)) break; (*work_done)++; #endif + skb = buffer_info->skb; + + if (++i == rx_ring->count) i = 0; + next_rxd = E1000_RX_DESC_PS(*rx_ring, i); + next_buffer = &rx_ring->buffer_info[i]; + next_skb = next_buffer->skb; + cleaned = TRUE; cleaned_count++; pci_unmap_single(pdev, buffer_info->dma, buffer_info->length, PCI_DMA_FROMDEVICE); - skb = buffer_info->skb; - - if(unlikely(!(staterr & E1000_RXD_STAT_EOP))) { + if (unlikely(!(staterr & E1000_RXD_STAT_EOP))) { E1000_DBG("%s: Packet Split buffers didn't pick up" " the full packet\n", netdev->name); dev_kfree_skb_irq(skb); goto next_desc; } - if(unlikely(staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK)) { + if (unlikely(staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK)) { dev_kfree_skb_irq(skb); goto next_desc; } length = le16_to_cpu(rx_desc->wb.middle.length0); - if(unlikely(!length)) { + if (unlikely(!length)) { E1000_DBG("%s: Last part of the packet spanning" " multiple descriptors\n", netdev->name); dev_kfree_skb_irq(skb); @@ -3773,8 +3863,8 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, /* Good Receive */ skb_put(skb, length); - for(j = 0; j < adapter->rx_ps_pages; j++) { - if(!(length = le16_to_cpu(rx_desc->wb.upper.length[j]))) + for (j = 0; j < adapter->rx_ps_pages; j++) { + if (!(length = le16_to_cpu(rx_desc->wb.upper.length[j]))) break; pci_unmap_page(pdev, ps_page_dma->ps_page_dma[j], @@ -3794,15 +3884,11 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, rx_desc->wb.lower.hi_dword.csum_ip.csum, skb); skb->protocol = eth_type_trans(skb, netdev); - if(likely(rx_desc->wb.upper.header_status & - E1000_RXDPS_HDRSTAT_HDRSP)) { + if (likely(rx_desc->wb.upper.header_status & + E1000_RXDPS_HDRSTAT_HDRSP)) adapter->rx_hdr_split++; -#ifdef HAVE_RX_ZERO_COPY - skb_shinfo(skb)->zero_copy = TRUE; -#endif - } #ifdef CONFIG_E1000_NAPI - if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) { + if (unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) { vlan_hwaccel_receive_skb(skb, adapter->vlgrp, le16_to_cpu(rx_desc->wb.middle.vlan) & E1000_RXD_SPC_VLAN_MASK); @@ -3810,7 +3896,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, netif_receive_skb(skb); } #else /* CONFIG_E1000_NAPI */ - if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) { + if (unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) { vlan_hwaccel_rx(skb, adapter->vlgrp, le16_to_cpu(rx_desc->wb.middle.vlan) & E1000_RXD_SPC_VLAN_MASK); @@ -3834,6 +3920,9 @@ next_desc: cleaned_count = 0; } + rx_desc = next_rxd; + buffer_info = next_buffer; + staterr = le32_to_cpu(rx_desc->wb.middle.status_error); } rx_ring->next_to_clean = i; @@ -3875,7 +3964,7 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter, } - if(unlikely(!skb)) { + if (unlikely(!skb)) { /* Better luck next round */ adapter->alloc_rx_buff_failed++; break; @@ -3940,20 +4029,23 @@ map_skb: rx_desc = E1000_RX_DESC(*rx_ring, i); rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); - if(unlikely((i & ~(E1000_RX_BUFFER_WRITE - 1)) == i)) { - /* Force memory writes to complete before letting h/w - * know there are new descriptors to fetch. (Only - * applicable for weak-ordered memory model archs, - * such as IA-64). */ - wmb(); - writel(i, adapter->hw.hw_addr + rx_ring->rdt); - } - - if(unlikely(++i == rx_ring->count)) i = 0; + if (unlikely(++i == rx_ring->count)) + i = 0; buffer_info = &rx_ring->buffer_info[i]; } - rx_ring->next_to_use = i; + if (likely(rx_ring->next_to_use != i)) { + rx_ring->next_to_use = i; + if (unlikely(i-- == 0)) + i = (rx_ring->count - 1); + + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). */ + wmb(); + writel(i, adapter->hw.hw_addr + rx_ring->rdt); + } } /** @@ -3983,13 +4075,15 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, while (cleaned_count--) { rx_desc = E1000_RX_DESC_PS(*rx_ring, i); - for(j = 0; j < PS_PAGE_BUFFERS; j++) { + for (j = 0; j < PS_PAGE_BUFFERS; j++) { if (j < adapter->rx_ps_pages) { if (likely(!ps_page->ps_page[j])) { ps_page->ps_page[j] = alloc_page(GFP_ATOMIC); - if (unlikely(!ps_page->ps_page[j])) + if (unlikely(!ps_page->ps_page[j])) { + adapter->alloc_rx_buff_failed++; goto no_buffers; + } ps_page_dma->ps_page_dma[j] = pci_map_page(pdev, ps_page->ps_page[j], @@ -3997,7 +4091,7 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, PCI_DMA_FROMDEVICE); } /* Refresh the desc even if buffer_addrs didn't - * change because each write-back erases + * change because each write-back erases * this info. */ rx_desc->read.buffer_addr[j+1] = @@ -4008,8 +4102,10 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, skb = dev_alloc_skb(adapter->rx_ps_bsize0 + NET_IP_ALIGN); - if(unlikely(!skb)) + if (unlikely(!skb)) { + adapter->alloc_rx_buff_failed++; break; + } /* Make buffer alignment 2 beyond a 16 byte boundary * this will result in a 16 byte aligned IP header after @@ -4027,27 +4123,28 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, rx_desc->read.buffer_addr[0] = cpu_to_le64(buffer_info->dma); - if(unlikely((i & ~(E1000_RX_BUFFER_WRITE - 1)) == i)) { - /* Force memory writes to complete before letting h/w - * know there are new descriptors to fetch. (Only - * applicable for weak-ordered memory model archs, - * such as IA-64). */ - wmb(); - /* Hardware increments by 16 bytes, but packet split - * descriptors are 32 bytes...so we increment tail - * twice as much. - */ - writel(i<<1, adapter->hw.hw_addr + rx_ring->rdt); - } - - if(unlikely(++i == rx_ring->count)) i = 0; + if (unlikely(++i == rx_ring->count)) i = 0; buffer_info = &rx_ring->buffer_info[i]; ps_page = &rx_ring->ps_page[i]; ps_page_dma = &rx_ring->ps_page_dma[i]; } no_buffers: - rx_ring->next_to_use = i; + if (likely(rx_ring->next_to_use != i)) { + rx_ring->next_to_use = i; + if (unlikely(i-- == 0)) i = (rx_ring->count - 1); + + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). */ + wmb(); + /* Hardware increments by 16 bytes, but packet split + * descriptors are 32 bytes...so we increment tail + * twice as much. + */ + writel(i<<1, adapter->hw.hw_addr + rx_ring->rdt); + } } /** @@ -4061,24 +4158,24 @@ e1000_smartspeed(struct e1000_adapter *adapter) uint16_t phy_status; uint16_t phy_ctrl; - if((adapter->hw.phy_type != e1000_phy_igp) || !adapter->hw.autoneg || + if ((adapter->hw.phy_type != e1000_phy_igp) || !adapter->hw.autoneg || !(adapter->hw.autoneg_advertised & ADVERTISE_1000_FULL)) return; - if(adapter->smartspeed == 0) { + if (adapter->smartspeed == 0) { /* If Master/Slave config fault is asserted twice, * we assume back-to-back */ e1000_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_status); - if(!(phy_status & SR_1000T_MS_CONFIG_FAULT)) return; + if (!(phy_status & SR_1000T_MS_CONFIG_FAULT)) return; e1000_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_status); - if(!(phy_status & SR_1000T_MS_CONFIG_FAULT)) return; + if (!(phy_status & SR_1000T_MS_CONFIG_FAULT)) return; e1000_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_ctrl); - if(phy_ctrl & CR_1000T_MS_ENABLE) { + if (phy_ctrl & CR_1000T_MS_ENABLE) { phy_ctrl &= ~CR_1000T_MS_ENABLE; e1000_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, phy_ctrl); adapter->smartspeed++; - if(!e1000_phy_setup_autoneg(&adapter->hw) && + if (!e1000_phy_setup_autoneg(&adapter->hw) && !e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_ctrl)) { phy_ctrl |= (MII_CR_AUTO_NEG_EN | @@ -4088,12 +4185,12 @@ e1000_smartspeed(struct e1000_adapter *adapter) } } return; - } else if(adapter->smartspeed == E1000_SMARTSPEED_DOWNSHIFT) { + } else if (adapter->smartspeed == E1000_SMARTSPEED_DOWNSHIFT) { /* If still no link, perhaps using 2/3 pair cable */ e1000_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_ctrl); phy_ctrl |= CR_1000T_MS_ENABLE; e1000_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, phy_ctrl); - if(!e1000_phy_setup_autoneg(&adapter->hw) && + if (!e1000_phy_setup_autoneg(&adapter->hw) && !e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_ctrl)) { phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); @@ -4101,7 +4198,7 @@ e1000_smartspeed(struct e1000_adapter *adapter) } } /* Restart process after E1000_SMARTSPEED_MAX iterations */ - if(adapter->smartspeed++ == E1000_SMARTSPEED_MAX) + if (adapter->smartspeed++ == E1000_SMARTSPEED_MAX) adapter->smartspeed = 0; } @@ -4142,7 +4239,7 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) uint16_t spddplx; unsigned long flags; - if(adapter->hw.media_type != e1000_media_type_copper) + if (adapter->hw.media_type != e1000_media_type_copper) return -EOPNOTSUPP; switch (cmd) { @@ -4150,10 +4247,10 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) data->phy_id = adapter->hw.phy_addr; break; case SIOCGMIIREG: - if(!capable(CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) return -EPERM; spin_lock_irqsave(&adapter->stats_lock, flags); - if(e1000_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, + if (e1000_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, &data->val_out)) { spin_unlock_irqrestore(&adapter->stats_lock, flags); return -EIO; @@ -4161,23 +4258,23 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) spin_unlock_irqrestore(&adapter->stats_lock, flags); break; case SIOCSMIIREG: - if(!capable(CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) return -EPERM; - if(data->reg_num & ~(0x1F)) + if (data->reg_num & ~(0x1F)) return -EFAULT; mii_reg = data->val_in; spin_lock_irqsave(&adapter->stats_lock, flags); - if(e1000_write_phy_reg(&adapter->hw, data->reg_num, + if (e1000_write_phy_reg(&adapter->hw, data->reg_num, mii_reg)) { spin_unlock_irqrestore(&adapter->stats_lock, flags); return -EIO; } - if(adapter->hw.phy_type == e1000_phy_m88) { + if (adapter->hw.phy_type == e1000_phy_m88) { switch (data->reg_num) { case PHY_CTRL: - if(mii_reg & MII_CR_POWER_DOWN) + if (mii_reg & MII_CR_POWER_DOWN) break; - if(mii_reg & MII_CR_AUTO_NEG_EN) { + if (mii_reg & MII_CR_AUTO_NEG_EN) { adapter->hw.autoneg = 1; adapter->hw.autoneg_advertised = 0x2F; } else { @@ -4192,14 +4289,14 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) HALF_DUPLEX; retval = e1000_set_spd_dplx(adapter, spddplx); - if(retval) { + if (retval) { spin_unlock_irqrestore( - &adapter->stats_lock, + &adapter->stats_lock, flags); return retval; } } - if(netif_running(adapter->netdev)) { + if (netif_running(adapter->netdev)) { e1000_down(adapter); e1000_up(adapter); } else @@ -4207,7 +4304,7 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) break; case M88E1000_PHY_SPEC_CTRL: case M88E1000_EXT_PHY_SPEC_CTRL: - if(e1000_phy_reset(&adapter->hw)) { + if (e1000_phy_reset(&adapter->hw)) { spin_unlock_irqrestore( &adapter->stats_lock, flags); return -EIO; @@ -4217,9 +4314,9 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) } else { switch (data->reg_num) { case PHY_CTRL: - if(mii_reg & MII_CR_POWER_DOWN) + if (mii_reg & MII_CR_POWER_DOWN) break; - if(netif_running(adapter->netdev)) { + if (netif_running(adapter->netdev)) { e1000_down(adapter); e1000_up(adapter); } else @@ -4241,7 +4338,7 @@ e1000_pci_set_mwi(struct e1000_hw *hw) struct e1000_adapter *adapter = hw->back; int ret_val = pci_set_mwi(adapter->pdev); - if(ret_val) + if (ret_val) DPRINTK(PROBE, ERR, "Error in setting MWI\n"); } @@ -4290,7 +4387,7 @@ e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) e1000_irq_disable(adapter); adapter->vlgrp = grp; - if(grp) { + if (grp) { /* enable VLAN tag insert/strip */ ctrl = E1000_READ_REG(&adapter->hw, CTRL); ctrl |= E1000_CTRL_VME; @@ -4312,7 +4409,7 @@ e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) rctl = E1000_READ_REG(&adapter->hw, RCTL); rctl &= ~E1000_RCTL_VFE; E1000_WRITE_REG(&adapter->hw, RCTL, rctl); - if(adapter->mng_vlan_id != (uint16_t)E1000_MNG_VLAN_NONE) { + if (adapter->mng_vlan_id != (uint16_t)E1000_MNG_VLAN_NONE) { e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; } @@ -4326,9 +4423,10 @@ e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid) { struct e1000_adapter *adapter = netdev_priv(netdev); uint32_t vfta, index; - if((adapter->hw.mng_cookie.status & - E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) && - (vid == adapter->mng_vlan_id)) + + if ((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) && + (vid == adapter->mng_vlan_id)) return; /* add VID to filter table */ index = (vid >> 5) & 0x7F; @@ -4345,13 +4443,13 @@ e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid) e1000_irq_disable(adapter); - if(adapter->vlgrp) + if (adapter->vlgrp) adapter->vlgrp->vlan_devices[vid] = NULL; e1000_irq_enable(adapter); - if((adapter->hw.mng_cookie.status & - E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) && + if ((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) && (vid == adapter->mng_vlan_id)) { /* release control to f/w */ e1000_release_hw_control(adapter); @@ -4370,10 +4468,10 @@ e1000_restore_vlan(struct e1000_adapter *adapter) { e1000_vlan_rx_register(adapter->netdev, adapter->vlgrp); - if(adapter->vlgrp) { + if (adapter->vlgrp) { uint16_t vid; - for(vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { - if(!adapter->vlgrp->vlan_devices[vid]) + for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { + if (!adapter->vlgrp->vlan_devices[vid]) continue; e1000_vlan_rx_add_vid(adapter->netdev, vid); } @@ -4386,13 +4484,13 @@ e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx) adapter->hw.autoneg = 0; /* Fiber NICs only allow 1000 gbps Full duplex */ - if((adapter->hw.media_type == e1000_media_type_fiber) && + if ((adapter->hw.media_type == e1000_media_type_fiber) && spddplx != (SPEED_1000 + DUPLEX_FULL)) { DPRINTK(PROBE, ERR, "Unsupported Speed/Duplex configuration\n"); return -EINVAL; } - switch(spddplx) { + switch (spddplx) { case SPEED_10 + DUPLEX_HALF: adapter->hw.forced_speed_duplex = e1000_10_half; break; @@ -4418,6 +4516,54 @@ e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx) } #ifdef CONFIG_PM +/* these functions save and restore 16 or 64 dwords (64-256 bytes) of config + * space versus the 64 bytes that pci_[save|restore]_state handle + */ +#define PCIE_CONFIG_SPACE_LEN 256 +#define PCI_CONFIG_SPACE_LEN 64 +static int +e1000_pci_save_state(struct e1000_adapter *adapter) +{ + struct pci_dev *dev = adapter->pdev; + int size; + int i; + if (adapter->hw.mac_type >= e1000_82571) + size = PCIE_CONFIG_SPACE_LEN; + else + size = PCI_CONFIG_SPACE_LEN; + + WARN_ON(adapter->config_space != NULL); + + adapter->config_space = kmalloc(size, GFP_KERNEL); + if (!adapter->config_space) { + DPRINTK(PROBE, ERR, "unable to allocate %d bytes\n", size); + return -ENOMEM; + } + for (i = 0; i < (size / 4); i++) + pci_read_config_dword(dev, i * 4, &adapter->config_space[i]); + return 0; +} + +static void +e1000_pci_restore_state(struct e1000_adapter *adapter) +{ + struct pci_dev *dev = adapter->pdev; + int size; + int i; + if (adapter->config_space == NULL) + return; + if (adapter->hw.mac_type >= e1000_82571) + size = PCIE_CONFIG_SPACE_LEN; + else + size = PCI_CONFIG_SPACE_LEN; + for (i = 0; i < (size / 4); i++) + pci_write_config_dword(dev, i * 4, adapter->config_space[i]); + kfree(adapter->config_space); + adapter->config_space = NULL; + return; +} +#endif /* CONFIG_PM */ + static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) { @@ -4429,25 +4575,33 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) netif_device_detach(netdev); - if(netif_running(netdev)) + if (netif_running(netdev)) e1000_down(adapter); +#ifdef CONFIG_PM + /* implement our own version of pci_save_state(pdev) because pci + * express adapters have larger 256 byte config spaces */ + retval = e1000_pci_save_state(adapter); + if (retval) + return retval; +#endif + status = E1000_READ_REG(&adapter->hw, STATUS); - if(status & E1000_STATUS_LU) + if (status & E1000_STATUS_LU) wufc &= ~E1000_WUFC_LNKC; - if(wufc) { + if (wufc) { e1000_setup_rctl(adapter); e1000_set_multi(netdev); /* turn on all-multi mode if wake on multicast is enabled */ - if(adapter->wol & E1000_WUFC_MC) { + if (adapter->wol & E1000_WUFC_MC) { rctl = E1000_READ_REG(&adapter->hw, RCTL); rctl |= E1000_RCTL_MPE; E1000_WRITE_REG(&adapter->hw, RCTL, rctl); } - if(adapter->hw.mac_type >= e1000_82540) { + if (adapter->hw.mac_type >= e1000_82540) { ctrl = E1000_READ_REG(&adapter->hw, CTRL); /* advertise wake from D3Cold */ #define E1000_CTRL_ADVD3WUC 0x00100000 @@ -4458,7 +4612,7 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); } - if(adapter->hw.media_type == e1000_media_type_fiber || + if (adapter->hw.media_type == e1000_media_type_fiber || adapter->hw.media_type == e1000_media_type_internal_serdes) { /* keep the laser running in D3 */ ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); @@ -4488,12 +4642,10 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) DPRINTK(PROBE, ERR, "Error enabling D3 cold wake\n"); } - pci_save_state(pdev); - - if(adapter->hw.mac_type >= e1000_82540 && + if (adapter->hw.mac_type >= e1000_82540 && adapter->hw.media_type == e1000_media_type_copper) { manc = E1000_READ_REG(&adapter->hw, MANC); - if(manc & E1000_MANC_SMBUS_EN) { + if (manc & E1000_MANC_SMBUS_EN) { manc |= E1000_MANC_ARP_EN; E1000_WRITE_REG(&adapter->hw, MANC, manc); retval = pci_enable_wake(pdev, PCI_D3hot, 1); @@ -4518,6 +4670,7 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } +#ifdef CONFIG_PM static int e1000_resume(struct pci_dev *pdev) { @@ -4529,6 +4682,7 @@ e1000_resume(struct pci_dev *pdev) retval = pci_set_power_state(pdev, PCI_D0); if (retval) DPRINTK(PROBE, ERR, "Error in setting power state\n"); + e1000_pci_restore_state(adapter); ret_val = pci_enable_device(pdev); pci_set_master(pdev); @@ -4542,12 +4696,12 @@ e1000_resume(struct pci_dev *pdev) e1000_reset(adapter); E1000_WRITE_REG(&adapter->hw, WUS, ~0); - if(netif_running(netdev)) + if (netif_running(netdev)) e1000_up(adapter); netif_device_attach(netdev); - if(adapter->hw.mac_type >= e1000_82540 && + if (adapter->hw.mac_type >= e1000_82540 && adapter->hw.media_type == e1000_media_type_copper) { manc = E1000_READ_REG(&adapter->hw, MANC); manc &= ~(E1000_MANC_ARP_EN); diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h index aac64de61437..9790db974dc1 100644 --- a/drivers/net/e1000/e1000_osdep.h +++ b/drivers/net/e1000/e1000_osdep.h @@ -47,7 +47,7 @@ BUG(); \ } else { \ msleep(x); \ - } } while(0) + } } while (0) /* Some workarounds require millisecond delays and are run during interrupt * context. Most notably, when establishing link, the phy may need tweaking diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index 0a7918c62557..3768d83cd577 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -227,7 +227,7 @@ static int __devinit e1000_validate_option(int *value, struct e1000_option *opt, struct e1000_adapter *adapter) { - if(*value == OPTION_UNSET) { + if (*value == OPTION_UNSET) { *value = opt->def; return 0; } @@ -244,7 +244,7 @@ e1000_validate_option(int *value, struct e1000_option *opt, } break; case range_option: - if(*value >= opt->arg.r.min && *value <= opt->arg.r.max) { + if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) { DPRINTK(PROBE, INFO, "%s set to %i\n", opt->name, *value); return 0; @@ -254,10 +254,10 @@ e1000_validate_option(int *value, struct e1000_option *opt, int i; struct e1000_opt_list *ent; - for(i = 0; i < opt->arg.l.nr; i++) { + for (i = 0; i < opt->arg.l.nr; i++) { ent = &opt->arg.l.p[i]; - if(*value == ent->i) { - if(ent->str[0] != '\0') + if (*value == ent->i) { + if (ent->str[0] != '\0') DPRINTK(PROBE, INFO, "%s\n", ent->str); return 0; } @@ -291,7 +291,7 @@ void __devinit e1000_check_options(struct e1000_adapter *adapter) { int bd = adapter->bd_number; - if(bd >= E1000_MAX_NIC) { + if (bd >= E1000_MAX_NIC) { DPRINTK(PROBE, NOTICE, "Warning: no configuration for board #%i\n", bd); DPRINTK(PROBE, NOTICE, "Using defaults for all values\n"); @@ -315,7 +315,7 @@ e1000_check_options(struct e1000_adapter *adapter) if (num_TxDescriptors > bd) { tx_ring->count = TxDescriptors[bd]; e1000_validate_option(&tx_ring->count, &opt, adapter); - E1000_ROUNDUP(tx_ring->count, + E1000_ROUNDUP(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE); } else { tx_ring->count = opt.def; @@ -341,7 +341,7 @@ e1000_check_options(struct e1000_adapter *adapter) if (num_RxDescriptors > bd) { rx_ring->count = RxDescriptors[bd]; e1000_validate_option(&rx_ring->count, &opt, adapter); - E1000_ROUNDUP(rx_ring->count, + E1000_ROUNDUP(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE); } else { rx_ring->count = opt.def; @@ -403,7 +403,7 @@ e1000_check_options(struct e1000_adapter *adapter) if (num_TxIntDelay > bd) { adapter->tx_int_delay = TxIntDelay[bd]; - e1000_validate_option(&adapter->tx_int_delay, &opt, + e1000_validate_option(&adapter->tx_int_delay, &opt, adapter); } else { adapter->tx_int_delay = opt.def; @@ -421,7 +421,7 @@ e1000_check_options(struct e1000_adapter *adapter) if (num_TxAbsIntDelay > bd) { adapter->tx_abs_int_delay = TxAbsIntDelay[bd]; - e1000_validate_option(&adapter->tx_abs_int_delay, &opt, + e1000_validate_option(&adapter->tx_abs_int_delay, &opt, adapter); } else { adapter->tx_abs_int_delay = opt.def; @@ -439,7 +439,7 @@ e1000_check_options(struct e1000_adapter *adapter) if (num_RxIntDelay > bd) { adapter->rx_int_delay = RxIntDelay[bd]; - e1000_validate_option(&adapter->rx_int_delay, &opt, + e1000_validate_option(&adapter->rx_int_delay, &opt, adapter); } else { adapter->rx_int_delay = opt.def; @@ -457,7 +457,7 @@ e1000_check_options(struct e1000_adapter *adapter) if (num_RxAbsIntDelay > bd) { adapter->rx_abs_int_delay = RxAbsIntDelay[bd]; - e1000_validate_option(&adapter->rx_abs_int_delay, &opt, + e1000_validate_option(&adapter->rx_abs_int_delay, &opt, adapter); } else { adapter->rx_abs_int_delay = opt.def; @@ -475,17 +475,17 @@ e1000_check_options(struct e1000_adapter *adapter) if (num_InterruptThrottleRate > bd) { adapter->itr = InterruptThrottleRate[bd]; - switch(adapter->itr) { + switch (adapter->itr) { case 0: - DPRINTK(PROBE, INFO, "%s turned off\n", + DPRINTK(PROBE, INFO, "%s turned off\n", opt.name); break; case 1: - DPRINTK(PROBE, INFO, "%s set to dynamic mode\n", + DPRINTK(PROBE, INFO, "%s set to dynamic mode\n", opt.name); break; default: - e1000_validate_option(&adapter->itr, &opt, + e1000_validate_option(&adapter->itr, &opt, adapter); break; } @@ -494,7 +494,7 @@ e1000_check_options(struct e1000_adapter *adapter) } } - switch(adapter->hw.media_type) { + switch (adapter->hw.media_type) { case e1000_media_type_fiber: case e1000_media_type_internal_serdes: e1000_check_fiber_options(adapter); @@ -518,17 +518,17 @@ static void __devinit e1000_check_fiber_options(struct e1000_adapter *adapter) { int bd = adapter->bd_number; - if(num_Speed > bd) { + if (num_Speed > bd) { DPRINTK(PROBE, INFO, "Speed not valid for fiber adapters, " "parameter ignored\n"); } - if(num_Duplex > bd) { + if (num_Duplex > bd) { DPRINTK(PROBE, INFO, "Duplex not valid for fiber adapters, " "parameter ignored\n"); } - if((num_AutoNeg > bd) && (AutoNeg[bd] != 0x20)) { + if ((num_AutoNeg > bd) && (AutoNeg[bd] != 0x20)) { DPRINTK(PROBE, INFO, "AutoNeg other than 1000/Full is " "not valid for fiber adapters, " "parameter ignored\n"); @@ -598,7 +598,7 @@ e1000_check_copper_options(struct e1000_adapter *adapter) } } - if((num_AutoNeg > bd) && (speed != 0 || dplx != 0)) { + if ((num_AutoNeg > bd) && (speed != 0 || dplx != 0)) { DPRINTK(PROBE, INFO, "AutoNeg specified along with Speed or Duplex, " "parameter ignored\n"); @@ -659,7 +659,7 @@ e1000_check_copper_options(struct e1000_adapter *adapter) switch (speed + dplx) { case 0: adapter->hw.autoneg = adapter->fc_autoneg = 1; - if((num_Speed > bd) && (speed != 0 || dplx != 0)) + if ((num_Speed > bd) && (speed != 0 || dplx != 0)) DPRINTK(PROBE, INFO, "Speed and duplex autonegotiation enabled\n"); break; diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index d9ce8c549416..bc36edff2058 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2595,15 +2595,11 @@ static int __init serial8250_init(void) if (ret) goto out; - ret = platform_driver_register(&serial8250_isa_driver); - if (ret) - goto unreg_uart_drv; - serial8250_isa_devs = platform_device_alloc("serial8250", PLAT8250_DEV_LEGACY); if (!serial8250_isa_devs) { ret = -ENOMEM; - goto unreg_plat_drv; + goto unreg_uart_drv; } ret = platform_device_add(serial8250_isa_devs); @@ -2612,12 +2608,13 @@ static int __init serial8250_init(void) serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev); - goto out; + ret = platform_driver_register(&serial8250_isa_driver); + if (ret == 0) + goto out; + platform_device_del(serial8250_isa_devs); put_dev: platform_device_put(serial8250_isa_devs); - unreg_plat_drv: - platform_driver_unregister(&serial8250_isa_driver); unreg_uart_drv: uart_unregister_driver(&serial8250_reg); out: diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 589fb076654a..2a912153321e 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -940,6 +940,7 @@ enum pci_board_num_t { pbn_b2_bt_2_921600, pbn_b2_bt_4_921600, + pbn_b3_2_115200, pbn_b3_4_115200, pbn_b3_8_115200, @@ -1311,6 +1312,12 @@ static struct pciserial_board pci_boards[] __devinitdata = { .uart_offset = 8, }, + [pbn_b3_2_115200] = { + .flags = FL_BASE3, + .num_ports = 2, + .base_baud = 115200, + .uart_offset = 8, + }, [pbn_b3_4_115200] = { .flags = FL_BASE3, .num_ports = 4, @@ -2272,6 +2279,9 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_nec_nile4 }, + { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b3_2_115200 }, { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b3_4_115200 }, diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 5e7199f7b59c..9fd1925de361 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -301,7 +301,7 @@ config SERIAL_AT91_TTYAT depends on SERIAL_AT91=y help Say Y here if you wish to have the five internal AT91RM9200 UARTs - appear as /dev/ttyAT0-4 (major 240, minor 0-4) instead of the + appear as /dev/ttyAT0-4 (major 204, minor 154-158) instead of the normal /dev/ttyS0-4 (major 4, minor 64-68). This is necessary if you also want other UARTs, such as external 8250/16C550 compatible UARTs. diff --git a/drivers/serial/at91_serial.c b/drivers/serial/at91_serial.c index 0e206063d685..2113feb75c39 100644 --- a/drivers/serial/at91_serial.c +++ b/drivers/serial/at91_serial.c @@ -222,8 +222,6 @@ static void at91_rx_chars(struct uart_port *port, struct pt_regs *regs) while (status & (AT91_US_RXRDY)) { ch = UART_GET_CHAR(port); - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - goto ignore_char; port->icount.rx++; flg = TTY_NORMAL; diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c index 5468e5a767e2..43e67d6c29d4 100644 --- a/drivers/serial/sn_console.c +++ b/drivers/serial/sn_console.c @@ -6,7 +6,7 @@ * driver for that. * * - * Copyright (c) 2004-2005 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2004-2006 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -829,8 +829,8 @@ static int __init sn_sal_module_init(void) misc.name = DEVICE_NAME_DYNAMIC; retval = misc_register(&misc); if (retval != 0) { - printk - ("Failed to register console device using misc_register.\n"); + printk(KERN_WARNING "Failed to register console " + "device using misc_register.\n"); return -ENODEV; } sal_console_uart.major = MISC_MAJOR; @@ -942,88 +942,75 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count) { unsigned long flags = 0; struct sn_cons_port *port = &sal_console_port; -#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) static int stole_lock = 0; -#endif BUG_ON(!port->sc_is_asynch); /* We can't look at the xmit buffer if we're not registered with serial core * yet. So only do the fancy recovery after registering */ - if (port->sc_port.info) { - - /* somebody really wants this output, might be an - * oops, kdb, panic, etc. make sure they get it. */ -#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) - if (spin_is_locked(&port->sc_port.lock)) { - int lhead = port->sc_port.info->xmit.head; - int ltail = port->sc_port.info->xmit.tail; - int counter, got_lock = 0; + if (!port->sc_port.info) { + /* Not yet registered with serial core - simple case */ + puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count); + return; + } - /* - * We attempt to determine if someone has died with the - * lock. We wait ~20 secs after the head and tail ptrs - * stop moving and assume the lock holder is not functional - * and plow ahead. If the lock is freed within the time out - * period we re-get the lock and go ahead normally. We also - * remember if we have plowed ahead so that we don't have - * to wait out the time out period again - the asumption - * is that we will time out again. - */ + /* somebody really wants this output, might be an + * oops, kdb, panic, etc. make sure they get it. */ + if (spin_is_locked(&port->sc_port.lock)) { + int lhead = port->sc_port.info->xmit.head; + int ltail = port->sc_port.info->xmit.tail; + int counter, got_lock = 0; + + /* + * We attempt to determine if someone has died with the + * lock. We wait ~20 secs after the head and tail ptrs + * stop moving and assume the lock holder is not functional + * and plow ahead. If the lock is freed within the time out + * period we re-get the lock and go ahead normally. We also + * remember if we have plowed ahead so that we don't have + * to wait out the time out period again - the asumption + * is that we will time out again. + */ - for (counter = 0; counter < 150; mdelay(125), counter++) { - if (!spin_is_locked(&port->sc_port.lock) - || stole_lock) { - if (!stole_lock) { - spin_lock_irqsave(&port-> - sc_port.lock, - flags); - got_lock = 1; - } - break; - } else { - /* still locked */ - if ((lhead != - port->sc_port.info->xmit.head) - || (ltail != - port->sc_port.info->xmit. - tail)) { - lhead = - port->sc_port.info->xmit. - head; - ltail = - port->sc_port.info->xmit. - tail; - counter = 0; - } + for (counter = 0; counter < 150; mdelay(125), counter++) { + if (!spin_is_locked(&port->sc_port.lock) + || stole_lock) { + if (!stole_lock) { + spin_lock_irqsave(&port->sc_port.lock, + flags); + got_lock = 1; } - } - /* flush anything in the serial core xmit buffer, raw */ - sn_transmit_chars(port, 1); - if (got_lock) { - spin_unlock_irqrestore(&port->sc_port.lock, - flags); - stole_lock = 0; + break; } else { - /* fell thru */ - stole_lock = 1; + /* still locked */ + if ((lhead != port->sc_port.info->xmit.head) + || (ltail != + port->sc_port.info->xmit.tail)) { + lhead = + port->sc_port.info->xmit.head; + ltail = + port->sc_port.info->xmit.tail; + counter = 0; + } } - puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count); - } else { - stole_lock = 0; -#endif - spin_lock_irqsave(&port->sc_port.lock, flags); - sn_transmit_chars(port, 1); + } + /* flush anything in the serial core xmit buffer, raw */ + sn_transmit_chars(port, 1); + if (got_lock) { spin_unlock_irqrestore(&port->sc_port.lock, flags); - - puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count); -#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) + stole_lock = 0; + } else { + /* fell thru */ + stole_lock = 1; } -#endif - } - else { - /* Not yet registered with serial core - simple case */ + puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count); + } else { + stole_lock = 0; + spin_lock_irqsave(&port->sc_port.lock, flags); + sn_transmit_chars(port, 1); + spin_unlock_irqrestore(&port->sc_port.lock, flags); + puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count); } } diff --git a/drivers/serial/suncore.c b/drivers/serial/suncore.c index 5fc4a62173d9..fa4ae94243c2 100644 --- a/drivers/serial/suncore.c +++ b/drivers/serial/suncore.c @@ -34,6 +34,7 @@ sunserial_console_termios(struct console *con) char *mode_prop = "ttyX-mode"; char *cd_prop = "ttyX-ignore-cd"; char *dtr_prop = "ttyX-rts-dtr-off"; + char *ssp_console_modes_prop = "ssp-console-modes"; int baud, bits, stop, cflag; char parity; int carrier = 0; @@ -43,14 +44,39 @@ sunserial_console_termios(struct console *con) if (!serial_console) return; - if (serial_console == 1) { + switch (serial_console) { + case PROMDEV_OTTYA: mode_prop[3] = 'a'; cd_prop[3] = 'a'; dtr_prop[3] = 'a'; - } else { + break; + + case PROMDEV_OTTYB: mode_prop[3] = 'b'; cd_prop[3] = 'b'; dtr_prop[3] = 'b'; + break; + + case PROMDEV_ORSC: + + nd = prom_pathtoinode("rsc"); + if (!nd) { + strcpy(mode, "115200,8,n,1,-"); + goto no_options; + } + + if (!prom_node_has_property(nd, ssp_console_modes_prop)) { + strcpy(mode, "115200,8,n,1,-"); + goto no_options; + } + + memset(mode, 0, sizeof(mode)); + prom_getstring(nd, ssp_console_modes_prop, mode, sizeof(mode)); + goto no_options; + + default: + strcpy(mode, "9600,8,n,1,-"); + goto no_options; } topnd = prom_getchild(prom_root_node); @@ -110,6 +136,10 @@ no_options: case 9600: cflag |= B9600; break; case 19200: cflag |= B19200; break; case 38400: cflag |= B38400; break; + case 57600: cflag |= B57600; break; + case 115200: cflag |= B115200; break; + case 230400: cflag |= B230400; break; + case 460800: cflag |= B460800; break; default: baud = 9600; cflag |= B9600; break; } diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 7e773ff76c61..8bcaebcc0ad7 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -897,9 +897,6 @@ static int sunsab_console_setup(struct console *con, char *options) sunserial_console_termios(con); - /* Firmware console speed is limited to 150-->38400 baud so - * this hackish cflag thing is OK. - */ switch (con->cflag & CBAUD) { case B150: baud = 150; break; case B300: baud = 300; break; @@ -910,6 +907,10 @@ static int sunsab_console_setup(struct console *con, char *options) default: case B9600: baud = 9600; break; case B19200: baud = 19200; break; case B38400: baud = 38400; break; + case B57600: baud = 57600; break; + case B115200: baud = 115200; break; + case B230400: baud = 230400; break; + case B460800: baud = 460800; break; }; /* |