diff options
author | David S. Miller <davem@davemloft.net> | 2018-03-14 13:50:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-03-14 13:50:47 -0400 |
commit | 4ea41f829a69828565b75515a091b394d5dc5116 (patch) | |
tree | 0e408fb22ba5389b2e655d1200023d4031222478 | |
parent | ea91df6d8a55836c7401eb6d5d4d828b659d8d67 (diff) | |
parent | 746201235b3f876792099079f4c6fea941d76183 (diff) |
Merge tag 'linux-can-fixes-for-4.16-20180314' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can
Marc Kleine-Budde says:
====================
pull-request: can 2018-03-14
this is a pull request of two patches for net/master.
Both patches are by Andri Yngvason and fix problems in the cc770 driver,
that show up quite fast on RT systems, but also on non RT setups.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/can/cc770/cc770.c | 103 | ||||
-rw-r--r-- | drivers/net/can/cc770/cc770.h | 2 |
2 files changed, 65 insertions, 40 deletions
diff --git a/drivers/net/can/cc770/cc770.c b/drivers/net/can/cc770/cc770.c index 1e37313054f3..2743d82d4424 100644 --- a/drivers/net/can/cc770/cc770.c +++ b/drivers/net/can/cc770/cc770.c | |||
@@ -390,37 +390,23 @@ static int cc770_get_berr_counter(const struct net_device *dev, | |||
390 | return 0; | 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 | struct cc770_priv *priv = netdev_priv(dev); | 395 | struct cc770_priv *priv = netdev_priv(dev); |
396 | struct net_device_stats *stats = &dev->stats; | 396 | struct can_frame *cf = (struct can_frame *)priv->tx_skb->data; |
397 | struct can_frame *cf = (struct can_frame *)skb->data; | ||
398 | unsigned int mo = obj2msgobj(CC770_OBJ_TX); | ||
399 | u8 dlc, rtr; | 397 | u8 dlc, rtr; |
400 | u32 id; | 398 | u32 id; |
401 | int i; | 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 | dlc = cf->can_dlc; | 401 | dlc = cf->can_dlc; |
415 | id = cf->can_id; | 402 | id = cf->can_id; |
416 | if (cf->can_id & CAN_RTR_FLAG) | 403 | rtr = cf->can_id & CAN_RTR_FLAG ? 0 : MSGCFG_DIR; |
417 | rtr = 0; | 404 | |
418 | else | 405 | cc770_write_reg(priv, msgobj[mo].ctrl0, |
419 | rtr = MSGCFG_DIR; | 406 | MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES); |
420 | cc770_write_reg(priv, msgobj[mo].ctrl1, | 407 | cc770_write_reg(priv, msgobj[mo].ctrl1, |
421 | RMTPND_RES | TXRQST_RES | CPUUPD_SET | NEWDAT_RES); | 408 | RMTPND_RES | TXRQST_RES | CPUUPD_SET | NEWDAT_RES); |
422 | cc770_write_reg(priv, msgobj[mo].ctrl0, | 409 | |
423 | MSGVAL_SET | TXIE_SET | RXIE_RES | INTPND_RES); | ||
424 | if (id & CAN_EFF_FLAG) { | 410 | if (id & CAN_EFF_FLAG) { |
425 | id &= CAN_EFF_MASK; | 411 | id &= CAN_EFF_MASK; |
426 | cc770_write_reg(priv, msgobj[mo].config, | 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 | for (i = 0; i < dlc; i++) | 425 | for (i = 0; i < dlc; i++) |
440 | cc770_write_reg(priv, msgobj[mo].data[i], cf->data[i]); | 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 | cc770_write_reg(priv, msgobj[mo].ctrl1, | 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 | /* | 442 | netif_stop_queue(dev); |
452 | * HM: We had some cases of repeated IRQs so make sure the | 443 | |
453 | * INT is acknowledged I know it's already further up, but | 444 | if ((cc770_read_reg(priv, |
454 | * doing again fixed the issue | 445 | msgobj[mo].ctrl1) & TXRQST_UNC) == TXRQST_SET) { |
455 | */ | 446 | netdev_err(dev, "TX register is still occupied!\n"); |
456 | cc770_write_reg(priv, msgobj[mo].ctrl0, | 447 | return NETDEV_TX_BUSY; |
457 | MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES); | 448 | } |
449 | |||
450 | priv->tx_skb = skb; | ||
451 | cc770_tx(dev, mo); | ||
458 | 452 | ||
459 | return NETDEV_TX_OK; | 453 | return NETDEV_TX_OK; |
460 | } | 454 | } |
@@ -680,19 +674,47 @@ static void cc770_tx_interrupt(struct net_device *dev, unsigned int o) | |||
680 | struct cc770_priv *priv = netdev_priv(dev); | 674 | struct cc770_priv *priv = netdev_priv(dev); |
681 | struct net_device_stats *stats = &dev->stats; | 675 | struct net_device_stats *stats = &dev->stats; |
682 | unsigned int mo = obj2msgobj(o); | 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 | cc770_write_reg(priv, msgobj[mo].ctrl0, | 682 | cc770_write_reg(priv, msgobj[mo].ctrl0, |
686 | MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES); | 683 | MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES); |
687 | /* | 684 | cc770_write_reg(priv, msgobj[mo].ctrl1, |
688 | * We had some cases of repeated IRQ so make sure the | 685 | RMTPND_RES | TXRQST_RES | MSGLST_RES | NEWDAT_RES); |
689 | * INT is acknowledged | 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, | 703 | if (unlikely(ctrl1 & NEWDAT_SET)) { |
692 | MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES); | 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 | can_get_echo_skb(dev, 0); | 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 | netif_wake_queue(dev); | 718 | netif_wake_queue(dev); |
697 | } | 719 | } |
698 | 720 | ||
@@ -804,6 +826,7 @@ struct net_device *alloc_cc770dev(int sizeof_priv) | |||
804 | priv->can.do_set_bittiming = cc770_set_bittiming; | 826 | priv->can.do_set_bittiming = cc770_set_bittiming; |
805 | priv->can.do_set_mode = cc770_set_mode; | 827 | priv->can.do_set_mode = cc770_set_mode; |
806 | priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; | 828 | priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; |
829 | priv->tx_skb = NULL; | ||
807 | 830 | ||
808 | memcpy(priv->obj_flags, cc770_obj_flags, sizeof(cc770_obj_flags)); | 831 | memcpy(priv->obj_flags, cc770_obj_flags, sizeof(cc770_obj_flags)); |
809 | 832 | ||
diff --git a/drivers/net/can/cc770/cc770.h b/drivers/net/can/cc770/cc770.h index a1739db98d91..95752e1d1283 100644 --- a/drivers/net/can/cc770/cc770.h +++ b/drivers/net/can/cc770/cc770.h | |||
@@ -193,6 +193,8 @@ struct cc770_priv { | |||
193 | u8 cpu_interface; /* CPU interface register */ | 193 | u8 cpu_interface; /* CPU interface register */ |
194 | u8 clkout; /* Clock out register */ | 194 | u8 clkout; /* Clock out register */ |
195 | u8 bus_config; /* Bus conffiguration register */ | 195 | u8 bus_config; /* Bus conffiguration register */ |
196 | |||
197 | struct sk_buff *tx_skb; | ||
196 | }; | 198 | }; |
197 | 199 | ||
198 | struct net_device *alloc_cc770dev(int sizeof_priv); | 200 | struct net_device *alloc_cc770dev(int sizeof_priv); |