Commit edec4282 authored by Arend van Spriel's avatar Arend van Spriel Committed by Kalle Valo

wifi: brcmfmac: allow per-vendor event handling

The firmware interface also defines events generated by
firmware on the device. As the get/set primitives the
events are likely to diverge between the vendors so this
commit adds support for per-vendor handling. The number
of events may differ so we let the vendor-specific code
allocate the struct brcmf_fweh_info which contains array
of event handlers. The existing event enumeration will be
used by the higher layers and thus are common definitions.
The vendor-specific code can provide a mapping table for
converting the common definition to the vendor-specific
firmware event definition and vice-versa.
Signed-off-by: default avatarArend van Spriel <arend.vanspriel@broadcom.com>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://msgid.link/20240106103835.269149-4-arend.vanspriel@broadcom.com
parent b822015a
...@@ -11,12 +11,29 @@ ...@@ -11,12 +11,29 @@
#include "vops.h" #include "vops.h"
#define BRCMF_BCA_E_LAST 212
static void brcmf_bca_feat_attach(struct brcmf_if *ifp) static void brcmf_bca_feat_attach(struct brcmf_if *ifp)
{ {
/* SAE support not confirmed so disabling for now */ /* SAE support not confirmed so disabling for now */
ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_SAE); ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_SAE);
} }
static int brcmf_bca_alloc_fweh_info(struct brcmf_pub *drvr)
{
struct brcmf_fweh_info *fweh;
fweh = kzalloc(struct_size(fweh, evt_handler, BRCMF_BCA_E_LAST),
GFP_KERNEL);
if (!fweh)
return -ENOMEM;
fweh->num_event_codes = BRCMF_BCA_E_LAST;
drvr->fweh = fweh;
return 0;
}
const struct brcmf_fwvid_ops brcmf_bca_ops = { const struct brcmf_fwvid_ops brcmf_bca_ops = {
.feat_attach = brcmf_bca_feat_attach, .feat_attach = brcmf_bca_feat_attach,
.alloc_fweh_info = brcmf_bca_alloc_fweh_info,
}; };
...@@ -266,7 +266,7 @@ static int brcmf_c_process_cal_blob(struct brcmf_if *ifp) ...@@ -266,7 +266,7 @@ static int brcmf_c_process_cal_blob(struct brcmf_if *ifp)
int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
{ {
struct brcmf_pub *drvr = ifp->drvr; struct brcmf_pub *drvr = ifp->drvr;
s8 eventmask[BRCMF_EVENTING_MASK_LEN]; struct brcmf_fweh_info *fweh = drvr->fweh;
u8 buf[BRCMF_DCMD_SMLEN]; u8 buf[BRCMF_DCMD_SMLEN];
struct brcmf_bus *bus; struct brcmf_bus *bus;
struct brcmf_rev_info_le revinfo; struct brcmf_rev_info_le revinfo;
...@@ -413,15 +413,21 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) ...@@ -413,15 +413,21 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
brcmf_c_set_joinpref_default(ifp); brcmf_c_set_joinpref_default(ifp);
/* Setup event_msgs, enable E_IF */ /* Setup event_msgs, enable E_IF */
err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask, err = brcmf_fil_iovar_data_get(ifp, "event_msgs", fweh->event_mask,
BRCMF_EVENTING_MASK_LEN); fweh->event_mask_len);
if (err) { if (err) {
bphy_err(drvr, "Get event_msgs error (%d)\n", err); bphy_err(drvr, "Get event_msgs error (%d)\n", err);
goto done; goto done;
} }
setbit(eventmask, BRCMF_E_IF); /*
err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask, * BRCMF_E_IF can safely be used to set the appropriate bit
BRCMF_EVENTING_MASK_LEN); * in the event_mask as the firmware event code is guaranteed
* to match the value of BRCMF_E_IF because it is old cruft
* that all vendors have.
*/
setbit(fweh->event_mask, BRCMF_E_IF);
err = brcmf_fil_iovar_data_set(ifp, "event_msgs", fweh->event_mask,
fweh->event_mask_len);
if (err) { if (err) {
bphy_err(drvr, "Set event_msgs error (%d)\n", err); bphy_err(drvr, "Set event_msgs error (%d)\n", err);
goto done; goto done;
......
...@@ -1348,13 +1348,17 @@ int brcmf_attach(struct device *dev) ...@@ -1348,13 +1348,17 @@ int brcmf_attach(struct device *dev)
goto fail; goto fail;
} }
/* attach firmware event handler */
ret = brcmf_fweh_attach(drvr);
if (ret != 0) {
bphy_err(drvr, "brcmf_fweh_attach failed\n");
goto fail;
}
/* Attach to events important for core code */ /* Attach to events important for core code */
brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG, brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG,
brcmf_psm_watchdog_notify); brcmf_psm_watchdog_notify);
/* attach firmware event handler */
brcmf_fweh_attach(drvr);
ret = brcmf_bus_started(drvr, drvr->ops); ret = brcmf_bus_started(drvr, drvr->ops);
if (ret != 0) { if (ret != 0) {
bphy_err(drvr, "dongle is not responding: err=%d\n", ret); bphy_err(drvr, "dongle is not responding: err=%d\n", ret);
......
...@@ -122,7 +122,7 @@ struct brcmf_pub { ...@@ -122,7 +122,7 @@ struct brcmf_pub {
struct mutex proto_block; struct mutex proto_block;
unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
struct brcmf_fweh_info fweh; struct brcmf_fweh_info *fweh;
struct brcmf_ampdu_rx_reorder struct brcmf_ampdu_rx_reorder
*reorder_flows[BRCMF_AMPDU_RX_REORDER_MAXFLOWS]; *reorder_flows[BRCMF_AMPDU_RX_REORDER_MAXFLOWS];
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#include "vops.h" #include "vops.h"
#define BRCMF_CYW_E_LAST 197
static int brcmf_cyw_set_sae_pwd(struct brcmf_if *ifp, static int brcmf_cyw_set_sae_pwd(struct brcmf_if *ifp,
struct cfg80211_crypto_settings *crypto) struct cfg80211_crypto_settings *crypto)
{ {
...@@ -37,6 +39,21 @@ static int brcmf_cyw_set_sae_pwd(struct brcmf_if *ifp, ...@@ -37,6 +39,21 @@ static int brcmf_cyw_set_sae_pwd(struct brcmf_if *ifp,
return err; return err;
} }
static int brcmf_cyw_alloc_fweh_info(struct brcmf_pub *drvr)
{
struct brcmf_fweh_info *fweh;
fweh = kzalloc(struct_size(fweh, evt_handler, BRCMF_CYW_E_LAST),
GFP_KERNEL);
if (!fweh)
return -ENOMEM;
fweh->num_event_codes = BRCMF_CYW_E_LAST;
drvr->fweh = fweh;
return 0;
}
const struct brcmf_fwvid_ops brcmf_cyw_ops = { const struct brcmf_fwvid_ops brcmf_cyw_ops = {
.set_sae_password = brcmf_cyw_set_sae_pwd, .set_sae_password = brcmf_cyw_set_sae_pwd,
.alloc_fweh_info = brcmf_cyw_alloc_fweh_info,
}; };
...@@ -14,7 +14,8 @@ ...@@ -14,7 +14,8 @@
#include "fweh.h" #include "fweh.h"
#include "fwil.h" #include "fwil.h"
#include "proto.h" #include "proto.h"
#include "bus.h"
#include "fwvid.h"
/** /**
* struct brcmf_fweh_queue_item - event item on event queue. * struct brcmf_fweh_queue_item - event item on event queue.
* *
...@@ -28,7 +29,7 @@ ...@@ -28,7 +29,7 @@
*/ */
struct brcmf_fweh_queue_item { struct brcmf_fweh_queue_item {
struct list_head q; struct list_head q;
enum brcmf_fweh_event_code code; u32 code;
u8 ifidx; u8 ifidx;
u8 ifaddr[ETH_ALEN]; u8 ifaddr[ETH_ALEN];
struct brcmf_event_msg_be emsg; struct brcmf_event_msg_be emsg;
...@@ -94,7 +95,7 @@ static void brcmf_fweh_queue_event(struct brcmf_fweh_info *fweh, ...@@ -94,7 +95,7 @@ static void brcmf_fweh_queue_event(struct brcmf_fweh_info *fweh,
static int brcmf_fweh_call_event_handler(struct brcmf_pub *drvr, static int brcmf_fweh_call_event_handler(struct brcmf_pub *drvr,
struct brcmf_if *ifp, struct brcmf_if *ifp,
enum brcmf_fweh_event_code code, u32 fwcode,
struct brcmf_event_msg *emsg, struct brcmf_event_msg *emsg,
void *data) void *data)
{ {
...@@ -102,13 +103,13 @@ static int brcmf_fweh_call_event_handler(struct brcmf_pub *drvr, ...@@ -102,13 +103,13 @@ static int brcmf_fweh_call_event_handler(struct brcmf_pub *drvr,
int err = -EINVAL; int err = -EINVAL;
if (ifp) { if (ifp) {
fweh = &ifp->drvr->fweh; fweh = ifp->drvr->fweh;
/* handle the event if valid interface and handler */ /* handle the event if valid interface and handler */
if (fweh->evt_handler[code]) if (fweh->evt_handler[fwcode])
err = fweh->evt_handler[code](ifp, emsg, data); err = fweh->evt_handler[fwcode](ifp, emsg, data);
else else
bphy_err(drvr, "unhandled event %d ignored\n", code); bphy_err(drvr, "unhandled fwevt %d ignored\n", fwcode);
} else { } else {
bphy_err(drvr, "no interface object\n"); bphy_err(drvr, "no interface object\n");
} }
...@@ -142,7 +143,7 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, ...@@ -142,7 +143,7 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
is_p2pdev = ((ifevent->flags & BRCMF_E_IF_FLAG_NOIF) && is_p2pdev = ((ifevent->flags & BRCMF_E_IF_FLAG_NOIF) &&
(ifevent->role == BRCMF_E_IF_ROLE_P2P_CLIENT || (ifevent->role == BRCMF_E_IF_ROLE_P2P_CLIENT ||
((ifevent->role == BRCMF_E_IF_ROLE_STA) && ((ifevent->role == BRCMF_E_IF_ROLE_STA) &&
(drvr->fweh.p2pdev_setup_ongoing)))); (drvr->fweh->p2pdev_setup_ongoing))));
if (!is_p2pdev && (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) { if (!is_p2pdev && (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) {
brcmf_dbg(EVENT, "event can be ignored\n"); brcmf_dbg(EVENT, "event can be ignored\n");
return; return;
...@@ -163,7 +164,7 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, ...@@ -163,7 +164,7 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
return; return;
if (!is_p2pdev) if (!is_p2pdev)
brcmf_proto_add_if(drvr, ifp); brcmf_proto_add_if(drvr, ifp);
if (!drvr->fweh.evt_handler[BRCMF_E_IF]) if (!drvr->fweh->evt_handler[BRCMF_E_IF])
if (brcmf_net_attach(ifp, false) < 0) if (brcmf_net_attach(ifp, false) < 0)
return; return;
} }
...@@ -183,6 +184,45 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, ...@@ -183,6 +184,45 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
} }
} }
static void brcmf_fweh_map_event_code(struct brcmf_fweh_info *fweh,
enum brcmf_fweh_event_code code,
u32 *fw_code)
{
int i;
if (WARN_ON(!fw_code))
return;
*fw_code = code;
if (fweh->event_map) {
for (i = 0; i < fweh->event_map->n_items; i++) {
if (fweh->event_map->items[i].code == code) {
*fw_code = fweh->event_map->items[i].fwevt_code;
break;
}
}
}
}
static void brcmf_fweh_map_fwevt_code(struct brcmf_fweh_info *fweh, u32 fw_code,
enum brcmf_fweh_event_code *code)
{
int i;
if (WARN_ON(!code))
return;
*code = fw_code;
if (fweh->event_map) {
for (i = 0; i < fweh->event_map->n_items; i++) {
if (fweh->event_map->items[i].fwevt_code == fw_code) {
*code = fweh->event_map->items[i].code;
break;
}
}
}
}
/** /**
* brcmf_fweh_dequeue_event() - get event from the queue. * brcmf_fweh_dequeue_event() - get event from the queue.
* *
...@@ -221,15 +261,19 @@ static void brcmf_fweh_event_worker(struct work_struct *work) ...@@ -221,15 +261,19 @@ static void brcmf_fweh_event_worker(struct work_struct *work)
struct brcmf_event_msg emsg; struct brcmf_event_msg emsg;
fweh = container_of(work, struct brcmf_fweh_info, event_work); fweh = container_of(work, struct brcmf_fweh_info, event_work);
drvr = container_of(fweh, struct brcmf_pub, fweh); drvr = fweh->drvr;
while ((event = brcmf_fweh_dequeue_event(fweh))) { while ((event = brcmf_fweh_dequeue_event(fweh))) {
brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n", enum brcmf_fweh_event_code code;
brcmf_fweh_event_name(event->code), event->code,
brcmf_fweh_map_fwevt_code(fweh, event->code, &code);
brcmf_dbg(EVENT, "event %s (%u:%u) ifidx %u bsscfg %u addr %pM\n",
brcmf_fweh_event_name(code), code, event->code,
event->emsg.ifidx, event->emsg.bsscfgidx, event->emsg.ifidx, event->emsg.bsscfgidx,
event->emsg.addr); event->emsg.addr);
if (event->emsg.bsscfgidx >= BRCMF_MAX_IFS) { if (event->emsg.bsscfgidx >= BRCMF_MAX_IFS) {
bphy_err(drvr, "invalid bsscfg index: %u\n", event->emsg.bsscfgidx); bphy_err(drvr, "invalid bsscfg index: %u\n",
event->emsg.bsscfgidx);
goto event_free; goto event_free;
} }
...@@ -237,7 +281,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work) ...@@ -237,7 +281,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work)
emsg_be = &event->emsg; emsg_be = &event->emsg;
emsg.version = be16_to_cpu(emsg_be->version); emsg.version = be16_to_cpu(emsg_be->version);
emsg.flags = be16_to_cpu(emsg_be->flags); emsg.flags = be16_to_cpu(emsg_be->flags);
emsg.event_code = event->code; emsg.event_code = code;
emsg.status = be32_to_cpu(emsg_be->status); emsg.status = be32_to_cpu(emsg_be->status);
emsg.reason = be32_to_cpu(emsg_be->reason); emsg.reason = be32_to_cpu(emsg_be->reason);
emsg.auth_type = be32_to_cpu(emsg_be->auth_type); emsg.auth_type = be32_to_cpu(emsg_be->auth_type);
...@@ -283,7 +327,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work) ...@@ -283,7 +327,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work)
*/ */
void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing) void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing)
{ {
ifp->drvr->fweh.p2pdev_setup_ongoing = ongoing; ifp->drvr->fweh->p2pdev_setup_ongoing = ongoing;
} }
/** /**
...@@ -291,12 +335,27 @@ void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing) ...@@ -291,12 +335,27 @@ void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing)
* *
* @drvr: driver information object. * @drvr: driver information object.
*/ */
void brcmf_fweh_attach(struct brcmf_pub *drvr) int brcmf_fweh_attach(struct brcmf_pub *drvr)
{ {
struct brcmf_fweh_info *fweh = &drvr->fweh; struct brcmf_fweh_info *fweh;
int err;
err = brcmf_fwvid_alloc_fweh_info(drvr);
if (err < 0)
return err;
fweh = drvr->fweh;
fweh->drvr = drvr;
fweh->event_mask_len = DIV_ROUND_UP(fweh->num_event_codes, 8);
fweh->event_mask = kzalloc(fweh->event_mask_len, GFP_KERNEL);
if (!fweh->event_mask)
return -ENOMEM;
INIT_WORK(&fweh->event_work, brcmf_fweh_event_worker); INIT_WORK(&fweh->event_work, brcmf_fweh_event_worker);
spin_lock_init(&fweh->evt_q_lock); spin_lock_init(&fweh->evt_q_lock);
INIT_LIST_HEAD(&fweh->event_q); INIT_LIST_HEAD(&fweh->event_q);
return 0;
} }
/** /**
...@@ -306,14 +365,19 @@ void brcmf_fweh_attach(struct brcmf_pub *drvr) ...@@ -306,14 +365,19 @@ void brcmf_fweh_attach(struct brcmf_pub *drvr)
*/ */
void brcmf_fweh_detach(struct brcmf_pub *drvr) void brcmf_fweh_detach(struct brcmf_pub *drvr)
{ {
struct brcmf_fweh_info *fweh = &drvr->fweh; struct brcmf_fweh_info *fweh = drvr->fweh;
if (!fweh)
return;
/* cancel the worker if initialized */ /* cancel the worker if initialized */
if (fweh->event_work.func) { if (fweh->event_work.func) {
cancel_work_sync(&fweh->event_work); cancel_work_sync(&fweh->event_work);
WARN_ON(!list_empty(&fweh->event_q)); WARN_ON(!list_empty(&fweh->event_q));
memset(fweh->evt_handler, 0, sizeof(fweh->evt_handler));
} }
drvr->fweh = NULL;
kfree(fweh->event_mask);
kfree(fweh);
} }
/** /**
...@@ -326,11 +390,17 @@ void brcmf_fweh_detach(struct brcmf_pub *drvr) ...@@ -326,11 +390,17 @@ void brcmf_fweh_detach(struct brcmf_pub *drvr)
int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code, int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code,
brcmf_fweh_handler_t handler) brcmf_fweh_handler_t handler)
{ {
if (drvr->fweh.evt_handler[code]) { struct brcmf_fweh_info *fweh = drvr->fweh;
u32 evt_handler_idx;
brcmf_fweh_map_event_code(fweh, code, &evt_handler_idx);
if (fweh->evt_handler[evt_handler_idx]) {
bphy_err(drvr, "event code %d already registered\n", code); bphy_err(drvr, "event code %d already registered\n", code);
return -ENOSPC; return -ENOSPC;
} }
drvr->fweh.evt_handler[code] = handler;
fweh->evt_handler[evt_handler_idx] = handler;
brcmf_dbg(TRACE, "event handler registered for %s\n", brcmf_dbg(TRACE, "event handler registered for %s\n",
brcmf_fweh_event_name(code)); brcmf_fweh_event_name(code));
return 0; return 0;
...@@ -345,9 +415,12 @@ int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code, ...@@ -345,9 +415,12 @@ int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code,
void brcmf_fweh_unregister(struct brcmf_pub *drvr, void brcmf_fweh_unregister(struct brcmf_pub *drvr,
enum brcmf_fweh_event_code code) enum brcmf_fweh_event_code code)
{ {
u32 evt_handler_idx;
brcmf_dbg(TRACE, "event handler cleared for %s\n", brcmf_dbg(TRACE, "event handler cleared for %s\n",
brcmf_fweh_event_name(code)); brcmf_fweh_event_name(code));
drvr->fweh.evt_handler[code] = NULL; brcmf_fweh_map_event_code(drvr->fweh, code, &evt_handler_idx);
drvr->fweh->evt_handler[evt_handler_idx] = NULL;
} }
/** /**
...@@ -357,27 +430,28 @@ void brcmf_fweh_unregister(struct brcmf_pub *drvr, ...@@ -357,27 +430,28 @@ void brcmf_fweh_unregister(struct brcmf_pub *drvr,
*/ */
int brcmf_fweh_activate_events(struct brcmf_if *ifp) int brcmf_fweh_activate_events(struct brcmf_if *ifp)
{ {
struct brcmf_pub *drvr = ifp->drvr; struct brcmf_fweh_info *fweh = ifp->drvr->fweh;
enum brcmf_fweh_event_code code;
int i, err; int i, err;
s8 eventmask[BRCMF_EVENTING_MASK_LEN];
memset(eventmask, 0, sizeof(eventmask)); memset(fweh->event_mask, 0, fweh->event_mask_len);
for (i = 0; i < BRCMF_E_LAST; i++) { for (i = 0; i < fweh->num_event_codes; i++) {
if (ifp->drvr->fweh.evt_handler[i]) { if (fweh->evt_handler[i]) {
brcmf_fweh_map_fwevt_code(fweh, i, &code);
brcmf_dbg(EVENT, "enable event %s\n", brcmf_dbg(EVENT, "enable event %s\n",
brcmf_fweh_event_name(i)); brcmf_fweh_event_name(code));
setbit(eventmask, i); setbit(fweh->event_mask, i);
} }
} }
/* want to handle IF event as well */ /* want to handle IF event as well */
brcmf_dbg(EVENT, "enable event IF\n"); brcmf_dbg(EVENT, "enable event IF\n");
setbit(eventmask, BRCMF_E_IF); setbit(fweh->event_mask, BRCMF_E_IF);
err = brcmf_fil_iovar_data_set(ifp, "event_msgs", err = brcmf_fil_iovar_data_set(ifp, "event_msgs", fweh->event_mask,
eventmask, BRCMF_EVENTING_MASK_LEN); fweh->event_mask_len);
if (err) if (err)
bphy_err(drvr, "Set event_msgs error (%d)\n", err); bphy_err(fweh->drvr, "Set event_msgs error (%d)\n", err);
return err; return err;
} }
...@@ -397,21 +471,21 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr, ...@@ -397,21 +471,21 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
struct brcmf_event *event_packet, struct brcmf_event *event_packet,
u32 packet_len, gfp_t gfp) u32 packet_len, gfp_t gfp)
{ {
enum brcmf_fweh_event_code code; u32 fwevt_idx;
struct brcmf_fweh_info *fweh = &drvr->fweh; struct brcmf_fweh_info *fweh = drvr->fweh;
struct brcmf_fweh_queue_item *event; struct brcmf_fweh_queue_item *event;
void *data; void *data;
u32 datalen; u32 datalen;
/* get event info */ /* get event info */
code = get_unaligned_be32(&event_packet->msg.event_type); fwevt_idx = get_unaligned_be32(&event_packet->msg.event_type);
datalen = get_unaligned_be32(&event_packet->msg.datalen); datalen = get_unaligned_be32(&event_packet->msg.datalen);
data = &event_packet[1]; data = &event_packet[1];
if (code >= BRCMF_E_LAST) if (fwevt_idx >= fweh->num_event_codes)
return; return;
if (code != BRCMF_E_IF && !fweh->evt_handler[code]) if (fwevt_idx != BRCMF_E_IF && !fweh->evt_handler[fwevt_idx])
return; return;
if (datalen > BRCMF_DCMD_MAXLEN || if (datalen > BRCMF_DCMD_MAXLEN ||
...@@ -422,13 +496,13 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr, ...@@ -422,13 +496,13 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
if (!event) if (!event)
return; return;
event->datalen = datalen; event->code = fwevt_idx;
event->code = code;
event->ifidx = event_packet->msg.ifidx; event->ifidx = event_packet->msg.ifidx;
/* use memcpy to get aligned event message */ /* use memcpy to get aligned event message */
memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg)); memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));
memcpy(event->data, data, datalen); memcpy(event->data, data, datalen);
event->datalen = datalen;
memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN); memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN);
brcmf_fweh_queue_event(fweh, event); brcmf_fweh_queue_event(fweh, event);
......
...@@ -17,6 +17,10 @@ struct brcmf_pub; ...@@ -17,6 +17,10 @@ struct brcmf_pub;
struct brcmf_if; struct brcmf_if;
struct brcmf_cfg80211_info; struct brcmf_cfg80211_info;
#define BRCMF_ABSTRACT_EVENT_BIT BIT(31)
#define BRCMF_ABSTRACT_ENUM_DEF(_id, _val) \
BRCMF_ENUM_DEF(_id, (BRCMF_ABSTRACT_EVENT_BIT | (_val)))
/* list of firmware events */ /* list of firmware events */
#define BRCMF_FWEH_EVENT_ENUM_DEFLIST \ #define BRCMF_FWEH_EVENT_ENUM_DEFLIST \
BRCMF_ENUM_DEF(SET_SSID, 0) \ BRCMF_ENUM_DEF(SET_SSID, 0) \
...@@ -98,16 +102,9 @@ struct brcmf_cfg80211_info; ...@@ -98,16 +102,9 @@ struct brcmf_cfg80211_info;
/* firmware event codes sent by the dongle */ /* firmware event codes sent by the dongle */
enum brcmf_fweh_event_code { enum brcmf_fweh_event_code {
BRCMF_FWEH_EVENT_ENUM_DEFLIST BRCMF_FWEH_EVENT_ENUM_DEFLIST
/* this determines event mask length which must match
* minimum length check in device firmware so it is
* hard-coded here.
*/
BRCMF_E_LAST = 139
}; };
#undef BRCMF_ENUM_DEF #undef BRCMF_ENUM_DEF
#define BRCMF_EVENTING_MASK_LEN DIV_ROUND_UP(BRCMF_E_LAST, 8)
/* flags field values in struct brcmf_event_msg */ /* flags field values in struct brcmf_event_msg */
#define BRCMF_EVENT_MSG_LINK 0x01 #define BRCMF_EVENT_MSG_LINK 0x01
#define BRCMF_EVENT_MSG_FLUSHTXQ 0x02 #define BRCMF_EVENT_MSG_FLUSHTXQ 0x02
...@@ -287,6 +284,33 @@ typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp, ...@@ -287,6 +284,33 @@ typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp,
const struct brcmf_event_msg *evtmsg, const struct brcmf_event_msg *evtmsg,
void *data); void *data);
/**
* struct brcmf_fweh_event_map_item - fweh event and firmware event pair.
*
* @code: fweh event code as used by higher layers.
* @fwevt_code: firmware event code as used by firmware.
*
* This mapping is needed when a functionally identical event has a
* different numerical definition between vendors. When such mapping
* is needed the higher layer event code should not collide with the
* firmware event.
*/
struct brcmf_fweh_event_map_item {
enum brcmf_fweh_event_code code;
u32 fwevt_code;
};
/**
* struct brcmf_fweh_event_map - mapping between firmware event and fweh event.
*
* @n_items: number of mapping items.
* @items: array of fweh event and firmware event pairs.
*/
struct brcmf_fweh_event_map {
u32 n_items;
const struct brcmf_fweh_event_map_item items[] __counted_by(n_items);
};
/** /**
* struct brcmf_fweh_info - firmware event handling information. * struct brcmf_fweh_info - firmware event handling information.
* *
...@@ -294,21 +318,33 @@ typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp, ...@@ -294,21 +318,33 @@ typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp,
* @event_work: event worker. * @event_work: event worker.
* @evt_q_lock: lock for event queue protection. * @evt_q_lock: lock for event queue protection.
* @event_q: event queue. * @event_q: event queue.
* @evt_handler: registered event handlers. * @event_mask_len: length of @event_mask used to enable firmware events.
* @event_mask: byte array used in 'event_msgs' iovar command.
* @event_map: mapping between fweh event and firmware event which
* may be provided by vendor-specific module for events that need
* mapping.
* @num_event_codes: number of firmware events supported by firmware which
* does a minimum length check for the @event_mask. This value is to
* be provided by vendor-specific module determining @event_mask_len
* and consequently the allocation size for @event_mask.
* @evt_handler: event handler registry indexed by firmware event code.
*/ */
struct brcmf_fweh_info { struct brcmf_fweh_info {
struct brcmf_pub *drvr;
bool p2pdev_setup_ongoing; bool p2pdev_setup_ongoing;
struct work_struct event_work; struct work_struct event_work;
spinlock_t evt_q_lock; spinlock_t evt_q_lock;
struct list_head event_q; struct list_head event_q;
int (*evt_handler[BRCMF_E_LAST])(struct brcmf_if *ifp, uint event_mask_len;
const struct brcmf_event_msg *evtmsg, u8 *event_mask;
void *data); struct brcmf_fweh_event_map *event_map;
uint num_event_codes;
brcmf_fweh_handler_t evt_handler[] __counted_by(num_event_codes);
}; };
const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code); const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code);
void brcmf_fweh_attach(struct brcmf_pub *drvr); int brcmf_fweh_attach(struct brcmf_pub *drvr);
void brcmf_fweh_detach(struct brcmf_pub *drvr); void brcmf_fweh_detach(struct brcmf_pub *drvr);
int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code, int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code,
int (*handler)(struct brcmf_if *ifp, int (*handler)(struct brcmf_if *ifp,
......
...@@ -89,7 +89,8 @@ int brcmf_fwvid_register_vendor(enum brcmf_fwvendor fwvid, struct module *vmod, ...@@ -89,7 +89,8 @@ int brcmf_fwvid_register_vendor(enum brcmf_fwvendor fwvid, struct module *vmod,
if (fwvid >= BRCMF_FWVENDOR_NUM) if (fwvid >= BRCMF_FWVENDOR_NUM)
return -ERANGE; return -ERANGE;
if (WARN_ON(!vmod) || WARN_ON(!vops)) if (WARN_ON(!vmod) || WARN_ON(!vops) ||
WARN_ON(!vops->alloc_fweh_info))
return -EINVAL; return -EINVAL;
if (WARN_ON(fwvid_list[fwvid].vmod)) if (WARN_ON(fwvid_list[fwvid].vmod))
......
...@@ -14,6 +14,7 @@ struct brcmf_if; ...@@ -14,6 +14,7 @@ struct brcmf_if;
struct brcmf_fwvid_ops { struct brcmf_fwvid_ops {
void (*feat_attach)(struct brcmf_if *ifp); void (*feat_attach)(struct brcmf_if *ifp);
int (*set_sae_password)(struct brcmf_if *ifp, struct cfg80211_crypto_settings *crypto); int (*set_sae_password)(struct brcmf_if *ifp, struct cfg80211_crypto_settings *crypto);
int (*alloc_fweh_info)(struct brcmf_pub *drvr);
}; };
/* exported functions */ /* exported functions */
...@@ -47,4 +48,12 @@ static inline int brcmf_fwvid_set_sae_password(struct brcmf_if *ifp, ...@@ -47,4 +48,12 @@ static inline int brcmf_fwvid_set_sae_password(struct brcmf_if *ifp,
return vops->set_sae_password(ifp, crypto); return vops->set_sae_password(ifp, crypto);
} }
static inline int brcmf_fwvid_alloc_fweh_info(struct brcmf_pub *drvr)
{
if (!drvr->vops)
return -EIO;
return drvr->vops->alloc_fweh_info(drvr);
}
#endif /* FWVID_H_ */ #endif /* FWVID_H_ */
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#include "vops.h" #include "vops.h"
#define BRCMF_WCC_E_LAST 213
static int brcmf_wcc_set_sae_pwd(struct brcmf_if *ifp, static int brcmf_wcc_set_sae_pwd(struct brcmf_if *ifp,
struct cfg80211_crypto_settings *crypto) struct cfg80211_crypto_settings *crypto)
{ {
...@@ -18,6 +20,21 @@ static int brcmf_wcc_set_sae_pwd(struct brcmf_if *ifp, ...@@ -18,6 +20,21 @@ static int brcmf_wcc_set_sae_pwd(struct brcmf_if *ifp,
BRCMF_WSEC_PASSPHRASE); BRCMF_WSEC_PASSPHRASE);
} }
static int brcmf_wcc_alloc_fweh_info(struct brcmf_pub *drvr)
{
struct brcmf_fweh_info *fweh;
fweh = kzalloc(struct_size(fweh, evt_handler, BRCMF_WCC_E_LAST),
GFP_KERNEL);
if (!fweh)
return -ENOMEM;
fweh->num_event_codes = BRCMF_WCC_E_LAST;
drvr->fweh = fweh;
return 0;
}
const struct brcmf_fwvid_ops brcmf_wcc_ops = { const struct brcmf_fwvid_ops brcmf_wcc_ops = {
.set_sae_password = brcmf_wcc_set_sae_pwd, .set_sae_password = brcmf_wcc_set_sae_pwd,
.alloc_fweh_info = brcmf_wcc_alloc_fweh_info,
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment