2 * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved.
4 * This program is free software; you may redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
9 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
10 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
11 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
12 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
13 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18 #include <linux/netdevice.h>
19 #include <linux/pci.h>
22 #include "usnic_common_pkt_hdr.h"
23 #include "usnic_fwd.h"
24 #include "usnic_log.h"
26 static int usnic_fwd_devcmd_locked(struct usnic_fwd_dev
*ufdev
, int vnic_idx
,
27 enum vnic_devcmd_cmd cmd
, u64
*a0
,
31 struct net_device
*netdev
= ufdev
->netdev
;
33 lockdep_assert_held(&ufdev
->lock
);
35 status
= enic_api_devcmd_proxy_by_index(netdev
,
41 if (status
== ERR_EINVAL
&& cmd
== CMD_DEL_FILTER
) {
42 usnic_dbg("Dev %s vnic idx %u cmd %u already deleted",
43 ufdev
->name
, vnic_idx
, cmd
);
45 usnic_err("Dev %s vnic idx %u cmd %u failed with status %d\n",
46 ufdev
->name
, vnic_idx
, cmd
,
50 usnic_dbg("Dev %s vnic idx %u cmd %u success",
51 ufdev
->name
, vnic_idx
, cmd
);
57 static int usnic_fwd_devcmd(struct usnic_fwd_dev
*ufdev
, int vnic_idx
,
58 enum vnic_devcmd_cmd cmd
, u64
*a0
, u64
*a1
)
62 spin_lock(&ufdev
->lock
);
63 status
= usnic_fwd_devcmd_locked(ufdev
, vnic_idx
, cmd
, a0
, a1
);
64 spin_unlock(&ufdev
->lock
);
69 struct usnic_fwd_dev
*usnic_fwd_dev_alloc(struct pci_dev
*pdev
)
71 struct usnic_fwd_dev
*ufdev
;
73 ufdev
= kzalloc(sizeof(*ufdev
), GFP_KERNEL
);
78 ufdev
->netdev
= pci_get_drvdata(pdev
);
79 spin_lock_init(&ufdev
->lock
);
80 strncpy(ufdev
->name
, netdev_name(ufdev
->netdev
),
81 sizeof(ufdev
->name
) - 1);
86 void usnic_fwd_dev_free(struct usnic_fwd_dev
*ufdev
)
91 void usnic_fwd_set_mac(struct usnic_fwd_dev
*ufdev
, char mac
[ETH_ALEN
])
93 spin_lock(&ufdev
->lock
);
94 memcpy(&ufdev
->mac
, mac
, sizeof(ufdev
->mac
));
95 spin_unlock(&ufdev
->lock
);
98 int usnic_fwd_add_ipaddr(struct usnic_fwd_dev
*ufdev
, __be32 inaddr
)
102 spin_lock(&ufdev
->lock
);
103 if (ufdev
->inaddr
== 0) {
104 ufdev
->inaddr
= inaddr
;
109 spin_unlock(&ufdev
->lock
);
114 void usnic_fwd_del_ipaddr(struct usnic_fwd_dev
*ufdev
)
116 spin_lock(&ufdev
->lock
);
118 spin_unlock(&ufdev
->lock
);
121 void usnic_fwd_carrier_up(struct usnic_fwd_dev
*ufdev
)
123 spin_lock(&ufdev
->lock
);
125 spin_unlock(&ufdev
->lock
);
128 void usnic_fwd_carrier_down(struct usnic_fwd_dev
*ufdev
)
130 spin_lock(&ufdev
->lock
);
132 spin_unlock(&ufdev
->lock
);
135 void usnic_fwd_set_mtu(struct usnic_fwd_dev
*ufdev
, unsigned int mtu
)
137 spin_lock(&ufdev
->lock
);
139 spin_unlock(&ufdev
->lock
);
142 static int usnic_fwd_dev_ready_locked(struct usnic_fwd_dev
*ufdev
)
144 lockdep_assert_held(&ufdev
->lock
);
152 static int validate_filter_locked(struct usnic_fwd_dev
*ufdev
,
153 struct filter
*filter
)
156 lockdep_assert_held(&ufdev
->lock
);
158 if (filter
->type
== FILTER_IPV4_5TUPLE
) {
159 if (!(filter
->u
.ipv4
.flags
& FILTER_FIELD_5TUP_DST_AD
))
161 if (!(filter
->u
.ipv4
.flags
& FILTER_FIELD_5TUP_DST_PT
))
163 else if (ufdev
->inaddr
== 0)
165 else if (filter
->u
.ipv4
.dst_port
== 0)
167 else if (ntohl(ufdev
->inaddr
) != filter
->u
.ipv4
.dst_addr
)
176 static void fill_tlv(struct filter_tlv
*tlv
, struct filter
*filter
,
177 struct filter_action
*action
)
179 tlv
->type
= CLSF_TLV_FILTER
;
180 tlv
->length
= sizeof(struct filter
);
181 *((struct filter
*)&tlv
->val
) = *filter
;
183 tlv
= (struct filter_tlv
*)((char *)tlv
+ sizeof(struct filter_tlv
) +
184 sizeof(struct filter
));
185 tlv
->type
= CLSF_TLV_ACTION
;
186 tlv
->length
= sizeof(struct filter_action
);
187 *((struct filter_action
*)&tlv
->val
) = *action
;
190 struct usnic_fwd_flow
*
191 usnic_fwd_alloc_flow(struct usnic_fwd_dev
*ufdev
, struct filter
*filter
,
192 struct usnic_filter_action
*uaction
)
194 struct filter_tlv
*tlv
;
195 struct pci_dev
*pdev
;
196 struct usnic_fwd_flow
*flow
;
203 tlv_size
= (2*sizeof(struct filter_tlv
) + sizeof(struct filter
) +
204 sizeof(struct filter_action
));
206 flow
= kzalloc(sizeof(*flow
), GFP_ATOMIC
);
208 return ERR_PTR(-ENOMEM
);
210 tlv
= pci_alloc_consistent(pdev
, tlv_size
, &tlv_pa
);
212 usnic_err("Failed to allocate memory\n");
217 fill_tlv(tlv
, filter
, &uaction
->action
);
219 spin_lock(&ufdev
->lock
);
220 status
= usnic_fwd_dev_ready_locked(ufdev
);
222 usnic_err("Forwarding dev %s not ready with status %d\n",
223 ufdev
->name
, status
);
227 status
= validate_filter_locked(ufdev
, filter
);
229 usnic_err("Failed to validate filter with status %d\n",
237 status
= usnic_fwd_devcmd_locked(ufdev
, uaction
->vnic_idx
,
238 CMD_ADD_FILTER
, &a0
, &a1
);
240 usnic_err("VF %s Filter add failed with status:%d",
241 ufdev
->name
, status
);
245 usnic_dbg("VF %s FILTER ID:%llu", ufdev
->name
, a0
);
248 flow
->flow_id
= (uint32_t) a0
;
249 flow
->vnic_idx
= uaction
->vnic_idx
;
253 spin_unlock(&ufdev
->lock
);
254 pci_free_consistent(pdev
, tlv_size
, tlv
, tlv_pa
);
259 return ERR_PTR(status
);
262 int usnic_fwd_dealloc_flow(struct usnic_fwd_flow
*flow
)
269 status
= usnic_fwd_devcmd(flow
->ufdev
, flow
->vnic_idx
,
270 CMD_DEL_FILTER
, &a0
, &a1
);
272 if (status
== ERR_EINVAL
) {
273 usnic_dbg("Filter %u already deleted for VF Idx %u pf: %s status: %d",
274 flow
->flow_id
, flow
->vnic_idx
,
275 flow
->ufdev
->name
, status
);
277 usnic_err("PF %s VF Idx %u Filter: %u FILTER DELETE failed with status %d",
278 flow
->ufdev
->name
, flow
->vnic_idx
,
279 flow
->flow_id
, status
);
283 * Log the error and fake success to the caller because if
284 * a flow fails to be deleted in the firmware, it is an
285 * unrecoverable error.
288 usnic_dbg("PF %s VF Idx %u Filter: %u FILTER DELETED",
289 flow
->ufdev
->name
, flow
->vnic_idx
,
297 int usnic_fwd_enable_qp(struct usnic_fwd_dev
*ufdev
, int vnic_idx
, int qp_idx
)
300 struct net_device
*pf_netdev
;
303 pf_netdev
= ufdev
->netdev
;
307 status
= usnic_fwd_devcmd(ufdev
, vnic_idx
, CMD_QP_ENABLE
,
310 usnic_err("PF %s VNIC Index %u RQ Index: %u ENABLE Failed with status %d",
311 netdev_name(pf_netdev
),
316 usnic_dbg("PF %s VNIC Index %u RQ Index: %u ENABLED",
317 netdev_name(pf_netdev
),
324 int usnic_fwd_disable_qp(struct usnic_fwd_dev
*ufdev
, int vnic_idx
, int qp_idx
)
328 struct net_device
*pf_netdev
;
330 pf_netdev
= ufdev
->netdev
;
334 status
= usnic_fwd_devcmd(ufdev
, vnic_idx
, CMD_QP_DISABLE
,
337 usnic_err("PF %s VNIC Index %u RQ Index: %u DISABLE Failed with status %d",
338 netdev_name(pf_netdev
),
343 usnic_dbg("PF %s VNIC Index %u RQ Index: %u DISABLED",
344 netdev_name(pf_netdev
),