These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / infiniband / hw / ocrdma / ocrdma_hw.c
index 47615ff..283ca84 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) CNA Adapters.              *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * This software is available to you under a choice of one of two licenses.
+ * You may choose to be licensed under the terms of the GNU General Public
+ * License (GPL) Version 2, available from the file COPYING in the main
+ * directory of this source tree, or the BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #include <linux/sched.h>
 #include <linux/interrupt.h>
@@ -32,6 +47,7 @@
 
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_user_verbs.h>
+#include <rdma/ib_cache.h>
 
 #include "ocrdma.h"
 #include "ocrdma_hw.h"
@@ -563,6 +579,8 @@ static int ocrdma_mbx_create_mq(struct ocrdma_dev *dev,
 
        cmd->async_event_bitmap = BIT(OCRDMA_ASYNC_GRP5_EVE_CODE);
        cmd->async_event_bitmap |= BIT(OCRDMA_ASYNC_RDMA_EVE_CODE);
+       /* Request link events on this  MQ. */
+       cmd->async_event_bitmap |= BIT(OCRDMA_ASYNC_LINK_EVE_CODE);
 
        cmd->async_cqid_ringsize = cq->id;
        cmd->async_cqid_ringsize |= (ocrdma_encoded_q_len(mq->len) <<
@@ -663,11 +681,33 @@ static void ocrdma_dispatch_ibevent(struct ocrdma_dev *dev,
        int dev_event = 0;
        int type = (cqe->valid_ae_event & OCRDMA_AE_MCQE_EVENT_TYPE_MASK) >>
            OCRDMA_AE_MCQE_EVENT_TYPE_SHIFT;
+       u16 qpid = cqe->qpvalid_qpid & OCRDMA_AE_MCQE_QPID_MASK;
+       u16 cqid = cqe->cqvalid_cqid & OCRDMA_AE_MCQE_CQID_MASK;
+
+       /*
+        * Some FW version returns wrong qp or cq ids in CQEs.
+        * Checking whether the IDs are valid
+        */
+
+       if (cqe->qpvalid_qpid & OCRDMA_AE_MCQE_QPVALID) {
+               if (qpid < dev->attr.max_qp)
+                       qp = dev->qp_tbl[qpid];
+               if (qp == NULL) {
+                       pr_err("ocrdma%d:Async event - qpid %u is not valid\n",
+                              dev->id, qpid);
+                       return;
+               }
+       }
 
-       if (cqe->qpvalid_qpid & OCRDMA_AE_MCQE_QPVALID)
-               qp = dev->qp_tbl[cqe->qpvalid_qpid & OCRDMA_AE_MCQE_QPID_MASK];
-       if (cqe->cqvalid_cqid & OCRDMA_AE_MCQE_CQVALID)
-               cq = dev->cq_tbl[cqe->cqvalid_cqid & OCRDMA_AE_MCQE_CQID_MASK];
+       if (cqe->cqvalid_cqid & OCRDMA_AE_MCQE_CQVALID) {
+               if (cqid < dev->attr.max_cq)
+                       cq = dev->cq_tbl[cqid];
+               if (cq == NULL) {
+                       pr_err("ocrdma%d:Async event - cqid %u is not valid\n",
+                              dev->id, cqid);
+                       return;
+               }
+       }
 
        memset(&ib_evt, 0, sizeof(ib_evt));
 
@@ -781,20 +821,42 @@ static void ocrdma_process_grp5_aync(struct ocrdma_dev *dev,
        }
 }
 
+static void ocrdma_process_link_state(struct ocrdma_dev *dev,
+                                     struct ocrdma_ae_mcqe *cqe)
+{
+       struct ocrdma_ae_lnkst_mcqe *evt;
+       u8 lstate;
+
+       evt = (struct ocrdma_ae_lnkst_mcqe *)cqe;
+       lstate = ocrdma_get_ae_link_state(evt->speed_state_ptn);
+
+       if (!(lstate & OCRDMA_AE_LSC_LLINK_MASK))
+               return;
+
+       if (dev->flags & OCRDMA_FLAGS_LINK_STATUS_INIT)
+               ocrdma_update_link_state(dev, (lstate & OCRDMA_LINK_ST_MASK));
+}
+
 static void ocrdma_process_acqe(struct ocrdma_dev *dev, void *ae_cqe)
 {
        /* async CQE processing */
        struct ocrdma_ae_mcqe *cqe = ae_cqe;
        u32 evt_code = (cqe->valid_ae_event & OCRDMA_AE_MCQE_EVENT_CODE_MASK) >>
                        OCRDMA_AE_MCQE_EVENT_CODE_SHIFT;
-
-       if (evt_code == OCRDMA_ASYNC_RDMA_EVE_CODE)
+       switch (evt_code) {
+       case OCRDMA_ASYNC_LINK_EVE_CODE:
+               ocrdma_process_link_state(dev, cqe);
+               break;
+       case OCRDMA_ASYNC_RDMA_EVE_CODE:
                ocrdma_dispatch_ibevent(dev, cqe);
-       else if (evt_code == OCRDMA_ASYNC_GRP5_EVE_CODE)
+               break;
+       case OCRDMA_ASYNC_GRP5_EVE_CODE:
                ocrdma_process_grp5_aync(dev, cqe);
-       else
+               break;
+       default:
                pr_err("%s(%d) invalid evt code=0x%x\n", __func__,
                       dev->id, evt_code);
+       }
 }
 
 static void ocrdma_process_mcqe(struct ocrdma_dev *dev, struct ocrdma_mcqe *cqe)
@@ -1325,7 +1387,8 @@ mbx_err:
        return status;
 }
 
-int ocrdma_mbx_get_link_speed(struct ocrdma_dev *dev, u8 *lnk_speed)
+int ocrdma_mbx_get_link_speed(struct ocrdma_dev *dev, u8 *lnk_speed,
+                             u8 *lnk_state)
 {
        int status = -ENOMEM;
        struct ocrdma_get_link_speed_rsp *rsp;
@@ -1346,8 +1409,11 @@ int ocrdma_mbx_get_link_speed(struct ocrdma_dev *dev, u8 *lnk_speed)
                goto mbx_err;
 
        rsp = (struct ocrdma_get_link_speed_rsp *)cmd;
-       *lnk_speed = (rsp->pflt_pps_ld_pnum & OCRDMA_PHY_PS_MASK)
-                       >> OCRDMA_PHY_PS_SHIFT;
+       if (lnk_speed)
+               *lnk_speed = (rsp->pflt_pps_ld_pnum & OCRDMA_PHY_PS_MASK)
+                             >> OCRDMA_PHY_PS_SHIFT;
+       if (lnk_state)
+               *lnk_state = (rsp->res_lnk_st & OCRDMA_LINK_ST_MASK);
 
 mbx_err:
        kfree(cmd);
@@ -2433,6 +2499,7 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
        int status;
        struct ib_ah_attr *ah_attr = &attrs->ah_attr;
        union ib_gid sgid, zgid;
+       struct ib_gid_attr sgid_attr;
        u32 vlan_id = 0xFFFF;
        u8 mac_addr[6];
        struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
@@ -2451,10 +2518,14 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
        cmd->flags |= OCRDMA_QP_PARA_FLOW_LBL_VALID;
        memcpy(&cmd->params.dgid[0], &ah_attr->grh.dgid.raw[0],
               sizeof(cmd->params.dgid));
-       status = ocrdma_query_gid(&dev->ibdev, 1,
-                       ah_attr->grh.sgid_index, &sgid);
-       if (status)
-               return status;
+
+       status = ib_get_cached_gid(&dev->ibdev, 1, ah_attr->grh.sgid_index,
+                                  &sgid, &sgid_attr);
+       if (!status && sgid_attr.ndev) {
+               vlan_id = rdma_vlan_dev_vlan_id(sgid_attr.ndev);
+               memcpy(mac_addr, sgid_attr.ndev->dev_addr, ETH_ALEN);
+               dev_put(sgid_attr.ndev);
+       }
 
        memset(&zgid, 0, sizeof(zgid));
        if (!memcmp(&sgid, &zgid, sizeof(zgid)))
@@ -2471,17 +2542,16 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
        ocrdma_cpu_to_le32(&cmd->params.dgid[0], sizeof(cmd->params.dgid));
        ocrdma_cpu_to_le32(&cmd->params.sgid[0], sizeof(cmd->params.sgid));
        cmd->params.vlan_dmac_b4_to_b5 = mac_addr[4] | (mac_addr[5] << 8);
-       if (attr_mask & IB_QP_VID) {
-               vlan_id = attrs->vlan_id;
-       } else if (dev->pfc_state) {
-               vlan_id = 0;
-               pr_err("ocrdma%d:Using VLAN with PFC is recommended\n",
-                       dev->id);
-               pr_err("ocrdma%d:Using VLAN 0 for this connection\n",
-                       dev->id);
-       }
 
-       if (vlan_id < 0x1000) {
+       if (vlan_id == 0xFFFF)
+               vlan_id = 0;
+       if (vlan_id || dev->pfc_state) {
+               if (!vlan_id) {
+                       pr_err("ocrdma%d:Using VLAN with PFC is recommended\n",
+                              dev->id);
+                       pr_err("ocrdma%d:Using VLAN 0 for this connection\n",
+                              dev->id);
+               }
                cmd->params.vlan_dmac_b4_to_b5 |=
                    vlan_id << OCRDMA_QP_PARAMS_VLAN_SHIFT;
                cmd->flags |= OCRDMA_QP_PARA_VLAN_EN_VALID;