Lines Matching +full:ras +full:- +full:to +full:- +full:cas

9  * Intel 5100X Chipset Memory Controller Hub (MCH) - Datasheet
13 * can not reflect this configuration so instead the chip-select
15 * the first half belonging to channel 0, the second half belonging
16 * to channel 1.
18 * This driver is for DDR2 DIMMs, and it uses chip select to select among the
70 #define I5100_NERR_NF_MEM 0xa4 /* MC Next Non-Fatal Errors */
82 #define I5100_MTR_0 0x154 /* Memory Technology Registers 0-3 */
85 #define I5100_NRECMEMA 0x190 /* Non-Recoverable Memory Error Log Reg A */
86 #define I5100_NRECMEMB 0x194 /* Non-Recoverable Memory Error Log Reg B */
127 return a & ((1 << 8) - 1); in i5100_spddata_data()
133 return ((dti & ((1 << 4) - 1)) << 28) | in i5100_spdcmd_create()
135 ((sa & ((1 << 3) - 1)) << 24) | in i5100_spdcmd_create()
136 ((ba & ((1 << 8) - 1)) << 16) | in i5100_spdcmd_create()
137 ((data & ((1 << 8) - 1)) << 8) | in i5100_spdcmd_create()
143 return a >> 12 & ((1 << 4) - 1); in i5100_tolm_tolm()
148 return a >> 4 & ((1 << 12) - 1); in i5100_mir_limit()
178 return a >> 16 & ((1 << 11) - 1); in i5100_dmir_limit()
183 return a >> (4 * i) & ((1 << 2) - 1); in i5100_dmir_rank()
208 return a >> 2 & ((1 << 2) - 1); in i5100_mtr_numrow()
213 return a & ((1 << 2) - 1); in i5100_mtr_numcol()
234 return a >> 15 & ((1 << 5) - 1); in i5100_nrecmema_merr()
239 return a >> 12 & ((1 << 3) - 1); in i5100_nrecmema_bank()
244 return a >> 8 & ((1 << 3) - 1); in i5100_nrecmema_rank()
249 return a >> 16 & ((1 << 13) - 1); in i5100_nrecmemb_cas()
254 return a & ((1 << 16) - 1); in i5100_nrecmemb_ras()
286 #define I5100_DIMM_ADDR_LINES (6 - 3) /* 64 bits / 8 bits per byte */
293 /* ranks on each dimm -- 0 maps to not present -- obtained via SPD */
297 * mainboard chip select map -- maps i5100 chip selects to
300 * we map -1 -> NC and assume both channels use the same
355 /* map a rank/chan to a slot number on the mainboard */
359 const struct i5100_priv *priv = mci->pvt_info; in i5100_rank_to_slot()
364 const int numrank = priv->dimm_numrank[chan][i]; in i5100_rank_to_slot()
367 if (priv->dimm_csmap[i][j] == rank) in i5100_rank_to_slot()
371 return -1; in i5100_rank_to_slot()
382 "aliased uncorrectable spare-copy data ECC", /* 5 */ in i5100_err_msg()
387 "non-aliased uncorrectable demand data ECC", /* 10 */ in i5100_err_msg()
388 "non-aliased uncorrectable spare-copy data ECC", /* 11 */ in i5100_err_msg()
389 "non-aliased uncorrectable patrol data ECC", /* 12 */ in i5100_err_msg()
392 "correctable spare-copy data ECC", /* 15 */ in i5100_err_msg()
409 /* convert csrow index into a rank (per channel -- 0..5) */
413 const struct i5100_priv *priv = mci->pvt_info; in i5100_csrow_to_rank()
415 return csrow % priv->ranksperchan; in i5100_csrow_to_rank()
422 const struct i5100_priv *priv = mci->pvt_info; in i5100_csrow_to_chan()
424 return csrow / priv->ranksperchan; in i5100_csrow_to_chan()
432 unsigned cas, in i5100_handle_ce() argument
433 unsigned ras, in i5100_handle_ce() argument
440 "bank %u, cas %u, ras %u\n", in i5100_handle_ce()
441 bank, cas, ras); in i5100_handle_ce()
445 chan, rank, -1, in i5100_handle_ce()
454 unsigned cas, in i5100_handle_ue() argument
455 unsigned ras, in i5100_handle_ue() argument
462 "bank %u, cas %u, ras %u\n", in i5100_handle_ue()
463 bank, cas, ras); in i5100_handle_ue()
467 chan, rank, -1, in i5100_handle_ue()
474 struct i5100_priv *priv = mci->pvt_info; in i5100_read_log()
475 struct pci_dev *pdev = (chan) ? priv->ch1mm : priv->ch0mm; in i5100_read_log()
482 unsigned cas; in i5100_read_log() local
483 unsigned ras; in i5100_read_log() local
502 cas = i5100_recmemb_cas(dw2); in i5100_read_log()
503 ras = i5100_recmemb_ras(dw2); in i5100_read_log()
512 i5100_handle_ce(mci, chan, bank, rank, syndrome, cas, ras, msg); in i5100_read_log()
524 cas = i5100_nrecmemb_cas(dw2); in i5100_read_log()
525 ras = i5100_nrecmemb_ras(dw2); in i5100_read_log()
534 i5100_handle_ue(mci, chan, bank, rank, syndrome, cas, ras, msg); in i5100_read_log()
542 struct i5100_priv *priv = mci->pvt_info; in i5100_check_error()
545 pci_read_config_dword(priv->mc, I5100_FERR_NF_MEM, &dw); in i5100_check_error()
548 pci_read_config_dword(priv->mc, I5100_NERR_NF_MEM, &dw2); in i5100_check_error()
554 pci_write_config_dword(priv->mc, I5100_NERR_NF_MEM, dw2); in i5100_check_error()
556 pci_write_config_dword(priv->mc, I5100_FERR_NF_MEM, dw); in i5100_check_error()
561 * delayed work to a workqueue, checking every few minutes if
573 pci_read_config_dword(priv->mc, I5100_MC, &dw); in i5100_refresh_scrubbing()
575 if (priv->scrub_enable) { in i5100_refresh_scrubbing()
577 pci_read_config_dword(priv->mc, I5100_MC, &dw); in i5100_refresh_scrubbing()
581 pci_write_config_dword(priv->mc, I5100_MC, dw); in i5100_refresh_scrubbing()
582 pci_read_config_dword(priv->mc, I5100_MC, &dw); in i5100_refresh_scrubbing()
585 schedule_delayed_work(&(priv->i5100_scrubbing), in i5100_refresh_scrubbing()
590 * The bandwidth is based on experimentation, feel free to refine it.
594 struct i5100_priv *priv = mci->pvt_info; in i5100_set_scrub_rate()
597 pci_read_config_dword(priv->mc, I5100_MC, &dw); in i5100_set_scrub_rate()
599 priv->scrub_enable = 1; in i5100_set_scrub_rate()
601 schedule_delayed_work(&(priv->i5100_scrubbing), in i5100_set_scrub_rate()
604 priv->scrub_enable = 0; in i5100_set_scrub_rate()
606 cancel_delayed_work(&(priv->i5100_scrubbing)); in i5100_set_scrub_rate()
608 pci_write_config_dword(priv->mc, I5100_MC, dw); in i5100_set_scrub_rate()
610 pci_read_config_dword(priv->mc, I5100_MC, &dw); in i5100_set_scrub_rate()
619 struct i5100_priv *priv = mci->pvt_info; in i5100_get_scrub_rate()
622 pci_read_config_dword(priv->mc, I5100_MC, &dw); in i5100_get_scrub_rate()
639 if (PCI_FUNC(ret->devfn) == func) in pci_get_device_func()
648 struct i5100_priv *priv = mci->pvt_info; in i5100_npages()
654 if (!priv->mtr[chan][chan_rank].present) in i5100_npages()
659 priv->mtr[chan][chan_rank].numcol + in i5100_npages()
660 priv->mtr[chan][chan_rank].numrow + in i5100_npages()
661 priv->mtr[chan][chan_rank].numbank; in i5100_npages()
669 struct i5100_priv *priv = mci->pvt_info; in i5100_init_mtr()
670 struct pci_dev *mms[2] = { priv->ch0mm, priv->ch1mm }; in i5100_init_mtr()
680 I5100_MTR_4 + (j - 4) * 2; in i5100_init_mtr()
685 priv->mtr[i][j].present = i5100_mtr_present(w); in i5100_init_mtr()
686 priv->mtr[i][j].ethrottle = i5100_mtr_ethrottle(w); in i5100_init_mtr()
687 priv->mtr[i][j].width = 4 + 4 * i5100_mtr_width(w); in i5100_init_mtr()
688 priv->mtr[i][j].numbank = 2 + i5100_mtr_numbank(w); in i5100_init_mtr()
689 priv->mtr[i][j].numrow = 13 + i5100_mtr_numrow(w); in i5100_init_mtr()
690 priv->mtr[i][j].numcol = 10 + i5100_mtr_numcol(w); in i5100_init_mtr()
696 * FIXME: make this into a real i2c adapter (so that dimm-decode
702 struct i5100_priv *priv = mci->pvt_info; in i5100_read_spd_byte()
705 pci_read_config_word(priv->mc, I5100_SPDDATA, &w); in i5100_read_spd_byte()
707 return -1; in i5100_read_spd_byte()
709 pci_write_config_dword(priv->mc, I5100_SPDCMD, in i5100_read_spd_byte()
713 /* wait up to 100ms */ in i5100_read_spd_byte()
716 pci_read_config_word(priv->mc, I5100_SPDDATA, &w); in i5100_read_spd_byte()
723 return -1; in i5100_read_spd_byte()
734 * o not the only way to may chip selects to dimm slots
735 * o investigate if there is some way to obtain this map from the bios
739 struct i5100_priv *priv = mci->pvt_info; in i5100_init_dimm_csmap()
746 priv->dimm_csmap[i][j] = -1; /* default NC */ in i5100_init_dimm_csmap()
750 if (priv->ranksperchan == 4) { in i5100_init_dimm_csmap()
751 priv->dimm_csmap[0][0] = 0; in i5100_init_dimm_csmap()
752 priv->dimm_csmap[0][1] = 3; in i5100_init_dimm_csmap()
753 priv->dimm_csmap[1][0] = 1; in i5100_init_dimm_csmap()
754 priv->dimm_csmap[1][1] = 2; in i5100_init_dimm_csmap()
755 priv->dimm_csmap[2][0] = 2; in i5100_init_dimm_csmap()
756 priv->dimm_csmap[3][0] = 3; in i5100_init_dimm_csmap()
758 priv->dimm_csmap[0][0] = 0; in i5100_init_dimm_csmap()
759 priv->dimm_csmap[0][1] = 1; in i5100_init_dimm_csmap()
760 priv->dimm_csmap[1][0] = 2; in i5100_init_dimm_csmap()
761 priv->dimm_csmap[1][1] = 3; in i5100_init_dimm_csmap()
762 priv->dimm_csmap[2][0] = 4; in i5100_init_dimm_csmap()
763 priv->dimm_csmap[2][1] = 5; in i5100_init_dimm_csmap()
770 struct i5100_priv *priv = mci->pvt_info; in i5100_init_dimm_layout()
780 priv->dimm_numrank[i][j] = 0; in i5100_init_dimm_layout()
782 priv->dimm_numrank[i][j] = (rank & 3) + 1; in i5100_init_dimm_layout()
794 struct i5100_priv *priv = mci->pvt_info; in i5100_init_interleaving()
795 struct pci_dev *mms[2] = { priv->ch0mm, priv->ch1mm }; in i5100_init_interleaving()
799 priv->tolm = (u64) i5100_tolm_tolm(w) * 256 * 1024 * 1024; in i5100_init_interleaving()
802 priv->mir[0].limit = (u64) i5100_mir_limit(w) << 28; in i5100_init_interleaving()
803 priv->mir[0].way[1] = i5100_mir_way1(w); in i5100_init_interleaving()
804 priv->mir[0].way[0] = i5100_mir_way0(w); in i5100_init_interleaving()
807 priv->mir[1].limit = (u64) i5100_mir_limit(w) << 28; in i5100_init_interleaving()
808 priv->mir[1].way[1] = i5100_mir_way1(w); in i5100_init_interleaving()
809 priv->mir[1].way[0] = i5100_mir_way0(w); in i5100_init_interleaving()
812 priv->amir[0] = w; in i5100_init_interleaving()
814 priv->amir[1] = w; in i5100_init_interleaving()
824 priv->dmir[i][j].limit = in i5100_init_interleaving()
827 priv->dmir[i][j].rank[k] = in i5100_init_interleaving()
837 struct i5100_priv *priv = mci->pvt_info; in i5100_init_csrows()
841 const unsigned long npages = i5100_npages(mci, dimm->idx); in i5100_init_csrows()
842 const unsigned int chan = i5100_csrow_to_chan(mci, dimm->idx); in i5100_init_csrows()
843 const unsigned int rank = i5100_csrow_to_rank(mci, dimm->idx); in i5100_init_csrows()
848 dimm->nr_pages = npages; in i5100_init_csrows()
849 dimm->grain = 32; in i5100_init_csrows()
850 dimm->dtype = (priv->mtr[chan][rank].width == 4) ? in i5100_init_csrows()
852 dimm->mtype = MEM_RDDR2; in i5100_init_csrows()
853 dimm->edac_mode = EDAC_SECDED; in i5100_init_csrows()
854 snprintf(dimm->label, sizeof(dimm->label), "DIMM%u", in i5100_init_csrows()
868 struct i5100_priv *priv = mci->pvt_info; in i5100_do_inject()
873 * 31 - ADDRMATCHEN in i5100_do_inject()
874 * 29:28 - HLINESEL in i5100_do_inject()
879 * 27 - EINJEN in i5100_do_inject()
880 * 25:19 - XORMASK1 for deviceptr1 in i5100_do_inject()
881 * 9:5 - SEC2RAM for deviceptr2 in i5100_do_inject()
882 * 4:0 - FIR2RAM for deviceptr1 in i5100_do_inject()
884 mask0 = ((priv->inject_hlinesel & 0x3) << 28) | in i5100_do_inject()
886 ((priv->inject_eccmask1 & 0xffff) << 10) | in i5100_do_inject()
887 ((priv->inject_deviceptr2 & 0x1f) << 5) | in i5100_do_inject()
888 (priv->inject_deviceptr1 & 0x1f); in i5100_do_inject()
891 * 15:0 - XORMASK2 for deviceptr2 in i5100_do_inject()
893 mask1 = priv->inject_eccmask2; in i5100_do_inject()
895 if (priv->inject_channel == 0) { in i5100_do_inject()
896 pci_write_config_dword(priv->mc, I5100_MEM0EINJMSK0, mask0); in i5100_do_inject()
897 pci_write_config_word(priv->mc, I5100_MEM0EINJMSK1, mask1); in i5100_do_inject()
899 pci_write_config_dword(priv->mc, I5100_MEM1EINJMSK0, mask0); in i5100_do_inject()
900 pci_write_config_word(priv->mc, I5100_MEM1EINJMSK1, mask1); in i5100_do_inject()
908 * which appears to be accurate for the i5100 in this area. in i5100_do_inject()
911 * The register needs to be flipped off then on else the hardware in i5100_do_inject()
915 * 1010 - Stop after one injection in i5100_do_inject()
916 * 1011 - Never stop injecting faults in i5100_do_inject()
919 * 1010 - Never start in i5100_do_inject()
920 * 1011 - Start immediately in i5100_do_inject()
922 pci_write_config_byte(priv->einj, I5100_DINJ0, 0xaa); in i5100_do_inject()
923 pci_write_config_byte(priv->einj, I5100_DINJ0, 0xab); in i5100_do_inject()
930 struct device *dev = file->private_data; in inject_enable_write()
946 struct i5100_priv *priv = mci->pvt_info; in i5100_setup_debugfs()
949 return -ENODEV; in i5100_setup_debugfs()
951 priv->debugfs = edac_debugfs_create_dir_at(mci->bus->name, i5100_debugfs); in i5100_setup_debugfs()
953 if (!priv->debugfs) in i5100_setup_debugfs()
954 return -ENOMEM; in i5100_setup_debugfs()
956 edac_debugfs_create_x8("inject_channel", S_IRUGO | S_IWUSR, priv->debugfs, in i5100_setup_debugfs()
957 &priv->inject_channel); in i5100_setup_debugfs()
958 edac_debugfs_create_x8("inject_hlinesel", S_IRUGO | S_IWUSR, priv->debugfs, in i5100_setup_debugfs()
959 &priv->inject_hlinesel); in i5100_setup_debugfs()
960 edac_debugfs_create_x8("inject_deviceptr1", S_IRUGO | S_IWUSR, priv->debugfs, in i5100_setup_debugfs()
961 &priv->inject_deviceptr1); in i5100_setup_debugfs()
962 edac_debugfs_create_x8("inject_deviceptr2", S_IRUGO | S_IWUSR, priv->debugfs, in i5100_setup_debugfs()
963 &priv->inject_deviceptr2); in i5100_setup_debugfs()
964 edac_debugfs_create_x16("inject_eccmask1", S_IRUGO | S_IWUSR, priv->debugfs, in i5100_setup_debugfs()
965 &priv->inject_eccmask1); in i5100_setup_debugfs()
966 edac_debugfs_create_x16("inject_eccmask2", S_IRUGO | S_IWUSR, priv->debugfs, in i5100_setup_debugfs()
967 &priv->inject_eccmask2); in i5100_setup_debugfs()
968 edac_debugfs_create_file("inject_enable", S_IWUSR, priv->debugfs, in i5100_setup_debugfs()
969 &mci->dev, &i5100_inject_enable_fops); in i5100_setup_debugfs()
986 if (PCI_FUNC(pdev->devfn) != 1) in i5100_init_one()
987 return -ENODEV; in i5100_init_one()
999 ret = -ENODEV; in i5100_init_one()
1016 ret = -ENODEV; in i5100_init_one()
1030 ret = -ENODEV; in i5100_init_one()
1049 ret = -ENOMEM; in i5100_init_one()
1058 ret = -ENODEV; in i5100_init_one()
1068 mci->pdev = &pdev->dev; in i5100_init_one()
1070 priv = mci->pvt_info; in i5100_init_one()
1071 priv->ranksperchan = ranksperch; in i5100_init_one()
1072 priv->mc = pdev; in i5100_init_one()
1073 priv->ch0mm = ch0mm; in i5100_init_one()
1074 priv->ch1mm = ch1mm; in i5100_init_one()
1075 priv->einj = einj; in i5100_init_one()
1077 INIT_DELAYED_WORK(&(priv->i5100_scrubbing), i5100_refresh_scrubbing); in i5100_init_one()
1082 priv->scrub_enable = 1; in i5100_init_one()
1083 schedule_delayed_work(&(priv->i5100_scrubbing), in i5100_init_one()
1090 mci->mtype_cap = MEM_FLAG_FB_DDR2; in i5100_init_one()
1091 mci->edac_ctl_cap = EDAC_FLAG_SECDED; in i5100_init_one()
1092 mci->edac_cap = EDAC_FLAG_SECDED; in i5100_init_one()
1093 mci->mod_name = "i5100_edac.c"; in i5100_init_one()
1094 mci->ctl_name = "i5100"; in i5100_init_one()
1095 mci->dev_name = pci_name(pdev); in i5100_init_one()
1096 mci->ctl_page_to_phys = NULL; in i5100_init_one()
1098 mci->edac_check = i5100_check_error; in i5100_init_one()
1099 mci->set_sdram_scrub_rate = i5100_set_scrub_rate; in i5100_init_one()
1100 mci->get_sdram_scrub_rate = i5100_get_scrub_rate; in i5100_init_one()
1102 priv->inject_channel = 0; in i5100_init_one()
1103 priv->inject_hlinesel = 0; in i5100_init_one()
1104 priv->inject_deviceptr1 = 0; in i5100_init_one()
1105 priv->inject_deviceptr2 = 0; in i5100_init_one()
1106 priv->inject_eccmask1 = 0; in i5100_init_one()
1107 priv->inject_eccmask2 = 0; in i5100_init_one()
1111 /* this strange construction seems to be in every driver, dunno why */ in i5100_init_one()
1122 ret = -ENODEV; in i5100_init_one()
1131 priv->scrub_enable = 0; in i5100_init_one()
1132 cancel_delayed_work_sync(&(priv->i5100_scrubbing)); in i5100_init_one()
1165 mci = edac_mc_del_mc(&pdev->dev); in i5100_remove_one()
1170 priv = mci->pvt_info; in i5100_remove_one()
1172 edac_debugfs_remove_recursive(priv->debugfs); in i5100_remove_one()
1174 priv->scrub_enable = 0; in i5100_remove_one()
1175 cancel_delayed_work_sync(&(priv->i5100_scrubbing)); in i5100_remove_one()
1178 pci_disable_device(priv->ch0mm); in i5100_remove_one()
1179 pci_disable_device(priv->ch1mm); in i5100_remove_one()
1180 pci_disable_device(priv->einj); in i5100_remove_one()
1181 pci_dev_put(priv->ch0mm); in i5100_remove_one()
1182 pci_dev_put(priv->ch1mm); in i5100_remove_one()
1183 pci_dev_put(priv->einj); in i5100_remove_one()