// SPDX-License-Identifier: GPL-2.0+/* * IBM Power Systems Virtual Management Channel Support. * * Copyright (c) 2004, 2018 IBM Corp. * Dave Engebretsen engebret@us.ibm.com * Steven Royer seroyer@linux.vnet.ibm.com * Adam Reznechek adreznec@linux.vnet.ibm.com * Bryant G. Ly <bryantly@linux.vnet.ibm.com> */ #include <linux/module.h>#include <linux/kernel.h>#include <linux/kthread.h>#include <linux/major.h>#include <linux/string.h>#include <linux/fcntl.h>#include <linux/slab.h>#include <linux/poll.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/interrupt.h>#include <linux/spinlock.h>#include <linux/percpu.h>#include <linux/delay.h>#include <linux/uaccess.h>#include <linux/io.h>#include <linux/miscdevice.h>#include <linux/sched/signal.h> #include <asm/byteorder.h>#include <asm/irq.h>#include <asm/vio.h> #include "ibmvmc.h" #define IBMVMC_DRIVER_VERSION "1.0" /* * Static global variables */static DECLARE_WAIT_QUEUE_HEAD(ibmvmc_read_wait); static const char ibmvmc_driver_name[] = "ibmvmc"; static struct ibmvmc_struct ibmvmc;static struct ibmvmc_hmc hmcs[MAX_HMCS];static struct crq_server_adapter ibmvmc_adapter; static int ibmvmc_max_buf_pool_size = DEFAULT_BUF_POOL_SIZE;static int ibmvmc_max_hmcs = DEFAULT_HMCS;static int ibmvmc_max_mtu = DEFAULT_MTU; static inline long h_copy_rdma(s64 length, u64 sliobn, u64 slioba, u64 dliobn, u64 dlioba){ long rc = 0; /* Ensure all writes to source memory are visible before hcall */ dma_wmb(); pr_debug("ibmvmc: h_copy_rdma(0x%llx, 0x%llx, 0x%llx, 0x%llx, 0x%llx\n", length, sliobn, slioba, dliobn, dlioba); rc = plpar_hcall_norets(H_COPY_RDMA, length, sliobn, slioba, dliobn, dlioba); pr_debug("ibmvmc: h_copy_rdma rc = 0x%lx\n", rc); return rc;} static inline void h_free_crq(uint32_t unit_address){ long rc = 0; do { if (H_IS_LONG_BUSY(rc)) msleep(get_longbusy_msecs(rc)); rc = plpar_hcall_norets(H_FREE_CRQ, unit_address); } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));} /** * h_request_vmc: - request a hypervisor virtual management channel device * @vmc_index: drc index of the vmc device created * * Requests the hypervisor create a new virtual management channel device, * allowing this partition to send hypervisor virtualization control * commands. * * Return: * 0 - Success * Non-zero - Failure */static inline long h_request_vmc(u32 *vmc_index){ long rc = 0; unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; do { if (H_IS_LONG_BUSY(rc)) msleep(get_longbusy_msecs(rc)); /* Call to request the VMC device from phyp */ rc = plpar_hcall(H_REQUEST_VMC, retbuf); pr_debug("ibmvmc: %s rc = 0x%lx\n", __func__, rc); *vmc_index = retbuf[0]; } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); return rc;} /* routines for managing a command/response queue *//** * ibmvmc_handle_event: - Interrupt handler for crq events * @irq: number of irq to handle, not used * @dev_instance: crq_server_adapter that received interrupt * * Disables interrupts and schedules ibmvmc_task * * Always returns IRQ_HANDLED */static irqreturn_t ibmvmc_handle_event(int irq, void *dev_instance){ struct crq_server_adapter *adapter = (struct crq_server_adapter *)dev_instance; vio_disable_interrupts(to_vio_dev(adapter->dev)); tasklet_schedule(&adapter->work_task); return IRQ_HANDLED;} /** * ibmvmc_release_crq_queue - Release CRQ Queue * * @adapter: crq_server_adapter struct * * Return: * 0 - Success * Non-Zero - Failure */static void ibmvmc_release_crq_queue(struct crq_server_adapter *adapter){ struct vio_dev *vdev = to_vio_dev(adapter->dev); struct crq_queue *queue = &adapter->queue; free_irq(vdev->irq, (void *)adapter); tasklet_kill(&adapter->work_task); if (adapter->reset_task) kthread_stop(adapter->reset_task); h_free_crq(vdev->unit_address); dma_unmap_single(adapter->dev, queue->msg_token, queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); free_page((unsigned long)queue->msgs);} /** * ibmvmc_reset_crq_queue - Reset CRQ Queue * * @adapter: crq_server_adapter struct * * This function calls h_free_crq and then calls H_REG_CRQ and does all the * bookkeeping to get us back to where we can communicate. * * Return: * 0 - Success * Non-Zero - Failure */static int ibmvmc_reset_crq_queue(struct crq_server_adapter *adapter){ struct vio_dev *vdev = to_vio_dev(adapter->dev); struct crq_queue *queue = &adapter->queue; int rc = 0; /* Close the CRQ */ h_free_crq(vdev->unit_address); /* Clean out the queue */ memset(queue->msgs, 0x00, PAGE_SIZE); queue->cur = 0; /* And re-open it again */ rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address, queue->msg_token, PAGE_SIZE); if (rc == 2) /* Adapter is good, but other end is not ready */ dev_warn(adapter->dev, "Partner adapter not ready\n"); else if (rc != 0) dev_err(adapter->dev, "couldn't register crq--rc 0x%x\n", rc); return rc;} /** * crq_queue_next_crq: - Returns the next entry in message queue * @queue: crq_queue to use * * Returns pointer to next entry in queue, or NULL if there are no new * entried in the CRQ. */static struct ibmvmc_crq_msg *crq_queue_next_crq(struct crq_queue *queue){ struct ibmvmc_crq_msg *crq; unsigned long flags; spin_lock_irqsave(&queue->lock, flags); crq = &queue->msgs[queue->cur]; if (crq->valid & 0x80) { if (++queue->cur == queue->size) queue->cur = 0; /* Ensure the read of the valid bit occurs before reading any * other bits of the CRQ entry */ dma_rmb(); } else { crq = NULL; } spin_unlock_irqrestore(&queue->lock, flags); return crq;} /** * ibmvmc_send_crq - Send CRQ * * @adapter: crq_server_adapter struct * @word1: Word1 Data field * @word2: Word2 Data field * * Return: * 0 - Success * Non-Zero - Failure */static long ibmvmc_send_crq(struct crq_server_adapter *adapter, u64 word1, u64 word2){ struct vio_dev *vdev = to_vio_dev(adapter->dev); long rc = 0; dev_dbg(adapter->dev, "(0x%x, 0x%016llx, 0x%016llx)\n", vdev->unit_address, word1, word2); /* * Ensure the command buffer is flushed to memory before handing it * over to the other side to prevent it from fetching any stale data. */ dma_wmb(); rc = plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2); dev_dbg(adapter->dev, "rc = 0x%lx\n", rc); return rc;} /** * alloc_dma_buffer - Create DMA Buffer * * @vdev: vio_dev struct * @size: Size field * @dma_handle: DMA address field * * Allocates memory for the command queue and maps remote memory into an * ioba. * * Returns a pointer to the buffer */static void *alloc_dma_buffer(struct vio_dev *vdev, size_t size, dma_addr_t *dma_handle){ /* allocate memory */ void *buffer = kzalloc(size, GFP_ATOMIC); if (!buffer) { *dma_handle = 0; return NULL; } /* DMA map */ *dma_handle = dma_map_single(&vdev->dev, buffer, size, DMA_BIDIRECTIONAL); if (dma_mapping_error(&vdev->dev, *dma_handle)) { *dma_handle = 0; kfree_sensitive(buffer); return NULL; } return buffer;} /** * free_dma_buffer - Free DMA Buffer * * @vdev: vio_dev struct * @size: Size field * @vaddr: Address field * @dma_handle: DMA address field * * Releases memory for a command queue and unmaps mapped remote memory. */static void free_dma_buffer(struct vio_dev *vdev, size_t size, void *vaddr, dma_addr_t dma_handle){ /* DMA unmap */ dma_unmap_single(&vdev->dev, dma_handle, size, DMA_BIDIRECTIONAL); /* deallocate memory */ kfree_sensitive(vaddr);} /** * ibmvmc_get_valid_hmc_buffer - Retrieve Valid HMC Buffer * * @hmc_index: HMC Index Field * * Return: * Pointer to ibmvmc_buffer */static struct ibmvmc_buffer *ibmvmc_get_valid_hmc_buffer(u8 hmc_index){ struct ibmvmc_buffer *buffer; struct ibmvmc_buffer *ret_buf = NULL; unsigned long i; if (hmc_index > ibmvmc.max_hmc_index) return NULL; buffer = hmcs[hmc_index].buffer; for (i = 0; i < ibmvmc_max_buf_pool_size; i++) { if (buffer[i].valid && buffer[i].free && buffer[i].owner == VMC_BUF_OWNER_ALPHA) { buffer[i].free = 0; ret_buf = &buffer[i]; break; } } return ret_buf;} /** * ibmvmc_get_free_hmc_buffer - Get Free HMC Buffer * * @adapter: crq_server_adapter struct * @hmc_index: Hmc Index field * * Return: * Pointer to ibmvmc_buffer */static struct ibmvmc_buffer *ibmvmc_get_free_hmc_buffer(struct crq_server_adapter *adapter, u8 hmc_index){ struct ibmvmc_buffer *buffer; struct ibmvmc_buffer *ret_buf = NULL; unsigned long i; if (hmc_index > ibmvmc.max_hmc_index) { dev_info(adapter->dev, "get_free_hmc_buffer: invalid hmc_index=0x%x\n", hmc_index); return NULL; } buffer = hmcs[hmc_index].buffer; for (i = 0; i < ibmvmc_max_buf_pool_size; i++) { if (buffer[i].free && buffer[i].owner == VMC_BUF_OWNER_ALPHA) { buffer[i].free = 0; ret_buf = &buffer[i]; break; } } return ret_buf;} /** * ibmvmc_free_hmc_buffer - Free an HMC Buffer * * @hmc: ibmvmc_hmc struct * @buffer: ibmvmc_buffer struct * */static void ibmvmc_free_hmc_buffer(struct ibmvmc_hmc *hmc, struct ibmvmc_buffer *buffer){ unsigned long flags; spin_lock_irqsave(&hmc->lock, flags); buffer->free = 1; spin_unlock_irqrestore(&hmc->lock, flags);} /** * ibmvmc_count_hmc_buffers - Count HMC Buffers * * @hmc_index: HMC Index field * @valid: Valid number of buffers field * @free: Free number of buffers field * */static void ibmvmc_count_hmc_buffers(u8 hmc_index, unsigned int *valid, unsigned int *free){ struct ibmvmc_buffer *buffer; unsigned long i; unsigned long flags; if (hmc_index > ibmvmc.max_hmc_index) return; if (!valid || !free) return; *valid = 0; *free = 0; buffer = hmcs[hmc_index].buffer; spin_lock_irqsave(&hmcs[hmc_index].lock, flags); for (i = 0; i < ibmvmc_max_buf_pool_size; i++) { if (buffer[i].valid) { *valid = *valid + 1; if (buffer[i].free) *free = *free + 1; } } spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags);} /** * ibmvmc_get_free_hmc - Get Free HMC * * Return: * Pointer to an available HMC Connection * Null otherwise */static struct ibmvmc_hmc *ibmvmc_get_free_hmc(void){ unsigned long i; unsigned long flags; /* * Find an available HMC connection. */ for (i = 0; i <= ibmvmc.max_hmc_index; i++) { spin_lock_irqsave(&hmcs[i].lock, flags); if (hmcs[i].state == ibmhmc_state_free) { hmcs[i].index = i; hmcs[i].state = ibmhmc_state_initial; spin_unlock_irqrestore(&hmcs[i].lock, flags); return &hmcs[i]; } spin_unlock_irqrestore(&hmcs[i].lock, flags); } return NULL;} /** * ibmvmc_return_hmc - Return an HMC Connection * * @hmc: ibmvmc_hmc struct * @release_readers: Number of readers connected to session * * This function releases the HMC connections back into the pool. * * Return: * 0 - Success * Non-zero - Failure */static int ibmvmc_return_hmc(struct ibmvmc_hmc *hmc, bool release_readers){ struct ibmvmc_buffer *buffer; struct crq_server_adapter *adapter; struct vio_dev *vdev; unsigned long i; unsigned long flags; if (!hmc || !hmc->adapter) return -EIO; if (release_readers) { if (hmc->file_session) { struct ibmvmc_file_session *session = hmc->file_session; session->valid = 0; wake_up_interruptible(&ibmvmc_read_wait); } } adapter = hmc->adapter; vdev = to_vio_dev(adapter->dev); Lines 1–500 of 2432. Load more
// SPDX-License-Identifier: GPL-2.0+ /* * IBM Power Systems Virtual Management Channel Support. * * Copyright (c) 2004, 2018 IBM Corp. * Dave Engebretsen engebret@us.ibm.com * Steven Royer seroyer@linux.vnet.ibm.com * Adam Reznechek adreznec@linux.vnet.ibm.com * Bryant G. Ly <bryantly@linux.vnet.ibm.com> */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/kthread.h> #include <linux/major.h> #include <linux/string.h> #include <linux/fcntl.h> #include <linux/slab.h> #include <linux/poll.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/percpu.h> #include <linux/delay.h> #include <linux/uaccess.h> #include <linux/io.h> #include <linux/miscdevice.h> #include <linux/sched/signal.h> #include <asm/byteorder.h> #include <asm/irq.h> #include <asm/vio.h> #include "ibmvmc.h" #define IBMVMC_DRIVER_VERSION "1.0" /* * Static global variables */ static DECLARE_WAIT_QUEUE_HEAD(ibmvmc_read_wait); static const char ibmvmc_driver_name[] = "ibmvmc"; static struct ibmvmc_struct ibmvmc; static struct ibmvmc_hmc hmcs[MAX_HMCS]; static struct crq_server_adapter ibmvmc_adapter; static int ibmvmc_max_buf_pool_size = DEFAULT_BUF_POOL_SIZE; static int ibmvmc_max_hmcs = DEFAULT_HMCS; static int ibmvmc_max_mtu = DEFAULT_MTU; static inline long h_copy_rdma(s64 length, u64 sliobn, u64 slioba, u64 dliobn, u64 dlioba) { long rc = 0; /* Ensure all writes to source memory are visible before hcall */ dma_wmb(); pr_debug("ibmvmc: h_copy_rdma(0x%llx, 0x%llx, 0x%llx, 0x%llx, 0x%llx\n", length, sliobn, slioba, dliobn, dlioba); rc = plpar_hcall_norets(H_COPY_RDMA, length, sliobn, slioba, dliobn, dlioba); pr_debug("ibmvmc: h_copy_rdma rc = 0x%lx\n", rc); return rc; } static inline void h_free_crq(uint32_t unit_address) { long rc = 0; do { if (H_IS_LONG_BUSY(rc)) msleep(get_longbusy_msecs(rc)); rc = plpar_hcall_norets(H_FREE_CRQ, unit_address); } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); } /** * h_request_vmc: - request a hypervisor virtual management channel device * @vmc_index: drc index of the vmc device created * * Requests the hypervisor create a new virtual management channel device, * allowing this partition to send hypervisor virtualization control * commands. * * Return: * 0 - Success * Non-zero - Failure */ static inline long h_request_vmc(u32 *vmc_index) { long rc = 0; unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; do { if (H_IS_LONG_BUSY(rc)) msleep(get_longbusy_msecs(rc)); /* Call to request the VMC device from phyp */ rc = plpar_hcall(H_REQUEST_VMC, retbuf); pr_debug("ibmvmc: %s rc = 0x%lx\n", __func__, rc); *vmc_index = retbuf[0]; } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); return rc; } /* routines for managing a command/response queue */ /** * ibmvmc_handle_event: - Interrupt handler for crq events * @irq: number of irq to handle, not used * @dev_instance: crq_server_adapter that received interrupt * * Disables interrupts and schedules ibmvmc_task * * Always returns IRQ_HANDLED */ static irqreturn_t ibmvmc_handle_event(int irq, void *dev_instance) { struct crq_server_adapter *adapter = (struct crq_server_adapter *)dev_instance; vio_disable_interrupts(to_vio_dev(adapter->dev)); tasklet_schedule(&adapter->work_task); return IRQ_HANDLED; } /** * ibmvmc_release_crq_queue - Release CRQ Queue * * @adapter: crq_server_adapter struct * * Return: * 0 - Success * Non-Zero - Failure */ static void ibmvmc_release_crq_queue(struct crq_server_adapter *adapter) { struct vio_dev *vdev = to_vio_dev(adapter->dev); struct crq_queue *queue = &adapter->queue; free_irq(vdev->irq, (void *)adapter); tasklet_kill(&adapter->work_task); if (adapter->reset_task) kthread_stop(adapter->reset_task); h_free_crq(vdev->unit_address); dma_unmap_single(adapter->dev, queue->msg_token, queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); free_page((unsigned long)queue->msgs); } /** * ibmvmc_reset_crq_queue - Reset CRQ Queue * * @adapter: crq_server_adapter struct * * This function calls h_free_crq and then calls H_REG_CRQ and does all the * bookkeeping to get us back to where we can communicate. * * Return: * 0 - Success * Non-Zero - Failure */ static int ibmvmc_reset_crq_queue(struct crq_server_adapter *adapter) { struct vio_dev *vdev = to_vio_dev(adapter->dev); struct crq_queue *queue = &adapter->queue; int rc = 0; /* Close the CRQ */ h_free_crq(vdev->unit_address); /* Clean out the queue */ memset(queue->msgs, 0x00, PAGE_SIZE); queue->cur = 0; /* And re-open it again */ rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address, queue->msg_token, PAGE_SIZE); if (rc == 2) /* Adapter is good, but other end is not ready */ dev_warn(adapter->dev, "Partner adapter not ready\n"); else if (rc != 0) dev_err(adapter->dev, "couldn't register crq--rc 0x%x\n", rc); return rc; } /** * crq_queue_next_crq: - Returns the next entry in message queue * @queue: crq_queue to use * * Returns pointer to next entry in queue, or NULL if there are no new * entried in the CRQ. */ static struct ibmvmc_crq_msg *crq_queue_next_crq(struct crq_queue *queue) { struct ibmvmc_crq_msg *crq; unsigned long flags; spin_lock_irqsave(&queue->lock, flags); crq = &queue->msgs[queue->cur]; if (crq->valid & 0x80) { if (++queue->cur == queue->size) queue->cur = 0; /* Ensure the read of the valid bit occurs before reading any * other bits of the CRQ entry */ dma_rmb(); } else { crq = NULL; } spin_unlock_irqrestore(&queue->lock, flags); return crq; } /** * ibmvmc_send_crq - Send CRQ * * @adapter: crq_server_adapter struct * @word1: Word1 Data field * @word2: Word2 Data field * * Return: * 0 - Success * Non-Zero - Failure */ static long ibmvmc_send_crq(struct crq_server_adapter *adapter, u64 word1, u64 word2) { struct vio_dev *vdev = to_vio_dev(adapter->dev); long rc = 0; dev_dbg(adapter->dev, "(0x%x, 0x%016llx, 0x%016llx)\n", vdev->unit_address, word1, word2); /* * Ensure the command buffer is flushed to memory before handing it * over to the other side to prevent it from fetching any stale data. */ dma_wmb(); rc = plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2); dev_dbg(adapter->dev, "rc = 0x%lx\n", rc); return rc; } /** * alloc_dma_buffer - Create DMA Buffer * * @vdev: vio_dev struct * @size: Size field * @dma_handle: DMA address field * * Allocates memory for the command queue and maps remote memory into an * ioba. * * Returns a pointer to the buffer */ static void *alloc_dma_buffer(struct vio_dev *vdev, size_t size, dma_addr_t *dma_handle) { /* allocate memory */ void *buffer = kzalloc(size, GFP_ATOMIC); if (!buffer) { *dma_handle = 0; return NULL; } /* DMA map */ *dma_handle = dma_map_single(&vdev->dev, buffer, size, DMA_BIDIRECTIONAL); if (dma_mapping_error(&vdev->dev, *dma_handle)) { *dma_handle = 0; kfree_sensitive(buffer); return NULL; } return buffer; } /** * free_dma_buffer - Free DMA Buffer * * @vdev: vio_dev struct * @size: Size field * @vaddr: Address field * @dma_handle: DMA address field * * Releases memory for a command queue and unmaps mapped remote memory. */ static void free_dma_buffer(struct vio_dev *vdev, size_t size, void *vaddr, dma_addr_t dma_handle) { /* DMA unmap */ dma_unmap_single(&vdev->dev, dma_handle, size, DMA_BIDIRECTIONAL); /* deallocate memory */ kfree_sensitive(vaddr); } /** * ibmvmc_get_valid_hmc_buffer - Retrieve Valid HMC Buffer * * @hmc_index: HMC Index Field * * Return: * Pointer to ibmvmc_buffer */ static struct ibmvmc_buffer *ibmvmc_get_valid_hmc_buffer(u8 hmc_index) { struct ibmvmc_buffer *buffer; struct ibmvmc_buffer *ret_buf = NULL; unsigned long i; if (hmc_index > ibmvmc.max_hmc_index) return NULL; buffer = hmcs[hmc_index].buffer; for (i = 0; i < ibmvmc_max_buf_pool_size; i++) { if (buffer[i].valid && buffer[i].free && buffer[i].owner == VMC_BUF_OWNER_ALPHA) { buffer[i].free = 0; ret_buf = &buffer[i]; break; } } return ret_buf; } /** * ibmvmc_get_free_hmc_buffer - Get Free HMC Buffer * * @adapter: crq_server_adapter struct * @hmc_index: Hmc Index field * * Return: * Pointer to ibmvmc_buffer */ static struct ibmvmc_buffer *ibmvmc_get_free_hmc_buffer(struct crq_server_adapter *adapter, u8 hmc_index) { struct ibmvmc_buffer *buffer; struct ibmvmc_buffer *ret_buf = NULL; unsigned long i; if (hmc_index > ibmvmc.max_hmc_index) { dev_info(adapter->dev, "get_free_hmc_buffer: invalid hmc_index=0x%x\n", hmc_index); return NULL; } buffer = hmcs[hmc_index].buffer; for (i = 0; i < ibmvmc_max_buf_pool_size; i++) { if (buffer[i].free && buffer[i].owner == VMC_BUF_OWNER_ALPHA) { buffer[i].free = 0; ret_buf = &buffer[i]; break; } } return ret_buf; } /** * ibmvmc_free_hmc_buffer - Free an HMC Buffer * * @hmc: ibmvmc_hmc struct * @buffer: ibmvmc_buffer struct * */ static void ibmvmc_free_hmc_buffer(struct ibmvmc_hmc *hmc, struct ibmvmc_buffer *buffer) { unsigned long flags; spin_lock_irqsave(&hmc->lock, flags); buffer->free = 1; spin_unlock_irqrestore(&hmc->lock, flags); } /** * ibmvmc_count_hmc_buffers - Count HMC Buffers * * @hmc_index: HMC Index field * @valid: Valid number of buffers field * @free: Free number of buffers field * */ static void ibmvmc_count_hmc_buffers(u8 hmc_index, unsigned int *valid, unsigned int *free) { struct ibmvmc_buffer *buffer; unsigned long i; unsigned long flags; if (hmc_index > ibmvmc.max_hmc_index) return; if (!valid || !free) return; *valid = 0; *free = 0; buffer = hmcs[hmc_index].buffer; spin_lock_irqsave(&hmcs[hmc_index].lock, flags); for (i = 0; i < ibmvmc_max_buf_pool_size; i++) { if (buffer[i].valid) { *valid = *valid + 1; if (buffer[i].free) *free = *free + 1; } } spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags); } /** * ibmvmc_get_free_hmc - Get Free HMC * * Return: * Pointer to an available HMC Connection * Null otherwise */ static struct ibmvmc_hmc *ibmvmc_get_free_hmc(void) { unsigned long i; unsigned long flags; /* * Find an available HMC connection. */ for (i = 0; i <= ibmvmc.max_hmc_index; i++) { spin_lock_irqsave(&hmcs[i].lock, flags); if (hmcs[i].state == ibmhmc_state_free) { hmcs[i].index = i; hmcs[i].state = ibmhmc_state_initial; spin_unlock_irqrestore(&hmcs[i].lock, flags); return &hmcs[i]; } spin_unlock_irqrestore(&hmcs[i].lock, flags); } return NULL; } /** * ibmvmc_return_hmc - Return an HMC Connection * * @hmc: ibmvmc_hmc struct * @release_readers: Number of readers connected to session * * This function releases the HMC connections back into the pool. * * Return: * 0 - Success * Non-zero - Failure */ static int ibmvmc_return_hmc(struct ibmvmc_hmc *hmc, bool release_readers) { struct ibmvmc_buffer *buffer; struct crq_server_adapter *adapter; struct vio_dev *vdev; unsigned long i; unsigned long flags; if (!hmc || !hmc->adapter) return -EIO; if (release_readers) { if (hmc->file_session) { struct ibmvmc_file_session *session = hmc->file_session; session->valid = 0; wake_up_interruptible(&ibmvmc_read_wait); } } adapter = hmc->adapter; vdev = to_vio_dev(adapter->dev);