vserver 1.9.5.x5
[linux-2.6.git] / arch / ppc64 / kernel / mf.c
index 02a68b1..1bd52ec 100644 (file)
@@ -1,6 +1,7 @@
 /*
   * mf.c
   * Copyright (C) 2001 Troy D. Armstrong  IBM Corporation
+  * Copyright (C) 2004 Stephen Rothwell  IBM Corporation
   *
   * This modules exists as an interface between a Linux secondary partition
   * running on an iSeries and the primary partition's Virtual Service
@@ -8,52 +9,44 @@
   * all partitions in the iSeries.  It also provides miscellaneous low-level
   * machine facility type operations.
   *
-  * 
+  *
   * 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 <asm/iSeries/mf.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
 #include <linux/completion.h>
-#include <asm/iSeries/HvLpConfig.h>
-#include <linux/slab.h>
 #include <linux/delay.h>
-#include <asm/nvram.h>
-#include <asm/time.h>
-#include <asm/iSeries/ItSpCommArea.h>
-#include <asm/uaccess.h>
 #include <linux/dma-mapping.h>
 #include <linux/bcd.h>
+
+#include <asm/time.h>
+#include <asm/uaccess.h>
 #include <asm/iSeries/vio.h>
+#include <asm/iSeries/mf.h>
+#include <asm/iSeries/HvLpConfig.h>
+#include <asm/iSeries/ItSpCommArea.h>
 
 /*
  * This is the structure layout for the Machine Facilites LPAR event
  * flows.
  */
-union safe_cast {
-       u64 ptr_as_u64;
-       void *ptr;
-};
-
-struct VspCmdData {
-       union safe_cast token;
+struct vsp_cmd_data {
+       u64 token;
        u16 cmd;
        HvLpIndex lp_index;
        u8 result_code;
@@ -81,12 +74,12 @@ struct VspCmdData {
        } sub_data;
 };
 
-struct VspRspData {
+struct vsp_rsp_data {
        struct completion com;
-       struct VspCmdData *response;
+       struct vsp_cmd_data *response;
 };
 
-struct AllocData {
+struct alloc_data {
        u16 size;
        u16 type;
        u32 count;
@@ -95,30 +88,30 @@ struct AllocData {
        HvLpIndex target_lp;
 };
 
-struct CeMsgData;
+struct ce_msg_data;
 
-typedef void (*CeMsgCompleteHandler)(void *token, struct CeMsgData *vspCmdRsp);
+typedef void (*ce_msg_comp_hdlr)(void *token, struct ce_msg_data *vsp_cmd_rsp);
 
-struct CeMsgCompleteData {
-       CeMsgCompleteHandler handler;
+struct ce_msg_comp_data {
+       ce_msg_comp_hdlr handler;
        void *token;
 };
 
-struct CeMsgData {
+struct ce_msg_data {
        u8 ce_msg[12];
        char reserved[4];
-       struct CeMsgCompleteData *completion;
+       struct ce_msg_comp_data *completion;
 };
 
-struct IoMFLpEvent {
+struct io_mf_lp_event {
        struct HvLpEvent hp_lp_event;
        u16 subtype_result_code;
        u16 reserved1;
        u32 reserved2;
        union {
-               struct AllocData alloc;
-               struct CeMsgData ce_msg;
-               struct VspCmdData vsp_cmd;
+               struct alloc_data alloc;
+               struct ce_msg_data ce_msg;
+               struct vsp_cmd_data vsp_cmd;
        } data;
 };
 
@@ -134,7 +127,7 @@ struct IoMFLpEvent {
  */
 struct pending_event {
        struct pending_event *next;
-       struct IoMFLpEvent event;
+       struct io_mf_lp_event event;
        MFCompleteHandler hdlr;
        char dma_data[72];
        unsigned dma_data_length;
@@ -172,7 +165,7 @@ static int signal_event(struct pending_event *ev)
        unsigned long flags;
        int go = 1;
        struct pending_event *ev1;
-       HvLpEvent_Rc hvRc;
+       HvLpEvent_Rc hv_rc;
 
        /* enqueue the event */
        if (ev != NULL) {
@@ -199,11 +192,11 @@ static int signal_event(struct pending_event *ev)
                                        pending_event_head->dma_data_length,
                                        HvLpDma_Direction_LocalToRemote);
 
-               hvRc = HvCallEvent_signalLpEvent(
+               hv_rc = HvCallEvent_signalLpEvent(
                                &pending_event_head->event.hp_lp_event);
-               if (hvRc != HvLpEvent_Rc_Good) {
-                       printk(KERN_ERR "mf.c: HvCallEvent_signalLpEvent() failed with %d\n",
-                                       (int)hvRc);
+               if (hv_rc != HvLpEvent_Rc_Good) {
+                       printk(KERN_ERR "mf.c: HvCallEvent_signalLpEvent() "
+                                       "failed with %d\n", (int)hv_rc);
 
                        spin_lock_irqsave(&pending_event_spinlock, flags);
                        ev1 = pending_event_head;
@@ -214,12 +207,8 @@ static int signal_event(struct pending_event *ev)
 
                        if (ev1 == ev)
                                rc = -EIO;
-                       else if (ev1->hdlr != NULL) {
-                               union safe_cast mySafeCast;
-
-                               mySafeCast.ptr_as_u64 = ev1->event.hp_lp_event.xCorrelationToken;
-                               (*ev1->hdlr)(mySafeCast.ptr, -EIO);
-                       }
+                       else if (ev1->hdlr != NULL)
+                               (*ev1->hdlr)((void *)ev1->event.hp_lp_event.xCorrelationToken, -EIO);
 
                        spin_lock_irqsave(&pending_event_spinlock, flags);
                        free_pending_event(ev1);
@@ -236,7 +225,7 @@ static int signal_event(struct pending_event *ev)
 static struct pending_event *new_pending_event(void)
 {
        struct pending_event *ev = NULL;
-       HvLpIndex primaryLp = HvLpConfig_getPrimaryLpIndex();
+       HvLpIndex primary_lp = HvLpConfig_getPrimaryLpIndex();
        unsigned long flags;
        struct HvLpEvent *hev;
 
@@ -246,12 +235,13 @@ static struct pending_event *new_pending_event(void)
                pending_event_avail = pending_event_avail->next;
        }
        spin_unlock_irqrestore(&pending_event_spinlock, flags);
-       if (ev == NULL)
-               ev = kmalloc(sizeof(struct pending_event),GFP_ATOMIC);
        if (ev == NULL) {
-               printk(KERN_ERR "mf.c: unable to kmalloc %ld bytes\n",
-                               sizeof(struct pending_event));
-               return NULL;
+               ev = kmalloc(sizeof(struct pending_event), GFP_ATOMIC);
+               if (ev == NULL) {
+                       printk(KERN_ERR "mf.c: unable to kmalloc %ld bytes\n",
+                                       sizeof(struct pending_event));
+                       return NULL;
+               }
        }
        memset(ev, 0, sizeof(struct pending_event));
        hev = &ev->event.hp_lp_event;
@@ -261,38 +251,38 @@ static struct pending_event *new_pending_event(void)
        hev->xFlags.xFunction = HvLpEvent_Function_Int;
        hev->xType = HvLpEvent_Type_MachineFac;
        hev->xSourceLp = HvLpConfig_getLpIndex();
-       hev->xTargetLp = primaryLp;
-       hev->xSizeMinus1 = sizeof(ev->event)-1;
+       hev->xTargetLp = primary_lp;
+       hev->xSizeMinus1 = sizeof(ev->event) - 1;
        hev->xRc = HvLpEvent_Rc_Good;
-       hev->xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primaryLp,
+       hev->xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primary_lp,
                        HvLpEvent_Type_MachineFac);
-       hev->xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primaryLp,
+       hev->xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primary_lp,
                        HvLpEvent_Type_MachineFac);
 
        return ev;
 }
 
-static int signal_vsp_instruction(struct VspCmdData *vspCmd)
+static int signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd)
 {
        struct pending_event *ev = new_pending_event();
        int rc;
-       struct VspRspData response;
+       struct vsp_rsp_data response;
 
        if (ev == NULL)
                return -ENOMEM;
 
        init_completion(&response.com);
-       response.response = vspCmd;
+       response.response = vsp_cmd;
        ev->event.hp_lp_event.xSubtype = 6;
        ev->event.hp_lp_event.x.xSubtypeData =
                subtype_data('M', 'F',  'V',  'I');
-       ev->event.data.vsp_cmd.token.ptr = &response;
-       ev->event.data.vsp_cmd.cmd = vspCmd->cmd;
+       ev->event.data.vsp_cmd.token = (u64)&response;
+       ev->event.data.vsp_cmd.cmd = vsp_cmd->cmd;
        ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex();
        ev->event.data.vsp_cmd.result_code = 0xFF;
        ev->event.data.vsp_cmd.reserved = 0;
        memcpy(&(ev->event.data.vsp_cmd.sub_data),
-                       &(vspCmd->sub_data), sizeof(vspCmd->sub_data));
+                       &(vsp_cmd->sub_data), sizeof(vsp_cmd->sub_data));
        mb();
 
        rc = signal_event(ev);
@@ -305,7 +295,7 @@ static int signal_vsp_instruction(struct VspCmdData *vspCmd)
 /*
  * Send a 12-byte CE message to the primary partition VSP object
  */
-static int signal_ce_msg(char *ce_msg, struct CeMsgCompleteData *completion)
+static int signal_ce_msg(char *ce_msg, struct ce_msg_comp_data *completion)
 {
        struct pending_event *ev = new_pending_event();
 
@@ -320,11 +310,23 @@ static int signal_ce_msg(char *ce_msg, struct CeMsgCompleteData *completion)
        return signal_event(ev);
 }
 
+/*
+ * Send a 12-byte CE message (with no data) to the primary partition VSP object
+ */
+static int signal_ce_msg_simple(u8 ce_op, struct ce_msg_comp_data *completion)
+{
+       u8 ce_msg[12];
+
+       memset(ce_msg, 0, sizeof(ce_msg));
+       ce_msg[3] = ce_op;
+       return signal_ce_msg(ce_msg, completion);
+}
+
 /*
  * Send a 12-byte CE message and DMA data to the primary partition VSP object
  */
 static int dma_and_signal_ce_msg(char *ce_msg,
-               struct CeMsgCompleteData *completion, void *dma_data,
+               struct ce_msg_comp_data *completion, void *dma_data,
                unsigned dma_data_length, unsigned remote_address)
 {
        struct pending_event *ev = new_pending_event();
@@ -356,7 +358,7 @@ static int shutdown(void)
        if (rc) {
                printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), "
                                "hard shutdown commencing\n", rc);
-               mf_powerOff();
+               mf_power_off();
        } else
                printk(KERN_INFO "mf.c: init has been successfully notified "
                                "to proceed with shutdown\n");
@@ -367,10 +369,12 @@ static int shutdown(void)
  * The primary partition VSP object is sending us a new
  * event flow.  Handle it...
  */
-static void intReceived(struct IoMFLpEvent *event)
+static void handle_int(struct io_mf_lp_event *event)
 {
-       int freeIt = 0;
-       struct pending_event *two = NULL;
+       struct ce_msg_data *ce_msg_data;
+       struct ce_msg_data *pce_msg_data;
+       unsigned long flags;
+       struct pending_event *pev;
 
        /* ack the interrupt */
        event->hp_lp_event.xRc = HvLpEvent_Rc_Good;
@@ -379,49 +383,42 @@ static void intReceived(struct IoMFLpEvent *event)
        /* process interrupt */
        switch (event->hp_lp_event.xSubtype) {
        case 0: /* CE message */
-               switch (event->data.ce_msg.ce_msg[3]) {
+               ce_msg_data = &event->data.ce_msg;
+               switch (ce_msg_data->ce_msg[3]) {
                case 0x5B:      /* power control notification */
-                       if ((event->data.ce_msg.ce_msg[5] & 0x20) != 0) {
+                       if ((ce_msg_data->ce_msg[5] & 0x20) != 0) {
                                printk(KERN_INFO "mf.c: Commencing partition shutdown\n");
                                if (shutdown() == 0)
-                                       signal_ce_msg("\x00\x00\x00\xDB\x00\x00\x00\x00\x00\x00\x00\x00", NULL);
+                                       signal_ce_msg_simple(0xDB, NULL);
                        }
                        break;
                case 0xC0:      /* get time */
-                       if ((pending_event_head == NULL) ||
-                           (pending_event_head->event.data.ce_msg.ce_msg[3]
-                            != 0x40))
+                       spin_lock_irqsave(&pending_event_spinlock, flags);
+                       pev = pending_event_head;
+                       if (pev != NULL)
+                               pending_event_head = pending_event_head->next;
+                       spin_unlock_irqrestore(&pending_event_spinlock, flags);
+                       if (pev == NULL)
                                break;
-                       freeIt = 1;
-                       if (pending_event_head->event.data.ce_msg.completion != 0) {
-                               CeMsgCompleteHandler handler = pending_event_head->event.data.ce_msg.completion->handler;
-                               void *token = pending_event_head->event.data.ce_msg.completion->token;
+                       pce_msg_data = &pev->event.data.ce_msg;
+                       if (pce_msg_data->ce_msg[3] != 0x40)
+                               break;
+                       if (pce_msg_data->completion != NULL) {
+                               ce_msg_comp_hdlr handler =
+                                       pce_msg_data->completion->handler;
+                               void *token = pce_msg_data->completion->token;
 
                                if (handler != NULL)
-                                       (*handler)(token, &(event->data.ce_msg));
+                                       (*handler)(token, ce_msg_data);
                        }
-                       break;
-               }
-
-               /* remove from queue */
-               if (freeIt == 1) {
-                       unsigned long flags;
-
                        spin_lock_irqsave(&pending_event_spinlock, flags);
-                       if (pending_event_head != NULL) {
-                               struct pending_event *oldHead =
-                                       pending_event_head;
-
-                               pending_event_head = pending_event_head->next;
-                               two = pending_event_head;
-                               free_pending_event(oldHead);
-                       }
+                       free_pending_event(pev);
                        spin_unlock_irqrestore(&pending_event_spinlock, flags);
+                       /* send next waiting event */
+                       if (pending_event_head != NULL)
+                               signal_event(NULL);
+                       break;
                }
-
-               /* send next waiting event */
-               if (two != NULL)
-                       signal_event(NULL);
                break;
        case 1: /* IT sys shutdown */
                printk(KERN_INFO "mf.c: Commencing system shutdown\n");
@@ -435,68 +432,70 @@ static void intReceived(struct IoMFLpEvent *event)
  * of a flow we sent to them.  If there are other flows queued
  * up, we must send another one now...
  */
-static void ackReceived(struct IoMFLpEvent *event)
+static void handle_ack(struct io_mf_lp_event *event)
 {
        unsigned long flags;
-       struct pending_event * two = NULL;
-       unsigned long freeIt = 0;
+       struct pending_event *two = NULL;
+       unsigned long free_it = 0;
+       struct ce_msg_data *ce_msg_data;
+       struct ce_msg_data *pce_msg_data;
+       struct vsp_rsp_data *rsp;
 
        /* handle current event */
-       if (pending_event_head != NULL) {
-               switch (event->hp_lp_event.xSubtype) {
-               case 0:     /* CE msg */
-                       if (event->data.ce_msg.ce_msg[3] == 0x40) {
-                               if (event->data.ce_msg.ce_msg[2] != 0) {
-                                       freeIt = 1;
-                                       if (pending_event_head->event.data.ce_msg.completion
-                                                       != 0) {
-                                               CeMsgCompleteHandler handler = pending_event_head->event.data.ce_msg.completion->handler;
-                                               void *token = pending_event_head->event.data.ce_msg.completion->token;
-
-                                               if (handler != NULL)
-                                                       (*handler)(token, &(event->data.ce_msg));
-                                       }
-                               }
-                       } else
-                               freeIt = 1;
-                       break;
-               case 4: /* allocate */
-               case 5: /* deallocate */
-                       if (pending_event_head->hdlr != NULL) {
-                               union safe_cast mySafeCast;
+       if (pending_event_head == NULL) {
+               printk(KERN_ERR "mf.c: stack empty for receiving ack\n");
+               return;
+       }
 
-                               mySafeCast.ptr_as_u64 = event->hp_lp_event.xCorrelationToken;
-                               (*pending_event_head->hdlr)(mySafeCast.ptr, event->data.alloc.count);
-                       }
-                       freeIt = 1;
+       switch (event->hp_lp_event.xSubtype) {
+       case 0:     /* CE msg */
+               ce_msg_data = &event->data.ce_msg;
+               if (ce_msg_data->ce_msg[3] != 0x40) {
+                       free_it = 1;
                        break;
-               case 6:
-                       {
-                               struct VspRspData *rsp = (struct VspRspData *)event->data.vsp_cmd.token.ptr;
-
-                               if (rsp != NULL) {
-                                       if (rsp->response != NULL)
-                                               memcpy(rsp->response, &(event->data.vsp_cmd), sizeof(event->data.vsp_cmd));
-                                       complete(&rsp->com);
-                               } else
-                                       printk(KERN_ERR "mf.c: no rsp\n");
-                               freeIt = 1;
-                       }
+               }
+               if (ce_msg_data->ce_msg[2] == 0)
+                       break;
+               free_it = 1;
+               pce_msg_data = &pending_event_head->event.data.ce_msg;
+               if (pce_msg_data->completion != NULL) {
+                       ce_msg_comp_hdlr handler =
+                               pce_msg_data->completion->handler;
+                       void *token = pce_msg_data->completion->token;
+
+                       if (handler != NULL)
+                               (*handler)(token, ce_msg_data);
+               }
+               break;
+       case 4: /* allocate */
+       case 5: /* deallocate */
+               if (pending_event_head->hdlr != NULL)
+                       (*pending_event_head->hdlr)((void *)event->hp_lp_event.xCorrelationToken, event->data.alloc.count);
+               free_it = 1;
+               break;
+       case 6:
+               free_it = 1;
+               rsp = (struct vsp_rsp_data *)event->data.vsp_cmd.token;
+               if (rsp == NULL) {
+                       printk(KERN_ERR "mf.c: no rsp\n");
                        break;
                }
+               if (rsp->response != NULL)
+                       memcpy(rsp->response, &event->data.vsp_cmd,
+                                       sizeof(event->data.vsp_cmd));
+               complete(&rsp->com);
+               break;
        }
-       else
-               printk(KERN_ERR "mf.c: stack empty for receiving ack\n");
 
        /* remove from queue */
        spin_lock_irqsave(&pending_event_spinlock, flags);
-       if ((pending_event_head != NULL) && (freeIt == 1)) {
+       if ((pending_event_head != NULL) && (free_it == 1)) {
                struct pending_event *oldHead = pending_event_head;
 
                pending_event_head = pending_event_head->next;
                two = pending_event_head;
                free_pending_event(oldHead);
-       } 
+       }
        spin_unlock_irqrestore(&pending_event_spinlock, flags);
 
        /* send next waiting event */
@@ -510,15 +509,15 @@ static void ackReceived(struct IoMFLpEvent *event)
  * parse it enough to know if it is an interrupt or an
  * acknowledge.
  */
-static void hvHandler(struct HvLpEvent *event, struct pt_regs *regs)
+static void hv_handler(struct HvLpEvent *event, struct pt_regs *regs)
 {
        if ((event != NULL) && (event->xType == HvLpEvent_Type_MachineFac)) {
                switch(event->xFlags.xFunction) {
                case HvLpEvent_Function_Ack:
-                       ackReceived((struct IoMFLpEvent *)event);
+                       handle_ack((struct io_mf_lp_event *)event);
                        break;
                case HvLpEvent_Function_Int:
-                       intReceived((struct IoMFLpEvent *)event);
+                       handle_int((struct io_mf_lp_event *)event);
                        break;
                default:
                        printk(KERN_ERR "mf.c: non ack/int event received\n");
@@ -532,9 +531,9 @@ static void hvHandler(struct HvLpEvent *event, struct pt_regs *regs)
  * Global kernel interface to allocate and seed events into the
  * Hypervisor.
  */
-void mf_allocateLpEvents(HvLpIndex targetLp, HvLpEvent_Type type,
+void mf_allocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type,
                unsigned size, unsigned count, MFCompleteHandler hdlr,
-               void *userToken)
+               void *user_token)
 {
        struct pending_event *ev = new_pending_event();
        int rc;
@@ -542,14 +541,11 @@ void mf_allocateLpEvents(HvLpIndex targetLp, HvLpEvent_Type type,
        if (ev == NULL) {
                rc = -ENOMEM;
        } else {
-               union safe_cast mine;
-
-               mine.ptr = userToken;
                ev->event.hp_lp_event.xSubtype = 4;
-               ev->event.hp_lp_event.xCorrelationToken = mine.ptr_as_u64;
+               ev->event.hp_lp_event.xCorrelationToken = (u64)user_token;
                ev->event.hp_lp_event.x.xSubtypeData =
                        subtype_data('M', 'F', 'M', 'A');
-               ev->event.data.alloc.target_lp = targetLp;
+               ev->event.data.alloc.target_lp = target_lp;
                ev->event.data.alloc.type = type;
                ev->event.data.alloc.size = size;
                ev->event.data.alloc.count = count;
@@ -557,16 +553,16 @@ void mf_allocateLpEvents(HvLpIndex targetLp, HvLpEvent_Type type,
                rc = signal_event(ev);
        }
        if ((rc != 0) && (hdlr != NULL))
-               (*hdlr)(userToken, rc);
+               (*hdlr)(user_token, rc);
 }
-EXPORT_SYMBOL(mf_allocateLpEvents);
+EXPORT_SYMBOL(mf_allocate_lp_events);
 
 /*
  * Global kernel interface to unseed and deallocate events already in
  * Hypervisor.
  */
-void mf_deallocateLpEvents(HvLpIndex targetLp, HvLpEvent_Type type,
-               unsigned count, MFCompleteHandler hdlr, void *userToken)
+void mf_deallocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type,
+               unsigned count, MFCompleteHandler hdlr, void *user_token)
 {
        struct pending_event *ev = new_pending_event();
        int rc;
@@ -574,33 +570,31 @@ void mf_deallocateLpEvents(HvLpIndex targetLp, HvLpEvent_Type type,
        if (ev == NULL)
                rc = -ENOMEM;
        else {
-               union safe_cast mine;
-
-               mine.ptr = userToken;
                ev->event.hp_lp_event.xSubtype = 5;
-               ev->event.hp_lp_event.xCorrelationToken = mine.ptr_as_u64;
+               ev->event.hp_lp_event.xCorrelationToken = (u64)user_token;
                ev->event.hp_lp_event.x.xSubtypeData =
                        subtype_data('M', 'F', 'M', 'D');
-               ev->event.data.alloc.target_lp = targetLp;
+               ev->event.data.alloc.target_lp = target_lp;
                ev->event.data.alloc.type = type;
                ev->event.data.alloc.count = count;
                ev->hdlr = hdlr;
                rc = signal_event(ev);
        }
        if ((rc != 0) && (hdlr != NULL))
-               (*hdlr)(userToken, rc);
+               (*hdlr)(user_token, rc);
 }
-EXPORT_SYMBOL(mf_deallocateLpEvents);
+EXPORT_SYMBOL(mf_deallocate_lp_events);
 
 /*
  * Global kernel interface to tell the VSP object in the primary
  * partition to power this partition off.
  */
-void mf_powerOff(void)
+void mf_power_off(void)
 {
        printk(KERN_INFO "mf.c: Down it goes...\n");
-       signal_ce_msg("\x00\x00\x00\x4D\x00\x00\x00\x00\x00\x00\x00\x00", NULL);
-       for (;;);
+       signal_ce_msg_simple(0x4d, NULL);
+       for (;;)
+               ;
 }
 
 /*
@@ -610,18 +604,21 @@ void mf_powerOff(void)
 void mf_reboot(void)
 {
        printk(KERN_INFO "mf.c: Preparing to bounce...\n");
-       signal_ce_msg("\x00\x00\x00\x4E\x00\x00\x00\x00\x00\x00\x00\x00", NULL);
-       for (;;);
+       signal_ce_msg_simple(0x4e, NULL);
+       for (;;)
+               ;
 }
 
 /*
  * Display a single word SRC onto the VSP control panel.
  */
-void mf_displaySrc(u32 word)
+void mf_display_src(u32 word)
 {
        u8 ce[12];
 
-       memcpy(ce, "\x00\x00\x00\x4A\x00\x00\x00\x01\x00\x00\x00\x00", 12);
+       memset(ce, 0, sizeof(ce));
+       ce[3] = 0x4a;
+       ce[7] = 0x01;
        ce[8] = word >> 24;
        ce[9] = word >> 16;
        ce[10] = word >> 8;
@@ -632,7 +629,7 @@ void mf_displaySrc(u32 word)
 /*
  * Display a single word SRC of the form "PROGXXXX" on the VSP control panel.
  */
-void mf_displayProgress(u16 value)
+void mf_display_progress(u16 value)
 {
        u8 ce[12];
        u8 src[72];
@@ -656,9 +653,9 @@ void mf_displayProgress(u16 value)
  * Clear the VSP control panel.  Used to "erase" an SRC that was
  * previously displayed.
  */
-void mf_clearSrc(void)
+void mf_clear_src(void)
 {
-       signal_ce_msg("\x00\x00\x00\x4B\x00\x00\x00\x00\x00\x00\x00\x00", NULL);
+       signal_ce_msg_simple(0x4b, NULL);
 }
 
 /*
@@ -674,71 +671,331 @@ void mf_init(void)
             i < sizeof(pending_event_prealloc) / sizeof(*pending_event_prealloc);
             ++i)
                free_pending_event(&pending_event_prealloc[i]);
-       HvLpEvent_registerHandler(HvLpEvent_Type_MachineFac, &hvHandler);
+       HvLpEvent_registerHandler(HvLpEvent_Type_MachineFac, &hv_handler);
 
        /* virtual continue ack */
-       signal_ce_msg("\x00\x00\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00", NULL);
+       signal_ce_msg_simple(0x57, NULL);
 
        /* initialization complete */
-       printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities initialized\n");
+       printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities "
+                       "initialized\n");
 }
 
-void mf_setSide(char side)
+struct rtc_time_data {
+       struct completion com;
+       struct ce_msg_data ce_msg;
+       int rc;
+};
+
+static void get_rtc_time_complete(void *token, struct ce_msg_data *ce_msg)
 {
-       u64 newSide;
-       struct VspCmdData myVspCmd;
+       struct rtc_time_data *rtc = token;
 
-       memset(&myVspCmd, 0, sizeof(myVspCmd));
-       switch (side) {
-       case 'A':       newSide = 0;
-                       break;
-       case 'B':       newSide = 1;
-                       break;
-       case 'C':       newSide = 2; 
-                       break;
-       default:        newSide = 3;
+       memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg));
+       rtc->rc = 0;
+       complete(&rtc->com);
+}
+
+int mf_get_rtc(struct rtc_time *tm)
+{
+       struct ce_msg_comp_data ce_complete;
+       struct rtc_time_data rtc_data;
+       int rc;
+
+       memset(&ce_complete, 0, sizeof(ce_complete));
+       memset(&rtc_data, 0, sizeof(rtc_data));
+       init_completion(&rtc_data.com);
+       ce_complete.handler = &get_rtc_time_complete;
+       ce_complete.token = &rtc_data;
+       rc = signal_ce_msg_simple(0x40, &ce_complete);
+       if (rc)
+               return rc;
+       wait_for_completion(&rtc_data.com);
+       tm->tm_wday = 0;
+       tm->tm_yday = 0;
+       tm->tm_isdst = 0;
+       if (rtc_data.rc) {
+               tm->tm_sec = 0;
+               tm->tm_min = 0;
+               tm->tm_hour = 0;
+               tm->tm_mday = 15;
+               tm->tm_mon = 5;
+               tm->tm_year = 52;
+               return rtc_data.rc;
+       }
+
+       if ((rtc_data.ce_msg.ce_msg[2] == 0xa9) ||
+           (rtc_data.ce_msg.ce_msg[2] == 0xaf)) {
+               /* TOD clock is not set */
+               tm->tm_sec = 1;
+               tm->tm_min = 1;
+               tm->tm_hour = 1;
+               tm->tm_mday = 10;
+               tm->tm_mon = 8;
+               tm->tm_year = 71;
+               mf_set_rtc(tm);
+       }
+       {
+               u8 *ce_msg = rtc_data.ce_msg.ce_msg;
+               u8 year = ce_msg[5];
+               u8 sec = ce_msg[6];
+               u8 min = ce_msg[7];
+               u8 hour = ce_msg[8];
+               u8 day = ce_msg[10];
+               u8 mon = ce_msg[11];
+
+               BCD_TO_BIN(sec);
+               BCD_TO_BIN(min);
+               BCD_TO_BIN(hour);
+               BCD_TO_BIN(day);
+               BCD_TO_BIN(mon);
+               BCD_TO_BIN(year);
+
+               if (year <= 69)
+                       year += 100;
+
+               tm->tm_sec = sec;
+               tm->tm_min = min;
+               tm->tm_hour = hour;
+               tm->tm_mday = day;
+               tm->tm_mon = mon;
+               tm->tm_year = year;
+       }
+
+       return 0;
+}
+
+int mf_set_rtc(struct rtc_time *tm)
+{
+       char ce_time[12];
+       u8 day, mon, hour, min, sec, y1, y2;
+       unsigned year;
+
+       year = 1900 + tm->tm_year;
+       y1 = year / 100;
+       y2 = year % 100;
+
+       sec = tm->tm_sec;
+       min = tm->tm_min;
+       hour = tm->tm_hour;
+       day = tm->tm_mday;
+       mon = tm->tm_mon + 1;
+
+       BIN_TO_BCD(sec);
+       BIN_TO_BCD(min);
+       BIN_TO_BCD(hour);
+       BIN_TO_BCD(mon);
+       BIN_TO_BCD(day);
+       BIN_TO_BCD(y1);
+       BIN_TO_BCD(y2);
+
+       memset(ce_time, 0, sizeof(ce_time));
+       ce_time[3] = 0x41;
+       ce_time[4] = y1;
+       ce_time[5] = y2;
+       ce_time[6] = sec;
+       ce_time[7] = min;
+       ce_time[8] = hour;
+       ce_time[10] = day;
+       ce_time[11] = mon;
+
+       return signal_ce_msg(ce_time, NULL);
+}
+
+#ifdef CONFIG_PROC_FS
+
+static int proc_mf_dump_cmdline(char *page, char **start, off_t off,
+               int count, int *eof, void *data)
+{
+       int len;
+       char *p;
+       struct vsp_cmd_data vsp_cmd;
+       int rc;
+       dma_addr_t dma_addr;
+
+       /* The HV appears to return no more than 256 bytes of command line */
+       if (off >= 256)
+               return 0;
+       if ((off + count) > 256)
+               count = 256 - off;
+
+       dma_addr = dma_map_single(iSeries_vio_dev, page, off + count,
+                       DMA_FROM_DEVICE);
+       if (dma_mapping_error(dma_addr))
+               return -ENOMEM;
+       memset(page, 0, off + count);
+       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
+       vsp_cmd.cmd = 33;
+       vsp_cmd.sub_data.kern.token = dma_addr;
+       vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
+       vsp_cmd.sub_data.kern.side = (u64)data;
+       vsp_cmd.sub_data.kern.length = off + count;
+       mb();
+       rc = signal_vsp_instruction(&vsp_cmd);
+       dma_unmap_single(iSeries_vio_dev, dma_addr, off + count,
+                       DMA_FROM_DEVICE);
+       if (rc)
+               return rc;
+       if (vsp_cmd.result_code != 0)
+               return -ENOMEM;
+       p = page;
+       len = 0;
+       while (len < (off + count)) {
+               if ((*p == '\0') || (*p == '\n')) {
+                       if (*p == '\0')
+                               *p = '\n';
+                       p++;
+                       len++;
+                       *eof = 1;
                        break;
+               }
+               p++;
+               len++;
        }
-       myVspCmd.sub_data.ipl_type = newSide;
-       myVspCmd.cmd = 10;
 
-       (void)signal_vsp_instruction(&myVspCmd);
+       if (len < off) {
+               *eof = 1;
+               len = 0;
+       }
+       return len;
 }
 
-char mf_getSide(void)
+#if 0
+static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side)
 {
-       char returnValue = ' ';
-       int rc = 0;
-       struct VspCmdData myVspCmd;
+       struct vsp_cmd_data vsp_cmd;
+       int rc;
+       int len = *size;
+       dma_addr_t dma_addr;
+
+       dma_addr = dma_map_single(iSeries_vio_dev, buffer, len,
+                       DMA_FROM_DEVICE);
+       memset(buffer, 0, len);
+       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
+       vsp_cmd.cmd = 32;
+       vsp_cmd.sub_data.kern.token = dma_addr;
+       vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
+       vsp_cmd.sub_data.kern.side = side;
+       vsp_cmd.sub_data.kern.offset = offset;
+       vsp_cmd.sub_data.kern.length = len;
+       mb();
+       rc = signal_vsp_instruction(&vsp_cmd);
+       if (rc == 0) {
+               if (vsp_cmd.result_code == 0)
+                       *size = vsp_cmd.sub_data.length_out;
+               else
+                       rc = -ENOMEM;
+       }
+
+       dma_unmap_single(iSeries_vio_dev, dma_addr, len, DMA_FROM_DEVICE);
+
+       return rc;
+}
+
+static int proc_mf_dump_vmlinux(char *page, char **start, off_t off,
+               int count, int *eof, void *data)
+{
+       int sizeToGet = count;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+
+       if (mf_getVmlinuxChunk(page, &sizeToGet, off, (u64)data) == 0) {
+               if (sizeToGet != 0) {
+                       *start = page + off;
+                       return sizeToGet;
+               }
+               *eof = 1;
+               return 0;
+       }
+       *eof = 1;
+       return 0;
+}
+#endif
+
+static int proc_mf_dump_side(char *page, char **start, off_t off,
+               int count, int *eof, void *data)
+{
+       int len;
+       char mf_current_side = ' ';
+       struct vsp_cmd_data vsp_cmd;
 
-       memset(&myVspCmd, 0, sizeof(myVspCmd));
-       myVspCmd.cmd = 2;
-       myVspCmd.sub_data.ipl_type = 0;
+       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
+       vsp_cmd.cmd = 2;
+       vsp_cmd.sub_data.ipl_type = 0;
        mb();
-       rc = signal_vsp_instruction(&myVspCmd);
 
-       if (rc != 0)
-               return returnValue;
+       if (signal_vsp_instruction(&vsp_cmd) == 0) {
+               if (vsp_cmd.result_code == 0) {
+                       switch (vsp_cmd.sub_data.ipl_type) {
+                       case 0: mf_current_side = 'A';
+                               break;
+                       case 1: mf_current_side = 'B';
+                               break;
+                       case 2: mf_current_side = 'C';
+                               break;
+                       default:        mf_current_side = 'D';
+                               break;
+                       }
+               }
+       }
+
+       len = sprintf(page, "%c\n", mf_current_side);
+
+       if (len <= (off + count))
+               *eof = 1;
+       *start = page + off;
+       len -= off;
+       if (len > count)
+               len = count;
+       if (len < 0)
+               len = 0;
+       return len;
+}
+
+static int proc_mf_change_side(struct file *file, const char __user *buffer,
+               unsigned long count, void *data)
+{
+       char side;
+       u64 newSide;
+       struct vsp_cmd_data vsp_cmd;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
 
-       if (myVspCmd.result_code == 0) {
-               switch (myVspCmd.sub_data.ipl_type) {
-               case 0: returnValue = 'A';
+       if (count == 0)
+               return 0;
+
+       if (get_user(side, buffer))
+               return -EFAULT;
+
+       switch (side) {
+       case 'A':       newSide = 0;
                        break;
-               case 1: returnValue = 'B';
+       case 'B':       newSide = 1;
                        break;
-               case 2: returnValue = 'C';
+       case 'C':       newSide = 2;
                        break;
-               default:        returnValue = 'D';
+       case 'D':       newSide = 3;
                        break;
-               }
+       default:
+               printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n");
+               return -EINVAL;
        }
-       return returnValue;
+
+       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
+       vsp_cmd.sub_data.ipl_type = newSide;
+       vsp_cmd.cmd = 10;
+
+       (void)signal_vsp_instruction(&vsp_cmd);
+
+       return count;
 }
 
-void mf_getSrcHistory(char *buffer, int size)
-{
 #if 0
-       struct IplTypeReturnStuff returnStuff;
+static void mf_getSrcHistory(char *buffer, int size)
+{
+       struct IplTypeReturnStuff return_stuff;
        struct pending_event *ev = new_pending_event();
        int rc = 0;
        char *pages[4];
@@ -751,13 +1008,13 @@ void mf_getSrcHistory(char *buffer, int size)
                         || (pages[2] == NULL) || (pages[3] == NULL))
                return -ENOMEM;
 
-       returnStuff.xType = 0;
-       returnStuff.xRc = 0;
-       returnStuff.xDone = 0;
+       return_stuff.xType = 0;
+       return_stuff.xRc = 0;
+       return_stuff.xDone = 0;
        ev->event.hp_lp_event.xSubtype = 6;
        ev->event.hp_lp_event.x.xSubtypeData =
                subtype_data('M', 'F', 'V', 'I');
-       ev->event.data.vsp_cmd.xEvent = &returnStuff;
+       ev->event.data.vsp_cmd.xEvent = &return_stuff;
        ev->event.data.vsp_cmd.cmd = 4;
        ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex();
        ev->event.data.vsp_cmd.result_code = 0xFF;
@@ -770,312 +1027,213 @@ void mf_getSrcHistory(char *buffer, int size)
        if (signal_event(ev) != 0)
                return;
 
-       while (returnStuff.xDone != 1)
+       while (return_stuff.xDone != 1)
                udelay(10);
-       if (returnStuff.xRc == 0)
+       if (return_stuff.xRc == 0)
                memcpy(buffer, pages[0], size);
        kfree(pages[0]);
        kfree(pages[1]);
        kfree(pages[2]);
        kfree(pages[3]);
-#endif
-}
-
-void mf_setCmdLine(const char *cmdline, int size, u64 side)
-{
-       struct VspCmdData myVspCmd;
-       dma_addr_t dma_addr = 0;
-       char *page = dma_alloc_coherent(iSeries_vio_dev, size, &dma_addr,
-                       GFP_ATOMIC);
-
-       if (page == NULL) {
-               printk(KERN_ERR "mf.c: couldn't allocate memory to set command line\n");
-               return;
-       }
-
-       copy_from_user(page, cmdline, size);
-
-       memset(&myVspCmd, 0, sizeof(myVspCmd));
-       myVspCmd.cmd = 31;
-       myVspCmd.sub_data.kern.token = dma_addr;
-       myVspCmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
-       myVspCmd.sub_data.kern.side = side;
-       myVspCmd.sub_data.kern.length = size;
-       mb();
-       (void)signal_vsp_instruction(&myVspCmd);
-
-       dma_free_coherent(iSeries_vio_dev, size, page, dma_addr);
 }
+#endif
 
-int mf_getCmdLine(char *cmdline, int *size, u64 side)
+static int proc_mf_dump_src(char *page, char **start, off_t off,
+               int count, int *eof, void *data)
 {
-       struct VspCmdData myVspCmd;
-       int rc;
-       int len = *size;
-       dma_addr_t dma_addr;
-
-       dma_addr = dma_map_single(iSeries_vio_dev, cmdline, len,
-                       DMA_FROM_DEVICE);
-       memset(cmdline, 0, len);
-       memset(&myVspCmd, 0, sizeof(myVspCmd));
-       myVspCmd.cmd = 33;
-       myVspCmd.sub_data.kern.token = dma_addr;
-       myVspCmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
-       myVspCmd.sub_data.kern.side = side;
-       myVspCmd.sub_data.kern.length = len;
-       mb();
-       rc = signal_vsp_instruction(&myVspCmd);
-
-       if (rc == 0) {
-               if (myVspCmd.result_code == 0)
-                       len = myVspCmd.sub_data.length_out;
 #if 0
-               else
-                       memcpy(cmdline, "Bad cmdline", 11);
-#endif
-       }
-
-       dma_unmap_single(iSeries_vio_dev, dma_addr, *size, DMA_FROM_DEVICE);
-
+       int len;
+
+       mf_getSrcHistory(page, count);
+       len = count;
+       len -= off;
+       if (len < count) {
+               *eof = 1;
+               if (len <= 0)
+                       return 0;
+       } else
+               len = count;
+       *start = page + off;
        return len;
+#else
+       return 0;
+#endif
 }
 
-
-int mf_setVmlinuxChunk(const char *buffer, int size, int offset, u64 side)
+static int proc_mf_change_src(struct file *file, const char __user *buffer,
+               unsigned long count, void *data)
 {
-       struct VspCmdData myVspCmd;
-       int rc;
-       dma_addr_t dma_addr = 0;
-       char *page = dma_alloc_coherent(iSeries_vio_dev, size, &dma_addr,
-                       GFP_ATOMIC);
+       char stkbuf[10];
 
-       if (page == NULL) {
-               printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n");
-               return -ENOMEM;
-       }
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
 
-       copy_from_user(page, buffer, size);
-       memset(&myVspCmd, 0, sizeof(myVspCmd));
-
-       myVspCmd.cmd = 30;
-       myVspCmd.sub_data.kern.token = dma_addr;
-       myVspCmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
-       myVspCmd.sub_data.kern.side = side;
-       myVspCmd.sub_data.kern.offset = offset;
-       myVspCmd.sub_data.kern.length = size;
-       mb();
-       rc = signal_vsp_instruction(&myVspCmd);
-       if (rc == 0) {
-               if (myVspCmd.result_code == 0)
-                       rc = 0;
-               else
-                       rc = -ENOMEM;
+       if ((count < 4) && (count != 1)) {
+               printk(KERN_ERR "mf_proc: invalid src\n");
+               return -EINVAL;
        }
 
-       dma_free_coherent(iSeries_vio_dev, size, page, dma_addr);
+       if (count > (sizeof(stkbuf) - 1))
+               count = sizeof(stkbuf) - 1;
+       if (copy_from_user(stkbuf, buffer, count))
+               return -EFAULT;
 
-       return rc;
+       if ((count == 1) && (*stkbuf == '\0'))
+               mf_clear_src();
+       else
+               mf_display_src(*(u32 *)stkbuf);
+
+       return count;
 }
 
-int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side)
+static int proc_mf_change_cmdline(struct file *file, const char __user *buffer,
+               unsigned long count, void *data)
 {
-       struct VspCmdData myVspCmd;
-       int rc;
-       int len = *size;
+       struct vsp_cmd_data vsp_cmd;
        dma_addr_t dma_addr;
+       char *page;
+       int ret = -EACCES;
 
-       dma_addr = dma_map_single(iSeries_vio_dev, buffer, len,
-                       DMA_FROM_DEVICE);
-       memset(buffer, 0, len);
-       memset(&myVspCmd, 0, sizeof(myVspCmd));
-       myVspCmd.cmd = 32;
-       myVspCmd.sub_data.kern.token = dma_addr;
-       myVspCmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
-       myVspCmd.sub_data.kern.side = side;
-       myVspCmd.sub_data.kern.offset = offset;
-       myVspCmd.sub_data.kern.length = len;
-       mb();
-       rc = signal_vsp_instruction(&myVspCmd);
-       if (rc == 0) {
-               if (myVspCmd.result_code == 0)
-                       *size = myVspCmd.sub_data.length_out;
-               else
-                       rc = -ENOMEM;
-       }
+       if (!capable(CAP_SYS_ADMIN))
+               goto out;
 
-       dma_unmap_single(iSeries_vio_dev, dma_addr, len, DMA_FROM_DEVICE);
+       dma_addr = 0;
+       page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr,
+                       GFP_ATOMIC);
+       ret = -ENOMEM;
+       if (page == NULL)
+               goto out;
+
+       ret = -EFAULT;
+       if (copy_from_user(page, buffer, count))
+               goto out_free;
+
+       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
+       vsp_cmd.cmd = 31;
+       vsp_cmd.sub_data.kern.token = dma_addr;
+       vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
+       vsp_cmd.sub_data.kern.side = (u64)data;
+       vsp_cmd.sub_data.kern.length = count;
+       mb();
+       (void)signal_vsp_instruction(&vsp_cmd);
+       ret = count;
 
-       return rc;
+out_free:
+       dma_free_coherent(iSeries_vio_dev, count, page, dma_addr);
+out:
+       return ret;
 }
 
-int mf_setRtcTime(unsigned long time)
+static ssize_t proc_mf_change_vmlinux(struct file *file,
+                                     const char __user *buf,
+                                     size_t count, loff_t *ppos)
 {
-       struct rtc_time tm;
+       struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+       ssize_t rc;
+       dma_addr_t dma_addr;
+       char *page;
+       struct vsp_cmd_data vsp_cmd;
 
-       to_tm(time, &tm);
+       rc = -EACCES;
+       if (!capable(CAP_SYS_ADMIN))
+               goto out;
 
-       return mf_setRtc(&tm);
+       dma_addr = 0;
+       page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr,
+                       GFP_ATOMIC);
+       rc = -ENOMEM;
+       if (page == NULL) {
+               printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n");
+               goto out;
+       }
+       rc = -EFAULT;
+       if (copy_from_user(page, buf, count))
+               goto out_free;
+
+       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
+       vsp_cmd.cmd = 30;
+       vsp_cmd.sub_data.kern.token = dma_addr;
+       vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
+       vsp_cmd.sub_data.kern.side = (u64)dp->data;
+       vsp_cmd.sub_data.kern.offset = *ppos;
+       vsp_cmd.sub_data.kern.length = count;
+       mb();
+       rc = signal_vsp_instruction(&vsp_cmd);
+       if (rc)
+               goto out_free;
+       rc = -ENOMEM;
+       if (vsp_cmd.result_code != 0)
+               goto out_free;
+
+       *ppos += count;
+       rc = count;
+out_free:
+       dma_free_coherent(iSeries_vio_dev, count, page, dma_addr);
+out:
+       return rc;
 }
 
-struct RtcTimeData {
-       struct completion com;
-       struct CeMsgData xCeMsg;
-       int xRc;
+static struct file_operations proc_vmlinux_operations = {
+       .write          = proc_mf_change_vmlinux,
 };
 
-void getRtcTimeComplete(void * token, struct CeMsgData *ceMsg)
+static int __init mf_proc_init(void)
 {
-       struct RtcTimeData *rtc = (struct RtcTimeData *)token;
-
-       memcpy(&(rtc->xCeMsg), ceMsg, sizeof(rtc->xCeMsg));
-       rtc->xRc = 0;
-       complete(&rtc->com);
-}
-
-static unsigned long lastsec = 1;
+       struct proc_dir_entry *mf_proc_root;
+       struct proc_dir_entry *ent;
+       struct proc_dir_entry *mf;
+       char name[2];
+       int i;
 
-int mf_getRtcTime(unsigned long *time)
-{
-       u32 dataWord1 = *((u32 *)(&xSpCommArea.xBcdTimeAtIplStart));
-       u32 dataWord2 = *(((u32 *)&(xSpCommArea.xBcdTimeAtIplStart)) + 1);
-       int year = 1970;
-       int year1 = (dataWord1 >> 24) & 0x000000FF;
-       int year2 = (dataWord1 >> 16) & 0x000000FF;
-       int sec = (dataWord1 >> 8) & 0x000000FF;
-       int min = dataWord1 & 0x000000FF;
-       int hour = (dataWord2 >> 24) & 0x000000FF;
-       int day = (dataWord2 >> 8) & 0x000000FF;
-       int mon = dataWord2 & 0x000000FF;
-
-       BCD_TO_BIN(sec);
-       BCD_TO_BIN(min);
-       BCD_TO_BIN(hour);
-       BCD_TO_BIN(day);
-       BCD_TO_BIN(mon);
-       BCD_TO_BIN(year1);
-       BCD_TO_BIN(year2);
-       year = year1 * 100 + year2;
-
-       *time = mktime(year, mon, day, hour, min, sec);
-       *time += (jiffies / HZ);
-    
-       /*
-        * Now THIS is a nasty hack!
-        * It ensures that the first two calls to mf_getRtcTime get different
-        * answers.  That way the loop in init_time (time.c) will not think
-        * the clock is stuck.
-        */
-       if (lastsec) {
-               *time -= lastsec;
-               --lastsec;
+       mf_proc_root = proc_mkdir("iSeries/mf", NULL);
+       if (!mf_proc_root)
+               return 1;
+
+       name[1] = '\0';
+       for (i = 0; i < 4; i++) {
+               name[0] = 'A' + i;
+               mf = proc_mkdir(name, mf_proc_root);
+               if (!mf)
+                       return 1;
+
+               ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf);
+               if (!ent)
+                       return 1;
+               ent->nlink = 1;
+               ent->data = (void *)(long)i;
+               ent->read_proc = proc_mf_dump_cmdline;
+               ent->write_proc = proc_mf_change_cmdline;
+
+               if (i == 3)     /* no vmlinux entry for 'D' */
+                       continue;
+
+               ent = create_proc_entry("vmlinux", S_IFREG|S_IWUSR, mf);
+               if (!ent)
+                       return 1;
+               ent->nlink = 1;
+               ent->data = (void *)(long)i;
+               ent->proc_fops = &proc_vmlinux_operations;
        }
-       return 0;
-}
-
-int mf_getRtc(struct rtc_time *tm)
-{
-       struct CeMsgCompleteData ceComplete;
-       struct RtcTimeData rtcData;
-       int rc;
-
-       memset(&ceComplete, 0, sizeof(ceComplete));
-       memset(&rtcData, 0, sizeof(rtcData));
-       init_completion(&rtcData.com);
-       ceComplete.handler = &getRtcTimeComplete;
-       ceComplete.token = (void *)&rtcData;
-       rc = signal_ce_msg("\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00",
-                       &ceComplete);
-       if (rc == 0) {
-               wait_for_completion(&rtcData.com);
-
-               if (rtcData.xRc == 0) {
-                       if ((rtcData.xCeMsg.ce_msg[2] == 0xa9) ||
-                           (rtcData.xCeMsg.ce_msg[2] == 0xaf)) {
-                               /* TOD clock is not set */
-                               tm->tm_sec = 1;
-                               tm->tm_min = 1;
-                               tm->tm_hour = 1;
-                               tm->tm_mday = 10;
-                               tm->tm_mon = 8;
-                               tm->tm_year = 71;
-                               mf_setRtc(tm);
-                       }
-                       {
-                               u32 dataWord1 = *((u32 *)(rtcData.xCeMsg.ce_msg+4));
-                               u32 dataWord2 = *((u32 *)(rtcData.xCeMsg.ce_msg+8));
-                               u8 year = (dataWord1 >> 16) & 0x000000FF;
-                               u8 sec = (dataWord1 >> 8) & 0x000000FF;
-                               u8 min = dataWord1 & 0x000000FF;
-                               u8 hour = (dataWord2 >> 24) & 0x000000FF;
-                               u8 day = (dataWord2 >> 8) & 0x000000FF;
-                               u8 mon = dataWord2 & 0x000000FF;
-
-                               BCD_TO_BIN(sec);
-                               BCD_TO_BIN(min);
-                               BCD_TO_BIN(hour);
-                               BCD_TO_BIN(day);
-                               BCD_TO_BIN(mon);
-                               BCD_TO_BIN(year);
-
-                               if (year <= 69)
-                                       year += 100;
-           
-                               tm->tm_sec = sec;
-                               tm->tm_min = min;
-                               tm->tm_hour = hour;
-                               tm->tm_mday = day;
-                               tm->tm_mon = mon;
-                               tm->tm_year = year;
-                       }
-               } else {
-                       rc = rtcData.xRc;
-                       tm->tm_sec = 0;
-                       tm->tm_min = 0;
-                       tm->tm_hour = 0;
-                       tm->tm_mday = 15;
-                       tm->tm_mon = 5;
-                       tm->tm_year = 52;
 
-               }
-               tm->tm_wday = 0;
-               tm->tm_yday = 0;
-               tm->tm_isdst = 0;
-       }
+       ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root);
+       if (!ent)
+               return 1;
+       ent->nlink = 1;
+       ent->data = (void *)0;
+       ent->read_proc = proc_mf_dump_side;
+       ent->write_proc = proc_mf_change_side;
+
+       ent = create_proc_entry("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root);
+       if (!ent)
+               return 1;
+       ent->nlink = 1;
+       ent->data = (void *)0;
+       ent->read_proc = proc_mf_dump_src;
+       ent->write_proc = proc_mf_change_src;
 
-       return rc;
+       return 0;
 }
 
-int mf_setRtc(struct rtc_time * tm)
-{
-       char ceTime[12] = "\x00\x00\x00\x41\x00\x00\x00\x00\x00\x00\x00\x00";
-       u8 day, mon, hour, min, sec, y1, y2;
-       unsigned year;
-    
-       year = 1900 + tm->tm_year;
-       y1 = year / 100;
-       y2 = year % 100;
-    
-       sec = tm->tm_sec;
-       min = tm->tm_min;
-       hour = tm->tm_hour;
-       day = tm->tm_mday;
-       mon = tm->tm_mon + 1;
-           
-       BIN_TO_BCD(sec);
-       BIN_TO_BCD(min);
-       BIN_TO_BCD(hour);
-       BIN_TO_BCD(mon);
-       BIN_TO_BCD(day);
-       BIN_TO_BCD(y1);
-       BIN_TO_BCD(y2);
+__initcall(mf_proc_init);
 
-       ceTime[4] = y1;
-       ceTime[5] = y2;
-       ceTime[6] = sec;
-       ceTime[7] = min;
-       ceTime[8] = hour;
-       ceTime[10] = day;
-       ceTime[11] = mon;
-   
-       return signal_ce_msg(ceTime, NULL);
-}
+#endif /* CONFIG_PROC_FS */