root/drivers/gpu/drm/nouveau/nvif/notify.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nvif_notify_put_
  2. nvif_notify_put
  3. nvif_notify_get_
  4. nvif_notify_get
  5. nvif_notify_func
  6. nvif_notify_work
  7. nvif_notify
  8. nvif_notify_fini
  9. nvif_notify_init

   1 /*
   2  * Copyright 2014 Red Hat Inc.
   3  *
   4  * Permission is hereby granted, free of charge, to any person obtaining a
   5  * copy of this software and associated documentation files (the "Software"),
   6  * to deal in the Software without restriction, including without limitation
   7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8  * and/or sell copies of the Software, and to permit persons to whom the
   9  * Software is furnished to do so, subject to the following conditions:
  10  *
  11  * The above copyright notice and this permission notice shall be included in
  12  * all copies or substantial portions of the Software.
  13  *
  14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20  * OTHER DEALINGS IN THE SOFTWARE.
  21  *
  22  * Authors: Ben Skeggs <bskeggs@redhat.com>
  23  */
  24 
  25 #include <nvif/client.h>
  26 #include <nvif/driver.h>
  27 #include <nvif/notify.h>
  28 #include <nvif/object.h>
  29 #include <nvif/ioctl.h>
  30 #include <nvif/event.h>
  31 
  32 static inline int
  33 nvif_notify_put_(struct nvif_notify *notify)
  34 {
  35         struct nvif_object *object = notify->object;
  36         struct {
  37                 struct nvif_ioctl_v0 ioctl;
  38                 struct nvif_ioctl_ntfy_put_v0 ntfy;
  39         } args = {
  40                 .ioctl.type = NVIF_IOCTL_V0_NTFY_PUT,
  41                 .ntfy.index = notify->index,
  42         };
  43 
  44         if (atomic_inc_return(&notify->putcnt) != 1)
  45                 return 0;
  46 
  47         return nvif_object_ioctl(object, &args, sizeof(args), NULL);
  48 }
  49 
  50 int
  51 nvif_notify_put(struct nvif_notify *notify)
  52 {
  53         if (likely(notify->object) &&
  54             test_and_clear_bit(NVIF_NOTIFY_USER, &notify->flags)) {
  55                 int ret = nvif_notify_put_(notify);
  56                 if (test_bit(NVIF_NOTIFY_WORK, &notify->flags))
  57                         flush_work(&notify->work);
  58                 return ret;
  59         }
  60         return 0;
  61 }
  62 
  63 static inline int
  64 nvif_notify_get_(struct nvif_notify *notify)
  65 {
  66         struct nvif_object *object = notify->object;
  67         struct {
  68                 struct nvif_ioctl_v0 ioctl;
  69                 struct nvif_ioctl_ntfy_get_v0 ntfy;
  70         } args = {
  71                 .ioctl.type = NVIF_IOCTL_V0_NTFY_GET,
  72                 .ntfy.index = notify->index,
  73         };
  74 
  75         if (atomic_dec_return(&notify->putcnt) != 0)
  76                 return 0;
  77 
  78         return nvif_object_ioctl(object, &args, sizeof(args), NULL);
  79 }
  80 
  81 int
  82 nvif_notify_get(struct nvif_notify *notify)
  83 {
  84         if (likely(notify->object) &&
  85             !test_and_set_bit(NVIF_NOTIFY_USER, &notify->flags))
  86                 return nvif_notify_get_(notify);
  87         return 0;
  88 }
  89 
  90 static inline int
  91 nvif_notify_func(struct nvif_notify *notify, bool keep)
  92 {
  93         int ret = notify->func(notify);
  94         if (ret == NVIF_NOTIFY_KEEP ||
  95             !test_and_clear_bit(NVIF_NOTIFY_USER, &notify->flags)) {
  96                 if (!keep)
  97                         atomic_dec(&notify->putcnt);
  98                 else
  99                         nvif_notify_get_(notify);
 100         }
 101         return ret;
 102 }
 103 
 104 static void
 105 nvif_notify_work(struct work_struct *work)
 106 {
 107         struct nvif_notify *notify = container_of(work, typeof(*notify), work);
 108         nvif_notify_func(notify, true);
 109 }
 110 
 111 int
 112 nvif_notify(const void *header, u32 length, const void *data, u32 size)
 113 {
 114         struct nvif_notify *notify = NULL;
 115         const union {
 116                 struct nvif_notify_rep_v0 v0;
 117         } *args = header;
 118         int ret = NVIF_NOTIFY_DROP;
 119 
 120         if (length == sizeof(args->v0) && args->v0.version == 0) {
 121                 if (WARN_ON(args->v0.route))
 122                         return NVIF_NOTIFY_DROP;
 123                 notify = (void *)(unsigned long)args->v0.token;
 124         }
 125 
 126         if (!WARN_ON(notify == NULL)) {
 127                 struct nvif_client *client = notify->object->client;
 128                 if (!WARN_ON(notify->size != size)) {
 129                         atomic_inc(&notify->putcnt);
 130                         if (test_bit(NVIF_NOTIFY_WORK, &notify->flags)) {
 131                                 memcpy((void *)notify->data, data, size);
 132                                 schedule_work(&notify->work);
 133                                 return NVIF_NOTIFY_DROP;
 134                         }
 135                         notify->data = data;
 136                         ret = nvif_notify_func(notify, client->driver->keep);
 137                         notify->data = NULL;
 138                 }
 139         }
 140 
 141         return ret;
 142 }
 143 
 144 int
 145 nvif_notify_fini(struct nvif_notify *notify)
 146 {
 147         struct nvif_object *object = notify->object;
 148         struct {
 149                 struct nvif_ioctl_v0 ioctl;
 150                 struct nvif_ioctl_ntfy_del_v0 ntfy;
 151         } args = {
 152                 .ioctl.type = NVIF_IOCTL_V0_NTFY_DEL,
 153                 .ntfy.index = notify->index,
 154         };
 155         int ret = nvif_notify_put(notify);
 156         if (ret >= 0 && object) {
 157                 ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
 158                 notify->object = NULL;
 159                 kfree((void *)notify->data);
 160         }
 161         return ret;
 162 }
 163 
 164 int
 165 nvif_notify_init(struct nvif_object *object, int (*func)(struct nvif_notify *),
 166                  bool work, u8 event, void *data, u32 size, u32 reply,
 167                  struct nvif_notify *notify)
 168 {
 169         struct {
 170                 struct nvif_ioctl_v0 ioctl;
 171                 struct nvif_ioctl_ntfy_new_v0 ntfy;
 172                 struct nvif_notify_req_v0 req;
 173         } *args;
 174         int ret = -ENOMEM;
 175 
 176         notify->object = object;
 177         notify->flags = 0;
 178         atomic_set(&notify->putcnt, 1);
 179         notify->func = func;
 180         notify->data = NULL;
 181         notify->size = reply;
 182         if (work) {
 183                 INIT_WORK(&notify->work, nvif_notify_work);
 184                 set_bit(NVIF_NOTIFY_WORK, &notify->flags);
 185                 notify->data = kmalloc(notify->size, GFP_KERNEL);
 186                 if (!notify->data)
 187                         goto done;
 188         }
 189 
 190         if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL)))
 191                 goto done;
 192         args->ioctl.version = 0;
 193         args->ioctl.type = NVIF_IOCTL_V0_NTFY_NEW;
 194         args->ntfy.version = 0;
 195         args->ntfy.event = event;
 196         args->req.version = 0;
 197         args->req.reply = notify->size;
 198         args->req.route = 0;
 199         args->req.token = (unsigned long)(void *)notify;
 200 
 201         memcpy(args->req.data, data, size);
 202         ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL);
 203         notify->index = args->ntfy.index;
 204         kfree(args);
 205 done:
 206         if (ret)
 207                 nvif_notify_fini(notify);
 208         return ret;
 209 }

/* [<][>][^][v][top][bottom][index][help] */