cregit-Linux how code gets into the kernel

Release 4.7 drivers/xen/xen-pciback/vpci.c

/*
 * PCI Backend - Provides a Virtual PCI bus (with real devices)
 *               to the frontend
 *
 *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/list.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/mutex.h>
#include "pciback.h"


#define PCI_SLOT_MAX 32


struct vpci_dev_data {
	/* Access to dev_list must be protected by lock */
	
struct list_head dev_list[PCI_SLOT_MAX];
	
struct mutex lock;
};


static inline struct list_head *list_first(struct list_head *head) { return head->next; }

Contributors

PersonTokensPropCommitsCommitProp
konrad rzeszutek wilkkonrad rzeszutek wilk19100.00%1100.00%
Total19100.00%1100.00%


static struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, unsigned int domain, unsigned int bus, unsigned int devfn) { struct pci_dev_entry *entry; struct pci_dev *dev = NULL; struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; if (domain != 0 || bus != 0) return NULL; if (PCI_SLOT(devfn) < PCI_SLOT_MAX) { mutex_lock(&vpci_dev->lock); list_for_each_entry(entry, &vpci_dev->dev_list[PCI_SLOT(devfn)], list) { if (PCI_FUNC(entry->dev->devfn) == PCI_FUNC(devfn)) { dev = entry->dev; break; } } mutex_unlock(&vpci_dev->lock); } return dev; }

Contributors

PersonTokensPropCommitsCommitProp
konrad rzeszutek wilkkonrad rzeszutek wilk124100.00%4100.00%
Total124100.00%4100.00%


static inline int match_slot(struct pci_dev *l, struct pci_dev *r) { if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus) && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn)) return 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
konrad rzeszutek wilkkonrad rzeszutek wilk61100.00%1100.00%
Total61100.00%1100.00%


static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, struct pci_dev *dev, int devid, publish_pci_dev_cb publish_cb) { int err = 0, slot, func = -1; struct pci_dev_entry *t, *dev_entry; struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) { err = -EFAULT; xenbus_dev_fatal(pdev->xdev, err, "Can't export bridges on the virtual PCI bus"); goto out; } dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL); if (!dev_entry) { err = -ENOMEM; xenbus_dev_fatal(pdev->xdev, err, "Error adding entry to virtual PCI bus"); goto out; } dev_entry->dev = dev; mutex_lock(&vpci_dev->lock); /* * Keep multi-function devices together on the virtual PCI bus, except * virtual functions. */ if (!dev->is_virtfn) { for (slot = 0; slot < PCI_SLOT_MAX; slot++) { if (list_empty(&vpci_dev->dev_list[slot])) continue; t = list_entry(list_first(&vpci_dev->dev_list[slot]), struct pci_dev_entry, list); if (match_slot(dev, t->dev)) { pr_info("vpci: %s: assign to virtual slot %d func %d\n", pci_name(dev), slot, PCI_FUNC(dev->devfn)); list_add_tail(&dev_entry->list, &vpci_dev->dev_list[slot]); func = PCI_FUNC(dev->devfn); goto unlock; } } } /* Assign to a new slot on the virtual PCI bus */ for (slot = 0; slot < PCI_SLOT_MAX; slot++) { if (list_empty(&vpci_dev->dev_list[slot])) { pr_info("vpci: %s: assign to virtual slot %d\n", pci_name(dev), slot); list_add_tail(&dev_entry->list, &vpci_dev->dev_list[slot]); func = dev->is_virtfn ? 0 : PCI_FUNC(dev->devfn); goto unlock; } } err = -ENOMEM; xenbus_dev_fatal(pdev->xdev, err, "No more space on root virtual PCI bus"); unlock: mutex_unlock(&vpci_dev->lock); /* Publish this device. */ if (!err) err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, func), devid); else kfree(dev_entry); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
konrad rzeszutek wilkkonrad rzeszutek wilk36692.19%457.14%
laszlo erseklaszlo ersek164.03%114.29%
joe perchesjoe perches92.27%114.29%
daeseok youndaeseok youn61.51%114.29%
Total397100.00%7100.00%


static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, struct pci_dev *dev, bool lock) { int slot; struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; struct pci_dev *found_dev = NULL; mutex_lock(&vpci_dev->lock); for (slot = 0; slot < PCI_SLOT_MAX; slot++) { struct pci_dev_entry *e; list_for_each_entry(e, &vpci_dev->dev_list[slot], list) { if (e->dev == dev) { list_del(&e->list); found_dev = e->dev; kfree(e); goto out; } } } out: mutex_unlock(&vpci_dev->lock); if (found_dev) { if (lock) device_lock(&found_dev->dev); pcistub_put_pci_dev(found_dev); if (lock) device_unlock(&found_dev->dev); } }

Contributors

PersonTokensPropCommitsCommitProp
konrad rzeszutek wilkkonrad rzeszutek wilk15299.35%583.33%
jan beulichjan beulich10.65%116.67%
Total153100.00%6100.00%


static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev) { int slot; struct vpci_dev_data *vpci_dev; vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL); if (!vpci_dev) return -ENOMEM; mutex_init(&vpci_dev->lock); for (slot = 0; slot < PCI_SLOT_MAX; slot++) INIT_LIST_HEAD(&vpci_dev->dev_list[slot]); pdev->pci_dev_data = vpci_dev; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
konrad rzeszutek wilkkonrad rzeszutek wilk82100.00%4100.00%
Total82100.00%4100.00%


static int __xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev, publish_pci_root_cb publish_cb) { /* The Virtual PCI bus has only one root */ return publish_cb(pdev, 0, 0); }

Contributors

PersonTokensPropCommitsCommitProp
konrad rzeszutek wilkkonrad rzeszutek wilk25100.00%3100.00%
Total25100.00%3100.00%


static void __xen_pcibk_release_devices(struct xen_pcibk_device *pdev) { int slot; struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; for (slot = 0; slot < PCI_SLOT_MAX; slot++) { struct pci_dev_entry *e, *tmp; list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot], list) { struct pci_dev *dev = e->dev; list_del(&e->list); device_lock(&dev->dev); pcistub_put_pci_dev(dev); device_unlock(&dev->dev); kfree(e); } } kfree(vpci_dev); pdev->pci_dev_data = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
konrad rzeszutek wilkkonrad rzeszutek wilk112100.00%4100.00%
Total112100.00%4100.00%


static int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, struct xen_pcibk_device *pdev, unsigned int *domain, unsigned int *bus, unsigned int *devfn) { struct pci_dev_entry *entry; struct pci_dev *dev = NULL; struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; int found = 0, slot; mutex_lock(&vpci_dev->lock); for (slot = 0; slot < PCI_SLOT_MAX; slot++) { list_for_each_entry(entry, &vpci_dev->dev_list[slot], list) { dev = entry->dev; if (dev && dev->bus->number == pcidev->bus->number && pci_domain_nr(dev->bus) == pci_domain_nr(pcidev->bus) && dev->devfn == pcidev->devfn) { found = 1; *domain = 0; *bus = 0; *devfn = PCI_DEVFN(slot, PCI_FUNC(pcidev->devfn)); } } } mutex_unlock(&vpci_dev->lock); return found; }

Contributors

PersonTokensPropCommitsCommitProp
konrad rzeszutek wilkkonrad rzeszutek wilk17799.44%480.00%
dan carpenterdan carpenter10.56%120.00%
Total178100.00%5100.00%

const struct xen_pcibk_backend xen_pcibk_vpci_backend = { .name = "vpci", .init = __xen_pcibk_init_devices, .free = __xen_pcibk_release_devices, .find = __xen_pcibk_get_pcifront_dev, .publish = __xen_pcibk_publish_pci_roots, .release = __xen_pcibk_release_pci_dev, .add = __xen_pcibk_add_pci_dev, .get = __xen_pcibk_get_pci_dev, };

Overall Contributors

PersonTokensPropCommitsCommitProp
konrad rzeszutek wilkkonrad rzeszutek wilk120196.70%550.00%
joe perchesjoe perches161.29%110.00%
laszlo erseklaszlo ersek161.29%110.00%
daeseok youndaeseok youn60.48%110.00%
jan beulichjan beulich20.16%110.00%
dan carpenterdan carpenter10.08%110.00%
Total1242100.00%10100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}