diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/net/wireless/wl12xx/wl1271_event.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_event.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_event.c | 157 |
1 files changed, 140 insertions, 17 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index f3afd4a6ff33..7468ef10194b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c | |||
@@ -24,25 +24,125 @@ | |||
24 | #include "wl1271.h" | 24 | #include "wl1271.h" |
25 | #include "wl1271_reg.h" | 25 | #include "wl1271_reg.h" |
26 | #include "wl1271_spi.h" | 26 | #include "wl1271_spi.h" |
27 | #include "wl1271_io.h" | ||
27 | #include "wl1271_event.h" | 28 | #include "wl1271_event.h" |
28 | #include "wl1271_ps.h" | 29 | #include "wl1271_ps.h" |
30 | #include "wl12xx_80211.h" | ||
29 | 31 | ||
30 | static int wl1271_event_scan_complete(struct wl1271 *wl, | 32 | static int wl1271_event_scan_complete(struct wl1271 *wl, |
31 | struct event_mailbox *mbox) | 33 | struct event_mailbox *mbox) |
32 | { | 34 | { |
35 | int size = sizeof(struct wl12xx_probe_req_template); | ||
33 | wl1271_debug(DEBUG_EVENT, "status: 0x%x", | 36 | wl1271_debug(DEBUG_EVENT, "status: 0x%x", |
34 | mbox->scheduled_scan_status); | 37 | mbox->scheduled_scan_status); |
35 | 38 | ||
36 | if (wl->scanning) { | 39 | if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) { |
37 | mutex_unlock(&wl->mutex); | 40 | if (wl->scan.state == WL1271_SCAN_BAND_DUAL) { |
38 | ieee80211_scan_completed(wl->hw, false); | 41 | wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, |
39 | mutex_lock(&wl->mutex); | 42 | NULL, size); |
40 | wl->scanning = false; | 43 | /* 2.4 GHz band scanned, scan 5 GHz band, pretend |
44 | * to the wl1271_cmd_scan function that we are not | ||
45 | * scanning as it checks that. | ||
46 | */ | ||
47 | clear_bit(WL1271_FLAG_SCANNING, &wl->flags); | ||
48 | wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len, | ||
49 | wl->scan.active, | ||
50 | wl->scan.high_prio, | ||
51 | WL1271_SCAN_BAND_5_GHZ, | ||
52 | wl->scan.probe_requests); | ||
53 | } else { | ||
54 | if (wl->scan.state == WL1271_SCAN_BAND_2_4_GHZ) | ||
55 | wl1271_cmd_template_set(wl, | ||
56 | CMD_TEMPL_CFG_PROBE_REQ_2_4, | ||
57 | NULL, size); | ||
58 | else | ||
59 | wl1271_cmd_template_set(wl, | ||
60 | CMD_TEMPL_CFG_PROBE_REQ_5, | ||
61 | NULL, size); | ||
62 | |||
63 | mutex_unlock(&wl->mutex); | ||
64 | ieee80211_scan_completed(wl->hw, false); | ||
65 | mutex_lock(&wl->mutex); | ||
66 | clear_bit(WL1271_FLAG_SCANNING, &wl->flags); | ||
67 | } | ||
41 | } | 68 | } |
42 | |||
43 | return 0; | 69 | return 0; |
44 | } | 70 | } |
45 | 71 | ||
72 | static int wl1271_event_ps_report(struct wl1271 *wl, | ||
73 | struct event_mailbox *mbox, | ||
74 | bool *beacon_loss) | ||
75 | { | ||
76 | int ret = 0; | ||
77 | |||
78 | wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status); | ||
79 | |||
80 | switch (mbox->ps_status) { | ||
81 | case EVENT_ENTER_POWER_SAVE_FAIL: | ||
82 | wl1271_debug(DEBUG_PSM, "PSM entry failed"); | ||
83 | |||
84 | if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) { | ||
85 | /* remain in active mode */ | ||
86 | wl->psm_entry_retry = 0; | ||
87 | break; | ||
88 | } | ||
89 | |||
90 | if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) { | ||
91 | wl->psm_entry_retry++; | ||
92 | ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, | ||
93 | true); | ||
94 | } else { | ||
95 | wl1271_error("PSM entry failed, giving up.\n"); | ||
96 | /* FIXME: this may need to be reconsidered. for now it | ||
97 | is not possible to indicate to the mac80211 | ||
98 | afterwards that PSM entry failed. To maximize | ||
99 | functionality (receiving data and remaining | ||
100 | associated) make sure that we are in sync with the | ||
101 | AP in regard of PSM mode. */ | ||
102 | ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, | ||
103 | false); | ||
104 | wl->psm_entry_retry = 0; | ||
105 | } | ||
106 | break; | ||
107 | case EVENT_ENTER_POWER_SAVE_SUCCESS: | ||
108 | wl->psm_entry_retry = 0; | ||
109 | |||
110 | /* enable beacon filtering */ | ||
111 | ret = wl1271_acx_beacon_filter_opt(wl, true); | ||
112 | if (ret < 0) | ||
113 | break; | ||
114 | |||
115 | /* enable beacon early termination */ | ||
116 | ret = wl1271_acx_bet_enable(wl, true); | ||
117 | if (ret < 0) | ||
118 | break; | ||
119 | |||
120 | /* go to extremely low power mode */ | ||
121 | wl1271_ps_elp_sleep(wl); | ||
122 | if (ret < 0) | ||
123 | break; | ||
124 | break; | ||
125 | case EVENT_EXIT_POWER_SAVE_FAIL: | ||
126 | wl1271_debug(DEBUG_PSM, "PSM exit failed"); | ||
127 | |||
128 | if (test_bit(WL1271_FLAG_PSM, &wl->flags)) { | ||
129 | wl->psm_entry_retry = 0; | ||
130 | break; | ||
131 | } | ||
132 | |||
133 | /* make sure the firmware goes to active mode - the frame to | ||
134 | be sent next will indicate to the AP, that we are active. */ | ||
135 | ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, | ||
136 | false); | ||
137 | break; | ||
138 | case EVENT_EXIT_POWER_SAVE_SUCCESS: | ||
139 | default: | ||
140 | break; | ||
141 | } | ||
142 | |||
143 | return ret; | ||
144 | } | ||
145 | |||
46 | static void wl1271_event_mbox_dump(struct event_mailbox *mbox) | 146 | static void wl1271_event_mbox_dump(struct event_mailbox *mbox) |
47 | { | 147 | { |
48 | wl1271_debug(DEBUG_EVENT, "MBOX DUMP:"); | 148 | wl1271_debug(DEBUG_EVENT, "MBOX DUMP:"); |
@@ -54,10 +154,12 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) | |||
54 | { | 154 | { |
55 | int ret; | 155 | int ret; |
56 | u32 vector; | 156 | u32 vector; |
157 | bool beacon_loss = false; | ||
57 | 158 | ||
58 | wl1271_event_mbox_dump(mbox); | 159 | wl1271_event_mbox_dump(mbox); |
59 | 160 | ||
60 | vector = mbox->events_vector & ~(mbox->events_mask); | 161 | vector = le32_to_cpu(mbox->events_vector); |
162 | vector &= ~(le32_to_cpu(mbox->events_mask)); | ||
61 | wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); | 163 | wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); |
62 | 164 | ||
63 | if (vector & SCAN_COMPLETE_EVENT_ID) { | 165 | if (vector & SCAN_COMPLETE_EVENT_ID) { |
@@ -66,14 +168,35 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) | |||
66 | return ret; | 168 | return ret; |
67 | } | 169 | } |
68 | 170 | ||
69 | if (vector & BSS_LOSE_EVENT_ID) { | 171 | /* |
172 | * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon | ||
173 | * filtering) is enabled. Without PSM, the stack will receive all | ||
174 | * beacons and can detect beacon loss by itself. | ||
175 | */ | ||
176 | if (vector & BSS_LOSE_EVENT_ID && | ||
177 | test_bit(WL1271_FLAG_PSM, &wl->flags)) { | ||
70 | wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); | 178 | wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); |
71 | 179 | ||
72 | if (wl->psm_requested && wl->psm) { | 180 | /* indicate to the stack, that beacons have been lost */ |
73 | ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE); | 181 | beacon_loss = true; |
74 | if (ret < 0) | 182 | } |
75 | return ret; | 183 | |
76 | } | 184 | if (vector & PS_REPORT_EVENT_ID) { |
185 | wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT"); | ||
186 | ret = wl1271_event_ps_report(wl, mbox, &beacon_loss); | ||
187 | if (ret < 0) | ||
188 | return ret; | ||
189 | } | ||
190 | |||
191 | if (wl->vif && beacon_loss) { | ||
192 | /* Obviously, it's dangerous to release the mutex while | ||
193 | we are holding many of the variables in the wl struct. | ||
194 | That's why it's done last in the function, and care must | ||
195 | be taken that nothing more is done after this function | ||
196 | returns. */ | ||
197 | mutex_unlock(&wl->mutex); | ||
198 | ieee80211_beacon_loss(wl->vif); | ||
199 | mutex_lock(&wl->mutex); | ||
77 | } | 200 | } |
78 | 201 | ||
79 | return 0; | 202 | return 0; |
@@ -92,7 +215,7 @@ int wl1271_event_unmask(struct wl1271 *wl) | |||
92 | 215 | ||
93 | void wl1271_event_mbox_config(struct wl1271 *wl) | 216 | void wl1271_event_mbox_config(struct wl1271 *wl) |
94 | { | 217 | { |
95 | wl->mbox_ptr[0] = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR); | 218 | wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR); |
96 | wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); | 219 | wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); |
97 | 220 | ||
98 | wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", | 221 | wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", |
@@ -110,8 +233,8 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) | |||
110 | return -EINVAL; | 233 | return -EINVAL; |
111 | 234 | ||
112 | /* first we read the mbox descriptor */ | 235 | /* first we read the mbox descriptor */ |
113 | wl1271_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, | 236 | wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox, |
114 | sizeof(struct event_mailbox)); | 237 | sizeof(struct event_mailbox), false); |
115 | 238 | ||
116 | /* process the descriptor */ | 239 | /* process the descriptor */ |
117 | ret = wl1271_event_process(wl, &mbox); | 240 | ret = wl1271_event_process(wl, &mbox); |
@@ -119,7 +242,7 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) | |||
119 | return ret; | 242 | return ret; |
120 | 243 | ||
121 | /* then we let the firmware know it can go on...*/ | 244 | /* then we let the firmware know it can go on...*/ |
122 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); | 245 | wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); |
123 | 246 | ||
124 | return 0; | 247 | return 0; |
125 | } | 248 | } |