From fbd568a3e61a7decb8a754ad952aaa5b5c82e9e5 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 1 May 2005 08:59:04 -0700 Subject: [PATCH] Change synchronize_kernel to _rcu and _sched This patch changes calls to synchronize_kernel(), deprecated in the earlier "Deprecate synchronize_kernel, GPL replacement" patch to instead call the new synchronize_rcu() and synchronize_sched() APIs. Signed-off-by: Paul E. McKenney Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_si_intf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/char/ipmi') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 29de259a981..44a7f13c788 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2199,7 +2199,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi) /* Wait until we know that we are out of any interrupt handlers might have been running before we freed the interrupt. */ - synchronize_kernel(); + synchronize_sched(); if (new_smi->si_sm) { if (new_smi->handlers) @@ -2312,7 +2312,7 @@ static void __exit cleanup_one_si(struct smi_info *to_clean) /* Wait until we know that we are out of any interrupt handlers might have been running before we freed the interrupt. */ - synchronize_kernel(); + synchronize_sched(); /* Wait for the timer to stop. This avoids problems with race conditions removing the timer here. */ -- cgit v1.2.3 From 9206880198589670dfc33feb9d2e903c3492701f Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Sun, 1 May 2005 08:59:10 -0700 Subject: [PATCH] IPMI: fix for handling bad IPMI DMI data Ignore the bottom bit of the base address from the DMI data. It is supposed to be set to 1 if it is I/O space. Few systems do this, but this enables the ones that do set it to work properly. Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_si_intf.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/char/ipmi') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 44a7f13c788..3522723eb6b 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1623,7 +1623,13 @@ static int decode_dmi(dmi_header_t *dm, int intf_num) } } else { /* Old DMI spec. */ - ipmi_data->base_addr = base_addr; + /* Note that technically, the lower bit of the base + * address should be 1 if the address is I/O and 0 if + * the address is in memory. So many systems get that + * wrong (and all that I have seen are I/O) so we just + * ignore that bit and assume I/O. Systems that use + * memory should use the newer spec, anyway. */ + ipmi_data->base_addr = base_addr & 0xfffe; ipmi_data->addr_space = IPMI_IO_ADDR_SPACE; ipmi_data->offset = 1; } -- cgit v1.2.3 From 35bc37a0e0979a091bcf5d9161ffe935b3aa998c Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Sun, 1 May 2005 08:59:10 -0700 Subject: [PATCH] IPMI: fix for handling bad ACPI data If the ACPI register bit width is zero (an invalid value) assume it is the default spacing. This avoids some coredumps on invalid data and makes some systems work that have broken ACPI data. Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_si_intf.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/char/ipmi') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 3522723eb6b..7522bd5f94d 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1526,8 +1526,17 @@ static int try_init_acpi(int intf_num, struct smi_info **new_info) info->irq_setup = NULL; } - regspacings[intf_num] = spmi->addr.register_bit_width / 8; - info->io.regspacing = spmi->addr.register_bit_width / 8; + if (spmi->addr.register_bit_width) { + /* A (hopefully) properly formed register bit width. */ + regspacings[intf_num] = spmi->addr.register_bit_width / 8; + info->io.regspacing = spmi->addr.register_bit_width / 8; + } else { + /* Some broken systems get this wrong and set the value + * to zero. Assume it is the default spacing. If that + * is wrong, too bad, the vendor should fix the tables. */ + regspacings[intf_num] = DEFAULT_REGSPACING; + info->io.regspacing = DEFAULT_REGSPACING; + } regsizes[intf_num] = regspacings[intf_num]; info->io.regsize = regsizes[intf_num]; regshifts[intf_num] = spmi->addr.register_bit_offset; -- cgit v1.2.3 From ec26d79f4f5822283e0bffa44a542fd13c5146e4 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Sun, 1 May 2005 08:59:11 -0700 Subject: [PATCH] ipmi: fix watchdog so the device can be reopened on an unexpected close If there is an unexpected close, still allow the watchdog interface to be re-opened on the IPMI watchdog. Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_watchdog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char/ipmi') diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index fd7093879c6..fcd1c02a32c 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -709,11 +709,11 @@ static int ipmi_close(struct inode *ino, struct file *filep) if (expect_close == 42) { ipmi_watchdog_state = WDOG_TIMEOUT_NONE; ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); - clear_bit(0, &ipmi_wdog_open); } else { printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); ipmi_heartbeat(); } + clear_bit(0, &ipmi_wdog_open); } ipmi_fasync (-1, filep, 0); -- cgit v1.2.3 From 9dbf68f97d585265eaadd15aea308efd9ae39d34 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Sun, 1 May 2005 08:59:11 -0700 Subject: [PATCH] ipmi: enable interrupts on the BT driver Enable interrupts for a BT interface. There is a specific register that needs to be set up to enable interrupts that also must be modified to clear the irq. Also, don't reset the BMC on a BT interface. That's probably not a good idea as the BMC may be performing other important functions and a reset should only be a last resort. Also, that register is also used to enable/disable interrupts to the BT; modifying it may screw up the interrupts. Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_bt_sm.c | 1 - drivers/char/ipmi/ipmi_si_intf.c | 40 +++++++++++++++++++++++++++++++++++----- 2 files changed, 35 insertions(+), 6 deletions(-) (limited to 'drivers/char/ipmi') diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index 225b330115b..5ce9c626903 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -235,7 +235,6 @@ static void reset_flags(struct si_sm_data *bt) if (BT_STATUS & BT_B_BUSY) BT_CONTROL(BT_B_BUSY); BT_CONTROL(BT_CLR_WR_PTR); BT_CONTROL(BT_SMS_ATN); - BT_INTMASK_W(BT_BMC_HWRST); #ifdef DEVELOPMENT_ONLY_NOT_FOR_PRODUCTION if (BT_STATUS & BT_B2H_ATN) { int i; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 7522bd5f94d..5419440087f 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -100,6 +100,11 @@ enum si_intf_state { /* FIXME - add watchdog stuff. */ }; +/* Some BT-specific defines we need here. */ +#define IPMI_BT_INTMASK_REG 2 +#define IPMI_BT_INTMASK_CLEAR_IRQ_BIT 2 +#define IPMI_BT_INTMASK_ENABLE_IRQ_BIT 1 + enum si_type { SI_KCS, SI_SMIC, SI_BT }; @@ -875,6 +880,17 @@ static irqreturn_t si_irq_handler(int irq, void *data, struct pt_regs *regs) return IRQ_HANDLED; } +static irqreturn_t si_bt_irq_handler(int irq, void *data, struct pt_regs *regs) +{ + struct smi_info *smi_info = data; + /* We need to clear the IRQ flag for the BT interface. */ + smi_info->io.outputb(&smi_info->io, IPMI_BT_INTMASK_REG, + IPMI_BT_INTMASK_CLEAR_IRQ_BIT + | IPMI_BT_INTMASK_ENABLE_IRQ_BIT); + return si_irq_handler(irq, data, regs); +} + + static struct ipmi_smi_handlers handlers = { .owner = THIS_MODULE, @@ -1001,11 +1017,22 @@ static int std_irq_setup(struct smi_info *info) if (!info->irq) return 0; - rv = request_irq(info->irq, - si_irq_handler, - SA_INTERRUPT, - DEVICE_NAME, - info); + if (info->si_type == SI_BT) { + rv = request_irq(info->irq, + si_bt_irq_handler, + SA_INTERRUPT, + DEVICE_NAME, + info); + if (!rv) + /* Enable the interrupt in the BT interface. */ + info->io.outputb(&info->io, IPMI_BT_INTMASK_REG, + IPMI_BT_INTMASK_ENABLE_IRQ_BIT); + } else + rv = request_irq(info->irq, + si_irq_handler, + SA_INTERRUPT, + DEVICE_NAME, + info); if (rv) { printk(KERN_WARNING "ipmi_si: %s unable to claim interrupt %d," @@ -1024,6 +1051,9 @@ static void std_irq_cleanup(struct smi_info *info) if (!info->irq) return; + if (info->si_type == SI_BT) + /* Disable the interrupt in the BT interface. */ + info->io.outputb(&info->io, IPMI_BT_INTMASK_REG, 0); free_irq(info->irq, info); } -- cgit v1.2.3 From 882fe011a92fa4fc31ca6cc95b279f7e4e52935c Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Sun, 1 May 2005 08:59:12 -0700 Subject: [PATCH] ipmi: fix a deadlock Correct an issue with the IPMI message layer taking a lock and calling lower layer driver. If an error occrues at the lower layer the lock can be taken again causing a deadlock. The lock is released before calling the lower layer. Signed-off-by: David Griego Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_msghandler.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'drivers/char/ipmi') diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index a6606a1aced..d7fb452af7f 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -2588,28 +2588,20 @@ handle_msg_timeout(struct ipmi_recv_msg *msg) deliver_response(msg); } -static void -send_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, - struct ipmi_smi_msg *smi_msg, - unsigned char seq, long seqid) +static struct ipmi_smi_msg * +smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, + unsigned char seq, long seqid) { - if (!smi_msg) - smi_msg = ipmi_alloc_smi_msg(); + struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg(); if (!smi_msg) /* If we can't allocate the message, then just return, we get 4 retries, so this should be ok. */ - return; + return NULL; memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len); smi_msg->data_size = recv_msg->msg.data_len; smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid); - /* Send the new message. We send with a zero priority. It - timed out, I doubt time is that critical now, and high - priority messages are really only for messages to the local - MC, which don't get resent. */ - intf->handlers->sender(intf->send_info, smi_msg, 0); - #ifdef DEBUG_MSGING { int m; @@ -2619,6 +2611,7 @@ send_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, printk("\n"); } #endif + return smi_msg; } static void @@ -2683,14 +2676,13 @@ ipmi_timeout_handler(long timeout_period) intf->timed_out_ipmb_commands++; spin_unlock(&intf->counter_lock); } else { + struct ipmi_smi_msg *smi_msg; /* More retries, send again. */ /* Start with the max timer, set to normal timer after the message is sent. */ ent->timeout = MAX_MSG_TIMEOUT; ent->retries_left--; - send_from_recv_msg(intf, ent->recv_msg, NULL, - j, ent->seqid); spin_lock(&intf->counter_lock); if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE) @@ -2698,6 +2690,20 @@ ipmi_timeout_handler(long timeout_period) else intf->retransmitted_ipmb_commands++; spin_unlock(&intf->counter_lock); + smi_msg = smi_from_recv_msg(intf, + ent->recv_msg, j, ent->seqid); + if(!smi_msg) + continue; + + spin_unlock_irqrestore(&(intf->seq_lock),flags); + /* Send the new message. We send with a zero + * priority. It timed out, I doubt time is + * that critical now, and high priority + * messages are really only for messages to the + * local MC, which don't get resent. */ + intf->handlers->sender(intf->send_info, + smi_msg, 0); + spin_lock_irqsave(&(intf->seq_lock), flags); } } spin_unlock_irqrestore(&(intf->seq_lock), flags); -- cgit v1.2.3