1 /*
2   * mf.c
3   * Copyright (C) 2001 Troy D. Armstrong  IBM Corporation
4   *
5   * This modules exists as an interface between a Linux secondary partition
6   * running on an iSeries and the primary partition's Virtual Service
7   * Processor (VSP) object.  The VSP has final authority over powering on/off
8   * all partitions in the iSeries.  It also provides miscellaneous low-level
9   * machine facility type operations.
10   *
11   *
12   * This program is free software; you can redistribute it and/or modify
13   * it under the terms of the GNU General Public License as published by
14   * the Free Software Foundation; either version 2 of the License, or
15   * (at your option) any later version.
16   *
17   * This program is distributed in the hope that it will be useful,
18   * but WITHOUT ANY WARRANTY; without even the implied warranty of
19   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20   * GNU General Public License for more details.
21   *
22   * You should have received a copy of the GNU General Public License
23   * along with this program; if not, write to the Free Software
24   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
25   */
26 
27 #include <asm/iSeries/mf.h>
28 #include <linux/types.h>
29 #include <linux/errno.h>
30 #include <linux/kernel.h>
31 #include <linux/init.h>
32 #include <linux/mm.h>
33 #include <asm/iSeries/HvLpConfig.h>
34 #include <linux/slab.h>
35 #include <linux/delay.h>
36 #include <asm/nvram.h>
37 #include <asm/time.h>
38 #include <asm/iSeries/ItSpCommArea.h>
39 #include <asm/iSeries/mf_proc.h>
40 #include <asm/iSeries/iSeries_proc.h>
41 #include <asm/uaccess.h>
42 #include <linux/pci.h>
43 
44 extern struct pci_dev * iSeries_vio_dev;
45 
46 /*
47  * This is the structure layout for the Machine Facilities LPAR event
48  * flows.
49  */
50 struct VspCmdData;
51 struct CeMsgData;
52 union SafeCast
53 {
54 	u64 ptrAsU64;
55 	void *ptr;
56 };
57 
58 
59 typedef void (*CeMsgCompleteHandler)( void *token, struct CeMsgData *vspCmdRsp );
60 
61 struct CeMsgCompleteData
62 {
63 	CeMsgCompleteHandler xHdlr;
64 	void *xToken;
65 };
66 
67 struct VspRspData
68 {
69 	struct semaphore *xSemaphore;
70 	struct VspCmdData *xResponse;
71 };
72 
73 struct IoMFLpEvent
74 {
75 	struct HvLpEvent xHvLpEvent;
76 
77 	u16 xSubtypeRc;
78 	u16 xRsvd1;
79 	u32 xRsvd2;
80 
81 	union
82 	{
83 
84 		struct AllocData
85 		{
86 			u16 xSize;
87 			u16 xType;
88 			u32 xCount;
89 			u16 xRsvd3;
90 			u8 xRsvd4;
91 			HvLpIndex xTargetLp;
92 		} xAllocData;
93 
94 		struct CeMsgData
95 		{
96 			u8 xCEMsg[12];
97 			char xReserved[4];
98 			struct CeMsgCompleteData *xToken;
99 		} xCEMsgData;
100 
101 		struct VspCmdData
102 		{
103 			union SafeCast xTokenUnion;
104 			u16 xCmd;
105 			HvLpIndex xLpIndex;
106 			u8 xRc;
107 			u32 xReserved1;
108 
109 			union VspCmdSubData
110 			{
111 				struct
112 				{
113 					u64 xState;
114 				} xGetStateOut;
115 
116 				struct
117 				{
118 					u64 xIplType;
119 				} xGetIplTypeOut, xFunction02SelectIplTypeIn;
120 
121 				struct
122 				{
123 					u64 xIplMode;
124 				} xGetIplModeOut, xFunction02SelectIplModeIn;
125 
126 				struct
127 				{
128 					u64 xPage[4];
129 				} xGetSrcHistoryIn;
130 
131 				struct
132 				{
133 					u64 xFlag;
134 				} xGetAutoIplWhenPrimaryIplsOut,
135 					xSetAutoIplWhenPrimaryIplsIn,
136 					xWhiteButtonPowerOffIn,
137 					xFunction08FastPowerOffIn,
138 					xIsSpcnRackPowerIncompleteOut;
139 
140 				struct
141 				{
142 					u64 xToken;
143 					u64 xAddressType;
144 					u64 xSide;
145 					u32 xTransferLength;
146 					u32 xOffset;
147 				} xSetKernelImageIn,
148 					xGetKernelImageIn,
149 					xSetKernelCmdLineIn,
150 					xGetKernelCmdLineIn;
151 
152 				struct
153 				{
154 					u32 xTransferLength;
155 				} xGetKernelImageOut,xGetKernelCmdLineOut;
156 
157 
158 				u8 xReserved2[80];
159 
160 			} xSubData;
161 		} xVspCmd;
162 	} xUnion;
163 };
164 
165 
166 /*
167  * All outgoing event traffic is kept on a FIFO queue.  The first
168  * pointer points to the one that is outstanding, and all new
169  * requests get stuck on the end.  Also, we keep a certain number of
170  * preallocated stack elements so that we can operate very early in
171  * the boot up sequence (before kmalloc is ready).
172  */
173 struct StackElement
174 {
175 	struct StackElement * next;
176 	struct IoMFLpEvent event;
177 	MFCompleteHandler hdlr;
178 	char dmaData[72];
179 	unsigned dmaDataLength;
180 	unsigned remoteAddress;
181 };
182 static spinlock_t spinlock;
183 static struct StackElement * head = NULL;
184 static struct StackElement * tail = NULL;
185 static struct StackElement * avail = NULL;
186 static struct StackElement prealloc[16];
187 
188 /*
189  * Put a stack element onto the available queue, so it can get reused.
190  * Attention! You must have the spinlock before calling!
191  */
free(struct StackElement * element)192 void free( struct StackElement * element )
193 {
194 	if ( element != NULL )
195 	{
196 		element->next = avail;
197 		avail = element;
198 	}
199 }
200 
201 /*
202  * Enqueue the outbound event onto the stack.  If the queue was
203  * empty to begin with, we must also issue it via the Hypervisor
204  * interface.  There is a section of code below that will touch
205  * the first stack pointer without the protection of the spinlock.
206  * This is OK, because we know that nobody else will be modifying
207  * the first pointer when we do this.
208  */
signalEvent(struct StackElement * newElement)209 static int signalEvent( struct StackElement * newElement )
210 {
211 	int rc = 0;
212 	unsigned long flags;
213 	int go = 1;
214 	struct StackElement * element;
215 	HvLpEvent_Rc hvRc;
216 
217 	/* enqueue the event */
218 	if ( newElement != NULL )
219 	{
220 		spin_lock_irqsave( &spinlock, flags );
221 		if ( head == NULL )
222 			head = newElement;
223 		else {
224 			go = 0;
225 			tail->next = newElement;
226 		}
227 		newElement->next = NULL;
228 		tail = newElement;
229 		spin_unlock_irqrestore( &spinlock, flags );
230 	}
231 
232 	/* send the event */
233 	while ( go )
234 	{
235 		go = 0;
236 
237 		/* any DMA data to send beforehand? */
238 		if ( head->dmaDataLength > 0 )
239 			HvCallEvent_dmaToSp( head->dmaData, head->remoteAddress, head->dmaDataLength, HvLpDma_Direction_LocalToRemote );
240 
241 		hvRc = HvCallEvent_signalLpEvent(&head->event.xHvLpEvent);
242 		if ( hvRc != HvLpEvent_Rc_Good )
243 		{
244 			printk( KERN_ERR "mf.c: HvCallEvent_signalLpEvent() failed with %d\n", (int)hvRc );
245 
246 			spin_lock_irqsave( &spinlock, flags );
247 			element = head;
248 			head = head->next;
249 			if ( head != NULL )
250 				go = 1;
251 			spin_unlock_irqrestore( &spinlock, flags );
252 
253 			if ( element == newElement )
254 				rc = -EIO;
255 			else {
256 				if ( element->hdlr != NULL )
257 				{
258 					union SafeCast mySafeCast;
259 					mySafeCast.ptrAsU64 = element->event.xHvLpEvent.xCorrelationToken;
260 					(*element->hdlr)( mySafeCast.ptr, -EIO );
261 				}
262 			}
263 
264 			spin_lock_irqsave( &spinlock, flags );
265 			free( element );
266 			spin_unlock_irqrestore( &spinlock, flags );
267 		}
268 	}
269 
270 	return rc;
271 }
272 
273 /*
274  * Allocate a new StackElement structure, and initialize it.
275  */
newStackElement(void)276 static struct StackElement * newStackElement( void )
277 {
278 	struct StackElement * newElement = NULL;
279 	HvLpIndex primaryLp = HvLpConfig_getPrimaryLpIndex();
280 	unsigned long flags;
281 
282 	if ( newElement == NULL )
283 	{
284 		spin_lock_irqsave( &spinlock, flags );
285 		if ( avail != NULL )
286 		{
287 			newElement = avail;
288 			avail = avail->next;
289 		}
290 		spin_unlock_irqrestore( &spinlock, flags );
291 	}
292 
293 	if ( newElement == NULL )
294 		newElement = kmalloc(sizeof(struct StackElement),GFP_ATOMIC);
295 
296 	if ( newElement == NULL )
297 	{
298 		printk( KERN_ERR "mf.c: unable to kmalloc %ld bytes\n", sizeof(struct StackElement) );
299 		return NULL;
300 	}
301 
302 	memset( newElement, 0, sizeof(struct StackElement) );
303 	newElement->event.xHvLpEvent.xFlags.xValid = 1;
304 	newElement->event.xHvLpEvent.xFlags.xAckType = HvLpEvent_AckType_ImmediateAck;
305 	newElement->event.xHvLpEvent.xFlags.xAckInd = HvLpEvent_AckInd_DoAck;
306 	newElement->event.xHvLpEvent.xFlags.xFunction = HvLpEvent_Function_Int;
307 	newElement->event.xHvLpEvent.xType = HvLpEvent_Type_MachineFac;
308 	newElement->event.xHvLpEvent.xSourceLp = HvLpConfig_getLpIndex();
309 	newElement->event.xHvLpEvent.xTargetLp = primaryLp;
310 	newElement->event.xHvLpEvent.xSizeMinus1 = sizeof(newElement->event)-1;
311 	newElement->event.xHvLpEvent.xRc = HvLpEvent_Rc_Good;
312 	newElement->event.xHvLpEvent.xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primaryLp,HvLpEvent_Type_MachineFac);
313 	newElement->event.xHvLpEvent.xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primaryLp,HvLpEvent_Type_MachineFac);
314 
315 	return newElement;
316 }
317 
signalVspInstruction(struct VspCmdData * vspCmd)318 static int signalVspInstruction( struct VspCmdData *vspCmd )
319 {
320 	struct StackElement * newElement = newStackElement();
321 	int rc = 0;
322 	struct VspRspData response;
323 	DECLARE_MUTEX_LOCKED(Semaphore);
324 	response.xSemaphore = &Semaphore;
325 	response.xResponse = vspCmd;
326 
327 	if ( newElement == NULL )
328 		rc = -ENOMEM;
329 	else {
330 		newElement->event.xHvLpEvent.xSubtype = 6;
331 		newElement->event.xHvLpEvent.x.xSubtypeData = ('M'<<24)+('F'<<16)+('V'<<8)+('I'<<0);
332 		newElement->event.xUnion.xVspCmd.xTokenUnion.ptr = &response;
333 		newElement->event.xUnion.xVspCmd.xCmd = vspCmd->xCmd;
334 		newElement->event.xUnion.xVspCmd.xLpIndex = HvLpConfig_getLpIndex();
335 		newElement->event.xUnion.xVspCmd.xRc = 0xFF;
336 		newElement->event.xUnion.xVspCmd.xReserved1 = 0;
337 		memcpy(&(newElement->event.xUnion.xVspCmd.xSubData),&(vspCmd->xSubData), sizeof(vspCmd->xSubData));
338 		mb();
339 
340 		rc = signalEvent(newElement);
341 	}
342 
343 	if (rc == 0)
344 	{
345 		down(&Semaphore);
346 	}
347 
348 	return rc;
349 }
350 
351 
352 /*
353  * Send a 12-byte CE message to the primary partition VSP object
354  */
signalCEMsg(char * ceMsg,void * token)355 static int signalCEMsg( char * ceMsg, void * token )
356 {
357 	struct StackElement * newElement = newStackElement();
358 	int rc = 0;
359 
360 	if ( newElement == NULL )
361 		rc = -ENOMEM;
362 	else {
363 		newElement->event.xHvLpEvent.xSubtype = 0;
364 		newElement->event.xHvLpEvent.x.xSubtypeData = ('M'<<24)+('F'<<16)+('C'<<8)+('E'<<0);
365 		memcpy( newElement->event.xUnion.xCEMsgData.xCEMsg, ceMsg, 12 );
366 		newElement->event.xUnion.xCEMsgData.xToken = token;
367 		rc = signalEvent(newElement);
368 	}
369 
370 	return rc;
371 }
372 
373 /*
374  * Send a 12-byte CE message and DMA data to the primary partition VSP object
375  */
dmaAndSignalCEMsg(char * ceMsg,void * token,void * dmaData,unsigned dmaDataLength,unsigned remoteAddress)376 static int dmaAndSignalCEMsg( char * ceMsg, void * token, void * dmaData, unsigned dmaDataLength, unsigned remoteAddress )
377 {
378 	struct StackElement * newElement = newStackElement();
379 	int rc = 0;
380 
381 	if ( newElement == NULL )
382 		rc = -ENOMEM;
383 	else {
384 		newElement->event.xHvLpEvent.xSubtype = 0;
385 		newElement->event.xHvLpEvent.x.xSubtypeData = ('M'<<24)+('F'<<16)+('C'<<8)+('E'<<0);
386 		memcpy( newElement->event.xUnion.xCEMsgData.xCEMsg, ceMsg, 12 );
387 		newElement->event.xUnion.xCEMsgData.xToken = token;
388 		memcpy( newElement->dmaData, dmaData, dmaDataLength );
389 		newElement->dmaDataLength = dmaDataLength;
390 		newElement->remoteAddress = remoteAddress;
391 		rc = signalEvent(newElement);
392 	}
393 
394 	return rc;
395 }
396 
397 /*
398  * Initiate a nice (hopefully) shutdown of Linux.  We simply are
399  * going to try and send the init process a SIGINT signal.  If
400  * this fails (why?), we'll simply force it off in a not-so-nice
401  * manner.
402  */
shutdown(void)403 static int shutdown( void )
404 {
405 	extern int cad_pid; /* from kernel/sys.c */
406 	int rc = kill_proc(cad_pid,SIGINT,1);
407 
408 	if ( rc )
409 	{
410 		printk( KERN_ALERT "mf.c: SIGINT to init failed (%d), hard shutdown commencing\n", rc );
411 		mf_powerOff();
412 	}
413 	else
414 		printk( KERN_INFO "mf.c: init has been successfully notified to proceed with shutdown\n" );
415 
416 	return rc;
417 }
418 
419 /*
420  * The primary partition VSP object is sending us a new
421  * event flow.  Handle it...
422  */
intReceived(struct IoMFLpEvent * event)423 static void intReceived( struct IoMFLpEvent * event )
424 {
425 	int freeIt = 0;
426 	struct StackElement * two = NULL;
427 	/* ack the interrupt */
428 	event->xHvLpEvent.xRc = HvLpEvent_Rc_Good;
429 	HvCallEvent_ackLpEvent( &event->xHvLpEvent );
430 
431     /* process interrupt */
432 	switch( event->xHvLpEvent.xSubtype )
433 	{
434 	case 0:	/* CE message */
435 		switch( event->xUnion.xCEMsgData.xCEMsg[3] )
436 		{
437 		case 0x5B:	/* power control notification */
438 			if ( (event->xUnion.xCEMsgData.xCEMsg[5]&0x20) != 0 )
439 			{
440 				printk( KERN_INFO "mf.c: Commencing partition shutdown\n" );
441 				if ( shutdown() == 0 )
442 					signalCEMsg( "\x00\x00\x00\xDB\x00\x00\x00\x00\x00\x00\x00\x00", NULL );
443 			}
444 			break;
445 		case 0xC0:	/* get time */
446 			{
447 				if ( (head != NULL) && ( head->event.xUnion.xCEMsgData.xCEMsg[3] == 0x40 ) )
448 				{
449 					freeIt = 1;
450 					if ( head->event.xUnion.xCEMsgData.xToken != 0 )
451 					{
452 						CeMsgCompleteHandler xHdlr = head->event.xUnion.xCEMsgData.xToken->xHdlr;
453 						void * token = head->event.xUnion.xCEMsgData.xToken->xToken;
454 
455 						if (xHdlr != NULL)
456 							(*xHdlr)( token, &(event->xUnion.xCEMsgData) );
457 					}
458 				}
459 			}
460 			break;
461 		}
462 
463 		/* remove from queue */
464 		if ( freeIt == 1 )
465 		{
466 			unsigned long flags;
467 			spin_lock_irqsave( &spinlock, flags );
468 			if ( head != NULL )
469 			{
470 				struct StackElement *oldHead = head;
471 				head = head->next;
472 				two = head;
473 				free( oldHead );
474 			}
475 			spin_unlock_irqrestore( &spinlock, flags );
476 		}
477 
478 		/* send next waiting event */
479 		if ( two != NULL )
480 			signalEvent( NULL );
481 		break;
482 	case 1:	/* IT sys shutdown */
483 		printk( KERN_INFO "mf.c: Commencing system shutdown\n" );
484 		shutdown();
485 		break;
486 	}
487 }
488 
489 /*
490  * The primary partition VSP object is acknowledging the receipt
491  * of a flow we sent to them.  If there are other flows queued
492  * up, we must send another one now...
493  */
ackReceived(struct IoMFLpEvent * event)494 static void ackReceived( struct IoMFLpEvent * event )
495 {
496 	unsigned long flags;
497 	struct StackElement * two = NULL;
498 	unsigned long freeIt = 0;
499 
500     /* handle current event */
501 	if ( head != NULL )
502 	{
503 		switch( event->xHvLpEvent.xSubtype )
504 		{
505 		case 0:     /* CE msg */
506 			if ( event->xUnion.xCEMsgData.xCEMsg[3] == 0x40 )
507 			{
508 				if ( event->xUnion.xCEMsgData.xCEMsg[2] != 0 )
509 				{
510 					freeIt = 1;
511 					if ( head->event.xUnion.xCEMsgData.xToken != 0 )
512 					{
513 						CeMsgCompleteHandler xHdlr = head->event.xUnion.xCEMsgData.xToken->xHdlr;
514 						void * token = head->event.xUnion.xCEMsgData.xToken->xToken;
515 
516 						if (xHdlr != NULL)
517 							(*xHdlr)( token, &(event->xUnion.xCEMsgData) );
518 					}
519 				}
520 			} else {
521 				freeIt = 1;
522 			}
523 			break;
524 		case 4:	/* allocate */
525 		case 5:	/* deallocate */
526 			if ( head->hdlr != NULL )
527 			{
528 				union SafeCast mySafeCast;
529 				mySafeCast.ptrAsU64 = event->xHvLpEvent.xCorrelationToken;
530 				(*head->hdlr)( mySafeCast.ptr, event->xUnion.xAllocData.xCount );
531 			}
532 			freeIt = 1;
533 			break;
534 		case 6:
535 			{
536 				struct VspRspData *rsp = (struct VspRspData *)event->xUnion.xVspCmd.xTokenUnion.ptr;
537 
538 				if (rsp != NULL)
539 				{
540 					if (rsp->xResponse != NULL)
541 						memcpy(rsp->xResponse, &(event->xUnion.xVspCmd), sizeof(event->xUnion.xVspCmd));
542 					if (rsp->xSemaphore != NULL)
543 						up(rsp->xSemaphore);
544 				} else {
545 					printk( KERN_ERR "mf.c: no rsp\n");
546 				}
547 				freeIt = 1;
548 			}
549 			break;
550 		}
551 	}
552 	else
553 		printk( KERN_ERR "mf.c: stack empty for receiving ack\n" );
554 
555     /* remove from queue */
556 	spin_lock_irqsave( &spinlock, flags );
557 	if (( head != NULL ) && ( freeIt == 1 ))
558 	{
559 		struct StackElement *oldHead = head;
560 		head = head->next;
561 		two = head;
562 		free( oldHead );
563 	}
564 	spin_unlock_irqrestore( &spinlock, flags );
565 
566     /* send next waiting event */
567 	if ( two != NULL )
568 		signalEvent( NULL );
569 }
570 
571 /*
572  * This is the generic event handler we are registering with
573  * the Hypervisor.  Ensure the flows are for us, and then
574  * parse it enough to know if it is an interrupt or an
575  * acknowledge.
576  */
hvHandler(struct HvLpEvent * event,struct pt_regs * regs)577 static void hvHandler( struct HvLpEvent * event, struct pt_regs * regs )
578 {
579 	if ( (event != NULL) && (event->xType == HvLpEvent_Type_MachineFac) )
580 	{
581 		switch( event->xFlags.xFunction )
582 		{
583 		case HvLpEvent_Function_Ack:
584 			ackReceived( (struct IoMFLpEvent *)event );
585 			break;
586 		case HvLpEvent_Function_Int:
587 			intReceived( (struct IoMFLpEvent *)event );
588 			break;
589 		default:
590 			printk( KERN_ERR "mf.c: non ack/int event received\n" );
591 			break;
592 		}
593 	}
594 	else
595 		printk( KERN_ERR "mf.c: alien event received\n" );
596 }
597 
598 /*
599  * Global kernel interface to allocate and seed events into the
600  * Hypervisor.
601  */
mf_allocateLpEvents(HvLpIndex targetLp,HvLpEvent_Type type,unsigned size,unsigned count,MFCompleteHandler hdlr,void * userToken)602 void mf_allocateLpEvents( HvLpIndex targetLp,
603 			  HvLpEvent_Type type,
604 			  unsigned size,
605 			  unsigned count,
606 			  MFCompleteHandler hdlr,
607 			  void * userToken )
608 {
609 	struct StackElement * newElement = newStackElement();
610 	int rc = 0;
611 
612 	if ( newElement == NULL )
613 		rc = -ENOMEM;
614 	else {
615 		union SafeCast mine;
616 		mine.ptr = userToken;
617 		newElement->event.xHvLpEvent.xSubtype = 4;
618 		newElement->event.xHvLpEvent.xCorrelationToken = mine.ptrAsU64;
619 		newElement->event.xHvLpEvent.x.xSubtypeData = ('M'<<24)+('F'<<16)+('M'<<8)+('A'<<0);
620 		newElement->event.xUnion.xAllocData.xTargetLp = targetLp;
621 		newElement->event.xUnion.xAllocData.xType = type;
622 		newElement->event.xUnion.xAllocData.xSize = size;
623 		newElement->event.xUnion.xAllocData.xCount = count;
624 		newElement->hdlr = hdlr;
625 		rc = signalEvent(newElement);
626 	}
627 
628 	if ( (rc != 0) && (hdlr != NULL) )
629 		(*hdlr)( userToken, rc );
630 }
631 
632 /*
633  * Global kernel interface to unseed and deallocate events already in
634  * Hypervisor.
635  */
mf_deallocateLpEvents(HvLpIndex targetLp,HvLpEvent_Type type,unsigned count,MFCompleteHandler hdlr,void * userToken)636 void mf_deallocateLpEvents( HvLpIndex targetLp,
637 			    HvLpEvent_Type type,
638 			    unsigned count,
639 			    MFCompleteHandler hdlr,
640 			    void * userToken )
641 {
642 	struct StackElement * newElement = newStackElement();
643 	int rc = 0;
644 
645 	if ( newElement == NULL )
646 		rc = -ENOMEM;
647 	else {
648 		union SafeCast mine;
649 		mine.ptr = userToken;
650 		newElement->event.xHvLpEvent.xSubtype = 5;
651 		newElement->event.xHvLpEvent.xCorrelationToken = mine.ptrAsU64;
652 		newElement->event.xHvLpEvent.x.xSubtypeData = ('M'<<24)+('F'<<16)+('M'<<8)+('D'<<0);
653 		newElement->event.xUnion.xAllocData.xTargetLp = targetLp;
654 		newElement->event.xUnion.xAllocData.xType = type;
655 		newElement->event.xUnion.xAllocData.xCount = count;
656 		newElement->hdlr = hdlr;
657 		rc = signalEvent(newElement);
658 	}
659 
660 	if ( (rc != 0) && (hdlr != NULL) )
661 		(*hdlr)( userToken, rc );
662 }
663 
664 /*
665  * Global kernel interface to tell the VSP object in the primary
666  * partition to power this partition off.
667  */
mf_powerOff(void)668 void mf_powerOff( void )
669 {
670 	printk( KERN_INFO "mf.c: Down it goes...\n" );
671 	signalCEMsg( "\x00\x00\x00\x4D\x00\x00\x00\x00\x00\x00\x00\x00", NULL );
672 	for (;;);
673 }
674 
675 /*
676  * Global kernel interface to tell the VSP object in the primary
677  * partition to reboot this partition.
678  */
mf_reboot(void)679 void mf_reboot( void )
680 {
681 	printk( KERN_INFO "mf.c: Preparing to bounce...\n" );
682 	signalCEMsg( "\x00\x00\x00\x4E\x00\x00\x00\x00\x00\x00\x00\x00", NULL );
683 	for (;;);
684 }
685 
686 /*
687  * Display a single word SRC onto the VSP control panel.
688  */
mf_displaySrc(u32 word)689 void mf_displaySrc( u32 word )
690 {
691 	u8 ce[12];
692 
693 	memcpy( ce, "\x00\x00\x00\x4A\x00\x00\x00\x01\x00\x00\x00\x00", 12 );
694 	ce[8] = word>>24;
695 	ce[9] = word>>16;
696 	ce[10] = word>>8;
697 	ce[11] = word;
698 	signalCEMsg( ce, NULL );
699 }
700 
701 /*
702  * Display a single word SRC of the form "PROGXXXX" on the VSP control panel.
703  */
mf_displayProgress(u16 value)704 void mf_displayProgress( u16 value )
705 {
706 	u8 ce[12];
707 	u8 src[72];
708 
709 	memcpy( ce, "\x00\x00\x04\x4A\x00\x00\x00\x48\x00\x00\x00\x00", 12 );
710 	memcpy( src,
711 		"\x01\x00\x00\x01"
712 		"\x00\x00\x00\x00"
713 		"\x00\x00\x00\x00"
714 		"\x00\x00\x00\x00"
715 		"\x00\x00\x00\x00"
716 		"\x00\x00\x00\x00"
717 		"\x00\x00\x00\x00"
718 		"\x00\x00\x00\x00"
719 		"\x00\x00\x00\x00"
720 		"\x00\x00\x00\x00"
721 		"PROGxxxx"
722 		"                        ",
723 		72 );
724 	src[6] = value>>8;
725 	src[7] = value&255;
726 	src[44] = "0123456789ABCDEF"[(value>>12)&15];
727 	src[45] = "0123456789ABCDEF"[(value>>8)&15];
728 	src[46] = "0123456789ABCDEF"[(value>>4)&15];
729 	src[47] = "0123456789ABCDEF"[value&15];
730 	dmaAndSignalCEMsg( ce, NULL, src, sizeof(src), 9*64*1024 );
731 }
732 
733 /*
734  * Clear the VSP control panel.  Used to "erase" an SRC that was
735  * previously displayed.
736  */
mf_clearSrc(void)737 void mf_clearSrc( void )
738 {
739 	signalCEMsg( "\x00\x00\x00\x4B\x00\x00\x00\x00\x00\x00\x00\x00", NULL );
740 }
741 
742 /*
743  * Initialization code here.
744  */
mf_init(void)745 void mf_init( void )
746 {
747 	int i;
748 
749     /* initialize */
750 	spin_lock_init( &spinlock );
751 	for ( i = 0; i < sizeof(prealloc)/sizeof(*prealloc); ++i )
752 		free( &prealloc[i] );
753 	HvLpEvent_registerHandler( HvLpEvent_Type_MachineFac, &hvHandler );
754 
755 	/* virtual continue ack */
756 	signalCEMsg( "\x00\x00\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00", NULL );
757 
758 	/* initialization complete */
759 	printk( KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities initialized\n" );
760 
761 	iSeries_proc_callback(&mf_proc_init);
762 }
763 
mf_setSide(char side)764 void mf_setSide(char side)
765 {
766 	int rc = 0;
767 	u64 newSide = 0;
768 	struct VspCmdData myVspCmd;
769 
770 	memset(&myVspCmd, 0, sizeof(myVspCmd));
771 	if (side == 'A')
772 		newSide = 0;
773 	else if (side == 'B')
774 		newSide = 1;
775 	else if (side == 'C')
776 		newSide = 2;
777 	else
778 		newSide = 3;
779 
780 	myVspCmd.xSubData.xFunction02SelectIplTypeIn.xIplType = newSide;
781 	myVspCmd.xCmd = 10;
782 
783 	rc = signalVspInstruction(&myVspCmd);
784 }
785 
mf_getSide(void)786 char mf_getSide(void)
787 {
788 	char returnValue = ' ';
789 	int rc = 0;
790 	struct VspCmdData myVspCmd;
791 
792 	memset(&myVspCmd, 0, sizeof(myVspCmd));
793 	myVspCmd.xCmd = 2;
794 	myVspCmd.xSubData.xFunction02SelectIplTypeIn.xIplType = 0;
795 	mb();
796 	rc = signalVspInstruction(&myVspCmd);
797 
798 	if (rc != 0)
799 	{
800 		return returnValue;
801 	} else {
802 		if (myVspCmd.xRc == 0)
803 		{
804 			if (myVspCmd.xSubData.xGetIplTypeOut.xIplType == 0)
805 				returnValue = 'A';
806 			else if (myVspCmd.xSubData.xGetIplTypeOut.xIplType == 1)
807 				returnValue = 'B';
808 			else if (myVspCmd.xSubData.xGetIplTypeOut.xIplType == 2)
809 				returnValue = 'C';
810 			else
811 				returnValue = 'D';
812 		}
813 	}
814 
815 	return returnValue;
816 }
817 
mf_getSrcHistory(char * buffer,int size)818 void mf_getSrcHistory(char *buffer, int size)
819 {
820     /*    struct IplTypeReturnStuff returnStuff;
821      struct StackElement * newElement = newStackElement();
822      int rc = 0;
823      char *pages[4];
824 
825      pages[0] = kmalloc(4096, GFP_ATOMIC);
826      pages[1] = kmalloc(4096, GFP_ATOMIC);
827      pages[2] = kmalloc(4096, GFP_ATOMIC);
828      pages[3] = kmalloc(4096, GFP_ATOMIC);
829      if (( newElement == NULL ) || (pages[0] == NULL) || (pages[1] == NULL) || (pages[2] == NULL) || (pages[3] == NULL))
830      rc = -ENOMEM;
831      else
832      {
833      returnStuff.xType = 0;
834      returnStuff.xRc = 0;
835      returnStuff.xDone = 0;
836      newElement->event.xHvLpEvent.xSubtype = 6;
837      newElement->event.xHvLpEvent.x.xSubtypeData = ('M'<<24)+('F'<<16)+('V'<<8)+('I'<<0);
838      newElement->event.xUnion.xVspCmd.xEvent = &returnStuff;
839      newElement->event.xUnion.xVspCmd.xCmd = 4;
840      newElement->event.xUnion.xVspCmd.xLpIndex = HvLpConfig_getLpIndex();
841      newElement->event.xUnion.xVspCmd.xRc = 0xFF;
842      newElement->event.xUnion.xVspCmd.xReserved1 = 0;
843      newElement->event.xUnion.xVspCmd.xSubData.xGetSrcHistoryIn.xPage[0] = (0x8000000000000000ULL | virt_to_absolute((unsigned long)pages[0]));
844      newElement->event.xUnion.xVspCmd.xSubData.xGetSrcHistoryIn.xPage[1] = (0x8000000000000000ULL | virt_to_absolute((unsigned long)pages[1]));
845      newElement->event.xUnion.xVspCmd.xSubData.xGetSrcHistoryIn.xPage[2] = (0x8000000000000000ULL | virt_to_absolute((unsigned long)pages[2]));
846      newElement->event.xUnion.xVspCmd.xSubData.xGetSrcHistoryIn.xPage[3] = (0x8000000000000000ULL | virt_to_absolute((unsigned long)pages[3]));
847      mb();
848      rc = signalEvent(newElement);
849      }
850 
851      if (rc != 0)
852      {
853      return;
854      }
855      else
856      {
857      while (returnStuff.xDone != 1)
858      {
859      udelay(10);
860      }
861 
862      if (returnStuff.xRc == 0)
863      {
864      memcpy(buffer, pages[0], size);
865      }
866      }
867 
868      kfree(pages[0]);
869      kfree(pages[1]);
870      kfree(pages[2]);
871      kfree(pages[3]);*/
872 }
873 
mf_setCmdLine(const char * cmdline,int size,u64 side)874 void mf_setCmdLine(const char *cmdline, int size, u64 side)
875 {
876 	struct VspCmdData myVspCmd;
877 	int rc = 0;
878 	dma_addr_t dma_addr = 0;
879 	char *page = pci_alloc_consistent(iSeries_vio_dev, size, &dma_addr);
880 
881 	if (page == NULL) {
882 		printk(KERN_ERR "mf.c: couldn't allocate memory to set command line\n");
883 		return;
884 	}
885 
886 	copy_from_user(page, cmdline, size);
887 
888 	memset(&myVspCmd, 0, sizeof(myVspCmd));
889 	myVspCmd.xCmd = 31;
890 	myVspCmd.xSubData.xSetKernelCmdLineIn.xToken = dma_addr;
891 	myVspCmd.xSubData.xSetKernelCmdLineIn.xAddressType = HvLpDma_AddressType_TceIndex;
892 	myVspCmd.xSubData.xSetKernelCmdLineIn.xSide = side;
893 	myVspCmd.xSubData.xSetKernelCmdLineIn.xTransferLength = size;
894 	mb();
895 	rc = signalVspInstruction(&myVspCmd);
896 
897 	pci_free_consistent(iSeries_vio_dev, size, page, dma_addr);
898 }
899 
mf_getCmdLine(char * cmdline,int * size,u64 side)900 int mf_getCmdLine(char *cmdline, int *size, u64 side)
901 {
902 	struct VspCmdData myVspCmd;
903 	int rc = 0;
904 	int len = *size;
905 	dma_addr_t dma_addr = pci_map_single(iSeries_vio_dev, cmdline, *size, PCI_DMA_FROMDEVICE);
906 
907 	memset(cmdline, 0, *size);
908 	memset(&myVspCmd, 0, sizeof(myVspCmd));
909 	myVspCmd.xCmd = 33;
910 	myVspCmd.xSubData.xGetKernelCmdLineIn.xToken = dma_addr;
911 	myVspCmd.xSubData.xGetKernelCmdLineIn.xAddressType = HvLpDma_AddressType_TceIndex;
912 	myVspCmd.xSubData.xGetKernelCmdLineIn.xSide = side;
913 	myVspCmd.xSubData.xGetKernelCmdLineIn.xTransferLength = *size;
914 	mb();
915 	rc = signalVspInstruction(&myVspCmd);
916 
917 	if ( ! rc ) {
918 
919 		if (myVspCmd.xRc == 0)
920 		{
921 			len = myVspCmd.xSubData.xGetKernelCmdLineOut.xTransferLength;
922 		}
923 		/* else
924 			{
925 			memcpy(cmdline, "Bad cmdline", 11);
926 			}
927 		*/
928 	}
929 
930 	pci_unmap_single(iSeries_vio_dev, dma_addr, *size, PCI_DMA_FROMDEVICE);
931 
932 	return len;
933 }
934 
935 
mf_setVmlinuxChunk(const char * buffer,int size,int offset,u64 side)936 int mf_setVmlinuxChunk(const char *buffer, int size, int offset, u64 side)
937 {
938 	struct VspCmdData myVspCmd;
939 	int rc = 0;
940 
941 	dma_addr_t dma_addr = 0;
942 
943 	char *page = pci_alloc_consistent(iSeries_vio_dev, size, &dma_addr);
944 
945 	if (page == NULL) {
946 		printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n");
947 		return -ENOMEM;
948 	}
949 
950 	copy_from_user(page, buffer, size);
951 	memset(&myVspCmd, 0, sizeof(myVspCmd));
952 
953 	myVspCmd.xCmd = 30;
954 	myVspCmd.xSubData.xGetKernelImageIn.xToken = dma_addr;
955 	myVspCmd.xSubData.xGetKernelImageIn.xAddressType = HvLpDma_AddressType_TceIndex;
956 	myVspCmd.xSubData.xGetKernelImageIn.xSide = side;
957 	myVspCmd.xSubData.xGetKernelImageIn.xOffset = offset;
958 	myVspCmd.xSubData.xGetKernelImageIn.xTransferLength = size;
959 	mb();
960 	rc = signalVspInstruction(&myVspCmd);
961 
962 	if (rc == 0)
963 	{
964 		if (myVspCmd.xRc == 0)
965 		{
966 			rc = 0;
967 		} else {
968 			rc = -ENOMEM;
969 		}
970 	}
971 
972 	pci_free_consistent(iSeries_vio_dev, size, page, dma_addr);
973 
974 	return rc;
975 }
976 
mf_getVmlinuxChunk(char * buffer,int * size,int offset,u64 side)977 int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side)
978 {
979 	struct VspCmdData myVspCmd;
980 	int rc = 0;
981 	int len = *size;
982 
983 	dma_addr_t dma_addr = pci_map_single(iSeries_vio_dev, buffer, *size, PCI_DMA_FROMDEVICE);
984 
985 	memset(buffer, 0, len);
986 
987 	memset(&myVspCmd, 0, sizeof(myVspCmd));
988 	myVspCmd.xCmd = 32;
989 	myVspCmd.xSubData.xGetKernelImageIn.xToken = dma_addr;
990 	myVspCmd.xSubData.xGetKernelImageIn.xAddressType = HvLpDma_AddressType_TceIndex;
991 	myVspCmd.xSubData.xGetKernelImageIn.xSide = side;
992 	myVspCmd.xSubData.xGetKernelImageIn.xOffset = offset;
993 	myVspCmd.xSubData.xGetKernelImageIn.xTransferLength = len;
994 	mb();
995 	rc = signalVspInstruction(&myVspCmd);
996 
997 	if (rc == 0)
998 	{
999 		if (myVspCmd.xRc == 0)
1000 		{
1001 			*size = myVspCmd.xSubData.xGetKernelImageOut.xTransferLength;
1002 		} else {
1003 			rc = -ENOMEM;
1004 		}
1005 	}
1006 
1007 	pci_unmap_single(iSeries_vio_dev, dma_addr, len, PCI_DMA_FROMDEVICE);
1008 
1009 	return rc;
1010 }
1011 
mf_setRtcTime(unsigned long time)1012 int mf_setRtcTime(unsigned long time)
1013 {
1014 	struct rtc_time tm;
1015 
1016 	to_tm(time, &tm);
1017 
1018 	return mf_setRtc( &tm );
1019 }
1020 
1021 struct RtcTimeData
1022 {
1023 	struct semaphore *xSemaphore;
1024 	struct CeMsgData xCeMsg;
1025 	int xRc;
1026 };
1027 
getRtcTimeComplete(void * token,struct CeMsgData * ceMsg)1028 void getRtcTimeComplete(void * token, struct CeMsgData *ceMsg)
1029 {
1030 	struct RtcTimeData *rtc = (struct RtcTimeData *)token;
1031 
1032 	memcpy(&(rtc->xCeMsg), ceMsg, sizeof(rtc->xCeMsg));
1033 
1034 	rtc->xRc = 0;
1035 	up(rtc->xSemaphore);
1036 }
1037 
1038 static unsigned long lastsec = 1;
1039 
mf_getRtcTime(unsigned long * time)1040 int mf_getRtcTime(unsigned long *time)
1041 {
1042 /*    unsigned long usec, tsec; */
1043 
1044 	u32 dataWord1 = *((u32 *)(&xSpCommArea.xBcdTimeAtIplStart));
1045 	u32 dataWord2 = *(((u32 *)&(xSpCommArea.xBcdTimeAtIplStart)) + 1);
1046 	int year = 1970;
1047 	int year1 = ( dataWord1 >> 24 ) & 0x000000FF;
1048 	int year2 = ( dataWord1 >> 16 ) & 0x000000FF;
1049 	int sec = ( dataWord1 >> 8 ) & 0x000000FF;
1050 	int min = dataWord1 & 0x000000FF;
1051 	int hour = ( dataWord2 >> 24 ) & 0x000000FF;
1052 	int day = ( dataWord2 >> 8 ) & 0x000000FF;
1053 	int mon = dataWord2 & 0x000000FF;
1054 
1055 	BCD_TO_BIN(sec);
1056 	BCD_TO_BIN(min);
1057 	BCD_TO_BIN(hour);
1058 	BCD_TO_BIN(day);
1059 	BCD_TO_BIN(mon);
1060 	BCD_TO_BIN(year1);
1061 	BCD_TO_BIN(year2);
1062 	year = year1 * 100 + year2;
1063 
1064 	*time = mktime(year, mon, day, hour, min, sec);
1065 
1066 	*time += ( jiffies / HZ );
1067 
1068 	/* Now THIS is a nasty hack!
1069 	 * It ensures that the first two calls to mf_getRtcTime get different
1070 	 * answers.  That way the loop in init_time (time.c) will not think
1071 	 * the clock is stuck.
1072 	 */
1073 	if ( lastsec ) {
1074 		*time -= lastsec;
1075 		--lastsec;
1076 	}
1077 
1078 	return 0;
1079 
1080 }
1081 
mf_getRtc(struct rtc_time * tm)1082 int mf_getRtc( struct rtc_time * tm )
1083 {
1084 
1085 	struct CeMsgCompleteData ceComplete;
1086 	struct RtcTimeData rtcData;
1087 	int rc = 0;
1088 	DECLARE_MUTEX_LOCKED(Semaphore);
1089 
1090 	memset(&ceComplete, 0, sizeof(ceComplete));
1091 	memset(&rtcData, 0, sizeof(rtcData));
1092 
1093 	rtcData.xSemaphore = &Semaphore;
1094 
1095 	ceComplete.xHdlr = &getRtcTimeComplete;
1096 	ceComplete.xToken = (void *)&rtcData;
1097 
1098 	rc = signalCEMsg( "\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00", &ceComplete );
1099 
1100 	if ( rc == 0 )
1101 	{
1102 		down(&Semaphore);
1103 
1104 		if ( rtcData.xRc == 0)
1105 		{
1106 			if ( ( rtcData.xCeMsg.xCEMsg[2] == 0xa9 ) ||
1107 			     ( rtcData.xCeMsg.xCEMsg[2] == 0xaf ) ) {
1108 				/* TOD clock is not set */
1109 				tm->tm_sec = 1;
1110 				tm->tm_min = 1;
1111 				tm->tm_hour = 1;
1112 				tm->tm_mday = 10;
1113 				tm->tm_mon = 8;
1114 				tm->tm_year = 71;
1115 				mf_setRtc( tm );
1116 			}
1117 			{
1118 				u32 dataWord1 = *((u32 *)(rtcData.xCeMsg.xCEMsg+4));
1119 				u32 dataWord2 = *((u32 *)(rtcData.xCeMsg.xCEMsg+8));
1120 				u8 year = (dataWord1 >> 16 ) & 0x000000FF;
1121 				u8 sec = ( dataWord1 >> 8 ) & 0x000000FF;
1122 				u8 min = dataWord1 & 0x000000FF;
1123 				u8 hour = ( dataWord2 >> 24 ) & 0x000000FF;
1124 				u8 day = ( dataWord2 >> 8 ) & 0x000000FF;
1125 				u8 mon = dataWord2 & 0x000000FF;
1126 
1127 				BCD_TO_BIN(sec);
1128 				BCD_TO_BIN(min);
1129 				BCD_TO_BIN(hour);
1130 				BCD_TO_BIN(day);
1131 				BCD_TO_BIN(mon);
1132 				BCD_TO_BIN(year);
1133 
1134 				if ( year <= 69 )
1135 					year += 100;
1136 
1137 				tm->tm_sec = sec;
1138 				tm->tm_min = min;
1139 				tm->tm_hour = hour;
1140 				tm->tm_mday = day;
1141 				tm->tm_mon = mon;
1142 				tm->tm_year = year;
1143 			}
1144 		} else {
1145 			rc = rtcData.xRc;
1146 			tm->tm_sec = 0;
1147 			tm->tm_min = 0;
1148 			tm->tm_hour = 0;
1149 			tm->tm_mday = 15;
1150 			tm->tm_mon = 5;
1151 			tm->tm_year = 52;
1152 
1153 		}
1154 		tm->tm_wday = 0;
1155 		tm->tm_yday = 0;
1156 		tm->tm_isdst = 0;
1157 
1158 	}
1159 
1160 	return rc;
1161 
1162 }
1163 
mf_setRtc(struct rtc_time * tm)1164 int mf_setRtc(struct rtc_time * tm)
1165 {
1166 	char ceTime[12] = "\x00\x00\x00\x41\x00\x00\x00\x00\x00\x00\x00\x00";
1167 	int rc = 0;
1168 	u8 day, mon, hour, min, sec, y1, y2;
1169 	unsigned year;
1170 
1171 	year = 1900 + tm->tm_year;
1172 	y1 = year / 100;
1173 	y2 = year % 100;
1174 
1175 	sec = tm->tm_sec;
1176 	min = tm->tm_min;
1177 	hour = tm->tm_hour;
1178 	day = tm->tm_mday;
1179 	mon = tm->tm_mon + 1;
1180 
1181 	BIN_TO_BCD(sec);
1182 	BIN_TO_BCD(min);
1183 	BIN_TO_BCD(hour);
1184 	BIN_TO_BCD(mon);
1185 	BIN_TO_BCD(day);
1186 	BIN_TO_BCD(y1);
1187 	BIN_TO_BCD(y2);
1188 
1189 	ceTime[4] = y1;
1190 	ceTime[5] = y2;
1191 	ceTime[6] = sec;
1192 	ceTime[7] = min;
1193 	ceTime[8] = hour;
1194 	ceTime[10] = day;
1195 	ceTime[11] = mon;
1196 
1197 	rc = signalCEMsg( ceTime, NULL );
1198 
1199 	return rc;
1200 }
1201 
1202 
1203 
1204