Commit bca0324d authored by Corey Minyard's avatar Corey Minyard Committed by Linus Torvalds

[PATCH] IPMI: remove interface number limits

Remove the arbitrary limit of number of IPMI interfaces.  This has been tested
with 8 interfaces.
Signed-off-by: default avatarCorey Minyard <minyard@acm.org>
Cc: Carol Hebert <cah@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f0b55da0
...@@ -193,6 +193,9 @@ struct ipmi_smi ...@@ -193,6 +193,9 @@ struct ipmi_smi
struct kref refcount; struct kref refcount;
/* Used for a list of interfaces. */
struct list_head link;
/* The list of upper layers that are using me. seq_lock /* The list of upper layers that are using me. seq_lock
* protects this. */ * protects this. */
struct list_head users; struct list_head users;
...@@ -338,13 +341,6 @@ struct ipmi_smi ...@@ -338,13 +341,6 @@ struct ipmi_smi
}; };
#define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev) #define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
/* Used to mark an interface entry that cannot be used but is not a
* free entry, either, primarily used at creation and deletion time so
* a slot doesn't get reused too quickly. */
#define IPMI_INVALID_INTERFACE_ENTRY ((ipmi_smi_t) ((long) 1))
#define IPMI_INVALID_INTERFACE(i) (((i) == NULL) \
|| (i == IPMI_INVALID_INTERFACE_ENTRY))
/** /**
* The driver model view of the IPMI messaging driver. * The driver model view of the IPMI messaging driver.
*/ */
...@@ -354,11 +350,8 @@ static struct device_driver ipmidriver = { ...@@ -354,11 +350,8 @@ static struct device_driver ipmidriver = {
}; };
static DEFINE_MUTEX(ipmidriver_mutex); static DEFINE_MUTEX(ipmidriver_mutex);
#define MAX_IPMI_INTERFACES 4 static struct list_head ipmi_interfaces = LIST_HEAD_INIT(ipmi_interfaces);
static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES]; static DEFINE_MUTEX(ipmi_interfaces_mutex);
/* Directly protects the ipmi_interfaces data structure. */
static DEFINE_SPINLOCK(interfaces_lock);
/* List of watchers that want to know when smi's are added and /* List of watchers that want to know when smi's are added and
deleted. */ deleted. */
...@@ -423,25 +416,50 @@ static void intf_free(struct kref *ref) ...@@ -423,25 +416,50 @@ static void intf_free(struct kref *ref)
kfree(intf); kfree(intf);
} }
struct watcher_entry {
struct list_head link;
int intf_num;
};
int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher) int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
{ {
int i; ipmi_smi_t intf;
unsigned long flags; struct list_head to_deliver = LIST_HEAD_INIT(to_deliver);
struct watcher_entry *e, *e2;
mutex_lock(&ipmi_interfaces_mutex);
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
if (intf->intf_num == -1)
continue;
e = kmalloc(sizeof(*e), GFP_KERNEL);
if (!e)
goto out_err;
e->intf_num = intf->intf_num;
list_add_tail(&e->link, &to_deliver);
}
down_write(&smi_watchers_sem); down_write(&smi_watchers_sem);
list_add(&(watcher->link), &smi_watchers); list_add(&(watcher->link), &smi_watchers);
up_write(&smi_watchers_sem); up_write(&smi_watchers_sem);
spin_lock_irqsave(&interfaces_lock, flags);
for (i = 0; i < MAX_IPMI_INTERFACES; i++) { mutex_unlock(&ipmi_interfaces_mutex);
ipmi_smi_t intf = ipmi_interfaces[i];
if (IPMI_INVALID_INTERFACE(intf)) list_for_each_entry_safe(e, e2, &to_deliver, link) {
continue; list_del(&e->link);
spin_unlock_irqrestore(&interfaces_lock, flags); watcher->new_smi(e->intf_num, intf->si_dev);
watcher->new_smi(i, intf->si_dev); kfree(e);
spin_lock_irqsave(&interfaces_lock, flags);
} }
spin_unlock_irqrestore(&interfaces_lock, flags);
return 0; return 0;
out_err:
list_for_each_entry_safe(e, e2, &to_deliver, link) {
list_del(&e->link);
kfree(e);
}
return -ENOMEM;
} }
int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher) int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
...@@ -776,17 +794,19 @@ int ipmi_create_user(unsigned int if_num, ...@@ -776,17 +794,19 @@ int ipmi_create_user(unsigned int if_num,
if (!new_user) if (!new_user)
return -ENOMEM; return -ENOMEM;
spin_lock_irqsave(&interfaces_lock, flags); rcu_read_lock();
intf = ipmi_interfaces[if_num]; list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
if ((if_num >= MAX_IPMI_INTERFACES) || IPMI_INVALID_INTERFACE(intf)) { if (intf->intf_num == if_num)
spin_unlock_irqrestore(&interfaces_lock, flags); goto found;
}
rcu_read_unlock();
rv = -EINVAL; rv = -EINVAL;
goto out_kfree; goto out_kfree;
}
found:
/* Note that each existing user holds a refcount to the interface. */ /* Note that each existing user holds a refcount to the interface. */
kref_get(&intf->refcount); kref_get(&intf->refcount);
spin_unlock_irqrestore(&interfaces_lock, flags); rcu_read_unlock();
kref_init(&new_user->refcount); kref_init(&new_user->refcount);
new_user->handler = handler; new_user->handler = handler;
...@@ -2449,9 +2469,10 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, ...@@ -2449,9 +2469,10 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
int i, j; int i, j;
int rv; int rv;
ipmi_smi_t intf; ipmi_smi_t intf;
unsigned long flags; ipmi_smi_t tintf;
int version_major; int version_major;
int version_minor; int version_minor;
struct list_head *link;
version_major = ipmi_version_major(device_id); version_major = ipmi_version_major(device_id);
version_minor = ipmi_version_minor(device_id); version_minor = ipmi_version_minor(device_id);
...@@ -2477,7 +2498,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, ...@@ -2477,7 +2498,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
kfree(intf); kfree(intf);
return -ENOMEM; return -ENOMEM;
} }
intf->intf_num = -1; intf->intf_num = -1; /* Mark it invalid for now. */
kref_init(&intf->refcount); kref_init(&intf->refcount);
intf->bmc->id = *device_id; intf->bmc->id = *device_id;
intf->si_dev = si_dev; intf->si_dev = si_dev;
...@@ -2511,20 +2532,22 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, ...@@ -2511,20 +2532,22 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
spin_lock_init(&intf->counter_lock); spin_lock_init(&intf->counter_lock);
intf->proc_dir = NULL; intf->proc_dir = NULL;
rv = -ENOMEM; mutex_lock(&ipmi_interfaces_mutex);
spin_lock_irqsave(&interfaces_lock, flags); /* Look for a hole in the numbers. */
for (i = 0; i < MAX_IPMI_INTERFACES; i++) { i = 0;
if (ipmi_interfaces[i] == NULL) { link = &ipmi_interfaces;
intf->intf_num = i; list_for_each_entry_rcu(tintf, &ipmi_interfaces, link) {
/* Reserve the entry till we are done. */ if (tintf->intf_num != i) {
ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY; link = &tintf->link;
rv = 0;
break; break;
} }
i++;
} }
spin_unlock_irqrestore(&interfaces_lock, flags); /* Add the new interface in numeric order. */
if (rv) if (i == 0)
goto out; list_add_rcu(&intf->link, &ipmi_interfaces);
else
list_add_tail_rcu(&intf->link, link);
rv = handlers->start_processing(send_info, intf); rv = handlers->start_processing(send_info, intf);
if (rv) if (rv)
...@@ -2562,16 +2585,14 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, ...@@ -2562,16 +2585,14 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
if (rv) { if (rv) {
if (intf->proc_dir) if (intf->proc_dir)
remove_proc_entries(intf); remove_proc_entries(intf);
list_del_rcu(&intf->link);
mutex_unlock(&ipmi_interfaces_mutex);
synchronize_rcu();
kref_put(&intf->refcount, intf_free); kref_put(&intf->refcount, intf_free);
if (i < MAX_IPMI_INTERFACES) {
spin_lock_irqsave(&interfaces_lock, flags);
ipmi_interfaces[i] = NULL;
spin_unlock_irqrestore(&interfaces_lock, flags);
}
} else { } else {
spin_lock_irqsave(&interfaces_lock, flags); /* After this point the interface is legal to use. */
ipmi_interfaces[i] = intf; intf->intf_num = i;
spin_unlock_irqrestore(&interfaces_lock, flags); mutex_unlock(&ipmi_interfaces_mutex);
call_smi_watchers(i, intf->si_dev); call_smi_watchers(i, intf->si_dev);
} }
...@@ -2580,26 +2601,14 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, ...@@ -2580,26 +2601,14 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
int ipmi_unregister_smi(ipmi_smi_t intf) int ipmi_unregister_smi(ipmi_smi_t intf)
{ {
int i;
struct ipmi_smi_watcher *w; struct ipmi_smi_watcher *w;
unsigned long flags;
ipmi_bmc_unregister(intf); ipmi_bmc_unregister(intf);
spin_lock_irqsave(&interfaces_lock, flags); mutex_lock(&ipmi_interfaces_mutex);
for (i = 0; i < MAX_IPMI_INTERFACES; i++) { list_del_rcu(&intf->link);
if (ipmi_interfaces[i] == intf) { mutex_unlock(&ipmi_interfaces_mutex);
/* Set the interface number reserved until we synchronize_rcu();
* are done. */
ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY;
intf->intf_num = -1;
break;
}
}
spin_unlock_irqrestore(&interfaces_lock,flags);
if (i == MAX_IPMI_INTERFACES)
return -ENODEV;
remove_proc_entries(intf); remove_proc_entries(intf);
...@@ -2607,14 +2616,9 @@ int ipmi_unregister_smi(ipmi_smi_t intf) ...@@ -2607,14 +2616,9 @@ int ipmi_unregister_smi(ipmi_smi_t intf)
an interface is gone. */ an interface is gone. */
down_read(&smi_watchers_sem); down_read(&smi_watchers_sem);
list_for_each_entry(w, &smi_watchers, link) list_for_each_entry(w, &smi_watchers, link)
w->smi_gone(i); w->smi_gone(intf->intf_num);
up_read(&smi_watchers_sem); up_read(&smi_watchers_sem);
/* Allow the entry to be reused now. */
spin_lock_irqsave(&interfaces_lock, flags);
ipmi_interfaces[i] = NULL;
spin_unlock_irqrestore(&interfaces_lock,flags);
kref_put(&intf->refcount, intf_free); kref_put(&intf->refcount, intf_free);
return 0; return 0;
} }
...@@ -3446,18 +3450,12 @@ static void ipmi_timeout_handler(long timeout_period) ...@@ -3446,18 +3450,12 @@ static void ipmi_timeout_handler(long timeout_period)
struct ipmi_recv_msg *msg, *msg2; struct ipmi_recv_msg *msg, *msg2;
struct ipmi_smi_msg *smi_msg, *smi_msg2; struct ipmi_smi_msg *smi_msg, *smi_msg2;
unsigned long flags; unsigned long flags;
int i, j; int i;
INIT_LIST_HEAD(&timeouts); INIT_LIST_HEAD(&timeouts);
spin_lock(&interfaces_lock); rcu_read_lock();
for (i = 0; i < MAX_IPMI_INTERFACES; i++) { list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
intf = ipmi_interfaces[i];
if (IPMI_INVALID_INTERFACE(intf))
continue;
kref_get(&intf->refcount);
spin_unlock(&interfaces_lock);
/* See if any waiting messages need to be processed. */ /* See if any waiting messages need to be processed. */
spin_lock_irqsave(&intf->waiting_msgs_lock, flags); spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
list_for_each_entry_safe(smi_msg, smi_msg2, list_for_each_entry_safe(smi_msg, smi_msg2,
...@@ -3477,35 +3475,26 @@ static void ipmi_timeout_handler(long timeout_period) ...@@ -3477,35 +3475,26 @@ static void ipmi_timeout_handler(long timeout_period)
have timed out, putting them in the timeouts have timed out, putting them in the timeouts
list. */ list. */
spin_lock_irqsave(&intf->seq_lock, flags); spin_lock_irqsave(&intf->seq_lock, flags);
for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++)
check_msg_timeout(intf, &(intf->seq_table[j]), check_msg_timeout(intf, &(intf->seq_table[i]),
&timeouts, timeout_period, j, &timeouts, timeout_period, i,
&flags); &flags);
spin_unlock_irqrestore(&intf->seq_lock, flags); spin_unlock_irqrestore(&intf->seq_lock, flags);
list_for_each_entry_safe(msg, msg2, &timeouts, link) list_for_each_entry_safe(msg, msg2, &timeouts, link)
handle_msg_timeout(msg); handle_msg_timeout(msg);
kref_put(&intf->refcount, intf_free);
spin_lock(&interfaces_lock);
} }
spin_unlock(&interfaces_lock); rcu_read_unlock();
} }
static void ipmi_request_event(void) static void ipmi_request_event(void)
{ {
ipmi_smi_t intf; ipmi_smi_t intf;
int i;
spin_lock(&interfaces_lock);
for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
intf = ipmi_interfaces[i];
if (IPMI_INVALID_INTERFACE(intf))
continue;
rcu_read_lock();
list_for_each_entry_rcu(intf, &ipmi_interfaces, link)
intf->handlers->request_events(intf->send_info); intf->handlers->request_events(intf->send_info);
} rcu_read_unlock();
spin_unlock(&interfaces_lock);
} }
static struct timer_list ipmi_timer; static struct timer_list ipmi_timer;
...@@ -3634,7 +3623,6 @@ static void send_panic_events(char *str) ...@@ -3634,7 +3623,6 @@ static void send_panic_events(char *str)
struct kernel_ipmi_msg msg; struct kernel_ipmi_msg msg;
ipmi_smi_t intf; ipmi_smi_t intf;
unsigned char data[16]; unsigned char data[16];
int i;
struct ipmi_system_interface_addr *si; struct ipmi_system_interface_addr *si;
struct ipmi_addr addr; struct ipmi_addr addr;
struct ipmi_smi_msg smi_msg; struct ipmi_smi_msg smi_msg;
...@@ -3668,9 +3656,9 @@ static void send_panic_events(char *str) ...@@ -3668,9 +3656,9 @@ static void send_panic_events(char *str)
recv_msg.done = dummy_recv_done_handler; recv_msg.done = dummy_recv_done_handler;
/* For every registered interface, send the event. */ /* For every registered interface, send the event. */
for (i = 0; i < MAX_IPMI_INTERFACES; i++) { list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
intf = ipmi_interfaces[i]; if (intf->intf_num == -1)
if (IPMI_INVALID_INTERFACE(intf)) /* Interface was not ready yet. */
continue; continue;
/* Send the event announcing the panic. */ /* Send the event announcing the panic. */
...@@ -3695,13 +3683,14 @@ static void send_panic_events(char *str) ...@@ -3695,13 +3683,14 @@ static void send_panic_events(char *str)
if (!str) if (!str)
return; return;
for (i = 0; i < MAX_IPMI_INTERFACES; i++) { /* For every registered interface, send the event. */
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
char *p = str; char *p = str;
struct ipmi_ipmb_addr *ipmb; struct ipmi_ipmb_addr *ipmb;
int j; int j;
intf = ipmi_interfaces[i]; if (intf->intf_num == -1)
if (IPMI_INVALID_INTERFACE(intf)) /* Interface was not ready yet. */
continue; continue;
/* First job here is to figure out where to send the /* First job here is to figure out where to send the
...@@ -3827,7 +3816,6 @@ static int panic_event(struct notifier_block *this, ...@@ -3827,7 +3816,6 @@ static int panic_event(struct notifier_block *this,
unsigned long event, unsigned long event,
void *ptr) void *ptr)
{ {
int i;
ipmi_smi_t intf; ipmi_smi_t intf;
if (has_panicked) if (has_panicked)
...@@ -3835,9 +3823,9 @@ static int panic_event(struct notifier_block *this, ...@@ -3835,9 +3823,9 @@ static int panic_event(struct notifier_block *this,
has_panicked = 1; has_panicked = 1;
/* For every registered interface, set it to run to completion. */ /* For every registered interface, set it to run to completion. */
for (i = 0; i < MAX_IPMI_INTERFACES; i++) { list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
intf = ipmi_interfaces[i]; if (intf->intf_num == -1)
if (IPMI_INVALID_INTERFACE(intf)) /* Interface was not ready yet. */
continue; continue;
intf->handlers->set_run_to_completion(intf->send_info, 1); intf->handlers->set_run_to_completion(intf->send_info, 1);
...@@ -3858,7 +3846,6 @@ static struct notifier_block panic_block = { ...@@ -3858,7 +3846,6 @@ static struct notifier_block panic_block = {
static int ipmi_init_msghandler(void) static int ipmi_init_msghandler(void)
{ {
int i;
int rv; int rv;
if (initialized) if (initialized)
...@@ -3873,9 +3860,6 @@ static int ipmi_init_msghandler(void) ...@@ -3873,9 +3860,6 @@ static int ipmi_init_msghandler(void)
printk(KERN_INFO "ipmi message handler version " printk(KERN_INFO "ipmi message handler version "
IPMI_DRIVER_VERSION "\n"); IPMI_DRIVER_VERSION "\n");
for (i = 0; i < MAX_IPMI_INTERFACES; i++)
ipmi_interfaces[i] = NULL;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
proc_ipmi_root = proc_mkdir("ipmi", NULL); proc_ipmi_root = proc_mkdir("ipmi", NULL);
if (!proc_ipmi_root) { if (!proc_ipmi_root) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment