162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/drivers/misc/xillybus_pcie.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2011 Xillybus Ltd, http://xillybus.com 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Driver for the Xillybus FPGA/host framework using PCI Express. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/pci.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include "xillybus.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ciMODULE_DESCRIPTION("Xillybus driver for PCIe"); 1662306a36Sopenharmony_ciMODULE_AUTHOR("Eli Billauer, Xillybus Ltd."); 1762306a36Sopenharmony_ciMODULE_ALIAS("xillybus_pcie"); 1862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define PCI_DEVICE_ID_XILLYBUS 0xebeb 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define PCI_VENDOR_ID_ACTEL 0x11aa 2362306a36Sopenharmony_ci#define PCI_VENDOR_ID_LATTICE 0x1204 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic const char xillyname[] = "xillybus_pcie"; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic const struct pci_device_id xillyids[] = { 2862306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_XILLYBUS)}, 2962306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_ALTERA, PCI_DEVICE_ID_XILLYBUS)}, 3062306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_ACTEL, PCI_DEVICE_ID_XILLYBUS)}, 3162306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_LATTICE, PCI_DEVICE_ID_XILLYBUS)}, 3262306a36Sopenharmony_ci { /* End: all zeroes */ } 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic int xilly_probe(struct pci_dev *pdev, 3662306a36Sopenharmony_ci const struct pci_device_id *ent) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci struct xilly_endpoint *endpoint; 3962306a36Sopenharmony_ci int rc; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci endpoint = xillybus_init_endpoint(&pdev->dev); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (!endpoint) 4462306a36Sopenharmony_ci return -ENOMEM; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci pci_set_drvdata(pdev, endpoint); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci endpoint->owner = THIS_MODULE; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci rc = pcim_enable_device(pdev); 5162306a36Sopenharmony_ci if (rc) { 5262306a36Sopenharmony_ci dev_err(endpoint->dev, 5362306a36Sopenharmony_ci "pcim_enable_device() failed. Aborting.\n"); 5462306a36Sopenharmony_ci return rc; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* L0s has caused packet drops. No power saving, thank you. */ 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { 6262306a36Sopenharmony_ci dev_err(endpoint->dev, 6362306a36Sopenharmony_ci "Incorrect BAR configuration. Aborting.\n"); 6462306a36Sopenharmony_ci return -ENODEV; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci rc = pcim_iomap_regions(pdev, 0x01, xillyname); 6862306a36Sopenharmony_ci if (rc) { 6962306a36Sopenharmony_ci dev_err(endpoint->dev, 7062306a36Sopenharmony_ci "pcim_iomap_regions() failed. Aborting.\n"); 7162306a36Sopenharmony_ci return rc; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci endpoint->registers = pcim_iomap_table(pdev)[0]; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci pci_set_master(pdev); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci /* Set up a single MSI interrupt */ 7962306a36Sopenharmony_ci if (pci_enable_msi(pdev)) { 8062306a36Sopenharmony_ci dev_err(endpoint->dev, 8162306a36Sopenharmony_ci "Failed to enable MSI interrupts. Aborting.\n"); 8262306a36Sopenharmony_ci return -ENODEV; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci rc = devm_request_irq(&pdev->dev, pdev->irq, xillybus_isr, 0, 8562306a36Sopenharmony_ci xillyname, endpoint); 8662306a36Sopenharmony_ci if (rc) { 8762306a36Sopenharmony_ci dev_err(endpoint->dev, 8862306a36Sopenharmony_ci "Failed to register MSI handler. Aborting.\n"); 8962306a36Sopenharmony_ci return -ENODEV; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* 9362306a36Sopenharmony_ci * Some (old and buggy?) hardware drops 64-bit addressed PCIe packets, 9462306a36Sopenharmony_ci * even when the PCIe driver claims that a 64-bit mask is OK. On the 9562306a36Sopenharmony_ci * other hand, on some architectures, 64-bit addressing is mandatory. 9662306a36Sopenharmony_ci * So go for the 64-bit mask only when failing is the other option. 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { 10062306a36Sopenharmony_ci endpoint->dma_using_dac = 0; 10162306a36Sopenharmony_ci } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) { 10262306a36Sopenharmony_ci endpoint->dma_using_dac = 1; 10362306a36Sopenharmony_ci } else { 10462306a36Sopenharmony_ci dev_err(endpoint->dev, "Failed to set DMA mask. Aborting.\n"); 10562306a36Sopenharmony_ci return -ENODEV; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return xillybus_endpoint_discovery(endpoint); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic void xilly_remove(struct pci_dev *pdev) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct xilly_endpoint *endpoint = pci_get_drvdata(pdev); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci xillybus_endpoint_remove(endpoint); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, xillyids); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic struct pci_driver xillybus_driver = { 12162306a36Sopenharmony_ci .name = xillyname, 12262306a36Sopenharmony_ci .id_table = xillyids, 12362306a36Sopenharmony_ci .probe = xilly_probe, 12462306a36Sopenharmony_ci .remove = xilly_remove, 12562306a36Sopenharmony_ci}; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cimodule_pci_driver(xillybus_driver); 128