mirror of
https://github.com/torvalds/linux.git
synced 2024-11-15 08:31:55 +00:00
brcmfmac: introduce feature and quirk handling
Introducing a new source module that will be responsible for identifying features and quirks related to the device being handled. Reviewed-by: Hante Meuleman <meuleman@broadcom.com> Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
ccfd1e810b
commit
c08437b4b5
@ -34,6 +34,7 @@ brcmfmac-objs += \
|
|||||||
dhd_common.o \
|
dhd_common.o \
|
||||||
dhd_linux.o \
|
dhd_linux.o \
|
||||||
firmware.o \
|
firmware.o \
|
||||||
|
feature.o \
|
||||||
btcoex.o \
|
btcoex.o \
|
||||||
vendor.o
|
vendor.o
|
||||||
brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
|
brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
|
||||||
|
@ -103,6 +103,10 @@ struct brcmf_pub {
|
|||||||
|
|
||||||
struct brcmf_ampdu_rx_reorder
|
struct brcmf_ampdu_rx_reorder
|
||||||
*reorder_flows[BRCMF_AMPDU_RX_REORDER_MAXFLOWS];
|
*reorder_flows[BRCMF_AMPDU_RX_REORDER_MAXFLOWS];
|
||||||
|
|
||||||
|
u32 feat_flags;
|
||||||
|
u32 chip_quirks;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
struct dentry *dbgfs_dir;
|
struct dentry *dbgfs_dir;
|
||||||
#endif
|
#endif
|
||||||
@ -175,7 +179,6 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
|
|||||||
void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx);
|
void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx);
|
||||||
void brcmf_txflowblock_if(struct brcmf_if *ifp,
|
void brcmf_txflowblock_if(struct brcmf_if *ifp,
|
||||||
enum brcmf_netif_stop_reason reason, bool state);
|
enum brcmf_netif_stop_reason reason, bool state);
|
||||||
u32 brcmf_get_chip_info(struct brcmf_if *ifp);
|
|
||||||
void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,
|
void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,
|
||||||
bool success);
|
bool success);
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "wl_cfg80211.h"
|
#include "wl_cfg80211.h"
|
||||||
#include "fwil.h"
|
#include "fwil.h"
|
||||||
#include "fwsignal.h"
|
#include "fwsignal.h"
|
||||||
|
#include "feature.h"
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
|
|
||||||
MODULE_AUTHOR("Broadcom Corporation");
|
MODULE_AUTHOR("Broadcom Corporation");
|
||||||
@ -936,6 +937,8 @@ int brcmf_bus_start(struct device *dev)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
brcmf_feat_attach(drvr);
|
||||||
|
|
||||||
ret = brcmf_fws_init(drvr);
|
ret = brcmf_fws_init(drvr);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -1073,16 +1076,6 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
|
|||||||
return !err;
|
return !err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* return chip id and rev of the device encoded in u32.
|
|
||||||
*/
|
|
||||||
u32 brcmf_get_chip_info(struct brcmf_if *ifp)
|
|
||||||
{
|
|
||||||
struct brcmf_bus *bus = ifp->drvr->bus_if;
|
|
||||||
|
|
||||||
return bus->chip << 4 | bus->chiprev;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void brcmf_driver_register(struct work_struct *work)
|
static void brcmf_driver_register(struct work_struct *work)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_BRCMFMAC_SDIO
|
#ifdef CONFIG_BRCMFMAC_SDIO
|
||||||
|
136
drivers/net/wireless/brcm80211/brcmfmac/feature.c
Normal file
136
drivers/net/wireless/brcm80211/brcmfmac/feature.c
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 Broadcom Corporation
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/netdevice.h>
|
||||||
|
|
||||||
|
#include <brcm_hw_ids.h>
|
||||||
|
#include "dhd.h"
|
||||||
|
#include "dhd_bus.h"
|
||||||
|
#include "dhd_dbg.h"
|
||||||
|
#include "fwil.h"
|
||||||
|
#include "feature.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* firmware error code received if iovar is unsupported.
|
||||||
|
*/
|
||||||
|
#define EBRCMF_FEAT_UNSUPPORTED 23
|
||||||
|
|
||||||
|
/*
|
||||||
|
* expand feature list to array of feature strings.
|
||||||
|
*/
|
||||||
|
#define BRCMF_FEAT_DEF(_f) \
|
||||||
|
#_f,
|
||||||
|
static const char *brcmf_feat_names[] = {
|
||||||
|
BRCMF_FEAT_LIST
|
||||||
|
};
|
||||||
|
#undef BRCMF_FEAT_DEF
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
/*
|
||||||
|
* expand quirk list to array of quirk strings.
|
||||||
|
*/
|
||||||
|
#define BRCMF_QUIRK_DEF(_q) \
|
||||||
|
#_q,
|
||||||
|
static const char * const brcmf_quirk_names[] = {
|
||||||
|
BRCMF_QUIRK_LIST
|
||||||
|
};
|
||||||
|
#undef BRCMF_QUIRK_DEF
|
||||||
|
|
||||||
|
/**
|
||||||
|
* brcmf_feat_debugfs_read() - expose feature info to debugfs.
|
||||||
|
*
|
||||||
|
* @seq: sequence for debugfs entry.
|
||||||
|
* @data: raw data pointer.
|
||||||
|
*/
|
||||||
|
static int brcmf_feat_debugfs_read(struct seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
|
||||||
|
u32 feats = bus_if->drvr->feat_flags;
|
||||||
|
u32 quirks = bus_if->drvr->chip_quirks;
|
||||||
|
int id;
|
||||||
|
|
||||||
|
seq_printf(seq, "Features: %08x\n", feats);
|
||||||
|
for (id = 0; id < BRCMF_FEAT_LAST; id++)
|
||||||
|
if (feats & BIT(id))
|
||||||
|
seq_printf(seq, "\t%s\n", brcmf_feat_names[id]);
|
||||||
|
seq_printf(seq, "\nQuirks: %08x\n", quirks);
|
||||||
|
for (id = 0; id < BRCMF_FEAT_QUIRK_LAST; id++)
|
||||||
|
if (quirks & BIT(id))
|
||||||
|
seq_printf(seq, "\t%s\n", brcmf_quirk_names[id]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int brcmf_feat_debugfs_read(struct seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* DEBUG */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* brcmf_feat_iovar_int_get() - determine feature through iovar query.
|
||||||
|
*
|
||||||
|
* @ifp: interface to query.
|
||||||
|
* @id: feature id.
|
||||||
|
* @name: iovar name.
|
||||||
|
*/
|
||||||
|
static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp,
|
||||||
|
enum brcmf_feat_id id, char *name)
|
||||||
|
{
|
||||||
|
u32 data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = brcmf_fil_iovar_int_get(ifp, name, &data);
|
||||||
|
if (err == 0) {
|
||||||
|
brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
|
||||||
|
ifp->drvr->feat_flags |= BIT(id);
|
||||||
|
} else {
|
||||||
|
brcmf_dbg(TRACE, "%s feature check failed: %d\n",
|
||||||
|
brcmf_feat_names[id], err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void brcmf_feat_attach(struct brcmf_pub *drvr)
|
||||||
|
{
|
||||||
|
struct brcmf_if *ifp = drvr->iflist[0];
|
||||||
|
|
||||||
|
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan");
|
||||||
|
|
||||||
|
/* set chip related quirks */
|
||||||
|
switch (drvr->bus_if->chip) {
|
||||||
|
case BRCM_CC_43236_CHIP_ID:
|
||||||
|
drvr->chip_quirks |= BIT(BRCMF_FEAT_QUIRK_AUTO_AUTH);
|
||||||
|
break;
|
||||||
|
case BRCM_CC_4329_CHIP_ID:
|
||||||
|
drvr->chip_quirks |= BIT(BRCMF_FEAT_QUIRK_NEED_MPC);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* no quirks */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
brcmf_debugfs_add_entry(drvr, "features", brcmf_feat_debugfs_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool brcmf_feat_is_enabled(struct brcmf_if *ifp, enum brcmf_feat_id id)
|
||||||
|
{
|
||||||
|
return (ifp->drvr->feat_flags & BIT(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool brcmf_feat_is_quirk_enabled(struct brcmf_if *ifp,
|
||||||
|
enum brcmf_feat_quirk quirk)
|
||||||
|
{
|
||||||
|
return (ifp->drvr->chip_quirks & BIT(quirk));
|
||||||
|
}
|
86
drivers/net/wireless/brcm80211/brcmfmac/feature.h
Normal file
86
drivers/net/wireless/brcm80211/brcmfmac/feature.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 Broadcom Corporation
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef _BRCMF_FEATURE_H
|
||||||
|
#define _BRCMF_FEATURE_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Features:
|
||||||
|
*
|
||||||
|
* MCHAN: multi-channel for concurrent P2P.
|
||||||
|
*/
|
||||||
|
#define BRCMF_FEAT_LIST \
|
||||||
|
BRCMF_FEAT_DEF(MCHAN)
|
||||||
|
/*
|
||||||
|
* Quirks:
|
||||||
|
*
|
||||||
|
* AUTO_AUTH: workaround needed for automatic authentication type.
|
||||||
|
* NEED_MPC: driver needs to disable MPC during scanning operation.
|
||||||
|
*/
|
||||||
|
#define BRCMF_QUIRK_LIST \
|
||||||
|
BRCMF_QUIRK_DEF(AUTO_AUTH) \
|
||||||
|
BRCMF_QUIRK_DEF(NEED_MPC)
|
||||||
|
|
||||||
|
#define BRCMF_FEAT_DEF(_f) \
|
||||||
|
BRCMF_FEAT_ ## _f,
|
||||||
|
/*
|
||||||
|
* expand feature list to enumeration.
|
||||||
|
*/
|
||||||
|
enum brcmf_feat_id {
|
||||||
|
BRCMF_FEAT_LIST
|
||||||
|
BRCMF_FEAT_LAST
|
||||||
|
};
|
||||||
|
#undef BRCMF_FEAT_DEF
|
||||||
|
|
||||||
|
#define BRCMF_QUIRK_DEF(_q) \
|
||||||
|
BRCMF_FEAT_QUIRK_ ## _q,
|
||||||
|
/*
|
||||||
|
* expand quirk list to enumeration.
|
||||||
|
*/
|
||||||
|
enum brcmf_feat_quirk {
|
||||||
|
BRCMF_QUIRK_LIST
|
||||||
|
BRCMF_FEAT_QUIRK_LAST
|
||||||
|
};
|
||||||
|
#undef BRCMF_QUIRK_DEF
|
||||||
|
|
||||||
|
/**
|
||||||
|
* brcmf_feat_attach() - determine features and quirks.
|
||||||
|
*
|
||||||
|
* @drvr: driver instance.
|
||||||
|
*/
|
||||||
|
void brcmf_feat_attach(struct brcmf_pub *drvr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* brcmf_feat_is_enabled() - query feature.
|
||||||
|
*
|
||||||
|
* @ifp: interface instance.
|
||||||
|
* @id: feature id to check.
|
||||||
|
*
|
||||||
|
* Return: true is feature is enabled; otherwise false.
|
||||||
|
*/
|
||||||
|
bool brcmf_feat_is_enabled(struct brcmf_if *ifp, enum brcmf_feat_id id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* brcmf_feat_is_quirk_enabled() - query chip quirk.
|
||||||
|
*
|
||||||
|
* @ifp: interface instance.
|
||||||
|
* @quirk: quirk id to check.
|
||||||
|
*
|
||||||
|
* Return: true is quirk is enabled; otherwise false.
|
||||||
|
*/
|
||||||
|
bool brcmf_feat_is_quirk_enabled(struct brcmf_if *ifp,
|
||||||
|
enum brcmf_feat_quirk quirk);
|
||||||
|
|
||||||
|
#endif /* _BRCMF_FEATURE_H */
|
@ -33,6 +33,7 @@
|
|||||||
#include "p2p.h"
|
#include "p2p.h"
|
||||||
#include "btcoex.h"
|
#include "btcoex.h"
|
||||||
#include "wl_cfg80211.h"
|
#include "wl_cfg80211.h"
|
||||||
|
#include "feature.h"
|
||||||
#include "fwil.h"
|
#include "fwil.h"
|
||||||
#include "vendor.h"
|
#include "vendor.h"
|
||||||
|
|
||||||
@ -592,7 +593,7 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
|
|||||||
|
|
||||||
static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
|
static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
|
||||||
{
|
{
|
||||||
if ((brcmf_get_chip_info(ifp) >> 4) == 0x4329)
|
if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC))
|
||||||
brcmf_set_mpc(ifp, mpc);
|
brcmf_set_mpc(ifp, mpc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1619,17 +1620,10 @@ static
|
|||||||
enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
|
enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
|
||||||
enum nl80211_auth_type type)
|
enum nl80211_auth_type type)
|
||||||
{
|
{
|
||||||
u32 ci;
|
if (type == NL80211_AUTHTYPE_AUTOMATIC &&
|
||||||
if (type == NL80211_AUTHTYPE_AUTOMATIC) {
|
brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) {
|
||||||
/* shift to ignore chip revision */
|
brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n");
|
||||||
ci = brcmf_get_chip_info(ifp) >> 4;
|
type = NL80211_AUTHTYPE_OPEN_SYSTEM;
|
||||||
switch (ci) {
|
|
||||||
case 43236:
|
|
||||||
brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n");
|
|
||||||
return NL80211_AUTHTYPE_OPEN_SYSTEM;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
@ -4310,10 +4304,10 @@ static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
|
|||||||
.types = BIT(NL80211_IFTYPE_P2P_DEVICE)
|
.types = BIT(NL80211_IFTYPE_P2P_DEVICE)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
|
static struct ieee80211_iface_combination brcmf_iface_combos[] = {
|
||||||
{
|
{
|
||||||
.max_interfaces = BRCMF_IFACE_MAX_CNT,
|
.max_interfaces = BRCMF_IFACE_MAX_CNT,
|
||||||
.num_different_channels = 2,
|
.num_different_channels = 1,
|
||||||
.n_limits = ARRAY_SIZE(brcmf_iface_limits),
|
.n_limits = ARRAY_SIZE(brcmf_iface_limits),
|
||||||
.limits = brcmf_iface_limits
|
.limits = brcmf_iface_limits
|
||||||
}
|
}
|
||||||
@ -4348,7 +4342,8 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
|
static
|
||||||
|
struct wiphy *brcmf_setup_wiphy(struct brcmf_if *ifp, struct device *phydev)
|
||||||
{
|
{
|
||||||
struct wiphy *wiphy;
|
struct wiphy *wiphy;
|
||||||
s32 err = 0;
|
s32 err = 0;
|
||||||
@ -4368,6 +4363,9 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
|
|||||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||||
BIT(NL80211_IFTYPE_P2P_GO) |
|
BIT(NL80211_IFTYPE_P2P_GO) |
|
||||||
BIT(NL80211_IFTYPE_P2P_DEVICE);
|
BIT(NL80211_IFTYPE_P2P_DEVICE);
|
||||||
|
/* need VSDB firmware feature for concurrent channels */
|
||||||
|
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
|
||||||
|
brcmf_iface_combos[0].num_different_channels = 2;
|
||||||
wiphy->iface_combinations = brcmf_iface_combos;
|
wiphy->iface_combinations = brcmf_iface_combos;
|
||||||
wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
|
wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
|
||||||
wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
|
wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
|
||||||
@ -5567,7 +5565,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ifp = netdev_priv(ndev);
|
ifp = netdev_priv(ndev);
|
||||||
wiphy = brcmf_setup_wiphy(busdev);
|
wiphy = brcmf_setup_wiphy(ifp, busdev);
|
||||||
if (IS_ERR(wiphy))
|
if (IS_ERR(wiphy))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user