178d88e8aSMauro Carvalho Chehab /* 278d88e8aSMauro Carvalho Chehab * Defines, structures, APIs for edac_mc module 378d88e8aSMauro Carvalho Chehab * 478d88e8aSMauro Carvalho Chehab * (C) 2007 Linux Networx (http://lnxi.com) 578d88e8aSMauro Carvalho Chehab * This file may be distributed under the terms of the 678d88e8aSMauro Carvalho Chehab * GNU General Public License. 778d88e8aSMauro Carvalho Chehab * 878d88e8aSMauro Carvalho Chehab * Written by Thayne Harbaugh 978d88e8aSMauro Carvalho Chehab * Based on work by Dan Hollis <goemon at anime dot net> and others. 1078d88e8aSMauro Carvalho Chehab * http://www.anime.net/~goemon/linux-ecc/ 1178d88e8aSMauro Carvalho Chehab * 1278d88e8aSMauro Carvalho Chehab * NMI handling support added by 1378d88e8aSMauro Carvalho Chehab * Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com> 1478d88e8aSMauro Carvalho Chehab * 1578d88e8aSMauro Carvalho Chehab * Refactored for multi-source files: 1678d88e8aSMauro Carvalho Chehab * Doug Thompson <norsk5@xmission.com> 1778d88e8aSMauro Carvalho Chehab * 1866c222a0SMauro Carvalho Chehab * Please look at Documentation/driver-api/edac.rst for more info about 1966c222a0SMauro Carvalho Chehab * EDAC core structs and functions. 2078d88e8aSMauro Carvalho Chehab */ 2178d88e8aSMauro Carvalho Chehab 2278d88e8aSMauro Carvalho Chehab #ifndef _EDAC_MC_H_ 2378d88e8aSMauro Carvalho Chehab #define _EDAC_MC_H_ 2478d88e8aSMauro Carvalho Chehab 2578d88e8aSMauro Carvalho Chehab #include <linux/kernel.h> 2678d88e8aSMauro Carvalho Chehab #include <linux/types.h> 2778d88e8aSMauro Carvalho Chehab #include <linux/module.h> 2878d88e8aSMauro Carvalho Chehab #include <linux/spinlock.h> 2978d88e8aSMauro Carvalho Chehab #include <linux/smp.h> 3078d88e8aSMauro Carvalho Chehab #include <linux/pci.h> 3178d88e8aSMauro Carvalho Chehab #include <linux/time.h> 3278d88e8aSMauro Carvalho Chehab #include <linux/nmi.h> 3378d88e8aSMauro Carvalho Chehab #include <linux/rcupdate.h> 3478d88e8aSMauro Carvalho Chehab #include <linux/completion.h> 3578d88e8aSMauro Carvalho Chehab #include <linux/kobject.h> 3678d88e8aSMauro Carvalho Chehab #include <linux/platform_device.h> 3778d88e8aSMauro Carvalho Chehab #include <linux/workqueue.h> 3878d88e8aSMauro Carvalho Chehab #include <linux/edac.h> 3978d88e8aSMauro Carvalho Chehab 4078d88e8aSMauro Carvalho Chehab #if PAGE_SHIFT < 20 4178d88e8aSMauro Carvalho Chehab #define PAGES_TO_MiB(pages) ((pages) >> (20 - PAGE_SHIFT)) 4278d88e8aSMauro Carvalho Chehab #define MiB_TO_PAGES(mb) ((mb) << (20 - PAGE_SHIFT)) 4378d88e8aSMauro Carvalho Chehab #else /* PAGE_SHIFT > 20 */ 4478d88e8aSMauro Carvalho Chehab #define PAGES_TO_MiB(pages) ((pages) << (PAGE_SHIFT - 20)) 4578d88e8aSMauro Carvalho Chehab #define MiB_TO_PAGES(mb) ((mb) >> (PAGE_SHIFT - 20)) 4678d88e8aSMauro Carvalho Chehab #endif 4778d88e8aSMauro Carvalho Chehab 4878d88e8aSMauro Carvalho Chehab #define edac_printk(level, prefix, fmt, arg...) \ 4978d88e8aSMauro Carvalho Chehab printk(level "EDAC " prefix ": " fmt, ##arg) 5078d88e8aSMauro Carvalho Chehab 5178d88e8aSMauro Carvalho Chehab #define edac_mc_printk(mci, level, fmt, arg...) \ 5278d88e8aSMauro Carvalho Chehab printk(level "EDAC MC%d: " fmt, mci->mc_idx, ##arg) 5378d88e8aSMauro Carvalho Chehab 5478d88e8aSMauro Carvalho Chehab #define edac_mc_chipset_printk(mci, level, prefix, fmt, arg...) \ 5578d88e8aSMauro Carvalho Chehab printk(level "EDAC " prefix " MC%d: " fmt, mci->mc_idx, ##arg) 5678d88e8aSMauro Carvalho Chehab 5778d88e8aSMauro Carvalho Chehab #define edac_device_printk(ctl, level, fmt, arg...) \ 5878d88e8aSMauro Carvalho Chehab printk(level "EDAC DEVICE%d: " fmt, ctl->dev_idx, ##arg) 5978d88e8aSMauro Carvalho Chehab 6078d88e8aSMauro Carvalho Chehab #define edac_pci_printk(ctl, level, fmt, arg...) \ 6178d88e8aSMauro Carvalho Chehab printk(level "EDAC PCI%d: " fmt, ctl->pci_idx, ##arg) 6278d88e8aSMauro Carvalho Chehab 6378d88e8aSMauro Carvalho Chehab /* prefixes for edac_printk() and edac_mc_printk() */ 6478d88e8aSMauro Carvalho Chehab #define EDAC_MC "MC" 6578d88e8aSMauro Carvalho Chehab #define EDAC_PCI "PCI" 6678d88e8aSMauro Carvalho Chehab #define EDAC_DEBUG "DEBUG" 6778d88e8aSMauro Carvalho Chehab 6878d88e8aSMauro Carvalho Chehab extern const char * const edac_mem_types[]; 6978d88e8aSMauro Carvalho Chehab 7078d88e8aSMauro Carvalho Chehab #ifdef CONFIG_EDAC_DEBUG 7178d88e8aSMauro Carvalho Chehab extern int edac_debug_level; 7278d88e8aSMauro Carvalho Chehab 7378d88e8aSMauro Carvalho Chehab #define edac_dbg(level, fmt, ...) \ 7478d88e8aSMauro Carvalho Chehab do { \ 7578d88e8aSMauro Carvalho Chehab if (level <= edac_debug_level) \ 7678d88e8aSMauro Carvalho Chehab edac_printk(KERN_DEBUG, EDAC_DEBUG, \ 7778d88e8aSMauro Carvalho Chehab "%s: " fmt, __func__, ##__VA_ARGS__); \ 7878d88e8aSMauro Carvalho Chehab } while (0) 7978d88e8aSMauro Carvalho Chehab 8078d88e8aSMauro Carvalho Chehab #else /* !CONFIG_EDAC_DEBUG */ 8178d88e8aSMauro Carvalho Chehab 8278d88e8aSMauro Carvalho Chehab #define edac_dbg(level, fmt, ...) \ 8378d88e8aSMauro Carvalho Chehab do { \ 8478d88e8aSMauro Carvalho Chehab if (0) \ 8578d88e8aSMauro Carvalho Chehab edac_printk(KERN_DEBUG, EDAC_DEBUG, \ 8678d88e8aSMauro Carvalho Chehab "%s: " fmt, __func__, ##__VA_ARGS__); \ 8778d88e8aSMauro Carvalho Chehab } while (0) 8878d88e8aSMauro Carvalho Chehab 8978d88e8aSMauro Carvalho Chehab #endif /* !CONFIG_EDAC_DEBUG */ 9078d88e8aSMauro Carvalho Chehab 9178d88e8aSMauro Carvalho Chehab #define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \ 9278d88e8aSMauro Carvalho Chehab PCI_DEVICE_ID_ ## vend ## _ ## dev 9378d88e8aSMauro Carvalho Chehab 9478d88e8aSMauro Carvalho Chehab #define edac_dev_name(dev) (dev)->dev_name 9578d88e8aSMauro Carvalho Chehab 9678d88e8aSMauro Carvalho Chehab #define to_mci(k) container_of(k, struct mem_ctl_info, dev) 9778d88e8aSMauro Carvalho Chehab 98e01aa14cSMauro Carvalho Chehab /** 9966c222a0SMauro Carvalho Chehab * edac_mc_alloc() - Allocate and partially fill a struct &mem_ctl_info. 10066c222a0SMauro Carvalho Chehab * 101e01aa14cSMauro Carvalho Chehab * @mc_num: Memory controller number 102e01aa14cSMauro Carvalho Chehab * @n_layers: Number of MC hierarchy layers 103e01aa14cSMauro Carvalho Chehab * @layers: Describes each layer as seen by the Memory Controller 104e01aa14cSMauro Carvalho Chehab * @sz_pvt: size of private storage needed 105e01aa14cSMauro Carvalho Chehab * 106e01aa14cSMauro Carvalho Chehab * 107e01aa14cSMauro Carvalho Chehab * Everything is kmalloc'ed as one big chunk - more efficient. 108e01aa14cSMauro Carvalho Chehab * Only can be used if all structures have the same lifetime - otherwise 109e01aa14cSMauro Carvalho Chehab * you have to allocate and initialize your own structures. 110e01aa14cSMauro Carvalho Chehab * 111e01aa14cSMauro Carvalho Chehab * Use edac_mc_free() to free mc structures allocated by this function. 112e01aa14cSMauro Carvalho Chehab * 113e01aa14cSMauro Carvalho Chehab * .. note:: 114e01aa14cSMauro Carvalho Chehab * 115e01aa14cSMauro Carvalho Chehab * drivers handle multi-rank memories in different ways: in some 116e01aa14cSMauro Carvalho Chehab * drivers, one multi-rank memory stick is mapped as one entry, while, in 117e01aa14cSMauro Carvalho Chehab * others, a single multi-rank memory stick would be mapped into several 118e01aa14cSMauro Carvalho Chehab * entries. Currently, this function will allocate multiple struct dimm_info 119e01aa14cSMauro Carvalho Chehab * on such scenarios, as grouping the multiple ranks require drivers change. 120e01aa14cSMauro Carvalho Chehab * 121e01aa14cSMauro Carvalho Chehab * Returns: 12266c222a0SMauro Carvalho Chehab * On success, return a pointer to struct mem_ctl_info pointer; 12366c222a0SMauro Carvalho Chehab * %NULL otherwise 124e01aa14cSMauro Carvalho Chehab */ 125d55c79acSRobert Richter struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num, 126d55c79acSRobert Richter unsigned int n_layers, 12778d88e8aSMauro Carvalho Chehab struct edac_mc_layer *layers, 128d55c79acSRobert Richter unsigned int sz_pvt); 129e01aa14cSMauro Carvalho Chehab 130e01aa14cSMauro Carvalho Chehab /** 1313877c7d1SToshi Kani * edac_get_owner - Return the owner's mod_name of EDAC MC 1323877c7d1SToshi Kani * 1333877c7d1SToshi Kani * Returns: 1343877c7d1SToshi Kani * Pointer to mod_name string when EDAC MC is owned. NULL otherwise. 1353877c7d1SToshi Kani */ 1363877c7d1SToshi Kani extern const char *edac_get_owner(void); 1373877c7d1SToshi Kani 1383877c7d1SToshi Kani /* 13966c222a0SMauro Carvalho Chehab * edac_mc_add_mc_with_groups() - Insert the @mci structure into the mci 14066c222a0SMauro Carvalho Chehab * global list and create sysfs entries associated with @mci structure. 14166c222a0SMauro Carvalho Chehab * 142e01aa14cSMauro Carvalho Chehab * @mci: pointer to the mci structure to be added to the list 143e01aa14cSMauro Carvalho Chehab * @groups: optional attribute groups for the driver-specific sysfs entries 144e01aa14cSMauro Carvalho Chehab * 14566c222a0SMauro Carvalho Chehab * Returns: 14666c222a0SMauro Carvalho Chehab * 0 on Success, or an error code on failure 147e01aa14cSMauro Carvalho Chehab */ 14878d88e8aSMauro Carvalho Chehab extern int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, 14978d88e8aSMauro Carvalho Chehab const struct attribute_group **groups); 15078d88e8aSMauro Carvalho Chehab #define edac_mc_add_mc(mci) edac_mc_add_mc_with_groups(mci, NULL) 151e01aa14cSMauro Carvalho Chehab 152e01aa14cSMauro Carvalho Chehab /** 15366c222a0SMauro Carvalho Chehab * edac_mc_free() - Frees a previously allocated @mci structure 15466c222a0SMauro Carvalho Chehab * 155e01aa14cSMauro Carvalho Chehab * @mci: pointer to a struct mem_ctl_info structure 156e01aa14cSMauro Carvalho Chehab */ 15778d88e8aSMauro Carvalho Chehab extern void edac_mc_free(struct mem_ctl_info *mci); 158e01aa14cSMauro Carvalho Chehab 159e01aa14cSMauro Carvalho Chehab /** 160d7fc9d77SYazen Ghannam * edac_has_mcs() - Check if any MCs have been allocated. 161d7fc9d77SYazen Ghannam * 162d7fc9d77SYazen Ghannam * Returns: 163d7fc9d77SYazen Ghannam * True if MC instances have been registered successfully. 164d7fc9d77SYazen Ghannam * False otherwise. 165d7fc9d77SYazen Ghannam */ 166d7fc9d77SYazen Ghannam extern bool edac_has_mcs(void); 167d7fc9d77SYazen Ghannam 168d7fc9d77SYazen Ghannam /** 16966c222a0SMauro Carvalho Chehab * edac_mc_find() - Search for a mem_ctl_info structure whose index is @idx. 170e01aa14cSMauro Carvalho Chehab * 171e01aa14cSMauro Carvalho Chehab * @idx: index to be seek 172e01aa14cSMauro Carvalho Chehab * 173e01aa14cSMauro Carvalho Chehab * If found, return a pointer to the structure. 174e01aa14cSMauro Carvalho Chehab * Else return NULL. 175e01aa14cSMauro Carvalho Chehab */ 17678d88e8aSMauro Carvalho Chehab extern struct mem_ctl_info *edac_mc_find(int idx); 177e01aa14cSMauro Carvalho Chehab 178e01aa14cSMauro Carvalho Chehab /** 17966c222a0SMauro Carvalho Chehab * find_mci_by_dev() - Scan list of controllers looking for the one that 18066c222a0SMauro Carvalho Chehab * manages the @dev device. 181e01aa14cSMauro Carvalho Chehab * 182e01aa14cSMauro Carvalho Chehab * @dev: pointer to a struct device related with the MCI 18366c222a0SMauro Carvalho Chehab * 18466c222a0SMauro Carvalho Chehab * Returns: on success, returns a pointer to struct &mem_ctl_info; 18566c222a0SMauro Carvalho Chehab * %NULL otherwise. 186e01aa14cSMauro Carvalho Chehab */ 18778d88e8aSMauro Carvalho Chehab extern struct mem_ctl_info *find_mci_by_dev(struct device *dev); 188e01aa14cSMauro Carvalho Chehab 189e01aa14cSMauro Carvalho Chehab /** 19066c222a0SMauro Carvalho Chehab * edac_mc_del_mc() - Remove sysfs entries for mci structure associated with 19166c222a0SMauro Carvalho Chehab * @dev and remove mci structure from global list. 192e01aa14cSMauro Carvalho Chehab * 193e01aa14cSMauro Carvalho Chehab * @dev: Pointer to struct &device representing mci structure to remove. 194e01aa14cSMauro Carvalho Chehab * 19566c222a0SMauro Carvalho Chehab * Returns: pointer to removed mci structure, or %NULL if device not found. 196e01aa14cSMauro Carvalho Chehab */ 19778d88e8aSMauro Carvalho Chehab extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev); 19866c222a0SMauro Carvalho Chehab 19966c222a0SMauro Carvalho Chehab /** 20066c222a0SMauro Carvalho Chehab * edac_mc_find_csrow_by_page() - Ancillary routine to identify what csrow 20166c222a0SMauro Carvalho Chehab * contains a memory page. 20266c222a0SMauro Carvalho Chehab * 20366c222a0SMauro Carvalho Chehab * @mci: pointer to a struct mem_ctl_info structure 20466c222a0SMauro Carvalho Chehab * @page: memory page to find 20566c222a0SMauro Carvalho Chehab * 20666c222a0SMauro Carvalho Chehab * Returns: on success, returns the csrow. -1 if not found. 20766c222a0SMauro Carvalho Chehab */ 20878d88e8aSMauro Carvalho Chehab extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, 20978d88e8aSMauro Carvalho Chehab unsigned long page); 21078d88e8aSMauro Carvalho Chehab 211e01aa14cSMauro Carvalho Chehab /** 21266c222a0SMauro Carvalho Chehab * edac_raw_mc_handle_error() - Reports a memory event to userspace without 21366c222a0SMauro Carvalho Chehab * doing anything to discover the error location. 214e01aa14cSMauro Carvalho Chehab * 215e01aa14cSMauro Carvalho Chehab * @e: error description 216e01aa14cSMauro Carvalho Chehab * 217e01aa14cSMauro Carvalho Chehab * This raw function is used internally by edac_mc_handle_error(). It should 218e01aa14cSMauro Carvalho Chehab * only be called directly when the hardware error come directly from BIOS, 219e01aa14cSMauro Carvalho Chehab * like in the case of APEI GHES driver. 220e01aa14cSMauro Carvalho Chehab */ 221*91b327f6SRobert Richter void edac_raw_mc_handle_error(struct edac_raw_error_desc *e); 22278d88e8aSMauro Carvalho Chehab 223e01aa14cSMauro Carvalho Chehab /** 22466c222a0SMauro Carvalho Chehab * edac_mc_handle_error() - Reports a memory event to userspace. 225e01aa14cSMauro Carvalho Chehab * 226e01aa14cSMauro Carvalho Chehab * @type: severity of the error (CE/UE/Fatal) 227e01aa14cSMauro Carvalho Chehab * @mci: a struct mem_ctl_info pointer 228e01aa14cSMauro Carvalho Chehab * @error_count: Number of errors of the same type 229e01aa14cSMauro Carvalho Chehab * @page_frame_number: mem page where the error occurred 230e01aa14cSMauro Carvalho Chehab * @offset_in_page: offset of the error inside the page 231e01aa14cSMauro Carvalho Chehab * @syndrome: ECC syndrome 232e01aa14cSMauro Carvalho Chehab * @top_layer: Memory layer[0] position 233e01aa14cSMauro Carvalho Chehab * @mid_layer: Memory layer[1] position 234e01aa14cSMauro Carvalho Chehab * @low_layer: Memory layer[2] position 235e01aa14cSMauro Carvalho Chehab * @msg: Message meaningful to the end users that 236e01aa14cSMauro Carvalho Chehab * explains the event 237e01aa14cSMauro Carvalho Chehab * @other_detail: Technical details about the event that 238e01aa14cSMauro Carvalho Chehab * may help hardware manufacturers and 239e01aa14cSMauro Carvalho Chehab * EDAC developers to analyse the event 240e01aa14cSMauro Carvalho Chehab */ 24178d88e8aSMauro Carvalho Chehab void edac_mc_handle_error(const enum hw_event_mc_err_type type, 24278d88e8aSMauro Carvalho Chehab struct mem_ctl_info *mci, 24378d88e8aSMauro Carvalho Chehab const u16 error_count, 24478d88e8aSMauro Carvalho Chehab const unsigned long page_frame_number, 24578d88e8aSMauro Carvalho Chehab const unsigned long offset_in_page, 24678d88e8aSMauro Carvalho Chehab const unsigned long syndrome, 24778d88e8aSMauro Carvalho Chehab const int top_layer, 24878d88e8aSMauro Carvalho Chehab const int mid_layer, 24978d88e8aSMauro Carvalho Chehab const int low_layer, 25078d88e8aSMauro Carvalho Chehab const char *msg, 25178d88e8aSMauro Carvalho Chehab const char *other_detail); 25278d88e8aSMauro Carvalho Chehab 25378d88e8aSMauro Carvalho Chehab /* 25478d88e8aSMauro Carvalho Chehab * edac misc APIs 25578d88e8aSMauro Carvalho Chehab */ 25678d88e8aSMauro Carvalho Chehab extern char *edac_op_state_to_string(int op_state); 25778d88e8aSMauro Carvalho Chehab 25878d88e8aSMauro Carvalho Chehab #endif /* _EDAC_MC_H_ */ 259