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 */ |