static int ti_hecc_rx_pkt(struct ti_hecc_priv *priv, int mbxno) { struct net_device_stats *stats = &priv->ndev->stats; struct can_frame *cf; struct sk_buff *skb; u32 data, mbx_mask; unsigned long flags; skb = alloc_can_skb(priv->ndev, &cf); if (!skb) { if (printk_ratelimit()) netdev_err(priv->ndev, "ti_hecc_rx_pkt: alloc_can_skb() failed\n"); return -ENOMEM; } mbx_mask = BIT(mbxno); data = hecc_read_mbx(priv, mbxno, HECC_CANMID); if (data & HECC_CANMID_IDE) cf->can_id = (data & CAN_EFF_MASK) | CAN_EFF_FLAG; else cf->can_id = (data >> 18) & CAN_SFF_MASK; data = hecc_read_mbx(priv, mbxno, HECC_CANMCF); if (data & HECC_CANMCF_RTR) cf->can_id |= CAN_RTR_FLAG; cf->can_dlc = get_can_dlc(data & 0xF); data = hecc_read_mbx(priv, mbxno, HECC_CANMDL); *(u32 *)(cf->data) = cpu_to_be32(data); if (cf->can_dlc > 4) { data = hecc_read_mbx(priv, mbxno, HECC_CANMDH); *(u32 *)(cf->data + 4) = cpu_to_be32(data); } else { *(u32 *)(cf->data + 4) = 0; } spin_lock_irqsave(&priv->mbx_lock, flags); hecc_clear_bit(priv, HECC_CANME, mbx_mask); hecc_write(priv, HECC_CANRMP, mbx_mask); /* enable mailbox only if it is part of rx buffer mailboxes */ if (priv->rx_next < HECC_RX_BUFFER_MBOX) hecc_set_bit(priv, HECC_CANME, mbx_mask); spin_unlock_irqrestore(&priv->mbx_lock, flags); stats->rx_bytes += cf->can_dlc; can_led_event(priv->ndev, CAN_LED_EVENT_RX); netif_receive_skb(skb); stats->rx_packets++; return 0; }
static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id) { struct net_device *ndev = (struct net_device *)dev_id; struct ti_hecc_priv *priv = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; u32 mbxno, mbx_mask, int_status, err_status; unsigned long ack, flags; int_status = hecc_read(priv, (priv->int_line) ? HECC_CANGIF1 : HECC_CANGIF0); if (!int_status) return IRQ_NONE; err_status = hecc_read(priv, HECC_CANES); if (err_status & (HECC_BUS_ERROR | HECC_CANES_BO | HECC_CANES_EP | HECC_CANES_EW)) ti_hecc_error(ndev, int_status, err_status); if (int_status & HECC_CANGIF_GMIF) { while (priv->tx_tail - priv->tx_head > 0) { mbxno = get_tx_tail_mb(priv); mbx_mask = BIT(mbxno); if (!(mbx_mask & hecc_read(priv, HECC_CANTA))) break; hecc_clear_bit(priv, HECC_CANMIM, mbx_mask); hecc_write(priv, HECC_CANTA, mbx_mask); spin_lock_irqsave(&priv->mbx_lock, flags); hecc_clear_bit(priv, HECC_CANME, mbx_mask); spin_unlock_irqrestore(&priv->mbx_lock, flags); stats->tx_bytes += hecc_read_mbx(priv, mbxno, HECC_CANMCF) & 0xF; stats->tx_packets++; can_get_echo_skb(ndev, mbxno); --priv->tx_tail; } /* restart queue if wrap-up or if queue stalled on last pkt */ if (((priv->tx_head == priv->tx_tail) && ((priv->tx_head & HECC_TX_MASK) != HECC_TX_MASK)) || (((priv->tx_tail & HECC_TX_MASK) == HECC_TX_MASK) && ((priv->tx_head & HECC_TX_MASK) == HECC_TX_MASK))) netif_wake_queue(ndev); /* Disable RX mailbox interrupts and let NAPI reenable them */ if (hecc_read(priv, HECC_CANRMP)) { ack = hecc_read(priv, HECC_CANMIM); ack &= BIT(HECC_MAX_TX_MBOX) - 1; hecc_write(priv, HECC_CANMIM, ack); napi_schedule(&priv->napi); } } /* clear all interrupt conditions - read back to avoid spurious ints */ if (priv->int_line) { hecc_write(priv, HECC_CANGIF1, HECC_SET_REG); int_status = hecc_read(priv, HECC_CANGIF1); } else { hecc_write(priv, HECC_CANGIF0, HECC_SET_REG); int_status = hecc_read(priv, HECC_CANGIF0); } return IRQ_HANDLED; }