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