mlxsw: pci: PTP: Hook into packet transmit path
authorPetr Machata <petrm@mellanox.com>
Sun, 30 Jun 2019 06:04:53 +0000 (09:04 +0300)
committerDavid S. Miller <davem@davemloft.net>
Tue, 2 Jul 2019 01:58:34 +0000 (18:58 -0700)
On Spectrum-1, timestamps are delivered separately from the packets, and
need to paired up. Therefore, at some point after mlxsw_sp_port_xmit()
is invoked, it is necessary to involve the chip-specific driver code to
allow it to do the necessary bookkeeping and matching.

On Spectrum-2, timestamps are delivered in CQE. For that reason,
position the point of driver involvement into mlxsw_pci_cqe_sdq_handle()
to make it hopefully easier to extend for Spectrum-2 in the future.

To tell the driver what port the packet was sent on, keep tx_info
in SKB control buffer.

Introduce a new driver core interface mlxsw_core_ptp_transmitted(), a
driver callback ptp_transmitted, and a PTP op transmitted. The callee is
responsible for taking care of releasing the SKB passed to the new
interfaces, and correspondingly have the new stub callbacks just call
dev_kfree_skb_any().

Follow-up patches will introduce the actual content into
mlxsw_sp1_ptp_transmitted() in particular.

Signed-off-by: Petr Machata <petrm@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/core.c
drivers/net/ethernet/mellanox/mlxsw/core.h
drivers/net/ethernet/mellanox/mlxsw/pci.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h

index 30e0526a9cf6145cf8b26368977591ecb0716c12..17ceac7505e55ecb3b08bfcb3e707c63b9522fa0 100644 (file)
@@ -1245,6 +1245,15 @@ int mlxsw_core_skb_transmit(struct mlxsw_core *mlxsw_core, struct sk_buff *skb,
 }
 EXPORT_SYMBOL(mlxsw_core_skb_transmit);
 
+void mlxsw_core_ptp_transmitted(struct mlxsw_core *mlxsw_core,
+                               struct sk_buff *skb, u8 local_port)
+{
+       if (mlxsw_core->driver->ptp_transmitted)
+               mlxsw_core->driver->ptp_transmitted(mlxsw_core, skb,
+                                                   local_port);
+}
+EXPORT_SYMBOL(mlxsw_core_ptp_transmitted);
+
 static bool __is_rx_listener_equal(const struct mlxsw_rx_listener *rxl_a,
                                   const struct mlxsw_rx_listener *rxl_b)
 {
index 06babcc58c7ae0558c7e18625503cc4d11ff952e..8efcff4b59cbce59dbed18de75aed5b666ae5943 100644 (file)
@@ -48,6 +48,8 @@ bool mlxsw_core_skb_transmit_busy(struct mlxsw_core *mlxsw_core,
                                  const struct mlxsw_tx_info *tx_info);
 int mlxsw_core_skb_transmit(struct mlxsw_core *mlxsw_core, struct sk_buff *skb,
                            const struct mlxsw_tx_info *tx_info);
+void mlxsw_core_ptp_transmitted(struct mlxsw_core *mlxsw_core,
+                               struct sk_buff *skb, u8 local_port);
 
 struct mlxsw_rx_listener {
        void (*func)(struct sk_buff *skb, u8 local_port, void *priv);
@@ -296,6 +298,13 @@ struct mlxsw_driver {
                             u64 *p_linear_size);
        int (*params_register)(struct mlxsw_core *mlxsw_core);
        void (*params_unregister)(struct mlxsw_core *mlxsw_core);
+
+       /* Notify a driver that a timestamped packet was transmitted. Driver
+        * is responsible for freeing the passed-in SKB.
+        */
+       void (*ptp_transmitted)(struct mlxsw_core *mlxsw_core,
+                               struct sk_buff *skb, u8 local_port);
+
        u8 txhdr_len;
        const struct mlxsw_config_profile *profile;
        bool res_query_enabled;
@@ -419,6 +428,7 @@ enum mlxsw_devlink_param_id {
 };
 
 struct mlxsw_skb_cb {
+       struct mlxsw_tx_info tx_info;
 };
 
 static inline struct mlxsw_skb_cb *mlxsw_skb_cb(struct sk_buff *skb)
index 6acb9bbfdf89fd49ba19dede7f8b1774e9c2290e..051b19388a812b0ceca68ac5efe7822f52e3a2e4 100644 (file)
@@ -508,17 +508,28 @@ static void mlxsw_pci_cqe_sdq_handle(struct mlxsw_pci *mlxsw_pci,
 {
        struct pci_dev *pdev = mlxsw_pci->pdev;
        struct mlxsw_pci_queue_elem_info *elem_info;
+       struct mlxsw_tx_info tx_info;
        char *wqe;
        struct sk_buff *skb;
        int i;
 
        spin_lock(&q->lock);
        elem_info = mlxsw_pci_queue_elem_info_consumer_get(q);
+       tx_info = mlxsw_skb_cb(elem_info->u.sdq.skb)->tx_info;
        skb = elem_info->u.sdq.skb;
        wqe = elem_info->elem;
        for (i = 0; i < MLXSW_PCI_WQE_SG_ENTRIES; i++)
                mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, i, DMA_TO_DEVICE);
-       dev_kfree_skb_any(skb);
+
+       if (unlikely(!tx_info.is_emad &&
+                    skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
+               mlxsw_core_ptp_transmitted(mlxsw_pci->core, skb,
+                                          tx_info.local_port);
+               skb = NULL;
+       }
+
+       if (skb)
+               dev_kfree_skb_any(skb);
        elem_info->u.sdq.skb = NULL;
 
        if (q->consumer_counter++ != consumer_counter_limit)
@@ -1548,6 +1559,7 @@ static int mlxsw_pci_skb_transmit(void *bus_priv, struct sk_buff *skb,
                err = -EAGAIN;
                goto unlock;
        }
+       mlxsw_skb_cb(skb)->tx_info = *tx_info;
        elem_info->u.sdq.skb = skb;
 
        wqe = elem_info->elem;
@@ -1571,6 +1583,9 @@ static int mlxsw_pci_skb_transmit(void *bus_priv, struct sk_buff *skb,
                        goto unmap_frags;
        }
 
+       if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
+               skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+
        /* Set unused sq entries byte count to zero. */
        for (i++; i < MLXSW_PCI_WQE_SG_ENTRIES; i++)
                mlxsw_pci_wqe_byte_count_set(wqe, i, 0);
index a0376d4f94a89ae7ac284d5be2676ea62a32039c..6a907e4918682e7b9ebf154bde4eb7e9eb3d5edc 100644 (file)
@@ -157,6 +157,12 @@ struct mlxsw_sp_ptp_ops {
         */
        void (*receive)(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
                        u8 local_port);
+
+       /* Notify a driver that a timestamped packet was transmitted. Driver
+        * is responsible for freeing the passed-in SKB.
+        */
+       void (*transmitted)(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
+                           u8 local_port);
 };
 
 static int mlxsw_sp_component_query(struct mlxfw_dev *mlxfw_dev,
@@ -4424,12 +4430,14 @@ static const struct mlxsw_sp_ptp_ops mlxsw_sp1_ptp_ops = {
        .clock_init     = mlxsw_sp1_ptp_clock_init,
        .clock_fini     = mlxsw_sp1_ptp_clock_fini,
        .receive        = mlxsw_sp1_ptp_receive,
+       .transmitted    = mlxsw_sp1_ptp_transmitted,
 };
 
 static const struct mlxsw_sp_ptp_ops mlxsw_sp2_ptp_ops = {
        .clock_init     = mlxsw_sp2_ptp_clock_init,
        .clock_fini     = mlxsw_sp2_ptp_clock_fini,
        .receive        = mlxsw_sp2_ptp_receive,
+       .transmitted    = mlxsw_sp2_ptp_transmitted,
 };
 
 static int mlxsw_sp_netdevice_event(struct notifier_block *unused,
@@ -4995,6 +5003,15 @@ static void mlxsw_sp2_params_unregister(struct mlxsw_core *mlxsw_core)
        mlxsw_sp_params_unregister(mlxsw_core);
 }
 
+static void mlxsw_sp_ptp_transmitted(struct mlxsw_core *mlxsw_core,
+                                    struct sk_buff *skb, u8 local_port)
+{
+       struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
+
+       skb_pull(skb, MLXSW_TXHDR_LEN);
+       mlxsw_sp->ptp_ops->transmitted(mlxsw_sp, skb, local_port);
+}
+
 static struct mlxsw_driver mlxsw_sp1_driver = {
        .kind                           = mlxsw_sp1_driver_name,
        .priv_size                      = sizeof(struct mlxsw_sp),
@@ -5019,6 +5036,7 @@ static struct mlxsw_driver mlxsw_sp1_driver = {
        .kvd_sizes_get                  = mlxsw_sp_kvd_sizes_get,
        .params_register                = mlxsw_sp_params_register,
        .params_unregister              = mlxsw_sp_params_unregister,
+       .ptp_transmitted                = mlxsw_sp_ptp_transmitted,
        .txhdr_len                      = MLXSW_TXHDR_LEN,
        .profile                        = &mlxsw_sp1_config_profile,
        .res_query_enabled              = true,
@@ -5047,6 +5065,7 @@ static struct mlxsw_driver mlxsw_sp2_driver = {
        .resources_register             = mlxsw_sp2_resources_register,
        .params_register                = mlxsw_sp2_params_register,
        .params_unregister              = mlxsw_sp2_params_unregister,
+       .ptp_transmitted                = mlxsw_sp_ptp_transmitted,
        .txhdr_len                      = MLXSW_TXHDR_LEN,
        .profile                        = &mlxsw_sp2_config_profile,
        .res_query_enabled              = true,
index 8eca1ac03e7a06713ee7614960f810269259b0e1..3af4573a4261dc5a8ba690ab77c1828212490574 100644 (file)
@@ -270,3 +270,9 @@ void mlxsw_sp1_ptp_receive(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
 {
        mlxsw_sp_rx_listener_no_mark_func(skb, local_port, mlxsw_sp);
 }
+
+void mlxsw_sp1_ptp_transmitted(struct mlxsw_sp *mlxsw_sp,
+                              struct sk_buff *skb, u8 local_port)
+{
+       dev_kfree_skb_any(skb);
+}
index 06bb303b54076106bdfae35dd79b692ac62ad897..84955aa79c01fb8587cb5e490fd215f1c2c03971 100644 (file)
@@ -20,6 +20,9 @@ void mlxsw_sp1_ptp_clock_fini(struct mlxsw_sp_ptp_clock *clock);
 void mlxsw_sp1_ptp_receive(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
                           u8 local_port);
 
+void mlxsw_sp1_ptp_transmitted(struct mlxsw_sp *mlxsw_sp,
+                              struct sk_buff *skb, u8 local_port);
+
 #else
 
 static inline struct mlxsw_sp_ptp_clock *
@@ -38,6 +41,12 @@ static inline void mlxsw_sp1_ptp_receive(struct mlxsw_sp *mlxsw_sp,
        mlxsw_sp_rx_listener_no_mark_func(skb, local_port, mlxsw_sp);
 }
 
+static inline void mlxsw_sp1_ptp_transmitted(struct mlxsw_sp *mlxsw_sp,
+                                            struct sk_buff *skb, u8 local_port)
+{
+       dev_kfree_skb_any(skb);
+}
+
 #endif
 
 static inline struct mlxsw_sp_ptp_clock *
@@ -56,4 +65,10 @@ static inline void mlxsw_sp2_ptp_receive(struct mlxsw_sp *mlxsw_sp,
        mlxsw_sp_rx_listener_no_mark_func(skb, local_port, mlxsw_sp);
 }
 
+static inline void mlxsw_sp2_ptp_transmitted(struct mlxsw_sp *mlxsw_sp,
+                                            struct sk_buff *skb, u8 local_port)
+{
+       dev_kfree_skb_any(skb);
+}
+
 #endif