diff options
Diffstat (limited to 'drivers/net/ehea/ehea_main.c')
-rw-r--r-- | drivers/net/ehea/ehea_main.c | 98 |
1 files changed, 85 insertions, 13 deletions
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 897719b49f96..bb7d306fb446 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -180,7 +180,7 @@ static void ehea_update_firmware_handles(void) num_portres * EHEA_NUM_PORTRES_FW_HANDLES; if (num_fw_handles) { - arr = kzalloc(num_fw_handles * sizeof(*arr), GFP_KERNEL); + arr = kcalloc(num_fw_handles, sizeof(*arr), GFP_KERNEL); if (!arr) goto out; /* Keep the existing array */ } else @@ -265,7 +265,7 @@ static void ehea_update_bcmc_registrations(void) } if (num_registrations) { - arr = kzalloc(num_registrations * sizeof(*arr), GFP_ATOMIC); + arr = kcalloc(num_registrations, sizeof(*arr), GFP_ATOMIC); if (!arr) goto out; /* Keep the existing array */ } else @@ -533,8 +533,15 @@ static inline void ehea_fill_skb(struct net_device *dev, int length = cqe->num_bytes_transfered - 4; /*remove CRC */ skb_put(skb, length); - skb->ip_summed = CHECKSUM_UNNECESSARY; skb->protocol = eth_type_trans(skb, dev); + + /* The packet was not an IPV4 packet so a complemented checksum was + calculated. The value is found in the Internet Checksum field. */ + if (cqe->status & EHEA_CQE_BLIND_CKSUM) { + skb->ip_summed = CHECKSUM_COMPLETE; + skb->csum = csum_unfold(~cqe->inet_checksum_value); + } else + skb->ip_summed = CHECKSUM_UNNECESSARY; } static inline struct sk_buff *get_skb_by_index(struct sk_buff **skb_array, @@ -776,6 +783,54 @@ static int ehea_proc_rwqes(struct net_device *dev, return processed; } +#define SWQE_RESTART_CHECK 0xdeadbeaff00d0000ull + +static void reset_sq_restart_flag(struct ehea_port *port) +{ + int i; + + for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { + struct ehea_port_res *pr = &port->port_res[i]; + pr->sq_restart_flag = 0; + } + wake_up(&port->restart_wq); +} + +static void check_sqs(struct ehea_port *port) +{ + struct ehea_swqe *swqe; + int swqe_index; + int i, k; + + for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { + struct ehea_port_res *pr = &port->port_res[i]; + int ret; + k = 0; + swqe = ehea_get_swqe(pr->qp, &swqe_index); + memset(swqe, 0, SWQE_HEADER_SIZE); + atomic_dec(&pr->swqe_avail); + + swqe->tx_control |= EHEA_SWQE_PURGE; + swqe->wr_id = SWQE_RESTART_CHECK; + swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION; + swqe->tx_control |= EHEA_SWQE_IMM_DATA_PRESENT; + swqe->immediate_data_length = 80; + + ehea_post_swqe(pr->qp, swqe); + + ret = wait_event_timeout(port->restart_wq, + pr->sq_restart_flag == 0, + msecs_to_jiffies(100)); + + if (!ret) { + ehea_error("HW/SW queues out of sync"); + ehea_schedule_port_reset(pr->port); + return; + } + } +} + + static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) { struct sk_buff *skb; @@ -793,6 +848,13 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) cqe_counter++; rmb(); + + if (cqe->wr_id == SWQE_RESTART_CHECK) { + pr->sq_restart_flag = 1; + swqe_av++; + break; + } + if (cqe->status & EHEA_CQE_STAT_ERR_MASK) { ehea_error("Bad send completion status=0x%04X", cqe->status); @@ -836,6 +898,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) pr->queue_stopped = 0; } spin_unlock_irqrestore(&pr->netif_queue, flags); + wake_up(&pr->port->swqe_avail_wq); return cqe; } @@ -1862,7 +1925,7 @@ static void ehea_promiscuous(struct net_device *dev, int enable) struct hcp_ehea_port_cb7 *cb7; u64 hret; - if ((enable && port->promisc) || (!enable && !port->promisc)) + if (enable == port->promisc) return; cb7 = (void *)get_zeroed_page(GFP_ATOMIC); @@ -2216,7 +2279,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) } pr->swqe_id_counter += 1; - if (port->vgrp && vlan_tx_tag_present(skb)) { + if (vlan_tx_tag_present(skb)) { swqe->tx_control |= EHEA_SWQE_VLAN_INSERT; swqe->vlan_tag = vlan_tx_tag_get(skb); } @@ -2600,6 +2663,9 @@ static int ehea_open(struct net_device *dev) netif_start_queue(dev); } + init_waitqueue_head(&port->swqe_avail_wq); + init_waitqueue_head(&port->restart_wq); + mutex_unlock(&port->port_lock); return ret; @@ -2672,11 +2738,15 @@ static void ehea_flush_sq(struct ehea_port *port) for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { struct ehea_port_res *pr = &port->port_res[i]; int swqe_max = pr->sq_skba_size - 2 - pr->swqe_ll_count; - int k = 0; - while (atomic_read(&pr->swqe_avail) < swqe_max) { - msleep(5); - if (++k == 20) - break; + int ret; + + ret = wait_event_timeout(port->swqe_avail_wq, + atomic_read(&pr->swqe_avail) >= swqe_max, + msecs_to_jiffies(100)); + + if (!ret) { + ehea_error("WARNING: sq not flushed completely"); + break; } } } @@ -2917,6 +2987,7 @@ static void ehea_rereg_mrs(struct work_struct *work) port_napi_disable(port); mutex_unlock(&port->port_lock); } + reset_sq_restart_flag(port); } /* Unregister old memory region */ @@ -2951,6 +3022,7 @@ static void ehea_rereg_mrs(struct work_struct *work) mutex_lock(&port->port_lock); port_napi_enable(port); ret = ehea_restart_qps(dev); + check_sqs(port); if (!ret) netif_wake_queue(dev); mutex_unlock(&port->port_lock); @@ -3663,7 +3735,7 @@ int __init ehea_module_init(void) if (ret) ehea_info("failed registering memory remove notifier"); - ret = crash_shutdown_register(&ehea_crash_handler); + ret = crash_shutdown_register(ehea_crash_handler); if (ret) ehea_info("failed registering crash handler"); @@ -3688,7 +3760,7 @@ out3: out2: unregister_memory_notifier(&ehea_mem_nb); unregister_reboot_notifier(&ehea_reboot_nb); - crash_shutdown_unregister(&ehea_crash_handler); + crash_shutdown_unregister(ehea_crash_handler); out: return ret; } @@ -3701,7 +3773,7 @@ static void __exit ehea_module_exit(void) driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities); ibmebus_unregister_driver(&ehea_driver); unregister_reboot_notifier(&ehea_reboot_nb); - ret = crash_shutdown_unregister(&ehea_crash_handler); + ret = crash_shutdown_unregister(ehea_crash_handler); if (ret) ehea_info("failed unregistering crash handler"); unregister_memory_notifier(&ehea_mem_nb); |