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

mcp251xfd-tef.c (6900B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
      4//
      5// Copyright (c) 2019, 2020, 2021 Pengutronix,
      6//               Marc Kleine-Budde <kernel@pengutronix.de>
      7//
      8// Based on:
      9//
     10// CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
     11//
     12// Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org>
     13//
     14
     15#include <linux/bitfield.h>
     16
     17#include "mcp251xfd.h"
     18
     19static inline int
     20mcp251xfd_tef_tail_get_from_chip(const struct mcp251xfd_priv *priv,
     21				 u8 *tef_tail)
     22{
     23	u32 tef_ua;
     24	int err;
     25
     26	err = regmap_read(priv->map_reg, MCP251XFD_REG_TEFUA, &tef_ua);
     27	if (err)
     28		return err;
     29
     30	*tef_tail = tef_ua / sizeof(struct mcp251xfd_hw_tef_obj);
     31
     32	return 0;
     33}
     34
     35static int mcp251xfd_check_tef_tail(const struct mcp251xfd_priv *priv)
     36{
     37	u8 tef_tail_chip, tef_tail;
     38	int err;
     39
     40	if (!IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY))
     41		return 0;
     42
     43	err = mcp251xfd_tef_tail_get_from_chip(priv, &tef_tail_chip);
     44	if (err)
     45		return err;
     46
     47	tef_tail = mcp251xfd_get_tef_tail(priv);
     48	if (tef_tail_chip != tef_tail) {
     49		netdev_err(priv->ndev,
     50			   "TEF tail of chip (0x%02x) and ours (0x%08x) inconsistent.\n",
     51			   tef_tail_chip, tef_tail);
     52		return -EILSEQ;
     53	}
     54
     55	return 0;
     56}
     57
     58static int
     59mcp251xfd_handle_tefif_recover(const struct mcp251xfd_priv *priv, const u32 seq)
     60{
     61	const struct mcp251xfd_tx_ring *tx_ring = priv->tx;
     62	u32 tef_sta;
     63	int err;
     64
     65	err = regmap_read(priv->map_reg, MCP251XFD_REG_TEFSTA, &tef_sta);
     66	if (err)
     67		return err;
     68
     69	if (tef_sta & MCP251XFD_REG_TEFSTA_TEFOVIF) {
     70		netdev_err(priv->ndev,
     71			   "Transmit Event FIFO buffer overflow.\n");
     72		return -ENOBUFS;
     73	}
     74
     75	netdev_info(priv->ndev,
     76		    "Transmit Event FIFO buffer %s. (seq=0x%08x, tef_tail=0x%08x, tef_head=0x%08x, tx_head=0x%08x).\n",
     77		    tef_sta & MCP251XFD_REG_TEFSTA_TEFFIF ?
     78		    "full" : tef_sta & MCP251XFD_REG_TEFSTA_TEFNEIF ?
     79		    "not empty" : "empty",
     80		    seq, priv->tef->tail, priv->tef->head, tx_ring->head);
     81
     82	/* The Sequence Number in the TEF doesn't match our tef_tail. */
     83	return -EAGAIN;
     84}
     85
     86static int
     87mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
     88			   const struct mcp251xfd_hw_tef_obj *hw_tef_obj,
     89			   unsigned int *frame_len_ptr)
     90{
     91	struct net_device_stats *stats = &priv->ndev->stats;
     92	struct sk_buff *skb;
     93	u32 seq, seq_masked, tef_tail_masked, tef_tail;
     94
     95	seq = FIELD_GET(MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK,
     96			hw_tef_obj->flags);
     97
     98	/* Use the MCP2517FD mask on the MCP2518FD, too. We only
     99	 * compare 7 bits, this should be enough to detect
    100	 * net-yet-completed, i.e. old TEF objects.
    101	 */
    102	seq_masked = seq &
    103		field_mask(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK);
    104	tef_tail_masked = priv->tef->tail &
    105		field_mask(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK);
    106	if (seq_masked != tef_tail_masked)
    107		return mcp251xfd_handle_tefif_recover(priv, seq);
    108
    109	tef_tail = mcp251xfd_get_tef_tail(priv);
    110	skb = priv->can.echo_skb[tef_tail];
    111	if (skb)
    112		mcp251xfd_skb_set_timestamp(priv, skb, hw_tef_obj->ts);
    113	stats->tx_bytes +=
    114		can_rx_offload_get_echo_skb(&priv->offload,
    115					    tef_tail, hw_tef_obj->ts,
    116					    frame_len_ptr);
    117	stats->tx_packets++;
    118	priv->tef->tail++;
    119
    120	return 0;
    121}
    122
    123static int mcp251xfd_tef_ring_update(struct mcp251xfd_priv *priv)
    124{
    125	const struct mcp251xfd_tx_ring *tx_ring = priv->tx;
    126	unsigned int new_head;
    127	u8 chip_tx_tail;
    128	int err;
    129
    130	err = mcp251xfd_tx_tail_get_from_chip(priv, &chip_tx_tail);
    131	if (err)
    132		return err;
    133
    134	/* chip_tx_tail, is the next TX-Object send by the HW.
    135	 * The new TEF head must be >= the old head, ...
    136	 */
    137	new_head = round_down(priv->tef->head, tx_ring->obj_num) + chip_tx_tail;
    138	if (new_head <= priv->tef->head)
    139		new_head += tx_ring->obj_num;
    140
    141	/* ... but it cannot exceed the TX head. */
    142	priv->tef->head = min(new_head, tx_ring->head);
    143
    144	return mcp251xfd_check_tef_tail(priv);
    145}
    146
    147static inline int
    148mcp251xfd_tef_obj_read(const struct mcp251xfd_priv *priv,
    149		       struct mcp251xfd_hw_tef_obj *hw_tef_obj,
    150		       const u8 offset, const u8 len)
    151{
    152	const struct mcp251xfd_tx_ring *tx_ring = priv->tx;
    153	const int val_bytes = regmap_get_val_bytes(priv->map_rx);
    154
    155	if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) &&
    156	    (offset > tx_ring->obj_num ||
    157	     len > tx_ring->obj_num ||
    158	     offset + len > tx_ring->obj_num)) {
    159		netdev_err(priv->ndev,
    160			   "Trying to read too many TEF objects (max=%d, offset=%d, len=%d).\n",
    161			   tx_ring->obj_num, offset, len);
    162		return -ERANGE;
    163	}
    164
    165	return regmap_bulk_read(priv->map_rx,
    166				mcp251xfd_get_tef_obj_addr(offset),
    167				hw_tef_obj,
    168				sizeof(*hw_tef_obj) / val_bytes * len);
    169}
    170
    171static inline void mcp251xfd_ecc_tefif_successful(struct mcp251xfd_priv *priv)
    172{
    173	struct mcp251xfd_ecc *ecc = &priv->ecc;
    174
    175	ecc->ecc_stat = 0;
    176}
    177
    178int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
    179{
    180	struct mcp251xfd_hw_tef_obj hw_tef_obj[MCP251XFD_TX_OBJ_NUM_MAX];
    181	unsigned int total_frame_len = 0;
    182	u8 tef_tail, len, l;
    183	int err, i;
    184
    185	err = mcp251xfd_tef_ring_update(priv);
    186	if (err)
    187		return err;
    188
    189	tef_tail = mcp251xfd_get_tef_tail(priv);
    190	len = mcp251xfd_get_tef_len(priv);
    191	l = mcp251xfd_get_tef_linear_len(priv);
    192	err = mcp251xfd_tef_obj_read(priv, hw_tef_obj, tef_tail, l);
    193	if (err)
    194		return err;
    195
    196	if (l < len) {
    197		err = mcp251xfd_tef_obj_read(priv, &hw_tef_obj[l], 0, len - l);
    198		if (err)
    199			return err;
    200	}
    201
    202	for (i = 0; i < len; i++) {
    203		unsigned int frame_len = 0;
    204
    205		err = mcp251xfd_handle_tefif_one(priv, &hw_tef_obj[i], &frame_len);
    206		/* -EAGAIN means the Sequence Number in the TEF
    207		 * doesn't match our tef_tail. This can happen if we
    208		 * read the TEF objects too early. Leave loop let the
    209		 * interrupt handler call us again.
    210		 */
    211		if (err == -EAGAIN)
    212			goto out_netif_wake_queue;
    213		if (err)
    214			return err;
    215
    216		total_frame_len += frame_len;
    217	}
    218
    219 out_netif_wake_queue:
    220	len = i;	/* number of handled goods TEFs */
    221	if (len) {
    222		struct mcp251xfd_tef_ring *ring = priv->tef;
    223		struct mcp251xfd_tx_ring *tx_ring = priv->tx;
    224		int offset;
    225
    226		/* Increment the TEF FIFO tail pointer 'len' times in
    227		 * a single SPI message.
    228		 *
    229		 * Note:
    230		 * Calculate offset, so that the SPI transfer ends on
    231		 * the last message of the uinc_xfer array, which has
    232		 * "cs_change == 0", to properly deactivate the chip
    233		 * select.
    234		 */
    235		offset = ARRAY_SIZE(ring->uinc_xfer) - len;
    236		err = spi_sync_transfer(priv->spi,
    237					ring->uinc_xfer + offset, len);
    238		if (err)
    239			return err;
    240
    241		tx_ring->tail += len;
    242		netdev_completed_queue(priv->ndev, len, total_frame_len);
    243
    244		err = mcp251xfd_check_tef_tail(priv);
    245		if (err)
    246			return err;
    247	}
    248
    249	mcp251xfd_ecc_tefif_successful(priv);
    250
    251	if (mcp251xfd_get_tx_free(priv->tx)) {
    252		/* Make sure that anybody stopping the queue after
    253		 * this sees the new tx_ring->tail.
    254		 */
    255		smp_mb();
    256		netif_wake_queue(priv->ndev);
    257	}
    258
    259	if (priv->tx_coalesce_usecs_irq)
    260		hrtimer_start(&priv->tx_irq_timer,
    261			      ns_to_ktime(priv->tx_coalesce_usecs_irq *
    262					  NSEC_PER_USEC),
    263			      HRTIMER_MODE_REL);
    264
    265	return 0;
    266}