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

Quelle  sxgbe_ethtool.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/* 10G controller driver for Samsung SoCs
 *
 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
 * http://www.samsung.com
 *
 * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/net_tstamp.h>
#include <linux/phy.h>
#include <linux/ptp_clock_kernel.h>

#include "sxgbe_common.h"
#include "sxgbe_reg.h"
#include "sxgbe_dma.h"

struct sxgbe_stats {
 char stat_string[ETH_GSTRING_LEN];
 int sizeof_stat;
 int stat_offset;
};

#define SXGBE_STAT(m)      \
{        \
 #m,       \
 sizeof_field(struct sxgbe_extra_stats, m),  \
 offsetof(struct sxgbe_priv_data, xstats.m)  \
}

static const struct sxgbe_stats sxgbe_gstrings_stats[] = {
 /* TX/RX IRQ events */
 SXGBE_STAT(tx_process_stopped_irq),
 SXGBE_STAT(tx_ctxt_desc_err),
 SXGBE_STAT(tx_threshold),
 SXGBE_STAT(rx_threshold),
 SXGBE_STAT(tx_pkt_n),
 SXGBE_STAT(rx_pkt_n),
 SXGBE_STAT(normal_irq_n),
 SXGBE_STAT(tx_normal_irq_n),
 SXGBE_STAT(rx_normal_irq_n),
 SXGBE_STAT(napi_poll),
 SXGBE_STAT(tx_clean),
 SXGBE_STAT(tx_reset_ic_bit),
 SXGBE_STAT(rx_process_stopped_irq),
 SXGBE_STAT(rx_underflow_irq),

 /* Bus access errors */
 SXGBE_STAT(fatal_bus_error_irq),
 SXGBE_STAT(tx_read_transfer_err),
 SXGBE_STAT(tx_write_transfer_err),
 SXGBE_STAT(tx_desc_access_err),
 SXGBE_STAT(tx_buffer_access_err),
 SXGBE_STAT(tx_data_transfer_err),
 SXGBE_STAT(rx_read_transfer_err),
 SXGBE_STAT(rx_write_transfer_err),
 SXGBE_STAT(rx_desc_access_err),
 SXGBE_STAT(rx_buffer_access_err),
 SXGBE_STAT(rx_data_transfer_err),

 /* EEE-LPI stats */
 SXGBE_STAT(tx_lpi_entry_n),
 SXGBE_STAT(tx_lpi_exit_n),
 SXGBE_STAT(rx_lpi_entry_n),
 SXGBE_STAT(rx_lpi_exit_n),
 SXGBE_STAT(eee_wakeup_error_n),

 /* RX specific */
 /* L2 error */
 SXGBE_STAT(rx_code_gmii_err),
 SXGBE_STAT(rx_watchdog_err),
 SXGBE_STAT(rx_crc_err),
 SXGBE_STAT(rx_gaint_pkt_err),
 SXGBE_STAT(ip_hdr_err),
 SXGBE_STAT(ip_payload_err),
 SXGBE_STAT(overflow_error),

 /* L2 Pkt type */
 SXGBE_STAT(len_pkt),
 SXGBE_STAT(mac_ctl_pkt),
 SXGBE_STAT(dcb_ctl_pkt),
 SXGBE_STAT(arp_pkt),
 SXGBE_STAT(oam_pkt),
 SXGBE_STAT(untag_okt),
 SXGBE_STAT(other_pkt),
 SXGBE_STAT(svlan_tag_pkt),
 SXGBE_STAT(cvlan_tag_pkt),
 SXGBE_STAT(dvlan_ocvlan_icvlan_pkt),
 SXGBE_STAT(dvlan_osvlan_isvlan_pkt),
 SXGBE_STAT(dvlan_osvlan_icvlan_pkt),
 SXGBE_STAT(dvan_ocvlan_icvlan_pkt),

 /* L3/L4 Pkt type */
 SXGBE_STAT(not_ip_pkt),
 SXGBE_STAT(ip4_tcp_pkt),
 SXGBE_STAT(ip4_udp_pkt),
 SXGBE_STAT(ip4_icmp_pkt),
 SXGBE_STAT(ip4_unknown_pkt),
 SXGBE_STAT(ip6_tcp_pkt),
 SXGBE_STAT(ip6_udp_pkt),
 SXGBE_STAT(ip6_icmp_pkt),
 SXGBE_STAT(ip6_unknown_pkt),

 /* Filter specific */
 SXGBE_STAT(vlan_filter_match),
 SXGBE_STAT(sa_filter_fail),
 SXGBE_STAT(da_filter_fail),
 SXGBE_STAT(hash_filter_pass),
 SXGBE_STAT(l3_filter_match),
 SXGBE_STAT(l4_filter_match),

 /* RX context specific */
 SXGBE_STAT(timestamp_dropped),
 SXGBE_STAT(rx_msg_type_no_ptp),
 SXGBE_STAT(rx_ptp_type_sync),
 SXGBE_STAT(rx_ptp_type_follow_up),
 SXGBE_STAT(rx_ptp_type_delay_req),
 SXGBE_STAT(rx_ptp_type_delay_resp),
 SXGBE_STAT(rx_ptp_type_pdelay_req),
 SXGBE_STAT(rx_ptp_type_pdelay_resp),
 SXGBE_STAT(rx_ptp_type_pdelay_follow_up),
 SXGBE_STAT(rx_ptp_announce),
 SXGBE_STAT(rx_ptp_mgmt),
 SXGBE_STAT(rx_ptp_signal),
 SXGBE_STAT(rx_ptp_resv_msg_type),
};
#define SXGBE_STATS_LEN ARRAY_SIZE(sxgbe_gstrings_stats)

static int sxgbe_get_eee(struct net_device *dev,
    struct ethtool_keee *edata)
{
 struct sxgbe_priv_data *priv = netdev_priv(dev);

 if (!priv->hw_cap.eee)
  return -EOPNOTSUPP;

 edata->tx_lpi_timer = priv->tx_lpi_timer;

 return phy_ethtool_get_eee(dev->phydev, edata);
}

static int sxgbe_set_eee(struct net_device *dev,
    struct ethtool_keee *edata)
{
 struct sxgbe_priv_data *priv = netdev_priv(dev);

 priv->eee_enabled = edata->eee_enabled;

 if (!priv->eee_enabled) {
  sxgbe_disable_eee_mode(priv);
 } else {
  /* We are asking for enabling the EEE but it is safe
 * to verify all by invoking the eee_init function.
 * In case of failure it will return an error.
 */

  priv->eee_enabled = sxgbe_eee_init(priv);
  if (!priv->eee_enabled)
   return -EOPNOTSUPP;

  /* Do not change tx_lpi_timer in case of failure */
  priv->tx_lpi_timer = edata->tx_lpi_timer;
 }

 return phy_ethtool_set_eee(dev->phydev, edata);
}

static void sxgbe_getdrvinfo(struct net_device *dev,
        struct ethtool_drvinfo *info)
{
 strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
 strscpy(info->version, DRV_VERSION, sizeof(info->version));
}

static u32 sxgbe_getmsglevel(struct net_device *dev)
{
 struct sxgbe_priv_data *priv = netdev_priv(dev);
 return priv->msg_enable;
}

static void sxgbe_setmsglevel(struct net_device *dev, u32 level)
{
 struct sxgbe_priv_data *priv = netdev_priv(dev);
 priv->msg_enable = level;
}

static void sxgbe_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
 int i;
 u8 *p = data;

 switch (stringset) {
 case ETH_SS_STATS:
  for (i = 0; i < SXGBE_STATS_LEN; i++) {
   memcpy(p, sxgbe_gstrings_stats[i].stat_string,
          ETH_GSTRING_LEN);
   p += ETH_GSTRING_LEN;
  }
  break;
 default:
  WARN_ON(1);
  break;
 }
}

static int sxgbe_get_sset_count(struct net_device *netdev, int sset)
{
 int len;

 switch (sset) {
 case ETH_SS_STATS:
  len = SXGBE_STATS_LEN;
  return len;
 default:
  return -EINVAL;
 }
}

static void sxgbe_get_ethtool_stats(struct net_device *dev,
        struct ethtool_stats *dummy, u64 *data)
{
 struct sxgbe_priv_data *priv = netdev_priv(dev);
 int i;
 char *p;

 if (priv->eee_enabled) {
  int val = phy_get_eee_err(dev->phydev);

  if (val)
   priv->xstats.eee_wakeup_error_n = val;
 }

 for (i = 0; i < SXGBE_STATS_LEN; i++) {
  p = (char *)priv + sxgbe_gstrings_stats[i].stat_offset;
  data[i] = (sxgbe_gstrings_stats[i].sizeof_stat == sizeof(u64))
   ? (*(u64 *)p) : (*(u32 *)p);
 }
}

static void sxgbe_get_channels(struct net_device *dev,
          struct ethtool_channels *channel)
{
 channel->max_rx = SXGBE_MAX_RX_CHANNELS;
 channel->max_tx = SXGBE_MAX_TX_CHANNELS;
 channel->rx_count = SXGBE_RX_QUEUES;
 channel->tx_count = SXGBE_TX_QUEUES;
}

static u32 sxgbe_riwt2usec(u32 riwt, struct sxgbe_priv_data *priv)
{
 unsigned long clk = clk_get_rate(priv->sxgbe_clk);

 if (!clk)
  return 0;

 return (riwt * 256) / (clk / 1000000);
}

static u32 sxgbe_usec2riwt(u32 usec, struct sxgbe_priv_data *priv)
{
 unsigned long clk = clk_get_rate(priv->sxgbe_clk);

 if (!clk)
  return 0;

 return (usec * (clk / 1000000)) / 256;
}

static int sxgbe_get_coalesce(struct net_device *dev,
         struct ethtool_coalesce *ec,
         struct kernel_ethtool_coalesce *kernel_coal,
         struct netlink_ext_ack *extack)
{
 struct sxgbe_priv_data *priv = netdev_priv(dev);

 if (priv->use_riwt)
  ec->rx_coalesce_usecs = sxgbe_riwt2usec(priv->rx_riwt, priv);

 return 0;
}

static int sxgbe_set_coalesce(struct net_device *dev,
         struct ethtool_coalesce *ec,
         struct kernel_ethtool_coalesce *kernel_coal,
         struct netlink_ext_ack *extack)
{
 struct sxgbe_priv_data *priv = netdev_priv(dev);
 unsigned int rx_riwt;

 if (!ec->rx_coalesce_usecs)
  return -EINVAL;

 rx_riwt = sxgbe_usec2riwt(ec->rx_coalesce_usecs, priv);

 if ((rx_riwt > SXGBE_MAX_DMA_RIWT) || (rx_riwt < SXGBE_MIN_DMA_RIWT))
  return -EINVAL;
 else if (!priv->use_riwt)
  return -EOPNOTSUPP;

 priv->rx_riwt = rx_riwt;
 priv->hw->dma->rx_watchdog(priv->ioaddr, priv->rx_riwt);

 return 0;
}

static int sxgbe_get_rxfh_fields(struct net_device *dev,
     struct ethtool_rxfh_fields *cmd)
{
 cmd->data = 0;

 /* Report default options for RSS on sxgbe */
 switch (cmd->flow_type) {
 case TCP_V4_FLOW:
 case UDP_V4_FLOW:
  cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
  fallthrough;
 case SCTP_V4_FLOW:
 case AH_ESP_V4_FLOW:
 case AH_V4_FLOW:
 case ESP_V4_FLOW:
 case IPV4_FLOW:
  cmd->data |= RXH_IP_SRC | RXH_IP_DST;
  break;
 case TCP_V6_FLOW:
 case UDP_V6_FLOW:
  cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
  fallthrough;
 case SCTP_V6_FLOW:
 case AH_ESP_V6_FLOW:
 case AH_V6_FLOW:
 case ESP_V6_FLOW:
 case IPV6_FLOW:
  cmd->data |= RXH_IP_SRC | RXH_IP_DST;
  break;
 default:
  return -EINVAL;
 }

 return 0;
}

static int sxgbe_set_rxfh_fields(struct net_device *dev,
     const struct ethtool_rxfh_fields *cmd,
     struct netlink_ext_ack *extack)
{
 struct sxgbe_priv_data *priv = netdev_priv(dev);
 u32 reg_val = 0;

 /* RSS does not support anything other than hashing
 * to queues on src and dst IPs and ports
 */

 if (cmd->data & ~(RXH_IP_SRC | RXH_IP_DST |
     RXH_L4_B_0_1 | RXH_L4_B_2_3))
  return -EINVAL;

 switch (cmd->flow_type) {
 case TCP_V4_FLOW:
 case TCP_V6_FLOW:
  if (!(cmd->data & RXH_IP_SRC) ||
      !(cmd->data & RXH_IP_DST) ||
      !(cmd->data & RXH_L4_B_0_1) ||
      !(cmd->data & RXH_L4_B_2_3))
   return -EINVAL;
  reg_val = SXGBE_CORE_RSS_CTL_TCP4TE;
  break;
 case UDP_V4_FLOW:
 case UDP_V6_FLOW:
  if (!(cmd->data & RXH_IP_SRC) ||
      !(cmd->data & RXH_IP_DST) ||
      !(cmd->data & RXH_L4_B_0_1) ||
      !(cmd->data & RXH_L4_B_2_3))
   return -EINVAL;
  reg_val = SXGBE_CORE_RSS_CTL_UDP4TE;
  break;
 case SCTP_V4_FLOW:
 case AH_ESP_V4_FLOW:
 case AH_V4_FLOW:
 case ESP_V4_FLOW:
 case AH_ESP_V6_FLOW:
 case AH_V6_FLOW:
 case ESP_V6_FLOW:
 case SCTP_V6_FLOW:
 case IPV4_FLOW:
 case IPV6_FLOW:
  if (!(cmd->data & RXH_IP_SRC) ||
      !(cmd->data & RXH_IP_DST) ||
      (cmd->data & RXH_L4_B_0_1) ||
      (cmd->data & RXH_L4_B_2_3))
   return -EINVAL;
  reg_val = SXGBE_CORE_RSS_CTL_IP2TE;
  break;
 default:
  return -EINVAL;
 }

 /* Read SXGBE RSS control register and update */
 reg_val |= readl(priv->ioaddr + SXGBE_CORE_RSS_CTL_REG);
 writel(reg_val, priv->ioaddr + SXGBE_CORE_RSS_CTL_REG);
 readl(priv->ioaddr + SXGBE_CORE_RSS_CTL_REG);

 return 0;
}

static void sxgbe_get_regs(struct net_device *dev,
      struct ethtool_regs *regs, void *space)
{
 struct sxgbe_priv_data *priv = netdev_priv(dev);
 u32 *reg_space = (u32 *)space;
 int reg_offset;
 int reg_ix = 0;
 void __iomem *ioaddr = priv->ioaddr;

 memset(reg_space, 0x0, REG_SPACE_SIZE);

 /* MAC registers */
 for (reg_offset = START_MAC_REG_OFFSET;
      reg_offset <= MAX_MAC_REG_OFFSET; reg_offset += 4) {
  reg_space[reg_ix] = readl(ioaddr + reg_offset);
  reg_ix++;
 }

 /* MTL registers */
 for (reg_offset = START_MTL_REG_OFFSET;
      reg_offset <= MAX_MTL_REG_OFFSET; reg_offset += 4) {
  reg_space[reg_ix] = readl(ioaddr + reg_offset);
  reg_ix++;
 }

 /* DMA registers */
 for (reg_offset = START_DMA_REG_OFFSET;
      reg_offset <= MAX_DMA_REG_OFFSET; reg_offset += 4) {
  reg_space[reg_ix] = readl(ioaddr + reg_offset);
  reg_ix++;
 }

 BUG_ON(reg_ix * 4 > REG_SPACE_SIZE);
}

static int sxgbe_get_regs_len(struct net_device *dev)
{
 return REG_SPACE_SIZE;
}

static const struct ethtool_ops sxgbe_ethtool_ops = {
 .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS,
 .get_drvinfo = sxgbe_getdrvinfo,
 .get_msglevel = sxgbe_getmsglevel,
 .set_msglevel = sxgbe_setmsglevel,
 .get_link = ethtool_op_get_link,
 .get_strings = sxgbe_get_strings,
 .get_ethtool_stats = sxgbe_get_ethtool_stats,
 .get_sset_count = sxgbe_get_sset_count,
 .get_channels = sxgbe_get_channels,
 .get_coalesce = sxgbe_get_coalesce,
 .set_coalesce = sxgbe_set_coalesce,
 .get_rxfh_fields = sxgbe_get_rxfh_fields,
 .set_rxfh_fields = sxgbe_set_rxfh_fields,
 .get_regs = sxgbe_get_regs,
 .get_regs_len = sxgbe_get_regs_len,
 .get_eee = sxgbe_get_eee,
 .set_eee = sxgbe_set_eee,
 .get_link_ksettings = phy_ethtool_get_link_ksettings,
 .set_link_ksettings = phy_ethtool_set_link_ksettings,
};

void sxgbe_set_ethtool_ops(struct net_device *netdev)
{
 netdev->ethtool_ops = &sxgbe_ethtool_ops;
}

Messung V0.5
C=97 H=95 G=95

¤ Dauer der Verarbeitung: 0.16 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.