pci-host-generic.c 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Simple, generic PCI host controller driver targeting firmware-initialised
  4. * systems and virtual machines (e.g. the PCI emulation provided by kvmtool).
  5. *
  6. * Copyright (C) 2014 ARM Limited
  7. *
  8. * Author: Will Deacon <[email protected]>
  9. */
  10. #include <linux/kernel.h>
  11. #include <linux/init.h>
  12. #include <linux/module.h>
  13. #include <linux/pci-ecam.h>
  14. #include <linux/platform_device.h>
  15. static const struct pci_ecam_ops gen_pci_cfg_cam_bus_ops = {
  16. .bus_shift = 16,
  17. .pci_ops = {
  18. .map_bus = pci_ecam_map_bus,
  19. .read = pci_generic_config_read,
  20. .write = pci_generic_config_write,
  21. }
  22. };
  23. static bool pci_dw_valid_device(struct pci_bus *bus, unsigned int devfn)
  24. {
  25. struct pci_config_window *cfg = bus->sysdata;
  26. /*
  27. * The Synopsys DesignWare PCIe controller in ECAM mode will not filter
  28. * type 0 config TLPs sent to devices 1 and up on its downstream port,
  29. * resulting in devices appearing multiple times on bus 0 unless we
  30. * filter out those accesses here.
  31. */
  32. if (bus->number == cfg->busr.start && PCI_SLOT(devfn) > 0)
  33. return false;
  34. return true;
  35. }
  36. static void __iomem *pci_dw_ecam_map_bus(struct pci_bus *bus,
  37. unsigned int devfn, int where)
  38. {
  39. if (!pci_dw_valid_device(bus, devfn))
  40. return NULL;
  41. return pci_ecam_map_bus(bus, devfn, where);
  42. }
  43. static const struct pci_ecam_ops pci_dw_ecam_bus_ops = {
  44. .pci_ops = {
  45. .map_bus = pci_dw_ecam_map_bus,
  46. .read = pci_generic_config_read,
  47. .write = pci_generic_config_write,
  48. }
  49. };
  50. static const struct of_device_id gen_pci_of_match[] = {
  51. { .compatible = "pci-host-cam-generic",
  52. .data = &gen_pci_cfg_cam_bus_ops },
  53. { .compatible = "pci-host-ecam-generic",
  54. .data = &pci_generic_ecam_ops },
  55. { .compatible = "marvell,armada8k-pcie-ecam",
  56. .data = &pci_dw_ecam_bus_ops },
  57. { .compatible = "socionext,synquacer-pcie-ecam",
  58. .data = &pci_dw_ecam_bus_ops },
  59. { .compatible = "snps,dw-pcie-ecam",
  60. .data = &pci_dw_ecam_bus_ops },
  61. { },
  62. };
  63. MODULE_DEVICE_TABLE(of, gen_pci_of_match);
  64. static struct platform_driver gen_pci_driver = {
  65. .driver = {
  66. .name = "pci-host-generic",
  67. .of_match_table = gen_pci_of_match,
  68. },
  69. .probe = pci_host_common_probe,
  70. .remove = pci_host_common_remove,
  71. };
  72. module_platform_driver(gen_pci_driver);
  73. MODULE_LICENSE("GPL v2");