]>
Commit | Line | Data |
---|---|---|
2bc65418 DT |
1 | #include "amd64_edac.h" |
2 | ||
3 | static struct edac_pci_ctl_info *amd64_ctl_pci; | |
4 | ||
5 | static int report_gart_errors; | |
6 | module_param(report_gart_errors, int, 0644); | |
7 | ||
8 | /* | |
9 | * Set by command line parameter. If BIOS has enabled the ECC, this override is | |
10 | * cleared to prevent re-enabling the hardware by this driver. | |
11 | */ | |
12 | static int ecc_enable_override; | |
13 | module_param(ecc_enable_override, int, 0644); | |
14 | ||
15 | /* Lookup table for all possible MC control instances */ | |
16 | struct amd64_pvt; | |
17 | static struct mem_ctl_info *mci_lookup[MAX_NUMNODES]; | |
18 | static struct amd64_pvt *pvt_lookup[MAX_NUMNODES]; | |
19 | ||
20 | /* | |
21 | * Memory scrubber control interface. For K8, memory scrubbing is handled by | |
22 | * hardware and can involve L2 cache, dcache as well as the main memory. With | |
23 | * F10, this is extended to L3 cache scrubbing on CPU models sporting that | |
24 | * functionality. | |
25 | * | |
26 | * This causes the "units" for the scrubbing speed to vary from 64 byte blocks | |
27 | * (dram) over to cache lines. This is nasty, so we will use bandwidth in | |
28 | * bytes/sec for the setting. | |
29 | * | |
30 | * Currently, we only do dram scrubbing. If the scrubbing is done in software on | |
31 | * other archs, we might not have access to the caches directly. | |
32 | */ | |
33 | ||
34 | /* | |
35 | * scan the scrub rate mapping table for a close or matching bandwidth value to | |
36 | * issue. If requested is too big, then use last maximum value found. | |
37 | */ | |
38 | static int amd64_search_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, | |
39 | u32 min_scrubrate) | |
40 | { | |
41 | u32 scrubval; | |
42 | int i; | |
43 | ||
44 | /* | |
45 | * map the configured rate (new_bw) to a value specific to the AMD64 | |
46 | * memory controller and apply to register. Search for the first | |
47 | * bandwidth entry that is greater or equal than the setting requested | |
48 | * and program that. If at last entry, turn off DRAM scrubbing. | |
49 | */ | |
50 | for (i = 0; i < ARRAY_SIZE(scrubrates); i++) { | |
51 | /* | |
52 | * skip scrub rates which aren't recommended | |
53 | * (see F10 BKDG, F3x58) | |
54 | */ | |
55 | if (scrubrates[i].scrubval < min_scrubrate) | |
56 | continue; | |
57 | ||
58 | if (scrubrates[i].bandwidth <= new_bw) | |
59 | break; | |
60 | ||
61 | /* | |
62 | * if no suitable bandwidth found, turn off DRAM scrubbing | |
63 | * entirely by falling back to the last element in the | |
64 | * scrubrates array. | |
65 | */ | |
66 | } | |
67 | ||
68 | scrubval = scrubrates[i].scrubval; | |
69 | if (scrubval) | |
70 | edac_printk(KERN_DEBUG, EDAC_MC, | |
71 | "Setting scrub rate bandwidth: %u\n", | |
72 | scrubrates[i].bandwidth); | |
73 | else | |
74 | edac_printk(KERN_DEBUG, EDAC_MC, "Turning scrubbing off.\n"); | |
75 | ||
76 | pci_write_bits32(ctl, K8_SCRCTRL, scrubval, 0x001F); | |
77 | ||
78 | return 0; | |
79 | } | |
80 | ||
81 | static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 *bandwidth) | |
82 | { | |
83 | struct amd64_pvt *pvt = mci->pvt_info; | |
84 | u32 min_scrubrate = 0x0; | |
85 | ||
86 | switch (boot_cpu_data.x86) { | |
87 | case 0xf: | |
88 | min_scrubrate = K8_MIN_SCRUB_RATE_BITS; | |
89 | break; | |
90 | case 0x10: | |
91 | min_scrubrate = F10_MIN_SCRUB_RATE_BITS; | |
92 | break; | |
93 | case 0x11: | |
94 | min_scrubrate = F11_MIN_SCRUB_RATE_BITS; | |
95 | break; | |
96 | ||
97 | default: | |
98 | amd64_printk(KERN_ERR, "Unsupported family!\n"); | |
99 | break; | |
100 | } | |
101 | return amd64_search_set_scrub_rate(pvt->misc_f3_ctl, *bandwidth, | |
102 | min_scrubrate); | |
103 | } | |
104 | ||
105 | static int amd64_get_scrub_rate(struct mem_ctl_info *mci, u32 *bw) | |
106 | { | |
107 | struct amd64_pvt *pvt = mci->pvt_info; | |
108 | u32 scrubval = 0; | |
109 | int status = -1, i, ret = 0; | |
110 | ||
111 | ret = pci_read_config_dword(pvt->misc_f3_ctl, K8_SCRCTRL, &scrubval); | |
112 | if (ret) | |
113 | debugf0("Reading K8_SCRCTRL failed\n"); | |
114 | ||
115 | scrubval = scrubval & 0x001F; | |
116 | ||
117 | edac_printk(KERN_DEBUG, EDAC_MC, | |
118 | "pci-read, sdram scrub control value: %d \n", scrubval); | |
119 | ||
120 | for (i = 0; ARRAY_SIZE(scrubrates); i++) { | |
121 | if (scrubrates[i].scrubval == scrubval) { | |
122 | *bw = scrubrates[i].bandwidth; | |
123 | status = 0; | |
124 | break; | |
125 | } | |
126 | } | |
127 | ||
128 | return status; | |
129 | } | |
130 |