0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
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(¬ify->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, ¬ify->flags)) {
0055 int ret = nvif_notify_put_(notify);
0056 if (test_bit(NVIF_NOTIFY_WORK, ¬ify->flags))
0057 flush_work(¬ify->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(¬ify->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, ¬ify->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, ¬ify->flags)) {
0096 if (!keep)
0097 atomic_dec(¬ify->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(¬ify->putcnt);
0130 if (test_bit(NVIF_NOTIFY_WORK, ¬ify->flags)) {
0131 memcpy((void *)notify->data, data, size);
0132 schedule_work(¬ify->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(¬ify->putcnt, 1);
0180 notify->func = func;
0181 notify->data = NULL;
0182 notify->size = reply;
0183 if (work) {
0184 INIT_WORK(¬ify->work, nvif_notify_work);
0185 set_bit(NVIF_NOTIFY_WORK, ¬ify->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 }