Skip to content

Commit 10c1c39

Browse files
0mhumarckleinebudde
authored andcommitted
can: m_can: Enable TX FIFO Handling for M_CAN IP version >= v3.1.x
* Added defines for TX Event FIFO Element * Adapted ndo_start_xmit function. For versions >= v3.1.x it uses the TX FIFO to optimize the data throughput. It stores the echo skb at the same index as in the M_CAN's TX FIFO. The frame's message marker is set to this index. This message marker is received in the TX Event FIFO after the message was successfully transmitted. It is used to echo the correct echo skb back to the network stack. * Added m_can_echo_tx_event function. It reads all received message markers in the TX Event FIFO and loops back the corresponding echo skbs. * ISR checks for new TX Event Entry interrupt for version >= 3.1.x. Signed-off-by: Mario Huettel <[email protected]> Reviewed-by: Oliver Hartkopp <[email protected]> Tested-by: Quentin Schulz <[email protected]> Signed-off-by: Marc Kleine-Budde <[email protected]>
1 parent 428479e commit 10c1c39

File tree

1 file changed

+159
-29
lines changed

1 file changed

+159
-29
lines changed

drivers/net/can/m_can/m_can.c

Lines changed: 159 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,11 @@ enum m_can_mram_cfg {
334334
#define TX_BUF_MM_SHIFT 24
335335
#define TX_BUF_MM_MASK (0xff << TX_BUF_MM_SHIFT)
336336

337+
/* Tx event FIFO Element */
338+
/* E1 */
339+
#define TX_EVENT_MM_SHIFT TX_BUF_MM_SHIFT
340+
#define TX_EVENT_MM_MASK (0xff << TX_EVENT_MM_SHIFT)
341+
337342
/* address offset and element number for each FIFO/Buffer in the Message RAM */
338343
struct mram_cfg {
339344
u16 off;
@@ -817,6 +822,44 @@ static int m_can_poll(struct napi_struct *napi, int quota)
817822
return work_done;
818823
}
819824

825+
static void m_can_echo_tx_event(struct net_device *dev)
826+
{
827+
u32 txe_count = 0;
828+
u32 m_can_txefs;
829+
u32 fgi = 0;
830+
int i = 0;
831+
unsigned int msg_mark;
832+
833+
struct m_can_priv *priv = netdev_priv(dev);
834+
struct net_device_stats *stats = &dev->stats;
835+
836+
/* read tx event fifo status */
837+
m_can_txefs = m_can_read(priv, M_CAN_TXEFS);
838+
839+
/* Get Tx Event fifo element count */
840+
txe_count = (m_can_txefs & TXEFS_EFFL_MASK)
841+
>> TXEFS_EFFL_SHIFT;
842+
843+
/* Get and process all sent elements */
844+
for (i = 0; i < txe_count; i++) {
845+
/* retrieve get index */
846+
fgi = (m_can_read(priv, M_CAN_TXEFS) & TXEFS_EFGI_MASK)
847+
>> TXEFS_EFGI_SHIFT;
848+
849+
/* get message marker */
850+
msg_mark = (m_can_txe_fifo_read(priv, fgi, 4) &
851+
TX_EVENT_MM_MASK) >> TX_EVENT_MM_SHIFT;
852+
853+
/* ack txe element */
854+
m_can_write(priv, M_CAN_TXEFA, (TXEFA_EFAI_MASK &
855+
(fgi << TXEFA_EFAI_SHIFT)));
856+
857+
/* update stats */
858+
stats->tx_bytes += can_get_echo_skb(dev, msg_mark);
859+
stats->tx_packets++;
860+
}
861+
}
862+
820863
static irqreturn_t m_can_isr(int irq, void *dev_id)
821864
{
822865
struct net_device *dev = (struct net_device *)dev_id;
@@ -843,12 +886,23 @@ static irqreturn_t m_can_isr(int irq, void *dev_id)
843886
napi_schedule(&priv->napi);
844887
}
845888

846-
/* transmission complete interrupt */
847-
if (ir & IR_TC) {
848-
stats->tx_bytes += can_get_echo_skb(dev, 0);
849-
stats->tx_packets++;
850-
can_led_event(dev, CAN_LED_EVENT_TX);
851-
netif_wake_queue(dev);
889+
if (priv->version == 30) {
890+
if (ir & IR_TC) {
891+
/* Transmission Complete Interrupt*/
892+
stats->tx_bytes += can_get_echo_skb(dev, 0);
893+
stats->tx_packets++;
894+
can_led_event(dev, CAN_LED_EVENT_TX);
895+
netif_wake_queue(dev);
896+
}
897+
} else {
898+
if (ir & IR_TEFN) {
899+
/* New TX FIFO Element arrived */
900+
m_can_echo_tx_event(dev);
901+
can_led_event(dev, CAN_LED_EVENT_TX);
902+
if (netif_queue_stopped(dev) &&
903+
!m_can_tx_fifo_full(priv))
904+
netif_wake_queue(dev);
905+
}
852906
}
853907

854908
return IRQ_HANDLED;
@@ -1291,19 +1345,34 @@ static int m_can_close(struct net_device *dev)
12911345
return 0;
12921346
}
12931347

1348+
static int m_can_next_echo_skb_occupied(struct net_device *dev, int putidx)
1349+
{
1350+
struct m_can_priv *priv = netdev_priv(dev);
1351+
/*get wrap around for loopback skb index */
1352+
unsigned int wrap = priv->can.echo_skb_max;
1353+
int next_idx;
1354+
1355+
/* calculate next index */
1356+
next_idx = (++putidx >= wrap ? 0 : putidx);
1357+
1358+
/* check if occupied */
1359+
return !!priv->can.echo_skb[next_idx];
1360+
}
1361+
12941362
static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,
12951363
struct net_device *dev)
12961364
{
12971365
struct m_can_priv *priv = netdev_priv(dev);
12981366
struct canfd_frame *cf = (struct canfd_frame *)skb->data;
1299-
u32 id, cccr;
1367+
u32 id, cccr, fdflags;
13001368
int i;
1369+
int putidx;
13011370

13021371
if (can_dropped_invalid_skb(dev, skb))
13031372
return NETDEV_TX_OK;
13041373

1305-
netif_stop_queue(dev);
1306-
1374+
/* Generate ID field for TX buffer Element */
1375+
/* Common to all supported M_CAN versions */
13071376
if (cf->can_id & CAN_EFF_FLAG) {
13081377
id = cf->can_id & CAN_EFF_MASK;
13091378
id |= TX_BUF_XTD;
@@ -1314,33 +1383,93 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,
13141383
if (cf->can_id & CAN_RTR_FLAG)
13151384
id |= TX_BUF_RTR;
13161385

1317-
/* message ram configuration */
1318-
m_can_fifo_write(priv, 0, M_CAN_FIFO_ID, id);
1319-
m_can_fifo_write(priv, 0, M_CAN_FIFO_DLC, can_len2dlc(cf->len) << 16);
1386+
if (priv->version == 30) {
1387+
netif_stop_queue(dev);
1388+
1389+
/* message ram configuration */
1390+
m_can_fifo_write(priv, 0, M_CAN_FIFO_ID, id);
1391+
m_can_fifo_write(priv, 0, M_CAN_FIFO_DLC,
1392+
can_len2dlc(cf->len) << 16);
13201393

1321-
for (i = 0; i < cf->len; i += 4)
1322-
m_can_fifo_write(priv, 0, M_CAN_FIFO_DATA(i / 4),
1323-
*(u32 *)(cf->data + i));
1394+
for (i = 0; i < cf->len; i += 4)
1395+
m_can_fifo_write(priv, 0,
1396+
M_CAN_FIFO_DATA(i / 4),
1397+
*(u32 *)(cf->data + i));
1398+
1399+
can_put_echo_skb(skb, dev, 0);
1400+
1401+
if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
1402+
cccr = m_can_read(priv, M_CAN_CCCR);
1403+
cccr &= ~(CCCR_CMR_MASK << CCCR_CMR_SHIFT);
1404+
if (can_is_canfd_skb(skb)) {
1405+
if (cf->flags & CANFD_BRS)
1406+
cccr |= CCCR_CMR_CANFD_BRS <<
1407+
CCCR_CMR_SHIFT;
1408+
else
1409+
cccr |= CCCR_CMR_CANFD <<
1410+
CCCR_CMR_SHIFT;
1411+
} else {
1412+
cccr |= CCCR_CMR_CAN << CCCR_CMR_SHIFT;
1413+
}
1414+
m_can_write(priv, M_CAN_CCCR, cccr);
1415+
}
1416+
m_can_write(priv, M_CAN_TXBTIE, 0x1);
1417+
m_can_write(priv, M_CAN_TXBAR, 0x1);
1418+
/* End of xmit function for version 3.0.x */
1419+
} else {
1420+
/* Transmit routine for version >= v3.1.x */
1421+
1422+
/* Check if FIFO full */
1423+
if (m_can_tx_fifo_full(priv)) {
1424+
/* This shouldn't happen */
1425+
netif_stop_queue(dev);
1426+
netdev_warn(dev,
1427+
"TX queue active although FIFO is full.");
1428+
return NETDEV_TX_BUSY;
1429+
}
13241430

1325-
can_put_echo_skb(skb, dev, 0);
1431+
/* get put index for frame */
1432+
putidx = ((m_can_read(priv, M_CAN_TXFQS) & TXFQS_TFQPI_MASK)
1433+
>> TXFQS_TFQPI_SHIFT);
1434+
/* Write ID Field to FIFO Element */
1435+
m_can_fifo_write(priv, putidx, M_CAN_FIFO_ID, id);
13261436

1327-
if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
1328-
cccr = m_can_read(priv, M_CAN_CCCR);
1329-
cccr &= ~(CCCR_CMR_MASK << CCCR_CMR_SHIFT);
1437+
/* get CAN FD configuration of frame */
1438+
fdflags = 0;
13301439
if (can_is_canfd_skb(skb)) {
1440+
fdflags |= TX_BUF_FDF;
13311441
if (cf->flags & CANFD_BRS)
1332-
cccr |= CCCR_CMR_CANFD_BRS << CCCR_CMR_SHIFT;
1333-
else
1334-
cccr |= CCCR_CMR_CANFD << CCCR_CMR_SHIFT;
1335-
} else {
1336-
cccr |= CCCR_CMR_CAN << CCCR_CMR_SHIFT;
1442+
fdflags |= TX_BUF_BRS;
13371443
}
1338-
m_can_write(priv, M_CAN_CCCR, cccr);
1339-
}
13401444

1341-
/* enable first TX buffer to start transfer */
1342-
m_can_write(priv, M_CAN_TXBTIE, 0x1);
1343-
m_can_write(priv, M_CAN_TXBAR, 0x1);
1445+
/* Construct DLC Field. Also contains CAN-FD configuration
1446+
* use put index of fifo as message marker
1447+
* it is used in TX interrupt for
1448+
* sending the correct echo frame
1449+
*/
1450+
m_can_fifo_write(priv, putidx, M_CAN_FIFO_DLC,
1451+
((putidx << TX_BUF_MM_SHIFT) &
1452+
TX_BUF_MM_MASK) |
1453+
(can_len2dlc(cf->len) << 16) |
1454+
fdflags | TX_BUF_EFC);
1455+
1456+
for (i = 0; i < cf->len; i += 4)
1457+
m_can_fifo_write(priv, putidx, M_CAN_FIFO_DATA(i / 4),
1458+
*(u32 *)(cf->data + i));
1459+
1460+
/* Push loopback echo.
1461+
* Will be looped back on TX interrupt based on message marker
1462+
*/
1463+
can_put_echo_skb(skb, dev, putidx);
1464+
1465+
/* Enable TX FIFO element to start transfer */
1466+
m_can_write(priv, M_CAN_TXBAR, (1 << putidx));
1467+
1468+
/* stop network queue if fifo full */
1469+
if (m_can_tx_fifo_full(priv) ||
1470+
m_can_next_echo_skb_occupied(dev, putidx))
1471+
netif_stop_queue(dev);
1472+
}
13441473

13451474
return NETDEV_TX_OK;
13461475
}
@@ -1516,6 +1645,7 @@ static int m_can_plat_probe(struct platform_device *pdev)
15161645
/* Probe finished
15171646
* Stop clocks. They will be reactivated once the M_CAN device is opened
15181647
*/
1648+
15191649
goto disable_cclk_ret;
15201650

15211651
failed_free_dev:

0 commit comments

Comments
 (0)