@@ -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 */
338343struct 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+
820863static 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+
12941362static 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
15211651failed_free_dev :
0 commit comments