aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches/brcm/998-survey.patch
blob: 9e9f4bbf8fbbdc8f38741d0113472e5c0eb2a187 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -2910,6 +2910,63 @@ done:
 }
 
 static int
+brcmf_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev,
+			   int idx, struct survey_info *survey)
+{
+	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+	struct brcmf_if *ifp = netdev_priv(ndev);
+	struct brcmu_chan ch;
+	enum nl80211_band band = 0;
+	s32 err = 0;
+	int noise;
+	u32 freq;
+	u32 chanspec;
+
+	memset(survey, 0, sizeof(struct survey_info));
+	if (idx != 0) {
+		if (idx >= cfg->pub->num_chan_stats || cfg->pub->chan_stats == NULL)
+			return -ENOENT;
+		if (cfg->pub->chan_stats[idx].freq == 0)
+			return -ENOENT;
+		survey->filled = SURVEY_INFO_NOISE_DBM;
+		survey->channel = ieee80211_get_channel(wiphy, cfg->pub->chan_stats[idx].freq);
+		survey->noise = cfg->pub->chan_stats[idx].noise;
+		return 0;
+	}
+
+	err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec);
+	if (err) {
+		brcmf_err("chanspec failed (%d)\n", err);
+		return err;
+	}
+
+	ch.chspec = chanspec;
+	cfg->d11inf.decchspec(&ch);
+
+	switch (ch.band) {
+	case BRCMU_CHAN_BAND_2G:
+		band = NL80211_BAND_2GHZ;
+		break;
+	case BRCMU_CHAN_BAND_5G:
+		band = NL80211_BAND_5GHZ;
+		break;
+	}
+
+	freq = ieee80211_channel_to_frequency(ch.control_ch_num, band);
+	survey->channel = ieee80211_get_channel(wiphy, freq);
+
+	err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PHY_NOISE, &noise);
+	if (err) {
+		brcmf_err("Could not get noise (%d)\n", err);
+		return err;
+	}
+
+	survey->filled = SURVEY_INFO_NOISE_DBM | SURVEY_INFO_IN_USE;
+	survey->noise = le32_to_cpu(noise);
+	return 0;
+}
+
+static int
 brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
 			    int idx, u8 *mac, struct station_info *sinfo)
 {
@@ -3005,6 +3062,7 @@ static s32 brcmf_inform_single_bss(struc
 	struct brcmu_chan ch;
 	u16 channel;
 	u32 freq;
+	int i;
 	u16 notify_capability;
 	u16 notify_interval;
 	u8 *notify_ie;
@@ -3029,6 +3087,17 @@ static s32 brcmf_inform_single_bss(struc
 		band = NL80211_BAND_5GHZ;
 
 	freq = ieee80211_channel_to_frequency(channel, band);
+	for (i = 0;i < cfg->pub->num_chan_stats;i++) {
+		if (freq == cfg->pub->chan_stats[i].freq)
+			break;
+		if (cfg->pub->chan_stats[i].freq == 0)
+			break;
+	}
+	if (i < cfg->pub->num_chan_stats) {
+		cfg->pub->chan_stats[i].freq = freq;
+		cfg->pub->chan_stats[i].noise = bi->phy_noise;
+	}
+
 	bss_data.chan = ieee80211_get_channel(wiphy, freq);
 	bss_data.scan_width = NL80211_BSS_CHAN_WIDTH_20;
 	bss_data.boottime_ns = ktime_to_ns(ktime_get_boottime());
@@ -5515,6 +5584,7 @@ static struct cfg80211_ops brcmf_cfg8021
 	.leave_ibss = brcmf_cfg80211_leave_ibss,
 	.get_station = brcmf_cfg80211_get_station,
 	.dump_station = brcmf_cfg80211_dump_station,
+	.dump_survey = brcmf_cfg80211_dump_survey,
 	.set_tx_power = brcmf_cfg80211_set_tx_power,
 	.get_tx_power = brcmf_cfg80211_get_tx_power,
 	.add_key = brcmf_cfg80211_add_key,
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -1356,6 +1356,8 @@ int brcmf_attach(struct device *dev)
 
 	/* Link to bus module */
 	drvr->hdrlen = 0;
+	drvr->chan_stats = vzalloc(256 * sizeof(struct brcmf_chan_stats));
+	drvr->num_chan_stats = 256;
 
 	/* Attach and link in the protocol */
 	ret = brcmf_proto_attach(drvr);
@@ -1438,6 +1440,12 @@ void brcmf_detach(struct device *dev)
 	if (drvr == NULL)
 		return;
 
+	drvr->num_chan_stats = 0;
+	if (drvr->chan_stats) {
+		vfree(drvr->chan_stats);
+		drvr->chan_stats = NULL;
+	}
+
 #ifdef CONFIG_INET
 	unregister_inetaddr_notifier(&drvr->inetaddr_notifier);
 #endif
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
@@ -91,6 +91,11 @@ struct brcmf_rev_info {
 	u32 nvramrev;
 };
 
+struct brcmf_chan_stats {
+	u32 freq;
+	int noise;
+};
+
 /* Common structure for module and instance linkage */
 struct brcmf_pub {
 	/* Linkage ponters */
@@ -100,6 +105,9 @@ struct brcmf_pub {
 	struct cfg80211_ops *ops;
 	struct brcmf_cfg80211_info *config;
 
+	int num_chan_stats;
+	struct brcmf_chan_stats *chan_stats;
+
 	/* Internal brcmf items */
 	uint hdrlen;		/* Total BRCMF header length (proto + bus) */