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
This commit is contained in:
Orhan K AKYILDIZ 2016-09-16 00:43:38 -07:00 • committed by Manjunathappa Prakash
commit 458fefc8bd
2 changed files with 114 additions and 7 deletions

View file

@ -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) */

View file

@ -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 */