diff options
Diffstat (limited to 'drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c')
-rw-r--r-- | drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c | 162 |
1 files changed, 120 insertions, 42 deletions
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c index 8a39be076e14..77129d5f410b 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c @@ -326,17 +326,36 @@ mcp251xfd_tx_ring_init_tx_obj(const struct mcp251xfd_priv *priv, static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv) { + struct mcp251xfd_tef_ring *tef_ring; struct mcp251xfd_tx_ring *tx_ring; struct mcp251xfd_rx_ring *rx_ring, *prev_rx_ring = NULL; struct mcp251xfd_tx_obj *tx_obj; u32 val; u16 addr; u8 len; - int i; + int i, j; /* TEF */ - priv->tef.head = 0; - priv->tef.tail = 0; + tef_ring = priv->tef; + tef_ring->head = 0; + tef_ring->tail = 0; + + /* FIFO increment TEF tail pointer */ + addr = MCP251XFD_REG_TEFCON; + val = MCP251XFD_REG_TEFCON_UINC; + len = mcp251xfd_cmd_prepare_write_reg(priv, &tef_ring->uinc_buf, + addr, val, val); + + for (j = 0; j < ARRAY_SIZE(tef_ring->uinc_xfer); j++) { + struct spi_transfer *xfer; + + xfer = &tef_ring->uinc_xfer[j]; + xfer->tx_buf = &tef_ring->uinc_buf; + xfer->len = len; + xfer->cs_change = 1; + xfer->cs_change_delay.value = 0; + xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; + } /* TX */ tx_ring = priv->tx; @@ -370,6 +389,23 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv) prev_rx_ring->obj_num; prev_rx_ring = rx_ring; + + /* FIFO increment RX tail pointer */ + addr = MCP251XFD_REG_FIFOCON(rx_ring->fifo_nr); + val = MCP251XFD_REG_FIFOCON_UINC; + len = mcp251xfd_cmd_prepare_write_reg(priv, &rx_ring->uinc_buf, + addr, val, val); + + for (j = 0; j < ARRAY_SIZE(rx_ring->uinc_xfer); j++) { + struct spi_transfer *xfer; + + xfer = &rx_ring->uinc_xfer[j]; + xfer->tx_buf = &rx_ring->uinc_buf; + xfer->len = len; + xfer->cs_change = 1; + xfer->cs_change_delay.value = 0; + xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; + } } } @@ -416,7 +452,8 @@ static int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv) int rx_obj_num; rx_obj_num = ram_free / rx_obj_size; - rx_obj_num = min(1 << (fls(rx_obj_num) - 1), 32); + rx_obj_num = min(1 << (fls(rx_obj_num) - 1), + MCP251XFD_RX_OBJ_NUM_MAX); rx_ring = kzalloc(sizeof(*rx_ring) + rx_obj_size * rx_obj_num, GFP_KERNEL); @@ -644,10 +681,7 @@ static int mcp251xfd_chip_softreset(const struct mcp251xfd_priv *priv) return 0; } - if (err) - return err; - - return -ETIMEDOUT; + return err; } static int mcp251xfd_chip_clock_init(const struct mcp251xfd_priv *priv) @@ -931,7 +965,10 @@ static u8 mcp251xfd_get_normal_mode(const struct mcp251xfd_priv *priv) { u8 mode; - if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) + + if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) + mode = MCP251XFD_REG_CON_MODE_INT_LOOPBACK; + else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) mode = MCP251XFD_REG_CON_MODE_LISTENONLY; else if (priv->can.ctrlmode & CAN_CTRLMODE_FD) mode = MCP251XFD_REG_CON_MODE_MIXED; @@ -1204,7 +1241,7 @@ mcp251xfd_handle_tefif_recover(const struct mcp251xfd_priv *priv, const u32 seq) tef_sta & MCP251XFD_REG_TEFSTA_TEFFIF ? "full" : tef_sta & MCP251XFD_REG_TEFSTA_TEFNEIF ? "not empty" : "empty", - seq, priv->tef.tail, priv->tef.head, tx_ring->head); + seq, priv->tef->tail, priv->tef->head, tx_ring->head); /* The Sequence Number in the TEF doesn't match our tef_tail. */ return -EAGAIN; @@ -1214,10 +1251,8 @@ static int mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv, const struct mcp251xfd_hw_tef_obj *hw_tef_obj) { - struct mcp251xfd_tx_ring *tx_ring = priv->tx; struct net_device_stats *stats = &priv->ndev->stats; u32 seq, seq_masked, tef_tail_masked; - int err; seq = FIELD_GET(MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK, hw_tef_obj->flags); @@ -1228,7 +1263,7 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv, */ seq_masked = seq & field_mask(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK); - tef_tail_masked = priv->tef.tail & + tef_tail_masked = priv->tef->tail & field_mask(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK); if (seq_masked != tef_tail_masked) return mcp251xfd_handle_tefif_recover(priv, seq); @@ -1238,18 +1273,9 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv, mcp251xfd_get_tef_tail(priv), hw_tef_obj->ts); stats->tx_packets++; + priv->tef->tail++; - /* finally increment the TEF pointer */ - err = regmap_update_bits(priv->map_reg, MCP251XFD_REG_TEFCON, - GENMASK(15, 8), - MCP251XFD_REG_TEFCON_UINC); - if (err) - return err; - - priv->tef.tail++; - tx_ring->tail++; - - return mcp251xfd_check_tef_tail(priv); + return 0; } static int mcp251xfd_tef_ring_update(struct mcp251xfd_priv *priv) @@ -1266,12 +1292,12 @@ static int mcp251xfd_tef_ring_update(struct mcp251xfd_priv *priv) /* chip_tx_tail, is the next TX-Object send by the HW. * The new TEF head must be >= the old head, ... */ - new_head = round_down(priv->tef.head, tx_ring->obj_num) + chip_tx_tail; - if (new_head <= priv->tef.head) + new_head = round_down(priv->tef->head, tx_ring->obj_num) + chip_tx_tail; + if (new_head <= priv->tef->head) new_head += tx_ring->obj_num; /* ... but it cannot exceed the TX head. */ - priv->tef.head = min(new_head, tx_ring->head); + priv->tef->head = min(new_head, tx_ring->head); return mcp251xfd_check_tef_tail(priv); } @@ -1336,6 +1362,40 @@ static int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv) } out_netif_wake_queue: + len = i; /* number of handled goods TEFs */ + if (len) { + struct mcp251xfd_tef_ring *ring = priv->tef; + struct mcp251xfd_tx_ring *tx_ring = priv->tx; + struct spi_transfer *last_xfer; + + tx_ring->tail += len; + + /* Increment the TEF FIFO tail pointer 'len' times in + * a single SPI message. + */ + + /* Note: + * + * "cs_change == 1" on the last transfer results in an + * active chip select after the complete SPI + * message. This causes the controller to interpret + * the next register access as data. Temporary set + * "cs_change" of the last transfer to "0" to properly + * deactivate the chip select at the end of the + * message. + */ + last_xfer = &ring->uinc_xfer[len - 1]; + last_xfer->cs_change = 0; + err = spi_sync_transfer(priv->spi, ring->uinc_xfer, len); + last_xfer->cs_change = 1; + if (err) + return err; + + err = mcp251xfd_check_tef_tail(priv); + if (err) + return err; + } + mcp251xfd_ecc_tefif_successful(priv); if (mcp251xfd_get_tx_free(priv->tx)) { @@ -1405,12 +1465,12 @@ mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv, cfd->flags |= CANFD_BRS; dlc = FIELD_GET(MCP251XFD_OBJ_FLAGS_DLC, hw_rx_obj->flags); - cfd->len = can_dlc2len(get_canfd_dlc(dlc)); + cfd->len = can_fd_dlc2len(dlc); } else { if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR) cfd->can_id |= CAN_RTR_FLAG; - cfd->len = get_can_dlc(FIELD_GET(MCP251XFD_OBJ_FLAGS_DLC, + cfd->len = can_cc_dlc2len(FIELD_GET(MCP251XFD_OBJ_FLAGS_DLC, hw_rx_obj->flags)); } @@ -1442,13 +1502,7 @@ mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv, if (err) stats->rx_fifo_errors++; - ring->tail++; - - /* finally increment the RX pointer */ - return regmap_update_bits(priv->map_reg, - MCP251XFD_REG_FIFOCON(ring->fifo_nr), - GENMASK(15, 8), - MCP251XFD_REG_FIFOCON_UINC); + return 0; } static inline int @@ -1480,6 +1534,8 @@ mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv, return err; while ((len = mcp251xfd_get_rx_linear_len(ring))) { + struct spi_transfer *last_xfer; + rx_tail = mcp251xfd_get_rx_tail(ring); err = mcp251xfd_rx_obj_read(priv, ring, hw_rx_obj, @@ -1494,6 +1550,28 @@ mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv, if (err) return err; } + + /* Increment the RX FIFO tail pointer 'len' times in a + * single SPI message. + */ + ring->tail += len; + + /* Note: + * + * "cs_change == 1" on the last transfer results in an + * active chip select after the complete SPI + * message. This causes the controller to interpret + * the next register access as data. Temporary set + * "cs_change" of the last transfer to "0" to properly + * deactivate the chip select at the end of the + * message. + */ + last_xfer = &ring->uinc_xfer[len - 1]; + last_xfer->cs_change = 0; + err = spi_sync_transfer(priv->spi, ring->uinc_xfer, len); + last_xfer->cs_change = 1; + if (err) + return err; } return 0; @@ -2244,7 +2322,7 @@ mcp251xfd_tx_obj_from_skb(const struct mcp251xfd_priv *priv, * harm, only the lower 7 bits will be transferred into the * TEF object. */ - dlc = can_len2dlc(cfd->len); + dlc = can_fd_len2dlc(cfd->len); flags |= FIELD_PREP(MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK, seq) | FIELD_PREP(MCP251XFD_OBJ_FLAGS_DLC, dlc); @@ -2273,7 +2351,7 @@ mcp251xfd_tx_obj_from_skb(const struct mcp251xfd_priv *priv, /* Clear data at end of CAN frame */ offset = round_down(cfd->len, sizeof(u32)); - len = round_up(can_dlc2len(dlc), sizeof(u32)) - offset; + len = round_up(can_fd_dlc2len(dlc), sizeof(u32)) - offset; if (MCP251XFD_SANITIZE_CAN && len) memset(hw_tx_obj->data + offset, 0x0, len); memcpy(hw_tx_obj->data, cfd->data, cfd->len); @@ -2281,7 +2359,7 @@ mcp251xfd_tx_obj_from_skb(const struct mcp251xfd_priv *priv, /* Number of bytes to be written into the RAM of the controller */ len = sizeof(hw_tx_obj->id) + sizeof(hw_tx_obj->flags); if (MCP251XFD_SANITIZE_CAN) - len += round_up(can_dlc2len(dlc), sizeof(u32)); + len += round_up(can_fd_dlc2len(dlc), sizeof(u32)); else len += round_up(cfd->len, sizeof(u32)); @@ -2806,9 +2884,9 @@ static int mcp251xfd_probe(struct spi_device *spi) priv->can.do_get_berr_counter = mcp251xfd_get_berr_counter; priv->can.bittiming_const = &mcp251xfd_bittiming_const; priv->can.data_bittiming_const = &mcp251xfd_data_bittiming_const; - priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY | - CAN_CTRLMODE_BERR_REPORTING | CAN_CTRLMODE_FD | - CAN_CTRLMODE_FD_NON_ISO; + priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | + CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_BERR_REPORTING | + CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO; priv->ndev = ndev; priv->spi = spi; priv->rx_int = rx_int; |