1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Defines, structures, APIs for edac_pci and edac_pci_sysfs
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * (C) 2007 Linux Networx (http://lnxi.com)
5*4882a593Smuzhiyun * This file may be distributed under the terms of the
6*4882a593Smuzhiyun * GNU General Public License.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Written by Thayne Harbaugh
9*4882a593Smuzhiyun * Based on work by Dan Hollis <goemon at anime dot net> and others.
10*4882a593Smuzhiyun * http://www.anime.net/~goemon/linux-ecc/
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * NMI handling support added by
13*4882a593Smuzhiyun * Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * Refactored for multi-source files:
16*4882a593Smuzhiyun * Doug Thompson <norsk5@xmission.com>
17*4882a593Smuzhiyun *
18*4882a593Smuzhiyun * Please look at Documentation/driver-api/edac.rst for more info about
19*4882a593Smuzhiyun * EDAC core structs and functions.
20*4882a593Smuzhiyun */
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #ifndef _EDAC_PCI_H_
23*4882a593Smuzhiyun #define _EDAC_PCI_H_
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include <linux/completion.h>
26*4882a593Smuzhiyun #include <linux/device.h>
27*4882a593Smuzhiyun #include <linux/edac.h>
28*4882a593Smuzhiyun #include <linux/kobject.h>
29*4882a593Smuzhiyun #include <linux/list.h>
30*4882a593Smuzhiyun #include <linux/pci.h>
31*4882a593Smuzhiyun #include <linux/types.h>
32*4882a593Smuzhiyun #include <linux/workqueue.h>
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #ifdef CONFIG_PCI
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun struct edac_pci_counter {
37*4882a593Smuzhiyun atomic_t pe_count;
38*4882a593Smuzhiyun atomic_t npe_count;
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun /*
42*4882a593Smuzhiyun * Abstract edac_pci control info structure
43*4882a593Smuzhiyun *
44*4882a593Smuzhiyun */
45*4882a593Smuzhiyun struct edac_pci_ctl_info {
46*4882a593Smuzhiyun /* for global list of edac_pci_ctl_info structs */
47*4882a593Smuzhiyun struct list_head link;
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun int pci_idx;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun struct bus_type *edac_subsys; /* pointer to subsystem */
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun /* the internal state of this controller instance */
54*4882a593Smuzhiyun int op_state;
55*4882a593Smuzhiyun /* work struct for this instance */
56*4882a593Smuzhiyun struct delayed_work work;
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun /* pointer to edac polling checking routine:
59*4882a593Smuzhiyun * If NOT NULL: points to polling check routine
60*4882a593Smuzhiyun * If NULL: Then assumes INTERRUPT operation, where
61*4882a593Smuzhiyun * MC driver will receive events
62*4882a593Smuzhiyun */
63*4882a593Smuzhiyun void (*edac_check) (struct edac_pci_ctl_info * edac_dev);
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun struct device *dev; /* pointer to device structure */
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun const char *mod_name; /* module name */
68*4882a593Smuzhiyun const char *ctl_name; /* edac controller name */
69*4882a593Smuzhiyun const char *dev_name; /* pci/platform/etc... name */
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun void *pvt_info; /* pointer to 'private driver' info */
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun unsigned long start_time; /* edac_pci load start time (jiffies) */
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun struct completion complete;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun /* sysfs top name under 'edac' directory
78*4882a593Smuzhiyun * and instance name:
79*4882a593Smuzhiyun * cpu/cpu0/...
80*4882a593Smuzhiyun * cpu/cpu1/...
81*4882a593Smuzhiyun * cpu/cpu2/...
82*4882a593Smuzhiyun * ...
83*4882a593Smuzhiyun */
84*4882a593Smuzhiyun char name[EDAC_DEVICE_NAME_LEN + 1];
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun /* Event counters for the this whole EDAC Device */
87*4882a593Smuzhiyun struct edac_pci_counter counters;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun /* edac sysfs device control for the 'name'
90*4882a593Smuzhiyun * device this structure controls
91*4882a593Smuzhiyun */
92*4882a593Smuzhiyun struct kobject kobj;
93*4882a593Smuzhiyun };
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun #define to_edac_pci_ctl_work(w) \
96*4882a593Smuzhiyun container_of(w, struct edac_pci_ctl_info,work)
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /* write all or some bits in a byte-register*/
pci_write_bits8(struct pci_dev * pdev,int offset,u8 value,u8 mask)99*4882a593Smuzhiyun static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value,
100*4882a593Smuzhiyun u8 mask)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun if (mask != 0xff) {
103*4882a593Smuzhiyun u8 buf;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun pci_read_config_byte(pdev, offset, &buf);
106*4882a593Smuzhiyun value &= mask;
107*4882a593Smuzhiyun buf &= ~mask;
108*4882a593Smuzhiyun value |= buf;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun pci_write_config_byte(pdev, offset, value);
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun /* write all or some bits in a word-register*/
pci_write_bits16(struct pci_dev * pdev,int offset,u16 value,u16 mask)115*4882a593Smuzhiyun static inline void pci_write_bits16(struct pci_dev *pdev, int offset,
116*4882a593Smuzhiyun u16 value, u16 mask)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun if (mask != 0xffff) {
119*4882a593Smuzhiyun u16 buf;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun pci_read_config_word(pdev, offset, &buf);
122*4882a593Smuzhiyun value &= mask;
123*4882a593Smuzhiyun buf &= ~mask;
124*4882a593Smuzhiyun value |= buf;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun pci_write_config_word(pdev, offset, value);
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /*
131*4882a593Smuzhiyun * pci_write_bits32
132*4882a593Smuzhiyun *
133*4882a593Smuzhiyun * edac local routine to do pci_write_config_dword, but adds
134*4882a593Smuzhiyun * a mask parameter. If mask is all ones, ignore the mask.
135*4882a593Smuzhiyun * Otherwise utilize the mask to isolate specified bits
136*4882a593Smuzhiyun *
137*4882a593Smuzhiyun * write all or some bits in a dword-register
138*4882a593Smuzhiyun */
pci_write_bits32(struct pci_dev * pdev,int offset,u32 value,u32 mask)139*4882a593Smuzhiyun static inline void pci_write_bits32(struct pci_dev *pdev, int offset,
140*4882a593Smuzhiyun u32 value, u32 mask)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun if (mask != 0xffffffff) {
143*4882a593Smuzhiyun u32 buf;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun pci_read_config_dword(pdev, offset, &buf);
146*4882a593Smuzhiyun value &= mask;
147*4882a593Smuzhiyun buf &= ~mask;
148*4882a593Smuzhiyun value |= buf;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun pci_write_config_dword(pdev, offset, value);
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun #endif /* CONFIG_PCI */
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun /*
157*4882a593Smuzhiyun * edac_pci APIs
158*4882a593Smuzhiyun */
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /**
161*4882a593Smuzhiyun * edac_pci_alloc_ctl_info:
162*4882a593Smuzhiyun * The alloc() function for the 'edac_pci' control info
163*4882a593Smuzhiyun * structure.
164*4882a593Smuzhiyun *
165*4882a593Smuzhiyun * @sz_pvt: size of the private info at struct &edac_pci_ctl_info
166*4882a593Smuzhiyun * @edac_pci_name: name of the PCI device
167*4882a593Smuzhiyun *
168*4882a593Smuzhiyun * The chip driver will allocate one of these for each
169*4882a593Smuzhiyun * edac_pci it is going to control/register with the EDAC CORE.
170*4882a593Smuzhiyun *
171*4882a593Smuzhiyun * Returns: a pointer to struct &edac_pci_ctl_info on success; %NULL otherwise.
172*4882a593Smuzhiyun */
173*4882a593Smuzhiyun extern struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt,
174*4882a593Smuzhiyun const char *edac_pci_name);
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun /**
177*4882a593Smuzhiyun * edac_pci_free_ctl_info():
178*4882a593Smuzhiyun * Last action on the pci control structure.
179*4882a593Smuzhiyun *
180*4882a593Smuzhiyun * @pci: pointer to struct &edac_pci_ctl_info
181*4882a593Smuzhiyun *
182*4882a593Smuzhiyun * Calls the remove sysfs information, which will unregister
183*4882a593Smuzhiyun * this control struct's kobj. When that kobj's ref count
184*4882a593Smuzhiyun * goes to zero, its release function will be call and then
185*4882a593Smuzhiyun * kfree() the memory.
186*4882a593Smuzhiyun */
187*4882a593Smuzhiyun extern void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci);
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun /**
190*4882a593Smuzhiyun * edac_pci_alloc_index: Allocate a unique PCI index number
191*4882a593Smuzhiyun *
192*4882a593Smuzhiyun * Returns:
193*4882a593Smuzhiyun * allocated index number
194*4882a593Smuzhiyun *
195*4882a593Smuzhiyun */
196*4882a593Smuzhiyun extern int edac_pci_alloc_index(void);
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun /**
199*4882a593Smuzhiyun * edac_pci_add_device(): Insert the 'edac_dev' structure into the
200*4882a593Smuzhiyun * edac_pci global list and create sysfs entries associated with
201*4882a593Smuzhiyun * edac_pci structure.
202*4882a593Smuzhiyun *
203*4882a593Smuzhiyun * @pci: pointer to the edac_device structure to be added to the list
204*4882a593Smuzhiyun * @edac_idx: A unique numeric identifier to be assigned to the
205*4882a593Smuzhiyun * 'edac_pci' structure.
206*4882a593Smuzhiyun *
207*4882a593Smuzhiyun * Returns:
208*4882a593Smuzhiyun * 0 on Success, or an error code on failure
209*4882a593Smuzhiyun */
210*4882a593Smuzhiyun extern int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx);
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun /**
213*4882a593Smuzhiyun * edac_pci_del_device()
214*4882a593Smuzhiyun * Remove sysfs entries for specified edac_pci structure and
215*4882a593Smuzhiyun * then remove edac_pci structure from global list
216*4882a593Smuzhiyun *
217*4882a593Smuzhiyun * @dev:
218*4882a593Smuzhiyun * Pointer to 'struct device' representing edac_pci structure
219*4882a593Smuzhiyun * to remove
220*4882a593Smuzhiyun *
221*4882a593Smuzhiyun * Returns:
222*4882a593Smuzhiyun * Pointer to removed edac_pci structure,
223*4882a593Smuzhiyun * or %NULL if device not found
224*4882a593Smuzhiyun */
225*4882a593Smuzhiyun extern struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev);
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun /**
228*4882a593Smuzhiyun * edac_pci_create_generic_ctl()
229*4882a593Smuzhiyun * A generic constructor for a PCI parity polling device
230*4882a593Smuzhiyun * Some systems have more than one domain of PCI busses.
231*4882a593Smuzhiyun * For systems with one domain, then this API will
232*4882a593Smuzhiyun * provide for a generic poller.
233*4882a593Smuzhiyun *
234*4882a593Smuzhiyun * @dev: pointer to struct &device;
235*4882a593Smuzhiyun * @mod_name: name of the PCI device
236*4882a593Smuzhiyun *
237*4882a593Smuzhiyun * This routine calls the edac_pci_alloc_ctl_info() for
238*4882a593Smuzhiyun * the generic device, with default values
239*4882a593Smuzhiyun *
240*4882a593Smuzhiyun * Returns: Pointer to struct &edac_pci_ctl_info on success, %NULL on
241*4882a593Smuzhiyun * failure.
242*4882a593Smuzhiyun */
243*4882a593Smuzhiyun extern struct edac_pci_ctl_info *edac_pci_create_generic_ctl(
244*4882a593Smuzhiyun struct device *dev,
245*4882a593Smuzhiyun const char *mod_name);
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun /**
248*4882a593Smuzhiyun * edac_pci_release_generic_ctl
249*4882a593Smuzhiyun * The release function of a generic EDAC PCI polling device
250*4882a593Smuzhiyun *
251*4882a593Smuzhiyun * @pci: pointer to struct &edac_pci_ctl_info
252*4882a593Smuzhiyun */
253*4882a593Smuzhiyun extern void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci);
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun /**
256*4882a593Smuzhiyun * edac_pci_create_sysfs
257*4882a593Smuzhiyun * Create the controls/attributes for the specified EDAC PCI device
258*4882a593Smuzhiyun *
259*4882a593Smuzhiyun * @pci: pointer to struct &edac_pci_ctl_info
260*4882a593Smuzhiyun */
261*4882a593Smuzhiyun extern int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci);
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun /**
264*4882a593Smuzhiyun * edac_pci_remove_sysfs()
265*4882a593Smuzhiyun * remove the controls and attributes for this EDAC PCI device
266*4882a593Smuzhiyun *
267*4882a593Smuzhiyun * @pci: pointer to struct &edac_pci_ctl_info
268*4882a593Smuzhiyun */
269*4882a593Smuzhiyun extern void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci);
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun #endif
272