Commit 0714256c authored by Petr Machata's avatar Petr Machata Committed by David S. Miller

mlxsw: pci: PTP: Hook into packet transmit path

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: default avatarPetr Machata <petrm@mellanox.com>
Acked-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarIdo Schimmel <idosch@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d7cd206d
...@@ -1245,6 +1245,15 @@ int mlxsw_core_skb_transmit(struct mlxsw_core *mlxsw_core, struct sk_buff *skb, ...@@ -1245,6 +1245,15 @@ int mlxsw_core_skb_transmit(struct mlxsw_core *mlxsw_core, struct sk_buff *skb,
} }
EXPORT_SYMBOL(mlxsw_core_skb_transmit); 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, static bool __is_rx_listener_equal(const struct mlxsw_rx_listener *rxl_a,
const struct mlxsw_rx_listener *rxl_b) const struct mlxsw_rx_listener *rxl_b)
{ {
......
...@@ -48,6 +48,8 @@ bool mlxsw_core_skb_transmit_busy(struct mlxsw_core *mlxsw_core, ...@@ -48,6 +48,8 @@ bool mlxsw_core_skb_transmit_busy(struct mlxsw_core *mlxsw_core,
const struct mlxsw_tx_info *tx_info); const struct mlxsw_tx_info *tx_info);
int mlxsw_core_skb_transmit(struct mlxsw_core *mlxsw_core, struct sk_buff *skb, int mlxsw_core_skb_transmit(struct mlxsw_core *mlxsw_core, struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info); 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 { struct mlxsw_rx_listener {
void (*func)(struct sk_buff *skb, u8 local_port, void *priv); void (*func)(struct sk_buff *skb, u8 local_port, void *priv);
...@@ -296,6 +298,13 @@ struct mlxsw_driver { ...@@ -296,6 +298,13 @@ struct mlxsw_driver {
u64 *p_linear_size); u64 *p_linear_size);
int (*params_register)(struct mlxsw_core *mlxsw_core); int (*params_register)(struct mlxsw_core *mlxsw_core);
void (*params_unregister)(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; u8 txhdr_len;
const struct mlxsw_config_profile *profile; const struct mlxsw_config_profile *profile;
bool res_query_enabled; bool res_query_enabled;
...@@ -419,6 +428,7 @@ enum mlxsw_devlink_param_id { ...@@ -419,6 +428,7 @@ enum mlxsw_devlink_param_id {
}; };
struct mlxsw_skb_cb { struct mlxsw_skb_cb {
struct mlxsw_tx_info tx_info;
}; };
static inline struct mlxsw_skb_cb *mlxsw_skb_cb(struct sk_buff *skb) static inline struct mlxsw_skb_cb *mlxsw_skb_cb(struct sk_buff *skb)
......
...@@ -508,17 +508,28 @@ static void mlxsw_pci_cqe_sdq_handle(struct mlxsw_pci *mlxsw_pci, ...@@ -508,17 +508,28 @@ static void mlxsw_pci_cqe_sdq_handle(struct mlxsw_pci *mlxsw_pci,
{ {
struct pci_dev *pdev = mlxsw_pci->pdev; struct pci_dev *pdev = mlxsw_pci->pdev;
struct mlxsw_pci_queue_elem_info *elem_info; struct mlxsw_pci_queue_elem_info *elem_info;
struct mlxsw_tx_info tx_info;
char *wqe; char *wqe;
struct sk_buff *skb; struct sk_buff *skb;
int i; int i;
spin_lock(&q->lock); spin_lock(&q->lock);
elem_info = mlxsw_pci_queue_elem_info_consumer_get(q); 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; skb = elem_info->u.sdq.skb;
wqe = elem_info->elem; wqe = elem_info->elem;
for (i = 0; i < MLXSW_PCI_WQE_SG_ENTRIES; i++) for (i = 0; i < MLXSW_PCI_WQE_SG_ENTRIES; i++)
mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, i, DMA_TO_DEVICE); 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; elem_info->u.sdq.skb = NULL;
if (q->consumer_counter++ != consumer_counter_limit) if (q->consumer_counter++ != consumer_counter_limit)
...@@ -1548,6 +1559,7 @@ static int mlxsw_pci_skb_transmit(void *bus_priv, struct sk_buff *skb, ...@@ -1548,6 +1559,7 @@ static int mlxsw_pci_skb_transmit(void *bus_priv, struct sk_buff *skb,
err = -EAGAIN; err = -EAGAIN;
goto unlock; goto unlock;
} }
mlxsw_skb_cb(skb)->tx_info = *tx_info;
elem_info->u.sdq.skb = skb; elem_info->u.sdq.skb = skb;
wqe = elem_info->elem; wqe = elem_info->elem;
...@@ -1571,6 +1583,9 @@ static int mlxsw_pci_skb_transmit(void *bus_priv, struct sk_buff *skb, ...@@ -1571,6 +1583,9 @@ static int mlxsw_pci_skb_transmit(void *bus_priv, struct sk_buff *skb,
goto unmap_frags; 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. */ /* Set unused sq entries byte count to zero. */
for (i++; i < MLXSW_PCI_WQE_SG_ENTRIES; i++) for (i++; i < MLXSW_PCI_WQE_SG_ENTRIES; i++)
mlxsw_pci_wqe_byte_count_set(wqe, i, 0); mlxsw_pci_wqe_byte_count_set(wqe, i, 0);
......
...@@ -157,6 +157,12 @@ struct mlxsw_sp_ptp_ops { ...@@ -157,6 +157,12 @@ struct mlxsw_sp_ptp_ops {
*/ */
void (*receive)(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb, void (*receive)(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
u8 local_port); 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, 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 = { ...@@ -4424,12 +4430,14 @@ static const struct mlxsw_sp_ptp_ops mlxsw_sp1_ptp_ops = {
.clock_init = mlxsw_sp1_ptp_clock_init, .clock_init = mlxsw_sp1_ptp_clock_init,
.clock_fini = mlxsw_sp1_ptp_clock_fini, .clock_fini = mlxsw_sp1_ptp_clock_fini,
.receive = mlxsw_sp1_ptp_receive, .receive = mlxsw_sp1_ptp_receive,
.transmitted = mlxsw_sp1_ptp_transmitted,
}; };
static const struct mlxsw_sp_ptp_ops mlxsw_sp2_ptp_ops = { static const struct mlxsw_sp_ptp_ops mlxsw_sp2_ptp_ops = {
.clock_init = mlxsw_sp2_ptp_clock_init, .clock_init = mlxsw_sp2_ptp_clock_init,
.clock_fini = mlxsw_sp2_ptp_clock_fini, .clock_fini = mlxsw_sp2_ptp_clock_fini,
.receive = mlxsw_sp2_ptp_receive, .receive = mlxsw_sp2_ptp_receive,
.transmitted = mlxsw_sp2_ptp_transmitted,
}; };
static int mlxsw_sp_netdevice_event(struct notifier_block *unused, 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) ...@@ -4995,6 +5003,15 @@ static void mlxsw_sp2_params_unregister(struct mlxsw_core *mlxsw_core)
mlxsw_sp_params_unregister(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 = { static struct mlxsw_driver mlxsw_sp1_driver = {
.kind = mlxsw_sp1_driver_name, .kind = mlxsw_sp1_driver_name,
.priv_size = sizeof(struct mlxsw_sp), .priv_size = sizeof(struct mlxsw_sp),
...@@ -5019,6 +5036,7 @@ static struct mlxsw_driver mlxsw_sp1_driver = { ...@@ -5019,6 +5036,7 @@ static struct mlxsw_driver mlxsw_sp1_driver = {
.kvd_sizes_get = mlxsw_sp_kvd_sizes_get, .kvd_sizes_get = mlxsw_sp_kvd_sizes_get,
.params_register = mlxsw_sp_params_register, .params_register = mlxsw_sp_params_register,
.params_unregister = mlxsw_sp_params_unregister, .params_unregister = mlxsw_sp_params_unregister,
.ptp_transmitted = mlxsw_sp_ptp_transmitted,
.txhdr_len = MLXSW_TXHDR_LEN, .txhdr_len = MLXSW_TXHDR_LEN,
.profile = &mlxsw_sp1_config_profile, .profile = &mlxsw_sp1_config_profile,
.res_query_enabled = true, .res_query_enabled = true,
...@@ -5047,6 +5065,7 @@ static struct mlxsw_driver mlxsw_sp2_driver = { ...@@ -5047,6 +5065,7 @@ static struct mlxsw_driver mlxsw_sp2_driver = {
.resources_register = mlxsw_sp2_resources_register, .resources_register = mlxsw_sp2_resources_register,
.params_register = mlxsw_sp2_params_register, .params_register = mlxsw_sp2_params_register,
.params_unregister = mlxsw_sp2_params_unregister, .params_unregister = mlxsw_sp2_params_unregister,
.ptp_transmitted = mlxsw_sp_ptp_transmitted,
.txhdr_len = MLXSW_TXHDR_LEN, .txhdr_len = MLXSW_TXHDR_LEN,
.profile = &mlxsw_sp2_config_profile, .profile = &mlxsw_sp2_config_profile,
.res_query_enabled = true, .res_query_enabled = true,
......
...@@ -270,3 +270,9 @@ void mlxsw_sp1_ptp_receive(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb, ...@@ -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); 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);
}
...@@ -20,6 +20,9 @@ void mlxsw_sp1_ptp_clock_fini(struct mlxsw_sp_ptp_clock *clock); ...@@ -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, void mlxsw_sp1_ptp_receive(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
u8 local_port); u8 local_port);
void mlxsw_sp1_ptp_transmitted(struct mlxsw_sp *mlxsw_sp,
struct sk_buff *skb, u8 local_port);
#else #else
static inline struct mlxsw_sp_ptp_clock * static inline struct mlxsw_sp_ptp_clock *
...@@ -38,6 +41,12 @@ static inline void mlxsw_sp1_ptp_receive(struct mlxsw_sp *mlxsw_sp, ...@@ -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); 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 #endif
static inline struct mlxsw_sp_ptp_clock * static inline struct mlxsw_sp_ptp_clock *
...@@ -56,4 +65,10 @@ static inline void mlxsw_sp2_ptp_receive(struct mlxsw_sp *mlxsw_sp, ...@@ -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); 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 #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment