19d1a546cSKirti Wankhede /* 29d1a546cSKirti Wankhede * Mediated virtual PCI serial host device driver 39d1a546cSKirti Wankhede * 49d1a546cSKirti Wankhede * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. 59d1a546cSKirti Wankhede * Author: Neo Jia <cjia@nvidia.com> 69d1a546cSKirti Wankhede * Kirti Wankhede <kwankhede@nvidia.com> 79d1a546cSKirti Wankhede * 89d1a546cSKirti Wankhede * This program is free software; you can redistribute it and/or modify 99d1a546cSKirti Wankhede * it under the terms of the GNU General Public License version 2 as 109d1a546cSKirti Wankhede * published by the Free Software Foundation. 119d1a546cSKirti Wankhede * 129d1a546cSKirti Wankhede * Sample driver that creates mdev device that simulates serial port over PCI 139d1a546cSKirti Wankhede * card. 149d1a546cSKirti Wankhede * 159d1a546cSKirti Wankhede */ 169d1a546cSKirti Wankhede 179d1a546cSKirti Wankhede #include <linux/init.h> 189d1a546cSKirti Wankhede #include <linux/module.h> 199d1a546cSKirti Wankhede #include <linux/device.h> 209d1a546cSKirti Wankhede #include <linux/kernel.h> 219d1a546cSKirti Wankhede #include <linux/fs.h> 229d1a546cSKirti Wankhede #include <linux/poll.h> 239d1a546cSKirti Wankhede #include <linux/slab.h> 249d1a546cSKirti Wankhede #include <linux/cdev.h> 259d1a546cSKirti Wankhede #include <linux/sched.h> 269d1a546cSKirti Wankhede #include <linux/wait.h> 279d1a546cSKirti Wankhede #include <linux/uuid.h> 289d1a546cSKirti Wankhede #include <linux/vfio.h> 299d1a546cSKirti Wankhede #include <linux/iommu.h> 309d1a546cSKirti Wankhede #include <linux/sysfs.h> 319d1a546cSKirti Wankhede #include <linux/ctype.h> 329d1a546cSKirti Wankhede #include <linux/file.h> 339d1a546cSKirti Wankhede #include <linux/mdev.h> 349d1a546cSKirti Wankhede #include <linux/pci.h> 359d1a546cSKirti Wankhede #include <linux/serial.h> 369d1a546cSKirti Wankhede #include <uapi/linux/serial_reg.h> 379d1a546cSKirti Wankhede #include <linux/eventfd.h> 389d1a546cSKirti Wankhede /* 399d1a546cSKirti Wankhede * #defines 409d1a546cSKirti Wankhede */ 419d1a546cSKirti Wankhede 429d1a546cSKirti Wankhede #define VERSION_STRING "0.1" 439d1a546cSKirti Wankhede #define DRIVER_AUTHOR "NVIDIA Corporation" 449d1a546cSKirti Wankhede 459d1a546cSKirti Wankhede #define MTTY_CLASS_NAME "mtty" 469d1a546cSKirti Wankhede 479d1a546cSKirti Wankhede #define MTTY_NAME "mtty" 489d1a546cSKirti Wankhede 499d1a546cSKirti Wankhede #define MTTY_STRING_LEN 16 509d1a546cSKirti Wankhede 519d1a546cSKirti Wankhede #define MTTY_CONFIG_SPACE_SIZE 0xff 529d1a546cSKirti Wankhede #define MTTY_IO_BAR_SIZE 0x8 539d1a546cSKirti Wankhede #define MTTY_MMIO_BAR_SIZE 0x100000 549d1a546cSKirti Wankhede 559d1a546cSKirti Wankhede #define STORE_LE16(addr, val) (*(u16 *)addr = val) 569d1a546cSKirti Wankhede #define STORE_LE32(addr, val) (*(u32 *)addr = val) 579d1a546cSKirti Wankhede 589d1a546cSKirti Wankhede #define MAX_FIFO_SIZE 16 599d1a546cSKirti Wankhede 609d1a546cSKirti Wankhede #define CIRCULAR_BUF_INC_IDX(idx) (idx = (idx + 1) & (MAX_FIFO_SIZE - 1)) 619d1a546cSKirti Wankhede 629d1a546cSKirti Wankhede #define MTTY_VFIO_PCI_OFFSET_SHIFT 40 639d1a546cSKirti Wankhede 649d1a546cSKirti Wankhede #define MTTY_VFIO_PCI_OFFSET_TO_INDEX(off) (off >> MTTY_VFIO_PCI_OFFSET_SHIFT) 659d1a546cSKirti Wankhede #define MTTY_VFIO_PCI_INDEX_TO_OFFSET(index) \ 669d1a546cSKirti Wankhede ((u64)(index) << MTTY_VFIO_PCI_OFFSET_SHIFT) 679d1a546cSKirti Wankhede #define MTTY_VFIO_PCI_OFFSET_MASK \ 689d1a546cSKirti Wankhede (((u64)(1) << MTTY_VFIO_PCI_OFFSET_SHIFT) - 1) 699d1a546cSKirti Wankhede #define MAX_MTTYS 24 709d1a546cSKirti Wankhede 719d1a546cSKirti Wankhede /* 729d1a546cSKirti Wankhede * Global Structures 739d1a546cSKirti Wankhede */ 749d1a546cSKirti Wankhede 759d1a546cSKirti Wankhede struct mtty_dev { 769d1a546cSKirti Wankhede dev_t vd_devt; 779d1a546cSKirti Wankhede struct class *vd_class; 789d1a546cSKirti Wankhede struct cdev vd_cdev; 799d1a546cSKirti Wankhede struct idr vd_idr; 809d1a546cSKirti Wankhede struct device dev; 819d1a546cSKirti Wankhede } mtty_dev; 829d1a546cSKirti Wankhede 839d1a546cSKirti Wankhede struct mdev_region_info { 849d1a546cSKirti Wankhede u64 start; 859d1a546cSKirti Wankhede u64 phys_start; 869d1a546cSKirti Wankhede u32 size; 879d1a546cSKirti Wankhede u64 vfio_offset; 889d1a546cSKirti Wankhede }; 899d1a546cSKirti Wankhede 909d1a546cSKirti Wankhede #if defined(DEBUG_REGS) 919d1a546cSKirti Wankhede const char *wr_reg[] = { 929d1a546cSKirti Wankhede "TX", 939d1a546cSKirti Wankhede "IER", 949d1a546cSKirti Wankhede "FCR", 959d1a546cSKirti Wankhede "LCR", 969d1a546cSKirti Wankhede "MCR", 979d1a546cSKirti Wankhede "LSR", 989d1a546cSKirti Wankhede "MSR", 999d1a546cSKirti Wankhede "SCR" 1009d1a546cSKirti Wankhede }; 1019d1a546cSKirti Wankhede 1029d1a546cSKirti Wankhede const char *rd_reg[] = { 1039d1a546cSKirti Wankhede "RX", 1049d1a546cSKirti Wankhede "IER", 1059d1a546cSKirti Wankhede "IIR", 1069d1a546cSKirti Wankhede "LCR", 1079d1a546cSKirti Wankhede "MCR", 1089d1a546cSKirti Wankhede "LSR", 1099d1a546cSKirti Wankhede "MSR", 1109d1a546cSKirti Wankhede "SCR" 1119d1a546cSKirti Wankhede }; 1129d1a546cSKirti Wankhede #endif 1139d1a546cSKirti Wankhede 1149d1a546cSKirti Wankhede /* loop back buffer */ 1159d1a546cSKirti Wankhede struct rxtx { 1169d1a546cSKirti Wankhede u8 fifo[MAX_FIFO_SIZE]; 1179d1a546cSKirti Wankhede u8 head, tail; 1189d1a546cSKirti Wankhede u8 count; 1199d1a546cSKirti Wankhede }; 1209d1a546cSKirti Wankhede 1219d1a546cSKirti Wankhede struct serial_port { 1229d1a546cSKirti Wankhede u8 uart_reg[8]; /* 8 registers */ 1239d1a546cSKirti Wankhede struct rxtx rxtx; /* loop back buffer */ 1249d1a546cSKirti Wankhede bool dlab; 1259d1a546cSKirti Wankhede bool overrun; 1269d1a546cSKirti Wankhede u16 divisor; 1279d1a546cSKirti Wankhede u8 fcr; /* FIFO control register */ 1289d1a546cSKirti Wankhede u8 max_fifo_size; 1299d1a546cSKirti Wankhede u8 intr_trigger_level; /* interrupt trigger level */ 1309d1a546cSKirti Wankhede }; 1319d1a546cSKirti Wankhede 1329d1a546cSKirti Wankhede /* State of each mdev device */ 1339d1a546cSKirti Wankhede struct mdev_state { 1349d1a546cSKirti Wankhede int irq_fd; 1359d1a546cSKirti Wankhede struct eventfd_ctx *intx_evtfd; 1369d1a546cSKirti Wankhede struct eventfd_ctx *msi_evtfd; 1379d1a546cSKirti Wankhede int irq_index; 1389d1a546cSKirti Wankhede u8 *vconfig; 1399d1a546cSKirti Wankhede struct mutex ops_lock; 1409d1a546cSKirti Wankhede struct mdev_device *mdev; 1419d1a546cSKirti Wankhede struct mdev_region_info region_info[VFIO_PCI_NUM_REGIONS]; 1429d1a546cSKirti Wankhede u32 bar_mask[VFIO_PCI_NUM_REGIONS]; 1439d1a546cSKirti Wankhede struct list_head next; 1449d1a546cSKirti Wankhede struct serial_port s[2]; 1459d1a546cSKirti Wankhede struct mutex rxtx_lock; 1469d1a546cSKirti Wankhede struct vfio_device_info dev_info; 1479d1a546cSKirti Wankhede int nr_ports; 1489d1a546cSKirti Wankhede }; 1499d1a546cSKirti Wankhede 1509d1a546cSKirti Wankhede struct mutex mdev_list_lock; 1519d1a546cSKirti Wankhede struct list_head mdev_devices_list; 1529d1a546cSKirti Wankhede 1539d1a546cSKirti Wankhede static const struct file_operations vd_fops = { 1549d1a546cSKirti Wankhede .owner = THIS_MODULE, 1559d1a546cSKirti Wankhede }; 1569d1a546cSKirti Wankhede 1579d1a546cSKirti Wankhede /* function prototypes */ 1589d1a546cSKirti Wankhede 1599d1a546cSKirti Wankhede static int mtty_trigger_interrupt(uuid_le uuid); 1609d1a546cSKirti Wankhede 1619d1a546cSKirti Wankhede /* Helper functions */ 1629d1a546cSKirti Wankhede static struct mdev_state *find_mdev_state_by_uuid(uuid_le uuid) 1639d1a546cSKirti Wankhede { 1649d1a546cSKirti Wankhede struct mdev_state *mds; 1659d1a546cSKirti Wankhede 1669d1a546cSKirti Wankhede list_for_each_entry(mds, &mdev_devices_list, next) { 16799e3123eSAlex Williamson if (uuid_le_cmp(mdev_uuid(mds->mdev), uuid) == 0) 1689d1a546cSKirti Wankhede return mds; 1699d1a546cSKirti Wankhede } 1709d1a546cSKirti Wankhede 1719d1a546cSKirti Wankhede return NULL; 1729d1a546cSKirti Wankhede } 1739d1a546cSKirti Wankhede 1749d1a546cSKirti Wankhede void dump_buffer(char *buf, uint32_t count) 1759d1a546cSKirti Wankhede { 1769d1a546cSKirti Wankhede #if defined(DEBUG) 1779d1a546cSKirti Wankhede int i; 1789d1a546cSKirti Wankhede 1799d1a546cSKirti Wankhede pr_info("Buffer:\n"); 1809d1a546cSKirti Wankhede for (i = 0; i < count; i++) { 1819d1a546cSKirti Wankhede pr_info("%2x ", *(buf + i)); 1829d1a546cSKirti Wankhede if ((i + 1) % 16 == 0) 1839d1a546cSKirti Wankhede pr_info("\n"); 1849d1a546cSKirti Wankhede } 1859d1a546cSKirti Wankhede #endif 1869d1a546cSKirti Wankhede } 1879d1a546cSKirti Wankhede 1889d1a546cSKirti Wankhede static void mtty_create_config_space(struct mdev_state *mdev_state) 1899d1a546cSKirti Wankhede { 1909d1a546cSKirti Wankhede /* PCI dev ID */ 1919d1a546cSKirti Wankhede STORE_LE32((u32 *) &mdev_state->vconfig[0x0], 0x32534348); 1929d1a546cSKirti Wankhede 1939d1a546cSKirti Wankhede /* Control: I/O+, Mem-, BusMaster- */ 1949d1a546cSKirti Wankhede STORE_LE16((u16 *) &mdev_state->vconfig[0x4], 0x0001); 1959d1a546cSKirti Wankhede 1969d1a546cSKirti Wankhede /* Status: capabilities list absent */ 1979d1a546cSKirti Wankhede STORE_LE16((u16 *) &mdev_state->vconfig[0x6], 0x0200); 1989d1a546cSKirti Wankhede 1999d1a546cSKirti Wankhede /* Rev ID */ 2009d1a546cSKirti Wankhede mdev_state->vconfig[0x8] = 0x10; 2019d1a546cSKirti Wankhede 2029d1a546cSKirti Wankhede /* programming interface class : 16550-compatible serial controller */ 2039d1a546cSKirti Wankhede mdev_state->vconfig[0x9] = 0x02; 2049d1a546cSKirti Wankhede 2059d1a546cSKirti Wankhede /* Sub class : 00 */ 2069d1a546cSKirti Wankhede mdev_state->vconfig[0xa] = 0x00; 2079d1a546cSKirti Wankhede 2089d1a546cSKirti Wankhede /* Base class : Simple Communication controllers */ 2099d1a546cSKirti Wankhede mdev_state->vconfig[0xb] = 0x07; 2109d1a546cSKirti Wankhede 2119d1a546cSKirti Wankhede /* base address registers */ 2129d1a546cSKirti Wankhede /* BAR0: IO space */ 2139d1a546cSKirti Wankhede STORE_LE32((u32 *) &mdev_state->vconfig[0x10], 0x000001); 2149d1a546cSKirti Wankhede mdev_state->bar_mask[0] = ~(MTTY_IO_BAR_SIZE) + 1; 2159d1a546cSKirti Wankhede 2169d1a546cSKirti Wankhede if (mdev_state->nr_ports == 2) { 2179d1a546cSKirti Wankhede /* BAR1: IO space */ 2189d1a546cSKirti Wankhede STORE_LE32((u32 *) &mdev_state->vconfig[0x14], 0x000001); 2199d1a546cSKirti Wankhede mdev_state->bar_mask[1] = ~(MTTY_IO_BAR_SIZE) + 1; 2209d1a546cSKirti Wankhede } 2219d1a546cSKirti Wankhede 2229d1a546cSKirti Wankhede /* Subsystem ID */ 2239d1a546cSKirti Wankhede STORE_LE32((u32 *) &mdev_state->vconfig[0x2c], 0x32534348); 2249d1a546cSKirti Wankhede 2259d1a546cSKirti Wankhede mdev_state->vconfig[0x34] = 0x00; /* Cap Ptr */ 2269d1a546cSKirti Wankhede mdev_state->vconfig[0x3d] = 0x01; /* interrupt pin (INTA#) */ 2279d1a546cSKirti Wankhede 2289d1a546cSKirti Wankhede /* Vendor specific data */ 2299d1a546cSKirti Wankhede mdev_state->vconfig[0x40] = 0x23; 2309d1a546cSKirti Wankhede mdev_state->vconfig[0x43] = 0x80; 2319d1a546cSKirti Wankhede mdev_state->vconfig[0x44] = 0x23; 2329d1a546cSKirti Wankhede mdev_state->vconfig[0x48] = 0x23; 2339d1a546cSKirti Wankhede mdev_state->vconfig[0x4c] = 0x23; 2349d1a546cSKirti Wankhede 2359d1a546cSKirti Wankhede mdev_state->vconfig[0x60] = 0x50; 2369d1a546cSKirti Wankhede mdev_state->vconfig[0x61] = 0x43; 2379d1a546cSKirti Wankhede mdev_state->vconfig[0x62] = 0x49; 2389d1a546cSKirti Wankhede mdev_state->vconfig[0x63] = 0x20; 2399d1a546cSKirti Wankhede mdev_state->vconfig[0x64] = 0x53; 2409d1a546cSKirti Wankhede mdev_state->vconfig[0x65] = 0x65; 2419d1a546cSKirti Wankhede mdev_state->vconfig[0x66] = 0x72; 2429d1a546cSKirti Wankhede mdev_state->vconfig[0x67] = 0x69; 2439d1a546cSKirti Wankhede mdev_state->vconfig[0x68] = 0x61; 2449d1a546cSKirti Wankhede mdev_state->vconfig[0x69] = 0x6c; 2459d1a546cSKirti Wankhede mdev_state->vconfig[0x6a] = 0x2f; 2469d1a546cSKirti Wankhede mdev_state->vconfig[0x6b] = 0x55; 2479d1a546cSKirti Wankhede mdev_state->vconfig[0x6c] = 0x41; 2489d1a546cSKirti Wankhede mdev_state->vconfig[0x6d] = 0x52; 2499d1a546cSKirti Wankhede mdev_state->vconfig[0x6e] = 0x54; 2509d1a546cSKirti Wankhede } 2519d1a546cSKirti Wankhede 2529d1a546cSKirti Wankhede static void handle_pci_cfg_write(struct mdev_state *mdev_state, u16 offset, 2539d1a546cSKirti Wankhede char *buf, u32 count) 2549d1a546cSKirti Wankhede { 2559d1a546cSKirti Wankhede u32 cfg_addr, bar_mask, bar_index = 0; 2569d1a546cSKirti Wankhede 2579d1a546cSKirti Wankhede switch (offset) { 2589d1a546cSKirti Wankhede case 0x04: /* device control */ 2599d1a546cSKirti Wankhede case 0x06: /* device status */ 2609d1a546cSKirti Wankhede /* do nothing */ 2619d1a546cSKirti Wankhede break; 2629d1a546cSKirti Wankhede case 0x3c: /* interrupt line */ 2639d1a546cSKirti Wankhede mdev_state->vconfig[0x3c] = buf[0]; 2649d1a546cSKirti Wankhede break; 2659d1a546cSKirti Wankhede case 0x3d: 2669d1a546cSKirti Wankhede /* 2679d1a546cSKirti Wankhede * Interrupt Pin is hardwired to INTA. 2689d1a546cSKirti Wankhede * This field is write protected by hardware 2699d1a546cSKirti Wankhede */ 2709d1a546cSKirti Wankhede break; 2719d1a546cSKirti Wankhede case 0x10: /* BAR0 */ 2729d1a546cSKirti Wankhede case 0x14: /* BAR1 */ 2739d1a546cSKirti Wankhede if (offset == 0x10) 2749d1a546cSKirti Wankhede bar_index = 0; 2759d1a546cSKirti Wankhede else if (offset == 0x14) 2769d1a546cSKirti Wankhede bar_index = 1; 2779d1a546cSKirti Wankhede 2789d1a546cSKirti Wankhede if ((mdev_state->nr_ports == 1) && (bar_index == 1)) { 2799d1a546cSKirti Wankhede STORE_LE32(&mdev_state->vconfig[offset], 0); 2809d1a546cSKirti Wankhede break; 2819d1a546cSKirti Wankhede } 2829d1a546cSKirti Wankhede 2839d1a546cSKirti Wankhede cfg_addr = *(u32 *)buf; 2849d1a546cSKirti Wankhede pr_info("BAR%d addr 0x%x\n", bar_index, cfg_addr); 2859d1a546cSKirti Wankhede 2869d1a546cSKirti Wankhede if (cfg_addr == 0xffffffff) { 2879d1a546cSKirti Wankhede bar_mask = mdev_state->bar_mask[bar_index]; 2889d1a546cSKirti Wankhede cfg_addr = (cfg_addr & bar_mask); 2899d1a546cSKirti Wankhede } 2909d1a546cSKirti Wankhede 2919d1a546cSKirti Wankhede cfg_addr |= (mdev_state->vconfig[offset] & 0x3ul); 2929d1a546cSKirti Wankhede STORE_LE32(&mdev_state->vconfig[offset], cfg_addr); 2939d1a546cSKirti Wankhede break; 2949d1a546cSKirti Wankhede case 0x18: /* BAR2 */ 2959d1a546cSKirti Wankhede case 0x1c: /* BAR3 */ 2969d1a546cSKirti Wankhede case 0x20: /* BAR4 */ 2979d1a546cSKirti Wankhede STORE_LE32(&mdev_state->vconfig[offset], 0); 2989d1a546cSKirti Wankhede break; 2999d1a546cSKirti Wankhede default: 3009d1a546cSKirti Wankhede pr_info("PCI config write @0x%x of %d bytes not handled\n", 3019d1a546cSKirti Wankhede offset, count); 3029d1a546cSKirti Wankhede break; 3039d1a546cSKirti Wankhede } 3049d1a546cSKirti Wankhede } 3059d1a546cSKirti Wankhede 3069d1a546cSKirti Wankhede static void handle_bar_write(unsigned int index, struct mdev_state *mdev_state, 3079d1a546cSKirti Wankhede u16 offset, char *buf, u32 count) 3089d1a546cSKirti Wankhede { 3099d1a546cSKirti Wankhede u8 data = *buf; 3109d1a546cSKirti Wankhede 3119d1a546cSKirti Wankhede /* Handle data written by guest */ 3129d1a546cSKirti Wankhede switch (offset) { 3139d1a546cSKirti Wankhede case UART_TX: 3149d1a546cSKirti Wankhede /* if DLAB set, data is LSB of divisor */ 3159d1a546cSKirti Wankhede if (mdev_state->s[index].dlab) { 3169d1a546cSKirti Wankhede mdev_state->s[index].divisor |= data; 3179d1a546cSKirti Wankhede break; 3189d1a546cSKirti Wankhede } 3199d1a546cSKirti Wankhede 3209d1a546cSKirti Wankhede mutex_lock(&mdev_state->rxtx_lock); 3219d1a546cSKirti Wankhede 3229d1a546cSKirti Wankhede /* save in TX buffer */ 3239d1a546cSKirti Wankhede if (mdev_state->s[index].rxtx.count < 3249d1a546cSKirti Wankhede mdev_state->s[index].max_fifo_size) { 3259d1a546cSKirti Wankhede mdev_state->s[index].rxtx.fifo[ 3269d1a546cSKirti Wankhede mdev_state->s[index].rxtx.head] = data; 3279d1a546cSKirti Wankhede mdev_state->s[index].rxtx.count++; 3289d1a546cSKirti Wankhede CIRCULAR_BUF_INC_IDX(mdev_state->s[index].rxtx.head); 3299d1a546cSKirti Wankhede mdev_state->s[index].overrun = false; 3309d1a546cSKirti Wankhede 3319d1a546cSKirti Wankhede /* 3329d1a546cSKirti Wankhede * Trigger interrupt if receive data interrupt is 3339d1a546cSKirti Wankhede * enabled and fifo reached trigger level 3349d1a546cSKirti Wankhede */ 3359d1a546cSKirti Wankhede if ((mdev_state->s[index].uart_reg[UART_IER] & 3369d1a546cSKirti Wankhede UART_IER_RDI) && 3379d1a546cSKirti Wankhede (mdev_state->s[index].rxtx.count == 3389d1a546cSKirti Wankhede mdev_state->s[index].intr_trigger_level)) { 3399d1a546cSKirti Wankhede /* trigger interrupt */ 3409d1a546cSKirti Wankhede #if defined(DEBUG_INTR) 3419d1a546cSKirti Wankhede pr_err("Serial port %d: Fifo level trigger\n", 3429d1a546cSKirti Wankhede index); 3439d1a546cSKirti Wankhede #endif 34499e3123eSAlex Williamson mtty_trigger_interrupt( 34599e3123eSAlex Williamson mdev_uuid(mdev_state->mdev)); 3469d1a546cSKirti Wankhede } 3479d1a546cSKirti Wankhede } else { 3489d1a546cSKirti Wankhede #if defined(DEBUG_INTR) 3499d1a546cSKirti Wankhede pr_err("Serial port %d: Buffer Overflow\n", index); 3509d1a546cSKirti Wankhede #endif 3519d1a546cSKirti Wankhede mdev_state->s[index].overrun = true; 3529d1a546cSKirti Wankhede 3539d1a546cSKirti Wankhede /* 3549d1a546cSKirti Wankhede * Trigger interrupt if receiver line status interrupt 3559d1a546cSKirti Wankhede * is enabled 3569d1a546cSKirti Wankhede */ 3579d1a546cSKirti Wankhede if (mdev_state->s[index].uart_reg[UART_IER] & 3589d1a546cSKirti Wankhede UART_IER_RLSI) 35999e3123eSAlex Williamson mtty_trigger_interrupt( 36099e3123eSAlex Williamson mdev_uuid(mdev_state->mdev)); 3619d1a546cSKirti Wankhede } 3629d1a546cSKirti Wankhede mutex_unlock(&mdev_state->rxtx_lock); 3639d1a546cSKirti Wankhede break; 3649d1a546cSKirti Wankhede 3659d1a546cSKirti Wankhede case UART_IER: 3669d1a546cSKirti Wankhede /* if DLAB set, data is MSB of divisor */ 3679d1a546cSKirti Wankhede if (mdev_state->s[index].dlab) 3689d1a546cSKirti Wankhede mdev_state->s[index].divisor |= (u16)data << 8; 3699d1a546cSKirti Wankhede else { 3709d1a546cSKirti Wankhede mdev_state->s[index].uart_reg[offset] = data; 3719d1a546cSKirti Wankhede mutex_lock(&mdev_state->rxtx_lock); 3729d1a546cSKirti Wankhede if ((data & UART_IER_THRI) && 3739d1a546cSKirti Wankhede (mdev_state->s[index].rxtx.head == 3749d1a546cSKirti Wankhede mdev_state->s[index].rxtx.tail)) { 3759d1a546cSKirti Wankhede #if defined(DEBUG_INTR) 3769d1a546cSKirti Wankhede pr_err("Serial port %d: IER_THRI write\n", 3779d1a546cSKirti Wankhede index); 3789d1a546cSKirti Wankhede #endif 37999e3123eSAlex Williamson mtty_trigger_interrupt( 38099e3123eSAlex Williamson mdev_uuid(mdev_state->mdev)); 3819d1a546cSKirti Wankhede } 3829d1a546cSKirti Wankhede 3839d1a546cSKirti Wankhede mutex_unlock(&mdev_state->rxtx_lock); 3849d1a546cSKirti Wankhede } 3859d1a546cSKirti Wankhede 3869d1a546cSKirti Wankhede break; 3879d1a546cSKirti Wankhede 3889d1a546cSKirti Wankhede case UART_FCR: 3899d1a546cSKirti Wankhede mdev_state->s[index].fcr = data; 3909d1a546cSKirti Wankhede 3919d1a546cSKirti Wankhede mutex_lock(&mdev_state->rxtx_lock); 3929d1a546cSKirti Wankhede if (data & (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)) { 3939d1a546cSKirti Wankhede /* clear loop back FIFO */ 3949d1a546cSKirti Wankhede mdev_state->s[index].rxtx.count = 0; 3959d1a546cSKirti Wankhede mdev_state->s[index].rxtx.head = 0; 3969d1a546cSKirti Wankhede mdev_state->s[index].rxtx.tail = 0; 3979d1a546cSKirti Wankhede } 3989d1a546cSKirti Wankhede mutex_unlock(&mdev_state->rxtx_lock); 3999d1a546cSKirti Wankhede 4009d1a546cSKirti Wankhede switch (data & UART_FCR_TRIGGER_MASK) { 4019d1a546cSKirti Wankhede case UART_FCR_TRIGGER_1: 4029d1a546cSKirti Wankhede mdev_state->s[index].intr_trigger_level = 1; 4039d1a546cSKirti Wankhede break; 4049d1a546cSKirti Wankhede 4059d1a546cSKirti Wankhede case UART_FCR_TRIGGER_4: 4069d1a546cSKirti Wankhede mdev_state->s[index].intr_trigger_level = 4; 4079d1a546cSKirti Wankhede break; 4089d1a546cSKirti Wankhede 4099d1a546cSKirti Wankhede case UART_FCR_TRIGGER_8: 4109d1a546cSKirti Wankhede mdev_state->s[index].intr_trigger_level = 8; 4119d1a546cSKirti Wankhede break; 4129d1a546cSKirti Wankhede 4139d1a546cSKirti Wankhede case UART_FCR_TRIGGER_14: 4149d1a546cSKirti Wankhede mdev_state->s[index].intr_trigger_level = 14; 4159d1a546cSKirti Wankhede break; 4169d1a546cSKirti Wankhede } 4179d1a546cSKirti Wankhede 4189d1a546cSKirti Wankhede /* 4199d1a546cSKirti Wankhede * Set trigger level to 1 otherwise or implement timer with 4209d1a546cSKirti Wankhede * timeout of 4 characters and on expiring that timer set 4219d1a546cSKirti Wankhede * Recevice data timeout in IIR register 4229d1a546cSKirti Wankhede */ 4239d1a546cSKirti Wankhede mdev_state->s[index].intr_trigger_level = 1; 4249d1a546cSKirti Wankhede if (data & UART_FCR_ENABLE_FIFO) 4259d1a546cSKirti Wankhede mdev_state->s[index].max_fifo_size = MAX_FIFO_SIZE; 4269d1a546cSKirti Wankhede else { 4279d1a546cSKirti Wankhede mdev_state->s[index].max_fifo_size = 1; 4289d1a546cSKirti Wankhede mdev_state->s[index].intr_trigger_level = 1; 4299d1a546cSKirti Wankhede } 4309d1a546cSKirti Wankhede 4319d1a546cSKirti Wankhede break; 4329d1a546cSKirti Wankhede 4339d1a546cSKirti Wankhede case UART_LCR: 4349d1a546cSKirti Wankhede if (data & UART_LCR_DLAB) { 4359d1a546cSKirti Wankhede mdev_state->s[index].dlab = true; 4369d1a546cSKirti Wankhede mdev_state->s[index].divisor = 0; 4379d1a546cSKirti Wankhede } else 4389d1a546cSKirti Wankhede mdev_state->s[index].dlab = false; 4399d1a546cSKirti Wankhede 4409d1a546cSKirti Wankhede mdev_state->s[index].uart_reg[offset] = data; 4419d1a546cSKirti Wankhede break; 4429d1a546cSKirti Wankhede 4439d1a546cSKirti Wankhede case UART_MCR: 4449d1a546cSKirti Wankhede mdev_state->s[index].uart_reg[offset] = data; 4459d1a546cSKirti Wankhede 4469d1a546cSKirti Wankhede if ((mdev_state->s[index].uart_reg[UART_IER] & UART_IER_MSI) && 4479d1a546cSKirti Wankhede (data & UART_MCR_OUT2)) { 4489d1a546cSKirti Wankhede #if defined(DEBUG_INTR) 4499d1a546cSKirti Wankhede pr_err("Serial port %d: MCR_OUT2 write\n", index); 4509d1a546cSKirti Wankhede #endif 45199e3123eSAlex Williamson mtty_trigger_interrupt(mdev_uuid(mdev_state->mdev)); 4529d1a546cSKirti Wankhede } 4539d1a546cSKirti Wankhede 4549d1a546cSKirti Wankhede if ((mdev_state->s[index].uart_reg[UART_IER] & UART_IER_MSI) && 4559d1a546cSKirti Wankhede (data & (UART_MCR_RTS | UART_MCR_DTR))) { 4569d1a546cSKirti Wankhede #if defined(DEBUG_INTR) 4579d1a546cSKirti Wankhede pr_err("Serial port %d: MCR RTS/DTR write\n", index); 4589d1a546cSKirti Wankhede #endif 45999e3123eSAlex Williamson mtty_trigger_interrupt(mdev_uuid(mdev_state->mdev)); 4609d1a546cSKirti Wankhede } 4619d1a546cSKirti Wankhede break; 4629d1a546cSKirti Wankhede 4639d1a546cSKirti Wankhede case UART_LSR: 4649d1a546cSKirti Wankhede case UART_MSR: 4659d1a546cSKirti Wankhede /* do nothing */ 4669d1a546cSKirti Wankhede break; 4679d1a546cSKirti Wankhede 4689d1a546cSKirti Wankhede case UART_SCR: 4699d1a546cSKirti Wankhede mdev_state->s[index].uart_reg[offset] = data; 4709d1a546cSKirti Wankhede break; 4719d1a546cSKirti Wankhede 4729d1a546cSKirti Wankhede default: 4739d1a546cSKirti Wankhede break; 4749d1a546cSKirti Wankhede } 4759d1a546cSKirti Wankhede } 4769d1a546cSKirti Wankhede 4779d1a546cSKirti Wankhede static void handle_bar_read(unsigned int index, struct mdev_state *mdev_state, 4789d1a546cSKirti Wankhede u16 offset, char *buf, u32 count) 4799d1a546cSKirti Wankhede { 4809d1a546cSKirti Wankhede /* Handle read requests by guest */ 4819d1a546cSKirti Wankhede switch (offset) { 4829d1a546cSKirti Wankhede case UART_RX: 4839d1a546cSKirti Wankhede /* if DLAB set, data is LSB of divisor */ 4849d1a546cSKirti Wankhede if (mdev_state->s[index].dlab) { 4859d1a546cSKirti Wankhede *buf = (u8)mdev_state->s[index].divisor; 4869d1a546cSKirti Wankhede break; 4879d1a546cSKirti Wankhede } 4889d1a546cSKirti Wankhede 4899d1a546cSKirti Wankhede mutex_lock(&mdev_state->rxtx_lock); 4909d1a546cSKirti Wankhede /* return data in tx buffer */ 4919d1a546cSKirti Wankhede if (mdev_state->s[index].rxtx.head != 4929d1a546cSKirti Wankhede mdev_state->s[index].rxtx.tail) { 4939d1a546cSKirti Wankhede *buf = mdev_state->s[index].rxtx.fifo[ 4949d1a546cSKirti Wankhede mdev_state->s[index].rxtx.tail]; 4959d1a546cSKirti Wankhede mdev_state->s[index].rxtx.count--; 4969d1a546cSKirti Wankhede CIRCULAR_BUF_INC_IDX(mdev_state->s[index].rxtx.tail); 4979d1a546cSKirti Wankhede } 4989d1a546cSKirti Wankhede 4999d1a546cSKirti Wankhede if (mdev_state->s[index].rxtx.head == 5009d1a546cSKirti Wankhede mdev_state->s[index].rxtx.tail) { 5019d1a546cSKirti Wankhede /* 5029d1a546cSKirti Wankhede * Trigger interrupt if tx buffer empty interrupt is 5039d1a546cSKirti Wankhede * enabled and fifo is empty 5049d1a546cSKirti Wankhede */ 5059d1a546cSKirti Wankhede #if defined(DEBUG_INTR) 5069d1a546cSKirti Wankhede pr_err("Serial port %d: Buffer Empty\n", index); 5079d1a546cSKirti Wankhede #endif 5089d1a546cSKirti Wankhede if (mdev_state->s[index].uart_reg[UART_IER] & 5099d1a546cSKirti Wankhede UART_IER_THRI) 51099e3123eSAlex Williamson mtty_trigger_interrupt( 51199e3123eSAlex Williamson mdev_uuid(mdev_state->mdev)); 5129d1a546cSKirti Wankhede } 5139d1a546cSKirti Wankhede mutex_unlock(&mdev_state->rxtx_lock); 5149d1a546cSKirti Wankhede 5159d1a546cSKirti Wankhede break; 5169d1a546cSKirti Wankhede 5179d1a546cSKirti Wankhede case UART_IER: 5189d1a546cSKirti Wankhede if (mdev_state->s[index].dlab) { 5199d1a546cSKirti Wankhede *buf = (u8)(mdev_state->s[index].divisor >> 8); 5209d1a546cSKirti Wankhede break; 5219d1a546cSKirti Wankhede } 5229d1a546cSKirti Wankhede *buf = mdev_state->s[index].uart_reg[offset] & 0x0f; 5239d1a546cSKirti Wankhede break; 5249d1a546cSKirti Wankhede 5259d1a546cSKirti Wankhede case UART_IIR: 5269d1a546cSKirti Wankhede { 5279d1a546cSKirti Wankhede u8 ier = mdev_state->s[index].uart_reg[UART_IER]; 5289d1a546cSKirti Wankhede *buf = 0; 5299d1a546cSKirti Wankhede 5309d1a546cSKirti Wankhede mutex_lock(&mdev_state->rxtx_lock); 5319d1a546cSKirti Wankhede /* Interrupt priority 1: Parity, overrun, framing or break */ 5329d1a546cSKirti Wankhede if ((ier & UART_IER_RLSI) && mdev_state->s[index].overrun) 5339d1a546cSKirti Wankhede *buf |= UART_IIR_RLSI; 5349d1a546cSKirti Wankhede 5359d1a546cSKirti Wankhede /* Interrupt priority 2: Fifo trigger level reached */ 5369d1a546cSKirti Wankhede if ((ier & UART_IER_RDI) && 537c9f89c3fSShunyong Yang (mdev_state->s[index].rxtx.count >= 5389d1a546cSKirti Wankhede mdev_state->s[index].intr_trigger_level)) 5399d1a546cSKirti Wankhede *buf |= UART_IIR_RDI; 5409d1a546cSKirti Wankhede 5419d1a546cSKirti Wankhede /* Interrupt priotiry 3: transmitter holding register empty */ 5429d1a546cSKirti Wankhede if ((ier & UART_IER_THRI) && 5439d1a546cSKirti Wankhede (mdev_state->s[index].rxtx.head == 5449d1a546cSKirti Wankhede mdev_state->s[index].rxtx.tail)) 5459d1a546cSKirti Wankhede *buf |= UART_IIR_THRI; 5469d1a546cSKirti Wankhede 5479d1a546cSKirti Wankhede /* Interrupt priotiry 4: Modem status: CTS, DSR, RI or DCD */ 5489d1a546cSKirti Wankhede if ((ier & UART_IER_MSI) && 5499d1a546cSKirti Wankhede (mdev_state->s[index].uart_reg[UART_MCR] & 5509d1a546cSKirti Wankhede (UART_MCR_RTS | UART_MCR_DTR))) 5519d1a546cSKirti Wankhede *buf |= UART_IIR_MSI; 5529d1a546cSKirti Wankhede 5539d1a546cSKirti Wankhede /* bit0: 0=> interrupt pending, 1=> no interrupt is pending */ 5549d1a546cSKirti Wankhede if (*buf == 0) 5559d1a546cSKirti Wankhede *buf = UART_IIR_NO_INT; 5569d1a546cSKirti Wankhede 5579d1a546cSKirti Wankhede /* set bit 6 & 7 to be 16550 compatible */ 5589d1a546cSKirti Wankhede *buf |= 0xC0; 5599d1a546cSKirti Wankhede mutex_unlock(&mdev_state->rxtx_lock); 5609d1a546cSKirti Wankhede } 5619d1a546cSKirti Wankhede break; 5629d1a546cSKirti Wankhede 5639d1a546cSKirti Wankhede case UART_LCR: 5649d1a546cSKirti Wankhede case UART_MCR: 5659d1a546cSKirti Wankhede *buf = mdev_state->s[index].uart_reg[offset]; 5669d1a546cSKirti Wankhede break; 5679d1a546cSKirti Wankhede 5689d1a546cSKirti Wankhede case UART_LSR: 5699d1a546cSKirti Wankhede { 5709d1a546cSKirti Wankhede u8 lsr = 0; 5719d1a546cSKirti Wankhede 5729d1a546cSKirti Wankhede mutex_lock(&mdev_state->rxtx_lock); 5739d1a546cSKirti Wankhede /* atleast one char in FIFO */ 5749d1a546cSKirti Wankhede if (mdev_state->s[index].rxtx.head != 5759d1a546cSKirti Wankhede mdev_state->s[index].rxtx.tail) 5769d1a546cSKirti Wankhede lsr |= UART_LSR_DR; 5779d1a546cSKirti Wankhede 5789d1a546cSKirti Wankhede /* if FIFO overrun */ 5799d1a546cSKirti Wankhede if (mdev_state->s[index].overrun) 5809d1a546cSKirti Wankhede lsr |= UART_LSR_OE; 5819d1a546cSKirti Wankhede 5829d1a546cSKirti Wankhede /* transmit FIFO empty and tramsitter empty */ 5839d1a546cSKirti Wankhede if (mdev_state->s[index].rxtx.head == 5849d1a546cSKirti Wankhede mdev_state->s[index].rxtx.tail) 5859d1a546cSKirti Wankhede lsr |= UART_LSR_TEMT | UART_LSR_THRE; 5869d1a546cSKirti Wankhede 5879d1a546cSKirti Wankhede mutex_unlock(&mdev_state->rxtx_lock); 5889d1a546cSKirti Wankhede *buf = lsr; 5899d1a546cSKirti Wankhede break; 5909d1a546cSKirti Wankhede } 5919d1a546cSKirti Wankhede case UART_MSR: 5929d1a546cSKirti Wankhede *buf = UART_MSR_DSR | UART_MSR_DDSR | UART_MSR_DCD; 5939d1a546cSKirti Wankhede 5949d1a546cSKirti Wankhede mutex_lock(&mdev_state->rxtx_lock); 5959d1a546cSKirti Wankhede /* if AFE is 1 and FIFO have space, set CTS bit */ 5969d1a546cSKirti Wankhede if (mdev_state->s[index].uart_reg[UART_MCR] & 5979d1a546cSKirti Wankhede UART_MCR_AFE) { 5989d1a546cSKirti Wankhede if (mdev_state->s[index].rxtx.count < 5999d1a546cSKirti Wankhede mdev_state->s[index].max_fifo_size) 6009d1a546cSKirti Wankhede *buf |= UART_MSR_CTS | UART_MSR_DCTS; 6019d1a546cSKirti Wankhede } else 6029d1a546cSKirti Wankhede *buf |= UART_MSR_CTS | UART_MSR_DCTS; 6039d1a546cSKirti Wankhede mutex_unlock(&mdev_state->rxtx_lock); 6049d1a546cSKirti Wankhede 6059d1a546cSKirti Wankhede break; 6069d1a546cSKirti Wankhede 6079d1a546cSKirti Wankhede case UART_SCR: 6089d1a546cSKirti Wankhede *buf = mdev_state->s[index].uart_reg[offset]; 6099d1a546cSKirti Wankhede break; 6109d1a546cSKirti Wankhede 6119d1a546cSKirti Wankhede default: 6129d1a546cSKirti Wankhede break; 6139d1a546cSKirti Wankhede } 6149d1a546cSKirti Wankhede } 6159d1a546cSKirti Wankhede 6169d1a546cSKirti Wankhede static void mdev_read_base(struct mdev_state *mdev_state) 6179d1a546cSKirti Wankhede { 6189d1a546cSKirti Wankhede int index, pos; 6199d1a546cSKirti Wankhede u32 start_lo, start_hi; 6209d1a546cSKirti Wankhede u32 mem_type; 6219d1a546cSKirti Wankhede 6229d1a546cSKirti Wankhede pos = PCI_BASE_ADDRESS_0; 6239d1a546cSKirti Wankhede 6249d1a546cSKirti Wankhede for (index = 0; index <= VFIO_PCI_BAR5_REGION_INDEX; index++) { 6259d1a546cSKirti Wankhede 6269d1a546cSKirti Wankhede if (!mdev_state->region_info[index].size) 6279d1a546cSKirti Wankhede continue; 6289d1a546cSKirti Wankhede 6299d1a546cSKirti Wankhede start_lo = (*(u32 *)(mdev_state->vconfig + pos)) & 6309d1a546cSKirti Wankhede PCI_BASE_ADDRESS_MEM_MASK; 6319d1a546cSKirti Wankhede mem_type = (*(u32 *)(mdev_state->vconfig + pos)) & 6329d1a546cSKirti Wankhede PCI_BASE_ADDRESS_MEM_TYPE_MASK; 6339d1a546cSKirti Wankhede 6349d1a546cSKirti Wankhede switch (mem_type) { 6359d1a546cSKirti Wankhede case PCI_BASE_ADDRESS_MEM_TYPE_64: 6369d1a546cSKirti Wankhede start_hi = (*(u32 *)(mdev_state->vconfig + pos + 4)); 6379d1a546cSKirti Wankhede pos += 4; 6389d1a546cSKirti Wankhede break; 6399d1a546cSKirti Wankhede case PCI_BASE_ADDRESS_MEM_TYPE_32: 6409d1a546cSKirti Wankhede case PCI_BASE_ADDRESS_MEM_TYPE_1M: 6419d1a546cSKirti Wankhede /* 1M mem BAR treated as 32-bit BAR */ 6429d1a546cSKirti Wankhede default: 6439d1a546cSKirti Wankhede /* mem unknown type treated as 32-bit BAR */ 6449d1a546cSKirti Wankhede start_hi = 0; 6459d1a546cSKirti Wankhede break; 6469d1a546cSKirti Wankhede } 6479d1a546cSKirti Wankhede pos += 4; 6489d1a546cSKirti Wankhede mdev_state->region_info[index].start = ((u64)start_hi << 32) | 6499d1a546cSKirti Wankhede start_lo; 6509d1a546cSKirti Wankhede } 6519d1a546cSKirti Wankhede } 6529d1a546cSKirti Wankhede 6539d1a546cSKirti Wankhede static ssize_t mdev_access(struct mdev_device *mdev, char *buf, size_t count, 6549d1a546cSKirti Wankhede loff_t pos, bool is_write) 6559d1a546cSKirti Wankhede { 6569d1a546cSKirti Wankhede struct mdev_state *mdev_state; 6579d1a546cSKirti Wankhede unsigned int index; 6589d1a546cSKirti Wankhede loff_t offset; 6599d1a546cSKirti Wankhede int ret = 0; 6609d1a546cSKirti Wankhede 6619d1a546cSKirti Wankhede if (!mdev || !buf) 6629d1a546cSKirti Wankhede return -EINVAL; 6639d1a546cSKirti Wankhede 6649d1a546cSKirti Wankhede mdev_state = mdev_get_drvdata(mdev); 6659d1a546cSKirti Wankhede if (!mdev_state) { 6669d1a546cSKirti Wankhede pr_err("%s mdev_state not found\n", __func__); 6679d1a546cSKirti Wankhede return -EINVAL; 6689d1a546cSKirti Wankhede } 6699d1a546cSKirti Wankhede 6709d1a546cSKirti Wankhede mutex_lock(&mdev_state->ops_lock); 6719d1a546cSKirti Wankhede 6729d1a546cSKirti Wankhede index = MTTY_VFIO_PCI_OFFSET_TO_INDEX(pos); 6739d1a546cSKirti Wankhede offset = pos & MTTY_VFIO_PCI_OFFSET_MASK; 6749d1a546cSKirti Wankhede switch (index) { 6759d1a546cSKirti Wankhede case VFIO_PCI_CONFIG_REGION_INDEX: 6769d1a546cSKirti Wankhede 6779d1a546cSKirti Wankhede #if defined(DEBUG) 6789d1a546cSKirti Wankhede pr_info("%s: PCI config space %s at offset 0x%llx\n", 6799d1a546cSKirti Wankhede __func__, is_write ? "write" : "read", offset); 6809d1a546cSKirti Wankhede #endif 6819d1a546cSKirti Wankhede if (is_write) { 6829d1a546cSKirti Wankhede dump_buffer(buf, count); 6839d1a546cSKirti Wankhede handle_pci_cfg_write(mdev_state, offset, buf, count); 6849d1a546cSKirti Wankhede } else { 6859d1a546cSKirti Wankhede memcpy(buf, (mdev_state->vconfig + offset), count); 6869d1a546cSKirti Wankhede dump_buffer(buf, count); 6879d1a546cSKirti Wankhede } 6889d1a546cSKirti Wankhede 6899d1a546cSKirti Wankhede break; 6909d1a546cSKirti Wankhede 6919d1a546cSKirti Wankhede case VFIO_PCI_BAR0_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX: 6929d1a546cSKirti Wankhede if (!mdev_state->region_info[index].start) 6939d1a546cSKirti Wankhede mdev_read_base(mdev_state); 6949d1a546cSKirti Wankhede 6959d1a546cSKirti Wankhede if (is_write) { 6969d1a546cSKirti Wankhede dump_buffer(buf, count); 6979d1a546cSKirti Wankhede 6989d1a546cSKirti Wankhede #if defined(DEBUG_REGS) 6999d1a546cSKirti Wankhede pr_info("%s: BAR%d WR @0x%llx %s val:0x%02x dlab:%d\n", 7009d1a546cSKirti Wankhede __func__, index, offset, wr_reg[offset], 7019d1a546cSKirti Wankhede (u8)*buf, mdev_state->s[index].dlab); 7029d1a546cSKirti Wankhede #endif 7039d1a546cSKirti Wankhede handle_bar_write(index, mdev_state, offset, buf, count); 7049d1a546cSKirti Wankhede } else { 7059d1a546cSKirti Wankhede handle_bar_read(index, mdev_state, offset, buf, count); 7069d1a546cSKirti Wankhede dump_buffer(buf, count); 7079d1a546cSKirti Wankhede 7089d1a546cSKirti Wankhede #if defined(DEBUG_REGS) 7099d1a546cSKirti Wankhede pr_info("%s: BAR%d RD @0x%llx %s val:0x%02x dlab:%d\n", 7109d1a546cSKirti Wankhede __func__, index, offset, rd_reg[offset], 7119d1a546cSKirti Wankhede (u8)*buf, mdev_state->s[index].dlab); 7129d1a546cSKirti Wankhede #endif 7139d1a546cSKirti Wankhede } 7149d1a546cSKirti Wankhede break; 7159d1a546cSKirti Wankhede 7169d1a546cSKirti Wankhede default: 7179d1a546cSKirti Wankhede ret = -1; 7189d1a546cSKirti Wankhede goto accessfailed; 7199d1a546cSKirti Wankhede } 7209d1a546cSKirti Wankhede 7219d1a546cSKirti Wankhede ret = count; 7229d1a546cSKirti Wankhede 7239d1a546cSKirti Wankhede 7249d1a546cSKirti Wankhede accessfailed: 7259d1a546cSKirti Wankhede mutex_unlock(&mdev_state->ops_lock); 7269d1a546cSKirti Wankhede 7279d1a546cSKirti Wankhede return ret; 7289d1a546cSKirti Wankhede } 7299d1a546cSKirti Wankhede 7309d1a546cSKirti Wankhede int mtty_create(struct kobject *kobj, struct mdev_device *mdev) 7319d1a546cSKirti Wankhede { 7329d1a546cSKirti Wankhede struct mdev_state *mdev_state; 7339d1a546cSKirti Wankhede char name[MTTY_STRING_LEN]; 7349d1a546cSKirti Wankhede int nr_ports = 0, i; 7359d1a546cSKirti Wankhede 7369d1a546cSKirti Wankhede if (!mdev) 7379d1a546cSKirti Wankhede return -EINVAL; 7389d1a546cSKirti Wankhede 7399d1a546cSKirti Wankhede for (i = 0; i < 2; i++) { 7409d1a546cSKirti Wankhede snprintf(name, MTTY_STRING_LEN, "%s-%d", 7419372e6feSAlex Williamson dev_driver_string(mdev_parent_dev(mdev)), i + 1); 7429d1a546cSKirti Wankhede if (!strcmp(kobj->name, name)) { 7439d1a546cSKirti Wankhede nr_ports = i + 1; 7449d1a546cSKirti Wankhede break; 7459d1a546cSKirti Wankhede } 7469d1a546cSKirti Wankhede } 7479d1a546cSKirti Wankhede 7489d1a546cSKirti Wankhede if (!nr_ports) 7499d1a546cSKirti Wankhede return -EINVAL; 7509d1a546cSKirti Wankhede 7519d1a546cSKirti Wankhede mdev_state = kzalloc(sizeof(struct mdev_state), GFP_KERNEL); 7529d1a546cSKirti Wankhede if (mdev_state == NULL) 7539d1a546cSKirti Wankhede return -ENOMEM; 7549d1a546cSKirti Wankhede 7559d1a546cSKirti Wankhede mdev_state->nr_ports = nr_ports; 7569d1a546cSKirti Wankhede mdev_state->irq_index = -1; 7579d1a546cSKirti Wankhede mdev_state->s[0].max_fifo_size = MAX_FIFO_SIZE; 7589d1a546cSKirti Wankhede mdev_state->s[1].max_fifo_size = MAX_FIFO_SIZE; 7599d1a546cSKirti Wankhede mutex_init(&mdev_state->rxtx_lock); 7609d1a546cSKirti Wankhede mdev_state->vconfig = kzalloc(MTTY_CONFIG_SPACE_SIZE, GFP_KERNEL); 7619d1a546cSKirti Wankhede 7629d1a546cSKirti Wankhede if (mdev_state->vconfig == NULL) { 7639d1a546cSKirti Wankhede kfree(mdev_state); 7649d1a546cSKirti Wankhede return -ENOMEM; 7659d1a546cSKirti Wankhede } 7669d1a546cSKirti Wankhede 7679d1a546cSKirti Wankhede mutex_init(&mdev_state->ops_lock); 7689d1a546cSKirti Wankhede mdev_state->mdev = mdev; 7699d1a546cSKirti Wankhede mdev_set_drvdata(mdev, mdev_state); 7709d1a546cSKirti Wankhede 7719d1a546cSKirti Wankhede mtty_create_config_space(mdev_state); 7729d1a546cSKirti Wankhede 7739d1a546cSKirti Wankhede mutex_lock(&mdev_list_lock); 7749d1a546cSKirti Wankhede list_add(&mdev_state->next, &mdev_devices_list); 7759d1a546cSKirti Wankhede mutex_unlock(&mdev_list_lock); 7769d1a546cSKirti Wankhede 7779d1a546cSKirti Wankhede return 0; 7789d1a546cSKirti Wankhede } 7799d1a546cSKirti Wankhede 7809d1a546cSKirti Wankhede int mtty_remove(struct mdev_device *mdev) 7819d1a546cSKirti Wankhede { 7829d1a546cSKirti Wankhede struct mdev_state *mds, *tmp_mds; 7839d1a546cSKirti Wankhede struct mdev_state *mdev_state = mdev_get_drvdata(mdev); 7849d1a546cSKirti Wankhede int ret = -EINVAL; 7859d1a546cSKirti Wankhede 7869d1a546cSKirti Wankhede mutex_lock(&mdev_list_lock); 7879d1a546cSKirti Wankhede list_for_each_entry_safe(mds, tmp_mds, &mdev_devices_list, next) { 7889d1a546cSKirti Wankhede if (mdev_state == mds) { 7899d1a546cSKirti Wankhede list_del(&mdev_state->next); 7909d1a546cSKirti Wankhede mdev_set_drvdata(mdev, NULL); 7919d1a546cSKirti Wankhede kfree(mdev_state->vconfig); 7929d1a546cSKirti Wankhede kfree(mdev_state); 7939d1a546cSKirti Wankhede ret = 0; 7949d1a546cSKirti Wankhede break; 7959d1a546cSKirti Wankhede } 7969d1a546cSKirti Wankhede } 7979d1a546cSKirti Wankhede mutex_unlock(&mdev_list_lock); 7989d1a546cSKirti Wankhede 7999d1a546cSKirti Wankhede return ret; 8009d1a546cSKirti Wankhede } 8019d1a546cSKirti Wankhede 8029d1a546cSKirti Wankhede int mtty_reset(struct mdev_device *mdev) 8039d1a546cSKirti Wankhede { 8049d1a546cSKirti Wankhede struct mdev_state *mdev_state; 8059d1a546cSKirti Wankhede 8069d1a546cSKirti Wankhede if (!mdev) 8079d1a546cSKirti Wankhede return -EINVAL; 8089d1a546cSKirti Wankhede 8099d1a546cSKirti Wankhede mdev_state = mdev_get_drvdata(mdev); 8109d1a546cSKirti Wankhede if (!mdev_state) 8119d1a546cSKirti Wankhede return -EINVAL; 8129d1a546cSKirti Wankhede 8139d1a546cSKirti Wankhede pr_info("%s: called\n", __func__); 8149d1a546cSKirti Wankhede 8159d1a546cSKirti Wankhede return 0; 8169d1a546cSKirti Wankhede } 8179d1a546cSKirti Wankhede 8189d1a546cSKirti Wankhede ssize_t mtty_read(struct mdev_device *mdev, char __user *buf, size_t count, 8199d1a546cSKirti Wankhede loff_t *ppos) 8209d1a546cSKirti Wankhede { 8219d1a546cSKirti Wankhede unsigned int done = 0; 8229d1a546cSKirti Wankhede int ret; 8239d1a546cSKirti Wankhede 8249d1a546cSKirti Wankhede while (count) { 8259d1a546cSKirti Wankhede size_t filled; 8269d1a546cSKirti Wankhede 8279d1a546cSKirti Wankhede if (count >= 4 && !(*ppos % 4)) { 8289d1a546cSKirti Wankhede u32 val; 8299d1a546cSKirti Wankhede 8309d1a546cSKirti Wankhede ret = mdev_access(mdev, (char *)&val, sizeof(val), 8319d1a546cSKirti Wankhede *ppos, false); 8329d1a546cSKirti Wankhede if (ret <= 0) 8339d1a546cSKirti Wankhede goto read_err; 8349d1a546cSKirti Wankhede 8359d1a546cSKirti Wankhede if (copy_to_user(buf, &val, sizeof(val))) 8369d1a546cSKirti Wankhede goto read_err; 8379d1a546cSKirti Wankhede 8389d1a546cSKirti Wankhede filled = 4; 8399d1a546cSKirti Wankhede } else if (count >= 2 && !(*ppos % 2)) { 8409d1a546cSKirti Wankhede u16 val; 8419d1a546cSKirti Wankhede 8429d1a546cSKirti Wankhede ret = mdev_access(mdev, (char *)&val, sizeof(val), 8439d1a546cSKirti Wankhede *ppos, false); 8449d1a546cSKirti Wankhede if (ret <= 0) 8459d1a546cSKirti Wankhede goto read_err; 8469d1a546cSKirti Wankhede 8479d1a546cSKirti Wankhede if (copy_to_user(buf, &val, sizeof(val))) 8489d1a546cSKirti Wankhede goto read_err; 8499d1a546cSKirti Wankhede 8509d1a546cSKirti Wankhede filled = 2; 8519d1a546cSKirti Wankhede } else { 8529d1a546cSKirti Wankhede u8 val; 8539d1a546cSKirti Wankhede 8549d1a546cSKirti Wankhede ret = mdev_access(mdev, (char *)&val, sizeof(val), 8559d1a546cSKirti Wankhede *ppos, false); 8569d1a546cSKirti Wankhede if (ret <= 0) 8579d1a546cSKirti Wankhede goto read_err; 8589d1a546cSKirti Wankhede 8599d1a546cSKirti Wankhede if (copy_to_user(buf, &val, sizeof(val))) 8609d1a546cSKirti Wankhede goto read_err; 8619d1a546cSKirti Wankhede 8629d1a546cSKirti Wankhede filled = 1; 8639d1a546cSKirti Wankhede } 8649d1a546cSKirti Wankhede 8659d1a546cSKirti Wankhede count -= filled; 8669d1a546cSKirti Wankhede done += filled; 8679d1a546cSKirti Wankhede *ppos += filled; 8689d1a546cSKirti Wankhede buf += filled; 8699d1a546cSKirti Wankhede } 8709d1a546cSKirti Wankhede 8719d1a546cSKirti Wankhede return done; 8729d1a546cSKirti Wankhede 8739d1a546cSKirti Wankhede read_err: 8749d1a546cSKirti Wankhede return -EFAULT; 8759d1a546cSKirti Wankhede } 8769d1a546cSKirti Wankhede 8779d1a546cSKirti Wankhede ssize_t mtty_write(struct mdev_device *mdev, const char __user *buf, 8789d1a546cSKirti Wankhede size_t count, loff_t *ppos) 8799d1a546cSKirti Wankhede { 8809d1a546cSKirti Wankhede unsigned int done = 0; 8819d1a546cSKirti Wankhede int ret; 8829d1a546cSKirti Wankhede 8839d1a546cSKirti Wankhede while (count) { 8849d1a546cSKirti Wankhede size_t filled; 8859d1a546cSKirti Wankhede 8869d1a546cSKirti Wankhede if (count >= 4 && !(*ppos % 4)) { 8879d1a546cSKirti Wankhede u32 val; 8889d1a546cSKirti Wankhede 8899d1a546cSKirti Wankhede if (copy_from_user(&val, buf, sizeof(val))) 8909d1a546cSKirti Wankhede goto write_err; 8919d1a546cSKirti Wankhede 8929d1a546cSKirti Wankhede ret = mdev_access(mdev, (char *)&val, sizeof(val), 8939d1a546cSKirti Wankhede *ppos, true); 8949d1a546cSKirti Wankhede if (ret <= 0) 8959d1a546cSKirti Wankhede goto write_err; 8969d1a546cSKirti Wankhede 8979d1a546cSKirti Wankhede filled = 4; 8989d1a546cSKirti Wankhede } else if (count >= 2 && !(*ppos % 2)) { 8999d1a546cSKirti Wankhede u16 val; 9009d1a546cSKirti Wankhede 9019d1a546cSKirti Wankhede if (copy_from_user(&val, buf, sizeof(val))) 9029d1a546cSKirti Wankhede goto write_err; 9039d1a546cSKirti Wankhede 9049d1a546cSKirti Wankhede ret = mdev_access(mdev, (char *)&val, sizeof(val), 9059d1a546cSKirti Wankhede *ppos, true); 9069d1a546cSKirti Wankhede if (ret <= 0) 9079d1a546cSKirti Wankhede goto write_err; 9089d1a546cSKirti Wankhede 9099d1a546cSKirti Wankhede filled = 2; 9109d1a546cSKirti Wankhede } else { 9119d1a546cSKirti Wankhede u8 val; 9129d1a546cSKirti Wankhede 9139d1a546cSKirti Wankhede if (copy_from_user(&val, buf, sizeof(val))) 9149d1a546cSKirti Wankhede goto write_err; 9159d1a546cSKirti Wankhede 9169d1a546cSKirti Wankhede ret = mdev_access(mdev, (char *)&val, sizeof(val), 9179d1a546cSKirti Wankhede *ppos, true); 9189d1a546cSKirti Wankhede if (ret <= 0) 9199d1a546cSKirti Wankhede goto write_err; 9209d1a546cSKirti Wankhede 9219d1a546cSKirti Wankhede filled = 1; 9229d1a546cSKirti Wankhede } 9239d1a546cSKirti Wankhede count -= filled; 9249d1a546cSKirti Wankhede done += filled; 9259d1a546cSKirti Wankhede *ppos += filled; 9269d1a546cSKirti Wankhede buf += filled; 9279d1a546cSKirti Wankhede } 9289d1a546cSKirti Wankhede 9299d1a546cSKirti Wankhede return done; 9309d1a546cSKirti Wankhede write_err: 9319d1a546cSKirti Wankhede return -EFAULT; 9329d1a546cSKirti Wankhede } 9339d1a546cSKirti Wankhede 9349d1a546cSKirti Wankhede static int mtty_set_irqs(struct mdev_device *mdev, uint32_t flags, 9359d1a546cSKirti Wankhede unsigned int index, unsigned int start, 9369d1a546cSKirti Wankhede unsigned int count, void *data) 9379d1a546cSKirti Wankhede { 9389d1a546cSKirti Wankhede int ret = 0; 9399d1a546cSKirti Wankhede struct mdev_state *mdev_state; 9409d1a546cSKirti Wankhede 9419d1a546cSKirti Wankhede if (!mdev) 9429d1a546cSKirti Wankhede return -EINVAL; 9439d1a546cSKirti Wankhede 9449d1a546cSKirti Wankhede mdev_state = mdev_get_drvdata(mdev); 9459d1a546cSKirti Wankhede if (!mdev_state) 9469d1a546cSKirti Wankhede return -EINVAL; 9479d1a546cSKirti Wankhede 9489d1a546cSKirti Wankhede mutex_lock(&mdev_state->ops_lock); 9499d1a546cSKirti Wankhede switch (index) { 9509d1a546cSKirti Wankhede case VFIO_PCI_INTX_IRQ_INDEX: 9519d1a546cSKirti Wankhede switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) { 9529d1a546cSKirti Wankhede case VFIO_IRQ_SET_ACTION_MASK: 9539d1a546cSKirti Wankhede case VFIO_IRQ_SET_ACTION_UNMASK: 9549d1a546cSKirti Wankhede break; 9559d1a546cSKirti Wankhede case VFIO_IRQ_SET_ACTION_TRIGGER: 9569d1a546cSKirti Wankhede { 9579d1a546cSKirti Wankhede if (flags & VFIO_IRQ_SET_DATA_NONE) { 9589d1a546cSKirti Wankhede pr_info("%s: disable INTx\n", __func__); 9599d1a546cSKirti Wankhede if (mdev_state->intx_evtfd) 9609d1a546cSKirti Wankhede eventfd_ctx_put(mdev_state->intx_evtfd); 9619d1a546cSKirti Wankhede break; 9629d1a546cSKirti Wankhede } 9639d1a546cSKirti Wankhede 9649d1a546cSKirti Wankhede if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { 9659d1a546cSKirti Wankhede int fd = *(int *)data; 9669d1a546cSKirti Wankhede 9679d1a546cSKirti Wankhede if (fd > 0) { 9689d1a546cSKirti Wankhede struct eventfd_ctx *evt; 9699d1a546cSKirti Wankhede 9709d1a546cSKirti Wankhede evt = eventfd_ctx_fdget(fd); 9719d1a546cSKirti Wankhede if (IS_ERR(evt)) { 9729d1a546cSKirti Wankhede ret = PTR_ERR(evt); 9739d1a546cSKirti Wankhede break; 9749d1a546cSKirti Wankhede } 9759d1a546cSKirti Wankhede mdev_state->intx_evtfd = evt; 9769d1a546cSKirti Wankhede mdev_state->irq_fd = fd; 9779d1a546cSKirti Wankhede mdev_state->irq_index = index; 9789d1a546cSKirti Wankhede break; 9799d1a546cSKirti Wankhede } 9809d1a546cSKirti Wankhede } 9819d1a546cSKirti Wankhede break; 9829d1a546cSKirti Wankhede } 9839d1a546cSKirti Wankhede } 9849d1a546cSKirti Wankhede break; 9859d1a546cSKirti Wankhede case VFIO_PCI_MSI_IRQ_INDEX: 9869d1a546cSKirti Wankhede switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) { 9879d1a546cSKirti Wankhede case VFIO_IRQ_SET_ACTION_MASK: 9889d1a546cSKirti Wankhede case VFIO_IRQ_SET_ACTION_UNMASK: 9899d1a546cSKirti Wankhede break; 9909d1a546cSKirti Wankhede case VFIO_IRQ_SET_ACTION_TRIGGER: 9919d1a546cSKirti Wankhede if (flags & VFIO_IRQ_SET_DATA_NONE) { 9929d1a546cSKirti Wankhede if (mdev_state->msi_evtfd) 9939d1a546cSKirti Wankhede eventfd_ctx_put(mdev_state->msi_evtfd); 9949d1a546cSKirti Wankhede pr_info("%s: disable MSI\n", __func__); 9959d1a546cSKirti Wankhede mdev_state->irq_index = VFIO_PCI_INTX_IRQ_INDEX; 9969d1a546cSKirti Wankhede break; 9979d1a546cSKirti Wankhede } 9989d1a546cSKirti Wankhede if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { 9999d1a546cSKirti Wankhede int fd = *(int *)data; 10009d1a546cSKirti Wankhede struct eventfd_ctx *evt; 10019d1a546cSKirti Wankhede 10029d1a546cSKirti Wankhede if (fd <= 0) 10039d1a546cSKirti Wankhede break; 10049d1a546cSKirti Wankhede 10059d1a546cSKirti Wankhede if (mdev_state->msi_evtfd) 10069d1a546cSKirti Wankhede break; 10079d1a546cSKirti Wankhede 10089d1a546cSKirti Wankhede evt = eventfd_ctx_fdget(fd); 10099d1a546cSKirti Wankhede if (IS_ERR(evt)) { 10109d1a546cSKirti Wankhede ret = PTR_ERR(evt); 10119d1a546cSKirti Wankhede break; 10129d1a546cSKirti Wankhede } 10139d1a546cSKirti Wankhede mdev_state->msi_evtfd = evt; 10149d1a546cSKirti Wankhede mdev_state->irq_fd = fd; 10159d1a546cSKirti Wankhede mdev_state->irq_index = index; 10169d1a546cSKirti Wankhede } 10179d1a546cSKirti Wankhede break; 10189d1a546cSKirti Wankhede } 10199d1a546cSKirti Wankhede break; 10209d1a546cSKirti Wankhede case VFIO_PCI_MSIX_IRQ_INDEX: 10219d1a546cSKirti Wankhede pr_info("%s: MSIX_IRQ\n", __func__); 10229d1a546cSKirti Wankhede break; 10239d1a546cSKirti Wankhede case VFIO_PCI_ERR_IRQ_INDEX: 10249d1a546cSKirti Wankhede pr_info("%s: ERR_IRQ\n", __func__); 10259d1a546cSKirti Wankhede break; 10269d1a546cSKirti Wankhede case VFIO_PCI_REQ_IRQ_INDEX: 10279d1a546cSKirti Wankhede pr_info("%s: REQ_IRQ\n", __func__); 10289d1a546cSKirti Wankhede break; 10299d1a546cSKirti Wankhede } 10309d1a546cSKirti Wankhede 10319d1a546cSKirti Wankhede mutex_unlock(&mdev_state->ops_lock); 10329d1a546cSKirti Wankhede return ret; 10339d1a546cSKirti Wankhede } 10349d1a546cSKirti Wankhede 10359d1a546cSKirti Wankhede static int mtty_trigger_interrupt(uuid_le uuid) 10369d1a546cSKirti Wankhede { 10379d1a546cSKirti Wankhede int ret = -1; 10389d1a546cSKirti Wankhede struct mdev_state *mdev_state; 10399d1a546cSKirti Wankhede 10409d1a546cSKirti Wankhede mdev_state = find_mdev_state_by_uuid(uuid); 10419d1a546cSKirti Wankhede 10429d1a546cSKirti Wankhede if (!mdev_state) { 10439d1a546cSKirti Wankhede pr_info("%s: mdev not found\n", __func__); 10449d1a546cSKirti Wankhede return -EINVAL; 10459d1a546cSKirti Wankhede } 10469d1a546cSKirti Wankhede 10479d1a546cSKirti Wankhede if ((mdev_state->irq_index == VFIO_PCI_MSI_IRQ_INDEX) && 10489d1a546cSKirti Wankhede (!mdev_state->msi_evtfd)) 10499d1a546cSKirti Wankhede return -EINVAL; 10509d1a546cSKirti Wankhede else if ((mdev_state->irq_index == VFIO_PCI_INTX_IRQ_INDEX) && 10519d1a546cSKirti Wankhede (!mdev_state->intx_evtfd)) { 10529d1a546cSKirti Wankhede pr_info("%s: Intr eventfd not found\n", __func__); 10539d1a546cSKirti Wankhede return -EINVAL; 10549d1a546cSKirti Wankhede } 10559d1a546cSKirti Wankhede 10569d1a546cSKirti Wankhede if (mdev_state->irq_index == VFIO_PCI_MSI_IRQ_INDEX) 10579d1a546cSKirti Wankhede ret = eventfd_signal(mdev_state->msi_evtfd, 1); 10589d1a546cSKirti Wankhede else 10599d1a546cSKirti Wankhede ret = eventfd_signal(mdev_state->intx_evtfd, 1); 10609d1a546cSKirti Wankhede 10619d1a546cSKirti Wankhede #if defined(DEBUG_INTR) 10629d1a546cSKirti Wankhede pr_info("Intx triggered\n"); 10639d1a546cSKirti Wankhede #endif 10649d1a546cSKirti Wankhede if (ret != 1) 10659d1a546cSKirti Wankhede pr_err("%s: eventfd signal failed (%d)\n", __func__, ret); 10669d1a546cSKirti Wankhede 10679d1a546cSKirti Wankhede return ret; 10689d1a546cSKirti Wankhede } 10699d1a546cSKirti Wankhede 10709d1a546cSKirti Wankhede int mtty_get_region_info(struct mdev_device *mdev, 10719d1a546cSKirti Wankhede struct vfio_region_info *region_info, 10729d1a546cSKirti Wankhede u16 *cap_type_id, void **cap_type) 10739d1a546cSKirti Wankhede { 10749d1a546cSKirti Wankhede unsigned int size = 0; 10759d1a546cSKirti Wankhede struct mdev_state *mdev_state; 10765c677869SDan Carpenter u32 bar_index; 10779d1a546cSKirti Wankhede 10789d1a546cSKirti Wankhede if (!mdev) 10799d1a546cSKirti Wankhede return -EINVAL; 10809d1a546cSKirti Wankhede 10819d1a546cSKirti Wankhede mdev_state = mdev_get_drvdata(mdev); 10829d1a546cSKirti Wankhede if (!mdev_state) 10839d1a546cSKirti Wankhede return -EINVAL; 10849d1a546cSKirti Wankhede 10859d1a546cSKirti Wankhede bar_index = region_info->index; 10865c677869SDan Carpenter if (bar_index >= VFIO_PCI_NUM_REGIONS) 10875c677869SDan Carpenter return -EINVAL; 10885c677869SDan Carpenter 10895c677869SDan Carpenter mutex_lock(&mdev_state->ops_lock); 10909d1a546cSKirti Wankhede 10919d1a546cSKirti Wankhede switch (bar_index) { 10929d1a546cSKirti Wankhede case VFIO_PCI_CONFIG_REGION_INDEX: 10939d1a546cSKirti Wankhede size = MTTY_CONFIG_SPACE_SIZE; 10949d1a546cSKirti Wankhede break; 10959d1a546cSKirti Wankhede case VFIO_PCI_BAR0_REGION_INDEX: 10969d1a546cSKirti Wankhede size = MTTY_IO_BAR_SIZE; 10979d1a546cSKirti Wankhede break; 10989d1a546cSKirti Wankhede case VFIO_PCI_BAR1_REGION_INDEX: 10999d1a546cSKirti Wankhede if (mdev_state->nr_ports == 2) 11009d1a546cSKirti Wankhede size = MTTY_IO_BAR_SIZE; 11019d1a546cSKirti Wankhede break; 11029d1a546cSKirti Wankhede default: 11039d1a546cSKirti Wankhede size = 0; 11049d1a546cSKirti Wankhede break; 11059d1a546cSKirti Wankhede } 11069d1a546cSKirti Wankhede 11079d1a546cSKirti Wankhede mdev_state->region_info[bar_index].size = size; 11089d1a546cSKirti Wankhede mdev_state->region_info[bar_index].vfio_offset = 11099d1a546cSKirti Wankhede MTTY_VFIO_PCI_INDEX_TO_OFFSET(bar_index); 11109d1a546cSKirti Wankhede 11119d1a546cSKirti Wankhede region_info->size = size; 11129d1a546cSKirti Wankhede region_info->offset = MTTY_VFIO_PCI_INDEX_TO_OFFSET(bar_index); 11139d1a546cSKirti Wankhede region_info->flags = VFIO_REGION_INFO_FLAG_READ | 11149d1a546cSKirti Wankhede VFIO_REGION_INFO_FLAG_WRITE; 11159d1a546cSKirti Wankhede mutex_unlock(&mdev_state->ops_lock); 11169d1a546cSKirti Wankhede return 0; 11179d1a546cSKirti Wankhede } 11189d1a546cSKirti Wankhede 11199d1a546cSKirti Wankhede int mtty_get_irq_info(struct mdev_device *mdev, struct vfio_irq_info *irq_info) 11209d1a546cSKirti Wankhede { 11219d1a546cSKirti Wankhede switch (irq_info->index) { 11229d1a546cSKirti Wankhede case VFIO_PCI_INTX_IRQ_INDEX: 11239d1a546cSKirti Wankhede case VFIO_PCI_MSI_IRQ_INDEX: 11249d1a546cSKirti Wankhede case VFIO_PCI_REQ_IRQ_INDEX: 11259d1a546cSKirti Wankhede break; 11269d1a546cSKirti Wankhede 11279d1a546cSKirti Wankhede default: 11289d1a546cSKirti Wankhede return -EINVAL; 11299d1a546cSKirti Wankhede } 11309d1a546cSKirti Wankhede 11319d1a546cSKirti Wankhede irq_info->flags = VFIO_IRQ_INFO_EVENTFD; 11329d1a546cSKirti Wankhede irq_info->count = 1; 11339d1a546cSKirti Wankhede 11349d1a546cSKirti Wankhede if (irq_info->index == VFIO_PCI_INTX_IRQ_INDEX) 11359d1a546cSKirti Wankhede irq_info->flags |= (VFIO_IRQ_INFO_MASKABLE | 11369d1a546cSKirti Wankhede VFIO_IRQ_INFO_AUTOMASKED); 11379d1a546cSKirti Wankhede else 11389d1a546cSKirti Wankhede irq_info->flags |= VFIO_IRQ_INFO_NORESIZE; 11399d1a546cSKirti Wankhede 11409d1a546cSKirti Wankhede return 0; 11419d1a546cSKirti Wankhede } 11429d1a546cSKirti Wankhede 11439d1a546cSKirti Wankhede int mtty_get_device_info(struct mdev_device *mdev, 11449d1a546cSKirti Wankhede struct vfio_device_info *dev_info) 11459d1a546cSKirti Wankhede { 11469d1a546cSKirti Wankhede dev_info->flags = VFIO_DEVICE_FLAGS_PCI; 11479d1a546cSKirti Wankhede dev_info->num_regions = VFIO_PCI_NUM_REGIONS; 11489d1a546cSKirti Wankhede dev_info->num_irqs = VFIO_PCI_NUM_IRQS; 11499d1a546cSKirti Wankhede 11509d1a546cSKirti Wankhede return 0; 11519d1a546cSKirti Wankhede } 11529d1a546cSKirti Wankhede 11539d1a546cSKirti Wankhede static long mtty_ioctl(struct mdev_device *mdev, unsigned int cmd, 11549d1a546cSKirti Wankhede unsigned long arg) 11559d1a546cSKirti Wankhede { 11569d1a546cSKirti Wankhede int ret = 0; 11579d1a546cSKirti Wankhede unsigned long minsz; 11589d1a546cSKirti Wankhede struct mdev_state *mdev_state; 11599d1a546cSKirti Wankhede 11609d1a546cSKirti Wankhede if (!mdev) 11619d1a546cSKirti Wankhede return -EINVAL; 11629d1a546cSKirti Wankhede 11639d1a546cSKirti Wankhede mdev_state = mdev_get_drvdata(mdev); 11649d1a546cSKirti Wankhede if (!mdev_state) 11659d1a546cSKirti Wankhede return -ENODEV; 11669d1a546cSKirti Wankhede 11679d1a546cSKirti Wankhede switch (cmd) { 11689d1a546cSKirti Wankhede case VFIO_DEVICE_GET_INFO: 11699d1a546cSKirti Wankhede { 11709d1a546cSKirti Wankhede struct vfio_device_info info; 11719d1a546cSKirti Wankhede 11729d1a546cSKirti Wankhede minsz = offsetofend(struct vfio_device_info, num_irqs); 11739d1a546cSKirti Wankhede 11749d1a546cSKirti Wankhede if (copy_from_user(&info, (void __user *)arg, minsz)) 11759d1a546cSKirti Wankhede return -EFAULT; 11769d1a546cSKirti Wankhede 11779d1a546cSKirti Wankhede if (info.argsz < minsz) 11789d1a546cSKirti Wankhede return -EINVAL; 11799d1a546cSKirti Wankhede 11809d1a546cSKirti Wankhede ret = mtty_get_device_info(mdev, &info); 11819d1a546cSKirti Wankhede if (ret) 11829d1a546cSKirti Wankhede return ret; 11839d1a546cSKirti Wankhede 11849d1a546cSKirti Wankhede memcpy(&mdev_state->dev_info, &info, sizeof(info)); 11859d1a546cSKirti Wankhede 11866ed0993aSDan Carpenter if (copy_to_user((void __user *)arg, &info, minsz)) 11876ed0993aSDan Carpenter return -EFAULT; 11886ed0993aSDan Carpenter 11896ed0993aSDan Carpenter return 0; 11909d1a546cSKirti Wankhede } 11919d1a546cSKirti Wankhede case VFIO_DEVICE_GET_REGION_INFO: 11929d1a546cSKirti Wankhede { 11939d1a546cSKirti Wankhede struct vfio_region_info info; 11949d1a546cSKirti Wankhede u16 cap_type_id = 0; 11959d1a546cSKirti Wankhede void *cap_type = NULL; 11969d1a546cSKirti Wankhede 11979d1a546cSKirti Wankhede minsz = offsetofend(struct vfio_region_info, offset); 11989d1a546cSKirti Wankhede 11999d1a546cSKirti Wankhede if (copy_from_user(&info, (void __user *)arg, minsz)) 12009d1a546cSKirti Wankhede return -EFAULT; 12019d1a546cSKirti Wankhede 12029d1a546cSKirti Wankhede if (info.argsz < minsz) 12039d1a546cSKirti Wankhede return -EINVAL; 12049d1a546cSKirti Wankhede 12059d1a546cSKirti Wankhede ret = mtty_get_region_info(mdev, &info, &cap_type_id, 12069d1a546cSKirti Wankhede &cap_type); 12079d1a546cSKirti Wankhede if (ret) 12089d1a546cSKirti Wankhede return ret; 12099d1a546cSKirti Wankhede 12106ed0993aSDan Carpenter if (copy_to_user((void __user *)arg, &info, minsz)) 12116ed0993aSDan Carpenter return -EFAULT; 12126ed0993aSDan Carpenter 12136ed0993aSDan Carpenter return 0; 12149d1a546cSKirti Wankhede } 12159d1a546cSKirti Wankhede 12169d1a546cSKirti Wankhede case VFIO_DEVICE_GET_IRQ_INFO: 12179d1a546cSKirti Wankhede { 12189d1a546cSKirti Wankhede struct vfio_irq_info info; 12199d1a546cSKirti Wankhede 12209d1a546cSKirti Wankhede minsz = offsetofend(struct vfio_irq_info, count); 12219d1a546cSKirti Wankhede 12229d1a546cSKirti Wankhede if (copy_from_user(&info, (void __user *)arg, minsz)) 12239d1a546cSKirti Wankhede return -EFAULT; 12249d1a546cSKirti Wankhede 12259d1a546cSKirti Wankhede if ((info.argsz < minsz) || 12269d1a546cSKirti Wankhede (info.index >= mdev_state->dev_info.num_irqs)) 12279d1a546cSKirti Wankhede return -EINVAL; 12289d1a546cSKirti Wankhede 12299d1a546cSKirti Wankhede ret = mtty_get_irq_info(mdev, &info); 12309d1a546cSKirti Wankhede if (ret) 12319d1a546cSKirti Wankhede return ret; 12329d1a546cSKirti Wankhede 12336ed0993aSDan Carpenter if (copy_to_user((void __user *)arg, &info, minsz)) 12346ed0993aSDan Carpenter return -EFAULT; 12356ed0993aSDan Carpenter 12366ed0993aSDan Carpenter return 0; 12379d1a546cSKirti Wankhede } 12389d1a546cSKirti Wankhede case VFIO_DEVICE_SET_IRQS: 12399d1a546cSKirti Wankhede { 12409d1a546cSKirti Wankhede struct vfio_irq_set hdr; 12419d1a546cSKirti Wankhede u8 *data = NULL, *ptr = NULL; 12429d1a546cSKirti Wankhede size_t data_size = 0; 12439d1a546cSKirti Wankhede 12449d1a546cSKirti Wankhede minsz = offsetofend(struct vfio_irq_set, count); 12459d1a546cSKirti Wankhede 12469d1a546cSKirti Wankhede if (copy_from_user(&hdr, (void __user *)arg, minsz)) 12479d1a546cSKirti Wankhede return -EFAULT; 12489d1a546cSKirti Wankhede 12499d1a546cSKirti Wankhede ret = vfio_set_irqs_validate_and_prepare(&hdr, 12509d1a546cSKirti Wankhede mdev_state->dev_info.num_irqs, 12519d1a546cSKirti Wankhede VFIO_PCI_NUM_IRQS, 12529d1a546cSKirti Wankhede &data_size); 12539d1a546cSKirti Wankhede if (ret) 12549d1a546cSKirti Wankhede return ret; 12559d1a546cSKirti Wankhede 12569d1a546cSKirti Wankhede if (data_size) { 12579d1a546cSKirti Wankhede ptr = data = memdup_user((void __user *)(arg + minsz), 12589d1a546cSKirti Wankhede data_size); 12599d1a546cSKirti Wankhede if (IS_ERR(data)) 12609d1a546cSKirti Wankhede return PTR_ERR(data); 12619d1a546cSKirti Wankhede } 12629d1a546cSKirti Wankhede 12639d1a546cSKirti Wankhede ret = mtty_set_irqs(mdev, hdr.flags, hdr.index, hdr.start, 12649d1a546cSKirti Wankhede hdr.count, data); 12659d1a546cSKirti Wankhede 12669d1a546cSKirti Wankhede kfree(ptr); 12679d1a546cSKirti Wankhede return ret; 12689d1a546cSKirti Wankhede } 12699d1a546cSKirti Wankhede case VFIO_DEVICE_RESET: 12709d1a546cSKirti Wankhede return mtty_reset(mdev); 12719d1a546cSKirti Wankhede } 12729d1a546cSKirti Wankhede return -ENOTTY; 12739d1a546cSKirti Wankhede } 12749d1a546cSKirti Wankhede 12759d1a546cSKirti Wankhede int mtty_open(struct mdev_device *mdev) 12769d1a546cSKirti Wankhede { 12779d1a546cSKirti Wankhede pr_info("%s\n", __func__); 12789d1a546cSKirti Wankhede return 0; 12799d1a546cSKirti Wankhede } 12809d1a546cSKirti Wankhede 12819d1a546cSKirti Wankhede void mtty_close(struct mdev_device *mdev) 12829d1a546cSKirti Wankhede { 12839d1a546cSKirti Wankhede pr_info("%s\n", __func__); 12849d1a546cSKirti Wankhede } 12859d1a546cSKirti Wankhede 12869d1a546cSKirti Wankhede static ssize_t 12879d1a546cSKirti Wankhede sample_mtty_dev_show(struct device *dev, struct device_attribute *attr, 12889d1a546cSKirti Wankhede char *buf) 12899d1a546cSKirti Wankhede { 12909d1a546cSKirti Wankhede return sprintf(buf, "This is phy device\n"); 12919d1a546cSKirti Wankhede } 12929d1a546cSKirti Wankhede 12939d1a546cSKirti Wankhede static DEVICE_ATTR_RO(sample_mtty_dev); 12949d1a546cSKirti Wankhede 12959d1a546cSKirti Wankhede static struct attribute *mtty_dev_attrs[] = { 12969d1a546cSKirti Wankhede &dev_attr_sample_mtty_dev.attr, 12979d1a546cSKirti Wankhede NULL, 12989d1a546cSKirti Wankhede }; 12999d1a546cSKirti Wankhede 13009d1a546cSKirti Wankhede static const struct attribute_group mtty_dev_group = { 13019d1a546cSKirti Wankhede .name = "mtty_dev", 13029d1a546cSKirti Wankhede .attrs = mtty_dev_attrs, 13039d1a546cSKirti Wankhede }; 13049d1a546cSKirti Wankhede 13059d1a546cSKirti Wankhede const struct attribute_group *mtty_dev_groups[] = { 13069d1a546cSKirti Wankhede &mtty_dev_group, 13079d1a546cSKirti Wankhede NULL, 13089d1a546cSKirti Wankhede }; 13099d1a546cSKirti Wankhede 13109d1a546cSKirti Wankhede static ssize_t 13119d1a546cSKirti Wankhede sample_mdev_dev_show(struct device *dev, struct device_attribute *attr, 13129d1a546cSKirti Wankhede char *buf) 13139d1a546cSKirti Wankhede { 131499e3123eSAlex Williamson if (mdev_from_dev(dev)) 131599e3123eSAlex Williamson return sprintf(buf, "This is MDEV %s\n", dev_name(dev)); 13169d1a546cSKirti Wankhede 13179d1a546cSKirti Wankhede return sprintf(buf, "\n"); 13189d1a546cSKirti Wankhede } 13199d1a546cSKirti Wankhede 13209d1a546cSKirti Wankhede static DEVICE_ATTR_RO(sample_mdev_dev); 13219d1a546cSKirti Wankhede 13229d1a546cSKirti Wankhede static struct attribute *mdev_dev_attrs[] = { 13239d1a546cSKirti Wankhede &dev_attr_sample_mdev_dev.attr, 13249d1a546cSKirti Wankhede NULL, 13259d1a546cSKirti Wankhede }; 13269d1a546cSKirti Wankhede 13279d1a546cSKirti Wankhede static const struct attribute_group mdev_dev_group = { 13289d1a546cSKirti Wankhede .name = "vendor", 13299d1a546cSKirti Wankhede .attrs = mdev_dev_attrs, 13309d1a546cSKirti Wankhede }; 13319d1a546cSKirti Wankhede 13329d1a546cSKirti Wankhede const struct attribute_group *mdev_dev_groups[] = { 13339d1a546cSKirti Wankhede &mdev_dev_group, 13349d1a546cSKirti Wankhede NULL, 13359d1a546cSKirti Wankhede }; 13369d1a546cSKirti Wankhede 13379d1a546cSKirti Wankhede static ssize_t 13389d1a546cSKirti Wankhede name_show(struct kobject *kobj, struct device *dev, char *buf) 13399d1a546cSKirti Wankhede { 13409d1a546cSKirti Wankhede char name[MTTY_STRING_LEN]; 13419d1a546cSKirti Wankhede int i; 13429d1a546cSKirti Wankhede const char *name_str[2] = {"Single port serial", "Dual port serial"}; 13439d1a546cSKirti Wankhede 13449d1a546cSKirti Wankhede for (i = 0; i < 2; i++) { 13459d1a546cSKirti Wankhede snprintf(name, MTTY_STRING_LEN, "%s-%d", 13469d1a546cSKirti Wankhede dev_driver_string(dev), i + 1); 13479d1a546cSKirti Wankhede if (!strcmp(kobj->name, name)) 13489d1a546cSKirti Wankhede return sprintf(buf, "%s\n", name_str[i]); 13499d1a546cSKirti Wankhede } 13509d1a546cSKirti Wankhede 13519d1a546cSKirti Wankhede return -EINVAL; 13529d1a546cSKirti Wankhede } 13539d1a546cSKirti Wankhede 13549d1a546cSKirti Wankhede MDEV_TYPE_ATTR_RO(name); 13559d1a546cSKirti Wankhede 13569d1a546cSKirti Wankhede static ssize_t 13579d1a546cSKirti Wankhede available_instances_show(struct kobject *kobj, struct device *dev, char *buf) 13589d1a546cSKirti Wankhede { 13599d1a546cSKirti Wankhede char name[MTTY_STRING_LEN]; 13609d1a546cSKirti Wankhede int i; 13619d1a546cSKirti Wankhede struct mdev_state *mds; 13629d1a546cSKirti Wankhede int ports = 0, used = 0; 13639d1a546cSKirti Wankhede 13649d1a546cSKirti Wankhede for (i = 0; i < 2; i++) { 13659d1a546cSKirti Wankhede snprintf(name, MTTY_STRING_LEN, "%s-%d", 13669d1a546cSKirti Wankhede dev_driver_string(dev), i + 1); 13679d1a546cSKirti Wankhede if (!strcmp(kobj->name, name)) { 13689d1a546cSKirti Wankhede ports = i + 1; 13699d1a546cSKirti Wankhede break; 13709d1a546cSKirti Wankhede } 13719d1a546cSKirti Wankhede } 13729d1a546cSKirti Wankhede 13739d1a546cSKirti Wankhede if (!ports) 13749d1a546cSKirti Wankhede return -EINVAL; 13759d1a546cSKirti Wankhede 13769d1a546cSKirti Wankhede list_for_each_entry(mds, &mdev_devices_list, next) 13779d1a546cSKirti Wankhede used += mds->nr_ports; 13789d1a546cSKirti Wankhede 13799d1a546cSKirti Wankhede return sprintf(buf, "%d\n", (MAX_MTTYS - used)/ports); 13809d1a546cSKirti Wankhede } 13819d1a546cSKirti Wankhede 13829d1a546cSKirti Wankhede MDEV_TYPE_ATTR_RO(available_instances); 13839d1a546cSKirti Wankhede 13849d1a546cSKirti Wankhede 13859d1a546cSKirti Wankhede static ssize_t device_api_show(struct kobject *kobj, struct device *dev, 13869d1a546cSKirti Wankhede char *buf) 13879d1a546cSKirti Wankhede { 13889d1a546cSKirti Wankhede return sprintf(buf, "%s\n", VFIO_DEVICE_API_PCI_STRING); 13899d1a546cSKirti Wankhede } 13909d1a546cSKirti Wankhede 13919d1a546cSKirti Wankhede MDEV_TYPE_ATTR_RO(device_api); 13929d1a546cSKirti Wankhede 13939d1a546cSKirti Wankhede static struct attribute *mdev_types_attrs[] = { 13949d1a546cSKirti Wankhede &mdev_type_attr_name.attr, 13959d1a546cSKirti Wankhede &mdev_type_attr_device_api.attr, 13969d1a546cSKirti Wankhede &mdev_type_attr_available_instances.attr, 13979d1a546cSKirti Wankhede NULL, 13989d1a546cSKirti Wankhede }; 13999d1a546cSKirti Wankhede 14009d1a546cSKirti Wankhede static struct attribute_group mdev_type_group1 = { 14019d1a546cSKirti Wankhede .name = "1", 14029d1a546cSKirti Wankhede .attrs = mdev_types_attrs, 14039d1a546cSKirti Wankhede }; 14049d1a546cSKirti Wankhede 14059d1a546cSKirti Wankhede static struct attribute_group mdev_type_group2 = { 14069d1a546cSKirti Wankhede .name = "2", 14079d1a546cSKirti Wankhede .attrs = mdev_types_attrs, 14089d1a546cSKirti Wankhede }; 14099d1a546cSKirti Wankhede 14109d1a546cSKirti Wankhede struct attribute_group *mdev_type_groups[] = { 14119d1a546cSKirti Wankhede &mdev_type_group1, 14129d1a546cSKirti Wankhede &mdev_type_group2, 14139d1a546cSKirti Wankhede NULL, 14149d1a546cSKirti Wankhede }; 14159d1a546cSKirti Wankhede 141679d40370SBhumika Goyal static const struct mdev_parent_ops mdev_fops = { 14179d1a546cSKirti Wankhede .owner = THIS_MODULE, 14189d1a546cSKirti Wankhede .dev_attr_groups = mtty_dev_groups, 14199d1a546cSKirti Wankhede .mdev_attr_groups = mdev_dev_groups, 14209d1a546cSKirti Wankhede .supported_type_groups = mdev_type_groups, 14219d1a546cSKirti Wankhede .create = mtty_create, 14229d1a546cSKirti Wankhede .remove = mtty_remove, 14239d1a546cSKirti Wankhede .open = mtty_open, 14249d1a546cSKirti Wankhede .release = mtty_close, 14259d1a546cSKirti Wankhede .read = mtty_read, 14269d1a546cSKirti Wankhede .write = mtty_write, 14279d1a546cSKirti Wankhede .ioctl = mtty_ioctl, 14289d1a546cSKirti Wankhede }; 14299d1a546cSKirti Wankhede 14309d1a546cSKirti Wankhede static void mtty_device_release(struct device *dev) 14319d1a546cSKirti Wankhede { 14329d1a546cSKirti Wankhede dev_dbg(dev, "mtty: released\n"); 14339d1a546cSKirti Wankhede } 14349d1a546cSKirti Wankhede 14359d1a546cSKirti Wankhede static int __init mtty_dev_init(void) 14369d1a546cSKirti Wankhede { 14379d1a546cSKirti Wankhede int ret = 0; 14389d1a546cSKirti Wankhede 14399d1a546cSKirti Wankhede pr_info("mtty_dev: %s\n", __func__); 14409d1a546cSKirti Wankhede 14419d1a546cSKirti Wankhede memset(&mtty_dev, 0, sizeof(mtty_dev)); 14429d1a546cSKirti Wankhede 14439d1a546cSKirti Wankhede idr_init(&mtty_dev.vd_idr); 14449d1a546cSKirti Wankhede 14459d1a546cSKirti Wankhede ret = alloc_chrdev_region(&mtty_dev.vd_devt, 0, MINORMASK, MTTY_NAME); 14469d1a546cSKirti Wankhede 14479d1a546cSKirti Wankhede if (ret < 0) { 14489d1a546cSKirti Wankhede pr_err("Error: failed to register mtty_dev, err:%d\n", ret); 14499d1a546cSKirti Wankhede return ret; 14509d1a546cSKirti Wankhede } 14519d1a546cSKirti Wankhede 14529d1a546cSKirti Wankhede cdev_init(&mtty_dev.vd_cdev, &vd_fops); 14539d1a546cSKirti Wankhede cdev_add(&mtty_dev.vd_cdev, mtty_dev.vd_devt, MINORMASK); 14549d1a546cSKirti Wankhede 14559d1a546cSKirti Wankhede pr_info("major_number:%d\n", MAJOR(mtty_dev.vd_devt)); 14569d1a546cSKirti Wankhede 14579d1a546cSKirti Wankhede mtty_dev.vd_class = class_create(THIS_MODULE, MTTY_CLASS_NAME); 14589d1a546cSKirti Wankhede 14599d1a546cSKirti Wankhede if (IS_ERR(mtty_dev.vd_class)) { 14609d1a546cSKirti Wankhede pr_err("Error: failed to register mtty_dev class\n"); 1461d293dbaaSDan Carpenter ret = PTR_ERR(mtty_dev.vd_class); 14629d1a546cSKirti Wankhede goto failed1; 14639d1a546cSKirti Wankhede } 14649d1a546cSKirti Wankhede 14659d1a546cSKirti Wankhede mtty_dev.dev.class = mtty_dev.vd_class; 14669d1a546cSKirti Wankhede mtty_dev.dev.release = mtty_device_release; 14679d1a546cSKirti Wankhede dev_set_name(&mtty_dev.dev, "%s", MTTY_NAME); 14689d1a546cSKirti Wankhede 14699d1a546cSKirti Wankhede ret = device_register(&mtty_dev.dev); 14709d1a546cSKirti Wankhede if (ret) 14719d1a546cSKirti Wankhede goto failed2; 14729d1a546cSKirti Wankhede 1473d293dbaaSDan Carpenter ret = mdev_register_device(&mtty_dev.dev, &mdev_fops); 1474d293dbaaSDan Carpenter if (ret) 14759d1a546cSKirti Wankhede goto failed3; 14769d1a546cSKirti Wankhede 14779d1a546cSKirti Wankhede mutex_init(&mdev_list_lock); 14789d1a546cSKirti Wankhede INIT_LIST_HEAD(&mdev_devices_list); 14799d1a546cSKirti Wankhede 14809d1a546cSKirti Wankhede goto all_done; 14819d1a546cSKirti Wankhede 14829d1a546cSKirti Wankhede failed3: 14839d1a546cSKirti Wankhede 14849d1a546cSKirti Wankhede device_unregister(&mtty_dev.dev); 14859d1a546cSKirti Wankhede failed2: 14869d1a546cSKirti Wankhede class_destroy(mtty_dev.vd_class); 14879d1a546cSKirti Wankhede 14889d1a546cSKirti Wankhede failed1: 14899d1a546cSKirti Wankhede cdev_del(&mtty_dev.vd_cdev); 14909d1a546cSKirti Wankhede unregister_chrdev_region(mtty_dev.vd_devt, MINORMASK); 14919d1a546cSKirti Wankhede 14929d1a546cSKirti Wankhede all_done: 14939d1a546cSKirti Wankhede return ret; 14949d1a546cSKirti Wankhede } 14959d1a546cSKirti Wankhede 14969d1a546cSKirti Wankhede static void __exit mtty_dev_exit(void) 14979d1a546cSKirti Wankhede { 14989d1a546cSKirti Wankhede mtty_dev.dev.bus = NULL; 14999d1a546cSKirti Wankhede mdev_unregister_device(&mtty_dev.dev); 15009d1a546cSKirti Wankhede 15019d1a546cSKirti Wankhede device_unregister(&mtty_dev.dev); 15029d1a546cSKirti Wankhede idr_destroy(&mtty_dev.vd_idr); 15039d1a546cSKirti Wankhede cdev_del(&mtty_dev.vd_cdev); 15049d1a546cSKirti Wankhede unregister_chrdev_region(mtty_dev.vd_devt, MINORMASK); 15059d1a546cSKirti Wankhede class_destroy(mtty_dev.vd_class); 15069d1a546cSKirti Wankhede mtty_dev.vd_class = NULL; 15079d1a546cSKirti Wankhede pr_info("mtty_dev: Unloaded!\n"); 15089d1a546cSKirti Wankhede } 15099d1a546cSKirti Wankhede 15109d1a546cSKirti Wankhede module_init(mtty_dev_init) 15119d1a546cSKirti Wankhede module_exit(mtty_dev_exit) 15129d1a546cSKirti Wankhede 15139d1a546cSKirti Wankhede MODULE_LICENSE("GPL v2"); 15149d1a546cSKirti Wankhede MODULE_INFO(supported, "Test driver that simulate serial port over PCI"); 15159d1a546cSKirti Wankhede MODULE_VERSION(VERSION_STRING); 15169d1a546cSKirti Wankhede MODULE_AUTHOR(DRIVER_AUTHOR); 1517