1e3cf00d0SUpinder Malhi /* 2e3cf00d0SUpinder Malhi * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved. 3e3cf00d0SUpinder Malhi * 43805eadeSJeff Squyres * This software is available to you under a choice of one of two 53805eadeSJeff Squyres * licenses. You may choose to be licensed under the terms of the GNU 63805eadeSJeff Squyres * General Public License (GPL) Version 2, available from the file 73805eadeSJeff Squyres * COPYING in the main directory of this source tree, or the 83805eadeSJeff Squyres * BSD license below: 93805eadeSJeff Squyres * 103805eadeSJeff Squyres * Redistribution and use in source and binary forms, with or 113805eadeSJeff Squyres * without modification, are permitted provided that the following 123805eadeSJeff Squyres * conditions are met: 133805eadeSJeff Squyres * 143805eadeSJeff Squyres * - Redistributions of source code must retain the above 153805eadeSJeff Squyres * copyright notice, this list of conditions and the following 163805eadeSJeff Squyres * disclaimer. 173805eadeSJeff Squyres * 183805eadeSJeff Squyres * - Redistributions in binary form must reproduce the above 193805eadeSJeff Squyres * copyright notice, this list of conditions and the following 203805eadeSJeff Squyres * disclaimer in the documentation and/or other materials 213805eadeSJeff Squyres * provided with the distribution. 22e3cf00d0SUpinder Malhi * 23e3cf00d0SUpinder Malhi * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24e3cf00d0SUpinder Malhi * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25e3cf00d0SUpinder Malhi * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26e3cf00d0SUpinder Malhi * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27e3cf00d0SUpinder Malhi * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28e3cf00d0SUpinder Malhi * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29e3cf00d0SUpinder Malhi * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30e3cf00d0SUpinder Malhi * SOFTWARE. 31e3cf00d0SUpinder Malhi * 32e3cf00d0SUpinder Malhi */ 33e3cf00d0SUpinder Malhi #include <linux/netdevice.h> 34e3cf00d0SUpinder Malhi #include <linux/pci.h> 35e3cf00d0SUpinder Malhi 36e3cf00d0SUpinder Malhi #include "enic_api.h" 37e3cf00d0SUpinder Malhi #include "usnic_common_pkt_hdr.h" 38e3cf00d0SUpinder Malhi #include "usnic_fwd.h" 39e3cf00d0SUpinder Malhi #include "usnic_log.h" 40e3cf00d0SUpinder Malhi 412183b990SUpinder Malhi static int usnic_fwd_devcmd_locked(struct usnic_fwd_dev *ufdev, int vnic_idx, 422183b990SUpinder Malhi enum vnic_devcmd_cmd cmd, u64 *a0, 432183b990SUpinder Malhi u64 *a1) 442183b990SUpinder Malhi { 452183b990SUpinder Malhi int status; 462183b990SUpinder Malhi struct net_device *netdev = ufdev->netdev; 472183b990SUpinder Malhi 482183b990SUpinder Malhi lockdep_assert_held(&ufdev->lock); 492183b990SUpinder Malhi 502183b990SUpinder Malhi status = enic_api_devcmd_proxy_by_index(netdev, 512183b990SUpinder Malhi vnic_idx, 522183b990SUpinder Malhi cmd, 532183b990SUpinder Malhi a0, a1, 542183b990SUpinder Malhi 1000); 552183b990SUpinder Malhi if (status) { 562183b990SUpinder Malhi if (status == ERR_EINVAL && cmd == CMD_DEL_FILTER) { 572183b990SUpinder Malhi usnic_dbg("Dev %s vnic idx %u cmd %u already deleted", 582183b990SUpinder Malhi ufdev->name, vnic_idx, cmd); 592183b990SUpinder Malhi } else { 602183b990SUpinder Malhi usnic_err("Dev %s vnic idx %u cmd %u failed with status %d\n", 612183b990SUpinder Malhi ufdev->name, vnic_idx, cmd, 622183b990SUpinder Malhi status); 632183b990SUpinder Malhi } 642183b990SUpinder Malhi } else { 652183b990SUpinder Malhi usnic_dbg("Dev %s vnic idx %u cmd %u success", 662183b990SUpinder Malhi ufdev->name, vnic_idx, cmd); 672183b990SUpinder Malhi } 682183b990SUpinder Malhi 692183b990SUpinder Malhi return status; 702183b990SUpinder Malhi } 712183b990SUpinder Malhi 722183b990SUpinder Malhi static int usnic_fwd_devcmd(struct usnic_fwd_dev *ufdev, int vnic_idx, 732183b990SUpinder Malhi enum vnic_devcmd_cmd cmd, u64 *a0, u64 *a1) 742183b990SUpinder Malhi { 752183b990SUpinder Malhi int status; 762183b990SUpinder Malhi 772183b990SUpinder Malhi spin_lock(&ufdev->lock); 782183b990SUpinder Malhi status = usnic_fwd_devcmd_locked(ufdev, vnic_idx, cmd, a0, a1); 792183b990SUpinder Malhi spin_unlock(&ufdev->lock); 802183b990SUpinder Malhi 812183b990SUpinder Malhi return status; 822183b990SUpinder Malhi } 832183b990SUpinder Malhi 84e3cf00d0SUpinder Malhi struct usnic_fwd_dev *usnic_fwd_dev_alloc(struct pci_dev *pdev) 85e3cf00d0SUpinder Malhi { 86e3cf00d0SUpinder Malhi struct usnic_fwd_dev *ufdev; 87e3cf00d0SUpinder Malhi 88e3cf00d0SUpinder Malhi ufdev = kzalloc(sizeof(*ufdev), GFP_KERNEL); 89e3cf00d0SUpinder Malhi if (!ufdev) 90e3cf00d0SUpinder Malhi return NULL; 91e3cf00d0SUpinder Malhi 92e3cf00d0SUpinder Malhi ufdev->pdev = pdev; 93e3cf00d0SUpinder Malhi ufdev->netdev = pci_get_drvdata(pdev); 94e3cf00d0SUpinder Malhi spin_lock_init(&ufdev->lock); 957cfcc71eSBart Van Assche BUILD_BUG_ON(sizeof(ufdev->name) != sizeof(ufdev->netdev->name)); 967cfcc71eSBart Van Assche strcpy(ufdev->name, ufdev->netdev->name); 97e3cf00d0SUpinder Malhi 98e3cf00d0SUpinder Malhi return ufdev; 99e3cf00d0SUpinder Malhi } 100e3cf00d0SUpinder Malhi 101e3cf00d0SUpinder Malhi void usnic_fwd_dev_free(struct usnic_fwd_dev *ufdev) 102e3cf00d0SUpinder Malhi { 103e3cf00d0SUpinder Malhi kfree(ufdev); 104e3cf00d0SUpinder Malhi } 105e3cf00d0SUpinder Malhi 1062183b990SUpinder Malhi void usnic_fwd_set_mac(struct usnic_fwd_dev *ufdev, char mac[ETH_ALEN]) 107e3cf00d0SUpinder Malhi { 108e3cf00d0SUpinder Malhi spin_lock(&ufdev->lock); 1092183b990SUpinder Malhi memcpy(&ufdev->mac, mac, sizeof(ufdev->mac)); 110e3cf00d0SUpinder Malhi spin_unlock(&ufdev->lock); 111e3cf00d0SUpinder Malhi } 112e3cf00d0SUpinder Malhi 1135d50f400SLeon Romanovsky void usnic_fwd_add_ipaddr(struct usnic_fwd_dev *ufdev, __be32 inaddr) 1143f92bed3SUpinder Malhi { 1153f92bed3SUpinder Malhi spin_lock(&ufdev->lock); 1165d50f400SLeon Romanovsky if (!ufdev->inaddr) 1173f92bed3SUpinder Malhi ufdev->inaddr = inaddr; 1183f92bed3SUpinder Malhi spin_unlock(&ufdev->lock); 1193f92bed3SUpinder Malhi } 1203f92bed3SUpinder Malhi 1213f92bed3SUpinder Malhi void usnic_fwd_del_ipaddr(struct usnic_fwd_dev *ufdev) 1223f92bed3SUpinder Malhi { 1233f92bed3SUpinder Malhi spin_lock(&ufdev->lock); 1243f92bed3SUpinder Malhi ufdev->inaddr = 0; 1253f92bed3SUpinder Malhi spin_unlock(&ufdev->lock); 1263f92bed3SUpinder Malhi } 1273f92bed3SUpinder Malhi 1282183b990SUpinder Malhi void usnic_fwd_carrier_up(struct usnic_fwd_dev *ufdev) 129e3cf00d0SUpinder Malhi { 1302183b990SUpinder Malhi spin_lock(&ufdev->lock); 1312183b990SUpinder Malhi ufdev->link_up = 1; 1322183b990SUpinder Malhi spin_unlock(&ufdev->lock); 133e3cf00d0SUpinder Malhi } 134e3cf00d0SUpinder Malhi 1352183b990SUpinder Malhi void usnic_fwd_carrier_down(struct usnic_fwd_dev *ufdev) 1362183b990SUpinder Malhi { 1372183b990SUpinder Malhi spin_lock(&ufdev->lock); 1382183b990SUpinder Malhi ufdev->link_up = 0; 1392183b990SUpinder Malhi spin_unlock(&ufdev->lock); 140e3cf00d0SUpinder Malhi } 141e3cf00d0SUpinder Malhi 1422183b990SUpinder Malhi void usnic_fwd_set_mtu(struct usnic_fwd_dev *ufdev, unsigned int mtu) 1432183b990SUpinder Malhi { 1442183b990SUpinder Malhi spin_lock(&ufdev->lock); 1452183b990SUpinder Malhi ufdev->mtu = mtu; 1462183b990SUpinder Malhi spin_unlock(&ufdev->lock); 1472183b990SUpinder Malhi } 1482183b990SUpinder Malhi 1492183b990SUpinder Malhi static int usnic_fwd_dev_ready_locked(struct usnic_fwd_dev *ufdev) 1502183b990SUpinder Malhi { 1512183b990SUpinder Malhi lockdep_assert_held(&ufdev->lock); 1522183b990SUpinder Malhi 1532183b990SUpinder Malhi if (!ufdev->link_up) 1542183b990SUpinder Malhi return -EPERM; 1552183b990SUpinder Malhi 1562183b990SUpinder Malhi return 0; 1572183b990SUpinder Malhi } 1582183b990SUpinder Malhi 1593f92bed3SUpinder Malhi static int validate_filter_locked(struct usnic_fwd_dev *ufdev, 1603f92bed3SUpinder Malhi struct filter *filter) 1613f92bed3SUpinder Malhi { 1623f92bed3SUpinder Malhi 1633f92bed3SUpinder Malhi lockdep_assert_held(&ufdev->lock); 1643f92bed3SUpinder Malhi 1653f92bed3SUpinder Malhi if (filter->type == FILTER_IPV4_5TUPLE) { 1663f92bed3SUpinder Malhi if (!(filter->u.ipv4.flags & FILTER_FIELD_5TUP_DST_AD)) 1673f92bed3SUpinder Malhi return -EACCES; 1683f92bed3SUpinder Malhi if (!(filter->u.ipv4.flags & FILTER_FIELD_5TUP_DST_PT)) 1693f92bed3SUpinder Malhi return -EBUSY; 1703f92bed3SUpinder Malhi else if (ufdev->inaddr == 0) 1713f92bed3SUpinder Malhi return -EINVAL; 1723f92bed3SUpinder Malhi else if (filter->u.ipv4.dst_port == 0) 1733f92bed3SUpinder Malhi return -ERANGE; 1743f92bed3SUpinder Malhi else if (ntohl(ufdev->inaddr) != filter->u.ipv4.dst_addr) 1753f92bed3SUpinder Malhi return -EFAULT; 1763f92bed3SUpinder Malhi else 1773f92bed3SUpinder Malhi return 0; 1783f92bed3SUpinder Malhi } 1793f92bed3SUpinder Malhi 1803f92bed3SUpinder Malhi return 0; 1813f92bed3SUpinder Malhi } 1823f92bed3SUpinder Malhi 1832183b990SUpinder Malhi static void fill_tlv(struct filter_tlv *tlv, struct filter *filter, 1842183b990SUpinder Malhi struct filter_action *action) 1852183b990SUpinder Malhi { 186e3cf00d0SUpinder Malhi tlv->type = CLSF_TLV_FILTER; 187e3cf00d0SUpinder Malhi tlv->length = sizeof(struct filter); 1882183b990SUpinder Malhi *((struct filter *)&tlv->val) = *filter; 1892183b990SUpinder Malhi 190e3cf00d0SUpinder Malhi tlv = (struct filter_tlv *)((char *)tlv + sizeof(struct filter_tlv) + 191e3cf00d0SUpinder Malhi sizeof(struct filter)); 192e3cf00d0SUpinder Malhi tlv->type = CLSF_TLV_ACTION; 193e3cf00d0SUpinder Malhi tlv->length = sizeof(struct filter_action); 1942183b990SUpinder Malhi *((struct filter_action *)&tlv->val) = *action; 1952183b990SUpinder Malhi } 196e3cf00d0SUpinder Malhi 1972183b990SUpinder Malhi struct usnic_fwd_flow* 1982183b990SUpinder Malhi usnic_fwd_alloc_flow(struct usnic_fwd_dev *ufdev, struct filter *filter, 1992183b990SUpinder Malhi struct usnic_filter_action *uaction) 2002183b990SUpinder Malhi { 2012183b990SUpinder Malhi struct filter_tlv *tlv; 2022183b990SUpinder Malhi struct pci_dev *pdev; 2032183b990SUpinder Malhi struct usnic_fwd_flow *flow; 2042183b990SUpinder Malhi uint64_t a0, a1; 2052183b990SUpinder Malhi uint64_t tlv_size; 2062183b990SUpinder Malhi dma_addr_t tlv_pa; 2072183b990SUpinder Malhi int status; 2082183b990SUpinder Malhi 2092183b990SUpinder Malhi pdev = ufdev->pdev; 2102183b990SUpinder Malhi tlv_size = (2*sizeof(struct filter_tlv) + sizeof(struct filter) + 2112183b990SUpinder Malhi sizeof(struct filter_action)); 2122183b990SUpinder Malhi 2132183b990SUpinder Malhi flow = kzalloc(sizeof(*flow), GFP_ATOMIC); 2142183b990SUpinder Malhi if (!flow) 2152183b990SUpinder Malhi return ERR_PTR(-ENOMEM); 2162183b990SUpinder Malhi 217*3e9fed7fSChristophe JAILLET tlv = dma_alloc_coherent(&pdev->dev, tlv_size, &tlv_pa, GFP_ATOMIC); 2182183b990SUpinder Malhi if (!tlv) { 2192183b990SUpinder Malhi usnic_err("Failed to allocate memory\n"); 2202183b990SUpinder Malhi status = -ENOMEM; 2212183b990SUpinder Malhi goto out_free_flow; 2222183b990SUpinder Malhi } 2232183b990SUpinder Malhi 2242183b990SUpinder Malhi fill_tlv(tlv, filter, &uaction->action); 2252183b990SUpinder Malhi 2262183b990SUpinder Malhi spin_lock(&ufdev->lock); 2272183b990SUpinder Malhi status = usnic_fwd_dev_ready_locked(ufdev); 2282183b990SUpinder Malhi if (status) { 2292183b990SUpinder Malhi usnic_err("Forwarding dev %s not ready with status %d\n", 2302183b990SUpinder Malhi ufdev->name, status); 2312183b990SUpinder Malhi goto out_free_tlv; 2322183b990SUpinder Malhi } 2332183b990SUpinder Malhi 2343f92bed3SUpinder Malhi status = validate_filter_locked(ufdev, filter); 2353f92bed3SUpinder Malhi if (status) { 2363f92bed3SUpinder Malhi usnic_err("Failed to validate filter with status %d\n", 2373f92bed3SUpinder Malhi status); 2383f92bed3SUpinder Malhi goto out_free_tlv; 2393f92bed3SUpinder Malhi } 2403f92bed3SUpinder Malhi 2412183b990SUpinder Malhi /* Issue Devcmd */ 2422183b990SUpinder Malhi a0 = tlv_pa; 2432183b990SUpinder Malhi a1 = tlv_size; 2442183b990SUpinder Malhi status = usnic_fwd_devcmd_locked(ufdev, uaction->vnic_idx, 2452183b990SUpinder Malhi CMD_ADD_FILTER, &a0, &a1); 246e3cf00d0SUpinder Malhi if (status) { 247e3cf00d0SUpinder Malhi usnic_err("VF %s Filter add failed with status:%d", 2482183b990SUpinder Malhi ufdev->name, status); 2492183b990SUpinder Malhi status = -EFAULT; 2502183b990SUpinder Malhi goto out_free_tlv; 251e3cf00d0SUpinder Malhi } else { 2522183b990SUpinder Malhi usnic_dbg("VF %s FILTER ID:%llu", ufdev->name, a0); 253e3cf00d0SUpinder Malhi } 254e3cf00d0SUpinder Malhi 2552183b990SUpinder Malhi flow->flow_id = (uint32_t) a0; 2562183b990SUpinder Malhi flow->vnic_idx = uaction->vnic_idx; 2572183b990SUpinder Malhi flow->ufdev = ufdev; 258e3cf00d0SUpinder Malhi 2592183b990SUpinder Malhi out_free_tlv: 2602183b990SUpinder Malhi spin_unlock(&ufdev->lock); 261*3e9fed7fSChristophe JAILLET dma_free_coherent(&pdev->dev, tlv_size, tlv, tlv_pa); 2622183b990SUpinder Malhi if (!status) 2632183b990SUpinder Malhi return flow; 2642183b990SUpinder Malhi out_free_flow: 2652183b990SUpinder Malhi kfree(flow); 2662183b990SUpinder Malhi return ERR_PTR(status); 267e3cf00d0SUpinder Malhi } 268e3cf00d0SUpinder Malhi 2692183b990SUpinder Malhi int usnic_fwd_dealloc_flow(struct usnic_fwd_flow *flow) 270e3cf00d0SUpinder Malhi { 271e3cf00d0SUpinder Malhi int status; 272e3cf00d0SUpinder Malhi u64 a0, a1; 273e3cf00d0SUpinder Malhi 2742183b990SUpinder Malhi a0 = flow->flow_id; 275e3cf00d0SUpinder Malhi 2762183b990SUpinder Malhi status = usnic_fwd_devcmd(flow->ufdev, flow->vnic_idx, 277e3cf00d0SUpinder Malhi CMD_DEL_FILTER, &a0, &a1); 278e3cf00d0SUpinder Malhi if (status) { 279e3cf00d0SUpinder Malhi if (status == ERR_EINVAL) { 280e3cf00d0SUpinder Malhi usnic_dbg("Filter %u already deleted for VF Idx %u pf: %s status: %d", 2812183b990SUpinder Malhi flow->flow_id, flow->vnic_idx, 2822183b990SUpinder Malhi flow->ufdev->name, status); 283e3cf00d0SUpinder Malhi } else { 284e3cf00d0SUpinder Malhi usnic_err("PF %s VF Idx %u Filter: %u FILTER DELETE failed with status %d", 2852183b990SUpinder Malhi flow->ufdev->name, flow->vnic_idx, 2862183b990SUpinder Malhi flow->flow_id, status); 287e3cf00d0SUpinder Malhi } 2882183b990SUpinder Malhi status = 0; 2892183b990SUpinder Malhi /* 2902183b990SUpinder Malhi * Log the error and fake success to the caller because if 2912183b990SUpinder Malhi * a flow fails to be deleted in the firmware, it is an 2922183b990SUpinder Malhi * unrecoverable error. 2932183b990SUpinder Malhi */ 294e3cf00d0SUpinder Malhi } else { 295e3cf00d0SUpinder Malhi usnic_dbg("PF %s VF Idx %u Filter: %u FILTER DELETED", 2962183b990SUpinder Malhi flow->ufdev->name, flow->vnic_idx, 2972183b990SUpinder Malhi flow->flow_id); 298e3cf00d0SUpinder Malhi } 299e3cf00d0SUpinder Malhi 3002183b990SUpinder Malhi kfree(flow); 301e3cf00d0SUpinder Malhi return status; 302e3cf00d0SUpinder Malhi } 303e3cf00d0SUpinder Malhi 3042183b990SUpinder Malhi int usnic_fwd_enable_qp(struct usnic_fwd_dev *ufdev, int vnic_idx, int qp_idx) 305e3cf00d0SUpinder Malhi { 306e3cf00d0SUpinder Malhi int status; 307e3cf00d0SUpinder Malhi struct net_device *pf_netdev; 308e3cf00d0SUpinder Malhi u64 a0, a1; 309e3cf00d0SUpinder Malhi 310e3cf00d0SUpinder Malhi pf_netdev = ufdev->netdev; 3112183b990SUpinder Malhi a0 = qp_idx; 312e3cf00d0SUpinder Malhi a1 = CMD_QP_RQWQ; 313e3cf00d0SUpinder Malhi 3142183b990SUpinder Malhi status = usnic_fwd_devcmd(ufdev, vnic_idx, CMD_QP_ENABLE, 3152183b990SUpinder Malhi &a0, &a1); 316e3cf00d0SUpinder Malhi if (status) { 317e3cf00d0SUpinder Malhi usnic_err("PF %s VNIC Index %u RQ Index: %u ENABLE Failed with status %d", 318e3cf00d0SUpinder Malhi netdev_name(pf_netdev), 319e3cf00d0SUpinder Malhi vnic_idx, 3202183b990SUpinder Malhi qp_idx, 321e3cf00d0SUpinder Malhi status); 322e3cf00d0SUpinder Malhi } else { 323e3cf00d0SUpinder Malhi usnic_dbg("PF %s VNIC Index %u RQ Index: %u ENABLED", 324e3cf00d0SUpinder Malhi netdev_name(pf_netdev), 3252183b990SUpinder Malhi vnic_idx, qp_idx); 326e3cf00d0SUpinder Malhi } 327e3cf00d0SUpinder Malhi 328e3cf00d0SUpinder Malhi return status; 329e3cf00d0SUpinder Malhi } 330e3cf00d0SUpinder Malhi 3312183b990SUpinder Malhi int usnic_fwd_disable_qp(struct usnic_fwd_dev *ufdev, int vnic_idx, int qp_idx) 332e3cf00d0SUpinder Malhi { 333e3cf00d0SUpinder Malhi int status; 334e3cf00d0SUpinder Malhi u64 a0, a1; 335e3cf00d0SUpinder Malhi struct net_device *pf_netdev; 336e3cf00d0SUpinder Malhi 337e3cf00d0SUpinder Malhi pf_netdev = ufdev->netdev; 3382183b990SUpinder Malhi a0 = qp_idx; 339e3cf00d0SUpinder Malhi a1 = CMD_QP_RQWQ; 340e3cf00d0SUpinder Malhi 3412183b990SUpinder Malhi status = usnic_fwd_devcmd(ufdev, vnic_idx, CMD_QP_DISABLE, 3422183b990SUpinder Malhi &a0, &a1); 343e3cf00d0SUpinder Malhi if (status) { 344e3cf00d0SUpinder Malhi usnic_err("PF %s VNIC Index %u RQ Index: %u DISABLE Failed with status %d", 345e3cf00d0SUpinder Malhi netdev_name(pf_netdev), 346e3cf00d0SUpinder Malhi vnic_idx, 3472183b990SUpinder Malhi qp_idx, 348e3cf00d0SUpinder Malhi status); 349e3cf00d0SUpinder Malhi } else { 350e3cf00d0SUpinder Malhi usnic_dbg("PF %s VNIC Index %u RQ Index: %u DISABLED", 351e3cf00d0SUpinder Malhi netdev_name(pf_netdev), 352e3cf00d0SUpinder Malhi vnic_idx, 3532183b990SUpinder Malhi qp_idx); 354e3cf00d0SUpinder Malhi } 355e3cf00d0SUpinder Malhi 356e3cf00d0SUpinder Malhi return status; 357e3cf00d0SUpinder Malhi } 358