cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

txrx.h (12344B)


      1/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
      2/* Copyright (c) 2019 Mellanox Technologies. */
      3
      4#ifndef __MLX5_EN_TXRX_H___
      5#define __MLX5_EN_TXRX_H___
      6
      7#include "en.h"
      8#include <linux/indirect_call_wrapper.h>
      9
     10#define MLX5E_TX_WQE_EMPTY_DS_COUNT (sizeof(struct mlx5e_tx_wqe) / MLX5_SEND_WQE_DS)
     11
     12#define INL_HDR_START_SZ (sizeof(((struct mlx5_wqe_eth_seg *)NULL)->inline_hdr.start))
     13
     14#define MLX5E_RX_ERR_CQE(cqe) (get_cqe_opcode(cqe) != MLX5_CQE_RESP_SEND)
     15
     16static inline
     17ktime_t mlx5e_cqe_ts_to_ns(cqe_ts_to_ns func, struct mlx5_clock *clock, u64 cqe_ts)
     18{
     19	return INDIRECT_CALL_2(func, mlx5_real_time_cyc2time, mlx5_timecounter_cyc2time,
     20			       clock, cqe_ts);
     21}
     22
     23enum mlx5e_icosq_wqe_type {
     24	MLX5E_ICOSQ_WQE_NOP,
     25	MLX5E_ICOSQ_WQE_UMR_RX,
     26	MLX5E_ICOSQ_WQE_SHAMPO_HD_UMR,
     27#ifdef CONFIG_MLX5_EN_TLS
     28	MLX5E_ICOSQ_WQE_UMR_TLS,
     29	MLX5E_ICOSQ_WQE_SET_PSV_TLS,
     30	MLX5E_ICOSQ_WQE_GET_PSV_TLS,
     31#endif
     32};
     33
     34/* General */
     35static inline bool mlx5e_skb_is_multicast(struct sk_buff *skb)
     36{
     37	return skb->pkt_type == PACKET_MULTICAST || skb->pkt_type == PACKET_BROADCAST;
     38}
     39
     40void mlx5e_trigger_irq(struct mlx5e_icosq *sq);
     41void mlx5e_completion_event(struct mlx5_core_cq *mcq, struct mlx5_eqe *eqe);
     42void mlx5e_cq_error_event(struct mlx5_core_cq *mcq, enum mlx5_event event);
     43int mlx5e_napi_poll(struct napi_struct *napi, int budget);
     44int mlx5e_poll_ico_cq(struct mlx5e_cq *cq);
     45
     46/* RX */
     47void mlx5e_page_dma_unmap(struct mlx5e_rq *rq, struct page *page);
     48void mlx5e_page_release_dynamic(struct mlx5e_rq *rq, struct page *page, bool recycle);
     49INDIRECT_CALLABLE_DECLARE(bool mlx5e_post_rx_wqes(struct mlx5e_rq *rq));
     50INDIRECT_CALLABLE_DECLARE(bool mlx5e_post_rx_mpwqes(struct mlx5e_rq *rq));
     51int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget);
     52void mlx5e_free_rx_descs(struct mlx5e_rq *rq);
     53void mlx5e_free_rx_in_progress_descs(struct mlx5e_rq *rq);
     54
     55/* TX */
     56netdev_tx_t mlx5e_xmit(struct sk_buff *skb, struct net_device *dev);
     57bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget);
     58void mlx5e_free_txqsq_descs(struct mlx5e_txqsq *sq);
     59
     60static inline bool
     61mlx5e_wqc_has_room_for(struct mlx5_wq_cyc *wq, u16 cc, u16 pc, u16 n)
     62{
     63	return (mlx5_wq_cyc_ctr2ix(wq, cc - pc) >= n) || (cc == pc);
     64}
     65
     66static inline void *mlx5e_fetch_wqe(struct mlx5_wq_cyc *wq, u16 pi, size_t wqe_size)
     67{
     68	void *wqe;
     69
     70	wqe = mlx5_wq_cyc_get_wqe(wq, pi);
     71	memset(wqe, 0, wqe_size);
     72
     73	return wqe;
     74}
     75
     76#define MLX5E_TX_FETCH_WQE(sq, pi) \
     77	((struct mlx5e_tx_wqe *)mlx5e_fetch_wqe(&(sq)->wq, pi, sizeof(struct mlx5e_tx_wqe)))
     78
     79static inline struct mlx5e_tx_wqe *
     80mlx5e_post_nop(struct mlx5_wq_cyc *wq, u32 sqn, u16 *pc)
     81{
     82	u16                         pi   = mlx5_wq_cyc_ctr2ix(wq, *pc);
     83	struct mlx5e_tx_wqe        *wqe  = mlx5_wq_cyc_get_wqe(wq, pi);
     84	struct mlx5_wqe_ctrl_seg   *cseg = &wqe->ctrl;
     85
     86	memset(cseg, 0, sizeof(*cseg));
     87
     88	cseg->opmod_idx_opcode = cpu_to_be32((*pc << 8) | MLX5_OPCODE_NOP);
     89	cseg->qpn_ds           = cpu_to_be32((sqn << 8) | 0x01);
     90
     91	(*pc)++;
     92
     93	return wqe;
     94}
     95
     96static inline struct mlx5e_tx_wqe *
     97mlx5e_post_nop_fence(struct mlx5_wq_cyc *wq, u32 sqn, u16 *pc)
     98{
     99	u16                         pi   = mlx5_wq_cyc_ctr2ix(wq, *pc);
    100	struct mlx5e_tx_wqe        *wqe  = mlx5_wq_cyc_get_wqe(wq, pi);
    101	struct mlx5_wqe_ctrl_seg   *cseg = &wqe->ctrl;
    102
    103	memset(cseg, 0, sizeof(*cseg));
    104
    105	cseg->opmod_idx_opcode = cpu_to_be32((*pc << 8) | MLX5_OPCODE_NOP);
    106	cseg->qpn_ds           = cpu_to_be32((sqn << 8) | 0x01);
    107	cseg->fm_ce_se         = MLX5_FENCE_MODE_INITIATOR_SMALL;
    108
    109	(*pc)++;
    110
    111	return wqe;
    112}
    113
    114struct mlx5e_tx_wqe_info {
    115	struct sk_buff *skb;
    116	u32 num_bytes;
    117	u8 num_wqebbs;
    118	u8 num_dma;
    119	u8 num_fifo_pkts;
    120#ifdef CONFIG_MLX5_EN_TLS
    121	struct page *resync_dump_frag_page;
    122#endif
    123};
    124
    125static inline u16 mlx5e_txqsq_get_next_pi(struct mlx5e_txqsq *sq, u16 size)
    126{
    127	struct mlx5_wq_cyc *wq = &sq->wq;
    128	u16 pi, contig_wqebbs;
    129
    130	pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
    131	contig_wqebbs = mlx5_wq_cyc_get_contig_wqebbs(wq, pi);
    132	if (unlikely(contig_wqebbs < size)) {
    133		struct mlx5e_tx_wqe_info *wi, *edge_wi;
    134
    135		wi = &sq->db.wqe_info[pi];
    136		edge_wi = wi + contig_wqebbs;
    137
    138		/* Fill SQ frag edge with NOPs to avoid WQE wrapping two pages. */
    139		for (; wi < edge_wi; wi++) {
    140			*wi = (struct mlx5e_tx_wqe_info) {
    141				.num_wqebbs = 1,
    142			};
    143			mlx5e_post_nop(wq, sq->sqn, &sq->pc);
    144		}
    145		sq->stats->nop += contig_wqebbs;
    146
    147		pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
    148	}
    149
    150	return pi;
    151}
    152
    153static inline u16 mlx5e_shampo_get_cqe_header_index(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
    154{
    155	return be16_to_cpu(cqe->shampo.header_entry_index) & (rq->mpwqe.shampo->hd_per_wq - 1);
    156}
    157
    158struct mlx5e_shampo_umr {
    159	u16 len;
    160};
    161
    162struct mlx5e_icosq_wqe_info {
    163	u8 wqe_type;
    164	u8 num_wqebbs;
    165
    166	/* Auxiliary data for different wqe types. */
    167	union {
    168		struct {
    169			struct mlx5e_rq *rq;
    170		} umr;
    171		struct mlx5e_shampo_umr shampo;
    172#ifdef CONFIG_MLX5_EN_TLS
    173		struct {
    174			struct mlx5e_ktls_offload_context_rx *priv_rx;
    175		} tls_set_params;
    176		struct {
    177			struct mlx5e_ktls_rx_resync_buf *buf;
    178		} tls_get_params;
    179#endif
    180	};
    181};
    182
    183void mlx5e_free_icosq_descs(struct mlx5e_icosq *sq);
    184
    185static inline u16 mlx5e_icosq_get_next_pi(struct mlx5e_icosq *sq, u16 size)
    186{
    187	struct mlx5_wq_cyc *wq = &sq->wq;
    188	u16 pi, contig_wqebbs;
    189
    190	pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
    191	contig_wqebbs = mlx5_wq_cyc_get_contig_wqebbs(wq, pi);
    192	if (unlikely(contig_wqebbs < size)) {
    193		struct mlx5e_icosq_wqe_info *wi, *edge_wi;
    194
    195		wi = &sq->db.wqe_info[pi];
    196		edge_wi = wi + contig_wqebbs;
    197
    198		/* Fill SQ frag edge with NOPs to avoid WQE wrapping two pages. */
    199		for (; wi < edge_wi; wi++) {
    200			*wi = (struct mlx5e_icosq_wqe_info) {
    201				.wqe_type   = MLX5E_ICOSQ_WQE_NOP,
    202				.num_wqebbs = 1,
    203			};
    204			mlx5e_post_nop(wq, sq->sqn, &sq->pc);
    205		}
    206
    207		pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
    208	}
    209
    210	return pi;
    211}
    212
    213static inline void
    214mlx5e_notify_hw(struct mlx5_wq_cyc *wq, u16 pc, void __iomem *uar_map,
    215		struct mlx5_wqe_ctrl_seg *ctrl)
    216{
    217	ctrl->fm_ce_se |= MLX5_WQE_CTRL_CQ_UPDATE;
    218	/* ensure wqe is visible to device before updating doorbell record */
    219	dma_wmb();
    220
    221	*wq->db = cpu_to_be32(pc);
    222
    223	/* ensure doorbell record is visible to device before ringing the
    224	 * doorbell
    225	 */
    226	wmb();
    227
    228	mlx5_write64((__be32 *)ctrl, uar_map);
    229}
    230
    231static inline void mlx5e_cq_arm(struct mlx5e_cq *cq)
    232{
    233	struct mlx5_core_cq *mcq;
    234
    235	mcq = &cq->mcq;
    236	mlx5_cq_arm(mcq, MLX5_CQ_DB_REQ_NOT, mcq->uar->map, cq->wq.cc);
    237}
    238
    239static inline struct mlx5e_sq_dma *
    240mlx5e_dma_get(struct mlx5e_txqsq *sq, u32 i)
    241{
    242	return &sq->db.dma_fifo[i & sq->dma_fifo_mask];
    243}
    244
    245static inline void
    246mlx5e_dma_push(struct mlx5e_txqsq *sq, dma_addr_t addr, u32 size,
    247	       enum mlx5e_dma_map_type map_type)
    248{
    249	struct mlx5e_sq_dma *dma = mlx5e_dma_get(sq, sq->dma_fifo_pc++);
    250
    251	dma->addr = addr;
    252	dma->size = size;
    253	dma->type = map_type;
    254}
    255
    256static inline
    257struct sk_buff **mlx5e_skb_fifo_get(struct mlx5e_skb_fifo *fifo, u16 i)
    258{
    259	return &fifo->fifo[i & fifo->mask];
    260}
    261
    262static inline
    263void mlx5e_skb_fifo_push(struct mlx5e_skb_fifo *fifo, struct sk_buff *skb)
    264{
    265	struct sk_buff **skb_item = mlx5e_skb_fifo_get(fifo, (*fifo->pc)++);
    266
    267	*skb_item = skb;
    268}
    269
    270static inline
    271struct sk_buff *mlx5e_skb_fifo_pop(struct mlx5e_skb_fifo *fifo)
    272{
    273	return *mlx5e_skb_fifo_get(fifo, (*fifo->cc)++);
    274}
    275
    276static inline void
    277mlx5e_tx_dma_unmap(struct device *pdev, struct mlx5e_sq_dma *dma)
    278{
    279	switch (dma->type) {
    280	case MLX5E_DMA_MAP_SINGLE:
    281		dma_unmap_single(pdev, dma->addr, dma->size, DMA_TO_DEVICE);
    282		break;
    283	case MLX5E_DMA_MAP_PAGE:
    284		dma_unmap_page(pdev, dma->addr, dma->size, DMA_TO_DEVICE);
    285		break;
    286	default:
    287		WARN_ONCE(true, "mlx5e_tx_dma_unmap unknown DMA type!\n");
    288	}
    289}
    290
    291void mlx5e_sq_xmit_simple(struct mlx5e_txqsq *sq, struct sk_buff *skb, bool xmit_more);
    292void mlx5e_tx_mpwqe_ensure_complete(struct mlx5e_txqsq *sq);
    293
    294static inline bool mlx5e_tx_mpwqe_is_full(struct mlx5e_tx_mpwqe *session, u8 max_sq_mpw_wqebbs)
    295{
    296	return session->ds_count == max_sq_mpw_wqebbs * MLX5_SEND_WQEBB_NUM_DS;
    297}
    298
    299static inline void mlx5e_rqwq_reset(struct mlx5e_rq *rq)
    300{
    301	if (rq->wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) {
    302		mlx5_wq_ll_reset(&rq->mpwqe.wq);
    303		rq->mpwqe.actual_wq_head = 0;
    304	} else {
    305		mlx5_wq_cyc_reset(&rq->wqe.wq);
    306	}
    307}
    308
    309static inline void mlx5e_dump_error_cqe(struct mlx5e_cq *cq, u32 qn,
    310					struct mlx5_err_cqe *err_cqe)
    311{
    312	struct mlx5_cqwq *wq = &cq->wq;
    313	u32 ci;
    314
    315	ci = mlx5_cqwq_ctr2ix(wq, wq->cc - 1);
    316
    317	netdev_err(cq->netdev,
    318		   "Error cqe on cqn 0x%x, ci 0x%x, qn 0x%x, opcode 0x%x, syndrome 0x%x, vendor syndrome 0x%x\n",
    319		   cq->mcq.cqn, ci, qn,
    320		   get_cqe_opcode((struct mlx5_cqe64 *)err_cqe),
    321		   err_cqe->syndrome, err_cqe->vendor_err_synd);
    322	mlx5_dump_err_cqe(cq->mdev, err_cqe);
    323}
    324
    325static inline u32 mlx5e_rqwq_get_size(struct mlx5e_rq *rq)
    326{
    327	switch (rq->wq_type) {
    328	case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
    329		return mlx5_wq_ll_get_size(&rq->mpwqe.wq);
    330	default:
    331		return mlx5_wq_cyc_get_size(&rq->wqe.wq);
    332	}
    333}
    334
    335static inline u32 mlx5e_rqwq_get_cur_sz(struct mlx5e_rq *rq)
    336{
    337	switch (rq->wq_type) {
    338	case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
    339		return rq->mpwqe.wq.cur_sz;
    340	default:
    341		return rq->wqe.wq.cur_sz;
    342	}
    343}
    344
    345static inline u16 mlx5e_rqwq_get_head(struct mlx5e_rq *rq)
    346{
    347	switch (rq->wq_type) {
    348	case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
    349		return mlx5_wq_ll_get_head(&rq->mpwqe.wq);
    350	default:
    351		return mlx5_wq_cyc_get_head(&rq->wqe.wq);
    352	}
    353}
    354
    355static inline u16 mlx5e_rqwq_get_wqe_counter(struct mlx5e_rq *rq)
    356{
    357	switch (rq->wq_type) {
    358	case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
    359		return mlx5_wq_ll_get_counter(&rq->mpwqe.wq);
    360	default:
    361		return mlx5_wq_cyc_get_counter(&rq->wqe.wq);
    362	}
    363}
    364
    365/* SW parser related functions */
    366
    367struct mlx5e_swp_spec {
    368	__be16 l3_proto;
    369	u8 l4_proto;
    370	u8 is_tun;
    371	__be16 tun_l3_proto;
    372	u8 tun_l4_proto;
    373};
    374
    375static inline void mlx5e_eseg_swp_offsets_add_vlan(struct mlx5_wqe_eth_seg *eseg)
    376{
    377	/* SWP offsets are in 2-bytes words */
    378	eseg->swp_outer_l3_offset += VLAN_HLEN / 2;
    379	eseg->swp_outer_l4_offset += VLAN_HLEN / 2;
    380	eseg->swp_inner_l3_offset += VLAN_HLEN / 2;
    381	eseg->swp_inner_l4_offset += VLAN_HLEN / 2;
    382}
    383
    384static inline void
    385mlx5e_set_eseg_swp(struct sk_buff *skb, struct mlx5_wqe_eth_seg *eseg,
    386		   struct mlx5e_swp_spec *swp_spec)
    387{
    388	/* SWP offsets are in 2-bytes words */
    389	eseg->swp_outer_l3_offset = skb_network_offset(skb) / 2;
    390	if (swp_spec->l3_proto == htons(ETH_P_IPV6))
    391		eseg->swp_flags |= MLX5_ETH_WQE_SWP_OUTER_L3_IPV6;
    392	if (swp_spec->l4_proto) {
    393		eseg->swp_outer_l4_offset = skb_transport_offset(skb) / 2;
    394		if (swp_spec->l4_proto == IPPROTO_UDP)
    395			eseg->swp_flags |= MLX5_ETH_WQE_SWP_OUTER_L4_UDP;
    396	}
    397
    398	if (swp_spec->is_tun) {
    399		eseg->swp_inner_l3_offset = skb_inner_network_offset(skb) / 2;
    400		if (swp_spec->tun_l3_proto == htons(ETH_P_IPV6))
    401			eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6;
    402	} else { /* typically for ipsec when xfrm mode != XFRM_MODE_TUNNEL */
    403		eseg->swp_inner_l3_offset = skb_network_offset(skb) / 2;
    404		if (swp_spec->l3_proto == htons(ETH_P_IPV6))
    405			eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6;
    406	}
    407	switch (swp_spec->tun_l4_proto) {
    408	case IPPROTO_UDP:
    409		eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L4_UDP;
    410		fallthrough;
    411	case IPPROTO_TCP:
    412		eseg->swp_inner_l4_offset = skb_inner_transport_offset(skb) / 2;
    413		break;
    414	}
    415}
    416
    417#define MLX5E_STOP_ROOM(wqebbs) ((wqebbs) * 2 - 1)
    418
    419static inline u16 mlx5e_stop_room_for_wqe(struct mlx5_core_dev *mdev, u16 wqe_size)
    420{
    421	/* A WQE must not cross the page boundary, hence two conditions:
    422	 * 1. Its size must not exceed the page size.
    423	 * 2. If the WQE size is X, and the space remaining in a page is less
    424	 *    than X, this space needs to be padded with NOPs. So, one WQE of
    425	 *    size X may require up to X-1 WQEBBs of padding, which makes the
    426	 *    stop room of X-1 + X.
    427	 * WQE size is also limited by the hardware limit.
    428	 */
    429	WARN_ONCE(wqe_size > mlx5e_get_max_sq_wqebbs(mdev),
    430		  "wqe_size %u is greater than max SQ WQEBBs %u",
    431		  wqe_size, mlx5e_get_max_sq_wqebbs(mdev));
    432
    433
    434	return MLX5E_STOP_ROOM(wqe_size);
    435}
    436
    437static inline u16 mlx5e_stop_room_for_max_wqe(struct mlx5_core_dev *mdev)
    438{
    439	return MLX5E_STOP_ROOM(mlx5e_get_max_sq_wqebbs(mdev));
    440}
    441
    442static inline bool mlx5e_icosq_can_post_wqe(struct mlx5e_icosq *sq, u16 wqe_size)
    443{
    444	u16 room = sq->reserved_room;
    445
    446	WARN_ONCE(wqe_size > sq->max_sq_wqebbs,
    447		  "wqe_size %u is greater than max SQ WQEBBs %u",
    448		  wqe_size, sq->max_sq_wqebbs);
    449
    450	room += MLX5E_STOP_ROOM(wqe_size);
    451
    452	return mlx5e_wqc_has_room_for(&sq->wq, sq->cc, sq->pc, room);
    453}
    454#endif