From 458fefc8bdc8329a9db0e56e545fc17f3d3becda Mon Sep 17 00:00:00 2001 From: Orhan K AKYILDIZ Date: Fri, 16 Sep 2016 00:43:38 -0700 Subject: [PATCH] qcacmn: Add a NAPI mode for roaming Add a new mode with a pair of new NAPI events, NAPI_EVT_USR_SERIAL and NAPI_EVT_USR_NORMAL, which allows client force NAPI to move all instances onto the same CPU and peg them there (blacklist); and to move back to normal mode of operation. This part implements the HIF portion. Goes with the corresponding HDD code. Change-Id: Id301267d654ef24de706f81b0bd712ed751d8265 CRs-Fixed: 1078976 --- hif/inc/hif_napi.h | 10 ++++ hif/src/hif_napi.c | 111 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 114 insertions(+), 7 deletions(-) diff --git a/hif/inc/hif_napi.h b/hif/inc/hif_napi.h index edf1fd06791e..69255d36ebf9 100644 --- a/hif/inc/hif_napi.h +++ b/hif/inc/hif_napi.h @@ -64,6 +64,8 @@ * EVT_CMD_STATE : cmd arg : by the vendor cmd * EVT_CPU_STATE : (cpu << 16)|state: CPU hotplug events * EVT_TPUT_STATE : (high/low) : tput trigger + * EVT_USR_SERIAL : num-serial_calls : WMA/ROAMING-START/IND + * EVT_USR_NORMAL : N/A : WMA/ROAMING-END */ enum qca_napi_event { NAPI_EVT_INVALID, @@ -71,6 +73,8 @@ enum qca_napi_event { NAPI_EVT_CMD_STATE, NAPI_EVT_CPU_STATE, NAPI_EVT_TPUT_STATE, + NAPI_EVT_USR_SERIAL, + NAPI_EVT_USR_NORMAL }; /** @@ -145,6 +149,10 @@ int hif_napi_poll(struct hif_opaque_softc *hif_ctx, struct qca_napi_data; static inline int hif_napi_cpu_init(void *ctx) { return 0; } static inline int hif_napi_cpu_deinit(void *ctx) { return 0; } +static inline int hif_napi_serialize(struct hif_opaque_softc *hif, int is_on) +{ + return -EPERM; +} #else /* HELIUMPLUS - NAPI CPU symbols are valid */ /* @@ -156,6 +164,8 @@ int hif_napi_cpu_deinit(void *); int hif_napi_cpu_migrate(struct qca_napi_data *napid, int cpu, int action); int hif_napi_cpu_blacklist(bool is_on); +int hif_napi_serialize(struct hif_opaque_softc *hif, int is_on); + #endif /* HELIUMPLUS */ #else /* ! defined(FEATURE_NAPI) */ diff --git a/hif/src/hif_napi.c b/hif/src/hif_napi.c index c19e5752725f..a7fa19f943c4 100644 --- a/hif/src/hif_napi.c +++ b/hif/src/hif_napi.c @@ -317,6 +317,22 @@ inline struct qca_napi_data *hif_napi_get_all(struct hif_opaque_softc *hif_ctx) * separate performance cores). * - CPU eligibility is kept up-to-date by NAPI_EVT_CPU_STATE events. * + * + In some cases (roaming peer management is the only case so far), a + * a client can trigger a "SERIALIZE" event. Basically, this means that the + * users is asking NAPI to go into a truly single execution context state. + * So, NAPI indicates to msm-irqbalancer that it wants to be blacklisted, + * (if called for the first time) and then moves all IRQs (for NAPI + * instances) to be collapsed to a single core. If called multiple times, + * it will just re-collapse the CPUs. This is because blacklist-on() API + * is reference-counted, and because the API has already been called. + * + * Such a user, should call "DESERIALIZE" (NORMAL) event, to set NAPI to go + * to its "normal" operation. Optionally, they can give a timeout value (in + * multiples of BusBandwidthCheckPeriod -- 100 msecs by default). In this + * case, NAPI will just set the current throughput state to uninitialized + * and set the delay period. Once policy handler is called, it would skip + * applying the policy delay period times, and otherwise apply the policy. + * * Return: * < 0: some error * = 0: event handled successfully @@ -331,6 +347,11 @@ int hif_napi_event(struct hif_opaque_softc *hif_ctx, enum qca_napi_event event, struct hif_softc *hif = HIF_GET_SOFTC(hif_ctx); struct qca_napi_data *napid = &(hif->napi_data); enum qca_napi_tput_state tput_mode = QCA_NAPI_TPUT_UNINITIALIZED; + enum { + BLACKLIST_NOT_PENDING, + BLACKLIST_ON_PENDING, + BLACKLIST_OFF_PENDING + } blacklist_pending = BLACKLIST_NOT_PENDING; NAPI_DEBUG("%s: -->(event=%d, aux=%p)", __func__, event, data); @@ -399,6 +420,7 @@ int hif_napi_event(struct hif_opaque_softc *hif_ctx, enum qca_napi_event event, rc = hif_napi_cpu_migrate(napid, HNC_ANY_CPU, HNC_ACT_COLLAPSE); + blacklist_pending = BLACKLIST_OFF_PENDING; } else { /* from TPUT_LO -> TPUT->HI */ NAPI_DEBUG("%s: Moving to napi_tput_HI state", @@ -407,12 +429,35 @@ int hif_napi_event(struct hif_opaque_softc *hif_ctx, enum qca_napi_event event, rc = hif_napi_cpu_migrate(napid, HNC_ANY_CPU, HNC_ACT_DISPERSE); + blacklist_pending = BLACKLIST_ON_PENDING; } napid->napi_mode = tput_mode; break; } + case NAPI_EVT_USR_SERIAL: { + unsigned long users = (unsigned long)data; + NAPI_DEBUG("%s: User forced SERIALIZATION; users=%ld", + __func__, users); + + rc = hif_napi_cpu_migrate(napid, + HNC_ANY_CPU, + HNC_ACT_COLLAPSE); + if ((users == 0) && (rc == 0)) + blacklist_pending = BLACKLIST_ON_PENDING; + break; + } + case NAPI_EVT_USR_NORMAL: { + NAPI_DEBUG("%s: User forced DE-SERIALIZATION", __func__); + /* + * Deserialization timeout is handled at hdd layer; + * just mark current mode to uninitialized to ensure + * it will be set when the delay is over + */ + napid->napi_mode = QCA_NAPI_TPUT_UNINITIALIZED; + break; + } default: { HIF_ERROR("%s: unknown event: %d (data=0x%0lx)", __func__, event, (unsigned long) data); @@ -424,11 +469,18 @@ int hif_napi_event(struct hif_opaque_softc *hif_ctx, enum qca_napi_event event, spin_unlock_bh(&(napid->lock)); /* Call this API without spin_locks hif_napi_cpu_blacklist */ - if (tput_mode == QCA_NAPI_TPUT_LO) - /* yield control of IRQs to kernel */ - hif_napi_cpu_blacklist(false); - else if (tput_mode == QCA_NAPI_TPUT_HI) + switch (blacklist_pending) { + case BLACKLIST_ON_PENDING: + /* assume the control of WLAN IRQs */ hif_napi_cpu_blacklist(true); + break; + case BLACKLIST_OFF_PENDING: + /* yield the control of WLAN IRQs */ + hif_napi_cpu_blacklist(false); + break; + default: /* nothing to do */ + break; + } /* switch blacklist_pending */ if (prev_state != hif->napi_data.state) { if (hif->napi_data.state == ENABLE_NAPI_MASK) { @@ -1177,15 +1229,60 @@ hncm_return: int hif_napi_cpu_blacklist(bool is_on) { int rc = 0; + static int ref_count; /* = 0 by the compiler */ NAPI_DEBUG("-->%s(%d)", __func__, is_on); - if (is_on) + if (is_on) { + ref_count++; rc = irq_blacklist_on(); - else - rc = irq_blacklist_off(); + } else { + do { + rc = irq_blacklist_off(); + ref_count--; + } while (ref_count > 0); + } NAPI_DEBUG("<--%s[%d]", __func__, rc); return rc; } +/** + * hif_napi_serialize() - [de-]serialize NAPI operations + * @hif: context + * @is_on: 1: serialize, 0: deserialize + * + * hif_napi_serialize(hif, 1) can be called multiple times. It will perform the + * following steps (see hif_napi_event for code): + * - put irqs of all NAPI instances on the same CPU + * - only for the first serialize call: blacklist + * + * hif_napi_serialize(hif, 0): + * - start a timer (multiple of BusBandwidthTimer -- default: 100 msec) + * - at the end of the timer, check the current throughput state and + * implement it. + */ +static unsigned long napi_serialize_reqs; +int hif_napi_serialize(struct hif_opaque_softc *hif, int is_on) +{ + int rc = -EINVAL; + + if (hif != NULL) + switch (is_on) { + case 0: { /* de-serialize */ + rc = hif_napi_event(hif, NAPI_EVT_USR_NORMAL, + (void *) 0); + napi_serialize_reqs = 0; + break; + } /* end de-serialize */ + case 1: { /* serialize */ + rc = hif_napi_event(hif, NAPI_EVT_USR_SERIAL, + (void *)napi_serialize_reqs++); + break; + } /* end serialize */ + default: + break; /* no-op */ + } /* switch */ + return rc; +} + #endif /* ifdef HELIUMPLUS */