1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * This file is part of wl1251 |
4 | * |
5 | * Copyright (c) 1998-2007 Texas Instruments Incorporated |
6 | * Copyright (C) 2008 Nokia Corporation |
7 | */ |
8 | |
9 | #include "wl1251.h" |
10 | #include "reg.h" |
11 | #include "io.h" |
12 | #include "event.h" |
13 | #include "ps.h" |
14 | |
15 | static int wl1251_event_scan_complete(struct wl1251 *wl, |
16 | struct event_mailbox *mbox) |
17 | { |
18 | int ret = 0; |
19 | |
20 | wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d" , |
21 | mbox->scheduled_scan_status, |
22 | mbox->scheduled_scan_channels); |
23 | |
24 | if (wl->scanning) { |
25 | struct cfg80211_scan_info info = { |
26 | .aborted = false, |
27 | }; |
28 | |
29 | ieee80211_scan_completed(hw: wl->hw, info: &info); |
30 | wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed" ); |
31 | wl->scanning = false; |
32 | if (wl->hw->conf.flags & IEEE80211_CONF_IDLE) |
33 | ret = wl1251_ps_set_mode(wl, mode: STATION_IDLE); |
34 | } |
35 | |
36 | return ret; |
37 | } |
38 | |
39 | #define WL1251_PSM_ENTRY_RETRIES 3 |
40 | static int wl1251_event_ps_report(struct wl1251 *wl, |
41 | struct event_mailbox *mbox) |
42 | { |
43 | int ret = 0; |
44 | |
45 | wl1251_debug(DEBUG_EVENT, "ps status: %x" , mbox->ps_status); |
46 | |
47 | switch (mbox->ps_status) { |
48 | case EVENT_ENTER_POWER_SAVE_FAIL: |
49 | wl1251_debug(DEBUG_PSM, "PSM entry failed" ); |
50 | |
51 | if (wl->station_mode != STATION_POWER_SAVE_MODE) { |
52 | /* remain in active mode */ |
53 | wl->psm_entry_retry = 0; |
54 | break; |
55 | } |
56 | |
57 | if (wl->psm_entry_retry < WL1251_PSM_ENTRY_RETRIES) { |
58 | wl->psm_entry_retry++; |
59 | ret = wl1251_ps_set_mode(wl, mode: STATION_POWER_SAVE_MODE); |
60 | } else { |
61 | wl1251_error("Power save entry failed, giving up" ); |
62 | wl->psm_entry_retry = 0; |
63 | } |
64 | break; |
65 | case EVENT_ENTER_POWER_SAVE_SUCCESS: |
66 | case EVENT_EXIT_POWER_SAVE_FAIL: |
67 | case EVENT_EXIT_POWER_SAVE_SUCCESS: |
68 | default: |
69 | wl->psm_entry_retry = 0; |
70 | break; |
71 | } |
72 | |
73 | return ret; |
74 | } |
75 | |
76 | static void wl1251_event_mbox_dump(struct event_mailbox *mbox) |
77 | { |
78 | wl1251_debug(DEBUG_EVENT, "MBOX DUMP:" ); |
79 | wl1251_debug(DEBUG_EVENT, "\tvector: 0x%x" , mbox->events_vector); |
80 | wl1251_debug(DEBUG_EVENT, "\tmask: 0x%x" , mbox->events_mask); |
81 | } |
82 | |
83 | static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox) |
84 | { |
85 | int ret; |
86 | u32 vector; |
87 | |
88 | wl1251_event_mbox_dump(mbox); |
89 | |
90 | vector = mbox->events_vector & ~(mbox->events_mask); |
91 | wl1251_debug(DEBUG_EVENT, "vector: 0x%x" , vector); |
92 | |
93 | if (vector & SCAN_COMPLETE_EVENT_ID) { |
94 | ret = wl1251_event_scan_complete(wl, mbox); |
95 | if (ret < 0) |
96 | return ret; |
97 | } |
98 | |
99 | if (vector & BSS_LOSE_EVENT_ID) { |
100 | wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT" ); |
101 | |
102 | if (wl->psm_requested && |
103 | wl->station_mode != STATION_ACTIVE_MODE) { |
104 | ret = wl1251_ps_set_mode(wl, mode: STATION_ACTIVE_MODE); |
105 | if (ret < 0) |
106 | return ret; |
107 | } |
108 | } |
109 | |
110 | if (vector & PS_REPORT_EVENT_ID) { |
111 | wl1251_debug(DEBUG_EVENT, "PS_REPORT_EVENT" ); |
112 | ret = wl1251_event_ps_report(wl, mbox); |
113 | if (ret < 0) |
114 | return ret; |
115 | } |
116 | |
117 | if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID) { |
118 | wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT" ); |
119 | |
120 | /* indicate to the stack, that beacons have been lost */ |
121 | if (wl->vif && wl->vif->type == NL80211_IFTYPE_STATION) |
122 | ieee80211_beacon_loss(vif: wl->vif); |
123 | } |
124 | |
125 | if (vector & REGAINED_BSS_EVENT_ID) { |
126 | if (wl->psm_requested) { |
127 | ret = wl1251_ps_set_mode(wl, mode: STATION_POWER_SAVE_MODE); |
128 | if (ret < 0) |
129 | return ret; |
130 | } |
131 | } |
132 | |
133 | if (wl->vif && wl->rssi_thold) { |
134 | if (vector & ROAMING_TRIGGER_LOW_RSSI_EVENT_ID) { |
135 | wl1251_debug(DEBUG_EVENT, |
136 | "ROAMING_TRIGGER_LOW_RSSI_EVENT" ); |
137 | ieee80211_cqm_rssi_notify(vif: wl->vif, |
138 | rssi_event: NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, |
139 | rssi_level: 0, GFP_KERNEL); |
140 | } |
141 | |
142 | if (vector & ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID) { |
143 | wl1251_debug(DEBUG_EVENT, |
144 | "ROAMING_TRIGGER_REGAINED_RSSI_EVENT" ); |
145 | ieee80211_cqm_rssi_notify(vif: wl->vif, |
146 | rssi_event: NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, |
147 | rssi_level: 0, GFP_KERNEL); |
148 | } |
149 | } |
150 | |
151 | return 0; |
152 | } |
153 | |
154 | /* |
155 | * Poll the mailbox event field until any of the bits in the mask is set or a |
156 | * timeout occurs (WL1251_EVENT_TIMEOUT in msecs) |
157 | */ |
158 | int wl1251_event_wait(struct wl1251 *wl, u32 mask, int timeout_ms) |
159 | { |
160 | u32 events_vector, event; |
161 | unsigned long timeout; |
162 | |
163 | timeout = jiffies + msecs_to_jiffies(m: timeout_ms); |
164 | |
165 | do { |
166 | if (time_after(jiffies, timeout)) |
167 | return -ETIMEDOUT; |
168 | |
169 | msleep(msecs: 1); |
170 | |
171 | /* read from both event fields */ |
172 | events_vector = wl1251_mem_read32(wl, addr: wl->mbox_ptr[0]); |
173 | event = events_vector & mask; |
174 | events_vector = wl1251_mem_read32(wl, addr: wl->mbox_ptr[1]); |
175 | event |= events_vector & mask; |
176 | } while (!event); |
177 | |
178 | return 0; |
179 | } |
180 | |
181 | int wl1251_event_unmask(struct wl1251 *wl) |
182 | { |
183 | int ret; |
184 | |
185 | ret = wl1251_acx_event_mbox_mask(wl, event_mask: ~(wl->event_mask)); |
186 | if (ret < 0) |
187 | return ret; |
188 | |
189 | return 0; |
190 | } |
191 | |
192 | void wl1251_event_mbox_config(struct wl1251 *wl) |
193 | { |
194 | wl->mbox_ptr[0] = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); |
195 | wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); |
196 | |
197 | wl1251_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x" , |
198 | wl->mbox_ptr[0], wl->mbox_ptr[1]); |
199 | } |
200 | |
201 | int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num) |
202 | { |
203 | struct event_mailbox *mbox; |
204 | int ret; |
205 | |
206 | wl1251_debug(DEBUG_EVENT, "EVENT on mbox %d" , mbox_num); |
207 | |
208 | if (mbox_num > 1) |
209 | return -EINVAL; |
210 | |
211 | mbox = kmalloc(size: sizeof(*mbox), GFP_KERNEL); |
212 | if (!mbox) { |
213 | wl1251_error("can not allocate mbox buffer" ); |
214 | return -ENOMEM; |
215 | } |
216 | |
217 | /* first we read the mbox descriptor */ |
218 | wl1251_mem_read(wl, addr: wl->mbox_ptr[mbox_num], buf: mbox, |
219 | len: sizeof(*mbox)); |
220 | |
221 | /* process the descriptor */ |
222 | ret = wl1251_event_process(wl, mbox); |
223 | kfree(objp: mbox); |
224 | |
225 | if (ret < 0) |
226 | return ret; |
227 | |
228 | /* then we let the firmware know it can go on...*/ |
229 | wl1251_reg_write32(wl, addr: ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); |
230 | |
231 | return 0; |
232 | } |
233 | |