diff options
Diffstat (limited to 'include/linux/edac.h')
-rw-r--r-- | include/linux/edac.h | 146 |
1 files changed, 68 insertions, 78 deletions
diff --git a/include/linux/edac.h b/include/linux/edac.h index c19483b90079..cc31b9742684 100644 --- a/include/linux/edac.h +++ b/include/linux/edac.h @@ -362,78 +362,6 @@ struct edac_mc_layer { */ #define EDAC_MAX_LAYERS 3 -/** - * EDAC_DIMM_OFF - Macro responsible to get a pointer offset inside a pointer - * array for the element given by [layer0,layer1,layer2] - * position - * - * @layers: a struct edac_mc_layer array, describing how many elements - * were allocated for each layer - * @nlayers: Number of layers at the @layers array - * @layer0: layer0 position - * @layer1: layer1 position. Unused if n_layers < 2 - * @layer2: layer2 position. Unused if n_layers < 3 - * - * For 1 layer, this macro returns "var[layer0] - var"; - * - * For 2 layers, this macro is similar to allocate a bi-dimensional array - * and to return "var[layer0][layer1] - var"; - * - * For 3 layers, this macro is similar to allocate a tri-dimensional array - * and to return "var[layer0][layer1][layer2] - var". - * - * A loop could be used here to make it more generic, but, as we only have - * 3 layers, this is a little faster. - * - * By design, layers can never be 0 or more than 3. If that ever happens, - * a NULL is returned, causing an OOPS during the memory allocation routine, - * with would point to the developer that he's doing something wrong. - */ -#define EDAC_DIMM_OFF(layers, nlayers, layer0, layer1, layer2) ({ \ - int __i; \ - if ((nlayers) == 1) \ - __i = layer0; \ - else if ((nlayers) == 2) \ - __i = (layer1) + ((layers[1]).size * (layer0)); \ - else if ((nlayers) == 3) \ - __i = (layer2) + ((layers[2]).size * ((layer1) + \ - ((layers[1]).size * (layer0)))); \ - else \ - __i = -EINVAL; \ - __i; \ -}) - -/** - * EDAC_DIMM_PTR - Macro responsible to get a pointer inside a pointer array - * for the element given by [layer0,layer1,layer2] position - * - * @layers: a struct edac_mc_layer array, describing how many elements - * were allocated for each layer - * @var: name of the var where we want to get the pointer - * (like mci->dimms) - * @nlayers: Number of layers at the @layers array - * @layer0: layer0 position - * @layer1: layer1 position. Unused if n_layers < 2 - * @layer2: layer2 position. Unused if n_layers < 3 - * - * For 1 layer, this macro returns "var[layer0]"; - * - * For 2 layers, this macro is similar to allocate a bi-dimensional array - * and to return "var[layer0][layer1]"; - * - * For 3 layers, this macro is similar to allocate a tri-dimensional array - * and to return "var[layer0][layer1][layer2]"; - */ -#define EDAC_DIMM_PTR(layers, var, nlayers, layer0, layer1, layer2) ({ \ - typeof(*var) __p; \ - int ___i = EDAC_DIMM_OFF(layers, nlayers, layer0, layer1, layer2); \ - if (___i < 0) \ - __p = NULL; \ - else \ - __p = (var)[___i]; \ - __p; \ -}) - struct dimm_info { struct device dev; @@ -443,6 +371,7 @@ struct dimm_info { unsigned int location[EDAC_MAX_LAYERS]; struct mem_ctl_info *mci; /* the parent */ + unsigned int idx; /* index within the parent dimm array */ u32 grain; /* granularity of reported error in bytes */ enum dev_type dtype; /* memory device type */ @@ -528,15 +457,10 @@ struct errcount_attribute_data { * (typically, a memory controller error) */ struct edac_raw_error_desc { - /* - * NOTE: everything before grain won't be cleaned by - * edac_raw_error_desc_clean() - */ char location[LOCATION_SIZE]; char label[(EDAC_MC_LABEL_LEN + 1 + sizeof(OTHER_LABEL)) * EDAC_MAX_LABELS]; long grain; - /* the vars below and grain will be cleaned on every new error report */ u16 error_count; int top_layer; int mid_layer; @@ -669,4 +593,70 @@ struct mem_ctl_info { bool fake_inject_ue; u16 fake_inject_count; }; -#endif + +#define mci_for_each_dimm(mci, dimm) \ + for ((dimm) = (mci)->dimms[0]; \ + (dimm); \ + (dimm) = (dimm)->idx + 1 < (mci)->tot_dimms \ + ? (mci)->dimms[(dimm)->idx + 1] \ + : NULL) + +/** + * edac_get_dimm_by_index - Get DIMM info at @index from a memory + * controller + * + * @mci: MC descriptor struct mem_ctl_info + * @index: index in the memory controller's DIMM array + * + * Returns a struct dimm_info * or NULL on failure. + */ +static inline struct dimm_info * +edac_get_dimm_by_index(struct mem_ctl_info *mci, int index) +{ + if (index < 0 || index >= mci->tot_dimms) + return NULL; + + if (WARN_ON_ONCE(mci->dimms[index]->idx != index)) + return NULL; + + return mci->dimms[index]; +} + +/** + * edac_get_dimm - Get DIMM info from a memory controller given by + * [layer0,layer1,layer2] position + * + * @mci: MC descriptor struct mem_ctl_info + * @layer0: layer0 position + * @layer1: layer1 position. Unused if n_layers < 2 + * @layer2: layer2 position. Unused if n_layers < 3 + * + * For 1 layer, this function returns "dimms[layer0]"; + * + * For 2 layers, this function is similar to allocating a two-dimensional + * array and returning "dimms[layer0][layer1]"; + * + * For 3 layers, this function is similar to allocating a tri-dimensional + * array and returning "dimms[layer0][layer1][layer2]"; + */ +static inline struct dimm_info *edac_get_dimm(struct mem_ctl_info *mci, + int layer0, int layer1, int layer2) +{ + int index; + + if (layer0 < 0 + || (mci->n_layers > 1 && layer1 < 0) + || (mci->n_layers > 2 && layer2 < 0)) + return NULL; + + index = layer0; + + if (mci->n_layers > 1) + index = index * mci->layers[1].size + layer1; + + if (mci->n_layers > 2) + index = index * mci->layers[2].size + layer2; + + return edac_get_dimm_by_index(mci, index); +} +#endif /* _LINUX_EDAC_H_ */ |