Adding VIOC device driver. Ethtool interface. Signed-off-by: Misha Tomushev <[EMAIL PROTECTED]>
diff -uprN linux-2.6.17/drivers/net/vioc/vioc_ethtool.c linux-2.6.17.vioc/drivers/net/vioc/vioc_ethtool.c --- linux-2.6.17/drivers/net/vioc/vioc_ethtool.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.17.vioc/drivers/net/vioc/vioc_ethtool.c 2006-10-04 10:36:10.000000000 -0700 @@ -0,0 +1,309 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2005 Fabric7 Systems. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * http://www.fabric7.com/ + * + * Maintainers: + * [EMAIL PROTECTED] + * + * + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/compiler.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/ethtool.h> +#include <linux/mii.h> +#include <linux/if_vlan.h> +#include <linux/wait.h> +#include <linux/sched.h> +#include <linux/notifier.h> +#include <linux/errno.h> + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/byteorder.h> +#include <asm/uaccess.h> + +#include "f7/vnic_hw_registers.h" +#include "f7/vnic_defs.h" + +#include <linux/moduleparam.h> +#include "vioc_vnic.h" +#include "vioc_api.h" +#include "driver_version.h" + +/* ethtool support for vnic */ + +#ifdef SIOCETHTOOL +#include <asm/uaccess.h> + +#ifndef ETH_GSTRING_LEN +#define ETH_GSTRING_LEN 32 +#endif + +#ifdef ETHTOOL_OPS_COMPAT +#include "kcompat_ethtool.c" +#endif + +#define VIOC_READ_REG(R, M, V, viocdev) (\ + readl((viocdev->ba.virt + GETRELADDR(M, V, R)))) + +#define VIOC_WRITE_REG(R, M, V, viocdev, value) (\ + (writel(value, viocdev->ba.virt + GETRELADDR(M, V, R)))) + +#ifdef ETHTOOL_GSTATS +struct vnic_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define VNIC_STAT(m) sizeof(((struct vnic_device *)0)->m), \ + offsetof(struct vnic_device, m) + +static const struct vnic_stats vnic_gstrings_stats[] = { + {"rx_packets", VNIC_STAT(net_stats.rx_packets)}, + {"tx_packets", VNIC_STAT(net_stats.tx_packets)}, + {"rx_bytes", VNIC_STAT(net_stats.rx_bytes)}, + {"tx_bytes", VNIC_STAT(net_stats.tx_bytes)}, + {"rx_errors", VNIC_STAT(net_stats.rx_errors)}, + {"tx_errors", VNIC_STAT(net_stats.tx_errors)}, + {"rx_dropped", VNIC_STAT(net_stats.rx_dropped)}, + {"tx_dropped", VNIC_STAT(net_stats.tx_dropped)}, + {"multicast", VNIC_STAT(net_stats.multicast)}, + {"collisions", VNIC_STAT(net_stats.collisions)}, + {"rx_length_errors", VNIC_STAT(net_stats.rx_length_errors)}, + {"rx_over_errors", VNIC_STAT(net_stats.rx_over_errors)}, + {"rx_crc_errors", VNIC_STAT(net_stats.rx_crc_errors)}, + {"rx_frame_errors", VNIC_STAT(net_stats.rx_frame_errors)}, + {"rx_fifo_errors", VNIC_STAT(net_stats.rx_fifo_errors)}, + {"rx_missed_errors", VNIC_STAT(net_stats.rx_missed_errors)}, + {"tx_aborted_errors", VNIC_STAT(net_stats.tx_aborted_errors)}, + {"tx_carrier_errors", VNIC_STAT(net_stats.tx_carrier_errors)}, + {"tx_fifo_errors", VNIC_STAT(net_stats.tx_fifo_errors)}, + {"tx_heartbeat_errors", VNIC_STAT(net_stats.tx_heartbeat_errors)}, + {"tx_window_errors", VNIC_STAT(net_stats.tx_window_errors)}, + {"rx_fragment_errors", VNIC_STAT(vnic_stats.rx_fragment_errors)}, + {"rx_dropped", VNIC_STAT(vnic_stats.rx_dropped)}, + {"tx_skb_equeued", VNIC_STAT(vnic_stats.skb_enqueued)}, + {"tx_skb_freed", VNIC_STAT(vnic_stats.skb_freed)}, + {"netif_stops", VNIC_STAT(vnic_stats.netif_stops)}, + {"tx_on_empty_intr", VNIC_STAT(vnic_stats.tx_on_empty_interrupts)}, + {"tx_headroom_misses", VNIC_STAT(vnic_stats.headroom_misses)}, + {"tx_headroom_miss_drops", VNIC_STAT(vnic_stats.headroom_miss_drops)}, + {"tx_ring_size", VNIC_STAT(txq.count)}, + {"tx_ring_capacity", VNIC_STAT(txq.empty)}, + {"pkts_till_intr", VNIC_STAT(txq.tx_pkts_til_irq)}, + {"pkts_till_bell", VNIC_STAT(txq.tx_pkts_til_bell)}, + {"bells", VNIC_STAT(txq.bells)}, + {"next_to_use", VNIC_STAT(txq.next_to_use)}, + {"next_to_clean", VNIC_STAT(txq.next_to_clean)}, + {"tx_frags", VNIC_STAT(txq.frags)}, + {"tx_ring_wraps", VNIC_STAT(txq.wraps)}, + {"tx_ring_fulls", VNIC_STAT(txq.full)} +}; + +#define VNIC_STATS_LEN \ + sizeof(vnic_gstrings_stats) / sizeof(struct vnic_stats) +#endif /* ETHTOOL_GSTATS */ +#ifdef ETHTOOL_TEST +static const char vnic_gstrings_test[][ETH_GSTRING_LEN] = { + "Register test (offline)", "Eeprom test (offline)", + "Interrupt test (offline)", "Loopback test (offline)", + "Link test (on/offline)" +}; + +#define VNIC_TEST_LEN sizeof(vnic_gstrings_test) / ETH_GSTRING_LEN +#endif /* ETHTOOL_TEST */ + +static int vnic_get_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + ecmd->supported = SUPPORTED_1000baseT_Full; + ecmd->advertising = ADVERTISED_TP; + ecmd->port = PORT_TP; + ecmd->phy_address = 0; /* !!! Stole from e1000 */ + ecmd->transceiver = XCVR_INTERNAL; + ecmd->duplex = DUPLEX_FULL; + ecmd->speed = 3; /* !!! Stole from e1000 */ + ecmd->autoneg = 0; + return 0; +} + +int vioc_trace; + +static u32 vnic_get_msglevel(struct net_device *netdev) +{ + return vioc_trace; +} + +static void vnic_set_msglevel(struct net_device *netdev, u32 data) +{ + vioc_trace = (int)data; +} + +#define VNIC_REGS_CNT 12 +#define VNIC_REGS_LINE_LEN 80 +static int vnic_get_regs_len(struct net_device *netdev) +{ + return (VNIC_REGS_CNT * VNIC_REGS_LINE_LEN); +} + +static void vnic_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *p) +{ + struct vnic_device *vnicdev = netdev->priv; + struct vioc_device *viocdev = vnicdev->viocdev; + char *regs_buff = p; + + memset(regs_buff, 0, VNIC_REGS_CNT * VNIC_REGS_LINE_LEN); + + regs->version = 1; + + sprintf(regs_buff, "%08Lx = %08x\n", + GETRELADDR(VREG_BMC_GLOBAL, VIOC_BMC, 0), + VIOC_READ_REG(VREG_BMC_GLOBAL, VIOC_BMC, 0, viocdev)); + regs_buff += strlen(regs_buff); + + sprintf(regs_buff, "%08Lx = %08x\n", + GETRELADDR(VREG_BMC_DEBUG, VIOC_BMC, 0), + VIOC_READ_REG(VREG_BMC_DEBUG, VIOC_BMC, 0, viocdev)); + regs_buff += strlen(regs_buff); + + sprintf(regs_buff, "%08Lx = %08x\n", + GETRELADDR(VREG_BMC_DEBUGPRIV, VIOC_BMC, 0), + VIOC_READ_REG(VREG_BMC_DEBUGPRIV, VIOC_BMC, 0, viocdev)); + regs_buff += strlen(regs_buff); + + sprintf(regs_buff, "%08Lx = %08x\n", + GETRELADDR(VREG_BMC_FABRIC, VIOC_BMC, 0), + VIOC_READ_REG(VREG_BMC_FABRIC, VIOC_BMC, 0, viocdev)); + regs_buff += strlen(regs_buff); + + sprintf(regs_buff, "%08Lx = %08x\n", + GETRELADDR(VREG_BMC_VNIC_EN, VIOC_BMC, 0), + VIOC_READ_REG(VREG_BMC_VNIC_EN, VIOC_BMC, 0, viocdev)); + regs_buff += strlen(regs_buff); + + sprintf(regs_buff, "%08Lx = %08x\n", + GETRELADDR(VREG_BMC_PORT_EN, VIOC_BMC, 0), + VIOC_READ_REG(VREG_BMC_PORT_EN, VIOC_BMC, 0, viocdev)); + regs_buff += strlen(regs_buff); + + sprintf(regs_buff, "%08Lx = %08x\n", + GETRELADDR(VREG_BMC_VNIC_CFG, VIOC_BMC, 0), + VIOC_READ_REG(VREG_BMC_VNIC_CFG, VIOC_BMC, 0, viocdev)); + regs_buff += strlen(regs_buff); + + sprintf(regs_buff, "%08Lx = %08x\n", + GETRELADDR(VREG_IHCU_RXDQEN, VIOC_IHCU, 0), + VIOC_READ_REG(VREG_IHCU_RXDQEN, VIOC_IHCU, 0, viocdev)); + regs_buff += strlen(regs_buff); + + sprintf(regs_buff, "%08Lx = %08x\n", + GETRELADDR(VREG_VENG_VLANTAG, VIOC_VENG, vnicdev->vnic_id), + VIOC_READ_REG(VREG_VENG_VLANTAG, VIOC_VENG, vnicdev->vnic_id, + viocdev)); + regs_buff += strlen(regs_buff); + + sprintf(regs_buff, "%08Lx = %08x\n", + GETRELADDR(VREG_VENG_TXD_CTL, VIOC_VENG, vnicdev->vnic_id), + VIOC_READ_REG(VREG_VENG_TXD_CTL, VIOC_VENG, vnicdev->vnic_id, + viocdev)); + regs_buff += strlen(regs_buff); + +} + +static void vnic_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct vnic_device *vnicdev = netdev->priv; + struct vioc_device *viocdev = vnicdev->viocdev; + + sprintf(drvinfo->driver, VIOC_DRV_MODULE_NAME); + strncpy(drvinfo->version, VIOC_DISPLAY_VERSION, 32); + sprintf(drvinfo->fw_version, "%02X-%02X", viocdev->vioc_bits_version, + viocdev->vioc_bits_subversion); + strncpy(drvinfo->bus_info, pci_name(viocdev->pdev), 32); + drvinfo->n_stats = VNIC_STATS_LEN; + drvinfo->testinfo_len = VNIC_TEST_LEN; + drvinfo->regdump_len = vnic_get_regs_len(netdev); + drvinfo->eedump_len = 0; +} + +static int vnic_get_stats_count(struct net_device *netdev) +{ + return VNIC_STATS_LEN; +} + +static void vnic_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 * data) +{ + struct vnic_device *vnicdev = netdev->priv; + int i; + + for (i = 0; i < VNIC_STATS_LEN; i++) { + char *p = (char *)vnicdev + vnic_gstrings_stats[i].stat_offset; + data[i] = (vnic_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? *(u64 *) p : *(u32 *) p; + } +} + +static void vnic_get_strings(struct net_device *netdev, u32 stringset, + u8 * data) +{ + int i; + + switch (stringset) { + case ETH_SS_TEST: + memcpy(data, *vnic_gstrings_test, + VNIC_TEST_LEN * ETH_GSTRING_LEN); + break; + case ETH_SS_STATS: + for (i = 0; i < VNIC_STATS_LEN; i++) { + memcpy(data + i * ETH_GSTRING_LEN, + vnic_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + } + break; + } +} + +struct ethtool_ops vioc_ethtool_ops = { + .get_settings = vnic_get_settings, + .get_drvinfo = vnic_get_drvinfo, + .get_regs_len = vnic_get_regs_len, + .get_regs = vnic_get_regs, + .get_msglevel = vnic_get_msglevel, + .set_msglevel = vnic_set_msglevel, + .get_strings = vnic_get_strings, + .get_stats_count = vnic_get_stats_count, + .get_ethtool_stats = vnic_get_ethtool_stats, +}; + +#endif /* SIOCETHTOOL */ -- Misha Tomushev [EMAIL PROTECTED] - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html