1 // SPDX-License-Identifier: GPL-2.0-only
3 * Interrupt bottom half (BH).
5 * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
6 * Copyright (c) 2010, ST-Ericsson
8 #include <linux/gpio/consumer.h>
9 #include <net/mac80211.h>
15 #include "secure_link.h"
17 #include "hif_api_cmd.h"
19 static void device_wakeup(struct wfx_dev
*wdev
)
21 if (!wdev
->pdata
.gpio_wakeup
)
23 if (gpiod_get_value(wdev
->pdata
.gpio_wakeup
))
26 gpiod_set_value(wdev
->pdata
.gpio_wakeup
, 1);
27 if (wfx_api_older_than(wdev
, 1, 4)) {
28 if (!completion_done(&wdev
->hif
.ctrl_ready
))
31 // completion.h does not provide any function to wait
32 // completion without consume it (a kind of
33 // wait_for_completion_done_timeout()). So we have to emulate
35 if (wait_for_completion_timeout(&wdev
->hif
.ctrl_ready
,
36 msecs_to_jiffies(2) + 1))
37 complete(&wdev
->hif
.ctrl_ready
);
39 dev_err(wdev
->dev
, "timeout while wake up chip\n");
43 static void device_release(struct wfx_dev
*wdev
)
45 if (!wdev
->pdata
.gpio_wakeup
)
48 gpiod_set_value(wdev
->pdata
.gpio_wakeup
, 0);
51 static int rx_helper(struct wfx_dev
*wdev
, size_t read_len
, int *is_cnf
)
60 WARN(read_len
< 4, "corrupted read");
61 WARN(read_len
> round_down(0xFFF, 2) * sizeof(u16
),
62 "%s: request exceed WFx capability", __func__
);
64 // Add 2 to take into account piggyback size
65 alloc_len
= wdev
->hwbus_ops
->align_size(wdev
->hwbus_priv
, read_len
+ 2);
66 skb
= dev_alloc_skb(alloc_len
);
70 if (wfx_data_read(wdev
, skb
->data
, alloc_len
))
73 piggyback
= le16_to_cpup((u16
*)(skb
->data
+ alloc_len
- 2));
74 _trace_piggyback(piggyback
, false);
76 hif
= (struct hif_msg
*)skb
->data
;
77 WARN(hif
->encrypted
& 0x1, "unsupported encryption type");
78 if (hif
->encrypted
== 0x2) {
79 if (wfx_sl_decode(wdev
, (void *)hif
)) {
81 // If frame was a confirmation, expect trouble in next
82 // exchange. However, it is harmless to fail to decode
83 // an indication frame, so try to continue. Anyway,
84 // piggyback is probably correct.
87 le16_to_cpus(&hif
->len
);
88 computed_len
= round_up(hif
->len
- sizeof(hif
->len
), 16)
89 + sizeof(struct hif_sl_msg
)
90 + sizeof(struct hif_sl_tag
);
92 le16_to_cpus(&hif
->len
);
93 computed_len
= round_up(hif
->len
, 2);
95 if (computed_len
!= read_len
) {
96 dev_err(wdev
->dev
, "inconsistent message length: %zu != %zu\n",
97 computed_len
, read_len
);
98 print_hex_dump(KERN_INFO
, "hif: ", DUMP_PREFIX_OFFSET
, 16, 1,
103 if (!(hif
->id
& HIF_ID_IS_INDICATION
)) {
105 if (hif
->id
== HIF_CNF_ID_MULTI_TRANSMIT
)
106 release_count
= le32_to_cpu(((struct hif_cnf_multi_transmit
*)hif
->body
)->num_tx_confs
);
109 WARN(wdev
->hif
.tx_buffers_used
< release_count
, "corrupted buffer counter");
110 wdev
->hif
.tx_buffers_used
-= release_count
;
111 if (!wdev
->hif
.tx_buffers_used
)
112 wake_up(&wdev
->hif
.tx_buffers_empty
);
114 _trace_hif_recv(hif
, wdev
->hif
.tx_buffers_used
);
116 if (hif
->id
!= HIF_IND_ID_EXCEPTION
&& hif
->id
!= HIF_IND_ID_ERROR
) {
117 if (hif
->seqnum
!= wdev
->hif
.rx_seqnum
)
118 dev_warn(wdev
->dev
, "wrong message sequence: %d != %d\n",
119 hif
->seqnum
, wdev
->hif
.rx_seqnum
);
120 wdev
->hif
.rx_seqnum
= (hif
->seqnum
+ 1) % (HIF_COUNTER_MAX
+ 1);
123 skb_put(skb
, hif
->len
);
124 // wfx_handle_rx takes care on SKB livetime
125 wfx_handle_rx(wdev
, skb
);
135 static int bh_work_rx(struct wfx_dev
*wdev
, int max_msg
, int *num_cnf
)
139 int ctrl_reg
, piggyback
;
142 for (i
= 0; i
< max_msg
; i
++) {
143 if (piggyback
& CTRL_NEXT_LEN_MASK
)
144 ctrl_reg
= piggyback
;
145 else if (try_wait_for_completion(&wdev
->hif
.ctrl_ready
))
146 ctrl_reg
= atomic_xchg(&wdev
->hif
.ctrl_reg
, 0);
149 if (!(ctrl_reg
& CTRL_NEXT_LEN_MASK
))
151 // ctrl_reg units are 16bits words
152 len
= (ctrl_reg
& CTRL_NEXT_LEN_MASK
) * 2;
153 piggyback
= rx_helper(wdev
, len
, num_cnf
);
156 if (!(piggyback
& CTRL_WLAN_READY
))
157 dev_err(wdev
->dev
, "unexpected piggyback value: ready bit not set: %04x\n",
160 if (piggyback
& CTRL_NEXT_LEN_MASK
) {
161 ctrl_reg
= atomic_xchg(&wdev
->hif
.ctrl_reg
, piggyback
);
162 complete(&wdev
->hif
.ctrl_ready
);
164 dev_err(wdev
->dev
, "unexpected IRQ happened: %04x/%04x\n",
165 ctrl_reg
, piggyback
);
170 static void tx_helper(struct wfx_dev
*wdev
, struct hif_msg
*hif
)
174 bool is_encrypted
= false;
175 size_t len
= le16_to_cpu(hif
->len
);
177 WARN(len
< sizeof(*hif
), "try to send corrupted data");
179 hif
->seqnum
= wdev
->hif
.tx_seqnum
;
180 wdev
->hif
.tx_seqnum
= (wdev
->hif
.tx_seqnum
+ 1) % (HIF_COUNTER_MAX
+ 1);
182 if (wfx_is_secure_command(wdev
, hif
->id
)) {
183 len
= round_up(len
- sizeof(hif
->len
), 16) + sizeof(hif
->len
) +
184 sizeof(struct hif_sl_msg_hdr
) +
185 sizeof(struct hif_sl_tag
);
186 // AES support encryption in-place. However, mac80211 access to
187 // 802.11 header after frame was sent (to get MAC addresses).
188 // So, keep origin buffer clear.
189 data
= kmalloc(len
, GFP_KERNEL
);
193 ret
= wfx_sl_encode(wdev
, hif
, data
);
199 WARN(len
> wdev
->hw_caps
.size_inp_ch_buf
,
200 "%s: request exceed WFx capability: %zu > %d\n", __func__
,
201 len
, wdev
->hw_caps
.size_inp_ch_buf
);
202 len
= wdev
->hwbus_ops
->align_size(wdev
->hwbus_priv
, len
);
203 ret
= wfx_data_write(wdev
, data
, len
);
207 wdev
->hif
.tx_buffers_used
++;
208 _trace_hif_send(hif
, wdev
->hif
.tx_buffers_used
);
214 static int bh_work_tx(struct wfx_dev
*wdev
, int max_msg
)
219 for (i
= 0; i
< max_msg
; i
++) {
221 if (wdev
->hif
.tx_buffers_used
< wdev
->hw_caps
.num_inp_ch_bufs
) {
222 if (try_wait_for_completion(&wdev
->hif_cmd
.ready
)) {
223 WARN(!mutex_is_locked(&wdev
->hif_cmd
.lock
), "data locking error");
224 hif
= wdev
->hif_cmd
.buf_send
;
226 hif
= wfx_tx_queues_get(wdev
);
231 tx_helper(wdev
, hif
);
236 /* In SDIO mode, it is necessary to make an access to a register to acknowledge
237 * last received message. It could be possible to restrict this acknowledge to
238 * SDIO mode and only if last operation was rx.
240 static void ack_sdio_data(struct wfx_dev
*wdev
)
244 config_reg_read(wdev
, &cfg_reg
);
245 if (cfg_reg
& 0xFF) {
246 dev_warn(wdev
->dev
, "chip reports errors: %02x\n",
248 config_reg_write_bits(wdev
, 0xFF, 0x00);
252 static void bh_work(struct work_struct
*work
)
254 struct wfx_dev
*wdev
= container_of(work
, struct wfx_dev
, hif
.bh
);
255 int stats_req
= 0, stats_cnf
= 0, stats_ind
= 0;
256 bool release_chip
= false, last_op_is_rx
= false;
261 num_tx
= bh_work_tx(wdev
, 32);
264 last_op_is_rx
= false;
265 num_rx
= bh_work_rx(wdev
, 32, &stats_cnf
);
268 last_op_is_rx
= true;
269 } while (num_rx
|| num_tx
);
270 stats_ind
-= stats_cnf
;
274 if (!wdev
->hif
.tx_buffers_used
&& !work_pending(work
)) {
275 device_release(wdev
);
278 _trace_bh_stats(stats_ind
, stats_req
, stats_cnf
,
279 wdev
->hif
.tx_buffers_used
, release_chip
);
283 * An IRQ from chip did occur
285 void wfx_bh_request_rx(struct wfx_dev
*wdev
)
289 control_reg_read(wdev
, &cur
);
290 prev
= atomic_xchg(&wdev
->hif
.ctrl_reg
, cur
);
291 complete(&wdev
->hif
.ctrl_ready
);
292 queue_work(system_highpri_wq
, &wdev
->hif
.bh
);
294 if (!(cur
& CTRL_NEXT_LEN_MASK
))
295 dev_err(wdev
->dev
, "unexpected control register value: length field is 0: %04x\n",
298 dev_err(wdev
->dev
, "received IRQ but previous data was not (yet) read: %04x/%04x\n",
303 * Driver want to send data
305 void wfx_bh_request_tx(struct wfx_dev
*wdev
)
307 queue_work(system_highpri_wq
, &wdev
->hif
.bh
);
310 void wfx_bh_register(struct wfx_dev
*wdev
)
312 INIT_WORK(&wdev
->hif
.bh
, bh_work
);
313 init_completion(&wdev
->hif
.ctrl_ready
);
314 init_waitqueue_head(&wdev
->hif
.tx_buffers_empty
);
317 void wfx_bh_unregister(struct wfx_dev
*wdev
)
319 flush_work(&wdev
->hif
.bh
);