Skip to content

Commit

Permalink
ehea: fix circular locking problem
Browse files Browse the repository at this point in the history
This patch fixes the circular locking problem by changing the locking strategy
concerning the logging of firmware handles.

Signed-off-by: Jan-Bernd Themann <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Jan-Bernd Themann authored and davem330 committed Mar 13, 2009
1 parent f9ac30f commit 52e21b1
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 27 deletions.
2 changes: 1 addition & 1 deletion drivers/net/ehea/ehea.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
#include <asm/io.h>

#define DRV_NAME "ehea"
#define DRV_VERSION "EHEA_0099"
#define DRV_VERSION "EHEA_0100"

/* eHEA capability flags */
#define DLPAR_PORT_ADD_REM 1
Expand Down
56 changes: 30 additions & 26 deletions drivers/net/ehea/ehea_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ static void ehea_update_firmware_handles(void)
int num_fw_handles, k, l;

/* Determine number of handles */
mutex_lock(&ehea_fw_handles.lock);

list_for_each_entry(adapter, &adapter_list, list) {
num_adapters++;

Expand All @@ -176,15 +178,19 @@ static void ehea_update_firmware_handles(void)
if (num_fw_handles) {
arr = kzalloc(num_fw_handles * sizeof(*arr), GFP_KERNEL);
if (!arr)
return; /* Keep the existing array */
goto out; /* Keep the existing array */
} else
goto out_update;

list_for_each_entry(adapter, &adapter_list, list) {
if (num_adapters == 0)
break;

for (k = 0; k < EHEA_MAX_PORTS; k++) {
struct ehea_port *port = adapter->port[k];

if (!port || (port->state != EHEA_PORT_UP))
if (!port || (port->state != EHEA_PORT_UP)
|| (num_ports == 0))
continue;

for (l = 0;
Expand All @@ -207,6 +213,7 @@ static void ehea_update_firmware_handles(void)
}
arr[i].adh = adapter->handle;
arr[i++].fwh = port->qp_eq->fw_handle;
num_ports--;
}

arr[i].adh = adapter->handle;
Expand All @@ -216,23 +223,29 @@ static void ehea_update_firmware_handles(void)
arr[i].adh = adapter->handle;
arr[i++].fwh = adapter->mr.handle;
}
num_adapters--;
}

out_update:
kfree(ehea_fw_handles.arr);
ehea_fw_handles.arr = arr;
ehea_fw_handles.num_entries = i;
out:
mutex_unlock(&ehea_fw_handles.lock);
}

static void ehea_update_bcmc_registrations(void)
{
unsigned long flags;
struct ehea_bcmc_reg_entry *arr = NULL;
struct ehea_adapter *adapter;
struct ehea_mc_list *mc_entry;
int num_registrations = 0;
int i = 0;
int k;

spin_lock_irqsave(&ehea_bcmc_regs.lock, flags);

/* Determine number of registrations */
list_for_each_entry(adapter, &adapter_list, list)
for (k = 0; k < EHEA_MAX_PORTS; k++) {
Expand All @@ -250,7 +263,7 @@ static void ehea_update_bcmc_registrations(void)
if (num_registrations) {
arr = kzalloc(num_registrations * sizeof(*arr), GFP_ATOMIC);
if (!arr)
return; /* Keep the existing array */
goto out; /* Keep the existing array */
} else
goto out_update;

Expand All @@ -261,6 +274,9 @@ static void ehea_update_bcmc_registrations(void)
if (!port || (port->state != EHEA_PORT_UP))
continue;

if (num_registrations == 0)
goto out_update;

arr[i].adh = adapter->handle;
arr[i].port_id = port->logical_port_id;
arr[i].reg_type = EHEA_BCMC_BROADCAST |
Expand All @@ -272,9 +288,13 @@ static void ehea_update_bcmc_registrations(void)
arr[i].reg_type = EHEA_BCMC_BROADCAST |
EHEA_BCMC_VLANID_ALL;
arr[i++].macaddr = port->mac_addr;
num_registrations -= 2;

list_for_each_entry(mc_entry,
&port->mc_list->list, list) {
if (num_registrations == 0)
goto out_update;

arr[i].adh = adapter->handle;
arr[i].port_id = port->logical_port_id;
arr[i].reg_type = EHEA_BCMC_SCOPE_ALL |
Expand All @@ -288,6 +308,7 @@ static void ehea_update_bcmc_registrations(void)
EHEA_BCMC_MULTICAST |
EHEA_BCMC_VLANID_ALL;
arr[i++].macaddr = mc_entry->macaddr;
num_registrations -= 2;
}
}
}
Expand All @@ -296,6 +317,8 @@ static void ehea_update_bcmc_registrations(void)
kfree(ehea_bcmc_regs.arr);
ehea_bcmc_regs.arr = arr;
ehea_bcmc_regs.num_entries = i;
out:
spin_unlock_irqrestore(&ehea_bcmc_regs.lock, flags);
}

static struct net_device_stats *ehea_get_stats(struct net_device *dev)
Expand Down Expand Up @@ -1762,8 +1785,6 @@ static int ehea_set_mac_addr(struct net_device *dev, void *sa)

memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len);

spin_lock(&ehea_bcmc_regs.lock);

/* Deregister old MAC in pHYP */
if (port->state == EHEA_PORT_UP) {
ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
Expand All @@ -1784,7 +1805,6 @@ static int ehea_set_mac_addr(struct net_device *dev, void *sa)

out_upregs:
ehea_update_bcmc_registrations();
spin_unlock(&ehea_bcmc_regs.lock);
out_free:
free_page((unsigned long)cb0);
out:
Expand Down Expand Up @@ -1946,8 +1966,6 @@ static void ehea_set_multicast_list(struct net_device *dev)
}
ehea_promiscuous(dev, 0);

spin_lock(&ehea_bcmc_regs.lock);

if (dev->flags & IFF_ALLMULTI) {
ehea_allmulti(dev, 1);
goto out;
Expand Down Expand Up @@ -1977,7 +1995,6 @@ static void ehea_set_multicast_list(struct net_device *dev)
}
out:
ehea_update_bcmc_registrations();
spin_unlock(&ehea_bcmc_regs.lock);
return;
}

Expand Down Expand Up @@ -2458,8 +2475,6 @@ static int ehea_up(struct net_device *dev)
if (port->state == EHEA_PORT_UP)
return 0;

mutex_lock(&ehea_fw_handles.lock);

ret = ehea_port_res_setup(port, port->num_def_qps,
port->num_add_tx_qps);
if (ret) {
Expand Down Expand Up @@ -2496,8 +2511,6 @@ static int ehea_up(struct net_device *dev)
}
}

spin_lock(&ehea_bcmc_regs.lock);

ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
if (ret) {
ret = -EIO;
Expand All @@ -2519,10 +2532,7 @@ static int ehea_up(struct net_device *dev)
ehea_info("Failed starting %s. ret=%i", dev->name, ret);

ehea_update_bcmc_registrations();
spin_unlock(&ehea_bcmc_regs.lock);

ehea_update_firmware_handles();
mutex_unlock(&ehea_fw_handles.lock);

return ret;
}
Expand Down Expand Up @@ -2572,9 +2582,6 @@ static int ehea_down(struct net_device *dev)
if (port->state == EHEA_PORT_DOWN)
return 0;

mutex_lock(&ehea_fw_handles.lock);

spin_lock(&ehea_bcmc_regs.lock);
ehea_drop_multicast_list(dev);
ehea_broadcast_reg_helper(port, H_DEREG_BCMC);

Expand All @@ -2583,15 +2590,13 @@ static int ehea_down(struct net_device *dev)
port->state = EHEA_PORT_DOWN;

ehea_update_bcmc_registrations();
spin_unlock(&ehea_bcmc_regs.lock);

ret = ehea_clean_all_portres(port);
if (ret)
ehea_info("Failed freeing resources for %s. ret=%i",
dev->name, ret);

ehea_update_firmware_handles();
mutex_unlock(&ehea_fw_handles.lock);

return ret;
}
Expand Down Expand Up @@ -3368,7 +3373,6 @@ static int __devinit ehea_probe_adapter(struct of_device *dev,
ehea_error("Invalid ibmebus device probed");
return -EINVAL;
}
mutex_lock(&ehea_fw_handles.lock);

adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
if (!adapter) {
Expand Down Expand Up @@ -3453,7 +3457,7 @@ static int __devinit ehea_probe_adapter(struct of_device *dev,

out:
ehea_update_firmware_handles();
mutex_unlock(&ehea_fw_handles.lock);

return ret;
}

Expand All @@ -3472,8 +3476,6 @@ static int __devexit ehea_remove(struct of_device *dev)

flush_scheduled_work();

mutex_lock(&ehea_fw_handles.lock);

ibmebus_free_irq(adapter->neq->attr.ist1, adapter);
tasklet_kill(&adapter->neq_tasklet);

Expand All @@ -3483,7 +3485,6 @@ static int __devexit ehea_remove(struct of_device *dev)
kfree(adapter);

ehea_update_firmware_handles();
mutex_unlock(&ehea_fw_handles.lock);

return 0;
}
Expand Down Expand Up @@ -3532,6 +3533,9 @@ static int ehea_mem_notifier(struct notifier_block *nb,
default:
break;
}

ehea_update_firmware_handles();

return NOTIFY_OK;
}

Expand Down

0 comments on commit 52e21b1

Please sign in to comment.