Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2014 Red Hat Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: Ben Skeggs <bskeggs@redhat.com>
0023  */
0024 
0025 #include <nvif/client.h>
0026 #include <nvif/driver.h>
0027 #include <nvif/notify.h>
0028 #include <nvif/object.h>
0029 #include <nvif/ioctl.h>
0030 #include <nvif/event.h>
0031 
0032 static inline int
0033 nvif_notify_put_(struct nvif_notify *notify)
0034 {
0035     struct nvif_object *object = notify->object;
0036     struct {
0037         struct nvif_ioctl_v0 ioctl;
0038         struct nvif_ioctl_ntfy_put_v0 ntfy;
0039     } args = {
0040         .ioctl.type = NVIF_IOCTL_V0_NTFY_PUT,
0041         .ntfy.index = notify->index,
0042     };
0043 
0044     if (atomic_inc_return(&notify->putcnt) != 1)
0045         return 0;
0046 
0047     return nvif_object_ioctl(object, &args, sizeof(args), NULL);
0048 }
0049 
0050 int
0051 nvif_notify_put(struct nvif_notify *notify)
0052 {
0053     if (likely(notify->object) &&
0054         test_and_clear_bit(NVIF_NOTIFY_USER, &notify->flags)) {
0055         int ret = nvif_notify_put_(notify);
0056         if (test_bit(NVIF_NOTIFY_WORK, &notify->flags))
0057             flush_work(&notify->work);
0058         return ret;
0059     }
0060     return 0;
0061 }
0062 
0063 static inline int
0064 nvif_notify_get_(struct nvif_notify *notify)
0065 {
0066     struct nvif_object *object = notify->object;
0067     struct {
0068         struct nvif_ioctl_v0 ioctl;
0069         struct nvif_ioctl_ntfy_get_v0 ntfy;
0070     } args = {
0071         .ioctl.type = NVIF_IOCTL_V0_NTFY_GET,
0072         .ntfy.index = notify->index,
0073     };
0074 
0075     if (atomic_dec_return(&notify->putcnt) != 0)
0076         return 0;
0077 
0078     return nvif_object_ioctl(object, &args, sizeof(args), NULL);
0079 }
0080 
0081 int
0082 nvif_notify_get(struct nvif_notify *notify)
0083 {
0084     if (likely(notify->object) &&
0085         !test_and_set_bit(NVIF_NOTIFY_USER, &notify->flags))
0086         return nvif_notify_get_(notify);
0087     return 0;
0088 }
0089 
0090 static inline int
0091 nvif_notify_func(struct nvif_notify *notify, bool keep)
0092 {
0093     int ret = notify->func(notify);
0094     if (ret == NVIF_NOTIFY_KEEP ||
0095         !test_and_clear_bit(NVIF_NOTIFY_USER, &notify->flags)) {
0096         if (!keep)
0097             atomic_dec(&notify->putcnt);
0098         else
0099             nvif_notify_get_(notify);
0100     }
0101     return ret;
0102 }
0103 
0104 static void
0105 nvif_notify_work(struct work_struct *work)
0106 {
0107     struct nvif_notify *notify = container_of(work, typeof(*notify), work);
0108     nvif_notify_func(notify, true);
0109 }
0110 
0111 int
0112 nvif_notify(const void *header, u32 length, const void *data, u32 size)
0113 {
0114     struct nvif_notify *notify = NULL;
0115     const union {
0116         struct nvif_notify_rep_v0 v0;
0117     } *args = header;
0118     int ret = NVIF_NOTIFY_DROP;
0119 
0120     if (length == sizeof(args->v0) && args->v0.version == 0) {
0121         if (WARN_ON(args->v0.route))
0122             return NVIF_NOTIFY_DROP;
0123         notify = (void *)(unsigned long)args->v0.token;
0124     }
0125 
0126     if (!WARN_ON(notify == NULL)) {
0127         struct nvif_client *client = notify->object->client;
0128         if (!WARN_ON(notify->size != size)) {
0129             atomic_inc(&notify->putcnt);
0130             if (test_bit(NVIF_NOTIFY_WORK, &notify->flags)) {
0131                 memcpy((void *)notify->data, data, size);
0132                 schedule_work(&notify->work);
0133                 return NVIF_NOTIFY_DROP;
0134             }
0135             notify->data = data;
0136             ret = nvif_notify_func(notify, client->driver->keep);
0137             notify->data = NULL;
0138         }
0139     }
0140 
0141     return ret;
0142 }
0143 
0144 int
0145 nvif_notify_dtor(struct nvif_notify *notify)
0146 {
0147     struct nvif_object *object = notify->object;
0148     struct {
0149         struct nvif_ioctl_v0 ioctl;
0150         struct nvif_ioctl_ntfy_del_v0 ntfy;
0151     } args = {
0152         .ioctl.type = NVIF_IOCTL_V0_NTFY_DEL,
0153         .ntfy.index = notify->index,
0154     };
0155     int ret = nvif_notify_put(notify);
0156     if (ret >= 0 && object) {
0157         ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
0158         notify->object = NULL;
0159         kfree((void *)notify->data);
0160     }
0161     return ret;
0162 }
0163 
0164 int
0165 nvif_notify_ctor(struct nvif_object *object, const char *name,
0166          int (*func)(struct nvif_notify *), bool work, u8 event,
0167          void *data, u32 size, u32 reply, struct nvif_notify *notify)
0168 {
0169     struct {
0170         struct nvif_ioctl_v0 ioctl;
0171         struct nvif_ioctl_ntfy_new_v0 ntfy;
0172         struct nvif_notify_req_v0 req;
0173     } *args;
0174     int ret = -ENOMEM;
0175 
0176     notify->object = object;
0177     notify->name = name ? name : "nvifNotify";
0178     notify->flags = 0;
0179     atomic_set(&notify->putcnt, 1);
0180     notify->func = func;
0181     notify->data = NULL;
0182     notify->size = reply;
0183     if (work) {
0184         INIT_WORK(&notify->work, nvif_notify_work);
0185         set_bit(NVIF_NOTIFY_WORK, &notify->flags);
0186         notify->data = kmalloc(notify->size, GFP_KERNEL);
0187         if (!notify->data)
0188             goto done;
0189     }
0190 
0191     if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL)))
0192         goto done;
0193     args->ioctl.version = 0;
0194     args->ioctl.type = NVIF_IOCTL_V0_NTFY_NEW;
0195     args->ntfy.version = 0;
0196     args->ntfy.event = event;
0197     args->req.version = 0;
0198     args->req.reply = notify->size;
0199     args->req.route = 0;
0200     args->req.token = (unsigned long)(void *)notify;
0201 
0202     memcpy(args->req.data, data, size);
0203     ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL);
0204     notify->index = args->ntfy.index;
0205     kfree(args);
0206 done:
0207     if (ret)
0208         nvif_notify_dtor(notify);
0209     return ret;
0210 }