pci-host-generic.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  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 <will.deacon@arm.com>
  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. .bus_shift = 20,
  45. .pci_ops = {
  46. .map_bus = pci_dw_ecam_map_bus,
  47. .read = pci_generic_config_read,
  48. .write = pci_generic_config_write,
  49. }
  50. };
  51. static const struct of_device_id gen_pci_of_match[] = {
  52. { .compatible = "pci-host-cam-generic",
  53. .data = &gen_pci_cfg_cam_bus_ops },
  54. { .compatible = "pci-host-ecam-generic",
  55. .data = &pci_generic_ecam_ops },
  56. { .compatible = "marvell,armada8k-pcie-ecam",
  57. .data = &pci_dw_ecam_bus_ops },
  58. { .compatible = "socionext,synquacer-pcie-ecam",
  59. .data = &pci_dw_ecam_bus_ops },
  60. { .compatible = "snps,dw-pcie-ecam",
  61. .data = &pci_dw_ecam_bus_ops },
  62. { },
  63. };
  64. MODULE_DEVICE_TABLE(of, gen_pci_of_match);
  65. static struct platform_driver gen_pci_driver = {
  66. .driver = {
  67. .name = "pci-host-generic",
  68. .of_match_table = gen_pci_of_match,
  69. },
  70. .probe = pci_host_common_probe,
  71. .remove = pci_host_common_remove,
  72. };
  73. module_platform_driver(gen_pci_driver);
  74. MODULE_LICENSE("GPL v2");