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
31static struct proc_dir_entry * iSeries_proc_root = NULL;
32static int iSeries_proc_initializationDone = 0;
33static spinlock_t iSeries_proc_lock;
34
35struct iSeries_proc_registration
36{
37	struct iSeries_proc_registration *next;
38	iSeriesProcFunction functionMember;
39};
40
41
42struct iSeries_proc_registration preallocated[16];
43#define MYQUEUETYPE(T) struct MYQueue##T
44#define MYQUEUE(T) \
45MYQUEUETYPE(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) \
52do { \
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) \
63do { \
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)
72MYQUEUE(iSeries_proc_registration);
73typedef MYQUEUETYPE(iSeries_proc_registration) aQueue;
74
75
76aQueue iSeries_free;
77aQueue iSeries_queued;
78
79void 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
95void 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
117void 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