iwm - Clear Time Event active state, when receiving End Notification.

* This hopefully avoids some firmware panics, I was occasionally seeing,
when iwm disconnects upon losing signal to an access point at some point.

* This is synchronizing the if_iwm_time_event.c file a bit more from the
corresponding Linux iwlwifi/mvm/time-event.c.

Taken-From:     Linux iwlwifi

Submitted by:	Augustin Cavalier <waddlesplash@gmail.com> (Haiku)
Obtained from:	DragonFlyBSD (e8cb71584a6a72232c13151d60e57f7f229220eb)
This commit is contained in:
Kyle Evans 2019-01-24 03:47:47 +00:00
parent 9a949c99e6
commit df34d80aa7
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=343384
4 changed files with 78 additions and 15 deletions

View File

@ -5375,15 +5375,9 @@ iwm_handle_rxb(struct iwm_softc *sc, struct mbuf *m)
break;
}
case IWM_TIME_EVENT_NOTIFICATION: {
struct iwm_time_event_notif *notif;
notif = (void *)pkt->data;
IWM_DPRINTF(sc, IWM_DEBUG_INTR,
"TE notif status = 0x%x action = 0x%x\n",
notif->status, notif->action);
case IWM_TIME_EVENT_NOTIFICATION:
iwm_mvm_rx_time_event_notif(sc, pkt);
break;
}
/*
* Firmware versions 21 and 22 generate some DEBUG_LOG_MSG

View File

@ -159,12 +159,73 @@ __FBSDID("$FreeBSD$");
#include <dev/iwm/if_iwm_pcie_trans.h>
#include <dev/iwm/if_iwm_time_event.h>
#define TU_TO_HZ(tu) (((uint64_t)(tu) * 1024 * hz) / 1000000)
static void
iwm_mvm_te_clear_data(struct iwm_softc *sc)
{
sc->sc_time_event_uid = 0;
sc->sc_time_event_duration = 0;
sc->sc_time_event_end_ticks = 0;
sc->sc_flags &= ~IWM_FLAG_TE_ACTIVE;
}
/*
* For the high priority TE use a time event type that has similar priority to
* the FW's action scan priority.
* Handles a FW notification for an event that is known to the driver.
*
* @mvm: the mvm component
* @te_data: the time event data
* @notif: the notification data corresponding the time event data.
*/
#define IWM_MVM_ROC_TE_TYPE_NORMAL IWM_TE_P2P_DEVICE_DISCOVERABLE
#define IWM_MVM_ROC_TE_TYPE_MGMT_TX IWM_TE_P2P_CLIENT_ASSOC
static void
iwm_mvm_te_handle_notif(struct iwm_softc *sc,
struct iwm_time_event_notif *notif)
{
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"Handle time event notif - UID = 0x%x action %d\n",
le32toh(notif->unique_id),
le32toh(notif->action));
if (!le32toh(notif->status)) {
const char *msg;
if (notif->action & htole32(IWM_TE_V2_NOTIF_HOST_EVENT_START))
msg = "Time Event start notification failure";
else
msg = "Time Event end notification failure";
IWM_DPRINTF(sc, IWM_DEBUG_TE, "%s\n", msg);
}
if (le32toh(notif->action) & IWM_TE_V2_NOTIF_HOST_EVENT_END) {
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"TE ended - current time %d, estimated end %d\n",
ticks, sc->sc_time_event_end_ticks);
iwm_mvm_te_clear_data(sc);
} else if (le32toh(notif->action) & IWM_TE_V2_NOTIF_HOST_EVENT_START) {
sc->sc_time_event_end_ticks =
ticks + TU_TO_HZ(sc->sc_time_event_duration);
} else {
device_printf(sc->sc_dev, "Got TE with unknown action\n");
}
}
/*
* The Rx handler for time event notifications
*/
void
iwm_mvm_rx_time_event_notif(struct iwm_softc *sc, struct iwm_rx_packet *pkt)
{
struct iwm_time_event_notif *notif = (void *)pkt->data;
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"Time event notification - UID = 0x%x action %d\n",
le32toh(notif->unique_id),
le32toh(notif->action));
iwm_mvm_te_handle_notif(sc, notif);
}
static int
iwm_mvm_te_notif(struct iwm_softc *sc, struct iwm_rx_packet *pkt,
@ -241,6 +302,8 @@ iwm_mvm_time_event_send_add(struct iwm_softc *sc, struct iwm_vap *ivp,
IWM_DPRINTF(sc, IWM_DEBUG_TE,
"Add new TE, duration %d TU\n", le32toh(te_cmd->duration));
sc->sc_time_event_duration = le32toh(te_cmd->duration);
/*
* Use a notification wait, which really just processes the
* command response and doesn't wait for anything, in order
@ -279,8 +342,6 @@ iwm_mvm_time_event_send_add(struct iwm_softc *sc, struct iwm_vap *ivp,
return ret;
}
#define TU_TO_HZ(tu) (((uint64_t)(tu) * 1024 * hz) / 1000000)
void
iwm_mvm_protect_session(struct iwm_softc *sc, struct iwm_vap *ivp,
uint32_t duration, uint32_t max_delay, boolean_t wait_for_notif)
@ -362,7 +423,7 @@ iwm_mvm_stop_session_protection(struct iwm_softc *sc, struct iwm_vap *ivp)
"%s: Removing TE 0x%x\n", __func__, le32toh(time_cmd.id));
if (iwm_mvm_send_cmd_pdu(sc, IWM_TIME_EVENT_CMD, 0, sizeof(time_cmd),
&time_cmd) == 0)
sc->sc_flags &= ~IWM_FLAG_TE_ACTIVE;
iwm_mvm_te_clear_data(sc);
DELAY(100);
}

View File

@ -107,6 +107,8 @@
#ifndef __IF_IWM_TIME_EVENT_H__
#define __IF_IWM_TIME_EVENT_H__
extern void iwm_mvm_rx_time_event_notif(struct iwm_softc *sc,
struct iwm_rx_packet *pkt);
extern void iwm_mvm_protect_session(struct iwm_softc *sc, struct iwm_vap *ivp,
uint32_t duration, uint32_t max_delay, boolean_t wait_for_notif);
extern void iwm_mvm_stop_session_protection(struct iwm_softc *sc,

View File

@ -566,6 +566,12 @@ struct iwm_softc {
/* Unique ID (assigned by the firmware) of the current Time Event. */
uint32_t sc_time_event_uid;
/* Duration of the Time Event in TU. */
uint32_t sc_time_event_duration;
/* Expected end of the Time Event in HZ ticks. */
int sc_time_event_end_ticks;
};
#define IWM_LOCK_INIT(_sc) \