14c45a51eSXuan Zhuo // SPDX-License-Identifier: GPL-2.0-or-later 24c45a51eSXuan Zhuo /* 34c45a51eSXuan Zhuo * Driver for Alibaba Elastic Ethernet Adapter. 44c45a51eSXuan Zhuo * 54c45a51eSXuan Zhuo * Copyright (C) 2025 Alibaba Inc. 64c45a51eSXuan Zhuo */ 74c45a51eSXuan Zhuo 84c45a51eSXuan Zhuo #include <linux/etherdevice.h> 94c45a51eSXuan Zhuo #include <linux/module.h> 104c45a51eSXuan Zhuo #include <linux/netdevice.h> 114c45a51eSXuan Zhuo #include <linux/rtnetlink.h> 124c45a51eSXuan Zhuo #include <net/netdev_queues.h> 134c45a51eSXuan Zhuo 144c45a51eSXuan Zhuo #include "eea_adminq.h" 154c45a51eSXuan Zhuo #include "eea_net.h" 164c45a51eSXuan Zhuo #include "eea_pci.h" 174c45a51eSXuan Zhuo #include "eea_ring.h" 184c45a51eSXuan Zhuo 194c45a51eSXuan Zhuo #define EEA_SPLIT_HDR_SIZE ALIGN(128, L1_CACHE_BYTES) 204c45a51eSXuan Zhuo 21aa8bca4cSXuan Zhuo static irqreturn_t eea_irq_handler(int irq, void *data) 22aa8bca4cSXuan Zhuo { 23aa8bca4cSXuan Zhuo struct eea_irq_blk *blk = data; 24aa8bca4cSXuan Zhuo 25aa8bca4cSXuan Zhuo napi_schedule_irqoff(&blk->napi); 26aa8bca4cSXuan Zhuo 27aa8bca4cSXuan Zhuo return IRQ_HANDLED; 28aa8bca4cSXuan Zhuo } 29aa8bca4cSXuan Zhuo 30aa8bca4cSXuan Zhuo static void eea_free_irq_blk(struct eea_net *enet) 31aa8bca4cSXuan Zhuo { 32aa8bca4cSXuan Zhuo struct eea_irq_blk *blk; 33aa8bca4cSXuan Zhuo u32 num; 34aa8bca4cSXuan Zhuo int i; 35aa8bca4cSXuan Zhuo 36aa8bca4cSXuan Zhuo if (!enet->irq_blks) 37aa8bca4cSXuan Zhuo return; 38aa8bca4cSXuan Zhuo 39aa8bca4cSXuan Zhuo num = enet->edev->rx_num; 40aa8bca4cSXuan Zhuo 41aa8bca4cSXuan Zhuo for (i = 0; i < num; i++) { 42aa8bca4cSXuan Zhuo blk = &enet->irq_blks[i]; 43aa8bca4cSXuan Zhuo 44aa8bca4cSXuan Zhuo if (blk->ready) 45aa8bca4cSXuan Zhuo eea_pci_free_irq(blk); 46aa8bca4cSXuan Zhuo 47aa8bca4cSXuan Zhuo blk->ready = false; 48aa8bca4cSXuan Zhuo } 49aa8bca4cSXuan Zhuo 50aa8bca4cSXuan Zhuo kvfree(enet->irq_blks); 51aa8bca4cSXuan Zhuo enet->irq_blks = NULL; 52aa8bca4cSXuan Zhuo } 53aa8bca4cSXuan Zhuo 54aa8bca4cSXuan Zhuo /* The driver will always attempt to allocate IRQ blocks based on the maximum 55aa8bca4cSXuan Zhuo * possible queue num. 56aa8bca4cSXuan Zhuo */ 57aa8bca4cSXuan Zhuo static int eea_alloc_irq_blks(struct eea_net *enet) 58aa8bca4cSXuan Zhuo { 59aa8bca4cSXuan Zhuo struct eea_device *edev = enet->edev; 60aa8bca4cSXuan Zhuo struct eea_irq_blk *blk, *irq_blks; 61aa8bca4cSXuan Zhuo int i, err, num; 62aa8bca4cSXuan Zhuo 63aa8bca4cSXuan Zhuo num = enet->edev->rx_num; 64aa8bca4cSXuan Zhuo 65aa8bca4cSXuan Zhuo irq_blks = kvcalloc(num, sizeof(*blk), GFP_KERNEL); 66aa8bca4cSXuan Zhuo if (!irq_blks) 67aa8bca4cSXuan Zhuo return -ENOMEM; 68aa8bca4cSXuan Zhuo 69aa8bca4cSXuan Zhuo enet->irq_blks = irq_blks; 70aa8bca4cSXuan Zhuo 71aa8bca4cSXuan Zhuo for (i = 0; i < num; i++) { 72aa8bca4cSXuan Zhuo blk = &irq_blks[i]; 73aa8bca4cSXuan Zhuo blk->idx = i; 74aa8bca4cSXuan Zhuo 75aa8bca4cSXuan Zhuo /* vec 0 is for error notify. */ 76aa8bca4cSXuan Zhuo blk->msix_vec = i + 1; 77aa8bca4cSXuan Zhuo 78aa8bca4cSXuan Zhuo err = eea_pci_request_irq(edev, blk, eea_irq_handler); 79aa8bca4cSXuan Zhuo if (err) 80aa8bca4cSXuan Zhuo goto err_free_irq_blk; 81aa8bca4cSXuan Zhuo 82aa8bca4cSXuan Zhuo blk->ready = true; 83aa8bca4cSXuan Zhuo } 84aa8bca4cSXuan Zhuo 85aa8bca4cSXuan Zhuo return 0; 86aa8bca4cSXuan Zhuo 87aa8bca4cSXuan Zhuo err_free_irq_blk: 88aa8bca4cSXuan Zhuo eea_free_irq_blk(enet); 89aa8bca4cSXuan Zhuo return err; 90aa8bca4cSXuan Zhuo } 91aa8bca4cSXuan Zhuo 92aa8bca4cSXuan Zhuo static int eea_update_queues(struct eea_net *enet) 93aa8bca4cSXuan Zhuo { 94aa8bca4cSXuan Zhuo return netif_set_real_num_queues(enet->netdev, enet->cfg.tx_ring_num, 95aa8bca4cSXuan Zhuo enet->cfg.rx_ring_num); 96aa8bca4cSXuan Zhuo } 97aa8bca4cSXuan Zhuo 98aa8bca4cSXuan Zhuo void eea_init_ctx(struct eea_net *enet, struct eea_net_init_ctx *ctx) 99aa8bca4cSXuan Zhuo { 100aa8bca4cSXuan Zhuo memset(ctx, 0, sizeof(*ctx)); 101aa8bca4cSXuan Zhuo 102aa8bca4cSXuan Zhuo ctx->netdev = enet->netdev; 103aa8bca4cSXuan Zhuo ctx->edev = enet->edev; 104aa8bca4cSXuan Zhuo ctx->cfg = enet->cfg; 105aa8bca4cSXuan Zhuo } 106aa8bca4cSXuan Zhuo 107aa8bca4cSXuan Zhuo static void eea_bind_q_and_cfg(struct eea_net *enet, 108aa8bca4cSXuan Zhuo struct eea_net_init_ctx *ctx) 109aa8bca4cSXuan Zhuo { 110aa8bca4cSXuan Zhuo struct eea_irq_blk *blk; 111aa8bca4cSXuan Zhuo struct eea_net_rx *rx; 112aa8bca4cSXuan Zhuo struct eea_net_tx *tx; 113aa8bca4cSXuan Zhuo int i; 114aa8bca4cSXuan Zhuo 115*4e88fb32SXuan Zhuo /* Since 'ndo_get_stats64' is not called in softirq context, there is no 116*4e88fb32SXuan Zhuo * need to use 'spin_lock_bh'. 117*4e88fb32SXuan Zhuo */ 118*4e88fb32SXuan Zhuo spin_lock(&enet->stats_lock); 119*4e88fb32SXuan Zhuo 120aa8bca4cSXuan Zhuo enet->cfg = ctx->cfg; 121aa8bca4cSXuan Zhuo enet->rx = ctx->rx; 122aa8bca4cSXuan Zhuo enet->tx = ctx->tx; 123aa8bca4cSXuan Zhuo 124aa8bca4cSXuan Zhuo for (i = 0; i < ctx->cfg.rx_ring_num; i++) { 125aa8bca4cSXuan Zhuo blk = &enet->irq_blks[i]; 126aa8bca4cSXuan Zhuo 127aa8bca4cSXuan Zhuo rx = ctx->rx[i]; 128aa8bca4cSXuan Zhuo tx = &ctx->tx[i]; 129aa8bca4cSXuan Zhuo 130aa8bca4cSXuan Zhuo rx->enet = enet; 131aa8bca4cSXuan Zhuo rx->napi = &blk->napi; 132aa8bca4cSXuan Zhuo rx->ering->msix_vec = blk->msix_vec; 133aa8bca4cSXuan Zhuo 134aa8bca4cSXuan Zhuo tx->enet = enet; 135aa8bca4cSXuan Zhuo tx->ering->msix_vec = blk->msix_vec; 136aa8bca4cSXuan Zhuo 137aa8bca4cSXuan Zhuo blk->rx = rx; 138aa8bca4cSXuan Zhuo } 139*4e88fb32SXuan Zhuo 140*4e88fb32SXuan Zhuo spin_unlock(&enet->stats_lock); 141aa8bca4cSXuan Zhuo } 142aa8bca4cSXuan Zhuo 143aa8bca4cSXuan Zhuo static void eea_unbind_q_and_cfg(struct eea_net *enet, 144aa8bca4cSXuan Zhuo struct eea_net_init_ctx *ctx) 145aa8bca4cSXuan Zhuo { 146aa8bca4cSXuan Zhuo struct eea_irq_blk *blk; 147aa8bca4cSXuan Zhuo struct eea_net_rx *rx; 148aa8bca4cSXuan Zhuo int i; 149aa8bca4cSXuan Zhuo 150*4e88fb32SXuan Zhuo spin_lock(&enet->stats_lock); 151*4e88fb32SXuan Zhuo 152aa8bca4cSXuan Zhuo ctx->cfg = enet->cfg; 153aa8bca4cSXuan Zhuo ctx->rx = enet->rx; 154aa8bca4cSXuan Zhuo ctx->tx = enet->tx; 155aa8bca4cSXuan Zhuo 156aa8bca4cSXuan Zhuo enet->rx = NULL; 157aa8bca4cSXuan Zhuo enet->tx = NULL; 158aa8bca4cSXuan Zhuo 159aa8bca4cSXuan Zhuo for (i = 0; i < ctx->cfg.rx_ring_num; i++) { 160aa8bca4cSXuan Zhuo blk = &enet->irq_blks[i]; 161aa8bca4cSXuan Zhuo 162aa8bca4cSXuan Zhuo rx = ctx->rx[i]; 163aa8bca4cSXuan Zhuo 164aa8bca4cSXuan Zhuo rx->napi = NULL; 165aa8bca4cSXuan Zhuo 166aa8bca4cSXuan Zhuo blk->rx = NULL; 167aa8bca4cSXuan Zhuo } 168*4e88fb32SXuan Zhuo 169*4e88fb32SXuan Zhuo spin_unlock(&enet->stats_lock); 170aa8bca4cSXuan Zhuo } 171aa8bca4cSXuan Zhuo 172aa8bca4cSXuan Zhuo static void eea_free_rxtx_q_mem(struct eea_net_init_ctx *ctx) 173aa8bca4cSXuan Zhuo { 174aa8bca4cSXuan Zhuo struct eea_net_rx *rx; 175aa8bca4cSXuan Zhuo struct eea_net_tx *tx; 176aa8bca4cSXuan Zhuo int i; 177aa8bca4cSXuan Zhuo 178aa8bca4cSXuan Zhuo for (i = 0; i < ctx->cfg.rx_ring_num; i++) { 179aa8bca4cSXuan Zhuo rx = ctx->rx[i]; 180aa8bca4cSXuan Zhuo tx = &ctx->tx[i]; 181aa8bca4cSXuan Zhuo 182aa8bca4cSXuan Zhuo eea_free_rx(rx, &ctx->cfg); 183aa8bca4cSXuan Zhuo eea_free_tx(tx, &ctx->cfg); 184aa8bca4cSXuan Zhuo } 185aa8bca4cSXuan Zhuo 186aa8bca4cSXuan Zhuo kvfree(ctx->rx); 187aa8bca4cSXuan Zhuo kvfree(ctx->tx); 188aa8bca4cSXuan Zhuo } 189aa8bca4cSXuan Zhuo 190aa8bca4cSXuan Zhuo /* alloc tx/rx: struct, ring, meta, pp, napi */ 191aa8bca4cSXuan Zhuo static int eea_alloc_rxtx_q_mem(struct eea_net_init_ctx *ctx) 192aa8bca4cSXuan Zhuo { 193aa8bca4cSXuan Zhuo struct eea_net_rx *rx; 194aa8bca4cSXuan Zhuo struct eea_net_tx *tx; 195aa8bca4cSXuan Zhuo int err, i; 196aa8bca4cSXuan Zhuo 197aa8bca4cSXuan Zhuo ctx->tx = kvcalloc(ctx->cfg.tx_ring_num, sizeof(*ctx->tx), GFP_KERNEL); 198aa8bca4cSXuan Zhuo if (!ctx->tx) 199aa8bca4cSXuan Zhuo return -ENOMEM; 200aa8bca4cSXuan Zhuo 201aa8bca4cSXuan Zhuo ctx->rx = kvcalloc(ctx->cfg.rx_ring_num, sizeof(*ctx->rx), GFP_KERNEL); 202aa8bca4cSXuan Zhuo if (!ctx->rx) 203aa8bca4cSXuan Zhuo goto err_free_tx; 204aa8bca4cSXuan Zhuo 205aa8bca4cSXuan Zhuo ctx->cfg.rx_sq_desc_size = sizeof(struct eea_rx_desc); 206aa8bca4cSXuan Zhuo ctx->cfg.rx_cq_desc_size = sizeof(struct eea_rx_cdesc); 207aa8bca4cSXuan Zhuo ctx->cfg.tx_sq_desc_size = sizeof(struct eea_tx_desc); 208aa8bca4cSXuan Zhuo ctx->cfg.tx_cq_desc_size = sizeof(struct eea_tx_cdesc); 209aa8bca4cSXuan Zhuo 210aa8bca4cSXuan Zhuo /* ethtool may config this. */ 211aa8bca4cSXuan Zhuo if (!ctx->cfg.split_hdr) 212aa8bca4cSXuan Zhuo ctx->cfg.rx_sq_desc_size = sizeof(struct eea_rx_desc_no_hdr); 213aa8bca4cSXuan Zhuo 214aa8bca4cSXuan Zhuo for (i = 0; i < ctx->cfg.rx_ring_num; i++) { 215aa8bca4cSXuan Zhuo rx = eea_alloc_rx(ctx, i); 216aa8bca4cSXuan Zhuo if (!rx) 217aa8bca4cSXuan Zhuo goto err_free; 218aa8bca4cSXuan Zhuo 219aa8bca4cSXuan Zhuo ctx->rx[i] = rx; 220aa8bca4cSXuan Zhuo 221aa8bca4cSXuan Zhuo tx = ctx->tx + i; 222aa8bca4cSXuan Zhuo err = eea_alloc_tx(ctx, tx, i); 223aa8bca4cSXuan Zhuo if (err) 224aa8bca4cSXuan Zhuo goto err_free; 225aa8bca4cSXuan Zhuo } 226aa8bca4cSXuan Zhuo 227aa8bca4cSXuan Zhuo return 0; 228aa8bca4cSXuan Zhuo 229aa8bca4cSXuan Zhuo err_free: 230aa8bca4cSXuan Zhuo for (i = 0; i < ctx->cfg.rx_ring_num; i++) { 231aa8bca4cSXuan Zhuo rx = ctx->rx[i]; 232aa8bca4cSXuan Zhuo tx = ctx->tx + i; 233aa8bca4cSXuan Zhuo 234aa8bca4cSXuan Zhuo eea_free_rx(rx, &ctx->cfg); 235aa8bca4cSXuan Zhuo eea_free_tx(tx, &ctx->cfg); 236aa8bca4cSXuan Zhuo } 237aa8bca4cSXuan Zhuo 238aa8bca4cSXuan Zhuo kvfree(ctx->rx); 239aa8bca4cSXuan Zhuo 240aa8bca4cSXuan Zhuo err_free_tx: 241aa8bca4cSXuan Zhuo kvfree(ctx->tx); 242aa8bca4cSXuan Zhuo return -ENOMEM; 243aa8bca4cSXuan Zhuo } 244aa8bca4cSXuan Zhuo 245aa8bca4cSXuan Zhuo static int eea_hw_active_ring(struct eea_net *enet) 246aa8bca4cSXuan Zhuo { 247aa8bca4cSXuan Zhuo return eea_adminq_create_q(enet, enet->cfg.rx_ring_num 248aa8bca4cSXuan Zhuo + enet->cfg.tx_ring_num, 0); 249aa8bca4cSXuan Zhuo } 250aa8bca4cSXuan Zhuo 251aa8bca4cSXuan Zhuo static int eea_hw_unactive_ring(struct eea_net *enet) 252aa8bca4cSXuan Zhuo { 253aa8bca4cSXuan Zhuo int err; 254aa8bca4cSXuan Zhuo 255aa8bca4cSXuan Zhuo err = eea_adminq_destroy_all_q(enet); 256aa8bca4cSXuan Zhuo if (err) 257aa8bca4cSXuan Zhuo netdev_warn(enet->netdev, "unactive rxtx ring failed.\n"); 258aa8bca4cSXuan Zhuo 259aa8bca4cSXuan Zhuo return err; 260aa8bca4cSXuan Zhuo } 261aa8bca4cSXuan Zhuo 262aa8bca4cSXuan Zhuo /* stop rx napi, stop tx queue. */ 263aa8bca4cSXuan Zhuo static void eea_stop_rxtx(struct net_device *netdev) 264aa8bca4cSXuan Zhuo { 265aa8bca4cSXuan Zhuo struct eea_net *enet = netdev_priv(netdev); 266aa8bca4cSXuan Zhuo int i; 267aa8bca4cSXuan Zhuo 268aa8bca4cSXuan Zhuo netif_tx_disable(netdev); 269aa8bca4cSXuan Zhuo 270aa8bca4cSXuan Zhuo for (i = 0; i < enet->cfg.rx_ring_num; i++) 271aa8bca4cSXuan Zhuo enet_rx_stop(enet->rx[i]); 272aa8bca4cSXuan Zhuo 273aa8bca4cSXuan Zhuo netif_carrier_off(netdev); 274aa8bca4cSXuan Zhuo } 275aa8bca4cSXuan Zhuo 276aa8bca4cSXuan Zhuo static void eea_start_rxtx(struct eea_net *enet) 277aa8bca4cSXuan Zhuo { 278aa8bca4cSXuan Zhuo int i; 279aa8bca4cSXuan Zhuo 280aa8bca4cSXuan Zhuo for (i = 0; i < enet->cfg.rx_ring_num; i++) 281aa8bca4cSXuan Zhuo enet_rx_start(enet->rx[i]); 282aa8bca4cSXuan Zhuo 283aa8bca4cSXuan Zhuo netif_tx_start_all_queues(enet->netdev); 284aa8bca4cSXuan Zhuo netif_carrier_on(enet->netdev); 285aa8bca4cSXuan Zhuo 286aa8bca4cSXuan Zhuo enet->started = true; 287aa8bca4cSXuan Zhuo } 288aa8bca4cSXuan Zhuo 289aa8bca4cSXuan Zhuo static int eea_netdev_stop(struct net_device *netdev) 290aa8bca4cSXuan Zhuo { 291aa8bca4cSXuan Zhuo struct eea_net *enet = netdev_priv(netdev); 292aa8bca4cSXuan Zhuo struct eea_net_init_ctx ctx; 293aa8bca4cSXuan Zhuo 294aa8bca4cSXuan Zhuo /* This function can be called during device anomaly recovery. To 295aa8bca4cSXuan Zhuo * prevent duplicate stop operations, the `started` flag is introduced 296aa8bca4cSXuan Zhuo * for checking. 297aa8bca4cSXuan Zhuo */ 298aa8bca4cSXuan Zhuo 299aa8bca4cSXuan Zhuo if (!enet->started) { 300aa8bca4cSXuan Zhuo netdev_warn(netdev, "eea netdev stop: but dev is not started.\n"); 301aa8bca4cSXuan Zhuo return 0; 302aa8bca4cSXuan Zhuo } 303aa8bca4cSXuan Zhuo 304aa8bca4cSXuan Zhuo eea_init_ctx(enet, &ctx); 305aa8bca4cSXuan Zhuo 306aa8bca4cSXuan Zhuo eea_stop_rxtx(netdev); 307aa8bca4cSXuan Zhuo eea_hw_unactive_ring(enet); 308aa8bca4cSXuan Zhuo eea_unbind_q_and_cfg(enet, &ctx); 309aa8bca4cSXuan Zhuo eea_free_rxtx_q_mem(&ctx); 310aa8bca4cSXuan Zhuo 311aa8bca4cSXuan Zhuo enet->started = false; 312aa8bca4cSXuan Zhuo 313aa8bca4cSXuan Zhuo return 0; 314aa8bca4cSXuan Zhuo } 315aa8bca4cSXuan Zhuo 316aa8bca4cSXuan Zhuo static int eea_netdev_open(struct net_device *netdev) 317aa8bca4cSXuan Zhuo { 318aa8bca4cSXuan Zhuo struct eea_net *enet = netdev_priv(netdev); 319aa8bca4cSXuan Zhuo struct eea_net_init_ctx ctx; 320aa8bca4cSXuan Zhuo int err; 321aa8bca4cSXuan Zhuo 322aa8bca4cSXuan Zhuo if (enet->link_err) { 323aa8bca4cSXuan Zhuo netdev_err(netdev, "netdev open err, because link error: %d\n", 324aa8bca4cSXuan Zhuo enet->link_err); 325aa8bca4cSXuan Zhuo return -EBUSY; 326aa8bca4cSXuan Zhuo } 327aa8bca4cSXuan Zhuo 328aa8bca4cSXuan Zhuo eea_init_ctx(enet, &ctx); 329aa8bca4cSXuan Zhuo 330aa8bca4cSXuan Zhuo err = eea_alloc_rxtx_q_mem(&ctx); 331aa8bca4cSXuan Zhuo if (err) 332aa8bca4cSXuan Zhuo goto err_done; 333aa8bca4cSXuan Zhuo 334aa8bca4cSXuan Zhuo eea_bind_q_and_cfg(enet, &ctx); 335aa8bca4cSXuan Zhuo 336aa8bca4cSXuan Zhuo err = eea_update_queues(enet); 337aa8bca4cSXuan Zhuo if (err) 338aa8bca4cSXuan Zhuo goto err_free_q; 339aa8bca4cSXuan Zhuo 340aa8bca4cSXuan Zhuo err = eea_hw_active_ring(enet); 341aa8bca4cSXuan Zhuo if (err) 342aa8bca4cSXuan Zhuo goto err_free_q; 343aa8bca4cSXuan Zhuo 344aa8bca4cSXuan Zhuo eea_start_rxtx(enet); 345aa8bca4cSXuan Zhuo 346aa8bca4cSXuan Zhuo return 0; 347aa8bca4cSXuan Zhuo 348aa8bca4cSXuan Zhuo err_free_q: 349aa8bca4cSXuan Zhuo eea_unbind_q_and_cfg(enet, &ctx); 350aa8bca4cSXuan Zhuo eea_free_rxtx_q_mem(&ctx); 351aa8bca4cSXuan Zhuo 352aa8bca4cSXuan Zhuo err_done: 353aa8bca4cSXuan Zhuo return err; 354aa8bca4cSXuan Zhuo } 355aa8bca4cSXuan Zhuo 356*4e88fb32SXuan Zhuo /* Statistics may be reset to zero upon device reset. This is expected behavior 357*4e88fb32SXuan Zhuo * for now and will be addressed in the future. 358*4e88fb32SXuan Zhuo */ 359*4e88fb32SXuan Zhuo static void eea_stats(struct net_device *netdev, struct rtnl_link_stats64 *tot) 360*4e88fb32SXuan Zhuo { 361*4e88fb32SXuan Zhuo struct eea_net *enet = netdev_priv(netdev); 362*4e88fb32SXuan Zhuo u64 packets, bytes, drop, lerr; 363*4e88fb32SXuan Zhuo u32 start; 364*4e88fb32SXuan Zhuo int i; 365*4e88fb32SXuan Zhuo 366*4e88fb32SXuan Zhuo spin_lock(&enet->stats_lock); 367*4e88fb32SXuan Zhuo 368*4e88fb32SXuan Zhuo if (enet->rx) { 369*4e88fb32SXuan Zhuo for (i = 0; i < enet->cfg.rx_ring_num; i++) { 370*4e88fb32SXuan Zhuo struct eea_net_rx *rx = enet->rx[i]; 371*4e88fb32SXuan Zhuo 372*4e88fb32SXuan Zhuo do { 373*4e88fb32SXuan Zhuo start = u64_stats_fetch_begin(&rx->stats.syncp); 374*4e88fb32SXuan Zhuo packets = u64_stats_read(&rx->stats.packets); 375*4e88fb32SXuan Zhuo bytes = u64_stats_read(&rx->stats.bytes); 376*4e88fb32SXuan Zhuo drop = u64_stats_read(&rx->stats.drops); 377*4e88fb32SXuan Zhuo lerr = u64_stats_read(&rx->stats.length_errors); 378*4e88fb32SXuan Zhuo } while (u64_stats_fetch_retry(&rx->stats.syncp, 379*4e88fb32SXuan Zhuo start)); 380*4e88fb32SXuan Zhuo 381*4e88fb32SXuan Zhuo tot->rx_packets += packets; 382*4e88fb32SXuan Zhuo tot->rx_bytes += bytes; 383*4e88fb32SXuan Zhuo tot->rx_dropped += drop; 384*4e88fb32SXuan Zhuo tot->rx_length_errors += lerr; 385*4e88fb32SXuan Zhuo tot->rx_errors += lerr; 386*4e88fb32SXuan Zhuo } 387*4e88fb32SXuan Zhuo } 388*4e88fb32SXuan Zhuo 389*4e88fb32SXuan Zhuo if (enet->tx) { 390*4e88fb32SXuan Zhuo for (i = 0; i < enet->cfg.tx_ring_num; i++) { 391*4e88fb32SXuan Zhuo struct eea_net_tx *tx = &enet->tx[i]; 392*4e88fb32SXuan Zhuo 393*4e88fb32SXuan Zhuo do { 394*4e88fb32SXuan Zhuo start = u64_stats_fetch_begin(&tx->stats.syncp); 395*4e88fb32SXuan Zhuo packets = u64_stats_read(&tx->stats.packets); 396*4e88fb32SXuan Zhuo bytes = u64_stats_read(&tx->stats.bytes); 397*4e88fb32SXuan Zhuo drop = u64_stats_read(&tx->stats.drops); 398*4e88fb32SXuan Zhuo } while (u64_stats_fetch_retry(&tx->stats.syncp, 399*4e88fb32SXuan Zhuo start)); 400*4e88fb32SXuan Zhuo 401*4e88fb32SXuan Zhuo tot->tx_packets += packets; 402*4e88fb32SXuan Zhuo tot->tx_bytes += bytes; 403*4e88fb32SXuan Zhuo tot->tx_dropped += drop; 404*4e88fb32SXuan Zhuo } 405*4e88fb32SXuan Zhuo } 406*4e88fb32SXuan Zhuo 407*4e88fb32SXuan Zhuo spin_unlock(&enet->stats_lock); 408*4e88fb32SXuan Zhuo } 409*4e88fb32SXuan Zhuo 410aa8bca4cSXuan Zhuo /* resources: ring, buffers, irq */ 411aa8bca4cSXuan Zhuo int eea_reset_hw_resources(struct eea_net *enet, struct eea_net_init_ctx *ctx) 412aa8bca4cSXuan Zhuo { 413aa8bca4cSXuan Zhuo struct eea_net_init_ctx ctx_old = {0}; 414aa8bca4cSXuan Zhuo int err, error; 415aa8bca4cSXuan Zhuo 416aa8bca4cSXuan Zhuo if (!netif_running(enet->netdev) || !enet->started) { 417*4e88fb32SXuan Zhuo spin_lock(&enet->stats_lock); 418aa8bca4cSXuan Zhuo enet->cfg = ctx->cfg; 419*4e88fb32SXuan Zhuo spin_unlock(&enet->stats_lock); 420aa8bca4cSXuan Zhuo return 0; 421aa8bca4cSXuan Zhuo } 422aa8bca4cSXuan Zhuo 423aa8bca4cSXuan Zhuo err = eea_alloc_rxtx_q_mem(ctx); 424aa8bca4cSXuan Zhuo if (err) { 425aa8bca4cSXuan Zhuo netdev_warn(enet->netdev, 426aa8bca4cSXuan Zhuo "eea reset: alloc q failed. stop reset. err %d\n", 427aa8bca4cSXuan Zhuo err); 428aa8bca4cSXuan Zhuo return err; 429aa8bca4cSXuan Zhuo } 430aa8bca4cSXuan Zhuo 431aa8bca4cSXuan Zhuo eea_stop_rxtx(enet->netdev); 432aa8bca4cSXuan Zhuo eea_hw_unactive_ring(enet); 433aa8bca4cSXuan Zhuo 434aa8bca4cSXuan Zhuo eea_unbind_q_and_cfg(enet, &ctx_old); 435aa8bca4cSXuan Zhuo eea_bind_q_and_cfg(enet, ctx); 436aa8bca4cSXuan Zhuo 437aa8bca4cSXuan Zhuo err = eea_update_queues(enet); 438aa8bca4cSXuan Zhuo if (err) { 439aa8bca4cSXuan Zhuo netdev_err(enet->netdev, 440aa8bca4cSXuan Zhuo "eea reset: set real num queues failed. err %d\n", 441aa8bca4cSXuan Zhuo err); 442aa8bca4cSXuan Zhuo goto err_bind_old; 443aa8bca4cSXuan Zhuo } 444aa8bca4cSXuan Zhuo 445aa8bca4cSXuan Zhuo err = eea_hw_active_ring(enet); 446aa8bca4cSXuan Zhuo if (err) { 447aa8bca4cSXuan Zhuo netdev_err(enet->netdev, "eea reset: active new ring. err %d\n", 448aa8bca4cSXuan Zhuo err); 449aa8bca4cSXuan Zhuo eea_unbind_q_and_cfg(enet, ctx); 450aa8bca4cSXuan Zhuo goto err_free_q; 451aa8bca4cSXuan Zhuo } 452aa8bca4cSXuan Zhuo 453aa8bca4cSXuan Zhuo eea_start_rxtx(enet); 454aa8bca4cSXuan Zhuo eea_free_rxtx_q_mem(&ctx_old); 455aa8bca4cSXuan Zhuo return 0; 456aa8bca4cSXuan Zhuo 457aa8bca4cSXuan Zhuo err_bind_old: 458aa8bca4cSXuan Zhuo eea_unbind_q_and_cfg(enet, ctx); 459aa8bca4cSXuan Zhuo eea_bind_q_and_cfg(enet, &ctx_old); 460aa8bca4cSXuan Zhuo error = eea_hw_active_ring(enet); 461aa8bca4cSXuan Zhuo if (error) { 462aa8bca4cSXuan Zhuo netdev_err(enet->netdev, "eea reset: active old ring. err %d\n", 463aa8bca4cSXuan Zhuo error); 464aa8bca4cSXuan Zhuo eea_unbind_q_and_cfg(enet, &ctx_old); 465aa8bca4cSXuan Zhuo err = error; 466aa8bca4cSXuan Zhuo goto err_free_q; 467aa8bca4cSXuan Zhuo } 468aa8bca4cSXuan Zhuo 469aa8bca4cSXuan Zhuo eea_start_rxtx(enet); 470aa8bca4cSXuan Zhuo eea_free_rxtx_q_mem(ctx); 471aa8bca4cSXuan Zhuo return err; 472aa8bca4cSXuan Zhuo 473aa8bca4cSXuan Zhuo err_free_q: 474aa8bca4cSXuan Zhuo 475aa8bca4cSXuan Zhuo /* An exception occurred at the hardware level, and there's not much we 476aa8bca4cSXuan Zhuo * can do about it -- we can only release the resources first. 477aa8bca4cSXuan Zhuo */ 478aa8bca4cSXuan Zhuo eea_free_rxtx_q_mem(ctx); 479aa8bca4cSXuan Zhuo eea_free_rxtx_q_mem(&ctx_old); 480aa8bca4cSXuan Zhuo enet->started = false; 481aa8bca4cSXuan Zhuo return err; 482aa8bca4cSXuan Zhuo } 483aa8bca4cSXuan Zhuo 484aa8bca4cSXuan Zhuo int eea_queues_check_and_reset(struct eea_device *edev) 485aa8bca4cSXuan Zhuo { 486aa8bca4cSXuan Zhuo struct eea_aq_dev_status dstatus = {0}; 487aa8bca4cSXuan Zhuo struct eea_aq_queue_status *qstatus; 488aa8bca4cSXuan Zhuo struct eea_aq_queue_status *qs; 489aa8bca4cSXuan Zhuo struct eea_net_init_ctx ctx; 490aa8bca4cSXuan Zhuo bool need_reset = false; 491aa8bca4cSXuan Zhuo int i, err = 0; 492aa8bca4cSXuan Zhuo 493aa8bca4cSXuan Zhuo rtnl_lock(); 494aa8bca4cSXuan Zhuo 495aa8bca4cSXuan Zhuo if (!netif_running(edev->enet->netdev)) 496aa8bca4cSXuan Zhuo goto err_unlock; 497aa8bca4cSXuan Zhuo 498aa8bca4cSXuan Zhuo /* Maybe stopped by ha. */ 499aa8bca4cSXuan Zhuo if (!edev->enet->started || edev->enet->link_err) 500aa8bca4cSXuan Zhuo goto err_unlock; 501aa8bca4cSXuan Zhuo 502aa8bca4cSXuan Zhuo err = eea_adminq_dev_status(edev->enet, &dstatus); 503aa8bca4cSXuan Zhuo if (err) { 504aa8bca4cSXuan Zhuo netdev_warn(edev->enet->netdev, "query queue status failed.\n"); 505aa8bca4cSXuan Zhuo goto err_unlock; 506aa8bca4cSXuan Zhuo } 507aa8bca4cSXuan Zhuo 508aa8bca4cSXuan Zhuo if (le16_to_cpu(dstatus.status->link_status) == EEA_LINK_DOWN_STATUS) { 509aa8bca4cSXuan Zhuo /* The device is broken, can not be up. */ 510aa8bca4cSXuan Zhuo eea_netdev_stop(edev->enet->netdev); 511aa8bca4cSXuan Zhuo edev->enet->link_err = EEA_LINK_ERR_LINK_DOWN; 512aa8bca4cSXuan Zhuo netdev_warn(edev->enet->netdev, "device link is down. stop device.\n"); 513aa8bca4cSXuan Zhuo goto err_free; 514aa8bca4cSXuan Zhuo } 515aa8bca4cSXuan Zhuo 516aa8bca4cSXuan Zhuo qstatus = dstatus.status->q_status; 517aa8bca4cSXuan Zhuo 518aa8bca4cSXuan Zhuo for (i = 0; i < dstatus.num; ++i) { 519aa8bca4cSXuan Zhuo qs = &qstatus[i]; 520aa8bca4cSXuan Zhuo 521aa8bca4cSXuan Zhuo if (le16_to_cpu(qs->status) == EEA_QUEUE_STATUS_NEED_RESET) { 522aa8bca4cSXuan Zhuo netdev_warn(edev->enet->netdev, 523aa8bca4cSXuan Zhuo "queue status: queue %u needs to reset\n", 524aa8bca4cSXuan Zhuo le16_to_cpu(qs->qidx)); 525aa8bca4cSXuan Zhuo need_reset = true; 526aa8bca4cSXuan Zhuo } 527aa8bca4cSXuan Zhuo } 528aa8bca4cSXuan Zhuo 529aa8bca4cSXuan Zhuo if (need_reset) { 530aa8bca4cSXuan Zhuo eea_init_ctx(edev->enet, &ctx); 531aa8bca4cSXuan Zhuo err = eea_reset_hw_resources(edev->enet, &ctx); 532aa8bca4cSXuan Zhuo } 533aa8bca4cSXuan Zhuo 534aa8bca4cSXuan Zhuo err_free: 535aa8bca4cSXuan Zhuo kfree(dstatus.status); 536aa8bca4cSXuan Zhuo 537aa8bca4cSXuan Zhuo err_unlock: 538aa8bca4cSXuan Zhuo rtnl_unlock(); 539aa8bca4cSXuan Zhuo return err; 540aa8bca4cSXuan Zhuo } 541aa8bca4cSXuan Zhuo 5424c45a51eSXuan Zhuo static int eea_update_cfg(struct eea_net *enet, 5434c45a51eSXuan Zhuo struct eea_device *edev, 5444c45a51eSXuan Zhuo struct eea_aq_cfg *hwcfg) 5454c45a51eSXuan Zhuo { 5464c45a51eSXuan Zhuo u32 rx_max = le32_to_cpu(hwcfg->rx_depth_max); 5474c45a51eSXuan Zhuo u32 tx_max = le32_to_cpu(hwcfg->tx_depth_max); 5484c45a51eSXuan Zhuo u32 rx_def = le32_to_cpu(hwcfg->rx_depth_def); 5494c45a51eSXuan Zhuo u32 tx_def = le32_to_cpu(hwcfg->tx_depth_def); 5504c45a51eSXuan Zhuo 5514c45a51eSXuan Zhuo /* Now, we assert that the rx ring num is equal to the tx ring num. */ 5524c45a51eSXuan Zhuo if (edev->rx_num != edev->tx_num) { 5534c45a51eSXuan Zhuo dev_err(edev->dma_dev, "Inconsistent ring num: RX %u, TX %u\n", 5544c45a51eSXuan Zhuo edev->rx_num, edev->tx_num); 5554c45a51eSXuan Zhuo return -EINVAL; 5564c45a51eSXuan Zhuo } 5574c45a51eSXuan Zhuo 5584c45a51eSXuan Zhuo if (rx_max > EEA_NET_IO_HW_RING_DEPTH_MAX || 5594c45a51eSXuan Zhuo rx_max < EEA_NET_IO_HW_RING_DEPTH_MIN || 5604c45a51eSXuan Zhuo tx_max > EEA_NET_IO_HW_RING_DEPTH_MAX || 5614c45a51eSXuan Zhuo tx_max < EEA_NET_IO_HW_RING_DEPTH_MIN) { 5624c45a51eSXuan Zhuo dev_err(edev->dma_dev, "Invalid HW max depth: RX %u, TX %u\n", 5634c45a51eSXuan Zhuo rx_max, tx_max); 5644c45a51eSXuan Zhuo return -EINVAL; 5654c45a51eSXuan Zhuo } 5664c45a51eSXuan Zhuo 5674c45a51eSXuan Zhuo if (rx_def > rx_max || 5684c45a51eSXuan Zhuo tx_def > tx_max || 5694c45a51eSXuan Zhuo rx_def < EEA_NET_IO_HW_RING_DEPTH_MIN || 5704c45a51eSXuan Zhuo tx_def < EEA_NET_IO_HW_RING_DEPTH_MIN) { 5714c45a51eSXuan Zhuo dev_err(edev->dma_dev, "Invalid default depth: RX %u (max %u), TX %u (max %u)\n", 5724c45a51eSXuan Zhuo rx_def, rx_max, tx_def, tx_max); 5734c45a51eSXuan Zhuo return -EINVAL; 5744c45a51eSXuan Zhuo } 5754c45a51eSXuan Zhuo 5764c45a51eSXuan Zhuo if (!is_power_of_2(rx_max) || !is_power_of_2(tx_max) || 5774c45a51eSXuan Zhuo !is_power_of_2(rx_def) || !is_power_of_2(tx_def)) { 5784c45a51eSXuan Zhuo dev_err(edev->dma_dev, "Ring depth must be power of 2\n"); 5794c45a51eSXuan Zhuo return -EINVAL; 5804c45a51eSXuan Zhuo } 5814c45a51eSXuan Zhuo 5824c45a51eSXuan Zhuo enet->cfg_hw.rx_ring_depth = rx_max; 5834c45a51eSXuan Zhuo enet->cfg_hw.tx_ring_depth = tx_max; 5844c45a51eSXuan Zhuo enet->cfg_hw.rx_ring_num = edev->rx_num; 5854c45a51eSXuan Zhuo enet->cfg_hw.tx_ring_num = edev->tx_num; 5864c45a51eSXuan Zhuo enet->cfg_hw.split_hdr = EEA_SPLIT_HDR_SIZE; 5874c45a51eSXuan Zhuo 5884c45a51eSXuan Zhuo enet->cfg.rx_ring_depth = rx_def; 5894c45a51eSXuan Zhuo enet->cfg.tx_ring_depth = tx_def; 5904c45a51eSXuan Zhuo enet->cfg.rx_ring_num = edev->rx_num; 5914c45a51eSXuan Zhuo enet->cfg.tx_ring_num = edev->tx_num; 5924c45a51eSXuan Zhuo 5934c45a51eSXuan Zhuo return 0; 5944c45a51eSXuan Zhuo } 5954c45a51eSXuan Zhuo 5964c45a51eSXuan Zhuo static int eea_netdev_init_features(struct net_device *netdev, 5974c45a51eSXuan Zhuo struct eea_net *enet, 5984c45a51eSXuan Zhuo struct eea_device *edev) 5994c45a51eSXuan Zhuo { 6004c45a51eSXuan Zhuo struct eea_aq_cfg *cfg; 6014c45a51eSXuan Zhuo int err; 6024c45a51eSXuan Zhuo u32 mtu; 6034c45a51eSXuan Zhuo 6044c45a51eSXuan Zhuo cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); 6054c45a51eSXuan Zhuo if (!cfg) 6064c45a51eSXuan Zhuo return -ENOMEM; 6074c45a51eSXuan Zhuo 6084c45a51eSXuan Zhuo err = eea_adminq_query_cfg(enet, cfg); 6094c45a51eSXuan Zhuo if (err) 6104c45a51eSXuan Zhuo goto err_free; 6114c45a51eSXuan Zhuo 6124c45a51eSXuan Zhuo mtu = le16_to_cpu(cfg->mtu); 6134c45a51eSXuan Zhuo if (mtu < ETH_MIN_MTU) { 6144c45a51eSXuan Zhuo dev_err(edev->dma_dev, "The device gave us an invalid MTU. Here we can only exit the initialization. %u < %u\n", 6154c45a51eSXuan Zhuo mtu, ETH_MIN_MTU); 6164c45a51eSXuan Zhuo err = -EINVAL; 6174c45a51eSXuan Zhuo goto err_free; 6184c45a51eSXuan Zhuo } 6194c45a51eSXuan Zhuo 6204c45a51eSXuan Zhuo err = eea_update_cfg(enet, edev, cfg); 6214c45a51eSXuan Zhuo if (err) 6224c45a51eSXuan Zhuo goto err_free; 6234c45a51eSXuan Zhuo 6244c45a51eSXuan Zhuo netdev->priv_flags |= IFF_UNICAST_FLT; 6254c45a51eSXuan Zhuo netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE; 6264c45a51eSXuan Zhuo 6274c45a51eSXuan Zhuo netdev->hw_features |= NETIF_F_HW_CSUM; 6284c45a51eSXuan Zhuo netdev->hw_features |= NETIF_F_GRO_HW; 6294c45a51eSXuan Zhuo netdev->hw_features |= NETIF_F_SG; 6304c45a51eSXuan Zhuo netdev->hw_features |= NETIF_F_TSO; 6314c45a51eSXuan Zhuo netdev->hw_features |= NETIF_F_TSO_ECN; 6324c45a51eSXuan Zhuo netdev->hw_features |= NETIF_F_TSO6; 6334c45a51eSXuan Zhuo netdev->hw_features |= NETIF_F_GSO_UDP_L4; 6344c45a51eSXuan Zhuo 6354c45a51eSXuan Zhuo netdev->features |= NETIF_F_HIGHDMA; 6364c45a51eSXuan Zhuo netdev->features |= NETIF_F_HW_CSUM; 6374c45a51eSXuan Zhuo netdev->features |= NETIF_F_SG; 6384c45a51eSXuan Zhuo netdev->features |= NETIF_F_GSO_ROBUST; 6394c45a51eSXuan Zhuo netdev->features |= netdev->hw_features & NETIF_F_ALL_TSO; 6404c45a51eSXuan Zhuo netdev->features |= NETIF_F_RXCSUM; 6414c45a51eSXuan Zhuo netdev->features |= NETIF_F_GRO_HW; 6424c45a51eSXuan Zhuo 6434c45a51eSXuan Zhuo netdev->vlan_features = netdev->features; 6444c45a51eSXuan Zhuo 6454c45a51eSXuan Zhuo if (!is_valid_ether_addr(cfg->mac)) { 6464c45a51eSXuan Zhuo dev_err(edev->dma_dev, "The device gave invalid mac %pM\n", 6474c45a51eSXuan Zhuo cfg->mac); 6484c45a51eSXuan Zhuo err = -EINVAL; 6494c45a51eSXuan Zhuo goto err_free; 6504c45a51eSXuan Zhuo } 6514c45a51eSXuan Zhuo 6524c45a51eSXuan Zhuo eth_hw_addr_set(netdev, cfg->mac); 6534c45a51eSXuan Zhuo 6544c45a51eSXuan Zhuo enet->speed = SPEED_UNKNOWN; 6554c45a51eSXuan Zhuo enet->duplex = DUPLEX_UNKNOWN; 6564c45a51eSXuan Zhuo 6574c45a51eSXuan Zhuo netdev->min_mtu = ETH_MIN_MTU; 6584c45a51eSXuan Zhuo 6594c45a51eSXuan Zhuo netdev->mtu = mtu; 6604c45a51eSXuan Zhuo 6614c45a51eSXuan Zhuo /* If jumbo frames are already enabled, then the returned MTU will be a 6624c45a51eSXuan Zhuo * jumbo MTU, and the driver will automatically enable jumbo frame 6634c45a51eSXuan Zhuo * support by default. 6644c45a51eSXuan Zhuo */ 6654c45a51eSXuan Zhuo netdev->max_mtu = mtu; 6664c45a51eSXuan Zhuo 6674c45a51eSXuan Zhuo err_free: 6684c45a51eSXuan Zhuo kfree(cfg); 6694c45a51eSXuan Zhuo return err; 6704c45a51eSXuan Zhuo } 6714c45a51eSXuan Zhuo 6724c45a51eSXuan Zhuo static const struct net_device_ops eea_netdev = { 673aa8bca4cSXuan Zhuo .ndo_open = eea_netdev_open, 674aa8bca4cSXuan Zhuo .ndo_stop = eea_netdev_stop, 675aa8bca4cSXuan Zhuo .ndo_start_xmit = eea_tx_xmit, 6764c45a51eSXuan Zhuo .ndo_validate_addr = eth_validate_addr, 677*4e88fb32SXuan Zhuo .ndo_get_stats64 = eea_stats, 6784c45a51eSXuan Zhuo .ndo_features_check = passthru_features_check, 6794c45a51eSXuan Zhuo }; 6804c45a51eSXuan Zhuo 6814c45a51eSXuan Zhuo static struct eea_net *eea_netdev_alloc(struct eea_device *edev, u32 pairs) 6824c45a51eSXuan Zhuo { 6834c45a51eSXuan Zhuo struct net_device *netdev; 6844c45a51eSXuan Zhuo struct eea_net *enet; 685aa8bca4cSXuan Zhuo int err; 6864c45a51eSXuan Zhuo 6874c45a51eSXuan Zhuo netdev = alloc_etherdev_mq(sizeof(struct eea_net), pairs); 6884c45a51eSXuan Zhuo if (!netdev) { 6894c45a51eSXuan Zhuo dev_err(edev->dma_dev, 6904c45a51eSXuan Zhuo "alloc_etherdev_mq failed with pairs %d\n", pairs); 6914c45a51eSXuan Zhuo return NULL; 6924c45a51eSXuan Zhuo } 6934c45a51eSXuan Zhuo 6944c45a51eSXuan Zhuo netdev->netdev_ops = &eea_netdev; 6955f4f7bc0SXuan Zhuo netdev->ethtool_ops = &eea_ethtool_ops; 6964c45a51eSXuan Zhuo SET_NETDEV_DEV(netdev, edev->dma_dev); 6974c45a51eSXuan Zhuo 6984c45a51eSXuan Zhuo enet = netdev_priv(netdev); 6994c45a51eSXuan Zhuo enet->netdev = netdev; 7004c45a51eSXuan Zhuo enet->edev = edev; 7014c45a51eSXuan Zhuo edev->enet = enet; 7024c45a51eSXuan Zhuo 703aa8bca4cSXuan Zhuo err = eea_alloc_irq_blks(enet); 704aa8bca4cSXuan Zhuo if (err) { 705aa8bca4cSXuan Zhuo dev_err(edev->dma_dev, 706aa8bca4cSXuan Zhuo "eea_alloc_irq_blks failed with pairs %d\n", pairs); 707aa8bca4cSXuan Zhuo free_netdev(netdev); 708aa8bca4cSXuan Zhuo return NULL; 709aa8bca4cSXuan Zhuo } 710aa8bca4cSXuan Zhuo 711*4e88fb32SXuan Zhuo spin_lock_init(&enet->stats_lock); 712*4e88fb32SXuan Zhuo 7134c45a51eSXuan Zhuo return enet; 7144c45a51eSXuan Zhuo } 7154c45a51eSXuan Zhuo 716df9cad6bSXuan Zhuo static void eea_update_ts_off(struct eea_device *edev, struct eea_net *enet) 717df9cad6bSXuan Zhuo { 718df9cad6bSXuan Zhuo u64 ts; 719df9cad6bSXuan Zhuo 720df9cad6bSXuan Zhuo ts = eea_pci_device_ts(edev); 721df9cad6bSXuan Zhuo 722df9cad6bSXuan Zhuo enet->hw_ts_offset = ktime_get_real() - ts; 723df9cad6bSXuan Zhuo } 724df9cad6bSXuan Zhuo 725aa8bca4cSXuan Zhuo static int eea_net_reprobe(struct eea_device *edev) 726aa8bca4cSXuan Zhuo { 727aa8bca4cSXuan Zhuo struct eea_net *enet = edev->enet; 728aa8bca4cSXuan Zhuo int err = 0; 729aa8bca4cSXuan Zhuo 730aa8bca4cSXuan Zhuo enet->edev = edev; 731aa8bca4cSXuan Zhuo 732aa8bca4cSXuan Zhuo if (!enet->adminq.ring) { 733aa8bca4cSXuan Zhuo err = eea_create_adminq(enet, edev->rx_num + edev->tx_num); 734aa8bca4cSXuan Zhuo if (err) 735aa8bca4cSXuan Zhuo return err; 736aa8bca4cSXuan Zhuo } 737aa8bca4cSXuan Zhuo 738aa8bca4cSXuan Zhuo err = eea_alloc_irq_blks(enet); 739aa8bca4cSXuan Zhuo if (err) 740aa8bca4cSXuan Zhuo goto err_destroy_aq; 741aa8bca4cSXuan Zhuo 742df9cad6bSXuan Zhuo eea_update_ts_off(edev, enet); 743df9cad6bSXuan Zhuo 744aa8bca4cSXuan Zhuo rtnl_lock(); 745aa8bca4cSXuan Zhuo 746aa8bca4cSXuan Zhuo enet->link_err = 0; 747aa8bca4cSXuan Zhuo if (edev->ha_reset_netdev_running && 748aa8bca4cSXuan Zhuo netif_running(edev->enet->netdev)) { 749aa8bca4cSXuan Zhuo err = eea_netdev_open(enet->netdev); 750aa8bca4cSXuan Zhuo if (err) { 751aa8bca4cSXuan Zhuo enet->link_err = EEA_LINK_ERR_HA_RESET_DEV; 752aa8bca4cSXuan Zhuo rtnl_unlock(); 753aa8bca4cSXuan Zhuo goto err_free_irq_blks; 754aa8bca4cSXuan Zhuo } 755aa8bca4cSXuan Zhuo } 756aa8bca4cSXuan Zhuo 757aa8bca4cSXuan Zhuo rtnl_unlock(); 758aa8bca4cSXuan Zhuo 759aa8bca4cSXuan Zhuo enet->wait_pci_ready = false; 760aa8bca4cSXuan Zhuo return 0; 761aa8bca4cSXuan Zhuo 762aa8bca4cSXuan Zhuo err_free_irq_blks: 763aa8bca4cSXuan Zhuo eea_free_irq_blk(enet); 764aa8bca4cSXuan Zhuo 765aa8bca4cSXuan Zhuo err_destroy_aq: 766aa8bca4cSXuan Zhuo eea_destroy_adminq(enet); 767aa8bca4cSXuan Zhuo 768aa8bca4cSXuan Zhuo return err; 769aa8bca4cSXuan Zhuo } 770aa8bca4cSXuan Zhuo 7714c45a51eSXuan Zhuo int eea_net_probe(struct eea_device *edev) 7724c45a51eSXuan Zhuo { 7734c45a51eSXuan Zhuo struct eea_net *enet; 7744c45a51eSXuan Zhuo int err = -ENOMEM; 7754c45a51eSXuan Zhuo 776aa8bca4cSXuan Zhuo /* If edev->enet is not null, then this is called from ha reset worker. 777aa8bca4cSXuan Zhuo * Call eea_net_reprobe() directly. 778aa8bca4cSXuan Zhuo */ 779aa8bca4cSXuan Zhuo if (edev->enet) 780aa8bca4cSXuan Zhuo return eea_net_reprobe(edev); 781aa8bca4cSXuan Zhuo 7824c45a51eSXuan Zhuo enet = eea_netdev_alloc(edev, edev->rx_num); 7834c45a51eSXuan Zhuo if (!enet) 7844c45a51eSXuan Zhuo return -ENOMEM; 7854c45a51eSXuan Zhuo 7864c45a51eSXuan Zhuo err = eea_create_adminq(enet, edev->rx_num + edev->tx_num); 7874c45a51eSXuan Zhuo if (err) 7884c45a51eSXuan Zhuo goto err_free_netdev; 7894c45a51eSXuan Zhuo 7904c45a51eSXuan Zhuo eea_adminq_config_host_info(enet); 7914c45a51eSXuan Zhuo 7924c45a51eSXuan Zhuo err = eea_netdev_init_features(enet->netdev, enet, edev); 7934c45a51eSXuan Zhuo if (err) 7944c45a51eSXuan Zhuo goto err_reset_dev; 7954c45a51eSXuan Zhuo 796df9cad6bSXuan Zhuo eea_update_ts_off(edev, enet); 797df9cad6bSXuan Zhuo 798*4e88fb32SXuan Zhuo netif_carrier_off(enet->netdev); 7994c45a51eSXuan Zhuo 800*4e88fb32SXuan Zhuo err = register_netdev(enet->netdev); 801*4e88fb32SXuan Zhuo if (err) 802*4e88fb32SXuan Zhuo goto err_reset_dev; 803*4e88fb32SXuan Zhuo 804*4e88fb32SXuan Zhuo netdev_dbg(enet->netdev, "eea probe success.\n"); 8054c45a51eSXuan Zhuo 8064c45a51eSXuan Zhuo return 0; 8074c45a51eSXuan Zhuo 8084c45a51eSXuan Zhuo err_reset_dev: 8094c45a51eSXuan Zhuo eea_device_reset(edev); 8104c45a51eSXuan Zhuo eea_destroy_adminq(enet); 8114c45a51eSXuan Zhuo 8124c45a51eSXuan Zhuo err_free_netdev: 813aa8bca4cSXuan Zhuo eea_free_irq_blk(enet); 8144c45a51eSXuan Zhuo free_netdev(enet->netdev); 8154c45a51eSXuan Zhuo return err; 8164c45a51eSXuan Zhuo } 8174c45a51eSXuan Zhuo 818aa8bca4cSXuan Zhuo static void eea_net_ha_reset_remove(struct eea_net *enet, 819aa8bca4cSXuan Zhuo struct eea_device *edev) 820aa8bca4cSXuan Zhuo { 821aa8bca4cSXuan Zhuo rtnl_lock(); 822aa8bca4cSXuan Zhuo edev->ha_reset_netdev_running = false; 823aa8bca4cSXuan Zhuo if (netif_running(enet->netdev)) { 824aa8bca4cSXuan Zhuo eea_netdev_stop(enet->netdev); 825aa8bca4cSXuan Zhuo edev->ha_reset_netdev_running = true; 826aa8bca4cSXuan Zhuo } 827aa8bca4cSXuan Zhuo 828aa8bca4cSXuan Zhuo /* Prevent that the user set up the net device. */ 829aa8bca4cSXuan Zhuo enet->link_err = EEA_LINK_ERR_HA_RESET_DEV; 830aa8bca4cSXuan Zhuo 831aa8bca4cSXuan Zhuo rtnl_unlock(); 832aa8bca4cSXuan Zhuo 833aa8bca4cSXuan Zhuo eea_device_reset(edev); 834aa8bca4cSXuan Zhuo eea_destroy_adminq(enet); 835aa8bca4cSXuan Zhuo eea_free_irq_blk(enet); 836aa8bca4cSXuan Zhuo 837aa8bca4cSXuan Zhuo enet->wait_pci_ready = true; 838aa8bca4cSXuan Zhuo } 839aa8bca4cSXuan Zhuo 840aa8bca4cSXuan Zhuo void eea_net_remove(struct eea_device *edev, bool ha) 8414c45a51eSXuan Zhuo { 8424c45a51eSXuan Zhuo struct net_device *netdev; 8434c45a51eSXuan Zhuo struct eea_net *enet; 8444c45a51eSXuan Zhuo 8454c45a51eSXuan Zhuo enet = edev->enet; 8464c45a51eSXuan Zhuo netdev = enet->netdev; 8474c45a51eSXuan Zhuo 848aa8bca4cSXuan Zhuo if (ha) { 849aa8bca4cSXuan Zhuo if (enet->wait_pci_ready) 850aa8bca4cSXuan Zhuo return; 8514c45a51eSXuan Zhuo 852aa8bca4cSXuan Zhuo eea_net_ha_reset_remove(enet, edev); 853aa8bca4cSXuan Zhuo return; 854aa8bca4cSXuan Zhuo } 855aa8bca4cSXuan Zhuo 856*4e88fb32SXuan Zhuo unregister_netdev(netdev); 857*4e88fb32SXuan Zhuo 858aa8bca4cSXuan Zhuo if (!enet->wait_pci_ready) { 8594c45a51eSXuan Zhuo eea_device_reset(edev); 8604c45a51eSXuan Zhuo eea_destroy_adminq(enet); 861aa8bca4cSXuan Zhuo eea_free_irq_blk(enet); 862aa8bca4cSXuan Zhuo } 8634c45a51eSXuan Zhuo 8644c45a51eSXuan Zhuo free_netdev(netdev); 8654c45a51eSXuan Zhuo } 8664c45a51eSXuan Zhuo 8674c45a51eSXuan Zhuo void eea_net_shutdown(struct eea_device *edev) 8684c45a51eSXuan Zhuo { 8694c45a51eSXuan Zhuo struct net_device *netdev; 8704c45a51eSXuan Zhuo struct eea_net *enet; 8714c45a51eSXuan Zhuo 8724c45a51eSXuan Zhuo enet = edev->enet; 8734c45a51eSXuan Zhuo netdev = enet->netdev; 8744c45a51eSXuan Zhuo 8754c45a51eSXuan Zhuo rtnl_lock(); 8764c45a51eSXuan Zhuo 8774c45a51eSXuan Zhuo netif_device_detach(netdev); 878*4e88fb32SXuan Zhuo dev_close(netdev); 8794c45a51eSXuan Zhuo 880aa8bca4cSXuan Zhuo if (!enet->wait_pci_ready) { 8814c45a51eSXuan Zhuo eea_device_reset(edev); 8824c45a51eSXuan Zhuo eea_destroy_adminq(enet); 883aa8bca4cSXuan Zhuo eea_free_irq_blk(enet); 884aa8bca4cSXuan Zhuo } 8854c45a51eSXuan Zhuo 8864c45a51eSXuan Zhuo rtnl_unlock(); 8874c45a51eSXuan Zhuo } 888