Merge tag 'wireless-drivers-for-davem-2014-12-26' of git://git.kernel.org/pub/scm...
[cascardo/linux.git] / drivers / net / wireless / iwlwifi / mvm / quota.c
index 4e20b3c..dbb2594 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -161,6 +163,9 @@ static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm,
                quota *= (beacon_int - mvm->noa_duration);
                quota /= beacon_int;
 
+               IWL_DEBUG_QUOTA(mvm, "quota: adjust for NoA from %d to %d\n",
+                               le32_to_cpu(cmd->quotas[i].quota), quota);
+
                cmd->quotas[i].quota = cpu_to_le32(quota);
        }
 #endif
@@ -170,12 +175,14 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
                          struct ieee80211_vif *disabled_vif)
 {
        struct iwl_time_quota_cmd cmd = {};
-       int i, idx, ret, num_active_macs, quota, quota_rem, n_non_lowlat;
+       int i, idx, err, num_active_macs, quota, quota_rem, n_non_lowlat;
        struct iwl_mvm_quota_iterator_data data = {
                .n_interfaces = {},
                .colors = { -1, -1, -1, -1 },
                .disabled_vif = disabled_vif,
        };
+       struct iwl_time_quota_cmd *last = &mvm->last_quota_cmd;
+       bool send = false;
 
        lockdep_assert_held(&mvm->mutex);
 
@@ -222,6 +229,9 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
                quota = (QUOTA_100 - QUOTA_LOWLAT_MIN) / n_non_lowlat;
                quota_rem = QUOTA_100 - n_non_lowlat * quota -
                            QUOTA_LOWLAT_MIN;
+               IWL_DEBUG_QUOTA(mvm,
+                               "quota: low-latency binding active, remaining quota per other binding: %d\n",
+                               quota);
        } else if (num_active_macs) {
                /*
                 * There are 0 or more than 1 low latency bindings, or all the
@@ -230,6 +240,9 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
                 */
                quota = QUOTA_100 / num_active_macs;
                quota_rem = QUOTA_100 % num_active_macs;
+               IWL_DEBUG_QUOTA(mvm,
+                               "quota: splitting evenly per binding: %d\n",
+                               quota);
        } else {
                /* values don't really matter - won't be used */
                quota = 0;
@@ -271,6 +284,9 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
        for (i = 0; i < MAX_BINDINGS; i++) {
                if (le32_to_cpu(cmd.quotas[i].quota) != 0) {
                        le32_add_cpu(&cmd.quotas[i].quota, quota_rem);
+                       IWL_DEBUG_QUOTA(mvm,
+                                       "quota: giving remainder of %d to binding %d\n",
+                                       quota_rem, i);
                        break;
                }
        }
@@ -279,15 +295,33 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
 
        /* check that we have non-zero quota for all valid bindings */
        for (i = 0; i < MAX_BINDINGS; i++) {
+               if (cmd.quotas[i].id_and_color != last->quotas[i].id_and_color)
+                       send = true;
+               if (cmd.quotas[i].max_duration != last->quotas[i].max_duration)
+                       send = true;
+               if (abs((int)le32_to_cpu(cmd.quotas[i].quota) -
+                       (int)le32_to_cpu(last->quotas[i].quota))
+                                               > IWL_MVM_QUOTA_THRESHOLD)
+                       send = true;
                if (cmd.quotas[i].id_and_color == cpu_to_le32(FW_CTXT_INVALID))
                        continue;
                WARN_ONCE(cmd.quotas[i].quota == 0,
                          "zero quota on binding %d\n", i);
        }
 
-       ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0,
-                                  sizeof(cmd), &cmd);
-       if (ret)
-               IWL_ERR(mvm, "Failed to send quota: %d\n", ret);
-       return ret;
+       if (!send) {
+               /* don't send a practically unchanged command, the firmware has
+                * to re-initialize a lot of state and that can have an adverse
+                * impact on it
+                */
+               return 0;
+       }
+
+       err = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, sizeof(cmd), &cmd);
+
+       if (err)
+               IWL_ERR(mvm, "Failed to send quota: %d\n", err);
+       else
+               mvm->last_quota_cmd = cmd;
+       return err;
 }