1e3cf00d0SUpinder Malhi /* 2e3cf00d0SUpinder Malhi * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved. 3e3cf00d0SUpinder Malhi * 4e3cf00d0SUpinder Malhi * This program is free software; you may redistribute it and/or modify 5e3cf00d0SUpinder Malhi * it under the terms of the GNU General Public License as published by 6e3cf00d0SUpinder Malhi * the Free Software Foundation; version 2 of the License. 7e3cf00d0SUpinder Malhi * 8e3cf00d0SUpinder Malhi * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 9e3cf00d0SUpinder Malhi * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 10e3cf00d0SUpinder Malhi * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 11e3cf00d0SUpinder Malhi * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 12e3cf00d0SUpinder Malhi * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 13e3cf00d0SUpinder Malhi * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14e3cf00d0SUpinder Malhi * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 15e3cf00d0SUpinder Malhi * SOFTWARE. 16e3cf00d0SUpinder Malhi * 17e3cf00d0SUpinder Malhi */ 18e3cf00d0SUpinder Malhi #include <linux/netdevice.h> 19e3cf00d0SUpinder Malhi #include <linux/pci.h> 20e3cf00d0SUpinder Malhi 21e3cf00d0SUpinder Malhi #include "enic_api.h" 22e3cf00d0SUpinder Malhi #include "usnic_common_pkt_hdr.h" 23e3cf00d0SUpinder Malhi #include "usnic_fwd.h" 24e3cf00d0SUpinder Malhi #include "usnic_log.h" 25e3cf00d0SUpinder Malhi 262183b990SUpinder Malhi static int usnic_fwd_devcmd_locked(struct usnic_fwd_dev *ufdev, int vnic_idx, 272183b990SUpinder Malhi enum vnic_devcmd_cmd cmd, u64 *a0, 282183b990SUpinder Malhi u64 *a1) 292183b990SUpinder Malhi { 302183b990SUpinder Malhi int status; 312183b990SUpinder Malhi struct net_device *netdev = ufdev->netdev; 322183b990SUpinder Malhi 332183b990SUpinder Malhi lockdep_assert_held(&ufdev->lock); 342183b990SUpinder Malhi 352183b990SUpinder Malhi status = enic_api_devcmd_proxy_by_index(netdev, 362183b990SUpinder Malhi vnic_idx, 372183b990SUpinder Malhi cmd, 382183b990SUpinder Malhi a0, a1, 392183b990SUpinder Malhi 1000); 402183b990SUpinder Malhi if (status) { 412183b990SUpinder Malhi if (status == ERR_EINVAL && cmd == CMD_DEL_FILTER) { 422183b990SUpinder Malhi usnic_dbg("Dev %s vnic idx %u cmd %u already deleted", 432183b990SUpinder Malhi ufdev->name, vnic_idx, cmd); 442183b990SUpinder Malhi } else { 452183b990SUpinder Malhi usnic_err("Dev %s vnic idx %u cmd %u failed with status %d\n", 462183b990SUpinder Malhi ufdev->name, vnic_idx, cmd, 472183b990SUpinder Malhi status); 482183b990SUpinder Malhi } 492183b990SUpinder Malhi } else { 502183b990SUpinder Malhi usnic_dbg("Dev %s vnic idx %u cmd %u success", 512183b990SUpinder Malhi ufdev->name, vnic_idx, cmd); 522183b990SUpinder Malhi } 532183b990SUpinder Malhi 542183b990SUpinder Malhi return status; 552183b990SUpinder Malhi } 562183b990SUpinder Malhi 572183b990SUpinder Malhi static int usnic_fwd_devcmd(struct usnic_fwd_dev *ufdev, int vnic_idx, 582183b990SUpinder Malhi enum vnic_devcmd_cmd cmd, u64 *a0, u64 *a1) 592183b990SUpinder Malhi { 602183b990SUpinder Malhi int status; 612183b990SUpinder Malhi 622183b990SUpinder Malhi spin_lock(&ufdev->lock); 632183b990SUpinder Malhi status = usnic_fwd_devcmd_locked(ufdev, vnic_idx, cmd, a0, a1); 642183b990SUpinder Malhi spin_unlock(&ufdev->lock); 652183b990SUpinder Malhi 662183b990SUpinder Malhi return status; 672183b990SUpinder Malhi } 682183b990SUpinder Malhi 69e3cf00d0SUpinder Malhi struct usnic_fwd_dev *usnic_fwd_dev_alloc(struct pci_dev *pdev) 70e3cf00d0SUpinder Malhi { 71e3cf00d0SUpinder Malhi struct usnic_fwd_dev *ufdev; 72e3cf00d0SUpinder Malhi 73e3cf00d0SUpinder Malhi ufdev = kzalloc(sizeof(*ufdev), GFP_KERNEL); 74e3cf00d0SUpinder Malhi if (!ufdev) 75e3cf00d0SUpinder Malhi return NULL; 76e3cf00d0SUpinder Malhi 77e3cf00d0SUpinder Malhi ufdev->pdev = pdev; 78e3cf00d0SUpinder Malhi ufdev->netdev = pci_get_drvdata(pdev); 79e3cf00d0SUpinder Malhi spin_lock_init(&ufdev->lock); 802183b990SUpinder Malhi strncpy(ufdev->name, netdev_name(ufdev->netdev), 812183b990SUpinder Malhi sizeof(ufdev->name) - 1); 82e3cf00d0SUpinder Malhi 83e3cf00d0SUpinder Malhi return ufdev; 84e3cf00d0SUpinder Malhi } 85e3cf00d0SUpinder Malhi 86e3cf00d0SUpinder Malhi void usnic_fwd_dev_free(struct usnic_fwd_dev *ufdev) 87e3cf00d0SUpinder Malhi { 88e3cf00d0SUpinder Malhi kfree(ufdev); 89e3cf00d0SUpinder Malhi } 90e3cf00d0SUpinder Malhi 912183b990SUpinder Malhi void usnic_fwd_set_mac(struct usnic_fwd_dev *ufdev, char mac[ETH_ALEN]) 92e3cf00d0SUpinder Malhi { 93e3cf00d0SUpinder Malhi spin_lock(&ufdev->lock); 942183b990SUpinder Malhi memcpy(&ufdev->mac, mac, sizeof(ufdev->mac)); 95e3cf00d0SUpinder Malhi spin_unlock(&ufdev->lock); 96e3cf00d0SUpinder Malhi } 97e3cf00d0SUpinder Malhi 98*3f92bed3SUpinder Malhi int usnic_fwd_add_ipaddr(struct usnic_fwd_dev *ufdev, __be32 inaddr) 99*3f92bed3SUpinder Malhi { 100*3f92bed3SUpinder Malhi int status; 101*3f92bed3SUpinder Malhi 102*3f92bed3SUpinder Malhi spin_lock(&ufdev->lock); 103*3f92bed3SUpinder Malhi if (ufdev->inaddr == 0) { 104*3f92bed3SUpinder Malhi ufdev->inaddr = inaddr; 105*3f92bed3SUpinder Malhi status = 0; 106*3f92bed3SUpinder Malhi } else { 107*3f92bed3SUpinder Malhi status = -EFAULT; 108*3f92bed3SUpinder Malhi } 109*3f92bed3SUpinder Malhi spin_unlock(&ufdev->lock); 110*3f92bed3SUpinder Malhi 111*3f92bed3SUpinder Malhi return status; 112*3f92bed3SUpinder Malhi } 113*3f92bed3SUpinder Malhi 114*3f92bed3SUpinder Malhi void usnic_fwd_del_ipaddr(struct usnic_fwd_dev *ufdev) 115*3f92bed3SUpinder Malhi { 116*3f92bed3SUpinder Malhi spin_lock(&ufdev->lock); 117*3f92bed3SUpinder Malhi ufdev->inaddr = 0; 118*3f92bed3SUpinder Malhi spin_unlock(&ufdev->lock); 119*3f92bed3SUpinder Malhi } 120*3f92bed3SUpinder Malhi 1212183b990SUpinder Malhi void usnic_fwd_carrier_up(struct usnic_fwd_dev *ufdev) 122e3cf00d0SUpinder Malhi { 1232183b990SUpinder Malhi spin_lock(&ufdev->lock); 1242183b990SUpinder Malhi ufdev->link_up = 1; 1252183b990SUpinder Malhi spin_unlock(&ufdev->lock); 126e3cf00d0SUpinder Malhi } 127e3cf00d0SUpinder Malhi 1282183b990SUpinder Malhi void usnic_fwd_carrier_down(struct usnic_fwd_dev *ufdev) 1292183b990SUpinder Malhi { 1302183b990SUpinder Malhi spin_lock(&ufdev->lock); 1312183b990SUpinder Malhi ufdev->link_up = 0; 1322183b990SUpinder Malhi spin_unlock(&ufdev->lock); 133e3cf00d0SUpinder Malhi } 134e3cf00d0SUpinder Malhi 1352183b990SUpinder Malhi void usnic_fwd_set_mtu(struct usnic_fwd_dev *ufdev, unsigned int mtu) 1362183b990SUpinder Malhi { 1372183b990SUpinder Malhi spin_lock(&ufdev->lock); 1382183b990SUpinder Malhi ufdev->mtu = mtu; 1392183b990SUpinder Malhi spin_unlock(&ufdev->lock); 1402183b990SUpinder Malhi } 1412183b990SUpinder Malhi 1422183b990SUpinder Malhi static int usnic_fwd_dev_ready_locked(struct usnic_fwd_dev *ufdev) 1432183b990SUpinder Malhi { 1442183b990SUpinder Malhi lockdep_assert_held(&ufdev->lock); 1452183b990SUpinder Malhi 1462183b990SUpinder Malhi if (!ufdev->link_up) 1472183b990SUpinder Malhi return -EPERM; 1482183b990SUpinder Malhi 1492183b990SUpinder Malhi return 0; 1502183b990SUpinder Malhi } 1512183b990SUpinder Malhi 152*3f92bed3SUpinder Malhi static int validate_filter_locked(struct usnic_fwd_dev *ufdev, 153*3f92bed3SUpinder Malhi struct filter *filter) 154*3f92bed3SUpinder Malhi { 155*3f92bed3SUpinder Malhi 156*3f92bed3SUpinder Malhi lockdep_assert_held(&ufdev->lock); 157*3f92bed3SUpinder Malhi 158*3f92bed3SUpinder Malhi if (filter->type == FILTER_IPV4_5TUPLE) { 159*3f92bed3SUpinder Malhi if (!(filter->u.ipv4.flags & FILTER_FIELD_5TUP_DST_AD)) 160*3f92bed3SUpinder Malhi return -EACCES; 161*3f92bed3SUpinder Malhi if (!(filter->u.ipv4.flags & FILTER_FIELD_5TUP_DST_PT)) 162*3f92bed3SUpinder Malhi return -EBUSY; 163*3f92bed3SUpinder Malhi else if (ufdev->inaddr == 0) 164*3f92bed3SUpinder Malhi return -EINVAL; 165*3f92bed3SUpinder Malhi else if (filter->u.ipv4.dst_port == 0) 166*3f92bed3SUpinder Malhi return -ERANGE; 167*3f92bed3SUpinder Malhi else if (ntohl(ufdev->inaddr) != filter->u.ipv4.dst_addr) 168*3f92bed3SUpinder Malhi return -EFAULT; 169*3f92bed3SUpinder Malhi else 170*3f92bed3SUpinder Malhi return 0; 171*3f92bed3SUpinder Malhi } 172*3f92bed3SUpinder Malhi 173*3f92bed3SUpinder Malhi return 0; 174*3f92bed3SUpinder Malhi } 175*3f92bed3SUpinder Malhi 1762183b990SUpinder Malhi static void fill_tlv(struct filter_tlv *tlv, struct filter *filter, 1772183b990SUpinder Malhi struct filter_action *action) 1782183b990SUpinder Malhi { 179e3cf00d0SUpinder Malhi tlv->type = CLSF_TLV_FILTER; 180e3cf00d0SUpinder Malhi tlv->length = sizeof(struct filter); 1812183b990SUpinder Malhi *((struct filter *)&tlv->val) = *filter; 1822183b990SUpinder Malhi 183e3cf00d0SUpinder Malhi tlv = (struct filter_tlv *)((char *)tlv + sizeof(struct filter_tlv) + 184e3cf00d0SUpinder Malhi sizeof(struct filter)); 185e3cf00d0SUpinder Malhi tlv->type = CLSF_TLV_ACTION; 186e3cf00d0SUpinder Malhi tlv->length = sizeof(struct filter_action); 1872183b990SUpinder Malhi *((struct filter_action *)&tlv->val) = *action; 1882183b990SUpinder Malhi } 189e3cf00d0SUpinder Malhi 1902183b990SUpinder Malhi struct usnic_fwd_flow* 1912183b990SUpinder Malhi usnic_fwd_alloc_flow(struct usnic_fwd_dev *ufdev, struct filter *filter, 1922183b990SUpinder Malhi struct usnic_filter_action *uaction) 1932183b990SUpinder Malhi { 1942183b990SUpinder Malhi struct filter_tlv *tlv; 1952183b990SUpinder Malhi struct pci_dev *pdev; 1962183b990SUpinder Malhi struct usnic_fwd_flow *flow; 1972183b990SUpinder Malhi uint64_t a0, a1; 1982183b990SUpinder Malhi uint64_t tlv_size; 1992183b990SUpinder Malhi dma_addr_t tlv_pa; 2002183b990SUpinder Malhi int status; 2012183b990SUpinder Malhi 2022183b990SUpinder Malhi pdev = ufdev->pdev; 2032183b990SUpinder Malhi tlv_size = (2*sizeof(struct filter_tlv) + sizeof(struct filter) + 2042183b990SUpinder Malhi sizeof(struct filter_action)); 2052183b990SUpinder Malhi 2062183b990SUpinder Malhi flow = kzalloc(sizeof(*flow), GFP_ATOMIC); 2072183b990SUpinder Malhi if (!flow) 2082183b990SUpinder Malhi return ERR_PTR(-ENOMEM); 2092183b990SUpinder Malhi 2102183b990SUpinder Malhi tlv = pci_alloc_consistent(pdev, tlv_size, &tlv_pa); 2112183b990SUpinder Malhi if (!tlv) { 2122183b990SUpinder Malhi usnic_err("Failed to allocate memory\n"); 2132183b990SUpinder Malhi status = -ENOMEM; 2142183b990SUpinder Malhi goto out_free_flow; 2152183b990SUpinder Malhi } 2162183b990SUpinder Malhi 2172183b990SUpinder Malhi fill_tlv(tlv, filter, &uaction->action); 2182183b990SUpinder Malhi 2192183b990SUpinder Malhi spin_lock(&ufdev->lock); 2202183b990SUpinder Malhi status = usnic_fwd_dev_ready_locked(ufdev); 2212183b990SUpinder Malhi if (status) { 2222183b990SUpinder Malhi usnic_err("Forwarding dev %s not ready with status %d\n", 2232183b990SUpinder Malhi ufdev->name, status); 2242183b990SUpinder Malhi goto out_free_tlv; 2252183b990SUpinder Malhi } 2262183b990SUpinder Malhi 227*3f92bed3SUpinder Malhi status = validate_filter_locked(ufdev, filter); 228*3f92bed3SUpinder Malhi if (status) { 229*3f92bed3SUpinder Malhi usnic_err("Failed to validate filter with status %d\n", 230*3f92bed3SUpinder Malhi status); 231*3f92bed3SUpinder Malhi goto out_free_tlv; 232*3f92bed3SUpinder Malhi } 233*3f92bed3SUpinder Malhi 2342183b990SUpinder Malhi /* Issue Devcmd */ 2352183b990SUpinder Malhi a0 = tlv_pa; 2362183b990SUpinder Malhi a1 = tlv_size; 2372183b990SUpinder Malhi status = usnic_fwd_devcmd_locked(ufdev, uaction->vnic_idx, 2382183b990SUpinder Malhi CMD_ADD_FILTER, &a0, &a1); 239e3cf00d0SUpinder Malhi if (status) { 240e3cf00d0SUpinder Malhi usnic_err("VF %s Filter add failed with status:%d", 2412183b990SUpinder Malhi ufdev->name, status); 2422183b990SUpinder Malhi status = -EFAULT; 2432183b990SUpinder Malhi goto out_free_tlv; 244e3cf00d0SUpinder Malhi } else { 2452183b990SUpinder Malhi usnic_dbg("VF %s FILTER ID:%llu", ufdev->name, a0); 246e3cf00d0SUpinder Malhi } 247e3cf00d0SUpinder Malhi 2482183b990SUpinder Malhi flow->flow_id = (uint32_t) a0; 2492183b990SUpinder Malhi flow->vnic_idx = uaction->vnic_idx; 2502183b990SUpinder Malhi flow->ufdev = ufdev; 251e3cf00d0SUpinder Malhi 2522183b990SUpinder Malhi out_free_tlv: 2532183b990SUpinder Malhi spin_unlock(&ufdev->lock); 2542183b990SUpinder Malhi pci_free_consistent(pdev, tlv_size, tlv, tlv_pa); 2552183b990SUpinder Malhi if (!status) 2562183b990SUpinder Malhi return flow; 2572183b990SUpinder Malhi out_free_flow: 2582183b990SUpinder Malhi kfree(flow); 2592183b990SUpinder Malhi return ERR_PTR(status); 260e3cf00d0SUpinder Malhi } 261e3cf00d0SUpinder Malhi 2622183b990SUpinder Malhi int usnic_fwd_dealloc_flow(struct usnic_fwd_flow *flow) 263e3cf00d0SUpinder Malhi { 264e3cf00d0SUpinder Malhi int status; 265e3cf00d0SUpinder Malhi u64 a0, a1; 266e3cf00d0SUpinder Malhi 2672183b990SUpinder Malhi a0 = flow->flow_id; 268e3cf00d0SUpinder Malhi 2692183b990SUpinder Malhi status = usnic_fwd_devcmd(flow->ufdev, flow->vnic_idx, 270e3cf00d0SUpinder Malhi CMD_DEL_FILTER, &a0, &a1); 271e3cf00d0SUpinder Malhi if (status) { 272e3cf00d0SUpinder Malhi if (status == ERR_EINVAL) { 273e3cf00d0SUpinder Malhi usnic_dbg("Filter %u already deleted for VF Idx %u pf: %s status: %d", 2742183b990SUpinder Malhi flow->flow_id, flow->vnic_idx, 2752183b990SUpinder Malhi flow->ufdev->name, status); 276e3cf00d0SUpinder Malhi } else { 277e3cf00d0SUpinder Malhi usnic_err("PF %s VF Idx %u Filter: %u FILTER DELETE failed with status %d", 2782183b990SUpinder Malhi flow->ufdev->name, flow->vnic_idx, 2792183b990SUpinder Malhi flow->flow_id, status); 280e3cf00d0SUpinder Malhi } 2812183b990SUpinder Malhi status = 0; 2822183b990SUpinder Malhi /* 2832183b990SUpinder Malhi * Log the error and fake success to the caller because if 2842183b990SUpinder Malhi * a flow fails to be deleted in the firmware, it is an 2852183b990SUpinder Malhi * unrecoverable error. 2862183b990SUpinder Malhi */ 287e3cf00d0SUpinder Malhi } else { 288e3cf00d0SUpinder Malhi usnic_dbg("PF %s VF Idx %u Filter: %u FILTER DELETED", 2892183b990SUpinder Malhi flow->ufdev->name, flow->vnic_idx, 2902183b990SUpinder Malhi flow->flow_id); 291e3cf00d0SUpinder Malhi } 292e3cf00d0SUpinder Malhi 2932183b990SUpinder Malhi kfree(flow); 294e3cf00d0SUpinder Malhi return status; 295e3cf00d0SUpinder Malhi } 296e3cf00d0SUpinder Malhi 2972183b990SUpinder Malhi int usnic_fwd_enable_qp(struct usnic_fwd_dev *ufdev, int vnic_idx, int qp_idx) 298e3cf00d0SUpinder Malhi { 299e3cf00d0SUpinder Malhi int status; 300e3cf00d0SUpinder Malhi struct net_device *pf_netdev; 301e3cf00d0SUpinder Malhi u64 a0, a1; 302e3cf00d0SUpinder Malhi 303e3cf00d0SUpinder Malhi pf_netdev = ufdev->netdev; 3042183b990SUpinder Malhi a0 = qp_idx; 305e3cf00d0SUpinder Malhi a1 = CMD_QP_RQWQ; 306e3cf00d0SUpinder Malhi 3072183b990SUpinder Malhi status = usnic_fwd_devcmd(ufdev, vnic_idx, CMD_QP_ENABLE, 3082183b990SUpinder Malhi &a0, &a1); 309e3cf00d0SUpinder Malhi if (status) { 310e3cf00d0SUpinder Malhi usnic_err("PF %s VNIC Index %u RQ Index: %u ENABLE Failed with status %d", 311e3cf00d0SUpinder Malhi netdev_name(pf_netdev), 312e3cf00d0SUpinder Malhi vnic_idx, 3132183b990SUpinder Malhi qp_idx, 314e3cf00d0SUpinder Malhi status); 315e3cf00d0SUpinder Malhi } else { 316e3cf00d0SUpinder Malhi usnic_dbg("PF %s VNIC Index %u RQ Index: %u ENABLED", 317e3cf00d0SUpinder Malhi netdev_name(pf_netdev), 3182183b990SUpinder Malhi vnic_idx, qp_idx); 319e3cf00d0SUpinder Malhi } 320e3cf00d0SUpinder Malhi 321e3cf00d0SUpinder Malhi return status; 322e3cf00d0SUpinder Malhi } 323e3cf00d0SUpinder Malhi 3242183b990SUpinder Malhi int usnic_fwd_disable_qp(struct usnic_fwd_dev *ufdev, int vnic_idx, int qp_idx) 325e3cf00d0SUpinder Malhi { 326e3cf00d0SUpinder Malhi int status; 327e3cf00d0SUpinder Malhi u64 a0, a1; 328e3cf00d0SUpinder Malhi struct net_device *pf_netdev; 329e3cf00d0SUpinder Malhi 330e3cf00d0SUpinder Malhi pf_netdev = ufdev->netdev; 3312183b990SUpinder Malhi a0 = qp_idx; 332e3cf00d0SUpinder Malhi a1 = CMD_QP_RQWQ; 333e3cf00d0SUpinder Malhi 3342183b990SUpinder Malhi status = usnic_fwd_devcmd(ufdev, vnic_idx, CMD_QP_DISABLE, 3352183b990SUpinder Malhi &a0, &a1); 336e3cf00d0SUpinder Malhi if (status) { 337e3cf00d0SUpinder Malhi usnic_err("PF %s VNIC Index %u RQ Index: %u DISABLE Failed with status %d", 338e3cf00d0SUpinder Malhi netdev_name(pf_netdev), 339e3cf00d0SUpinder Malhi vnic_idx, 3402183b990SUpinder Malhi qp_idx, 341e3cf00d0SUpinder Malhi status); 342e3cf00d0SUpinder Malhi } else { 343e3cf00d0SUpinder Malhi usnic_dbg("PF %s VNIC Index %u RQ Index: %u DISABLED", 344e3cf00d0SUpinder Malhi netdev_name(pf_netdev), 345e3cf00d0SUpinder Malhi vnic_idx, 3462183b990SUpinder Malhi qp_idx); 347e3cf00d0SUpinder Malhi } 348e3cf00d0SUpinder Malhi 349e3cf00d0SUpinder Malhi return status; 350e3cf00d0SUpinder Malhi } 351