Skip to content

Commit 6cc6426

Browse files
Marek Vasutmarckleinebudde
authored andcommitted
can: ifi: Add obscure bit swap for EFF frame IDs
In case of CAN2.0 EFF frame, the controller handles frame IDs in a rather bizzare way. The ID is split into an extended part, IDX[28:11] and standard part, ID[10:0]. In the TX path, the core first sends the top 11 bits of the IDX, followed by ID and finally the rest of IDX. In the RX path, the core stores the ID the LSbit part of IDX field, followed by the LSbit parts of real IDX. The MSbit parts of IDX are stored in ID field of the register. This patch implements the necessary bit shuffling to mitigate this obscure behavior. In case two of these controllers are connected together, the RX and TX bit swapping nullifies itself and the issue does not manifest. The issue only manifests when talking to another different CAN controller. Signed-off-by: Marek Vasut <[email protected]> Cc: Marc Kleine-Budde <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Oliver Hartkopp <[email protected]> Cc: Wolfgang Grandegger <[email protected]> Reviewed-by: Oliver Hartkopp <[email protected]> Signed-off-by: Marc Kleine-Budde <[email protected]>
1 parent 2236543 commit 6cc6426

File tree

1 file changed

+29
-2
lines changed

1 file changed

+29
-2
lines changed

drivers/net/can/ifi_canfd/ifi_canfd.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,11 @@
136136
#define IFI_CANFD_RXFIFO_ID 0x6c
137137
#define IFI_CANFD_RXFIFO_ID_ID_OFFSET 0
138138
#define IFI_CANFD_RXFIFO_ID_ID_STD_MASK CAN_SFF_MASK
139+
#define IFI_CANFD_RXFIFO_ID_ID_STD_OFFSET 0
140+
#define IFI_CANFD_RXFIFO_ID_ID_STD_WIDTH 10
139141
#define IFI_CANFD_RXFIFO_ID_ID_XTD_MASK CAN_EFF_MASK
142+
#define IFI_CANFD_RXFIFO_ID_ID_XTD_OFFSET 11
143+
#define IFI_CANFD_RXFIFO_ID_ID_XTD_WIDTH 18
140144
#define IFI_CANFD_RXFIFO_ID_IDE BIT(29)
141145

142146
#define IFI_CANFD_RXFIFO_DATA 0x70 /* 0x70..0xac */
@@ -157,7 +161,11 @@
157161
#define IFI_CANFD_TXFIFO_ID 0xbc
158162
#define IFI_CANFD_TXFIFO_ID_ID_OFFSET 0
159163
#define IFI_CANFD_TXFIFO_ID_ID_STD_MASK CAN_SFF_MASK
164+
#define IFI_CANFD_TXFIFO_ID_ID_STD_OFFSET 0
165+
#define IFI_CANFD_TXFIFO_ID_ID_STD_WIDTH 10
160166
#define IFI_CANFD_TXFIFO_ID_ID_XTD_MASK CAN_EFF_MASK
167+
#define IFI_CANFD_TXFIFO_ID_ID_XTD_OFFSET 11
168+
#define IFI_CANFD_TXFIFO_ID_ID_XTD_WIDTH 18
161169
#define IFI_CANFD_TXFIFO_ID_IDE BIT(29)
162170

163171
#define IFI_CANFD_TXFIFO_DATA 0xc0 /* 0xb0..0xfc */
@@ -229,10 +237,20 @@ static void ifi_canfd_read_fifo(struct net_device *ndev)
229237

230238
rxid = readl(priv->base + IFI_CANFD_RXFIFO_ID);
231239
id = (rxid >> IFI_CANFD_RXFIFO_ID_ID_OFFSET);
232-
if (id & IFI_CANFD_RXFIFO_ID_IDE)
240+
if (id & IFI_CANFD_RXFIFO_ID_IDE) {
233241
id &= IFI_CANFD_RXFIFO_ID_ID_XTD_MASK;
234-
else
242+
/*
243+
* In case the Extended ID frame is received, the standard
244+
* and extended part of the ID are swapped in the register,
245+
* so swap them back to obtain the correct ID.
246+
*/
247+
id = (id >> IFI_CANFD_RXFIFO_ID_ID_XTD_OFFSET) |
248+
((id & IFI_CANFD_RXFIFO_ID_ID_STD_MASK) <<
249+
IFI_CANFD_RXFIFO_ID_ID_XTD_WIDTH);
250+
id |= CAN_EFF_FLAG;
251+
} else {
235252
id &= IFI_CANFD_RXFIFO_ID_ID_STD_MASK;
253+
}
236254
cf->can_id = id;
237255

238256
if (rxdlc & IFI_CANFD_RXFIFO_DLC_ESI) {
@@ -767,6 +785,15 @@ static netdev_tx_t ifi_canfd_start_xmit(struct sk_buff *skb,
767785

768786
if (cf->can_id & CAN_EFF_FLAG) {
769787
txid = cf->can_id & CAN_EFF_MASK;
788+
/*
789+
* In case the Extended ID frame is transmitted, the
790+
* standard and extended part of the ID are swapped
791+
* in the register, so swap them back to send the
792+
* correct ID.
793+
*/
794+
txid = (txid >> IFI_CANFD_TXFIFO_ID_ID_XTD_WIDTH) |
795+
((txid & IFI_CANFD_TXFIFO_ID_ID_XTD_MASK) <<
796+
IFI_CANFD_TXFIFO_ID_ID_XTD_OFFSET);
770797
txid |= IFI_CANFD_TXFIFO_ID_IDE;
771798
} else {
772799
txid = cf->can_id & CAN_SFF_MASK;

0 commit comments

Comments
 (0)