Skip to content

Commit

Permalink
fm10k: Add support for VF
Browse files Browse the repository at this point in the history
This patch provides the functions necessary to configure the VF making use
of the same API pointers as the PF.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
  • Loading branch information
Alexander Duyck authored and Jeff Kirsher committed Sep 23, 2014
1 parent b651957 commit 5cb8db4
Show file tree
Hide file tree
Showing 9 changed files with 837 additions and 4 deletions.
2 changes: 1 addition & 1 deletion drivers/net/ethernet/intel/fm10k/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@
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_netdev.o fm10k_ethtool.o fm10k_pf.o fm10k_vf.o \
fm10k_mbx.o fm10k_tlv.o
4 changes: 3 additions & 1 deletion drivers/net/ethernet/intel/fm10k/fm10k.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <linux/pci.h>

#include "fm10k_pf.h"
#include "fm10k_vf.h"

#define FM10K_MAX_JUMBO_FRAME_SIZE 15358 /* Maximum supported size 15K */

Expand Down Expand Up @@ -180,12 +181,13 @@ static inline struct netdev_queue *txring_txq(const struct fm10k_ring *ring)
#define MIN_Q_VECTORS 1
enum fm10k_non_q_vectors {
FM10K_MBX_VECTOR,
#define NON_Q_VECTORS_VF NON_Q_VECTORS_PF
NON_Q_VECTORS_PF
};

#define NON_Q_VECTORS(hw) (((hw)->mac.type == fm10k_mac_pf) ? \
NON_Q_VECTORS_PF : \
0)
NON_Q_VECTORS_VF)
#define MIN_MSIX_COUNT(hw) (MIN_Q_VECTORS + NON_Q_VECTORS(hw))

struct fm10k_q_vector {
Expand Down
114 changes: 114 additions & 0 deletions drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,28 @@ static const struct fm10k_stats fm10k_gstrings_stats[] = {
FM10K_NETDEV_STATS_LEN + \
FM10K_QUEUE_STATS_LEN)

static const char fm10k_gstrings_test[][ETH_GSTRING_LEN] = {
"Mailbox test (on/offline)"
};

#define FM10K_TEST_LEN (sizeof(fm10k_gstrings_test) / ETH_GSTRING_LEN)

enum fm10k_self_test_types {
FM10K_TEST_MBX,
FM10K_TEST_MAX = FM10K_TEST_LEN
};

static void fm10k_get_strings(struct net_device *dev, u32 stringset,
u8 *data)
{
char *p = (char *)data;
int i;

switch (stringset) {
case ETH_SS_TEST:
memcpy(data, *fm10k_gstrings_test,
FM10K_TEST_LEN * ETH_GSTRING_LEN);
break;
case ETH_SS_STATS:
for (i = 0; i < FM10K_NETDEV_STATS_LEN; i++) {
memcpy(p, fm10k_gstrings_net_stats[i].stat_string,
Expand Down Expand Up @@ -138,6 +153,8 @@ static void fm10k_get_strings(struct net_device *dev, u32 stringset,
static int fm10k_get_sset_count(struct net_device *dev, int sset)
{
switch (sset) {
case ETH_SS_TEST:
return FM10K_TEST_LEN;
case ETH_SS_STATS:
return FM10K_STATS_LEN;
default:
Expand Down Expand Up @@ -287,6 +304,28 @@ static void fm10k_get_regs(struct net_device *netdev,
for (i = 0; i < 130; i++)
*(buff++) = fm10k_read_reg(hw, FM10K_ITR(i));

break;
case fm10k_mac_vf:
/* General VF registers */
*(buff++) = fm10k_read_reg(hw, FM10K_VFCTRL);
*(buff++) = fm10k_read_reg(hw, FM10K_VFINT_MAP);
*(buff++) = fm10k_read_reg(hw, FM10K_VFSYSTIME);

/* Interrupt Throttling Registers */
for (i = 0; i < 8; i++)
*(buff++) = fm10k_read_reg(hw, FM10K_VFITR(i));

fm10k_get_reg_vsi(hw, buff, 0);
buff += FM10K_REGS_LEN_VSI;

for (i = 0; i < FM10K_MAX_QUEUES_POOL; i++) {
if (i < hw->mac.max_queues)
fm10k_get_reg_q(hw, buff, i);
else
memset(buff, 0, sizeof(u32) * FM10K_REGS_LEN_Q);
buff += FM10K_REGS_LEN_Q;
}

break;
default:
return;
Expand All @@ -296,6 +335,8 @@ static void fm10k_get_regs(struct net_device *netdev,
/* If function above adds more registers these define need to be updated */
#define FM10K_REGS_LEN_PF \
(162 + (65 * FM10K_REGS_LEN_VSI) + (FM10K_MAX_QUEUES_PF * FM10K_REGS_LEN_Q))
#define FM10K_REGS_LEN_VF \
(11 + FM10K_REGS_LEN_VSI + (FM10K_MAX_QUEUES_POOL * FM10K_REGS_LEN_Q))

static int fm10k_get_regs_len(struct net_device *netdev)
{
Expand All @@ -305,6 +346,8 @@ static int fm10k_get_regs_len(struct net_device *netdev)
switch (hw->mac.type) {
case fm10k_mac_pf:
return FM10K_REGS_LEN_PF * sizeof(u32);
case fm10k_mac_vf:
return FM10K_REGS_LEN_VF * sizeof(u32);
default:
return 0;
}
Expand Down Expand Up @@ -734,6 +777,76 @@ static int fm10k_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
return ret;
}

static int fm10k_mbx_test(struct fm10k_intfc *interface, u64 *data)
{
struct fm10k_hw *hw = &interface->hw;
struct fm10k_mbx_info *mbx = &hw->mbx;
u32 attr_flag, test_msg[6];
unsigned long timeout;
int err;

/* For now this is a VF only feature */
if (hw->mac.type != fm10k_mac_vf)
return 0;

/* loop through both nested and unnested attribute types */
for (attr_flag = (1 << FM10K_TEST_MSG_UNSET);
attr_flag < (1 << (2 * FM10K_TEST_MSG_NESTED));
attr_flag += attr_flag) {
/* generate message to be tested */
fm10k_tlv_msg_test_create(test_msg, attr_flag);

fm10k_mbx_lock(interface);
mbx->test_result = FM10K_NOT_IMPLEMENTED;
err = mbx->ops.enqueue_tx(hw, mbx, test_msg);
fm10k_mbx_unlock(interface);

/* wait up to 1 second for response */
timeout = jiffies + HZ;
do {
if (err < 0)
goto err_out;

usleep_range(500, 1000);

fm10k_mbx_lock(interface);
mbx->ops.process(hw, mbx);
fm10k_mbx_unlock(interface);

err = mbx->test_result;
if (!err)
break;
} while (time_is_after_jiffies(timeout));

/* reporting errors */
if (err)
goto err_out;
}

err_out:
*data = err < 0 ? (attr_flag) : (err > 0);
return err;
}

static void fm10k_self_test(struct net_device *dev,
struct ethtool_test *eth_test, u64 *data)
{
struct fm10k_intfc *interface = netdev_priv(dev);
struct fm10k_hw *hw = &interface->hw;

memset(data, 0, sizeof(*data) * FM10K_TEST_LEN);

if (FM10K_REMOVED(hw)) {
netif_err(interface, drv, dev,
"Interface removed - test blocked\n");
eth_test->flags |= ETH_TEST_FL_FAILED;
return;
}

if (fm10k_mbx_test(interface, &data[FM10K_TEST_MBX]))
eth_test->flags |= ETH_TEST_FL_FAILED;
}

static u32 fm10k_get_reta_size(struct net_device *netdev)
{
return FM10K_RETA_SIZE * FM10K_RETA_ENTRIES_PER_REG;
Expand Down Expand Up @@ -911,6 +1024,7 @@ static const struct ethtool_ops fm10k_ethtool_ops = {
.set_rxnfc = fm10k_set_rxnfc,
.get_regs = fm10k_get_regs,
.get_regs_len = fm10k_get_regs_len,
.self_test = fm10k_self_test,
.get_rxfh_indir_size = fm10k_get_reta_size,
.get_rxfh_key_size = fm10k_get_rssrk_size,
.get_rxfh = fm10k_get_rssh,
Expand Down
4 changes: 4 additions & 0 deletions drivers/net/ethernet/intel/fm10k/fm10k_mbx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1517,6 +1517,10 @@ s32 fm10k_pfvf_mbx_init(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx,
{
/* initialize registers */
switch (hw->mac.type) {
case fm10k_mac_vf:
mbx->mbx_reg = FM10K_VFMBX;
mbx->mbmem_reg = FM10K_VFMBMEM(FM10K_VFMBMEM_VF_XOR);
break;
case fm10k_mac_pf:
/* there are only 64 VF <-> PF mailboxes */
if (id < 64) {
Expand Down
15 changes: 15 additions & 0 deletions drivers/net/ethernet/intel/fm10k/fm10k_netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,21 @@ void fm10k_restore_rx_state(struct fm10k_intfc *interface)
int xcast_mode;
u16 vid, glort;

/* restore our address if perm_addr is set */
if (hw->mac.type == fm10k_mac_vf) {
if (is_valid_ether_addr(hw->mac.perm_addr)) {
ether_addr_copy(hw->mac.addr, hw->mac.perm_addr);
ether_addr_copy(netdev->perm_addr, hw->mac.perm_addr);
ether_addr_copy(netdev->dev_addr, hw->mac.perm_addr);
netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
}

if (hw->mac.vlan_override)
netdev->features &= ~NETIF_F_HW_VLAN_CTAG_RX;
else
netdev->features |= NETIF_F_HW_VLAN_CTAG_RX;
}

/* record glort for this interface */
glort = interface->glort;

Expand Down
102 changes: 100 additions & 2 deletions drivers/net/ethernet/intel/fm10k/fm10k_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

static const struct fm10k_info *fm10k_info_tbl[] = {
[fm10k_device_pf] = &fm10k_pf_info,
[fm10k_device_vf] = &fm10k_vf_info,
};

/**
Expand All @@ -38,6 +39,7 @@ static const struct fm10k_info *fm10k_info_tbl[] = {
*/
static const struct pci_device_id fm10k_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, FM10K_DEV_ID_PF), fm10k_device_pf },
{ PCI_VDEVICE(INTEL, FM10K_DEV_ID_VF), fm10k_device_vf },
/* required last entry */
{ 0, }
};
Expand Down Expand Up @@ -805,6 +807,28 @@ static irqreturn_t fm10k_msix_clean_rings(int irq, void *data)
return IRQ_HANDLED;
}

static irqreturn_t fm10k_msix_mbx_vf(int irq, void *data)
{
struct fm10k_intfc *interface = data;
struct fm10k_hw *hw = &interface->hw;
struct fm10k_mbx_info *mbx = &hw->mbx;

/* re-enable mailbox interrupt and indicate 20us delay */
fm10k_write_reg(hw, FM10K_VFITR(FM10K_MBX_VECTOR),
FM10K_ITR_ENABLE | FM10K_MBX_INT_DELAY);

/* service upstream mailbox */
if (fm10k_mbx_trylock(interface)) {
mbx->ops.process(hw, mbx);
fm10k_mbx_unlock(interface);
}

hw->mac.get_host_state = 1;
fm10k_service_event_schedule(interface);

return IRQ_HANDLED;
}

#define FM10K_ERR_MSG(type) case (type): error = #type; break
static void fm10k_print_fault(struct fm10k_intfc *interface, int type,
struct fm10k_fault *fault)
Expand Down Expand Up @@ -996,13 +1020,42 @@ void fm10k_mbx_free_irq(struct fm10k_intfc *interface)
FM10K_EIMR_DISABLE(VFLR) |
FM10K_EIMR_DISABLE(MAXHOLDTIME));
itr_reg = FM10K_ITR(FM10K_MBX_VECTOR);
} else {
itr_reg = FM10K_VFITR(FM10K_MBX_VECTOR);
}

fm10k_write_reg(hw, itr_reg, FM10K_ITR_MASK_SET);

free_irq(entry->vector, interface);
}

static s32 fm10k_mbx_mac_addr(struct fm10k_hw *hw, u32 **results,
struct fm10k_mbx_info *mbx)
{
bool vlan_override = hw->mac.vlan_override;
u16 default_vid = hw->mac.default_vid;
struct fm10k_intfc *interface;
s32 err;

err = fm10k_msg_mac_vlan_vf(hw, results, mbx);
if (err)
return err;

interface = container_of(hw, struct fm10k_intfc, hw);

/* MAC was changed so we need reset */
if (is_valid_ether_addr(hw->mac.perm_addr) &&
memcmp(hw->mac.perm_addr, hw->mac.addr, ETH_ALEN))
interface->flags |= FM10K_FLAG_RESET_REQUESTED;

/* VLAN override was changed, or default VLAN changed */
if ((vlan_override != hw->mac.vlan_override) ||
(default_vid != hw->mac.default_vid))
interface->flags |= FM10K_FLAG_RESET_REQUESTED;

return 0;
}

/* generic error handler for mailbox issues */
static s32 fm10k_mbx_error(struct fm10k_hw *hw, u32 **results,
struct fm10k_mbx_info *mbx)
Expand All @@ -1019,6 +1072,46 @@ static s32 fm10k_mbx_error(struct fm10k_hw *hw, u32 **results,
return 0;
}

static const struct fm10k_msg_data vf_mbx_data[] = {
FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test),
FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_mbx_mac_addr),
FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_msg_lport_state_vf),
FM10K_TLV_MSG_ERROR_HANDLER(fm10k_mbx_error),
};

static int fm10k_mbx_request_irq_vf(struct fm10k_intfc *interface)
{
struct msix_entry *entry = &interface->msix_entries[FM10K_MBX_VECTOR];
struct net_device *dev = interface->netdev;
struct fm10k_hw *hw = &interface->hw;
int err;

/* Use timer0 for interrupt moderation on the mailbox */
u32 itr = FM10K_INT_MAP_TIMER0 | entry->entry;

/* register mailbox handlers */
err = hw->mbx.ops.register_handlers(&hw->mbx, vf_mbx_data);
if (err)
return err;

/* request the IRQ */
err = request_irq(entry->vector, fm10k_msix_mbx_vf, 0,
dev->name, interface);
if (err) {
netif_err(interface, probe, dev,
"request_irq for msix_mbx failed: %d\n", err);
return err;
}

/* map all of the interrupt sources */
fm10k_write_reg(hw, FM10K_VFINT_MAP, itr);

/* enable interrupt */
fm10k_write_reg(hw, FM10K_VFITR(entry->entry), FM10K_ITR_ENABLE);

return 0;
}

static s32 fm10k_lport_map(struct fm10k_hw *hw, u32 **results,
struct fm10k_mbx_info *mbx)
{
Expand Down Expand Up @@ -1142,7 +1235,10 @@ int fm10k_mbx_request_irq(struct fm10k_intfc *interface)
int err;

/* enable Mailbox cause */
err = fm10k_mbx_request_irq_pf(interface);
if (hw->mac.type == fm10k_mac_pf)
err = fm10k_mbx_request_irq_pf(interface);
else
err = fm10k_mbx_request_irq_vf(interface);

/* connect mailbox */
if (!err)
Expand Down Expand Up @@ -1220,7 +1316,9 @@ int fm10k_qv_request_irq(struct fm10k_intfc *interface)
}

/* Assign ITR register to q_vector */
q_vector->itr = &interface->uc_addr[FM10K_ITR(entry->entry)];
q_vector->itr = (hw->mac.type == fm10k_mac_pf) ?
&interface->uc_addr[FM10K_ITR(entry->entry)] :
&interface->uc_addr[FM10K_VFITR(entry->entry)];

/* request the IRQ */
err = request_irq(entry->vector, &fm10k_msix_clean_rings, 0,
Expand Down
Loading

0 comments on commit 5cb8db4

Please sign in to comment.