Commit 6383cb42 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus-6.6-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip

Pull xen updates from Juergen Gross:

 - a bunch of minor cleanups

 - a patch adding irqfd support for virtio backends running as user
   daemon supporting Xen guests

* tag 'for-linus-6.6-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
  xen: privcmd: Add support for irqfd
  xen/xenbus: Avoid a lockdep warning when adding a watch
  xen: Fix one kernel-doc comment
  xen: xenbus: Use helper function IS_ERR_OR_NULL()
  xen: Switch to use kmemdup() helper
  xen-pciback: Remove unused function declarations
  x86/xen: Make virt_to_pfn() a static inline
  xen: remove a confusing comment on auto-translated guest I/O
  xen/evtchn: Remove unused function declaration xen_set_affinity_evtchn()
parents 54203417 f8941e6c
......@@ -295,7 +295,10 @@ static inline unsigned long bfn_to_local_pfn(unsigned long mfn)
/* VIRT <-> MACHINE conversion */
#define virt_to_machine(v) (phys_to_machine(XPADDR(__pa(v))))
#define virt_to_pfn(v) (PFN_DOWN(__pa(v)))
static inline unsigned long virt_to_pfn(const void *v)
{
return PFN_DOWN(__pa(v));
}
#define virt_to_mfn(v) (pfn_to_mfn(virt_to_pfn(v)))
#define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT))
......
......@@ -523,7 +523,7 @@ static void __init xen_load_gdt_boot(const struct desc_ptr *dtr)
BUG_ON(size > PAGE_SIZE);
BUG_ON(va & ~PAGE_MASK);
pfn = virt_to_pfn(va);
pfn = virt_to_pfn((void *)va);
mfn = pfn_to_mfn(pfn);
pte = pfn_pte(pfn, PAGE_KERNEL_RO);
......
......@@ -2202,13 +2202,13 @@ static void xen_zap_pfn_range(unsigned long vaddr, unsigned int order,
mcs = __xen_mc_entry(0);
if (in_frames)
in_frames[i] = virt_to_mfn(vaddr);
in_frames[i] = virt_to_mfn((void *)vaddr);
MULTI_update_va_mapping(mcs.mc, vaddr, VOID_PTE, 0);
__set_phys_to_machine(virt_to_pfn(vaddr), INVALID_P2M_ENTRY);
__set_phys_to_machine(virt_to_pfn((void *)vaddr), INVALID_P2M_ENTRY);
if (out_frames)
out_frames[i] = virt_to_pfn(vaddr);
out_frames[i] = virt_to_pfn((void *)vaddr);
}
xen_mc_issue(0);
}
......@@ -2250,7 +2250,7 @@ static void xen_remap_exchanged_ptes(unsigned long vaddr, int order,
MULTI_update_va_mapping(mcs.mc, vaddr,
mfn_pte(mfn, PAGE_KERNEL), flags);
set_phys_to_machine(virt_to_pfn(vaddr), mfn);
set_phys_to_machine(virt_to_pfn((void *)vaddr), mfn);
}
xen_mc_issue(0);
......@@ -2310,12 +2310,6 @@ int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order,
int success;
unsigned long vstart = (unsigned long)phys_to_virt(pstart);
/*
* Currently an auto-translated guest will not perform I/O, nor will
* it require PAE page directories below 4GB. Therefore any calls to
* this function are redundant and can be ignored.
*/
if (unlikely(order > MAX_CONTIG_ORDER))
return -ENOMEM;
......@@ -2327,7 +2321,7 @@ int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order,
xen_zap_pfn_range(vstart, order, in_frames, NULL);
/* 2. Get a new contiguous memory extent. */
out_frame = virt_to_pfn(vstart);
out_frame = virt_to_pfn((void *)vstart);
success = xen_exchange_memory(1UL << order, 0, in_frames,
1, order, &out_frame,
address_bits);
......@@ -2360,7 +2354,7 @@ void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order)
spin_lock_irqsave(&xen_reservation_lock, flags);
/* 1. Find start MFN of contiguous extent. */
in_frame = virt_to_mfn(vstart);
in_frame = virt_to_mfn((void *)vstart);
/* 2. Zap current PTEs. */
xen_zap_pfn_range(vstart, order, NULL, out_frames);
......
......@@ -340,7 +340,7 @@ static void __init xen_do_set_identity_and_remap_chunk(
WARN_ON(size == 0);
mfn_save = virt_to_mfn(buf);
mfn_save = virt_to_mfn((void *)buf);
for (ident_pfn_iter = start_pfn, remap_pfn_iter = remap_pfn;
ident_pfn_iter < ident_end_pfn;
......@@ -503,7 +503,7 @@ void __init xen_remap_memory(void)
unsigned long pfn_s = ~0UL;
unsigned long len = 0;
mfn_save = virt_to_mfn(buf);
mfn_save = virt_to_mfn((void *)buf);
while (xen_remap_mfn != INVALID_P2M_ENTRY) {
/* Map the remap information */
......
......@@ -269,6 +269,13 @@ config XEN_PRIVCMD
disaggregated Xen setups this driver might be needed for other
domains, too.
config XEN_PRIVCMD_IRQFD
bool "Xen irqfd support"
depends on XEN_PRIVCMD && XEN_VIRTIO && EVENTFD
help
Using the irqfd mechanism a virtio backend running in a daemon can
speed up interrupt injection into a guest.
config XEN_ACPI_PROCESSOR
tristate "Xen ACPI processor"
depends on XEN && XEN_PV_DOM0 && X86 && ACPI_PROCESSOR && CPU_FREQ
......
......@@ -1044,7 +1044,7 @@ EXPORT_SYMBOL_GPL(gnttab_pages_clear_private);
/**
* gnttab_free_pages - free pages allocated by gnttab_alloc_pages()
* @nr_pages; number of pages to free
* @nr_pages: number of pages to free
* @pages: the pages
*/
void gnttab_free_pages(int nr_pages, struct page **pages)
......
......@@ -9,11 +9,16 @@
#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
#include <linux/eventfd.h>
#include <linux/file.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/workqueue.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/mman.h>
......@@ -833,6 +838,263 @@ static long privcmd_ioctl_mmap_resource(struct file *file,
return rc;
}
#ifdef CONFIG_XEN_PRIVCMD_IRQFD
/* Irqfd support */
static struct workqueue_struct *irqfd_cleanup_wq;
static DEFINE_MUTEX(irqfds_lock);
static LIST_HEAD(irqfds_list);
struct privcmd_kernel_irqfd {
struct xen_dm_op_buf xbufs;
domid_t dom;
bool error;
struct eventfd_ctx *eventfd;
struct work_struct shutdown;
wait_queue_entry_t wait;
struct list_head list;
poll_table pt;
};
static void irqfd_deactivate(struct privcmd_kernel_irqfd *kirqfd)
{
lockdep_assert_held(&irqfds_lock);
list_del_init(&kirqfd->list);
queue_work(irqfd_cleanup_wq, &kirqfd->shutdown);
}
static void irqfd_shutdown(struct work_struct *work)
{
struct privcmd_kernel_irqfd *kirqfd =
container_of(work, struct privcmd_kernel_irqfd, shutdown);
u64 cnt;
eventfd_ctx_remove_wait_queue(kirqfd->eventfd, &kirqfd->wait, &cnt);
eventfd_ctx_put(kirqfd->eventfd);
kfree(kirqfd);
}
static void irqfd_inject(struct privcmd_kernel_irqfd *kirqfd)
{
u64 cnt;
long rc;
eventfd_ctx_do_read(kirqfd->eventfd, &cnt);
xen_preemptible_hcall_begin();
rc = HYPERVISOR_dm_op(kirqfd->dom, 1, &kirqfd->xbufs);
xen_preemptible_hcall_end();
/* Don't repeat the error message for consecutive failures */
if (rc && !kirqfd->error) {
pr_err("Failed to configure irq for guest domain: %d\n",
kirqfd->dom);
}
kirqfd->error = rc;
}
static int
irqfd_wakeup(wait_queue_entry_t *wait, unsigned int mode, int sync, void *key)
{
struct privcmd_kernel_irqfd *kirqfd =
container_of(wait, struct privcmd_kernel_irqfd, wait);
__poll_t flags = key_to_poll(key);
if (flags & EPOLLIN)
irqfd_inject(kirqfd);
if (flags & EPOLLHUP) {
mutex_lock(&irqfds_lock);
irqfd_deactivate(kirqfd);
mutex_unlock(&irqfds_lock);
}
return 0;
}
static void
irqfd_poll_func(struct file *file, wait_queue_head_t *wqh, poll_table *pt)
{
struct privcmd_kernel_irqfd *kirqfd =
container_of(pt, struct privcmd_kernel_irqfd, pt);
add_wait_queue_priority(wqh, &kirqfd->wait);
}
static int privcmd_irqfd_assign(struct privcmd_irqfd *irqfd)
{
struct privcmd_kernel_irqfd *kirqfd, *tmp;
__poll_t events;
struct fd f;
void *dm_op;
int ret;
kirqfd = kzalloc(sizeof(*kirqfd) + irqfd->size, GFP_KERNEL);
if (!kirqfd)
return -ENOMEM;
dm_op = kirqfd + 1;
if (copy_from_user(dm_op, irqfd->dm_op, irqfd->size)) {
ret = -EFAULT;
goto error_kfree;
}
kirqfd->xbufs.size = irqfd->size;
set_xen_guest_handle(kirqfd->xbufs.h, dm_op);
kirqfd->dom = irqfd->dom;
INIT_WORK(&kirqfd->shutdown, irqfd_shutdown);
f = fdget(irqfd->fd);
if (!f.file) {
ret = -EBADF;
goto error_kfree;
}
kirqfd->eventfd = eventfd_ctx_fileget(f.file);
if (IS_ERR(kirqfd->eventfd)) {
ret = PTR_ERR(kirqfd->eventfd);
goto error_fd_put;
}
/*
* Install our own custom wake-up handling so we are notified via a
* callback whenever someone signals the underlying eventfd.
*/
init_waitqueue_func_entry(&kirqfd->wait, irqfd_wakeup);
init_poll_funcptr(&kirqfd->pt, irqfd_poll_func);
mutex_lock(&irqfds_lock);
list_for_each_entry(tmp, &irqfds_list, list) {
if (kirqfd->eventfd == tmp->eventfd) {
ret = -EBUSY;
mutex_unlock(&irqfds_lock);
goto error_eventfd;
}
}
list_add_tail(&kirqfd->list, &irqfds_list);
mutex_unlock(&irqfds_lock);
/*
* Check if there was an event already pending on the eventfd before we
* registered, and trigger it as if we didn't miss it.
*/
events = vfs_poll(f.file, &kirqfd->pt);
if (events & EPOLLIN)
irqfd_inject(kirqfd);
/*
* Do not drop the file until the kirqfd is fully initialized, otherwise
* we might race against the EPOLLHUP.
*/
fdput(f);
return 0;
error_eventfd:
eventfd_ctx_put(kirqfd->eventfd);
error_fd_put:
fdput(f);
error_kfree:
kfree(kirqfd);
return ret;
}
static int privcmd_irqfd_deassign(struct privcmd_irqfd *irqfd)
{
struct privcmd_kernel_irqfd *kirqfd;
struct eventfd_ctx *eventfd;
eventfd = eventfd_ctx_fdget(irqfd->fd);
if (IS_ERR(eventfd))
return PTR_ERR(eventfd);
mutex_lock(&irqfds_lock);
list_for_each_entry(kirqfd, &irqfds_list, list) {
if (kirqfd->eventfd == eventfd) {
irqfd_deactivate(kirqfd);
break;
}
}
mutex_unlock(&irqfds_lock);
eventfd_ctx_put(eventfd);
/*
* Block until we know all outstanding shutdown jobs have completed so
* that we guarantee there will not be any more interrupts once this
* deassign function returns.
*/
flush_workqueue(irqfd_cleanup_wq);
return 0;
}
static long privcmd_ioctl_irqfd(struct file *file, void __user *udata)
{
struct privcmd_data *data = file->private_data;
struct privcmd_irqfd irqfd;
if (copy_from_user(&irqfd, udata, sizeof(irqfd)))
return -EFAULT;
/* No other flags should be set */
if (irqfd.flags & ~PRIVCMD_IRQFD_FLAG_DEASSIGN)
return -EINVAL;
/* If restriction is in place, check the domid matches */
if (data->domid != DOMID_INVALID && data->domid != irqfd.dom)
return -EPERM;
if (irqfd.flags & PRIVCMD_IRQFD_FLAG_DEASSIGN)
return privcmd_irqfd_deassign(&irqfd);
return privcmd_irqfd_assign(&irqfd);
}
static int privcmd_irqfd_init(void)
{
irqfd_cleanup_wq = alloc_workqueue("privcmd-irqfd-cleanup", 0, 0);
if (!irqfd_cleanup_wq)
return -ENOMEM;
return 0;
}
static void privcmd_irqfd_exit(void)
{
struct privcmd_kernel_irqfd *kirqfd, *tmp;
mutex_lock(&irqfds_lock);
list_for_each_entry_safe(kirqfd, tmp, &irqfds_list, list)
irqfd_deactivate(kirqfd);
mutex_unlock(&irqfds_lock);
destroy_workqueue(irqfd_cleanup_wq);
}
#else
static inline long privcmd_ioctl_irqfd(struct file *file, void __user *udata)
{
return -EOPNOTSUPP;
}
static inline int privcmd_irqfd_init(void)
{
return 0;
}
static inline void privcmd_irqfd_exit(void)
{
}
#endif /* CONFIG_XEN_PRIVCMD_IRQFD */
static long privcmd_ioctl(struct file *file,
unsigned int cmd, unsigned long data)
{
......@@ -868,6 +1130,10 @@ static long privcmd_ioctl(struct file *file,
ret = privcmd_ioctl_mmap_resource(file, udata);
break;
case IOCTL_PRIVCMD_IRQFD:
ret = privcmd_ioctl_irqfd(file, udata);
break;
default:
break;
}
......@@ -992,15 +1258,27 @@ static int __init privcmd_init(void)
err = misc_register(&xen_privcmdbuf_dev);
if (err != 0) {
pr_err("Could not register Xen hypercall-buf device\n");
misc_deregister(&privcmd_dev);
return err;
goto err_privcmdbuf;
}
err = privcmd_irqfd_init();
if (err != 0) {
pr_err("irqfd init failed\n");
goto err_irqfd;
}
return 0;
err_irqfd:
misc_deregister(&xen_privcmdbuf_dev);
err_privcmdbuf:
misc_deregister(&privcmd_dev);
return err;
}
static void __exit privcmd_exit(void)
{
privcmd_irqfd_exit();
misc_deregister(&privcmd_dev);
misc_deregister(&xen_privcmdbuf_dev);
}
......
......@@ -473,11 +473,8 @@ static int xen_upload_processor_pm_data(void)
if (!_pr)
continue;
if (!pr_backup) {
pr_backup = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
if (pr_backup)
memcpy(pr_backup, _pr, sizeof(struct acpi_processor));
}
if (!pr_backup)
pr_backup = kmemdup(_pr, sizeof(*_pr), GFP_KERNEL);
(void)upload_pm_data(_pr);
}
......
......@@ -21,8 +21,6 @@ struct xen_pcibk_config_quirk {
int xen_pcibk_config_quirks_add_field(struct pci_dev *dev, struct config_field
*field);
int xen_pcibk_config_quirks_remove_field(struct pci_dev *dev, int reg);
int xen_pcibk_config_quirks_init(struct pci_dev *dev);
void xen_pcibk_config_field_free(struct config_field *field);
......
......@@ -201,6 +201,3 @@ static inline void xen_pcibk_lateeoi(struct xen_pcibk_device *pdev,
int xen_pcibk_xenbus_register(void);
void xen_pcibk_xenbus_unregister(void);
#endif
/* Handles shared IRQs that can to device domain and control domain. */
void xen_pcibk_irq_handler(struct pci_dev *dev, int reset);
......@@ -429,7 +429,7 @@ static void xenbus_check_frontend(char *class, char *dev)
printk(KERN_DEBUG "XENBUS: frontend %s %s\n",
frontend, xenbus_strstate(fe_state));
backend = xenbus_read(XBT_NIL, frontend, "backend", NULL);
if (!backend || IS_ERR(backend))
if (IS_ERR_OR_NULL(backend))
goto out;
err = xenbus_scanf(XBT_NIL, backend, "state", "%i", &be_state);
if (err == 1)
......
......@@ -840,8 +840,8 @@ void xs_suspend(void)
{
xs_suspend_enter();
down_write(&xs_watch_rwsem);
mutex_lock(&xs_response_mutex);
down_write(&xs_watch_rwsem);
}
void xs_resume(void)
......@@ -866,8 +866,8 @@ void xs_resume(void)
void xs_suspend_cancel(void)
{
mutex_unlock(&xs_response_mutex);
up_write(&xs_watch_rwsem);
mutex_unlock(&xs_response_mutex);
xs_suspend_exit();
}
......
......@@ -98,6 +98,18 @@ struct privcmd_mmap_resource {
__u64 addr;
};
/* For privcmd_irqfd::flags */
#define PRIVCMD_IRQFD_FLAG_DEASSIGN (1 << 0)
struct privcmd_irqfd {
void __user *dm_op;
__u32 size; /* Size of structure pointed by dm_op */
__u32 fd;
__u32 flags;
domid_t dom;
__u8 pad[2];
};
/*
* @cmd: IOCTL_PRIVCMD_HYPERCALL
* @arg: &privcmd_hypercall_t
......@@ -125,5 +137,7 @@ struct privcmd_mmap_resource {
_IOC(_IOC_NONE, 'P', 6, sizeof(domid_t))
#define IOCTL_PRIVCMD_MMAP_RESOURCE \
_IOC(_IOC_NONE, 'P', 7, sizeof(struct privcmd_mmap_resource))
#define IOCTL_PRIVCMD_IRQFD \
_IOC(_IOC_NONE, 'P', 8, sizeof(struct privcmd_irqfd))
#endif /* __LINUX_PUBLIC_PRIVCMD_H__ */
......@@ -75,7 +75,6 @@ void evtchn_put(evtchn_port_t evtchn);
void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector);
void rebind_evtchn_irq(evtchn_port_t evtchn, int irq);
int xen_set_affinity_evtchn(struct irq_desc *desc, unsigned int tcpu);
static inline void notify_remote_via_evtchn(evtchn_port_t port)
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment