// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB /* * Copyright (c) 2005 Mellanox Technologies. All rights reserved. * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All rights reserved. * Copyright 2019 Marvell. All rights reserved. */ #include <linux/xarray.h> #include "uverbs.h" #include "core_priv.h" /** * rdma_umap_priv_init() - Initialize the private data of a vma * * @priv: The already allocated private data * @vma: The vm area struct that needs private data * @entry: entry into the mmap_xa that needs to be linked with * this vma * * Each time we map IO memory into user space this keeps track of the * mapping. When the device is hot-unplugged we 'zap' the mmaps in user space * to point to the zero page and allow the hot unplug to proceed. * * This is necessary for cases like PCI physical hot unplug as the actual BAR * memory may vanish after this and access to it from userspace could MCE. * * RDMA drivers supporting disassociation must have their user space designed * to cope in some way with their IO pages going to the zero page. * */ void rdma_umap_priv_init(struct rdma_umap_priv *priv, struct vm_area_struct *vma, struct rdma_user_mmap_entry *entry) { … } EXPORT_SYMBOL(…); /** * rdma_user_mmap_io() - Map IO memory into a process * * @ucontext: associated user context * @vma: the vma related to the current mmap call * @pfn: pfn to map * @size: size to map * @prot: pgprot to use in remap call * @entry: mmap_entry retrieved from rdma_user_mmap_entry_get(), or NULL * if mmap_entry is not used by the driver * * This is to be called by drivers as part of their mmap() functions if they * wish to send something like PCI-E BAR memory to userspace. * * Return -EINVAL on wrong flags or size, -EAGAIN on failure to map. 0 on * success. */ int rdma_user_mmap_io(struct ib_ucontext *ucontext, struct vm_area_struct *vma, unsigned long pfn, unsigned long size, pgprot_t prot, struct rdma_user_mmap_entry *entry) { … } EXPORT_SYMBOL(…); /** * rdma_user_mmap_entry_get_pgoff() - Get an entry from the mmap_xa * * @ucontext: associated user context * @pgoff: The mmap offset >> PAGE_SHIFT * * This function is called when a user tries to mmap with an offset (returned * by rdma_user_mmap_get_offset()) it initially received from the driver. The * rdma_user_mmap_entry was created by the function * rdma_user_mmap_entry_insert(). This function increases the refcnt of the * entry so that it won't be deleted from the xarray in the meantime. * * Return an reference to an entry if exists or NULL if there is no * match. rdma_user_mmap_entry_put() must be called to put the reference. */ struct rdma_user_mmap_entry * rdma_user_mmap_entry_get_pgoff(struct ib_ucontext *ucontext, unsigned long pgoff) { … } EXPORT_SYMBOL(…); /** * rdma_user_mmap_entry_get() - Get an entry from the mmap_xa * * @ucontext: associated user context * @vma: the vma being mmap'd into * * This function is like rdma_user_mmap_entry_get_pgoff() except that it also * checks that the VMA is correct. */ struct rdma_user_mmap_entry * rdma_user_mmap_entry_get(struct ib_ucontext *ucontext, struct vm_area_struct *vma) { … } EXPORT_SYMBOL(…); static void rdma_user_mmap_entry_free(struct kref *kref) { … } /** * rdma_user_mmap_entry_put() - Drop reference to the mmap entry * * @entry: an entry in the mmap_xa * * This function is called when the mapping is closed if it was * an io mapping or when the driver is done with the entry for * some other reason. * Should be called after rdma_user_mmap_entry_get was called * and entry is no longer needed. This function will erase the * entry and free it if its refcnt reaches zero. */ void rdma_user_mmap_entry_put(struct rdma_user_mmap_entry *entry) { … } EXPORT_SYMBOL(…); /** * rdma_user_mmap_entry_remove() - Drop reference to entry and * mark it as unmmapable * * @entry: the entry to insert into the mmap_xa * * Drivers can call this to prevent userspace from creating more mappings for * entry, however existing mmaps continue to exist and ops->mmap_free() will * not be called until all user mmaps are destroyed. */ void rdma_user_mmap_entry_remove(struct rdma_user_mmap_entry *entry) { … } EXPORT_SYMBOL(…); /** * rdma_user_mmap_entry_insert_range() - Insert an entry to the mmap_xa * in a given range. * * @ucontext: associated user context. * @entry: the entry to insert into the mmap_xa * @length: length of the address that will be mmapped * @min_pgoff: minimum pgoff to be returned * @max_pgoff: maximum pgoff to be returned * * This function should be called by drivers that use the rdma_user_mmap * interface for implementing their mmap syscall A database of mmap offsets is * handled in the core and helper functions are provided to insert entries * into the database and extract entries when the user calls mmap with the * given offset. The function allocates a unique page offset in a given range * that should be provided to user, the user will use the offset to retrieve * information such as address to be mapped and how. * * Return: 0 on success and -ENOMEM on failure */ int rdma_user_mmap_entry_insert_range(struct ib_ucontext *ucontext, struct rdma_user_mmap_entry *entry, size_t length, u32 min_pgoff, u32 max_pgoff) { … } EXPORT_SYMBOL(…); /** * rdma_user_mmap_entry_insert() - Insert an entry to the mmap_xa. * * @ucontext: associated user context. * @entry: the entry to insert into the mmap_xa * @length: length of the address that will be mmapped * * This function should be called by drivers that use the rdma_user_mmap * interface for handling user mmapped addresses. The database is handled in * the core and helper functions are provided to insert entries into the * database and extract entries when the user calls mmap with the given offset. * The function allocates a unique page offset that should be provided to user, * the user will use the offset to retrieve information such as address to * be mapped and how. * * Return: 0 on success and -ENOMEM on failure */ int rdma_user_mmap_entry_insert(struct ib_ucontext *ucontext, struct rdma_user_mmap_entry *entry, size_t length) { … } EXPORT_SYMBOL(…);