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> 7bc610777SAlexander Duyck 8bc610777SAlexander Duyck #include "fbnic.h" 9bc610777SAlexander Duyck #include "fbnic_netdev.h" 10bc610777SAlexander Duyck #include "fbnic_txrx.h" 11bc610777SAlexander Duyck 12bc610777SAlexander Duyck int __fbnic_open(struct fbnic_net *fbn) 13bc610777SAlexander Duyck { 1420d2e88cSAlexander Duyck struct fbnic_dev *fbd = fbn->fbd; 15bc610777SAlexander Duyck int err; 16bc610777SAlexander Duyck 17bc610777SAlexander Duyck err = fbnic_alloc_napi_vectors(fbn); 18bc610777SAlexander Duyck if (err) 19bc610777SAlexander Duyck return err; 20bc610777SAlexander Duyck 2140bf06a1SAlexander Duyck err = fbnic_alloc_resources(fbn); 2240bf06a1SAlexander Duyck if (err) 2340bf06a1SAlexander Duyck goto free_napi_vectors; 2440bf06a1SAlexander Duyck 25bc610777SAlexander Duyck err = netif_set_real_num_tx_queues(fbn->netdev, 26bc610777SAlexander Duyck fbn->num_tx_queues); 27bc610777SAlexander Duyck if (err) 28bc610777SAlexander Duyck goto free_resources; 29bc610777SAlexander Duyck 30bc610777SAlexander Duyck err = netif_set_real_num_rx_queues(fbn->netdev, 31bc610777SAlexander Duyck fbn->num_rx_queues); 32bc610777SAlexander Duyck if (err) 33bc610777SAlexander Duyck goto free_resources; 34bc610777SAlexander Duyck 3520d2e88cSAlexander Duyck /* Send ownership message and flush to verify FW has seen it */ 3620d2e88cSAlexander Duyck err = fbnic_fw_xmit_ownership_msg(fbd, true); 3720d2e88cSAlexander Duyck if (err) { 3820d2e88cSAlexander Duyck dev_warn(fbd->dev, 3920d2e88cSAlexander Duyck "Error %d sending host ownership message to the firmware\n", 4020d2e88cSAlexander Duyck err); 4120d2e88cSAlexander Duyck goto free_resources; 4220d2e88cSAlexander Duyck } 4320d2e88cSAlexander Duyck 4420d2e88cSAlexander Duyck err = fbnic_fw_init_heartbeat(fbd, false); 4520d2e88cSAlexander Duyck if (err) 4620d2e88cSAlexander Duyck goto release_ownership; 4720d2e88cSAlexander Duyck 4869684376SAlexander Duyck err = fbnic_pcs_irq_enable(fbd); 4969684376SAlexander Duyck if (err) 5069684376SAlexander Duyck goto release_ownership; 5169684376SAlexander Duyck 52bc610777SAlexander Duyck return 0; 5320d2e88cSAlexander Duyck release_ownership: 5420d2e88cSAlexander Duyck fbnic_fw_xmit_ownership_msg(fbn->fbd, false); 55bc610777SAlexander Duyck free_resources: 5640bf06a1SAlexander Duyck fbnic_free_resources(fbn); 5740bf06a1SAlexander Duyck free_napi_vectors: 58bc610777SAlexander Duyck fbnic_free_napi_vectors(fbn); 59bc610777SAlexander Duyck return err; 60bc610777SAlexander Duyck } 61bc610777SAlexander Duyck 62bc610777SAlexander Duyck static int fbnic_open(struct net_device *netdev) 63bc610777SAlexander Duyck { 64bc610777SAlexander Duyck struct fbnic_net *fbn = netdev_priv(netdev); 65bc610777SAlexander Duyck int err; 66bc610777SAlexander Duyck 67bc610777SAlexander Duyck err = __fbnic_open(fbn); 68bc610777SAlexander Duyck if (!err) 69bc610777SAlexander Duyck fbnic_up(fbn); 70bc610777SAlexander Duyck 71bc610777SAlexander Duyck return err; 72bc610777SAlexander Duyck } 73bc610777SAlexander Duyck 74bc610777SAlexander Duyck static int fbnic_stop(struct net_device *netdev) 75bc610777SAlexander Duyck { 76bc610777SAlexander Duyck struct fbnic_net *fbn = netdev_priv(netdev); 77bc610777SAlexander Duyck 78bc610777SAlexander Duyck fbnic_down(fbn); 7969684376SAlexander Duyck fbnic_pcs_irq_disable(fbn->fbd); 80bc610777SAlexander Duyck 8120d2e88cSAlexander Duyck fbnic_fw_xmit_ownership_msg(fbn->fbd, false); 8220d2e88cSAlexander Duyck 8340bf06a1SAlexander Duyck fbnic_free_resources(fbn); 84bc610777SAlexander Duyck fbnic_free_napi_vectors(fbn); 85bc610777SAlexander Duyck 86bc610777SAlexander Duyck return 0; 87bc610777SAlexander Duyck } 88bc610777SAlexander Duyck 89bc610777SAlexander Duyck static const struct net_device_ops fbnic_netdev_ops = { 90bc610777SAlexander Duyck .ndo_open = fbnic_open, 91bc610777SAlexander Duyck .ndo_stop = fbnic_stop, 92bc610777SAlexander Duyck .ndo_validate_addr = eth_validate_addr, 93bc610777SAlexander Duyck .ndo_start_xmit = fbnic_xmit_frame, 94bc610777SAlexander Duyck }; 95bc610777SAlexander Duyck 96bc610777SAlexander Duyck void fbnic_reset_queues(struct fbnic_net *fbn, 97bc610777SAlexander Duyck unsigned int tx, unsigned int rx) 98bc610777SAlexander Duyck { 99bc610777SAlexander Duyck struct fbnic_dev *fbd = fbn->fbd; 100bc610777SAlexander Duyck unsigned int max_napis; 101bc610777SAlexander Duyck 102bc610777SAlexander Duyck max_napis = fbd->num_irqs - FBNIC_NON_NAPI_VECTORS; 103bc610777SAlexander Duyck 104bc610777SAlexander Duyck tx = min(tx, max_napis); 105bc610777SAlexander Duyck fbn->num_tx_queues = tx; 106bc610777SAlexander Duyck 107bc610777SAlexander Duyck rx = min(rx, max_napis); 108bc610777SAlexander Duyck fbn->num_rx_queues = rx; 109bc610777SAlexander Duyck 110bc610777SAlexander Duyck fbn->num_napi = max(tx, rx); 111bc610777SAlexander Duyck } 112bc610777SAlexander Duyck 113bc610777SAlexander Duyck /** 114bc610777SAlexander Duyck * fbnic_netdev_free - Free the netdev associate with fbnic 115bc610777SAlexander Duyck * @fbd: Driver specific structure to free netdev from 116bc610777SAlexander Duyck * 117bc610777SAlexander Duyck * Allocate and initialize the netdev and netdev private structure. Bind 118bc610777SAlexander Duyck * together the hardware, netdev, and pci data structures. 119bc610777SAlexander Duyck **/ 120bc610777SAlexander Duyck void fbnic_netdev_free(struct fbnic_dev *fbd) 121bc610777SAlexander Duyck { 12269684376SAlexander Duyck struct fbnic_net *fbn = netdev_priv(fbd->netdev); 12369684376SAlexander Duyck 12469684376SAlexander Duyck if (fbn->phylink) 12569684376SAlexander Duyck phylink_destroy(fbn->phylink); 12669684376SAlexander Duyck 127bc610777SAlexander Duyck free_netdev(fbd->netdev); 128bc610777SAlexander Duyck fbd->netdev = NULL; 129bc610777SAlexander Duyck } 130bc610777SAlexander Duyck 131bc610777SAlexander Duyck /** 132bc610777SAlexander Duyck * fbnic_netdev_alloc - Allocate a netdev and associate with fbnic 133bc610777SAlexander Duyck * @fbd: Driver specific structure to associate netdev with 134bc610777SAlexander Duyck * 135bc610777SAlexander Duyck * Allocate and initialize the netdev and netdev private structure. Bind 136bc610777SAlexander Duyck * together the hardware, netdev, and pci data structures. 137bc610777SAlexander Duyck * 138bc610777SAlexander Duyck * Return: 0 on success, negative on failure 139bc610777SAlexander Duyck **/ 140bc610777SAlexander Duyck struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd) 141bc610777SAlexander Duyck { 142bc610777SAlexander Duyck struct net_device *netdev; 143bc610777SAlexander Duyck struct fbnic_net *fbn; 144bc610777SAlexander Duyck int default_queues; 145bc610777SAlexander Duyck 146bc610777SAlexander Duyck netdev = alloc_etherdev_mq(sizeof(*fbn), FBNIC_MAX_RXQS); 147bc610777SAlexander Duyck if (!netdev) 148bc610777SAlexander Duyck return NULL; 149bc610777SAlexander Duyck 150bc610777SAlexander Duyck SET_NETDEV_DEV(netdev, fbd->dev); 151bc610777SAlexander Duyck fbd->netdev = netdev; 152bc610777SAlexander Duyck 153bc610777SAlexander Duyck netdev->netdev_ops = &fbnic_netdev_ops; 154bc610777SAlexander Duyck 155bc610777SAlexander Duyck fbn = netdev_priv(netdev); 156bc610777SAlexander Duyck 157bc610777SAlexander Duyck fbn->netdev = netdev; 158bc610777SAlexander Duyck fbn->fbd = fbd; 159bc610777SAlexander Duyck INIT_LIST_HEAD(&fbn->napis); 160bc610777SAlexander Duyck 16140bf06a1SAlexander Duyck fbn->txq_size = FBNIC_TXQ_SIZE_DEFAULT; 1620cb4c0a1SAlexander Duyck fbn->hpq_size = FBNIC_HPQ_SIZE_DEFAULT; 1630cb4c0a1SAlexander Duyck fbn->ppq_size = FBNIC_PPQ_SIZE_DEFAULT; 1640cb4c0a1SAlexander Duyck fbn->rcq_size = FBNIC_RCQ_SIZE_DEFAULT; 16540bf06a1SAlexander Duyck 166bc610777SAlexander Duyck default_queues = netif_get_num_default_rss_queues(); 167bc610777SAlexander Duyck if (default_queues > fbd->max_num_queues) 168bc610777SAlexander Duyck default_queues = fbd->max_num_queues; 169bc610777SAlexander Duyck 170bc610777SAlexander Duyck fbnic_reset_queues(fbn, default_queues, default_queues); 171bc610777SAlexander Duyck 172bc610777SAlexander Duyck netdev->min_mtu = IPV6_MIN_MTU; 173bc610777SAlexander Duyck netdev->max_mtu = FBNIC_MAX_JUMBO_FRAME_SIZE - ETH_HLEN; 174bc610777SAlexander Duyck 17569684376SAlexander Duyck /* TBD: This is workaround for BMC as phylink doesn't have support 17669684376SAlexander Duyck * for leavling the link enabled if a BMC is present. 17769684376SAlexander Duyck */ 17869684376SAlexander Duyck netdev->ethtool->wol_enabled = true; 17969684376SAlexander Duyck 18069684376SAlexander Duyck fbn->fec = FBNIC_FEC_AUTO | FBNIC_FEC_RS; 18169684376SAlexander Duyck fbn->link_mode = FBNIC_LINK_AUTO | FBNIC_LINK_50R2; 182bc610777SAlexander Duyck netif_carrier_off(netdev); 183bc610777SAlexander Duyck 184bc610777SAlexander Duyck netif_tx_stop_all_queues(netdev); 185bc610777SAlexander Duyck 18669684376SAlexander Duyck if (fbnic_phylink_init(netdev)) { 18769684376SAlexander Duyck fbnic_netdev_free(fbd); 18869684376SAlexander Duyck return NULL; 18969684376SAlexander Duyck } 19069684376SAlexander Duyck 191bc610777SAlexander Duyck return netdev; 192bc610777SAlexander Duyck } 193bc610777SAlexander Duyck 194bc610777SAlexander Duyck static int fbnic_dsn_to_mac_addr(u64 dsn, char *addr) 195bc610777SAlexander Duyck { 196bc610777SAlexander Duyck addr[0] = (dsn >> 56) & 0xFF; 197bc610777SAlexander Duyck addr[1] = (dsn >> 48) & 0xFF; 198bc610777SAlexander Duyck addr[2] = (dsn >> 40) & 0xFF; 199bc610777SAlexander Duyck addr[3] = (dsn >> 16) & 0xFF; 200bc610777SAlexander Duyck addr[4] = (dsn >> 8) & 0xFF; 201bc610777SAlexander Duyck addr[5] = dsn & 0xFF; 202bc610777SAlexander Duyck 203bc610777SAlexander Duyck return is_valid_ether_addr(addr) ? 0 : -EINVAL; 204bc610777SAlexander Duyck } 205bc610777SAlexander Duyck 206bc610777SAlexander Duyck /** 207bc610777SAlexander Duyck * fbnic_netdev_register - Initialize general software structures 208bc610777SAlexander Duyck * @netdev: Netdev containing structure to initialize and register 209bc610777SAlexander Duyck * 210bc610777SAlexander Duyck * Initialize the MAC address for the netdev and register it. 211bc610777SAlexander Duyck * 212bc610777SAlexander Duyck * Return: 0 on success, negative on failure 213bc610777SAlexander Duyck **/ 214bc610777SAlexander Duyck int fbnic_netdev_register(struct net_device *netdev) 215bc610777SAlexander Duyck { 216bc610777SAlexander Duyck struct fbnic_net *fbn = netdev_priv(netdev); 217bc610777SAlexander Duyck struct fbnic_dev *fbd = fbn->fbd; 218bc610777SAlexander Duyck u64 dsn = fbd->dsn; 219bc610777SAlexander Duyck u8 addr[ETH_ALEN]; 220bc610777SAlexander Duyck int err; 221bc610777SAlexander Duyck 222bc610777SAlexander Duyck err = fbnic_dsn_to_mac_addr(dsn, addr); 223bc610777SAlexander Duyck if (!err) { 224bc610777SAlexander Duyck ether_addr_copy(netdev->perm_addr, addr); 225bc610777SAlexander Duyck eth_hw_addr_set(netdev, addr); 226bc610777SAlexander Duyck } else { 227bc610777SAlexander Duyck /* A randomly assigned MAC address will cause provisioning 228bc610777SAlexander Duyck * issues so instead just fail to spawn the netdev and 229bc610777SAlexander Duyck * avoid any confusion. 230bc610777SAlexander Duyck */ 231bc610777SAlexander Duyck dev_err(fbd->dev, "MAC addr %pM invalid\n", addr); 232bc610777SAlexander Duyck return err; 233bc610777SAlexander Duyck } 234bc610777SAlexander Duyck 235bc610777SAlexander Duyck return register_netdev(netdev); 236bc610777SAlexander Duyck } 237bc610777SAlexander Duyck 238bc610777SAlexander Duyck void fbnic_netdev_unregister(struct net_device *netdev) 239bc610777SAlexander Duyck { 240bc610777SAlexander Duyck unregister_netdev(netdev); 241bc610777SAlexander Duyck } 242