提交 82f19183 编写于 作者: D David S. Miller

Merge tag 'linux-can-fixes-for-3.14-20140303' of git://gitorious.org/linux-can/linux-can

linux-can-fixes-for-3.14-20140303

Marc Kleine-Budde says:

====================
this is a pull request of 8 patches. Oliver Hartkopp contributes a patch which
removes the CAN FD compatibility for CAN 2.0 sockets, as it turns out that this
compatibility has some conceptual cornercases. The remaining 7 patches are by
me, they address a problem in the flexcan driver. When shutting down the
interface ("ifconfig can0 down") under heavy network load the whole system will
hang. This series reworks the actual sequence in close() and the transition
from and to the low power modes of the CAN controller.
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
...@@ -554,12 +554,6 @@ solution for a couple of reasons: ...@@ -554,12 +554,6 @@ solution for a couple of reasons:
not specified in the struct can_frame and therefore it is only valid in not specified in the struct can_frame and therefore it is only valid in
CANFD_MTU sized CAN FD frames. CANFD_MTU sized CAN FD frames.
As long as the payload length is <=8 the received CAN frames from CAN FD
capable CAN devices can be received and read by legacy sockets too. When
user-generated CAN FD frames have a payload length <=8 these can be send
by legacy CAN network interfaces too. Sending CAN FD frames with payload
length > 8 to a legacy CAN network interface returns an -EMSGSIZE error.
Implementation hint for new CAN applications: Implementation hint for new CAN applications:
To build a CAN FD aware application use struct canfd_frame as basic CAN To build a CAN FD aware application use struct canfd_frame as basic CAN
......
...@@ -144,6 +144,8 @@ ...@@ -144,6 +144,8 @@
#define FLEXCAN_MB_CODE_MASK (0xf0ffffff) #define FLEXCAN_MB_CODE_MASK (0xf0ffffff)
#define FLEXCAN_TIMEOUT_US (50)
/* /*
* FLEXCAN hardware feature flags * FLEXCAN hardware feature flags
* *
...@@ -262,6 +264,22 @@ static inline void flexcan_write(u32 val, void __iomem *addr) ...@@ -262,6 +264,22 @@ static inline void flexcan_write(u32 val, void __iomem *addr)
} }
#endif #endif
static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv)
{
if (!priv->reg_xceiver)
return 0;
return regulator_enable(priv->reg_xceiver);
}
static inline int flexcan_transceiver_disable(const struct flexcan_priv *priv)
{
if (!priv->reg_xceiver)
return 0;
return regulator_disable(priv->reg_xceiver);
}
static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv, static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
u32 reg_esr) u32 reg_esr)
{ {
...@@ -269,26 +287,95 @@ static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv, ...@@ -269,26 +287,95 @@ static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
(reg_esr & FLEXCAN_ESR_ERR_BUS); (reg_esr & FLEXCAN_ESR_ERR_BUS);
} }
static inline void flexcan_chip_enable(struct flexcan_priv *priv) static int flexcan_chip_enable(struct flexcan_priv *priv)
{ {
struct flexcan_regs __iomem *regs = priv->base; struct flexcan_regs __iomem *regs = priv->base;
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
u32 reg; u32 reg;
reg = flexcan_read(&regs->mcr); reg = flexcan_read(&regs->mcr);
reg &= ~FLEXCAN_MCR_MDIS; reg &= ~FLEXCAN_MCR_MDIS;
flexcan_write(reg, &regs->mcr); flexcan_write(reg, &regs->mcr);
udelay(10); while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
usleep_range(10, 20);
if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK)
return -ETIMEDOUT;
return 0;
} }
static inline void flexcan_chip_disable(struct flexcan_priv *priv) static int flexcan_chip_disable(struct flexcan_priv *priv)
{ {
struct flexcan_regs __iomem *regs = priv->base; struct flexcan_regs __iomem *regs = priv->base;
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
u32 reg; u32 reg;
reg = flexcan_read(&regs->mcr); reg = flexcan_read(&regs->mcr);
reg |= FLEXCAN_MCR_MDIS; reg |= FLEXCAN_MCR_MDIS;
flexcan_write(reg, &regs->mcr); flexcan_write(reg, &regs->mcr);
while (timeout-- && !(flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
usleep_range(10, 20);
if (!(flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
return -ETIMEDOUT;
return 0;
}
static int flexcan_chip_freeze(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->base;
unsigned int timeout = 1000 * 1000 * 10 / priv->can.bittiming.bitrate;
u32 reg;
reg = flexcan_read(&regs->mcr);
reg |= FLEXCAN_MCR_HALT;
flexcan_write(reg, &regs->mcr);
while (timeout-- && !(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
usleep_range(100, 200);
if (!(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
return -ETIMEDOUT;
return 0;
}
static int flexcan_chip_unfreeze(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->base;
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
u32 reg;
reg = flexcan_read(&regs->mcr);
reg &= ~FLEXCAN_MCR_HALT;
flexcan_write(reg, &regs->mcr);
while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
usleep_range(10, 20);
if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK)
return -ETIMEDOUT;
return 0;
}
static int flexcan_chip_softreset(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->base;
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
flexcan_write(FLEXCAN_MCR_SOFTRST, &regs->mcr);
while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_SOFTRST))
usleep_range(10, 20);
if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_SOFTRST)
return -ETIMEDOUT;
return 0;
} }
static int flexcan_get_berr_counter(const struct net_device *dev, static int flexcan_get_berr_counter(const struct net_device *dev,
...@@ -709,19 +796,14 @@ static int flexcan_chip_start(struct net_device *dev) ...@@ -709,19 +796,14 @@ static int flexcan_chip_start(struct net_device *dev)
u32 reg_mcr, reg_ctrl; u32 reg_mcr, reg_ctrl;
/* enable module */ /* enable module */
flexcan_chip_enable(priv); err = flexcan_chip_enable(priv);
if (err)
return err;
/* soft reset */ /* soft reset */
flexcan_write(FLEXCAN_MCR_SOFTRST, &regs->mcr); err = flexcan_chip_softreset(priv);
udelay(10); if (err)
goto out_chip_disable;
reg_mcr = flexcan_read(&regs->mcr);
if (reg_mcr & FLEXCAN_MCR_SOFTRST) {
netdev_err(dev, "Failed to softreset can module (mcr=0x%08x)\n",
reg_mcr);
err = -ENODEV;
goto out;
}
flexcan_set_bittiming(dev); flexcan_set_bittiming(dev);
...@@ -788,16 +870,14 @@ static int flexcan_chip_start(struct net_device *dev) ...@@ -788,16 +870,14 @@ static int flexcan_chip_start(struct net_device *dev)
if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES)
flexcan_write(0x0, &regs->rxfgmask); flexcan_write(0x0, &regs->rxfgmask);
if (priv->reg_xceiver) { err = flexcan_transceiver_enable(priv);
err = regulator_enable(priv->reg_xceiver); if (err)
if (err) goto out_chip_disable;
goto out;
}
/* synchronize with the can bus */ /* synchronize with the can bus */
reg_mcr = flexcan_read(&regs->mcr); err = flexcan_chip_unfreeze(priv);
reg_mcr &= ~FLEXCAN_MCR_HALT; if (err)
flexcan_write(reg_mcr, &regs->mcr); goto out_transceiver_disable;
priv->can.state = CAN_STATE_ERROR_ACTIVE; priv->can.state = CAN_STATE_ERROR_ACTIVE;
...@@ -810,7 +890,9 @@ static int flexcan_chip_start(struct net_device *dev) ...@@ -810,7 +890,9 @@ static int flexcan_chip_start(struct net_device *dev)
return 0; return 0;
out: out_transceiver_disable:
flexcan_transceiver_disable(priv);
out_chip_disable:
flexcan_chip_disable(priv); flexcan_chip_disable(priv);
return err; return err;
} }
...@@ -825,18 +907,17 @@ static void flexcan_chip_stop(struct net_device *dev) ...@@ -825,18 +907,17 @@ static void flexcan_chip_stop(struct net_device *dev)
{ {
struct flexcan_priv *priv = netdev_priv(dev); struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->base; struct flexcan_regs __iomem *regs = priv->base;
u32 reg;
/* freeze + disable module */
flexcan_chip_freeze(priv);
flexcan_chip_disable(priv);
/* Disable all interrupts */ /* Disable all interrupts */
flexcan_write(0, &regs->imask1); flexcan_write(0, &regs->imask1);
flexcan_write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
&regs->ctrl);
/* Disable + halt module */ flexcan_transceiver_disable(priv);
reg = flexcan_read(&regs->mcr);
reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT;
flexcan_write(reg, &regs->mcr);
if (priv->reg_xceiver)
regulator_disable(priv->reg_xceiver);
priv->can.state = CAN_STATE_STOPPED; priv->can.state = CAN_STATE_STOPPED;
return; return;
...@@ -866,7 +947,7 @@ static int flexcan_open(struct net_device *dev) ...@@ -866,7 +947,7 @@ static int flexcan_open(struct net_device *dev)
/* start chip and queuing */ /* start chip and queuing */
err = flexcan_chip_start(dev); err = flexcan_chip_start(dev);
if (err) if (err)
goto out_close; goto out_free_irq;
can_led_event(dev, CAN_LED_EVENT_OPEN); can_led_event(dev, CAN_LED_EVENT_OPEN);
...@@ -875,6 +956,8 @@ static int flexcan_open(struct net_device *dev) ...@@ -875,6 +956,8 @@ static int flexcan_open(struct net_device *dev)
return 0; return 0;
out_free_irq:
free_irq(dev->irq, dev);
out_close: out_close:
close_candev(dev); close_candev(dev);
out_disable_per: out_disable_per:
...@@ -945,12 +1028,16 @@ static int register_flexcandev(struct net_device *dev) ...@@ -945,12 +1028,16 @@ static int register_flexcandev(struct net_device *dev)
goto out_disable_ipg; goto out_disable_ipg;
/* select "bus clock", chip must be disabled */ /* select "bus clock", chip must be disabled */
flexcan_chip_disable(priv); err = flexcan_chip_disable(priv);
if (err)
goto out_disable_per;
reg = flexcan_read(&regs->ctrl); reg = flexcan_read(&regs->ctrl);
reg |= FLEXCAN_CTRL_CLK_SRC; reg |= FLEXCAN_CTRL_CLK_SRC;
flexcan_write(reg, &regs->ctrl); flexcan_write(reg, &regs->ctrl);
flexcan_chip_enable(priv); err = flexcan_chip_enable(priv);
if (err)
goto out_chip_disable;
/* set freeze, halt and activate FIFO, restrict register access */ /* set freeze, halt and activate FIFO, restrict register access */
reg = flexcan_read(&regs->mcr); reg = flexcan_read(&regs->mcr);
...@@ -967,14 +1054,15 @@ static int register_flexcandev(struct net_device *dev) ...@@ -967,14 +1054,15 @@ static int register_flexcandev(struct net_device *dev)
if (!(reg & FLEXCAN_MCR_FEN)) { if (!(reg & FLEXCAN_MCR_FEN)) {
netdev_err(dev, "Could not enable RX FIFO, unsupported core\n"); netdev_err(dev, "Could not enable RX FIFO, unsupported core\n");
err = -ENODEV; err = -ENODEV;
goto out_disable_per; goto out_chip_disable;
} }
err = register_candev(dev); err = register_candev(dev);
out_disable_per:
/* disable core and turn off clocks */ /* disable core and turn off clocks */
out_chip_disable:
flexcan_chip_disable(priv); flexcan_chip_disable(priv);
out_disable_per:
clk_disable_unprepare(priv->clk_per); clk_disable_unprepare(priv->clk_per);
out_disable_ipg: out_disable_ipg:
clk_disable_unprepare(priv->clk_ipg); clk_disable_unprepare(priv->clk_ipg);
...@@ -1104,9 +1192,10 @@ static int flexcan_probe(struct platform_device *pdev) ...@@ -1104,9 +1192,10 @@ static int flexcan_probe(struct platform_device *pdev)
static int flexcan_remove(struct platform_device *pdev) static int flexcan_remove(struct platform_device *pdev)
{ {
struct net_device *dev = platform_get_drvdata(pdev); struct net_device *dev = platform_get_drvdata(pdev);
struct flexcan_priv *priv = netdev_priv(dev);
unregister_flexcandev(dev); unregister_flexcandev(dev);
netif_napi_del(&priv->napi);
free_candev(dev); free_candev(dev);
return 0; return 0;
...@@ -1117,8 +1206,11 @@ static int flexcan_suspend(struct device *device) ...@@ -1117,8 +1206,11 @@ static int flexcan_suspend(struct device *device)
{ {
struct net_device *dev = dev_get_drvdata(device); struct net_device *dev = dev_get_drvdata(device);
struct flexcan_priv *priv = netdev_priv(dev); struct flexcan_priv *priv = netdev_priv(dev);
int err;
flexcan_chip_disable(priv); err = flexcan_chip_disable(priv);
if (err)
return err;
if (netif_running(dev)) { if (netif_running(dev)) {
netif_stop_queue(dev); netif_stop_queue(dev);
...@@ -1139,9 +1231,7 @@ static int flexcan_resume(struct device *device) ...@@ -1139,9 +1231,7 @@ static int flexcan_resume(struct device *device)
netif_device_attach(dev); netif_device_attach(dev);
netif_start_queue(dev); netif_start_queue(dev);
} }
flexcan_chip_enable(priv); return flexcan_chip_enable(priv);
return 0;
} }
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
......
...@@ -121,13 +121,9 @@ static void raw_rcv(struct sk_buff *oskb, void *data) ...@@ -121,13 +121,9 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
if (!ro->recv_own_msgs && oskb->sk == sk) if (!ro->recv_own_msgs && oskb->sk == sk)
return; return;
/* do not pass frames with DLC > 8 to a legacy socket */ /* do not pass non-CAN2.0 frames to a legacy socket */
if (!ro->fd_frames) { if (!ro->fd_frames && oskb->len != CAN_MTU)
struct canfd_frame *cfd = (struct canfd_frame *)oskb->data; return;
if (unlikely(cfd->len > CAN_MAX_DLEN))
return;
}
/* clone the given skb to be able to enqueue it into the rcv queue */ /* clone the given skb to be able to enqueue it into the rcv queue */
skb = skb_clone(oskb, GFP_ATOMIC); skb = skb_clone(oskb, GFP_ATOMIC);
...@@ -738,9 +734,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -738,9 +734,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size, int flags) struct msghdr *msg, size_t size, int flags)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct raw_sock *ro = raw_sk(sk);
struct sk_buff *skb; struct sk_buff *skb;
int rxmtu;
int err = 0; int err = 0;
int noblock; int noblock;
...@@ -751,20 +745,10 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -751,20 +745,10 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
if (!skb) if (!skb)
return err; return err;
/* if (size < skb->len)
* when serving a legacy socket the DLC <= 8 is already checked inside
* raw_rcv(). Now check if we need to pass a canfd_frame to a legacy
* socket and cut the possible CANFD_MTU/CAN_MTU length to CAN_MTU
*/
if (!ro->fd_frames)
rxmtu = CAN_MTU;
else
rxmtu = skb->len;
if (size < rxmtu)
msg->msg_flags |= MSG_TRUNC; msg->msg_flags |= MSG_TRUNC;
else else
size = rxmtu; size = skb->len;
err = memcpy_toiovec(msg->msg_iov, skb->data, size); err = memcpy_toiovec(msg->msg_iov, skb->data, size);
if (err < 0) { if (err < 0) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册