@@ -390,37 +390,23 @@ static int cc770_get_berr_counter(const struct net_device *dev,
390
390
return 0 ;
391
391
}
392
392
393
- static netdev_tx_t cc770_start_xmit (struct sk_buff * skb , struct net_device * dev )
393
+ static void cc770_tx (struct net_device * dev , int mo )
394
394
{
395
395
struct cc770_priv * priv = netdev_priv (dev );
396
- struct net_device_stats * stats = & dev -> stats ;
397
- struct can_frame * cf = (struct can_frame * )skb -> data ;
398
- unsigned int mo = obj2msgobj (CC770_OBJ_TX );
396
+ struct can_frame * cf = (struct can_frame * )priv -> tx_skb -> data ;
399
397
u8 dlc , rtr ;
400
398
u32 id ;
401
399
int i ;
402
400
403
- if (can_dropped_invalid_skb (dev , skb ))
404
- return NETDEV_TX_OK ;
405
-
406
- if ((cc770_read_reg (priv ,
407
- msgobj [mo ].ctrl1 ) & TXRQST_UNC ) == TXRQST_SET ) {
408
- netdev_err (dev , "TX register is still occupied!\n" );
409
- return NETDEV_TX_BUSY ;
410
- }
411
-
412
- netif_stop_queue (dev );
413
-
414
401
dlc = cf -> can_dlc ;
415
402
id = cf -> can_id ;
416
- if ( cf -> can_id & CAN_RTR_FLAG )
417
- rtr = 0 ;
418
- else
419
- rtr = MSGCFG_DIR ;
403
+ rtr = cf -> can_id & CAN_RTR_FLAG ? 0 : MSGCFG_DIR ;
404
+
405
+ cc770_write_reg ( priv , msgobj [ mo ]. ctrl0 ,
406
+ MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES ) ;
420
407
cc770_write_reg (priv , msgobj [mo ].ctrl1 ,
421
408
RMTPND_RES | TXRQST_RES | CPUUPD_SET | NEWDAT_RES );
422
- cc770_write_reg (priv , msgobj [mo ].ctrl0 ,
423
- MSGVAL_SET | TXIE_SET | RXIE_RES | INTPND_RES );
409
+
424
410
if (id & CAN_EFF_FLAG ) {
425
411
id &= CAN_EFF_MASK ;
426
412
cc770_write_reg (priv , msgobj [mo ].config ,
@@ -439,22 +425,30 @@ static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev)
439
425
for (i = 0 ; i < dlc ; i ++ )
440
426
cc770_write_reg (priv , msgobj [mo ].data [i ], cf -> data [i ]);
441
427
442
- /* Store echo skb before starting the transfer */
443
- can_put_echo_skb (skb , dev , 0 );
444
-
445
428
cc770_write_reg (priv , msgobj [mo ].ctrl1 ,
446
- RMTPND_RES | TXRQST_SET | CPUUPD_RES | NEWDAT_UNC );
429
+ RMTPND_UNC | TXRQST_SET | CPUUPD_RES | NEWDAT_UNC );
430
+ cc770_write_reg (priv , msgobj [mo ].ctrl0 ,
431
+ MSGVAL_SET | TXIE_SET | RXIE_SET | INTPND_UNC );
432
+ }
447
433
448
- stats -> tx_bytes += dlc ;
434
+ static netdev_tx_t cc770_start_xmit (struct sk_buff * skb , struct net_device * dev )
435
+ {
436
+ struct cc770_priv * priv = netdev_priv (dev );
437
+ unsigned int mo = obj2msgobj (CC770_OBJ_TX );
449
438
439
+ if (can_dropped_invalid_skb (dev , skb ))
440
+ return NETDEV_TX_OK ;
450
441
451
- /*
452
- * HM: We had some cases of repeated IRQs so make sure the
453
- * INT is acknowledged I know it's already further up, but
454
- * doing again fixed the issue
455
- */
456
- cc770_write_reg (priv , msgobj [mo ].ctrl0 ,
457
- MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES );
442
+ netif_stop_queue (dev );
443
+
444
+ if ((cc770_read_reg (priv ,
445
+ msgobj [mo ].ctrl1 ) & TXRQST_UNC ) == TXRQST_SET ) {
446
+ netdev_err (dev , "TX register is still occupied!\n" );
447
+ return NETDEV_TX_BUSY ;
448
+ }
449
+
450
+ priv -> tx_skb = skb ;
451
+ cc770_tx (dev , mo );
458
452
459
453
return NETDEV_TX_OK ;
460
454
}
@@ -680,19 +674,47 @@ static void cc770_tx_interrupt(struct net_device *dev, unsigned int o)
680
674
struct cc770_priv * priv = netdev_priv (dev );
681
675
struct net_device_stats * stats = & dev -> stats ;
682
676
unsigned int mo = obj2msgobj (o );
677
+ struct can_frame * cf ;
678
+ u8 ctrl1 ;
679
+
680
+ ctrl1 = cc770_read_reg (priv , msgobj [mo ].ctrl1 );
683
681
684
- /* Nothing more to send, switch off interrupts */
685
682
cc770_write_reg (priv , msgobj [mo ].ctrl0 ,
686
683
MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES );
687
- /*
688
- * We had some cases of repeated IRQ so make sure the
689
- * INT is acknowledged
684
+ cc770_write_reg (priv , msgobj [mo ].ctrl1 ,
685
+ RMTPND_RES | TXRQST_RES | MSGLST_RES | NEWDAT_RES );
686
+
687
+ if (unlikely (!priv -> tx_skb )) {
688
+ netdev_err (dev , "missing tx skb in tx interrupt\n" );
689
+ return ;
690
+ }
691
+
692
+ if (unlikely (ctrl1 & MSGLST_SET )) {
693
+ stats -> rx_over_errors ++ ;
694
+ stats -> rx_errors ++ ;
695
+ }
696
+
697
+ /* When the CC770 is sending an RTR message and it receives a regular
698
+ * message that matches the id of the RTR message, it will overwrite the
699
+ * outgoing message in the TX register. When this happens we must
700
+ * process the received message and try to transmit the outgoing skb
701
+ * again.
690
702
*/
691
- cc770_write_reg (priv , msgobj [mo ].ctrl0 ,
692
- MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES );
703
+ if (unlikely (ctrl1 & NEWDAT_SET )) {
704
+ cc770_rx (dev , mo , ctrl1 );
705
+ cc770_tx (dev , mo );
706
+ return ;
707
+ }
693
708
694
- stats -> tx_packets ++ ;
709
+ can_put_echo_skb ( priv -> tx_skb , dev , 0 ) ;
695
710
can_get_echo_skb (dev , 0 );
711
+
712
+ cf = (struct can_frame * )priv -> tx_skb -> data ;
713
+ stats -> tx_bytes += cf -> can_dlc ;
714
+ stats -> tx_packets ++ ;
715
+
716
+ priv -> tx_skb = NULL ;
717
+
696
718
netif_wake_queue (dev );
697
719
}
698
720
@@ -804,6 +826,7 @@ struct net_device *alloc_cc770dev(int sizeof_priv)
804
826
priv -> can .do_set_bittiming = cc770_set_bittiming ;
805
827
priv -> can .do_set_mode = cc770_set_mode ;
806
828
priv -> can .ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES ;
829
+ priv -> tx_skb = NULL ;
807
830
808
831
memcpy (priv -> obj_flags , cc770_obj_flags , sizeof (cc770_obj_flags ));
809
832
0 commit comments