diff --git a/arch/x86/include/asm/xen/events.h b/arch/x86/include/asm/xen/events.h index e6911caf5bbf..608a79d5a466 100644 --- a/arch/x86/include/asm/xen/events.h +++ b/arch/x86/include/asm/xen/events.h @@ -20,15 +20,4 @@ static inline int xen_irqs_disabled(struct pt_regs *regs) /* No need for a barrier -- XCHG is a barrier on x86. */ #define xchg_xen_ulong(ptr, val) xchg((ptr), (val)) -extern int xen_have_vector_callback; - -/* - * Events delivered via platform PCI interrupts are always - * routed to vcpu 0 and hence cannot be rebound. - */ -static inline bool xen_support_evtchn_rebind(void) -{ - return (!xen_hvm_domain() || xen_have_vector_callback); -} - #endif /* _ASM_X86_XEN_EVENTS_H */ diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index 3a483cb5ac81..bedfab98077a 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -456,7 +456,7 @@ void __init xen_msi_init(void) int __init pci_xen_hvm_init(void) { - if (!xen_have_vector_callback || !xen_feature(XENFEAT_hvm_pirqs)) + if (!xen_feature(XENFEAT_hvm_pirqs)) return 0; #ifdef CONFIG_ACPI diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index f1d2182e071f..c0fdd57da7aa 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -137,8 +137,10 @@ struct shared_info xen_dummy_shared_info; void *xen_initial_gdt; RESERVE_BRK(shared_info_page_brk, PAGE_SIZE); -__read_mostly int xen_have_vector_callback; -EXPORT_SYMBOL_GPL(xen_have_vector_callback); + +static int xen_cpu_up_prepare(unsigned int cpu); +static int xen_cpu_up_online(unsigned int cpu); +static int xen_cpu_dead(unsigned int cpu); /* * Point at some empty memory to start with. We map the real shared_info @@ -1519,10 +1521,7 @@ static void __init xen_pvh_early_guest_init(void) if (!xen_feature(XENFEAT_auto_translated_physmap)) return; - if (!xen_feature(XENFEAT_hvm_callback_vector)) - return; - - xen_have_vector_callback = 1; + BUG_ON(!xen_feature(XENFEAT_hvm_callback_vector)); xen_pvh_early_cpu_init(0, false); xen_pvh_set_cr_flags(0); @@ -1538,6 +1537,24 @@ static void __init xen_dom0_set_legacy_features(void) x86_platform.legacy.rtc = 1; } +static int xen_cpuhp_setup(void) +{ + int rc; + + rc = cpuhp_setup_state_nocalls(CPUHP_XEN_PREPARE, + "XEN_HVM_GUEST_PREPARE", + xen_cpu_up_prepare, xen_cpu_dead); + if (rc >= 0) { + rc = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, + "XEN_HVM_GUEST_ONLINE", + xen_cpu_up_online, NULL); + if (rc < 0) + cpuhp_remove_state_nocalls(CPUHP_XEN_PREPARE); + } + + return rc >= 0 ? 0 : rc; +} + /* First C function to be called on Xen boot */ asmlinkage __visible void __init xen_start_kernel(void) { @@ -1639,6 +1656,8 @@ asmlinkage __visible void __init xen_start_kernel(void) possible map and a non-dummy shared_info. */ per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0]; + WARN_ON(xen_cpuhp_setup()); + local_irq_disable(); early_boot_irqs_disabled = true; @@ -1819,31 +1838,54 @@ static void __init init_hvm_pv_info(void) xen_domain_type = XEN_HVM_DOMAIN; } -static int xen_hvm_cpu_notify(struct notifier_block *self, unsigned long action, - void *hcpu) +static int xen_cpu_up_prepare(unsigned int cpu) { - int cpu = (long)hcpu; - switch (action) { - case CPU_UP_PREPARE: + int rc; + + if (xen_hvm_domain()) { + /* + * This can happen if CPU was offlined earlier and + * offlining timed out in common_cpu_die(). + */ + if (cpu_report_state(cpu) == CPU_DEAD_FROZEN) { + xen_smp_intr_free(cpu); + xen_uninit_lock_cpu(cpu); + } + if (cpu_acpi_id(cpu) != U32_MAX) per_cpu(xen_vcpu_id, cpu) = cpu_acpi_id(cpu); else per_cpu(xen_vcpu_id, cpu) = cpu; xen_vcpu_setup(cpu); - if (xen_have_vector_callback) { - if (xen_feature(XENFEAT_hvm_safe_pvclock)) - xen_setup_timer(cpu); - } - break; - default: - break; } - return NOTIFY_OK; + + if (xen_pv_domain() || xen_feature(XENFEAT_hvm_safe_pvclock)) + xen_setup_timer(cpu); + + rc = xen_smp_intr_init(cpu); + if (rc) { + WARN(1, "xen_smp_intr_init() for CPU %d failed: %d\n", + cpu, rc); + return rc; + } + return 0; } -static struct notifier_block xen_hvm_cpu_notifier = { - .notifier_call = xen_hvm_cpu_notify, -}; +static int xen_cpu_dead(unsigned int cpu) +{ + xen_smp_intr_free(cpu); + + if (xen_pv_domain() || xen_feature(XENFEAT_hvm_safe_pvclock)) + xen_teardown_timer(cpu); + + return 0; +} + +static int xen_cpu_up_online(unsigned int cpu) +{ + xen_init_lock_cpu(cpu); + return 0; +} #ifdef CONFIG_KEXEC_CORE static void xen_hvm_shutdown(void) @@ -1871,10 +1913,10 @@ static void __init xen_hvm_guest_init(void) xen_panic_handler_init(); - if (xen_feature(XENFEAT_hvm_callback_vector)) - xen_have_vector_callback = 1; + BUG_ON(!xen_feature(XENFEAT_hvm_callback_vector)); + xen_hvm_smp_init(); - register_cpu_notifier(&xen_hvm_cpu_notifier); + WARN_ON(xen_cpuhp_setup()); xen_unplug_emulated_devices(); x86_init.irqs.intr_init = xen_init_IRQ; xen_hvm_init_time_ops(); @@ -1910,7 +1952,7 @@ bool xen_hvm_need_lapic(void) return false; if (!xen_hvm_domain()) return false; - if (xen_feature(XENFEAT_hvm_pirqs) && xen_have_vector_callback) + if (xen_feature(XENFEAT_hvm_pirqs)) return false; return true; } diff --git a/arch/x86/xen/grant-table.c b/arch/x86/xen/grant-table.c index de4144c24f1c..809b6c812654 100644 --- a/arch/x86/xen/grant-table.c +++ b/arch/x86/xen/grant-table.c @@ -89,7 +89,7 @@ void arch_gnttab_unmap(void *shared, unsigned long nr_gframes) static int arch_gnttab_valloc(struct gnttab_vm_area *area, unsigned nr_frames) { - area->ptes = kmalloc(sizeof(pte_t *) * nr_frames, GFP_KERNEL); + area->ptes = kmalloc_array(nr_frames, sizeof(*area->ptes), GFP_KERNEL); if (area->ptes == NULL) return -ENOMEM; diff --git a/arch/x86/xen/platform-pci-unplug.c b/arch/x86/xen/platform-pci-unplug.c index d37a0c7f82cb..90d1b83cf35f 100644 --- a/arch/x86/xen/platform-pci-unplug.c +++ b/arch/x86/xen/platform-pci-unplug.c @@ -61,7 +61,7 @@ static int check_platform_magic(void) } break; default: - printk(KERN_WARNING "Xen Platform PCI: unknown I/O protocol version"); + printk(KERN_WARNING "Xen Platform PCI: unknown I/O protocol version\n"); return XEN_PLATFORM_ERR_PROTOCOL; } diff --git a/arch/x86/xen/pmu.c b/arch/x86/xen/pmu.c index 32bdc2c90297..b9fc52556bcc 100644 --- a/arch/x86/xen/pmu.c +++ b/arch/x86/xen/pmu.c @@ -547,8 +547,11 @@ void xen_pmu_init(int cpu) return; fail: - pr_info_once("Could not initialize VPMU for cpu %d, error %d\n", - cpu, err); + if (err == -EOPNOTSUPP || err == -ENOSYS) + pr_info_once("VPMU disabled by hypervisor.\n"); + else + pr_info_once("Could not initialize VPMU for cpu %d, error %d\n", + cpu, err); free_pages((unsigned long)xenpmu_data, 0); } diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index 0b4d04c8ab4d..9fa27ceeecfd 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -87,6 +87,12 @@ static void cpu_bringup(void) cpu_data(cpu).x86_max_cores = 1; set_cpu_sibling_map(cpu); + /* + * identify_cpu() may have set logical_pkg_id to -1 due + * to incorrect phys_proc_id. Let's re-comupte it. + */ + topology_update_package_map(apic->cpu_present_to_apicid(cpu), cpu); + xen_setup_cpu_clockevents(); notify_cpu_starting(cpu); @@ -115,7 +121,7 @@ asmlinkage __visible void cpu_bringup_and_idle(int cpu) cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); } -static void xen_smp_intr_free(unsigned int cpu) +void xen_smp_intr_free(unsigned int cpu) { if (per_cpu(xen_resched_irq, cpu).irq >= 0) { unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu).irq, NULL); @@ -159,7 +165,7 @@ static void xen_smp_intr_free(unsigned int cpu) per_cpu(xen_pmu_irq, cpu).name = NULL; } }; -static int xen_smp_intr_init(unsigned int cpu) +int xen_smp_intr_init(unsigned int cpu) { int rc; char *resched_name, *callfunc_name, *debug_name, *pmu_name; @@ -475,8 +481,6 @@ static int xen_cpu_up(unsigned int cpu, struct task_struct *idle) common_cpu_up(cpu, idle); xen_setup_runstate_info(cpu); - xen_setup_timer(cpu); - xen_init_lock_cpu(cpu); /* * PV VCPUs are always successfully taken down (see 'while' loop @@ -495,10 +499,6 @@ static int xen_cpu_up(unsigned int cpu, struct task_struct *idle) xen_pmu_init(cpu); - rc = xen_smp_intr_init(cpu); - if (rc) - return rc; - rc = HYPERVISOR_vcpu_op(VCPUOP_up, xen_vcpu_nr(cpu), NULL); BUG_ON(rc); @@ -769,47 +769,10 @@ static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus) xen_init_lock_cpu(0); } -static int xen_hvm_cpu_up(unsigned int cpu, struct task_struct *tidle) -{ - int rc; - - /* - * This can happen if CPU was offlined earlier and - * offlining timed out in common_cpu_die(). - */ - if (cpu_report_state(cpu) == CPU_DEAD_FROZEN) { - xen_smp_intr_free(cpu); - xen_uninit_lock_cpu(cpu); - } - - /* - * xen_smp_intr_init() needs to run before native_cpu_up() - * so that IPI vectors are set up on the booting CPU before - * it is marked online in native_cpu_up(). - */ - rc = xen_smp_intr_init(cpu); - WARN_ON(rc); - if (!rc) - rc = native_cpu_up(cpu, tidle); - - /* - * We must initialize the slowpath CPU kicker _after_ the native - * path has executed. If we initialized it before none of the - * unlocker IPI kicks would reach the booting CPU as the booting - * CPU had not set itself 'online' in cpu_online_mask. That mask - * is checked when IPIs are sent (on HVM at least). - */ - xen_init_lock_cpu(cpu); - return rc; -} - void __init xen_hvm_smp_init(void) { - if (!xen_have_vector_callback) - return; smp_ops.smp_prepare_cpus = xen_hvm_smp_prepare_cpus; smp_ops.smp_send_reschedule = xen_smp_send_reschedule; - smp_ops.cpu_up = xen_hvm_cpu_up; smp_ops.cpu_die = xen_cpu_die; smp_ops.send_call_func_ipi = xen_smp_send_call_function_ipi; smp_ops.send_call_func_single_ipi = xen_smp_send_call_function_single_ipi; diff --git a/arch/x86/xen/smp.h b/arch/x86/xen/smp.h index 963d62a35c82..c5c16dc4f694 100644 --- a/arch/x86/xen/smp.h +++ b/arch/x86/xen/smp.h @@ -1,5 +1,6 @@ #ifndef _XEN_SMP_H +#ifdef CONFIG_SMP extern void xen_send_IPI_mask(const struct cpumask *mask, int vector); extern void xen_send_IPI_mask_allbutself(const struct cpumask *mask, @@ -8,6 +9,18 @@ extern void xen_send_IPI_allbutself(int vector); extern void xen_send_IPI_all(int vector); extern void xen_send_IPI_self(int vector); +extern int xen_smp_intr_init(unsigned int cpu); +extern void xen_smp_intr_free(unsigned int cpu); + +#else /* CONFIG_SMP */ + +static inline int xen_smp_intr_init(unsigned int cpu) +{ + return 0; +} +static inline void xen_smp_intr_free(unsigned int cpu) {} +#endif /* CONFIG_SMP */ + #ifdef CONFIG_XEN_PVH extern void xen_pvh_early_cpu_init(int cpu, bool entry); #else diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 67356d29d74d..33d8f6a7829d 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -432,11 +432,6 @@ static void xen_hvm_setup_cpu_clockevents(void) void __init xen_hvm_init_time_ops(void) { - /* vector callback is needed otherwise we cannot receive interrupts - * on cpu > 0 and at this point we don't know how many cpus are - * available */ - if (!xen_have_vector_callback) - return; if (!xen_feature(XENFEAT_hvm_safe_pvclock)) { printk(KERN_INFO "Xen doesn't support pvclock on HVM," "disable pv timer\n"); diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index d5dbdb9d24d8..9ecfcdcdd6d6 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -1314,9 +1314,6 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu) if (!VALID_EVTCHN(evtchn)) return -1; - if (!xen_support_evtchn_rebind()) - return -1; - /* Send future instances of this interrupt to other vcpu. */ bind_vcpu.port = evtchn; bind_vcpu.vcpu = xen_vcpu_nr(tcpu); @@ -1650,20 +1647,15 @@ void xen_callback_vector(void) { int rc; uint64_t callback_via; - if (xen_have_vector_callback) { - callback_via = HVM_CALLBACK_VECTOR(HYPERVISOR_CALLBACK_VECTOR); - rc = xen_set_callback_via(callback_via); - if (rc) { - pr_err("Request for Xen HVM callback vector failed\n"); - xen_have_vector_callback = 0; - return; - } - pr_info("Xen HVM callback vector for event delivery is enabled\n"); - /* in the restore case the vector has already been allocated */ - if (!test_bit(HYPERVISOR_CALLBACK_VECTOR, used_vectors)) - alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, - xen_hvm_callback_vector); - } + + callback_via = HVM_CALLBACK_VECTOR(HYPERVISOR_CALLBACK_VECTOR); + rc = xen_set_callback_via(callback_via); + BUG_ON(rc); + pr_info("Xen HVM callback vector for event delivery is enabled\n"); + /* in the restore case the vector has already been allocated */ + if (!test_bit(HYPERVISOR_CALLBACK_VECTOR, used_vectors)) + alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, + xen_hvm_callback_vector); } #else void xen_callback_vector(void) {} diff --git a/drivers/xen/events/events_fifo.c b/drivers/xen/events/events_fifo.c index 266c2c733039..7ef27c6ed72f 100644 --- a/drivers/xen/events/events_fifo.c +++ b/drivers/xen/events/events_fifo.c @@ -418,30 +418,18 @@ static int evtchn_fifo_alloc_control_block(unsigned cpu) return ret; } -static int evtchn_fifo_cpu_notification(struct notifier_block *self, - unsigned long action, - void *hcpu) +static int xen_evtchn_cpu_prepare(unsigned int cpu) { - int cpu = (long)hcpu; - int ret = 0; - - switch (action) { - case CPU_UP_PREPARE: - if (!per_cpu(cpu_control_block, cpu)) - ret = evtchn_fifo_alloc_control_block(cpu); - break; - case CPU_DEAD: - __evtchn_fifo_handle_events(cpu, true); - break; - default: - break; - } - return ret < 0 ? NOTIFY_BAD : NOTIFY_OK; + if (!per_cpu(cpu_control_block, cpu)) + return evtchn_fifo_alloc_control_block(cpu); + return 0; } -static struct notifier_block evtchn_fifo_cpu_notifier = { - .notifier_call = evtchn_fifo_cpu_notification, -}; +static int xen_evtchn_cpu_dead(unsigned int cpu) +{ + __evtchn_fifo_handle_events(cpu, true); + return 0; +} int __init xen_evtchn_fifo_init(void) { @@ -456,7 +444,9 @@ int __init xen_evtchn_fifo_init(void) evtchn_ops = &evtchn_ops_fifo; - register_cpu_notifier(&evtchn_fifo_cpu_notifier); + cpuhp_setup_state_nocalls(CPUHP_XEN_EVTCHN_PREPARE, + "CPUHP_XEN_EVTCHN_PREPARE", + xen_evtchn_cpu_prepare, xen_evtchn_cpu_dead); out: put_cpu(); return ret; diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c index cf9666680c8c..b59c9455aae1 100644 --- a/drivers/xen/platform-pci.c +++ b/drivers/xen/platform-pci.c @@ -42,7 +42,6 @@ static unsigned long platform_mmio; static unsigned long platform_mmio_alloc; static unsigned long platform_mmiolen; -static uint64_t callback_via; static unsigned long alloc_xen_mmio(unsigned long len) { @@ -55,51 +54,6 @@ static unsigned long alloc_xen_mmio(unsigned long len) return addr; } -static uint64_t get_callback_via(struct pci_dev *pdev) -{ - u8 pin; - int irq; - - irq = pdev->irq; - if (irq < 16) - return irq; /* ISA IRQ */ - - pin = pdev->pin; - - /* We don't know the GSI. Specify the PCI INTx line instead. */ - return ((uint64_t)0x01 << 56) | /* PCI INTx identifier */ - ((uint64_t)pci_domain_nr(pdev->bus) << 32) | - ((uint64_t)pdev->bus->number << 16) | - ((uint64_t)(pdev->devfn & 0xff) << 8) | - ((uint64_t)(pin - 1) & 3); -} - -static irqreturn_t do_hvm_evtchn_intr(int irq, void *dev_id) -{ - xen_hvm_evtchn_do_upcall(); - return IRQ_HANDLED; -} - -static int xen_allocate_irq(struct pci_dev *pdev) -{ - return request_irq(pdev->irq, do_hvm_evtchn_intr, - IRQF_NOBALANCING | IRQF_TRIGGER_RISING, - "xen-platform-pci", pdev); -} - -static int platform_pci_resume(struct pci_dev *pdev) -{ - int err; - if (xen_have_vector_callback) - return 0; - err = xen_set_callback_via(callback_via); - if (err) { - dev_err(&pdev->dev, "platform_pci_resume failure!\n"); - return err; - } - return 0; -} - static int platform_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -138,21 +92,6 @@ static int platform_pci_probe(struct pci_dev *pdev, platform_mmio = mmio_addr; platform_mmiolen = mmio_len; - if (!xen_have_vector_callback) { - ret = xen_allocate_irq(pdev); - if (ret) { - dev_warn(&pdev->dev, "request_irq failed err=%d\n", ret); - goto out; - } - callback_via = get_callback_via(pdev); - ret = xen_set_callback_via(callback_via); - if (ret) { - dev_warn(&pdev->dev, "Unable to set the evtchn callback " - "err=%d\n", ret); - goto out; - } - } - max_nr_gframes = gnttab_max_grant_frames(); grant_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes); ret = gnttab_setup_auto_xlat_frames(grant_frames); @@ -184,9 +123,6 @@ static struct pci_driver platform_driver = { .name = DRV_NAME, .probe = platform_pci_probe, .id_table = platform_pci_tbl, -#ifdef CONFIG_PM - .resume_early = platform_pci_resume, -#endif }; static int __init platform_pci_init(void) diff --git a/drivers/xen/sys-hypervisor.c b/drivers/xen/sys-hypervisor.c index 6881b3ceb675..84106f9c456c 100644 --- a/drivers/xen/sys-hypervisor.c +++ b/drivers/xen/sys-hypervisor.c @@ -215,7 +215,7 @@ static const struct attribute_group xen_compilation_group = { .attrs = xen_compile_attrs, }; -static int __init xen_compilation_init(void) +static int __init xen_sysfs_compilation_init(void) { return sysfs_create_group(hypervisor_kobj, &xen_compilation_group); } @@ -341,7 +341,7 @@ static const struct attribute_group xen_properties_group = { .attrs = xen_properties_attrs, }; -static int __init xen_properties_init(void) +static int __init xen_sysfs_properties_init(void) { return sysfs_create_group(hypervisor_kobj, &xen_properties_group); } @@ -455,7 +455,7 @@ static const struct attribute_group xen_pmu_group = { .attrs = xen_pmu_attrs, }; -static int __init xen_pmu_init(void) +static int __init xen_sysfs_pmu_init(void) { return sysfs_create_group(hypervisor_kobj, &xen_pmu_group); } @@ -474,18 +474,18 @@ static int __init hyper_sysfs_init(void) ret = xen_sysfs_version_init(); if (ret) goto version_out; - ret = xen_compilation_init(); + ret = xen_sysfs_compilation_init(); if (ret) goto comp_out; ret = xen_sysfs_uuid_init(); if (ret) goto uuid_out; - ret = xen_properties_init(); + ret = xen_sysfs_properties_init(); if (ret) goto prop_out; #ifdef CONFIG_XEN_HAVE_VPMU if (xen_initial_domain()) { - ret = xen_pmu_init(); + ret = xen_sysfs_pmu_init(); if (ret) { sysfs_remove_group(hypervisor_kobj, &xen_properties_group); diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c index 258b7c325649..6331a95691a4 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c @@ -25,6 +25,8 @@ #include "conf_space.h" #include "conf_space_quirks.h" +#define PCISTUB_DRIVER_NAME "pciback" + static char *pci_devs_to_hide; wait_queue_head_t xen_pcibk_aer_wait_queue; /*Add sem for sync AER handling and xen_pcibk remove/reconfigue ops, @@ -149,13 +151,10 @@ static inline void pcistub_device_put(struct pcistub_device *psdev) kref_put(&psdev->kref, pcistub_device_release); } -static struct pcistub_device *pcistub_device_find(int domain, int bus, - int slot, int func) +static struct pcistub_device *pcistub_device_find_locked(int domain, int bus, + int slot, int func) { - struct pcistub_device *psdev = NULL; - unsigned long flags; - - spin_lock_irqsave(&pcistub_devices_lock, flags); + struct pcistub_device *psdev; list_for_each_entry(psdev, &pcistub_devices, dev_list) { if (psdev->dev != NULL @@ -163,15 +162,25 @@ static struct pcistub_device *pcistub_device_find(int domain, int bus, && bus == psdev->dev->bus->number && slot == PCI_SLOT(psdev->dev->devfn) && func == PCI_FUNC(psdev->dev->devfn)) { - pcistub_device_get(psdev); - goto out; + return psdev; } } - /* didn't find it */ - psdev = NULL; + return NULL; +} + +static struct pcistub_device *pcistub_device_find(int domain, int bus, + int slot, int func) +{ + struct pcistub_device *psdev; + unsigned long flags; + + spin_lock_irqsave(&pcistub_devices_lock, flags); + + psdev = pcistub_device_find_locked(domain, bus, slot, func); + if (psdev) + pcistub_device_get(psdev); -out: spin_unlock_irqrestore(&pcistub_devices_lock, flags); return psdev; } @@ -207,16 +216,9 @@ struct pci_dev *pcistub_get_pci_dev_by_slot(struct xen_pcibk_device *pdev, spin_lock_irqsave(&pcistub_devices_lock, flags); - list_for_each_entry(psdev, &pcistub_devices, dev_list) { - if (psdev->dev != NULL - && domain == pci_domain_nr(psdev->dev->bus) - && bus == psdev->dev->bus->number - && slot == PCI_SLOT(psdev->dev->devfn) - && func == PCI_FUNC(psdev->dev->devfn)) { - found_dev = pcistub_device_get_pci_dev(pdev, psdev); - break; - } - } + psdev = pcistub_device_find_locked(domain, bus, slot, func); + if (psdev) + found_dev = pcistub_device_get_pci_dev(pdev, psdev); spin_unlock_irqrestore(&pcistub_devices_lock, flags); return found_dev; @@ -478,15 +480,48 @@ static int __init pcistub_init_devices_late(void) return 0; } -static int pcistub_seize(struct pci_dev *dev) +static void pcistub_device_id_add_list(struct pcistub_device_id *new, + int domain, int bus, unsigned int devfn) +{ + struct pcistub_device_id *pci_dev_id; + unsigned long flags; + int found = 0; + + spin_lock_irqsave(&device_ids_lock, flags); + + list_for_each_entry(pci_dev_id, &pcistub_device_ids, slot_list) { + if (pci_dev_id->domain == domain && pci_dev_id->bus == bus && + pci_dev_id->devfn == devfn) { + found = 1; + break; + } + } + + if (!found) { + new->domain = domain; + new->bus = bus; + new->devfn = devfn; + list_add_tail(&new->slot_list, &pcistub_device_ids); + } + + spin_unlock_irqrestore(&device_ids_lock, flags); + + if (found) + kfree(new); +} + +static int pcistub_seize(struct pci_dev *dev, + struct pcistub_device_id *pci_dev_id) { struct pcistub_device *psdev; unsigned long flags; int err = 0; psdev = pcistub_device_alloc(dev); - if (!psdev) + if (!psdev) { + kfree(pci_dev_id); return -ENOMEM; + } spin_lock_irqsave(&pcistub_devices_lock, flags); @@ -507,8 +542,12 @@ static int pcistub_seize(struct pci_dev *dev) spin_unlock_irqrestore(&pcistub_devices_lock, flags); - if (err) + if (err) { + kfree(pci_dev_id); pcistub_device_put(psdev); + } else if (pci_dev_id) + pcistub_device_id_add_list(pci_dev_id, pci_domain_nr(dev->bus), + dev->bus->number, dev->devfn); return err; } @@ -517,11 +556,16 @@ static int pcistub_seize(struct pci_dev *dev) * other functions that take the sysfs lock. */ static int pcistub_probe(struct pci_dev *dev, const struct pci_device_id *id) { - int err = 0; + int err = 0, match; + struct pcistub_device_id *pci_dev_id = NULL; dev_dbg(&dev->dev, "probing...\n"); - if (pcistub_match(dev)) { + match = pcistub_match(dev); + + if ((dev->driver_override && + !strcmp(dev->driver_override, PCISTUB_DRIVER_NAME)) || + match) { if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { @@ -532,8 +576,16 @@ static int pcistub_probe(struct pci_dev *dev, const struct pci_device_id *id) goto out; } + if (!match) { + pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_ATOMIC); + if (!pci_dev_id) { + err = -ENOMEM; + goto out; + } + } + dev_info(&dev->dev, "seizing device\n"); - err = pcistub_seize(dev); + err = pcistub_seize(dev, pci_dev_id); } else /* Didn't find the device */ err = -ENODEV; @@ -945,7 +997,7 @@ static const struct pci_error_handlers xen_pcibk_error_handler = { static struct pci_driver xen_pcibk_pci_driver = { /* The name should be xen_pciback, but until the tools are updated * we will keep it as pciback. */ - .name = "pciback", + .name = PCISTUB_DRIVER_NAME, .id_table = pcistub_ids, .probe = pcistub_probe, .remove = pcistub_remove, @@ -1012,7 +1064,6 @@ static inline int str_to_quirk(const char *buf, int *domain, int *bus, int static int pcistub_device_id_add(int domain, int bus, int slot, int func) { struct pcistub_device_id *pci_dev_id; - unsigned long flags; int rc = 0, devfn = PCI_DEVFN(slot, func); if (slot < 0) { @@ -1042,16 +1093,10 @@ static int pcistub_device_id_add(int domain, int bus, int slot, int func) if (!pci_dev_id) return -ENOMEM; - pci_dev_id->domain = domain; - pci_dev_id->bus = bus; - pci_dev_id->devfn = devfn; - pr_debug("wants to seize %04x:%02x:%02x.%d\n", domain, bus, slot, func); - spin_lock_irqsave(&device_ids_lock, flags); - list_add_tail(&pci_dev_id->slot_list, &pcistub_device_ids); - spin_unlock_irqrestore(&device_ids_lock, flags); + pcistub_device_id_add_list(pci_dev_id, domain, bus, devfn); return 0; } diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index a8ffc405f915..9b207a8c5af3 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -43,6 +43,8 @@ enum cpuhp_state { CPUHP_CPUIDLE_COUPLED_PREPARE, CPUHP_POWERPC_PMAC_PREPARE, CPUHP_POWERPC_MMU_CTX_PREPARE, + CPUHP_XEN_PREPARE, + CPUHP_XEN_EVTCHN_PREPARE, CPUHP_NOTIFY_PREPARE, CPUHP_ARM_SHMOBILE_SCU_PREPARE, CPUHP_SH_SH3X_PREPARE, diff --git a/include/xen/xen.h b/include/xen/xen.h index 0c0e3ef4c45d..f0f0252cff9a 100644 --- a/include/xen/xen.h +++ b/include/xen/xen.h @@ -38,8 +38,7 @@ extern enum xen_domain_type xen_domain_type; */ #include #define xen_pvh_domain() (xen_pv_domain() && \ - xen_feature(XENFEAT_auto_translated_physmap) && \ - xen_have_vector_callback) + xen_feature(XENFEAT_auto_translated_physmap)) #else #define xen_pvh_domain() (0) #endif