aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/ipmi/ipmi_si_intf.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/ipmi/ipmi_si_intf.c')
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c105
1 files changed, 68 insertions, 37 deletions
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index d1c44fd17aa8..e36487db0e94 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -328,7 +328,10 @@ static void deliver_recv_msg(struct smi_info *smi_info,
328 struct ipmi_smi_msg *msg) 328 struct ipmi_smi_msg *msg)
329{ 329{
330 /* Deliver the message to the upper layer. */ 330 /* Deliver the message to the upper layer. */
331 ipmi_smi_msg_received(smi_info->intf, msg); 331 if (smi_info->intf)
332 ipmi_smi_msg_received(smi_info->intf, msg);
333 else
334 ipmi_free_smi_msg(msg);
332} 335}
333 336
334static void return_hosed_msg(struct smi_info *smi_info, int cCode) 337static void return_hosed_msg(struct smi_info *smi_info, int cCode)
@@ -436,6 +439,32 @@ static void start_clear_flags(struct smi_info *smi_info)
436 smi_info->si_state = SI_CLEARING_FLAGS; 439 smi_info->si_state = SI_CLEARING_FLAGS;
437} 440}
438 441
442static void start_getting_msg_queue(struct smi_info *smi_info)
443{
444 smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
445 smi_info->curr_msg->data[1] = IPMI_GET_MSG_CMD;
446 smi_info->curr_msg->data_size = 2;
447
448 smi_info->handlers->start_transaction(
449 smi_info->si_sm,
450 smi_info->curr_msg->data,
451 smi_info->curr_msg->data_size);
452 smi_info->si_state = SI_GETTING_MESSAGES;
453}
454
455static void start_getting_events(struct smi_info *smi_info)
456{
457 smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
458 smi_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
459 smi_info->curr_msg->data_size = 2;
460
461 smi_info->handlers->start_transaction(
462 smi_info->si_sm,
463 smi_info->curr_msg->data,
464 smi_info->curr_msg->data_size);
465 smi_info->si_state = SI_GETTING_EVENTS;
466}
467
439static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val) 468static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
440{ 469{
441 smi_info->last_timeout_jiffies = jiffies; 470 smi_info->last_timeout_jiffies = jiffies;
@@ -449,22 +478,45 @@ static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
449 * polled until we can allocate some memory. Once we have some 478 * polled until we can allocate some memory. Once we have some
450 * memory, we will re-enable the interrupt. 479 * memory, we will re-enable the interrupt.
451 */ 480 */
452static inline void disable_si_irq(struct smi_info *smi_info) 481static inline bool disable_si_irq(struct smi_info *smi_info)
453{ 482{
454 if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { 483 if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
455 start_disable_irq(smi_info); 484 start_disable_irq(smi_info);
456 smi_info->interrupt_disabled = true; 485 smi_info->interrupt_disabled = true;
457 if (!atomic_read(&smi_info->stop_operation)) 486 return true;
458 smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES);
459 } 487 }
488 return false;
460} 489}
461 490
462static inline void enable_si_irq(struct smi_info *smi_info) 491static inline bool enable_si_irq(struct smi_info *smi_info)
463{ 492{
464 if ((smi_info->irq) && (smi_info->interrupt_disabled)) { 493 if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
465 start_enable_irq(smi_info); 494 start_enable_irq(smi_info);
466 smi_info->interrupt_disabled = false; 495 smi_info->interrupt_disabled = false;
496 return true;
467 } 497 }
498 return false;
499}
500
501/*
502 * Allocate a message. If unable to allocate, start the interrupt
503 * disable process and return NULL. If able to allocate but
504 * interrupts are disabled, free the message and return NULL after
505 * starting the interrupt enable process.
506 */
507static struct ipmi_smi_msg *alloc_msg_handle_irq(struct smi_info *smi_info)
508{
509 struct ipmi_smi_msg *msg;
510
511 msg = ipmi_alloc_smi_msg();
512 if (!msg) {
513 if (!disable_si_irq(smi_info))
514 smi_info->si_state = SI_NORMAL;
515 } else if (enable_si_irq(smi_info)) {
516 ipmi_free_smi_msg(msg);
517 msg = NULL;
518 }
519 return msg;
468} 520}
469 521
470static void handle_flags(struct smi_info *smi_info) 522static void handle_flags(struct smi_info *smi_info)
@@ -476,45 +528,22 @@ static void handle_flags(struct smi_info *smi_info)
476 528
477 start_clear_flags(smi_info); 529 start_clear_flags(smi_info);
478 smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT; 530 smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
479 ipmi_smi_watchdog_pretimeout(smi_info->intf); 531 if (smi_info->intf)
532 ipmi_smi_watchdog_pretimeout(smi_info->intf);
480 } else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) { 533 } else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
481 /* Messages available. */ 534 /* Messages available. */
482 smi_info->curr_msg = ipmi_alloc_smi_msg(); 535 smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
483 if (!smi_info->curr_msg) { 536 if (!smi_info->curr_msg)
484 disable_si_irq(smi_info);
485 smi_info->si_state = SI_NORMAL;
486 return; 537 return;
487 }
488 enable_si_irq(smi_info);
489 538
490 smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2); 539 start_getting_msg_queue(smi_info);
491 smi_info->curr_msg->data[1] = IPMI_GET_MSG_CMD;
492 smi_info->curr_msg->data_size = 2;
493
494 smi_info->handlers->start_transaction(
495 smi_info->si_sm,
496 smi_info->curr_msg->data,
497 smi_info->curr_msg->data_size);
498 smi_info->si_state = SI_GETTING_MESSAGES;
499 } else if (smi_info->msg_flags & EVENT_MSG_BUFFER_FULL) { 540 } else if (smi_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
500 /* Events available. */ 541 /* Events available. */
501 smi_info->curr_msg = ipmi_alloc_smi_msg(); 542 smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
502 if (!smi_info->curr_msg) { 543 if (!smi_info->curr_msg)
503 disable_si_irq(smi_info);
504 smi_info->si_state = SI_NORMAL;
505 return; 544 return;
506 }
507 enable_si_irq(smi_info);
508 545
509 smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2); 546 start_getting_events(smi_info);
510 smi_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
511 smi_info->curr_msg->data_size = 2;
512
513 smi_info->handlers->start_transaction(
514 smi_info->si_sm,
515 smi_info->curr_msg->data,
516 smi_info->curr_msg->data_size);
517 smi_info->si_state = SI_GETTING_EVENTS;
518 } else if (smi_info->msg_flags & OEM_DATA_AVAIL && 547 } else if (smi_info->msg_flags & OEM_DATA_AVAIL &&
519 smi_info->oem_data_avail_handler) { 548 smi_info->oem_data_avail_handler) {
520 if (smi_info->oem_data_avail_handler(smi_info)) 549 if (smi_info->oem_data_avail_handler(smi_info))
@@ -709,7 +738,9 @@ static void handle_transaction_done(struct smi_info *smi_info)
709 "Maybe ok, but ipmi might run very slowly.\n"); 738 "Maybe ok, but ipmi might run very slowly.\n");
710 } else 739 } else
711 smi_info->interrupt_disabled = false; 740 smi_info->interrupt_disabled = false;
712 smi_info->si_state = SI_NORMAL; 741
742 /* We enabled interrupts, flags may be pending. */
743 handle_flags(smi_info);
713 break; 744 break;
714 } 745 }
715 746