[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20091221075951.GD21782@verge.net.au>
Date: Mon, 21 Dec 2009 18:59:54 +1100
From: Simon Horman <horms@...ge.net.au>
To: Jeff Kirsher <jeffrey.t.kirsher@...el.com>
Cc: netdev@...r.kernel.org, gospo@...hat.com,
Greg Rose <gregory.v.rose@...el.com>
Subject: Re: [RFC PATCH v2 04/12] ixgbevf: Driver main and ethool interface
module and main header
On Fri, Dec 18, 2009 at 02:51:58PM -0800, Jeff Kirsher wrote:
> From: Greg Rose <gregory.v.rose@...el.com>
>
> These modules and header contain the Linux OS network interface code and core
> interrupt and network send/receive handlers.
>
> Signed-off-by: Greg Rose <gregory.v.rose@...el.com>
> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@...el.com>
> ---
>
> drivers/net/ixgbevf/ethtool.c | 718 +++++++
> drivers/net/ixgbevf/ixgbevf.h | 318 +++
> drivers/net/ixgbevf/ixgbevf_main.c | 3594 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 4630 insertions(+), 0 deletions(-)
> create mode 100644 drivers/net/ixgbevf/ethtool.c
> create mode 100644 drivers/net/ixgbevf/ixgbevf.h
> create mode 100644 drivers/net/ixgbevf/ixgbevf_main.c
>
> diff --git a/drivers/net/ixgbevf/ethtool.c b/drivers/net/ixgbevf/ethtool.c
> new file mode 100644
> index 0000000..6cf0110
> --- /dev/null
> +++ b/drivers/net/ixgbevf/ethtool.c
> @@ -0,0 +1,718 @@
> +/*******************************************************************************
> +
> + Intel 82599 Virtual Function driver
> + Copyright(c) 1999 - 2009 Intel Corporation.
> +
> + This program is free software; you can redistribute it and/or modify it
> + under the terms and conditions of the GNU General Public License,
> + version 2, as published by the Free Software Foundation.
> +
> + This program is distributed in the hope 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.,
> + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> +
> + The full GNU General Public License is included in this distribution in
> + the file called "COPYING".
> +
> + Contact Information:
> + e1000-devel Mailing List <e1000-devel@...ts.sourceforge.net>
> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
> +
> +*******************************************************************************/
> +
> +/* ethtool support for ixgbevf */
> +
> +#include <linux/types.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/netdevice.h>
> +#include <linux/ethtool.h>
> +#include <linux/vmalloc.h>
> +#include <linux/if_vlan.h>
> +#include <linux/uaccess.h>
> +
> +#include "ixgbevf.h"
> +
> +#define IXGBE_ALL_RAR_ENTRIES 16
> +
> +#ifdef ETHTOOL_GSTATS
> +struct ixgbe_stats {
> + char stat_string[ETH_GSTRING_LEN];
> + int sizeof_stat;
> + int stat_offset;
> + int base_stat_offset;
> +};
> +
> +#define IXGBEVF_STAT(m, b) sizeof(((struct ixgbevf_adapter *)0)->m), \
> + offsetof(struct ixgbevf_adapter, m), \
> + offsetof(struct ixgbevf_adapter, b)
> +static struct ixgbe_stats ixgbe_gstrings_stats[] = {
> + {"rx_packets", IXGBEVF_STAT(stats.vfgprc, stats.base_vfgprc)},
> + {"tx_packets", IXGBEVF_STAT(stats.vfgptc, stats.base_vfgptc)},
> + {"rx_bytes", IXGBEVF_STAT(stats.vfgorc, stats.base_vfgorc)},
> + {"tx_bytes", IXGBEVF_STAT(stats.vfgotc, stats.base_vfgotc)},
> + {"tx_busy", IXGBEVF_STAT(tx_busy, zero_base)},
> + {"multicast", IXGBEVF_STAT(stats.vfmprc, stats.base_vfmprc)},
> + {"rx_csum_offload_good", IXGBEVF_STAT(hw_csum_rx_good, zero_base)},
> + {"rx_csum_offload_errors", IXGBEVF_STAT(hw_csum_rx_error, zero_base)},
> + {"tx_csum_offload_ctxt", IXGBEVF_STAT(hw_csum_tx_good, zero_base)},
> + {"rx_header_split", IXGBEVF_STAT(rx_hdr_split, zero_base)},
> +};
> +
> +#define IXGBE_QUEUE_STATS_LEN 0
> +#define IXGBE_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbe_gstrings_stats)
> +
> +#define IXGBEVF_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN)
> +#endif /* ETHTOOL_GSTATS */
> +#ifdef ETHTOOL_TEST
> +static const char ixgbe_gstrings_test[][ETH_GSTRING_LEN] = {
> + "Register test (offline)",
> + "Link test (on/offline)"
> +};
> +#define IXGBE_TEST_LEN (sizeof(ixgbe_gstrings_test) / ETH_GSTRING_LEN)
> +#endif /* ETHTOOL_TEST */
> +
> +static int ixgbevf_get_settings(struct net_device *netdev,
> + struct ethtool_cmd *ecmd)
> +{
> + struct ixgbevf_adapter *adapter = netdev_priv(netdev);
> + struct ixgbe_hw *hw = &adapter->hw;
> + u32 link_speed = 0;
> + bool link_up;
> +
> + ecmd->supported = SUPPORTED_10000baseT_Full;
> + ecmd->autoneg = AUTONEG_DISABLE;
> + ecmd->transceiver = XCVR_DUMMY1;
> + ecmd->port = -1;
> +
> + hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
> +
> + if (link_up) {
> + ecmd->speed = (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ?
> + SPEED_10000 : SPEED_1000;
> + ecmd->duplex = DUPLEX_FULL;
> + } else {
> + ecmd->speed = -1;
> + ecmd->duplex = -1;
> + }
> +
> + return 0;
> +}
> +
> +static u32 ixgbevf_get_rx_csum(struct net_device *netdev)
> +{
> + struct ixgbevf_adapter *adapter = netdev_priv(netdev);
> + return adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED;
> +}
> +
> +static int ixgbevf_set_rx_csum(struct net_device *netdev, u32 data)
> +{
> + struct ixgbevf_adapter *adapter = netdev_priv(netdev);
> + if (data)
> + adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED;
> + else
> + adapter->flags &= ~IXGBE_FLAG_RX_CSUM_ENABLED;
> +
> + if (netif_running(netdev)) {
> + if (!adapter->dev_closed)
> + ixgbevf_reinit_locked(adapter);
> + } else {
> + ixgbevf_reset(adapter);
> + }
> +
> + return 0;
> +}
> +
> +static int ixgbevf_set_tso(struct net_device *netdev, u32 data)
> +{
> + if (data) {
> + netdev->features |= NETIF_F_TSO;
> + netdev->features |= NETIF_F_TSO6;
> + } else {
> + netif_tx_stop_all_queues(netdev);
> + netdev->features &= ~NETIF_F_TSO;
> + netdev->features &= ~NETIF_F_TSO6;
> + netif_tx_start_all_queues(netdev);
> + }
> + return 0;
> +}
> +
> +static u32 ixgbevf_get_msglevel(struct net_device *netdev)
> +{
> + struct ixgbevf_adapter *adapter = netdev_priv(netdev);
> + return adapter->msg_enable;
> +}
> +
> +static void ixgbevf_set_msglevel(struct net_device *netdev, u32 data)
> +{
> + struct ixgbevf_adapter *adapter = netdev_priv(netdev);
> + adapter->msg_enable = data;
> +}
> +
> +#define IXGBE_GET_STAT(_A_, _R_) (_A_->stats._R_)
> +
> +static char *ixgbevf_reg_names[] = {
> + "IXGBE_VFCTRL",
> + "IXGBE_VFSTATUS",
> + "IXGBE_VFLINKS",
> + "IXGBE_VFRXMEMWRAP",
> + "IXGBE_VFRTIMER",
> + "IXGBE_VTEICR",
> + "IXGBE_VTEICS",
> + "IXGBE_VTEIMS",
> + "IXGBE_VTEIMC",
> + "IXGBE_VTEIAC",
> + "IXGBE_VTEIAM",
> + "IXGBE_VTEITR",
> + "IXGBE_VTIVAR",
> + "IXGBE_VTIVAR_MISC",
> + "IXGBE_VFRDBAL0",
> + "IXGBE_VFRDBAL1",
> + "IXGBE_VFRDBAH0",
> + "IXGBE_VFRDBAH1",
> + "IXGBE_VFRDLEN0",
> + "IXGBE_VFRDLEN1",
> + "IXGBE_VFRDH0",
> + "IXGBE_VFRDH1",
> + "IXGBE_VFRDT0",
> + "IXGBE_VFRDT1",
> + "IXGBE_VFRXDCTL0",
> + "IXGBE_VFRXDCTL1",
> + "IXGBE_VFSRRCTL0",
> + "IXGBE_VFSRRCTL1",
> + "IXGBE_VFPSRTYPE",
> + "IXGBE_VFTDBAL0",
> + "IXGBE_VFTDBAL1",
> + "IXGBE_VFTDBAH0",
> + "IXGBE_VFTDBAH1",
> + "IXGBE_VFTDLEN0",
> + "IXGBE_VFTDLEN1",
> + "IXGBE_VFTDH0",
> + "IXGBE_VFTDH1",
> + "IXGBE_VFTDT0",
> + "IXGBE_VFTDT1",
> + "IXGBE_VFTXDCTL0",
> + "IXGBE_VFTXDCTL1",
> + "IXGBE_VFTDWBAL0",
> + "IXGBE_VFTDWBAL1",
> + "IXGBE_VFTDWBAH0",
> + "IXGBE_VFTDWBAH1"
> +};
> +
> +
> +static int ixgbevf_get_regs_len(struct net_device *netdev)
> +{
> + return (ARRAY_SIZE(ixgbevf_reg_names)) * sizeof(u32);
> +}
> +
> +static void ixgbevf_get_regs(struct net_device *netdev,
> + struct ethtool_regs *regs,
> + void *p)
> +{
> + struct ixgbevf_adapter *adapter = netdev_priv(netdev);
> + struct ixgbe_hw *hw = &adapter->hw;
> + u32 *regs_buff = p;
> + u32 regs_len = ixgbevf_get_regs_len(netdev);
> + u8 i;
> +
> + memset(p, 0, regs_len);
> +
> + regs->version = (1 << 24) | hw->revision_id << 16 | hw->device_id;
> +
> + /* General Registers */
> + regs_buff[0] = IXGBE_READ_REG(hw, IXGBE_VFCTRL);
> + regs_buff[1] = IXGBE_READ_REG(hw, IXGBE_VFSTATUS);
> + regs_buff[2] = IXGBE_READ_REG(hw, IXGBE_VFLINKS);
> + regs_buff[3] = IXGBE_READ_REG(hw, IXGBE_VFRXMEMWRAP);
> + regs_buff[4] = IXGBE_READ_REG(hw, IXGBE_VFRTIMER);
> +
> + /* Interrupt */
> + /* don't read EICR because it can clear interrupt causes, instead
> + * read EICS which is a shadow but doesn't clear EICR */
> + regs_buff[5] = IXGBE_READ_REG(hw, IXGBE_VTEICS);
> + regs_buff[6] = IXGBE_READ_REG(hw, IXGBE_VTEICS);
> + regs_buff[7] = IXGBE_READ_REG(hw, IXGBE_VTEIMS);
> + regs_buff[8] = IXGBE_READ_REG(hw, IXGBE_VTEIMC);
> + regs_buff[9] = IXGBE_READ_REG(hw, IXGBE_VTEIAC);
> + regs_buff[10] = IXGBE_READ_REG(hw, IXGBE_VTEIAM);
> + regs_buff[11] = IXGBE_READ_REG(hw, IXGBE_VTEITR(0));
> + regs_buff[12] = IXGBE_READ_REG(hw, IXGBE_VTIVAR(0));
> + regs_buff[13] = IXGBE_READ_REG(hw, IXGBE_VTIVAR_MISC);
> +
> + /* Receive DMA */
> + for (i = 0; i < 2; i++)
> + regs_buff[14 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDBAL(i));
> + for (i = 0; i < 2; i++)
> + regs_buff[16 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDBAH(i));
> + for (i = 0; i < 2; i++)
> + regs_buff[18 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDLEN(i));
> + for (i = 0; i < 2; i++)
> + regs_buff[20 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDH(i));
> + for (i = 0; i < 2; i++)
> + regs_buff[22 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDT(i));
> + for (i = 0; i < 2; i++)
> + regs_buff[24 + i] = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i));
> + for (i = 0; i < 2; i++)
> + regs_buff[26 + i] = IXGBE_READ_REG(hw, IXGBE_VFSRRCTL(i));
> +
> + /* Receive */
> + regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_VFPSRTYPE);
> +
> + /* Transmit */
> + for (i = 0; i < 2; i++)
> + regs_buff[29 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDBAL(i));
> + for (i = 0; i < 2; i++)
> + regs_buff[31 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDBAH(i));
> + for (i = 0; i < 2; i++)
> + regs_buff[33 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDLEN(i));
> + for (i = 0; i < 2; i++)
> + regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDH(i));
> + for (i = 0; i < 2; i++)
> + regs_buff[37 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDT(i));
> + for (i = 0; i < 2; i++)
> + regs_buff[39 + i] = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(i));
> + for (i = 0; i < 2; i++)
> + regs_buff[41 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDWBAL(i));
> + for (i = 0; i < 2; i++)
> + regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDWBAH(i));
> +
> + for (i = 0; i < regs_len; i++)
> + printk(KERN_INFO "%s\t%8.8x\n",
> + ixgbevf_reg_names[i], regs_buff[i]);
> +}
> +
> +static void ixgbevf_get_drvinfo(struct net_device *netdev,
> + struct ethtool_drvinfo *drvinfo)
> +{
> + struct ixgbevf_adapter *adapter = netdev_priv(netdev);
> +
> + strlcpy(drvinfo->driver, ixgbevf_driver_name, 32);
> + strlcpy(drvinfo->version, ixgbevf_driver_version, 32);
> +
> + strlcpy(drvinfo->fw_version, "N/A", 4);
> + strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
> +}
> +
> +static void ixgbevf_get_ringparam(struct net_device *netdev,
> + struct ethtool_ringparam *ring)
> +{
> + struct ixgbevf_adapter *adapter = netdev_priv(netdev);
> + struct ixgbevf_ring *tx_ring = adapter->tx_ring;
> + struct ixgbevf_ring *rx_ring = adapter->rx_ring;
> +
> + ring->rx_max_pending = IXGBEVF_MAX_RXD;
> + ring->tx_max_pending = IXGBEVF_MAX_TXD;
> + ring->rx_mini_max_pending = 0;
> + ring->rx_jumbo_max_pending = 0;
> + ring->rx_pending = rx_ring->count;
> + ring->tx_pending = tx_ring->count;
> + ring->rx_mini_pending = 0;
> + ring->rx_jumbo_pending = 0;
> +}
> +
> +static int ixgbevf_set_ringparam(struct net_device *netdev,
> + struct ethtool_ringparam *ring)
> +{
> + struct ixgbevf_adapter *adapter = netdev_priv(netdev);
> + struct ixgbevf_ring *tx_ring, *rx_ring;
> + int i, err;
> + u32 new_rx_count, new_tx_count;
> + bool need_update = false;
> +
> + if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
> + return -EINVAL;
> +
> + new_rx_count = max(ring->rx_pending, (u32)IXGBEVF_MIN_RXD);
> + new_rx_count = min(new_rx_count, (u32)IXGBEVF_MAX_RXD);
> + new_rx_count = ALIGN(new_rx_count, IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE);
> +
> + new_tx_count = max(ring->tx_pending, (u32)IXGBEVF_MIN_TXD);
> + new_tx_count = min(new_tx_count, (u32)IXGBEVF_MAX_TXD);
> + new_tx_count = ALIGN(new_tx_count, IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE);
> +
> + if ((new_tx_count == adapter->tx_ring->count) &&
> + (new_rx_count == adapter->rx_ring->count)) {
> + /* nothing to do */
> + return 0;
> + }
> +
> + while (test_and_set_bit(__IXGBEVF_RESETTING, &adapter->state))
> + msleep(1);
> +
> + tx_ring = kcalloc(adapter->num_tx_queues,
> + sizeof(struct ixgbevf_ring), GFP_KERNEL);
> + if (!tx_ring) {
> + err = -ENOMEM;
> + goto err_setup;
> + }
> +
> + if (new_tx_count != adapter->tx_ring_count) {
> + memcpy(tx_ring, adapter->tx_ring,
> + adapter->num_tx_queues * sizeof(struct ixgbevf_ring));
> + for (i = 0; i < adapter->num_tx_queues; i++) {
> + tx_ring[i].count = new_tx_count;
> + err = ixgbevf_setup_tx_resources(adapter,
> + &tx_ring[i]);
> + if (err) {
> + while (i) {
> + i--;
> + ixgbevf_free_tx_resources(adapter,
> + &tx_ring[i]);
> + }
> + goto err_setup;
> + }
> + tx_ring[i].v_idx = adapter->tx_ring[i].v_idx;
> + }
> + need_update = true;
> + }
> +
> + rx_ring = kcalloc(adapter->num_rx_queues,
> + sizeof(struct ixgbevf_ring), GFP_KERNEL);
> + if ((!rx_ring) && (need_update)) {
> + for (i = 0; i < adapter->num_tx_queues; i++)
> + ixgbevf_free_tx_resources(adapter, &tx_ring[i]);
> + kfree(tx_ring);
> + err = -ENOMEM;
> + goto err_setup;
> + }
> +
> + if (new_rx_count != adapter->rx_ring_count) {
> + memcpy(rx_ring, adapter->rx_ring,
> + adapter->num_rx_queues * sizeof(struct ixgbevf_ring));
> + for (i = 0; i < adapter->num_rx_queues; i++) {
> + rx_ring[i].count = new_rx_count;
> + err = ixgbevf_setup_rx_resources(adapter,
> + &rx_ring[i]);
> + if (err) {
> + while (i) {
> + i--;
> + ixgbevf_free_rx_resources(adapter,
> + &rx_ring[i]);
> + }
> + goto err_setup;
Are some calls to ixgbevf_free_tx_resources()
needed here? Perhaps the ones for
on rx_ring failure could be moved down
to an err_tx_clear or similar?
(sorry for the shoddy name)
> + }
> + rx_ring[i].v_idx = adapter->rx_ring[i].v_idx;
> + }
> + need_update = true;
> + }
> +
> + /* if rings need to be updated, here's the place to do it in one shot */
> + if (need_update) {
> + if (netif_running(netdev))
> + ixgbevf_down(adapter);
> +
> + /* tx */
> + if (new_tx_count != adapter->tx_ring_count) {
> + kfree(adapter->tx_ring);
> + adapter->tx_ring = tx_ring;
> + tx_ring = NULL;
> + adapter->tx_ring_count = new_tx_count;
> + }
> +
> + /* rx */
> + if (new_rx_count != adapter->rx_ring_count) {
> + kfree(adapter->rx_ring);
> + adapter->rx_ring = rx_ring;
> + rx_ring = NULL;
> + adapter->rx_ring_count = new_rx_count;
> + }
> + }
Can tx_ring and rx_ring leak here?
> +
> + /* success! */
> + err = 0;
> + if (netif_running(netdev))
> + ixgbevf_up(adapter);
> +
> +err_setup:
> + clear_bit(__IXGBEVF_RESETTING, &adapter->state);
> + return err;
> +}
Dinner calls...
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists