diff options
Diffstat (limited to 'drivers/staging/sxg/sxg_ethtool.c')
-rw-r--r-- | drivers/staging/sxg/sxg_ethtool.c | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/drivers/staging/sxg/sxg_ethtool.c b/drivers/staging/sxg/sxg_ethtool.c new file mode 100644 index 00000000000..97f765d1250 --- /dev/null +++ b/drivers/staging/sxg/sxg_ethtool.c @@ -0,0 +1,328 @@ +/************************************************************************** + * + * Copyright (C) 2000-2008 Alacritech, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY ALACRITECH, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ALACRITECH, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies, either expressed or implied, of Alacritech, Inc. + * + **************************************************************************/ + +/* + * FILENAME: sxg_ethtool.c + * + * The ethtool support for SXG driver for Alacritech's 10Gbe products. + * + * NOTE: This is the standard, non-accelerated version of Alacritech's + * IS-NIC driver. + */ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/skbuff.h> +#include <linux/pci.h> + +#include "sxg_os.h" +#include "sxghw.h" +#include "sxghif.h" +#include "sxg.h" + +struct sxg_nic_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define SXG_NIC_STATS(m) sizeof(((struct adapter_t *)0)->m), \ + offsetof(struct adapter_t, m) + +#define USER_VIEWABLE_EEPROM_SIZE 28 + +static struct sxg_nic_stats sxg_nic_gstrings_stats[] = { + {"xmit_ring_0_full", SXG_NIC_STATS(Stats.XmtZeroFull)}, + + /* May be will need in future */ +/* {"dumb_xmit_broadcast_packets", SXG_NIC_STATS(Stats.DumbXmtBcastPkts)}, + {"dumb_xmit_broadcast_bytes", SXG_NIC_STATS(Stats.DumbXmtBcastBytes)}, + {"dumb_xmit_unicast_packets", SXG_NIC_STATS(Stats.DumbXmtUcastPkts)}, + {"dumb_xmit_unicast_bytes", SXG_NIC_STATS(Stats.DumbXmtUcastBytes)}, +*/ + {"xmit_queue_length", SXG_NIC_STATS(Stats.XmtQLen)}, + {"memory_allocation_failure", SXG_NIC_STATS(Stats.NoMem)}, + {"Interrupts", SXG_NIC_STATS(Stats.NumInts)}, + {"false_interrupts", SXG_NIC_STATS(Stats.FalseInts)}, + {"processed_data_queue_full", SXG_NIC_STATS(Stats.PdqFull)}, + {"event_ring_full", SXG_NIC_STATS(Stats.EventRingFull)}, + {"transport_checksum_error", SXG_NIC_STATS(Stats.TransportCsum)}, + {"transport_underflow_error", SXG_NIC_STATS(Stats.TransportUflow)}, + {"transport_header_length_error", SXG_NIC_STATS(Stats.TransportHdrLen)}, + {"network_checksum_error", SXG_NIC_STATS(Stats.NetworkCsum)}, + {"network_underflow_error", SXG_NIC_STATS(Stats.NetworkUflow)}, + {"network_header_length_error", SXG_NIC_STATS(Stats.NetworkHdrLen)}, + {"receive_parity_error", SXG_NIC_STATS(Stats.Parity)}, + {"link_parity_error", SXG_NIC_STATS(Stats.LinkParity)}, + {"link/data early_error", SXG_NIC_STATS(Stats.LinkEarly)}, + {"buffer_overflow_error", SXG_NIC_STATS(Stats.LinkBufOflow)}, + {"link_code_error", SXG_NIC_STATS(Stats.LinkCode)}, + {"dribble nibble", SXG_NIC_STATS(Stats.LinkDribble)}, + {"CRC_error", SXG_NIC_STATS(Stats.LinkCrc)}, + {"link_overflow_error", SXG_NIC_STATS(Stats.LinkOflow)}, + {"link_underflow_error", SXG_NIC_STATS(Stats.LinkUflow)}, + + /* May be need in future */ +/* {"dumb_rcv_broadcast_packets", SXG_NIC_STATS(Stats.DumbRcvBcastPkts)}, + {"dumb_rcv_broadcast_bytes", SXG_NIC_STATS(Stats.DumbRcvBcastBytes)}, +*/ {"dumb_rcv_multicast_packets", SXG_NIC_STATS(Stats.DumbRcvMcastPkts)}, + {"dumb_rcv_multicast_bytes", SXG_NIC_STATS(Stats.DumbRcvMcastBytes)}, +/* {"dumb_rcv_unicast_packets", SXG_NIC_STATS(Stats.DumbRcvUcastPkts)}, + {"dumb_rcv_unicast_bytes", SXG_NIC_STATS(Stats.DumbRcvUcastBytes)}, +*/ + {"no_sgl_buffer", SXG_NIC_STATS(Stats.NoSglBuf)}, +}; + +#define SXG_NIC_STATS_LEN ARRAY_SIZE(sxg_nic_gstrings_stats) + +static inline void sxg_reg32_write(void __iomem *reg, u32 value, bool flush) +{ + writel(value, reg); + if (flush) + mb(); +} + +static inline void sxg_reg64_write(struct adapter_t *adapter, void __iomem *reg, + u64 value, u32 cpu) +{ + u32 value_high = (u32) (value >> 32); + u32 value_low = (u32) (value & 0x00000000FFFFFFFF); + unsigned long flags; + + spin_lock_irqsave(&adapter->Bit64RegLock, flags); + writel(value_high, (void __iomem *)(&adapter->UcodeRegs[cpu].Upper)); + writel(value_low, reg); + spin_unlock_irqrestore(&adapter->Bit64RegLock, flags); +} + +static void +sxg_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) +{ + struct adapter_t *adapter = netdev_priv(dev); + strncpy(drvinfo->driver, sxg_driver_name, 32); + strncpy(drvinfo->version, SXG_DRV_VERSION, 32); +// strncpy(drvinfo->fw_version, SAHARA_UCODE_VERS_STRING, 32); + strncpy(drvinfo->bus_info, pci_name(adapter->pcidev), 32); + /* TODO : Read the major and minor number of firmware. Is this + * from the FLASH/EEPROM or download file ? + */ + /* LINSYS : Check if this is correct or if not find the right value + * Also check what is the right EEPROM length : EEPROM_SIZE_XFMR or EEPROM_SIZE_NO_XFMR + */ +} + +static int sxg_nic_set_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + /* No settings are applicable as we support only 10Gb/FIBRE_media */ + return -EOPNOTSUPP; +} + +static void +sxg_nic_get_strings(struct net_device *netdev, u32 stringset, u8 * data) +{ + int index; + + switch(stringset) { + case ETH_SS_TEST: + break; + case ETH_SS_STATS: + for (index = 0; index < SXG_NIC_STATS_LEN; index++) { + memcpy(data + index * ETH_GSTRING_LEN, + sxg_nic_gstrings_stats[index].stat_string, + ETH_GSTRING_LEN); + } + break; + } +} + +static void +sxg_nic_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 * data) +{ + struct adapter_t *adapter = netdev_priv(netdev); + int index; + for (index = 0; index < SXG_NIC_STATS_LEN; index++) { + char *p = (char *)adapter + + sxg_nic_gstrings_stats[index].stat_offset; + data[index] = (sxg_nic_gstrings_stats[index].sizeof_stat == + sizeof(u64)) ? *(u64 *) p : *(u32 *) p; + } +} + +static int sxg_nic_get_sset_count(struct net_device *netdev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return SXG_NIC_STATS_LEN; + default: + return -EOPNOTSUPP; + } +} + +static int sxg_nic_get_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct adapter_t *adapter = netdev_priv(netdev); + + ecmd->supported = SUPPORTED_10000baseT_Full; + ecmd->autoneg = AUTONEG_ENABLE; //VSS check This + ecmd->transceiver = XCVR_EXTERNAL; //VSS check This + + /* For Fibre Channel */ + ecmd->supported |= SUPPORTED_FIBRE; + ecmd->advertising = (ADVERTISED_10000baseT_Full | + ADVERTISED_FIBRE); + ecmd->port = PORT_FIBRE; + + + /* Link Speed */ + if(adapter->LinkState & SXG_LINK_UP) { + ecmd->speed = SPEED_10000; //adapter->LinkSpeed; + ecmd->duplex = DUPLEX_FULL; + } + return 0; +} + +static u32 sxg_nic_get_rx_csum(struct net_device *netdev) +{ + struct adapter_t *adapter = netdev_priv(netdev); + return ((adapter->flags & SXG_RCV_IP_CSUM_ENABLED) && + (adapter->flags & SXG_RCV_TCP_CSUM_ENABLED)); +} + +static int sxg_nic_set_rx_csum(struct net_device *netdev, u32 data) +{ + struct adapter_t *adapter = netdev_priv(netdev); + if (data) + adapter->flags |= SXG_RCV_IP_CSUM_ENABLED; + else + adapter->flags &= ~SXG_RCV_IP_CSUM_ENABLED; + /* + * We dont need to write to the card to do checksums. + * It does it anyways. + */ + return 0; +} + +static int sxg_nic_get_regs_len(struct net_device *dev) +{ + return (SXG_HWREG_MEMSIZE + SXG_UCODEREG_MEMSIZE); +} + +static void sxg_nic_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *p) +{ + struct adapter_t *adapter = netdev_priv(netdev); + struct sxg_hw_regs *HwRegs = adapter->HwRegs; + struct sxg_ucode_regs *UcodeRegs = adapter->UcodeRegs; + u32 *buff = p; + + memset(p, 0, (sizeof(struct sxg_hw_regs)+sizeof(struct sxg_ucode_regs))); + memcpy(buff, HwRegs, sizeof(struct sxg_hw_regs)); + memcpy((buff+sizeof(struct sxg_hw_regs)), UcodeRegs, sizeof(struct sxg_ucode_regs)); +} + +static int sxg_nic_get_eeprom_len(struct net_device *netdev) +{ + return (USER_VIEWABLE_EEPROM_SIZE); +} + +static int sxg_nic_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct adapter_t *adapter = netdev_priv(netdev); + struct sw_cfg_data *data; + unsigned long i, status; + dma_addr_t p_addr; + + data = pci_alloc_consistent(adapter->pcidev, sizeof(struct sw_cfg_data), + &p_addr); + if(!data) { + /* + * We cant get even this much memory. Raise a hell + * Get out of here + */ + printk(KERN_ERR"%s : Could not allocate memory for reading \ + EEPROM\n", __FUNCTION__); + return -ENOMEM; + } + + WRITE_REG(adapter->UcodeRegs[0].ConfigStat, SXG_CFG_TIMEOUT, TRUE); + WRITE_REG64(adapter, adapter->UcodeRegs[0].Config, p_addr, 0); + for(i=0; i<1000; i++) { + READ_REG(adapter->UcodeRegs[0].ConfigStat, status); + if (status != SXG_CFG_TIMEOUT) + break; + mdelay(1); /* Do we really need this */ + } + + memset(bytes, 0, eeprom->len); + memcpy(bytes, data->MacAddr[0].MacAddr, sizeof(struct sxg_config_mac)); + memcpy(bytes+6, data->AtkFru.PartNum, 6); + memcpy(bytes+12, data->AtkFru.Revision, 2); + memcpy(bytes+14, data->AtkFru.Serial, 14); + + return 0; +} + +struct ethtool_ops sxg_nic_ethtool_ops = { + .get_settings = sxg_nic_get_settings, + .set_settings = sxg_nic_set_settings, + .get_drvinfo = sxg_nic_get_drvinfo, + .get_regs_len = sxg_nic_get_regs_len, + .get_regs = sxg_nic_get_regs, + .get_link = ethtool_op_get_link, +// .get_wol = sxg_nic_get_wol, + .get_eeprom_len = sxg_nic_get_eeprom_len, + .get_eeprom = sxg_nic_get_eeprom, +// .get_pauseparam = sxg_nic_get_pauseparam, +// .set_pauseparam = sxg_nic_set_pauseparam, + .set_tx_csum = ethtool_op_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, +// .get_tso = sxg_nic_get_tso, +// .set_tso = sxg_nic_set_tso, +// .self_test = sxg_nic_diag_test, + .get_strings = sxg_nic_get_strings, + .get_ethtool_stats = sxg_nic_get_ethtool_stats, + .get_sset_count = sxg_nic_get_sset_count, + .get_rx_csum = sxg_nic_get_rx_csum, + .set_rx_csum = sxg_nic_set_rx_csum, +// .get_coalesce = sxg_nic_get_intr_coalesce, +// .set_coalesce = sxg_nic_set_intr_coalesce, +}; |