18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/drivers/net/ethernet/ibm/ehea/ehea_main.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * eHEA ethernet device driver for IBM eServer System p 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * (C) Copyright IBM Corp. 2006 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Authors: 108c2ecf20Sopenharmony_ci * Christoph Raisch <raisch@de.ibm.com> 118c2ecf20Sopenharmony_ci * Jan-Bernd Themann <themann@de.ibm.com> 128c2ecf20Sopenharmony_ci * Thomas Klein <tklein@de.ibm.com> 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/device.h> 188c2ecf20Sopenharmony_ci#include <linux/in.h> 198c2ecf20Sopenharmony_ci#include <linux/ip.h> 208c2ecf20Sopenharmony_ci#include <linux/tcp.h> 218c2ecf20Sopenharmony_ci#include <linux/udp.h> 228c2ecf20Sopenharmony_ci#include <linux/if.h> 238c2ecf20Sopenharmony_ci#include <linux/list.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 268c2ecf20Sopenharmony_ci#include <linux/notifier.h> 278c2ecf20Sopenharmony_ci#include <linux/reboot.h> 288c2ecf20Sopenharmony_ci#include <linux/memory.h> 298c2ecf20Sopenharmony_ci#include <asm/kexec.h> 308c2ecf20Sopenharmony_ci#include <linux/mutex.h> 318c2ecf20Sopenharmony_ci#include <linux/prefetch.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <net/ip.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "ehea.h" 368c2ecf20Sopenharmony_ci#include "ehea_qmr.h" 378c2ecf20Sopenharmony_ci#include "ehea_phyp.h" 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 418c2ecf20Sopenharmony_ciMODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>"); 428c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("IBM eServer HEA Driver"); 438c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic int msg_level = -1; 478c2ecf20Sopenharmony_cistatic int rq1_entries = EHEA_DEF_ENTRIES_RQ1; 488c2ecf20Sopenharmony_cistatic int rq2_entries = EHEA_DEF_ENTRIES_RQ2; 498c2ecf20Sopenharmony_cistatic int rq3_entries = EHEA_DEF_ENTRIES_RQ3; 508c2ecf20Sopenharmony_cistatic int sq_entries = EHEA_DEF_ENTRIES_SQ; 518c2ecf20Sopenharmony_cistatic int use_mcs = 1; 528c2ecf20Sopenharmony_cistatic int prop_carrier_state; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cimodule_param(msg_level, int, 0); 558c2ecf20Sopenharmony_cimodule_param(rq1_entries, int, 0); 568c2ecf20Sopenharmony_cimodule_param(rq2_entries, int, 0); 578c2ecf20Sopenharmony_cimodule_param(rq3_entries, int, 0); 588c2ecf20Sopenharmony_cimodule_param(sq_entries, int, 0); 598c2ecf20Sopenharmony_cimodule_param(prop_carrier_state, int, 0); 608c2ecf20Sopenharmony_cimodule_param(use_mcs, int, 0); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ciMODULE_PARM_DESC(msg_level, "msg_level"); 638c2ecf20Sopenharmony_ciMODULE_PARM_DESC(prop_carrier_state, "Propagate carrier state of physical " 648c2ecf20Sopenharmony_ci "port to stack. 1:yes, 0:no. Default = 0 "); 658c2ecf20Sopenharmony_ciMODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 " 668c2ecf20Sopenharmony_ci "[2^x - 1], x = [7..14]. Default = " 678c2ecf20Sopenharmony_ci __MODULE_STRING(EHEA_DEF_ENTRIES_RQ3) ")"); 688c2ecf20Sopenharmony_ciMODULE_PARM_DESC(rq2_entries, "Number of entries for Receive Queue 2 " 698c2ecf20Sopenharmony_ci "[2^x - 1], x = [7..14]. Default = " 708c2ecf20Sopenharmony_ci __MODULE_STRING(EHEA_DEF_ENTRIES_RQ2) ")"); 718c2ecf20Sopenharmony_ciMODULE_PARM_DESC(rq1_entries, "Number of entries for Receive Queue 1 " 728c2ecf20Sopenharmony_ci "[2^x - 1], x = [7..14]. Default = " 738c2ecf20Sopenharmony_ci __MODULE_STRING(EHEA_DEF_ENTRIES_RQ1) ")"); 748c2ecf20Sopenharmony_ciMODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue " 758c2ecf20Sopenharmony_ci "[2^x - 1], x = [7..14]. Default = " 768c2ecf20Sopenharmony_ci __MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")"); 778c2ecf20Sopenharmony_ciMODULE_PARM_DESC(use_mcs, " Multiple receive queues, 1: enable, 0: disable, " 788c2ecf20Sopenharmony_ci "Default = 1"); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic int port_name_cnt; 818c2ecf20Sopenharmony_cistatic LIST_HEAD(adapter_list); 828c2ecf20Sopenharmony_cistatic unsigned long ehea_driver_flags; 838c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(dlpar_mem_lock); 848c2ecf20Sopenharmony_cistatic struct ehea_fw_handle_array ehea_fw_handles; 858c2ecf20Sopenharmony_cistatic struct ehea_bcmc_reg_array ehea_bcmc_regs; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic int ehea_probe_adapter(struct platform_device *dev); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic int ehea_remove(struct platform_device *dev); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic const struct of_device_id ehea_module_device_table[] = { 938c2ecf20Sopenharmony_ci { 948c2ecf20Sopenharmony_ci .name = "lhea", 958c2ecf20Sopenharmony_ci .compatible = "IBM,lhea", 968c2ecf20Sopenharmony_ci }, 978c2ecf20Sopenharmony_ci { 988c2ecf20Sopenharmony_ci .type = "network", 998c2ecf20Sopenharmony_ci .compatible = "IBM,lhea-ethernet", 1008c2ecf20Sopenharmony_ci }, 1018c2ecf20Sopenharmony_ci {}, 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ehea_module_device_table); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic const struct of_device_id ehea_device_table[] = { 1068c2ecf20Sopenharmony_ci { 1078c2ecf20Sopenharmony_ci .name = "lhea", 1088c2ecf20Sopenharmony_ci .compatible = "IBM,lhea", 1098c2ecf20Sopenharmony_ci }, 1108c2ecf20Sopenharmony_ci {}, 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic struct platform_driver ehea_driver = { 1148c2ecf20Sopenharmony_ci .driver = { 1158c2ecf20Sopenharmony_ci .name = "ehea", 1168c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1178c2ecf20Sopenharmony_ci .of_match_table = ehea_device_table, 1188c2ecf20Sopenharmony_ci }, 1198c2ecf20Sopenharmony_ci .probe = ehea_probe_adapter, 1208c2ecf20Sopenharmony_ci .remove = ehea_remove, 1218c2ecf20Sopenharmony_ci}; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_civoid ehea_dump(void *adr, int len, char *msg) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci int x; 1268c2ecf20Sopenharmony_ci unsigned char *deb = adr; 1278c2ecf20Sopenharmony_ci for (x = 0; x < len; x += 16) { 1288c2ecf20Sopenharmony_ci pr_info("%s adr=%p ofs=%04x %016llx %016llx\n", 1298c2ecf20Sopenharmony_ci msg, deb, x, *((u64 *)&deb[0]), *((u64 *)&deb[8])); 1308c2ecf20Sopenharmony_ci deb += 16; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic void ehea_schedule_port_reset(struct ehea_port *port) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci if (!test_bit(__EHEA_DISABLE_PORT_RESET, &port->flags)) 1378c2ecf20Sopenharmony_ci schedule_work(&port->reset_task); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic void ehea_update_firmware_handles(void) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct ehea_fw_handle_entry *arr = NULL; 1438c2ecf20Sopenharmony_ci struct ehea_adapter *adapter; 1448c2ecf20Sopenharmony_ci int num_adapters = 0; 1458c2ecf20Sopenharmony_ci int num_ports = 0; 1468c2ecf20Sopenharmony_ci int num_portres = 0; 1478c2ecf20Sopenharmony_ci int i = 0; 1488c2ecf20Sopenharmony_ci int num_fw_handles, k, l; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* Determine number of handles */ 1518c2ecf20Sopenharmony_ci mutex_lock(&ehea_fw_handles.lock); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci list_for_each_entry(adapter, &adapter_list, list) { 1548c2ecf20Sopenharmony_ci num_adapters++; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci for (k = 0; k < EHEA_MAX_PORTS; k++) { 1578c2ecf20Sopenharmony_ci struct ehea_port *port = adapter->port[k]; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (!port || (port->state != EHEA_PORT_UP)) 1608c2ecf20Sopenharmony_ci continue; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci num_ports++; 1638c2ecf20Sopenharmony_ci num_portres += port->num_def_qps; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci num_fw_handles = num_adapters * EHEA_NUM_ADAPTER_FW_HANDLES + 1688c2ecf20Sopenharmony_ci num_ports * EHEA_NUM_PORT_FW_HANDLES + 1698c2ecf20Sopenharmony_ci num_portres * EHEA_NUM_PORTRES_FW_HANDLES; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if (num_fw_handles) { 1728c2ecf20Sopenharmony_ci arr = kcalloc(num_fw_handles, sizeof(*arr), GFP_KERNEL); 1738c2ecf20Sopenharmony_ci if (!arr) 1748c2ecf20Sopenharmony_ci goto out; /* Keep the existing array */ 1758c2ecf20Sopenharmony_ci } else 1768c2ecf20Sopenharmony_ci goto out_update; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci list_for_each_entry(adapter, &adapter_list, list) { 1798c2ecf20Sopenharmony_ci if (num_adapters == 0) 1808c2ecf20Sopenharmony_ci break; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci for (k = 0; k < EHEA_MAX_PORTS; k++) { 1838c2ecf20Sopenharmony_ci struct ehea_port *port = adapter->port[k]; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (!port || (port->state != EHEA_PORT_UP) || 1868c2ecf20Sopenharmony_ci (num_ports == 0)) 1878c2ecf20Sopenharmony_ci continue; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci for (l = 0; l < port->num_def_qps; l++) { 1908c2ecf20Sopenharmony_ci struct ehea_port_res *pr = &port->port_res[l]; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci arr[i].adh = adapter->handle; 1938c2ecf20Sopenharmony_ci arr[i++].fwh = pr->qp->fw_handle; 1948c2ecf20Sopenharmony_ci arr[i].adh = adapter->handle; 1958c2ecf20Sopenharmony_ci arr[i++].fwh = pr->send_cq->fw_handle; 1968c2ecf20Sopenharmony_ci arr[i].adh = adapter->handle; 1978c2ecf20Sopenharmony_ci arr[i++].fwh = pr->recv_cq->fw_handle; 1988c2ecf20Sopenharmony_ci arr[i].adh = adapter->handle; 1998c2ecf20Sopenharmony_ci arr[i++].fwh = pr->eq->fw_handle; 2008c2ecf20Sopenharmony_ci arr[i].adh = adapter->handle; 2018c2ecf20Sopenharmony_ci arr[i++].fwh = pr->send_mr.handle; 2028c2ecf20Sopenharmony_ci arr[i].adh = adapter->handle; 2038c2ecf20Sopenharmony_ci arr[i++].fwh = pr->recv_mr.handle; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci arr[i].adh = adapter->handle; 2068c2ecf20Sopenharmony_ci arr[i++].fwh = port->qp_eq->fw_handle; 2078c2ecf20Sopenharmony_ci num_ports--; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci arr[i].adh = adapter->handle; 2118c2ecf20Sopenharmony_ci arr[i++].fwh = adapter->neq->fw_handle; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (adapter->mr.handle) { 2148c2ecf20Sopenharmony_ci arr[i].adh = adapter->handle; 2158c2ecf20Sopenharmony_ci arr[i++].fwh = adapter->mr.handle; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci num_adapters--; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ciout_update: 2218c2ecf20Sopenharmony_ci kfree(ehea_fw_handles.arr); 2228c2ecf20Sopenharmony_ci ehea_fw_handles.arr = arr; 2238c2ecf20Sopenharmony_ci ehea_fw_handles.num_entries = i; 2248c2ecf20Sopenharmony_ciout: 2258c2ecf20Sopenharmony_ci mutex_unlock(&ehea_fw_handles.lock); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic void ehea_update_bcmc_registrations(void) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci unsigned long flags; 2318c2ecf20Sopenharmony_ci struct ehea_bcmc_reg_entry *arr = NULL; 2328c2ecf20Sopenharmony_ci struct ehea_adapter *adapter; 2338c2ecf20Sopenharmony_ci struct ehea_mc_list *mc_entry; 2348c2ecf20Sopenharmony_ci int num_registrations = 0; 2358c2ecf20Sopenharmony_ci int i = 0; 2368c2ecf20Sopenharmony_ci int k; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci spin_lock_irqsave(&ehea_bcmc_regs.lock, flags); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* Determine number of registrations */ 2418c2ecf20Sopenharmony_ci list_for_each_entry(adapter, &adapter_list, list) 2428c2ecf20Sopenharmony_ci for (k = 0; k < EHEA_MAX_PORTS; k++) { 2438c2ecf20Sopenharmony_ci struct ehea_port *port = adapter->port[k]; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (!port || (port->state != EHEA_PORT_UP)) 2468c2ecf20Sopenharmony_ci continue; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci num_registrations += 2; /* Broadcast registrations */ 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci list_for_each_entry(mc_entry, &port->mc_list->list,list) 2518c2ecf20Sopenharmony_ci num_registrations += 2; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (num_registrations) { 2558c2ecf20Sopenharmony_ci arr = kcalloc(num_registrations, sizeof(*arr), GFP_ATOMIC); 2568c2ecf20Sopenharmony_ci if (!arr) 2578c2ecf20Sopenharmony_ci goto out; /* Keep the existing array */ 2588c2ecf20Sopenharmony_ci } else 2598c2ecf20Sopenharmony_ci goto out_update; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci list_for_each_entry(adapter, &adapter_list, list) { 2628c2ecf20Sopenharmony_ci for (k = 0; k < EHEA_MAX_PORTS; k++) { 2638c2ecf20Sopenharmony_ci struct ehea_port *port = adapter->port[k]; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (!port || (port->state != EHEA_PORT_UP)) 2668c2ecf20Sopenharmony_ci continue; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (num_registrations == 0) 2698c2ecf20Sopenharmony_ci goto out_update; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci arr[i].adh = adapter->handle; 2728c2ecf20Sopenharmony_ci arr[i].port_id = port->logical_port_id; 2738c2ecf20Sopenharmony_ci arr[i].reg_type = EHEA_BCMC_BROADCAST | 2748c2ecf20Sopenharmony_ci EHEA_BCMC_UNTAGGED; 2758c2ecf20Sopenharmony_ci arr[i++].macaddr = port->mac_addr; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci arr[i].adh = adapter->handle; 2788c2ecf20Sopenharmony_ci arr[i].port_id = port->logical_port_id; 2798c2ecf20Sopenharmony_ci arr[i].reg_type = EHEA_BCMC_BROADCAST | 2808c2ecf20Sopenharmony_ci EHEA_BCMC_VLANID_ALL; 2818c2ecf20Sopenharmony_ci arr[i++].macaddr = port->mac_addr; 2828c2ecf20Sopenharmony_ci num_registrations -= 2; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci list_for_each_entry(mc_entry, 2858c2ecf20Sopenharmony_ci &port->mc_list->list, list) { 2868c2ecf20Sopenharmony_ci if (num_registrations == 0) 2878c2ecf20Sopenharmony_ci goto out_update; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci arr[i].adh = adapter->handle; 2908c2ecf20Sopenharmony_ci arr[i].port_id = port->logical_port_id; 2918c2ecf20Sopenharmony_ci arr[i].reg_type = EHEA_BCMC_MULTICAST | 2928c2ecf20Sopenharmony_ci EHEA_BCMC_UNTAGGED; 2938c2ecf20Sopenharmony_ci if (mc_entry->macaddr == 0) 2948c2ecf20Sopenharmony_ci arr[i].reg_type |= EHEA_BCMC_SCOPE_ALL; 2958c2ecf20Sopenharmony_ci arr[i++].macaddr = mc_entry->macaddr; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci arr[i].adh = adapter->handle; 2988c2ecf20Sopenharmony_ci arr[i].port_id = port->logical_port_id; 2998c2ecf20Sopenharmony_ci arr[i].reg_type = EHEA_BCMC_MULTICAST | 3008c2ecf20Sopenharmony_ci EHEA_BCMC_VLANID_ALL; 3018c2ecf20Sopenharmony_ci if (mc_entry->macaddr == 0) 3028c2ecf20Sopenharmony_ci arr[i].reg_type |= EHEA_BCMC_SCOPE_ALL; 3038c2ecf20Sopenharmony_ci arr[i++].macaddr = mc_entry->macaddr; 3048c2ecf20Sopenharmony_ci num_registrations -= 2; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ciout_update: 3108c2ecf20Sopenharmony_ci kfree(ehea_bcmc_regs.arr); 3118c2ecf20Sopenharmony_ci ehea_bcmc_regs.arr = arr; 3128c2ecf20Sopenharmony_ci ehea_bcmc_regs.num_entries = i; 3138c2ecf20Sopenharmony_ciout: 3148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ehea_bcmc_regs.lock, flags); 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic void ehea_get_stats64(struct net_device *dev, 3188c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *stats) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct ehea_port *port = netdev_priv(dev); 3218c2ecf20Sopenharmony_ci u64 rx_packets = 0, tx_packets = 0, rx_bytes = 0, tx_bytes = 0; 3228c2ecf20Sopenharmony_ci int i; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci for (i = 0; i < port->num_def_qps; i++) { 3258c2ecf20Sopenharmony_ci rx_packets += port->port_res[i].rx_packets; 3268c2ecf20Sopenharmony_ci rx_bytes += port->port_res[i].rx_bytes; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci for (i = 0; i < port->num_def_qps; i++) { 3308c2ecf20Sopenharmony_ci tx_packets += port->port_res[i].tx_packets; 3318c2ecf20Sopenharmony_ci tx_bytes += port->port_res[i].tx_bytes; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci stats->tx_packets = tx_packets; 3358c2ecf20Sopenharmony_ci stats->rx_bytes = rx_bytes; 3368c2ecf20Sopenharmony_ci stats->tx_bytes = tx_bytes; 3378c2ecf20Sopenharmony_ci stats->rx_packets = rx_packets; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci stats->multicast = port->stats.multicast; 3408c2ecf20Sopenharmony_ci stats->rx_errors = port->stats.rx_errors; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic void ehea_update_stats(struct work_struct *work) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct ehea_port *port = 3468c2ecf20Sopenharmony_ci container_of(work, struct ehea_port, stats_work.work); 3478c2ecf20Sopenharmony_ci struct net_device *dev = port->netdev; 3488c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *stats = &port->stats; 3498c2ecf20Sopenharmony_ci struct hcp_ehea_port_cb2 *cb2; 3508c2ecf20Sopenharmony_ci u64 hret; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci cb2 = (void *)get_zeroed_page(GFP_KERNEL); 3538c2ecf20Sopenharmony_ci if (!cb2) { 3548c2ecf20Sopenharmony_ci netdev_err(dev, "No mem for cb2. Some interface statistics were not updated\n"); 3558c2ecf20Sopenharmony_ci goto resched; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci hret = ehea_h_query_ehea_port(port->adapter->handle, 3598c2ecf20Sopenharmony_ci port->logical_port_id, 3608c2ecf20Sopenharmony_ci H_PORT_CB2, H_PORT_CB2_ALL, cb2); 3618c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 3628c2ecf20Sopenharmony_ci netdev_err(dev, "query_ehea_port failed\n"); 3638c2ecf20Sopenharmony_ci goto out_herr; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (netif_msg_hw(port)) 3678c2ecf20Sopenharmony_ci ehea_dump(cb2, sizeof(*cb2), "net_device_stats"); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci stats->multicast = cb2->rxmcp; 3708c2ecf20Sopenharmony_ci stats->rx_errors = cb2->rxuerr; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ciout_herr: 3738c2ecf20Sopenharmony_ci free_page((unsigned long)cb2); 3748c2ecf20Sopenharmony_ciresched: 3758c2ecf20Sopenharmony_ci schedule_delayed_work(&port->stats_work, 3768c2ecf20Sopenharmony_ci round_jiffies_relative(msecs_to_jiffies(1000))); 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci struct sk_buff **skb_arr_rq1 = pr->rq1_skba.arr; 3828c2ecf20Sopenharmony_ci struct net_device *dev = pr->port->netdev; 3838c2ecf20Sopenharmony_ci int max_index_mask = pr->rq1_skba.len - 1; 3848c2ecf20Sopenharmony_ci int fill_wqes = pr->rq1_skba.os_skbs + nr_of_wqes; 3858c2ecf20Sopenharmony_ci int adder = 0; 3868c2ecf20Sopenharmony_ci int i; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci pr->rq1_skba.os_skbs = 0; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) { 3918c2ecf20Sopenharmony_ci if (nr_of_wqes > 0) 3928c2ecf20Sopenharmony_ci pr->rq1_skba.index = index; 3938c2ecf20Sopenharmony_ci pr->rq1_skba.os_skbs = fill_wqes; 3948c2ecf20Sopenharmony_ci return; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci for (i = 0; i < fill_wqes; i++) { 3988c2ecf20Sopenharmony_ci if (!skb_arr_rq1[index]) { 3998c2ecf20Sopenharmony_ci skb_arr_rq1[index] = netdev_alloc_skb(dev, 4008c2ecf20Sopenharmony_ci EHEA_L_PKT_SIZE); 4018c2ecf20Sopenharmony_ci if (!skb_arr_rq1[index]) { 4028c2ecf20Sopenharmony_ci pr->rq1_skba.os_skbs = fill_wqes - i; 4038c2ecf20Sopenharmony_ci break; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci index--; 4078c2ecf20Sopenharmony_ci index &= max_index_mask; 4088c2ecf20Sopenharmony_ci adder++; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (adder == 0) 4128c2ecf20Sopenharmony_ci return; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci /* Ring doorbell */ 4158c2ecf20Sopenharmony_ci ehea_update_rq1a(pr->qp, adder); 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic void ehea_init_fill_rq1(struct ehea_port_res *pr, int nr_rq1a) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci struct sk_buff **skb_arr_rq1 = pr->rq1_skba.arr; 4218c2ecf20Sopenharmony_ci struct net_device *dev = pr->port->netdev; 4228c2ecf20Sopenharmony_ci int i; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if (nr_rq1a > pr->rq1_skba.len) { 4258c2ecf20Sopenharmony_ci netdev_err(dev, "NR_RQ1A bigger than skb array len\n"); 4268c2ecf20Sopenharmony_ci return; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci for (i = 0; i < nr_rq1a; i++) { 4308c2ecf20Sopenharmony_ci skb_arr_rq1[i] = netdev_alloc_skb(dev, EHEA_L_PKT_SIZE); 4318c2ecf20Sopenharmony_ci if (!skb_arr_rq1[i]) 4328c2ecf20Sopenharmony_ci break; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci /* Ring doorbell */ 4358c2ecf20Sopenharmony_ci ehea_update_rq1a(pr->qp, i - 1); 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic int ehea_refill_rq_def(struct ehea_port_res *pr, 4398c2ecf20Sopenharmony_ci struct ehea_q_skb_arr *q_skba, int rq_nr, 4408c2ecf20Sopenharmony_ci int num_wqes, int wqe_type, int packet_size) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct net_device *dev = pr->port->netdev; 4438c2ecf20Sopenharmony_ci struct ehea_qp *qp = pr->qp; 4448c2ecf20Sopenharmony_ci struct sk_buff **skb_arr = q_skba->arr; 4458c2ecf20Sopenharmony_ci struct ehea_rwqe *rwqe; 4468c2ecf20Sopenharmony_ci int i, index, max_index_mask, fill_wqes; 4478c2ecf20Sopenharmony_ci int adder = 0; 4488c2ecf20Sopenharmony_ci int ret = 0; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci fill_wqes = q_skba->os_skbs + num_wqes; 4518c2ecf20Sopenharmony_ci q_skba->os_skbs = 0; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) { 4548c2ecf20Sopenharmony_ci q_skba->os_skbs = fill_wqes; 4558c2ecf20Sopenharmony_ci return ret; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci index = q_skba->index; 4598c2ecf20Sopenharmony_ci max_index_mask = q_skba->len - 1; 4608c2ecf20Sopenharmony_ci for (i = 0; i < fill_wqes; i++) { 4618c2ecf20Sopenharmony_ci u64 tmp_addr; 4628c2ecf20Sopenharmony_ci struct sk_buff *skb; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci skb = netdev_alloc_skb_ip_align(dev, packet_size); 4658c2ecf20Sopenharmony_ci if (!skb) { 4668c2ecf20Sopenharmony_ci q_skba->os_skbs = fill_wqes - i; 4678c2ecf20Sopenharmony_ci if (q_skba->os_skbs == q_skba->len - 2) { 4688c2ecf20Sopenharmony_ci netdev_info(pr->port->netdev, 4698c2ecf20Sopenharmony_ci "rq%i ran dry - no mem for skb\n", 4708c2ecf20Sopenharmony_ci rq_nr); 4718c2ecf20Sopenharmony_ci ret = -ENOMEM; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci break; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci skb_arr[index] = skb; 4778c2ecf20Sopenharmony_ci tmp_addr = ehea_map_vaddr(skb->data); 4788c2ecf20Sopenharmony_ci if (tmp_addr == -1) { 4798c2ecf20Sopenharmony_ci dev_consume_skb_any(skb); 4808c2ecf20Sopenharmony_ci q_skba->os_skbs = fill_wqes - i; 4818c2ecf20Sopenharmony_ci ret = 0; 4828c2ecf20Sopenharmony_ci break; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci rwqe = ehea_get_next_rwqe(qp, rq_nr); 4868c2ecf20Sopenharmony_ci rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, wqe_type) 4878c2ecf20Sopenharmony_ci | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index); 4888c2ecf20Sopenharmony_ci rwqe->sg_list[0].l_key = pr->recv_mr.lkey; 4898c2ecf20Sopenharmony_ci rwqe->sg_list[0].vaddr = tmp_addr; 4908c2ecf20Sopenharmony_ci rwqe->sg_list[0].len = packet_size; 4918c2ecf20Sopenharmony_ci rwqe->data_segments = 1; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci index++; 4948c2ecf20Sopenharmony_ci index &= max_index_mask; 4958c2ecf20Sopenharmony_ci adder++; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci q_skba->index = index; 4998c2ecf20Sopenharmony_ci if (adder == 0) 5008c2ecf20Sopenharmony_ci goto out; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* Ring doorbell */ 5038c2ecf20Sopenharmony_ci iosync(); 5048c2ecf20Sopenharmony_ci if (rq_nr == 2) 5058c2ecf20Sopenharmony_ci ehea_update_rq2a(pr->qp, adder); 5068c2ecf20Sopenharmony_ci else 5078c2ecf20Sopenharmony_ci ehea_update_rq3a(pr->qp, adder); 5088c2ecf20Sopenharmony_ciout: 5098c2ecf20Sopenharmony_ci return ret; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic int ehea_refill_rq2(struct ehea_port_res *pr, int nr_of_wqes) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci return ehea_refill_rq_def(pr, &pr->rq2_skba, 2, 5168c2ecf20Sopenharmony_ci nr_of_wqes, EHEA_RWQE2_TYPE, 5178c2ecf20Sopenharmony_ci EHEA_RQ2_PKT_SIZE); 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic int ehea_refill_rq3(struct ehea_port_res *pr, int nr_of_wqes) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci return ehea_refill_rq_def(pr, &pr->rq3_skba, 3, 5248c2ecf20Sopenharmony_ci nr_of_wqes, EHEA_RWQE3_TYPE, 5258c2ecf20Sopenharmony_ci EHEA_MAX_PACKET_SIZE); 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic inline int ehea_check_cqe(struct ehea_cqe *cqe, int *rq_num) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci *rq_num = (cqe->type & EHEA_CQE_TYPE_RQ) >> 5; 5318c2ecf20Sopenharmony_ci if ((cqe->status & EHEA_CQE_STAT_ERR_MASK) == 0) 5328c2ecf20Sopenharmony_ci return 0; 5338c2ecf20Sopenharmony_ci if (((cqe->status & EHEA_CQE_STAT_ERR_TCP) != 0) && 5348c2ecf20Sopenharmony_ci (cqe->header_length == 0)) 5358c2ecf20Sopenharmony_ci return 0; 5368c2ecf20Sopenharmony_ci return -EINVAL; 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cistatic inline void ehea_fill_skb(struct net_device *dev, 5408c2ecf20Sopenharmony_ci struct sk_buff *skb, struct ehea_cqe *cqe, 5418c2ecf20Sopenharmony_ci struct ehea_port_res *pr) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci int length = cqe->num_bytes_transfered - 4; /*remove CRC */ 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci skb_put(skb, length); 5468c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* The packet was not an IPV4 packet so a complemented checksum was 5498c2ecf20Sopenharmony_ci calculated. The value is found in the Internet Checksum field. */ 5508c2ecf20Sopenharmony_ci if (cqe->status & EHEA_CQE_BLIND_CKSUM) { 5518c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_COMPLETE; 5528c2ecf20Sopenharmony_ci skb->csum = csum_unfold(~cqe->inet_checksum_value); 5538c2ecf20Sopenharmony_ci } else 5548c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci skb_record_rx_queue(skb, pr - &pr->port->port_res[0]); 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic inline struct sk_buff *get_skb_by_index(struct sk_buff **skb_array, 5608c2ecf20Sopenharmony_ci int arr_len, 5618c2ecf20Sopenharmony_ci struct ehea_cqe *cqe) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci int skb_index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id); 5648c2ecf20Sopenharmony_ci struct sk_buff *skb; 5658c2ecf20Sopenharmony_ci void *pref; 5668c2ecf20Sopenharmony_ci int x; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci x = skb_index + 1; 5698c2ecf20Sopenharmony_ci x &= (arr_len - 1); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci pref = skb_array[x]; 5728c2ecf20Sopenharmony_ci if (pref) { 5738c2ecf20Sopenharmony_ci prefetchw(pref); 5748c2ecf20Sopenharmony_ci prefetchw(pref + EHEA_CACHE_LINE); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci pref = (skb_array[x]->data); 5778c2ecf20Sopenharmony_ci prefetch(pref); 5788c2ecf20Sopenharmony_ci prefetch(pref + EHEA_CACHE_LINE); 5798c2ecf20Sopenharmony_ci prefetch(pref + EHEA_CACHE_LINE * 2); 5808c2ecf20Sopenharmony_ci prefetch(pref + EHEA_CACHE_LINE * 3); 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci skb = skb_array[skb_index]; 5848c2ecf20Sopenharmony_ci skb_array[skb_index] = NULL; 5858c2ecf20Sopenharmony_ci return skb; 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic inline struct sk_buff *get_skb_by_index_ll(struct sk_buff **skb_array, 5898c2ecf20Sopenharmony_ci int arr_len, int wqe_index) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci struct sk_buff *skb; 5928c2ecf20Sopenharmony_ci void *pref; 5938c2ecf20Sopenharmony_ci int x; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci x = wqe_index + 1; 5968c2ecf20Sopenharmony_ci x &= (arr_len - 1); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci pref = skb_array[x]; 5998c2ecf20Sopenharmony_ci if (pref) { 6008c2ecf20Sopenharmony_ci prefetchw(pref); 6018c2ecf20Sopenharmony_ci prefetchw(pref + EHEA_CACHE_LINE); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci pref = (skb_array[x]->data); 6048c2ecf20Sopenharmony_ci prefetchw(pref); 6058c2ecf20Sopenharmony_ci prefetchw(pref + EHEA_CACHE_LINE); 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci skb = skb_array[wqe_index]; 6098c2ecf20Sopenharmony_ci skb_array[wqe_index] = NULL; 6108c2ecf20Sopenharmony_ci return skb; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic int ehea_treat_poll_error(struct ehea_port_res *pr, int rq, 6148c2ecf20Sopenharmony_ci struct ehea_cqe *cqe, int *processed_rq2, 6158c2ecf20Sopenharmony_ci int *processed_rq3) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci struct sk_buff *skb; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (cqe->status & EHEA_CQE_STAT_ERR_TCP) 6208c2ecf20Sopenharmony_ci pr->p_stats.err_tcp_cksum++; 6218c2ecf20Sopenharmony_ci if (cqe->status & EHEA_CQE_STAT_ERR_IP) 6228c2ecf20Sopenharmony_ci pr->p_stats.err_ip_cksum++; 6238c2ecf20Sopenharmony_ci if (cqe->status & EHEA_CQE_STAT_ERR_CRC) 6248c2ecf20Sopenharmony_ci pr->p_stats.err_frame_crc++; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (rq == 2) { 6278c2ecf20Sopenharmony_ci *processed_rq2 += 1; 6288c2ecf20Sopenharmony_ci skb = get_skb_by_index(pr->rq2_skba.arr, pr->rq2_skba.len, cqe); 6298c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 6308c2ecf20Sopenharmony_ci } else if (rq == 3) { 6318c2ecf20Sopenharmony_ci *processed_rq3 += 1; 6328c2ecf20Sopenharmony_ci skb = get_skb_by_index(pr->rq3_skba.arr, pr->rq3_skba.len, cqe); 6338c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci if (cqe->status & EHEA_CQE_STAT_FAT_ERR_MASK) { 6378c2ecf20Sopenharmony_ci if (netif_msg_rx_err(pr->port)) { 6388c2ecf20Sopenharmony_ci pr_err("Critical receive error for QP %d. Resetting port.\n", 6398c2ecf20Sopenharmony_ci pr->qp->init_attr.qp_nr); 6408c2ecf20Sopenharmony_ci ehea_dump(cqe, sizeof(*cqe), "CQE"); 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci ehea_schedule_port_reset(pr->port); 6438c2ecf20Sopenharmony_ci return 1; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci return 0; 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_cistatic int ehea_proc_rwqes(struct net_device *dev, 6508c2ecf20Sopenharmony_ci struct ehea_port_res *pr, 6518c2ecf20Sopenharmony_ci int budget) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci struct ehea_port *port = pr->port; 6548c2ecf20Sopenharmony_ci struct ehea_qp *qp = pr->qp; 6558c2ecf20Sopenharmony_ci struct ehea_cqe *cqe; 6568c2ecf20Sopenharmony_ci struct sk_buff *skb; 6578c2ecf20Sopenharmony_ci struct sk_buff **skb_arr_rq1 = pr->rq1_skba.arr; 6588c2ecf20Sopenharmony_ci struct sk_buff **skb_arr_rq2 = pr->rq2_skba.arr; 6598c2ecf20Sopenharmony_ci struct sk_buff **skb_arr_rq3 = pr->rq3_skba.arr; 6608c2ecf20Sopenharmony_ci int skb_arr_rq1_len = pr->rq1_skba.len; 6618c2ecf20Sopenharmony_ci int skb_arr_rq2_len = pr->rq2_skba.len; 6628c2ecf20Sopenharmony_ci int skb_arr_rq3_len = pr->rq3_skba.len; 6638c2ecf20Sopenharmony_ci int processed, processed_rq1, processed_rq2, processed_rq3; 6648c2ecf20Sopenharmony_ci u64 processed_bytes = 0; 6658c2ecf20Sopenharmony_ci int wqe_index, last_wqe_index, rq, port_reset; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci processed = processed_rq1 = processed_rq2 = processed_rq3 = 0; 6688c2ecf20Sopenharmony_ci last_wqe_index = 0; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci cqe = ehea_poll_rq1(qp, &wqe_index); 6718c2ecf20Sopenharmony_ci while ((processed < budget) && cqe) { 6728c2ecf20Sopenharmony_ci ehea_inc_rq1(qp); 6738c2ecf20Sopenharmony_ci processed_rq1++; 6748c2ecf20Sopenharmony_ci processed++; 6758c2ecf20Sopenharmony_ci if (netif_msg_rx_status(port)) 6768c2ecf20Sopenharmony_ci ehea_dump(cqe, sizeof(*cqe), "CQE"); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci last_wqe_index = wqe_index; 6798c2ecf20Sopenharmony_ci rmb(); 6808c2ecf20Sopenharmony_ci if (!ehea_check_cqe(cqe, &rq)) { 6818c2ecf20Sopenharmony_ci if (rq == 1) { 6828c2ecf20Sopenharmony_ci /* LL RQ1 */ 6838c2ecf20Sopenharmony_ci skb = get_skb_by_index_ll(skb_arr_rq1, 6848c2ecf20Sopenharmony_ci skb_arr_rq1_len, 6858c2ecf20Sopenharmony_ci wqe_index); 6868c2ecf20Sopenharmony_ci if (unlikely(!skb)) { 6878c2ecf20Sopenharmony_ci netif_info(port, rx_err, dev, 6888c2ecf20Sopenharmony_ci "LL rq1: skb=NULL\n"); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(dev, 6918c2ecf20Sopenharmony_ci EHEA_L_PKT_SIZE); 6928c2ecf20Sopenharmony_ci if (!skb) 6938c2ecf20Sopenharmony_ci break; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci skb_copy_to_linear_data(skb, ((char *)cqe) + 64, 6968c2ecf20Sopenharmony_ci cqe->num_bytes_transfered - 4); 6978c2ecf20Sopenharmony_ci ehea_fill_skb(dev, skb, cqe, pr); 6988c2ecf20Sopenharmony_ci } else if (rq == 2) { 6998c2ecf20Sopenharmony_ci /* RQ2 */ 7008c2ecf20Sopenharmony_ci skb = get_skb_by_index(skb_arr_rq2, 7018c2ecf20Sopenharmony_ci skb_arr_rq2_len, cqe); 7028c2ecf20Sopenharmony_ci if (unlikely(!skb)) { 7038c2ecf20Sopenharmony_ci netif_err(port, rx_err, dev, 7048c2ecf20Sopenharmony_ci "rq2: skb=NULL\n"); 7058c2ecf20Sopenharmony_ci break; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci ehea_fill_skb(dev, skb, cqe, pr); 7088c2ecf20Sopenharmony_ci processed_rq2++; 7098c2ecf20Sopenharmony_ci } else { 7108c2ecf20Sopenharmony_ci /* RQ3 */ 7118c2ecf20Sopenharmony_ci skb = get_skb_by_index(skb_arr_rq3, 7128c2ecf20Sopenharmony_ci skb_arr_rq3_len, cqe); 7138c2ecf20Sopenharmony_ci if (unlikely(!skb)) { 7148c2ecf20Sopenharmony_ci netif_err(port, rx_err, dev, 7158c2ecf20Sopenharmony_ci "rq3: skb=NULL\n"); 7168c2ecf20Sopenharmony_ci break; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci ehea_fill_skb(dev, skb, cqe, pr); 7198c2ecf20Sopenharmony_ci processed_rq3++; 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci processed_bytes += skb->len; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if (cqe->status & EHEA_CQE_VLAN_TAG_XTRACT) 7258c2ecf20Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), 7268c2ecf20Sopenharmony_ci cqe->vlan_tag); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci napi_gro_receive(&pr->napi, skb); 7298c2ecf20Sopenharmony_ci } else { 7308c2ecf20Sopenharmony_ci pr->p_stats.poll_receive_errors++; 7318c2ecf20Sopenharmony_ci port_reset = ehea_treat_poll_error(pr, rq, cqe, 7328c2ecf20Sopenharmony_ci &processed_rq2, 7338c2ecf20Sopenharmony_ci &processed_rq3); 7348c2ecf20Sopenharmony_ci if (port_reset) 7358c2ecf20Sopenharmony_ci break; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci cqe = ehea_poll_rq1(qp, &wqe_index); 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci pr->rx_packets += processed; 7418c2ecf20Sopenharmony_ci pr->rx_bytes += processed_bytes; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci ehea_refill_rq1(pr, last_wqe_index, processed_rq1); 7448c2ecf20Sopenharmony_ci ehea_refill_rq2(pr, processed_rq2); 7458c2ecf20Sopenharmony_ci ehea_refill_rq3(pr, processed_rq3); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci return processed; 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci#define SWQE_RESTART_CHECK 0xdeadbeaff00d0000ull 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_cistatic void reset_sq_restart_flag(struct ehea_port *port) 7538c2ecf20Sopenharmony_ci{ 7548c2ecf20Sopenharmony_ci int i; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci for (i = 0; i < port->num_def_qps; i++) { 7578c2ecf20Sopenharmony_ci struct ehea_port_res *pr = &port->port_res[i]; 7588c2ecf20Sopenharmony_ci pr->sq_restart_flag = 0; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci wake_up(&port->restart_wq); 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_cistatic void check_sqs(struct ehea_port *port) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci struct ehea_swqe *swqe; 7668c2ecf20Sopenharmony_ci int swqe_index; 7678c2ecf20Sopenharmony_ci int i; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci for (i = 0; i < port->num_def_qps; i++) { 7708c2ecf20Sopenharmony_ci struct ehea_port_res *pr = &port->port_res[i]; 7718c2ecf20Sopenharmony_ci int ret; 7728c2ecf20Sopenharmony_ci swqe = ehea_get_swqe(pr->qp, &swqe_index); 7738c2ecf20Sopenharmony_ci memset(swqe, 0, SWQE_HEADER_SIZE); 7748c2ecf20Sopenharmony_ci atomic_dec(&pr->swqe_avail); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci swqe->tx_control |= EHEA_SWQE_PURGE; 7778c2ecf20Sopenharmony_ci swqe->wr_id = SWQE_RESTART_CHECK; 7788c2ecf20Sopenharmony_ci swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION; 7798c2ecf20Sopenharmony_ci swqe->tx_control |= EHEA_SWQE_IMM_DATA_PRESENT; 7808c2ecf20Sopenharmony_ci swqe->immediate_data_length = 80; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci ehea_post_swqe(pr->qp, swqe); 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci ret = wait_event_timeout(port->restart_wq, 7858c2ecf20Sopenharmony_ci pr->sq_restart_flag == 0, 7868c2ecf20Sopenharmony_ci msecs_to_jiffies(100)); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci if (!ret) { 7898c2ecf20Sopenharmony_ci pr_err("HW/SW queues out of sync\n"); 7908c2ecf20Sopenharmony_ci ehea_schedule_port_reset(pr->port); 7918c2ecf20Sopenharmony_ci return; 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci struct sk_buff *skb; 8008c2ecf20Sopenharmony_ci struct ehea_cq *send_cq = pr->send_cq; 8018c2ecf20Sopenharmony_ci struct ehea_cqe *cqe; 8028c2ecf20Sopenharmony_ci int quota = my_quota; 8038c2ecf20Sopenharmony_ci int cqe_counter = 0; 8048c2ecf20Sopenharmony_ci int swqe_av = 0; 8058c2ecf20Sopenharmony_ci int index; 8068c2ecf20Sopenharmony_ci struct netdev_queue *txq = netdev_get_tx_queue(pr->port->netdev, 8078c2ecf20Sopenharmony_ci pr - &pr->port->port_res[0]); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci cqe = ehea_poll_cq(send_cq); 8108c2ecf20Sopenharmony_ci while (cqe && (quota > 0)) { 8118c2ecf20Sopenharmony_ci ehea_inc_cq(send_cq); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci cqe_counter++; 8148c2ecf20Sopenharmony_ci rmb(); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (cqe->wr_id == SWQE_RESTART_CHECK) { 8178c2ecf20Sopenharmony_ci pr->sq_restart_flag = 1; 8188c2ecf20Sopenharmony_ci swqe_av++; 8198c2ecf20Sopenharmony_ci break; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci if (cqe->status & EHEA_CQE_STAT_ERR_MASK) { 8238c2ecf20Sopenharmony_ci pr_err("Bad send completion status=0x%04X\n", 8248c2ecf20Sopenharmony_ci cqe->status); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (netif_msg_tx_err(pr->port)) 8278c2ecf20Sopenharmony_ci ehea_dump(cqe, sizeof(*cqe), "Send CQE"); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci if (cqe->status & EHEA_CQE_STAT_RESET_MASK) { 8308c2ecf20Sopenharmony_ci pr_err("Resetting port\n"); 8318c2ecf20Sopenharmony_ci ehea_schedule_port_reset(pr->port); 8328c2ecf20Sopenharmony_ci break; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci if (netif_msg_tx_done(pr->port)) 8378c2ecf20Sopenharmony_ci ehea_dump(cqe, sizeof(*cqe), "CQE"); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci if (likely(EHEA_BMASK_GET(EHEA_WR_ID_TYPE, cqe->wr_id) 8408c2ecf20Sopenharmony_ci == EHEA_SWQE2_TYPE)) { 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id); 8438c2ecf20Sopenharmony_ci skb = pr->sq_skba.arr[index]; 8448c2ecf20Sopenharmony_ci dev_consume_skb_any(skb); 8458c2ecf20Sopenharmony_ci pr->sq_skba.arr[index] = NULL; 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci swqe_av += EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id); 8498c2ecf20Sopenharmony_ci quota--; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci cqe = ehea_poll_cq(send_cq); 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci ehea_update_feca(send_cq, cqe_counter); 8558c2ecf20Sopenharmony_ci atomic_add(swqe_av, &pr->swqe_avail); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci if (unlikely(netif_tx_queue_stopped(txq) && 8588c2ecf20Sopenharmony_ci (atomic_read(&pr->swqe_avail) >= pr->swqe_refill_th))) { 8598c2ecf20Sopenharmony_ci __netif_tx_lock(txq, smp_processor_id()); 8608c2ecf20Sopenharmony_ci if (netif_tx_queue_stopped(txq) && 8618c2ecf20Sopenharmony_ci (atomic_read(&pr->swqe_avail) >= pr->swqe_refill_th)) 8628c2ecf20Sopenharmony_ci netif_tx_wake_queue(txq); 8638c2ecf20Sopenharmony_ci __netif_tx_unlock(txq); 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci wake_up(&pr->port->swqe_avail_wq); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci return cqe; 8698c2ecf20Sopenharmony_ci} 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci#define EHEA_POLL_MAX_CQES 65535 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_cistatic int ehea_poll(struct napi_struct *napi, int budget) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci struct ehea_port_res *pr = container_of(napi, struct ehea_port_res, 8768c2ecf20Sopenharmony_ci napi); 8778c2ecf20Sopenharmony_ci struct net_device *dev = pr->port->netdev; 8788c2ecf20Sopenharmony_ci struct ehea_cqe *cqe; 8798c2ecf20Sopenharmony_ci struct ehea_cqe *cqe_skb = NULL; 8808c2ecf20Sopenharmony_ci int wqe_index; 8818c2ecf20Sopenharmony_ci int rx = 0; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES); 8848c2ecf20Sopenharmony_ci rx += ehea_proc_rwqes(dev, pr, budget - rx); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci while (rx != budget) { 8878c2ecf20Sopenharmony_ci napi_complete(napi); 8888c2ecf20Sopenharmony_ci ehea_reset_cq_ep(pr->recv_cq); 8898c2ecf20Sopenharmony_ci ehea_reset_cq_ep(pr->send_cq); 8908c2ecf20Sopenharmony_ci ehea_reset_cq_n1(pr->recv_cq); 8918c2ecf20Sopenharmony_ci ehea_reset_cq_n1(pr->send_cq); 8928c2ecf20Sopenharmony_ci rmb(); 8938c2ecf20Sopenharmony_ci cqe = ehea_poll_rq1(pr->qp, &wqe_index); 8948c2ecf20Sopenharmony_ci cqe_skb = ehea_poll_cq(pr->send_cq); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci if (!cqe && !cqe_skb) 8978c2ecf20Sopenharmony_ci return rx; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci if (!napi_reschedule(napi)) 9008c2ecf20Sopenharmony_ci return rx; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES); 9038c2ecf20Sopenharmony_ci rx += ehea_proc_rwqes(dev, pr, budget - rx); 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci return rx; 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_cistatic irqreturn_t ehea_recv_irq_handler(int irq, void *param) 9108c2ecf20Sopenharmony_ci{ 9118c2ecf20Sopenharmony_ci struct ehea_port_res *pr = param; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci napi_schedule(&pr->napi); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci return IRQ_HANDLED; 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_cistatic irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param) 9198c2ecf20Sopenharmony_ci{ 9208c2ecf20Sopenharmony_ci struct ehea_port *port = param; 9218c2ecf20Sopenharmony_ci struct ehea_eqe *eqe; 9228c2ecf20Sopenharmony_ci struct ehea_qp *qp; 9238c2ecf20Sopenharmony_ci u32 qp_token; 9248c2ecf20Sopenharmony_ci u64 resource_type, aer, aerr; 9258c2ecf20Sopenharmony_ci int reset_port = 0; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci eqe = ehea_poll_eq(port->qp_eq); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci while (eqe) { 9308c2ecf20Sopenharmony_ci qp_token = EHEA_BMASK_GET(EHEA_EQE_QP_TOKEN, eqe->entry); 9318c2ecf20Sopenharmony_ci pr_err("QP aff_err: entry=0x%llx, token=0x%x\n", 9328c2ecf20Sopenharmony_ci eqe->entry, qp_token); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci qp = port->port_res[qp_token].qp; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci resource_type = ehea_error_data(port->adapter, qp->fw_handle, 9378c2ecf20Sopenharmony_ci &aer, &aerr); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (resource_type == EHEA_AER_RESTYPE_QP) { 9408c2ecf20Sopenharmony_ci if ((aer & EHEA_AER_RESET_MASK) || 9418c2ecf20Sopenharmony_ci (aerr & EHEA_AERR_RESET_MASK)) 9428c2ecf20Sopenharmony_ci reset_port = 1; 9438c2ecf20Sopenharmony_ci } else 9448c2ecf20Sopenharmony_ci reset_port = 1; /* Reset in case of CQ or EQ error */ 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci eqe = ehea_poll_eq(port->qp_eq); 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if (reset_port) { 9508c2ecf20Sopenharmony_ci pr_err("Resetting port\n"); 9518c2ecf20Sopenharmony_ci ehea_schedule_port_reset(port); 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci return IRQ_HANDLED; 9558c2ecf20Sopenharmony_ci} 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_cistatic struct ehea_port *ehea_get_port(struct ehea_adapter *adapter, 9588c2ecf20Sopenharmony_ci int logical_port) 9598c2ecf20Sopenharmony_ci{ 9608c2ecf20Sopenharmony_ci int i; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci for (i = 0; i < EHEA_MAX_PORTS; i++) 9638c2ecf20Sopenharmony_ci if (adapter->port[i]) 9648c2ecf20Sopenharmony_ci if (adapter->port[i]->logical_port_id == logical_port) 9658c2ecf20Sopenharmony_ci return adapter->port[i]; 9668c2ecf20Sopenharmony_ci return NULL; 9678c2ecf20Sopenharmony_ci} 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ciint ehea_sense_port_attr(struct ehea_port *port) 9708c2ecf20Sopenharmony_ci{ 9718c2ecf20Sopenharmony_ci int ret; 9728c2ecf20Sopenharmony_ci u64 hret; 9738c2ecf20Sopenharmony_ci struct hcp_ehea_port_cb0 *cb0; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci /* may be called via ehea_neq_tasklet() */ 9768c2ecf20Sopenharmony_ci cb0 = (void *)get_zeroed_page(GFP_ATOMIC); 9778c2ecf20Sopenharmony_ci if (!cb0) { 9788c2ecf20Sopenharmony_ci pr_err("no mem for cb0\n"); 9798c2ecf20Sopenharmony_ci ret = -ENOMEM; 9808c2ecf20Sopenharmony_ci goto out; 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci hret = ehea_h_query_ehea_port(port->adapter->handle, 9848c2ecf20Sopenharmony_ci port->logical_port_id, H_PORT_CB0, 9858c2ecf20Sopenharmony_ci EHEA_BMASK_SET(H_PORT_CB0_ALL, 0xFFFF), 9868c2ecf20Sopenharmony_ci cb0); 9878c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 9888c2ecf20Sopenharmony_ci ret = -EIO; 9898c2ecf20Sopenharmony_ci goto out_free; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci /* MAC address */ 9938c2ecf20Sopenharmony_ci port->mac_addr = cb0->port_mac_addr << 16; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci if (!is_valid_ether_addr((u8 *)&port->mac_addr)) { 9968c2ecf20Sopenharmony_ci ret = -EADDRNOTAVAIL; 9978c2ecf20Sopenharmony_ci goto out_free; 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci /* Port speed */ 10018c2ecf20Sopenharmony_ci switch (cb0->port_speed) { 10028c2ecf20Sopenharmony_ci case H_SPEED_10M_H: 10038c2ecf20Sopenharmony_ci port->port_speed = EHEA_SPEED_10M; 10048c2ecf20Sopenharmony_ci port->full_duplex = 0; 10058c2ecf20Sopenharmony_ci break; 10068c2ecf20Sopenharmony_ci case H_SPEED_10M_F: 10078c2ecf20Sopenharmony_ci port->port_speed = EHEA_SPEED_10M; 10088c2ecf20Sopenharmony_ci port->full_duplex = 1; 10098c2ecf20Sopenharmony_ci break; 10108c2ecf20Sopenharmony_ci case H_SPEED_100M_H: 10118c2ecf20Sopenharmony_ci port->port_speed = EHEA_SPEED_100M; 10128c2ecf20Sopenharmony_ci port->full_duplex = 0; 10138c2ecf20Sopenharmony_ci break; 10148c2ecf20Sopenharmony_ci case H_SPEED_100M_F: 10158c2ecf20Sopenharmony_ci port->port_speed = EHEA_SPEED_100M; 10168c2ecf20Sopenharmony_ci port->full_duplex = 1; 10178c2ecf20Sopenharmony_ci break; 10188c2ecf20Sopenharmony_ci case H_SPEED_1G_F: 10198c2ecf20Sopenharmony_ci port->port_speed = EHEA_SPEED_1G; 10208c2ecf20Sopenharmony_ci port->full_duplex = 1; 10218c2ecf20Sopenharmony_ci break; 10228c2ecf20Sopenharmony_ci case H_SPEED_10G_F: 10238c2ecf20Sopenharmony_ci port->port_speed = EHEA_SPEED_10G; 10248c2ecf20Sopenharmony_ci port->full_duplex = 1; 10258c2ecf20Sopenharmony_ci break; 10268c2ecf20Sopenharmony_ci default: 10278c2ecf20Sopenharmony_ci port->port_speed = 0; 10288c2ecf20Sopenharmony_ci port->full_duplex = 0; 10298c2ecf20Sopenharmony_ci break; 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci port->autoneg = 1; 10338c2ecf20Sopenharmony_ci port->num_mcs = cb0->num_default_qps; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci /* Number of default QPs */ 10368c2ecf20Sopenharmony_ci if (use_mcs) 10378c2ecf20Sopenharmony_ci port->num_def_qps = cb0->num_default_qps; 10388c2ecf20Sopenharmony_ci else 10398c2ecf20Sopenharmony_ci port->num_def_qps = 1; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci if (!port->num_def_qps) { 10428c2ecf20Sopenharmony_ci ret = -EINVAL; 10438c2ecf20Sopenharmony_ci goto out_free; 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci ret = 0; 10478c2ecf20Sopenharmony_ciout_free: 10488c2ecf20Sopenharmony_ci if (ret || netif_msg_probe(port)) 10498c2ecf20Sopenharmony_ci ehea_dump(cb0, sizeof(*cb0), "ehea_sense_port_attr"); 10508c2ecf20Sopenharmony_ci free_page((unsigned long)cb0); 10518c2ecf20Sopenharmony_ciout: 10528c2ecf20Sopenharmony_ci return ret; 10538c2ecf20Sopenharmony_ci} 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ciint ehea_set_portspeed(struct ehea_port *port, u32 port_speed) 10568c2ecf20Sopenharmony_ci{ 10578c2ecf20Sopenharmony_ci struct hcp_ehea_port_cb4 *cb4; 10588c2ecf20Sopenharmony_ci u64 hret; 10598c2ecf20Sopenharmony_ci int ret = 0; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci cb4 = (void *)get_zeroed_page(GFP_KERNEL); 10628c2ecf20Sopenharmony_ci if (!cb4) { 10638c2ecf20Sopenharmony_ci pr_err("no mem for cb4\n"); 10648c2ecf20Sopenharmony_ci ret = -ENOMEM; 10658c2ecf20Sopenharmony_ci goto out; 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci cb4->port_speed = port_speed; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci netif_carrier_off(port->netdev); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci hret = ehea_h_modify_ehea_port(port->adapter->handle, 10738c2ecf20Sopenharmony_ci port->logical_port_id, 10748c2ecf20Sopenharmony_ci H_PORT_CB4, H_PORT_CB4_SPEED, cb4); 10758c2ecf20Sopenharmony_ci if (hret == H_SUCCESS) { 10768c2ecf20Sopenharmony_ci port->autoneg = port_speed == EHEA_SPEED_AUTONEG ? 1 : 0; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci hret = ehea_h_query_ehea_port(port->adapter->handle, 10798c2ecf20Sopenharmony_ci port->logical_port_id, 10808c2ecf20Sopenharmony_ci H_PORT_CB4, H_PORT_CB4_SPEED, 10818c2ecf20Sopenharmony_ci cb4); 10828c2ecf20Sopenharmony_ci if (hret == H_SUCCESS) { 10838c2ecf20Sopenharmony_ci switch (cb4->port_speed) { 10848c2ecf20Sopenharmony_ci case H_SPEED_10M_H: 10858c2ecf20Sopenharmony_ci port->port_speed = EHEA_SPEED_10M; 10868c2ecf20Sopenharmony_ci port->full_duplex = 0; 10878c2ecf20Sopenharmony_ci break; 10888c2ecf20Sopenharmony_ci case H_SPEED_10M_F: 10898c2ecf20Sopenharmony_ci port->port_speed = EHEA_SPEED_10M; 10908c2ecf20Sopenharmony_ci port->full_duplex = 1; 10918c2ecf20Sopenharmony_ci break; 10928c2ecf20Sopenharmony_ci case H_SPEED_100M_H: 10938c2ecf20Sopenharmony_ci port->port_speed = EHEA_SPEED_100M; 10948c2ecf20Sopenharmony_ci port->full_duplex = 0; 10958c2ecf20Sopenharmony_ci break; 10968c2ecf20Sopenharmony_ci case H_SPEED_100M_F: 10978c2ecf20Sopenharmony_ci port->port_speed = EHEA_SPEED_100M; 10988c2ecf20Sopenharmony_ci port->full_duplex = 1; 10998c2ecf20Sopenharmony_ci break; 11008c2ecf20Sopenharmony_ci case H_SPEED_1G_F: 11018c2ecf20Sopenharmony_ci port->port_speed = EHEA_SPEED_1G; 11028c2ecf20Sopenharmony_ci port->full_duplex = 1; 11038c2ecf20Sopenharmony_ci break; 11048c2ecf20Sopenharmony_ci case H_SPEED_10G_F: 11058c2ecf20Sopenharmony_ci port->port_speed = EHEA_SPEED_10G; 11068c2ecf20Sopenharmony_ci port->full_duplex = 1; 11078c2ecf20Sopenharmony_ci break; 11088c2ecf20Sopenharmony_ci default: 11098c2ecf20Sopenharmony_ci port->port_speed = 0; 11108c2ecf20Sopenharmony_ci port->full_duplex = 0; 11118c2ecf20Sopenharmony_ci break; 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci } else { 11148c2ecf20Sopenharmony_ci pr_err("Failed sensing port speed\n"); 11158c2ecf20Sopenharmony_ci ret = -EIO; 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci } else { 11188c2ecf20Sopenharmony_ci if (hret == H_AUTHORITY) { 11198c2ecf20Sopenharmony_ci pr_info("Hypervisor denied setting port speed\n"); 11208c2ecf20Sopenharmony_ci ret = -EPERM; 11218c2ecf20Sopenharmony_ci } else { 11228c2ecf20Sopenharmony_ci ret = -EIO; 11238c2ecf20Sopenharmony_ci pr_err("Failed setting port speed\n"); 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci if (!prop_carrier_state || (port->phy_link == EHEA_PHY_LINK_UP)) 11278c2ecf20Sopenharmony_ci netif_carrier_on(port->netdev); 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci free_page((unsigned long)cb4); 11308c2ecf20Sopenharmony_ciout: 11318c2ecf20Sopenharmony_ci return ret; 11328c2ecf20Sopenharmony_ci} 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_cistatic void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe) 11358c2ecf20Sopenharmony_ci{ 11368c2ecf20Sopenharmony_ci int ret; 11378c2ecf20Sopenharmony_ci u8 ec; 11388c2ecf20Sopenharmony_ci u8 portnum; 11398c2ecf20Sopenharmony_ci struct ehea_port *port; 11408c2ecf20Sopenharmony_ci struct net_device *dev; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci ec = EHEA_BMASK_GET(NEQE_EVENT_CODE, eqe); 11438c2ecf20Sopenharmony_ci portnum = EHEA_BMASK_GET(NEQE_PORTNUM, eqe); 11448c2ecf20Sopenharmony_ci port = ehea_get_port(adapter, portnum); 11458c2ecf20Sopenharmony_ci if (!port) { 11468c2ecf20Sopenharmony_ci netdev_err(NULL, "unknown portnum %x\n", portnum); 11478c2ecf20Sopenharmony_ci return; 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci dev = port->netdev; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci switch (ec) { 11528c2ecf20Sopenharmony_ci case EHEA_EC_PORTSTATE_CHG: /* port state change */ 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci if (EHEA_BMASK_GET(NEQE_PORT_UP, eqe)) { 11558c2ecf20Sopenharmony_ci if (!netif_carrier_ok(dev)) { 11568c2ecf20Sopenharmony_ci ret = ehea_sense_port_attr(port); 11578c2ecf20Sopenharmony_ci if (ret) { 11588c2ecf20Sopenharmony_ci netdev_err(dev, "failed resensing port attributes\n"); 11598c2ecf20Sopenharmony_ci break; 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci netif_info(port, link, dev, 11638c2ecf20Sopenharmony_ci "Logical port up: %dMbps %s Duplex\n", 11648c2ecf20Sopenharmony_ci port->port_speed, 11658c2ecf20Sopenharmony_ci port->full_duplex == 1 ? 11668c2ecf20Sopenharmony_ci "Full" : "Half"); 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci netif_carrier_on(dev); 11698c2ecf20Sopenharmony_ci netif_wake_queue(dev); 11708c2ecf20Sopenharmony_ci } 11718c2ecf20Sopenharmony_ci } else 11728c2ecf20Sopenharmony_ci if (netif_carrier_ok(dev)) { 11738c2ecf20Sopenharmony_ci netif_info(port, link, dev, 11748c2ecf20Sopenharmony_ci "Logical port down\n"); 11758c2ecf20Sopenharmony_ci netif_carrier_off(dev); 11768c2ecf20Sopenharmony_ci netif_tx_disable(dev); 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PORT_UP, eqe)) { 11808c2ecf20Sopenharmony_ci port->phy_link = EHEA_PHY_LINK_UP; 11818c2ecf20Sopenharmony_ci netif_info(port, link, dev, 11828c2ecf20Sopenharmony_ci "Physical port up\n"); 11838c2ecf20Sopenharmony_ci if (prop_carrier_state) 11848c2ecf20Sopenharmony_ci netif_carrier_on(dev); 11858c2ecf20Sopenharmony_ci } else { 11868c2ecf20Sopenharmony_ci port->phy_link = EHEA_PHY_LINK_DOWN; 11878c2ecf20Sopenharmony_ci netif_info(port, link, dev, 11888c2ecf20Sopenharmony_ci "Physical port down\n"); 11898c2ecf20Sopenharmony_ci if (prop_carrier_state) 11908c2ecf20Sopenharmony_ci netif_carrier_off(dev); 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PRIMARY, eqe)) 11948c2ecf20Sopenharmony_ci netdev_info(dev, 11958c2ecf20Sopenharmony_ci "External switch port is primary port\n"); 11968c2ecf20Sopenharmony_ci else 11978c2ecf20Sopenharmony_ci netdev_info(dev, 11988c2ecf20Sopenharmony_ci "External switch port is backup port\n"); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci break; 12018c2ecf20Sopenharmony_ci case EHEA_EC_ADAPTER_MALFUNC: 12028c2ecf20Sopenharmony_ci netdev_err(dev, "Adapter malfunction\n"); 12038c2ecf20Sopenharmony_ci break; 12048c2ecf20Sopenharmony_ci case EHEA_EC_PORT_MALFUNC: 12058c2ecf20Sopenharmony_ci netdev_info(dev, "Port malfunction\n"); 12068c2ecf20Sopenharmony_ci netif_carrier_off(dev); 12078c2ecf20Sopenharmony_ci netif_tx_disable(dev); 12088c2ecf20Sopenharmony_ci break; 12098c2ecf20Sopenharmony_ci default: 12108c2ecf20Sopenharmony_ci netdev_err(dev, "unknown event code %x, eqe=0x%llX\n", ec, eqe); 12118c2ecf20Sopenharmony_ci break; 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_cistatic void ehea_neq_tasklet(struct tasklet_struct *t) 12168c2ecf20Sopenharmony_ci{ 12178c2ecf20Sopenharmony_ci struct ehea_adapter *adapter = from_tasklet(adapter, t, neq_tasklet); 12188c2ecf20Sopenharmony_ci struct ehea_eqe *eqe; 12198c2ecf20Sopenharmony_ci u64 event_mask; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci eqe = ehea_poll_eq(adapter->neq); 12228c2ecf20Sopenharmony_ci pr_debug("eqe=%p\n", eqe); 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci while (eqe) { 12258c2ecf20Sopenharmony_ci pr_debug("*eqe=%lx\n", (unsigned long) eqe->entry); 12268c2ecf20Sopenharmony_ci ehea_parse_eqe(adapter, eqe->entry); 12278c2ecf20Sopenharmony_ci eqe = ehea_poll_eq(adapter->neq); 12288c2ecf20Sopenharmony_ci pr_debug("next eqe=%p\n", eqe); 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci event_mask = EHEA_BMASK_SET(NELR_PORTSTATE_CHG, 1) 12328c2ecf20Sopenharmony_ci | EHEA_BMASK_SET(NELR_ADAPTER_MALFUNC, 1) 12338c2ecf20Sopenharmony_ci | EHEA_BMASK_SET(NELR_PORT_MALFUNC, 1); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci ehea_h_reset_events(adapter->handle, 12368c2ecf20Sopenharmony_ci adapter->neq->fw_handle, event_mask); 12378c2ecf20Sopenharmony_ci} 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_cistatic irqreturn_t ehea_interrupt_neq(int irq, void *param) 12408c2ecf20Sopenharmony_ci{ 12418c2ecf20Sopenharmony_ci struct ehea_adapter *adapter = param; 12428c2ecf20Sopenharmony_ci tasklet_hi_schedule(&adapter->neq_tasklet); 12438c2ecf20Sopenharmony_ci return IRQ_HANDLED; 12448c2ecf20Sopenharmony_ci} 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_cistatic int ehea_fill_port_res(struct ehea_port_res *pr) 12488c2ecf20Sopenharmony_ci{ 12498c2ecf20Sopenharmony_ci int ret; 12508c2ecf20Sopenharmony_ci struct ehea_qp_init_attr *init_attr = &pr->qp->init_attr; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci ehea_init_fill_rq1(pr, pr->rq1_skba.len); 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci ret = ehea_refill_rq2(pr, init_attr->act_nr_rwqes_rq2 - 1); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci ret |= ehea_refill_rq3(pr, init_attr->act_nr_rwqes_rq3 - 1); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci return ret; 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_cistatic int ehea_reg_interrupts(struct net_device *dev) 12628c2ecf20Sopenharmony_ci{ 12638c2ecf20Sopenharmony_ci struct ehea_port *port = netdev_priv(dev); 12648c2ecf20Sopenharmony_ci struct ehea_port_res *pr; 12658c2ecf20Sopenharmony_ci int i, ret; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci snprintf(port->int_aff_name, EHEA_IRQ_NAME_SIZE - 1, "%s-aff", 12698c2ecf20Sopenharmony_ci dev->name); 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci ret = ibmebus_request_irq(port->qp_eq->attr.ist1, 12728c2ecf20Sopenharmony_ci ehea_qp_aff_irq_handler, 12738c2ecf20Sopenharmony_ci 0, port->int_aff_name, port); 12748c2ecf20Sopenharmony_ci if (ret) { 12758c2ecf20Sopenharmony_ci netdev_err(dev, "failed registering irq for qp_aff_irq_handler:ist=%X\n", 12768c2ecf20Sopenharmony_ci port->qp_eq->attr.ist1); 12778c2ecf20Sopenharmony_ci goto out_free_qpeq; 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci netif_info(port, ifup, dev, 12818c2ecf20Sopenharmony_ci "irq_handle 0x%X for function qp_aff_irq_handler registered\n", 12828c2ecf20Sopenharmony_ci port->qp_eq->attr.ist1); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci for (i = 0; i < port->num_def_qps; i++) { 12868c2ecf20Sopenharmony_ci pr = &port->port_res[i]; 12878c2ecf20Sopenharmony_ci snprintf(pr->int_send_name, EHEA_IRQ_NAME_SIZE - 1, 12888c2ecf20Sopenharmony_ci "%s-queue%d", dev->name, i); 12898c2ecf20Sopenharmony_ci ret = ibmebus_request_irq(pr->eq->attr.ist1, 12908c2ecf20Sopenharmony_ci ehea_recv_irq_handler, 12918c2ecf20Sopenharmony_ci 0, pr->int_send_name, pr); 12928c2ecf20Sopenharmony_ci if (ret) { 12938c2ecf20Sopenharmony_ci netdev_err(dev, "failed registering irq for ehea_queue port_res_nr:%d, ist=%X\n", 12948c2ecf20Sopenharmony_ci i, pr->eq->attr.ist1); 12958c2ecf20Sopenharmony_ci goto out_free_req; 12968c2ecf20Sopenharmony_ci } 12978c2ecf20Sopenharmony_ci netif_info(port, ifup, dev, 12988c2ecf20Sopenharmony_ci "irq_handle 0x%X for function ehea_queue_int %d registered\n", 12998c2ecf20Sopenharmony_ci pr->eq->attr.ist1, i); 13008c2ecf20Sopenharmony_ci } 13018c2ecf20Sopenharmony_ciout: 13028c2ecf20Sopenharmony_ci return ret; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ciout_free_req: 13068c2ecf20Sopenharmony_ci while (--i >= 0) { 13078c2ecf20Sopenharmony_ci u32 ist = port->port_res[i].eq->attr.ist1; 13088c2ecf20Sopenharmony_ci ibmebus_free_irq(ist, &port->port_res[i]); 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ciout_free_qpeq: 13128c2ecf20Sopenharmony_ci ibmebus_free_irq(port->qp_eq->attr.ist1, port); 13138c2ecf20Sopenharmony_ci i = port->num_def_qps; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci goto out; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci} 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_cistatic void ehea_free_interrupts(struct net_device *dev) 13208c2ecf20Sopenharmony_ci{ 13218c2ecf20Sopenharmony_ci struct ehea_port *port = netdev_priv(dev); 13228c2ecf20Sopenharmony_ci struct ehea_port_res *pr; 13238c2ecf20Sopenharmony_ci int i; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci /* send */ 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci for (i = 0; i < port->num_def_qps; i++) { 13288c2ecf20Sopenharmony_ci pr = &port->port_res[i]; 13298c2ecf20Sopenharmony_ci ibmebus_free_irq(pr->eq->attr.ist1, pr); 13308c2ecf20Sopenharmony_ci netif_info(port, intr, dev, 13318c2ecf20Sopenharmony_ci "free send irq for res %d with handle 0x%X\n", 13328c2ecf20Sopenharmony_ci i, pr->eq->attr.ist1); 13338c2ecf20Sopenharmony_ci } 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci /* associated events */ 13368c2ecf20Sopenharmony_ci ibmebus_free_irq(port->qp_eq->attr.ist1, port); 13378c2ecf20Sopenharmony_ci netif_info(port, intr, dev, 13388c2ecf20Sopenharmony_ci "associated event interrupt for handle 0x%X freed\n", 13398c2ecf20Sopenharmony_ci port->qp_eq->attr.ist1); 13408c2ecf20Sopenharmony_ci} 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_cistatic int ehea_configure_port(struct ehea_port *port) 13438c2ecf20Sopenharmony_ci{ 13448c2ecf20Sopenharmony_ci int ret, i; 13458c2ecf20Sopenharmony_ci u64 hret, mask; 13468c2ecf20Sopenharmony_ci struct hcp_ehea_port_cb0 *cb0; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci ret = -ENOMEM; 13498c2ecf20Sopenharmony_ci cb0 = (void *)get_zeroed_page(GFP_KERNEL); 13508c2ecf20Sopenharmony_ci if (!cb0) 13518c2ecf20Sopenharmony_ci goto out; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci cb0->port_rc = EHEA_BMASK_SET(PXLY_RC_VALID, 1) 13548c2ecf20Sopenharmony_ci | EHEA_BMASK_SET(PXLY_RC_IP_CHKSUM, 1) 13558c2ecf20Sopenharmony_ci | EHEA_BMASK_SET(PXLY_RC_TCP_UDP_CHKSUM, 1) 13568c2ecf20Sopenharmony_ci | EHEA_BMASK_SET(PXLY_RC_VLAN_XTRACT, 1) 13578c2ecf20Sopenharmony_ci | EHEA_BMASK_SET(PXLY_RC_VLAN_TAG_FILTER, 13588c2ecf20Sopenharmony_ci PXLY_RC_VLAN_FILTER) 13598c2ecf20Sopenharmony_ci | EHEA_BMASK_SET(PXLY_RC_JUMBO_FRAME, 1); 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci for (i = 0; i < port->num_mcs; i++) 13628c2ecf20Sopenharmony_ci if (use_mcs) 13638c2ecf20Sopenharmony_ci cb0->default_qpn_arr[i] = 13648c2ecf20Sopenharmony_ci port->port_res[i].qp->init_attr.qp_nr; 13658c2ecf20Sopenharmony_ci else 13668c2ecf20Sopenharmony_ci cb0->default_qpn_arr[i] = 13678c2ecf20Sopenharmony_ci port->port_res[0].qp->init_attr.qp_nr; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci if (netif_msg_ifup(port)) 13708c2ecf20Sopenharmony_ci ehea_dump(cb0, sizeof(*cb0), "ehea_configure_port"); 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci mask = EHEA_BMASK_SET(H_PORT_CB0_PRC, 1) 13738c2ecf20Sopenharmony_ci | EHEA_BMASK_SET(H_PORT_CB0_DEFQPNARRAY, 1); 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci hret = ehea_h_modify_ehea_port(port->adapter->handle, 13768c2ecf20Sopenharmony_ci port->logical_port_id, 13778c2ecf20Sopenharmony_ci H_PORT_CB0, mask, cb0); 13788c2ecf20Sopenharmony_ci ret = -EIO; 13798c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) 13808c2ecf20Sopenharmony_ci goto out_free; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci ret = 0; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ciout_free: 13858c2ecf20Sopenharmony_ci free_page((unsigned long)cb0); 13868c2ecf20Sopenharmony_ciout: 13878c2ecf20Sopenharmony_ci return ret; 13888c2ecf20Sopenharmony_ci} 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_cistatic int ehea_gen_smrs(struct ehea_port_res *pr) 13918c2ecf20Sopenharmony_ci{ 13928c2ecf20Sopenharmony_ci int ret; 13938c2ecf20Sopenharmony_ci struct ehea_adapter *adapter = pr->port->adapter; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci ret = ehea_gen_smr(adapter, &adapter->mr, &pr->send_mr); 13968c2ecf20Sopenharmony_ci if (ret) 13978c2ecf20Sopenharmony_ci goto out; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci ret = ehea_gen_smr(adapter, &adapter->mr, &pr->recv_mr); 14008c2ecf20Sopenharmony_ci if (ret) 14018c2ecf20Sopenharmony_ci goto out_free; 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci return 0; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ciout_free: 14068c2ecf20Sopenharmony_ci ehea_rem_mr(&pr->send_mr); 14078c2ecf20Sopenharmony_ciout: 14088c2ecf20Sopenharmony_ci pr_err("Generating SMRS failed\n"); 14098c2ecf20Sopenharmony_ci return -EIO; 14108c2ecf20Sopenharmony_ci} 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_cistatic int ehea_rem_smrs(struct ehea_port_res *pr) 14138c2ecf20Sopenharmony_ci{ 14148c2ecf20Sopenharmony_ci if ((ehea_rem_mr(&pr->send_mr)) || 14158c2ecf20Sopenharmony_ci (ehea_rem_mr(&pr->recv_mr))) 14168c2ecf20Sopenharmony_ci return -EIO; 14178c2ecf20Sopenharmony_ci else 14188c2ecf20Sopenharmony_ci return 0; 14198c2ecf20Sopenharmony_ci} 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_cistatic int ehea_init_q_skba(struct ehea_q_skb_arr *q_skba, int max_q_entries) 14228c2ecf20Sopenharmony_ci{ 14238c2ecf20Sopenharmony_ci int arr_size = sizeof(void *) * max_q_entries; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci q_skba->arr = vzalloc(arr_size); 14268c2ecf20Sopenharmony_ci if (!q_skba->arr) 14278c2ecf20Sopenharmony_ci return -ENOMEM; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci q_skba->len = max_q_entries; 14308c2ecf20Sopenharmony_ci q_skba->index = 0; 14318c2ecf20Sopenharmony_ci q_skba->os_skbs = 0; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci return 0; 14348c2ecf20Sopenharmony_ci} 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_cistatic int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, 14378c2ecf20Sopenharmony_ci struct port_res_cfg *pr_cfg, int queue_token) 14388c2ecf20Sopenharmony_ci{ 14398c2ecf20Sopenharmony_ci struct ehea_adapter *adapter = port->adapter; 14408c2ecf20Sopenharmony_ci enum ehea_eq_type eq_type = EHEA_EQ; 14418c2ecf20Sopenharmony_ci struct ehea_qp_init_attr *init_attr = NULL; 14428c2ecf20Sopenharmony_ci int ret = -EIO; 14438c2ecf20Sopenharmony_ci u64 tx_bytes, rx_bytes, tx_packets, rx_packets; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci tx_bytes = pr->tx_bytes; 14468c2ecf20Sopenharmony_ci tx_packets = pr->tx_packets; 14478c2ecf20Sopenharmony_ci rx_bytes = pr->rx_bytes; 14488c2ecf20Sopenharmony_ci rx_packets = pr->rx_packets; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci memset(pr, 0, sizeof(struct ehea_port_res)); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci pr->tx_bytes = tx_bytes; 14538c2ecf20Sopenharmony_ci pr->tx_packets = tx_packets; 14548c2ecf20Sopenharmony_ci pr->rx_bytes = rx_bytes; 14558c2ecf20Sopenharmony_ci pr->rx_packets = rx_packets; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci pr->port = port; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci pr->eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0); 14608c2ecf20Sopenharmony_ci if (!pr->eq) { 14618c2ecf20Sopenharmony_ci pr_err("create_eq failed (eq)\n"); 14628c2ecf20Sopenharmony_ci goto out_free; 14638c2ecf20Sopenharmony_ci } 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci pr->recv_cq = ehea_create_cq(adapter, pr_cfg->max_entries_rcq, 14668c2ecf20Sopenharmony_ci pr->eq->fw_handle, 14678c2ecf20Sopenharmony_ci port->logical_port_id); 14688c2ecf20Sopenharmony_ci if (!pr->recv_cq) { 14698c2ecf20Sopenharmony_ci pr_err("create_cq failed (cq_recv)\n"); 14708c2ecf20Sopenharmony_ci goto out_free; 14718c2ecf20Sopenharmony_ci } 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci pr->send_cq = ehea_create_cq(adapter, pr_cfg->max_entries_scq, 14748c2ecf20Sopenharmony_ci pr->eq->fw_handle, 14758c2ecf20Sopenharmony_ci port->logical_port_id); 14768c2ecf20Sopenharmony_ci if (!pr->send_cq) { 14778c2ecf20Sopenharmony_ci pr_err("create_cq failed (cq_send)\n"); 14788c2ecf20Sopenharmony_ci goto out_free; 14798c2ecf20Sopenharmony_ci } 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci if (netif_msg_ifup(port)) 14828c2ecf20Sopenharmony_ci pr_info("Send CQ: act_nr_cqes=%d, Recv CQ: act_nr_cqes=%d\n", 14838c2ecf20Sopenharmony_ci pr->send_cq->attr.act_nr_of_cqes, 14848c2ecf20Sopenharmony_ci pr->recv_cq->attr.act_nr_of_cqes); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci init_attr = kzalloc(sizeof(*init_attr), GFP_KERNEL); 14878c2ecf20Sopenharmony_ci if (!init_attr) { 14888c2ecf20Sopenharmony_ci ret = -ENOMEM; 14898c2ecf20Sopenharmony_ci pr_err("no mem for ehea_qp_init_attr\n"); 14908c2ecf20Sopenharmony_ci goto out_free; 14918c2ecf20Sopenharmony_ci } 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci init_attr->low_lat_rq1 = 1; 14948c2ecf20Sopenharmony_ci init_attr->signalingtype = 1; /* generate CQE if specified in WQE */ 14958c2ecf20Sopenharmony_ci init_attr->rq_count = 3; 14968c2ecf20Sopenharmony_ci init_attr->qp_token = queue_token; 14978c2ecf20Sopenharmony_ci init_attr->max_nr_send_wqes = pr_cfg->max_entries_sq; 14988c2ecf20Sopenharmony_ci init_attr->max_nr_rwqes_rq1 = pr_cfg->max_entries_rq1; 14998c2ecf20Sopenharmony_ci init_attr->max_nr_rwqes_rq2 = pr_cfg->max_entries_rq2; 15008c2ecf20Sopenharmony_ci init_attr->max_nr_rwqes_rq3 = pr_cfg->max_entries_rq3; 15018c2ecf20Sopenharmony_ci init_attr->wqe_size_enc_sq = EHEA_SG_SQ; 15028c2ecf20Sopenharmony_ci init_attr->wqe_size_enc_rq1 = EHEA_SG_RQ1; 15038c2ecf20Sopenharmony_ci init_attr->wqe_size_enc_rq2 = EHEA_SG_RQ2; 15048c2ecf20Sopenharmony_ci init_attr->wqe_size_enc_rq3 = EHEA_SG_RQ3; 15058c2ecf20Sopenharmony_ci init_attr->rq2_threshold = EHEA_RQ2_THRESHOLD; 15068c2ecf20Sopenharmony_ci init_attr->rq3_threshold = EHEA_RQ3_THRESHOLD; 15078c2ecf20Sopenharmony_ci init_attr->port_nr = port->logical_port_id; 15088c2ecf20Sopenharmony_ci init_attr->send_cq_handle = pr->send_cq->fw_handle; 15098c2ecf20Sopenharmony_ci init_attr->recv_cq_handle = pr->recv_cq->fw_handle; 15108c2ecf20Sopenharmony_ci init_attr->aff_eq_handle = port->qp_eq->fw_handle; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci pr->qp = ehea_create_qp(adapter, adapter->pd, init_attr); 15138c2ecf20Sopenharmony_ci if (!pr->qp) { 15148c2ecf20Sopenharmony_ci pr_err("create_qp failed\n"); 15158c2ecf20Sopenharmony_ci ret = -EIO; 15168c2ecf20Sopenharmony_ci goto out_free; 15178c2ecf20Sopenharmony_ci } 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci if (netif_msg_ifup(port)) 15208c2ecf20Sopenharmony_ci pr_info("QP: qp_nr=%d\n act_nr_snd_wqe=%d\n nr_rwqe_rq1=%d\n nr_rwqe_rq2=%d\n nr_rwqe_rq3=%d\n", 15218c2ecf20Sopenharmony_ci init_attr->qp_nr, 15228c2ecf20Sopenharmony_ci init_attr->act_nr_send_wqes, 15238c2ecf20Sopenharmony_ci init_attr->act_nr_rwqes_rq1, 15248c2ecf20Sopenharmony_ci init_attr->act_nr_rwqes_rq2, 15258c2ecf20Sopenharmony_ci init_attr->act_nr_rwqes_rq3); 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci pr->sq_skba_size = init_attr->act_nr_send_wqes + 1; 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci ret = ehea_init_q_skba(&pr->sq_skba, pr->sq_skba_size); 15308c2ecf20Sopenharmony_ci ret |= ehea_init_q_skba(&pr->rq1_skba, init_attr->act_nr_rwqes_rq1 + 1); 15318c2ecf20Sopenharmony_ci ret |= ehea_init_q_skba(&pr->rq2_skba, init_attr->act_nr_rwqes_rq2 + 1); 15328c2ecf20Sopenharmony_ci ret |= ehea_init_q_skba(&pr->rq3_skba, init_attr->act_nr_rwqes_rq3 + 1); 15338c2ecf20Sopenharmony_ci if (ret) 15348c2ecf20Sopenharmony_ci goto out_free; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci pr->swqe_refill_th = init_attr->act_nr_send_wqes / 10; 15378c2ecf20Sopenharmony_ci if (ehea_gen_smrs(pr) != 0) { 15388c2ecf20Sopenharmony_ci ret = -EIO; 15398c2ecf20Sopenharmony_ci goto out_free; 15408c2ecf20Sopenharmony_ci } 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci atomic_set(&pr->swqe_avail, init_attr->act_nr_send_wqes - 1); 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci kfree(init_attr); 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci netif_napi_add(pr->port->netdev, &pr->napi, ehea_poll, 64); 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci ret = 0; 15498c2ecf20Sopenharmony_ci goto out; 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ciout_free: 15528c2ecf20Sopenharmony_ci kfree(init_attr); 15538c2ecf20Sopenharmony_ci vfree(pr->sq_skba.arr); 15548c2ecf20Sopenharmony_ci vfree(pr->rq1_skba.arr); 15558c2ecf20Sopenharmony_ci vfree(pr->rq2_skba.arr); 15568c2ecf20Sopenharmony_ci vfree(pr->rq3_skba.arr); 15578c2ecf20Sopenharmony_ci ehea_destroy_qp(pr->qp); 15588c2ecf20Sopenharmony_ci ehea_destroy_cq(pr->send_cq); 15598c2ecf20Sopenharmony_ci ehea_destroy_cq(pr->recv_cq); 15608c2ecf20Sopenharmony_ci ehea_destroy_eq(pr->eq); 15618c2ecf20Sopenharmony_ciout: 15628c2ecf20Sopenharmony_ci return ret; 15638c2ecf20Sopenharmony_ci} 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_cistatic int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr) 15668c2ecf20Sopenharmony_ci{ 15678c2ecf20Sopenharmony_ci int ret, i; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci if (pr->qp) 15708c2ecf20Sopenharmony_ci netif_napi_del(&pr->napi); 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci ret = ehea_destroy_qp(pr->qp); 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci if (!ret) { 15758c2ecf20Sopenharmony_ci ehea_destroy_cq(pr->send_cq); 15768c2ecf20Sopenharmony_ci ehea_destroy_cq(pr->recv_cq); 15778c2ecf20Sopenharmony_ci ehea_destroy_eq(pr->eq); 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci for (i = 0; i < pr->rq1_skba.len; i++) 15808c2ecf20Sopenharmony_ci dev_kfree_skb(pr->rq1_skba.arr[i]); 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci for (i = 0; i < pr->rq2_skba.len; i++) 15838c2ecf20Sopenharmony_ci dev_kfree_skb(pr->rq2_skba.arr[i]); 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci for (i = 0; i < pr->rq3_skba.len; i++) 15868c2ecf20Sopenharmony_ci dev_kfree_skb(pr->rq3_skba.arr[i]); 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci for (i = 0; i < pr->sq_skba.len; i++) 15898c2ecf20Sopenharmony_ci dev_kfree_skb(pr->sq_skba.arr[i]); 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci vfree(pr->rq1_skba.arr); 15928c2ecf20Sopenharmony_ci vfree(pr->rq2_skba.arr); 15938c2ecf20Sopenharmony_ci vfree(pr->rq3_skba.arr); 15948c2ecf20Sopenharmony_ci vfree(pr->sq_skba.arr); 15958c2ecf20Sopenharmony_ci ret = ehea_rem_smrs(pr); 15968c2ecf20Sopenharmony_ci } 15978c2ecf20Sopenharmony_ci return ret; 15988c2ecf20Sopenharmony_ci} 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_cistatic void write_swqe2_immediate(struct sk_buff *skb, struct ehea_swqe *swqe, 16018c2ecf20Sopenharmony_ci u32 lkey) 16028c2ecf20Sopenharmony_ci{ 16038c2ecf20Sopenharmony_ci int skb_data_size = skb_headlen(skb); 16048c2ecf20Sopenharmony_ci u8 *imm_data = &swqe->u.immdata_desc.immediate_data[0]; 16058c2ecf20Sopenharmony_ci struct ehea_vsgentry *sg1entry = &swqe->u.immdata_desc.sg_entry; 16068c2ecf20Sopenharmony_ci unsigned int immediate_len = SWQE2_MAX_IMM; 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci swqe->descriptors = 0; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci if (skb_is_gso(skb)) { 16118c2ecf20Sopenharmony_ci swqe->tx_control |= EHEA_SWQE_TSO; 16128c2ecf20Sopenharmony_ci swqe->mss = skb_shinfo(skb)->gso_size; 16138c2ecf20Sopenharmony_ci /* 16148c2ecf20Sopenharmony_ci * For TSO packets we only copy the headers into the 16158c2ecf20Sopenharmony_ci * immediate area. 16168c2ecf20Sopenharmony_ci */ 16178c2ecf20Sopenharmony_ci immediate_len = ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb); 16188c2ecf20Sopenharmony_ci } 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci if (skb_is_gso(skb) || skb_data_size >= SWQE2_MAX_IMM) { 16218c2ecf20Sopenharmony_ci skb_copy_from_linear_data(skb, imm_data, immediate_len); 16228c2ecf20Sopenharmony_ci swqe->immediate_data_length = immediate_len; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci if (skb_data_size > immediate_len) { 16258c2ecf20Sopenharmony_ci sg1entry->l_key = lkey; 16268c2ecf20Sopenharmony_ci sg1entry->len = skb_data_size - immediate_len; 16278c2ecf20Sopenharmony_ci sg1entry->vaddr = 16288c2ecf20Sopenharmony_ci ehea_map_vaddr(skb->data + immediate_len); 16298c2ecf20Sopenharmony_ci swqe->descriptors++; 16308c2ecf20Sopenharmony_ci } 16318c2ecf20Sopenharmony_ci } else { 16328c2ecf20Sopenharmony_ci skb_copy_from_linear_data(skb, imm_data, skb_data_size); 16338c2ecf20Sopenharmony_ci swqe->immediate_data_length = skb_data_size; 16348c2ecf20Sopenharmony_ci } 16358c2ecf20Sopenharmony_ci} 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_cistatic inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev, 16388c2ecf20Sopenharmony_ci struct ehea_swqe *swqe, u32 lkey) 16398c2ecf20Sopenharmony_ci{ 16408c2ecf20Sopenharmony_ci struct ehea_vsgentry *sg_list, *sg1entry, *sgentry; 16418c2ecf20Sopenharmony_ci skb_frag_t *frag; 16428c2ecf20Sopenharmony_ci int nfrags, sg1entry_contains_frag_data, i; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci nfrags = skb_shinfo(skb)->nr_frags; 16458c2ecf20Sopenharmony_ci sg1entry = &swqe->u.immdata_desc.sg_entry; 16468c2ecf20Sopenharmony_ci sg_list = (struct ehea_vsgentry *)&swqe->u.immdata_desc.sg_list; 16478c2ecf20Sopenharmony_ci sg1entry_contains_frag_data = 0; 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci write_swqe2_immediate(skb, swqe, lkey); 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci /* write descriptors */ 16528c2ecf20Sopenharmony_ci if (nfrags > 0) { 16538c2ecf20Sopenharmony_ci if (swqe->descriptors == 0) { 16548c2ecf20Sopenharmony_ci /* sg1entry not yet used */ 16558c2ecf20Sopenharmony_ci frag = &skb_shinfo(skb)->frags[0]; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci /* copy sg1entry data */ 16588c2ecf20Sopenharmony_ci sg1entry->l_key = lkey; 16598c2ecf20Sopenharmony_ci sg1entry->len = skb_frag_size(frag); 16608c2ecf20Sopenharmony_ci sg1entry->vaddr = 16618c2ecf20Sopenharmony_ci ehea_map_vaddr(skb_frag_address(frag)); 16628c2ecf20Sopenharmony_ci swqe->descriptors++; 16638c2ecf20Sopenharmony_ci sg1entry_contains_frag_data = 1; 16648c2ecf20Sopenharmony_ci } 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci for (i = sg1entry_contains_frag_data; i < nfrags; i++) { 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci frag = &skb_shinfo(skb)->frags[i]; 16698c2ecf20Sopenharmony_ci sgentry = &sg_list[i - sg1entry_contains_frag_data]; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci sgentry->l_key = lkey; 16728c2ecf20Sopenharmony_ci sgentry->len = skb_frag_size(frag); 16738c2ecf20Sopenharmony_ci sgentry->vaddr = ehea_map_vaddr(skb_frag_address(frag)); 16748c2ecf20Sopenharmony_ci swqe->descriptors++; 16758c2ecf20Sopenharmony_ci } 16768c2ecf20Sopenharmony_ci } 16778c2ecf20Sopenharmony_ci} 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_cistatic int ehea_broadcast_reg_helper(struct ehea_port *port, u32 hcallid) 16808c2ecf20Sopenharmony_ci{ 16818c2ecf20Sopenharmony_ci int ret = 0; 16828c2ecf20Sopenharmony_ci u64 hret; 16838c2ecf20Sopenharmony_ci u8 reg_type; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci /* De/Register untagged packets */ 16868c2ecf20Sopenharmony_ci reg_type = EHEA_BCMC_BROADCAST | EHEA_BCMC_UNTAGGED; 16878c2ecf20Sopenharmony_ci hret = ehea_h_reg_dereg_bcmc(port->adapter->handle, 16888c2ecf20Sopenharmony_ci port->logical_port_id, 16898c2ecf20Sopenharmony_ci reg_type, port->mac_addr, 0, hcallid); 16908c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 16918c2ecf20Sopenharmony_ci pr_err("%sregistering bc address failed (tagged)\n", 16928c2ecf20Sopenharmony_ci hcallid == H_REG_BCMC ? "" : "de"); 16938c2ecf20Sopenharmony_ci ret = -EIO; 16948c2ecf20Sopenharmony_ci goto out_herr; 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci /* De/Register VLAN packets */ 16988c2ecf20Sopenharmony_ci reg_type = EHEA_BCMC_BROADCAST | EHEA_BCMC_VLANID_ALL; 16998c2ecf20Sopenharmony_ci hret = ehea_h_reg_dereg_bcmc(port->adapter->handle, 17008c2ecf20Sopenharmony_ci port->logical_port_id, 17018c2ecf20Sopenharmony_ci reg_type, port->mac_addr, 0, hcallid); 17028c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 17038c2ecf20Sopenharmony_ci pr_err("%sregistering bc address failed (vlan)\n", 17048c2ecf20Sopenharmony_ci hcallid == H_REG_BCMC ? "" : "de"); 17058c2ecf20Sopenharmony_ci ret = -EIO; 17068c2ecf20Sopenharmony_ci } 17078c2ecf20Sopenharmony_ciout_herr: 17088c2ecf20Sopenharmony_ci return ret; 17098c2ecf20Sopenharmony_ci} 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_cistatic int ehea_set_mac_addr(struct net_device *dev, void *sa) 17128c2ecf20Sopenharmony_ci{ 17138c2ecf20Sopenharmony_ci struct ehea_port *port = netdev_priv(dev); 17148c2ecf20Sopenharmony_ci struct sockaddr *mac_addr = sa; 17158c2ecf20Sopenharmony_ci struct hcp_ehea_port_cb0 *cb0; 17168c2ecf20Sopenharmony_ci int ret; 17178c2ecf20Sopenharmony_ci u64 hret; 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(mac_addr->sa_data)) { 17208c2ecf20Sopenharmony_ci ret = -EADDRNOTAVAIL; 17218c2ecf20Sopenharmony_ci goto out; 17228c2ecf20Sopenharmony_ci } 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci cb0 = (void *)get_zeroed_page(GFP_KERNEL); 17258c2ecf20Sopenharmony_ci if (!cb0) { 17268c2ecf20Sopenharmony_ci pr_err("no mem for cb0\n"); 17278c2ecf20Sopenharmony_ci ret = -ENOMEM; 17288c2ecf20Sopenharmony_ci goto out; 17298c2ecf20Sopenharmony_ci } 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci memcpy(&(cb0->port_mac_addr), &(mac_addr->sa_data[0]), ETH_ALEN); 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci cb0->port_mac_addr = cb0->port_mac_addr >> 16; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci hret = ehea_h_modify_ehea_port(port->adapter->handle, 17368c2ecf20Sopenharmony_ci port->logical_port_id, H_PORT_CB0, 17378c2ecf20Sopenharmony_ci EHEA_BMASK_SET(H_PORT_CB0_MAC, 1), cb0); 17388c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 17398c2ecf20Sopenharmony_ci ret = -EIO; 17408c2ecf20Sopenharmony_ci goto out_free; 17418c2ecf20Sopenharmony_ci } 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len); 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci /* Deregister old MAC in pHYP */ 17468c2ecf20Sopenharmony_ci if (port->state == EHEA_PORT_UP) { 17478c2ecf20Sopenharmony_ci ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC); 17488c2ecf20Sopenharmony_ci if (ret) 17498c2ecf20Sopenharmony_ci goto out_upregs; 17508c2ecf20Sopenharmony_ci } 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci port->mac_addr = cb0->port_mac_addr << 16; 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci /* Register new MAC in pHYP */ 17558c2ecf20Sopenharmony_ci if (port->state == EHEA_PORT_UP) { 17568c2ecf20Sopenharmony_ci ret = ehea_broadcast_reg_helper(port, H_REG_BCMC); 17578c2ecf20Sopenharmony_ci if (ret) 17588c2ecf20Sopenharmony_ci goto out_upregs; 17598c2ecf20Sopenharmony_ci } 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci ret = 0; 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ciout_upregs: 17648c2ecf20Sopenharmony_ci ehea_update_bcmc_registrations(); 17658c2ecf20Sopenharmony_ciout_free: 17668c2ecf20Sopenharmony_ci free_page((unsigned long)cb0); 17678c2ecf20Sopenharmony_ciout: 17688c2ecf20Sopenharmony_ci return ret; 17698c2ecf20Sopenharmony_ci} 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_cistatic void ehea_promiscuous_error(u64 hret, int enable) 17728c2ecf20Sopenharmony_ci{ 17738c2ecf20Sopenharmony_ci if (hret == H_AUTHORITY) 17748c2ecf20Sopenharmony_ci pr_info("Hypervisor denied %sabling promiscuous mode\n", 17758c2ecf20Sopenharmony_ci enable == 1 ? "en" : "dis"); 17768c2ecf20Sopenharmony_ci else 17778c2ecf20Sopenharmony_ci pr_err("failed %sabling promiscuous mode\n", 17788c2ecf20Sopenharmony_ci enable == 1 ? "en" : "dis"); 17798c2ecf20Sopenharmony_ci} 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_cistatic void ehea_promiscuous(struct net_device *dev, int enable) 17828c2ecf20Sopenharmony_ci{ 17838c2ecf20Sopenharmony_ci struct ehea_port *port = netdev_priv(dev); 17848c2ecf20Sopenharmony_ci struct hcp_ehea_port_cb7 *cb7; 17858c2ecf20Sopenharmony_ci u64 hret; 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci if (enable == port->promisc) 17888c2ecf20Sopenharmony_ci return; 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci cb7 = (void *)get_zeroed_page(GFP_ATOMIC); 17918c2ecf20Sopenharmony_ci if (!cb7) { 17928c2ecf20Sopenharmony_ci pr_err("no mem for cb7\n"); 17938c2ecf20Sopenharmony_ci goto out; 17948c2ecf20Sopenharmony_ci } 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci /* Modify Pxs_DUCQPN in CB7 */ 17978c2ecf20Sopenharmony_ci cb7->def_uc_qpn = enable == 1 ? port->port_res[0].qp->fw_handle : 0; 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci hret = ehea_h_modify_ehea_port(port->adapter->handle, 18008c2ecf20Sopenharmony_ci port->logical_port_id, 18018c2ecf20Sopenharmony_ci H_PORT_CB7, H_PORT_CB7_DUCQPN, cb7); 18028c2ecf20Sopenharmony_ci if (hret) { 18038c2ecf20Sopenharmony_ci ehea_promiscuous_error(hret, enable); 18048c2ecf20Sopenharmony_ci goto out; 18058c2ecf20Sopenharmony_ci } 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci port->promisc = enable; 18088c2ecf20Sopenharmony_ciout: 18098c2ecf20Sopenharmony_ci free_page((unsigned long)cb7); 18108c2ecf20Sopenharmony_ci} 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_cistatic u64 ehea_multicast_reg_helper(struct ehea_port *port, u64 mc_mac_addr, 18138c2ecf20Sopenharmony_ci u32 hcallid) 18148c2ecf20Sopenharmony_ci{ 18158c2ecf20Sopenharmony_ci u64 hret; 18168c2ecf20Sopenharmony_ci u8 reg_type; 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci reg_type = EHEA_BCMC_MULTICAST | EHEA_BCMC_UNTAGGED; 18198c2ecf20Sopenharmony_ci if (mc_mac_addr == 0) 18208c2ecf20Sopenharmony_ci reg_type |= EHEA_BCMC_SCOPE_ALL; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci hret = ehea_h_reg_dereg_bcmc(port->adapter->handle, 18238c2ecf20Sopenharmony_ci port->logical_port_id, 18248c2ecf20Sopenharmony_ci reg_type, mc_mac_addr, 0, hcallid); 18258c2ecf20Sopenharmony_ci if (hret) 18268c2ecf20Sopenharmony_ci goto out; 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci reg_type = EHEA_BCMC_MULTICAST | EHEA_BCMC_VLANID_ALL; 18298c2ecf20Sopenharmony_ci if (mc_mac_addr == 0) 18308c2ecf20Sopenharmony_ci reg_type |= EHEA_BCMC_SCOPE_ALL; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci hret = ehea_h_reg_dereg_bcmc(port->adapter->handle, 18338c2ecf20Sopenharmony_ci port->logical_port_id, 18348c2ecf20Sopenharmony_ci reg_type, mc_mac_addr, 0, hcallid); 18358c2ecf20Sopenharmony_ciout: 18368c2ecf20Sopenharmony_ci return hret; 18378c2ecf20Sopenharmony_ci} 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_cistatic int ehea_drop_multicast_list(struct net_device *dev) 18408c2ecf20Sopenharmony_ci{ 18418c2ecf20Sopenharmony_ci struct ehea_port *port = netdev_priv(dev); 18428c2ecf20Sopenharmony_ci struct ehea_mc_list *mc_entry = port->mc_list; 18438c2ecf20Sopenharmony_ci struct list_head *pos; 18448c2ecf20Sopenharmony_ci struct list_head *temp; 18458c2ecf20Sopenharmony_ci int ret = 0; 18468c2ecf20Sopenharmony_ci u64 hret; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci list_for_each_safe(pos, temp, &(port->mc_list->list)) { 18498c2ecf20Sopenharmony_ci mc_entry = list_entry(pos, struct ehea_mc_list, list); 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci hret = ehea_multicast_reg_helper(port, mc_entry->macaddr, 18528c2ecf20Sopenharmony_ci H_DEREG_BCMC); 18538c2ecf20Sopenharmony_ci if (hret) { 18548c2ecf20Sopenharmony_ci pr_err("failed deregistering mcast MAC\n"); 18558c2ecf20Sopenharmony_ci ret = -EIO; 18568c2ecf20Sopenharmony_ci } 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci list_del(pos); 18598c2ecf20Sopenharmony_ci kfree(mc_entry); 18608c2ecf20Sopenharmony_ci } 18618c2ecf20Sopenharmony_ci return ret; 18628c2ecf20Sopenharmony_ci} 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_cistatic void ehea_allmulti(struct net_device *dev, int enable) 18658c2ecf20Sopenharmony_ci{ 18668c2ecf20Sopenharmony_ci struct ehea_port *port = netdev_priv(dev); 18678c2ecf20Sopenharmony_ci u64 hret; 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci if (!port->allmulti) { 18708c2ecf20Sopenharmony_ci if (enable) { 18718c2ecf20Sopenharmony_ci /* Enable ALLMULTI */ 18728c2ecf20Sopenharmony_ci ehea_drop_multicast_list(dev); 18738c2ecf20Sopenharmony_ci hret = ehea_multicast_reg_helper(port, 0, H_REG_BCMC); 18748c2ecf20Sopenharmony_ci if (!hret) 18758c2ecf20Sopenharmony_ci port->allmulti = 1; 18768c2ecf20Sopenharmony_ci else 18778c2ecf20Sopenharmony_ci netdev_err(dev, 18788c2ecf20Sopenharmony_ci "failed enabling IFF_ALLMULTI\n"); 18798c2ecf20Sopenharmony_ci } 18808c2ecf20Sopenharmony_ci } else { 18818c2ecf20Sopenharmony_ci if (!enable) { 18828c2ecf20Sopenharmony_ci /* Disable ALLMULTI */ 18838c2ecf20Sopenharmony_ci hret = ehea_multicast_reg_helper(port, 0, H_DEREG_BCMC); 18848c2ecf20Sopenharmony_ci if (!hret) 18858c2ecf20Sopenharmony_ci port->allmulti = 0; 18868c2ecf20Sopenharmony_ci else 18878c2ecf20Sopenharmony_ci netdev_err(dev, 18888c2ecf20Sopenharmony_ci "failed disabling IFF_ALLMULTI\n"); 18898c2ecf20Sopenharmony_ci } 18908c2ecf20Sopenharmony_ci } 18918c2ecf20Sopenharmony_ci} 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_cistatic void ehea_add_multicast_entry(struct ehea_port *port, u8 *mc_mac_addr) 18948c2ecf20Sopenharmony_ci{ 18958c2ecf20Sopenharmony_ci struct ehea_mc_list *ehea_mcl_entry; 18968c2ecf20Sopenharmony_ci u64 hret; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci ehea_mcl_entry = kzalloc(sizeof(*ehea_mcl_entry), GFP_ATOMIC); 18998c2ecf20Sopenharmony_ci if (!ehea_mcl_entry) 19008c2ecf20Sopenharmony_ci return; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ehea_mcl_entry->list); 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci memcpy(&ehea_mcl_entry->macaddr, mc_mac_addr, ETH_ALEN); 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci hret = ehea_multicast_reg_helper(port, ehea_mcl_entry->macaddr, 19078c2ecf20Sopenharmony_ci H_REG_BCMC); 19088c2ecf20Sopenharmony_ci if (!hret) 19098c2ecf20Sopenharmony_ci list_add(&ehea_mcl_entry->list, &port->mc_list->list); 19108c2ecf20Sopenharmony_ci else { 19118c2ecf20Sopenharmony_ci pr_err("failed registering mcast MAC\n"); 19128c2ecf20Sopenharmony_ci kfree(ehea_mcl_entry); 19138c2ecf20Sopenharmony_ci } 19148c2ecf20Sopenharmony_ci} 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_cistatic void ehea_set_multicast_list(struct net_device *dev) 19178c2ecf20Sopenharmony_ci{ 19188c2ecf20Sopenharmony_ci struct ehea_port *port = netdev_priv(dev); 19198c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 19208c2ecf20Sopenharmony_ci int ret; 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci ehea_promiscuous(dev, !!(dev->flags & IFF_PROMISC)); 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci if (dev->flags & IFF_ALLMULTI) { 19258c2ecf20Sopenharmony_ci ehea_allmulti(dev, 1); 19268c2ecf20Sopenharmony_ci goto out; 19278c2ecf20Sopenharmony_ci } 19288c2ecf20Sopenharmony_ci ehea_allmulti(dev, 0); 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci if (!netdev_mc_empty(dev)) { 19318c2ecf20Sopenharmony_ci ret = ehea_drop_multicast_list(dev); 19328c2ecf20Sopenharmony_ci if (ret) { 19338c2ecf20Sopenharmony_ci /* Dropping the current multicast list failed. 19348c2ecf20Sopenharmony_ci * Enabling ALL_MULTI is the best we can do. 19358c2ecf20Sopenharmony_ci */ 19368c2ecf20Sopenharmony_ci ehea_allmulti(dev, 1); 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci if (netdev_mc_count(dev) > port->adapter->max_mc_mac) { 19408c2ecf20Sopenharmony_ci pr_info("Mcast registration limit reached (0x%llx). Use ALLMULTI!\n", 19418c2ecf20Sopenharmony_ci port->adapter->max_mc_mac); 19428c2ecf20Sopenharmony_ci goto out; 19438c2ecf20Sopenharmony_ci } 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) 19468c2ecf20Sopenharmony_ci ehea_add_multicast_entry(port, ha->addr); 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci } 19498c2ecf20Sopenharmony_ciout: 19508c2ecf20Sopenharmony_ci ehea_update_bcmc_registrations(); 19518c2ecf20Sopenharmony_ci} 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_cistatic void xmit_common(struct sk_buff *skb, struct ehea_swqe *swqe) 19548c2ecf20Sopenharmony_ci{ 19558c2ecf20Sopenharmony_ci swqe->tx_control |= EHEA_SWQE_IMM_DATA_PRESENT | EHEA_SWQE_CRC; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci if (vlan_get_protocol(skb) != htons(ETH_P_IP)) 19588c2ecf20Sopenharmony_ci return; 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) 19618c2ecf20Sopenharmony_ci swqe->tx_control |= EHEA_SWQE_IP_CHECKSUM; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci swqe->ip_start = skb_network_offset(skb); 19648c2ecf20Sopenharmony_ci swqe->ip_end = swqe->ip_start + ip_hdrlen(skb) - 1; 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci switch (ip_hdr(skb)->protocol) { 19678c2ecf20Sopenharmony_ci case IPPROTO_UDP: 19688c2ecf20Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) 19698c2ecf20Sopenharmony_ci swqe->tx_control |= EHEA_SWQE_TCP_CHECKSUM; 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci swqe->tcp_offset = swqe->ip_end + 1 + 19728c2ecf20Sopenharmony_ci offsetof(struct udphdr, check); 19738c2ecf20Sopenharmony_ci break; 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci case IPPROTO_TCP: 19768c2ecf20Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) 19778c2ecf20Sopenharmony_ci swqe->tx_control |= EHEA_SWQE_TCP_CHECKSUM; 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci swqe->tcp_offset = swqe->ip_end + 1 + 19808c2ecf20Sopenharmony_ci offsetof(struct tcphdr, check); 19818c2ecf20Sopenharmony_ci break; 19828c2ecf20Sopenharmony_ci } 19838c2ecf20Sopenharmony_ci} 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_cistatic void ehea_xmit2(struct sk_buff *skb, struct net_device *dev, 19868c2ecf20Sopenharmony_ci struct ehea_swqe *swqe, u32 lkey) 19878c2ecf20Sopenharmony_ci{ 19888c2ecf20Sopenharmony_ci swqe->tx_control |= EHEA_SWQE_DESCRIPTORS_PRESENT; 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci xmit_common(skb, swqe); 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci write_swqe2_data(skb, dev, swqe, lkey); 19938c2ecf20Sopenharmony_ci} 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_cistatic void ehea_xmit3(struct sk_buff *skb, struct net_device *dev, 19968c2ecf20Sopenharmony_ci struct ehea_swqe *swqe) 19978c2ecf20Sopenharmony_ci{ 19988c2ecf20Sopenharmony_ci u8 *imm_data = &swqe->u.immdata_nodesc.immediate_data[0]; 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci xmit_common(skb, swqe); 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci if (!skb->data_len) 20038c2ecf20Sopenharmony_ci skb_copy_from_linear_data(skb, imm_data, skb->len); 20048c2ecf20Sopenharmony_ci else 20058c2ecf20Sopenharmony_ci skb_copy_bits(skb, 0, imm_data, skb->len); 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci swqe->immediate_data_length = skb->len; 20088c2ecf20Sopenharmony_ci dev_consume_skb_any(skb); 20098c2ecf20Sopenharmony_ci} 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_cistatic netdev_tx_t ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) 20128c2ecf20Sopenharmony_ci{ 20138c2ecf20Sopenharmony_ci struct ehea_port *port = netdev_priv(dev); 20148c2ecf20Sopenharmony_ci struct ehea_swqe *swqe; 20158c2ecf20Sopenharmony_ci u32 lkey; 20168c2ecf20Sopenharmony_ci int swqe_index; 20178c2ecf20Sopenharmony_ci struct ehea_port_res *pr; 20188c2ecf20Sopenharmony_ci struct netdev_queue *txq; 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci pr = &port->port_res[skb_get_queue_mapping(skb)]; 20218c2ecf20Sopenharmony_ci txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci swqe = ehea_get_swqe(pr->qp, &swqe_index); 20248c2ecf20Sopenharmony_ci memset(swqe, 0, SWQE_HEADER_SIZE); 20258c2ecf20Sopenharmony_ci atomic_dec(&pr->swqe_avail); 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 20288c2ecf20Sopenharmony_ci swqe->tx_control |= EHEA_SWQE_VLAN_INSERT; 20298c2ecf20Sopenharmony_ci swqe->vlan_tag = skb_vlan_tag_get(skb); 20308c2ecf20Sopenharmony_ci } 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci pr->tx_packets++; 20338c2ecf20Sopenharmony_ci pr->tx_bytes += skb->len; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci if (skb->len <= SWQE3_MAX_IMM) { 20368c2ecf20Sopenharmony_ci u32 sig_iv = port->sig_comp_iv; 20378c2ecf20Sopenharmony_ci u32 swqe_num = pr->swqe_id_counter; 20388c2ecf20Sopenharmony_ci ehea_xmit3(skb, dev, swqe); 20398c2ecf20Sopenharmony_ci swqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_SWQE3_TYPE) 20408c2ecf20Sopenharmony_ci | EHEA_BMASK_SET(EHEA_WR_ID_COUNT, swqe_num); 20418c2ecf20Sopenharmony_ci if (pr->swqe_ll_count >= (sig_iv - 1)) { 20428c2ecf20Sopenharmony_ci swqe->wr_id |= EHEA_BMASK_SET(EHEA_WR_ID_REFILL, 20438c2ecf20Sopenharmony_ci sig_iv); 20448c2ecf20Sopenharmony_ci swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION; 20458c2ecf20Sopenharmony_ci pr->swqe_ll_count = 0; 20468c2ecf20Sopenharmony_ci } else 20478c2ecf20Sopenharmony_ci pr->swqe_ll_count += 1; 20488c2ecf20Sopenharmony_ci } else { 20498c2ecf20Sopenharmony_ci swqe->wr_id = 20508c2ecf20Sopenharmony_ci EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_SWQE2_TYPE) 20518c2ecf20Sopenharmony_ci | EHEA_BMASK_SET(EHEA_WR_ID_COUNT, pr->swqe_id_counter) 20528c2ecf20Sopenharmony_ci | EHEA_BMASK_SET(EHEA_WR_ID_REFILL, 1) 20538c2ecf20Sopenharmony_ci | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, pr->sq_skba.index); 20548c2ecf20Sopenharmony_ci pr->sq_skba.arr[pr->sq_skba.index] = skb; 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci pr->sq_skba.index++; 20578c2ecf20Sopenharmony_ci pr->sq_skba.index &= (pr->sq_skba.len - 1); 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci lkey = pr->send_mr.lkey; 20608c2ecf20Sopenharmony_ci ehea_xmit2(skb, dev, swqe, lkey); 20618c2ecf20Sopenharmony_ci swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION; 20628c2ecf20Sopenharmony_ci } 20638c2ecf20Sopenharmony_ci pr->swqe_id_counter += 1; 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci netif_info(port, tx_queued, dev, 20668c2ecf20Sopenharmony_ci "post swqe on QP %d\n", pr->qp->init_attr.qp_nr); 20678c2ecf20Sopenharmony_ci if (netif_msg_tx_queued(port)) 20688c2ecf20Sopenharmony_ci ehea_dump(swqe, 512, "swqe"); 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) { 20718c2ecf20Sopenharmony_ci netif_tx_stop_queue(txq); 20728c2ecf20Sopenharmony_ci swqe->tx_control |= EHEA_SWQE_PURGE; 20738c2ecf20Sopenharmony_ci } 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci ehea_post_swqe(pr->qp, swqe); 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) { 20788c2ecf20Sopenharmony_ci pr->p_stats.queue_stopped++; 20798c2ecf20Sopenharmony_ci netif_tx_stop_queue(txq); 20808c2ecf20Sopenharmony_ci } 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 20838c2ecf20Sopenharmony_ci} 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_cistatic int ehea_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid) 20868c2ecf20Sopenharmony_ci{ 20878c2ecf20Sopenharmony_ci struct ehea_port *port = netdev_priv(dev); 20888c2ecf20Sopenharmony_ci struct ehea_adapter *adapter = port->adapter; 20898c2ecf20Sopenharmony_ci struct hcp_ehea_port_cb1 *cb1; 20908c2ecf20Sopenharmony_ci int index; 20918c2ecf20Sopenharmony_ci u64 hret; 20928c2ecf20Sopenharmony_ci int err = 0; 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci cb1 = (void *)get_zeroed_page(GFP_KERNEL); 20958c2ecf20Sopenharmony_ci if (!cb1) { 20968c2ecf20Sopenharmony_ci pr_err("no mem for cb1\n"); 20978c2ecf20Sopenharmony_ci err = -ENOMEM; 20988c2ecf20Sopenharmony_ci goto out; 20998c2ecf20Sopenharmony_ci } 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id, 21028c2ecf20Sopenharmony_ci H_PORT_CB1, H_PORT_CB1_ALL, cb1); 21038c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 21048c2ecf20Sopenharmony_ci pr_err("query_ehea_port failed\n"); 21058c2ecf20Sopenharmony_ci err = -EINVAL; 21068c2ecf20Sopenharmony_ci goto out; 21078c2ecf20Sopenharmony_ci } 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci index = (vid / 64); 21108c2ecf20Sopenharmony_ci cb1->vlan_filter[index] |= ((u64)(0x8000000000000000 >> (vid & 0x3F))); 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id, 21138c2ecf20Sopenharmony_ci H_PORT_CB1, H_PORT_CB1_ALL, cb1); 21148c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 21158c2ecf20Sopenharmony_ci pr_err("modify_ehea_port failed\n"); 21168c2ecf20Sopenharmony_ci err = -EINVAL; 21178c2ecf20Sopenharmony_ci } 21188c2ecf20Sopenharmony_ciout: 21198c2ecf20Sopenharmony_ci free_page((unsigned long)cb1); 21208c2ecf20Sopenharmony_ci return err; 21218c2ecf20Sopenharmony_ci} 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_cistatic int ehea_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid) 21248c2ecf20Sopenharmony_ci{ 21258c2ecf20Sopenharmony_ci struct ehea_port *port = netdev_priv(dev); 21268c2ecf20Sopenharmony_ci struct ehea_adapter *adapter = port->adapter; 21278c2ecf20Sopenharmony_ci struct hcp_ehea_port_cb1 *cb1; 21288c2ecf20Sopenharmony_ci int index; 21298c2ecf20Sopenharmony_ci u64 hret; 21308c2ecf20Sopenharmony_ci int err = 0; 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci cb1 = (void *)get_zeroed_page(GFP_KERNEL); 21338c2ecf20Sopenharmony_ci if (!cb1) { 21348c2ecf20Sopenharmony_ci pr_err("no mem for cb1\n"); 21358c2ecf20Sopenharmony_ci err = -ENOMEM; 21368c2ecf20Sopenharmony_ci goto out; 21378c2ecf20Sopenharmony_ci } 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id, 21408c2ecf20Sopenharmony_ci H_PORT_CB1, H_PORT_CB1_ALL, cb1); 21418c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 21428c2ecf20Sopenharmony_ci pr_err("query_ehea_port failed\n"); 21438c2ecf20Sopenharmony_ci err = -EINVAL; 21448c2ecf20Sopenharmony_ci goto out; 21458c2ecf20Sopenharmony_ci } 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci index = (vid / 64); 21488c2ecf20Sopenharmony_ci cb1->vlan_filter[index] &= ~((u64)(0x8000000000000000 >> (vid & 0x3F))); 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id, 21518c2ecf20Sopenharmony_ci H_PORT_CB1, H_PORT_CB1_ALL, cb1); 21528c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 21538c2ecf20Sopenharmony_ci pr_err("modify_ehea_port failed\n"); 21548c2ecf20Sopenharmony_ci err = -EINVAL; 21558c2ecf20Sopenharmony_ci } 21568c2ecf20Sopenharmony_ciout: 21578c2ecf20Sopenharmony_ci free_page((unsigned long)cb1); 21588c2ecf20Sopenharmony_ci return err; 21598c2ecf20Sopenharmony_ci} 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_cistatic int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp) 21628c2ecf20Sopenharmony_ci{ 21638c2ecf20Sopenharmony_ci int ret = -EIO; 21648c2ecf20Sopenharmony_ci u64 hret; 21658c2ecf20Sopenharmony_ci u16 dummy16 = 0; 21668c2ecf20Sopenharmony_ci u64 dummy64 = 0; 21678c2ecf20Sopenharmony_ci struct hcp_modify_qp_cb0 *cb0; 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci cb0 = (void *)get_zeroed_page(GFP_KERNEL); 21708c2ecf20Sopenharmony_ci if (!cb0) { 21718c2ecf20Sopenharmony_ci ret = -ENOMEM; 21728c2ecf20Sopenharmony_ci goto out; 21738c2ecf20Sopenharmony_ci } 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle, 21768c2ecf20Sopenharmony_ci EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0); 21778c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 21788c2ecf20Sopenharmony_ci pr_err("query_ehea_qp failed (1)\n"); 21798c2ecf20Sopenharmony_ci goto out; 21808c2ecf20Sopenharmony_ci } 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci cb0->qp_ctl_reg = H_QP_CR_STATE_INITIALIZED; 21838c2ecf20Sopenharmony_ci hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle, 21848c2ecf20Sopenharmony_ci EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0, 21858c2ecf20Sopenharmony_ci &dummy64, &dummy64, &dummy16, &dummy16); 21868c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 21878c2ecf20Sopenharmony_ci pr_err("modify_ehea_qp failed (1)\n"); 21888c2ecf20Sopenharmony_ci goto out; 21898c2ecf20Sopenharmony_ci } 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_ci hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle, 21928c2ecf20Sopenharmony_ci EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0); 21938c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 21948c2ecf20Sopenharmony_ci pr_err("query_ehea_qp failed (2)\n"); 21958c2ecf20Sopenharmony_ci goto out; 21968c2ecf20Sopenharmony_ci } 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci cb0->qp_ctl_reg = H_QP_CR_ENABLED | H_QP_CR_STATE_INITIALIZED; 21998c2ecf20Sopenharmony_ci hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle, 22008c2ecf20Sopenharmony_ci EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0, 22018c2ecf20Sopenharmony_ci &dummy64, &dummy64, &dummy16, &dummy16); 22028c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 22038c2ecf20Sopenharmony_ci pr_err("modify_ehea_qp failed (2)\n"); 22048c2ecf20Sopenharmony_ci goto out; 22058c2ecf20Sopenharmony_ci } 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle, 22088c2ecf20Sopenharmony_ci EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0); 22098c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 22108c2ecf20Sopenharmony_ci pr_err("query_ehea_qp failed (3)\n"); 22118c2ecf20Sopenharmony_ci goto out; 22128c2ecf20Sopenharmony_ci } 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci cb0->qp_ctl_reg = H_QP_CR_ENABLED | H_QP_CR_STATE_RDY2SND; 22158c2ecf20Sopenharmony_ci hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle, 22168c2ecf20Sopenharmony_ci EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0, 22178c2ecf20Sopenharmony_ci &dummy64, &dummy64, &dummy16, &dummy16); 22188c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 22198c2ecf20Sopenharmony_ci pr_err("modify_ehea_qp failed (3)\n"); 22208c2ecf20Sopenharmony_ci goto out; 22218c2ecf20Sopenharmony_ci } 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle, 22248c2ecf20Sopenharmony_ci EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0); 22258c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 22268c2ecf20Sopenharmony_ci pr_err("query_ehea_qp failed (4)\n"); 22278c2ecf20Sopenharmony_ci goto out; 22288c2ecf20Sopenharmony_ci } 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci ret = 0; 22318c2ecf20Sopenharmony_ciout: 22328c2ecf20Sopenharmony_ci free_page((unsigned long)cb0); 22338c2ecf20Sopenharmony_ci return ret; 22348c2ecf20Sopenharmony_ci} 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_cistatic int ehea_port_res_setup(struct ehea_port *port, int def_qps) 22378c2ecf20Sopenharmony_ci{ 22388c2ecf20Sopenharmony_ci int ret, i; 22398c2ecf20Sopenharmony_ci struct port_res_cfg pr_cfg, pr_cfg_small_rx; 22408c2ecf20Sopenharmony_ci enum ehea_eq_type eq_type = EHEA_EQ; 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci port->qp_eq = ehea_create_eq(port->adapter, eq_type, 22438c2ecf20Sopenharmony_ci EHEA_MAX_ENTRIES_EQ, 1); 22448c2ecf20Sopenharmony_ci if (!port->qp_eq) { 22458c2ecf20Sopenharmony_ci ret = -EINVAL; 22468c2ecf20Sopenharmony_ci pr_err("ehea_create_eq failed (qp_eq)\n"); 22478c2ecf20Sopenharmony_ci goto out_kill_eq; 22488c2ecf20Sopenharmony_ci } 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci pr_cfg.max_entries_rcq = rq1_entries + rq2_entries + rq3_entries; 22518c2ecf20Sopenharmony_ci pr_cfg.max_entries_scq = sq_entries * 2; 22528c2ecf20Sopenharmony_ci pr_cfg.max_entries_sq = sq_entries; 22538c2ecf20Sopenharmony_ci pr_cfg.max_entries_rq1 = rq1_entries; 22548c2ecf20Sopenharmony_ci pr_cfg.max_entries_rq2 = rq2_entries; 22558c2ecf20Sopenharmony_ci pr_cfg.max_entries_rq3 = rq3_entries; 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci pr_cfg_small_rx.max_entries_rcq = 1; 22588c2ecf20Sopenharmony_ci pr_cfg_small_rx.max_entries_scq = sq_entries; 22598c2ecf20Sopenharmony_ci pr_cfg_small_rx.max_entries_sq = sq_entries; 22608c2ecf20Sopenharmony_ci pr_cfg_small_rx.max_entries_rq1 = 1; 22618c2ecf20Sopenharmony_ci pr_cfg_small_rx.max_entries_rq2 = 1; 22628c2ecf20Sopenharmony_ci pr_cfg_small_rx.max_entries_rq3 = 1; 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci for (i = 0; i < def_qps; i++) { 22658c2ecf20Sopenharmony_ci ret = ehea_init_port_res(port, &port->port_res[i], &pr_cfg, i); 22668c2ecf20Sopenharmony_ci if (ret) 22678c2ecf20Sopenharmony_ci goto out_clean_pr; 22688c2ecf20Sopenharmony_ci } 22698c2ecf20Sopenharmony_ci for (i = def_qps; i < def_qps; i++) { 22708c2ecf20Sopenharmony_ci ret = ehea_init_port_res(port, &port->port_res[i], 22718c2ecf20Sopenharmony_ci &pr_cfg_small_rx, i); 22728c2ecf20Sopenharmony_ci if (ret) 22738c2ecf20Sopenharmony_ci goto out_clean_pr; 22748c2ecf20Sopenharmony_ci } 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci return 0; 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_ciout_clean_pr: 22798c2ecf20Sopenharmony_ci while (--i >= 0) 22808c2ecf20Sopenharmony_ci ehea_clean_portres(port, &port->port_res[i]); 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ciout_kill_eq: 22838c2ecf20Sopenharmony_ci ehea_destroy_eq(port->qp_eq); 22848c2ecf20Sopenharmony_ci return ret; 22858c2ecf20Sopenharmony_ci} 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_cistatic int ehea_clean_all_portres(struct ehea_port *port) 22888c2ecf20Sopenharmony_ci{ 22898c2ecf20Sopenharmony_ci int ret = 0; 22908c2ecf20Sopenharmony_ci int i; 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci for (i = 0; i < port->num_def_qps; i++) 22938c2ecf20Sopenharmony_ci ret |= ehea_clean_portres(port, &port->port_res[i]); 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci ret |= ehea_destroy_eq(port->qp_eq); 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci return ret; 22988c2ecf20Sopenharmony_ci} 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_cistatic void ehea_remove_adapter_mr(struct ehea_adapter *adapter) 23018c2ecf20Sopenharmony_ci{ 23028c2ecf20Sopenharmony_ci if (adapter->active_ports) 23038c2ecf20Sopenharmony_ci return; 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci ehea_rem_mr(&adapter->mr); 23068c2ecf20Sopenharmony_ci} 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_cistatic int ehea_add_adapter_mr(struct ehea_adapter *adapter) 23098c2ecf20Sopenharmony_ci{ 23108c2ecf20Sopenharmony_ci if (adapter->active_ports) 23118c2ecf20Sopenharmony_ci return 0; 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci return ehea_reg_kernel_mr(adapter, &adapter->mr); 23148c2ecf20Sopenharmony_ci} 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_cistatic int ehea_up(struct net_device *dev) 23178c2ecf20Sopenharmony_ci{ 23188c2ecf20Sopenharmony_ci int ret, i; 23198c2ecf20Sopenharmony_ci struct ehea_port *port = netdev_priv(dev); 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci if (port->state == EHEA_PORT_UP) 23228c2ecf20Sopenharmony_ci return 0; 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci ret = ehea_port_res_setup(port, port->num_def_qps); 23258c2ecf20Sopenharmony_ci if (ret) { 23268c2ecf20Sopenharmony_ci netdev_err(dev, "port_res_failed\n"); 23278c2ecf20Sopenharmony_ci goto out; 23288c2ecf20Sopenharmony_ci } 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci /* Set default QP for this port */ 23318c2ecf20Sopenharmony_ci ret = ehea_configure_port(port); 23328c2ecf20Sopenharmony_ci if (ret) { 23338c2ecf20Sopenharmony_ci netdev_err(dev, "ehea_configure_port failed. ret:%d\n", ret); 23348c2ecf20Sopenharmony_ci goto out_clean_pr; 23358c2ecf20Sopenharmony_ci } 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci ret = ehea_reg_interrupts(dev); 23388c2ecf20Sopenharmony_ci if (ret) { 23398c2ecf20Sopenharmony_ci netdev_err(dev, "reg_interrupts failed. ret:%d\n", ret); 23408c2ecf20Sopenharmony_ci goto out_clean_pr; 23418c2ecf20Sopenharmony_ci } 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci for (i = 0; i < port->num_def_qps; i++) { 23448c2ecf20Sopenharmony_ci ret = ehea_activate_qp(port->adapter, port->port_res[i].qp); 23458c2ecf20Sopenharmony_ci if (ret) { 23468c2ecf20Sopenharmony_ci netdev_err(dev, "activate_qp failed\n"); 23478c2ecf20Sopenharmony_ci goto out_free_irqs; 23488c2ecf20Sopenharmony_ci } 23498c2ecf20Sopenharmony_ci } 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci for (i = 0; i < port->num_def_qps; i++) { 23528c2ecf20Sopenharmony_ci ret = ehea_fill_port_res(&port->port_res[i]); 23538c2ecf20Sopenharmony_ci if (ret) { 23548c2ecf20Sopenharmony_ci netdev_err(dev, "out_free_irqs\n"); 23558c2ecf20Sopenharmony_ci goto out_free_irqs; 23568c2ecf20Sopenharmony_ci } 23578c2ecf20Sopenharmony_ci } 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci ret = ehea_broadcast_reg_helper(port, H_REG_BCMC); 23608c2ecf20Sopenharmony_ci if (ret) { 23618c2ecf20Sopenharmony_ci ret = -EIO; 23628c2ecf20Sopenharmony_ci goto out_free_irqs; 23638c2ecf20Sopenharmony_ci } 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci port->state = EHEA_PORT_UP; 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci ret = 0; 23688c2ecf20Sopenharmony_ci goto out; 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_ciout_free_irqs: 23718c2ecf20Sopenharmony_ci ehea_free_interrupts(dev); 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ciout_clean_pr: 23748c2ecf20Sopenharmony_ci ehea_clean_all_portres(port); 23758c2ecf20Sopenharmony_ciout: 23768c2ecf20Sopenharmony_ci if (ret) 23778c2ecf20Sopenharmony_ci netdev_info(dev, "Failed starting. ret=%i\n", ret); 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci ehea_update_bcmc_registrations(); 23808c2ecf20Sopenharmony_ci ehea_update_firmware_handles(); 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci return ret; 23838c2ecf20Sopenharmony_ci} 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_cistatic void port_napi_disable(struct ehea_port *port) 23868c2ecf20Sopenharmony_ci{ 23878c2ecf20Sopenharmony_ci int i; 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci for (i = 0; i < port->num_def_qps; i++) 23908c2ecf20Sopenharmony_ci napi_disable(&port->port_res[i].napi); 23918c2ecf20Sopenharmony_ci} 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_cistatic void port_napi_enable(struct ehea_port *port) 23948c2ecf20Sopenharmony_ci{ 23958c2ecf20Sopenharmony_ci int i; 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci for (i = 0; i < port->num_def_qps; i++) 23988c2ecf20Sopenharmony_ci napi_enable(&port->port_res[i].napi); 23998c2ecf20Sopenharmony_ci} 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_cistatic int ehea_open(struct net_device *dev) 24028c2ecf20Sopenharmony_ci{ 24038c2ecf20Sopenharmony_ci int ret; 24048c2ecf20Sopenharmony_ci struct ehea_port *port = netdev_priv(dev); 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci mutex_lock(&port->port_lock); 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci netif_info(port, ifup, dev, "enabling port\n"); 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci netif_carrier_off(dev); 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci ret = ehea_up(dev); 24138c2ecf20Sopenharmony_ci if (!ret) { 24148c2ecf20Sopenharmony_ci port_napi_enable(port); 24158c2ecf20Sopenharmony_ci netif_tx_start_all_queues(dev); 24168c2ecf20Sopenharmony_ci } 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci mutex_unlock(&port->port_lock); 24198c2ecf20Sopenharmony_ci schedule_delayed_work(&port->stats_work, 24208c2ecf20Sopenharmony_ci round_jiffies_relative(msecs_to_jiffies(1000))); 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci return ret; 24238c2ecf20Sopenharmony_ci} 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_cistatic int ehea_down(struct net_device *dev) 24268c2ecf20Sopenharmony_ci{ 24278c2ecf20Sopenharmony_ci int ret; 24288c2ecf20Sopenharmony_ci struct ehea_port *port = netdev_priv(dev); 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci if (port->state == EHEA_PORT_DOWN) 24318c2ecf20Sopenharmony_ci return 0; 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci ehea_drop_multicast_list(dev); 24348c2ecf20Sopenharmony_ci ehea_allmulti(dev, 0); 24358c2ecf20Sopenharmony_ci ehea_broadcast_reg_helper(port, H_DEREG_BCMC); 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci ehea_free_interrupts(dev); 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci port->state = EHEA_PORT_DOWN; 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci ehea_update_bcmc_registrations(); 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_ci ret = ehea_clean_all_portres(port); 24448c2ecf20Sopenharmony_ci if (ret) 24458c2ecf20Sopenharmony_ci netdev_info(dev, "Failed freeing resources. ret=%i\n", ret); 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci ehea_update_firmware_handles(); 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_ci return ret; 24508c2ecf20Sopenharmony_ci} 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_cistatic int ehea_stop(struct net_device *dev) 24538c2ecf20Sopenharmony_ci{ 24548c2ecf20Sopenharmony_ci int ret; 24558c2ecf20Sopenharmony_ci struct ehea_port *port = netdev_priv(dev); 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci netif_info(port, ifdown, dev, "disabling port\n"); 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci set_bit(__EHEA_DISABLE_PORT_RESET, &port->flags); 24608c2ecf20Sopenharmony_ci cancel_work_sync(&port->reset_task); 24618c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&port->stats_work); 24628c2ecf20Sopenharmony_ci mutex_lock(&port->port_lock); 24638c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(dev); 24648c2ecf20Sopenharmony_ci port_napi_disable(port); 24658c2ecf20Sopenharmony_ci ret = ehea_down(dev); 24668c2ecf20Sopenharmony_ci mutex_unlock(&port->port_lock); 24678c2ecf20Sopenharmony_ci clear_bit(__EHEA_DISABLE_PORT_RESET, &port->flags); 24688c2ecf20Sopenharmony_ci return ret; 24698c2ecf20Sopenharmony_ci} 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_cistatic void ehea_purge_sq(struct ehea_qp *orig_qp) 24728c2ecf20Sopenharmony_ci{ 24738c2ecf20Sopenharmony_ci struct ehea_qp qp = *orig_qp; 24748c2ecf20Sopenharmony_ci struct ehea_qp_init_attr *init_attr = &qp.init_attr; 24758c2ecf20Sopenharmony_ci struct ehea_swqe *swqe; 24768c2ecf20Sopenharmony_ci int wqe_index; 24778c2ecf20Sopenharmony_ci int i; 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci for (i = 0; i < init_attr->act_nr_send_wqes; i++) { 24808c2ecf20Sopenharmony_ci swqe = ehea_get_swqe(&qp, &wqe_index); 24818c2ecf20Sopenharmony_ci swqe->tx_control |= EHEA_SWQE_PURGE; 24828c2ecf20Sopenharmony_ci } 24838c2ecf20Sopenharmony_ci} 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_cistatic void ehea_flush_sq(struct ehea_port *port) 24868c2ecf20Sopenharmony_ci{ 24878c2ecf20Sopenharmony_ci int i; 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci for (i = 0; i < port->num_def_qps; i++) { 24908c2ecf20Sopenharmony_ci struct ehea_port_res *pr = &port->port_res[i]; 24918c2ecf20Sopenharmony_ci int swqe_max = pr->sq_skba_size - 2 - pr->swqe_ll_count; 24928c2ecf20Sopenharmony_ci int ret; 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci ret = wait_event_timeout(port->swqe_avail_wq, 24958c2ecf20Sopenharmony_ci atomic_read(&pr->swqe_avail) >= swqe_max, 24968c2ecf20Sopenharmony_ci msecs_to_jiffies(100)); 24978c2ecf20Sopenharmony_ci 24988c2ecf20Sopenharmony_ci if (!ret) { 24998c2ecf20Sopenharmony_ci pr_err("WARNING: sq not flushed completely\n"); 25008c2ecf20Sopenharmony_ci break; 25018c2ecf20Sopenharmony_ci } 25028c2ecf20Sopenharmony_ci } 25038c2ecf20Sopenharmony_ci} 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_cistatic int ehea_stop_qps(struct net_device *dev) 25068c2ecf20Sopenharmony_ci{ 25078c2ecf20Sopenharmony_ci struct ehea_port *port = netdev_priv(dev); 25088c2ecf20Sopenharmony_ci struct ehea_adapter *adapter = port->adapter; 25098c2ecf20Sopenharmony_ci struct hcp_modify_qp_cb0 *cb0; 25108c2ecf20Sopenharmony_ci int ret = -EIO; 25118c2ecf20Sopenharmony_ci int dret; 25128c2ecf20Sopenharmony_ci int i; 25138c2ecf20Sopenharmony_ci u64 hret; 25148c2ecf20Sopenharmony_ci u64 dummy64 = 0; 25158c2ecf20Sopenharmony_ci u16 dummy16 = 0; 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_ci cb0 = (void *)get_zeroed_page(GFP_KERNEL); 25188c2ecf20Sopenharmony_ci if (!cb0) { 25198c2ecf20Sopenharmony_ci ret = -ENOMEM; 25208c2ecf20Sopenharmony_ci goto out; 25218c2ecf20Sopenharmony_ci } 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_ci for (i = 0; i < (port->num_def_qps); i++) { 25248c2ecf20Sopenharmony_ci struct ehea_port_res *pr = &port->port_res[i]; 25258c2ecf20Sopenharmony_ci struct ehea_qp *qp = pr->qp; 25268c2ecf20Sopenharmony_ci 25278c2ecf20Sopenharmony_ci /* Purge send queue */ 25288c2ecf20Sopenharmony_ci ehea_purge_sq(qp); 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_ci /* Disable queue pair */ 25318c2ecf20Sopenharmony_ci hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle, 25328c2ecf20Sopenharmony_ci EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), 25338c2ecf20Sopenharmony_ci cb0); 25348c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 25358c2ecf20Sopenharmony_ci pr_err("query_ehea_qp failed (1)\n"); 25368c2ecf20Sopenharmony_ci goto out; 25378c2ecf20Sopenharmony_ci } 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci cb0->qp_ctl_reg = (cb0->qp_ctl_reg & H_QP_CR_RES_STATE) << 8; 25408c2ecf20Sopenharmony_ci cb0->qp_ctl_reg &= ~H_QP_CR_ENABLED; 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle, 25438c2ecf20Sopenharmony_ci EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 25448c2ecf20Sopenharmony_ci 1), cb0, &dummy64, 25458c2ecf20Sopenharmony_ci &dummy64, &dummy16, &dummy16); 25468c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 25478c2ecf20Sopenharmony_ci pr_err("modify_ehea_qp failed (1)\n"); 25488c2ecf20Sopenharmony_ci goto out; 25498c2ecf20Sopenharmony_ci } 25508c2ecf20Sopenharmony_ci 25518c2ecf20Sopenharmony_ci hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle, 25528c2ecf20Sopenharmony_ci EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), 25538c2ecf20Sopenharmony_ci cb0); 25548c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 25558c2ecf20Sopenharmony_ci pr_err("query_ehea_qp failed (2)\n"); 25568c2ecf20Sopenharmony_ci goto out; 25578c2ecf20Sopenharmony_ci } 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_ci /* deregister shared memory regions */ 25608c2ecf20Sopenharmony_ci dret = ehea_rem_smrs(pr); 25618c2ecf20Sopenharmony_ci if (dret) { 25628c2ecf20Sopenharmony_ci pr_err("unreg shared memory region failed\n"); 25638c2ecf20Sopenharmony_ci goto out; 25648c2ecf20Sopenharmony_ci } 25658c2ecf20Sopenharmony_ci } 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci ret = 0; 25688c2ecf20Sopenharmony_ciout: 25698c2ecf20Sopenharmony_ci free_page((unsigned long)cb0); 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci return ret; 25728c2ecf20Sopenharmony_ci} 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_cistatic void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res *pr) 25758c2ecf20Sopenharmony_ci{ 25768c2ecf20Sopenharmony_ci struct ehea_qp qp = *orig_qp; 25778c2ecf20Sopenharmony_ci struct ehea_qp_init_attr *init_attr = &qp.init_attr; 25788c2ecf20Sopenharmony_ci struct ehea_rwqe *rwqe; 25798c2ecf20Sopenharmony_ci struct sk_buff **skba_rq2 = pr->rq2_skba.arr; 25808c2ecf20Sopenharmony_ci struct sk_buff **skba_rq3 = pr->rq3_skba.arr; 25818c2ecf20Sopenharmony_ci struct sk_buff *skb; 25828c2ecf20Sopenharmony_ci u32 lkey = pr->recv_mr.lkey; 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci int i; 25868c2ecf20Sopenharmony_ci int index; 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci for (i = 0; i < init_attr->act_nr_rwqes_rq2 + 1; i++) { 25898c2ecf20Sopenharmony_ci rwqe = ehea_get_next_rwqe(&qp, 2); 25908c2ecf20Sopenharmony_ci rwqe->sg_list[0].l_key = lkey; 25918c2ecf20Sopenharmony_ci index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, rwqe->wr_id); 25928c2ecf20Sopenharmony_ci skb = skba_rq2[index]; 25938c2ecf20Sopenharmony_ci if (skb) 25948c2ecf20Sopenharmony_ci rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data); 25958c2ecf20Sopenharmony_ci } 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci for (i = 0; i < init_attr->act_nr_rwqes_rq3 + 1; i++) { 25988c2ecf20Sopenharmony_ci rwqe = ehea_get_next_rwqe(&qp, 3); 25998c2ecf20Sopenharmony_ci rwqe->sg_list[0].l_key = lkey; 26008c2ecf20Sopenharmony_ci index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, rwqe->wr_id); 26018c2ecf20Sopenharmony_ci skb = skba_rq3[index]; 26028c2ecf20Sopenharmony_ci if (skb) 26038c2ecf20Sopenharmony_ci rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data); 26048c2ecf20Sopenharmony_ci } 26058c2ecf20Sopenharmony_ci} 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_cistatic int ehea_restart_qps(struct net_device *dev) 26088c2ecf20Sopenharmony_ci{ 26098c2ecf20Sopenharmony_ci struct ehea_port *port = netdev_priv(dev); 26108c2ecf20Sopenharmony_ci struct ehea_adapter *adapter = port->adapter; 26118c2ecf20Sopenharmony_ci int ret = 0; 26128c2ecf20Sopenharmony_ci int i; 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci struct hcp_modify_qp_cb0 *cb0; 26158c2ecf20Sopenharmony_ci u64 hret; 26168c2ecf20Sopenharmony_ci u64 dummy64 = 0; 26178c2ecf20Sopenharmony_ci u16 dummy16 = 0; 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci cb0 = (void *)get_zeroed_page(GFP_KERNEL); 26208c2ecf20Sopenharmony_ci if (!cb0) 26218c2ecf20Sopenharmony_ci return -ENOMEM; 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_ci for (i = 0; i < (port->num_def_qps); i++) { 26248c2ecf20Sopenharmony_ci struct ehea_port_res *pr = &port->port_res[i]; 26258c2ecf20Sopenharmony_ci struct ehea_qp *qp = pr->qp; 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci ret = ehea_gen_smrs(pr); 26288c2ecf20Sopenharmony_ci if (ret) { 26298c2ecf20Sopenharmony_ci netdev_err(dev, "creation of shared memory regions failed\n"); 26308c2ecf20Sopenharmony_ci goto out; 26318c2ecf20Sopenharmony_ci } 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci ehea_update_rqs(qp, pr); 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci /* Enable queue pair */ 26368c2ecf20Sopenharmony_ci hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle, 26378c2ecf20Sopenharmony_ci EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), 26388c2ecf20Sopenharmony_ci cb0); 26398c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 26408c2ecf20Sopenharmony_ci netdev_err(dev, "query_ehea_qp failed (1)\n"); 26418c2ecf20Sopenharmony_ci ret = -EFAULT; 26428c2ecf20Sopenharmony_ci goto out; 26438c2ecf20Sopenharmony_ci } 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ci cb0->qp_ctl_reg = (cb0->qp_ctl_reg & H_QP_CR_RES_STATE) << 8; 26468c2ecf20Sopenharmony_ci cb0->qp_ctl_reg |= H_QP_CR_ENABLED; 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle, 26498c2ecf20Sopenharmony_ci EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 26508c2ecf20Sopenharmony_ci 1), cb0, &dummy64, 26518c2ecf20Sopenharmony_ci &dummy64, &dummy16, &dummy16); 26528c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 26538c2ecf20Sopenharmony_ci netdev_err(dev, "modify_ehea_qp failed (1)\n"); 26548c2ecf20Sopenharmony_ci ret = -EFAULT; 26558c2ecf20Sopenharmony_ci goto out; 26568c2ecf20Sopenharmony_ci } 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle, 26598c2ecf20Sopenharmony_ci EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), 26608c2ecf20Sopenharmony_ci cb0); 26618c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 26628c2ecf20Sopenharmony_ci netdev_err(dev, "query_ehea_qp failed (2)\n"); 26638c2ecf20Sopenharmony_ci ret = -EFAULT; 26648c2ecf20Sopenharmony_ci goto out; 26658c2ecf20Sopenharmony_ci } 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci /* refill entire queue */ 26688c2ecf20Sopenharmony_ci ehea_refill_rq1(pr, pr->rq1_skba.index, 0); 26698c2ecf20Sopenharmony_ci ehea_refill_rq2(pr, 0); 26708c2ecf20Sopenharmony_ci ehea_refill_rq3(pr, 0); 26718c2ecf20Sopenharmony_ci } 26728c2ecf20Sopenharmony_ciout: 26738c2ecf20Sopenharmony_ci free_page((unsigned long)cb0); 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_ci return ret; 26768c2ecf20Sopenharmony_ci} 26778c2ecf20Sopenharmony_ci 26788c2ecf20Sopenharmony_cistatic void ehea_reset_port(struct work_struct *work) 26798c2ecf20Sopenharmony_ci{ 26808c2ecf20Sopenharmony_ci int ret; 26818c2ecf20Sopenharmony_ci struct ehea_port *port = 26828c2ecf20Sopenharmony_ci container_of(work, struct ehea_port, reset_task); 26838c2ecf20Sopenharmony_ci struct net_device *dev = port->netdev; 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci mutex_lock(&dlpar_mem_lock); 26868c2ecf20Sopenharmony_ci port->resets++; 26878c2ecf20Sopenharmony_ci mutex_lock(&port->port_lock); 26888c2ecf20Sopenharmony_ci netif_tx_disable(dev); 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci port_napi_disable(port); 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ci ehea_down(dev); 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci ret = ehea_up(dev); 26958c2ecf20Sopenharmony_ci if (ret) 26968c2ecf20Sopenharmony_ci goto out; 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_ci ehea_set_multicast_list(dev); 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci netif_info(port, timer, dev, "reset successful\n"); 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci port_napi_enable(port); 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_ci netif_tx_wake_all_queues(dev); 27058c2ecf20Sopenharmony_ciout: 27068c2ecf20Sopenharmony_ci mutex_unlock(&port->port_lock); 27078c2ecf20Sopenharmony_ci mutex_unlock(&dlpar_mem_lock); 27088c2ecf20Sopenharmony_ci} 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_cistatic void ehea_rereg_mrs(void) 27118c2ecf20Sopenharmony_ci{ 27128c2ecf20Sopenharmony_ci int ret, i; 27138c2ecf20Sopenharmony_ci struct ehea_adapter *adapter; 27148c2ecf20Sopenharmony_ci 27158c2ecf20Sopenharmony_ci pr_info("LPAR memory changed - re-initializing driver\n"); 27168c2ecf20Sopenharmony_ci 27178c2ecf20Sopenharmony_ci list_for_each_entry(adapter, &adapter_list, list) 27188c2ecf20Sopenharmony_ci if (adapter->active_ports) { 27198c2ecf20Sopenharmony_ci /* Shutdown all ports */ 27208c2ecf20Sopenharmony_ci for (i = 0; i < EHEA_MAX_PORTS; i++) { 27218c2ecf20Sopenharmony_ci struct ehea_port *port = adapter->port[i]; 27228c2ecf20Sopenharmony_ci struct net_device *dev; 27238c2ecf20Sopenharmony_ci 27248c2ecf20Sopenharmony_ci if (!port) 27258c2ecf20Sopenharmony_ci continue; 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci dev = port->netdev; 27288c2ecf20Sopenharmony_ci 27298c2ecf20Sopenharmony_ci if (dev->flags & IFF_UP) { 27308c2ecf20Sopenharmony_ci mutex_lock(&port->port_lock); 27318c2ecf20Sopenharmony_ci netif_tx_disable(dev); 27328c2ecf20Sopenharmony_ci ehea_flush_sq(port); 27338c2ecf20Sopenharmony_ci ret = ehea_stop_qps(dev); 27348c2ecf20Sopenharmony_ci if (ret) { 27358c2ecf20Sopenharmony_ci mutex_unlock(&port->port_lock); 27368c2ecf20Sopenharmony_ci goto out; 27378c2ecf20Sopenharmony_ci } 27388c2ecf20Sopenharmony_ci port_napi_disable(port); 27398c2ecf20Sopenharmony_ci mutex_unlock(&port->port_lock); 27408c2ecf20Sopenharmony_ci } 27418c2ecf20Sopenharmony_ci reset_sq_restart_flag(port); 27428c2ecf20Sopenharmony_ci } 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci /* Unregister old memory region */ 27458c2ecf20Sopenharmony_ci ret = ehea_rem_mr(&adapter->mr); 27468c2ecf20Sopenharmony_ci if (ret) { 27478c2ecf20Sopenharmony_ci pr_err("unregister MR failed - driver inoperable!\n"); 27488c2ecf20Sopenharmony_ci goto out; 27498c2ecf20Sopenharmony_ci } 27508c2ecf20Sopenharmony_ci } 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_ci clear_bit(__EHEA_STOP_XFER, &ehea_driver_flags); 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ci list_for_each_entry(adapter, &adapter_list, list) 27558c2ecf20Sopenharmony_ci if (adapter->active_ports) { 27568c2ecf20Sopenharmony_ci /* Register new memory region */ 27578c2ecf20Sopenharmony_ci ret = ehea_reg_kernel_mr(adapter, &adapter->mr); 27588c2ecf20Sopenharmony_ci if (ret) { 27598c2ecf20Sopenharmony_ci pr_err("register MR failed - driver inoperable!\n"); 27608c2ecf20Sopenharmony_ci goto out; 27618c2ecf20Sopenharmony_ci } 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci /* Restart all ports */ 27648c2ecf20Sopenharmony_ci for (i = 0; i < EHEA_MAX_PORTS; i++) { 27658c2ecf20Sopenharmony_ci struct ehea_port *port = adapter->port[i]; 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci if (port) { 27688c2ecf20Sopenharmony_ci struct net_device *dev = port->netdev; 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci if (dev->flags & IFF_UP) { 27718c2ecf20Sopenharmony_ci mutex_lock(&port->port_lock); 27728c2ecf20Sopenharmony_ci ret = ehea_restart_qps(dev); 27738c2ecf20Sopenharmony_ci if (!ret) { 27748c2ecf20Sopenharmony_ci check_sqs(port); 27758c2ecf20Sopenharmony_ci port_napi_enable(port); 27768c2ecf20Sopenharmony_ci netif_tx_wake_all_queues(dev); 27778c2ecf20Sopenharmony_ci } else { 27788c2ecf20Sopenharmony_ci netdev_err(dev, "Unable to restart QPS\n"); 27798c2ecf20Sopenharmony_ci } 27808c2ecf20Sopenharmony_ci mutex_unlock(&port->port_lock); 27818c2ecf20Sopenharmony_ci } 27828c2ecf20Sopenharmony_ci } 27838c2ecf20Sopenharmony_ci } 27848c2ecf20Sopenharmony_ci } 27858c2ecf20Sopenharmony_ci pr_info("re-initializing driver complete\n"); 27868c2ecf20Sopenharmony_ciout: 27878c2ecf20Sopenharmony_ci return; 27888c2ecf20Sopenharmony_ci} 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_cistatic void ehea_tx_watchdog(struct net_device *dev, unsigned int txqueue) 27918c2ecf20Sopenharmony_ci{ 27928c2ecf20Sopenharmony_ci struct ehea_port *port = netdev_priv(dev); 27938c2ecf20Sopenharmony_ci 27948c2ecf20Sopenharmony_ci if (netif_carrier_ok(dev) && 27958c2ecf20Sopenharmony_ci !test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)) 27968c2ecf20Sopenharmony_ci ehea_schedule_port_reset(port); 27978c2ecf20Sopenharmony_ci} 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_cistatic int ehea_sense_adapter_attr(struct ehea_adapter *adapter) 28008c2ecf20Sopenharmony_ci{ 28018c2ecf20Sopenharmony_ci struct hcp_query_ehea *cb; 28028c2ecf20Sopenharmony_ci u64 hret; 28038c2ecf20Sopenharmony_ci int ret; 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_ci cb = (void *)get_zeroed_page(GFP_KERNEL); 28068c2ecf20Sopenharmony_ci if (!cb) { 28078c2ecf20Sopenharmony_ci ret = -ENOMEM; 28088c2ecf20Sopenharmony_ci goto out; 28098c2ecf20Sopenharmony_ci } 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci hret = ehea_h_query_ehea(adapter->handle, cb); 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_ci if (hret != H_SUCCESS) { 28148c2ecf20Sopenharmony_ci ret = -EIO; 28158c2ecf20Sopenharmony_ci goto out_herr; 28168c2ecf20Sopenharmony_ci } 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_ci adapter->max_mc_mac = cb->max_mc_mac - 1; 28198c2ecf20Sopenharmony_ci ret = 0; 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_ciout_herr: 28228c2ecf20Sopenharmony_ci free_page((unsigned long)cb); 28238c2ecf20Sopenharmony_ciout: 28248c2ecf20Sopenharmony_ci return ret; 28258c2ecf20Sopenharmony_ci} 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_cistatic int ehea_get_jumboframe_status(struct ehea_port *port, int *jumbo) 28288c2ecf20Sopenharmony_ci{ 28298c2ecf20Sopenharmony_ci struct hcp_ehea_port_cb4 *cb4; 28308c2ecf20Sopenharmony_ci u64 hret; 28318c2ecf20Sopenharmony_ci int ret = 0; 28328c2ecf20Sopenharmony_ci 28338c2ecf20Sopenharmony_ci *jumbo = 0; 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_ci /* (Try to) enable *jumbo frames */ 28368c2ecf20Sopenharmony_ci cb4 = (void *)get_zeroed_page(GFP_KERNEL); 28378c2ecf20Sopenharmony_ci if (!cb4) { 28388c2ecf20Sopenharmony_ci pr_err("no mem for cb4\n"); 28398c2ecf20Sopenharmony_ci ret = -ENOMEM; 28408c2ecf20Sopenharmony_ci goto out; 28418c2ecf20Sopenharmony_ci } else { 28428c2ecf20Sopenharmony_ci hret = ehea_h_query_ehea_port(port->adapter->handle, 28438c2ecf20Sopenharmony_ci port->logical_port_id, 28448c2ecf20Sopenharmony_ci H_PORT_CB4, 28458c2ecf20Sopenharmony_ci H_PORT_CB4_JUMBO, cb4); 28468c2ecf20Sopenharmony_ci if (hret == H_SUCCESS) { 28478c2ecf20Sopenharmony_ci if (cb4->jumbo_frame) 28488c2ecf20Sopenharmony_ci *jumbo = 1; 28498c2ecf20Sopenharmony_ci else { 28508c2ecf20Sopenharmony_ci cb4->jumbo_frame = 1; 28518c2ecf20Sopenharmony_ci hret = ehea_h_modify_ehea_port(port->adapter-> 28528c2ecf20Sopenharmony_ci handle, 28538c2ecf20Sopenharmony_ci port-> 28548c2ecf20Sopenharmony_ci logical_port_id, 28558c2ecf20Sopenharmony_ci H_PORT_CB4, 28568c2ecf20Sopenharmony_ci H_PORT_CB4_JUMBO, 28578c2ecf20Sopenharmony_ci cb4); 28588c2ecf20Sopenharmony_ci if (hret == H_SUCCESS) 28598c2ecf20Sopenharmony_ci *jumbo = 1; 28608c2ecf20Sopenharmony_ci } 28618c2ecf20Sopenharmony_ci } else 28628c2ecf20Sopenharmony_ci ret = -EINVAL; 28638c2ecf20Sopenharmony_ci 28648c2ecf20Sopenharmony_ci free_page((unsigned long)cb4); 28658c2ecf20Sopenharmony_ci } 28668c2ecf20Sopenharmony_ciout: 28678c2ecf20Sopenharmony_ci return ret; 28688c2ecf20Sopenharmony_ci} 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_cistatic ssize_t ehea_show_port_id(struct device *dev, 28718c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 28728c2ecf20Sopenharmony_ci{ 28738c2ecf20Sopenharmony_ci struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev); 28748c2ecf20Sopenharmony_ci return sprintf(buf, "%d", port->logical_port_id); 28758c2ecf20Sopenharmony_ci} 28768c2ecf20Sopenharmony_ci 28778c2ecf20Sopenharmony_cistatic DEVICE_ATTR(log_port_id, 0444, ehea_show_port_id, NULL); 28788c2ecf20Sopenharmony_ci 28798c2ecf20Sopenharmony_cistatic void logical_port_release(struct device *dev) 28808c2ecf20Sopenharmony_ci{ 28818c2ecf20Sopenharmony_ci struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev); 28828c2ecf20Sopenharmony_ci of_node_put(port->ofdev.dev.of_node); 28838c2ecf20Sopenharmony_ci} 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_cistatic struct device *ehea_register_port(struct ehea_port *port, 28868c2ecf20Sopenharmony_ci struct device_node *dn) 28878c2ecf20Sopenharmony_ci{ 28888c2ecf20Sopenharmony_ci int ret; 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_ci port->ofdev.dev.of_node = of_node_get(dn); 28918c2ecf20Sopenharmony_ci port->ofdev.dev.parent = &port->adapter->ofdev->dev; 28928c2ecf20Sopenharmony_ci port->ofdev.dev.bus = &ibmebus_bus_type; 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci dev_set_name(&port->ofdev.dev, "port%d", port_name_cnt++); 28958c2ecf20Sopenharmony_ci port->ofdev.dev.release = logical_port_release; 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_ci ret = of_device_register(&port->ofdev); 28988c2ecf20Sopenharmony_ci if (ret) { 28998c2ecf20Sopenharmony_ci pr_err("failed to register device. ret=%d\n", ret); 29008c2ecf20Sopenharmony_ci put_device(&port->ofdev.dev); 29018c2ecf20Sopenharmony_ci goto out; 29028c2ecf20Sopenharmony_ci } 29038c2ecf20Sopenharmony_ci 29048c2ecf20Sopenharmony_ci ret = device_create_file(&port->ofdev.dev, &dev_attr_log_port_id); 29058c2ecf20Sopenharmony_ci if (ret) { 29068c2ecf20Sopenharmony_ci pr_err("failed to register attributes, ret=%d\n", ret); 29078c2ecf20Sopenharmony_ci goto out_unreg_of_dev; 29088c2ecf20Sopenharmony_ci } 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ci return &port->ofdev.dev; 29118c2ecf20Sopenharmony_ci 29128c2ecf20Sopenharmony_ciout_unreg_of_dev: 29138c2ecf20Sopenharmony_ci of_device_unregister(&port->ofdev); 29148c2ecf20Sopenharmony_ciout: 29158c2ecf20Sopenharmony_ci return NULL; 29168c2ecf20Sopenharmony_ci} 29178c2ecf20Sopenharmony_ci 29188c2ecf20Sopenharmony_cistatic void ehea_unregister_port(struct ehea_port *port) 29198c2ecf20Sopenharmony_ci{ 29208c2ecf20Sopenharmony_ci device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id); 29218c2ecf20Sopenharmony_ci of_device_unregister(&port->ofdev); 29228c2ecf20Sopenharmony_ci} 29238c2ecf20Sopenharmony_ci 29248c2ecf20Sopenharmony_cistatic const struct net_device_ops ehea_netdev_ops = { 29258c2ecf20Sopenharmony_ci .ndo_open = ehea_open, 29268c2ecf20Sopenharmony_ci .ndo_stop = ehea_stop, 29278c2ecf20Sopenharmony_ci .ndo_start_xmit = ehea_start_xmit, 29288c2ecf20Sopenharmony_ci .ndo_get_stats64 = ehea_get_stats64, 29298c2ecf20Sopenharmony_ci .ndo_set_mac_address = ehea_set_mac_addr, 29308c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 29318c2ecf20Sopenharmony_ci .ndo_set_rx_mode = ehea_set_multicast_list, 29328c2ecf20Sopenharmony_ci .ndo_vlan_rx_add_vid = ehea_vlan_rx_add_vid, 29338c2ecf20Sopenharmony_ci .ndo_vlan_rx_kill_vid = ehea_vlan_rx_kill_vid, 29348c2ecf20Sopenharmony_ci .ndo_tx_timeout = ehea_tx_watchdog, 29358c2ecf20Sopenharmony_ci}; 29368c2ecf20Sopenharmony_ci 29378c2ecf20Sopenharmony_cistatic struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, 29388c2ecf20Sopenharmony_ci u32 logical_port_id, 29398c2ecf20Sopenharmony_ci struct device_node *dn) 29408c2ecf20Sopenharmony_ci{ 29418c2ecf20Sopenharmony_ci int ret; 29428c2ecf20Sopenharmony_ci struct net_device *dev; 29438c2ecf20Sopenharmony_ci struct ehea_port *port; 29448c2ecf20Sopenharmony_ci struct device *port_dev; 29458c2ecf20Sopenharmony_ci int jumbo; 29468c2ecf20Sopenharmony_ci 29478c2ecf20Sopenharmony_ci /* allocate memory for the port structures */ 29488c2ecf20Sopenharmony_ci dev = alloc_etherdev_mq(sizeof(struct ehea_port), EHEA_MAX_PORT_RES); 29498c2ecf20Sopenharmony_ci 29508c2ecf20Sopenharmony_ci if (!dev) { 29518c2ecf20Sopenharmony_ci ret = -ENOMEM; 29528c2ecf20Sopenharmony_ci goto out_err; 29538c2ecf20Sopenharmony_ci } 29548c2ecf20Sopenharmony_ci 29558c2ecf20Sopenharmony_ci port = netdev_priv(dev); 29568c2ecf20Sopenharmony_ci 29578c2ecf20Sopenharmony_ci mutex_init(&port->port_lock); 29588c2ecf20Sopenharmony_ci port->state = EHEA_PORT_DOWN; 29598c2ecf20Sopenharmony_ci port->sig_comp_iv = sq_entries / 10; 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_ci port->adapter = adapter; 29628c2ecf20Sopenharmony_ci port->netdev = dev; 29638c2ecf20Sopenharmony_ci port->logical_port_id = logical_port_id; 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT); 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL); 29688c2ecf20Sopenharmony_ci if (!port->mc_list) { 29698c2ecf20Sopenharmony_ci ret = -ENOMEM; 29708c2ecf20Sopenharmony_ci goto out_free_ethdev; 29718c2ecf20Sopenharmony_ci } 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&port->mc_list->list); 29748c2ecf20Sopenharmony_ci 29758c2ecf20Sopenharmony_ci ret = ehea_sense_port_attr(port); 29768c2ecf20Sopenharmony_ci if (ret) 29778c2ecf20Sopenharmony_ci goto out_free_mc_list; 29788c2ecf20Sopenharmony_ci 29798c2ecf20Sopenharmony_ci netif_set_real_num_rx_queues(dev, port->num_def_qps); 29808c2ecf20Sopenharmony_ci netif_set_real_num_tx_queues(dev, port->num_def_qps); 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci port_dev = ehea_register_port(port, dn); 29838c2ecf20Sopenharmony_ci if (!port_dev) 29848c2ecf20Sopenharmony_ci goto out_free_mc_list; 29858c2ecf20Sopenharmony_ci 29868c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, port_dev); 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_ci /* initialize net_device structure */ 29898c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, &port->mac_addr, ETH_ALEN); 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_ci dev->netdev_ops = &ehea_netdev_ops; 29928c2ecf20Sopenharmony_ci ehea_set_ethtool_ops(dev); 29938c2ecf20Sopenharmony_ci 29948c2ecf20Sopenharmony_ci dev->hw_features = NETIF_F_SG | NETIF_F_TSO | 29958c2ecf20Sopenharmony_ci NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_CTAG_TX; 29968c2ecf20Sopenharmony_ci dev->features = NETIF_F_SG | NETIF_F_TSO | 29978c2ecf20Sopenharmony_ci NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | 29988c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | 29998c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXCSUM; 30008c2ecf20Sopenharmony_ci dev->vlan_features = NETIF_F_SG | NETIF_F_TSO | NETIF_F_HIGHDMA | 30018c2ecf20Sopenharmony_ci NETIF_F_IP_CSUM; 30028c2ecf20Sopenharmony_ci dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT; 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci /* MTU range: 68 - 9022 */ 30058c2ecf20Sopenharmony_ci dev->min_mtu = ETH_MIN_MTU; 30068c2ecf20Sopenharmony_ci dev->max_mtu = EHEA_MAX_PACKET_SIZE; 30078c2ecf20Sopenharmony_ci 30088c2ecf20Sopenharmony_ci INIT_WORK(&port->reset_task, ehea_reset_port); 30098c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&port->stats_work, ehea_update_stats); 30108c2ecf20Sopenharmony_ci 30118c2ecf20Sopenharmony_ci init_waitqueue_head(&port->swqe_avail_wq); 30128c2ecf20Sopenharmony_ci init_waitqueue_head(&port->restart_wq); 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci ret = register_netdev(dev); 30158c2ecf20Sopenharmony_ci if (ret) { 30168c2ecf20Sopenharmony_ci pr_err("register_netdev failed. ret=%d\n", ret); 30178c2ecf20Sopenharmony_ci goto out_unreg_port; 30188c2ecf20Sopenharmony_ci } 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci ret = ehea_get_jumboframe_status(port, &jumbo); 30218c2ecf20Sopenharmony_ci if (ret) 30228c2ecf20Sopenharmony_ci netdev_err(dev, "failed determining jumbo frame status\n"); 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_ci netdev_info(dev, "Jumbo frames are %sabled\n", 30258c2ecf20Sopenharmony_ci jumbo == 1 ? "en" : "dis"); 30268c2ecf20Sopenharmony_ci 30278c2ecf20Sopenharmony_ci adapter->active_ports++; 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci return port; 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_ciout_unreg_port: 30328c2ecf20Sopenharmony_ci ehea_unregister_port(port); 30338c2ecf20Sopenharmony_ci 30348c2ecf20Sopenharmony_ciout_free_mc_list: 30358c2ecf20Sopenharmony_ci kfree(port->mc_list); 30368c2ecf20Sopenharmony_ci 30378c2ecf20Sopenharmony_ciout_free_ethdev: 30388c2ecf20Sopenharmony_ci free_netdev(dev); 30398c2ecf20Sopenharmony_ci 30408c2ecf20Sopenharmony_ciout_err: 30418c2ecf20Sopenharmony_ci pr_err("setting up logical port with id=%d failed, ret=%d\n", 30428c2ecf20Sopenharmony_ci logical_port_id, ret); 30438c2ecf20Sopenharmony_ci return NULL; 30448c2ecf20Sopenharmony_ci} 30458c2ecf20Sopenharmony_ci 30468c2ecf20Sopenharmony_cistatic void ehea_shutdown_single_port(struct ehea_port *port) 30478c2ecf20Sopenharmony_ci{ 30488c2ecf20Sopenharmony_ci struct ehea_adapter *adapter = port->adapter; 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_ci cancel_work_sync(&port->reset_task); 30518c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&port->stats_work); 30528c2ecf20Sopenharmony_ci unregister_netdev(port->netdev); 30538c2ecf20Sopenharmony_ci ehea_unregister_port(port); 30548c2ecf20Sopenharmony_ci kfree(port->mc_list); 30558c2ecf20Sopenharmony_ci free_netdev(port->netdev); 30568c2ecf20Sopenharmony_ci adapter->active_ports--; 30578c2ecf20Sopenharmony_ci} 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_cistatic int ehea_setup_ports(struct ehea_adapter *adapter) 30608c2ecf20Sopenharmony_ci{ 30618c2ecf20Sopenharmony_ci struct device_node *lhea_dn; 30628c2ecf20Sopenharmony_ci struct device_node *eth_dn = NULL; 30638c2ecf20Sopenharmony_ci 30648c2ecf20Sopenharmony_ci const u32 *dn_log_port_id; 30658c2ecf20Sopenharmony_ci int i = 0; 30668c2ecf20Sopenharmony_ci 30678c2ecf20Sopenharmony_ci lhea_dn = adapter->ofdev->dev.of_node; 30688c2ecf20Sopenharmony_ci while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) { 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no", 30718c2ecf20Sopenharmony_ci NULL); 30728c2ecf20Sopenharmony_ci if (!dn_log_port_id) { 30738c2ecf20Sopenharmony_ci pr_err("bad device node: eth_dn name=%pOF\n", eth_dn); 30748c2ecf20Sopenharmony_ci continue; 30758c2ecf20Sopenharmony_ci } 30768c2ecf20Sopenharmony_ci 30778c2ecf20Sopenharmony_ci if (ehea_add_adapter_mr(adapter)) { 30788c2ecf20Sopenharmony_ci pr_err("creating MR failed\n"); 30798c2ecf20Sopenharmony_ci of_node_put(eth_dn); 30808c2ecf20Sopenharmony_ci return -EIO; 30818c2ecf20Sopenharmony_ci } 30828c2ecf20Sopenharmony_ci 30838c2ecf20Sopenharmony_ci adapter->port[i] = ehea_setup_single_port(adapter, 30848c2ecf20Sopenharmony_ci *dn_log_port_id, 30858c2ecf20Sopenharmony_ci eth_dn); 30868c2ecf20Sopenharmony_ci if (adapter->port[i]) 30878c2ecf20Sopenharmony_ci netdev_info(adapter->port[i]->netdev, 30888c2ecf20Sopenharmony_ci "logical port id #%d\n", *dn_log_port_id); 30898c2ecf20Sopenharmony_ci else 30908c2ecf20Sopenharmony_ci ehea_remove_adapter_mr(adapter); 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_ci i++; 30938c2ecf20Sopenharmony_ci } 30948c2ecf20Sopenharmony_ci return 0; 30958c2ecf20Sopenharmony_ci} 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_cistatic struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter, 30988c2ecf20Sopenharmony_ci u32 logical_port_id) 30998c2ecf20Sopenharmony_ci{ 31008c2ecf20Sopenharmony_ci struct device_node *lhea_dn; 31018c2ecf20Sopenharmony_ci struct device_node *eth_dn = NULL; 31028c2ecf20Sopenharmony_ci const u32 *dn_log_port_id; 31038c2ecf20Sopenharmony_ci 31048c2ecf20Sopenharmony_ci lhea_dn = adapter->ofdev->dev.of_node; 31058c2ecf20Sopenharmony_ci while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) { 31068c2ecf20Sopenharmony_ci 31078c2ecf20Sopenharmony_ci dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no", 31088c2ecf20Sopenharmony_ci NULL); 31098c2ecf20Sopenharmony_ci if (dn_log_port_id) 31108c2ecf20Sopenharmony_ci if (*dn_log_port_id == logical_port_id) 31118c2ecf20Sopenharmony_ci return eth_dn; 31128c2ecf20Sopenharmony_ci } 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_ci return NULL; 31158c2ecf20Sopenharmony_ci} 31168c2ecf20Sopenharmony_ci 31178c2ecf20Sopenharmony_cistatic ssize_t ehea_probe_port(struct device *dev, 31188c2ecf20Sopenharmony_ci struct device_attribute *attr, 31198c2ecf20Sopenharmony_ci const char *buf, size_t count) 31208c2ecf20Sopenharmony_ci{ 31218c2ecf20Sopenharmony_ci struct ehea_adapter *adapter = dev_get_drvdata(dev); 31228c2ecf20Sopenharmony_ci struct ehea_port *port; 31238c2ecf20Sopenharmony_ci struct device_node *eth_dn = NULL; 31248c2ecf20Sopenharmony_ci int i; 31258c2ecf20Sopenharmony_ci 31268c2ecf20Sopenharmony_ci u32 logical_port_id; 31278c2ecf20Sopenharmony_ci 31288c2ecf20Sopenharmony_ci sscanf(buf, "%d", &logical_port_id); 31298c2ecf20Sopenharmony_ci 31308c2ecf20Sopenharmony_ci port = ehea_get_port(adapter, logical_port_id); 31318c2ecf20Sopenharmony_ci 31328c2ecf20Sopenharmony_ci if (port) { 31338c2ecf20Sopenharmony_ci netdev_info(port->netdev, "adding port with logical port id=%d failed: port already configured\n", 31348c2ecf20Sopenharmony_ci logical_port_id); 31358c2ecf20Sopenharmony_ci return -EINVAL; 31368c2ecf20Sopenharmony_ci } 31378c2ecf20Sopenharmony_ci 31388c2ecf20Sopenharmony_ci eth_dn = ehea_get_eth_dn(adapter, logical_port_id); 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci if (!eth_dn) { 31418c2ecf20Sopenharmony_ci pr_info("no logical port with id %d found\n", logical_port_id); 31428c2ecf20Sopenharmony_ci return -EINVAL; 31438c2ecf20Sopenharmony_ci } 31448c2ecf20Sopenharmony_ci 31458c2ecf20Sopenharmony_ci if (ehea_add_adapter_mr(adapter)) { 31468c2ecf20Sopenharmony_ci pr_err("creating MR failed\n"); 31478c2ecf20Sopenharmony_ci of_node_put(eth_dn); 31488c2ecf20Sopenharmony_ci return -EIO; 31498c2ecf20Sopenharmony_ci } 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_ci port = ehea_setup_single_port(adapter, logical_port_id, eth_dn); 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_ci of_node_put(eth_dn); 31548c2ecf20Sopenharmony_ci 31558c2ecf20Sopenharmony_ci if (port) { 31568c2ecf20Sopenharmony_ci for (i = 0; i < EHEA_MAX_PORTS; i++) 31578c2ecf20Sopenharmony_ci if (!adapter->port[i]) { 31588c2ecf20Sopenharmony_ci adapter->port[i] = port; 31598c2ecf20Sopenharmony_ci break; 31608c2ecf20Sopenharmony_ci } 31618c2ecf20Sopenharmony_ci 31628c2ecf20Sopenharmony_ci netdev_info(port->netdev, "added: (logical port id=%d)\n", 31638c2ecf20Sopenharmony_ci logical_port_id); 31648c2ecf20Sopenharmony_ci } else { 31658c2ecf20Sopenharmony_ci ehea_remove_adapter_mr(adapter); 31668c2ecf20Sopenharmony_ci return -EIO; 31678c2ecf20Sopenharmony_ci } 31688c2ecf20Sopenharmony_ci 31698c2ecf20Sopenharmony_ci return (ssize_t) count; 31708c2ecf20Sopenharmony_ci} 31718c2ecf20Sopenharmony_ci 31728c2ecf20Sopenharmony_cistatic ssize_t ehea_remove_port(struct device *dev, 31738c2ecf20Sopenharmony_ci struct device_attribute *attr, 31748c2ecf20Sopenharmony_ci const char *buf, size_t count) 31758c2ecf20Sopenharmony_ci{ 31768c2ecf20Sopenharmony_ci struct ehea_adapter *adapter = dev_get_drvdata(dev); 31778c2ecf20Sopenharmony_ci struct ehea_port *port; 31788c2ecf20Sopenharmony_ci int i; 31798c2ecf20Sopenharmony_ci u32 logical_port_id; 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_ci sscanf(buf, "%d", &logical_port_id); 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci port = ehea_get_port(adapter, logical_port_id); 31848c2ecf20Sopenharmony_ci 31858c2ecf20Sopenharmony_ci if (port) { 31868c2ecf20Sopenharmony_ci netdev_info(port->netdev, "removed: (logical port id=%d)\n", 31878c2ecf20Sopenharmony_ci logical_port_id); 31888c2ecf20Sopenharmony_ci 31898c2ecf20Sopenharmony_ci ehea_shutdown_single_port(port); 31908c2ecf20Sopenharmony_ci 31918c2ecf20Sopenharmony_ci for (i = 0; i < EHEA_MAX_PORTS; i++) 31928c2ecf20Sopenharmony_ci if (adapter->port[i] == port) { 31938c2ecf20Sopenharmony_ci adapter->port[i] = NULL; 31948c2ecf20Sopenharmony_ci break; 31958c2ecf20Sopenharmony_ci } 31968c2ecf20Sopenharmony_ci } else { 31978c2ecf20Sopenharmony_ci pr_err("removing port with logical port id=%d failed. port not configured.\n", 31988c2ecf20Sopenharmony_ci logical_port_id); 31998c2ecf20Sopenharmony_ci return -EINVAL; 32008c2ecf20Sopenharmony_ci } 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_ci ehea_remove_adapter_mr(adapter); 32038c2ecf20Sopenharmony_ci 32048c2ecf20Sopenharmony_ci return (ssize_t) count; 32058c2ecf20Sopenharmony_ci} 32068c2ecf20Sopenharmony_ci 32078c2ecf20Sopenharmony_cistatic DEVICE_ATTR(probe_port, 0200, NULL, ehea_probe_port); 32088c2ecf20Sopenharmony_cistatic DEVICE_ATTR(remove_port, 0200, NULL, ehea_remove_port); 32098c2ecf20Sopenharmony_ci 32108c2ecf20Sopenharmony_cistatic int ehea_create_device_sysfs(struct platform_device *dev) 32118c2ecf20Sopenharmony_ci{ 32128c2ecf20Sopenharmony_ci int ret = device_create_file(&dev->dev, &dev_attr_probe_port); 32138c2ecf20Sopenharmony_ci if (ret) 32148c2ecf20Sopenharmony_ci goto out; 32158c2ecf20Sopenharmony_ci 32168c2ecf20Sopenharmony_ci ret = device_create_file(&dev->dev, &dev_attr_remove_port); 32178c2ecf20Sopenharmony_ciout: 32188c2ecf20Sopenharmony_ci return ret; 32198c2ecf20Sopenharmony_ci} 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_cistatic void ehea_remove_device_sysfs(struct platform_device *dev) 32228c2ecf20Sopenharmony_ci{ 32238c2ecf20Sopenharmony_ci device_remove_file(&dev->dev, &dev_attr_probe_port); 32248c2ecf20Sopenharmony_ci device_remove_file(&dev->dev, &dev_attr_remove_port); 32258c2ecf20Sopenharmony_ci} 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_cistatic int ehea_reboot_notifier(struct notifier_block *nb, 32288c2ecf20Sopenharmony_ci unsigned long action, void *unused) 32298c2ecf20Sopenharmony_ci{ 32308c2ecf20Sopenharmony_ci if (action == SYS_RESTART) { 32318c2ecf20Sopenharmony_ci pr_info("Reboot: freeing all eHEA resources\n"); 32328c2ecf20Sopenharmony_ci ibmebus_unregister_driver(&ehea_driver); 32338c2ecf20Sopenharmony_ci } 32348c2ecf20Sopenharmony_ci return NOTIFY_DONE; 32358c2ecf20Sopenharmony_ci} 32368c2ecf20Sopenharmony_ci 32378c2ecf20Sopenharmony_cistatic struct notifier_block ehea_reboot_nb = { 32388c2ecf20Sopenharmony_ci .notifier_call = ehea_reboot_notifier, 32398c2ecf20Sopenharmony_ci}; 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_cistatic int ehea_mem_notifier(struct notifier_block *nb, 32428c2ecf20Sopenharmony_ci unsigned long action, void *data) 32438c2ecf20Sopenharmony_ci{ 32448c2ecf20Sopenharmony_ci int ret = NOTIFY_BAD; 32458c2ecf20Sopenharmony_ci struct memory_notify *arg = data; 32468c2ecf20Sopenharmony_ci 32478c2ecf20Sopenharmony_ci mutex_lock(&dlpar_mem_lock); 32488c2ecf20Sopenharmony_ci 32498c2ecf20Sopenharmony_ci switch (action) { 32508c2ecf20Sopenharmony_ci case MEM_CANCEL_OFFLINE: 32518c2ecf20Sopenharmony_ci pr_info("memory offlining canceled"); 32528c2ecf20Sopenharmony_ci fallthrough; /* re-add canceled memory block */ 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_ci case MEM_ONLINE: 32558c2ecf20Sopenharmony_ci pr_info("memory is going online"); 32568c2ecf20Sopenharmony_ci set_bit(__EHEA_STOP_XFER, &ehea_driver_flags); 32578c2ecf20Sopenharmony_ci if (ehea_add_sect_bmap(arg->start_pfn, arg->nr_pages)) 32588c2ecf20Sopenharmony_ci goto out_unlock; 32598c2ecf20Sopenharmony_ci ehea_rereg_mrs(); 32608c2ecf20Sopenharmony_ci break; 32618c2ecf20Sopenharmony_ci 32628c2ecf20Sopenharmony_ci case MEM_GOING_OFFLINE: 32638c2ecf20Sopenharmony_ci pr_info("memory is going offline"); 32648c2ecf20Sopenharmony_ci set_bit(__EHEA_STOP_XFER, &ehea_driver_flags); 32658c2ecf20Sopenharmony_ci if (ehea_rem_sect_bmap(arg->start_pfn, arg->nr_pages)) 32668c2ecf20Sopenharmony_ci goto out_unlock; 32678c2ecf20Sopenharmony_ci ehea_rereg_mrs(); 32688c2ecf20Sopenharmony_ci break; 32698c2ecf20Sopenharmony_ci 32708c2ecf20Sopenharmony_ci default: 32718c2ecf20Sopenharmony_ci break; 32728c2ecf20Sopenharmony_ci } 32738c2ecf20Sopenharmony_ci 32748c2ecf20Sopenharmony_ci ehea_update_firmware_handles(); 32758c2ecf20Sopenharmony_ci ret = NOTIFY_OK; 32768c2ecf20Sopenharmony_ci 32778c2ecf20Sopenharmony_ciout_unlock: 32788c2ecf20Sopenharmony_ci mutex_unlock(&dlpar_mem_lock); 32798c2ecf20Sopenharmony_ci return ret; 32808c2ecf20Sopenharmony_ci} 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_cistatic struct notifier_block ehea_mem_nb = { 32838c2ecf20Sopenharmony_ci .notifier_call = ehea_mem_notifier, 32848c2ecf20Sopenharmony_ci}; 32858c2ecf20Sopenharmony_ci 32868c2ecf20Sopenharmony_cistatic void ehea_crash_handler(void) 32878c2ecf20Sopenharmony_ci{ 32888c2ecf20Sopenharmony_ci int i; 32898c2ecf20Sopenharmony_ci 32908c2ecf20Sopenharmony_ci if (ehea_fw_handles.arr) 32918c2ecf20Sopenharmony_ci for (i = 0; i < ehea_fw_handles.num_entries; i++) 32928c2ecf20Sopenharmony_ci ehea_h_free_resource(ehea_fw_handles.arr[i].adh, 32938c2ecf20Sopenharmony_ci ehea_fw_handles.arr[i].fwh, 32948c2ecf20Sopenharmony_ci FORCE_FREE); 32958c2ecf20Sopenharmony_ci 32968c2ecf20Sopenharmony_ci if (ehea_bcmc_regs.arr) 32978c2ecf20Sopenharmony_ci for (i = 0; i < ehea_bcmc_regs.num_entries; i++) 32988c2ecf20Sopenharmony_ci ehea_h_reg_dereg_bcmc(ehea_bcmc_regs.arr[i].adh, 32998c2ecf20Sopenharmony_ci ehea_bcmc_regs.arr[i].port_id, 33008c2ecf20Sopenharmony_ci ehea_bcmc_regs.arr[i].reg_type, 33018c2ecf20Sopenharmony_ci ehea_bcmc_regs.arr[i].macaddr, 33028c2ecf20Sopenharmony_ci 0, H_DEREG_BCMC); 33038c2ecf20Sopenharmony_ci} 33048c2ecf20Sopenharmony_ci 33058c2ecf20Sopenharmony_cistatic atomic_t ehea_memory_hooks_registered; 33068c2ecf20Sopenharmony_ci 33078c2ecf20Sopenharmony_ci/* Register memory hooks on probe of first adapter */ 33088c2ecf20Sopenharmony_cistatic int ehea_register_memory_hooks(void) 33098c2ecf20Sopenharmony_ci{ 33108c2ecf20Sopenharmony_ci int ret = 0; 33118c2ecf20Sopenharmony_ci 33128c2ecf20Sopenharmony_ci if (atomic_inc_return(&ehea_memory_hooks_registered) > 1) 33138c2ecf20Sopenharmony_ci return 0; 33148c2ecf20Sopenharmony_ci 33158c2ecf20Sopenharmony_ci ret = ehea_create_busmap(); 33168c2ecf20Sopenharmony_ci if (ret) { 33178c2ecf20Sopenharmony_ci pr_info("ehea_create_busmap failed\n"); 33188c2ecf20Sopenharmony_ci goto out; 33198c2ecf20Sopenharmony_ci } 33208c2ecf20Sopenharmony_ci 33218c2ecf20Sopenharmony_ci ret = register_reboot_notifier(&ehea_reboot_nb); 33228c2ecf20Sopenharmony_ci if (ret) { 33238c2ecf20Sopenharmony_ci pr_info("register_reboot_notifier failed\n"); 33248c2ecf20Sopenharmony_ci goto out; 33258c2ecf20Sopenharmony_ci } 33268c2ecf20Sopenharmony_ci 33278c2ecf20Sopenharmony_ci ret = register_memory_notifier(&ehea_mem_nb); 33288c2ecf20Sopenharmony_ci if (ret) { 33298c2ecf20Sopenharmony_ci pr_info("register_memory_notifier failed\n"); 33308c2ecf20Sopenharmony_ci goto out2; 33318c2ecf20Sopenharmony_ci } 33328c2ecf20Sopenharmony_ci 33338c2ecf20Sopenharmony_ci ret = crash_shutdown_register(ehea_crash_handler); 33348c2ecf20Sopenharmony_ci if (ret) { 33358c2ecf20Sopenharmony_ci pr_info("crash_shutdown_register failed\n"); 33368c2ecf20Sopenharmony_ci goto out3; 33378c2ecf20Sopenharmony_ci } 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_ci return 0; 33408c2ecf20Sopenharmony_ci 33418c2ecf20Sopenharmony_ciout3: 33428c2ecf20Sopenharmony_ci unregister_memory_notifier(&ehea_mem_nb); 33438c2ecf20Sopenharmony_ciout2: 33448c2ecf20Sopenharmony_ci unregister_reboot_notifier(&ehea_reboot_nb); 33458c2ecf20Sopenharmony_ciout: 33468c2ecf20Sopenharmony_ci atomic_dec(&ehea_memory_hooks_registered); 33478c2ecf20Sopenharmony_ci return ret; 33488c2ecf20Sopenharmony_ci} 33498c2ecf20Sopenharmony_ci 33508c2ecf20Sopenharmony_cistatic void ehea_unregister_memory_hooks(void) 33518c2ecf20Sopenharmony_ci{ 33528c2ecf20Sopenharmony_ci /* Only remove the hooks if we've registered them */ 33538c2ecf20Sopenharmony_ci if (atomic_read(&ehea_memory_hooks_registered) == 0) 33548c2ecf20Sopenharmony_ci return; 33558c2ecf20Sopenharmony_ci 33568c2ecf20Sopenharmony_ci unregister_reboot_notifier(&ehea_reboot_nb); 33578c2ecf20Sopenharmony_ci if (crash_shutdown_unregister(ehea_crash_handler)) 33588c2ecf20Sopenharmony_ci pr_info("failed unregistering crash handler\n"); 33598c2ecf20Sopenharmony_ci unregister_memory_notifier(&ehea_mem_nb); 33608c2ecf20Sopenharmony_ci} 33618c2ecf20Sopenharmony_ci 33628c2ecf20Sopenharmony_cistatic int ehea_probe_adapter(struct platform_device *dev) 33638c2ecf20Sopenharmony_ci{ 33648c2ecf20Sopenharmony_ci struct ehea_adapter *adapter; 33658c2ecf20Sopenharmony_ci const u64 *adapter_handle; 33668c2ecf20Sopenharmony_ci int ret; 33678c2ecf20Sopenharmony_ci int i; 33688c2ecf20Sopenharmony_ci 33698c2ecf20Sopenharmony_ci ret = ehea_register_memory_hooks(); 33708c2ecf20Sopenharmony_ci if (ret) 33718c2ecf20Sopenharmony_ci return ret; 33728c2ecf20Sopenharmony_ci 33738c2ecf20Sopenharmony_ci if (!dev || !dev->dev.of_node) { 33748c2ecf20Sopenharmony_ci pr_err("Invalid ibmebus device probed\n"); 33758c2ecf20Sopenharmony_ci return -EINVAL; 33768c2ecf20Sopenharmony_ci } 33778c2ecf20Sopenharmony_ci 33788c2ecf20Sopenharmony_ci adapter = devm_kzalloc(&dev->dev, sizeof(*adapter), GFP_KERNEL); 33798c2ecf20Sopenharmony_ci if (!adapter) { 33808c2ecf20Sopenharmony_ci ret = -ENOMEM; 33818c2ecf20Sopenharmony_ci dev_err(&dev->dev, "no mem for ehea_adapter\n"); 33828c2ecf20Sopenharmony_ci goto out; 33838c2ecf20Sopenharmony_ci } 33848c2ecf20Sopenharmony_ci 33858c2ecf20Sopenharmony_ci list_add(&adapter->list, &adapter_list); 33868c2ecf20Sopenharmony_ci 33878c2ecf20Sopenharmony_ci adapter->ofdev = dev; 33888c2ecf20Sopenharmony_ci 33898c2ecf20Sopenharmony_ci adapter_handle = of_get_property(dev->dev.of_node, "ibm,hea-handle", 33908c2ecf20Sopenharmony_ci NULL); 33918c2ecf20Sopenharmony_ci if (adapter_handle) 33928c2ecf20Sopenharmony_ci adapter->handle = *adapter_handle; 33938c2ecf20Sopenharmony_ci 33948c2ecf20Sopenharmony_ci if (!adapter->handle) { 33958c2ecf20Sopenharmony_ci dev_err(&dev->dev, "failed getting handle for adapter" 33968c2ecf20Sopenharmony_ci " '%pOF'\n", dev->dev.of_node); 33978c2ecf20Sopenharmony_ci ret = -ENODEV; 33988c2ecf20Sopenharmony_ci goto out_free_ad; 33998c2ecf20Sopenharmony_ci } 34008c2ecf20Sopenharmony_ci 34018c2ecf20Sopenharmony_ci adapter->pd = EHEA_PD_ID; 34028c2ecf20Sopenharmony_ci 34038c2ecf20Sopenharmony_ci platform_set_drvdata(dev, adapter); 34048c2ecf20Sopenharmony_ci 34058c2ecf20Sopenharmony_ci 34068c2ecf20Sopenharmony_ci /* initialize adapter and ports */ 34078c2ecf20Sopenharmony_ci /* get adapter properties */ 34088c2ecf20Sopenharmony_ci ret = ehea_sense_adapter_attr(adapter); 34098c2ecf20Sopenharmony_ci if (ret) { 34108c2ecf20Sopenharmony_ci dev_err(&dev->dev, "sense_adapter_attr failed: %d\n", ret); 34118c2ecf20Sopenharmony_ci goto out_free_ad; 34128c2ecf20Sopenharmony_ci } 34138c2ecf20Sopenharmony_ci 34148c2ecf20Sopenharmony_ci adapter->neq = ehea_create_eq(adapter, 34158c2ecf20Sopenharmony_ci EHEA_NEQ, EHEA_MAX_ENTRIES_EQ, 1); 34168c2ecf20Sopenharmony_ci if (!adapter->neq) { 34178c2ecf20Sopenharmony_ci ret = -EIO; 34188c2ecf20Sopenharmony_ci dev_err(&dev->dev, "NEQ creation failed\n"); 34198c2ecf20Sopenharmony_ci goto out_free_ad; 34208c2ecf20Sopenharmony_ci } 34218c2ecf20Sopenharmony_ci 34228c2ecf20Sopenharmony_ci tasklet_setup(&adapter->neq_tasklet, ehea_neq_tasklet); 34238c2ecf20Sopenharmony_ci 34248c2ecf20Sopenharmony_ci ret = ehea_create_device_sysfs(dev); 34258c2ecf20Sopenharmony_ci if (ret) 34268c2ecf20Sopenharmony_ci goto out_kill_eq; 34278c2ecf20Sopenharmony_ci 34288c2ecf20Sopenharmony_ci ret = ehea_setup_ports(adapter); 34298c2ecf20Sopenharmony_ci if (ret) { 34308c2ecf20Sopenharmony_ci dev_err(&dev->dev, "setup_ports failed\n"); 34318c2ecf20Sopenharmony_ci goto out_rem_dev_sysfs; 34328c2ecf20Sopenharmony_ci } 34338c2ecf20Sopenharmony_ci 34348c2ecf20Sopenharmony_ci ret = ibmebus_request_irq(adapter->neq->attr.ist1, 34358c2ecf20Sopenharmony_ci ehea_interrupt_neq, 0, 34368c2ecf20Sopenharmony_ci "ehea_neq", adapter); 34378c2ecf20Sopenharmony_ci if (ret) { 34388c2ecf20Sopenharmony_ci dev_err(&dev->dev, "requesting NEQ IRQ failed\n"); 34398c2ecf20Sopenharmony_ci goto out_shutdown_ports; 34408c2ecf20Sopenharmony_ci } 34418c2ecf20Sopenharmony_ci 34428c2ecf20Sopenharmony_ci /* Handle any events that might be pending. */ 34438c2ecf20Sopenharmony_ci tasklet_hi_schedule(&adapter->neq_tasklet); 34448c2ecf20Sopenharmony_ci 34458c2ecf20Sopenharmony_ci ret = 0; 34468c2ecf20Sopenharmony_ci goto out; 34478c2ecf20Sopenharmony_ci 34488c2ecf20Sopenharmony_ciout_shutdown_ports: 34498c2ecf20Sopenharmony_ci for (i = 0; i < EHEA_MAX_PORTS; i++) 34508c2ecf20Sopenharmony_ci if (adapter->port[i]) { 34518c2ecf20Sopenharmony_ci ehea_shutdown_single_port(adapter->port[i]); 34528c2ecf20Sopenharmony_ci adapter->port[i] = NULL; 34538c2ecf20Sopenharmony_ci } 34548c2ecf20Sopenharmony_ci 34558c2ecf20Sopenharmony_ciout_rem_dev_sysfs: 34568c2ecf20Sopenharmony_ci ehea_remove_device_sysfs(dev); 34578c2ecf20Sopenharmony_ci 34588c2ecf20Sopenharmony_ciout_kill_eq: 34598c2ecf20Sopenharmony_ci ehea_destroy_eq(adapter->neq); 34608c2ecf20Sopenharmony_ci 34618c2ecf20Sopenharmony_ciout_free_ad: 34628c2ecf20Sopenharmony_ci list_del(&adapter->list); 34638c2ecf20Sopenharmony_ci 34648c2ecf20Sopenharmony_ciout: 34658c2ecf20Sopenharmony_ci ehea_update_firmware_handles(); 34668c2ecf20Sopenharmony_ci 34678c2ecf20Sopenharmony_ci return ret; 34688c2ecf20Sopenharmony_ci} 34698c2ecf20Sopenharmony_ci 34708c2ecf20Sopenharmony_cistatic int ehea_remove(struct platform_device *dev) 34718c2ecf20Sopenharmony_ci{ 34728c2ecf20Sopenharmony_ci struct ehea_adapter *adapter = platform_get_drvdata(dev); 34738c2ecf20Sopenharmony_ci int i; 34748c2ecf20Sopenharmony_ci 34758c2ecf20Sopenharmony_ci for (i = 0; i < EHEA_MAX_PORTS; i++) 34768c2ecf20Sopenharmony_ci if (adapter->port[i]) { 34778c2ecf20Sopenharmony_ci ehea_shutdown_single_port(adapter->port[i]); 34788c2ecf20Sopenharmony_ci adapter->port[i] = NULL; 34798c2ecf20Sopenharmony_ci } 34808c2ecf20Sopenharmony_ci 34818c2ecf20Sopenharmony_ci ehea_remove_device_sysfs(dev); 34828c2ecf20Sopenharmony_ci 34838c2ecf20Sopenharmony_ci ibmebus_free_irq(adapter->neq->attr.ist1, adapter); 34848c2ecf20Sopenharmony_ci tasklet_kill(&adapter->neq_tasklet); 34858c2ecf20Sopenharmony_ci 34868c2ecf20Sopenharmony_ci ehea_destroy_eq(adapter->neq); 34878c2ecf20Sopenharmony_ci ehea_remove_adapter_mr(adapter); 34888c2ecf20Sopenharmony_ci list_del(&adapter->list); 34898c2ecf20Sopenharmony_ci 34908c2ecf20Sopenharmony_ci ehea_update_firmware_handles(); 34918c2ecf20Sopenharmony_ci 34928c2ecf20Sopenharmony_ci return 0; 34938c2ecf20Sopenharmony_ci} 34948c2ecf20Sopenharmony_ci 34958c2ecf20Sopenharmony_cistatic int check_module_parm(void) 34968c2ecf20Sopenharmony_ci{ 34978c2ecf20Sopenharmony_ci int ret = 0; 34988c2ecf20Sopenharmony_ci 34998c2ecf20Sopenharmony_ci if ((rq1_entries < EHEA_MIN_ENTRIES_QP) || 35008c2ecf20Sopenharmony_ci (rq1_entries > EHEA_MAX_ENTRIES_RQ1)) { 35018c2ecf20Sopenharmony_ci pr_info("Bad parameter: rq1_entries\n"); 35028c2ecf20Sopenharmony_ci ret = -EINVAL; 35038c2ecf20Sopenharmony_ci } 35048c2ecf20Sopenharmony_ci if ((rq2_entries < EHEA_MIN_ENTRIES_QP) || 35058c2ecf20Sopenharmony_ci (rq2_entries > EHEA_MAX_ENTRIES_RQ2)) { 35068c2ecf20Sopenharmony_ci pr_info("Bad parameter: rq2_entries\n"); 35078c2ecf20Sopenharmony_ci ret = -EINVAL; 35088c2ecf20Sopenharmony_ci } 35098c2ecf20Sopenharmony_ci if ((rq3_entries < EHEA_MIN_ENTRIES_QP) || 35108c2ecf20Sopenharmony_ci (rq3_entries > EHEA_MAX_ENTRIES_RQ3)) { 35118c2ecf20Sopenharmony_ci pr_info("Bad parameter: rq3_entries\n"); 35128c2ecf20Sopenharmony_ci ret = -EINVAL; 35138c2ecf20Sopenharmony_ci } 35148c2ecf20Sopenharmony_ci if ((sq_entries < EHEA_MIN_ENTRIES_QP) || 35158c2ecf20Sopenharmony_ci (sq_entries > EHEA_MAX_ENTRIES_SQ)) { 35168c2ecf20Sopenharmony_ci pr_info("Bad parameter: sq_entries\n"); 35178c2ecf20Sopenharmony_ci ret = -EINVAL; 35188c2ecf20Sopenharmony_ci } 35198c2ecf20Sopenharmony_ci 35208c2ecf20Sopenharmony_ci return ret; 35218c2ecf20Sopenharmony_ci} 35228c2ecf20Sopenharmony_ci 35238c2ecf20Sopenharmony_cistatic ssize_t capabilities_show(struct device_driver *drv, char *buf) 35248c2ecf20Sopenharmony_ci{ 35258c2ecf20Sopenharmony_ci return sprintf(buf, "%d", EHEA_CAPABILITIES); 35268c2ecf20Sopenharmony_ci} 35278c2ecf20Sopenharmony_ci 35288c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(capabilities); 35298c2ecf20Sopenharmony_ci 35308c2ecf20Sopenharmony_cistatic int __init ehea_module_init(void) 35318c2ecf20Sopenharmony_ci{ 35328c2ecf20Sopenharmony_ci int ret; 35338c2ecf20Sopenharmony_ci 35348c2ecf20Sopenharmony_ci pr_info("IBM eHEA ethernet device driver (Release %s)\n", DRV_VERSION); 35358c2ecf20Sopenharmony_ci 35368c2ecf20Sopenharmony_ci memset(&ehea_fw_handles, 0, sizeof(ehea_fw_handles)); 35378c2ecf20Sopenharmony_ci memset(&ehea_bcmc_regs, 0, sizeof(ehea_bcmc_regs)); 35388c2ecf20Sopenharmony_ci 35398c2ecf20Sopenharmony_ci mutex_init(&ehea_fw_handles.lock); 35408c2ecf20Sopenharmony_ci spin_lock_init(&ehea_bcmc_regs.lock); 35418c2ecf20Sopenharmony_ci 35428c2ecf20Sopenharmony_ci ret = check_module_parm(); 35438c2ecf20Sopenharmony_ci if (ret) 35448c2ecf20Sopenharmony_ci goto out; 35458c2ecf20Sopenharmony_ci 35468c2ecf20Sopenharmony_ci ret = ibmebus_register_driver(&ehea_driver); 35478c2ecf20Sopenharmony_ci if (ret) { 35488c2ecf20Sopenharmony_ci pr_err("failed registering eHEA device driver on ebus\n"); 35498c2ecf20Sopenharmony_ci goto out; 35508c2ecf20Sopenharmony_ci } 35518c2ecf20Sopenharmony_ci 35528c2ecf20Sopenharmony_ci ret = driver_create_file(&ehea_driver.driver, 35538c2ecf20Sopenharmony_ci &driver_attr_capabilities); 35548c2ecf20Sopenharmony_ci if (ret) { 35558c2ecf20Sopenharmony_ci pr_err("failed to register capabilities attribute, ret=%d\n", 35568c2ecf20Sopenharmony_ci ret); 35578c2ecf20Sopenharmony_ci goto out2; 35588c2ecf20Sopenharmony_ci } 35598c2ecf20Sopenharmony_ci 35608c2ecf20Sopenharmony_ci return ret; 35618c2ecf20Sopenharmony_ci 35628c2ecf20Sopenharmony_ciout2: 35638c2ecf20Sopenharmony_ci ibmebus_unregister_driver(&ehea_driver); 35648c2ecf20Sopenharmony_ciout: 35658c2ecf20Sopenharmony_ci return ret; 35668c2ecf20Sopenharmony_ci} 35678c2ecf20Sopenharmony_ci 35688c2ecf20Sopenharmony_cistatic void __exit ehea_module_exit(void) 35698c2ecf20Sopenharmony_ci{ 35708c2ecf20Sopenharmony_ci driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities); 35718c2ecf20Sopenharmony_ci ibmebus_unregister_driver(&ehea_driver); 35728c2ecf20Sopenharmony_ci ehea_unregister_memory_hooks(); 35738c2ecf20Sopenharmony_ci kfree(ehea_fw_handles.arr); 35748c2ecf20Sopenharmony_ci kfree(ehea_bcmc_regs.arr); 35758c2ecf20Sopenharmony_ci ehea_destroy_busmap(); 35768c2ecf20Sopenharmony_ci} 35778c2ecf20Sopenharmony_ci 35788c2ecf20Sopenharmony_cimodule_init(ehea_module_init); 35798c2ecf20Sopenharmony_cimodule_exit(ehea_module_exit); 3580