Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 54539
b: refs/heads/master
c: ee6cd5f
h: refs/heads/master
i:
  54537: f0e66c0
  54535: d4b9bd8
v: v3
  • Loading branch information
Corey Minyard authored and Linus Torvalds committed May 8, 2007
1 parent f40e2f0 commit e3499b8
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 36 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: dba9b4f6a096f39dd58d67fbc643a7c1bf2973eb
refs/heads/master: ee6cd5f8f573ad11f270a07fb201822c2862474d
124 changes: 89 additions & 35 deletions trunk/drivers/char/ipmi/ipmi_si_intf.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@
#define SI_SHORT_TIMEOUT_USEC 250 /* .25ms when the SM request a
short timeout */

/* Bit for BMC global enables. */
#define IPMI_BMC_RCV_MSG_INTR 0x01
#define IPMI_BMC_EVT_MSG_INTR 0x02
#define IPMI_BMC_EVT_MSG_BUFF 0x04
#define IPMI_BMC_SYS_LOG 0x08

enum si_intf_state {
SI_NORMAL,
SI_GETTING_FLAGS,
Expand All @@ -90,7 +96,9 @@ enum si_intf_state {
SI_CLEARING_FLAGS_THEN_SET_IRQ,
SI_GETTING_MESSAGES,
SI_ENABLE_INTERRUPTS1,
SI_ENABLE_INTERRUPTS2
SI_ENABLE_INTERRUPTS2,
SI_DISABLE_INTERRUPTS1,
SI_DISABLE_INTERRUPTS2
/* FIXME - add watchdog stuff. */
};

Expand Down Expand Up @@ -339,6 +347,17 @@ static void start_enable_irq(struct smi_info *smi_info)
smi_info->si_state = SI_ENABLE_INTERRUPTS1;
}

static void start_disable_irq(struct smi_info *smi_info)
{
unsigned char msg[2];

msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;

smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
smi_info->si_state = SI_DISABLE_INTERRUPTS1;
}

static void start_clear_flags(struct smi_info *smi_info)
{
unsigned char msg[3];
Expand All @@ -359,15 +378,15 @@ static void start_clear_flags(struct smi_info *smi_info)
static inline void disable_si_irq(struct smi_info *smi_info)
{
if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
disable_irq_nosync(smi_info->irq);
start_disable_irq(smi_info);
smi_info->interrupt_disabled = 1;
}
}

static inline void enable_si_irq(struct smi_info *smi_info)
{
if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
enable_irq(smi_info->irq);
start_enable_irq(smi_info);
smi_info->interrupt_disabled = 0;
}
}
Expand Down Expand Up @@ -589,7 +608,9 @@ static void handle_transaction_done(struct smi_info *smi_info)
} else {
msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
msg[2] = msg[3] | 1; /* enable msg queue int */
msg[2] = (msg[3] |
IPMI_BMC_RCV_MSG_INTR |
IPMI_BMC_EVT_MSG_INTR);
smi_info->handlers->start_transaction(
smi_info->si_sm, msg, 3);
smi_info->si_state = SI_ENABLE_INTERRUPTS2;
Expand All @@ -611,6 +632,45 @@ static void handle_transaction_done(struct smi_info *smi_info)
smi_info->si_state = SI_NORMAL;
break;
}

case SI_DISABLE_INTERRUPTS1:
{
unsigned char msg[4];

/* We got the flags from the SMI, now handle them. */
smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
if (msg[2] != 0) {
printk(KERN_WARNING
"ipmi_si: Could not disable interrupts"
", failed get.\n");
smi_info->si_state = SI_NORMAL;
} else {
msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
msg[2] = (msg[3] &
~(IPMI_BMC_RCV_MSG_INTR |
IPMI_BMC_EVT_MSG_INTR));
smi_info->handlers->start_transaction(
smi_info->si_sm, msg, 3);
smi_info->si_state = SI_DISABLE_INTERRUPTS2;
}
break;
}

case SI_DISABLE_INTERRUPTS2:
{
unsigned char msg[4];

/* We got the flags from the SMI, now handle them. */
smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
if (msg[2] != 0) {
printk(KERN_WARNING
"ipmi_si: Could not disable interrupts"
", failed set.\n");
}
smi_info->si_state = SI_NORMAL;
break;
}
}
}

Expand Down Expand Up @@ -864,9 +924,6 @@ static void smi_timeout(unsigned long data)
struct timeval t;
#endif

if (atomic_read(&smi_info->stop_operation))
return;

spin_lock_irqsave(&(smi_info->si_lock), flags);
#ifdef DEBUG_TIMING
do_gettimeofday(&t);
Expand Down Expand Up @@ -922,15 +979,11 @@ static irqreturn_t si_irq_handler(int irq, void *data)
smi_info->interrupts++;
spin_unlock(&smi_info->count_lock);

if (atomic_read(&smi_info->stop_operation))
goto out;

#ifdef DEBUG_TIMING
do_gettimeofday(&t);
printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
smi_event_handler(smi_info, 0);
out:
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
return IRQ_HANDLED;
}
Expand Down Expand Up @@ -1118,7 +1171,7 @@ static int std_irq_setup(struct smi_info *info)
if (info->si_type == SI_BT) {
rv = request_irq(info->irq,
si_bt_irq_handler,
IRQF_DISABLED,
IRQF_SHARED | IRQF_DISABLED,
DEVICE_NAME,
info);
if (!rv)
Expand All @@ -1128,7 +1181,7 @@ static int std_irq_setup(struct smi_info *info)
} else
rv = request_irq(info->irq,
si_irq_handler,
IRQF_DISABLED,
IRQF_SHARED | IRQF_DISABLED,
DEVICE_NAME,
info);
if (rv) {
Expand Down Expand Up @@ -1708,15 +1761,11 @@ static u32 ipmi_acpi_gpe(void *context)
smi_info->interrupts++;
spin_unlock(&smi_info->count_lock);

if (atomic_read(&smi_info->stop_operation))
goto out;

#ifdef DEBUG_TIMING
do_gettimeofday(&t);
printk("**ACPI_GPE: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
smi_event_handler(smi_info, 0);
out:
spin_unlock_irqrestore(&(smi_info->si_lock), flags);

return ACPI_INTERRUPT_HANDLED;
Expand Down Expand Up @@ -2942,28 +2991,33 @@ static void cleanup_one_si(struct smi_info *to_clean)

list_del(&to_clean->link);

/* Tell the timer and interrupt handlers that we are shutting
down. */
spin_lock_irqsave(&(to_clean->si_lock), flags);
spin_lock(&(to_clean->msg_lock));

/* Tell the driver that we are shutting down. */
atomic_inc(&to_clean->stop_operation);

if (to_clean->irq_cleanup)
to_clean->irq_cleanup(to_clean);

spin_unlock(&(to_clean->msg_lock));
spin_unlock_irqrestore(&(to_clean->si_lock), flags);

/* Wait until we know that we are out of any interrupt
handlers might have been running before we freed the
interrupt. */
synchronize_sched();

/* Make sure the timer and thread are stopped and will not run
again. */
wait_for_timer_and_thread(to_clean);

/* Interrupts and timeouts are stopped, now make sure the
interface is in a clean state. */
/* Timeouts are stopped, now make sure the interrupts are off
for the device. A little tricky with locks to make sure
there are no races. */
spin_lock_irqsave(&to_clean->si_lock, flags);
while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
spin_unlock_irqrestore(&to_clean->si_lock, flags);
poll(to_clean);
schedule_timeout_uninterruptible(1);
spin_lock_irqsave(&to_clean->si_lock, flags);
}
disable_si_irq(to_clean);
spin_unlock_irqrestore(&to_clean->si_lock, flags);
while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
poll(to_clean);
schedule_timeout_uninterruptible(1);
}

/* Clean up interrupts and make sure that everything is done. */
if (to_clean->irq_cleanup)
to_clean->irq_cleanup(to_clean);
while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
poll(to_clean);
schedule_timeout_uninterruptible(1);
Expand Down

0 comments on commit e3499b8

Please sign in to comment.