diff options
Diffstat (limited to 'drivers/net/ehea/ehea_main.c')
-rw-r--r-- | drivers/net/ehea/ehea_main.c | 144 |
1 files changed, 130 insertions, 14 deletions
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 383144db4d1..1d1571cf322 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -79,6 +79,11 @@ MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue " MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 1 "); static int port_name_cnt = 0; +static LIST_HEAD(adapter_list); +u64 ehea_driver_flags = 0; +struct workqueue_struct *ehea_driver_wq; +struct work_struct ehea_rereg_mr_task; + static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, const struct of_device_id *id); @@ -238,13 +243,17 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr, rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, wqe_type) | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index); rwqe->sg_list[0].l_key = pr->recv_mr.lkey; - rwqe->sg_list[0].vaddr = (u64)skb->data; + rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data); rwqe->sg_list[0].len = packet_size; rwqe->data_segments = 1; index++; index &= max_index_mask; + + if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) + goto out; } + q_skba->index = index; /* Ring doorbell */ @@ -253,7 +262,7 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr, ehea_update_rq2a(pr->qp, i); else ehea_update_rq3a(pr->qp, i); - +out: return ret; } @@ -1321,7 +1330,7 @@ static void write_swqe2_TSO(struct sk_buff *skb, sg1entry->len = skb_data_size - headersize; tmp_addr = (u64)(skb->data + headersize); - sg1entry->vaddr = tmp_addr; + sg1entry->vaddr = ehea_map_vaddr(tmp_addr); swqe->descriptors++; } } else @@ -1352,7 +1361,7 @@ static void write_swqe2_nonTSO(struct sk_buff *skb, sg1entry->l_key = lkey; sg1entry->len = skb_data_size - SWQE2_MAX_IMM; tmp_addr = (u64)(skb->data + SWQE2_MAX_IMM); - sg1entry->vaddr = tmp_addr; + sg1entry->vaddr = ehea_map_vaddr(tmp_addr); swqe->descriptors++; } } else { @@ -1391,7 +1400,7 @@ static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev, sg1entry->len = frag->size; tmp_addr = (u64)(page_address(frag->page) + frag->page_offset); - sg1entry->vaddr = tmp_addr; + sg1entry->vaddr = ehea_map_vaddr(tmp_addr); swqe->descriptors++; sg1entry_contains_frag_data = 1; } @@ -1406,7 +1415,7 @@ static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev, tmp_addr = (u64)(page_address(frag->page) + frag->page_offset); - sgentry->vaddr = tmp_addr; + sgentry->vaddr = ehea_map_vaddr(tmp_addr); swqe->descriptors++; } } @@ -1878,6 +1887,9 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) ehea_dump(swqe, 512, "swqe"); } + if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) + goto out; + ehea_post_swqe(pr->qp, swqe); pr->tx_packets++; @@ -1892,7 +1904,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) } dev->trans_start = jiffies; spin_unlock(&pr->xmit_lock); - +out: return NETDEV_TX_OK; } @@ -2220,6 +2232,9 @@ out_dereg_bc: out_clean_pr: ehea_clean_all_portres(port); out: + if (ret) + ehea_info("Failed starting %s. ret=%i", dev->name, ret); + return ret; } @@ -2259,8 +2274,13 @@ static int ehea_down(struct net_device *dev) msleep(1); ehea_broadcast_reg_helper(port, H_DEREG_BCMC); - ret = ehea_clean_all_portres(port); port->state = EHEA_PORT_DOWN; + + ret = ehea_clean_all_portres(port); + if (ret) + ehea_info("Failed freeing resources for %s. ret=%i", + dev->name, ret); + return ret; } @@ -2292,15 +2312,11 @@ static void ehea_reset_port(struct work_struct *work) netif_stop_queue(dev); netif_poll_disable(dev); - ret = ehea_down(dev); - if (ret) - ehea_error("ehea_down failed. not all resources are freed"); + ehea_down(dev); ret = ehea_up(dev); - if (ret) { - ehea_error("Reset device %s failed: ret=%d", dev->name, ret); + if (ret) goto out; - } if (netif_msg_timer(port)) ehea_info("Device %s resetted successfully", dev->name); @@ -2312,6 +2328,88 @@ out: return; } +static void ehea_rereg_mrs(struct work_struct *work) +{ + int ret, i; + struct ehea_adapter *adapter; + + ehea_info("LPAR memory enlarged - re-initializing driver"); + + list_for_each_entry(adapter, &adapter_list, list) + if (adapter->active_ports) { + /* Shutdown all ports */ + for (i = 0; i < EHEA_MAX_PORTS; i++) { + struct ehea_port *port = adapter->port[i]; + + if (port) { + struct net_device *dev = port->netdev; + + if (dev->flags & IFF_UP) { + ehea_info("stopping %s", + dev->name); + down(&port->port_lock); + netif_stop_queue(dev); + netif_poll_disable(dev); + ehea_down(dev); + up(&port->port_lock); + } + } + } + + /* Unregister old memory region */ + ret = ehea_rem_mr(&adapter->mr); + if (ret) { + ehea_error("unregister MR failed - driver" + " inoperable!"); + goto out; + } + } + + ehea_destroy_busmap(); + + ret = ehea_create_busmap(); + if (ret) + goto out; + + clear_bit(__EHEA_STOP_XFER, &ehea_driver_flags); + + list_for_each_entry(adapter, &adapter_list, list) + if (adapter->active_ports) { + /* Register new memory region */ + ret = ehea_reg_kernel_mr(adapter, &adapter->mr); + if (ret) { + ehea_error("register MR failed - driver" + " inoperable!"); + goto out; + } + + /* Restart all ports */ + for (i = 0; i < EHEA_MAX_PORTS; i++) { + struct ehea_port *port = adapter->port[i]; + + if (port) { + struct net_device *dev = port->netdev; + + if (dev->flags & IFF_UP) { + ehea_info("restarting %s", + dev->name); + down(&port->port_lock); + + ret = ehea_up(dev); + if (!ret) { + netif_poll_enable(dev); + netif_wake_queue(dev); + } + + up(&port->port_lock); + } + } + } + } +out: + return; +} + static void ehea_tx_watchdog(struct net_device *dev) { struct ehea_port *port = netdev_priv(dev); @@ -2573,6 +2671,8 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, ehea_info("%s: Jumbo frames are %sabled", dev->name, jumbo == 1 ? "en" : "dis"); + adapter->active_ports++; + return port; out_unreg_port: @@ -2596,6 +2696,7 @@ static void ehea_shutdown_single_port(struct ehea_port *port) ehea_unregister_port(port); kfree(port->mc_list); free_netdev(port->netdev); + port->adapter->active_ports--; } static int ehea_setup_ports(struct ehea_adapter *adapter) @@ -2788,6 +2889,8 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, goto out; } + list_add(&adapter->list, &adapter_list); + adapter->ebus_dev = dev; adapter_handle = of_get_property(dev->ofdev.node, "ibm,hea-handle", @@ -2891,7 +2994,10 @@ static int __devexit ehea_remove(struct ibmebus_dev *dev) ehea_destroy_eq(adapter->neq); ehea_remove_adapter_mr(adapter); + list_del(&adapter->list); + kfree(adapter); + return 0; } @@ -2939,9 +3045,18 @@ int __init ehea_module_init(void) printk(KERN_INFO "IBM eHEA ethernet device driver (Release %s)\n", DRV_VERSION); + ehea_driver_wq = create_workqueue("ehea_driver_wq"); + + INIT_WORK(&ehea_rereg_mr_task, ehea_rereg_mrs); + ret = check_module_parm(); if (ret) goto out; + + ret = ehea_create_busmap(); + if (ret) + goto out; + ret = ibmebus_register_driver(&ehea_driver); if (ret) { ehea_error("failed registering eHEA device driver on ebus"); @@ -2965,6 +3080,7 @@ static void __exit ehea_module_exit(void) { driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities); ibmebus_unregister_driver(&ehea_driver); + ehea_destroy_busmap(); } module_init(ehea_module_init); |