10eca353eSBryant G. Ly // SPDX-License-Identifier: GPL-2.0+
20eca353eSBryant G. Ly /*
30eca353eSBryant G. Ly * IBM Power Systems Virtual Management Channel Support.
40eca353eSBryant G. Ly *
50eca353eSBryant G. Ly * Copyright (c) 2004, 2018 IBM Corp.
60eca353eSBryant G. Ly * Dave Engebretsen engebret@us.ibm.com
70eca353eSBryant G. Ly * Steven Royer seroyer@linux.vnet.ibm.com
80eca353eSBryant G. Ly * Adam Reznechek adreznec@linux.vnet.ibm.com
90eca353eSBryant G. Ly * Bryant G. Ly <bryantly@linux.vnet.ibm.com>
100eca353eSBryant G. Ly */
110eca353eSBryant G. Ly
120eca353eSBryant G. Ly #include <linux/module.h>
130eca353eSBryant G. Ly #include <linux/kernel.h>
140eca353eSBryant G. Ly #include <linux/kthread.h>
150eca353eSBryant G. Ly #include <linux/major.h>
160eca353eSBryant G. Ly #include <linux/string.h>
170eca353eSBryant G. Ly #include <linux/fcntl.h>
180eca353eSBryant G. Ly #include <linux/slab.h>
190eca353eSBryant G. Ly #include <linux/poll.h>
200eca353eSBryant G. Ly #include <linux/init.h>
210eca353eSBryant G. Ly #include <linux/fs.h>
220eca353eSBryant G. Ly #include <linux/interrupt.h>
230eca353eSBryant G. Ly #include <linux/spinlock.h>
240eca353eSBryant G. Ly #include <linux/percpu.h>
250eca353eSBryant G. Ly #include <linux/delay.h>
260eca353eSBryant G. Ly #include <linux/uaccess.h>
270eca353eSBryant G. Ly #include <linux/io.h>
280eca353eSBryant G. Ly #include <linux/miscdevice.h>
290eca353eSBryant G. Ly #include <linux/sched/signal.h>
300eca353eSBryant G. Ly
310eca353eSBryant G. Ly #include <asm/byteorder.h>
320eca353eSBryant G. Ly #include <asm/irq.h>
330eca353eSBryant G. Ly #include <asm/vio.h>
340eca353eSBryant G. Ly
350eca353eSBryant G. Ly #include "ibmvmc.h"
360eca353eSBryant G. Ly
370eca353eSBryant G. Ly #define IBMVMC_DRIVER_VERSION "1.0"
380eca353eSBryant G. Ly
390eca353eSBryant G. Ly /*
400eca353eSBryant G. Ly * Static global variables
410eca353eSBryant G. Ly */
420eca353eSBryant G. Ly static DECLARE_WAIT_QUEUE_HEAD(ibmvmc_read_wait);
430eca353eSBryant G. Ly
440eca353eSBryant G. Ly static const char ibmvmc_driver_name[] = "ibmvmc";
450eca353eSBryant G. Ly
460eca353eSBryant G. Ly static struct ibmvmc_struct ibmvmc;
470eca353eSBryant G. Ly static struct ibmvmc_hmc hmcs[MAX_HMCS];
480eca353eSBryant G. Ly static struct crq_server_adapter ibmvmc_adapter;
490eca353eSBryant G. Ly
500eca353eSBryant G. Ly static int ibmvmc_max_buf_pool_size = DEFAULT_BUF_POOL_SIZE;
510eca353eSBryant G. Ly static int ibmvmc_max_hmcs = DEFAULT_HMCS;
520eca353eSBryant G. Ly static int ibmvmc_max_mtu = DEFAULT_MTU;
530eca353eSBryant G. Ly
h_copy_rdma(s64 length,u64 sliobn,u64 slioba,u64 dliobn,u64 dlioba)540eca353eSBryant G. Ly static inline long h_copy_rdma(s64 length, u64 sliobn, u64 slioba,
550eca353eSBryant G. Ly u64 dliobn, u64 dlioba)
560eca353eSBryant G. Ly {
570eca353eSBryant G. Ly long rc = 0;
580eca353eSBryant G. Ly
590eca353eSBryant G. Ly /* Ensure all writes to source memory are visible before hcall */
600eca353eSBryant G. Ly dma_wmb();
610eca353eSBryant G. Ly pr_debug("ibmvmc: h_copy_rdma(0x%llx, 0x%llx, 0x%llx, 0x%llx, 0x%llx\n",
620eca353eSBryant G. Ly length, sliobn, slioba, dliobn, dlioba);
630eca353eSBryant G. Ly rc = plpar_hcall_norets(H_COPY_RDMA, length, sliobn, slioba,
640eca353eSBryant G. Ly dliobn, dlioba);
650eca353eSBryant G. Ly pr_debug("ibmvmc: h_copy_rdma rc = 0x%lx\n", rc);
660eca353eSBryant G. Ly
670eca353eSBryant G. Ly return rc;
680eca353eSBryant G. Ly }
690eca353eSBryant G. Ly
h_free_crq(uint32_t unit_address)700eca353eSBryant G. Ly static inline void h_free_crq(uint32_t unit_address)
710eca353eSBryant G. Ly {
720eca353eSBryant G. Ly long rc = 0;
730eca353eSBryant G. Ly
740eca353eSBryant G. Ly do {
750eca353eSBryant G. Ly if (H_IS_LONG_BUSY(rc))
760eca353eSBryant G. Ly msleep(get_longbusy_msecs(rc));
770eca353eSBryant G. Ly
780eca353eSBryant G. Ly rc = plpar_hcall_norets(H_FREE_CRQ, unit_address);
790eca353eSBryant G. Ly } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
800eca353eSBryant G. Ly }
810eca353eSBryant G. Ly
820eca353eSBryant G. Ly /**
830eca353eSBryant G. Ly * h_request_vmc: - request a hypervisor virtual management channel device
840eca353eSBryant G. Ly * @vmc_index: drc index of the vmc device created
850eca353eSBryant G. Ly *
860eca353eSBryant G. Ly * Requests the hypervisor create a new virtual management channel device,
870eca353eSBryant G. Ly * allowing this partition to send hypervisor virtualization control
880eca353eSBryant G. Ly * commands.
890eca353eSBryant G. Ly *
900eca353eSBryant G. Ly * Return:
910eca353eSBryant G. Ly * 0 - Success
920eca353eSBryant G. Ly * Non-zero - Failure
930eca353eSBryant G. Ly */
h_request_vmc(u32 * vmc_index)940eca353eSBryant G. Ly static inline long h_request_vmc(u32 *vmc_index)
950eca353eSBryant G. Ly {
960eca353eSBryant G. Ly long rc = 0;
970eca353eSBryant G. Ly unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
980eca353eSBryant G. Ly
990eca353eSBryant G. Ly do {
1000eca353eSBryant G. Ly if (H_IS_LONG_BUSY(rc))
1010eca353eSBryant G. Ly msleep(get_longbusy_msecs(rc));
1020eca353eSBryant G. Ly
1030eca353eSBryant G. Ly /* Call to request the VMC device from phyp */
1040eca353eSBryant G. Ly rc = plpar_hcall(H_REQUEST_VMC, retbuf);
1050eca353eSBryant G. Ly pr_debug("ibmvmc: %s rc = 0x%lx\n", __func__, rc);
1060eca353eSBryant G. Ly *vmc_index = retbuf[0];
1070eca353eSBryant G. Ly } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
1080eca353eSBryant G. Ly
1090eca353eSBryant G. Ly return rc;
1100eca353eSBryant G. Ly }
1110eca353eSBryant G. Ly
1120eca353eSBryant G. Ly /* routines for managing a command/response queue */
1130eca353eSBryant G. Ly /**
1140eca353eSBryant G. Ly * ibmvmc_handle_event: - Interrupt handler for crq events
1150eca353eSBryant G. Ly * @irq: number of irq to handle, not used
1160eca353eSBryant G. Ly * @dev_instance: crq_server_adapter that received interrupt
1170eca353eSBryant G. Ly *
1180eca353eSBryant G. Ly * Disables interrupts and schedules ibmvmc_task
1190eca353eSBryant G. Ly *
1200eca353eSBryant G. Ly * Always returns IRQ_HANDLED
1210eca353eSBryant G. Ly */
ibmvmc_handle_event(int irq,void * dev_instance)1220eca353eSBryant G. Ly static irqreturn_t ibmvmc_handle_event(int irq, void *dev_instance)
1230eca353eSBryant G. Ly {
1240eca353eSBryant G. Ly struct crq_server_adapter *adapter =
1250eca353eSBryant G. Ly (struct crq_server_adapter *)dev_instance;
1260eca353eSBryant G. Ly
1270eca353eSBryant G. Ly vio_disable_interrupts(to_vio_dev(adapter->dev));
1280eca353eSBryant G. Ly tasklet_schedule(&adapter->work_task);
1290eca353eSBryant G. Ly
1300eca353eSBryant G. Ly return IRQ_HANDLED;
1310eca353eSBryant G. Ly }
1320eca353eSBryant G. Ly
1330eca353eSBryant G. Ly /**
1340eca353eSBryant G. Ly * ibmvmc_release_crq_queue - Release CRQ Queue
1350eca353eSBryant G. Ly *
1360eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
1370eca353eSBryant G. Ly *
1380eca353eSBryant G. Ly * Return:
1390eca353eSBryant G. Ly * 0 - Success
1400eca353eSBryant G. Ly * Non-Zero - Failure
1410eca353eSBryant G. Ly */
ibmvmc_release_crq_queue(struct crq_server_adapter * adapter)1420eca353eSBryant G. Ly static void ibmvmc_release_crq_queue(struct crq_server_adapter *adapter)
1430eca353eSBryant G. Ly {
1440eca353eSBryant G. Ly struct vio_dev *vdev = to_vio_dev(adapter->dev);
1450eca353eSBryant G. Ly struct crq_queue *queue = &adapter->queue;
1460eca353eSBryant G. Ly
1470eca353eSBryant G. Ly free_irq(vdev->irq, (void *)adapter);
1480eca353eSBryant G. Ly tasklet_kill(&adapter->work_task);
1490eca353eSBryant G. Ly
1500eca353eSBryant G. Ly if (adapter->reset_task)
1510eca353eSBryant G. Ly kthread_stop(adapter->reset_task);
1520eca353eSBryant G. Ly
1530eca353eSBryant G. Ly h_free_crq(vdev->unit_address);
1540eca353eSBryant G. Ly dma_unmap_single(adapter->dev,
1550eca353eSBryant G. Ly queue->msg_token,
1560eca353eSBryant G. Ly queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
1570eca353eSBryant G. Ly free_page((unsigned long)queue->msgs);
1580eca353eSBryant G. Ly }
1590eca353eSBryant G. Ly
1600eca353eSBryant G. Ly /**
1610eca353eSBryant G. Ly * ibmvmc_reset_crq_queue - Reset CRQ Queue
1620eca353eSBryant G. Ly *
1630eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
1640eca353eSBryant G. Ly *
1650eca353eSBryant G. Ly * This function calls h_free_crq and then calls H_REG_CRQ and does all the
1660eca353eSBryant G. Ly * bookkeeping to get us back to where we can communicate.
1670eca353eSBryant G. Ly *
1680eca353eSBryant G. Ly * Return:
1690eca353eSBryant G. Ly * 0 - Success
1700eca353eSBryant G. Ly * Non-Zero - Failure
1710eca353eSBryant G. Ly */
ibmvmc_reset_crq_queue(struct crq_server_adapter * adapter)1720eca353eSBryant G. Ly static int ibmvmc_reset_crq_queue(struct crq_server_adapter *adapter)
1730eca353eSBryant G. Ly {
1740eca353eSBryant G. Ly struct vio_dev *vdev = to_vio_dev(adapter->dev);
1750eca353eSBryant G. Ly struct crq_queue *queue = &adapter->queue;
1760eca353eSBryant G. Ly int rc = 0;
1770eca353eSBryant G. Ly
1780eca353eSBryant G. Ly /* Close the CRQ */
1790eca353eSBryant G. Ly h_free_crq(vdev->unit_address);
1800eca353eSBryant G. Ly
1810eca353eSBryant G. Ly /* Clean out the queue */
1820eca353eSBryant G. Ly memset(queue->msgs, 0x00, PAGE_SIZE);
1830eca353eSBryant G. Ly queue->cur = 0;
1840eca353eSBryant G. Ly
1850eca353eSBryant G. Ly /* And re-open it again */
1860eca353eSBryant G. Ly rc = plpar_hcall_norets(H_REG_CRQ,
1870eca353eSBryant G. Ly vdev->unit_address,
1880eca353eSBryant G. Ly queue->msg_token, PAGE_SIZE);
1890eca353eSBryant G. Ly if (rc == 2)
1900eca353eSBryant G. Ly /* Adapter is good, but other end is not ready */
1910eca353eSBryant G. Ly dev_warn(adapter->dev, "Partner adapter not ready\n");
1920eca353eSBryant G. Ly else if (rc != 0)
1930eca353eSBryant G. Ly dev_err(adapter->dev, "couldn't register crq--rc 0x%x\n", rc);
1940eca353eSBryant G. Ly
1950eca353eSBryant G. Ly return rc;
1960eca353eSBryant G. Ly }
1970eca353eSBryant G. Ly
1980eca353eSBryant G. Ly /**
1990eca353eSBryant G. Ly * crq_queue_next_crq: - Returns the next entry in message queue
2000eca353eSBryant G. Ly * @queue: crq_queue to use
2010eca353eSBryant G. Ly *
2020eca353eSBryant G. Ly * Returns pointer to next entry in queue, or NULL if there are no new
2030eca353eSBryant G. Ly * entried in the CRQ.
2040eca353eSBryant G. Ly */
crq_queue_next_crq(struct crq_queue * queue)2050eca353eSBryant G. Ly static struct ibmvmc_crq_msg *crq_queue_next_crq(struct crq_queue *queue)
2060eca353eSBryant G. Ly {
2070eca353eSBryant G. Ly struct ibmvmc_crq_msg *crq;
2080eca353eSBryant G. Ly unsigned long flags;
2090eca353eSBryant G. Ly
2100eca353eSBryant G. Ly spin_lock_irqsave(&queue->lock, flags);
2110eca353eSBryant G. Ly crq = &queue->msgs[queue->cur];
2120eca353eSBryant G. Ly if (crq->valid & 0x80) {
2130eca353eSBryant G. Ly if (++queue->cur == queue->size)
2140eca353eSBryant G. Ly queue->cur = 0;
2150eca353eSBryant G. Ly
2160eca353eSBryant G. Ly /* Ensure the read of the valid bit occurs before reading any
2170eca353eSBryant G. Ly * other bits of the CRQ entry
2180eca353eSBryant G. Ly */
2190eca353eSBryant G. Ly dma_rmb();
2200eca353eSBryant G. Ly } else {
2210eca353eSBryant G. Ly crq = NULL;
2220eca353eSBryant G. Ly }
2230eca353eSBryant G. Ly
2240eca353eSBryant G. Ly spin_unlock_irqrestore(&queue->lock, flags);
2250eca353eSBryant G. Ly
2260eca353eSBryant G. Ly return crq;
2270eca353eSBryant G. Ly }
2280eca353eSBryant G. Ly
2290eca353eSBryant G. Ly /**
2300eca353eSBryant G. Ly * ibmvmc_send_crq - Send CRQ
2310eca353eSBryant G. Ly *
2320eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
2330eca353eSBryant G. Ly * @word1: Word1 Data field
2340eca353eSBryant G. Ly * @word2: Word2 Data field
2350eca353eSBryant G. Ly *
2360eca353eSBryant G. Ly * Return:
2370eca353eSBryant G. Ly * 0 - Success
2380eca353eSBryant G. Ly * Non-Zero - Failure
2390eca353eSBryant G. Ly */
ibmvmc_send_crq(struct crq_server_adapter * adapter,u64 word1,u64 word2)2400eca353eSBryant G. Ly static long ibmvmc_send_crq(struct crq_server_adapter *adapter,
2410eca353eSBryant G. Ly u64 word1, u64 word2)
2420eca353eSBryant G. Ly {
2430eca353eSBryant G. Ly struct vio_dev *vdev = to_vio_dev(adapter->dev);
2440eca353eSBryant G. Ly long rc = 0;
2450eca353eSBryant G. Ly
2460eca353eSBryant G. Ly dev_dbg(adapter->dev, "(0x%x, 0x%016llx, 0x%016llx)\n",
2470eca353eSBryant G. Ly vdev->unit_address, word1, word2);
2480eca353eSBryant G. Ly
2490eca353eSBryant G. Ly /*
2500eca353eSBryant G. Ly * Ensure the command buffer is flushed to memory before handing it
2510eca353eSBryant G. Ly * over to the other side to prevent it from fetching any stale data.
2520eca353eSBryant G. Ly */
2530eca353eSBryant G. Ly dma_wmb();
2540eca353eSBryant G. Ly rc = plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2);
2550eca353eSBryant G. Ly dev_dbg(adapter->dev, "rc = 0x%lx\n", rc);
2560eca353eSBryant G. Ly
2570eca353eSBryant G. Ly return rc;
2580eca353eSBryant G. Ly }
2590eca353eSBryant G. Ly
2600eca353eSBryant G. Ly /**
2610eca353eSBryant G. Ly * alloc_dma_buffer - Create DMA Buffer
2620eca353eSBryant G. Ly *
2630eca353eSBryant G. Ly * @vdev: vio_dev struct
2640eca353eSBryant G. Ly * @size: Size field
2650eca353eSBryant G. Ly * @dma_handle: DMA address field
2660eca353eSBryant G. Ly *
2670eca353eSBryant G. Ly * Allocates memory for the command queue and maps remote memory into an
2680eca353eSBryant G. Ly * ioba.
2690eca353eSBryant G. Ly *
2700eca353eSBryant G. Ly * Returns a pointer to the buffer
2710eca353eSBryant G. Ly */
alloc_dma_buffer(struct vio_dev * vdev,size_t size,dma_addr_t * dma_handle)2720eca353eSBryant G. Ly static void *alloc_dma_buffer(struct vio_dev *vdev, size_t size,
2730eca353eSBryant G. Ly dma_addr_t *dma_handle)
2740eca353eSBryant G. Ly {
2750eca353eSBryant G. Ly /* allocate memory */
27697b715b6SWei Yongjun void *buffer = kzalloc(size, GFP_ATOMIC);
2770eca353eSBryant G. Ly
2780eca353eSBryant G. Ly if (!buffer) {
2790eca353eSBryant G. Ly *dma_handle = 0;
2800eca353eSBryant G. Ly return NULL;
2810eca353eSBryant G. Ly }
2820eca353eSBryant G. Ly
2830eca353eSBryant G. Ly /* DMA map */
2840eca353eSBryant G. Ly *dma_handle = dma_map_single(&vdev->dev, buffer, size,
2850eca353eSBryant G. Ly DMA_BIDIRECTIONAL);
2860eca353eSBryant G. Ly
2870eca353eSBryant G. Ly if (dma_mapping_error(&vdev->dev, *dma_handle)) {
2880eca353eSBryant G. Ly *dma_handle = 0;
289453431a5SWaiman Long kfree_sensitive(buffer);
2900eca353eSBryant G. Ly return NULL;
2910eca353eSBryant G. Ly }
2920eca353eSBryant G. Ly
2930eca353eSBryant G. Ly return buffer;
2940eca353eSBryant G. Ly }
2950eca353eSBryant G. Ly
2960eca353eSBryant G. Ly /**
2970eca353eSBryant G. Ly * free_dma_buffer - Free DMA Buffer
2980eca353eSBryant G. Ly *
2990eca353eSBryant G. Ly * @vdev: vio_dev struct
3000eca353eSBryant G. Ly * @size: Size field
3010eca353eSBryant G. Ly * @vaddr: Address field
3020eca353eSBryant G. Ly * @dma_handle: DMA address field
3030eca353eSBryant G. Ly *
3040eca353eSBryant G. Ly * Releases memory for a command queue and unmaps mapped remote memory.
3050eca353eSBryant G. Ly */
free_dma_buffer(struct vio_dev * vdev,size_t size,void * vaddr,dma_addr_t dma_handle)3060eca353eSBryant G. Ly static void free_dma_buffer(struct vio_dev *vdev, size_t size, void *vaddr,
3070eca353eSBryant G. Ly dma_addr_t dma_handle)
3080eca353eSBryant G. Ly {
3090eca353eSBryant G. Ly /* DMA unmap */
3100eca353eSBryant G. Ly dma_unmap_single(&vdev->dev, dma_handle, size, DMA_BIDIRECTIONAL);
3110eca353eSBryant G. Ly
3120eca353eSBryant G. Ly /* deallocate memory */
313453431a5SWaiman Long kfree_sensitive(vaddr);
3140eca353eSBryant G. Ly }
3150eca353eSBryant G. Ly
3160eca353eSBryant G. Ly /**
3170eca353eSBryant G. Ly * ibmvmc_get_valid_hmc_buffer - Retrieve Valid HMC Buffer
3180eca353eSBryant G. Ly *
3190eca353eSBryant G. Ly * @hmc_index: HMC Index Field
3200eca353eSBryant G. Ly *
3210eca353eSBryant G. Ly * Return:
3220eca353eSBryant G. Ly * Pointer to ibmvmc_buffer
3230eca353eSBryant G. Ly */
ibmvmc_get_valid_hmc_buffer(u8 hmc_index)3240eca353eSBryant G. Ly static struct ibmvmc_buffer *ibmvmc_get_valid_hmc_buffer(u8 hmc_index)
3250eca353eSBryant G. Ly {
3260eca353eSBryant G. Ly struct ibmvmc_buffer *buffer;
3270eca353eSBryant G. Ly struct ibmvmc_buffer *ret_buf = NULL;
3280eca353eSBryant G. Ly unsigned long i;
3290eca353eSBryant G. Ly
3300eca353eSBryant G. Ly if (hmc_index > ibmvmc.max_hmc_index)
3310eca353eSBryant G. Ly return NULL;
3320eca353eSBryant G. Ly
3330eca353eSBryant G. Ly buffer = hmcs[hmc_index].buffer;
3340eca353eSBryant G. Ly
3350eca353eSBryant G. Ly for (i = 0; i < ibmvmc_max_buf_pool_size; i++) {
3360eca353eSBryant G. Ly if (buffer[i].valid && buffer[i].free &&
3370eca353eSBryant G. Ly buffer[i].owner == VMC_BUF_OWNER_ALPHA) {
3380eca353eSBryant G. Ly buffer[i].free = 0;
3390eca353eSBryant G. Ly ret_buf = &buffer[i];
3400eca353eSBryant G. Ly break;
3410eca353eSBryant G. Ly }
3420eca353eSBryant G. Ly }
3430eca353eSBryant G. Ly
3440eca353eSBryant G. Ly return ret_buf;
3450eca353eSBryant G. Ly }
3460eca353eSBryant G. Ly
3470eca353eSBryant G. Ly /**
3480eca353eSBryant G. Ly * ibmvmc_get_free_hmc_buffer - Get Free HMC Buffer
3490eca353eSBryant G. Ly *
3500eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
3510eca353eSBryant G. Ly * @hmc_index: Hmc Index field
3520eca353eSBryant G. Ly *
3530eca353eSBryant G. Ly * Return:
3540eca353eSBryant G. Ly * Pointer to ibmvmc_buffer
3550eca353eSBryant G. Ly */
ibmvmc_get_free_hmc_buffer(struct crq_server_adapter * adapter,u8 hmc_index)3560eca353eSBryant G. Ly static struct ibmvmc_buffer *ibmvmc_get_free_hmc_buffer(struct crq_server_adapter *adapter,
3570eca353eSBryant G. Ly u8 hmc_index)
3580eca353eSBryant G. Ly {
3590eca353eSBryant G. Ly struct ibmvmc_buffer *buffer;
3600eca353eSBryant G. Ly struct ibmvmc_buffer *ret_buf = NULL;
3610eca353eSBryant G. Ly unsigned long i;
3620eca353eSBryant G. Ly
3630eca353eSBryant G. Ly if (hmc_index > ibmvmc.max_hmc_index) {
3640eca353eSBryant G. Ly dev_info(adapter->dev, "get_free_hmc_buffer: invalid hmc_index=0x%x\n",
3650eca353eSBryant G. Ly hmc_index);
3660eca353eSBryant G. Ly return NULL;
3670eca353eSBryant G. Ly }
3680eca353eSBryant G. Ly
3690eca353eSBryant G. Ly buffer = hmcs[hmc_index].buffer;
3700eca353eSBryant G. Ly
3710eca353eSBryant G. Ly for (i = 0; i < ibmvmc_max_buf_pool_size; i++) {
3720eca353eSBryant G. Ly if (buffer[i].free &&
3730eca353eSBryant G. Ly buffer[i].owner == VMC_BUF_OWNER_ALPHA) {
3740eca353eSBryant G. Ly buffer[i].free = 0;
3750eca353eSBryant G. Ly ret_buf = &buffer[i];
3760eca353eSBryant G. Ly break;
3770eca353eSBryant G. Ly }
3780eca353eSBryant G. Ly }
3790eca353eSBryant G. Ly
3800eca353eSBryant G. Ly return ret_buf;
3810eca353eSBryant G. Ly }
3820eca353eSBryant G. Ly
3830eca353eSBryant G. Ly /**
3840eca353eSBryant G. Ly * ibmvmc_free_hmc_buffer - Free an HMC Buffer
3850eca353eSBryant G. Ly *
3860eca353eSBryant G. Ly * @hmc: ibmvmc_hmc struct
3870eca353eSBryant G. Ly * @buffer: ibmvmc_buffer struct
3880eca353eSBryant G. Ly *
3890eca353eSBryant G. Ly */
ibmvmc_free_hmc_buffer(struct ibmvmc_hmc * hmc,struct ibmvmc_buffer * buffer)3900eca353eSBryant G. Ly static void ibmvmc_free_hmc_buffer(struct ibmvmc_hmc *hmc,
3910eca353eSBryant G. Ly struct ibmvmc_buffer *buffer)
3920eca353eSBryant G. Ly {
3930eca353eSBryant G. Ly unsigned long flags;
3940eca353eSBryant G. Ly
3950eca353eSBryant G. Ly spin_lock_irqsave(&hmc->lock, flags);
3960eca353eSBryant G. Ly buffer->free = 1;
3970eca353eSBryant G. Ly spin_unlock_irqrestore(&hmc->lock, flags);
3980eca353eSBryant G. Ly }
3990eca353eSBryant G. Ly
4000eca353eSBryant G. Ly /**
4010eca353eSBryant G. Ly * ibmvmc_count_hmc_buffers - Count HMC Buffers
4020eca353eSBryant G. Ly *
4030eca353eSBryant G. Ly * @hmc_index: HMC Index field
4040eca353eSBryant G. Ly * @valid: Valid number of buffers field
4050eca353eSBryant G. Ly * @free: Free number of buffers field
4060eca353eSBryant G. Ly *
4070eca353eSBryant G. Ly */
ibmvmc_count_hmc_buffers(u8 hmc_index,unsigned int * valid,unsigned int * free)4080eca353eSBryant G. Ly static void ibmvmc_count_hmc_buffers(u8 hmc_index, unsigned int *valid,
4090eca353eSBryant G. Ly unsigned int *free)
4100eca353eSBryant G. Ly {
4110eca353eSBryant G. Ly struct ibmvmc_buffer *buffer;
4120eca353eSBryant G. Ly unsigned long i;
4130eca353eSBryant G. Ly unsigned long flags;
4140eca353eSBryant G. Ly
4150eca353eSBryant G. Ly if (hmc_index > ibmvmc.max_hmc_index)
4160eca353eSBryant G. Ly return;
4170eca353eSBryant G. Ly
4180eca353eSBryant G. Ly if (!valid || !free)
4190eca353eSBryant G. Ly return;
4200eca353eSBryant G. Ly
4210eca353eSBryant G. Ly *valid = 0; *free = 0;
4220eca353eSBryant G. Ly
4230eca353eSBryant G. Ly buffer = hmcs[hmc_index].buffer;
4240eca353eSBryant G. Ly spin_lock_irqsave(&hmcs[hmc_index].lock, flags);
4250eca353eSBryant G. Ly
4260eca353eSBryant G. Ly for (i = 0; i < ibmvmc_max_buf_pool_size; i++) {
4270eca353eSBryant G. Ly if (buffer[i].valid) {
4280eca353eSBryant G. Ly *valid = *valid + 1;
4290eca353eSBryant G. Ly if (buffer[i].free)
4300eca353eSBryant G. Ly *free = *free + 1;
4310eca353eSBryant G. Ly }
4320eca353eSBryant G. Ly }
4330eca353eSBryant G. Ly
4340eca353eSBryant G. Ly spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags);
4350eca353eSBryant G. Ly }
4360eca353eSBryant G. Ly
4370eca353eSBryant G. Ly /**
4380eca353eSBryant G. Ly * ibmvmc_get_free_hmc - Get Free HMC
4390eca353eSBryant G. Ly *
4400eca353eSBryant G. Ly * Return:
4410eca353eSBryant G. Ly * Pointer to an available HMC Connection
4420eca353eSBryant G. Ly * Null otherwise
4430eca353eSBryant G. Ly */
ibmvmc_get_free_hmc(void)4440eca353eSBryant G. Ly static struct ibmvmc_hmc *ibmvmc_get_free_hmc(void)
4450eca353eSBryant G. Ly {
4460eca353eSBryant G. Ly unsigned long i;
4470eca353eSBryant G. Ly unsigned long flags;
4480eca353eSBryant G. Ly
4490eca353eSBryant G. Ly /*
4500eca353eSBryant G. Ly * Find an available HMC connection.
4510eca353eSBryant G. Ly */
4520eca353eSBryant G. Ly for (i = 0; i <= ibmvmc.max_hmc_index; i++) {
4530eca353eSBryant G. Ly spin_lock_irqsave(&hmcs[i].lock, flags);
4540eca353eSBryant G. Ly if (hmcs[i].state == ibmhmc_state_free) {
4550eca353eSBryant G. Ly hmcs[i].index = i;
4560eca353eSBryant G. Ly hmcs[i].state = ibmhmc_state_initial;
4570eca353eSBryant G. Ly spin_unlock_irqrestore(&hmcs[i].lock, flags);
4580eca353eSBryant G. Ly return &hmcs[i];
4590eca353eSBryant G. Ly }
4600eca353eSBryant G. Ly spin_unlock_irqrestore(&hmcs[i].lock, flags);
4610eca353eSBryant G. Ly }
4620eca353eSBryant G. Ly
4630eca353eSBryant G. Ly return NULL;
4640eca353eSBryant G. Ly }
4650eca353eSBryant G. Ly
4660eca353eSBryant G. Ly /**
4670eca353eSBryant G. Ly * ibmvmc_return_hmc - Return an HMC Connection
4680eca353eSBryant G. Ly *
4690eca353eSBryant G. Ly * @hmc: ibmvmc_hmc struct
4700eca353eSBryant G. Ly * @release_readers: Number of readers connected to session
4710eca353eSBryant G. Ly *
4720eca353eSBryant G. Ly * This function releases the HMC connections back into the pool.
4730eca353eSBryant G. Ly *
4740eca353eSBryant G. Ly * Return:
4750eca353eSBryant G. Ly * 0 - Success
4760eca353eSBryant G. Ly * Non-zero - Failure
4770eca353eSBryant G. Ly */
ibmvmc_return_hmc(struct ibmvmc_hmc * hmc,bool release_readers)4780eca353eSBryant G. Ly static int ibmvmc_return_hmc(struct ibmvmc_hmc *hmc, bool release_readers)
4790eca353eSBryant G. Ly {
4800eca353eSBryant G. Ly struct ibmvmc_buffer *buffer;
4810eca353eSBryant G. Ly struct crq_server_adapter *adapter;
4820eca353eSBryant G. Ly struct vio_dev *vdev;
4830eca353eSBryant G. Ly unsigned long i;
4840eca353eSBryant G. Ly unsigned long flags;
4850eca353eSBryant G. Ly
4860eca353eSBryant G. Ly if (!hmc || !hmc->adapter)
4870eca353eSBryant G. Ly return -EIO;
4880eca353eSBryant G. Ly
4890eca353eSBryant G. Ly if (release_readers) {
4900eca353eSBryant G. Ly if (hmc->file_session) {
4910eca353eSBryant G. Ly struct ibmvmc_file_session *session = hmc->file_session;
4920eca353eSBryant G. Ly
4930eca353eSBryant G. Ly session->valid = 0;
4940eca353eSBryant G. Ly wake_up_interruptible(&ibmvmc_read_wait);
4950eca353eSBryant G. Ly }
4960eca353eSBryant G. Ly }
4970eca353eSBryant G. Ly
4980eca353eSBryant G. Ly adapter = hmc->adapter;
4990eca353eSBryant G. Ly vdev = to_vio_dev(adapter->dev);
5000eca353eSBryant G. Ly
5010eca353eSBryant G. Ly spin_lock_irqsave(&hmc->lock, flags);
5020eca353eSBryant G. Ly hmc->index = 0;
5030eca353eSBryant G. Ly hmc->state = ibmhmc_state_free;
5040eca353eSBryant G. Ly hmc->queue_head = 0;
5050eca353eSBryant G. Ly hmc->queue_tail = 0;
5060eca353eSBryant G. Ly buffer = hmc->buffer;
5070eca353eSBryant G. Ly for (i = 0; i < ibmvmc_max_buf_pool_size; i++) {
5080eca353eSBryant G. Ly if (buffer[i].valid) {
5090eca353eSBryant G. Ly free_dma_buffer(vdev,
5100eca353eSBryant G. Ly ibmvmc.max_mtu,
5110eca353eSBryant G. Ly buffer[i].real_addr_local,
5120eca353eSBryant G. Ly buffer[i].dma_addr_local);
5130eca353eSBryant G. Ly dev_dbg(adapter->dev, "Forgot buffer id 0x%lx\n", i);
5140eca353eSBryant G. Ly }
5150eca353eSBryant G. Ly memset(&buffer[i], 0, sizeof(struct ibmvmc_buffer));
5160eca353eSBryant G. Ly
5170eca353eSBryant G. Ly hmc->queue_outbound_msgs[i] = VMC_INVALID_BUFFER_ID;
5180eca353eSBryant G. Ly }
5190eca353eSBryant G. Ly
5200eca353eSBryant G. Ly spin_unlock_irqrestore(&hmc->lock, flags);
5210eca353eSBryant G. Ly
5220eca353eSBryant G. Ly return 0;
5230eca353eSBryant G. Ly }
5240eca353eSBryant G. Ly
5250eca353eSBryant G. Ly /**
5260eca353eSBryant G. Ly * ibmvmc_send_open - Interface Open
5270eca353eSBryant G. Ly * @buffer: Pointer to ibmvmc_buffer struct
5280eca353eSBryant G. Ly * @hmc: Pointer to ibmvmc_hmc struct
5290eca353eSBryant G. Ly *
5300eca353eSBryant G. Ly * This command is sent by the management partition as the result of a
5310eca353eSBryant G. Ly * management partition device request. It causes the hypervisor to
5320eca353eSBryant G. Ly * prepare a set of data buffers for the management application connection
5330eca353eSBryant G. Ly * indicated HMC idx. A unique HMC Idx would be used if multiple management
5340eca353eSBryant G. Ly * applications running concurrently were desired. Before responding to this
5350eca353eSBryant G. Ly * command, the hypervisor must provide the management partition with at
5360eca353eSBryant G. Ly * least one of these new buffers via the Add Buffer. This indicates whether
5370eca353eSBryant G. Ly * the messages are inbound or outbound from the hypervisor.
5380eca353eSBryant G. Ly *
5390eca353eSBryant G. Ly * Return:
5400eca353eSBryant G. Ly * 0 - Success
5410eca353eSBryant G. Ly * Non-zero - Failure
5420eca353eSBryant G. Ly */
ibmvmc_send_open(struct ibmvmc_buffer * buffer,struct ibmvmc_hmc * hmc)5430eca353eSBryant G. Ly static int ibmvmc_send_open(struct ibmvmc_buffer *buffer,
5440eca353eSBryant G. Ly struct ibmvmc_hmc *hmc)
5450eca353eSBryant G. Ly {
5460eca353eSBryant G. Ly struct ibmvmc_crq_msg crq_msg;
5470eca353eSBryant G. Ly struct crq_server_adapter *adapter;
5480eca353eSBryant G. Ly __be64 *crq_as_u64 = (__be64 *)&crq_msg;
5490eca353eSBryant G. Ly int rc = 0;
5500eca353eSBryant G. Ly
5510eca353eSBryant G. Ly if (!hmc || !hmc->adapter)
5520eca353eSBryant G. Ly return -EIO;
5530eca353eSBryant G. Ly
5540eca353eSBryant G. Ly adapter = hmc->adapter;
5550eca353eSBryant G. Ly
5560eca353eSBryant G. Ly dev_dbg(adapter->dev, "send_open: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
5570eca353eSBryant G. Ly (unsigned long)buffer->size, (unsigned long)adapter->liobn,
5580eca353eSBryant G. Ly (unsigned long)buffer->dma_addr_local,
5590eca353eSBryant G. Ly (unsigned long)adapter->riobn,
5600eca353eSBryant G. Ly (unsigned long)buffer->dma_addr_remote);
5610eca353eSBryant G. Ly
5620eca353eSBryant G. Ly rc = h_copy_rdma(buffer->size,
5630eca353eSBryant G. Ly adapter->liobn,
5640eca353eSBryant G. Ly buffer->dma_addr_local,
5650eca353eSBryant G. Ly adapter->riobn,
5660eca353eSBryant G. Ly buffer->dma_addr_remote);
5670eca353eSBryant G. Ly if (rc) {
5680eca353eSBryant G. Ly dev_err(adapter->dev, "Error: In send_open, h_copy_rdma rc 0x%x\n",
5690eca353eSBryant G. Ly rc);
5700eca353eSBryant G. Ly return -EIO;
5710eca353eSBryant G. Ly }
5720eca353eSBryant G. Ly
5730eca353eSBryant G. Ly hmc->state = ibmhmc_state_opening;
5740eca353eSBryant G. Ly
5750eca353eSBryant G. Ly crq_msg.valid = 0x80;
5760eca353eSBryant G. Ly crq_msg.type = VMC_MSG_OPEN;
5770eca353eSBryant G. Ly crq_msg.status = 0;
5780eca353eSBryant G. Ly crq_msg.var1.rsvd = 0;
5790eca353eSBryant G. Ly crq_msg.hmc_session = hmc->session;
5800eca353eSBryant G. Ly crq_msg.hmc_index = hmc->index;
5810eca353eSBryant G. Ly crq_msg.var2.buffer_id = cpu_to_be16(buffer->id);
5820eca353eSBryant G. Ly crq_msg.rsvd = 0;
5830eca353eSBryant G. Ly crq_msg.var3.rsvd = 0;
5840eca353eSBryant G. Ly
5850eca353eSBryant G. Ly ibmvmc_send_crq(adapter, be64_to_cpu(crq_as_u64[0]),
5860eca353eSBryant G. Ly be64_to_cpu(crq_as_u64[1]));
5870eca353eSBryant G. Ly
5880eca353eSBryant G. Ly return rc;
5890eca353eSBryant G. Ly }
5900eca353eSBryant G. Ly
5910eca353eSBryant G. Ly /**
5920eca353eSBryant G. Ly * ibmvmc_send_close - Interface Close
5930eca353eSBryant G. Ly * @hmc: Pointer to ibmvmc_hmc struct
5940eca353eSBryant G. Ly *
5950eca353eSBryant G. Ly * This command is sent by the management partition to terminate a
5960eca353eSBryant G. Ly * management application to hypervisor connection. When this command is
5970eca353eSBryant G. Ly * sent, the management partition has quiesced all I/O operations to all
5980eca353eSBryant G. Ly * buffers associated with this management application connection, and
5990eca353eSBryant G. Ly * has freed any storage for these buffers.
6000eca353eSBryant G. Ly *
6010eca353eSBryant G. Ly * Return:
6020eca353eSBryant G. Ly * 0 - Success
6030eca353eSBryant G. Ly * Non-zero - Failure
6040eca353eSBryant G. Ly */
ibmvmc_send_close(struct ibmvmc_hmc * hmc)6050eca353eSBryant G. Ly static int ibmvmc_send_close(struct ibmvmc_hmc *hmc)
6060eca353eSBryant G. Ly {
6070eca353eSBryant G. Ly struct ibmvmc_crq_msg crq_msg;
6080eca353eSBryant G. Ly struct crq_server_adapter *adapter;
6090eca353eSBryant G. Ly __be64 *crq_as_u64 = (__be64 *)&crq_msg;
6100eca353eSBryant G. Ly int rc = 0;
6110eca353eSBryant G. Ly
6120eca353eSBryant G. Ly if (!hmc || !hmc->adapter)
6130eca353eSBryant G. Ly return -EIO;
6140eca353eSBryant G. Ly
6150eca353eSBryant G. Ly adapter = hmc->adapter;
6160eca353eSBryant G. Ly
6170eca353eSBryant G. Ly dev_info(adapter->dev, "CRQ send: close\n");
6180eca353eSBryant G. Ly
6190eca353eSBryant G. Ly crq_msg.valid = 0x80;
6200eca353eSBryant G. Ly crq_msg.type = VMC_MSG_CLOSE;
6210eca353eSBryant G. Ly crq_msg.status = 0;
6220eca353eSBryant G. Ly crq_msg.var1.rsvd = 0;
6230eca353eSBryant G. Ly crq_msg.hmc_session = hmc->session;
6240eca353eSBryant G. Ly crq_msg.hmc_index = hmc->index;
6250eca353eSBryant G. Ly crq_msg.var2.rsvd = 0;
6260eca353eSBryant G. Ly crq_msg.rsvd = 0;
6270eca353eSBryant G. Ly crq_msg.var3.rsvd = 0;
6280eca353eSBryant G. Ly
6290eca353eSBryant G. Ly ibmvmc_send_crq(adapter, be64_to_cpu(crq_as_u64[0]),
6300eca353eSBryant G. Ly be64_to_cpu(crq_as_u64[1]));
6310eca353eSBryant G. Ly
6320eca353eSBryant G. Ly return rc;
6330eca353eSBryant G. Ly }
6340eca353eSBryant G. Ly
6350eca353eSBryant G. Ly /**
6360eca353eSBryant G. Ly * ibmvmc_send_capabilities - Send VMC Capabilities
6370eca353eSBryant G. Ly *
6380eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
6390eca353eSBryant G. Ly *
6400eca353eSBryant G. Ly * The capabilities message is an administrative message sent after the CRQ
6410eca353eSBryant G. Ly * initialization sequence of messages and is used to exchange VMC capabilities
6420eca353eSBryant G. Ly * between the management partition and the hypervisor. The management
6430eca353eSBryant G. Ly * partition must send this message and the hypervisor must respond with VMC
6440eca353eSBryant G. Ly * capabilities Response message before HMC interface message can begin. Any
6450eca353eSBryant G. Ly * HMC interface messages received before the exchange of capabilities has
6460eca353eSBryant G. Ly * complete are dropped.
6470eca353eSBryant G. Ly *
6480eca353eSBryant G. Ly * Return:
6490eca353eSBryant G. Ly * 0 - Success
6500eca353eSBryant G. Ly */
ibmvmc_send_capabilities(struct crq_server_adapter * adapter)6510eca353eSBryant G. Ly static int ibmvmc_send_capabilities(struct crq_server_adapter *adapter)
6520eca353eSBryant G. Ly {
6530eca353eSBryant G. Ly struct ibmvmc_admin_crq_msg crq_msg;
6540eca353eSBryant G. Ly __be64 *crq_as_u64 = (__be64 *)&crq_msg;
6550eca353eSBryant G. Ly
6560eca353eSBryant G. Ly dev_dbg(adapter->dev, "ibmvmc: CRQ send: capabilities\n");
6570eca353eSBryant G. Ly crq_msg.valid = 0x80;
6580eca353eSBryant G. Ly crq_msg.type = VMC_MSG_CAP;
6590eca353eSBryant G. Ly crq_msg.status = 0;
6600eca353eSBryant G. Ly crq_msg.rsvd[0] = 0;
6610eca353eSBryant G. Ly crq_msg.rsvd[1] = 0;
6620eca353eSBryant G. Ly crq_msg.max_hmc = ibmvmc_max_hmcs;
6630eca353eSBryant G. Ly crq_msg.max_mtu = cpu_to_be32(ibmvmc_max_mtu);
6640eca353eSBryant G. Ly crq_msg.pool_size = cpu_to_be16(ibmvmc_max_buf_pool_size);
6650eca353eSBryant G. Ly crq_msg.crq_size = cpu_to_be16(adapter->queue.size);
6660eca353eSBryant G. Ly crq_msg.version = cpu_to_be16(IBMVMC_PROTOCOL_VERSION);
6670eca353eSBryant G. Ly
6680eca353eSBryant G. Ly ibmvmc_send_crq(adapter, be64_to_cpu(crq_as_u64[0]),
6690eca353eSBryant G. Ly be64_to_cpu(crq_as_u64[1]));
6700eca353eSBryant G. Ly
6710eca353eSBryant G. Ly ibmvmc.state = ibmvmc_state_capabilities;
6720eca353eSBryant G. Ly
6730eca353eSBryant G. Ly return 0;
6740eca353eSBryant G. Ly }
6750eca353eSBryant G. Ly
6760eca353eSBryant G. Ly /**
6770eca353eSBryant G. Ly * ibmvmc_send_add_buffer_resp - Add Buffer Response
6780eca353eSBryant G. Ly *
6790eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
6800eca353eSBryant G. Ly * @status: Status field
6810eca353eSBryant G. Ly * @hmc_session: HMC Session field
6820eca353eSBryant G. Ly * @hmc_index: HMC Index field
6830eca353eSBryant G. Ly * @buffer_id: Buffer Id field
6840eca353eSBryant G. Ly *
6850eca353eSBryant G. Ly * This command is sent by the management partition to the hypervisor in
6860eca353eSBryant G. Ly * response to the Add Buffer message. The Status field indicates the result of
6870eca353eSBryant G. Ly * the command.
6880eca353eSBryant G. Ly *
6890eca353eSBryant G. Ly * Return:
6900eca353eSBryant G. Ly * 0 - Success
6910eca353eSBryant G. Ly */
ibmvmc_send_add_buffer_resp(struct crq_server_adapter * adapter,u8 status,u8 hmc_session,u8 hmc_index,u16 buffer_id)6920eca353eSBryant G. Ly static int ibmvmc_send_add_buffer_resp(struct crq_server_adapter *adapter,
6930eca353eSBryant G. Ly u8 status, u8 hmc_session,
6940eca353eSBryant G. Ly u8 hmc_index, u16 buffer_id)
6950eca353eSBryant G. Ly {
6960eca353eSBryant G. Ly struct ibmvmc_crq_msg crq_msg;
6970eca353eSBryant G. Ly __be64 *crq_as_u64 = (__be64 *)&crq_msg;
6980eca353eSBryant G. Ly
6990eca353eSBryant G. Ly dev_dbg(adapter->dev, "CRQ send: add_buffer_resp\n");
7000eca353eSBryant G. Ly crq_msg.valid = 0x80;
7010eca353eSBryant G. Ly crq_msg.type = VMC_MSG_ADD_BUF_RESP;
7020eca353eSBryant G. Ly crq_msg.status = status;
7030eca353eSBryant G. Ly crq_msg.var1.rsvd = 0;
7040eca353eSBryant G. Ly crq_msg.hmc_session = hmc_session;
7050eca353eSBryant G. Ly crq_msg.hmc_index = hmc_index;
7060eca353eSBryant G. Ly crq_msg.var2.buffer_id = cpu_to_be16(buffer_id);
7070eca353eSBryant G. Ly crq_msg.rsvd = 0;
7080eca353eSBryant G. Ly crq_msg.var3.rsvd = 0;
7090eca353eSBryant G. Ly
7100eca353eSBryant G. Ly ibmvmc_send_crq(adapter, be64_to_cpu(crq_as_u64[0]),
7110eca353eSBryant G. Ly be64_to_cpu(crq_as_u64[1]));
7120eca353eSBryant G. Ly
7130eca353eSBryant G. Ly return 0;
7140eca353eSBryant G. Ly }
7150eca353eSBryant G. Ly
7160eca353eSBryant G. Ly /**
7170eca353eSBryant G. Ly * ibmvmc_send_rem_buffer_resp - Remove Buffer Response
7180eca353eSBryant G. Ly *
7190eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
7200eca353eSBryant G. Ly * @status: Status field
7210eca353eSBryant G. Ly * @hmc_session: HMC Session field
7220eca353eSBryant G. Ly * @hmc_index: HMC Index field
7230eca353eSBryant G. Ly * @buffer_id: Buffer Id field
7240eca353eSBryant G. Ly *
7250eca353eSBryant G. Ly * This command is sent by the management partition to the hypervisor in
7260eca353eSBryant G. Ly * response to the Remove Buffer message. The Buffer ID field indicates
7270eca353eSBryant G. Ly * which buffer the management partition selected to remove. The Status
7280eca353eSBryant G. Ly * field indicates the result of the command.
7290eca353eSBryant G. Ly *
7300eca353eSBryant G. Ly * Return:
7310eca353eSBryant G. Ly * 0 - Success
7320eca353eSBryant G. Ly */
ibmvmc_send_rem_buffer_resp(struct crq_server_adapter * adapter,u8 status,u8 hmc_session,u8 hmc_index,u16 buffer_id)7330eca353eSBryant G. Ly static int ibmvmc_send_rem_buffer_resp(struct crq_server_adapter *adapter,
7340eca353eSBryant G. Ly u8 status, u8 hmc_session,
7350eca353eSBryant G. Ly u8 hmc_index, u16 buffer_id)
7360eca353eSBryant G. Ly {
7370eca353eSBryant G. Ly struct ibmvmc_crq_msg crq_msg;
7380eca353eSBryant G. Ly __be64 *crq_as_u64 = (__be64 *)&crq_msg;
7390eca353eSBryant G. Ly
7400eca353eSBryant G. Ly dev_dbg(adapter->dev, "CRQ send: rem_buffer_resp\n");
7410eca353eSBryant G. Ly crq_msg.valid = 0x80;
7420eca353eSBryant G. Ly crq_msg.type = VMC_MSG_REM_BUF_RESP;
7430eca353eSBryant G. Ly crq_msg.status = status;
7440eca353eSBryant G. Ly crq_msg.var1.rsvd = 0;
7450eca353eSBryant G. Ly crq_msg.hmc_session = hmc_session;
7460eca353eSBryant G. Ly crq_msg.hmc_index = hmc_index;
7470eca353eSBryant G. Ly crq_msg.var2.buffer_id = cpu_to_be16(buffer_id);
7480eca353eSBryant G. Ly crq_msg.rsvd = 0;
7490eca353eSBryant G. Ly crq_msg.var3.rsvd = 0;
7500eca353eSBryant G. Ly
7510eca353eSBryant G. Ly ibmvmc_send_crq(adapter, be64_to_cpu(crq_as_u64[0]),
7520eca353eSBryant G. Ly be64_to_cpu(crq_as_u64[1]));
7530eca353eSBryant G. Ly
7540eca353eSBryant G. Ly return 0;
7550eca353eSBryant G. Ly }
7560eca353eSBryant G. Ly
7570eca353eSBryant G. Ly /**
7580eca353eSBryant G. Ly * ibmvmc_send_msg - Signal Message
7590eca353eSBryant G. Ly *
7600eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
7610eca353eSBryant G. Ly * @buffer: ibmvmc_buffer struct
7620eca353eSBryant G. Ly * @hmc: ibmvmc_hmc struct
76318248659SLee Jones * @msg_len: message length field
7640eca353eSBryant G. Ly *
7650eca353eSBryant G. Ly * This command is sent between the management partition and the hypervisor
7660eca353eSBryant G. Ly * in order to signal the arrival of an HMC protocol message. The command
7670eca353eSBryant G. Ly * can be sent by both the management partition and the hypervisor. It is
7680eca353eSBryant G. Ly * used for all traffic between the management application and the hypervisor,
7690eca353eSBryant G. Ly * regardless of who initiated the communication.
7700eca353eSBryant G. Ly *
7710eca353eSBryant G. Ly * There is no response to this message.
7720eca353eSBryant G. Ly *
7730eca353eSBryant G. Ly * Return:
7740eca353eSBryant G. Ly * 0 - Success
7750eca353eSBryant G. Ly * Non-zero - Failure
7760eca353eSBryant G. Ly */
ibmvmc_send_msg(struct crq_server_adapter * adapter,struct ibmvmc_buffer * buffer,struct ibmvmc_hmc * hmc,int msg_len)7770eca353eSBryant G. Ly static int ibmvmc_send_msg(struct crq_server_adapter *adapter,
7780eca353eSBryant G. Ly struct ibmvmc_buffer *buffer,
7790eca353eSBryant G. Ly struct ibmvmc_hmc *hmc, int msg_len)
7800eca353eSBryant G. Ly {
7810eca353eSBryant G. Ly struct ibmvmc_crq_msg crq_msg;
7820eca353eSBryant G. Ly __be64 *crq_as_u64 = (__be64 *)&crq_msg;
7830eca353eSBryant G. Ly int rc = 0;
7840eca353eSBryant G. Ly
7850eca353eSBryant G. Ly dev_dbg(adapter->dev, "CRQ send: rdma to HV\n");
7860eca353eSBryant G. Ly rc = h_copy_rdma(msg_len,
7870eca353eSBryant G. Ly adapter->liobn,
7880eca353eSBryant G. Ly buffer->dma_addr_local,
7890eca353eSBryant G. Ly adapter->riobn,
7900eca353eSBryant G. Ly buffer->dma_addr_remote);
7910eca353eSBryant G. Ly if (rc) {
7920eca353eSBryant G. Ly dev_err(adapter->dev, "Error in send_msg, h_copy_rdma rc 0x%x\n",
7930eca353eSBryant G. Ly rc);
7940eca353eSBryant G. Ly return rc;
7950eca353eSBryant G. Ly }
7960eca353eSBryant G. Ly
7970eca353eSBryant G. Ly crq_msg.valid = 0x80;
7980eca353eSBryant G. Ly crq_msg.type = VMC_MSG_SIGNAL;
7990eca353eSBryant G. Ly crq_msg.status = 0;
8000eca353eSBryant G. Ly crq_msg.var1.rsvd = 0;
8010eca353eSBryant G. Ly crq_msg.hmc_session = hmc->session;
8020eca353eSBryant G. Ly crq_msg.hmc_index = hmc->index;
8030eca353eSBryant G. Ly crq_msg.var2.buffer_id = cpu_to_be16(buffer->id);
8040eca353eSBryant G. Ly crq_msg.var3.msg_len = cpu_to_be32(msg_len);
8050eca353eSBryant G. Ly dev_dbg(adapter->dev, "CRQ send: msg to HV 0x%llx 0x%llx\n",
8060eca353eSBryant G. Ly be64_to_cpu(crq_as_u64[0]), be64_to_cpu(crq_as_u64[1]));
8070eca353eSBryant G. Ly
8080eca353eSBryant G. Ly buffer->owner = VMC_BUF_OWNER_HV;
8090eca353eSBryant G. Ly ibmvmc_send_crq(adapter, be64_to_cpu(crq_as_u64[0]),
8100eca353eSBryant G. Ly be64_to_cpu(crq_as_u64[1]));
8110eca353eSBryant G. Ly
8120eca353eSBryant G. Ly return rc;
8130eca353eSBryant G. Ly }
8140eca353eSBryant G. Ly
8150eca353eSBryant G. Ly /**
8160eca353eSBryant G. Ly * ibmvmc_open - Open Session
8170eca353eSBryant G. Ly *
8180eca353eSBryant G. Ly * @inode: inode struct
8190eca353eSBryant G. Ly * @file: file struct
8200eca353eSBryant G. Ly *
8210eca353eSBryant G. Ly * Return:
8220eca353eSBryant G. Ly * 0 - Success
823e25df781SGustavo A. R. Silva * Non-zero - Failure
8240eca353eSBryant G. Ly */
ibmvmc_open(struct inode * inode,struct file * file)8250eca353eSBryant G. Ly static int ibmvmc_open(struct inode *inode, struct file *file)
8260eca353eSBryant G. Ly {
8270eca353eSBryant G. Ly struct ibmvmc_file_session *session;
8280eca353eSBryant G. Ly
8290eca353eSBryant G. Ly pr_debug("%s: inode = 0x%lx, file = 0x%lx, state = 0x%x\n", __func__,
8300eca353eSBryant G. Ly (unsigned long)inode, (unsigned long)file,
8310eca353eSBryant G. Ly ibmvmc.state);
8320eca353eSBryant G. Ly
8330eca353eSBryant G. Ly session = kzalloc(sizeof(*session), GFP_KERNEL);
834e25df781SGustavo A. R. Silva if (!session)
835e25df781SGustavo A. R. Silva return -ENOMEM;
836e25df781SGustavo A. R. Silva
8370eca353eSBryant G. Ly session->file = file;
8380eca353eSBryant G. Ly file->private_data = session;
8390eca353eSBryant G. Ly
840e25df781SGustavo A. R. Silva return 0;
8410eca353eSBryant G. Ly }
8420eca353eSBryant G. Ly
8430eca353eSBryant G. Ly /**
8440eca353eSBryant G. Ly * ibmvmc_close - Close Session
8450eca353eSBryant G. Ly *
8460eca353eSBryant G. Ly * @inode: inode struct
8470eca353eSBryant G. Ly * @file: file struct
8480eca353eSBryant G. Ly *
8490eca353eSBryant G. Ly * Return:
8500eca353eSBryant G. Ly * 0 - Success
8510eca353eSBryant G. Ly * Non-zero - Failure
8520eca353eSBryant G. Ly */
ibmvmc_close(struct inode * inode,struct file * file)8530eca353eSBryant G. Ly static int ibmvmc_close(struct inode *inode, struct file *file)
8540eca353eSBryant G. Ly {
8550eca353eSBryant G. Ly struct ibmvmc_file_session *session;
8560eca353eSBryant G. Ly struct ibmvmc_hmc *hmc;
8570eca353eSBryant G. Ly int rc = 0;
8580eca353eSBryant G. Ly unsigned long flags;
8590eca353eSBryant G. Ly
8600eca353eSBryant G. Ly pr_debug("%s: file = 0x%lx, state = 0x%x\n", __func__,
8610eca353eSBryant G. Ly (unsigned long)file, ibmvmc.state);
8620eca353eSBryant G. Ly
8630eca353eSBryant G. Ly session = file->private_data;
8640eca353eSBryant G. Ly if (!session)
8650eca353eSBryant G. Ly return -EIO;
8660eca353eSBryant G. Ly
8670eca353eSBryant G. Ly hmc = session->hmc;
8680eca353eSBryant G. Ly if (hmc) {
8690eca353eSBryant G. Ly if (!hmc->adapter)
8700eca353eSBryant G. Ly return -EIO;
8710eca353eSBryant G. Ly
8720eca353eSBryant G. Ly if (ibmvmc.state == ibmvmc_state_failed) {
8730eca353eSBryant G. Ly dev_warn(hmc->adapter->dev, "close: state_failed\n");
8740eca353eSBryant G. Ly return -EIO;
8750eca353eSBryant G. Ly }
8760eca353eSBryant G. Ly
8770eca353eSBryant G. Ly spin_lock_irqsave(&hmc->lock, flags);
8780eca353eSBryant G. Ly if (hmc->state >= ibmhmc_state_opening) {
8790eca353eSBryant G. Ly rc = ibmvmc_send_close(hmc);
8800eca353eSBryant G. Ly if (rc)
8810eca353eSBryant G. Ly dev_warn(hmc->adapter->dev, "close: send_close failed.\n");
8820eca353eSBryant G. Ly }
8830eca353eSBryant G. Ly spin_unlock_irqrestore(&hmc->lock, flags);
8840eca353eSBryant G. Ly }
8850eca353eSBryant G. Ly
886453431a5SWaiman Long kfree_sensitive(session);
8870eca353eSBryant G. Ly
8880eca353eSBryant G. Ly return rc;
8890eca353eSBryant G. Ly }
8900eca353eSBryant G. Ly
8910eca353eSBryant G. Ly /**
8920eca353eSBryant G. Ly * ibmvmc_read - Read
8930eca353eSBryant G. Ly *
8940eca353eSBryant G. Ly * @file: file struct
8950eca353eSBryant G. Ly * @buf: Character buffer
8960eca353eSBryant G. Ly * @nbytes: Size in bytes
8970eca353eSBryant G. Ly * @ppos: Offset
8980eca353eSBryant G. Ly *
8990eca353eSBryant G. Ly * Return:
9000eca353eSBryant G. Ly * 0 - Success
9010eca353eSBryant G. Ly * Non-zero - Failure
9020eca353eSBryant G. Ly */
ibmvmc_read(struct file * file,char * buf,size_t nbytes,loff_t * ppos)9030eca353eSBryant G. Ly static ssize_t ibmvmc_read(struct file *file, char *buf, size_t nbytes,
9040eca353eSBryant G. Ly loff_t *ppos)
9050eca353eSBryant G. Ly {
9060eca353eSBryant G. Ly struct ibmvmc_file_session *session;
9070eca353eSBryant G. Ly struct ibmvmc_hmc *hmc;
9080eca353eSBryant G. Ly struct crq_server_adapter *adapter;
9090eca353eSBryant G. Ly struct ibmvmc_buffer *buffer;
9100eca353eSBryant G. Ly ssize_t n;
9110eca353eSBryant G. Ly ssize_t retval = 0;
9120eca353eSBryant G. Ly unsigned long flags;
9130eca353eSBryant G. Ly DEFINE_WAIT(wait);
9140eca353eSBryant G. Ly
9150eca353eSBryant G. Ly pr_debug("ibmvmc: read: file = 0x%lx, buf = 0x%lx, nbytes = 0x%lx\n",
9160eca353eSBryant G. Ly (unsigned long)file, (unsigned long)buf,
9170eca353eSBryant G. Ly (unsigned long)nbytes);
9180eca353eSBryant G. Ly
9190eca353eSBryant G. Ly if (nbytes == 0)
9200eca353eSBryant G. Ly return 0;
9210eca353eSBryant G. Ly
9220eca353eSBryant G. Ly if (nbytes > ibmvmc.max_mtu) {
9230eca353eSBryant G. Ly pr_warn("ibmvmc: read: nbytes invalid 0x%x\n",
9240eca353eSBryant G. Ly (unsigned int)nbytes);
9250eca353eSBryant G. Ly return -EINVAL;
9260eca353eSBryant G. Ly }
9270eca353eSBryant G. Ly
9280eca353eSBryant G. Ly session = file->private_data;
9290eca353eSBryant G. Ly if (!session) {
9300eca353eSBryant G. Ly pr_warn("ibmvmc: read: no session\n");
9310eca353eSBryant G. Ly return -EIO;
9320eca353eSBryant G. Ly }
9330eca353eSBryant G. Ly
9340eca353eSBryant G. Ly hmc = session->hmc;
9350eca353eSBryant G. Ly if (!hmc) {
9360eca353eSBryant G. Ly pr_warn("ibmvmc: read: no hmc\n");
9370eca353eSBryant G. Ly return -EIO;
9380eca353eSBryant G. Ly }
9390eca353eSBryant G. Ly
9400eca353eSBryant G. Ly adapter = hmc->adapter;
9410eca353eSBryant G. Ly if (!adapter) {
9420eca353eSBryant G. Ly pr_warn("ibmvmc: read: no adapter\n");
9430eca353eSBryant G. Ly return -EIO;
9440eca353eSBryant G. Ly }
9450eca353eSBryant G. Ly
9460eca353eSBryant G. Ly do {
9470eca353eSBryant G. Ly prepare_to_wait(&ibmvmc_read_wait, &wait, TASK_INTERRUPTIBLE);
9480eca353eSBryant G. Ly
9490eca353eSBryant G. Ly spin_lock_irqsave(&hmc->lock, flags);
9500eca353eSBryant G. Ly if (hmc->queue_tail != hmc->queue_head)
9510eca353eSBryant G. Ly /* Data is available */
9520eca353eSBryant G. Ly break;
9530eca353eSBryant G. Ly
9540eca353eSBryant G. Ly spin_unlock_irqrestore(&hmc->lock, flags);
9550eca353eSBryant G. Ly
9560eca353eSBryant G. Ly if (!session->valid) {
9570eca353eSBryant G. Ly retval = -EBADFD;
9580eca353eSBryant G. Ly goto out;
9590eca353eSBryant G. Ly }
9600eca353eSBryant G. Ly if (file->f_flags & O_NONBLOCK) {
9610eca353eSBryant G. Ly retval = -EAGAIN;
9620eca353eSBryant G. Ly goto out;
9630eca353eSBryant G. Ly }
9640eca353eSBryant G. Ly
9650eca353eSBryant G. Ly schedule();
9660eca353eSBryant G. Ly
9670eca353eSBryant G. Ly if (signal_pending(current)) {
9680eca353eSBryant G. Ly retval = -ERESTARTSYS;
9690eca353eSBryant G. Ly goto out;
9700eca353eSBryant G. Ly }
9710eca353eSBryant G. Ly } while (1);
9720eca353eSBryant G. Ly
9730eca353eSBryant G. Ly buffer = &(hmc->buffer[hmc->queue_outbound_msgs[hmc->queue_tail]]);
9740eca353eSBryant G. Ly hmc->queue_tail++;
9750eca353eSBryant G. Ly if (hmc->queue_tail == ibmvmc_max_buf_pool_size)
9760eca353eSBryant G. Ly hmc->queue_tail = 0;
9770eca353eSBryant G. Ly spin_unlock_irqrestore(&hmc->lock, flags);
9780eca353eSBryant G. Ly
9790eca353eSBryant G. Ly nbytes = min_t(size_t, nbytes, buffer->msg_len);
9800eca353eSBryant G. Ly n = copy_to_user((void *)buf, buffer->real_addr_local, nbytes);
9810eca353eSBryant G. Ly dev_dbg(adapter->dev, "read: copy to user nbytes = 0x%lx.\n", nbytes);
9820eca353eSBryant G. Ly ibmvmc_free_hmc_buffer(hmc, buffer);
9830eca353eSBryant G. Ly retval = nbytes;
9840eca353eSBryant G. Ly
9850eca353eSBryant G. Ly if (n) {
9860eca353eSBryant G. Ly dev_warn(adapter->dev, "read: copy to user failed.\n");
9870eca353eSBryant G. Ly retval = -EFAULT;
9880eca353eSBryant G. Ly }
9890eca353eSBryant G. Ly
9900eca353eSBryant G. Ly out:
9910eca353eSBryant G. Ly finish_wait(&ibmvmc_read_wait, &wait);
9920eca353eSBryant G. Ly dev_dbg(adapter->dev, "read: out %ld\n", retval);
9930eca353eSBryant G. Ly return retval;
9940eca353eSBryant G. Ly }
9950eca353eSBryant G. Ly
9960eca353eSBryant G. Ly /**
9970eca353eSBryant G. Ly * ibmvmc_poll - Poll
9980eca353eSBryant G. Ly *
9990eca353eSBryant G. Ly * @file: file struct
10000eca353eSBryant G. Ly * @wait: Poll Table
10010eca353eSBryant G. Ly *
10020eca353eSBryant G. Ly * Return:
10030eca353eSBryant G. Ly * poll.h return values
10040eca353eSBryant G. Ly */
ibmvmc_poll(struct file * file,poll_table * wait)10050eca353eSBryant G. Ly static unsigned int ibmvmc_poll(struct file *file, poll_table *wait)
10060eca353eSBryant G. Ly {
10070eca353eSBryant G. Ly struct ibmvmc_file_session *session;
10080eca353eSBryant G. Ly struct ibmvmc_hmc *hmc;
10090eca353eSBryant G. Ly unsigned int mask = 0;
10100eca353eSBryant G. Ly
10110eca353eSBryant G. Ly session = file->private_data;
10120eca353eSBryant G. Ly if (!session)
10130eca353eSBryant G. Ly return 0;
10140eca353eSBryant G. Ly
10150eca353eSBryant G. Ly hmc = session->hmc;
10160eca353eSBryant G. Ly if (!hmc)
10170eca353eSBryant G. Ly return 0;
10180eca353eSBryant G. Ly
10190eca353eSBryant G. Ly poll_wait(file, &ibmvmc_read_wait, wait);
10200eca353eSBryant G. Ly
10210eca353eSBryant G. Ly if (hmc->queue_head != hmc->queue_tail)
10220eca353eSBryant G. Ly mask |= POLLIN | POLLRDNORM;
10230eca353eSBryant G. Ly
10240eca353eSBryant G. Ly return mask;
10250eca353eSBryant G. Ly }
10260eca353eSBryant G. Ly
10270eca353eSBryant G. Ly /**
10280eca353eSBryant G. Ly * ibmvmc_write - Write
10290eca353eSBryant G. Ly *
10300eca353eSBryant G. Ly * @file: file struct
103118248659SLee Jones * @buffer: Character buffer
10320eca353eSBryant G. Ly * @count: Count field
10330eca353eSBryant G. Ly * @ppos: Offset
10340eca353eSBryant G. Ly *
10350eca353eSBryant G. Ly * Return:
10360eca353eSBryant G. Ly * 0 - Success
10370eca353eSBryant G. Ly * Non-zero - Failure
10380eca353eSBryant G. Ly */
ibmvmc_write(struct file * file,const char * buffer,size_t count,loff_t * ppos)10390eca353eSBryant G. Ly static ssize_t ibmvmc_write(struct file *file, const char *buffer,
10400eca353eSBryant G. Ly size_t count, loff_t *ppos)
10410eca353eSBryant G. Ly {
10428789c172SAl Viro struct inode *inode;
10430eca353eSBryant G. Ly struct ibmvmc_buffer *vmc_buffer;
10440eca353eSBryant G. Ly struct ibmvmc_file_session *session;
10450eca353eSBryant G. Ly struct crq_server_adapter *adapter;
10460eca353eSBryant G. Ly struct ibmvmc_hmc *hmc;
10470eca353eSBryant G. Ly unsigned char *buf;
10480eca353eSBryant G. Ly unsigned long flags;
10490eca353eSBryant G. Ly size_t bytes;
10500eca353eSBryant G. Ly const char *p = buffer;
10510eca353eSBryant G. Ly size_t c = count;
10520eca353eSBryant G. Ly int ret = 0;
10530eca353eSBryant G. Ly
10540eca353eSBryant G. Ly session = file->private_data;
10550eca353eSBryant G. Ly if (!session)
10560eca353eSBryant G. Ly return -EIO;
10570eca353eSBryant G. Ly
10580eca353eSBryant G. Ly hmc = session->hmc;
10590eca353eSBryant G. Ly if (!hmc)
10600eca353eSBryant G. Ly return -EIO;
10610eca353eSBryant G. Ly
10620eca353eSBryant G. Ly spin_lock_irqsave(&hmc->lock, flags);
10630eca353eSBryant G. Ly if (hmc->state == ibmhmc_state_free) {
10640eca353eSBryant G. Ly /* HMC connection is not valid (possibly was reset under us). */
10650eca353eSBryant G. Ly ret = -EIO;
10660eca353eSBryant G. Ly goto out;
10670eca353eSBryant G. Ly }
10680eca353eSBryant G. Ly
10690eca353eSBryant G. Ly adapter = hmc->adapter;
10700eca353eSBryant G. Ly if (!adapter) {
10710eca353eSBryant G. Ly ret = -EIO;
10720eca353eSBryant G. Ly goto out;
10730eca353eSBryant G. Ly }
10740eca353eSBryant G. Ly
10750eca353eSBryant G. Ly if (count > ibmvmc.max_mtu) {
10760eca353eSBryant G. Ly dev_warn(adapter->dev, "invalid buffer size 0x%lx\n",
10770eca353eSBryant G. Ly (unsigned long)count);
10780eca353eSBryant G. Ly ret = -EIO;
10790eca353eSBryant G. Ly goto out;
10800eca353eSBryant G. Ly }
10810eca353eSBryant G. Ly
10820eca353eSBryant G. Ly /* Waiting for the open resp message to the ioctl(1) - retry */
10830eca353eSBryant G. Ly if (hmc->state == ibmhmc_state_opening) {
10840eca353eSBryant G. Ly ret = -EBUSY;
10850eca353eSBryant G. Ly goto out;
10860eca353eSBryant G. Ly }
10870eca353eSBryant G. Ly
10880eca353eSBryant G. Ly /* Make sure the ioctl() was called & the open msg sent, and that
10890eca353eSBryant G. Ly * the HMC connection has not failed.
10900eca353eSBryant G. Ly */
10910eca353eSBryant G. Ly if (hmc->state != ibmhmc_state_ready) {
10920eca353eSBryant G. Ly ret = -EIO;
10930eca353eSBryant G. Ly goto out;
10940eca353eSBryant G. Ly }
10950eca353eSBryant G. Ly
10960eca353eSBryant G. Ly vmc_buffer = ibmvmc_get_valid_hmc_buffer(hmc->index);
10970eca353eSBryant G. Ly if (!vmc_buffer) {
10980eca353eSBryant G. Ly /* No buffer available for the msg send, or we have not yet
10990eca353eSBryant G. Ly * completed the open/open_resp sequence. Retry until this is
11000eca353eSBryant G. Ly * complete.
11010eca353eSBryant G. Ly */
11020eca353eSBryant G. Ly ret = -EBUSY;
11030eca353eSBryant G. Ly goto out;
11040eca353eSBryant G. Ly }
11050eca353eSBryant G. Ly if (!vmc_buffer->real_addr_local) {
11060eca353eSBryant G. Ly dev_err(adapter->dev, "no buffer storage assigned\n");
11070eca353eSBryant G. Ly ret = -EIO;
11080eca353eSBryant G. Ly goto out;
11090eca353eSBryant G. Ly }
11100eca353eSBryant G. Ly buf = vmc_buffer->real_addr_local;
11110eca353eSBryant G. Ly
11120eca353eSBryant G. Ly while (c > 0) {
11130eca353eSBryant G. Ly bytes = min_t(size_t, c, vmc_buffer->size);
11140eca353eSBryant G. Ly
11150eca353eSBryant G. Ly bytes -= copy_from_user(buf, p, bytes);
11160eca353eSBryant G. Ly if (!bytes) {
11170eca353eSBryant G. Ly ret = -EFAULT;
11180eca353eSBryant G. Ly goto out;
11190eca353eSBryant G. Ly }
11200eca353eSBryant G. Ly c -= bytes;
11210eca353eSBryant G. Ly p += bytes;
11220eca353eSBryant G. Ly }
11230eca353eSBryant G. Ly if (p == buffer)
11240eca353eSBryant G. Ly goto out;
11250eca353eSBryant G. Ly
11268789c172SAl Viro inode = file_inode(file);
1127*41441cecSJeff Layton inode->i_mtime = inode_set_ctime_current(inode);
11288789c172SAl Viro mark_inode_dirty(inode);
11290eca353eSBryant G. Ly
11300eca353eSBryant G. Ly dev_dbg(adapter->dev, "write: file = 0x%lx, count = 0x%lx\n",
11310eca353eSBryant G. Ly (unsigned long)file, (unsigned long)count);
11320eca353eSBryant G. Ly
11330eca353eSBryant G. Ly ibmvmc_send_msg(adapter, vmc_buffer, hmc, count);
11340eca353eSBryant G. Ly ret = p - buffer;
11350eca353eSBryant G. Ly out:
11360eca353eSBryant G. Ly spin_unlock_irqrestore(&hmc->lock, flags);
11370eca353eSBryant G. Ly return (ssize_t)(ret);
11380eca353eSBryant G. Ly }
11390eca353eSBryant G. Ly
11400eca353eSBryant G. Ly /**
11410eca353eSBryant G. Ly * ibmvmc_setup_hmc - Setup the HMC
11420eca353eSBryant G. Ly *
11430eca353eSBryant G. Ly * @session: ibmvmc_file_session struct
11440eca353eSBryant G. Ly *
11450eca353eSBryant G. Ly * Return:
11460eca353eSBryant G. Ly * 0 - Success
11470eca353eSBryant G. Ly * Non-zero - Failure
11480eca353eSBryant G. Ly */
ibmvmc_setup_hmc(struct ibmvmc_file_session * session)11490eca353eSBryant G. Ly static long ibmvmc_setup_hmc(struct ibmvmc_file_session *session)
11500eca353eSBryant G. Ly {
11510eca353eSBryant G. Ly struct ibmvmc_hmc *hmc;
11520eca353eSBryant G. Ly unsigned int valid, free, index;
11530eca353eSBryant G. Ly
11540eca353eSBryant G. Ly if (ibmvmc.state == ibmvmc_state_failed) {
11550eca353eSBryant G. Ly pr_warn("ibmvmc: Reserve HMC: state_failed\n");
11560eca353eSBryant G. Ly return -EIO;
11570eca353eSBryant G. Ly }
11580eca353eSBryant G. Ly
11590eca353eSBryant G. Ly if (ibmvmc.state < ibmvmc_state_ready) {
11600eca353eSBryant G. Ly pr_warn("ibmvmc: Reserve HMC: not state_ready\n");
11610eca353eSBryant G. Ly return -EAGAIN;
11620eca353eSBryant G. Ly }
11630eca353eSBryant G. Ly
11640eca353eSBryant G. Ly /* Device is busy until capabilities have been exchanged and we
11650eca353eSBryant G. Ly * have a generic buffer for each possible HMC connection.
11660eca353eSBryant G. Ly */
11670eca353eSBryant G. Ly for (index = 0; index <= ibmvmc.max_hmc_index; index++) {
11680eca353eSBryant G. Ly valid = 0;
11690eca353eSBryant G. Ly ibmvmc_count_hmc_buffers(index, &valid, &free);
11700eca353eSBryant G. Ly if (valid == 0) {
11710eca353eSBryant G. Ly pr_warn("ibmvmc: buffers not ready for index %d\n",
11720eca353eSBryant G. Ly index);
11730eca353eSBryant G. Ly return -ENOBUFS;
11740eca353eSBryant G. Ly }
11750eca353eSBryant G. Ly }
11760eca353eSBryant G. Ly
11770eca353eSBryant G. Ly /* Get an hmc object, and transition to ibmhmc_state_initial */
11780eca353eSBryant G. Ly hmc = ibmvmc_get_free_hmc();
11790eca353eSBryant G. Ly if (!hmc) {
11800eca353eSBryant G. Ly pr_warn("%s: free hmc not found\n", __func__);
11810eca353eSBryant G. Ly return -EBUSY;
11820eca353eSBryant G. Ly }
11830eca353eSBryant G. Ly
11840eca353eSBryant G. Ly hmc->session = hmc->session + 1;
11850eca353eSBryant G. Ly if (hmc->session == 0xff)
11860eca353eSBryant G. Ly hmc->session = 1;
11870eca353eSBryant G. Ly
11880eca353eSBryant G. Ly session->hmc = hmc;
11890eca353eSBryant G. Ly hmc->adapter = &ibmvmc_adapter;
11900eca353eSBryant G. Ly hmc->file_session = session;
11910eca353eSBryant G. Ly session->valid = 1;
11920eca353eSBryant G. Ly
11930eca353eSBryant G. Ly return 0;
11940eca353eSBryant G. Ly }
11950eca353eSBryant G. Ly
11960eca353eSBryant G. Ly /**
11970eca353eSBryant G. Ly * ibmvmc_ioctl_sethmcid - IOCTL Set HMC ID
11980eca353eSBryant G. Ly *
11990eca353eSBryant G. Ly * @session: ibmvmc_file_session struct
12000eca353eSBryant G. Ly * @new_hmc_id: HMC id field
12010eca353eSBryant G. Ly *
12020eca353eSBryant G. Ly * IOCTL command to setup the hmc id
12030eca353eSBryant G. Ly *
12040eca353eSBryant G. Ly * Return:
12050eca353eSBryant G. Ly * 0 - Success
12060eca353eSBryant G. Ly * Non-zero - Failure
12070eca353eSBryant G. Ly */
ibmvmc_ioctl_sethmcid(struct ibmvmc_file_session * session,unsigned char __user * new_hmc_id)12080eca353eSBryant G. Ly static long ibmvmc_ioctl_sethmcid(struct ibmvmc_file_session *session,
12090eca353eSBryant G. Ly unsigned char __user *new_hmc_id)
12100eca353eSBryant G. Ly {
12110eca353eSBryant G. Ly struct ibmvmc_hmc *hmc;
12120eca353eSBryant G. Ly struct ibmvmc_buffer *buffer;
12130eca353eSBryant G. Ly size_t bytes;
12140eca353eSBryant G. Ly char print_buffer[HMC_ID_LEN + 1];
12150eca353eSBryant G. Ly unsigned long flags;
12160eca353eSBryant G. Ly long rc = 0;
12170eca353eSBryant G. Ly
12180eca353eSBryant G. Ly /* Reserve HMC session */
12190eca353eSBryant G. Ly hmc = session->hmc;
12200eca353eSBryant G. Ly if (!hmc) {
12210eca353eSBryant G. Ly rc = ibmvmc_setup_hmc(session);
12220eca353eSBryant G. Ly if (rc)
12230eca353eSBryant G. Ly return rc;
12240eca353eSBryant G. Ly
12250eca353eSBryant G. Ly hmc = session->hmc;
12260eca353eSBryant G. Ly if (!hmc) {
12270eca353eSBryant G. Ly pr_err("ibmvmc: setup_hmc success but no hmc\n");
12280eca353eSBryant G. Ly return -EIO;
12290eca353eSBryant G. Ly }
12300eca353eSBryant G. Ly }
12310eca353eSBryant G. Ly
12320eca353eSBryant G. Ly if (hmc->state != ibmhmc_state_initial) {
12330eca353eSBryant G. Ly pr_warn("ibmvmc: sethmcid: invalid state to send open 0x%x\n",
12340eca353eSBryant G. Ly hmc->state);
12350eca353eSBryant G. Ly return -EIO;
12360eca353eSBryant G. Ly }
12370eca353eSBryant G. Ly
12380eca353eSBryant G. Ly bytes = copy_from_user(hmc->hmc_id, new_hmc_id, HMC_ID_LEN);
12390eca353eSBryant G. Ly if (bytes)
12400eca353eSBryant G. Ly return -EFAULT;
12410eca353eSBryant G. Ly
12420eca353eSBryant G. Ly /* Send Open Session command */
12430eca353eSBryant G. Ly spin_lock_irqsave(&hmc->lock, flags);
12440eca353eSBryant G. Ly buffer = ibmvmc_get_valid_hmc_buffer(hmc->index);
12450eca353eSBryant G. Ly spin_unlock_irqrestore(&hmc->lock, flags);
12460eca353eSBryant G. Ly
12470eca353eSBryant G. Ly if (!buffer || !buffer->real_addr_local) {
12480eca353eSBryant G. Ly pr_warn("ibmvmc: sethmcid: no buffer available\n");
12490eca353eSBryant G. Ly return -EIO;
12500eca353eSBryant G. Ly }
12510eca353eSBryant G. Ly
12520eca353eSBryant G. Ly /* Make sure buffer is NULL terminated before trying to print it */
12530eca353eSBryant G. Ly memset(print_buffer, 0, HMC_ID_LEN + 1);
12540eca353eSBryant G. Ly strncpy(print_buffer, hmc->hmc_id, HMC_ID_LEN);
12550eca353eSBryant G. Ly pr_info("ibmvmc: sethmcid: Set HMC ID: \"%s\"\n", print_buffer);
12560eca353eSBryant G. Ly
12570eca353eSBryant G. Ly memcpy(buffer->real_addr_local, hmc->hmc_id, HMC_ID_LEN);
12580eca353eSBryant G. Ly /* RDMA over ID, send open msg, change state to ibmhmc_state_opening */
12590eca353eSBryant G. Ly rc = ibmvmc_send_open(buffer, hmc);
12600eca353eSBryant G. Ly
12610eca353eSBryant G. Ly return rc;
12620eca353eSBryant G. Ly }
12630eca353eSBryant G. Ly
12640eca353eSBryant G. Ly /**
12650eca353eSBryant G. Ly * ibmvmc_ioctl_query - IOCTL Query
12660eca353eSBryant G. Ly *
12670eca353eSBryant G. Ly * @session: ibmvmc_file_session struct
12680eca353eSBryant G. Ly * @ret_struct: ibmvmc_query_struct
12690eca353eSBryant G. Ly *
12700eca353eSBryant G. Ly * Return:
12710eca353eSBryant G. Ly * 0 - Success
12720eca353eSBryant G. Ly * Non-zero - Failure
12730eca353eSBryant G. Ly */
ibmvmc_ioctl_query(struct ibmvmc_file_session * session,struct ibmvmc_query_struct __user * ret_struct)12740eca353eSBryant G. Ly static long ibmvmc_ioctl_query(struct ibmvmc_file_session *session,
12750eca353eSBryant G. Ly struct ibmvmc_query_struct __user *ret_struct)
12760eca353eSBryant G. Ly {
12770eca353eSBryant G. Ly struct ibmvmc_query_struct query_struct;
12780eca353eSBryant G. Ly size_t bytes;
12790eca353eSBryant G. Ly
12800eca353eSBryant G. Ly memset(&query_struct, 0, sizeof(query_struct));
12810eca353eSBryant G. Ly query_struct.have_vmc = (ibmvmc.state > ibmvmc_state_initial);
12820eca353eSBryant G. Ly query_struct.state = ibmvmc.state;
12830eca353eSBryant G. Ly query_struct.vmc_drc_index = ibmvmc.vmc_drc_index;
12840eca353eSBryant G. Ly
12850eca353eSBryant G. Ly bytes = copy_to_user(ret_struct, &query_struct,
12860eca353eSBryant G. Ly sizeof(query_struct));
12870eca353eSBryant G. Ly if (bytes)
12880eca353eSBryant G. Ly return -EFAULT;
12890eca353eSBryant G. Ly
12900eca353eSBryant G. Ly return 0;
12910eca353eSBryant G. Ly }
12920eca353eSBryant G. Ly
12930eca353eSBryant G. Ly /**
12940eca353eSBryant G. Ly * ibmvmc_ioctl_requestvmc - IOCTL Request VMC
12950eca353eSBryant G. Ly *
12960eca353eSBryant G. Ly * @session: ibmvmc_file_session struct
12970eca353eSBryant G. Ly * @ret_vmc_index: VMC Index
12980eca353eSBryant G. Ly *
12990eca353eSBryant G. Ly * Return:
13000eca353eSBryant G. Ly * 0 - Success
13010eca353eSBryant G. Ly * Non-zero - Failure
13020eca353eSBryant G. Ly */
ibmvmc_ioctl_requestvmc(struct ibmvmc_file_session * session,u32 __user * ret_vmc_index)13030eca353eSBryant G. Ly static long ibmvmc_ioctl_requestvmc(struct ibmvmc_file_session *session,
13040eca353eSBryant G. Ly u32 __user *ret_vmc_index)
13050eca353eSBryant G. Ly {
13060eca353eSBryant G. Ly /* TODO: (adreznec) Add locking to control multiple process access */
13070eca353eSBryant G. Ly size_t bytes;
13080eca353eSBryant G. Ly long rc;
13090eca353eSBryant G. Ly u32 vmc_drc_index;
13100eca353eSBryant G. Ly
13110eca353eSBryant G. Ly /* Call to request the VMC device from phyp*/
13120eca353eSBryant G. Ly rc = h_request_vmc(&vmc_drc_index);
13130eca353eSBryant G. Ly pr_debug("ibmvmc: requestvmc: H_REQUEST_VMC rc = 0x%lx\n", rc);
13140eca353eSBryant G. Ly
13150eca353eSBryant G. Ly if (rc == H_SUCCESS) {
13160eca353eSBryant G. Ly rc = 0;
13170eca353eSBryant G. Ly } else if (rc == H_FUNCTION) {
13180eca353eSBryant G. Ly pr_err("ibmvmc: requestvmc: h_request_vmc not supported\n");
13190eca353eSBryant G. Ly return -EPERM;
13200eca353eSBryant G. Ly } else if (rc == H_AUTHORITY) {
13210eca353eSBryant G. Ly pr_err("ibmvmc: requestvmc: hypervisor denied vmc request\n");
13220eca353eSBryant G. Ly return -EPERM;
13230eca353eSBryant G. Ly } else if (rc == H_HARDWARE) {
13240eca353eSBryant G. Ly pr_err("ibmvmc: requestvmc: hypervisor hardware fault\n");
13250eca353eSBryant G. Ly return -EIO;
13260eca353eSBryant G. Ly } else if (rc == H_RESOURCE) {
13270eca353eSBryant G. Ly pr_err("ibmvmc: requestvmc: vmc resource unavailable\n");
13280eca353eSBryant G. Ly return -ENODEV;
13290eca353eSBryant G. Ly } else if (rc == H_NOT_AVAILABLE) {
13300eca353eSBryant G. Ly pr_err("ibmvmc: requestvmc: system cannot be vmc managed\n");
13310eca353eSBryant G. Ly return -EPERM;
13320eca353eSBryant G. Ly } else if (rc == H_PARAMETER) {
13330eca353eSBryant G. Ly pr_err("ibmvmc: requestvmc: invalid parameter\n");
13340eca353eSBryant G. Ly return -EINVAL;
13350eca353eSBryant G. Ly }
13360eca353eSBryant G. Ly
13370eca353eSBryant G. Ly /* Success, set the vmc index in global struct */
13380eca353eSBryant G. Ly ibmvmc.vmc_drc_index = vmc_drc_index;
13390eca353eSBryant G. Ly
13400eca353eSBryant G. Ly bytes = copy_to_user(ret_vmc_index, &vmc_drc_index,
13410eca353eSBryant G. Ly sizeof(*ret_vmc_index));
13420eca353eSBryant G. Ly if (bytes) {
13430eca353eSBryant G. Ly pr_warn("ibmvmc: requestvmc: copy to user failed.\n");
13440eca353eSBryant G. Ly return -EFAULT;
13450eca353eSBryant G. Ly }
13460eca353eSBryant G. Ly return rc;
13470eca353eSBryant G. Ly }
13480eca353eSBryant G. Ly
13490eca353eSBryant G. Ly /**
13500eca353eSBryant G. Ly * ibmvmc_ioctl - IOCTL
13510eca353eSBryant G. Ly *
135218248659SLee Jones * @file: file information
13530eca353eSBryant G. Ly * @cmd: cmd field
13540eca353eSBryant G. Ly * @arg: Argument field
13550eca353eSBryant G. Ly *
13560eca353eSBryant G. Ly * Return:
13570eca353eSBryant G. Ly * 0 - Success
13580eca353eSBryant G. Ly * Non-zero - Failure
13590eca353eSBryant G. Ly */
ibmvmc_ioctl(struct file * file,unsigned int cmd,unsigned long arg)13600eca353eSBryant G. Ly static long ibmvmc_ioctl(struct file *file,
13610eca353eSBryant G. Ly unsigned int cmd, unsigned long arg)
13620eca353eSBryant G. Ly {
13630eca353eSBryant G. Ly struct ibmvmc_file_session *session = file->private_data;
13640eca353eSBryant G. Ly
13650eca353eSBryant G. Ly pr_debug("ibmvmc: ioctl file=0x%lx, cmd=0x%x, arg=0x%lx, ses=0x%lx\n",
13660eca353eSBryant G. Ly (unsigned long)file, cmd, arg,
13670eca353eSBryant G. Ly (unsigned long)session);
13680eca353eSBryant G. Ly
13690eca353eSBryant G. Ly if (!session) {
13700eca353eSBryant G. Ly pr_warn("ibmvmc: ioctl: no session\n");
13710eca353eSBryant G. Ly return -EIO;
13720eca353eSBryant G. Ly }
13730eca353eSBryant G. Ly
13740eca353eSBryant G. Ly switch (cmd) {
13750eca353eSBryant G. Ly case VMC_IOCTL_SETHMCID:
13760eca353eSBryant G. Ly return ibmvmc_ioctl_sethmcid(session,
13770eca353eSBryant G. Ly (unsigned char __user *)arg);
13780eca353eSBryant G. Ly case VMC_IOCTL_QUERY:
13790eca353eSBryant G. Ly return ibmvmc_ioctl_query(session,
13800eca353eSBryant G. Ly (struct ibmvmc_query_struct __user *)arg);
13810eca353eSBryant G. Ly case VMC_IOCTL_REQUESTVMC:
13820eca353eSBryant G. Ly return ibmvmc_ioctl_requestvmc(session,
13830eca353eSBryant G. Ly (unsigned int __user *)arg);
13840eca353eSBryant G. Ly default:
13850eca353eSBryant G. Ly pr_warn("ibmvmc: unknown ioctl 0x%x\n", cmd);
13860eca353eSBryant G. Ly return -EINVAL;
13870eca353eSBryant G. Ly }
13880eca353eSBryant G. Ly }
13890eca353eSBryant G. Ly
13900eca353eSBryant G. Ly static const struct file_operations ibmvmc_fops = {
13910eca353eSBryant G. Ly .owner = THIS_MODULE,
13920eca353eSBryant G. Ly .read = ibmvmc_read,
13930eca353eSBryant G. Ly .write = ibmvmc_write,
13940eca353eSBryant G. Ly .poll = ibmvmc_poll,
13950eca353eSBryant G. Ly .unlocked_ioctl = ibmvmc_ioctl,
13960eca353eSBryant G. Ly .open = ibmvmc_open,
13970eca353eSBryant G. Ly .release = ibmvmc_close,
13980eca353eSBryant G. Ly };
13990eca353eSBryant G. Ly
14000eca353eSBryant G. Ly /**
14010eca353eSBryant G. Ly * ibmvmc_add_buffer - Add Buffer
14020eca353eSBryant G. Ly *
14030eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
14040eca353eSBryant G. Ly * @crq: ibmvmc_crq_msg struct
14050eca353eSBryant G. Ly *
14060eca353eSBryant G. Ly * This message transfers a buffer from hypervisor ownership to management
14070eca353eSBryant G. Ly * partition ownership. The LIOBA is obtained from the virtual TCE table
14080eca353eSBryant G. Ly * associated with the hypervisor side of the VMC device, and points to a
14090eca353eSBryant G. Ly * buffer of size MTU (as established in the capabilities exchange).
14100eca353eSBryant G. Ly *
14110eca353eSBryant G. Ly * Typical flow for ading buffers:
14120eca353eSBryant G. Ly * 1. A new management application connection is opened by the management
14130eca353eSBryant G. Ly * partition.
14140eca353eSBryant G. Ly * 2. The hypervisor assigns new buffers for the traffic associated with
14150eca353eSBryant G. Ly * that connection.
14160eca353eSBryant G. Ly * 3. The hypervisor sends VMC Add Buffer messages to the management
14170eca353eSBryant G. Ly * partition, informing it of the new buffers.
14180eca353eSBryant G. Ly * 4. The hypervisor sends an HMC protocol message (to the management
14190eca353eSBryant G. Ly * application) notifying it of the new buffers. This informs the
14200eca353eSBryant G. Ly * application that it has buffers available for sending HMC
14210eca353eSBryant G. Ly * commands.
14220eca353eSBryant G. Ly *
14230eca353eSBryant G. Ly * Return:
14240eca353eSBryant G. Ly * 0 - Success
14250eca353eSBryant G. Ly * Non-zero - Failure
14260eca353eSBryant G. Ly */
ibmvmc_add_buffer(struct crq_server_adapter * adapter,struct ibmvmc_crq_msg * crq)14270eca353eSBryant G. Ly static int ibmvmc_add_buffer(struct crq_server_adapter *adapter,
14280eca353eSBryant G. Ly struct ibmvmc_crq_msg *crq)
14290eca353eSBryant G. Ly {
14300eca353eSBryant G. Ly struct ibmvmc_buffer *buffer;
14310eca353eSBryant G. Ly u8 hmc_index;
14320eca353eSBryant G. Ly u8 hmc_session;
14330eca353eSBryant G. Ly u16 buffer_id;
14340eca353eSBryant G. Ly unsigned long flags;
14350eca353eSBryant G. Ly int rc = 0;
14360eca353eSBryant G. Ly
14370eca353eSBryant G. Ly if (!crq)
14380eca353eSBryant G. Ly return -1;
14390eca353eSBryant G. Ly
14400eca353eSBryant G. Ly hmc_session = crq->hmc_session;
14410eca353eSBryant G. Ly hmc_index = crq->hmc_index;
14420eca353eSBryant G. Ly buffer_id = be16_to_cpu(crq->var2.buffer_id);
14430eca353eSBryant G. Ly
14440eca353eSBryant G. Ly if (hmc_index > ibmvmc.max_hmc_index) {
14450eca353eSBryant G. Ly dev_err(adapter->dev, "add_buffer: invalid hmc_index = 0x%x\n",
14460eca353eSBryant G. Ly hmc_index);
14470eca353eSBryant G. Ly ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_HMC_INDEX,
14480eca353eSBryant G. Ly hmc_session, hmc_index, buffer_id);
14490eca353eSBryant G. Ly return -1;
14500eca353eSBryant G. Ly }
14510eca353eSBryant G. Ly
14520eca353eSBryant G. Ly if (buffer_id >= ibmvmc.max_buffer_pool_size) {
14530eca353eSBryant G. Ly dev_err(adapter->dev, "add_buffer: invalid buffer_id = 0x%x\n",
14540eca353eSBryant G. Ly buffer_id);
14550eca353eSBryant G. Ly ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_BUFFER_ID,
14560eca353eSBryant G. Ly hmc_session, hmc_index, buffer_id);
14570eca353eSBryant G. Ly return -1;
14580eca353eSBryant G. Ly }
14590eca353eSBryant G. Ly
14600eca353eSBryant G. Ly spin_lock_irqsave(&hmcs[hmc_index].lock, flags);
14610eca353eSBryant G. Ly buffer = &hmcs[hmc_index].buffer[buffer_id];
14620eca353eSBryant G. Ly
14630eca353eSBryant G. Ly if (buffer->real_addr_local || buffer->dma_addr_local) {
14640eca353eSBryant G. Ly dev_warn(adapter->dev, "add_buffer: already allocated id = 0x%lx\n",
14650eca353eSBryant G. Ly (unsigned long)buffer_id);
14660eca353eSBryant G. Ly spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags);
14670eca353eSBryant G. Ly ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_BUFFER_ID,
14680eca353eSBryant G. Ly hmc_session, hmc_index, buffer_id);
14690eca353eSBryant G. Ly return -1;
14700eca353eSBryant G. Ly }
14710eca353eSBryant G. Ly
14720eca353eSBryant G. Ly buffer->real_addr_local = alloc_dma_buffer(to_vio_dev(adapter->dev),
14730eca353eSBryant G. Ly ibmvmc.max_mtu,
14740eca353eSBryant G. Ly &buffer->dma_addr_local);
14750eca353eSBryant G. Ly
14760eca353eSBryant G. Ly if (!buffer->real_addr_local) {
14770eca353eSBryant G. Ly dev_err(adapter->dev, "add_buffer: alloc_dma_buffer failed.\n");
14780eca353eSBryant G. Ly spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags);
14790eca353eSBryant G. Ly ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INTERFACE_FAILURE,
14800eca353eSBryant G. Ly hmc_session, hmc_index, buffer_id);
14810eca353eSBryant G. Ly return -1;
14820eca353eSBryant G. Ly }
14830eca353eSBryant G. Ly
14840eca353eSBryant G. Ly buffer->dma_addr_remote = be32_to_cpu(crq->var3.lioba);
14850eca353eSBryant G. Ly buffer->size = ibmvmc.max_mtu;
14860eca353eSBryant G. Ly buffer->owner = crq->var1.owner;
14870eca353eSBryant G. Ly buffer->free = 1;
14880eca353eSBryant G. Ly /* Must ensure valid==1 is observable only after all other fields are */
14890eca353eSBryant G. Ly dma_wmb();
14900eca353eSBryant G. Ly buffer->valid = 1;
14910eca353eSBryant G. Ly buffer->id = buffer_id;
14920eca353eSBryant G. Ly
14930eca353eSBryant G. Ly dev_dbg(adapter->dev, "add_buffer: successfully added a buffer:\n");
14940eca353eSBryant G. Ly dev_dbg(adapter->dev, " index: %d, session: %d, buffer: 0x%x, owner: %d\n",
14950eca353eSBryant G. Ly hmc_index, hmc_session, buffer_id, buffer->owner);
14960eca353eSBryant G. Ly dev_dbg(adapter->dev, " local: 0x%x, remote: 0x%x\n",
14970eca353eSBryant G. Ly (u32)buffer->dma_addr_local,
14980eca353eSBryant G. Ly (u32)buffer->dma_addr_remote);
14990eca353eSBryant G. Ly spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags);
15000eca353eSBryant G. Ly
15010eca353eSBryant G. Ly ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_SUCCESS, hmc_session,
15020eca353eSBryant G. Ly hmc_index, buffer_id);
15030eca353eSBryant G. Ly
15040eca353eSBryant G. Ly return rc;
15050eca353eSBryant G. Ly }
15060eca353eSBryant G. Ly
15070eca353eSBryant G. Ly /**
15080eca353eSBryant G. Ly * ibmvmc_rem_buffer - Remove Buffer
15090eca353eSBryant G. Ly *
15100eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
15110eca353eSBryant G. Ly * @crq: ibmvmc_crq_msg struct
15120eca353eSBryant G. Ly *
15130eca353eSBryant G. Ly * This message requests an HMC buffer to be transferred from management
15140eca353eSBryant G. Ly * partition ownership to hypervisor ownership. The management partition may
15150eca353eSBryant G. Ly * not be able to satisfy the request at a particular point in time if all its
15160eca353eSBryant G. Ly * buffers are in use. The management partition requires a depth of at least
15170eca353eSBryant G. Ly * one inbound buffer to allow management application commands to flow to the
15180eca353eSBryant G. Ly * hypervisor. It is, therefore, an interface error for the hypervisor to
15190eca353eSBryant G. Ly * attempt to remove the management partition's last buffer.
15200eca353eSBryant G. Ly *
15210eca353eSBryant G. Ly * The hypervisor is expected to manage buffer usage with the management
15220eca353eSBryant G. Ly * application directly and inform the management partition when buffers may be
15230eca353eSBryant G. Ly * removed. The typical flow for removing buffers:
15240eca353eSBryant G. Ly *
15250eca353eSBryant G. Ly * 1. The management application no longer needs a communication path to a
15260eca353eSBryant G. Ly * particular hypervisor function. That function is closed.
15270eca353eSBryant G. Ly * 2. The hypervisor and the management application quiesce all traffic to that
15280eca353eSBryant G. Ly * function. The hypervisor requests a reduction in buffer pool size.
15290eca353eSBryant G. Ly * 3. The management application acknowledges the reduction in buffer pool size.
15300eca353eSBryant G. Ly * 4. The hypervisor sends a Remove Buffer message to the management partition,
15310eca353eSBryant G. Ly * informing it of the reduction in buffers.
15320eca353eSBryant G. Ly * 5. The management partition verifies it can remove the buffer. This is
15330eca353eSBryant G. Ly * possible if buffers have been quiesced.
15340eca353eSBryant G. Ly *
15350eca353eSBryant G. Ly * Return:
15360eca353eSBryant G. Ly * 0 - Success
15370eca353eSBryant G. Ly * Non-zero - Failure
15380eca353eSBryant G. Ly */
15390eca353eSBryant G. Ly /*
15400eca353eSBryant G. Ly * The hypervisor requested that we pick an unused buffer, and return it.
15410eca353eSBryant G. Ly * Before sending the buffer back, we free any storage associated with the
15420eca353eSBryant G. Ly * buffer.
15430eca353eSBryant G. Ly */
ibmvmc_rem_buffer(struct crq_server_adapter * adapter,struct ibmvmc_crq_msg * crq)15440eca353eSBryant G. Ly static int ibmvmc_rem_buffer(struct crq_server_adapter *adapter,
15450eca353eSBryant G. Ly struct ibmvmc_crq_msg *crq)
15460eca353eSBryant G. Ly {
15470eca353eSBryant G. Ly struct ibmvmc_buffer *buffer;
15480eca353eSBryant G. Ly u8 hmc_index;
15490eca353eSBryant G. Ly u8 hmc_session;
15500eca353eSBryant G. Ly u16 buffer_id = 0;
15510eca353eSBryant G. Ly unsigned long flags;
15520eca353eSBryant G. Ly int rc = 0;
15530eca353eSBryant G. Ly
15540eca353eSBryant G. Ly if (!crq)
15550eca353eSBryant G. Ly return -1;
15560eca353eSBryant G. Ly
15570eca353eSBryant G. Ly hmc_session = crq->hmc_session;
15580eca353eSBryant G. Ly hmc_index = crq->hmc_index;
15590eca353eSBryant G. Ly
15600eca353eSBryant G. Ly if (hmc_index > ibmvmc.max_hmc_index) {
15610eca353eSBryant G. Ly dev_warn(adapter->dev, "rem_buffer: invalid hmc_index = 0x%x\n",
15620eca353eSBryant G. Ly hmc_index);
15630eca353eSBryant G. Ly ibmvmc_send_rem_buffer_resp(adapter, VMC_MSG_INVALID_HMC_INDEX,
15640eca353eSBryant G. Ly hmc_session, hmc_index, buffer_id);
15650eca353eSBryant G. Ly return -1;
15660eca353eSBryant G. Ly }
15670eca353eSBryant G. Ly
15680eca353eSBryant G. Ly spin_lock_irqsave(&hmcs[hmc_index].lock, flags);
15690eca353eSBryant G. Ly buffer = ibmvmc_get_free_hmc_buffer(adapter, hmc_index);
15700eca353eSBryant G. Ly if (!buffer) {
15710eca353eSBryant G. Ly dev_info(adapter->dev, "rem_buffer: no buffer to remove\n");
15720eca353eSBryant G. Ly spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags);
15730eca353eSBryant G. Ly ibmvmc_send_rem_buffer_resp(adapter, VMC_MSG_NO_BUFFER,
15740eca353eSBryant G. Ly hmc_session, hmc_index,
15750eca353eSBryant G. Ly VMC_INVALID_BUFFER_ID);
15760eca353eSBryant G. Ly return -1;
15770eca353eSBryant G. Ly }
15780eca353eSBryant G. Ly
15790eca353eSBryant G. Ly buffer_id = buffer->id;
15800eca353eSBryant G. Ly
15810eca353eSBryant G. Ly if (buffer->valid)
15820eca353eSBryant G. Ly free_dma_buffer(to_vio_dev(adapter->dev),
15830eca353eSBryant G. Ly ibmvmc.max_mtu,
15840eca353eSBryant G. Ly buffer->real_addr_local,
15850eca353eSBryant G. Ly buffer->dma_addr_local);
15860eca353eSBryant G. Ly
15870eca353eSBryant G. Ly memset(buffer, 0, sizeof(struct ibmvmc_buffer));
15880eca353eSBryant G. Ly spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags);
15890eca353eSBryant G. Ly
15900eca353eSBryant G. Ly dev_dbg(adapter->dev, "rem_buffer: removed buffer 0x%x.\n", buffer_id);
15910eca353eSBryant G. Ly ibmvmc_send_rem_buffer_resp(adapter, VMC_MSG_SUCCESS, hmc_session,
15920eca353eSBryant G. Ly hmc_index, buffer_id);
15930eca353eSBryant G. Ly
15940eca353eSBryant G. Ly return rc;
15950eca353eSBryant G. Ly }
15960eca353eSBryant G. Ly
ibmvmc_recv_msg(struct crq_server_adapter * adapter,struct ibmvmc_crq_msg * crq)15970eca353eSBryant G. Ly static int ibmvmc_recv_msg(struct crq_server_adapter *adapter,
15980eca353eSBryant G. Ly struct ibmvmc_crq_msg *crq)
15990eca353eSBryant G. Ly {
16000eca353eSBryant G. Ly struct ibmvmc_buffer *buffer;
16010eca353eSBryant G. Ly struct ibmvmc_hmc *hmc;
16020eca353eSBryant G. Ly unsigned long msg_len;
16030eca353eSBryant G. Ly u8 hmc_index;
16040eca353eSBryant G. Ly u8 hmc_session;
16050eca353eSBryant G. Ly u16 buffer_id;
16060eca353eSBryant G. Ly unsigned long flags;
16070eca353eSBryant G. Ly int rc = 0;
16080eca353eSBryant G. Ly
16090eca353eSBryant G. Ly if (!crq)
16100eca353eSBryant G. Ly return -1;
16110eca353eSBryant G. Ly
16120eca353eSBryant G. Ly /* Hypervisor writes CRQs directly into our memory in big endian */
16130eca353eSBryant G. Ly dev_dbg(adapter->dev, "Recv_msg: msg from HV 0x%016llx 0x%016llx\n",
16140eca353eSBryant G. Ly be64_to_cpu(*((unsigned long *)crq)),
16150eca353eSBryant G. Ly be64_to_cpu(*(((unsigned long *)crq) + 1)));
16160eca353eSBryant G. Ly
16170eca353eSBryant G. Ly hmc_session = crq->hmc_session;
16180eca353eSBryant G. Ly hmc_index = crq->hmc_index;
16190eca353eSBryant G. Ly buffer_id = be16_to_cpu(crq->var2.buffer_id);
16200eca353eSBryant G. Ly msg_len = be32_to_cpu(crq->var3.msg_len);
16210eca353eSBryant G. Ly
16220eca353eSBryant G. Ly if (hmc_index > ibmvmc.max_hmc_index) {
16230eca353eSBryant G. Ly dev_err(adapter->dev, "Recv_msg: invalid hmc_index = 0x%x\n",
16240eca353eSBryant G. Ly hmc_index);
16250eca353eSBryant G. Ly ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_HMC_INDEX,
16260eca353eSBryant G. Ly hmc_session, hmc_index, buffer_id);
16270eca353eSBryant G. Ly return -1;
16280eca353eSBryant G. Ly }
16290eca353eSBryant G. Ly
16300eca353eSBryant G. Ly if (buffer_id >= ibmvmc.max_buffer_pool_size) {
16310eca353eSBryant G. Ly dev_err(adapter->dev, "Recv_msg: invalid buffer_id = 0x%x\n",
16320eca353eSBryant G. Ly buffer_id);
16330eca353eSBryant G. Ly ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_BUFFER_ID,
16340eca353eSBryant G. Ly hmc_session, hmc_index, buffer_id);
16350eca353eSBryant G. Ly return -1;
16360eca353eSBryant G. Ly }
16370eca353eSBryant G. Ly
16380eca353eSBryant G. Ly hmc = &hmcs[hmc_index];
16390eca353eSBryant G. Ly spin_lock_irqsave(&hmc->lock, flags);
16400eca353eSBryant G. Ly
16410eca353eSBryant G. Ly if (hmc->state == ibmhmc_state_free) {
16420eca353eSBryant G. Ly dev_err(adapter->dev, "Recv_msg: invalid hmc state = 0x%x\n",
16430eca353eSBryant G. Ly hmc->state);
16440eca353eSBryant G. Ly /* HMC connection is not valid (possibly was reset under us). */
16450eca353eSBryant G. Ly spin_unlock_irqrestore(&hmc->lock, flags);
16460eca353eSBryant G. Ly return -1;
16470eca353eSBryant G. Ly }
16480eca353eSBryant G. Ly
16490eca353eSBryant G. Ly buffer = &hmc->buffer[buffer_id];
16500eca353eSBryant G. Ly
16510eca353eSBryant G. Ly if (buffer->valid == 0 || buffer->owner == VMC_BUF_OWNER_ALPHA) {
16520eca353eSBryant G. Ly dev_err(adapter->dev, "Recv_msg: not valid, or not HV. 0x%x 0x%x\n",
16530eca353eSBryant G. Ly buffer->valid, buffer->owner);
16540eca353eSBryant G. Ly spin_unlock_irqrestore(&hmc->lock, flags);
16550eca353eSBryant G. Ly return -1;
16560eca353eSBryant G. Ly }
16570eca353eSBryant G. Ly
16580eca353eSBryant G. Ly /* RDMA the data into the partition. */
16590eca353eSBryant G. Ly rc = h_copy_rdma(msg_len,
16600eca353eSBryant G. Ly adapter->riobn,
16610eca353eSBryant G. Ly buffer->dma_addr_remote,
16620eca353eSBryant G. Ly adapter->liobn,
16630eca353eSBryant G. Ly buffer->dma_addr_local);
16640eca353eSBryant G. Ly
16650eca353eSBryant G. Ly dev_dbg(adapter->dev, "Recv_msg: msg_len = 0x%x, buffer_id = 0x%x, queue_head = 0x%x, hmc_idx = 0x%x\n",
16660eca353eSBryant G. Ly (unsigned int)msg_len, (unsigned int)buffer_id,
16670eca353eSBryant G. Ly (unsigned int)hmc->queue_head, (unsigned int)hmc_index);
16680eca353eSBryant G. Ly buffer->msg_len = msg_len;
16690eca353eSBryant G. Ly buffer->free = 0;
16700eca353eSBryant G. Ly buffer->owner = VMC_BUF_OWNER_ALPHA;
16710eca353eSBryant G. Ly
16720eca353eSBryant G. Ly if (rc) {
16730eca353eSBryant G. Ly dev_err(adapter->dev, "Failure in recv_msg: h_copy_rdma = 0x%x\n",
16740eca353eSBryant G. Ly rc);
16750eca353eSBryant G. Ly spin_unlock_irqrestore(&hmc->lock, flags);
16760eca353eSBryant G. Ly return -1;
16770eca353eSBryant G. Ly }
16780eca353eSBryant G. Ly
16790eca353eSBryant G. Ly /* Must be locked because read operates on the same data */
16800eca353eSBryant G. Ly hmc->queue_outbound_msgs[hmc->queue_head] = buffer_id;
16810eca353eSBryant G. Ly hmc->queue_head++;
16820eca353eSBryant G. Ly if (hmc->queue_head == ibmvmc_max_buf_pool_size)
16830eca353eSBryant G. Ly hmc->queue_head = 0;
16840eca353eSBryant G. Ly
16850eca353eSBryant G. Ly if (hmc->queue_head == hmc->queue_tail)
16860eca353eSBryant G. Ly dev_err(adapter->dev, "outbound buffer queue wrapped.\n");
16870eca353eSBryant G. Ly
16880eca353eSBryant G. Ly spin_unlock_irqrestore(&hmc->lock, flags);
16890eca353eSBryant G. Ly
16900eca353eSBryant G. Ly wake_up_interruptible(&ibmvmc_read_wait);
16910eca353eSBryant G. Ly
16920eca353eSBryant G. Ly return 0;
16930eca353eSBryant G. Ly }
16940eca353eSBryant G. Ly
16950eca353eSBryant G. Ly /**
16960eca353eSBryant G. Ly * ibmvmc_process_capabilities - Process Capabilities
16970eca353eSBryant G. Ly *
16980eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
16990eca353eSBryant G. Ly * @crqp: ibmvmc_crq_msg struct
17000eca353eSBryant G. Ly *
17010eca353eSBryant G. Ly */
ibmvmc_process_capabilities(struct crq_server_adapter * adapter,struct ibmvmc_crq_msg * crqp)17020eca353eSBryant G. Ly static void ibmvmc_process_capabilities(struct crq_server_adapter *adapter,
17030eca353eSBryant G. Ly struct ibmvmc_crq_msg *crqp)
17040eca353eSBryant G. Ly {
17050eca353eSBryant G. Ly struct ibmvmc_admin_crq_msg *crq = (struct ibmvmc_admin_crq_msg *)crqp;
17060eca353eSBryant G. Ly
17070eca353eSBryant G. Ly if ((be16_to_cpu(crq->version) >> 8) !=
17080eca353eSBryant G. Ly (IBMVMC_PROTOCOL_VERSION >> 8)) {
17090eca353eSBryant G. Ly dev_err(adapter->dev, "init failed, incompatible versions 0x%x 0x%x\n",
17100eca353eSBryant G. Ly be16_to_cpu(crq->version),
17110eca353eSBryant G. Ly IBMVMC_PROTOCOL_VERSION);
17120eca353eSBryant G. Ly ibmvmc.state = ibmvmc_state_failed;
17130eca353eSBryant G. Ly return;
17140eca353eSBryant G. Ly }
17150eca353eSBryant G. Ly
17160eca353eSBryant G. Ly ibmvmc.max_mtu = min_t(u32, ibmvmc_max_mtu, be32_to_cpu(crq->max_mtu));
17170eca353eSBryant G. Ly ibmvmc.max_buffer_pool_size = min_t(u16, ibmvmc_max_buf_pool_size,
17180eca353eSBryant G. Ly be16_to_cpu(crq->pool_size));
17190eca353eSBryant G. Ly ibmvmc.max_hmc_index = min_t(u8, ibmvmc_max_hmcs, crq->max_hmc) - 1;
17200eca353eSBryant G. Ly ibmvmc.state = ibmvmc_state_ready;
17210eca353eSBryant G. Ly
17220eca353eSBryant G. Ly dev_info(adapter->dev, "Capabilities: mtu=0x%x, pool_size=0x%x, max_hmc=0x%x\n",
17230eca353eSBryant G. Ly ibmvmc.max_mtu, ibmvmc.max_buffer_pool_size,
17240eca353eSBryant G. Ly ibmvmc.max_hmc_index);
17250eca353eSBryant G. Ly }
17260eca353eSBryant G. Ly
17270eca353eSBryant G. Ly /**
17280eca353eSBryant G. Ly * ibmvmc_validate_hmc_session - Validate HMC Session
17290eca353eSBryant G. Ly *
17300eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
17310eca353eSBryant G. Ly * @crq: ibmvmc_crq_msg struct
17320eca353eSBryant G. Ly *
17330eca353eSBryant G. Ly * Return:
17340eca353eSBryant G. Ly * 0 - Success
17350eca353eSBryant G. Ly * Non-zero - Failure
17360eca353eSBryant G. Ly */
ibmvmc_validate_hmc_session(struct crq_server_adapter * adapter,struct ibmvmc_crq_msg * crq)17370eca353eSBryant G. Ly static int ibmvmc_validate_hmc_session(struct crq_server_adapter *adapter,
17380eca353eSBryant G. Ly struct ibmvmc_crq_msg *crq)
17390eca353eSBryant G. Ly {
17400eca353eSBryant G. Ly unsigned char hmc_index;
17410eca353eSBryant G. Ly
17420eca353eSBryant G. Ly hmc_index = crq->hmc_index;
17430eca353eSBryant G. Ly
17440eca353eSBryant G. Ly if (crq->hmc_session == 0)
17450eca353eSBryant G. Ly return 0;
17460eca353eSBryant G. Ly
17470eca353eSBryant G. Ly if (hmc_index > ibmvmc.max_hmc_index)
17480eca353eSBryant G. Ly return -1;
17490eca353eSBryant G. Ly
17500eca353eSBryant G. Ly if (hmcs[hmc_index].session != crq->hmc_session) {
17510eca353eSBryant G. Ly dev_warn(adapter->dev, "Drop, bad session: expected 0x%x, recv 0x%x\n",
17520eca353eSBryant G. Ly hmcs[hmc_index].session, crq->hmc_session);
17530eca353eSBryant G. Ly return -1;
17540eca353eSBryant G. Ly }
17550eca353eSBryant G. Ly
17560eca353eSBryant G. Ly return 0;
17570eca353eSBryant G. Ly }
17580eca353eSBryant G. Ly
17590eca353eSBryant G. Ly /**
17600eca353eSBryant G. Ly * ibmvmc_reset - Reset
17610eca353eSBryant G. Ly *
17620eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
17630eca353eSBryant G. Ly * @xport_event: export_event field
17640eca353eSBryant G. Ly *
17650eca353eSBryant G. Ly * Closes all HMC sessions and conditionally schedules a CRQ reset.
17660eca353eSBryant G. Ly * @xport_event: If true, the partner closed their CRQ; we don't need to reset.
17670eca353eSBryant G. Ly * If false, we need to schedule a CRQ reset.
17680eca353eSBryant G. Ly */
ibmvmc_reset(struct crq_server_adapter * adapter,bool xport_event)17690eca353eSBryant G. Ly static void ibmvmc_reset(struct crq_server_adapter *adapter, bool xport_event)
17700eca353eSBryant G. Ly {
17710eca353eSBryant G. Ly int i;
17720eca353eSBryant G. Ly
17730eca353eSBryant G. Ly if (ibmvmc.state != ibmvmc_state_sched_reset) {
17740eca353eSBryant G. Ly dev_info(adapter->dev, "*** Reset to initial state.\n");
17750eca353eSBryant G. Ly for (i = 0; i < ibmvmc_max_hmcs; i++)
17760eca353eSBryant G. Ly ibmvmc_return_hmc(&hmcs[i], xport_event);
17770eca353eSBryant G. Ly
17780eca353eSBryant G. Ly if (xport_event) {
17790eca353eSBryant G. Ly /* CRQ was closed by the partner. We don't need to do
17800eca353eSBryant G. Ly * anything except set ourself to the correct state to
17810eca353eSBryant G. Ly * handle init msgs.
17820eca353eSBryant G. Ly */
17830eca353eSBryant G. Ly ibmvmc.state = ibmvmc_state_crqinit;
17840eca353eSBryant G. Ly } else {
17850eca353eSBryant G. Ly /* The partner did not close their CRQ - instead, we're
17860eca353eSBryant G. Ly * closing the CRQ on our end. Need to schedule this
17870eca353eSBryant G. Ly * for process context, because CRQ reset may require a
17880eca353eSBryant G. Ly * sleep.
17890eca353eSBryant G. Ly *
17900eca353eSBryant G. Ly * Setting ibmvmc.state here immediately prevents
17910eca353eSBryant G. Ly * ibmvmc_open from completing until the reset
17920eca353eSBryant G. Ly * completes in process context.
17930eca353eSBryant G. Ly */
17940eca353eSBryant G. Ly ibmvmc.state = ibmvmc_state_sched_reset;
17950eca353eSBryant G. Ly dev_dbg(adapter->dev, "Device reset scheduled");
17960eca353eSBryant G. Ly wake_up_interruptible(&adapter->reset_wait_queue);
17970eca353eSBryant G. Ly }
17980eca353eSBryant G. Ly }
17990eca353eSBryant G. Ly }
18000eca353eSBryant G. Ly
18010eca353eSBryant G. Ly /**
18020eca353eSBryant G. Ly * ibmvmc_reset_task - Reset Task
18030eca353eSBryant G. Ly *
18040eca353eSBryant G. Ly * @data: Data field
18050eca353eSBryant G. Ly *
18060eca353eSBryant G. Ly * Performs a CRQ reset of the VMC device in process context.
18070eca353eSBryant G. Ly * NOTE: This function should not be called directly, use ibmvmc_reset.
18080eca353eSBryant G. Ly */
ibmvmc_reset_task(void * data)18090eca353eSBryant G. Ly static int ibmvmc_reset_task(void *data)
18100eca353eSBryant G. Ly {
18110eca353eSBryant G. Ly struct crq_server_adapter *adapter = data;
18120eca353eSBryant G. Ly int rc;
18130eca353eSBryant G. Ly
18140eca353eSBryant G. Ly set_user_nice(current, -20);
18150eca353eSBryant G. Ly
18160eca353eSBryant G. Ly while (!kthread_should_stop()) {
18170eca353eSBryant G. Ly wait_event_interruptible(adapter->reset_wait_queue,
18180eca353eSBryant G. Ly (ibmvmc.state == ibmvmc_state_sched_reset) ||
18190eca353eSBryant G. Ly kthread_should_stop());
18200eca353eSBryant G. Ly
18210eca353eSBryant G. Ly if (kthread_should_stop())
18220eca353eSBryant G. Ly break;
18230eca353eSBryant G. Ly
18240eca353eSBryant G. Ly dev_dbg(adapter->dev, "CRQ resetting in process context");
18250eca353eSBryant G. Ly tasklet_disable(&adapter->work_task);
18260eca353eSBryant G. Ly
18270eca353eSBryant G. Ly rc = ibmvmc_reset_crq_queue(adapter);
18280eca353eSBryant G. Ly
18290eca353eSBryant G. Ly if (rc != H_SUCCESS && rc != H_RESOURCE) {
18300eca353eSBryant G. Ly dev_err(adapter->dev, "Error initializing CRQ. rc = 0x%x\n",
18310eca353eSBryant G. Ly rc);
18320eca353eSBryant G. Ly ibmvmc.state = ibmvmc_state_failed;
18330eca353eSBryant G. Ly } else {
18340eca353eSBryant G. Ly ibmvmc.state = ibmvmc_state_crqinit;
18350eca353eSBryant G. Ly
18360eca353eSBryant G. Ly if (ibmvmc_send_crq(adapter, 0xC001000000000000LL, 0)
18370eca353eSBryant G. Ly != 0 && rc != H_RESOURCE)
18380eca353eSBryant G. Ly dev_warn(adapter->dev, "Failed to send initialize CRQ message\n");
18390eca353eSBryant G. Ly }
18400eca353eSBryant G. Ly
18410eca353eSBryant G. Ly vio_enable_interrupts(to_vio_dev(adapter->dev));
18420eca353eSBryant G. Ly tasklet_enable(&adapter->work_task);
18430eca353eSBryant G. Ly }
18440eca353eSBryant G. Ly
18450eca353eSBryant G. Ly return 0;
18460eca353eSBryant G. Ly }
18470eca353eSBryant G. Ly
18480eca353eSBryant G. Ly /**
18490eca353eSBryant G. Ly * ibmvmc_process_open_resp - Process Open Response
18500eca353eSBryant G. Ly *
18510eca353eSBryant G. Ly * @crq: ibmvmc_crq_msg struct
18520eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
18530eca353eSBryant G. Ly *
18540eca353eSBryant G. Ly * This command is sent by the hypervisor in response to the Interface
18550eca353eSBryant G. Ly * Open message. When this message is received, the indicated buffer is
18560eca353eSBryant G. Ly * again available for management partition use.
18570eca353eSBryant G. Ly */
ibmvmc_process_open_resp(struct ibmvmc_crq_msg * crq,struct crq_server_adapter * adapter)18580eca353eSBryant G. Ly static void ibmvmc_process_open_resp(struct ibmvmc_crq_msg *crq,
18590eca353eSBryant G. Ly struct crq_server_adapter *adapter)
18600eca353eSBryant G. Ly {
18610eca353eSBryant G. Ly unsigned char hmc_index;
18620eca353eSBryant G. Ly unsigned short buffer_id;
18630eca353eSBryant G. Ly
18640eca353eSBryant G. Ly hmc_index = crq->hmc_index;
18650eca353eSBryant G. Ly if (hmc_index > ibmvmc.max_hmc_index) {
18660eca353eSBryant G. Ly /* Why would PHYP give an index > max negotiated? */
18670eca353eSBryant G. Ly ibmvmc_reset(adapter, false);
18680eca353eSBryant G. Ly return;
18690eca353eSBryant G. Ly }
18700eca353eSBryant G. Ly
18710eca353eSBryant G. Ly if (crq->status) {
18720eca353eSBryant G. Ly dev_warn(adapter->dev, "open_resp: failed - status 0x%x\n",
18730eca353eSBryant G. Ly crq->status);
18740eca353eSBryant G. Ly ibmvmc_return_hmc(&hmcs[hmc_index], false);
18750eca353eSBryant G. Ly return;
18760eca353eSBryant G. Ly }
18770eca353eSBryant G. Ly
18780eca353eSBryant G. Ly if (hmcs[hmc_index].state == ibmhmc_state_opening) {
18790eca353eSBryant G. Ly buffer_id = be16_to_cpu(crq->var2.buffer_id);
18800eca353eSBryant G. Ly if (buffer_id >= ibmvmc.max_buffer_pool_size) {
18810eca353eSBryant G. Ly dev_err(adapter->dev, "open_resp: invalid buffer_id = 0x%x\n",
18820eca353eSBryant G. Ly buffer_id);
18830eca353eSBryant G. Ly hmcs[hmc_index].state = ibmhmc_state_failed;
18840eca353eSBryant G. Ly } else {
18850eca353eSBryant G. Ly ibmvmc_free_hmc_buffer(&hmcs[hmc_index],
18860eca353eSBryant G. Ly &hmcs[hmc_index].buffer[buffer_id]);
18870eca353eSBryant G. Ly hmcs[hmc_index].state = ibmhmc_state_ready;
18880eca353eSBryant G. Ly dev_dbg(adapter->dev, "open_resp: set hmc state = ready\n");
18890eca353eSBryant G. Ly }
18900eca353eSBryant G. Ly } else {
18910eca353eSBryant G. Ly dev_warn(adapter->dev, "open_resp: invalid hmc state (0x%x)\n",
18920eca353eSBryant G. Ly hmcs[hmc_index].state);
18930eca353eSBryant G. Ly }
18940eca353eSBryant G. Ly }
18950eca353eSBryant G. Ly
18960eca353eSBryant G. Ly /**
18970eca353eSBryant G. Ly * ibmvmc_process_close_resp - Process Close Response
18980eca353eSBryant G. Ly *
18990eca353eSBryant G. Ly * @crq: ibmvmc_crq_msg struct
19000eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
19010eca353eSBryant G. Ly *
19020eca353eSBryant G. Ly * This command is sent by the hypervisor in response to the managemant
19030eca353eSBryant G. Ly * application Interface Close message.
19040eca353eSBryant G. Ly *
19050eca353eSBryant G. Ly * If the close fails, simply reset the entire driver as the state of the VMC
19060eca353eSBryant G. Ly * must be in tough shape.
19070eca353eSBryant G. Ly */
ibmvmc_process_close_resp(struct ibmvmc_crq_msg * crq,struct crq_server_adapter * adapter)19080eca353eSBryant G. Ly static void ibmvmc_process_close_resp(struct ibmvmc_crq_msg *crq,
19090eca353eSBryant G. Ly struct crq_server_adapter *adapter)
19100eca353eSBryant G. Ly {
19110eca353eSBryant G. Ly unsigned char hmc_index;
19120eca353eSBryant G. Ly
19130eca353eSBryant G. Ly hmc_index = crq->hmc_index;
19140eca353eSBryant G. Ly if (hmc_index > ibmvmc.max_hmc_index) {
19150eca353eSBryant G. Ly ibmvmc_reset(adapter, false);
19160eca353eSBryant G. Ly return;
19170eca353eSBryant G. Ly }
19180eca353eSBryant G. Ly
19190eca353eSBryant G. Ly if (crq->status) {
19200eca353eSBryant G. Ly dev_warn(adapter->dev, "close_resp: failed - status 0x%x\n",
19210eca353eSBryant G. Ly crq->status);
19220eca353eSBryant G. Ly ibmvmc_reset(adapter, false);
19230eca353eSBryant G. Ly return;
19240eca353eSBryant G. Ly }
19250eca353eSBryant G. Ly
19260eca353eSBryant G. Ly ibmvmc_return_hmc(&hmcs[hmc_index], false);
19270eca353eSBryant G. Ly }
19280eca353eSBryant G. Ly
19290eca353eSBryant G. Ly /**
19300eca353eSBryant G. Ly * ibmvmc_crq_process - Process CRQ
19310eca353eSBryant G. Ly *
19320eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
19330eca353eSBryant G. Ly * @crq: ibmvmc_crq_msg struct
19340eca353eSBryant G. Ly *
19350eca353eSBryant G. Ly * Process the CRQ message based upon the type of message received.
19360eca353eSBryant G. Ly *
19370eca353eSBryant G. Ly */
ibmvmc_crq_process(struct crq_server_adapter * adapter,struct ibmvmc_crq_msg * crq)19380eca353eSBryant G. Ly static void ibmvmc_crq_process(struct crq_server_adapter *adapter,
19390eca353eSBryant G. Ly struct ibmvmc_crq_msg *crq)
19400eca353eSBryant G. Ly {
19410eca353eSBryant G. Ly switch (crq->type) {
19420eca353eSBryant G. Ly case VMC_MSG_CAP_RESP:
19430eca353eSBryant G. Ly dev_dbg(adapter->dev, "CRQ recv: capabilities resp (0x%x)\n",
19440eca353eSBryant G. Ly crq->type);
19450eca353eSBryant G. Ly if (ibmvmc.state == ibmvmc_state_capabilities)
19460eca353eSBryant G. Ly ibmvmc_process_capabilities(adapter, crq);
19470eca353eSBryant G. Ly else
19480eca353eSBryant G. Ly dev_warn(adapter->dev, "caps msg invalid in state 0x%x\n",
19490eca353eSBryant G. Ly ibmvmc.state);
19500eca353eSBryant G. Ly break;
19510eca353eSBryant G. Ly case VMC_MSG_OPEN_RESP:
19520eca353eSBryant G. Ly dev_dbg(adapter->dev, "CRQ recv: open resp (0x%x)\n",
19530eca353eSBryant G. Ly crq->type);
19540eca353eSBryant G. Ly if (ibmvmc_validate_hmc_session(adapter, crq) == 0)
19550eca353eSBryant G. Ly ibmvmc_process_open_resp(crq, adapter);
19560eca353eSBryant G. Ly break;
19570eca353eSBryant G. Ly case VMC_MSG_ADD_BUF:
19580eca353eSBryant G. Ly dev_dbg(adapter->dev, "CRQ recv: add buf (0x%x)\n",
19590eca353eSBryant G. Ly crq->type);
19600eca353eSBryant G. Ly if (ibmvmc_validate_hmc_session(adapter, crq) == 0)
19610eca353eSBryant G. Ly ibmvmc_add_buffer(adapter, crq);
19620eca353eSBryant G. Ly break;
19630eca353eSBryant G. Ly case VMC_MSG_REM_BUF:
19640eca353eSBryant G. Ly dev_dbg(adapter->dev, "CRQ recv: rem buf (0x%x)\n",
19650eca353eSBryant G. Ly crq->type);
19660eca353eSBryant G. Ly if (ibmvmc_validate_hmc_session(adapter, crq) == 0)
19670eca353eSBryant G. Ly ibmvmc_rem_buffer(adapter, crq);
19680eca353eSBryant G. Ly break;
19690eca353eSBryant G. Ly case VMC_MSG_SIGNAL:
19700eca353eSBryant G. Ly dev_dbg(adapter->dev, "CRQ recv: signal msg (0x%x)\n",
19710eca353eSBryant G. Ly crq->type);
19720eca353eSBryant G. Ly if (ibmvmc_validate_hmc_session(adapter, crq) == 0)
19730eca353eSBryant G. Ly ibmvmc_recv_msg(adapter, crq);
19740eca353eSBryant G. Ly break;
19750eca353eSBryant G. Ly case VMC_MSG_CLOSE_RESP:
19760eca353eSBryant G. Ly dev_dbg(adapter->dev, "CRQ recv: close resp (0x%x)\n",
19770eca353eSBryant G. Ly crq->type);
19780eca353eSBryant G. Ly if (ibmvmc_validate_hmc_session(adapter, crq) == 0)
19790eca353eSBryant G. Ly ibmvmc_process_close_resp(crq, adapter);
19800eca353eSBryant G. Ly break;
19810eca353eSBryant G. Ly case VMC_MSG_CAP:
19820eca353eSBryant G. Ly case VMC_MSG_OPEN:
19830eca353eSBryant G. Ly case VMC_MSG_CLOSE:
19840eca353eSBryant G. Ly case VMC_MSG_ADD_BUF_RESP:
19850eca353eSBryant G. Ly case VMC_MSG_REM_BUF_RESP:
19860eca353eSBryant G. Ly dev_warn(adapter->dev, "CRQ recv: unexpected msg (0x%x)\n",
19870eca353eSBryant G. Ly crq->type);
19880eca353eSBryant G. Ly break;
19890eca353eSBryant G. Ly default:
19900eca353eSBryant G. Ly dev_warn(adapter->dev, "CRQ recv: unknown msg (0x%x)\n",
19910eca353eSBryant G. Ly crq->type);
19920eca353eSBryant G. Ly break;
19930eca353eSBryant G. Ly }
19940eca353eSBryant G. Ly }
19950eca353eSBryant G. Ly
19960eca353eSBryant G. Ly /**
19970eca353eSBryant G. Ly * ibmvmc_handle_crq_init - Handle CRQ Init
19980eca353eSBryant G. Ly *
19990eca353eSBryant G. Ly * @crq: ibmvmc_crq_msg struct
20000eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
20010eca353eSBryant G. Ly *
20020eca353eSBryant G. Ly * Handle the type of crq initialization based on whether
20030eca353eSBryant G. Ly * it is a message or a response.
20040eca353eSBryant G. Ly *
20050eca353eSBryant G. Ly */
ibmvmc_handle_crq_init(struct ibmvmc_crq_msg * crq,struct crq_server_adapter * adapter)20060eca353eSBryant G. Ly static void ibmvmc_handle_crq_init(struct ibmvmc_crq_msg *crq,
20070eca353eSBryant G. Ly struct crq_server_adapter *adapter)
20080eca353eSBryant G. Ly {
20090eca353eSBryant G. Ly switch (crq->type) {
20100eca353eSBryant G. Ly case 0x01: /* Initialization message */
20110eca353eSBryant G. Ly dev_dbg(adapter->dev, "CRQ recv: CRQ init msg - state 0x%x\n",
20120eca353eSBryant G. Ly ibmvmc.state);
20130eca353eSBryant G. Ly if (ibmvmc.state == ibmvmc_state_crqinit) {
20140eca353eSBryant G. Ly /* Send back a response */
20150eca353eSBryant G. Ly if (ibmvmc_send_crq(adapter, 0xC002000000000000,
20160eca353eSBryant G. Ly 0) == 0)
20170eca353eSBryant G. Ly ibmvmc_send_capabilities(adapter);
20180eca353eSBryant G. Ly else
20190eca353eSBryant G. Ly dev_err(adapter->dev, " Unable to send init rsp\n");
20200eca353eSBryant G. Ly } else {
20210eca353eSBryant G. Ly dev_err(adapter->dev, "Invalid state 0x%x mtu = 0x%x\n",
20220eca353eSBryant G. Ly ibmvmc.state, ibmvmc.max_mtu);
20230eca353eSBryant G. Ly }
20240eca353eSBryant G. Ly
20250eca353eSBryant G. Ly break;
20260eca353eSBryant G. Ly case 0x02: /* Initialization response */
20270eca353eSBryant G. Ly dev_dbg(adapter->dev, "CRQ recv: initialization resp msg - state 0x%x\n",
20280eca353eSBryant G. Ly ibmvmc.state);
20290eca353eSBryant G. Ly if (ibmvmc.state == ibmvmc_state_crqinit)
20300eca353eSBryant G. Ly ibmvmc_send_capabilities(adapter);
20310eca353eSBryant G. Ly break;
20320eca353eSBryant G. Ly default:
20330eca353eSBryant G. Ly dev_warn(adapter->dev, "Unknown crq message type 0x%lx\n",
20340eca353eSBryant G. Ly (unsigned long)crq->type);
20350eca353eSBryant G. Ly }
20360eca353eSBryant G. Ly }
20370eca353eSBryant G. Ly
20380eca353eSBryant G. Ly /**
20390eca353eSBryant G. Ly * ibmvmc_handle_crq - Handle CRQ
20400eca353eSBryant G. Ly *
20410eca353eSBryant G. Ly * @crq: ibmvmc_crq_msg struct
20420eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
20430eca353eSBryant G. Ly *
20440eca353eSBryant G. Ly * Read the command elements from the command queue and execute the
20450eca353eSBryant G. Ly * requests based upon the type of crq message.
20460eca353eSBryant G. Ly *
20470eca353eSBryant G. Ly */
ibmvmc_handle_crq(struct ibmvmc_crq_msg * crq,struct crq_server_adapter * adapter)20480eca353eSBryant G. Ly static void ibmvmc_handle_crq(struct ibmvmc_crq_msg *crq,
20490eca353eSBryant G. Ly struct crq_server_adapter *adapter)
20500eca353eSBryant G. Ly {
20510eca353eSBryant G. Ly switch (crq->valid) {
20520eca353eSBryant G. Ly case 0xC0: /* initialization */
20530eca353eSBryant G. Ly ibmvmc_handle_crq_init(crq, adapter);
20540eca353eSBryant G. Ly break;
20550eca353eSBryant G. Ly case 0xFF: /* Hypervisor telling us the connection is closed */
20560eca353eSBryant G. Ly dev_warn(adapter->dev, "CRQ recv: virtual adapter failed - resetting.\n");
20570eca353eSBryant G. Ly ibmvmc_reset(adapter, true);
20580eca353eSBryant G. Ly break;
20590eca353eSBryant G. Ly case 0x80: /* real payload */
20600eca353eSBryant G. Ly ibmvmc_crq_process(adapter, crq);
20610eca353eSBryant G. Ly break;
20620eca353eSBryant G. Ly default:
20630eca353eSBryant G. Ly dev_warn(adapter->dev, "CRQ recv: unknown msg 0x%02x.\n",
20640eca353eSBryant G. Ly crq->valid);
20650eca353eSBryant G. Ly break;
20660eca353eSBryant G. Ly }
20670eca353eSBryant G. Ly }
20680eca353eSBryant G. Ly
ibmvmc_task(unsigned long data)20690eca353eSBryant G. Ly static void ibmvmc_task(unsigned long data)
20700eca353eSBryant G. Ly {
20710eca353eSBryant G. Ly struct crq_server_adapter *adapter =
20720eca353eSBryant G. Ly (struct crq_server_adapter *)data;
20730eca353eSBryant G. Ly struct vio_dev *vdev = to_vio_dev(adapter->dev);
20740eca353eSBryant G. Ly struct ibmvmc_crq_msg *crq;
20750eca353eSBryant G. Ly int done = 0;
20760eca353eSBryant G. Ly
20770eca353eSBryant G. Ly while (!done) {
20780eca353eSBryant G. Ly /* Pull all the valid messages off the CRQ */
20790eca353eSBryant G. Ly while ((crq = crq_queue_next_crq(&adapter->queue)) != NULL) {
20800eca353eSBryant G. Ly ibmvmc_handle_crq(crq, adapter);
20810eca353eSBryant G. Ly crq->valid = 0x00;
20820eca353eSBryant G. Ly /* CRQ reset was requested, stop processing CRQs.
20830eca353eSBryant G. Ly * Interrupts will be re-enabled by the reset task.
20840eca353eSBryant G. Ly */
20850eca353eSBryant G. Ly if (ibmvmc.state == ibmvmc_state_sched_reset)
20860eca353eSBryant G. Ly return;
20870eca353eSBryant G. Ly }
20880eca353eSBryant G. Ly
20890eca353eSBryant G. Ly vio_enable_interrupts(vdev);
20900eca353eSBryant G. Ly crq = crq_queue_next_crq(&adapter->queue);
20910eca353eSBryant G. Ly if (crq) {
20920eca353eSBryant G. Ly vio_disable_interrupts(vdev);
20930eca353eSBryant G. Ly ibmvmc_handle_crq(crq, adapter);
20940eca353eSBryant G. Ly crq->valid = 0x00;
20950eca353eSBryant G. Ly /* CRQ reset was requested, stop processing CRQs.
20960eca353eSBryant G. Ly * Interrupts will be re-enabled by the reset task.
20970eca353eSBryant G. Ly */
20980eca353eSBryant G. Ly if (ibmvmc.state == ibmvmc_state_sched_reset)
20990eca353eSBryant G. Ly return;
21000eca353eSBryant G. Ly } else {
21010eca353eSBryant G. Ly done = 1;
21020eca353eSBryant G. Ly }
21030eca353eSBryant G. Ly }
21040eca353eSBryant G. Ly }
21050eca353eSBryant G. Ly
21060eca353eSBryant G. Ly /**
21070eca353eSBryant G. Ly * ibmvmc_init_crq_queue - Init CRQ Queue
21080eca353eSBryant G. Ly *
21090eca353eSBryant G. Ly * @adapter: crq_server_adapter struct
21100eca353eSBryant G. Ly *
21110eca353eSBryant G. Ly * Return:
21120eca353eSBryant G. Ly * 0 - Success
21130eca353eSBryant G. Ly * Non-zero - Failure
21140eca353eSBryant G. Ly */
ibmvmc_init_crq_queue(struct crq_server_adapter * adapter)21150eca353eSBryant G. Ly static int ibmvmc_init_crq_queue(struct crq_server_adapter *adapter)
21160eca353eSBryant G. Ly {
21170eca353eSBryant G. Ly struct vio_dev *vdev = to_vio_dev(adapter->dev);
21180eca353eSBryant G. Ly struct crq_queue *queue = &adapter->queue;
21190eca353eSBryant G. Ly int rc = 0;
21200eca353eSBryant G. Ly int retrc = 0;
21210eca353eSBryant G. Ly
21220eca353eSBryant G. Ly queue->msgs = (struct ibmvmc_crq_msg *)get_zeroed_page(GFP_KERNEL);
21230eca353eSBryant G. Ly
21240eca353eSBryant G. Ly if (!queue->msgs)
21250eca353eSBryant G. Ly goto malloc_failed;
21260eca353eSBryant G. Ly
21270eca353eSBryant G. Ly queue->size = PAGE_SIZE / sizeof(*queue->msgs);
21280eca353eSBryant G. Ly
21290eca353eSBryant G. Ly queue->msg_token = dma_map_single(adapter->dev, queue->msgs,
21300eca353eSBryant G. Ly queue->size * sizeof(*queue->msgs),
21310eca353eSBryant G. Ly DMA_BIDIRECTIONAL);
21320eca353eSBryant G. Ly
21330eca353eSBryant G. Ly if (dma_mapping_error(adapter->dev, queue->msg_token))
21340eca353eSBryant G. Ly goto map_failed;
21350eca353eSBryant G. Ly
21360eca353eSBryant G. Ly retrc = plpar_hcall_norets(H_REG_CRQ,
21370eca353eSBryant G. Ly vdev->unit_address,
21380eca353eSBryant G. Ly queue->msg_token, PAGE_SIZE);
2139c55e9318SBryant G. Ly rc = retrc;
21400eca353eSBryant G. Ly
21410eca353eSBryant G. Ly if (rc == H_RESOURCE)
21420eca353eSBryant G. Ly rc = ibmvmc_reset_crq_queue(adapter);
21430eca353eSBryant G. Ly
21440eca353eSBryant G. Ly if (rc == 2) {
21450eca353eSBryant G. Ly dev_warn(adapter->dev, "Partner adapter not ready\n");
21460eca353eSBryant G. Ly retrc = 0;
21470eca353eSBryant G. Ly } else if (rc != 0) {
21480eca353eSBryant G. Ly dev_err(adapter->dev, "Error %d opening adapter\n", rc);
21490eca353eSBryant G. Ly goto reg_crq_failed;
21500eca353eSBryant G. Ly }
21510eca353eSBryant G. Ly
21520eca353eSBryant G. Ly queue->cur = 0;
21530eca353eSBryant G. Ly spin_lock_init(&queue->lock);
21540eca353eSBryant G. Ly
21550eca353eSBryant G. Ly tasklet_init(&adapter->work_task, ibmvmc_task, (unsigned long)adapter);
21560eca353eSBryant G. Ly
21570eca353eSBryant G. Ly if (request_irq(vdev->irq,
21580eca353eSBryant G. Ly ibmvmc_handle_event,
21590eca353eSBryant G. Ly 0, "ibmvmc", (void *)adapter) != 0) {
21600eca353eSBryant G. Ly dev_err(adapter->dev, "couldn't register irq 0x%x\n",
21610eca353eSBryant G. Ly vdev->irq);
21620eca353eSBryant G. Ly goto req_irq_failed;
21630eca353eSBryant G. Ly }
21640eca353eSBryant G. Ly
21650eca353eSBryant G. Ly rc = vio_enable_interrupts(vdev);
21660eca353eSBryant G. Ly if (rc != 0) {
21670eca353eSBryant G. Ly dev_err(adapter->dev, "Error %d enabling interrupts!!!\n", rc);
21680eca353eSBryant G. Ly goto req_irq_failed;
21690eca353eSBryant G. Ly }
21700eca353eSBryant G. Ly
21710eca353eSBryant G. Ly return retrc;
21720eca353eSBryant G. Ly
21730eca353eSBryant G. Ly req_irq_failed:
21740eca353eSBryant G. Ly /* Cannot have any work since we either never got our IRQ registered,
21750eca353eSBryant G. Ly * or never got interrupts enabled
21760eca353eSBryant G. Ly */
21770eca353eSBryant G. Ly tasklet_kill(&adapter->work_task);
21780eca353eSBryant G. Ly h_free_crq(vdev->unit_address);
21790eca353eSBryant G. Ly reg_crq_failed:
21800eca353eSBryant G. Ly dma_unmap_single(adapter->dev,
21810eca353eSBryant G. Ly queue->msg_token,
21820eca353eSBryant G. Ly queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
21830eca353eSBryant G. Ly map_failed:
21840eca353eSBryant G. Ly free_page((unsigned long)queue->msgs);
21850eca353eSBryant G. Ly malloc_failed:
21860eca353eSBryant G. Ly return -ENOMEM;
21870eca353eSBryant G. Ly }
21880eca353eSBryant G. Ly
21890eca353eSBryant G. Ly /* Fill in the liobn and riobn fields on the adapter */
read_dma_window(struct vio_dev * vdev,struct crq_server_adapter * adapter)21900eca353eSBryant G. Ly static int read_dma_window(struct vio_dev *vdev,
21910eca353eSBryant G. Ly struct crq_server_adapter *adapter)
21920eca353eSBryant G. Ly {
21930eca353eSBryant G. Ly const __be32 *dma_window;
21940eca353eSBryant G. Ly const __be32 *prop;
21950eca353eSBryant G. Ly
21960eca353eSBryant G. Ly /* TODO Using of_parse_dma_window would be better, but it doesn't give
21970eca353eSBryant G. Ly * a way to read multiple windows without already knowing the size of
21980eca353eSBryant G. Ly * a window or the number of windows
21990eca353eSBryant G. Ly */
22000eca353eSBryant G. Ly dma_window =
22010eca353eSBryant G. Ly (const __be32 *)vio_get_attribute(vdev, "ibm,my-dma-window",
22020eca353eSBryant G. Ly NULL);
22030eca353eSBryant G. Ly if (!dma_window) {
22040eca353eSBryant G. Ly dev_warn(adapter->dev, "Couldn't find ibm,my-dma-window property\n");
22050eca353eSBryant G. Ly return -1;
22060eca353eSBryant G. Ly }
22070eca353eSBryant G. Ly
22080eca353eSBryant G. Ly adapter->liobn = be32_to_cpu(*dma_window);
22090eca353eSBryant G. Ly dma_window++;
22100eca353eSBryant G. Ly
22110eca353eSBryant G. Ly prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-address-cells",
22120eca353eSBryant G. Ly NULL);
22130eca353eSBryant G. Ly if (!prop) {
22140eca353eSBryant G. Ly dev_warn(adapter->dev, "Couldn't find ibm,#dma-address-cells property\n");
22150eca353eSBryant G. Ly dma_window++;
22160eca353eSBryant G. Ly } else {
22170eca353eSBryant G. Ly dma_window += be32_to_cpu(*prop);
22180eca353eSBryant G. Ly }
22190eca353eSBryant G. Ly
22200eca353eSBryant G. Ly prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-size-cells",
22210eca353eSBryant G. Ly NULL);
22220eca353eSBryant G. Ly if (!prop) {
22230eca353eSBryant G. Ly dev_warn(adapter->dev, "Couldn't find ibm,#dma-size-cells property\n");
22240eca353eSBryant G. Ly dma_window++;
22250eca353eSBryant G. Ly } else {
22260eca353eSBryant G. Ly dma_window += be32_to_cpu(*prop);
22270eca353eSBryant G. Ly }
22280eca353eSBryant G. Ly
22290eca353eSBryant G. Ly /* dma_window should point to the second window now */
22300eca353eSBryant G. Ly adapter->riobn = be32_to_cpu(*dma_window);
22310eca353eSBryant G. Ly
22320eca353eSBryant G. Ly return 0;
22330eca353eSBryant G. Ly }
22340eca353eSBryant G. Ly
ibmvmc_probe(struct vio_dev * vdev,const struct vio_device_id * id)22350eca353eSBryant G. Ly static int ibmvmc_probe(struct vio_dev *vdev, const struct vio_device_id *id)
22360eca353eSBryant G. Ly {
22370eca353eSBryant G. Ly struct crq_server_adapter *adapter = &ibmvmc_adapter;
22380eca353eSBryant G. Ly int rc;
22390eca353eSBryant G. Ly
22400eca353eSBryant G. Ly dev_set_drvdata(&vdev->dev, NULL);
22410eca353eSBryant G. Ly memset(adapter, 0, sizeof(*adapter));
22420eca353eSBryant G. Ly adapter->dev = &vdev->dev;
22430eca353eSBryant G. Ly
22440eca353eSBryant G. Ly dev_info(adapter->dev, "Probe for UA 0x%x\n", vdev->unit_address);
22450eca353eSBryant G. Ly
22460eca353eSBryant G. Ly rc = read_dma_window(vdev, adapter);
22470eca353eSBryant G. Ly if (rc != 0) {
22480eca353eSBryant G. Ly ibmvmc.state = ibmvmc_state_failed;
22490eca353eSBryant G. Ly return -1;
22500eca353eSBryant G. Ly }
22510eca353eSBryant G. Ly
22520eca353eSBryant G. Ly dev_dbg(adapter->dev, "Probe: liobn 0x%x, riobn 0x%x\n",
22530eca353eSBryant G. Ly adapter->liobn, adapter->riobn);
22540eca353eSBryant G. Ly
22550eca353eSBryant G. Ly init_waitqueue_head(&adapter->reset_wait_queue);
22560eca353eSBryant G. Ly adapter->reset_task = kthread_run(ibmvmc_reset_task, adapter, "ibmvmc");
22570eca353eSBryant G. Ly if (IS_ERR(adapter->reset_task)) {
22580eca353eSBryant G. Ly dev_err(adapter->dev, "Failed to start reset thread\n");
22590eca353eSBryant G. Ly ibmvmc.state = ibmvmc_state_failed;
22600eca353eSBryant G. Ly rc = PTR_ERR(adapter->reset_task);
22610eca353eSBryant G. Ly adapter->reset_task = NULL;
22620eca353eSBryant G. Ly return rc;
22630eca353eSBryant G. Ly }
22640eca353eSBryant G. Ly
22650eca353eSBryant G. Ly rc = ibmvmc_init_crq_queue(adapter);
22660eca353eSBryant G. Ly if (rc != 0 && rc != H_RESOURCE) {
22670eca353eSBryant G. Ly dev_err(adapter->dev, "Error initializing CRQ. rc = 0x%x\n",
22680eca353eSBryant G. Ly rc);
22690eca353eSBryant G. Ly ibmvmc.state = ibmvmc_state_failed;
22700eca353eSBryant G. Ly goto crq_failed;
22710eca353eSBryant G. Ly }
22720eca353eSBryant G. Ly
22730eca353eSBryant G. Ly ibmvmc.state = ibmvmc_state_crqinit;
22740eca353eSBryant G. Ly
22750eca353eSBryant G. Ly /* Try to send an initialization message. Note that this is allowed
22760eca353eSBryant G. Ly * to fail if the other end is not acive. In that case we just wait
22770eca353eSBryant G. Ly * for the other side to initialize.
22780eca353eSBryant G. Ly */
22790eca353eSBryant G. Ly if (ibmvmc_send_crq(adapter, 0xC001000000000000LL, 0) != 0 &&
22800eca353eSBryant G. Ly rc != H_RESOURCE)
22810eca353eSBryant G. Ly dev_warn(adapter->dev, "Failed to send initialize CRQ message\n");
22820eca353eSBryant G. Ly
22830eca353eSBryant G. Ly dev_set_drvdata(&vdev->dev, adapter);
22840eca353eSBryant G. Ly
22850eca353eSBryant G. Ly return 0;
22860eca353eSBryant G. Ly
22870eca353eSBryant G. Ly crq_failed:
22880eca353eSBryant G. Ly kthread_stop(adapter->reset_task);
22890eca353eSBryant G. Ly adapter->reset_task = NULL;
22900eca353eSBryant G. Ly return -EPERM;
22910eca353eSBryant G. Ly }
22920eca353eSBryant G. Ly
ibmvmc_remove(struct vio_dev * vdev)2293386a966fSUwe Kleine-König static void ibmvmc_remove(struct vio_dev *vdev)
22940eca353eSBryant G. Ly {
22950eca353eSBryant G. Ly struct crq_server_adapter *adapter = dev_get_drvdata(&vdev->dev);
22960eca353eSBryant G. Ly
22970eca353eSBryant G. Ly dev_info(adapter->dev, "Entering remove for UA 0x%x\n",
22980eca353eSBryant G. Ly vdev->unit_address);
22990eca353eSBryant G. Ly ibmvmc_release_crq_queue(adapter);
23000eca353eSBryant G. Ly }
23010eca353eSBryant G. Ly
23020eca353eSBryant G. Ly static struct vio_device_id ibmvmc_device_table[] = {
23030eca353eSBryant G. Ly { "ibm,vmc", "IBM,vmc" },
23040eca353eSBryant G. Ly { "", "" }
23050eca353eSBryant G. Ly };
23060eca353eSBryant G. Ly MODULE_DEVICE_TABLE(vio, ibmvmc_device_table);
23070eca353eSBryant G. Ly
23080eca353eSBryant G. Ly static struct vio_driver ibmvmc_driver = {
23090eca353eSBryant G. Ly .name = ibmvmc_driver_name,
23100eca353eSBryant G. Ly .id_table = ibmvmc_device_table,
23110eca353eSBryant G. Ly .probe = ibmvmc_probe,
23120eca353eSBryant G. Ly .remove = ibmvmc_remove,
23130eca353eSBryant G. Ly };
23140eca353eSBryant G. Ly
ibmvmc_scrub_module_parms(void)23150eca353eSBryant G. Ly static void __init ibmvmc_scrub_module_parms(void)
23160eca353eSBryant G. Ly {
23170eca353eSBryant G. Ly if (ibmvmc_max_mtu > MAX_MTU) {
23180eca353eSBryant G. Ly pr_warn("ibmvmc: Max MTU reduced to %d\n", MAX_MTU);
23190eca353eSBryant G. Ly ibmvmc_max_mtu = MAX_MTU;
23200eca353eSBryant G. Ly } else if (ibmvmc_max_mtu < MIN_MTU) {
23210eca353eSBryant G. Ly pr_warn("ibmvmc: Max MTU increased to %d\n", MIN_MTU);
23220eca353eSBryant G. Ly ibmvmc_max_mtu = MIN_MTU;
23230eca353eSBryant G. Ly }
23240eca353eSBryant G. Ly
23250eca353eSBryant G. Ly if (ibmvmc_max_buf_pool_size > MAX_BUF_POOL_SIZE) {
23260eca353eSBryant G. Ly pr_warn("ibmvmc: Max buffer pool size reduced to %d\n",
23270eca353eSBryant G. Ly MAX_BUF_POOL_SIZE);
23280eca353eSBryant G. Ly ibmvmc_max_buf_pool_size = MAX_BUF_POOL_SIZE;
23290eca353eSBryant G. Ly } else if (ibmvmc_max_buf_pool_size < MIN_BUF_POOL_SIZE) {
23300eca353eSBryant G. Ly pr_warn("ibmvmc: Max buffer pool size increased to %d\n",
23310eca353eSBryant G. Ly MIN_BUF_POOL_SIZE);
23320eca353eSBryant G. Ly ibmvmc_max_buf_pool_size = MIN_BUF_POOL_SIZE;
23330eca353eSBryant G. Ly }
23340eca353eSBryant G. Ly
23350eca353eSBryant G. Ly if (ibmvmc_max_hmcs > MAX_HMCS) {
23360eca353eSBryant G. Ly pr_warn("ibmvmc: Max HMCs reduced to %d\n", MAX_HMCS);
23370eca353eSBryant G. Ly ibmvmc_max_hmcs = MAX_HMCS;
23380eca353eSBryant G. Ly } else if (ibmvmc_max_hmcs < MIN_HMCS) {
23390eca353eSBryant G. Ly pr_warn("ibmvmc: Max HMCs increased to %d\n", MIN_HMCS);
23400eca353eSBryant G. Ly ibmvmc_max_hmcs = MIN_HMCS;
23410eca353eSBryant G. Ly }
23420eca353eSBryant G. Ly }
23430eca353eSBryant G. Ly
23440eca353eSBryant G. Ly static struct miscdevice ibmvmc_miscdev = {
23450eca353eSBryant G. Ly .name = ibmvmc_driver_name,
23460eca353eSBryant G. Ly .minor = MISC_DYNAMIC_MINOR,
23470eca353eSBryant G. Ly .fops = &ibmvmc_fops,
23480eca353eSBryant G. Ly };
23490eca353eSBryant G. Ly
ibmvmc_module_init(void)23500eca353eSBryant G. Ly static int __init ibmvmc_module_init(void)
23510eca353eSBryant G. Ly {
23520eca353eSBryant G. Ly int rc, i, j;
23530eca353eSBryant G. Ly
23540eca353eSBryant G. Ly ibmvmc.state = ibmvmc_state_initial;
23550eca353eSBryant G. Ly pr_info("ibmvmc: version %s\n", IBMVMC_DRIVER_VERSION);
23560eca353eSBryant G. Ly
23570eca353eSBryant G. Ly rc = misc_register(&ibmvmc_miscdev);
23580eca353eSBryant G. Ly if (rc) {
23590eca353eSBryant G. Ly pr_err("ibmvmc: misc registration failed\n");
23600eca353eSBryant G. Ly goto misc_register_failed;
23610eca353eSBryant G. Ly }
23620eca353eSBryant G. Ly pr_info("ibmvmc: node %d:%d\n", MISC_MAJOR,
23630eca353eSBryant G. Ly ibmvmc_miscdev.minor);
23640eca353eSBryant G. Ly
23650eca353eSBryant G. Ly /* Initialize data structures */
23660eca353eSBryant G. Ly memset(hmcs, 0, sizeof(struct ibmvmc_hmc) * MAX_HMCS);
23670eca353eSBryant G. Ly for (i = 0; i < MAX_HMCS; i++) {
23680eca353eSBryant G. Ly spin_lock_init(&hmcs[i].lock);
23690eca353eSBryant G. Ly hmcs[i].state = ibmhmc_state_free;
23700eca353eSBryant G. Ly for (j = 0; j < MAX_BUF_POOL_SIZE; j++)
23710eca353eSBryant G. Ly hmcs[i].queue_outbound_msgs[j] = VMC_INVALID_BUFFER_ID;
23720eca353eSBryant G. Ly }
23730eca353eSBryant G. Ly
23740eca353eSBryant G. Ly /* Sanity check module parms */
23750eca353eSBryant G. Ly ibmvmc_scrub_module_parms();
23760eca353eSBryant G. Ly
23770eca353eSBryant G. Ly /*
23780eca353eSBryant G. Ly * Initialize some reasonable values. Might be negotiated smaller
23790eca353eSBryant G. Ly * values during the capabilities exchange.
23800eca353eSBryant G. Ly */
23810eca353eSBryant G. Ly ibmvmc.max_mtu = ibmvmc_max_mtu;
23820eca353eSBryant G. Ly ibmvmc.max_buffer_pool_size = ibmvmc_max_buf_pool_size;
23830eca353eSBryant G. Ly ibmvmc.max_hmc_index = ibmvmc_max_hmcs - 1;
23840eca353eSBryant G. Ly
23850eca353eSBryant G. Ly rc = vio_register_driver(&ibmvmc_driver);
23860eca353eSBryant G. Ly
23870eca353eSBryant G. Ly if (rc) {
23880eca353eSBryant G. Ly pr_err("ibmvmc: rc %d from vio_register_driver\n", rc);
23890eca353eSBryant G. Ly goto vio_reg_failed;
23900eca353eSBryant G. Ly }
23910eca353eSBryant G. Ly
23920eca353eSBryant G. Ly return 0;
23930eca353eSBryant G. Ly
23940eca353eSBryant G. Ly vio_reg_failed:
23950eca353eSBryant G. Ly misc_deregister(&ibmvmc_miscdev);
23960eca353eSBryant G. Ly misc_register_failed:
23970eca353eSBryant G. Ly return rc;
23980eca353eSBryant G. Ly }
23990eca353eSBryant G. Ly
ibmvmc_module_exit(void)24000eca353eSBryant G. Ly static void __exit ibmvmc_module_exit(void)
24010eca353eSBryant G. Ly {
24020eca353eSBryant G. Ly pr_info("ibmvmc: module exit\n");
24030eca353eSBryant G. Ly vio_unregister_driver(&ibmvmc_driver);
24040eca353eSBryant G. Ly misc_deregister(&ibmvmc_miscdev);
24050eca353eSBryant G. Ly }
24060eca353eSBryant G. Ly
24070eca353eSBryant G. Ly module_init(ibmvmc_module_init);
24080eca353eSBryant G. Ly module_exit(ibmvmc_module_exit);
24090eca353eSBryant G. Ly
24100eca353eSBryant G. Ly module_param_named(buf_pool_size, ibmvmc_max_buf_pool_size,
24110eca353eSBryant G. Ly int, 0644);
24120eca353eSBryant G. Ly MODULE_PARM_DESC(buf_pool_size, "Buffer pool size");
24130eca353eSBryant G. Ly module_param_named(max_hmcs, ibmvmc_max_hmcs, int, 0644);
24140eca353eSBryant G. Ly MODULE_PARM_DESC(max_hmcs, "Max HMCs");
24150eca353eSBryant G. Ly module_param_named(max_mtu, ibmvmc_max_mtu, int, 0644);
24160eca353eSBryant G. Ly MODULE_PARM_DESC(max_mtu, "Max MTU");
24170eca353eSBryant G. Ly
24180eca353eSBryant G. Ly MODULE_AUTHOR("Steven Royer <seroyer@linux.vnet.ibm.com>");
24190eca353eSBryant G. Ly MODULE_DESCRIPTION("IBM VMC");
24200eca353eSBryant G. Ly MODULE_VERSION(IBMVMC_DRIVER_VERSION);
24210eca353eSBryant G. Ly MODULE_LICENSE("GPL v2");
2422