linux/drivers/xen/pci.c
<<
>>
Prefs
   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
  20#include <linux/pci.h>
  21#include <xen/xen.h>
  22#include <xen/interface/physdev.h>
  23#include <xen/interface/xen.h>
  24
  25#include <asm/xen/hypervisor.h>
  26#include <asm/xen/hypercall.h>
  27#include "../pci/pci.h"
  28
  29static int xen_add_device(struct device *dev)
  30{
  31        int r;
  32        struct pci_dev *pci_dev = to_pci_dev(dev);
  33
  34#ifdef CONFIG_PCI_IOV
  35        if (pci_dev->is_virtfn) {
  36                struct physdev_manage_pci_ext manage_pci_ext = {
  37                        .bus            = pci_dev->bus->number,
  38                        .devfn          = pci_dev->devfn,
  39                        .is_virtfn      = 1,
  40                        .physfn.bus     = pci_dev->physfn->bus->number,
  41                        .physfn.devfn   = pci_dev->physfn->devfn,
  42                };
  43
  44                r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext,
  45                        &manage_pci_ext);
  46        } else
  47#endif
  48        if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) {
  49                struct physdev_manage_pci_ext manage_pci_ext = {
  50                        .bus            = pci_dev->bus->number,
  51                        .devfn          = pci_dev->devfn,
  52                        .is_extfn       = 1,
  53                };
  54
  55                r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add_ext,
  56                        &manage_pci_ext);
  57        } else {
  58                struct physdev_manage_pci manage_pci = {
  59                        .bus    = pci_dev->bus->number,
  60                        .devfn  = pci_dev->devfn,
  61                };
  62
  63                r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_add,
  64                        &manage_pci);
  65        }
  66
  67        return r;
  68}
  69
  70static int xen_remove_device(struct device *dev)
  71{
  72        int r;
  73        struct pci_dev *pci_dev = to_pci_dev(dev);
  74        struct physdev_manage_pci manage_pci;
  75
  76        manage_pci.bus = pci_dev->bus->number;
  77        manage_pci.devfn = pci_dev->devfn;
  78
  79        r = HYPERVISOR_physdev_op(PHYSDEVOP_manage_pci_remove,
  80                &manage_pci);
  81
  82        return r;
  83}
  84
  85static int xen_pci_notifier(struct notifier_block *nb,
  86                            unsigned long action, void *data)
  87{
  88        struct device *dev = data;
  89        int r = 0;
  90
  91        switch (action) {
  92        case BUS_NOTIFY_ADD_DEVICE:
  93                r = xen_add_device(dev);
  94                break;
  95        case BUS_NOTIFY_DEL_DEVICE:
  96                r = xen_remove_device(dev);
  97                break;
  98        default:
  99                break;
 100        }
 101
 102        return r;
 103}
 104
 105struct notifier_block device_nb = {
 106        .notifier_call = xen_pci_notifier,
 107};
 108
 109static int __init register_xen_pci_notifier(void)
 110{
 111        if (!xen_initial_domain())
 112                return 0;
 113
 114        return bus_register_notifier(&pci_bus_type, &device_nb);
 115}
 116
 117arch_initcall(register_xen_pci_notifier);
 118