linux-can-fixes-for-3.15-20140401
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iEYEABECAAYFAlM6jfsACgkQjTAFq1RaXHOVTwCeOyOYOJ+Ze2x33WydGcGsvX8a QPoAoJVAcekmL5MVbcMTTvc8QL1AebAm =4aEp -----END PGP SIGNATURE----- Merge tag 'linux-can-fixes-for-3.15-20140401' of git://gitorious.org/linux-can/linux-can linux-can-fixes-for-3.15-20140401 Marc Kleine-Budde says: ==================== this is a pull request of 16 patches for the 3.15 release cycle. Bjorn Van Tilt contributes a patch which fixes a memory leak in usb_8dev's usb_8dev_start_xmit()s error path. A patch by Robert Schwebel fixes a typo in the can documentation. The remaining patches all target the c_can driver. Two of them are by me; they add a missing netif_napi_del() and return value checking. Thomas Gleixner contributes 12 patches, which address several shortcomings in the driver like hardware initialisation, concurrency, message ordering and poor performance. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
f91ca783f1
|
@ -1017,7 +1017,7 @@ solution for a couple of reasons:
|
||||||
in case of a bus-off condition after the specified delay time
|
in case of a bus-off condition after the specified delay time
|
||||||
in milliseconds. By default it's off.
|
in milliseconds. By default it's off.
|
||||||
|
|
||||||
"bitrate 125000 sample_point 0.875"
|
"bitrate 125000 sample-point 0.875"
|
||||||
Shows the real bit-rate in bits/sec and the sample-point in the
|
Shows the real bit-rate in bits/sec and the sample-point in the
|
||||||
range 0.000..0.999. If the calculation of bit-timing parameters
|
range 0.000..0.999. If the calculation of bit-timing parameters
|
||||||
is enabled in the kernel (CONFIG_CAN_CALC_BITTIMING=y), the
|
is enabled in the kernel (CONFIG_CAN_CALC_BITTIMING=y), the
|
||||||
|
|
|
@ -114,6 +114,14 @@
|
||||||
IF_COMM_CONTROL | IF_COMM_TXRQST | \
|
IF_COMM_CONTROL | IF_COMM_TXRQST | \
|
||||||
IF_COMM_DATAA | IF_COMM_DATAB)
|
IF_COMM_DATAA | IF_COMM_DATAB)
|
||||||
|
|
||||||
|
/* For the low buffers we clear the interrupt bit, but keep newdat */
|
||||||
|
#define IF_COMM_RCV_LOW (IF_COMM_MASK | IF_COMM_ARB | \
|
||||||
|
IF_COMM_CONTROL | IF_COMM_CLR_INT_PND | \
|
||||||
|
IF_COMM_DATAA | IF_COMM_DATAB)
|
||||||
|
|
||||||
|
/* For the high buffers we clear the interrupt bit and newdat */
|
||||||
|
#define IF_COMM_RCV_HIGH (IF_COMM_RCV_LOW | IF_COMM_TXRQST)
|
||||||
|
|
||||||
/* IFx arbitration */
|
/* IFx arbitration */
|
||||||
#define IF_ARB_MSGVAL BIT(15)
|
#define IF_ARB_MSGVAL BIT(15)
|
||||||
#define IF_ARB_MSGXTD BIT(14)
|
#define IF_ARB_MSGXTD BIT(14)
|
||||||
|
@ -122,7 +130,6 @@
|
||||||
/* IFx message control */
|
/* IFx message control */
|
||||||
#define IF_MCONT_NEWDAT BIT(15)
|
#define IF_MCONT_NEWDAT BIT(15)
|
||||||
#define IF_MCONT_MSGLST BIT(14)
|
#define IF_MCONT_MSGLST BIT(14)
|
||||||
#define IF_MCONT_CLR_MSGLST (0 << 14)
|
|
||||||
#define IF_MCONT_INTPND BIT(13)
|
#define IF_MCONT_INTPND BIT(13)
|
||||||
#define IF_MCONT_UMASK BIT(12)
|
#define IF_MCONT_UMASK BIT(12)
|
||||||
#define IF_MCONT_TXIE BIT(11)
|
#define IF_MCONT_TXIE BIT(11)
|
||||||
|
@ -133,31 +140,10 @@
|
||||||
#define IF_MCONT_DLC_MASK 0xf
|
#define IF_MCONT_DLC_MASK 0xf
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IFx register masks:
|
* Use IF1 for RX and IF2 for TX
|
||||||
* allow easy operation on 16-bit registers when the
|
|
||||||
* argument is 32-bit instead
|
|
||||||
*/
|
*/
|
||||||
#define IFX_WRITE_LOW_16BIT(x) ((x) & 0xFFFF)
|
#define IF_RX 0
|
||||||
#define IFX_WRITE_HIGH_16BIT(x) (((x) & 0xFFFF0000) >> 16)
|
#define IF_TX 1
|
||||||
|
|
||||||
/* message object split */
|
|
||||||
#define C_CAN_NO_OF_OBJECTS 32
|
|
||||||
#define C_CAN_MSG_OBJ_RX_NUM 16
|
|
||||||
#define C_CAN_MSG_OBJ_TX_NUM 16
|
|
||||||
|
|
||||||
#define C_CAN_MSG_OBJ_RX_FIRST 1
|
|
||||||
#define C_CAN_MSG_OBJ_RX_LAST (C_CAN_MSG_OBJ_RX_FIRST + \
|
|
||||||
C_CAN_MSG_OBJ_RX_NUM - 1)
|
|
||||||
|
|
||||||
#define C_CAN_MSG_OBJ_TX_FIRST (C_CAN_MSG_OBJ_RX_LAST + 1)
|
|
||||||
#define C_CAN_MSG_OBJ_TX_LAST (C_CAN_MSG_OBJ_TX_FIRST + \
|
|
||||||
C_CAN_MSG_OBJ_TX_NUM - 1)
|
|
||||||
|
|
||||||
#define C_CAN_MSG_OBJ_RX_SPLIT 9
|
|
||||||
#define C_CAN_MSG_RX_LOW_LAST (C_CAN_MSG_OBJ_RX_SPLIT - 1)
|
|
||||||
|
|
||||||
#define C_CAN_NEXT_MSG_OBJ_MASK (C_CAN_MSG_OBJ_TX_NUM - 1)
|
|
||||||
#define RECEIVE_OBJECT_BITS 0x0000ffff
|
|
||||||
|
|
||||||
/* status interrupt */
|
/* status interrupt */
|
||||||
#define STATUS_INTERRUPT 0x8000
|
#define STATUS_INTERRUPT 0x8000
|
||||||
|
@ -246,10 +232,9 @@ static inline int get_tx_next_msg_obj(const struct c_can_priv *priv)
|
||||||
C_CAN_MSG_OBJ_TX_FIRST;
|
C_CAN_MSG_OBJ_TX_FIRST;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int get_tx_echo_msg_obj(const struct c_can_priv *priv)
|
static inline int get_tx_echo_msg_obj(int txecho)
|
||||||
{
|
{
|
||||||
return (priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) +
|
return (txecho & C_CAN_NEXT_MSG_OBJ_MASK) + C_CAN_MSG_OBJ_TX_FIRST;
|
||||||
C_CAN_MSG_OBJ_TX_FIRST;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 c_can_read_reg32(struct c_can_priv *priv, enum reg index)
|
static u32 c_can_read_reg32(struct c_can_priv *priv, enum reg index)
|
||||||
|
@ -366,18 +351,6 @@ static void c_can_write_msg_object(struct net_device *dev,
|
||||||
c_can_object_put(dev, iface, objno, IF_COMM_ALL);
|
c_can_object_put(dev, iface, objno, IF_COMM_ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void c_can_mark_rx_msg_obj(struct net_device *dev,
|
|
||||||
int iface, int ctrl_mask,
|
|
||||||
int obj)
|
|
||||||
{
|
|
||||||
struct c_can_priv *priv = netdev_priv(dev);
|
|
||||||
|
|
||||||
priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
|
|
||||||
ctrl_mask & ~(IF_MCONT_MSGLST | IF_MCONT_INTPND));
|
|
||||||
c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device *dev,
|
static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device *dev,
|
||||||
int iface,
|
int iface,
|
||||||
int ctrl_mask)
|
int ctrl_mask)
|
||||||
|
@ -387,45 +360,27 @@ static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device *dev,
|
||||||
|
|
||||||
for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++) {
|
for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++) {
|
||||||
priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
|
priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
|
||||||
ctrl_mask & ~(IF_MCONT_MSGLST |
|
ctrl_mask & ~IF_MCONT_NEWDAT);
|
||||||
IF_MCONT_INTPND | IF_MCONT_NEWDAT));
|
|
||||||
c_can_object_put(dev, iface, i, IF_COMM_CONTROL);
|
c_can_object_put(dev, iface, i, IF_COMM_CONTROL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void c_can_activate_rx_msg_obj(struct net_device *dev,
|
static int c_can_handle_lost_msg_obj(struct net_device *dev,
|
||||||
int iface, int ctrl_mask,
|
int iface, int objno, u32 ctrl)
|
||||||
int obj)
|
|
||||||
{
|
{
|
||||||
struct c_can_priv *priv = netdev_priv(dev);
|
|
||||||
|
|
||||||
priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
|
|
||||||
ctrl_mask & ~(IF_MCONT_MSGLST |
|
|
||||||
IF_MCONT_INTPND | IF_MCONT_NEWDAT));
|
|
||||||
c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void c_can_handle_lost_msg_obj(struct net_device *dev,
|
|
||||||
int iface, int objno)
|
|
||||||
{
|
|
||||||
struct c_can_priv *priv = netdev_priv(dev);
|
|
||||||
struct net_device_stats *stats = &dev->stats;
|
struct net_device_stats *stats = &dev->stats;
|
||||||
struct sk_buff *skb;
|
struct c_can_priv *priv = netdev_priv(dev);
|
||||||
struct can_frame *frame;
|
struct can_frame *frame;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
netdev_err(dev, "msg lost in buffer %d\n", objno);
|
ctrl &= ~(IF_MCONT_MSGLST | IF_MCONT_INTPND | IF_MCONT_NEWDAT);
|
||||||
|
priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), ctrl);
|
||||||
c_can_object_get(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST);
|
c_can_object_put(dev, iface, objno, IF_COMM_CONTROL);
|
||||||
|
|
||||||
priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
|
|
||||||
IF_MCONT_CLR_MSGLST);
|
|
||||||
|
|
||||||
c_can_object_put(dev, 0, objno, IF_COMM_CONTROL);
|
|
||||||
|
|
||||||
/* create an error msg */
|
/* create an error msg */
|
||||||
skb = alloc_can_err_skb(dev, &frame);
|
skb = alloc_can_err_skb(dev, &frame);
|
||||||
if (unlikely(!skb))
|
if (unlikely(!skb))
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
frame->can_id |= CAN_ERR_CRTL;
|
frame->can_id |= CAN_ERR_CRTL;
|
||||||
frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
|
frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
|
||||||
|
@ -433,6 +388,7 @@ static void c_can_handle_lost_msg_obj(struct net_device *dev,
|
||||||
stats->rx_over_errors++;
|
stats->rx_over_errors++;
|
||||||
|
|
||||||
netif_receive_skb(skb);
|
netif_receive_skb(skb);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
|
static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
|
||||||
|
@ -477,9 +433,6 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
|
||||||
|
|
||||||
stats->rx_packets++;
|
stats->rx_packets++;
|
||||||
stats->rx_bytes += frame->can_dlc;
|
stats->rx_bytes += frame->can_dlc;
|
||||||
|
|
||||||
can_led_event(dev, CAN_LED_EVENT_RX);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -548,10 +501,12 @@ static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
|
||||||
if (can_dropped_invalid_skb(dev, skb))
|
if (can_dropped_invalid_skb(dev, skb))
|
||||||
return NETDEV_TX_OK;
|
return NETDEV_TX_OK;
|
||||||
|
|
||||||
|
spin_lock_bh(&priv->xmit_lock);
|
||||||
msg_obj_no = get_tx_next_msg_obj(priv);
|
msg_obj_no = get_tx_next_msg_obj(priv);
|
||||||
|
|
||||||
/* prepare message object for transmission */
|
/* prepare message object for transmission */
|
||||||
c_can_write_msg_object(dev, 0, frame, msg_obj_no);
|
c_can_write_msg_object(dev, IF_TX, frame, msg_obj_no);
|
||||||
|
priv->dlc[msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST] = frame->can_dlc;
|
||||||
can_put_echo_skb(skb, dev, msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
|
can_put_echo_skb(skb, dev, msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -562,10 +517,26 @@ static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
|
||||||
if (c_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) ||
|
if (c_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) ||
|
||||||
(priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) == 0)
|
(priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) == 0)
|
||||||
netif_stop_queue(dev);
|
netif_stop_queue(dev);
|
||||||
|
spin_unlock_bh(&priv->xmit_lock);
|
||||||
|
|
||||||
return NETDEV_TX_OK;
|
return NETDEV_TX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int c_can_wait_for_ctrl_init(struct net_device *dev,
|
||||||
|
struct c_can_priv *priv, u32 init)
|
||||||
|
{
|
||||||
|
int retry = 0;
|
||||||
|
|
||||||
|
while (init != (priv->read_reg(priv, C_CAN_CTRL_REG) & CONTROL_INIT)) {
|
||||||
|
udelay(10);
|
||||||
|
if (retry++ > 1000) {
|
||||||
|
netdev_err(dev, "CCTRL: set CONTROL_INIT failed\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int c_can_set_bittiming(struct net_device *dev)
|
static int c_can_set_bittiming(struct net_device *dev)
|
||||||
{
|
{
|
||||||
unsigned int reg_btr, reg_brpe, ctrl_save;
|
unsigned int reg_btr, reg_brpe, ctrl_save;
|
||||||
|
@ -573,6 +544,7 @@ static int c_can_set_bittiming(struct net_device *dev)
|
||||||
u32 ten_bit_brp;
|
u32 ten_bit_brp;
|
||||||
struct c_can_priv *priv = netdev_priv(dev);
|
struct c_can_priv *priv = netdev_priv(dev);
|
||||||
const struct can_bittiming *bt = &priv->can.bittiming;
|
const struct can_bittiming *bt = &priv->can.bittiming;
|
||||||
|
int res;
|
||||||
|
|
||||||
/* c_can provides a 6-bit brp and 4-bit brpe fields */
|
/* c_can provides a 6-bit brp and 4-bit brpe fields */
|
||||||
ten_bit_brp = bt->brp - 1;
|
ten_bit_brp = bt->brp - 1;
|
||||||
|
@ -590,13 +562,17 @@ static int c_can_set_bittiming(struct net_device *dev)
|
||||||
"setting BTR=%04x BRPE=%04x\n", reg_btr, reg_brpe);
|
"setting BTR=%04x BRPE=%04x\n", reg_btr, reg_brpe);
|
||||||
|
|
||||||
ctrl_save = priv->read_reg(priv, C_CAN_CTRL_REG);
|
ctrl_save = priv->read_reg(priv, C_CAN_CTRL_REG);
|
||||||
priv->write_reg(priv, C_CAN_CTRL_REG,
|
ctrl_save &= ~CONTROL_INIT;
|
||||||
ctrl_save | CONTROL_CCE | CONTROL_INIT);
|
priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_CCE | CONTROL_INIT);
|
||||||
|
res = c_can_wait_for_ctrl_init(dev, priv, CONTROL_INIT);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
|
||||||
priv->write_reg(priv, C_CAN_BTR_REG, reg_btr);
|
priv->write_reg(priv, C_CAN_BTR_REG, reg_btr);
|
||||||
priv->write_reg(priv, C_CAN_BRPEXT_REG, reg_brpe);
|
priv->write_reg(priv, C_CAN_BRPEXT_REG, reg_brpe);
|
||||||
priv->write_reg(priv, C_CAN_CTRL_REG, ctrl_save);
|
priv->write_reg(priv, C_CAN_CTRL_REG, ctrl_save);
|
||||||
|
|
||||||
return 0;
|
return c_can_wait_for_ctrl_init(dev, priv, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -614,14 +590,14 @@ static void c_can_configure_msg_objects(struct net_device *dev)
|
||||||
|
|
||||||
/* first invalidate all message objects */
|
/* first invalidate all message objects */
|
||||||
for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_NO_OF_OBJECTS; i++)
|
for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_NO_OF_OBJECTS; i++)
|
||||||
c_can_inval_msg_object(dev, 0, i);
|
c_can_inval_msg_object(dev, IF_RX, i);
|
||||||
|
|
||||||
/* setup receive message objects */
|
/* setup receive message objects */
|
||||||
for (i = C_CAN_MSG_OBJ_RX_FIRST; i < C_CAN_MSG_OBJ_RX_LAST; i++)
|
for (i = C_CAN_MSG_OBJ_RX_FIRST; i < C_CAN_MSG_OBJ_RX_LAST; i++)
|
||||||
c_can_setup_receive_object(dev, 0, i, 0, 0,
|
c_can_setup_receive_object(dev, IF_RX, i, 0, 0,
|
||||||
(IF_MCONT_RXIE | IF_MCONT_UMASK) & ~IF_MCONT_EOB);
|
(IF_MCONT_RXIE | IF_MCONT_UMASK) & ~IF_MCONT_EOB);
|
||||||
|
|
||||||
c_can_setup_receive_object(dev, 0, C_CAN_MSG_OBJ_RX_LAST, 0, 0,
|
c_can_setup_receive_object(dev, IF_RX, C_CAN_MSG_OBJ_RX_LAST, 0, 0,
|
||||||
IF_MCONT_EOB | IF_MCONT_RXIE | IF_MCONT_UMASK);
|
IF_MCONT_EOB | IF_MCONT_RXIE | IF_MCONT_UMASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -631,7 +607,7 @@ static void c_can_configure_msg_objects(struct net_device *dev)
|
||||||
* - set operating mode
|
* - set operating mode
|
||||||
* - configure message objects
|
* - configure message objects
|
||||||
*/
|
*/
|
||||||
static void c_can_chip_config(struct net_device *dev)
|
static int c_can_chip_config(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct c_can_priv *priv = netdev_priv(dev);
|
struct c_can_priv *priv = netdev_priv(dev);
|
||||||
|
|
||||||
|
@ -668,15 +644,18 @@ static void c_can_chip_config(struct net_device *dev)
|
||||||
priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
|
priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
|
||||||
|
|
||||||
/* set bittiming params */
|
/* set bittiming params */
|
||||||
c_can_set_bittiming(dev);
|
return c_can_set_bittiming(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void c_can_start(struct net_device *dev)
|
static int c_can_start(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct c_can_priv *priv = netdev_priv(dev);
|
struct c_can_priv *priv = netdev_priv(dev);
|
||||||
|
int err;
|
||||||
|
|
||||||
/* basic c_can configuration */
|
/* basic c_can configuration */
|
||||||
c_can_chip_config(dev);
|
err = c_can_chip_config(dev);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
priv->can.state = CAN_STATE_ERROR_ACTIVE;
|
priv->can.state = CAN_STATE_ERROR_ACTIVE;
|
||||||
|
|
||||||
|
@ -685,6 +664,8 @@ static void c_can_start(struct net_device *dev)
|
||||||
|
|
||||||
/* enable status change, error and module interrupts */
|
/* enable status change, error and module interrupts */
|
||||||
c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
|
c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void c_can_stop(struct net_device *dev)
|
static void c_can_stop(struct net_device *dev)
|
||||||
|
@ -700,9 +681,13 @@ static void c_can_stop(struct net_device *dev)
|
||||||
|
|
||||||
static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
|
static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
|
||||||
{
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case CAN_MODE_START:
|
case CAN_MODE_START:
|
||||||
c_can_start(dev);
|
err = c_can_start(dev);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
netif_wake_queue(dev);
|
netif_wake_queue(dev);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -740,8 +725,6 @@ static int c_can_get_berr_counter(const struct net_device *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* theory of operation:
|
|
||||||
*
|
|
||||||
* priv->tx_echo holds the number of the oldest can_frame put for
|
* priv->tx_echo holds the number of the oldest can_frame put for
|
||||||
* transmission into the hardware, but not yet ACKed by the CAN tx
|
* transmission into the hardware, but not yet ACKed by the CAN tx
|
||||||
* complete IRQ.
|
* complete IRQ.
|
||||||
|
@ -752,33 +735,113 @@ static int c_can_get_berr_counter(const struct net_device *dev,
|
||||||
*/
|
*/
|
||||||
static void c_can_do_tx(struct net_device *dev)
|
static void c_can_do_tx(struct net_device *dev)
|
||||||
{
|
{
|
||||||
u32 val;
|
|
||||||
u32 msg_obj_no;
|
|
||||||
struct c_can_priv *priv = netdev_priv(dev);
|
struct c_can_priv *priv = netdev_priv(dev);
|
||||||
struct net_device_stats *stats = &dev->stats;
|
struct net_device_stats *stats = &dev->stats;
|
||||||
|
u32 val, obj, pkts = 0, bytes = 0;
|
||||||
|
|
||||||
for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
|
spin_lock_bh(&priv->xmit_lock);
|
||||||
msg_obj_no = get_tx_echo_msg_obj(priv);
|
|
||||||
|
for (; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
|
||||||
|
obj = get_tx_echo_msg_obj(priv->tx_echo);
|
||||||
val = c_can_read_reg32(priv, C_CAN_TXRQST1_REG);
|
val = c_can_read_reg32(priv, C_CAN_TXRQST1_REG);
|
||||||
if (!(val & (1 << (msg_obj_no - 1)))) {
|
|
||||||
can_get_echo_skb(dev,
|
if (val & (1 << (obj - 1)))
|
||||||
msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
|
|
||||||
c_can_object_get(dev, 0, msg_obj_no, IF_COMM_ALL);
|
|
||||||
stats->tx_bytes += priv->read_reg(priv,
|
|
||||||
C_CAN_IFACE(MSGCTRL_REG, 0))
|
|
||||||
& IF_MCONT_DLC_MASK;
|
|
||||||
stats->tx_packets++;
|
|
||||||
can_led_event(dev, CAN_LED_EVENT_TX);
|
|
||||||
c_can_inval_msg_object(dev, 0, msg_obj_no);
|
|
||||||
} else {
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
can_get_echo_skb(dev, obj - C_CAN_MSG_OBJ_TX_FIRST);
|
||||||
|
bytes += priv->dlc[obj - C_CAN_MSG_OBJ_TX_FIRST];
|
||||||
|
pkts++;
|
||||||
|
c_can_inval_msg_object(dev, IF_TX, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* restart queue if wrap-up or if queue stalled on last pkt */
|
/* restart queue if wrap-up or if queue stalled on last pkt */
|
||||||
if (((priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) != 0) ||
|
if (((priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) != 0) ||
|
||||||
((priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) == 0))
|
((priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) == 0))
|
||||||
netif_wake_queue(dev);
|
netif_wake_queue(dev);
|
||||||
|
|
||||||
|
spin_unlock_bh(&priv->xmit_lock);
|
||||||
|
|
||||||
|
if (pkts) {
|
||||||
|
stats->tx_bytes += bytes;
|
||||||
|
stats->tx_packets += pkts;
|
||||||
|
can_led_event(dev, CAN_LED_EVENT_TX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have a gap in the pending bits, that means we either
|
||||||
|
* raced with the hardware or failed to readout all upper
|
||||||
|
* objects in the last run due to quota limit.
|
||||||
|
*/
|
||||||
|
static u32 c_can_adjust_pending(u32 pend)
|
||||||
|
{
|
||||||
|
u32 weight, lasts;
|
||||||
|
|
||||||
|
if (pend == RECEIVE_OBJECT_BITS)
|
||||||
|
return pend;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the last set bit is larger than the number of pending
|
||||||
|
* bits we have a gap.
|
||||||
|
*/
|
||||||
|
weight = hweight32(pend);
|
||||||
|
lasts = fls(pend);
|
||||||
|
|
||||||
|
/* If the bits are linear, nothing to do */
|
||||||
|
if (lasts == weight)
|
||||||
|
return pend;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the first set bit after the gap. We walk backwards
|
||||||
|
* from the last set bit.
|
||||||
|
*/
|
||||||
|
for (lasts--; pend & (1 << (lasts - 1)); lasts--);
|
||||||
|
|
||||||
|
return pend & ~((1 << lasts) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
|
||||||
|
u32 pend, int quota)
|
||||||
|
{
|
||||||
|
u32 pkts = 0, ctrl, obj, mcmd;
|
||||||
|
|
||||||
|
while ((obj = ffs(pend)) && quota > 0) {
|
||||||
|
pend &= ~BIT(obj - 1);
|
||||||
|
|
||||||
|
mcmd = obj < C_CAN_MSG_RX_LOW_LAST ?
|
||||||
|
IF_COMM_RCV_LOW : IF_COMM_RCV_HIGH;
|
||||||
|
|
||||||
|
c_can_object_get(dev, IF_RX, obj, mcmd);
|
||||||
|
ctrl = priv->read_reg(priv, C_CAN_IFACE(MSGCTRL_REG, IF_RX));
|
||||||
|
|
||||||
|
if (ctrl & IF_MCONT_MSGLST) {
|
||||||
|
int n = c_can_handle_lost_msg_obj(dev, IF_RX, obj, ctrl);
|
||||||
|
|
||||||
|
pkts += n;
|
||||||
|
quota -= n;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This really should not happen, but this covers some
|
||||||
|
* odd HW behaviour. Do not remove that unless you
|
||||||
|
* want to brick your machine.
|
||||||
|
*/
|
||||||
|
if (!(ctrl & IF_MCONT_NEWDAT))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* read the data from the message object */
|
||||||
|
c_can_read_msg_object(dev, IF_RX, ctrl);
|
||||||
|
|
||||||
|
if (obj == C_CAN_MSG_RX_LOW_LAST)
|
||||||
|
/* activate all lower message objects */
|
||||||
|
c_can_activate_all_lower_rx_msg_obj(dev, IF_RX, ctrl);
|
||||||
|
|
||||||
|
pkts++;
|
||||||
|
quota--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -805,10 +868,8 @@ static void c_can_do_tx(struct net_device *dev)
|
||||||
*/
|
*/
|
||||||
static int c_can_do_rx_poll(struct net_device *dev, int quota)
|
static int c_can_do_rx_poll(struct net_device *dev, int quota)
|
||||||
{
|
{
|
||||||
u32 num_rx_pkts = 0;
|
|
||||||
unsigned int msg_obj, msg_ctrl_save;
|
|
||||||
struct c_can_priv *priv = netdev_priv(dev);
|
struct c_can_priv *priv = netdev_priv(dev);
|
||||||
u16 val;
|
u32 pkts = 0, pend = 0, toread, n;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It is faster to read only one 16bit register. This is only possible
|
* It is faster to read only one 16bit register. This is only possible
|
||||||
|
@ -817,49 +878,31 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota)
|
||||||
BUILD_BUG_ON_MSG(C_CAN_MSG_OBJ_RX_LAST > 16,
|
BUILD_BUG_ON_MSG(C_CAN_MSG_OBJ_RX_LAST > 16,
|
||||||
"Implementation does not support more message objects than 16");
|
"Implementation does not support more message objects than 16");
|
||||||
|
|
||||||
while (quota > 0 && (val = priv->read_reg(priv, C_CAN_INTPND1_REG))) {
|
while (quota > 0) {
|
||||||
while ((msg_obj = ffs(val)) && quota > 0) {
|
if (!pend) {
|
||||||
val &= ~BIT(msg_obj - 1);
|
pend = priv->read_reg(priv, C_CAN_INTPND1_REG);
|
||||||
|
if (!pend)
|
||||||
c_can_object_get(dev, 0, msg_obj, IF_COMM_ALL &
|
break;
|
||||||
~IF_COMM_TXRQST);
|
/*
|
||||||
msg_ctrl_save = priv->read_reg(priv,
|
* If the pending field has a gap, handle the
|
||||||
C_CAN_IFACE(MSGCTRL_REG, 0));
|
* bits above the gap first.
|
||||||
|
*/
|
||||||
if (msg_ctrl_save & IF_MCONT_MSGLST) {
|
toread = c_can_adjust_pending(pend);
|
||||||
c_can_handle_lost_msg_obj(dev, 0, msg_obj);
|
} else {
|
||||||
num_rx_pkts++;
|
toread = pend;
|
||||||
quota--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg_ctrl_save & IF_MCONT_EOB)
|
|
||||||
return num_rx_pkts;
|
|
||||||
|
|
||||||
if (!(msg_ctrl_save & IF_MCONT_NEWDAT))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* read the data from the message object */
|
|
||||||
c_can_read_msg_object(dev, 0, msg_ctrl_save);
|
|
||||||
|
|
||||||
if (msg_obj < C_CAN_MSG_RX_LOW_LAST)
|
|
||||||
c_can_mark_rx_msg_obj(dev, 0,
|
|
||||||
msg_ctrl_save, msg_obj);
|
|
||||||
else if (msg_obj > C_CAN_MSG_RX_LOW_LAST)
|
|
||||||
/* activate this msg obj */
|
|
||||||
c_can_activate_rx_msg_obj(dev, 0,
|
|
||||||
msg_ctrl_save, msg_obj);
|
|
||||||
else if (msg_obj == C_CAN_MSG_RX_LOW_LAST)
|
|
||||||
/* activate all lower message objects */
|
|
||||||
c_can_activate_all_lower_rx_msg_obj(dev,
|
|
||||||
0, msg_ctrl_save);
|
|
||||||
|
|
||||||
num_rx_pkts++;
|
|
||||||
quota--;
|
|
||||||
}
|
}
|
||||||
|
/* Remove the bits from pend */
|
||||||
|
pend &= ~toread;
|
||||||
|
/* Read the objects */
|
||||||
|
n = c_can_read_objects(dev, priv, toread, quota);
|
||||||
|
pkts += n;
|
||||||
|
quota -= n;
|
||||||
}
|
}
|
||||||
|
|
||||||
return num_rx_pkts;
|
if (pkts)
|
||||||
|
can_led_event(dev, CAN_LED_EVENT_RX);
|
||||||
|
|
||||||
|
return pkts;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int c_can_has_and_handle_berr(struct c_can_priv *priv)
|
static inline int c_can_has_and_handle_berr(struct c_can_priv *priv)
|
||||||
|
@ -1133,17 +1176,20 @@ static int c_can_open(struct net_device *dev)
|
||||||
goto exit_irq_fail;
|
goto exit_irq_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
napi_enable(&priv->napi);
|
/* start the c_can controller */
|
||||||
|
err = c_can_start(dev);
|
||||||
|
if (err)
|
||||||
|
goto exit_start_fail;
|
||||||
|
|
||||||
can_led_event(dev, CAN_LED_EVENT_OPEN);
|
can_led_event(dev, CAN_LED_EVENT_OPEN);
|
||||||
|
|
||||||
/* start the c_can controller */
|
napi_enable(&priv->napi);
|
||||||
c_can_start(dev);
|
|
||||||
|
|
||||||
netif_start_queue(dev);
|
netif_start_queue(dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
exit_start_fail:
|
||||||
|
free_irq(dev->irq, dev);
|
||||||
exit_irq_fail:
|
exit_irq_fail:
|
||||||
close_candev(dev);
|
close_candev(dev);
|
||||||
exit_open_fail:
|
exit_open_fail:
|
||||||
|
@ -1180,6 +1226,7 @@ struct net_device *alloc_c_can_dev(void)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
priv = netdev_priv(dev);
|
priv = netdev_priv(dev);
|
||||||
|
spin_lock_init(&priv->xmit_lock);
|
||||||
netif_napi_add(dev, &priv->napi, c_can_poll, C_CAN_NAPI_WEIGHT);
|
netif_napi_add(dev, &priv->napi, c_can_poll, C_CAN_NAPI_WEIGHT);
|
||||||
|
|
||||||
priv->dev = dev;
|
priv->dev = dev;
|
||||||
|
@ -1260,15 +1307,16 @@ int c_can_power_up(struct net_device *dev)
|
||||||
if (time_after(jiffies, time_out))
|
if (time_after(jiffies, time_out))
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
|
|
||||||
c_can_start(dev);
|
return c_can_start(dev);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(c_can_power_up);
|
EXPORT_SYMBOL_GPL(c_can_power_up);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void free_c_can_dev(struct net_device *dev)
|
void free_c_can_dev(struct net_device *dev)
|
||||||
{
|
{
|
||||||
|
struct c_can_priv *priv = netdev_priv(dev);
|
||||||
|
|
||||||
|
netif_napi_del(&priv->napi);
|
||||||
free_candev(dev);
|
free_candev(dev);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(free_c_can_dev);
|
EXPORT_SYMBOL_GPL(free_c_can_dev);
|
||||||
|
|
|
@ -22,6 +22,33 @@
|
||||||
#ifndef C_CAN_H
|
#ifndef C_CAN_H
|
||||||
#define C_CAN_H
|
#define C_CAN_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IFx register masks:
|
||||||
|
* allow easy operation on 16-bit registers when the
|
||||||
|
* argument is 32-bit instead
|
||||||
|
*/
|
||||||
|
#define IFX_WRITE_LOW_16BIT(x) ((x) & 0xFFFF)
|
||||||
|
#define IFX_WRITE_HIGH_16BIT(x) (((x) & 0xFFFF0000) >> 16)
|
||||||
|
|
||||||
|
/* message object split */
|
||||||
|
#define C_CAN_NO_OF_OBJECTS 32
|
||||||
|
#define C_CAN_MSG_OBJ_RX_NUM 16
|
||||||
|
#define C_CAN_MSG_OBJ_TX_NUM 16
|
||||||
|
|
||||||
|
#define C_CAN_MSG_OBJ_RX_FIRST 1
|
||||||
|
#define C_CAN_MSG_OBJ_RX_LAST (C_CAN_MSG_OBJ_RX_FIRST + \
|
||||||
|
C_CAN_MSG_OBJ_RX_NUM - 1)
|
||||||
|
|
||||||
|
#define C_CAN_MSG_OBJ_TX_FIRST (C_CAN_MSG_OBJ_RX_LAST + 1)
|
||||||
|
#define C_CAN_MSG_OBJ_TX_LAST (C_CAN_MSG_OBJ_TX_FIRST + \
|
||||||
|
C_CAN_MSG_OBJ_TX_NUM - 1)
|
||||||
|
|
||||||
|
#define C_CAN_MSG_OBJ_RX_SPLIT 9
|
||||||
|
#define C_CAN_MSG_RX_LOW_LAST (C_CAN_MSG_OBJ_RX_SPLIT - 1)
|
||||||
|
|
||||||
|
#define C_CAN_NEXT_MSG_OBJ_MASK (C_CAN_MSG_OBJ_TX_NUM - 1)
|
||||||
|
#define RECEIVE_OBJECT_BITS 0x0000ffff
|
||||||
|
|
||||||
enum reg {
|
enum reg {
|
||||||
C_CAN_CTRL_REG = 0,
|
C_CAN_CTRL_REG = 0,
|
||||||
C_CAN_CTRL_EX_REG,
|
C_CAN_CTRL_EX_REG,
|
||||||
|
@ -156,6 +183,7 @@ struct c_can_priv {
|
||||||
struct napi_struct napi;
|
struct napi_struct napi;
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
struct device *device;
|
struct device *device;
|
||||||
|
spinlock_t xmit_lock;
|
||||||
int tx_object;
|
int tx_object;
|
||||||
int current_status;
|
int current_status;
|
||||||
int last_status;
|
int last_status;
|
||||||
|
@ -172,6 +200,7 @@ struct c_can_priv {
|
||||||
u32 __iomem *raminit_ctrlreg;
|
u32 __iomem *raminit_ctrlreg;
|
||||||
unsigned int instance;
|
unsigned int instance;
|
||||||
void (*raminit) (const struct c_can_priv *priv, bool enable);
|
void (*raminit) (const struct c_can_priv *priv, bool enable);
|
||||||
|
u32 dlc[C_CAN_MSG_OBJ_TX_NUM];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct net_device *alloc_c_can_dev(void);
|
struct net_device *alloc_c_can_dev(void);
|
||||||
|
|
|
@ -37,8 +37,10 @@
|
||||||
|
|
||||||
#include "c_can.h"
|
#include "c_can.h"
|
||||||
|
|
||||||
#define CAN_RAMINIT_START_MASK(i) (1 << (i))
|
#define CAN_RAMINIT_START_MASK(i) (0x001 << (i))
|
||||||
|
#define CAN_RAMINIT_DONE_MASK(i) (0x100 << (i))
|
||||||
|
#define CAN_RAMINIT_ALL_MASK(i) (0x101 << (i))
|
||||||
|
static DEFINE_SPINLOCK(raminit_lock);
|
||||||
/*
|
/*
|
||||||
* 16-bit c_can registers can be arranged differently in the memory
|
* 16-bit c_can registers can be arranged differently in the memory
|
||||||
* architecture of different implementations. For example: 16-bit
|
* architecture of different implementations. For example: 16-bit
|
||||||
|
@ -69,16 +71,41 @@ static void c_can_plat_write_reg_aligned_to_32bit(struct c_can_priv *priv,
|
||||||
writew(val, priv->base + 2 * priv->regs[index]);
|
writew(val, priv->base + 2 * priv->regs[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void c_can_hw_raminit_wait(const struct c_can_priv *priv, u32 mask,
|
||||||
|
u32 val)
|
||||||
|
{
|
||||||
|
/* We look only at the bits of our instance. */
|
||||||
|
val &= mask;
|
||||||
|
while ((readl(priv->raminit_ctrlreg) & mask) != val)
|
||||||
|
udelay(1);
|
||||||
|
}
|
||||||
|
|
||||||
static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable)
|
static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable)
|
||||||
{
|
{
|
||||||
u32 val;
|
u32 mask = CAN_RAMINIT_ALL_MASK(priv->instance);
|
||||||
|
u32 ctrl;
|
||||||
|
|
||||||
val = readl(priv->raminit_ctrlreg);
|
spin_lock(&raminit_lock);
|
||||||
if (enable)
|
|
||||||
val |= CAN_RAMINIT_START_MASK(priv->instance);
|
ctrl = readl(priv->raminit_ctrlreg);
|
||||||
else
|
/* We clear the done and start bit first. The start bit is
|
||||||
val &= ~CAN_RAMINIT_START_MASK(priv->instance);
|
* looking at the 0 -> transition, but is not self clearing;
|
||||||
writel(val, priv->raminit_ctrlreg);
|
* And we clear the init done bit as well.
|
||||||
|
*/
|
||||||
|
ctrl &= ~CAN_RAMINIT_START_MASK(priv->instance);
|
||||||
|
ctrl |= CAN_RAMINIT_DONE_MASK(priv->instance);
|
||||||
|
writel(ctrl, priv->raminit_ctrlreg);
|
||||||
|
ctrl &= ~CAN_RAMINIT_DONE_MASK(priv->instance);
|
||||||
|
c_can_hw_raminit_wait(priv, ctrl, mask);
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
/* Set start bit and wait for the done bit. */
|
||||||
|
ctrl |= CAN_RAMINIT_START_MASK(priv->instance);
|
||||||
|
writel(ctrl, priv->raminit_ctrlreg);
|
||||||
|
ctrl |= CAN_RAMINIT_DONE_MASK(priv->instance);
|
||||||
|
c_can_hw_raminit_wait(priv, ctrl, mask);
|
||||||
|
}
|
||||||
|
spin_unlock(&raminit_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_device_id c_can_id_table[] = {
|
static struct platform_device_id c_can_id_table[] = {
|
||||||
|
|
|
@ -697,8 +697,8 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb,
|
||||||
return NETDEV_TX_OK;
|
return NETDEV_TX_OK;
|
||||||
|
|
||||||
nofreecontext:
|
nofreecontext:
|
||||||
usb_unanchor_urb(urb);
|
|
||||||
usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
|
usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
|
||||||
|
usb_free_urb(urb);
|
||||||
|
|
||||||
netdev_warn(netdev, "couldn't find free context");
|
netdev_warn(netdev, "couldn't find free context");
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue