Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

EDAC, altera: Add Altera L2 cache and OCRAM support

Add L2 Cache and On-Chip RAM EDAC support for the Altera SoCs. The SDRAM
controller is using the Memory Controller model.

Each type of ECC is individually configurable.

Signed-off-by: Thor Thayer <tthayer@opensource.altera.com>
Cc: devicetree@vger.kernel.org
Cc: dinguyen@opensource.altera.com
Cc: galak@codeaurora.org
Cc: grant.likely@linaro.org
Cc: ijc+devicetree@hellion.org.uk
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux@arm.linux.org.uk
Cc: linux-doc@vger.kernel.org
Cc: linux-edac <linux-edac@vger.kernel.org>
Cc: mark.rutland@arm.com
Cc: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Cc: pawel.moll@arm.com
Cc: robh+dt@kernel.org
Link: http://lkml.kernel.org/r/1455132384-17108-1-git-send-email-tthayer@opensource.altera.com
Signed-off-by: Borislav Petkov <bp@suse.de>

authored by

Thor Thayer and committed by
Borislav Petkov
c3eea194 9bf4f005

+512 -8
+21 -5
drivers/edac/Kconfig
··· 367 367 Support for error detection and correction on the 368 368 Cavium Octeon family of SOCs. 369 369 370 - config EDAC_ALTERA_MC 371 - bool "Altera SDRAM Memory Controller EDAC" 370 + config EDAC_ALTERA 371 + bool "Altera SOCFPGA ECC" 372 372 depends on EDAC_MM_EDAC=y && ARCH_SOCFPGA 373 373 help 374 374 Support for error detection and correction on the 375 - Altera SDRAM memory controller. Note that the 376 - preloader must initialize the SDRAM before loading 377 - the kernel. 375 + Altera SOCs. This must be selected for SDRAM ECC. 376 + Note that the preloader must initialize the SDRAM 377 + before loading the kernel. 378 + 379 + config EDAC_ALTERA_L2C 380 + bool "Altera L2 Cache ECC" 381 + depends on EDAC_ALTERA=y 382 + select CACHE_L2X0 383 + help 384 + Support for error detection and correction on the 385 + Altera L2 cache Memory for Altera SoCs. This option 386 + requires L2 cache so it will force that selection. 387 + 388 + config EDAC_ALTERA_OCRAM 389 + bool "Altera On-Chip RAM ECC" 390 + depends on EDAC_ALTERA=y && SRAM && GENERIC_ALLOCATOR 391 + help 392 + Support for error detection and correction on the 393 + Altera On-Chip RAM Memory for Altera SoCs. 378 394 379 395 config EDAC_SYNOPSYS 380 396 tristate "Synopsys DDR Memory Controller"
+1 -1
drivers/edac/Makefile
··· 67 67 obj-$(CONFIG_EDAC_OCTEON_LMC) += octeon_edac-lmc.o 68 68 obj-$(CONFIG_EDAC_OCTEON_PCI) += octeon_edac-pci.o 69 69 70 - obj-$(CONFIG_EDAC_ALTERA_MC) += altera_edac.o 70 + obj-$(CONFIG_EDAC_ALTERA) += altera_edac.o 71 71 obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o 72 72 obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o
+490 -2
drivers/edac/altera_edac.c
··· 1 1 /* 2 - * Copyright Altera Corporation (C) 2014-2015. All rights reserved. 2 + * Copyright Altera Corporation (C) 2014-2016. All rights reserved. 3 3 * Copyright 2011-2012 Calxeda, Inc. 4 4 * 5 5 * This program is free software; you can redistribute it and/or modify it ··· 17 17 * Adapted from the highbank_mc_edac driver. 18 18 */ 19 19 20 + #include <asm/cacheflush.h> 20 21 #include <linux/ctype.h> 21 22 #include <linux/edac.h> 23 + #include <linux/genalloc.h> 22 24 #include <linux/interrupt.h> 23 25 #include <linux/kernel.h> 24 26 #include <linux/mfd/syscon.h> ··· 36 34 37 35 #define EDAC_MOD_STR "altera_edac" 38 36 #define EDAC_VERSION "1" 37 + #define EDAC_DEVICE "Altera" 39 38 40 39 static const struct altr_sdram_prv_data c5_data = { 41 40 .ecc_ctrl_offset = CV_CTLCFG_OFST, ··· 77 74 .ce_set_mask = A10_DIAGINT_TSERRA_MASK, 78 75 .ue_set_mask = A10_DIAGINT_TDERRA_MASK, 79 76 }; 77 + 78 + /************************** EDAC Device Defines **************************/ 79 + 80 + /* OCRAM ECC Management Group Defines */ 81 + #define ALTR_MAN_GRP_OCRAM_ECC_OFFSET 0x04 82 + #define ALTR_OCR_ECC_EN BIT(0) 83 + #define ALTR_OCR_ECC_INJS BIT(1) 84 + #define ALTR_OCR_ECC_INJD BIT(2) 85 + #define ALTR_OCR_ECC_SERR BIT(3) 86 + #define ALTR_OCR_ECC_DERR BIT(4) 87 + 88 + /* L2 ECC Management Group Defines */ 89 + #define ALTR_MAN_GRP_L2_ECC_OFFSET 0x00 90 + #define ALTR_L2_ECC_EN BIT(0) 91 + #define ALTR_L2_ECC_INJS BIT(1) 92 + #define ALTR_L2_ECC_INJD BIT(2) 93 + 94 + #define ALTR_UE_TRIGGER_CHAR 'U' /* Trigger for UE */ 95 + #define ALTR_TRIGGER_READ_WRD_CNT 32 /* Line size x 4 */ 96 + #define ALTR_TRIG_OCRAM_BYTE_SIZE 128 /* Line size x 4 */ 97 + #define ALTR_TRIG_L2C_BYTE_SIZE 4096 /* Full Page */ 98 + 99 + /*********************** EDAC Memory Controller Functions ****************/ 100 + 101 + /* The SDRAM controller uses the EDAC Memory Controller framework. */ 80 102 81 103 static irqreturn_t altr_sdram_mc_err_handler(int irq, void *dev_id) 82 104 { ··· 532 504 533 505 module_platform_driver(altr_sdram_edac_driver); 534 506 507 + /************************* EDAC Parent Probe *************************/ 508 + 509 + static const struct of_device_id altr_edac_device_of_match[]; 510 + 511 + static const struct of_device_id altr_edac_of_match[] = { 512 + { .compatible = "altr,socfpga-ecc-manager" }, 513 + {}, 514 + }; 515 + MODULE_DEVICE_TABLE(of, altr_edac_of_match); 516 + 517 + static int altr_edac_probe(struct platform_device *pdev) 518 + { 519 + of_platform_populate(pdev->dev.of_node, altr_edac_device_of_match, 520 + NULL, &pdev->dev); 521 + return 0; 522 + } 523 + 524 + static struct platform_driver altr_edac_driver = { 525 + .probe = altr_edac_probe, 526 + .driver = { 527 + .name = "socfpga_ecc_manager", 528 + .of_match_table = altr_edac_of_match, 529 + }, 530 + }; 531 + module_platform_driver(altr_edac_driver); 532 + 533 + /************************* EDAC Device Functions *************************/ 534 + 535 + /* 536 + * EDAC Device Functions (shared between various IPs). 537 + * The discrete memories use the EDAC Device framework. The probe 538 + * and error handling functions are very similar between memories 539 + * so they are shared. The memory allocation and freeing for EDAC 540 + * trigger testing are different for each memory. 541 + */ 542 + 543 + const struct edac_device_prv_data ocramecc_data; 544 + const struct edac_device_prv_data l2ecc_data; 545 + 546 + struct edac_device_prv_data { 547 + int (*setup)(struct platform_device *pdev, void __iomem *base); 548 + int ce_clear_mask; 549 + int ue_clear_mask; 550 + char dbgfs_name[20]; 551 + void * (*alloc_mem)(size_t size, void **other); 552 + void (*free_mem)(void *p, size_t size, void *other); 553 + int ecc_enable_mask; 554 + int ce_set_mask; 555 + int ue_set_mask; 556 + int trig_alloc_sz; 557 + }; 558 + 559 + struct altr_edac_device_dev { 560 + void __iomem *base; 561 + int sb_irq; 562 + int db_irq; 563 + const struct edac_device_prv_data *data; 564 + struct dentry *debugfs_dir; 565 + char *edac_dev_name; 566 + }; 567 + 568 + static irqreturn_t altr_edac_device_handler(int irq, void *dev_id) 569 + { 570 + irqreturn_t ret_value = IRQ_NONE; 571 + struct edac_device_ctl_info *dci = dev_id; 572 + struct altr_edac_device_dev *drvdata = dci->pvt_info; 573 + const struct edac_device_prv_data *priv = drvdata->data; 574 + 575 + if (irq == drvdata->sb_irq) { 576 + if (priv->ce_clear_mask) 577 + writel(priv->ce_clear_mask, drvdata->base); 578 + edac_device_handle_ce(dci, 0, 0, drvdata->edac_dev_name); 579 + ret_value = IRQ_HANDLED; 580 + } else if (irq == drvdata->db_irq) { 581 + if (priv->ue_clear_mask) 582 + writel(priv->ue_clear_mask, drvdata->base); 583 + edac_device_handle_ue(dci, 0, 0, drvdata->edac_dev_name); 584 + panic("\nEDAC:ECC_DEVICE[Uncorrectable errors]\n"); 585 + ret_value = IRQ_HANDLED; 586 + } else { 587 + WARN_ON(1); 588 + } 589 + 590 + return ret_value; 591 + } 592 + 593 + static ssize_t altr_edac_device_trig(struct file *file, 594 + const char __user *user_buf, 595 + size_t count, loff_t *ppos) 596 + 597 + { 598 + u32 *ptemp, i, error_mask; 599 + int result = 0; 600 + u8 trig_type; 601 + unsigned long flags; 602 + struct edac_device_ctl_info *edac_dci = file->private_data; 603 + struct altr_edac_device_dev *drvdata = edac_dci->pvt_info; 604 + const struct edac_device_prv_data *priv = drvdata->data; 605 + void *generic_ptr = edac_dci->dev; 606 + 607 + if (!user_buf || get_user(trig_type, user_buf)) 608 + return -EFAULT; 609 + 610 + if (!priv->alloc_mem) 611 + return -ENOMEM; 612 + 613 + /* 614 + * Note that generic_ptr is initialized to the device * but in 615 + * some alloc_functions, this is overridden and returns data. 616 + */ 617 + ptemp = priv->alloc_mem(priv->trig_alloc_sz, &generic_ptr); 618 + if (!ptemp) { 619 + edac_printk(KERN_ERR, EDAC_DEVICE, 620 + "Inject: Buffer Allocation error\n"); 621 + return -ENOMEM; 622 + } 623 + 624 + if (trig_type == ALTR_UE_TRIGGER_CHAR) 625 + error_mask = priv->ue_set_mask; 626 + else 627 + error_mask = priv->ce_set_mask; 628 + 629 + edac_printk(KERN_ALERT, EDAC_DEVICE, 630 + "Trigger Error Mask (0x%X)\n", error_mask); 631 + 632 + local_irq_save(flags); 633 + /* write ECC corrupted data out. */ 634 + for (i = 0; i < (priv->trig_alloc_sz / sizeof(*ptemp)); i++) { 635 + /* Read data so we're in the correct state */ 636 + rmb(); 637 + if (ACCESS_ONCE(ptemp[i])) 638 + result = -1; 639 + /* Toggle Error bit (it is latched), leave ECC enabled */ 640 + writel(error_mask, drvdata->base); 641 + writel(priv->ecc_enable_mask, drvdata->base); 642 + ptemp[i] = i; 643 + } 644 + /* Ensure it has been written out */ 645 + wmb(); 646 + local_irq_restore(flags); 647 + 648 + if (result) 649 + edac_printk(KERN_ERR, EDAC_DEVICE, "Mem Not Cleared\n"); 650 + 651 + /* Read out written data. ECC error caused here */ 652 + for (i = 0; i < ALTR_TRIGGER_READ_WRD_CNT; i++) 653 + if (ACCESS_ONCE(ptemp[i]) != i) 654 + edac_printk(KERN_ERR, EDAC_DEVICE, 655 + "Read doesn't match written data\n"); 656 + 657 + if (priv->free_mem) 658 + priv->free_mem(ptemp, priv->trig_alloc_sz, generic_ptr); 659 + 660 + return count; 661 + } 662 + 663 + static const struct file_operations altr_edac_device_inject_fops = { 664 + .open = simple_open, 665 + .write = altr_edac_device_trig, 666 + .llseek = generic_file_llseek, 667 + }; 668 + 669 + static void altr_create_edacdev_dbgfs(struct edac_device_ctl_info *edac_dci, 670 + const struct edac_device_prv_data *priv) 671 + { 672 + struct altr_edac_device_dev *drvdata = edac_dci->pvt_info; 673 + 674 + if (!IS_ENABLED(CONFIG_EDAC_DEBUG)) 675 + return; 676 + 677 + drvdata->debugfs_dir = edac_debugfs_create_dir(drvdata->edac_dev_name); 678 + if (!drvdata->debugfs_dir) 679 + return; 680 + 681 + if (!edac_debugfs_create_file(priv->dbgfs_name, S_IWUSR, 682 + drvdata->debugfs_dir, edac_dci, 683 + &altr_edac_device_inject_fops)) 684 + debugfs_remove_recursive(drvdata->debugfs_dir); 685 + } 686 + 687 + static const struct of_device_id altr_edac_device_of_match[] = { 688 + #ifdef CONFIG_EDAC_ALTERA_L2C 689 + { .compatible = "altr,socfpga-l2-ecc", .data = (void *)&l2ecc_data }, 690 + #endif 691 + #ifdef CONFIG_EDAC_ALTERA_OCRAM 692 + { .compatible = "altr,socfpga-ocram-ecc", 693 + .data = (void *)&ocramecc_data }, 694 + #endif 695 + {}, 696 + }; 697 + MODULE_DEVICE_TABLE(of, altr_edac_device_of_match); 698 + 699 + /* 700 + * altr_edac_device_probe() 701 + * This is a generic EDAC device driver that will support 702 + * various Altera memory devices such as the L2 cache ECC and 703 + * OCRAM ECC as well as the memories for other peripherals. 704 + * Module specific initialization is done by passing the 705 + * function index in the device tree. 706 + */ 707 + static int altr_edac_device_probe(struct platform_device *pdev) 708 + { 709 + struct edac_device_ctl_info *dci; 710 + struct altr_edac_device_dev *drvdata; 711 + struct resource *r; 712 + int res = 0; 713 + struct device_node *np = pdev->dev.of_node; 714 + char *ecc_name = (char *)np->name; 715 + static int dev_instance; 716 + 717 + if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) { 718 + edac_printk(KERN_ERR, EDAC_DEVICE, 719 + "Unable to open devm\n"); 720 + return -ENOMEM; 721 + } 722 + 723 + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 724 + if (!r) { 725 + edac_printk(KERN_ERR, EDAC_DEVICE, 726 + "Unable to get mem resource\n"); 727 + res = -ENODEV; 728 + goto fail; 729 + } 730 + 731 + if (!devm_request_mem_region(&pdev->dev, r->start, resource_size(r), 732 + dev_name(&pdev->dev))) { 733 + edac_printk(KERN_ERR, EDAC_DEVICE, 734 + "%s:Error requesting mem region\n", ecc_name); 735 + res = -EBUSY; 736 + goto fail; 737 + } 738 + 739 + dci = edac_device_alloc_ctl_info(sizeof(*drvdata), ecc_name, 740 + 1, ecc_name, 1, 0, NULL, 0, 741 + dev_instance++); 742 + 743 + if (!dci) { 744 + edac_printk(KERN_ERR, EDAC_DEVICE, 745 + "%s: Unable to allocate EDAC device\n", ecc_name); 746 + res = -ENOMEM; 747 + goto fail; 748 + } 749 + 750 + drvdata = dci->pvt_info; 751 + dci->dev = &pdev->dev; 752 + platform_set_drvdata(pdev, dci); 753 + drvdata->edac_dev_name = ecc_name; 754 + 755 + drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r)); 756 + if (!drvdata->base) 757 + goto fail1; 758 + 759 + /* Get driver specific data for this EDAC device */ 760 + drvdata->data = of_match_node(altr_edac_device_of_match, np)->data; 761 + 762 + /* Check specific dependencies for the module */ 763 + if (drvdata->data->setup) { 764 + res = drvdata->data->setup(pdev, drvdata->base); 765 + if (res) 766 + goto fail1; 767 + } 768 + 769 + drvdata->sb_irq = platform_get_irq(pdev, 0); 770 + res = devm_request_irq(&pdev->dev, drvdata->sb_irq, 771 + altr_edac_device_handler, 772 + 0, dev_name(&pdev->dev), dci); 773 + if (res) 774 + goto fail1; 775 + 776 + drvdata->db_irq = platform_get_irq(pdev, 1); 777 + res = devm_request_irq(&pdev->dev, drvdata->db_irq, 778 + altr_edac_device_handler, 779 + 0, dev_name(&pdev->dev), dci); 780 + if (res) 781 + goto fail1; 782 + 783 + dci->mod_name = "Altera ECC Manager"; 784 + dci->dev_name = drvdata->edac_dev_name; 785 + 786 + res = edac_device_add_device(dci); 787 + if (res) 788 + goto fail1; 789 + 790 + altr_create_edacdev_dbgfs(dci, drvdata->data); 791 + 792 + devres_close_group(&pdev->dev, NULL); 793 + 794 + return 0; 795 + 796 + fail1: 797 + edac_device_free_ctl_info(dci); 798 + fail: 799 + devres_release_group(&pdev->dev, NULL); 800 + edac_printk(KERN_ERR, EDAC_DEVICE, 801 + "%s:Error setting up EDAC device: %d\n", ecc_name, res); 802 + 803 + return res; 804 + } 805 + 806 + static int altr_edac_device_remove(struct platform_device *pdev) 807 + { 808 + struct edac_device_ctl_info *dci = platform_get_drvdata(pdev); 809 + struct altr_edac_device_dev *drvdata = dci->pvt_info; 810 + 811 + debugfs_remove_recursive(drvdata->debugfs_dir); 812 + edac_device_del_device(&pdev->dev); 813 + edac_device_free_ctl_info(dci); 814 + 815 + return 0; 816 + } 817 + 818 + static struct platform_driver altr_edac_device_driver = { 819 + .probe = altr_edac_device_probe, 820 + .remove = altr_edac_device_remove, 821 + .driver = { 822 + .name = "altr_edac_device", 823 + .of_match_table = altr_edac_device_of_match, 824 + }, 825 + }; 826 + module_platform_driver(altr_edac_device_driver); 827 + 828 + /*********************** OCRAM EDAC Device Functions *********************/ 829 + 830 + #ifdef CONFIG_EDAC_ALTERA_OCRAM 831 + 832 + static void *ocram_alloc_mem(size_t size, void **other) 833 + { 834 + struct device_node *np; 835 + struct gen_pool *gp; 836 + void *sram_addr; 837 + 838 + np = of_find_compatible_node(NULL, NULL, "altr,socfpga-ocram-ecc"); 839 + if (!np) 840 + return NULL; 841 + 842 + gp = of_gen_pool_get(np, "iram", 0); 843 + of_node_put(np); 844 + if (!gp) 845 + return NULL; 846 + 847 + sram_addr = (void *)gen_pool_alloc(gp, size); 848 + if (!sram_addr) 849 + return NULL; 850 + 851 + memset(sram_addr, 0, size); 852 + /* Ensure data is written out */ 853 + wmb(); 854 + 855 + /* Remember this handle for freeing later */ 856 + *other = gp; 857 + 858 + return sram_addr; 859 + } 860 + 861 + static void ocram_free_mem(void *p, size_t size, void *other) 862 + { 863 + gen_pool_free((struct gen_pool *)other, (u32)p, size); 864 + } 865 + 866 + /* 867 + * altr_ocram_check_deps() 868 + * Test for OCRAM cache ECC dependencies upon entry because 869 + * platform specific startup should have initialized the 870 + * On-Chip RAM memory and enabled the ECC. 871 + * Can't turn on ECC here because accessing un-initialized 872 + * memory will cause CE/UE errors possibly causing an ABORT. 873 + */ 874 + static int altr_ocram_check_deps(struct platform_device *pdev, 875 + void __iomem *base) 876 + { 877 + if (readl(base) & ALTR_OCR_ECC_EN) 878 + return 0; 879 + 880 + edac_printk(KERN_ERR, EDAC_DEVICE, 881 + "OCRAM: No ECC present or ECC disabled.\n"); 882 + return -ENODEV; 883 + } 884 + 885 + const struct edac_device_prv_data ocramecc_data = { 886 + .setup = altr_ocram_check_deps, 887 + .ce_clear_mask = (ALTR_OCR_ECC_EN | ALTR_OCR_ECC_SERR), 888 + .ue_clear_mask = (ALTR_OCR_ECC_EN | ALTR_OCR_ECC_DERR), 889 + .dbgfs_name = "altr_ocram_trigger", 890 + .alloc_mem = ocram_alloc_mem, 891 + .free_mem = ocram_free_mem, 892 + .ecc_enable_mask = ALTR_OCR_ECC_EN, 893 + .ce_set_mask = (ALTR_OCR_ECC_EN | ALTR_OCR_ECC_INJS), 894 + .ue_set_mask = (ALTR_OCR_ECC_EN | ALTR_OCR_ECC_INJD), 895 + .trig_alloc_sz = ALTR_TRIG_OCRAM_BYTE_SIZE, 896 + }; 897 + 898 + #endif /* CONFIG_EDAC_ALTERA_OCRAM */ 899 + 900 + /********************* L2 Cache EDAC Device Functions ********************/ 901 + 902 + #ifdef CONFIG_EDAC_ALTERA_L2C 903 + 904 + static void *l2_alloc_mem(size_t size, void **other) 905 + { 906 + struct device *dev = *other; 907 + void *ptemp = devm_kzalloc(dev, size, GFP_KERNEL); 908 + 909 + if (!ptemp) 910 + return NULL; 911 + 912 + /* Make sure everything is written out */ 913 + wmb(); 914 + 915 + /* 916 + * Clean all cache levels up to LoC (includes L2) 917 + * This ensures the corrupted data is written into 918 + * L2 cache for readback test (which causes ECC error). 919 + */ 920 + flush_cache_all(); 921 + 922 + return ptemp; 923 + } 924 + 925 + static void l2_free_mem(void *p, size_t size, void *other) 926 + { 927 + struct device *dev = other; 928 + 929 + if (dev && p) 930 + devm_kfree(dev, p); 931 + } 932 + 933 + /* 934 + * altr_l2_check_deps() 935 + * Test for L2 cache ECC dependencies upon entry because 936 + * platform specific startup should have initialized the L2 937 + * memory and enabled the ECC. 938 + * Bail if ECC is not enabled. 939 + * Note that L2 Cache Enable is forced at build time. 940 + */ 941 + static int altr_l2_check_deps(struct platform_device *pdev, 942 + void __iomem *base) 943 + { 944 + if (readl(base) & ALTR_L2_ECC_EN) 945 + return 0; 946 + 947 + edac_printk(KERN_ERR, EDAC_DEVICE, 948 + "L2: No ECC present, or ECC disabled\n"); 949 + return -ENODEV; 950 + } 951 + 952 + const struct edac_device_prv_data l2ecc_data = { 953 + .setup = altr_l2_check_deps, 954 + .ce_clear_mask = 0, 955 + .ue_clear_mask = 0, 956 + .dbgfs_name = "altr_l2_trigger", 957 + .alloc_mem = l2_alloc_mem, 958 + .free_mem = l2_free_mem, 959 + .ecc_enable_mask = ALTR_L2_ECC_EN, 960 + .ce_set_mask = (ALTR_L2_ECC_EN | ALTR_L2_ECC_INJS), 961 + .ue_set_mask = (ALTR_L2_ECC_EN | ALTR_L2_ECC_INJD), 962 + .trig_alloc_sz = ALTR_TRIG_L2C_BYTE_SIZE, 963 + }; 964 + 965 + #endif /* CONFIG_EDAC_ALTERA_L2C */ 966 + 535 967 MODULE_LICENSE("GPL v2"); 536 968 MODULE_AUTHOR("Thor Thayer"); 537 - MODULE_DESCRIPTION("EDAC Driver for Altera SDRAM Controller"); 969 + MODULE_DESCRIPTION("EDAC Driver for Altera Memories");