Exemple #1
0
/* 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;
}
Exemple #2
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;
}