1 /************************************************************************/
2 /* File pcifr_proc.c created by Allan Trautman on Thu Aug 2 2001. */
3 /************************************************************************/
4 /* Supports the ../proc/ppc64/pcifr for the pci flight recorder. */
5 /* Copyright (C) 20yy <Allan H Trautman> <IBM Corp> */
6 /* */
7 /* This program is free software; you can redistribute it and/or modify */
8 /* it under the terms of the GNU General Public License as published by */
9 /* the Free Software Foundation; either version 2 of the License, or */
10 /* (at your option) any later version. */
11 /* */
12 /* This program is distributed in the hope that it will be useful, */
13 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
14 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
15 /* GNU General Public License for more details. */
16 /* */
17 /* You should have received a copy of the GNU General Public License */
18 /* along with this program; if not, write to the: */
19 /* Free Software Foundation, Inc., */
20 /* 59 Temple Place, Suite 330, */
21 /* Boston, MA 02111-1307 USA */
22 /************************************************************************/
23 #include <stdarg.h>
24 #include <linux/kernel.h>
25
26 #include <linux/proc_fs.h>
27 #include <asm/uaccess.h>
28 #include <asm/time.h>
29
30 #include <linux/pci.h>
31 #include <asm/pci-bridge.h>
32 #include <linux/netdevice.h>
33
34 #include <asm/flight_recorder.h>
35 #include <asm/iSeries/iSeries_pci.h>
36 #include "pci.h"
37
38 void pci_Fr_TestCode(void);
39
40 static spinlock_t proc_pcifr_lock;
41 struct flightRecorder* PciFr = NULL;
42
43 extern long Pci_Interrupt_Count;
44 extern long Pci_Event_Count;
45 extern long Pci_Io_Read_Count;
46 extern long Pci_Io_Write_Count;
47 extern long Pci_Cfg_Read_Count;
48 extern long Pci_Cfg_Write_Count;
49 extern long Pci_Error_Count;
50
51 /************************************************************************/
52 /* Forward declares. */
53 /************************************************************************/
54 static struct proc_dir_entry *pciFr_proc_root = NULL;
55 int proc_pciFr_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);
56 int proc_pciFr_write_proc(struct file *file, const char *buffer, unsigned long count, void *data);
57
58 static struct proc_dir_entry *pciDev_proc_root = NULL;
59 int proc_pciDev_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);
60 int proc_pciDev_write_proc(struct file *file, const char *buffer, unsigned long count, void *data);
61
62 /************************************************************************/
63 /* Create entry ../proc/ppc64/pcifr */
64 /************************************************************************/
proc_pciFr_init(struct proc_dir_entry * proc_ppc64_root)65 void proc_pciFr_init(struct proc_dir_entry *proc_ppc64_root)
66 {
67 if (proc_ppc64_root == NULL) return;
68
69 /* Read = User,Group,Other, Write User */
70 printk("PCI: Creating ../proc/ppc64/pcifr \n");
71 spin_lock(&proc_pcifr_lock);
72 pciFr_proc_root = create_proc_entry("pcifr", S_IFREG | S_IRUGO | S_IWUSR, proc_ppc64_root);
73 spin_unlock(&proc_pcifr_lock);
74
75 if (pciFr_proc_root == NULL) return;
76
77 pciFr_proc_root->nlink = 1;
78 pciFr_proc_root->data = (void *)0;
79 pciFr_proc_root->read_proc = proc_pciFr_read_proc;
80 pciFr_proc_root->write_proc = proc_pciFr_write_proc;
81
82 PciFr = alloc_Flight_Recorder(NULL,"PciFr", 4096);
83
84 printk("PCI: Creating ../proc/ppc64/pci \n");
85 spin_lock(&proc_pcifr_lock);
86 pciDev_proc_root = create_proc_entry("pci", S_IFREG | S_IRUGO | S_IWUSR, proc_ppc64_root);
87 spin_unlock(&proc_pcifr_lock);
88
89 if (pciDev_proc_root == NULL) return;
90
91 pciDev_proc_root->nlink = 1;
92 pciDev_proc_root->data = (void *)0;
93 pciDev_proc_root->read_proc = proc_pciDev_read_proc;
94 pciDev_proc_root->write_proc = proc_pciDev_write_proc;
95 }
96
97 static char* PciFrBuffer = NULL;
98 static int PciFrBufLen = 0;
99 static char* PciFrBufPtr = NULL;
100 static int PciFileSize = 0;
101
102 /*******************************************************************************/
103 /* Read function for ../proc/ppc64/pcifr. */
104 /* -> Function grabs a copy of the pcifr(could change) and writes the data to */
105 /* the caller. Note, it may not all fit in the buffer. The function */
106 /* handles the repeated calls until all the data has been read. */
107 /* Tip: */
108 /* ./fs/proc/generic.c::proc_file_read is the caller of this routine. */
109 /*******************************************************************************/
proc_pciFr_read_proc(char * page,char ** start,off_t off,int count,int * eof,void * data)110 int proc_pciFr_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
111 {
112 /* First call will have offset 0, get snapshot the pcifr */
113 if( off == 0) {
114 spin_lock(&proc_pcifr_lock);
115 PciFrBuffer = (char*)kmalloc(PciFr->Size, GFP_KERNEL);
116 PciFrBufLen = fr_Dump(PciFr,PciFrBuffer, PciFr->Size);
117 PciFrBufPtr = PciFrBuffer;
118 PciFileSize = 0;
119 }
120 /* For the persistant folks, set eof and return zero length. */
121 else if( PciFrBuffer == NULL) {
122 *eof = 1;
123 return 0;
124 }
125 /* - If there is more data than will fit, move what will fit. */
126 /* - The rest will get moved on the next call. */
127 int MoveSize = PciFrBufLen;
128 if( MoveSize > count) MoveSize = count;
129
130 /* Move the data info the FileSystem buffer. */
131 memcpy(page+off,PciFrBufPtr,MoveSize);
132 PciFrBufPtr += MoveSize;
133 PciFileSize += MoveSize;
134 PciFrBufLen -= MoveSize;
135
136 /* If all the data has been moved, free the buffer and set EOF. */
137 if( PciFrBufLen == 0) {
138 kfree(PciFrBuffer);
139 PciFrBuffer = NULL;
140 spin_unlock(&proc_pcifr_lock);
141 *eof = 1;
142 }
143 return PciFileSize;
144 }
145 /*******************************************************************************/
146 /* Gets called when client writes to ../proc/ppc64/pcifr */
147 /*******************************************************************************/
proc_pciFr_write_proc(struct file * file,const char * buffer,unsigned long count,void * data)148 int proc_pciFr_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
149 {
150 return count;
151 }
152 static spinlock_t ProcBufferLock;
153 static char* ProcBuffer = NULL;
154 static int ProcBufSize = 0;
155 static char* ProcBufPtr = NULL;
156 static int ProcFileSize = 0;
157
158 /*******************************************************************************/
159 /* Build Device Buffer for /proc/ppc64/pci */
160 /*******************************************************************************/
build_PciDev_Buffer(int BufferSize)161 static int build_PciDev_Buffer(int BufferSize)
162 {
163 ProcBuffer = (char*)kmalloc(BufferSize, GFP_KERNEL);
164 ProcBufPtr = ProcBuffer;
165
166 int BufLen = 0;
167
168 BufLen += sprintf(ProcBuffer+BufLen,"Pci I/O Reads. %8ld ",Pci_Io_Read_Count);
169 BufLen += sprintf(ProcBuffer+BufLen,"Pci I/O Writes %8ld\n",Pci_Io_Write_Count);
170
171 BufLen += sprintf(ProcBuffer+BufLen,"Pci Cfg Reads. %8ld ",Pci_Cfg_Read_Count);
172 BufLen += sprintf(ProcBuffer+BufLen,"Pci Cfg Writes %8ld\n",Pci_Cfg_Write_Count);
173
174 BufLen += sprintf(ProcBuffer+BufLen,"Pci I/O Errors %8ld\n",Pci_Error_Count);
175 BufLen += sprintf(ProcBuffer+BufLen,"\n");
176
177 /***************************************************************************/
178 /* List the devices */
179 /***************************************************************************/
180 struct pci_dev* PciDev; /* Device pointer */
181 struct net_device* dev; /* net_device pointer */
182 int DeviceCount = 0;
183 pci_for_each_dev(PciDev) {
184 if ( BufLen > BufferSize-128) { /* Room for another line? */
185 BufLen +=sprintf(ProcBuffer+BufLen,"Buffer Full\n");
186 break;
187 }
188 if( PCI_SLOT(PciDev->devfn) != 0) {
189 ++DeviceCount;
190 BufLen += sprintf(ProcBuffer+BufLen,"%3d. ",DeviceCount);
191 if ( PciDev->sysdata != NULL ) {
192 BufLen += format_device_location(PciDev,ProcBuffer+BufLen,128);
193 }
194 else {
195 BufLen += sprintf(ProcBuffer+BufLen,"No Device Node!\n");
196 }
197 BufLen += sprintf(ProcBuffer+BufLen,"\n");
198
199 /* look for the net devices out */
200 for (dev = dev_base; dev != NULL; dev = dev->next) {
201 int j;
202
203 if (!dev->base_addr) /* virtual device, no base address */
204 break;
205
206 for (j=0;j<6;j++) { /* PCI has 6 base addresses */
207 if (dev->base_addr == PciDev->resource[j].start ) {
208 BufLen += sprintf(ProcBuffer+BufLen, " - Net device: %s\n", dev->name);
209 break;
210 } /* if */
211 }
212 if (j!=6) break; /* found one */
213 } /* for */
214 } /* if(PCI_SLOT(PciDev->devfn) != 0) */
215 }
216 return BufLen;
217 }
218 /*******************************************************************************/
219 /* Get called when client reads the ../proc/ppc64/pcifr. */
220 /*******************************************************************************/
proc_pciDev_read_proc(char * page,char ** start,off_t off,int count,int * eof,void * data)221 int proc_pciDev_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
222 {
223 /* First call will have offset 0 */
224 if( off == 0) {
225 spin_lock(&ProcBufferLock);
226 ProcBufSize = build_PciDev_Buffer(4096);
227 ProcFileSize = 0;
228 }
229 /* For the persistant folks, set eof and return zero length. */
230 else if( ProcBuffer == NULL) {
231 *eof = 1;
232 return 0;
233 }
234 /* How much data can be moved */
235 int MoveSize = ProcBufSize;
236 if( MoveSize > count) MoveSize = count;
237
238 /* Move the data info the FileSystem buffer. */
239 memcpy(page+off,ProcBufPtr,MoveSize);
240 ProcBufPtr += MoveSize;
241 ProcBufSize -= MoveSize;
242 ProcFileSize += MoveSize;
243
244 /* If all the data has been moved, free the buffer and set EOF. */
245 if( ProcBufSize == 0) {
246 kfree(ProcBuffer );
247 ProcBuffer = NULL;
248 spin_unlock(&ProcBufferLock);
249 *eof = 1;
250 }
251 return ProcFileSize;
252 }
253 /*******************************************************************************/
254 /* Gets called when client writes to ../proc/ppc64/pcifr */
255 /*******************************************************************************/
proc_pciDev_write_proc(struct file * file,const char * buffer,unsigned long count,void * data)256 int proc_pciDev_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
257 {
258 return count;
259 }
260