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