lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<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