]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
driver, pci: add functions to add/del devices to/from root-cell
authorHenning Schild <henning.schild@siemens.com>
Wed, 26 Nov 2014 18:04:01 +0000 (19:04 +0100)
committerJan Kiszka <jan.kiszka@siemens.com>
Wed, 26 Nov 2014 18:14:50 +0000 (19:14 +0100)
This patch introduces functions to add or remove PCI devices in the root
cell. The functions are not called yet, the patch prepares for virtual
PCI devices.
The original idea was to remove PCI devices from Linux on cell create
and re-add them on cell destroy. But in this case Linux could reprogram
the BARs so we ignore regular PCI devices for now.

Signed-off-by: Henning Schild <henning.schild@siemens.com>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
driver.c

index 00dda9a96ff114986aa55ed74735a15be42e9b61..cb76370f55882a1cc2be89a1fb84235e6bd144d7 100644 (file)
--- a/driver.c
+++ b/driver.c
@@ -26,6 +26,7 @@
 #include <linux/reboot.h>
 #include <linux/vmalloc.h>
 #include <linux/io.h>
+#include <linux/pci.h>
 #include <asm/smp.h>
 #include <asm/cacheflush.h>
 
@@ -97,7 +98,9 @@ struct cell {
        unsigned int id;
        cpumask_t cpus_assigned;
        u32 num_memory_regions;
+       u32 num_pci_devices;
        struct jailhouse_memory *memory_regions;
+       struct jailhouse_pci_device *pci_devices;
 };
 
 MODULE_DESCRIPTION("Loader for Jailhouse partitioning hypervisor");
@@ -137,6 +140,59 @@ static void init_hypercall(void)
 }
 #endif
 
+enum { JAILHOUSE_PCI_ACTION_ADD, JAILHOUSE_PCI_ACTION_DEL };
+
+#ifdef CONFIG_PCI
+static void jailhouse_pci_add_device(const struct jailhouse_pci_device *dev)
+{
+       int num;
+       struct pci_bus *bus;
+
+       bus = pci_find_bus(dev->domain, PCI_BUS_NUM(dev->bdf));
+       if (bus) {
+               num = pci_scan_slot(bus, dev->bdf & 0xff);
+               if (num) {
+                       pci_lock_rescan_remove();
+                       pci_bus_assign_resources(bus);
+                       pci_bus_add_devices(bus);
+                       pci_unlock_rescan_remove();
+               }
+       }
+}
+
+static void jailhouse_pci_remove_device(const struct jailhouse_pci_device *dev)
+{
+       struct pci_dev *l_dev;
+
+       l_dev = pci_get_bus_and_slot(PCI_BUS_NUM(dev->bdf), dev->bdf & 0xff);
+       if (l_dev)
+               pci_stop_and_remove_bus_device_locked(l_dev);
+}
+
+static void jailhouse_pci_do_all_devices(struct cell *cell, unsigned int type,
+                                        unsigned int action)
+{
+       unsigned int n;
+       const struct jailhouse_pci_device *dev;
+
+       dev = cell->pci_devices;
+       for (n = cell->num_pci_devices; n > 0; n--) {
+               if (dev->type == type) {
+                       if (action == JAILHOUSE_PCI_ACTION_ADD)
+                               jailhouse_pci_add_device(dev);
+                       else if (action == JAILHOUSE_PCI_ACTION_DEL)
+                               jailhouse_pci_remove_device(dev);
+               }
+               dev++;
+       }
+}
+#else /* CONFIG_PCI */
+static void jailhouse_pci_do_all_devices(struct cell *cell, unsigned int type,
+                                        unsigned int action)
+{
+}
+#endif /* CONFIG_PCI */
+
 struct jailhouse_cpu_stats_attr {
        struct kobj_attribute kattr;
        unsigned int code;
@@ -287,6 +343,7 @@ static void cell_kobj_release(struct kobject *kobj)
        struct cell *cell = container_of(kobj, struct cell, kobj);
 
        vfree(cell->memory_regions);
+       vfree(cell->pci_devices);
        kfree(cell);
 }
 
@@ -321,7 +378,19 @@ static struct cell *create_cell(const struct jailhouse_cell_desc *cell_desc)
 
        memcpy(cell->memory_regions, jailhouse_cell_mem_regions(cell_desc),
               sizeof(struct jailhouse_memory) * cell->num_memory_regions);
+#ifdef CONFIG_PCI
+       cell->num_pci_devices = cell_desc->num_pci_devices;
+       cell->pci_devices = vmalloc(sizeof(struct jailhouse_pci_device) *
+                                   cell->num_pci_devices);
+       if (cell->num_pci_devices && !cell->pci_devices) {
+               vfree(cell->memory_regions);
+               kfree(cell);
+               return ERR_PTR(-ENOMEM);
+       }
 
+       memcpy(cell->pci_devices, jailhouse_cell_pci_devices(cell_desc),
+              sizeof(struct jailhouse_pci_device) * cell->num_pci_devices);
+#endif
        err = kobject_init_and_add(&cell->kobj, &cell_type, cells_dir, "%s",
                                   cell_desc->name);
        if (err) {