1 // SPDX-License-Identifier: ISC 2 /* 3 * Copyright (c) 2012 Broadcom Corporation 4 */ 5 #include <linux/netdevice.h> 6 7 #include "brcmu_wifi.h" 8 #include "brcmu_utils.h" 9 10 #include "cfg80211.h" 11 #include "core.h" 12 #include "debug.h" 13 #include "tracepoint.h" 14 #include "fweh.h" 15 #include "fwil.h" 16 #include "proto.h" 17 #include "bus.h" 18 #include "fwvid.h" 19 /** 20 * struct brcmf_fweh_queue_item - event item on event queue. 21 * 22 * @q: list element for queuing. 23 * @code: event code. 24 * @ifidx: interface index related to this event. 25 * @ifaddr: ethernet address for interface. 26 * @emsg: common parameters of the firmware event message. 27 * @datalen: length of the data array 28 * @data: event specific data part of the firmware event. 29 */ 30 struct brcmf_fweh_queue_item { 31 struct list_head q; 32 u32 code; 33 u8 ifidx; 34 u8 ifaddr[ETH_ALEN]; 35 struct brcmf_event_msg_be emsg; 36 u32 datalen; 37 u8 data[] __counted_by(datalen); 38 }; 39 40 /* 41 * struct brcmf_fweh_event_name - code, name mapping entry. 42 */ 43 struct brcmf_fweh_event_name { 44 enum brcmf_fweh_event_code code; 45 const char *name; 46 }; 47 48 #ifdef DEBUG 49 #define BRCMF_ENUM_DEF(id, val) \ 50 { val, #id }, 51 52 /* array for mapping code to event name */ 53 static struct brcmf_fweh_event_name fweh_event_names[] = { 54 BRCMF_FWEH_EVENT_ENUM_DEFLIST 55 }; 56 #undef BRCMF_ENUM_DEF 57 58 /** 59 * brcmf_fweh_event_name() - returns name for given event code. 60 * 61 * @code: code to lookup. 62 */ 63 const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code) 64 { 65 int i; 66 for (i = 0; i < ARRAY_SIZE(fweh_event_names); i++) { 67 if (fweh_event_names[i].code == code) 68 return fweh_event_names[i].name; 69 } 70 return "unknown"; 71 } 72 #else 73 const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code) 74 { 75 return "nodebug"; 76 } 77 #endif 78 BRCMF_EXPORT_SYMBOL_GPL(brcmf_fweh_event_name); 79 80 /** 81 * brcmf_fweh_queue_event() - create and queue event. 82 * 83 * @fweh: firmware event handling info. 84 * @event: event queue entry. 85 */ 86 static void brcmf_fweh_queue_event(struct brcmf_fweh_info *fweh, 87 struct brcmf_fweh_queue_item *event) 88 { 89 ulong flags; 90 91 spin_lock_irqsave(&fweh->evt_q_lock, flags); 92 list_add_tail(&event->q, &fweh->event_q); 93 spin_unlock_irqrestore(&fweh->evt_q_lock, flags); 94 schedule_work(&fweh->event_work); 95 } 96 97 static int brcmf_fweh_call_event_handler(struct brcmf_pub *drvr, 98 struct brcmf_if *ifp, 99 u32 fwcode, 100 struct brcmf_event_msg *emsg, 101 void *data) 102 { 103 struct brcmf_fweh_info *fweh; 104 int err = -EINVAL; 105 106 if (ifp) { 107 fweh = ifp->drvr->fweh; 108 109 /* handle the event if valid interface and handler */ 110 if (fweh->evt_handler[fwcode]) 111 err = fweh->evt_handler[fwcode](ifp, emsg, data); 112 else 113 bphy_err(drvr, "unhandled fwevt %d ignored\n", fwcode); 114 } else { 115 bphy_err(drvr, "no interface object\n"); 116 } 117 return err; 118 } 119 120 /** 121 * brcmf_fweh_handle_if_event() - handle IF event. 122 * 123 * @drvr: driver information object. 124 * @emsg: event message object. 125 * @data: event object. 126 */ 127 static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, 128 struct brcmf_event_msg *emsg, 129 void *data) 130 { 131 struct brcmf_if_event *ifevent = data; 132 struct brcmf_if *ifp; 133 bool is_p2pdev; 134 135 brcmf_dbg(EVENT, "action: %u ifidx: %u bsscfgidx: %u flags: %u role: %u\n", 136 ifevent->action, ifevent->ifidx, ifevent->bsscfgidx, 137 ifevent->flags, ifevent->role); 138 139 /* The P2P Device interface event must not be ignored contrary to what 140 * firmware tells us. Older firmware uses p2p noif, with sta role. 141 * This should be accepted when p2pdev_setup is ongoing. TDLS setup will 142 * use the same ifevent and should be ignored. 143 */ 144 is_p2pdev = ((ifevent->flags & BRCMF_E_IF_FLAG_NOIF) && 145 (ifevent->role == BRCMF_E_IF_ROLE_P2P_CLIENT || 146 ((ifevent->role == BRCMF_E_IF_ROLE_STA) && 147 (drvr->fweh->p2pdev_setup_ongoing)))); 148 if (!is_p2pdev && (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) { 149 brcmf_dbg(EVENT, "event can be ignored\n"); 150 return; 151 } 152 if (ifevent->ifidx >= BRCMF_MAX_IFS) { 153 bphy_err(drvr, "invalid interface index: %u\n", ifevent->ifidx); 154 return; 155 } 156 157 ifp = drvr->iflist[ifevent->bsscfgidx]; 158 159 if (ifevent->action == BRCMF_E_IF_ADD) { 160 brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname, 161 emsg->addr); 162 ifp = brcmf_add_if(drvr, ifevent->bsscfgidx, ifevent->ifidx, 163 is_p2pdev, emsg->ifname, emsg->addr); 164 if (IS_ERR(ifp)) 165 return; 166 if (!is_p2pdev) 167 brcmf_proto_add_if(drvr, ifp); 168 if (!drvr->fweh->evt_handler[BRCMF_E_IF]) 169 if (brcmf_net_attach(ifp, false) < 0) 170 return; 171 } 172 173 if (ifp && ifevent->action == BRCMF_E_IF_CHANGE) 174 brcmf_proto_reset_if(drvr, ifp); 175 176 brcmf_fweh_call_event_handler(drvr, ifp, emsg->event_code, emsg, 177 data); 178 179 if (ifp && ifevent->action == BRCMF_E_IF_DEL) { 180 bool armed = brcmf_cfg80211_vif_event_armed(drvr->config); 181 182 /* Default handling in case no-one waits for this event */ 183 if (!armed) 184 brcmf_remove_interface(ifp, false); 185 } 186 } 187 188 static void brcmf_fweh_map_event_code(struct brcmf_fweh_info *fweh, 189 enum brcmf_fweh_event_code code, 190 u32 *fw_code) 191 { 192 int i; 193 194 if (WARN_ON(!fw_code)) 195 return; 196 197 *fw_code = code; 198 if (fweh->event_map) { 199 for (i = 0; i < fweh->event_map->n_items; i++) { 200 if (fweh->event_map->items[i].code == code) { 201 *fw_code = fweh->event_map->items[i].fwevt_code; 202 break; 203 } 204 } 205 } 206 } 207 208 static void brcmf_fweh_map_fwevt_code(struct brcmf_fweh_info *fweh, u32 fw_code, 209 enum brcmf_fweh_event_code *code) 210 { 211 int i; 212 213 if (WARN_ON(!code)) 214 return; 215 216 *code = fw_code; 217 if (fweh->event_map) { 218 for (i = 0; i < fweh->event_map->n_items; i++) { 219 if (fweh->event_map->items[i].fwevt_code == fw_code) { 220 *code = fweh->event_map->items[i].code; 221 break; 222 } 223 } 224 } 225 } 226 227 /** 228 * brcmf_fweh_dequeue_event() - get event from the queue. 229 * 230 * @fweh: firmware event handling info. 231 */ 232 static struct brcmf_fweh_queue_item * 233 brcmf_fweh_dequeue_event(struct brcmf_fweh_info *fweh) 234 { 235 struct brcmf_fweh_queue_item *event = NULL; 236 ulong flags; 237 238 spin_lock_irqsave(&fweh->evt_q_lock, flags); 239 if (!list_empty(&fweh->event_q)) { 240 event = list_first_entry(&fweh->event_q, 241 struct brcmf_fweh_queue_item, q); 242 list_del(&event->q); 243 } 244 spin_unlock_irqrestore(&fweh->evt_q_lock, flags); 245 246 return event; 247 } 248 249 /** 250 * brcmf_fweh_event_worker() - firmware event worker. 251 * 252 * @work: worker object. 253 */ 254 static void brcmf_fweh_event_worker(struct work_struct *work) 255 { 256 struct brcmf_pub *drvr; 257 struct brcmf_if *ifp; 258 struct brcmf_fweh_info *fweh; 259 struct brcmf_fweh_queue_item *event; 260 int err = 0; 261 struct brcmf_event_msg_be *emsg_be; 262 struct brcmf_event_msg emsg; 263 264 fweh = container_of(work, struct brcmf_fweh_info, event_work); 265 drvr = fweh->drvr; 266 267 while ((event = brcmf_fweh_dequeue_event(fweh))) { 268 enum brcmf_fweh_event_code code; 269 270 brcmf_fweh_map_fwevt_code(fweh, event->code, &code); 271 brcmf_dbg(EVENT, "event %s (%u:%u) ifidx %u bsscfg %u addr %pM\n", 272 brcmf_fweh_event_name(code), code, event->code, 273 event->emsg.ifidx, event->emsg.bsscfgidx, 274 event->emsg.addr); 275 if (event->emsg.bsscfgidx >= BRCMF_MAX_IFS) { 276 bphy_err(drvr, "invalid bsscfg index: %u\n", 277 event->emsg.bsscfgidx); 278 goto event_free; 279 } 280 281 /* convert event message */ 282 emsg_be = &event->emsg; 283 emsg.version = be16_to_cpu(emsg_be->version); 284 emsg.flags = be16_to_cpu(emsg_be->flags); 285 emsg.event_code = code; 286 emsg.status = be32_to_cpu(emsg_be->status); 287 emsg.reason = be32_to_cpu(emsg_be->reason); 288 emsg.auth_type = be32_to_cpu(emsg_be->auth_type); 289 emsg.datalen = be32_to_cpu(emsg_be->datalen); 290 memcpy(emsg.addr, emsg_be->addr, ETH_ALEN); 291 memcpy(emsg.ifname, emsg_be->ifname, sizeof(emsg.ifname)); 292 emsg.ifidx = emsg_be->ifidx; 293 emsg.bsscfgidx = emsg_be->bsscfgidx; 294 295 brcmf_dbg(EVENT, " version %u flags %u status %u reason %u\n", 296 emsg.version, emsg.flags, emsg.status, emsg.reason); 297 brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data, 298 min_t(u32, emsg.datalen, 64), 299 "event payload, len=%d\n", emsg.datalen); 300 301 /* special handling of interface event */ 302 if (event->code == BRCMF_E_IF) { 303 brcmf_fweh_handle_if_event(drvr, &emsg, event->data); 304 goto event_free; 305 } 306 307 if (event->code == BRCMF_E_TDLS_PEER_EVENT) 308 ifp = drvr->iflist[0]; 309 else 310 ifp = drvr->iflist[emsg.bsscfgidx]; 311 err = brcmf_fweh_call_event_handler(drvr, ifp, event->code, 312 &emsg, event->data); 313 if (err) { 314 bphy_err(drvr, "event handler failed (%d)\n", 315 event->code); 316 err = 0; 317 } 318 event_free: 319 kfree(event); 320 } 321 } 322 323 /** 324 * brcmf_fweh_p2pdev_setup() - P2P device setup ongoing (or not). 325 * 326 * @ifp: ifp on which setup is taking place or finished. 327 * @ongoing: p2p device setup in progress (or not). 328 */ 329 void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing) 330 { 331 ifp->drvr->fweh->p2pdev_setup_ongoing = ongoing; 332 } 333 334 /** 335 * brcmf_fweh_attach() - initialize firmware event handling. 336 * 337 * @drvr: driver information object. 338 */ 339 int brcmf_fweh_attach(struct brcmf_pub *drvr) 340 { 341 struct brcmf_fweh_info *fweh; 342 int err; 343 344 err = brcmf_fwvid_alloc_fweh_info(drvr); 345 if (err < 0) 346 return err; 347 348 fweh = drvr->fweh; 349 fweh->drvr = drvr; 350 351 fweh->event_mask_len = DIV_ROUND_UP(fweh->num_event_codes, 8); 352 fweh->event_mask = kzalloc(fweh->event_mask_len, GFP_KERNEL); 353 if (!fweh->event_mask) 354 return -ENOMEM; 355 356 INIT_WORK(&fweh->event_work, brcmf_fweh_event_worker); 357 spin_lock_init(&fweh->evt_q_lock); 358 INIT_LIST_HEAD(&fweh->event_q); 359 return 0; 360 } 361 362 /** 363 * brcmf_fweh_detach() - cleanup firmware event handling. 364 * 365 * @drvr: driver information object. 366 */ 367 void brcmf_fweh_detach(struct brcmf_pub *drvr) 368 { 369 struct brcmf_fweh_info *fweh = drvr->fweh; 370 371 if (!fweh) 372 return; 373 374 /* cancel the worker if initialized */ 375 if (fweh->event_work.func) { 376 cancel_work_sync(&fweh->event_work); 377 WARN_ON(!list_empty(&fweh->event_q)); 378 } 379 drvr->fweh = NULL; 380 kfree(fweh->event_mask); 381 kfree(fweh); 382 } 383 384 /** 385 * brcmf_fweh_register() - register handler for given event code. 386 * 387 * @drvr: driver information object. 388 * @code: event code. 389 * @handler: handler for the given event code. 390 */ 391 int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code, 392 brcmf_fweh_handler_t handler) 393 { 394 struct brcmf_fweh_info *fweh = drvr->fweh; 395 u32 evt_handler_idx; 396 397 brcmf_fweh_map_event_code(fweh, code, &evt_handler_idx); 398 399 if (fweh->evt_handler[evt_handler_idx]) { 400 bphy_err(drvr, "event code %d already registered\n", code); 401 return -ENOSPC; 402 } 403 404 fweh->evt_handler[evt_handler_idx] = handler; 405 brcmf_dbg(TRACE, "event handler registered for %s\n", 406 brcmf_fweh_event_name(code)); 407 return 0; 408 } 409 BRCMF_EXPORT_SYMBOL_GPL(brcmf_fweh_register); 410 411 /** 412 * brcmf_fweh_unregister() - remove handler for given code. 413 * 414 * @drvr: driver information object. 415 * @code: event code. 416 */ 417 void brcmf_fweh_unregister(struct brcmf_pub *drvr, 418 enum brcmf_fweh_event_code code) 419 { 420 u32 evt_handler_idx; 421 422 brcmf_dbg(TRACE, "event handler cleared for %s\n", 423 brcmf_fweh_event_name(code)); 424 brcmf_fweh_map_event_code(drvr->fweh, code, &evt_handler_idx); 425 drvr->fweh->evt_handler[evt_handler_idx] = NULL; 426 } 427 428 /** 429 * brcmf_fweh_activate_events() - enables firmware events registered. 430 * 431 * @ifp: primary interface object. 432 */ 433 int brcmf_fweh_activate_events(struct brcmf_if *ifp) 434 { 435 struct brcmf_fweh_info *fweh = ifp->drvr->fweh; 436 enum brcmf_fweh_event_code code; 437 int i, err; 438 439 memset(fweh->event_mask, 0, fweh->event_mask_len); 440 for (i = 0; i < fweh->num_event_codes; i++) { 441 if (fweh->evt_handler[i]) { 442 brcmf_fweh_map_fwevt_code(fweh, i, &code); 443 brcmf_dbg(EVENT, "enable event %s\n", 444 brcmf_fweh_event_name(code)); 445 setbit(fweh->event_mask, i); 446 } 447 } 448 449 /* want to handle IF event as well */ 450 brcmf_dbg(EVENT, "enable event IF\n"); 451 setbit(fweh->event_mask, BRCMF_E_IF); 452 453 /* allow per-vendor method to activate firmware events */ 454 if (!brcmf_fwvid_activate_events(ifp)) 455 return 0; 456 457 err = brcmf_fil_iovar_data_set(ifp, "event_msgs", fweh->event_mask, 458 fweh->event_mask_len); 459 if (err) 460 bphy_err(fweh->drvr, "Set event_msgs error (%d)\n", err); 461 return err; 462 } 463 464 /** 465 * brcmf_fweh_process_event() - process skb as firmware event. 466 * 467 * @drvr: driver information object. 468 * @event_packet: event packet to process. 469 * @packet_len: length of the packet 470 * @gfp: memory allocation flags. 471 * 472 * If the packet buffer contains a firmware event message it will 473 * dispatch the event to a registered handler (using worker). 474 */ 475 void brcmf_fweh_process_event(struct brcmf_pub *drvr, 476 struct brcmf_event *event_packet, 477 u32 packet_len, gfp_t gfp) 478 { 479 u32 fwevt_idx; 480 struct brcmf_fweh_info *fweh = drvr->fweh; 481 struct brcmf_fweh_queue_item *event; 482 void *data; 483 u32 datalen; 484 485 /* get event info */ 486 fwevt_idx = get_unaligned_be32(&event_packet->msg.event_type); 487 datalen = get_unaligned_be32(&event_packet->msg.datalen); 488 data = &event_packet[1]; 489 490 if (fwevt_idx >= fweh->num_event_codes) 491 return; 492 493 if (fwevt_idx != BRCMF_E_IF && !fweh->evt_handler[fwevt_idx]) 494 return; 495 496 if (datalen > BRCMF_DCMD_MAXLEN || 497 datalen + sizeof(*event_packet) > packet_len) 498 return; 499 500 event = kzalloc(struct_size(event, data, datalen), gfp); 501 if (!event) 502 return; 503 504 event->code = fwevt_idx; 505 event->datalen = datalen; 506 event->ifidx = event_packet->msg.ifidx; 507 508 /* use memcpy to get aligned event message */ 509 memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg)); 510 memcpy(event->data, data, datalen); 511 memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN); 512 513 brcmf_fweh_queue_event(fweh, event); 514 } 515