mf.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:29k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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