1bc610777SAlexander Duyck // SPDX-License-Identifier: GPL-2.0 2bc610777SAlexander Duyck /* Copyright (c) Meta Platforms, Inc. and affiliates. */ 3bc610777SAlexander Duyck 4bc610777SAlexander Duyck #include <linux/etherdevice.h> 5bc610777SAlexander Duyck #include <linux/ipv6.h> 6bc610777SAlexander Duyck #include <linux/types.h> 78be1bd91SStanislav Fomichev #include <net/netdev_queues.h> 8bc610777SAlexander Duyck 9bc610777SAlexander Duyck #include "fbnic.h" 10bc610777SAlexander Duyck #include "fbnic_netdev.h" 11bc610777SAlexander Duyck #include "fbnic_txrx.h" 12bc610777SAlexander Duyck 13bc610777SAlexander Duyck int __fbnic_open(struct fbnic_net *fbn) 14bc610777SAlexander Duyck { 1520d2e88cSAlexander Duyck struct fbnic_dev *fbd = fbn->fbd; 16bc610777SAlexander Duyck int err; 17bc610777SAlexander Duyck 18bc610777SAlexander Duyck err = fbnic_alloc_napi_vectors(fbn); 19bc610777SAlexander Duyck if (err) 20bc610777SAlexander Duyck return err; 21bc610777SAlexander Duyck 2240bf06a1SAlexander Duyck err = fbnic_alloc_resources(fbn); 2340bf06a1SAlexander Duyck if (err) 2440bf06a1SAlexander Duyck goto free_napi_vectors; 2540bf06a1SAlexander Duyck 26557d0223SAlexander Duyck err = fbnic_set_netif_queues(fbn); 27bc610777SAlexander Duyck if (err) 28bc610777SAlexander Duyck goto free_resources; 29bc610777SAlexander Duyck 3020d2e88cSAlexander Duyck /* Send ownership message and flush to verify FW has seen it */ 3120d2e88cSAlexander Duyck err = fbnic_fw_xmit_ownership_msg(fbd, true); 3220d2e88cSAlexander Duyck if (err) { 3320d2e88cSAlexander Duyck dev_warn(fbd->dev, 3420d2e88cSAlexander Duyck "Error %d sending host ownership message to the firmware\n", 3520d2e88cSAlexander Duyck err); 3620d2e88cSAlexander Duyck goto free_resources; 3720d2e88cSAlexander Duyck } 3820d2e88cSAlexander Duyck 39ad8e66a4SVadim Fedorenko err = fbnic_time_start(fbn); 4020d2e88cSAlexander Duyck if (err) 4120d2e88cSAlexander Duyck goto release_ownership; 4220d2e88cSAlexander Duyck 43ad8e66a4SVadim Fedorenko err = fbnic_fw_init_heartbeat(fbd, false); 44ad8e66a4SVadim Fedorenko if (err) 45ad8e66a4SVadim Fedorenko goto time_stop; 46ad8e66a4SVadim Fedorenko 4769684376SAlexander Duyck err = fbnic_pcs_irq_enable(fbd); 4869684376SAlexander Duyck if (err) 49ad8e66a4SVadim Fedorenko goto time_stop; 50eb690ef8SAlexander Duyck /* Pull the BMC config and initialize the RPC */ 51eb690ef8SAlexander Duyck fbnic_bmc_rpc_init(fbd); 52355440a6SAlexander Duyck fbnic_rss_reinit(fbd, fbn); 5369684376SAlexander Duyck 54bc610777SAlexander Duyck return 0; 55ad8e66a4SVadim Fedorenko time_stop: 56ad8e66a4SVadim Fedorenko fbnic_time_stop(fbn); 5720d2e88cSAlexander Duyck release_ownership: 5820d2e88cSAlexander Duyck fbnic_fw_xmit_ownership_msg(fbn->fbd, false); 59bc610777SAlexander Duyck free_resources: 6040bf06a1SAlexander Duyck fbnic_free_resources(fbn); 6140bf06a1SAlexander Duyck free_napi_vectors: 62bc610777SAlexander Duyck fbnic_free_napi_vectors(fbn); 63bc610777SAlexander Duyck return err; 64bc610777SAlexander Duyck } 65bc610777SAlexander Duyck 66bc610777SAlexander Duyck static int fbnic_open(struct net_device *netdev) 67bc610777SAlexander Duyck { 68bc610777SAlexander Duyck struct fbnic_net *fbn = netdev_priv(netdev); 69bc610777SAlexander Duyck int err; 70bc610777SAlexander Duyck 713a856ab3SJakub Kicinski fbnic_napi_name_irqs(fbn->fbd); 723a856ab3SJakub Kicinski 73bc610777SAlexander Duyck err = __fbnic_open(fbn); 74bc610777SAlexander Duyck if (!err) 75bc610777SAlexander Duyck fbnic_up(fbn); 76bc610777SAlexander Duyck 77bc610777SAlexander Duyck return err; 78bc610777SAlexander Duyck } 79bc610777SAlexander Duyck 80bc610777SAlexander Duyck static int fbnic_stop(struct net_device *netdev) 81bc610777SAlexander Duyck { 82bc610777SAlexander Duyck struct fbnic_net *fbn = netdev_priv(netdev); 83bc610777SAlexander Duyck 84bc610777SAlexander Duyck fbnic_down(fbn); 8569684376SAlexander Duyck fbnic_pcs_irq_disable(fbn->fbd); 86bc610777SAlexander Duyck 87ad8e66a4SVadim Fedorenko fbnic_time_stop(fbn); 8820d2e88cSAlexander Duyck fbnic_fw_xmit_ownership_msg(fbn->fbd, false); 8920d2e88cSAlexander Duyck 90557d0223SAlexander Duyck fbnic_reset_netif_queues(fbn); 9140bf06a1SAlexander Duyck fbnic_free_resources(fbn); 92bc610777SAlexander Duyck fbnic_free_napi_vectors(fbn); 93bc610777SAlexander Duyck 94bc610777SAlexander Duyck return 0; 95bc610777SAlexander Duyck } 96bc610777SAlexander Duyck 97eb690ef8SAlexander Duyck static int fbnic_uc_sync(struct net_device *netdev, const unsigned char *addr) 98eb690ef8SAlexander Duyck { 99eb690ef8SAlexander Duyck struct fbnic_net *fbn = netdev_priv(netdev); 100eb690ef8SAlexander Duyck struct fbnic_mac_addr *avail_addr; 101eb690ef8SAlexander Duyck 102eb690ef8SAlexander Duyck if (WARN_ON(!is_valid_ether_addr(addr))) 103eb690ef8SAlexander Duyck return -EADDRNOTAVAIL; 104eb690ef8SAlexander Duyck 105eb690ef8SAlexander Duyck avail_addr = __fbnic_uc_sync(fbn->fbd, addr); 106eb690ef8SAlexander Duyck if (!avail_addr) 107eb690ef8SAlexander Duyck return -ENOSPC; 108eb690ef8SAlexander Duyck 109eb690ef8SAlexander Duyck /* Add type flag indicating this address is in use by the host */ 110eb690ef8SAlexander Duyck set_bit(FBNIC_MAC_ADDR_T_UNICAST, avail_addr->act_tcam); 111eb690ef8SAlexander Duyck 112eb690ef8SAlexander Duyck return 0; 113eb690ef8SAlexander Duyck } 114eb690ef8SAlexander Duyck 115eb690ef8SAlexander Duyck static int fbnic_uc_unsync(struct net_device *netdev, const unsigned char *addr) 116eb690ef8SAlexander Duyck { 117eb690ef8SAlexander Duyck struct fbnic_net *fbn = netdev_priv(netdev); 118eb690ef8SAlexander Duyck struct fbnic_dev *fbd = fbn->fbd; 119eb690ef8SAlexander Duyck int i, ret; 120eb690ef8SAlexander Duyck 121eb690ef8SAlexander Duyck /* Scan from middle of list to bottom, filling bottom up. 122eb690ef8SAlexander Duyck * Skip the first entry which is reserved for dev_addr and 123eb690ef8SAlexander Duyck * leave the last entry to use for promiscuous filtering. 124eb690ef8SAlexander Duyck */ 125eb690ef8SAlexander Duyck for (i = fbd->mac_addr_boundary, ret = -ENOENT; 126eb690ef8SAlexander Duyck i < FBNIC_RPC_TCAM_MACDA_HOST_ADDR_IDX && ret; i++) { 127eb690ef8SAlexander Duyck struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[i]; 128eb690ef8SAlexander Duyck 129eb690ef8SAlexander Duyck if (!ether_addr_equal(mac_addr->value.addr8, addr)) 130eb690ef8SAlexander Duyck continue; 131eb690ef8SAlexander Duyck 132eb690ef8SAlexander Duyck ret = __fbnic_uc_unsync(mac_addr); 133eb690ef8SAlexander Duyck } 134eb690ef8SAlexander Duyck 135eb690ef8SAlexander Duyck return ret; 136eb690ef8SAlexander Duyck } 137eb690ef8SAlexander Duyck 138eb690ef8SAlexander Duyck static int fbnic_mc_sync(struct net_device *netdev, const unsigned char *addr) 139eb690ef8SAlexander Duyck { 140eb690ef8SAlexander Duyck struct fbnic_net *fbn = netdev_priv(netdev); 141eb690ef8SAlexander Duyck struct fbnic_mac_addr *avail_addr; 142eb690ef8SAlexander Duyck 143eb690ef8SAlexander Duyck if (WARN_ON(!is_multicast_ether_addr(addr))) 144eb690ef8SAlexander Duyck return -EADDRNOTAVAIL; 145eb690ef8SAlexander Duyck 146eb690ef8SAlexander Duyck avail_addr = __fbnic_mc_sync(fbn->fbd, addr); 147eb690ef8SAlexander Duyck if (!avail_addr) 148eb690ef8SAlexander Duyck return -ENOSPC; 149eb690ef8SAlexander Duyck 150eb690ef8SAlexander Duyck /* Add type flag indicating this address is in use by the host */ 151eb690ef8SAlexander Duyck set_bit(FBNIC_MAC_ADDR_T_MULTICAST, avail_addr->act_tcam); 152eb690ef8SAlexander Duyck 153eb690ef8SAlexander Duyck return 0; 154eb690ef8SAlexander Duyck } 155eb690ef8SAlexander Duyck 156eb690ef8SAlexander Duyck static int fbnic_mc_unsync(struct net_device *netdev, const unsigned char *addr) 157eb690ef8SAlexander Duyck { 158eb690ef8SAlexander Duyck struct fbnic_net *fbn = netdev_priv(netdev); 159eb690ef8SAlexander Duyck struct fbnic_dev *fbd = fbn->fbd; 160eb690ef8SAlexander Duyck int i, ret; 161eb690ef8SAlexander Duyck 162eb690ef8SAlexander Duyck /* Scan from middle of list to top, filling top down. 163eb690ef8SAlexander Duyck * Skip over the address reserved for the BMC MAC and 164eb690ef8SAlexander Duyck * exclude index 0 as that belongs to the broadcast address 165eb690ef8SAlexander Duyck */ 166eb690ef8SAlexander Duyck for (i = fbd->mac_addr_boundary, ret = -ENOENT; 167eb690ef8SAlexander Duyck --i > FBNIC_RPC_TCAM_MACDA_BROADCAST_IDX && ret;) { 168eb690ef8SAlexander Duyck struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[i]; 169eb690ef8SAlexander Duyck 170eb690ef8SAlexander Duyck if (!ether_addr_equal(mac_addr->value.addr8, addr)) 171eb690ef8SAlexander Duyck continue; 172eb690ef8SAlexander Duyck 173eb690ef8SAlexander Duyck ret = __fbnic_mc_unsync(mac_addr); 174eb690ef8SAlexander Duyck } 175eb690ef8SAlexander Duyck 176eb690ef8SAlexander Duyck return ret; 177eb690ef8SAlexander Duyck } 178eb690ef8SAlexander Duyck 179eb690ef8SAlexander Duyck void __fbnic_set_rx_mode(struct net_device *netdev) 180eb690ef8SAlexander Duyck { 181eb690ef8SAlexander Duyck struct fbnic_net *fbn = netdev_priv(netdev); 182eb690ef8SAlexander Duyck bool uc_promisc = false, mc_promisc = false; 183eb690ef8SAlexander Duyck struct fbnic_dev *fbd = fbn->fbd; 184eb690ef8SAlexander Duyck struct fbnic_mac_addr *mac_addr; 185eb690ef8SAlexander Duyck int err; 186eb690ef8SAlexander Duyck 187eb690ef8SAlexander Duyck /* Populate host address from dev_addr */ 188eb690ef8SAlexander Duyck mac_addr = &fbd->mac_addr[FBNIC_RPC_TCAM_MACDA_HOST_ADDR_IDX]; 189eb690ef8SAlexander Duyck if (!ether_addr_equal(mac_addr->value.addr8, netdev->dev_addr) || 190eb690ef8SAlexander Duyck mac_addr->state != FBNIC_TCAM_S_VALID) { 191eb690ef8SAlexander Duyck ether_addr_copy(mac_addr->value.addr8, netdev->dev_addr); 192eb690ef8SAlexander Duyck mac_addr->state = FBNIC_TCAM_S_UPDATE; 193eb690ef8SAlexander Duyck set_bit(FBNIC_MAC_ADDR_T_UNICAST, mac_addr->act_tcam); 194eb690ef8SAlexander Duyck } 195eb690ef8SAlexander Duyck 196eb690ef8SAlexander Duyck /* Populate broadcast address if broadcast is enabled */ 197eb690ef8SAlexander Duyck mac_addr = &fbd->mac_addr[FBNIC_RPC_TCAM_MACDA_BROADCAST_IDX]; 198eb690ef8SAlexander Duyck if (netdev->flags & IFF_BROADCAST) { 199eb690ef8SAlexander Duyck if (!is_broadcast_ether_addr(mac_addr->value.addr8) || 200eb690ef8SAlexander Duyck mac_addr->state != FBNIC_TCAM_S_VALID) { 201eb690ef8SAlexander Duyck eth_broadcast_addr(mac_addr->value.addr8); 202eb690ef8SAlexander Duyck mac_addr->state = FBNIC_TCAM_S_ADD; 203eb690ef8SAlexander Duyck } 204eb690ef8SAlexander Duyck set_bit(FBNIC_MAC_ADDR_T_BROADCAST, mac_addr->act_tcam); 205eb690ef8SAlexander Duyck } else if (mac_addr->state == FBNIC_TCAM_S_VALID) { 206eb690ef8SAlexander Duyck __fbnic_xc_unsync(mac_addr, FBNIC_MAC_ADDR_T_BROADCAST); 207eb690ef8SAlexander Duyck } 208eb690ef8SAlexander Duyck 209eb690ef8SAlexander Duyck /* Synchronize unicast and multicast address lists */ 210eb690ef8SAlexander Duyck err = __dev_uc_sync(netdev, fbnic_uc_sync, fbnic_uc_unsync); 211eb690ef8SAlexander Duyck if (err == -ENOSPC) 212eb690ef8SAlexander Duyck uc_promisc = true; 213eb690ef8SAlexander Duyck err = __dev_mc_sync(netdev, fbnic_mc_sync, fbnic_mc_unsync); 214eb690ef8SAlexander Duyck if (err == -ENOSPC) 215eb690ef8SAlexander Duyck mc_promisc = true; 216eb690ef8SAlexander Duyck 217eb690ef8SAlexander Duyck uc_promisc |= !!(netdev->flags & IFF_PROMISC); 218eb690ef8SAlexander Duyck mc_promisc |= !!(netdev->flags & IFF_ALLMULTI) || uc_promisc; 219eb690ef8SAlexander Duyck 220eb690ef8SAlexander Duyck /* Populate last TCAM entry with promiscuous entry and 0/1 bit mask */ 221eb690ef8SAlexander Duyck mac_addr = &fbd->mac_addr[FBNIC_RPC_TCAM_MACDA_PROMISC_IDX]; 222eb690ef8SAlexander Duyck if (uc_promisc) { 223eb690ef8SAlexander Duyck if (!is_zero_ether_addr(mac_addr->value.addr8) || 224eb690ef8SAlexander Duyck mac_addr->state != FBNIC_TCAM_S_VALID) { 225eb690ef8SAlexander Duyck eth_zero_addr(mac_addr->value.addr8); 226eb690ef8SAlexander Duyck eth_broadcast_addr(mac_addr->mask.addr8); 227eb690ef8SAlexander Duyck clear_bit(FBNIC_MAC_ADDR_T_ALLMULTI, 228eb690ef8SAlexander Duyck mac_addr->act_tcam); 229eb690ef8SAlexander Duyck set_bit(FBNIC_MAC_ADDR_T_PROMISC, 230eb690ef8SAlexander Duyck mac_addr->act_tcam); 231eb690ef8SAlexander Duyck mac_addr->state = FBNIC_TCAM_S_ADD; 232eb690ef8SAlexander Duyck } 233eb690ef8SAlexander Duyck } else if (mc_promisc && 234eb690ef8SAlexander Duyck (!fbnic_bmc_present(fbd) || !fbd->fw_cap.all_multi)) { 235eb690ef8SAlexander Duyck /* We have to add a special handler for multicast as the 236eb690ef8SAlexander Duyck * BMC may have an all-multi rule already in place. As such 237eb690ef8SAlexander Duyck * adding a rule ourselves won't do any good so we will have 238eb690ef8SAlexander Duyck * to modify the rules for the ALL MULTI below if the BMC 239eb690ef8SAlexander Duyck * already has the rule in place. 240eb690ef8SAlexander Duyck */ 241eb690ef8SAlexander Duyck if (!is_multicast_ether_addr(mac_addr->value.addr8) || 242eb690ef8SAlexander Duyck mac_addr->state != FBNIC_TCAM_S_VALID) { 243eb690ef8SAlexander Duyck eth_zero_addr(mac_addr->value.addr8); 244eb690ef8SAlexander Duyck eth_broadcast_addr(mac_addr->mask.addr8); 245eb690ef8SAlexander Duyck mac_addr->value.addr8[0] ^= 1; 246eb690ef8SAlexander Duyck mac_addr->mask.addr8[0] ^= 1; 247eb690ef8SAlexander Duyck set_bit(FBNIC_MAC_ADDR_T_ALLMULTI, 248eb690ef8SAlexander Duyck mac_addr->act_tcam); 249eb690ef8SAlexander Duyck clear_bit(FBNIC_MAC_ADDR_T_PROMISC, 250eb690ef8SAlexander Duyck mac_addr->act_tcam); 251eb690ef8SAlexander Duyck mac_addr->state = FBNIC_TCAM_S_ADD; 252eb690ef8SAlexander Duyck } 253eb690ef8SAlexander Duyck } else if (mac_addr->state == FBNIC_TCAM_S_VALID) { 254eb690ef8SAlexander Duyck if (test_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam)) { 255eb690ef8SAlexander Duyck clear_bit(FBNIC_MAC_ADDR_T_ALLMULTI, 256eb690ef8SAlexander Duyck mac_addr->act_tcam); 257eb690ef8SAlexander Duyck clear_bit(FBNIC_MAC_ADDR_T_PROMISC, 258eb690ef8SAlexander Duyck mac_addr->act_tcam); 259eb690ef8SAlexander Duyck } else { 260eb690ef8SAlexander Duyck mac_addr->state = FBNIC_TCAM_S_DELETE; 261eb690ef8SAlexander Duyck } 262eb690ef8SAlexander Duyck } 263eb690ef8SAlexander Duyck 264eb690ef8SAlexander Duyck /* Add rules for BMC all multicast if it is enabled */ 265eb690ef8SAlexander Duyck fbnic_bmc_rpc_all_multi_config(fbd, mc_promisc); 266eb690ef8SAlexander Duyck 267eb690ef8SAlexander Duyck /* Sift out any unshared BMC rules and place them in BMC only section */ 268eb690ef8SAlexander Duyck fbnic_sift_macda(fbd); 269eb690ef8SAlexander Duyck 270eb690ef8SAlexander Duyck /* Write updates to hardware */ 271355440a6SAlexander Duyck fbnic_write_rules(fbd); 272eb690ef8SAlexander Duyck fbnic_write_macda(fbd); 27390c940ffSMohsin Bashir fbnic_write_tce_tcam(fbd); 274eb690ef8SAlexander Duyck } 275eb690ef8SAlexander Duyck 276eb690ef8SAlexander Duyck static void fbnic_set_rx_mode(struct net_device *netdev) 277eb690ef8SAlexander Duyck { 278eb690ef8SAlexander Duyck /* No need to update the hardware if we are not running */ 279eb690ef8SAlexander Duyck if (netif_running(netdev)) 280eb690ef8SAlexander Duyck __fbnic_set_rx_mode(netdev); 281eb690ef8SAlexander Duyck } 282eb690ef8SAlexander Duyck 283eb690ef8SAlexander Duyck static int fbnic_set_mac(struct net_device *netdev, void *p) 284eb690ef8SAlexander Duyck { 285eb690ef8SAlexander Duyck struct sockaddr *addr = p; 286eb690ef8SAlexander Duyck 287eb690ef8SAlexander Duyck if (!is_valid_ether_addr(addr->sa_data)) 288eb690ef8SAlexander Duyck return -EADDRNOTAVAIL; 289eb690ef8SAlexander Duyck 290eb690ef8SAlexander Duyck eth_hw_addr_set(netdev, addr->sa_data); 291eb690ef8SAlexander Duyck 292eb690ef8SAlexander Duyck fbnic_set_rx_mode(netdev); 293eb690ef8SAlexander Duyck 294eb690ef8SAlexander Duyck return 0; 295eb690ef8SAlexander Duyck } 296eb690ef8SAlexander Duyck 297eb690ef8SAlexander Duyck void fbnic_clear_rx_mode(struct net_device *netdev) 298eb690ef8SAlexander Duyck { 299eb690ef8SAlexander Duyck struct fbnic_net *fbn = netdev_priv(netdev); 300eb690ef8SAlexander Duyck struct fbnic_dev *fbd = fbn->fbd; 301eb690ef8SAlexander Duyck int idx; 302eb690ef8SAlexander Duyck 303eb690ef8SAlexander Duyck for (idx = ARRAY_SIZE(fbd->mac_addr); idx--;) { 304eb690ef8SAlexander Duyck struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[idx]; 305eb690ef8SAlexander Duyck 306eb690ef8SAlexander Duyck if (mac_addr->state != FBNIC_TCAM_S_VALID) 307eb690ef8SAlexander Duyck continue; 308eb690ef8SAlexander Duyck 309eb690ef8SAlexander Duyck bitmap_clear(mac_addr->act_tcam, 310eb690ef8SAlexander Duyck FBNIC_MAC_ADDR_T_HOST_START, 311eb690ef8SAlexander Duyck FBNIC_MAC_ADDR_T_HOST_LEN); 312eb690ef8SAlexander Duyck 313eb690ef8SAlexander Duyck if (bitmap_empty(mac_addr->act_tcam, 314eb690ef8SAlexander Duyck FBNIC_RPC_TCAM_ACT_NUM_ENTRIES)) 315eb690ef8SAlexander Duyck mac_addr->state = FBNIC_TCAM_S_DELETE; 316eb690ef8SAlexander Duyck } 317eb690ef8SAlexander Duyck 318eb690ef8SAlexander Duyck /* Write updates to hardware */ 319eb690ef8SAlexander Duyck fbnic_write_macda(fbd); 320eb690ef8SAlexander Duyck 321eb690ef8SAlexander Duyck __dev_uc_unsync(netdev, NULL); 322eb690ef8SAlexander Duyck __dev_mc_unsync(netdev, NULL); 323eb690ef8SAlexander Duyck } 324eb690ef8SAlexander Duyck 3256a2b3edeSVadim Fedorenko static int fbnic_hwtstamp_get(struct net_device *netdev, 3266a2b3edeSVadim Fedorenko struct kernel_hwtstamp_config *config) 3276a2b3edeSVadim Fedorenko { 3286a2b3edeSVadim Fedorenko struct fbnic_net *fbn = netdev_priv(netdev); 3296a2b3edeSVadim Fedorenko 3306a2b3edeSVadim Fedorenko *config = fbn->hwtstamp_config; 3316a2b3edeSVadim Fedorenko 3326a2b3edeSVadim Fedorenko return 0; 3336a2b3edeSVadim Fedorenko } 3346a2b3edeSVadim Fedorenko 3356a2b3edeSVadim Fedorenko static int fbnic_hwtstamp_set(struct net_device *netdev, 3366a2b3edeSVadim Fedorenko struct kernel_hwtstamp_config *config, 3376a2b3edeSVadim Fedorenko struct netlink_ext_ack *extack) 3386a2b3edeSVadim Fedorenko { 3396a2b3edeSVadim Fedorenko struct fbnic_net *fbn = netdev_priv(netdev); 3406a2b3edeSVadim Fedorenko int old_rx_filter; 3416a2b3edeSVadim Fedorenko 3426a2b3edeSVadim Fedorenko if (config->source != HWTSTAMP_SOURCE_NETDEV) 3436a2b3edeSVadim Fedorenko return -EOPNOTSUPP; 3446a2b3edeSVadim Fedorenko 3456a2b3edeSVadim Fedorenko if (!kernel_hwtstamp_config_changed(config, &fbn->hwtstamp_config)) 3466a2b3edeSVadim Fedorenko return 0; 3476a2b3edeSVadim Fedorenko 3486a2b3edeSVadim Fedorenko /* Upscale the filters */ 3496a2b3edeSVadim Fedorenko switch (config->rx_filter) { 3506a2b3edeSVadim Fedorenko case HWTSTAMP_FILTER_NONE: 3516a2b3edeSVadim Fedorenko case HWTSTAMP_FILTER_ALL: 3526a2b3edeSVadim Fedorenko case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 3536a2b3edeSVadim Fedorenko case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 3546a2b3edeSVadim Fedorenko case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: 3556a2b3edeSVadim Fedorenko case HWTSTAMP_FILTER_PTP_V2_EVENT: 3566a2b3edeSVadim Fedorenko break; 3576a2b3edeSVadim Fedorenko case HWTSTAMP_FILTER_NTP_ALL: 3586a2b3edeSVadim Fedorenko config->rx_filter = HWTSTAMP_FILTER_ALL; 3596a2b3edeSVadim Fedorenko break; 3606a2b3edeSVadim Fedorenko case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 3616a2b3edeSVadim Fedorenko case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 3626a2b3edeSVadim Fedorenko config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; 3636a2b3edeSVadim Fedorenko break; 3646a2b3edeSVadim Fedorenko case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 3656a2b3edeSVadim Fedorenko case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 3666a2b3edeSVadim Fedorenko config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; 3676a2b3edeSVadim Fedorenko break; 3686a2b3edeSVadim Fedorenko case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: 3696a2b3edeSVadim Fedorenko case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: 3706a2b3edeSVadim Fedorenko config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; 3716a2b3edeSVadim Fedorenko break; 3726a2b3edeSVadim Fedorenko case HWTSTAMP_FILTER_PTP_V2_SYNC: 3736a2b3edeSVadim Fedorenko case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: 3746a2b3edeSVadim Fedorenko config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; 3756a2b3edeSVadim Fedorenko break; 3766a2b3edeSVadim Fedorenko default: 3776a2b3edeSVadim Fedorenko return -ERANGE; 3786a2b3edeSVadim Fedorenko } 3796a2b3edeSVadim Fedorenko 3806a2b3edeSVadim Fedorenko /* Configure */ 3816a2b3edeSVadim Fedorenko old_rx_filter = fbn->hwtstamp_config.rx_filter; 3826a2b3edeSVadim Fedorenko memcpy(&fbn->hwtstamp_config, config, sizeof(*config)); 3836a2b3edeSVadim Fedorenko 3846a2b3edeSVadim Fedorenko if (old_rx_filter != config->rx_filter && netif_running(fbn->netdev)) { 3856a2b3edeSVadim Fedorenko fbnic_rss_reinit(fbn->fbd, fbn); 3866a2b3edeSVadim Fedorenko fbnic_write_rules(fbn->fbd); 3876a2b3edeSVadim Fedorenko } 3886a2b3edeSVadim Fedorenko 3896a2b3edeSVadim Fedorenko /* Save / report back filter configuration 3906a2b3edeSVadim Fedorenko * Note that our filter configuration is inexact. Instead of 3916a2b3edeSVadim Fedorenko * filtering for a specific UDP port or L2 Ethertype we are 3926a2b3edeSVadim Fedorenko * filtering in all UDP or all non-IP packets for timestamping. So 3936a2b3edeSVadim Fedorenko * if anything other than FILTER_ALL is requested we report 3946a2b3edeSVadim Fedorenko * FILTER_SOME indicating that we will be timestamping a few 3956a2b3edeSVadim Fedorenko * additional packets. 3966a2b3edeSVadim Fedorenko */ 3976a2b3edeSVadim Fedorenko if (config->rx_filter > HWTSTAMP_FILTER_ALL) 3986a2b3edeSVadim Fedorenko config->rx_filter = HWTSTAMP_FILTER_SOME; 3996a2b3edeSVadim Fedorenko 4006a2b3edeSVadim Fedorenko return 0; 4016a2b3edeSVadim Fedorenko } 4026a2b3edeSVadim Fedorenko 40345d84008SJakub Kicinski static void fbnic_get_stats64(struct net_device *dev, 40445d84008SJakub Kicinski struct rtnl_link_stats64 *stats64) 40545d84008SJakub Kicinski { 4068f20a2bfSMohsin Bashir u64 rx_bytes, rx_packets, rx_dropped = 0, rx_errors = 0; 40745d84008SJakub Kicinski u64 tx_bytes, tx_packets, tx_dropped = 0; 40845d84008SJakub Kicinski struct fbnic_net *fbn = netdev_priv(dev); 4098f20a2bfSMohsin Bashir struct fbnic_dev *fbd = fbn->fbd; 41045d84008SJakub Kicinski struct fbnic_queue_stats *stats; 411986c63a0SMohsin Bashir u64 rx_over = 0, rx_missed = 0; 41245d84008SJakub Kicinski unsigned int start, i; 4138f20a2bfSMohsin Bashir 4148f20a2bfSMohsin Bashir fbnic_get_hw_stats(fbd); 41545d84008SJakub Kicinski 41645d84008SJakub Kicinski stats = &fbn->tx_stats; 41745d84008SJakub Kicinski 41845d84008SJakub Kicinski tx_bytes = stats->bytes; 41945d84008SJakub Kicinski tx_packets = stats->packets; 42045d84008SJakub Kicinski tx_dropped = stats->dropped; 42145d84008SJakub Kicinski 42245d84008SJakub Kicinski stats64->tx_bytes = tx_bytes; 42345d84008SJakub Kicinski stats64->tx_packets = tx_packets; 42445d84008SJakub Kicinski stats64->tx_dropped = tx_dropped; 42545d84008SJakub Kicinski 426*5f8bd2ceSMohsin Bashir /* Record drops from Tx HW Datapath */ 427*5f8bd2ceSMohsin Bashir tx_dropped += fbd->hw_stats.tmi.drop.frames.value; 428*5f8bd2ceSMohsin Bashir 42945d84008SJakub Kicinski for (i = 0; i < fbn->num_tx_queues; i++) { 43045d84008SJakub Kicinski struct fbnic_ring *txr = fbn->tx[i]; 43145d84008SJakub Kicinski 43245d84008SJakub Kicinski if (!txr) 43345d84008SJakub Kicinski continue; 43445d84008SJakub Kicinski 43545d84008SJakub Kicinski stats = &txr->stats; 43645d84008SJakub Kicinski do { 43745d84008SJakub Kicinski start = u64_stats_fetch_begin(&stats->syncp); 43845d84008SJakub Kicinski tx_bytes = stats->bytes; 43945d84008SJakub Kicinski tx_packets = stats->packets; 44045d84008SJakub Kicinski tx_dropped = stats->dropped; 44145d84008SJakub Kicinski } while (u64_stats_fetch_retry(&stats->syncp, start)); 44245d84008SJakub Kicinski 44345d84008SJakub Kicinski stats64->tx_bytes += tx_bytes; 44445d84008SJakub Kicinski stats64->tx_packets += tx_packets; 44545d84008SJakub Kicinski stats64->tx_dropped += tx_dropped; 44645d84008SJakub Kicinski } 44745d84008SJakub Kicinski 44845d84008SJakub Kicinski stats = &fbn->rx_stats; 44945d84008SJakub Kicinski 45045d84008SJakub Kicinski rx_bytes = stats->bytes; 45145d84008SJakub Kicinski rx_packets = stats->packets; 45245d84008SJakub Kicinski rx_dropped = stats->dropped; 45345d84008SJakub Kicinski 4548f20a2bfSMohsin Bashir spin_lock(&fbd->hw_stats_lock); 455986c63a0SMohsin Bashir /* Record drops for the host FIFOs. 456986c63a0SMohsin Bashir * 4: network to Host, 6: BMC to Host 457986c63a0SMohsin Bashir * Exclude the BMC and MC FIFOs as those stats may contain drops 458986c63a0SMohsin Bashir * due to unrelated items such as TCAM misses. They are still 459986c63a0SMohsin Bashir * accessible through the ethtool stats. 460986c63a0SMohsin Bashir */ 461986c63a0SMohsin Bashir i = FBNIC_RXB_FIFO_HOST; 462986c63a0SMohsin Bashir rx_missed += fbd->hw_stats.rxb.fifo[i].drop.frames.value; 463986c63a0SMohsin Bashir i = FBNIC_RXB_FIFO_BMC_TO_HOST; 464986c63a0SMohsin Bashir rx_missed += fbd->hw_stats.rxb.fifo[i].drop.frames.value; 465986c63a0SMohsin Bashir 4668f20a2bfSMohsin Bashir for (i = 0; i < fbd->max_num_queues; i++) { 4678f20a2bfSMohsin Bashir /* Report packets dropped due to CQ/BDQ being full/empty */ 4688f20a2bfSMohsin Bashir rx_over += fbd->hw_stats.hw_q[i].rde_pkt_cq_drop.value; 4698f20a2bfSMohsin Bashir rx_over += fbd->hw_stats.hw_q[i].rde_pkt_bdq_drop.value; 4708f20a2bfSMohsin Bashir 4718f20a2bfSMohsin Bashir /* Report packets with errors */ 4728f20a2bfSMohsin Bashir rx_errors += fbd->hw_stats.hw_q[i].rde_pkt_err.value; 4738f20a2bfSMohsin Bashir } 4748f20a2bfSMohsin Bashir spin_unlock(&fbd->hw_stats_lock); 4758f20a2bfSMohsin Bashir 47645d84008SJakub Kicinski stats64->rx_bytes = rx_bytes; 47745d84008SJakub Kicinski stats64->rx_packets = rx_packets; 47845d84008SJakub Kicinski stats64->rx_dropped = rx_dropped; 4798f20a2bfSMohsin Bashir stats64->rx_over_errors = rx_over; 4808f20a2bfSMohsin Bashir stats64->rx_errors = rx_errors; 481986c63a0SMohsin Bashir stats64->rx_missed_errors = rx_missed; 48245d84008SJakub Kicinski 48345d84008SJakub Kicinski for (i = 0; i < fbn->num_rx_queues; i++) { 48445d84008SJakub Kicinski struct fbnic_ring *rxr = fbn->rx[i]; 48545d84008SJakub Kicinski 48645d84008SJakub Kicinski if (!rxr) 48745d84008SJakub Kicinski continue; 48845d84008SJakub Kicinski 48945d84008SJakub Kicinski stats = &rxr->stats; 49045d84008SJakub Kicinski do { 49145d84008SJakub Kicinski start = u64_stats_fetch_begin(&stats->syncp); 49245d84008SJakub Kicinski rx_bytes = stats->bytes; 49345d84008SJakub Kicinski rx_packets = stats->packets; 49445d84008SJakub Kicinski rx_dropped = stats->dropped; 49545d84008SJakub Kicinski } while (u64_stats_fetch_retry(&stats->syncp, start)); 49645d84008SJakub Kicinski 49745d84008SJakub Kicinski stats64->rx_bytes += rx_bytes; 49845d84008SJakub Kicinski stats64->rx_packets += rx_packets; 49945d84008SJakub Kicinski stats64->rx_dropped += rx_dropped; 50045d84008SJakub Kicinski } 50145d84008SJakub Kicinski } 50245d84008SJakub Kicinski 503bc610777SAlexander Duyck static const struct net_device_ops fbnic_netdev_ops = { 504bc610777SAlexander Duyck .ndo_open = fbnic_open, 505bc610777SAlexander Duyck .ndo_stop = fbnic_stop, 506bc610777SAlexander Duyck .ndo_validate_addr = eth_validate_addr, 507bc610777SAlexander Duyck .ndo_start_xmit = fbnic_xmit_frame, 5089a57bacdSAlexander Duyck .ndo_features_check = fbnic_features_check, 509eb690ef8SAlexander Duyck .ndo_set_mac_address = fbnic_set_mac, 510eb690ef8SAlexander Duyck .ndo_set_rx_mode = fbnic_set_rx_mode, 51145d84008SJakub Kicinski .ndo_get_stats64 = fbnic_get_stats64, 5126a2b3edeSVadim Fedorenko .ndo_hwtstamp_get = fbnic_hwtstamp_get, 5136a2b3edeSVadim Fedorenko .ndo_hwtstamp_set = fbnic_hwtstamp_set, 514bc610777SAlexander Duyck }; 515bc610777SAlexander Duyck 5168be1bd91SStanislav Fomichev static void fbnic_get_queue_stats_rx(struct net_device *dev, int idx, 5178be1bd91SStanislav Fomichev struct netdev_queue_stats_rx *rx) 5188be1bd91SStanislav Fomichev { 5198be1bd91SStanislav Fomichev struct fbnic_net *fbn = netdev_priv(dev); 5208be1bd91SStanislav Fomichev struct fbnic_ring *rxr = fbn->rx[idx]; 5218f20a2bfSMohsin Bashir struct fbnic_dev *fbd = fbn->fbd; 5228be1bd91SStanislav Fomichev struct fbnic_queue_stats *stats; 52367dc4eb5SJakub Kicinski u64 bytes, packets, alloc_fail; 52467dc4eb5SJakub Kicinski u64 csum_complete, csum_none; 5258be1bd91SStanislav Fomichev unsigned int start; 5268be1bd91SStanislav Fomichev 5278be1bd91SStanislav Fomichev if (!rxr) 5288be1bd91SStanislav Fomichev return; 5298be1bd91SStanislav Fomichev 5308be1bd91SStanislav Fomichev stats = &rxr->stats; 5318be1bd91SStanislav Fomichev do { 5328be1bd91SStanislav Fomichev start = u64_stats_fetch_begin(&stats->syncp); 5338be1bd91SStanislav Fomichev bytes = stats->bytes; 5348be1bd91SStanislav Fomichev packets = stats->packets; 53567dc4eb5SJakub Kicinski alloc_fail = stats->rx.alloc_failed; 53667dc4eb5SJakub Kicinski csum_complete = stats->rx.csum_complete; 53767dc4eb5SJakub Kicinski csum_none = stats->rx.csum_none; 5388be1bd91SStanislav Fomichev } while (u64_stats_fetch_retry(&stats->syncp, start)); 5398be1bd91SStanislav Fomichev 5408be1bd91SStanislav Fomichev rx->bytes = bytes; 5418be1bd91SStanislav Fomichev rx->packets = packets; 54267dc4eb5SJakub Kicinski rx->alloc_fail = alloc_fail; 54367dc4eb5SJakub Kicinski rx->csum_complete = csum_complete; 54467dc4eb5SJakub Kicinski rx->csum_none = csum_none; 5458f20a2bfSMohsin Bashir 5468f20a2bfSMohsin Bashir fbnic_get_hw_q_stats(fbd, fbd->hw_stats.hw_q); 5478f20a2bfSMohsin Bashir 5488f20a2bfSMohsin Bashir spin_lock(&fbd->hw_stats_lock); 5498f20a2bfSMohsin Bashir rx->hw_drop_overruns = fbd->hw_stats.hw_q[idx].rde_pkt_cq_drop.value + 5508f20a2bfSMohsin Bashir fbd->hw_stats.hw_q[idx].rde_pkt_bdq_drop.value; 5518f20a2bfSMohsin Bashir rx->hw_drops = fbd->hw_stats.hw_q[idx].rde_pkt_err.value + 5528f20a2bfSMohsin Bashir rx->hw_drop_overruns; 5538f20a2bfSMohsin Bashir spin_unlock(&fbd->hw_stats_lock); 5548be1bd91SStanislav Fomichev } 5558be1bd91SStanislav Fomichev 5568be1bd91SStanislav Fomichev static void fbnic_get_queue_stats_tx(struct net_device *dev, int idx, 5578be1bd91SStanislav Fomichev struct netdev_queue_stats_tx *tx) 5588be1bd91SStanislav Fomichev { 5598be1bd91SStanislav Fomichev struct fbnic_net *fbn = netdev_priv(dev); 5608be1bd91SStanislav Fomichev struct fbnic_ring *txr = fbn->tx[idx]; 5618be1bd91SStanislav Fomichev struct fbnic_queue_stats *stats; 562b0b0f520SJakub Kicinski u64 stop, wake, csum, lso; 5638be1bd91SStanislav Fomichev unsigned int start; 5648be1bd91SStanislav Fomichev u64 bytes, packets; 5658be1bd91SStanislav Fomichev 5668be1bd91SStanislav Fomichev if (!txr) 5678be1bd91SStanislav Fomichev return; 5688be1bd91SStanislav Fomichev 5698be1bd91SStanislav Fomichev stats = &txr->stats; 5708be1bd91SStanislav Fomichev do { 5718be1bd91SStanislav Fomichev start = u64_stats_fetch_begin(&stats->syncp); 5728be1bd91SStanislav Fomichev bytes = stats->bytes; 5738be1bd91SStanislav Fomichev packets = stats->packets; 5741e07e361SJakub Kicinski csum = stats->twq.csum_partial; 575b0b0f520SJakub Kicinski lso = stats->twq.lso; 5761e07e361SJakub Kicinski stop = stats->twq.stop; 5771e07e361SJakub Kicinski wake = stats->twq.wake; 5788be1bd91SStanislav Fomichev } while (u64_stats_fetch_retry(&stats->syncp, start)); 5798be1bd91SStanislav Fomichev 5808be1bd91SStanislav Fomichev tx->bytes = bytes; 5818be1bd91SStanislav Fomichev tx->packets = packets; 582b0b0f520SJakub Kicinski tx->needs_csum = csum + lso; 583b0b0f520SJakub Kicinski tx->hw_gso_wire_packets = lso; 5841e07e361SJakub Kicinski tx->stop = stop; 5851e07e361SJakub Kicinski tx->wake = wake; 5868be1bd91SStanislav Fomichev } 5878be1bd91SStanislav Fomichev 5888be1bd91SStanislav Fomichev static void fbnic_get_base_stats(struct net_device *dev, 5898be1bd91SStanislav Fomichev struct netdev_queue_stats_rx *rx, 5908be1bd91SStanislav Fomichev struct netdev_queue_stats_tx *tx) 5918be1bd91SStanislav Fomichev { 5928be1bd91SStanislav Fomichev struct fbnic_net *fbn = netdev_priv(dev); 5938be1bd91SStanislav Fomichev 5948be1bd91SStanislav Fomichev tx->bytes = fbn->tx_stats.bytes; 5958be1bd91SStanislav Fomichev tx->packets = fbn->tx_stats.packets; 596b0b0f520SJakub Kicinski tx->needs_csum = fbn->tx_stats.twq.csum_partial + fbn->tx_stats.twq.lso; 597b0b0f520SJakub Kicinski tx->hw_gso_wire_packets = fbn->tx_stats.twq.lso; 5981e07e361SJakub Kicinski tx->stop = fbn->tx_stats.twq.stop; 5991e07e361SJakub Kicinski tx->wake = fbn->tx_stats.twq.wake; 6008be1bd91SStanislav Fomichev 6018be1bd91SStanislav Fomichev rx->bytes = fbn->rx_stats.bytes; 6028be1bd91SStanislav Fomichev rx->packets = fbn->rx_stats.packets; 60367dc4eb5SJakub Kicinski rx->alloc_fail = fbn->rx_stats.rx.alloc_failed; 60467dc4eb5SJakub Kicinski rx->csum_complete = fbn->rx_stats.rx.csum_complete; 60567dc4eb5SJakub Kicinski rx->csum_none = fbn->rx_stats.rx.csum_none; 6068be1bd91SStanislav Fomichev } 6078be1bd91SStanislav Fomichev 6088be1bd91SStanislav Fomichev static const struct netdev_stat_ops fbnic_stat_ops = { 6098be1bd91SStanislav Fomichev .get_queue_stats_rx = fbnic_get_queue_stats_rx, 6108be1bd91SStanislav Fomichev .get_queue_stats_tx = fbnic_get_queue_stats_tx, 6118be1bd91SStanislav Fomichev .get_base_stats = fbnic_get_base_stats, 6128be1bd91SStanislav Fomichev }; 6138be1bd91SStanislav Fomichev 614bc610777SAlexander Duyck void fbnic_reset_queues(struct fbnic_net *fbn, 615bc610777SAlexander Duyck unsigned int tx, unsigned int rx) 616bc610777SAlexander Duyck { 617bc610777SAlexander Duyck struct fbnic_dev *fbd = fbn->fbd; 618bc610777SAlexander Duyck unsigned int max_napis; 619bc610777SAlexander Duyck 620bc610777SAlexander Duyck max_napis = fbd->num_irqs - FBNIC_NON_NAPI_VECTORS; 621bc610777SAlexander Duyck 622bc610777SAlexander Duyck tx = min(tx, max_napis); 623bc610777SAlexander Duyck fbn->num_tx_queues = tx; 624bc610777SAlexander Duyck 625bc610777SAlexander Duyck rx = min(rx, max_napis); 626bc610777SAlexander Duyck fbn->num_rx_queues = rx; 627bc610777SAlexander Duyck 628bc610777SAlexander Duyck fbn->num_napi = max(tx, rx); 629bc610777SAlexander Duyck } 630bc610777SAlexander Duyck 631bc610777SAlexander Duyck /** 632bc610777SAlexander Duyck * fbnic_netdev_free - Free the netdev associate with fbnic 633bc610777SAlexander Duyck * @fbd: Driver specific structure to free netdev from 634bc610777SAlexander Duyck * 635bc610777SAlexander Duyck * Allocate and initialize the netdev and netdev private structure. Bind 636bc610777SAlexander Duyck * together the hardware, netdev, and pci data structures. 637bc610777SAlexander Duyck **/ 638bc610777SAlexander Duyck void fbnic_netdev_free(struct fbnic_dev *fbd) 639bc610777SAlexander Duyck { 64069684376SAlexander Duyck struct fbnic_net *fbn = netdev_priv(fbd->netdev); 64169684376SAlexander Duyck 64269684376SAlexander Duyck if (fbn->phylink) 64369684376SAlexander Duyck phylink_destroy(fbn->phylink); 64469684376SAlexander Duyck 645bc610777SAlexander Duyck free_netdev(fbd->netdev); 646bc610777SAlexander Duyck fbd->netdev = NULL; 647bc610777SAlexander Duyck } 648bc610777SAlexander Duyck 649bc610777SAlexander Duyck /** 650bc610777SAlexander Duyck * fbnic_netdev_alloc - Allocate a netdev and associate with fbnic 651bc610777SAlexander Duyck * @fbd: Driver specific structure to associate netdev with 652bc610777SAlexander Duyck * 653bc610777SAlexander Duyck * Allocate and initialize the netdev and netdev private structure. Bind 654bc610777SAlexander Duyck * together the hardware, netdev, and pci data structures. 655bc610777SAlexander Duyck * 65626aa7992SMohsin Bashir * Return: Pointer to net_device on success, NULL on failure 657bc610777SAlexander Duyck **/ 658bc610777SAlexander Duyck struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd) 659bc610777SAlexander Duyck { 660bc610777SAlexander Duyck struct net_device *netdev; 661bc610777SAlexander Duyck struct fbnic_net *fbn; 662bc610777SAlexander Duyck int default_queues; 663bc610777SAlexander Duyck 664bc610777SAlexander Duyck netdev = alloc_etherdev_mq(sizeof(*fbn), FBNIC_MAX_RXQS); 665bc610777SAlexander Duyck if (!netdev) 666bc610777SAlexander Duyck return NULL; 667bc610777SAlexander Duyck 668bc610777SAlexander Duyck SET_NETDEV_DEV(netdev, fbd->dev); 669bc610777SAlexander Duyck fbd->netdev = netdev; 670bc610777SAlexander Duyck 671bc610777SAlexander Duyck netdev->netdev_ops = &fbnic_netdev_ops; 6728be1bd91SStanislav Fomichev netdev->stat_ops = &fbnic_stat_ops; 673bc610777SAlexander Duyck 674bd2557a5SMohsin Bashir fbnic_set_ethtool_ops(netdev); 675bd2557a5SMohsin Bashir 676bc610777SAlexander Duyck fbn = netdev_priv(netdev); 677bc610777SAlexander Duyck 678bc610777SAlexander Duyck fbn->netdev = netdev; 679bc610777SAlexander Duyck fbn->fbd = fbd; 680bc610777SAlexander Duyck 68140bf06a1SAlexander Duyck fbn->txq_size = FBNIC_TXQ_SIZE_DEFAULT; 6820cb4c0a1SAlexander Duyck fbn->hpq_size = FBNIC_HPQ_SIZE_DEFAULT; 6830cb4c0a1SAlexander Duyck fbn->ppq_size = FBNIC_PPQ_SIZE_DEFAULT; 6840cb4c0a1SAlexander Duyck fbn->rcq_size = FBNIC_RCQ_SIZE_DEFAULT; 68540bf06a1SAlexander Duyck 6867b5b7a59SMohsin Bashir fbn->tx_usecs = FBNIC_TX_USECS_DEFAULT; 6877b5b7a59SMohsin Bashir fbn->rx_usecs = FBNIC_RX_USECS_DEFAULT; 6887b5b7a59SMohsin Bashir fbn->rx_max_frames = FBNIC_RX_FRAMES_DEFAULT; 6897b5b7a59SMohsin Bashir 690bc610777SAlexander Duyck default_queues = netif_get_num_default_rss_queues(); 691bc610777SAlexander Duyck if (default_queues > fbd->max_num_queues) 692bc610777SAlexander Duyck default_queues = fbd->max_num_queues; 693bc610777SAlexander Duyck 694bc610777SAlexander Duyck fbnic_reset_queues(fbn, default_queues, default_queues); 695bc610777SAlexander Duyck 696355440a6SAlexander Duyck fbnic_reset_indir_tbl(fbn); 697355440a6SAlexander Duyck fbnic_rss_key_fill(fbn->rss_key); 698355440a6SAlexander Duyck fbnic_rss_init_en_mask(fbn); 699355440a6SAlexander Duyck 70009717c28SAlexander Duyck netdev->priv_flags |= IFF_UNICAST_FLT; 70109717c28SAlexander Duyck 702b0b0f520SJakub Kicinski netdev->gso_partial_features = 703b0b0f520SJakub Kicinski NETIF_F_GSO_GRE | 704b0b0f520SJakub Kicinski NETIF_F_GSO_GRE_CSUM | 705b0b0f520SJakub Kicinski NETIF_F_GSO_IPXIP4 | 706b0b0f520SJakub Kicinski NETIF_F_GSO_UDP_TUNNEL | 707b0b0f520SJakub Kicinski NETIF_F_GSO_UDP_TUNNEL_CSUM; 708b0b0f520SJakub Kicinski 7099a57bacdSAlexander Duyck netdev->features |= 710b0b0f520SJakub Kicinski netdev->gso_partial_features | 711b0b0f520SJakub Kicinski FBNIC_TUN_GSO_FEATURES | 712a29b8eb6SAlexander Duyck NETIF_F_RXHASH | 7139a57bacdSAlexander Duyck NETIF_F_SG | 714a29b8eb6SAlexander Duyck NETIF_F_HW_CSUM | 715b0b0f520SJakub Kicinski NETIF_F_RXCSUM | 716b0b0f520SJakub Kicinski NETIF_F_TSO | 717b0b0f520SJakub Kicinski NETIF_F_TSO_ECN | 718b0b0f520SJakub Kicinski NETIF_F_TSO6 | 719b0b0f520SJakub Kicinski NETIF_F_GSO_PARTIAL | 720b0b0f520SJakub Kicinski NETIF_F_GSO_UDP_L4; 7219a57bacdSAlexander Duyck 7229a57bacdSAlexander Duyck netdev->hw_features |= netdev->features; 7239a57bacdSAlexander Duyck netdev->vlan_features |= netdev->features; 7249a57bacdSAlexander Duyck netdev->hw_enc_features |= netdev->features; 72522300354SAlexander Duyck netdev->features |= NETIF_F_NTUPLE; 7269a57bacdSAlexander Duyck 727bc610777SAlexander Duyck netdev->min_mtu = IPV6_MIN_MTU; 728bc610777SAlexander Duyck netdev->max_mtu = FBNIC_MAX_JUMBO_FRAME_SIZE - ETH_HLEN; 729bc610777SAlexander Duyck 73069684376SAlexander Duyck /* TBD: This is workaround for BMC as phylink doesn't have support 73169684376SAlexander Duyck * for leavling the link enabled if a BMC is present. 73269684376SAlexander Duyck */ 73369684376SAlexander Duyck netdev->ethtool->wol_enabled = true; 73469684376SAlexander Duyck 73569684376SAlexander Duyck fbn->fec = FBNIC_FEC_AUTO | FBNIC_FEC_RS; 73669684376SAlexander Duyck fbn->link_mode = FBNIC_LINK_AUTO | FBNIC_LINK_50R2; 737bc610777SAlexander Duyck netif_carrier_off(netdev); 738bc610777SAlexander Duyck 739bc610777SAlexander Duyck netif_tx_stop_all_queues(netdev); 740bc610777SAlexander Duyck 74169684376SAlexander Duyck if (fbnic_phylink_init(netdev)) { 74269684376SAlexander Duyck fbnic_netdev_free(fbd); 74369684376SAlexander Duyck return NULL; 74469684376SAlexander Duyck } 74569684376SAlexander Duyck 746bc610777SAlexander Duyck return netdev; 747bc610777SAlexander Duyck } 748bc610777SAlexander Duyck 749bc610777SAlexander Duyck static int fbnic_dsn_to_mac_addr(u64 dsn, char *addr) 750bc610777SAlexander Duyck { 751bc610777SAlexander Duyck addr[0] = (dsn >> 56) & 0xFF; 752bc610777SAlexander Duyck addr[1] = (dsn >> 48) & 0xFF; 753bc610777SAlexander Duyck addr[2] = (dsn >> 40) & 0xFF; 754bc610777SAlexander Duyck addr[3] = (dsn >> 16) & 0xFF; 755bc610777SAlexander Duyck addr[4] = (dsn >> 8) & 0xFF; 756bc610777SAlexander Duyck addr[5] = dsn & 0xFF; 757bc610777SAlexander Duyck 758bc610777SAlexander Duyck return is_valid_ether_addr(addr) ? 0 : -EINVAL; 759bc610777SAlexander Duyck } 760bc610777SAlexander Duyck 761bc610777SAlexander Duyck /** 762bc610777SAlexander Duyck * fbnic_netdev_register - Initialize general software structures 763bc610777SAlexander Duyck * @netdev: Netdev containing structure to initialize and register 764bc610777SAlexander Duyck * 765bc610777SAlexander Duyck * Initialize the MAC address for the netdev and register it. 766bc610777SAlexander Duyck * 767bc610777SAlexander Duyck * Return: 0 on success, negative on failure 768bc610777SAlexander Duyck **/ 769bc610777SAlexander Duyck int fbnic_netdev_register(struct net_device *netdev) 770bc610777SAlexander Duyck { 771bc610777SAlexander Duyck struct fbnic_net *fbn = netdev_priv(netdev); 772bc610777SAlexander Duyck struct fbnic_dev *fbd = fbn->fbd; 773bc610777SAlexander Duyck u64 dsn = fbd->dsn; 774bc610777SAlexander Duyck u8 addr[ETH_ALEN]; 775bc610777SAlexander Duyck int err; 776bc610777SAlexander Duyck 777bc610777SAlexander Duyck err = fbnic_dsn_to_mac_addr(dsn, addr); 778bc610777SAlexander Duyck if (!err) { 779bc610777SAlexander Duyck ether_addr_copy(netdev->perm_addr, addr); 780bc610777SAlexander Duyck eth_hw_addr_set(netdev, addr); 781bc610777SAlexander Duyck } else { 782bc610777SAlexander Duyck /* A randomly assigned MAC address will cause provisioning 783bc610777SAlexander Duyck * issues so instead just fail to spawn the netdev and 784bc610777SAlexander Duyck * avoid any confusion. 785bc610777SAlexander Duyck */ 786bc610777SAlexander Duyck dev_err(fbd->dev, "MAC addr %pM invalid\n", addr); 787bc610777SAlexander Duyck return err; 788bc610777SAlexander Duyck } 789bc610777SAlexander Duyck 790bc610777SAlexander Duyck return register_netdev(netdev); 791bc610777SAlexander Duyck } 792bc610777SAlexander Duyck 793bc610777SAlexander Duyck void fbnic_netdev_unregister(struct net_device *netdev) 794bc610777SAlexander Duyck { 795bc610777SAlexander Duyck unregister_netdev(netdev); 796bc610777SAlexander Duyck } 797