Commit 4ea41f82 authored by David S. Miller's avatar David S. Miller

Merge tag 'linux-can-fixes-for-4.16-20180314' of...

Merge tag 'linux-can-fixes-for-4.16-20180314' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can

Marc Kleine-Budde says:

====================
pull-request: can 2018-03-14

this is a pull request of two patches for net/master.

Both patches are by Andri Yngvason and fix problems in the cc770 driver,
that show up quite fast on RT systems, but also on non RT setups.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ea91df6d 74620123
...@@ -390,37 +390,23 @@ static int cc770_get_berr_counter(const struct net_device *dev, ...@@ -390,37 +390,23 @@ static int cc770_get_berr_counter(const struct net_device *dev,
return 0; return 0;
} }
static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev) static void cc770_tx(struct net_device *dev, int mo)
{ {
struct cc770_priv *priv = netdev_priv(dev); struct cc770_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats; struct can_frame *cf = (struct can_frame *)priv->tx_skb->data;
struct can_frame *cf = (struct can_frame *)skb->data;
unsigned int mo = obj2msgobj(CC770_OBJ_TX);
u8 dlc, rtr; u8 dlc, rtr;
u32 id; u32 id;
int i; int i;
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
if ((cc770_read_reg(priv,
msgobj[mo].ctrl1) & TXRQST_UNC) == TXRQST_SET) {
netdev_err(dev, "TX register is still occupied!\n");
return NETDEV_TX_BUSY;
}
netif_stop_queue(dev);
dlc = cf->can_dlc; dlc = cf->can_dlc;
id = cf->can_id; id = cf->can_id;
if (cf->can_id & CAN_RTR_FLAG) rtr = cf->can_id & CAN_RTR_FLAG ? 0 : MSGCFG_DIR;
rtr = 0;
else cc770_write_reg(priv, msgobj[mo].ctrl0,
rtr = MSGCFG_DIR; MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES);
cc770_write_reg(priv, msgobj[mo].ctrl1, cc770_write_reg(priv, msgobj[mo].ctrl1,
RMTPND_RES | TXRQST_RES | CPUUPD_SET | NEWDAT_RES); RMTPND_RES | TXRQST_RES | CPUUPD_SET | NEWDAT_RES);
cc770_write_reg(priv, msgobj[mo].ctrl0,
MSGVAL_SET | TXIE_SET | RXIE_RES | INTPND_RES);
if (id & CAN_EFF_FLAG) { if (id & CAN_EFF_FLAG) {
id &= CAN_EFF_MASK; id &= CAN_EFF_MASK;
cc770_write_reg(priv, msgobj[mo].config, cc770_write_reg(priv, msgobj[mo].config,
...@@ -439,22 +425,30 @@ static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -439,22 +425,30 @@ static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev)
for (i = 0; i < dlc; i++) for (i = 0; i < dlc; i++)
cc770_write_reg(priv, msgobj[mo].data[i], cf->data[i]); cc770_write_reg(priv, msgobj[mo].data[i], cf->data[i]);
/* Store echo skb before starting the transfer */
can_put_echo_skb(skb, dev, 0);
cc770_write_reg(priv, msgobj[mo].ctrl1, cc770_write_reg(priv, msgobj[mo].ctrl1,
RMTPND_RES | TXRQST_SET | CPUUPD_RES | NEWDAT_UNC); RMTPND_UNC | TXRQST_SET | CPUUPD_RES | NEWDAT_UNC);
cc770_write_reg(priv, msgobj[mo].ctrl0,
MSGVAL_SET | TXIE_SET | RXIE_SET | INTPND_UNC);
}
stats->tx_bytes += dlc; static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct cc770_priv *priv = netdev_priv(dev);
unsigned int mo = obj2msgobj(CC770_OBJ_TX);
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
/* netif_stop_queue(dev);
* HM: We had some cases of repeated IRQs so make sure the
* INT is acknowledged I know it's already further up, but if ((cc770_read_reg(priv,
* doing again fixed the issue msgobj[mo].ctrl1) & TXRQST_UNC) == TXRQST_SET) {
*/ netdev_err(dev, "TX register is still occupied!\n");
cc770_write_reg(priv, msgobj[mo].ctrl0, return NETDEV_TX_BUSY;
MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES); }
priv->tx_skb = skb;
cc770_tx(dev, mo);
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
...@@ -680,19 +674,47 @@ static void cc770_tx_interrupt(struct net_device *dev, unsigned int o) ...@@ -680,19 +674,47 @@ static void cc770_tx_interrupt(struct net_device *dev, unsigned int o)
struct cc770_priv *priv = netdev_priv(dev); struct cc770_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats; struct net_device_stats *stats = &dev->stats;
unsigned int mo = obj2msgobj(o); unsigned int mo = obj2msgobj(o);
struct can_frame *cf;
u8 ctrl1;
ctrl1 = cc770_read_reg(priv, msgobj[mo].ctrl1);
/* Nothing more to send, switch off interrupts */
cc770_write_reg(priv, msgobj[mo].ctrl0, cc770_write_reg(priv, msgobj[mo].ctrl0,
MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES); MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES);
/* cc770_write_reg(priv, msgobj[mo].ctrl1,
* We had some cases of repeated IRQ so make sure the RMTPND_RES | TXRQST_RES | MSGLST_RES | NEWDAT_RES);
* INT is acknowledged
if (unlikely(!priv->tx_skb)) {
netdev_err(dev, "missing tx skb in tx interrupt\n");
return;
}
if (unlikely(ctrl1 & MSGLST_SET)) {
stats->rx_over_errors++;
stats->rx_errors++;
}
/* When the CC770 is sending an RTR message and it receives a regular
* message that matches the id of the RTR message, it will overwrite the
* outgoing message in the TX register. When this happens we must
* process the received message and try to transmit the outgoing skb
* again.
*/ */
cc770_write_reg(priv, msgobj[mo].ctrl0, if (unlikely(ctrl1 & NEWDAT_SET)) {
MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES); cc770_rx(dev, mo, ctrl1);
cc770_tx(dev, mo);
return;
}
stats->tx_packets++; can_put_echo_skb(priv->tx_skb, dev, 0);
can_get_echo_skb(dev, 0); can_get_echo_skb(dev, 0);
cf = (struct can_frame *)priv->tx_skb->data;
stats->tx_bytes += cf->can_dlc;
stats->tx_packets++;
priv->tx_skb = NULL;
netif_wake_queue(dev); netif_wake_queue(dev);
} }
...@@ -804,6 +826,7 @@ struct net_device *alloc_cc770dev(int sizeof_priv) ...@@ -804,6 +826,7 @@ struct net_device *alloc_cc770dev(int sizeof_priv)
priv->can.do_set_bittiming = cc770_set_bittiming; priv->can.do_set_bittiming = cc770_set_bittiming;
priv->can.do_set_mode = cc770_set_mode; priv->can.do_set_mode = cc770_set_mode;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
priv->tx_skb = NULL;
memcpy(priv->obj_flags, cc770_obj_flags, sizeof(cc770_obj_flags)); memcpy(priv->obj_flags, cc770_obj_flags, sizeof(cc770_obj_flags));
......
...@@ -193,6 +193,8 @@ struct cc770_priv { ...@@ -193,6 +193,8 @@ struct cc770_priv {
u8 cpu_interface; /* CPU interface register */ u8 cpu_interface; /* CPU interface register */
u8 clkout; /* Clock out register */ u8 clkout; /* Clock out register */
u8 bus_config; /* Bus conffiguration register */ u8 bus_config; /* Bus conffiguration register */
struct sk_buff *tx_skb;
}; };
struct net_device *alloc_cc770dev(int sizeof_priv); struct net_device *alloc_cc770dev(int sizeof_priv);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment