/* Use this for Rx handlers that do not need notification validation */ #define RX_HANDLER_NO_VAL(_grp, _cmd, _name, _context) \
{.cmd_id = WIDE_ID(_grp, _cmd), \
.context = _context, \
.fn = iwl_mld_handle_##_name, \
},
/* Currently only defined for the RX_HANDLER_SIZES options. Use this for * notifications that belong to a specific object, and that should be * canceled when the object is removed
*/ #define RX_HANDLER_OF_OBJ(_grp, _cmd, _name, _obj_type) \
{.cmd_id = WIDE_ID(_grp, _cmd), \ /* Only async handlers can be canceled */ \
.context = RX_HANDLER_ASYNC, \
.fn = iwl_mld_handle_##_name, \
.sizes = iwl_notif_struct_sizes_##_name, \
.n_sizes = ARRAY_SIZE(iwl_notif_struct_sizes_##_name), \
.obj_type = IWL_MLD_OBJECT_TYPE_##_obj_type, \
.cancel = iwl_mld_cancel_##_name, \
},
/* MU-MIMO Group Id action frame is little endian. We treat * the data received from firmware as if it came from the * action frame, so no conversion is needed.
*/
ieee80211_update_mu_groups(vif, link_id,
(u8 *)¬if->membership_status,
(u8 *)¬if->user_position);
}
}
/* This handler is called in SYNC mode because it needs to be serialized with * Rx as specified in ieee80211_update_mu_groups()'s documentation.
*/ staticvoid iwl_mld_handle_mu_mimo_grp_notif(struct iwl_mld *mld, struct iwl_rx_packet *pkt)
{ struct iwl_mu_group_mgmt_notif *notif = (void *)pkt->data;
switch (vif->type) { case NL80211_IFTYPE_AP: /* We don't support canceling a CSA as it was advertised * by the AP itself
*/ if (!link_conf->csa_active) return;
ieee80211_csa_finish(vif, link_conf->link_id); break; case NL80211_IFTYPE_STATION: if (!link_conf->csa_active) { /* Either unexpected cs notif or mac80211 chose to * ignore, for example in channel switch to same channel
*/ struct iwl_cancel_channel_switch_cmd cmd = {
.id = cpu_to_le32(link_id),
};
if (iwl_mld_send_cmd_pdu(mld,
WIDE_ID(MAC_CONF_GROUP,
CANCEL_CHANNEL_SWITCH_CMD),
&cmd))
IWL_ERR(mld, "Failed to cancel the channel switch\n"); return;
}
/** * DOC: Notification versioning * * The firmware's notifications change from time to time. In order to * differentiate between different versions of the same notification, the * firmware advertises the version of each notification. * Here are listed all the notifications that are supported. Several versions * of the same notification can be allowed at the same time: * * CMD_VERSION(my_multi_version_notif, * CMD_VER_ENTRY(1, iwl_my_multi_version_notif_ver1) * CMD_VER_ENTRY(2, iwl_my_multi_version_notif_ver2) * * etc... * * The driver will enforce that the notification coming from the firmware * has its version listed here and it'll also enforce that the firmware sent * at least enough bytes to cover the structure listed in the CMD_VER_ENTRY.
*/
/** * DOC: Handlers for fw notifications * * Here are listed the notifications IDs (including the group ID), the handler * of the notification and how it should be called: * * - RX_HANDLER_SYNC: will be called as part of the Rx path * - RX_HANDLER_ASYNC: will be handled in a working with the wiphy_lock held * * This means that if the firmware sends two notifications A and B in that * order and notification A is RX_HANDLER_ASYNC and notification is * RX_HANDLER_SYNC, the handler of B will likely be called before the handler * of A. * * This list should be in order of frequency for performance purposes. * The handler can be one from two contexts, see &iwl_rx_handler_context * * A handler can declare that it relies on a specific object in which case it * can be cancelled in case the object is deleted. In order to use this * mechanism, a cancellation function is needed. The cancellation function must * receive an object id (the index of that object in the firmware) and a * notification payload. It'll return true if that specific notification should * be cancelled upon the obliteration of the specific instance of the object. * * DEFINE_SIMPLE_CANCELLATION allows to easily create a cancellation function * that wills simply return true if a given object id matches the object id in * the firmware notification.
*/
/* If n_sizes == 0, it indicates that a validation function may be used * or that no validation is required.
*/ if (!handler->n_sizes) { if (handler->val_fn) return handler->val_fn(mld, pkt); returntrue;
}
staticvoid iwl_mld_rx_notif(struct iwl_mld *mld, struct iwl_rx_cmd_buffer *rxb, struct iwl_rx_packet *pkt)
{ for (int i = 0; i < ARRAY_SIZE(iwl_mld_rx_handlers); i++) { conststruct iwl_rx_handler *rx_h = &iwl_mld_rx_handlers[i]; struct iwl_async_handler_entry *entry;
if (rx_h->cmd_id != WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd)) continue;
if (!iwl_mld_notif_is_valid(mld, pkt, rx_h)) return;
if (rx_h->context == RX_HANDLER_SYNC) {
rx_h->fn(mld, pkt); break;
}
entry = kzalloc(sizeof(*entry), GFP_ATOMIC); /* we can't do much... */ if (!entry) return;
/* Set the async handler entry */
entry->rxb._page = rxb_steal_page(rxb);
entry->rxb._offset = rxb->_offset;
entry->rxb._rx_page_order = rxb->_rx_page_order;
entry->rx_h = rx_h;
/* Add it to the list and queue the work */
spin_lock(&mld->async_handlers_lock);
list_add_tail(&entry->list, &mld->async_handlers_list);
spin_unlock(&mld->async_handlers_lock);
/* Sync with Rx path with a lock. Remove all the entries from this * list, add them to a local one (lock free), and then handle them.
*/
spin_lock_bh(&mld->async_handlers_lock);
list_splice_init(&mld->async_handlers_list, &local_list);
spin_unlock_bh(&mld->async_handlers_lock);
if (WARN_ON(obj_type == IWL_MLD_OBJECT_TYPE_NONE)) return;
/* Sync with RX path and remove matching entries from the async list */
spin_lock_bh(&mld->async_handlers_lock);
list_for_each_entry_safe(entry, tmp, &mld->async_handlers_list, list) { conststruct iwl_rx_handler *rx_h = entry->rx_h;
if (rx_h->obj_type != obj_type || WARN_ON(!rx_h->cancel)) continue;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.