diff options
| author | Stefan Agner <stefan@agner.ch> | 2014-07-15 08:56:20 -0400 |
|---|---|---|
| committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2014-08-17 19:03:39 -0400 |
| commit | ec56acfef2af184ca485ffeba16adbd56c110c94 (patch) | |
| tree | 3c7509c81a1ae6854a437a7d98f0df313e1e0565 | |
| parent | 4ade6feb52262eae0c40d6714e3446bfa4d19a5f (diff) | |
can: flexcan: flexcan_get_berr_counter(): switch on clocks before accessing ecr register
The funcion flexcan_get_berr_counter() may be called from userspace even if the
interface is down, this the clocks are disabled. This patch switches on the
clocks before accessing the ecr register.
Reported-by: Ashutosh Singh <ashuleapyear@gmail.com>
Signed-off-by: Stefan Agner <stefan@agner.ch>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
| -rw-r--r-- | drivers/net/can/flexcan.c | 30 |
1 files changed, 27 insertions, 3 deletions
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index f425ec2c7839..6bfe24aefea0 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c | |||
| @@ -378,8 +378,9 @@ static int flexcan_chip_softreset(struct flexcan_priv *priv) | |||
| 378 | return 0; | 378 | return 0; |
| 379 | } | 379 | } |
| 380 | 380 | ||
| 381 | static int flexcan_get_berr_counter(const struct net_device *dev, | 381 | |
| 382 | struct can_berr_counter *bec) | 382 | static int __flexcan_get_berr_counter(const struct net_device *dev, |
| 383 | struct can_berr_counter *bec) | ||
| 383 | { | 384 | { |
| 384 | const struct flexcan_priv *priv = netdev_priv(dev); | 385 | const struct flexcan_priv *priv = netdev_priv(dev); |
| 385 | struct flexcan_regs __iomem *regs = priv->base; | 386 | struct flexcan_regs __iomem *regs = priv->base; |
| @@ -391,6 +392,29 @@ static int flexcan_get_berr_counter(const struct net_device *dev, | |||
| 391 | return 0; | 392 | return 0; |
| 392 | } | 393 | } |
| 393 | 394 | ||
| 395 | static int flexcan_get_berr_counter(const struct net_device *dev, | ||
| 396 | struct can_berr_counter *bec) | ||
| 397 | { | ||
| 398 | const struct flexcan_priv *priv = netdev_priv(dev); | ||
| 399 | int err; | ||
| 400 | |||
| 401 | err = clk_prepare_enable(priv->clk_ipg); | ||
| 402 | if (err) | ||
| 403 | return err; | ||
| 404 | |||
| 405 | err = clk_prepare_enable(priv->clk_per); | ||
| 406 | if (err) | ||
| 407 | goto out_disable_ipg; | ||
| 408 | |||
| 409 | err = __flexcan_get_berr_counter(dev, bec); | ||
| 410 | |||
| 411 | clk_disable_unprepare(priv->clk_per); | ||
| 412 | out_disable_ipg: | ||
| 413 | clk_disable_unprepare(priv->clk_ipg); | ||
| 414 | |||
| 415 | return err; | ||
| 416 | } | ||
| 417 | |||
| 394 | static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev) | 418 | static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev) |
| 395 | { | 419 | { |
| 396 | const struct flexcan_priv *priv = netdev_priv(dev); | 420 | const struct flexcan_priv *priv = netdev_priv(dev); |
| @@ -503,7 +527,7 @@ static void do_state(struct net_device *dev, | |||
| 503 | struct flexcan_priv *priv = netdev_priv(dev); | 527 | struct flexcan_priv *priv = netdev_priv(dev); |
| 504 | struct can_berr_counter bec; | 528 | struct can_berr_counter bec; |
| 505 | 529 | ||
| 506 | flexcan_get_berr_counter(dev, &bec); | 530 | __flexcan_get_berr_counter(dev, &bec); |
| 507 | 531 | ||
| 508 | switch (priv->can.state) { | 532 | switch (priv->can.state) { |
| 509 | case CAN_STATE_ERROR_ACTIVE: | 533 | case CAN_STATE_ERROR_ACTIVE: |
