pci.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /*
  2. * Copyright (c) 2009, Intel Corporation.
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms and conditions of the GNU General Public License,
  6. * version 2, as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope it will be useful, but WITHOUT
  9. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  11. * more details.
  12. *
  13. * You should have received a copy of the GNU General Public License along with
  14. * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  15. * Place - Suite 330, Boston, MA 02111-1307 USA.
  16. *
  17. * Author: Weidong Han <weidong.han@intel.com>
  18. */
  19. #include <linux/pci.h>
  20. #include <xen/xen.h>
  21. #include <xen/interface/physdev.h>
  22. #include <xen/interface/xen.h>
  23. #include <asm/xen/hypervisor.h>
  24. #include <asm/xen/hypercall.h>
  25. #include "../pci/pci.h"
  26. static int xen_add_device(struct device *dev)
  27. {
  28. int r;
  29. struct pci_dev *pci_dev = to_pci_dev(dev);
  30. #ifdef CONFIG_PCI_IOV
  31. if (pci_dev->is_virtfn) {
  32. struct physdev_manage_pci_ext manage_pci_ext = {
  33. .bus = pci_dev->bus->number,
  34. .devfn = pci_dev->devfn,
  35. .is_virtfn = 1,
  36. .physfn.bus = pci_dev->physfn->bus->number,
  37. .physfn.devfn = pci_dev->physfn->devfn,
  38. };
  39. r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext,
  40. &manage_pci_ext);
  41. } else
  42. #endif
  43. if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) {
  44. struct physdev_manage_pci_ext manage_pci_ext = {
  45. .bus = pci_dev->bus->number,
  46. .devfn = pci_dev->devfn,
  47. .is_extfn = 1,
  48. };
  49. r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext,
  50. &manage_pci_ext);
  51. } else {
  52. struct physdev_manage_pci manage_pci = {
  53. .bus = pci_dev->bus->number,
  54. .devfn = pci_dev->devfn,
  55. };
  56. r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add,
  57. &manage_pci);
  58. }
  59. return r;
  60. }
  61. static int xen_remove_device(struct device *dev)
  62. {
  63. int r;
  64. struct pci_dev *pci_dev = to_pci_dev(dev);
  65. struct physdev_manage_pci manage_pci;
  66. manage_pci.bus = pci_dev->bus->number;
  67. manage_pci.devfn = pci_dev->devfn;
  68. r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_remove,
  69. &manage_pci);
  70. return r;
  71. }
  72. static int xen_pci_notifier(struct notifier_block *nb,
  73. unsigned long action, void *data)
  74. {
  75. struct device *dev = data;
  76. int r = 0;
  77. switch (action) {
  78. case BUS_NOTIFY_ADD_DEVICE:
  79. r = xen_add_device(dev);
  80. break;
  81. case BUS_NOTIFY_DEL_DEVICE:
  82. r = xen_remove_device(dev);
  83. break;
  84. default:
  85. break;
  86. }
  87. return r;
  88. }
  89. struct notifier_block device_nb = {
  90. .notifier_call = xen_pci_notifier,
  91. };
  92. static int __init register_xen_pci_notifier(void)
  93. {
  94. if (!xen_initial_domain())
  95. return 0;
  96. return bus_register_notifier(&pci_bus_type, &device_nb);
  97. }
  98. arch_initcall(register_xen_pci_notifier);