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-rx.c (6588B)


      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_rx_head_get_from_chip(const struct mcp251xfd_priv *priv,
     21				const struct mcp251xfd_rx_ring *ring,
     22				u8 *rx_head, bool *fifo_empty)
     23{
     24	u32 fifo_sta;
     25	int err;
     26
     27	err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOSTA(ring->fifo_nr),
     28			  &fifo_sta);
     29	if (err)
     30		return err;
     31
     32	*rx_head = FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, fifo_sta);
     33	*fifo_empty = !(fifo_sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF);
     34
     35	return 0;
     36}
     37
     38static inline int
     39mcp251xfd_rx_tail_get_from_chip(const struct mcp251xfd_priv *priv,
     40				const struct mcp251xfd_rx_ring *ring,
     41				u8 *rx_tail)
     42{
     43	u32 fifo_ua;
     44	int err;
     45
     46	err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOUA(ring->fifo_nr),
     47			  &fifo_ua);
     48	if (err)
     49		return err;
     50
     51	fifo_ua -= ring->base - MCP251XFD_RAM_START;
     52	*rx_tail = fifo_ua / ring->obj_size;
     53
     54	return 0;
     55}
     56
     57static int
     58mcp251xfd_check_rx_tail(const struct mcp251xfd_priv *priv,
     59			const struct mcp251xfd_rx_ring *ring)
     60{
     61	u8 rx_tail_chip, rx_tail;
     62	int err;
     63
     64	if (!IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY))
     65		return 0;
     66
     67	err = mcp251xfd_rx_tail_get_from_chip(priv, ring, &rx_tail_chip);
     68	if (err)
     69		return err;
     70
     71	rx_tail = mcp251xfd_get_rx_tail(ring);
     72	if (rx_tail_chip != rx_tail) {
     73		netdev_err(priv->ndev,
     74			   "RX tail of chip (%d) and ours (%d) inconsistent.\n",
     75			   rx_tail_chip, rx_tail);
     76		return -EILSEQ;
     77	}
     78
     79	return 0;
     80}
     81
     82static int
     83mcp251xfd_rx_ring_update(const struct mcp251xfd_priv *priv,
     84			 struct mcp251xfd_rx_ring *ring)
     85{
     86	u32 new_head;
     87	u8 chip_rx_head;
     88	bool fifo_empty;
     89	int err;
     90
     91	err = mcp251xfd_rx_head_get_from_chip(priv, ring, &chip_rx_head,
     92					      &fifo_empty);
     93	if (err || fifo_empty)
     94		return err;
     95
     96	/* chip_rx_head, is the next RX-Object filled by the HW.
     97	 * The new RX head must be >= the old head.
     98	 */
     99	new_head = round_down(ring->head, ring->obj_num) + chip_rx_head;
    100	if (new_head <= ring->head)
    101		new_head += ring->obj_num;
    102
    103	ring->head = new_head;
    104
    105	return mcp251xfd_check_rx_tail(priv, ring);
    106}
    107
    108static void
    109mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv,
    110			   const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj,
    111			   struct sk_buff *skb)
    112{
    113	struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
    114	u8 dlc;
    115
    116	if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_IDE) {
    117		u32 sid, eid;
    118
    119		eid = FIELD_GET(MCP251XFD_OBJ_ID_EID_MASK, hw_rx_obj->id);
    120		sid = FIELD_GET(MCP251XFD_OBJ_ID_SID_MASK, hw_rx_obj->id);
    121
    122		cfd->can_id = CAN_EFF_FLAG |
    123			FIELD_PREP(MCP251XFD_REG_FRAME_EFF_EID_MASK, eid) |
    124			FIELD_PREP(MCP251XFD_REG_FRAME_EFF_SID_MASK, sid);
    125	} else {
    126		cfd->can_id = FIELD_GET(MCP251XFD_OBJ_ID_SID_MASK,
    127					hw_rx_obj->id);
    128	}
    129
    130	dlc = FIELD_GET(MCP251XFD_OBJ_FLAGS_DLC_MASK, hw_rx_obj->flags);
    131
    132	/* CANFD */
    133	if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_FDF) {
    134		if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_ESI)
    135			cfd->flags |= CANFD_ESI;
    136
    137		if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_BRS)
    138			cfd->flags |= CANFD_BRS;
    139
    140		cfd->len = can_fd_dlc2len(dlc);
    141	} else {
    142		if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR)
    143			cfd->can_id |= CAN_RTR_FLAG;
    144
    145		can_frame_set_cc_len((struct can_frame *)cfd, dlc,
    146				     priv->can.ctrlmode);
    147	}
    148
    149	if (!(hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR))
    150		memcpy(cfd->data, hw_rx_obj->data, cfd->len);
    151
    152	mcp251xfd_skb_set_timestamp(priv, skb, hw_rx_obj->ts);
    153}
    154
    155static int
    156mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv,
    157			  struct mcp251xfd_rx_ring *ring,
    158			  const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj)
    159{
    160	struct net_device_stats *stats = &priv->ndev->stats;
    161	struct sk_buff *skb;
    162	struct canfd_frame *cfd;
    163	int err;
    164
    165	if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_FDF)
    166		skb = alloc_canfd_skb(priv->ndev, &cfd);
    167	else
    168		skb = alloc_can_skb(priv->ndev, (struct can_frame **)&cfd);
    169
    170	if (!skb) {
    171		stats->rx_dropped++;
    172		return 0;
    173	}
    174
    175	mcp251xfd_hw_rx_obj_to_skb(priv, hw_rx_obj, skb);
    176	err = can_rx_offload_queue_timestamp(&priv->offload, skb, hw_rx_obj->ts);
    177	if (err)
    178		stats->rx_fifo_errors++;
    179
    180	return 0;
    181}
    182
    183static inline int
    184mcp251xfd_rx_obj_read(const struct mcp251xfd_priv *priv,
    185		      const struct mcp251xfd_rx_ring *ring,
    186		      struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj,
    187		      const u8 offset, const u8 len)
    188{
    189	const int val_bytes = regmap_get_val_bytes(priv->map_rx);
    190	int err;
    191
    192	err = regmap_bulk_read(priv->map_rx,
    193			       mcp251xfd_get_rx_obj_addr(ring, offset),
    194			       hw_rx_obj,
    195			       len * ring->obj_size / val_bytes);
    196
    197	return err;
    198}
    199
    200static int
    201mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv,
    202			   struct mcp251xfd_rx_ring *ring)
    203{
    204	struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj = ring->obj;
    205	u8 rx_tail, len;
    206	int err, i;
    207
    208	err = mcp251xfd_rx_ring_update(priv, ring);
    209	if (err)
    210		return err;
    211
    212	while ((len = mcp251xfd_get_rx_linear_len(ring))) {
    213		int offset;
    214
    215		rx_tail = mcp251xfd_get_rx_tail(ring);
    216
    217		err = mcp251xfd_rx_obj_read(priv, ring, hw_rx_obj,
    218					    rx_tail, len);
    219		if (err)
    220			return err;
    221
    222		for (i = 0; i < len; i++) {
    223			err = mcp251xfd_handle_rxif_one(priv, ring,
    224							(void *)hw_rx_obj +
    225							i * ring->obj_size);
    226			if (err)
    227				return err;
    228		}
    229
    230		/* Increment the RX FIFO tail pointer 'len' times in a
    231		 * single SPI message.
    232		 *
    233		 * Note:
    234		 * Calculate offset, so that the SPI transfer ends on
    235		 * the last message of the uinc_xfer array, which has
    236		 * "cs_change == 0", to properly deactivate the chip
    237		 * select.
    238		 */
    239		offset = ARRAY_SIZE(ring->uinc_xfer) - len;
    240		err = spi_sync_transfer(priv->spi,
    241					ring->uinc_xfer + offset, len);
    242		if (err)
    243			return err;
    244
    245		ring->tail += len;
    246	}
    247
    248	return 0;
    249}
    250
    251int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv)
    252{
    253	struct mcp251xfd_rx_ring *ring;
    254	int err, n;
    255
    256	mcp251xfd_for_each_rx_ring(priv, ring, n) {
    257		/* - if RX IRQ coalescing is active always handle ring 0
    258		 * - only handle rings if RX IRQ is active
    259		 */
    260		if ((ring->nr > 0 || !priv->rx_obj_num_coalesce_irq) &&
    261		    !(priv->regs_status.rxif & BIT(ring->fifo_nr)))
    262			continue;
    263
    264		err = mcp251xfd_handle_rxif_ring(priv, ring);
    265		if (err)
    266			return err;
    267	}
    268
    269	if (priv->rx_coalesce_usecs_irq)
    270		hrtimer_start(&priv->rx_irq_timer,
    271			      ns_to_ktime(priv->rx_coalesce_usecs_irq *
    272					  NSEC_PER_USEC),
    273			      HRTIMER_MODE_REL);
    274
    275	return 0;
    276}