1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
44extern struct pci_dev * iSeries_vio_dev;
45
46
47
48
49
50struct VspCmdData;
51struct CeMsgData;
52union SafeCast
53{
54 u64 ptrAsU64;
55 void *ptr;
56};
57
58
59typedef void (*CeMsgCompleteHandler)( void *token, struct CeMsgData *vspCmdRsp );
60
61struct CeMsgCompleteData
62{
63 CeMsgCompleteHandler xHdlr;
64 void *xToken;
65};
66
67struct VspRspData
68{
69 struct semaphore *xSemaphore;
70 struct VspCmdData *xResponse;
71};
72
73struct 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
168
169
170
171
172
173struct StackElement
174{
175 struct StackElement * next;
176 struct IoMFLpEvent event;
177 MFCompleteHandler hdlr;
178 char dmaData[72];
179 unsigned dmaDataLength;
180 unsigned remoteAddress;
181};
182static spinlock_t spinlock;
183static struct StackElement * head = NULL;
184static struct StackElement * tail = NULL;
185static struct StackElement * avail = NULL;
186static struct StackElement prealloc[16];
187
188
189
190
191
192void free( struct StackElement * element )
193{
194 if ( element != NULL )
195 {
196 element->next = avail;
197 avail = element;
198 }
199}
200
201
202
203
204
205
206
207
208
209static 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
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
233 while ( go )
234 {
235 go = 0;
236
237
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
275
276static 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
318static 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
354
355static 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
375
376static 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
399
400
401
402
403static int shutdown( void )
404{
405 extern int cad_pid;
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
421
422
423static void intReceived( struct IoMFLpEvent * event )
424{
425 int freeIt = 0;
426 struct StackElement * two = NULL;
427
428 event->xHvLpEvent.xRc = HvLpEvent_Rc_Good;
429 HvCallEvent_ackLpEvent( &event->xHvLpEvent );
430
431
432 switch( event->xHvLpEvent.xSubtype )
433 {
434 case 0:
435 switch( event->xUnion.xCEMsgData.xCEMsg[3] )
436 {
437 case 0x5B:
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:
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
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
479 if ( two != NULL )
480 signalEvent( NULL );
481 break;
482 case 1:
483 printk( KERN_INFO "mf.c: Commencing system shutdown\n" );
484 shutdown();
485 break;
486 }
487}
488
489
490
491
492
493
494static void ackReceived( struct IoMFLpEvent * event )
495{
496 unsigned long flags;
497 struct StackElement * two = NULL;
498 unsigned long freeIt = 0;
499
500
501 if ( head != NULL )
502 {
503 switch( event->xHvLpEvent.xSubtype )
504 {
505 case 0:
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:
525 case 5:
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
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
567 if ( two != NULL )
568 signalEvent( NULL );
569}
570
571
572
573
574
575
576
577static 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
600
601
602void 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
634
635
636void 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
666
667
668void 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
677
678
679void 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
688
689void 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
703
704void 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
735
736
737void mf_clearSrc( void )
738{
739 signalCEMsg( "\x00\x00\x00\x4B\x00\x00\x00\x00\x00\x00\x00\x00", NULL );
740}
741
742
743
744
745void mf_init( void )
746{
747 int i;
748
749
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
756 signalCEMsg( "\x00\x00\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00", NULL );
757
758
759 printk( KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities initialized\n" );
760
761 iSeries_proc_callback(&mf_proc_init);
762}
763
764void 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
786char 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
818void mf_getSrcHistory(char *buffer, int size)
819{
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872}
873
874void 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
900int 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
924
925
926
927
928 }
929
930 pci_unmap_single(iSeries_vio_dev, dma_addr, *size, PCI_DMA_FROMDEVICE);
931
932 return len;
933}
934
935
936int 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
977int 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
1012int 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
1021struct RtcTimeData
1022{
1023 struct semaphore *xSemaphore;
1024 struct CeMsgData xCeMsg;
1025 int xRc;
1026};
1027
1028void 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
1038static unsigned long lastsec = 1;
1039
1040int mf_getRtcTime(unsigned long *time)
1041{
1042
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
1069
1070
1071
1072
1073 if ( lastsec ) {
1074 *time -= lastsec;
1075 --lastsec;
1076 }
1077
1078 return 0;
1079
1080}
1081
1082int 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
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
1164int 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