/* * iSeries_proc.c * Copyright (C) 2001 Kyle A. Lucke IBM Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/proc_fs.h> #include <linux/spinlock.h> #include <linux/init.h> #include <linux/module.h> #include <asm/iSeries/iSeries_proc.h> static struct proc_dir_entry *iSeries_proc_root; static int iSeries_proc_initializationDone; static spinlock_t iSeries_proc_lock; struct iSeries_proc_registration { struct iSeries_proc_registration *next; iSeriesProcFunction functionMember; }; struct iSeries_proc_registration preallocated[16]; #define MYQUEUETYPE(T) struct MYQueue##T #define MYQUEUE(T) \ MYQUEUETYPE(T) \ { \ struct T *head; \ struct T *tail; \ } #define MYQUEUECTOR(q) do { (q)->head = NULL; (q)->tail = NULL; } while(0) #define MYQUEUEENQ(q, p) \ do { \ (p)->next = NULL; \ if ((q)->head != NULL) { \ (q)->head->next = (p); \ (q)->head = (p); \ } else { \ (q)->tail = (q)->head = (p); \ } \ } while(0) #define MYQUEUEDEQ(q,p) \ do { \ (p) = (q)->tail; \ if ((p) != NULL) { \ (q)->tail = (p)->next; \ (p)->next = NULL; \ } \ if ((q)->tail == NULL) \ (q)->head = NULL; \ } while(0) MYQUEUE(iSeries_proc_registration); typedef MYQUEUETYPE(iSeries_proc_registration) aQueue; static aQueue iSeries_free; static aQueue iSeries_queued; void iSeries_proc_early_init(void) { int i = 0; unsigned long flags; iSeries_proc_initializationDone = 0; spin_lock_init(&iSeries_proc_lock); MYQUEUECTOR(&iSeries_free); MYQUEUECTOR(&iSeries_queued); spin_lock_irqsave(&iSeries_proc_lock, flags); for (i = 0; i < 16; ++i) MYQUEUEENQ(&iSeries_free, preallocated + i); spin_unlock_irqrestore(&iSeries_proc_lock, flags); } static int iSeries_proc_create(void) { unsigned long flags; struct iSeries_proc_registration *reg; printk("iSeries_proc: Creating /proc/iSeries\n"); spin_lock_irqsave(&iSeries_proc_lock, flags); iSeries_proc_root = proc_mkdir("iSeries", 0); if (!iSeries_proc_root) goto out; MYQUEUEDEQ(&iSeries_queued, reg); while (reg != NULL) { (*(reg->functionMember))(iSeries_proc_root); MYQUEUEDEQ(&iSeries_queued, reg); } iSeries_proc_initializationDone = 1; out: spin_unlock_irqrestore(&iSeries_proc_lock, flags); return 0; } arch_initcall(iSeries_proc_create); void iSeries_proc_callback(iSeriesProcFunction initFunction) { unsigned long flags; spin_lock_irqsave(&iSeries_proc_lock, flags); if (iSeries_proc_initializationDone) (*initFunction)(iSeries_proc_root); else { struct iSeries_proc_registration *reg = NULL; MYQUEUEDEQ(&iSeries_free, reg); if (reg != NULL) { reg->functionMember = initFunction; MYQUEUEENQ(&iSeries_queued, reg); } else printk("Couldn't get a queue entry\n"); } spin_unlock_irqrestore(&iSeries_proc_lock, flags); } EXPORT_SYMBOL(iSeries_proc_callback);