xref: /linux/drivers/char/xillybus/xillybus_pcie.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
1a6377d90SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
27051924fSEli Billauer /*
37051924fSEli Billauer  * linux/drivers/misc/xillybus_pcie.c
47051924fSEli Billauer  *
57051924fSEli Billauer  * Copyright 2011 Xillybus Ltd, http://xillybus.com
67051924fSEli Billauer  *
77051924fSEli Billauer  * Driver for the Xillybus FPGA/host framework using PCI Express.
87051924fSEli Billauer  */
97051924fSEli Billauer 
107051924fSEli Billauer #include <linux/module.h>
117051924fSEli Billauer #include <linux/pci.h>
127051924fSEli Billauer #include <linux/slab.h>
137051924fSEli Billauer #include "xillybus.h"
147051924fSEli Billauer 
157051924fSEli Billauer MODULE_DESCRIPTION("Xillybus driver for PCIe");
167051924fSEli Billauer MODULE_AUTHOR("Eli Billauer, Xillybus Ltd.");
177051924fSEli Billauer MODULE_ALIAS("xillybus_pcie");
187051924fSEli Billauer MODULE_LICENSE("GPL v2");
197051924fSEli Billauer 
207051924fSEli Billauer #define PCI_DEVICE_ID_XILLYBUS		0xebeb
217051924fSEli Billauer 
227051924fSEli Billauer #define PCI_VENDOR_ID_ACTEL		0x11aa
237051924fSEli Billauer #define PCI_VENDOR_ID_LATTICE		0x1204
247051924fSEli Billauer 
257051924fSEli Billauer static const char xillyname[] = "xillybus_pcie";
267051924fSEli Billauer 
277051924fSEli Billauer static const struct pci_device_id xillyids[] = {
287051924fSEli Billauer 	{PCI_DEVICE(PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_XILLYBUS)},
297051924fSEli Billauer 	{PCI_DEVICE(PCI_VENDOR_ID_ALTERA, PCI_DEVICE_ID_XILLYBUS)},
307051924fSEli Billauer 	{PCI_DEVICE(PCI_VENDOR_ID_ACTEL, PCI_DEVICE_ID_XILLYBUS)},
317051924fSEli Billauer 	{PCI_DEVICE(PCI_VENDOR_ID_LATTICE, PCI_DEVICE_ID_XILLYBUS)},
327051924fSEli Billauer 	{ /* End: all zeroes */ }
337051924fSEli Billauer };
347051924fSEli Billauer 
xilly_probe(struct pci_dev * pdev,const struct pci_device_id * ent)357051924fSEli Billauer static int xilly_probe(struct pci_dev *pdev,
367051924fSEli Billauer 		       const struct pci_device_id *ent)
377051924fSEli Billauer {
387051924fSEli Billauer 	struct xilly_endpoint *endpoint;
397051924fSEli Billauer 	int rc;
407051924fSEli Billauer 
41*c31bbc14SEli Billauer 	endpoint = xillybus_init_endpoint(&pdev->dev);
427051924fSEli Billauer 
437051924fSEli Billauer 	if (!endpoint)
447051924fSEli Billauer 		return -ENOMEM;
457051924fSEli Billauer 
467051924fSEli Billauer 	pci_set_drvdata(pdev, endpoint);
477051924fSEli Billauer 
48*c31bbc14SEli Billauer 	endpoint->owner = THIS_MODULE;
49*c31bbc14SEli Billauer 
507051924fSEli Billauer 	rc = pcim_enable_device(pdev);
517051924fSEli Billauer 	if (rc) {
527051924fSEli Billauer 		dev_err(endpoint->dev,
537051924fSEli Billauer 			"pcim_enable_device() failed. Aborting.\n");
547051924fSEli Billauer 		return rc;
557051924fSEli Billauer 	}
567051924fSEli Billauer 
577051924fSEli Billauer 	/* L0s has caused packet drops. No power saving, thank you. */
587051924fSEli Billauer 
597051924fSEli Billauer 	pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S);
607051924fSEli Billauer 
617051924fSEli Billauer 	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
627051924fSEli Billauer 		dev_err(endpoint->dev,
637051924fSEli Billauer 			"Incorrect BAR configuration. Aborting.\n");
647051924fSEli Billauer 		return -ENODEV;
657051924fSEli Billauer 	}
667051924fSEli Billauer 
677051924fSEli Billauer 	rc = pcim_iomap_regions(pdev, 0x01, xillyname);
687051924fSEli Billauer 	if (rc) {
697051924fSEli Billauer 		dev_err(endpoint->dev,
707051924fSEli Billauer 			"pcim_iomap_regions() failed. Aborting.\n");
717051924fSEli Billauer 		return rc;
727051924fSEli Billauer 	}
737051924fSEli Billauer 
747051924fSEli Billauer 	endpoint->registers = pcim_iomap_table(pdev)[0];
757051924fSEli Billauer 
767051924fSEli Billauer 	pci_set_master(pdev);
777051924fSEli Billauer 
787051924fSEli Billauer 	/* Set up a single MSI interrupt */
797051924fSEli Billauer 	if (pci_enable_msi(pdev)) {
807051924fSEli Billauer 		dev_err(endpoint->dev,
817051924fSEli Billauer 			"Failed to enable MSI interrupts. Aborting.\n");
827051924fSEli Billauer 		return -ENODEV;
837051924fSEli Billauer 	}
847051924fSEli Billauer 	rc = devm_request_irq(&pdev->dev, pdev->irq, xillybus_isr, 0,
857051924fSEli Billauer 			      xillyname, endpoint);
867051924fSEli Billauer 	if (rc) {
877051924fSEli Billauer 		dev_err(endpoint->dev,
887051924fSEli Billauer 			"Failed to register MSI handler. Aborting.\n");
897051924fSEli Billauer 		return -ENODEV;
907051924fSEli Billauer 	}
917051924fSEli Billauer 
927051924fSEli Billauer 	/*
936497a875SEli Billauer 	 * Some (old and buggy?) hardware drops 64-bit addressed PCIe packets,
946497a875SEli Billauer 	 * even when the PCIe driver claims that a 64-bit mask is OK. On the
956497a875SEli Billauer 	 * other hand, on some architectures, 64-bit addressing is mandatory.
966497a875SEli Billauer 	 * So go for the 64-bit mask only when failing is the other option.
977051924fSEli Billauer 	 */
987051924fSEli Billauer 
99b46f7d33SChristophe JAILLET 	if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
1007051924fSEli Billauer 		endpoint->dma_using_dac = 0;
101b46f7d33SChristophe JAILLET 	} else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) {
1026497a875SEli Billauer 		endpoint->dma_using_dac = 1;
1037051924fSEli Billauer 	} else {
1047051924fSEli Billauer 		dev_err(endpoint->dev, "Failed to set DMA mask. Aborting.\n");
1057051924fSEli Billauer 		return -ENODEV;
1067051924fSEli Billauer 	}
1077051924fSEli Billauer 
1087051924fSEli Billauer 	return xillybus_endpoint_discovery(endpoint);
1097051924fSEli Billauer }
1107051924fSEli Billauer 
xilly_remove(struct pci_dev * pdev)1117051924fSEli Billauer static void xilly_remove(struct pci_dev *pdev)
1127051924fSEli Billauer {
1137051924fSEli Billauer 	struct xilly_endpoint *endpoint = pci_get_drvdata(pdev);
1147051924fSEli Billauer 
1157051924fSEli Billauer 	xillybus_endpoint_remove(endpoint);
1167051924fSEli Billauer }
1177051924fSEli Billauer 
1187051924fSEli Billauer MODULE_DEVICE_TABLE(pci, xillyids);
1197051924fSEli Billauer 
1207051924fSEli Billauer static struct pci_driver xillybus_driver = {
1217051924fSEli Billauer 	.name = xillyname,
1227051924fSEli Billauer 	.id_table = xillyids,
1237051924fSEli Billauer 	.probe = xilly_probe,
1247051924fSEli Billauer 	.remove = xilly_remove,
1257051924fSEli Billauer };
1267051924fSEli Billauer 
1277051924fSEli Billauer module_pci_driver(xillybus_driver);
128