1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 29d1a546cSKirti Wankhede /* 39d1a546cSKirti Wankhede * Mediated virtual PCI serial host device driver 49d1a546cSKirti Wankhede * 59d1a546cSKirti Wankhede * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. 69d1a546cSKirti Wankhede * Author: Neo Jia <cjia@nvidia.com> 79d1a546cSKirti Wankhede * Kirti Wankhede <kwankhede@nvidia.com> 89d1a546cSKirti Wankhede * 99d1a546cSKirti Wankhede * Sample driver that creates mdev device that simulates serial port over PCI 109d1a546cSKirti Wankhede * card. 119d1a546cSKirti Wankhede */ 129d1a546cSKirti Wankhede 139d1a546cSKirti Wankhede #include <linux/init.h> 149d1a546cSKirti Wankhede #include <linux/module.h> 159d1a546cSKirti Wankhede #include <linux/device.h> 169d1a546cSKirti Wankhede #include <linux/kernel.h> 179d1a546cSKirti Wankhede #include <linux/fs.h> 189d1a546cSKirti Wankhede #include <linux/poll.h> 199d1a546cSKirti Wankhede #include <linux/slab.h> 209d1a546cSKirti Wankhede #include <linux/cdev.h> 219d1a546cSKirti Wankhede #include <linux/sched.h> 229d1a546cSKirti Wankhede #include <linux/wait.h> 239d1a546cSKirti Wankhede #include <linux/uuid.h> 249d1a546cSKirti Wankhede #include <linux/vfio.h> 259d1a546cSKirti Wankhede #include <linux/iommu.h> 269d1a546cSKirti Wankhede #include <linux/sysfs.h> 279d1a546cSKirti Wankhede #include <linux/ctype.h> 289d1a546cSKirti Wankhede #include <linux/file.h> 299d1a546cSKirti Wankhede #include <linux/mdev.h> 309d1a546cSKirti Wankhede #include <linux/pci.h> 319d1a546cSKirti Wankhede #include <linux/serial.h> 329d1a546cSKirti Wankhede #include <uapi/linux/serial_reg.h> 339d1a546cSKirti Wankhede #include <linux/eventfd.h> 349d1a546cSKirti Wankhede /* 359d1a546cSKirti Wankhede * #defines 369d1a546cSKirti Wankhede */ 379d1a546cSKirti Wankhede 389d1a546cSKirti Wankhede #define VERSION_STRING "0.1" 399d1a546cSKirti Wankhede #define DRIVER_AUTHOR "NVIDIA Corporation" 409d1a546cSKirti Wankhede 419d1a546cSKirti Wankhede #define MTTY_CLASS_NAME "mtty" 429d1a546cSKirti Wankhede 439d1a546cSKirti Wankhede #define MTTY_NAME "mtty" 449d1a546cSKirti Wankhede 459d1a546cSKirti Wankhede #define MTTY_STRING_LEN 16 469d1a546cSKirti Wankhede 479d1a546cSKirti Wankhede #define MTTY_CONFIG_SPACE_SIZE 0xff 489d1a546cSKirti Wankhede #define MTTY_IO_BAR_SIZE 0x8 499d1a546cSKirti Wankhede #define MTTY_MMIO_BAR_SIZE 0x100000 509d1a546cSKirti Wankhede 519d1a546cSKirti Wankhede #define STORE_LE16(addr, val) (*(u16 *)addr = val) 529d1a546cSKirti Wankhede #define STORE_LE32(addr, val) (*(u32 *)addr = val) 539d1a546cSKirti Wankhede 549d1a546cSKirti Wankhede #define MAX_FIFO_SIZE 16 559d1a546cSKirti Wankhede 569d1a546cSKirti Wankhede #define CIRCULAR_BUF_INC_IDX(idx) (idx = (idx + 1) & (MAX_FIFO_SIZE - 1)) 579d1a546cSKirti Wankhede 589d1a546cSKirti Wankhede #define MTTY_VFIO_PCI_OFFSET_SHIFT 40 599d1a546cSKirti Wankhede 609d1a546cSKirti Wankhede #define MTTY_VFIO_PCI_OFFSET_TO_INDEX(off) (off >> MTTY_VFIO_PCI_OFFSET_SHIFT) 619d1a546cSKirti Wankhede #define MTTY_VFIO_PCI_INDEX_TO_OFFSET(index) \ 629d1a546cSKirti Wankhede ((u64)(index) << MTTY_VFIO_PCI_OFFSET_SHIFT) 639d1a546cSKirti Wankhede #define MTTY_VFIO_PCI_OFFSET_MASK \ 649d1a546cSKirti Wankhede (((u64)(1) << MTTY_VFIO_PCI_OFFSET_SHIFT) - 1) 659d1a546cSKirti Wankhede #define MAX_MTTYS 24 669d1a546cSKirti Wankhede 679d1a546cSKirti Wankhede /* 689d1a546cSKirti Wankhede * Global Structures 699d1a546cSKirti Wankhede */ 709d1a546cSKirti Wankhede 714b2dbd56SKefeng Wang static struct mtty_dev { 729d1a546cSKirti Wankhede dev_t vd_devt; 739d1a546cSKirti Wankhede struct class *vd_class; 749d1a546cSKirti Wankhede struct cdev vd_cdev; 759d1a546cSKirti Wankhede struct idr vd_idr; 769d1a546cSKirti Wankhede struct device dev; 779d1a546cSKirti Wankhede } mtty_dev; 789d1a546cSKirti Wankhede 799d1a546cSKirti Wankhede struct mdev_region_info { 809d1a546cSKirti Wankhede u64 start; 819d1a546cSKirti Wankhede u64 phys_start; 829d1a546cSKirti Wankhede u32 size; 839d1a546cSKirti Wankhede u64 vfio_offset; 849d1a546cSKirti Wankhede }; 859d1a546cSKirti Wankhede 869d1a546cSKirti Wankhede #if defined(DEBUG_REGS) 874b2dbd56SKefeng Wang static const char *wr_reg[] = { 889d1a546cSKirti Wankhede "TX", 899d1a546cSKirti Wankhede "IER", 909d1a546cSKirti Wankhede "FCR", 919d1a546cSKirti Wankhede "LCR", 929d1a546cSKirti Wankhede "MCR", 939d1a546cSKirti Wankhede "LSR", 949d1a546cSKirti Wankhede "MSR", 959d1a546cSKirti Wankhede "SCR" 969d1a546cSKirti Wankhede }; 979d1a546cSKirti Wankhede 984b2dbd56SKefeng Wang static const char *rd_reg[] = { 999d1a546cSKirti Wankhede "RX", 1009d1a546cSKirti Wankhede "IER", 1019d1a546cSKirti Wankhede "IIR", 1029d1a546cSKirti Wankhede "LCR", 1039d1a546cSKirti Wankhede "MCR", 1049d1a546cSKirti Wankhede "LSR", 1059d1a546cSKirti Wankhede "MSR", 1069d1a546cSKirti Wankhede "SCR" 1079d1a546cSKirti Wankhede }; 1089d1a546cSKirti Wankhede #endif 1099d1a546cSKirti Wankhede 1109d1a546cSKirti Wankhede /* loop back buffer */ 1119d1a546cSKirti Wankhede struct rxtx { 1129d1a546cSKirti Wankhede u8 fifo[MAX_FIFO_SIZE]; 1139d1a546cSKirti Wankhede u8 head, tail; 1149d1a546cSKirti Wankhede u8 count; 1159d1a546cSKirti Wankhede }; 1169d1a546cSKirti Wankhede 1179d1a546cSKirti Wankhede struct serial_port { 1189d1a546cSKirti Wankhede u8 uart_reg[8]; /* 8 registers */ 1199d1a546cSKirti Wankhede struct rxtx rxtx; /* loop back buffer */ 1209d1a546cSKirti Wankhede bool dlab; 1219d1a546cSKirti Wankhede bool overrun; 1229d1a546cSKirti Wankhede u16 divisor; 1239d1a546cSKirti Wankhede u8 fcr; /* FIFO control register */ 1249d1a546cSKirti Wankhede u8 max_fifo_size; 1259d1a546cSKirti Wankhede u8 intr_trigger_level; /* interrupt trigger level */ 1269d1a546cSKirti Wankhede }; 1279d1a546cSKirti Wankhede 1289d1a546cSKirti Wankhede /* State of each mdev device */ 1299d1a546cSKirti Wankhede struct mdev_state { 13009177ac9SJason Gunthorpe struct vfio_device vdev; 1319d1a546cSKirti Wankhede int irq_fd; 1329d1a546cSKirti Wankhede struct eventfd_ctx *intx_evtfd; 1339d1a546cSKirti Wankhede struct eventfd_ctx *msi_evtfd; 1349d1a546cSKirti Wankhede int irq_index; 1359d1a546cSKirti Wankhede u8 *vconfig; 1369d1a546cSKirti Wankhede struct mutex ops_lock; 1379d1a546cSKirti Wankhede struct mdev_device *mdev; 1389d1a546cSKirti Wankhede struct mdev_region_info region_info[VFIO_PCI_NUM_REGIONS]; 1399d1a546cSKirti Wankhede u32 bar_mask[VFIO_PCI_NUM_REGIONS]; 1409d1a546cSKirti Wankhede struct list_head next; 1419d1a546cSKirti Wankhede struct serial_port s[2]; 1429d1a546cSKirti Wankhede struct mutex rxtx_lock; 1439d1a546cSKirti Wankhede struct vfio_device_info dev_info; 1449d1a546cSKirti Wankhede int nr_ports; 1459d1a546cSKirti Wankhede }; 1469d1a546cSKirti Wankhede 14797d0a687SAlex Williamson static atomic_t mdev_avail_ports = ATOMIC_INIT(MAX_MTTYS); 1489d1a546cSKirti Wankhede 1499d1a546cSKirti Wankhede static const struct file_operations vd_fops = { 1509d1a546cSKirti Wankhede .owner = THIS_MODULE, 1519d1a546cSKirti Wankhede }; 1529d1a546cSKirti Wankhede 15309177ac9SJason Gunthorpe static const struct vfio_device_ops mtty_dev_ops; 15409177ac9SJason Gunthorpe 1559d1a546cSKirti Wankhede /* function prototypes */ 1569d1a546cSKirti Wankhede 157eee413e6SParav Pandit static int mtty_trigger_interrupt(struct mdev_state *mdev_state); 1589d1a546cSKirti Wankhede 1599d1a546cSKirti Wankhede /* Helper functions */ 1609d1a546cSKirti Wankhede 1614b2dbd56SKefeng Wang static void dump_buffer(u8 *buf, uint32_t count) 1629d1a546cSKirti Wankhede { 1639d1a546cSKirti Wankhede #if defined(DEBUG) 1649d1a546cSKirti Wankhede int i; 1659d1a546cSKirti Wankhede 1669d1a546cSKirti Wankhede pr_info("Buffer:\n"); 1679d1a546cSKirti Wankhede for (i = 0; i < count; i++) { 1689d1a546cSKirti Wankhede pr_info("%2x ", *(buf + i)); 1699d1a546cSKirti Wankhede if ((i + 1) % 16 == 0) 1709d1a546cSKirti Wankhede pr_info("\n"); 1719d1a546cSKirti Wankhede } 1729d1a546cSKirti Wankhede #endif 1739d1a546cSKirti Wankhede } 1749d1a546cSKirti Wankhede 1759d1a546cSKirti Wankhede static void mtty_create_config_space(struct mdev_state *mdev_state) 1769d1a546cSKirti Wankhede { 1779d1a546cSKirti Wankhede /* PCI dev ID */ 1789d1a546cSKirti Wankhede STORE_LE32((u32 *) &mdev_state->vconfig[0x0], 0x32534348); 1799d1a546cSKirti Wankhede 1809d1a546cSKirti Wankhede /* Control: I/O+, Mem-, BusMaster- */ 1819d1a546cSKirti Wankhede STORE_LE16((u16 *) &mdev_state->vconfig[0x4], 0x0001); 1829d1a546cSKirti Wankhede 1839d1a546cSKirti Wankhede /* Status: capabilities list absent */ 1849d1a546cSKirti Wankhede STORE_LE16((u16 *) &mdev_state->vconfig[0x6], 0x0200); 1859d1a546cSKirti Wankhede 1869d1a546cSKirti Wankhede /* Rev ID */ 1879d1a546cSKirti Wankhede mdev_state->vconfig[0x8] = 0x10; 1889d1a546cSKirti Wankhede 1899d1a546cSKirti Wankhede /* programming interface class : 16550-compatible serial controller */ 1909d1a546cSKirti Wankhede mdev_state->vconfig[0x9] = 0x02; 1919d1a546cSKirti Wankhede 1929d1a546cSKirti Wankhede /* Sub class : 00 */ 1939d1a546cSKirti Wankhede mdev_state->vconfig[0xa] = 0x00; 1949d1a546cSKirti Wankhede 1959d1a546cSKirti Wankhede /* Base class : Simple Communication controllers */ 1969d1a546cSKirti Wankhede mdev_state->vconfig[0xb] = 0x07; 1979d1a546cSKirti Wankhede 1989d1a546cSKirti Wankhede /* base address registers */ 1999d1a546cSKirti Wankhede /* BAR0: IO space */ 2009d1a546cSKirti Wankhede STORE_LE32((u32 *) &mdev_state->vconfig[0x10], 0x000001); 2019d1a546cSKirti Wankhede mdev_state->bar_mask[0] = ~(MTTY_IO_BAR_SIZE) + 1; 2029d1a546cSKirti Wankhede 2039d1a546cSKirti Wankhede if (mdev_state->nr_ports == 2) { 2049d1a546cSKirti Wankhede /* BAR1: IO space */ 2059d1a546cSKirti Wankhede STORE_LE32((u32 *) &mdev_state->vconfig[0x14], 0x000001); 2069d1a546cSKirti Wankhede mdev_state->bar_mask[1] = ~(MTTY_IO_BAR_SIZE) + 1; 2079d1a546cSKirti Wankhede } 2089d1a546cSKirti Wankhede 2099d1a546cSKirti Wankhede /* Subsystem ID */ 2109d1a546cSKirti Wankhede STORE_LE32((u32 *) &mdev_state->vconfig[0x2c], 0x32534348); 2119d1a546cSKirti Wankhede 2129d1a546cSKirti Wankhede mdev_state->vconfig[0x34] = 0x00; /* Cap Ptr */ 2139d1a546cSKirti Wankhede mdev_state->vconfig[0x3d] = 0x01; /* interrupt pin (INTA#) */ 2149d1a546cSKirti Wankhede 2159d1a546cSKirti Wankhede /* Vendor specific data */ 2169d1a546cSKirti Wankhede mdev_state->vconfig[0x40] = 0x23; 2179d1a546cSKirti Wankhede mdev_state->vconfig[0x43] = 0x80; 2189d1a546cSKirti Wankhede mdev_state->vconfig[0x44] = 0x23; 2199d1a546cSKirti Wankhede mdev_state->vconfig[0x48] = 0x23; 2209d1a546cSKirti Wankhede mdev_state->vconfig[0x4c] = 0x23; 2219d1a546cSKirti Wankhede 2229d1a546cSKirti Wankhede mdev_state->vconfig[0x60] = 0x50; 2239d1a546cSKirti Wankhede mdev_state->vconfig[0x61] = 0x43; 2249d1a546cSKirti Wankhede mdev_state->vconfig[0x62] = 0x49; 2259d1a546cSKirti Wankhede mdev_state->vconfig[0x63] = 0x20; 2269d1a546cSKirti Wankhede mdev_state->vconfig[0x64] = 0x53; 2279d1a546cSKirti Wankhede mdev_state->vconfig[0x65] = 0x65; 2289d1a546cSKirti Wankhede mdev_state->vconfig[0x66] = 0x72; 2299d1a546cSKirti Wankhede mdev_state->vconfig[0x67] = 0x69; 2309d1a546cSKirti Wankhede mdev_state->vconfig[0x68] = 0x61; 2319d1a546cSKirti Wankhede mdev_state->vconfig[0x69] = 0x6c; 2329d1a546cSKirti Wankhede mdev_state->vconfig[0x6a] = 0x2f; 2339d1a546cSKirti Wankhede mdev_state->vconfig[0x6b] = 0x55; 2349d1a546cSKirti Wankhede mdev_state->vconfig[0x6c] = 0x41; 2359d1a546cSKirti Wankhede mdev_state->vconfig[0x6d] = 0x52; 2369d1a546cSKirti Wankhede mdev_state->vconfig[0x6e] = 0x54; 2379d1a546cSKirti Wankhede } 2389d1a546cSKirti Wankhede 2399d1a546cSKirti Wankhede static void handle_pci_cfg_write(struct mdev_state *mdev_state, u16 offset, 2408ba35b3aSNathan Chancellor u8 *buf, u32 count) 2419d1a546cSKirti Wankhede { 2429d1a546cSKirti Wankhede u32 cfg_addr, bar_mask, bar_index = 0; 2439d1a546cSKirti Wankhede 2449d1a546cSKirti Wankhede switch (offset) { 2459d1a546cSKirti Wankhede case 0x04: /* device control */ 2469d1a546cSKirti Wankhede case 0x06: /* device status */ 2479d1a546cSKirti Wankhede /* do nothing */ 2489d1a546cSKirti Wankhede break; 2499d1a546cSKirti Wankhede case 0x3c: /* interrupt line */ 2509d1a546cSKirti Wankhede mdev_state->vconfig[0x3c] = buf[0]; 2519d1a546cSKirti Wankhede break; 2529d1a546cSKirti Wankhede case 0x3d: 2539d1a546cSKirti Wankhede /* 2549d1a546cSKirti Wankhede * Interrupt Pin is hardwired to INTA. 2559d1a546cSKirti Wankhede * This field is write protected by hardware 2569d1a546cSKirti Wankhede */ 2579d1a546cSKirti Wankhede break; 2589d1a546cSKirti Wankhede case 0x10: /* BAR0 */ 2599d1a546cSKirti Wankhede case 0x14: /* BAR1 */ 2609d1a546cSKirti Wankhede if (offset == 0x10) 2619d1a546cSKirti Wankhede bar_index = 0; 2629d1a546cSKirti Wankhede else if (offset == 0x14) 2639d1a546cSKirti Wankhede bar_index = 1; 2649d1a546cSKirti Wankhede 2659d1a546cSKirti Wankhede if ((mdev_state->nr_ports == 1) && (bar_index == 1)) { 2669d1a546cSKirti Wankhede STORE_LE32(&mdev_state->vconfig[offset], 0); 2679d1a546cSKirti Wankhede break; 2689d1a546cSKirti Wankhede } 2699d1a546cSKirti Wankhede 2709d1a546cSKirti Wankhede cfg_addr = *(u32 *)buf; 2719d1a546cSKirti Wankhede pr_info("BAR%d addr 0x%x\n", bar_index, cfg_addr); 2729d1a546cSKirti Wankhede 2739d1a546cSKirti Wankhede if (cfg_addr == 0xffffffff) { 2749d1a546cSKirti Wankhede bar_mask = mdev_state->bar_mask[bar_index]; 2759d1a546cSKirti Wankhede cfg_addr = (cfg_addr & bar_mask); 2769d1a546cSKirti Wankhede } 2779d1a546cSKirti Wankhede 2789d1a546cSKirti Wankhede cfg_addr |= (mdev_state->vconfig[offset] & 0x3ul); 2799d1a546cSKirti Wankhede STORE_LE32(&mdev_state->vconfig[offset], cfg_addr); 2809d1a546cSKirti Wankhede break; 2819d1a546cSKirti Wankhede case 0x18: /* BAR2 */ 2829d1a546cSKirti Wankhede case 0x1c: /* BAR3 */ 2839d1a546cSKirti Wankhede case 0x20: /* BAR4 */ 2849d1a546cSKirti Wankhede STORE_LE32(&mdev_state->vconfig[offset], 0); 2859d1a546cSKirti Wankhede break; 2869d1a546cSKirti Wankhede default: 2879d1a546cSKirti Wankhede pr_info("PCI config write @0x%x of %d bytes not handled\n", 2889d1a546cSKirti Wankhede offset, count); 2899d1a546cSKirti Wankhede break; 2909d1a546cSKirti Wankhede } 2919d1a546cSKirti Wankhede } 2929d1a546cSKirti Wankhede 2939d1a546cSKirti Wankhede static void handle_bar_write(unsigned int index, struct mdev_state *mdev_state, 2948ba35b3aSNathan Chancellor u16 offset, u8 *buf, u32 count) 2959d1a546cSKirti Wankhede { 2969d1a546cSKirti Wankhede u8 data = *buf; 2979d1a546cSKirti Wankhede 2989d1a546cSKirti Wankhede /* Handle data written by guest */ 2999d1a546cSKirti Wankhede switch (offset) { 3009d1a546cSKirti Wankhede case UART_TX: 3019d1a546cSKirti Wankhede /* if DLAB set, data is LSB of divisor */ 3029d1a546cSKirti Wankhede if (mdev_state->s[index].dlab) { 3039d1a546cSKirti Wankhede mdev_state->s[index].divisor |= data; 3049d1a546cSKirti Wankhede break; 3059d1a546cSKirti Wankhede } 3069d1a546cSKirti Wankhede 3079d1a546cSKirti Wankhede mutex_lock(&mdev_state->rxtx_lock); 3089d1a546cSKirti Wankhede 3099d1a546cSKirti Wankhede /* save in TX buffer */ 3109d1a546cSKirti Wankhede if (mdev_state->s[index].rxtx.count < 3119d1a546cSKirti Wankhede mdev_state->s[index].max_fifo_size) { 3129d1a546cSKirti Wankhede mdev_state->s[index].rxtx.fifo[ 3139d1a546cSKirti Wankhede mdev_state->s[index].rxtx.head] = data; 3149d1a546cSKirti Wankhede mdev_state->s[index].rxtx.count++; 3159d1a546cSKirti Wankhede CIRCULAR_BUF_INC_IDX(mdev_state->s[index].rxtx.head); 3169d1a546cSKirti Wankhede mdev_state->s[index].overrun = false; 3179d1a546cSKirti Wankhede 3189d1a546cSKirti Wankhede /* 3199d1a546cSKirti Wankhede * Trigger interrupt if receive data interrupt is 3209d1a546cSKirti Wankhede * enabled and fifo reached trigger level 3219d1a546cSKirti Wankhede */ 3229d1a546cSKirti Wankhede if ((mdev_state->s[index].uart_reg[UART_IER] & 3239d1a546cSKirti Wankhede UART_IER_RDI) && 3249d1a546cSKirti Wankhede (mdev_state->s[index].rxtx.count == 3259d1a546cSKirti Wankhede mdev_state->s[index].intr_trigger_level)) { 3269d1a546cSKirti Wankhede /* trigger interrupt */ 3279d1a546cSKirti Wankhede #if defined(DEBUG_INTR) 3289d1a546cSKirti Wankhede pr_err("Serial port %d: Fifo level trigger\n", 3299d1a546cSKirti Wankhede index); 3309d1a546cSKirti Wankhede #endif 331eee413e6SParav Pandit mtty_trigger_interrupt(mdev_state); 3329d1a546cSKirti Wankhede } 3339d1a546cSKirti Wankhede } else { 3349d1a546cSKirti Wankhede #if defined(DEBUG_INTR) 3359d1a546cSKirti Wankhede pr_err("Serial port %d: Buffer Overflow\n", index); 3369d1a546cSKirti Wankhede #endif 3379d1a546cSKirti Wankhede mdev_state->s[index].overrun = true; 3389d1a546cSKirti Wankhede 3399d1a546cSKirti Wankhede /* 3409d1a546cSKirti Wankhede * Trigger interrupt if receiver line status interrupt 3419d1a546cSKirti Wankhede * is enabled 3429d1a546cSKirti Wankhede */ 3439d1a546cSKirti Wankhede if (mdev_state->s[index].uart_reg[UART_IER] & 3449d1a546cSKirti Wankhede UART_IER_RLSI) 345eee413e6SParav Pandit mtty_trigger_interrupt(mdev_state); 3469d1a546cSKirti Wankhede } 3479d1a546cSKirti Wankhede mutex_unlock(&mdev_state->rxtx_lock); 3489d1a546cSKirti Wankhede break; 3499d1a546cSKirti Wankhede 3509d1a546cSKirti Wankhede case UART_IER: 3519d1a546cSKirti Wankhede /* if DLAB set, data is MSB of divisor */ 3529d1a546cSKirti Wankhede if (mdev_state->s[index].dlab) 3539d1a546cSKirti Wankhede mdev_state->s[index].divisor |= (u16)data << 8; 3549d1a546cSKirti Wankhede else { 3559d1a546cSKirti Wankhede mdev_state->s[index].uart_reg[offset] = data; 3569d1a546cSKirti Wankhede mutex_lock(&mdev_state->rxtx_lock); 3579d1a546cSKirti Wankhede if ((data & UART_IER_THRI) && 3589d1a546cSKirti Wankhede (mdev_state->s[index].rxtx.head == 3599d1a546cSKirti Wankhede mdev_state->s[index].rxtx.tail)) { 3609d1a546cSKirti Wankhede #if defined(DEBUG_INTR) 3619d1a546cSKirti Wankhede pr_err("Serial port %d: IER_THRI write\n", 3629d1a546cSKirti Wankhede index); 3639d1a546cSKirti Wankhede #endif 364eee413e6SParav Pandit mtty_trigger_interrupt(mdev_state); 3659d1a546cSKirti Wankhede } 3669d1a546cSKirti Wankhede 3679d1a546cSKirti Wankhede mutex_unlock(&mdev_state->rxtx_lock); 3689d1a546cSKirti Wankhede } 3699d1a546cSKirti Wankhede 3709d1a546cSKirti Wankhede break; 3719d1a546cSKirti Wankhede 3729d1a546cSKirti Wankhede case UART_FCR: 3739d1a546cSKirti Wankhede mdev_state->s[index].fcr = data; 3749d1a546cSKirti Wankhede 3759d1a546cSKirti Wankhede mutex_lock(&mdev_state->rxtx_lock); 3769d1a546cSKirti Wankhede if (data & (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)) { 3779d1a546cSKirti Wankhede /* clear loop back FIFO */ 3789d1a546cSKirti Wankhede mdev_state->s[index].rxtx.count = 0; 3799d1a546cSKirti Wankhede mdev_state->s[index].rxtx.head = 0; 3809d1a546cSKirti Wankhede mdev_state->s[index].rxtx.tail = 0; 3819d1a546cSKirti Wankhede } 3829d1a546cSKirti Wankhede mutex_unlock(&mdev_state->rxtx_lock); 3839d1a546cSKirti Wankhede 3849d1a546cSKirti Wankhede switch (data & UART_FCR_TRIGGER_MASK) { 3859d1a546cSKirti Wankhede case UART_FCR_TRIGGER_1: 3869d1a546cSKirti Wankhede mdev_state->s[index].intr_trigger_level = 1; 3879d1a546cSKirti Wankhede break; 3889d1a546cSKirti Wankhede 3899d1a546cSKirti Wankhede case UART_FCR_TRIGGER_4: 3909d1a546cSKirti Wankhede mdev_state->s[index].intr_trigger_level = 4; 3919d1a546cSKirti Wankhede break; 3929d1a546cSKirti Wankhede 3939d1a546cSKirti Wankhede case UART_FCR_TRIGGER_8: 3949d1a546cSKirti Wankhede mdev_state->s[index].intr_trigger_level = 8; 3959d1a546cSKirti Wankhede break; 3969d1a546cSKirti Wankhede 3979d1a546cSKirti Wankhede case UART_FCR_TRIGGER_14: 3989d1a546cSKirti Wankhede mdev_state->s[index].intr_trigger_level = 14; 3999d1a546cSKirti Wankhede break; 4009d1a546cSKirti Wankhede } 4019d1a546cSKirti Wankhede 4029d1a546cSKirti Wankhede /* 4039d1a546cSKirti Wankhede * Set trigger level to 1 otherwise or implement timer with 4049d1a546cSKirti Wankhede * timeout of 4 characters and on expiring that timer set 4059d1a546cSKirti Wankhede * Recevice data timeout in IIR register 4069d1a546cSKirti Wankhede */ 4079d1a546cSKirti Wankhede mdev_state->s[index].intr_trigger_level = 1; 4089d1a546cSKirti Wankhede if (data & UART_FCR_ENABLE_FIFO) 4099d1a546cSKirti Wankhede mdev_state->s[index].max_fifo_size = MAX_FIFO_SIZE; 4109d1a546cSKirti Wankhede else { 4119d1a546cSKirti Wankhede mdev_state->s[index].max_fifo_size = 1; 4129d1a546cSKirti Wankhede mdev_state->s[index].intr_trigger_level = 1; 4139d1a546cSKirti Wankhede } 4149d1a546cSKirti Wankhede 4159d1a546cSKirti Wankhede break; 4169d1a546cSKirti Wankhede 4179d1a546cSKirti Wankhede case UART_LCR: 4189d1a546cSKirti Wankhede if (data & UART_LCR_DLAB) { 4199d1a546cSKirti Wankhede mdev_state->s[index].dlab = true; 4209d1a546cSKirti Wankhede mdev_state->s[index].divisor = 0; 4219d1a546cSKirti Wankhede } else 4229d1a546cSKirti Wankhede mdev_state->s[index].dlab = false; 4239d1a546cSKirti Wankhede 4249d1a546cSKirti Wankhede mdev_state->s[index].uart_reg[offset] = data; 4259d1a546cSKirti Wankhede break; 4269d1a546cSKirti Wankhede 4279d1a546cSKirti Wankhede case UART_MCR: 4289d1a546cSKirti Wankhede mdev_state->s[index].uart_reg[offset] = data; 4299d1a546cSKirti Wankhede 4309d1a546cSKirti Wankhede if ((mdev_state->s[index].uart_reg[UART_IER] & UART_IER_MSI) && 4319d1a546cSKirti Wankhede (data & UART_MCR_OUT2)) { 4329d1a546cSKirti Wankhede #if defined(DEBUG_INTR) 4339d1a546cSKirti Wankhede pr_err("Serial port %d: MCR_OUT2 write\n", index); 4349d1a546cSKirti Wankhede #endif 435eee413e6SParav Pandit mtty_trigger_interrupt(mdev_state); 4369d1a546cSKirti Wankhede } 4379d1a546cSKirti Wankhede 4389d1a546cSKirti Wankhede if ((mdev_state->s[index].uart_reg[UART_IER] & UART_IER_MSI) && 4399d1a546cSKirti Wankhede (data & (UART_MCR_RTS | UART_MCR_DTR))) { 4409d1a546cSKirti Wankhede #if defined(DEBUG_INTR) 4419d1a546cSKirti Wankhede pr_err("Serial port %d: MCR RTS/DTR write\n", index); 4429d1a546cSKirti Wankhede #endif 443eee413e6SParav Pandit mtty_trigger_interrupt(mdev_state); 4449d1a546cSKirti Wankhede } 4459d1a546cSKirti Wankhede break; 4469d1a546cSKirti Wankhede 4479d1a546cSKirti Wankhede case UART_LSR: 4489d1a546cSKirti Wankhede case UART_MSR: 4499d1a546cSKirti Wankhede /* do nothing */ 4509d1a546cSKirti Wankhede break; 4519d1a546cSKirti Wankhede 4529d1a546cSKirti Wankhede case UART_SCR: 4539d1a546cSKirti Wankhede mdev_state->s[index].uart_reg[offset] = data; 4549d1a546cSKirti Wankhede break; 4559d1a546cSKirti Wankhede 4569d1a546cSKirti Wankhede default: 4579d1a546cSKirti Wankhede break; 4589d1a546cSKirti Wankhede } 4599d1a546cSKirti Wankhede } 4609d1a546cSKirti Wankhede 4619d1a546cSKirti Wankhede static void handle_bar_read(unsigned int index, struct mdev_state *mdev_state, 4628ba35b3aSNathan Chancellor u16 offset, u8 *buf, u32 count) 4639d1a546cSKirti Wankhede { 4649d1a546cSKirti Wankhede /* Handle read requests by guest */ 4659d1a546cSKirti Wankhede switch (offset) { 4669d1a546cSKirti Wankhede case UART_RX: 4679d1a546cSKirti Wankhede /* if DLAB set, data is LSB of divisor */ 4689d1a546cSKirti Wankhede if (mdev_state->s[index].dlab) { 4699d1a546cSKirti Wankhede *buf = (u8)mdev_state->s[index].divisor; 4709d1a546cSKirti Wankhede break; 4719d1a546cSKirti Wankhede } 4729d1a546cSKirti Wankhede 4739d1a546cSKirti Wankhede mutex_lock(&mdev_state->rxtx_lock); 4749d1a546cSKirti Wankhede /* return data in tx buffer */ 4759d1a546cSKirti Wankhede if (mdev_state->s[index].rxtx.head != 4769d1a546cSKirti Wankhede mdev_state->s[index].rxtx.tail) { 4779d1a546cSKirti Wankhede *buf = mdev_state->s[index].rxtx.fifo[ 4789d1a546cSKirti Wankhede mdev_state->s[index].rxtx.tail]; 4799d1a546cSKirti Wankhede mdev_state->s[index].rxtx.count--; 4809d1a546cSKirti Wankhede CIRCULAR_BUF_INC_IDX(mdev_state->s[index].rxtx.tail); 4819d1a546cSKirti Wankhede } 4829d1a546cSKirti Wankhede 4839d1a546cSKirti Wankhede if (mdev_state->s[index].rxtx.head == 4849d1a546cSKirti Wankhede mdev_state->s[index].rxtx.tail) { 4859d1a546cSKirti Wankhede /* 4869d1a546cSKirti Wankhede * Trigger interrupt if tx buffer empty interrupt is 4879d1a546cSKirti Wankhede * enabled and fifo is empty 4889d1a546cSKirti Wankhede */ 4899d1a546cSKirti Wankhede #if defined(DEBUG_INTR) 4909d1a546cSKirti Wankhede pr_err("Serial port %d: Buffer Empty\n", index); 4919d1a546cSKirti Wankhede #endif 4929d1a546cSKirti Wankhede if (mdev_state->s[index].uart_reg[UART_IER] & 4939d1a546cSKirti Wankhede UART_IER_THRI) 494eee413e6SParav Pandit mtty_trigger_interrupt(mdev_state); 4959d1a546cSKirti Wankhede } 4969d1a546cSKirti Wankhede mutex_unlock(&mdev_state->rxtx_lock); 4979d1a546cSKirti Wankhede 4989d1a546cSKirti Wankhede break; 4999d1a546cSKirti Wankhede 5009d1a546cSKirti Wankhede case UART_IER: 5019d1a546cSKirti Wankhede if (mdev_state->s[index].dlab) { 5029d1a546cSKirti Wankhede *buf = (u8)(mdev_state->s[index].divisor >> 8); 5039d1a546cSKirti Wankhede break; 5049d1a546cSKirti Wankhede } 5059d1a546cSKirti Wankhede *buf = mdev_state->s[index].uart_reg[offset] & 0x0f; 5069d1a546cSKirti Wankhede break; 5079d1a546cSKirti Wankhede 5089d1a546cSKirti Wankhede case UART_IIR: 5099d1a546cSKirti Wankhede { 5109d1a546cSKirti Wankhede u8 ier = mdev_state->s[index].uart_reg[UART_IER]; 5119d1a546cSKirti Wankhede *buf = 0; 5129d1a546cSKirti Wankhede 5139d1a546cSKirti Wankhede mutex_lock(&mdev_state->rxtx_lock); 5149d1a546cSKirti Wankhede /* Interrupt priority 1: Parity, overrun, framing or break */ 5159d1a546cSKirti Wankhede if ((ier & UART_IER_RLSI) && mdev_state->s[index].overrun) 5169d1a546cSKirti Wankhede *buf |= UART_IIR_RLSI; 5179d1a546cSKirti Wankhede 5189d1a546cSKirti Wankhede /* Interrupt priority 2: Fifo trigger level reached */ 5199d1a546cSKirti Wankhede if ((ier & UART_IER_RDI) && 520c9f89c3fSShunyong Yang (mdev_state->s[index].rxtx.count >= 5219d1a546cSKirti Wankhede mdev_state->s[index].intr_trigger_level)) 5229d1a546cSKirti Wankhede *buf |= UART_IIR_RDI; 5239d1a546cSKirti Wankhede 5249d1a546cSKirti Wankhede /* Interrupt priotiry 3: transmitter holding register empty */ 5259d1a546cSKirti Wankhede if ((ier & UART_IER_THRI) && 5269d1a546cSKirti Wankhede (mdev_state->s[index].rxtx.head == 5279d1a546cSKirti Wankhede mdev_state->s[index].rxtx.tail)) 5289d1a546cSKirti Wankhede *buf |= UART_IIR_THRI; 5299d1a546cSKirti Wankhede 5309d1a546cSKirti Wankhede /* Interrupt priotiry 4: Modem status: CTS, DSR, RI or DCD */ 5319d1a546cSKirti Wankhede if ((ier & UART_IER_MSI) && 5329d1a546cSKirti Wankhede (mdev_state->s[index].uart_reg[UART_MCR] & 5339d1a546cSKirti Wankhede (UART_MCR_RTS | UART_MCR_DTR))) 5349d1a546cSKirti Wankhede *buf |= UART_IIR_MSI; 5359d1a546cSKirti Wankhede 5369d1a546cSKirti Wankhede /* bit0: 0=> interrupt pending, 1=> no interrupt is pending */ 5379d1a546cSKirti Wankhede if (*buf == 0) 5389d1a546cSKirti Wankhede *buf = UART_IIR_NO_INT; 5399d1a546cSKirti Wankhede 5409d1a546cSKirti Wankhede /* set bit 6 & 7 to be 16550 compatible */ 5419d1a546cSKirti Wankhede *buf |= 0xC0; 5429d1a546cSKirti Wankhede mutex_unlock(&mdev_state->rxtx_lock); 5439d1a546cSKirti Wankhede } 5449d1a546cSKirti Wankhede break; 5459d1a546cSKirti Wankhede 5469d1a546cSKirti Wankhede case UART_LCR: 5479d1a546cSKirti Wankhede case UART_MCR: 5489d1a546cSKirti Wankhede *buf = mdev_state->s[index].uart_reg[offset]; 5499d1a546cSKirti Wankhede break; 5509d1a546cSKirti Wankhede 5519d1a546cSKirti Wankhede case UART_LSR: 5529d1a546cSKirti Wankhede { 5539d1a546cSKirti Wankhede u8 lsr = 0; 5549d1a546cSKirti Wankhede 5559d1a546cSKirti Wankhede mutex_lock(&mdev_state->rxtx_lock); 5569d1a546cSKirti Wankhede /* atleast one char in FIFO */ 5579d1a546cSKirti Wankhede if (mdev_state->s[index].rxtx.head != 5589d1a546cSKirti Wankhede mdev_state->s[index].rxtx.tail) 5599d1a546cSKirti Wankhede lsr |= UART_LSR_DR; 5609d1a546cSKirti Wankhede 5619d1a546cSKirti Wankhede /* if FIFO overrun */ 5629d1a546cSKirti Wankhede if (mdev_state->s[index].overrun) 5639d1a546cSKirti Wankhede lsr |= UART_LSR_OE; 5649d1a546cSKirti Wankhede 5659d1a546cSKirti Wankhede /* transmit FIFO empty and tramsitter empty */ 5669d1a546cSKirti Wankhede if (mdev_state->s[index].rxtx.head == 5679d1a546cSKirti Wankhede mdev_state->s[index].rxtx.tail) 5689d1a546cSKirti Wankhede lsr |= UART_LSR_TEMT | UART_LSR_THRE; 5699d1a546cSKirti Wankhede 5709d1a546cSKirti Wankhede mutex_unlock(&mdev_state->rxtx_lock); 5719d1a546cSKirti Wankhede *buf = lsr; 5729d1a546cSKirti Wankhede break; 5739d1a546cSKirti Wankhede } 5749d1a546cSKirti Wankhede case UART_MSR: 5759d1a546cSKirti Wankhede *buf = UART_MSR_DSR | UART_MSR_DDSR | UART_MSR_DCD; 5769d1a546cSKirti Wankhede 5779d1a546cSKirti Wankhede mutex_lock(&mdev_state->rxtx_lock); 5789d1a546cSKirti Wankhede /* if AFE is 1 and FIFO have space, set CTS bit */ 5799d1a546cSKirti Wankhede if (mdev_state->s[index].uart_reg[UART_MCR] & 5809d1a546cSKirti Wankhede UART_MCR_AFE) { 5819d1a546cSKirti Wankhede if (mdev_state->s[index].rxtx.count < 5829d1a546cSKirti Wankhede mdev_state->s[index].max_fifo_size) 5839d1a546cSKirti Wankhede *buf |= UART_MSR_CTS | UART_MSR_DCTS; 5849d1a546cSKirti Wankhede } else 5859d1a546cSKirti Wankhede *buf |= UART_MSR_CTS | UART_MSR_DCTS; 5869d1a546cSKirti Wankhede mutex_unlock(&mdev_state->rxtx_lock); 5879d1a546cSKirti Wankhede 5889d1a546cSKirti Wankhede break; 5899d1a546cSKirti Wankhede 5909d1a546cSKirti Wankhede case UART_SCR: 5919d1a546cSKirti Wankhede *buf = mdev_state->s[index].uart_reg[offset]; 5929d1a546cSKirti Wankhede break; 5939d1a546cSKirti Wankhede 5949d1a546cSKirti Wankhede default: 5959d1a546cSKirti Wankhede break; 5969d1a546cSKirti Wankhede } 5979d1a546cSKirti Wankhede } 5989d1a546cSKirti Wankhede 5999d1a546cSKirti Wankhede static void mdev_read_base(struct mdev_state *mdev_state) 6009d1a546cSKirti Wankhede { 6019d1a546cSKirti Wankhede int index, pos; 6029d1a546cSKirti Wankhede u32 start_lo, start_hi; 6039d1a546cSKirti Wankhede u32 mem_type; 6049d1a546cSKirti Wankhede 6059d1a546cSKirti Wankhede pos = PCI_BASE_ADDRESS_0; 6069d1a546cSKirti Wankhede 6079d1a546cSKirti Wankhede for (index = 0; index <= VFIO_PCI_BAR5_REGION_INDEX; index++) { 6089d1a546cSKirti Wankhede 6099d1a546cSKirti Wankhede if (!mdev_state->region_info[index].size) 6109d1a546cSKirti Wankhede continue; 6119d1a546cSKirti Wankhede 6129d1a546cSKirti Wankhede start_lo = (*(u32 *)(mdev_state->vconfig + pos)) & 6139d1a546cSKirti Wankhede PCI_BASE_ADDRESS_MEM_MASK; 6149d1a546cSKirti Wankhede mem_type = (*(u32 *)(mdev_state->vconfig + pos)) & 6159d1a546cSKirti Wankhede PCI_BASE_ADDRESS_MEM_TYPE_MASK; 6169d1a546cSKirti Wankhede 6179d1a546cSKirti Wankhede switch (mem_type) { 6189d1a546cSKirti Wankhede case PCI_BASE_ADDRESS_MEM_TYPE_64: 6199d1a546cSKirti Wankhede start_hi = (*(u32 *)(mdev_state->vconfig + pos + 4)); 6209d1a546cSKirti Wankhede pos += 4; 6219d1a546cSKirti Wankhede break; 6229d1a546cSKirti Wankhede case PCI_BASE_ADDRESS_MEM_TYPE_32: 6239d1a546cSKirti Wankhede case PCI_BASE_ADDRESS_MEM_TYPE_1M: 6249d1a546cSKirti Wankhede /* 1M mem BAR treated as 32-bit BAR */ 6259d1a546cSKirti Wankhede default: 6269d1a546cSKirti Wankhede /* mem unknown type treated as 32-bit BAR */ 6279d1a546cSKirti Wankhede start_hi = 0; 6289d1a546cSKirti Wankhede break; 6299d1a546cSKirti Wankhede } 6309d1a546cSKirti Wankhede pos += 4; 6319d1a546cSKirti Wankhede mdev_state->region_info[index].start = ((u64)start_hi << 32) | 6329d1a546cSKirti Wankhede start_lo; 6339d1a546cSKirti Wankhede } 6349d1a546cSKirti Wankhede } 6359d1a546cSKirti Wankhede 63609177ac9SJason Gunthorpe static ssize_t mdev_access(struct mdev_state *mdev_state, u8 *buf, size_t count, 6379d1a546cSKirti Wankhede loff_t pos, bool is_write) 6389d1a546cSKirti Wankhede { 6399d1a546cSKirti Wankhede unsigned int index; 6409d1a546cSKirti Wankhede loff_t offset; 6419d1a546cSKirti Wankhede int ret = 0; 6429d1a546cSKirti Wankhede 64309177ac9SJason Gunthorpe if (!buf) 6449d1a546cSKirti Wankhede return -EINVAL; 6459d1a546cSKirti Wankhede 6469d1a546cSKirti Wankhede mutex_lock(&mdev_state->ops_lock); 6479d1a546cSKirti Wankhede 6489d1a546cSKirti Wankhede index = MTTY_VFIO_PCI_OFFSET_TO_INDEX(pos); 6499d1a546cSKirti Wankhede offset = pos & MTTY_VFIO_PCI_OFFSET_MASK; 6509d1a546cSKirti Wankhede switch (index) { 6519d1a546cSKirti Wankhede case VFIO_PCI_CONFIG_REGION_INDEX: 6529d1a546cSKirti Wankhede 6539d1a546cSKirti Wankhede #if defined(DEBUG) 6549d1a546cSKirti Wankhede pr_info("%s: PCI config space %s at offset 0x%llx\n", 6559d1a546cSKirti Wankhede __func__, is_write ? "write" : "read", offset); 6569d1a546cSKirti Wankhede #endif 6579d1a546cSKirti Wankhede if (is_write) { 6589d1a546cSKirti Wankhede dump_buffer(buf, count); 6599d1a546cSKirti Wankhede handle_pci_cfg_write(mdev_state, offset, buf, count); 6609d1a546cSKirti Wankhede } else { 6619d1a546cSKirti Wankhede memcpy(buf, (mdev_state->vconfig + offset), count); 6629d1a546cSKirti Wankhede dump_buffer(buf, count); 6639d1a546cSKirti Wankhede } 6649d1a546cSKirti Wankhede 6659d1a546cSKirti Wankhede break; 6669d1a546cSKirti Wankhede 6679d1a546cSKirti Wankhede case VFIO_PCI_BAR0_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX: 6689d1a546cSKirti Wankhede if (!mdev_state->region_info[index].start) 6699d1a546cSKirti Wankhede mdev_read_base(mdev_state); 6709d1a546cSKirti Wankhede 6719d1a546cSKirti Wankhede if (is_write) { 6729d1a546cSKirti Wankhede dump_buffer(buf, count); 6739d1a546cSKirti Wankhede 6749d1a546cSKirti Wankhede #if defined(DEBUG_REGS) 6759d1a546cSKirti Wankhede pr_info("%s: BAR%d WR @0x%llx %s val:0x%02x dlab:%d\n", 6769d1a546cSKirti Wankhede __func__, index, offset, wr_reg[offset], 6778ba35b3aSNathan Chancellor *buf, mdev_state->s[index].dlab); 6789d1a546cSKirti Wankhede #endif 6799d1a546cSKirti Wankhede handle_bar_write(index, mdev_state, offset, buf, count); 6809d1a546cSKirti Wankhede } else { 6819d1a546cSKirti Wankhede handle_bar_read(index, mdev_state, offset, buf, count); 6829d1a546cSKirti Wankhede dump_buffer(buf, count); 6839d1a546cSKirti Wankhede 6849d1a546cSKirti Wankhede #if defined(DEBUG_REGS) 6859d1a546cSKirti Wankhede pr_info("%s: BAR%d RD @0x%llx %s val:0x%02x dlab:%d\n", 6869d1a546cSKirti Wankhede __func__, index, offset, rd_reg[offset], 6878ba35b3aSNathan Chancellor *buf, mdev_state->s[index].dlab); 6889d1a546cSKirti Wankhede #endif 6899d1a546cSKirti Wankhede } 6909d1a546cSKirti Wankhede break; 6919d1a546cSKirti Wankhede 6929d1a546cSKirti Wankhede default: 6939d1a546cSKirti Wankhede ret = -1; 6949d1a546cSKirti Wankhede goto accessfailed; 6959d1a546cSKirti Wankhede } 6969d1a546cSKirti Wankhede 6979d1a546cSKirti Wankhede ret = count; 6989d1a546cSKirti Wankhede 6999d1a546cSKirti Wankhede 7009d1a546cSKirti Wankhede accessfailed: 7019d1a546cSKirti Wankhede mutex_unlock(&mdev_state->ops_lock); 7029d1a546cSKirti Wankhede 7039d1a546cSKirti Wankhede return ret; 7049d1a546cSKirti Wankhede } 7059d1a546cSKirti Wankhede 706*67c5a181SYi Liu static int mtty_init_dev(struct vfio_device *vdev) 7079d1a546cSKirti Wankhede { 708*67c5a181SYi Liu struct mdev_state *mdev_state = 709*67c5a181SYi Liu container_of(vdev, struct mdev_state, vdev); 710*67c5a181SYi Liu struct mdev_device *mdev = to_mdev_device(vdev->dev); 711c594b26fSJason Gunthorpe int nr_ports = mdev_get_type_group_id(mdev) + 1; 71297d0a687SAlex Williamson int avail_ports = atomic_read(&mdev_avail_ports); 71309177ac9SJason Gunthorpe int ret; 7149d1a546cSKirti Wankhede 71597d0a687SAlex Williamson do { 71697d0a687SAlex Williamson if (avail_ports < nr_ports) 71797d0a687SAlex Williamson return -ENOSPC; 71897d0a687SAlex Williamson } while (!atomic_try_cmpxchg(&mdev_avail_ports, 71997d0a687SAlex Williamson &avail_ports, avail_ports - nr_ports)); 72097d0a687SAlex Williamson 7219d1a546cSKirti Wankhede mdev_state->nr_ports = nr_ports; 7229d1a546cSKirti Wankhede mdev_state->irq_index = -1; 7239d1a546cSKirti Wankhede mdev_state->s[0].max_fifo_size = MAX_FIFO_SIZE; 7249d1a546cSKirti Wankhede mdev_state->s[1].max_fifo_size = MAX_FIFO_SIZE; 7259d1a546cSKirti Wankhede mutex_init(&mdev_state->rxtx_lock); 7269d1a546cSKirti Wankhede 727*67c5a181SYi Liu mdev_state->vconfig = kzalloc(MTTY_CONFIG_SPACE_SIZE, GFP_KERNEL); 728*67c5a181SYi Liu if (!mdev_state->vconfig) { 729ae03c377SMax Gurtovoy ret = -ENOMEM; 730*67c5a181SYi Liu goto err_nr_ports; 7319d1a546cSKirti Wankhede } 7329d1a546cSKirti Wankhede 7339d1a546cSKirti Wankhede mutex_init(&mdev_state->ops_lock); 7349d1a546cSKirti Wankhede mdev_state->mdev = mdev; 7359d1a546cSKirti Wankhede mtty_create_config_space(mdev_state); 7369d1a546cSKirti Wankhede return 0; 737ae03c377SMax Gurtovoy 738ae03c377SMax Gurtovoy err_nr_ports: 739ae03c377SMax Gurtovoy atomic_add(nr_ports, &mdev_avail_ports); 740ae03c377SMax Gurtovoy return ret; 7419d1a546cSKirti Wankhede } 7429d1a546cSKirti Wankhede 743*67c5a181SYi Liu static int mtty_probe(struct mdev_device *mdev) 744*67c5a181SYi Liu { 745*67c5a181SYi Liu struct mdev_state *mdev_state; 746*67c5a181SYi Liu int ret; 747*67c5a181SYi Liu 748*67c5a181SYi Liu mdev_state = vfio_alloc_device(mdev_state, vdev, &mdev->dev, 749*67c5a181SYi Liu &mtty_dev_ops); 750*67c5a181SYi Liu if (IS_ERR(mdev_state)) 751*67c5a181SYi Liu return PTR_ERR(mdev_state); 752*67c5a181SYi Liu 753*67c5a181SYi Liu ret = vfio_register_emulated_iommu_dev(&mdev_state->vdev); 754*67c5a181SYi Liu if (ret) 755*67c5a181SYi Liu goto err_put_vdev; 756*67c5a181SYi Liu dev_set_drvdata(&mdev->dev, mdev_state); 757*67c5a181SYi Liu return 0; 758*67c5a181SYi Liu 759*67c5a181SYi Liu err_put_vdev: 760*67c5a181SYi Liu vfio_put_device(&mdev_state->vdev); 761*67c5a181SYi Liu return ret; 762*67c5a181SYi Liu } 763*67c5a181SYi Liu 764*67c5a181SYi Liu static void mtty_release_dev(struct vfio_device *vdev) 765*67c5a181SYi Liu { 766*67c5a181SYi Liu struct mdev_state *mdev_state = 767*67c5a181SYi Liu container_of(vdev, struct mdev_state, vdev); 768*67c5a181SYi Liu 769*67c5a181SYi Liu atomic_add(mdev_state->nr_ports, &mdev_avail_ports); 770*67c5a181SYi Liu kfree(mdev_state->vconfig); 771*67c5a181SYi Liu vfio_free_device(vdev); 772*67c5a181SYi Liu } 773*67c5a181SYi Liu 77409177ac9SJason Gunthorpe static void mtty_remove(struct mdev_device *mdev) 7759d1a546cSKirti Wankhede { 77609177ac9SJason Gunthorpe struct mdev_state *mdev_state = dev_get_drvdata(&mdev->dev); 7779d1a546cSKirti Wankhede 77809177ac9SJason Gunthorpe vfio_unregister_group_dev(&mdev_state->vdev); 779*67c5a181SYi Liu vfio_put_device(&mdev_state->vdev); 7809d1a546cSKirti Wankhede } 7819d1a546cSKirti Wankhede 78209177ac9SJason Gunthorpe static int mtty_reset(struct mdev_state *mdev_state) 7839d1a546cSKirti Wankhede { 7849d1a546cSKirti Wankhede pr_info("%s: called\n", __func__); 7859d1a546cSKirti Wankhede 7869d1a546cSKirti Wankhede return 0; 7879d1a546cSKirti Wankhede } 7889d1a546cSKirti Wankhede 78909177ac9SJason Gunthorpe static ssize_t mtty_read(struct vfio_device *vdev, char __user *buf, 7904b2dbd56SKefeng Wang size_t count, loff_t *ppos) 7919d1a546cSKirti Wankhede { 79209177ac9SJason Gunthorpe struct mdev_state *mdev_state = 79309177ac9SJason Gunthorpe container_of(vdev, struct mdev_state, vdev); 7949d1a546cSKirti Wankhede unsigned int done = 0; 7959d1a546cSKirti Wankhede int ret; 7969d1a546cSKirti Wankhede 7979d1a546cSKirti Wankhede while (count) { 7989d1a546cSKirti Wankhede size_t filled; 7999d1a546cSKirti Wankhede 8009d1a546cSKirti Wankhede if (count >= 4 && !(*ppos % 4)) { 8019d1a546cSKirti Wankhede u32 val; 8029d1a546cSKirti Wankhede 80309177ac9SJason Gunthorpe ret = mdev_access(mdev_state, (u8 *)&val, sizeof(val), 8049d1a546cSKirti Wankhede *ppos, false); 8059d1a546cSKirti Wankhede if (ret <= 0) 8069d1a546cSKirti Wankhede goto read_err; 8079d1a546cSKirti Wankhede 8089d1a546cSKirti Wankhede if (copy_to_user(buf, &val, sizeof(val))) 8099d1a546cSKirti Wankhede goto read_err; 8109d1a546cSKirti Wankhede 8119d1a546cSKirti Wankhede filled = 4; 8129d1a546cSKirti Wankhede } else if (count >= 2 && !(*ppos % 2)) { 8139d1a546cSKirti Wankhede u16 val; 8149d1a546cSKirti Wankhede 81509177ac9SJason Gunthorpe ret = mdev_access(mdev_state, (u8 *)&val, sizeof(val), 8169d1a546cSKirti Wankhede *ppos, false); 8179d1a546cSKirti Wankhede if (ret <= 0) 8189d1a546cSKirti Wankhede goto read_err; 8199d1a546cSKirti Wankhede 8209d1a546cSKirti Wankhede if (copy_to_user(buf, &val, sizeof(val))) 8219d1a546cSKirti Wankhede goto read_err; 8229d1a546cSKirti Wankhede 8239d1a546cSKirti Wankhede filled = 2; 8249d1a546cSKirti Wankhede } else { 8259d1a546cSKirti Wankhede u8 val; 8269d1a546cSKirti Wankhede 82709177ac9SJason Gunthorpe ret = mdev_access(mdev_state, (u8 *)&val, sizeof(val), 8289d1a546cSKirti Wankhede *ppos, false); 8299d1a546cSKirti Wankhede if (ret <= 0) 8309d1a546cSKirti Wankhede goto read_err; 8319d1a546cSKirti Wankhede 8329d1a546cSKirti Wankhede if (copy_to_user(buf, &val, sizeof(val))) 8339d1a546cSKirti Wankhede goto read_err; 8349d1a546cSKirti Wankhede 8359d1a546cSKirti Wankhede filled = 1; 8369d1a546cSKirti Wankhede } 8379d1a546cSKirti Wankhede 8389d1a546cSKirti Wankhede count -= filled; 8399d1a546cSKirti Wankhede done += filled; 8409d1a546cSKirti Wankhede *ppos += filled; 8419d1a546cSKirti Wankhede buf += filled; 8429d1a546cSKirti Wankhede } 8439d1a546cSKirti Wankhede 8449d1a546cSKirti Wankhede return done; 8459d1a546cSKirti Wankhede 8469d1a546cSKirti Wankhede read_err: 8479d1a546cSKirti Wankhede return -EFAULT; 8489d1a546cSKirti Wankhede } 8499d1a546cSKirti Wankhede 85009177ac9SJason Gunthorpe static ssize_t mtty_write(struct vfio_device *vdev, const char __user *buf, 8519d1a546cSKirti Wankhede size_t count, loff_t *ppos) 8529d1a546cSKirti Wankhede { 85309177ac9SJason Gunthorpe struct mdev_state *mdev_state = 85409177ac9SJason Gunthorpe container_of(vdev, struct mdev_state, vdev); 8559d1a546cSKirti Wankhede unsigned int done = 0; 8569d1a546cSKirti Wankhede int ret; 8579d1a546cSKirti Wankhede 8589d1a546cSKirti Wankhede while (count) { 8599d1a546cSKirti Wankhede size_t filled; 8609d1a546cSKirti Wankhede 8619d1a546cSKirti Wankhede if (count >= 4 && !(*ppos % 4)) { 8629d1a546cSKirti Wankhede u32 val; 8639d1a546cSKirti Wankhede 8649d1a546cSKirti Wankhede if (copy_from_user(&val, buf, sizeof(val))) 8659d1a546cSKirti Wankhede goto write_err; 8669d1a546cSKirti Wankhede 86709177ac9SJason Gunthorpe ret = mdev_access(mdev_state, (u8 *)&val, sizeof(val), 8689d1a546cSKirti Wankhede *ppos, true); 8699d1a546cSKirti Wankhede if (ret <= 0) 8709d1a546cSKirti Wankhede goto write_err; 8719d1a546cSKirti Wankhede 8729d1a546cSKirti Wankhede filled = 4; 8739d1a546cSKirti Wankhede } else if (count >= 2 && !(*ppos % 2)) { 8749d1a546cSKirti Wankhede u16 val; 8759d1a546cSKirti Wankhede 8769d1a546cSKirti Wankhede if (copy_from_user(&val, buf, sizeof(val))) 8779d1a546cSKirti Wankhede goto write_err; 8789d1a546cSKirti Wankhede 87909177ac9SJason Gunthorpe ret = mdev_access(mdev_state, (u8 *)&val, sizeof(val), 8809d1a546cSKirti Wankhede *ppos, true); 8819d1a546cSKirti Wankhede if (ret <= 0) 8829d1a546cSKirti Wankhede goto write_err; 8839d1a546cSKirti Wankhede 8849d1a546cSKirti Wankhede filled = 2; 8859d1a546cSKirti Wankhede } else { 8869d1a546cSKirti Wankhede u8 val; 8879d1a546cSKirti Wankhede 8889d1a546cSKirti Wankhede if (copy_from_user(&val, buf, sizeof(val))) 8899d1a546cSKirti Wankhede goto write_err; 8909d1a546cSKirti Wankhede 89109177ac9SJason Gunthorpe ret = mdev_access(mdev_state, (u8 *)&val, sizeof(val), 8929d1a546cSKirti Wankhede *ppos, true); 8939d1a546cSKirti Wankhede if (ret <= 0) 8949d1a546cSKirti Wankhede goto write_err; 8959d1a546cSKirti Wankhede 8969d1a546cSKirti Wankhede filled = 1; 8979d1a546cSKirti Wankhede } 8989d1a546cSKirti Wankhede count -= filled; 8999d1a546cSKirti Wankhede done += filled; 9009d1a546cSKirti Wankhede *ppos += filled; 9019d1a546cSKirti Wankhede buf += filled; 9029d1a546cSKirti Wankhede } 9039d1a546cSKirti Wankhede 9049d1a546cSKirti Wankhede return done; 9059d1a546cSKirti Wankhede write_err: 9069d1a546cSKirti Wankhede return -EFAULT; 9079d1a546cSKirti Wankhede } 9089d1a546cSKirti Wankhede 90909177ac9SJason Gunthorpe static int mtty_set_irqs(struct mdev_state *mdev_state, uint32_t flags, 9109d1a546cSKirti Wankhede unsigned int index, unsigned int start, 9119d1a546cSKirti Wankhede unsigned int count, void *data) 9129d1a546cSKirti Wankhede { 9139d1a546cSKirti Wankhede int ret = 0; 9149d1a546cSKirti Wankhede 9159d1a546cSKirti Wankhede mutex_lock(&mdev_state->ops_lock); 9169d1a546cSKirti Wankhede switch (index) { 9179d1a546cSKirti Wankhede case VFIO_PCI_INTX_IRQ_INDEX: 9189d1a546cSKirti Wankhede switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) { 9199d1a546cSKirti Wankhede case VFIO_IRQ_SET_ACTION_MASK: 9209d1a546cSKirti Wankhede case VFIO_IRQ_SET_ACTION_UNMASK: 9219d1a546cSKirti Wankhede break; 9229d1a546cSKirti Wankhede case VFIO_IRQ_SET_ACTION_TRIGGER: 9239d1a546cSKirti Wankhede { 9249d1a546cSKirti Wankhede if (flags & VFIO_IRQ_SET_DATA_NONE) { 9259d1a546cSKirti Wankhede pr_info("%s: disable INTx\n", __func__); 9269d1a546cSKirti Wankhede if (mdev_state->intx_evtfd) 9279d1a546cSKirti Wankhede eventfd_ctx_put(mdev_state->intx_evtfd); 9289d1a546cSKirti Wankhede break; 9299d1a546cSKirti Wankhede } 9309d1a546cSKirti Wankhede 9319d1a546cSKirti Wankhede if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { 9329d1a546cSKirti Wankhede int fd = *(int *)data; 9339d1a546cSKirti Wankhede 9349d1a546cSKirti Wankhede if (fd > 0) { 9359d1a546cSKirti Wankhede struct eventfd_ctx *evt; 9369d1a546cSKirti Wankhede 9379d1a546cSKirti Wankhede evt = eventfd_ctx_fdget(fd); 9389d1a546cSKirti Wankhede if (IS_ERR(evt)) { 9399d1a546cSKirti Wankhede ret = PTR_ERR(evt); 9409d1a546cSKirti Wankhede break; 9419d1a546cSKirti Wankhede } 9429d1a546cSKirti Wankhede mdev_state->intx_evtfd = evt; 9439d1a546cSKirti Wankhede mdev_state->irq_fd = fd; 9449d1a546cSKirti Wankhede mdev_state->irq_index = index; 9459d1a546cSKirti Wankhede break; 9469d1a546cSKirti Wankhede } 9479d1a546cSKirti Wankhede } 9489d1a546cSKirti Wankhede break; 9499d1a546cSKirti Wankhede } 9509d1a546cSKirti Wankhede } 9519d1a546cSKirti Wankhede break; 9529d1a546cSKirti Wankhede case VFIO_PCI_MSI_IRQ_INDEX: 9539d1a546cSKirti Wankhede switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) { 9549d1a546cSKirti Wankhede case VFIO_IRQ_SET_ACTION_MASK: 9559d1a546cSKirti Wankhede case VFIO_IRQ_SET_ACTION_UNMASK: 9569d1a546cSKirti Wankhede break; 9579d1a546cSKirti Wankhede case VFIO_IRQ_SET_ACTION_TRIGGER: 9589d1a546cSKirti Wankhede if (flags & VFIO_IRQ_SET_DATA_NONE) { 9599d1a546cSKirti Wankhede if (mdev_state->msi_evtfd) 9609d1a546cSKirti Wankhede eventfd_ctx_put(mdev_state->msi_evtfd); 9619d1a546cSKirti Wankhede pr_info("%s: disable MSI\n", __func__); 9629d1a546cSKirti Wankhede mdev_state->irq_index = VFIO_PCI_INTX_IRQ_INDEX; 9639d1a546cSKirti Wankhede break; 9649d1a546cSKirti Wankhede } 9659d1a546cSKirti Wankhede if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { 9669d1a546cSKirti Wankhede int fd = *(int *)data; 9679d1a546cSKirti Wankhede struct eventfd_ctx *evt; 9689d1a546cSKirti Wankhede 9699d1a546cSKirti Wankhede if (fd <= 0) 9709d1a546cSKirti Wankhede break; 9719d1a546cSKirti Wankhede 9729d1a546cSKirti Wankhede if (mdev_state->msi_evtfd) 9739d1a546cSKirti Wankhede break; 9749d1a546cSKirti Wankhede 9759d1a546cSKirti Wankhede evt = eventfd_ctx_fdget(fd); 9769d1a546cSKirti Wankhede if (IS_ERR(evt)) { 9779d1a546cSKirti Wankhede ret = PTR_ERR(evt); 9789d1a546cSKirti Wankhede break; 9799d1a546cSKirti Wankhede } 9809d1a546cSKirti Wankhede mdev_state->msi_evtfd = evt; 9819d1a546cSKirti Wankhede mdev_state->irq_fd = fd; 9829d1a546cSKirti Wankhede mdev_state->irq_index = index; 9839d1a546cSKirti Wankhede } 9849d1a546cSKirti Wankhede break; 9859d1a546cSKirti Wankhede } 9869d1a546cSKirti Wankhede break; 9879d1a546cSKirti Wankhede case VFIO_PCI_MSIX_IRQ_INDEX: 9889d1a546cSKirti Wankhede pr_info("%s: MSIX_IRQ\n", __func__); 9899d1a546cSKirti Wankhede break; 9909d1a546cSKirti Wankhede case VFIO_PCI_ERR_IRQ_INDEX: 9919d1a546cSKirti Wankhede pr_info("%s: ERR_IRQ\n", __func__); 9929d1a546cSKirti Wankhede break; 9939d1a546cSKirti Wankhede case VFIO_PCI_REQ_IRQ_INDEX: 9949d1a546cSKirti Wankhede pr_info("%s: REQ_IRQ\n", __func__); 9959d1a546cSKirti Wankhede break; 9969d1a546cSKirti Wankhede } 9979d1a546cSKirti Wankhede 9989d1a546cSKirti Wankhede mutex_unlock(&mdev_state->ops_lock); 9999d1a546cSKirti Wankhede return ret; 10009d1a546cSKirti Wankhede } 10019d1a546cSKirti Wankhede 1002eee413e6SParav Pandit static int mtty_trigger_interrupt(struct mdev_state *mdev_state) 10039d1a546cSKirti Wankhede { 10049d1a546cSKirti Wankhede int ret = -1; 10059d1a546cSKirti Wankhede 10069d1a546cSKirti Wankhede if ((mdev_state->irq_index == VFIO_PCI_MSI_IRQ_INDEX) && 10079d1a546cSKirti Wankhede (!mdev_state->msi_evtfd)) 10089d1a546cSKirti Wankhede return -EINVAL; 10099d1a546cSKirti Wankhede else if ((mdev_state->irq_index == VFIO_PCI_INTX_IRQ_INDEX) && 10109d1a546cSKirti Wankhede (!mdev_state->intx_evtfd)) { 10119d1a546cSKirti Wankhede pr_info("%s: Intr eventfd not found\n", __func__); 10129d1a546cSKirti Wankhede return -EINVAL; 10139d1a546cSKirti Wankhede } 10149d1a546cSKirti Wankhede 10159d1a546cSKirti Wankhede if (mdev_state->irq_index == VFIO_PCI_MSI_IRQ_INDEX) 10169d1a546cSKirti Wankhede ret = eventfd_signal(mdev_state->msi_evtfd, 1); 10179d1a546cSKirti Wankhede else 10189d1a546cSKirti Wankhede ret = eventfd_signal(mdev_state->intx_evtfd, 1); 10199d1a546cSKirti Wankhede 10209d1a546cSKirti Wankhede #if defined(DEBUG_INTR) 10219d1a546cSKirti Wankhede pr_info("Intx triggered\n"); 10229d1a546cSKirti Wankhede #endif 10239d1a546cSKirti Wankhede if (ret != 1) 10249d1a546cSKirti Wankhede pr_err("%s: eventfd signal failed (%d)\n", __func__, ret); 10259d1a546cSKirti Wankhede 10269d1a546cSKirti Wankhede return ret; 10279d1a546cSKirti Wankhede } 10289d1a546cSKirti Wankhede 102909177ac9SJason Gunthorpe static int mtty_get_region_info(struct mdev_state *mdev_state, 10309d1a546cSKirti Wankhede struct vfio_region_info *region_info, 10319d1a546cSKirti Wankhede u16 *cap_type_id, void **cap_type) 10329d1a546cSKirti Wankhede { 10339d1a546cSKirti Wankhede unsigned int size = 0; 10345c677869SDan Carpenter u32 bar_index; 10359d1a546cSKirti Wankhede 10369d1a546cSKirti Wankhede bar_index = region_info->index; 10375c677869SDan Carpenter if (bar_index >= VFIO_PCI_NUM_REGIONS) 10385c677869SDan Carpenter return -EINVAL; 10395c677869SDan Carpenter 10405c677869SDan Carpenter mutex_lock(&mdev_state->ops_lock); 10419d1a546cSKirti Wankhede 10429d1a546cSKirti Wankhede switch (bar_index) { 10439d1a546cSKirti Wankhede case VFIO_PCI_CONFIG_REGION_INDEX: 10449d1a546cSKirti Wankhede size = MTTY_CONFIG_SPACE_SIZE; 10459d1a546cSKirti Wankhede break; 10469d1a546cSKirti Wankhede case VFIO_PCI_BAR0_REGION_INDEX: 10479d1a546cSKirti Wankhede size = MTTY_IO_BAR_SIZE; 10489d1a546cSKirti Wankhede break; 10499d1a546cSKirti Wankhede case VFIO_PCI_BAR1_REGION_INDEX: 10509d1a546cSKirti Wankhede if (mdev_state->nr_ports == 2) 10519d1a546cSKirti Wankhede size = MTTY_IO_BAR_SIZE; 10529d1a546cSKirti Wankhede break; 10539d1a546cSKirti Wankhede default: 10549d1a546cSKirti Wankhede size = 0; 10559d1a546cSKirti Wankhede break; 10569d1a546cSKirti Wankhede } 10579d1a546cSKirti Wankhede 10589d1a546cSKirti Wankhede mdev_state->region_info[bar_index].size = size; 10599d1a546cSKirti Wankhede mdev_state->region_info[bar_index].vfio_offset = 10609d1a546cSKirti Wankhede MTTY_VFIO_PCI_INDEX_TO_OFFSET(bar_index); 10619d1a546cSKirti Wankhede 10629d1a546cSKirti Wankhede region_info->size = size; 10639d1a546cSKirti Wankhede region_info->offset = MTTY_VFIO_PCI_INDEX_TO_OFFSET(bar_index); 10649d1a546cSKirti Wankhede region_info->flags = VFIO_REGION_INFO_FLAG_READ | 10659d1a546cSKirti Wankhede VFIO_REGION_INFO_FLAG_WRITE; 10669d1a546cSKirti Wankhede mutex_unlock(&mdev_state->ops_lock); 10679d1a546cSKirti Wankhede return 0; 10689d1a546cSKirti Wankhede } 10699d1a546cSKirti Wankhede 107009177ac9SJason Gunthorpe static int mtty_get_irq_info(struct vfio_irq_info *irq_info) 10719d1a546cSKirti Wankhede { 10729d1a546cSKirti Wankhede switch (irq_info->index) { 10739d1a546cSKirti Wankhede case VFIO_PCI_INTX_IRQ_INDEX: 10749d1a546cSKirti Wankhede case VFIO_PCI_MSI_IRQ_INDEX: 10759d1a546cSKirti Wankhede case VFIO_PCI_REQ_IRQ_INDEX: 10769d1a546cSKirti Wankhede break; 10779d1a546cSKirti Wankhede 10789d1a546cSKirti Wankhede default: 10799d1a546cSKirti Wankhede return -EINVAL; 10809d1a546cSKirti Wankhede } 10819d1a546cSKirti Wankhede 10829d1a546cSKirti Wankhede irq_info->flags = VFIO_IRQ_INFO_EVENTFD; 10839d1a546cSKirti Wankhede irq_info->count = 1; 10849d1a546cSKirti Wankhede 10859d1a546cSKirti Wankhede if (irq_info->index == VFIO_PCI_INTX_IRQ_INDEX) 10869d1a546cSKirti Wankhede irq_info->flags |= (VFIO_IRQ_INFO_MASKABLE | 10879d1a546cSKirti Wankhede VFIO_IRQ_INFO_AUTOMASKED); 10889d1a546cSKirti Wankhede else 10899d1a546cSKirti Wankhede irq_info->flags |= VFIO_IRQ_INFO_NORESIZE; 10909d1a546cSKirti Wankhede 10919d1a546cSKirti Wankhede return 0; 10929d1a546cSKirti Wankhede } 10939d1a546cSKirti Wankhede 109409177ac9SJason Gunthorpe static int mtty_get_device_info(struct vfio_device_info *dev_info) 10959d1a546cSKirti Wankhede { 10969d1a546cSKirti Wankhede dev_info->flags = VFIO_DEVICE_FLAGS_PCI; 10979d1a546cSKirti Wankhede dev_info->num_regions = VFIO_PCI_NUM_REGIONS; 10989d1a546cSKirti Wankhede dev_info->num_irqs = VFIO_PCI_NUM_IRQS; 10999d1a546cSKirti Wankhede 11009d1a546cSKirti Wankhede return 0; 11019d1a546cSKirti Wankhede } 11029d1a546cSKirti Wankhede 110309177ac9SJason Gunthorpe static long mtty_ioctl(struct vfio_device *vdev, unsigned int cmd, 11049d1a546cSKirti Wankhede unsigned long arg) 11059d1a546cSKirti Wankhede { 110609177ac9SJason Gunthorpe struct mdev_state *mdev_state = 110709177ac9SJason Gunthorpe container_of(vdev, struct mdev_state, vdev); 11089d1a546cSKirti Wankhede int ret = 0; 11099d1a546cSKirti Wankhede unsigned long minsz; 11109d1a546cSKirti Wankhede 11119d1a546cSKirti Wankhede switch (cmd) { 11129d1a546cSKirti Wankhede case VFIO_DEVICE_GET_INFO: 11139d1a546cSKirti Wankhede { 11149d1a546cSKirti Wankhede struct vfio_device_info info; 11159d1a546cSKirti Wankhede 11169d1a546cSKirti Wankhede minsz = offsetofend(struct vfio_device_info, num_irqs); 11179d1a546cSKirti Wankhede 11189d1a546cSKirti Wankhede if (copy_from_user(&info, (void __user *)arg, minsz)) 11199d1a546cSKirti Wankhede return -EFAULT; 11209d1a546cSKirti Wankhede 11219d1a546cSKirti Wankhede if (info.argsz < minsz) 11229d1a546cSKirti Wankhede return -EINVAL; 11239d1a546cSKirti Wankhede 112409177ac9SJason Gunthorpe ret = mtty_get_device_info(&info); 11259d1a546cSKirti Wankhede if (ret) 11269d1a546cSKirti Wankhede return ret; 11279d1a546cSKirti Wankhede 11289d1a546cSKirti Wankhede memcpy(&mdev_state->dev_info, &info, sizeof(info)); 11299d1a546cSKirti Wankhede 11306ed0993aSDan Carpenter if (copy_to_user((void __user *)arg, &info, minsz)) 11316ed0993aSDan Carpenter return -EFAULT; 11326ed0993aSDan Carpenter 11336ed0993aSDan Carpenter return 0; 11349d1a546cSKirti Wankhede } 11359d1a546cSKirti Wankhede case VFIO_DEVICE_GET_REGION_INFO: 11369d1a546cSKirti Wankhede { 11379d1a546cSKirti Wankhede struct vfio_region_info info; 11389d1a546cSKirti Wankhede u16 cap_type_id = 0; 11399d1a546cSKirti Wankhede void *cap_type = NULL; 11409d1a546cSKirti Wankhede 11419d1a546cSKirti Wankhede minsz = offsetofend(struct vfio_region_info, offset); 11429d1a546cSKirti Wankhede 11439d1a546cSKirti Wankhede if (copy_from_user(&info, (void __user *)arg, minsz)) 11449d1a546cSKirti Wankhede return -EFAULT; 11459d1a546cSKirti Wankhede 11469d1a546cSKirti Wankhede if (info.argsz < minsz) 11479d1a546cSKirti Wankhede return -EINVAL; 11489d1a546cSKirti Wankhede 114909177ac9SJason Gunthorpe ret = mtty_get_region_info(mdev_state, &info, &cap_type_id, 11509d1a546cSKirti Wankhede &cap_type); 11519d1a546cSKirti Wankhede if (ret) 11529d1a546cSKirti Wankhede return ret; 11539d1a546cSKirti Wankhede 11546ed0993aSDan Carpenter if (copy_to_user((void __user *)arg, &info, minsz)) 11556ed0993aSDan Carpenter return -EFAULT; 11566ed0993aSDan Carpenter 11576ed0993aSDan Carpenter return 0; 11589d1a546cSKirti Wankhede } 11599d1a546cSKirti Wankhede 11609d1a546cSKirti Wankhede case VFIO_DEVICE_GET_IRQ_INFO: 11619d1a546cSKirti Wankhede { 11629d1a546cSKirti Wankhede struct vfio_irq_info info; 11639d1a546cSKirti Wankhede 11649d1a546cSKirti Wankhede minsz = offsetofend(struct vfio_irq_info, count); 11659d1a546cSKirti Wankhede 11669d1a546cSKirti Wankhede if (copy_from_user(&info, (void __user *)arg, minsz)) 11679d1a546cSKirti Wankhede return -EFAULT; 11689d1a546cSKirti Wankhede 11699d1a546cSKirti Wankhede if ((info.argsz < minsz) || 11709d1a546cSKirti Wankhede (info.index >= mdev_state->dev_info.num_irqs)) 11719d1a546cSKirti Wankhede return -EINVAL; 11729d1a546cSKirti Wankhede 117309177ac9SJason Gunthorpe ret = mtty_get_irq_info(&info); 11749d1a546cSKirti Wankhede if (ret) 11759d1a546cSKirti Wankhede return ret; 11769d1a546cSKirti Wankhede 11776ed0993aSDan Carpenter if (copy_to_user((void __user *)arg, &info, minsz)) 11786ed0993aSDan Carpenter return -EFAULT; 11796ed0993aSDan Carpenter 11806ed0993aSDan Carpenter return 0; 11819d1a546cSKirti Wankhede } 11829d1a546cSKirti Wankhede case VFIO_DEVICE_SET_IRQS: 11839d1a546cSKirti Wankhede { 11849d1a546cSKirti Wankhede struct vfio_irq_set hdr; 11859d1a546cSKirti Wankhede u8 *data = NULL, *ptr = NULL; 11869d1a546cSKirti Wankhede size_t data_size = 0; 11879d1a546cSKirti Wankhede 11889d1a546cSKirti Wankhede minsz = offsetofend(struct vfio_irq_set, count); 11899d1a546cSKirti Wankhede 11909d1a546cSKirti Wankhede if (copy_from_user(&hdr, (void __user *)arg, minsz)) 11919d1a546cSKirti Wankhede return -EFAULT; 11929d1a546cSKirti Wankhede 11939d1a546cSKirti Wankhede ret = vfio_set_irqs_validate_and_prepare(&hdr, 11949d1a546cSKirti Wankhede mdev_state->dev_info.num_irqs, 11959d1a546cSKirti Wankhede VFIO_PCI_NUM_IRQS, 11969d1a546cSKirti Wankhede &data_size); 11979d1a546cSKirti Wankhede if (ret) 11989d1a546cSKirti Wankhede return ret; 11999d1a546cSKirti Wankhede 12009d1a546cSKirti Wankhede if (data_size) { 12019d1a546cSKirti Wankhede ptr = data = memdup_user((void __user *)(arg + minsz), 12029d1a546cSKirti Wankhede data_size); 12039d1a546cSKirti Wankhede if (IS_ERR(data)) 12049d1a546cSKirti Wankhede return PTR_ERR(data); 12059d1a546cSKirti Wankhede } 12069d1a546cSKirti Wankhede 120709177ac9SJason Gunthorpe ret = mtty_set_irqs(mdev_state, hdr.flags, hdr.index, hdr.start, 12089d1a546cSKirti Wankhede hdr.count, data); 12099d1a546cSKirti Wankhede 12109d1a546cSKirti Wankhede kfree(ptr); 12119d1a546cSKirti Wankhede return ret; 12129d1a546cSKirti Wankhede } 12139d1a546cSKirti Wankhede case VFIO_DEVICE_RESET: 121409177ac9SJason Gunthorpe return mtty_reset(mdev_state); 12159d1a546cSKirti Wankhede } 12169d1a546cSKirti Wankhede return -ENOTTY; 12179d1a546cSKirti Wankhede } 12189d1a546cSKirti Wankhede 12199d1a546cSKirti Wankhede static ssize_t 12209d1a546cSKirti Wankhede sample_mdev_dev_show(struct device *dev, struct device_attribute *attr, 12219d1a546cSKirti Wankhede char *buf) 12229d1a546cSKirti Wankhede { 122399e3123eSAlex Williamson return sprintf(buf, "This is MDEV %s\n", dev_name(dev)); 12249d1a546cSKirti Wankhede } 12259d1a546cSKirti Wankhede 12269d1a546cSKirti Wankhede static DEVICE_ATTR_RO(sample_mdev_dev); 12279d1a546cSKirti Wankhede 12289d1a546cSKirti Wankhede static struct attribute *mdev_dev_attrs[] = { 12299d1a546cSKirti Wankhede &dev_attr_sample_mdev_dev.attr, 12309d1a546cSKirti Wankhede NULL, 12319d1a546cSKirti Wankhede }; 12329d1a546cSKirti Wankhede 12339d1a546cSKirti Wankhede static const struct attribute_group mdev_dev_group = { 12349d1a546cSKirti Wankhede .name = "vendor", 12359d1a546cSKirti Wankhede .attrs = mdev_dev_attrs, 12369d1a546cSKirti Wankhede }; 12379d1a546cSKirti Wankhede 12384b2dbd56SKefeng Wang static const struct attribute_group *mdev_dev_groups[] = { 12399d1a546cSKirti Wankhede &mdev_dev_group, 12409d1a546cSKirti Wankhede NULL, 12419d1a546cSKirti Wankhede }; 12429d1a546cSKirti Wankhede 12439169cff1SJason Gunthorpe static ssize_t name_show(struct mdev_type *mtype, 12449169cff1SJason Gunthorpe struct mdev_type_attribute *attr, char *buf) 12459d1a546cSKirti Wankhede { 1246c594b26fSJason Gunthorpe static const char *name_str[2] = { "Single port serial", 1247c594b26fSJason Gunthorpe "Dual port serial" }; 12489d1a546cSKirti Wankhede 1249c594b26fSJason Gunthorpe return sysfs_emit(buf, "%s\n", 12509169cff1SJason Gunthorpe name_str[mtype_get_type_group_id(mtype)]); 12519d1a546cSKirti Wankhede } 12529d1a546cSKirti Wankhede 12534b2dbd56SKefeng Wang static MDEV_TYPE_ATTR_RO(name); 12549d1a546cSKirti Wankhede 12559169cff1SJason Gunthorpe static ssize_t available_instances_show(struct mdev_type *mtype, 12569169cff1SJason Gunthorpe struct mdev_type_attribute *attr, 12579169cff1SJason Gunthorpe char *buf) 12589d1a546cSKirti Wankhede { 12599169cff1SJason Gunthorpe unsigned int ports = mtype_get_type_group_id(mtype) + 1; 12609d1a546cSKirti Wankhede 126197d0a687SAlex Williamson return sprintf(buf, "%d\n", atomic_read(&mdev_avail_ports) / ports); 12629d1a546cSKirti Wankhede } 12639d1a546cSKirti Wankhede 12644b2dbd56SKefeng Wang static MDEV_TYPE_ATTR_RO(available_instances); 12659d1a546cSKirti Wankhede 12669169cff1SJason Gunthorpe static ssize_t device_api_show(struct mdev_type *mtype, 12679169cff1SJason Gunthorpe struct mdev_type_attribute *attr, char *buf) 12689d1a546cSKirti Wankhede { 12699d1a546cSKirti Wankhede return sprintf(buf, "%s\n", VFIO_DEVICE_API_PCI_STRING); 12709d1a546cSKirti Wankhede } 12719d1a546cSKirti Wankhede 12724b2dbd56SKefeng Wang static MDEV_TYPE_ATTR_RO(device_api); 12739d1a546cSKirti Wankhede 12749d1a546cSKirti Wankhede static struct attribute *mdev_types_attrs[] = { 12759d1a546cSKirti Wankhede &mdev_type_attr_name.attr, 12769d1a546cSKirti Wankhede &mdev_type_attr_device_api.attr, 12779d1a546cSKirti Wankhede &mdev_type_attr_available_instances.attr, 12789d1a546cSKirti Wankhede NULL, 12799d1a546cSKirti Wankhede }; 12809d1a546cSKirti Wankhede 12819d1a546cSKirti Wankhede static struct attribute_group mdev_type_group1 = { 12829d1a546cSKirti Wankhede .name = "1", 12839d1a546cSKirti Wankhede .attrs = mdev_types_attrs, 12849d1a546cSKirti Wankhede }; 12859d1a546cSKirti Wankhede 12869d1a546cSKirti Wankhede static struct attribute_group mdev_type_group2 = { 12879d1a546cSKirti Wankhede .name = "2", 12889d1a546cSKirti Wankhede .attrs = mdev_types_attrs, 12899d1a546cSKirti Wankhede }; 12909d1a546cSKirti Wankhede 12914b2dbd56SKefeng Wang static struct attribute_group *mdev_type_groups[] = { 12929d1a546cSKirti Wankhede &mdev_type_group1, 12939d1a546cSKirti Wankhede &mdev_type_group2, 12949d1a546cSKirti Wankhede NULL, 12959d1a546cSKirti Wankhede }; 12969d1a546cSKirti Wankhede 129709177ac9SJason Gunthorpe static const struct vfio_device_ops mtty_dev_ops = { 129809177ac9SJason Gunthorpe .name = "vfio-mtty", 1299*67c5a181SYi Liu .init = mtty_init_dev, 1300*67c5a181SYi Liu .release = mtty_release_dev, 13019d1a546cSKirti Wankhede .read = mtty_read, 13029d1a546cSKirti Wankhede .write = mtty_write, 13039d1a546cSKirti Wankhede .ioctl = mtty_ioctl, 13049d1a546cSKirti Wankhede }; 13059d1a546cSKirti Wankhede 130609177ac9SJason Gunthorpe static struct mdev_driver mtty_driver = { 130709177ac9SJason Gunthorpe .driver = { 130809177ac9SJason Gunthorpe .name = "mtty", 130909177ac9SJason Gunthorpe .owner = THIS_MODULE, 131009177ac9SJason Gunthorpe .mod_name = KBUILD_MODNAME, 131109177ac9SJason Gunthorpe .dev_groups = mdev_dev_groups, 131209177ac9SJason Gunthorpe }, 131309177ac9SJason Gunthorpe .probe = mtty_probe, 131409177ac9SJason Gunthorpe .remove = mtty_remove, 131509177ac9SJason Gunthorpe .supported_type_groups = mdev_type_groups, 131609177ac9SJason Gunthorpe }; 131709177ac9SJason Gunthorpe 13189d1a546cSKirti Wankhede static void mtty_device_release(struct device *dev) 13199d1a546cSKirti Wankhede { 13209d1a546cSKirti Wankhede dev_dbg(dev, "mtty: released\n"); 13219d1a546cSKirti Wankhede } 13229d1a546cSKirti Wankhede 13239d1a546cSKirti Wankhede static int __init mtty_dev_init(void) 13249d1a546cSKirti Wankhede { 13259d1a546cSKirti Wankhede int ret = 0; 13269d1a546cSKirti Wankhede 13279d1a546cSKirti Wankhede pr_info("mtty_dev: %s\n", __func__); 13289d1a546cSKirti Wankhede 13299d1a546cSKirti Wankhede memset(&mtty_dev, 0, sizeof(mtty_dev)); 13309d1a546cSKirti Wankhede 13319d1a546cSKirti Wankhede idr_init(&mtty_dev.vd_idr); 13329d1a546cSKirti Wankhede 13333e4835f7SChengguang Xu ret = alloc_chrdev_region(&mtty_dev.vd_devt, 0, MINORMASK + 1, 13343e4835f7SChengguang Xu MTTY_NAME); 13359d1a546cSKirti Wankhede 13369d1a546cSKirti Wankhede if (ret < 0) { 13379d1a546cSKirti Wankhede pr_err("Error: failed to register mtty_dev, err:%d\n", ret); 13389d1a546cSKirti Wankhede return ret; 13399d1a546cSKirti Wankhede } 13409d1a546cSKirti Wankhede 13419d1a546cSKirti Wankhede cdev_init(&mtty_dev.vd_cdev, &vd_fops); 13423e4835f7SChengguang Xu cdev_add(&mtty_dev.vd_cdev, mtty_dev.vd_devt, MINORMASK + 1); 13439d1a546cSKirti Wankhede 13449d1a546cSKirti Wankhede pr_info("major_number:%d\n", MAJOR(mtty_dev.vd_devt)); 13459d1a546cSKirti Wankhede 134609177ac9SJason Gunthorpe ret = mdev_register_driver(&mtty_driver); 134709177ac9SJason Gunthorpe if (ret) 134809177ac9SJason Gunthorpe goto err_cdev; 134909177ac9SJason Gunthorpe 13509d1a546cSKirti Wankhede mtty_dev.vd_class = class_create(THIS_MODULE, MTTY_CLASS_NAME); 13519d1a546cSKirti Wankhede 13529d1a546cSKirti Wankhede if (IS_ERR(mtty_dev.vd_class)) { 13539d1a546cSKirti Wankhede pr_err("Error: failed to register mtty_dev class\n"); 1354d293dbaaSDan Carpenter ret = PTR_ERR(mtty_dev.vd_class); 135509177ac9SJason Gunthorpe goto err_driver; 13569d1a546cSKirti Wankhede } 13579d1a546cSKirti Wankhede 13589d1a546cSKirti Wankhede mtty_dev.dev.class = mtty_dev.vd_class; 13599d1a546cSKirti Wankhede mtty_dev.dev.release = mtty_device_release; 13609d1a546cSKirti Wankhede dev_set_name(&mtty_dev.dev, "%s", MTTY_NAME); 13619d1a546cSKirti Wankhede 13629d1a546cSKirti Wankhede ret = device_register(&mtty_dev.dev); 13639d1a546cSKirti Wankhede if (ret) 136409177ac9SJason Gunthorpe goto err_class; 13659d1a546cSKirti Wankhede 13666b42f491SJason Gunthorpe ret = mdev_register_device(&mtty_dev.dev, &mtty_driver); 1367d293dbaaSDan Carpenter if (ret) 136809177ac9SJason Gunthorpe goto err_device; 136909177ac9SJason Gunthorpe return 0; 13709d1a546cSKirti Wankhede 137109177ac9SJason Gunthorpe err_device: 13729d1a546cSKirti Wankhede device_unregister(&mtty_dev.dev); 137309177ac9SJason Gunthorpe err_class: 13749d1a546cSKirti Wankhede class_destroy(mtty_dev.vd_class); 137509177ac9SJason Gunthorpe err_driver: 137609177ac9SJason Gunthorpe mdev_unregister_driver(&mtty_driver); 137709177ac9SJason Gunthorpe err_cdev: 13789d1a546cSKirti Wankhede cdev_del(&mtty_dev.vd_cdev); 13793e4835f7SChengguang Xu unregister_chrdev_region(mtty_dev.vd_devt, MINORMASK + 1); 13809d1a546cSKirti Wankhede return ret; 13819d1a546cSKirti Wankhede } 13829d1a546cSKirti Wankhede 13839d1a546cSKirti Wankhede static void __exit mtty_dev_exit(void) 13849d1a546cSKirti Wankhede { 13859d1a546cSKirti Wankhede mtty_dev.dev.bus = NULL; 13869d1a546cSKirti Wankhede mdev_unregister_device(&mtty_dev.dev); 13879d1a546cSKirti Wankhede 13889d1a546cSKirti Wankhede device_unregister(&mtty_dev.dev); 13899d1a546cSKirti Wankhede idr_destroy(&mtty_dev.vd_idr); 139009177ac9SJason Gunthorpe mdev_unregister_driver(&mtty_driver); 13919d1a546cSKirti Wankhede cdev_del(&mtty_dev.vd_cdev); 13923e4835f7SChengguang Xu unregister_chrdev_region(mtty_dev.vd_devt, MINORMASK + 1); 13939d1a546cSKirti Wankhede class_destroy(mtty_dev.vd_class); 13949d1a546cSKirti Wankhede mtty_dev.vd_class = NULL; 13959d1a546cSKirti Wankhede pr_info("mtty_dev: Unloaded!\n"); 13969d1a546cSKirti Wankhede } 13979d1a546cSKirti Wankhede 13989d1a546cSKirti Wankhede module_init(mtty_dev_init) 13999d1a546cSKirti Wankhede module_exit(mtty_dev_exit) 14009d1a546cSKirti Wankhede 14019d1a546cSKirti Wankhede MODULE_LICENSE("GPL v2"); 14029d1a546cSKirti Wankhede MODULE_INFO(supported, "Test driver that simulate serial port over PCI"); 14039d1a546cSKirti Wankhede MODULE_VERSION(VERSION_STRING); 14049d1a546cSKirti Wankhede MODULE_AUTHOR(DRIVER_AUTHOR); 1405