mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
merge with xen-unstable.hg
This commit is contained in:
commit
71c2db7e6e
36 files changed
+602
-435
No files matched your search
@@ -75,7 +75,9 @@ $(LINUX_DIR)/include/linux/autoconf.h: $(LINUX_SRCDIR)/.valid-src
|
||||
# tree. Finally attempt to use make defconfig.
|
||||
set -e ; \
|
||||
CONFIG_VERSION=$$(sed -ne 's/$$(XENGUEST)//; s/^EXTRAVERSION = //p' $(LINUX_SRCDIR)/Makefile); \
|
||||
if [ -r $(DESTDIR)/boot/config-$(LINUX_VER3)$$CONFIG_VERSION$(EXTRAVERSION) ] ; then \
|
||||
if [ ! -z "$(XEN_LINUX_CONFIG)" -a -r $(XEN_LINUX_CONFIG) ]; then \
|
||||
cp $(XEN_LINUX_CONFIG) $(CONFIG_FILE); \
|
||||
elif [ -r $(DESTDIR)/boot/config-$(LINUX_VER3)$$CONFIG_VERSION$(EXTRAVERSION) ] ; then \
|
||||
cp $(DESTDIR)/boot/config-$(LINUX_VER3)$$CONFIG_VERSION$(EXTRAVERSION) $(CONFIG_FILE) ; \
|
||||
elif [ -e $(LINUX_SRCDIR)/buildconfigs/create_config.sh ] ; then \
|
||||
cd $(LINUX_SRCDIR) && sh buildconfigs/create_config.sh \
|
||||
|
||||
@@ -54,13 +54,13 @@ static void *
|
||||
smbios_type_4_init(void *start, unsigned int cpu_number,
|
||||
char *cpu_manufacturer);
|
||||
static void *
|
||||
smbios_type_16_init(void *start, uint32_t memory_size_mb);
|
||||
smbios_type_16_init(void *start, uint32_t memory_size_mb, int nr_mem_devs);
|
||||
static void *
|
||||
smbios_type_17_init(void *start, uint32_t memory_size_mb);
|
||||
smbios_type_17_init(void *start, uint32_t memory_size_mb, int instance);
|
||||
static void *
|
||||
smbios_type_19_init(void *start, uint32_t memory_size_mb);
|
||||
smbios_type_19_init(void *start, uint32_t memory_size_mb, int instance);
|
||||
static void *
|
||||
smbios_type_20_init(void *start, uint32_t memory_size_mb);
|
||||
smbios_type_20_init(void *start, uint32_t memory_size_mb, int instance);
|
||||
static void *
|
||||
smbios_type_32_init(void *start);
|
||||
static void *
|
||||
@@ -92,6 +92,7 @@ write_smbios_tables(void *start,
|
||||
unsigned cpu_num, nr_structs = 0, max_struct_size = 0;
|
||||
char *p, *q;
|
||||
char cpu_manufacturer[15];
|
||||
int i, nr_mem_devs;
|
||||
|
||||
get_cpu_manufacturer(cpu_manufacturer, 15);
|
||||
|
||||
@@ -111,10 +112,19 @@ write_smbios_tables(void *start,
|
||||
do_struct(smbios_type_3_init(p));
|
||||
for ( cpu_num = 1; cpu_num <= vcpus; cpu_num++ )
|
||||
do_struct(smbios_type_4_init(p, cpu_num, cpu_manufacturer));
|
||||
do_struct(smbios_type_16_init(p, memsize));
|
||||
do_struct(smbios_type_17_init(p, memsize));
|
||||
do_struct(smbios_type_19_init(p, memsize));
|
||||
do_struct(smbios_type_20_init(p, memsize));
|
||||
|
||||
/* Each 'memory device' covers up to 16GB of address space. */
|
||||
nr_mem_devs = (memsize + 0x3fff) >> 14;
|
||||
do_struct(smbios_type_16_init(p, memsize, nr_mem_devs));
|
||||
for ( i = 0; i < nr_mem_devs; i++ )
|
||||
{
|
||||
uint32_t dev_memsize = ((i == (nr_mem_devs - 1))
|
||||
? (memsize & 0x3fff) : 0x4000);
|
||||
do_struct(smbios_type_17_init(p, dev_memsize, i));
|
||||
do_struct(smbios_type_19_init(p, dev_memsize, i));
|
||||
do_struct(smbios_type_20_init(p, dev_memsize, i));
|
||||
}
|
||||
|
||||
do_struct(smbios_type_32_init(p));
|
||||
do_struct(smbios_type_127_init(p));
|
||||
|
||||
@@ -441,7 +451,7 @@ smbios_type_4_init(
|
||||
|
||||
/* Type 16 -- Physical Memory Array */
|
||||
static void *
|
||||
smbios_type_16_init(void *start, uint32_t memsize)
|
||||
smbios_type_16_init(void *start, uint32_t memsize, int nr_mem_devs)
|
||||
{
|
||||
struct smbios_type_16 *p = (struct smbios_type_16*)start;
|
||||
|
||||
@@ -456,7 +466,7 @@ smbios_type_16_init(void *start, uint32_t memsize)
|
||||
p->error_correction = 0x01; /* other */
|
||||
p->maximum_capacity = memsize * 1024;
|
||||
p->memory_error_information_handle = 0xfffe; /* none provided */
|
||||
p->number_of_memory_devices = 1;
|
||||
p->number_of_memory_devices = nr_mem_devs;
|
||||
|
||||
start += sizeof(struct smbios_type_16);
|
||||
*((uint16_t *)start) = 0;
|
||||
@@ -465,22 +475,22 @@ smbios_type_16_init(void *start, uint32_t memsize)
|
||||
|
||||
/* Type 17 -- Memory Device */
|
||||
static void *
|
||||
smbios_type_17_init(void *start, uint32_t memory_size_mb)
|
||||
smbios_type_17_init(void *start, uint32_t memory_size_mb, int instance)
|
||||
{
|
||||
char buf[16];
|
||||
struct smbios_type_17 *p = (struct smbios_type_17 *)start;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
p->header.type = 17;
|
||||
p->header.length = sizeof(struct smbios_type_17);
|
||||
p->header.handle = 0x1100;
|
||||
p->header.handle = 0x1100 + instance;
|
||||
|
||||
p->physical_memory_array_handle = 0x1000;
|
||||
p->total_width = 64;
|
||||
p->data_width = 64;
|
||||
/* truncate memory_size_mb to 16 bits and clear most significant
|
||||
bit [indicates size in MB] */
|
||||
p->size = (uint16_t) memory_size_mb & 0x7fff;
|
||||
ASSERT((memory_size_mb & ~0x7fff) == 0);
|
||||
p->size = memory_size_mb;
|
||||
p->form_factor = 0x09; /* DIMM */
|
||||
p->device_set = 0;
|
||||
p->device_locator_str = 1;
|
||||
@@ -489,8 +499,11 @@ smbios_type_17_init(void *start, uint32_t memory_size_mb)
|
||||
p->type_detail = 0;
|
||||
|
||||
start += sizeof(struct smbios_type_17);
|
||||
strcpy((char *)start, "DIMM 1");
|
||||
start += strlen("DIMM 1") + 1;
|
||||
strcpy(start, "DIMM ");
|
||||
start += strlen("DIMM ");
|
||||
itoa(buf, instance);
|
||||
strcpy(start, buf);
|
||||
start += strlen(buf) + 1;
|
||||
*((uint8_t *)start) = 0;
|
||||
|
||||
return start+1;
|
||||
@@ -498,7 +511,7 @@ smbios_type_17_init(void *start, uint32_t memory_size_mb)
|
||||
|
||||
/* Type 19 -- Memory Array Mapped Address */
|
||||
static void *
|
||||
smbios_type_19_init(void *start, uint32_t memory_size_mb)
|
||||
smbios_type_19_init(void *start, uint32_t memory_size_mb, int instance)
|
||||
{
|
||||
struct smbios_type_19 *p = (struct smbios_type_19 *)start;
|
||||
|
||||
@@ -506,10 +519,10 @@ smbios_type_19_init(void *start, uint32_t memory_size_mb)
|
||||
|
||||
p->header.type = 19;
|
||||
p->header.length = sizeof(struct smbios_type_19);
|
||||
p->header.handle = 0x1300;
|
||||
p->header.handle = 0x1300 + instance;
|
||||
|
||||
p->starting_address = 0;
|
||||
p->ending_address = (memory_size_mb-1) * 1024;
|
||||
p->starting_address = instance << 24;
|
||||
p->ending_address = p->starting_address + (memory_size_mb << 10) - 1;
|
||||
p->memory_array_handle = 0x1000;
|
||||
p->partition_width = 1;
|
||||
|
||||
@@ -520,7 +533,7 @@ smbios_type_19_init(void *start, uint32_t memory_size_mb)
|
||||
|
||||
/* Type 20 -- Memory Device Mapped Address */
|
||||
static void *
|
||||
smbios_type_20_init(void *start, uint32_t memory_size_mb)
|
||||
smbios_type_20_init(void *start, uint32_t memory_size_mb, int instance)
|
||||
{
|
||||
struct smbios_type_20 *p = (struct smbios_type_20 *)start;
|
||||
|
||||
@@ -528,12 +541,12 @@ smbios_type_20_init(void *start, uint32_t memory_size_mb)
|
||||
|
||||
p->header.type = 20;
|
||||
p->header.length = sizeof(struct smbios_type_20);
|
||||
p->header.handle = 0x1400;
|
||||
p->header.handle = 0x1400 + instance;
|
||||
|
||||
p->starting_address = 0;
|
||||
p->ending_address = (memory_size_mb-1)*1024;
|
||||
p->memory_device_handle = 0x1100;
|
||||
p->memory_array_mapped_address_handle = 0x1300;
|
||||
p->starting_address = instance << 24;
|
||||
p->ending_address = p->starting_address + (memory_size_mb << 10) - 1;
|
||||
p->memory_device_handle = 0x1100 + instance;
|
||||
p->memory_array_mapped_address_handle = 0x1300 + instance;
|
||||
p->partition_row_position = 1;
|
||||
p->interleave_position = 0;
|
||||
p->interleaved_data_depth = 0;
|
||||
|
||||
@@ -33,7 +33,7 @@ define(`create_domain', `
|
||||
getvcpuinfo getaddrsize getvcpuaffinity};
|
||||
allow $1 $2:shadow {enable};
|
||||
allow $1 $2:mmu {map_read map_write memorymap adjust pinpage};
|
||||
allow $2 $2:mmu {map_read map_write pinpage};
|
||||
allow $2 $2:mmu {map_read map_write adjust pinpage};
|
||||
allow $2 domio_t:mmu {map_read};
|
||||
allow $2 $2:grant {query setup};
|
||||
allow $1 $2:grant {map_read unmap};
|
||||
@@ -110,6 +110,9 @@ allow dom0_t evchn0-U_t:event {send};
|
||||
create_channel(domU_t, dom0_t, evchnU-0_t)
|
||||
allow domU_t evchnU-0_t:event {send};
|
||||
|
||||
allow dom0_t dom0_t:event {send};
|
||||
allow dom0_t domU_t:grant {copy};
|
||||
|
||||
manage_domain(dom0_t, domU_t)
|
||||
|
||||
################################################################################
|
||||
|
||||
+1
-1
@@ -161,7 +161,7 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
|
||||
ret = xc_pm_get_pxstat(xc_fd, 0, pxstat);
|
||||
ret = xc_pm_get_pxstat(xc_fd, i, pxstat);
|
||||
if( ret ) {
|
||||
fprintf(stderr, "failed to get P-states statistics information\n");
|
||||
free(pxstat->trans_pt);
|
||||
|
||||
@@ -142,7 +142,7 @@ class LiloConfigFile(object):
|
||||
self.images.append(image)
|
||||
|
||||
def _get_default(self):
|
||||
for i in range(0, len(self.images) - 1):
|
||||
for i in range(len(self.images)):
|
||||
if self.images[i].title == self._default:
|
||||
return i
|
||||
return 0
|
||||
@@ -150,8 +150,8 @@ class LiloConfigFile(object):
|
||||
self._default = val
|
||||
default = property(_get_default, _set_default)
|
||||
|
||||
commands = { "default": "self.default",
|
||||
"timeout": "self.timeout",
|
||||
commands = { "default": "default",
|
||||
"timeout": "timeout",
|
||||
"prompt": None,
|
||||
"relocatable": None,
|
||||
}
|
||||
|
||||
@@ -35,7 +35,10 @@ def calc_dom_ssidref_from_info(info):
|
||||
return ssidref
|
||||
|
||||
def set_security_label(policy, label):
|
||||
return label
|
||||
if label:
|
||||
return label
|
||||
else:
|
||||
return ""
|
||||
|
||||
def ssidref2security_label(ssidref):
|
||||
label = ssidref2label(ssidref)
|
||||
|
||||
@@ -1303,7 +1303,7 @@ class XendDomainInfo:
|
||||
t.mkdir()
|
||||
t.set_permissions({'dom' : self.domid, 'read' : True})
|
||||
t.write('vm', self.vmpath)
|
||||
for i in [ 'device', 'control', 'error' ]:
|
||||
for i in [ 'device', 'control', 'error', 'memory' ]:
|
||||
t.mkdir(i)
|
||||
t.set_permissions(i, {'dom' : self.domid})
|
||||
|
||||
|
||||
@@ -502,7 +502,7 @@ class ImageHandler:
|
||||
if fifo_fd >= 0:
|
||||
self._openSentinel(sentinel_path_fifo)
|
||||
os.close(fifo_fd)
|
||||
self.pid = self.vm._gatherDom(('image/device-model-pid', int))
|
||||
self.pid = self.vm.gatherDom(('image/device-model-pid', int))
|
||||
log.debug("%s device model rediscovered, pid %s sentinel fifo %s",
|
||||
name, self.pid, sentinel_path_fifo)
|
||||
self.sentinel_thread = thread.start_new_thread(self._sentinel_watch,())
|
||||
|
||||
@@ -459,6 +459,7 @@ void arch_domain_destroy(struct domain *d)
|
||||
hvm_domain_destroy(d);
|
||||
|
||||
pci_release_devices(d);
|
||||
free_domain_pirqs(d);
|
||||
if ( !is_idle_domain(d) )
|
||||
iommu_domain_destroy(d);
|
||||
|
||||
|
||||
@@ -124,9 +124,11 @@ static void svm_dirq_assist(struct vcpu *v)
|
||||
if ( !test_and_clear_bit(irq, &hvm_irq_dpci->dirq_mask) )
|
||||
continue;
|
||||
|
||||
spin_lock(&d->event_lock);
|
||||
if ( test_bit(_HVM_IRQ_DPCI_MSI, &hvm_irq_dpci->mirq[irq].flags) )
|
||||
{
|
||||
hvm_pci_msi_assert(d, irq);
|
||||
spin_unlock(&d->event_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -137,9 +139,7 @@ static void svm_dirq_assist(struct vcpu *v)
|
||||
device = digl->device;
|
||||
intx = digl->intx;
|
||||
hvm_pci_intx_assert(d, device, intx);
|
||||
spin_lock(&hvm_irq_dpci->dirq_lock);
|
||||
hvm_irq_dpci->mirq[irq].pending++;
|
||||
spin_unlock(&hvm_irq_dpci->dirq_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -151,6 +151,7 @@ static void svm_dirq_assist(struct vcpu *v)
|
||||
*/
|
||||
set_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, irq)],
|
||||
NOW() + PT_IRQ_TIME_OUT);
|
||||
spin_unlock(&d->event_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ int vmsi_deliver(struct domain *d, int pirq)
|
||||
"vector=%x trig_mode=%x\n",
|
||||
dest, dest_mode, delivery_mode, vector, trig_mode);
|
||||
|
||||
if ( !(hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_MSI) )
|
||||
if ( !test_bit(_HVM_IRQ_DPCI_MSI, &hvm_irq_dpci->mirq[pirq].flags) )
|
||||
{
|
||||
gdprintk(XENLOG_WARNING, "pirq %x not msi \n", pirq);
|
||||
return 0;
|
||||
|
||||
@@ -127,11 +127,13 @@ static void vmx_dirq_assist(struct vcpu *v)
|
||||
if ( !test_and_clear_bit(irq, &hvm_irq_dpci->dirq_mask) )
|
||||
continue;
|
||||
|
||||
if ( test_bit(_HVM_IRQ_DPCI_MSI, &hvm_irq_dpci->mirq[irq].flags) )
|
||||
{
|
||||
hvm_pci_msi_assert(d, irq);
|
||||
continue;
|
||||
}
|
||||
spin_lock(&d->event_lock);
|
||||
if ( test_bit(_HVM_IRQ_DPCI_MSI, &hvm_irq_dpci->mirq[irq].flags) )
|
||||
{
|
||||
hvm_pci_msi_assert(d, irq);
|
||||
spin_unlock(&d->event_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
stop_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, irq)]);
|
||||
|
||||
@@ -140,9 +142,7 @@ static void vmx_dirq_assist(struct vcpu *v)
|
||||
device = digl->device;
|
||||
intx = digl->intx;
|
||||
hvm_pci_intx_assert(d, device, intx);
|
||||
spin_lock(&hvm_irq_dpci->dirq_lock);
|
||||
hvm_irq_dpci->mirq[irq].pending++;
|
||||
spin_unlock(&hvm_irq_dpci->dirq_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -154,6 +154,7 @@ static void vmx_dirq_assist(struct vcpu *v)
|
||||
*/
|
||||
set_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, irq)],
|
||||
NOW() + PT_IRQ_TIME_OUT);
|
||||
spin_unlock(&d->event_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -408,6 +408,10 @@ void __init init_IRQ(void)
|
||||
irq_desc[LEGACY_VECTOR(i)].handler = &i8259A_irq_type;
|
||||
}
|
||||
|
||||
/* Never allocate the hypercall vector or Linux/BSD fast-trap vector. */
|
||||
vector_irq[HYPERCALL_VECTOR] = NEVER_ASSIGN;
|
||||
vector_irq[0x80] = NEVER_ASSIGN;
|
||||
|
||||
apic_intr_init();
|
||||
|
||||
/* Set the clock to HZ Hz */
|
||||
|
||||
+26
-18
@@ -87,7 +87,8 @@ static struct irq_pin_list {
|
||||
} irq_2_pin[PIN_MAP_SIZE];
|
||||
static int irq_2_pin_free_entry = NR_IRQS;
|
||||
|
||||
int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
|
||||
int vector_irq[NR_VECTORS] __read_mostly = {
|
||||
[0 ... NR_VECTORS - 1] = FREE_TO_ASSIGN};
|
||||
|
||||
/*
|
||||
* The common case is 1:1 IRQ<->pin mappings. Sometimes there are
|
||||
@@ -666,40 +667,47 @@ static inline int IO_APIC_irq_trigger(int irq)
|
||||
/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
|
||||
u8 irq_vector[NR_IRQ_VECTORS] __read_mostly;
|
||||
|
||||
int free_irq_vector(int vector)
|
||||
{
|
||||
int irq;
|
||||
|
||||
BUG_ON((vector > LAST_DYNAMIC_VECTOR) || (vector < FIRST_DYNAMIC_VECTOR));
|
||||
|
||||
spin_lock(&vector_lock);
|
||||
if ((irq = vector_irq[vector]) == AUTO_ASSIGN)
|
||||
vector_irq[vector] = FREE_TO_ASSIGN;
|
||||
spin_unlock(&vector_lock);
|
||||
|
||||
return (irq == AUTO_ASSIGN) ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
int assign_irq_vector(int irq)
|
||||
{
|
||||
static unsigned current_vector = FIRST_DYNAMIC_VECTOR, offset = 0;
|
||||
static unsigned current_vector = FIRST_DYNAMIC_VECTOR;
|
||||
unsigned vector;
|
||||
|
||||
BUG_ON(irq >= NR_IRQ_VECTORS);
|
||||
|
||||
spin_lock(&vector_lock);
|
||||
|
||||
if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) {
|
||||
if ((irq != AUTO_ASSIGN) && (IO_APIC_VECTOR(irq) > 0)) {
|
||||
spin_unlock(&vector_lock);
|
||||
return IO_APIC_VECTOR(irq);
|
||||
}
|
||||
|
||||
next:
|
||||
current_vector += 8;
|
||||
vector = current_vector;
|
||||
while (vector_irq[vector] != FREE_TO_ASSIGN) {
|
||||
vector += 8;
|
||||
if (vector > LAST_DYNAMIC_VECTOR)
|
||||
vector = FIRST_DYNAMIC_VECTOR + ((vector + 1) & 7);
|
||||
|
||||
/* Skip the hypercall vector. */
|
||||
if (current_vector == HYPERCALL_VECTOR)
|
||||
goto next;
|
||||
|
||||
/* Skip the Linux/BSD fast-trap vector. */
|
||||
if (current_vector == 0x80)
|
||||
goto next;
|
||||
|
||||
if (current_vector > LAST_DYNAMIC_VECTOR) {
|
||||
offset++;
|
||||
if (!(offset%8)) {
|
||||
if (vector == current_vector) {
|
||||
spin_unlock(&vector_lock);
|
||||
return -ENOSPC;
|
||||
}
|
||||
current_vector = FIRST_DYNAMIC_VECTOR + offset;
|
||||
}
|
||||
|
||||
vector = current_vector;
|
||||
current_vector = vector;
|
||||
vector_irq[vector] = irq;
|
||||
if (irq != AUTO_ASSIGN)
|
||||
IO_APIC_VECTOR(irq) = vector;
|
||||
|
||||
+175
-5
@@ -14,8 +14,11 @@
|
||||
#include <xen/sched.h>
|
||||
#include <xen/keyhandler.h>
|
||||
#include <xen/compat.h>
|
||||
#include <asm/current.h>
|
||||
#include <xen/iocap.h>
|
||||
#include <xen/iommu.h>
|
||||
#include <asm/msi.h>
|
||||
#include <asm/current.h>
|
||||
#include <public/physdev.h>
|
||||
|
||||
/* opt_noirqbalance: If true, software IRQ balancing/affinity is disabled. */
|
||||
int opt_noirqbalance = 0;
|
||||
@@ -282,7 +285,7 @@ static void __do_IRQ_guest(int vector)
|
||||
* The descriptor is returned locked. This function is safe against changes
|
||||
* to the per-domain irq-to-vector mapping.
|
||||
*/
|
||||
static irq_desc_t *domain_spin_lock_irq_desc(
|
||||
irq_desc_t *domain_spin_lock_irq_desc(
|
||||
struct domain *d, int irq, unsigned long *pflags)
|
||||
{
|
||||
unsigned int vector;
|
||||
@@ -511,7 +514,7 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
|
||||
int rc = 0;
|
||||
cpumask_t cpumask = CPU_MASK_NONE;
|
||||
|
||||
WARN_ON(!spin_is_locked(&v->domain->evtchn_lock));
|
||||
WARN_ON(!spin_is_locked(&v->domain->event_lock));
|
||||
BUG_ON(!local_irq_is_enabled());
|
||||
|
||||
retry:
|
||||
@@ -681,7 +684,7 @@ void pirq_guest_unbind(struct domain *d, int irq)
|
||||
irq_desc_t *desc;
|
||||
int vector;
|
||||
|
||||
WARN_ON(!spin_is_locked(&d->evtchn_lock));
|
||||
WARN_ON(!spin_is_locked(&d->event_lock));
|
||||
|
||||
BUG_ON(!local_irq_is_enabled());
|
||||
desc = domain_spin_lock_irq_desc(d, irq, NULL);
|
||||
@@ -708,7 +711,7 @@ int pirq_guest_force_unbind(struct domain *d, int irq)
|
||||
irq_guest_action_t *action;
|
||||
int i, bound = 0;
|
||||
|
||||
WARN_ON(!spin_is_locked(&d->evtchn_lock));
|
||||
WARN_ON(!spin_is_locked(&d->event_lock));
|
||||
|
||||
BUG_ON(!local_irq_is_enabled());
|
||||
desc = domain_spin_lock_irq_desc(d, irq, NULL);
|
||||
@@ -731,6 +734,173 @@ int pirq_guest_force_unbind(struct domain *d, int irq)
|
||||
return bound;
|
||||
}
|
||||
|
||||
int get_free_pirq(struct domain *d, int type, int index)
|
||||
{
|
||||
int i;
|
||||
|
||||
ASSERT(spin_is_locked(&d->event_lock));
|
||||
|
||||
if ( type == MAP_PIRQ_TYPE_GSI )
|
||||
{
|
||||
for ( i = 16; i < NR_PIRQS; i++ )
|
||||
if ( !d->arch.pirq_vector[i] )
|
||||
break;
|
||||
if ( i == NR_PIRQS )
|
||||
return -ENOSPC;
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( i = NR_PIRQS - 1; i >= 16; i-- )
|
||||
if ( !d->arch.pirq_vector[i] )
|
||||
break;
|
||||
if ( i == 16 )
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int map_domain_pirq(
|
||||
struct domain *d, int pirq, int vector, int type, void *data)
|
||||
{
|
||||
int ret = 0;
|
||||
int old_vector, old_pirq;
|
||||
irq_desc_t *desc;
|
||||
unsigned long flags;
|
||||
|
||||
ASSERT(spin_is_locked(&d->event_lock));
|
||||
|
||||
if ( !IS_PRIV(current->domain) )
|
||||
return -EPERM;
|
||||
|
||||
if ( pirq < 0 || pirq >= NR_PIRQS || vector < 0 || vector >= NR_VECTORS )
|
||||
{
|
||||
dprintk(XENLOG_G_ERR, "dom%d: invalid pirq %d or vector %d\n",
|
||||
d->domain_id, pirq, vector);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
old_vector = d->arch.pirq_vector[pirq];
|
||||
old_pirq = d->arch.vector_pirq[vector];
|
||||
|
||||
if ( (old_vector && (old_vector != vector) ) ||
|
||||
(old_pirq && (old_pirq != pirq)) )
|
||||
{
|
||||
dprintk(XENLOG_G_ERR, "dom%d: pirq %d or vector %d already mapped\n",
|
||||
d->domain_id, pirq, vector);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = irq_permit_access(d, pirq);
|
||||
if ( ret )
|
||||
{
|
||||
dprintk(XENLOG_G_ERR, "dom%d: could not permit access to irq %d\n",
|
||||
d->domain_id, pirq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
desc = &irq_desc[vector];
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
|
||||
if ( type == MAP_PIRQ_TYPE_MSI )
|
||||
{
|
||||
struct msi_info *msi = (struct msi_info *)data;
|
||||
if ( desc->handler != &no_irq_type )
|
||||
dprintk(XENLOG_G_ERR, "dom%d: vector %d in use\n",
|
||||
d->domain_id, vector);
|
||||
desc->handler = &pci_msi_type;
|
||||
ret = pci_enable_msi(msi);
|
||||
if ( ret )
|
||||
goto done;
|
||||
}
|
||||
|
||||
d->arch.pirq_vector[pirq] = vector;
|
||||
d->arch.vector_pirq[vector] = pirq;
|
||||
|
||||
done:
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* The pirq should have been unbound before this call. */
|
||||
int unmap_domain_pirq(struct domain *d, int pirq)
|
||||
{
|
||||
unsigned long flags;
|
||||
irq_desc_t *desc;
|
||||
int vector, ret = 0;
|
||||
bool_t forced_unbind;
|
||||
|
||||
if ( (pirq < 0) || (pirq >= NR_PIRQS) )
|
||||
return -EINVAL;
|
||||
|
||||
if ( !IS_PRIV(current->domain) )
|
||||
return -EINVAL;
|
||||
|
||||
ASSERT(spin_is_locked(&d->event_lock));
|
||||
|
||||
vector = d->arch.pirq_vector[pirq];
|
||||
if ( vector <= 0 )
|
||||
{
|
||||
dprintk(XENLOG_G_ERR, "dom%d: pirq %d not mapped\n",
|
||||
d->domain_id, pirq);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
forced_unbind = pirq_guest_force_unbind(d, pirq);
|
||||
if ( forced_unbind )
|
||||
dprintk(XENLOG_G_WARNING, "dom%d: forcing unbind of pirq %d\n",
|
||||
d->domain_id, pirq);
|
||||
|
||||
desc = &irq_desc[vector];
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
|
||||
BUG_ON(vector != d->arch.pirq_vector[pirq]);
|
||||
|
||||
if ( desc->msi_desc )
|
||||
pci_disable_msi(vector);
|
||||
|
||||
if ( desc->handler == &pci_msi_type )
|
||||
{
|
||||
desc->handler = &no_irq_type;
|
||||
free_irq_vector(vector);
|
||||
}
|
||||
|
||||
if ( !forced_unbind )
|
||||
{
|
||||
d->arch.pirq_vector[pirq] = 0;
|
||||
d->arch.vector_pirq[vector] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
d->arch.pirq_vector[pirq] = -vector;
|
||||
d->arch.vector_pirq[vector] = -pirq;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
|
||||
ret = irq_deny_access(d, pirq);
|
||||
if ( ret )
|
||||
dprintk(XENLOG_G_ERR, "dom%d: could not deny access to irq %d\n",
|
||||
d->domain_id, pirq);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void free_domain_pirqs(struct domain *d)
|
||||
{
|
||||
int i;
|
||||
|
||||
spin_lock(&d->event_lock);
|
||||
|
||||
for ( i = 0; i < NR_PIRQS; i++ )
|
||||
if ( d->arch.pirq_vector[i] > 0 )
|
||||
unmap_domain_pirq(d, i);
|
||||
|
||||
spin_unlock(&d->event_lock);
|
||||
}
|
||||
|
||||
extern void dump_ioapic_irq_info(void);
|
||||
|
||||
static void dump_irqs(unsigned char key)
|
||||
|
||||
+1
-1
@@ -3067,7 +3067,7 @@ static int destroy_grant_pte_mapping(
|
||||
ol1e = *(l1_pgentry_t *)va;
|
||||
|
||||
/* Check that the virtual address supplied is actually mapped to frame. */
|
||||
if ( unlikely((l1e_get_intpte(ol1e) >> PAGE_SHIFT) != frame) )
|
||||
if ( unlikely(l1e_get_pfn(ol1e) != frame) )
|
||||
{
|
||||
page_unlock(page);
|
||||
MEM_LOG("PTE entry %lx for address %"PRIx64" doesn't match frame %lx",
|
||||
|
||||
+1
-60
@@ -1,12 +1,9 @@
|
||||
/******************************************************************************
|
||||
* pci.c
|
||||
*
|
||||
* PCI access functions.
|
||||
* Architecture-dependent PCI access functions.
|
||||
*/
|
||||
|
||||
#include <xen/config.h>
|
||||
#include <xen/pci.h>
|
||||
#include <xen/pci_regs.h>
|
||||
#include <xen/spinlock.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
@@ -118,59 +115,3 @@ void pci_conf_write32(
|
||||
pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), 0, 4, data);
|
||||
}
|
||||
|
||||
int pci_find_cap_offset(u8 bus, u8 dev, u8 func, u8 cap)
|
||||
{
|
||||
u8 id;
|
||||
int max_cap = 48;
|
||||
u8 pos = PCI_CAPABILITY_LIST;
|
||||
u16 status;
|
||||
|
||||
status = pci_conf_read16(bus, dev, func, PCI_STATUS);
|
||||
if ( (status & PCI_STATUS_CAP_LIST) == 0 )
|
||||
return 0;
|
||||
|
||||
while ( max_cap-- )
|
||||
{
|
||||
pos = pci_conf_read8(bus, dev, func, pos);
|
||||
if ( pos < 0x40 )
|
||||
break;
|
||||
|
||||
pos &= ~3;
|
||||
id = pci_conf_read8(bus, dev, func, pos + PCI_CAP_LIST_ID);
|
||||
|
||||
if ( id == 0xff )
|
||||
break;
|
||||
else if ( id == cap )
|
||||
return pos;
|
||||
|
||||
pos += PCI_CAP_LIST_NEXT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pci_find_next_cap(u8 bus, unsigned int devfn, u8 pos, int cap)
|
||||
{
|
||||
u8 id;
|
||||
int ttl = 48;
|
||||
|
||||
while ( ttl-- )
|
||||
{
|
||||
pos = pci_conf_read8(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);
|
||||
if ( pos < 0x40 )
|
||||
break;
|
||||
|
||||
pos &= ~3;
|
||||
id = pci_conf_read8(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
|
||||
pos + PCI_CAP_LIST_ID);
|
||||
|
||||
if ( id == 0xff )
|
||||
break;
|
||||
if ( id == cap )
|
||||
return pos;
|
||||
|
||||
pos += PCI_CAP_LIST_NEXT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+32
-174
@@ -26,168 +26,12 @@ int
|
||||
ioapic_guest_write(
|
||||
unsigned long physbase, unsigned int reg, u32 pval);
|
||||
|
||||
static int get_free_pirq(struct domain *d, int type, int index)
|
||||
{
|
||||
int i;
|
||||
|
||||
ASSERT(spin_is_locked(&d->evtchn_lock));
|
||||
|
||||
if ( type == MAP_PIRQ_TYPE_GSI )
|
||||
{
|
||||
for ( i = 16; i < NR_PIRQS; i++ )
|
||||
if ( !d->arch.pirq_vector[i] )
|
||||
break;
|
||||
if ( i == NR_PIRQS )
|
||||
return -ENOSPC;
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( i = NR_PIRQS - 1; i >= 16; i-- )
|
||||
if ( !d->arch.pirq_vector[i] )
|
||||
break;
|
||||
if ( i == 16 )
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int map_domain_pirq(struct domain *d, int pirq, int vector,
|
||||
struct physdev_map_pirq *map)
|
||||
{
|
||||
int ret = 0;
|
||||
int old_vector, old_pirq;
|
||||
struct msi_info msi;
|
||||
irq_desc_t *desc;
|
||||
unsigned long flags;
|
||||
|
||||
ASSERT(spin_is_locked(&d->evtchn_lock));
|
||||
|
||||
if ( !IS_PRIV(current->domain) )
|
||||
return -EPERM;
|
||||
|
||||
if ( pirq < 0 || pirq >= NR_PIRQS || vector < 0 || vector >= NR_VECTORS )
|
||||
{
|
||||
dprintk(XENLOG_G_ERR, "dom%d: invalid pirq %d or vector %d\n",
|
||||
d->domain_id, pirq, vector);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
old_vector = d->arch.pirq_vector[pirq];
|
||||
old_pirq = d->arch.vector_pirq[vector];
|
||||
|
||||
if ( (old_vector && (old_vector != vector) ) ||
|
||||
(old_pirq && (old_pirq != pirq)) )
|
||||
{
|
||||
dprintk(XENLOG_G_ERR, "dom%d: pirq %d or vector %d already mapped\n",
|
||||
d->domain_id, pirq, vector);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = irq_permit_access(d, pirq);
|
||||
if ( ret )
|
||||
{
|
||||
dprintk(XENLOG_G_ERR, "dom%d: could not permit access to irq %d\n",
|
||||
d->domain_id, pirq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
desc = &irq_desc[vector];
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
|
||||
if ( map && MAP_PIRQ_TYPE_MSI == map->type )
|
||||
{
|
||||
if ( desc->handler != &no_irq_type )
|
||||
dprintk(XENLOG_G_ERR, "dom%d: vector %d in use\n",
|
||||
d->domain_id, vector);
|
||||
desc->handler = &pci_msi_type;
|
||||
|
||||
msi.bus = map->bus;
|
||||
msi.devfn = map->devfn;
|
||||
msi.entry_nr = map->entry_nr;
|
||||
msi.table_base = map->table_base;
|
||||
msi.vector = vector;
|
||||
|
||||
ret = pci_enable_msi(&msi);
|
||||
if ( ret )
|
||||
goto done;
|
||||
}
|
||||
|
||||
d->arch.pirq_vector[pirq] = vector;
|
||||
d->arch.vector_pirq[vector] = pirq;
|
||||
|
||||
done:
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* The pirq should have been unbound before this call. */
|
||||
static int unmap_domain_pirq(struct domain *d, int pirq)
|
||||
{
|
||||
unsigned long flags;
|
||||
irq_desc_t *desc;
|
||||
int vector, ret = 0;
|
||||
bool_t forced_unbind;
|
||||
|
||||
if ( (pirq < 0) || (pirq >= NR_PIRQS) )
|
||||
return -EINVAL;
|
||||
|
||||
if ( !IS_PRIV(current->domain) )
|
||||
return -EINVAL;
|
||||
|
||||
ASSERT(spin_is_locked(&d->evtchn_lock));
|
||||
|
||||
vector = d->arch.pirq_vector[pirq];
|
||||
if ( vector <= 0 )
|
||||
{
|
||||
dprintk(XENLOG_G_ERR, "dom%d: pirq %d not mapped\n",
|
||||
d->domain_id, pirq);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
forced_unbind = pirq_guest_force_unbind(d, pirq);
|
||||
if ( forced_unbind )
|
||||
dprintk(XENLOG_G_WARNING, "dom%d: forcing unbind of pirq %d\n",
|
||||
d->domain_id, pirq);
|
||||
|
||||
desc = &irq_desc[vector];
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
|
||||
BUG_ON(vector != d->arch.pirq_vector[pirq]);
|
||||
|
||||
if ( desc->msi_desc )
|
||||
pci_disable_msi(vector);
|
||||
|
||||
if ( desc->handler == &pci_msi_type )
|
||||
desc->handler = &no_irq_type;
|
||||
|
||||
if ( !forced_unbind )
|
||||
{
|
||||
d->arch.pirq_vector[pirq] = 0;
|
||||
d->arch.vector_pirq[vector] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
d->arch.pirq_vector[pirq] = -vector;
|
||||
d->arch.vector_pirq[vector] = -pirq;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
|
||||
ret = irq_deny_access(d, pirq);
|
||||
if ( ret )
|
||||
dprintk(XENLOG_G_ERR, "dom%d: could not deny access to irq %d\n",
|
||||
d->domain_id, pirq);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int physdev_map_pirq(struct physdev_map_pirq *map)
|
||||
{
|
||||
struct domain *d;
|
||||
int vector, pirq, ret = 0;
|
||||
struct msi_info _msi;
|
||||
void *map_data = NULL;
|
||||
|
||||
if ( !IS_PRIV(current->domain) )
|
||||
return -EPERM;
|
||||
@@ -206,6 +50,7 @@ static int physdev_map_pirq(struct physdev_map_pirq *map)
|
||||
goto free_domain;
|
||||
}
|
||||
|
||||
/* Verify or get vector. */
|
||||
switch ( map->type )
|
||||
{
|
||||
case MAP_PIRQ_TYPE_GSI:
|
||||
@@ -220,31 +65,42 @@ static int physdev_map_pirq(struct physdev_map_pirq *map)
|
||||
if ( !vector )
|
||||
{
|
||||
dprintk(XENLOG_G_ERR, "dom%d: map irq with no vector %d\n",
|
||||
d->domain_id, map->index);
|
||||
d->domain_id, vector);
|
||||
ret = -EINVAL;
|
||||
goto free_domain;
|
||||
}
|
||||
break;
|
||||
|
||||
case MAP_PIRQ_TYPE_MSI:
|
||||
vector = map->index;
|
||||
if ( vector == -1 )
|
||||
vector = assign_irq_vector(AUTO_ASSIGN);
|
||||
if ( vector == -1 )
|
||||
vector = assign_irq_vector(AUTO_ASSIGN);
|
||||
|
||||
if ( vector < 0 || vector >= NR_VECTORS )
|
||||
{
|
||||
dprintk(XENLOG_G_ERR, "dom%d: map irq with wrong vector %d\n",
|
||||
d->domain_id, map->index);
|
||||
d->domain_id, vector);
|
||||
ret = -EINVAL;
|
||||
goto free_domain;
|
||||
}
|
||||
|
||||
_msi.bus = map->bus;
|
||||
_msi.devfn = map->devfn;
|
||||
_msi.entry_nr = map->entry_nr;
|
||||
_msi.table_base = map->table_base;
|
||||
_msi.vector = vector;
|
||||
map_data = &_msi;
|
||||
break;
|
||||
|
||||
default:
|
||||
dprintk(XENLOG_G_ERR, "dom%d: wrong map_pirq type %x\n", d->domain_id, map->type);
|
||||
dprintk(XENLOG_G_ERR, "dom%d: wrong map_pirq type %x\n",
|
||||
d->domain_id, map->type);
|
||||
ret = -EINVAL;
|
||||
goto free_domain;
|
||||
}
|
||||
|
||||
spin_lock(&d->evtchn_lock);
|
||||
/* Verify or get pirq. */
|
||||
spin_lock(&d->event_lock);
|
||||
if ( map->pirq < 0 )
|
||||
{
|
||||
if ( d->arch.vector_pirq[vector] )
|
||||
@@ -284,13 +140,14 @@ static int physdev_map_pirq(struct physdev_map_pirq *map)
|
||||
pirq = map->pirq;
|
||||
}
|
||||
|
||||
|
||||
ret = map_domain_pirq(d, pirq, vector, map);
|
||||
|
||||
if ( !ret )
|
||||
ret = map_domain_pirq(d, pirq, vector, map->type, map_data);
|
||||
if ( ret == 0 )
|
||||
map->pirq = pirq;
|
||||
|
||||
done:
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
if ( (ret != 0) && (map->type == MAP_PIRQ_TYPE_MSI) && (map->index == -1) )
|
||||
free_irq_vector(vector);
|
||||
free_domain:
|
||||
rcu_unlock_domain(d);
|
||||
return ret;
|
||||
@@ -312,9 +169,9 @@ static int physdev_unmap_pirq(struct physdev_unmap_pirq *unmap)
|
||||
if ( d == NULL )
|
||||
return -ESRCH;
|
||||
|
||||
spin_lock(&d->evtchn_lock);
|
||||
spin_lock(&d->event_lock);
|
||||
ret = unmap_domain_pirq(d, unmap->pirq);
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
|
||||
rcu_unlock_domain(d);
|
||||
|
||||
@@ -441,9 +298,10 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
|
||||
|
||||
irq_op.vector = assign_irq_vector(irq);
|
||||
|
||||
spin_lock(&dom0->evtchn_lock);
|
||||
ret = map_domain_pirq(dom0, irq_op.irq, irq_op.vector, NULL);
|
||||
spin_unlock(&dom0->evtchn_lock);
|
||||
spin_lock(&dom0->event_lock);
|
||||
ret = map_domain_pirq(dom0, irq_op.irq, irq_op.vector,
|
||||
MAP_PIRQ_TYPE_GSI, NULL);
|
||||
spin_unlock(&dom0->event_lock);
|
||||
|
||||
if ( copy_to_guest(arg, &irq_op, 1) != 0 )
|
||||
ret = -EFAULT;
|
||||
|
||||
@@ -69,6 +69,7 @@ SECTIONS
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
__init_end = .;
|
||||
|
||||
__per_cpu_shift = PERCPU_SHIFT; /* kdump assist */
|
||||
__per_cpu_start = .;
|
||||
.data.percpu : { *(.data.percpu) } :text
|
||||
__per_cpu_data_end = .;
|
||||
|
||||
@@ -67,6 +67,7 @@ SECTIONS
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
__init_end = .;
|
||||
|
||||
__per_cpu_shift = PERCPU_SHIFT; /* kdump assist */
|
||||
__per_cpu_start = .;
|
||||
.data.percpu : { *(.data.percpu) } :text
|
||||
__per_cpu_data_end = .;
|
||||
|
||||
+44
-44
@@ -133,7 +133,7 @@ static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc)
|
||||
if ( rc )
|
||||
return rc;
|
||||
|
||||
spin_lock(&d->evtchn_lock);
|
||||
spin_lock(&d->event_lock);
|
||||
|
||||
if ( (port = get_free_port(d)) < 0 )
|
||||
ERROR_EXIT_DOM(port, d);
|
||||
@@ -150,7 +150,7 @@ static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc)
|
||||
alloc->port = port;
|
||||
|
||||
out:
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
rcu_unlock_domain(d);
|
||||
|
||||
return rc;
|
||||
@@ -174,14 +174,14 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
|
||||
/* Avoid deadlock by first acquiring lock of domain with smaller id. */
|
||||
if ( ld < rd )
|
||||
{
|
||||
spin_lock(&ld->evtchn_lock);
|
||||
spin_lock(&rd->evtchn_lock);
|
||||
spin_lock(&ld->event_lock);
|
||||
spin_lock(&rd->event_lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ld != rd )
|
||||
spin_lock(&rd->evtchn_lock);
|
||||
spin_lock(&ld->evtchn_lock);
|
||||
spin_lock(&rd->event_lock);
|
||||
spin_lock(&ld->event_lock);
|
||||
}
|
||||
|
||||
if ( (lport = get_free_port(ld)) < 0 )
|
||||
@@ -216,9 +216,9 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
|
||||
bind->local_port = lport;
|
||||
|
||||
out:
|
||||
spin_unlock(&ld->evtchn_lock);
|
||||
spin_unlock(&ld->event_lock);
|
||||
if ( ld != rd )
|
||||
spin_unlock(&rd->evtchn_lock);
|
||||
spin_unlock(&rd->event_lock);
|
||||
|
||||
rcu_unlock_domain(rd);
|
||||
|
||||
@@ -244,7 +244,7 @@ static long evtchn_bind_virq(evtchn_bind_virq_t *bind)
|
||||
((v = d->vcpu[vcpu]) == NULL) )
|
||||
return -ENOENT;
|
||||
|
||||
spin_lock(&d->evtchn_lock);
|
||||
spin_lock(&d->event_lock);
|
||||
|
||||
if ( v->virq_to_evtchn[virq] != 0 )
|
||||
ERROR_EXIT(-EEXIST);
|
||||
@@ -260,7 +260,7 @@ static long evtchn_bind_virq(evtchn_bind_virq_t *bind)
|
||||
v->virq_to_evtchn[virq] = bind->port = port;
|
||||
|
||||
out:
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -277,7 +277,7 @@ static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind)
|
||||
(d->vcpu[vcpu] == NULL) )
|
||||
return -ENOENT;
|
||||
|
||||
spin_lock(&d->evtchn_lock);
|
||||
spin_lock(&d->event_lock);
|
||||
|
||||
if ( (port = get_free_port(d)) < 0 )
|
||||
ERROR_EXIT(port);
|
||||
@@ -289,7 +289,7 @@ static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind)
|
||||
bind->port = port;
|
||||
|
||||
out:
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -308,7 +308,7 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
|
||||
if ( !irq_access_permitted(d, pirq) )
|
||||
return -EPERM;
|
||||
|
||||
spin_lock(&d->evtchn_lock);
|
||||
spin_lock(&d->event_lock);
|
||||
|
||||
if ( d->pirq_to_evtchn[pirq] != 0 )
|
||||
ERROR_EXIT(-EEXIST);
|
||||
@@ -333,7 +333,7 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
|
||||
bind->port = port;
|
||||
|
||||
out:
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -348,7 +348,7 @@ static long __evtchn_close(struct domain *d1, int port1)
|
||||
long rc = 0;
|
||||
|
||||
again:
|
||||
spin_lock(&d1->evtchn_lock);
|
||||
spin_lock(&d1->event_lock);
|
||||
|
||||
if ( !port_is_valid(d1, port1) )
|
||||
{
|
||||
@@ -404,12 +404,12 @@ static long __evtchn_close(struct domain *d1, int port1)
|
||||
|
||||
if ( d1 < d2 )
|
||||
{
|
||||
spin_lock(&d2->evtchn_lock);
|
||||
spin_lock(&d2->event_lock);
|
||||
}
|
||||
else if ( d1 != d2 )
|
||||
{
|
||||
spin_unlock(&d1->evtchn_lock);
|
||||
spin_lock(&d2->evtchn_lock);
|
||||
spin_unlock(&d1->event_lock);
|
||||
spin_lock(&d2->event_lock);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
@@ -454,11 +454,11 @@ static long __evtchn_close(struct domain *d1, int port1)
|
||||
if ( d2 != NULL )
|
||||
{
|
||||
if ( d1 != d2 )
|
||||
spin_unlock(&d2->evtchn_lock);
|
||||
spin_unlock(&d2->event_lock);
|
||||
put_domain(d2);
|
||||
}
|
||||
|
||||
spin_unlock(&d1->evtchn_lock);
|
||||
spin_unlock(&d1->event_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -476,11 +476,11 @@ int evtchn_send(struct domain *d, unsigned int lport)
|
||||
struct vcpu *rvcpu;
|
||||
int rport, ret = 0;
|
||||
|
||||
spin_lock(&ld->evtchn_lock);
|
||||
spin_lock(&ld->event_lock);
|
||||
|
||||
if ( unlikely(!port_is_valid(ld, lport)) )
|
||||
{
|
||||
spin_unlock(&ld->evtchn_lock);
|
||||
spin_unlock(&ld->event_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -489,7 +489,7 @@ int evtchn_send(struct domain *d, unsigned int lport)
|
||||
/* Guest cannot send via a Xen-attached event channel. */
|
||||
if ( unlikely(lchn->consumer_is_xen) )
|
||||
{
|
||||
spin_unlock(&ld->evtchn_lock);
|
||||
spin_unlock(&ld->event_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -527,7 +527,7 @@ int evtchn_send(struct domain *d, unsigned int lport)
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock(&ld->evtchn_lock);
|
||||
spin_unlock(&ld->event_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -656,7 +656,7 @@ static long evtchn_status(evtchn_status_t *status)
|
||||
if ( rc )
|
||||
return rc;
|
||||
|
||||
spin_lock(&d->evtchn_lock);
|
||||
spin_lock(&d->event_lock);
|
||||
|
||||
if ( !port_is_valid(d, port) )
|
||||
{
|
||||
@@ -704,7 +704,7 @@ static long evtchn_status(evtchn_status_t *status)
|
||||
status->vcpu = chn->notify_vcpu_id;
|
||||
|
||||
out:
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
rcu_unlock_domain(d);
|
||||
|
||||
return rc;
|
||||
@@ -720,7 +720,7 @@ long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id)
|
||||
if ( (vcpu_id >= ARRAY_SIZE(d->vcpu)) || (d->vcpu[vcpu_id] == NULL) )
|
||||
return -ENOENT;
|
||||
|
||||
spin_lock(&d->evtchn_lock);
|
||||
spin_lock(&d->event_lock);
|
||||
|
||||
if ( !port_is_valid(d, port) )
|
||||
{
|
||||
@@ -756,7 +756,7 @@ long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id)
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -768,11 +768,11 @@ static long evtchn_unmask(evtchn_unmask_t *unmask)
|
||||
int port = unmask->port;
|
||||
struct vcpu *v;
|
||||
|
||||
spin_lock(&d->evtchn_lock);
|
||||
spin_lock(&d->event_lock);
|
||||
|
||||
if ( unlikely(!port_is_valid(d, port)) )
|
||||
{
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -790,7 +790,7 @@ static long evtchn_unmask(evtchn_unmask_t *unmask)
|
||||
vcpu_mark_events_pending(v);
|
||||
}
|
||||
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -944,7 +944,7 @@ int alloc_unbound_xen_event_channel(
|
||||
struct domain *d = local_vcpu->domain;
|
||||
int port;
|
||||
|
||||
spin_lock(&d->evtchn_lock);
|
||||
spin_lock(&d->event_lock);
|
||||
|
||||
if ( (port = get_free_port(d)) < 0 )
|
||||
goto out;
|
||||
@@ -956,7 +956,7 @@ int alloc_unbound_xen_event_channel(
|
||||
chn->u.unbound.remote_domid = remote_domid;
|
||||
|
||||
out:
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
|
||||
return port;
|
||||
}
|
||||
@@ -968,11 +968,11 @@ void free_xen_event_channel(
|
||||
struct evtchn *chn;
|
||||
struct domain *d = local_vcpu->domain;
|
||||
|
||||
spin_lock(&d->evtchn_lock);
|
||||
spin_lock(&d->event_lock);
|
||||
|
||||
if ( unlikely(d->is_dying) )
|
||||
{
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -981,7 +981,7 @@ void free_xen_event_channel(
|
||||
BUG_ON(!chn->consumer_is_xen);
|
||||
chn->consumer_is_xen = 0;
|
||||
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
|
||||
(void)__evtchn_close(d, port);
|
||||
}
|
||||
@@ -993,7 +993,7 @@ void notify_via_xen_event_channel(int lport)
|
||||
struct domain *ld = current->domain, *rd;
|
||||
int rport;
|
||||
|
||||
spin_lock(&ld->evtchn_lock);
|
||||
spin_lock(&ld->event_lock);
|
||||
|
||||
ASSERT(port_is_valid(ld, lport));
|
||||
lchn = evtchn_from_port(ld, lport);
|
||||
@@ -1007,13 +1007,13 @@ void notify_via_xen_event_channel(int lport)
|
||||
evtchn_set_pending(rd->vcpu[rchn->notify_vcpu_id], rport);
|
||||
}
|
||||
|
||||
spin_unlock(&ld->evtchn_lock);
|
||||
spin_unlock(&ld->event_lock);
|
||||
}
|
||||
|
||||
|
||||
int evtchn_init(struct domain *d)
|
||||
{
|
||||
spin_lock_init(&d->evtchn_lock);
|
||||
spin_lock_init(&d->event_lock);
|
||||
if ( get_free_port(d) != 0 )
|
||||
return -EINVAL;
|
||||
evtchn_from_port(d, 0)->state = ECS_RESERVED;
|
||||
@@ -1027,7 +1027,7 @@ void evtchn_destroy(struct domain *d)
|
||||
|
||||
/* After this barrier no new event-channel allocations can occur. */
|
||||
BUG_ON(!d->is_dying);
|
||||
spin_barrier(&d->evtchn_lock);
|
||||
spin_barrier(&d->event_lock);
|
||||
|
||||
/* Close all existing event channels. */
|
||||
for ( i = 0; port_is_valid(d, i); i++ )
|
||||
@@ -1037,14 +1037,14 @@ void evtchn_destroy(struct domain *d)
|
||||
}
|
||||
|
||||
/* Free all event-channel buckets. */
|
||||
spin_lock(&d->evtchn_lock);
|
||||
spin_lock(&d->event_lock);
|
||||
for ( i = 0; i < NR_EVTCHN_BUCKETS; i++ )
|
||||
{
|
||||
xsm_free_security_evtchn(d->evtchn[i]);
|
||||
xfree(d->evtchn[i]);
|
||||
d->evtchn[i] = NULL;
|
||||
}
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
}
|
||||
|
||||
static void domain_dump_evtchn_info(struct domain *d)
|
||||
@@ -1053,7 +1053,7 @@ static void domain_dump_evtchn_info(struct domain *d)
|
||||
|
||||
printk("Domain %d polling vCPUs: %08lx\n", d->domain_id, d->poll_mask[0]);
|
||||
|
||||
if ( !spin_trylock(&d->evtchn_lock) )
|
||||
if ( !spin_trylock(&d->event_lock) )
|
||||
return;
|
||||
|
||||
printk("Event channel information for domain %d:\n",
|
||||
@@ -1094,7 +1094,7 @@ static void domain_dump_evtchn_info(struct domain *d)
|
||||
printk(" x=%d\n", chn->consumer_is_xen);
|
||||
}
|
||||
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
}
|
||||
|
||||
static void dump_evtchn_info(unsigned char key)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
subdir-y += char
|
||||
subdir-y += cpufreq
|
||||
subdir-y += pci
|
||||
subdir-$(x86) += passthrough
|
||||
subdir-$(HAS_ACPI) += acpi
|
||||
subdir-$(HAS_VGA) += video
|
||||
@@ -26,10 +26,14 @@ static void pt_irq_time_out(void *data)
|
||||
struct hvm_mirq_dpci_mapping *irq_map = data;
|
||||
unsigned int guest_gsi, machine_gsi = 0;
|
||||
int vector;
|
||||
struct hvm_irq_dpci *dpci = domain_get_irq_dpci(irq_map->dom);
|
||||
struct hvm_irq_dpci *dpci = NULL;
|
||||
struct dev_intx_gsi_link *digl;
|
||||
uint32_t device, intx;
|
||||
|
||||
spin_lock(&irq_map->dom->event_lock);
|
||||
|
||||
dpci = domain_get_irq_dpci(irq_map->dom);
|
||||
ASSERT(dpci);
|
||||
list_for_each_entry ( digl, &irq_map->digl_list, list )
|
||||
{
|
||||
guest_gsi = digl->gsi;
|
||||
@@ -41,55 +45,65 @@ static void pt_irq_time_out(void *data)
|
||||
|
||||
clear_bit(machine_gsi, dpci->dirq_mask);
|
||||
vector = domain_irq_to_vector(irq_map->dom, machine_gsi);
|
||||
stop_timer(&dpci->hvm_timer[vector]);
|
||||
spin_lock(&dpci->dirq_lock);
|
||||
dpci->mirq[machine_gsi].pending = 0;
|
||||
spin_unlock(&dpci->dirq_lock);
|
||||
spin_unlock(&irq_map->dom->event_lock);
|
||||
pirq_guest_eoi(irq_map->dom, machine_gsi);
|
||||
}
|
||||
|
||||
int pt_irq_create_bind_vtd(
|
||||
struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
|
||||
{
|
||||
struct hvm_irq_dpci *hvm_irq_dpci = domain_get_irq_dpci(d);
|
||||
struct hvm_irq_dpci *hvm_irq_dpci = NULL;
|
||||
uint32_t machine_gsi, guest_gsi;
|
||||
uint32_t device, intx, link;
|
||||
struct dev_intx_gsi_link *digl;
|
||||
int pirq = pt_irq_bind->machine_irq;
|
||||
|
||||
if ( pirq < 0 || pirq >= NR_PIRQS )
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&d->event_lock);
|
||||
|
||||
hvm_irq_dpci = domain_get_irq_dpci(d);
|
||||
if ( hvm_irq_dpci == NULL )
|
||||
{
|
||||
hvm_irq_dpci = xmalloc(struct hvm_irq_dpci);
|
||||
if ( hvm_irq_dpci == NULL )
|
||||
{
|
||||
spin_unlock(&d->event_lock);
|
||||
return -ENOMEM;
|
||||
|
||||
}
|
||||
memset(hvm_irq_dpci, 0, sizeof(*hvm_irq_dpci));
|
||||
spin_lock_init(&hvm_irq_dpci->dirq_lock);
|
||||
for ( int i = 0; i < NR_IRQS; i++ )
|
||||
INIT_LIST_HEAD(&hvm_irq_dpci->mirq[i].digl_list);
|
||||
}
|
||||
|
||||
if ( domain_set_irq_dpci(d, hvm_irq_dpci) == 0 )
|
||||
xfree(hvm_irq_dpci);
|
||||
if ( domain_set_irq_dpci(d, hvm_irq_dpci) == 0 )
|
||||
{
|
||||
xfree(hvm_irq_dpci);
|
||||
spin_unlock(&d->event_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ( pt_irq_bind->irq_type == PT_IRQ_TYPE_MSI )
|
||||
{
|
||||
int pirq = pt_irq_bind->machine_irq;
|
||||
|
||||
if ( pirq < 0 || pirq >= NR_IRQS )
|
||||
return -EINVAL;
|
||||
|
||||
if ( !(hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_VALID ) )
|
||||
if ( !test_and_set_bit(pirq, hvm_irq_dpci->mapping))
|
||||
{
|
||||
hvm_irq_dpci->mirq[pirq].flags |= HVM_IRQ_DPCI_VALID |
|
||||
HVM_IRQ_DPCI_MSI ;
|
||||
set_bit(_HVM_IRQ_DPCI_MSI, &hvm_irq_dpci->mirq[pirq].flags);
|
||||
hvm_irq_dpci->mirq[pirq].gmsi.gvec = pt_irq_bind->u.msi.gvec;
|
||||
hvm_irq_dpci->mirq[pirq].gmsi.gflags = pt_irq_bind->u.msi.gflags;
|
||||
hvm_irq_dpci->msi_gvec_pirq[pt_irq_bind->u.msi.gvec] = pirq;
|
||||
/* bind after hvm_irq_dpci is setup to avoid race with irq handler*/
|
||||
pirq_guest_bind(d->vcpu[0], pirq, 0);
|
||||
}
|
||||
else if (hvm_irq_dpci->mirq[pirq].gmsi.gvec != pt_irq_bind->u.msi.gvec
|
||||
||hvm_irq_dpci->msi_gvec_pirq[pt_irq_bind->u.msi.gvec] != pirq)
|
||||
|
||||
hvm_irq_dpci->mirq[pirq].flags |= HVM_IRQ_DPCI_VALID |HVM_IRQ_DPCI_MSI ;
|
||||
hvm_irq_dpci->mirq[pirq].gmsi.gvec = pt_irq_bind->u.msi.gvec;
|
||||
hvm_irq_dpci->mirq[pirq].gmsi.gflags = pt_irq_bind->u.msi.gflags;
|
||||
hvm_irq_dpci->msi_gvec_pirq[pt_irq_bind->u.msi.gvec] = pirq;
|
||||
|
||||
{
|
||||
spin_unlock(&d->event_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -102,7 +116,10 @@ int pt_irq_create_bind_vtd(
|
||||
|
||||
digl = xmalloc(struct dev_intx_gsi_link);
|
||||
if ( !digl )
|
||||
{
|
||||
spin_unlock(&d->event_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
digl->device = device;
|
||||
digl->intx = intx;
|
||||
@@ -117,11 +134,11 @@ int pt_irq_create_bind_vtd(
|
||||
hvm_irq_dpci->girq[guest_gsi].machine_gsi = machine_gsi;
|
||||
|
||||
/* Bind the same mirq once in the same domain */
|
||||
if ( !(hvm_irq_dpci->mirq[machine_gsi].flags & HVM_IRQ_DPCI_VALID) )
|
||||
if ( !test_and_set_bit(machine_gsi, hvm_irq_dpci->mapping))
|
||||
{
|
||||
hvm_irq_dpci->mirq[machine_gsi].flags |= HVM_IRQ_DPCI_VALID;
|
||||
hvm_irq_dpci->mirq[machine_gsi].dom = d;
|
||||
|
||||
/* Init timer before binding */
|
||||
init_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, machine_gsi)],
|
||||
pt_irq_time_out, &hvm_irq_dpci->mirq[machine_gsi], 0);
|
||||
/* Deal with gsi for legacy devices */
|
||||
@@ -132,37 +149,45 @@ int pt_irq_create_bind_vtd(
|
||||
"VT-d irq bind: m_irq = %x device = %x intx = %x\n",
|
||||
machine_gsi, device, intx);
|
||||
}
|
||||
spin_unlock(&d->event_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pt_irq_destroy_bind_vtd(
|
||||
struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
|
||||
{
|
||||
struct hvm_irq_dpci *hvm_irq_dpci = domain_get_irq_dpci(d);
|
||||
struct hvm_irq_dpci *hvm_irq_dpci = NULL;
|
||||
uint32_t machine_gsi, guest_gsi;
|
||||
uint32_t device, intx, link;
|
||||
struct list_head *digl_list, *tmp;
|
||||
struct dev_intx_gsi_link *digl;
|
||||
|
||||
if ( hvm_irq_dpci == NULL )
|
||||
return 0;
|
||||
|
||||
machine_gsi = pt_irq_bind->machine_irq;
|
||||
device = pt_irq_bind->u.pci.device;
|
||||
intx = pt_irq_bind->u.pci.intx;
|
||||
guest_gsi = hvm_pci_intx_gsi(device, intx);
|
||||
link = hvm_pci_intx_link(device, intx);
|
||||
hvm_irq_dpci->link_cnt[link]--;
|
||||
|
||||
gdprintk(XENLOG_INFO,
|
||||
"pt_irq_destroy_bind_vtd: machine_gsi=%d "
|
||||
"guest_gsi=%d, device=%d, intx=%d.\n",
|
||||
machine_gsi, guest_gsi, device, intx);
|
||||
spin_lock(&d->event_lock);
|
||||
|
||||
hvm_irq_dpci = domain_get_irq_dpci(d);
|
||||
|
||||
if ( hvm_irq_dpci == NULL )
|
||||
{
|
||||
spin_unlock(&d->event_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hvm_irq_dpci->link_cnt[link]--;
|
||||
memset(&hvm_irq_dpci->girq[guest_gsi], 0,
|
||||
sizeof(struct hvm_girq_dpci_mapping));
|
||||
|
||||
/* clear the mirq info */
|
||||
if ( (hvm_irq_dpci->mirq[machine_gsi].flags & HVM_IRQ_DPCI_VALID) )
|
||||
if ( test_bit(machine_gsi, hvm_irq_dpci->mapping))
|
||||
{
|
||||
list_for_each_safe ( digl_list, tmp,
|
||||
&hvm_irq_dpci->mirq[machine_gsi].digl_list )
|
||||
@@ -185,9 +210,10 @@ int pt_irq_destroy_bind_vtd(
|
||||
kill_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, machine_gsi)]);
|
||||
hvm_irq_dpci->mirq[machine_gsi].dom = NULL;
|
||||
hvm_irq_dpci->mirq[machine_gsi].flags = 0;
|
||||
clear_bit(machine_gsi, hvm_irq_dpci->mapping);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&d->event_lock);
|
||||
gdprintk(XENLOG_INFO,
|
||||
"XEN_DOMCTL_irq_unmapping: m_irq = %x device = %x intx = %x\n",
|
||||
machine_gsi, device, intx);
|
||||
@@ -199,8 +225,9 @@ int hvm_do_IRQ_dpci(struct domain *d, unsigned int mirq)
|
||||
{
|
||||
struct hvm_irq_dpci *dpci = domain_get_irq_dpci(d);
|
||||
|
||||
ASSERT(spin_is_locked(&irq_desc[domain_irq_to_vector(d, mirq)].lock));
|
||||
if ( !iommu_enabled || (d == dom0) || !dpci ||
|
||||
!dpci->mirq[mirq].flags & HVM_IRQ_DPCI_VALID )
|
||||
!test_bit(mirq, dpci->mapping))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@@ -218,44 +245,46 @@ int hvm_do_IRQ_dpci(struct domain *d, unsigned int mirq)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void hvm_dpci_msi_eoi(struct domain *d, int vector)
|
||||
{
|
||||
struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
|
||||
int pirq;
|
||||
unsigned long flags;
|
||||
irq_desc_t *desc;
|
||||
int pirq;
|
||||
|
||||
if ( !iommu_enabled || (hvm_irq_dpci == NULL) )
|
||||
return;
|
||||
|
||||
spin_lock(&d->event_lock);
|
||||
pirq = hvm_irq_dpci->msi_gvec_pirq[vector];
|
||||
|
||||
if ( ( pirq >= 0 ) && (pirq < NR_PIRQS) &&
|
||||
(hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_VALID) &&
|
||||
(hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_MSI) )
|
||||
{
|
||||
int vec;
|
||||
vec = domain_irq_to_vector(d, pirq);
|
||||
desc = &irq_desc[vec];
|
||||
test_bit(pirq, hvm_irq_dpci->mapping) &&
|
||||
(test_bit(_HVM_IRQ_DPCI_MSI, &hvm_irq_dpci->mirq[pirq].flags)))
|
||||
{
|
||||
BUG_ON(!local_irq_is_enabled());
|
||||
desc = domain_spin_lock_irq_desc(d, pirq, NULL);
|
||||
if (!desc)
|
||||
{
|
||||
spin_unlock(&d->event_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
desc->status &= ~IRQ_INPROGRESS;
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
desc->status &= ~IRQ_INPROGRESS;
|
||||
spin_unlock_irq(&desc->lock);
|
||||
|
||||
pirq_guest_eoi(d, pirq);
|
||||
}
|
||||
pirq_guest_eoi(d, pirq);
|
||||
}
|
||||
|
||||
spin_unlock(&d->event_lock);
|
||||
}
|
||||
|
||||
void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi,
|
||||
union vioapic_redir_entry *ent)
|
||||
{
|
||||
struct hvm_irq_dpci *hvm_irq_dpci = domain_get_irq_dpci(d);
|
||||
struct hvm_irq_dpci *hvm_irq_dpci = NULL;
|
||||
uint32_t device, intx, machine_gsi;
|
||||
|
||||
if ( !iommu_enabled || (hvm_irq_dpci == NULL) ||
|
||||
(guest_gsi >= NR_ISAIRQS &&
|
||||
!hvm_irq_dpci->girq[guest_gsi].valid) )
|
||||
if ( !iommu_enabled)
|
||||
return;
|
||||
|
||||
if ( guest_gsi < NR_ISAIRQS )
|
||||
@@ -264,23 +293,34 @@ void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi,
|
||||
return;
|
||||
}
|
||||
|
||||
machine_gsi = hvm_irq_dpci->girq[guest_gsi].machine_gsi;
|
||||
spin_lock(&d->event_lock);
|
||||
hvm_irq_dpci = domain_get_irq_dpci(d);
|
||||
|
||||
if((hvm_irq_dpci == NULL) ||
|
||||
(guest_gsi >= NR_ISAIRQS &&
|
||||
!hvm_irq_dpci->girq[guest_gsi].valid) )
|
||||
{
|
||||
spin_unlock(&d->event_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
device = hvm_irq_dpci->girq[guest_gsi].device;
|
||||
intx = hvm_irq_dpci->girq[guest_gsi].intx;
|
||||
hvm_pci_intx_deassert(d, device, intx);
|
||||
|
||||
spin_lock(&hvm_irq_dpci->dirq_lock);
|
||||
machine_gsi = hvm_irq_dpci->girq[guest_gsi].machine_gsi;
|
||||
if ( --hvm_irq_dpci->mirq[machine_gsi].pending == 0 )
|
||||
{
|
||||
spin_unlock(&hvm_irq_dpci->dirq_lock);
|
||||
|
||||
if ( (ent == NULL) || !ent->fields.mask )
|
||||
{
|
||||
/*
|
||||
* No need to get vector lock for timer
|
||||
* since interrupt is still not EOIed
|
||||
*/
|
||||
stop_timer(&hvm_irq_dpci->hvm_timer[
|
||||
domain_irq_to_vector(d, machine_gsi)]);
|
||||
pirq_guest_eoi(d, machine_gsi);
|
||||
}
|
||||
}
|
||||
else
|
||||
spin_unlock(&hvm_irq_dpci->dirq_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
}
|
||||
@@ -154,7 +154,7 @@ int pci_remove_device(u8 bus, u8 devfn)
|
||||
|
||||
static void pci_clean_dpci_irqs(struct domain *d)
|
||||
{
|
||||
struct hvm_irq_dpci *hvm_irq_dpci = domain_get_irq_dpci(d);
|
||||
struct hvm_irq_dpci *hvm_irq_dpci = NULL;
|
||||
uint32_t i;
|
||||
struct list_head *digl_list, *tmp;
|
||||
struct dev_intx_gsi_link *digl;
|
||||
@@ -165,13 +165,14 @@ static void pci_clean_dpci_irqs(struct domain *d)
|
||||
if ( !is_hvm_domain(d) && !need_iommu(d) )
|
||||
return;
|
||||
|
||||
spin_lock(&d->event_lock);
|
||||
hvm_irq_dpci = domain_get_irq_dpci(d);
|
||||
if ( hvm_irq_dpci != NULL )
|
||||
{
|
||||
for ( i = 0; i < NR_IRQS; i++ )
|
||||
for ( i = find_first_bit(hvm_irq_dpci->mapping, NR_PIRQS);
|
||||
i < NR_PIRQS;
|
||||
i = find_next_bit(hvm_irq_dpci->mapping, NR_PIRQS, i + 1) )
|
||||
{
|
||||
if ( !(hvm_irq_dpci->mirq[i].flags & HVM_IRQ_DPCI_VALID) )
|
||||
continue;
|
||||
|
||||
pirq_guest_unbind(d, i);
|
||||
kill_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(i)]);
|
||||
|
||||
@@ -188,6 +189,7 @@ static void pci_clean_dpci_irqs(struct domain *d)
|
||||
d->arch.hvm_domain.irq.dpci = NULL;
|
||||
xfree(hvm_irq_dpci);
|
||||
}
|
||||
spin_unlock(&d->event_lock);
|
||||
}
|
||||
|
||||
void pci_release_devices(struct domain *d)
|
||||
|
||||
@@ -44,7 +44,7 @@ u16 apicid_to_bdf(int apic_id)
|
||||
}
|
||||
|
||||
static int remap_entry_to_ioapic_rte(
|
||||
struct iommu *iommu, struct IO_APIC_route_entry *old_rte)
|
||||
struct iommu *iommu, struct IO_xAPIC_route_entry *old_rte)
|
||||
{
|
||||
struct iremap_entry *iremap_entry = NULL, *iremap_entries;
|
||||
struct IO_APIC_route_remap_entry *remap_rte;
|
||||
@@ -90,13 +90,13 @@ static int remap_entry_to_ioapic_rte(
|
||||
}
|
||||
|
||||
static int ioapic_rte_to_remap_entry(struct iommu *iommu,
|
||||
int apic_id, struct IO_APIC_route_entry *old_rte,
|
||||
int apic_id, struct IO_xAPIC_route_entry *old_rte,
|
||||
unsigned int rte_upper, unsigned int value)
|
||||
{
|
||||
struct iremap_entry *iremap_entry = NULL, *iremap_entries;
|
||||
struct iremap_entry new_ire;
|
||||
struct IO_APIC_route_remap_entry *remap_rte;
|
||||
struct IO_APIC_route_entry new_rte;
|
||||
struct IO_xAPIC_route_entry new_rte;
|
||||
int index;
|
||||
unsigned long flags;
|
||||
struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu);
|
||||
@@ -177,7 +177,7 @@ static int ioapic_rte_to_remap_entry(struct iommu *iommu,
|
||||
unsigned int io_apic_read_remap_rte(
|
||||
unsigned int apic, unsigned int reg)
|
||||
{
|
||||
struct IO_APIC_route_entry old_rte = { 0 };
|
||||
struct IO_xAPIC_route_entry old_rte = { 0 };
|
||||
struct IO_APIC_route_remap_entry *remap_rte;
|
||||
int rte_upper = (reg & 1) ? 1 : 0;
|
||||
struct iommu *iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid);
|
||||
@@ -222,7 +222,7 @@ unsigned int io_apic_read_remap_rte(
|
||||
void io_apic_write_remap_rte(
|
||||
unsigned int apic, unsigned int reg, unsigned int value)
|
||||
{
|
||||
struct IO_APIC_route_entry old_rte = { 0 };
|
||||
struct IO_xAPIC_route_entry old_rte = { 0 };
|
||||
struct IO_APIC_route_remap_entry *remap_rte;
|
||||
unsigned int rte_upper = (reg & 1) ? 1 : 0;
|
||||
struct iommu *iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid);
|
||||
|
||||
@@ -23,6 +23,43 @@
|
||||
|
||||
#include <xen/iommu.h>
|
||||
|
||||
/* Accomodate both IOAPIC and IOSAPIC. */
|
||||
struct IO_xAPIC_route_entry {
|
||||
__u32 vector : 8,
|
||||
delivery_mode : 3, /* 000: FIXED
|
||||
* 001: lowest prio
|
||||
* 111: ExtINT
|
||||
*/
|
||||
dest_mode : 1, /* 0: physical, 1: logical */
|
||||
delivery_status : 1,
|
||||
polarity : 1,
|
||||
irr : 1,
|
||||
trigger : 1, /* 0: edge, 1: level */
|
||||
mask : 1, /* 0: enabled, 1: disabled */
|
||||
__reserved_2 : 15;
|
||||
|
||||
union {
|
||||
struct { __u32
|
||||
__reserved_1 : 24,
|
||||
physical_dest : 4,
|
||||
__reserved_2 : 4;
|
||||
} physical;
|
||||
|
||||
struct { __u32
|
||||
__reserved_1 : 24,
|
||||
logical_dest : 8;
|
||||
} logical;
|
||||
|
||||
#ifdef __ia64__
|
||||
struct { __u32
|
||||
__reserved_1 : 16,
|
||||
dest_id : 16;
|
||||
};
|
||||
#endif
|
||||
} dest;
|
||||
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct IO_APIC_route_remap_entry {
|
||||
union {
|
||||
u64 val;
|
||||
|
||||
@@ -85,37 +85,41 @@ int domain_set_irq_dpci(struct domain *domain, struct hvm_irq_dpci *dpci)
|
||||
void hvm_dpci_isairq_eoi(struct domain *d, unsigned int isairq)
|
||||
{
|
||||
struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
|
||||
struct hvm_irq_dpci *dpci = domain_get_irq_dpci(d);
|
||||
struct hvm_irq_dpci *dpci = NULL;
|
||||
struct dev_intx_gsi_link *digl, *tmp;
|
||||
int i;
|
||||
|
||||
ASSERT(isairq < NR_ISAIRQS);
|
||||
if ( !vtd_enabled || !dpci ||
|
||||
!test_bit(isairq, dpci->isairq_map) )
|
||||
if ( !vtd_enabled)
|
||||
return;
|
||||
|
||||
/* Multiple mirq may be mapped to one isa irq */
|
||||
for ( i = 0; i < NR_IRQS; i++ )
|
||||
{
|
||||
if ( !dpci->mirq[i].flags & HVM_IRQ_DPCI_VALID )
|
||||
continue;
|
||||
spin_lock(&d->event_lock);
|
||||
|
||||
dpci = domain_get_irq_dpci(d);
|
||||
|
||||
if ( !dpci || !test_bit(isairq, dpci->isairq_map) )
|
||||
{
|
||||
spin_unlock(&d->event_lock);
|
||||
return;
|
||||
}
|
||||
/* Multiple mirq may be mapped to one isa irq */
|
||||
for ( i = find_first_bit(dpci->mapping, NR_PIRQS);
|
||||
i < NR_PIRQS;
|
||||
i = find_next_bit(dpci->mapping, NR_PIRQS, i + 1) )
|
||||
{
|
||||
list_for_each_entry_safe ( digl, tmp,
|
||||
&dpci->mirq[i].digl_list, list )
|
||||
{
|
||||
if ( hvm_irq->pci_link.route[digl->link] == isairq )
|
||||
{
|
||||
hvm_pci_intx_deassert(d, digl->device, digl->intx);
|
||||
spin_lock(&dpci->dirq_lock);
|
||||
if ( --dpci->mirq[i].pending == 0 )
|
||||
{
|
||||
spin_unlock(&dpci->dirq_lock);
|
||||
stop_timer(&dpci->hvm_timer[domain_irq_to_vector(d, i)]);
|
||||
pirq_guest_eoi(d, i);
|
||||
}
|
||||
else
|
||||
spin_unlock(&dpci->dirq_lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock(&d->event_lock);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
obj-y += pci.o
|
||||
@@ -0,0 +1,64 @@
|
||||
/******************************************************************************
|
||||
* pci.c
|
||||
*
|
||||
* Architecture-independent PCI access functions.
|
||||
*/
|
||||
|
||||
#include <xen/pci.h>
|
||||
#include <xen/pci_regs.h>
|
||||
|
||||
int pci_find_cap_offset(u8 bus, u8 dev, u8 func, u8 cap)
|
||||
{
|
||||
u8 id;
|
||||
int max_cap = 48;
|
||||
u8 pos = PCI_CAPABILITY_LIST;
|
||||
u16 status;
|
||||
|
||||
status = pci_conf_read16(bus, dev, func, PCI_STATUS);
|
||||
if ( (status & PCI_STATUS_CAP_LIST) == 0 )
|
||||
return 0;
|
||||
|
||||
while ( max_cap-- )
|
||||
{
|
||||
pos = pci_conf_read8(bus, dev, func, pos);
|
||||
if ( pos < 0x40 )
|
||||
break;
|
||||
|
||||
pos &= ~3;
|
||||
id = pci_conf_read8(bus, dev, func, pos + PCI_CAP_LIST_ID);
|
||||
|
||||
if ( id == 0xff )
|
||||
break;
|
||||
else if ( id == cap )
|
||||
return pos;
|
||||
|
||||
pos += PCI_CAP_LIST_NEXT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pci_find_next_cap(u8 bus, unsigned int devfn, u8 pos, int cap)
|
||||
{
|
||||
u8 id;
|
||||
int ttl = 48;
|
||||
|
||||
while ( ttl-- )
|
||||
{
|
||||
pos = pci_conf_read8(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);
|
||||
if ( pos < 0x40 )
|
||||
break;
|
||||
|
||||
pos &= ~3;
|
||||
id = pci_conf_read8(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
|
||||
pos + PCI_CAP_LIST_ID);
|
||||
|
||||
if ( id == 0xff )
|
||||
break;
|
||||
if ( id == cap )
|
||||
return pos;
|
||||
|
||||
pos += PCI_CAP_LIST_NEXT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -235,7 +235,7 @@ struct arch_domain
|
||||
/* Shadow translated domain: P2M mapping */
|
||||
pagetable_t phys_table;
|
||||
|
||||
/* NB. protected by d->evtchn_lock and by irq_desc[vector].lock */
|
||||
/* NB. protected by d->event_lock and by irq_desc[vector].lock */
|
||||
int vector_pirq[NR_VECTORS];
|
||||
int pirq_vector[NR_PIRQS];
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <xen/types.h>
|
||||
#include <xen/spinlock.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/pirq.h>
|
||||
#include <asm/hvm/hvm.h>
|
||||
#include <asm/hvm/vpic.h>
|
||||
#include <asm/hvm/vioapic.h>
|
||||
@@ -38,8 +39,6 @@ struct dev_intx_gsi_link {
|
||||
uint8_t link;
|
||||
};
|
||||
|
||||
#define HVM_IRQ_DPCI_VALID 0x1
|
||||
#define HVM_IRQ_DPCI_MSI 0x2
|
||||
#define _HVM_IRQ_DPCI_MSI 0x1
|
||||
|
||||
struct hvm_gmsi_info {
|
||||
@@ -64,9 +63,10 @@ struct hvm_girq_dpci_mapping {
|
||||
|
||||
#define NR_ISAIRQS 16
|
||||
#define NR_LINK 4
|
||||
/* Protected by domain's event_lock */
|
||||
struct hvm_irq_dpci {
|
||||
spinlock_t dirq_lock;
|
||||
/* Machine IRQ to guest device/intx mapping. */
|
||||
DECLARE_BITMAP(mapping, NR_PIRQS);
|
||||
struct hvm_mirq_dpci_mapping mirq[NR_IRQS];
|
||||
/* Guest IRQ to guest device/intx mapping. */
|
||||
struct hvm_girq_dpci_mapping girq[NR_IRQS];
|
||||
|
||||
@@ -190,5 +190,6 @@ static inline int ioapic_resume(void) {return 0};
|
||||
#endif
|
||||
|
||||
extern int assign_irq_vector(int irq);
|
||||
extern int free_irq_vector(int vector);
|
||||
|
||||
#endif
|
||||
@@ -19,7 +19,9 @@
|
||||
|
||||
extern int vector_irq[NR_VECTORS];
|
||||
extern u8 irq_vector[NR_IRQ_VECTORS];
|
||||
#define AUTO_ASSIGN -1
|
||||
#define AUTO_ASSIGN -1
|
||||
#define NEVER_ASSIGN -2
|
||||
#define FREE_TO_ASSIGN -3
|
||||
|
||||
#define platform_legacy_irq(irq) ((irq) < 16)
|
||||
|
||||
@@ -52,6 +54,12 @@ extern atomic_t irq_mis_count;
|
||||
int pirq_acktype(struct domain *d, int irq);
|
||||
int pirq_shared(struct domain *d , int irq);
|
||||
|
||||
int map_domain_pirq(struct domain *d, int pirq, int vector, int type,
|
||||
void *data);
|
||||
int unmap_domain_pirq(struct domain *d, int pirq);
|
||||
int get_free_pirq(struct domain *d, int type, int index);
|
||||
void free_domain_pirqs(struct domain *d);
|
||||
|
||||
#define domain_irq_to_vector(d, irq) ((d)->arch.pirq_vector[(irq)])
|
||||
#define domain_vector_to_irq(d, vec) ((d)->arch.vector_pirq[(vec)])
|
||||
|
||||
|
||||
@@ -78,6 +78,8 @@ extern int pirq_guest_eoi(struct domain *d, int irq);
|
||||
extern int pirq_guest_unmask(struct domain *d);
|
||||
extern int pirq_guest_bind(struct vcpu *v, int irq, int will_share);
|
||||
extern void pirq_guest_unbind(struct domain *d, int irq);
|
||||
extern irq_desc_t *domain_spin_lock_irq_desc(
|
||||
struct domain *d, int irq, unsigned long *pflags);
|
||||
|
||||
static inline void set_native_irq_info(int irq, cpumask_t mask)
|
||||
{
|
||||
|
||||
@@ -188,7 +188,7 @@ struct domain
|
||||
|
||||
/* Event channel information. */
|
||||
struct evtchn *evtchn[NR_EVTCHN_BUCKETS];
|
||||
spinlock_t evtchn_lock;
|
||||
spinlock_t event_lock;
|
||||
|
||||
struct grant_table *grant_table;
|
||||
|
||||
|
||||
@@ -248,11 +248,11 @@ ste_init_state(struct acm_sized_buffer *errors)
|
||||
/* a) check for event channel conflicts */
|
||||
for ( bucket = 0; bucket < NR_EVTCHN_BUCKETS; bucket++ )
|
||||
{
|
||||
spin_lock(&d->evtchn_lock);
|
||||
spin_lock(&d->event_lock);
|
||||
ports = d->evtchn[bucket];
|
||||
if ( ports == NULL)
|
||||
{
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -280,7 +280,7 @@ ste_init_state(struct acm_sized_buffer *errors)
|
||||
printkd("%s: Policy violation in event channel domain "
|
||||
"%x -> domain %x.\n",
|
||||
__func__, d->domain_id, rdomid);
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
|
||||
acm_array_append_tuple(errors,
|
||||
ACM_EVTCHN_SHARING_VIOLATION,
|
||||
@@ -288,7 +288,7 @@ ste_init_state(struct acm_sized_buffer *errors)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
spin_unlock(&d->event_lock);
|
||||
}
|
||||
|
||||
|
||||
|
||||