aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/cisco
diff options
context:
space:
mode:
authorGovindarajulu Varadarajan <_govind@gmx.com>2014-06-23 06:38:00 -0400
committerDavid S. Miller <davem@davemloft.net>2014-06-23 17:32:19 -0400
commit631185273b6e1f8e0b5a00c1aca08650b2d18a57 (patch)
tree4ac92e09234d69b33ff4826af4eed9f94cc30dc5 /drivers/net/ethernet/cisco
parent10cc88446cec4eee8e2efab24ad387d52ef1f4fb (diff)
enic: devcmd for adding IP 5 tuple hardware filters
This patch adds interface to add and delete IP 5 tuple filter. This interface is used by Accelerated RFS code to steer a flow to corresponding receive queue. As of now adaptor supports only ipv4 + tcp/udp packet steering. Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/cisco')
-rw-r--r--drivers/net/ethernet/cisco/enic/Makefile2
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_clsf.c66
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_clsf.h10
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_dev.c61
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_dev.h2
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_devcmd.h5
6 files changed, 145 insertions, 1 deletions
diff --git a/drivers/net/ethernet/cisco/enic/Makefile b/drivers/net/ethernet/cisco/enic/Makefile
index 239e1e46545d..aadcaf7876ce 100644
--- a/drivers/net/ethernet/cisco/enic/Makefile
+++ b/drivers/net/ethernet/cisco/enic/Makefile
@@ -2,5 +2,5 @@ obj-$(CONFIG_ENIC) := enic.o
2 2
3enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \ 3enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \
4 enic_res.o enic_dev.o enic_pp.o vnic_dev.o vnic_rq.o vnic_vic.o \ 4 enic_res.o enic_dev.o enic_pp.o vnic_dev.o vnic_rq.o vnic_vic.o \
5 enic_ethtool.o enic_api.o 5 enic_ethtool.o enic_api.o enic_clsf.o
6 6
diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c
new file mode 100644
index 000000000000..f6703c4f76a9
--- /dev/null
+++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c
@@ -0,0 +1,66 @@
1#include <linux/if.h>
2#include <linux/if_ether.h>
3#include <linux/if_link.h>
4#include <linux/netdevice.h>
5#include <linux/in.h>
6#include <linux/types.h>
7#include <linux/skbuff.h>
8#include <net/flow_keys.h>
9#include "enic_res.h"
10#include "enic_clsf.h"
11
12/* enic_addfltr_5t - Add ipv4 5tuple filter
13 * @enic: enic struct of vnic
14 * @keys: flow_keys of ipv4 5tuple
15 * @rq: rq number to steer to
16 *
17 * This function returns filter_id(hardware_id) of the filter
18 * added. In case of error it returns an negative number.
19 */
20int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq)
21{
22 int res;
23 struct filter data;
24
25 switch (keys->ip_proto) {
26 case IPPROTO_TCP:
27 data.u.ipv4.protocol = PROTO_TCP;
28 break;
29 case IPPROTO_UDP:
30 data.u.ipv4.protocol = PROTO_UDP;
31 break;
32 default:
33 return -EPROTONOSUPPORT;
34 };
35 data.type = FILTER_IPV4_5TUPLE;
36 data.u.ipv4.src_addr = ntohl(keys->src);
37 data.u.ipv4.dst_addr = ntohl(keys->dst);
38 data.u.ipv4.src_port = ntohs(keys->port16[0]);
39 data.u.ipv4.dst_port = ntohs(keys->port16[1]);
40 data.u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE;
41
42 spin_lock_bh(&enic->devcmd_lock);
43 res = vnic_dev_classifier(enic->vdev, CLSF_ADD, &rq, &data);
44 spin_unlock_bh(&enic->devcmd_lock);
45 res = (res == 0) ? rq : res;
46
47 return res;
48}
49
50/* enic_delfltr - Delete clsf filter
51 * @enic: enic struct of vnic
52 * @filter_id: filter_is(hardware_id) of filter to be deleted
53 *
54 * This function returns zero in case of success, negative number incase of
55 * error.
56 */
57int enic_delfltr(struct enic *enic, u16 filter_id)
58{
59 int ret;
60
61 spin_lock_bh(&enic->devcmd_lock);
62 ret = vnic_dev_classifier(enic->vdev, CLSF_DEL, &filter_id, NULL);
63 spin_unlock_bh(&enic->devcmd_lock);
64
65 return ret;
66}
diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.h b/drivers/net/ethernet/cisco/enic/enic_clsf.h
new file mode 100644
index 000000000000..b6925b368b77
--- /dev/null
+++ b/drivers/net/ethernet/cisco/enic/enic_clsf.h
@@ -0,0 +1,10 @@
1#ifndef _ENIC_CLSF_H_
2#define _ENIC_CLSF_H_
3
4#include "vnic_dev.h"
5#include "enic.h"
6
7int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq);
8int enic_delfltr(struct enic *enic, u16 filter_id);
9
10#endif /* _ENIC_CLSF_H_ */
diff --git a/drivers/net/ethernet/cisco/enic/vnic_dev.c b/drivers/net/ethernet/cisco/enic/vnic_dev.c
index 263081b8e636..5abc496bcf29 100644
--- a/drivers/net/ethernet/cisco/enic/vnic_dev.c
+++ b/drivers/net/ethernet/cisco/enic/vnic_dev.c
@@ -1048,3 +1048,64 @@ int vnic_dev_set_mac_addr(struct vnic_dev *vdev, u8 *mac_addr)
1048 1048
1049 return vnic_dev_cmd(vdev, CMD_SET_MAC_ADDR, &a0, &a1, wait); 1049 return vnic_dev_cmd(vdev, CMD_SET_MAC_ADDR, &a0, &a1, wait);
1050} 1050}
1051
1052/* vnic_dev_classifier: Add/Delete classifier entries
1053 * @vdev: vdev of the device
1054 * @cmd: CLSF_ADD for Add filter
1055 * CLSF_DEL for Delete filter
1056 * @entry: In case of ADD filter, the caller passes the RQ number in this
1057 * variable.
1058 *
1059 * This function stores the filter_id returned by the firmware in the
1060 * same variable before return;
1061 *
1062 * In case of DEL filter, the caller passes the RQ number. Return
1063 * value is irrelevant.
1064 * @data: filter data
1065 */
1066int vnic_dev_classifier(struct vnic_dev *vdev, u8 cmd, u16 *entry,
1067 struct filter *data)
1068{
1069 u64 a0, a1;
1070 int wait = 1000;
1071 dma_addr_t tlv_pa;
1072 int ret = -EINVAL;
1073 struct filter_tlv *tlv, *tlv_va;
1074 struct filter_action *action;
1075 u64 tlv_size;
1076
1077 if (cmd == CLSF_ADD) {
1078 tlv_size = sizeof(struct filter) +
1079 sizeof(struct filter_action) +
1080 2 * sizeof(struct filter_tlv);
1081 tlv_va = pci_alloc_consistent(vdev->pdev, tlv_size, &tlv_pa);
1082 if (!tlv_va)
1083 return -ENOMEM;
1084 tlv = tlv_va;
1085 a0 = tlv_pa;
1086 a1 = tlv_size;
1087 memset(tlv, 0, tlv_size);
1088 tlv->type = CLSF_TLV_FILTER;
1089 tlv->length = sizeof(struct filter);
1090 *(struct filter *)&tlv->val = *data;
1091
1092 tlv = (struct filter_tlv *)((char *)tlv +
1093 sizeof(struct filter_tlv) +
1094 sizeof(struct filter));
1095
1096 tlv->type = CLSF_TLV_ACTION;
1097 tlv->length = sizeof(struct filter_action);
1098 action = (struct filter_action *)&tlv->val;
1099 action->type = FILTER_ACTION_RQ_STEERING;
1100 action->u.rq_idx = *entry;
1101
1102 ret = vnic_dev_cmd(vdev, CMD_ADD_FILTER, &a0, &a1, wait);
1103 *entry = (u16)a0;
1104 pci_free_consistent(vdev->pdev, tlv_size, tlv_va, tlv_pa);
1105 } else if (cmd == CLSF_DEL) {
1106 a0 = *entry;
1107 ret = vnic_dev_cmd(vdev, CMD_DEL_FILTER, &a0, &a1, wait);
1108 }
1109
1110 return ret;
1111}
diff --git a/drivers/net/ethernet/cisco/enic/vnic_dev.h b/drivers/net/ethernet/cisco/enic/vnic_dev.h
index 1f3b301f8225..1fb214efceba 100644
--- a/drivers/net/ethernet/cisco/enic/vnic_dev.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_dev.h
@@ -133,5 +133,7 @@ int vnic_dev_enable2(struct vnic_dev *vdev, int active);
133int vnic_dev_enable2_done(struct vnic_dev *vdev, int *status); 133int vnic_dev_enable2_done(struct vnic_dev *vdev, int *status);
134int vnic_dev_deinit_done(struct vnic_dev *vdev, int *status); 134int vnic_dev_deinit_done(struct vnic_dev *vdev, int *status);
135int vnic_dev_set_mac_addr(struct vnic_dev *vdev, u8 *mac_addr); 135int vnic_dev_set_mac_addr(struct vnic_dev *vdev, u8 *mac_addr);
136int vnic_dev_classifier(struct vnic_dev *vdev, u8 cmd, u16 *entry,
137 struct filter *data);
136 138
137#endif /* _VNIC_DEV_H_ */ 139#endif /* _VNIC_DEV_H_ */
diff --git a/drivers/net/ethernet/cisco/enic/vnic_devcmd.h b/drivers/net/ethernet/cisco/enic/vnic_devcmd.h
index b9a0d78fd639..435d0cd96c22 100644
--- a/drivers/net/ethernet/cisco/enic/vnic_devcmd.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_devcmd.h
@@ -603,6 +603,11 @@ struct filter_tlv {
603 u_int32_t val[0]; 603 u_int32_t val[0];
604}; 604};
605 605
606enum {
607 CLSF_ADD = 0,
608 CLSF_DEL = 1,
609};
610
606/* 611/*
607 * Writing cmd register causes STAT_BUSY to get set in status register. 612 * Writing cmd register causes STAT_BUSY to get set in status register.
608 * When cmd completes, STAT_BUSY will be cleared. 613 * When cmd completes, STAT_BUSY will be cleared.