diff options
Diffstat (limited to 'drivers/char/ipmi/ipmi_si_intf.c')
-rw-r--r-- | drivers/char/ipmi/ipmi_si_intf.c | 105 |
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 | ||
334 | static void return_hosed_msg(struct smi_info *smi_info, int cCode) | 337 | static 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 | ||
442 | static 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 | |||
455 | static 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 | |||
439 | static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val) | 468 | static 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 | */ |
452 | static inline void disable_si_irq(struct smi_info *smi_info) | 481 | static 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 | ||
462 | static inline void enable_si_irq(struct smi_info *smi_info) | 491 | static 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 | */ | ||
507 | static 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 | ||
470 | static void handle_flags(struct smi_info *smi_info) | 522 | static 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 | ||