qed: Add support for PTP resource locking.
authorsudarsana.kalluru@cavium.com <sudarsana.kalluru@cavium.com>
Wed, 26 Apr 2017 16:00:50 +0000 (09:00 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 27 Apr 2017 20:51:33 +0000 (16:51 -0400)
The patch adds support for per-port resource lock in favour of PTP.
PTP module acquires/releases the MFW resource lock while enabling/
disabling the PTP on the interface. The PF instance which has the
ownership of this resource lock will get the exclusive access to the
PTP clock functionality on the port.

Signed-off-by: Sudarsana Reddy Kalluru <Sudarsana.Kalluru@cavium.com>
Signed-off-by: Yuval Mintz <Yuval.Mintz@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qed/qed.h
drivers/net/ethernet/qlogic/qed/qed_dev.c
drivers/net/ethernet/qlogic/qed/qed_mcp.h
drivers/net/ethernet/qlogic/qed/qed_ptp.c

index 8a8f139..3f8d07b 100644 (file)
@@ -767,6 +767,7 @@ void qed_configure_vp_wfq_on_link_change(struct qed_dev *cdev,
 
 void qed_clean_wfq_db(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
 int qed_device_num_engines(struct qed_dev *cdev);
+int qed_device_get_port_id(struct qed_dev *cdev);
 
 #define QED_LEADING_HWFN(dev)   (&dev->hwfns[0])
 
index 2a3ae00..aa1a4d5 100644 (file)
@@ -4064,3 +4064,17 @@ int qed_device_num_engines(struct qed_dev *cdev)
 {
        return QED_IS_BB(cdev) ? 2 : 1;
 }
+
+static int qed_device_num_ports(struct qed_dev *cdev)
+{
+       /* in CMT always only one port */
+       if (cdev->num_hwfns > 1)
+               return 1;
+
+       return cdev->num_ports_in_engines * qed_device_num_engines(cdev);
+}
+
+int qed_device_get_port_id(struct qed_dev *cdev)
+{
+       return (QED_LEADING_HWFN(cdev)->abs_pf_id) % qed_device_num_ports(cdev);
+}
index e8cf597..5ae35d6 100644 (file)
@@ -795,6 +795,10 @@ int qed_mcp_ov_update_eswitch(struct qed_hwfn *p_hwfn,
 
 enum qed_resc_lock {
        QED_RESC_LOCK_DBG_DUMP = QED_MCP_RESC_LOCK_MIN_VAL,
+       QED_RESC_LOCK_PTP_PORT0,
+       QED_RESC_LOCK_PTP_PORT1,
+       QED_RESC_LOCK_PTP_PORT2,
+       QED_RESC_LOCK_PTP_PORT3,
        QED_RESC_LOCK_RESC_ALLOC = QED_MCP_RESC_LOCK_MAX_VAL,
        QED_RESC_LOCK_RESC_INVALID
 };
index 80c9c0b..26a9baf 100644 (file)
@@ -34,6 +34,7 @@
 #include "qed_dev_api.h"
 #include "qed_hw.h"
 #include "qed_l2.h"
+#include "qed_mcp.h"
 #include "qed_ptp.h"
 #include "qed_reg_addr.h"
 
 #define QED_DRIFT_CNTR_DIRECTION_SHIFT         31
 #define QED_TIMESTAMP_MASK                     BIT(16)
 
+static enum qed_resc_lock qed_ptcdev_to_resc(struct qed_hwfn *p_hwfn)
+{
+       switch (qed_device_get_port_id(p_hwfn->cdev)) {
+       case 0:
+               return QED_RESC_LOCK_PTP_PORT0;
+       case 1:
+               return QED_RESC_LOCK_PTP_PORT1;
+       case 2:
+               return QED_RESC_LOCK_PTP_PORT2;
+       case 3:
+               return QED_RESC_LOCK_PTP_PORT3;
+       default:
+               return QED_RESC_LOCK_RESC_INVALID;
+       }
+}
+
+static int qed_ptp_res_lock(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
+{
+       struct qed_resc_lock_params params;
+       enum qed_resc_lock resource;
+       int rc;
+
+       resource = qed_ptcdev_to_resc(p_hwfn);
+       if (resource == QED_RESC_LOCK_RESC_INVALID)
+               return -EINVAL;
+
+       qed_mcp_resc_lock_default_init(&params, NULL, resource, true);
+
+       rc = qed_mcp_resc_lock(p_hwfn, p_ptt, &params);
+       if (rc && rc != -EINVAL) {
+               return rc;
+       } else if (rc == -EINVAL) {
+               /* MFW doesn't support resource locking, first PF on the port
+                * has lock ownership.
+                */
+               if (p_hwfn->abs_pf_id < p_hwfn->cdev->num_ports_in_engines)
+                       return 0;
+
+               DP_INFO(p_hwfn, "PF doesn't have lock ownership\n");
+               return -EBUSY;
+       } else if (!rc && !params.b_granted) {
+               DP_INFO(p_hwfn, "Failed to acquire ptp resource lock\n");
+               return -EBUSY;
+       }
+
+       return rc;
+}
+
+static int qed_ptp_res_unlock(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
+{
+       struct qed_resc_unlock_params params;
+       enum qed_resc_lock resource;
+       int rc;
+
+       resource = qed_ptcdev_to_resc(p_hwfn);
+       if (resource == QED_RESC_LOCK_RESC_INVALID)
+               return -EINVAL;
+
+       qed_mcp_resc_lock_default_init(NULL, &params, resource, true);
+
+       rc = qed_mcp_resc_unlock(p_hwfn, p_ptt, &params);
+       if (rc == -EINVAL) {
+               /* MFW doesn't support locking, first PF has lock ownership */
+               if (p_hwfn->abs_pf_id < p_hwfn->cdev->num_ports_in_engines) {
+                       rc = 0;
+               } else {
+                       DP_INFO(p_hwfn, "PF doesn't have lock ownership\n");
+                       return -EINVAL;
+               }
+       } else if (rc) {
+               DP_INFO(p_hwfn, "Failed to release the ptp resource lock\n");
+       }
+
+       return rc;
+}
+
 /* Read Rx timestamp */
 static int qed_ptp_hw_read_rx_ts(struct qed_dev *cdev, u64 *timestamp)
 {
@@ -249,6 +326,14 @@ static int qed_ptp_hw_enable(struct qed_dev *cdev)
 {
        struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
        struct qed_ptt *p_ptt = p_hwfn->p_ptp_ptt;
+       int rc;
+
+       rc = qed_ptp_res_lock(p_hwfn, p_ptt);
+       if (rc) {
+               DP_INFO(p_hwfn,
+                       "Couldn't acquire the resource lock, skip ptp enable for this PF\n");
+               return rc;
+       }
 
        /* Reset PTP event detection rules - will be configured in the IOCTL */
        qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_PTP_PARAM_MASK, 0x7FF);
@@ -305,6 +390,8 @@ static int qed_ptp_hw_disable(struct qed_dev *cdev)
        struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
        struct qed_ptt *p_ptt = p_hwfn->p_ptp_ptt;
 
+       qed_ptp_res_unlock(p_hwfn, p_ptt);
+
        /* Reset PTP event detection rules */
        qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_PTP_PARAM_MASK, 0x7FF);
        qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_PTP_RULE_MASK, 0x3FFF);