18c2ecf20Sopenharmony_ci/****************************************************************************** 28c2ecf20Sopenharmony_ci* This software may be used and distributed according to the terms of 38c2ecf20Sopenharmony_ci* the GNU General Public License (GPL), incorporated herein by reference. 48c2ecf20Sopenharmony_ci* Drivers based on or derived from this code fall under the GPL and must 58c2ecf20Sopenharmony_ci* retain the authorship, copyright and license notice. This file is not 68c2ecf20Sopenharmony_ci* a complete program and may only be used when the entire operating 78c2ecf20Sopenharmony_ci* system is licensed under the GPL. 88c2ecf20Sopenharmony_ci* See the file COPYING in this distribution for more information. 98c2ecf20Sopenharmony_ci* 108c2ecf20Sopenharmony_ci* vxge-main.c: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O 118c2ecf20Sopenharmony_ci* Virtualized Server Adapter. 128c2ecf20Sopenharmony_ci* Copyright(c) 2002-2010 Exar Corp. 138c2ecf20Sopenharmony_ci* 148c2ecf20Sopenharmony_ci* The module loadable parameters that are supported by the driver and a brief 158c2ecf20Sopenharmony_ci* explanation of all the variables: 168c2ecf20Sopenharmony_ci* vlan_tag_strip: 178c2ecf20Sopenharmony_ci* Strip VLAN Tag enable/disable. Instructs the device to remove 188c2ecf20Sopenharmony_ci* the VLAN tag from all received tagged frames that are not 198c2ecf20Sopenharmony_ci* replicated at the internal L2 switch. 208c2ecf20Sopenharmony_ci* 0 - Do not strip the VLAN tag. 218c2ecf20Sopenharmony_ci* 1 - Strip the VLAN tag. 228c2ecf20Sopenharmony_ci* 238c2ecf20Sopenharmony_ci* addr_learn_en: 248c2ecf20Sopenharmony_ci* Enable learning the mac address of the guest OS interface in 258c2ecf20Sopenharmony_ci* a virtualization environment. 268c2ecf20Sopenharmony_ci* 0 - DISABLE 278c2ecf20Sopenharmony_ci* 1 - ENABLE 288c2ecf20Sopenharmony_ci* 298c2ecf20Sopenharmony_ci* max_config_port: 308c2ecf20Sopenharmony_ci* Maximum number of port to be supported. 318c2ecf20Sopenharmony_ci* MIN -1 and MAX - 2 328c2ecf20Sopenharmony_ci* 338c2ecf20Sopenharmony_ci* max_config_vpath: 348c2ecf20Sopenharmony_ci* This configures the maximum no of VPATH configures for each 358c2ecf20Sopenharmony_ci* device function. 368c2ecf20Sopenharmony_ci* MIN - 1 and MAX - 17 378c2ecf20Sopenharmony_ci* 388c2ecf20Sopenharmony_ci* max_config_dev: 398c2ecf20Sopenharmony_ci* This configures maximum no of Device function to be enabled. 408c2ecf20Sopenharmony_ci* MIN - 1 and MAX - 17 418c2ecf20Sopenharmony_ci* 428c2ecf20Sopenharmony_ci******************************************************************************/ 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#include <linux/bitops.h> 478c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 488c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 498c2ecf20Sopenharmony_ci#include <linux/pci.h> 508c2ecf20Sopenharmony_ci#include <linux/slab.h> 518c2ecf20Sopenharmony_ci#include <linux/tcp.h> 528c2ecf20Sopenharmony_ci#include <net/ip.h> 538c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 548c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 558c2ecf20Sopenharmony_ci#include <linux/firmware.h> 568c2ecf20Sopenharmony_ci#include <linux/net_tstamp.h> 578c2ecf20Sopenharmony_ci#include <linux/prefetch.h> 588c2ecf20Sopenharmony_ci#include <linux/module.h> 598c2ecf20Sopenharmony_ci#include "vxge-main.h" 608c2ecf20Sopenharmony_ci#include "vxge-reg.h" 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 638c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Neterion's X3100 Series 10GbE PCIe I/O" 648c2ecf20Sopenharmony_ci "Virtualized Server Adapter"); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic const struct pci_device_id vxge_id_table[] = { 678c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_TITAN_WIN, PCI_ANY_ID, 688c2ecf20Sopenharmony_ci PCI_ANY_ID}, 698c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_TITAN_UNI, PCI_ANY_ID, 708c2ecf20Sopenharmony_ci PCI_ANY_ID}, 718c2ecf20Sopenharmony_ci {0} 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, vxge_id_table); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ciVXGE_MODULE_PARAM_INT(vlan_tag_strip, VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE); 778c2ecf20Sopenharmony_ciVXGE_MODULE_PARAM_INT(addr_learn_en, VXGE_HW_MAC_ADDR_LEARN_DEFAULT); 788c2ecf20Sopenharmony_ciVXGE_MODULE_PARAM_INT(max_config_port, VXGE_MAX_CONFIG_PORT); 798c2ecf20Sopenharmony_ciVXGE_MODULE_PARAM_INT(max_config_vpath, VXGE_USE_DEFAULT); 808c2ecf20Sopenharmony_ciVXGE_MODULE_PARAM_INT(max_mac_vpath, VXGE_MAX_MAC_ADDR_COUNT); 818c2ecf20Sopenharmony_ciVXGE_MODULE_PARAM_INT(max_config_dev, VXGE_MAX_CONFIG_DEV); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic u16 vpath_selector[VXGE_HW_MAX_VIRTUAL_PATHS] = 848c2ecf20Sopenharmony_ci {0, 1, 3, 3, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 15, 31}; 858c2ecf20Sopenharmony_cistatic unsigned int bw_percentage[VXGE_HW_MAX_VIRTUAL_PATHS] = 868c2ecf20Sopenharmony_ci {[0 ...(VXGE_HW_MAX_VIRTUAL_PATHS - 1)] = 0xFF}; 878c2ecf20Sopenharmony_cimodule_param_array(bw_percentage, uint, NULL, 0); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic struct vxge_drv_config *driver_config; 908c2ecf20Sopenharmony_cistatic enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic inline int is_vxge_card_up(struct vxgedev *vdev) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci return test_bit(__VXGE_STATE_CARD_UP, &vdev->state); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic inline void VXGE_COMPLETE_VPATH_TX(struct vxge_fifo *fifo) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci struct sk_buff **skb_ptr = NULL; 1008c2ecf20Sopenharmony_ci struct sk_buff **temp; 1018c2ecf20Sopenharmony_ci#define NR_SKB_COMPLETED 16 1028c2ecf20Sopenharmony_ci struct sk_buff *completed[NR_SKB_COMPLETED]; 1038c2ecf20Sopenharmony_ci int more; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci do { 1068c2ecf20Sopenharmony_ci more = 0; 1078c2ecf20Sopenharmony_ci skb_ptr = completed; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (__netif_tx_trylock(fifo->txq)) { 1108c2ecf20Sopenharmony_ci vxge_hw_vpath_poll_tx(fifo->handle, &skb_ptr, 1118c2ecf20Sopenharmony_ci NR_SKB_COMPLETED, &more); 1128c2ecf20Sopenharmony_ci __netif_tx_unlock(fifo->txq); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* free SKBs */ 1168c2ecf20Sopenharmony_ci for (temp = completed; temp != skb_ptr; temp++) 1178c2ecf20Sopenharmony_ci dev_consume_skb_irq(*temp); 1188c2ecf20Sopenharmony_ci } while (more); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic inline void VXGE_COMPLETE_ALL_TX(struct vxgedev *vdev) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci int i; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* Complete all transmits */ 1268c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) 1278c2ecf20Sopenharmony_ci VXGE_COMPLETE_VPATH_TX(&vdev->vpaths[i].fifo); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic inline void VXGE_COMPLETE_ALL_RX(struct vxgedev *vdev) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci int i; 1338c2ecf20Sopenharmony_ci struct vxge_ring *ring; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* Complete all receives*/ 1368c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 1378c2ecf20Sopenharmony_ci ring = &vdev->vpaths[i].ring; 1388c2ecf20Sopenharmony_ci vxge_hw_vpath_poll_rx(ring->handle); 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/* 1438c2ecf20Sopenharmony_ci * vxge_callback_link_up 1448c2ecf20Sopenharmony_ci * 1458c2ecf20Sopenharmony_ci * This function is called during interrupt context to notify link up state 1468c2ecf20Sopenharmony_ci * change. 1478c2ecf20Sopenharmony_ci */ 1488c2ecf20Sopenharmony_cistatic void vxge_callback_link_up(struct __vxge_hw_device *hldev) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct net_device *dev = hldev->ndev; 1518c2ecf20Sopenharmony_ci struct vxgedev *vdev = netdev_priv(dev); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", 1548c2ecf20Sopenharmony_ci vdev->ndev->name, __func__, __LINE__); 1558c2ecf20Sopenharmony_ci netdev_notice(vdev->ndev, "Link Up\n"); 1568c2ecf20Sopenharmony_ci vdev->stats.link_up++; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci netif_carrier_on(vdev->ndev); 1598c2ecf20Sopenharmony_ci netif_tx_wake_all_queues(vdev->ndev); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 1628c2ecf20Sopenharmony_ci "%s: %s:%d Exiting...", vdev->ndev->name, __func__, __LINE__); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* 1668c2ecf20Sopenharmony_ci * vxge_callback_link_down 1678c2ecf20Sopenharmony_ci * 1688c2ecf20Sopenharmony_ci * This function is called during interrupt context to notify link down state 1698c2ecf20Sopenharmony_ci * change. 1708c2ecf20Sopenharmony_ci */ 1718c2ecf20Sopenharmony_cistatic void vxge_callback_link_down(struct __vxge_hw_device *hldev) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct net_device *dev = hldev->ndev; 1748c2ecf20Sopenharmony_ci struct vxgedev *vdev = netdev_priv(dev); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 1778c2ecf20Sopenharmony_ci "%s: %s:%d", vdev->ndev->name, __func__, __LINE__); 1788c2ecf20Sopenharmony_ci netdev_notice(vdev->ndev, "Link Down\n"); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci vdev->stats.link_down++; 1818c2ecf20Sopenharmony_ci netif_carrier_off(vdev->ndev); 1828c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(vdev->ndev); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 1858c2ecf20Sopenharmony_ci "%s: %s:%d Exiting...", vdev->ndev->name, __func__, __LINE__); 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci/* 1898c2ecf20Sopenharmony_ci * vxge_rx_alloc 1908c2ecf20Sopenharmony_ci * 1918c2ecf20Sopenharmony_ci * Allocate SKB. 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_cistatic struct sk_buff * 1948c2ecf20Sopenharmony_civxge_rx_alloc(void *dtrh, struct vxge_ring *ring, const int skb_size) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct net_device *dev; 1978c2ecf20Sopenharmony_ci struct sk_buff *skb; 1988c2ecf20Sopenharmony_ci struct vxge_rx_priv *rx_priv; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci dev = ring->ndev; 2018c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", 2028c2ecf20Sopenharmony_ci ring->ndev->name, __func__, __LINE__); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci rx_priv = vxge_hw_ring_rxd_private_get(dtrh); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* try to allocate skb first. this one may fail */ 2078c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(dev, skb_size + 2088c2ecf20Sopenharmony_ci VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN); 2098c2ecf20Sopenharmony_ci if (skb == NULL) { 2108c2ecf20Sopenharmony_ci vxge_debug_mem(VXGE_ERR, 2118c2ecf20Sopenharmony_ci "%s: out of memory to allocate SKB", dev->name); 2128c2ecf20Sopenharmony_ci ring->stats.skb_alloc_fail++; 2138c2ecf20Sopenharmony_ci return NULL; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci vxge_debug_mem(VXGE_TRACE, 2178c2ecf20Sopenharmony_ci "%s: %s:%d Skb : 0x%p", ring->ndev->name, 2188c2ecf20Sopenharmony_ci __func__, __LINE__, skb); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci skb_reserve(skb, VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci rx_priv->skb = skb; 2238c2ecf20Sopenharmony_ci rx_priv->skb_data = NULL; 2248c2ecf20Sopenharmony_ci rx_priv->data_size = skb_size; 2258c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 2268c2ecf20Sopenharmony_ci "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci return skb; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci/* 2328c2ecf20Sopenharmony_ci * vxge_rx_map 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_cistatic int vxge_rx_map(void *dtrh, struct vxge_ring *ring) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct vxge_rx_priv *rx_priv; 2378c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", 2408c2ecf20Sopenharmony_ci ring->ndev->name, __func__, __LINE__); 2418c2ecf20Sopenharmony_ci rx_priv = vxge_hw_ring_rxd_private_get(dtrh); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci rx_priv->skb_data = rx_priv->skb->data; 2448c2ecf20Sopenharmony_ci dma_addr = dma_map_single(&ring->pdev->dev, rx_priv->skb_data, 2458c2ecf20Sopenharmony_ci rx_priv->data_size, DMA_FROM_DEVICE); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(&ring->pdev->dev, dma_addr))) { 2488c2ecf20Sopenharmony_ci ring->stats.pci_map_fail++; 2498c2ecf20Sopenharmony_ci return -EIO; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci vxge_debug_mem(VXGE_TRACE, 2528c2ecf20Sopenharmony_ci "%s: %s:%d 1 buffer mode dma_addr = 0x%llx", 2538c2ecf20Sopenharmony_ci ring->ndev->name, __func__, __LINE__, 2548c2ecf20Sopenharmony_ci (unsigned long long)dma_addr); 2558c2ecf20Sopenharmony_ci vxge_hw_ring_rxd_1b_set(dtrh, dma_addr, rx_priv->data_size); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci rx_priv->data_dma = dma_addr; 2588c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 2598c2ecf20Sopenharmony_ci "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return 0; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci/* 2658c2ecf20Sopenharmony_ci * vxge_rx_initial_replenish 2668c2ecf20Sopenharmony_ci * Allocation of RxD as an initial replenish procedure. 2678c2ecf20Sopenharmony_ci */ 2688c2ecf20Sopenharmony_cistatic enum vxge_hw_status 2698c2ecf20Sopenharmony_civxge_rx_initial_replenish(void *dtrh, void *userdata) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct vxge_ring *ring = (struct vxge_ring *)userdata; 2728c2ecf20Sopenharmony_ci struct vxge_rx_priv *rx_priv; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", 2758c2ecf20Sopenharmony_ci ring->ndev->name, __func__, __LINE__); 2768c2ecf20Sopenharmony_ci if (vxge_rx_alloc(dtrh, ring, 2778c2ecf20Sopenharmony_ci VXGE_LL_MAX_FRAME_SIZE(ring->ndev)) == NULL) 2788c2ecf20Sopenharmony_ci return VXGE_HW_FAIL; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (vxge_rx_map(dtrh, ring)) { 2818c2ecf20Sopenharmony_ci rx_priv = vxge_hw_ring_rxd_private_get(dtrh); 2828c2ecf20Sopenharmony_ci dev_kfree_skb(rx_priv->skb); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci return VXGE_HW_FAIL; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 2878c2ecf20Sopenharmony_ci "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return VXGE_HW_OK; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic inline void 2938c2ecf20Sopenharmony_civxge_rx_complete(struct vxge_ring *ring, struct sk_buff *skb, u16 vlan, 2948c2ecf20Sopenharmony_ci int pkt_length, struct vxge_hw_ring_rxd_info *ext_info) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", 2988c2ecf20Sopenharmony_ci ring->ndev->name, __func__, __LINE__); 2998c2ecf20Sopenharmony_ci skb_record_rx_queue(skb, ring->driver_id); 3008c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, ring->ndev); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci u64_stats_update_begin(&ring->stats.syncp); 3038c2ecf20Sopenharmony_ci ring->stats.rx_frms++; 3048c2ecf20Sopenharmony_ci ring->stats.rx_bytes += pkt_length; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (skb->pkt_type == PACKET_MULTICAST) 3078c2ecf20Sopenharmony_ci ring->stats.rx_mcast++; 3088c2ecf20Sopenharmony_ci u64_stats_update_end(&ring->stats.syncp); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci vxge_debug_rx(VXGE_TRACE, 3118c2ecf20Sopenharmony_ci "%s: %s:%d skb protocol = %d", 3128c2ecf20Sopenharmony_ci ring->ndev->name, __func__, __LINE__, skb->protocol); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (ext_info->vlan && 3158c2ecf20Sopenharmony_ci ring->vlan_tag_strip == VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE) 3168c2ecf20Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ext_info->vlan); 3178c2ecf20Sopenharmony_ci napi_gro_receive(ring->napi_p, skb); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 3208c2ecf20Sopenharmony_ci "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__); 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic inline void vxge_re_pre_post(void *dtr, struct vxge_ring *ring, 3248c2ecf20Sopenharmony_ci struct vxge_rx_priv *rx_priv) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci dma_sync_single_for_device(&ring->pdev->dev, rx_priv->data_dma, 3278c2ecf20Sopenharmony_ci rx_priv->data_size, DMA_FROM_DEVICE); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci vxge_hw_ring_rxd_1b_set(dtr, rx_priv->data_dma, rx_priv->data_size); 3308c2ecf20Sopenharmony_ci vxge_hw_ring_rxd_pre_post(ring->handle, dtr); 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic inline void vxge_post(int *dtr_cnt, void **first_dtr, 3348c2ecf20Sopenharmony_ci void *post_dtr, struct __vxge_hw_ring *ringh) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci int dtr_count = *dtr_cnt; 3378c2ecf20Sopenharmony_ci if ((*dtr_cnt % VXGE_HW_RXSYNC_FREQ_CNT) == 0) { 3388c2ecf20Sopenharmony_ci if (*first_dtr) 3398c2ecf20Sopenharmony_ci vxge_hw_ring_rxd_post_post_wmb(ringh, *first_dtr); 3408c2ecf20Sopenharmony_ci *first_dtr = post_dtr; 3418c2ecf20Sopenharmony_ci } else 3428c2ecf20Sopenharmony_ci vxge_hw_ring_rxd_post_post(ringh, post_dtr); 3438c2ecf20Sopenharmony_ci dtr_count++; 3448c2ecf20Sopenharmony_ci *dtr_cnt = dtr_count; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci/* 3488c2ecf20Sopenharmony_ci * vxge_rx_1b_compl 3498c2ecf20Sopenharmony_ci * 3508c2ecf20Sopenharmony_ci * If the interrupt is because of a received frame or if the receive ring 3518c2ecf20Sopenharmony_ci * contains fresh as yet un-processed frames, this function is called. 3528c2ecf20Sopenharmony_ci */ 3538c2ecf20Sopenharmony_cistatic enum vxge_hw_status 3548c2ecf20Sopenharmony_civxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, 3558c2ecf20Sopenharmony_ci u8 t_code, void *userdata) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci struct vxge_ring *ring = (struct vxge_ring *)userdata; 3588c2ecf20Sopenharmony_ci struct net_device *dev = ring->ndev; 3598c2ecf20Sopenharmony_ci unsigned int dma_sizes; 3608c2ecf20Sopenharmony_ci void *first_dtr = NULL; 3618c2ecf20Sopenharmony_ci int dtr_cnt = 0; 3628c2ecf20Sopenharmony_ci int data_size; 3638c2ecf20Sopenharmony_ci dma_addr_t data_dma; 3648c2ecf20Sopenharmony_ci int pkt_length; 3658c2ecf20Sopenharmony_ci struct sk_buff *skb; 3668c2ecf20Sopenharmony_ci struct vxge_rx_priv *rx_priv; 3678c2ecf20Sopenharmony_ci struct vxge_hw_ring_rxd_info ext_info; 3688c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", 3698c2ecf20Sopenharmony_ci ring->ndev->name, __func__, __LINE__); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (ring->budget <= 0) 3728c2ecf20Sopenharmony_ci goto out; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci do { 3758c2ecf20Sopenharmony_ci prefetch((char *)dtr + L1_CACHE_BYTES); 3768c2ecf20Sopenharmony_ci rx_priv = vxge_hw_ring_rxd_private_get(dtr); 3778c2ecf20Sopenharmony_ci skb = rx_priv->skb; 3788c2ecf20Sopenharmony_ci data_size = rx_priv->data_size; 3798c2ecf20Sopenharmony_ci data_dma = rx_priv->data_dma; 3808c2ecf20Sopenharmony_ci prefetch(rx_priv->skb_data); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci vxge_debug_rx(VXGE_TRACE, 3838c2ecf20Sopenharmony_ci "%s: %s:%d skb = 0x%p", 3848c2ecf20Sopenharmony_ci ring->ndev->name, __func__, __LINE__, skb); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci vxge_hw_ring_rxd_1b_get(ringh, dtr, &dma_sizes); 3878c2ecf20Sopenharmony_ci pkt_length = dma_sizes; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci pkt_length -= ETH_FCS_LEN; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci vxge_debug_rx(VXGE_TRACE, 3928c2ecf20Sopenharmony_ci "%s: %s:%d Packet Length = %d", 3938c2ecf20Sopenharmony_ci ring->ndev->name, __func__, __LINE__, pkt_length); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci vxge_hw_ring_rxd_1b_info_get(ringh, dtr, &ext_info); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* check skb validity */ 3988c2ecf20Sopenharmony_ci vxge_assert(skb); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci prefetch((char *)skb + L1_CACHE_BYTES); 4018c2ecf20Sopenharmony_ci if (unlikely(t_code)) { 4028c2ecf20Sopenharmony_ci if (vxge_hw_ring_handle_tcode(ringh, dtr, t_code) != 4038c2ecf20Sopenharmony_ci VXGE_HW_OK) { 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci ring->stats.rx_errors++; 4068c2ecf20Sopenharmony_ci vxge_debug_rx(VXGE_TRACE, 4078c2ecf20Sopenharmony_ci "%s: %s :%d Rx T_code is %d", 4088c2ecf20Sopenharmony_ci ring->ndev->name, __func__, 4098c2ecf20Sopenharmony_ci __LINE__, t_code); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* If the t_code is not supported and if the 4128c2ecf20Sopenharmony_ci * t_code is other than 0x5 (unparseable packet 4138c2ecf20Sopenharmony_ci * such as unknown UPV6 header), Drop it !!! 4148c2ecf20Sopenharmony_ci */ 4158c2ecf20Sopenharmony_ci vxge_re_pre_post(dtr, ring, rx_priv); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci vxge_post(&dtr_cnt, &first_dtr, dtr, ringh); 4188c2ecf20Sopenharmony_ci ring->stats.rx_dropped++; 4198c2ecf20Sopenharmony_ci continue; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (pkt_length > VXGE_LL_RX_COPY_THRESHOLD) { 4248c2ecf20Sopenharmony_ci if (vxge_rx_alloc(dtr, ring, data_size) != NULL) { 4258c2ecf20Sopenharmony_ci if (!vxge_rx_map(dtr, ring)) { 4268c2ecf20Sopenharmony_ci skb_put(skb, pkt_length); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci dma_unmap_single(&ring->pdev->dev, 4298c2ecf20Sopenharmony_ci data_dma, data_size, 4308c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci vxge_hw_ring_rxd_pre_post(ringh, dtr); 4338c2ecf20Sopenharmony_ci vxge_post(&dtr_cnt, &first_dtr, dtr, 4348c2ecf20Sopenharmony_ci ringh); 4358c2ecf20Sopenharmony_ci } else { 4368c2ecf20Sopenharmony_ci dev_kfree_skb(rx_priv->skb); 4378c2ecf20Sopenharmony_ci rx_priv->skb = skb; 4388c2ecf20Sopenharmony_ci rx_priv->data_size = data_size; 4398c2ecf20Sopenharmony_ci vxge_re_pre_post(dtr, ring, rx_priv); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci vxge_post(&dtr_cnt, &first_dtr, dtr, 4428c2ecf20Sopenharmony_ci ringh); 4438c2ecf20Sopenharmony_ci ring->stats.rx_dropped++; 4448c2ecf20Sopenharmony_ci break; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci } else { 4478c2ecf20Sopenharmony_ci vxge_re_pre_post(dtr, ring, rx_priv); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci vxge_post(&dtr_cnt, &first_dtr, dtr, ringh); 4508c2ecf20Sopenharmony_ci ring->stats.rx_dropped++; 4518c2ecf20Sopenharmony_ci break; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci } else { 4548c2ecf20Sopenharmony_ci struct sk_buff *skb_up; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci skb_up = netdev_alloc_skb(dev, pkt_length + 4578c2ecf20Sopenharmony_ci VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN); 4588c2ecf20Sopenharmony_ci if (skb_up != NULL) { 4598c2ecf20Sopenharmony_ci skb_reserve(skb_up, 4608c2ecf20Sopenharmony_ci VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(&ring->pdev->dev, 4638c2ecf20Sopenharmony_ci data_dma, data_size, 4648c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci vxge_debug_mem(VXGE_TRACE, 4678c2ecf20Sopenharmony_ci "%s: %s:%d skb_up = %p", 4688c2ecf20Sopenharmony_ci ring->ndev->name, __func__, 4698c2ecf20Sopenharmony_ci __LINE__, skb); 4708c2ecf20Sopenharmony_ci memcpy(skb_up->data, skb->data, pkt_length); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci vxge_re_pre_post(dtr, ring, rx_priv); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci vxge_post(&dtr_cnt, &first_dtr, dtr, 4758c2ecf20Sopenharmony_ci ringh); 4768c2ecf20Sopenharmony_ci /* will netif_rx small SKB instead */ 4778c2ecf20Sopenharmony_ci skb = skb_up; 4788c2ecf20Sopenharmony_ci skb_put(skb, pkt_length); 4798c2ecf20Sopenharmony_ci } else { 4808c2ecf20Sopenharmony_ci vxge_re_pre_post(dtr, ring, rx_priv); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci vxge_post(&dtr_cnt, &first_dtr, dtr, ringh); 4838c2ecf20Sopenharmony_ci vxge_debug_rx(VXGE_ERR, 4848c2ecf20Sopenharmony_ci "%s: vxge_rx_1b_compl: out of " 4858c2ecf20Sopenharmony_ci "memory", dev->name); 4868c2ecf20Sopenharmony_ci ring->stats.skb_alloc_fail++; 4878c2ecf20Sopenharmony_ci break; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if ((ext_info.proto & VXGE_HW_FRAME_PROTO_TCP_OR_UDP) && 4928c2ecf20Sopenharmony_ci !(ext_info.proto & VXGE_HW_FRAME_PROTO_IP_FRAG) && 4938c2ecf20Sopenharmony_ci (dev->features & NETIF_F_RXCSUM) && /* Offload Rx side CSUM */ 4948c2ecf20Sopenharmony_ci ext_info.l3_cksum == VXGE_HW_L3_CKSUM_OK && 4958c2ecf20Sopenharmony_ci ext_info.l4_cksum == VXGE_HW_L4_CKSUM_OK) 4968c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 4978c2ecf20Sopenharmony_ci else 4988c2ecf20Sopenharmony_ci skb_checksum_none_assert(skb); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (ring->rx_hwts) { 5028c2ecf20Sopenharmony_ci struct skb_shared_hwtstamps *skb_hwts; 5038c2ecf20Sopenharmony_ci u32 ns = *(u32 *)(skb->head + pkt_length); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci skb_hwts = skb_hwtstamps(skb); 5068c2ecf20Sopenharmony_ci skb_hwts->hwtstamp = ns_to_ktime(ns); 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci /* rth_hash_type and rth_it_hit are non-zero regardless of 5108c2ecf20Sopenharmony_ci * whether rss is enabled. Only the rth_value is zero/non-zero 5118c2ecf20Sopenharmony_ci * if rss is disabled/enabled, so key off of that. 5128c2ecf20Sopenharmony_ci */ 5138c2ecf20Sopenharmony_ci if (ext_info.rth_value) 5148c2ecf20Sopenharmony_ci skb_set_hash(skb, ext_info.rth_value, 5158c2ecf20Sopenharmony_ci PKT_HASH_TYPE_L3); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci vxge_rx_complete(ring, skb, ext_info.vlan, 5188c2ecf20Sopenharmony_ci pkt_length, &ext_info); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci ring->budget--; 5218c2ecf20Sopenharmony_ci ring->pkts_processed++; 5228c2ecf20Sopenharmony_ci if (!ring->budget) 5238c2ecf20Sopenharmony_ci break; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci } while (vxge_hw_ring_rxd_next_completed(ringh, &dtr, 5268c2ecf20Sopenharmony_ci &t_code) == VXGE_HW_OK); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci if (first_dtr) 5298c2ecf20Sopenharmony_ci vxge_hw_ring_rxd_post_post_wmb(ringh, first_dtr); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ciout: 5328c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 5338c2ecf20Sopenharmony_ci "%s:%d Exiting...", 5348c2ecf20Sopenharmony_ci __func__, __LINE__); 5358c2ecf20Sopenharmony_ci return VXGE_HW_OK; 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci/* 5398c2ecf20Sopenharmony_ci * vxge_xmit_compl 5408c2ecf20Sopenharmony_ci * 5418c2ecf20Sopenharmony_ci * If an interrupt was raised to indicate DMA complete of the Tx packet, 5428c2ecf20Sopenharmony_ci * this function is called. It identifies the last TxD whose buffer was 5438c2ecf20Sopenharmony_ci * freed and frees all skbs whose data have already DMA'ed into the NICs 5448c2ecf20Sopenharmony_ci * internal memory. 5458c2ecf20Sopenharmony_ci */ 5468c2ecf20Sopenharmony_cistatic enum vxge_hw_status 5478c2ecf20Sopenharmony_civxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr, 5488c2ecf20Sopenharmony_ci enum vxge_hw_fifo_tcode t_code, void *userdata, 5498c2ecf20Sopenharmony_ci struct sk_buff ***skb_ptr, int nr_skb, int *more) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci struct vxge_fifo *fifo = (struct vxge_fifo *)userdata; 5528c2ecf20Sopenharmony_ci struct sk_buff *skb, **done_skb = *skb_ptr; 5538c2ecf20Sopenharmony_ci int pkt_cnt = 0; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 5568c2ecf20Sopenharmony_ci "%s:%d Entered....", __func__, __LINE__); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci do { 5598c2ecf20Sopenharmony_ci int frg_cnt; 5608c2ecf20Sopenharmony_ci skb_frag_t *frag; 5618c2ecf20Sopenharmony_ci int i = 0, j; 5628c2ecf20Sopenharmony_ci struct vxge_tx_priv *txd_priv = 5638c2ecf20Sopenharmony_ci vxge_hw_fifo_txdl_private_get(dtr); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci skb = txd_priv->skb; 5668c2ecf20Sopenharmony_ci frg_cnt = skb_shinfo(skb)->nr_frags; 5678c2ecf20Sopenharmony_ci frag = &skb_shinfo(skb)->frags[0]; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci vxge_debug_tx(VXGE_TRACE, 5708c2ecf20Sopenharmony_ci "%s: %s:%d fifo_hw = %p dtr = %p " 5718c2ecf20Sopenharmony_ci "tcode = 0x%x", fifo->ndev->name, __func__, 5728c2ecf20Sopenharmony_ci __LINE__, fifo_hw, dtr, t_code); 5738c2ecf20Sopenharmony_ci /* check skb validity */ 5748c2ecf20Sopenharmony_ci vxge_assert(skb); 5758c2ecf20Sopenharmony_ci vxge_debug_tx(VXGE_TRACE, 5768c2ecf20Sopenharmony_ci "%s: %s:%d skb = %p itxd_priv = %p frg_cnt = %d", 5778c2ecf20Sopenharmony_ci fifo->ndev->name, __func__, __LINE__, 5788c2ecf20Sopenharmony_ci skb, txd_priv, frg_cnt); 5798c2ecf20Sopenharmony_ci if (unlikely(t_code)) { 5808c2ecf20Sopenharmony_ci fifo->stats.tx_errors++; 5818c2ecf20Sopenharmony_ci vxge_debug_tx(VXGE_ERR, 5828c2ecf20Sopenharmony_ci "%s: tx: dtr %p completed due to " 5838c2ecf20Sopenharmony_ci "error t_code %01x", fifo->ndev->name, 5848c2ecf20Sopenharmony_ci dtr, t_code); 5858c2ecf20Sopenharmony_ci vxge_hw_fifo_handle_tcode(fifo_hw, dtr, t_code); 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* for unfragmented skb */ 5898c2ecf20Sopenharmony_ci dma_unmap_single(&fifo->pdev->dev, txd_priv->dma_buffers[i++], 5908c2ecf20Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci for (j = 0; j < frg_cnt; j++) { 5938c2ecf20Sopenharmony_ci dma_unmap_page(&fifo->pdev->dev, 5948c2ecf20Sopenharmony_ci txd_priv->dma_buffers[i++], 5958c2ecf20Sopenharmony_ci skb_frag_size(frag), DMA_TO_DEVICE); 5968c2ecf20Sopenharmony_ci frag += 1; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci vxge_hw_fifo_txdl_free(fifo_hw, dtr); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci /* Updating the statistics block */ 6028c2ecf20Sopenharmony_ci u64_stats_update_begin(&fifo->stats.syncp); 6038c2ecf20Sopenharmony_ci fifo->stats.tx_frms++; 6048c2ecf20Sopenharmony_ci fifo->stats.tx_bytes += skb->len; 6058c2ecf20Sopenharmony_ci u64_stats_update_end(&fifo->stats.syncp); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci *done_skb++ = skb; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (--nr_skb <= 0) { 6108c2ecf20Sopenharmony_ci *more = 1; 6118c2ecf20Sopenharmony_ci break; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci pkt_cnt++; 6158c2ecf20Sopenharmony_ci if (pkt_cnt > fifo->indicate_max_pkts) 6168c2ecf20Sopenharmony_ci break; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci } while (vxge_hw_fifo_txdl_next_completed(fifo_hw, 6198c2ecf20Sopenharmony_ci &dtr, &t_code) == VXGE_HW_OK); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci *skb_ptr = done_skb; 6228c2ecf20Sopenharmony_ci if (netif_tx_queue_stopped(fifo->txq)) 6238c2ecf20Sopenharmony_ci netif_tx_wake_queue(fifo->txq); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 6268c2ecf20Sopenharmony_ci "%s: %s:%d Exiting...", 6278c2ecf20Sopenharmony_ci fifo->ndev->name, __func__, __LINE__); 6288c2ecf20Sopenharmony_ci return VXGE_HW_OK; 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci/* select a vpath to transmit the packet */ 6328c2ecf20Sopenharmony_cistatic u32 vxge_get_vpath_no(struct vxgedev *vdev, struct sk_buff *skb) 6338c2ecf20Sopenharmony_ci{ 6348c2ecf20Sopenharmony_ci u16 queue_len, counter = 0; 6358c2ecf20Sopenharmony_ci if (skb->protocol == htons(ETH_P_IP)) { 6368c2ecf20Sopenharmony_ci struct iphdr *ip; 6378c2ecf20Sopenharmony_ci struct tcphdr *th; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci ip = ip_hdr(skb); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (!ip_is_fragment(ip)) { 6428c2ecf20Sopenharmony_ci th = (struct tcphdr *)(((unsigned char *)ip) + 6438c2ecf20Sopenharmony_ci ip->ihl*4); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci queue_len = vdev->no_of_vpath; 6468c2ecf20Sopenharmony_ci counter = (ntohs(th->source) + 6478c2ecf20Sopenharmony_ci ntohs(th->dest)) & 6488c2ecf20Sopenharmony_ci vdev->vpath_selector[queue_len - 1]; 6498c2ecf20Sopenharmony_ci if (counter >= queue_len) 6508c2ecf20Sopenharmony_ci counter = queue_len - 1; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci return counter; 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic enum vxge_hw_status vxge_search_mac_addr_in_list( 6578c2ecf20Sopenharmony_ci struct vxge_vpath *vpath, u64 del_mac) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci struct list_head *entry, *next; 6608c2ecf20Sopenharmony_ci list_for_each_safe(entry, next, &vpath->mac_addr_list) { 6618c2ecf20Sopenharmony_ci if (((struct vxge_mac_addrs *)entry)->macaddr == del_mac) 6628c2ecf20Sopenharmony_ci return TRUE; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci return FALSE; 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistatic int vxge_mac_list_add(struct vxge_vpath *vpath, struct macInfo *mac) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci struct vxge_mac_addrs *new_mac_entry; 6708c2ecf20Sopenharmony_ci u8 *mac_address = NULL; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci if (vpath->mac_addr_cnt >= VXGE_MAX_LEARN_MAC_ADDR_CNT) 6738c2ecf20Sopenharmony_ci return TRUE; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci new_mac_entry = kzalloc(sizeof(struct vxge_mac_addrs), GFP_ATOMIC); 6768c2ecf20Sopenharmony_ci if (!new_mac_entry) { 6778c2ecf20Sopenharmony_ci vxge_debug_mem(VXGE_ERR, 6788c2ecf20Sopenharmony_ci "%s: memory allocation failed", 6798c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME); 6808c2ecf20Sopenharmony_ci return FALSE; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci list_add(&new_mac_entry->item, &vpath->mac_addr_list); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci /* Copy the new mac address to the list */ 6868c2ecf20Sopenharmony_ci mac_address = (u8 *)&new_mac_entry->macaddr; 6878c2ecf20Sopenharmony_ci memcpy(mac_address, mac->macaddr, ETH_ALEN); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci new_mac_entry->state = mac->state; 6908c2ecf20Sopenharmony_ci vpath->mac_addr_cnt++; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(mac->macaddr)) 6938c2ecf20Sopenharmony_ci vpath->mcast_addr_cnt++; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci return TRUE; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci/* Add a mac address to DA table */ 6998c2ecf20Sopenharmony_cistatic enum vxge_hw_status 7008c2ecf20Sopenharmony_civxge_add_mac_addr(struct vxgedev *vdev, struct macInfo *mac) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci enum vxge_hw_status status = VXGE_HW_OK; 7038c2ecf20Sopenharmony_ci struct vxge_vpath *vpath; 7048c2ecf20Sopenharmony_ci enum vxge_hw_vpath_mac_addr_add_mode duplicate_mode; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(mac->macaddr)) 7078c2ecf20Sopenharmony_ci duplicate_mode = VXGE_HW_VPATH_MAC_ADDR_ADD_DUPLICATE; 7088c2ecf20Sopenharmony_ci else 7098c2ecf20Sopenharmony_ci duplicate_mode = VXGE_HW_VPATH_MAC_ADDR_REPLACE_DUPLICATE; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[mac->vpath_no]; 7128c2ecf20Sopenharmony_ci status = vxge_hw_vpath_mac_addr_add(vpath->handle, mac->macaddr, 7138c2ecf20Sopenharmony_ci mac->macmask, duplicate_mode); 7148c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 7158c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 7168c2ecf20Sopenharmony_ci "DA config add entry failed for vpath:%d", 7178c2ecf20Sopenharmony_ci vpath->device_id); 7188c2ecf20Sopenharmony_ci } else 7198c2ecf20Sopenharmony_ci if (FALSE == vxge_mac_list_add(vpath, mac)) 7208c2ecf20Sopenharmony_ci status = -EPERM; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci return status; 7238c2ecf20Sopenharmony_ci} 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_cistatic int vxge_learn_mac(struct vxgedev *vdev, u8 *mac_header) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci struct macInfo mac_info; 7288c2ecf20Sopenharmony_ci u8 *mac_address = NULL; 7298c2ecf20Sopenharmony_ci u64 mac_addr = 0, vpath_vector = 0; 7308c2ecf20Sopenharmony_ci int vpath_idx = 0; 7318c2ecf20Sopenharmony_ci enum vxge_hw_status status = VXGE_HW_OK; 7328c2ecf20Sopenharmony_ci struct vxge_vpath *vpath = NULL; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci mac_address = (u8 *)&mac_addr; 7358c2ecf20Sopenharmony_ci memcpy(mac_address, mac_header, ETH_ALEN); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci /* Is this mac address already in the list? */ 7388c2ecf20Sopenharmony_ci for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) { 7398c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[vpath_idx]; 7408c2ecf20Sopenharmony_ci if (vxge_search_mac_addr_in_list(vpath, mac_addr)) 7418c2ecf20Sopenharmony_ci return vpath_idx; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci memset(&mac_info, 0, sizeof(struct macInfo)); 7458c2ecf20Sopenharmony_ci memcpy(mac_info.macaddr, mac_header, ETH_ALEN); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci /* Any vpath has room to add mac address to its da table? */ 7488c2ecf20Sopenharmony_ci for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) { 7498c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[vpath_idx]; 7508c2ecf20Sopenharmony_ci if (vpath->mac_addr_cnt < vpath->max_mac_addr_cnt) { 7518c2ecf20Sopenharmony_ci /* Add this mac address to this vpath */ 7528c2ecf20Sopenharmony_ci mac_info.vpath_no = vpath_idx; 7538c2ecf20Sopenharmony_ci mac_info.state = VXGE_LL_MAC_ADDR_IN_DA_TABLE; 7548c2ecf20Sopenharmony_ci status = vxge_add_mac_addr(vdev, &mac_info); 7558c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) 7568c2ecf20Sopenharmony_ci return -EPERM; 7578c2ecf20Sopenharmony_ci return vpath_idx; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci mac_info.state = VXGE_LL_MAC_ADDR_IN_LIST; 7628c2ecf20Sopenharmony_ci vpath_idx = 0; 7638c2ecf20Sopenharmony_ci mac_info.vpath_no = vpath_idx; 7648c2ecf20Sopenharmony_ci /* Is the first vpath already selected as catch-basin ? */ 7658c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[vpath_idx]; 7668c2ecf20Sopenharmony_ci if (vpath->mac_addr_cnt > vpath->max_mac_addr_cnt) { 7678c2ecf20Sopenharmony_ci /* Add this mac address to this vpath */ 7688c2ecf20Sopenharmony_ci if (FALSE == vxge_mac_list_add(vpath, &mac_info)) 7698c2ecf20Sopenharmony_ci return -EPERM; 7708c2ecf20Sopenharmony_ci return vpath_idx; 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci /* Select first vpath as catch-basin */ 7748c2ecf20Sopenharmony_ci vpath_vector = vxge_mBIT(vpath->device_id); 7758c2ecf20Sopenharmony_ci status = vxge_hw_mgmt_reg_write(vpath->vdev->devh, 7768c2ecf20Sopenharmony_ci vxge_hw_mgmt_reg_type_mrpcim, 7778c2ecf20Sopenharmony_ci 0, 7788c2ecf20Sopenharmony_ci (ulong)offsetof( 7798c2ecf20Sopenharmony_ci struct vxge_hw_mrpcim_reg, 7808c2ecf20Sopenharmony_ci rts_mgr_cbasin_cfg), 7818c2ecf20Sopenharmony_ci vpath_vector); 7828c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 7838c2ecf20Sopenharmony_ci vxge_debug_tx(VXGE_ERR, 7848c2ecf20Sopenharmony_ci "%s: Unable to set the vpath-%d in catch-basin mode", 7858c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME, vpath->device_id); 7868c2ecf20Sopenharmony_ci return -EPERM; 7878c2ecf20Sopenharmony_ci } 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (FALSE == vxge_mac_list_add(vpath, &mac_info)) 7908c2ecf20Sopenharmony_ci return -EPERM; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci return vpath_idx; 7938c2ecf20Sopenharmony_ci} 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci/** 7968c2ecf20Sopenharmony_ci * vxge_xmit 7978c2ecf20Sopenharmony_ci * @skb : the socket buffer containing the Tx data. 7988c2ecf20Sopenharmony_ci * @dev : device pointer. 7998c2ecf20Sopenharmony_ci * 8008c2ecf20Sopenharmony_ci * This function is the Tx entry point of the driver. Neterion NIC supports 8018c2ecf20Sopenharmony_ci * certain protocol assist features on Tx side, namely CSO, S/G, LSO. 8028c2ecf20Sopenharmony_ci*/ 8038c2ecf20Sopenharmony_cistatic netdev_tx_t 8048c2ecf20Sopenharmony_civxge_xmit(struct sk_buff *skb, struct net_device *dev) 8058c2ecf20Sopenharmony_ci{ 8068c2ecf20Sopenharmony_ci struct vxge_fifo *fifo = NULL; 8078c2ecf20Sopenharmony_ci void *dtr_priv; 8088c2ecf20Sopenharmony_ci void *dtr = NULL; 8098c2ecf20Sopenharmony_ci struct vxgedev *vdev = NULL; 8108c2ecf20Sopenharmony_ci enum vxge_hw_status status; 8118c2ecf20Sopenharmony_ci int frg_cnt, first_frg_len; 8128c2ecf20Sopenharmony_ci skb_frag_t *frag; 8138c2ecf20Sopenharmony_ci int i = 0, j = 0, avail; 8148c2ecf20Sopenharmony_ci u64 dma_pointer; 8158c2ecf20Sopenharmony_ci struct vxge_tx_priv *txdl_priv = NULL; 8168c2ecf20Sopenharmony_ci struct __vxge_hw_fifo *fifo_hw; 8178c2ecf20Sopenharmony_ci int offload_type; 8188c2ecf20Sopenharmony_ci int vpath_no = 0; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", 8218c2ecf20Sopenharmony_ci dev->name, __func__, __LINE__); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci /* A buffer with no data will be dropped */ 8248c2ecf20Sopenharmony_ci if (unlikely(skb->len <= 0)) { 8258c2ecf20Sopenharmony_ci vxge_debug_tx(VXGE_ERR, 8268c2ecf20Sopenharmony_ci "%s: Buffer has no data..", dev->name); 8278c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 8288c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci vdev = netdev_priv(dev); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci if (unlikely(!is_vxge_card_up(vdev))) { 8348c2ecf20Sopenharmony_ci vxge_debug_tx(VXGE_ERR, 8358c2ecf20Sopenharmony_ci "%s: vdev not initialized", dev->name); 8368c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 8378c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci if (vdev->config.addr_learn_en) { 8418c2ecf20Sopenharmony_ci vpath_no = vxge_learn_mac(vdev, skb->data + ETH_ALEN); 8428c2ecf20Sopenharmony_ci if (vpath_no == -EPERM) { 8438c2ecf20Sopenharmony_ci vxge_debug_tx(VXGE_ERR, 8448c2ecf20Sopenharmony_ci "%s: Failed to store the mac address", 8458c2ecf20Sopenharmony_ci dev->name); 8468c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 8478c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if (vdev->config.tx_steering_type == TX_MULTIQ_STEERING) 8528c2ecf20Sopenharmony_ci vpath_no = skb_get_queue_mapping(skb); 8538c2ecf20Sopenharmony_ci else if (vdev->config.tx_steering_type == TX_PORT_STEERING) 8548c2ecf20Sopenharmony_ci vpath_no = vxge_get_vpath_no(vdev, skb); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci vxge_debug_tx(VXGE_TRACE, "%s: vpath_no= %d", dev->name, vpath_no); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci if (vpath_no >= vdev->no_of_vpath) 8598c2ecf20Sopenharmony_ci vpath_no = 0; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci fifo = &vdev->vpaths[vpath_no].fifo; 8628c2ecf20Sopenharmony_ci fifo_hw = fifo->handle; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci if (netif_tx_queue_stopped(fifo->txq)) 8658c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci avail = vxge_hw_fifo_free_txdl_count_get(fifo_hw); 8688c2ecf20Sopenharmony_ci if (avail == 0) { 8698c2ecf20Sopenharmony_ci vxge_debug_tx(VXGE_ERR, 8708c2ecf20Sopenharmony_ci "%s: No free TXDs available", dev->name); 8718c2ecf20Sopenharmony_ci fifo->stats.txd_not_free++; 8728c2ecf20Sopenharmony_ci goto _exit0; 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci /* Last TXD? Stop tx queue to avoid dropping packets. TX 8768c2ecf20Sopenharmony_ci * completion will resume the queue. 8778c2ecf20Sopenharmony_ci */ 8788c2ecf20Sopenharmony_ci if (avail == 1) 8798c2ecf20Sopenharmony_ci netif_tx_stop_queue(fifo->txq); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci status = vxge_hw_fifo_txdl_reserve(fifo_hw, &dtr, &dtr_priv); 8828c2ecf20Sopenharmony_ci if (unlikely(status != VXGE_HW_OK)) { 8838c2ecf20Sopenharmony_ci vxge_debug_tx(VXGE_ERR, 8848c2ecf20Sopenharmony_ci "%s: Out of descriptors .", dev->name); 8858c2ecf20Sopenharmony_ci fifo->stats.txd_out_of_desc++; 8868c2ecf20Sopenharmony_ci goto _exit0; 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci vxge_debug_tx(VXGE_TRACE, 8908c2ecf20Sopenharmony_ci "%s: %s:%d fifo_hw = %p dtr = %p dtr_priv = %p", 8918c2ecf20Sopenharmony_ci dev->name, __func__, __LINE__, 8928c2ecf20Sopenharmony_ci fifo_hw, dtr, dtr_priv); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 8958c2ecf20Sopenharmony_ci u16 vlan_tag = skb_vlan_tag_get(skb); 8968c2ecf20Sopenharmony_ci vxge_hw_fifo_txdl_vlan_set(dtr, vlan_tag); 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci first_frg_len = skb_headlen(skb); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci dma_pointer = dma_map_single(&fifo->pdev->dev, skb->data, 9028c2ecf20Sopenharmony_ci first_frg_len, DMA_TO_DEVICE); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(&fifo->pdev->dev, dma_pointer))) { 9058c2ecf20Sopenharmony_ci vxge_hw_fifo_txdl_free(fifo_hw, dtr); 9068c2ecf20Sopenharmony_ci fifo->stats.pci_map_fail++; 9078c2ecf20Sopenharmony_ci goto _exit0; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci txdl_priv = vxge_hw_fifo_txdl_private_get(dtr); 9118c2ecf20Sopenharmony_ci txdl_priv->skb = skb; 9128c2ecf20Sopenharmony_ci txdl_priv->dma_buffers[j] = dma_pointer; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci frg_cnt = skb_shinfo(skb)->nr_frags; 9158c2ecf20Sopenharmony_ci vxge_debug_tx(VXGE_TRACE, 9168c2ecf20Sopenharmony_ci "%s: %s:%d skb = %p txdl_priv = %p " 9178c2ecf20Sopenharmony_ci "frag_cnt = %d dma_pointer = 0x%llx", dev->name, 9188c2ecf20Sopenharmony_ci __func__, __LINE__, skb, txdl_priv, 9198c2ecf20Sopenharmony_ci frg_cnt, (unsigned long long)dma_pointer); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci vxge_hw_fifo_txdl_buffer_set(fifo_hw, dtr, j++, dma_pointer, 9228c2ecf20Sopenharmony_ci first_frg_len); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci frag = &skb_shinfo(skb)->frags[0]; 9258c2ecf20Sopenharmony_ci for (i = 0; i < frg_cnt; i++) { 9268c2ecf20Sopenharmony_ci /* ignore 0 length fragment */ 9278c2ecf20Sopenharmony_ci if (!skb_frag_size(frag)) 9288c2ecf20Sopenharmony_ci continue; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci dma_pointer = (u64)skb_frag_dma_map(&fifo->pdev->dev, frag, 9318c2ecf20Sopenharmony_ci 0, skb_frag_size(frag), 9328c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(&fifo->pdev->dev, dma_pointer))) 9358c2ecf20Sopenharmony_ci goto _exit2; 9368c2ecf20Sopenharmony_ci vxge_debug_tx(VXGE_TRACE, 9378c2ecf20Sopenharmony_ci "%s: %s:%d frag = %d dma_pointer = 0x%llx", 9388c2ecf20Sopenharmony_ci dev->name, __func__, __LINE__, i, 9398c2ecf20Sopenharmony_ci (unsigned long long)dma_pointer); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci txdl_priv->dma_buffers[j] = dma_pointer; 9428c2ecf20Sopenharmony_ci vxge_hw_fifo_txdl_buffer_set(fifo_hw, dtr, j++, dma_pointer, 9438c2ecf20Sopenharmony_ci skb_frag_size(frag)); 9448c2ecf20Sopenharmony_ci frag += 1; 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci offload_type = vxge_offload_type(skb); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) { 9508c2ecf20Sopenharmony_ci int mss = vxge_tcp_mss(skb); 9518c2ecf20Sopenharmony_ci if (mss) { 9528c2ecf20Sopenharmony_ci vxge_debug_tx(VXGE_TRACE, "%s: %s:%d mss = %d", 9538c2ecf20Sopenharmony_ci dev->name, __func__, __LINE__, mss); 9548c2ecf20Sopenharmony_ci vxge_hw_fifo_txdl_mss_set(dtr, mss); 9558c2ecf20Sopenharmony_ci } else { 9568c2ecf20Sopenharmony_ci vxge_assert(skb->len <= 9578c2ecf20Sopenharmony_ci dev->mtu + VXGE_HW_MAC_HEADER_MAX_SIZE); 9588c2ecf20Sopenharmony_ci vxge_assert(0); 9598c2ecf20Sopenharmony_ci goto _exit1; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) 9648c2ecf20Sopenharmony_ci vxge_hw_fifo_txdl_cksum_set_bits(dtr, 9658c2ecf20Sopenharmony_ci VXGE_HW_FIFO_TXD_TX_CKO_IPV4_EN | 9668c2ecf20Sopenharmony_ci VXGE_HW_FIFO_TXD_TX_CKO_TCP_EN | 9678c2ecf20Sopenharmony_ci VXGE_HW_FIFO_TXD_TX_CKO_UDP_EN); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci vxge_hw_fifo_txdl_post(fifo_hw, dtr); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", 9728c2ecf20Sopenharmony_ci dev->name, __func__, __LINE__); 9738c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci_exit2: 9768c2ecf20Sopenharmony_ci vxge_debug_tx(VXGE_TRACE, "%s: pci_map_page failed", dev->name); 9778c2ecf20Sopenharmony_ci_exit1: 9788c2ecf20Sopenharmony_ci j = 0; 9798c2ecf20Sopenharmony_ci frag = &skb_shinfo(skb)->frags[0]; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci dma_unmap_single(&fifo->pdev->dev, txdl_priv->dma_buffers[j++], 9828c2ecf20Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci for (; j < i; j++) { 9858c2ecf20Sopenharmony_ci dma_unmap_page(&fifo->pdev->dev, txdl_priv->dma_buffers[j], 9868c2ecf20Sopenharmony_ci skb_frag_size(frag), DMA_TO_DEVICE); 9878c2ecf20Sopenharmony_ci frag += 1; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci vxge_hw_fifo_txdl_free(fifo_hw, dtr); 9918c2ecf20Sopenharmony_ci_exit0: 9928c2ecf20Sopenharmony_ci netif_tx_stop_queue(fifo->txq); 9938c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci/* 9998c2ecf20Sopenharmony_ci * vxge_rx_term 10008c2ecf20Sopenharmony_ci * 10018c2ecf20Sopenharmony_ci * Function will be called by hw function to abort all outstanding receive 10028c2ecf20Sopenharmony_ci * descriptors. 10038c2ecf20Sopenharmony_ci */ 10048c2ecf20Sopenharmony_cistatic void 10058c2ecf20Sopenharmony_civxge_rx_term(void *dtrh, enum vxge_hw_rxd_state state, void *userdata) 10068c2ecf20Sopenharmony_ci{ 10078c2ecf20Sopenharmony_ci struct vxge_ring *ring = (struct vxge_ring *)userdata; 10088c2ecf20Sopenharmony_ci struct vxge_rx_priv *rx_priv = 10098c2ecf20Sopenharmony_ci vxge_hw_ring_rxd_private_get(dtrh); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", 10128c2ecf20Sopenharmony_ci ring->ndev->name, __func__, __LINE__); 10138c2ecf20Sopenharmony_ci if (state != VXGE_HW_RXD_STATE_POSTED) 10148c2ecf20Sopenharmony_ci return; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci dma_unmap_single(&ring->pdev->dev, rx_priv->data_dma, 10178c2ecf20Sopenharmony_ci rx_priv->data_size, DMA_FROM_DEVICE); 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci dev_kfree_skb(rx_priv->skb); 10208c2ecf20Sopenharmony_ci rx_priv->skb_data = NULL; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 10238c2ecf20Sopenharmony_ci "%s: %s:%d Exiting...", 10248c2ecf20Sopenharmony_ci ring->ndev->name, __func__, __LINE__); 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci/* 10288c2ecf20Sopenharmony_ci * vxge_tx_term 10298c2ecf20Sopenharmony_ci * 10308c2ecf20Sopenharmony_ci * Function will be called to abort all outstanding tx descriptors 10318c2ecf20Sopenharmony_ci */ 10328c2ecf20Sopenharmony_cistatic void 10338c2ecf20Sopenharmony_civxge_tx_term(void *dtrh, enum vxge_hw_txdl_state state, void *userdata) 10348c2ecf20Sopenharmony_ci{ 10358c2ecf20Sopenharmony_ci struct vxge_fifo *fifo = (struct vxge_fifo *)userdata; 10368c2ecf20Sopenharmony_ci skb_frag_t *frag; 10378c2ecf20Sopenharmony_ci int i = 0, j, frg_cnt; 10388c2ecf20Sopenharmony_ci struct vxge_tx_priv *txd_priv = vxge_hw_fifo_txdl_private_get(dtrh); 10398c2ecf20Sopenharmony_ci struct sk_buff *skb = txd_priv->skb; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci if (state != VXGE_HW_TXDL_STATE_POSTED) 10448c2ecf20Sopenharmony_ci return; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci /* check skb validity */ 10478c2ecf20Sopenharmony_ci vxge_assert(skb); 10488c2ecf20Sopenharmony_ci frg_cnt = skb_shinfo(skb)->nr_frags; 10498c2ecf20Sopenharmony_ci frag = &skb_shinfo(skb)->frags[0]; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci /* for unfragmented skb */ 10528c2ecf20Sopenharmony_ci dma_unmap_single(&fifo->pdev->dev, txd_priv->dma_buffers[i++], 10538c2ecf20Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci for (j = 0; j < frg_cnt; j++) { 10568c2ecf20Sopenharmony_ci dma_unmap_page(&fifo->pdev->dev, txd_priv->dma_buffers[i++], 10578c2ecf20Sopenharmony_ci skb_frag_size(frag), DMA_TO_DEVICE); 10588c2ecf20Sopenharmony_ci frag += 1; 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 10648c2ecf20Sopenharmony_ci "%s:%d Exiting...", __func__, __LINE__); 10658c2ecf20Sopenharmony_ci} 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_cistatic int vxge_mac_list_del(struct vxge_vpath *vpath, struct macInfo *mac) 10688c2ecf20Sopenharmony_ci{ 10698c2ecf20Sopenharmony_ci struct list_head *entry, *next; 10708c2ecf20Sopenharmony_ci u64 del_mac = 0; 10718c2ecf20Sopenharmony_ci u8 *mac_address = (u8 *) (&del_mac); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci /* Copy the mac address to delete from the list */ 10748c2ecf20Sopenharmony_ci memcpy(mac_address, mac->macaddr, ETH_ALEN); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci list_for_each_safe(entry, next, &vpath->mac_addr_list) { 10778c2ecf20Sopenharmony_ci if (((struct vxge_mac_addrs *)entry)->macaddr == del_mac) { 10788c2ecf20Sopenharmony_ci list_del(entry); 10798c2ecf20Sopenharmony_ci kfree(entry); 10808c2ecf20Sopenharmony_ci vpath->mac_addr_cnt--; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(mac->macaddr)) 10838c2ecf20Sopenharmony_ci vpath->mcast_addr_cnt--; 10848c2ecf20Sopenharmony_ci return TRUE; 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci return FALSE; 10898c2ecf20Sopenharmony_ci} 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci/* delete a mac address from DA table */ 10928c2ecf20Sopenharmony_cistatic enum vxge_hw_status 10938c2ecf20Sopenharmony_civxge_del_mac_addr(struct vxgedev *vdev, struct macInfo *mac) 10948c2ecf20Sopenharmony_ci{ 10958c2ecf20Sopenharmony_ci enum vxge_hw_status status = VXGE_HW_OK; 10968c2ecf20Sopenharmony_ci struct vxge_vpath *vpath; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[mac->vpath_no]; 10998c2ecf20Sopenharmony_ci status = vxge_hw_vpath_mac_addr_delete(vpath->handle, mac->macaddr, 11008c2ecf20Sopenharmony_ci mac->macmask); 11018c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 11028c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 11038c2ecf20Sopenharmony_ci "DA config delete entry failed for vpath:%d", 11048c2ecf20Sopenharmony_ci vpath->device_id); 11058c2ecf20Sopenharmony_ci } else 11068c2ecf20Sopenharmony_ci vxge_mac_list_del(vpath, mac); 11078c2ecf20Sopenharmony_ci return status; 11088c2ecf20Sopenharmony_ci} 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci/** 11118c2ecf20Sopenharmony_ci * vxge_set_multicast 11128c2ecf20Sopenharmony_ci * @dev: pointer to the device structure 11138c2ecf20Sopenharmony_ci * 11148c2ecf20Sopenharmony_ci * Entry point for multicast address enable/disable 11158c2ecf20Sopenharmony_ci * This function is a driver entry point which gets called by the kernel 11168c2ecf20Sopenharmony_ci * whenever multicast addresses must be enabled/disabled. This also gets 11178c2ecf20Sopenharmony_ci * called to set/reset promiscuous mode. Depending on the deivce flag, we 11188c2ecf20Sopenharmony_ci * determine, if multicast address must be enabled or if promiscuous mode 11198c2ecf20Sopenharmony_ci * is to be disabled etc. 11208c2ecf20Sopenharmony_ci */ 11218c2ecf20Sopenharmony_cistatic void vxge_set_multicast(struct net_device *dev) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 11248c2ecf20Sopenharmony_ci struct vxgedev *vdev; 11258c2ecf20Sopenharmony_ci int i, mcast_cnt = 0; 11268c2ecf20Sopenharmony_ci struct vxge_vpath *vpath; 11278c2ecf20Sopenharmony_ci enum vxge_hw_status status = VXGE_HW_OK; 11288c2ecf20Sopenharmony_ci struct macInfo mac_info; 11298c2ecf20Sopenharmony_ci int vpath_idx = 0; 11308c2ecf20Sopenharmony_ci struct vxge_mac_addrs *mac_entry; 11318c2ecf20Sopenharmony_ci struct list_head *list_head; 11328c2ecf20Sopenharmony_ci struct list_head *entry, *next; 11338c2ecf20Sopenharmony_ci u8 *mac_address = NULL; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 11368c2ecf20Sopenharmony_ci "%s:%d", __func__, __LINE__); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci vdev = netdev_priv(dev); 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci if (unlikely(!is_vxge_card_up(vdev))) 11418c2ecf20Sopenharmony_ci return; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci if ((dev->flags & IFF_ALLMULTI) && (!vdev->all_multi_flg)) { 11448c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 11458c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[i]; 11468c2ecf20Sopenharmony_ci vxge_assert(vpath->is_open); 11478c2ecf20Sopenharmony_ci status = vxge_hw_vpath_mcast_enable(vpath->handle); 11488c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) 11498c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, "failed to enable " 11508c2ecf20Sopenharmony_ci "multicast, status %d", status); 11518c2ecf20Sopenharmony_ci vdev->all_multi_flg = 1; 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci } else if (!(dev->flags & IFF_ALLMULTI) && (vdev->all_multi_flg)) { 11548c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 11558c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[i]; 11568c2ecf20Sopenharmony_ci vxge_assert(vpath->is_open); 11578c2ecf20Sopenharmony_ci status = vxge_hw_vpath_mcast_disable(vpath->handle); 11588c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) 11598c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, "failed to disable " 11608c2ecf20Sopenharmony_ci "multicast, status %d", status); 11618c2ecf20Sopenharmony_ci vdev->all_multi_flg = 0; 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci if (!vdev->config.addr_learn_en) { 11678c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 11688c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[i]; 11698c2ecf20Sopenharmony_ci vxge_assert(vpath->is_open); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci if (dev->flags & IFF_PROMISC) 11728c2ecf20Sopenharmony_ci status = vxge_hw_vpath_promisc_enable( 11738c2ecf20Sopenharmony_ci vpath->handle); 11748c2ecf20Sopenharmony_ci else 11758c2ecf20Sopenharmony_ci status = vxge_hw_vpath_promisc_disable( 11768c2ecf20Sopenharmony_ci vpath->handle); 11778c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) 11788c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, "failed to %s promisc" 11798c2ecf20Sopenharmony_ci ", status %d", dev->flags&IFF_PROMISC ? 11808c2ecf20Sopenharmony_ci "enable" : "disable", status); 11818c2ecf20Sopenharmony_ci } 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci memset(&mac_info, 0, sizeof(struct macInfo)); 11858c2ecf20Sopenharmony_ci /* Update individual M_CAST address list */ 11868c2ecf20Sopenharmony_ci if ((!vdev->all_multi_flg) && netdev_mc_count(dev)) { 11878c2ecf20Sopenharmony_ci mcast_cnt = vdev->vpaths[0].mcast_addr_cnt; 11888c2ecf20Sopenharmony_ci list_head = &vdev->vpaths[0].mac_addr_list; 11898c2ecf20Sopenharmony_ci if ((netdev_mc_count(dev) + 11908c2ecf20Sopenharmony_ci (vdev->vpaths[0].mac_addr_cnt - mcast_cnt)) > 11918c2ecf20Sopenharmony_ci vdev->vpaths[0].max_mac_addr_cnt) 11928c2ecf20Sopenharmony_ci goto _set_all_mcast; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci /* Delete previous MC's */ 11958c2ecf20Sopenharmony_ci for (i = 0; i < mcast_cnt; i++) { 11968c2ecf20Sopenharmony_ci list_for_each_safe(entry, next, list_head) { 11978c2ecf20Sopenharmony_ci mac_entry = (struct vxge_mac_addrs *)entry; 11988c2ecf20Sopenharmony_ci /* Copy the mac address to delete */ 11998c2ecf20Sopenharmony_ci mac_address = (u8 *)&mac_entry->macaddr; 12008c2ecf20Sopenharmony_ci memcpy(mac_info.macaddr, mac_address, ETH_ALEN); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(mac_info.macaddr)) { 12038c2ecf20Sopenharmony_ci for (vpath_idx = 0; vpath_idx < 12048c2ecf20Sopenharmony_ci vdev->no_of_vpath; 12058c2ecf20Sopenharmony_ci vpath_idx++) { 12068c2ecf20Sopenharmony_ci mac_info.vpath_no = vpath_idx; 12078c2ecf20Sopenharmony_ci status = vxge_del_mac_addr( 12088c2ecf20Sopenharmony_ci vdev, 12098c2ecf20Sopenharmony_ci &mac_info); 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci /* Add new ones */ 12168c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 12178c2ecf20Sopenharmony_ci memcpy(mac_info.macaddr, ha->addr, ETH_ALEN); 12188c2ecf20Sopenharmony_ci for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; 12198c2ecf20Sopenharmony_ci vpath_idx++) { 12208c2ecf20Sopenharmony_ci mac_info.vpath_no = vpath_idx; 12218c2ecf20Sopenharmony_ci mac_info.state = VXGE_LL_MAC_ADDR_IN_DA_TABLE; 12228c2ecf20Sopenharmony_ci status = vxge_add_mac_addr(vdev, &mac_info); 12238c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 12248c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 12258c2ecf20Sopenharmony_ci "%s:%d Setting individual" 12268c2ecf20Sopenharmony_ci "multicast address failed", 12278c2ecf20Sopenharmony_ci __func__, __LINE__); 12288c2ecf20Sopenharmony_ci goto _set_all_mcast; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci return; 12348c2ecf20Sopenharmony_ci_set_all_mcast: 12358c2ecf20Sopenharmony_ci mcast_cnt = vdev->vpaths[0].mcast_addr_cnt; 12368c2ecf20Sopenharmony_ci /* Delete previous MC's */ 12378c2ecf20Sopenharmony_ci for (i = 0; i < mcast_cnt; i++) { 12388c2ecf20Sopenharmony_ci list_for_each_safe(entry, next, list_head) { 12398c2ecf20Sopenharmony_ci mac_entry = (struct vxge_mac_addrs *)entry; 12408c2ecf20Sopenharmony_ci /* Copy the mac address to delete */ 12418c2ecf20Sopenharmony_ci mac_address = (u8 *)&mac_entry->macaddr; 12428c2ecf20Sopenharmony_ci memcpy(mac_info.macaddr, mac_address, ETH_ALEN); 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(mac_info.macaddr)) 12458c2ecf20Sopenharmony_ci break; 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; 12498c2ecf20Sopenharmony_ci vpath_idx++) { 12508c2ecf20Sopenharmony_ci mac_info.vpath_no = vpath_idx; 12518c2ecf20Sopenharmony_ci status = vxge_del_mac_addr(vdev, &mac_info); 12528c2ecf20Sopenharmony_ci } 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci /* Enable all multicast */ 12568c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 12578c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[i]; 12588c2ecf20Sopenharmony_ci vxge_assert(vpath->is_open); 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci status = vxge_hw_vpath_mcast_enable(vpath->handle); 12618c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 12628c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 12638c2ecf20Sopenharmony_ci "%s:%d Enabling all multicasts failed", 12648c2ecf20Sopenharmony_ci __func__, __LINE__); 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci vdev->all_multi_flg = 1; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci dev->flags |= IFF_ALLMULTI; 12698c2ecf20Sopenharmony_ci } 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 12728c2ecf20Sopenharmony_ci "%s:%d Exiting...", __func__, __LINE__); 12738c2ecf20Sopenharmony_ci} 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci/** 12768c2ecf20Sopenharmony_ci * vxge_set_mac_addr 12778c2ecf20Sopenharmony_ci * @dev: pointer to the device structure 12788c2ecf20Sopenharmony_ci * @p: socket info 12798c2ecf20Sopenharmony_ci * 12808c2ecf20Sopenharmony_ci * Update entry "0" (default MAC addr) 12818c2ecf20Sopenharmony_ci */ 12828c2ecf20Sopenharmony_cistatic int vxge_set_mac_addr(struct net_device *dev, void *p) 12838c2ecf20Sopenharmony_ci{ 12848c2ecf20Sopenharmony_ci struct sockaddr *addr = p; 12858c2ecf20Sopenharmony_ci struct vxgedev *vdev; 12868c2ecf20Sopenharmony_ci enum vxge_hw_status status = VXGE_HW_OK; 12878c2ecf20Sopenharmony_ci struct macInfo mac_info_new, mac_info_old; 12888c2ecf20Sopenharmony_ci int vpath_idx = 0; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__); 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci vdev = netdev_priv(dev); 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(addr->sa_data)) 12958c2ecf20Sopenharmony_ci return -EINVAL; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci memset(&mac_info_new, 0, sizeof(struct macInfo)); 12988c2ecf20Sopenharmony_ci memset(&mac_info_old, 0, sizeof(struct macInfo)); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s:%d Exiting...", 13018c2ecf20Sopenharmony_ci __func__, __LINE__); 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci /* Get the old address */ 13048c2ecf20Sopenharmony_ci memcpy(mac_info_old.macaddr, dev->dev_addr, dev->addr_len); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci /* Copy the new address */ 13078c2ecf20Sopenharmony_ci memcpy(mac_info_new.macaddr, addr->sa_data, dev->addr_len); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci /* First delete the old mac address from all the vpaths 13108c2ecf20Sopenharmony_ci as we can't specify the index while adding new mac address */ 13118c2ecf20Sopenharmony_ci for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) { 13128c2ecf20Sopenharmony_ci struct vxge_vpath *vpath = &vdev->vpaths[vpath_idx]; 13138c2ecf20Sopenharmony_ci if (!vpath->is_open) { 13148c2ecf20Sopenharmony_ci /* This can happen when this interface is added/removed 13158c2ecf20Sopenharmony_ci to the bonding interface. Delete this station address 13168c2ecf20Sopenharmony_ci from the linked list */ 13178c2ecf20Sopenharmony_ci vxge_mac_list_del(vpath, &mac_info_old); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci /* Add this new address to the linked list 13208c2ecf20Sopenharmony_ci for later restoring */ 13218c2ecf20Sopenharmony_ci vxge_mac_list_add(vpath, &mac_info_new); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci continue; 13248c2ecf20Sopenharmony_ci } 13258c2ecf20Sopenharmony_ci /* Delete the station address */ 13268c2ecf20Sopenharmony_ci mac_info_old.vpath_no = vpath_idx; 13278c2ecf20Sopenharmony_ci status = vxge_del_mac_addr(vdev, &mac_info_old); 13288c2ecf20Sopenharmony_ci } 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci if (unlikely(!is_vxge_card_up(vdev))) { 13318c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); 13328c2ecf20Sopenharmony_ci return VXGE_HW_OK; 13338c2ecf20Sopenharmony_ci } 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci /* Set this mac address to all the vpaths */ 13368c2ecf20Sopenharmony_ci for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) { 13378c2ecf20Sopenharmony_ci mac_info_new.vpath_no = vpath_idx; 13388c2ecf20Sopenharmony_ci mac_info_new.state = VXGE_LL_MAC_ADDR_IN_DA_TABLE; 13398c2ecf20Sopenharmony_ci status = vxge_add_mac_addr(vdev, &mac_info_new); 13408c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) 13418c2ecf20Sopenharmony_ci return -EINVAL; 13428c2ecf20Sopenharmony_ci } 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci return status; 13478c2ecf20Sopenharmony_ci} 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci/* 13508c2ecf20Sopenharmony_ci * vxge_vpath_intr_enable 13518c2ecf20Sopenharmony_ci * @vdev: pointer to vdev 13528c2ecf20Sopenharmony_ci * @vp_id: vpath for which to enable the interrupts 13538c2ecf20Sopenharmony_ci * 13548c2ecf20Sopenharmony_ci * Enables the interrupts for the vpath 13558c2ecf20Sopenharmony_ci*/ 13568c2ecf20Sopenharmony_cistatic void vxge_vpath_intr_enable(struct vxgedev *vdev, int vp_id) 13578c2ecf20Sopenharmony_ci{ 13588c2ecf20Sopenharmony_ci struct vxge_vpath *vpath = &vdev->vpaths[vp_id]; 13598c2ecf20Sopenharmony_ci int msix_id = 0; 13608c2ecf20Sopenharmony_ci int tim_msix_id[4] = {0, 1, 0, 0}; 13618c2ecf20Sopenharmony_ci int alarm_msix_id = VXGE_ALARM_MSIX_ID; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci vxge_hw_vpath_intr_enable(vpath->handle); 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci if (vdev->config.intr_type == INTA) 13668c2ecf20Sopenharmony_ci vxge_hw_vpath_inta_unmask_tx_rx(vpath->handle); 13678c2ecf20Sopenharmony_ci else { 13688c2ecf20Sopenharmony_ci vxge_hw_vpath_msix_set(vpath->handle, tim_msix_id, 13698c2ecf20Sopenharmony_ci alarm_msix_id); 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci msix_id = vpath->device_id * VXGE_HW_VPATH_MSIX_ACTIVE; 13728c2ecf20Sopenharmony_ci vxge_hw_vpath_msix_unmask(vpath->handle, msix_id); 13738c2ecf20Sopenharmony_ci vxge_hw_vpath_msix_unmask(vpath->handle, msix_id + 1); 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci /* enable the alarm vector */ 13768c2ecf20Sopenharmony_ci msix_id = (vpath->handle->vpath->hldev->first_vp_id * 13778c2ecf20Sopenharmony_ci VXGE_HW_VPATH_MSIX_ACTIVE) + alarm_msix_id; 13788c2ecf20Sopenharmony_ci vxge_hw_vpath_msix_unmask(vpath->handle, msix_id); 13798c2ecf20Sopenharmony_ci } 13808c2ecf20Sopenharmony_ci} 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci/* 13838c2ecf20Sopenharmony_ci * vxge_vpath_intr_disable 13848c2ecf20Sopenharmony_ci * @vdev: pointer to vdev 13858c2ecf20Sopenharmony_ci * @vp_id: vpath for which to disable the interrupts 13868c2ecf20Sopenharmony_ci * 13878c2ecf20Sopenharmony_ci * Disables the interrupts for the vpath 13888c2ecf20Sopenharmony_ci*/ 13898c2ecf20Sopenharmony_cistatic void vxge_vpath_intr_disable(struct vxgedev *vdev, int vp_id) 13908c2ecf20Sopenharmony_ci{ 13918c2ecf20Sopenharmony_ci struct vxge_vpath *vpath = &vdev->vpaths[vp_id]; 13928c2ecf20Sopenharmony_ci struct __vxge_hw_device *hldev; 13938c2ecf20Sopenharmony_ci int msix_id; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci hldev = pci_get_drvdata(vdev->pdev); 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci vxge_hw_vpath_wait_receive_idle(hldev, vpath->device_id); 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci vxge_hw_vpath_intr_disable(vpath->handle); 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci if (vdev->config.intr_type == INTA) 14028c2ecf20Sopenharmony_ci vxge_hw_vpath_inta_mask_tx_rx(vpath->handle); 14038c2ecf20Sopenharmony_ci else { 14048c2ecf20Sopenharmony_ci msix_id = vpath->device_id * VXGE_HW_VPATH_MSIX_ACTIVE; 14058c2ecf20Sopenharmony_ci vxge_hw_vpath_msix_mask(vpath->handle, msix_id); 14068c2ecf20Sopenharmony_ci vxge_hw_vpath_msix_mask(vpath->handle, msix_id + 1); 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci /* disable the alarm vector */ 14098c2ecf20Sopenharmony_ci msix_id = (vpath->handle->vpath->hldev->first_vp_id * 14108c2ecf20Sopenharmony_ci VXGE_HW_VPATH_MSIX_ACTIVE) + VXGE_ALARM_MSIX_ID; 14118c2ecf20Sopenharmony_ci vxge_hw_vpath_msix_mask(vpath->handle, msix_id); 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci/* list all mac addresses from DA table */ 14168c2ecf20Sopenharmony_cistatic enum vxge_hw_status 14178c2ecf20Sopenharmony_civxge_search_mac_addr_in_da_table(struct vxge_vpath *vpath, struct macInfo *mac) 14188c2ecf20Sopenharmony_ci{ 14198c2ecf20Sopenharmony_ci enum vxge_hw_status status = VXGE_HW_OK; 14208c2ecf20Sopenharmony_ci unsigned char macmask[ETH_ALEN]; 14218c2ecf20Sopenharmony_ci unsigned char macaddr[ETH_ALEN]; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci status = vxge_hw_vpath_mac_addr_get(vpath->handle, 14248c2ecf20Sopenharmony_ci macaddr, macmask); 14258c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 14268c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 14278c2ecf20Sopenharmony_ci "DA config list entry failed for vpath:%d", 14288c2ecf20Sopenharmony_ci vpath->device_id); 14298c2ecf20Sopenharmony_ci return status; 14308c2ecf20Sopenharmony_ci } 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci while (!ether_addr_equal(mac->macaddr, macaddr)) { 14338c2ecf20Sopenharmony_ci status = vxge_hw_vpath_mac_addr_get_next(vpath->handle, 14348c2ecf20Sopenharmony_ci macaddr, macmask); 14358c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) 14368c2ecf20Sopenharmony_ci break; 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci return status; 14408c2ecf20Sopenharmony_ci} 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci/* Store all mac addresses from the list to the DA table */ 14438c2ecf20Sopenharmony_cistatic enum vxge_hw_status vxge_restore_vpath_mac_addr(struct vxge_vpath *vpath) 14448c2ecf20Sopenharmony_ci{ 14458c2ecf20Sopenharmony_ci enum vxge_hw_status status = VXGE_HW_OK; 14468c2ecf20Sopenharmony_ci struct macInfo mac_info; 14478c2ecf20Sopenharmony_ci u8 *mac_address = NULL; 14488c2ecf20Sopenharmony_ci struct list_head *entry, *next; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci memset(&mac_info, 0, sizeof(struct macInfo)); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci if (vpath->is_open) { 14538c2ecf20Sopenharmony_ci list_for_each_safe(entry, next, &vpath->mac_addr_list) { 14548c2ecf20Sopenharmony_ci mac_address = 14558c2ecf20Sopenharmony_ci (u8 *)& 14568c2ecf20Sopenharmony_ci ((struct vxge_mac_addrs *)entry)->macaddr; 14578c2ecf20Sopenharmony_ci memcpy(mac_info.macaddr, mac_address, ETH_ALEN); 14588c2ecf20Sopenharmony_ci ((struct vxge_mac_addrs *)entry)->state = 14598c2ecf20Sopenharmony_ci VXGE_LL_MAC_ADDR_IN_DA_TABLE; 14608c2ecf20Sopenharmony_ci /* does this mac address already exist in da table? */ 14618c2ecf20Sopenharmony_ci status = vxge_search_mac_addr_in_da_table(vpath, 14628c2ecf20Sopenharmony_ci &mac_info); 14638c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 14648c2ecf20Sopenharmony_ci /* Add this mac address to the DA table */ 14658c2ecf20Sopenharmony_ci status = vxge_hw_vpath_mac_addr_add( 14668c2ecf20Sopenharmony_ci vpath->handle, mac_info.macaddr, 14678c2ecf20Sopenharmony_ci mac_info.macmask, 14688c2ecf20Sopenharmony_ci VXGE_HW_VPATH_MAC_ADDR_ADD_DUPLICATE); 14698c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 14708c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 14718c2ecf20Sopenharmony_ci "DA add entry failed for vpath:%d", 14728c2ecf20Sopenharmony_ci vpath->device_id); 14738c2ecf20Sopenharmony_ci ((struct vxge_mac_addrs *)entry)->state 14748c2ecf20Sopenharmony_ci = VXGE_LL_MAC_ADDR_IN_LIST; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci } 14778c2ecf20Sopenharmony_ci } 14788c2ecf20Sopenharmony_ci } 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci return status; 14818c2ecf20Sopenharmony_ci} 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci/* Store all vlan ids from the list to the vid table */ 14848c2ecf20Sopenharmony_cistatic enum vxge_hw_status 14858c2ecf20Sopenharmony_civxge_restore_vpath_vid_table(struct vxge_vpath *vpath) 14868c2ecf20Sopenharmony_ci{ 14878c2ecf20Sopenharmony_ci enum vxge_hw_status status = VXGE_HW_OK; 14888c2ecf20Sopenharmony_ci struct vxgedev *vdev = vpath->vdev; 14898c2ecf20Sopenharmony_ci u16 vid; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci if (!vpath->is_open) 14928c2ecf20Sopenharmony_ci return status; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci for_each_set_bit(vid, vdev->active_vlans, VLAN_N_VID) 14958c2ecf20Sopenharmony_ci status = vxge_hw_vpath_vid_add(vpath->handle, vid); 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci return status; 14988c2ecf20Sopenharmony_ci} 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci/* 15018c2ecf20Sopenharmony_ci * vxge_reset_vpath 15028c2ecf20Sopenharmony_ci * @vdev: pointer to vdev 15038c2ecf20Sopenharmony_ci * @vp_id: vpath to reset 15048c2ecf20Sopenharmony_ci * 15058c2ecf20Sopenharmony_ci * Resets the vpath 15068c2ecf20Sopenharmony_ci*/ 15078c2ecf20Sopenharmony_cistatic int vxge_reset_vpath(struct vxgedev *vdev, int vp_id) 15088c2ecf20Sopenharmony_ci{ 15098c2ecf20Sopenharmony_ci enum vxge_hw_status status = VXGE_HW_OK; 15108c2ecf20Sopenharmony_ci struct vxge_vpath *vpath = &vdev->vpaths[vp_id]; 15118c2ecf20Sopenharmony_ci int ret = 0; 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci /* check if device is down already */ 15148c2ecf20Sopenharmony_ci if (unlikely(!is_vxge_card_up(vdev))) 15158c2ecf20Sopenharmony_ci return 0; 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci /* is device reset already scheduled */ 15188c2ecf20Sopenharmony_ci if (test_bit(__VXGE_STATE_RESET_CARD, &vdev->state)) 15198c2ecf20Sopenharmony_ci return 0; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci if (vpath->handle) { 15228c2ecf20Sopenharmony_ci if (vxge_hw_vpath_reset(vpath->handle) == VXGE_HW_OK) { 15238c2ecf20Sopenharmony_ci if (is_vxge_card_up(vdev) && 15248c2ecf20Sopenharmony_ci vxge_hw_vpath_recover_from_reset(vpath->handle) 15258c2ecf20Sopenharmony_ci != VXGE_HW_OK) { 15268c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 15278c2ecf20Sopenharmony_ci "vxge_hw_vpath_recover_from_reset" 15288c2ecf20Sopenharmony_ci "failed for vpath:%d", vp_id); 15298c2ecf20Sopenharmony_ci return status; 15308c2ecf20Sopenharmony_ci } 15318c2ecf20Sopenharmony_ci } else { 15328c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 15338c2ecf20Sopenharmony_ci "vxge_hw_vpath_reset failed for" 15348c2ecf20Sopenharmony_ci "vpath:%d", vp_id); 15358c2ecf20Sopenharmony_ci return status; 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci } else 15388c2ecf20Sopenharmony_ci return VXGE_HW_FAIL; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci vxge_restore_vpath_mac_addr(vpath); 15418c2ecf20Sopenharmony_ci vxge_restore_vpath_vid_table(vpath); 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci /* Enable all broadcast */ 15448c2ecf20Sopenharmony_ci vxge_hw_vpath_bcast_enable(vpath->handle); 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci /* Enable all multicast */ 15478c2ecf20Sopenharmony_ci if (vdev->all_multi_flg) { 15488c2ecf20Sopenharmony_ci status = vxge_hw_vpath_mcast_enable(vpath->handle); 15498c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) 15508c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 15518c2ecf20Sopenharmony_ci "%s:%d Enabling multicast failed", 15528c2ecf20Sopenharmony_ci __func__, __LINE__); 15538c2ecf20Sopenharmony_ci } 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci /* Enable the interrupts */ 15568c2ecf20Sopenharmony_ci vxge_vpath_intr_enable(vdev, vp_id); 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci smp_wmb(); 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci /* Enable the flow of traffic through the vpath */ 15618c2ecf20Sopenharmony_ci vxge_hw_vpath_enable(vpath->handle); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci smp_wmb(); 15648c2ecf20Sopenharmony_ci vxge_hw_vpath_rx_doorbell_init(vpath->handle); 15658c2ecf20Sopenharmony_ci vpath->ring.last_status = VXGE_HW_OK; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci /* Vpath reset done */ 15688c2ecf20Sopenharmony_ci clear_bit(vp_id, &vdev->vp_reset); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci /* Start the vpath queue */ 15718c2ecf20Sopenharmony_ci if (netif_tx_queue_stopped(vpath->fifo.txq)) 15728c2ecf20Sopenharmony_ci netif_tx_wake_queue(vpath->fifo.txq); 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci return ret; 15758c2ecf20Sopenharmony_ci} 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci/* Configure CI */ 15788c2ecf20Sopenharmony_cistatic void vxge_config_ci_for_tti_rti(struct vxgedev *vdev) 15798c2ecf20Sopenharmony_ci{ 15808c2ecf20Sopenharmony_ci int i = 0; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci /* Enable CI for RTI */ 15838c2ecf20Sopenharmony_ci if (vdev->config.intr_type == MSI_X) { 15848c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 15858c2ecf20Sopenharmony_ci struct __vxge_hw_ring *hw_ring; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci hw_ring = vdev->vpaths[i].ring.handle; 15888c2ecf20Sopenharmony_ci vxge_hw_vpath_dynamic_rti_ci_set(hw_ring); 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ci } 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci /* Enable CI for TTI */ 15938c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 15948c2ecf20Sopenharmony_ci struct __vxge_hw_fifo *hw_fifo = vdev->vpaths[i].fifo.handle; 15958c2ecf20Sopenharmony_ci vxge_hw_vpath_tti_ci_set(hw_fifo); 15968c2ecf20Sopenharmony_ci /* 15978c2ecf20Sopenharmony_ci * For Inta (with or without napi), Set CI ON for only one 15988c2ecf20Sopenharmony_ci * vpath. (Have only one free running timer). 15998c2ecf20Sopenharmony_ci */ 16008c2ecf20Sopenharmony_ci if ((vdev->config.intr_type == INTA) && (i == 0)) 16018c2ecf20Sopenharmony_ci break; 16028c2ecf20Sopenharmony_ci } 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci return; 16058c2ecf20Sopenharmony_ci} 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_cistatic int do_vxge_reset(struct vxgedev *vdev, int event) 16088c2ecf20Sopenharmony_ci{ 16098c2ecf20Sopenharmony_ci enum vxge_hw_status status; 16108c2ecf20Sopenharmony_ci int ret = 0, vp_id, i; 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__); 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci if ((event == VXGE_LL_FULL_RESET) || (event == VXGE_LL_START_RESET)) { 16158c2ecf20Sopenharmony_ci /* check if device is down already */ 16168c2ecf20Sopenharmony_ci if (unlikely(!is_vxge_card_up(vdev))) 16178c2ecf20Sopenharmony_ci return 0; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci /* is reset already scheduled */ 16208c2ecf20Sopenharmony_ci if (test_and_set_bit(__VXGE_STATE_RESET_CARD, &vdev->state)) 16218c2ecf20Sopenharmony_ci return 0; 16228c2ecf20Sopenharmony_ci } 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci if (event == VXGE_LL_FULL_RESET) { 16258c2ecf20Sopenharmony_ci netif_carrier_off(vdev->ndev); 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci /* wait for all the vpath reset to complete */ 16288c2ecf20Sopenharmony_ci for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) { 16298c2ecf20Sopenharmony_ci while (test_bit(vp_id, &vdev->vp_reset)) 16308c2ecf20Sopenharmony_ci msleep(50); 16318c2ecf20Sopenharmony_ci } 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci netif_carrier_on(vdev->ndev); 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci /* if execution mode is set to debug, don't reset the adapter */ 16368c2ecf20Sopenharmony_ci if (unlikely(vdev->exec_mode)) { 16378c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 16388c2ecf20Sopenharmony_ci "%s: execution mode is debug, returning..", 16398c2ecf20Sopenharmony_ci vdev->ndev->name); 16408c2ecf20Sopenharmony_ci clear_bit(__VXGE_STATE_CARD_UP, &vdev->state); 16418c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(vdev->ndev); 16428c2ecf20Sopenharmony_ci return 0; 16438c2ecf20Sopenharmony_ci } 16448c2ecf20Sopenharmony_ci } 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci if (event == VXGE_LL_FULL_RESET) { 16478c2ecf20Sopenharmony_ci vxge_hw_device_wait_receive_idle(vdev->devh); 16488c2ecf20Sopenharmony_ci vxge_hw_device_intr_disable(vdev->devh); 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci switch (vdev->cric_err_event) { 16518c2ecf20Sopenharmony_ci case VXGE_HW_EVENT_UNKNOWN: 16528c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(vdev->ndev); 16538c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 16548c2ecf20Sopenharmony_ci "fatal: %s: Disabling device due to" 16558c2ecf20Sopenharmony_ci "unknown error", 16568c2ecf20Sopenharmony_ci vdev->ndev->name); 16578c2ecf20Sopenharmony_ci ret = -EPERM; 16588c2ecf20Sopenharmony_ci goto out; 16598c2ecf20Sopenharmony_ci case VXGE_HW_EVENT_RESET_START: 16608c2ecf20Sopenharmony_ci break; 16618c2ecf20Sopenharmony_ci case VXGE_HW_EVENT_RESET_COMPLETE: 16628c2ecf20Sopenharmony_ci case VXGE_HW_EVENT_LINK_DOWN: 16638c2ecf20Sopenharmony_ci case VXGE_HW_EVENT_LINK_UP: 16648c2ecf20Sopenharmony_ci case VXGE_HW_EVENT_ALARM_CLEARED: 16658c2ecf20Sopenharmony_ci case VXGE_HW_EVENT_ECCERR: 16668c2ecf20Sopenharmony_ci case VXGE_HW_EVENT_MRPCIM_ECCERR: 16678c2ecf20Sopenharmony_ci ret = -EPERM; 16688c2ecf20Sopenharmony_ci goto out; 16698c2ecf20Sopenharmony_ci case VXGE_HW_EVENT_FIFO_ERR: 16708c2ecf20Sopenharmony_ci case VXGE_HW_EVENT_VPATH_ERR: 16718c2ecf20Sopenharmony_ci break; 16728c2ecf20Sopenharmony_ci case VXGE_HW_EVENT_CRITICAL_ERR: 16738c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(vdev->ndev); 16748c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 16758c2ecf20Sopenharmony_ci "fatal: %s: Disabling device due to" 16768c2ecf20Sopenharmony_ci "serious error", 16778c2ecf20Sopenharmony_ci vdev->ndev->name); 16788c2ecf20Sopenharmony_ci /* SOP or device reset required */ 16798c2ecf20Sopenharmony_ci /* This event is not currently used */ 16808c2ecf20Sopenharmony_ci ret = -EPERM; 16818c2ecf20Sopenharmony_ci goto out; 16828c2ecf20Sopenharmony_ci case VXGE_HW_EVENT_SERR: 16838c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(vdev->ndev); 16848c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 16858c2ecf20Sopenharmony_ci "fatal: %s: Disabling device due to" 16868c2ecf20Sopenharmony_ci "serious error", 16878c2ecf20Sopenharmony_ci vdev->ndev->name); 16888c2ecf20Sopenharmony_ci ret = -EPERM; 16898c2ecf20Sopenharmony_ci goto out; 16908c2ecf20Sopenharmony_ci case VXGE_HW_EVENT_SRPCIM_SERR: 16918c2ecf20Sopenharmony_ci case VXGE_HW_EVENT_MRPCIM_SERR: 16928c2ecf20Sopenharmony_ci ret = -EPERM; 16938c2ecf20Sopenharmony_ci goto out; 16948c2ecf20Sopenharmony_ci case VXGE_HW_EVENT_SLOT_FREEZE: 16958c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(vdev->ndev); 16968c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 16978c2ecf20Sopenharmony_ci "fatal: %s: Disabling device due to" 16988c2ecf20Sopenharmony_ci "slot freeze", 16998c2ecf20Sopenharmony_ci vdev->ndev->name); 17008c2ecf20Sopenharmony_ci ret = -EPERM; 17018c2ecf20Sopenharmony_ci goto out; 17028c2ecf20Sopenharmony_ci default: 17038c2ecf20Sopenharmony_ci break; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci } 17068c2ecf20Sopenharmony_ci } 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci if ((event == VXGE_LL_FULL_RESET) || (event == VXGE_LL_START_RESET)) 17098c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(vdev->ndev); 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci if (event == VXGE_LL_FULL_RESET) { 17128c2ecf20Sopenharmony_ci status = vxge_reset_all_vpaths(vdev); 17138c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 17148c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 17158c2ecf20Sopenharmony_ci "fatal: %s: can not reset vpaths", 17168c2ecf20Sopenharmony_ci vdev->ndev->name); 17178c2ecf20Sopenharmony_ci ret = -EPERM; 17188c2ecf20Sopenharmony_ci goto out; 17198c2ecf20Sopenharmony_ci } 17208c2ecf20Sopenharmony_ci } 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci if (event == VXGE_LL_COMPL_RESET) { 17238c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) 17248c2ecf20Sopenharmony_ci if (vdev->vpaths[i].handle) { 17258c2ecf20Sopenharmony_ci if (vxge_hw_vpath_recover_from_reset( 17268c2ecf20Sopenharmony_ci vdev->vpaths[i].handle) 17278c2ecf20Sopenharmony_ci != VXGE_HW_OK) { 17288c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 17298c2ecf20Sopenharmony_ci "vxge_hw_vpath_recover_" 17308c2ecf20Sopenharmony_ci "from_reset failed for vpath: " 17318c2ecf20Sopenharmony_ci "%d", i); 17328c2ecf20Sopenharmony_ci ret = -EPERM; 17338c2ecf20Sopenharmony_ci goto out; 17348c2ecf20Sopenharmony_ci } 17358c2ecf20Sopenharmony_ci } else { 17368c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 17378c2ecf20Sopenharmony_ci "vxge_hw_vpath_reset failed for " 17388c2ecf20Sopenharmony_ci "vpath:%d", i); 17398c2ecf20Sopenharmony_ci ret = -EPERM; 17408c2ecf20Sopenharmony_ci goto out; 17418c2ecf20Sopenharmony_ci } 17428c2ecf20Sopenharmony_ci } 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci if ((event == VXGE_LL_FULL_RESET) || (event == VXGE_LL_COMPL_RESET)) { 17458c2ecf20Sopenharmony_ci /* Reprogram the DA table with populated mac addresses */ 17468c2ecf20Sopenharmony_ci for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) { 17478c2ecf20Sopenharmony_ci vxge_restore_vpath_mac_addr(&vdev->vpaths[vp_id]); 17488c2ecf20Sopenharmony_ci vxge_restore_vpath_vid_table(&vdev->vpaths[vp_id]); 17498c2ecf20Sopenharmony_ci } 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci /* enable vpath interrupts */ 17528c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) 17538c2ecf20Sopenharmony_ci vxge_vpath_intr_enable(vdev, i); 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci vxge_hw_device_intr_enable(vdev->devh); 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci smp_wmb(); 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci /* Indicate card up */ 17608c2ecf20Sopenharmony_ci set_bit(__VXGE_STATE_CARD_UP, &vdev->state); 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci /* Get the traffic to flow through the vpaths */ 17638c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 17648c2ecf20Sopenharmony_ci vxge_hw_vpath_enable(vdev->vpaths[i].handle); 17658c2ecf20Sopenharmony_ci smp_wmb(); 17668c2ecf20Sopenharmony_ci vxge_hw_vpath_rx_doorbell_init(vdev->vpaths[i].handle); 17678c2ecf20Sopenharmony_ci } 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci netif_tx_wake_all_queues(vdev->ndev); 17708c2ecf20Sopenharmony_ci } 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci /* configure CI */ 17738c2ecf20Sopenharmony_ci vxge_config_ci_for_tti_rti(vdev); 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ciout: 17768c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 17778c2ecf20Sopenharmony_ci "%s:%d Exiting...", __func__, __LINE__); 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci /* Indicate reset done */ 17808c2ecf20Sopenharmony_ci if ((event == VXGE_LL_FULL_RESET) || (event == VXGE_LL_COMPL_RESET)) 17818c2ecf20Sopenharmony_ci clear_bit(__VXGE_STATE_RESET_CARD, &vdev->state); 17828c2ecf20Sopenharmony_ci return ret; 17838c2ecf20Sopenharmony_ci} 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci/* 17868c2ecf20Sopenharmony_ci * vxge_reset 17878c2ecf20Sopenharmony_ci * @vdev: pointer to ll device 17888c2ecf20Sopenharmony_ci * 17898c2ecf20Sopenharmony_ci * driver may reset the chip on events of serr, eccerr, etc 17908c2ecf20Sopenharmony_ci */ 17918c2ecf20Sopenharmony_cistatic void vxge_reset(struct work_struct *work) 17928c2ecf20Sopenharmony_ci{ 17938c2ecf20Sopenharmony_ci struct vxgedev *vdev = container_of(work, struct vxgedev, reset_task); 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci if (!netif_running(vdev->ndev)) 17968c2ecf20Sopenharmony_ci return; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci do_vxge_reset(vdev, VXGE_LL_FULL_RESET); 17998c2ecf20Sopenharmony_ci} 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci/** 18028c2ecf20Sopenharmony_ci * vxge_poll - Receive handler when Receive Polling is used. 18038c2ecf20Sopenharmony_ci * @napi: pointer to the napi structure. 18048c2ecf20Sopenharmony_ci * @budget: Number of packets budgeted to be processed in this iteration. 18058c2ecf20Sopenharmony_ci * 18068c2ecf20Sopenharmony_ci * This function comes into picture only if Receive side is being handled 18078c2ecf20Sopenharmony_ci * through polling (called NAPI in linux). It mostly does what the normal 18088c2ecf20Sopenharmony_ci * Rx interrupt handler does in terms of descriptor and packet processing 18098c2ecf20Sopenharmony_ci * but not in an interrupt context. Also it will process a specified number 18108c2ecf20Sopenharmony_ci * of packets at most in one iteration. This value is passed down by the 18118c2ecf20Sopenharmony_ci * kernel as the function argument 'budget'. 18128c2ecf20Sopenharmony_ci */ 18138c2ecf20Sopenharmony_cistatic int vxge_poll_msix(struct napi_struct *napi, int budget) 18148c2ecf20Sopenharmony_ci{ 18158c2ecf20Sopenharmony_ci struct vxge_ring *ring = container_of(napi, struct vxge_ring, napi); 18168c2ecf20Sopenharmony_ci int pkts_processed; 18178c2ecf20Sopenharmony_ci int budget_org = budget; 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci ring->budget = budget; 18208c2ecf20Sopenharmony_ci ring->pkts_processed = 0; 18218c2ecf20Sopenharmony_ci vxge_hw_vpath_poll_rx(ring->handle); 18228c2ecf20Sopenharmony_ci pkts_processed = ring->pkts_processed; 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci if (pkts_processed < budget_org) { 18258c2ecf20Sopenharmony_ci napi_complete_done(napi, pkts_processed); 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci /* Re enable the Rx interrupts for the vpath */ 18288c2ecf20Sopenharmony_ci vxge_hw_channel_msix_unmask( 18298c2ecf20Sopenharmony_ci (struct __vxge_hw_channel *)ring->handle, 18308c2ecf20Sopenharmony_ci ring->rx_vector_no); 18318c2ecf20Sopenharmony_ci } 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci /* We are copying and returning the local variable, in case if after 18348c2ecf20Sopenharmony_ci * clearing the msix interrupt above, if the interrupt fires right 18358c2ecf20Sopenharmony_ci * away which can preempt this NAPI thread */ 18368c2ecf20Sopenharmony_ci return pkts_processed; 18378c2ecf20Sopenharmony_ci} 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_cistatic int vxge_poll_inta(struct napi_struct *napi, int budget) 18408c2ecf20Sopenharmony_ci{ 18418c2ecf20Sopenharmony_ci struct vxgedev *vdev = container_of(napi, struct vxgedev, napi); 18428c2ecf20Sopenharmony_ci int pkts_processed = 0; 18438c2ecf20Sopenharmony_ci int i; 18448c2ecf20Sopenharmony_ci int budget_org = budget; 18458c2ecf20Sopenharmony_ci struct vxge_ring *ring; 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci struct __vxge_hw_device *hldev = pci_get_drvdata(vdev->pdev); 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 18508c2ecf20Sopenharmony_ci ring = &vdev->vpaths[i].ring; 18518c2ecf20Sopenharmony_ci ring->budget = budget; 18528c2ecf20Sopenharmony_ci ring->pkts_processed = 0; 18538c2ecf20Sopenharmony_ci vxge_hw_vpath_poll_rx(ring->handle); 18548c2ecf20Sopenharmony_ci pkts_processed += ring->pkts_processed; 18558c2ecf20Sopenharmony_ci budget -= ring->pkts_processed; 18568c2ecf20Sopenharmony_ci if (budget <= 0) 18578c2ecf20Sopenharmony_ci break; 18588c2ecf20Sopenharmony_ci } 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci VXGE_COMPLETE_ALL_TX(vdev); 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci if (pkts_processed < budget_org) { 18638c2ecf20Sopenharmony_ci napi_complete_done(napi, pkts_processed); 18648c2ecf20Sopenharmony_ci /* Re enable the Rx interrupts for the ring */ 18658c2ecf20Sopenharmony_ci vxge_hw_device_unmask_all(hldev); 18668c2ecf20Sopenharmony_ci vxge_hw_device_flush_io(hldev); 18678c2ecf20Sopenharmony_ci } 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci return pkts_processed; 18708c2ecf20Sopenharmony_ci} 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 18738c2ecf20Sopenharmony_ci/** 18748c2ecf20Sopenharmony_ci * vxge_netpoll - netpoll event handler entry point 18758c2ecf20Sopenharmony_ci * @dev : pointer to the device structure. 18768c2ecf20Sopenharmony_ci * Description: 18778c2ecf20Sopenharmony_ci * This function will be called by upper layer to check for events on the 18788c2ecf20Sopenharmony_ci * interface in situations where interrupts are disabled. It is used for 18798c2ecf20Sopenharmony_ci * specific in-kernel networking tasks, such as remote consoles and kernel 18808c2ecf20Sopenharmony_ci * debugging over the network (example netdump in RedHat). 18818c2ecf20Sopenharmony_ci */ 18828c2ecf20Sopenharmony_cistatic void vxge_netpoll(struct net_device *dev) 18838c2ecf20Sopenharmony_ci{ 18848c2ecf20Sopenharmony_ci struct vxgedev *vdev = netdev_priv(dev); 18858c2ecf20Sopenharmony_ci struct pci_dev *pdev = vdev->pdev; 18868c2ecf20Sopenharmony_ci struct __vxge_hw_device *hldev = pci_get_drvdata(pdev); 18878c2ecf20Sopenharmony_ci const int irq = pdev->irq; 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__); 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci if (pci_channel_offline(pdev)) 18928c2ecf20Sopenharmony_ci return; 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci disable_irq(irq); 18958c2ecf20Sopenharmony_ci vxge_hw_device_clear_tx_rx(hldev); 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci vxge_hw_device_clear_tx_rx(hldev); 18988c2ecf20Sopenharmony_ci VXGE_COMPLETE_ALL_RX(vdev); 18998c2ecf20Sopenharmony_ci VXGE_COMPLETE_ALL_TX(vdev); 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci enable_irq(irq); 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 19048c2ecf20Sopenharmony_ci "%s:%d Exiting...", __func__, __LINE__); 19058c2ecf20Sopenharmony_ci} 19068c2ecf20Sopenharmony_ci#endif 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci/* RTH configuration */ 19098c2ecf20Sopenharmony_cistatic enum vxge_hw_status vxge_rth_configure(struct vxgedev *vdev) 19108c2ecf20Sopenharmony_ci{ 19118c2ecf20Sopenharmony_ci enum vxge_hw_status status = VXGE_HW_OK; 19128c2ecf20Sopenharmony_ci struct vxge_hw_rth_hash_types hash_types; 19138c2ecf20Sopenharmony_ci u8 itable[256] = {0}; /* indirection table */ 19148c2ecf20Sopenharmony_ci u8 mtable[256] = {0}; /* CPU to vpath mapping */ 19158c2ecf20Sopenharmony_ci int index; 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci /* 19188c2ecf20Sopenharmony_ci * Filling 19198c2ecf20Sopenharmony_ci * - itable with bucket numbers 19208c2ecf20Sopenharmony_ci * - mtable with bucket-to-vpath mapping 19218c2ecf20Sopenharmony_ci */ 19228c2ecf20Sopenharmony_ci for (index = 0; index < (1 << vdev->config.rth_bkt_sz); index++) { 19238c2ecf20Sopenharmony_ci itable[index] = index; 19248c2ecf20Sopenharmony_ci mtable[index] = index % vdev->no_of_vpath; 19258c2ecf20Sopenharmony_ci } 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci /* set indirection table, bucket-to-vpath mapping */ 19288c2ecf20Sopenharmony_ci status = vxge_hw_vpath_rts_rth_itable_set(vdev->vp_handles, 19298c2ecf20Sopenharmony_ci vdev->no_of_vpath, 19308c2ecf20Sopenharmony_ci mtable, itable, 19318c2ecf20Sopenharmony_ci vdev->config.rth_bkt_sz); 19328c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 19338c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 19348c2ecf20Sopenharmony_ci "RTH indirection table configuration failed " 19358c2ecf20Sopenharmony_ci "for vpath:%d", vdev->vpaths[0].device_id); 19368c2ecf20Sopenharmony_ci return status; 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci /* Fill RTH hash types */ 19408c2ecf20Sopenharmony_ci hash_types.hash_type_tcpipv4_en = vdev->config.rth_hash_type_tcpipv4; 19418c2ecf20Sopenharmony_ci hash_types.hash_type_ipv4_en = vdev->config.rth_hash_type_ipv4; 19428c2ecf20Sopenharmony_ci hash_types.hash_type_tcpipv6_en = vdev->config.rth_hash_type_tcpipv6; 19438c2ecf20Sopenharmony_ci hash_types.hash_type_ipv6_en = vdev->config.rth_hash_type_ipv6; 19448c2ecf20Sopenharmony_ci hash_types.hash_type_tcpipv6ex_en = 19458c2ecf20Sopenharmony_ci vdev->config.rth_hash_type_tcpipv6ex; 19468c2ecf20Sopenharmony_ci hash_types.hash_type_ipv6ex_en = vdev->config.rth_hash_type_ipv6ex; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci /* 19498c2ecf20Sopenharmony_ci * Because the itable_set() method uses the active_table field 19508c2ecf20Sopenharmony_ci * for the target virtual path the RTH config should be updated 19518c2ecf20Sopenharmony_ci * for all VPATHs. The h/w only uses the lowest numbered VPATH 19528c2ecf20Sopenharmony_ci * when steering frames. 19538c2ecf20Sopenharmony_ci */ 19548c2ecf20Sopenharmony_ci for (index = 0; index < vdev->no_of_vpath; index++) { 19558c2ecf20Sopenharmony_ci status = vxge_hw_vpath_rts_rth_set( 19568c2ecf20Sopenharmony_ci vdev->vpaths[index].handle, 19578c2ecf20Sopenharmony_ci vdev->config.rth_algorithm, 19588c2ecf20Sopenharmony_ci &hash_types, 19598c2ecf20Sopenharmony_ci vdev->config.rth_bkt_sz); 19608c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 19618c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 19628c2ecf20Sopenharmony_ci "RTH configuration failed for vpath:%d", 19638c2ecf20Sopenharmony_ci vdev->vpaths[index].device_id); 19648c2ecf20Sopenharmony_ci return status; 19658c2ecf20Sopenharmony_ci } 19668c2ecf20Sopenharmony_ci } 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci return status; 19698c2ecf20Sopenharmony_ci} 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci/* reset vpaths */ 19728c2ecf20Sopenharmony_cistatic enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev) 19738c2ecf20Sopenharmony_ci{ 19748c2ecf20Sopenharmony_ci enum vxge_hw_status status = VXGE_HW_OK; 19758c2ecf20Sopenharmony_ci struct vxge_vpath *vpath; 19768c2ecf20Sopenharmony_ci int i; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 19798c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[i]; 19808c2ecf20Sopenharmony_ci if (vpath->handle) { 19818c2ecf20Sopenharmony_ci if (vxge_hw_vpath_reset(vpath->handle) == VXGE_HW_OK) { 19828c2ecf20Sopenharmony_ci if (is_vxge_card_up(vdev) && 19838c2ecf20Sopenharmony_ci vxge_hw_vpath_recover_from_reset( 19848c2ecf20Sopenharmony_ci vpath->handle) != VXGE_HW_OK) { 19858c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 19868c2ecf20Sopenharmony_ci "vxge_hw_vpath_recover_" 19878c2ecf20Sopenharmony_ci "from_reset failed for vpath: " 19888c2ecf20Sopenharmony_ci "%d", i); 19898c2ecf20Sopenharmony_ci return status; 19908c2ecf20Sopenharmony_ci } 19918c2ecf20Sopenharmony_ci } else { 19928c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 19938c2ecf20Sopenharmony_ci "vxge_hw_vpath_reset failed for " 19948c2ecf20Sopenharmony_ci "vpath:%d", i); 19958c2ecf20Sopenharmony_ci return status; 19968c2ecf20Sopenharmony_ci } 19978c2ecf20Sopenharmony_ci } 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci return status; 20018c2ecf20Sopenharmony_ci} 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci/* close vpaths */ 20048c2ecf20Sopenharmony_cistatic void vxge_close_vpaths(struct vxgedev *vdev, int index) 20058c2ecf20Sopenharmony_ci{ 20068c2ecf20Sopenharmony_ci struct vxge_vpath *vpath; 20078c2ecf20Sopenharmony_ci int i; 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci for (i = index; i < vdev->no_of_vpath; i++) { 20108c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[i]; 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci if (vpath->handle && vpath->is_open) { 20138c2ecf20Sopenharmony_ci vxge_hw_vpath_close(vpath->handle); 20148c2ecf20Sopenharmony_ci vdev->stats.vpaths_open--; 20158c2ecf20Sopenharmony_ci } 20168c2ecf20Sopenharmony_ci vpath->is_open = 0; 20178c2ecf20Sopenharmony_ci vpath->handle = NULL; 20188c2ecf20Sopenharmony_ci } 20198c2ecf20Sopenharmony_ci} 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci/* open vpaths */ 20228c2ecf20Sopenharmony_cistatic int vxge_open_vpaths(struct vxgedev *vdev) 20238c2ecf20Sopenharmony_ci{ 20248c2ecf20Sopenharmony_ci struct vxge_hw_vpath_attr attr; 20258c2ecf20Sopenharmony_ci enum vxge_hw_status status; 20268c2ecf20Sopenharmony_ci struct vxge_vpath *vpath; 20278c2ecf20Sopenharmony_ci u32 vp_id = 0; 20288c2ecf20Sopenharmony_ci int i; 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 20318c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[i]; 20328c2ecf20Sopenharmony_ci vxge_assert(vpath->is_configured); 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci if (!vdev->titan1) { 20358c2ecf20Sopenharmony_ci struct vxge_hw_vp_config *vcfg; 20368c2ecf20Sopenharmony_ci vcfg = &vdev->devh->config.vp_config[vpath->device_id]; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci vcfg->rti.urange_a = RTI_T1A_RX_URANGE_A; 20398c2ecf20Sopenharmony_ci vcfg->rti.urange_b = RTI_T1A_RX_URANGE_B; 20408c2ecf20Sopenharmony_ci vcfg->rti.urange_c = RTI_T1A_RX_URANGE_C; 20418c2ecf20Sopenharmony_ci vcfg->tti.uec_a = TTI_T1A_TX_UFC_A; 20428c2ecf20Sopenharmony_ci vcfg->tti.uec_b = TTI_T1A_TX_UFC_B; 20438c2ecf20Sopenharmony_ci vcfg->tti.uec_c = TTI_T1A_TX_UFC_C(vdev->mtu); 20448c2ecf20Sopenharmony_ci vcfg->tti.uec_d = TTI_T1A_TX_UFC_D(vdev->mtu); 20458c2ecf20Sopenharmony_ci vcfg->tti.ltimer_val = VXGE_T1A_TTI_LTIMER_VAL; 20468c2ecf20Sopenharmony_ci vcfg->tti.rtimer_val = VXGE_T1A_TTI_RTIMER_VAL; 20478c2ecf20Sopenharmony_ci } 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci attr.vp_id = vpath->device_id; 20508c2ecf20Sopenharmony_ci attr.fifo_attr.callback = vxge_xmit_compl; 20518c2ecf20Sopenharmony_ci attr.fifo_attr.txdl_term = vxge_tx_term; 20528c2ecf20Sopenharmony_ci attr.fifo_attr.per_txdl_space = sizeof(struct vxge_tx_priv); 20538c2ecf20Sopenharmony_ci attr.fifo_attr.userdata = &vpath->fifo; 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci attr.ring_attr.callback = vxge_rx_1b_compl; 20568c2ecf20Sopenharmony_ci attr.ring_attr.rxd_init = vxge_rx_initial_replenish; 20578c2ecf20Sopenharmony_ci attr.ring_attr.rxd_term = vxge_rx_term; 20588c2ecf20Sopenharmony_ci attr.ring_attr.per_rxd_space = sizeof(struct vxge_rx_priv); 20598c2ecf20Sopenharmony_ci attr.ring_attr.userdata = &vpath->ring; 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci vpath->ring.ndev = vdev->ndev; 20628c2ecf20Sopenharmony_ci vpath->ring.pdev = vdev->pdev; 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci status = vxge_hw_vpath_open(vdev->devh, &attr, &vpath->handle); 20658c2ecf20Sopenharmony_ci if (status == VXGE_HW_OK) { 20668c2ecf20Sopenharmony_ci vpath->fifo.handle = 20678c2ecf20Sopenharmony_ci (struct __vxge_hw_fifo *)attr.fifo_attr.userdata; 20688c2ecf20Sopenharmony_ci vpath->ring.handle = 20698c2ecf20Sopenharmony_ci (struct __vxge_hw_ring *)attr.ring_attr.userdata; 20708c2ecf20Sopenharmony_ci vpath->fifo.tx_steering_type = 20718c2ecf20Sopenharmony_ci vdev->config.tx_steering_type; 20728c2ecf20Sopenharmony_ci vpath->fifo.ndev = vdev->ndev; 20738c2ecf20Sopenharmony_ci vpath->fifo.pdev = vdev->pdev; 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci u64_stats_init(&vpath->fifo.stats.syncp); 20768c2ecf20Sopenharmony_ci u64_stats_init(&vpath->ring.stats.syncp); 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci if (vdev->config.tx_steering_type) 20798c2ecf20Sopenharmony_ci vpath->fifo.txq = 20808c2ecf20Sopenharmony_ci netdev_get_tx_queue(vdev->ndev, i); 20818c2ecf20Sopenharmony_ci else 20828c2ecf20Sopenharmony_ci vpath->fifo.txq = 20838c2ecf20Sopenharmony_ci netdev_get_tx_queue(vdev->ndev, 0); 20848c2ecf20Sopenharmony_ci vpath->fifo.indicate_max_pkts = 20858c2ecf20Sopenharmony_ci vdev->config.fifo_indicate_max_pkts; 20868c2ecf20Sopenharmony_ci vpath->fifo.tx_vector_no = 0; 20878c2ecf20Sopenharmony_ci vpath->ring.rx_vector_no = 0; 20888c2ecf20Sopenharmony_ci vpath->ring.rx_hwts = vdev->rx_hwts; 20898c2ecf20Sopenharmony_ci vpath->is_open = 1; 20908c2ecf20Sopenharmony_ci vdev->vp_handles[i] = vpath->handle; 20918c2ecf20Sopenharmony_ci vpath->ring.vlan_tag_strip = vdev->vlan_tag_strip; 20928c2ecf20Sopenharmony_ci vdev->stats.vpaths_open++; 20938c2ecf20Sopenharmony_ci } else { 20948c2ecf20Sopenharmony_ci vdev->stats.vpath_open_fail++; 20958c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, "%s: vpath: %d failed to " 20968c2ecf20Sopenharmony_ci "open with status: %d", 20978c2ecf20Sopenharmony_ci vdev->ndev->name, vpath->device_id, 20988c2ecf20Sopenharmony_ci status); 20998c2ecf20Sopenharmony_ci vxge_close_vpaths(vdev, 0); 21008c2ecf20Sopenharmony_ci return -EPERM; 21018c2ecf20Sopenharmony_ci } 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci vp_id = vpath->handle->vpath->vp_id; 21048c2ecf20Sopenharmony_ci vdev->vpaths_deployed |= vxge_mBIT(vp_id); 21058c2ecf20Sopenharmony_ci } 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci return VXGE_HW_OK; 21088c2ecf20Sopenharmony_ci} 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci/** 21118c2ecf20Sopenharmony_ci * adaptive_coalesce_tx_interrupts - Changes the interrupt coalescing 21128c2ecf20Sopenharmony_ci * if the interrupts are not within a range 21138c2ecf20Sopenharmony_ci * @fifo: pointer to transmit fifo structure 21148c2ecf20Sopenharmony_ci * Description: The function changes boundary timer and restriction timer 21158c2ecf20Sopenharmony_ci * value depends on the traffic 21168c2ecf20Sopenharmony_ci * Return Value: None 21178c2ecf20Sopenharmony_ci */ 21188c2ecf20Sopenharmony_cistatic void adaptive_coalesce_tx_interrupts(struct vxge_fifo *fifo) 21198c2ecf20Sopenharmony_ci{ 21208c2ecf20Sopenharmony_ci fifo->interrupt_count++; 21218c2ecf20Sopenharmony_ci if (time_before(fifo->jiffies + HZ / 100, jiffies)) { 21228c2ecf20Sopenharmony_ci struct __vxge_hw_fifo *hw_fifo = fifo->handle; 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci fifo->jiffies = jiffies; 21258c2ecf20Sopenharmony_ci if (fifo->interrupt_count > VXGE_T1A_MAX_TX_INTERRUPT_COUNT && 21268c2ecf20Sopenharmony_ci hw_fifo->rtimer != VXGE_TTI_RTIMER_ADAPT_VAL) { 21278c2ecf20Sopenharmony_ci hw_fifo->rtimer = VXGE_TTI_RTIMER_ADAPT_VAL; 21288c2ecf20Sopenharmony_ci vxge_hw_vpath_dynamic_tti_rtimer_set(hw_fifo); 21298c2ecf20Sopenharmony_ci } else if (hw_fifo->rtimer != 0) { 21308c2ecf20Sopenharmony_ci hw_fifo->rtimer = 0; 21318c2ecf20Sopenharmony_ci vxge_hw_vpath_dynamic_tti_rtimer_set(hw_fifo); 21328c2ecf20Sopenharmony_ci } 21338c2ecf20Sopenharmony_ci fifo->interrupt_count = 0; 21348c2ecf20Sopenharmony_ci } 21358c2ecf20Sopenharmony_ci} 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci/** 21388c2ecf20Sopenharmony_ci * adaptive_coalesce_rx_interrupts - Changes the interrupt coalescing 21398c2ecf20Sopenharmony_ci * if the interrupts are not within a range 21408c2ecf20Sopenharmony_ci * @ring: pointer to receive ring structure 21418c2ecf20Sopenharmony_ci * Description: The function increases of decreases the packet counts within 21428c2ecf20Sopenharmony_ci * the ranges of traffic utilization, if the interrupts due to this ring are 21438c2ecf20Sopenharmony_ci * not within a fixed range. 21448c2ecf20Sopenharmony_ci * Return Value: Nothing 21458c2ecf20Sopenharmony_ci */ 21468c2ecf20Sopenharmony_cistatic void adaptive_coalesce_rx_interrupts(struct vxge_ring *ring) 21478c2ecf20Sopenharmony_ci{ 21488c2ecf20Sopenharmony_ci ring->interrupt_count++; 21498c2ecf20Sopenharmony_ci if (time_before(ring->jiffies + HZ / 100, jiffies)) { 21508c2ecf20Sopenharmony_ci struct __vxge_hw_ring *hw_ring = ring->handle; 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci ring->jiffies = jiffies; 21538c2ecf20Sopenharmony_ci if (ring->interrupt_count > VXGE_T1A_MAX_INTERRUPT_COUNT && 21548c2ecf20Sopenharmony_ci hw_ring->rtimer != VXGE_RTI_RTIMER_ADAPT_VAL) { 21558c2ecf20Sopenharmony_ci hw_ring->rtimer = VXGE_RTI_RTIMER_ADAPT_VAL; 21568c2ecf20Sopenharmony_ci vxge_hw_vpath_dynamic_rti_rtimer_set(hw_ring); 21578c2ecf20Sopenharmony_ci } else if (hw_ring->rtimer != 0) { 21588c2ecf20Sopenharmony_ci hw_ring->rtimer = 0; 21598c2ecf20Sopenharmony_ci vxge_hw_vpath_dynamic_rti_rtimer_set(hw_ring); 21608c2ecf20Sopenharmony_ci } 21618c2ecf20Sopenharmony_ci ring->interrupt_count = 0; 21628c2ecf20Sopenharmony_ci } 21638c2ecf20Sopenharmony_ci} 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci/* 21668c2ecf20Sopenharmony_ci * vxge_isr_napi 21678c2ecf20Sopenharmony_ci * @irq: the irq of the device. 21688c2ecf20Sopenharmony_ci * @dev_id: a void pointer to the hldev structure of the Titan device 21698c2ecf20Sopenharmony_ci * @ptregs: pointer to the registers pushed on the stack. 21708c2ecf20Sopenharmony_ci * 21718c2ecf20Sopenharmony_ci * This function is the ISR handler of the device when napi is enabled. It 21728c2ecf20Sopenharmony_ci * identifies the reason for the interrupt and calls the relevant service 21738c2ecf20Sopenharmony_ci * routines. 21748c2ecf20Sopenharmony_ci */ 21758c2ecf20Sopenharmony_cistatic irqreturn_t vxge_isr_napi(int irq, void *dev_id) 21768c2ecf20Sopenharmony_ci{ 21778c2ecf20Sopenharmony_ci struct __vxge_hw_device *hldev; 21788c2ecf20Sopenharmony_ci u64 reason; 21798c2ecf20Sopenharmony_ci enum vxge_hw_status status; 21808c2ecf20Sopenharmony_ci struct vxgedev *vdev = (struct vxgedev *)dev_id; 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci vxge_debug_intr(VXGE_TRACE, "%s:%d", __func__, __LINE__); 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci hldev = pci_get_drvdata(vdev->pdev); 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci if (pci_channel_offline(vdev->pdev)) 21878c2ecf20Sopenharmony_ci return IRQ_NONE; 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci if (unlikely(!is_vxge_card_up(vdev))) 21908c2ecf20Sopenharmony_ci return IRQ_HANDLED; 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci status = vxge_hw_device_begin_irq(hldev, vdev->exec_mode, &reason); 21938c2ecf20Sopenharmony_ci if (status == VXGE_HW_OK) { 21948c2ecf20Sopenharmony_ci vxge_hw_device_mask_all(hldev); 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci if (reason & 21978c2ecf20Sopenharmony_ci VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_TRAFFIC_INT( 21988c2ecf20Sopenharmony_ci vdev->vpaths_deployed >> 21998c2ecf20Sopenharmony_ci (64 - VXGE_HW_MAX_VIRTUAL_PATHS))) { 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci vxge_hw_device_clear_tx_rx(hldev); 22028c2ecf20Sopenharmony_ci napi_schedule(&vdev->napi); 22038c2ecf20Sopenharmony_ci vxge_debug_intr(VXGE_TRACE, 22048c2ecf20Sopenharmony_ci "%s:%d Exiting...", __func__, __LINE__); 22058c2ecf20Sopenharmony_ci return IRQ_HANDLED; 22068c2ecf20Sopenharmony_ci } else 22078c2ecf20Sopenharmony_ci vxge_hw_device_unmask_all(hldev); 22088c2ecf20Sopenharmony_ci } else if (unlikely((status == VXGE_HW_ERR_VPATH) || 22098c2ecf20Sopenharmony_ci (status == VXGE_HW_ERR_CRITICAL) || 22108c2ecf20Sopenharmony_ci (status == VXGE_HW_ERR_FIFO))) { 22118c2ecf20Sopenharmony_ci vxge_hw_device_mask_all(hldev); 22128c2ecf20Sopenharmony_ci vxge_hw_device_flush_io(hldev); 22138c2ecf20Sopenharmony_ci return IRQ_HANDLED; 22148c2ecf20Sopenharmony_ci } else if (unlikely(status == VXGE_HW_ERR_SLOT_FREEZE)) 22158c2ecf20Sopenharmony_ci return IRQ_HANDLED; 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci vxge_debug_intr(VXGE_TRACE, "%s:%d Exiting...", __func__, __LINE__); 22188c2ecf20Sopenharmony_ci return IRQ_NONE; 22198c2ecf20Sopenharmony_ci} 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_cistatic irqreturn_t vxge_tx_msix_handle(int irq, void *dev_id) 22228c2ecf20Sopenharmony_ci{ 22238c2ecf20Sopenharmony_ci struct vxge_fifo *fifo = (struct vxge_fifo *)dev_id; 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci adaptive_coalesce_tx_interrupts(fifo); 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci vxge_hw_channel_msix_mask((struct __vxge_hw_channel *)fifo->handle, 22288c2ecf20Sopenharmony_ci fifo->tx_vector_no); 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci vxge_hw_channel_msix_clear((struct __vxge_hw_channel *)fifo->handle, 22318c2ecf20Sopenharmony_ci fifo->tx_vector_no); 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci VXGE_COMPLETE_VPATH_TX(fifo); 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci vxge_hw_channel_msix_unmask((struct __vxge_hw_channel *)fifo->handle, 22368c2ecf20Sopenharmony_ci fifo->tx_vector_no); 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci return IRQ_HANDLED; 22398c2ecf20Sopenharmony_ci} 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_cistatic irqreturn_t vxge_rx_msix_napi_handle(int irq, void *dev_id) 22428c2ecf20Sopenharmony_ci{ 22438c2ecf20Sopenharmony_ci struct vxge_ring *ring = (struct vxge_ring *)dev_id; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci adaptive_coalesce_rx_interrupts(ring); 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci vxge_hw_channel_msix_mask((struct __vxge_hw_channel *)ring->handle, 22488c2ecf20Sopenharmony_ci ring->rx_vector_no); 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci vxge_hw_channel_msix_clear((struct __vxge_hw_channel *)ring->handle, 22518c2ecf20Sopenharmony_ci ring->rx_vector_no); 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_ci napi_schedule(&ring->napi); 22548c2ecf20Sopenharmony_ci return IRQ_HANDLED; 22558c2ecf20Sopenharmony_ci} 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_cistatic irqreturn_t 22588c2ecf20Sopenharmony_civxge_alarm_msix_handle(int irq, void *dev_id) 22598c2ecf20Sopenharmony_ci{ 22608c2ecf20Sopenharmony_ci int i; 22618c2ecf20Sopenharmony_ci enum vxge_hw_status status; 22628c2ecf20Sopenharmony_ci struct vxge_vpath *vpath = (struct vxge_vpath *)dev_id; 22638c2ecf20Sopenharmony_ci struct vxgedev *vdev = vpath->vdev; 22648c2ecf20Sopenharmony_ci int msix_id = (vpath->handle->vpath->vp_id * 22658c2ecf20Sopenharmony_ci VXGE_HW_VPATH_MSIX_ACTIVE) + VXGE_ALARM_MSIX_ID; 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 22688c2ecf20Sopenharmony_ci /* Reduce the chance of losing alarm interrupts by masking 22698c2ecf20Sopenharmony_ci * the vector. A pending bit will be set if an alarm is 22708c2ecf20Sopenharmony_ci * generated and on unmask the interrupt will be fired. 22718c2ecf20Sopenharmony_ci */ 22728c2ecf20Sopenharmony_ci vxge_hw_vpath_msix_mask(vdev->vpaths[i].handle, msix_id); 22738c2ecf20Sopenharmony_ci vxge_hw_vpath_msix_clear(vdev->vpaths[i].handle, msix_id); 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ci status = vxge_hw_vpath_alarm_process(vdev->vpaths[i].handle, 22768c2ecf20Sopenharmony_ci vdev->exec_mode); 22778c2ecf20Sopenharmony_ci if (status == VXGE_HW_OK) { 22788c2ecf20Sopenharmony_ci vxge_hw_vpath_msix_unmask(vdev->vpaths[i].handle, 22798c2ecf20Sopenharmony_ci msix_id); 22808c2ecf20Sopenharmony_ci continue; 22818c2ecf20Sopenharmony_ci } 22828c2ecf20Sopenharmony_ci vxge_debug_intr(VXGE_ERR, 22838c2ecf20Sopenharmony_ci "%s: vxge_hw_vpath_alarm_process failed %x ", 22848c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME, status); 22858c2ecf20Sopenharmony_ci } 22868c2ecf20Sopenharmony_ci return IRQ_HANDLED; 22878c2ecf20Sopenharmony_ci} 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_cistatic int vxge_alloc_msix(struct vxgedev *vdev) 22908c2ecf20Sopenharmony_ci{ 22918c2ecf20Sopenharmony_ci int j, i, ret = 0; 22928c2ecf20Sopenharmony_ci int msix_intr_vect = 0, temp; 22938c2ecf20Sopenharmony_ci vdev->intr_cnt = 0; 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_cistart: 22968c2ecf20Sopenharmony_ci /* Tx/Rx MSIX Vectors count */ 22978c2ecf20Sopenharmony_ci vdev->intr_cnt = vdev->no_of_vpath * 2; 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci /* Alarm MSIX Vectors count */ 23008c2ecf20Sopenharmony_ci vdev->intr_cnt++; 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci vdev->entries = kcalloc(vdev->intr_cnt, sizeof(struct msix_entry), 23038c2ecf20Sopenharmony_ci GFP_KERNEL); 23048c2ecf20Sopenharmony_ci if (!vdev->entries) { 23058c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 23068c2ecf20Sopenharmony_ci "%s: memory allocation failed", 23078c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME); 23088c2ecf20Sopenharmony_ci ret = -ENOMEM; 23098c2ecf20Sopenharmony_ci goto alloc_entries_failed; 23108c2ecf20Sopenharmony_ci } 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci vdev->vxge_entries = kcalloc(vdev->intr_cnt, 23138c2ecf20Sopenharmony_ci sizeof(struct vxge_msix_entry), 23148c2ecf20Sopenharmony_ci GFP_KERNEL); 23158c2ecf20Sopenharmony_ci if (!vdev->vxge_entries) { 23168c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, "%s: memory allocation failed", 23178c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME); 23188c2ecf20Sopenharmony_ci ret = -ENOMEM; 23198c2ecf20Sopenharmony_ci goto alloc_vxge_entries_failed; 23208c2ecf20Sopenharmony_ci } 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci for (i = 0, j = 0; i < vdev->no_of_vpath; i++) { 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci msix_intr_vect = i * VXGE_HW_VPATH_MSIX_ACTIVE; 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci /* Initialize the fifo vector */ 23278c2ecf20Sopenharmony_ci vdev->entries[j].entry = msix_intr_vect; 23288c2ecf20Sopenharmony_ci vdev->vxge_entries[j].entry = msix_intr_vect; 23298c2ecf20Sopenharmony_ci vdev->vxge_entries[j].in_use = 0; 23308c2ecf20Sopenharmony_ci j++; 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci /* Initialize the ring vector */ 23338c2ecf20Sopenharmony_ci vdev->entries[j].entry = msix_intr_vect + 1; 23348c2ecf20Sopenharmony_ci vdev->vxge_entries[j].entry = msix_intr_vect + 1; 23358c2ecf20Sopenharmony_ci vdev->vxge_entries[j].in_use = 0; 23368c2ecf20Sopenharmony_ci j++; 23378c2ecf20Sopenharmony_ci } 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci /* Initialize the alarm vector */ 23408c2ecf20Sopenharmony_ci vdev->entries[j].entry = VXGE_ALARM_MSIX_ID; 23418c2ecf20Sopenharmony_ci vdev->vxge_entries[j].entry = VXGE_ALARM_MSIX_ID; 23428c2ecf20Sopenharmony_ci vdev->vxge_entries[j].in_use = 0; 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci ret = pci_enable_msix_range(vdev->pdev, 23458c2ecf20Sopenharmony_ci vdev->entries, 3, vdev->intr_cnt); 23468c2ecf20Sopenharmony_ci if (ret < 0) { 23478c2ecf20Sopenharmony_ci ret = -ENODEV; 23488c2ecf20Sopenharmony_ci goto enable_msix_failed; 23498c2ecf20Sopenharmony_ci } else if (ret < vdev->intr_cnt) { 23508c2ecf20Sopenharmony_ci pci_disable_msix(vdev->pdev); 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 23538c2ecf20Sopenharmony_ci "%s: MSI-X enable failed for %d vectors, ret: %d", 23548c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME, vdev->intr_cnt, ret); 23558c2ecf20Sopenharmony_ci if (max_config_vpath != VXGE_USE_DEFAULT) { 23568c2ecf20Sopenharmony_ci ret = -ENODEV; 23578c2ecf20Sopenharmony_ci goto enable_msix_failed; 23588c2ecf20Sopenharmony_ci } 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci kfree(vdev->entries); 23618c2ecf20Sopenharmony_ci kfree(vdev->vxge_entries); 23628c2ecf20Sopenharmony_ci vdev->entries = NULL; 23638c2ecf20Sopenharmony_ci vdev->vxge_entries = NULL; 23648c2ecf20Sopenharmony_ci /* Try with less no of vector by reducing no of vpaths count */ 23658c2ecf20Sopenharmony_ci temp = (ret - 1)/2; 23668c2ecf20Sopenharmony_ci vxge_close_vpaths(vdev, temp); 23678c2ecf20Sopenharmony_ci vdev->no_of_vpath = temp; 23688c2ecf20Sopenharmony_ci goto start; 23698c2ecf20Sopenharmony_ci } 23708c2ecf20Sopenharmony_ci return 0; 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_cienable_msix_failed: 23738c2ecf20Sopenharmony_ci kfree(vdev->vxge_entries); 23748c2ecf20Sopenharmony_cialloc_vxge_entries_failed: 23758c2ecf20Sopenharmony_ci kfree(vdev->entries); 23768c2ecf20Sopenharmony_cialloc_entries_failed: 23778c2ecf20Sopenharmony_ci return ret; 23788c2ecf20Sopenharmony_ci} 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_cistatic int vxge_enable_msix(struct vxgedev *vdev) 23818c2ecf20Sopenharmony_ci{ 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci int i, ret = 0; 23848c2ecf20Sopenharmony_ci /* 0 - Tx, 1 - Rx */ 23858c2ecf20Sopenharmony_ci int tim_msix_id[4] = {0, 1, 0, 0}; 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci vdev->intr_cnt = 0; 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci /* allocate msix vectors */ 23908c2ecf20Sopenharmony_ci ret = vxge_alloc_msix(vdev); 23918c2ecf20Sopenharmony_ci if (!ret) { 23928c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 23938c2ecf20Sopenharmony_ci struct vxge_vpath *vpath = &vdev->vpaths[i]; 23948c2ecf20Sopenharmony_ci 23958c2ecf20Sopenharmony_ci /* If fifo or ring are not enabled, the MSIX vector for 23968c2ecf20Sopenharmony_ci * it should be set to 0. 23978c2ecf20Sopenharmony_ci */ 23988c2ecf20Sopenharmony_ci vpath->ring.rx_vector_no = (vpath->device_id * 23998c2ecf20Sopenharmony_ci VXGE_HW_VPATH_MSIX_ACTIVE) + 1; 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_ci vpath->fifo.tx_vector_no = (vpath->device_id * 24028c2ecf20Sopenharmony_ci VXGE_HW_VPATH_MSIX_ACTIVE); 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci vxge_hw_vpath_msix_set(vpath->handle, tim_msix_id, 24058c2ecf20Sopenharmony_ci VXGE_ALARM_MSIX_ID); 24068c2ecf20Sopenharmony_ci } 24078c2ecf20Sopenharmony_ci } 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci return ret; 24108c2ecf20Sopenharmony_ci} 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_cistatic void vxge_rem_msix_isr(struct vxgedev *vdev) 24138c2ecf20Sopenharmony_ci{ 24148c2ecf20Sopenharmony_ci int intr_cnt; 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci for (intr_cnt = 0; intr_cnt < (vdev->no_of_vpath * 2 + 1); 24178c2ecf20Sopenharmony_ci intr_cnt++) { 24188c2ecf20Sopenharmony_ci if (vdev->vxge_entries[intr_cnt].in_use) { 24198c2ecf20Sopenharmony_ci synchronize_irq(vdev->entries[intr_cnt].vector); 24208c2ecf20Sopenharmony_ci free_irq(vdev->entries[intr_cnt].vector, 24218c2ecf20Sopenharmony_ci vdev->vxge_entries[intr_cnt].arg); 24228c2ecf20Sopenharmony_ci vdev->vxge_entries[intr_cnt].in_use = 0; 24238c2ecf20Sopenharmony_ci } 24248c2ecf20Sopenharmony_ci } 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci kfree(vdev->entries); 24278c2ecf20Sopenharmony_ci kfree(vdev->vxge_entries); 24288c2ecf20Sopenharmony_ci vdev->entries = NULL; 24298c2ecf20Sopenharmony_ci vdev->vxge_entries = NULL; 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_ci if (vdev->config.intr_type == MSI_X) 24328c2ecf20Sopenharmony_ci pci_disable_msix(vdev->pdev); 24338c2ecf20Sopenharmony_ci} 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_cistatic void vxge_rem_isr(struct vxgedev *vdev) 24368c2ecf20Sopenharmony_ci{ 24378c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PCI_MSI) && 24388c2ecf20Sopenharmony_ci vdev->config.intr_type == MSI_X) { 24398c2ecf20Sopenharmony_ci vxge_rem_msix_isr(vdev); 24408c2ecf20Sopenharmony_ci } else if (vdev->config.intr_type == INTA) { 24418c2ecf20Sopenharmony_ci synchronize_irq(vdev->pdev->irq); 24428c2ecf20Sopenharmony_ci free_irq(vdev->pdev->irq, vdev); 24438c2ecf20Sopenharmony_ci } 24448c2ecf20Sopenharmony_ci} 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_cistatic int vxge_add_isr(struct vxgedev *vdev) 24478c2ecf20Sopenharmony_ci{ 24488c2ecf20Sopenharmony_ci int ret = 0; 24498c2ecf20Sopenharmony_ci int vp_idx = 0, intr_idx = 0, intr_cnt = 0, msix_idx = 0, irq_req = 0; 24508c2ecf20Sopenharmony_ci int pci_fun = PCI_FUNC(vdev->pdev->devfn); 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PCI_MSI) && vdev->config.intr_type == MSI_X) 24538c2ecf20Sopenharmony_ci ret = vxge_enable_msix(vdev); 24548c2ecf20Sopenharmony_ci 24558c2ecf20Sopenharmony_ci if (ret) { 24568c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 24578c2ecf20Sopenharmony_ci "%s: Enabling MSI-X Failed", VXGE_DRIVER_NAME); 24588c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 24598c2ecf20Sopenharmony_ci "%s: Defaulting to INTA", VXGE_DRIVER_NAME); 24608c2ecf20Sopenharmony_ci vdev->config.intr_type = INTA; 24618c2ecf20Sopenharmony_ci } 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PCI_MSI) && vdev->config.intr_type == MSI_X) { 24648c2ecf20Sopenharmony_ci for (intr_idx = 0; 24658c2ecf20Sopenharmony_ci intr_idx < (vdev->no_of_vpath * 24668c2ecf20Sopenharmony_ci VXGE_HW_VPATH_MSIX_ACTIVE); intr_idx++) { 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_ci msix_idx = intr_idx % VXGE_HW_VPATH_MSIX_ACTIVE; 24698c2ecf20Sopenharmony_ci irq_req = 0; 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci switch (msix_idx) { 24728c2ecf20Sopenharmony_ci case 0: 24738c2ecf20Sopenharmony_ci snprintf(vdev->desc[intr_cnt], VXGE_INTR_STRLEN, 24748c2ecf20Sopenharmony_ci "%s:vxge:MSI-X %d - Tx - fn:%d vpath:%d", 24758c2ecf20Sopenharmony_ci vdev->ndev->name, 24768c2ecf20Sopenharmony_ci vdev->entries[intr_cnt].entry, 24778c2ecf20Sopenharmony_ci pci_fun, vp_idx); 24788c2ecf20Sopenharmony_ci ret = request_irq( 24798c2ecf20Sopenharmony_ci vdev->entries[intr_cnt].vector, 24808c2ecf20Sopenharmony_ci vxge_tx_msix_handle, 0, 24818c2ecf20Sopenharmony_ci vdev->desc[intr_cnt], 24828c2ecf20Sopenharmony_ci &vdev->vpaths[vp_idx].fifo); 24838c2ecf20Sopenharmony_ci vdev->vxge_entries[intr_cnt].arg = 24848c2ecf20Sopenharmony_ci &vdev->vpaths[vp_idx].fifo; 24858c2ecf20Sopenharmony_ci irq_req = 1; 24868c2ecf20Sopenharmony_ci break; 24878c2ecf20Sopenharmony_ci case 1: 24888c2ecf20Sopenharmony_ci snprintf(vdev->desc[intr_cnt], VXGE_INTR_STRLEN, 24898c2ecf20Sopenharmony_ci "%s:vxge:MSI-X %d - Rx - fn:%d vpath:%d", 24908c2ecf20Sopenharmony_ci vdev->ndev->name, 24918c2ecf20Sopenharmony_ci vdev->entries[intr_cnt].entry, 24928c2ecf20Sopenharmony_ci pci_fun, vp_idx); 24938c2ecf20Sopenharmony_ci ret = request_irq( 24948c2ecf20Sopenharmony_ci vdev->entries[intr_cnt].vector, 24958c2ecf20Sopenharmony_ci vxge_rx_msix_napi_handle, 0, 24968c2ecf20Sopenharmony_ci vdev->desc[intr_cnt], 24978c2ecf20Sopenharmony_ci &vdev->vpaths[vp_idx].ring); 24988c2ecf20Sopenharmony_ci vdev->vxge_entries[intr_cnt].arg = 24998c2ecf20Sopenharmony_ci &vdev->vpaths[vp_idx].ring; 25008c2ecf20Sopenharmony_ci irq_req = 1; 25018c2ecf20Sopenharmony_ci break; 25028c2ecf20Sopenharmony_ci } 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_ci if (ret) { 25058c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 25068c2ecf20Sopenharmony_ci "%s: MSIX - %d Registration failed", 25078c2ecf20Sopenharmony_ci vdev->ndev->name, intr_cnt); 25088c2ecf20Sopenharmony_ci vxge_rem_msix_isr(vdev); 25098c2ecf20Sopenharmony_ci vdev->config.intr_type = INTA; 25108c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 25118c2ecf20Sopenharmony_ci "%s: Defaulting to INTA", 25128c2ecf20Sopenharmony_ci vdev->ndev->name); 25138c2ecf20Sopenharmony_ci goto INTA_MODE; 25148c2ecf20Sopenharmony_ci } 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci if (irq_req) { 25178c2ecf20Sopenharmony_ci /* We requested for this msix interrupt */ 25188c2ecf20Sopenharmony_ci vdev->vxge_entries[intr_cnt].in_use = 1; 25198c2ecf20Sopenharmony_ci msix_idx += vdev->vpaths[vp_idx].device_id * 25208c2ecf20Sopenharmony_ci VXGE_HW_VPATH_MSIX_ACTIVE; 25218c2ecf20Sopenharmony_ci vxge_hw_vpath_msix_unmask( 25228c2ecf20Sopenharmony_ci vdev->vpaths[vp_idx].handle, 25238c2ecf20Sopenharmony_ci msix_idx); 25248c2ecf20Sopenharmony_ci intr_cnt++; 25258c2ecf20Sopenharmony_ci } 25268c2ecf20Sopenharmony_ci 25278c2ecf20Sopenharmony_ci /* Point to next vpath handler */ 25288c2ecf20Sopenharmony_ci if (((intr_idx + 1) % VXGE_HW_VPATH_MSIX_ACTIVE == 0) && 25298c2ecf20Sopenharmony_ci (vp_idx < (vdev->no_of_vpath - 1))) 25308c2ecf20Sopenharmony_ci vp_idx++; 25318c2ecf20Sopenharmony_ci } 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci intr_cnt = vdev->no_of_vpath * 2; 25348c2ecf20Sopenharmony_ci snprintf(vdev->desc[intr_cnt], VXGE_INTR_STRLEN, 25358c2ecf20Sopenharmony_ci "%s:vxge:MSI-X %d - Alarm - fn:%d", 25368c2ecf20Sopenharmony_ci vdev->ndev->name, 25378c2ecf20Sopenharmony_ci vdev->entries[intr_cnt].entry, 25388c2ecf20Sopenharmony_ci pci_fun); 25398c2ecf20Sopenharmony_ci /* For Alarm interrupts */ 25408c2ecf20Sopenharmony_ci ret = request_irq(vdev->entries[intr_cnt].vector, 25418c2ecf20Sopenharmony_ci vxge_alarm_msix_handle, 0, 25428c2ecf20Sopenharmony_ci vdev->desc[intr_cnt], 25438c2ecf20Sopenharmony_ci &vdev->vpaths[0]); 25448c2ecf20Sopenharmony_ci if (ret) { 25458c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 25468c2ecf20Sopenharmony_ci "%s: MSIX - %d Registration failed", 25478c2ecf20Sopenharmony_ci vdev->ndev->name, intr_cnt); 25488c2ecf20Sopenharmony_ci vxge_rem_msix_isr(vdev); 25498c2ecf20Sopenharmony_ci vdev->config.intr_type = INTA; 25508c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 25518c2ecf20Sopenharmony_ci "%s: Defaulting to INTA", 25528c2ecf20Sopenharmony_ci vdev->ndev->name); 25538c2ecf20Sopenharmony_ci goto INTA_MODE; 25548c2ecf20Sopenharmony_ci } 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_ci msix_idx = (vdev->vpaths[0].handle->vpath->vp_id * 25578c2ecf20Sopenharmony_ci VXGE_HW_VPATH_MSIX_ACTIVE) + VXGE_ALARM_MSIX_ID; 25588c2ecf20Sopenharmony_ci vxge_hw_vpath_msix_unmask(vdev->vpaths[vp_idx].handle, 25598c2ecf20Sopenharmony_ci msix_idx); 25608c2ecf20Sopenharmony_ci vdev->vxge_entries[intr_cnt].in_use = 1; 25618c2ecf20Sopenharmony_ci vdev->vxge_entries[intr_cnt].arg = &vdev->vpaths[0]; 25628c2ecf20Sopenharmony_ci } 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ciINTA_MODE: 25658c2ecf20Sopenharmony_ci if (vdev->config.intr_type == INTA) { 25668c2ecf20Sopenharmony_ci snprintf(vdev->desc[0], VXGE_INTR_STRLEN, 25678c2ecf20Sopenharmony_ci "%s:vxge:INTA", vdev->ndev->name); 25688c2ecf20Sopenharmony_ci vxge_hw_device_set_intr_type(vdev->devh, 25698c2ecf20Sopenharmony_ci VXGE_HW_INTR_MODE_IRQLINE); 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci vxge_hw_vpath_tti_ci_set(vdev->vpaths[0].fifo.handle); 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci ret = request_irq((int) vdev->pdev->irq, 25748c2ecf20Sopenharmony_ci vxge_isr_napi, 25758c2ecf20Sopenharmony_ci IRQF_SHARED, vdev->desc[0], vdev); 25768c2ecf20Sopenharmony_ci if (ret) { 25778c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 25788c2ecf20Sopenharmony_ci "%s %s-%d: ISR registration failed", 25798c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME, "IRQ", vdev->pdev->irq); 25808c2ecf20Sopenharmony_ci return -ENODEV; 25818c2ecf20Sopenharmony_ci } 25828c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 25838c2ecf20Sopenharmony_ci "new %s-%d line allocated", 25848c2ecf20Sopenharmony_ci "IRQ", vdev->pdev->irq); 25858c2ecf20Sopenharmony_ci } 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci return VXGE_HW_OK; 25888c2ecf20Sopenharmony_ci} 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_cistatic void vxge_poll_vp_reset(struct timer_list *t) 25918c2ecf20Sopenharmony_ci{ 25928c2ecf20Sopenharmony_ci struct vxgedev *vdev = from_timer(vdev, t, vp_reset_timer); 25938c2ecf20Sopenharmony_ci int i, j = 0; 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 25968c2ecf20Sopenharmony_ci if (test_bit(i, &vdev->vp_reset)) { 25978c2ecf20Sopenharmony_ci vxge_reset_vpath(vdev, i); 25988c2ecf20Sopenharmony_ci j++; 25998c2ecf20Sopenharmony_ci } 26008c2ecf20Sopenharmony_ci } 26018c2ecf20Sopenharmony_ci if (j && (vdev->config.intr_type != MSI_X)) { 26028c2ecf20Sopenharmony_ci vxge_hw_device_unmask_all(vdev->devh); 26038c2ecf20Sopenharmony_ci vxge_hw_device_flush_io(vdev->devh); 26048c2ecf20Sopenharmony_ci } 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci mod_timer(&vdev->vp_reset_timer, jiffies + HZ / 2); 26078c2ecf20Sopenharmony_ci} 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_cistatic void vxge_poll_vp_lockup(struct timer_list *t) 26108c2ecf20Sopenharmony_ci{ 26118c2ecf20Sopenharmony_ci struct vxgedev *vdev = from_timer(vdev, t, vp_lockup_timer); 26128c2ecf20Sopenharmony_ci enum vxge_hw_status status = VXGE_HW_OK; 26138c2ecf20Sopenharmony_ci struct vxge_vpath *vpath; 26148c2ecf20Sopenharmony_ci struct vxge_ring *ring; 26158c2ecf20Sopenharmony_ci int i; 26168c2ecf20Sopenharmony_ci unsigned long rx_frms; 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 26198c2ecf20Sopenharmony_ci ring = &vdev->vpaths[i].ring; 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci /* Truncated to machine word size number of frames */ 26228c2ecf20Sopenharmony_ci rx_frms = READ_ONCE(ring->stats.rx_frms); 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci /* Did this vpath received any packets */ 26258c2ecf20Sopenharmony_ci if (ring->stats.prev_rx_frms == rx_frms) { 26268c2ecf20Sopenharmony_ci status = vxge_hw_vpath_check_leak(ring->handle); 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci /* Did it received any packets last time */ 26298c2ecf20Sopenharmony_ci if ((VXGE_HW_FAIL == status) && 26308c2ecf20Sopenharmony_ci (VXGE_HW_FAIL == ring->last_status)) { 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci /* schedule vpath reset */ 26338c2ecf20Sopenharmony_ci if (!test_and_set_bit(i, &vdev->vp_reset)) { 26348c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[i]; 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_ci /* disable interrupts for this vpath */ 26378c2ecf20Sopenharmony_ci vxge_vpath_intr_disable(vdev, i); 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_ci /* stop the queue for this vpath */ 26408c2ecf20Sopenharmony_ci netif_tx_stop_queue(vpath->fifo.txq); 26418c2ecf20Sopenharmony_ci continue; 26428c2ecf20Sopenharmony_ci } 26438c2ecf20Sopenharmony_ci } 26448c2ecf20Sopenharmony_ci } 26458c2ecf20Sopenharmony_ci ring->stats.prev_rx_frms = rx_frms; 26468c2ecf20Sopenharmony_ci ring->last_status = status; 26478c2ecf20Sopenharmony_ci } 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci /* Check every 1 milli second */ 26508c2ecf20Sopenharmony_ci mod_timer(&vdev->vp_lockup_timer, jiffies + HZ / 1000); 26518c2ecf20Sopenharmony_ci} 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_cistatic netdev_features_t vxge_fix_features(struct net_device *dev, 26548c2ecf20Sopenharmony_ci netdev_features_t features) 26558c2ecf20Sopenharmony_ci{ 26568c2ecf20Sopenharmony_ci netdev_features_t changed = dev->features ^ features; 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci /* Enabling RTH requires some of the logic in vxge_device_register and a 26598c2ecf20Sopenharmony_ci * vpath reset. Due to these restrictions, only allow modification 26608c2ecf20Sopenharmony_ci * while the interface is down. 26618c2ecf20Sopenharmony_ci */ 26628c2ecf20Sopenharmony_ci if ((changed & NETIF_F_RXHASH) && netif_running(dev)) 26638c2ecf20Sopenharmony_ci features ^= NETIF_F_RXHASH; 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_ci return features; 26668c2ecf20Sopenharmony_ci} 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_cistatic int vxge_set_features(struct net_device *dev, netdev_features_t features) 26698c2ecf20Sopenharmony_ci{ 26708c2ecf20Sopenharmony_ci struct vxgedev *vdev = netdev_priv(dev); 26718c2ecf20Sopenharmony_ci netdev_features_t changed = dev->features ^ features; 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci if (!(changed & NETIF_F_RXHASH)) 26748c2ecf20Sopenharmony_ci return 0; 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci /* !netif_running() ensured by vxge_fix_features() */ 26778c2ecf20Sopenharmony_ci 26788c2ecf20Sopenharmony_ci vdev->devh->config.rth_en = !!(features & NETIF_F_RXHASH); 26798c2ecf20Sopenharmony_ci if (vxge_reset_all_vpaths(vdev) != VXGE_HW_OK) { 26808c2ecf20Sopenharmony_ci dev->features = features ^ NETIF_F_RXHASH; 26818c2ecf20Sopenharmony_ci vdev->devh->config.rth_en = !!(dev->features & NETIF_F_RXHASH); 26828c2ecf20Sopenharmony_ci return -EIO; 26838c2ecf20Sopenharmony_ci } 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci return 0; 26868c2ecf20Sopenharmony_ci} 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci/** 26898c2ecf20Sopenharmony_ci * vxge_open 26908c2ecf20Sopenharmony_ci * @dev: pointer to the device structure. 26918c2ecf20Sopenharmony_ci * 26928c2ecf20Sopenharmony_ci * This function is the open entry point of the driver. It mainly calls a 26938c2ecf20Sopenharmony_ci * function to allocate Rx buffers and inserts them into the buffer 26948c2ecf20Sopenharmony_ci * descriptors and then enables the Rx part of the NIC. 26958c2ecf20Sopenharmony_ci * Return value: '0' on success and an appropriate (-)ve integer as 26968c2ecf20Sopenharmony_ci * defined in errno.h file on failure. 26978c2ecf20Sopenharmony_ci */ 26988c2ecf20Sopenharmony_cistatic int vxge_open(struct net_device *dev) 26998c2ecf20Sopenharmony_ci{ 27008c2ecf20Sopenharmony_ci enum vxge_hw_status status; 27018c2ecf20Sopenharmony_ci struct vxgedev *vdev; 27028c2ecf20Sopenharmony_ci struct __vxge_hw_device *hldev; 27038c2ecf20Sopenharmony_ci struct vxge_vpath *vpath; 27048c2ecf20Sopenharmony_ci int ret = 0; 27058c2ecf20Sopenharmony_ci int i; 27068c2ecf20Sopenharmony_ci u64 val64; 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 27098c2ecf20Sopenharmony_ci "%s: %s:%d", dev->name, __func__, __LINE__); 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci vdev = netdev_priv(dev); 27128c2ecf20Sopenharmony_ci hldev = pci_get_drvdata(vdev->pdev); 27138c2ecf20Sopenharmony_ci 27148c2ecf20Sopenharmony_ci /* make sure you have link off by default every time Nic is 27158c2ecf20Sopenharmony_ci * initialized */ 27168c2ecf20Sopenharmony_ci netif_carrier_off(dev); 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci /* Open VPATHs */ 27198c2ecf20Sopenharmony_ci status = vxge_open_vpaths(vdev); 27208c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 27218c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 27228c2ecf20Sopenharmony_ci "%s: fatal: Vpath open failed", vdev->ndev->name); 27238c2ecf20Sopenharmony_ci ret = -EPERM; 27248c2ecf20Sopenharmony_ci goto out0; 27258c2ecf20Sopenharmony_ci } 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci vdev->mtu = dev->mtu; 27288c2ecf20Sopenharmony_ci 27298c2ecf20Sopenharmony_ci status = vxge_add_isr(vdev); 27308c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 27318c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 27328c2ecf20Sopenharmony_ci "%s: fatal: ISR add failed", dev->name); 27338c2ecf20Sopenharmony_ci ret = -EPERM; 27348c2ecf20Sopenharmony_ci goto out1; 27358c2ecf20Sopenharmony_ci } 27368c2ecf20Sopenharmony_ci 27378c2ecf20Sopenharmony_ci if (vdev->config.intr_type != MSI_X) { 27388c2ecf20Sopenharmony_ci netif_napi_add(dev, &vdev->napi, vxge_poll_inta, 27398c2ecf20Sopenharmony_ci vdev->config.napi_weight); 27408c2ecf20Sopenharmony_ci napi_enable(&vdev->napi); 27418c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 27428c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[i]; 27438c2ecf20Sopenharmony_ci vpath->ring.napi_p = &vdev->napi; 27448c2ecf20Sopenharmony_ci } 27458c2ecf20Sopenharmony_ci } else { 27468c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 27478c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[i]; 27488c2ecf20Sopenharmony_ci netif_napi_add(dev, &vpath->ring.napi, 27498c2ecf20Sopenharmony_ci vxge_poll_msix, vdev->config.napi_weight); 27508c2ecf20Sopenharmony_ci napi_enable(&vpath->ring.napi); 27518c2ecf20Sopenharmony_ci vpath->ring.napi_p = &vpath->ring.napi; 27528c2ecf20Sopenharmony_ci } 27538c2ecf20Sopenharmony_ci } 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_ci /* configure RTH */ 27568c2ecf20Sopenharmony_ci if (vdev->config.rth_steering) { 27578c2ecf20Sopenharmony_ci status = vxge_rth_configure(vdev); 27588c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 27598c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 27608c2ecf20Sopenharmony_ci "%s: fatal: RTH configuration failed", 27618c2ecf20Sopenharmony_ci dev->name); 27628c2ecf20Sopenharmony_ci ret = -EPERM; 27638c2ecf20Sopenharmony_ci goto out2; 27648c2ecf20Sopenharmony_ci } 27658c2ecf20Sopenharmony_ci } 27668c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Receive Hashing Offload %s\n", dev->name, 27678c2ecf20Sopenharmony_ci hldev->config.rth_en ? "enabled" : "disabled"); 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 27708c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[i]; 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci /* set initial mtu before enabling the device */ 27738c2ecf20Sopenharmony_ci status = vxge_hw_vpath_mtu_set(vpath->handle, vdev->mtu); 27748c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 27758c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 27768c2ecf20Sopenharmony_ci "%s: fatal: can not set new MTU", dev->name); 27778c2ecf20Sopenharmony_ci ret = -EPERM; 27788c2ecf20Sopenharmony_ci goto out2; 27798c2ecf20Sopenharmony_ci } 27808c2ecf20Sopenharmony_ci } 27818c2ecf20Sopenharmony_ci 27828c2ecf20Sopenharmony_ci VXGE_DEVICE_DEBUG_LEVEL_SET(VXGE_TRACE, VXGE_COMPONENT_LL, vdev); 27838c2ecf20Sopenharmony_ci vxge_debug_init(vdev->level_trace, 27848c2ecf20Sopenharmony_ci "%s: MTU is %d", vdev->ndev->name, vdev->mtu); 27858c2ecf20Sopenharmony_ci VXGE_DEVICE_DEBUG_LEVEL_SET(VXGE_ERR, VXGE_COMPONENT_LL, vdev); 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_ci /* Restore the DA, VID table and also multicast and promiscuous mode 27888c2ecf20Sopenharmony_ci * states 27898c2ecf20Sopenharmony_ci */ 27908c2ecf20Sopenharmony_ci if (vdev->all_multi_flg) { 27918c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 27928c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[i]; 27938c2ecf20Sopenharmony_ci vxge_restore_vpath_mac_addr(vpath); 27948c2ecf20Sopenharmony_ci vxge_restore_vpath_vid_table(vpath); 27958c2ecf20Sopenharmony_ci 27968c2ecf20Sopenharmony_ci status = vxge_hw_vpath_mcast_enable(vpath->handle); 27978c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) 27988c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 27998c2ecf20Sopenharmony_ci "%s:%d Enabling multicast failed", 28008c2ecf20Sopenharmony_ci __func__, __LINE__); 28018c2ecf20Sopenharmony_ci } 28028c2ecf20Sopenharmony_ci } 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_ci /* Enable vpath to sniff all unicast/multicast traffic that not 28058c2ecf20Sopenharmony_ci * addressed to them. We allow promiscuous mode for PF only 28068c2ecf20Sopenharmony_ci */ 28078c2ecf20Sopenharmony_ci 28088c2ecf20Sopenharmony_ci val64 = 0; 28098c2ecf20Sopenharmony_ci for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) 28108c2ecf20Sopenharmony_ci val64 |= VXGE_HW_RXMAC_AUTHORIZE_ALL_ADDR_VP(i); 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci vxge_hw_mgmt_reg_write(vdev->devh, 28138c2ecf20Sopenharmony_ci vxge_hw_mgmt_reg_type_mrpcim, 28148c2ecf20Sopenharmony_ci 0, 28158c2ecf20Sopenharmony_ci (ulong)offsetof(struct vxge_hw_mrpcim_reg, 28168c2ecf20Sopenharmony_ci rxmac_authorize_all_addr), 28178c2ecf20Sopenharmony_ci val64); 28188c2ecf20Sopenharmony_ci 28198c2ecf20Sopenharmony_ci vxge_hw_mgmt_reg_write(vdev->devh, 28208c2ecf20Sopenharmony_ci vxge_hw_mgmt_reg_type_mrpcim, 28218c2ecf20Sopenharmony_ci 0, 28228c2ecf20Sopenharmony_ci (ulong)offsetof(struct vxge_hw_mrpcim_reg, 28238c2ecf20Sopenharmony_ci rxmac_authorize_all_vid), 28248c2ecf20Sopenharmony_ci val64); 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_ci vxge_set_multicast(dev); 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_ci /* Enabling Bcast and mcast for all vpath */ 28298c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 28308c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[i]; 28318c2ecf20Sopenharmony_ci status = vxge_hw_vpath_bcast_enable(vpath->handle); 28328c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) 28338c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 28348c2ecf20Sopenharmony_ci "%s : Can not enable bcast for vpath " 28358c2ecf20Sopenharmony_ci "id %d", dev->name, i); 28368c2ecf20Sopenharmony_ci if (vdev->config.addr_learn_en) { 28378c2ecf20Sopenharmony_ci status = vxge_hw_vpath_mcast_enable(vpath->handle); 28388c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) 28398c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 28408c2ecf20Sopenharmony_ci "%s : Can not enable mcast for vpath " 28418c2ecf20Sopenharmony_ci "id %d", dev->name, i); 28428c2ecf20Sopenharmony_ci } 28438c2ecf20Sopenharmony_ci } 28448c2ecf20Sopenharmony_ci 28458c2ecf20Sopenharmony_ci vxge_hw_device_setpause_data(vdev->devh, 0, 28468c2ecf20Sopenharmony_ci vdev->config.tx_pause_enable, 28478c2ecf20Sopenharmony_ci vdev->config.rx_pause_enable); 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_ci if (vdev->vp_reset_timer.function == NULL) 28508c2ecf20Sopenharmony_ci vxge_os_timer(&vdev->vp_reset_timer, vxge_poll_vp_reset, 28518c2ecf20Sopenharmony_ci HZ / 2); 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_ci /* There is no need to check for RxD leak and RxD lookup on Titan1A */ 28548c2ecf20Sopenharmony_ci if (vdev->titan1 && vdev->vp_lockup_timer.function == NULL) 28558c2ecf20Sopenharmony_ci vxge_os_timer(&vdev->vp_lockup_timer, vxge_poll_vp_lockup, 28568c2ecf20Sopenharmony_ci HZ / 2); 28578c2ecf20Sopenharmony_ci 28588c2ecf20Sopenharmony_ci set_bit(__VXGE_STATE_CARD_UP, &vdev->state); 28598c2ecf20Sopenharmony_ci 28608c2ecf20Sopenharmony_ci smp_wmb(); 28618c2ecf20Sopenharmony_ci 28628c2ecf20Sopenharmony_ci if (vxge_hw_device_link_state_get(vdev->devh) == VXGE_HW_LINK_UP) { 28638c2ecf20Sopenharmony_ci netif_carrier_on(vdev->ndev); 28648c2ecf20Sopenharmony_ci netdev_notice(vdev->ndev, "Link Up\n"); 28658c2ecf20Sopenharmony_ci vdev->stats.link_up++; 28668c2ecf20Sopenharmony_ci } 28678c2ecf20Sopenharmony_ci 28688c2ecf20Sopenharmony_ci vxge_hw_device_intr_enable(vdev->devh); 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci smp_wmb(); 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 28738c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[i]; 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci vxge_hw_vpath_enable(vpath->handle); 28768c2ecf20Sopenharmony_ci smp_wmb(); 28778c2ecf20Sopenharmony_ci vxge_hw_vpath_rx_doorbell_init(vpath->handle); 28788c2ecf20Sopenharmony_ci } 28798c2ecf20Sopenharmony_ci 28808c2ecf20Sopenharmony_ci netif_tx_start_all_queues(vdev->ndev); 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_ci /* configure CI */ 28838c2ecf20Sopenharmony_ci vxge_config_ci_for_tti_rti(vdev); 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_ci goto out0; 28868c2ecf20Sopenharmony_ci 28878c2ecf20Sopenharmony_ciout2: 28888c2ecf20Sopenharmony_ci vxge_rem_isr(vdev); 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_ci /* Disable napi */ 28918c2ecf20Sopenharmony_ci if (vdev->config.intr_type != MSI_X) 28928c2ecf20Sopenharmony_ci napi_disable(&vdev->napi); 28938c2ecf20Sopenharmony_ci else { 28948c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) 28958c2ecf20Sopenharmony_ci napi_disable(&vdev->vpaths[i].ring.napi); 28968c2ecf20Sopenharmony_ci } 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_ciout1: 28998c2ecf20Sopenharmony_ci vxge_close_vpaths(vdev, 0); 29008c2ecf20Sopenharmony_ciout0: 29018c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 29028c2ecf20Sopenharmony_ci "%s: %s:%d Exiting...", 29038c2ecf20Sopenharmony_ci dev->name, __func__, __LINE__); 29048c2ecf20Sopenharmony_ci return ret; 29058c2ecf20Sopenharmony_ci} 29068c2ecf20Sopenharmony_ci 29078c2ecf20Sopenharmony_ci/* Loop through the mac address list and delete all the entries */ 29088c2ecf20Sopenharmony_cistatic void vxge_free_mac_add_list(struct vxge_vpath *vpath) 29098c2ecf20Sopenharmony_ci{ 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci struct list_head *entry, *next; 29128c2ecf20Sopenharmony_ci if (list_empty(&vpath->mac_addr_list)) 29138c2ecf20Sopenharmony_ci return; 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci list_for_each_safe(entry, next, &vpath->mac_addr_list) { 29168c2ecf20Sopenharmony_ci list_del(entry); 29178c2ecf20Sopenharmony_ci kfree(entry); 29188c2ecf20Sopenharmony_ci } 29198c2ecf20Sopenharmony_ci} 29208c2ecf20Sopenharmony_ci 29218c2ecf20Sopenharmony_cistatic void vxge_napi_del_all(struct vxgedev *vdev) 29228c2ecf20Sopenharmony_ci{ 29238c2ecf20Sopenharmony_ci int i; 29248c2ecf20Sopenharmony_ci if (vdev->config.intr_type != MSI_X) 29258c2ecf20Sopenharmony_ci netif_napi_del(&vdev->napi); 29268c2ecf20Sopenharmony_ci else { 29278c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) 29288c2ecf20Sopenharmony_ci netif_napi_del(&vdev->vpaths[i].ring.napi); 29298c2ecf20Sopenharmony_ci } 29308c2ecf20Sopenharmony_ci} 29318c2ecf20Sopenharmony_ci 29328c2ecf20Sopenharmony_cistatic int do_vxge_close(struct net_device *dev, int do_io) 29338c2ecf20Sopenharmony_ci{ 29348c2ecf20Sopenharmony_ci enum vxge_hw_status status; 29358c2ecf20Sopenharmony_ci struct vxgedev *vdev; 29368c2ecf20Sopenharmony_ci struct __vxge_hw_device *hldev; 29378c2ecf20Sopenharmony_ci int i; 29388c2ecf20Sopenharmony_ci u64 val64, vpath_vector; 29398c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", 29408c2ecf20Sopenharmony_ci dev->name, __func__, __LINE__); 29418c2ecf20Sopenharmony_ci 29428c2ecf20Sopenharmony_ci vdev = netdev_priv(dev); 29438c2ecf20Sopenharmony_ci hldev = pci_get_drvdata(vdev->pdev); 29448c2ecf20Sopenharmony_ci 29458c2ecf20Sopenharmony_ci if (unlikely(!is_vxge_card_up(vdev))) 29468c2ecf20Sopenharmony_ci return 0; 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ci /* If vxge_handle_crit_err task is executing, 29498c2ecf20Sopenharmony_ci * wait till it completes. */ 29508c2ecf20Sopenharmony_ci while (test_and_set_bit(__VXGE_STATE_RESET_CARD, &vdev->state)) 29518c2ecf20Sopenharmony_ci msleep(50); 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci if (do_io) { 29548c2ecf20Sopenharmony_ci /* Put the vpath back in normal mode */ 29558c2ecf20Sopenharmony_ci vpath_vector = vxge_mBIT(vdev->vpaths[0].device_id); 29568c2ecf20Sopenharmony_ci status = vxge_hw_mgmt_reg_read(vdev->devh, 29578c2ecf20Sopenharmony_ci vxge_hw_mgmt_reg_type_mrpcim, 29588c2ecf20Sopenharmony_ci 0, 29598c2ecf20Sopenharmony_ci (ulong)offsetof( 29608c2ecf20Sopenharmony_ci struct vxge_hw_mrpcim_reg, 29618c2ecf20Sopenharmony_ci rts_mgr_cbasin_cfg), 29628c2ecf20Sopenharmony_ci &val64); 29638c2ecf20Sopenharmony_ci if (status == VXGE_HW_OK) { 29648c2ecf20Sopenharmony_ci val64 &= ~vpath_vector; 29658c2ecf20Sopenharmony_ci status = vxge_hw_mgmt_reg_write(vdev->devh, 29668c2ecf20Sopenharmony_ci vxge_hw_mgmt_reg_type_mrpcim, 29678c2ecf20Sopenharmony_ci 0, 29688c2ecf20Sopenharmony_ci (ulong)offsetof( 29698c2ecf20Sopenharmony_ci struct vxge_hw_mrpcim_reg, 29708c2ecf20Sopenharmony_ci rts_mgr_cbasin_cfg), 29718c2ecf20Sopenharmony_ci val64); 29728c2ecf20Sopenharmony_ci } 29738c2ecf20Sopenharmony_ci 29748c2ecf20Sopenharmony_ci /* Remove the function 0 from promiscuous mode */ 29758c2ecf20Sopenharmony_ci vxge_hw_mgmt_reg_write(vdev->devh, 29768c2ecf20Sopenharmony_ci vxge_hw_mgmt_reg_type_mrpcim, 29778c2ecf20Sopenharmony_ci 0, 29788c2ecf20Sopenharmony_ci (ulong)offsetof(struct vxge_hw_mrpcim_reg, 29798c2ecf20Sopenharmony_ci rxmac_authorize_all_addr), 29808c2ecf20Sopenharmony_ci 0); 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci vxge_hw_mgmt_reg_write(vdev->devh, 29838c2ecf20Sopenharmony_ci vxge_hw_mgmt_reg_type_mrpcim, 29848c2ecf20Sopenharmony_ci 0, 29858c2ecf20Sopenharmony_ci (ulong)offsetof(struct vxge_hw_mrpcim_reg, 29868c2ecf20Sopenharmony_ci rxmac_authorize_all_vid), 29878c2ecf20Sopenharmony_ci 0); 29888c2ecf20Sopenharmony_ci 29898c2ecf20Sopenharmony_ci smp_wmb(); 29908c2ecf20Sopenharmony_ci } 29918c2ecf20Sopenharmony_ci 29928c2ecf20Sopenharmony_ci if (vdev->titan1) 29938c2ecf20Sopenharmony_ci del_timer_sync(&vdev->vp_lockup_timer); 29948c2ecf20Sopenharmony_ci 29958c2ecf20Sopenharmony_ci del_timer_sync(&vdev->vp_reset_timer); 29968c2ecf20Sopenharmony_ci 29978c2ecf20Sopenharmony_ci if (do_io) 29988c2ecf20Sopenharmony_ci vxge_hw_device_wait_receive_idle(hldev); 29998c2ecf20Sopenharmony_ci 30008c2ecf20Sopenharmony_ci clear_bit(__VXGE_STATE_CARD_UP, &vdev->state); 30018c2ecf20Sopenharmony_ci 30028c2ecf20Sopenharmony_ci /* Disable napi */ 30038c2ecf20Sopenharmony_ci if (vdev->config.intr_type != MSI_X) 30048c2ecf20Sopenharmony_ci napi_disable(&vdev->napi); 30058c2ecf20Sopenharmony_ci else { 30068c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) 30078c2ecf20Sopenharmony_ci napi_disable(&vdev->vpaths[i].ring.napi); 30088c2ecf20Sopenharmony_ci } 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_ci netif_carrier_off(vdev->ndev); 30118c2ecf20Sopenharmony_ci netdev_notice(vdev->ndev, "Link Down\n"); 30128c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(vdev->ndev); 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci /* Note that at this point xmit() is stopped by upper layer */ 30158c2ecf20Sopenharmony_ci if (do_io) 30168c2ecf20Sopenharmony_ci vxge_hw_device_intr_disable(vdev->devh); 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_ci vxge_rem_isr(vdev); 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci vxge_napi_del_all(vdev); 30218c2ecf20Sopenharmony_ci 30228c2ecf20Sopenharmony_ci if (do_io) 30238c2ecf20Sopenharmony_ci vxge_reset_all_vpaths(vdev); 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci vxge_close_vpaths(vdev, 0); 30268c2ecf20Sopenharmony_ci 30278c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 30288c2ecf20Sopenharmony_ci "%s: %s:%d Exiting...", dev->name, __func__, __LINE__); 30298c2ecf20Sopenharmony_ci 30308c2ecf20Sopenharmony_ci clear_bit(__VXGE_STATE_RESET_CARD, &vdev->state); 30318c2ecf20Sopenharmony_ci 30328c2ecf20Sopenharmony_ci return 0; 30338c2ecf20Sopenharmony_ci} 30348c2ecf20Sopenharmony_ci 30358c2ecf20Sopenharmony_ci/** 30368c2ecf20Sopenharmony_ci * vxge_close 30378c2ecf20Sopenharmony_ci * @dev: device pointer. 30388c2ecf20Sopenharmony_ci * 30398c2ecf20Sopenharmony_ci * This is the stop entry point of the driver. It needs to undo exactly 30408c2ecf20Sopenharmony_ci * whatever was done by the open entry point, thus it's usually referred to 30418c2ecf20Sopenharmony_ci * as the close function.Among other things this function mainly stops the 30428c2ecf20Sopenharmony_ci * Rx side of the NIC and frees all the Rx buffers in the Rx rings. 30438c2ecf20Sopenharmony_ci * Return value: '0' on success and an appropriate (-)ve integer as 30448c2ecf20Sopenharmony_ci * defined in errno.h file on failure. 30458c2ecf20Sopenharmony_ci */ 30468c2ecf20Sopenharmony_cistatic int vxge_close(struct net_device *dev) 30478c2ecf20Sopenharmony_ci{ 30488c2ecf20Sopenharmony_ci do_vxge_close(dev, 1); 30498c2ecf20Sopenharmony_ci return 0; 30508c2ecf20Sopenharmony_ci} 30518c2ecf20Sopenharmony_ci 30528c2ecf20Sopenharmony_ci/** 30538c2ecf20Sopenharmony_ci * vxge_change_mtu 30548c2ecf20Sopenharmony_ci * @dev: net device pointer. 30558c2ecf20Sopenharmony_ci * @new_mtu :the new MTU size for the device. 30568c2ecf20Sopenharmony_ci * 30578c2ecf20Sopenharmony_ci * A driver entry point to change MTU size for the device. Before changing 30588c2ecf20Sopenharmony_ci * the MTU the device must be stopped. 30598c2ecf20Sopenharmony_ci */ 30608c2ecf20Sopenharmony_cistatic int vxge_change_mtu(struct net_device *dev, int new_mtu) 30618c2ecf20Sopenharmony_ci{ 30628c2ecf20Sopenharmony_ci struct vxgedev *vdev = netdev_priv(dev); 30638c2ecf20Sopenharmony_ci 30648c2ecf20Sopenharmony_ci vxge_debug_entryexit(vdev->level_trace, 30658c2ecf20Sopenharmony_ci "%s:%d", __func__, __LINE__); 30668c2ecf20Sopenharmony_ci 30678c2ecf20Sopenharmony_ci /* check if device is down already */ 30688c2ecf20Sopenharmony_ci if (unlikely(!is_vxge_card_up(vdev))) { 30698c2ecf20Sopenharmony_ci /* just store new value, will use later on open() */ 30708c2ecf20Sopenharmony_ci dev->mtu = new_mtu; 30718c2ecf20Sopenharmony_ci vxge_debug_init(vdev->level_err, 30728c2ecf20Sopenharmony_ci "%s", "device is down on MTU change"); 30738c2ecf20Sopenharmony_ci return 0; 30748c2ecf20Sopenharmony_ci } 30758c2ecf20Sopenharmony_ci 30768c2ecf20Sopenharmony_ci vxge_debug_init(vdev->level_trace, 30778c2ecf20Sopenharmony_ci "trying to apply new MTU %d", new_mtu); 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_ci if (vxge_close(dev)) 30808c2ecf20Sopenharmony_ci return -EIO; 30818c2ecf20Sopenharmony_ci 30828c2ecf20Sopenharmony_ci dev->mtu = new_mtu; 30838c2ecf20Sopenharmony_ci vdev->mtu = new_mtu; 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_ci if (vxge_open(dev)) 30868c2ecf20Sopenharmony_ci return -EIO; 30878c2ecf20Sopenharmony_ci 30888c2ecf20Sopenharmony_ci vxge_debug_init(vdev->level_trace, 30898c2ecf20Sopenharmony_ci "%s: MTU changed to %d", vdev->ndev->name, new_mtu); 30908c2ecf20Sopenharmony_ci 30918c2ecf20Sopenharmony_ci vxge_debug_entryexit(vdev->level_trace, 30928c2ecf20Sopenharmony_ci "%s:%d Exiting...", __func__, __LINE__); 30938c2ecf20Sopenharmony_ci 30948c2ecf20Sopenharmony_ci return 0; 30958c2ecf20Sopenharmony_ci} 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_ci/** 30988c2ecf20Sopenharmony_ci * vxge_get_stats64 30998c2ecf20Sopenharmony_ci * @dev: pointer to the device structure 31008c2ecf20Sopenharmony_ci * @net_stats: pointer to struct rtnl_link_stats64 31018c2ecf20Sopenharmony_ci * 31028c2ecf20Sopenharmony_ci */ 31038c2ecf20Sopenharmony_cistatic void 31048c2ecf20Sopenharmony_civxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats) 31058c2ecf20Sopenharmony_ci{ 31068c2ecf20Sopenharmony_ci struct vxgedev *vdev = netdev_priv(dev); 31078c2ecf20Sopenharmony_ci int k; 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_ci /* net_stats already zeroed by caller */ 31108c2ecf20Sopenharmony_ci for (k = 0; k < vdev->no_of_vpath; k++) { 31118c2ecf20Sopenharmony_ci struct vxge_ring_stats *rxstats = &vdev->vpaths[k].ring.stats; 31128c2ecf20Sopenharmony_ci struct vxge_fifo_stats *txstats = &vdev->vpaths[k].fifo.stats; 31138c2ecf20Sopenharmony_ci unsigned int start; 31148c2ecf20Sopenharmony_ci u64 packets, bytes, multicast; 31158c2ecf20Sopenharmony_ci 31168c2ecf20Sopenharmony_ci do { 31178c2ecf20Sopenharmony_ci start = u64_stats_fetch_begin_irq(&rxstats->syncp); 31188c2ecf20Sopenharmony_ci 31198c2ecf20Sopenharmony_ci packets = rxstats->rx_frms; 31208c2ecf20Sopenharmony_ci multicast = rxstats->rx_mcast; 31218c2ecf20Sopenharmony_ci bytes = rxstats->rx_bytes; 31228c2ecf20Sopenharmony_ci } while (u64_stats_fetch_retry_irq(&rxstats->syncp, start)); 31238c2ecf20Sopenharmony_ci 31248c2ecf20Sopenharmony_ci net_stats->rx_packets += packets; 31258c2ecf20Sopenharmony_ci net_stats->rx_bytes += bytes; 31268c2ecf20Sopenharmony_ci net_stats->multicast += multicast; 31278c2ecf20Sopenharmony_ci 31288c2ecf20Sopenharmony_ci net_stats->rx_errors += rxstats->rx_errors; 31298c2ecf20Sopenharmony_ci net_stats->rx_dropped += rxstats->rx_dropped; 31308c2ecf20Sopenharmony_ci 31318c2ecf20Sopenharmony_ci do { 31328c2ecf20Sopenharmony_ci start = u64_stats_fetch_begin_irq(&txstats->syncp); 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_ci packets = txstats->tx_frms; 31358c2ecf20Sopenharmony_ci bytes = txstats->tx_bytes; 31368c2ecf20Sopenharmony_ci } while (u64_stats_fetch_retry_irq(&txstats->syncp, start)); 31378c2ecf20Sopenharmony_ci 31388c2ecf20Sopenharmony_ci net_stats->tx_packets += packets; 31398c2ecf20Sopenharmony_ci net_stats->tx_bytes += bytes; 31408c2ecf20Sopenharmony_ci net_stats->tx_errors += txstats->tx_errors; 31418c2ecf20Sopenharmony_ci } 31428c2ecf20Sopenharmony_ci} 31438c2ecf20Sopenharmony_ci 31448c2ecf20Sopenharmony_cistatic enum vxge_hw_status vxge_timestamp_config(struct __vxge_hw_device *devh) 31458c2ecf20Sopenharmony_ci{ 31468c2ecf20Sopenharmony_ci enum vxge_hw_status status; 31478c2ecf20Sopenharmony_ci u64 val64; 31488c2ecf20Sopenharmony_ci 31498c2ecf20Sopenharmony_ci /* Timestamp is passed to the driver via the FCS, therefore we 31508c2ecf20Sopenharmony_ci * must disable the FCS stripping by the adapter. Since this is 31518c2ecf20Sopenharmony_ci * required for the driver to load (due to a hardware bug), 31528c2ecf20Sopenharmony_ci * there is no need to do anything special here. 31538c2ecf20Sopenharmony_ci */ 31548c2ecf20Sopenharmony_ci val64 = VXGE_HW_XMAC_TIMESTAMP_EN | 31558c2ecf20Sopenharmony_ci VXGE_HW_XMAC_TIMESTAMP_USE_LINK_ID(0) | 31568c2ecf20Sopenharmony_ci VXGE_HW_XMAC_TIMESTAMP_INTERVAL(0); 31578c2ecf20Sopenharmony_ci 31588c2ecf20Sopenharmony_ci status = vxge_hw_mgmt_reg_write(devh, 31598c2ecf20Sopenharmony_ci vxge_hw_mgmt_reg_type_mrpcim, 31608c2ecf20Sopenharmony_ci 0, 31618c2ecf20Sopenharmony_ci offsetof(struct vxge_hw_mrpcim_reg, 31628c2ecf20Sopenharmony_ci xmac_timestamp), 31638c2ecf20Sopenharmony_ci val64); 31648c2ecf20Sopenharmony_ci vxge_hw_device_flush_io(devh); 31658c2ecf20Sopenharmony_ci devh->config.hwts_en = VXGE_HW_HWTS_ENABLE; 31668c2ecf20Sopenharmony_ci return status; 31678c2ecf20Sopenharmony_ci} 31688c2ecf20Sopenharmony_ci 31698c2ecf20Sopenharmony_cistatic int vxge_hwtstamp_set(struct vxgedev *vdev, void __user *data) 31708c2ecf20Sopenharmony_ci{ 31718c2ecf20Sopenharmony_ci struct hwtstamp_config config; 31728c2ecf20Sopenharmony_ci int i; 31738c2ecf20Sopenharmony_ci 31748c2ecf20Sopenharmony_ci if (copy_from_user(&config, data, sizeof(config))) 31758c2ecf20Sopenharmony_ci return -EFAULT; 31768c2ecf20Sopenharmony_ci 31778c2ecf20Sopenharmony_ci /* reserved for future extensions */ 31788c2ecf20Sopenharmony_ci if (config.flags) 31798c2ecf20Sopenharmony_ci return -EINVAL; 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_ci /* Transmit HW Timestamp not supported */ 31828c2ecf20Sopenharmony_ci switch (config.tx_type) { 31838c2ecf20Sopenharmony_ci case HWTSTAMP_TX_OFF: 31848c2ecf20Sopenharmony_ci break; 31858c2ecf20Sopenharmony_ci case HWTSTAMP_TX_ON: 31868c2ecf20Sopenharmony_ci default: 31878c2ecf20Sopenharmony_ci return -ERANGE; 31888c2ecf20Sopenharmony_ci } 31898c2ecf20Sopenharmony_ci 31908c2ecf20Sopenharmony_ci switch (config.rx_filter) { 31918c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_NONE: 31928c2ecf20Sopenharmony_ci vdev->rx_hwts = 0; 31938c2ecf20Sopenharmony_ci config.rx_filter = HWTSTAMP_FILTER_NONE; 31948c2ecf20Sopenharmony_ci break; 31958c2ecf20Sopenharmony_ci 31968c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_ALL: 31978c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_SOME: 31988c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 31998c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 32008c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 32018c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 32028c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 32038c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 32048c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: 32058c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: 32068c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: 32078c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_EVENT: 32088c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_SYNC: 32098c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: 32108c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_NTP_ALL: 32118c2ecf20Sopenharmony_ci if (vdev->devh->config.hwts_en != VXGE_HW_HWTS_ENABLE) 32128c2ecf20Sopenharmony_ci return -EFAULT; 32138c2ecf20Sopenharmony_ci 32148c2ecf20Sopenharmony_ci vdev->rx_hwts = 1; 32158c2ecf20Sopenharmony_ci config.rx_filter = HWTSTAMP_FILTER_ALL; 32168c2ecf20Sopenharmony_ci break; 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_ci default: 32198c2ecf20Sopenharmony_ci return -ERANGE; 32208c2ecf20Sopenharmony_ci } 32218c2ecf20Sopenharmony_ci 32228c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) 32238c2ecf20Sopenharmony_ci vdev->vpaths[i].ring.rx_hwts = vdev->rx_hwts; 32248c2ecf20Sopenharmony_ci 32258c2ecf20Sopenharmony_ci if (copy_to_user(data, &config, sizeof(config))) 32268c2ecf20Sopenharmony_ci return -EFAULT; 32278c2ecf20Sopenharmony_ci 32288c2ecf20Sopenharmony_ci return 0; 32298c2ecf20Sopenharmony_ci} 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_cistatic int vxge_hwtstamp_get(struct vxgedev *vdev, void __user *data) 32328c2ecf20Sopenharmony_ci{ 32338c2ecf20Sopenharmony_ci struct hwtstamp_config config; 32348c2ecf20Sopenharmony_ci 32358c2ecf20Sopenharmony_ci config.flags = 0; 32368c2ecf20Sopenharmony_ci config.tx_type = HWTSTAMP_TX_OFF; 32378c2ecf20Sopenharmony_ci config.rx_filter = (vdev->rx_hwts ? 32388c2ecf20Sopenharmony_ci HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE); 32398c2ecf20Sopenharmony_ci 32408c2ecf20Sopenharmony_ci if (copy_to_user(data, &config, sizeof(config))) 32418c2ecf20Sopenharmony_ci return -EFAULT; 32428c2ecf20Sopenharmony_ci 32438c2ecf20Sopenharmony_ci return 0; 32448c2ecf20Sopenharmony_ci} 32458c2ecf20Sopenharmony_ci 32468c2ecf20Sopenharmony_ci/** 32478c2ecf20Sopenharmony_ci * vxge_ioctl 32488c2ecf20Sopenharmony_ci * @dev: Device pointer. 32498c2ecf20Sopenharmony_ci * @rq: An IOCTL specific structure, that can contain a pointer to 32508c2ecf20Sopenharmony_ci * a proprietary structure used to pass information to the driver. 32518c2ecf20Sopenharmony_ci * @cmd: This is used to distinguish between the different commands that 32528c2ecf20Sopenharmony_ci * can be passed to the IOCTL functions. 32538c2ecf20Sopenharmony_ci * 32548c2ecf20Sopenharmony_ci * Entry point for the Ioctl. 32558c2ecf20Sopenharmony_ci */ 32568c2ecf20Sopenharmony_cistatic int vxge_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 32578c2ecf20Sopenharmony_ci{ 32588c2ecf20Sopenharmony_ci struct vxgedev *vdev = netdev_priv(dev); 32598c2ecf20Sopenharmony_ci 32608c2ecf20Sopenharmony_ci switch (cmd) { 32618c2ecf20Sopenharmony_ci case SIOCSHWTSTAMP: 32628c2ecf20Sopenharmony_ci return vxge_hwtstamp_set(vdev, rq->ifr_data); 32638c2ecf20Sopenharmony_ci case SIOCGHWTSTAMP: 32648c2ecf20Sopenharmony_ci return vxge_hwtstamp_get(vdev, rq->ifr_data); 32658c2ecf20Sopenharmony_ci default: 32668c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 32678c2ecf20Sopenharmony_ci } 32688c2ecf20Sopenharmony_ci} 32698c2ecf20Sopenharmony_ci 32708c2ecf20Sopenharmony_ci/** 32718c2ecf20Sopenharmony_ci * vxge_tx_watchdog 32728c2ecf20Sopenharmony_ci * @dev: pointer to net device structure 32738c2ecf20Sopenharmony_ci * @txqueue: index of the hanging queue 32748c2ecf20Sopenharmony_ci * 32758c2ecf20Sopenharmony_ci * Watchdog for transmit side. 32768c2ecf20Sopenharmony_ci * This function is triggered if the Tx Queue is stopped 32778c2ecf20Sopenharmony_ci * for a pre-defined amount of time when the Interface is still up. 32788c2ecf20Sopenharmony_ci */ 32798c2ecf20Sopenharmony_cistatic void vxge_tx_watchdog(struct net_device *dev, unsigned int txqueue) 32808c2ecf20Sopenharmony_ci{ 32818c2ecf20Sopenharmony_ci struct vxgedev *vdev; 32828c2ecf20Sopenharmony_ci 32838c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__); 32848c2ecf20Sopenharmony_ci 32858c2ecf20Sopenharmony_ci vdev = netdev_priv(dev); 32868c2ecf20Sopenharmony_ci 32878c2ecf20Sopenharmony_ci vdev->cric_err_event = VXGE_HW_EVENT_RESET_START; 32888c2ecf20Sopenharmony_ci 32898c2ecf20Sopenharmony_ci schedule_work(&vdev->reset_task); 32908c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 32918c2ecf20Sopenharmony_ci "%s:%d Exiting...", __func__, __LINE__); 32928c2ecf20Sopenharmony_ci} 32938c2ecf20Sopenharmony_ci 32948c2ecf20Sopenharmony_ci/** 32958c2ecf20Sopenharmony_ci * vxge_vlan_rx_add_vid 32968c2ecf20Sopenharmony_ci * @dev: net device pointer. 32978c2ecf20Sopenharmony_ci * @proto: vlan protocol 32988c2ecf20Sopenharmony_ci * @vid: vid 32998c2ecf20Sopenharmony_ci * 33008c2ecf20Sopenharmony_ci * Add the vlan id to the devices vlan id table 33018c2ecf20Sopenharmony_ci */ 33028c2ecf20Sopenharmony_cistatic int 33038c2ecf20Sopenharmony_civxge_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid) 33048c2ecf20Sopenharmony_ci{ 33058c2ecf20Sopenharmony_ci struct vxgedev *vdev = netdev_priv(dev); 33068c2ecf20Sopenharmony_ci struct vxge_vpath *vpath; 33078c2ecf20Sopenharmony_ci int vp_id; 33088c2ecf20Sopenharmony_ci 33098c2ecf20Sopenharmony_ci /* Add these vlan to the vid table */ 33108c2ecf20Sopenharmony_ci for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) { 33118c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[vp_id]; 33128c2ecf20Sopenharmony_ci if (!vpath->is_open) 33138c2ecf20Sopenharmony_ci continue; 33148c2ecf20Sopenharmony_ci vxge_hw_vpath_vid_add(vpath->handle, vid); 33158c2ecf20Sopenharmony_ci } 33168c2ecf20Sopenharmony_ci set_bit(vid, vdev->active_vlans); 33178c2ecf20Sopenharmony_ci return 0; 33188c2ecf20Sopenharmony_ci} 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_ci/** 33218c2ecf20Sopenharmony_ci * vxge_vlan_rx_kill_vid 33228c2ecf20Sopenharmony_ci * @dev: net device pointer. 33238c2ecf20Sopenharmony_ci * @proto: vlan protocol 33248c2ecf20Sopenharmony_ci * @vid: vid 33258c2ecf20Sopenharmony_ci * 33268c2ecf20Sopenharmony_ci * Remove the vlan id from the device's vlan id table 33278c2ecf20Sopenharmony_ci */ 33288c2ecf20Sopenharmony_cistatic int 33298c2ecf20Sopenharmony_civxge_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid) 33308c2ecf20Sopenharmony_ci{ 33318c2ecf20Sopenharmony_ci struct vxgedev *vdev = netdev_priv(dev); 33328c2ecf20Sopenharmony_ci struct vxge_vpath *vpath; 33338c2ecf20Sopenharmony_ci int vp_id; 33348c2ecf20Sopenharmony_ci 33358c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__); 33368c2ecf20Sopenharmony_ci 33378c2ecf20Sopenharmony_ci /* Delete this vlan from the vid table */ 33388c2ecf20Sopenharmony_ci for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) { 33398c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[vp_id]; 33408c2ecf20Sopenharmony_ci if (!vpath->is_open) 33418c2ecf20Sopenharmony_ci continue; 33428c2ecf20Sopenharmony_ci vxge_hw_vpath_vid_delete(vpath->handle, vid); 33438c2ecf20Sopenharmony_ci } 33448c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, 33458c2ecf20Sopenharmony_ci "%s:%d Exiting...", __func__, __LINE__); 33468c2ecf20Sopenharmony_ci clear_bit(vid, vdev->active_vlans); 33478c2ecf20Sopenharmony_ci return 0; 33488c2ecf20Sopenharmony_ci} 33498c2ecf20Sopenharmony_ci 33508c2ecf20Sopenharmony_cistatic const struct net_device_ops vxge_netdev_ops = { 33518c2ecf20Sopenharmony_ci .ndo_open = vxge_open, 33528c2ecf20Sopenharmony_ci .ndo_stop = vxge_close, 33538c2ecf20Sopenharmony_ci .ndo_get_stats64 = vxge_get_stats64, 33548c2ecf20Sopenharmony_ci .ndo_start_xmit = vxge_xmit, 33558c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 33568c2ecf20Sopenharmony_ci .ndo_set_rx_mode = vxge_set_multicast, 33578c2ecf20Sopenharmony_ci .ndo_do_ioctl = vxge_ioctl, 33588c2ecf20Sopenharmony_ci .ndo_set_mac_address = vxge_set_mac_addr, 33598c2ecf20Sopenharmony_ci .ndo_change_mtu = vxge_change_mtu, 33608c2ecf20Sopenharmony_ci .ndo_fix_features = vxge_fix_features, 33618c2ecf20Sopenharmony_ci .ndo_set_features = vxge_set_features, 33628c2ecf20Sopenharmony_ci .ndo_vlan_rx_kill_vid = vxge_vlan_rx_kill_vid, 33638c2ecf20Sopenharmony_ci .ndo_vlan_rx_add_vid = vxge_vlan_rx_add_vid, 33648c2ecf20Sopenharmony_ci .ndo_tx_timeout = vxge_tx_watchdog, 33658c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 33668c2ecf20Sopenharmony_ci .ndo_poll_controller = vxge_netpoll, 33678c2ecf20Sopenharmony_ci#endif 33688c2ecf20Sopenharmony_ci}; 33698c2ecf20Sopenharmony_ci 33708c2ecf20Sopenharmony_cistatic int vxge_device_register(struct __vxge_hw_device *hldev, 33718c2ecf20Sopenharmony_ci struct vxge_config *config, int high_dma, 33728c2ecf20Sopenharmony_ci int no_of_vpath, struct vxgedev **vdev_out) 33738c2ecf20Sopenharmony_ci{ 33748c2ecf20Sopenharmony_ci struct net_device *ndev; 33758c2ecf20Sopenharmony_ci enum vxge_hw_status status = VXGE_HW_OK; 33768c2ecf20Sopenharmony_ci struct vxgedev *vdev; 33778c2ecf20Sopenharmony_ci int ret = 0, no_of_queue = 1; 33788c2ecf20Sopenharmony_ci u64 stat; 33798c2ecf20Sopenharmony_ci 33808c2ecf20Sopenharmony_ci *vdev_out = NULL; 33818c2ecf20Sopenharmony_ci if (config->tx_steering_type) 33828c2ecf20Sopenharmony_ci no_of_queue = no_of_vpath; 33838c2ecf20Sopenharmony_ci 33848c2ecf20Sopenharmony_ci ndev = alloc_etherdev_mq(sizeof(struct vxgedev), 33858c2ecf20Sopenharmony_ci no_of_queue); 33868c2ecf20Sopenharmony_ci if (ndev == NULL) { 33878c2ecf20Sopenharmony_ci vxge_debug_init( 33888c2ecf20Sopenharmony_ci vxge_hw_device_trace_level_get(hldev), 33898c2ecf20Sopenharmony_ci "%s : device allocation failed", __func__); 33908c2ecf20Sopenharmony_ci ret = -ENODEV; 33918c2ecf20Sopenharmony_ci goto _out0; 33928c2ecf20Sopenharmony_ci } 33938c2ecf20Sopenharmony_ci 33948c2ecf20Sopenharmony_ci vxge_debug_entryexit( 33958c2ecf20Sopenharmony_ci vxge_hw_device_trace_level_get(hldev), 33968c2ecf20Sopenharmony_ci "%s: %s:%d Entering...", 33978c2ecf20Sopenharmony_ci ndev->name, __func__, __LINE__); 33988c2ecf20Sopenharmony_ci 33998c2ecf20Sopenharmony_ci vdev = netdev_priv(ndev); 34008c2ecf20Sopenharmony_ci memset(vdev, 0, sizeof(struct vxgedev)); 34018c2ecf20Sopenharmony_ci 34028c2ecf20Sopenharmony_ci vdev->ndev = ndev; 34038c2ecf20Sopenharmony_ci vdev->devh = hldev; 34048c2ecf20Sopenharmony_ci vdev->pdev = hldev->pdev; 34058c2ecf20Sopenharmony_ci memcpy(&vdev->config, config, sizeof(struct vxge_config)); 34068c2ecf20Sopenharmony_ci vdev->rx_hwts = 0; 34078c2ecf20Sopenharmony_ci vdev->titan1 = (vdev->pdev->revision == VXGE_HW_TITAN1_PCI_REVISION); 34088c2ecf20Sopenharmony_ci 34098c2ecf20Sopenharmony_ci SET_NETDEV_DEV(ndev, &vdev->pdev->dev); 34108c2ecf20Sopenharmony_ci 34118c2ecf20Sopenharmony_ci ndev->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | 34128c2ecf20Sopenharmony_ci NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | 34138c2ecf20Sopenharmony_ci NETIF_F_TSO | NETIF_F_TSO6 | 34148c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX; 34158c2ecf20Sopenharmony_ci if (vdev->config.rth_steering != NO_STEERING) 34168c2ecf20Sopenharmony_ci ndev->hw_features |= NETIF_F_RXHASH; 34178c2ecf20Sopenharmony_ci 34188c2ecf20Sopenharmony_ci ndev->features |= ndev->hw_features | 34198c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER; 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ci 34228c2ecf20Sopenharmony_ci ndev->netdev_ops = &vxge_netdev_ops; 34238c2ecf20Sopenharmony_ci 34248c2ecf20Sopenharmony_ci ndev->watchdog_timeo = VXGE_LL_WATCH_DOG_TIMEOUT; 34258c2ecf20Sopenharmony_ci INIT_WORK(&vdev->reset_task, vxge_reset); 34268c2ecf20Sopenharmony_ci 34278c2ecf20Sopenharmony_ci vxge_initialize_ethtool_ops(ndev); 34288c2ecf20Sopenharmony_ci 34298c2ecf20Sopenharmony_ci /* Allocate memory for vpath */ 34308c2ecf20Sopenharmony_ci vdev->vpaths = kcalloc(no_of_vpath, sizeof(struct vxge_vpath), 34318c2ecf20Sopenharmony_ci GFP_KERNEL); 34328c2ecf20Sopenharmony_ci if (!vdev->vpaths) { 34338c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 34348c2ecf20Sopenharmony_ci "%s: vpath memory allocation failed", 34358c2ecf20Sopenharmony_ci vdev->ndev->name); 34368c2ecf20Sopenharmony_ci ret = -ENOMEM; 34378c2ecf20Sopenharmony_ci goto _out1; 34388c2ecf20Sopenharmony_ci } 34398c2ecf20Sopenharmony_ci 34408c2ecf20Sopenharmony_ci vxge_debug_init(vxge_hw_device_trace_level_get(hldev), 34418c2ecf20Sopenharmony_ci "%s : checksumming enabled", __func__); 34428c2ecf20Sopenharmony_ci 34438c2ecf20Sopenharmony_ci if (high_dma) { 34448c2ecf20Sopenharmony_ci ndev->features |= NETIF_F_HIGHDMA; 34458c2ecf20Sopenharmony_ci vxge_debug_init(vxge_hw_device_trace_level_get(hldev), 34468c2ecf20Sopenharmony_ci "%s : using High DMA", __func__); 34478c2ecf20Sopenharmony_ci } 34488c2ecf20Sopenharmony_ci 34498c2ecf20Sopenharmony_ci /* MTU range: 68 - 9600 */ 34508c2ecf20Sopenharmony_ci ndev->min_mtu = VXGE_HW_MIN_MTU; 34518c2ecf20Sopenharmony_ci ndev->max_mtu = VXGE_HW_MAX_MTU; 34528c2ecf20Sopenharmony_ci 34538c2ecf20Sopenharmony_ci ret = register_netdev(ndev); 34548c2ecf20Sopenharmony_ci if (ret) { 34558c2ecf20Sopenharmony_ci vxge_debug_init(vxge_hw_device_trace_level_get(hldev), 34568c2ecf20Sopenharmony_ci "%s: %s : device registration failed!", 34578c2ecf20Sopenharmony_ci ndev->name, __func__); 34588c2ecf20Sopenharmony_ci goto _out2; 34598c2ecf20Sopenharmony_ci } 34608c2ecf20Sopenharmony_ci 34618c2ecf20Sopenharmony_ci /* Set the factory defined MAC address initially */ 34628c2ecf20Sopenharmony_ci ndev->addr_len = ETH_ALEN; 34638c2ecf20Sopenharmony_ci 34648c2ecf20Sopenharmony_ci /* Make Link state as off at this point, when the Link change 34658c2ecf20Sopenharmony_ci * interrupt comes the state will be automatically changed to 34668c2ecf20Sopenharmony_ci * the right state. 34678c2ecf20Sopenharmony_ci */ 34688c2ecf20Sopenharmony_ci netif_carrier_off(ndev); 34698c2ecf20Sopenharmony_ci 34708c2ecf20Sopenharmony_ci vxge_debug_init(vxge_hw_device_trace_level_get(hldev), 34718c2ecf20Sopenharmony_ci "%s: Ethernet device registered", 34728c2ecf20Sopenharmony_ci ndev->name); 34738c2ecf20Sopenharmony_ci 34748c2ecf20Sopenharmony_ci hldev->ndev = ndev; 34758c2ecf20Sopenharmony_ci *vdev_out = vdev; 34768c2ecf20Sopenharmony_ci 34778c2ecf20Sopenharmony_ci /* Resetting the Device stats */ 34788c2ecf20Sopenharmony_ci status = vxge_hw_mrpcim_stats_access( 34798c2ecf20Sopenharmony_ci hldev, 34808c2ecf20Sopenharmony_ci VXGE_HW_STATS_OP_CLEAR_ALL_STATS, 34818c2ecf20Sopenharmony_ci 0, 34828c2ecf20Sopenharmony_ci 0, 34838c2ecf20Sopenharmony_ci &stat); 34848c2ecf20Sopenharmony_ci 34858c2ecf20Sopenharmony_ci if (status == VXGE_HW_ERR_PRIVILEGED_OPERATION) 34868c2ecf20Sopenharmony_ci vxge_debug_init( 34878c2ecf20Sopenharmony_ci vxge_hw_device_trace_level_get(hldev), 34888c2ecf20Sopenharmony_ci "%s: device stats clear returns" 34898c2ecf20Sopenharmony_ci "VXGE_HW_ERR_PRIVILEGED_OPERATION", ndev->name); 34908c2ecf20Sopenharmony_ci 34918c2ecf20Sopenharmony_ci vxge_debug_entryexit(vxge_hw_device_trace_level_get(hldev), 34928c2ecf20Sopenharmony_ci "%s: %s:%d Exiting...", 34938c2ecf20Sopenharmony_ci ndev->name, __func__, __LINE__); 34948c2ecf20Sopenharmony_ci 34958c2ecf20Sopenharmony_ci return ret; 34968c2ecf20Sopenharmony_ci_out2: 34978c2ecf20Sopenharmony_ci kfree(vdev->vpaths); 34988c2ecf20Sopenharmony_ci_out1: 34998c2ecf20Sopenharmony_ci free_netdev(ndev); 35008c2ecf20Sopenharmony_ci_out0: 35018c2ecf20Sopenharmony_ci return ret; 35028c2ecf20Sopenharmony_ci} 35038c2ecf20Sopenharmony_ci 35048c2ecf20Sopenharmony_ci/* 35058c2ecf20Sopenharmony_ci * vxge_device_unregister 35068c2ecf20Sopenharmony_ci * 35078c2ecf20Sopenharmony_ci * This function will unregister and free network device 35088c2ecf20Sopenharmony_ci */ 35098c2ecf20Sopenharmony_cistatic void vxge_device_unregister(struct __vxge_hw_device *hldev) 35108c2ecf20Sopenharmony_ci{ 35118c2ecf20Sopenharmony_ci struct vxgedev *vdev; 35128c2ecf20Sopenharmony_ci struct net_device *dev; 35138c2ecf20Sopenharmony_ci char buf[IFNAMSIZ]; 35148c2ecf20Sopenharmony_ci 35158c2ecf20Sopenharmony_ci dev = hldev->ndev; 35168c2ecf20Sopenharmony_ci vdev = netdev_priv(dev); 35178c2ecf20Sopenharmony_ci 35188c2ecf20Sopenharmony_ci vxge_debug_entryexit(vdev->level_trace, "%s: %s:%d", vdev->ndev->name, 35198c2ecf20Sopenharmony_ci __func__, __LINE__); 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_ci strlcpy(buf, dev->name, IFNAMSIZ); 35228c2ecf20Sopenharmony_ci 35238c2ecf20Sopenharmony_ci flush_work(&vdev->reset_task); 35248c2ecf20Sopenharmony_ci 35258c2ecf20Sopenharmony_ci /* in 2.6 will call stop() if device is up */ 35268c2ecf20Sopenharmony_ci unregister_netdev(dev); 35278c2ecf20Sopenharmony_ci 35288c2ecf20Sopenharmony_ci kfree(vdev->vpaths); 35298c2ecf20Sopenharmony_ci 35308c2ecf20Sopenharmony_ci vxge_debug_init(vdev->level_trace, "%s: ethernet device unregistered", 35318c2ecf20Sopenharmony_ci buf); 35328c2ecf20Sopenharmony_ci vxge_debug_entryexit(vdev->level_trace, "%s: %s:%d Exiting...", buf, 35338c2ecf20Sopenharmony_ci __func__, __LINE__); 35348c2ecf20Sopenharmony_ci 35358c2ecf20Sopenharmony_ci /* we are safe to free it now */ 35368c2ecf20Sopenharmony_ci free_netdev(dev); 35378c2ecf20Sopenharmony_ci} 35388c2ecf20Sopenharmony_ci 35398c2ecf20Sopenharmony_ci/* 35408c2ecf20Sopenharmony_ci * vxge_callback_crit_err 35418c2ecf20Sopenharmony_ci * 35428c2ecf20Sopenharmony_ci * This function is called by the alarm handler in interrupt context. 35438c2ecf20Sopenharmony_ci * Driver must analyze it based on the event type. 35448c2ecf20Sopenharmony_ci */ 35458c2ecf20Sopenharmony_cistatic void 35468c2ecf20Sopenharmony_civxge_callback_crit_err(struct __vxge_hw_device *hldev, 35478c2ecf20Sopenharmony_ci enum vxge_hw_event type, u64 vp_id) 35488c2ecf20Sopenharmony_ci{ 35498c2ecf20Sopenharmony_ci struct net_device *dev = hldev->ndev; 35508c2ecf20Sopenharmony_ci struct vxgedev *vdev = netdev_priv(dev); 35518c2ecf20Sopenharmony_ci struct vxge_vpath *vpath = NULL; 35528c2ecf20Sopenharmony_ci int vpath_idx; 35538c2ecf20Sopenharmony_ci 35548c2ecf20Sopenharmony_ci vxge_debug_entryexit(vdev->level_trace, 35558c2ecf20Sopenharmony_ci "%s: %s:%d", vdev->ndev->name, __func__, __LINE__); 35568c2ecf20Sopenharmony_ci 35578c2ecf20Sopenharmony_ci /* Note: This event type should be used for device wide 35588c2ecf20Sopenharmony_ci * indications only - Serious errors, Slot freeze and critical errors 35598c2ecf20Sopenharmony_ci */ 35608c2ecf20Sopenharmony_ci vdev->cric_err_event = type; 35618c2ecf20Sopenharmony_ci 35628c2ecf20Sopenharmony_ci for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) { 35638c2ecf20Sopenharmony_ci vpath = &vdev->vpaths[vpath_idx]; 35648c2ecf20Sopenharmony_ci if (vpath->device_id == vp_id) 35658c2ecf20Sopenharmony_ci break; 35668c2ecf20Sopenharmony_ci } 35678c2ecf20Sopenharmony_ci 35688c2ecf20Sopenharmony_ci if (!test_bit(__VXGE_STATE_RESET_CARD, &vdev->state)) { 35698c2ecf20Sopenharmony_ci if (type == VXGE_HW_EVENT_SLOT_FREEZE) { 35708c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 35718c2ecf20Sopenharmony_ci "%s: Slot is frozen", vdev->ndev->name); 35728c2ecf20Sopenharmony_ci } else if (type == VXGE_HW_EVENT_SERR) { 35738c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 35748c2ecf20Sopenharmony_ci "%s: Encountered Serious Error", 35758c2ecf20Sopenharmony_ci vdev->ndev->name); 35768c2ecf20Sopenharmony_ci } else if (type == VXGE_HW_EVENT_CRITICAL_ERR) 35778c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 35788c2ecf20Sopenharmony_ci "%s: Encountered Critical Error", 35798c2ecf20Sopenharmony_ci vdev->ndev->name); 35808c2ecf20Sopenharmony_ci } 35818c2ecf20Sopenharmony_ci 35828c2ecf20Sopenharmony_ci if ((type == VXGE_HW_EVENT_SERR) || 35838c2ecf20Sopenharmony_ci (type == VXGE_HW_EVENT_SLOT_FREEZE)) { 35848c2ecf20Sopenharmony_ci if (unlikely(vdev->exec_mode)) 35858c2ecf20Sopenharmony_ci clear_bit(__VXGE_STATE_CARD_UP, &vdev->state); 35868c2ecf20Sopenharmony_ci } else if (type == VXGE_HW_EVENT_CRITICAL_ERR) { 35878c2ecf20Sopenharmony_ci vxge_hw_device_mask_all(hldev); 35888c2ecf20Sopenharmony_ci if (unlikely(vdev->exec_mode)) 35898c2ecf20Sopenharmony_ci clear_bit(__VXGE_STATE_CARD_UP, &vdev->state); 35908c2ecf20Sopenharmony_ci } else if ((type == VXGE_HW_EVENT_FIFO_ERR) || 35918c2ecf20Sopenharmony_ci (type == VXGE_HW_EVENT_VPATH_ERR)) { 35928c2ecf20Sopenharmony_ci 35938c2ecf20Sopenharmony_ci if (unlikely(vdev->exec_mode)) 35948c2ecf20Sopenharmony_ci clear_bit(__VXGE_STATE_CARD_UP, &vdev->state); 35958c2ecf20Sopenharmony_ci else { 35968c2ecf20Sopenharmony_ci /* check if this vpath is already set for reset */ 35978c2ecf20Sopenharmony_ci if (!test_and_set_bit(vpath_idx, &vdev->vp_reset)) { 35988c2ecf20Sopenharmony_ci 35998c2ecf20Sopenharmony_ci /* disable interrupts for this vpath */ 36008c2ecf20Sopenharmony_ci vxge_vpath_intr_disable(vdev, vpath_idx); 36018c2ecf20Sopenharmony_ci 36028c2ecf20Sopenharmony_ci /* stop the queue for this vpath */ 36038c2ecf20Sopenharmony_ci netif_tx_stop_queue(vpath->fifo.txq); 36048c2ecf20Sopenharmony_ci } 36058c2ecf20Sopenharmony_ci } 36068c2ecf20Sopenharmony_ci } 36078c2ecf20Sopenharmony_ci 36088c2ecf20Sopenharmony_ci vxge_debug_entryexit(vdev->level_trace, 36098c2ecf20Sopenharmony_ci "%s: %s:%d Exiting...", 36108c2ecf20Sopenharmony_ci vdev->ndev->name, __func__, __LINE__); 36118c2ecf20Sopenharmony_ci} 36128c2ecf20Sopenharmony_ci 36138c2ecf20Sopenharmony_cistatic void verify_bandwidth(void) 36148c2ecf20Sopenharmony_ci{ 36158c2ecf20Sopenharmony_ci int i, band_width, total = 0, equal_priority = 0; 36168c2ecf20Sopenharmony_ci 36178c2ecf20Sopenharmony_ci /* 1. If user enters 0 for some fifo, give equal priority to all */ 36188c2ecf20Sopenharmony_ci for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { 36198c2ecf20Sopenharmony_ci if (bw_percentage[i] == 0) { 36208c2ecf20Sopenharmony_ci equal_priority = 1; 36218c2ecf20Sopenharmony_ci break; 36228c2ecf20Sopenharmony_ci } 36238c2ecf20Sopenharmony_ci } 36248c2ecf20Sopenharmony_ci 36258c2ecf20Sopenharmony_ci if (!equal_priority) { 36268c2ecf20Sopenharmony_ci /* 2. If sum exceeds 100, give equal priority to all */ 36278c2ecf20Sopenharmony_ci for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { 36288c2ecf20Sopenharmony_ci if (bw_percentage[i] == 0xFF) 36298c2ecf20Sopenharmony_ci break; 36308c2ecf20Sopenharmony_ci 36318c2ecf20Sopenharmony_ci total += bw_percentage[i]; 36328c2ecf20Sopenharmony_ci if (total > VXGE_HW_VPATH_BANDWIDTH_MAX) { 36338c2ecf20Sopenharmony_ci equal_priority = 1; 36348c2ecf20Sopenharmony_ci break; 36358c2ecf20Sopenharmony_ci } 36368c2ecf20Sopenharmony_ci } 36378c2ecf20Sopenharmony_ci } 36388c2ecf20Sopenharmony_ci 36398c2ecf20Sopenharmony_ci if (!equal_priority) { 36408c2ecf20Sopenharmony_ci /* Is all the bandwidth consumed? */ 36418c2ecf20Sopenharmony_ci if (total < VXGE_HW_VPATH_BANDWIDTH_MAX) { 36428c2ecf20Sopenharmony_ci if (i < VXGE_HW_MAX_VIRTUAL_PATHS) { 36438c2ecf20Sopenharmony_ci /* Split rest of bw equally among next VPs*/ 36448c2ecf20Sopenharmony_ci band_width = 36458c2ecf20Sopenharmony_ci (VXGE_HW_VPATH_BANDWIDTH_MAX - total) / 36468c2ecf20Sopenharmony_ci (VXGE_HW_MAX_VIRTUAL_PATHS - i); 36478c2ecf20Sopenharmony_ci if (band_width < 2) /* min of 2% */ 36488c2ecf20Sopenharmony_ci equal_priority = 1; 36498c2ecf20Sopenharmony_ci else { 36508c2ecf20Sopenharmony_ci for (; i < VXGE_HW_MAX_VIRTUAL_PATHS; 36518c2ecf20Sopenharmony_ci i++) 36528c2ecf20Sopenharmony_ci bw_percentage[i] = 36538c2ecf20Sopenharmony_ci band_width; 36548c2ecf20Sopenharmony_ci } 36558c2ecf20Sopenharmony_ci } 36568c2ecf20Sopenharmony_ci } else if (i < VXGE_HW_MAX_VIRTUAL_PATHS) 36578c2ecf20Sopenharmony_ci equal_priority = 1; 36588c2ecf20Sopenharmony_ci } 36598c2ecf20Sopenharmony_ci 36608c2ecf20Sopenharmony_ci if (equal_priority) { 36618c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 36628c2ecf20Sopenharmony_ci "%s: Assigning equal bandwidth to all the vpaths", 36638c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME); 36648c2ecf20Sopenharmony_ci bw_percentage[0] = VXGE_HW_VPATH_BANDWIDTH_MAX / 36658c2ecf20Sopenharmony_ci VXGE_HW_MAX_VIRTUAL_PATHS; 36668c2ecf20Sopenharmony_ci for (i = 1; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) 36678c2ecf20Sopenharmony_ci bw_percentage[i] = bw_percentage[0]; 36688c2ecf20Sopenharmony_ci } 36698c2ecf20Sopenharmony_ci} 36708c2ecf20Sopenharmony_ci 36718c2ecf20Sopenharmony_ci/* 36728c2ecf20Sopenharmony_ci * Vpath configuration 36738c2ecf20Sopenharmony_ci */ 36748c2ecf20Sopenharmony_cistatic int vxge_config_vpaths(struct vxge_hw_device_config *device_config, 36758c2ecf20Sopenharmony_ci u64 vpath_mask, struct vxge_config *config_param) 36768c2ecf20Sopenharmony_ci{ 36778c2ecf20Sopenharmony_ci int i, no_of_vpaths = 0, default_no_vpath = 0, temp; 36788c2ecf20Sopenharmony_ci u32 txdl_size, txdl_per_memblock; 36798c2ecf20Sopenharmony_ci 36808c2ecf20Sopenharmony_ci temp = driver_config->vpath_per_dev; 36818c2ecf20Sopenharmony_ci if ((driver_config->vpath_per_dev == VXGE_USE_DEFAULT) && 36828c2ecf20Sopenharmony_ci (max_config_dev == VXGE_MAX_CONFIG_DEV)) { 36838c2ecf20Sopenharmony_ci /* No more CPU. Return vpath number as zero.*/ 36848c2ecf20Sopenharmony_ci if (driver_config->g_no_cpus == -1) 36858c2ecf20Sopenharmony_ci return 0; 36868c2ecf20Sopenharmony_ci 36878c2ecf20Sopenharmony_ci if (!driver_config->g_no_cpus) 36888c2ecf20Sopenharmony_ci driver_config->g_no_cpus = 36898c2ecf20Sopenharmony_ci netif_get_num_default_rss_queues(); 36908c2ecf20Sopenharmony_ci 36918c2ecf20Sopenharmony_ci driver_config->vpath_per_dev = driver_config->g_no_cpus >> 1; 36928c2ecf20Sopenharmony_ci if (!driver_config->vpath_per_dev) 36938c2ecf20Sopenharmony_ci driver_config->vpath_per_dev = 1; 36948c2ecf20Sopenharmony_ci 36958c2ecf20Sopenharmony_ci for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) 36968c2ecf20Sopenharmony_ci if (!vxge_bVALn(vpath_mask, i, 1)) 36978c2ecf20Sopenharmony_ci continue; 36988c2ecf20Sopenharmony_ci else 36998c2ecf20Sopenharmony_ci default_no_vpath++; 37008c2ecf20Sopenharmony_ci if (default_no_vpath < driver_config->vpath_per_dev) 37018c2ecf20Sopenharmony_ci driver_config->vpath_per_dev = default_no_vpath; 37028c2ecf20Sopenharmony_ci 37038c2ecf20Sopenharmony_ci driver_config->g_no_cpus = driver_config->g_no_cpus - 37048c2ecf20Sopenharmony_ci (driver_config->vpath_per_dev * 2); 37058c2ecf20Sopenharmony_ci if (driver_config->g_no_cpus <= 0) 37068c2ecf20Sopenharmony_ci driver_config->g_no_cpus = -1; 37078c2ecf20Sopenharmony_ci } 37088c2ecf20Sopenharmony_ci 37098c2ecf20Sopenharmony_ci if (driver_config->vpath_per_dev == 1) { 37108c2ecf20Sopenharmony_ci vxge_debug_ll_config(VXGE_TRACE, 37118c2ecf20Sopenharmony_ci "%s: Disable tx and rx steering, " 37128c2ecf20Sopenharmony_ci "as single vpath is configured", VXGE_DRIVER_NAME); 37138c2ecf20Sopenharmony_ci config_param->rth_steering = NO_STEERING; 37148c2ecf20Sopenharmony_ci config_param->tx_steering_type = NO_STEERING; 37158c2ecf20Sopenharmony_ci device_config->rth_en = 0; 37168c2ecf20Sopenharmony_ci } 37178c2ecf20Sopenharmony_ci 37188c2ecf20Sopenharmony_ci /* configure bandwidth */ 37198c2ecf20Sopenharmony_ci for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) 37208c2ecf20Sopenharmony_ci device_config->vp_config[i].min_bandwidth = bw_percentage[i]; 37218c2ecf20Sopenharmony_ci 37228c2ecf20Sopenharmony_ci for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { 37238c2ecf20Sopenharmony_ci device_config->vp_config[i].vp_id = i; 37248c2ecf20Sopenharmony_ci device_config->vp_config[i].mtu = VXGE_HW_DEFAULT_MTU; 37258c2ecf20Sopenharmony_ci if (no_of_vpaths < driver_config->vpath_per_dev) { 37268c2ecf20Sopenharmony_ci if (!vxge_bVALn(vpath_mask, i, 1)) { 37278c2ecf20Sopenharmony_ci vxge_debug_ll_config(VXGE_TRACE, 37288c2ecf20Sopenharmony_ci "%s: vpath: %d is not available", 37298c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME, i); 37308c2ecf20Sopenharmony_ci continue; 37318c2ecf20Sopenharmony_ci } else { 37328c2ecf20Sopenharmony_ci vxge_debug_ll_config(VXGE_TRACE, 37338c2ecf20Sopenharmony_ci "%s: vpath: %d available", 37348c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME, i); 37358c2ecf20Sopenharmony_ci no_of_vpaths++; 37368c2ecf20Sopenharmony_ci } 37378c2ecf20Sopenharmony_ci } else { 37388c2ecf20Sopenharmony_ci vxge_debug_ll_config(VXGE_TRACE, 37398c2ecf20Sopenharmony_ci "%s: vpath: %d is not configured, " 37408c2ecf20Sopenharmony_ci "max_config_vpath exceeded", 37418c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME, i); 37428c2ecf20Sopenharmony_ci break; 37438c2ecf20Sopenharmony_ci } 37448c2ecf20Sopenharmony_ci 37458c2ecf20Sopenharmony_ci /* Configure Tx fifo's */ 37468c2ecf20Sopenharmony_ci device_config->vp_config[i].fifo.enable = 37478c2ecf20Sopenharmony_ci VXGE_HW_FIFO_ENABLE; 37488c2ecf20Sopenharmony_ci device_config->vp_config[i].fifo.max_frags = 37498c2ecf20Sopenharmony_ci MAX_SKB_FRAGS + 1; 37508c2ecf20Sopenharmony_ci device_config->vp_config[i].fifo.memblock_size = 37518c2ecf20Sopenharmony_ci VXGE_HW_MIN_FIFO_MEMBLOCK_SIZE; 37528c2ecf20Sopenharmony_ci 37538c2ecf20Sopenharmony_ci txdl_size = device_config->vp_config[i].fifo.max_frags * 37548c2ecf20Sopenharmony_ci sizeof(struct vxge_hw_fifo_txd); 37558c2ecf20Sopenharmony_ci txdl_per_memblock = VXGE_HW_MIN_FIFO_MEMBLOCK_SIZE / txdl_size; 37568c2ecf20Sopenharmony_ci 37578c2ecf20Sopenharmony_ci device_config->vp_config[i].fifo.fifo_blocks = 37588c2ecf20Sopenharmony_ci ((VXGE_DEF_FIFO_LENGTH - 1) / txdl_per_memblock) + 1; 37598c2ecf20Sopenharmony_ci 37608c2ecf20Sopenharmony_ci device_config->vp_config[i].fifo.intr = 37618c2ecf20Sopenharmony_ci VXGE_HW_FIFO_QUEUE_INTR_DISABLE; 37628c2ecf20Sopenharmony_ci 37638c2ecf20Sopenharmony_ci /* Configure tti properties */ 37648c2ecf20Sopenharmony_ci device_config->vp_config[i].tti.intr_enable = 37658c2ecf20Sopenharmony_ci VXGE_HW_TIM_INTR_ENABLE; 37668c2ecf20Sopenharmony_ci 37678c2ecf20Sopenharmony_ci device_config->vp_config[i].tti.btimer_val = 37688c2ecf20Sopenharmony_ci (VXGE_TTI_BTIMER_VAL * 1000) / 272; 37698c2ecf20Sopenharmony_ci 37708c2ecf20Sopenharmony_ci device_config->vp_config[i].tti.timer_ac_en = 37718c2ecf20Sopenharmony_ci VXGE_HW_TIM_TIMER_AC_ENABLE; 37728c2ecf20Sopenharmony_ci 37738c2ecf20Sopenharmony_ci /* For msi-x with napi (each vector has a handler of its own) - 37748c2ecf20Sopenharmony_ci * Set CI to OFF for all vpaths 37758c2ecf20Sopenharmony_ci */ 37768c2ecf20Sopenharmony_ci device_config->vp_config[i].tti.timer_ci_en = 37778c2ecf20Sopenharmony_ci VXGE_HW_TIM_TIMER_CI_DISABLE; 37788c2ecf20Sopenharmony_ci 37798c2ecf20Sopenharmony_ci device_config->vp_config[i].tti.timer_ri_en = 37808c2ecf20Sopenharmony_ci VXGE_HW_TIM_TIMER_RI_DISABLE; 37818c2ecf20Sopenharmony_ci 37828c2ecf20Sopenharmony_ci device_config->vp_config[i].tti.util_sel = 37838c2ecf20Sopenharmony_ci VXGE_HW_TIM_UTIL_SEL_LEGACY_TX_NET_UTIL; 37848c2ecf20Sopenharmony_ci 37858c2ecf20Sopenharmony_ci device_config->vp_config[i].tti.ltimer_val = 37868c2ecf20Sopenharmony_ci (VXGE_TTI_LTIMER_VAL * 1000) / 272; 37878c2ecf20Sopenharmony_ci 37888c2ecf20Sopenharmony_ci device_config->vp_config[i].tti.rtimer_val = 37898c2ecf20Sopenharmony_ci (VXGE_TTI_RTIMER_VAL * 1000) / 272; 37908c2ecf20Sopenharmony_ci 37918c2ecf20Sopenharmony_ci device_config->vp_config[i].tti.urange_a = TTI_TX_URANGE_A; 37928c2ecf20Sopenharmony_ci device_config->vp_config[i].tti.urange_b = TTI_TX_URANGE_B; 37938c2ecf20Sopenharmony_ci device_config->vp_config[i].tti.urange_c = TTI_TX_URANGE_C; 37948c2ecf20Sopenharmony_ci device_config->vp_config[i].tti.uec_a = TTI_TX_UFC_A; 37958c2ecf20Sopenharmony_ci device_config->vp_config[i].tti.uec_b = TTI_TX_UFC_B; 37968c2ecf20Sopenharmony_ci device_config->vp_config[i].tti.uec_c = TTI_TX_UFC_C; 37978c2ecf20Sopenharmony_ci device_config->vp_config[i].tti.uec_d = TTI_TX_UFC_D; 37988c2ecf20Sopenharmony_ci 37998c2ecf20Sopenharmony_ci /* Configure Rx rings */ 38008c2ecf20Sopenharmony_ci device_config->vp_config[i].ring.enable = 38018c2ecf20Sopenharmony_ci VXGE_HW_RING_ENABLE; 38028c2ecf20Sopenharmony_ci 38038c2ecf20Sopenharmony_ci device_config->vp_config[i].ring.ring_blocks = 38048c2ecf20Sopenharmony_ci VXGE_HW_DEF_RING_BLOCKS; 38058c2ecf20Sopenharmony_ci 38068c2ecf20Sopenharmony_ci device_config->vp_config[i].ring.buffer_mode = 38078c2ecf20Sopenharmony_ci VXGE_HW_RING_RXD_BUFFER_MODE_1; 38088c2ecf20Sopenharmony_ci 38098c2ecf20Sopenharmony_ci device_config->vp_config[i].ring.rxds_limit = 38108c2ecf20Sopenharmony_ci VXGE_HW_DEF_RING_RXDS_LIMIT; 38118c2ecf20Sopenharmony_ci 38128c2ecf20Sopenharmony_ci device_config->vp_config[i].ring.scatter_mode = 38138c2ecf20Sopenharmony_ci VXGE_HW_RING_SCATTER_MODE_A; 38148c2ecf20Sopenharmony_ci 38158c2ecf20Sopenharmony_ci /* Configure rti properties */ 38168c2ecf20Sopenharmony_ci device_config->vp_config[i].rti.intr_enable = 38178c2ecf20Sopenharmony_ci VXGE_HW_TIM_INTR_ENABLE; 38188c2ecf20Sopenharmony_ci 38198c2ecf20Sopenharmony_ci device_config->vp_config[i].rti.btimer_val = 38208c2ecf20Sopenharmony_ci (VXGE_RTI_BTIMER_VAL * 1000)/272; 38218c2ecf20Sopenharmony_ci 38228c2ecf20Sopenharmony_ci device_config->vp_config[i].rti.timer_ac_en = 38238c2ecf20Sopenharmony_ci VXGE_HW_TIM_TIMER_AC_ENABLE; 38248c2ecf20Sopenharmony_ci 38258c2ecf20Sopenharmony_ci device_config->vp_config[i].rti.timer_ci_en = 38268c2ecf20Sopenharmony_ci VXGE_HW_TIM_TIMER_CI_DISABLE; 38278c2ecf20Sopenharmony_ci 38288c2ecf20Sopenharmony_ci device_config->vp_config[i].rti.timer_ri_en = 38298c2ecf20Sopenharmony_ci VXGE_HW_TIM_TIMER_RI_DISABLE; 38308c2ecf20Sopenharmony_ci 38318c2ecf20Sopenharmony_ci device_config->vp_config[i].rti.util_sel = 38328c2ecf20Sopenharmony_ci VXGE_HW_TIM_UTIL_SEL_LEGACY_RX_NET_UTIL; 38338c2ecf20Sopenharmony_ci 38348c2ecf20Sopenharmony_ci device_config->vp_config[i].rti.urange_a = 38358c2ecf20Sopenharmony_ci RTI_RX_URANGE_A; 38368c2ecf20Sopenharmony_ci device_config->vp_config[i].rti.urange_b = 38378c2ecf20Sopenharmony_ci RTI_RX_URANGE_B; 38388c2ecf20Sopenharmony_ci device_config->vp_config[i].rti.urange_c = 38398c2ecf20Sopenharmony_ci RTI_RX_URANGE_C; 38408c2ecf20Sopenharmony_ci device_config->vp_config[i].rti.uec_a = RTI_RX_UFC_A; 38418c2ecf20Sopenharmony_ci device_config->vp_config[i].rti.uec_b = RTI_RX_UFC_B; 38428c2ecf20Sopenharmony_ci device_config->vp_config[i].rti.uec_c = RTI_RX_UFC_C; 38438c2ecf20Sopenharmony_ci device_config->vp_config[i].rti.uec_d = RTI_RX_UFC_D; 38448c2ecf20Sopenharmony_ci 38458c2ecf20Sopenharmony_ci device_config->vp_config[i].rti.rtimer_val = 38468c2ecf20Sopenharmony_ci (VXGE_RTI_RTIMER_VAL * 1000) / 272; 38478c2ecf20Sopenharmony_ci 38488c2ecf20Sopenharmony_ci device_config->vp_config[i].rti.ltimer_val = 38498c2ecf20Sopenharmony_ci (VXGE_RTI_LTIMER_VAL * 1000) / 272; 38508c2ecf20Sopenharmony_ci 38518c2ecf20Sopenharmony_ci device_config->vp_config[i].rpa_strip_vlan_tag = 38528c2ecf20Sopenharmony_ci vlan_tag_strip; 38538c2ecf20Sopenharmony_ci } 38548c2ecf20Sopenharmony_ci 38558c2ecf20Sopenharmony_ci driver_config->vpath_per_dev = temp; 38568c2ecf20Sopenharmony_ci return no_of_vpaths; 38578c2ecf20Sopenharmony_ci} 38588c2ecf20Sopenharmony_ci 38598c2ecf20Sopenharmony_ci/* initialize device configuratrions */ 38608c2ecf20Sopenharmony_cistatic void vxge_device_config_init(struct vxge_hw_device_config *device_config, 38618c2ecf20Sopenharmony_ci int *intr_type) 38628c2ecf20Sopenharmony_ci{ 38638c2ecf20Sopenharmony_ci /* Used for CQRQ/SRQ. */ 38648c2ecf20Sopenharmony_ci device_config->dma_blockpool_initial = 38658c2ecf20Sopenharmony_ci VXGE_HW_INITIAL_DMA_BLOCK_POOL_SIZE; 38668c2ecf20Sopenharmony_ci 38678c2ecf20Sopenharmony_ci device_config->dma_blockpool_max = 38688c2ecf20Sopenharmony_ci VXGE_HW_MAX_DMA_BLOCK_POOL_SIZE; 38698c2ecf20Sopenharmony_ci 38708c2ecf20Sopenharmony_ci if (max_mac_vpath > VXGE_MAX_MAC_ADDR_COUNT) 38718c2ecf20Sopenharmony_ci max_mac_vpath = VXGE_MAX_MAC_ADDR_COUNT; 38728c2ecf20Sopenharmony_ci 38738c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_PCI_MSI)) { 38748c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 38758c2ecf20Sopenharmony_ci "%s: This Kernel does not support " 38768c2ecf20Sopenharmony_ci "MSI-X. Defaulting to INTA", VXGE_DRIVER_NAME); 38778c2ecf20Sopenharmony_ci *intr_type = INTA; 38788c2ecf20Sopenharmony_ci } 38798c2ecf20Sopenharmony_ci 38808c2ecf20Sopenharmony_ci /* Configure whether MSI-X or IRQL. */ 38818c2ecf20Sopenharmony_ci switch (*intr_type) { 38828c2ecf20Sopenharmony_ci case INTA: 38838c2ecf20Sopenharmony_ci device_config->intr_mode = VXGE_HW_INTR_MODE_IRQLINE; 38848c2ecf20Sopenharmony_ci break; 38858c2ecf20Sopenharmony_ci 38868c2ecf20Sopenharmony_ci case MSI_X: 38878c2ecf20Sopenharmony_ci device_config->intr_mode = VXGE_HW_INTR_MODE_MSIX_ONE_SHOT; 38888c2ecf20Sopenharmony_ci break; 38898c2ecf20Sopenharmony_ci } 38908c2ecf20Sopenharmony_ci 38918c2ecf20Sopenharmony_ci /* Timer period between device poll */ 38928c2ecf20Sopenharmony_ci device_config->device_poll_millis = VXGE_TIMER_DELAY; 38938c2ecf20Sopenharmony_ci 38948c2ecf20Sopenharmony_ci /* Configure mac based steering. */ 38958c2ecf20Sopenharmony_ci device_config->rts_mac_en = addr_learn_en; 38968c2ecf20Sopenharmony_ci 38978c2ecf20Sopenharmony_ci /* Configure Vpaths */ 38988c2ecf20Sopenharmony_ci device_config->rth_it_type = VXGE_HW_RTH_IT_TYPE_MULTI_IT; 38998c2ecf20Sopenharmony_ci 39008c2ecf20Sopenharmony_ci vxge_debug_ll_config(VXGE_TRACE, "%s : Device Config Params ", 39018c2ecf20Sopenharmony_ci __func__); 39028c2ecf20Sopenharmony_ci vxge_debug_ll_config(VXGE_TRACE, "intr_mode : %d", 39038c2ecf20Sopenharmony_ci device_config->intr_mode); 39048c2ecf20Sopenharmony_ci vxge_debug_ll_config(VXGE_TRACE, "device_poll_millis : %d", 39058c2ecf20Sopenharmony_ci device_config->device_poll_millis); 39068c2ecf20Sopenharmony_ci vxge_debug_ll_config(VXGE_TRACE, "rth_en : %d", 39078c2ecf20Sopenharmony_ci device_config->rth_en); 39088c2ecf20Sopenharmony_ci vxge_debug_ll_config(VXGE_TRACE, "rth_it_type : %d", 39098c2ecf20Sopenharmony_ci device_config->rth_it_type); 39108c2ecf20Sopenharmony_ci} 39118c2ecf20Sopenharmony_ci 39128c2ecf20Sopenharmony_cistatic void vxge_print_parm(struct vxgedev *vdev, u64 vpath_mask) 39138c2ecf20Sopenharmony_ci{ 39148c2ecf20Sopenharmony_ci int i; 39158c2ecf20Sopenharmony_ci 39168c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 39178c2ecf20Sopenharmony_ci "%s: %d Vpath(s) opened", 39188c2ecf20Sopenharmony_ci vdev->ndev->name, vdev->no_of_vpath); 39198c2ecf20Sopenharmony_ci 39208c2ecf20Sopenharmony_ci switch (vdev->config.intr_type) { 39218c2ecf20Sopenharmony_ci case INTA: 39228c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 39238c2ecf20Sopenharmony_ci "%s: Interrupt type INTA", vdev->ndev->name); 39248c2ecf20Sopenharmony_ci break; 39258c2ecf20Sopenharmony_ci 39268c2ecf20Sopenharmony_ci case MSI_X: 39278c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 39288c2ecf20Sopenharmony_ci "%s: Interrupt type MSI-X", vdev->ndev->name); 39298c2ecf20Sopenharmony_ci break; 39308c2ecf20Sopenharmony_ci } 39318c2ecf20Sopenharmony_ci 39328c2ecf20Sopenharmony_ci if (vdev->config.rth_steering) { 39338c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 39348c2ecf20Sopenharmony_ci "%s: RTH steering enabled for TCP_IPV4", 39358c2ecf20Sopenharmony_ci vdev->ndev->name); 39368c2ecf20Sopenharmony_ci } else { 39378c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 39388c2ecf20Sopenharmony_ci "%s: RTH steering disabled", vdev->ndev->name); 39398c2ecf20Sopenharmony_ci } 39408c2ecf20Sopenharmony_ci 39418c2ecf20Sopenharmony_ci switch (vdev->config.tx_steering_type) { 39428c2ecf20Sopenharmony_ci case NO_STEERING: 39438c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 39448c2ecf20Sopenharmony_ci "%s: Tx steering disabled", vdev->ndev->name); 39458c2ecf20Sopenharmony_ci break; 39468c2ecf20Sopenharmony_ci case TX_PRIORITY_STEERING: 39478c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 39488c2ecf20Sopenharmony_ci "%s: Unsupported tx steering option", 39498c2ecf20Sopenharmony_ci vdev->ndev->name); 39508c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 39518c2ecf20Sopenharmony_ci "%s: Tx steering disabled", vdev->ndev->name); 39528c2ecf20Sopenharmony_ci vdev->config.tx_steering_type = 0; 39538c2ecf20Sopenharmony_ci break; 39548c2ecf20Sopenharmony_ci case TX_VLAN_STEERING: 39558c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 39568c2ecf20Sopenharmony_ci "%s: Unsupported tx steering option", 39578c2ecf20Sopenharmony_ci vdev->ndev->name); 39588c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 39598c2ecf20Sopenharmony_ci "%s: Tx steering disabled", vdev->ndev->name); 39608c2ecf20Sopenharmony_ci vdev->config.tx_steering_type = 0; 39618c2ecf20Sopenharmony_ci break; 39628c2ecf20Sopenharmony_ci case TX_MULTIQ_STEERING: 39638c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 39648c2ecf20Sopenharmony_ci "%s: Tx multiqueue steering enabled", 39658c2ecf20Sopenharmony_ci vdev->ndev->name); 39668c2ecf20Sopenharmony_ci break; 39678c2ecf20Sopenharmony_ci case TX_PORT_STEERING: 39688c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 39698c2ecf20Sopenharmony_ci "%s: Tx port steering enabled", 39708c2ecf20Sopenharmony_ci vdev->ndev->name); 39718c2ecf20Sopenharmony_ci break; 39728c2ecf20Sopenharmony_ci default: 39738c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 39748c2ecf20Sopenharmony_ci "%s: Unsupported tx steering type", 39758c2ecf20Sopenharmony_ci vdev->ndev->name); 39768c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 39778c2ecf20Sopenharmony_ci "%s: Tx steering disabled", vdev->ndev->name); 39788c2ecf20Sopenharmony_ci vdev->config.tx_steering_type = 0; 39798c2ecf20Sopenharmony_ci } 39808c2ecf20Sopenharmony_ci 39818c2ecf20Sopenharmony_ci if (vdev->config.addr_learn_en) 39828c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 39838c2ecf20Sopenharmony_ci "%s: MAC Address learning enabled", vdev->ndev->name); 39848c2ecf20Sopenharmony_ci 39858c2ecf20Sopenharmony_ci for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { 39868c2ecf20Sopenharmony_ci if (!vxge_bVALn(vpath_mask, i, 1)) 39878c2ecf20Sopenharmony_ci continue; 39888c2ecf20Sopenharmony_ci vxge_debug_ll_config(VXGE_TRACE, 39898c2ecf20Sopenharmony_ci "%s: MTU size - %d", vdev->ndev->name, 39908c2ecf20Sopenharmony_ci ((vdev->devh))-> 39918c2ecf20Sopenharmony_ci config.vp_config[i].mtu); 39928c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 39938c2ecf20Sopenharmony_ci "%s: VLAN tag stripping %s", vdev->ndev->name, 39948c2ecf20Sopenharmony_ci ((vdev->devh))-> 39958c2ecf20Sopenharmony_ci config.vp_config[i].rpa_strip_vlan_tag 39968c2ecf20Sopenharmony_ci ? "Enabled" : "Disabled"); 39978c2ecf20Sopenharmony_ci vxge_debug_ll_config(VXGE_TRACE, 39988c2ecf20Sopenharmony_ci "%s: Max frags : %d", vdev->ndev->name, 39998c2ecf20Sopenharmony_ci ((vdev->devh))-> 40008c2ecf20Sopenharmony_ci config.vp_config[i].fifo.max_frags); 40018c2ecf20Sopenharmony_ci break; 40028c2ecf20Sopenharmony_ci } 40038c2ecf20Sopenharmony_ci} 40048c2ecf20Sopenharmony_ci 40058c2ecf20Sopenharmony_ci/** 40068c2ecf20Sopenharmony_ci * vxge_pm_suspend - vxge power management suspend entry point 40078c2ecf20Sopenharmony_ci * @dev_d: device pointer 40088c2ecf20Sopenharmony_ci * 40098c2ecf20Sopenharmony_ci */ 40108c2ecf20Sopenharmony_cistatic int __maybe_unused vxge_pm_suspend(struct device *dev_d) 40118c2ecf20Sopenharmony_ci{ 40128c2ecf20Sopenharmony_ci return -ENOSYS; 40138c2ecf20Sopenharmony_ci} 40148c2ecf20Sopenharmony_ci/** 40158c2ecf20Sopenharmony_ci * vxge_pm_resume - vxge power management resume entry point 40168c2ecf20Sopenharmony_ci * @dev_d: device pointer 40178c2ecf20Sopenharmony_ci * 40188c2ecf20Sopenharmony_ci */ 40198c2ecf20Sopenharmony_cistatic int __maybe_unused vxge_pm_resume(struct device *dev_d) 40208c2ecf20Sopenharmony_ci{ 40218c2ecf20Sopenharmony_ci return -ENOSYS; 40228c2ecf20Sopenharmony_ci} 40238c2ecf20Sopenharmony_ci 40248c2ecf20Sopenharmony_ci/** 40258c2ecf20Sopenharmony_ci * vxge_io_error_detected - called when PCI error is detected 40268c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device 40278c2ecf20Sopenharmony_ci * @state: The current pci connection state 40288c2ecf20Sopenharmony_ci * 40298c2ecf20Sopenharmony_ci * This function is called after a PCI bus error affecting 40308c2ecf20Sopenharmony_ci * this device has been detected. 40318c2ecf20Sopenharmony_ci */ 40328c2ecf20Sopenharmony_cistatic pci_ers_result_t vxge_io_error_detected(struct pci_dev *pdev, 40338c2ecf20Sopenharmony_ci pci_channel_state_t state) 40348c2ecf20Sopenharmony_ci{ 40358c2ecf20Sopenharmony_ci struct __vxge_hw_device *hldev = pci_get_drvdata(pdev); 40368c2ecf20Sopenharmony_ci struct net_device *netdev = hldev->ndev; 40378c2ecf20Sopenharmony_ci 40388c2ecf20Sopenharmony_ci netif_device_detach(netdev); 40398c2ecf20Sopenharmony_ci 40408c2ecf20Sopenharmony_ci if (state == pci_channel_io_perm_failure) 40418c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 40428c2ecf20Sopenharmony_ci 40438c2ecf20Sopenharmony_ci if (netif_running(netdev)) { 40448c2ecf20Sopenharmony_ci /* Bring down the card, while avoiding PCI I/O */ 40458c2ecf20Sopenharmony_ci do_vxge_close(netdev, 0); 40468c2ecf20Sopenharmony_ci } 40478c2ecf20Sopenharmony_ci 40488c2ecf20Sopenharmony_ci pci_disable_device(pdev); 40498c2ecf20Sopenharmony_ci 40508c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_NEED_RESET; 40518c2ecf20Sopenharmony_ci} 40528c2ecf20Sopenharmony_ci 40538c2ecf20Sopenharmony_ci/** 40548c2ecf20Sopenharmony_ci * vxge_io_slot_reset - called after the pci bus has been reset. 40558c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device 40568c2ecf20Sopenharmony_ci * 40578c2ecf20Sopenharmony_ci * Restart the card from scratch, as if from a cold-boot. 40588c2ecf20Sopenharmony_ci * At this point, the card has exprienced a hard reset, 40598c2ecf20Sopenharmony_ci * followed by fixups by BIOS, and has its config space 40608c2ecf20Sopenharmony_ci * set up identically to what it was at cold boot. 40618c2ecf20Sopenharmony_ci */ 40628c2ecf20Sopenharmony_cistatic pci_ers_result_t vxge_io_slot_reset(struct pci_dev *pdev) 40638c2ecf20Sopenharmony_ci{ 40648c2ecf20Sopenharmony_ci struct __vxge_hw_device *hldev = pci_get_drvdata(pdev); 40658c2ecf20Sopenharmony_ci struct net_device *netdev = hldev->ndev; 40668c2ecf20Sopenharmony_ci 40678c2ecf20Sopenharmony_ci struct vxgedev *vdev = netdev_priv(netdev); 40688c2ecf20Sopenharmony_ci 40698c2ecf20Sopenharmony_ci if (pci_enable_device(pdev)) { 40708c2ecf20Sopenharmony_ci netdev_err(netdev, "Cannot re-enable device after reset\n"); 40718c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 40728c2ecf20Sopenharmony_ci } 40738c2ecf20Sopenharmony_ci 40748c2ecf20Sopenharmony_ci pci_set_master(pdev); 40758c2ecf20Sopenharmony_ci do_vxge_reset(vdev, VXGE_LL_FULL_RESET); 40768c2ecf20Sopenharmony_ci 40778c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_RECOVERED; 40788c2ecf20Sopenharmony_ci} 40798c2ecf20Sopenharmony_ci 40808c2ecf20Sopenharmony_ci/** 40818c2ecf20Sopenharmony_ci * vxge_io_resume - called when traffic can start flowing again. 40828c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device 40838c2ecf20Sopenharmony_ci * 40848c2ecf20Sopenharmony_ci * This callback is called when the error recovery driver tells 40858c2ecf20Sopenharmony_ci * us that its OK to resume normal operation. 40868c2ecf20Sopenharmony_ci */ 40878c2ecf20Sopenharmony_cistatic void vxge_io_resume(struct pci_dev *pdev) 40888c2ecf20Sopenharmony_ci{ 40898c2ecf20Sopenharmony_ci struct __vxge_hw_device *hldev = pci_get_drvdata(pdev); 40908c2ecf20Sopenharmony_ci struct net_device *netdev = hldev->ndev; 40918c2ecf20Sopenharmony_ci 40928c2ecf20Sopenharmony_ci if (netif_running(netdev)) { 40938c2ecf20Sopenharmony_ci if (vxge_open(netdev)) { 40948c2ecf20Sopenharmony_ci netdev_err(netdev, 40958c2ecf20Sopenharmony_ci "Can't bring device back up after reset\n"); 40968c2ecf20Sopenharmony_ci return; 40978c2ecf20Sopenharmony_ci } 40988c2ecf20Sopenharmony_ci } 40998c2ecf20Sopenharmony_ci 41008c2ecf20Sopenharmony_ci netif_device_attach(netdev); 41018c2ecf20Sopenharmony_ci} 41028c2ecf20Sopenharmony_ci 41038c2ecf20Sopenharmony_cistatic inline u32 vxge_get_num_vfs(u64 function_mode) 41048c2ecf20Sopenharmony_ci{ 41058c2ecf20Sopenharmony_ci u32 num_functions = 0; 41068c2ecf20Sopenharmony_ci 41078c2ecf20Sopenharmony_ci switch (function_mode) { 41088c2ecf20Sopenharmony_ci case VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION: 41098c2ecf20Sopenharmony_ci case VXGE_HW_FUNCTION_MODE_SRIOV_8: 41108c2ecf20Sopenharmony_ci num_functions = 8; 41118c2ecf20Sopenharmony_ci break; 41128c2ecf20Sopenharmony_ci case VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION: 41138c2ecf20Sopenharmony_ci num_functions = 1; 41148c2ecf20Sopenharmony_ci break; 41158c2ecf20Sopenharmony_ci case VXGE_HW_FUNCTION_MODE_SRIOV: 41168c2ecf20Sopenharmony_ci case VXGE_HW_FUNCTION_MODE_MRIOV: 41178c2ecf20Sopenharmony_ci case VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_17: 41188c2ecf20Sopenharmony_ci num_functions = 17; 41198c2ecf20Sopenharmony_ci break; 41208c2ecf20Sopenharmony_ci case VXGE_HW_FUNCTION_MODE_SRIOV_4: 41218c2ecf20Sopenharmony_ci num_functions = 4; 41228c2ecf20Sopenharmony_ci break; 41238c2ecf20Sopenharmony_ci case VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_2: 41248c2ecf20Sopenharmony_ci num_functions = 2; 41258c2ecf20Sopenharmony_ci break; 41268c2ecf20Sopenharmony_ci case VXGE_HW_FUNCTION_MODE_MRIOV_8: 41278c2ecf20Sopenharmony_ci num_functions = 8; /* TODO */ 41288c2ecf20Sopenharmony_ci break; 41298c2ecf20Sopenharmony_ci } 41308c2ecf20Sopenharmony_ci return num_functions; 41318c2ecf20Sopenharmony_ci} 41328c2ecf20Sopenharmony_ci 41338c2ecf20Sopenharmony_ciint vxge_fw_upgrade(struct vxgedev *vdev, char *fw_name, int override) 41348c2ecf20Sopenharmony_ci{ 41358c2ecf20Sopenharmony_ci struct __vxge_hw_device *hldev = vdev->devh; 41368c2ecf20Sopenharmony_ci u32 maj, min, bld, cmaj, cmin, cbld; 41378c2ecf20Sopenharmony_ci enum vxge_hw_status status; 41388c2ecf20Sopenharmony_ci const struct firmware *fw; 41398c2ecf20Sopenharmony_ci int ret; 41408c2ecf20Sopenharmony_ci 41418c2ecf20Sopenharmony_ci ret = request_firmware(&fw, fw_name, &vdev->pdev->dev); 41428c2ecf20Sopenharmony_ci if (ret) { 41438c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, "%s: Firmware file '%s' not found", 41448c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME, fw_name); 41458c2ecf20Sopenharmony_ci goto out; 41468c2ecf20Sopenharmony_ci } 41478c2ecf20Sopenharmony_ci 41488c2ecf20Sopenharmony_ci /* Load the new firmware onto the adapter */ 41498c2ecf20Sopenharmony_ci status = vxge_update_fw_image(hldev, fw->data, fw->size); 41508c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 41518c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 41528c2ecf20Sopenharmony_ci "%s: FW image download to adapter failed '%s'.", 41538c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME, fw_name); 41548c2ecf20Sopenharmony_ci ret = -EIO; 41558c2ecf20Sopenharmony_ci goto out; 41568c2ecf20Sopenharmony_ci } 41578c2ecf20Sopenharmony_ci 41588c2ecf20Sopenharmony_ci /* Read the version of the new firmware */ 41598c2ecf20Sopenharmony_ci status = vxge_hw_upgrade_read_version(hldev, &maj, &min, &bld); 41608c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 41618c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 41628c2ecf20Sopenharmony_ci "%s: Upgrade read version failed '%s'.", 41638c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME, fw_name); 41648c2ecf20Sopenharmony_ci ret = -EIO; 41658c2ecf20Sopenharmony_ci goto out; 41668c2ecf20Sopenharmony_ci } 41678c2ecf20Sopenharmony_ci 41688c2ecf20Sopenharmony_ci cmaj = vdev->config.device_hw_info.fw_version.major; 41698c2ecf20Sopenharmony_ci cmin = vdev->config.device_hw_info.fw_version.minor; 41708c2ecf20Sopenharmony_ci cbld = vdev->config.device_hw_info.fw_version.build; 41718c2ecf20Sopenharmony_ci /* It's possible the version in /lib/firmware is not the latest version. 41728c2ecf20Sopenharmony_ci * If so, we could get into a loop of trying to upgrade to the latest 41738c2ecf20Sopenharmony_ci * and flashing the older version. 41748c2ecf20Sopenharmony_ci */ 41758c2ecf20Sopenharmony_ci if (VXGE_FW_VER(maj, min, bld) == VXGE_FW_VER(cmaj, cmin, cbld) && 41768c2ecf20Sopenharmony_ci !override) { 41778c2ecf20Sopenharmony_ci ret = -EINVAL; 41788c2ecf20Sopenharmony_ci goto out; 41798c2ecf20Sopenharmony_ci } 41808c2ecf20Sopenharmony_ci 41818c2ecf20Sopenharmony_ci printk(KERN_NOTICE "Upgrade to firmware version %d.%d.%d commencing\n", 41828c2ecf20Sopenharmony_ci maj, min, bld); 41838c2ecf20Sopenharmony_ci 41848c2ecf20Sopenharmony_ci /* Flash the adapter with the new firmware */ 41858c2ecf20Sopenharmony_ci status = vxge_hw_flash_fw(hldev); 41868c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 41878c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, "%s: Upgrade commit failed '%s'.", 41888c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME, fw_name); 41898c2ecf20Sopenharmony_ci ret = -EIO; 41908c2ecf20Sopenharmony_ci goto out; 41918c2ecf20Sopenharmony_ci } 41928c2ecf20Sopenharmony_ci 41938c2ecf20Sopenharmony_ci printk(KERN_NOTICE "Upgrade of firmware successful! Adapter must be " 41948c2ecf20Sopenharmony_ci "hard reset before using, thus requiring a system reboot or a " 41958c2ecf20Sopenharmony_ci "hotplug event.\n"); 41968c2ecf20Sopenharmony_ci 41978c2ecf20Sopenharmony_ciout: 41988c2ecf20Sopenharmony_ci release_firmware(fw); 41998c2ecf20Sopenharmony_ci return ret; 42008c2ecf20Sopenharmony_ci} 42018c2ecf20Sopenharmony_ci 42028c2ecf20Sopenharmony_cistatic int vxge_probe_fw_update(struct vxgedev *vdev) 42038c2ecf20Sopenharmony_ci{ 42048c2ecf20Sopenharmony_ci u32 maj, min, bld; 42058c2ecf20Sopenharmony_ci int ret, gpxe = 0; 42068c2ecf20Sopenharmony_ci char *fw_name; 42078c2ecf20Sopenharmony_ci 42088c2ecf20Sopenharmony_ci maj = vdev->config.device_hw_info.fw_version.major; 42098c2ecf20Sopenharmony_ci min = vdev->config.device_hw_info.fw_version.minor; 42108c2ecf20Sopenharmony_ci bld = vdev->config.device_hw_info.fw_version.build; 42118c2ecf20Sopenharmony_ci 42128c2ecf20Sopenharmony_ci if (VXGE_FW_VER(maj, min, bld) == VXGE_CERT_FW_VER) 42138c2ecf20Sopenharmony_ci return 0; 42148c2ecf20Sopenharmony_ci 42158c2ecf20Sopenharmony_ci /* Ignore the build number when determining if the current firmware is 42168c2ecf20Sopenharmony_ci * "too new" to load the driver 42178c2ecf20Sopenharmony_ci */ 42188c2ecf20Sopenharmony_ci if (VXGE_FW_VER(maj, min, 0) > VXGE_CERT_FW_VER) { 42198c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, "%s: Firmware newer than last known " 42208c2ecf20Sopenharmony_ci "version, unable to load driver\n", 42218c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME); 42228c2ecf20Sopenharmony_ci return -EINVAL; 42238c2ecf20Sopenharmony_ci } 42248c2ecf20Sopenharmony_ci 42258c2ecf20Sopenharmony_ci /* Firmware 1.4.4 and older cannot be upgraded, and is too ancient to 42268c2ecf20Sopenharmony_ci * work with this driver. 42278c2ecf20Sopenharmony_ci */ 42288c2ecf20Sopenharmony_ci if (VXGE_FW_VER(maj, min, bld) <= VXGE_FW_DEAD_VER) { 42298c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, "%s: Firmware %d.%d.%d cannot be " 42308c2ecf20Sopenharmony_ci "upgraded\n", VXGE_DRIVER_NAME, maj, min, bld); 42318c2ecf20Sopenharmony_ci return -EINVAL; 42328c2ecf20Sopenharmony_ci } 42338c2ecf20Sopenharmony_ci 42348c2ecf20Sopenharmony_ci /* If file not specified, determine gPXE or not */ 42358c2ecf20Sopenharmony_ci if (VXGE_FW_VER(maj, min, bld) >= VXGE_EPROM_FW_VER) { 42368c2ecf20Sopenharmony_ci int i; 42378c2ecf20Sopenharmony_ci for (i = 0; i < VXGE_HW_MAX_ROM_IMAGES; i++) 42388c2ecf20Sopenharmony_ci if (vdev->devh->eprom_versions[i]) { 42398c2ecf20Sopenharmony_ci gpxe = 1; 42408c2ecf20Sopenharmony_ci break; 42418c2ecf20Sopenharmony_ci } 42428c2ecf20Sopenharmony_ci } 42438c2ecf20Sopenharmony_ci if (gpxe) 42448c2ecf20Sopenharmony_ci fw_name = "vxge/X3fw-pxe.ncf"; 42458c2ecf20Sopenharmony_ci else 42468c2ecf20Sopenharmony_ci fw_name = "vxge/X3fw.ncf"; 42478c2ecf20Sopenharmony_ci 42488c2ecf20Sopenharmony_ci ret = vxge_fw_upgrade(vdev, fw_name, 0); 42498c2ecf20Sopenharmony_ci /* -EINVAL and -ENOENT are not fatal errors for flashing firmware on 42508c2ecf20Sopenharmony_ci * probe, so ignore them 42518c2ecf20Sopenharmony_ci */ 42528c2ecf20Sopenharmony_ci if (ret != -EINVAL && ret != -ENOENT) 42538c2ecf20Sopenharmony_ci return -EIO; 42548c2ecf20Sopenharmony_ci else 42558c2ecf20Sopenharmony_ci ret = 0; 42568c2ecf20Sopenharmony_ci 42578c2ecf20Sopenharmony_ci if (VXGE_FW_VER(VXGE_CERT_FW_VER_MAJOR, VXGE_CERT_FW_VER_MINOR, 0) > 42588c2ecf20Sopenharmony_ci VXGE_FW_VER(maj, min, 0)) { 42598c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, "%s: Firmware %d.%d.%d is too old to" 42608c2ecf20Sopenharmony_ci " be used with this driver.", 42618c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME, maj, min, bld); 42628c2ecf20Sopenharmony_ci return -EINVAL; 42638c2ecf20Sopenharmony_ci } 42648c2ecf20Sopenharmony_ci 42658c2ecf20Sopenharmony_ci return ret; 42668c2ecf20Sopenharmony_ci} 42678c2ecf20Sopenharmony_ci 42688c2ecf20Sopenharmony_cistatic int is_sriov_initialized(struct pci_dev *pdev) 42698c2ecf20Sopenharmony_ci{ 42708c2ecf20Sopenharmony_ci int pos; 42718c2ecf20Sopenharmony_ci u16 ctrl; 42728c2ecf20Sopenharmony_ci 42738c2ecf20Sopenharmony_ci pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); 42748c2ecf20Sopenharmony_ci if (pos) { 42758c2ecf20Sopenharmony_ci pci_read_config_word(pdev, pos + PCI_SRIOV_CTRL, &ctrl); 42768c2ecf20Sopenharmony_ci if (ctrl & PCI_SRIOV_CTRL_VFE) 42778c2ecf20Sopenharmony_ci return 1; 42788c2ecf20Sopenharmony_ci } 42798c2ecf20Sopenharmony_ci return 0; 42808c2ecf20Sopenharmony_ci} 42818c2ecf20Sopenharmony_ci 42828c2ecf20Sopenharmony_cistatic const struct vxge_hw_uld_cbs vxge_callbacks = { 42838c2ecf20Sopenharmony_ci .link_up = vxge_callback_link_up, 42848c2ecf20Sopenharmony_ci .link_down = vxge_callback_link_down, 42858c2ecf20Sopenharmony_ci .crit_err = vxge_callback_crit_err, 42868c2ecf20Sopenharmony_ci}; 42878c2ecf20Sopenharmony_ci 42888c2ecf20Sopenharmony_ci/** 42898c2ecf20Sopenharmony_ci * vxge_probe 42908c2ecf20Sopenharmony_ci * @pdev : structure containing the PCI related information of the device. 42918c2ecf20Sopenharmony_ci * @pre: List of PCI devices supported by the driver listed in vxge_id_table. 42928c2ecf20Sopenharmony_ci * Description: 42938c2ecf20Sopenharmony_ci * This function is called when a new PCI device gets detected and initializes 42948c2ecf20Sopenharmony_ci * it. 42958c2ecf20Sopenharmony_ci * Return value: 42968c2ecf20Sopenharmony_ci * returns 0 on success and negative on failure. 42978c2ecf20Sopenharmony_ci * 42988c2ecf20Sopenharmony_ci */ 42998c2ecf20Sopenharmony_cistatic int 43008c2ecf20Sopenharmony_civxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) 43018c2ecf20Sopenharmony_ci{ 43028c2ecf20Sopenharmony_ci struct __vxge_hw_device *hldev; 43038c2ecf20Sopenharmony_ci enum vxge_hw_status status; 43048c2ecf20Sopenharmony_ci int ret; 43058c2ecf20Sopenharmony_ci int high_dma = 0; 43068c2ecf20Sopenharmony_ci u64 vpath_mask = 0; 43078c2ecf20Sopenharmony_ci struct vxgedev *vdev; 43088c2ecf20Sopenharmony_ci struct vxge_config *ll_config = NULL; 43098c2ecf20Sopenharmony_ci struct vxge_hw_device_config *device_config = NULL; 43108c2ecf20Sopenharmony_ci struct vxge_hw_device_attr attr; 43118c2ecf20Sopenharmony_ci int i, j, no_of_vpath = 0, max_vpath_supported = 0; 43128c2ecf20Sopenharmony_ci u8 *macaddr; 43138c2ecf20Sopenharmony_ci struct vxge_mac_addrs *entry; 43148c2ecf20Sopenharmony_ci static int bus = -1, device = -1; 43158c2ecf20Sopenharmony_ci u32 host_type; 43168c2ecf20Sopenharmony_ci u8 new_device = 0; 43178c2ecf20Sopenharmony_ci enum vxge_hw_status is_privileged; 43188c2ecf20Sopenharmony_ci u32 function_mode; 43198c2ecf20Sopenharmony_ci u32 num_vfs = 0; 43208c2ecf20Sopenharmony_ci 43218c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__); 43228c2ecf20Sopenharmony_ci attr.pdev = pdev; 43238c2ecf20Sopenharmony_ci 43248c2ecf20Sopenharmony_ci /* In SRIOV-17 mode, functions of the same adapter 43258c2ecf20Sopenharmony_ci * can be deployed on different buses 43268c2ecf20Sopenharmony_ci */ 43278c2ecf20Sopenharmony_ci if (((bus != pdev->bus->number) || (device != PCI_SLOT(pdev->devfn))) && 43288c2ecf20Sopenharmony_ci !pdev->is_virtfn) 43298c2ecf20Sopenharmony_ci new_device = 1; 43308c2ecf20Sopenharmony_ci 43318c2ecf20Sopenharmony_ci bus = pdev->bus->number; 43328c2ecf20Sopenharmony_ci device = PCI_SLOT(pdev->devfn); 43338c2ecf20Sopenharmony_ci 43348c2ecf20Sopenharmony_ci if (new_device) { 43358c2ecf20Sopenharmony_ci if (driver_config->config_dev_cnt && 43368c2ecf20Sopenharmony_ci (driver_config->config_dev_cnt != 43378c2ecf20Sopenharmony_ci driver_config->total_dev_cnt)) 43388c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 43398c2ecf20Sopenharmony_ci "%s: Configured %d of %d devices", 43408c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME, 43418c2ecf20Sopenharmony_ci driver_config->config_dev_cnt, 43428c2ecf20Sopenharmony_ci driver_config->total_dev_cnt); 43438c2ecf20Sopenharmony_ci driver_config->config_dev_cnt = 0; 43448c2ecf20Sopenharmony_ci driver_config->total_dev_cnt = 0; 43458c2ecf20Sopenharmony_ci } 43468c2ecf20Sopenharmony_ci 43478c2ecf20Sopenharmony_ci /* Now making the CPU based no of vpath calculation 43488c2ecf20Sopenharmony_ci * applicable for individual functions as well. 43498c2ecf20Sopenharmony_ci */ 43508c2ecf20Sopenharmony_ci driver_config->g_no_cpus = 0; 43518c2ecf20Sopenharmony_ci driver_config->vpath_per_dev = max_config_vpath; 43528c2ecf20Sopenharmony_ci 43538c2ecf20Sopenharmony_ci driver_config->total_dev_cnt++; 43548c2ecf20Sopenharmony_ci if (++driver_config->config_dev_cnt > max_config_dev) { 43558c2ecf20Sopenharmony_ci ret = 0; 43568c2ecf20Sopenharmony_ci goto _exit0; 43578c2ecf20Sopenharmony_ci } 43588c2ecf20Sopenharmony_ci 43598c2ecf20Sopenharmony_ci device_config = kzalloc(sizeof(struct vxge_hw_device_config), 43608c2ecf20Sopenharmony_ci GFP_KERNEL); 43618c2ecf20Sopenharmony_ci if (!device_config) { 43628c2ecf20Sopenharmony_ci ret = -ENOMEM; 43638c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 43648c2ecf20Sopenharmony_ci "device_config : malloc failed %s %d", 43658c2ecf20Sopenharmony_ci __FILE__, __LINE__); 43668c2ecf20Sopenharmony_ci goto _exit0; 43678c2ecf20Sopenharmony_ci } 43688c2ecf20Sopenharmony_ci 43698c2ecf20Sopenharmony_ci ll_config = kzalloc(sizeof(struct vxge_config), GFP_KERNEL); 43708c2ecf20Sopenharmony_ci if (!ll_config) { 43718c2ecf20Sopenharmony_ci ret = -ENOMEM; 43728c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 43738c2ecf20Sopenharmony_ci "device_config : malloc failed %s %d", 43748c2ecf20Sopenharmony_ci __FILE__, __LINE__); 43758c2ecf20Sopenharmony_ci goto _exit0; 43768c2ecf20Sopenharmony_ci } 43778c2ecf20Sopenharmony_ci ll_config->tx_steering_type = TX_MULTIQ_STEERING; 43788c2ecf20Sopenharmony_ci ll_config->intr_type = MSI_X; 43798c2ecf20Sopenharmony_ci ll_config->napi_weight = NEW_NAPI_WEIGHT; 43808c2ecf20Sopenharmony_ci ll_config->rth_steering = RTH_STEERING; 43818c2ecf20Sopenharmony_ci 43828c2ecf20Sopenharmony_ci /* get the default configuration parameters */ 43838c2ecf20Sopenharmony_ci vxge_hw_device_config_default_get(device_config); 43848c2ecf20Sopenharmony_ci 43858c2ecf20Sopenharmony_ci /* initialize configuration parameters */ 43868c2ecf20Sopenharmony_ci vxge_device_config_init(device_config, &ll_config->intr_type); 43878c2ecf20Sopenharmony_ci 43888c2ecf20Sopenharmony_ci ret = pci_enable_device(pdev); 43898c2ecf20Sopenharmony_ci if (ret) { 43908c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 43918c2ecf20Sopenharmony_ci "%s : can not enable PCI device", __func__); 43928c2ecf20Sopenharmony_ci goto _exit0; 43938c2ecf20Sopenharmony_ci } 43948c2ecf20Sopenharmony_ci 43958c2ecf20Sopenharmony_ci if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) { 43968c2ecf20Sopenharmony_ci vxge_debug_ll_config(VXGE_TRACE, 43978c2ecf20Sopenharmony_ci "%s : using 64bit DMA", __func__); 43988c2ecf20Sopenharmony_ci 43998c2ecf20Sopenharmony_ci high_dma = 1; 44008c2ecf20Sopenharmony_ci 44018c2ecf20Sopenharmony_ci if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) { 44028c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 44038c2ecf20Sopenharmony_ci "%s : unable to obtain 64bit DMA for " 44048c2ecf20Sopenharmony_ci "consistent allocations", __func__); 44058c2ecf20Sopenharmony_ci ret = -ENOMEM; 44068c2ecf20Sopenharmony_ci goto _exit1; 44078c2ecf20Sopenharmony_ci } 44088c2ecf20Sopenharmony_ci } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { 44098c2ecf20Sopenharmony_ci vxge_debug_ll_config(VXGE_TRACE, 44108c2ecf20Sopenharmony_ci "%s : using 32bit DMA", __func__); 44118c2ecf20Sopenharmony_ci } else { 44128c2ecf20Sopenharmony_ci ret = -ENOMEM; 44138c2ecf20Sopenharmony_ci goto _exit1; 44148c2ecf20Sopenharmony_ci } 44158c2ecf20Sopenharmony_ci 44168c2ecf20Sopenharmony_ci ret = pci_request_region(pdev, 0, VXGE_DRIVER_NAME); 44178c2ecf20Sopenharmony_ci if (ret) { 44188c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 44198c2ecf20Sopenharmony_ci "%s : request regions failed", __func__); 44208c2ecf20Sopenharmony_ci goto _exit1; 44218c2ecf20Sopenharmony_ci } 44228c2ecf20Sopenharmony_ci 44238c2ecf20Sopenharmony_ci pci_set_master(pdev); 44248c2ecf20Sopenharmony_ci 44258c2ecf20Sopenharmony_ci attr.bar0 = pci_ioremap_bar(pdev, 0); 44268c2ecf20Sopenharmony_ci if (!attr.bar0) { 44278c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 44288c2ecf20Sopenharmony_ci "%s : cannot remap io memory bar0", __func__); 44298c2ecf20Sopenharmony_ci ret = -ENODEV; 44308c2ecf20Sopenharmony_ci goto _exit2; 44318c2ecf20Sopenharmony_ci } 44328c2ecf20Sopenharmony_ci vxge_debug_ll_config(VXGE_TRACE, 44338c2ecf20Sopenharmony_ci "pci ioremap bar0: %p:0x%llx", 44348c2ecf20Sopenharmony_ci attr.bar0, 44358c2ecf20Sopenharmony_ci (unsigned long long)pci_resource_start(pdev, 0)); 44368c2ecf20Sopenharmony_ci 44378c2ecf20Sopenharmony_ci status = vxge_hw_device_hw_info_get(attr.bar0, 44388c2ecf20Sopenharmony_ci &ll_config->device_hw_info); 44398c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 44408c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 44418c2ecf20Sopenharmony_ci "%s: Reading of hardware info failed." 44428c2ecf20Sopenharmony_ci "Please try upgrading the firmware.", VXGE_DRIVER_NAME); 44438c2ecf20Sopenharmony_ci ret = -EINVAL; 44448c2ecf20Sopenharmony_ci goto _exit3; 44458c2ecf20Sopenharmony_ci } 44468c2ecf20Sopenharmony_ci 44478c2ecf20Sopenharmony_ci vpath_mask = ll_config->device_hw_info.vpath_mask; 44488c2ecf20Sopenharmony_ci if (vpath_mask == 0) { 44498c2ecf20Sopenharmony_ci vxge_debug_ll_config(VXGE_TRACE, 44508c2ecf20Sopenharmony_ci "%s: No vpaths available in device", VXGE_DRIVER_NAME); 44518c2ecf20Sopenharmony_ci ret = -EINVAL; 44528c2ecf20Sopenharmony_ci goto _exit3; 44538c2ecf20Sopenharmony_ci } 44548c2ecf20Sopenharmony_ci 44558c2ecf20Sopenharmony_ci vxge_debug_ll_config(VXGE_TRACE, 44568c2ecf20Sopenharmony_ci "%s:%d Vpath mask = %llx", __func__, __LINE__, 44578c2ecf20Sopenharmony_ci (unsigned long long)vpath_mask); 44588c2ecf20Sopenharmony_ci 44598c2ecf20Sopenharmony_ci function_mode = ll_config->device_hw_info.function_mode; 44608c2ecf20Sopenharmony_ci host_type = ll_config->device_hw_info.host_type; 44618c2ecf20Sopenharmony_ci is_privileged = __vxge_hw_device_is_privilaged(host_type, 44628c2ecf20Sopenharmony_ci ll_config->device_hw_info.func_id); 44638c2ecf20Sopenharmony_ci 44648c2ecf20Sopenharmony_ci /* Check how many vpaths are available */ 44658c2ecf20Sopenharmony_ci for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { 44668c2ecf20Sopenharmony_ci if (!((vpath_mask) & vxge_mBIT(i))) 44678c2ecf20Sopenharmony_ci continue; 44688c2ecf20Sopenharmony_ci max_vpath_supported++; 44698c2ecf20Sopenharmony_ci } 44708c2ecf20Sopenharmony_ci 44718c2ecf20Sopenharmony_ci if (new_device) 44728c2ecf20Sopenharmony_ci num_vfs = vxge_get_num_vfs(function_mode) - 1; 44738c2ecf20Sopenharmony_ci 44748c2ecf20Sopenharmony_ci /* Enable SRIOV mode, if firmware has SRIOV support and if it is a PF */ 44758c2ecf20Sopenharmony_ci if (is_sriov(function_mode) && !is_sriov_initialized(pdev) && 44768c2ecf20Sopenharmony_ci (ll_config->intr_type != INTA)) { 44778c2ecf20Sopenharmony_ci ret = pci_enable_sriov(pdev, num_vfs); 44788c2ecf20Sopenharmony_ci if (ret) 44798c2ecf20Sopenharmony_ci vxge_debug_ll_config(VXGE_ERR, 44808c2ecf20Sopenharmony_ci "Failed in enabling SRIOV mode: %d\n", ret); 44818c2ecf20Sopenharmony_ci /* No need to fail out, as an error here is non-fatal */ 44828c2ecf20Sopenharmony_ci } 44838c2ecf20Sopenharmony_ci 44848c2ecf20Sopenharmony_ci /* 44858c2ecf20Sopenharmony_ci * Configure vpaths and get driver configured number of vpaths 44868c2ecf20Sopenharmony_ci * which is less than or equal to the maximum vpaths per function. 44878c2ecf20Sopenharmony_ci */ 44888c2ecf20Sopenharmony_ci no_of_vpath = vxge_config_vpaths(device_config, vpath_mask, ll_config); 44898c2ecf20Sopenharmony_ci if (!no_of_vpath) { 44908c2ecf20Sopenharmony_ci vxge_debug_ll_config(VXGE_ERR, 44918c2ecf20Sopenharmony_ci "%s: No more vpaths to configure", VXGE_DRIVER_NAME); 44928c2ecf20Sopenharmony_ci ret = 0; 44938c2ecf20Sopenharmony_ci goto _exit3; 44948c2ecf20Sopenharmony_ci } 44958c2ecf20Sopenharmony_ci 44968c2ecf20Sopenharmony_ci /* Setting driver callbacks */ 44978c2ecf20Sopenharmony_ci attr.uld_callbacks = &vxge_callbacks; 44988c2ecf20Sopenharmony_ci 44998c2ecf20Sopenharmony_ci status = vxge_hw_device_initialize(&hldev, &attr, device_config); 45008c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 45018c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 45028c2ecf20Sopenharmony_ci "Failed to initialize device (%d)", status); 45038c2ecf20Sopenharmony_ci ret = -EINVAL; 45048c2ecf20Sopenharmony_ci goto _exit3; 45058c2ecf20Sopenharmony_ci } 45068c2ecf20Sopenharmony_ci 45078c2ecf20Sopenharmony_ci if (VXGE_FW_VER(ll_config->device_hw_info.fw_version.major, 45088c2ecf20Sopenharmony_ci ll_config->device_hw_info.fw_version.minor, 45098c2ecf20Sopenharmony_ci ll_config->device_hw_info.fw_version.build) >= 45108c2ecf20Sopenharmony_ci VXGE_EPROM_FW_VER) { 45118c2ecf20Sopenharmony_ci struct eprom_image img[VXGE_HW_MAX_ROM_IMAGES]; 45128c2ecf20Sopenharmony_ci 45138c2ecf20Sopenharmony_ci status = vxge_hw_vpath_eprom_img_ver_get(hldev, img); 45148c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 45158c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, "%s: Reading of EPROM failed", 45168c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME); 45178c2ecf20Sopenharmony_ci /* This is a non-fatal error, continue */ 45188c2ecf20Sopenharmony_ci } 45198c2ecf20Sopenharmony_ci 45208c2ecf20Sopenharmony_ci for (i = 0; i < VXGE_HW_MAX_ROM_IMAGES; i++) { 45218c2ecf20Sopenharmony_ci hldev->eprom_versions[i] = img[i].version; 45228c2ecf20Sopenharmony_ci if (!img[i].is_valid) 45238c2ecf20Sopenharmony_ci break; 45248c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, "%s: EPROM %d, version " 45258c2ecf20Sopenharmony_ci "%d.%d.%d.%d", VXGE_DRIVER_NAME, i, 45268c2ecf20Sopenharmony_ci VXGE_EPROM_IMG_MAJOR(img[i].version), 45278c2ecf20Sopenharmony_ci VXGE_EPROM_IMG_MINOR(img[i].version), 45288c2ecf20Sopenharmony_ci VXGE_EPROM_IMG_FIX(img[i].version), 45298c2ecf20Sopenharmony_ci VXGE_EPROM_IMG_BUILD(img[i].version)); 45308c2ecf20Sopenharmony_ci } 45318c2ecf20Sopenharmony_ci } 45328c2ecf20Sopenharmony_ci 45338c2ecf20Sopenharmony_ci /* if FCS stripping is not disabled in MAC fail driver load */ 45348c2ecf20Sopenharmony_ci status = vxge_hw_vpath_strip_fcs_check(hldev, vpath_mask); 45358c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 45368c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, "%s: FCS stripping is enabled in MAC" 45378c2ecf20Sopenharmony_ci " failing driver load", VXGE_DRIVER_NAME); 45388c2ecf20Sopenharmony_ci ret = -EINVAL; 45398c2ecf20Sopenharmony_ci goto _exit4; 45408c2ecf20Sopenharmony_ci } 45418c2ecf20Sopenharmony_ci 45428c2ecf20Sopenharmony_ci /* Always enable HWTS. This will always cause the FCS to be invalid, 45438c2ecf20Sopenharmony_ci * due to the fact that HWTS is using the FCS as the location of the 45448c2ecf20Sopenharmony_ci * timestamp. The HW FCS checking will still correctly determine if 45458c2ecf20Sopenharmony_ci * there is a valid checksum, and the FCS is being removed by the driver 45468c2ecf20Sopenharmony_ci * anyway. So no functionality is being lost. Since it is always 45478c2ecf20Sopenharmony_ci * enabled, we now simply use the ioctl call to set whether or not the 45488c2ecf20Sopenharmony_ci * driver should be paying attention to the HWTS. 45498c2ecf20Sopenharmony_ci */ 45508c2ecf20Sopenharmony_ci if (is_privileged == VXGE_HW_OK) { 45518c2ecf20Sopenharmony_ci status = vxge_timestamp_config(hldev); 45528c2ecf20Sopenharmony_ci if (status != VXGE_HW_OK) { 45538c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, "%s: HWTS enable failed", 45548c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME); 45558c2ecf20Sopenharmony_ci ret = -EFAULT; 45568c2ecf20Sopenharmony_ci goto _exit4; 45578c2ecf20Sopenharmony_ci } 45588c2ecf20Sopenharmony_ci } 45598c2ecf20Sopenharmony_ci 45608c2ecf20Sopenharmony_ci vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL); 45618c2ecf20Sopenharmony_ci 45628c2ecf20Sopenharmony_ci /* set private device info */ 45638c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, hldev); 45648c2ecf20Sopenharmony_ci 45658c2ecf20Sopenharmony_ci ll_config->fifo_indicate_max_pkts = VXGE_FIFO_INDICATE_MAX_PKTS; 45668c2ecf20Sopenharmony_ci ll_config->addr_learn_en = addr_learn_en; 45678c2ecf20Sopenharmony_ci ll_config->rth_algorithm = RTH_ALG_JENKINS; 45688c2ecf20Sopenharmony_ci ll_config->rth_hash_type_tcpipv4 = 1; 45698c2ecf20Sopenharmony_ci ll_config->rth_hash_type_ipv4 = 0; 45708c2ecf20Sopenharmony_ci ll_config->rth_hash_type_tcpipv6 = 0; 45718c2ecf20Sopenharmony_ci ll_config->rth_hash_type_ipv6 = 0; 45728c2ecf20Sopenharmony_ci ll_config->rth_hash_type_tcpipv6ex = 0; 45738c2ecf20Sopenharmony_ci ll_config->rth_hash_type_ipv6ex = 0; 45748c2ecf20Sopenharmony_ci ll_config->rth_bkt_sz = RTH_BUCKET_SIZE; 45758c2ecf20Sopenharmony_ci ll_config->tx_pause_enable = VXGE_PAUSE_CTRL_ENABLE; 45768c2ecf20Sopenharmony_ci ll_config->rx_pause_enable = VXGE_PAUSE_CTRL_ENABLE; 45778c2ecf20Sopenharmony_ci 45788c2ecf20Sopenharmony_ci ret = vxge_device_register(hldev, ll_config, high_dma, no_of_vpath, 45798c2ecf20Sopenharmony_ci &vdev); 45808c2ecf20Sopenharmony_ci if (ret) { 45818c2ecf20Sopenharmony_ci ret = -EINVAL; 45828c2ecf20Sopenharmony_ci goto _exit4; 45838c2ecf20Sopenharmony_ci } 45848c2ecf20Sopenharmony_ci 45858c2ecf20Sopenharmony_ci ret = vxge_probe_fw_update(vdev); 45868c2ecf20Sopenharmony_ci if (ret) 45878c2ecf20Sopenharmony_ci goto _exit5; 45888c2ecf20Sopenharmony_ci 45898c2ecf20Sopenharmony_ci vxge_hw_device_debug_set(hldev, VXGE_TRACE, VXGE_COMPONENT_LL); 45908c2ecf20Sopenharmony_ci VXGE_COPY_DEBUG_INFO_TO_LL(vdev, vxge_hw_device_error_level_get(hldev), 45918c2ecf20Sopenharmony_ci vxge_hw_device_trace_level_get(hldev)); 45928c2ecf20Sopenharmony_ci 45938c2ecf20Sopenharmony_ci /* set private HW device info */ 45948c2ecf20Sopenharmony_ci vdev->mtu = VXGE_HW_DEFAULT_MTU; 45958c2ecf20Sopenharmony_ci vdev->bar0 = attr.bar0; 45968c2ecf20Sopenharmony_ci vdev->max_vpath_supported = max_vpath_supported; 45978c2ecf20Sopenharmony_ci vdev->no_of_vpath = no_of_vpath; 45988c2ecf20Sopenharmony_ci 45998c2ecf20Sopenharmony_ci /* Virtual Path count */ 46008c2ecf20Sopenharmony_ci for (i = 0, j = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { 46018c2ecf20Sopenharmony_ci if (!vxge_bVALn(vpath_mask, i, 1)) 46028c2ecf20Sopenharmony_ci continue; 46038c2ecf20Sopenharmony_ci if (j >= vdev->no_of_vpath) 46048c2ecf20Sopenharmony_ci break; 46058c2ecf20Sopenharmony_ci 46068c2ecf20Sopenharmony_ci vdev->vpaths[j].is_configured = 1; 46078c2ecf20Sopenharmony_ci vdev->vpaths[j].device_id = i; 46088c2ecf20Sopenharmony_ci vdev->vpaths[j].ring.driver_id = j; 46098c2ecf20Sopenharmony_ci vdev->vpaths[j].vdev = vdev; 46108c2ecf20Sopenharmony_ci vdev->vpaths[j].max_mac_addr_cnt = max_mac_vpath; 46118c2ecf20Sopenharmony_ci memcpy((u8 *)vdev->vpaths[j].macaddr, 46128c2ecf20Sopenharmony_ci ll_config->device_hw_info.mac_addrs[i], 46138c2ecf20Sopenharmony_ci ETH_ALEN); 46148c2ecf20Sopenharmony_ci 46158c2ecf20Sopenharmony_ci /* Initialize the mac address list header */ 46168c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vdev->vpaths[j].mac_addr_list); 46178c2ecf20Sopenharmony_ci 46188c2ecf20Sopenharmony_ci vdev->vpaths[j].mac_addr_cnt = 0; 46198c2ecf20Sopenharmony_ci vdev->vpaths[j].mcast_addr_cnt = 0; 46208c2ecf20Sopenharmony_ci j++; 46218c2ecf20Sopenharmony_ci } 46228c2ecf20Sopenharmony_ci vdev->exec_mode = VXGE_EXEC_MODE_DISABLE; 46238c2ecf20Sopenharmony_ci vdev->max_config_port = max_config_port; 46248c2ecf20Sopenharmony_ci 46258c2ecf20Sopenharmony_ci vdev->vlan_tag_strip = vlan_tag_strip; 46268c2ecf20Sopenharmony_ci 46278c2ecf20Sopenharmony_ci /* map the hashing selector table to the configured vpaths */ 46288c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) 46298c2ecf20Sopenharmony_ci vdev->vpath_selector[i] = vpath_selector[i]; 46308c2ecf20Sopenharmony_ci 46318c2ecf20Sopenharmony_ci macaddr = (u8 *)vdev->vpaths[0].macaddr; 46328c2ecf20Sopenharmony_ci 46338c2ecf20Sopenharmony_ci ll_config->device_hw_info.serial_number[VXGE_HW_INFO_LEN - 1] = '\0'; 46348c2ecf20Sopenharmony_ci ll_config->device_hw_info.product_desc[VXGE_HW_INFO_LEN - 1] = '\0'; 46358c2ecf20Sopenharmony_ci ll_config->device_hw_info.part_number[VXGE_HW_INFO_LEN - 1] = '\0'; 46368c2ecf20Sopenharmony_ci 46378c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, "%s: SERIAL NUMBER: %s", 46388c2ecf20Sopenharmony_ci vdev->ndev->name, ll_config->device_hw_info.serial_number); 46398c2ecf20Sopenharmony_ci 46408c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, "%s: PART NUMBER: %s", 46418c2ecf20Sopenharmony_ci vdev->ndev->name, ll_config->device_hw_info.part_number); 46428c2ecf20Sopenharmony_ci 46438c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, "%s: Neterion %s Server Adapter", 46448c2ecf20Sopenharmony_ci vdev->ndev->name, ll_config->device_hw_info.product_desc); 46458c2ecf20Sopenharmony_ci 46468c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, "%s: MAC ADDR: %pM", 46478c2ecf20Sopenharmony_ci vdev->ndev->name, macaddr); 46488c2ecf20Sopenharmony_ci 46498c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, "%s: Link Width x%d", 46508c2ecf20Sopenharmony_ci vdev->ndev->name, vxge_hw_device_link_width_get(hldev)); 46518c2ecf20Sopenharmony_ci 46528c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 46538c2ecf20Sopenharmony_ci "%s: Firmware version : %s Date : %s", vdev->ndev->name, 46548c2ecf20Sopenharmony_ci ll_config->device_hw_info.fw_version.version, 46558c2ecf20Sopenharmony_ci ll_config->device_hw_info.fw_date.date); 46568c2ecf20Sopenharmony_ci 46578c2ecf20Sopenharmony_ci if (new_device) { 46588c2ecf20Sopenharmony_ci switch (ll_config->device_hw_info.function_mode) { 46598c2ecf20Sopenharmony_ci case VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION: 46608c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 46618c2ecf20Sopenharmony_ci "%s: Single Function Mode Enabled", vdev->ndev->name); 46628c2ecf20Sopenharmony_ci break; 46638c2ecf20Sopenharmony_ci case VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION: 46648c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 46658c2ecf20Sopenharmony_ci "%s: Multi Function Mode Enabled", vdev->ndev->name); 46668c2ecf20Sopenharmony_ci break; 46678c2ecf20Sopenharmony_ci case VXGE_HW_FUNCTION_MODE_SRIOV: 46688c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 46698c2ecf20Sopenharmony_ci "%s: Single Root IOV Mode Enabled", vdev->ndev->name); 46708c2ecf20Sopenharmony_ci break; 46718c2ecf20Sopenharmony_ci case VXGE_HW_FUNCTION_MODE_MRIOV: 46728c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_TRACE, 46738c2ecf20Sopenharmony_ci "%s: Multi Root IOV Mode Enabled", vdev->ndev->name); 46748c2ecf20Sopenharmony_ci break; 46758c2ecf20Sopenharmony_ci } 46768c2ecf20Sopenharmony_ci } 46778c2ecf20Sopenharmony_ci 46788c2ecf20Sopenharmony_ci vxge_print_parm(vdev, vpath_mask); 46798c2ecf20Sopenharmony_ci 46808c2ecf20Sopenharmony_ci /* Store the fw version for ethttool option */ 46818c2ecf20Sopenharmony_ci strcpy(vdev->fw_version, ll_config->device_hw_info.fw_version.version); 46828c2ecf20Sopenharmony_ci memcpy(vdev->ndev->dev_addr, (u8 *)vdev->vpaths[0].macaddr, ETH_ALEN); 46838c2ecf20Sopenharmony_ci 46848c2ecf20Sopenharmony_ci /* Copy the station mac address to the list */ 46858c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) { 46868c2ecf20Sopenharmony_ci entry = kzalloc(sizeof(struct vxge_mac_addrs), GFP_KERNEL); 46878c2ecf20Sopenharmony_ci if (NULL == entry) { 46888c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 46898c2ecf20Sopenharmony_ci "%s: mac_addr_list : memory allocation failed", 46908c2ecf20Sopenharmony_ci vdev->ndev->name); 46918c2ecf20Sopenharmony_ci ret = -EPERM; 46928c2ecf20Sopenharmony_ci goto _exit6; 46938c2ecf20Sopenharmony_ci } 46948c2ecf20Sopenharmony_ci macaddr = (u8 *)&entry->macaddr; 46958c2ecf20Sopenharmony_ci memcpy(macaddr, vdev->ndev->dev_addr, ETH_ALEN); 46968c2ecf20Sopenharmony_ci list_add(&entry->item, &vdev->vpaths[i].mac_addr_list); 46978c2ecf20Sopenharmony_ci vdev->vpaths[i].mac_addr_cnt = 1; 46988c2ecf20Sopenharmony_ci } 46998c2ecf20Sopenharmony_ci 47008c2ecf20Sopenharmony_ci kfree(device_config); 47018c2ecf20Sopenharmony_ci 47028c2ecf20Sopenharmony_ci /* 47038c2ecf20Sopenharmony_ci * INTA is shared in multi-function mode. This is unlike the INTA 47048c2ecf20Sopenharmony_ci * implementation in MR mode, where each VH has its own INTA message. 47058c2ecf20Sopenharmony_ci * - INTA is masked (disabled) as long as at least one function sets 47068c2ecf20Sopenharmony_ci * its TITAN_MASK_ALL_INT.ALARM bit. 47078c2ecf20Sopenharmony_ci * - INTA is unmasked (enabled) when all enabled functions have cleared 47088c2ecf20Sopenharmony_ci * their own TITAN_MASK_ALL_INT.ALARM bit. 47098c2ecf20Sopenharmony_ci * The TITAN_MASK_ALL_INT ALARM & TRAFFIC bits are cleared on power up. 47108c2ecf20Sopenharmony_ci * Though this driver leaves the top level interrupts unmasked while 47118c2ecf20Sopenharmony_ci * leaving the required module interrupt bits masked on exit, there 47128c2ecf20Sopenharmony_ci * could be a rougue driver around that does not follow this procedure 47138c2ecf20Sopenharmony_ci * resulting in a failure to generate interrupts. The following code is 47148c2ecf20Sopenharmony_ci * present to prevent such a failure. 47158c2ecf20Sopenharmony_ci */ 47168c2ecf20Sopenharmony_ci 47178c2ecf20Sopenharmony_ci if (ll_config->device_hw_info.function_mode == 47188c2ecf20Sopenharmony_ci VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION) 47198c2ecf20Sopenharmony_ci if (vdev->config.intr_type == INTA) 47208c2ecf20Sopenharmony_ci vxge_hw_device_unmask_all(hldev); 47218c2ecf20Sopenharmony_ci 47228c2ecf20Sopenharmony_ci vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", 47238c2ecf20Sopenharmony_ci vdev->ndev->name, __func__, __LINE__); 47248c2ecf20Sopenharmony_ci 47258c2ecf20Sopenharmony_ci vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL); 47268c2ecf20Sopenharmony_ci VXGE_COPY_DEBUG_INFO_TO_LL(vdev, vxge_hw_device_error_level_get(hldev), 47278c2ecf20Sopenharmony_ci vxge_hw_device_trace_level_get(hldev)); 47288c2ecf20Sopenharmony_ci 47298c2ecf20Sopenharmony_ci kfree(ll_config); 47308c2ecf20Sopenharmony_ci return 0; 47318c2ecf20Sopenharmony_ci 47328c2ecf20Sopenharmony_ci_exit6: 47338c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) 47348c2ecf20Sopenharmony_ci vxge_free_mac_add_list(&vdev->vpaths[i]); 47358c2ecf20Sopenharmony_ci_exit5: 47368c2ecf20Sopenharmony_ci vxge_device_unregister(hldev); 47378c2ecf20Sopenharmony_ci_exit4: 47388c2ecf20Sopenharmony_ci vxge_hw_device_terminate(hldev); 47398c2ecf20Sopenharmony_ci pci_disable_sriov(pdev); 47408c2ecf20Sopenharmony_ci_exit3: 47418c2ecf20Sopenharmony_ci iounmap(attr.bar0); 47428c2ecf20Sopenharmony_ci_exit2: 47438c2ecf20Sopenharmony_ci pci_release_region(pdev, 0); 47448c2ecf20Sopenharmony_ci_exit1: 47458c2ecf20Sopenharmony_ci pci_disable_device(pdev); 47468c2ecf20Sopenharmony_ci_exit0: 47478c2ecf20Sopenharmony_ci kfree(ll_config); 47488c2ecf20Sopenharmony_ci kfree(device_config); 47498c2ecf20Sopenharmony_ci driver_config->config_dev_cnt--; 47508c2ecf20Sopenharmony_ci driver_config->total_dev_cnt--; 47518c2ecf20Sopenharmony_ci return ret; 47528c2ecf20Sopenharmony_ci} 47538c2ecf20Sopenharmony_ci 47548c2ecf20Sopenharmony_ci/** 47558c2ecf20Sopenharmony_ci * vxge_rem_nic - Free the PCI device 47568c2ecf20Sopenharmony_ci * @pdev: structure containing the PCI related information of the device. 47578c2ecf20Sopenharmony_ci * Description: This function is called by the Pci subsystem to release a 47588c2ecf20Sopenharmony_ci * PCI device and free up all resource held up by the device. 47598c2ecf20Sopenharmony_ci */ 47608c2ecf20Sopenharmony_cistatic void vxge_remove(struct pci_dev *pdev) 47618c2ecf20Sopenharmony_ci{ 47628c2ecf20Sopenharmony_ci struct __vxge_hw_device *hldev; 47638c2ecf20Sopenharmony_ci struct vxgedev *vdev; 47648c2ecf20Sopenharmony_ci int i; 47658c2ecf20Sopenharmony_ci 47668c2ecf20Sopenharmony_ci hldev = pci_get_drvdata(pdev); 47678c2ecf20Sopenharmony_ci if (hldev == NULL) 47688c2ecf20Sopenharmony_ci return; 47698c2ecf20Sopenharmony_ci 47708c2ecf20Sopenharmony_ci vdev = netdev_priv(hldev->ndev); 47718c2ecf20Sopenharmony_ci 47728c2ecf20Sopenharmony_ci vxge_debug_entryexit(vdev->level_trace, "%s:%d", __func__, __LINE__); 47738c2ecf20Sopenharmony_ci vxge_debug_init(vdev->level_trace, "%s : removing PCI device...", 47748c2ecf20Sopenharmony_ci __func__); 47758c2ecf20Sopenharmony_ci 47768c2ecf20Sopenharmony_ci for (i = 0; i < vdev->no_of_vpath; i++) 47778c2ecf20Sopenharmony_ci vxge_free_mac_add_list(&vdev->vpaths[i]); 47788c2ecf20Sopenharmony_ci 47798c2ecf20Sopenharmony_ci vxge_device_unregister(hldev); 47808c2ecf20Sopenharmony_ci /* Do not call pci_disable_sriov here, as it will break child devices */ 47818c2ecf20Sopenharmony_ci vxge_hw_device_terminate(hldev); 47828c2ecf20Sopenharmony_ci iounmap(vdev->bar0); 47838c2ecf20Sopenharmony_ci pci_release_region(pdev, 0); 47848c2ecf20Sopenharmony_ci pci_disable_device(pdev); 47858c2ecf20Sopenharmony_ci driver_config->config_dev_cnt--; 47868c2ecf20Sopenharmony_ci driver_config->total_dev_cnt--; 47878c2ecf20Sopenharmony_ci 47888c2ecf20Sopenharmony_ci vxge_debug_init(vdev->level_trace, "%s:%d Device unregistered", 47898c2ecf20Sopenharmony_ci __func__, __LINE__); 47908c2ecf20Sopenharmony_ci vxge_debug_entryexit(vdev->level_trace, "%s:%d Exiting...", __func__, 47918c2ecf20Sopenharmony_ci __LINE__); 47928c2ecf20Sopenharmony_ci} 47938c2ecf20Sopenharmony_ci 47948c2ecf20Sopenharmony_cistatic const struct pci_error_handlers vxge_err_handler = { 47958c2ecf20Sopenharmony_ci .error_detected = vxge_io_error_detected, 47968c2ecf20Sopenharmony_ci .slot_reset = vxge_io_slot_reset, 47978c2ecf20Sopenharmony_ci .resume = vxge_io_resume, 47988c2ecf20Sopenharmony_ci}; 47998c2ecf20Sopenharmony_ci 48008c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(vxge_pm_ops, vxge_pm_suspend, vxge_pm_resume); 48018c2ecf20Sopenharmony_ci 48028c2ecf20Sopenharmony_cistatic struct pci_driver vxge_driver = { 48038c2ecf20Sopenharmony_ci .name = VXGE_DRIVER_NAME, 48048c2ecf20Sopenharmony_ci .id_table = vxge_id_table, 48058c2ecf20Sopenharmony_ci .probe = vxge_probe, 48068c2ecf20Sopenharmony_ci .remove = vxge_remove, 48078c2ecf20Sopenharmony_ci .driver.pm = &vxge_pm_ops, 48088c2ecf20Sopenharmony_ci .err_handler = &vxge_err_handler, 48098c2ecf20Sopenharmony_ci}; 48108c2ecf20Sopenharmony_ci 48118c2ecf20Sopenharmony_cistatic int __init 48128c2ecf20Sopenharmony_civxge_starter(void) 48138c2ecf20Sopenharmony_ci{ 48148c2ecf20Sopenharmony_ci int ret = 0; 48158c2ecf20Sopenharmony_ci 48168c2ecf20Sopenharmony_ci pr_info("Copyright(c) 2002-2010 Exar Corp.\n"); 48178c2ecf20Sopenharmony_ci pr_info("Driver version: %s\n", DRV_VERSION); 48188c2ecf20Sopenharmony_ci 48198c2ecf20Sopenharmony_ci verify_bandwidth(); 48208c2ecf20Sopenharmony_ci 48218c2ecf20Sopenharmony_ci driver_config = kzalloc(sizeof(struct vxge_drv_config), GFP_KERNEL); 48228c2ecf20Sopenharmony_ci if (!driver_config) 48238c2ecf20Sopenharmony_ci return -ENOMEM; 48248c2ecf20Sopenharmony_ci 48258c2ecf20Sopenharmony_ci ret = pci_register_driver(&vxge_driver); 48268c2ecf20Sopenharmony_ci if (ret) { 48278c2ecf20Sopenharmony_ci kfree(driver_config); 48288c2ecf20Sopenharmony_ci goto err; 48298c2ecf20Sopenharmony_ci } 48308c2ecf20Sopenharmony_ci 48318c2ecf20Sopenharmony_ci if (driver_config->config_dev_cnt && 48328c2ecf20Sopenharmony_ci (driver_config->config_dev_cnt != driver_config->total_dev_cnt)) 48338c2ecf20Sopenharmony_ci vxge_debug_init(VXGE_ERR, 48348c2ecf20Sopenharmony_ci "%s: Configured %d of %d devices", 48358c2ecf20Sopenharmony_ci VXGE_DRIVER_NAME, driver_config->config_dev_cnt, 48368c2ecf20Sopenharmony_ci driver_config->total_dev_cnt); 48378c2ecf20Sopenharmony_cierr: 48388c2ecf20Sopenharmony_ci return ret; 48398c2ecf20Sopenharmony_ci} 48408c2ecf20Sopenharmony_ci 48418c2ecf20Sopenharmony_cistatic void __exit 48428c2ecf20Sopenharmony_civxge_closer(void) 48438c2ecf20Sopenharmony_ci{ 48448c2ecf20Sopenharmony_ci pci_unregister_driver(&vxge_driver); 48458c2ecf20Sopenharmony_ci kfree(driver_config); 48468c2ecf20Sopenharmony_ci} 48478c2ecf20Sopenharmony_cimodule_init(vxge_starter); 48488c2ecf20Sopenharmony_cimodule_exit(vxge_closer); 4849