Commit b1840060 authored by David S. Miller's avatar David S. Miller

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next

Jeff Kirsher says:

====================
Intel Wired LAN Driver Updates 2014-09-23

This patch series adds support for the FM10000 Ethernet switch host
interface.  The Intel FM10000 Ethernet Switch is a 48-port Ethernet switch
supporting both Ethernet ports and PCI Express host interfaces.  The fm10k
driver provides support for the host interface portion of the switch, both
PF and VF.

As the host interfaces are directly connected to the switch this results in
some significant differences versus a standard network driver.  For example
there is no PHY or MII on the device.  Since packets are delivered directly
from the switch to the host interface these are unnecessary.  Otherwise most
of the functionality is very similar to our other network drivers such as
ixgbe or igb.  For example we support all the standard network offloads,
jumbo frames, SR-IOV (64 VFS), PTP, and some VXLAN and NVGRE offloads.

v2: converted dev_consume_skb_any() to dev_kfree_skb_any()
    fix up PTP code based on feedback from the community
v3: converted the use of smb_mb__before_clear_bit() to smb_mb__before_atomic()
    added vmalloc header to patch 15
    added prefetch header to patch 16
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 58e3cac5 a211e013
...@@ -300,4 +300,23 @@ config I40EVF ...@@ -300,4 +300,23 @@ config I40EVF
will be called i40evf. MSI-X interrupt support is required will be called i40evf. MSI-X interrupt support is required
for this driver to work correctly. for this driver to work correctly.
config FM10K
tristate "Intel(R) FM10000 Ethernet Switch Host Interface Support"
default n
depends on PCI_MSI
---help---
This driver supports Intel(R) FM10000 Ethernet Switch Host
Interface. For more information on how to identify your adapter,
go to the Adapter & Driver ID Guide at:
<http://support.intel.com/support/network/sb/CS-008441.htm>
For general information and support, go to the Intel support
website at:
<http://support.intel.com>
To compile this driver as a module, choose M here. The module
will be called fm10k. MSI-X interrupt support is required
endif # NET_VENDOR_INTEL endif # NET_VENDOR_INTEL
...@@ -12,3 +12,4 @@ obj-$(CONFIG_IXGBEVF) += ixgbevf/ ...@@ -12,3 +12,4 @@ obj-$(CONFIG_IXGBEVF) += ixgbevf/
obj-$(CONFIG_I40E) += i40e/ obj-$(CONFIG_I40E) += i40e/
obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_IXGB) += ixgb/
obj-$(CONFIG_I40EVF) += i40evf/ obj-$(CONFIG_I40EVF) += i40evf/
obj-$(CONFIG_FM10K) += fm10k/
################################################################################
#
# Intel Ethernet Switch Host Interface Driver
# Copyright(c) 2013 - 2014 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.
#
# The full GNU General Public License is included in this distribution in
# the file called "COPYING".
#
# Contact Information:
# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
#
################################################################################
#
# Makefile for the Intel(R) FM10000 Ethernet Switch Host Interface driver
#
obj-$(CONFIG_FM10K) += fm10k.o
fm10k-objs := fm10k_main.o fm10k_common.o fm10k_pci.o \
fm10k_netdev.o fm10k_ethtool.o fm10k_pf.o fm10k_vf.o \
fm10k_mbx.o fm10k_iov.o fm10k_tlv.o \
fm10k_debugfs.o fm10k_ptp.o fm10k_dcbnl.o
This diff is collapsed.
This diff is collapsed.
/* Intel Ethernet Switch Host Interface Driver
* Copyright(c) 2013 - 2014 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*/
#ifndef _FM10K_COMMON_H_
#define _FM10K_COMMON_H_
#include "fm10k_type.h"
#define FM10K_REMOVED(hw_addr) unlikely(!(hw_addr))
/* PCI configuration read */
u16 fm10k_read_pci_cfg_word(struct fm10k_hw *hw, u32 reg);
/* read operations, indexed using DWORDS */
u32 fm10k_read_reg(struct fm10k_hw *hw, int reg);
/* write operations, indexed using DWORDS */
#define fm10k_write_reg(hw, reg, val) \
do { \
u32 __iomem *hw_addr = ACCESS_ONCE((hw)->hw_addr); \
if (!FM10K_REMOVED(hw_addr)) \
writel((val), &hw_addr[(reg)]); \
} while (0)
/* Switch register write operations, index using DWORDS */
#define fm10k_write_sw_reg(hw, reg, val) \
do { \
u32 __iomem *sw_addr = ACCESS_ONCE((hw)->sw_addr); \
if (!FM10K_REMOVED(sw_addr)) \
writel((val), &sw_addr[(reg)]); \
} while (0)
/* read ctrl register which has no clear on read fields as PCIe flush */
#define fm10k_write_flush(hw) fm10k_read_reg((hw), FM10K_CTRL)
s32 fm10k_get_bus_info_generic(struct fm10k_hw *hw);
s32 fm10k_get_invariants_generic(struct fm10k_hw *hw);
s32 fm10k_disable_queues_generic(struct fm10k_hw *hw, u16 q_cnt);
s32 fm10k_start_hw_generic(struct fm10k_hw *hw);
s32 fm10k_stop_hw_generic(struct fm10k_hw *hw);
u32 fm10k_read_hw_stats_32b(struct fm10k_hw *hw, u32 addr,
struct fm10k_hw_stat *stat);
#define fm10k_update_hw_base_32b(stat, delta) ((stat)->base_l += (delta))
void fm10k_update_hw_stats_q(struct fm10k_hw *hw, struct fm10k_hw_stats_q *q,
u32 idx, u32 count);
#define fm10k_unbind_hw_stats_32b(s) ((s)->base_h = 0)
void fm10k_unbind_hw_stats_q(struct fm10k_hw_stats_q *q, u32 idx, u32 count);
s32 fm10k_get_host_state_generic(struct fm10k_hw *hw, bool *host_ready);
#endif /* _FM10K_COMMON_H_ */
/* Intel Ethernet Switch Host Interface Driver
* Copyright(c) 2013 - 2014 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*/
#include "fm10k.h"
#ifdef CONFIG_DCB
/**
* fm10k_dcbnl_ieee_getets - get the ETS configuration for the device
* @dev: netdev interface for the device
* @ets: ETS structure to push configuration to
**/
static int fm10k_dcbnl_ieee_getets(struct net_device *dev, struct ieee_ets *ets)
{
int i;
/* we support 8 TCs in all modes */
ets->ets_cap = IEEE_8021QAZ_MAX_TCS;
ets->cbs = 0;
/* we only support strict priority and cannot do traffic shaping */
memset(ets->tc_tx_bw, 0, sizeof(ets->tc_tx_bw));
memset(ets->tc_rx_bw, 0, sizeof(ets->tc_rx_bw));
memset(ets->tc_tsa, IEEE_8021QAZ_TSA_STRICT, sizeof(ets->tc_tsa));
/* populate the prio map based on the netdev */
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
ets->prio_tc[i] = netdev_get_prio_tc_map(dev, i);
return 0;
}
/**
* fm10k_dcbnl_ieee_setets - set the ETS configuration for the device
* @dev: netdev interface for the device
* @ets: ETS structure to pull configuration from
**/
static int fm10k_dcbnl_ieee_setets(struct net_device *dev, struct ieee_ets *ets)
{
u8 num_tc = 0;
int i, err;
/* verify type and determine num_tcs needed */
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
if (ets->tc_tx_bw[i] || ets->tc_rx_bw[i])
return -EINVAL;
if (ets->tc_tsa[i] != IEEE_8021QAZ_TSA_STRICT)
return -EINVAL;
if (ets->prio_tc[i] > num_tc)
num_tc = ets->prio_tc[i];
}
/* if requested TC is greater than 0 then num_tcs is max + 1 */
if (num_tc)
num_tc++;
if (num_tc > IEEE_8021QAZ_MAX_TCS)
return -EINVAL;
/* update TC hardware mapping if necessary */
if (num_tc != netdev_get_num_tc(dev)) {
err = fm10k_setup_tc(dev, num_tc);
if (err)
return err;
}
/* update priority mapping */
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
netdev_set_prio_tc_map(dev, i, ets->prio_tc[i]);
return 0;
}
/**
* fm10k_dcbnl_ieee_getpfc - get the PFC configuration for the device
* @dev: netdev interface for the device
* @pfc: PFC structure to push configuration to
**/
static int fm10k_dcbnl_ieee_getpfc(struct net_device *dev, struct ieee_pfc *pfc)
{
struct fm10k_intfc *interface = netdev_priv(dev);
/* record flow control max count and state of TCs */
pfc->pfc_cap = IEEE_8021QAZ_MAX_TCS;
pfc->pfc_en = interface->pfc_en;
return 0;
}
/**
* fm10k_dcbnl_ieee_setpfc - set the PFC configuration for the device
* @dev: netdev interface for the device
* @pfc: PFC structure to pull configuration from
**/
static int fm10k_dcbnl_ieee_setpfc(struct net_device *dev, struct ieee_pfc *pfc)
{
struct fm10k_intfc *interface = netdev_priv(dev);
/* record PFC configuration to interface */
interface->pfc_en = pfc->pfc_en;
/* if we are running update the drop_en state for all queues */
if (netif_running(dev))
fm10k_update_rx_drop_en(interface);
return 0;
}
/**
* fm10k_dcbnl_ieee_getdcbx - get the DCBX configuration for the device
* @dev: netdev interface for the device
*
* Returns that we support only IEEE DCB for this interface
**/
static u8 fm10k_dcbnl_getdcbx(struct net_device *dev)
{
return DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE;
}
/**
* fm10k_dcbnl_ieee_setdcbx - get the DCBX configuration for the device
* @dev: netdev interface for the device
* @mode: new mode for this device
*
* Returns error on attempt to enable anything but IEEE DCB for this interface
**/
static u8 fm10k_dcbnl_setdcbx(struct net_device *dev, u8 mode)
{
return (mode != (DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE)) ? 1 : 0;
}
static const struct dcbnl_rtnl_ops fm10k_dcbnl_ops = {
.ieee_getets = fm10k_dcbnl_ieee_getets,
.ieee_setets = fm10k_dcbnl_ieee_setets,
.ieee_getpfc = fm10k_dcbnl_ieee_getpfc,
.ieee_setpfc = fm10k_dcbnl_ieee_setpfc,
.getdcbx = fm10k_dcbnl_getdcbx,
.setdcbx = fm10k_dcbnl_setdcbx,
};
#endif /* CONFIG_DCB */
/**
* fm10k_dcbnl_set_ops - Configures dcbnl ops pointer for netdev
* @dev: netdev interface for the device
*
* Enables PF for DCB by assigning DCBNL ops pointer.
**/
void fm10k_dcbnl_set_ops(struct net_device *dev)
{
#ifdef CONFIG_DCB
struct fm10k_intfc *interface = netdev_priv(dev);
struct fm10k_hw *hw = &interface->hw;
if (hw->mac.type == fm10k_mac_pf)
dev->dcbnl_ops = &fm10k_dcbnl_ops;
#endif /* CONFIG_DCB */
}
/* Intel Ethernet Switch Host Interface Driver
* Copyright(c) 2013 - 2014 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*/
#ifdef CONFIG_DEBUG_FS
#include "fm10k.h"
#include <linux/debugfs.h>
#include <linux/seq_file.h>
static struct dentry *dbg_root;
/* Descriptor Seq Functions */
static void *fm10k_dbg_desc_seq_start(struct seq_file *s, loff_t *pos)
{
struct fm10k_ring *ring = s->private;
return (*pos < ring->count) ? pos : NULL;
}
static void *fm10k_dbg_desc_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
struct fm10k_ring *ring = s->private;
return (++(*pos) < ring->count) ? pos : NULL;
}
static void fm10k_dbg_desc_seq_stop(struct seq_file *s, void *v)
{
/* Do nothing. */
}
static void fm10k_dbg_desc_break(struct seq_file *s, int i)
{
while (i--)
seq_puts(s, "-");
seq_puts(s, "\n");
}
static int fm10k_dbg_tx_desc_seq_show(struct seq_file *s, void *v)
{
struct fm10k_ring *ring = s->private;
int i = *(loff_t *)v;
static const char tx_desc_hdr[] =
"DES BUFFER_ADDRESS LENGTH VLAN MSS HDRLEN FLAGS\n";
/* Generate header */
if (!i) {
seq_printf(s, tx_desc_hdr);
fm10k_dbg_desc_break(s, sizeof(tx_desc_hdr) - 1);
}
/* Validate descriptor allocation */
if (!ring->desc) {
seq_printf(s, "%03X Descriptor ring not allocated.\n", i);
} else {
struct fm10k_tx_desc *txd = FM10K_TX_DESC(ring, i);
seq_printf(s, "%03X %#018llx %#06x %#06x %#06x %#06x %#04x\n",
i, txd->buffer_addr, txd->buflen, txd->vlan,
txd->mss, txd->hdrlen, txd->flags);
}
return 0;
}
static int fm10k_dbg_rx_desc_seq_show(struct seq_file *s, void *v)
{
struct fm10k_ring *ring = s->private;
int i = *(loff_t *)v;
static const char rx_desc_hdr[] =
"DES DATA RSS STATERR LENGTH VLAN DGLORT SGLORT TIMESTAMP\n";
/* Generate header */
if (!i) {
seq_printf(s, rx_desc_hdr);
fm10k_dbg_desc_break(s, sizeof(rx_desc_hdr) - 1);
}
/* Validate descriptor allocation */
if (!ring->desc) {
seq_printf(s, "%03X Descriptor ring not allocated.\n", i);
} else {
union fm10k_rx_desc *rxd = FM10K_RX_DESC(ring, i);
seq_printf(s,
"%03X %#010x %#010x %#010x %#06x %#06x %#06x %#06x %#018llx\n",
i, rxd->d.data, rxd->d.rss, rxd->d.staterr,
rxd->w.length, rxd->w.vlan, rxd->w.dglort,
rxd->w.sglort, rxd->q.timestamp);
}
return 0;
}
static const struct seq_operations fm10k_dbg_tx_desc_seq_ops = {
.start = fm10k_dbg_desc_seq_start,
.next = fm10k_dbg_desc_seq_next,
.stop = fm10k_dbg_desc_seq_stop,
.show = fm10k_dbg_tx_desc_seq_show,
};
static const struct seq_operations fm10k_dbg_rx_desc_seq_ops = {
.start = fm10k_dbg_desc_seq_start,
.next = fm10k_dbg_desc_seq_next,
.stop = fm10k_dbg_desc_seq_stop,
.show = fm10k_dbg_rx_desc_seq_show,
};
static int fm10k_dbg_desc_open(struct inode *inode, struct file *filep)
{
struct fm10k_ring *ring = inode->i_private;
struct fm10k_q_vector *q_vector = ring->q_vector;
const struct seq_operations *desc_seq_ops;
int err;
if (ring < q_vector->rx.ring)
desc_seq_ops = &fm10k_dbg_tx_desc_seq_ops;
else
desc_seq_ops = &fm10k_dbg_rx_desc_seq_ops;
err = seq_open(filep, desc_seq_ops);
if (err)
return err;
((struct seq_file *)filep->private_data)->private = ring;
return 0;
}
static const struct file_operations fm10k_dbg_desc_fops = {
.owner = THIS_MODULE,
.open = fm10k_dbg_desc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
/**
* fm10k_dbg_q_vector_init - setup debugfs for the q_vectors
* @q_vector: q_vector to allocate directories for
*
* A folder is created for each q_vector found. In each q_vector
* folder, a debugfs file is created for each tx and rx ring
* allocated to the q_vector.
**/
void fm10k_dbg_q_vector_init(struct fm10k_q_vector *q_vector)
{
struct fm10k_intfc *interface = q_vector->interface;
char name[16];
int i;
if (!interface->dbg_intfc)
return;
/* Generate a folder for each q_vector */
sprintf(name, "q_vector.%03d", q_vector->v_idx);
q_vector->dbg_q_vector = debugfs_create_dir(name, interface->dbg_intfc);
if (!q_vector->dbg_q_vector)
return;
/* Generate a file for each rx ring in the q_vector */
for (i = 0; i < q_vector->tx.count; i++) {
struct fm10k_ring *ring = &q_vector->tx.ring[i];
sprintf(name, "tx_ring.%03d", ring->queue_index);
debugfs_create_file(name, 0600,
q_vector->dbg_q_vector, ring,
&fm10k_dbg_desc_fops);
}
/* Generate a file for each rx ring in the q_vector */
for (i = 0; i < q_vector->rx.count; i++) {
struct fm10k_ring *ring = &q_vector->rx.ring[i];
sprintf(name, "rx_ring.%03d", ring->queue_index);
debugfs_create_file(name, 0600,
q_vector->dbg_q_vector, ring,
&fm10k_dbg_desc_fops);
}
}
/**
* fm10k_dbg_free_q_vector_dir - setup debugfs for the q_vectors
* @q_vector: q_vector to allocate directories for
**/
void fm10k_dbg_q_vector_exit(struct fm10k_q_vector *q_vector)
{
struct fm10k_intfc *interface = q_vector->interface;
if (interface->dbg_intfc)
debugfs_remove_recursive(q_vector->dbg_q_vector);
q_vector->dbg_q_vector = NULL;
}
/**
* fm10k_dbg_intfc_init - setup the debugfs directory for the intferface
* @interface: the interface that is starting up
**/
void fm10k_dbg_intfc_init(struct fm10k_intfc *interface)
{
const char *name = pci_name(interface->pdev);
if (dbg_root)
interface->dbg_intfc = debugfs_create_dir(name, dbg_root);
}
/**
* fm10k_dbg_intfc_exit - clean out the interface's debugfs entries
* @interface: the interface that is stopping
**/
void fm10k_dbg_intfc_exit(struct fm10k_intfc *interface)
{
if (dbg_root)
debugfs_remove_recursive(interface->dbg_intfc);
interface->dbg_intfc = NULL;
}
/**
* fm10k_dbg_init - start up debugfs for the driver
**/
void fm10k_dbg_init(void)
{
dbg_root = debugfs_create_dir(fm10k_driver_name, NULL);
}
/**
* fm10k_dbg_exit - clean out the driver's debugfs entries
**/
void fm10k_dbg_exit(void)
{
debugfs_remove_recursive(dbg_root);
dbg_root = NULL;
}
#endif /* CONFIG_DEBUG_FS */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment