/*
- * Copyright 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
+ * Copyright 2007-2010 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* Compatibility file for Linux wireless for kernels 2.6.25.
*/
-#include <net/compat.h>
-
-/* All things not in 2.6.22, 2.6.23 and 2.6.24 */
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
-
-/* Backport work for QoS dependencies (kernel/pm_qos_params.c)
- * ipw2100 now makes use of
- * pm_qos_add_requirement(),
- * pm_qos_update_requirement() and
- * pm_qos_remove_requirement() from it
- *
- * */
-
-/*
- * locking rule: all changes to target_value or requirements or notifiers lists
- * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
- * held, taken with _irqsave. One lock to rule them all
- */
-struct requirement_list {
- struct list_head list;
- union {
- s32 value;
- s32 usec;
- s32 kbps;
- };
- char *name;
-};
-
-static s32 max_compare(s32 v1, s32 v2);
-static s32 min_compare(s32 v1, s32 v2);
-
-struct pm_qos_object {
- struct requirement_list requirements;
- struct blocking_notifier_head *notifiers;
- struct miscdevice pm_qos_power_miscdev;
- char *name;
- s32 default_value;
- s32 target_value;
- s32 (*comparitor)(s32, s32);
-};
-
-static struct pm_qos_object null_pm_qos;
-static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
-static struct pm_qos_object cpu_dma_pm_qos = {
- .requirements = {LIST_HEAD_INIT(cpu_dma_pm_qos.requirements.list)},
- .notifiers = &cpu_dma_lat_notifier,
- .name = "cpu_dma_latency",
- .default_value = 2000 * USEC_PER_SEC,
- .target_value = 2000 * USEC_PER_SEC,
- .comparitor = min_compare
-};
-
-static BLOCKING_NOTIFIER_HEAD(network_lat_notifier);
-static struct pm_qos_object network_lat_pm_qos = {
- .requirements = {LIST_HEAD_INIT(network_lat_pm_qos.requirements.list)},
- .notifiers = &network_lat_notifier,
- .name = "network_latency",
- .default_value = 2000 * USEC_PER_SEC,
- .target_value = 2000 * USEC_PER_SEC,
- .comparitor = min_compare
-};
-
-
-static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
-static struct pm_qos_object network_throughput_pm_qos = {
- .requirements =
- {LIST_HEAD_INIT(network_throughput_pm_qos.requirements.list)},
- .notifiers = &network_throughput_notifier,
- .name = "network_throughput",
- .default_value = 0,
- .target_value = 0,
- .comparitor = max_compare
-};
-
-
-static struct pm_qos_object *pm_qos_array[] = {
- &null_pm_qos,
- &cpu_dma_pm_qos,
- &network_lat_pm_qos,
- &network_throughput_pm_qos
-};
-
-static DEFINE_SPINLOCK(pm_qos_lock);
-
-/* static helper functions */
-static s32 max_compare(s32 v1, s32 v2)
-{
- return max(v1, v2);
-}
-
-static s32 min_compare(s32 v1, s32 v2)
-{
- return min(v1, v2);
-}
-
-static void update_target(int target)
-{
- s32 extreme_value;
- struct requirement_list *node;
- unsigned long flags;
- int call_notifier = 0;
-
- spin_lock_irqsave(&pm_qos_lock, flags);
- extreme_value = pm_qos_array[target]->default_value;
- list_for_each_entry(node,
- &pm_qos_array[target]->requirements.list, list) {
- extreme_value = pm_qos_array[target]->comparitor(
- extreme_value, node->value);
- }
- if (pm_qos_array[target]->target_value != extreme_value) {
- call_notifier = 1;
- pm_qos_array[target]->target_value = extreme_value;
- pr_debug(KERN_ERR "new target for qos %d is %d\n", target,
- pm_qos_array[target]->target_value);
- }
- spin_unlock_irqrestore(&pm_qos_lock, flags);
-
- if (call_notifier)
- blocking_notifier_call_chain(pm_qos_array[target]->notifiers,
- (unsigned long) extreme_value, NULL);
-}
-
-
-/**
- * pm_qos_add_requirement - inserts new qos request into the list
- * @pm_qos_class: identifies which list of qos request to us
- * @name: identifies the request
- * @value: defines the qos request
- *
- * This function inserts a new entry in the pm_qos_class list of requested qos
- * performance charactoistics. It recomputes the agregate QoS expectations for
- * the pm_qos_class of parrameters.
- */
-int pm_qos_add_requirement(int pm_qos_class, char *name, s32 value)
-{
- struct requirement_list *dep;
- unsigned long flags;
-
- dep = kzalloc(sizeof(struct requirement_list), GFP_KERNEL);
- if (dep) {
- if (value == PM_QOS_DEFAULT_VALUE)
- dep->value = pm_qos_array[pm_qos_class]->default_value;
- else
- dep->value = value;
- dep->name = kstrdup(name, GFP_KERNEL);
- if (!dep->name)
- goto cleanup;
-
- spin_lock_irqsave(&pm_qos_lock, flags);
- list_add(&dep->list,
- &pm_qos_array[pm_qos_class]->requirements.list);
- spin_unlock_irqrestore(&pm_qos_lock, flags);
- update_target(pm_qos_class);
-
- return 0;
- }
-
-cleanup:
- kfree(dep);
- return -ENOMEM;
-}
-EXPORT_SYMBOL_GPL(pm_qos_add_requirement);
-
-/**
- * pm_qos_update_requirement - modifies an existing qos request
- * @pm_qos_class: identifies which list of qos request to us
- * @name: identifies the request
- * @value: defines the qos request
- *
- * Updates an existing qos requierement for the pm_qos_class of parameters along
- * with updating the target pm_qos_class value.
- *
- * If the named request isn't in the lest then no change is made.
- */
-int pm_qos_update_requirement(int pm_qos_class, char *name, s32 new_value)
-{
- unsigned long flags;
- struct requirement_list *node;
- int pending_update = 0;
-
- spin_lock_irqsave(&pm_qos_lock, flags);
- list_for_each_entry(node,
- &pm_qos_array[pm_qos_class]->requirements.list, list) {
- if (strcmp(node->name, name) == 0) {
- if (new_value == PM_QOS_DEFAULT_VALUE)
- node->value =
- pm_qos_array[pm_qos_class]->default_value;
- else
- node->value = new_value;
- pending_update = 1;
- break;
- }
- }
- spin_unlock_irqrestore(&pm_qos_lock, flags);
- if (pending_update)
- update_target(pm_qos_class);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(pm_qos_update_requirement);
-
-/**
- * pm_qos_remove_requirement - modifies an existing qos request
- * @pm_qos_class: identifies which list of qos request to us
- * @name: identifies the request
- *
- * Will remove named qos request from pm_qos_class list of parrameters and
- * recompute the current target value for the pm_qos_class.
- */
-void pm_qos_remove_requirement(int pm_qos_class, char *name)
-{
- unsigned long flags;
- struct requirement_list *node;
- int pending_update = 0;
-
- spin_lock_irqsave(&pm_qos_lock, flags);
- list_for_each_entry(node,
- &pm_qos_array[pm_qos_class]->requirements.list, list) {
- if (strcmp(node->name, name) == 0) {
- kfree(node->name);
- list_del(&node->list);
- kfree(node);
- pending_update = 1;
- break;
- }
- }
- spin_unlock_irqrestore(&pm_qos_lock, flags);
- if (pending_update)
- update_target(pm_qos_class);
-}
-EXPORT_SYMBOL_GPL(pm_qos_remove_requirement);
-
+#include <linux/miscdevice.h>
/**
* The following things are out of ./lib/vsprintf.c
EXPORT_SYMBOL(strict_strtoul);
EXPORT_SYMBOL(strict_strtol);
-int __dev_addr_sync(struct dev_addr_list **to, int *to_count,
- struct dev_addr_list **from, int *from_count)
-{
- struct dev_addr_list *da, *next;
- int err = 0;
-
- da = *from;
- while (da != NULL) {
- next = da->next;
- if (!da->da_synced) {
- err = __dev_addr_add(to, to_count,
- da->da_addr, da->da_addrlen, 0);
- if (err < 0)
- break;
- da->da_synced = 1;
- da->da_users++;
- } else if (da->da_users == 1) {
- __dev_addr_delete(to, to_count,
- da->da_addr, da->da_addrlen, 0);
- __dev_addr_delete(from, from_count,
- da->da_addr, da->da_addrlen, 0);
- }
- da = next;
- }
- return err;
-}
-EXPORT_SYMBOL_GPL(__dev_addr_sync);
-
-void __dev_addr_unsync(struct dev_addr_list **to, int *to_count,
- struct dev_addr_list **from, int *from_count)
-{
- struct dev_addr_list *da, *next;
-
- da = *from;
- while (da != NULL) {
- next = da->next;
- if (da->da_synced) {
- __dev_addr_delete(to, to_count,
- da->da_addr, da->da_addrlen, 0);
- da->da_synced = 0;
- __dev_addr_delete(from, from_count,
- da->da_addr, da->da_addrlen, 0);
- }
- da = next;
- }
-}
-EXPORT_SYMBOL_GPL(__dev_addr_unsync);
-
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) */
-