Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/net/ethernet/intel/ixgbe/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 340 kB image not shown  

Quelle  ixgbe_main.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 1999 - 2024 Intel Corporation. */

#include <linux/types.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/vmalloc.h>
#include <linux/string.h>
#include <linux/in.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/sctp.h>
#include <linux/pkt_sched.h>
#include <linux/ipv6.h>
#include <linux/slab.h>
#include <net/checksum.h>
#include <net/ip6_checksum.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/if.h>
#include <linux/if_vlan.h>
#include <linux/if_macvlan.h>
#include <linux/if_bridge.h>
#include <linux/prefetch.h>
#include <linux/bpf.h>
#include <linux/bpf_trace.h>
#include <linux/atomic.h>
#include <linux/numa.h>
#include <generated/utsrelease.h>
#include <scsi/fc/fc_fcoe.h>
#include <net/udp_tunnel.h>
#include <net/pkt_cls.h>
#include <net/tc_act/tc_gact.h>
#include <net/tc_act/tc_mirred.h>
#include <net/vxlan.h>
#include <net/mpls.h>
#include <net/netdev_queues.h>
#include <net/xdp_sock_drv.h>
#include <net/xfrm.h>

#include "ixgbe.h"
#include "ixgbe_common.h"
#include "ixgbe_e610.h"
#include "ixgbe_dcb_82599.h"
#include "ixgbe_mbx.h"
#include "ixgbe_phy.h"
#include "ixgbe_sriov.h"
#include "ixgbe_model.h"
#include "ixgbe_txrx_common.h"
#include "devlink/devlink.h"

char ixgbe_driver_name[] = "ixgbe";
static const char ixgbe_driver_string[] =
         "Intel(R) 10 Gigabit PCI Express Network Driver";
#ifdef IXGBE_FCOE
char ixgbe_default_device_descr[] =
         "Intel(R) 10 Gigabit Network Connection";
#else
static char ixgbe_default_device_descr[] =
         "Intel(R) 10 Gigabit Network Connection";
#endif
static const char ixgbe_copyright[] =
    "Copyright (c) 1999-2016 Intel Corporation.";

static const char ixgbe_overheat_msg[] = "Network adapter has been stopped because it has over heated. Restart the computer. If the problem persists, power off the system and replace the adapter";

static const struct ixgbe_info *ixgbe_info_tbl[] = {
 [board_82598]  = &ixgbe_82598_info,
 [board_82599]  = &ixgbe_82599_info,
 [board_X540]  = &ixgbe_X540_info,
 [board_X550]  = &ixgbe_X550_info,
 [board_X550EM_x] = &ixgbe_X550EM_x_info,
 [board_x550em_x_fw] = &ixgbe_x550em_x_fw_info,
 [board_x550em_a] = &ixgbe_x550em_a_info,
 [board_x550em_a_fw] = &ixgbe_x550em_a_fw_info,
 [board_e610]  = &ixgbe_e610_info,
};

/* ixgbe_pci_tbl - PCI Device ID Table
 *
 * Wildcard entries (PCI_ANY_ID) should come last
 * Last entry must be all 0s
 *
 * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
 *   Class, Class Mask, private data (not used) }
 */

static const struct pci_device_id ixgbe_pci_tbl[] = {
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598), board_82598 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_DUAL_PORT), board_82598 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_SINGLE_PORT), board_82598 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT), board_82598 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT2), board_82598 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4), board_82598 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT), board_82598 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_DA_DUAL_PORT), board_82598 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM), board_82598 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_XF_LR), board_82598 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_SFP_LOM), board_82598 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_BX), board_82598 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KX4), board_82599 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_XAUI_LOM), board_82599 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KR), board_82599 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP), board_82599 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_EM), board_82599 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KX4_MEZZ), board_82599 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_CX4), board_82599 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_BACKPLANE_FCOE), board_82599 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_FCOE), board_82599 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_T3_LOM), board_82599 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_COMBO_BACKPLANE), board_82599 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T), board_X540 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF2), board_82599 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_LS), board_82599 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_QSFP_SF_QP), board_82599 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599EN_SFP), board_82599 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF_QP), board_82599 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T1), board_X540 },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550T), board_X550},
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550T1), board_X550},
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_KX4), board_X550EM_x},
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_XFI), board_X550EM_x},
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_KR), board_X550EM_x},
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_10G_T), board_X550EM_x},
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_SFP), board_X550EM_x},
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_1G_T), board_x550em_x_fw},
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_KR), board_x550em_a },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_KR_L), board_x550em_a },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SFP_N), board_x550em_a },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SGMII), board_x550em_a },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SGMII_L), board_x550em_a },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_10G_T), board_x550em_a},
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SFP), board_x550em_a },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_1G_T), board_x550em_a_fw },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_1G_T_L), board_x550em_a_fw },
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_BACKPLANE), board_e610},
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_SFP), board_e610},
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_10G_T), board_e610},
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_2_5G_T), board_e610},
 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_E610_SGMII), board_e610},
 /* required last entry */
 {0, }
};
MODULE_DEVICE_TABLE(pci, ixgbe_pci_tbl);

#ifdef CONFIG_IXGBE_DCA
static int ixgbe_notify_dca(struct notifier_block *, unsigned long event,
       void *p);
static struct notifier_block dca_notifier = {
 .notifier_call = ixgbe_notify_dca,
 .next          = NULL,
 .priority      = 0
};
#endif

#ifdef CONFIG_PCI_IOV
static unsigned int max_vfs;
module_param(max_vfs, uint, 0);
MODULE_PARM_DESC(max_vfs,
   "Maximum number of virtual functions to allocate per physical function - default is zero and maximum value is 63. (Deprecated)");
#endif /* CONFIG_PCI_IOV */

static bool allow_unsupported_sfp;
module_param(allow_unsupported_sfp, bool, 0444);
MODULE_PARM_DESC(allow_unsupported_sfp,
   "Allow unsupported and untested SFP+ modules on 82599-based adapters");

#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK)
static int debug = -1;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");

MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver");
MODULE_LICENSE("GPL v2");

DEFINE_STATIC_KEY_FALSE(ixgbe_xdp_locking_key);
EXPORT_SYMBOL(ixgbe_xdp_locking_key);

static struct workqueue_struct *ixgbe_wq;

static bool ixgbe_check_cfg_remove(struct ixgbe_hw *hw, struct pci_dev *pdev);
static void ixgbe_watchdog_link_is_down(struct ixgbe_adapter *);
static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *);
static void ixgbe_watchdog_update_link(struct ixgbe_adapter *);

static const struct net_device_ops ixgbe_netdev_ops;

static bool netif_is_ixgbe(struct net_device *dev)
{
 return dev && (dev->netdev_ops == &ixgbe_netdev_ops);
}

static int ixgbe_read_pci_cfg_word_parent(struct ixgbe_adapter *adapter,
       u32 reg, u16 *value)
{
 struct pci_dev *parent_dev;
 struct pci_bus *parent_bus;

 parent_bus = adapter->pdev->bus->parent;
 if (!parent_bus)
  return -1;

 parent_dev = parent_bus->self;
 if (!parent_dev)
  return -1;

 if (!pci_is_pcie(parent_dev))
  return -1;

 pcie_capability_read_word(parent_dev, reg, value);
 if (*value == IXGBE_FAILED_READ_CFG_WORD &&
     ixgbe_check_cfg_remove(&adapter->hw, parent_dev))
  return -1;
 return 0;
}

static int ixgbe_get_parent_bus_info(struct ixgbe_adapter *adapter)
{
 struct ixgbe_hw *hw = &adapter->hw;
 u16 link_status = 0;
 int err;

 hw->bus.type = ixgbe_bus_type_pci_express;

 /* Get the negotiated link width and speed from PCI config space of the
 * parent, as this device is behind a switch
 */

 err = ixgbe_read_pci_cfg_word_parent(adapter, 18, &link_status);

 /* assume caller will handle error case */
 if (err)
  return err;

 hw->bus.width = ixgbe_convert_bus_width(link_status);
 hw->bus.speed = ixgbe_convert_bus_speed(link_status);

 return 0;
}

/**
 * ixgbe_pcie_from_parent - Determine whether PCIe info should come from parent
 * @hw: hw specific details
 *
 * This function is used by probe to determine whether a device's PCI-Express
 * bandwidth details should be gathered from the parent bus instead of from the
 * device. Used to ensure that various locations all have the correct device ID
 * checks.
 *
 * Return: true if information should be collected from the parent bus, false
 *         otherwise
 */

static bool ixgbe_pcie_from_parent(struct ixgbe_hw *hw)
{
 switch (hw->device_id) {
 case IXGBE_DEV_ID_82599_SFP_SF_QP:
 case IXGBE_DEV_ID_82599_QSFP_SF_QP:
  return true;
 default:
  return false;
 }
}

static void ixgbe_check_minimum_link(struct ixgbe_adapter *adapter,
         int expected_gts)
{
 struct ixgbe_hw *hw = &adapter->hw;
 struct pci_dev *pdev;

 /* Some devices are not connected over PCIe and thus do not negotiate
 * speed. These devices do not have valid bus info, and thus any report
 * we generate may not be correct.
 */

 if (hw->bus.type == ixgbe_bus_type_internal)
  return;

 /* determine whether to use the parent device */
 if (ixgbe_pcie_from_parent(&adapter->hw))
  pdev = adapter->pdev->bus->parent->self;
 else
  pdev = adapter->pdev;

 pcie_print_link_status(pdev);
}

static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter)
{
 if (!test_bit(__IXGBE_DOWN, &adapter->state) &&
     !test_bit(__IXGBE_REMOVING, &adapter->state) &&
     !test_and_set_bit(__IXGBE_SERVICE_SCHED, &adapter->state))
  queue_work(ixgbe_wq, &adapter->service_task);
}

static void ixgbe_remove_adapter(struct ixgbe_hw *hw)
{
 struct ixgbe_adapter *adapter = hw->back;

 if (!hw->hw_addr)
  return;
 hw->hw_addr = NULL;
 e_dev_err("Adapter removed\n");
 if (test_bit(__IXGBE_SERVICE_INITED, &adapter->state))
  ixgbe_service_event_schedule(adapter);
}

static u32 ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg)
{
 u8 __iomem *reg_addr;
 u32 value;
 int i;

 reg_addr = READ_ONCE(hw->hw_addr);
 if (ixgbe_removed(reg_addr))
  return IXGBE_FAILED_READ_REG;

 /* Register read of 0xFFFFFFF can indicate the adapter has been removed,
 * so perform several status register reads to determine if the adapter
 * has been removed.
 */

 for (i = 0; i < IXGBE_FAILED_READ_RETRIES; i++) {
  value = readl(reg_addr + IXGBE_STATUS);
  if (value != IXGBE_FAILED_READ_REG)
   break;
  mdelay(3);
 }

 if (value == IXGBE_FAILED_READ_REG)
  ixgbe_remove_adapter(hw);
 else
  value = readl(reg_addr + reg);
 return value;
}

/**
 * ixgbe_read_reg - Read from device register
 * @hw: hw specific details
 * @reg: offset of register to read
 *
 * Returns : value read or IXGBE_FAILED_READ_REG if removed
 *
 * This function is used to read device registers. It checks for device
 * removal by confirming any read that returns all ones by checking the
 * status register value for all ones. This function avoids reading from
 * the hardware if a removal was previously detected in which case it
 * returns IXGBE_FAILED_READ_REG (all ones).
 */

u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg)
{
 u8 __iomem *reg_addr = READ_ONCE(hw->hw_addr);
 u32 value;

 if (ixgbe_removed(reg_addr))
  return IXGBE_FAILED_READ_REG;
 if (unlikely(hw->phy.nw_mng_if_sel &
       IXGBE_NW_MNG_IF_SEL_SGMII_ENABLE)) {
  struct ixgbe_adapter *adapter;
  int i;

  for (i = 0; i < 200; ++i) {
   value = readl(reg_addr + IXGBE_MAC_SGMII_BUSY);
   if (likely(!value))
    goto writes_completed;
   if (value == IXGBE_FAILED_READ_REG) {
    ixgbe_remove_adapter(hw);
    return IXGBE_FAILED_READ_REG;
   }
   udelay(5);
  }

  adapter = hw->back;
  e_warn(hw, "register writes incomplete %08x\n", value);
 }

writes_completed:
 value = readl(reg_addr + reg);
 if (unlikely(value == IXGBE_FAILED_READ_REG))
  value = ixgbe_check_remove(hw, reg);
 return value;
}

static bool ixgbe_check_cfg_remove(struct ixgbe_hw *hw, struct pci_dev *pdev)
{
 u16 value;

 pci_read_config_word(pdev, PCI_VENDOR_ID, &value);
 if (value == IXGBE_FAILED_READ_CFG_WORD) {
  ixgbe_remove_adapter(hw);
  return true;
 }
 return false;
}

u16 ixgbe_read_pci_cfg_word(struct ixgbe_hw *hw, u32 reg)
{
 struct ixgbe_adapter *adapter = hw->back;
 u16 value;

 if (ixgbe_removed(hw->hw_addr))
  return IXGBE_FAILED_READ_CFG_WORD;
 pci_read_config_word(adapter->pdev, reg, &value);
 if (value == IXGBE_FAILED_READ_CFG_WORD &&
     ixgbe_check_cfg_remove(hw, adapter->pdev))
  return IXGBE_FAILED_READ_CFG_WORD;
 return value;
}

#ifdef CONFIG_PCI_IOV
static u32 ixgbe_read_pci_cfg_dword(struct ixgbe_hw *hw, u32 reg)
{
 struct ixgbe_adapter *adapter = hw->back;
 u32 value;

 if (ixgbe_removed(hw->hw_addr))
  return IXGBE_FAILED_READ_CFG_DWORD;
 pci_read_config_dword(adapter->pdev, reg, &value);
 if (value == IXGBE_FAILED_READ_CFG_DWORD &&
     ixgbe_check_cfg_remove(hw, adapter->pdev))
  return IXGBE_FAILED_READ_CFG_DWORD;
 return value;
}
#endif /* CONFIG_PCI_IOV */

void ixgbe_write_pci_cfg_word(struct ixgbe_hw *hw, u32 reg, u16 value)
{
 struct ixgbe_adapter *adapter = hw->back;

 if (ixgbe_removed(hw->hw_addr))
  return;
 pci_write_config_word(adapter->pdev, reg, value);
}

static void ixgbe_service_event_complete(struct ixgbe_adapter *adapter)
{
 BUG_ON(!test_bit(__IXGBE_SERVICE_SCHED, &adapter->state));

 /* flush memory to make sure state is correct before next watchdog */
 smp_mb__before_atomic();
 clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state);
}

struct ixgbe_reg_info {
 u32 ofs;
 char *name;
};

static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {

 /* General Registers */
 {IXGBE_CTRL, "CTRL"},
 {IXGBE_STATUS, "STATUS"},
 {IXGBE_CTRL_EXT, "CTRL_EXT"},

 /* Interrupt Registers */
 {IXGBE_EICR, "EICR"},

 /* RX Registers */
 {IXGBE_SRRCTL(0), "SRRCTL"},
 {IXGBE_DCA_RXCTRL(0), "DRXCTL"},
 {IXGBE_RDLEN(0), "RDLEN"},
 {IXGBE_RDH(0), "RDH"},
 {IXGBE_RDT(0), "RDT"},
 {IXGBE_RXDCTL(0), "RXDCTL"},
 {IXGBE_RDBAL(0), "RDBAL"},
 {IXGBE_RDBAH(0), "RDBAH"},

 /* TX Registers */
 {IXGBE_TDBAL(0), "TDBAL"},
 {IXGBE_TDBAH(0), "TDBAH"},
 {IXGBE_TDLEN(0), "TDLEN"},
 {IXGBE_TDH(0), "TDH"},
 {IXGBE_TDT(0), "TDT"},
 {IXGBE_TXDCTL(0), "TXDCTL"},

 /* List Terminator */
 { .name = NULL }
};


/*
 * ixgbe_regdump - register printout routine
 */

static void ixgbe_regdump(struct ixgbe_hw *hw, struct ixgbe_reg_info *reginfo)
{
 int i;
 char rname[16];
 u32 regs[64];

 switch (reginfo->ofs) {
 case IXGBE_SRRCTL(0):
  for (i = 0; i < 64; i++)
   regs[i] = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i));
  break;
 case IXGBE_DCA_RXCTRL(0):
  for (i = 0; i < 64; i++)
   regs[i] = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i));
  break;
 case IXGBE_RDLEN(0):
  for (i = 0; i < 64; i++)
   regs[i] = IXGBE_READ_REG(hw, IXGBE_RDLEN(i));
  break;
 case IXGBE_RDH(0):
  for (i = 0; i < 64; i++)
   regs[i] = IXGBE_READ_REG(hw, IXGBE_RDH(i));
  break;
 case IXGBE_RDT(0):
  for (i = 0; i < 64; i++)
   regs[i] = IXGBE_READ_REG(hw, IXGBE_RDT(i));
  break;
 case IXGBE_RXDCTL(0):
  for (i = 0; i < 64; i++)
   regs[i] = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i));
  break;
 case IXGBE_RDBAL(0):
  for (i = 0; i < 64; i++)
   regs[i] = IXGBE_READ_REG(hw, IXGBE_RDBAL(i));
  break;
 case IXGBE_RDBAH(0):
  for (i = 0; i < 64; i++)
   regs[i] = IXGBE_READ_REG(hw, IXGBE_RDBAH(i));
  break;
 case IXGBE_TDBAL(0):
  for (i = 0; i < 64; i++)
   regs[i] = IXGBE_READ_REG(hw, IXGBE_TDBAL(i));
  break;
 case IXGBE_TDBAH(0):
  for (i = 0; i < 64; i++)
   regs[i] = IXGBE_READ_REG(hw, IXGBE_TDBAH(i));
  break;
 case IXGBE_TDLEN(0):
  for (i = 0; i < 64; i++)
   regs[i] = IXGBE_READ_REG(hw, IXGBE_TDLEN(i));
  break;
 case IXGBE_TDH(0):
  for (i = 0; i < 64; i++)
   regs[i] = IXGBE_READ_REG(hw, IXGBE_TDH(i));
  break;
 case IXGBE_TDT(0):
  for (i = 0; i < 64; i++)
   regs[i] = IXGBE_READ_REG(hw, IXGBE_TDT(i));
  break;
 case IXGBE_TXDCTL(0):
  for (i = 0; i < 64; i++)
   regs[i] = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i));
  break;
 default:
  pr_info("%-15s %08x\n",
   reginfo->name, IXGBE_READ_REG(hw, reginfo->ofs));
  return;
 }

 i = 0;
 while (i < 64) {
  int j;
  char buf[9 * 8 + 1];
  char *p = buf;

  snprintf(rname, 16, "%s[%d-%d]", reginfo->name, i, i + 7);
  for (j = 0; j < 8; j++)
   p += sprintf(p, " %08x", regs[i++]);
  pr_err("%-15s%s\n", rname, buf);
 }

}

static void ixgbe_print_buffer(struct ixgbe_ring *ring, int n)
{
 struct ixgbe_tx_buffer *tx_buffer;

 tx_buffer = &ring->tx_buffer_info[ring->next_to_clean];
 pr_info(" %5d %5X %5X %016llX %08X %p %016llX\n",
  n, ring->next_to_use, ring->next_to_clean,
  (u64)dma_unmap_addr(tx_buffer, dma),
  dma_unmap_len(tx_buffer, len),
  tx_buffer->next_to_watch,
  (u64)tx_buffer->time_stamp);
}

/*
 * ixgbe_dump - Print registers, tx-rings and rx-rings
 */

static void ixgbe_dump(struct ixgbe_adapter *adapter)
{
 struct net_device *netdev = adapter->netdev;
 struct ixgbe_hw *hw = &adapter->hw;
 struct ixgbe_reg_info *reginfo;
 int n = 0;
 struct ixgbe_ring *ring;
 struct ixgbe_tx_buffer *tx_buffer;
 union ixgbe_adv_tx_desc *tx_desc;
 struct my_u0 { u64 a; u64 b; } *u0;
 struct ixgbe_ring *rx_ring;
 union ixgbe_adv_rx_desc *rx_desc;
 struct ixgbe_rx_buffer *rx_buffer_info;
 int i = 0;

 if (!netif_msg_hw(adapter))
  return;

 /* Print netdevice Info */
 if (netdev) {
  dev_info(&adapter->pdev->dev, "Net device Info\n");
  pr_info("Device Name state "
   "trans_start\n");
  pr_info("%-15s %016lX %016lX\n",
   netdev->name,
   netdev->state,
   dev_trans_start(netdev));
 }

 /* Print Registers */
 dev_info(&adapter->pdev->dev, "Register Dump\n");
 pr_info(" Register Name Value\n");
 for (reginfo = (struct ixgbe_reg_info *)ixgbe_reg_info_tbl;
      reginfo->name; reginfo++) {
  ixgbe_regdump(hw, reginfo);
 }

 /* Print TX Ring Summary */
 if (!netdev || !netif_running(netdev))
  return;

 dev_info(&adapter->pdev->dev, "TX Rings Summary\n");
 pr_info(" %s %s %s %s\n",
  "Queue [NTU] [NTC] [bi(ntc)->dma ]",
  "leng""ntw""timestamp");
 for (n = 0; n < adapter->num_tx_queues; n++) {
  ring = adapter->tx_ring[n];
  ixgbe_print_buffer(ring, n);
 }

 for (n = 0; n < adapter->num_xdp_queues; n++) {
  ring = adapter->xdp_ring[n];
  ixgbe_print_buffer(ring, n);
 }

 /* Print TX Rings */
 if (!netif_msg_tx_done(adapter))
  goto rx_ring_summary;

 dev_info(&adapter->pdev->dev, "TX Rings Dump\n");

 /* Transmit Descriptor Formats
 *
 * 82598 Advanced Transmit Descriptor
 *   +--------------------------------------------------------------+
 * 0 |         Buffer Address [63:0]                                |
 *   +--------------------------------------------------------------+
 * 8 |  PAYLEN  | POPTS  | IDX | STA | DCMD  |DTYP |  RSV |  DTALEN |
 *   +--------------------------------------------------------------+
 *   63       46 45    40 39 36 35 32 31   24 23 20 19              0
 *
 * 82598 Advanced Transmit Descriptor (Write-Back Format)
 *   +--------------------------------------------------------------+
 * 0 |                          RSV [63:0]                          |
 *   +--------------------------------------------------------------+
 * 8 |            RSV           |  STA  |          NXTSEQ           |
 *   +--------------------------------------------------------------+
 *   63                       36 35   32 31                         0
 *
 * 82599+ Advanced Transmit Descriptor
 *   +--------------------------------------------------------------+
 * 0 |         Buffer Address [63:0]                                |
 *   +--------------------------------------------------------------+
 * 8 |PAYLEN  |POPTS|CC|IDX  |STA  |DCMD  |DTYP |MAC  |RSV  |DTALEN |
 *   +--------------------------------------------------------------+
 *   63     46 45 40 39 38 36 35 32 31  24 23 20 19 18 17 16 15     0
 *
 * 82599+ Advanced Transmit Descriptor (Write-Back Format)
 *   +--------------------------------------------------------------+
 * 0 |                          RSV [63:0]                          |
 *   +--------------------------------------------------------------+
 * 8 |            RSV           |  STA  |           RSV             |
 *   +--------------------------------------------------------------+
 *   63                       36 35   32 31                         0
 */


 for (n = 0; n < adapter->num_tx_queues; n++) {
  ring = adapter->tx_ring[n];
  pr_info("------------------------------------\n");
  pr_info("TX QUEUE INDEX = %d\n", ring->queue_index);
  pr_info("------------------------------------\n");
  pr_info("%s%s %s %s %s %s\n",
   "T [desc] [address 63:0 ] ",
   "[PlPOIdStDDt Ln] [bi->dma ] ",
   "leng""ntw""timestamp""bi->skb");

  for (i = 0; ring->desc && (i < ring->count); i++) {
   tx_desc = IXGBE_TX_DESC(ring, i);
   tx_buffer = &ring->tx_buffer_info[i];
   u0 = (struct my_u0 *)tx_desc;
   if (dma_unmap_len(tx_buffer, len) > 0) {
    const char *ring_desc;

    if (i == ring->next_to_use &&
        i == ring->next_to_clean)
     ring_desc = " NTC/U";
    else if (i == ring->next_to_use)
     ring_desc = " NTU";
    else if (i == ring->next_to_clean)
     ring_desc = " NTC";
    else
     ring_desc = "";
    pr_info("T [0x%03X] %016llX %016llX %016llX %08X %p %016llX %p%s",
     i,
     le64_to_cpu((__force __le64)u0->a),
     le64_to_cpu((__force __le64)u0->b),
     (u64)dma_unmap_addr(tx_buffer, dma),
     dma_unmap_len(tx_buffer, len),
     tx_buffer->next_to_watch,
     (u64)tx_buffer->time_stamp,
     tx_buffer->skb,
     ring_desc);

    if (netif_msg_pktdata(adapter) &&
        tx_buffer->skb)
     print_hex_dump(KERN_INFO, "",
      DUMP_PREFIX_ADDRESS, 16, 1,
      tx_buffer->skb->data,
      dma_unmap_len(tx_buffer, len),
      true);
   }
  }
 }

 /* Print RX Rings Summary */
rx_ring_summary:
 dev_info(&adapter->pdev->dev, "RX Rings Summary\n");
 pr_info("Queue [NTU] [NTC]\n");
 for (n = 0; n < adapter->num_rx_queues; n++) {
  rx_ring = adapter->rx_ring[n];
  pr_info("%5d %5X %5X\n",
   n, rx_ring->next_to_use, rx_ring->next_to_clean);
 }

 /* Print RX Rings */
 if (!netif_msg_rx_status(adapter))
  return;

 dev_info(&adapter->pdev->dev, "RX Rings Dump\n");

 /* Receive Descriptor Formats
 *
 * 82598 Advanced Receive Descriptor (Read) Format
 *    63                                           1        0
 *    +-----------------------------------------------------+
 *  0 |       Packet Buffer Address [63:1]           |A0/NSE|
 *    +----------------------------------------------+------+
 *  8 |       Header Buffer Address [63:1]           |  DD  |
 *    +-----------------------------------------------------+
 *
 *
 * 82598 Advanced Receive Descriptor (Write-Back) Format
 *
 *   63       48 47    32 31  30      21 20 16 15   4 3     0
 *   +------------------------------------------------------+
 * 0 |       RSS Hash /  |SPH| HDR_LEN  | RSV |Packet|  RSS |
 *   | Packet   | IP     |   |          |     | Type | Type |
 *   | Checksum | Ident  |   |          |     |      |      |
 *   +------------------------------------------------------+
 * 8 | VLAN Tag | Length | Extended Error | Extended Status |
 *   +------------------------------------------------------+
 *   63       48 47    32 31            20 19               0
 *
 * 82599+ Advanced Receive Descriptor (Read) Format
 *    63                                           1        0
 *    +-----------------------------------------------------+
 *  0 |       Packet Buffer Address [63:1]           |A0/NSE|
 *    +----------------------------------------------+------+
 *  8 |       Header Buffer Address [63:1]           |  DD  |
 *    +-----------------------------------------------------+
 *
 *
 * 82599+ Advanced Receive Descriptor (Write-Back) Format
 *
 *   63       48 47    32 31  30      21 20 17 16   4 3     0
 *   +------------------------------------------------------+
 * 0 |RSS / Frag Checksum|SPH| HDR_LEN  |RSC- |Packet|  RSS |
 *   |/ RTT / PCoE_PARAM |   |          | CNT | Type | Type |
 *   |/ Flow Dir Flt ID  |   |          |     |      |      |
 *   +------------------------------------------------------+
 * 8 | VLAN Tag | Length |Extended Error| Xtnd Status/NEXTP |
 *   +------------------------------------------------------+
 *   63       48 47    32 31          20 19                 0
 */


 for (n = 0; n < adapter->num_rx_queues; n++) {
  rx_ring = adapter->rx_ring[n];
  pr_info("------------------------------------\n");
  pr_info("RX QUEUE INDEX = %d\n", rx_ring->queue_index);
  pr_info("------------------------------------\n");
  pr_info("%s%s%s\n",
   "R [desc] [ PktBuf A0] ",
   "[ HeadBuf DD] [bi->dma ] [bi->skb ] ",
   "<-- Adv Rx Read format");
  pr_info("%s%s%s\n",
   "RWB[desc] [PcsmIpSHl PtRs] ",
   "[vl er S cks ln] ---------------- [bi->skb ] ",
   "<-- Adv Rx Write-Back format");

  for (i = 0; i < rx_ring->count; i++) {
   const char *ring_desc;

   if (i == rx_ring->next_to_use)
    ring_desc = " NTU";
   else if (i == rx_ring->next_to_clean)
    ring_desc = " NTC";
   else
    ring_desc = "";

   rx_buffer_info = &rx_ring->rx_buffer_info[i];
   rx_desc = IXGBE_RX_DESC(rx_ring, i);
   u0 = (struct my_u0 *)rx_desc;
   if (rx_desc->wb.upper.length) {
    /* Descriptor Done */
    pr_info("RWB[0x%03X] %016llX %016llX ---------------- %p%s\n",
     i,
     le64_to_cpu((__force __le64)u0->a),
     le64_to_cpu((__force __le64)u0->b),
     rx_buffer_info->skb,
     ring_desc);
   } else {
    pr_info("R [0x%03X] %016llX %016llX %016llX %p%s\n",
     i,
     le64_to_cpu((__force __le64)u0->a),
     le64_to_cpu((__force __le64)u0->b),
     (u64)rx_buffer_info->dma,
     rx_buffer_info->skb,
     ring_desc);

    if (netif_msg_pktdata(adapter) &&
        rx_buffer_info->dma) {
     print_hex_dump(KERN_INFO, "",
        DUMP_PREFIX_ADDRESS, 16, 1,
        page_address(rx_buffer_info->page) +
          rx_buffer_info->page_offset,
        ixgbe_rx_bufsz(rx_ring), true);
    }
   }
  }
 }
}

static void ixgbe_release_hw_control(struct ixgbe_adapter *adapter)
{
 u32 ctrl_ext;

 /* Let firmware take over control of h/w */
 ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
 IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
   ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD);
}

static void ixgbe_get_hw_control(struct ixgbe_adapter *adapter)
{
 u32 ctrl_ext;

 /* Let firmware know the driver has taken over */
 ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
 IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
   ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD);
}

/**
 * ixgbe_set_ivar - set the IVAR registers, mapping interrupt causes to vectors
 * @adapter: pointer to adapter struct
 * @direction: 0 for Rx, 1 for Tx, -1 for other causes
 * @queue: queue to map the corresponding interrupt to
 * @msix_vector: the vector to map to the corresponding queue
 *
 */

static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, s8 direction,
      u8 queue, u8 msix_vector)
{
 u32 ivar, index;
 struct ixgbe_hw *hw = &adapter->hw;
 switch (hw->mac.type) {
 case ixgbe_mac_82598EB:
  msix_vector |= IXGBE_IVAR_ALLOC_VAL;
  if (direction == -1)
   direction = 0;
  index = (((direction * 64) + queue) >> 2) & 0x1F;
  ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
  ivar &= ~(0xFF << (8 * (queue & 0x3)));
  ivar |= (msix_vector << (8 * (queue & 0x3)));
  IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
  break;
 case ixgbe_mac_82599EB:
 case ixgbe_mac_X540:
 case ixgbe_mac_X550:
 case ixgbe_mac_X550EM_x:
 case ixgbe_mac_x550em_a:
 case ixgbe_mac_e610:
  if (direction == -1) {
   /* other causes */
   msix_vector |= IXGBE_IVAR_ALLOC_VAL;
   index = ((queue & 1) * 8);
   ivar = IXGBE_READ_REG(&adapter->hw, IXGBE_IVAR_MISC);
   ivar &= ~(0xFF << index);
   ivar |= (msix_vector << index);
   IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR_MISC, ivar);
   break;
  } else {
   /* tx or rx causes */
   msix_vector |= IXGBE_IVAR_ALLOC_VAL;
   index = ((16 * (queue & 1)) + (8 * direction));
   ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(queue >> 1));
   ivar &= ~(0xFF << index);
   ivar |= (msix_vector << index);
   IXGBE_WRITE_REG(hw, IXGBE_IVAR(queue >> 1), ivar);
   break;
  }
 default:
  break;
 }
}

void ixgbe_irq_rearm_queues(struct ixgbe_adapter *adapter,
       u64 qmask)
{
 u32 mask;

 switch (adapter->hw.mac.type) {
 case ixgbe_mac_82598EB:
  mask = (IXGBE_EIMS_RTX_QUEUE & qmask);
  IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask);
  break;
 case ixgbe_mac_82599EB:
 case ixgbe_mac_X540:
 case ixgbe_mac_X550:
 case ixgbe_mac_X550EM_x:
 case ixgbe_mac_x550em_a:
 case ixgbe_mac_e610:
  mask = (qmask & 0xFFFFFFFF);
  IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask);
  mask = (qmask >> 32);
  IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask);
  break;
 default:
  break;
 }
}

static void ixgbe_update_xoff_rx_lfc(struct ixgbe_adapter *adapter)
{
 struct ixgbe_hw *hw = &adapter->hw;
 struct ixgbe_hw_stats *hwstats = &adapter->stats;
 int i;
 u32 data;

 if ((hw->fc.current_mode != ixgbe_fc_full) &&
     (hw->fc.current_mode != ixgbe_fc_rx_pause))
  return;

 switch (hw->mac.type) {
 case ixgbe_mac_82598EB:
  data = IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
  break;
 default:
  data = IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT);
 }
 hwstats->lxoffrxc += data;

 /* refill credits (no tx hang) if we received xoff */
 if (!data)
  return;

 for (i = 0; i < adapter->num_tx_queues; i++)
  clear_bit(__IXGBE_HANG_CHECK_ARMED,
     &adapter->tx_ring[i]->state);
}

static void ixgbe_update_xoff_received(struct ixgbe_adapter *adapter)
{
 struct ixgbe_hw *hw = &adapter->hw;
 struct ixgbe_hw_stats *hwstats = &adapter->stats;
 u32 xoff[8] = {0};
 u8 tc;
 int i;
 bool pfc_en = adapter->dcb_cfg.pfc_mode_enable;

 if (adapter->ixgbe_ieee_pfc)
  pfc_en |= !!(adapter->ixgbe_ieee_pfc->pfc_en);

 if (!(adapter->flags & IXGBE_FLAG_DCB_ENABLED) || !pfc_en) {
  ixgbe_update_xoff_rx_lfc(adapter);
  return;
 }

 /* update stats for each tc, only valid with PFC enabled */
 for (i = 0; i < MAX_TX_PACKET_BUFFERS; i++) {
  u32 pxoffrxc;

  switch (hw->mac.type) {
  case ixgbe_mac_82598EB:
   pxoffrxc = IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(i));
   break;
  default:
   pxoffrxc = IXGBE_READ_REG(hw, IXGBE_PXOFFRXCNT(i));
  }
  hwstats->pxoffrxc[i] += pxoffrxc;
  /* Get the TC for given UP */
  tc = netdev_get_prio_tc_map(adapter->netdev, i);
  xoff[tc] += pxoffrxc;
 }

 /* disarm tx queues that have received xoff frames */
 for (i = 0; i < adapter->num_tx_queues; i++) {
  struct ixgbe_ring *tx_ring = adapter->tx_ring[i];

  tc = tx_ring->dcb_tc;
  if (xoff[tc])
   clear_bit(__IXGBE_HANG_CHECK_ARMED, &tx_ring->state);
 }

 for (i = 0; i < adapter->num_xdp_queues; i++) {
  struct ixgbe_ring *xdp_ring = adapter->xdp_ring[i];

  tc = xdp_ring->dcb_tc;
  if (xoff[tc])
   clear_bit(__IXGBE_HANG_CHECK_ARMED, &xdp_ring->state);
 }
}

static u64 ixgbe_get_tx_completed(struct ixgbe_ring *ring)
{
 return ring->stats.packets;
}

static u64 ixgbe_get_tx_pending(struct ixgbe_ring *ring)
{
 unsigned int head, tail;

 head = ring->next_to_clean;
 tail = ring->next_to_use;

 return ((head <= tail) ? tail : tail + ring->count) - head;
}

/**
 * ixgbe_get_vf_idx - provide VF index number based on queue index
 * @adapter: pointer to the adapter struct
 * @queue: Tx queue identifier
 * @vf: output VF index
 *
 * Provide VF index number associated to the input queue.
 *
 * Returns: 0 if VF provided or error number.
 */

static int ixgbe_get_vf_idx(struct ixgbe_adapter *adapter, u16 queue, u16 *vf)
{
 struct ixgbe_hw *hw = &adapter->hw;
 u8 queue_count;
 u32 reg;

 if (queue >= adapter->num_tx_queues)
  return -EINVAL;

 /* Determine number of queues by checking
 * number of virtual functions
 */

 reg = IXGBE_READ_REG(hw, IXGBE_GCR_EXT);
 switch (reg & IXGBE_GCR_EXT_VT_MODE_MASK) {
 case IXGBE_GCR_EXT_VT_MODE_64:
  queue_count = IXGBE_64VFS_QUEUES;
  break;
 case IXGBE_GCR_EXT_VT_MODE_32:
  queue_count = IXGBE_32VFS_QUEUES;
  break;
 case IXGBE_GCR_EXT_VT_MODE_16:
  queue_count = IXGBE_16VFS_QUEUES;
  break;
 default:
  return -EINVAL;
 }

 *vf = queue / queue_count;

 return 0;
}

static bool ixgbe_check_tx_hang(struct ixgbe_ring *tx_ring)
{
 u32 tx_done = ixgbe_get_tx_completed(tx_ring);
 u32 tx_done_old = tx_ring->tx_stats.tx_done_old;
 u32 tx_pending = ixgbe_get_tx_pending(tx_ring);

 clear_check_for_tx_hang(tx_ring);

 /*
 * Check for a hung queue, but be thorough. This verifies
 * that a transmit has been completed since the previous
 * check AND there is at least one packet pending. The
 * ARMED bit is set to indicate a potential hang. The
 * bit is cleared if a pause frame is received to remove
 * false hang detection due to PFC or 802.3x frames. By
 * requiring this to fail twice we avoid races with
 * pfc clearing the ARMED bit and conditions where we
 * run the check_tx_hang logic with a transmit completion
 * pending but without time to complete it yet.
 */

 if (tx_done_old == tx_done && tx_pending)
  /* make sure it is true for two checks in a row */
  return test_and_set_bit(__IXGBE_HANG_CHECK_ARMED,
     &tx_ring->state);
 /* update completed stats and continue */
 tx_ring->tx_stats.tx_done_old = tx_done;
 /* reset the countdown */
 clear_bit(__IXGBE_HANG_CHECK_ARMED, &tx_ring->state);

 return false;
}

/**
 * ixgbe_tx_timeout_reset - initiate reset due to Tx timeout
 * @adapter: driver private struct
 **/

static void ixgbe_tx_timeout_reset(struct ixgbe_adapter *adapter)
{

 /* Do the reset outside of interrupt context */
 if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
  set_bit(__IXGBE_RESET_REQUESTED, &adapter->state);
  e_warn(drv, "initiating reset due to tx timeout\n");
  ixgbe_service_event_schedule(adapter);
 }
}

/**
 * ixgbe_tx_maxrate - callback to set the maximum per-queue bitrate
 * @netdev: network interface device structure
 * @queue_index: Tx queue to set
 * @maxrate: desired maximum transmit bitrate
 **/

static int ixgbe_tx_maxrate(struct net_device *netdev,
       int queue_index, u32 maxrate)
{
 struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev);
 struct ixgbe_hw *hw = &adapter->hw;
 u32 bcnrc_val = ixgbe_link_mbps(adapter);

 if (!maxrate)
  return 0;

 /* Calculate the rate factor values to set */
 bcnrc_val <<= IXGBE_RTTBCNRC_RF_INT_SHIFT;
 bcnrc_val /= maxrate;

 /* clear everything but the rate factor */
 bcnrc_val &= IXGBE_RTTBCNRC_RF_INT_MASK |
 IXGBE_RTTBCNRC_RF_DEC_MASK;

 /* enable the rate scheduler */
 bcnrc_val |= IXGBE_RTTBCNRC_RS_ENA;

 IXGBE_WRITE_REG(hw, IXGBE_RTTDQSEL, queue_index);
 IXGBE_WRITE_REG(hw, IXGBE_RTTBCNRC, bcnrc_val);

 return 0;
}

/**
 * ixgbe_update_tx_ring_stats - Update Tx ring specific counters
 * @tx_ring: ring to update
 * @q_vector: queue vector ring belongs to
 * @pkts: number of processed packets
 * @bytes: number of processed bytes
 */

void ixgbe_update_tx_ring_stats(struct ixgbe_ring *tx_ring,
    struct ixgbe_q_vector *q_vector, u64 pkts,
    u64 bytes)
{
 u64_stats_update_begin(&tx_ring->syncp);
 tx_ring->stats.bytes += bytes;
 tx_ring->stats.packets += pkts;
 u64_stats_update_end(&tx_ring->syncp);
 q_vector->tx.total_bytes += bytes;
 q_vector->tx.total_packets += pkts;
}

/**
 * ixgbe_update_rx_ring_stats - Update Rx ring specific counters
 * @rx_ring: ring to update
 * @q_vector: queue vector ring belongs to
 * @pkts: number of processed packets
 * @bytes: number of processed bytes
 */

void ixgbe_update_rx_ring_stats(struct ixgbe_ring *rx_ring,
    struct ixgbe_q_vector *q_vector, u64 pkts,
    u64 bytes)
{
 u64_stats_update_begin(&rx_ring->syncp);
 rx_ring->stats.bytes += bytes;
 rx_ring->stats.packets += pkts;
 u64_stats_update_end(&rx_ring->syncp);
 q_vector->rx.total_bytes += bytes;
 q_vector->rx.total_packets += pkts;
}

/**
 * ixgbe_pf_handle_tx_hang - handle Tx hang on PF
 * @tx_ring: tx ring number
 * @next: next ring
 *
 * Prints a message containing details about the tx hang.
 */

static void ixgbe_pf_handle_tx_hang(struct ixgbe_ring *tx_ring,
        unsigned int next)
{
 struct ixgbe_adapter *adapter = netdev_priv(tx_ring->netdev);
 struct ixgbe_hw *hw = &adapter->hw;

 e_err(drv, "Detected Tx Unit Hang\n"
     " Tx Queue <%d>\n"
     " TDH, TDT <%x>, <%x>\n"
     " next_to_use <%x>\n"
     " next_to_clean <%x>\n"
     "tx_buffer_info[next_to_clean]\n"
     " time_stamp <%lx>\n"
     " jiffies <%lx>\n",
       tx_ring->queue_index,
       IXGBE_READ_REG(hw, IXGBE_TDH(tx_ring->reg_idx)),
       IXGBE_READ_REG(hw, IXGBE_TDT(tx_ring->reg_idx)),
       tx_ring->next_to_use, next,
       tx_ring->tx_buffer_info[next].time_stamp, jiffies);

 netif_stop_subqueue(tx_ring->netdev,
       tx_ring->queue_index);
}

/**
 * ixgbe_vf_handle_tx_hang - handle Tx hang on VF
 * @adapter: structure containing ring specific data
 * @vf: VF index
 *
 * Print a message containing details about malicious driver detection.
 * Set malicious VF link down if the detection happened several times.
 */

static void ixgbe_vf_handle_tx_hang(struct ixgbe_adapter *adapter, u16 vf)
{
 struct ixgbe_hw *hw = &adapter->hw;

 if (adapter->hw.mac.type != ixgbe_mac_e610)
  return;

 e_warn(drv,
        "Malicious Driver Detection tx hang detected on PF %d VF %d MAC: %pM",
        hw->bus.func, vf, adapter->vfinfo[vf].vf_mac_addresses);

 adapter->tx_hang_count[vf]++;
 if (adapter->tx_hang_count[vf] == IXGBE_MAX_TX_VF_HANGS) {
  ixgbe_set_vf_link_state(adapter, vf,
     IFLA_VF_LINK_STATE_DISABLE);
  adapter->tx_hang_count[vf] = 0;
 }
}

static u32 ixgbe_poll_tx_icache(struct ixgbe_hw *hw, u16 queue, u16 idx)
{
 IXGBE_WRITE_REG(hw, IXGBE_TXDESCIC, queue * idx);
 return IXGBE_READ_REG(hw, IXGBE_TXDESCIC);
}

/**
 * ixgbe_check_illegal_queue - search for queue with illegal packet
 * @adapter: structure containing ring specific data
 * @queue: queue index
 *
 * Check if tx descriptor connected with input queue
 * contains illegal packet.
 *
 * Returns: true if queue contain illegal packet.
 */

static bool ixgbe_check_illegal_queue(struct ixgbe_adapter *adapter,
          u16 queue)
{
 u32 hdr_len_reg, mss_len_reg, type_reg;
 struct ixgbe_hw *hw = &adapter->hw;
 u32 mss_len, header_len, reg;

 for (u16 i = 0; i < IXGBE_MAX_TX_DESCRIPTORS; i++) {
  /* HW will clear bit IXGBE_TXDESCIC_READY when address
 * is written to address field. HW will set this bit
 * when iCache read is done, and data is ready at TIC_DWx.
 * Set descriptor address.
 */

  read_poll_timeout(ixgbe_poll_tx_icache, reg,
      !(reg & IXGBE_TXDESCIC_READY), 0, 0, false,
      hw, queue, i);

  /* read tx descriptor access registers */
  hdr_len_reg = IXGBE_READ_REG(hw, IXGBE_TIC_DW2(IXGBE_VLAN_MACIP_LENS_REG));
  type_reg = IXGBE_READ_REG(hw, IXGBE_TIC_DW2(IXGBE_TYPE_TUCMD_MLHL));
  mss_len_reg = IXGBE_READ_REG(hw, IXGBE_TIC_DW2(IXGBE_MSS_L4LEN_IDX));

  /* check if Advanced Context Descriptor */
  if (FIELD_GET(IXGBE_ADVTXD_DTYP_MASK, type_reg) !=
      IXGBE_ADVTXD_DTYP_CTXT)
   continue;

  /* check for illegal MSS and Header length */
  mss_len = FIELD_GET(IXGBE_ADVTXD_MSS_MASK, mss_len_reg);
  header_len = FIELD_GET(IXGBE_ADVTXD_HEADER_LEN_MASK,
           hdr_len_reg);
  if ((mss_len + header_len) > SZ_16K) {
   e_warn(probe, "mss len + header len too long\n");
   return true;
  }
 }

 return false;
}

/**
 * ixgbe_handle_mdd_event - handle mdd event
 * @adapter: structure containing ring specific data
 * @tx_ring: tx descriptor ring to handle
 *
 * Reset VF driver if malicious vf detected or
 * illegal packet in an any queue detected.
 */

static void ixgbe_handle_mdd_event(struct ixgbe_adapter *adapter,
       struct ixgbe_ring *tx_ring)
{
 u16 vf, q;

 if (adapter->vfinfo && ixgbe_check_mdd_event(adapter)) {
  /* vf mdd info and malicious vf detected */
  if (!ixgbe_get_vf_idx(adapter, tx_ring->queue_index, &vf))
   ixgbe_vf_handle_tx_hang(adapter, vf);
 } else {
  /* malicious vf not detected */
  for (q = 0; q < IXGBE_MAX_TX_QUEUES; q++) {
   if (ixgbe_check_illegal_queue(adapter, q) &&
       !ixgbe_get_vf_idx(adapter, q, &vf))
    /* illegal queue detected */
    ixgbe_vf_handle_tx_hang(adapter, vf);
  }
 }
}

/**
 * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
 * @q_vector: structure containing interrupt and ring information
 * @tx_ring: tx ring to clean
 * @napi_budget: Used to determine if we are in netpoll
 **/

static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
          struct ixgbe_ring *tx_ring, int napi_budget)
{
 struct ixgbe_adapter *adapter = q_vector->adapter;
 struct ixgbe_tx_buffer *tx_buffer;
 union ixgbe_adv_tx_desc *tx_desc;
 unsigned int total_bytes = 0, total_packets = 0, total_ipsec = 0;
 unsigned int budget = q_vector->tx.work_limit;
 unsigned int i = tx_ring->next_to_clean;
 struct netdev_queue *txq;

 if (test_bit(__IXGBE_DOWN, &adapter->state))
  return true;

 tx_buffer = &tx_ring->tx_buffer_info[i];
 tx_desc = IXGBE_TX_DESC(tx_ring, i);
 i -= tx_ring->count;

 do {
  union ixgbe_adv_tx_desc *eop_desc = tx_buffer->next_to_watch;

  /* if next_to_watch is not set then there is no work pending */
  if (!eop_desc)
   break;

  /* prevent any other reads prior to eop_desc */
  smp_rmb();

  /* if DD is not set pending work has not been completed */
  if (!(eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)))
   break;

  /* clear next_to_watch to prevent false hangs */
  tx_buffer->next_to_watch = NULL;

  /* update the statistics for this packet */
  total_bytes += tx_buffer->bytecount;
  total_packets += tx_buffer->gso_segs;
  if (tx_buffer->tx_flags & IXGBE_TX_FLAGS_IPSEC)
   total_ipsec++;

  /* free the skb */
  if (ring_is_xdp(tx_ring))
   xdp_return_frame(tx_buffer->xdpf);
  else
   napi_consume_skb(tx_buffer->skb, napi_budget);

  /* unmap skb header data */
  dma_unmap_single(tx_ring->dev,
     dma_unmap_addr(tx_buffer, dma),
     dma_unmap_len(tx_buffer, len),
     DMA_TO_DEVICE);

  /* clear tx_buffer data */
  dma_unmap_len_set(tx_buffer, len, 0);

  /* unmap remaining buffers */
  while (tx_desc != eop_desc) {
   tx_buffer++;
   tx_desc++;
   i++;
   if (unlikely(!i)) {
    i -= tx_ring->count;
    tx_buffer = tx_ring->tx_buffer_info;
    tx_desc = IXGBE_TX_DESC(tx_ring, 0);
   }

   /* unmap any remaining paged data */
   if (dma_unmap_len(tx_buffer, len)) {
    dma_unmap_page(tx_ring->dev,
            dma_unmap_addr(tx_buffer, dma),
            dma_unmap_len(tx_buffer, len),
            DMA_TO_DEVICE);
    dma_unmap_len_set(tx_buffer, len, 0);
   }
  }

  /* move us one more past the eop_desc for start of next pkt */
  tx_buffer++;
  tx_desc++;
  i++;
  if (unlikely(!i)) {
   i -= tx_ring->count;
   tx_buffer = tx_ring->tx_buffer_info;
   tx_desc = IXGBE_TX_DESC(tx_ring, 0);
  }

  /* issue prefetch for next Tx descriptor */
  prefetch(tx_desc);

  /* update budget accounting */
  budget--;
 } while (likely(budget));

 i += tx_ring->count;
 tx_ring->next_to_clean = i;
 ixgbe_update_tx_ring_stats(tx_ring, q_vector, total_packets,
       total_bytes);
 adapter->tx_ipsec += total_ipsec;

 if (ring_is_xdp(tx_ring))
  return !!budget;

 if (check_for_tx_hang(tx_ring) && ixgbe_check_tx_hang(tx_ring)) {
  if (adapter->hw.mac.type == ixgbe_mac_e610)
   ixgbe_handle_mdd_event(adapter, tx_ring);

  ixgbe_pf_handle_tx_hang(tx_ring, i);

  e_info(probe,
         "tx hang %d detected on queue %d, resetting adapter\n",
   adapter->tx_timeout_count + 1, tx_ring->queue_index);

  /* schedule immediate reset if we believe we hung */
  ixgbe_tx_timeout_reset(adapter);

  /* the adapter is about to reset, no point in enabling stuff */
  return true;
 }

#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
 txq = netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index);
 if (!__netif_txq_completed_wake(txq, total_packets, total_bytes,
     ixgbe_desc_unused(tx_ring),
     TX_WAKE_THRESHOLD,
     !netif_carrier_ok(tx_ring->netdev) ||
     test_bit(__IXGBE_DOWN, &adapter->state)))
  ++tx_ring->tx_stats.restart_queue;

 return !!budget;
}

#ifdef CONFIG_IXGBE_DCA
static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter,
    struct ixgbe_ring *tx_ring,
    int cpu)
{
 struct ixgbe_hw *hw = &adapter->hw;
 u32 txctrl = 0;
 u16 reg_offset;

 if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
  txctrl = dca3_get_tag(tx_ring->dev, cpu);

 switch (hw->mac.type) {
 case ixgbe_mac_82598EB:
  reg_offset = IXGBE_DCA_TXCTRL(tx_ring->reg_idx);
  break;
 case ixgbe_mac_82599EB:
 case ixgbe_mac_X540:
  reg_offset = IXGBE_DCA_TXCTRL_82599(tx_ring->reg_idx);
  txctrl <<= IXGBE_DCA_TXCTRL_CPUID_SHIFT_82599;
  break;
 default:
  /* for unknown hardware do not write register */
  return;
 }

 /*
 * We can enable relaxed ordering for reads, but not writes when
 * DCA is enabled.  This is due to a known issue in some chipsets
 * which will cause the DCA tag to be cleared.
 */

 txctrl |= IXGBE_DCA_TXCTRL_DESC_RRO_EN |
    IXGBE_DCA_TXCTRL_DATA_RRO_EN |
    IXGBE_DCA_TXCTRL_DESC_DCA_EN;

 IXGBE_WRITE_REG(hw, reg_offset, txctrl);
}

static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter,
    struct ixgbe_ring *rx_ring,
    int cpu)
{
 struct ixgbe_hw *hw = &adapter->hw;
 u32 rxctrl = 0;
 u8 reg_idx = rx_ring->reg_idx;

 if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
  rxctrl = dca3_get_tag(rx_ring->dev, cpu);

 switch (hw->mac.type) {
 case ixgbe_mac_82599EB:
 case ixgbe_mac_X540:
  rxctrl <<= IXGBE_DCA_RXCTRL_CPUID_SHIFT_82599;
  break;
 default:
  break;
 }

 /*
 * We can enable relaxed ordering for reads, but not writes when
 * DCA is enabled.  This is due to a known issue in some chipsets
 * which will cause the DCA tag to be cleared.
 */

 rxctrl |= IXGBE_DCA_RXCTRL_DESC_RRO_EN |
    IXGBE_DCA_RXCTRL_DATA_DCA_EN |
    IXGBE_DCA_RXCTRL_DESC_DCA_EN;

 IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(reg_idx), rxctrl);
}

static void ixgbe_update_dca(struct ixgbe_q_vector *q_vector)
{
 struct ixgbe_adapter *adapter = q_vector->adapter;
 struct ixgbe_ring *ring;
 int cpu = get_cpu();

 if (q_vector->cpu == cpu)
  goto out_no_update;

 ixgbe_for_each_ring(ring, q_vector->tx)
  ixgbe_update_tx_dca(adapter, ring, cpu);

 ixgbe_for_each_ring(ring, q_vector->rx)
  ixgbe_update_rx_dca(adapter, ring, cpu);

 q_vector->cpu = cpu;
out_no_update:
 put_cpu();
}

static void ixgbe_setup_dca(struct ixgbe_adapter *adapter)
{
 int i;

 /* always use CB2 mode, difference is masked in the CB driver */
 if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
  IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_CTRL,
    IXGBE_DCA_CTRL_DCA_MODE_CB2);
 else
  IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_CTRL,
    IXGBE_DCA_CTRL_DCA_DISABLE);

 for (i = 0; i < adapter->num_q_vectors; i++) {
  adapter->q_vector[i]->cpu = -1;
  ixgbe_update_dca(adapter->q_vector[i]);
 }
}

static int __ixgbe_notify_dca(struct device *dev, void *data)
{
 struct ixgbe_adapter *adapter = dev_get_drvdata(dev);
 unsigned long event = *(unsigned long *)data;

 if (!(adapter->flags & IXGBE_FLAG_DCA_CAPABLE))
  return 0;

 switch (event) {
 case DCA_PROVIDER_ADD:
  /* if we're already enabled, don't do it again */
  if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
   break;
  if (dca_add_requester(dev) == 0) {
   adapter->flags |= IXGBE_FLAG_DCA_ENABLED;
   IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_CTRL,
     IXGBE_DCA_CTRL_DCA_MODE_CB2);
   break;
  }
  fallthrough; /* DCA is disabled. */
 case DCA_PROVIDER_REMOVE:
  if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) {
   dca_remove_requester(dev);
   adapter->flags &= ~IXGBE_FLAG_DCA_ENABLED;
   IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_CTRL,
     IXGBE_DCA_CTRL_DCA_DISABLE);
  }
  break;
 }

 return 0;
}

#endif /* CONFIG_IXGBE_DCA */

#define IXGBE_RSS_L4_TYPES_MASK \
 ((1ul << IXGBE_RXDADV_RSSTYPE_IPV4_TCP) | \
  (1ul << IXGBE_RXDADV_RSSTYPE_IPV4_UDP) | \
  (1ul << IXGBE_RXDADV_RSSTYPE_IPV6_TCP) | \
  (1ul << IXGBE_RXDADV_RSSTYPE_IPV6_UDP))

static inline void ixgbe_rx_hash(struct ixgbe_ring *ring,
     union ixgbe_adv_rx_desc *rx_desc,
     struct sk_buff *skb)
{
 u16 rss_type;

 if (!(ring->netdev->features & NETIF_F_RXHASH))
  return;

 rss_type = le16_to_cpu(rx_desc->wb.lower.lo_dword.hs_rss.pkt_info) &
     IXGBE_RXDADV_RSSTYPE_MASK;

 if (!rss_type)
  return;

 skb_set_hash(skb, le32_to_cpu(rx_desc->wb.lower.hi_dword.rss),
       (IXGBE_RSS_L4_TYPES_MASK & (1ul << rss_type)) ?
       PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
}

#ifdef IXGBE_FCOE
/**
 * ixgbe_rx_is_fcoe - check the rx desc for incoming pkt type
 * @ring: structure containing ring specific data
 * @rx_desc: advanced rx descriptor
 *
 * Returns : true if it is FCoE pkt
 */

static inline bool ixgbe_rx_is_fcoe(struct ixgbe_ring *ring,
        union ixgbe_adv_rx_desc *rx_desc)
{
 __le16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;

 return test_bit(__IXGBE_RX_FCOE, &ring->state) &&
        ((pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_ETQF_MASK)) ==
  (cpu_to_le16(IXGBE_ETQF_FILTER_FCOE <<
        IXGBE_RXDADV_PKTTYPE_ETQF_SHIFT)));
}

#endif /* IXGBE_FCOE */
/**
 * ixgbe_rx_checksum - indicate in skb if hw indicated a good cksum
 * @ring: structure containing ring specific data
 * @rx_desc: current Rx descriptor being processed
 * @skb: skb currently being received and modified
 **/

static inline void ixgbe_rx_checksum(struct ixgbe_ring *ring,
         union ixgbe_adv_rx_desc *rx_desc,
         struct sk_buff *skb)
{
 __le16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;
 bool encap_pkt = false;

 skb_checksum_none_assert(skb);

 /* Rx csum disabled */
 if (!(ring->netdev->features & NETIF_F_RXCSUM))
  return;

 /* check for VXLAN and Geneve packets */
 if (pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_VXLAN)) {
  encap_pkt = true;
  skb->encapsulation = 1;
 }

 /* if IP and error */
 if (ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_IPCS) &&
     ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_IPE)) {
  ring->rx_stats.csum_err++;
  return;
 }

 if (!ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_L4CS))
  return;

 if (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_TCPE)) {
  /*
 * 82599 errata, UDP frames with a 0 checksum can be marked as
 * checksum errors.
 */

  if ((pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_UDP)) &&
      test_bit(__IXGBE_RX_CSUM_UDP_ZERO_ERR, &ring->state))
   return;

  ring->rx_stats.csum_err++;
  return;
 }

 /* It must be a TCP or UDP packet with a valid checksum */
 skb->ip_summed = CHECKSUM_UNNECESSARY;
 if (encap_pkt) {
  if (!ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_OUTERIPCS))
   return;

  if (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_OUTERIPER)) {
   skb->ip_summed = CHECKSUM_NONE;
   return;
  }
  /* If we checked the outer header let the stack know */
  skb->csum_level = 1;
 }
}

static unsigned int ixgbe_rx_offset(struct ixgbe_ring *rx_ring)
{
 return ring_uses_build_skb(rx_ring) ? IXGBE_SKB_PAD : 0;
}

static bool ixgbe_alloc_mapped_page(struct ixgbe_ring *rx_ring,
        struct ixgbe_rx_buffer *bi)
{
 struct page *page = bi->page;
 dma_addr_t dma;

 /* since we are recycling buffers we should seldom need to alloc */
 if (likely(page))
  return true;

 /* alloc new page for storage */
 page = dev_alloc_pages(ixgbe_rx_pg_order(rx_ring));
 if (unlikely(!page)) {
  rx_ring->rx_stats.alloc_rx_page_failed++;
  return false;
 }

 /* map page for use */
 dma = dma_map_page_attrs(rx_ring->dev, page, 0,
     ixgbe_rx_pg_size(rx_ring),
     DMA_FROM_DEVICE,
     IXGBE_RX_DMA_ATTR);

 /*
 * if mapping failed free memory back to system since
 * there isn't much point in holding memory we can't use
 */

 if (dma_mapping_error(rx_ring->dev, dma)) {
  __free_pages(page, ixgbe_rx_pg_order(rx_ring));

  rx_ring->rx_stats.alloc_rx_page_failed++;
  return false;
 }

 bi->dma = dma;
 bi->page = page;
 bi->page_offset = rx_ring->rx_offset;
 page_ref_add(page, USHRT_MAX - 1);
 bi->pagecnt_bias = USHRT_MAX;
 rx_ring->rx_stats.alloc_rx_page++;

 return true;
}

/**
 * ixgbe_alloc_rx_buffers - Replace used receive buffers
 * @rx_ring: ring to place buffers on
 * @cleaned_count: number of buffers to replace
 **/

void ixgbe_alloc_rx_buffers(struct ixgbe_ring *rx_ring, u16 cleaned_count)
{
 union ixgbe_adv_rx_desc *rx_desc;
 struct ixgbe_rx_buffer *bi;
 u16 i = rx_ring->next_to_use;
 u16 bufsz;

 /* nothing to do */
 if (!cleaned_count)
  return;

 rx_desc = IXGBE_RX_DESC(rx_ring, i);
 bi = &rx_ring->rx_buffer_info[i];
 i -= rx_ring->count;

 bufsz = ixgbe_rx_bufsz(rx_ring);

 do {
  if (!ixgbe_alloc_mapped_page(rx_ring, bi))
   break;

  /* sync the buffer for use by the device */
  dma_sync_single_range_for_device(rx_ring->dev, bi->dma,
       bi->page_offset, bufsz,
       DMA_FROM_DEVICE);

  /*
 * Refresh the desc even if buffer_addrs didn't change
 * because each write-back erases this info.
 */

  rx_desc->read.pkt_addr = cpu_to_le64(bi->dma + bi->page_offset);

  rx_desc++;
  bi++;
  i++;
  if (unlikely(!i)) {
   rx_desc = IXGBE_RX_DESC(rx_ring, 0);
   bi = rx_ring->rx_buffer_info;
   i -= rx_ring->count;
  }

  /* clear the length for the next_to_use descriptor */
  rx_desc->wb.upper.length = 0;

  cleaned_count--;
 } while (cleaned_count);

 i += rx_ring->count;

 if (rx_ring->next_to_use != i) {
  rx_ring->next_to_use = i;

  /* update next to alloc since we have filled the ring */
  rx_ring->next_to_alloc = i;

  /* Force memory writes to complete before letting h/w
 * know there are new descriptors to fetch.  (Only
 * applicable for weak-ordered memory model archs,
 * such as IA-64).
 */

  wmb();
  writel(i, rx_ring->tail);
 }
}

static void ixgbe_set_rsc_gso_size(struct ixgbe_ring *ring,
       struct sk_buff *skb)
{
 u16 hdr_len = skb_headlen(skb);

 /* set gso_size to avoid messing up TCP MSS */
 skb_shinfo(skb)->gso_size = DIV_ROUND_UP((skb->len - hdr_len),
       IXGBE_CB(skb)->append_cnt);
 skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
}

static void ixgbe_update_rsc_stats(struct ixgbe_ring *rx_ring,
       struct sk_buff *skb)
{
 /* if append_cnt is 0 then frame is not RSC */
 if (!IXGBE_CB(skb)->append_cnt)
  return;

 rx_ring->rx_stats.rsc_count += IXGBE_CB(skb)->append_cnt;
 rx_ring->rx_stats.rsc_flush++;

 ixgbe_set_rsc_gso_size(rx_ring, skb);

 /* gso_size is computed using append_cnt so always clear it last */
 IXGBE_CB(skb)->append_cnt = 0;
}

/**
 * ixgbe_process_skb_fields - Populate skb header fields from Rx descriptor
 * @rx_ring: rx descriptor ring packet is being transacted on
 * @rx_desc: pointer to the EOP Rx descriptor
 * @skb: pointer to current skb being populated
 *
 * This function checks the ring, descriptor, and packet information in
 * order to populate the hash, checksum, VLAN, timestamp, protocol, and
 * other fields within the skb.
 **/

void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring,
         union ixgbe_adv_rx_desc *rx_desc,
         struct sk_buff *skb)
{
 struct net_device *dev = rx_ring->netdev;
 u32 flags = rx_ring->q_vector->adapter->flags;

 ixgbe_update_rsc_stats(rx_ring, skb);

 ixgbe_rx_hash(rx_ring, rx_desc, skb);

 ixgbe_rx_checksum(rx_ring, rx_desc, skb);

 if (unlikely(flags & IXGBE_FLAG_RX_HWTSTAMP_ENABLED))
  ixgbe_ptp_rx_hwtstamp(rx_ring, rx_desc, skb);

 if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
     ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_VP)) {
  u16 vid = le16_to_cpu(rx_desc->wb.upper.vlan);
  __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
 }

 if (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_SECP))
  ixgbe_ipsec_rx(rx_ring, rx_desc, skb);

 /* record Rx queue, or update MACVLAN statistics */
 if (netif_is_ixgbe(dev))
  skb_record_rx_queue(skb, rx_ring->queue_index);
 else
  macvlan_count_rx(netdev_priv(dev), skb->len + ETH_HLEN, true,
     false);

 skb->protocol = eth_type_trans(skb, dev);
}

void ixgbe_rx_skb(struct ixgbe_q_vector *q_vector,
    struct sk_buff *skb)
{
 napi_gro_receive(&q_vector->napi, skb);
}

/**
 * ixgbe_is_non_eop - process handling of non-EOP buffers
 * @rx_ring: Rx ring being processed
 * @rx_desc: Rx descriptor for current buffer
 * @skb: Current socket buffer containing buffer in progress
 *
 * This function updates next to clean.  If the buffer is an EOP buffer
 * this function exits returning false, otherwise it will place the
 * sk_buff in the next buffer to be chained and return true indicating
 * that this is in fact a non-EOP buffer.
 **/

static bool ixgbe_is_non_eop(struct ixgbe_ring *rx_ring,
        union ixgbe_adv_rx_desc *rx_desc,
        struct sk_buff *skb)
{
 u32 ntc = rx_ring->next_to_clean + 1;

 /* fetch, update, and store next to clean */
 ntc = (ntc < rx_ring->count) ? ntc : 0;
 rx_ring->next_to_clean = ntc;

 prefetch(IXGBE_RX_DESC(rx_ring, ntc));

 /* update RSC append count if present */
 if (ring_is_rsc_enabled(rx_ring)) {
  __le32 rsc_enabled = rx_desc->wb.lower.lo_dword.data &
         cpu_to_le32(IXGBE_RXDADV_RSCCNT_MASK);

  if (unlikely(rsc_enabled)) {
   u32 rsc_cnt = le32_to_cpu(rsc_enabled);

   rsc_cnt >>= IXGBE_RXDADV_RSCCNT_SHIFT;
   IXGBE_CB(skb)->append_cnt += rsc_cnt - 1;

   /* update ntc based on RSC value */
   ntc = le32_to_cpu(rx_desc->wb.upper.status_error);
   ntc &= IXGBE_RXDADV_NEXTP_MASK;
   ntc >>= IXGBE_RXDADV_NEXTP_SHIFT;
  }
 }

 /* if we are the last buffer then there is nothing else to do */
 if (likely(ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_EOP)))
  return false;

 /* place skb in next buffer to be received */
 rx_ring->rx_buffer_info[ntc].skb = skb;
 rx_ring->rx_stats.non_eop_descs++;

 return true;
}

/**
 * ixgbe_pull_tail - ixgbe specific version of skb_pull_tail
 * @rx_ring: rx descriptor ring packet is being transacted on
 * @skb: pointer to current skb being adjusted
 *
 * This function is an ixgbe specific version of __pskb_pull_tail.  The
 * main difference between this version and the original function is that
 * this function can make several assumptions about the state of things
 * that allow for significant optimizations versus the standard function.
 * As a result we can do things like drop a frag and maintain an accurate
 * truesize for the skb.
 */

static void ixgbe_pull_tail(struct ixgbe_ring *rx_ring,
       struct sk_buff *skb)
{
 skb_frag_t *frag = &skb_shinfo(skb)->frags[0];
 unsigned char *va;
 unsigned int pull_len;

 /*
 * it is valid to use page_address instead of kmap since we are
 * working with pages allocated out of the lomem pool per
 * alloc_page(GFP_ATOMIC)
 */

 va = skb_frag_address(frag);

 /*
 * we need the header to contain the greater of either ETH_HLEN or
 * 60 bytes if the skb->len is less than 60 for skb_pad.
 */

 pull_len = eth_get_headlen(skb->dev, va, IXGBE_RX_HDR_SIZE);

 /* align pull length to size of long to optimize memcpy performance */
 skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long)));

 /* update all of the pointers */
 skb_frag_size_sub(frag, pull_len);
 skb_frag_off_add(frag, pull_len);
 skb->data_len -= pull_len;
 skb->tail += pull_len;
}

/**
 * ixgbe_dma_sync_frag - perform DMA sync for first frag of SKB
 * @rx_ring: rx descriptor ring packet is being transacted on
 * @skb: pointer to current skb being updated
 *
 * This function provides a basic DMA sync up for the first fragment of an
 * skb.  The reason for doing this is that the first fragment cannot be
 * unmapped until we have reached the end of packet descriptor for a buffer
 * chain.
 */

static void ixgbe_dma_sync_frag(struct ixgbe_ring *rx_ring,
    struct sk_buff *skb)
{
 if (ring_uses_build_skb(rx_ring)) {
  unsigned long mask = (unsigned long)ixgbe_rx_pg_size(rx_ring) - 1;
  unsigned long offset = (unsigned long)(skb->data) & mask;

  dma_sync_single_range_for_cpu(rx_ring->dev,
           IXGBE_CB(skb)->dma,
           offset,
           skb_headlen(skb),
           DMA_FROM_DEVICE);
 } else {
  skb_frag_t *frag = &skb_shinfo(skb)->frags[0];

  dma_sync_single_range_for_cpu(rx_ring->dev,
           IXGBE_CB(skb)->dma,
           skb_frag_off(frag),
           skb_frag_size(frag),
           DMA_FROM_DEVICE);
 }

 /* If the page was released, just unmap it. */
 if (unlikely(IXGBE_CB(skb)->page_released)) {
  dma_unmap_page_attrs(rx_ring->dev, IXGBE_CB(skb)->dma,
         ixgbe_rx_pg_size(rx_ring),
         DMA_FROM_DEVICE,
         IXGBE_RX_DMA_ATTR);
 }
}

/**
 * ixgbe_cleanup_headers - Correct corrupted or empty headers
 * @rx_ring: rx descriptor ring packet is being transacted on
 * @rx_desc: pointer to the EOP Rx descriptor
 * @skb: pointer to current skb being fixed
 *
 * Check if the skb is valid in the XDP case it will be an error pointer.
 * Return true in this case to abort processing and advance to next
 * descriptor.
 *
 * Check for corrupted packet headers caused by senders on the local L2
 * embedded NIC switch not setting up their Tx Descriptors right.  These
 * should be very rare.
 *
 * Also address the case where we are pulling data in on pages only
 * and as such no data is present in the skb header.
 *
 * In addition if skb is not at least 60 bytes we need to pad it so that
 * it is large enough to qualify as a valid Ethernet frame.
 *
 * Returns true if an error was encountered and skb was freed.
 **/

bool ixgbe_cleanup_headers(struct ixgbe_ring *rx_ring,
      union ixgbe_adv_rx_desc *rx_desc,
      struct sk_buff *skb)
{
 struct net_device *netdev = rx_ring->netdev;

 /* Verify netdev is present, and that packet does not have any
 * errors that would be unacceptable to the netdev.
 */

 if (!netdev ||
     (unlikely(ixgbe_test_staterr(rx_desc,
      IXGBE_RXDADV_ERR_FRAME_ERR_MASK) &&
      !(netdev->features & NETIF_F_RXALL)))) {
  dev_kfree_skb_any(skb);
  return true;
 }

 /* place header in linear portion of buffer */
 if (!skb_headlen(skb))
  ixgbe_pull_tail(rx_ring, skb);

#ifdef IXGBE_FCOE
 /* do not attempt to pad FCoE Frames as this will disrupt DDP */
 if (ixgbe_rx_is_fcoe(rx_ring, rx_desc))
  return false;

#endif
 /* if eth_skb_pad returns an error the skb was freed */
 if (eth_skb_pad(skb))
  return true;

 return false;
}

/**
 * ixgbe_reuse_rx_page - page flip buffer and store it back on the ring
 * @rx_ring: rx descriptor ring to store buffers on
 * @old_buff: donor buffer to have page reused
 *
 * Synchronizes page for reuse by the adapter
 **/

static void ixgbe_reuse_rx_page(struct ixgbe_ring *rx_ring,
    struct ixgbe_rx_buffer *old_buff)
{
 struct ixgbe_rx_buffer *new_buff;
 u16 nta = rx_ring->next_to_alloc;

 new_buff = &rx_ring->rx_buffer_info[nta];

 /* update, and store next to alloc */
 nta++;
 rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0;

 /* Transfer page from old buffer to new buffer.
 * Move each member individually to avoid possible store
 * forwarding stalls and unnecessary copy of skb.
 */

 new_buff->dma  = old_buff->dma;
 new_buff->page  = old_buff->page;
 new_buff->page_offset = old_buff->page_offset;
 new_buff->pagecnt_bias = old_buff->pagecnt_bias;
}

static bool ixgbe_can_reuse_rx_page(struct ixgbe_rx_buffer *rx_buffer,
        int rx_buffer_pgcnt)
{
 unsigned int pagecnt_bias = rx_buffer->pagecnt_bias;
 struct page *page = rx_buffer->page;

 /* avoid re-using remote and pfmemalloc pages */
 if (!dev_page_is_reusable(page))
  return false;

#if (PAGE_SIZE < 8192)
 /* if we are only owner of page we can reuse it */
 if (unlikely((rx_buffer_pgcnt - pagecnt_bias) > 1))
  return false;
#else
 /* The last offset is a bit aggressive in that we assume the
 * worst case of FCoE being enabled and using a 3K buffer.
 * However this should have minimal impact as the 1K extra is
 * still less than one buffer in size.
 */

#define IXGBE_LAST_OFFSET \
 (SKB_WITH_OVERHEAD(PAGE_SIZE) - IXGBE_RXBUFFER_3K)
 if (rx_buffer->page_offset > IXGBE_LAST_OFFSET)
  return false;
#endif

 /* If we have drained the page fragment pool we need to update
 * the pagecnt_bias and page count so that we fully restock the
 * number of references the driver holds.
 */

 if (unlikely(pagecnt_bias == 1)) {
  page_ref_add(page, USHRT_MAX - 1);
  rx_buffer->pagecnt_bias = USHRT_MAX;
 }

 return true;
}

/**
 * ixgbe_add_rx_frag - Add contents of Rx buffer to sk_buff
 * @rx_ring: rx descriptor ring to transact packets on
 * @rx_buffer: buffer containing page to add
 * @skb: sk_buff to place the data into
 * @size: size of data in rx_buffer
 *
 * This function will add the data contained in rx_buffer->page to the skb.
 * This is done either through a direct copy if the data in the buffer is
 * less than the skb header size, otherwise it will just attach the page as
 * a frag to the skb.
 *
 * The function will then update the page offset if necessary and return
 * true if the buffer can be reused by the adapter.
 **/

static void ixgbe_add_rx_frag(struct ixgbe_ring *rx_ring,
         struct ixgbe_rx_buffer *rx_buffer,
         struct sk_buff *skb,
         unsigned int size)
{
#if (PAGE_SIZE < 8192)
 unsigned int truesize = ixgbe_rx_pg_size(rx_ring) / 2;
#else
 unsigned int truesize = rx_ring->rx_offset ?
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=94 H=90 G=91

¤ Dauer der Verarbeitung: 0.42 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.