Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 255673
b: refs/heads/master
c: e4911d5
h: refs/heads/master
i:
  255671: b56d0a5
v: v3
  • Loading branch information
Alexander Duyck authored and Jeff Kirsher committed Jun 24, 2011
1 parent 9a28000 commit 9c0f837
Show file tree
Hide file tree
Showing 3 changed files with 291 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 3e05334f8be83e8529f1cbf4f4dea06a4d51d676
refs/heads/master: e4911d57a45ca30771c64b56e552891fcd105070
245 changes: 245 additions & 0 deletions trunk/drivers/net/ixgbe/ixgbe_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -2456,6 +2456,250 @@ static int ixgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
return ret;
}

static int ixgbe_update_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
struct ixgbe_fdir_filter *input,
u16 sw_idx)
{
struct ixgbe_hw *hw = &adapter->hw;
struct hlist_node *node, *node2, *parent;
struct ixgbe_fdir_filter *rule;
int err = -EINVAL;

parent = NULL;
rule = NULL;

hlist_for_each_entry_safe(rule, node, node2,
&adapter->fdir_filter_list, fdir_node) {
/* hash found, or no matching entry */
if (rule->sw_idx >= sw_idx)
break;
parent = node;
}

/* if there is an old rule occupying our place remove it */
if (rule && (rule->sw_idx == sw_idx)) {
if (!input || (rule->filter.formatted.bkt_hash !=
input->filter.formatted.bkt_hash)) {
err = ixgbe_fdir_erase_perfect_filter_82599(hw,
&rule->filter,
sw_idx);
}

hlist_del(&rule->fdir_node);
kfree(rule);
adapter->fdir_filter_count--;
}

/*
* If no input this was a delete, err should be 0 if a rule was
* successfully found and removed from the list else -EINVAL
*/
if (!input)
return err;

/* initialize node and set software index */
INIT_HLIST_NODE(&input->fdir_node);

/* add filter to the list */
if (parent)
hlist_add_after(parent, &input->fdir_node);
else
hlist_add_head(&input->fdir_node,
&adapter->fdir_filter_list);

/* update counts */
adapter->fdir_filter_count++;

return 0;
}

static int ixgbe_flowspec_to_flow_type(struct ethtool_rx_flow_spec *fsp,
u8 *flow_type)
{
switch (fsp->flow_type & ~FLOW_EXT) {
case TCP_V4_FLOW:
*flow_type = IXGBE_ATR_FLOW_TYPE_TCPV4;
break;
case UDP_V4_FLOW:
*flow_type = IXGBE_ATR_FLOW_TYPE_UDPV4;
break;
case SCTP_V4_FLOW:
*flow_type = IXGBE_ATR_FLOW_TYPE_SCTPV4;
break;
case IP_USER_FLOW:
switch (fsp->h_u.usr_ip4_spec.proto) {
case IPPROTO_TCP:
*flow_type = IXGBE_ATR_FLOW_TYPE_TCPV4;
break;
case IPPROTO_UDP:
*flow_type = IXGBE_ATR_FLOW_TYPE_UDPV4;
break;
case IPPROTO_SCTP:
*flow_type = IXGBE_ATR_FLOW_TYPE_SCTPV4;
break;
case 0:
if (!fsp->m_u.usr_ip4_spec.proto) {
*flow_type = IXGBE_ATR_FLOW_TYPE_IPV4;
break;
}
default:
return 0;
}
break;
default:
return 0;
}

return 1;
}

static int ixgbe_add_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
struct ethtool_rxnfc *cmd)
{
struct ethtool_rx_flow_spec *fsp =
(struct ethtool_rx_flow_spec *)&cmd->fs;
struct ixgbe_hw *hw = &adapter->hw;
struct ixgbe_fdir_filter *input;
union ixgbe_atr_input mask;
int err;

if (!(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
return -EOPNOTSUPP;

/*
* Don't allow programming if the action is a queue greater than
* the number of online Rx queues.
*/
if ((fsp->ring_cookie != RX_CLS_FLOW_DISC) &&
(fsp->ring_cookie >= adapter->num_rx_queues))
return -EINVAL;

/* Don't allow indexes to exist outside of available space */
if (fsp->location >= ((1024 << adapter->fdir_pballoc) - 2)) {
e_err(drv, "Location out of range\n");
return -EINVAL;
}

input = kzalloc(sizeof(*input), GFP_ATOMIC);
if (!input)
return -ENOMEM;

memset(&mask, 0, sizeof(union ixgbe_atr_input));

/* set SW index */
input->sw_idx = fsp->location;

/* record flow type */
if (!ixgbe_flowspec_to_flow_type(fsp,
&input->filter.formatted.flow_type)) {
e_err(drv, "Unrecognized flow type\n");
goto err_out;
}

mask.formatted.flow_type = IXGBE_ATR_L4TYPE_IPV6_MASK |
IXGBE_ATR_L4TYPE_MASK;

if (input->filter.formatted.flow_type == IXGBE_ATR_FLOW_TYPE_IPV4)
mask.formatted.flow_type &= IXGBE_ATR_L4TYPE_IPV6_MASK;

/* Copy input into formatted structures */
input->filter.formatted.src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
mask.formatted.src_ip[0] = fsp->m_u.tcp_ip4_spec.ip4src;
input->filter.formatted.dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;
mask.formatted.dst_ip[0] = fsp->m_u.tcp_ip4_spec.ip4dst;
input->filter.formatted.src_port = fsp->h_u.tcp_ip4_spec.psrc;
mask.formatted.src_port = fsp->m_u.tcp_ip4_spec.psrc;
input->filter.formatted.dst_port = fsp->h_u.tcp_ip4_spec.pdst;
mask.formatted.dst_port = fsp->m_u.tcp_ip4_spec.pdst;

if (fsp->flow_type & FLOW_EXT) {
input->filter.formatted.vm_pool =
(unsigned char)ntohl(fsp->h_ext.data[1]);
mask.formatted.vm_pool =
(unsigned char)ntohl(fsp->m_ext.data[1]);
input->filter.formatted.vlan_id = fsp->h_ext.vlan_tci;
mask.formatted.vlan_id = fsp->m_ext.vlan_tci;
input->filter.formatted.flex_bytes =
fsp->h_ext.vlan_etype;
mask.formatted.flex_bytes = fsp->m_ext.vlan_etype;
}

/* determine if we need to drop or route the packet */
if (fsp->ring_cookie == RX_CLS_FLOW_DISC)
input->action = IXGBE_FDIR_DROP_QUEUE;
else
input->action = fsp->ring_cookie;

spin_lock(&adapter->fdir_perfect_lock);

if (hlist_empty(&adapter->fdir_filter_list)) {
/* save mask and program input mask into HW */
memcpy(&adapter->fdir_mask, &mask, sizeof(mask));
err = ixgbe_fdir_set_input_mask_82599(hw, &mask);
if (err) {
e_err(drv, "Error writing mask\n");
goto err_out_w_lock;
}
} else if (memcmp(&adapter->fdir_mask, &mask, sizeof(mask))) {
e_err(drv, "Only one mask supported per port\n");
goto err_out_w_lock;
}

/* apply mask and compute/store hash */
ixgbe_atr_compute_perfect_hash_82599(&input->filter, &mask);

/* program filters to filter memory */
err = ixgbe_fdir_write_perfect_filter_82599(hw,
&input->filter, input->sw_idx,
adapter->rx_ring[input->action]->reg_idx);
if (err)
goto err_out_w_lock;

ixgbe_update_ethtool_fdir_entry(adapter, input, input->sw_idx);

spin_unlock(&adapter->fdir_perfect_lock);

return err;
err_out_w_lock:
spin_unlock(&adapter->fdir_perfect_lock);
err_out:
kfree(input);
return -EINVAL;
}

static int ixgbe_del_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
struct ethtool_rxnfc *cmd)
{
struct ethtool_rx_flow_spec *fsp =
(struct ethtool_rx_flow_spec *)&cmd->fs;
int err;

spin_lock(&adapter->fdir_perfect_lock);
err = ixgbe_update_ethtool_fdir_entry(adapter, NULL, fsp->location);
spin_unlock(&adapter->fdir_perfect_lock);

return err;
}

static int ixgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
{
struct ixgbe_adapter *adapter = netdev_priv(dev);
int ret = -EOPNOTSUPP;

switch (cmd->cmd) {
case ETHTOOL_SRXCLSRLINS:
ret = ixgbe_add_ethtool_fdir_entry(adapter, cmd);
break;
case ETHTOOL_SRXCLSRLDEL:
ret = ixgbe_del_ethtool_fdir_entry(adapter, cmd);
break;
default:
break;
}

return ret;
}

static const struct ethtool_ops ixgbe_ethtool_ops = {
.get_settings = ixgbe_get_settings,
.set_settings = ixgbe_set_settings,
Expand Down Expand Up @@ -2492,6 +2736,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = {
.get_flags = ethtool_op_get_flags,
.set_flags = ixgbe_set_flags,
.get_rxnfc = ixgbe_get_rxnfc,
.set_rxnfc = ixgbe_set_rxnfc,
};

void ixgbe_set_ethtool_ops(struct net_device *netdev)
Expand Down
45 changes: 45 additions & 0 deletions trunk/drivers/net/ixgbe/ixgbe_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3741,6 +3741,28 @@ static void ixgbe_configure_pb(struct ixgbe_adapter *adapter)
hw->mac.ops.set_rxpba(&adapter->hw, num_tc, hdrm, PBA_STRATEGY_EQUAL);
}

static void ixgbe_fdir_filter_restore(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
struct hlist_node *node, *node2;
struct ixgbe_fdir_filter *filter;

spin_lock(&adapter->fdir_perfect_lock);

if (!hlist_empty(&adapter->fdir_filter_list))
ixgbe_fdir_set_input_mask_82599(hw, &adapter->fdir_mask);

hlist_for_each_entry_safe(filter, node, node2,
&adapter->fdir_filter_list, fdir_node) {
ixgbe_fdir_write_perfect_filter_82599(hw,
&filter->filter,
filter->sw_idx,
filter->action);
}

spin_unlock(&adapter->fdir_perfect_lock);
}

static void ixgbe_configure(struct ixgbe_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
Expand All @@ -3765,6 +3787,10 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter)
adapter->tx_ring[i]->atr_sample_rate =
adapter->atr_sample_rate;
ixgbe_init_fdir_signature_82599(hw, adapter->fdir_pballoc);
} else if (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) {
ixgbe_init_fdir_perfect_82599(&adapter->hw,
adapter->fdir_pballoc);
ixgbe_fdir_filter_restore(adapter);
}
ixgbe_configure_virtualization(adapter);

Expand Down Expand Up @@ -4141,6 +4167,23 @@ static void ixgbe_clean_all_tx_rings(struct ixgbe_adapter *adapter)
ixgbe_clean_tx_ring(adapter->tx_ring[i]);
}

static void ixgbe_fdir_filter_exit(struct ixgbe_adapter *adapter)
{
struct hlist_node *node, *node2;
struct ixgbe_fdir_filter *filter;

spin_lock(&adapter->fdir_perfect_lock);

hlist_for_each_entry_safe(filter, node, node2,
&adapter->fdir_filter_list, fdir_node) {
hlist_del(&filter->fdir_node);
kfree(filter);
}
adapter->fdir_filter_count = 0;

spin_unlock(&adapter->fdir_perfect_lock);
}

void ixgbe_down(struct ixgbe_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
Expand Down Expand Up @@ -5527,6 +5570,8 @@ static int ixgbe_close(struct net_device *netdev)
ixgbe_down(adapter);
ixgbe_free_irq(adapter);

ixgbe_fdir_filter_exit(adapter);

ixgbe_free_all_tx_resources(adapter);
ixgbe_free_all_rx_resources(adapter);

Expand Down

0 comments on commit 9c0f837

Please sign in to comment.