/**
  * enum idpf_mbx_opc - PF/VF mailbox commands
  * @idpf_mbq_opc_send_msg_to_cp: used by PF or VF to send a message to its CP
+ * @idpf_mbq_opc_send_msg_to_peer_drv: used by PF or VF to send a message to
+ *                                    any peer driver
  */
 enum idpf_mbx_opc {
        idpf_mbq_opc_send_msg_to_cp             = 0x0801,
+       idpf_mbq_opc_send_msg_to_peer_drv       = 0x0804,
 };
 
 /* API supported for control queue management */
 
        return ((u64)hi << 32) | lo;
 }
 
+/**
+ * idpf_ptp_read_src_clk_reg_mailbox - Read the main timer value through mailbox
+ * @adapter: Driver specific private structure
+ * @sts: Optional parameter for holding a pair of system timestamps from
+ *      the system clock. Will be ignored when NULL is given.
+ * @src_clk: Returned main timer value in nanoseconds unit
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int idpf_ptp_read_src_clk_reg_mailbox(struct idpf_adapter *adapter,
+                                            struct ptp_system_timestamp *sts,
+                                            u64 *src_clk)
+{
+       struct idpf_ptp_dev_timers clk_time;
+       int err;
+
+       /* Read the system timestamp pre PHC read */
+       ptp_read_system_prets(sts);
+
+       err = idpf_ptp_get_dev_clk_time(adapter, &clk_time);
+       if (err)
+               return err;
+
+       /* Read the system timestamp post PHC read */
+       ptp_read_system_postts(sts);
+
+       *src_clk = clk_time.dev_clk_time_ns;
+
+       return 0;
+}
+
 /**
  * idpf_ptp_read_src_clk_reg - Read the main timer value
  * @adapter: Driver specific private structure
        switch (adapter->ptp->get_dev_clk_time_access) {
        case IDPF_PTP_NONE:
                return -EOPNOTSUPP;
+       case IDPF_PTP_MAILBOX:
+               return idpf_ptp_read_src_clk_reg_mailbox(adapter, sts, src_clk);
        case IDPF_PTP_DIRECT:
                *src_clk = idpf_ptp_read_src_clk_reg_direct(adapter, sts);
                break;
 
        IDPF_PTP_MAILBOX,
 };
 
+/**
+ * struct idpf_ptp_secondary_mbx - PTP secondary mailbox
+ * @peer_mbx_q_id: PTP mailbox queue ID
+ * @peer_id: Peer ID for PTP Device Control daemon
+ * @valid: indicates whether secondary mailblox is supported by the Control
+ *        Plane
+ */
+struct idpf_ptp_secondary_mbx {
+       u16 peer_mbx_q_id;
+       u16 peer_id;
+       bool valid:1;
+};
+
 /**
  * struct idpf_ptp - PTP parameters
  * @info: structure defining PTP hardware capabilities
  * @caps: PTP capabilities negotiated with the Control Plane
  * @get_dev_clk_time_access: access type for getting the device clock time
  * @rsv: reserved bits
+ * @secondary_mbx: parameters for using dedicated PTP mailbox
  * @read_dev_clk_lock: spinlock protecting access to the device clock read
  *                    operation executed by the HW latch
  */
        u32 caps;
        enum idpf_ptp_access get_dev_clk_time_access:2;
        u32 rsv:30;
+       struct idpf_ptp_secondary_mbx secondary_mbx;
        spinlock_t read_dev_clk_lock;
 };
 
        return ptp->adapter;
 }
 
+/**
+ * struct idpf_ptp_dev_timers - System time and device time values
+ * @sys_time_ns: system time value expressed in nanoseconds
+ * @dev_clk_time_ns: device clock time value expressed in nanoseconds
+ */
+struct idpf_ptp_dev_timers {
+       u64 sys_time_ns;
+       u64 dev_clk_time_ns;
+};
+
 #if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
 int idpf_ptp_init(struct idpf_adapter *adapter);
 void idpf_ptp_release(struct idpf_adapter *adapter);
 int idpf_ptp_get_caps(struct idpf_adapter *adapter);
 void idpf_ptp_get_features_access(const struct idpf_adapter *adapter);
+int idpf_ptp_get_dev_clk_time(struct idpf_adapter *adapter,
+                             struct idpf_ptp_dev_timers *dev_clk_time);
 #else /* CONFIG_PTP_1588_CLOCK */
 static inline int idpf_ptp_init(struct idpf_adapter *adapter)
 {
 static inline void
 idpf_ptp_get_features_access(const struct idpf_adapter *adapter) { }
 
+static inline int
+idpf_ptp_get_dev_clk_time(struct idpf_adapter *adapter,
+                         struct idpf_ptp_dev_timers *dev_clk_time)
+{
+       return -EOPNOTSUPP;
+}
+
 #endif /* CONFIG_PTP_1588_CLOCK */
 #endif /* _IDPF_PTP_H */
 
        return err;
 }
 
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+/**
+ * idpf_ptp_is_mb_msg - Check if the message is PTP-related
+ * @op: virtchnl opcode
+ *
+ * Return: true if msg is PTP-related, false otherwise.
+ */
+static bool idpf_ptp_is_mb_msg(u32 op)
+{
+       switch (op) {
+       case VIRTCHNL2_OP_PTP_GET_DEV_CLK_TIME:
+       case VIRTCHNL2_OP_PTP_GET_CROSS_TIME:
+               return true;
+       default:
+               return false;
+       }
+}
+
+/**
+ * idpf_prepare_ptp_mb_msg - Prepare PTP related message
+ *
+ * @adapter: Driver specific private structure
+ * @op: virtchnl opcode
+ * @ctlq_msg: Corresponding control queue message
+ */
+static void idpf_prepare_ptp_mb_msg(struct idpf_adapter *adapter, u32 op,
+                                   struct idpf_ctlq_msg *ctlq_msg)
+{
+       /* If the message is PTP-related and the secondary mailbox is available,
+        * send the message through the secondary mailbox.
+        */
+       if (!idpf_ptp_is_mb_msg(op) || !adapter->ptp->secondary_mbx.valid)
+               return;
+
+       ctlq_msg->opcode = idpf_mbq_opc_send_msg_to_peer_drv;
+       ctlq_msg->func_id = adapter->ptp->secondary_mbx.peer_mbx_q_id;
+       ctlq_msg->host_id = adapter->ptp->secondary_mbx.peer_id;
+}
+#else /* !CONFIG_PTP_1588_CLOCK */
+static void idpf_prepare_ptp_mb_msg(struct idpf_adapter *adapter, u32 op,
+                                   struct idpf_ctlq_msg *ctlq_msg)
+{ }
+#endif /* CONFIG_PTP_1588_CLOCK */
+
 /**
  * idpf_send_mb_msg - Send message over mailbox
  * @adapter: Driver specific private structure
 
        ctlq_msg->opcode = idpf_mbq_opc_send_msg_to_cp;
        ctlq_msg->func_id = 0;
+
+       idpf_prepare_ptp_mb_msg(adapter, op, ctlq_msg);
+
        ctlq_msg->data_len = msg_size;
        ctlq_msg->cookie.mbx.chnl_opcode = op;
        ctlq_msg->cookie.mbx.chnl_retval = 0;
 
                .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
        };
        struct virtchnl2_ptp_clk_reg_offsets clock_offsets;
+       struct idpf_ptp_secondary_mbx *scnd_mbx;
        struct idpf_ptp *ptp = adapter->ptp;
        enum idpf_ptp_access access_type;
        u32 temp_offset;
 
        ptp->caps = le32_to_cpu(recv_ptp_caps_msg->caps);
 
+       scnd_mbx = &ptp->secondary_mbx;
+       scnd_mbx->peer_mbx_q_id = le16_to_cpu(recv_ptp_caps_msg->peer_mbx_q_id);
+
+       /* if the ptp_mb_q_id holds invalid value (0xffff), the secondary
+        * mailbox is not supported.
+        */
+       scnd_mbx->valid = scnd_mbx->peer_mbx_q_id != 0xffff;
+       if (scnd_mbx->valid)
+               scnd_mbx->peer_id = recv_ptp_caps_msg->peer_id;
+
        /* Determine the access type for the PTP features */
        idpf_ptp_get_features_access(adapter);
 
 
        return 0;
 }
+
+/**
+ * idpf_ptp_get_dev_clk_time - Send virtchnl get device clk time message
+ * @adapter: Driver specific private structure
+ * @dev_clk_time: Pointer to the device clock structure where the value is set
+ *
+ * Send virtchnl get time message to get the time of the clock.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+int idpf_ptp_get_dev_clk_time(struct idpf_adapter *adapter,
+                             struct idpf_ptp_dev_timers *dev_clk_time)
+{
+       struct virtchnl2_ptp_get_dev_clk_time get_dev_clk_time_msg;
+       struct idpf_vc_xn_params xn_params = {
+               .vc_op = VIRTCHNL2_OP_PTP_GET_DEV_CLK_TIME,
+               .send_buf.iov_base = &get_dev_clk_time_msg,
+               .send_buf.iov_len = sizeof(get_dev_clk_time_msg),
+               .recv_buf.iov_base = &get_dev_clk_time_msg,
+               .recv_buf.iov_len = sizeof(get_dev_clk_time_msg),
+               .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
+       };
+       int reply_sz;
+       u64 dev_time;
+
+       reply_sz = idpf_vc_xn_exec(adapter, &xn_params);
+       if (reply_sz < 0)
+               return reply_sz;
+       if (reply_sz != sizeof(get_dev_clk_time_msg))
+               return -EIO;
+
+       dev_time = le64_to_cpu(get_dev_clk_time_msg.dev_time_ns);
+       dev_clk_time->dev_clk_time_ns = dev_time;
+
+       return 0;
+}