linux/drivers/misc/mic/host/mic_fops.c
<<
>>
Prefs
   1/*
   2 * Intel MIC Platform Software Stack (MPSS)
   3 *
   4 * Copyright(c) 2013 Intel Corporation.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License, version 2, as
   8 * published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13 * General Public License for more details.
  14 *
  15 * The full GNU General Public License is included in this distribution in
  16 * the file called "COPYING".
  17 *
  18 * Intel MIC Host driver.
  19 *
  20 */
  21#include <linux/poll.h>
  22#include <linux/pci.h>
  23
  24#include <linux/mic_common.h>
  25#include "../common/mic_dev.h"
  26#include "mic_device.h"
  27#include "mic_fops.h"
  28#include "mic_virtio.h"
  29
  30int mic_open(struct inode *inode, struct file *f)
  31{
  32        struct mic_vdev *mvdev;
  33        struct mic_device *mdev = container_of(f->private_data,
  34                struct mic_device, miscdev);
  35
  36        mvdev = kzalloc(sizeof(*mvdev), GFP_KERNEL);
  37        if (!mvdev)
  38                return -ENOMEM;
  39
  40        init_waitqueue_head(&mvdev->waitq);
  41        INIT_LIST_HEAD(&mvdev->list);
  42        mvdev->mdev = mdev;
  43        mvdev->virtio_id = -1;
  44
  45        f->private_data = mvdev;
  46        return 0;
  47}
  48
  49int mic_release(struct inode *inode, struct file *f)
  50{
  51        struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data;
  52
  53        if (-1 != mvdev->virtio_id)
  54                mic_virtio_del_device(mvdev);
  55        f->private_data = NULL;
  56        kfree(mvdev);
  57        return 0;
  58}
  59
  60long mic_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
  61{
  62        struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data;
  63        void __user *argp = (void __user *)arg;
  64        int ret;
  65
  66        switch (cmd) {
  67        case MIC_VIRTIO_ADD_DEVICE:
  68        {
  69                ret = mic_virtio_add_device(mvdev, argp);
  70                if (ret < 0) {
  71                        dev_err(mic_dev(mvdev),
  72                                "%s %d errno ret %d\n",
  73                                __func__, __LINE__, ret);
  74                        return ret;
  75                }
  76                break;
  77        }
  78        case MIC_VIRTIO_COPY_DESC:
  79        {
  80                struct mic_copy_desc copy;
  81
  82                ret = mic_vdev_inited(mvdev);
  83                if (ret)
  84                        return ret;
  85
  86                if (copy_from_user(&copy, argp, sizeof(copy)))
  87                        return -EFAULT;
  88
  89                dev_dbg(mic_dev(mvdev),
  90                        "%s %d === iovcnt 0x%x vr_idx 0x%x update_used %d\n",
  91                        __func__, __LINE__, copy.iovcnt, copy.vr_idx,
  92                        copy.update_used);
  93
  94                ret = mic_virtio_copy_desc(mvdev, &copy);
  95                if (ret < 0) {
  96                        dev_err(mic_dev(mvdev),
  97                                "%s %d errno ret %d\n",
  98                                __func__, __LINE__, ret);
  99                        return ret;
 100                }
 101                if (copy_to_user(
 102                        &((struct mic_copy_desc __user *)argp)->out_len,
 103                        &copy.out_len, sizeof(copy.out_len))) {
 104                        dev_err(mic_dev(mvdev), "%s %d errno ret %d\n",
 105                                __func__, __LINE__, -EFAULT);
 106                        return -EFAULT;
 107                }
 108                break;
 109        }
 110        case MIC_VIRTIO_CONFIG_CHANGE:
 111        {
 112                ret = mic_vdev_inited(mvdev);
 113                if (ret)
 114                        return ret;
 115
 116                ret = mic_virtio_config_change(mvdev, argp);
 117                if (ret < 0) {
 118                        dev_err(mic_dev(mvdev),
 119                                "%s %d errno ret %d\n",
 120                                __func__, __LINE__, ret);
 121                        return ret;
 122                }
 123                break;
 124        }
 125        default:
 126                return -ENOIOCTLCMD;
 127        };
 128        return 0;
 129}
 130
 131/*
 132 * We return POLLIN | POLLOUT from poll when new buffers are enqueued, and
 133 * not when previously enqueued buffers may be available. This means that
 134 * in the card->host (TX) path, when userspace is unblocked by poll it
 135 * must drain all available descriptors or it can stall.
 136 */
 137unsigned int mic_poll(struct file *f, poll_table *wait)
 138{
 139        struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data;
 140        int mask = 0;
 141
 142        poll_wait(f, &mvdev->waitq, wait);
 143
 144        if (mic_vdev_inited(mvdev)) {
 145                mask = POLLERR;
 146        } else if (mvdev->poll_wake) {
 147                mvdev->poll_wake = 0;
 148                mask = POLLIN | POLLOUT;
 149        }
 150
 151        return mask;
 152}
 153
 154static inline int
 155mic_query_offset(struct mic_vdev *mvdev, unsigned long offset,
 156                 unsigned long *size, unsigned long *pa)
 157{
 158        struct mic_device *mdev = mvdev->mdev;
 159        unsigned long start = MIC_DP_SIZE;
 160        int i;
 161
 162        /*
 163         * MMAP interface is as follows:
 164         * offset                               region
 165         * 0x0                                  virtio device_page
 166         * 0x1000                               first vring
 167         * 0x1000 + size of 1st vring           second vring
 168         * ....
 169         */
 170        if (!offset) {
 171                *pa = virt_to_phys(mdev->dp);
 172                *size = MIC_DP_SIZE;
 173                return 0;
 174        }
 175
 176        for (i = 0; i < mvdev->dd->num_vq; i++) {
 177                struct mic_vringh *mvr = &mvdev->mvr[i];
 178                if (offset == start) {
 179                        *pa = virt_to_phys(mvr->vring.va);
 180                        *size = mvr->vring.len;
 181                        return 0;
 182                }
 183                start += mvr->vring.len;
 184        }
 185        return -1;
 186}
 187
 188/*
 189 * Maps the device page and virtio rings to user space for readonly access.
 190 */
 191int
 192mic_mmap(struct file *f, struct vm_area_struct *vma)
 193{
 194        struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data;
 195        unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 196        unsigned long pa, size = vma->vm_end - vma->vm_start, size_rem = size;
 197        int i, err;
 198
 199        err = mic_vdev_inited(mvdev);
 200        if (err)
 201                return err;
 202
 203        if (vma->vm_flags & VM_WRITE)
 204                return -EACCES;
 205
 206        while (size_rem) {
 207                i = mic_query_offset(mvdev, offset, &size, &pa);
 208                if (i < 0)
 209                        return -EINVAL;
 210                err = remap_pfn_range(vma, vma->vm_start + offset,
 211                        pa >> PAGE_SHIFT, size, vma->vm_page_prot);
 212                if (err)
 213                        return err;
 214                dev_dbg(mic_dev(mvdev),
 215                        "%s %d type %d size 0x%lx off 0x%lx pa 0x%lx vma 0x%lx\n",
 216                        __func__, __LINE__, mvdev->virtio_id, size, offset,
 217                        pa, vma->vm_start + offset);
 218                size_rem -= size;
 219                offset += size;
 220        }
 221        return 0;
 222}
 223