aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2014-04-11 04:13:15 -0400
committerMarc Kleine-Budde <mkl@pengutronix.de>2014-04-24 16:08:57 -0400
commitfa39b54ccf28a0a85256f04881297cd75b8ef204 (patch)
tree6e98a32816a07adfa875f9a9acb8d241221b5634
parentb9011aae9389c8853c1ccc2236f500a6e648c525 (diff)
can: c_can: Get rid of pointless interrupts
The driver handles pointlessly TWO interrupts per packet. The reason is that it enables the status interrupt which fires for each rx and tx packet and it enables the per message object interrupts as well. The status interrupt merily acks or in case of D_CAN ignores the TX/RX state and then the message object interrupt fires. The message objects interrupts are only useful if all message objects have hardware filters activated. But we don't have that and its not simple to implement in that driver without rewriting it completely. So we can ditch the message object interrupts and handle the RX/TX right away from the status interrupt. Instead of TWO we handle ONE. Note: We must keep the TXIE/RXIE bits in the message buffers because the status interrupt alone is not reliable enough in corner cases. If we ever have the need for HW filtering, then this code needs a complete overhaul and we can think about it then. For now we prefer a lower interrupt load. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Alexander Stein <alexander.stein@systec-electronic.com> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
-rw-r--r--drivers/net/can/c_can/c_can.c122
-rw-r--r--drivers/net/can/c_can/c_can.h3
2 files changed, 48 insertions, 77 deletions
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
index b381f7bfb895..09cb68772737 100644
--- a/drivers/net/can/c_can/c_can.c
+++ b/drivers/net/can/c_can/c_can.c
@@ -593,7 +593,7 @@ static void c_can_configure_msg_objects(struct net_device *dev)
593 /* setup receive message objects */ 593 /* setup receive message objects */
594 for (i = C_CAN_MSG_OBJ_RX_FIRST; i < C_CAN_MSG_OBJ_RX_LAST; i++) 594 for (i = C_CAN_MSG_OBJ_RX_FIRST; i < C_CAN_MSG_OBJ_RX_LAST; i++)
595 c_can_setup_receive_object(dev, IF_RX, i, 0, 0, 595 c_can_setup_receive_object(dev, IF_RX, i, 0, 0,
596 (IF_MCONT_RXIE | IF_MCONT_UMASK) & ~IF_MCONT_EOB); 596 IF_MCONT_RXIE | IF_MCONT_UMASK);
597 597
598 c_can_setup_receive_object(dev, IF_RX, C_CAN_MSG_OBJ_RX_LAST, 0, 0, 598 c_can_setup_receive_object(dev, IF_RX, C_CAN_MSG_OBJ_RX_LAST, 0, 0,
599 IF_MCONT_EOB | IF_MCONT_RXIE | IF_MCONT_UMASK); 599 IF_MCONT_EOB | IF_MCONT_RXIE | IF_MCONT_UMASK);
@@ -649,8 +649,9 @@ static int c_can_start(struct net_device *dev)
649 649
650 priv->can.state = CAN_STATE_ERROR_ACTIVE; 650 priv->can.state = CAN_STATE_ERROR_ACTIVE;
651 651
652 /* reset tx helper pointers */ 652 /* reset tx helper pointers and the rx mask */
653 priv->tx_next = priv->tx_echo = 0; 653 priv->tx_next = priv->tx_echo = 0;
654 priv->rxmasked = 0;
654 655
655 return 0; 656 return 0;
656} 657}
@@ -823,9 +824,13 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
823 /* read the data from the message object */ 824 /* read the data from the message object */
824 c_can_read_msg_object(dev, IF_RX, ctrl); 825 c_can_read_msg_object(dev, IF_RX, ctrl);
825 826
826 if (obj == C_CAN_MSG_RX_LOW_LAST) 827 if (obj < C_CAN_MSG_RX_LOW_LAST)
828 priv->rxmasked |= BIT(obj - 1);
829 else if (obj == C_CAN_MSG_RX_LOW_LAST) {
830 priv->rxmasked = 0;
827 /* activate all lower message objects */ 831 /* activate all lower message objects */
828 c_can_activate_all_lower_rx_msg_obj(dev, IF_RX); 832 c_can_activate_all_lower_rx_msg_obj(dev, IF_RX);
833 }
829 834
830 pkts++; 835 pkts++;
831 quota--; 836 quota--;
@@ -870,7 +875,8 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota)
870 875
871 while (quota > 0) { 876 while (quota > 0) {
872 if (!pend) { 877 if (!pend) {
873 pend = priv->read_reg(priv, C_CAN_INTPND1_REG); 878 pend = priv->read_reg(priv, C_CAN_NEWDAT1_REG);
879 pend &= ~priv->rxmasked;
874 if (!pend) 880 if (!pend)
875 break; 881 break;
876 /* 882 /*
@@ -1040,10 +1046,6 @@ static int c_can_handle_bus_err(struct net_device *dev,
1040 break; 1046 break;
1041 } 1047 }
1042 1048
1043 /* set a `lec` value so that we can check for updates later */
1044 if (priv->type != BOSCH_D_CAN)
1045 priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
1046
1047 stats->rx_packets++; 1049 stats->rx_packets++;
1048 stats->rx_bytes += cf->can_dlc; 1050 stats->rx_bytes += cf->can_dlc;
1049 netif_receive_skb(skb); 1051 netif_receive_skb(skb);
@@ -1052,79 +1054,50 @@ static int c_can_handle_bus_err(struct net_device *dev,
1052 1054
1053static int c_can_poll(struct napi_struct *napi, int quota) 1055static int c_can_poll(struct napi_struct *napi, int quota)
1054{ 1056{
1055 u16 irqstatus;
1056 int work_done = 0;
1057 struct net_device *dev = napi->dev; 1057 struct net_device *dev = napi->dev;
1058 struct c_can_priv *priv = netdev_priv(dev); 1058 struct c_can_priv *priv = netdev_priv(dev);
1059 u16 curr, last = priv->last_status;
1060 int work_done = 0;
1059 1061
1060 irqstatus = priv->irqstatus; 1062 priv->last_status = curr = priv->read_reg(priv, C_CAN_STS_REG);
1061 if (!irqstatus) 1063 /* Ack status on C_CAN. D_CAN is self clearing */
1062 goto end; 1064 if (priv->type != BOSCH_D_CAN)
1065 priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
1063 1066
1064 /* status events have the highest priority */ 1067 /* handle state changes */
1065 if (irqstatus == STATUS_INTERRUPT) { 1068 if ((curr & STATUS_EWARN) && (!(last & STATUS_EWARN))) {
1066 priv->current_status = priv->read_reg(priv, 1069 netdev_dbg(dev, "entered error warning state\n");
1067 C_CAN_STS_REG); 1070 work_done += c_can_handle_state_change(dev, C_CAN_ERROR_WARNING);
1068 1071 }
1069 /* handle Tx/Rx events */
1070 if (priv->current_status & STATUS_TXOK &&
1071 priv->type != BOSCH_D_CAN)
1072 priv->write_reg(priv, C_CAN_STS_REG,
1073 priv->current_status & ~STATUS_TXOK);
1074
1075 if (priv->current_status & STATUS_RXOK &&
1076 priv->type != BOSCH_D_CAN)
1077 priv->write_reg(priv, C_CAN_STS_REG,
1078 priv->current_status & ~STATUS_RXOK);
1079
1080 /* handle state changes */
1081 if ((priv->current_status & STATUS_EWARN) &&
1082 (!(priv->last_status & STATUS_EWARN))) {
1083 netdev_dbg(dev, "entered error warning state\n");
1084 work_done += c_can_handle_state_change(dev,
1085 C_CAN_ERROR_WARNING);
1086 }
1087 if ((priv->current_status & STATUS_EPASS) &&
1088 (!(priv->last_status & STATUS_EPASS))) {
1089 netdev_dbg(dev, "entered error passive state\n");
1090 work_done += c_can_handle_state_change(dev,
1091 C_CAN_ERROR_PASSIVE);
1092 }
1093 if ((priv->current_status & STATUS_BOFF) &&
1094 (!(priv->last_status & STATUS_BOFF))) {
1095 netdev_dbg(dev, "entered bus off state\n");
1096 work_done += c_can_handle_state_change(dev,
1097 C_CAN_BUS_OFF);
1098 goto end;
1099 }
1100 1072
1101 /* handle bus recovery events */ 1073 if ((curr & STATUS_EPASS) && (!(last & STATUS_EPASS))) {
1102 if ((!(priv->current_status & STATUS_BOFF)) && 1074 netdev_dbg(dev, "entered error passive state\n");
1103 (priv->last_status & STATUS_BOFF)) { 1075 work_done += c_can_handle_state_change(dev, C_CAN_ERROR_PASSIVE);
1104 netdev_dbg(dev, "left bus off state\n"); 1076 }
1105 priv->can.state = CAN_STATE_ERROR_ACTIVE;
1106 }
1107 if ((!(priv->current_status & STATUS_EPASS)) &&
1108 (priv->last_status & STATUS_EPASS)) {
1109 netdev_dbg(dev, "left error passive state\n");
1110 priv->can.state = CAN_STATE_ERROR_ACTIVE;
1111 }
1112 1077
1113 priv->last_status = priv->current_status; 1078 if ((curr & STATUS_BOFF) && (!(last & STATUS_BOFF))) {
1114 1079 netdev_dbg(dev, "entered bus off state\n");
1115 /* handle lec errors on the bus */ 1080 work_done += c_can_handle_state_change(dev, C_CAN_BUS_OFF);
1116 work_done += c_can_handle_bus_err(dev, 1081 goto end;
1117 priv->current_status & LEC_MASK);
1118 } else if ((irqstatus >= C_CAN_MSG_OBJ_RX_FIRST) &&
1119 (irqstatus <= C_CAN_MSG_OBJ_RX_LAST)) {
1120 /* handle events corresponding to receive message objects */
1121 work_done += c_can_do_rx_poll(dev, (quota - work_done));
1122 } else if ((irqstatus >= C_CAN_MSG_OBJ_TX_FIRST) &&
1123 (irqstatus <= C_CAN_MSG_OBJ_TX_LAST)) {
1124 /* handle events corresponding to transmit message objects */
1125 c_can_do_tx(dev);
1126 } 1082 }
1127 1083
1084 /* handle bus recovery events */
1085 if ((!(curr & STATUS_BOFF)) && (last & STATUS_BOFF)) {
1086 netdev_dbg(dev, "left bus off state\n");
1087 priv->can.state = CAN_STATE_ERROR_ACTIVE;
1088 }
1089 if ((!(curr & STATUS_EPASS)) && (last & STATUS_EPASS)) {
1090 netdev_dbg(dev, "left error passive state\n");
1091 priv->can.state = CAN_STATE_ERROR_ACTIVE;
1092 }
1093
1094 /* handle lec errors on the bus */
1095 work_done += c_can_handle_bus_err(dev, curr & LEC_MASK);
1096
1097 /* Handle Tx/Rx events. We do this unconditionally */
1098 work_done += c_can_do_rx_poll(dev, (quota - work_done));
1099 c_can_do_tx(dev);
1100
1128end: 1101end:
1129 if (work_done < quota) { 1102 if (work_done < quota) {
1130 napi_complete(napi); 1103 napi_complete(napi);
@@ -1141,8 +1114,7 @@ static irqreturn_t c_can_isr(int irq, void *dev_id)
1141 struct net_device *dev = (struct net_device *)dev_id; 1114 struct net_device *dev = (struct net_device *)dev_id;
1142 struct c_can_priv *priv = netdev_priv(dev); 1115 struct c_can_priv *priv = netdev_priv(dev);
1143 1116
1144 priv->irqstatus = priv->read_reg(priv, C_CAN_INT_REG); 1117 if (!priv->read_reg(priv, C_CAN_INT_REG))
1145 if (!priv->irqstatus)
1146 return IRQ_NONE; 1118 return IRQ_NONE;
1147 1119
1148 /* disable all interrupts and schedule the NAPI */ 1120 /* disable all interrupts and schedule the NAPI */
diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h
index faa8404162b3..cd91960ce92c 100644
--- a/drivers/net/can/c_can/c_can.h
+++ b/drivers/net/can/c_can/c_can.h
@@ -185,7 +185,6 @@ struct c_can_priv {
185 struct device *device; 185 struct device *device;
186 spinlock_t xmit_lock; 186 spinlock_t xmit_lock;
187 int tx_object; 187 int tx_object;
188 int current_status;
189 int last_status; 188 int last_status;
190 u16 (*read_reg) (struct c_can_priv *priv, enum reg index); 189 u16 (*read_reg) (struct c_can_priv *priv, enum reg index);
191 void (*write_reg) (struct c_can_priv *priv, enum reg index, u16 val); 190 void (*write_reg) (struct c_can_priv *priv, enum reg index, u16 val);
@@ -195,11 +194,11 @@ struct c_can_priv {
195 unsigned int tx_next; 194 unsigned int tx_next;
196 unsigned int tx_echo; 195 unsigned int tx_echo;
197 void *priv; /* for board-specific data */ 196 void *priv; /* for board-specific data */
198 u16 irqstatus;
199 enum c_can_dev_id type; 197 enum c_can_dev_id type;
200 u32 __iomem *raminit_ctrlreg; 198 u32 __iomem *raminit_ctrlreg;
201 unsigned int instance; 199 unsigned int instance;
202 void (*raminit) (const struct c_can_priv *priv, bool enable); 200 void (*raminit) (const struct c_can_priv *priv, bool enable);
201 u32 rxmasked;
203 u32 dlc[C_CAN_MSG_OBJ_TX_NUM]; 202 u32 dlc[C_CAN_MSG_OBJ_TX_NUM];
204}; 203};
205 204