b43legacy: move under broadcom vendor directory
[linux-2.6-block.git] / drivers / net / wireless / brcm80211 / brcmfmac / feature.c
CommitLineData
c08437b4
AS
1/*
2 * Copyright (c) 2014 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <linux/netdevice.h>
8268c201 18#include <linux/module.h>
c08437b4
AS
19
20#include <brcm_hw_ids.h>
122d3d04 21#include "core.h"
d14f78b9 22#include "bus.h"
a8e8ed34 23#include "debug.h"
c08437b4
AS
24#include "fwil.h"
25#include "feature.h"
26
8268c201
HM
27
28/* Module param feature_disable (global for all devices) */
29static int brcmf_feature_disable;
30module_param_named(feature_disable, brcmf_feature_disable, int, 0);
31MODULE_PARM_DESC(feature_disable, "Disable features");
32
c08437b4
AS
33/*
34 * expand feature list to array of feature strings.
35 */
36#define BRCMF_FEAT_DEF(_f) \
37 #_f,
38static const char *brcmf_feat_names[] = {
39 BRCMF_FEAT_LIST
40};
41#undef BRCMF_FEAT_DEF
42
43#ifdef DEBUG
44/*
45 * expand quirk list to array of quirk strings.
46 */
47#define BRCMF_QUIRK_DEF(_q) \
48 #_q,
49static const char * const brcmf_quirk_names[] = {
50 BRCMF_QUIRK_LIST
51};
52#undef BRCMF_QUIRK_DEF
53
54/**
55 * brcmf_feat_debugfs_read() - expose feature info to debugfs.
56 *
57 * @seq: sequence for debugfs entry.
58 * @data: raw data pointer.
59 */
60static int brcmf_feat_debugfs_read(struct seq_file *seq, void *data)
61{
62 struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
63 u32 feats = bus_if->drvr->feat_flags;
64 u32 quirks = bus_if->drvr->chip_quirks;
65 int id;
66
67 seq_printf(seq, "Features: %08x\n", feats);
68 for (id = 0; id < BRCMF_FEAT_LAST; id++)
69 if (feats & BIT(id))
70 seq_printf(seq, "\t%s\n", brcmf_feat_names[id]);
71 seq_printf(seq, "\nQuirks: %08x\n", quirks);
72 for (id = 0; id < BRCMF_FEAT_QUIRK_LAST; id++)
73 if (quirks & BIT(id))
74 seq_printf(seq, "\t%s\n", brcmf_quirk_names[id]);
75 return 0;
76}
77#else
78static int brcmf_feat_debugfs_read(struct seq_file *seq, void *data)
79{
80 return 0;
81}
82#endif /* DEBUG */
83
84/**
85 * brcmf_feat_iovar_int_get() - determine feature through iovar query.
86 *
87 * @ifp: interface to query.
88 * @id: feature id.
89 * @name: iovar name.
90 */
91static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp,
92 enum brcmf_feat_id id, char *name)
93{
94 u32 data;
95 int err;
96
97 err = brcmf_fil_iovar_int_get(ifp, name, &data);
98 if (err == 0) {
99 brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
100 ifp->drvr->feat_flags |= BIT(id);
101 } else {
102 brcmf_dbg(TRACE, "%s feature check failed: %d\n",
103 brcmf_feat_names[id], err);
104 }
105}
106
a44aa400
HM
107/**
108 * brcmf_feat_iovar_int_set() - determine feature through iovar set.
109 *
110 * @ifp: interface to query.
111 * @id: feature id.
112 * @name: iovar name.
113 */
114static void brcmf_feat_iovar_int_set(struct brcmf_if *ifp,
115 enum brcmf_feat_id id, char *name, u32 val)
116{
117 int err;
118
119 err = brcmf_fil_iovar_int_set(ifp, name, val);
120 if (err == 0) {
121 brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
122 ifp->drvr->feat_flags |= BIT(id);
123 } else {
124 brcmf_dbg(TRACE, "%s feature check failed: %d\n",
125 brcmf_feat_names[id], err);
126 }
127}
128
c08437b4
AS
129void brcmf_feat_attach(struct brcmf_pub *drvr)
130{
46f3b6ee 131 struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
c08437b4
AS
132
133 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan");
7a7a87dc 134 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn");
4eb3af7c
HM
135 if (drvr->bus_if->wowl_supported)
136 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
f93a25b3
AS
137 if (drvr->bus_if->chip != BRCM_CC_43362_CHIP_ID)
138 brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0);
2b560d71 139 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_P2P, "p2p");
c08437b4 140
8268c201
HM
141 if (brcmf_feature_disable) {
142 brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n",
143 ifp->drvr->feat_flags, brcmf_feature_disable);
144 ifp->drvr->feat_flags &= ~brcmf_feature_disable;
145 }
146
c08437b4
AS
147 /* set chip related quirks */
148 switch (drvr->bus_if->chip) {
149 case BRCM_CC_43236_CHIP_ID:
150 drvr->chip_quirks |= BIT(BRCMF_FEAT_QUIRK_AUTO_AUTH);
151 break;
152 case BRCM_CC_4329_CHIP_ID:
153 drvr->chip_quirks |= BIT(BRCMF_FEAT_QUIRK_NEED_MPC);
154 break;
155 default:
156 /* no quirks */
157 break;
158 }
159
160 brcmf_debugfs_add_entry(drvr, "features", brcmf_feat_debugfs_read);
161}
162
163bool brcmf_feat_is_enabled(struct brcmf_if *ifp, enum brcmf_feat_id id)
164{
165 return (ifp->drvr->feat_flags & BIT(id));
166}
167
168bool brcmf_feat_is_quirk_enabled(struct brcmf_if *ifp,
169 enum brcmf_feat_quirk quirk)
170{
171 return (ifp->drvr->chip_quirks & BIT(quirk));
172}