diff options
Diffstat (limited to 'drivers/net/can/peak_canfd/peak_pciefd_main.c')
-rw-r--r-- | drivers/net/can/peak_canfd/peak_pciefd_main.c | 39 |
1 files changed, 29 insertions, 10 deletions
diff --git a/drivers/net/can/peak_canfd/peak_pciefd_main.c b/drivers/net/can/peak_canfd/peak_pciefd_main.c index b9e28578bc7b..c458d5fdc8d3 100644 --- a/drivers/net/can/peak_canfd/peak_pciefd_main.c +++ b/drivers/net/can/peak_canfd/peak_pciefd_main.c @@ -58,6 +58,10 @@ MODULE_LICENSE("GPL v2"); #define PCIEFD_REG_SYS_VER1 0x0040 /* version reg #1 */ #define PCIEFD_REG_SYS_VER2 0x0044 /* version reg #2 */ +#define PCIEFD_FW_VERSION(x, y, z) (((u32)(x) << 24) | \ + ((u32)(y) << 16) | \ + ((u32)(z) << 8)) + /* System Control Registers Bits */ #define PCIEFD_SYS_CTL_TS_RST 0x00000001 /* timestamp clock */ #define PCIEFD_SYS_CTL_CLK_EN 0x00000002 /* system clock */ @@ -170,9 +174,6 @@ struct pciefd_page { u32 size; }; -#define CANFD_IRQ_SET 0x00000001 -#define CANFD_TX_PATH_SET 0x00000002 - /* CAN-FD channel object */ struct pciefd_board; struct pciefd_can { @@ -414,7 +415,7 @@ static int pciefd_pre_cmd(struct peak_canfd_priv *ucan) break; /* going into operational mode: setup IRQ handler */ - err = request_irq(priv->board->pci_dev->irq, + err = request_irq(priv->ucan.ndev->irq, pciefd_irq_handler, IRQF_SHARED, PCIEFD_DRV_NAME, @@ -487,15 +488,18 @@ static int pciefd_post_cmd(struct peak_canfd_priv *ucan) /* controller now in reset mode: */ + /* disable IRQ for this CAN */ + pciefd_can_writereg(priv, CANFD_CTL_IEN_BIT, + PCIEFD_REG_CAN_RX_CTL_CLR); + /* stop and reset DMA addresses in Tx/Rx engines */ pciefd_can_clear_tx_dma(priv); pciefd_can_clear_rx_dma(priv); - /* disable IRQ for this CAN */ - pciefd_can_writereg(priv, CANFD_CTL_IEN_BIT, - PCIEFD_REG_CAN_RX_CTL_CLR); + /* wait for above commands to complete (read cycle) */ + (void)pciefd_sys_readreg(priv->board, PCIEFD_REG_SYS_VER1); - free_irq(priv->board->pci_dev->irq, priv); + free_irq(priv->ucan.ndev->irq, priv); ucan->can.state = CAN_STATE_STOPPED; @@ -634,7 +638,7 @@ static int pciefd_can_probe(struct pciefd_board *pciefd) GFP_KERNEL); if (!priv->tx_dma_vaddr) { dev_err(&pciefd->pci_dev->dev, - "Tx dmaim_alloc_coherent(%u) failure\n", + "Tx dmam_alloc_coherent(%u) failure\n", PCIEFD_TX_DMA_SIZE); goto err_free_candev; } @@ -687,7 +691,7 @@ static int pciefd_can_probe(struct pciefd_board *pciefd) pciefd->can[pciefd->can_count] = priv; dev_info(&pciefd->pci_dev->dev, "%s at reg_base=0x%p irq=%d\n", - ndev->name, priv->reg_base, pciefd->pci_dev->irq); + ndev->name, priv->reg_base, ndev->irq); return 0; @@ -782,6 +786,21 @@ static int peak_pciefd_probe(struct pci_dev *pdev, "%ux CAN-FD PCAN-PCIe FPGA v%u.%u.%u:\n", can_count, hw_ver_major, hw_ver_minor, hw_ver_sub); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + /* FW < v3.3.0 DMA logic doesn't handle correctly the mix of 32-bit and + * 64-bit logical addresses: this workaround forces usage of 32-bit + * DMA addresses only when such a fw is detected. + */ + if (PCIEFD_FW_VERSION(hw_ver_major, hw_ver_minor, hw_ver_sub) < + PCIEFD_FW_VERSION(3, 3, 0)) { + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (err) + dev_warn(&pdev->dev, + "warning: can't set DMA mask %llxh (err %d)\n", + DMA_BIT_MASK(32), err); + } +#endif + /* stop system clock */ pciefd_sys_writereg(pciefd, PCIEFD_SYS_CTL_CLK_EN, PCIEFD_REG_SYS_CTL_CLR); |