/* board specific CANFD command pre-processing */ static int pciefd_pre_cmd(struct peak_canfd_priv *ucan) { struct pciefd_can *priv = (struct pciefd_can *)ucan; u16 cmd = pucan_cmd_get_opcode(&priv->pucan_cmd); int err; /* pre-process command */ switch (cmd) { case PUCAN_CMD_NORMAL_MODE: case PUCAN_CMD_LISTEN_ONLY_MODE: if (ucan->can.state == CAN_STATE_BUS_OFF) break; /* going into operational mode: setup IRQ handler */ err = request_irq(priv->board->pci_dev->irq, pciefd_irq_handler, IRQF_SHARED, PCIEFD_DRV_NAME, priv); if (err) return err; /* setup Rx DMA address */ pciefd_can_setup_rx_dma(priv); /* setup max count of msgs per IRQ */ pciefd_can_writereg(priv, (CANFD_CTL_IRQ_TL_DEF) << 8 | CANFD_CTL_IRQ_CL_DEF, PCIEFD_REG_CAN_RX_CTL_WRT); /* clear DMA RST for Rx (Rx start) */ pciefd_can_writereg(priv, CANFD_CTL_RST_BIT, PCIEFD_REG_CAN_RX_CTL_CLR); /* reset timestamps */ pciefd_can_writereg(priv, !CANFD_MISC_TS_RST, PCIEFD_REG_CAN_MISC); /* do an initial ACK */ pciefd_can_ack_rx_dma(priv); /* enable IRQ for this CAN after having set next irq_tag */ pciefd_can_writereg(priv, CANFD_CTL_IEN_BIT, PCIEFD_REG_CAN_RX_CTL_SET); /* Tx path will be setup as soon as RX_BARRIER is received */ break; default: break; } return 0; }
/* IRQ handler */ static irqreturn_t pciefd_irq_handler(int irq, void *arg) { struct pciefd_can *priv = arg; struct pciefd_rx_dma *rx_dma = priv->rx_dma_vaddr; /* INTA mode only to sync with PCIe transaction */ if (!pci_dev_msi_enabled(priv->board->pci_dev)) (void)pciefd_sys_readreg(priv->board, PCIEFD_REG_SYS_VER1); /* read IRQ status from the first 32-bits of the Rx DMA area */ priv->irq_status = le32_to_cpu(rx_dma->irq_status); /* check if this (shared) IRQ is for this CAN */ if (pciefd_irq_tag(priv->irq_status) != priv->irq_tag) return IRQ_NONE; /* handle rx messages (if any) */ peak_canfd_handle_msgs_list(&priv->ucan, rx_dma->msg, pciefd_irq_rx_cnt(priv->irq_status)); /* handle tx link interrupt (if any) */ if (pciefd_irq_is_lnk(priv->irq_status)) { unsigned long flags; spin_lock_irqsave(&priv->tx_lock, flags); priv->tx_pages_free++; spin_unlock_irqrestore(&priv->tx_lock, flags); /* wake producer up (only if enough room in echo_skb array) */ spin_lock_irqsave(&priv->ucan.echo_lock, flags); if (!priv->ucan.can.echo_skb[priv->ucan.echo_idx]) netif_wake_queue(priv->ucan.ndev); spin_unlock_irqrestore(&priv->ucan.echo_lock, flags); } /* re-enable Rx DMA transfer for this CAN */ pciefd_can_ack_rx_dma(priv); return IRQ_HANDLED; }