// SPDX-License-Identifier: GPL-2.0-or-later 
 | 
/* 
 | 
 * Network device driver for Cell Processor-Based Blade 
 | 
 * 
 | 
 * (C) Copyright IBM Corp. 2005 
 | 
 * 
 | 
 * Authors : Utz Bacher <utz.bacher@de.ibm.com> 
 | 
 *           Jens Osterkamp <Jens.Osterkamp@de.ibm.com> 
 | 
 */ 
 | 
  
 | 
#include <linux/netdevice.h> 
 | 
#include <linux/ethtool.h> 
 | 
#include <linux/pci.h> 
 | 
  
 | 
#include "spider_net.h" 
 | 
  
 | 
  
 | 
static struct { 
 | 
    const char str[ETH_GSTRING_LEN]; 
 | 
} ethtool_stats_keys[] = { 
 | 
    { "tx_packets" }, 
 | 
    { "tx_bytes" }, 
 | 
    { "rx_packets" }, 
 | 
    { "rx_bytes" }, 
 | 
    { "tx_errors" }, 
 | 
    { "tx_dropped" }, 
 | 
    { "rx_dropped" }, 
 | 
    { "rx_descriptor_error" }, 
 | 
    { "tx_timeouts" }, 
 | 
    { "alloc_rx_skb_error" }, 
 | 
    { "rx_iommu_map_error" }, 
 | 
    { "tx_iommu_map_error" }, 
 | 
    { "rx_desc_unk_state" }, 
 | 
}; 
 | 
  
 | 
static int 
 | 
spider_net_ethtool_get_link_ksettings(struct net_device *netdev, 
 | 
                      struct ethtool_link_ksettings *cmd) 
 | 
{ 
 | 
    struct spider_net_card *card; 
 | 
    card = netdev_priv(netdev); 
 | 
  
 | 
    ethtool_link_ksettings_zero_link_mode(cmd, supported); 
 | 
    ethtool_link_ksettings_add_link_mode(cmd, supported, 1000baseT_Full); 
 | 
    ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); 
 | 
  
 | 
    ethtool_link_ksettings_zero_link_mode(cmd, advertising); 
 | 
    ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full); 
 | 
    ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); 
 | 
  
 | 
    cmd->base.port = PORT_FIBRE; 
 | 
    cmd->base.speed = card->phy.speed; 
 | 
    cmd->base.duplex = DUPLEX_FULL; 
 | 
  
 | 
    return 0; 
 | 
} 
 | 
  
 | 
static void 
 | 
spider_net_ethtool_get_drvinfo(struct net_device *netdev, 
 | 
                   struct ethtool_drvinfo *drvinfo) 
 | 
{ 
 | 
    struct spider_net_card *card; 
 | 
    card = netdev_priv(netdev); 
 | 
  
 | 
    /* clear and fill out info */ 
 | 
    strlcpy(drvinfo->driver, spider_net_driver_name, 
 | 
        sizeof(drvinfo->driver)); 
 | 
    strlcpy(drvinfo->version, VERSION, sizeof(drvinfo->version)); 
 | 
    strlcpy(drvinfo->fw_version, "no information", 
 | 
        sizeof(drvinfo->fw_version)); 
 | 
    strlcpy(drvinfo->bus_info, pci_name(card->pdev), 
 | 
        sizeof(drvinfo->bus_info)); 
 | 
} 
 | 
  
 | 
static void 
 | 
spider_net_ethtool_get_wol(struct net_device *netdev, 
 | 
               struct ethtool_wolinfo *wolinfo) 
 | 
{ 
 | 
    /* no support for wol */ 
 | 
    wolinfo->supported = 0; 
 | 
    wolinfo->wolopts = 0; 
 | 
} 
 | 
  
 | 
static u32 
 | 
spider_net_ethtool_get_msglevel(struct net_device *netdev) 
 | 
{ 
 | 
    struct spider_net_card *card; 
 | 
    card = netdev_priv(netdev); 
 | 
    return card->msg_enable; 
 | 
} 
 | 
  
 | 
static void 
 | 
spider_net_ethtool_set_msglevel(struct net_device *netdev, 
 | 
                u32 level) 
 | 
{ 
 | 
    struct spider_net_card *card; 
 | 
    card = netdev_priv(netdev); 
 | 
    card->msg_enable = level; 
 | 
} 
 | 
  
 | 
static int 
 | 
spider_net_ethtool_nway_reset(struct net_device *netdev) 
 | 
{ 
 | 
    if (netif_running(netdev)) { 
 | 
        spider_net_stop(netdev); 
 | 
        spider_net_open(netdev); 
 | 
    } 
 | 
    return 0; 
 | 
} 
 | 
  
 | 
static void 
 | 
spider_net_ethtool_get_ringparam(struct net_device *netdev, 
 | 
                 struct ethtool_ringparam *ering) 
 | 
{ 
 | 
    struct spider_net_card *card = netdev_priv(netdev); 
 | 
  
 | 
    ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX; 
 | 
    ering->tx_pending = card->tx_chain.num_desc; 
 | 
    ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX; 
 | 
    ering->rx_pending = card->rx_chain.num_desc; 
 | 
} 
 | 
  
 | 
static int spider_net_get_sset_count(struct net_device *netdev, int sset) 
 | 
{ 
 | 
    switch (sset) { 
 | 
    case ETH_SS_STATS: 
 | 
        return ARRAY_SIZE(ethtool_stats_keys); 
 | 
    default: 
 | 
        return -EOPNOTSUPP; 
 | 
    } 
 | 
} 
 | 
  
 | 
static void spider_net_get_ethtool_stats(struct net_device *netdev, 
 | 
        struct ethtool_stats *stats, u64 *data) 
 | 
{ 
 | 
    struct spider_net_card *card = netdev_priv(netdev); 
 | 
  
 | 
    data[0] = netdev->stats.tx_packets; 
 | 
    data[1] = netdev->stats.tx_bytes; 
 | 
    data[2] = netdev->stats.rx_packets; 
 | 
    data[3] = netdev->stats.rx_bytes; 
 | 
    data[4] = netdev->stats.tx_errors; 
 | 
    data[5] = netdev->stats.tx_dropped; 
 | 
    data[6] = netdev->stats.rx_dropped; 
 | 
    data[7] = card->spider_stats.rx_desc_error; 
 | 
    data[8] = card->spider_stats.tx_timeouts; 
 | 
    data[9] = card->spider_stats.alloc_rx_skb_error; 
 | 
    data[10] = card->spider_stats.rx_iommu_map_error; 
 | 
    data[11] = card->spider_stats.tx_iommu_map_error; 
 | 
    data[12] = card->spider_stats.rx_desc_unk_state; 
 | 
} 
 | 
  
 | 
static void spider_net_get_strings(struct net_device *netdev, u32 stringset, 
 | 
                   u8 *data) 
 | 
{ 
 | 
    memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys)); 
 | 
} 
 | 
  
 | 
const struct ethtool_ops spider_net_ethtool_ops = { 
 | 
    .get_drvinfo        = spider_net_ethtool_get_drvinfo, 
 | 
    .get_wol        = spider_net_ethtool_get_wol, 
 | 
    .get_msglevel        = spider_net_ethtool_get_msglevel, 
 | 
    .set_msglevel        = spider_net_ethtool_set_msglevel, 
 | 
    .get_link        = ethtool_op_get_link, 
 | 
    .nway_reset        = spider_net_ethtool_nway_reset, 
 | 
    .get_ringparam          = spider_net_ethtool_get_ringparam, 
 | 
    .get_strings        = spider_net_get_strings, 
 | 
    .get_sset_count        = spider_net_get_sset_count, 
 | 
    .get_ethtool_stats    = spider_net_get_ethtool_stats, 
 | 
    .get_link_ksettings    = spider_net_ethtool_get_link_ksettings, 
 | 
}; 
 |