Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 204781
b: refs/heads/master
c: 183d03c
h: refs/heads/master
i:
  204779: 9ee08d3
v: v3
  • Loading branch information
Stefano Stabellini authored and Jeremy Fitzhardinge committed Jul 22, 2010
1 parent 4783c0c commit 97527dc
Show file tree
Hide file tree
Showing 11 changed files with 292 additions and 19 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 38e20b07efd541a959de367dc90a17f92ce2e8a6
refs/heads/master: 183d03cc4ff39e0f0d952c09aa96d0abfd6e0c3c
9 changes: 9 additions & 0 deletions trunk/drivers/xen/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,13 @@ config XEN_SYS_HYPERVISOR
virtual environment, /sys/hypervisor will still be present,
but will have no xen contents.

config XEN_PLATFORM_PCI
tristate "xen platform pci device driver"
depends on XEN
default m
help
Driver for the Xen PCI Platform device: it is responsible for
initializing xenbus and grant_table when running in a Xen HVM
domain. As a consequence this driver is required to run any Xen PV
frontend on Xen HVM.
endmenu
3 changes: 2 additions & 1 deletion trunk/drivers/xen/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
obj-$(CONFIG_XEN_BALLOON) += balloon.o
obj-$(CONFIG_XEN_DEV_EVTCHN) += evtchn.o
obj-$(CONFIG_XENFS) += xenfs/
obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o
8 changes: 6 additions & 2 deletions trunk/drivers/xen/events.c
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,7 @@ static void __xen_evtchn_do_upcall(void)

count = __get_cpu_var(xed_nesting_count);
__get_cpu_var(xed_nesting_count) = 0;
} while(count != 1);
} while (count != 1 || vcpu_info->evtchn_upcall_pending);

out:

Expand All @@ -689,6 +689,7 @@ void xen_hvm_evtchn_do_upcall(void)
{
__xen_evtchn_do_upcall();
}
EXPORT_SYMBOL_GPL(xen_hvm_evtchn_do_upcall);

/* Rebind a new event channel to an existing irq. */
void rebind_evtchn_irq(int evtchn, int irq)
Expand Down Expand Up @@ -725,7 +726,10 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
struct evtchn_bind_vcpu bind_vcpu;
int evtchn = evtchn_from_irq(irq);

if (!VALID_EVTCHN(evtchn))
/* events delivered via platform PCI interrupts are always
* routed to vcpu 0 */
if (!VALID_EVTCHN(evtchn) ||
(xen_hvm_domain() && !xen_have_vector_callback))
return -1;

/* Send future instances of this interrupt to other vcpu. */
Expand Down
77 changes: 67 additions & 10 deletions trunk/drivers/xen/grant-table.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/uaccess.h>
#include <linux/io.h>

#include <xen/xen.h>
#include <xen/interface/xen.h>
#include <xen/page.h>
#include <xen/grant_table.h>
#include <xen/interface/memory.h>
#include <asm/xen/hypercall.h>

#include <asm/pgtable.h>
Expand All @@ -59,6 +61,8 @@ static unsigned int boot_max_nr_grant_frames;
static int gnttab_free_count;
static grant_ref_t gnttab_free_head;
static DEFINE_SPINLOCK(gnttab_list_lock);
unsigned long xen_hvm_resume_frames;
EXPORT_SYMBOL_GPL(xen_hvm_resume_frames);

static struct grant_entry *shared;

Expand Down Expand Up @@ -433,14 +437,15 @@ static unsigned int __max_nr_grant_frames(void)
return query.max_nr_frames;
}

static inline unsigned int max_nr_grant_frames(void)
unsigned int gnttab_max_grant_frames(void)
{
unsigned int xen_max = __max_nr_grant_frames();

if (xen_max > boot_max_nr_grant_frames)
return boot_max_nr_grant_frames;
return xen_max;
}
EXPORT_SYMBOL_GPL(gnttab_max_grant_frames);

static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
{
Expand All @@ -449,6 +454,30 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
unsigned int nr_gframes = end_idx + 1;
int rc;

if (xen_hvm_domain()) {
struct xen_add_to_physmap xatp;
unsigned int i = end_idx;
rc = 0;
/*
* Loop backwards, so that the first hypercall has the largest
* index, ensuring that the table will grow only once.
*/
do {
xatp.domid = DOMID_SELF;
xatp.idx = i;
xatp.space = XENMAPSPACE_grant_table;
xatp.gpfn = (xen_hvm_resume_frames >> PAGE_SHIFT) + i;
rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp);
if (rc != 0) {
printk(KERN_WARNING
"grant table add_to_physmap failed, err=%d\n", rc);
break;
}
} while (i-- > start_idx);

return rc;
}

frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC);
if (!frames)
return -ENOMEM;
Expand All @@ -465,7 +494,7 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)

BUG_ON(rc || setup.status);

rc = arch_gnttab_map_shared(frames, nr_gframes, max_nr_grant_frames(),
rc = arch_gnttab_map_shared(frames, nr_gframes, gnttab_max_grant_frames(),
&shared);
BUG_ON(rc);

Expand All @@ -476,9 +505,27 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)

int gnttab_resume(void)
{
if (max_nr_grant_frames() < nr_grant_frames)
unsigned int max_nr_gframes;

max_nr_gframes = gnttab_max_grant_frames();
if (max_nr_gframes < nr_grant_frames)
return -ENOSYS;
return gnttab_map(0, nr_grant_frames - 1);

if (xen_pv_domain())
return gnttab_map(0, nr_grant_frames - 1);

if (!shared) {
shared = ioremap(xen_hvm_resume_frames, PAGE_SIZE * max_nr_gframes);
if (shared == NULL) {
printk(KERN_WARNING
"Failed to ioremap gnttab share frames!");
return -ENOMEM;
}
}

gnttab_map(0, nr_grant_frames - 1);

return 0;
}

int gnttab_suspend(void)
Expand All @@ -495,7 +542,7 @@ static int gnttab_expand(unsigned int req_entries)
cur = nr_grant_frames;
extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) /
GREFS_PER_GRANT_FRAME);
if (cur + extra > max_nr_grant_frames())
if (cur + extra > gnttab_max_grant_frames())
return -ENOSPC;

rc = gnttab_map(cur, cur + extra - 1);
Expand All @@ -505,15 +552,12 @@ static int gnttab_expand(unsigned int req_entries)
return rc;
}

static int __devinit gnttab_init(void)
int gnttab_init(void)
{
int i;
unsigned int max_nr_glist_frames, nr_glist_frames;
unsigned int nr_init_grefs;

if (!xen_domain())
return -ENODEV;

nr_grant_frames = 1;
boot_max_nr_grant_frames = __max_nr_grant_frames();

Expand Down Expand Up @@ -556,5 +600,18 @@ static int __devinit gnttab_init(void)
kfree(gnttab_list);
return -ENOMEM;
}
EXPORT_SYMBOL_GPL(gnttab_init);

static int __devinit __gnttab_init(void)
{
/* Delay grant-table initialization in the PV on HVM case */
if (xen_hvm_domain())
return 0;

if (!xen_pv_domain())
return -ENODEV;

return gnttab_init();
}

core_initcall(gnttab_init);
core_initcall(__gnttab_init);
1 change: 1 addition & 0 deletions trunk/drivers/xen/manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,5 +264,6 @@ static int __init setup_shutdown_event(void)

return 0;
}
EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);

subsys_initcall(setup_shutdown_event);
181 changes: 181 additions & 0 deletions trunk/drivers/xen/platform-pci.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/******************************************************************************
* platform-pci.c
*
* Xen platform PCI device driver
* Copyright (c) 2005, Intel Corporation.
* Copyright (c) 2007, XenSource Inc.
* Copyright (c) 2010, Citrix
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
*
*/


#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/pci.h>

#include <xen/grant_table.h>
#include <xen/xenbus.h>
#include <xen/events.h>
#include <xen/hvm.h>

#define DRV_NAME "xen-platform-pci"

MODULE_AUTHOR("ssmith@xensource.com and stefano.stabellini@eu.citrix.com");
MODULE_DESCRIPTION("Xen platform PCI device");
MODULE_LICENSE("GPL");

static unsigned long platform_mmio;
static unsigned long platform_mmio_alloc;
static unsigned long platform_mmiolen;

unsigned long alloc_xen_mmio(unsigned long len)
{
unsigned long addr;

addr = platform_mmio + platform_mmio_alloc;
platform_mmio_alloc += len;
BUG_ON(platform_mmio_alloc > platform_mmiolen);

return addr;
}

static uint64_t get_callback_via(struct pci_dev *pdev)
{
u8 pin;
int irq;

irq = pdev->irq;
if (irq < 16)
return irq; /* ISA IRQ */

pin = pdev->pin;

/* We don't know the GSI. Specify the PCI INTx line instead. */
return ((uint64_t)0x01 << 56) | /* PCI INTx identifier */
((uint64_t)pci_domain_nr(pdev->bus) << 32) |
((uint64_t)pdev->bus->number << 16) |
((uint64_t)(pdev->devfn & 0xff) << 8) |
((uint64_t)(pin - 1) & 3);
}

static irqreturn_t do_hvm_evtchn_intr(int irq, void *dev_id)
{
xen_hvm_evtchn_do_upcall();
return IRQ_HANDLED;
}

static int xen_allocate_irq(struct pci_dev *pdev)
{
return request_irq(pdev->irq, do_hvm_evtchn_intr,
IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TRIGGER_RISING,
"xen-platform-pci", pdev);
}

static int __devinit platform_pci_init(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
int i, ret;
long ioaddr, iolen;
long mmio_addr, mmio_len;
uint64_t callback_via;
unsigned int max_nr_gframes;

i = pci_enable_device(pdev);
if (i)
return i;

ioaddr = pci_resource_start(pdev, 0);
iolen = pci_resource_len(pdev, 0);

mmio_addr = pci_resource_start(pdev, 1);
mmio_len = pci_resource_len(pdev, 1);

if (mmio_addr == 0 || ioaddr == 0) {
dev_err(&pdev->dev, "no resources found\n");
ret = -ENOENT;
goto pci_out;
}

if (request_mem_region(mmio_addr, mmio_len, DRV_NAME) == NULL) {
dev_err(&pdev->dev, "MEM I/O resource 0x%lx @ 0x%lx busy\n",
mmio_addr, mmio_len);
ret = -EBUSY;
goto pci_out;
}

if (request_region(ioaddr, iolen, DRV_NAME) == NULL) {
dev_err(&pdev->dev, "I/O resource 0x%lx @ 0x%lx busy\n",
iolen, ioaddr);
ret = -EBUSY;
goto mem_out;
}

platform_mmio = mmio_addr;
platform_mmiolen = mmio_len;

if (!xen_have_vector_callback) {
ret = xen_allocate_irq(pdev);
if (ret) {
dev_warn(&pdev->dev, "request_irq failed err=%d\n", ret);
goto out;
}
callback_via = get_callback_via(pdev);
ret = xen_set_callback_via(callback_via);
if (ret) {
dev_warn(&pdev->dev, "Unable to set the evtchn callback "
"err=%d\n", ret);
goto out;
}
}

max_nr_gframes = gnttab_max_grant_frames();
xen_hvm_resume_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes);
ret = gnttab_init();
if (ret)
goto out;
xenbus_probe(NULL);
return 0;

out:
release_region(ioaddr, iolen);
mem_out:
release_mem_region(mmio_addr, mmio_len);
pci_out:
pci_disable_device(pdev);
return ret;
}

static struct pci_device_id platform_pci_tbl[] __devinitdata = {
{PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0,}
};

MODULE_DEVICE_TABLE(pci, platform_pci_tbl);

static struct pci_driver platform_driver = {
.name = DRV_NAME,
.probe = platform_pci_init,
.id_table = platform_pci_tbl,
};

static int __init platform_pci_module_init(void)
{
return pci_register_driver(&platform_driver);
}

module_init(platform_pci_module_init);
Loading

0 comments on commit 97527dc

Please sign in to comment.