18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * IBM Power Systems Virtual Management Channel Support.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2004, 2018 IBM Corp.
68c2ecf20Sopenharmony_ci *   Dave Engebretsen engebret@us.ibm.com
78c2ecf20Sopenharmony_ci *   Steven Royer seroyer@linux.vnet.ibm.com
88c2ecf20Sopenharmony_ci *   Adam Reznechek adreznec@linux.vnet.ibm.com
98c2ecf20Sopenharmony_ci *   Bryant G. Ly <bryantly@linux.vnet.ibm.com>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/kthread.h>
158c2ecf20Sopenharmony_ci#include <linux/major.h>
168c2ecf20Sopenharmony_ci#include <linux/string.h>
178c2ecf20Sopenharmony_ci#include <linux/fcntl.h>
188c2ecf20Sopenharmony_ci#include <linux/slab.h>
198c2ecf20Sopenharmony_ci#include <linux/poll.h>
208c2ecf20Sopenharmony_ci#include <linux/init.h>
218c2ecf20Sopenharmony_ci#include <linux/fs.h>
228c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
238c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
248c2ecf20Sopenharmony_ci#include <linux/percpu.h>
258c2ecf20Sopenharmony_ci#include <linux/delay.h>
268c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
278c2ecf20Sopenharmony_ci#include <linux/io.h>
288c2ecf20Sopenharmony_ci#include <linux/miscdevice.h>
298c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include <asm/byteorder.h>
328c2ecf20Sopenharmony_ci#include <asm/irq.h>
338c2ecf20Sopenharmony_ci#include <asm/vio.h>
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include "ibmvmc.h"
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#define IBMVMC_DRIVER_VERSION "1.0"
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/*
408c2ecf20Sopenharmony_ci * Static global variables
418c2ecf20Sopenharmony_ci */
428c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(ibmvmc_read_wait);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic const char ibmvmc_driver_name[] = "ibmvmc";
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic struct ibmvmc_struct ibmvmc;
478c2ecf20Sopenharmony_cistatic struct ibmvmc_hmc hmcs[MAX_HMCS];
488c2ecf20Sopenharmony_cistatic struct crq_server_adapter ibmvmc_adapter;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic int ibmvmc_max_buf_pool_size = DEFAULT_BUF_POOL_SIZE;
518c2ecf20Sopenharmony_cistatic int ibmvmc_max_hmcs = DEFAULT_HMCS;
528c2ecf20Sopenharmony_cistatic int ibmvmc_max_mtu = DEFAULT_MTU;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic inline long h_copy_rdma(s64 length, u64 sliobn, u64 slioba,
558c2ecf20Sopenharmony_ci			       u64 dliobn, u64 dlioba)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	long rc = 0;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	/* Ensure all writes to source memory are visible before hcall */
608c2ecf20Sopenharmony_ci	dma_wmb();
618c2ecf20Sopenharmony_ci	pr_debug("ibmvmc: h_copy_rdma(0x%llx, 0x%llx, 0x%llx, 0x%llx, 0x%llx\n",
628c2ecf20Sopenharmony_ci		 length, sliobn, slioba, dliobn, dlioba);
638c2ecf20Sopenharmony_ci	rc = plpar_hcall_norets(H_COPY_RDMA, length, sliobn, slioba,
648c2ecf20Sopenharmony_ci				dliobn, dlioba);
658c2ecf20Sopenharmony_ci	pr_debug("ibmvmc: h_copy_rdma rc = 0x%lx\n", rc);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	return rc;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic inline void h_free_crq(uint32_t unit_address)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	long rc = 0;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	do {
758c2ecf20Sopenharmony_ci		if (H_IS_LONG_BUSY(rc))
768c2ecf20Sopenharmony_ci			msleep(get_longbusy_msecs(rc));
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci		rc = plpar_hcall_norets(H_FREE_CRQ, unit_address);
798c2ecf20Sopenharmony_ci	} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci/**
838c2ecf20Sopenharmony_ci * h_request_vmc: - request a hypervisor virtual management channel device
848c2ecf20Sopenharmony_ci * @vmc_index: drc index of the vmc device created
858c2ecf20Sopenharmony_ci *
868c2ecf20Sopenharmony_ci * Requests the hypervisor create a new virtual management channel device,
878c2ecf20Sopenharmony_ci * allowing this partition to send hypervisor virtualization control
888c2ecf20Sopenharmony_ci * commands.
898c2ecf20Sopenharmony_ci *
908c2ecf20Sopenharmony_ci * Return:
918c2ecf20Sopenharmony_ci *	0 - Success
928c2ecf20Sopenharmony_ci *	Non-zero - Failure
938c2ecf20Sopenharmony_ci */
948c2ecf20Sopenharmony_cistatic inline long h_request_vmc(u32 *vmc_index)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	long rc = 0;
978c2ecf20Sopenharmony_ci	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	do {
1008c2ecf20Sopenharmony_ci		if (H_IS_LONG_BUSY(rc))
1018c2ecf20Sopenharmony_ci			msleep(get_longbusy_msecs(rc));
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci		/* Call to request the VMC device from phyp */
1048c2ecf20Sopenharmony_ci		rc = plpar_hcall(H_REQUEST_VMC, retbuf);
1058c2ecf20Sopenharmony_ci		pr_debug("ibmvmc: %s rc = 0x%lx\n", __func__, rc);
1068c2ecf20Sopenharmony_ci		*vmc_index = retbuf[0];
1078c2ecf20Sopenharmony_ci	} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	return rc;
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci/* routines for managing a command/response queue */
1138c2ecf20Sopenharmony_ci/**
1148c2ecf20Sopenharmony_ci * ibmvmc_handle_event: - Interrupt handler for crq events
1158c2ecf20Sopenharmony_ci * @irq:        number of irq to handle, not used
1168c2ecf20Sopenharmony_ci * @dev_instance: crq_server_adapter that received interrupt
1178c2ecf20Sopenharmony_ci *
1188c2ecf20Sopenharmony_ci * Disables interrupts and schedules ibmvmc_task
1198c2ecf20Sopenharmony_ci *
1208c2ecf20Sopenharmony_ci * Always returns IRQ_HANDLED
1218c2ecf20Sopenharmony_ci */
1228c2ecf20Sopenharmony_cistatic irqreturn_t ibmvmc_handle_event(int irq, void *dev_instance)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	struct crq_server_adapter *adapter =
1258c2ecf20Sopenharmony_ci		(struct crq_server_adapter *)dev_instance;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	vio_disable_interrupts(to_vio_dev(adapter->dev));
1288c2ecf20Sopenharmony_ci	tasklet_schedule(&adapter->work_task);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci/**
1348c2ecf20Sopenharmony_ci * ibmvmc_release_crq_queue - Release CRQ Queue
1358c2ecf20Sopenharmony_ci *
1368c2ecf20Sopenharmony_ci * @adapter:	crq_server_adapter struct
1378c2ecf20Sopenharmony_ci *
1388c2ecf20Sopenharmony_ci * Return:
1398c2ecf20Sopenharmony_ci *	0 - Success
1408c2ecf20Sopenharmony_ci *	Non-Zero - Failure
1418c2ecf20Sopenharmony_ci */
1428c2ecf20Sopenharmony_cistatic void ibmvmc_release_crq_queue(struct crq_server_adapter *adapter)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	struct vio_dev *vdev = to_vio_dev(adapter->dev);
1458c2ecf20Sopenharmony_ci	struct crq_queue *queue = &adapter->queue;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	free_irq(vdev->irq, (void *)adapter);
1488c2ecf20Sopenharmony_ci	tasklet_kill(&adapter->work_task);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	if (adapter->reset_task)
1518c2ecf20Sopenharmony_ci		kthread_stop(adapter->reset_task);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	h_free_crq(vdev->unit_address);
1548c2ecf20Sopenharmony_ci	dma_unmap_single(adapter->dev,
1558c2ecf20Sopenharmony_ci			 queue->msg_token,
1568c2ecf20Sopenharmony_ci			 queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
1578c2ecf20Sopenharmony_ci	free_page((unsigned long)queue->msgs);
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci/**
1618c2ecf20Sopenharmony_ci * ibmvmc_reset_crq_queue - Reset CRQ Queue
1628c2ecf20Sopenharmony_ci *
1638c2ecf20Sopenharmony_ci * @adapter:	crq_server_adapter struct
1648c2ecf20Sopenharmony_ci *
1658c2ecf20Sopenharmony_ci * This function calls h_free_crq and then calls H_REG_CRQ and does all the
1668c2ecf20Sopenharmony_ci * bookkeeping to get us back to where we can communicate.
1678c2ecf20Sopenharmony_ci *
1688c2ecf20Sopenharmony_ci * Return:
1698c2ecf20Sopenharmony_ci *	0 - Success
1708c2ecf20Sopenharmony_ci *	Non-Zero - Failure
1718c2ecf20Sopenharmony_ci */
1728c2ecf20Sopenharmony_cistatic int ibmvmc_reset_crq_queue(struct crq_server_adapter *adapter)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	struct vio_dev *vdev = to_vio_dev(adapter->dev);
1758c2ecf20Sopenharmony_ci	struct crq_queue *queue = &adapter->queue;
1768c2ecf20Sopenharmony_ci	int rc = 0;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	/* Close the CRQ */
1798c2ecf20Sopenharmony_ci	h_free_crq(vdev->unit_address);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	/* Clean out the queue */
1828c2ecf20Sopenharmony_ci	memset(queue->msgs, 0x00, PAGE_SIZE);
1838c2ecf20Sopenharmony_ci	queue->cur = 0;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	/* And re-open it again */
1868c2ecf20Sopenharmony_ci	rc = plpar_hcall_norets(H_REG_CRQ,
1878c2ecf20Sopenharmony_ci				vdev->unit_address,
1888c2ecf20Sopenharmony_ci				queue->msg_token, PAGE_SIZE);
1898c2ecf20Sopenharmony_ci	if (rc == 2)
1908c2ecf20Sopenharmony_ci		/* Adapter is good, but other end is not ready */
1918c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "Partner adapter not ready\n");
1928c2ecf20Sopenharmony_ci	else if (rc != 0)
1938c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "couldn't register crq--rc 0x%x\n", rc);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	return rc;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci/**
1998c2ecf20Sopenharmony_ci * crq_queue_next_crq: - Returns the next entry in message queue
2008c2ecf20Sopenharmony_ci * @queue:      crq_queue to use
2018c2ecf20Sopenharmony_ci *
2028c2ecf20Sopenharmony_ci * Returns pointer to next entry in queue, or NULL if there are no new
2038c2ecf20Sopenharmony_ci * entried in the CRQ.
2048c2ecf20Sopenharmony_ci */
2058c2ecf20Sopenharmony_cistatic struct ibmvmc_crq_msg *crq_queue_next_crq(struct crq_queue *queue)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	struct ibmvmc_crq_msg *crq;
2088c2ecf20Sopenharmony_ci	unsigned long flags;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	spin_lock_irqsave(&queue->lock, flags);
2118c2ecf20Sopenharmony_ci	crq = &queue->msgs[queue->cur];
2128c2ecf20Sopenharmony_ci	if (crq->valid & 0x80) {
2138c2ecf20Sopenharmony_ci		if (++queue->cur == queue->size)
2148c2ecf20Sopenharmony_ci			queue->cur = 0;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci		/* Ensure the read of the valid bit occurs before reading any
2178c2ecf20Sopenharmony_ci		 * other bits of the CRQ entry
2188c2ecf20Sopenharmony_ci		 */
2198c2ecf20Sopenharmony_ci		dma_rmb();
2208c2ecf20Sopenharmony_ci	} else {
2218c2ecf20Sopenharmony_ci		crq = NULL;
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&queue->lock, flags);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	return crq;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci/**
2308c2ecf20Sopenharmony_ci * ibmvmc_send_crq - Send CRQ
2318c2ecf20Sopenharmony_ci *
2328c2ecf20Sopenharmony_ci * @adapter:	crq_server_adapter struct
2338c2ecf20Sopenharmony_ci * @word1:	Word1 Data field
2348c2ecf20Sopenharmony_ci * @word2:	Word2 Data field
2358c2ecf20Sopenharmony_ci *
2368c2ecf20Sopenharmony_ci * Return:
2378c2ecf20Sopenharmony_ci *	0 - Success
2388c2ecf20Sopenharmony_ci *	Non-Zero - Failure
2398c2ecf20Sopenharmony_ci */
2408c2ecf20Sopenharmony_cistatic long ibmvmc_send_crq(struct crq_server_adapter *adapter,
2418c2ecf20Sopenharmony_ci			    u64 word1, u64 word2)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	struct vio_dev *vdev = to_vio_dev(adapter->dev);
2448c2ecf20Sopenharmony_ci	long rc = 0;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "(0x%x, 0x%016llx, 0x%016llx)\n",
2478c2ecf20Sopenharmony_ci		vdev->unit_address, word1, word2);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	/*
2508c2ecf20Sopenharmony_ci	 * Ensure the command buffer is flushed to memory before handing it
2518c2ecf20Sopenharmony_ci	 * over to the other side to prevent it from fetching any stale data.
2528c2ecf20Sopenharmony_ci	 */
2538c2ecf20Sopenharmony_ci	dma_wmb();
2548c2ecf20Sopenharmony_ci	rc = plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2);
2558c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "rc = 0x%lx\n", rc);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	return rc;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci/**
2618c2ecf20Sopenharmony_ci * alloc_dma_buffer - Create DMA Buffer
2628c2ecf20Sopenharmony_ci *
2638c2ecf20Sopenharmony_ci * @vdev:	vio_dev struct
2648c2ecf20Sopenharmony_ci * @size:	Size field
2658c2ecf20Sopenharmony_ci * @dma_handle:	DMA address field
2668c2ecf20Sopenharmony_ci *
2678c2ecf20Sopenharmony_ci * Allocates memory for the command queue and maps remote memory into an
2688c2ecf20Sopenharmony_ci * ioba.
2698c2ecf20Sopenharmony_ci *
2708c2ecf20Sopenharmony_ci * Returns a pointer to the buffer
2718c2ecf20Sopenharmony_ci */
2728c2ecf20Sopenharmony_cistatic void *alloc_dma_buffer(struct vio_dev *vdev, size_t size,
2738c2ecf20Sopenharmony_ci			      dma_addr_t *dma_handle)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	/* allocate memory */
2768c2ecf20Sopenharmony_ci	void *buffer = kzalloc(size, GFP_ATOMIC);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (!buffer) {
2798c2ecf20Sopenharmony_ci		*dma_handle = 0;
2808c2ecf20Sopenharmony_ci		return NULL;
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	/* DMA map */
2848c2ecf20Sopenharmony_ci	*dma_handle = dma_map_single(&vdev->dev, buffer, size,
2858c2ecf20Sopenharmony_ci				     DMA_BIDIRECTIONAL);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	if (dma_mapping_error(&vdev->dev, *dma_handle)) {
2888c2ecf20Sopenharmony_ci		*dma_handle = 0;
2898c2ecf20Sopenharmony_ci		kfree_sensitive(buffer);
2908c2ecf20Sopenharmony_ci		return NULL;
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	return buffer;
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci/**
2978c2ecf20Sopenharmony_ci * free_dma_buffer - Free DMA Buffer
2988c2ecf20Sopenharmony_ci *
2998c2ecf20Sopenharmony_ci * @vdev:	vio_dev struct
3008c2ecf20Sopenharmony_ci * @size:	Size field
3018c2ecf20Sopenharmony_ci * @vaddr:	Address field
3028c2ecf20Sopenharmony_ci * @dma_handle:	DMA address field
3038c2ecf20Sopenharmony_ci *
3048c2ecf20Sopenharmony_ci * Releases memory for a command queue and unmaps mapped remote memory.
3058c2ecf20Sopenharmony_ci */
3068c2ecf20Sopenharmony_cistatic void free_dma_buffer(struct vio_dev *vdev, size_t size, void *vaddr,
3078c2ecf20Sopenharmony_ci			    dma_addr_t dma_handle)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	/* DMA unmap */
3108c2ecf20Sopenharmony_ci	dma_unmap_single(&vdev->dev, dma_handle, size, DMA_BIDIRECTIONAL);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	/* deallocate memory */
3138c2ecf20Sopenharmony_ci	kfree_sensitive(vaddr);
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci/**
3178c2ecf20Sopenharmony_ci * ibmvmc_get_valid_hmc_buffer - Retrieve Valid HMC Buffer
3188c2ecf20Sopenharmony_ci *
3198c2ecf20Sopenharmony_ci * @hmc_index:	HMC Index Field
3208c2ecf20Sopenharmony_ci *
3218c2ecf20Sopenharmony_ci * Return:
3228c2ecf20Sopenharmony_ci *	Pointer to ibmvmc_buffer
3238c2ecf20Sopenharmony_ci */
3248c2ecf20Sopenharmony_cistatic struct ibmvmc_buffer *ibmvmc_get_valid_hmc_buffer(u8 hmc_index)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	struct ibmvmc_buffer *buffer;
3278c2ecf20Sopenharmony_ci	struct ibmvmc_buffer *ret_buf = NULL;
3288c2ecf20Sopenharmony_ci	unsigned long i;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if (hmc_index > ibmvmc.max_hmc_index)
3318c2ecf20Sopenharmony_ci		return NULL;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	buffer = hmcs[hmc_index].buffer;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	for (i = 0; i < ibmvmc_max_buf_pool_size; i++) {
3368c2ecf20Sopenharmony_ci		if (buffer[i].valid && buffer[i].free &&
3378c2ecf20Sopenharmony_ci		    buffer[i].owner == VMC_BUF_OWNER_ALPHA) {
3388c2ecf20Sopenharmony_ci			buffer[i].free = 0;
3398c2ecf20Sopenharmony_ci			ret_buf = &buffer[i];
3408c2ecf20Sopenharmony_ci			break;
3418c2ecf20Sopenharmony_ci		}
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	return ret_buf;
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci/**
3488c2ecf20Sopenharmony_ci * ibmvmc_get_free_hmc_buffer - Get Free HMC Buffer
3498c2ecf20Sopenharmony_ci *
3508c2ecf20Sopenharmony_ci * @adapter:	crq_server_adapter struct
3518c2ecf20Sopenharmony_ci * @hmc_index:	Hmc Index field
3528c2ecf20Sopenharmony_ci *
3538c2ecf20Sopenharmony_ci * Return:
3548c2ecf20Sopenharmony_ci *	Pointer to ibmvmc_buffer
3558c2ecf20Sopenharmony_ci */
3568c2ecf20Sopenharmony_cistatic struct ibmvmc_buffer *ibmvmc_get_free_hmc_buffer(struct crq_server_adapter *adapter,
3578c2ecf20Sopenharmony_ci							u8 hmc_index)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	struct ibmvmc_buffer *buffer;
3608c2ecf20Sopenharmony_ci	struct ibmvmc_buffer *ret_buf = NULL;
3618c2ecf20Sopenharmony_ci	unsigned long i;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	if (hmc_index > ibmvmc.max_hmc_index) {
3648c2ecf20Sopenharmony_ci		dev_info(adapter->dev, "get_free_hmc_buffer: invalid hmc_index=0x%x\n",
3658c2ecf20Sopenharmony_ci			 hmc_index);
3668c2ecf20Sopenharmony_ci		return NULL;
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	buffer = hmcs[hmc_index].buffer;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	for (i = 0; i < ibmvmc_max_buf_pool_size; i++) {
3728c2ecf20Sopenharmony_ci		if (buffer[i].free &&
3738c2ecf20Sopenharmony_ci		    buffer[i].owner == VMC_BUF_OWNER_ALPHA) {
3748c2ecf20Sopenharmony_ci			buffer[i].free = 0;
3758c2ecf20Sopenharmony_ci			ret_buf = &buffer[i];
3768c2ecf20Sopenharmony_ci			break;
3778c2ecf20Sopenharmony_ci		}
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	return ret_buf;
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci/**
3848c2ecf20Sopenharmony_ci * ibmvmc_free_hmc_buffer - Free an HMC Buffer
3858c2ecf20Sopenharmony_ci *
3868c2ecf20Sopenharmony_ci * @hmc:	ibmvmc_hmc struct
3878c2ecf20Sopenharmony_ci * @buffer:	ibmvmc_buffer struct
3888c2ecf20Sopenharmony_ci *
3898c2ecf20Sopenharmony_ci */
3908c2ecf20Sopenharmony_cistatic void ibmvmc_free_hmc_buffer(struct ibmvmc_hmc *hmc,
3918c2ecf20Sopenharmony_ci				   struct ibmvmc_buffer *buffer)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	unsigned long flags;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hmc->lock, flags);
3968c2ecf20Sopenharmony_ci	buffer->free = 1;
3978c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hmc->lock, flags);
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci/**
4018c2ecf20Sopenharmony_ci * ibmvmc_count_hmc_buffers - Count HMC Buffers
4028c2ecf20Sopenharmony_ci *
4038c2ecf20Sopenharmony_ci * @hmc_index:	HMC Index field
4048c2ecf20Sopenharmony_ci * @valid:	Valid number of buffers field
4058c2ecf20Sopenharmony_ci * @free:	Free number of buffers field
4068c2ecf20Sopenharmony_ci *
4078c2ecf20Sopenharmony_ci */
4088c2ecf20Sopenharmony_cistatic void ibmvmc_count_hmc_buffers(u8 hmc_index, unsigned int *valid,
4098c2ecf20Sopenharmony_ci				     unsigned int *free)
4108c2ecf20Sopenharmony_ci{
4118c2ecf20Sopenharmony_ci	struct ibmvmc_buffer *buffer;
4128c2ecf20Sopenharmony_ci	unsigned long i;
4138c2ecf20Sopenharmony_ci	unsigned long flags;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	if (hmc_index > ibmvmc.max_hmc_index)
4168c2ecf20Sopenharmony_ci		return;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	if (!valid || !free)
4198c2ecf20Sopenharmony_ci		return;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	*valid = 0; *free = 0;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	buffer = hmcs[hmc_index].buffer;
4248c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hmcs[hmc_index].lock, flags);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	for (i = 0; i < ibmvmc_max_buf_pool_size; i++) {
4278c2ecf20Sopenharmony_ci		if (buffer[i].valid) {
4288c2ecf20Sopenharmony_ci			*valid = *valid + 1;
4298c2ecf20Sopenharmony_ci			if (buffer[i].free)
4308c2ecf20Sopenharmony_ci				*free = *free + 1;
4318c2ecf20Sopenharmony_ci		}
4328c2ecf20Sopenharmony_ci	}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags);
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci/**
4388c2ecf20Sopenharmony_ci * ibmvmc_get_free_hmc - Get Free HMC
4398c2ecf20Sopenharmony_ci *
4408c2ecf20Sopenharmony_ci * Return:
4418c2ecf20Sopenharmony_ci *	Pointer to an available HMC Connection
4428c2ecf20Sopenharmony_ci *	Null otherwise
4438c2ecf20Sopenharmony_ci */
4448c2ecf20Sopenharmony_cistatic struct ibmvmc_hmc *ibmvmc_get_free_hmc(void)
4458c2ecf20Sopenharmony_ci{
4468c2ecf20Sopenharmony_ci	unsigned long i;
4478c2ecf20Sopenharmony_ci	unsigned long flags;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	/*
4508c2ecf20Sopenharmony_ci	 * Find an available HMC connection.
4518c2ecf20Sopenharmony_ci	 */
4528c2ecf20Sopenharmony_ci	for (i = 0; i <= ibmvmc.max_hmc_index; i++) {
4538c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hmcs[i].lock, flags);
4548c2ecf20Sopenharmony_ci		if (hmcs[i].state == ibmhmc_state_free) {
4558c2ecf20Sopenharmony_ci			hmcs[i].index = i;
4568c2ecf20Sopenharmony_ci			hmcs[i].state = ibmhmc_state_initial;
4578c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&hmcs[i].lock, flags);
4588c2ecf20Sopenharmony_ci			return &hmcs[i];
4598c2ecf20Sopenharmony_ci		}
4608c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hmcs[i].lock, flags);
4618c2ecf20Sopenharmony_ci	}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	return NULL;
4648c2ecf20Sopenharmony_ci}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci/**
4678c2ecf20Sopenharmony_ci * ibmvmc_return_hmc - Return an HMC Connection
4688c2ecf20Sopenharmony_ci *
4698c2ecf20Sopenharmony_ci * @hmc:		ibmvmc_hmc struct
4708c2ecf20Sopenharmony_ci * @release_readers:	Number of readers connected to session
4718c2ecf20Sopenharmony_ci *
4728c2ecf20Sopenharmony_ci * This function releases the HMC connections back into the pool.
4738c2ecf20Sopenharmony_ci *
4748c2ecf20Sopenharmony_ci * Return:
4758c2ecf20Sopenharmony_ci *	0 - Success
4768c2ecf20Sopenharmony_ci *	Non-zero - Failure
4778c2ecf20Sopenharmony_ci */
4788c2ecf20Sopenharmony_cistatic int ibmvmc_return_hmc(struct ibmvmc_hmc *hmc, bool release_readers)
4798c2ecf20Sopenharmony_ci{
4808c2ecf20Sopenharmony_ci	struct ibmvmc_buffer *buffer;
4818c2ecf20Sopenharmony_ci	struct crq_server_adapter *adapter;
4828c2ecf20Sopenharmony_ci	struct vio_dev *vdev;
4838c2ecf20Sopenharmony_ci	unsigned long i;
4848c2ecf20Sopenharmony_ci	unsigned long flags;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	if (!hmc || !hmc->adapter)
4878c2ecf20Sopenharmony_ci		return -EIO;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	if (release_readers) {
4908c2ecf20Sopenharmony_ci		if (hmc->file_session) {
4918c2ecf20Sopenharmony_ci			struct ibmvmc_file_session *session = hmc->file_session;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci			session->valid = 0;
4948c2ecf20Sopenharmony_ci			wake_up_interruptible(&ibmvmc_read_wait);
4958c2ecf20Sopenharmony_ci		}
4968c2ecf20Sopenharmony_ci	}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	adapter = hmc->adapter;
4998c2ecf20Sopenharmony_ci	vdev = to_vio_dev(adapter->dev);
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hmc->lock, flags);
5028c2ecf20Sopenharmony_ci	hmc->index = 0;
5038c2ecf20Sopenharmony_ci	hmc->state = ibmhmc_state_free;
5048c2ecf20Sopenharmony_ci	hmc->queue_head = 0;
5058c2ecf20Sopenharmony_ci	hmc->queue_tail = 0;
5068c2ecf20Sopenharmony_ci	buffer = hmc->buffer;
5078c2ecf20Sopenharmony_ci	for (i = 0; i < ibmvmc_max_buf_pool_size; i++) {
5088c2ecf20Sopenharmony_ci		if (buffer[i].valid) {
5098c2ecf20Sopenharmony_ci			free_dma_buffer(vdev,
5108c2ecf20Sopenharmony_ci					ibmvmc.max_mtu,
5118c2ecf20Sopenharmony_ci					buffer[i].real_addr_local,
5128c2ecf20Sopenharmony_ci					buffer[i].dma_addr_local);
5138c2ecf20Sopenharmony_ci			dev_dbg(adapter->dev, "Forgot buffer id 0x%lx\n", i);
5148c2ecf20Sopenharmony_ci		}
5158c2ecf20Sopenharmony_ci		memset(&buffer[i], 0, sizeof(struct ibmvmc_buffer));
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci		hmc->queue_outbound_msgs[i] = VMC_INVALID_BUFFER_ID;
5188c2ecf20Sopenharmony_ci	}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hmc->lock, flags);
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	return 0;
5238c2ecf20Sopenharmony_ci}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci/**
5268c2ecf20Sopenharmony_ci * ibmvmc_send_open - Interface Open
5278c2ecf20Sopenharmony_ci * @buffer: Pointer to ibmvmc_buffer struct
5288c2ecf20Sopenharmony_ci * @hmc: Pointer to ibmvmc_hmc struct
5298c2ecf20Sopenharmony_ci *
5308c2ecf20Sopenharmony_ci * This command is sent by the management partition as the result of a
5318c2ecf20Sopenharmony_ci * management partition device request. It causes the hypervisor to
5328c2ecf20Sopenharmony_ci * prepare a set of data buffers for the management application connection
5338c2ecf20Sopenharmony_ci * indicated HMC idx. A unique HMC Idx would be used if multiple management
5348c2ecf20Sopenharmony_ci * applications running concurrently were desired. Before responding to this
5358c2ecf20Sopenharmony_ci * command, the hypervisor must provide the management partition with at
5368c2ecf20Sopenharmony_ci * least one of these new buffers via the Add Buffer. This indicates whether
5378c2ecf20Sopenharmony_ci * the messages are inbound or outbound from the hypervisor.
5388c2ecf20Sopenharmony_ci *
5398c2ecf20Sopenharmony_ci * Return:
5408c2ecf20Sopenharmony_ci *	0 - Success
5418c2ecf20Sopenharmony_ci *	Non-zero - Failure
5428c2ecf20Sopenharmony_ci */
5438c2ecf20Sopenharmony_cistatic int ibmvmc_send_open(struct ibmvmc_buffer *buffer,
5448c2ecf20Sopenharmony_ci			    struct ibmvmc_hmc *hmc)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	struct ibmvmc_crq_msg crq_msg;
5478c2ecf20Sopenharmony_ci	struct crq_server_adapter *adapter;
5488c2ecf20Sopenharmony_ci	__be64 *crq_as_u64 = (__be64 *)&crq_msg;
5498c2ecf20Sopenharmony_ci	int rc = 0;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	if (!hmc || !hmc->adapter)
5528c2ecf20Sopenharmony_ci		return -EIO;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	adapter = hmc->adapter;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "send_open: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
5578c2ecf20Sopenharmony_ci		(unsigned long)buffer->size, (unsigned long)adapter->liobn,
5588c2ecf20Sopenharmony_ci		(unsigned long)buffer->dma_addr_local,
5598c2ecf20Sopenharmony_ci		(unsigned long)adapter->riobn,
5608c2ecf20Sopenharmony_ci		(unsigned long)buffer->dma_addr_remote);
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	rc = h_copy_rdma(buffer->size,
5638c2ecf20Sopenharmony_ci			 adapter->liobn,
5648c2ecf20Sopenharmony_ci			 buffer->dma_addr_local,
5658c2ecf20Sopenharmony_ci			 adapter->riobn,
5668c2ecf20Sopenharmony_ci			 buffer->dma_addr_remote);
5678c2ecf20Sopenharmony_ci	if (rc) {
5688c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "Error: In send_open, h_copy_rdma rc 0x%x\n",
5698c2ecf20Sopenharmony_ci			rc);
5708c2ecf20Sopenharmony_ci		return -EIO;
5718c2ecf20Sopenharmony_ci	}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	hmc->state = ibmhmc_state_opening;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	crq_msg.valid = 0x80;
5768c2ecf20Sopenharmony_ci	crq_msg.type = VMC_MSG_OPEN;
5778c2ecf20Sopenharmony_ci	crq_msg.status = 0;
5788c2ecf20Sopenharmony_ci	crq_msg.var1.rsvd = 0;
5798c2ecf20Sopenharmony_ci	crq_msg.hmc_session = hmc->session;
5808c2ecf20Sopenharmony_ci	crq_msg.hmc_index = hmc->index;
5818c2ecf20Sopenharmony_ci	crq_msg.var2.buffer_id = cpu_to_be16(buffer->id);
5828c2ecf20Sopenharmony_ci	crq_msg.rsvd = 0;
5838c2ecf20Sopenharmony_ci	crq_msg.var3.rsvd = 0;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	ibmvmc_send_crq(adapter, be64_to_cpu(crq_as_u64[0]),
5868c2ecf20Sopenharmony_ci			be64_to_cpu(crq_as_u64[1]));
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	return rc;
5898c2ecf20Sopenharmony_ci}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci/**
5928c2ecf20Sopenharmony_ci * ibmvmc_send_close - Interface Close
5938c2ecf20Sopenharmony_ci * @hmc: Pointer to ibmvmc_hmc struct
5948c2ecf20Sopenharmony_ci *
5958c2ecf20Sopenharmony_ci * This command is sent by the management partition to terminate a
5968c2ecf20Sopenharmony_ci * management application to hypervisor connection. When this command is
5978c2ecf20Sopenharmony_ci * sent, the management partition has quiesced all I/O operations to all
5988c2ecf20Sopenharmony_ci * buffers associated with this management application connection, and
5998c2ecf20Sopenharmony_ci * has freed any storage for these buffers.
6008c2ecf20Sopenharmony_ci *
6018c2ecf20Sopenharmony_ci * Return:
6028c2ecf20Sopenharmony_ci *	0 - Success
6038c2ecf20Sopenharmony_ci *	Non-zero - Failure
6048c2ecf20Sopenharmony_ci */
6058c2ecf20Sopenharmony_cistatic int ibmvmc_send_close(struct ibmvmc_hmc *hmc)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	struct ibmvmc_crq_msg crq_msg;
6088c2ecf20Sopenharmony_ci	struct crq_server_adapter *adapter;
6098c2ecf20Sopenharmony_ci	__be64 *crq_as_u64 = (__be64 *)&crq_msg;
6108c2ecf20Sopenharmony_ci	int rc = 0;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	if (!hmc || !hmc->adapter)
6138c2ecf20Sopenharmony_ci		return -EIO;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	adapter = hmc->adapter;
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	dev_info(adapter->dev, "CRQ send: close\n");
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	crq_msg.valid = 0x80;
6208c2ecf20Sopenharmony_ci	crq_msg.type = VMC_MSG_CLOSE;
6218c2ecf20Sopenharmony_ci	crq_msg.status = 0;
6228c2ecf20Sopenharmony_ci	crq_msg.var1.rsvd = 0;
6238c2ecf20Sopenharmony_ci	crq_msg.hmc_session = hmc->session;
6248c2ecf20Sopenharmony_ci	crq_msg.hmc_index = hmc->index;
6258c2ecf20Sopenharmony_ci	crq_msg.var2.rsvd = 0;
6268c2ecf20Sopenharmony_ci	crq_msg.rsvd = 0;
6278c2ecf20Sopenharmony_ci	crq_msg.var3.rsvd = 0;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	ibmvmc_send_crq(adapter, be64_to_cpu(crq_as_u64[0]),
6308c2ecf20Sopenharmony_ci			be64_to_cpu(crq_as_u64[1]));
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	return rc;
6338c2ecf20Sopenharmony_ci}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci/**
6368c2ecf20Sopenharmony_ci * ibmvmc_send_capabilities - Send VMC Capabilities
6378c2ecf20Sopenharmony_ci *
6388c2ecf20Sopenharmony_ci * @adapter:	crq_server_adapter struct
6398c2ecf20Sopenharmony_ci *
6408c2ecf20Sopenharmony_ci * The capabilities message is an administrative message sent after the CRQ
6418c2ecf20Sopenharmony_ci * initialization sequence of messages and is used to exchange VMC capabilities
6428c2ecf20Sopenharmony_ci * between the management partition and the hypervisor. The management
6438c2ecf20Sopenharmony_ci * partition must send this message and the hypervisor must respond with VMC
6448c2ecf20Sopenharmony_ci * capabilities Response message before HMC interface message can begin. Any
6458c2ecf20Sopenharmony_ci * HMC interface messages received before the exchange of capabilities has
6468c2ecf20Sopenharmony_ci * complete are dropped.
6478c2ecf20Sopenharmony_ci *
6488c2ecf20Sopenharmony_ci * Return:
6498c2ecf20Sopenharmony_ci *	0 - Success
6508c2ecf20Sopenharmony_ci */
6518c2ecf20Sopenharmony_cistatic int ibmvmc_send_capabilities(struct crq_server_adapter *adapter)
6528c2ecf20Sopenharmony_ci{
6538c2ecf20Sopenharmony_ci	struct ibmvmc_admin_crq_msg crq_msg;
6548c2ecf20Sopenharmony_ci	__be64 *crq_as_u64 = (__be64 *)&crq_msg;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "ibmvmc: CRQ send: capabilities\n");
6578c2ecf20Sopenharmony_ci	crq_msg.valid = 0x80;
6588c2ecf20Sopenharmony_ci	crq_msg.type = VMC_MSG_CAP;
6598c2ecf20Sopenharmony_ci	crq_msg.status = 0;
6608c2ecf20Sopenharmony_ci	crq_msg.rsvd[0] = 0;
6618c2ecf20Sopenharmony_ci	crq_msg.rsvd[1] = 0;
6628c2ecf20Sopenharmony_ci	crq_msg.max_hmc = ibmvmc_max_hmcs;
6638c2ecf20Sopenharmony_ci	crq_msg.max_mtu = cpu_to_be32(ibmvmc_max_mtu);
6648c2ecf20Sopenharmony_ci	crq_msg.pool_size = cpu_to_be16(ibmvmc_max_buf_pool_size);
6658c2ecf20Sopenharmony_ci	crq_msg.crq_size = cpu_to_be16(adapter->queue.size);
6668c2ecf20Sopenharmony_ci	crq_msg.version = cpu_to_be16(IBMVMC_PROTOCOL_VERSION);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	ibmvmc_send_crq(adapter, be64_to_cpu(crq_as_u64[0]),
6698c2ecf20Sopenharmony_ci			be64_to_cpu(crq_as_u64[1]));
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	ibmvmc.state = ibmvmc_state_capabilities;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	return 0;
6748c2ecf20Sopenharmony_ci}
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci/**
6778c2ecf20Sopenharmony_ci * ibmvmc_send_add_buffer_resp - Add Buffer Response
6788c2ecf20Sopenharmony_ci *
6798c2ecf20Sopenharmony_ci * @adapter:	crq_server_adapter struct
6808c2ecf20Sopenharmony_ci * @status:	Status field
6818c2ecf20Sopenharmony_ci * @hmc_session: HMC Session field
6828c2ecf20Sopenharmony_ci * @hmc_index:	HMC Index field
6838c2ecf20Sopenharmony_ci * @buffer_id:	Buffer Id field
6848c2ecf20Sopenharmony_ci *
6858c2ecf20Sopenharmony_ci * This command is sent by the management partition to the hypervisor in
6868c2ecf20Sopenharmony_ci * response to the Add Buffer message. The Status field indicates the result of
6878c2ecf20Sopenharmony_ci * the command.
6888c2ecf20Sopenharmony_ci *
6898c2ecf20Sopenharmony_ci * Return:
6908c2ecf20Sopenharmony_ci *	0 - Success
6918c2ecf20Sopenharmony_ci */
6928c2ecf20Sopenharmony_cistatic int ibmvmc_send_add_buffer_resp(struct crq_server_adapter *adapter,
6938c2ecf20Sopenharmony_ci				       u8 status, u8 hmc_session,
6948c2ecf20Sopenharmony_ci				       u8 hmc_index, u16 buffer_id)
6958c2ecf20Sopenharmony_ci{
6968c2ecf20Sopenharmony_ci	struct ibmvmc_crq_msg crq_msg;
6978c2ecf20Sopenharmony_ci	__be64 *crq_as_u64 = (__be64 *)&crq_msg;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "CRQ send: add_buffer_resp\n");
7008c2ecf20Sopenharmony_ci	crq_msg.valid = 0x80;
7018c2ecf20Sopenharmony_ci	crq_msg.type = VMC_MSG_ADD_BUF_RESP;
7028c2ecf20Sopenharmony_ci	crq_msg.status = status;
7038c2ecf20Sopenharmony_ci	crq_msg.var1.rsvd = 0;
7048c2ecf20Sopenharmony_ci	crq_msg.hmc_session = hmc_session;
7058c2ecf20Sopenharmony_ci	crq_msg.hmc_index = hmc_index;
7068c2ecf20Sopenharmony_ci	crq_msg.var2.buffer_id = cpu_to_be16(buffer_id);
7078c2ecf20Sopenharmony_ci	crq_msg.rsvd = 0;
7088c2ecf20Sopenharmony_ci	crq_msg.var3.rsvd = 0;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	ibmvmc_send_crq(adapter, be64_to_cpu(crq_as_u64[0]),
7118c2ecf20Sopenharmony_ci			be64_to_cpu(crq_as_u64[1]));
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	return 0;
7148c2ecf20Sopenharmony_ci}
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci/**
7178c2ecf20Sopenharmony_ci * ibmvmc_send_rem_buffer_resp - Remove Buffer Response
7188c2ecf20Sopenharmony_ci *
7198c2ecf20Sopenharmony_ci * @adapter:	crq_server_adapter struct
7208c2ecf20Sopenharmony_ci * @status:	Status field
7218c2ecf20Sopenharmony_ci * @hmc_session: HMC Session field
7228c2ecf20Sopenharmony_ci * @hmc_index:	HMC Index field
7238c2ecf20Sopenharmony_ci * @buffer_id:	Buffer Id field
7248c2ecf20Sopenharmony_ci *
7258c2ecf20Sopenharmony_ci * This command is sent by the management partition to the hypervisor in
7268c2ecf20Sopenharmony_ci * response to the Remove Buffer message. The Buffer ID field indicates
7278c2ecf20Sopenharmony_ci * which buffer the management partition selected to remove. The Status
7288c2ecf20Sopenharmony_ci * field indicates the result of the command.
7298c2ecf20Sopenharmony_ci *
7308c2ecf20Sopenharmony_ci * Return:
7318c2ecf20Sopenharmony_ci *	0 - Success
7328c2ecf20Sopenharmony_ci */
7338c2ecf20Sopenharmony_cistatic int ibmvmc_send_rem_buffer_resp(struct crq_server_adapter *adapter,
7348c2ecf20Sopenharmony_ci				       u8 status, u8 hmc_session,
7358c2ecf20Sopenharmony_ci				       u8 hmc_index, u16 buffer_id)
7368c2ecf20Sopenharmony_ci{
7378c2ecf20Sopenharmony_ci	struct ibmvmc_crq_msg crq_msg;
7388c2ecf20Sopenharmony_ci	__be64 *crq_as_u64 = (__be64 *)&crq_msg;
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "CRQ send: rem_buffer_resp\n");
7418c2ecf20Sopenharmony_ci	crq_msg.valid = 0x80;
7428c2ecf20Sopenharmony_ci	crq_msg.type = VMC_MSG_REM_BUF_RESP;
7438c2ecf20Sopenharmony_ci	crq_msg.status = status;
7448c2ecf20Sopenharmony_ci	crq_msg.var1.rsvd = 0;
7458c2ecf20Sopenharmony_ci	crq_msg.hmc_session = hmc_session;
7468c2ecf20Sopenharmony_ci	crq_msg.hmc_index = hmc_index;
7478c2ecf20Sopenharmony_ci	crq_msg.var2.buffer_id = cpu_to_be16(buffer_id);
7488c2ecf20Sopenharmony_ci	crq_msg.rsvd = 0;
7498c2ecf20Sopenharmony_ci	crq_msg.var3.rsvd = 0;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	ibmvmc_send_crq(adapter, be64_to_cpu(crq_as_u64[0]),
7528c2ecf20Sopenharmony_ci			be64_to_cpu(crq_as_u64[1]));
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	return 0;
7558c2ecf20Sopenharmony_ci}
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci/**
7588c2ecf20Sopenharmony_ci * ibmvmc_send_msg - Signal Message
7598c2ecf20Sopenharmony_ci *
7608c2ecf20Sopenharmony_ci * @adapter:	crq_server_adapter struct
7618c2ecf20Sopenharmony_ci * @buffer:	ibmvmc_buffer struct
7628c2ecf20Sopenharmony_ci * @hmc:	ibmvmc_hmc struct
7638c2ecf20Sopenharmony_ci * @msg_len:	message length field
7648c2ecf20Sopenharmony_ci *
7658c2ecf20Sopenharmony_ci * This command is sent between the management partition and the hypervisor
7668c2ecf20Sopenharmony_ci * in order to signal the arrival of an HMC protocol message. The command
7678c2ecf20Sopenharmony_ci * can be sent by both the management partition and the hypervisor. It is
7688c2ecf20Sopenharmony_ci * used for all traffic between the management application and the hypervisor,
7698c2ecf20Sopenharmony_ci * regardless of who initiated the communication.
7708c2ecf20Sopenharmony_ci *
7718c2ecf20Sopenharmony_ci * There is no response to this message.
7728c2ecf20Sopenharmony_ci *
7738c2ecf20Sopenharmony_ci * Return:
7748c2ecf20Sopenharmony_ci *	0 - Success
7758c2ecf20Sopenharmony_ci *	Non-zero - Failure
7768c2ecf20Sopenharmony_ci */
7778c2ecf20Sopenharmony_cistatic int ibmvmc_send_msg(struct crq_server_adapter *adapter,
7788c2ecf20Sopenharmony_ci			   struct ibmvmc_buffer *buffer,
7798c2ecf20Sopenharmony_ci			   struct ibmvmc_hmc *hmc, int msg_len)
7808c2ecf20Sopenharmony_ci{
7818c2ecf20Sopenharmony_ci	struct ibmvmc_crq_msg crq_msg;
7828c2ecf20Sopenharmony_ci	__be64 *crq_as_u64 = (__be64 *)&crq_msg;
7838c2ecf20Sopenharmony_ci	int rc = 0;
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "CRQ send: rdma to HV\n");
7868c2ecf20Sopenharmony_ci	rc = h_copy_rdma(msg_len,
7878c2ecf20Sopenharmony_ci			 adapter->liobn,
7888c2ecf20Sopenharmony_ci			 buffer->dma_addr_local,
7898c2ecf20Sopenharmony_ci			 adapter->riobn,
7908c2ecf20Sopenharmony_ci			 buffer->dma_addr_remote);
7918c2ecf20Sopenharmony_ci	if (rc) {
7928c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "Error in send_msg, h_copy_rdma rc 0x%x\n",
7938c2ecf20Sopenharmony_ci			rc);
7948c2ecf20Sopenharmony_ci		return rc;
7958c2ecf20Sopenharmony_ci	}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	crq_msg.valid = 0x80;
7988c2ecf20Sopenharmony_ci	crq_msg.type = VMC_MSG_SIGNAL;
7998c2ecf20Sopenharmony_ci	crq_msg.status = 0;
8008c2ecf20Sopenharmony_ci	crq_msg.var1.rsvd = 0;
8018c2ecf20Sopenharmony_ci	crq_msg.hmc_session = hmc->session;
8028c2ecf20Sopenharmony_ci	crq_msg.hmc_index = hmc->index;
8038c2ecf20Sopenharmony_ci	crq_msg.var2.buffer_id = cpu_to_be16(buffer->id);
8048c2ecf20Sopenharmony_ci	crq_msg.var3.msg_len = cpu_to_be32(msg_len);
8058c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "CRQ send: msg to HV 0x%llx 0x%llx\n",
8068c2ecf20Sopenharmony_ci		be64_to_cpu(crq_as_u64[0]), be64_to_cpu(crq_as_u64[1]));
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	buffer->owner = VMC_BUF_OWNER_HV;
8098c2ecf20Sopenharmony_ci	ibmvmc_send_crq(adapter, be64_to_cpu(crq_as_u64[0]),
8108c2ecf20Sopenharmony_ci			be64_to_cpu(crq_as_u64[1]));
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	return rc;
8138c2ecf20Sopenharmony_ci}
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci/**
8168c2ecf20Sopenharmony_ci * ibmvmc_open - Open Session
8178c2ecf20Sopenharmony_ci *
8188c2ecf20Sopenharmony_ci * @inode:	inode struct
8198c2ecf20Sopenharmony_ci * @file:	file struct
8208c2ecf20Sopenharmony_ci *
8218c2ecf20Sopenharmony_ci * Return:
8228c2ecf20Sopenharmony_ci *	0 - Success
8238c2ecf20Sopenharmony_ci *	Non-zero - Failure
8248c2ecf20Sopenharmony_ci */
8258c2ecf20Sopenharmony_cistatic int ibmvmc_open(struct inode *inode, struct file *file)
8268c2ecf20Sopenharmony_ci{
8278c2ecf20Sopenharmony_ci	struct ibmvmc_file_session *session;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	pr_debug("%s: inode = 0x%lx, file = 0x%lx, state = 0x%x\n", __func__,
8308c2ecf20Sopenharmony_ci		 (unsigned long)inode, (unsigned long)file,
8318c2ecf20Sopenharmony_ci		 ibmvmc.state);
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	session = kzalloc(sizeof(*session), GFP_KERNEL);
8348c2ecf20Sopenharmony_ci	if (!session)
8358c2ecf20Sopenharmony_ci		return -ENOMEM;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	session->file = file;
8388c2ecf20Sopenharmony_ci	file->private_data = session;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	return 0;
8418c2ecf20Sopenharmony_ci}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci/**
8448c2ecf20Sopenharmony_ci * ibmvmc_close - Close Session
8458c2ecf20Sopenharmony_ci *
8468c2ecf20Sopenharmony_ci * @inode:	inode struct
8478c2ecf20Sopenharmony_ci * @file:	file struct
8488c2ecf20Sopenharmony_ci *
8498c2ecf20Sopenharmony_ci * Return:
8508c2ecf20Sopenharmony_ci *	0 - Success
8518c2ecf20Sopenharmony_ci *	Non-zero - Failure
8528c2ecf20Sopenharmony_ci */
8538c2ecf20Sopenharmony_cistatic int ibmvmc_close(struct inode *inode, struct file *file)
8548c2ecf20Sopenharmony_ci{
8558c2ecf20Sopenharmony_ci	struct ibmvmc_file_session *session;
8568c2ecf20Sopenharmony_ci	struct ibmvmc_hmc *hmc;
8578c2ecf20Sopenharmony_ci	int rc = 0;
8588c2ecf20Sopenharmony_ci	unsigned long flags;
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	pr_debug("%s: file = 0x%lx, state = 0x%x\n", __func__,
8618c2ecf20Sopenharmony_ci		 (unsigned long)file, ibmvmc.state);
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	session = file->private_data;
8648c2ecf20Sopenharmony_ci	if (!session)
8658c2ecf20Sopenharmony_ci		return -EIO;
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	hmc = session->hmc;
8688c2ecf20Sopenharmony_ci	if (hmc) {
8698c2ecf20Sopenharmony_ci		if (!hmc->adapter)
8708c2ecf20Sopenharmony_ci			return -EIO;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci		if (ibmvmc.state == ibmvmc_state_failed) {
8738c2ecf20Sopenharmony_ci			dev_warn(hmc->adapter->dev, "close: state_failed\n");
8748c2ecf20Sopenharmony_ci			return -EIO;
8758c2ecf20Sopenharmony_ci		}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hmc->lock, flags);
8788c2ecf20Sopenharmony_ci		if (hmc->state >= ibmhmc_state_opening) {
8798c2ecf20Sopenharmony_ci			rc = ibmvmc_send_close(hmc);
8808c2ecf20Sopenharmony_ci			if (rc)
8818c2ecf20Sopenharmony_ci				dev_warn(hmc->adapter->dev, "close: send_close failed.\n");
8828c2ecf20Sopenharmony_ci		}
8838c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hmc->lock, flags);
8848c2ecf20Sopenharmony_ci	}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	kfree_sensitive(session);
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	return rc;
8898c2ecf20Sopenharmony_ci}
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci/**
8928c2ecf20Sopenharmony_ci * ibmvmc_read - Read
8938c2ecf20Sopenharmony_ci *
8948c2ecf20Sopenharmony_ci * @file:	file struct
8958c2ecf20Sopenharmony_ci * @buf:	Character buffer
8968c2ecf20Sopenharmony_ci * @nbytes:	Size in bytes
8978c2ecf20Sopenharmony_ci * @ppos:	Offset
8988c2ecf20Sopenharmony_ci *
8998c2ecf20Sopenharmony_ci * Return:
9008c2ecf20Sopenharmony_ci *	0 - Success
9018c2ecf20Sopenharmony_ci *	Non-zero - Failure
9028c2ecf20Sopenharmony_ci */
9038c2ecf20Sopenharmony_cistatic ssize_t ibmvmc_read(struct file *file, char *buf, size_t nbytes,
9048c2ecf20Sopenharmony_ci			   loff_t *ppos)
9058c2ecf20Sopenharmony_ci{
9068c2ecf20Sopenharmony_ci	struct ibmvmc_file_session *session;
9078c2ecf20Sopenharmony_ci	struct ibmvmc_hmc *hmc;
9088c2ecf20Sopenharmony_ci	struct crq_server_adapter *adapter;
9098c2ecf20Sopenharmony_ci	struct ibmvmc_buffer *buffer;
9108c2ecf20Sopenharmony_ci	ssize_t n;
9118c2ecf20Sopenharmony_ci	ssize_t retval = 0;
9128c2ecf20Sopenharmony_ci	unsigned long flags;
9138c2ecf20Sopenharmony_ci	DEFINE_WAIT(wait);
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	pr_debug("ibmvmc: read: file = 0x%lx, buf = 0x%lx, nbytes = 0x%lx\n",
9168c2ecf20Sopenharmony_ci		 (unsigned long)file, (unsigned long)buf,
9178c2ecf20Sopenharmony_ci		 (unsigned long)nbytes);
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	if (nbytes == 0)
9208c2ecf20Sopenharmony_ci		return 0;
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	if (nbytes > ibmvmc.max_mtu) {
9238c2ecf20Sopenharmony_ci		pr_warn("ibmvmc: read: nbytes invalid 0x%x\n",
9248c2ecf20Sopenharmony_ci			(unsigned int)nbytes);
9258c2ecf20Sopenharmony_ci		return -EINVAL;
9268c2ecf20Sopenharmony_ci	}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	session = file->private_data;
9298c2ecf20Sopenharmony_ci	if (!session) {
9308c2ecf20Sopenharmony_ci		pr_warn("ibmvmc: read: no session\n");
9318c2ecf20Sopenharmony_ci		return -EIO;
9328c2ecf20Sopenharmony_ci	}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	hmc = session->hmc;
9358c2ecf20Sopenharmony_ci	if (!hmc) {
9368c2ecf20Sopenharmony_ci		pr_warn("ibmvmc: read: no hmc\n");
9378c2ecf20Sopenharmony_ci		return -EIO;
9388c2ecf20Sopenharmony_ci	}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	adapter = hmc->adapter;
9418c2ecf20Sopenharmony_ci	if (!adapter) {
9428c2ecf20Sopenharmony_ci		pr_warn("ibmvmc: read: no adapter\n");
9438c2ecf20Sopenharmony_ci		return -EIO;
9448c2ecf20Sopenharmony_ci	}
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	do {
9478c2ecf20Sopenharmony_ci		prepare_to_wait(&ibmvmc_read_wait, &wait, TASK_INTERRUPTIBLE);
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hmc->lock, flags);
9508c2ecf20Sopenharmony_ci		if (hmc->queue_tail != hmc->queue_head)
9518c2ecf20Sopenharmony_ci			/* Data is available */
9528c2ecf20Sopenharmony_ci			break;
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hmc->lock, flags);
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci		if (!session->valid) {
9578c2ecf20Sopenharmony_ci			retval = -EBADFD;
9588c2ecf20Sopenharmony_ci			goto out;
9598c2ecf20Sopenharmony_ci		}
9608c2ecf20Sopenharmony_ci		if (file->f_flags & O_NONBLOCK) {
9618c2ecf20Sopenharmony_ci			retval = -EAGAIN;
9628c2ecf20Sopenharmony_ci			goto out;
9638c2ecf20Sopenharmony_ci		}
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci		schedule();
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci		if (signal_pending(current)) {
9688c2ecf20Sopenharmony_ci			retval = -ERESTARTSYS;
9698c2ecf20Sopenharmony_ci			goto out;
9708c2ecf20Sopenharmony_ci		}
9718c2ecf20Sopenharmony_ci	} while (1);
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	buffer = &(hmc->buffer[hmc->queue_outbound_msgs[hmc->queue_tail]]);
9748c2ecf20Sopenharmony_ci	hmc->queue_tail++;
9758c2ecf20Sopenharmony_ci	if (hmc->queue_tail == ibmvmc_max_buf_pool_size)
9768c2ecf20Sopenharmony_ci		hmc->queue_tail = 0;
9778c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hmc->lock, flags);
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	nbytes = min_t(size_t, nbytes, buffer->msg_len);
9808c2ecf20Sopenharmony_ci	n = copy_to_user((void *)buf, buffer->real_addr_local, nbytes);
9818c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "read: copy to user nbytes = 0x%lx.\n", nbytes);
9828c2ecf20Sopenharmony_ci	ibmvmc_free_hmc_buffer(hmc, buffer);
9838c2ecf20Sopenharmony_ci	retval = nbytes;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	if (n) {
9868c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "read: copy to user failed.\n");
9878c2ecf20Sopenharmony_ci		retval = -EFAULT;
9888c2ecf20Sopenharmony_ci	}
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci out:
9918c2ecf20Sopenharmony_ci	finish_wait(&ibmvmc_read_wait, &wait);
9928c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "read: out %ld\n", retval);
9938c2ecf20Sopenharmony_ci	return retval;
9948c2ecf20Sopenharmony_ci}
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci/**
9978c2ecf20Sopenharmony_ci * ibmvmc_poll - Poll
9988c2ecf20Sopenharmony_ci *
9998c2ecf20Sopenharmony_ci * @file:	file struct
10008c2ecf20Sopenharmony_ci * @wait:	Poll Table
10018c2ecf20Sopenharmony_ci *
10028c2ecf20Sopenharmony_ci * Return:
10038c2ecf20Sopenharmony_ci *	poll.h return values
10048c2ecf20Sopenharmony_ci */
10058c2ecf20Sopenharmony_cistatic unsigned int ibmvmc_poll(struct file *file, poll_table *wait)
10068c2ecf20Sopenharmony_ci{
10078c2ecf20Sopenharmony_ci	struct ibmvmc_file_session *session;
10088c2ecf20Sopenharmony_ci	struct ibmvmc_hmc *hmc;
10098c2ecf20Sopenharmony_ci	unsigned int mask = 0;
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	session = file->private_data;
10128c2ecf20Sopenharmony_ci	if (!session)
10138c2ecf20Sopenharmony_ci		return 0;
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	hmc = session->hmc;
10168c2ecf20Sopenharmony_ci	if (!hmc)
10178c2ecf20Sopenharmony_ci		return 0;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	poll_wait(file, &ibmvmc_read_wait, wait);
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	if (hmc->queue_head != hmc->queue_tail)
10228c2ecf20Sopenharmony_ci		mask |= POLLIN | POLLRDNORM;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	return mask;
10258c2ecf20Sopenharmony_ci}
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci/**
10288c2ecf20Sopenharmony_ci * ibmvmc_write - Write
10298c2ecf20Sopenharmony_ci *
10308c2ecf20Sopenharmony_ci * @file:	file struct
10318c2ecf20Sopenharmony_ci * @buffer:	Character buffer
10328c2ecf20Sopenharmony_ci * @count:	Count field
10338c2ecf20Sopenharmony_ci * @ppos:	Offset
10348c2ecf20Sopenharmony_ci *
10358c2ecf20Sopenharmony_ci * Return:
10368c2ecf20Sopenharmony_ci *	0 - Success
10378c2ecf20Sopenharmony_ci *	Non-zero - Failure
10388c2ecf20Sopenharmony_ci */
10398c2ecf20Sopenharmony_cistatic ssize_t ibmvmc_write(struct file *file, const char *buffer,
10408c2ecf20Sopenharmony_ci			    size_t count, loff_t *ppos)
10418c2ecf20Sopenharmony_ci{
10428c2ecf20Sopenharmony_ci	struct ibmvmc_buffer *vmc_buffer;
10438c2ecf20Sopenharmony_ci	struct ibmvmc_file_session *session;
10448c2ecf20Sopenharmony_ci	struct crq_server_adapter *adapter;
10458c2ecf20Sopenharmony_ci	struct ibmvmc_hmc *hmc;
10468c2ecf20Sopenharmony_ci	unsigned char *buf;
10478c2ecf20Sopenharmony_ci	unsigned long flags;
10488c2ecf20Sopenharmony_ci	size_t bytes;
10498c2ecf20Sopenharmony_ci	const char *p = buffer;
10508c2ecf20Sopenharmony_ci	size_t c = count;
10518c2ecf20Sopenharmony_ci	int ret = 0;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	session = file->private_data;
10548c2ecf20Sopenharmony_ci	if (!session)
10558c2ecf20Sopenharmony_ci		return -EIO;
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	hmc = session->hmc;
10588c2ecf20Sopenharmony_ci	if (!hmc)
10598c2ecf20Sopenharmony_ci		return -EIO;
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hmc->lock, flags);
10628c2ecf20Sopenharmony_ci	if (hmc->state == ibmhmc_state_free) {
10638c2ecf20Sopenharmony_ci		/* HMC connection is not valid (possibly was reset under us). */
10648c2ecf20Sopenharmony_ci		ret = -EIO;
10658c2ecf20Sopenharmony_ci		goto out;
10668c2ecf20Sopenharmony_ci	}
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	adapter = hmc->adapter;
10698c2ecf20Sopenharmony_ci	if (!adapter) {
10708c2ecf20Sopenharmony_ci		ret = -EIO;
10718c2ecf20Sopenharmony_ci		goto out;
10728c2ecf20Sopenharmony_ci	}
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	if (count > ibmvmc.max_mtu) {
10758c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "invalid buffer size 0x%lx\n",
10768c2ecf20Sopenharmony_ci			 (unsigned long)count);
10778c2ecf20Sopenharmony_ci		ret = -EIO;
10788c2ecf20Sopenharmony_ci		goto out;
10798c2ecf20Sopenharmony_ci	}
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	/* Waiting for the open resp message to the ioctl(1) - retry */
10828c2ecf20Sopenharmony_ci	if (hmc->state == ibmhmc_state_opening) {
10838c2ecf20Sopenharmony_ci		ret = -EBUSY;
10848c2ecf20Sopenharmony_ci		goto out;
10858c2ecf20Sopenharmony_ci	}
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	/* Make sure the ioctl() was called & the open msg sent, and that
10888c2ecf20Sopenharmony_ci	 * the HMC connection has not failed.
10898c2ecf20Sopenharmony_ci	 */
10908c2ecf20Sopenharmony_ci	if (hmc->state != ibmhmc_state_ready) {
10918c2ecf20Sopenharmony_ci		ret = -EIO;
10928c2ecf20Sopenharmony_ci		goto out;
10938c2ecf20Sopenharmony_ci	}
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	vmc_buffer = ibmvmc_get_valid_hmc_buffer(hmc->index);
10968c2ecf20Sopenharmony_ci	if (!vmc_buffer) {
10978c2ecf20Sopenharmony_ci		/* No buffer available for the msg send, or we have not yet
10988c2ecf20Sopenharmony_ci		 * completed the open/open_resp sequence.  Retry until this is
10998c2ecf20Sopenharmony_ci		 * complete.
11008c2ecf20Sopenharmony_ci		 */
11018c2ecf20Sopenharmony_ci		ret = -EBUSY;
11028c2ecf20Sopenharmony_ci		goto out;
11038c2ecf20Sopenharmony_ci	}
11048c2ecf20Sopenharmony_ci	if (!vmc_buffer->real_addr_local) {
11058c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "no buffer storage assigned\n");
11068c2ecf20Sopenharmony_ci		ret = -EIO;
11078c2ecf20Sopenharmony_ci		goto out;
11088c2ecf20Sopenharmony_ci	}
11098c2ecf20Sopenharmony_ci	buf = vmc_buffer->real_addr_local;
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	while (c > 0) {
11128c2ecf20Sopenharmony_ci		bytes = min_t(size_t, c, vmc_buffer->size);
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci		bytes -= copy_from_user(buf, p, bytes);
11158c2ecf20Sopenharmony_ci		if (!bytes) {
11168c2ecf20Sopenharmony_ci			ret = -EFAULT;
11178c2ecf20Sopenharmony_ci			goto out;
11188c2ecf20Sopenharmony_ci		}
11198c2ecf20Sopenharmony_ci		c -= bytes;
11208c2ecf20Sopenharmony_ci		p += bytes;
11218c2ecf20Sopenharmony_ci	}
11228c2ecf20Sopenharmony_ci	if (p == buffer)
11238c2ecf20Sopenharmony_ci		goto out;
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	file->f_path.dentry->d_inode->i_mtime = current_time(file_inode(file));
11268c2ecf20Sopenharmony_ci	mark_inode_dirty(file->f_path.dentry->d_inode);
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "write: file = 0x%lx, count = 0x%lx\n",
11298c2ecf20Sopenharmony_ci		(unsigned long)file, (unsigned long)count);
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	ibmvmc_send_msg(adapter, vmc_buffer, hmc, count);
11328c2ecf20Sopenharmony_ci	ret = p - buffer;
11338c2ecf20Sopenharmony_ci out:
11348c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hmc->lock, flags);
11358c2ecf20Sopenharmony_ci	return (ssize_t)(ret);
11368c2ecf20Sopenharmony_ci}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci/**
11398c2ecf20Sopenharmony_ci * ibmvmc_setup_hmc - Setup the HMC
11408c2ecf20Sopenharmony_ci *
11418c2ecf20Sopenharmony_ci * @session:	ibmvmc_file_session struct
11428c2ecf20Sopenharmony_ci *
11438c2ecf20Sopenharmony_ci * Return:
11448c2ecf20Sopenharmony_ci *	0 - Success
11458c2ecf20Sopenharmony_ci *	Non-zero - Failure
11468c2ecf20Sopenharmony_ci */
11478c2ecf20Sopenharmony_cistatic long ibmvmc_setup_hmc(struct ibmvmc_file_session *session)
11488c2ecf20Sopenharmony_ci{
11498c2ecf20Sopenharmony_ci	struct ibmvmc_hmc *hmc;
11508c2ecf20Sopenharmony_ci	unsigned int valid, free, index;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	if (ibmvmc.state == ibmvmc_state_failed) {
11538c2ecf20Sopenharmony_ci		pr_warn("ibmvmc: Reserve HMC: state_failed\n");
11548c2ecf20Sopenharmony_ci		return -EIO;
11558c2ecf20Sopenharmony_ci	}
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	if (ibmvmc.state < ibmvmc_state_ready) {
11588c2ecf20Sopenharmony_ci		pr_warn("ibmvmc: Reserve HMC: not state_ready\n");
11598c2ecf20Sopenharmony_ci		return -EAGAIN;
11608c2ecf20Sopenharmony_ci	}
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	/* Device is busy until capabilities have been exchanged and we
11638c2ecf20Sopenharmony_ci	 * have a generic buffer for each possible HMC connection.
11648c2ecf20Sopenharmony_ci	 */
11658c2ecf20Sopenharmony_ci	for (index = 0; index <= ibmvmc.max_hmc_index; index++) {
11668c2ecf20Sopenharmony_ci		valid = 0;
11678c2ecf20Sopenharmony_ci		ibmvmc_count_hmc_buffers(index, &valid, &free);
11688c2ecf20Sopenharmony_ci		if (valid == 0) {
11698c2ecf20Sopenharmony_ci			pr_warn("ibmvmc: buffers not ready for index %d\n",
11708c2ecf20Sopenharmony_ci				index);
11718c2ecf20Sopenharmony_ci			return -ENOBUFS;
11728c2ecf20Sopenharmony_ci		}
11738c2ecf20Sopenharmony_ci	}
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	/* Get an hmc object, and transition to ibmhmc_state_initial */
11768c2ecf20Sopenharmony_ci	hmc = ibmvmc_get_free_hmc();
11778c2ecf20Sopenharmony_ci	if (!hmc) {
11788c2ecf20Sopenharmony_ci		pr_warn("%s: free hmc not found\n", __func__);
11798c2ecf20Sopenharmony_ci		return -EBUSY;
11808c2ecf20Sopenharmony_ci	}
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	hmc->session = hmc->session + 1;
11838c2ecf20Sopenharmony_ci	if (hmc->session == 0xff)
11848c2ecf20Sopenharmony_ci		hmc->session = 1;
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	session->hmc = hmc;
11878c2ecf20Sopenharmony_ci	hmc->adapter = &ibmvmc_adapter;
11888c2ecf20Sopenharmony_ci	hmc->file_session = session;
11898c2ecf20Sopenharmony_ci	session->valid = 1;
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	return 0;
11928c2ecf20Sopenharmony_ci}
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci/**
11958c2ecf20Sopenharmony_ci * ibmvmc_ioctl_sethmcid - IOCTL Set HMC ID
11968c2ecf20Sopenharmony_ci *
11978c2ecf20Sopenharmony_ci * @session:	ibmvmc_file_session struct
11988c2ecf20Sopenharmony_ci * @new_hmc_id:	HMC id field
11998c2ecf20Sopenharmony_ci *
12008c2ecf20Sopenharmony_ci * IOCTL command to setup the hmc id
12018c2ecf20Sopenharmony_ci *
12028c2ecf20Sopenharmony_ci * Return:
12038c2ecf20Sopenharmony_ci *	0 - Success
12048c2ecf20Sopenharmony_ci *	Non-zero - Failure
12058c2ecf20Sopenharmony_ci */
12068c2ecf20Sopenharmony_cistatic long ibmvmc_ioctl_sethmcid(struct ibmvmc_file_session *session,
12078c2ecf20Sopenharmony_ci				  unsigned char __user *new_hmc_id)
12088c2ecf20Sopenharmony_ci{
12098c2ecf20Sopenharmony_ci	struct ibmvmc_hmc *hmc;
12108c2ecf20Sopenharmony_ci	struct ibmvmc_buffer *buffer;
12118c2ecf20Sopenharmony_ci	size_t bytes;
12128c2ecf20Sopenharmony_ci	char print_buffer[HMC_ID_LEN + 1];
12138c2ecf20Sopenharmony_ci	unsigned long flags;
12148c2ecf20Sopenharmony_ci	long rc = 0;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	/* Reserve HMC session */
12178c2ecf20Sopenharmony_ci	hmc = session->hmc;
12188c2ecf20Sopenharmony_ci	if (!hmc) {
12198c2ecf20Sopenharmony_ci		rc = ibmvmc_setup_hmc(session);
12208c2ecf20Sopenharmony_ci		if (rc)
12218c2ecf20Sopenharmony_ci			return rc;
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci		hmc = session->hmc;
12248c2ecf20Sopenharmony_ci		if (!hmc) {
12258c2ecf20Sopenharmony_ci			pr_err("ibmvmc: setup_hmc success but no hmc\n");
12268c2ecf20Sopenharmony_ci			return -EIO;
12278c2ecf20Sopenharmony_ci		}
12288c2ecf20Sopenharmony_ci	}
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	if (hmc->state != ibmhmc_state_initial) {
12318c2ecf20Sopenharmony_ci		pr_warn("ibmvmc: sethmcid: invalid state to send open 0x%x\n",
12328c2ecf20Sopenharmony_ci			hmc->state);
12338c2ecf20Sopenharmony_ci		return -EIO;
12348c2ecf20Sopenharmony_ci	}
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci	bytes = copy_from_user(hmc->hmc_id, new_hmc_id, HMC_ID_LEN);
12378c2ecf20Sopenharmony_ci	if (bytes)
12388c2ecf20Sopenharmony_ci		return -EFAULT;
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	/* Send Open Session command */
12418c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hmc->lock, flags);
12428c2ecf20Sopenharmony_ci	buffer = ibmvmc_get_valid_hmc_buffer(hmc->index);
12438c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hmc->lock, flags);
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	if (!buffer || !buffer->real_addr_local) {
12468c2ecf20Sopenharmony_ci		pr_warn("ibmvmc: sethmcid: no buffer available\n");
12478c2ecf20Sopenharmony_ci		return -EIO;
12488c2ecf20Sopenharmony_ci	}
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	/* Make sure buffer is NULL terminated before trying to print it */
12518c2ecf20Sopenharmony_ci	memset(print_buffer, 0, HMC_ID_LEN + 1);
12528c2ecf20Sopenharmony_ci	strncpy(print_buffer, hmc->hmc_id, HMC_ID_LEN);
12538c2ecf20Sopenharmony_ci	pr_info("ibmvmc: sethmcid: Set HMC ID: \"%s\"\n", print_buffer);
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	memcpy(buffer->real_addr_local, hmc->hmc_id, HMC_ID_LEN);
12568c2ecf20Sopenharmony_ci	/* RDMA over ID, send open msg, change state to ibmhmc_state_opening */
12578c2ecf20Sopenharmony_ci	rc = ibmvmc_send_open(buffer, hmc);
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	return rc;
12608c2ecf20Sopenharmony_ci}
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci/**
12638c2ecf20Sopenharmony_ci * ibmvmc_ioctl_query - IOCTL Query
12648c2ecf20Sopenharmony_ci *
12658c2ecf20Sopenharmony_ci * @session:	ibmvmc_file_session struct
12668c2ecf20Sopenharmony_ci * @ret_struct:	ibmvmc_query_struct
12678c2ecf20Sopenharmony_ci *
12688c2ecf20Sopenharmony_ci * Return:
12698c2ecf20Sopenharmony_ci *	0 - Success
12708c2ecf20Sopenharmony_ci *	Non-zero - Failure
12718c2ecf20Sopenharmony_ci */
12728c2ecf20Sopenharmony_cistatic long ibmvmc_ioctl_query(struct ibmvmc_file_session *session,
12738c2ecf20Sopenharmony_ci			       struct ibmvmc_query_struct __user *ret_struct)
12748c2ecf20Sopenharmony_ci{
12758c2ecf20Sopenharmony_ci	struct ibmvmc_query_struct query_struct;
12768c2ecf20Sopenharmony_ci	size_t bytes;
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	memset(&query_struct, 0, sizeof(query_struct));
12798c2ecf20Sopenharmony_ci	query_struct.have_vmc = (ibmvmc.state > ibmvmc_state_initial);
12808c2ecf20Sopenharmony_ci	query_struct.state = ibmvmc.state;
12818c2ecf20Sopenharmony_ci	query_struct.vmc_drc_index = ibmvmc.vmc_drc_index;
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	bytes = copy_to_user(ret_struct, &query_struct,
12848c2ecf20Sopenharmony_ci			     sizeof(query_struct));
12858c2ecf20Sopenharmony_ci	if (bytes)
12868c2ecf20Sopenharmony_ci		return -EFAULT;
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	return 0;
12898c2ecf20Sopenharmony_ci}
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci/**
12928c2ecf20Sopenharmony_ci * ibmvmc_ioctl_requestvmc - IOCTL Request VMC
12938c2ecf20Sopenharmony_ci *
12948c2ecf20Sopenharmony_ci * @session:	ibmvmc_file_session struct
12958c2ecf20Sopenharmony_ci * @ret_vmc_index:	VMC Index
12968c2ecf20Sopenharmony_ci *
12978c2ecf20Sopenharmony_ci * Return:
12988c2ecf20Sopenharmony_ci *	0 - Success
12998c2ecf20Sopenharmony_ci *	Non-zero - Failure
13008c2ecf20Sopenharmony_ci */
13018c2ecf20Sopenharmony_cistatic long ibmvmc_ioctl_requestvmc(struct ibmvmc_file_session *session,
13028c2ecf20Sopenharmony_ci				    u32 __user *ret_vmc_index)
13038c2ecf20Sopenharmony_ci{
13048c2ecf20Sopenharmony_ci	/* TODO: (adreznec) Add locking to control multiple process access */
13058c2ecf20Sopenharmony_ci	size_t bytes;
13068c2ecf20Sopenharmony_ci	long rc;
13078c2ecf20Sopenharmony_ci	u32 vmc_drc_index;
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	/* Call to request the VMC device from phyp*/
13108c2ecf20Sopenharmony_ci	rc = h_request_vmc(&vmc_drc_index);
13118c2ecf20Sopenharmony_ci	pr_debug("ibmvmc: requestvmc: H_REQUEST_VMC rc = 0x%lx\n", rc);
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci	if (rc == H_SUCCESS) {
13148c2ecf20Sopenharmony_ci		rc = 0;
13158c2ecf20Sopenharmony_ci	} else if (rc == H_FUNCTION) {
13168c2ecf20Sopenharmony_ci		pr_err("ibmvmc: requestvmc: h_request_vmc not supported\n");
13178c2ecf20Sopenharmony_ci		return -EPERM;
13188c2ecf20Sopenharmony_ci	} else if (rc == H_AUTHORITY) {
13198c2ecf20Sopenharmony_ci		pr_err("ibmvmc: requestvmc: hypervisor denied vmc request\n");
13208c2ecf20Sopenharmony_ci		return -EPERM;
13218c2ecf20Sopenharmony_ci	} else if (rc == H_HARDWARE) {
13228c2ecf20Sopenharmony_ci		pr_err("ibmvmc: requestvmc: hypervisor hardware fault\n");
13238c2ecf20Sopenharmony_ci		return -EIO;
13248c2ecf20Sopenharmony_ci	} else if (rc == H_RESOURCE) {
13258c2ecf20Sopenharmony_ci		pr_err("ibmvmc: requestvmc: vmc resource unavailable\n");
13268c2ecf20Sopenharmony_ci		return -ENODEV;
13278c2ecf20Sopenharmony_ci	} else if (rc == H_NOT_AVAILABLE) {
13288c2ecf20Sopenharmony_ci		pr_err("ibmvmc: requestvmc: system cannot be vmc managed\n");
13298c2ecf20Sopenharmony_ci		return -EPERM;
13308c2ecf20Sopenharmony_ci	} else if (rc == H_PARAMETER) {
13318c2ecf20Sopenharmony_ci		pr_err("ibmvmc: requestvmc: invalid parameter\n");
13328c2ecf20Sopenharmony_ci		return -EINVAL;
13338c2ecf20Sopenharmony_ci	}
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	/* Success, set the vmc index in global struct */
13368c2ecf20Sopenharmony_ci	ibmvmc.vmc_drc_index = vmc_drc_index;
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	bytes = copy_to_user(ret_vmc_index, &vmc_drc_index,
13398c2ecf20Sopenharmony_ci			     sizeof(*ret_vmc_index));
13408c2ecf20Sopenharmony_ci	if (bytes) {
13418c2ecf20Sopenharmony_ci		pr_warn("ibmvmc: requestvmc: copy to user failed.\n");
13428c2ecf20Sopenharmony_ci		return -EFAULT;
13438c2ecf20Sopenharmony_ci	}
13448c2ecf20Sopenharmony_ci	return rc;
13458c2ecf20Sopenharmony_ci}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci/**
13488c2ecf20Sopenharmony_ci * ibmvmc_ioctl - IOCTL
13498c2ecf20Sopenharmony_ci *
13508c2ecf20Sopenharmony_ci * @file:	file information
13518c2ecf20Sopenharmony_ci * @cmd:	cmd field
13528c2ecf20Sopenharmony_ci * @arg:	Argument field
13538c2ecf20Sopenharmony_ci *
13548c2ecf20Sopenharmony_ci * Return:
13558c2ecf20Sopenharmony_ci *	0 - Success
13568c2ecf20Sopenharmony_ci *	Non-zero - Failure
13578c2ecf20Sopenharmony_ci */
13588c2ecf20Sopenharmony_cistatic long ibmvmc_ioctl(struct file *file,
13598c2ecf20Sopenharmony_ci			 unsigned int cmd, unsigned long arg)
13608c2ecf20Sopenharmony_ci{
13618c2ecf20Sopenharmony_ci	struct ibmvmc_file_session *session = file->private_data;
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	pr_debug("ibmvmc: ioctl file=0x%lx, cmd=0x%x, arg=0x%lx, ses=0x%lx\n",
13648c2ecf20Sopenharmony_ci		 (unsigned long)file, cmd, arg,
13658c2ecf20Sopenharmony_ci		 (unsigned long)session);
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	if (!session) {
13688c2ecf20Sopenharmony_ci		pr_warn("ibmvmc: ioctl: no session\n");
13698c2ecf20Sopenharmony_ci		return -EIO;
13708c2ecf20Sopenharmony_ci	}
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci	switch (cmd) {
13738c2ecf20Sopenharmony_ci	case VMC_IOCTL_SETHMCID:
13748c2ecf20Sopenharmony_ci		return ibmvmc_ioctl_sethmcid(session,
13758c2ecf20Sopenharmony_ci			(unsigned char __user *)arg);
13768c2ecf20Sopenharmony_ci	case VMC_IOCTL_QUERY:
13778c2ecf20Sopenharmony_ci		return ibmvmc_ioctl_query(session,
13788c2ecf20Sopenharmony_ci			(struct ibmvmc_query_struct __user *)arg);
13798c2ecf20Sopenharmony_ci	case VMC_IOCTL_REQUESTVMC:
13808c2ecf20Sopenharmony_ci		return ibmvmc_ioctl_requestvmc(session,
13818c2ecf20Sopenharmony_ci			(unsigned int __user *)arg);
13828c2ecf20Sopenharmony_ci	default:
13838c2ecf20Sopenharmony_ci		pr_warn("ibmvmc: unknown ioctl 0x%x\n", cmd);
13848c2ecf20Sopenharmony_ci		return -EINVAL;
13858c2ecf20Sopenharmony_ci	}
13868c2ecf20Sopenharmony_ci}
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_cistatic const struct file_operations ibmvmc_fops = {
13898c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
13908c2ecf20Sopenharmony_ci	.read		= ibmvmc_read,
13918c2ecf20Sopenharmony_ci	.write		= ibmvmc_write,
13928c2ecf20Sopenharmony_ci	.poll		= ibmvmc_poll,
13938c2ecf20Sopenharmony_ci	.unlocked_ioctl	= ibmvmc_ioctl,
13948c2ecf20Sopenharmony_ci	.open           = ibmvmc_open,
13958c2ecf20Sopenharmony_ci	.release        = ibmvmc_close,
13968c2ecf20Sopenharmony_ci};
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci/**
13998c2ecf20Sopenharmony_ci * ibmvmc_add_buffer - Add Buffer
14008c2ecf20Sopenharmony_ci *
14018c2ecf20Sopenharmony_ci * @adapter: crq_server_adapter struct
14028c2ecf20Sopenharmony_ci * @crq:	ibmvmc_crq_msg struct
14038c2ecf20Sopenharmony_ci *
14048c2ecf20Sopenharmony_ci * This message transfers a buffer from hypervisor ownership to management
14058c2ecf20Sopenharmony_ci * partition ownership. The LIOBA is obtained from the virtual TCE table
14068c2ecf20Sopenharmony_ci * associated with the hypervisor side of the VMC device, and points to a
14078c2ecf20Sopenharmony_ci * buffer of size MTU (as established in the capabilities exchange).
14088c2ecf20Sopenharmony_ci *
14098c2ecf20Sopenharmony_ci * Typical flow for ading buffers:
14108c2ecf20Sopenharmony_ci * 1. A new management application connection is opened by the management
14118c2ecf20Sopenharmony_ci *	partition.
14128c2ecf20Sopenharmony_ci * 2. The hypervisor assigns new buffers for the traffic associated with
14138c2ecf20Sopenharmony_ci *	that connection.
14148c2ecf20Sopenharmony_ci * 3. The hypervisor sends VMC Add Buffer messages to the management
14158c2ecf20Sopenharmony_ci *	partition, informing it of the new buffers.
14168c2ecf20Sopenharmony_ci * 4. The hypervisor sends an HMC protocol message (to the management
14178c2ecf20Sopenharmony_ci *	application) notifying it of the new buffers. This informs the
14188c2ecf20Sopenharmony_ci *	application that it has buffers available for sending HMC
14198c2ecf20Sopenharmony_ci *	commands.
14208c2ecf20Sopenharmony_ci *
14218c2ecf20Sopenharmony_ci * Return:
14228c2ecf20Sopenharmony_ci *	0 - Success
14238c2ecf20Sopenharmony_ci *	Non-zero - Failure
14248c2ecf20Sopenharmony_ci */
14258c2ecf20Sopenharmony_cistatic int ibmvmc_add_buffer(struct crq_server_adapter *adapter,
14268c2ecf20Sopenharmony_ci			     struct ibmvmc_crq_msg *crq)
14278c2ecf20Sopenharmony_ci{
14288c2ecf20Sopenharmony_ci	struct ibmvmc_buffer *buffer;
14298c2ecf20Sopenharmony_ci	u8 hmc_index;
14308c2ecf20Sopenharmony_ci	u8 hmc_session;
14318c2ecf20Sopenharmony_ci	u16 buffer_id;
14328c2ecf20Sopenharmony_ci	unsigned long flags;
14338c2ecf20Sopenharmony_ci	int rc = 0;
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci	if (!crq)
14368c2ecf20Sopenharmony_ci		return -1;
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	hmc_session = crq->hmc_session;
14398c2ecf20Sopenharmony_ci	hmc_index = crq->hmc_index;
14408c2ecf20Sopenharmony_ci	buffer_id = be16_to_cpu(crq->var2.buffer_id);
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	if (hmc_index > ibmvmc.max_hmc_index) {
14438c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "add_buffer: invalid hmc_index = 0x%x\n",
14448c2ecf20Sopenharmony_ci			hmc_index);
14458c2ecf20Sopenharmony_ci		ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_HMC_INDEX,
14468c2ecf20Sopenharmony_ci					    hmc_session, hmc_index, buffer_id);
14478c2ecf20Sopenharmony_ci		return -1;
14488c2ecf20Sopenharmony_ci	}
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci	if (buffer_id >= ibmvmc.max_buffer_pool_size) {
14518c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "add_buffer: invalid buffer_id = 0x%x\n",
14528c2ecf20Sopenharmony_ci			buffer_id);
14538c2ecf20Sopenharmony_ci		ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_BUFFER_ID,
14548c2ecf20Sopenharmony_ci					    hmc_session, hmc_index, buffer_id);
14558c2ecf20Sopenharmony_ci		return -1;
14568c2ecf20Sopenharmony_ci	}
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hmcs[hmc_index].lock, flags);
14598c2ecf20Sopenharmony_ci	buffer = &hmcs[hmc_index].buffer[buffer_id];
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	if (buffer->real_addr_local || buffer->dma_addr_local) {
14628c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "add_buffer: already allocated id = 0x%lx\n",
14638c2ecf20Sopenharmony_ci			 (unsigned long)buffer_id);
14648c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags);
14658c2ecf20Sopenharmony_ci		ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_BUFFER_ID,
14668c2ecf20Sopenharmony_ci					    hmc_session, hmc_index, buffer_id);
14678c2ecf20Sopenharmony_ci		return -1;
14688c2ecf20Sopenharmony_ci	}
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	buffer->real_addr_local = alloc_dma_buffer(to_vio_dev(adapter->dev),
14718c2ecf20Sopenharmony_ci						   ibmvmc.max_mtu,
14728c2ecf20Sopenharmony_ci						   &buffer->dma_addr_local);
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_ci	if (!buffer->real_addr_local) {
14758c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "add_buffer: alloc_dma_buffer failed.\n");
14768c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags);
14778c2ecf20Sopenharmony_ci		ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INTERFACE_FAILURE,
14788c2ecf20Sopenharmony_ci					    hmc_session, hmc_index, buffer_id);
14798c2ecf20Sopenharmony_ci		return -1;
14808c2ecf20Sopenharmony_ci	}
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	buffer->dma_addr_remote = be32_to_cpu(crq->var3.lioba);
14838c2ecf20Sopenharmony_ci	buffer->size = ibmvmc.max_mtu;
14848c2ecf20Sopenharmony_ci	buffer->owner = crq->var1.owner;
14858c2ecf20Sopenharmony_ci	buffer->free = 1;
14868c2ecf20Sopenharmony_ci	/* Must ensure valid==1 is observable only after all other fields are */
14878c2ecf20Sopenharmony_ci	dma_wmb();
14888c2ecf20Sopenharmony_ci	buffer->valid = 1;
14898c2ecf20Sopenharmony_ci	buffer->id = buffer_id;
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "add_buffer: successfully added a buffer:\n");
14928c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "   index: %d, session: %d, buffer: 0x%x, owner: %d\n",
14938c2ecf20Sopenharmony_ci		hmc_index, hmc_session, buffer_id, buffer->owner);
14948c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "   local: 0x%x, remote: 0x%x\n",
14958c2ecf20Sopenharmony_ci		(u32)buffer->dma_addr_local,
14968c2ecf20Sopenharmony_ci		(u32)buffer->dma_addr_remote);
14978c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags);
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_SUCCESS, hmc_session,
15008c2ecf20Sopenharmony_ci				    hmc_index, buffer_id);
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	return rc;
15038c2ecf20Sopenharmony_ci}
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci/**
15068c2ecf20Sopenharmony_ci * ibmvmc_rem_buffer - Remove Buffer
15078c2ecf20Sopenharmony_ci *
15088c2ecf20Sopenharmony_ci * @adapter: crq_server_adapter struct
15098c2ecf20Sopenharmony_ci * @crq:	ibmvmc_crq_msg struct
15108c2ecf20Sopenharmony_ci *
15118c2ecf20Sopenharmony_ci * This message requests an HMC buffer to be transferred from management
15128c2ecf20Sopenharmony_ci * partition ownership to hypervisor ownership. The management partition may
15138c2ecf20Sopenharmony_ci * not be able to satisfy the request at a particular point in time if all its
15148c2ecf20Sopenharmony_ci * buffers are in use. The management partition requires a depth of at least
15158c2ecf20Sopenharmony_ci * one inbound buffer to allow management application commands to flow to the
15168c2ecf20Sopenharmony_ci * hypervisor. It is, therefore, an interface error for the hypervisor to
15178c2ecf20Sopenharmony_ci * attempt to remove the management partition's last buffer.
15188c2ecf20Sopenharmony_ci *
15198c2ecf20Sopenharmony_ci * The hypervisor is expected to manage buffer usage with the management
15208c2ecf20Sopenharmony_ci * application directly and inform the management partition when buffers may be
15218c2ecf20Sopenharmony_ci * removed. The typical flow for removing buffers:
15228c2ecf20Sopenharmony_ci *
15238c2ecf20Sopenharmony_ci * 1. The management application no longer needs a communication path to a
15248c2ecf20Sopenharmony_ci *	particular hypervisor function. That function is closed.
15258c2ecf20Sopenharmony_ci * 2. The hypervisor and the management application quiesce all traffic to that
15268c2ecf20Sopenharmony_ci *	function. The hypervisor requests a reduction in buffer pool size.
15278c2ecf20Sopenharmony_ci * 3. The management application acknowledges the reduction in buffer pool size.
15288c2ecf20Sopenharmony_ci * 4. The hypervisor sends a Remove Buffer message to the management partition,
15298c2ecf20Sopenharmony_ci *	informing it of the reduction in buffers.
15308c2ecf20Sopenharmony_ci * 5. The management partition verifies it can remove the buffer. This is
15318c2ecf20Sopenharmony_ci *	possible if buffers have been quiesced.
15328c2ecf20Sopenharmony_ci *
15338c2ecf20Sopenharmony_ci * Return:
15348c2ecf20Sopenharmony_ci *	0 - Success
15358c2ecf20Sopenharmony_ci *	Non-zero - Failure
15368c2ecf20Sopenharmony_ci */
15378c2ecf20Sopenharmony_ci/*
15388c2ecf20Sopenharmony_ci * The hypervisor requested that we pick an unused buffer, and return it.
15398c2ecf20Sopenharmony_ci * Before sending the buffer back, we free any storage associated with the
15408c2ecf20Sopenharmony_ci * buffer.
15418c2ecf20Sopenharmony_ci */
15428c2ecf20Sopenharmony_cistatic int ibmvmc_rem_buffer(struct crq_server_adapter *adapter,
15438c2ecf20Sopenharmony_ci			     struct ibmvmc_crq_msg *crq)
15448c2ecf20Sopenharmony_ci{
15458c2ecf20Sopenharmony_ci	struct ibmvmc_buffer *buffer;
15468c2ecf20Sopenharmony_ci	u8 hmc_index;
15478c2ecf20Sopenharmony_ci	u8 hmc_session;
15488c2ecf20Sopenharmony_ci	u16 buffer_id = 0;
15498c2ecf20Sopenharmony_ci	unsigned long flags;
15508c2ecf20Sopenharmony_ci	int rc = 0;
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	if (!crq)
15538c2ecf20Sopenharmony_ci		return -1;
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	hmc_session = crq->hmc_session;
15568c2ecf20Sopenharmony_ci	hmc_index = crq->hmc_index;
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci	if (hmc_index > ibmvmc.max_hmc_index) {
15598c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "rem_buffer: invalid hmc_index = 0x%x\n",
15608c2ecf20Sopenharmony_ci			 hmc_index);
15618c2ecf20Sopenharmony_ci		ibmvmc_send_rem_buffer_resp(adapter, VMC_MSG_INVALID_HMC_INDEX,
15628c2ecf20Sopenharmony_ci					    hmc_session, hmc_index, buffer_id);
15638c2ecf20Sopenharmony_ci		return -1;
15648c2ecf20Sopenharmony_ci	}
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hmcs[hmc_index].lock, flags);
15678c2ecf20Sopenharmony_ci	buffer = ibmvmc_get_free_hmc_buffer(adapter, hmc_index);
15688c2ecf20Sopenharmony_ci	if (!buffer) {
15698c2ecf20Sopenharmony_ci		dev_info(adapter->dev, "rem_buffer: no buffer to remove\n");
15708c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags);
15718c2ecf20Sopenharmony_ci		ibmvmc_send_rem_buffer_resp(adapter, VMC_MSG_NO_BUFFER,
15728c2ecf20Sopenharmony_ci					    hmc_session, hmc_index,
15738c2ecf20Sopenharmony_ci					    VMC_INVALID_BUFFER_ID);
15748c2ecf20Sopenharmony_ci		return -1;
15758c2ecf20Sopenharmony_ci	}
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci	buffer_id = buffer->id;
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci	if (buffer->valid)
15808c2ecf20Sopenharmony_ci		free_dma_buffer(to_vio_dev(adapter->dev),
15818c2ecf20Sopenharmony_ci				ibmvmc.max_mtu,
15828c2ecf20Sopenharmony_ci				buffer->real_addr_local,
15838c2ecf20Sopenharmony_ci				buffer->dma_addr_local);
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	memset(buffer, 0, sizeof(struct ibmvmc_buffer));
15868c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hmcs[hmc_index].lock, flags);
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "rem_buffer: removed buffer 0x%x.\n", buffer_id);
15898c2ecf20Sopenharmony_ci	ibmvmc_send_rem_buffer_resp(adapter, VMC_MSG_SUCCESS, hmc_session,
15908c2ecf20Sopenharmony_ci				    hmc_index, buffer_id);
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci	return rc;
15938c2ecf20Sopenharmony_ci}
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_cistatic int ibmvmc_recv_msg(struct crq_server_adapter *adapter,
15968c2ecf20Sopenharmony_ci			   struct ibmvmc_crq_msg *crq)
15978c2ecf20Sopenharmony_ci{
15988c2ecf20Sopenharmony_ci	struct ibmvmc_buffer *buffer;
15998c2ecf20Sopenharmony_ci	struct ibmvmc_hmc *hmc;
16008c2ecf20Sopenharmony_ci	unsigned long msg_len;
16018c2ecf20Sopenharmony_ci	u8 hmc_index;
16028c2ecf20Sopenharmony_ci	u8 hmc_session;
16038c2ecf20Sopenharmony_ci	u16 buffer_id;
16048c2ecf20Sopenharmony_ci	unsigned long flags;
16058c2ecf20Sopenharmony_ci	int rc = 0;
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	if (!crq)
16088c2ecf20Sopenharmony_ci		return -1;
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci	/* Hypervisor writes CRQs directly into our memory in big endian */
16118c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "Recv_msg: msg from HV 0x%016llx 0x%016llx\n",
16128c2ecf20Sopenharmony_ci		be64_to_cpu(*((unsigned long *)crq)),
16138c2ecf20Sopenharmony_ci		be64_to_cpu(*(((unsigned long *)crq) + 1)));
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	hmc_session = crq->hmc_session;
16168c2ecf20Sopenharmony_ci	hmc_index = crq->hmc_index;
16178c2ecf20Sopenharmony_ci	buffer_id = be16_to_cpu(crq->var2.buffer_id);
16188c2ecf20Sopenharmony_ci	msg_len = be32_to_cpu(crq->var3.msg_len);
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	if (hmc_index > ibmvmc.max_hmc_index) {
16218c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "Recv_msg: invalid hmc_index = 0x%x\n",
16228c2ecf20Sopenharmony_ci			hmc_index);
16238c2ecf20Sopenharmony_ci		ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_HMC_INDEX,
16248c2ecf20Sopenharmony_ci					    hmc_session, hmc_index, buffer_id);
16258c2ecf20Sopenharmony_ci		return -1;
16268c2ecf20Sopenharmony_ci	}
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	if (buffer_id >= ibmvmc.max_buffer_pool_size) {
16298c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "Recv_msg: invalid buffer_id = 0x%x\n",
16308c2ecf20Sopenharmony_ci			buffer_id);
16318c2ecf20Sopenharmony_ci		ibmvmc_send_add_buffer_resp(adapter, VMC_MSG_INVALID_BUFFER_ID,
16328c2ecf20Sopenharmony_ci					    hmc_session, hmc_index, buffer_id);
16338c2ecf20Sopenharmony_ci		return -1;
16348c2ecf20Sopenharmony_ci	}
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci	hmc = &hmcs[hmc_index];
16378c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hmc->lock, flags);
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci	if (hmc->state == ibmhmc_state_free) {
16408c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "Recv_msg: invalid hmc state = 0x%x\n",
16418c2ecf20Sopenharmony_ci			hmc->state);
16428c2ecf20Sopenharmony_ci		/* HMC connection is not valid (possibly was reset under us). */
16438c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hmc->lock, flags);
16448c2ecf20Sopenharmony_ci		return -1;
16458c2ecf20Sopenharmony_ci	}
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci	buffer = &hmc->buffer[buffer_id];
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	if (buffer->valid == 0 || buffer->owner == VMC_BUF_OWNER_ALPHA) {
16508c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "Recv_msg: not valid, or not HV.  0x%x 0x%x\n",
16518c2ecf20Sopenharmony_ci			buffer->valid, buffer->owner);
16528c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hmc->lock, flags);
16538c2ecf20Sopenharmony_ci		return -1;
16548c2ecf20Sopenharmony_ci	}
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci	/* RDMA the data into the partition. */
16578c2ecf20Sopenharmony_ci	rc = h_copy_rdma(msg_len,
16588c2ecf20Sopenharmony_ci			 adapter->riobn,
16598c2ecf20Sopenharmony_ci			 buffer->dma_addr_remote,
16608c2ecf20Sopenharmony_ci			 adapter->liobn,
16618c2ecf20Sopenharmony_ci			 buffer->dma_addr_local);
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "Recv_msg: msg_len = 0x%x, buffer_id = 0x%x, queue_head = 0x%x, hmc_idx = 0x%x\n",
16648c2ecf20Sopenharmony_ci		(unsigned int)msg_len, (unsigned int)buffer_id,
16658c2ecf20Sopenharmony_ci		(unsigned int)hmc->queue_head, (unsigned int)hmc_index);
16668c2ecf20Sopenharmony_ci	buffer->msg_len = msg_len;
16678c2ecf20Sopenharmony_ci	buffer->free = 0;
16688c2ecf20Sopenharmony_ci	buffer->owner = VMC_BUF_OWNER_ALPHA;
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci	if (rc) {
16718c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "Failure in recv_msg: h_copy_rdma = 0x%x\n",
16728c2ecf20Sopenharmony_ci			rc);
16738c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hmc->lock, flags);
16748c2ecf20Sopenharmony_ci		return -1;
16758c2ecf20Sopenharmony_ci	}
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci	/* Must be locked because read operates on the same data */
16788c2ecf20Sopenharmony_ci	hmc->queue_outbound_msgs[hmc->queue_head] = buffer_id;
16798c2ecf20Sopenharmony_ci	hmc->queue_head++;
16808c2ecf20Sopenharmony_ci	if (hmc->queue_head == ibmvmc_max_buf_pool_size)
16818c2ecf20Sopenharmony_ci		hmc->queue_head = 0;
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci	if (hmc->queue_head == hmc->queue_tail)
16848c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "outbound buffer queue wrapped.\n");
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hmc->lock, flags);
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci	wake_up_interruptible(&ibmvmc_read_wait);
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci	return 0;
16918c2ecf20Sopenharmony_ci}
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci/**
16948c2ecf20Sopenharmony_ci * ibmvmc_process_capabilities - Process Capabilities
16958c2ecf20Sopenharmony_ci *
16968c2ecf20Sopenharmony_ci * @adapter:	crq_server_adapter struct
16978c2ecf20Sopenharmony_ci * @crqp:	ibmvmc_crq_msg struct
16988c2ecf20Sopenharmony_ci *
16998c2ecf20Sopenharmony_ci */
17008c2ecf20Sopenharmony_cistatic void ibmvmc_process_capabilities(struct crq_server_adapter *adapter,
17018c2ecf20Sopenharmony_ci					struct ibmvmc_crq_msg *crqp)
17028c2ecf20Sopenharmony_ci{
17038c2ecf20Sopenharmony_ci	struct ibmvmc_admin_crq_msg *crq = (struct ibmvmc_admin_crq_msg *)crqp;
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci	if ((be16_to_cpu(crq->version) >> 8) !=
17068c2ecf20Sopenharmony_ci			(IBMVMC_PROTOCOL_VERSION >> 8)) {
17078c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "init failed, incompatible versions 0x%x 0x%x\n",
17088c2ecf20Sopenharmony_ci			be16_to_cpu(crq->version),
17098c2ecf20Sopenharmony_ci			IBMVMC_PROTOCOL_VERSION);
17108c2ecf20Sopenharmony_ci		ibmvmc.state = ibmvmc_state_failed;
17118c2ecf20Sopenharmony_ci		return;
17128c2ecf20Sopenharmony_ci	}
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci	ibmvmc.max_mtu = min_t(u32, ibmvmc_max_mtu, be32_to_cpu(crq->max_mtu));
17158c2ecf20Sopenharmony_ci	ibmvmc.max_buffer_pool_size = min_t(u16, ibmvmc_max_buf_pool_size,
17168c2ecf20Sopenharmony_ci					    be16_to_cpu(crq->pool_size));
17178c2ecf20Sopenharmony_ci	ibmvmc.max_hmc_index = min_t(u8, ibmvmc_max_hmcs, crq->max_hmc) - 1;
17188c2ecf20Sopenharmony_ci	ibmvmc.state = ibmvmc_state_ready;
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	dev_info(adapter->dev, "Capabilities: mtu=0x%x, pool_size=0x%x, max_hmc=0x%x\n",
17218c2ecf20Sopenharmony_ci		 ibmvmc.max_mtu, ibmvmc.max_buffer_pool_size,
17228c2ecf20Sopenharmony_ci		 ibmvmc.max_hmc_index);
17238c2ecf20Sopenharmony_ci}
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci/**
17268c2ecf20Sopenharmony_ci * ibmvmc_validate_hmc_session - Validate HMC Session
17278c2ecf20Sopenharmony_ci *
17288c2ecf20Sopenharmony_ci * @adapter:	crq_server_adapter struct
17298c2ecf20Sopenharmony_ci * @crq:	ibmvmc_crq_msg struct
17308c2ecf20Sopenharmony_ci *
17318c2ecf20Sopenharmony_ci * Return:
17328c2ecf20Sopenharmony_ci *	0 - Success
17338c2ecf20Sopenharmony_ci *	Non-zero - Failure
17348c2ecf20Sopenharmony_ci */
17358c2ecf20Sopenharmony_cistatic int ibmvmc_validate_hmc_session(struct crq_server_adapter *adapter,
17368c2ecf20Sopenharmony_ci				       struct ibmvmc_crq_msg *crq)
17378c2ecf20Sopenharmony_ci{
17388c2ecf20Sopenharmony_ci	unsigned char hmc_index;
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci	hmc_index = crq->hmc_index;
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci	if (crq->hmc_session == 0)
17438c2ecf20Sopenharmony_ci		return 0;
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	if (hmc_index > ibmvmc.max_hmc_index)
17468c2ecf20Sopenharmony_ci		return -1;
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	if (hmcs[hmc_index].session != crq->hmc_session) {
17498c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "Drop, bad session: expected 0x%x, recv 0x%x\n",
17508c2ecf20Sopenharmony_ci			 hmcs[hmc_index].session, crq->hmc_session);
17518c2ecf20Sopenharmony_ci		return -1;
17528c2ecf20Sopenharmony_ci	}
17538c2ecf20Sopenharmony_ci
17548c2ecf20Sopenharmony_ci	return 0;
17558c2ecf20Sopenharmony_ci}
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci/**
17588c2ecf20Sopenharmony_ci * ibmvmc_reset - Reset
17598c2ecf20Sopenharmony_ci *
17608c2ecf20Sopenharmony_ci * @adapter:	crq_server_adapter struct
17618c2ecf20Sopenharmony_ci * @xport_event:	export_event field
17628c2ecf20Sopenharmony_ci *
17638c2ecf20Sopenharmony_ci * Closes all HMC sessions and conditionally schedules a CRQ reset.
17648c2ecf20Sopenharmony_ci * @xport_event: If true, the partner closed their CRQ; we don't need to reset.
17658c2ecf20Sopenharmony_ci *               If false, we need to schedule a CRQ reset.
17668c2ecf20Sopenharmony_ci */
17678c2ecf20Sopenharmony_cistatic void ibmvmc_reset(struct crq_server_adapter *adapter, bool xport_event)
17688c2ecf20Sopenharmony_ci{
17698c2ecf20Sopenharmony_ci	int i;
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci	if (ibmvmc.state != ibmvmc_state_sched_reset) {
17728c2ecf20Sopenharmony_ci		dev_info(adapter->dev, "*** Reset to initial state.\n");
17738c2ecf20Sopenharmony_ci		for (i = 0; i < ibmvmc_max_hmcs; i++)
17748c2ecf20Sopenharmony_ci			ibmvmc_return_hmc(&hmcs[i], xport_event);
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci		if (xport_event) {
17778c2ecf20Sopenharmony_ci			/* CRQ was closed by the partner.  We don't need to do
17788c2ecf20Sopenharmony_ci			 * anything except set ourself to the correct state to
17798c2ecf20Sopenharmony_ci			 * handle init msgs.
17808c2ecf20Sopenharmony_ci			 */
17818c2ecf20Sopenharmony_ci			ibmvmc.state = ibmvmc_state_crqinit;
17828c2ecf20Sopenharmony_ci		} else {
17838c2ecf20Sopenharmony_ci			/* The partner did not close their CRQ - instead, we're
17848c2ecf20Sopenharmony_ci			 * closing the CRQ on our end. Need to schedule this
17858c2ecf20Sopenharmony_ci			 * for process context, because CRQ reset may require a
17868c2ecf20Sopenharmony_ci			 * sleep.
17878c2ecf20Sopenharmony_ci			 *
17888c2ecf20Sopenharmony_ci			 * Setting ibmvmc.state here immediately prevents
17898c2ecf20Sopenharmony_ci			 * ibmvmc_open from completing until the reset
17908c2ecf20Sopenharmony_ci			 * completes in process context.
17918c2ecf20Sopenharmony_ci			 */
17928c2ecf20Sopenharmony_ci			ibmvmc.state = ibmvmc_state_sched_reset;
17938c2ecf20Sopenharmony_ci			dev_dbg(adapter->dev, "Device reset scheduled");
17948c2ecf20Sopenharmony_ci			wake_up_interruptible(&adapter->reset_wait_queue);
17958c2ecf20Sopenharmony_ci		}
17968c2ecf20Sopenharmony_ci	}
17978c2ecf20Sopenharmony_ci}
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci/**
18008c2ecf20Sopenharmony_ci * ibmvmc_reset_task - Reset Task
18018c2ecf20Sopenharmony_ci *
18028c2ecf20Sopenharmony_ci * @data:	Data field
18038c2ecf20Sopenharmony_ci *
18048c2ecf20Sopenharmony_ci * Performs a CRQ reset of the VMC device in process context.
18058c2ecf20Sopenharmony_ci * NOTE: This function should not be called directly, use ibmvmc_reset.
18068c2ecf20Sopenharmony_ci */
18078c2ecf20Sopenharmony_cistatic int ibmvmc_reset_task(void *data)
18088c2ecf20Sopenharmony_ci{
18098c2ecf20Sopenharmony_ci	struct crq_server_adapter *adapter = data;
18108c2ecf20Sopenharmony_ci	int rc;
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci	set_user_nice(current, -20);
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_ci	while (!kthread_should_stop()) {
18158c2ecf20Sopenharmony_ci		wait_event_interruptible(adapter->reset_wait_queue,
18168c2ecf20Sopenharmony_ci			(ibmvmc.state == ibmvmc_state_sched_reset) ||
18178c2ecf20Sopenharmony_ci			kthread_should_stop());
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci		if (kthread_should_stop())
18208c2ecf20Sopenharmony_ci			break;
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci		dev_dbg(adapter->dev, "CRQ resetting in process context");
18238c2ecf20Sopenharmony_ci		tasklet_disable(&adapter->work_task);
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ci		rc = ibmvmc_reset_crq_queue(adapter);
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci		if (rc != H_SUCCESS && rc != H_RESOURCE) {
18288c2ecf20Sopenharmony_ci			dev_err(adapter->dev, "Error initializing CRQ.  rc = 0x%x\n",
18298c2ecf20Sopenharmony_ci				rc);
18308c2ecf20Sopenharmony_ci			ibmvmc.state = ibmvmc_state_failed;
18318c2ecf20Sopenharmony_ci		} else {
18328c2ecf20Sopenharmony_ci			ibmvmc.state = ibmvmc_state_crqinit;
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci			if (ibmvmc_send_crq(adapter, 0xC001000000000000LL, 0)
18358c2ecf20Sopenharmony_ci			    != 0 && rc != H_RESOURCE)
18368c2ecf20Sopenharmony_ci				dev_warn(adapter->dev, "Failed to send initialize CRQ message\n");
18378c2ecf20Sopenharmony_ci		}
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci		vio_enable_interrupts(to_vio_dev(adapter->dev));
18408c2ecf20Sopenharmony_ci		tasklet_enable(&adapter->work_task);
18418c2ecf20Sopenharmony_ci	}
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_ci	return 0;
18448c2ecf20Sopenharmony_ci}
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci/**
18478c2ecf20Sopenharmony_ci * ibmvmc_process_open_resp - Process Open Response
18488c2ecf20Sopenharmony_ci *
18498c2ecf20Sopenharmony_ci * @crq: ibmvmc_crq_msg struct
18508c2ecf20Sopenharmony_ci * @adapter:    crq_server_adapter struct
18518c2ecf20Sopenharmony_ci *
18528c2ecf20Sopenharmony_ci * This command is sent by the hypervisor in response to the Interface
18538c2ecf20Sopenharmony_ci * Open message. When this message is received, the indicated buffer is
18548c2ecf20Sopenharmony_ci * again available for management partition use.
18558c2ecf20Sopenharmony_ci */
18568c2ecf20Sopenharmony_cistatic void ibmvmc_process_open_resp(struct ibmvmc_crq_msg *crq,
18578c2ecf20Sopenharmony_ci				     struct crq_server_adapter *adapter)
18588c2ecf20Sopenharmony_ci{
18598c2ecf20Sopenharmony_ci	unsigned char hmc_index;
18608c2ecf20Sopenharmony_ci	unsigned short buffer_id;
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_ci	hmc_index = crq->hmc_index;
18638c2ecf20Sopenharmony_ci	if (hmc_index > ibmvmc.max_hmc_index) {
18648c2ecf20Sopenharmony_ci		/* Why would PHYP give an index > max negotiated? */
18658c2ecf20Sopenharmony_ci		ibmvmc_reset(adapter, false);
18668c2ecf20Sopenharmony_ci		return;
18678c2ecf20Sopenharmony_ci	}
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_ci	if (crq->status) {
18708c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "open_resp: failed - status 0x%x\n",
18718c2ecf20Sopenharmony_ci			 crq->status);
18728c2ecf20Sopenharmony_ci		ibmvmc_return_hmc(&hmcs[hmc_index], false);
18738c2ecf20Sopenharmony_ci		return;
18748c2ecf20Sopenharmony_ci	}
18758c2ecf20Sopenharmony_ci
18768c2ecf20Sopenharmony_ci	if (hmcs[hmc_index].state == ibmhmc_state_opening) {
18778c2ecf20Sopenharmony_ci		buffer_id = be16_to_cpu(crq->var2.buffer_id);
18788c2ecf20Sopenharmony_ci		if (buffer_id >= ibmvmc.max_buffer_pool_size) {
18798c2ecf20Sopenharmony_ci			dev_err(adapter->dev, "open_resp: invalid buffer_id = 0x%x\n",
18808c2ecf20Sopenharmony_ci				buffer_id);
18818c2ecf20Sopenharmony_ci			hmcs[hmc_index].state = ibmhmc_state_failed;
18828c2ecf20Sopenharmony_ci		} else {
18838c2ecf20Sopenharmony_ci			ibmvmc_free_hmc_buffer(&hmcs[hmc_index],
18848c2ecf20Sopenharmony_ci					       &hmcs[hmc_index].buffer[buffer_id]);
18858c2ecf20Sopenharmony_ci			hmcs[hmc_index].state = ibmhmc_state_ready;
18868c2ecf20Sopenharmony_ci			dev_dbg(adapter->dev, "open_resp: set hmc state = ready\n");
18878c2ecf20Sopenharmony_ci		}
18888c2ecf20Sopenharmony_ci	} else {
18898c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "open_resp: invalid hmc state (0x%x)\n",
18908c2ecf20Sopenharmony_ci			 hmcs[hmc_index].state);
18918c2ecf20Sopenharmony_ci	}
18928c2ecf20Sopenharmony_ci}
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci/**
18958c2ecf20Sopenharmony_ci * ibmvmc_process_close_resp - Process Close Response
18968c2ecf20Sopenharmony_ci *
18978c2ecf20Sopenharmony_ci * @crq: ibmvmc_crq_msg struct
18988c2ecf20Sopenharmony_ci * @adapter:    crq_server_adapter struct
18998c2ecf20Sopenharmony_ci *
19008c2ecf20Sopenharmony_ci * This command is sent by the hypervisor in response to the managemant
19018c2ecf20Sopenharmony_ci * application Interface Close message.
19028c2ecf20Sopenharmony_ci *
19038c2ecf20Sopenharmony_ci * If the close fails, simply reset the entire driver as the state of the VMC
19048c2ecf20Sopenharmony_ci * must be in tough shape.
19058c2ecf20Sopenharmony_ci */
19068c2ecf20Sopenharmony_cistatic void ibmvmc_process_close_resp(struct ibmvmc_crq_msg *crq,
19078c2ecf20Sopenharmony_ci				      struct crq_server_adapter *adapter)
19088c2ecf20Sopenharmony_ci{
19098c2ecf20Sopenharmony_ci	unsigned char hmc_index;
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci	hmc_index = crq->hmc_index;
19128c2ecf20Sopenharmony_ci	if (hmc_index > ibmvmc.max_hmc_index) {
19138c2ecf20Sopenharmony_ci		ibmvmc_reset(adapter, false);
19148c2ecf20Sopenharmony_ci		return;
19158c2ecf20Sopenharmony_ci	}
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_ci	if (crq->status) {
19188c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "close_resp: failed - status 0x%x\n",
19198c2ecf20Sopenharmony_ci			 crq->status);
19208c2ecf20Sopenharmony_ci		ibmvmc_reset(adapter, false);
19218c2ecf20Sopenharmony_ci		return;
19228c2ecf20Sopenharmony_ci	}
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_ci	ibmvmc_return_hmc(&hmcs[hmc_index], false);
19258c2ecf20Sopenharmony_ci}
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_ci/**
19288c2ecf20Sopenharmony_ci * ibmvmc_crq_process - Process CRQ
19298c2ecf20Sopenharmony_ci *
19308c2ecf20Sopenharmony_ci * @adapter:    crq_server_adapter struct
19318c2ecf20Sopenharmony_ci * @crq:	ibmvmc_crq_msg struct
19328c2ecf20Sopenharmony_ci *
19338c2ecf20Sopenharmony_ci * Process the CRQ message based upon the type of message received.
19348c2ecf20Sopenharmony_ci *
19358c2ecf20Sopenharmony_ci */
19368c2ecf20Sopenharmony_cistatic void ibmvmc_crq_process(struct crq_server_adapter *adapter,
19378c2ecf20Sopenharmony_ci			       struct ibmvmc_crq_msg *crq)
19388c2ecf20Sopenharmony_ci{
19398c2ecf20Sopenharmony_ci	switch (crq->type) {
19408c2ecf20Sopenharmony_ci	case VMC_MSG_CAP_RESP:
19418c2ecf20Sopenharmony_ci		dev_dbg(adapter->dev, "CRQ recv: capabilities resp (0x%x)\n",
19428c2ecf20Sopenharmony_ci			crq->type);
19438c2ecf20Sopenharmony_ci		if (ibmvmc.state == ibmvmc_state_capabilities)
19448c2ecf20Sopenharmony_ci			ibmvmc_process_capabilities(adapter, crq);
19458c2ecf20Sopenharmony_ci		else
19468c2ecf20Sopenharmony_ci			dev_warn(adapter->dev, "caps msg invalid in state 0x%x\n",
19478c2ecf20Sopenharmony_ci				 ibmvmc.state);
19488c2ecf20Sopenharmony_ci		break;
19498c2ecf20Sopenharmony_ci	case VMC_MSG_OPEN_RESP:
19508c2ecf20Sopenharmony_ci		dev_dbg(adapter->dev, "CRQ recv: open resp (0x%x)\n",
19518c2ecf20Sopenharmony_ci			crq->type);
19528c2ecf20Sopenharmony_ci		if (ibmvmc_validate_hmc_session(adapter, crq) == 0)
19538c2ecf20Sopenharmony_ci			ibmvmc_process_open_resp(crq, adapter);
19548c2ecf20Sopenharmony_ci		break;
19558c2ecf20Sopenharmony_ci	case VMC_MSG_ADD_BUF:
19568c2ecf20Sopenharmony_ci		dev_dbg(adapter->dev, "CRQ recv: add buf (0x%x)\n",
19578c2ecf20Sopenharmony_ci			crq->type);
19588c2ecf20Sopenharmony_ci		if (ibmvmc_validate_hmc_session(adapter, crq) == 0)
19598c2ecf20Sopenharmony_ci			ibmvmc_add_buffer(adapter, crq);
19608c2ecf20Sopenharmony_ci		break;
19618c2ecf20Sopenharmony_ci	case VMC_MSG_REM_BUF:
19628c2ecf20Sopenharmony_ci		dev_dbg(adapter->dev, "CRQ recv: rem buf (0x%x)\n",
19638c2ecf20Sopenharmony_ci			crq->type);
19648c2ecf20Sopenharmony_ci		if (ibmvmc_validate_hmc_session(adapter, crq) == 0)
19658c2ecf20Sopenharmony_ci			ibmvmc_rem_buffer(adapter, crq);
19668c2ecf20Sopenharmony_ci		break;
19678c2ecf20Sopenharmony_ci	case VMC_MSG_SIGNAL:
19688c2ecf20Sopenharmony_ci		dev_dbg(adapter->dev, "CRQ recv: signal msg (0x%x)\n",
19698c2ecf20Sopenharmony_ci			crq->type);
19708c2ecf20Sopenharmony_ci		if (ibmvmc_validate_hmc_session(adapter, crq) == 0)
19718c2ecf20Sopenharmony_ci			ibmvmc_recv_msg(adapter, crq);
19728c2ecf20Sopenharmony_ci		break;
19738c2ecf20Sopenharmony_ci	case VMC_MSG_CLOSE_RESP:
19748c2ecf20Sopenharmony_ci		dev_dbg(adapter->dev, "CRQ recv: close resp (0x%x)\n",
19758c2ecf20Sopenharmony_ci			crq->type);
19768c2ecf20Sopenharmony_ci		if (ibmvmc_validate_hmc_session(adapter, crq) == 0)
19778c2ecf20Sopenharmony_ci			ibmvmc_process_close_resp(crq, adapter);
19788c2ecf20Sopenharmony_ci		break;
19798c2ecf20Sopenharmony_ci	case VMC_MSG_CAP:
19808c2ecf20Sopenharmony_ci	case VMC_MSG_OPEN:
19818c2ecf20Sopenharmony_ci	case VMC_MSG_CLOSE:
19828c2ecf20Sopenharmony_ci	case VMC_MSG_ADD_BUF_RESP:
19838c2ecf20Sopenharmony_ci	case VMC_MSG_REM_BUF_RESP:
19848c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "CRQ recv: unexpected msg (0x%x)\n",
19858c2ecf20Sopenharmony_ci			 crq->type);
19868c2ecf20Sopenharmony_ci		break;
19878c2ecf20Sopenharmony_ci	default:
19888c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "CRQ recv: unknown msg (0x%x)\n",
19898c2ecf20Sopenharmony_ci			 crq->type);
19908c2ecf20Sopenharmony_ci		break;
19918c2ecf20Sopenharmony_ci	}
19928c2ecf20Sopenharmony_ci}
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci/**
19958c2ecf20Sopenharmony_ci * ibmvmc_handle_crq_init - Handle CRQ Init
19968c2ecf20Sopenharmony_ci *
19978c2ecf20Sopenharmony_ci * @crq:	ibmvmc_crq_msg struct
19988c2ecf20Sopenharmony_ci * @adapter:	crq_server_adapter struct
19998c2ecf20Sopenharmony_ci *
20008c2ecf20Sopenharmony_ci * Handle the type of crq initialization based on whether
20018c2ecf20Sopenharmony_ci * it is a message or a response.
20028c2ecf20Sopenharmony_ci *
20038c2ecf20Sopenharmony_ci */
20048c2ecf20Sopenharmony_cistatic void ibmvmc_handle_crq_init(struct ibmvmc_crq_msg *crq,
20058c2ecf20Sopenharmony_ci				   struct crq_server_adapter *adapter)
20068c2ecf20Sopenharmony_ci{
20078c2ecf20Sopenharmony_ci	switch (crq->type) {
20088c2ecf20Sopenharmony_ci	case 0x01:	/* Initialization message */
20098c2ecf20Sopenharmony_ci		dev_dbg(adapter->dev, "CRQ recv: CRQ init msg - state 0x%x\n",
20108c2ecf20Sopenharmony_ci			ibmvmc.state);
20118c2ecf20Sopenharmony_ci		if (ibmvmc.state == ibmvmc_state_crqinit) {
20128c2ecf20Sopenharmony_ci			/* Send back a response */
20138c2ecf20Sopenharmony_ci			if (ibmvmc_send_crq(adapter, 0xC002000000000000,
20148c2ecf20Sopenharmony_ci					    0) == 0)
20158c2ecf20Sopenharmony_ci				ibmvmc_send_capabilities(adapter);
20168c2ecf20Sopenharmony_ci			else
20178c2ecf20Sopenharmony_ci				dev_err(adapter->dev, " Unable to send init rsp\n");
20188c2ecf20Sopenharmony_ci		} else {
20198c2ecf20Sopenharmony_ci			dev_err(adapter->dev, "Invalid state 0x%x mtu = 0x%x\n",
20208c2ecf20Sopenharmony_ci				ibmvmc.state, ibmvmc.max_mtu);
20218c2ecf20Sopenharmony_ci		}
20228c2ecf20Sopenharmony_ci
20238c2ecf20Sopenharmony_ci		break;
20248c2ecf20Sopenharmony_ci	case 0x02:	/* Initialization response */
20258c2ecf20Sopenharmony_ci		dev_dbg(adapter->dev, "CRQ recv: initialization resp msg - state 0x%x\n",
20268c2ecf20Sopenharmony_ci			ibmvmc.state);
20278c2ecf20Sopenharmony_ci		if (ibmvmc.state == ibmvmc_state_crqinit)
20288c2ecf20Sopenharmony_ci			ibmvmc_send_capabilities(adapter);
20298c2ecf20Sopenharmony_ci		break;
20308c2ecf20Sopenharmony_ci	default:
20318c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "Unknown crq message type 0x%lx\n",
20328c2ecf20Sopenharmony_ci			 (unsigned long)crq->type);
20338c2ecf20Sopenharmony_ci	}
20348c2ecf20Sopenharmony_ci}
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci/**
20378c2ecf20Sopenharmony_ci * ibmvmc_handle_crq - Handle CRQ
20388c2ecf20Sopenharmony_ci *
20398c2ecf20Sopenharmony_ci * @crq:	ibmvmc_crq_msg struct
20408c2ecf20Sopenharmony_ci * @adapter:	crq_server_adapter struct
20418c2ecf20Sopenharmony_ci *
20428c2ecf20Sopenharmony_ci * Read the command elements from the command queue and execute the
20438c2ecf20Sopenharmony_ci * requests based upon the type of crq message.
20448c2ecf20Sopenharmony_ci *
20458c2ecf20Sopenharmony_ci */
20468c2ecf20Sopenharmony_cistatic void ibmvmc_handle_crq(struct ibmvmc_crq_msg *crq,
20478c2ecf20Sopenharmony_ci			      struct crq_server_adapter *adapter)
20488c2ecf20Sopenharmony_ci{
20498c2ecf20Sopenharmony_ci	switch (crq->valid) {
20508c2ecf20Sopenharmony_ci	case 0xC0:		/* initialization */
20518c2ecf20Sopenharmony_ci		ibmvmc_handle_crq_init(crq, adapter);
20528c2ecf20Sopenharmony_ci		break;
20538c2ecf20Sopenharmony_ci	case 0xFF:	/* Hypervisor telling us the connection is closed */
20548c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "CRQ recv: virtual adapter failed - resetting.\n");
20558c2ecf20Sopenharmony_ci		ibmvmc_reset(adapter, true);
20568c2ecf20Sopenharmony_ci		break;
20578c2ecf20Sopenharmony_ci	case 0x80:	/* real payload */
20588c2ecf20Sopenharmony_ci		ibmvmc_crq_process(adapter, crq);
20598c2ecf20Sopenharmony_ci		break;
20608c2ecf20Sopenharmony_ci	default:
20618c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "CRQ recv: unknown msg 0x%02x.\n",
20628c2ecf20Sopenharmony_ci			 crq->valid);
20638c2ecf20Sopenharmony_ci		break;
20648c2ecf20Sopenharmony_ci	}
20658c2ecf20Sopenharmony_ci}
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_cistatic void ibmvmc_task(unsigned long data)
20688c2ecf20Sopenharmony_ci{
20698c2ecf20Sopenharmony_ci	struct crq_server_adapter *adapter =
20708c2ecf20Sopenharmony_ci		(struct crq_server_adapter *)data;
20718c2ecf20Sopenharmony_ci	struct vio_dev *vdev = to_vio_dev(adapter->dev);
20728c2ecf20Sopenharmony_ci	struct ibmvmc_crq_msg *crq;
20738c2ecf20Sopenharmony_ci	int done = 0;
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_ci	while (!done) {
20768c2ecf20Sopenharmony_ci		/* Pull all the valid messages off the CRQ */
20778c2ecf20Sopenharmony_ci		while ((crq = crq_queue_next_crq(&adapter->queue)) != NULL) {
20788c2ecf20Sopenharmony_ci			ibmvmc_handle_crq(crq, adapter);
20798c2ecf20Sopenharmony_ci			crq->valid = 0x00;
20808c2ecf20Sopenharmony_ci			/* CRQ reset was requested, stop processing CRQs.
20818c2ecf20Sopenharmony_ci			 * Interrupts will be re-enabled by the reset task.
20828c2ecf20Sopenharmony_ci			 */
20838c2ecf20Sopenharmony_ci			if (ibmvmc.state == ibmvmc_state_sched_reset)
20848c2ecf20Sopenharmony_ci				return;
20858c2ecf20Sopenharmony_ci		}
20868c2ecf20Sopenharmony_ci
20878c2ecf20Sopenharmony_ci		vio_enable_interrupts(vdev);
20888c2ecf20Sopenharmony_ci		crq = crq_queue_next_crq(&adapter->queue);
20898c2ecf20Sopenharmony_ci		if (crq) {
20908c2ecf20Sopenharmony_ci			vio_disable_interrupts(vdev);
20918c2ecf20Sopenharmony_ci			ibmvmc_handle_crq(crq, adapter);
20928c2ecf20Sopenharmony_ci			crq->valid = 0x00;
20938c2ecf20Sopenharmony_ci			/* CRQ reset was requested, stop processing CRQs.
20948c2ecf20Sopenharmony_ci			 * Interrupts will be re-enabled by the reset task.
20958c2ecf20Sopenharmony_ci			 */
20968c2ecf20Sopenharmony_ci			if (ibmvmc.state == ibmvmc_state_sched_reset)
20978c2ecf20Sopenharmony_ci				return;
20988c2ecf20Sopenharmony_ci		} else {
20998c2ecf20Sopenharmony_ci			done = 1;
21008c2ecf20Sopenharmony_ci		}
21018c2ecf20Sopenharmony_ci	}
21028c2ecf20Sopenharmony_ci}
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci/**
21058c2ecf20Sopenharmony_ci * ibmvmc_init_crq_queue - Init CRQ Queue
21068c2ecf20Sopenharmony_ci *
21078c2ecf20Sopenharmony_ci * @adapter:	crq_server_adapter struct
21088c2ecf20Sopenharmony_ci *
21098c2ecf20Sopenharmony_ci * Return:
21108c2ecf20Sopenharmony_ci *	0 - Success
21118c2ecf20Sopenharmony_ci *	Non-zero - Failure
21128c2ecf20Sopenharmony_ci */
21138c2ecf20Sopenharmony_cistatic int ibmvmc_init_crq_queue(struct crq_server_adapter *adapter)
21148c2ecf20Sopenharmony_ci{
21158c2ecf20Sopenharmony_ci	struct vio_dev *vdev = to_vio_dev(adapter->dev);
21168c2ecf20Sopenharmony_ci	struct crq_queue *queue = &adapter->queue;
21178c2ecf20Sopenharmony_ci	int rc = 0;
21188c2ecf20Sopenharmony_ci	int retrc = 0;
21198c2ecf20Sopenharmony_ci
21208c2ecf20Sopenharmony_ci	queue->msgs = (struct ibmvmc_crq_msg *)get_zeroed_page(GFP_KERNEL);
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci	if (!queue->msgs)
21238c2ecf20Sopenharmony_ci		goto malloc_failed;
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci	queue->size = PAGE_SIZE / sizeof(*queue->msgs);
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci	queue->msg_token = dma_map_single(adapter->dev, queue->msgs,
21288c2ecf20Sopenharmony_ci					  queue->size * sizeof(*queue->msgs),
21298c2ecf20Sopenharmony_ci					  DMA_BIDIRECTIONAL);
21308c2ecf20Sopenharmony_ci
21318c2ecf20Sopenharmony_ci	if (dma_mapping_error(adapter->dev, queue->msg_token))
21328c2ecf20Sopenharmony_ci		goto map_failed;
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci	retrc = plpar_hcall_norets(H_REG_CRQ,
21358c2ecf20Sopenharmony_ci				   vdev->unit_address,
21368c2ecf20Sopenharmony_ci				   queue->msg_token, PAGE_SIZE);
21378c2ecf20Sopenharmony_ci	rc = retrc;
21388c2ecf20Sopenharmony_ci
21398c2ecf20Sopenharmony_ci	if (rc == H_RESOURCE)
21408c2ecf20Sopenharmony_ci		rc = ibmvmc_reset_crq_queue(adapter);
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_ci	if (rc == 2) {
21438c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "Partner adapter not ready\n");
21448c2ecf20Sopenharmony_ci		retrc = 0;
21458c2ecf20Sopenharmony_ci	} else if (rc != 0) {
21468c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "Error %d opening adapter\n", rc);
21478c2ecf20Sopenharmony_ci		goto reg_crq_failed;
21488c2ecf20Sopenharmony_ci	}
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci	queue->cur = 0;
21518c2ecf20Sopenharmony_ci	spin_lock_init(&queue->lock);
21528c2ecf20Sopenharmony_ci
21538c2ecf20Sopenharmony_ci	tasklet_init(&adapter->work_task, ibmvmc_task, (unsigned long)adapter);
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci	if (request_irq(vdev->irq,
21568c2ecf20Sopenharmony_ci			ibmvmc_handle_event,
21578c2ecf20Sopenharmony_ci			0, "ibmvmc", (void *)adapter) != 0) {
21588c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "couldn't register irq 0x%x\n",
21598c2ecf20Sopenharmony_ci			vdev->irq);
21608c2ecf20Sopenharmony_ci		goto req_irq_failed;
21618c2ecf20Sopenharmony_ci	}
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci	rc = vio_enable_interrupts(vdev);
21648c2ecf20Sopenharmony_ci	if (rc != 0) {
21658c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "Error %d enabling interrupts!!!\n", rc);
21668c2ecf20Sopenharmony_ci		goto req_irq_failed;
21678c2ecf20Sopenharmony_ci	}
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci	return retrc;
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_cireq_irq_failed:
21728c2ecf20Sopenharmony_ci	/* Cannot have any work since we either never got our IRQ registered,
21738c2ecf20Sopenharmony_ci	 * or never got interrupts enabled
21748c2ecf20Sopenharmony_ci	 */
21758c2ecf20Sopenharmony_ci	tasklet_kill(&adapter->work_task);
21768c2ecf20Sopenharmony_ci	h_free_crq(vdev->unit_address);
21778c2ecf20Sopenharmony_cireg_crq_failed:
21788c2ecf20Sopenharmony_ci	dma_unmap_single(adapter->dev,
21798c2ecf20Sopenharmony_ci			 queue->msg_token,
21808c2ecf20Sopenharmony_ci			 queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
21818c2ecf20Sopenharmony_cimap_failed:
21828c2ecf20Sopenharmony_ci	free_page((unsigned long)queue->msgs);
21838c2ecf20Sopenharmony_cimalloc_failed:
21848c2ecf20Sopenharmony_ci	return -ENOMEM;
21858c2ecf20Sopenharmony_ci}
21868c2ecf20Sopenharmony_ci
21878c2ecf20Sopenharmony_ci/* Fill in the liobn and riobn fields on the adapter */
21888c2ecf20Sopenharmony_cistatic int read_dma_window(struct vio_dev *vdev,
21898c2ecf20Sopenharmony_ci			   struct crq_server_adapter *adapter)
21908c2ecf20Sopenharmony_ci{
21918c2ecf20Sopenharmony_ci	const __be32 *dma_window;
21928c2ecf20Sopenharmony_ci	const __be32 *prop;
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ci	/* TODO Using of_parse_dma_window would be better, but it doesn't give
21958c2ecf20Sopenharmony_ci	 * a way to read multiple windows without already knowing the size of
21968c2ecf20Sopenharmony_ci	 * a window or the number of windows
21978c2ecf20Sopenharmony_ci	 */
21988c2ecf20Sopenharmony_ci	dma_window =
21998c2ecf20Sopenharmony_ci		(const __be32 *)vio_get_attribute(vdev, "ibm,my-dma-window",
22008c2ecf20Sopenharmony_ci						NULL);
22018c2ecf20Sopenharmony_ci	if (!dma_window) {
22028c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "Couldn't find ibm,my-dma-window property\n");
22038c2ecf20Sopenharmony_ci		return -1;
22048c2ecf20Sopenharmony_ci	}
22058c2ecf20Sopenharmony_ci
22068c2ecf20Sopenharmony_ci	adapter->liobn = be32_to_cpu(*dma_window);
22078c2ecf20Sopenharmony_ci	dma_window++;
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_ci	prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-address-cells",
22108c2ecf20Sopenharmony_ci						NULL);
22118c2ecf20Sopenharmony_ci	if (!prop) {
22128c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "Couldn't find ibm,#dma-address-cells property\n");
22138c2ecf20Sopenharmony_ci		dma_window++;
22148c2ecf20Sopenharmony_ci	} else {
22158c2ecf20Sopenharmony_ci		dma_window += be32_to_cpu(*prop);
22168c2ecf20Sopenharmony_ci	}
22178c2ecf20Sopenharmony_ci
22188c2ecf20Sopenharmony_ci	prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-size-cells",
22198c2ecf20Sopenharmony_ci						NULL);
22208c2ecf20Sopenharmony_ci	if (!prop) {
22218c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "Couldn't find ibm,#dma-size-cells property\n");
22228c2ecf20Sopenharmony_ci		dma_window++;
22238c2ecf20Sopenharmony_ci	} else {
22248c2ecf20Sopenharmony_ci		dma_window += be32_to_cpu(*prop);
22258c2ecf20Sopenharmony_ci	}
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_ci	/* dma_window should point to the second window now */
22288c2ecf20Sopenharmony_ci	adapter->riobn = be32_to_cpu(*dma_window);
22298c2ecf20Sopenharmony_ci
22308c2ecf20Sopenharmony_ci	return 0;
22318c2ecf20Sopenharmony_ci}
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_cistatic int ibmvmc_probe(struct vio_dev *vdev, const struct vio_device_id *id)
22348c2ecf20Sopenharmony_ci{
22358c2ecf20Sopenharmony_ci	struct crq_server_adapter *adapter = &ibmvmc_adapter;
22368c2ecf20Sopenharmony_ci	int rc;
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_ci	dev_set_drvdata(&vdev->dev, NULL);
22398c2ecf20Sopenharmony_ci	memset(adapter, 0, sizeof(*adapter));
22408c2ecf20Sopenharmony_ci	adapter->dev = &vdev->dev;
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci	dev_info(adapter->dev, "Probe for UA 0x%x\n", vdev->unit_address);
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci	rc = read_dma_window(vdev, adapter);
22458c2ecf20Sopenharmony_ci	if (rc != 0) {
22468c2ecf20Sopenharmony_ci		ibmvmc.state = ibmvmc_state_failed;
22478c2ecf20Sopenharmony_ci		return -1;
22488c2ecf20Sopenharmony_ci	}
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_ci	dev_dbg(adapter->dev, "Probe: liobn 0x%x, riobn 0x%x\n",
22518c2ecf20Sopenharmony_ci		adapter->liobn, adapter->riobn);
22528c2ecf20Sopenharmony_ci
22538c2ecf20Sopenharmony_ci	init_waitqueue_head(&adapter->reset_wait_queue);
22548c2ecf20Sopenharmony_ci	adapter->reset_task = kthread_run(ibmvmc_reset_task, adapter, "ibmvmc");
22558c2ecf20Sopenharmony_ci	if (IS_ERR(adapter->reset_task)) {
22568c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "Failed to start reset thread\n");
22578c2ecf20Sopenharmony_ci		ibmvmc.state = ibmvmc_state_failed;
22588c2ecf20Sopenharmony_ci		rc = PTR_ERR(adapter->reset_task);
22598c2ecf20Sopenharmony_ci		adapter->reset_task = NULL;
22608c2ecf20Sopenharmony_ci		return rc;
22618c2ecf20Sopenharmony_ci	}
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_ci	rc = ibmvmc_init_crq_queue(adapter);
22648c2ecf20Sopenharmony_ci	if (rc != 0 && rc != H_RESOURCE) {
22658c2ecf20Sopenharmony_ci		dev_err(adapter->dev, "Error initializing CRQ.  rc = 0x%x\n",
22668c2ecf20Sopenharmony_ci			rc);
22678c2ecf20Sopenharmony_ci		ibmvmc.state = ibmvmc_state_failed;
22688c2ecf20Sopenharmony_ci		goto crq_failed;
22698c2ecf20Sopenharmony_ci	}
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_ci	ibmvmc.state = ibmvmc_state_crqinit;
22728c2ecf20Sopenharmony_ci
22738c2ecf20Sopenharmony_ci	/* Try to send an initialization message.  Note that this is allowed
22748c2ecf20Sopenharmony_ci	 * to fail if the other end is not acive.  In that case we just wait
22758c2ecf20Sopenharmony_ci	 * for the other side to initialize.
22768c2ecf20Sopenharmony_ci	 */
22778c2ecf20Sopenharmony_ci	if (ibmvmc_send_crq(adapter, 0xC001000000000000LL, 0) != 0 &&
22788c2ecf20Sopenharmony_ci	    rc != H_RESOURCE)
22798c2ecf20Sopenharmony_ci		dev_warn(adapter->dev, "Failed to send initialize CRQ message\n");
22808c2ecf20Sopenharmony_ci
22818c2ecf20Sopenharmony_ci	dev_set_drvdata(&vdev->dev, adapter);
22828c2ecf20Sopenharmony_ci
22838c2ecf20Sopenharmony_ci	return 0;
22848c2ecf20Sopenharmony_ci
22858c2ecf20Sopenharmony_cicrq_failed:
22868c2ecf20Sopenharmony_ci	kthread_stop(adapter->reset_task);
22878c2ecf20Sopenharmony_ci	adapter->reset_task = NULL;
22888c2ecf20Sopenharmony_ci	return -EPERM;
22898c2ecf20Sopenharmony_ci}
22908c2ecf20Sopenharmony_ci
22918c2ecf20Sopenharmony_cistatic int ibmvmc_remove(struct vio_dev *vdev)
22928c2ecf20Sopenharmony_ci{
22938c2ecf20Sopenharmony_ci	struct crq_server_adapter *adapter = dev_get_drvdata(&vdev->dev);
22948c2ecf20Sopenharmony_ci
22958c2ecf20Sopenharmony_ci	dev_info(adapter->dev, "Entering remove for UA 0x%x\n",
22968c2ecf20Sopenharmony_ci		 vdev->unit_address);
22978c2ecf20Sopenharmony_ci	ibmvmc_release_crq_queue(adapter);
22988c2ecf20Sopenharmony_ci
22998c2ecf20Sopenharmony_ci	return 0;
23008c2ecf20Sopenharmony_ci}
23018c2ecf20Sopenharmony_ci
23028c2ecf20Sopenharmony_cistatic struct vio_device_id ibmvmc_device_table[] = {
23038c2ecf20Sopenharmony_ci	{ "ibm,vmc", "IBM,vmc" },
23048c2ecf20Sopenharmony_ci	{ "", "" }
23058c2ecf20Sopenharmony_ci};
23068c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(vio, ibmvmc_device_table);
23078c2ecf20Sopenharmony_ci
23088c2ecf20Sopenharmony_cistatic struct vio_driver ibmvmc_driver = {
23098c2ecf20Sopenharmony_ci	.name        = ibmvmc_driver_name,
23108c2ecf20Sopenharmony_ci	.id_table    = ibmvmc_device_table,
23118c2ecf20Sopenharmony_ci	.probe       = ibmvmc_probe,
23128c2ecf20Sopenharmony_ci	.remove      = ibmvmc_remove,
23138c2ecf20Sopenharmony_ci};
23148c2ecf20Sopenharmony_ci
23158c2ecf20Sopenharmony_cistatic void __init ibmvmc_scrub_module_parms(void)
23168c2ecf20Sopenharmony_ci{
23178c2ecf20Sopenharmony_ci	if (ibmvmc_max_mtu > MAX_MTU) {
23188c2ecf20Sopenharmony_ci		pr_warn("ibmvmc: Max MTU reduced to %d\n", MAX_MTU);
23198c2ecf20Sopenharmony_ci		ibmvmc_max_mtu = MAX_MTU;
23208c2ecf20Sopenharmony_ci	} else if (ibmvmc_max_mtu < MIN_MTU) {
23218c2ecf20Sopenharmony_ci		pr_warn("ibmvmc: Max MTU increased to %d\n", MIN_MTU);
23228c2ecf20Sopenharmony_ci		ibmvmc_max_mtu = MIN_MTU;
23238c2ecf20Sopenharmony_ci	}
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci	if (ibmvmc_max_buf_pool_size > MAX_BUF_POOL_SIZE) {
23268c2ecf20Sopenharmony_ci		pr_warn("ibmvmc: Max buffer pool size reduced to %d\n",
23278c2ecf20Sopenharmony_ci			MAX_BUF_POOL_SIZE);
23288c2ecf20Sopenharmony_ci		ibmvmc_max_buf_pool_size = MAX_BUF_POOL_SIZE;
23298c2ecf20Sopenharmony_ci	} else if (ibmvmc_max_buf_pool_size < MIN_BUF_POOL_SIZE) {
23308c2ecf20Sopenharmony_ci		pr_warn("ibmvmc: Max buffer pool size increased to %d\n",
23318c2ecf20Sopenharmony_ci			MIN_BUF_POOL_SIZE);
23328c2ecf20Sopenharmony_ci		ibmvmc_max_buf_pool_size = MIN_BUF_POOL_SIZE;
23338c2ecf20Sopenharmony_ci	}
23348c2ecf20Sopenharmony_ci
23358c2ecf20Sopenharmony_ci	if (ibmvmc_max_hmcs > MAX_HMCS) {
23368c2ecf20Sopenharmony_ci		pr_warn("ibmvmc: Max HMCs reduced to %d\n", MAX_HMCS);
23378c2ecf20Sopenharmony_ci		ibmvmc_max_hmcs = MAX_HMCS;
23388c2ecf20Sopenharmony_ci	} else if (ibmvmc_max_hmcs < MIN_HMCS) {
23398c2ecf20Sopenharmony_ci		pr_warn("ibmvmc: Max HMCs increased to %d\n", MIN_HMCS);
23408c2ecf20Sopenharmony_ci		ibmvmc_max_hmcs = MIN_HMCS;
23418c2ecf20Sopenharmony_ci	}
23428c2ecf20Sopenharmony_ci}
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_cistatic struct miscdevice ibmvmc_miscdev = {
23458c2ecf20Sopenharmony_ci	.name = ibmvmc_driver_name,
23468c2ecf20Sopenharmony_ci	.minor = MISC_DYNAMIC_MINOR,
23478c2ecf20Sopenharmony_ci	.fops = &ibmvmc_fops,
23488c2ecf20Sopenharmony_ci};
23498c2ecf20Sopenharmony_ci
23508c2ecf20Sopenharmony_cistatic int __init ibmvmc_module_init(void)
23518c2ecf20Sopenharmony_ci{
23528c2ecf20Sopenharmony_ci	int rc, i, j;
23538c2ecf20Sopenharmony_ci
23548c2ecf20Sopenharmony_ci	ibmvmc.state = ibmvmc_state_initial;
23558c2ecf20Sopenharmony_ci	pr_info("ibmvmc: version %s\n", IBMVMC_DRIVER_VERSION);
23568c2ecf20Sopenharmony_ci
23578c2ecf20Sopenharmony_ci	rc = misc_register(&ibmvmc_miscdev);
23588c2ecf20Sopenharmony_ci	if (rc) {
23598c2ecf20Sopenharmony_ci		pr_err("ibmvmc: misc registration failed\n");
23608c2ecf20Sopenharmony_ci		goto misc_register_failed;
23618c2ecf20Sopenharmony_ci	}
23628c2ecf20Sopenharmony_ci	pr_info("ibmvmc: node %d:%d\n", MISC_MAJOR,
23638c2ecf20Sopenharmony_ci		ibmvmc_miscdev.minor);
23648c2ecf20Sopenharmony_ci
23658c2ecf20Sopenharmony_ci	/* Initialize data structures */
23668c2ecf20Sopenharmony_ci	memset(hmcs, 0, sizeof(struct ibmvmc_hmc) * MAX_HMCS);
23678c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_HMCS; i++) {
23688c2ecf20Sopenharmony_ci		spin_lock_init(&hmcs[i].lock);
23698c2ecf20Sopenharmony_ci		hmcs[i].state = ibmhmc_state_free;
23708c2ecf20Sopenharmony_ci		for (j = 0; j < MAX_BUF_POOL_SIZE; j++)
23718c2ecf20Sopenharmony_ci			hmcs[i].queue_outbound_msgs[j] = VMC_INVALID_BUFFER_ID;
23728c2ecf20Sopenharmony_ci	}
23738c2ecf20Sopenharmony_ci
23748c2ecf20Sopenharmony_ci	/* Sanity check module parms */
23758c2ecf20Sopenharmony_ci	ibmvmc_scrub_module_parms();
23768c2ecf20Sopenharmony_ci
23778c2ecf20Sopenharmony_ci	/*
23788c2ecf20Sopenharmony_ci	 * Initialize some reasonable values.  Might be negotiated smaller
23798c2ecf20Sopenharmony_ci	 * values during the capabilities exchange.
23808c2ecf20Sopenharmony_ci	 */
23818c2ecf20Sopenharmony_ci	ibmvmc.max_mtu = ibmvmc_max_mtu;
23828c2ecf20Sopenharmony_ci	ibmvmc.max_buffer_pool_size = ibmvmc_max_buf_pool_size;
23838c2ecf20Sopenharmony_ci	ibmvmc.max_hmc_index = ibmvmc_max_hmcs - 1;
23848c2ecf20Sopenharmony_ci
23858c2ecf20Sopenharmony_ci	rc = vio_register_driver(&ibmvmc_driver);
23868c2ecf20Sopenharmony_ci
23878c2ecf20Sopenharmony_ci	if (rc) {
23888c2ecf20Sopenharmony_ci		pr_err("ibmvmc: rc %d from vio_register_driver\n", rc);
23898c2ecf20Sopenharmony_ci		goto vio_reg_failed;
23908c2ecf20Sopenharmony_ci	}
23918c2ecf20Sopenharmony_ci
23928c2ecf20Sopenharmony_ci	return 0;
23938c2ecf20Sopenharmony_ci
23948c2ecf20Sopenharmony_civio_reg_failed:
23958c2ecf20Sopenharmony_ci	misc_deregister(&ibmvmc_miscdev);
23968c2ecf20Sopenharmony_cimisc_register_failed:
23978c2ecf20Sopenharmony_ci	return rc;
23988c2ecf20Sopenharmony_ci}
23998c2ecf20Sopenharmony_ci
24008c2ecf20Sopenharmony_cistatic void __exit ibmvmc_module_exit(void)
24018c2ecf20Sopenharmony_ci{
24028c2ecf20Sopenharmony_ci	pr_info("ibmvmc: module exit\n");
24038c2ecf20Sopenharmony_ci	vio_unregister_driver(&ibmvmc_driver);
24048c2ecf20Sopenharmony_ci	misc_deregister(&ibmvmc_miscdev);
24058c2ecf20Sopenharmony_ci}
24068c2ecf20Sopenharmony_ci
24078c2ecf20Sopenharmony_cimodule_init(ibmvmc_module_init);
24088c2ecf20Sopenharmony_cimodule_exit(ibmvmc_module_exit);
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_cimodule_param_named(buf_pool_size, ibmvmc_max_buf_pool_size,
24118c2ecf20Sopenharmony_ci		   int, 0644);
24128c2ecf20Sopenharmony_ciMODULE_PARM_DESC(buf_pool_size, "Buffer pool size");
24138c2ecf20Sopenharmony_cimodule_param_named(max_hmcs, ibmvmc_max_hmcs, int, 0644);
24148c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_hmcs, "Max HMCs");
24158c2ecf20Sopenharmony_cimodule_param_named(max_mtu, ibmvmc_max_mtu, int, 0644);
24168c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_mtu, "Max MTU");
24178c2ecf20Sopenharmony_ci
24188c2ecf20Sopenharmony_ciMODULE_AUTHOR("Steven Royer <seroyer@linux.vnet.ibm.com>");
24198c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("IBM VMC");
24208c2ecf20Sopenharmony_ciMODULE_VERSION(IBMVMC_DRIVER_VERSION);
24218c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
2422