Rearrange module order for easy placement on external builds
[~emulex/for-vlad/old/compat.git] / compat / compat-2.6.25.c
1 /*
2  * Copyright 2007       Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * Compatibility file for Linux wireless for kernels 2.6.25.
9  */
10
11 #include <net/compat.h>
12
13 /* All things not in 2.6.22, 2.6.23 and 2.6.24 */
14 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
15
16 /* Backport work for QoS dependencies (kernel/pm_qos_params.c)
17  * ipw2100 now makes use of
18  * pm_qos_add_requirement(),
19  * pm_qos_update_requirement() and
20  * pm_qos_remove_requirement() from it
21  *
22  * */
23
24 /*
25  * locking rule: all changes to target_value or requirements or notifiers lists
26  * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
27  * held, taken with _irqsave.  One lock to rule them all
28  */
29 struct requirement_list {
30         struct list_head list;
31         union {
32                 s32 value;
33                 s32 usec;
34                 s32 kbps;
35         };
36         char *name;
37 };
38
39 static s32 max_compare(s32 v1, s32 v2);
40 static s32 min_compare(s32 v1, s32 v2);
41
42 struct pm_qos_object {
43         struct requirement_list requirements;
44         struct blocking_notifier_head *notifiers;
45         struct miscdevice pm_qos_power_miscdev;
46         char *name;
47         s32 default_value;
48         s32 target_value;
49         s32 (*comparitor)(s32, s32);
50 };
51
52 static struct pm_qos_object null_pm_qos;
53 static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
54 static struct pm_qos_object cpu_dma_pm_qos = {
55         .requirements = {LIST_HEAD_INIT(cpu_dma_pm_qos.requirements.list)},
56         .notifiers = &cpu_dma_lat_notifier,
57         .name = "cpu_dma_latency",
58         .default_value = 2000 * USEC_PER_SEC,
59         .target_value = 2000 * USEC_PER_SEC,
60         .comparitor = min_compare
61 };
62
63 static BLOCKING_NOTIFIER_HEAD(network_lat_notifier);
64 static struct pm_qos_object network_lat_pm_qos = {
65         .requirements = {LIST_HEAD_INIT(network_lat_pm_qos.requirements.list)},
66         .notifiers = &network_lat_notifier,
67         .name = "network_latency",
68         .default_value = 2000 * USEC_PER_SEC,
69         .target_value = 2000 * USEC_PER_SEC,
70         .comparitor = min_compare
71 };
72
73
74 static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
75 static struct pm_qos_object network_throughput_pm_qos = {
76         .requirements =
77                 {LIST_HEAD_INIT(network_throughput_pm_qos.requirements.list)},
78         .notifiers = &network_throughput_notifier,
79         .name = "network_throughput",
80         .default_value = 0,
81         .target_value = 0,
82         .comparitor = max_compare
83 };
84
85
86 static struct pm_qos_object *pm_qos_array[] = {
87         &null_pm_qos,
88         &cpu_dma_pm_qos,
89         &network_lat_pm_qos,
90         &network_throughput_pm_qos
91 };
92
93 static DEFINE_SPINLOCK(pm_qos_lock);
94
95 /* static helper functions */
96 static s32 max_compare(s32 v1, s32 v2)
97 {
98         return max(v1, v2);
99 }
100
101 static s32 min_compare(s32 v1, s32 v2)
102 {
103         return min(v1, v2);
104 }
105
106 static void update_target(int target)
107 {
108         s32 extreme_value;
109         struct requirement_list *node;
110         unsigned long flags;
111         int call_notifier = 0;
112
113         spin_lock_irqsave(&pm_qos_lock, flags);
114         extreme_value = pm_qos_array[target]->default_value;
115         list_for_each_entry(node,
116                         &pm_qos_array[target]->requirements.list, list) {
117                 extreme_value = pm_qos_array[target]->comparitor(
118                                 extreme_value, node->value);
119         }
120         if (pm_qos_array[target]->target_value != extreme_value) {
121                 call_notifier = 1;
122                 pm_qos_array[target]->target_value = extreme_value;
123                 pr_debug(KERN_ERR "new target for qos %d is %d\n", target,
124                         pm_qos_array[target]->target_value);
125         }
126         spin_unlock_irqrestore(&pm_qos_lock, flags);
127
128         if (call_notifier)
129                 blocking_notifier_call_chain(pm_qos_array[target]->notifiers,
130                         (unsigned long) extreme_value, NULL);
131 }
132
133
134 /**
135  * pm_qos_add_requirement - inserts new qos request into the list
136  * @pm_qos_class: identifies which list of qos request to us
137  * @name: identifies the request
138  * @value: defines the qos request
139  *
140  * This function inserts a new entry in the pm_qos_class list of requested qos
141  * performance charactoistics.  It recomputes the agregate QoS expectations for
142  * the pm_qos_class of parrameters.
143  */
144 int pm_qos_add_requirement(int pm_qos_class, char *name, s32 value)
145 {
146         struct requirement_list *dep;
147         unsigned long flags;
148
149         dep = kzalloc(sizeof(struct requirement_list), GFP_KERNEL);
150         if (dep) {
151                 if (value == PM_QOS_DEFAULT_VALUE)
152                         dep->value = pm_qos_array[pm_qos_class]->default_value;
153                 else
154                         dep->value = value;
155                 dep->name = kstrdup(name, GFP_KERNEL);
156                 if (!dep->name)
157                         goto cleanup;
158
159                 spin_lock_irqsave(&pm_qos_lock, flags);
160                 list_add(&dep->list,
161                         &pm_qos_array[pm_qos_class]->requirements.list);
162                 spin_unlock_irqrestore(&pm_qos_lock, flags);
163                 update_target(pm_qos_class);
164
165                 return 0;
166         }
167
168 cleanup:
169         kfree(dep);
170         return -ENOMEM;
171 }
172 EXPORT_SYMBOL_GPL(pm_qos_add_requirement);
173
174 /**
175  * pm_qos_update_requirement - modifies an existing qos request
176  * @pm_qos_class: identifies which list of qos request to us
177  * @name: identifies the request
178  * @value: defines the qos request
179  *
180  * Updates an existing qos requierement for the pm_qos_class of parameters along
181  * with updating the target pm_qos_class value.
182  *
183  * If the named request isn't in the lest then no change is made.
184  */
185 int pm_qos_update_requirement(int pm_qos_class, char *name, s32 new_value)
186 {
187         unsigned long flags;
188         struct requirement_list *node;
189         int pending_update = 0;
190
191         spin_lock_irqsave(&pm_qos_lock, flags);
192         list_for_each_entry(node,
193                 &pm_qos_array[pm_qos_class]->requirements.list, list) {
194                 if (strcmp(node->name, name) == 0) {
195                         if (new_value == PM_QOS_DEFAULT_VALUE)
196                                 node->value =
197                                 pm_qos_array[pm_qos_class]->default_value;
198                         else
199                                 node->value = new_value;
200                         pending_update = 1;
201                         break;
202                 }
203         }
204         spin_unlock_irqrestore(&pm_qos_lock, flags);
205         if (pending_update)
206                 update_target(pm_qos_class);
207
208         return 0;
209 }
210 EXPORT_SYMBOL_GPL(pm_qos_update_requirement);
211
212 /**
213  * pm_qos_remove_requirement - modifies an existing qos request
214  * @pm_qos_class: identifies which list of qos request to us
215  * @name: identifies the request
216  *
217  * Will remove named qos request from pm_qos_class list of parrameters and
218  * recompute the current target value for the pm_qos_class.
219  */
220 void pm_qos_remove_requirement(int pm_qos_class, char *name)
221 {
222         unsigned long flags;
223         struct requirement_list *node;
224         int pending_update = 0;
225
226         spin_lock_irqsave(&pm_qos_lock, flags);
227         list_for_each_entry(node,
228                 &pm_qos_array[pm_qos_class]->requirements.list, list) {
229                 if (strcmp(node->name, name) == 0) {
230                         kfree(node->name);
231                         list_del(&node->list);
232                         kfree(node);
233                         pending_update = 1;
234                         break;
235                 }
236         }
237         spin_unlock_irqrestore(&pm_qos_lock, flags);
238         if (pending_update)
239                 update_target(pm_qos_class);
240 }
241 EXPORT_SYMBOL_GPL(pm_qos_remove_requirement);
242
243
244 /**
245  * The following things are out of ./lib/vsprintf.c
246  * The new iwlwifi driver is using them.
247  */
248
249 /**
250  * strict_strtoul - convert a string to an unsigned long strictly
251  * @cp: The string to be converted
252  * @base: The number base to use
253  * @res: The converted result value
254  *
255  * strict_strtoul converts a string to an unsigned long only if the
256  * string is really an unsigned long string, any string containing
257  * any invalid char at the tail will be rejected and -EINVAL is returned,
258  * only a newline char at the tail is acceptible because people generally
259  * change a module parameter in the following way:
260  *
261  *      echo 1024 > /sys/module/e1000/parameters/copybreak
262  *
263  * echo will append a newline to the tail.
264  *
265  * It returns 0 if conversion is successful and *res is set to the converted
266  * value, otherwise it returns -EINVAL and *res is set to 0.
267  *
268  * simple_strtoul just ignores the successive invalid characters and
269  * return the converted value of prefix part of the string.
270  */
271 int strict_strtoul(const char *cp, unsigned int base, unsigned long *res);
272
273 /**
274  * strict_strtol - convert a string to a long strictly
275  * @cp: The string to be converted
276  * @base: The number base to use
277  * @res: The converted result value
278  *
279  * strict_strtol is similiar to strict_strtoul, but it allows the first
280  * character of a string is '-'.
281  *
282  * It returns 0 if conversion is successful and *res is set to the converted
283  * value, otherwise it returns -EINVAL and *res is set to 0.
284  */
285 int strict_strtol(const char *cp, unsigned int base, long *res);
286
287 #define define_strict_strtoux(type, valtype)                            \
288 int strict_strtou##type(const char *cp, unsigned int base, valtype *res)\
289 {                                                                       \
290         char *tail;                                                     \
291         valtype val;                                                    \
292         size_t len;                                                     \
293                                                                         \
294         *res = 0;                                                       \
295         len = strlen(cp);                                               \
296         if (len == 0)                                                   \
297                 return -EINVAL;                                         \
298                                                                         \
299         val = simple_strtou##type(cp, &tail, base);                     \
300         if ((*tail == '\0') ||                                          \
301                 ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {\
302                 *res = val;                                             \
303                 return 0;                                               \
304         }                                                               \
305                                                                         \
306         return -EINVAL;                                                 \
307 }                                                                       \
308
309 #define define_strict_strtox(type, valtype)                             \
310 int strict_strto##type(const char *cp, unsigned int base, valtype *res) \
311 {                                                                       \
312         int ret;                                                        \
313         if (*cp == '-') {                                               \
314                 ret = strict_strtou##type(cp+1, base, res);             \
315                 if (!ret)                                               \
316                         *res = -(*res);                                 \
317         } else                                                          \
318                 ret = strict_strtou##type(cp, base, res);               \
319                                                                         \
320         return ret;                                                     \
321 }                                                                       \
322
323 define_strict_strtoux(l, unsigned long)
324 define_strict_strtox(l, long)
325
326 EXPORT_SYMBOL(strict_strtoul);
327 EXPORT_SYMBOL(strict_strtol);
328
329 int __dev_addr_sync(struct dev_addr_list **to, int *to_count,
330                     struct dev_addr_list **from, int *from_count)
331 {
332         struct dev_addr_list *da, *next;
333         int err = 0;
334
335         da = *from;
336         while (da != NULL) {
337                 next = da->next;
338                 if (!da->da_synced) {
339                         err = __dev_addr_add(to, to_count,
340                                              da->da_addr, da->da_addrlen, 0);
341                         if (err < 0)
342                                 break;
343                         da->da_synced = 1;
344                         da->da_users++;
345                 } else if (da->da_users == 1) {
346                         __dev_addr_delete(to, to_count,
347                                           da->da_addr, da->da_addrlen, 0);
348                         __dev_addr_delete(from, from_count,
349                                           da->da_addr, da->da_addrlen, 0);
350                 }
351                 da = next;
352         }
353         return err;
354 }
355 EXPORT_SYMBOL_GPL(__dev_addr_sync);
356
357 void __dev_addr_unsync(struct dev_addr_list **to, int *to_count,
358                        struct dev_addr_list **from, int *from_count)
359 {
360         struct dev_addr_list *da, *next;
361
362         da = *from;
363         while (da != NULL) {
364                 next = da->next;
365                 if (da->da_synced) {
366                         __dev_addr_delete(to, to_count,
367                                           da->da_addr, da->da_addrlen, 0);
368                         da->da_synced = 0;
369                         __dev_addr_delete(from, from_count,
370                                           da->da_addr, da->da_addrlen, 0);
371                 }
372                 da = next;
373         }
374 }
375 EXPORT_SYMBOL_GPL(__dev_addr_unsync);
376
377 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) */
378