162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 2013 - 2019 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include "fm10k.h" 562306a36Sopenharmony_ci#include <linux/vmalloc.h> 662306a36Sopenharmony_ci#include <net/udp_tunnel.h> 762306a36Sopenharmony_ci#include <linux/if_macvlan.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci/** 1062306a36Sopenharmony_ci * fm10k_setup_tx_resources - allocate Tx resources (Descriptors) 1162306a36Sopenharmony_ci * @tx_ring: tx descriptor ring (for a specific queue) to setup 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Return 0 on success, negative on failure 1462306a36Sopenharmony_ci **/ 1562306a36Sopenharmony_ciint fm10k_setup_tx_resources(struct fm10k_ring *tx_ring) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci struct device *dev = tx_ring->dev; 1862306a36Sopenharmony_ci int size; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci size = sizeof(struct fm10k_tx_buffer) * tx_ring->count; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci tx_ring->tx_buffer = vzalloc(size); 2362306a36Sopenharmony_ci if (!tx_ring->tx_buffer) 2462306a36Sopenharmony_ci goto err; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci u64_stats_init(&tx_ring->syncp); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci /* round up to nearest 4K */ 2962306a36Sopenharmony_ci tx_ring->size = tx_ring->count * sizeof(struct fm10k_tx_desc); 3062306a36Sopenharmony_ci tx_ring->size = ALIGN(tx_ring->size, 4096); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci tx_ring->desc = dma_alloc_coherent(dev, tx_ring->size, 3362306a36Sopenharmony_ci &tx_ring->dma, GFP_KERNEL); 3462306a36Sopenharmony_ci if (!tx_ring->desc) 3562306a36Sopenharmony_ci goto err; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci return 0; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cierr: 4062306a36Sopenharmony_ci vfree(tx_ring->tx_buffer); 4162306a36Sopenharmony_ci tx_ring->tx_buffer = NULL; 4262306a36Sopenharmony_ci return -ENOMEM; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/** 4662306a36Sopenharmony_ci * fm10k_setup_all_tx_resources - allocate all queues Tx resources 4762306a36Sopenharmony_ci * @interface: board private structure 4862306a36Sopenharmony_ci * 4962306a36Sopenharmony_ci * If this function returns with an error, then it's possible one or 5062306a36Sopenharmony_ci * more of the rings is populated (while the rest are not). It is the 5162306a36Sopenharmony_ci * callers duty to clean those orphaned rings. 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * Return 0 on success, negative on failure 5462306a36Sopenharmony_ci **/ 5562306a36Sopenharmony_cistatic int fm10k_setup_all_tx_resources(struct fm10k_intfc *interface) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci int i, err; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci for (i = 0; i < interface->num_tx_queues; i++) { 6062306a36Sopenharmony_ci err = fm10k_setup_tx_resources(interface->tx_ring[i]); 6162306a36Sopenharmony_ci if (!err) 6262306a36Sopenharmony_ci continue; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci netif_err(interface, probe, interface->netdev, 6562306a36Sopenharmony_ci "Allocation for Tx Queue %u failed\n", i); 6662306a36Sopenharmony_ci goto err_setup_tx; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci return 0; 7062306a36Sopenharmony_cierr_setup_tx: 7162306a36Sopenharmony_ci /* rewind the index freeing the rings as we go */ 7262306a36Sopenharmony_ci while (i--) 7362306a36Sopenharmony_ci fm10k_free_tx_resources(interface->tx_ring[i]); 7462306a36Sopenharmony_ci return err; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/** 7862306a36Sopenharmony_ci * fm10k_setup_rx_resources - allocate Rx resources (Descriptors) 7962306a36Sopenharmony_ci * @rx_ring: rx descriptor ring (for a specific queue) to setup 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * Returns 0 on success, negative on failure 8262306a36Sopenharmony_ci **/ 8362306a36Sopenharmony_ciint fm10k_setup_rx_resources(struct fm10k_ring *rx_ring) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct device *dev = rx_ring->dev; 8662306a36Sopenharmony_ci int size; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci size = sizeof(struct fm10k_rx_buffer) * rx_ring->count; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci rx_ring->rx_buffer = vzalloc(size); 9162306a36Sopenharmony_ci if (!rx_ring->rx_buffer) 9262306a36Sopenharmony_ci goto err; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci u64_stats_init(&rx_ring->syncp); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci /* Round up to nearest 4K */ 9762306a36Sopenharmony_ci rx_ring->size = rx_ring->count * sizeof(union fm10k_rx_desc); 9862306a36Sopenharmony_ci rx_ring->size = ALIGN(rx_ring->size, 4096); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci rx_ring->desc = dma_alloc_coherent(dev, rx_ring->size, 10162306a36Sopenharmony_ci &rx_ring->dma, GFP_KERNEL); 10262306a36Sopenharmony_ci if (!rx_ring->desc) 10362306a36Sopenharmony_ci goto err; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci return 0; 10662306a36Sopenharmony_cierr: 10762306a36Sopenharmony_ci vfree(rx_ring->rx_buffer); 10862306a36Sopenharmony_ci rx_ring->rx_buffer = NULL; 10962306a36Sopenharmony_ci return -ENOMEM; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/** 11362306a36Sopenharmony_ci * fm10k_setup_all_rx_resources - allocate all queues Rx resources 11462306a36Sopenharmony_ci * @interface: board private structure 11562306a36Sopenharmony_ci * 11662306a36Sopenharmony_ci * If this function returns with an error, then it's possible one or 11762306a36Sopenharmony_ci * more of the rings is populated (while the rest are not). It is the 11862306a36Sopenharmony_ci * callers duty to clean those orphaned rings. 11962306a36Sopenharmony_ci * 12062306a36Sopenharmony_ci * Return 0 on success, negative on failure 12162306a36Sopenharmony_ci **/ 12262306a36Sopenharmony_cistatic int fm10k_setup_all_rx_resources(struct fm10k_intfc *interface) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci int i, err; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci for (i = 0; i < interface->num_rx_queues; i++) { 12762306a36Sopenharmony_ci err = fm10k_setup_rx_resources(interface->rx_ring[i]); 12862306a36Sopenharmony_ci if (!err) 12962306a36Sopenharmony_ci continue; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci netif_err(interface, probe, interface->netdev, 13262306a36Sopenharmony_ci "Allocation for Rx Queue %u failed\n", i); 13362306a36Sopenharmony_ci goto err_setup_rx; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci return 0; 13762306a36Sopenharmony_cierr_setup_rx: 13862306a36Sopenharmony_ci /* rewind the index freeing the rings as we go */ 13962306a36Sopenharmony_ci while (i--) 14062306a36Sopenharmony_ci fm10k_free_rx_resources(interface->rx_ring[i]); 14162306a36Sopenharmony_ci return err; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_civoid fm10k_unmap_and_free_tx_resource(struct fm10k_ring *ring, 14562306a36Sopenharmony_ci struct fm10k_tx_buffer *tx_buffer) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci if (tx_buffer->skb) { 14862306a36Sopenharmony_ci dev_kfree_skb_any(tx_buffer->skb); 14962306a36Sopenharmony_ci if (dma_unmap_len(tx_buffer, len)) 15062306a36Sopenharmony_ci dma_unmap_single(ring->dev, 15162306a36Sopenharmony_ci dma_unmap_addr(tx_buffer, dma), 15262306a36Sopenharmony_ci dma_unmap_len(tx_buffer, len), 15362306a36Sopenharmony_ci DMA_TO_DEVICE); 15462306a36Sopenharmony_ci } else if (dma_unmap_len(tx_buffer, len)) { 15562306a36Sopenharmony_ci dma_unmap_page(ring->dev, 15662306a36Sopenharmony_ci dma_unmap_addr(tx_buffer, dma), 15762306a36Sopenharmony_ci dma_unmap_len(tx_buffer, len), 15862306a36Sopenharmony_ci DMA_TO_DEVICE); 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci tx_buffer->next_to_watch = NULL; 16162306a36Sopenharmony_ci tx_buffer->skb = NULL; 16262306a36Sopenharmony_ci dma_unmap_len_set(tx_buffer, len, 0); 16362306a36Sopenharmony_ci /* tx_buffer must be completely set up in the transmit path */ 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci/** 16762306a36Sopenharmony_ci * fm10k_clean_tx_ring - Free Tx Buffers 16862306a36Sopenharmony_ci * @tx_ring: ring to be cleaned 16962306a36Sopenharmony_ci **/ 17062306a36Sopenharmony_cistatic void fm10k_clean_tx_ring(struct fm10k_ring *tx_ring) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci unsigned long size; 17362306a36Sopenharmony_ci u16 i; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* ring already cleared, nothing to do */ 17662306a36Sopenharmony_ci if (!tx_ring->tx_buffer) 17762306a36Sopenharmony_ci return; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* Free all the Tx ring sk_buffs */ 18062306a36Sopenharmony_ci for (i = 0; i < tx_ring->count; i++) { 18162306a36Sopenharmony_ci struct fm10k_tx_buffer *tx_buffer = &tx_ring->tx_buffer[i]; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci fm10k_unmap_and_free_tx_resource(tx_ring, tx_buffer); 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci /* reset BQL values */ 18762306a36Sopenharmony_ci netdev_tx_reset_queue(txring_txq(tx_ring)); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci size = sizeof(struct fm10k_tx_buffer) * tx_ring->count; 19062306a36Sopenharmony_ci memset(tx_ring->tx_buffer, 0, size); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* Zero out the descriptor ring */ 19362306a36Sopenharmony_ci memset(tx_ring->desc, 0, tx_ring->size); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/** 19762306a36Sopenharmony_ci * fm10k_free_tx_resources - Free Tx Resources per Queue 19862306a36Sopenharmony_ci * @tx_ring: Tx descriptor ring for a specific queue 19962306a36Sopenharmony_ci * 20062306a36Sopenharmony_ci * Free all transmit software resources 20162306a36Sopenharmony_ci **/ 20262306a36Sopenharmony_civoid fm10k_free_tx_resources(struct fm10k_ring *tx_ring) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci fm10k_clean_tx_ring(tx_ring); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci vfree(tx_ring->tx_buffer); 20762306a36Sopenharmony_ci tx_ring->tx_buffer = NULL; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* if not set, then don't free */ 21062306a36Sopenharmony_ci if (!tx_ring->desc) 21162306a36Sopenharmony_ci return; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci dma_free_coherent(tx_ring->dev, tx_ring->size, 21462306a36Sopenharmony_ci tx_ring->desc, tx_ring->dma); 21562306a36Sopenharmony_ci tx_ring->desc = NULL; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/** 21962306a36Sopenharmony_ci * fm10k_clean_all_tx_rings - Free Tx Buffers for all queues 22062306a36Sopenharmony_ci * @interface: board private structure 22162306a36Sopenharmony_ci **/ 22262306a36Sopenharmony_civoid fm10k_clean_all_tx_rings(struct fm10k_intfc *interface) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci int i; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci for (i = 0; i < interface->num_tx_queues; i++) 22762306a36Sopenharmony_ci fm10k_clean_tx_ring(interface->tx_ring[i]); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci/** 23162306a36Sopenharmony_ci * fm10k_free_all_tx_resources - Free Tx Resources for All Queues 23262306a36Sopenharmony_ci * @interface: board private structure 23362306a36Sopenharmony_ci * 23462306a36Sopenharmony_ci * Free all transmit software resources 23562306a36Sopenharmony_ci **/ 23662306a36Sopenharmony_cistatic void fm10k_free_all_tx_resources(struct fm10k_intfc *interface) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci int i = interface->num_tx_queues; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci while (i--) 24162306a36Sopenharmony_ci fm10k_free_tx_resources(interface->tx_ring[i]); 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci/** 24562306a36Sopenharmony_ci * fm10k_clean_rx_ring - Free Rx Buffers per Queue 24662306a36Sopenharmony_ci * @rx_ring: ring to free buffers from 24762306a36Sopenharmony_ci **/ 24862306a36Sopenharmony_cistatic void fm10k_clean_rx_ring(struct fm10k_ring *rx_ring) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci unsigned long size; 25162306a36Sopenharmony_ci u16 i; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (!rx_ring->rx_buffer) 25462306a36Sopenharmony_ci return; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci dev_kfree_skb(rx_ring->skb); 25762306a36Sopenharmony_ci rx_ring->skb = NULL; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* Free all the Rx ring sk_buffs */ 26062306a36Sopenharmony_ci for (i = 0; i < rx_ring->count; i++) { 26162306a36Sopenharmony_ci struct fm10k_rx_buffer *buffer = &rx_ring->rx_buffer[i]; 26262306a36Sopenharmony_ci /* clean-up will only set page pointer to NULL */ 26362306a36Sopenharmony_ci if (!buffer->page) 26462306a36Sopenharmony_ci continue; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci dma_unmap_page(rx_ring->dev, buffer->dma, 26762306a36Sopenharmony_ci PAGE_SIZE, DMA_FROM_DEVICE); 26862306a36Sopenharmony_ci __free_page(buffer->page); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci buffer->page = NULL; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci size = sizeof(struct fm10k_rx_buffer) * rx_ring->count; 27462306a36Sopenharmony_ci memset(rx_ring->rx_buffer, 0, size); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* Zero out the descriptor ring */ 27762306a36Sopenharmony_ci memset(rx_ring->desc, 0, rx_ring->size); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci rx_ring->next_to_alloc = 0; 28062306a36Sopenharmony_ci rx_ring->next_to_clean = 0; 28162306a36Sopenharmony_ci rx_ring->next_to_use = 0; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/** 28562306a36Sopenharmony_ci * fm10k_free_rx_resources - Free Rx Resources 28662306a36Sopenharmony_ci * @rx_ring: ring to clean the resources from 28762306a36Sopenharmony_ci * 28862306a36Sopenharmony_ci * Free all receive software resources 28962306a36Sopenharmony_ci **/ 29062306a36Sopenharmony_civoid fm10k_free_rx_resources(struct fm10k_ring *rx_ring) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci fm10k_clean_rx_ring(rx_ring); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci vfree(rx_ring->rx_buffer); 29562306a36Sopenharmony_ci rx_ring->rx_buffer = NULL; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci /* if not set, then don't free */ 29862306a36Sopenharmony_ci if (!rx_ring->desc) 29962306a36Sopenharmony_ci return; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci dma_free_coherent(rx_ring->dev, rx_ring->size, 30262306a36Sopenharmony_ci rx_ring->desc, rx_ring->dma); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci rx_ring->desc = NULL; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci/** 30862306a36Sopenharmony_ci * fm10k_clean_all_rx_rings - Free Rx Buffers for all queues 30962306a36Sopenharmony_ci * @interface: board private structure 31062306a36Sopenharmony_ci **/ 31162306a36Sopenharmony_civoid fm10k_clean_all_rx_rings(struct fm10k_intfc *interface) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci int i; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci for (i = 0; i < interface->num_rx_queues; i++) 31662306a36Sopenharmony_ci fm10k_clean_rx_ring(interface->rx_ring[i]); 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci/** 32062306a36Sopenharmony_ci * fm10k_free_all_rx_resources - Free Rx Resources for All Queues 32162306a36Sopenharmony_ci * @interface: board private structure 32262306a36Sopenharmony_ci * 32362306a36Sopenharmony_ci * Free all receive software resources 32462306a36Sopenharmony_ci **/ 32562306a36Sopenharmony_cistatic void fm10k_free_all_rx_resources(struct fm10k_intfc *interface) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci int i = interface->num_rx_queues; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci while (i--) 33062306a36Sopenharmony_ci fm10k_free_rx_resources(interface->rx_ring[i]); 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci/** 33462306a36Sopenharmony_ci * fm10k_request_glort_range - Request GLORTs for use in configuring rules 33562306a36Sopenharmony_ci * @interface: board private structure 33662306a36Sopenharmony_ci * 33762306a36Sopenharmony_ci * This function allocates a range of glorts for this interface to use. 33862306a36Sopenharmony_ci **/ 33962306a36Sopenharmony_cistatic void fm10k_request_glort_range(struct fm10k_intfc *interface) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 34262306a36Sopenharmony_ci u16 mask = (~hw->mac.dglort_map) >> FM10K_DGLORTMAP_MASK_SHIFT; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* establish GLORT base */ 34562306a36Sopenharmony_ci interface->glort = hw->mac.dglort_map & FM10K_DGLORTMAP_NONE; 34662306a36Sopenharmony_ci interface->glort_count = 0; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* nothing we can do until mask is allocated */ 34962306a36Sopenharmony_ci if (hw->mac.dglort_map == FM10K_DGLORTMAP_NONE) 35062306a36Sopenharmony_ci return; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* we support 3 possible GLORT configurations. 35362306a36Sopenharmony_ci * 1: VFs consume all but the last 1 35462306a36Sopenharmony_ci * 2: VFs and PF split glorts with possible gap between 35562306a36Sopenharmony_ci * 3: VFs allocated first 64, all others belong to PF 35662306a36Sopenharmony_ci */ 35762306a36Sopenharmony_ci if (mask <= hw->iov.total_vfs) { 35862306a36Sopenharmony_ci interface->glort_count = 1; 35962306a36Sopenharmony_ci interface->glort += mask; 36062306a36Sopenharmony_ci } else if (mask < 64) { 36162306a36Sopenharmony_ci interface->glort_count = (mask + 1) / 2; 36262306a36Sopenharmony_ci interface->glort += interface->glort_count; 36362306a36Sopenharmony_ci } else { 36462306a36Sopenharmony_ci interface->glort_count = mask - 63; 36562306a36Sopenharmony_ci interface->glort += 64; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci/** 37062306a36Sopenharmony_ci * fm10k_restore_udp_port_info 37162306a36Sopenharmony_ci * @interface: board private structure 37262306a36Sopenharmony_ci * 37362306a36Sopenharmony_ci * This function restores the value in the tunnel_cfg register(s) after reset 37462306a36Sopenharmony_ci **/ 37562306a36Sopenharmony_cistatic void fm10k_restore_udp_port_info(struct fm10k_intfc *interface) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* only the PF supports configuring tunnels */ 38062306a36Sopenharmony_ci if (hw->mac.type != fm10k_mac_pf) 38162306a36Sopenharmony_ci return; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* restore tunnel configuration register */ 38462306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TUNNEL_CFG, 38562306a36Sopenharmony_ci ntohs(interface->vxlan_port) | 38662306a36Sopenharmony_ci (ETH_P_TEB << FM10K_TUNNEL_CFG_NVGRE_SHIFT)); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci /* restore Geneve tunnel configuration register */ 38962306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TUNNEL_CFG_GENEVE, 39062306a36Sopenharmony_ci ntohs(interface->geneve_port)); 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci/** 39462306a36Sopenharmony_ci * fm10k_udp_tunnel_sync - Called when UDP tunnel ports change 39562306a36Sopenharmony_ci * @dev: network interface device structure 39662306a36Sopenharmony_ci * @table: Tunnel table (according to tables of @fm10k_udp_tunnels) 39762306a36Sopenharmony_ci * 39862306a36Sopenharmony_ci * This function is called when a new UDP tunnel port is added or deleted. 39962306a36Sopenharmony_ci * Due to hardware restrictions, only one port per type can be offloaded at 40062306a36Sopenharmony_ci * once. Core will send to the driver a port of its choice. 40162306a36Sopenharmony_ci **/ 40262306a36Sopenharmony_cistatic int fm10k_udp_tunnel_sync(struct net_device *dev, unsigned int table) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 40562306a36Sopenharmony_ci struct udp_tunnel_info ti; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci udp_tunnel_nic_get_port(dev, table, 0, &ti); 40862306a36Sopenharmony_ci if (!table) 40962306a36Sopenharmony_ci interface->vxlan_port = ti.port; 41062306a36Sopenharmony_ci else 41162306a36Sopenharmony_ci interface->geneve_port = ti.port; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci fm10k_restore_udp_port_info(interface); 41462306a36Sopenharmony_ci return 0; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic const struct udp_tunnel_nic_info fm10k_udp_tunnels = { 41862306a36Sopenharmony_ci .sync_table = fm10k_udp_tunnel_sync, 41962306a36Sopenharmony_ci .tables = { 42062306a36Sopenharmony_ci { .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_VXLAN, }, 42162306a36Sopenharmony_ci { .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_GENEVE, }, 42262306a36Sopenharmony_ci }, 42362306a36Sopenharmony_ci}; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci/** 42662306a36Sopenharmony_ci * fm10k_open - Called when a network interface is made active 42762306a36Sopenharmony_ci * @netdev: network interface device structure 42862306a36Sopenharmony_ci * 42962306a36Sopenharmony_ci * Returns 0 on success, negative value on failure 43062306a36Sopenharmony_ci * 43162306a36Sopenharmony_ci * The open entry point is called when a network interface is made 43262306a36Sopenharmony_ci * active by the system (IFF_UP). At this point all resources needed 43362306a36Sopenharmony_ci * for transmit and receive operations are allocated, the interrupt 43462306a36Sopenharmony_ci * handler is registered with the OS, the watchdog timer is started, 43562306a36Sopenharmony_ci * and the stack is notified that the interface is ready. 43662306a36Sopenharmony_ci **/ 43762306a36Sopenharmony_ciint fm10k_open(struct net_device *netdev) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 44062306a36Sopenharmony_ci int err; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci /* allocate transmit descriptors */ 44362306a36Sopenharmony_ci err = fm10k_setup_all_tx_resources(interface); 44462306a36Sopenharmony_ci if (err) 44562306a36Sopenharmony_ci goto err_setup_tx; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci /* allocate receive descriptors */ 44862306a36Sopenharmony_ci err = fm10k_setup_all_rx_resources(interface); 44962306a36Sopenharmony_ci if (err) 45062306a36Sopenharmony_ci goto err_setup_rx; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* allocate interrupt resources */ 45362306a36Sopenharmony_ci err = fm10k_qv_request_irq(interface); 45462306a36Sopenharmony_ci if (err) 45562306a36Sopenharmony_ci goto err_req_irq; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* setup GLORT assignment for this port */ 45862306a36Sopenharmony_ci fm10k_request_glort_range(interface); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* Notify the stack of the actual queue counts */ 46162306a36Sopenharmony_ci err = netif_set_real_num_tx_queues(netdev, 46262306a36Sopenharmony_ci interface->num_tx_queues); 46362306a36Sopenharmony_ci if (err) 46462306a36Sopenharmony_ci goto err_set_queues; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci err = netif_set_real_num_rx_queues(netdev, 46762306a36Sopenharmony_ci interface->num_rx_queues); 46862306a36Sopenharmony_ci if (err) 46962306a36Sopenharmony_ci goto err_set_queues; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci fm10k_up(interface); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci return 0; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cierr_set_queues: 47662306a36Sopenharmony_ci fm10k_qv_free_irq(interface); 47762306a36Sopenharmony_cierr_req_irq: 47862306a36Sopenharmony_ci fm10k_free_all_rx_resources(interface); 47962306a36Sopenharmony_cierr_setup_rx: 48062306a36Sopenharmony_ci fm10k_free_all_tx_resources(interface); 48162306a36Sopenharmony_cierr_setup_tx: 48262306a36Sopenharmony_ci return err; 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci/** 48662306a36Sopenharmony_ci * fm10k_close - Disables a network interface 48762306a36Sopenharmony_ci * @netdev: network interface device structure 48862306a36Sopenharmony_ci * 48962306a36Sopenharmony_ci * Returns 0, this is not allowed to fail 49062306a36Sopenharmony_ci * 49162306a36Sopenharmony_ci * The close entry point is called when an interface is de-activated 49262306a36Sopenharmony_ci * by the OS. The hardware is still under the drivers control, but 49362306a36Sopenharmony_ci * needs to be disabled. A global MAC reset is issued to stop the 49462306a36Sopenharmony_ci * hardware, and all transmit and receive resources are freed. 49562306a36Sopenharmony_ci **/ 49662306a36Sopenharmony_ciint fm10k_close(struct net_device *netdev) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci fm10k_down(interface); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci fm10k_qv_free_irq(interface); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci fm10k_free_all_tx_resources(interface); 50562306a36Sopenharmony_ci fm10k_free_all_rx_resources(interface); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci return 0; 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic netdev_tx_t fm10k_xmit_frame(struct sk_buff *skb, struct net_device *dev) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 51362306a36Sopenharmony_ci int num_tx_queues = READ_ONCE(interface->num_tx_queues); 51462306a36Sopenharmony_ci unsigned int r_idx = skb->queue_mapping; 51562306a36Sopenharmony_ci int err; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci if (!num_tx_queues) 51862306a36Sopenharmony_ci return NETDEV_TX_BUSY; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci if ((skb->protocol == htons(ETH_P_8021Q)) && 52162306a36Sopenharmony_ci !skb_vlan_tag_present(skb)) { 52262306a36Sopenharmony_ci /* FM10K only supports hardware tagging, any tags in frame 52362306a36Sopenharmony_ci * are considered 2nd level or "outer" tags 52462306a36Sopenharmony_ci */ 52562306a36Sopenharmony_ci struct vlan_hdr *vhdr; 52662306a36Sopenharmony_ci __be16 proto; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci /* make sure skb is not shared */ 52962306a36Sopenharmony_ci skb = skb_share_check(skb, GFP_ATOMIC); 53062306a36Sopenharmony_ci if (!skb) 53162306a36Sopenharmony_ci return NETDEV_TX_OK; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci /* make sure there is enough room to move the ethernet header */ 53462306a36Sopenharmony_ci if (unlikely(!pskb_may_pull(skb, VLAN_ETH_HLEN))) 53562306a36Sopenharmony_ci return NETDEV_TX_OK; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci /* verify the skb head is not shared */ 53862306a36Sopenharmony_ci err = skb_cow_head(skb, 0); 53962306a36Sopenharmony_ci if (err) { 54062306a36Sopenharmony_ci dev_kfree_skb(skb); 54162306a36Sopenharmony_ci return NETDEV_TX_OK; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* locate VLAN header */ 54562306a36Sopenharmony_ci vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* pull the 2 key pieces of data out of it */ 54862306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, 54962306a36Sopenharmony_ci htons(ETH_P_8021Q), 55062306a36Sopenharmony_ci ntohs(vhdr->h_vlan_TCI)); 55162306a36Sopenharmony_ci proto = vhdr->h_vlan_encapsulated_proto; 55262306a36Sopenharmony_ci skb->protocol = (ntohs(proto) >= 1536) ? proto : 55362306a36Sopenharmony_ci htons(ETH_P_802_2); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* squash it by moving the ethernet addresses up 4 bytes */ 55662306a36Sopenharmony_ci memmove(skb->data + VLAN_HLEN, skb->data, 12); 55762306a36Sopenharmony_ci __skb_pull(skb, VLAN_HLEN); 55862306a36Sopenharmony_ci skb_reset_mac_header(skb); 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci /* The minimum packet size for a single buffer is 17B so pad the skb 56262306a36Sopenharmony_ci * in order to meet this minimum size requirement. 56362306a36Sopenharmony_ci */ 56462306a36Sopenharmony_ci if (unlikely(skb->len < 17)) { 56562306a36Sopenharmony_ci int pad_len = 17 - skb->len; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (skb_pad(skb, pad_len)) 56862306a36Sopenharmony_ci return NETDEV_TX_OK; 56962306a36Sopenharmony_ci __skb_put(skb, pad_len); 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci if (r_idx >= num_tx_queues) 57362306a36Sopenharmony_ci r_idx %= num_tx_queues; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci err = fm10k_xmit_frame_ring(skb, interface->tx_ring[r_idx]); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci return err; 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci/** 58162306a36Sopenharmony_ci * fm10k_tx_timeout - Respond to a Tx Hang 58262306a36Sopenharmony_ci * @netdev: network interface device structure 58362306a36Sopenharmony_ci * @txqueue: the index of the Tx queue that timed out 58462306a36Sopenharmony_ci **/ 58562306a36Sopenharmony_cistatic void fm10k_tx_timeout(struct net_device *netdev, unsigned int txqueue) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 58862306a36Sopenharmony_ci struct fm10k_ring *tx_ring; 58962306a36Sopenharmony_ci bool real_tx_hang = false; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (txqueue >= interface->num_tx_queues) { 59262306a36Sopenharmony_ci WARN(1, "invalid Tx queue index %d", txqueue); 59362306a36Sopenharmony_ci return; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci tx_ring = interface->tx_ring[txqueue]; 59762306a36Sopenharmony_ci if (check_for_tx_hang(tx_ring) && fm10k_check_tx_hang(tx_ring)) 59862306a36Sopenharmony_ci real_tx_hang = true; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci#define TX_TIMEO_LIMIT 16000 60162306a36Sopenharmony_ci if (real_tx_hang) { 60262306a36Sopenharmony_ci fm10k_tx_timeout_reset(interface); 60362306a36Sopenharmony_ci } else { 60462306a36Sopenharmony_ci netif_info(interface, drv, netdev, 60562306a36Sopenharmony_ci "Fake Tx hang detected with timeout of %d seconds\n", 60662306a36Sopenharmony_ci netdev->watchdog_timeo / HZ); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci /* fake Tx hang - increase the kernel timeout */ 60962306a36Sopenharmony_ci if (netdev->watchdog_timeo < TX_TIMEO_LIMIT) 61062306a36Sopenharmony_ci netdev->watchdog_timeo *= 2; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci/** 61562306a36Sopenharmony_ci * fm10k_host_mbx_ready - Check PF interface's mailbox readiness 61662306a36Sopenharmony_ci * @interface: board private structure 61762306a36Sopenharmony_ci * 61862306a36Sopenharmony_ci * This function checks if the PF interface's mailbox is ready before queueing 61962306a36Sopenharmony_ci * mailbox messages for transmission. This will prevent filling the TX mailbox 62062306a36Sopenharmony_ci * queue when the receiver is not ready. VF interfaces are exempt from this 62162306a36Sopenharmony_ci * check since it will block all PF-VF mailbox messages from being sent from 62262306a36Sopenharmony_ci * the VF to the PF at initialization. 62362306a36Sopenharmony_ci **/ 62462306a36Sopenharmony_cistatic bool fm10k_host_mbx_ready(struct fm10k_intfc *interface) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci return (hw->mac.type == fm10k_mac_vf || interface->host_ready); 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci/** 63262306a36Sopenharmony_ci * fm10k_queue_vlan_request - Queue a VLAN update request 63362306a36Sopenharmony_ci * @interface: the fm10k interface structure 63462306a36Sopenharmony_ci * @vid: the VLAN vid 63562306a36Sopenharmony_ci * @vsi: VSI index number 63662306a36Sopenharmony_ci * @set: whether to set or clear 63762306a36Sopenharmony_ci * 63862306a36Sopenharmony_ci * This function queues up a VLAN update. For VFs, this must be sent to the 63962306a36Sopenharmony_ci * managing PF over the mailbox. For PFs, we'll use the same handling so that 64062306a36Sopenharmony_ci * it's similar to the VF. This avoids storming the PF<->VF mailbox with too 64162306a36Sopenharmony_ci * many VLAN updates during reset. 64262306a36Sopenharmony_ci */ 64362306a36Sopenharmony_ciint fm10k_queue_vlan_request(struct fm10k_intfc *interface, 64462306a36Sopenharmony_ci u32 vid, u8 vsi, bool set) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct fm10k_macvlan_request *request; 64762306a36Sopenharmony_ci unsigned long flags; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci /* This must be atomic since we may be called while the netdev 65062306a36Sopenharmony_ci * addr_list_lock is held 65162306a36Sopenharmony_ci */ 65262306a36Sopenharmony_ci request = kzalloc(sizeof(*request), GFP_ATOMIC); 65362306a36Sopenharmony_ci if (!request) 65462306a36Sopenharmony_ci return -ENOMEM; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci request->type = FM10K_VLAN_REQUEST; 65762306a36Sopenharmony_ci request->vlan.vid = vid; 65862306a36Sopenharmony_ci request->vlan.vsi = vsi; 65962306a36Sopenharmony_ci request->set = set; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci spin_lock_irqsave(&interface->macvlan_lock, flags); 66262306a36Sopenharmony_ci list_add_tail(&request->list, &interface->macvlan_requests); 66362306a36Sopenharmony_ci spin_unlock_irqrestore(&interface->macvlan_lock, flags); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci fm10k_macvlan_schedule(interface); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci return 0; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci/** 67162306a36Sopenharmony_ci * fm10k_queue_mac_request - Queue a MAC update request 67262306a36Sopenharmony_ci * @interface: the fm10k interface structure 67362306a36Sopenharmony_ci * @glort: the target glort for this update 67462306a36Sopenharmony_ci * @addr: the address to update 67562306a36Sopenharmony_ci * @vid: the vid to update 67662306a36Sopenharmony_ci * @set: whether to add or remove 67762306a36Sopenharmony_ci * 67862306a36Sopenharmony_ci * This function queues up a MAC request for sending to the switch manager. 67962306a36Sopenharmony_ci * A separate thread monitors the queue and sends updates to the switch 68062306a36Sopenharmony_ci * manager. Return 0 on success, and negative error code on failure. 68162306a36Sopenharmony_ci **/ 68262306a36Sopenharmony_ciint fm10k_queue_mac_request(struct fm10k_intfc *interface, u16 glort, 68362306a36Sopenharmony_ci const unsigned char *addr, u16 vid, bool set) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci struct fm10k_macvlan_request *request; 68662306a36Sopenharmony_ci unsigned long flags; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci /* This must be atomic since we may be called while the netdev 68962306a36Sopenharmony_ci * addr_list_lock is held 69062306a36Sopenharmony_ci */ 69162306a36Sopenharmony_ci request = kzalloc(sizeof(*request), GFP_ATOMIC); 69262306a36Sopenharmony_ci if (!request) 69362306a36Sopenharmony_ci return -ENOMEM; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci if (is_multicast_ether_addr(addr)) 69662306a36Sopenharmony_ci request->type = FM10K_MC_MAC_REQUEST; 69762306a36Sopenharmony_ci else 69862306a36Sopenharmony_ci request->type = FM10K_UC_MAC_REQUEST; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci ether_addr_copy(request->mac.addr, addr); 70162306a36Sopenharmony_ci request->mac.glort = glort; 70262306a36Sopenharmony_ci request->mac.vid = vid; 70362306a36Sopenharmony_ci request->set = set; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci spin_lock_irqsave(&interface->macvlan_lock, flags); 70662306a36Sopenharmony_ci list_add_tail(&request->list, &interface->macvlan_requests); 70762306a36Sopenharmony_ci spin_unlock_irqrestore(&interface->macvlan_lock, flags); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci fm10k_macvlan_schedule(interface); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci return 0; 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci/** 71562306a36Sopenharmony_ci * fm10k_clear_macvlan_queue - Cancel pending updates for a given glort 71662306a36Sopenharmony_ci * @interface: the fm10k interface structure 71762306a36Sopenharmony_ci * @glort: the target glort to clear 71862306a36Sopenharmony_ci * @vlans: true to clear VLAN messages, false to ignore them 71962306a36Sopenharmony_ci * 72062306a36Sopenharmony_ci * Cancel any outstanding MAC/VLAN requests for a given glort. This is 72162306a36Sopenharmony_ci * expected to be called when a logical port goes down. 72262306a36Sopenharmony_ci **/ 72362306a36Sopenharmony_civoid fm10k_clear_macvlan_queue(struct fm10k_intfc *interface, 72462306a36Sopenharmony_ci u16 glort, bool vlans) 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci struct fm10k_macvlan_request *r, *tmp; 72862306a36Sopenharmony_ci unsigned long flags; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci spin_lock_irqsave(&interface->macvlan_lock, flags); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* Free any outstanding MAC/VLAN requests for this interface */ 73362306a36Sopenharmony_ci list_for_each_entry_safe(r, tmp, &interface->macvlan_requests, list) { 73462306a36Sopenharmony_ci switch (r->type) { 73562306a36Sopenharmony_ci case FM10K_MC_MAC_REQUEST: 73662306a36Sopenharmony_ci case FM10K_UC_MAC_REQUEST: 73762306a36Sopenharmony_ci /* Don't free requests for other interfaces */ 73862306a36Sopenharmony_ci if (r->mac.glort != glort) 73962306a36Sopenharmony_ci break; 74062306a36Sopenharmony_ci fallthrough; 74162306a36Sopenharmony_ci case FM10K_VLAN_REQUEST: 74262306a36Sopenharmony_ci if (vlans) { 74362306a36Sopenharmony_ci list_del(&r->list); 74462306a36Sopenharmony_ci kfree(r); 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci break; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci spin_unlock_irqrestore(&interface->macvlan_lock, flags); 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_cistatic int fm10k_uc_vlan_unsync(struct net_device *netdev, 75462306a36Sopenharmony_ci const unsigned char *uc_addr) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 75762306a36Sopenharmony_ci u16 glort = interface->glort; 75862306a36Sopenharmony_ci u16 vid = interface->vid; 75962306a36Sopenharmony_ci bool set = !!(vid / VLAN_N_VID); 76062306a36Sopenharmony_ci int err; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci /* drop any leading bits on the VLAN ID */ 76362306a36Sopenharmony_ci vid &= VLAN_N_VID - 1; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci err = fm10k_queue_mac_request(interface, glort, uc_addr, vid, set); 76662306a36Sopenharmony_ci if (err) 76762306a36Sopenharmony_ci return err; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* return non-zero value as we are only doing a partial sync/unsync */ 77062306a36Sopenharmony_ci return 1; 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic int fm10k_mc_vlan_unsync(struct net_device *netdev, 77462306a36Sopenharmony_ci const unsigned char *mc_addr) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 77762306a36Sopenharmony_ci u16 glort = interface->glort; 77862306a36Sopenharmony_ci u16 vid = interface->vid; 77962306a36Sopenharmony_ci bool set = !!(vid / VLAN_N_VID); 78062306a36Sopenharmony_ci int err; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci /* drop any leading bits on the VLAN ID */ 78362306a36Sopenharmony_ci vid &= VLAN_N_VID - 1; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci err = fm10k_queue_mac_request(interface, glort, mc_addr, vid, set); 78662306a36Sopenharmony_ci if (err) 78762306a36Sopenharmony_ci return err; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci /* return non-zero value as we are only doing a partial sync/unsync */ 79062306a36Sopenharmony_ci return 1; 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic int fm10k_update_vid(struct net_device *netdev, u16 vid, bool set) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 79662306a36Sopenharmony_ci struct fm10k_l2_accel *l2_accel = interface->l2_accel; 79762306a36Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 79862306a36Sopenharmony_ci u16 glort; 79962306a36Sopenharmony_ci s32 err; 80062306a36Sopenharmony_ci int i; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci /* updates do not apply to VLAN 0 */ 80362306a36Sopenharmony_ci if (!vid) 80462306a36Sopenharmony_ci return 0; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci if (vid >= VLAN_N_VID) 80762306a36Sopenharmony_ci return -EINVAL; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci /* Verify that we have permission to add VLANs. If this is a request 81062306a36Sopenharmony_ci * to remove a VLAN, we still want to allow the user to remove the 81162306a36Sopenharmony_ci * VLAN device. In that case, we need to clear the bit in the 81262306a36Sopenharmony_ci * active_vlans bitmask. 81362306a36Sopenharmony_ci */ 81462306a36Sopenharmony_ci if (set && hw->mac.vlan_override) 81562306a36Sopenharmony_ci return -EACCES; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci /* update active_vlans bitmask */ 81862306a36Sopenharmony_ci set_bit(vid, interface->active_vlans); 81962306a36Sopenharmony_ci if (!set) 82062306a36Sopenharmony_ci clear_bit(vid, interface->active_vlans); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci /* disable the default VLAN ID on ring if we have an active VLAN */ 82362306a36Sopenharmony_ci for (i = 0; i < interface->num_rx_queues; i++) { 82462306a36Sopenharmony_ci struct fm10k_ring *rx_ring = interface->rx_ring[i]; 82562306a36Sopenharmony_ci u16 rx_vid = rx_ring->vid & (VLAN_N_VID - 1); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (test_bit(rx_vid, interface->active_vlans)) 82862306a36Sopenharmony_ci rx_ring->vid |= FM10K_VLAN_CLEAR; 82962306a36Sopenharmony_ci else 83062306a36Sopenharmony_ci rx_ring->vid &= ~FM10K_VLAN_CLEAR; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci /* If our VLAN has been overridden, there is no reason to send VLAN 83462306a36Sopenharmony_ci * removal requests as they will be silently ignored. 83562306a36Sopenharmony_ci */ 83662306a36Sopenharmony_ci if (hw->mac.vlan_override) 83762306a36Sopenharmony_ci return 0; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci /* Do not remove default VLAN ID related entries from VLAN and MAC 84062306a36Sopenharmony_ci * tables 84162306a36Sopenharmony_ci */ 84262306a36Sopenharmony_ci if (!set && vid == hw->mac.default_vid) 84362306a36Sopenharmony_ci return 0; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci /* Do not throw an error if the interface is down. We will sync once 84662306a36Sopenharmony_ci * we come up 84762306a36Sopenharmony_ci */ 84862306a36Sopenharmony_ci if (test_bit(__FM10K_DOWN, interface->state)) 84962306a36Sopenharmony_ci return 0; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci fm10k_mbx_lock(interface); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci /* only need to update the VLAN if not in promiscuous mode */ 85462306a36Sopenharmony_ci if (!(netdev->flags & IFF_PROMISC)) { 85562306a36Sopenharmony_ci err = fm10k_queue_vlan_request(interface, vid, 0, set); 85662306a36Sopenharmony_ci if (err) 85762306a36Sopenharmony_ci goto err_out; 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci /* Update our base MAC address */ 86162306a36Sopenharmony_ci err = fm10k_queue_mac_request(interface, interface->glort, 86262306a36Sopenharmony_ci hw->mac.addr, vid, set); 86362306a36Sopenharmony_ci if (err) 86462306a36Sopenharmony_ci goto err_out; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci /* Update L2 accelerated macvlan addresses */ 86762306a36Sopenharmony_ci if (l2_accel) { 86862306a36Sopenharmony_ci for (i = 0; i < l2_accel->size; i++) { 86962306a36Sopenharmony_ci struct net_device *sdev = l2_accel->macvlan[i]; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci if (!sdev) 87262306a36Sopenharmony_ci continue; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci glort = l2_accel->dglort + 1 + i; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci fm10k_queue_mac_request(interface, glort, 87762306a36Sopenharmony_ci sdev->dev_addr, 87862306a36Sopenharmony_ci vid, set); 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci /* set VLAN ID prior to syncing/unsyncing the VLAN */ 88362306a36Sopenharmony_ci interface->vid = vid + (set ? VLAN_N_VID : 0); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci /* Update the unicast and multicast address list to add/drop VLAN */ 88662306a36Sopenharmony_ci __dev_uc_unsync(netdev, fm10k_uc_vlan_unsync); 88762306a36Sopenharmony_ci __dev_mc_unsync(netdev, fm10k_mc_vlan_unsync); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_cierr_out: 89062306a36Sopenharmony_ci fm10k_mbx_unlock(interface); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci return err; 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_cistatic int fm10k_vlan_rx_add_vid(struct net_device *netdev, 89662306a36Sopenharmony_ci __always_unused __be16 proto, u16 vid) 89762306a36Sopenharmony_ci{ 89862306a36Sopenharmony_ci /* update VLAN and address table based on changes */ 89962306a36Sopenharmony_ci return fm10k_update_vid(netdev, vid, true); 90062306a36Sopenharmony_ci} 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_cistatic int fm10k_vlan_rx_kill_vid(struct net_device *netdev, 90362306a36Sopenharmony_ci __always_unused __be16 proto, u16 vid) 90462306a36Sopenharmony_ci{ 90562306a36Sopenharmony_ci /* update VLAN and address table based on changes */ 90662306a36Sopenharmony_ci return fm10k_update_vid(netdev, vid, false); 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_cistatic u16 fm10k_find_next_vlan(struct fm10k_intfc *interface, u16 vid) 91062306a36Sopenharmony_ci{ 91162306a36Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 91262306a36Sopenharmony_ci u16 default_vid = hw->mac.default_vid; 91362306a36Sopenharmony_ci u16 vid_limit = vid < default_vid ? default_vid : VLAN_N_VID; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci vid = find_next_bit(interface->active_vlans, vid_limit, ++vid); 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci return vid; 91862306a36Sopenharmony_ci} 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_cistatic void fm10k_clear_unused_vlans(struct fm10k_intfc *interface) 92162306a36Sopenharmony_ci{ 92262306a36Sopenharmony_ci u32 vid, prev_vid; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci /* loop through and find any gaps in the table */ 92562306a36Sopenharmony_ci for (vid = 0, prev_vid = 0; 92662306a36Sopenharmony_ci prev_vid < VLAN_N_VID; 92762306a36Sopenharmony_ci prev_vid = vid + 1, vid = fm10k_find_next_vlan(interface, vid)) { 92862306a36Sopenharmony_ci if (prev_vid == vid) 92962306a36Sopenharmony_ci continue; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci /* send request to clear multiple bits at a time */ 93262306a36Sopenharmony_ci prev_vid += (vid - prev_vid - 1) << FM10K_VLAN_LENGTH_SHIFT; 93362306a36Sopenharmony_ci fm10k_queue_vlan_request(interface, prev_vid, 0, false); 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_cistatic int __fm10k_uc_sync(struct net_device *dev, 93862306a36Sopenharmony_ci const unsigned char *addr, bool sync) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 94162306a36Sopenharmony_ci u16 vid, glort = interface->glort; 94262306a36Sopenharmony_ci s32 err; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci if (!is_valid_ether_addr(addr)) 94562306a36Sopenharmony_ci return -EADDRNOTAVAIL; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci for (vid = fm10k_find_next_vlan(interface, 0); 94862306a36Sopenharmony_ci vid < VLAN_N_VID; 94962306a36Sopenharmony_ci vid = fm10k_find_next_vlan(interface, vid)) { 95062306a36Sopenharmony_ci err = fm10k_queue_mac_request(interface, glort, 95162306a36Sopenharmony_ci addr, vid, sync); 95262306a36Sopenharmony_ci if (err) 95362306a36Sopenharmony_ci return err; 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci return 0; 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cistatic int fm10k_uc_sync(struct net_device *dev, 96062306a36Sopenharmony_ci const unsigned char *addr) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci return __fm10k_uc_sync(dev, addr, true); 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_cistatic int fm10k_uc_unsync(struct net_device *dev, 96662306a36Sopenharmony_ci const unsigned char *addr) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci return __fm10k_uc_sync(dev, addr, false); 96962306a36Sopenharmony_ci} 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_cistatic int fm10k_set_mac(struct net_device *dev, void *p) 97262306a36Sopenharmony_ci{ 97362306a36Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 97462306a36Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 97562306a36Sopenharmony_ci struct sockaddr *addr = p; 97662306a36Sopenharmony_ci s32 err = 0; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci if (!is_valid_ether_addr(addr->sa_data)) 97962306a36Sopenharmony_ci return -EADDRNOTAVAIL; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci if (dev->flags & IFF_UP) { 98262306a36Sopenharmony_ci /* setting MAC address requires mailbox */ 98362306a36Sopenharmony_ci fm10k_mbx_lock(interface); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci err = fm10k_uc_sync(dev, addr->sa_data); 98662306a36Sopenharmony_ci if (!err) 98762306a36Sopenharmony_ci fm10k_uc_unsync(dev, hw->mac.addr); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci fm10k_mbx_unlock(interface); 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci if (!err) { 99362306a36Sopenharmony_ci eth_hw_addr_set(dev, addr->sa_data); 99462306a36Sopenharmony_ci ether_addr_copy(hw->mac.addr, addr->sa_data); 99562306a36Sopenharmony_ci dev->addr_assign_type &= ~NET_ADDR_RANDOM; 99662306a36Sopenharmony_ci } 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci /* if we had a mailbox error suggest trying again */ 99962306a36Sopenharmony_ci return err ? -EAGAIN : 0; 100062306a36Sopenharmony_ci} 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_cistatic int __fm10k_mc_sync(struct net_device *dev, 100362306a36Sopenharmony_ci const unsigned char *addr, bool sync) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 100662306a36Sopenharmony_ci u16 vid, glort = interface->glort; 100762306a36Sopenharmony_ci s32 err; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (!is_multicast_ether_addr(addr)) 101062306a36Sopenharmony_ci return -EADDRNOTAVAIL; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci for (vid = fm10k_find_next_vlan(interface, 0); 101362306a36Sopenharmony_ci vid < VLAN_N_VID; 101462306a36Sopenharmony_ci vid = fm10k_find_next_vlan(interface, vid)) { 101562306a36Sopenharmony_ci err = fm10k_queue_mac_request(interface, glort, 101662306a36Sopenharmony_ci addr, vid, sync); 101762306a36Sopenharmony_ci if (err) 101862306a36Sopenharmony_ci return err; 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci return 0; 102262306a36Sopenharmony_ci} 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_cistatic int fm10k_mc_sync(struct net_device *dev, 102562306a36Sopenharmony_ci const unsigned char *addr) 102662306a36Sopenharmony_ci{ 102762306a36Sopenharmony_ci return __fm10k_mc_sync(dev, addr, true); 102862306a36Sopenharmony_ci} 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_cistatic int fm10k_mc_unsync(struct net_device *dev, 103162306a36Sopenharmony_ci const unsigned char *addr) 103262306a36Sopenharmony_ci{ 103362306a36Sopenharmony_ci return __fm10k_mc_sync(dev, addr, false); 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_cistatic void fm10k_set_rx_mode(struct net_device *dev) 103762306a36Sopenharmony_ci{ 103862306a36Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 103962306a36Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 104062306a36Sopenharmony_ci int xcast_mode; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci /* no need to update the harwdare if we are not running */ 104362306a36Sopenharmony_ci if (!(dev->flags & IFF_UP)) 104462306a36Sopenharmony_ci return; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci /* determine new mode based on flags */ 104762306a36Sopenharmony_ci xcast_mode = (dev->flags & IFF_PROMISC) ? FM10K_XCAST_MODE_PROMISC : 104862306a36Sopenharmony_ci (dev->flags & IFF_ALLMULTI) ? FM10K_XCAST_MODE_ALLMULTI : 104962306a36Sopenharmony_ci (dev->flags & (IFF_BROADCAST | IFF_MULTICAST)) ? 105062306a36Sopenharmony_ci FM10K_XCAST_MODE_MULTI : FM10K_XCAST_MODE_NONE; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci fm10k_mbx_lock(interface); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci /* update xcast mode first, but only if it changed */ 105562306a36Sopenharmony_ci if (interface->xcast_mode != xcast_mode) { 105662306a36Sopenharmony_ci /* update VLAN table when entering promiscuous mode */ 105762306a36Sopenharmony_ci if (xcast_mode == FM10K_XCAST_MODE_PROMISC) 105862306a36Sopenharmony_ci fm10k_queue_vlan_request(interface, FM10K_VLAN_ALL, 105962306a36Sopenharmony_ci 0, true); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci /* clear VLAN table when exiting promiscuous mode */ 106262306a36Sopenharmony_ci if (interface->xcast_mode == FM10K_XCAST_MODE_PROMISC) 106362306a36Sopenharmony_ci fm10k_clear_unused_vlans(interface); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci /* update xcast mode if host's mailbox is ready */ 106662306a36Sopenharmony_ci if (fm10k_host_mbx_ready(interface)) 106762306a36Sopenharmony_ci hw->mac.ops.update_xcast_mode(hw, interface->glort, 106862306a36Sopenharmony_ci xcast_mode); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci /* record updated xcast mode state */ 107162306a36Sopenharmony_ci interface->xcast_mode = xcast_mode; 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci /* synchronize all of the addresses */ 107562306a36Sopenharmony_ci __dev_uc_sync(dev, fm10k_uc_sync, fm10k_uc_unsync); 107662306a36Sopenharmony_ci __dev_mc_sync(dev, fm10k_mc_sync, fm10k_mc_unsync); 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci fm10k_mbx_unlock(interface); 107962306a36Sopenharmony_ci} 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_civoid fm10k_restore_rx_state(struct fm10k_intfc *interface) 108262306a36Sopenharmony_ci{ 108362306a36Sopenharmony_ci struct fm10k_l2_accel *l2_accel = interface->l2_accel; 108462306a36Sopenharmony_ci struct net_device *netdev = interface->netdev; 108562306a36Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 108662306a36Sopenharmony_ci int xcast_mode, i; 108762306a36Sopenharmony_ci u16 vid, glort; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci /* record glort for this interface */ 109062306a36Sopenharmony_ci glort = interface->glort; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci /* convert interface flags to xcast mode */ 109362306a36Sopenharmony_ci if (netdev->flags & IFF_PROMISC) 109462306a36Sopenharmony_ci xcast_mode = FM10K_XCAST_MODE_PROMISC; 109562306a36Sopenharmony_ci else if (netdev->flags & IFF_ALLMULTI) 109662306a36Sopenharmony_ci xcast_mode = FM10K_XCAST_MODE_ALLMULTI; 109762306a36Sopenharmony_ci else if (netdev->flags & (IFF_BROADCAST | IFF_MULTICAST)) 109862306a36Sopenharmony_ci xcast_mode = FM10K_XCAST_MODE_MULTI; 109962306a36Sopenharmony_ci else 110062306a36Sopenharmony_ci xcast_mode = FM10K_XCAST_MODE_NONE; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci fm10k_mbx_lock(interface); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci /* Enable logical port if host's mailbox is ready */ 110562306a36Sopenharmony_ci if (fm10k_host_mbx_ready(interface)) 110662306a36Sopenharmony_ci hw->mac.ops.update_lport_state(hw, glort, 110762306a36Sopenharmony_ci interface->glort_count, true); 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci /* update VLAN table */ 111062306a36Sopenharmony_ci fm10k_queue_vlan_request(interface, FM10K_VLAN_ALL, 0, 111162306a36Sopenharmony_ci xcast_mode == FM10K_XCAST_MODE_PROMISC); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci /* update table with current entries */ 111462306a36Sopenharmony_ci for (vid = fm10k_find_next_vlan(interface, 0); 111562306a36Sopenharmony_ci vid < VLAN_N_VID; 111662306a36Sopenharmony_ci vid = fm10k_find_next_vlan(interface, vid)) { 111762306a36Sopenharmony_ci fm10k_queue_vlan_request(interface, vid, 0, true); 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci fm10k_queue_mac_request(interface, glort, 112062306a36Sopenharmony_ci hw->mac.addr, vid, true); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci /* synchronize macvlan addresses */ 112362306a36Sopenharmony_ci if (l2_accel) { 112462306a36Sopenharmony_ci for (i = 0; i < l2_accel->size; i++) { 112562306a36Sopenharmony_ci struct net_device *sdev = l2_accel->macvlan[i]; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci if (!sdev) 112862306a36Sopenharmony_ci continue; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci glort = l2_accel->dglort + 1 + i; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci fm10k_queue_mac_request(interface, glort, 113362306a36Sopenharmony_ci sdev->dev_addr, 113462306a36Sopenharmony_ci vid, true); 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci } 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci /* update xcast mode before synchronizing addresses if host's mailbox 114062306a36Sopenharmony_ci * is ready 114162306a36Sopenharmony_ci */ 114262306a36Sopenharmony_ci if (fm10k_host_mbx_ready(interface)) 114362306a36Sopenharmony_ci hw->mac.ops.update_xcast_mode(hw, glort, xcast_mode); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci /* synchronize all of the addresses */ 114662306a36Sopenharmony_ci __dev_uc_sync(netdev, fm10k_uc_sync, fm10k_uc_unsync); 114762306a36Sopenharmony_ci __dev_mc_sync(netdev, fm10k_mc_sync, fm10k_mc_unsync); 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci /* synchronize macvlan addresses */ 115062306a36Sopenharmony_ci if (l2_accel) { 115162306a36Sopenharmony_ci for (i = 0; i < l2_accel->size; i++) { 115262306a36Sopenharmony_ci struct net_device *sdev = l2_accel->macvlan[i]; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci if (!sdev) 115562306a36Sopenharmony_ci continue; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci glort = l2_accel->dglort + 1 + i; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci hw->mac.ops.update_xcast_mode(hw, glort, 116062306a36Sopenharmony_ci FM10K_XCAST_MODE_NONE); 116162306a36Sopenharmony_ci fm10k_queue_mac_request(interface, glort, 116262306a36Sopenharmony_ci sdev->dev_addr, 116362306a36Sopenharmony_ci hw->mac.default_vid, true); 116462306a36Sopenharmony_ci } 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci fm10k_mbx_unlock(interface); 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci /* record updated xcast mode state */ 117062306a36Sopenharmony_ci interface->xcast_mode = xcast_mode; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci /* Restore tunnel configuration */ 117362306a36Sopenharmony_ci fm10k_restore_udp_port_info(interface); 117462306a36Sopenharmony_ci} 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_civoid fm10k_reset_rx_state(struct fm10k_intfc *interface) 117762306a36Sopenharmony_ci{ 117862306a36Sopenharmony_ci struct net_device *netdev = interface->netdev; 117962306a36Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci /* Wait for MAC/VLAN work to finish */ 118262306a36Sopenharmony_ci while (test_bit(__FM10K_MACVLAN_SCHED, interface->state)) 118362306a36Sopenharmony_ci usleep_range(1000, 2000); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci /* Cancel pending MAC/VLAN requests */ 118662306a36Sopenharmony_ci fm10k_clear_macvlan_queue(interface, interface->glort, true); 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci fm10k_mbx_lock(interface); 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci /* clear the logical port state on lower device if host's mailbox is 119162306a36Sopenharmony_ci * ready 119262306a36Sopenharmony_ci */ 119362306a36Sopenharmony_ci if (fm10k_host_mbx_ready(interface)) 119462306a36Sopenharmony_ci hw->mac.ops.update_lport_state(hw, interface->glort, 119562306a36Sopenharmony_ci interface->glort_count, false); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci fm10k_mbx_unlock(interface); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci /* reset flags to default state */ 120062306a36Sopenharmony_ci interface->xcast_mode = FM10K_XCAST_MODE_NONE; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci /* clear the sync flag since the lport has been dropped */ 120362306a36Sopenharmony_ci __dev_uc_unsync(netdev, NULL); 120462306a36Sopenharmony_ci __dev_mc_unsync(netdev, NULL); 120562306a36Sopenharmony_ci} 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci/** 120862306a36Sopenharmony_ci * fm10k_get_stats64 - Get System Network Statistics 120962306a36Sopenharmony_ci * @netdev: network interface device structure 121062306a36Sopenharmony_ci * @stats: storage space for 64bit statistics 121162306a36Sopenharmony_ci * 121262306a36Sopenharmony_ci * Obtain 64bit statistics in a way that is safe for both 32bit and 64bit 121362306a36Sopenharmony_ci * architectures. 121462306a36Sopenharmony_ci */ 121562306a36Sopenharmony_cistatic void fm10k_get_stats64(struct net_device *netdev, 121662306a36Sopenharmony_ci struct rtnl_link_stats64 *stats) 121762306a36Sopenharmony_ci{ 121862306a36Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(netdev); 121962306a36Sopenharmony_ci struct fm10k_ring *ring; 122062306a36Sopenharmony_ci unsigned int start, i; 122162306a36Sopenharmony_ci u64 bytes, packets; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci rcu_read_lock(); 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci for (i = 0; i < interface->num_rx_queues; i++) { 122662306a36Sopenharmony_ci ring = READ_ONCE(interface->rx_ring[i]); 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci if (!ring) 122962306a36Sopenharmony_ci continue; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci do { 123262306a36Sopenharmony_ci start = u64_stats_fetch_begin(&ring->syncp); 123362306a36Sopenharmony_ci packets = ring->stats.packets; 123462306a36Sopenharmony_ci bytes = ring->stats.bytes; 123562306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&ring->syncp, start)); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci stats->rx_packets += packets; 123862306a36Sopenharmony_ci stats->rx_bytes += bytes; 123962306a36Sopenharmony_ci } 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci for (i = 0; i < interface->num_tx_queues; i++) { 124262306a36Sopenharmony_ci ring = READ_ONCE(interface->tx_ring[i]); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci if (!ring) 124562306a36Sopenharmony_ci continue; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci do { 124862306a36Sopenharmony_ci start = u64_stats_fetch_begin(&ring->syncp); 124962306a36Sopenharmony_ci packets = ring->stats.packets; 125062306a36Sopenharmony_ci bytes = ring->stats.bytes; 125162306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&ring->syncp, start)); 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci stats->tx_packets += packets; 125462306a36Sopenharmony_ci stats->tx_bytes += bytes; 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci rcu_read_unlock(); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci /* following stats updated by fm10k_service_task() */ 126062306a36Sopenharmony_ci stats->rx_missed_errors = netdev->stats.rx_missed_errors; 126162306a36Sopenharmony_ci} 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ciint fm10k_setup_tc(struct net_device *dev, u8 tc) 126462306a36Sopenharmony_ci{ 126562306a36Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 126662306a36Sopenharmony_ci int err; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci /* Currently only the PF supports priority classes */ 126962306a36Sopenharmony_ci if (tc && (interface->hw.mac.type != fm10k_mac_pf)) 127062306a36Sopenharmony_ci return -EINVAL; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci /* Hardware supports up to 8 traffic classes */ 127362306a36Sopenharmony_ci if (tc > 8) 127462306a36Sopenharmony_ci return -EINVAL; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci /* Hardware has to reinitialize queues to match packet 127762306a36Sopenharmony_ci * buffer alignment. Unfortunately, the hardware is not 127862306a36Sopenharmony_ci * flexible enough to do this dynamically. 127962306a36Sopenharmony_ci */ 128062306a36Sopenharmony_ci if (netif_running(dev)) 128162306a36Sopenharmony_ci fm10k_close(dev); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci fm10k_mbx_free_irq(interface); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci fm10k_clear_queueing_scheme(interface); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci /* we expect the prio_tc map to be repopulated later */ 128862306a36Sopenharmony_ci netdev_reset_tc(dev); 128962306a36Sopenharmony_ci netdev_set_num_tc(dev, tc); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci err = fm10k_init_queueing_scheme(interface); 129262306a36Sopenharmony_ci if (err) 129362306a36Sopenharmony_ci goto err_queueing_scheme; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci err = fm10k_mbx_request_irq(interface); 129662306a36Sopenharmony_ci if (err) 129762306a36Sopenharmony_ci goto err_mbx_irq; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci err = netif_running(dev) ? fm10k_open(dev) : 0; 130062306a36Sopenharmony_ci if (err) 130162306a36Sopenharmony_ci goto err_open; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci /* flag to indicate SWPRI has yet to be updated */ 130462306a36Sopenharmony_ci set_bit(FM10K_FLAG_SWPRI_CONFIG, interface->flags); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci return 0; 130762306a36Sopenharmony_cierr_open: 130862306a36Sopenharmony_ci fm10k_mbx_free_irq(interface); 130962306a36Sopenharmony_cierr_mbx_irq: 131062306a36Sopenharmony_ci fm10k_clear_queueing_scheme(interface); 131162306a36Sopenharmony_cierr_queueing_scheme: 131262306a36Sopenharmony_ci netif_device_detach(dev); 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci return err; 131562306a36Sopenharmony_ci} 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_cistatic int __fm10k_setup_tc(struct net_device *dev, enum tc_setup_type type, 131862306a36Sopenharmony_ci void *type_data) 131962306a36Sopenharmony_ci{ 132062306a36Sopenharmony_ci struct tc_mqprio_qopt *mqprio = type_data; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci if (type != TC_SETUP_QDISC_MQPRIO) 132362306a36Sopenharmony_ci return -EOPNOTSUPP; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci return fm10k_setup_tc(dev, mqprio->num_tc); 132862306a36Sopenharmony_ci} 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_cistatic void fm10k_assign_l2_accel(struct fm10k_intfc *interface, 133162306a36Sopenharmony_ci struct fm10k_l2_accel *l2_accel) 133262306a36Sopenharmony_ci{ 133362306a36Sopenharmony_ci int i; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci for (i = 0; i < interface->num_rx_queues; i++) { 133662306a36Sopenharmony_ci struct fm10k_ring *ring = interface->rx_ring[i]; 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci rcu_assign_pointer(ring->l2_accel, l2_accel); 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci interface->l2_accel = l2_accel; 134262306a36Sopenharmony_ci} 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_cistatic void *fm10k_dfwd_add_station(struct net_device *dev, 134562306a36Sopenharmony_ci struct net_device *sdev) 134662306a36Sopenharmony_ci{ 134762306a36Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 134862306a36Sopenharmony_ci struct fm10k_l2_accel *l2_accel = interface->l2_accel; 134962306a36Sopenharmony_ci struct fm10k_l2_accel *old_l2_accel = NULL; 135062306a36Sopenharmony_ci struct fm10k_dglort_cfg dglort = { 0 }; 135162306a36Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 135262306a36Sopenharmony_ci int size, i; 135362306a36Sopenharmony_ci u16 vid, glort; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci /* The hardware supported by fm10k only filters on the destination MAC 135662306a36Sopenharmony_ci * address. In order to avoid issues we only support offloading modes 135762306a36Sopenharmony_ci * where the hardware can actually provide the functionality. 135862306a36Sopenharmony_ci */ 135962306a36Sopenharmony_ci if (!macvlan_supports_dest_filter(sdev)) 136062306a36Sopenharmony_ci return ERR_PTR(-EMEDIUMTYPE); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci /* allocate l2 accel structure if it is not available */ 136362306a36Sopenharmony_ci if (!l2_accel) { 136462306a36Sopenharmony_ci /* verify there is enough free GLORTs to support l2_accel */ 136562306a36Sopenharmony_ci if (interface->glort_count < 7) 136662306a36Sopenharmony_ci return ERR_PTR(-EBUSY); 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci size = offsetof(struct fm10k_l2_accel, macvlan[7]); 136962306a36Sopenharmony_ci l2_accel = kzalloc(size, GFP_KERNEL); 137062306a36Sopenharmony_ci if (!l2_accel) 137162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci l2_accel->size = 7; 137462306a36Sopenharmony_ci l2_accel->dglort = interface->glort; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci /* update pointers */ 137762306a36Sopenharmony_ci fm10k_assign_l2_accel(interface, l2_accel); 137862306a36Sopenharmony_ci /* do not expand if we are at our limit */ 137962306a36Sopenharmony_ci } else if ((l2_accel->count == FM10K_MAX_STATIONS) || 138062306a36Sopenharmony_ci (l2_accel->count == (interface->glort_count - 1))) { 138162306a36Sopenharmony_ci return ERR_PTR(-EBUSY); 138262306a36Sopenharmony_ci /* expand if we have hit the size limit */ 138362306a36Sopenharmony_ci } else if (l2_accel->count == l2_accel->size) { 138462306a36Sopenharmony_ci old_l2_accel = l2_accel; 138562306a36Sopenharmony_ci size = offsetof(struct fm10k_l2_accel, 138662306a36Sopenharmony_ci macvlan[(l2_accel->size * 2) + 1]); 138762306a36Sopenharmony_ci l2_accel = kzalloc(size, GFP_KERNEL); 138862306a36Sopenharmony_ci if (!l2_accel) 138962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci memcpy(l2_accel, old_l2_accel, 139262306a36Sopenharmony_ci offsetof(struct fm10k_l2_accel, 139362306a36Sopenharmony_ci macvlan[old_l2_accel->size])); 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci l2_accel->size = (old_l2_accel->size * 2) + 1; 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci /* update pointers */ 139862306a36Sopenharmony_ci fm10k_assign_l2_accel(interface, l2_accel); 139962306a36Sopenharmony_ci kfree_rcu(old_l2_accel, rcu); 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci /* add macvlan to accel table, and record GLORT for position */ 140362306a36Sopenharmony_ci for (i = 0; i < l2_accel->size; i++) { 140462306a36Sopenharmony_ci if (!l2_accel->macvlan[i]) 140562306a36Sopenharmony_ci break; 140662306a36Sopenharmony_ci } 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci /* record station */ 140962306a36Sopenharmony_ci l2_accel->macvlan[i] = sdev; 141062306a36Sopenharmony_ci l2_accel->count++; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci /* configure default DGLORT mapping for RSS/DCB */ 141362306a36Sopenharmony_ci dglort.idx = fm10k_dglort_pf_rss; 141462306a36Sopenharmony_ci dglort.inner_rss = 1; 141562306a36Sopenharmony_ci dglort.rss_l = fls(interface->ring_feature[RING_F_RSS].mask); 141662306a36Sopenharmony_ci dglort.pc_l = fls(interface->ring_feature[RING_F_QOS].mask); 141762306a36Sopenharmony_ci dglort.glort = interface->glort; 141862306a36Sopenharmony_ci dglort.shared_l = fls(l2_accel->size); 141962306a36Sopenharmony_ci hw->mac.ops.configure_dglort_map(hw, &dglort); 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci /* Add rules for this specific dglort to the switch */ 142262306a36Sopenharmony_ci fm10k_mbx_lock(interface); 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci glort = l2_accel->dglort + 1 + i; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci if (fm10k_host_mbx_ready(interface)) 142762306a36Sopenharmony_ci hw->mac.ops.update_xcast_mode(hw, glort, 142862306a36Sopenharmony_ci FM10K_XCAST_MODE_NONE); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci fm10k_queue_mac_request(interface, glort, sdev->dev_addr, 143162306a36Sopenharmony_ci hw->mac.default_vid, true); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci for (vid = fm10k_find_next_vlan(interface, 0); 143462306a36Sopenharmony_ci vid < VLAN_N_VID; 143562306a36Sopenharmony_ci vid = fm10k_find_next_vlan(interface, vid)) 143662306a36Sopenharmony_ci fm10k_queue_mac_request(interface, glort, sdev->dev_addr, 143762306a36Sopenharmony_ci vid, true); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci fm10k_mbx_unlock(interface); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci return sdev; 144262306a36Sopenharmony_ci} 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_cistatic void fm10k_dfwd_del_station(struct net_device *dev, void *priv) 144562306a36Sopenharmony_ci{ 144662306a36Sopenharmony_ci struct fm10k_intfc *interface = netdev_priv(dev); 144762306a36Sopenharmony_ci struct fm10k_l2_accel *l2_accel = READ_ONCE(interface->l2_accel); 144862306a36Sopenharmony_ci struct fm10k_dglort_cfg dglort = { 0 }; 144962306a36Sopenharmony_ci struct fm10k_hw *hw = &interface->hw; 145062306a36Sopenharmony_ci struct net_device *sdev = priv; 145162306a36Sopenharmony_ci u16 vid, glort; 145262306a36Sopenharmony_ci int i; 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci if (!l2_accel) 145562306a36Sopenharmony_ci return; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci /* search table for matching interface */ 145862306a36Sopenharmony_ci for (i = 0; i < l2_accel->size; i++) { 145962306a36Sopenharmony_ci if (l2_accel->macvlan[i] == sdev) 146062306a36Sopenharmony_ci break; 146162306a36Sopenharmony_ci } 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci /* exit if macvlan not found */ 146462306a36Sopenharmony_ci if (i == l2_accel->size) 146562306a36Sopenharmony_ci return; 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci /* Remove any rules specific to this dglort */ 146862306a36Sopenharmony_ci fm10k_mbx_lock(interface); 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci glort = l2_accel->dglort + 1 + i; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci if (fm10k_host_mbx_ready(interface)) 147362306a36Sopenharmony_ci hw->mac.ops.update_xcast_mode(hw, glort, 147462306a36Sopenharmony_ci FM10K_XCAST_MODE_NONE); 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci fm10k_queue_mac_request(interface, glort, sdev->dev_addr, 147762306a36Sopenharmony_ci hw->mac.default_vid, false); 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci for (vid = fm10k_find_next_vlan(interface, 0); 148062306a36Sopenharmony_ci vid < VLAN_N_VID; 148162306a36Sopenharmony_ci vid = fm10k_find_next_vlan(interface, vid)) 148262306a36Sopenharmony_ci fm10k_queue_mac_request(interface, glort, sdev->dev_addr, 148362306a36Sopenharmony_ci vid, false); 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci fm10k_mbx_unlock(interface); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci /* record removal */ 148862306a36Sopenharmony_ci l2_accel->macvlan[i] = NULL; 148962306a36Sopenharmony_ci l2_accel->count--; 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci /* configure default DGLORT mapping for RSS/DCB */ 149262306a36Sopenharmony_ci dglort.idx = fm10k_dglort_pf_rss; 149362306a36Sopenharmony_ci dglort.inner_rss = 1; 149462306a36Sopenharmony_ci dglort.rss_l = fls(interface->ring_feature[RING_F_RSS].mask); 149562306a36Sopenharmony_ci dglort.pc_l = fls(interface->ring_feature[RING_F_QOS].mask); 149662306a36Sopenharmony_ci dglort.glort = interface->glort; 149762306a36Sopenharmony_ci dglort.shared_l = fls(l2_accel->size); 149862306a36Sopenharmony_ci hw->mac.ops.configure_dglort_map(hw, &dglort); 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci /* If table is empty remove it */ 150162306a36Sopenharmony_ci if (l2_accel->count == 0) { 150262306a36Sopenharmony_ci fm10k_assign_l2_accel(interface, NULL); 150362306a36Sopenharmony_ci kfree_rcu(l2_accel, rcu); 150462306a36Sopenharmony_ci } 150562306a36Sopenharmony_ci} 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_cistatic netdev_features_t fm10k_features_check(struct sk_buff *skb, 150862306a36Sopenharmony_ci struct net_device *dev, 150962306a36Sopenharmony_ci netdev_features_t features) 151062306a36Sopenharmony_ci{ 151162306a36Sopenharmony_ci if (!skb->encapsulation || fm10k_tx_encap_offload(skb)) 151262306a36Sopenharmony_ci return features; 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); 151562306a36Sopenharmony_ci} 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_cistatic const struct net_device_ops fm10k_netdev_ops = { 151862306a36Sopenharmony_ci .ndo_open = fm10k_open, 151962306a36Sopenharmony_ci .ndo_stop = fm10k_close, 152062306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 152162306a36Sopenharmony_ci .ndo_start_xmit = fm10k_xmit_frame, 152262306a36Sopenharmony_ci .ndo_set_mac_address = fm10k_set_mac, 152362306a36Sopenharmony_ci .ndo_tx_timeout = fm10k_tx_timeout, 152462306a36Sopenharmony_ci .ndo_vlan_rx_add_vid = fm10k_vlan_rx_add_vid, 152562306a36Sopenharmony_ci .ndo_vlan_rx_kill_vid = fm10k_vlan_rx_kill_vid, 152662306a36Sopenharmony_ci .ndo_set_rx_mode = fm10k_set_rx_mode, 152762306a36Sopenharmony_ci .ndo_get_stats64 = fm10k_get_stats64, 152862306a36Sopenharmony_ci .ndo_setup_tc = __fm10k_setup_tc, 152962306a36Sopenharmony_ci .ndo_set_vf_mac = fm10k_ndo_set_vf_mac, 153062306a36Sopenharmony_ci .ndo_set_vf_vlan = fm10k_ndo_set_vf_vlan, 153162306a36Sopenharmony_ci .ndo_set_vf_rate = fm10k_ndo_set_vf_bw, 153262306a36Sopenharmony_ci .ndo_get_vf_config = fm10k_ndo_get_vf_config, 153362306a36Sopenharmony_ci .ndo_get_vf_stats = fm10k_ndo_get_vf_stats, 153462306a36Sopenharmony_ci .ndo_dfwd_add_station = fm10k_dfwd_add_station, 153562306a36Sopenharmony_ci .ndo_dfwd_del_station = fm10k_dfwd_del_station, 153662306a36Sopenharmony_ci .ndo_features_check = fm10k_features_check, 153762306a36Sopenharmony_ci}; 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci#define DEFAULT_DEBUG_LEVEL_SHIFT 3 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_cistruct net_device *fm10k_alloc_netdev(const struct fm10k_info *info) 154262306a36Sopenharmony_ci{ 154362306a36Sopenharmony_ci netdev_features_t hw_features; 154462306a36Sopenharmony_ci struct fm10k_intfc *interface; 154562306a36Sopenharmony_ci struct net_device *dev; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci dev = alloc_etherdev_mq(sizeof(struct fm10k_intfc), MAX_QUEUES); 154862306a36Sopenharmony_ci if (!dev) 154962306a36Sopenharmony_ci return NULL; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci /* set net device and ethtool ops */ 155262306a36Sopenharmony_ci dev->netdev_ops = &fm10k_netdev_ops; 155362306a36Sopenharmony_ci fm10k_set_ethtool_ops(dev); 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci /* configure default debug level */ 155662306a36Sopenharmony_ci interface = netdev_priv(dev); 155762306a36Sopenharmony_ci interface->msg_enable = BIT(DEFAULT_DEBUG_LEVEL_SHIFT) - 1; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci /* configure default features */ 156062306a36Sopenharmony_ci dev->features |= NETIF_F_IP_CSUM | 156162306a36Sopenharmony_ci NETIF_F_IPV6_CSUM | 156262306a36Sopenharmony_ci NETIF_F_SG | 156362306a36Sopenharmony_ci NETIF_F_TSO | 156462306a36Sopenharmony_ci NETIF_F_TSO6 | 156562306a36Sopenharmony_ci NETIF_F_TSO_ECN | 156662306a36Sopenharmony_ci NETIF_F_RXHASH | 156762306a36Sopenharmony_ci NETIF_F_RXCSUM; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci /* Only the PF can support VXLAN and NVGRE tunnel offloads */ 157062306a36Sopenharmony_ci if (info->mac == fm10k_mac_pf) { 157162306a36Sopenharmony_ci dev->hw_enc_features = NETIF_F_IP_CSUM | 157262306a36Sopenharmony_ci NETIF_F_TSO | 157362306a36Sopenharmony_ci NETIF_F_TSO6 | 157462306a36Sopenharmony_ci NETIF_F_TSO_ECN | 157562306a36Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL | 157662306a36Sopenharmony_ci NETIF_F_IPV6_CSUM | 157762306a36Sopenharmony_ci NETIF_F_SG; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci dev->features |= NETIF_F_GSO_UDP_TUNNEL; 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci dev->udp_tunnel_nic_info = &fm10k_udp_tunnels; 158262306a36Sopenharmony_ci } 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci /* all features defined to this point should be changeable */ 158562306a36Sopenharmony_ci hw_features = dev->features; 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci /* allow user to enable L2 forwarding acceleration */ 158862306a36Sopenharmony_ci hw_features |= NETIF_F_HW_L2FW_DOFFLOAD; 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci /* configure VLAN features */ 159162306a36Sopenharmony_ci dev->vlan_features |= dev->features; 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci /* we want to leave these both on as we cannot disable VLAN tag 159462306a36Sopenharmony_ci * insertion or stripping on the hardware since it is contained 159562306a36Sopenharmony_ci * in the FTAG and not in the frame itself. 159662306a36Sopenharmony_ci */ 159762306a36Sopenharmony_ci dev->features |= NETIF_F_HW_VLAN_CTAG_TX | 159862306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX | 159962306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_FILTER; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci dev->priv_flags |= IFF_UNICAST_FLT; 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci dev->hw_features |= hw_features; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci /* MTU range: 68 - 15342 */ 160662306a36Sopenharmony_ci dev->min_mtu = ETH_MIN_MTU; 160762306a36Sopenharmony_ci dev->max_mtu = FM10K_MAX_JUMBO_FRAME_SIZE; 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci return dev; 161062306a36Sopenharmony_ci} 1611