SOF_TIMESTAMPING_RAW_HARDWARE;
 
        info->tx_types = BIT(HWTSTAMP_TX_OFF);
+       info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);
 
        if (!vport->tx_tstamp_caps ||
            vport->adapter->ptp->tx_tstamp_access == IDPF_PTP_NONE)
 
                return -EPERM;
        }
 
-       if (!idpf_ptp_is_vport_tx_tstamp_ena(vport)) {
+       if (!idpf_ptp_is_vport_tx_tstamp_ena(vport) &&
+           !idpf_ptp_is_vport_rx_tstamp_ena(vport)) {
                idpf_vport_ctrl_unlock(netdev);
                return -EOPNOTSUPP;
        }
                return -EPERM;
        }
 
-       if (!idpf_ptp_is_vport_tx_tstamp_ena(vport)) {
+       if (!idpf_ptp_is_vport_tx_tstamp_ena(vport) &&
+           !idpf_ptp_is_vport_rx_tstamp_ena(vport)) {
                idpf_vport_ctrl_unlock(netdev);
                return 0;
        }
 
        return 0;
 }
 
+/**
+ * idpf_ptp_update_phctime_rxq_grp - Update the cached PHC time for a given Rx
+ *                                  queue group.
+ * @grp: receive queue group in which Rx timestamp is enabled
+ * @split: Indicates whether the queue model is split or single queue
+ * @systime: Cached system time
+ */
+static void
+idpf_ptp_update_phctime_rxq_grp(const struct idpf_rxq_group *grp, bool split,
+                               u64 systime)
+{
+       struct idpf_rx_queue *rxq;
+       u16 i;
+
+       if (!split) {
+               for (i = 0; i < grp->singleq.num_rxq; i++) {
+                       rxq = grp->singleq.rxqs[i];
+                       if (rxq)
+                               WRITE_ONCE(rxq->cached_phc_time, systime);
+               }
+       } else {
+               for (i = 0; i < grp->splitq.num_rxq_sets; i++) {
+                       rxq = &grp->splitq.rxq_sets[i]->rxq;
+                       if (rxq)
+                               WRITE_ONCE(rxq->cached_phc_time, systime);
+               }
+       }
+}
+
 /**
  * idpf_ptp_update_cached_phctime - Update the cached PHC time values
  * @adapter: Driver specific private structure
  *
  * This function updates the system time values which are cached in the adapter
- * structure.
+ * structure and the Rx queues.
  *
  * This function must be called periodically to ensure that the cached value
  * is never more than 2 seconds old.
        WRITE_ONCE(adapter->ptp->cached_phc_time, systime);
        WRITE_ONCE(adapter->ptp->cached_phc_jiffies, jiffies);
 
+       idpf_for_each_vport(adapter, vport) {
+               bool split;
+
+               if (!vport || !vport->rxq_grps)
+                       continue;
+
+               split = idpf_is_queue_model_split(vport->rxq_model);
+
+               for (u16 i = 0; i < vport->num_rxq_grp; i++) {
+                       struct idpf_rxq_group *grp = &vport->rxq_grps[i];
+
+                       idpf_ptp_update_phctime_rxq_grp(grp, split, systime);
+               }
+       }
+
        return 0;
 }
 
        return 0;
 }
 
+/**
+ * idpf_ptp_set_rx_tstamp - Enable or disable Rx timestamping
+ * @vport: Virtual port structure
+ * @rx_filter: Receive timestamp filter
+ */
+static void idpf_ptp_set_rx_tstamp(struct idpf_vport *vport, int rx_filter)
+{
+       bool enable = true, splitq;
+
+       splitq = idpf_is_queue_model_split(vport->rxq_model);
+
+       if (rx_filter == HWTSTAMP_FILTER_NONE) {
+               enable = false;
+               vport->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
+       } else {
+               vport->tstamp_config.rx_filter = HWTSTAMP_FILTER_ALL;
+       }
+
+       for (u16 i = 0; i < vport->num_rxq_grp; i++) {
+               struct idpf_rxq_group *grp = &vport->rxq_grps[i];
+               struct idpf_rx_queue *rx_queue;
+               u16 j, num_rxq;
+
+               if (splitq)
+                       num_rxq = grp->splitq.num_rxq_sets;
+               else
+                       num_rxq = grp->singleq.num_rxq;
+
+               for (j = 0; j < num_rxq; j++) {
+                       if (splitq)
+                               rx_queue = &grp->splitq.rxq_sets[j]->rxq;
+                       else
+                               rx_queue = grp->singleq.rxqs[j];
+
+                       if (enable)
+                               idpf_queue_set(PTP, rx_queue);
+                       else
+                               idpf_queue_clear(PTP, rx_queue);
+               }
+       }
+}
+
 /**
  * idpf_ptp_set_timestamp_mode - Setup driver for requested timestamp mode
  * @vport: Virtual port structure
        }
 
        vport->tstamp_config.tx_type = config->tx_type;
+       idpf_ptp_set_rx_tstamp(vport, config->rx_filter);
        *config = vport->tstamp_config;
 
        return 0;
 
                return true;
 }
 
+/**
+ * idpf_ptp_is_vport_rx_tstamp_ena - Verify the Rx timestamping enablement for
+ *                                  a given vport.
+ * @vport: Virtual port structure
+ *
+ * Rx timestamp feature is enabled if the PTP clock for the adapter is created
+ * and it is possible to read the value of the device clock. The second
+ * assumption comes from the need to extend the Rx timestamp value to 64 bit
+ * based on the current device clock time.
+ *
+ * Return: true if the Rx timestamping is enabled, false otherwise.
+ */
+static inline bool idpf_ptp_is_vport_rx_tstamp_ena(struct idpf_vport *vport)
+{
+       if (!vport->adapter->ptp ||
+           vport->adapter->ptp->get_dev_clk_time_access == IDPF_PTP_NONE)
+               return false;
+       else
+               return true;
+}
+
 #if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
 int idpf_ptp_init(struct idpf_adapter *adapter);
 void idpf_ptp_release(struct idpf_adapter *adapter);
 
        return 0;
 }
 
+/**
+ * idpf_rx_hwtstamp - check for an RX timestamp and pass up the stack
+ * @rxq: pointer to the rx queue that receives the timestamp
+ * @rx_desc: pointer to rx descriptor containing timestamp
+ * @skb: skb to put timestamp in
+ */
+static void
+idpf_rx_hwtstamp(const struct idpf_rx_queue *rxq,
+                const struct virtchnl2_rx_flex_desc_adv_nic_3 *rx_desc,
+                struct sk_buff *skb)
+{
+       u64 cached_time, ts_ns;
+       u32 ts_high;
+
+       if (!(rx_desc->ts_low & VIRTCHNL2_RX_FLEX_TSTAMP_VALID))
+               return;
+
+       cached_time = READ_ONCE(rxq->cached_phc_time);
+
+       ts_high = le32_to_cpu(rx_desc->ts_high);
+       ts_ns = idpf_ptp_tstamp_extend_32b_to_64b(cached_time, ts_high);
+
+       *skb_hwtstamps(skb) = (struct skb_shared_hwtstamps) {
+               .hwtstamp = ns_to_ktime(ts_ns),
+       };
+}
+
 /**
  * idpf_rx_process_skb_fields - Populate skb header fields from Rx descriptor
  * @rxq: Rx descriptor ring packet is being transacted on
        /* process RSS/hash */
        idpf_rx_hash(rxq, skb, rx_desc, decoded);
 
+       if (idpf_queue_has(PTP, rxq))
+               idpf_rx_hwtstamp(rxq, rx_desc, skb);
+
        skb->protocol = eth_type_trans(skb, rxq->netdev);
        skb_record_rx_queue(skb, rxq->idx);
 
 
  * @__IDPF_Q_POLL_MODE: Enable poll mode
  * @__IDPF_Q_CRC_EN: enable CRC offload in singleq mode
  * @__IDPF_Q_HSPLIT_EN: enable header split on Rx (splitq)
+ * @__IDPF_Q_PTP: indicates whether the Rx timestamping is enabled for the
+ *               queue
  * @__IDPF_Q_FLAGS_NBITS: Must be last
  */
 enum idpf_queue_flags_t {
        __IDPF_Q_POLL_MODE,
        __IDPF_Q_CRC_EN,
        __IDPF_Q_HSPLIT_EN,
+       __IDPF_Q_PTP,
 
        __IDPF_Q_FLAGS_NBITS,
 };
  * @next_to_alloc: RX buffer to allocate at
  * @skb: Pointer to the skb
  * @truesize: data buffer truesize in singleq
+ * @cached_phc_time: Cached PHC time for the Rx queue
  * @stats_sync: See struct u64_stats_sync
  * @q_stats: See union idpf_rx_queue_stats
  * @q_id: Queue id
 
        struct sk_buff *skb;
        u32 truesize;
+       u64 cached_phc_time;
 
        struct u64_stats_sync stats_sync;
        struct idpf_rx_queue_stats q_stats;
        __cacheline_group_end_aligned(cold);
 };
 libeth_cacheline_set_assert(struct idpf_rx_queue, 64,
-                           80 + sizeof(struct u64_stats_sync),
+                           88 + sizeof(struct u64_stats_sync),
                            32);
 
 /**