1 /*
2   * iSeries_proc.c
3   * Copyright (C) 2001  Kyle A. Lucke IBM Corporation
4   *
5   * This program is free software; you can redistribute it and/or modify
6   * it under the terms of the GNU General Public License as published by
7   * the Free Software Foundation; either version 2 of the License, or
8   * (at your option) any later version.
9   *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with this program; if not, write to the Free Software
17   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18   */
19 
20 
21 /* Change Activity: */
22 /* End Change Activity */
23 
24 #include <linux/proc_fs.h>
25 #include <linux/spinlock.h>
26 #ifndef _ISERIES_PROC_H
27 #include <asm/iSeries/iSeries_proc.h>
28 #endif
29 
30 
31 static struct proc_dir_entry * iSeries_proc_root = NULL;
32 static int iSeries_proc_initializationDone = 0;
33 static spinlock_t iSeries_proc_lock;
34 
35 struct iSeries_proc_registration
36 {
37 	struct iSeries_proc_registration *next;
38 	iSeriesProcFunction functionMember;
39 };
40 
41 
42 struct iSeries_proc_registration preallocated[16];
43 #define MYQUEUETYPE(T) struct MYQueue##T
44 #define MYQUEUE(T) \
45 MYQUEUETYPE(T) \
46 { \
47 	struct T *head; \
48 	struct T *tail; \
49 }
50 #define MYQUEUECTOR(q) do { (q)->head = NULL; (q)->tail = NULL; } while(0)
51 #define MYQUEUEENQ(q, p) \
52 do { \
53 	(p)->next = NULL; \
54 	if ((q)->head != NULL) { \
55 		(q)->head->next = (p); \
56 		(q)->head = (p); \
57 	} else { \
58 		(q)->tail = (q)->head = (p); \
59 	} \
60 } while(0)
61 
62 #define MYQUEUEDEQ(q,p) \
63 do { \
64 	(p) = (q)->tail; \
65 	if ((p) != NULL) { \
66 		(q)->tail = (p)->next; \
67 		(p)->next = NULL; \
68 	} \
69 	if ((q)->tail == NULL) \
70 		(q)->head = NULL; \
71 } while(0)
72 MYQUEUE(iSeries_proc_registration);
73 typedef MYQUEUETYPE(iSeries_proc_registration) aQueue;
74 
75 
76 aQueue iSeries_free;
77 aQueue iSeries_queued;
78 
iSeries_proc_early_init(void)79 void iSeries_proc_early_init(void)
80 {
81 	int i = 0;
82 	unsigned long flags;
83 	iSeries_proc_initializationDone = 0;
84 	spin_lock_init(&iSeries_proc_lock);
85 	MYQUEUECTOR(&iSeries_free);
86 	MYQUEUECTOR(&iSeries_queued);
87 
88 	spin_lock_irqsave(&iSeries_proc_lock, flags);
89 	for (i = 0; i < 16; ++i) {
90 		MYQUEUEENQ(&iSeries_free, preallocated+i);
91 	}
92 	spin_unlock_irqrestore(&iSeries_proc_lock, flags);
93 }
94 
iSeries_proc_create(void)95 void iSeries_proc_create(void)
96 {
97 	unsigned long flags;
98 	struct iSeries_proc_registration *reg = NULL;
99 	spin_lock_irqsave(&iSeries_proc_lock, flags);
100 	printk("iSeries_proc: Creating /proc/iSeries\n");
101 
102 	iSeries_proc_root = proc_mkdir("iSeries", 0);
103 	if (!iSeries_proc_root) return;
104 
105 	MYQUEUEDEQ(&iSeries_queued, reg);
106 
107 	while (reg != NULL) {
108 		(*(reg->functionMember))(iSeries_proc_root);
109 
110 		MYQUEUEDEQ(&iSeries_queued, reg);
111 	}
112 
113 	iSeries_proc_initializationDone = 1;
114 	spin_unlock_irqrestore(&iSeries_proc_lock, flags);
115 }
116 
iSeries_proc_callback(iSeriesProcFunction initFunction)117 void iSeries_proc_callback(iSeriesProcFunction initFunction)
118 {
119 	unsigned long flags;
120 	spin_lock_irqsave(&iSeries_proc_lock, flags);
121 
122 	if (iSeries_proc_initializationDone) {
123 		(*initFunction)(iSeries_proc_root);
124 	} else {
125 		struct iSeries_proc_registration *reg = NULL;
126 
127 		MYQUEUEDEQ(&iSeries_free, reg);
128 
129 		if (reg != NULL) {
130 			/* printk("Registering %p in reg %p\n", initFunction, reg); */
131 			reg->functionMember = initFunction;
132 
133 			MYQUEUEENQ(&iSeries_queued, reg);
134 		} else {
135 			printk("Couldn't get a queue entry\n");
136 		}
137 	}
138 
139 	spin_unlock_irqrestore(&iSeries_proc_lock, flags);
140 }
141 
142 
143