Skip to content

Commit c7eb923

Browse files
can: mcp251xfd: mcp251xfd_regmap_crc_read(): work around broken CRC on TBC register
MCP251XFD_REG_TBC is the time base counter register. It increments once per SYS clock tick, which is 20 or 40 MHz. Observation shows that if the lowest byte (which is transferred first on the SPI bus) of that register is 0x00 or 0x80 the calculated CRC doesn't always match the transferred one. To reproduce this problem let the driver read the TBC register in a high frequency. This can be done by attaching only the mcp251xfd CAN controller to a valid terminated CAN bus and send a single CAN frame. As there are no other CAN controller on the bus, the sent CAN frame is not ACKed and the mcp251xfd repeats it. If user space enables the bus error reporting, each of the NACK errors is reported with a time stamp (which is read from the TBC register) to user space. $ ip link set can0 down $ ip link set can0 up type can bitrate 500000 berr-reporting on $ cansend can0 4FF#ff.01.00.00.00.00.00.00 This leads to several error messages per second: | mcp251xfd spi0.0 can0: CRC read error at address 0x0010 (length=4, data=00 3a 86 da, CRC=0x7753) retrying. | mcp251xfd spi0.0 can0: CRC read error at address 0x0010 (length=4, data=80 01 b4 da, CRC=0x5830) retrying. | mcp251xfd spi0.0 can0: CRC read error at address 0x0010 (length=4, data=00 e9 23 db, CRC=0xa723) retrying. | mcp251xfd spi0.0 can0: CRC read error at address 0x0010 (length=4, data=00 8a 30 db, CRC=0x4a9c) retrying. | mcp251xfd spi0.0 can0: CRC read error at address 0x0010 (length=4, data=80 f3 43 db, CRC=0x66d2) retrying. If the highest bit in the lowest byte is flipped the transferred CRC matches the calculated one. We assume for now the CRC calculation in the chip works on wrong data and the transferred data is correct. This patch implements the following workaround: - If a CRC read error on the TBC register is detected and the lowest byte is 0x00 or 0x80, the highest bit of the lowest byte is flipped and the CRC is calculated again. - If the CRC now matches, the _original_ data is passed to the reader. For now we assume transferred data was OK. Link: https://lore.kernel.org/r/[email protected] Cc: Manivannan Sadhasivam <[email protected]> Cc: Thomas Kopp <[email protected]> Signed-off-by: Marc Kleine-Budde <[email protected]>
1 parent ef7a8c3 commit c7eb923

File tree

1 file changed

+34
-0
lines changed

1 file changed

+34
-0
lines changed

drivers/net/can/spi/mcp251xfd/mcp251xfd-regmap.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,40 @@ mcp251xfd_regmap_crc_read(void *context,
321321
if (err != -EBADMSG)
322322
return err;
323323

324+
/* MCP251XFD_REG_TBC is the time base counter
325+
* register. It increments once per SYS clock tick,
326+
* which is 20 or 40 MHz.
327+
*
328+
* Observation shows that if the lowest byte (which is
329+
* transferred first on the SPI bus) of that register
330+
* is 0x00 or 0x80 the calculated CRC doesn't always
331+
* match the transferred one.
332+
*
333+
* If the highest bit in the lowest byte is flipped
334+
* the transferred CRC matches the calculated one. We
335+
* assume for now the CRC calculation in the chip
336+
* works on wrong data and the transferred data is
337+
* correct.
338+
*/
339+
if (reg == MCP251XFD_REG_TBC &&
340+
(buf_rx->data[0] == 0x0 || buf_rx->data[0] == 0x80)) {
341+
/* Flip highest bit in lowest byte of le32 */
342+
buf_rx->data[0] ^= 0x80;
343+
344+
/* re-check CRC */
345+
err = mcp251xfd_regmap_crc_read_check_crc(buf_rx,
346+
buf_tx,
347+
val_len);
348+
if (!err) {
349+
/* If CRC is now correct, assume
350+
* transferred data was OK, flip bit
351+
* back to original value.
352+
*/
353+
buf_rx->data[0] ^= 0x80;
354+
goto out;
355+
}
356+
}
357+
324358
/* MCP251XFD_REG_OSC is the first ever reg we read from.
325359
*
326360
* The chip may be in deep sleep and this SPI transfer

0 commit comments

Comments
 (0)