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 26*2183b990SUpinder Malhi static int usnic_fwd_devcmd_locked(struct usnic_fwd_dev *ufdev, int vnic_idx, 27*2183b990SUpinder Malhi enum vnic_devcmd_cmd cmd, u64 *a0, 28*2183b990SUpinder Malhi u64 *a1) 29*2183b990SUpinder Malhi { 30*2183b990SUpinder Malhi int status; 31*2183b990SUpinder Malhi struct net_device *netdev = ufdev->netdev; 32*2183b990SUpinder Malhi 33*2183b990SUpinder Malhi lockdep_assert_held(&ufdev->lock); 34*2183b990SUpinder Malhi 35*2183b990SUpinder Malhi status = enic_api_devcmd_proxy_by_index(netdev, 36*2183b990SUpinder Malhi vnic_idx, 37*2183b990SUpinder Malhi cmd, 38*2183b990SUpinder Malhi a0, a1, 39*2183b990SUpinder Malhi 1000); 40*2183b990SUpinder Malhi if (status) { 41*2183b990SUpinder Malhi if (status == ERR_EINVAL && cmd == CMD_DEL_FILTER) { 42*2183b990SUpinder Malhi usnic_dbg("Dev %s vnic idx %u cmd %u already deleted", 43*2183b990SUpinder Malhi ufdev->name, vnic_idx, cmd); 44*2183b990SUpinder Malhi } else { 45*2183b990SUpinder Malhi usnic_err("Dev %s vnic idx %u cmd %u failed with status %d\n", 46*2183b990SUpinder Malhi ufdev->name, vnic_idx, cmd, 47*2183b990SUpinder Malhi status); 48*2183b990SUpinder Malhi } 49*2183b990SUpinder Malhi } else { 50*2183b990SUpinder Malhi usnic_dbg("Dev %s vnic idx %u cmd %u success", 51*2183b990SUpinder Malhi ufdev->name, vnic_idx, cmd); 52*2183b990SUpinder Malhi } 53*2183b990SUpinder Malhi 54*2183b990SUpinder Malhi return status; 55*2183b990SUpinder Malhi } 56*2183b990SUpinder Malhi 57*2183b990SUpinder Malhi static int usnic_fwd_devcmd(struct usnic_fwd_dev *ufdev, int vnic_idx, 58*2183b990SUpinder Malhi enum vnic_devcmd_cmd cmd, u64 *a0, u64 *a1) 59*2183b990SUpinder Malhi { 60*2183b990SUpinder Malhi int status; 61*2183b990SUpinder Malhi 62*2183b990SUpinder Malhi spin_lock(&ufdev->lock); 63*2183b990SUpinder Malhi status = usnic_fwd_devcmd_locked(ufdev, vnic_idx, cmd, a0, a1); 64*2183b990SUpinder Malhi spin_unlock(&ufdev->lock); 65*2183b990SUpinder Malhi 66*2183b990SUpinder Malhi return status; 67*2183b990SUpinder Malhi } 68*2183b990SUpinder 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); 80*2183b990SUpinder Malhi strncpy(ufdev->name, netdev_name(ufdev->netdev), 81*2183b990SUpinder 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 91*2183b990SUpinder Malhi void usnic_fwd_set_mac(struct usnic_fwd_dev *ufdev, char mac[ETH_ALEN]) 92e3cf00d0SUpinder Malhi { 93e3cf00d0SUpinder Malhi spin_lock(&ufdev->lock); 94*2183b990SUpinder Malhi memcpy(&ufdev->mac, mac, sizeof(ufdev->mac)); 95e3cf00d0SUpinder Malhi spin_unlock(&ufdev->lock); 96e3cf00d0SUpinder Malhi } 97e3cf00d0SUpinder Malhi 98*2183b990SUpinder Malhi void usnic_fwd_carrier_up(struct usnic_fwd_dev *ufdev) 99e3cf00d0SUpinder Malhi { 100*2183b990SUpinder Malhi spin_lock(&ufdev->lock); 101*2183b990SUpinder Malhi ufdev->link_up = 1; 102*2183b990SUpinder Malhi spin_unlock(&ufdev->lock); 103e3cf00d0SUpinder Malhi } 104e3cf00d0SUpinder Malhi 105*2183b990SUpinder Malhi void usnic_fwd_carrier_down(struct usnic_fwd_dev *ufdev) 106*2183b990SUpinder Malhi { 107*2183b990SUpinder Malhi spin_lock(&ufdev->lock); 108*2183b990SUpinder Malhi ufdev->link_up = 0; 109*2183b990SUpinder Malhi spin_unlock(&ufdev->lock); 110e3cf00d0SUpinder Malhi } 111e3cf00d0SUpinder Malhi 112*2183b990SUpinder Malhi void usnic_fwd_set_mtu(struct usnic_fwd_dev *ufdev, unsigned int mtu) 113*2183b990SUpinder Malhi { 114*2183b990SUpinder Malhi spin_lock(&ufdev->lock); 115*2183b990SUpinder Malhi ufdev->mtu = mtu; 116*2183b990SUpinder Malhi spin_unlock(&ufdev->lock); 117*2183b990SUpinder Malhi } 118*2183b990SUpinder Malhi 119*2183b990SUpinder Malhi static int usnic_fwd_dev_ready_locked(struct usnic_fwd_dev *ufdev) 120*2183b990SUpinder Malhi { 121*2183b990SUpinder Malhi lockdep_assert_held(&ufdev->lock); 122*2183b990SUpinder Malhi 123*2183b990SUpinder Malhi if (!ufdev->link_up) 124*2183b990SUpinder Malhi return -EPERM; 125*2183b990SUpinder Malhi 126*2183b990SUpinder Malhi return 0; 127*2183b990SUpinder Malhi } 128*2183b990SUpinder Malhi 129*2183b990SUpinder Malhi static void fill_tlv(struct filter_tlv *tlv, struct filter *filter, 130*2183b990SUpinder Malhi struct filter_action *action) 131*2183b990SUpinder Malhi { 132e3cf00d0SUpinder Malhi tlv->type = CLSF_TLV_FILTER; 133e3cf00d0SUpinder Malhi tlv->length = sizeof(struct filter); 134*2183b990SUpinder Malhi *((struct filter *)&tlv->val) = *filter; 135*2183b990SUpinder Malhi 136e3cf00d0SUpinder Malhi tlv = (struct filter_tlv *)((char *)tlv + sizeof(struct filter_tlv) + 137e3cf00d0SUpinder Malhi sizeof(struct filter)); 138e3cf00d0SUpinder Malhi tlv->type = CLSF_TLV_ACTION; 139e3cf00d0SUpinder Malhi tlv->length = sizeof(struct filter_action); 140*2183b990SUpinder Malhi *((struct filter_action *)&tlv->val) = *action; 141*2183b990SUpinder Malhi } 142e3cf00d0SUpinder Malhi 143*2183b990SUpinder Malhi struct usnic_fwd_flow* 144*2183b990SUpinder Malhi usnic_fwd_alloc_flow(struct usnic_fwd_dev *ufdev, struct filter *filter, 145*2183b990SUpinder Malhi struct usnic_filter_action *uaction) 146*2183b990SUpinder Malhi { 147*2183b990SUpinder Malhi struct filter_tlv *tlv; 148*2183b990SUpinder Malhi struct pci_dev *pdev; 149*2183b990SUpinder Malhi struct usnic_fwd_flow *flow; 150*2183b990SUpinder Malhi uint64_t a0, a1; 151*2183b990SUpinder Malhi uint64_t tlv_size; 152*2183b990SUpinder Malhi dma_addr_t tlv_pa; 153*2183b990SUpinder Malhi int status; 154*2183b990SUpinder Malhi 155*2183b990SUpinder Malhi pdev = ufdev->pdev; 156*2183b990SUpinder Malhi tlv_size = (2*sizeof(struct filter_tlv) + sizeof(struct filter) + 157*2183b990SUpinder Malhi sizeof(struct filter_action)); 158*2183b990SUpinder Malhi 159*2183b990SUpinder Malhi flow = kzalloc(sizeof(*flow), GFP_ATOMIC); 160*2183b990SUpinder Malhi if (!flow) 161*2183b990SUpinder Malhi return ERR_PTR(-ENOMEM); 162*2183b990SUpinder Malhi 163*2183b990SUpinder Malhi tlv = pci_alloc_consistent(pdev, tlv_size, &tlv_pa); 164*2183b990SUpinder Malhi if (!tlv) { 165*2183b990SUpinder Malhi usnic_err("Failed to allocate memory\n"); 166*2183b990SUpinder Malhi status = -ENOMEM; 167*2183b990SUpinder Malhi goto out_free_flow; 168*2183b990SUpinder Malhi } 169*2183b990SUpinder Malhi 170*2183b990SUpinder Malhi fill_tlv(tlv, filter, &uaction->action); 171*2183b990SUpinder Malhi 172*2183b990SUpinder Malhi spin_lock(&ufdev->lock); 173*2183b990SUpinder Malhi status = usnic_fwd_dev_ready_locked(ufdev); 174*2183b990SUpinder Malhi if (status) { 175*2183b990SUpinder Malhi usnic_err("Forwarding dev %s not ready with status %d\n", 176*2183b990SUpinder Malhi ufdev->name, status); 177*2183b990SUpinder Malhi goto out_free_tlv; 178*2183b990SUpinder Malhi } 179*2183b990SUpinder Malhi 180*2183b990SUpinder Malhi /* Issue Devcmd */ 181*2183b990SUpinder Malhi a0 = tlv_pa; 182*2183b990SUpinder Malhi a1 = tlv_size; 183*2183b990SUpinder Malhi status = usnic_fwd_devcmd_locked(ufdev, uaction->vnic_idx, 184*2183b990SUpinder Malhi CMD_ADD_FILTER, &a0, &a1); 185e3cf00d0SUpinder Malhi if (status) { 186e3cf00d0SUpinder Malhi usnic_err("VF %s Filter add failed with status:%d", 187*2183b990SUpinder Malhi ufdev->name, status); 188*2183b990SUpinder Malhi status = -EFAULT; 189*2183b990SUpinder Malhi goto out_free_tlv; 190e3cf00d0SUpinder Malhi } else { 191*2183b990SUpinder Malhi usnic_dbg("VF %s FILTER ID:%llu", ufdev->name, a0); 192e3cf00d0SUpinder Malhi } 193e3cf00d0SUpinder Malhi 194*2183b990SUpinder Malhi flow->flow_id = (uint32_t) a0; 195*2183b990SUpinder Malhi flow->vnic_idx = uaction->vnic_idx; 196*2183b990SUpinder Malhi flow->ufdev = ufdev; 197e3cf00d0SUpinder Malhi 198*2183b990SUpinder Malhi out_free_tlv: 199*2183b990SUpinder Malhi spin_unlock(&ufdev->lock); 200*2183b990SUpinder Malhi pci_free_consistent(pdev, tlv_size, tlv, tlv_pa); 201*2183b990SUpinder Malhi if (!status) 202*2183b990SUpinder Malhi return flow; 203*2183b990SUpinder Malhi out_free_flow: 204*2183b990SUpinder Malhi kfree(flow); 205*2183b990SUpinder Malhi return ERR_PTR(status); 206e3cf00d0SUpinder Malhi } 207e3cf00d0SUpinder Malhi 208*2183b990SUpinder Malhi int usnic_fwd_dealloc_flow(struct usnic_fwd_flow *flow) 209e3cf00d0SUpinder Malhi { 210e3cf00d0SUpinder Malhi int status; 211e3cf00d0SUpinder Malhi u64 a0, a1; 212e3cf00d0SUpinder Malhi 213*2183b990SUpinder Malhi a0 = flow->flow_id; 214e3cf00d0SUpinder Malhi 215*2183b990SUpinder Malhi status = usnic_fwd_devcmd(flow->ufdev, flow->vnic_idx, 216e3cf00d0SUpinder Malhi CMD_DEL_FILTER, &a0, &a1); 217e3cf00d0SUpinder Malhi if (status) { 218e3cf00d0SUpinder Malhi if (status == ERR_EINVAL) { 219e3cf00d0SUpinder Malhi usnic_dbg("Filter %u already deleted for VF Idx %u pf: %s status: %d", 220*2183b990SUpinder Malhi flow->flow_id, flow->vnic_idx, 221*2183b990SUpinder Malhi flow->ufdev->name, status); 222e3cf00d0SUpinder Malhi } else { 223e3cf00d0SUpinder Malhi usnic_err("PF %s VF Idx %u Filter: %u FILTER DELETE failed with status %d", 224*2183b990SUpinder Malhi flow->ufdev->name, flow->vnic_idx, 225*2183b990SUpinder Malhi flow->flow_id, status); 226e3cf00d0SUpinder Malhi } 227*2183b990SUpinder Malhi status = 0; 228*2183b990SUpinder Malhi /* 229*2183b990SUpinder Malhi * Log the error and fake success to the caller because if 230*2183b990SUpinder Malhi * a flow fails to be deleted in the firmware, it is an 231*2183b990SUpinder Malhi * unrecoverable error. 232*2183b990SUpinder Malhi */ 233e3cf00d0SUpinder Malhi } else { 234e3cf00d0SUpinder Malhi usnic_dbg("PF %s VF Idx %u Filter: %u FILTER DELETED", 235*2183b990SUpinder Malhi flow->ufdev->name, flow->vnic_idx, 236*2183b990SUpinder Malhi flow->flow_id); 237e3cf00d0SUpinder Malhi } 238e3cf00d0SUpinder Malhi 239*2183b990SUpinder Malhi kfree(flow); 240e3cf00d0SUpinder Malhi return status; 241e3cf00d0SUpinder Malhi } 242e3cf00d0SUpinder Malhi 243*2183b990SUpinder Malhi int usnic_fwd_enable_qp(struct usnic_fwd_dev *ufdev, int vnic_idx, int qp_idx) 244e3cf00d0SUpinder Malhi { 245e3cf00d0SUpinder Malhi int status; 246e3cf00d0SUpinder Malhi struct net_device *pf_netdev; 247e3cf00d0SUpinder Malhi u64 a0, a1; 248e3cf00d0SUpinder Malhi 249e3cf00d0SUpinder Malhi pf_netdev = ufdev->netdev; 250*2183b990SUpinder Malhi a0 = qp_idx; 251e3cf00d0SUpinder Malhi a1 = CMD_QP_RQWQ; 252e3cf00d0SUpinder Malhi 253*2183b990SUpinder Malhi status = usnic_fwd_devcmd(ufdev, vnic_idx, CMD_QP_ENABLE, 254*2183b990SUpinder Malhi &a0, &a1); 255e3cf00d0SUpinder Malhi if (status) { 256e3cf00d0SUpinder Malhi usnic_err("PF %s VNIC Index %u RQ Index: %u ENABLE Failed with status %d", 257e3cf00d0SUpinder Malhi netdev_name(pf_netdev), 258e3cf00d0SUpinder Malhi vnic_idx, 259*2183b990SUpinder Malhi qp_idx, 260e3cf00d0SUpinder Malhi status); 261e3cf00d0SUpinder Malhi } else { 262e3cf00d0SUpinder Malhi usnic_dbg("PF %s VNIC Index %u RQ Index: %u ENABLED", 263e3cf00d0SUpinder Malhi netdev_name(pf_netdev), 264*2183b990SUpinder Malhi vnic_idx, qp_idx); 265e3cf00d0SUpinder Malhi } 266e3cf00d0SUpinder Malhi 267e3cf00d0SUpinder Malhi return status; 268e3cf00d0SUpinder Malhi } 269e3cf00d0SUpinder Malhi 270*2183b990SUpinder Malhi int usnic_fwd_disable_qp(struct usnic_fwd_dev *ufdev, int vnic_idx, int qp_idx) 271e3cf00d0SUpinder Malhi { 272e3cf00d0SUpinder Malhi int status; 273e3cf00d0SUpinder Malhi u64 a0, a1; 274e3cf00d0SUpinder Malhi struct net_device *pf_netdev; 275e3cf00d0SUpinder Malhi 276e3cf00d0SUpinder Malhi pf_netdev = ufdev->netdev; 277*2183b990SUpinder Malhi a0 = qp_idx; 278e3cf00d0SUpinder Malhi a1 = CMD_QP_RQWQ; 279e3cf00d0SUpinder Malhi 280*2183b990SUpinder Malhi status = usnic_fwd_devcmd(ufdev, vnic_idx, CMD_QP_DISABLE, 281*2183b990SUpinder Malhi &a0, &a1); 282e3cf00d0SUpinder Malhi if (status) { 283e3cf00d0SUpinder Malhi usnic_err("PF %s VNIC Index %u RQ Index: %u DISABLE Failed with status %d", 284e3cf00d0SUpinder Malhi netdev_name(pf_netdev), 285e3cf00d0SUpinder Malhi vnic_idx, 286*2183b990SUpinder Malhi qp_idx, 287e3cf00d0SUpinder Malhi status); 288e3cf00d0SUpinder Malhi } else { 289e3cf00d0SUpinder Malhi usnic_dbg("PF %s VNIC Index %u RQ Index: %u DISABLED", 290e3cf00d0SUpinder Malhi netdev_name(pf_netdev), 291e3cf00d0SUpinder Malhi vnic_idx, 292*2183b990SUpinder Malhi qp_idx); 293e3cf00d0SUpinder Malhi } 294e3cf00d0SUpinder Malhi 295e3cf00d0SUpinder Malhi return status; 296e3cf00d0SUpinder Malhi } 297