diff options
Diffstat (limited to 'drivers/edac/mpc85xx_edac.c')
| -rw-r--r-- | drivers/edac/mpc85xx_edac.c | 163 |
1 files changed, 151 insertions, 12 deletions
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index ecd5928d7110..94cac0aacea3 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c | |||
| @@ -239,16 +239,15 @@ static int __devinit mpc85xx_pci_err_probe(struct of_device *op, | |||
| 239 | /* we only need the error registers */ | 239 | /* we only need the error registers */ |
| 240 | r.start += 0xe00; | 240 | r.start += 0xe00; |
| 241 | 241 | ||
| 242 | if (!devm_request_mem_region(&op->dev, r.start, | 242 | if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), |
| 243 | r.end - r.start + 1, pdata->name)) { | 243 | pdata->name)) { |
| 244 | printk(KERN_ERR "%s: Error while requesting mem region\n", | 244 | printk(KERN_ERR "%s: Error while requesting mem region\n", |
| 245 | __func__); | 245 | __func__); |
| 246 | res = -EBUSY; | 246 | res = -EBUSY; |
| 247 | goto err; | 247 | goto err; |
| 248 | } | 248 | } |
| 249 | 249 | ||
| 250 | pdata->pci_vbase = devm_ioremap(&op->dev, r.start, | 250 | pdata->pci_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); |
| 251 | r.end - r.start + 1); | ||
| 252 | if (!pdata->pci_vbase) { | 251 | if (!pdata->pci_vbase) { |
| 253 | printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__); | 252 | printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__); |
| 254 | res = -ENOMEM; | 253 | res = -ENOMEM; |
| @@ -668,15 +667,125 @@ static struct of_platform_driver mpc85xx_l2_err_driver = { | |||
| 668 | 667 | ||
| 669 | /**************************** MC Err device ***************************/ | 668 | /**************************** MC Err device ***************************/ |
| 670 | 669 | ||
| 670 | /* | ||
| 671 | * Taken from table 8-55 in the MPC8641 User's Manual and/or 9-61 in the | ||
| 672 | * MPC8572 User's Manual. Each line represents a syndrome bit column as a | ||
| 673 | * 64-bit value, but split into an upper and lower 32-bit chunk. The labels | ||
| 674 | * below correspond to Freescale's manuals. | ||
| 675 | */ | ||
| 676 | static unsigned int ecc_table[16] = { | ||
| 677 | /* MSB LSB */ | ||
| 678 | /* [0:31] [32:63] */ | ||
| 679 | 0xf00fe11e, 0xc33c0ff7, /* Syndrome bit 7 */ | ||
| 680 | 0x00ff00ff, 0x00fff0ff, | ||
| 681 | 0x0f0f0f0f, 0x0f0fff00, | ||
| 682 | 0x11113333, 0x7777000f, | ||
| 683 | 0x22224444, 0x8888222f, | ||
| 684 | 0x44448888, 0xffff4441, | ||
| 685 | 0x8888ffff, 0x11118882, | ||
| 686 | 0xffff1111, 0x22221114, /* Syndrome bit 0 */ | ||
| 687 | }; | ||
| 688 | |||
| 689 | /* | ||
| 690 | * Calculate the correct ECC value for a 64-bit value specified by high:low | ||
| 691 | */ | ||
| 692 | static u8 calculate_ecc(u32 high, u32 low) | ||
| 693 | { | ||
| 694 | u32 mask_low; | ||
| 695 | u32 mask_high; | ||
| 696 | int bit_cnt; | ||
| 697 | u8 ecc = 0; | ||
| 698 | int i; | ||
| 699 | int j; | ||
| 700 | |||
| 701 | for (i = 0; i < 8; i++) { | ||
| 702 | mask_high = ecc_table[i * 2]; | ||
| 703 | mask_low = ecc_table[i * 2 + 1]; | ||
| 704 | bit_cnt = 0; | ||
| 705 | |||
| 706 | for (j = 0; j < 32; j++) { | ||
| 707 | if ((mask_high >> j) & 1) | ||
| 708 | bit_cnt ^= (high >> j) & 1; | ||
| 709 | if ((mask_low >> j) & 1) | ||
| 710 | bit_cnt ^= (low >> j) & 1; | ||
| 711 | } | ||
| 712 | |||
| 713 | ecc |= bit_cnt << i; | ||
| 714 | } | ||
| 715 | |||
| 716 | return ecc; | ||
| 717 | } | ||
| 718 | |||
| 719 | /* | ||
| 720 | * Create the syndrome code which is generated if the data line specified by | ||
| 721 | * 'bit' failed. Eg generate an 8-bit codes seen in Table 8-55 in the MPC8641 | ||
| 722 | * User's Manual and 9-61 in the MPC8572 User's Manual. | ||
| 723 | */ | ||
| 724 | static u8 syndrome_from_bit(unsigned int bit) { | ||
| 725 | int i; | ||
| 726 | u8 syndrome = 0; | ||
| 727 | |||
| 728 | /* | ||
| 729 | * Cycle through the upper or lower 32-bit portion of each value in | ||
| 730 | * ecc_table depending on if 'bit' is in the upper or lower half of | ||
| 731 | * 64-bit data. | ||
| 732 | */ | ||
| 733 | for (i = bit < 32; i < 16; i += 2) | ||
| 734 | syndrome |= ((ecc_table[i] >> (bit % 32)) & 1) << (i / 2); | ||
| 735 | |||
| 736 | return syndrome; | ||
| 737 | } | ||
| 738 | |||
| 739 | /* | ||
| 740 | * Decode data and ecc syndrome to determine what went wrong | ||
| 741 | * Note: This can only decode single-bit errors | ||
| 742 | */ | ||
| 743 | static void sbe_ecc_decode(u32 cap_high, u32 cap_low, u32 cap_ecc, | ||
| 744 | int *bad_data_bit, int *bad_ecc_bit) | ||
| 745 | { | ||
| 746 | int i; | ||
| 747 | u8 syndrome; | ||
| 748 | |||
| 749 | *bad_data_bit = -1; | ||
| 750 | *bad_ecc_bit = -1; | ||
| 751 | |||
| 752 | /* | ||
| 753 | * Calculate the ECC of the captured data and XOR it with the captured | ||
| 754 | * ECC to find an ECC syndrome value we can search for | ||
| 755 | */ | ||
| 756 | syndrome = calculate_ecc(cap_high, cap_low) ^ cap_ecc; | ||
| 757 | |||
| 758 | /* Check if a data line is stuck... */ | ||
| 759 | for (i = 0; i < 64; i++) { | ||
| 760 | if (syndrome == syndrome_from_bit(i)) { | ||
| 761 | *bad_data_bit = i; | ||
| 762 | return; | ||
| 763 | } | ||
| 764 | } | ||
| 765 | |||
| 766 | /* If data is correct, check ECC bits for errors... */ | ||
| 767 | for (i = 0; i < 8; i++) { | ||
| 768 | if ((syndrome >> i) & 0x1) { | ||
| 769 | *bad_ecc_bit = i; | ||
| 770 | return; | ||
| 771 | } | ||
| 772 | } | ||
| 773 | } | ||
| 774 | |||
| 671 | static void mpc85xx_mc_check(struct mem_ctl_info *mci) | 775 | static void mpc85xx_mc_check(struct mem_ctl_info *mci) |
| 672 | { | 776 | { |
| 673 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | 777 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; |
| 674 | struct csrow_info *csrow; | 778 | struct csrow_info *csrow; |
| 779 | u32 bus_width; | ||
| 675 | u32 err_detect; | 780 | u32 err_detect; |
| 676 | u32 syndrome; | 781 | u32 syndrome; |
| 677 | u32 err_addr; | 782 | u32 err_addr; |
| 678 | u32 pfn; | 783 | u32 pfn; |
| 679 | int row_index; | 784 | int row_index; |
| 785 | u32 cap_high; | ||
| 786 | u32 cap_low; | ||
| 787 | int bad_data_bit; | ||
| 788 | int bad_ecc_bit; | ||
| 680 | 789 | ||
| 681 | err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT); | 790 | err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT); |
| 682 | if (!err_detect) | 791 | if (!err_detect) |
| @@ -692,6 +801,15 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci) | |||
| 692 | } | 801 | } |
| 693 | 802 | ||
| 694 | syndrome = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ECC); | 803 | syndrome = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ECC); |
| 804 | |||
| 805 | /* Mask off appropriate bits of syndrome based on bus width */ | ||
| 806 | bus_width = (in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG) & | ||
| 807 | DSC_DBW_MASK) ? 32 : 64; | ||
| 808 | if (bus_width == 64) | ||
| 809 | syndrome &= 0xff; | ||
| 810 | else | ||
| 811 | syndrome &= 0xffff; | ||
| 812 | |||
| 695 | err_addr = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ADDRESS); | 813 | err_addr = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ADDRESS); |
| 696 | pfn = err_addr >> PAGE_SHIFT; | 814 | pfn = err_addr >> PAGE_SHIFT; |
| 697 | 815 | ||
| @@ -701,14 +819,35 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci) | |||
| 701 | break; | 819 | break; |
| 702 | } | 820 | } |
| 703 | 821 | ||
| 704 | mpc85xx_mc_printk(mci, KERN_ERR, "Capture Data High: %#8.8x\n", | 822 | cap_high = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_HI); |
| 705 | in_be32(pdata->mc_vbase + | 823 | cap_low = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_LO); |
| 706 | MPC85XX_MC_CAPTURE_DATA_HI)); | 824 | |
| 707 | mpc85xx_mc_printk(mci, KERN_ERR, "Capture Data Low: %#8.8x\n", | 825 | /* |
| 708 | in_be32(pdata->mc_vbase + | 826 | * Analyze single-bit errors on 64-bit wide buses |
| 709 | MPC85XX_MC_CAPTURE_DATA_LO)); | 827 | * TODO: Add support for 32-bit wide buses |
| 710 | mpc85xx_mc_printk(mci, KERN_ERR, "syndrome: %#8.8x\n", syndrome); | 828 | */ |
| 711 | mpc85xx_mc_printk(mci, KERN_ERR, "err addr: %#8.8x\n", err_addr); | 829 | if ((err_detect & DDR_EDE_SBE) && (bus_width == 64)) { |
| 830 | sbe_ecc_decode(cap_high, cap_low, syndrome, | ||
| 831 | &bad_data_bit, &bad_ecc_bit); | ||
| 832 | |||
| 833 | if (bad_data_bit != -1) | ||
| 834 | mpc85xx_mc_printk(mci, KERN_ERR, | ||
| 835 | "Faulty Data bit: %d\n", bad_data_bit); | ||
| 836 | if (bad_ecc_bit != -1) | ||
| 837 | mpc85xx_mc_printk(mci, KERN_ERR, | ||
| 838 | "Faulty ECC bit: %d\n", bad_ecc_bit); | ||
| 839 | |||
| 840 | mpc85xx_mc_printk(mci, KERN_ERR, | ||
| 841 | "Expected Data / ECC:\t%#8.8x_%08x / %#2.2x\n", | ||
| 842 | cap_high ^ (1 << (bad_data_bit - 32)), | ||
| 843 | cap_low ^ (1 << bad_data_bit), | ||
| 844 | syndrome ^ (1 << bad_ecc_bit)); | ||
| 845 | } | ||
| 846 | |||
| 847 | mpc85xx_mc_printk(mci, KERN_ERR, | ||
| 848 | "Captured Data / ECC:\t%#8.8x_%08x / %#2.2x\n", | ||
| 849 | cap_high, cap_low, syndrome); | ||
| 850 | mpc85xx_mc_printk(mci, KERN_ERR, "Err addr: %#8.8x\n", err_addr); | ||
| 712 | mpc85xx_mc_printk(mci, KERN_ERR, "PFN: %#8.8x\n", pfn); | 851 | mpc85xx_mc_printk(mci, KERN_ERR, "PFN: %#8.8x\n", pfn); |
| 713 | 852 | ||
| 714 | /* we are out of range */ | 853 | /* we are out of range */ |
