diff options
| author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-02-21 11:36:45 -0500 |
|---|---|---|
| committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-02-21 11:48:45 -0500 |
| commit | c7ef7645544131b0750478d1cf94cdfa945c809d (patch) | |
| tree | 4442e415b365cd43be1d8a73703f809f78177560 | |
| parent | 80cc7d87d5eb34375f916d282450a0906a8ead60 (diff) | |
edac: reduce stack pressure by using a pre-allocated buffer
The number of variables at the stack is too big.
Reduces the stack usage by using a pre-allocated error
buffer.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
| -rw-r--r-- | drivers/edac/edac_mc.c | 81 | ||||
| -rw-r--r-- | include/linux/edac.h | 56 |
2 files changed, 104 insertions, 33 deletions
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 34eb9703ed33..4f18dd755939 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
| @@ -1065,7 +1065,6 @@ static void edac_ue_error(struct mem_ctl_info *mci, | |||
| 1065 | edac_inc_ue_error(mci, enable_per_layer_report, pos, error_count); | 1065 | edac_inc_ue_error(mci, enable_per_layer_report, pos, error_count); |
| 1066 | } | 1066 | } |
| 1067 | 1067 | ||
| 1068 | #define OTHER_LABEL " or " | ||
| 1069 | 1068 | ||
| 1070 | /** | 1069 | /** |
| 1071 | * edac_mc_handle_error - reports a memory event to userspace | 1070 | * edac_mc_handle_error - reports a memory event to userspace |
| @@ -1097,19 +1096,28 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, | |||
| 1097 | const char *msg, | 1096 | const char *msg, |
| 1098 | const char *other_detail) | 1097 | const char *other_detail) |
| 1099 | { | 1098 | { |
| 1100 | /* FIXME: too much for stack: move it to some pre-alocated area */ | 1099 | char detail[80]; |
| 1101 | char detail[80], location[80]; | ||
| 1102 | char label[(EDAC_MC_LABEL_LEN + 1 + sizeof(OTHER_LABEL)) * mci->tot_dimms]; | ||
| 1103 | char *p; | 1100 | char *p; |
| 1104 | int row = -1, chan = -1; | 1101 | int row = -1, chan = -1; |
| 1105 | int pos[EDAC_MAX_LAYERS] = { top_layer, mid_layer, low_layer }; | 1102 | int pos[EDAC_MAX_LAYERS] = { top_layer, mid_layer, low_layer }; |
| 1106 | int i; | 1103 | int i, n_labels = 0; |
| 1107 | long grain; | ||
| 1108 | bool enable_per_layer_report = false; | ||
| 1109 | u8 grain_bits; | 1104 | u8 grain_bits; |
| 1105 | struct edac_raw_error_desc *e = &mci->error_desc; | ||
| 1110 | 1106 | ||
| 1111 | edac_dbg(3, "MC%d\n", mci->mc_idx); | 1107 | edac_dbg(3, "MC%d\n", mci->mc_idx); |
| 1112 | 1108 | ||
| 1109 | /* Fills the error report buffer */ | ||
| 1110 | memset(e, 0, sizeof (*e)); | ||
| 1111 | e->error_count = error_count; | ||
| 1112 | e->top_layer = top_layer; | ||
| 1113 | e->mid_layer = mid_layer; | ||
| 1114 | e->low_layer = low_layer; | ||
| 1115 | e->page_frame_number = page_frame_number; | ||
| 1116 | e->offset_in_page = offset_in_page; | ||
| 1117 | e->syndrome = syndrome; | ||
| 1118 | e->msg = msg; | ||
| 1119 | e->other_detail = other_detail; | ||
| 1120 | |||
| 1113 | /* | 1121 | /* |
| 1114 | * Check if the event report is consistent and if the memory | 1122 | * Check if the event report is consistent and if the memory |
| 1115 | * location is known. If it is known, enable_per_layer_report will be | 1123 | * location is known. If it is known, enable_per_layer_report will be |
| @@ -1132,7 +1140,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, | |||
| 1132 | pos[i] = -1; | 1140 | pos[i] = -1; |
| 1133 | } | 1141 | } |
| 1134 | if (pos[i] >= 0) | 1142 | if (pos[i] >= 0) |
| 1135 | enable_per_layer_report = true; | 1143 | e->enable_per_layer_report = true; |
| 1136 | } | 1144 | } |
| 1137 | 1145 | ||
| 1138 | /* | 1146 | /* |
| @@ -1146,8 +1154,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, | |||
| 1146 | * where each memory belongs to a separate channel within the same | 1154 | * where each memory belongs to a separate channel within the same |
| 1147 | * branch. | 1155 | * branch. |
| 1148 | */ | 1156 | */ |
| 1149 | grain = 0; | 1157 | p = e->label; |
| 1150 | p = label; | ||
| 1151 | *p = '\0'; | 1158 | *p = '\0'; |
| 1152 | 1159 | ||
| 1153 | for (i = 0; i < mci->tot_dimms; i++) { | 1160 | for (i = 0; i < mci->tot_dimms; i++) { |
| @@ -1161,8 +1168,8 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, | |||
| 1161 | continue; | 1168 | continue; |
| 1162 | 1169 | ||
| 1163 | /* get the max grain, over the error match range */ | 1170 | /* get the max grain, over the error match range */ |
| 1164 | if (dimm->grain > grain) | 1171 | if (dimm->grain > e->grain) |
| 1165 | grain = dimm->grain; | 1172 | e->grain = dimm->grain; |
| 1166 | 1173 | ||
| 1167 | /* | 1174 | /* |
| 1168 | * If the error is memory-controller wide, there's no need to | 1175 | * If the error is memory-controller wide, there's no need to |
| @@ -1170,8 +1177,13 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, | |||
| 1170 | * channel/memory controller/... may be affected. | 1177 | * channel/memory controller/... may be affected. |
| 1171 | * Also, don't show errors for empty DIMM slots. | 1178 | * Also, don't show errors for empty DIMM slots. |
| 1172 | */ | 1179 | */ |
| 1173 | if (enable_per_layer_report && dimm->nr_pages) { | 1180 | if (e->enable_per_layer_report && dimm->nr_pages) { |
| 1174 | if (p != label) { | 1181 | if (n_labels >= EDAC_MAX_LABELS) { |
| 1182 | e->enable_per_layer_report = false; | ||
| 1183 | break; | ||
| 1184 | } | ||
| 1185 | n_labels++; | ||
| 1186 | if (p != e->label) { | ||
| 1175 | strcpy(p, OTHER_LABEL); | 1187 | strcpy(p, OTHER_LABEL); |
| 1176 | p += strlen(OTHER_LABEL); | 1188 | p += strlen(OTHER_LABEL); |
| 1177 | } | 1189 | } |
| @@ -1198,12 +1210,12 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, | |||
| 1198 | } | 1210 | } |
| 1199 | } | 1211 | } |
| 1200 | 1212 | ||
| 1201 | if (!enable_per_layer_report) { | 1213 | if (!e->enable_per_layer_report) { |
| 1202 | strcpy(label, "any memory"); | 1214 | strcpy(e->label, "any memory"); |
| 1203 | } else { | 1215 | } else { |
| 1204 | edac_dbg(4, "csrow/channel to increment: (%d,%d)\n", row, chan); | 1216 | edac_dbg(4, "csrow/channel to increment: (%d,%d)\n", row, chan); |
| 1205 | if (p == label) | 1217 | if (p == e->label) |
| 1206 | strcpy(label, "unknown memory"); | 1218 | strcpy(e->label, "unknown memory"); |
| 1207 | if (type == HW_EVENT_ERR_CORRECTED) { | 1219 | if (type == HW_EVENT_ERR_CORRECTED) { |
| 1208 | if (row >= 0) { | 1220 | if (row >= 0) { |
| 1209 | mci->csrows[row]->ce_count += error_count; | 1221 | mci->csrows[row]->ce_count += error_count; |
| @@ -1216,7 +1228,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, | |||
| 1216 | } | 1228 | } |
| 1217 | 1229 | ||
| 1218 | /* Fill the RAM location data */ | 1230 | /* Fill the RAM location data */ |
| 1219 | p = location; | 1231 | p = e->location; |
| 1220 | 1232 | ||
| 1221 | for (i = 0; i < mci->n_layers; i++) { | 1233 | for (i = 0; i < mci->n_layers; i++) { |
| 1222 | if (pos[i] < 0) | 1234 | if (pos[i] < 0) |
| @@ -1226,32 +1238,35 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, | |||
| 1226 | edac_layer_name[mci->layers[i].type], | 1238 | edac_layer_name[mci->layers[i].type], |
| 1227 | pos[i]); | 1239 | pos[i]); |
| 1228 | } | 1240 | } |
| 1229 | if (p > location) | 1241 | if (p > e->location) |
| 1230 | *(p - 1) = '\0'; | 1242 | *(p - 1) = '\0'; |
| 1231 | 1243 | ||
| 1232 | /* Report the error via the trace interface */ | 1244 | /* Report the error via the trace interface */ |
| 1233 | grain_bits = fls_long(grain) + 1; | 1245 | grain_bits = fls_long(e->grain) + 1; |
| 1234 | trace_mc_event(type, msg, label, error_count, | 1246 | trace_mc_event(type, e->msg, e->label, e->error_count, |
| 1235 | mci->mc_idx, top_layer, mid_layer, low_layer, | 1247 | mci->mc_idx, e->top_layer, e->mid_layer, e->low_layer, |
| 1236 | PAGES_TO_MiB(page_frame_number) | offset_in_page, | 1248 | PAGES_TO_MiB(e->page_frame_number) | e->offset_in_page, |
| 1237 | grain_bits, syndrome, other_detail); | 1249 | grain_bits, e->syndrome, other_detail); |
| 1238 | 1250 | ||
| 1239 | /* Memory type dependent details about the error */ | 1251 | /* Memory type dependent details about the error */ |
| 1240 | if (type == HW_EVENT_ERR_CORRECTED) { | 1252 | if (type == HW_EVENT_ERR_CORRECTED) { |
| 1241 | snprintf(detail, sizeof(detail), | 1253 | snprintf(detail, sizeof(detail), |
| 1242 | "page:0x%lx offset:0x%lx grain:%ld syndrome:0x%lx", | 1254 | "page:0x%lx offset:0x%lx grain:%ld syndrome:0x%lx", |
| 1243 | page_frame_number, offset_in_page, | 1255 | e->page_frame_number, e->offset_in_page, |
| 1244 | grain, syndrome); | 1256 | e->grain, e->syndrome); |
| 1245 | edac_ce_error(mci, error_count, pos, msg, location, label, | 1257 | edac_ce_error(mci, e->error_count, pos, e->msg, e->location, |
| 1246 | detail, other_detail, enable_per_layer_report, | 1258 | e->label, detail, other_detail, |
| 1247 | page_frame_number, offset_in_page, grain); | 1259 | e->enable_per_layer_report, |
| 1260 | e->page_frame_number, e->offset_in_page, | ||
| 1261 | e->grain); | ||
| 1248 | } else { | 1262 | } else { |
| 1249 | snprintf(detail, sizeof(detail), | 1263 | snprintf(detail, sizeof(detail), |
| 1250 | "page:0x%lx offset:0x%lx grain:%ld", | 1264 | "page:0x%lx offset:0x%lx grain:%ld", |
| 1251 | page_frame_number, offset_in_page, grain); | 1265 | page_frame_number, offset_in_page, e->grain); |
| 1252 | 1266 | ||
| 1253 | edac_ue_error(mci, error_count, pos, msg, location, label, | 1267 | edac_ue_error(mci, e->error_count, pos, e->msg, e->location, |
| 1254 | detail, other_detail, enable_per_layer_report); | 1268 | e->label, detail, other_detail, |
| 1269 | e->enable_per_layer_report); | ||
| 1255 | } | 1270 | } |
| 1256 | } | 1271 | } |
| 1257 | EXPORT_SYMBOL_GPL(edac_mc_handle_error); | 1272 | EXPORT_SYMBOL_GPL(edac_mc_handle_error); |
diff --git a/include/linux/edac.h b/include/linux/edac.h index ff18efc754f3..096b7fcdf484 100644 --- a/include/linux/edac.h +++ b/include/linux/edac.h | |||
| @@ -47,8 +47,18 @@ static inline void opstate_init(void) | |||
| 47 | return; | 47 | return; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | /* Max length of a DIMM label*/ | ||
| 50 | #define EDAC_MC_LABEL_LEN 31 | 51 | #define EDAC_MC_LABEL_LEN 31 |
| 51 | 52 | ||
| 53 | /* Maximum size of the location string */ | ||
| 54 | #define LOCATION_SIZE 80 | ||
| 55 | |||
| 56 | /* Defines the maximum number of labels that can be reported */ | ||
| 57 | #define EDAC_MAX_LABELS 8 | ||
| 58 | |||
| 59 | /* String used to join two or more labels */ | ||
| 60 | #define OTHER_LABEL " or " | ||
| 61 | |||
| 52 | /** | 62 | /** |
| 53 | * enum dev_type - describe the type of memory DRAM chips used at the stick | 63 | * enum dev_type - describe the type of memory DRAM chips used at the stick |
| 54 | * @DEV_UNKNOWN: Can't be determined, or MC doesn't support detect it | 64 | * @DEV_UNKNOWN: Can't be determined, or MC doesn't support detect it |
| @@ -553,6 +563,46 @@ struct errcount_attribute_data { | |||
| 553 | int layer0, layer1, layer2; | 563 | int layer0, layer1, layer2; |
| 554 | }; | 564 | }; |
| 555 | 565 | ||
| 566 | /** | ||
| 567 | * edac_raw_error_desc - Raw error report structure | ||
| 568 | * @grain: minimum granularity for an error report, in bytes | ||
| 569 | * @error_count: number of errors of the same type | ||
| 570 | * @top_layer: top layer of the error (layer[0]) | ||
| 571 | * @mid_layer: middle layer of the error (layer[1]) | ||
| 572 | * @low_layer: low layer of the error (layer[2]) | ||
| 573 | * @page_frame_number: page where the error happened | ||
| 574 | * @offset_in_page: page offset | ||
| 575 | * @syndrome: syndrome of the error (or 0 if unknown or if | ||
| 576 | * the syndrome is not applicable) | ||
| 577 | * @msg: error message | ||
| 578 | * @location: location of the error | ||
| 579 | * @label: label of the affected DIMM(s) | ||
| 580 | * @other_detail: other driver-specific detail about the error | ||
| 581 | * @enable_per_layer_report: if false, the error affects all layers | ||
| 582 | * (typically, a memory controller error) | ||
| 583 | */ | ||
| 584 | struct edac_raw_error_desc { | ||
| 585 | /* | ||
| 586 | * NOTE: everything before grain won't be cleaned by | ||
| 587 | * edac_raw_error_desc_clean() | ||
| 588 | */ | ||
| 589 | char location[LOCATION_SIZE]; | ||
| 590 | char label[(EDAC_MC_LABEL_LEN + 1 + sizeof(OTHER_LABEL)) * EDAC_MAX_LABELS]; | ||
| 591 | long grain; | ||
| 592 | |||
| 593 | /* the vars below and grain will be cleaned on every new error report */ | ||
| 594 | u16 error_count; | ||
| 595 | int top_layer; | ||
| 596 | int mid_layer; | ||
| 597 | int low_layer; | ||
| 598 | unsigned long page_frame_number; | ||
| 599 | unsigned long offset_in_page; | ||
| 600 | unsigned long syndrome; | ||
| 601 | const char *msg; | ||
| 602 | const char *other_detail; | ||
| 603 | bool enable_per_layer_report; | ||
| 604 | }; | ||
| 605 | |||
| 556 | /* MEMORY controller information structure | 606 | /* MEMORY controller information structure |
| 557 | */ | 607 | */ |
| 558 | struct mem_ctl_info { | 608 | struct mem_ctl_info { |
| @@ -660,6 +710,12 @@ struct mem_ctl_info { | |||
| 660 | /* work struct for this MC */ | 710 | /* work struct for this MC */ |
| 661 | struct delayed_work work; | 711 | struct delayed_work work; |
| 662 | 712 | ||
| 713 | /* | ||
| 714 | * Used to report an error - by being at the global struct | ||
| 715 | * makes the memory allocated by the EDAC core | ||
| 716 | */ | ||
| 717 | struct edac_raw_error_desc error_desc; | ||
| 718 | |||
| 663 | /* the internal state of this controller instance */ | 719 | /* the internal state of this controller instance */ |
| 664 | int op_state; | 720 | int op_state; |
| 665 | 721 | ||
