aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2014-04-11 04:13:10 -0400
committerMarc Kleine-Budde <mkl@pengutronix.de>2014-04-24 16:08:55 -0400
commitbed11db3d4095e5f818f5e8bf7f43ef2beb36d4e (patch)
tree71b380c8e8ef583fccf8217787d905cedb0b0e38
parent129eef2184218f4603f406945552ff4e58b05cf1 (diff)
can: c_can: Fix startup logic
c_can_start() enables interrupts way too early. The first enabling happens when setting the control mode in c_can_chip_config() and then again at the end of the function. But that happens before napi_enable() and that means that an interrupt which comes in will disable interrupts again and call napi_schedule, which ignores the request and the later napi_enable() is not making thinks work either. So the interface is up with all device interrupts disabled. Move the device interrupt after napi_enable() and add it to the other callsites of c_can_start() in c_can_set_mode() and c_can_power_up() 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.c35
1 files changed, 17 insertions, 18 deletions
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
index a5c8dcfa8357..b1629a47c03b 100644
--- a/drivers/net/can/c_can/c_can.c
+++ b/drivers/net/can/c_can/c_can.c
@@ -612,30 +612,22 @@ static int c_can_chip_config(struct net_device *dev)
612 struct c_can_priv *priv = netdev_priv(dev); 612 struct c_can_priv *priv = netdev_priv(dev);
613 613
614 /* enable automatic retransmission */ 614 /* enable automatic retransmission */
615 priv->write_reg(priv, C_CAN_CTRL_REG, 615 priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_ENABLE_AR);
616 CONTROL_ENABLE_AR);
617 616
618 if ((priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) && 617 if ((priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) &&
619 (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)) { 618 (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)) {
620 /* loopback + silent mode : useful for hot self-test */ 619 /* loopback + silent mode : useful for hot self-test */
621 priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE | 620 priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST);
622 CONTROL_SIE | CONTROL_IE | CONTROL_TEST); 621 priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK | TEST_SILENT);
623 priv->write_reg(priv, C_CAN_TEST_REG,
624 TEST_LBACK | TEST_SILENT);
625 } else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { 622 } else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
626 /* loopback mode : useful for self-test function */ 623 /* loopback mode : useful for self-test function */
627 priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE | 624 priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST);
628 CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
629 priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK); 625 priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK);
630 } else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) { 626 } else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
631 /* silent mode : bus-monitoring mode */ 627 /* silent mode : bus-monitoring mode */
632 priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE | 628 priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST);
633 CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
634 priv->write_reg(priv, C_CAN_TEST_REG, TEST_SILENT); 629 priv->write_reg(priv, C_CAN_TEST_REG, TEST_SILENT);
635 } else 630 }
636 /* normal mode*/
637 priv->write_reg(priv, C_CAN_CTRL_REG,
638 CONTROL_EIE | CONTROL_SIE | CONTROL_IE);
639 631
640 /* configure message objects */ 632 /* configure message objects */
641 c_can_configure_msg_objects(dev); 633 c_can_configure_msg_objects(dev);
@@ -662,9 +654,6 @@ static int c_can_start(struct net_device *dev)
662 /* reset tx helper pointers */ 654 /* reset tx helper pointers */
663 priv->tx_next = priv->tx_echo = 0; 655 priv->tx_next = priv->tx_echo = 0;
664 656
665 /* enable status change, error and module interrupts */
666 c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
667
668 return 0; 657 return 0;
669} 658}
670 659
@@ -681,6 +670,7 @@ static void c_can_stop(struct net_device *dev)
681 670
682static int c_can_set_mode(struct net_device *dev, enum can_mode mode) 671static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
683{ 672{
673 struct c_can_priv *priv = netdev_priv(dev);
684 int err; 674 int err;
685 675
686 switch (mode) { 676 switch (mode) {
@@ -689,6 +679,8 @@ static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
689 if (err) 679 if (err)
690 return err; 680 return err;
691 netif_wake_queue(dev); 681 netif_wake_queue(dev);
682 /* enable status change, error and module interrupts */
683 c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
692 break; 684 break;
693 default: 685 default:
694 return -EOPNOTSUPP; 686 return -EOPNOTSUPP;
@@ -1184,6 +1176,8 @@ static int c_can_open(struct net_device *dev)
1184 can_led_event(dev, CAN_LED_EVENT_OPEN); 1176 can_led_event(dev, CAN_LED_EVENT_OPEN);
1185 1177
1186 napi_enable(&priv->napi); 1178 napi_enable(&priv->napi);
1179 /* enable status change, error and module interrupts */
1180 c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
1187 netif_start_queue(dev); 1181 netif_start_queue(dev);
1188 1182
1189 return 0; 1183 return 0;
@@ -1281,6 +1275,7 @@ int c_can_power_up(struct net_device *dev)
1281 u32 val; 1275 u32 val;
1282 unsigned long time_out; 1276 unsigned long time_out;
1283 struct c_can_priv *priv = netdev_priv(dev); 1277 struct c_can_priv *priv = netdev_priv(dev);
1278 int ret;
1284 1279
1285 if (!(dev->flags & IFF_UP)) 1280 if (!(dev->flags & IFF_UP))
1286 return 0; 1281 return 0;
@@ -1307,7 +1302,11 @@ int c_can_power_up(struct net_device *dev)
1307 if (time_after(jiffies, time_out)) 1302 if (time_after(jiffies, time_out))
1308 return -ETIMEDOUT; 1303 return -ETIMEDOUT;
1309 1304
1310 return c_can_start(dev); 1305 ret = c_can_start(dev);
1306 if (!ret)
1307 c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
1308
1309 return ret;
1311} 1310}
1312EXPORT_SYMBOL_GPL(c_can_power_up); 1311EXPORT_SYMBOL_GPL(c_can_power_up);
1313#endif 1312#endif