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