This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / arch / ppc64 / kernel / mf.c
index 1bd52ec..02a68b1 100644 (file)
@@ -1,7 +1,6 @@
 /*
   * 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
@@ -9,44 +8,52 @@
   * 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 <linux/dma-mapping.h>
-#include <linux/bcd.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/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.
  */
-struct vsp_cmd_data {
-       u64 token;
+union safe_cast {
+       u64 ptr_as_u64;
+       void *ptr;
+};
+
+struct VspCmdData {
+       union safe_cast token;
        u16 cmd;
        HvLpIndex lp_index;
        u8 result_code;
@@ -74,12 +81,12 @@ struct vsp_cmd_data {
        } sub_data;
 };
 
-struct vsp_rsp_data {
+struct VspRspData {
        struct completion com;
-       struct vsp_cmd_data *response;
+       struct VspCmdData *response;
 };
 
-struct alloc_data {
+struct AllocData {
        u16 size;
        u16 type;
        u32 count;
@@ -88,30 +95,30 @@ struct alloc_data {
        HvLpIndex target_lp;
 };
 
-struct ce_msg_data;
+struct CeMsgData;
 
-typedef void (*ce_msg_comp_hdlr)(void *token, struct ce_msg_data *vsp_cmd_rsp);
+typedef void (*CeMsgCompleteHandler)(void *token, struct CeMsgData *vspCmdRsp);
 
-struct ce_msg_comp_data {
-       ce_msg_comp_hdlr handler;
+struct CeMsgCompleteData {
+       CeMsgCompleteHandler handler;
        void *token;
 };
 
-struct ce_msg_data {
+struct CeMsgData {
        u8 ce_msg[12];
        char reserved[4];
-       struct ce_msg_comp_data *completion;
+       struct CeMsgCompleteData *completion;
 };
 
-struct io_mf_lp_event {
+struct IoMFLpEvent {
        struct HvLpEvent hp_lp_event;
        u16 subtype_result_code;
        u16 reserved1;
        u32 reserved2;
        union {
-               struct alloc_data alloc;
-               struct ce_msg_data ce_msg;
-               struct vsp_cmd_data vsp_cmd;
+               struct AllocData alloc;
+               struct CeMsgData ce_msg;
+               struct VspCmdData vsp_cmd;
        } data;
 };
 
@@ -127,7 +134,7 @@ struct io_mf_lp_event {
  */
 struct pending_event {
        struct pending_event *next;
-       struct io_mf_lp_event event;
+       struct IoMFLpEvent event;
        MFCompleteHandler hdlr;
        char dma_data[72];
        unsigned dma_data_length;
@@ -165,7 +172,7 @@ static int signal_event(struct pending_event *ev)
        unsigned long flags;
        int go = 1;
        struct pending_event *ev1;
-       HvLpEvent_Rc hv_rc;
+       HvLpEvent_Rc hvRc;
 
        /* enqueue the event */
        if (ev != NULL) {
@@ -192,11 +199,11 @@ static int signal_event(struct pending_event *ev)
                                        pending_event_head->dma_data_length,
                                        HvLpDma_Direction_LocalToRemote);
 
-               hv_rc = HvCallEvent_signalLpEvent(
+               hvRc = HvCallEvent_signalLpEvent(
                                &pending_event_head->event.hp_lp_event);
-               if (hv_rc != HvLpEvent_Rc_Good) {
-                       printk(KERN_ERR "mf.c: HvCallEvent_signalLpEvent() "
-                                       "failed with %d\n", (int)hv_rc);
+               if (hvRc != HvLpEvent_Rc_Good) {
+                       printk(KERN_ERR "mf.c: HvCallEvent_signalLpEvent() failed with %d\n",
+                                       (int)hvRc);
 
                        spin_lock_irqsave(&pending_event_spinlock, flags);
                        ev1 = pending_event_head;
@@ -207,8 +214,12 @@ static int signal_event(struct pending_event *ev)
 
                        if (ev1 == ev)
                                rc = -EIO;
-                       else if (ev1->hdlr != NULL)
-                               (*ev1->hdlr)((void *)ev1->event.hp_lp_event.xCorrelationToken, -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);
+                       }
 
                        spin_lock_irqsave(&pending_event_spinlock, flags);
                        free_pending_event(ev1);
@@ -225,7 +236,7 @@ static int signal_event(struct pending_event *ev)
 static struct pending_event *new_pending_event(void)
 {
        struct pending_event *ev = NULL;
-       HvLpIndex primary_lp = HvLpConfig_getPrimaryLpIndex();
+       HvLpIndex primaryLp = HvLpConfig_getPrimaryLpIndex();
        unsigned long flags;
        struct HvLpEvent *hev;
 
@@ -235,13 +246,12 @@ 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) {
-               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;
-               }
+               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;
@@ -251,38 +261,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 = primary_lp;
-       hev->xSizeMinus1 = sizeof(ev->event) - 1;
+       hev->xTargetLp = primaryLp;
+       hev->xSizeMinus1 = sizeof(ev->event)-1;
        hev->xRc = HvLpEvent_Rc_Good;
-       hev->xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primary_lp,
+       hev->xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primaryLp,
                        HvLpEvent_Type_MachineFac);
-       hev->xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primary_lp,
+       hev->xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primaryLp,
                        HvLpEvent_Type_MachineFac);
 
        return ev;
 }
 
-static int signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd)
+static int signal_vsp_instruction(struct VspCmdData *vspCmd)
 {
        struct pending_event *ev = new_pending_event();
        int rc;
-       struct vsp_rsp_data response;
+       struct VspRspData response;
 
        if (ev == NULL)
                return -ENOMEM;
 
        init_completion(&response.com);
-       response.response = vsp_cmd;
+       response.response = vspCmd;
        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 = (u64)&response;
-       ev->event.data.vsp_cmd.cmd = vsp_cmd->cmd;
+       ev->event.data.vsp_cmd.token.ptr = &response;
+       ev->event.data.vsp_cmd.cmd = vspCmd->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),
-                       &(vsp_cmd->sub_data), sizeof(vsp_cmd->sub_data));
+                       &(vspCmd->sub_data), sizeof(vspCmd->sub_data));
        mb();
 
        rc = signal_event(ev);
@@ -295,7 +305,7 @@ static int signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd)
 /*
  * Send a 12-byte CE message to the primary partition VSP object
  */
-static int signal_ce_msg(char *ce_msg, struct ce_msg_comp_data *completion)
+static int signal_ce_msg(char *ce_msg, struct CeMsgCompleteData *completion)
 {
        struct pending_event *ev = new_pending_event();
 
@@ -310,23 +320,11 @@ static int signal_ce_msg(char *ce_msg, struct ce_msg_comp_data *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 ce_msg_comp_data *completion, void *dma_data,
+               struct CeMsgCompleteData *completion, void *dma_data,
                unsigned dma_data_length, unsigned remote_address)
 {
        struct pending_event *ev = new_pending_event();
@@ -358,7 +356,7 @@ static int shutdown(void)
        if (rc) {
                printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), "
                                "hard shutdown commencing\n", rc);
-               mf_power_off();
+               mf_powerOff();
        } else
                printk(KERN_INFO "mf.c: init has been successfully notified "
                                "to proceed with shutdown\n");
@@ -369,12 +367,10 @@ static int shutdown(void)
  * The primary partition VSP object is sending us a new
  * event flow.  Handle it...
  */
-static void handle_int(struct io_mf_lp_event *event)
+static void intReceived(struct IoMFLpEvent *event)
 {
-       struct ce_msg_data *ce_msg_data;
-       struct ce_msg_data *pce_msg_data;
-       unsigned long flags;
-       struct pending_event *pev;
+       int freeIt = 0;
+       struct pending_event *two = NULL;
 
        /* ack the interrupt */
        event->hp_lp_event.xRc = HvLpEvent_Rc_Good;
@@ -383,42 +379,49 @@ static void handle_int(struct io_mf_lp_event *event)
        /* process interrupt */
        switch (event->hp_lp_event.xSubtype) {
        case 0: /* CE message */
-               ce_msg_data = &event->data.ce_msg;
-               switch (ce_msg_data->ce_msg[3]) {
+               switch (event->data.ce_msg.ce_msg[3]) {
                case 0x5B:      /* power control notification */
-                       if ((ce_msg_data->ce_msg[5] & 0x20) != 0) {
+                       if ((event->data.ce_msg.ce_msg[5] & 0x20) != 0) {
                                printk(KERN_INFO "mf.c: Commencing partition shutdown\n");
                                if (shutdown() == 0)
-                                       signal_ce_msg_simple(0xDB, NULL);
+                                       signal_ce_msg("\x00\x00\x00\xDB\x00\x00\x00\x00\x00\x00\x00\x00", NULL);
                        }
                        break;
                case 0xC0:      /* get time */
-                       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)
+                       if ((pending_event_head == NULL) ||
+                           (pending_event_head->event.data.ce_msg.ce_msg[3]
+                            != 0x40))
                                break;
-                       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;
+                       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, ce_msg_data);
+                                       (*handler)(token, &(event->data.ce_msg));
                        }
+                       break;
+               }
+
+               /* remove from queue */
+               if (freeIt == 1) {
+                       unsigned long flags;
+
                        spin_lock_irqsave(&pending_event_spinlock, flags);
-                       free_pending_event(pev);
+                       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);
+                       }
                        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");
@@ -432,70 +435,68 @@ static void handle_int(struct io_mf_lp_event *event)
  * of a flow we sent to them.  If there are other flows queued
  * up, we must send another one now...
  */
-static void handle_ack(struct io_mf_lp_event *event)
+static void ackReceived(struct IoMFLpEvent *event)
 {
        unsigned long flags;
-       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;
+       struct pending_event * two = NULL;
+       unsigned long freeIt = 0;
 
        /* handle current event */
-       if (pending_event_head == NULL) {
-               printk(KERN_ERR "mf.c: stack empty for receiving ack\n");
-               return;
-       }
-
-       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;
+       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;
-               }
-               if (ce_msg_data->ce_msg[2] == 0)
+               case 4: /* allocate */
+               case 5: /* deallocate */
+                       if (pending_event_head->hdlr != NULL) {
+                               union safe_cast mySafeCast;
+
+                               mySafeCast.ptr_as_u64 = event->hp_lp_event.xCorrelationToken;
+                               (*pending_event_head->hdlr)(mySafeCast.ptr, event->data.alloc.count);
+                       }
+                       freeIt = 1;
                        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");
+               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;
+                       }
                        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) && (free_it == 1)) {
+       if ((pending_event_head != NULL) && (freeIt == 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 */
@@ -509,15 +510,15 @@ static void handle_ack(struct io_mf_lp_event *event)
  * parse it enough to know if it is an interrupt or an
  * acknowledge.
  */
-static void hv_handler(struct HvLpEvent *event, struct pt_regs *regs)
+static void hvHandler(struct HvLpEvent *event, struct pt_regs *regs)
 {
        if ((event != NULL) && (event->xType == HvLpEvent_Type_MachineFac)) {
                switch(event->xFlags.xFunction) {
                case HvLpEvent_Function_Ack:
-                       handle_ack((struct io_mf_lp_event *)event);
+                       ackReceived((struct IoMFLpEvent *)event);
                        break;
                case HvLpEvent_Function_Int:
-                       handle_int((struct io_mf_lp_event *)event);
+                       intReceived((struct IoMFLpEvent *)event);
                        break;
                default:
                        printk(KERN_ERR "mf.c: non ack/int event received\n");
@@ -531,9 +532,9 @@ static void hv_handler(struct HvLpEvent *event, struct pt_regs *regs)
  * Global kernel interface to allocate and seed events into the
  * Hypervisor.
  */
-void mf_allocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type,
+void mf_allocateLpEvents(HvLpIndex targetLp, HvLpEvent_Type type,
                unsigned size, unsigned count, MFCompleteHandler hdlr,
-               void *user_token)
+               void *userToken)
 {
        struct pending_event *ev = new_pending_event();
        int rc;
@@ -541,11 +542,14 @@ void mf_allocate_lp_events(HvLpIndex target_lp, 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 = (u64)user_token;
+               ev->event.hp_lp_event.xCorrelationToken = mine.ptr_as_u64;
                ev->event.hp_lp_event.x.xSubtypeData =
                        subtype_data('M', 'F', 'M', 'A');
-               ev->event.data.alloc.target_lp = target_lp;
+               ev->event.data.alloc.target_lp = targetLp;
                ev->event.data.alloc.type = type;
                ev->event.data.alloc.size = size;
                ev->event.data.alloc.count = count;
@@ -553,16 +557,16 @@ void mf_allocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type,
                rc = signal_event(ev);
        }
        if ((rc != 0) && (hdlr != NULL))
-               (*hdlr)(user_token, rc);
+               (*hdlr)(userToken, rc);
 }
-EXPORT_SYMBOL(mf_allocate_lp_events);
+EXPORT_SYMBOL(mf_allocateLpEvents);
 
 /*
  * Global kernel interface to unseed and deallocate events already in
  * Hypervisor.
  */
-void mf_deallocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type,
-               unsigned count, MFCompleteHandler hdlr, void *user_token)
+void mf_deallocateLpEvents(HvLpIndex targetLp, HvLpEvent_Type type,
+               unsigned count, MFCompleteHandler hdlr, void *userToken)
 {
        struct pending_event *ev = new_pending_event();
        int rc;
@@ -570,31 +574,33 @@ void mf_deallocate_lp_events(HvLpIndex target_lp, 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 = (u64)user_token;
+               ev->event.hp_lp_event.xCorrelationToken = mine.ptr_as_u64;
                ev->event.hp_lp_event.x.xSubtypeData =
                        subtype_data('M', 'F', 'M', 'D');
-               ev->event.data.alloc.target_lp = target_lp;
+               ev->event.data.alloc.target_lp = targetLp;
                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)(user_token, rc);
+               (*hdlr)(userToken, rc);
 }
-EXPORT_SYMBOL(mf_deallocate_lp_events);
+EXPORT_SYMBOL(mf_deallocateLpEvents);
 
 /*
  * Global kernel interface to tell the VSP object in the primary
  * partition to power this partition off.
  */
-void mf_power_off(void)
+void mf_powerOff(void)
 {
        printk(KERN_INFO "mf.c: Down it goes...\n");
-       signal_ce_msg_simple(0x4d, NULL);
-       for (;;)
-               ;
+       signal_ce_msg("\x00\x00\x00\x4D\x00\x00\x00\x00\x00\x00\x00\x00", NULL);
+       for (;;);
 }
 
 /*
@@ -604,21 +610,18 @@ void mf_power_off(void)
 void mf_reboot(void)
 {
        printk(KERN_INFO "mf.c: Preparing to bounce...\n");
-       signal_ce_msg_simple(0x4e, NULL);
-       for (;;)
-               ;
+       signal_ce_msg("\x00\x00\x00\x4E\x00\x00\x00\x00\x00\x00\x00\x00", NULL);
+       for (;;);
 }
 
 /*
  * Display a single word SRC onto the VSP control panel.
  */
-void mf_display_src(u32 word)
+void mf_displaySrc(u32 word)
 {
        u8 ce[12];
 
-       memset(ce, 0, sizeof(ce));
-       ce[3] = 0x4a;
-       ce[7] = 0x01;
+       memcpy(ce, "\x00\x00\x00\x4A\x00\x00\x00\x01\x00\x00\x00\x00", 12);
        ce[8] = word >> 24;
        ce[9] = word >> 16;
        ce[10] = word >> 8;
@@ -629,7 +632,7 @@ void mf_display_src(u32 word)
 /*
  * Display a single word SRC of the form "PROGXXXX" on the VSP control panel.
  */
-void mf_display_progress(u16 value)
+void mf_displayProgress(u16 value)
 {
        u8 ce[12];
        u8 src[72];
@@ -653,9 +656,9 @@ void mf_display_progress(u16 value)
  * Clear the VSP control panel.  Used to "erase" an SRC that was
  * previously displayed.
  */
-void mf_clear_src(void)
+void mf_clearSrc(void)
 {
-       signal_ce_msg_simple(0x4b, NULL);
+       signal_ce_msg("\x00\x00\x00\x4B\x00\x00\x00\x00\x00\x00\x00\x00", NULL);
 }
 
 /*
@@ -671,331 +674,71 @@ 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, &hv_handler);
+       HvLpEvent_registerHandler(HvLpEvent_Type_MachineFac, &hvHandler);
 
        /* virtual continue ack */
-       signal_ce_msg_simple(0x57, NULL);
+       signal_ce_msg("\x00\x00\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00", NULL);
 
        /* initialization complete */
-       printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities "
-                       "initialized\n");
-}
-
-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)
-{
-       struct rtc_time_data *rtc = token;
-
-       memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg));
-       rtc->rc = 0;
-       complete(&rtc->com);
+       printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities initialized\n");
 }
 
-int mf_get_rtc(struct rtc_time *tm)
+void mf_setSide(char side)
 {
-       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;
+       u64 newSide;
+       struct VspCmdData myVspCmd;
 
-       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;
+       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;
                        break;
-               }
-               p++;
-               len++;
-       }
-
-       if (len < off) {
-               *eof = 1;
-               len = 0;
-       }
-       return len;
-}
-
-#if 0
-static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side)
-{
-       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;
        }
+       myVspCmd.sub_data.ipl_type = newSide;
+       myVspCmd.cmd = 10;
 
-       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;
+       (void)signal_vsp_instruction(&myVspCmd);
 }
-#endif
 
-static int proc_mf_dump_side(char *page, char **start, off_t off,
-               int count, int *eof, void *data)
+char mf_getSide(void)
 {
-       int len;
-       char mf_current_side = ' ';
-       struct vsp_cmd_data vsp_cmd;
+       char returnValue = ' ';
+       int rc = 0;
+       struct VspCmdData myVspCmd;
 
-       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
-       vsp_cmd.cmd = 2;
-       vsp_cmd.sub_data.ipl_type = 0;
+       memset(&myVspCmd, 0, sizeof(myVspCmd));
+       myVspCmd.cmd = 2;
+       myVspCmd.sub_data.ipl_type = 0;
        mb();
+       rc = signal_vsp_instruction(&myVspCmd);
 
-       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 (rc != 0)
+               return returnValue;
 
-       if (count == 0)
-               return 0;
-
-       if (get_user(side, buffer))
-               return -EFAULT;
-
-       switch (side) {
-       case 'A':       newSide = 0;
+       if (myVspCmd.result_code == 0) {
+               switch (myVspCmd.sub_data.ipl_type) {
+               case 0: returnValue = 'A';
                        break;
-       case 'B':       newSide = 1;
+               case 1: returnValue = 'B';
                        break;
-       case 'C':       newSide = 2;
+               case 2: returnValue = 'C';
                        break;
-       case 'D':       newSide = 3;
+               default:        returnValue = 'D';
                        break;
-       default:
-               printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n");
-               return -EINVAL;
+               }
        }
-
-       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;
+       return returnValue;
 }
 
-#if 0
-static void mf_getSrcHistory(char *buffer, int size)
+void mf_getSrcHistory(char *buffer, int size)
 {
-       struct IplTypeReturnStuff return_stuff;
+#if 0
+       struct IplTypeReturnStuff returnStuff;
        struct pending_event *ev = new_pending_event();
        int rc = 0;
        char *pages[4];
@@ -1008,13 +751,13 @@ static void mf_getSrcHistory(char *buffer, int size)
                         || (pages[2] == NULL) || (pages[3] == NULL))
                return -ENOMEM;
 
-       return_stuff.xType = 0;
-       return_stuff.xRc = 0;
-       return_stuff.xDone = 0;
+       returnStuff.xType = 0;
+       returnStuff.xRc = 0;
+       returnStuff.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 = &return_stuff;
+       ev->event.data.vsp_cmd.xEvent = &returnStuff;
        ev->event.data.vsp_cmd.cmd = 4;
        ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex();
        ev->event.data.vsp_cmd.result_code = 0xFF;
@@ -1027,213 +770,312 @@ static void mf_getSrcHistory(char *buffer, int size)
        if (signal_event(ev) != 0)
                return;
 
-       while (return_stuff.xDone != 1)
+       while (returnStuff.xDone != 1)
                udelay(10);
-       if (return_stuff.xRc == 0)
+       if (returnStuff.xRc == 0)
                memcpy(buffer, pages[0], size);
        kfree(pages[0]);
        kfree(pages[1]);
        kfree(pages[2]);
        kfree(pages[3]);
-}
-#endif
-
-static int proc_mf_dump_src(char *page, char **start, off_t off,
-               int count, int *eof, void *data)
-{
-#if 0
-       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
 }
 
-static int proc_mf_change_src(struct file *file, const char __user *buffer,
-               unsigned long count, void *data)
+void mf_setCmdLine(const char *cmdline, int size, u64 side)
 {
-       char stkbuf[10];
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EACCES;
+       struct VspCmdData myVspCmd;
+       dma_addr_t dma_addr = 0;
+       char *page = dma_alloc_coherent(iSeries_vio_dev, size, &dma_addr,
+                       GFP_ATOMIC);
 
-       if ((count < 4) && (count != 1)) {
-               printk(KERN_ERR "mf_proc: invalid src\n");
-               return -EINVAL;
+       if (page == NULL) {
+               printk(KERN_ERR "mf.c: couldn't allocate memory to set command line\n");
+               return;
        }
 
-       if (count > (sizeof(stkbuf) - 1))
-               count = sizeof(stkbuf) - 1;
-       if (copy_from_user(stkbuf, buffer, count))
-               return -EFAULT;
+       copy_from_user(page, cmdline, size);
 
-       if ((count == 1) && (*stkbuf == '\0'))
-               mf_clear_src();
-       else
-               mf_display_src(*(u32 *)stkbuf);
+       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);
 
-       return count;
+       dma_free_coherent(iSeries_vio_dev, size, page, dma_addr);
 }
 
-static int proc_mf_change_cmdline(struct file *file, const char __user *buffer,
-               unsigned long count, void *data)
+int mf_getCmdLine(char *cmdline, int *size, u64 side)
 {
-       struct vsp_cmd_data vsp_cmd;
+       struct VspCmdData myVspCmd;
+       int rc;
+       int len = *size;
        dma_addr_t dma_addr;
-       char *page;
-       int ret = -EACCES;
 
-       if (!capable(CAP_SYS_ADMIN))
-               goto out;
-
-       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;
+       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();
-       (void)signal_vsp_instruction(&vsp_cmd);
-       ret = count;
+       rc = signal_vsp_instruction(&myVspCmd);
 
-out_free:
-       dma_free_coherent(iSeries_vio_dev, count, page, dma_addr);
-out:
-       return ret;
-}
+       if (rc == 0) {
+               if (myVspCmd.result_code == 0)
+                       len = myVspCmd.sub_data.length_out;
+#if 0
+               else
+                       memcpy(cmdline, "Bad cmdline", 11);
+#endif
+       }
 
-static ssize_t proc_mf_change_vmlinux(struct file *file,
-                                     const char __user *buf,
-                                     size_t count, loff_t *ppos)
-{
-       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;
+       dma_unmap_single(iSeries_vio_dev, dma_addr, *size, DMA_FROM_DEVICE);
+
+       return len;
+}
 
-       rc = -EACCES;
-       if (!capable(CAP_SYS_ADMIN))
-               goto out;
 
-       dma_addr = 0;
-       page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr,
+int mf_setVmlinuxChunk(const char *buffer, int size, int offset, u64 side)
+{
+       struct VspCmdData myVspCmd;
+       int rc;
+       dma_addr_t dma_addr = 0;
+       char *page = dma_alloc_coherent(iSeries_vio_dev, size, &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;
+               return -ENOMEM;
        }
-       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;
+
+       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;
+       }
+
+       dma_free_coherent(iSeries_vio_dev, size, page, dma_addr);
+
+       return rc;
+}
+
+int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side)
+{
+       struct VspCmdData myVspCmd;
+       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(&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(&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:
+       rc = signal_vsp_instruction(&myVspCmd);
+       if (rc == 0) {
+               if (myVspCmd.result_code == 0)
+                       *size = myVspCmd.sub_data.length_out;
+               else
+                       rc = -ENOMEM;
+       }
+
+       dma_unmap_single(iSeries_vio_dev, dma_addr, len, DMA_FROM_DEVICE);
+
        return rc;
 }
 
-static struct file_operations proc_vmlinux_operations = {
-       .write          = proc_mf_change_vmlinux,
+int mf_setRtcTime(unsigned long time)
+{
+       struct rtc_time tm;
+
+       to_tm(time, &tm);
+
+       return mf_setRtc(&tm);
+}
+
+struct RtcTimeData {
+       struct completion com;
+       struct CeMsgData xCeMsg;
+       int xRc;
 };
 
-static int __init mf_proc_init(void)
+void getRtcTimeComplete(void * token, struct CeMsgData *ceMsg)
 {
-       struct proc_dir_entry *mf_proc_root;
-       struct proc_dir_entry *ent;
-       struct proc_dir_entry *mf;
-       char name[2];
-       int i;
+       struct RtcTimeData *rtc = (struct RtcTimeData *)token;
 
-       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;
-       }
+       memcpy(&(rtc->xCeMsg), ceMsg, sizeof(rtc->xCeMsg));
+       rtc->xRc = 0;
+       complete(&rtc->com);
+}
 
-       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;
+static unsigned long lastsec = 1;
 
+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;
+       }
        return 0;
 }
 
-__initcall(mf_proc_init);
+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;
+       }
 
-#endif /* CONFIG_PROC_FS */
+       return rc;
+}
+
+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);
+
+       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);
+}