/* 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; }
/* probe for the entire device */ static int peak_pciefd_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct pciefd_board *pciefd; int err, can_count; u16 sub_sys_id; u8 hw_ver_major; u8 hw_ver_minor; u8 hw_ver_sub; u32 v2; err = pci_enable_device(pdev); if (err) return err; err = pci_request_regions(pdev, PCIEFD_DRV_NAME); if (err) goto err_disable_pci; /* the number of channels depends on sub-system id */ err = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &sub_sys_id); if (err) goto err_release_regions; dev_dbg(&pdev->dev, "probing device %04x:%04x:%04x\n", pdev->vendor, pdev->device, sub_sys_id); if (sub_sys_id >= 0x0012) can_count = 4; else if (sub_sys_id >= 0x0010) can_count = 3; else if (sub_sys_id >= 0x0004) can_count = 2; else can_count = 1; /* allocate board structure object */ pciefd = devm_kzalloc(&pdev->dev, sizeof(*pciefd) + can_count * sizeof(*pciefd->can), GFP_KERNEL); if (!pciefd) { err = -ENOMEM; goto err_release_regions; } /* initialize the board structure */ pciefd->pci_dev = pdev; spin_lock_init(&pciefd->cmd_lock); /* save the PCI BAR0 virtual address for further system regs access */ pciefd->reg_base = pci_iomap(pdev, 0, PCIEFD_BAR0_SIZE); if (!pciefd->reg_base) { dev_err(&pdev->dev, "failed to map PCI resource #0\n"); err = -ENOMEM; goto err_release_regions; } /* read the firmware version number */ v2 = pciefd_sys_readreg(pciefd, PCIEFD_REG_SYS_VER2); hw_ver_major = (v2 & 0x0000f000) >> 12; hw_ver_minor = (v2 & 0x00000f00) >> 8; hw_ver_sub = (v2 & 0x000000f0) >> 4; dev_info(&pdev->dev, "%ux CAN-FD PCAN-PCIe FPGA v%u.%u.%u:\n", can_count, hw_ver_major, hw_ver_minor, hw_ver_sub); /* stop system clock */ pciefd_sys_writereg(pciefd, PCIEFD_SYS_CTL_CLK_EN, PCIEFD_REG_SYS_CTL_CLR); pci_set_master(pdev); /* create now the corresponding channels objects */ while (pciefd->can_count < can_count) { err = pciefd_can_probe(pciefd); if (err) goto err_free_canfd; pciefd->can_count++; } /* set system timestamps counter in RST mode */ pciefd_sys_writereg(pciefd, PCIEFD_SYS_CTL_TS_RST, PCIEFD_REG_SYS_CTL_SET); /* wait a bit (read cycle) */ (void)pciefd_sys_readreg(pciefd, PCIEFD_REG_SYS_VER1); /* free all clocks */ pciefd_sys_writereg(pciefd, PCIEFD_SYS_CTL_TS_RST, PCIEFD_REG_SYS_CTL_CLR); /* start system clock */ pciefd_sys_writereg(pciefd, PCIEFD_SYS_CTL_CLK_EN, PCIEFD_REG_SYS_CTL_SET); /* remember the board structure address in the device user data */ pci_set_drvdata(pdev, pciefd); return 0; err_free_canfd: pciefd_can_remove_all(pciefd); pci_iounmap(pdev, pciefd->reg_base); err_release_regions: pci_release_regions(pdev); err_disable_pci: pci_disable_device(pdev); return err; }