diff options
| -rw-r--r-- | drivers/net/can/c_can/c_can.c | 107 |
1 files changed, 56 insertions, 51 deletions
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index 1fe79ce50c5a..bd7234eb42f4 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c | |||
| @@ -849,6 +849,52 @@ static u32 c_can_adjust_pending(u32 pend) | |||
| 849 | return pend & ~((1 << lasts) - 1); | 849 | return pend & ~((1 << lasts) - 1); |
| 850 | } | 850 | } |
| 851 | 851 | ||
| 852 | static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv, | ||
| 853 | u32 pend, int quota) | ||
| 854 | { | ||
| 855 | u32 pkts = 0, ctrl, obj; | ||
| 856 | |||
| 857 | while ((obj = ffs(pend)) && quota > 0) { | ||
| 858 | pend &= ~BIT(obj - 1); | ||
| 859 | |||
| 860 | c_can_object_get(dev, IF_RX, obj, IF_COMM_ALL & ~IF_COMM_TXRQST); | ||
| 861 | ctrl = priv->read_reg(priv, C_CAN_IFACE(MSGCTRL_REG, IF_RX)); | ||
| 862 | |||
| 863 | if (ctrl & IF_MCONT_MSGLST) { | ||
| 864 | int n = c_can_handle_lost_msg_obj(dev, IF_RX, obj, ctrl); | ||
| 865 | |||
| 866 | pkts += n; | ||
| 867 | quota -= n; | ||
| 868 | continue; | ||
| 869 | } | ||
| 870 | |||
| 871 | /* | ||
| 872 | * This really should not happen, but this covers some | ||
| 873 | * odd HW behaviour. Do not remove that unless you | ||
| 874 | * want to brick your machine. | ||
| 875 | */ | ||
| 876 | if (!(ctrl & IF_MCONT_NEWDAT)) | ||
| 877 | continue; | ||
| 878 | |||
| 879 | /* read the data from the message object */ | ||
| 880 | c_can_read_msg_object(dev, IF_RX, ctrl); | ||
| 881 | |||
| 882 | if (obj < C_CAN_MSG_RX_LOW_LAST) | ||
| 883 | c_can_mark_rx_msg_obj(dev, IF_RX, ctrl, obj); | ||
| 884 | else if (obj > C_CAN_MSG_RX_LOW_LAST) | ||
| 885 | /* activate this msg obj */ | ||
| 886 | c_can_activate_rx_msg_obj(dev, IF_RX, ctrl, obj); | ||
| 887 | else if (obj == C_CAN_MSG_RX_LOW_LAST) | ||
| 888 | /* activate all lower message objects */ | ||
| 889 | c_can_activate_all_lower_rx_msg_obj(dev, IF_RX, ctrl); | ||
| 890 | |||
| 891 | pkts++; | ||
| 892 | quota--; | ||
| 893 | } | ||
| 894 | |||
| 895 | return pkts; | ||
| 896 | } | ||
| 897 | |||
| 852 | /* | 898 | /* |
| 853 | * theory of operation: | 899 | * theory of operation: |
| 854 | * | 900 | * |
| @@ -873,10 +919,8 @@ static u32 c_can_adjust_pending(u32 pend) | |||
| 873 | */ | 919 | */ |
| 874 | static int c_can_do_rx_poll(struct net_device *dev, int quota) | 920 | static int c_can_do_rx_poll(struct net_device *dev, int quota) |
| 875 | { | 921 | { |
| 876 | u32 num_rx_pkts = 0; | ||
| 877 | unsigned int msg_obj, msg_ctrl_save; | ||
| 878 | struct c_can_priv *priv = netdev_priv(dev); | 922 | struct c_can_priv *priv = netdev_priv(dev); |
| 879 | u32 val, pend = 0; | 923 | u32 pkts = 0, pend = 0, toread, n; |
| 880 | 924 | ||
| 881 | /* | 925 | /* |
| 882 | * It is faster to read only one 16bit register. This is only possible | 926 | * It is faster to read only one 16bit register. This is only possible |
| @@ -886,65 +930,26 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota) | |||
| 886 | "Implementation does not support more message objects than 16"); | 930 | "Implementation does not support more message objects than 16"); |
| 887 | 931 | ||
| 888 | while (quota > 0) { | 932 | while (quota > 0) { |
| 889 | |||
| 890 | if (!pend) { | 933 | if (!pend) { |
| 891 | pend = priv->read_reg(priv, C_CAN_INTPND1_REG); | 934 | pend = priv->read_reg(priv, C_CAN_INTPND1_REG); |
| 892 | if (!pend) | 935 | if (!pend) |
| 893 | return num_rx_pkts; | 936 | break; |
| 894 | /* | 937 | /* |
| 895 | * If the pending field has a gap, handle the | 938 | * If the pending field has a gap, handle the |
| 896 | * bits above the gap first. | 939 | * bits above the gap first. |
| 897 | */ | 940 | */ |
| 898 | val = c_can_adjust_pending(pend); | 941 | toread = c_can_adjust_pending(pend); |
| 899 | } else { | 942 | } else { |
| 900 | val = pend; | 943 | toread = pend; |
| 901 | } | 944 | } |
| 902 | /* Remove the bits from pend */ | 945 | /* Remove the bits from pend */ |
| 903 | pend &= ~val; | 946 | pend &= ~toread; |
| 904 | 947 | /* Read the objects */ | |
| 905 | while ((msg_obj = ffs(val)) && quota > 0) { | 948 | n = c_can_read_objects(dev, priv, toread, quota); |
| 906 | val &= ~BIT(msg_obj - 1); | 949 | pkts += n; |
| 907 | 950 | quota -= n; | |
| 908 | c_can_object_get(dev, IF_RX, msg_obj, IF_COMM_ALL & | ||
| 909 | ~IF_COMM_TXRQST); | ||
| 910 | msg_ctrl_save = priv->read_reg(priv, | ||
| 911 | C_CAN_IFACE(MSGCTRL_REG, IF_RX)); | ||
| 912 | |||
| 913 | if (msg_ctrl_save & IF_MCONT_MSGLST) { | ||
| 914 | int n; | ||
| 915 | |||
| 916 | n = c_can_handle_lost_msg_obj(dev, IF_RX, | ||
| 917 | msg_obj, | ||
| 918 | msg_ctrl_save); | ||
| 919 | num_rx_pkts += n; | ||
| 920 | quota -=n; | ||
| 921 | continue; | ||
| 922 | } | ||
| 923 | |||
| 924 | if (!(msg_ctrl_save & IF_MCONT_NEWDAT)) | ||
| 925 | continue; | ||
| 926 | |||
| 927 | /* read the data from the message object */ | ||
| 928 | c_can_read_msg_object(dev, IF_RX, msg_ctrl_save); | ||
| 929 | |||
| 930 | if (msg_obj < C_CAN_MSG_RX_LOW_LAST) | ||
| 931 | c_can_mark_rx_msg_obj(dev, IF_RX, | ||
| 932 | msg_ctrl_save, msg_obj); | ||
| 933 | else if (msg_obj > C_CAN_MSG_RX_LOW_LAST) | ||
| 934 | /* activate this msg obj */ | ||
| 935 | c_can_activate_rx_msg_obj(dev, IF_RX, | ||
| 936 | msg_ctrl_save, msg_obj); | ||
| 937 | else if (msg_obj == C_CAN_MSG_RX_LOW_LAST) | ||
| 938 | /* activate all lower message objects */ | ||
| 939 | c_can_activate_all_lower_rx_msg_obj(dev, | ||
| 940 | IF_RX, msg_ctrl_save); | ||
| 941 | |||
| 942 | num_rx_pkts++; | ||
| 943 | quota--; | ||
| 944 | } | ||
| 945 | } | 951 | } |
| 946 | 952 | return pkts; | |
| 947 | return num_rx_pkts; | ||
| 948 | } | 953 | } |
| 949 | 954 | ||
| 950 | static inline int c_can_has_and_handle_berr(struct c_can_priv *priv) | 955 | static inline int c_can_has_and_handle_berr(struct c_can_priv *priv) |
