aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/can/c_can/c_can.c52
1 files changed, 50 insertions, 2 deletions
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
index 38f9adaf15ac..cef9967eff93 100644
--- a/drivers/net/can/c_can/c_can.c
+++ b/drivers/net/can/c_can/c_can.c
@@ -817,6 +817,38 @@ static void c_can_do_tx(struct net_device *dev)
817} 817}
818 818
819/* 819/*
820 * If we have a gap in the pending bits, that means we either
821 * raced with the hardware or failed to readout all upper
822 * objects in the last run due to quota limit.
823 */
824static u32 c_can_adjust_pending(u32 pend)
825{
826 u32 weight, lasts;
827
828 if (pend == RECEIVE_OBJECT_BITS)
829 return pend;
830
831 /*
832 * If the last set bit is larger than the number of pending
833 * bits we have a gap.
834 */
835 weight = hweight32(pend);
836 lasts = fls(pend);
837
838 /* If the bits are linear, nothing to do */
839 if (lasts == weight)
840 return pend;
841
842 /*
843 * Find the first set bit after the gap. We walk backwards
844 * from the last set bit.
845 */
846 for (lasts--; pend & (1 << (lasts - 1)); lasts--);
847
848 return pend & ~((1 << lasts) - 1);
849}
850
851/*
820 * theory of operation: 852 * theory of operation:
821 * 853 *
822 * c_can core saves a received CAN message into the first free message 854 * c_can core saves a received CAN message into the first free message
@@ -843,7 +875,7 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota)
843 u32 num_rx_pkts = 0; 875 u32 num_rx_pkts = 0;
844 unsigned int msg_obj, msg_ctrl_save; 876 unsigned int msg_obj, msg_ctrl_save;
845 struct c_can_priv *priv = netdev_priv(dev); 877 struct c_can_priv *priv = netdev_priv(dev);
846 u16 val; 878 u32 val, pend = 0;
847 879
848 /* 880 /*
849 * It is faster to read only one 16bit register. This is only possible 881 * It is faster to read only one 16bit register. This is only possible
@@ -852,7 +884,23 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota)
852 BUILD_BUG_ON_MSG(C_CAN_MSG_OBJ_RX_LAST > 16, 884 BUILD_BUG_ON_MSG(C_CAN_MSG_OBJ_RX_LAST > 16,
853 "Implementation does not support more message objects than 16"); 885 "Implementation does not support more message objects than 16");
854 886
855 while (quota > 0 && (val = priv->read_reg(priv, C_CAN_INTPND1_REG))) { 887 while (quota > 0) {
888
889 if (!pend) {
890 pend = priv->read_reg(priv, C_CAN_INTPND1_REG);
891 if (!pend)
892 return num_rx_pkts;
893 /*
894 * If the pending field has a gap, handle the
895 * bits above the gap first.
896 */
897 val = c_can_adjust_pending(pend);
898 } else {
899 val = pend;
900 }
901 /* Remove the bits from pend */
902 pend &= ~val;
903
856 while ((msg_obj = ffs(val)) && quota > 0) { 904 while ((msg_obj = ffs(val)) && quota > 0) {
857 val &= ~BIT(msg_obj - 1); 905 val &= ~BIT(msg_obj - 1);
858 906