xref: /linux/drivers/misc/ibmvmc.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
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*5776aa6bSJeff Layton 	inode_set_mtime_to_ts(inode, 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 
12522801baddSJustin Stitt 	strscpy(print_buffer, hmc->hmc_id, sizeof(print_buffer));
12530eca353eSBryant G. Ly 	pr_info("ibmvmc: sethmcid: Set HMC ID: \"%s\"\n", print_buffer);
12540eca353eSBryant G. Ly 
12550eca353eSBryant G. Ly 	memcpy(buffer->real_addr_local, hmc->hmc_id, HMC_ID_LEN);
12560eca353eSBryant G. Ly 	/* RDMA over ID, send open msg, change state to ibmhmc_state_opening */
12570eca353eSBryant G. Ly 	rc = ibmvmc_send_open(buffer, hmc);
12580eca353eSBryant G. Ly 
12590eca353eSBryant G. Ly 	return rc;
12600eca353eSBryant G. Ly }
12610eca353eSBryant G. Ly 
12620eca353eSBryant G. Ly /**
12630eca353eSBryant G. Ly  * ibmvmc_ioctl_query - IOCTL Query
12640eca353eSBryant G. Ly  *
12650eca353eSBryant G. Ly  * @session:	ibmvmc_file_session struct
12660eca353eSBryant G. Ly  * @ret_struct:	ibmvmc_query_struct
12670eca353eSBryant G. Ly  *
12680eca353eSBryant G. Ly  * Return:
12690eca353eSBryant G. Ly  *	0 - Success
12700eca353eSBryant G. Ly  *	Non-zero - Failure
12710eca353eSBryant G. Ly  */
ibmvmc_ioctl_query(struct ibmvmc_file_session * session,struct ibmvmc_query_struct __user * ret_struct)12720eca353eSBryant G. Ly static long ibmvmc_ioctl_query(struct ibmvmc_file_session *session,
12730eca353eSBryant G. Ly 			       struct ibmvmc_query_struct __user *ret_struct)
12740eca353eSBryant G. Ly {
12750eca353eSBryant G. Ly 	struct ibmvmc_query_struct query_struct;
12760eca353eSBryant G. Ly 	size_t bytes;
12770eca353eSBryant G. Ly 
12780eca353eSBryant G. Ly 	memset(&query_struct, 0, sizeof(query_struct));
12790eca353eSBryant G. Ly 	query_struct.have_vmc = (ibmvmc.state > ibmvmc_state_initial);
12800eca353eSBryant G. Ly 	query_struct.state = ibmvmc.state;
12810eca353eSBryant G. Ly 	query_struct.vmc_drc_index = ibmvmc.vmc_drc_index;
12820eca353eSBryant G. Ly 
12830eca353eSBryant G. Ly 	bytes = copy_to_user(ret_struct, &query_struct,
12840eca353eSBryant G. Ly 			     sizeof(query_struct));
12850eca353eSBryant G. Ly 	if (bytes)
12860eca353eSBryant G. Ly 		return -EFAULT;
12870eca353eSBryant G. Ly 
12880eca353eSBryant G. Ly 	return 0;
12890eca353eSBryant G. Ly }
12900eca353eSBryant G. Ly 
12910eca353eSBryant G. Ly /**
12920eca353eSBryant G. Ly  * ibmvmc_ioctl_requestvmc - IOCTL Request VMC
12930eca353eSBryant G. Ly  *
12940eca353eSBryant G. Ly  * @session:	ibmvmc_file_session struct
12950eca353eSBryant G. Ly  * @ret_vmc_index:	VMC Index
12960eca353eSBryant G. Ly  *
12970eca353eSBryant G. Ly  * Return:
12980eca353eSBryant G. Ly  *	0 - Success
12990eca353eSBryant G. Ly  *	Non-zero - Failure
13000eca353eSBryant G. Ly  */
ibmvmc_ioctl_requestvmc(struct ibmvmc_file_session * session,u32 __user * ret_vmc_index)13010eca353eSBryant G. Ly static long ibmvmc_ioctl_requestvmc(struct ibmvmc_file_session *session,
13020eca353eSBryant G. Ly 				    u32 __user *ret_vmc_index)
13030eca353eSBryant G. Ly {
13040eca353eSBryant G. Ly 	/* TODO: (adreznec) Add locking to control multiple process access */
13050eca353eSBryant G. Ly 	size_t bytes;
13060eca353eSBryant G. Ly 	long rc;
13070eca353eSBryant G. Ly 	u32 vmc_drc_index;
13080eca353eSBryant G. Ly 
13090eca353eSBryant G. Ly 	/* Call to request the VMC device from phyp*/
13100eca353eSBryant G. Ly 	rc = h_request_vmc(&vmc_drc_index);
13110eca353eSBryant G. Ly 	pr_debug("ibmvmc: requestvmc: H_REQUEST_VMC rc = 0x%lx\n", rc);
13120eca353eSBryant G. Ly 
13130eca353eSBryant G. Ly 	if (rc == H_SUCCESS) {
13140eca353eSBryant G. Ly 		rc = 0;
13150eca353eSBryant G. Ly 	} else if (rc == H_FUNCTION) {
13160eca353eSBryant G. Ly 		pr_err("ibmvmc: requestvmc: h_request_vmc not supported\n");
13170eca353eSBryant G. Ly 		return -EPERM;
13180eca353eSBryant G. Ly 	} else if (rc == H_AUTHORITY) {
13190eca353eSBryant G. Ly 		pr_err("ibmvmc: requestvmc: hypervisor denied vmc request\n");
13200eca353eSBryant G. Ly 		return -EPERM;
13210eca353eSBryant G. Ly 	} else if (rc == H_HARDWARE) {
13220eca353eSBryant G. Ly 		pr_err("ibmvmc: requestvmc: hypervisor hardware fault\n");
13230eca353eSBryant G. Ly 		return -EIO;
13240eca353eSBryant G. Ly 	} else if (rc == H_RESOURCE) {
13250eca353eSBryant G. Ly 		pr_err("ibmvmc: requestvmc: vmc resource unavailable\n");
13260eca353eSBryant G. Ly 		return -ENODEV;
13270eca353eSBryant G. Ly 	} else if (rc == H_NOT_AVAILABLE) {
13280eca353eSBryant G. Ly 		pr_err("ibmvmc: requestvmc: system cannot be vmc managed\n");
13290eca353eSBryant G. Ly 		return -EPERM;
13300eca353eSBryant G. Ly 	} else if (rc == H_PARAMETER) {
13310eca353eSBryant G. Ly 		pr_err("ibmvmc: requestvmc: invalid parameter\n");
13320eca353eSBryant G. Ly 		return -EINVAL;
13330eca353eSBryant G. Ly 	}
13340eca353eSBryant G. Ly 
13350eca353eSBryant G. Ly 	/* Success, set the vmc index in global struct */
13360eca353eSBryant G. Ly 	ibmvmc.vmc_drc_index = vmc_drc_index;
13370eca353eSBryant G. Ly 
13380eca353eSBryant G. Ly 	bytes = copy_to_user(ret_vmc_index, &vmc_drc_index,
13390eca353eSBryant G. Ly 			     sizeof(*ret_vmc_index));
13400eca353eSBryant G. Ly 	if (bytes) {
13410eca353eSBryant G. Ly 		pr_warn("ibmvmc: requestvmc: copy to user failed.\n");
13420eca353eSBryant G. Ly 		return -EFAULT;
13430eca353eSBryant G. Ly 	}
13440eca353eSBryant G. Ly 	return rc;
13450eca353eSBryant G. Ly }
13460eca353eSBryant G. Ly 
13470eca353eSBryant G. Ly /**
13480eca353eSBryant G. Ly  * ibmvmc_ioctl - IOCTL
13490eca353eSBryant G. Ly  *
135018248659SLee Jones  * @file:	file information
13510eca353eSBryant G. Ly  * @cmd:	cmd field
13520eca353eSBryant G. Ly  * @arg:	Argument field
13530eca353eSBryant G. Ly  *
13540eca353eSBryant G. Ly  * Return:
13550eca353eSBryant G. Ly  *	0 - Success
13560eca353eSBryant G. Ly  *	Non-zero - Failure
13570eca353eSBryant G. Ly  */
ibmvmc_ioctl(struct file * file,unsigned int cmd,unsigned long arg)13580eca353eSBryant G. Ly static long ibmvmc_ioctl(struct file *file,
13590eca353eSBryant G. Ly 			 unsigned int cmd, unsigned long arg)
13600eca353eSBryant G. Ly {
13610eca353eSBryant G. Ly 	struct ibmvmc_file_session *session = file->private_data;
13620eca353eSBryant G. Ly 
13630eca353eSBryant G. Ly 	pr_debug("ibmvmc: ioctl file=0x%lx, cmd=0x%x, arg=0x%lx, ses=0x%lx\n",
13640eca353eSBryant G. Ly 		 (unsigned long)file, cmd, arg,
13650eca353eSBryant G. Ly 		 (unsigned long)session);
13660eca353eSBryant G. Ly 
13670eca353eSBryant G. Ly 	if (!session) {
13680eca353eSBryant G. Ly 		pr_warn("ibmvmc: ioctl: no session\n");
13690eca353eSBryant G. Ly 		return -EIO;
13700eca353eSBryant G. Ly 	}
13710eca353eSBryant G. Ly 
13720eca353eSBryant G. Ly 	switch (cmd) {
13730eca353eSBryant G. Ly 	case VMC_IOCTL_SETHMCID:
13740eca353eSBryant G. Ly 		return ibmvmc_ioctl_sethmcid(session,
13750eca353eSBryant G. Ly 			(unsigned char __user *)arg);
13760eca353eSBryant G. Ly 	case VMC_IOCTL_QUERY:
13770eca353eSBryant G. Ly 		return ibmvmc_ioctl_query(session,
13780eca353eSBryant G. Ly 			(struct ibmvmc_query_struct __user *)arg);
13790eca353eSBryant G. Ly 	case VMC_IOCTL_REQUESTVMC:
13800eca353eSBryant G. Ly 		return ibmvmc_ioctl_requestvmc(session,
13810eca353eSBryant G. Ly 			(unsigned int __user *)arg);
13820eca353eSBryant G. Ly 	default:
13830eca353eSBryant G. Ly 		pr_warn("ibmvmc: unknown ioctl 0x%x\n", cmd);
13840eca353eSBryant G. Ly 		return -EINVAL;
13850eca353eSBryant G. Ly 	}
13860eca353eSBryant G. Ly }
13870eca353eSBryant G. Ly 
13880eca353eSBryant G. Ly static const struct file_operations ibmvmc_fops = {
13890eca353eSBryant G. Ly 	.owner		= THIS_MODULE,
13900eca353eSBryant G. Ly 	.read		= ibmvmc_read,
13910eca353eSBryant G. Ly 	.write		= ibmvmc_write,
13920eca353eSBryant G. Ly 	.poll		= ibmvmc_poll,
13930eca353eSBryant G. Ly 	.unlocked_ioctl	= ibmvmc_ioctl,
13940eca353eSBryant G. Ly 	.open           = ibmvmc_open,
13950eca353eSBryant G. Ly 	.release        = ibmvmc_close,
13960eca353eSBryant G. Ly };
13970eca353eSBryant G. Ly 
13980eca353eSBryant G. Ly /**
13990eca353eSBryant G. Ly  * ibmvmc_add_buffer - Add Buffer
14000eca353eSBryant G. Ly  *
14010eca353eSBryant G. Ly  * @adapter: crq_server_adapter struct
14020eca353eSBryant G. Ly  * @crq:	ibmvmc_crq_msg struct
14030eca353eSBryant G. Ly  *
14040eca353eSBryant G. Ly  * This message transfers a buffer from hypervisor ownership to management
14050eca353eSBryant G. Ly  * partition ownership. The LIOBA is obtained from the virtual TCE table
14060eca353eSBryant G. Ly  * associated with the hypervisor side of the VMC device, and points to a
14070eca353eSBryant G. Ly  * buffer of size MTU (as established in the capabilities exchange).
14080eca353eSBryant G. Ly  *
14090eca353eSBryant G. Ly  * Typical flow for ading buffers:
14100eca353eSBryant G. Ly  * 1. A new management application connection is opened by the management
14110eca353eSBryant G. Ly  *	partition.
14120eca353eSBryant G. Ly  * 2. The hypervisor assigns new buffers for the traffic associated with
14130eca353eSBryant G. Ly  *	that connection.
14140eca353eSBryant G. Ly  * 3. The hypervisor sends VMC Add Buffer messages to the management
14150eca353eSBryant G. Ly  *	partition, informing it of the new buffers.
14160eca353eSBryant G. Ly  * 4. The hypervisor sends an HMC protocol message (to the management
14170eca353eSBryant G. Ly  *	application) notifying it of the new buffers. This informs the
14180eca353eSBryant G. Ly  *	application that it has buffers available for sending HMC
14190eca353eSBryant G. Ly  *	commands.
14200eca353eSBryant G. Ly  *
14210eca353eSBryant G. Ly  * Return:
14220eca353eSBryant G. Ly  *	0 - Success
14230eca353eSBryant G. Ly  *	Non-zero - Failure
14240eca353eSBryant G. Ly  */
ibmvmc_add_buffer(struct crq_server_adapter * adapter,struct ibmvmc_crq_msg * crq)14250eca353eSBryant G. Ly static int ibmvmc_add_buffer(struct crq_server_adapter *adapter,
14260eca353eSBryant G. Ly 			     struct ibmvmc_crq_msg *crq)
14270eca353eSBryant G. Ly {
14280eca353eSBryant G. Ly 	struct ibmvmc_buffer *buffer;
14290eca353eSBryant G. Ly 	u8 hmc_index;
14300eca353eSBryant G. Ly 	u8 hmc_session;
14310eca353eSBryant G. Ly 	u16 buffer_id;
14320eca353eSBryant G. Ly 	unsigned long flags;
14330eca353eSBryant G. Ly 	int rc = 0;
14340eca353eSBryant G. Ly 
14350eca353eSBryant G. Ly 	if (!crq)
14360eca353eSBryant G. Ly 		return -1;
14370eca353eSBryant G. Ly 
14380eca353eSBryant G. Ly 	hmc_session = crq->hmc_session;
14390eca353eSBryant G. Ly 	hmc_index = crq->hmc_index;
14400eca353eSBryant G. Ly 	buffer_id = be16_to_cpu(crq->var2.buffer_id);
14410eca353eSBryant G. Ly 
14420eca353eSBryant G. Ly 	if (hmc_index > ibmvmc.max_hmc_index) {
14430eca353eSBryant G. Ly 		dev_err(adapter->dev, "add_buffer: invalid hmc_index = 0x%x\n",
14440eca353eSBryant G. Ly 			hmc_index);
14450eca353eSBryant G. Ly 		ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_HMC_INDEX,
14460eca353eSBryant G. Ly 					    hmc_session, hmc_index, buffer_id);
14470eca353eSBryant G. Ly 		return -1;
14480eca353eSBryant G. Ly 	}
14490eca353eSBryant G. Ly 
14500eca353eSBryant G. Ly 	if (buffer_id >= ibmvmc.max_buffer_pool_size) {
14510eca353eSBryant G. Ly 		dev_err(adapter->dev, "add_buffer: invalid buffer_id = 0x%x\n",
14520eca353eSBryant G. Ly 			buffer_id);
14530eca353eSBryant G. Ly 		ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_BUFFER_ID,
14540eca353eSBryant G. Ly 					    hmc_session, hmc_index, buffer_id);
14550eca353eSBryant G. Ly 		return -1;
14560eca353eSBryant G. Ly 	}
14570eca353eSBryant G. Ly 
14580eca353eSBryant G. Ly 	spin_lock_irqsave(&hmcs[hmc_index].lock, flags);
14590eca353eSBryant G. Ly 	buffer = &hmcs[hmc_index].buffer[buffer_id];
14600eca353eSBryant G. Ly 
14610eca353eSBryant G. Ly 	if (buffer->real_addr_local || buffer->dma_addr_local) {
14620eca353eSBryant G. Ly 		dev_warn(adapter->dev, "add_buffer: already allocated id = 0x%lx\n",
14630eca353eSBryant G. Ly 			 (unsigned long)buffer_id);
14640eca353eSBryant G. Ly 		spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags);
14650eca353eSBryant G. Ly 		ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_BUFFER_ID,
14660eca353eSBryant G. Ly 					    hmc_session, hmc_index, buffer_id);
14670eca353eSBryant G. Ly 		return -1;
14680eca353eSBryant G. Ly 	}
14690eca353eSBryant G. Ly 
14700eca353eSBryant G. Ly 	buffer->real_addr_local = alloc_dma_buffer(to_vio_dev(adapter->dev),
14710eca353eSBryant G. Ly 						   ibmvmc.max_mtu,
14720eca353eSBryant G. Ly 						   &buffer->dma_addr_local);
14730eca353eSBryant G. Ly 
14740eca353eSBryant G. Ly 	if (!buffer->real_addr_local) {
14750eca353eSBryant G. Ly 		dev_err(adapter->dev, "add_buffer: alloc_dma_buffer failed.\n");
14760eca353eSBryant G. Ly 		spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags);
14770eca353eSBryant G. Ly 		ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INTERFACE_FAILURE,
14780eca353eSBryant G. Ly 					    hmc_session, hmc_index, buffer_id);
14790eca353eSBryant G. Ly 		return -1;
14800eca353eSBryant G. Ly 	}
14810eca353eSBryant G. Ly 
14820eca353eSBryant G. Ly 	buffer->dma_addr_remote = be32_to_cpu(crq->var3.lioba);
14830eca353eSBryant G. Ly 	buffer->size = ibmvmc.max_mtu;
14840eca353eSBryant G. Ly 	buffer->owner = crq->var1.owner;
14850eca353eSBryant G. Ly 	buffer->free = 1;
14860eca353eSBryant G. Ly 	/* Must ensure valid==1 is observable only after all other fields are */
14870eca353eSBryant G. Ly 	dma_wmb();
14880eca353eSBryant G. Ly 	buffer->valid = 1;
14890eca353eSBryant G. Ly 	buffer->id = buffer_id;
14900eca353eSBryant G. Ly 
14910eca353eSBryant G. Ly 	dev_dbg(adapter->dev, "add_buffer: successfully added a buffer:\n");
14920eca353eSBryant G. Ly 	dev_dbg(adapter->dev, "   index: %d, session: %d, buffer: 0x%x, owner: %d\n",
14930eca353eSBryant G. Ly 		hmc_index, hmc_session, buffer_id, buffer->owner);
14940eca353eSBryant G. Ly 	dev_dbg(adapter->dev, "   local: 0x%x, remote: 0x%x\n",
14950eca353eSBryant G. Ly 		(u32)buffer->dma_addr_local,
14960eca353eSBryant G. Ly 		(u32)buffer->dma_addr_remote);
14970eca353eSBryant G. Ly 	spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags);
14980eca353eSBryant G. Ly 
14990eca353eSBryant G. Ly 	ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_SUCCESS, hmc_session,
15000eca353eSBryant G. Ly 				    hmc_index, buffer_id);
15010eca353eSBryant G. Ly 
15020eca353eSBryant G. Ly 	return rc;
15030eca353eSBryant G. Ly }
15040eca353eSBryant G. Ly 
15050eca353eSBryant G. Ly /**
15060eca353eSBryant G. Ly  * ibmvmc_rem_buffer - Remove Buffer
15070eca353eSBryant G. Ly  *
15080eca353eSBryant G. Ly  * @adapter: crq_server_adapter struct
15090eca353eSBryant G. Ly  * @crq:	ibmvmc_crq_msg struct
15100eca353eSBryant G. Ly  *
15110eca353eSBryant G. Ly  * This message requests an HMC buffer to be transferred from management
15120eca353eSBryant G. Ly  * partition ownership to hypervisor ownership. The management partition may
15130eca353eSBryant G. Ly  * not be able to satisfy the request at a particular point in time if all its
15140eca353eSBryant G. Ly  * buffers are in use. The management partition requires a depth of at least
15150eca353eSBryant G. Ly  * one inbound buffer to allow management application commands to flow to the
15160eca353eSBryant G. Ly  * hypervisor. It is, therefore, an interface error for the hypervisor to
15170eca353eSBryant G. Ly  * attempt to remove the management partition's last buffer.
15180eca353eSBryant G. Ly  *
15190eca353eSBryant G. Ly  * The hypervisor is expected to manage buffer usage with the management
15200eca353eSBryant G. Ly  * application directly and inform the management partition when buffers may be
15210eca353eSBryant G. Ly  * removed. The typical flow for removing buffers:
15220eca353eSBryant G. Ly  *
15230eca353eSBryant G. Ly  * 1. The management application no longer needs a communication path to a
15240eca353eSBryant G. Ly  *	particular hypervisor function. That function is closed.
15250eca353eSBryant G. Ly  * 2. The hypervisor and the management application quiesce all traffic to that
15260eca353eSBryant G. Ly  *	function. The hypervisor requests a reduction in buffer pool size.
15270eca353eSBryant G. Ly  * 3. The management application acknowledges the reduction in buffer pool size.
15280eca353eSBryant G. Ly  * 4. The hypervisor sends a Remove Buffer message to the management partition,
15290eca353eSBryant G. Ly  *	informing it of the reduction in buffers.
15300eca353eSBryant G. Ly  * 5. The management partition verifies it can remove the buffer. This is
15310eca353eSBryant G. Ly  *	possible if buffers have been quiesced.
15320eca353eSBryant G. Ly  *
15330eca353eSBryant G. Ly  * Return:
15340eca353eSBryant G. Ly  *	0 - Success
15350eca353eSBryant G. Ly  *	Non-zero - Failure
15360eca353eSBryant G. Ly  */
15370eca353eSBryant G. Ly /*
15380eca353eSBryant G. Ly  * The hypervisor requested that we pick an unused buffer, and return it.
15390eca353eSBryant G. Ly  * Before sending the buffer back, we free any storage associated with the
15400eca353eSBryant G. Ly  * buffer.
15410eca353eSBryant G. Ly  */
ibmvmc_rem_buffer(struct crq_server_adapter * adapter,struct ibmvmc_crq_msg * crq)15420eca353eSBryant G. Ly static int ibmvmc_rem_buffer(struct crq_server_adapter *adapter,
15430eca353eSBryant G. Ly 			     struct ibmvmc_crq_msg *crq)
15440eca353eSBryant G. Ly {
15450eca353eSBryant G. Ly 	struct ibmvmc_buffer *buffer;
15460eca353eSBryant G. Ly 	u8 hmc_index;
15470eca353eSBryant G. Ly 	u8 hmc_session;
15480eca353eSBryant G. Ly 	u16 buffer_id = 0;
15490eca353eSBryant G. Ly 	unsigned long flags;
15500eca353eSBryant G. Ly 	int rc = 0;
15510eca353eSBryant G. Ly 
15520eca353eSBryant G. Ly 	if (!crq)
15530eca353eSBryant G. Ly 		return -1;
15540eca353eSBryant G. Ly 
15550eca353eSBryant G. Ly 	hmc_session = crq->hmc_session;
15560eca353eSBryant G. Ly 	hmc_index = crq->hmc_index;
15570eca353eSBryant G. Ly 
15580eca353eSBryant G. Ly 	if (hmc_index > ibmvmc.max_hmc_index) {
15590eca353eSBryant G. Ly 		dev_warn(adapter->dev, "rem_buffer: invalid hmc_index = 0x%x\n",
15600eca353eSBryant G. Ly 			 hmc_index);
15610eca353eSBryant G. Ly 		ibmvmc_send_rem_buffer_resp(adapter, VMC_MSG_INVALID_HMC_INDEX,
15620eca353eSBryant G. Ly 					    hmc_session, hmc_index, buffer_id);
15630eca353eSBryant G. Ly 		return -1;
15640eca353eSBryant G. Ly 	}
15650eca353eSBryant G. Ly 
15660eca353eSBryant G. Ly 	spin_lock_irqsave(&hmcs[hmc_index].lock, flags);
15670eca353eSBryant G. Ly 	buffer = ibmvmc_get_free_hmc_buffer(adapter, hmc_index);
15680eca353eSBryant G. Ly 	if (!buffer) {
15690eca353eSBryant G. Ly 		dev_info(adapter->dev, "rem_buffer: no buffer to remove\n");
15700eca353eSBryant G. Ly 		spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags);
15710eca353eSBryant G. Ly 		ibmvmc_send_rem_buffer_resp(adapter, VMC_MSG_NO_BUFFER,
15720eca353eSBryant G. Ly 					    hmc_session, hmc_index,
15730eca353eSBryant G. Ly 					    VMC_INVALID_BUFFER_ID);
15740eca353eSBryant G. Ly 		return -1;
15750eca353eSBryant G. Ly 	}
15760eca353eSBryant G. Ly 
15770eca353eSBryant G. Ly 	buffer_id = buffer->id;
15780eca353eSBryant G. Ly 
15790eca353eSBryant G. Ly 	if (buffer->valid)
15800eca353eSBryant G. Ly 		free_dma_buffer(to_vio_dev(adapter->dev),
15810eca353eSBryant G. Ly 				ibmvmc.max_mtu,
15820eca353eSBryant G. Ly 				buffer->real_addr_local,
15830eca353eSBryant G. Ly 				buffer->dma_addr_local);
15840eca353eSBryant G. Ly 
15850eca353eSBryant G. Ly 	memset(buffer, 0, sizeof(struct ibmvmc_buffer));
15860eca353eSBryant G. Ly 	spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags);
15870eca353eSBryant G. Ly 
15880eca353eSBryant G. Ly 	dev_dbg(adapter->dev, "rem_buffer: removed buffer 0x%x.\n", buffer_id);
15890eca353eSBryant G. Ly 	ibmvmc_send_rem_buffer_resp(adapter, VMC_MSG_SUCCESS, hmc_session,
15900eca353eSBryant G. Ly 				    hmc_index, buffer_id);
15910eca353eSBryant G. Ly 
15920eca353eSBryant G. Ly 	return rc;
15930eca353eSBryant G. Ly }
15940eca353eSBryant G. Ly 
ibmvmc_recv_msg(struct crq_server_adapter * adapter,struct ibmvmc_crq_msg * crq)15950eca353eSBryant G. Ly static int ibmvmc_recv_msg(struct crq_server_adapter *adapter,
15960eca353eSBryant G. Ly 			   struct ibmvmc_crq_msg *crq)
15970eca353eSBryant G. Ly {
15980eca353eSBryant G. Ly 	struct ibmvmc_buffer *buffer;
15990eca353eSBryant G. Ly 	struct ibmvmc_hmc *hmc;
16000eca353eSBryant G. Ly 	unsigned long msg_len;
16010eca353eSBryant G. Ly 	u8 hmc_index;
16020eca353eSBryant G. Ly 	u8 hmc_session;
16030eca353eSBryant G. Ly 	u16 buffer_id;
16040eca353eSBryant G. Ly 	unsigned long flags;
16050eca353eSBryant G. Ly 	int rc = 0;
16060eca353eSBryant G. Ly 
16070eca353eSBryant G. Ly 	if (!crq)
16080eca353eSBryant G. Ly 		return -1;
16090eca353eSBryant G. Ly 
16100eca353eSBryant G. Ly 	/* Hypervisor writes CRQs directly into our memory in big endian */
16110eca353eSBryant G. Ly 	dev_dbg(adapter->dev, "Recv_msg: msg from HV 0x%016llx 0x%016llx\n",
16120eca353eSBryant G. Ly 		be64_to_cpu(*((unsigned long *)crq)),
16130eca353eSBryant G. Ly 		be64_to_cpu(*(((unsigned long *)crq) + 1)));
16140eca353eSBryant G. Ly 
16150eca353eSBryant G. Ly 	hmc_session = crq->hmc_session;
16160eca353eSBryant G. Ly 	hmc_index = crq->hmc_index;
16170eca353eSBryant G. Ly 	buffer_id = be16_to_cpu(crq->var2.buffer_id);
16180eca353eSBryant G. Ly 	msg_len = be32_to_cpu(crq->var3.msg_len);
16190eca353eSBryant G. Ly 
16200eca353eSBryant G. Ly 	if (hmc_index > ibmvmc.max_hmc_index) {
16210eca353eSBryant G. Ly 		dev_err(adapter->dev, "Recv_msg: invalid hmc_index = 0x%x\n",
16220eca353eSBryant G. Ly 			hmc_index);
16230eca353eSBryant G. Ly 		ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_HMC_INDEX,
16240eca353eSBryant G. Ly 					    hmc_session, hmc_index, buffer_id);
16250eca353eSBryant G. Ly 		return -1;
16260eca353eSBryant G. Ly 	}
16270eca353eSBryant G. Ly 
16280eca353eSBryant G. Ly 	if (buffer_id >= ibmvmc.max_buffer_pool_size) {
16290eca353eSBryant G. Ly 		dev_err(adapter->dev, "Recv_msg: invalid buffer_id = 0x%x\n",
16300eca353eSBryant G. Ly 			buffer_id);
16310eca353eSBryant G. Ly 		ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_BUFFER_ID,
16320eca353eSBryant G. Ly 					    hmc_session, hmc_index, buffer_id);
16330eca353eSBryant G. Ly 		return -1;
16340eca353eSBryant G. Ly 	}
16350eca353eSBryant G. Ly 
16360eca353eSBryant G. Ly 	hmc = &hmcs[hmc_index];
16370eca353eSBryant G. Ly 	spin_lock_irqsave(&hmc->lock, flags);
16380eca353eSBryant G. Ly 
16390eca353eSBryant G. Ly 	if (hmc->state == ibmhmc_state_free) {
16400eca353eSBryant G. Ly 		dev_err(adapter->dev, "Recv_msg: invalid hmc state = 0x%x\n",
16410eca353eSBryant G. Ly 			hmc->state);
16420eca353eSBryant G. Ly 		/* HMC connection is not valid (possibly was reset under us). */
16430eca353eSBryant G. Ly 		spin_unlock_irqrestore(&hmc->lock, flags);
16440eca353eSBryant G. Ly 		return -1;
16450eca353eSBryant G. Ly 	}
16460eca353eSBryant G. Ly 
16470eca353eSBryant G. Ly 	buffer = &hmc->buffer[buffer_id];
16480eca353eSBryant G. Ly 
16490eca353eSBryant G. Ly 	if (buffer->valid == 0 || buffer->owner == VMC_BUF_OWNER_ALPHA) {
16500eca353eSBryant G. Ly 		dev_err(adapter->dev, "Recv_msg: not valid, or not HV.  0x%x 0x%x\n",
16510eca353eSBryant G. Ly 			buffer->valid, buffer->owner);
16520eca353eSBryant G. Ly 		spin_unlock_irqrestore(&hmc->lock, flags);
16530eca353eSBryant G. Ly 		return -1;
16540eca353eSBryant G. Ly 	}
16550eca353eSBryant G. Ly 
16560eca353eSBryant G. Ly 	/* RDMA the data into the partition. */
16570eca353eSBryant G. Ly 	rc = h_copy_rdma(msg_len,
16580eca353eSBryant G. Ly 			 adapter->riobn,
16590eca353eSBryant G. Ly 			 buffer->dma_addr_remote,
16600eca353eSBryant G. Ly 			 adapter->liobn,
16610eca353eSBryant G. Ly 			 buffer->dma_addr_local);
16620eca353eSBryant G. Ly 
16630eca353eSBryant 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",
16640eca353eSBryant G. Ly 		(unsigned int)msg_len, (unsigned int)buffer_id,
16650eca353eSBryant G. Ly 		(unsigned int)hmc->queue_head, (unsigned int)hmc_index);
16660eca353eSBryant G. Ly 	buffer->msg_len = msg_len;
16670eca353eSBryant G. Ly 	buffer->free = 0;
16680eca353eSBryant G. Ly 	buffer->owner = VMC_BUF_OWNER_ALPHA;
16690eca353eSBryant G. Ly 
16700eca353eSBryant G. Ly 	if (rc) {
16710eca353eSBryant G. Ly 		dev_err(adapter->dev, "Failure in recv_msg: h_copy_rdma = 0x%x\n",
16720eca353eSBryant G. Ly 			rc);
16730eca353eSBryant G. Ly 		spin_unlock_irqrestore(&hmc->lock, flags);
16740eca353eSBryant G. Ly 		return -1;
16750eca353eSBryant G. Ly 	}
16760eca353eSBryant G. Ly 
16770eca353eSBryant G. Ly 	/* Must be locked because read operates on the same data */
16780eca353eSBryant G. Ly 	hmc->queue_outbound_msgs[hmc->queue_head] = buffer_id;
16790eca353eSBryant G. Ly 	hmc->queue_head++;
16800eca353eSBryant G. Ly 	if (hmc->queue_head == ibmvmc_max_buf_pool_size)
16810eca353eSBryant G. Ly 		hmc->queue_head = 0;
16820eca353eSBryant G. Ly 
16830eca353eSBryant G. Ly 	if (hmc->queue_head == hmc->queue_tail)
16840eca353eSBryant G. Ly 		dev_err(adapter->dev, "outbound buffer queue wrapped.\n");
16850eca353eSBryant G. Ly 
16860eca353eSBryant G. Ly 	spin_unlock_irqrestore(&hmc->lock, flags);
16870eca353eSBryant G. Ly 
16880eca353eSBryant G. Ly 	wake_up_interruptible(&ibmvmc_read_wait);
16890eca353eSBryant G. Ly 
16900eca353eSBryant G. Ly 	return 0;
16910eca353eSBryant G. Ly }
16920eca353eSBryant G. Ly 
16930eca353eSBryant G. Ly /**
16940eca353eSBryant G. Ly  * ibmvmc_process_capabilities - Process Capabilities
16950eca353eSBryant G. Ly  *
16960eca353eSBryant G. Ly  * @adapter:	crq_server_adapter struct
16970eca353eSBryant G. Ly  * @crqp:	ibmvmc_crq_msg struct
16980eca353eSBryant G. Ly  *
16990eca353eSBryant G. Ly  */
ibmvmc_process_capabilities(struct crq_server_adapter * adapter,struct ibmvmc_crq_msg * crqp)17000eca353eSBryant G. Ly static void ibmvmc_process_capabilities(struct crq_server_adapter *adapter,
17010eca353eSBryant G. Ly 					struct ibmvmc_crq_msg *crqp)
17020eca353eSBryant G. Ly {
17030eca353eSBryant G. Ly 	struct ibmvmc_admin_crq_msg *crq = (struct ibmvmc_admin_crq_msg *)crqp;
17040eca353eSBryant G. Ly 
17050eca353eSBryant G. Ly 	if ((be16_to_cpu(crq->version) >> 8) !=
17060eca353eSBryant G. Ly 			(IBMVMC_PROTOCOL_VERSION >> 8)) {
17070eca353eSBryant G. Ly 		dev_err(adapter->dev, "init failed, incompatible versions 0x%x 0x%x\n",
17080eca353eSBryant G. Ly 			be16_to_cpu(crq->version),
17090eca353eSBryant G. Ly 			IBMVMC_PROTOCOL_VERSION);
17100eca353eSBryant G. Ly 		ibmvmc.state = ibmvmc_state_failed;
17110eca353eSBryant G. Ly 		return;
17120eca353eSBryant G. Ly 	}
17130eca353eSBryant G. Ly 
17140eca353eSBryant G. Ly 	ibmvmc.max_mtu = min_t(u32, ibmvmc_max_mtu, be32_to_cpu(crq->max_mtu));
17150eca353eSBryant G. Ly 	ibmvmc.max_buffer_pool_size = min_t(u16, ibmvmc_max_buf_pool_size,
17160eca353eSBryant G. Ly 					    be16_to_cpu(crq->pool_size));
17170eca353eSBryant G. Ly 	ibmvmc.max_hmc_index = min_t(u8, ibmvmc_max_hmcs, crq->max_hmc) - 1;
17180eca353eSBryant G. Ly 	ibmvmc.state = ibmvmc_state_ready;
17190eca353eSBryant G. Ly 
17200eca353eSBryant G. Ly 	dev_info(adapter->dev, "Capabilities: mtu=0x%x, pool_size=0x%x, max_hmc=0x%x\n",
17210eca353eSBryant G. Ly 		 ibmvmc.max_mtu, ibmvmc.max_buffer_pool_size,
17220eca353eSBryant G. Ly 		 ibmvmc.max_hmc_index);
17230eca353eSBryant G. Ly }
17240eca353eSBryant G. Ly 
17250eca353eSBryant G. Ly /**
17260eca353eSBryant G. Ly  * ibmvmc_validate_hmc_session - Validate HMC Session
17270eca353eSBryant G. Ly  *
17280eca353eSBryant G. Ly  * @adapter:	crq_server_adapter struct
17290eca353eSBryant G. Ly  * @crq:	ibmvmc_crq_msg struct
17300eca353eSBryant G. Ly  *
17310eca353eSBryant G. Ly  * Return:
17320eca353eSBryant G. Ly  *	0 - Success
17330eca353eSBryant G. Ly  *	Non-zero - Failure
17340eca353eSBryant G. Ly  */
ibmvmc_validate_hmc_session(struct crq_server_adapter * adapter,struct ibmvmc_crq_msg * crq)17350eca353eSBryant G. Ly static int ibmvmc_validate_hmc_session(struct crq_server_adapter *adapter,
17360eca353eSBryant G. Ly 				       struct ibmvmc_crq_msg *crq)
17370eca353eSBryant G. Ly {
17380eca353eSBryant G. Ly 	unsigned char hmc_index;
17390eca353eSBryant G. Ly 
17400eca353eSBryant G. Ly 	hmc_index = crq->hmc_index;
17410eca353eSBryant G. Ly 
17420eca353eSBryant G. Ly 	if (crq->hmc_session == 0)
17430eca353eSBryant G. Ly 		return 0;
17440eca353eSBryant G. Ly 
17450eca353eSBryant G. Ly 	if (hmc_index > ibmvmc.max_hmc_index)
17460eca353eSBryant G. Ly 		return -1;
17470eca353eSBryant G. Ly 
17480eca353eSBryant G. Ly 	if (hmcs[hmc_index].session != crq->hmc_session) {
17490eca353eSBryant G. Ly 		dev_warn(adapter->dev, "Drop, bad session: expected 0x%x, recv 0x%x\n",
17500eca353eSBryant G. Ly 			 hmcs[hmc_index].session, crq->hmc_session);
17510eca353eSBryant G. Ly 		return -1;
17520eca353eSBryant G. Ly 	}
17530eca353eSBryant G. Ly 
17540eca353eSBryant G. Ly 	return 0;
17550eca353eSBryant G. Ly }
17560eca353eSBryant G. Ly 
17570eca353eSBryant G. Ly /**
17580eca353eSBryant G. Ly  * ibmvmc_reset - Reset
17590eca353eSBryant G. Ly  *
17600eca353eSBryant G. Ly  * @adapter:	crq_server_adapter struct
17610eca353eSBryant G. Ly  * @xport_event:	export_event field
17620eca353eSBryant G. Ly  *
17630eca353eSBryant G. Ly  * Closes all HMC sessions and conditionally schedules a CRQ reset.
17640eca353eSBryant G. Ly  * @xport_event: If true, the partner closed their CRQ; we don't need to reset.
17650eca353eSBryant G. Ly  *               If false, we need to schedule a CRQ reset.
17660eca353eSBryant G. Ly  */
ibmvmc_reset(struct crq_server_adapter * adapter,bool xport_event)17670eca353eSBryant G. Ly static void ibmvmc_reset(struct crq_server_adapter *adapter, bool xport_event)
17680eca353eSBryant G. Ly {
17690eca353eSBryant G. Ly 	int i;
17700eca353eSBryant G. Ly 
17710eca353eSBryant G. Ly 	if (ibmvmc.state != ibmvmc_state_sched_reset) {
17720eca353eSBryant G. Ly 		dev_info(adapter->dev, "*** Reset to initial state.\n");
17730eca353eSBryant G. Ly 		for (i = 0; i < ibmvmc_max_hmcs; i++)
17740eca353eSBryant G. Ly 			ibmvmc_return_hmc(&hmcs[i], xport_event);
17750eca353eSBryant G. Ly 
17760eca353eSBryant G. Ly 		if (xport_event) {
17770eca353eSBryant G. Ly 			/* CRQ was closed by the partner.  We don't need to do
17780eca353eSBryant G. Ly 			 * anything except set ourself to the correct state to
17790eca353eSBryant G. Ly 			 * handle init msgs.
17800eca353eSBryant G. Ly 			 */
17810eca353eSBryant G. Ly 			ibmvmc.state = ibmvmc_state_crqinit;
17820eca353eSBryant G. Ly 		} else {
17830eca353eSBryant G. Ly 			/* The partner did not close their CRQ - instead, we're
17840eca353eSBryant G. Ly 			 * closing the CRQ on our end. Need to schedule this
17850eca353eSBryant G. Ly 			 * for process context, because CRQ reset may require a
17860eca353eSBryant G. Ly 			 * sleep.
17870eca353eSBryant G. Ly 			 *
17880eca353eSBryant G. Ly 			 * Setting ibmvmc.state here immediately prevents
17890eca353eSBryant G. Ly 			 * ibmvmc_open from completing until the reset
17900eca353eSBryant G. Ly 			 * completes in process context.
17910eca353eSBryant G. Ly 			 */
17920eca353eSBryant G. Ly 			ibmvmc.state = ibmvmc_state_sched_reset;
17930eca353eSBryant G. Ly 			dev_dbg(adapter->dev, "Device reset scheduled");
17940eca353eSBryant G. Ly 			wake_up_interruptible(&adapter->reset_wait_queue);
17950eca353eSBryant G. Ly 		}
17960eca353eSBryant G. Ly 	}
17970eca353eSBryant G. Ly }
17980eca353eSBryant G. Ly 
17990eca353eSBryant G. Ly /**
18000eca353eSBryant G. Ly  * ibmvmc_reset_task - Reset Task
18010eca353eSBryant G. Ly  *
18020eca353eSBryant G. Ly  * @data:	Data field
18030eca353eSBryant G. Ly  *
18040eca353eSBryant G. Ly  * Performs a CRQ reset of the VMC device in process context.
18050eca353eSBryant G. Ly  * NOTE: This function should not be called directly, use ibmvmc_reset.
18060eca353eSBryant G. Ly  */
ibmvmc_reset_task(void * data)18070eca353eSBryant G. Ly static int ibmvmc_reset_task(void *data)
18080eca353eSBryant G. Ly {
18090eca353eSBryant G. Ly 	struct crq_server_adapter *adapter = data;
18100eca353eSBryant G. Ly 	int rc;
18110eca353eSBryant G. Ly 
18120eca353eSBryant G. Ly 	set_user_nice(current, -20);
18130eca353eSBryant G. Ly 
18140eca353eSBryant G. Ly 	while (!kthread_should_stop()) {
18150eca353eSBryant G. Ly 		wait_event_interruptible(adapter->reset_wait_queue,
18160eca353eSBryant G. Ly 			(ibmvmc.state == ibmvmc_state_sched_reset) ||
18170eca353eSBryant G. Ly 			kthread_should_stop());
18180eca353eSBryant G. Ly 
18190eca353eSBryant G. Ly 		if (kthread_should_stop())
18200eca353eSBryant G. Ly 			break;
18210eca353eSBryant G. Ly 
18220eca353eSBryant G. Ly 		dev_dbg(adapter->dev, "CRQ resetting in process context");
18230eca353eSBryant G. Ly 		tasklet_disable(&adapter->work_task);
18240eca353eSBryant G. Ly 
18250eca353eSBryant G. Ly 		rc = ibmvmc_reset_crq_queue(adapter);
18260eca353eSBryant G. Ly 
18270eca353eSBryant G. Ly 		if (rc != H_SUCCESS && rc != H_RESOURCE) {
18280eca353eSBryant G. Ly 			dev_err(adapter->dev, "Error initializing CRQ.  rc = 0x%x\n",
18290eca353eSBryant G. Ly 				rc);
18300eca353eSBryant G. Ly 			ibmvmc.state = ibmvmc_state_failed;
18310eca353eSBryant G. Ly 		} else {
18320eca353eSBryant G. Ly 			ibmvmc.state = ibmvmc_state_crqinit;
18330eca353eSBryant G. Ly 
18340eca353eSBryant G. Ly 			if (ibmvmc_send_crq(adapter, 0xC001000000000000LL, 0)
18350eca353eSBryant G. Ly 			    != 0 && rc != H_RESOURCE)
18360eca353eSBryant G. Ly 				dev_warn(adapter->dev, "Failed to send initialize CRQ message\n");
18370eca353eSBryant G. Ly 		}
18380eca353eSBryant G. Ly 
18390eca353eSBryant G. Ly 		vio_enable_interrupts(to_vio_dev(adapter->dev));
18400eca353eSBryant G. Ly 		tasklet_enable(&adapter->work_task);
18410eca353eSBryant G. Ly 	}
18420eca353eSBryant G. Ly 
18430eca353eSBryant G. Ly 	return 0;
18440eca353eSBryant G. Ly }
18450eca353eSBryant G. Ly 
18460eca353eSBryant G. Ly /**
18470eca353eSBryant G. Ly  * ibmvmc_process_open_resp - Process Open Response
18480eca353eSBryant G. Ly  *
18490eca353eSBryant G. Ly  * @crq: ibmvmc_crq_msg struct
18500eca353eSBryant G. Ly  * @adapter:    crq_server_adapter struct
18510eca353eSBryant G. Ly  *
18520eca353eSBryant G. Ly  * This command is sent by the hypervisor in response to the Interface
18530eca353eSBryant G. Ly  * Open message. When this message is received, the indicated buffer is
18540eca353eSBryant G. Ly  * again available for management partition use.
18550eca353eSBryant G. Ly  */
ibmvmc_process_open_resp(struct ibmvmc_crq_msg * crq,struct crq_server_adapter * adapter)18560eca353eSBryant G. Ly static void ibmvmc_process_open_resp(struct ibmvmc_crq_msg *crq,
18570eca353eSBryant G. Ly 				     struct crq_server_adapter *adapter)
18580eca353eSBryant G. Ly {
18590eca353eSBryant G. Ly 	unsigned char hmc_index;
18600eca353eSBryant G. Ly 	unsigned short buffer_id;
18610eca353eSBryant G. Ly 
18620eca353eSBryant G. Ly 	hmc_index = crq->hmc_index;
18630eca353eSBryant G. Ly 	if (hmc_index > ibmvmc.max_hmc_index) {
18640eca353eSBryant G. Ly 		/* Why would PHYP give an index > max negotiated? */
18650eca353eSBryant G. Ly 		ibmvmc_reset(adapter, false);
18660eca353eSBryant G. Ly 		return;
18670eca353eSBryant G. Ly 	}
18680eca353eSBryant G. Ly 
18690eca353eSBryant G. Ly 	if (crq->status) {
18700eca353eSBryant G. Ly 		dev_warn(adapter->dev, "open_resp: failed - status 0x%x\n",
18710eca353eSBryant G. Ly 			 crq->status);
18720eca353eSBryant G. Ly 		ibmvmc_return_hmc(&hmcs[hmc_index], false);
18730eca353eSBryant G. Ly 		return;
18740eca353eSBryant G. Ly 	}
18750eca353eSBryant G. Ly 
18760eca353eSBryant G. Ly 	if (hmcs[hmc_index].state == ibmhmc_state_opening) {
18770eca353eSBryant G. Ly 		buffer_id = be16_to_cpu(crq->var2.buffer_id);
18780eca353eSBryant G. Ly 		if (buffer_id >= ibmvmc.max_buffer_pool_size) {
18790eca353eSBryant G. Ly 			dev_err(adapter->dev, "open_resp: invalid buffer_id = 0x%x\n",
18800eca353eSBryant G. Ly 				buffer_id);
18810eca353eSBryant G. Ly 			hmcs[hmc_index].state = ibmhmc_state_failed;
18820eca353eSBryant G. Ly 		} else {
18830eca353eSBryant G. Ly 			ibmvmc_free_hmc_buffer(&hmcs[hmc_index],
18840eca353eSBryant G. Ly 					       &hmcs[hmc_index].buffer[buffer_id]);
18850eca353eSBryant G. Ly 			hmcs[hmc_index].state = ibmhmc_state_ready;
18860eca353eSBryant G. Ly 			dev_dbg(adapter->dev, "open_resp: set hmc state = ready\n");
18870eca353eSBryant G. Ly 		}
18880eca353eSBryant G. Ly 	} else {
18890eca353eSBryant G. Ly 		dev_warn(adapter->dev, "open_resp: invalid hmc state (0x%x)\n",
18900eca353eSBryant G. Ly 			 hmcs[hmc_index].state);
18910eca353eSBryant G. Ly 	}
18920eca353eSBryant G. Ly }
18930eca353eSBryant G. Ly 
18940eca353eSBryant G. Ly /**
18950eca353eSBryant G. Ly  * ibmvmc_process_close_resp - Process Close Response
18960eca353eSBryant G. Ly  *
18970eca353eSBryant G. Ly  * @crq: ibmvmc_crq_msg struct
18980eca353eSBryant G. Ly  * @adapter:    crq_server_adapter struct
18990eca353eSBryant G. Ly  *
19000eca353eSBryant G. Ly  * This command is sent by the hypervisor in response to the managemant
19010eca353eSBryant G. Ly  * application Interface Close message.
19020eca353eSBryant G. Ly  *
19030eca353eSBryant G. Ly  * If the close fails, simply reset the entire driver as the state of the VMC
19040eca353eSBryant G. Ly  * must be in tough shape.
19050eca353eSBryant G. Ly  */
ibmvmc_process_close_resp(struct ibmvmc_crq_msg * crq,struct crq_server_adapter * adapter)19060eca353eSBryant G. Ly static void ibmvmc_process_close_resp(struct ibmvmc_crq_msg *crq,
19070eca353eSBryant G. Ly 				      struct crq_server_adapter *adapter)
19080eca353eSBryant G. Ly {
19090eca353eSBryant G. Ly 	unsigned char hmc_index;
19100eca353eSBryant G. Ly 
19110eca353eSBryant G. Ly 	hmc_index = crq->hmc_index;
19120eca353eSBryant G. Ly 	if (hmc_index > ibmvmc.max_hmc_index) {
19130eca353eSBryant G. Ly 		ibmvmc_reset(adapter, false);
19140eca353eSBryant G. Ly 		return;
19150eca353eSBryant G. Ly 	}
19160eca353eSBryant G. Ly 
19170eca353eSBryant G. Ly 	if (crq->status) {
19180eca353eSBryant G. Ly 		dev_warn(adapter->dev, "close_resp: failed - status 0x%x\n",
19190eca353eSBryant G. Ly 			 crq->status);
19200eca353eSBryant G. Ly 		ibmvmc_reset(adapter, false);
19210eca353eSBryant G. Ly 		return;
19220eca353eSBryant G. Ly 	}
19230eca353eSBryant G. Ly 
19240eca353eSBryant G. Ly 	ibmvmc_return_hmc(&hmcs[hmc_index], false);
19250eca353eSBryant G. Ly }
19260eca353eSBryant G. Ly 
19270eca353eSBryant G. Ly /**
19280eca353eSBryant G. Ly  * ibmvmc_crq_process - Process CRQ
19290eca353eSBryant G. Ly  *
19300eca353eSBryant G. Ly  * @adapter:    crq_server_adapter struct
19310eca353eSBryant G. Ly  * @crq:	ibmvmc_crq_msg struct
19320eca353eSBryant G. Ly  *
19330eca353eSBryant G. Ly  * Process the CRQ message based upon the type of message received.
19340eca353eSBryant G. Ly  *
19350eca353eSBryant G. Ly  */
ibmvmc_crq_process(struct crq_server_adapter * adapter,struct ibmvmc_crq_msg * crq)19360eca353eSBryant G. Ly static void ibmvmc_crq_process(struct crq_server_adapter *adapter,
19370eca353eSBryant G. Ly 			       struct ibmvmc_crq_msg *crq)
19380eca353eSBryant G. Ly {
19390eca353eSBryant G. Ly 	switch (crq->type) {
19400eca353eSBryant G. Ly 	case VMC_MSG_CAP_RESP:
19410eca353eSBryant G. Ly 		dev_dbg(adapter->dev, "CRQ recv: capabilities resp (0x%x)\n",
19420eca353eSBryant G. Ly 			crq->type);
19430eca353eSBryant G. Ly 		if (ibmvmc.state == ibmvmc_state_capabilities)
19440eca353eSBryant G. Ly 			ibmvmc_process_capabilities(adapter, crq);
19450eca353eSBryant G. Ly 		else
19460eca353eSBryant G. Ly 			dev_warn(adapter->dev, "caps msg invalid in state 0x%x\n",
19470eca353eSBryant G. Ly 				 ibmvmc.state);
19480eca353eSBryant G. Ly 		break;
19490eca353eSBryant G. Ly 	case VMC_MSG_OPEN_RESP:
19500eca353eSBryant G. Ly 		dev_dbg(adapter->dev, "CRQ recv: open resp (0x%x)\n",
19510eca353eSBryant G. Ly 			crq->type);
19520eca353eSBryant G. Ly 		if (ibmvmc_validate_hmc_session(adapter, crq) == 0)
19530eca353eSBryant G. Ly 			ibmvmc_process_open_resp(crq, adapter);
19540eca353eSBryant G. Ly 		break;
19550eca353eSBryant G. Ly 	case VMC_MSG_ADD_BUF:
19560eca353eSBryant G. Ly 		dev_dbg(adapter->dev, "CRQ recv: add buf (0x%x)\n",
19570eca353eSBryant G. Ly 			crq->type);
19580eca353eSBryant G. Ly 		if (ibmvmc_validate_hmc_session(adapter, crq) == 0)
19590eca353eSBryant G. Ly 			ibmvmc_add_buffer(adapter, crq);
19600eca353eSBryant G. Ly 		break;
19610eca353eSBryant G. Ly 	case VMC_MSG_REM_BUF:
19620eca353eSBryant G. Ly 		dev_dbg(adapter->dev, "CRQ recv: rem buf (0x%x)\n",
19630eca353eSBryant G. Ly 			crq->type);
19640eca353eSBryant G. Ly 		if (ibmvmc_validate_hmc_session(adapter, crq) == 0)
19650eca353eSBryant G. Ly 			ibmvmc_rem_buffer(adapter, crq);
19660eca353eSBryant G. Ly 		break;
19670eca353eSBryant G. Ly 	case VMC_MSG_SIGNAL:
19680eca353eSBryant G. Ly 		dev_dbg(adapter->dev, "CRQ recv: signal msg (0x%x)\n",
19690eca353eSBryant G. Ly 			crq->type);
19700eca353eSBryant G. Ly 		if (ibmvmc_validate_hmc_session(adapter, crq) == 0)
19710eca353eSBryant G. Ly 			ibmvmc_recv_msg(adapter, crq);
19720eca353eSBryant G. Ly 		break;
19730eca353eSBryant G. Ly 	case VMC_MSG_CLOSE_RESP:
19740eca353eSBryant G. Ly 		dev_dbg(adapter->dev, "CRQ recv: close resp (0x%x)\n",
19750eca353eSBryant G. Ly 			crq->type);
19760eca353eSBryant G. Ly 		if (ibmvmc_validate_hmc_session(adapter, crq) == 0)
19770eca353eSBryant G. Ly 			ibmvmc_process_close_resp(crq, adapter);
19780eca353eSBryant G. Ly 		break;
19790eca353eSBryant G. Ly 	case VMC_MSG_CAP:
19800eca353eSBryant G. Ly 	case VMC_MSG_OPEN:
19810eca353eSBryant G. Ly 	case VMC_MSG_CLOSE:
19820eca353eSBryant G. Ly 	case VMC_MSG_ADD_BUF_RESP:
19830eca353eSBryant G. Ly 	case VMC_MSG_REM_BUF_RESP:
19840eca353eSBryant G. Ly 		dev_warn(adapter->dev, "CRQ recv: unexpected msg (0x%x)\n",
19850eca353eSBryant G. Ly 			 crq->type);
19860eca353eSBryant G. Ly 		break;
19870eca353eSBryant G. Ly 	default:
19880eca353eSBryant G. Ly 		dev_warn(adapter->dev, "CRQ recv: unknown msg (0x%x)\n",
19890eca353eSBryant G. Ly 			 crq->type);
19900eca353eSBryant G. Ly 		break;
19910eca353eSBryant G. Ly 	}
19920eca353eSBryant G. Ly }
19930eca353eSBryant G. Ly 
19940eca353eSBryant G. Ly /**
19950eca353eSBryant G. Ly  * ibmvmc_handle_crq_init - Handle CRQ Init
19960eca353eSBryant G. Ly  *
19970eca353eSBryant G. Ly  * @crq:	ibmvmc_crq_msg struct
19980eca353eSBryant G. Ly  * @adapter:	crq_server_adapter struct
19990eca353eSBryant G. Ly  *
20000eca353eSBryant G. Ly  * Handle the type of crq initialization based on whether
20010eca353eSBryant G. Ly  * it is a message or a response.
20020eca353eSBryant G. Ly  *
20030eca353eSBryant G. Ly  */
ibmvmc_handle_crq_init(struct ibmvmc_crq_msg * crq,struct crq_server_adapter * adapter)20040eca353eSBryant G. Ly static void ibmvmc_handle_crq_init(struct ibmvmc_crq_msg *crq,
20050eca353eSBryant G. Ly 				   struct crq_server_adapter *adapter)
20060eca353eSBryant G. Ly {
20070eca353eSBryant G. Ly 	switch (crq->type) {
20080eca353eSBryant G. Ly 	case 0x01:	/* Initialization message */
20090eca353eSBryant G. Ly 		dev_dbg(adapter->dev, "CRQ recv: CRQ init msg - state 0x%x\n",
20100eca353eSBryant G. Ly 			ibmvmc.state);
20110eca353eSBryant G. Ly 		if (ibmvmc.state == ibmvmc_state_crqinit) {
20120eca353eSBryant G. Ly 			/* Send back a response */
20130eca353eSBryant G. Ly 			if (ibmvmc_send_crq(adapter, 0xC002000000000000,
20140eca353eSBryant G. Ly 					    0) == 0)
20150eca353eSBryant G. Ly 				ibmvmc_send_capabilities(adapter);
20160eca353eSBryant G. Ly 			else
20170eca353eSBryant G. Ly 				dev_err(adapter->dev, " Unable to send init rsp\n");
20180eca353eSBryant G. Ly 		} else {
20190eca353eSBryant G. Ly 			dev_err(adapter->dev, "Invalid state 0x%x mtu = 0x%x\n",
20200eca353eSBryant G. Ly 				ibmvmc.state, ibmvmc.max_mtu);
20210eca353eSBryant G. Ly 		}
20220eca353eSBryant G. Ly 
20230eca353eSBryant G. Ly 		break;
20240eca353eSBryant G. Ly 	case 0x02:	/* Initialization response */
20250eca353eSBryant G. Ly 		dev_dbg(adapter->dev, "CRQ recv: initialization resp msg - state 0x%x\n",
20260eca353eSBryant G. Ly 			ibmvmc.state);
20270eca353eSBryant G. Ly 		if (ibmvmc.state == ibmvmc_state_crqinit)
20280eca353eSBryant G. Ly 			ibmvmc_send_capabilities(adapter);
20290eca353eSBryant G. Ly 		break;
20300eca353eSBryant G. Ly 	default:
20310eca353eSBryant G. Ly 		dev_warn(adapter->dev, "Unknown crq message type 0x%lx\n",
20320eca353eSBryant G. Ly 			 (unsigned long)crq->type);
20330eca353eSBryant G. Ly 	}
20340eca353eSBryant G. Ly }
20350eca353eSBryant G. Ly 
20360eca353eSBryant G. Ly /**
20370eca353eSBryant G. Ly  * ibmvmc_handle_crq - Handle CRQ
20380eca353eSBryant G. Ly  *
20390eca353eSBryant G. Ly  * @crq:	ibmvmc_crq_msg struct
20400eca353eSBryant G. Ly  * @adapter:	crq_server_adapter struct
20410eca353eSBryant G. Ly  *
20420eca353eSBryant G. Ly  * Read the command elements from the command queue and execute the
20430eca353eSBryant G. Ly  * requests based upon the type of crq message.
20440eca353eSBryant G. Ly  *
20450eca353eSBryant G. Ly  */
ibmvmc_handle_crq(struct ibmvmc_crq_msg * crq,struct crq_server_adapter * adapter)20460eca353eSBryant G. Ly static void ibmvmc_handle_crq(struct ibmvmc_crq_msg *crq,
20470eca353eSBryant G. Ly 			      struct crq_server_adapter *adapter)
20480eca353eSBryant G. Ly {
20490eca353eSBryant G. Ly 	switch (crq->valid) {
20500eca353eSBryant G. Ly 	case 0xC0:		/* initialization */
20510eca353eSBryant G. Ly 		ibmvmc_handle_crq_init(crq, adapter);
20520eca353eSBryant G. Ly 		break;
20530eca353eSBryant G. Ly 	case 0xFF:	/* Hypervisor telling us the connection is closed */
20540eca353eSBryant G. Ly 		dev_warn(adapter->dev, "CRQ recv: virtual adapter failed - resetting.\n");
20550eca353eSBryant G. Ly 		ibmvmc_reset(adapter, true);
20560eca353eSBryant G. Ly 		break;
20570eca353eSBryant G. Ly 	case 0x80:	/* real payload */
20580eca353eSBryant G. Ly 		ibmvmc_crq_process(adapter, crq);
20590eca353eSBryant G. Ly 		break;
20600eca353eSBryant G. Ly 	default:
20610eca353eSBryant G. Ly 		dev_warn(adapter->dev, "CRQ recv: unknown msg 0x%02x.\n",
20620eca353eSBryant G. Ly 			 crq->valid);
20630eca353eSBryant G. Ly 		break;
20640eca353eSBryant G. Ly 	}
20650eca353eSBryant G. Ly }
20660eca353eSBryant G. Ly 
ibmvmc_task(unsigned long data)20670eca353eSBryant G. Ly static void ibmvmc_task(unsigned long data)
20680eca353eSBryant G. Ly {
20690eca353eSBryant G. Ly 	struct crq_server_adapter *adapter =
20700eca353eSBryant G. Ly 		(struct crq_server_adapter *)data;
20710eca353eSBryant G. Ly 	struct vio_dev *vdev = to_vio_dev(adapter->dev);
20720eca353eSBryant G. Ly 	struct ibmvmc_crq_msg *crq;
20730eca353eSBryant G. Ly 	int done = 0;
20740eca353eSBryant G. Ly 
20750eca353eSBryant G. Ly 	while (!done) {
20760eca353eSBryant G. Ly 		/* Pull all the valid messages off the CRQ */
20770eca353eSBryant G. Ly 		while ((crq = crq_queue_next_crq(&adapter->queue)) != NULL) {
20780eca353eSBryant G. Ly 			ibmvmc_handle_crq(crq, adapter);
20790eca353eSBryant G. Ly 			crq->valid = 0x00;
20800eca353eSBryant G. Ly 			/* CRQ reset was requested, stop processing CRQs.
20810eca353eSBryant G. Ly 			 * Interrupts will be re-enabled by the reset task.
20820eca353eSBryant G. Ly 			 */
20830eca353eSBryant G. Ly 			if (ibmvmc.state == ibmvmc_state_sched_reset)
20840eca353eSBryant G. Ly 				return;
20850eca353eSBryant G. Ly 		}
20860eca353eSBryant G. Ly 
20870eca353eSBryant G. Ly 		vio_enable_interrupts(vdev);
20880eca353eSBryant G. Ly 		crq = crq_queue_next_crq(&adapter->queue);
20890eca353eSBryant G. Ly 		if (crq) {
20900eca353eSBryant G. Ly 			vio_disable_interrupts(vdev);
20910eca353eSBryant G. Ly 			ibmvmc_handle_crq(crq, adapter);
20920eca353eSBryant G. Ly 			crq->valid = 0x00;
20930eca353eSBryant G. Ly 			/* CRQ reset was requested, stop processing CRQs.
20940eca353eSBryant G. Ly 			 * Interrupts will be re-enabled by the reset task.
20950eca353eSBryant G. Ly 			 */
20960eca353eSBryant G. Ly 			if (ibmvmc.state == ibmvmc_state_sched_reset)
20970eca353eSBryant G. Ly 				return;
20980eca353eSBryant G. Ly 		} else {
20990eca353eSBryant G. Ly 			done = 1;
21000eca353eSBryant G. Ly 		}
21010eca353eSBryant G. Ly 	}
21020eca353eSBryant G. Ly }
21030eca353eSBryant G. Ly 
21040eca353eSBryant G. Ly /**
21050eca353eSBryant G. Ly  * ibmvmc_init_crq_queue - Init CRQ Queue
21060eca353eSBryant G. Ly  *
21070eca353eSBryant G. Ly  * @adapter:	crq_server_adapter struct
21080eca353eSBryant G. Ly  *
21090eca353eSBryant G. Ly  * Return:
21100eca353eSBryant G. Ly  *	0 - Success
21110eca353eSBryant G. Ly  *	Non-zero - Failure
21120eca353eSBryant G. Ly  */
ibmvmc_init_crq_queue(struct crq_server_adapter * adapter)21130eca353eSBryant G. Ly static int ibmvmc_init_crq_queue(struct crq_server_adapter *adapter)
21140eca353eSBryant G. Ly {
21150eca353eSBryant G. Ly 	struct vio_dev *vdev = to_vio_dev(adapter->dev);
21160eca353eSBryant G. Ly 	struct crq_queue *queue = &adapter->queue;
21170eca353eSBryant G. Ly 	int rc = 0;
21180eca353eSBryant G. Ly 	int retrc = 0;
21190eca353eSBryant G. Ly 
21200eca353eSBryant G. Ly 	queue->msgs = (struct ibmvmc_crq_msg *)get_zeroed_page(GFP_KERNEL);
21210eca353eSBryant G. Ly 
21220eca353eSBryant G. Ly 	if (!queue->msgs)
21230eca353eSBryant G. Ly 		goto malloc_failed;
21240eca353eSBryant G. Ly 
21250eca353eSBryant G. Ly 	queue->size = PAGE_SIZE / sizeof(*queue->msgs);
21260eca353eSBryant G. Ly 
21270eca353eSBryant G. Ly 	queue->msg_token = dma_map_single(adapter->dev, queue->msgs,
21280eca353eSBryant G. Ly 					  queue->size * sizeof(*queue->msgs),
21290eca353eSBryant G. Ly 					  DMA_BIDIRECTIONAL);
21300eca353eSBryant G. Ly 
21310eca353eSBryant G. Ly 	if (dma_mapping_error(adapter->dev, queue->msg_token))
21320eca353eSBryant G. Ly 		goto map_failed;
21330eca353eSBryant G. Ly 
21340eca353eSBryant G. Ly 	retrc = plpar_hcall_norets(H_REG_CRQ,
21350eca353eSBryant G. Ly 				   vdev->unit_address,
21360eca353eSBryant G. Ly 				   queue->msg_token, PAGE_SIZE);
2137c55e9318SBryant G. Ly 	rc = retrc;
21380eca353eSBryant G. Ly 
21390eca353eSBryant G. Ly 	if (rc == H_RESOURCE)
21400eca353eSBryant G. Ly 		rc = ibmvmc_reset_crq_queue(adapter);
21410eca353eSBryant G. Ly 
21420eca353eSBryant G. Ly 	if (rc == 2) {
21430eca353eSBryant G. Ly 		dev_warn(adapter->dev, "Partner adapter not ready\n");
21440eca353eSBryant G. Ly 		retrc = 0;
21450eca353eSBryant G. Ly 	} else if (rc != 0) {
21460eca353eSBryant G. Ly 		dev_err(adapter->dev, "Error %d opening adapter\n", rc);
21470eca353eSBryant G. Ly 		goto reg_crq_failed;
21480eca353eSBryant G. Ly 	}
21490eca353eSBryant G. Ly 
21500eca353eSBryant G. Ly 	queue->cur = 0;
21510eca353eSBryant G. Ly 	spin_lock_init(&queue->lock);
21520eca353eSBryant G. Ly 
21530eca353eSBryant G. Ly 	tasklet_init(&adapter->work_task, ibmvmc_task, (unsigned long)adapter);
21540eca353eSBryant G. Ly 
21550eca353eSBryant G. Ly 	if (request_irq(vdev->irq,
21560eca353eSBryant G. Ly 			ibmvmc_handle_event,
21570eca353eSBryant G. Ly 			0, "ibmvmc", (void *)adapter) != 0) {
21580eca353eSBryant G. Ly 		dev_err(adapter->dev, "couldn't register irq 0x%x\n",
21590eca353eSBryant G. Ly 			vdev->irq);
21600eca353eSBryant G. Ly 		goto req_irq_failed;
21610eca353eSBryant G. Ly 	}
21620eca353eSBryant G. Ly 
21630eca353eSBryant G. Ly 	rc = vio_enable_interrupts(vdev);
21640eca353eSBryant G. Ly 	if (rc != 0) {
21650eca353eSBryant G. Ly 		dev_err(adapter->dev, "Error %d enabling interrupts!!!\n", rc);
21660eca353eSBryant G. Ly 		goto req_irq_failed;
21670eca353eSBryant G. Ly 	}
21680eca353eSBryant G. Ly 
21690eca353eSBryant G. Ly 	return retrc;
21700eca353eSBryant G. Ly 
21710eca353eSBryant G. Ly req_irq_failed:
21720eca353eSBryant G. Ly 	/* Cannot have any work since we either never got our IRQ registered,
21730eca353eSBryant G. Ly 	 * or never got interrupts enabled
21740eca353eSBryant G. Ly 	 */
21750eca353eSBryant G. Ly 	tasklet_kill(&adapter->work_task);
21760eca353eSBryant G. Ly 	h_free_crq(vdev->unit_address);
21770eca353eSBryant G. Ly reg_crq_failed:
21780eca353eSBryant G. Ly 	dma_unmap_single(adapter->dev,
21790eca353eSBryant G. Ly 			 queue->msg_token,
21800eca353eSBryant G. Ly 			 queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
21810eca353eSBryant G. Ly map_failed:
21820eca353eSBryant G. Ly 	free_page((unsigned long)queue->msgs);
21830eca353eSBryant G. Ly malloc_failed:
21840eca353eSBryant G. Ly 	return -ENOMEM;
21850eca353eSBryant G. Ly }
21860eca353eSBryant G. Ly 
21870eca353eSBryant G. Ly /* Fill in the liobn and riobn fields on the adapter */
read_dma_window(struct vio_dev * vdev,struct crq_server_adapter * adapter)21880eca353eSBryant G. Ly static int read_dma_window(struct vio_dev *vdev,
21890eca353eSBryant G. Ly 			   struct crq_server_adapter *adapter)
21900eca353eSBryant G. Ly {
21910eca353eSBryant G. Ly 	const __be32 *dma_window;
21920eca353eSBryant G. Ly 	const __be32 *prop;
21930eca353eSBryant G. Ly 
21940eca353eSBryant G. Ly 	/* TODO Using of_parse_dma_window would be better, but it doesn't give
21950eca353eSBryant G. Ly 	 * a way to read multiple windows without already knowing the size of
21960eca353eSBryant G. Ly 	 * a window or the number of windows
21970eca353eSBryant G. Ly 	 */
21980eca353eSBryant G. Ly 	dma_window =
21990eca353eSBryant G. Ly 		(const __be32 *)vio_get_attribute(vdev, "ibm,my-dma-window",
22000eca353eSBryant G. Ly 						NULL);
22010eca353eSBryant G. Ly 	if (!dma_window) {
22020eca353eSBryant G. Ly 		dev_warn(adapter->dev, "Couldn't find ibm,my-dma-window property\n");
22030eca353eSBryant G. Ly 		return -1;
22040eca353eSBryant G. Ly 	}
22050eca353eSBryant G. Ly 
22060eca353eSBryant G. Ly 	adapter->liobn = be32_to_cpu(*dma_window);
22070eca353eSBryant G. Ly 	dma_window++;
22080eca353eSBryant G. Ly 
22090eca353eSBryant G. Ly 	prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-address-cells",
22100eca353eSBryant G. Ly 						NULL);
22110eca353eSBryant G. Ly 	if (!prop) {
22120eca353eSBryant G. Ly 		dev_warn(adapter->dev, "Couldn't find ibm,#dma-address-cells property\n");
22130eca353eSBryant G. Ly 		dma_window++;
22140eca353eSBryant G. Ly 	} else {
22150eca353eSBryant G. Ly 		dma_window += be32_to_cpu(*prop);
22160eca353eSBryant G. Ly 	}
22170eca353eSBryant G. Ly 
22180eca353eSBryant G. Ly 	prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-size-cells",
22190eca353eSBryant G. Ly 						NULL);
22200eca353eSBryant G. Ly 	if (!prop) {
22210eca353eSBryant G. Ly 		dev_warn(adapter->dev, "Couldn't find ibm,#dma-size-cells property\n");
22220eca353eSBryant G. Ly 		dma_window++;
22230eca353eSBryant G. Ly 	} else {
22240eca353eSBryant G. Ly 		dma_window += be32_to_cpu(*prop);
22250eca353eSBryant G. Ly 	}
22260eca353eSBryant G. Ly 
22270eca353eSBryant G. Ly 	/* dma_window should point to the second window now */
22280eca353eSBryant G. Ly 	adapter->riobn = be32_to_cpu(*dma_window);
22290eca353eSBryant G. Ly 
22300eca353eSBryant G. Ly 	return 0;
22310eca353eSBryant G. Ly }
22320eca353eSBryant G. Ly 
ibmvmc_probe(struct vio_dev * vdev,const struct vio_device_id * id)22330eca353eSBryant G. Ly static int ibmvmc_probe(struct vio_dev *vdev, const struct vio_device_id *id)
22340eca353eSBryant G. Ly {
22350eca353eSBryant G. Ly 	struct crq_server_adapter *adapter = &ibmvmc_adapter;
22360eca353eSBryant G. Ly 	int rc;
22370eca353eSBryant G. Ly 
22380eca353eSBryant G. Ly 	dev_set_drvdata(&vdev->dev, NULL);
22390eca353eSBryant G. Ly 	memset(adapter, 0, sizeof(*adapter));
22400eca353eSBryant G. Ly 	adapter->dev = &vdev->dev;
22410eca353eSBryant G. Ly 
22420eca353eSBryant G. Ly 	dev_info(adapter->dev, "Probe for UA 0x%x\n", vdev->unit_address);
22430eca353eSBryant G. Ly 
22440eca353eSBryant G. Ly 	rc = read_dma_window(vdev, adapter);
22450eca353eSBryant G. Ly 	if (rc != 0) {
22460eca353eSBryant G. Ly 		ibmvmc.state = ibmvmc_state_failed;
22470eca353eSBryant G. Ly 		return -1;
22480eca353eSBryant G. Ly 	}
22490eca353eSBryant G. Ly 
22500eca353eSBryant G. Ly 	dev_dbg(adapter->dev, "Probe: liobn 0x%x, riobn 0x%x\n",
22510eca353eSBryant G. Ly 		adapter->liobn, adapter->riobn);
22520eca353eSBryant G. Ly 
22530eca353eSBryant G. Ly 	init_waitqueue_head(&adapter->reset_wait_queue);
22540eca353eSBryant G. Ly 	adapter->reset_task = kthread_run(ibmvmc_reset_task, adapter, "ibmvmc");
22550eca353eSBryant G. Ly 	if (IS_ERR(adapter->reset_task)) {
22560eca353eSBryant G. Ly 		dev_err(adapter->dev, "Failed to start reset thread\n");
22570eca353eSBryant G. Ly 		ibmvmc.state = ibmvmc_state_failed;
22580eca353eSBryant G. Ly 		rc = PTR_ERR(adapter->reset_task);
22590eca353eSBryant G. Ly 		adapter->reset_task = NULL;
22600eca353eSBryant G. Ly 		return rc;
22610eca353eSBryant G. Ly 	}
22620eca353eSBryant G. Ly 
22630eca353eSBryant G. Ly 	rc = ibmvmc_init_crq_queue(adapter);
22640eca353eSBryant G. Ly 	if (rc != 0 && rc != H_RESOURCE) {
22650eca353eSBryant G. Ly 		dev_err(adapter->dev, "Error initializing CRQ.  rc = 0x%x\n",
22660eca353eSBryant G. Ly 			rc);
22670eca353eSBryant G. Ly 		ibmvmc.state = ibmvmc_state_failed;
22680eca353eSBryant G. Ly 		goto crq_failed;
22690eca353eSBryant G. Ly 	}
22700eca353eSBryant G. Ly 
22710eca353eSBryant G. Ly 	ibmvmc.state = ibmvmc_state_crqinit;
22720eca353eSBryant G. Ly 
22730eca353eSBryant G. Ly 	/* Try to send an initialization message.  Note that this is allowed
22740eca353eSBryant G. Ly 	 * to fail if the other end is not acive.  In that case we just wait
22750eca353eSBryant G. Ly 	 * for the other side to initialize.
22760eca353eSBryant G. Ly 	 */
22770eca353eSBryant G. Ly 	if (ibmvmc_send_crq(adapter, 0xC001000000000000LL, 0) != 0 &&
22780eca353eSBryant G. Ly 	    rc != H_RESOURCE)
22790eca353eSBryant G. Ly 		dev_warn(adapter->dev, "Failed to send initialize CRQ message\n");
22800eca353eSBryant G. Ly 
22810eca353eSBryant G. Ly 	dev_set_drvdata(&vdev->dev, adapter);
22820eca353eSBryant G. Ly 
22830eca353eSBryant G. Ly 	return 0;
22840eca353eSBryant G. Ly 
22850eca353eSBryant G. Ly crq_failed:
22860eca353eSBryant G. Ly 	kthread_stop(adapter->reset_task);
22870eca353eSBryant G. Ly 	adapter->reset_task = NULL;
22880eca353eSBryant G. Ly 	return -EPERM;
22890eca353eSBryant G. Ly }
22900eca353eSBryant G. Ly 
ibmvmc_remove(struct vio_dev * vdev)2291386a966fSUwe Kleine-König static void ibmvmc_remove(struct vio_dev *vdev)
22920eca353eSBryant G. Ly {
22930eca353eSBryant G. Ly 	struct crq_server_adapter *adapter = dev_get_drvdata(&vdev->dev);
22940eca353eSBryant G. Ly 
22950eca353eSBryant G. Ly 	dev_info(adapter->dev, "Entering remove for UA 0x%x\n",
22960eca353eSBryant G. Ly 		 vdev->unit_address);
22970eca353eSBryant G. Ly 	ibmvmc_release_crq_queue(adapter);
22980eca353eSBryant G. Ly }
22990eca353eSBryant G. Ly 
23000eca353eSBryant G. Ly static struct vio_device_id ibmvmc_device_table[] = {
23010eca353eSBryant G. Ly 	{ "ibm,vmc", "IBM,vmc" },
23020eca353eSBryant G. Ly 	{ "", "" }
23030eca353eSBryant G. Ly };
23040eca353eSBryant G. Ly MODULE_DEVICE_TABLE(vio, ibmvmc_device_table);
23050eca353eSBryant G. Ly 
23060eca353eSBryant G. Ly static struct vio_driver ibmvmc_driver = {
23070eca353eSBryant G. Ly 	.name        = ibmvmc_driver_name,
23080eca353eSBryant G. Ly 	.id_table    = ibmvmc_device_table,
23090eca353eSBryant G. Ly 	.probe       = ibmvmc_probe,
23100eca353eSBryant G. Ly 	.remove      = ibmvmc_remove,
23110eca353eSBryant G. Ly };
23120eca353eSBryant G. Ly 
ibmvmc_scrub_module_parms(void)23130eca353eSBryant G. Ly static void __init ibmvmc_scrub_module_parms(void)
23140eca353eSBryant G. Ly {
23150eca353eSBryant G. Ly 	if (ibmvmc_max_mtu > MAX_MTU) {
23160eca353eSBryant G. Ly 		pr_warn("ibmvmc: Max MTU reduced to %d\n", MAX_MTU);
23170eca353eSBryant G. Ly 		ibmvmc_max_mtu = MAX_MTU;
23180eca353eSBryant G. Ly 	} else if (ibmvmc_max_mtu < MIN_MTU) {
23190eca353eSBryant G. Ly 		pr_warn("ibmvmc: Max MTU increased to %d\n", MIN_MTU);
23200eca353eSBryant G. Ly 		ibmvmc_max_mtu = MIN_MTU;
23210eca353eSBryant G. Ly 	}
23220eca353eSBryant G. Ly 
23230eca353eSBryant G. Ly 	if (ibmvmc_max_buf_pool_size > MAX_BUF_POOL_SIZE) {
23240eca353eSBryant G. Ly 		pr_warn("ibmvmc: Max buffer pool size reduced to %d\n",
23250eca353eSBryant G. Ly 			MAX_BUF_POOL_SIZE);
23260eca353eSBryant G. Ly 		ibmvmc_max_buf_pool_size = MAX_BUF_POOL_SIZE;
23270eca353eSBryant G. Ly 	} else if (ibmvmc_max_buf_pool_size < MIN_BUF_POOL_SIZE) {
23280eca353eSBryant G. Ly 		pr_warn("ibmvmc: Max buffer pool size increased to %d\n",
23290eca353eSBryant G. Ly 			MIN_BUF_POOL_SIZE);
23300eca353eSBryant G. Ly 		ibmvmc_max_buf_pool_size = MIN_BUF_POOL_SIZE;
23310eca353eSBryant G. Ly 	}
23320eca353eSBryant G. Ly 
23330eca353eSBryant G. Ly 	if (ibmvmc_max_hmcs > MAX_HMCS) {
23340eca353eSBryant G. Ly 		pr_warn("ibmvmc: Max HMCs reduced to %d\n", MAX_HMCS);
23350eca353eSBryant G. Ly 		ibmvmc_max_hmcs = MAX_HMCS;
23360eca353eSBryant G. Ly 	} else if (ibmvmc_max_hmcs < MIN_HMCS) {
23370eca353eSBryant G. Ly 		pr_warn("ibmvmc: Max HMCs increased to %d\n", MIN_HMCS);
23380eca353eSBryant G. Ly 		ibmvmc_max_hmcs = MIN_HMCS;
23390eca353eSBryant G. Ly 	}
23400eca353eSBryant G. Ly }
23410eca353eSBryant G. Ly 
23420eca353eSBryant G. Ly static struct miscdevice ibmvmc_miscdev = {
23430eca353eSBryant G. Ly 	.name = ibmvmc_driver_name,
23440eca353eSBryant G. Ly 	.minor = MISC_DYNAMIC_MINOR,
23450eca353eSBryant G. Ly 	.fops = &ibmvmc_fops,
23460eca353eSBryant G. Ly };
23470eca353eSBryant G. Ly 
ibmvmc_module_init(void)23480eca353eSBryant G. Ly static int __init ibmvmc_module_init(void)
23490eca353eSBryant G. Ly {
23500eca353eSBryant G. Ly 	int rc, i, j;
23510eca353eSBryant G. Ly 
23520eca353eSBryant G. Ly 	ibmvmc.state = ibmvmc_state_initial;
23530eca353eSBryant G. Ly 	pr_info("ibmvmc: version %s\n", IBMVMC_DRIVER_VERSION);
23540eca353eSBryant G. Ly 
23550eca353eSBryant G. Ly 	rc = misc_register(&ibmvmc_miscdev);
23560eca353eSBryant G. Ly 	if (rc) {
23570eca353eSBryant G. Ly 		pr_err("ibmvmc: misc registration failed\n");
23580eca353eSBryant G. Ly 		goto misc_register_failed;
23590eca353eSBryant G. Ly 	}
23600eca353eSBryant G. Ly 	pr_info("ibmvmc: node %d:%d\n", MISC_MAJOR,
23610eca353eSBryant G. Ly 		ibmvmc_miscdev.minor);
23620eca353eSBryant G. Ly 
23630eca353eSBryant G. Ly 	/* Initialize data structures */
23640eca353eSBryant G. Ly 	memset(hmcs, 0, sizeof(struct ibmvmc_hmc) * MAX_HMCS);
23650eca353eSBryant G. Ly 	for (i = 0; i < MAX_HMCS; i++) {
23660eca353eSBryant G. Ly 		spin_lock_init(&hmcs[i].lock);
23670eca353eSBryant G. Ly 		hmcs[i].state = ibmhmc_state_free;
23680eca353eSBryant G. Ly 		for (j = 0; j < MAX_BUF_POOL_SIZE; j++)
23690eca353eSBryant G. Ly 			hmcs[i].queue_outbound_msgs[j] = VMC_INVALID_BUFFER_ID;
23700eca353eSBryant G. Ly 	}
23710eca353eSBryant G. Ly 
23720eca353eSBryant G. Ly 	/* Sanity check module parms */
23730eca353eSBryant G. Ly 	ibmvmc_scrub_module_parms();
23740eca353eSBryant G. Ly 
23750eca353eSBryant G. Ly 	/*
23760eca353eSBryant G. Ly 	 * Initialize some reasonable values.  Might be negotiated smaller
23770eca353eSBryant G. Ly 	 * values during the capabilities exchange.
23780eca353eSBryant G. Ly 	 */
23790eca353eSBryant G. Ly 	ibmvmc.max_mtu = ibmvmc_max_mtu;
23800eca353eSBryant G. Ly 	ibmvmc.max_buffer_pool_size = ibmvmc_max_buf_pool_size;
23810eca353eSBryant G. Ly 	ibmvmc.max_hmc_index = ibmvmc_max_hmcs - 1;
23820eca353eSBryant G. Ly 
23830eca353eSBryant G. Ly 	rc = vio_register_driver(&ibmvmc_driver);
23840eca353eSBryant G. Ly 
23850eca353eSBryant G. Ly 	if (rc) {
23860eca353eSBryant G. Ly 		pr_err("ibmvmc: rc %d from vio_register_driver\n", rc);
23870eca353eSBryant G. Ly 		goto vio_reg_failed;
23880eca353eSBryant G. Ly 	}
23890eca353eSBryant G. Ly 
23900eca353eSBryant G. Ly 	return 0;
23910eca353eSBryant G. Ly 
23920eca353eSBryant G. Ly vio_reg_failed:
23930eca353eSBryant G. Ly 	misc_deregister(&ibmvmc_miscdev);
23940eca353eSBryant G. Ly misc_register_failed:
23950eca353eSBryant G. Ly 	return rc;
23960eca353eSBryant G. Ly }
23970eca353eSBryant G. Ly 
ibmvmc_module_exit(void)23980eca353eSBryant G. Ly static void __exit ibmvmc_module_exit(void)
23990eca353eSBryant G. Ly {
24000eca353eSBryant G. Ly 	pr_info("ibmvmc: module exit\n");
24010eca353eSBryant G. Ly 	vio_unregister_driver(&ibmvmc_driver);
24020eca353eSBryant G. Ly 	misc_deregister(&ibmvmc_miscdev);
24030eca353eSBryant G. Ly }
24040eca353eSBryant G. Ly 
24050eca353eSBryant G. Ly module_init(ibmvmc_module_init);
24060eca353eSBryant G. Ly module_exit(ibmvmc_module_exit);
24070eca353eSBryant G. Ly 
24080eca353eSBryant G. Ly module_param_named(buf_pool_size, ibmvmc_max_buf_pool_size,
24090eca353eSBryant G. Ly 		   int, 0644);
24100eca353eSBryant G. Ly MODULE_PARM_DESC(buf_pool_size, "Buffer pool size");
24110eca353eSBryant G. Ly module_param_named(max_hmcs, ibmvmc_max_hmcs, int, 0644);
24120eca353eSBryant G. Ly MODULE_PARM_DESC(max_hmcs, "Max HMCs");
24130eca353eSBryant G. Ly module_param_named(max_mtu, ibmvmc_max_mtu, int, 0644);
24140eca353eSBryant G. Ly MODULE_PARM_DESC(max_mtu, "Max MTU");
24150eca353eSBryant G. Ly 
24160eca353eSBryant G. Ly MODULE_AUTHOR("Steven Royer <seroyer@linux.vnet.ibm.com>");
24170eca353eSBryant G. Ly MODULE_DESCRIPTION("IBM VMC");
24180eca353eSBryant G. Ly MODULE_VERSION(IBMVMC_DRIVER_VERSION);
24190eca353eSBryant G. Ly MODULE_LICENSE("GPL v2");
2420