18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Defines, structures, APIs for edac_pci and edac_pci_sysfs 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * (C) 2007 Linux Networx (http://lnxi.com) 58c2ecf20Sopenharmony_ci * This file may be distributed under the terms of the 68c2ecf20Sopenharmony_ci * GNU General Public License. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Written by Thayne Harbaugh 98c2ecf20Sopenharmony_ci * Based on work by Dan Hollis <goemon at anime dot net> and others. 108c2ecf20Sopenharmony_ci * http://www.anime.net/~goemon/linux-ecc/ 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * NMI handling support added by 138c2ecf20Sopenharmony_ci * Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com> 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Refactored for multi-source files: 168c2ecf20Sopenharmony_ci * Doug Thompson <norsk5@xmission.com> 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Please look at Documentation/driver-api/edac.rst for more info about 198c2ecf20Sopenharmony_ci * EDAC core structs and functions. 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#ifndef _EDAC_PCI_H_ 238c2ecf20Sopenharmony_ci#define _EDAC_PCI_H_ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <linux/completion.h> 268c2ecf20Sopenharmony_ci#include <linux/device.h> 278c2ecf20Sopenharmony_ci#include <linux/edac.h> 288c2ecf20Sopenharmony_ci#include <linux/kobject.h> 298c2ecf20Sopenharmony_ci#include <linux/list.h> 308c2ecf20Sopenharmony_ci#include <linux/pci.h> 318c2ecf20Sopenharmony_ci#include <linux/types.h> 328c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistruct edac_pci_counter { 378c2ecf20Sopenharmony_ci atomic_t pe_count; 388c2ecf20Sopenharmony_ci atomic_t npe_count; 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* 428c2ecf20Sopenharmony_ci * Abstract edac_pci control info structure 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_cistruct edac_pci_ctl_info { 468c2ecf20Sopenharmony_ci /* for global list of edac_pci_ctl_info structs */ 478c2ecf20Sopenharmony_ci struct list_head link; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci int pci_idx; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci struct bus_type *edac_subsys; /* pointer to subsystem */ 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci /* the internal state of this controller instance */ 548c2ecf20Sopenharmony_ci int op_state; 558c2ecf20Sopenharmony_ci /* work struct for this instance */ 568c2ecf20Sopenharmony_ci struct delayed_work work; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci /* pointer to edac polling checking routine: 598c2ecf20Sopenharmony_ci * If NOT NULL: points to polling check routine 608c2ecf20Sopenharmony_ci * If NULL: Then assumes INTERRUPT operation, where 618c2ecf20Sopenharmony_ci * MC driver will receive events 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_ci void (*edac_check) (struct edac_pci_ctl_info * edac_dev); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci struct device *dev; /* pointer to device structure */ 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci const char *mod_name; /* module name */ 688c2ecf20Sopenharmony_ci const char *ctl_name; /* edac controller name */ 698c2ecf20Sopenharmony_ci const char *dev_name; /* pci/platform/etc... name */ 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci void *pvt_info; /* pointer to 'private driver' info */ 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci unsigned long start_time; /* edac_pci load start time (jiffies) */ 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci struct completion complete; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* sysfs top name under 'edac' directory 788c2ecf20Sopenharmony_ci * and instance name: 798c2ecf20Sopenharmony_ci * cpu/cpu0/... 808c2ecf20Sopenharmony_ci * cpu/cpu1/... 818c2ecf20Sopenharmony_ci * cpu/cpu2/... 828c2ecf20Sopenharmony_ci * ... 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_ci char name[EDAC_DEVICE_NAME_LEN + 1]; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* Event counters for the this whole EDAC Device */ 878c2ecf20Sopenharmony_ci struct edac_pci_counter counters; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* edac sysfs device control for the 'name' 908c2ecf20Sopenharmony_ci * device this structure controls 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_ci struct kobject kobj; 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci#define to_edac_pci_ctl_work(w) \ 968c2ecf20Sopenharmony_ci container_of(w, struct edac_pci_ctl_info,work) 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* write all or some bits in a byte-register*/ 998c2ecf20Sopenharmony_cistatic inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value, 1008c2ecf20Sopenharmony_ci u8 mask) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci if (mask != 0xff) { 1038c2ecf20Sopenharmony_ci u8 buf; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, offset, &buf); 1068c2ecf20Sopenharmony_ci value &= mask; 1078c2ecf20Sopenharmony_ci buf &= ~mask; 1088c2ecf20Sopenharmony_ci value |= buf; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, offset, value); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* write all or some bits in a word-register*/ 1158c2ecf20Sopenharmony_cistatic inline void pci_write_bits16(struct pci_dev *pdev, int offset, 1168c2ecf20Sopenharmony_ci u16 value, u16 mask) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci if (mask != 0xffff) { 1198c2ecf20Sopenharmony_ci u16 buf; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci pci_read_config_word(pdev, offset, &buf); 1228c2ecf20Sopenharmony_ci value &= mask; 1238c2ecf20Sopenharmony_ci buf &= ~mask; 1248c2ecf20Sopenharmony_ci value |= buf; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci pci_write_config_word(pdev, offset, value); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* 1318c2ecf20Sopenharmony_ci * pci_write_bits32 1328c2ecf20Sopenharmony_ci * 1338c2ecf20Sopenharmony_ci * edac local routine to do pci_write_config_dword, but adds 1348c2ecf20Sopenharmony_ci * a mask parameter. If mask is all ones, ignore the mask. 1358c2ecf20Sopenharmony_ci * Otherwise utilize the mask to isolate specified bits 1368c2ecf20Sopenharmony_ci * 1378c2ecf20Sopenharmony_ci * write all or some bits in a dword-register 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_cistatic inline void pci_write_bits32(struct pci_dev *pdev, int offset, 1408c2ecf20Sopenharmony_ci u32 value, u32 mask) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci if (mask != 0xffffffff) { 1438c2ecf20Sopenharmony_ci u32 buf; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, offset, &buf); 1468c2ecf20Sopenharmony_ci value &= mask; 1478c2ecf20Sopenharmony_ci buf &= ~mask; 1488c2ecf20Sopenharmony_ci value |= buf; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, offset, value); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/* 1578c2ecf20Sopenharmony_ci * edac_pci APIs 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/** 1618c2ecf20Sopenharmony_ci * edac_pci_alloc_ctl_info: 1628c2ecf20Sopenharmony_ci * The alloc() function for the 'edac_pci' control info 1638c2ecf20Sopenharmony_ci * structure. 1648c2ecf20Sopenharmony_ci * 1658c2ecf20Sopenharmony_ci * @sz_pvt: size of the private info at struct &edac_pci_ctl_info 1668c2ecf20Sopenharmony_ci * @edac_pci_name: name of the PCI device 1678c2ecf20Sopenharmony_ci * 1688c2ecf20Sopenharmony_ci * The chip driver will allocate one of these for each 1698c2ecf20Sopenharmony_ci * edac_pci it is going to control/register with the EDAC CORE. 1708c2ecf20Sopenharmony_ci * 1718c2ecf20Sopenharmony_ci * Returns: a pointer to struct &edac_pci_ctl_info on success; %NULL otherwise. 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_ciextern struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt, 1748c2ecf20Sopenharmony_ci const char *edac_pci_name); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci/** 1778c2ecf20Sopenharmony_ci * edac_pci_free_ctl_info(): 1788c2ecf20Sopenharmony_ci * Last action on the pci control structure. 1798c2ecf20Sopenharmony_ci * 1808c2ecf20Sopenharmony_ci * @pci: pointer to struct &edac_pci_ctl_info 1818c2ecf20Sopenharmony_ci * 1828c2ecf20Sopenharmony_ci * Calls the remove sysfs information, which will unregister 1838c2ecf20Sopenharmony_ci * this control struct's kobj. When that kobj's ref count 1848c2ecf20Sopenharmony_ci * goes to zero, its release function will be call and then 1858c2ecf20Sopenharmony_ci * kfree() the memory. 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ciextern void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci/** 1908c2ecf20Sopenharmony_ci * edac_pci_alloc_index: Allocate a unique PCI index number 1918c2ecf20Sopenharmony_ci * 1928c2ecf20Sopenharmony_ci * Returns: 1938c2ecf20Sopenharmony_ci * allocated index number 1948c2ecf20Sopenharmony_ci * 1958c2ecf20Sopenharmony_ci */ 1968c2ecf20Sopenharmony_ciextern int edac_pci_alloc_index(void); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/** 1998c2ecf20Sopenharmony_ci * edac_pci_add_device(): Insert the 'edac_dev' structure into the 2008c2ecf20Sopenharmony_ci * edac_pci global list and create sysfs entries associated with 2018c2ecf20Sopenharmony_ci * edac_pci structure. 2028c2ecf20Sopenharmony_ci * 2038c2ecf20Sopenharmony_ci * @pci: pointer to the edac_device structure to be added to the list 2048c2ecf20Sopenharmony_ci * @edac_idx: A unique numeric identifier to be assigned to the 2058c2ecf20Sopenharmony_ci * 'edac_pci' structure. 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * Returns: 2088c2ecf20Sopenharmony_ci * 0 on Success, or an error code on failure 2098c2ecf20Sopenharmony_ci */ 2108c2ecf20Sopenharmony_ciextern int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci/** 2138c2ecf20Sopenharmony_ci * edac_pci_del_device() 2148c2ecf20Sopenharmony_ci * Remove sysfs entries for specified edac_pci structure and 2158c2ecf20Sopenharmony_ci * then remove edac_pci structure from global list 2168c2ecf20Sopenharmony_ci * 2178c2ecf20Sopenharmony_ci * @dev: 2188c2ecf20Sopenharmony_ci * Pointer to 'struct device' representing edac_pci structure 2198c2ecf20Sopenharmony_ci * to remove 2208c2ecf20Sopenharmony_ci * 2218c2ecf20Sopenharmony_ci * Returns: 2228c2ecf20Sopenharmony_ci * Pointer to removed edac_pci structure, 2238c2ecf20Sopenharmony_ci * or %NULL if device not found 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ciextern struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci/** 2288c2ecf20Sopenharmony_ci * edac_pci_create_generic_ctl() 2298c2ecf20Sopenharmony_ci * A generic constructor for a PCI parity polling device 2308c2ecf20Sopenharmony_ci * Some systems have more than one domain of PCI busses. 2318c2ecf20Sopenharmony_ci * For systems with one domain, then this API will 2328c2ecf20Sopenharmony_ci * provide for a generic poller. 2338c2ecf20Sopenharmony_ci * 2348c2ecf20Sopenharmony_ci * @dev: pointer to struct &device; 2358c2ecf20Sopenharmony_ci * @mod_name: name of the PCI device 2368c2ecf20Sopenharmony_ci * 2378c2ecf20Sopenharmony_ci * This routine calls the edac_pci_alloc_ctl_info() for 2388c2ecf20Sopenharmony_ci * the generic device, with default values 2398c2ecf20Sopenharmony_ci * 2408c2ecf20Sopenharmony_ci * Returns: Pointer to struct &edac_pci_ctl_info on success, %NULL on 2418c2ecf20Sopenharmony_ci * failure. 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_ciextern struct edac_pci_ctl_info *edac_pci_create_generic_ctl( 2448c2ecf20Sopenharmony_ci struct device *dev, 2458c2ecf20Sopenharmony_ci const char *mod_name); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci/** 2488c2ecf20Sopenharmony_ci * edac_pci_release_generic_ctl 2498c2ecf20Sopenharmony_ci * The release function of a generic EDAC PCI polling device 2508c2ecf20Sopenharmony_ci * 2518c2ecf20Sopenharmony_ci * @pci: pointer to struct &edac_pci_ctl_info 2528c2ecf20Sopenharmony_ci */ 2538c2ecf20Sopenharmony_ciextern void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci/** 2568c2ecf20Sopenharmony_ci * edac_pci_create_sysfs 2578c2ecf20Sopenharmony_ci * Create the controls/attributes for the specified EDAC PCI device 2588c2ecf20Sopenharmony_ci * 2598c2ecf20Sopenharmony_ci * @pci: pointer to struct &edac_pci_ctl_info 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_ciextern int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci/** 2648c2ecf20Sopenharmony_ci * edac_pci_remove_sysfs() 2658c2ecf20Sopenharmony_ci * remove the controls and attributes for this EDAC PCI device 2668c2ecf20Sopenharmony_ci * 2678c2ecf20Sopenharmony_ci * @pci: pointer to struct &edac_pci_ctl_info 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_ciextern void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci#endif 272