mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
Merge branch 'staging' of ssh://xenbits.xen.org/home/xen/git/xen into staging
This commit is contained in:
commit
5157e9dfd5
24 files changed
+800
-389
No files matched your search
@@ -198,6 +198,16 @@ Scrub free RAM during boot. This is a safety feature to prevent
|
||||
accidentally leaking sensitive VM data into other VMs if Xen crashes
|
||||
and reboots.
|
||||
|
||||
### `bootscrub_chunk`
|
||||
> `= <size>`
|
||||
|
||||
> Default: `128M`
|
||||
|
||||
Maximum RAM block size chunks to be scrubbed whilst holding the page heap lock
|
||||
and not running softirqs. Reduce this if softirqs are not being run frequently
|
||||
enough. Setting this to a high value may cause boot failure, particularly if
|
||||
the NMI watchdog is also enabled.
|
||||
|
||||
### cachesize
|
||||
> `= <size>`
|
||||
|
||||
|
||||
@@ -12,13 +12,6 @@ is quite more complex and slow. On these machines, a NUMA node is usually
|
||||
defined as a set of processor cores (typically a physical CPU package) and
|
||||
the memory directly attached to the set of cores.
|
||||
|
||||
The Xen hypervisor deals with NUMA machines by assigning to each domain
|
||||
a "node affinity", i.e., a set of NUMA nodes of the host from which they
|
||||
get their memory allocated. Also, even if the node affinity of a domain
|
||||
is allowed to change on-line, it is very important to "place" the domain
|
||||
correctly when it is fist created, as the most of its memory is allocated
|
||||
at that time and can not (for now) be moved easily.
|
||||
|
||||
NUMA awareness becomes very important as soon as many domains start
|
||||
running memory-intensive workloads on a shared host. In fact, the cost
|
||||
of accessing non node-local memory locations is very high, and the
|
||||
@@ -27,14 +20,37 @@ performance degradation is likely to be noticeable.
|
||||
For more information, have a look at the [Xen NUMA Introduction][numa_intro]
|
||||
page on the Wiki.
|
||||
|
||||
## Xen and NUMA machines: the concept of _node-affinity_ ##
|
||||
|
||||
The Xen hypervisor deals with NUMA machines throughout the concept of
|
||||
_node-affinity_. The node-affinity of a domain is the set of NUMA nodes
|
||||
of the host where the memory for the domain is being allocated (mostly,
|
||||
at domain creation time). This is, at least in principle, different and
|
||||
unrelated with the vCPU (hard and soft, see below) scheduling affinity,
|
||||
which instead is the set of pCPUs where the vCPU is allowed (or prefers)
|
||||
to run.
|
||||
|
||||
Of course, despite the fact that they belong to and affect different
|
||||
subsystems, the domain node-affinity and the vCPUs affinity are not
|
||||
completely independent.
|
||||
In fact, if the domain node-affinity is not explicitly specified by the
|
||||
user, via the proper libxl calls or xl config item, it will be computed
|
||||
basing on the vCPUs' scheduling affinity.
|
||||
|
||||
Notice that, even if the node affinity of a domain may change on-line,
|
||||
it is very important to "place" the domain correctly when it is fist
|
||||
created, as the most of its memory is allocated at that time and can
|
||||
not (for now) be moved easily.
|
||||
|
||||
### Placing via pinning and cpupools ###
|
||||
|
||||
The simplest way of placing a domain on a NUMA node is statically pinning
|
||||
the domain's vCPUs to the pCPUs of the node. This goes under the name of
|
||||
CPU affinity and can be set through the "cpus=" option in the config file
|
||||
(more about this below). Another option is to pool together the pCPUs
|
||||
spanning the node and put the domain in such a cpupool with the "pool="
|
||||
config option (as documented in our [Wiki][cpupools_howto]).
|
||||
The simplest way of placing a domain on a NUMA node is setting the hard
|
||||
scheduling affinity of the domain's vCPUs to the pCPUs of the node. This
|
||||
also goes under the name of vCPU pinning, and can be done through the
|
||||
"cpus=" option in the config file (more about this below). Another option
|
||||
is to pool together the pCPUs spanning the node and put the domain in
|
||||
such a _cpupool_ with the "pool=" config option (as documented in our
|
||||
[Wiki][cpupools_howto]).
|
||||
|
||||
In both the above cases, the domain will not be able to execute outside
|
||||
the specified set of pCPUs for any reasons, even if all those pCPUs are
|
||||
@@ -45,24 +61,45 @@ may come at he cost of some load imbalances.
|
||||
|
||||
### NUMA aware scheduling ###
|
||||
|
||||
If the credit scheduler is in use, the concept of node affinity defined
|
||||
above does not only apply to memory. In fact, starting from Xen 4.3, the
|
||||
scheduler always tries to run the domain's vCPUs on one of the nodes in
|
||||
its node affinity. Only if that turns out to be impossible, it will just
|
||||
pick any free pCPU.
|
||||
If using the credit1 scheduler, and starting from Xen 4.3, the scheduler
|
||||
itself always tries to run the domain's vCPUs on one of the nodes in
|
||||
its node-affinity. Only if that turns out to be impossible, it will just
|
||||
pick any free pCPU. Locality of access is less guaranteed than in the
|
||||
pinning case, but that comes along with better chances to exploit all
|
||||
the host resources (e.g., the pCPUs).
|
||||
|
||||
This is, therefore, something more flexible than CPU affinity, as a domain
|
||||
can still run everywhere, it just prefers some nodes rather than others.
|
||||
Locality of access is less guaranteed than in the pinning case, but that
|
||||
comes along with better chances to exploit all the host resources (e.g.,
|
||||
the pCPUs).
|
||||
Starting from Xen 4.5, credit1 supports two forms of affinity: hard and
|
||||
soft, both on a per-vCPU basis. This means each vCPU can have its own
|
||||
soft affinity, stating where such vCPU prefers to execute on. This is
|
||||
less strict than what it (also starting from 4.5) is called hard affinity,
|
||||
as the vCPU can potentially run everywhere, it just prefers some pCPUs
|
||||
rather than others.
|
||||
In Xen 4.5, therefore, NUMA-aware scheduling is achieved by matching the
|
||||
soft affinity of the vCPUs of a domain with its node-affinity.
|
||||
|
||||
In fact, if all the pCPUs in a domain's node affinity are busy, it is
|
||||
possible for the domain to run outside of there, but it is very likely that
|
||||
slower execution (due to remote memory accesses) is still better than no
|
||||
execution at all, as it would happen with pinning. For this reason, NUMA
|
||||
aware scheduling has the potential of bringing substantial performances
|
||||
benefits, although this will depend on the workload.
|
||||
In fact, as it was for 4.3, if all the pCPUs in a vCPU's soft affinity
|
||||
are busy, it is possible for the domain to run outside from there. The
|
||||
idea is that slower execution (due to remote memory accesses) is still
|
||||
better than no execution at all (as it would happen with pinning). For
|
||||
this reason, NUMA aware scheduling has the potential of bringing
|
||||
substantial performances benefits, although this will depend on the
|
||||
workload.
|
||||
|
||||
Notice that, for each vCPU, the following three scenarios are possbile:
|
||||
|
||||
* a vCPU *is pinned* to some pCPUs and *does not have* any soft affinity
|
||||
In this case, the vCPU is always scheduled on one of the pCPUs to which
|
||||
it is pinned, without any specific peference among them.
|
||||
* a vCPU *has* its own soft affinity and *is not* pinned to any particular
|
||||
pCPU. In this case, the vCPU can run on every pCPU. Nevertheless, the
|
||||
scheduler will try to have it running on one of the pCPUs in its soft
|
||||
affinity;
|
||||
* a vCPU *has* its own vCPU soft affinity and *is also* pinned to some
|
||||
pCPUs. In this case, the vCPU is always scheduled on one of the pCPUs
|
||||
onto which it is pinned, with, among them, a preference for the ones
|
||||
that also forms its soft affinity. In case pinning and soft affinity
|
||||
form two disjoint sets of pCPUs, pinning "wins", and the soft affinity
|
||||
is just ignored.
|
||||
|
||||
## Guest placement in xl ##
|
||||
|
||||
@@ -71,25 +108,23 @@ both manual or automatic placement of them across the host's NUMA nodes.
|
||||
|
||||
Note that xm/xend does a very similar thing, the only differences being
|
||||
the details of the heuristics adopted for automatic placement (see below),
|
||||
and the lack of support (in both xm/xend and the Xen versions where that\
|
||||
and the lack of support (in both xm/xend and the Xen versions where that
|
||||
was the default toolstack) for NUMA aware scheduling.
|
||||
|
||||
### Placing the guest manually ###
|
||||
|
||||
Thanks to the "cpus=" option, it is possible to specify where a domain
|
||||
should be created and scheduled on, directly in its config file. This
|
||||
affects NUMA placement and memory accesses as the hypervisor constructs
|
||||
the node affinity of a VM basing right on its CPU affinity when it is
|
||||
created.
|
||||
affects NUMA placement and memory accesses as, in this case, the
|
||||
hypervisor constructs the node-affinity of a VM basing right on its
|
||||
vCPU pinning when it is created.
|
||||
|
||||
This is very simple and effective, but requires the user/system
|
||||
administrator to explicitly specify affinities for each and every domain,
|
||||
administrator to explicitly specify the pinning for each and every domain,
|
||||
or Xen won't be able to guarantee the locality for their memory accesses.
|
||||
|
||||
Notice that this also pins the domain's vCPUs to the specified set of
|
||||
pCPUs, so it not only sets the domain's node affinity (its memory will
|
||||
come from the nodes to which the pCPUs belong), but at the same time
|
||||
forces the vCPUs of the domain to be scheduled on those same pCPUs.
|
||||
That, of course, also mean the vCPUs of the domain will only be able to
|
||||
execute on those same pCPUs.
|
||||
|
||||
### Placing the guest automatically ###
|
||||
|
||||
@@ -97,7 +132,9 @@ If no "cpus=" option is specified in the config file, libxl tries
|
||||
to figure out on its own on which node(s) the domain could fit best.
|
||||
If it finds one (some), the domain's node affinity get set to there,
|
||||
and both memory allocations and NUMA aware scheduling (for the credit
|
||||
scheduler and starting from Xen 4.3) will comply with it.
|
||||
scheduler and starting from Xen 4.3) will comply with it. Starting from
|
||||
Xen 4.5, this also means that the mask resulting from this "fitting"
|
||||
procedure will become the soft affinity of all the vCPUs of the domain.
|
||||
|
||||
It is worthwhile noting that optimally fitting a set of VMs on the NUMA
|
||||
nodes of an host is an incarnation of the Bin Packing Problem. In fact,
|
||||
@@ -142,34 +179,43 @@ any placement from happening:
|
||||
|
||||
libxl_defbool_set(&domain_build_info->numa_placement, false);
|
||||
|
||||
Also, if `numa_placement` is set to `true`, the domain must not
|
||||
have any CPU affinity (i.e., `domain_build_info->cpumap` must
|
||||
have all its bits set, as it is by default), or domain creation
|
||||
will fail returning `ERROR_INVAL`.
|
||||
Also, if `numa_placement` is set to `true`, the domain's vCPUs must
|
||||
not be pinned (i.e., `domain_build_info->cpumap` must have all its
|
||||
bits set, as it is by default), or domain creation will fail with
|
||||
`ERROR_INVAL`.
|
||||
|
||||
Starting from Xen 4.3, in case automatic placement happens (and is
|
||||
successful), it will affect the domain's node affinity and _not_ its
|
||||
CPU affinity. Namely, the domain's vCPUs will not be pinned to any
|
||||
successful), it will affect the domain's node-affinity and _not_ its
|
||||
vCPU pinning. Namely, the domain's vCPUs will not be pinned to any
|
||||
pCPU on the host, but the memory from the domain will come from the
|
||||
selected node(s) and the NUMA aware scheduling (if the credit scheduler
|
||||
is in use) will try to keep the domain there as much as possible.
|
||||
is in use) will try to keep the domain's vCPUs there as much as possible.
|
||||
|
||||
Besides than that, looking and/or tweaking the placement algorithm
|
||||
search "Automatic NUMA placement" in libxl\_internal.h.
|
||||
|
||||
Note this may change in future versions of Xen/libxl.
|
||||
|
||||
## Xen < 4.5 ##
|
||||
|
||||
The concept of vCPU soft affinity has been introduced for the first time
|
||||
in Xen 4.5. In 4.3, it is the domain's node-affinity that drives the
|
||||
NUMA-aware scheduler. The main difference is soft affinity is per-vCPU,
|
||||
and so each vCPU can have its own mask of pCPUs, while node-affinity is
|
||||
per-domain, that is the equivalent of having all the vCPUs with the same
|
||||
soft affinity.
|
||||
|
||||
## Xen < 4.3 ##
|
||||
|
||||
As NUMA aware scheduling is a new feature of Xen 4.3, things are a little
|
||||
bit different for earlier version of Xen. If no "cpus=" option is specified
|
||||
and Xen 4.2 is in use, the automatic placement algorithm still runs, but
|
||||
the results is used to _pin_ the vCPUs of the domain to the output node(s).
|
||||
This is consistent with what was happening with xm/xend, which were also
|
||||
affecting the domain's CPU affinity.
|
||||
This is consistent with what was happening with xm/xend.
|
||||
|
||||
On a version of Xen earlier than 4.2, there is not automatic placement at
|
||||
all in xl or libxl, and hence no node or CPU affinity being affected.
|
||||
all in xl or libxl, and hence no node-affinity, vCPU affinity or pinning
|
||||
being introduced/modified.
|
||||
|
||||
## Limitations ##
|
||||
|
||||
|
||||
+34
-16
@@ -225,13 +225,14 @@ int xc_vcpu_setaffinity(xc_interface *xch,
|
||||
|
||||
domctl.cmd = XEN_DOMCTL_setvcpuaffinity;
|
||||
domctl.domain = (domid_t)domid;
|
||||
domctl.u.vcpuaffinity.vcpu = vcpu;
|
||||
domctl.u.vcpuaffinity.vcpu = vcpu;
|
||||
domctl.u.vcpuaffinity.flags = XEN_VCPUAFFINITY_HARD;
|
||||
|
||||
memcpy(local, cpumap, cpusize);
|
||||
|
||||
set_xen_guest_handle(domctl.u.vcpuaffinity.cpumap.bitmap, local);
|
||||
set_xen_guest_handle(domctl.u.vcpuaffinity.cpumap_hard.bitmap, local);
|
||||
|
||||
domctl.u.vcpuaffinity.cpumap.nr_bits = cpusize * 8;
|
||||
domctl.u.vcpuaffinity.cpumap_hard.nr_bits = cpusize * 8;
|
||||
|
||||
ret = do_domctl(xch, &domctl);
|
||||
|
||||
@@ -269,9 +270,10 @@ int xc_vcpu_getaffinity(xc_interface *xch,
|
||||
domctl.cmd = XEN_DOMCTL_getvcpuaffinity;
|
||||
domctl.domain = (domid_t)domid;
|
||||
domctl.u.vcpuaffinity.vcpu = vcpu;
|
||||
domctl.u.vcpuaffinity.flags = XEN_VCPUAFFINITY_HARD;
|
||||
|
||||
set_xen_guest_handle(domctl.u.vcpuaffinity.cpumap.bitmap, local);
|
||||
domctl.u.vcpuaffinity.cpumap.nr_bits = cpusize * 8;
|
||||
set_xen_guest_handle(domctl.u.vcpuaffinity.cpumap_hard.bitmap, local);
|
||||
domctl.u.vcpuaffinity.cpumap_hard.nr_bits = cpusize * 8;
|
||||
|
||||
ret = do_domctl(xch, &domctl);
|
||||
|
||||
@@ -1702,16 +1704,21 @@ int xc_domain_bind_pt_irq(
|
||||
bind->hvm_domid = domid;
|
||||
bind->irq_type = irq_type;
|
||||
bind->machine_irq = machine_irq;
|
||||
if ( irq_type == PT_IRQ_TYPE_PCI ||
|
||||
irq_type == PT_IRQ_TYPE_MSI_TRANSLATE )
|
||||
switch ( irq_type )
|
||||
{
|
||||
case PT_IRQ_TYPE_PCI:
|
||||
case PT_IRQ_TYPE_MSI_TRANSLATE:
|
||||
bind->u.pci.bus = bus;
|
||||
bind->u.pci.device = device;
|
||||
bind->u.pci.device = device;
|
||||
bind->u.pci.intx = intx;
|
||||
}
|
||||
else if ( irq_type == PT_IRQ_TYPE_ISA )
|
||||
case PT_IRQ_TYPE_ISA:
|
||||
bind->u.isa.isa_irq = isa_irq;
|
||||
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = do_domctl(xch, &domctl);
|
||||
return rc;
|
||||
}
|
||||
@@ -1737,11 +1744,22 @@ int xc_domain_unbind_pt_irq(
|
||||
bind->hvm_domid = domid;
|
||||
bind->irq_type = irq_type;
|
||||
bind->machine_irq = machine_irq;
|
||||
bind->u.pci.bus = bus;
|
||||
bind->u.pci.device = device;
|
||||
bind->u.pci.intx = intx;
|
||||
bind->u.isa.isa_irq = isa_irq;
|
||||
|
||||
switch ( irq_type )
|
||||
{
|
||||
case PT_IRQ_TYPE_PCI:
|
||||
case PT_IRQ_TYPE_MSI_TRANSLATE:
|
||||
bind->u.pci.bus = bus;
|
||||
bind->u.pci.device = device;
|
||||
bind->u.pci.intx = intx;
|
||||
break;
|
||||
case PT_IRQ_TYPE_ISA:
|
||||
bind->u.isa.isa_irq = isa_irq;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = do_domctl(xch, &domctl);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#define RESOLUTION 1024
|
||||
#define DECAY 4
|
||||
#define MAX_INTERESTING 50000
|
||||
#define LATENCY_MULTIPLIER 10
|
||||
|
||||
/*
|
||||
* Concepts and ideas behind the menu governor
|
||||
@@ -88,6 +89,9 @@
|
||||
* the average interrupt interval is, the smaller C state latency should be
|
||||
* and thus the less likely a busy CPU will hit such a deep C state.
|
||||
*
|
||||
* As an additional rule to reduce the performance impact, menu tries to
|
||||
* limit the exit latency duration to be no more than 10% of the decaying
|
||||
* measured idle time.
|
||||
*/
|
||||
|
||||
struct perf_factor{
|
||||
@@ -102,6 +106,7 @@ struct menu_device
|
||||
int last_state_idx;
|
||||
unsigned int expected_us;
|
||||
u64 predicted_us;
|
||||
u64 latency_factor;
|
||||
unsigned int measured_us;
|
||||
unsigned int exit_us;
|
||||
unsigned int bucket;
|
||||
@@ -199,6 +204,10 @@ static int menu_select(struct acpi_processor_power *power)
|
||||
|
||||
io_interval = avg_intr_interval_us();
|
||||
|
||||
data->latency_factor = DIV_ROUND(
|
||||
data->latency_factor * (DECAY - 1) + data->measured_us,
|
||||
DECAY);
|
||||
|
||||
/*
|
||||
* if the correction factor is 0 (eg first time init or cpu hotplug
|
||||
* etc), we actually want to start out with a unity factor.
|
||||
@@ -220,6 +229,8 @@ static int menu_select(struct acpi_processor_power *power)
|
||||
break;
|
||||
if (s->latency * IO_MULTIPLIER > io_interval)
|
||||
break;
|
||||
if (s->latency * LATENCY_MULTIPLIER > data->latency_factor)
|
||||
break;
|
||||
/* TBD: we need to check the QoS requirment in future */
|
||||
data->exit_us = s->latency;
|
||||
data->last_state_idx = i;
|
||||
@@ -231,18 +242,16 @@ static int menu_select(struct acpi_processor_power *power)
|
||||
static void menu_reflect(struct acpi_processor_power *power)
|
||||
{
|
||||
struct menu_device *data = &__get_cpu_var(menu_devices);
|
||||
unsigned int last_idle_us = power->last_residency;
|
||||
unsigned int measured_us;
|
||||
u64 new_factor;
|
||||
|
||||
measured_us = last_idle_us;
|
||||
data->measured_us = power->last_residency;
|
||||
|
||||
/*
|
||||
* We correct for the exit latency; we are assuming here that the
|
||||
* exit latency happens after the event that we're interested in.
|
||||
*/
|
||||
if (measured_us > data->exit_us)
|
||||
measured_us -= data->exit_us;
|
||||
if (data->measured_us > data->exit_us)
|
||||
data->measured_us -= data->exit_us;
|
||||
|
||||
/* update our correction ratio */
|
||||
|
||||
@@ -250,7 +259,7 @@ static void menu_reflect(struct acpi_processor_power *power)
|
||||
* (DECAY - 1) / DECAY;
|
||||
|
||||
if (data->expected_us > 0 && data->measured_us < MAX_INTERESTING)
|
||||
new_factor += RESOLUTION * measured_us / data->expected_us;
|
||||
new_factor += RESOLUTION * data->measured_us / data->expected_us;
|
||||
else
|
||||
/*
|
||||
* we were idle so long that we count it as a perfect
|
||||
|
||||
@@ -49,11 +49,15 @@ static int __read_mostly nr_intel_ext_msrs;
|
||||
#define INTEL_SRAR_INSTR_FETCH 0x150
|
||||
|
||||
#ifdef CONFIG_X86_MCE_THERMAL
|
||||
#define MCE_RING 0x1
|
||||
static DEFINE_PER_CPU(int, last_state);
|
||||
|
||||
static void intel_thermal_interrupt(struct cpu_user_regs *regs)
|
||||
{
|
||||
uint64_t msr_content;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
static DEFINE_PER_CPU(s_time_t, next);
|
||||
int *this_last_state;
|
||||
|
||||
ack_APIC_irq();
|
||||
|
||||
@@ -62,13 +66,17 @@ static void intel_thermal_interrupt(struct cpu_user_regs *regs)
|
||||
|
||||
per_cpu(next, cpu) = NOW() + MILLISECS(5000);
|
||||
rdmsrl(MSR_IA32_THERM_STATUS, msr_content);
|
||||
if (msr_content & 0x1) {
|
||||
printk(KERN_EMERG "CPU%d: Temperature above threshold\n", cpu);
|
||||
printk(KERN_EMERG "CPU%d: Running in modulated clock mode\n",
|
||||
cpu);
|
||||
this_last_state = &per_cpu(last_state, cpu);
|
||||
if ( *this_last_state == (msr_content & MCE_RING) )
|
||||
return;
|
||||
*this_last_state = msr_content & MCE_RING;
|
||||
if ( msr_content & MCE_RING )
|
||||
{
|
||||
printk(KERN_EMERG "CPU%u: Temperature above threshold\n", cpu);
|
||||
printk(KERN_EMERG "CPU%u: Running in modulated clock mode\n", cpu);
|
||||
add_taint(TAINT_MACHINE_CHECK);
|
||||
} else {
|
||||
printk(KERN_INFO "CPU%d: Temperature/speed normal\n", cpu);
|
||||
printk(KERN_INFO "CPU%u: Temperature/speed normal\n", cpu);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -802,6 +810,7 @@ static int cpu_mcabank_alloc(unsigned int cpu)
|
||||
|
||||
per_cpu(no_cmci_banks, cpu) = cmci;
|
||||
per_cpu(mce_banks_owned, cpu) = owned;
|
||||
per_cpu(last_state, cpu) = -1;
|
||||
|
||||
return 0;
|
||||
out:
|
||||
|
||||
@@ -344,11 +344,12 @@ static EFI_FILE_HANDLE __init get_parent_handle(EFI_LOADED_IMAGE *loaded_image,
|
||||
ret = efi_bs->HandleProtocol(loaded_image->DeviceHandle,
|
||||
&fs_protocol, (void **)&fio);
|
||||
if ( EFI_ERROR(ret) )
|
||||
blexit(L"Couldn't obtain the File System Protocol Interface");
|
||||
PrintErrMesg(L"Couldn't obtain the File System Protocol Interface",
|
||||
ret);
|
||||
ret = fio->OpenVolume(fio, &dir_handle);
|
||||
} while ( ret == EFI_MEDIA_CHANGED );
|
||||
if ( ret != EFI_SUCCESS )
|
||||
blexit(L"OpenVolume failure");
|
||||
PrintErrMesg(L"OpenVolume failure", ret);
|
||||
|
||||
#define buffer ((CHAR16 *)keyhandler_scratch)
|
||||
#define BUFFERSIZE sizeof(keyhandler_scratch)
|
||||
@@ -967,8 +968,8 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
|
||||
|
||||
if ( !EFI_ERROR(efi_bs->LocateProtocol(&shim_lock_guid, NULL,
|
||||
(void **)&shim_lock)) &&
|
||||
shim_lock->Verify(kernel.ptr, kernel.size) != EFI_SUCCESS )
|
||||
blexit(L"Dom0 kernel image could not be verified.");
|
||||
(status = shim_lock->Verify(kernel.ptr, kernel.size)) != EFI_SUCCESS )
|
||||
PrintErrMesg(L"Dom0 kernel image could not be verified", status);
|
||||
|
||||
name.s = get_value(&cfg, section.s, "ramdisk");
|
||||
if ( name.s )
|
||||
@@ -1379,8 +1380,8 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
|
||||
}
|
||||
}
|
||||
|
||||
status = efi_bs->GetMemoryMap(&efi_memmap_size, NULL, &map_key,
|
||||
&efi_mdesc_size, &mdesc_ver);
|
||||
efi_bs->GetMemoryMap(&efi_memmap_size, NULL, &map_key,
|
||||
&efi_mdesc_size, &mdesc_ver);
|
||||
mbi.mem_upper -= efi_memmap_size;
|
||||
mbi.mem_upper &= -__alignof__(EFI_MEMORY_DESCRIPTOR);
|
||||
if ( mbi.mem_upper < xen_phys_start )
|
||||
@@ -1389,7 +1390,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
|
||||
status = efi_bs->GetMemoryMap(&efi_memmap_size, efi_memmap, &map_key,
|
||||
&efi_mdesc_size, &mdesc_ver);
|
||||
if ( EFI_ERROR(status) )
|
||||
blexit(L"Cannot obtain memory map");
|
||||
PrintErrMesg(L"Cannot obtain memory map", status);
|
||||
|
||||
/* Populate E820 table and check trampoline area availability. */
|
||||
e = e820map - 1;
|
||||
|
||||
@@ -37,9 +37,8 @@ static int physdev_hvm_map_pirq(
|
||||
switch ( type )
|
||||
{
|
||||
case MAP_PIRQ_TYPE_GSI: {
|
||||
struct hvm_irq_dpci *hvm_irq_dpci;
|
||||
struct hvm_girq_dpci_mapping *girq;
|
||||
uint32_t machine_gsi = 0;
|
||||
const struct hvm_irq_dpci *hvm_irq_dpci;
|
||||
unsigned int machine_gsi = 0;
|
||||
|
||||
if ( *index < 0 || *index >= NR_HVM_IRQS )
|
||||
{
|
||||
@@ -52,6 +51,8 @@ static int physdev_hvm_map_pirq(
|
||||
hvm_irq_dpci = domain_get_irq_dpci(d);
|
||||
if ( hvm_irq_dpci )
|
||||
{
|
||||
const struct hvm_girq_dpci_mapping *girq;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(hvm_irq_dpci->girq) < NR_HVM_IRQS);
|
||||
list_for_each_entry ( girq,
|
||||
&hvm_irq_dpci->girq[*index],
|
||||
|
||||
@@ -3173,7 +3173,8 @@ static void nmi_mce_softirq(void)
|
||||
|
||||
/* Set the tmp value unconditionally, so that
|
||||
* the check in the iret hypercall works. */
|
||||
cpumask_copy(st->vcpu->cpu_affinity_tmp, st->vcpu->cpu_affinity);
|
||||
cpumask_copy(st->vcpu->cpu_hard_affinity_tmp,
|
||||
st->vcpu->cpu_hard_affinity);
|
||||
|
||||
if ((cpu != st->processor)
|
||||
|| (st->processor != st->vcpu->processor))
|
||||
@@ -3182,7 +3183,7 @@ static void nmi_mce_softirq(void)
|
||||
* Make sure to wakeup the vcpu on the
|
||||
* specified processor.
|
||||
*/
|
||||
vcpu_set_affinity(st->vcpu, cpumask_of(st->processor));
|
||||
vcpu_set_hard_affinity(st->vcpu, cpumask_of(st->processor));
|
||||
|
||||
/* Affinity is restored in the iret hypercall. */
|
||||
}
|
||||
@@ -3208,11 +3209,11 @@ void async_exception_cleanup(struct vcpu *curr)
|
||||
return;
|
||||
|
||||
/* Restore affinity. */
|
||||
if ( !cpumask_empty(curr->cpu_affinity_tmp) &&
|
||||
!cpumask_equal(curr->cpu_affinity_tmp, curr->cpu_affinity) )
|
||||
if ( !cpumask_empty(curr->cpu_hard_affinity_tmp) &&
|
||||
!cpumask_equal(curr->cpu_hard_affinity_tmp, curr->cpu_hard_affinity) )
|
||||
{
|
||||
vcpu_set_affinity(curr, curr->cpu_affinity_tmp);
|
||||
cpumask_clear(curr->cpu_affinity_tmp);
|
||||
vcpu_set_hard_affinity(curr, curr->cpu_hard_affinity_tmp);
|
||||
cpumask_clear(curr->cpu_hard_affinity_tmp);
|
||||
}
|
||||
|
||||
if ( !(curr->async_exception_mask & (curr->async_exception_mask - 1)) )
|
||||
|
||||
+53
-35
@@ -125,9 +125,10 @@ struct vcpu *alloc_vcpu(
|
||||
|
||||
tasklet_init(&v->continue_hypercall_tasklet, NULL, 0);
|
||||
|
||||
if ( !zalloc_cpumask_var(&v->cpu_affinity) ||
|
||||
!zalloc_cpumask_var(&v->cpu_affinity_tmp) ||
|
||||
!zalloc_cpumask_var(&v->cpu_affinity_saved) ||
|
||||
if ( !zalloc_cpumask_var(&v->cpu_hard_affinity) ||
|
||||
!zalloc_cpumask_var(&v->cpu_hard_affinity_tmp) ||
|
||||
!zalloc_cpumask_var(&v->cpu_hard_affinity_saved) ||
|
||||
!zalloc_cpumask_var(&v->cpu_soft_affinity) ||
|
||||
!zalloc_cpumask_var(&v->vcpu_dirty_cpumask) )
|
||||
goto fail_free;
|
||||
|
||||
@@ -156,9 +157,10 @@ struct vcpu *alloc_vcpu(
|
||||
fail_wq:
|
||||
destroy_waitqueue_vcpu(v);
|
||||
fail_free:
|
||||
free_cpumask_var(v->cpu_affinity);
|
||||
free_cpumask_var(v->cpu_affinity_tmp);
|
||||
free_cpumask_var(v->cpu_affinity_saved);
|
||||
free_cpumask_var(v->cpu_hard_affinity);
|
||||
free_cpumask_var(v->cpu_hard_affinity_tmp);
|
||||
free_cpumask_var(v->cpu_hard_affinity_saved);
|
||||
free_cpumask_var(v->cpu_soft_affinity);
|
||||
free_cpumask_var(v->vcpu_dirty_cpumask);
|
||||
free_vcpu_struct(v);
|
||||
return NULL;
|
||||
@@ -407,17 +409,17 @@ struct domain *domain_create(
|
||||
|
||||
void domain_update_node_affinity(struct domain *d)
|
||||
{
|
||||
cpumask_var_t cpumask;
|
||||
cpumask_var_t online_affinity;
|
||||
cpumask_var_t dom_cpumask, dom_cpumask_soft;
|
||||
cpumask_t *dom_affinity;
|
||||
const cpumask_t *online;
|
||||
struct vcpu *v;
|
||||
unsigned int node;
|
||||
unsigned int cpu;
|
||||
|
||||
if ( !zalloc_cpumask_var(&cpumask) )
|
||||
if ( !zalloc_cpumask_var(&dom_cpumask) )
|
||||
return;
|
||||
if ( !alloc_cpumask_var(&online_affinity) )
|
||||
if ( !zalloc_cpumask_var(&dom_cpumask_soft) )
|
||||
{
|
||||
free_cpumask_var(cpumask);
|
||||
free_cpumask_var(dom_cpumask);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -425,33 +427,48 @@ void domain_update_node_affinity(struct domain *d)
|
||||
|
||||
spin_lock(&d->node_affinity_lock);
|
||||
|
||||
for_each_vcpu ( d, v )
|
||||
{
|
||||
cpumask_and(online_affinity, v->cpu_affinity, online);
|
||||
cpumask_or(cpumask, cpumask, online_affinity);
|
||||
}
|
||||
|
||||
/*
|
||||
* If d->auto_node_affinity is true, the domain's node-affinity mask
|
||||
* (d->node_affinity) is automaically computed from all the domain's
|
||||
* vcpus' vcpu-affinity masks (the union of which we have just built
|
||||
* above in cpumask). OTOH, if d->auto_node_affinity is false, we
|
||||
* must leave the node-affinity of the domain alone.
|
||||
* If d->auto_node_affinity is true, let's compute the domain's
|
||||
* node-affinity and update d->node_affinity accordingly. if false,
|
||||
* just leave d->auto_node_affinity alone.
|
||||
*/
|
||||
if ( d->auto_node_affinity )
|
||||
{
|
||||
nodes_clear(d->node_affinity);
|
||||
for_each_online_node ( node )
|
||||
if ( cpumask_intersects(&node_to_cpumask(node), cpumask) )
|
||||
node_set(node, d->node_affinity);
|
||||
}
|
||||
/*
|
||||
* We want the narrowest possible set of pcpus (to get the narowest
|
||||
* possible set of nodes). What we need is the cpumask of where the
|
||||
* domain can run (the union of the hard affinity of all its vcpus),
|
||||
* and the full mask of where it would prefer to run (the union of
|
||||
* the soft affinity of all its various vcpus). Let's build them.
|
||||
*/
|
||||
for_each_vcpu ( d, v )
|
||||
{
|
||||
cpumask_or(dom_cpumask, dom_cpumask, v->cpu_hard_affinity);
|
||||
cpumask_or(dom_cpumask_soft, dom_cpumask_soft,
|
||||
v->cpu_soft_affinity);
|
||||
}
|
||||
/* Filter out non-online cpus */
|
||||
cpumask_and(dom_cpumask, dom_cpumask, online);
|
||||
ASSERT(!cpumask_empty(dom_cpumask));
|
||||
/* And compute the intersection between hard, online and soft */
|
||||
cpumask_and(dom_cpumask_soft, dom_cpumask_soft, dom_cpumask);
|
||||
|
||||
sched_set_node_affinity(d, &d->node_affinity);
|
||||
/*
|
||||
* If not empty, the intersection of hard, soft and online is the
|
||||
* narrowest set we want. If empty, we fall back to hard&online.
|
||||
*/
|
||||
dom_affinity = cpumask_empty(dom_cpumask_soft) ?
|
||||
dom_cpumask : dom_cpumask_soft;
|
||||
|
||||
nodes_clear(d->node_affinity);
|
||||
for_each_cpu ( cpu, dom_affinity )
|
||||
node_set(cpu_to_node(cpu), d->node_affinity);
|
||||
}
|
||||
|
||||
spin_unlock(&d->node_affinity_lock);
|
||||
|
||||
free_cpumask_var(online_affinity);
|
||||
free_cpumask_var(cpumask);
|
||||
free_cpumask_var(dom_cpumask_soft);
|
||||
free_cpumask_var(dom_cpumask);
|
||||
}
|
||||
|
||||
|
||||
@@ -792,9 +809,10 @@ static void complete_domain_destroy(struct rcu_head *head)
|
||||
for ( i = d->max_vcpus - 1; i >= 0; i-- )
|
||||
if ( (v = d->vcpu[i]) != NULL )
|
||||
{
|
||||
free_cpumask_var(v->cpu_affinity);
|
||||
free_cpumask_var(v->cpu_affinity_tmp);
|
||||
free_cpumask_var(v->cpu_affinity_saved);
|
||||
free_cpumask_var(v->cpu_hard_affinity);
|
||||
free_cpumask_var(v->cpu_hard_affinity_tmp);
|
||||
free_cpumask_var(v->cpu_hard_affinity_saved);
|
||||
free_cpumask_var(v->cpu_soft_affinity);
|
||||
free_cpumask_var(v->vcpu_dirty_cpumask);
|
||||
free_vcpu_struct(v);
|
||||
}
|
||||
@@ -934,7 +952,7 @@ int vcpu_reset(struct vcpu *v)
|
||||
v->async_exception_mask = 0;
|
||||
memset(v->async_exception_state, 0, sizeof(v->async_exception_state));
|
||||
#endif
|
||||
cpumask_clear(v->cpu_affinity_tmp);
|
||||
cpumask_clear(v->cpu_hard_affinity_tmp);
|
||||
clear_bit(_VPF_blocked, &v->pause_flags);
|
||||
clear_bit(_VPF_in_reset, &v->pause_flags);
|
||||
|
||||
|
||||
+97
-10
@@ -287,6 +287,16 @@ void domctl_lock_release(void)
|
||||
spin_unlock(¤t->domain->hypercall_deadlock_mutex);
|
||||
}
|
||||
|
||||
static inline
|
||||
int vcpuaffinity_params_invalid(const xen_domctl_vcpuaffinity_t *vcpuaff)
|
||||
{
|
||||
return vcpuaff->flags == 0 ||
|
||||
((vcpuaff->flags & XEN_VCPUAFFINITY_HARD) &&
|
||||
guest_handle_is_null(vcpuaff->cpumap_hard.bitmap)) ||
|
||||
((vcpuaff->flags & XEN_VCPUAFFINITY_SOFT) &&
|
||||
guest_handle_is_null(vcpuaff->cpumap_soft.bitmap));
|
||||
}
|
||||
|
||||
long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
|
||||
{
|
||||
long ret = 0;
|
||||
@@ -601,31 +611,108 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
|
||||
case XEN_DOMCTL_getvcpuaffinity:
|
||||
{
|
||||
struct vcpu *v;
|
||||
xen_domctl_vcpuaffinity_t *vcpuaff = &op->u.vcpuaffinity;
|
||||
|
||||
ret = -EINVAL;
|
||||
if ( op->u.vcpuaffinity.vcpu >= d->max_vcpus )
|
||||
if ( vcpuaff->vcpu >= d->max_vcpus )
|
||||
break;
|
||||
|
||||
ret = -ESRCH;
|
||||
if ( (v = d->vcpu[op->u.vcpuaffinity.vcpu]) == NULL )
|
||||
if ( (v = d->vcpu[vcpuaff->vcpu]) == NULL )
|
||||
break;
|
||||
|
||||
ret = -EINVAL;
|
||||
if ( vcpuaffinity_params_invalid(vcpuaff) )
|
||||
break;
|
||||
|
||||
if ( op->cmd == XEN_DOMCTL_setvcpuaffinity )
|
||||
{
|
||||
cpumask_var_t new_affinity;
|
||||
cpumask_var_t new_affinity, old_affinity;
|
||||
cpumask_t *online = cpupool_online_cpumask(v->domain->cpupool);;
|
||||
|
||||
ret = xenctl_bitmap_to_cpumask(
|
||||
&new_affinity, &op->u.vcpuaffinity.cpumap);
|
||||
if ( !ret )
|
||||
/*
|
||||
* We want to be able to restore hard affinity if we are trying
|
||||
* setting both and changing soft affinity (which happens later,
|
||||
* when hard affinity has been succesfully chaged already) fails.
|
||||
*/
|
||||
if ( !alloc_cpumask_var(&old_affinity) )
|
||||
{
|
||||
ret = vcpu_set_affinity(v, new_affinity);
|
||||
free_cpumask_var(new_affinity);
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
cpumask_copy(old_affinity, v->cpu_hard_affinity);
|
||||
|
||||
if ( !alloc_cpumask_var(&new_affinity) )
|
||||
{
|
||||
free_cpumask_var(old_affinity);
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We both set a new affinity and report back to the caller what
|
||||
* the scheduler will be effectively using.
|
||||
*/
|
||||
if ( vcpuaff->flags & XEN_VCPUAFFINITY_HARD )
|
||||
{
|
||||
ret = xenctl_bitmap_to_bitmap(cpumask_bits(new_affinity),
|
||||
&vcpuaff->cpumap_hard,
|
||||
nr_cpu_ids);
|
||||
if ( !ret )
|
||||
ret = vcpu_set_hard_affinity(v, new_affinity);
|
||||
if ( ret )
|
||||
goto setvcpuaffinity_out;
|
||||
|
||||
/*
|
||||
* For hard affinity, what we return is the intersection of
|
||||
* cpupool's online mask and the new hard affinity.
|
||||
*/
|
||||
cpumask_and(new_affinity, online, v->cpu_hard_affinity);
|
||||
ret = cpumask_to_xenctl_bitmap(&vcpuaff->cpumap_hard,
|
||||
new_affinity);
|
||||
}
|
||||
if ( vcpuaff->flags & XEN_VCPUAFFINITY_SOFT )
|
||||
{
|
||||
ret = xenctl_bitmap_to_bitmap(cpumask_bits(new_affinity),
|
||||
&vcpuaff->cpumap_soft,
|
||||
nr_cpu_ids);
|
||||
if ( !ret)
|
||||
ret = vcpu_set_soft_affinity(v, new_affinity);
|
||||
if ( ret )
|
||||
{
|
||||
/*
|
||||
* Since we're returning error, the caller expects nothing
|
||||
* happened, so we rollback the changes to hard affinity
|
||||
* (if any).
|
||||
*/
|
||||
if ( vcpuaff->flags & XEN_VCPUAFFINITY_HARD )
|
||||
vcpu_set_hard_affinity(v, old_affinity);
|
||||
goto setvcpuaffinity_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* For soft affinity, we return the intersection between the
|
||||
* new soft affinity, the cpupool's online map and the (new)
|
||||
* hard affinity.
|
||||
*/
|
||||
cpumask_and(new_affinity, new_affinity, online);
|
||||
cpumask_and(new_affinity, new_affinity, v->cpu_hard_affinity);
|
||||
ret = cpumask_to_xenctl_bitmap(&vcpuaff->cpumap_soft,
|
||||
new_affinity);
|
||||
}
|
||||
|
||||
setvcpuaffinity_out:
|
||||
free_cpumask_var(new_affinity);
|
||||
free_cpumask_var(old_affinity);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = cpumask_to_xenctl_bitmap(
|
||||
&op->u.vcpuaffinity.cpumap, v->cpu_affinity);
|
||||
if ( vcpuaff->flags & XEN_VCPUAFFINITY_HARD )
|
||||
ret = cpumask_to_xenctl_bitmap(&vcpuaff->cpumap_hard,
|
||||
v->cpu_hard_affinity);
|
||||
if ( vcpuaff->flags & XEN_VCPUAFFINITY_SOFT )
|
||||
ret = cpumask_to_xenctl_bitmap(&vcpuaff->cpumap_soft,
|
||||
v->cpu_soft_affinity);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -295,8 +295,10 @@ static void dump_domains(unsigned char key)
|
||||
!vcpu_event_delivery_is_enabled(v));
|
||||
cpuset_print(tmpstr, sizeof(tmpstr), v->vcpu_dirty_cpumask);
|
||||
printk("dirty_cpus=%s ", tmpstr);
|
||||
cpuset_print(tmpstr, sizeof(tmpstr), v->cpu_affinity);
|
||||
cpuset_print(tmpstr, sizeof(tmpstr), v->cpu_hard_affinity);
|
||||
printk("cpu_affinity=%s\n", tmpstr);
|
||||
cpuset_print(tmpstr, sizeof(tmpstr), v->cpu_soft_affinity);
|
||||
printk("cpu_soft_affinity=%s\n", tmpstr);
|
||||
printk(" pause_count=%d pause_flags=%lx\n",
|
||||
atomic_read(&v->pause_count), v->pause_flags);
|
||||
arch_dump_vcpu_info(v);
|
||||
|
||||
+198
-20
@@ -64,6 +64,13 @@ string_param("badpage", opt_badpage);
|
||||
static bool_t opt_bootscrub __initdata = 1;
|
||||
boolean_param("bootscrub", opt_bootscrub);
|
||||
|
||||
/*
|
||||
* bootscrub_chunk -> Amount of bytes to scrub lockstep on non-SMT CPUs
|
||||
* on all NUMA nodes.
|
||||
*/
|
||||
static unsigned long __initdata opt_bootscrub_chunk = MB(128);
|
||||
size_param("bootscrub_chunk", opt_bootscrub_chunk);
|
||||
|
||||
/*
|
||||
* Bit width of the DMA heap -- used to override NUMA-node-first.
|
||||
* allocation strategy, which can otherwise exhaust low memory.
|
||||
@@ -90,6 +97,16 @@ static struct bootmem_region {
|
||||
} *__initdata bootmem_region_list;
|
||||
static unsigned int __initdata nr_bootmem_regions;
|
||||
|
||||
struct scrub_region {
|
||||
unsigned long offset;
|
||||
unsigned long start;
|
||||
unsigned long per_cpu_sz;
|
||||
unsigned long rem;
|
||||
cpumask_t cpus;
|
||||
};
|
||||
static struct scrub_region __initdata region[MAX_NUMNODES];
|
||||
static unsigned long __initdata chunk_size;
|
||||
|
||||
static void __init boot_bug(int line)
|
||||
{
|
||||
panic("Boot BUG at %s:%d", __FILE__, line);
|
||||
@@ -1256,42 +1273,203 @@ void __init end_boot_allocator(void)
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
static void __init smp_scrub_heap_pages(void *data)
|
||||
{
|
||||
unsigned long mfn, start, end;
|
||||
struct page_info *pg;
|
||||
struct scrub_region *r;
|
||||
unsigned int temp_cpu, node, cpu_idx = 0;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
|
||||
if ( data )
|
||||
r = data;
|
||||
else
|
||||
{
|
||||
node = cpu_to_node(cpu);
|
||||
if ( node == NUMA_NO_NODE )
|
||||
return;
|
||||
r = ®ion[node];
|
||||
}
|
||||
|
||||
/* Determine the current CPU's index into CPU's linked to this node. */
|
||||
for_each_cpu ( temp_cpu, &r->cpus )
|
||||
{
|
||||
if ( cpu == temp_cpu )
|
||||
break;
|
||||
cpu_idx++;
|
||||
}
|
||||
|
||||
/* Calculate the starting mfn for this CPU's memory block. */
|
||||
start = r->start + (r->per_cpu_sz * cpu_idx) + r->offset;
|
||||
|
||||
/* Calculate the end mfn into this CPU's memory block for this iteration. */
|
||||
if ( r->offset + chunk_size >= r->per_cpu_sz )
|
||||
{
|
||||
end = r->start + (r->per_cpu_sz * cpu_idx) + r->per_cpu_sz;
|
||||
|
||||
if ( r->rem && (cpumask_weight(&r->cpus) - 1 == cpu_idx) )
|
||||
end += r->rem;
|
||||
}
|
||||
else
|
||||
end = start + chunk_size;
|
||||
|
||||
for ( mfn = start; mfn < end; mfn++ )
|
||||
{
|
||||
pg = mfn_to_page(mfn);
|
||||
|
||||
/* Check the mfn is valid and page is free. */
|
||||
if ( !mfn_valid(mfn) || !page_state_is(pg, free) )
|
||||
continue;
|
||||
|
||||
scrub_one_page(pg);
|
||||
}
|
||||
}
|
||||
|
||||
static int __init find_non_smt(unsigned int node, cpumask_t *dest)
|
||||
{
|
||||
cpumask_t node_cpus;
|
||||
unsigned int i, cpu;
|
||||
|
||||
cpumask_and(&node_cpus, &node_to_cpumask(node), &cpu_online_map);
|
||||
cpumask_clear(dest);
|
||||
for_each_cpu ( i, &node_cpus )
|
||||
{
|
||||
if ( cpumask_intersects(dest, per_cpu(cpu_sibling_mask, i)) )
|
||||
continue;
|
||||
cpu = cpumask_first(per_cpu(cpu_sibling_mask, i));
|
||||
cpumask_set_cpu(cpu, dest);
|
||||
}
|
||||
return cpumask_weight(dest);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scrub all unallocated pages in all heap zones. This function is more
|
||||
* convoluted than appears necessary because we do not want to continuously
|
||||
* hold the lock while scrubbing very large memory areas.
|
||||
* Scrub all unallocated pages in all heap zones. This function uses all
|
||||
* online cpu's to scrub the memory in parallel.
|
||||
*/
|
||||
void __init scrub_heap_pages(void)
|
||||
{
|
||||
unsigned long mfn;
|
||||
struct page_info *pg;
|
||||
cpumask_t node_cpus, all_worker_cpus;
|
||||
unsigned int i, j;
|
||||
unsigned long offset, max_per_cpu_sz = 0;
|
||||
unsigned long start, end;
|
||||
unsigned long rem = 0;
|
||||
int last_distance, best_node;
|
||||
int cpus;
|
||||
|
||||
if ( !opt_bootscrub )
|
||||
return;
|
||||
|
||||
printk("Scrubbing Free RAM: ");
|
||||
cpumask_clear(&all_worker_cpus);
|
||||
/* Scrub block size. */
|
||||
chunk_size = opt_bootscrub_chunk >> PAGE_SHIFT;
|
||||
if ( chunk_size == 0 )
|
||||
chunk_size = MB(128) >> PAGE_SHIFT;
|
||||
|
||||
for ( mfn = first_valid_mfn; mfn < max_page; mfn++ )
|
||||
/* Round #0 - figure out amounts and which CPUs to use. */
|
||||
for_each_online_node ( i )
|
||||
{
|
||||
if ( !node_spanned_pages(i) )
|
||||
continue;
|
||||
/* Calculate Node memory start and end address. */
|
||||
start = max(node_start_pfn(i), first_valid_mfn);
|
||||
end = min(node_start_pfn(i) + node_spanned_pages(i), max_page);
|
||||
/* Just in case NODE has 1 page and starts below first_valid_mfn. */
|
||||
end = max(end, start);
|
||||
/* CPUs that are online and on this node (if none, that it is OK). */
|
||||
cpus = find_non_smt(i, &node_cpus);
|
||||
cpumask_or(&all_worker_cpus, &all_worker_cpus, &node_cpus);
|
||||
if ( cpus <= 0 )
|
||||
{
|
||||
/* No CPUs on this node. Round #2 will take of it. */
|
||||
rem = 0;
|
||||
region[i].per_cpu_sz = (end - start);
|
||||
}
|
||||
else
|
||||
{
|
||||
rem = (end - start) % cpus;
|
||||
region[i].per_cpu_sz = (end - start) / cpus;
|
||||
if ( region[i].per_cpu_sz > max_per_cpu_sz )
|
||||
max_per_cpu_sz = region[i].per_cpu_sz;
|
||||
}
|
||||
region[i].start = start;
|
||||
region[i].rem = rem;
|
||||
cpumask_copy(®ion[i].cpus, &node_cpus);
|
||||
}
|
||||
|
||||
printk("Scrubbing Free RAM on %d nodes using %d CPUs\n", num_online_nodes(),
|
||||
cpumask_weight(&all_worker_cpus));
|
||||
|
||||
/* Round: #1 - do NUMA nodes with CPUs. */
|
||||
for ( offset = 0; offset < max_per_cpu_sz; offset += chunk_size )
|
||||
{
|
||||
for_each_online_node ( i )
|
||||
region[i].offset = offset;
|
||||
|
||||
process_pending_softirqs();
|
||||
|
||||
pg = mfn_to_page(mfn);
|
||||
spin_lock(&heap_lock);
|
||||
on_selected_cpus(&all_worker_cpus, smp_scrub_heap_pages, NULL, 1);
|
||||
spin_unlock(&heap_lock);
|
||||
|
||||
/* Quick lock-free check. */
|
||||
if ( !mfn_valid(mfn) || !page_state_is(pg, free) )
|
||||
printk(".");
|
||||
}
|
||||
|
||||
/*
|
||||
* Round #2: NUMA nodes with no CPUs get scrubbed with CPUs on the node
|
||||
* closest to us and with CPUs.
|
||||
*/
|
||||
for_each_online_node ( i )
|
||||
{
|
||||
node_cpus = node_to_cpumask(i);
|
||||
|
||||
if ( !cpumask_empty(&node_cpus) )
|
||||
continue;
|
||||
|
||||
/* Every 100MB, print a progress dot. */
|
||||
if ( (mfn % ((100*1024*1024)/PAGE_SIZE)) == 0 )
|
||||
last_distance = INT_MAX;
|
||||
best_node = first_node(node_online_map);
|
||||
/* Figure out which NODE CPUs are close. */
|
||||
for_each_online_node ( j )
|
||||
{
|
||||
int distance;
|
||||
|
||||
if ( cpumask_empty(&node_to_cpumask(j)) )
|
||||
continue;
|
||||
|
||||
distance = __node_distance(i, j);
|
||||
if ( distance < last_distance )
|
||||
{
|
||||
last_distance = distance;
|
||||
best_node = j;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Use CPUs from best node, and if there are no CPUs on the
|
||||
* first node (the default) use the BSP.
|
||||
*/
|
||||
cpus = find_non_smt(best_node, &node_cpus);
|
||||
if ( cpus == 0 )
|
||||
{
|
||||
cpumask_set_cpu(smp_processor_id(), &node_cpus);
|
||||
cpus = 1;
|
||||
}
|
||||
/* We already have the node information from round #0. */
|
||||
region[i].rem = region[i].per_cpu_sz % cpus;
|
||||
region[i].per_cpu_sz /= cpus;
|
||||
max_per_cpu_sz = region[i].per_cpu_sz;
|
||||
cpumask_copy(®ion[i].cpus, &node_cpus);
|
||||
|
||||
for ( offset = 0; offset < max_per_cpu_sz; offset += chunk_size )
|
||||
{
|
||||
region[i].offset = offset;
|
||||
|
||||
process_pending_softirqs();
|
||||
|
||||
spin_lock(&heap_lock);
|
||||
on_selected_cpus(&node_cpus, smp_scrub_heap_pages, ®ion[i], 1);
|
||||
spin_unlock(&heap_lock);
|
||||
|
||||
printk(".");
|
||||
|
||||
spin_lock(&heap_lock);
|
||||
|
||||
/* Re-check page status with lock held. */
|
||||
if ( page_state_is(pg, free) )
|
||||
scrub_one_page(pg);
|
||||
|
||||
spin_unlock(&heap_lock);
|
||||
}
|
||||
}
|
||||
|
||||
printk("done.\n");
|
||||
|
||||
+64
-97
@@ -112,10 +112,24 @@
|
||||
|
||||
|
||||
/*
|
||||
* Node Balancing
|
||||
* Hard and soft affinity load balancing.
|
||||
*
|
||||
* Idea is each vcpu has some pcpus that it prefers, some that it does not
|
||||
* prefer but is OK with, and some that it cannot run on at all. The first
|
||||
* set of pcpus are the ones that are both in the soft affinity *and* in the
|
||||
* hard affinity; the second set of pcpus are the ones that are in the hard
|
||||
* affinity but *not* in the soft affinity; the third set of pcpus are the
|
||||
* ones that are not in the hard affinity.
|
||||
*
|
||||
* We implement a two step balancing logic. Basically, every time there is
|
||||
* the need to decide where to run a vcpu, we first check the soft affinity
|
||||
* (well, actually, the && between soft and hard affinity), to see if we can
|
||||
* send it where it prefers to (and can) run on. However, if the first step
|
||||
* does not find any suitable and free pcpu, we fall back checking the hard
|
||||
* affinity.
|
||||
*/
|
||||
#define CSCHED_BALANCE_NODE_AFFINITY 0
|
||||
#define CSCHED_BALANCE_CPU_AFFINITY 1
|
||||
#define CSCHED_BALANCE_SOFT_AFFINITY 0
|
||||
#define CSCHED_BALANCE_HARD_AFFINITY 1
|
||||
|
||||
/*
|
||||
* Boot parameters
|
||||
@@ -138,7 +152,7 @@ struct csched_pcpu {
|
||||
|
||||
/*
|
||||
* Convenience macro for accessing the per-PCPU cpumask we need for
|
||||
* implementing the two steps (vcpu and node affinity) balancing logic.
|
||||
* implementing the two steps (soft and hard affinity) balancing logic.
|
||||
* It is stored in csched_pcpu so that serialization is not an issue,
|
||||
* as there is a csched_pcpu for each PCPU and we always hold the
|
||||
* runqueue spin-lock when using this.
|
||||
@@ -178,9 +192,6 @@ struct csched_dom {
|
||||
struct list_head active_vcpu;
|
||||
struct list_head active_sdom_elem;
|
||||
struct domain *dom;
|
||||
/* cpumask translated from the domain's node-affinity.
|
||||
* Basically, the CPUs we prefer to be scheduled on. */
|
||||
cpumask_var_t node_affinity_cpumask;
|
||||
uint16_t active_vcpu_count;
|
||||
uint16_t weight;
|
||||
uint16_t cap;
|
||||
@@ -261,59 +272,28 @@ __runq_remove(struct csched_vcpu *svc)
|
||||
list_del_init(&svc->runq_elem);
|
||||
}
|
||||
|
||||
/*
|
||||
* Translates node-affinity mask into a cpumask, so that we can use it during
|
||||
* actual scheduling. That of course will contain all the cpus from all the
|
||||
* set nodes in the original node-affinity mask.
|
||||
*
|
||||
* Note that any serialization needed to access mask safely is complete
|
||||
* responsibility of the caller of this function/hook.
|
||||
*/
|
||||
static void csched_set_node_affinity(
|
||||
const struct scheduler *ops,
|
||||
struct domain *d,
|
||||
nodemask_t *mask)
|
||||
{
|
||||
struct csched_dom *sdom;
|
||||
int node;
|
||||
|
||||
/* Skip idle domain since it doesn't even have a node_affinity_cpumask */
|
||||
if ( unlikely(is_idle_domain(d)) )
|
||||
return;
|
||||
|
||||
sdom = CSCHED_DOM(d);
|
||||
cpumask_clear(sdom->node_affinity_cpumask);
|
||||
for_each_node_mask( node, *mask )
|
||||
cpumask_or(sdom->node_affinity_cpumask, sdom->node_affinity_cpumask,
|
||||
&node_to_cpumask(node));
|
||||
}
|
||||
|
||||
#define for_each_csched_balance_step(step) \
|
||||
for ( (step) = 0; (step) <= CSCHED_BALANCE_CPU_AFFINITY; (step)++ )
|
||||
for ( (step) = 0; (step) <= CSCHED_BALANCE_HARD_AFFINITY; (step)++ )
|
||||
|
||||
|
||||
/*
|
||||
* vcpu-affinity balancing is always necessary and must never be skipped.
|
||||
* OTOH, if a domain's node-affinity is said to be automatically computed
|
||||
* (or if it just spans all the nodes), we can safely avoid dealing with
|
||||
* node-affinity entirely.
|
||||
* Hard affinity balancing is always necessary and must never be skipped.
|
||||
* OTOH, if the vcpu's soft affinity is full (it spans all the possible
|
||||
* pcpus) we can safely avoid dealing with it entirely.
|
||||
*
|
||||
* Node-affinity is also deemed meaningless in case it has empty
|
||||
* intersection with mask, to cover the cases where using the node-affinity
|
||||
* A vcpu's soft affinity is also deemed meaningless in case it has empty
|
||||
* intersection with mask, to cover the cases where using the soft affinity
|
||||
* mask seems legit, but would instead led to trying to schedule the vcpu
|
||||
* on _no_ pcpu! Typical use cases are for mask to be equal to the vcpu's
|
||||
* vcpu-affinity, or to the && of vcpu-affinity and the set of online cpus
|
||||
* hard affinity, or to the && of hard affinity and the set of online cpus
|
||||
* in the domain's cpupool.
|
||||
*/
|
||||
static inline int __vcpu_has_node_affinity(const struct vcpu *vc,
|
||||
static inline int __vcpu_has_soft_affinity(const struct vcpu *vc,
|
||||
const cpumask_t *mask)
|
||||
{
|
||||
const struct domain *d = vc->domain;
|
||||
const struct csched_dom *sdom = CSCHED_DOM(d);
|
||||
|
||||
if ( d->auto_node_affinity
|
||||
|| cpumask_full(sdom->node_affinity_cpumask)
|
||||
|| !cpumask_intersects(sdom->node_affinity_cpumask, mask) )
|
||||
if ( cpumask_full(vc->cpu_soft_affinity)
|
||||
|| !cpumask_intersects(vc->cpu_soft_affinity, mask) )
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@@ -321,24 +301,23 @@ static inline int __vcpu_has_node_affinity(const struct vcpu *vc,
|
||||
|
||||
/*
|
||||
* Each csched-balance step uses its own cpumask. This function determines
|
||||
* which one (given the step) and copies it in mask. For the node-affinity
|
||||
* balancing step, the pcpus that are not part of vc's vcpu-affinity are
|
||||
* which one (given the step) and copies it in mask. For the soft affinity
|
||||
* balancing step, the pcpus that are not part of vc's hard affinity are
|
||||
* filtered out from the result, to avoid running a vcpu where it would
|
||||
* like, but is not allowed to!
|
||||
*/
|
||||
static void
|
||||
csched_balance_cpumask(const struct vcpu *vc, int step, cpumask_t *mask)
|
||||
{
|
||||
if ( step == CSCHED_BALANCE_NODE_AFFINITY )
|
||||
if ( step == CSCHED_BALANCE_SOFT_AFFINITY )
|
||||
{
|
||||
cpumask_and(mask, CSCHED_DOM(vc->domain)->node_affinity_cpumask,
|
||||
vc->cpu_affinity);
|
||||
cpumask_and(mask, vc->cpu_soft_affinity, vc->cpu_hard_affinity);
|
||||
|
||||
if ( unlikely(cpumask_empty(mask)) )
|
||||
cpumask_copy(mask, vc->cpu_affinity);
|
||||
cpumask_copy(mask, vc->cpu_hard_affinity);
|
||||
}
|
||||
else /* step == CSCHED_BALANCE_CPU_AFFINITY */
|
||||
cpumask_copy(mask, vc->cpu_affinity);
|
||||
else /* step == CSCHED_BALANCE_HARD_AFFINITY */
|
||||
cpumask_copy(mask, vc->cpu_hard_affinity);
|
||||
}
|
||||
|
||||
static void burn_credits(struct csched_vcpu *svc, s_time_t now)
|
||||
@@ -398,16 +377,16 @@ __runq_tickle(unsigned int cpu, struct csched_vcpu *new)
|
||||
else if ( !idlers_empty )
|
||||
{
|
||||
/*
|
||||
* Node and vcpu-affinity balancing loop. For vcpus without
|
||||
* a useful node-affinity, consider vcpu-affinity only.
|
||||
* Soft and hard affinity balancing loop. For vcpus without
|
||||
* a useful soft affinity, consider hard affinity only.
|
||||
*/
|
||||
for_each_csched_balance_step( balance_step )
|
||||
{
|
||||
int new_idlers_empty;
|
||||
|
||||
if ( balance_step == CSCHED_BALANCE_NODE_AFFINITY
|
||||
&& !__vcpu_has_node_affinity(new->vcpu,
|
||||
new->vcpu->cpu_affinity) )
|
||||
if ( balance_step == CSCHED_BALANCE_SOFT_AFFINITY
|
||||
&& !__vcpu_has_soft_affinity(new->vcpu,
|
||||
new->vcpu->cpu_hard_affinity) )
|
||||
continue;
|
||||
|
||||
/* Are there idlers suitable for new (for this balance step)? */
|
||||
@@ -418,11 +397,11 @@ __runq_tickle(unsigned int cpu, struct csched_vcpu *new)
|
||||
|
||||
/*
|
||||
* Let's not be too harsh! If there aren't idlers suitable
|
||||
* for new in its node-affinity mask, make sure we check its
|
||||
* vcpu-affinity as well, before taking final decisions.
|
||||
* for new in its soft affinity mask, make sure we check its
|
||||
* hard affinity as well, before taking final decisions.
|
||||
*/
|
||||
if ( new_idlers_empty
|
||||
&& balance_step == CSCHED_BALANCE_NODE_AFFINITY )
|
||||
&& balance_step == CSCHED_BALANCE_SOFT_AFFINITY )
|
||||
continue;
|
||||
|
||||
/*
|
||||
@@ -642,30 +621,30 @@ _csched_cpu_pick(const struct scheduler *ops, struct vcpu *vc, bool_t commit)
|
||||
|
||||
/* Store in cpus the mask of online cpus on which the domain can run */
|
||||
online = cpupool_scheduler_cpumask(vc->domain->cpupool);
|
||||
cpumask_and(&cpus, vc->cpu_affinity, online);
|
||||
cpumask_and(&cpus, vc->cpu_hard_affinity, online);
|
||||
|
||||
for_each_csched_balance_step( balance_step )
|
||||
{
|
||||
/*
|
||||
* We want to pick up a pcpu among the ones that are online and
|
||||
* can accommodate vc, which is basically what we computed above
|
||||
* and stored in cpus. As far as vcpu-affinity is concerned,
|
||||
* and stored in cpus. As far as hard affinity is concerned,
|
||||
* there always will be at least one of these pcpus, hence cpus
|
||||
* is never empty and the calls to cpumask_cycle() and
|
||||
* cpumask_test_cpu() below are ok.
|
||||
*
|
||||
* On the other hand, when considering node-affinity too, it
|
||||
* On the other hand, when considering soft affinity too, it
|
||||
* is possible for the mask to become empty (for instance, if the
|
||||
* domain has been put in a cpupool that does not contain any of the
|
||||
* nodes in its node-affinity), which would result in the ASSERT()-s
|
||||
* pcpus in its soft affinity), which would result in the ASSERT()-s
|
||||
* inside cpumask_*() operations triggering (in debug builds).
|
||||
*
|
||||
* Therefore, in this case, we filter the node-affinity mask against
|
||||
* cpus and, if the result is empty, we just skip the node-affinity
|
||||
* Therefore, in this case, we filter the soft affinity mask against
|
||||
* cpus and, if the result is empty, we just skip the soft affinity
|
||||
* balancing step all together.
|
||||
*/
|
||||
if ( balance_step == CSCHED_BALANCE_NODE_AFFINITY
|
||||
&& !__vcpu_has_node_affinity(vc, &cpus) )
|
||||
if ( balance_step == CSCHED_BALANCE_SOFT_AFFINITY
|
||||
&& !__vcpu_has_soft_affinity(vc, &cpus) )
|
||||
continue;
|
||||
|
||||
/* Pick an online CPU from the proper affinity mask */
|
||||
@@ -1122,13 +1101,6 @@ csched_alloc_domdata(const struct scheduler *ops, struct domain *dom)
|
||||
if ( sdom == NULL )
|
||||
return NULL;
|
||||
|
||||
if ( !alloc_cpumask_var(&sdom->node_affinity_cpumask) )
|
||||
{
|
||||
xfree(sdom);
|
||||
return NULL;
|
||||
}
|
||||
cpumask_setall(sdom->node_affinity_cpumask);
|
||||
|
||||
/* Initialize credit and weight */
|
||||
INIT_LIST_HEAD(&sdom->active_vcpu);
|
||||
INIT_LIST_HEAD(&sdom->active_sdom_elem);
|
||||
@@ -1158,9 +1130,6 @@ csched_dom_init(const struct scheduler *ops, struct domain *dom)
|
||||
static void
|
||||
csched_free_domdata(const struct scheduler *ops, void *data)
|
||||
{
|
||||
struct csched_dom *sdom = data;
|
||||
|
||||
free_cpumask_var(sdom->node_affinity_cpumask);
|
||||
xfree(data);
|
||||
}
|
||||
|
||||
@@ -1486,19 +1455,19 @@ csched_runq_steal(int peer_cpu, int cpu, int pri, int balance_step)
|
||||
BUG_ON( is_idle_vcpu(vc) );
|
||||
|
||||
/*
|
||||
* If the vcpu has no useful node-affinity, skip this vcpu.
|
||||
* In fact, what we want is to check if we have any node-affine
|
||||
* work to steal, before starting to look at vcpu-affine work.
|
||||
* If the vcpu has no useful soft affinity, skip this vcpu.
|
||||
* In fact, what we want is to check if we have any "soft-affine
|
||||
* work" to steal, before starting to look at "hard-affine work".
|
||||
*
|
||||
* Notice that, if not even one vCPU on this runq has a useful
|
||||
* node-affinity, we could have avoid considering this runq for
|
||||
* a node balancing step in the first place. This, for instance,
|
||||
* soft affinity, we could have avoid considering this runq for
|
||||
* a soft balancing step in the first place. This, for instance,
|
||||
* can be implemented by taking note of on what runq there are
|
||||
* vCPUs with useful node-affinities in some sort of bitmap
|
||||
* vCPUs with useful soft affinities in some sort of bitmap
|
||||
* or counter.
|
||||
*/
|
||||
if ( balance_step == CSCHED_BALANCE_NODE_AFFINITY
|
||||
&& !__vcpu_has_node_affinity(vc, vc->cpu_affinity) )
|
||||
if ( balance_step == CSCHED_BALANCE_SOFT_AFFINITY
|
||||
&& !__vcpu_has_soft_affinity(vc, vc->cpu_hard_affinity) )
|
||||
continue;
|
||||
|
||||
csched_balance_cpumask(vc, balance_step, csched_balance_mask);
|
||||
@@ -1546,17 +1515,17 @@ csched_load_balance(struct csched_private *prv, int cpu,
|
||||
SCHED_STAT_CRANK(load_balance_other);
|
||||
|
||||
/*
|
||||
* Let's look around for work to steal, taking both vcpu-affinity
|
||||
* and node-affinity into account. More specifically, we check all
|
||||
* Let's look around for work to steal, taking both hard affinity
|
||||
* and soft affinity into account. More specifically, we check all
|
||||
* the non-idle CPUs' runq, looking for:
|
||||
* 1. any node-affine work to steal first,
|
||||
* 2. if not finding anything, any vcpu-affine work to steal.
|
||||
* 1. any "soft-affine work" to steal first,
|
||||
* 2. if not finding anything, any "hard-affine work" to steal.
|
||||
*/
|
||||
for_each_csched_balance_step( bstep )
|
||||
{
|
||||
/*
|
||||
* We peek at the non-idling CPUs in a node-wise fashion. In fact,
|
||||
* it is more likely that we find some node-affine work on our same
|
||||
* it is more likely that we find some affine work on our same
|
||||
* node, not to mention that migrating vcpus within the same node
|
||||
* could well expected to be cheaper than across-nodes (memory
|
||||
* stays local, there might be some node-wide cache[s], etc.).
|
||||
@@ -1982,8 +1951,6 @@ const struct scheduler sched_credit_def = {
|
||||
.adjust = csched_dom_cntl,
|
||||
.adjust_global = csched_sys_cntl,
|
||||
|
||||
.set_node_affinity = csched_set_node_affinity,
|
||||
|
||||
.pick_cpu = csched_cpu_pick,
|
||||
.do_schedule = csched_schedule,
|
||||
|
||||
|
||||
@@ -384,7 +384,7 @@ static int sedf_pick_cpu(const struct scheduler *ops, struct vcpu *v)
|
||||
cpumask_t *online;
|
||||
|
||||
online = cpupool_scheduler_cpumask(v->domain->cpupool);
|
||||
cpumask_and(&online_affinity, v->cpu_affinity, online);
|
||||
cpumask_and(&online_affinity, v->cpu_hard_affinity, online);
|
||||
return cpumask_cycle(v->vcpu_id % cpumask_weight(&online_affinity) - 1,
|
||||
&online_affinity);
|
||||
}
|
||||
|
||||
+40
-26
@@ -194,9 +194,11 @@ int sched_init_vcpu(struct vcpu *v, unsigned int processor)
|
||||
*/
|
||||
v->processor = processor;
|
||||
if ( is_idle_domain(d) || d->is_pinned )
|
||||
cpumask_copy(v->cpu_affinity, cpumask_of(processor));
|
||||
cpumask_copy(v->cpu_hard_affinity, cpumask_of(processor));
|
||||
else
|
||||
cpumask_setall(v->cpu_affinity);
|
||||
cpumask_setall(v->cpu_hard_affinity);
|
||||
|
||||
cpumask_setall(v->cpu_soft_affinity);
|
||||
|
||||
/* Initialise the per-vcpu timers. */
|
||||
init_timer(&v->periodic_timer, vcpu_periodic_timer_fn,
|
||||
@@ -285,7 +287,8 @@ int sched_move_domain(struct domain *d, struct cpupool *c)
|
||||
migrate_timer(&v->singleshot_timer, new_p);
|
||||
migrate_timer(&v->poll_timer, new_p);
|
||||
|
||||
cpumask_setall(v->cpu_affinity);
|
||||
cpumask_setall(v->cpu_hard_affinity);
|
||||
cpumask_setall(v->cpu_soft_affinity);
|
||||
|
||||
lock = vcpu_schedule_lock_irq(v);
|
||||
v->processor = new_p;
|
||||
@@ -307,7 +310,9 @@ int sched_move_domain(struct domain *d, struct cpupool *c)
|
||||
SCHED_OP(old_ops, free_vdata, vcpudata);
|
||||
}
|
||||
|
||||
domain_update_node_affinity(d);
|
||||
/* Do we have vcpus already? If not, no need to update node-affinity */
|
||||
if ( d->vcpu )
|
||||
domain_update_node_affinity(d);
|
||||
|
||||
domain_unpause(d);
|
||||
|
||||
@@ -458,7 +463,7 @@ static void vcpu_migrate(struct vcpu *v)
|
||||
*/
|
||||
if ( pick_called &&
|
||||
(new_lock == per_cpu(schedule_data, new_cpu).schedule_lock) &&
|
||||
cpumask_test_cpu(new_cpu, v->cpu_affinity) &&
|
||||
cpumask_test_cpu(new_cpu, v->cpu_hard_affinity) &&
|
||||
cpumask_test_cpu(new_cpu, v->domain->cpupool->cpu_valid) )
|
||||
break;
|
||||
|
||||
@@ -561,7 +566,7 @@ void restore_vcpu_affinity(struct domain *d)
|
||||
if ( v->affinity_broken )
|
||||
{
|
||||
printk(XENLOG_DEBUG "Restoring affinity for %pv\n", v);
|
||||
cpumask_copy(v->cpu_affinity, v->cpu_affinity_saved);
|
||||
cpumask_copy(v->cpu_hard_affinity, v->cpu_hard_affinity_saved);
|
||||
v->affinity_broken = 0;
|
||||
}
|
||||
|
||||
@@ -604,19 +609,20 @@ int cpu_disable_scheduler(unsigned int cpu)
|
||||
unsigned long flags;
|
||||
spinlock_t *lock = vcpu_schedule_lock_irqsave(v, &flags);
|
||||
|
||||
cpumask_and(&online_affinity, v->cpu_affinity, c->cpu_valid);
|
||||
cpumask_and(&online_affinity, v->cpu_hard_affinity, c->cpu_valid);
|
||||
if ( cpumask_empty(&online_affinity) &&
|
||||
cpumask_test_cpu(cpu, v->cpu_affinity) )
|
||||
cpumask_test_cpu(cpu, v->cpu_hard_affinity) )
|
||||
{
|
||||
printk(XENLOG_DEBUG "Breaking affinity for %pv\n", v);
|
||||
|
||||
if (system_state == SYS_STATE_suspend)
|
||||
{
|
||||
cpumask_copy(v->cpu_affinity_saved, v->cpu_affinity);
|
||||
cpumask_copy(v->cpu_hard_affinity_saved,
|
||||
v->cpu_hard_affinity);
|
||||
v->affinity_broken = 1;
|
||||
}
|
||||
|
||||
cpumask_setall(v->cpu_affinity);
|
||||
cpumask_setall(v->cpu_hard_affinity);
|
||||
}
|
||||
|
||||
if ( v->processor == cpu )
|
||||
@@ -644,27 +650,14 @@ int cpu_disable_scheduler(unsigned int cpu)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void sched_set_node_affinity(struct domain *d, nodemask_t *mask)
|
||||
static int vcpu_set_affinity(
|
||||
struct vcpu *v, const cpumask_t *affinity, cpumask_t *which)
|
||||
{
|
||||
SCHED_OP(DOM2OP(d), set_node_affinity, d, mask);
|
||||
}
|
||||
|
||||
int vcpu_set_affinity(struct vcpu *v, const cpumask_t *affinity)
|
||||
{
|
||||
cpumask_t online_affinity;
|
||||
cpumask_t *online;
|
||||
spinlock_t *lock;
|
||||
|
||||
if ( v->domain->is_pinned )
|
||||
return -EINVAL;
|
||||
online = VCPU2ONLINE(v);
|
||||
cpumask_and(&online_affinity, affinity, online);
|
||||
if ( cpumask_empty(&online_affinity) )
|
||||
return -EINVAL;
|
||||
|
||||
lock = vcpu_schedule_lock_irq(v);
|
||||
|
||||
cpumask_copy(v->cpu_affinity, affinity);
|
||||
cpumask_copy(which, affinity);
|
||||
|
||||
/* Always ask the scheduler to re-evaluate placement
|
||||
* when changing the affinity */
|
||||
@@ -683,6 +676,27 @@ int vcpu_set_affinity(struct vcpu *v, const cpumask_t *affinity)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vcpu_set_hard_affinity(struct vcpu *v, const cpumask_t *affinity)
|
||||
{
|
||||
cpumask_t online_affinity;
|
||||
cpumask_t *online;
|
||||
|
||||
if ( v->domain->is_pinned )
|
||||
return -EINVAL;
|
||||
|
||||
online = VCPU2ONLINE(v);
|
||||
cpumask_and(&online_affinity, affinity, online);
|
||||
if ( cpumask_empty(&online_affinity) )
|
||||
return -EINVAL;
|
||||
|
||||
return vcpu_set_affinity(v, affinity, v->cpu_hard_affinity);
|
||||
}
|
||||
|
||||
int vcpu_set_soft_affinity(struct vcpu *v, const cpumask_t *affinity)
|
||||
{
|
||||
return vcpu_set_affinity(v, affinity, v->cpu_soft_affinity);
|
||||
}
|
||||
|
||||
/* Block the currently-executing domain until a pertinent event occurs. */
|
||||
void vcpu_block(void)
|
||||
{
|
||||
|
||||
+5
-5
@@ -134,8 +134,8 @@ static void __prepare_to_wait(struct waitqueue_vcpu *wqv)
|
||||
|
||||
/* Save current VCPU affinity; force wakeup on *this* CPU only. */
|
||||
wqv->wakeup_cpu = smp_processor_id();
|
||||
cpumask_copy(&wqv->saved_affinity, curr->cpu_affinity);
|
||||
if ( vcpu_set_affinity(curr, cpumask_of(wqv->wakeup_cpu)) )
|
||||
cpumask_copy(&wqv->saved_affinity, curr->cpu_hard_affinity);
|
||||
if ( vcpu_set_hard_affinity(curr, cpumask_of(wqv->wakeup_cpu)) )
|
||||
{
|
||||
gdprintk(XENLOG_ERR, "Unable to set vcpu affinity\n");
|
||||
domain_crash_synchronous();
|
||||
@@ -166,7 +166,7 @@ static void __prepare_to_wait(struct waitqueue_vcpu *wqv)
|
||||
static void __finish_wait(struct waitqueue_vcpu *wqv)
|
||||
{
|
||||
wqv->esp = NULL;
|
||||
(void)vcpu_set_affinity(current, &wqv->saved_affinity);
|
||||
(void)vcpu_set_hard_affinity(current, &wqv->saved_affinity);
|
||||
}
|
||||
|
||||
void check_wakeup_from_wait(void)
|
||||
@@ -183,8 +183,8 @@ void check_wakeup_from_wait(void)
|
||||
{
|
||||
/* Re-set VCPU affinity and re-enter the scheduler. */
|
||||
struct vcpu *curr = current;
|
||||
cpumask_copy(&wqv->saved_affinity, curr->cpu_affinity);
|
||||
if ( vcpu_set_affinity(curr, cpumask_of(wqv->wakeup_cpu)) )
|
||||
cpumask_copy(&wqv->saved_affinity, curr->cpu_hard_affinity);
|
||||
if ( vcpu_set_hard_affinity(curr, cpumask_of(wqv->wakeup_cpu)) )
|
||||
{
|
||||
gdprintk(XENLOG_ERR, "Unable to set vcpu affinity\n");
|
||||
domain_crash_synchronous();
|
||||
|
||||
+107
-86
@@ -51,11 +51,8 @@ static int pt_irq_guest_eoi(struct domain *d, struct hvm_pirq_dpci *pirq_dpci,
|
||||
static void pt_irq_time_out(void *data)
|
||||
{
|
||||
struct hvm_pirq_dpci *irq_map = data;
|
||||
unsigned int guest_gsi;
|
||||
struct hvm_irq_dpci *dpci = NULL;
|
||||
struct dev_intx_gsi_link *digl;
|
||||
struct hvm_girq_dpci_mapping *girq;
|
||||
uint32_t device, intx;
|
||||
const struct hvm_irq_dpci *dpci;
|
||||
const struct dev_intx_gsi_link *digl;
|
||||
|
||||
spin_lock(&irq_map->dom->event_lock);
|
||||
|
||||
@@ -63,16 +60,16 @@ static void pt_irq_time_out(void *data)
|
||||
ASSERT(dpci);
|
||||
list_for_each_entry ( digl, &irq_map->digl_list, list )
|
||||
{
|
||||
guest_gsi = digl->gsi;
|
||||
unsigned int guest_gsi = hvm_pci_intx_gsi(digl->device, digl->intx);
|
||||
const struct hvm_girq_dpci_mapping *girq;
|
||||
|
||||
list_for_each_entry ( girq, &dpci->girq[guest_gsi], list )
|
||||
{
|
||||
struct pirq *pirq = pirq_info(irq_map->dom, girq->machine_gsi);
|
||||
|
||||
pirq_dpci(pirq)->flags |= HVM_IRQ_DPCI_EOI_LATCH;
|
||||
}
|
||||
device = digl->device;
|
||||
intx = digl->intx;
|
||||
hvm_pci_intx_deassert(irq_map->dom, device, intx);
|
||||
hvm_pci_intx_deassert(irq_map->dom, digl->device, digl->intx);
|
||||
}
|
||||
|
||||
pt_pirq_iterate(irq_map->dom, pt_irq_guest_eoi, NULL);
|
||||
@@ -96,13 +93,9 @@ void free_hvm_irq_dpci(struct hvm_irq_dpci *dpci)
|
||||
int pt_irq_create_bind(
|
||||
struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
|
||||
{
|
||||
struct hvm_irq_dpci *hvm_irq_dpci = NULL;
|
||||
struct hvm_irq_dpci *hvm_irq_dpci;
|
||||
struct hvm_pirq_dpci *pirq_dpci;
|
||||
struct pirq *info;
|
||||
uint32_t guest_gsi;
|
||||
uint32_t device, intx, link;
|
||||
struct dev_intx_gsi_link *digl;
|
||||
struct hvm_girq_dpci_mapping *girq;
|
||||
int rc, pirq = pt_irq_bind->machine_irq;
|
||||
|
||||
if ( pirq < 0 || pirq >= d->nr_pirqs )
|
||||
@@ -113,6 +106,8 @@ int pt_irq_create_bind(
|
||||
hvm_irq_dpci = domain_get_irq_dpci(d);
|
||||
if ( hvm_irq_dpci == NULL )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
hvm_irq_dpci = xzalloc(struct hvm_irq_dpci);
|
||||
if ( hvm_irq_dpci == NULL )
|
||||
{
|
||||
@@ -122,7 +117,7 @@ int pt_irq_create_bind(
|
||||
softirq_tasklet_init(
|
||||
&hvm_irq_dpci->dirq_tasklet,
|
||||
hvm_dirq_assist, (unsigned long)d);
|
||||
for ( int i = 0; i < NR_HVM_IRQS; i++ )
|
||||
for ( i = 0; i < NR_HVM_IRQS; i++ )
|
||||
INIT_LIST_HEAD(&hvm_irq_dpci->girq[i]);
|
||||
|
||||
d->arch.hvm_domain.irq.dpci = hvm_irq_dpci;
|
||||
@@ -136,7 +131,9 @@ int pt_irq_create_bind(
|
||||
}
|
||||
pirq_dpci = pirq_dpci(info);
|
||||
|
||||
if ( pt_irq_bind->irq_type == PT_IRQ_TYPE_MSI )
|
||||
switch ( pt_irq_bind->irq_type )
|
||||
{
|
||||
case PT_IRQ_TYPE_MSI:
|
||||
{
|
||||
uint8_t dest, dest_mode;
|
||||
int dest_vcpu_id;
|
||||
@@ -169,15 +166,16 @@ int pt_irq_create_bind(
|
||||
{
|
||||
uint32_t mask = HVM_IRQ_DPCI_MACH_MSI | HVM_IRQ_DPCI_GUEST_MSI;
|
||||
|
||||
if ( (pirq_dpci->flags & mask) != mask)
|
||||
if ( (pirq_dpci->flags & mask) != mask )
|
||||
{
|
||||
spin_unlock(&d->event_lock);
|
||||
return -EBUSY;
|
||||
spin_unlock(&d->event_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* if pirq is already mapped as vmsi, update the guest data/addr */
|
||||
/* If pirq is already mapped as vmsi, update guest data/addr. */
|
||||
if ( pirq_dpci->gmsi.gvec != pt_irq_bind->u.msi.gvec ||
|
||||
pirq_dpci->gmsi.gflags != pt_irq_bind->u.msi.gflags) {
|
||||
pirq_dpci->gmsi.gflags != pt_irq_bind->u.msi.gflags )
|
||||
{
|
||||
/* Directly clear pending EOIs before enabling new MSI info. */
|
||||
pirq_guest_eoi(info);
|
||||
|
||||
@@ -185,7 +183,7 @@ int pt_irq_create_bind(
|
||||
pirq_dpci->gmsi.gflags = pt_irq_bind->u.msi.gflags;
|
||||
}
|
||||
}
|
||||
/* Caculate dest_vcpu_id for MSI-type pirq migration */
|
||||
/* Calculate dest_vcpu_id for MSI-type pirq migration. */
|
||||
dest = pirq_dpci->gmsi.gflags & VMSI_DEST_ID_MASK;
|
||||
dest_mode = !!(pirq_dpci->gmsi.gflags & VMSI_DM_MASK);
|
||||
dest_vcpu_id = hvm_girq_dest_2_vcpu_id(d, dest, dest_mode);
|
||||
@@ -193,36 +191,37 @@ int pt_irq_create_bind(
|
||||
spin_unlock(&d->event_lock);
|
||||
if ( dest_vcpu_id >= 0 )
|
||||
hvm_migrate_pirqs(d->vcpu[dest_vcpu_id]);
|
||||
break;
|
||||
}
|
||||
else
|
||||
|
||||
case PT_IRQ_TYPE_PCI:
|
||||
case PT_IRQ_TYPE_MSI_TRANSLATE:
|
||||
{
|
||||
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);
|
||||
unsigned int bus = pt_irq_bind->u.pci.bus;
|
||||
unsigned int device = pt_irq_bind->u.pci.device;
|
||||
unsigned int intx = pt_irq_bind->u.pci.intx;
|
||||
unsigned int guest_gsi = hvm_pci_intx_gsi(device, intx);
|
||||
unsigned int link = hvm_pci_intx_link(device, intx);
|
||||
struct dev_intx_gsi_link *digl = xmalloc(struct dev_intx_gsi_link);
|
||||
struct hvm_girq_dpci_mapping *girq =
|
||||
xmalloc(struct hvm_girq_dpci_mapping);
|
||||
|
||||
if ( !digl || !girq )
|
||||
{
|
||||
spin_unlock(&d->event_lock);
|
||||
xfree(girq);
|
||||
xfree(digl);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hvm_irq_dpci->link_cnt[link]++;
|
||||
|
||||
digl = xmalloc(struct dev_intx_gsi_link);
|
||||
if ( !digl )
|
||||
{
|
||||
spin_unlock(&d->event_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
girq = xmalloc(struct hvm_girq_dpci_mapping);
|
||||
if ( !girq )
|
||||
{
|
||||
xfree(digl);
|
||||
spin_unlock(&d->event_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
digl->bus = bus;
|
||||
digl->device = device;
|
||||
digl->intx = intx;
|
||||
digl->gsi = guest_gsi;
|
||||
digl->link = link;
|
||||
list_add_tail(&digl->list, &pirq_dpci->digl_list);
|
||||
|
||||
girq->bus = bus;
|
||||
girq->device = device;
|
||||
girq->intx = intx;
|
||||
girq->machine_gsi = pirq;
|
||||
@@ -261,12 +260,12 @@ int pt_irq_create_bind(
|
||||
kill_timer(&pirq_dpci->timer);
|
||||
pirq_dpci->dom = NULL;
|
||||
list_del(&girq->list);
|
||||
xfree(girq);
|
||||
list_del(&digl->list);
|
||||
hvm_irq_dpci->link_cnt[link]--;
|
||||
pirq_dpci->flags = 0;
|
||||
pirq_cleanup_check(info, d);
|
||||
spin_unlock(&d->event_lock);
|
||||
xfree(girq);
|
||||
xfree(digl);
|
||||
return rc;
|
||||
}
|
||||
@@ -276,33 +275,51 @@ int pt_irq_create_bind(
|
||||
|
||||
if ( iommu_verbose )
|
||||
dprintk(XENLOG_G_INFO,
|
||||
"d%d: bind: m_gsi=%u g_gsi=%u device=%u intx=%u\n",
|
||||
d->domain_id, pirq, guest_gsi, device, intx);
|
||||
"d%d: bind: m_gsi=%u g_gsi=%u dev=%02x.%02x.%u intx=%u\n",
|
||||
d->domain_id, pirq, guest_gsi, bus,
|
||||
PCI_SLOT(device), PCI_FUNC(device), intx);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
spin_unlock(&d->event_lock);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pt_irq_destroy_bind(
|
||||
struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
|
||||
{
|
||||
struct hvm_irq_dpci *hvm_irq_dpci = NULL;
|
||||
struct hvm_irq_dpci *hvm_irq_dpci;
|
||||
struct hvm_pirq_dpci *pirq_dpci;
|
||||
uint32_t machine_gsi, guest_gsi;
|
||||
uint32_t device, intx, link;
|
||||
unsigned int machine_gsi = pt_irq_bind->machine_irq;
|
||||
unsigned int bus = pt_irq_bind->u.pci.bus;
|
||||
unsigned int device = pt_irq_bind->u.pci.device;
|
||||
unsigned int intx = pt_irq_bind->u.pci.intx;
|
||||
unsigned int guest_gsi = hvm_pci_intx_gsi(device, intx);
|
||||
unsigned int link = hvm_pci_intx_link(device, intx);
|
||||
struct dev_intx_gsi_link *digl, *tmp;
|
||||
struct hvm_girq_dpci_mapping *girq;
|
||||
struct pirq *pirq;
|
||||
|
||||
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);
|
||||
switch ( pt_irq_bind->irq_type )
|
||||
{
|
||||
case PT_IRQ_TYPE_PCI:
|
||||
case PT_IRQ_TYPE_MSI_TRANSLATE:
|
||||
break;
|
||||
case PT_IRQ_TYPE_MSI:
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if ( iommu_verbose )
|
||||
dprintk(XENLOG_G_INFO,
|
||||
"d%d: unbind: m_gsi=%u g_gsi=%u device=%u intx=%u\n",
|
||||
d->domain_id, machine_gsi, guest_gsi, device, intx);
|
||||
"d%d: unbind: m_gsi=%u g_gsi=%u dev=%02x:%02x.%u intx=%u\n",
|
||||
d->domain_id, machine_gsi, guest_gsi, bus,
|
||||
PCI_SLOT(device), PCI_FUNC(device), intx);
|
||||
|
||||
spin_lock(&d->event_lock);
|
||||
|
||||
@@ -314,18 +331,28 @@ int pt_irq_destroy_bind(
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hvm_irq_dpci->link_cnt[link]--;
|
||||
|
||||
list_for_each_entry ( girq, &hvm_irq_dpci->girq[guest_gsi], list )
|
||||
{
|
||||
if ( girq->machine_gsi == machine_gsi )
|
||||
if ( girq->bus == bus &&
|
||||
girq->device == device &&
|
||||
girq->intx == intx &&
|
||||
girq->machine_gsi == machine_gsi )
|
||||
{
|
||||
list_del(&girq->list);
|
||||
xfree(girq);
|
||||
break;
|
||||
list_del(&girq->list);
|
||||
xfree(girq);
|
||||
girq = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( girq )
|
||||
{
|
||||
spin_unlock(&d->event_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hvm_irq_dpci->link_cnt[link]--;
|
||||
|
||||
pirq = pirq_info(d, machine_gsi);
|
||||
pirq_dpci = pirq_dpci(pirq);
|
||||
|
||||
@@ -334,10 +361,9 @@ int pt_irq_destroy_bind(
|
||||
{
|
||||
list_for_each_entry_safe ( digl, tmp, &pirq_dpci->digl_list, list )
|
||||
{
|
||||
if ( digl->device == device &&
|
||||
digl->intx == intx &&
|
||||
digl->link == link &&
|
||||
digl->gsi == guest_gsi )
|
||||
if ( digl->bus == bus &&
|
||||
digl->device == device &&
|
||||
digl->intx == intx )
|
||||
{
|
||||
list_del(&digl->list);
|
||||
xfree(digl);
|
||||
@@ -359,8 +385,9 @@ int pt_irq_destroy_bind(
|
||||
|
||||
if ( iommu_verbose )
|
||||
dprintk(XENLOG_G_INFO,
|
||||
"d%d unmap: m_irq=%u device=%u intx=%u\n",
|
||||
d->domain_id, machine_gsi, device, intx);
|
||||
"d%d unmap: m_irq=%u dev=%02x:%02x.%u intx=%u\n",
|
||||
d->domain_id, machine_gsi, bus,
|
||||
PCI_SLOT(device), PCI_FUNC(device), intx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -481,11 +508,10 @@ static void hvm_pci_msi_assert(
|
||||
static int _hvm_dirq_assist(struct domain *d, struct hvm_pirq_dpci *pirq_dpci,
|
||||
void *arg)
|
||||
{
|
||||
uint32_t device, intx;
|
||||
struct dev_intx_gsi_link *digl;
|
||||
|
||||
if ( test_and_clear_bool(pirq_dpci->masked) )
|
||||
{
|
||||
const struct dev_intx_gsi_link *digl;
|
||||
|
||||
if ( pirq_dpci->flags & HVM_IRQ_DPCI_GUEST_MSI )
|
||||
{
|
||||
hvm_pci_msi_assert(d, pirq_dpci);
|
||||
@@ -496,12 +522,10 @@ static int _hvm_dirq_assist(struct domain *d, struct hvm_pirq_dpci *pirq_dpci,
|
||||
{
|
||||
struct pirq *info = dpci_pirq(pirq_dpci);
|
||||
|
||||
device = digl->device;
|
||||
intx = digl->intx;
|
||||
if ( hvm_domain_use_pirq(d, info) )
|
||||
send_guest_pirq(d, info);
|
||||
else
|
||||
hvm_pci_intx_assert(d, device, intx);
|
||||
hvm_pci_intx_assert(d, digl->device, digl->intx);
|
||||
pirq_dpci->pending++;
|
||||
|
||||
if ( pirq_dpci->flags & HVM_IRQ_DPCI_TRANSLATE )
|
||||
@@ -537,16 +561,13 @@ static void hvm_dirq_assist(unsigned long _d)
|
||||
}
|
||||
|
||||
static void __hvm_dpci_eoi(struct domain *d,
|
||||
struct hvm_girq_dpci_mapping *girq,
|
||||
union vioapic_redir_entry *ent)
|
||||
const struct hvm_girq_dpci_mapping *girq,
|
||||
const union vioapic_redir_entry *ent)
|
||||
{
|
||||
uint32_t device, intx;
|
||||
struct pirq *pirq;
|
||||
struct hvm_pirq_dpci *pirq_dpci;
|
||||
|
||||
device = girq->device;
|
||||
intx = girq->intx;
|
||||
hvm_pci_intx_deassert(d, device, intx);
|
||||
hvm_pci_intx_deassert(d, girq->device, girq->intx);
|
||||
|
||||
pirq = pirq_info(d, girq->machine_gsi);
|
||||
pirq_dpci = pirq_dpci(pirq);
|
||||
@@ -556,8 +577,8 @@ static void __hvm_dpci_eoi(struct domain *d,
|
||||
* since interrupt is still not EOIed
|
||||
*/
|
||||
if ( --pirq_dpci->pending ||
|
||||
( ent && ent->fields.mask ) ||
|
||||
! pt_irq_need_timer(pirq_dpci->flags) )
|
||||
(ent && ent->fields.mask) ||
|
||||
!pt_irq_need_timer(pirq_dpci->flags) )
|
||||
return;
|
||||
|
||||
stop_timer(&pirq_dpci->timer);
|
||||
@@ -565,10 +586,10 @@ static void __hvm_dpci_eoi(struct domain *d,
|
||||
}
|
||||
|
||||
void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi,
|
||||
union vioapic_redir_entry *ent)
|
||||
const union vioapic_redir_entry *ent)
|
||||
{
|
||||
struct hvm_irq_dpci *hvm_irq_dpci;
|
||||
struct hvm_girq_dpci_mapping *girq;
|
||||
const struct hvm_irq_dpci *hvm_irq_dpci;
|
||||
const struct hvm_girq_dpci_mapping *girq;
|
||||
|
||||
if ( !iommu_enabled )
|
||||
return;
|
||||
|
||||
@@ -69,11 +69,13 @@ static int _hvm_dpci_isairq_eoi(struct domain *d,
|
||||
{
|
||||
struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
|
||||
unsigned int isairq = (long)arg;
|
||||
struct dev_intx_gsi_link *digl, *tmp;
|
||||
const struct dev_intx_gsi_link *digl;
|
||||
|
||||
list_for_each_entry_safe ( digl, tmp, &pirq_dpci->digl_list, list )
|
||||
list_for_each_entry ( digl, &pirq_dpci->digl_list, list )
|
||||
{
|
||||
if ( hvm_irq->pci_link.route[digl->link] == isairq )
|
||||
unsigned int link = hvm_pci_intx_link(digl->device, digl->intx);
|
||||
|
||||
if ( hvm_irq->pci_link.route[link] == isairq )
|
||||
{
|
||||
hvm_pci_intx_deassert(d, digl->device, digl->intx);
|
||||
if ( --pirq_dpci->pending == 0 )
|
||||
|
||||
@@ -12,6 +12,7 @@ static inline __attribute__((pure)) int phys_to_nid(paddr_t addr)
|
||||
|
||||
/* XXX: implement NUMA support */
|
||||
#define node_spanned_pages(nid) (total_pages)
|
||||
#define node_start_pfn(nid) (frametable_base_mfn)
|
||||
#define __node_distance(a, b) (20)
|
||||
|
||||
#endif /* __ARCH_ARM_NUMA_H */
|
||||
|
||||
@@ -123,7 +123,7 @@ int handle_pio(uint16_t port, unsigned int size, int dir);
|
||||
void hvm_interrupt_post(struct vcpu *v, int vector, int type);
|
||||
void hvm_io_assist(ioreq_t *p);
|
||||
void hvm_dpci_eoi(struct domain *d, unsigned int guest_irq,
|
||||
union vioapic_redir_entry *ent);
|
||||
const union vioapic_redir_entry *ent);
|
||||
void msix_write_completion(struct vcpu *);
|
||||
|
||||
struct hvm_hw_stdvga {
|
||||
|
||||
@@ -300,8 +300,33 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_nodeaffinity_t);
|
||||
/* XEN_DOMCTL_setvcpuaffinity */
|
||||
/* XEN_DOMCTL_getvcpuaffinity */
|
||||
struct xen_domctl_vcpuaffinity {
|
||||
uint32_t vcpu; /* IN */
|
||||
struct xenctl_bitmap cpumap; /* IN/OUT */
|
||||
/* IN variables. */
|
||||
uint32_t vcpu;
|
||||
/* Set/get the hard affinity for vcpu */
|
||||
#define _XEN_VCPUAFFINITY_HARD 0
|
||||
#define XEN_VCPUAFFINITY_HARD (1U<<_XEN_VCPUAFFINITY_HARD)
|
||||
/* Set/get the soft affinity for vcpu */
|
||||
#define _XEN_VCPUAFFINITY_SOFT 1
|
||||
#define XEN_VCPUAFFINITY_SOFT (1U<<_XEN_VCPUAFFINITY_SOFT)
|
||||
uint32_t flags;
|
||||
/*
|
||||
* IN/OUT variables.
|
||||
*
|
||||
* Both are IN/OUT for XEN_DOMCTL_setvcpuaffinity, in which case they
|
||||
* contain effective hard or/and soft affinity. That is, upon successful
|
||||
* return, cpumap_soft, contains the intersection of the soft affinity,
|
||||
* hard affinity and the cpupool's online CPUs for the domain (if
|
||||
* XEN_VCPUAFFINITY_SOFT was set in flags). cpumap_hard contains the
|
||||
* intersection between hard affinity and the cpupool's online CPUs (if
|
||||
* XEN_VCPUAFFINITY_HARD was set in flags).
|
||||
*
|
||||
* Both are OUT-only for XEN_DOMCTL_getvcpuaffinity, in which case they
|
||||
* contain the plain hard and/or soft affinity masks that were set during
|
||||
* previous successful calls to XEN_DOMCTL_setvcpuaffinity (or the
|
||||
* default values), without intersecting or altering them in any way.
|
||||
*/
|
||||
struct xenctl_bitmap cpumap_hard;
|
||||
struct xenctl_bitmap cpumap_soft;
|
||||
};
|
||||
typedef struct xen_domctl_vcpuaffinity xen_domctl_vcpuaffinity_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(xen_domctl_vcpuaffinity_t);
|
||||
|
||||
@@ -30,10 +30,9 @@
|
||||
|
||||
struct dev_intx_gsi_link {
|
||||
struct list_head list;
|
||||
uint8_t bus;
|
||||
uint8_t device;
|
||||
uint8_t intx;
|
||||
uint8_t gsi;
|
||||
uint8_t link;
|
||||
};
|
||||
|
||||
#define _HVM_IRQ_DPCI_MACH_PCI_SHIFT 0
|
||||
@@ -69,6 +68,7 @@ struct hvm_gmsi_info {
|
||||
|
||||
struct hvm_girq_dpci_mapping {
|
||||
struct list_head list;
|
||||
uint8_t bus;
|
||||
uint8_t device;
|
||||
uint8_t intx;
|
||||
uint8_t machine_gsi;
|
||||
|
||||
@@ -158,8 +158,6 @@ struct scheduler {
|
||||
struct xen_domctl_scheduler_op *);
|
||||
int (*adjust_global) (const struct scheduler *,
|
||||
struct xen_sysctl_scheduler_op *);
|
||||
void (*set_node_affinity) (const struct scheduler *,
|
||||
struct domain *, nodemask_t *);
|
||||
void (*dump_settings) (const struct scheduler *);
|
||||
void (*dump_cpu_state) (const struct scheduler *, int);
|
||||
|
||||
|
||||
@@ -219,11 +219,14 @@ struct vcpu
|
||||
spinlock_t virq_lock;
|
||||
|
||||
/* Bitmask of CPUs on which this VCPU may run. */
|
||||
cpumask_var_t cpu_affinity;
|
||||
cpumask_var_t cpu_hard_affinity;
|
||||
/* Used to change affinity temporarily. */
|
||||
cpumask_var_t cpu_affinity_tmp;
|
||||
cpumask_var_t cpu_hard_affinity_tmp;
|
||||
/* Used to restore affinity across S3. */
|
||||
cpumask_var_t cpu_affinity_saved;
|
||||
cpumask_var_t cpu_hard_affinity_saved;
|
||||
|
||||
/* Bitmask of CPUs on which this VCPU prefers to run. */
|
||||
cpumask_var_t cpu_soft_affinity;
|
||||
|
||||
/* Bitmask of CPUs which are holding onto this VCPU's state. */
|
||||
cpumask_var_t vcpu_dirty_cpumask;
|
||||
@@ -627,7 +630,6 @@ void sched_destroy_domain(struct domain *d);
|
||||
int sched_move_domain(struct domain *d, struct cpupool *c);
|
||||
long sched_adjust(struct domain *, struct xen_domctl_scheduler_op *);
|
||||
long sched_adjust_global(struct xen_sysctl_scheduler_op *);
|
||||
void sched_set_node_affinity(struct domain *, nodemask_t *);
|
||||
int sched_id(void);
|
||||
void sched_tick_suspend(void);
|
||||
void sched_tick_resume(void);
|
||||
@@ -779,7 +781,8 @@ void scheduler_free(struct scheduler *sched);
|
||||
int schedule_cpu_switch(unsigned int cpu, struct cpupool *c);
|
||||
void vcpu_force_reschedule(struct vcpu *v);
|
||||
int cpu_disable_scheduler(unsigned int cpu);
|
||||
int vcpu_set_affinity(struct vcpu *v, const cpumask_t *affinity);
|
||||
int vcpu_set_hard_affinity(struct vcpu *v, const cpumask_t *affinity);
|
||||
int vcpu_set_soft_affinity(struct vcpu *v, const cpumask_t *affinity);
|
||||
void restore_vcpu_affinity(struct domain *d);
|
||||
|
||||
void vcpu_runstate_get(struct vcpu *v, struct vcpu_runstate_info *runstate);
|
||||
@@ -819,7 +822,7 @@ void watchdog_domain_destroy(struct domain *d);
|
||||
#define has_hvm_container_domain(d) ((d)->guest_type != guest_type_pv)
|
||||
#define has_hvm_container_vcpu(v) (has_hvm_container_domain((v)->domain))
|
||||
#define is_pinned_vcpu(v) ((v)->domain->is_pinned || \
|
||||
cpumask_weight((v)->cpu_affinity) == 1)
|
||||
cpumask_weight((v)->cpu_hard_affinity) == 1)
|
||||
#ifdef HAS_PASSTHROUGH
|
||||
#define need_iommu(d) ((d)->need_iommu)
|
||||
#else
|
||||
|
||||