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 sk_buff *skb; struct can_frame *frame; netdev_err(dev, "msg lost in buffer %d\n", objno); c_can_object_get(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST); 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 */ skb = alloc_can_err_skb(dev, &frame); if (unlikely(!skb)) return; frame->can_id |= CAN_ERR_CRTL; frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; stats->rx_errors++; stats->rx_over_errors++; netif_receive_skb(skb); }
static void c_can_setup_receive_object(struct net_device *dev, int iface, int objno, unsigned int mask, unsigned int id, unsigned int mcont) { struct c_can_priv *priv = netdev_priv(dev); priv->write_reg(priv, C_CAN_IFACE(MASK1_REG, iface), IFX_WRITE_LOW_16BIT(mask)); /* According to C_CAN documentation, the reserved bit * in IFx_MASK2 register is fixed 1 */ priv->write_reg(priv, C_CAN_IFACE(MASK2_REG, iface), IFX_WRITE_HIGH_16BIT(mask) | BIT(13)); priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), IFX_WRITE_LOW_16BIT(id)); priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), (IF_ARB_MSGVAL | IFX_WRITE_HIGH_16BIT(id))); priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), mcont); c_can_object_put(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST); netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, c_can_read_reg32(priv, C_CAN_MSGVAL1_REG)); }
static int c_can_handle_lost_msg_obj(struct net_device *dev, int iface, int objno, u32 ctrl) { struct net_device_stats *stats = &dev->stats; struct c_can_priv *priv = netdev_priv(dev); struct can_frame *frame; struct sk_buff *skb; ctrl &= ~(IF_MCONT_MSGLST | IF_MCONT_INTPND | IF_MCONT_NEWDAT); priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), ctrl); c_can_object_put(dev, iface, objno, IF_COMM_CONTROL); stats->rx_errors++; stats->rx_over_errors++; /* create an error msg */ skb = alloc_can_err_skb(dev, &frame); if (unlikely(!skb)) return 0; frame->can_id |= CAN_ERR_CRTL; frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; netif_receive_skb(skb); return 1; }
static void c_can_write_msg_object(struct net_device *dev, int iface, struct can_frame *frame, int objno) { int i; u16 flags = 0; unsigned int id; struct c_can_priv *priv = netdev_priv(dev); if (!(frame->can_id & CAN_RTR_FLAG)) flags |= IF_ARB_TRANSMIT; if (frame->can_id & CAN_EFF_FLAG) { id = frame->can_id & CAN_EFF_MASK; flags |= IF_ARB_MSGXTD; } else id = ((frame->can_id & CAN_SFF_MASK) << 18); flags |= IF_ARB_MSGVAL; priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), IFX_WRITE_LOW_16BIT(id)); priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), flags | IFX_WRITE_HIGH_16BIT(id)); for (i = 0; i < frame->can_dlc; i += 2) { priv->write_reg(priv, C_CAN_IFACE(DATA1_REG, iface) + i / 2, frame->data[i] | (frame->data[i + 1] << 8)); } /* enable interrupt for this message object */ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), IF_MCONT_TXIE | IF_MCONT_TXRQST | IF_MCONT_EOB | frame->can_dlc); c_can_object_put(dev, iface, objno, IF_COMM_ALL); }
static void c_can_setup_receive_object(struct net_device *dev, int iface, int objno, unsigned int mask, unsigned int id, unsigned int mcont) { struct c_can_priv *priv = netdev_priv(dev); priv->write_reg(priv, &priv->regs->ifregs[iface].mask1, IFX_WRITE_LOW_16BIT(mask)); /* According to C_CAN documentation, the reserved bit * in IFx_MASK2 register is fixed 1 */ priv->write_reg(priv, &priv->regs->ifregs[iface].mask2, IFX_WRITE_HIGH_16BIT(mask) | BIT(13)); priv->write_reg(priv, &priv->regs->ifregs[iface].arb1, IFX_WRITE_LOW_16BIT(id)); priv->write_reg(priv, &priv->regs->ifregs[iface].arb2, (IF_ARB_MSGVAL | IFX_WRITE_HIGH_16BIT(id))); priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl, mcont); c_can_object_put(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST); netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, c_can_read_reg32(priv, &priv->regs->msgval1)); }
/* * Note: According to documentation clearing TXIE while MSGVAL is set * is not allowed, but works nicely on C/DCAN. And that lowers the I/O * load significantly. */ static void c_can_inval_tx_object(struct net_device *dev, int iface, int obj) { struct c_can_priv *priv = netdev_priv(dev); priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), 0); c_can_object_put(dev, iface, obj, IF_COMM_INVAL); }
static netdev_tx_t c_can_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct can_frame *frame = (struct can_frame *)skb->data; struct c_can_priv *priv = netdev_priv(dev); u32 idx, obj; if (can_dropped_invalid_skb(dev, skb)) return NETDEV_TX_OK; /* * This is not a FIFO. C/D_CAN sends out the buffers * prioritized. The lowest buffer number wins. */ idx = fls(atomic_read(&priv->tx_active)); obj = idx + C_CAN_MSG_OBJ_TX_FIRST; /* If this is the last buffer, stop the xmit queue */ if (idx == C_CAN_MSG_OBJ_TX_NUM - 1) netif_stop_queue(dev); /* * Store the message in the interface so we can call * can_put_echo_skb(). We must do this before we enable * transmit as we might race against do_tx(). */ c_can_setup_tx_object(dev, IF_TX, frame, idx); priv->dlc[idx] = frame->can_dlc; can_put_echo_skb(skb, dev, idx); /* Update the active bits */ atomic_add((1 << idx), &priv->tx_active); /* Start transmission */ c_can_object_put(dev, IF_TX, obj, IF_COMM_TX); return NETDEV_TX_OK; }
static inline void c_can_activate_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 | IF_MCONT_NEWDAT)); c_can_object_put(dev, iface, obj, IF_COMM_CONTROL); }
static inline void c_can_activate_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, &priv->regs->ifregs[iface].msg_cntrl, 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_inval_msg_object(struct net_device *dev, int iface, int objno) { struct c_can_priv *priv = netdev_priv(dev); priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), 0); priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), 0); priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), 0); c_can_object_put(dev, iface, objno, IF_COMM_ARB | IF_COMM_CONTROL); netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, c_can_read_reg32(priv, C_CAN_MSGVAL1_REG)); }
static void c_can_inval_msg_object(struct net_device *dev, int iface, int objno) { struct c_can_priv *priv = netdev_priv(dev); priv->write_reg(priv, &priv->regs->ifregs[iface].arb1, 0); priv->write_reg(priv, &priv->regs->ifregs[iface].arb2, 0); priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl, 0); c_can_object_put(dev, iface, objno, IF_COMM_ARB | IF_COMM_CONTROL); netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, c_can_read_reg32(priv, &priv->regs->msgval1)); }
static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device *dev, int iface, int ctrl_mask) { int i; struct c_can_priv *priv = netdev_priv(dev); 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), ctrl_mask & ~(IF_MCONT_MSGLST | IF_MCONT_INTPND | IF_MCONT_NEWDAT)); c_can_object_put(dev, iface, i, IF_COMM_CONTROL); } }
static void c_can_setup_receive_object(struct net_device *dev, int iface, u32 obj, u32 mask, u32 id, u32 mcont) { struct c_can_priv *priv = netdev_priv(dev); mask |= BIT(29); priv->write_reg32(priv, C_CAN_IFACE(MASK1_REG, iface), mask); id |= IF_ARB_MSGVAL; priv->write_reg32(priv, C_CAN_IFACE(ARB1_REG, iface), id); priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), mcont); c_can_object_put(dev, iface, obj, IF_COMM_RCV_SETUP); }
static void c_can_setup_receive_object(struct net_device *dev, int iface, int objno, unsigned int mask, unsigned int id, unsigned int mcont) { struct c_can_priv *priv = netdev_priv(dev); priv->write_reg(priv, &priv->regs->ifregs[iface].mask1, IFX_WRITE_LOW_16BIT(mask)); priv->write_reg(priv, &priv->regs->ifregs[iface].mask2, IFX_WRITE_HIGH_16BIT(mask)); priv->write_reg(priv, &priv->regs->ifregs[iface].arb1, IFX_WRITE_LOW_16BIT(id)); priv->write_reg(priv, &priv->regs->ifregs[iface].arb2, (IF_ARB_MSGVAL | IFX_WRITE_HIGH_16BIT(id))); priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl, mcont); c_can_object_put(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST); netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, c_can_read_reg32(priv, &priv->regs->msgval1)); }