aboutsummaryrefslogtreecommitdiffstats
path: root/lib/crc7.c
blob: bf6255e239193159afb1fc6fef402b6b011f1b22 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/*
 *      crc7.c
 *
 * This source code is licensed under the GNU General Public License,
 * Version 2. See the file COPYING for more details.
 */

#include <linux/types.h>
#include <linux/module.h>
#include <linux/crc7.h>


/*
 * Table for CRC-7 (polynomial x^7 + x^3 + 1).
 * This is a big-endian CRC (msbit is highest power of x),
 * aligned so the msbit of the byte is the x^6 coefficient
 * and the lsbit is not used.
 */
const u8 crc7_be_syndrome_table[256] = {
	0x00, 0x12, 0x24, 0x36, 0x48, 0x5a, 0x6c, 0x7e,
	0x90, 0x82, 0xb4, 0xa6, 0xd8, 0xca, 0xfc, 0xee,
	0x32, 0x20, 0x16, 0x04, 0x7a, 0x68, 0x5e, 0x4c,
	0xa2, 0xb0, 0x86, 0x94, 0xea, 0xf8, 0xce, 0xdc,
	0x64, 0x76, 0x40, 0x52, 0x2c, 0x3e, 0x08, 0x1a,
	0xf4, 0xe6, 0xd0, 0xc2, 0xbc, 0xae, 0x98, 0x8a,
	0x56, 0x44, 0x72, 0x60, 0x1e, 0x0c, 0x3a, 0x28,
	0xc6, 0xd4, 0xe2, 0xf0, 0x8e, 0x9c, 0xaa, 0xb8,
	0xc8, 0xda, 0xec, 0xfe, 0x80, 0x92, 0xa4, 0xb6,
	0x58, 0x4a, 0x7c, 0x6e, 0x10, 0x02, 0x34, 0x26,
	0xfa, 0xe8, 0xde, 0xcc, 0xb2, 0xa0, 0x96, 0x84,
	0x6a, 0x78, 0x4e, 0x5c, 0x22, 0x30, 0x06, 0x14,
	0xac, 0xbe, 0x88, 0x9a, 0xe4, 0xf6, 0xc0, 0xd2,
	0x3c, 0x2e, 0x18, 0x0a, 0x74, 0x66, 0x50, 0x42,
	0x9e, 0x8c, 0xba, 0xa8, 0xd6, 0xc4, 0xf2, 0xe0,
	0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54, 0x62, 0x70,
	0x82, 0x90, 0xa6, 0xb4, 0xca, 0xd8, 0xee, 0xfc,
	0x12, 0x00, 0x36, 0x24, 0x5a, 0x48, 0x7e, 0x6c,
	0xb0, 0xa2, 0x94, 0x86, 0xf8, 0xea, 0xdc, 0xce,
	0x20, 0x32, 0x04, 0x16, 0x68, 0x7a, 0x4c, 0x5e,
	0xe6, 0xf4, 0xc2, 0xd0, 0xae, 0xbc, 0x8a, 0x98,
	0x76, 0x64, 0x52, 0x40, 0x3e, 0x2c, 0x1a, 0x08,
	0xd4, 0xc6, 0xf0, 0xe2, 0x9c, 0x8e, 0xb8, 0xaa,
	0x44, 0x56, 0x60, 0x72, 0x0c, 0x1e, 0x28, 0x3a,
	0x4a, 0x58, 0x6e, 0x7c, 0x02, 0x10, 0x26, 0x34,
	0xda, 0xc8, 0xfe, 0xec, 0x92, 0x80, 0xb6, 0xa4,
	0x78, 0x6a, 0x5c, 0x4e, 0x30, 0x22, 0x14, 0x06,
	0xe8, 0xfa, 0xcc, 0xde, 0xa0, 0xb2, 0x84, 0x96,
	0x2e, 0x3c, 0x0a, 0x18, 0x66, 0x74, 0x42, 0x50,
	0xbe, 0xac, 0x9a, 0x88, 0xf6, 0xe4, 0xd2, 0xc0,
	0x1c, 0x0e, 0x38, 0x2a, 0x54, 0x46, 0x70, 0x62,
	0x8c, 0x9e, 0xa8, 0xba, 0xc4, 0xd6, 0xe0, 0xf2
};
EXPORT_SYMBOL(crc7_be_syndrome_table);

/**
 * crc7 - update the CRC7 for the data buffer
 * @crc:     previous CRC7 value
 * @buffer:  data pointer
 * @len:     number of bytes in the buffer
 * Context: any
 *
 * Returns the updated CRC7 value.
 * The CRC7 is left-aligned in the byte (the lsbit is always 0), as that
 * makes the computation easier, and all callers want it in that form.
 *
 */
u8 crc7_be(u8 crc, const u8 *buffer, size_t len)
{
	while (len--)
		crc = crc7_be_byte(crc, *buffer++);
	return crc;
}
EXPORT_SYMBOL(crc7_be);

MODULE_DESCRIPTION("CRC7 calculations");
MODULE_LICENSE("GPL");
ss="hl com"> * * Written by Thayne Harbaugh * Based on work by Dan Hollis <goemon at anime dot net> and others. * http://www.anime.net/~goemon/linux-ecc/ * * Datasheet: * http://www.intel.com/content/www/us/en/chipsets/e7501-chipset-memory-controller-hub-datasheet.html * * 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/module.h> #include <linux/init.h> #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/edac.h> #include "edac_core.h" #define E7XXX_REVISION " Ver: 2.0.2" #define EDAC_MOD_STR "e7xxx_edac" #define e7xxx_printk(level, fmt, arg...) \ edac_printk(level, "e7xxx", fmt, ##arg) #define e7xxx_mc_printk(mci, level, fmt, arg...) \ edac_mc_chipset_printk(mci, level, "e7xxx", fmt, ##arg) #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 /* 2 channels, 4 dimms/channel */ /* 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 struct edac_pci_ctl_info *e7xxx_pci; 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) { edac_dbg(3, "\n"); 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; edac_dbg(3, "\n"); if ((page < pvt->tolm) || ((page >= 0x100000) && (page < pvt->remapbase))) return page; remap = (page - pvt->tolm) + pvt->remapbase; if (remap < pvt->remaplimit) return remap; e7xxx_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; edac_dbg(3, "\n"); /* 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_error(HW_EVENT_ERR_CORRECTED, mci, 1, page, 0, syndrome, row, channel, -1, "e7xxx CE", ""); } static void process_ce_no_info(struct mem_ctl_info *mci) { edac_dbg(3, "\n"); edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, -1, -1, -1, "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; edac_dbg(3, "\n"); /* 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_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, block_page, 0, 0, row, -1, -1, "e7xxx UE", ""); } static void process_ue_no_info(struct mem_ctl_info *mci) { edac_dbg(3, "\n"); edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, -1, -1, -1, "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; edac_dbg(3, "\n"); e7xxx_get_error_info(mci, &info); e7xxx_process_error_info(mci, &info, 1); } /* Return 1 if dual channel mode is active. Else return 0. */ static inline int dual_channel_active(u32 drc, int dev_idx) { return (dev_idx == E7501) ? ((drc >> 22) & 0x1) : 1; } /* Return DRB granularity (0=32mb, 1=64mb). */ static inline int drb_granularity(u32 drc, int dev_idx) { /* only e7501 can be single channel */ return (dev_idx == E7501) ? ((drc >> 18) & 0x3) : 1; } static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, int dev_idx, u32 drc) { unsigned long last_cumul_size; int index, j; u8 value; u32 dra, cumul_size, nr_pages; int drc_chan, drc_drbg, drc_ddim, mem_dev; struct csrow_info *csrow; struct dimm_info *dimm; enum edac_type edac_mode; pci_read_config_dword(pdev, E7XXX_DRA, &dra); drc_chan = dual_channel_active(drc, dev_idx); drc_drbg = drb_granularity(drc, dev_idx); drc_ddim = (drc >> 20) & 0x3; last_cumul_size = 0; /* 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 (index = 0; index < mci->nr_csrows; index++) { /* mem_dev 0=x8, 1=x4 */