diff options
Diffstat (limited to 'drivers/net/ehea/ehea_main.c')
| -rw-r--r-- | drivers/net/ehea/ehea_main.c | 89 | 
1 files changed, 63 insertions, 26 deletions
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index f9bc21c74b5..0920b796bd7 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -35,6 +35,7 @@  #include <linux/if_ether.h>  #include <linux/notifier.h>  #include <linux/reboot.h> +#include <linux/memory.h>  #include <asm/kexec.h>  #include <linux/mutex.h> @@ -117,6 +118,7 @@ static struct of_device_id ehea_device_table[] = {  	},  	{},  }; +MODULE_DEVICE_TABLE(of, ehea_device_table);  static struct of_platform_driver ehea_driver = {  	.name = "ehea", @@ -136,6 +138,12 @@ void ehea_dump(void *adr, int len, char *msg)  	}  } +void ehea_schedule_port_reset(struct ehea_port *port) +{ +	if (!test_bit(__EHEA_DISABLE_PORT_RESET, &port->flags)) +		schedule_work(&port->reset_task); +} +  static void ehea_update_firmware_handles(void)  {  	struct ehea_fw_handle_entry *arr = NULL; @@ -240,7 +248,7 @@ static void ehea_update_bcmc_registrations(void)  		}  	if (num_registrations) { -		arr = kzalloc(num_registrations * sizeof(*arr), GFP_KERNEL); +		arr = kzalloc(num_registrations * sizeof(*arr), GFP_ATOMIC);  		if (!arr)  			return;  /* Keep the existing array */  	} else @@ -300,7 +308,7 @@ static struct net_device_stats *ehea_get_stats(struct net_device *dev)  	memset(stats, 0, sizeof(*stats)); -	cb2 = kzalloc(PAGE_SIZE, GFP_KERNEL); +	cb2 = kzalloc(PAGE_SIZE, GFP_ATOMIC);  	if (!cb2) {  		ehea_error("no mem for cb2");  		goto out; @@ -586,7 +594,7 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,  				   "Resetting port.", pr->qp->init_attr.qp_nr);  			ehea_dump(cqe, sizeof(*cqe), "CQE");  		} -		schedule_work(&pr->port->reset_task); +		ehea_schedule_port_reset(pr->port);  		return 1;  	} @@ -615,7 +623,7 @@ static int get_skb_hdr(struct sk_buff *skb, void **iphdr,  	*tcph = tcp_hdr(skb);  	/* check if ip header and tcp header are complete */ -	if (iph->tot_len < ip_len + tcp_hdrlen(skb)) +	if (ntohs(iph->tot_len) < ip_len + tcp_hdrlen(skb))  		return -1;  	*hdr_flags = LRO_IPV4 | LRO_TCP; @@ -764,7 +772,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)  			ehea_error("Send Completion Error: Resetting port");  			if (netif_msg_tx_err(pr->port))  				ehea_dump(cqe, sizeof(*cqe), "Send CQE"); -			schedule_work(&pr->port->reset_task); +			ehea_schedule_port_reset(pr->port);  			break;  		} @@ -884,7 +892,7 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)  		eqe = ehea_poll_eq(port->qp_eq);  	} -	schedule_work(&port->reset_task); +	ehea_schedule_port_reset(port);  	return IRQ_HANDLED;  } @@ -1762,25 +1770,29 @@ static int ehea_set_mac_addr(struct net_device *dev, void *sa)  	memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len); -	mutex_lock(&ehea_bcmc_regs.lock); +	spin_lock(&ehea_bcmc_regs.lock);  	/* Deregister old MAC in pHYP */ -	ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC); -	if (ret) -		goto out_upregs; +	if (port->state == EHEA_PORT_UP) { +		ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC); +		if (ret) +			goto out_upregs; +	}  	port->mac_addr = cb0->port_mac_addr << 16;  	/* Register new MAC in pHYP */ -	ret = ehea_broadcast_reg_helper(port, H_REG_BCMC); -	if (ret) -		goto out_upregs; +	if (port->state == EHEA_PORT_UP) { +		ret = ehea_broadcast_reg_helper(port, H_REG_BCMC); +		if (ret) +			goto out_upregs; +	}  	ret = 0;  out_upregs:  	ehea_update_bcmc_registrations(); -	mutex_unlock(&ehea_bcmc_regs.lock); +	spin_unlock(&ehea_bcmc_regs.lock);  out_free:  	kfree(cb0);  out: @@ -1942,7 +1954,7 @@ static void ehea_set_multicast_list(struct net_device *dev)  	}  	ehea_promiscuous(dev, 0); -	mutex_lock(&ehea_bcmc_regs.lock); +	spin_lock(&ehea_bcmc_regs.lock);  	if (dev->flags & IFF_ALLMULTI) {  		ehea_allmulti(dev, 1); @@ -1973,7 +1985,7 @@ static void ehea_set_multicast_list(struct net_device *dev)  	}  out:  	ehea_update_bcmc_registrations(); -	mutex_unlock(&ehea_bcmc_regs.lock); +	spin_unlock(&ehea_bcmc_regs.lock);  	return;  } @@ -2212,8 +2224,6 @@ static void ehea_vlan_rx_register(struct net_device *dev,  		goto out;  	} -	memset(cb1->vlan_filter, 0, sizeof(cb1->vlan_filter)); -  	hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,  				       H_PORT_CB1, H_PORT_CB1_ALL, cb1);  	if (hret != H_SUCCESS) @@ -2494,7 +2504,7 @@ static int ehea_up(struct net_device *dev)  		}  	} -	mutex_lock(&ehea_bcmc_regs.lock); +	spin_lock(&ehea_bcmc_regs.lock);  	ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);  	if (ret) { @@ -2517,7 +2527,7 @@ out:  		ehea_info("Failed starting %s. ret=%i", dev->name, ret);  	ehea_update_bcmc_registrations(); -	mutex_unlock(&ehea_bcmc_regs.lock); +	spin_unlock(&ehea_bcmc_regs.lock);  	ehea_update_firmware_handles();  	mutex_unlock(&ehea_fw_handles.lock); @@ -2572,7 +2582,7 @@ static int ehea_down(struct net_device *dev)  	mutex_lock(&ehea_fw_handles.lock); -	mutex_lock(&ehea_bcmc_regs.lock); +	spin_lock(&ehea_bcmc_regs.lock);  	ehea_drop_multicast_list(dev);  	ehea_broadcast_reg_helper(port, H_DEREG_BCMC); @@ -2581,7 +2591,7 @@ static int ehea_down(struct net_device *dev)  	port->state = EHEA_PORT_DOWN;  	ehea_update_bcmc_registrations(); -	mutex_unlock(&ehea_bcmc_regs.lock); +	spin_unlock(&ehea_bcmc_regs.lock);  	ret = ehea_clean_all_portres(port);  	if (ret) @@ -2602,12 +2612,14 @@ static int ehea_stop(struct net_device *dev)  	if (netif_msg_ifdown(port))  		ehea_info("disabling port %s", dev->name); -	flush_scheduled_work(); +	set_bit(__EHEA_DISABLE_PORT_RESET, &port->flags); +	cancel_work_sync(&port->reset_task);  	mutex_lock(&port->port_lock);  	netif_stop_queue(dev);  	port_napi_disable(port);  	ret = ehea_down(dev);  	mutex_unlock(&port->port_lock); +	clear_bit(__EHEA_DISABLE_PORT_RESET, &port->flags);  	return ret;  } @@ -2937,7 +2949,7 @@ static void ehea_tx_watchdog(struct net_device *dev)  	if (netif_carrier_ok(dev) &&  	    !test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)) -		schedule_work(&port->reset_task); +		ehea_schedule_port_reset(port);  }  int ehea_sense_adapter_attr(struct ehea_adapter *adapter) @@ -3177,11 +3189,12 @@ out_err:  static void ehea_shutdown_single_port(struct ehea_port *port)  { +	struct ehea_adapter *adapter = port->adapter;  	unregister_netdev(port->netdev);  	ehea_unregister_port(port);  	kfree(port->mc_list);  	free_netdev(port->netdev); -	port->adapter->active_ports--; +	adapter->active_ports--;  }  static int ehea_setup_ports(struct ehea_adapter *adapter) @@ -3503,6 +3516,24 @@ void ehea_crash_handler(void)  					      0, H_DEREG_BCMC);  } +static int ehea_mem_notifier(struct notifier_block *nb, +                             unsigned long action, void *data) +{ +	switch (action) { +	case MEM_OFFLINE: +		ehea_info("memory has been removed"); +		ehea_rereg_mrs(NULL); +		break; +	default: +		break; +	} +	return NOTIFY_OK; +} + +static struct notifier_block ehea_mem_nb = { +	.notifier_call = ehea_mem_notifier, +}; +  static int ehea_reboot_notifier(struct notifier_block *nb,  				unsigned long action, void *unused)  { @@ -3567,7 +3598,7 @@ int __init ehea_module_init(void)  	memset(&ehea_bcmc_regs, 0, sizeof(ehea_bcmc_regs));  	mutex_init(&ehea_fw_handles.lock); -	mutex_init(&ehea_bcmc_regs.lock); +	spin_lock_init(&ehea_bcmc_regs.lock);  	ret = check_module_parm();  	if (ret) @@ -3581,6 +3612,10 @@ int __init ehea_module_init(void)  	if (ret)  		ehea_info("failed registering reboot notifier"); +	ret = register_memory_notifier(&ehea_mem_nb); +	if (ret) +		ehea_info("failed registering memory remove notifier"); +  	ret = crash_shutdown_register(&ehea_crash_handler);  	if (ret)  		ehea_info("failed registering crash handler"); @@ -3604,6 +3639,7 @@ int __init ehea_module_init(void)  out3:  	ibmebus_unregister_driver(&ehea_driver);  out2: +	unregister_memory_notifier(&ehea_mem_nb);  	unregister_reboot_notifier(&ehea_reboot_nb);  	crash_shutdown_unregister(&ehea_crash_handler);  out: @@ -3621,6 +3657,7 @@ static void __exit ehea_module_exit(void)  	ret = crash_shutdown_unregister(&ehea_crash_handler);  	if (ret)  		ehea_info("failed unregistering crash handler"); +	unregister_memory_notifier(&ehea_mem_nb);  	kfree(ehea_fw_handles.arr);  	kfree(ehea_bcmc_regs.arr);  	ehea_destroy_busmap();  |