1e3cf00d0SUpinder Malhi /* 2e3cf00d0SUpinder Malhi * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved. 3e3cf00d0SUpinder Malhi * 4*3805eadeSJeff Squyres * This software is available to you under a choice of one of two 5*3805eadeSJeff Squyres * licenses. You may choose to be licensed under the terms of the GNU 6*3805eadeSJeff Squyres * General Public License (GPL) Version 2, available from the file 7*3805eadeSJeff Squyres * COPYING in the main directory of this source tree, or the 8*3805eadeSJeff Squyres * BSD license below: 9*3805eadeSJeff Squyres * 10*3805eadeSJeff Squyres * Redistribution and use in source and binary forms, with or 11*3805eadeSJeff Squyres * without modification, are permitted provided that the following 12*3805eadeSJeff Squyres * conditions are met: 13*3805eadeSJeff Squyres * 14*3805eadeSJeff Squyres * - Redistributions of source code must retain the above 15*3805eadeSJeff Squyres * copyright notice, this list of conditions and the following 16*3805eadeSJeff Squyres * disclaimer. 17*3805eadeSJeff Squyres * 18*3805eadeSJeff Squyres * - Redistributions in binary form must reproduce the above 19*3805eadeSJeff Squyres * copyright notice, this list of conditions and the following 20*3805eadeSJeff Squyres * disclaimer in the documentation and/or other materials 21*3805eadeSJeff 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); 952183b990SUpinder Malhi strncpy(ufdev->name, netdev_name(ufdev->netdev), 962183b990SUpinder Malhi sizeof(ufdev->name) - 1); 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 1133f92bed3SUpinder Malhi int usnic_fwd_add_ipaddr(struct usnic_fwd_dev *ufdev, __be32 inaddr) 1143f92bed3SUpinder Malhi { 1153f92bed3SUpinder Malhi int status; 1163f92bed3SUpinder Malhi 1173f92bed3SUpinder Malhi spin_lock(&ufdev->lock); 1183f92bed3SUpinder Malhi if (ufdev->inaddr == 0) { 1193f92bed3SUpinder Malhi ufdev->inaddr = inaddr; 1203f92bed3SUpinder Malhi status = 0; 1213f92bed3SUpinder Malhi } else { 1223f92bed3SUpinder Malhi status = -EFAULT; 1233f92bed3SUpinder Malhi } 1243f92bed3SUpinder Malhi spin_unlock(&ufdev->lock); 1253f92bed3SUpinder Malhi 1263f92bed3SUpinder Malhi return status; 1273f92bed3SUpinder Malhi } 1283f92bed3SUpinder Malhi 1293f92bed3SUpinder Malhi void usnic_fwd_del_ipaddr(struct usnic_fwd_dev *ufdev) 1303f92bed3SUpinder Malhi { 1313f92bed3SUpinder Malhi spin_lock(&ufdev->lock); 1323f92bed3SUpinder Malhi ufdev->inaddr = 0; 1333f92bed3SUpinder Malhi spin_unlock(&ufdev->lock); 1343f92bed3SUpinder Malhi } 1353f92bed3SUpinder Malhi 1362183b990SUpinder Malhi void usnic_fwd_carrier_up(struct usnic_fwd_dev *ufdev) 137e3cf00d0SUpinder Malhi { 1382183b990SUpinder Malhi spin_lock(&ufdev->lock); 1392183b990SUpinder Malhi ufdev->link_up = 1; 1402183b990SUpinder Malhi spin_unlock(&ufdev->lock); 141e3cf00d0SUpinder Malhi } 142e3cf00d0SUpinder Malhi 1432183b990SUpinder Malhi void usnic_fwd_carrier_down(struct usnic_fwd_dev *ufdev) 1442183b990SUpinder Malhi { 1452183b990SUpinder Malhi spin_lock(&ufdev->lock); 1462183b990SUpinder Malhi ufdev->link_up = 0; 1472183b990SUpinder Malhi spin_unlock(&ufdev->lock); 148e3cf00d0SUpinder Malhi } 149e3cf00d0SUpinder Malhi 1502183b990SUpinder Malhi void usnic_fwd_set_mtu(struct usnic_fwd_dev *ufdev, unsigned int mtu) 1512183b990SUpinder Malhi { 1522183b990SUpinder Malhi spin_lock(&ufdev->lock); 1532183b990SUpinder Malhi ufdev->mtu = mtu; 1542183b990SUpinder Malhi spin_unlock(&ufdev->lock); 1552183b990SUpinder Malhi } 1562183b990SUpinder Malhi 1572183b990SUpinder Malhi static int usnic_fwd_dev_ready_locked(struct usnic_fwd_dev *ufdev) 1582183b990SUpinder Malhi { 1592183b990SUpinder Malhi lockdep_assert_held(&ufdev->lock); 1602183b990SUpinder Malhi 1612183b990SUpinder Malhi if (!ufdev->link_up) 1622183b990SUpinder Malhi return -EPERM; 1632183b990SUpinder Malhi 1642183b990SUpinder Malhi return 0; 1652183b990SUpinder Malhi } 1662183b990SUpinder Malhi 1673f92bed3SUpinder Malhi static int validate_filter_locked(struct usnic_fwd_dev *ufdev, 1683f92bed3SUpinder Malhi struct filter *filter) 1693f92bed3SUpinder Malhi { 1703f92bed3SUpinder Malhi 1713f92bed3SUpinder Malhi lockdep_assert_held(&ufdev->lock); 1723f92bed3SUpinder Malhi 1733f92bed3SUpinder Malhi if (filter->type == FILTER_IPV4_5TUPLE) { 1743f92bed3SUpinder Malhi if (!(filter->u.ipv4.flags & FILTER_FIELD_5TUP_DST_AD)) 1753f92bed3SUpinder Malhi return -EACCES; 1763f92bed3SUpinder Malhi if (!(filter->u.ipv4.flags & FILTER_FIELD_5TUP_DST_PT)) 1773f92bed3SUpinder Malhi return -EBUSY; 1783f92bed3SUpinder Malhi else if (ufdev->inaddr == 0) 1793f92bed3SUpinder Malhi return -EINVAL; 1803f92bed3SUpinder Malhi else if (filter->u.ipv4.dst_port == 0) 1813f92bed3SUpinder Malhi return -ERANGE; 1823f92bed3SUpinder Malhi else if (ntohl(ufdev->inaddr) != filter->u.ipv4.dst_addr) 1833f92bed3SUpinder Malhi return -EFAULT; 1843f92bed3SUpinder Malhi else 1853f92bed3SUpinder Malhi return 0; 1863f92bed3SUpinder Malhi } 1873f92bed3SUpinder Malhi 1883f92bed3SUpinder Malhi return 0; 1893f92bed3SUpinder Malhi } 1903f92bed3SUpinder Malhi 1912183b990SUpinder Malhi static void fill_tlv(struct filter_tlv *tlv, struct filter *filter, 1922183b990SUpinder Malhi struct filter_action *action) 1932183b990SUpinder Malhi { 194e3cf00d0SUpinder Malhi tlv->type = CLSF_TLV_FILTER; 195e3cf00d0SUpinder Malhi tlv->length = sizeof(struct filter); 1962183b990SUpinder Malhi *((struct filter *)&tlv->val) = *filter; 1972183b990SUpinder Malhi 198e3cf00d0SUpinder Malhi tlv = (struct filter_tlv *)((char *)tlv + sizeof(struct filter_tlv) + 199e3cf00d0SUpinder Malhi sizeof(struct filter)); 200e3cf00d0SUpinder Malhi tlv->type = CLSF_TLV_ACTION; 201e3cf00d0SUpinder Malhi tlv->length = sizeof(struct filter_action); 2022183b990SUpinder Malhi *((struct filter_action *)&tlv->val) = *action; 2032183b990SUpinder Malhi } 204e3cf00d0SUpinder Malhi 2052183b990SUpinder Malhi struct usnic_fwd_flow* 2062183b990SUpinder Malhi usnic_fwd_alloc_flow(struct usnic_fwd_dev *ufdev, struct filter *filter, 2072183b990SUpinder Malhi struct usnic_filter_action *uaction) 2082183b990SUpinder Malhi { 2092183b990SUpinder Malhi struct filter_tlv *tlv; 2102183b990SUpinder Malhi struct pci_dev *pdev; 2112183b990SUpinder Malhi struct usnic_fwd_flow *flow; 2122183b990SUpinder Malhi uint64_t a0, a1; 2132183b990SUpinder Malhi uint64_t tlv_size; 2142183b990SUpinder Malhi dma_addr_t tlv_pa; 2152183b990SUpinder Malhi int status; 2162183b990SUpinder Malhi 2172183b990SUpinder Malhi pdev = ufdev->pdev; 2182183b990SUpinder Malhi tlv_size = (2*sizeof(struct filter_tlv) + sizeof(struct filter) + 2192183b990SUpinder Malhi sizeof(struct filter_action)); 2202183b990SUpinder Malhi 2212183b990SUpinder Malhi flow = kzalloc(sizeof(*flow), GFP_ATOMIC); 2222183b990SUpinder Malhi if (!flow) 2232183b990SUpinder Malhi return ERR_PTR(-ENOMEM); 2242183b990SUpinder Malhi 2252183b990SUpinder Malhi tlv = pci_alloc_consistent(pdev, tlv_size, &tlv_pa); 2262183b990SUpinder Malhi if (!tlv) { 2272183b990SUpinder Malhi usnic_err("Failed to allocate memory\n"); 2282183b990SUpinder Malhi status = -ENOMEM; 2292183b990SUpinder Malhi goto out_free_flow; 2302183b990SUpinder Malhi } 2312183b990SUpinder Malhi 2322183b990SUpinder Malhi fill_tlv(tlv, filter, &uaction->action); 2332183b990SUpinder Malhi 2342183b990SUpinder Malhi spin_lock(&ufdev->lock); 2352183b990SUpinder Malhi status = usnic_fwd_dev_ready_locked(ufdev); 2362183b990SUpinder Malhi if (status) { 2372183b990SUpinder Malhi usnic_err("Forwarding dev %s not ready with status %d\n", 2382183b990SUpinder Malhi ufdev->name, status); 2392183b990SUpinder Malhi goto out_free_tlv; 2402183b990SUpinder Malhi } 2412183b990SUpinder Malhi 2423f92bed3SUpinder Malhi status = validate_filter_locked(ufdev, filter); 2433f92bed3SUpinder Malhi if (status) { 2443f92bed3SUpinder Malhi usnic_err("Failed to validate filter with status %d\n", 2453f92bed3SUpinder Malhi status); 2463f92bed3SUpinder Malhi goto out_free_tlv; 2473f92bed3SUpinder Malhi } 2483f92bed3SUpinder Malhi 2492183b990SUpinder Malhi /* Issue Devcmd */ 2502183b990SUpinder Malhi a0 = tlv_pa; 2512183b990SUpinder Malhi a1 = tlv_size; 2522183b990SUpinder Malhi status = usnic_fwd_devcmd_locked(ufdev, uaction->vnic_idx, 2532183b990SUpinder Malhi CMD_ADD_FILTER, &a0, &a1); 254e3cf00d0SUpinder Malhi if (status) { 255e3cf00d0SUpinder Malhi usnic_err("VF %s Filter add failed with status:%d", 2562183b990SUpinder Malhi ufdev->name, status); 2572183b990SUpinder Malhi status = -EFAULT; 2582183b990SUpinder Malhi goto out_free_tlv; 259e3cf00d0SUpinder Malhi } else { 2602183b990SUpinder Malhi usnic_dbg("VF %s FILTER ID:%llu", ufdev->name, a0); 261e3cf00d0SUpinder Malhi } 262e3cf00d0SUpinder Malhi 2632183b990SUpinder Malhi flow->flow_id = (uint32_t) a0; 2642183b990SUpinder Malhi flow->vnic_idx = uaction->vnic_idx; 2652183b990SUpinder Malhi flow->ufdev = ufdev; 266e3cf00d0SUpinder Malhi 2672183b990SUpinder Malhi out_free_tlv: 2682183b990SUpinder Malhi spin_unlock(&ufdev->lock); 2692183b990SUpinder Malhi pci_free_consistent(pdev, tlv_size, tlv, tlv_pa); 2702183b990SUpinder Malhi if (!status) 2712183b990SUpinder Malhi return flow; 2722183b990SUpinder Malhi out_free_flow: 2732183b990SUpinder Malhi kfree(flow); 2742183b990SUpinder Malhi return ERR_PTR(status); 275e3cf00d0SUpinder Malhi } 276e3cf00d0SUpinder Malhi 2772183b990SUpinder Malhi int usnic_fwd_dealloc_flow(struct usnic_fwd_flow *flow) 278e3cf00d0SUpinder Malhi { 279e3cf00d0SUpinder Malhi int status; 280e3cf00d0SUpinder Malhi u64 a0, a1; 281e3cf00d0SUpinder Malhi 2822183b990SUpinder Malhi a0 = flow->flow_id; 283e3cf00d0SUpinder Malhi 2842183b990SUpinder Malhi status = usnic_fwd_devcmd(flow->ufdev, flow->vnic_idx, 285e3cf00d0SUpinder Malhi CMD_DEL_FILTER, &a0, &a1); 286e3cf00d0SUpinder Malhi if (status) { 287e3cf00d0SUpinder Malhi if (status == ERR_EINVAL) { 288e3cf00d0SUpinder Malhi usnic_dbg("Filter %u already deleted for VF Idx %u pf: %s status: %d", 2892183b990SUpinder Malhi flow->flow_id, flow->vnic_idx, 2902183b990SUpinder Malhi flow->ufdev->name, status); 291e3cf00d0SUpinder Malhi } else { 292e3cf00d0SUpinder Malhi usnic_err("PF %s VF Idx %u Filter: %u FILTER DELETE failed with status %d", 2932183b990SUpinder Malhi flow->ufdev->name, flow->vnic_idx, 2942183b990SUpinder Malhi flow->flow_id, status); 295e3cf00d0SUpinder Malhi } 2962183b990SUpinder Malhi status = 0; 2972183b990SUpinder Malhi /* 2982183b990SUpinder Malhi * Log the error and fake success to the caller because if 2992183b990SUpinder Malhi * a flow fails to be deleted in the firmware, it is an 3002183b990SUpinder Malhi * unrecoverable error. 3012183b990SUpinder Malhi */ 302e3cf00d0SUpinder Malhi } else { 303e3cf00d0SUpinder Malhi usnic_dbg("PF %s VF Idx %u Filter: %u FILTER DELETED", 3042183b990SUpinder Malhi flow->ufdev->name, flow->vnic_idx, 3052183b990SUpinder Malhi flow->flow_id); 306e3cf00d0SUpinder Malhi } 307e3cf00d0SUpinder Malhi 3082183b990SUpinder Malhi kfree(flow); 309e3cf00d0SUpinder Malhi return status; 310e3cf00d0SUpinder Malhi } 311e3cf00d0SUpinder Malhi 3122183b990SUpinder Malhi int usnic_fwd_enable_qp(struct usnic_fwd_dev *ufdev, int vnic_idx, int qp_idx) 313e3cf00d0SUpinder Malhi { 314e3cf00d0SUpinder Malhi int status; 315e3cf00d0SUpinder Malhi struct net_device *pf_netdev; 316e3cf00d0SUpinder Malhi u64 a0, a1; 317e3cf00d0SUpinder Malhi 318e3cf00d0SUpinder Malhi pf_netdev = ufdev->netdev; 3192183b990SUpinder Malhi a0 = qp_idx; 320e3cf00d0SUpinder Malhi a1 = CMD_QP_RQWQ; 321e3cf00d0SUpinder Malhi 3222183b990SUpinder Malhi status = usnic_fwd_devcmd(ufdev, vnic_idx, CMD_QP_ENABLE, 3232183b990SUpinder Malhi &a0, &a1); 324e3cf00d0SUpinder Malhi if (status) { 325e3cf00d0SUpinder Malhi usnic_err("PF %s VNIC Index %u RQ Index: %u ENABLE Failed with status %d", 326e3cf00d0SUpinder Malhi netdev_name(pf_netdev), 327e3cf00d0SUpinder Malhi vnic_idx, 3282183b990SUpinder Malhi qp_idx, 329e3cf00d0SUpinder Malhi status); 330e3cf00d0SUpinder Malhi } else { 331e3cf00d0SUpinder Malhi usnic_dbg("PF %s VNIC Index %u RQ Index: %u ENABLED", 332e3cf00d0SUpinder Malhi netdev_name(pf_netdev), 3332183b990SUpinder Malhi vnic_idx, qp_idx); 334e3cf00d0SUpinder Malhi } 335e3cf00d0SUpinder Malhi 336e3cf00d0SUpinder Malhi return status; 337e3cf00d0SUpinder Malhi } 338e3cf00d0SUpinder Malhi 3392183b990SUpinder Malhi int usnic_fwd_disable_qp(struct usnic_fwd_dev *ufdev, int vnic_idx, int qp_idx) 340e3cf00d0SUpinder Malhi { 341e3cf00d0SUpinder Malhi int status; 342e3cf00d0SUpinder Malhi u64 a0, a1; 343e3cf00d0SUpinder Malhi struct net_device *pf_netdev; 344e3cf00d0SUpinder Malhi 345e3cf00d0SUpinder Malhi pf_netdev = ufdev->netdev; 3462183b990SUpinder Malhi a0 = qp_idx; 347e3cf00d0SUpinder Malhi a1 = CMD_QP_RQWQ; 348e3cf00d0SUpinder Malhi 3492183b990SUpinder Malhi status = usnic_fwd_devcmd(ufdev, vnic_idx, CMD_QP_DISABLE, 3502183b990SUpinder Malhi &a0, &a1); 351e3cf00d0SUpinder Malhi if (status) { 352e3cf00d0SUpinder Malhi usnic_err("PF %s VNIC Index %u RQ Index: %u DISABLE Failed with status %d", 353e3cf00d0SUpinder Malhi netdev_name(pf_netdev), 354e3cf00d0SUpinder Malhi vnic_idx, 3552183b990SUpinder Malhi qp_idx, 356e3cf00d0SUpinder Malhi status); 357e3cf00d0SUpinder Malhi } else { 358e3cf00d0SUpinder Malhi usnic_dbg("PF %s VNIC Index %u RQ Index: %u DISABLED", 359e3cf00d0SUpinder Malhi netdev_name(pf_netdev), 360e3cf00d0SUpinder Malhi vnic_idx, 3612183b990SUpinder Malhi qp_idx); 362e3cf00d0SUpinder Malhi } 363e3cf00d0SUpinder Malhi 364e3cf00d0SUpinder Malhi return status; 365e3cf00d0SUpinder Malhi } 366