// SPDX-License-Identifier: GPL-2.0-only /* * IBM Accelerator Family 'GenWQE' * * (C) Copyright IBM Corp. 2013 * * Author: Frank Haverkamp <[email protected]> * Author: Joerg-Stephan Vogt <[email protected]> * Author: Michael Jung <[email protected]> * Author: Michael Ruettger <[email protected]> */ /* * Character device representation of the GenWQE device. This allows * user-space applications to communicate with the card. */ #include <linux/kernel.h> #include <linux/types.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/string.h> #include <linux/fs.h> #include <linux/sched/signal.h> #include <linux/wait.h> #include <linux/delay.h> #include <linux/atomic.h> #include "card_base.h" #include "card_ddcb.h" static int genwqe_open_files(struct genwqe_dev *cd) { … } static void genwqe_add_file(struct genwqe_dev *cd, struct genwqe_file *cfile) { … } static int genwqe_del_file(struct genwqe_dev *cd, struct genwqe_file *cfile) { … } static void genwqe_add_pin(struct genwqe_file *cfile, struct dma_mapping *m) { … } static int genwqe_del_pin(struct genwqe_file *cfile, struct dma_mapping *m) { … } /** * genwqe_search_pin() - Search for the mapping for a userspace address * @cfile: Descriptor of opened file * @u_addr: User virtual address * @size: Size of buffer * @virt_addr: Virtual address to be updated * * Return: Pointer to the corresponding mapping NULL if not found */ static struct dma_mapping *genwqe_search_pin(struct genwqe_file *cfile, unsigned long u_addr, unsigned int size, void **virt_addr) { … } static void __genwqe_add_mapping(struct genwqe_file *cfile, struct dma_mapping *dma_map) { … } static void __genwqe_del_mapping(struct genwqe_file *cfile, struct dma_mapping *dma_map) { … } /** * __genwqe_search_mapping() - Search for the mapping for a userspace address * @cfile: descriptor of opened file * @u_addr: user virtual address * @size: size of buffer * @dma_addr: DMA address to be updated * @virt_addr: Virtual address to be updated * Return: Pointer to the corresponding mapping NULL if not found */ static struct dma_mapping *__genwqe_search_mapping(struct genwqe_file *cfile, unsigned long u_addr, unsigned int size, dma_addr_t *dma_addr, void **virt_addr) { … } static void genwqe_remove_mappings(struct genwqe_file *cfile) { … } static void genwqe_remove_pinnings(struct genwqe_file *cfile) { … } /** * genwqe_kill_fasync() - Send signal to all processes with open GenWQE files * @cd: GenWQE device information * @sig: Signal to send out * * E.g. genwqe_send_signal(cd, SIGIO); */ static int genwqe_kill_fasync(struct genwqe_dev *cd, int sig) { … } static int genwqe_terminate(struct genwqe_dev *cd) { … } /** * genwqe_open() - file open * @inode: file system information * @filp: file handle * * This function is executed whenever an application calls * open("/dev/genwqe",..). * * Return: 0 if successful or <0 if errors */ static int genwqe_open(struct inode *inode, struct file *filp) { … } /** * genwqe_fasync() - Setup process to receive SIGIO. * @fd: file descriptor * @filp: file handle * @mode: file mode * * Sending a signal is working as following: * * if (cdev->async_queue) * kill_fasync(&cdev->async_queue, SIGIO, POLL_IN); * * Some devices also implement asynchronous notification to indicate * when the device can be written; in this case, of course, * kill_fasync must be called with a mode of POLL_OUT. */ static int genwqe_fasync(int fd, struct file *filp, int mode) { … } /** * genwqe_release() - file close * @inode: file system information * @filp: file handle * * This function is executed whenever an application calls 'close(fd_genwqe)' * * Return: always 0 */ static int genwqe_release(struct inode *inode, struct file *filp) { … } static void genwqe_vma_open(struct vm_area_struct *vma) { … } /** * genwqe_vma_close() - Called each time when vma is unmapped * @vma: VMA area to close * * Free memory which got allocated by GenWQE mmap(). */ static void genwqe_vma_close(struct vm_area_struct *vma) { … } static const struct vm_operations_struct genwqe_vma_ops = …; /** * genwqe_mmap() - Provide contignous buffers to userspace * @filp: File pointer (unused) * @vma: VMA area to map * * We use mmap() to allocate contignous buffers used for DMA * transfers. After the buffer is allocated we remap it to user-space * and remember a reference to our dma_mapping data structure, where * we store the associated DMA address and allocated size. * * When we receive a DDCB execution request with the ATS bits set to * plain buffer, we lookup our dma_mapping list to find the * corresponding DMA address for the associated user-space address. */ static int genwqe_mmap(struct file *filp, struct vm_area_struct *vma) { … } #define FLASH_BLOCK … /** * do_flash_update() - Excute flash update (write image or CVPD) * @cfile: Descriptor of opened file * @load: details about image load * * Return: 0 if successful */ static int do_flash_update(struct genwqe_file *cfile, struct genwqe_bitstream *load) { … } static int do_flash_read(struct genwqe_file *cfile, struct genwqe_bitstream *load) { … } static int genwqe_pin_mem(struct genwqe_file *cfile, struct genwqe_mem *m) { … } static int genwqe_unpin_mem(struct genwqe_file *cfile, struct genwqe_mem *m) { … } /** * ddcb_cmd_cleanup() - Remove dynamically created fixup entries * @cfile: Descriptor of opened file * @req: DDCB work request * * Only if there are any. Pinnings are not removed. */ static int ddcb_cmd_cleanup(struct genwqe_file *cfile, struct ddcb_requ *req) { … } /** * ddcb_cmd_fixups() - Establish DMA fixups/sglists for user memory references * @cfile: Descriptor of opened file * @req: DDCB work request * * Before the DDCB gets executed we need to handle the fixups. We * replace the user-space addresses with DMA addresses or do * additional setup work e.g. generating a scatter-gather list which * is used to describe the memory referred to in the fixup. */ static int ddcb_cmd_fixups(struct genwqe_file *cfile, struct ddcb_requ *req) { … } /** * genwqe_execute_ddcb() - Execute DDCB using userspace address fixups * @cfile: Descriptor of opened file * @cmd: Command identifier (passed from user) * * The code will build up the translation tables or lookup the * contignous memory allocation table to find the right translations * and DMA addresses. */ static int genwqe_execute_ddcb(struct genwqe_file *cfile, struct genwqe_ddcb_cmd *cmd) { … } static int do_execute_ddcb(struct genwqe_file *cfile, unsigned long arg, int raw) { … } /** * genwqe_ioctl() - IO control * @filp: file handle * @cmd: command identifier (passed from user) * @arg: argument (passed from user) * * Return: 0 success */ static long genwqe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { … } static const struct file_operations genwqe_fops = …; static int genwqe_device_initialized(struct genwqe_dev *cd) { … } /** * genwqe_device_create() - Create and configure genwqe char device * @cd: genwqe device descriptor * * This function must be called before we create any more genwqe * character devices, because it is allocating the major and minor * number which are supposed to be used by the client drivers. */ int genwqe_device_create(struct genwqe_dev *cd) { … } static int genwqe_inform_and_stop_processes(struct genwqe_dev *cd) { … } /** * genwqe_device_remove() - Remove genwqe's char device * @cd: GenWQE device information * * This function must be called after the client devices are removed * because it will free the major/minor number range for the genwqe * drivers. * * This function must be robust enough to be called twice. */ int genwqe_device_remove(struct genwqe_dev *cd) { … }