Linux Audio

Check our new training course

Loading...
v6.8
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Device handling thread implementation for mac80211 ST-Ericsson CW1200 drivers
  4 *
  5 * Copyright (c) 2010, ST-Ericsson
  6 * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
  7 *
  8 * Based on:
  9 * ST-Ericsson UMAC CW1200 driver, which is
 10 * Copyright (c) 2010, ST-Ericsson
 11 * Author: Ajitpal Singh <ajitpal.singh@stericsson.com>
 12 */
 13
 14#include <linux/module.h>
 15#include <net/mac80211.h>
 16#include <linux/kthread.h>
 17#include <linux/timer.h>
 18
 19#include "cw1200.h"
 20#include "bh.h"
 21#include "hwio.h"
 22#include "wsm.h"
 23#include "hwbus.h"
 24#include "debug.h"
 25#include "fwio.h"
 26
 27static int cw1200_bh(void *arg);
 28
 29#define DOWNLOAD_BLOCK_SIZE_WR	(0x1000 - 4)
 30/* an SPI message cannot be bigger than (2"12-1)*2 bytes
 31 * "*2" to cvt to bytes
 32 */
 33#define MAX_SZ_RD_WR_BUFFERS	(DOWNLOAD_BLOCK_SIZE_WR*2)
 34#define PIGGYBACK_CTRL_REG	(2)
 35#define EFFECTIVE_BUF_SIZE	(MAX_SZ_RD_WR_BUFFERS - PIGGYBACK_CTRL_REG)
 36
 37/* Suspend state privates */
 38enum cw1200_bh_pm_state {
 39	CW1200_BH_RESUMED = 0,
 40	CW1200_BH_SUSPEND,
 41	CW1200_BH_SUSPENDED,
 42	CW1200_BH_RESUME,
 43};
 44
 
 
 
 45static void cw1200_bh_work(struct work_struct *work)
 46{
 47	struct cw1200_common *priv =
 48	container_of(work, struct cw1200_common, bh_work);
 49	cw1200_bh(priv);
 50}
 51
 52int cw1200_register_bh(struct cw1200_common *priv)
 53{
 54	int err = 0;
 55	/* Realtime workqueue */
 56	priv->bh_workqueue = alloc_workqueue("cw1200_bh",
 57				WQ_MEM_RECLAIM | WQ_HIGHPRI
 58				| WQ_CPU_INTENSIVE, 1);
 59
 60	if (!priv->bh_workqueue)
 61		return -ENOMEM;
 62
 63	INIT_WORK(&priv->bh_work, cw1200_bh_work);
 64
 65	pr_debug("[BH] register.\n");
 66
 67	atomic_set(&priv->bh_rx, 0);
 68	atomic_set(&priv->bh_tx, 0);
 69	atomic_set(&priv->bh_term, 0);
 70	atomic_set(&priv->bh_suspend, CW1200_BH_RESUMED);
 71	priv->bh_error = 0;
 72	priv->hw_bufs_used = 0;
 73	priv->buf_id_tx = 0;
 74	priv->buf_id_rx = 0;
 75	init_waitqueue_head(&priv->bh_wq);
 76	init_waitqueue_head(&priv->bh_evt_wq);
 77
 78	err = !queue_work(priv->bh_workqueue, &priv->bh_work);
 79	WARN_ON(err);
 80	return err;
 81}
 82
 83void cw1200_unregister_bh(struct cw1200_common *priv)
 84{
 85	atomic_inc(&priv->bh_term);
 86	wake_up(&priv->bh_wq);
 87
 
 
 88	destroy_workqueue(priv->bh_workqueue);
 89	priv->bh_workqueue = NULL;
 90
 91	pr_debug("[BH] unregistered.\n");
 92}
 93
 94void cw1200_irq_handler(struct cw1200_common *priv)
 95{
 96	pr_debug("[BH] irq.\n");
 97
 98	/* Disable Interrupts! */
 99	/* NOTE:  hwbus_ops->lock already held */
100	__cw1200_irq_enable(priv, 0);
101
102	if (/* WARN_ON */(priv->bh_error))
103		return;
104
105	if (atomic_inc_return(&priv->bh_rx) == 1)
106		wake_up(&priv->bh_wq);
107}
108EXPORT_SYMBOL_GPL(cw1200_irq_handler);
109
110void cw1200_bh_wakeup(struct cw1200_common *priv)
111{
112	pr_debug("[BH] wakeup.\n");
113	if (priv->bh_error) {
114		pr_err("[BH] wakeup failed (BH error)\n");
115		return;
116	}
117
118	if (atomic_inc_return(&priv->bh_tx) == 1)
119		wake_up(&priv->bh_wq);
120}
121
122int cw1200_bh_suspend(struct cw1200_common *priv)
123{
124	pr_debug("[BH] suspend.\n");
125	if (priv->bh_error) {
126		wiphy_warn(priv->hw->wiphy, "BH error -- can't suspend\n");
127		return -EINVAL;
128	}
129
130	atomic_set(&priv->bh_suspend, CW1200_BH_SUSPEND);
131	wake_up(&priv->bh_wq);
132	return wait_event_timeout(priv->bh_evt_wq, priv->bh_error ||
133		(CW1200_BH_SUSPENDED == atomic_read(&priv->bh_suspend)),
134		 1 * HZ) ? 0 : -ETIMEDOUT;
135}
136
137int cw1200_bh_resume(struct cw1200_common *priv)
138{
139	pr_debug("[BH] resume.\n");
140	if (priv->bh_error) {
141		wiphy_warn(priv->hw->wiphy, "BH error -- can't resume\n");
142		return -EINVAL;
143	}
144
145	atomic_set(&priv->bh_suspend, CW1200_BH_RESUME);
146	wake_up(&priv->bh_wq);
147	return wait_event_timeout(priv->bh_evt_wq, priv->bh_error ||
148		(CW1200_BH_RESUMED == atomic_read(&priv->bh_suspend)),
149		1 * HZ) ? 0 : -ETIMEDOUT;
150}
151
152static inline void wsm_alloc_tx_buffer(struct cw1200_common *priv)
153{
154	++priv->hw_bufs_used;
155}
156
157int wsm_release_tx_buffer(struct cw1200_common *priv, int count)
158{
159	int ret = 0;
160	int hw_bufs_used = priv->hw_bufs_used;
161
162	priv->hw_bufs_used -= count;
163	if (WARN_ON(priv->hw_bufs_used < 0))
164		ret = -1;
165	else if (hw_bufs_used >= priv->wsm_caps.input_buffers)
166		ret = 1;
167	if (!priv->hw_bufs_used)
168		wake_up(&priv->bh_evt_wq);
169	return ret;
170}
171
172static int cw1200_bh_read_ctrl_reg(struct cw1200_common *priv,
173					  u16 *ctrl_reg)
174{
175	int ret;
176
177	ret = cw1200_reg_read_16(priv,
178			ST90TDS_CONTROL_REG_ID, ctrl_reg);
179	if (ret) {
180		ret = cw1200_reg_read_16(priv,
181				ST90TDS_CONTROL_REG_ID, ctrl_reg);
182		if (ret)
183			pr_err("[BH] Failed to read control register.\n");
184	}
185
186	return ret;
187}
188
189static int cw1200_device_wakeup(struct cw1200_common *priv)
190{
191	u16 ctrl_reg;
192	int ret;
193
194	pr_debug("[BH] Device wakeup.\n");
195
196	/* First, set the dpll register */
197	ret = cw1200_reg_write_32(priv, ST90TDS_TSET_GEN_R_W_REG_ID,
198				  cw1200_dpll_from_clk(priv->hw_refclk));
199	if (WARN_ON(ret))
200		return ret;
201
202	/* To force the device to be always-on, the host sets WLAN_UP to 1 */
203	ret = cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID,
204			ST90TDS_CONT_WUP_BIT);
205	if (WARN_ON(ret))
206		return ret;
207
208	ret = cw1200_bh_read_ctrl_reg(priv, &ctrl_reg);
209	if (WARN_ON(ret))
210		return ret;
211
212	/* If the device returns WLAN_RDY as 1, the device is active and will
213	 * remain active.
214	 */
215	if (ctrl_reg & ST90TDS_CONT_RDY_BIT) {
216		pr_debug("[BH] Device awake.\n");
217		return 1;
218	}
219
220	return 0;
221}
222
223/* Must be called from BH thraed. */
224void cw1200_enable_powersave(struct cw1200_common *priv,
225			     bool enable)
226{
227	pr_debug("[BH] Powerave is %s.\n",
228		 enable ? "enabled" : "disabled");
229	priv->powersave_enabled = enable;
230}
231
232static int cw1200_bh_rx_helper(struct cw1200_common *priv,
233			       uint16_t *ctrl_reg,
234			       int *tx)
235{
236	size_t read_len = 0;
237	struct sk_buff *skb_rx = NULL;
238	struct wsm_hdr *wsm;
239	size_t wsm_len;
240	u16 wsm_id;
241	u8 wsm_seq;
242	int rx_resync = 1;
243
244	size_t alloc_len;
245	u8 *data;
246
247	read_len = (*ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) * 2;
248	if (!read_len)
249		return 0; /* No more work */
250
251	if (WARN_ON((read_len < sizeof(struct wsm_hdr)) ||
252		    (read_len > EFFECTIVE_BUF_SIZE))) {
253		pr_debug("Invalid read len: %zu (%04x)",
254			 read_len, *ctrl_reg);
255		goto err;
256	}
257
258	/* Add SIZE of PIGGYBACK reg (CONTROL Reg)
259	 * to the NEXT Message length + 2 Bytes for SKB
260	 */
261	read_len = read_len + 2;
262
263	alloc_len = priv->hwbus_ops->align_size(
264		priv->hwbus_priv, read_len);
265
266	/* Check if not exceeding CW1200 capabilities */
267	if (WARN_ON_ONCE(alloc_len > EFFECTIVE_BUF_SIZE)) {
268		pr_debug("Read aligned len: %zu\n",
269			 alloc_len);
270	}
271
272	skb_rx = dev_alloc_skb(alloc_len);
273	if (WARN_ON(!skb_rx))
274		goto err;
275
276	skb_trim(skb_rx, 0);
277	skb_put(skb_rx, read_len);
278	data = skb_rx->data;
279	if (WARN_ON(!data))
280		goto err;
281
282	if (WARN_ON(cw1200_data_read(priv, data, alloc_len))) {
283		pr_err("rx blew up, len %zu\n", alloc_len);
284		goto err;
285	}
286
287	/* Piggyback */
288	*ctrl_reg = __le16_to_cpu(
289		((__le16 *)data)[alloc_len / 2 - 1]);
290
291	wsm = (struct wsm_hdr *)data;
292	wsm_len = __le16_to_cpu(wsm->len);
293	if (WARN_ON(wsm_len > read_len))
294		goto err;
295
296	if (priv->wsm_enable_wsm_dumps)
297		print_hex_dump_bytes("<-- ",
298				     DUMP_PREFIX_NONE,
299				     data, wsm_len);
300
301	wsm_id  = __le16_to_cpu(wsm->id) & 0xFFF;
302	wsm_seq = (__le16_to_cpu(wsm->id) >> 13) & 7;
303
304	skb_trim(skb_rx, wsm_len);
305
306	if (wsm_id == 0x0800) {
307		wsm_handle_exception(priv,
308				     &data[sizeof(*wsm)],
309				     wsm_len - sizeof(*wsm));
310		goto err;
311	} else if (!rx_resync) {
312		if (WARN_ON(wsm_seq != priv->wsm_rx_seq))
313			goto err;
314	}
315	priv->wsm_rx_seq = (wsm_seq + 1) & 7;
316	rx_resync = 0;
317
318	if (wsm_id & 0x0400) {
319		int rc = wsm_release_tx_buffer(priv, 1);
320		if (WARN_ON(rc < 0))
321			return rc;
322		else if (rc > 0)
323			*tx = 1;
324	}
325
326	/* cw1200_wsm_rx takes care on SKB livetime */
327	if (WARN_ON(wsm_handle_rx(priv, wsm_id, wsm, &skb_rx)))
328		goto err;
329
330	dev_kfree_skb(skb_rx);
 
 
 
331
332	return 0;
333
334err:
335	dev_kfree_skb(skb_rx);
 
 
 
336	return -1;
337}
338
339static int cw1200_bh_tx_helper(struct cw1200_common *priv,
340			       int *pending_tx,
341			       int *tx_burst)
342{
343	size_t tx_len;
344	u8 *data;
345	int ret;
346	struct wsm_hdr *wsm;
347
348	if (priv->device_can_sleep) {
349		ret = cw1200_device_wakeup(priv);
350		if (WARN_ON(ret < 0)) { /* Error in wakeup */
351			*pending_tx = 1;
352			return 0;
353		} else if (ret) { /* Woke up */
354			priv->device_can_sleep = false;
355		} else { /* Did not awake */
356			*pending_tx = 1;
357			return 0;
358		}
359	}
360
361	wsm_alloc_tx_buffer(priv);
362	ret = wsm_get_tx(priv, &data, &tx_len, tx_burst);
363	if (ret <= 0) {
364		wsm_release_tx_buffer(priv, 1);
365		if (WARN_ON(ret < 0))
366			return ret; /* Error */
367		return 0; /* No work */
368	}
369
370	wsm = (struct wsm_hdr *)data;
371	BUG_ON(tx_len < sizeof(*wsm));
372	BUG_ON(__le16_to_cpu(wsm->len) != tx_len);
373
374	atomic_inc(&priv->bh_tx);
375
376	tx_len = priv->hwbus_ops->align_size(
377		priv->hwbus_priv, tx_len);
378
379	/* Check if not exceeding CW1200 capabilities */
380	if (WARN_ON_ONCE(tx_len > EFFECTIVE_BUF_SIZE))
381		pr_debug("Write aligned len: %zu\n", tx_len);
382
383	wsm->id &= __cpu_to_le16(0xffff ^ WSM_TX_SEQ(WSM_TX_SEQ_MAX));
384	wsm->id |= __cpu_to_le16(WSM_TX_SEQ(priv->wsm_tx_seq));
385
386	if (WARN_ON(cw1200_data_write(priv, data, tx_len))) {
387		pr_err("tx blew up, len %zu\n", tx_len);
388		wsm_release_tx_buffer(priv, 1);
389		return -1; /* Error */
390	}
391
392	if (priv->wsm_enable_wsm_dumps)
393		print_hex_dump_bytes("--> ",
394				     DUMP_PREFIX_NONE,
395				     data,
396				     __le16_to_cpu(wsm->len));
397
398	wsm_txed(priv, data);
399	priv->wsm_tx_seq = (priv->wsm_tx_seq + 1) & WSM_TX_SEQ_MAX;
400
401	if (*tx_burst > 1) {
402		cw1200_debug_tx_burst(priv);
403		return 1; /* Work remains */
404	}
405
406	return 0;
407}
408
409static int cw1200_bh(void *arg)
410{
411	struct cw1200_common *priv = arg;
412	int rx, tx, term, suspend;
413	u16 ctrl_reg = 0;
414	int tx_allowed;
415	int pending_tx = 0;
416	int tx_burst;
417	long status;
418	u32 dummy;
419	int ret;
420
421	for (;;) {
422		if (!priv->hw_bufs_used &&
423		    priv->powersave_enabled &&
424		    !priv->device_can_sleep &&
425		    !atomic_read(&priv->recent_scan)) {
426			status = 1 * HZ;
427			pr_debug("[BH] Device wakedown. No data.\n");
428			cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID, 0);
429			priv->device_can_sleep = true;
430		} else if (priv->hw_bufs_used) {
431			/* Interrupt loss detection */
432			status = 1 * HZ;
433		} else {
434			status = MAX_SCHEDULE_TIMEOUT;
435		}
436
437		/* Dummy Read for SDIO retry mechanism*/
438		if ((priv->hw_type != -1) &&
439		    (atomic_read(&priv->bh_rx) == 0) &&
440		    (atomic_read(&priv->bh_tx) == 0))
441			cw1200_reg_read(priv, ST90TDS_CONFIG_REG_ID,
442					&dummy, sizeof(dummy));
443
444		pr_debug("[BH] waiting ...\n");
445		status = wait_event_interruptible_timeout(priv->bh_wq, ({
446				rx = atomic_xchg(&priv->bh_rx, 0);
447				tx = atomic_xchg(&priv->bh_tx, 0);
448				term = atomic_xchg(&priv->bh_term, 0);
449				suspend = pending_tx ?
450					0 : atomic_read(&priv->bh_suspend);
451				(rx || tx || term || suspend || priv->bh_error);
452			}), status);
453
454		pr_debug("[BH] - rx: %d, tx: %d, term: %d, bh_err: %d, suspend: %d, status: %ld\n",
455			 rx, tx, term, suspend, priv->bh_error, status);
456
457		/* Did an error occur? */
458		if ((status < 0 && status != -ERESTARTSYS) ||
459		    term || priv->bh_error) {
460			break;
461		}
462		if (!status) {  /* wait_event timed out */
463			unsigned long timestamp = jiffies;
464			long timeout;
465			int pending = 0;
466			int i;
467
468			/* Check to see if we have any outstanding frames */
469			if (priv->hw_bufs_used && (!rx || !tx)) {
470				wiphy_warn(priv->hw->wiphy,
471					   "Missed interrupt? (%d frames outstanding)\n",
472					   priv->hw_bufs_used);
473				rx = 1;
474
475				/* Get a timestamp of "oldest" frame */
476				for (i = 0; i < 4; ++i)
477					pending += cw1200_queue_get_xmit_timestamp(
478						&priv->tx_queue[i],
479						&timestamp,
480						priv->pending_frame_id);
481
482				/* Check if frame transmission is timed out.
483				 * Add an extra second with respect to possible
484				 * interrupt loss.
485				 */
486				timeout = timestamp +
487					WSM_CMD_LAST_CHANCE_TIMEOUT +
488					1 * HZ  -
489					jiffies;
490
491				/* And terminate BH thread if the frame is "stuck" */
492				if (pending && timeout < 0) {
493					wiphy_warn(priv->hw->wiphy,
494						   "Timeout waiting for TX confirm (%d/%d pending, %ld vs %lu).\n",
495						   priv->hw_bufs_used, pending,
496						   timestamp, jiffies);
497					break;
498				}
499			} else if (!priv->device_can_sleep &&
500				   !atomic_read(&priv->recent_scan)) {
501				pr_debug("[BH] Device wakedown. Timeout.\n");
502				cw1200_reg_write_16(priv,
503						    ST90TDS_CONTROL_REG_ID, 0);
504				priv->device_can_sleep = true;
505			}
506			goto done;
507		} else if (suspend) {
508			pr_debug("[BH] Device suspend.\n");
509			if (priv->powersave_enabled) {
510				pr_debug("[BH] Device wakedown. Suspend.\n");
511				cw1200_reg_write_16(priv,
512						    ST90TDS_CONTROL_REG_ID, 0);
513				priv->device_can_sleep = true;
514			}
515
516			atomic_set(&priv->bh_suspend, CW1200_BH_SUSPENDED);
517			wake_up(&priv->bh_evt_wq);
518			status = wait_event_interruptible(priv->bh_wq,
519							  CW1200_BH_RESUME == atomic_read(&priv->bh_suspend));
520			if (status < 0) {
521				wiphy_err(priv->hw->wiphy,
522					  "Failed to wait for resume: %ld.\n",
523					  status);
524				break;
525			}
526			pr_debug("[BH] Device resume.\n");
527			atomic_set(&priv->bh_suspend, CW1200_BH_RESUMED);
528			wake_up(&priv->bh_evt_wq);
529			atomic_inc(&priv->bh_rx);
530			goto done;
531		}
532
533	rx:
534		tx += pending_tx;
535		pending_tx = 0;
536
537		if (cw1200_bh_read_ctrl_reg(priv, &ctrl_reg))
538			break;
539
540		/* Don't bother trying to rx unless we have data to read */
541		if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) {
542			ret = cw1200_bh_rx_helper(priv, &ctrl_reg, &tx);
543			if (ret < 0)
544				break;
545			/* Double up here if there's more data.. */
546			if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) {
547				ret = cw1200_bh_rx_helper(priv, &ctrl_reg, &tx);
548				if (ret < 0)
549					break;
550			}
551		}
552
553	tx:
554		if (tx) {
555			tx = 0;
556
557			BUG_ON(priv->hw_bufs_used > priv->wsm_caps.input_buffers);
558			tx_burst = priv->wsm_caps.input_buffers - priv->hw_bufs_used;
559			tx_allowed = tx_burst > 0;
560
561			if (!tx_allowed) {
562				/* Buffers full.  Ensure we process tx
563				 * after we handle rx..
564				 */
565				pending_tx = tx;
566				goto done_rx;
567			}
568			ret = cw1200_bh_tx_helper(priv, &pending_tx, &tx_burst);
569			if (ret < 0)
570				break;
571			if (ret > 0) /* More to transmit */
572				tx = ret;
573
574			/* Re-read ctrl reg */
575			if (cw1200_bh_read_ctrl_reg(priv, &ctrl_reg))
576				break;
577		}
578
579	done_rx:
580		if (priv->bh_error)
581			break;
582		if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK)
583			goto rx;
584		if (tx)
585			goto tx;
586
587	done:
588		/* Re-enable device interrupts */
589		priv->hwbus_ops->lock(priv->hwbus_priv);
590		__cw1200_irq_enable(priv, 1);
591		priv->hwbus_ops->unlock(priv->hwbus_priv);
592	}
593
594	/* Explicitly disable device interrupts */
595	priv->hwbus_ops->lock(priv->hwbus_priv);
596	__cw1200_irq_enable(priv, 0);
597	priv->hwbus_ops->unlock(priv->hwbus_priv);
598
599	if (!term) {
600		pr_err("[BH] Fatal error, exiting.\n");
601		priv->bh_error = 1;
602		/* TODO: schedule_work(recovery) */
603	}
604	return 0;
605}
v5.9
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Device handling thread implementation for mac80211 ST-Ericsson CW1200 drivers
  4 *
  5 * Copyright (c) 2010, ST-Ericsson
  6 * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
  7 *
  8 * Based on:
  9 * ST-Ericsson UMAC CW1200 driver, which is
 10 * Copyright (c) 2010, ST-Ericsson
 11 * Author: Ajitpal Singh <ajitpal.singh@stericsson.com>
 12 */
 13
 14#include <linux/module.h>
 15#include <net/mac80211.h>
 16#include <linux/kthread.h>
 17#include <linux/timer.h>
 18
 19#include "cw1200.h"
 20#include "bh.h"
 21#include "hwio.h"
 22#include "wsm.h"
 23#include "hwbus.h"
 24#include "debug.h"
 25#include "fwio.h"
 26
 27static int cw1200_bh(void *arg);
 28
 29#define DOWNLOAD_BLOCK_SIZE_WR	(0x1000 - 4)
 30/* an SPI message cannot be bigger than (2"12-1)*2 bytes
 31 * "*2" to cvt to bytes
 32 */
 33#define MAX_SZ_RD_WR_BUFFERS	(DOWNLOAD_BLOCK_SIZE_WR*2)
 34#define PIGGYBACK_CTRL_REG	(2)
 35#define EFFECTIVE_BUF_SIZE	(MAX_SZ_RD_WR_BUFFERS - PIGGYBACK_CTRL_REG)
 36
 37/* Suspend state privates */
 38enum cw1200_bh_pm_state {
 39	CW1200_BH_RESUMED = 0,
 40	CW1200_BH_SUSPEND,
 41	CW1200_BH_SUSPENDED,
 42	CW1200_BH_RESUME,
 43};
 44
 45typedef int (*cw1200_wsm_handler)(struct cw1200_common *priv,
 46	u8 *data, size_t size);
 47
 48static void cw1200_bh_work(struct work_struct *work)
 49{
 50	struct cw1200_common *priv =
 51	container_of(work, struct cw1200_common, bh_work);
 52	cw1200_bh(priv);
 53}
 54
 55int cw1200_register_bh(struct cw1200_common *priv)
 56{
 57	int err = 0;
 58	/* Realtime workqueue */
 59	priv->bh_workqueue = alloc_workqueue("cw1200_bh",
 60				WQ_MEM_RECLAIM | WQ_HIGHPRI
 61				| WQ_CPU_INTENSIVE, 1);
 62
 63	if (!priv->bh_workqueue)
 64		return -ENOMEM;
 65
 66	INIT_WORK(&priv->bh_work, cw1200_bh_work);
 67
 68	pr_debug("[BH] register.\n");
 69
 70	atomic_set(&priv->bh_rx, 0);
 71	atomic_set(&priv->bh_tx, 0);
 72	atomic_set(&priv->bh_term, 0);
 73	atomic_set(&priv->bh_suspend, CW1200_BH_RESUMED);
 74	priv->bh_error = 0;
 75	priv->hw_bufs_used = 0;
 76	priv->buf_id_tx = 0;
 77	priv->buf_id_rx = 0;
 78	init_waitqueue_head(&priv->bh_wq);
 79	init_waitqueue_head(&priv->bh_evt_wq);
 80
 81	err = !queue_work(priv->bh_workqueue, &priv->bh_work);
 82	WARN_ON(err);
 83	return err;
 84}
 85
 86void cw1200_unregister_bh(struct cw1200_common *priv)
 87{
 88	atomic_add(1, &priv->bh_term);
 89	wake_up(&priv->bh_wq);
 90
 91	flush_workqueue(priv->bh_workqueue);
 92
 93	destroy_workqueue(priv->bh_workqueue);
 94	priv->bh_workqueue = NULL;
 95
 96	pr_debug("[BH] unregistered.\n");
 97}
 98
 99void cw1200_irq_handler(struct cw1200_common *priv)
100{
101	pr_debug("[BH] irq.\n");
102
103	/* Disable Interrupts! */
104	/* NOTE:  hwbus_ops->lock already held */
105	__cw1200_irq_enable(priv, 0);
106
107	if (/* WARN_ON */(priv->bh_error))
108		return;
109
110	if (atomic_add_return(1, &priv->bh_rx) == 1)
111		wake_up(&priv->bh_wq);
112}
113EXPORT_SYMBOL_GPL(cw1200_irq_handler);
114
115void cw1200_bh_wakeup(struct cw1200_common *priv)
116{
117	pr_debug("[BH] wakeup.\n");
118	if (priv->bh_error) {
119		pr_err("[BH] wakeup failed (BH error)\n");
120		return;
121	}
122
123	if (atomic_add_return(1, &priv->bh_tx) == 1)
124		wake_up(&priv->bh_wq);
125}
126
127int cw1200_bh_suspend(struct cw1200_common *priv)
128{
129	pr_debug("[BH] suspend.\n");
130	if (priv->bh_error) {
131		wiphy_warn(priv->hw->wiphy, "BH error -- can't suspend\n");
132		return -EINVAL;
133	}
134
135	atomic_set(&priv->bh_suspend, CW1200_BH_SUSPEND);
136	wake_up(&priv->bh_wq);
137	return wait_event_timeout(priv->bh_evt_wq, priv->bh_error ||
138		(CW1200_BH_SUSPENDED == atomic_read(&priv->bh_suspend)),
139		 1 * HZ) ? 0 : -ETIMEDOUT;
140}
141
142int cw1200_bh_resume(struct cw1200_common *priv)
143{
144	pr_debug("[BH] resume.\n");
145	if (priv->bh_error) {
146		wiphy_warn(priv->hw->wiphy, "BH error -- can't resume\n");
147		return -EINVAL;
148	}
149
150	atomic_set(&priv->bh_suspend, CW1200_BH_RESUME);
151	wake_up(&priv->bh_wq);
152	return wait_event_timeout(priv->bh_evt_wq, priv->bh_error ||
153		(CW1200_BH_RESUMED == atomic_read(&priv->bh_suspend)),
154		1 * HZ) ? 0 : -ETIMEDOUT;
155}
156
157static inline void wsm_alloc_tx_buffer(struct cw1200_common *priv)
158{
159	++priv->hw_bufs_used;
160}
161
162int wsm_release_tx_buffer(struct cw1200_common *priv, int count)
163{
164	int ret = 0;
165	int hw_bufs_used = priv->hw_bufs_used;
166
167	priv->hw_bufs_used -= count;
168	if (WARN_ON(priv->hw_bufs_used < 0))
169		ret = -1;
170	else if (hw_bufs_used >= priv->wsm_caps.input_buffers)
171		ret = 1;
172	if (!priv->hw_bufs_used)
173		wake_up(&priv->bh_evt_wq);
174	return ret;
175}
176
177static int cw1200_bh_read_ctrl_reg(struct cw1200_common *priv,
178					  u16 *ctrl_reg)
179{
180	int ret;
181
182	ret = cw1200_reg_read_16(priv,
183			ST90TDS_CONTROL_REG_ID, ctrl_reg);
184	if (ret) {
185		ret = cw1200_reg_read_16(priv,
186				ST90TDS_CONTROL_REG_ID, ctrl_reg);
187		if (ret)
188			pr_err("[BH] Failed to read control register.\n");
189	}
190
191	return ret;
192}
193
194static int cw1200_device_wakeup(struct cw1200_common *priv)
195{
196	u16 ctrl_reg;
197	int ret;
198
199	pr_debug("[BH] Device wakeup.\n");
200
201	/* First, set the dpll register */
202	ret = cw1200_reg_write_32(priv, ST90TDS_TSET_GEN_R_W_REG_ID,
203				  cw1200_dpll_from_clk(priv->hw_refclk));
204	if (WARN_ON(ret))
205		return ret;
206
207	/* To force the device to be always-on, the host sets WLAN_UP to 1 */
208	ret = cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID,
209			ST90TDS_CONT_WUP_BIT);
210	if (WARN_ON(ret))
211		return ret;
212
213	ret = cw1200_bh_read_ctrl_reg(priv, &ctrl_reg);
214	if (WARN_ON(ret))
215		return ret;
216
217	/* If the device returns WLAN_RDY as 1, the device is active and will
218	 * remain active.
219	 */
220	if (ctrl_reg & ST90TDS_CONT_RDY_BIT) {
221		pr_debug("[BH] Device awake.\n");
222		return 1;
223	}
224
225	return 0;
226}
227
228/* Must be called from BH thraed. */
229void cw1200_enable_powersave(struct cw1200_common *priv,
230			     bool enable)
231{
232	pr_debug("[BH] Powerave is %s.\n",
233		 enable ? "enabled" : "disabled");
234	priv->powersave_enabled = enable;
235}
236
237static int cw1200_bh_rx_helper(struct cw1200_common *priv,
238			       uint16_t *ctrl_reg,
239			       int *tx)
240{
241	size_t read_len = 0;
242	struct sk_buff *skb_rx = NULL;
243	struct wsm_hdr *wsm;
244	size_t wsm_len;
245	u16 wsm_id;
246	u8 wsm_seq;
247	int rx_resync = 1;
248
249	size_t alloc_len;
250	u8 *data;
251
252	read_len = (*ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) * 2;
253	if (!read_len)
254		return 0; /* No more work */
255
256	if (WARN_ON((read_len < sizeof(struct wsm_hdr)) ||
257		    (read_len > EFFECTIVE_BUF_SIZE))) {
258		pr_debug("Invalid read len: %zu (%04x)",
259			 read_len, *ctrl_reg);
260		goto err;
261	}
262
263	/* Add SIZE of PIGGYBACK reg (CONTROL Reg)
264	 * to the NEXT Message length + 2 Bytes for SKB
265	 */
266	read_len = read_len + 2;
267
268	alloc_len = priv->hwbus_ops->align_size(
269		priv->hwbus_priv, read_len);
270
271	/* Check if not exceeding CW1200 capabilities */
272	if (WARN_ON_ONCE(alloc_len > EFFECTIVE_BUF_SIZE)) {
273		pr_debug("Read aligned len: %zu\n",
274			 alloc_len);
275	}
276
277	skb_rx = dev_alloc_skb(alloc_len);
278	if (WARN_ON(!skb_rx))
279		goto err;
280
281	skb_trim(skb_rx, 0);
282	skb_put(skb_rx, read_len);
283	data = skb_rx->data;
284	if (WARN_ON(!data))
285		goto err;
286
287	if (WARN_ON(cw1200_data_read(priv, data, alloc_len))) {
288		pr_err("rx blew up, len %zu\n", alloc_len);
289		goto err;
290	}
291
292	/* Piggyback */
293	*ctrl_reg = __le16_to_cpu(
294		((__le16 *)data)[alloc_len / 2 - 1]);
295
296	wsm = (struct wsm_hdr *)data;
297	wsm_len = __le16_to_cpu(wsm->len);
298	if (WARN_ON(wsm_len > read_len))
299		goto err;
300
301	if (priv->wsm_enable_wsm_dumps)
302		print_hex_dump_bytes("<-- ",
303				     DUMP_PREFIX_NONE,
304				     data, wsm_len);
305
306	wsm_id  = __le16_to_cpu(wsm->id) & 0xFFF;
307	wsm_seq = (__le16_to_cpu(wsm->id) >> 13) & 7;
308
309	skb_trim(skb_rx, wsm_len);
310
311	if (wsm_id == 0x0800) {
312		wsm_handle_exception(priv,
313				     &data[sizeof(*wsm)],
314				     wsm_len - sizeof(*wsm));
315		goto err;
316	} else if (!rx_resync) {
317		if (WARN_ON(wsm_seq != priv->wsm_rx_seq))
318			goto err;
319	}
320	priv->wsm_rx_seq = (wsm_seq + 1) & 7;
321	rx_resync = 0;
322
323	if (wsm_id & 0x0400) {
324		int rc = wsm_release_tx_buffer(priv, 1);
325		if (WARN_ON(rc < 0))
326			return rc;
327		else if (rc > 0)
328			*tx = 1;
329	}
330
331	/* cw1200_wsm_rx takes care on SKB livetime */
332	if (WARN_ON(wsm_handle_rx(priv, wsm_id, wsm, &skb_rx)))
333		goto err;
334
335	if (skb_rx) {
336		dev_kfree_skb(skb_rx);
337		skb_rx = NULL;
338	}
339
340	return 0;
341
342err:
343	if (skb_rx) {
344		dev_kfree_skb(skb_rx);
345		skb_rx = NULL;
346	}
347	return -1;
348}
349
350static int cw1200_bh_tx_helper(struct cw1200_common *priv,
351			       int *pending_tx,
352			       int *tx_burst)
353{
354	size_t tx_len;
355	u8 *data;
356	int ret;
357	struct wsm_hdr *wsm;
358
359	if (priv->device_can_sleep) {
360		ret = cw1200_device_wakeup(priv);
361		if (WARN_ON(ret < 0)) { /* Error in wakeup */
362			*pending_tx = 1;
363			return 0;
364		} else if (ret) { /* Woke up */
365			priv->device_can_sleep = false;
366		} else { /* Did not awake */
367			*pending_tx = 1;
368			return 0;
369		}
370	}
371
372	wsm_alloc_tx_buffer(priv);
373	ret = wsm_get_tx(priv, &data, &tx_len, tx_burst);
374	if (ret <= 0) {
375		wsm_release_tx_buffer(priv, 1);
376		if (WARN_ON(ret < 0))
377			return ret; /* Error */
378		return 0; /* No work */
379	}
380
381	wsm = (struct wsm_hdr *)data;
382	BUG_ON(tx_len < sizeof(*wsm));
383	BUG_ON(__le16_to_cpu(wsm->len) != tx_len);
384
385	atomic_add(1, &priv->bh_tx);
386
387	tx_len = priv->hwbus_ops->align_size(
388		priv->hwbus_priv, tx_len);
389
390	/* Check if not exceeding CW1200 capabilities */
391	if (WARN_ON_ONCE(tx_len > EFFECTIVE_BUF_SIZE))
392		pr_debug("Write aligned len: %zu\n", tx_len);
393
394	wsm->id &= __cpu_to_le16(0xffff ^ WSM_TX_SEQ(WSM_TX_SEQ_MAX));
395	wsm->id |= __cpu_to_le16(WSM_TX_SEQ(priv->wsm_tx_seq));
396
397	if (WARN_ON(cw1200_data_write(priv, data, tx_len))) {
398		pr_err("tx blew up, len %zu\n", tx_len);
399		wsm_release_tx_buffer(priv, 1);
400		return -1; /* Error */
401	}
402
403	if (priv->wsm_enable_wsm_dumps)
404		print_hex_dump_bytes("--> ",
405				     DUMP_PREFIX_NONE,
406				     data,
407				     __le16_to_cpu(wsm->len));
408
409	wsm_txed(priv, data);
410	priv->wsm_tx_seq = (priv->wsm_tx_seq + 1) & WSM_TX_SEQ_MAX;
411
412	if (*tx_burst > 1) {
413		cw1200_debug_tx_burst(priv);
414		return 1; /* Work remains */
415	}
416
417	return 0;
418}
419
420static int cw1200_bh(void *arg)
421{
422	struct cw1200_common *priv = arg;
423	int rx, tx, term, suspend;
424	u16 ctrl_reg = 0;
425	int tx_allowed;
426	int pending_tx = 0;
427	int tx_burst;
428	long status;
429	u32 dummy;
430	int ret;
431
432	for (;;) {
433		if (!priv->hw_bufs_used &&
434		    priv->powersave_enabled &&
435		    !priv->device_can_sleep &&
436		    !atomic_read(&priv->recent_scan)) {
437			status = 1 * HZ;
438			pr_debug("[BH] Device wakedown. No data.\n");
439			cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID, 0);
440			priv->device_can_sleep = true;
441		} else if (priv->hw_bufs_used) {
442			/* Interrupt loss detection */
443			status = 1 * HZ;
444		} else {
445			status = MAX_SCHEDULE_TIMEOUT;
446		}
447
448		/* Dummy Read for SDIO retry mechanism*/
449		if ((priv->hw_type != -1) &&
450		    (atomic_read(&priv->bh_rx) == 0) &&
451		    (atomic_read(&priv->bh_tx) == 0))
452			cw1200_reg_read(priv, ST90TDS_CONFIG_REG_ID,
453					&dummy, sizeof(dummy));
454
455		pr_debug("[BH] waiting ...\n");
456		status = wait_event_interruptible_timeout(priv->bh_wq, ({
457				rx = atomic_xchg(&priv->bh_rx, 0);
458				tx = atomic_xchg(&priv->bh_tx, 0);
459				term = atomic_xchg(&priv->bh_term, 0);
460				suspend = pending_tx ?
461					0 : atomic_read(&priv->bh_suspend);
462				(rx || tx || term || suspend || priv->bh_error);
463			}), status);
464
465		pr_debug("[BH] - rx: %d, tx: %d, term: %d, bh_err: %d, suspend: %d, status: %ld\n",
466			 rx, tx, term, suspend, priv->bh_error, status);
467
468		/* Did an error occur? */
469		if ((status < 0 && status != -ERESTARTSYS) ||
470		    term || priv->bh_error) {
471			break;
472		}
473		if (!status) {  /* wait_event timed out */
474			unsigned long timestamp = jiffies;
475			long timeout;
476			int pending = 0;
477			int i;
478
479			/* Check to see if we have any outstanding frames */
480			if (priv->hw_bufs_used && (!rx || !tx)) {
481				wiphy_warn(priv->hw->wiphy,
482					   "Missed interrupt? (%d frames outstanding)\n",
483					   priv->hw_bufs_used);
484				rx = 1;
485
486				/* Get a timestamp of "oldest" frame */
487				for (i = 0; i < 4; ++i)
488					pending += cw1200_queue_get_xmit_timestamp(
489						&priv->tx_queue[i],
490						&timestamp,
491						priv->pending_frame_id);
492
493				/* Check if frame transmission is timed out.
494				 * Add an extra second with respect to possible
495				 * interrupt loss.
496				 */
497				timeout = timestamp +
498					WSM_CMD_LAST_CHANCE_TIMEOUT +
499					1 * HZ  -
500					jiffies;
501
502				/* And terminate BH thread if the frame is "stuck" */
503				if (pending && timeout < 0) {
504					wiphy_warn(priv->hw->wiphy,
505						   "Timeout waiting for TX confirm (%d/%d pending, %ld vs %lu).\n",
506						   priv->hw_bufs_used, pending,
507						   timestamp, jiffies);
508					break;
509				}
510			} else if (!priv->device_can_sleep &&
511				   !atomic_read(&priv->recent_scan)) {
512				pr_debug("[BH] Device wakedown. Timeout.\n");
513				cw1200_reg_write_16(priv,
514						    ST90TDS_CONTROL_REG_ID, 0);
515				priv->device_can_sleep = true;
516			}
517			goto done;
518		} else if (suspend) {
519			pr_debug("[BH] Device suspend.\n");
520			if (priv->powersave_enabled) {
521				pr_debug("[BH] Device wakedown. Suspend.\n");
522				cw1200_reg_write_16(priv,
523						    ST90TDS_CONTROL_REG_ID, 0);
524				priv->device_can_sleep = true;
525			}
526
527			atomic_set(&priv->bh_suspend, CW1200_BH_SUSPENDED);
528			wake_up(&priv->bh_evt_wq);
529			status = wait_event_interruptible(priv->bh_wq,
530							  CW1200_BH_RESUME == atomic_read(&priv->bh_suspend));
531			if (status < 0) {
532				wiphy_err(priv->hw->wiphy,
533					  "Failed to wait for resume: %ld.\n",
534					  status);
535				break;
536			}
537			pr_debug("[BH] Device resume.\n");
538			atomic_set(&priv->bh_suspend, CW1200_BH_RESUMED);
539			wake_up(&priv->bh_evt_wq);
540			atomic_add(1, &priv->bh_rx);
541			goto done;
542		}
543
544	rx:
545		tx += pending_tx;
546		pending_tx = 0;
547
548		if (cw1200_bh_read_ctrl_reg(priv, &ctrl_reg))
549			break;
550
551		/* Don't bother trying to rx unless we have data to read */
552		if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) {
553			ret = cw1200_bh_rx_helper(priv, &ctrl_reg, &tx);
554			if (ret < 0)
555				break;
556			/* Double up here if there's more data.. */
557			if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) {
558				ret = cw1200_bh_rx_helper(priv, &ctrl_reg, &tx);
559				if (ret < 0)
560					break;
561			}
562		}
563
564	tx:
565		if (tx) {
566			tx = 0;
567
568			BUG_ON(priv->hw_bufs_used > priv->wsm_caps.input_buffers);
569			tx_burst = priv->wsm_caps.input_buffers - priv->hw_bufs_used;
570			tx_allowed = tx_burst > 0;
571
572			if (!tx_allowed) {
573				/* Buffers full.  Ensure we process tx
574				 * after we handle rx..
575				 */
576				pending_tx = tx;
577				goto done_rx;
578			}
579			ret = cw1200_bh_tx_helper(priv, &pending_tx, &tx_burst);
580			if (ret < 0)
581				break;
582			if (ret > 0) /* More to transmit */
583				tx = ret;
584
585			/* Re-read ctrl reg */
586			if (cw1200_bh_read_ctrl_reg(priv, &ctrl_reg))
587				break;
588		}
589
590	done_rx:
591		if (priv->bh_error)
592			break;
593		if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK)
594			goto rx;
595		if (tx)
596			goto tx;
597
598	done:
599		/* Re-enable device interrupts */
600		priv->hwbus_ops->lock(priv->hwbus_priv);
601		__cw1200_irq_enable(priv, 1);
602		priv->hwbus_ops->unlock(priv->hwbus_priv);
603	}
604
605	/* Explicitly disable device interrupts */
606	priv->hwbus_ops->lock(priv->hwbus_priv);
607	__cw1200_irq_enable(priv, 0);
608	priv->hwbus_ops->unlock(priv->hwbus_priv);
609
610	if (!term) {
611		pr_err("[BH] Fatal error, exiting.\n");
612		priv->bh_error = 1;
613		/* TODO: schedule_work(recovery) */
614	}
615	return 0;
616}