Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.15 1321 lines 32 kB view raw
1/* 2 * Copyright (C) 2001 Troy D. Armstrong IBM Corporation 3 * Copyright (C) 2004-2005 Stephen Rothwell 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 <linux/types.h> 28#include <linux/errno.h> 29#include <linux/kernel.h> 30#include <linux/init.h> 31#include <linux/completion.h> 32#include <linux/delay.h> 33#include <linux/dma-mapping.h> 34#include <linux/bcd.h> 35#include <linux/rtc.h> 36 37#include <asm/time.h> 38#include <asm/uaccess.h> 39#include <asm/paca.h> 40#include <asm/abs_addr.h> 41#include <asm/iseries/vio.h> 42#include <asm/iseries/mf.h> 43#include <asm/iseries/hv_lp_config.h> 44#include <asm/iseries/it_lp_queue.h> 45 46#include "setup.h" 47 48extern int piranha_simulator; 49 50/* 51 * This is the structure layout for the Machine Facilites LPAR event 52 * flows. 53 */ 54struct vsp_cmd_data { 55 u64 token; 56 u16 cmd; 57 HvLpIndex lp_index; 58 u8 result_code; 59 u32 reserved; 60 union { 61 u64 state; /* GetStateOut */ 62 u64 ipl_type; /* GetIplTypeOut, Function02SelectIplTypeIn */ 63 u64 ipl_mode; /* GetIplModeOut, Function02SelectIplModeIn */ 64 u64 page[4]; /* GetSrcHistoryIn */ 65 u64 flag; /* GetAutoIplWhenPrimaryIplsOut, 66 SetAutoIplWhenPrimaryIplsIn, 67 WhiteButtonPowerOffIn, 68 Function08FastPowerOffIn, 69 IsSpcnRackPowerIncompleteOut */ 70 struct { 71 u64 token; 72 u64 address_type; 73 u64 side; 74 u32 length; 75 u32 offset; 76 } kern; /* SetKernelImageIn, GetKernelImageIn, 77 SetKernelCmdLineIn, GetKernelCmdLineIn */ 78 u32 length_out; /* GetKernelImageOut, GetKernelCmdLineOut */ 79 u8 reserved[80]; 80 } sub_data; 81}; 82 83struct vsp_rsp_data { 84 struct completion com; 85 struct vsp_cmd_data *response; 86}; 87 88struct alloc_data { 89 u16 size; 90 u16 type; 91 u32 count; 92 u16 reserved1; 93 u8 reserved2; 94 HvLpIndex target_lp; 95}; 96 97struct ce_msg_data; 98 99typedef void (*ce_msg_comp_hdlr)(void *token, struct ce_msg_data *vsp_cmd_rsp); 100 101struct ce_msg_comp_data { 102 ce_msg_comp_hdlr handler; 103 void *token; 104}; 105 106struct ce_msg_data { 107 u8 ce_msg[12]; 108 char reserved[4]; 109 struct ce_msg_comp_data *completion; 110}; 111 112struct io_mf_lp_event { 113 struct HvLpEvent hp_lp_event; 114 u16 subtype_result_code; 115 u16 reserved1; 116 u32 reserved2; 117 union { 118 struct alloc_data alloc; 119 struct ce_msg_data ce_msg; 120 struct vsp_cmd_data vsp_cmd; 121 } data; 122}; 123 124#define subtype_data(a, b, c, d) \ 125 (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) 126 127/* 128 * All outgoing event traffic is kept on a FIFO queue. The first 129 * pointer points to the one that is outstanding, and all new 130 * requests get stuck on the end. Also, we keep a certain number of 131 * preallocated pending events so that we can operate very early in 132 * the boot up sequence (before kmalloc is ready). 133 */ 134struct pending_event { 135 struct pending_event *next; 136 struct io_mf_lp_event event; 137 MFCompleteHandler hdlr; 138 char dma_data[72]; 139 unsigned dma_data_length; 140 unsigned remote_address; 141}; 142static spinlock_t pending_event_spinlock; 143static struct pending_event *pending_event_head; 144static struct pending_event *pending_event_tail; 145static struct pending_event *pending_event_avail; 146static struct pending_event pending_event_prealloc[16]; 147 148/* 149 * Put a pending event onto the available queue, so it can get reused. 150 * Attention! You must have the pending_event_spinlock before calling! 151 */ 152static void free_pending_event(struct pending_event *ev) 153{ 154 if (ev != NULL) { 155 ev->next = pending_event_avail; 156 pending_event_avail = ev; 157 } 158} 159 160/* 161 * Enqueue the outbound event onto the stack. If the queue was 162 * empty to begin with, we must also issue it via the Hypervisor 163 * interface. There is a section of code below that will touch 164 * the first stack pointer without the protection of the pending_event_spinlock. 165 * This is OK, because we know that nobody else will be modifying 166 * the first pointer when we do this. 167 */ 168static int signal_event(struct pending_event *ev) 169{ 170 int rc = 0; 171 unsigned long flags; 172 int go = 1; 173 struct pending_event *ev1; 174 HvLpEvent_Rc hv_rc; 175 176 /* enqueue the event */ 177 if (ev != NULL) { 178 ev->next = NULL; 179 spin_lock_irqsave(&pending_event_spinlock, flags); 180 if (pending_event_head == NULL) 181 pending_event_head = ev; 182 else { 183 go = 0; 184 pending_event_tail->next = ev; 185 } 186 pending_event_tail = ev; 187 spin_unlock_irqrestore(&pending_event_spinlock, flags); 188 } 189 190 /* send the event */ 191 while (go) { 192 go = 0; 193 194 /* any DMA data to send beforehand? */ 195 if (pending_event_head->dma_data_length > 0) 196 HvCallEvent_dmaToSp(pending_event_head->dma_data, 197 pending_event_head->remote_address, 198 pending_event_head->dma_data_length, 199 HvLpDma_Direction_LocalToRemote); 200 201 hv_rc = HvCallEvent_signalLpEvent( 202 &pending_event_head->event.hp_lp_event); 203 if (hv_rc != HvLpEvent_Rc_Good) { 204 printk(KERN_ERR "mf.c: HvCallEvent_signalLpEvent() " 205 "failed with %d\n", (int)hv_rc); 206 207 spin_lock_irqsave(&pending_event_spinlock, flags); 208 ev1 = pending_event_head; 209 pending_event_head = pending_event_head->next; 210 if (pending_event_head != NULL) 211 go = 1; 212 spin_unlock_irqrestore(&pending_event_spinlock, flags); 213 214 if (ev1 == ev) 215 rc = -EIO; 216 else if (ev1->hdlr != NULL) 217 (*ev1->hdlr)((void *)ev1->event.hp_lp_event.xCorrelationToken, -EIO); 218 219 spin_lock_irqsave(&pending_event_spinlock, flags); 220 free_pending_event(ev1); 221 spin_unlock_irqrestore(&pending_event_spinlock, flags); 222 } 223 } 224 225 return rc; 226} 227 228/* 229 * Allocate a new pending_event structure, and initialize it. 230 */ 231static struct pending_event *new_pending_event(void) 232{ 233 struct pending_event *ev = NULL; 234 HvLpIndex primary_lp = HvLpConfig_getPrimaryLpIndex(); 235 unsigned long flags; 236 struct HvLpEvent *hev; 237 238 spin_lock_irqsave(&pending_event_spinlock, flags); 239 if (pending_event_avail != NULL) { 240 ev = pending_event_avail; 241 pending_event_avail = pending_event_avail->next; 242 } 243 spin_unlock_irqrestore(&pending_event_spinlock, flags); 244 if (ev == NULL) { 245 ev = kmalloc(sizeof(struct pending_event), GFP_ATOMIC); 246 if (ev == NULL) { 247 printk(KERN_ERR "mf.c: unable to kmalloc %ld bytes\n", 248 sizeof(struct pending_event)); 249 return NULL; 250 } 251 } 252 memset(ev, 0, sizeof(struct pending_event)); 253 hev = &ev->event.hp_lp_event; 254 hev->xFlags.xValid = 1; 255 hev->xFlags.xAckType = HvLpEvent_AckType_ImmediateAck; 256 hev->xFlags.xAckInd = HvLpEvent_AckInd_DoAck; 257 hev->xFlags.xFunction = HvLpEvent_Function_Int; 258 hev->xType = HvLpEvent_Type_MachineFac; 259 hev->xSourceLp = HvLpConfig_getLpIndex(); 260 hev->xTargetLp = primary_lp; 261 hev->xSizeMinus1 = sizeof(ev->event) - 1; 262 hev->xRc = HvLpEvent_Rc_Good; 263 hev->xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primary_lp, 264 HvLpEvent_Type_MachineFac); 265 hev->xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primary_lp, 266 HvLpEvent_Type_MachineFac); 267 268 return ev; 269} 270 271static int signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd) 272{ 273 struct pending_event *ev = new_pending_event(); 274 int rc; 275 struct vsp_rsp_data response; 276 277 if (ev == NULL) 278 return -ENOMEM; 279 280 init_completion(&response.com); 281 response.response = vsp_cmd; 282 ev->event.hp_lp_event.xSubtype = 6; 283 ev->event.hp_lp_event.x.xSubtypeData = 284 subtype_data('M', 'F', 'V', 'I'); 285 ev->event.data.vsp_cmd.token = (u64)&response; 286 ev->event.data.vsp_cmd.cmd = vsp_cmd->cmd; 287 ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex(); 288 ev->event.data.vsp_cmd.result_code = 0xFF; 289 ev->event.data.vsp_cmd.reserved = 0; 290 memcpy(&(ev->event.data.vsp_cmd.sub_data), 291 &(vsp_cmd->sub_data), sizeof(vsp_cmd->sub_data)); 292 mb(); 293 294 rc = signal_event(ev); 295 if (rc == 0) 296 wait_for_completion(&response.com); 297 return rc; 298} 299 300 301/* 302 * Send a 12-byte CE message to the primary partition VSP object 303 */ 304static int signal_ce_msg(char *ce_msg, struct ce_msg_comp_data *completion) 305{ 306 struct pending_event *ev = new_pending_event(); 307 308 if (ev == NULL) 309 return -ENOMEM; 310 311 ev->event.hp_lp_event.xSubtype = 0; 312 ev->event.hp_lp_event.x.xSubtypeData = 313 subtype_data('M', 'F', 'C', 'E'); 314 memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12); 315 ev->event.data.ce_msg.completion = completion; 316 return signal_event(ev); 317} 318 319/* 320 * Send a 12-byte CE message (with no data) to the primary partition VSP object 321 */ 322static int signal_ce_msg_simple(u8 ce_op, struct ce_msg_comp_data *completion) 323{ 324 u8 ce_msg[12]; 325 326 memset(ce_msg, 0, sizeof(ce_msg)); 327 ce_msg[3] = ce_op; 328 return signal_ce_msg(ce_msg, completion); 329} 330 331/* 332 * Send a 12-byte CE message and DMA data to the primary partition VSP object 333 */ 334static int dma_and_signal_ce_msg(char *ce_msg, 335 struct ce_msg_comp_data *completion, void *dma_data, 336 unsigned dma_data_length, unsigned remote_address) 337{ 338 struct pending_event *ev = new_pending_event(); 339 340 if (ev == NULL) 341 return -ENOMEM; 342 343 ev->event.hp_lp_event.xSubtype = 0; 344 ev->event.hp_lp_event.x.xSubtypeData = 345 subtype_data('M', 'F', 'C', 'E'); 346 memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12); 347 ev->event.data.ce_msg.completion = completion; 348 memcpy(ev->dma_data, dma_data, dma_data_length); 349 ev->dma_data_length = dma_data_length; 350 ev->remote_address = remote_address; 351 return signal_event(ev); 352} 353 354/* 355 * Initiate a nice (hopefully) shutdown of Linux. We simply are 356 * going to try and send the init process a SIGINT signal. If 357 * this fails (why?), we'll simply force it off in a not-so-nice 358 * manner. 359 */ 360static int shutdown(void) 361{ 362 int rc = kill_proc(1, SIGINT, 1); 363 364 if (rc) { 365 printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), " 366 "hard shutdown commencing\n", rc); 367 mf_power_off(); 368 } else 369 printk(KERN_INFO "mf.c: init has been successfully notified " 370 "to proceed with shutdown\n"); 371 return rc; 372} 373 374/* 375 * The primary partition VSP object is sending us a new 376 * event flow. Handle it... 377 */ 378static void handle_int(struct io_mf_lp_event *event) 379{ 380 struct ce_msg_data *ce_msg_data; 381 struct ce_msg_data *pce_msg_data; 382 unsigned long flags; 383 struct pending_event *pev; 384 385 /* ack the interrupt */ 386 event->hp_lp_event.xRc = HvLpEvent_Rc_Good; 387 HvCallEvent_ackLpEvent(&event->hp_lp_event); 388 389 /* process interrupt */ 390 switch (event->hp_lp_event.xSubtype) { 391 case 0: /* CE message */ 392 ce_msg_data = &event->data.ce_msg; 393 switch (ce_msg_data->ce_msg[3]) { 394 case 0x5B: /* power control notification */ 395 if ((ce_msg_data->ce_msg[5] & 0x20) != 0) { 396 printk(KERN_INFO "mf.c: Commencing partition shutdown\n"); 397 if (shutdown() == 0) 398 signal_ce_msg_simple(0xDB, NULL); 399 } 400 break; 401 case 0xC0: /* get time */ 402 spin_lock_irqsave(&pending_event_spinlock, flags); 403 pev = pending_event_head; 404 if (pev != NULL) 405 pending_event_head = pending_event_head->next; 406 spin_unlock_irqrestore(&pending_event_spinlock, flags); 407 if (pev == NULL) 408 break; 409 pce_msg_data = &pev->event.data.ce_msg; 410 if (pce_msg_data->ce_msg[3] != 0x40) 411 break; 412 if (pce_msg_data->completion != NULL) { 413 ce_msg_comp_hdlr handler = 414 pce_msg_data->completion->handler; 415 void *token = pce_msg_data->completion->token; 416 417 if (handler != NULL) 418 (*handler)(token, ce_msg_data); 419 } 420 spin_lock_irqsave(&pending_event_spinlock, flags); 421 free_pending_event(pev); 422 spin_unlock_irqrestore(&pending_event_spinlock, flags); 423 /* send next waiting event */ 424 if (pending_event_head != NULL) 425 signal_event(NULL); 426 break; 427 } 428 break; 429 case 1: /* IT sys shutdown */ 430 printk(KERN_INFO "mf.c: Commencing system shutdown\n"); 431 shutdown(); 432 break; 433 } 434} 435 436/* 437 * The primary partition VSP object is acknowledging the receipt 438 * of a flow we sent to them. If there are other flows queued 439 * up, we must send another one now... 440 */ 441static void handle_ack(struct io_mf_lp_event *event) 442{ 443 unsigned long flags; 444 struct pending_event *two = NULL; 445 unsigned long free_it = 0; 446 struct ce_msg_data *ce_msg_data; 447 struct ce_msg_data *pce_msg_data; 448 struct vsp_rsp_data *rsp; 449 450 /* handle current event */ 451 if (pending_event_head == NULL) { 452 printk(KERN_ERR "mf.c: stack empty for receiving ack\n"); 453 return; 454 } 455 456 switch (event->hp_lp_event.xSubtype) { 457 case 0: /* CE msg */ 458 ce_msg_data = &event->data.ce_msg; 459 if (ce_msg_data->ce_msg[3] != 0x40) { 460 free_it = 1; 461 break; 462 } 463 if (ce_msg_data->ce_msg[2] == 0) 464 break; 465 free_it = 1; 466 pce_msg_data = &pending_event_head->event.data.ce_msg; 467 if (pce_msg_data->completion != NULL) { 468 ce_msg_comp_hdlr handler = 469 pce_msg_data->completion->handler; 470 void *token = pce_msg_data->completion->token; 471 472 if (handler != NULL) 473 (*handler)(token, ce_msg_data); 474 } 475 break; 476 case 4: /* allocate */ 477 case 5: /* deallocate */ 478 if (pending_event_head->hdlr != NULL) 479 (*pending_event_head->hdlr)((void *)event->hp_lp_event.xCorrelationToken, event->data.alloc.count); 480 free_it = 1; 481 break; 482 case 6: 483 free_it = 1; 484 rsp = (struct vsp_rsp_data *)event->data.vsp_cmd.token; 485 if (rsp == NULL) { 486 printk(KERN_ERR "mf.c: no rsp\n"); 487 break; 488 } 489 if (rsp->response != NULL) 490 memcpy(rsp->response, &event->data.vsp_cmd, 491 sizeof(event->data.vsp_cmd)); 492 complete(&rsp->com); 493 break; 494 } 495 496 /* remove from queue */ 497 spin_lock_irqsave(&pending_event_spinlock, flags); 498 if ((pending_event_head != NULL) && (free_it == 1)) { 499 struct pending_event *oldHead = pending_event_head; 500 501 pending_event_head = pending_event_head->next; 502 two = pending_event_head; 503 free_pending_event(oldHead); 504 } 505 spin_unlock_irqrestore(&pending_event_spinlock, flags); 506 507 /* send next waiting event */ 508 if (two != NULL) 509 signal_event(NULL); 510} 511 512/* 513 * This is the generic event handler we are registering with 514 * the Hypervisor. Ensure the flows are for us, and then 515 * parse it enough to know if it is an interrupt or an 516 * acknowledge. 517 */ 518static void hv_handler(struct HvLpEvent *event, struct pt_regs *regs) 519{ 520 if ((event != NULL) && (event->xType == HvLpEvent_Type_MachineFac)) { 521 switch(event->xFlags.xFunction) { 522 case HvLpEvent_Function_Ack: 523 handle_ack((struct io_mf_lp_event *)event); 524 break; 525 case HvLpEvent_Function_Int: 526 handle_int((struct io_mf_lp_event *)event); 527 break; 528 default: 529 printk(KERN_ERR "mf.c: non ack/int event received\n"); 530 break; 531 } 532 } else 533 printk(KERN_ERR "mf.c: alien event received\n"); 534} 535 536/* 537 * Global kernel interface to allocate and seed events into the 538 * Hypervisor. 539 */ 540void mf_allocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type, 541 unsigned size, unsigned count, MFCompleteHandler hdlr, 542 void *user_token) 543{ 544 struct pending_event *ev = new_pending_event(); 545 int rc; 546 547 if (ev == NULL) { 548 rc = -ENOMEM; 549 } else { 550 ev->event.hp_lp_event.xSubtype = 4; 551 ev->event.hp_lp_event.xCorrelationToken = (u64)user_token; 552 ev->event.hp_lp_event.x.xSubtypeData = 553 subtype_data('M', 'F', 'M', 'A'); 554 ev->event.data.alloc.target_lp = target_lp; 555 ev->event.data.alloc.type = type; 556 ev->event.data.alloc.size = size; 557 ev->event.data.alloc.count = count; 558 ev->hdlr = hdlr; 559 rc = signal_event(ev); 560 } 561 if ((rc != 0) && (hdlr != NULL)) 562 (*hdlr)(user_token, rc); 563} 564EXPORT_SYMBOL(mf_allocate_lp_events); 565 566/* 567 * Global kernel interface to unseed and deallocate events already in 568 * Hypervisor. 569 */ 570void mf_deallocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type, 571 unsigned count, MFCompleteHandler hdlr, void *user_token) 572{ 573 struct pending_event *ev = new_pending_event(); 574 int rc; 575 576 if (ev == NULL) 577 rc = -ENOMEM; 578 else { 579 ev->event.hp_lp_event.xSubtype = 5; 580 ev->event.hp_lp_event.xCorrelationToken = (u64)user_token; 581 ev->event.hp_lp_event.x.xSubtypeData = 582 subtype_data('M', 'F', 'M', 'D'); 583 ev->event.data.alloc.target_lp = target_lp; 584 ev->event.data.alloc.type = type; 585 ev->event.data.alloc.count = count; 586 ev->hdlr = hdlr; 587 rc = signal_event(ev); 588 } 589 if ((rc != 0) && (hdlr != NULL)) 590 (*hdlr)(user_token, rc); 591} 592EXPORT_SYMBOL(mf_deallocate_lp_events); 593 594/* 595 * Global kernel interface to tell the VSP object in the primary 596 * partition to power this partition off. 597 */ 598void mf_power_off(void) 599{ 600 printk(KERN_INFO "mf.c: Down it goes...\n"); 601 signal_ce_msg_simple(0x4d, NULL); 602 for (;;) 603 ; 604} 605 606/* 607 * Global kernel interface to tell the VSP object in the primary 608 * partition to reboot this partition. 609 */ 610void mf_reboot(void) 611{ 612 printk(KERN_INFO "mf.c: Preparing to bounce...\n"); 613 signal_ce_msg_simple(0x4e, NULL); 614 for (;;) 615 ; 616} 617 618/* 619 * Display a single word SRC onto the VSP control panel. 620 */ 621void mf_display_src(u32 word) 622{ 623 u8 ce[12]; 624 625 memset(ce, 0, sizeof(ce)); 626 ce[3] = 0x4a; 627 ce[7] = 0x01; 628 ce[8] = word >> 24; 629 ce[9] = word >> 16; 630 ce[10] = word >> 8; 631 ce[11] = word; 632 signal_ce_msg(ce, NULL); 633} 634 635/* 636 * Display a single word SRC of the form "PROGXXXX" on the VSP control panel. 637 */ 638void mf_display_progress(u16 value) 639{ 640 u8 ce[12]; 641 u8 src[72]; 642 643 memcpy(ce, "\x00\x00\x04\x4A\x00\x00\x00\x48\x00\x00\x00\x00", 12); 644 memcpy(src, "\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" 645 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 646 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 647 "\x00\x00\x00\x00PROGxxxx ", 648 72); 649 src[6] = value >> 8; 650 src[7] = value & 255; 651 src[44] = "0123456789ABCDEF"[(value >> 12) & 15]; 652 src[45] = "0123456789ABCDEF"[(value >> 8) & 15]; 653 src[46] = "0123456789ABCDEF"[(value >> 4) & 15]; 654 src[47] = "0123456789ABCDEF"[value & 15]; 655 dma_and_signal_ce_msg(ce, NULL, src, sizeof(src), 9 * 64 * 1024); 656} 657 658/* 659 * Clear the VSP control panel. Used to "erase" an SRC that was 660 * previously displayed. 661 */ 662void mf_clear_src(void) 663{ 664 signal_ce_msg_simple(0x4b, NULL); 665} 666 667/* 668 * Initialization code here. 669 */ 670void mf_init(void) 671{ 672 int i; 673 674 /* initialize */ 675 spin_lock_init(&pending_event_spinlock); 676 for (i = 0; 677 i < sizeof(pending_event_prealloc) / sizeof(*pending_event_prealloc); 678 ++i) 679 free_pending_event(&pending_event_prealloc[i]); 680 HvLpEvent_registerHandler(HvLpEvent_Type_MachineFac, &hv_handler); 681 682 /* virtual continue ack */ 683 signal_ce_msg_simple(0x57, NULL); 684 685 /* initialization complete */ 686 printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities " 687 "initialized\n"); 688} 689 690struct rtc_time_data { 691 struct completion com; 692 struct ce_msg_data ce_msg; 693 int rc; 694}; 695 696static void get_rtc_time_complete(void *token, struct ce_msg_data *ce_msg) 697{ 698 struct rtc_time_data *rtc = token; 699 700 memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg)); 701 rtc->rc = 0; 702 complete(&rtc->com); 703} 704 705static int rtc_set_tm(int rc, u8 *ce_msg, struct rtc_time *tm) 706{ 707 tm->tm_wday = 0; 708 tm->tm_yday = 0; 709 tm->tm_isdst = 0; 710 if (rc) { 711 tm->tm_sec = 0; 712 tm->tm_min = 0; 713 tm->tm_hour = 0; 714 tm->tm_mday = 15; 715 tm->tm_mon = 5; 716 tm->tm_year = 52; 717 return rc; 718 } 719 720 if ((ce_msg[2] == 0xa9) || 721 (ce_msg[2] == 0xaf)) { 722 /* TOD clock is not set */ 723 tm->tm_sec = 1; 724 tm->tm_min = 1; 725 tm->tm_hour = 1; 726 tm->tm_mday = 10; 727 tm->tm_mon = 8; 728 tm->tm_year = 71; 729 mf_set_rtc(tm); 730 } 731 { 732 u8 year = ce_msg[5]; 733 u8 sec = ce_msg[6]; 734 u8 min = ce_msg[7]; 735 u8 hour = ce_msg[8]; 736 u8 day = ce_msg[10]; 737 u8 mon = ce_msg[11]; 738 739 BCD_TO_BIN(sec); 740 BCD_TO_BIN(min); 741 BCD_TO_BIN(hour); 742 BCD_TO_BIN(day); 743 BCD_TO_BIN(mon); 744 BCD_TO_BIN(year); 745 746 if (year <= 69) 747 year += 100; 748 749 tm->tm_sec = sec; 750 tm->tm_min = min; 751 tm->tm_hour = hour; 752 tm->tm_mday = day; 753 tm->tm_mon = mon; 754 tm->tm_year = year; 755 } 756 757 return 0; 758} 759 760int mf_get_rtc(struct rtc_time *tm) 761{ 762 struct ce_msg_comp_data ce_complete; 763 struct rtc_time_data rtc_data; 764 int rc; 765 766 memset(&ce_complete, 0, sizeof(ce_complete)); 767 memset(&rtc_data, 0, sizeof(rtc_data)); 768 init_completion(&rtc_data.com); 769 ce_complete.handler = &get_rtc_time_complete; 770 ce_complete.token = &rtc_data; 771 rc = signal_ce_msg_simple(0x40, &ce_complete); 772 if (rc) 773 return rc; 774 wait_for_completion(&rtc_data.com); 775 return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm); 776} 777 778struct boot_rtc_time_data { 779 int busy; 780 struct ce_msg_data ce_msg; 781 int rc; 782}; 783 784static void get_boot_rtc_time_complete(void *token, struct ce_msg_data *ce_msg) 785{ 786 struct boot_rtc_time_data *rtc = token; 787 788 memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg)); 789 rtc->rc = 0; 790 rtc->busy = 0; 791} 792 793int mf_get_boot_rtc(struct rtc_time *tm) 794{ 795 struct ce_msg_comp_data ce_complete; 796 struct boot_rtc_time_data rtc_data; 797 int rc; 798 799 memset(&ce_complete, 0, sizeof(ce_complete)); 800 memset(&rtc_data, 0, sizeof(rtc_data)); 801 rtc_data.busy = 1; 802 ce_complete.handler = &get_boot_rtc_time_complete; 803 ce_complete.token = &rtc_data; 804 rc = signal_ce_msg_simple(0x40, &ce_complete); 805 if (rc) 806 return rc; 807 /* We need to poll here as we are not yet taking interrupts */ 808 while (rtc_data.busy) { 809 if (hvlpevent_is_pending()) 810 process_hvlpevents(NULL); 811 } 812 return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm); 813} 814 815int mf_set_rtc(struct rtc_time *tm) 816{ 817 char ce_time[12]; 818 u8 day, mon, hour, min, sec, y1, y2; 819 unsigned year; 820 821 year = 1900 + tm->tm_year; 822 y1 = year / 100; 823 y2 = year % 100; 824 825 sec = tm->tm_sec; 826 min = tm->tm_min; 827 hour = tm->tm_hour; 828 day = tm->tm_mday; 829 mon = tm->tm_mon + 1; 830 831 BIN_TO_BCD(sec); 832 BIN_TO_BCD(min); 833 BIN_TO_BCD(hour); 834 BIN_TO_BCD(mon); 835 BIN_TO_BCD(day); 836 BIN_TO_BCD(y1); 837 BIN_TO_BCD(y2); 838 839 memset(ce_time, 0, sizeof(ce_time)); 840 ce_time[3] = 0x41; 841 ce_time[4] = y1; 842 ce_time[5] = y2; 843 ce_time[6] = sec; 844 ce_time[7] = min; 845 ce_time[8] = hour; 846 ce_time[10] = day; 847 ce_time[11] = mon; 848 849 return signal_ce_msg(ce_time, NULL); 850} 851 852#ifdef CONFIG_PROC_FS 853 854static int proc_mf_dump_cmdline(char *page, char **start, off_t off, 855 int count, int *eof, void *data) 856{ 857 int len; 858 char *p; 859 struct vsp_cmd_data vsp_cmd; 860 int rc; 861 dma_addr_t dma_addr; 862 863 /* The HV appears to return no more than 256 bytes of command line */ 864 if (off >= 256) 865 return 0; 866 if ((off + count) > 256) 867 count = 256 - off; 868 869 dma_addr = dma_map_single(iSeries_vio_dev, page, off + count, 870 DMA_FROM_DEVICE); 871 if (dma_mapping_error(dma_addr)) 872 return -ENOMEM; 873 memset(page, 0, off + count); 874 memset(&vsp_cmd, 0, sizeof(vsp_cmd)); 875 vsp_cmd.cmd = 33; 876 vsp_cmd.sub_data.kern.token = dma_addr; 877 vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; 878 vsp_cmd.sub_data.kern.side = (u64)data; 879 vsp_cmd.sub_data.kern.length = off + count; 880 mb(); 881 rc = signal_vsp_instruction(&vsp_cmd); 882 dma_unmap_single(iSeries_vio_dev, dma_addr, off + count, 883 DMA_FROM_DEVICE); 884 if (rc) 885 return rc; 886 if (vsp_cmd.result_code != 0) 887 return -ENOMEM; 888 p = page; 889 len = 0; 890 while (len < (off + count)) { 891 if ((*p == '\0') || (*p == '\n')) { 892 if (*p == '\0') 893 *p = '\n'; 894 p++; 895 len++; 896 *eof = 1; 897 break; 898 } 899 p++; 900 len++; 901 } 902 903 if (len < off) { 904 *eof = 1; 905 len = 0; 906 } 907 return len; 908} 909 910#if 0 911static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side) 912{ 913 struct vsp_cmd_data vsp_cmd; 914 int rc; 915 int len = *size; 916 dma_addr_t dma_addr; 917 918 dma_addr = dma_map_single(iSeries_vio_dev, buffer, len, 919 DMA_FROM_DEVICE); 920 memset(buffer, 0, len); 921 memset(&vsp_cmd, 0, sizeof(vsp_cmd)); 922 vsp_cmd.cmd = 32; 923 vsp_cmd.sub_data.kern.token = dma_addr; 924 vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; 925 vsp_cmd.sub_data.kern.side = side; 926 vsp_cmd.sub_data.kern.offset = offset; 927 vsp_cmd.sub_data.kern.length = len; 928 mb(); 929 rc = signal_vsp_instruction(&vsp_cmd); 930 if (rc == 0) { 931 if (vsp_cmd.result_code == 0) 932 *size = vsp_cmd.sub_data.length_out; 933 else 934 rc = -ENOMEM; 935 } 936 937 dma_unmap_single(iSeries_vio_dev, dma_addr, len, DMA_FROM_DEVICE); 938 939 return rc; 940} 941 942static int proc_mf_dump_vmlinux(char *page, char **start, off_t off, 943 int count, int *eof, void *data) 944{ 945 int sizeToGet = count; 946 947 if (!capable(CAP_SYS_ADMIN)) 948 return -EACCES; 949 950 if (mf_getVmlinuxChunk(page, &sizeToGet, off, (u64)data) == 0) { 951 if (sizeToGet != 0) { 952 *start = page + off; 953 return sizeToGet; 954 } 955 *eof = 1; 956 return 0; 957 } 958 *eof = 1; 959 return 0; 960} 961#endif 962 963static int proc_mf_dump_side(char *page, char **start, off_t off, 964 int count, int *eof, void *data) 965{ 966 int len; 967 char mf_current_side = ' '; 968 struct vsp_cmd_data vsp_cmd; 969 970 memset(&vsp_cmd, 0, sizeof(vsp_cmd)); 971 vsp_cmd.cmd = 2; 972 vsp_cmd.sub_data.ipl_type = 0; 973 mb(); 974 975 if (signal_vsp_instruction(&vsp_cmd) == 0) { 976 if (vsp_cmd.result_code == 0) { 977 switch (vsp_cmd.sub_data.ipl_type) { 978 case 0: mf_current_side = 'A'; 979 break; 980 case 1: mf_current_side = 'B'; 981 break; 982 case 2: mf_current_side = 'C'; 983 break; 984 default: mf_current_side = 'D'; 985 break; 986 } 987 } 988 } 989 990 len = sprintf(page, "%c\n", mf_current_side); 991 992 if (len <= (off + count)) 993 *eof = 1; 994 *start = page + off; 995 len -= off; 996 if (len > count) 997 len = count; 998 if (len < 0) 999 len = 0; 1000 return len; 1001} 1002 1003static int proc_mf_change_side(struct file *file, const char __user *buffer, 1004 unsigned long count, void *data) 1005{ 1006 char side; 1007 u64 newSide; 1008 struct vsp_cmd_data vsp_cmd; 1009 1010 if (!capable(CAP_SYS_ADMIN)) 1011 return -EACCES; 1012 1013 if (count == 0) 1014 return 0; 1015 1016 if (get_user(side, buffer)) 1017 return -EFAULT; 1018 1019 switch (side) { 1020 case 'A': newSide = 0; 1021 break; 1022 case 'B': newSide = 1; 1023 break; 1024 case 'C': newSide = 2; 1025 break; 1026 case 'D': newSide = 3; 1027 break; 1028 default: 1029 printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n"); 1030 return -EINVAL; 1031 } 1032 1033 memset(&vsp_cmd, 0, sizeof(vsp_cmd)); 1034 vsp_cmd.sub_data.ipl_type = newSide; 1035 vsp_cmd.cmd = 10; 1036 1037 (void)signal_vsp_instruction(&vsp_cmd); 1038 1039 return count; 1040} 1041 1042#if 0 1043static void mf_getSrcHistory(char *buffer, int size) 1044{ 1045 struct IplTypeReturnStuff return_stuff; 1046 struct pending_event *ev = new_pending_event(); 1047 int rc = 0; 1048 char *pages[4]; 1049 1050 pages[0] = kmalloc(4096, GFP_ATOMIC); 1051 pages[1] = kmalloc(4096, GFP_ATOMIC); 1052 pages[2] = kmalloc(4096, GFP_ATOMIC); 1053 pages[3] = kmalloc(4096, GFP_ATOMIC); 1054 if ((ev == NULL) || (pages[0] == NULL) || (pages[1] == NULL) 1055 || (pages[2] == NULL) || (pages[3] == NULL)) 1056 return -ENOMEM; 1057 1058 return_stuff.xType = 0; 1059 return_stuff.xRc = 0; 1060 return_stuff.xDone = 0; 1061 ev->event.hp_lp_event.xSubtype = 6; 1062 ev->event.hp_lp_event.x.xSubtypeData = 1063 subtype_data('M', 'F', 'V', 'I'); 1064 ev->event.data.vsp_cmd.xEvent = &return_stuff; 1065 ev->event.data.vsp_cmd.cmd = 4; 1066 ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex(); 1067 ev->event.data.vsp_cmd.result_code = 0xFF; 1068 ev->event.data.vsp_cmd.reserved = 0; 1069 ev->event.data.vsp_cmd.sub_data.page[0] = iseries_hv_addr(pages[0]); 1070 ev->event.data.vsp_cmd.sub_data.page[1] = iseries_hv_addr(pages[1]); 1071 ev->event.data.vsp_cmd.sub_data.page[2] = iseries_hv_addr(pages[2]); 1072 ev->event.data.vsp_cmd.sub_data.page[3] = iseries_hv_addr(pages[3]); 1073 mb(); 1074 if (signal_event(ev) != 0) 1075 return; 1076 1077 while (return_stuff.xDone != 1) 1078 udelay(10); 1079 if (return_stuff.xRc == 0) 1080 memcpy(buffer, pages[0], size); 1081 kfree(pages[0]); 1082 kfree(pages[1]); 1083 kfree(pages[2]); 1084 kfree(pages[3]); 1085} 1086#endif 1087 1088static int proc_mf_dump_src(char *page, char **start, off_t off, 1089 int count, int *eof, void *data) 1090{ 1091#if 0 1092 int len; 1093 1094 mf_getSrcHistory(page, count); 1095 len = count; 1096 len -= off; 1097 if (len < count) { 1098 *eof = 1; 1099 if (len <= 0) 1100 return 0; 1101 } else 1102 len = count; 1103 *start = page + off; 1104 return len; 1105#else 1106 return 0; 1107#endif 1108} 1109 1110static int proc_mf_change_src(struct file *file, const char __user *buffer, 1111 unsigned long count, void *data) 1112{ 1113 char stkbuf[10]; 1114 1115 if (!capable(CAP_SYS_ADMIN)) 1116 return -EACCES; 1117 1118 if ((count < 4) && (count != 1)) { 1119 printk(KERN_ERR "mf_proc: invalid src\n"); 1120 return -EINVAL; 1121 } 1122 1123 if (count > (sizeof(stkbuf) - 1)) 1124 count = sizeof(stkbuf) - 1; 1125 if (copy_from_user(stkbuf, buffer, count)) 1126 return -EFAULT; 1127 1128 if ((count == 1) && (*stkbuf == '\0')) 1129 mf_clear_src(); 1130 else 1131 mf_display_src(*(u32 *)stkbuf); 1132 1133 return count; 1134} 1135 1136static int proc_mf_change_cmdline(struct file *file, const char __user *buffer, 1137 unsigned long count, void *data) 1138{ 1139 struct vsp_cmd_data vsp_cmd; 1140 dma_addr_t dma_addr; 1141 char *page; 1142 int ret = -EACCES; 1143 1144 if (!capable(CAP_SYS_ADMIN)) 1145 goto out; 1146 1147 dma_addr = 0; 1148 page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr, 1149 GFP_ATOMIC); 1150 ret = -ENOMEM; 1151 if (page == NULL) 1152 goto out; 1153 1154 ret = -EFAULT; 1155 if (copy_from_user(page, buffer, count)) 1156 goto out_free; 1157 1158 memset(&vsp_cmd, 0, sizeof(vsp_cmd)); 1159 vsp_cmd.cmd = 31; 1160 vsp_cmd.sub_data.kern.token = dma_addr; 1161 vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; 1162 vsp_cmd.sub_data.kern.side = (u64)data; 1163 vsp_cmd.sub_data.kern.length = count; 1164 mb(); 1165 (void)signal_vsp_instruction(&vsp_cmd); 1166 ret = count; 1167 1168out_free: 1169 dma_free_coherent(iSeries_vio_dev, count, page, dma_addr); 1170out: 1171 return ret; 1172} 1173 1174static ssize_t proc_mf_change_vmlinux(struct file *file, 1175 const char __user *buf, 1176 size_t count, loff_t *ppos) 1177{ 1178 struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); 1179 ssize_t rc; 1180 dma_addr_t dma_addr; 1181 char *page; 1182 struct vsp_cmd_data vsp_cmd; 1183 1184 rc = -EACCES; 1185 if (!capable(CAP_SYS_ADMIN)) 1186 goto out; 1187 1188 dma_addr = 0; 1189 page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr, 1190 GFP_ATOMIC); 1191 rc = -ENOMEM; 1192 if (page == NULL) { 1193 printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n"); 1194 goto out; 1195 } 1196 rc = -EFAULT; 1197 if (copy_from_user(page, buf, count)) 1198 goto out_free; 1199 1200 memset(&vsp_cmd, 0, sizeof(vsp_cmd)); 1201 vsp_cmd.cmd = 30; 1202 vsp_cmd.sub_data.kern.token = dma_addr; 1203 vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; 1204 vsp_cmd.sub_data.kern.side = (u64)dp->data; 1205 vsp_cmd.sub_data.kern.offset = *ppos; 1206 vsp_cmd.sub_data.kern.length = count; 1207 mb(); 1208 rc = signal_vsp_instruction(&vsp_cmd); 1209 if (rc) 1210 goto out_free; 1211 rc = -ENOMEM; 1212 if (vsp_cmd.result_code != 0) 1213 goto out_free; 1214 1215 *ppos += count; 1216 rc = count; 1217out_free: 1218 dma_free_coherent(iSeries_vio_dev, count, page, dma_addr); 1219out: 1220 return rc; 1221} 1222 1223static struct file_operations proc_vmlinux_operations = { 1224 .write = proc_mf_change_vmlinux, 1225}; 1226 1227static int __init mf_proc_init(void) 1228{ 1229 struct proc_dir_entry *mf_proc_root; 1230 struct proc_dir_entry *ent; 1231 struct proc_dir_entry *mf; 1232 char name[2]; 1233 int i; 1234 1235 mf_proc_root = proc_mkdir("iSeries/mf", NULL); 1236 if (!mf_proc_root) 1237 return 1; 1238 1239 name[1] = '\0'; 1240 for (i = 0; i < 4; i++) { 1241 name[0] = 'A' + i; 1242 mf = proc_mkdir(name, mf_proc_root); 1243 if (!mf) 1244 return 1; 1245 1246 ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf); 1247 if (!ent) 1248 return 1; 1249 ent->nlink = 1; 1250 ent->data = (void *)(long)i; 1251 ent->read_proc = proc_mf_dump_cmdline; 1252 ent->write_proc = proc_mf_change_cmdline; 1253 1254 if (i == 3) /* no vmlinux entry for 'D' */ 1255 continue; 1256 1257 ent = create_proc_entry("vmlinux", S_IFREG|S_IWUSR, mf); 1258 if (!ent) 1259 return 1; 1260 ent->nlink = 1; 1261 ent->data = (void *)(long)i; 1262 ent->proc_fops = &proc_vmlinux_operations; 1263 } 1264 1265 ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); 1266 if (!ent) 1267 return 1; 1268 ent->nlink = 1; 1269 ent->data = (void *)0; 1270 ent->read_proc = proc_mf_dump_side; 1271 ent->write_proc = proc_mf_change_side; 1272 1273 ent = create_proc_entry("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); 1274 if (!ent) 1275 return 1; 1276 ent->nlink = 1; 1277 ent->data = (void *)0; 1278 ent->read_proc = proc_mf_dump_src; 1279 ent->write_proc = proc_mf_change_src; 1280 1281 return 0; 1282} 1283 1284__initcall(mf_proc_init); 1285 1286#endif /* CONFIG_PROC_FS */ 1287 1288/* 1289 * Get the RTC from the virtual service processor 1290 * This requires flowing LpEvents to the primary partition 1291 */ 1292void iSeries_get_rtc_time(struct rtc_time *rtc_tm) 1293{ 1294 if (piranha_simulator) 1295 return; 1296 1297 mf_get_rtc(rtc_tm); 1298 rtc_tm->tm_mon--; 1299} 1300 1301/* 1302 * Set the RTC in the virtual service processor 1303 * This requires flowing LpEvents to the primary partition 1304 */ 1305int iSeries_set_rtc_time(struct rtc_time *tm) 1306{ 1307 mf_set_rtc(tm); 1308 return 0; 1309} 1310 1311unsigned long iSeries_get_boot_time(void) 1312{ 1313 struct rtc_time tm; 1314 1315 if (piranha_simulator) 1316 return 0; 1317 1318 mf_get_boot_rtc(&tm); 1319 return mktime(tm.tm_year + 1900, tm.tm_mon, tm.tm_mday, 1320 tm.tm_hour, tm.tm_min, tm.tm_sec); 1321}