x86: handle domains with no CPUs usable for intr delivery
We can end up with a domain having no CPUs capable of receiving I/O
interrupts. This can occur, for example, when all APIC IDs in a given
domain are 256 or greater, and we have no IOMMU.
In this case disable per-domain interrupt support, effectively reverting
to the behaviour before commit a48de40bcc
("Only use CPUs in the
domain the device is attached to for default"). This has a performance
impact but at least allows the system to be functional. It is a stop-
gap until we can rely on the presence of an IOMMU on all x86 platforms.
Thanks to AMD for providing the high-thread-count machine I used for
testing this change, and to cperciva for testing on other hardware.
Reviewed by: jhb
Tested by: cperciva, emaste
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D41501
This commit is contained in:
parent
b404e03007
commit
4258eb5a0d
|
@ -578,10 +578,17 @@ DB_SHOW_COMMAND(irqs, db_show_irqs)
|
|||
/*
|
||||
* Support for balancing interrupt sources across CPUs. For now we just
|
||||
* allocate CPUs round-robin.
|
||||
*
|
||||
* XXX If the system has a domain with without any usable CPUs (e.g., where all
|
||||
* APIC IDs are 256 or greater and we do not have an IOMMU) we use
|
||||
* intr_no_domain to fall back to assigning interrupts without regard for
|
||||
* domain. Once we can rely on the presence of an IOMMU on all x86 platforms
|
||||
* we can revert this.
|
||||
*/
|
||||
|
||||
cpuset_t intr_cpus = CPUSET_T_INITIALIZER(0x1);
|
||||
static int current_cpu[MAXMEMDOM];
|
||||
static bool intr_no_domain;
|
||||
|
||||
static void
|
||||
intr_init_cpus(void)
|
||||
|
@ -589,7 +596,15 @@ intr_init_cpus(void)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < vm_ndomains; i++) {
|
||||
if (CPU_OVERLAP(&cpuset_domain[i], &intr_cpus) == 0) {
|
||||
intr_no_domain = true;
|
||||
printf("%s: unable to route interrupts to CPUs in domain %d\n",
|
||||
__func__, i);
|
||||
}
|
||||
|
||||
current_cpu[i] = 0;
|
||||
if (intr_no_domain && i > 0)
|
||||
continue;
|
||||
if (!CPU_ISSET(current_cpu[i], &intr_cpus) ||
|
||||
!CPU_ISSET(current_cpu[i], &cpuset_domain[i]))
|
||||
intr_next_cpu(i);
|
||||
|
@ -615,6 +630,8 @@ intr_next_cpu(int domain)
|
|||
return (PCPU_GET(apic_id));
|
||||
#endif
|
||||
|
||||
if (intr_no_domain)
|
||||
domain = 0;
|
||||
mtx_lock_spin(&icu_lock);
|
||||
apic_id = cpu_apic_ids[current_cpu[domain]];
|
||||
do {
|
||||
|
@ -622,7 +639,8 @@ intr_next_cpu(int domain)
|
|||
if (current_cpu[domain] > mp_maxid)
|
||||
current_cpu[domain] = 0;
|
||||
} while (!CPU_ISSET(current_cpu[domain], &intr_cpus) ||
|
||||
!CPU_ISSET(current_cpu[domain], &cpuset_domain[domain]));
|
||||
(!CPU_ISSET(current_cpu[domain], &cpuset_domain[domain]) &&
|
||||
!intr_no_domain));
|
||||
mtx_unlock_spin(&icu_lock);
|
||||
return (apic_id);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue