]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/nouveau/core/core/event.c
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi...
[karo-tx-linux.git] / drivers / gpu / drm / nouveau / core / core / event.c
1 /*
2  * Copyright 2013 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
23 #include <core/os.h>
24 #include <core/event.h>
25
26 void
27 nouveau_event_put(struct nouveau_eventh *handler)
28 {
29         struct nouveau_event *event = handler->event;
30         unsigned long flags;
31         if (__test_and_clear_bit(NVKM_EVENT_ENABLE, &handler->flags)) {
32                 spin_lock_irqsave(&event->refs_lock, flags);
33                 if (!--event->index[handler->index].refs) {
34                         if (event->disable)
35                                 event->disable(event, handler->index);
36                 }
37                 spin_unlock_irqrestore(&event->refs_lock, flags);
38         }
39 }
40
41 void
42 nouveau_event_get(struct nouveau_eventh *handler)
43 {
44         struct nouveau_event *event = handler->event;
45         unsigned long flags;
46         if (!__test_and_set_bit(NVKM_EVENT_ENABLE, &handler->flags)) {
47                 spin_lock_irqsave(&event->refs_lock, flags);
48                 if (!event->index[handler->index].refs++) {
49                         if (event->enable)
50                                 event->enable(event, handler->index);
51                 }
52                 spin_unlock_irqrestore(&event->refs_lock, flags);
53         }
54 }
55
56 static void
57 nouveau_event_fini(struct nouveau_eventh *handler)
58 {
59         struct nouveau_event *event = handler->event;
60         unsigned long flags;
61         nouveau_event_put(handler);
62         spin_lock_irqsave(&event->list_lock, flags);
63         list_del(&handler->head);
64         spin_unlock_irqrestore(&event->list_lock, flags);
65 }
66
67 static int
68 nouveau_event_init(struct nouveau_event *event, int index,
69                    int (*func)(void *, int), void *priv,
70                    struct nouveau_eventh *handler)
71 {
72         unsigned long flags;
73
74         if (index >= event->index_nr)
75                 return -EINVAL;
76
77         handler->event = event;
78         handler->flags = 0;
79         handler->index = index;
80         handler->func = func;
81         handler->priv = priv;
82
83         spin_lock_irqsave(&event->list_lock, flags);
84         list_add_tail(&handler->head, &event->index[index].list);
85         spin_unlock_irqrestore(&event->list_lock, flags);
86         return 0;
87 }
88
89 int
90 nouveau_event_new(struct nouveau_event *event, int index,
91                   int (*func)(void *, int), void *priv,
92                   struct nouveau_eventh **phandler)
93 {
94         struct nouveau_eventh *handler;
95         int ret = -ENOMEM;
96
97         handler = *phandler = kmalloc(sizeof(*handler), GFP_KERNEL);
98         if (handler) {
99                 ret = nouveau_event_init(event, index, func, priv, handler);
100                 if (ret)
101                         kfree(handler);
102         }
103
104         return ret;
105 }
106
107 void
108 nouveau_event_ref(struct nouveau_eventh *handler, struct nouveau_eventh **ref)
109 {
110         BUG_ON(handler != NULL);
111         if (*ref) {
112                 nouveau_event_fini(*ref);
113                 kfree(*ref);
114         }
115         *ref = handler;
116 }
117
118 void
119 nouveau_event_trigger(struct nouveau_event *event, int index)
120 {
121         struct nouveau_eventh *handler;
122         unsigned long flags;
123
124         if (WARN_ON(index >= event->index_nr))
125                 return;
126
127         spin_lock_irqsave(&event->list_lock, flags);
128         list_for_each_entry(handler, &event->index[index].list, head) {
129                 if (test_bit(NVKM_EVENT_ENABLE, &handler->flags) &&
130                     handler->func(handler->priv, index) == NVKM_EVENT_DROP)
131                         nouveau_event_put(handler);
132         }
133         spin_unlock_irqrestore(&event->list_lock, flags);
134 }
135
136 void
137 nouveau_event_destroy(struct nouveau_event **pevent)
138 {
139         struct nouveau_event *event = *pevent;
140         if (event) {
141                 kfree(event);
142                 *pevent = NULL;
143         }
144 }
145
146 int
147 nouveau_event_create(int index_nr, struct nouveau_event **pevent)
148 {
149         struct nouveau_event *event;
150         int i;
151
152         event = *pevent = kzalloc(sizeof(*event) + index_nr *
153                                   sizeof(event->index[0]), GFP_KERNEL);
154         if (!event)
155                 return -ENOMEM;
156
157         spin_lock_init(&event->list_lock);
158         spin_lock_init(&event->refs_lock);
159         for (i = 0; i < index_nr; i++)
160                 INIT_LIST_HEAD(&event->index[i].list);
161         event->index_nr = index_nr;
162         return 0;
163 }