Skip to content

Commit d6a5c56

Browse files
Arend van SprielKalle Valo
authored andcommitted
wifi: brcmfmac: add support for vendor-specific firmware api
The driver is being used by multiple vendors who develop the firmware api independently. So far the firmware api as used by the driver has not diverged (yet). This change adds framework for supporting multiple firmware apis. The vendor-specific support code has to provide a number of callback operations. Right now it is only attach and detach callbacks so no real functionality as the api is still common. This code only adds WCC variant anyway, which is selected for all devices right now. The vendor-specific part will be built in a separate module when the driver is configured to be built as a module through Kconfig, ie. when CONFIG_BRCMFMAC=m. Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com> Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com> Reviewed-by: Franky Lin <franky.lin@broadcom.com> Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com> Signed-off-by: Kalle Valo <kvalo@kernel.org> Link: https://lore.kernel.org/r/20221129135446.151065-4-arend.vanspriel@broadcom.com
1 parent da6d9c8 commit d6a5c56

File tree

10 files changed

+334
-0
lines changed

10 files changed

+334
-0
lines changed

drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ brcmfmac-objs += \
2020
common.o \
2121
core.o \
2222
firmware.o \
23+
fwvid.o \
2324
feature.o \
2425
btcoex.o \
2526
vendor.o \
@@ -47,3 +48,9 @@ brcmfmac-$(CONFIG_OF) += \
4748
of.o
4849
brcmfmac-$(CONFIG_DMI) += \
4950
dmi.o
51+
52+
ifeq ($(CONFIG_BRCMFMAC),m)
53+
obj-m += wcc/
54+
else
55+
brcmfmac-$(CONFIG_BRCMFMAC) += wcc/core.o
56+
endif

drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,9 @@ struct brcmf_bus_stats {
155155
* @fwvid: firmware vendor-support identifier of the device.
156156
* @always_use_fws_queue: bus wants use queue also when fwsignal is inactive.
157157
* @wowl_supported: is wowl supported by bus driver.
158+
* @ops: callbacks for this bus instance.
158159
* @msgbuf: msgbuf protocol parameters provided by bus layer.
160+
* @list: member used to add this bus instance to linked list.
159161
*/
160162
struct brcmf_bus {
161163
union {
@@ -177,6 +179,8 @@ struct brcmf_bus {
177179

178180
const struct brcmf_bus_ops *ops;
179181
struct brcmf_bus_msgbuf *msgbuf;
182+
183+
struct list_head list;
180184
};
181185

182186
/*

drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "core.h"
2020
#include "bus.h"
21+
#include "fwvid.h"
2122
#include "debug.h"
2223
#include "fwil_types.h"
2324
#include "p2p.h"
@@ -1332,6 +1333,12 @@ int brcmf_attach(struct device *dev)
13321333
/* Link to bus module */
13331334
drvr->hdrlen = 0;
13341335

1336+
ret = brcmf_fwvid_attach(drvr);
1337+
if (ret != 0) {
1338+
bphy_err(drvr, "brcmf_fwvid_attach failed\n");
1339+
goto fail;
1340+
}
1341+
13351342
/* Attach and link in the protocol */
13361343
ret = brcmf_proto_attach(drvr);
13371344
if (ret != 0) {
@@ -1443,6 +1450,8 @@ void brcmf_detach(struct device *dev)
14431450
brcmf_cfg80211_detach(drvr->config);
14441451
drvr->config = NULL;
14451452
}
1453+
1454+
brcmf_fwvid_detach(drvr);
14461455
}
14471456

14481457
void brcmf_free(struct device *dev)

drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ struct brcmf_pub {
137137

138138
u8 clmver[BRCMF_DCMD_SMLEN];
139139
u8 sta_mac_idx;
140+
const struct brcmf_fwvid_ops *vops;
141+
void *vdata;
140142
};
141143

142144
/* forward declarations */
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
// SPDX-License-Identifier: ISC
2+
/*
3+
* Copyright (c) 2022 Broadcom Corporation
4+
*/
5+
#include <linux/errno.h>
6+
#include <linux/export.h>
7+
#include <linux/module.h>
8+
#include <linux/kmod.h>
9+
#include <linux/list.h>
10+
#include <linux/completion.h>
11+
#include <linux/mutex.h>
12+
#include <linux/printk.h>
13+
#include <linux/jiffies.h>
14+
#include <linux/workqueue.h>
15+
16+
#include "core.h"
17+
#include "bus.h"
18+
#include "debug.h"
19+
#include "fwvid.h"
20+
21+
#include "wcc/vops.h"
22+
23+
struct brcmf_fwvid_entry {
24+
const char *name;
25+
const struct brcmf_fwvid_ops *vops;
26+
struct list_head drvr_list;
27+
#if IS_MODULE(CONFIG_BRCMFMAC)
28+
struct module *vmod;
29+
struct completion reg_done;
30+
#endif
31+
};
32+
33+
static DEFINE_MUTEX(fwvid_list_lock);
34+
35+
#if IS_MODULE(CONFIG_BRCMFMAC)
36+
#define FWVID_ENTRY_INIT(_vid, _name) \
37+
[BRCMF_FWVENDOR_ ## _vid] = { \
38+
.name = #_name, \
39+
.reg_done = COMPLETION_INITIALIZER(fwvid_list[BRCMF_FWVENDOR_ ## _vid].reg_done), \
40+
.drvr_list = LIST_HEAD_INIT(fwvid_list[BRCMF_FWVENDOR_ ## _vid].drvr_list), \
41+
}
42+
#else
43+
#define FWVID_ENTRY_INIT(_vid, _name) \
44+
[BRCMF_FWVENDOR_ ## _vid] = { \
45+
.name = #_name, \
46+
.drvr_list = LIST_HEAD_INIT(fwvid_list[BRCMF_FWVENDOR_ ## _vid].drvr_list), \
47+
.vops = _vid ## _VOPS \
48+
}
49+
#endif /* IS_MODULE(CONFIG_BRCMFMAC) */
50+
51+
static struct brcmf_fwvid_entry fwvid_list[BRCMF_FWVENDOR_NUM] = {
52+
FWVID_ENTRY_INIT(WCC, wcc),
53+
};
54+
55+
#if IS_MODULE(CONFIG_BRCMFMAC)
56+
static int brcmf_fwvid_request_module(enum brcmf_fwvendor fwvid)
57+
{
58+
int ret;
59+
60+
if (!fwvid_list[fwvid].vmod) {
61+
struct completion *reg_done = &fwvid_list[fwvid].reg_done;
62+
63+
mutex_unlock(&fwvid_list_lock);
64+
65+
ret = request_module("brcmfmac-%s", fwvid_list[fwvid].name);
66+
if (ret)
67+
goto fail;
68+
69+
ret = wait_for_completion_interruptible(reg_done);
70+
if (ret)
71+
goto fail;
72+
73+
mutex_lock(&fwvid_list_lock);
74+
}
75+
return 0;
76+
77+
fail:
78+
brcmf_err("mod=%s: failed %d\n", fwvid_list[fwvid].name, ret);
79+
return ret;
80+
}
81+
82+
int brcmf_fwvid_register_vendor(enum brcmf_fwvendor fwvid, struct module *vmod,
83+
const struct brcmf_fwvid_ops *vops)
84+
{
85+
if (fwvid >= BRCMF_FWVENDOR_NUM)
86+
return -ERANGE;
87+
88+
if (WARN_ON(!vmod) || WARN_ON(!vops) ||
89+
WARN_ON(!vops->attach) || WARN_ON(!vops->detach))
90+
return -EINVAL;
91+
92+
if (WARN_ON(fwvid_list[fwvid].vmod))
93+
return -EEXIST;
94+
95+
brcmf_dbg(TRACE, "mod=%s: enter\n", fwvid_list[fwvid].name);
96+
97+
mutex_lock(&fwvid_list_lock);
98+
99+
fwvid_list[fwvid].vmod = vmod;
100+
fwvid_list[fwvid].vops = vops;
101+
102+
mutex_unlock(&fwvid_list_lock);
103+
104+
complete_all(&fwvid_list[fwvid].reg_done);
105+
106+
return 0;
107+
}
108+
EXPORT_SYMBOL(brcmf_fwvid_register_vendor);
109+
110+
int brcmf_fwvid_unregister_vendor(enum brcmf_fwvendor fwvid, struct module *mod)
111+
{
112+
struct brcmf_bus *bus, *tmp;
113+
114+
if (fwvid >= BRCMF_FWVENDOR_NUM)
115+
return -ERANGE;
116+
117+
if (WARN_ON(fwvid_list[fwvid].vmod != mod))
118+
return -ENOENT;
119+
120+
mutex_lock(&fwvid_list_lock);
121+
122+
list_for_each_entry_safe(bus, tmp, &fwvid_list[fwvid].drvr_list, list) {
123+
mutex_unlock(&fwvid_list_lock);
124+
125+
brcmf_dbg(INFO, "mod=%s: removing %s\n", fwvid_list[fwvid].name,
126+
dev_name(bus->dev));
127+
brcmf_bus_remove(bus);
128+
129+
mutex_lock(&fwvid_list_lock);
130+
}
131+
132+
fwvid_list[fwvid].vmod = NULL;
133+
fwvid_list[fwvid].vops = NULL;
134+
reinit_completion(&fwvid_list[fwvid].reg_done);
135+
136+
brcmf_dbg(TRACE, "mod=%s: exit\n", fwvid_list[fwvid].name);
137+
mutex_unlock(&fwvid_list_lock);
138+
139+
return 0;
140+
}
141+
EXPORT_SYMBOL(brcmf_fwvid_unregister_vendor);
142+
#else
143+
static inline int brcmf_fwvid_request_module(enum brcmf_fwvendor fwvid)
144+
{
145+
return 0;
146+
}
147+
#endif
148+
149+
int brcmf_fwvid_attach_ops(struct brcmf_pub *drvr)
150+
{
151+
enum brcmf_fwvendor fwvid = drvr->bus_if->fwvid;
152+
int ret;
153+
154+
if (fwvid >= ARRAY_SIZE(fwvid_list))
155+
return -ERANGE;
156+
157+
brcmf_dbg(TRACE, "mod=%s: enter: dev %s\n", fwvid_list[fwvid].name,
158+
dev_name(drvr->bus_if->dev));
159+
160+
mutex_lock(&fwvid_list_lock);
161+
162+
ret = brcmf_fwvid_request_module(fwvid);
163+
if (ret)
164+
return ret;
165+
166+
drvr->vops = fwvid_list[fwvid].vops;
167+
list_add(&drvr->bus_if->list, &fwvid_list[fwvid].drvr_list);
168+
169+
mutex_unlock(&fwvid_list_lock);
170+
171+
return ret;
172+
}
173+
174+
void brcmf_fwvid_detach_ops(struct brcmf_pub *drvr)
175+
{
176+
enum brcmf_fwvendor fwvid = drvr->bus_if->fwvid;
177+
178+
if (fwvid >= ARRAY_SIZE(fwvid_list))
179+
return;
180+
181+
brcmf_dbg(TRACE, "mod=%s: enter: dev %s\n", fwvid_list[fwvid].name,
182+
dev_name(drvr->bus_if->dev));
183+
184+
mutex_lock(&fwvid_list_lock);
185+
186+
drvr->vops = NULL;
187+
list_del(&drvr->bus_if->list);
188+
189+
mutex_unlock(&fwvid_list_lock);
190+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/* SPDX-License-Identifier: ISC */
2+
/*
3+
* Copyright (c) 2022 Broadcom Corporation
4+
*/
5+
#ifndef FWVID_H_
6+
#define FWVID_H_
7+
8+
#include "firmware.h"
9+
10+
struct brcmf_pub;
11+
12+
struct brcmf_fwvid_ops {
13+
int (*attach)(struct brcmf_pub *drvr);
14+
void (*detach)(struct brcmf_pub *drvr);
15+
};
16+
17+
/* exported functions */
18+
int brcmf_fwvid_register_vendor(enum brcmf_fwvendor fwvid, struct module *mod,
19+
const struct brcmf_fwvid_ops *ops);
20+
int brcmf_fwvid_unregister_vendor(enum brcmf_fwvendor fwvid, struct module *mod);
21+
22+
/* core driver functions */
23+
int brcmf_fwvid_attach_ops(struct brcmf_pub *drvr);
24+
void brcmf_fwvid_detach_ops(struct brcmf_pub *drvr);
25+
26+
static inline int brcmf_fwvid_attach(struct brcmf_pub *drvr)
27+
{
28+
int ret;
29+
30+
ret = brcmf_fwvid_attach_ops(drvr);
31+
if (ret)
32+
return ret;
33+
34+
return drvr->vops->attach(drvr);
35+
}
36+
37+
static inline void brcmf_fwvid_detach(struct brcmf_pub *drvr)
38+
{
39+
if (!drvr->vops)
40+
return;
41+
42+
drvr->vops->detach(drvr);
43+
brcmf_fwvid_detach_ops(drvr);
44+
}
45+
46+
#endif /* FWVID_H_ */
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# SPDX-License-Identifier: ISC
2+
#
3+
# Copyright (c) 2022 Broadcom Corporation
4+
5+
ccflags-y += \
6+
-I $(srctree)/$(src) \
7+
-I $(srctree)/$(src)/.. \
8+
-I $(srctree)/$(src)/../../include
9+
10+
obj-m += brcmfmac-wcc.o
11+
brcmfmac-wcc-objs += \
12+
core.o module.o
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// SPDX-License-Identifier: ISC
2+
/*
3+
* Copyright (c) 2022 Broadcom Corporation
4+
*/
5+
#include <linux/errno.h>
6+
#include <linux/types.h>
7+
#include <core.h>
8+
#include <bus.h>
9+
#include <fwvid.h>
10+
11+
#include "vops.h"
12+
13+
static int brcmf_wcc_attach(struct brcmf_pub *drvr)
14+
{
15+
pr_err("%s: executing\n", __func__);
16+
return 0;
17+
}
18+
19+
static void brcmf_wcc_detach(struct brcmf_pub *drvr)
20+
{
21+
pr_err("%s: executing\n", __func__);
22+
}
23+
24+
const struct brcmf_fwvid_ops brcmf_wcc_ops = {
25+
.attach = brcmf_wcc_attach,
26+
.detach = brcmf_wcc_detach,
27+
};
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// SPDX-License-Identifier: ISC
2+
/*
3+
* Copyright (c) 2022 Broadcom Corporation
4+
*/
5+
#include <linux/module.h>
6+
#include <bus.h>
7+
#include <core.h>
8+
#include <fwvid.h>
9+
10+
#include "vops.h"
11+
12+
static int __init brcmf_wcc_init(void)
13+
{
14+
return brcmf_fwvid_register_vendor(BRCMF_FWVENDOR_WCC, THIS_MODULE,
15+
&brcmf_wcc_ops);
16+
}
17+
18+
static void __exit brcmf_wcc_exit(void)
19+
{
20+
brcmf_fwvid_unregister_vendor(BRCMF_FWVENDOR_WCC, THIS_MODULE);
21+
}
22+
23+
MODULE_LICENSE("Dual BSD/GPL");
24+
25+
module_init(brcmf_wcc_init);
26+
module_exit(brcmf_wcc_exit);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* SPDX-License-Identifier: ISC */
2+
/*
3+
* Copyright (c) 2022 Broadcom Corporation
4+
*/
5+
#ifndef _BRCMFMAC_WCC_VOPS_H
6+
#define _BRCMFMAC_WCC_VOPS_H
7+
8+
extern const struct brcmf_fwvid_ops brcmf_wcc_ops;
9+
#define WCC_VOPS (&brcmf_wcc_ops)
10+
11+
#endif /* _BRCMFMAC_WCC_VOPS_H */

0 commit comments

Comments
 (0)