Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d97e2d2b authored by Jes Sorensen's avatar Jes Sorensen Committed by Greg Kroah-Hartman
Browse files

staging: rtl8723au: Use a workqueue for command handling



Rewrite the old thread based code to use a workqueue instead. This
removes a pile of complexity, locks and queues and eliminates problem
that cmd handling could have been killed from userspace.

This was suggested by Tejun Heo - thanks!

Signed-off-by: default avatarJes Sorensen <Jes.Sorensen@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 6f1c59bf
Loading
Loading
Loading
Loading
+59 −152
Original line number Diff line number Diff line
@@ -176,13 +176,6 @@ int rtw_init_cmd_priv23a(struct cmd_priv *pcmdpriv)
{
	int res = _SUCCESS;

	sema_init(&pcmdpriv->cmd_queue_sema, 0);
	sema_init(&pcmdpriv->terminate_cmdthread_sema, 0);

	_rtw_init_queue23a(&pcmdpriv->cmd_queue);

	pcmdpriv->cmd_seq = 1;

	pcmdpriv->cmd_allocated_buf = kzalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ,
					      GFP_KERNEL);

@@ -209,6 +202,11 @@ int rtw_init_cmd_priv23a(struct cmd_priv *pcmdpriv)
	pcmdpriv->cmd_done_cnt = 0;
	pcmdpriv->rsp_cnt = 0;


	pcmdpriv->wq = alloc_workqueue("rtl8723au", 0, 1);
	if (!pcmdpriv->wq)
		res = _FAIL;

exit:

	return res;
@@ -260,32 +258,6 @@ void _rtw_free_cmd_priv23a(struct cmd_priv *pcmdpriv)
	}
}

/*
Calling Context:
rtw_enqueue_cmd23a can only be called between kernel thread,
since only spin_lock is used.

ISR/Call-Back functions can't call this sub-function.
*/

int _rtw_enqueue_cmd23a(struct rtw_queue *queue, struct cmd_obj *obj)
{
	unsigned long irqL;

	if (obj == NULL)
		goto exit;

	spin_lock_irqsave(&queue->lock, irqL);

	list_add_tail(&obj->list, &queue->queue);

	spin_unlock_irqrestore(&queue->lock, irqL);

exit:

	return _SUCCESS;
}

u32 rtw_init_evt_priv23a(struct evt_priv *pevtpriv)
{
	int res;
@@ -330,21 +302,21 @@ static int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
	if (cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan))
		bAllow = true;

	if ((pcmdpriv->padapter->hw_init_completed == false &&
	     bAllow == false) || pcmdpriv->cmdthd_running == false)
	if (pcmdpriv->padapter->hw_init_completed == false && bAllow == false)
		return _FAIL;
	return _SUCCESS;
}

u32 rtw_enqueue_cmd23a(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
static void rtw_cmd_work(struct work_struct *work);

int rtw_enqueue_cmd23a(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
{
	int res = _FAIL;
	struct rtw_adapter *padapter = pcmdpriv->padapter;

	if (!cmd_obj)
		goto exit;

	cmd_obj->padapter = padapter;
	cmd_obj->padapter = pcmdpriv->padapter;

	res = rtw_cmd_filter(pcmdpriv, cmd_obj);
	if (res == _FAIL) {
@@ -352,32 +324,18 @@ u32 rtw_enqueue_cmd23a(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
		goto exit;
	}

	res = _rtw_enqueue_cmd23a(&pcmdpriv->cmd_queue, cmd_obj);
	INIT_WORK(&cmd_obj->work, rtw_cmd_work);

	if (res == _SUCCESS)
		up(&pcmdpriv->cmd_queue_sema);
	res = queue_work(pcmdpriv->wq, &cmd_obj->work);

	if (!res) {
		printk(KERN_ERR "%s: Call to queue_work() failed\n", __func__);
		res = _FAIL;
	} else
		res = _SUCCESS;
exit:
	return res;
}

static struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv)
{
	struct cmd_obj *obj;
	struct rtw_queue *queue = &pcmdpriv->cmd_queue;
	unsigned long irqL;

	spin_lock_irqsave(&queue->lock, irqL);
	if (list_empty(&queue->queue))
		obj = NULL;
	else {
		obj = container_of((&queue->queue)->next, struct cmd_obj, list);
		list_del_init(&obj->list);
	}

	spin_unlock_irqrestore(&queue->lock, irqL);

	return obj;
	return res;
}

void rtw_cmd_clr_isr23a(struct	cmd_priv *pcmdpriv)
@@ -404,42 +362,16 @@ void rtw_free_cmd_obj23a(struct cmd_obj *pcmd)
	kfree(pcmd);
}

int rtw_cmd_thread23a(void *context)
static void rtw_cmd_work(struct work_struct *work)
{
	u8 ret;
	struct cmd_obj *pcmd;
	u8 *pcmdbuf, *prspbuf;
	u8 (*cmd_hdl)(struct rtw_adapter *padapter, u8* pbuf);
	void (*pcmd_callback)(struct rtw_adapter *dev, struct cmd_obj *pcmd);
	struct rtw_adapter *padapter = (struct rtw_adapter *)context;
	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;

	allow_signal(SIGTERM);
	struct cmd_priv *pcmdpriv;
	struct cmd_obj *pcmd = container_of(work, struct cmd_obj, work);
	u8 *pcmdbuf;

	pcmdpriv = &pcmd->padapter->cmdpriv;
	pcmdbuf = pcmdpriv->cmd_buf;
	prspbuf = pcmdpriv->rsp_buf;

	pcmdpriv->cmdthd_running = true;
	up(&pcmdpriv->terminate_cmdthread_sema);

	RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
		 ("start r871x rtw_cmd_thread23a !!!!\n"));

	while(1) {
		if (down_interruptible(&pcmdpriv->cmd_queue_sema))
			break;
_next:
		if ((padapter->bDriverStopped == true) ||
		    (padapter->bSurpriseRemoved == true)) {
			DBG_8723A("%s: DriverStopped(%d) SurpriseRemoved(%d) "
				  "break at line %d\n",	__func__,
				  padapter->bDriverStopped,
				  padapter->bSurpriseRemoved, __LINE__);
			break;
		}

		if (!(pcmd = rtw_dequeue_cmd(pcmdpriv)))
			continue;

	if (rtw_cmd_filter(pcmdpriv, pcmd) == _FAIL) {
		pcmd->res = H2C_DROPPED;
@@ -455,27 +387,22 @@ int rtw_cmd_thread23a(void *context)
	if (pcmd->cmdcode < (sizeof(wlancmds)/sizeof(struct cmd_hdl))) {
		cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns;

			if (cmd_hdl) {
				ret = cmd_hdl(pcmd->padapter, pcmdbuf);
				pcmd->res = ret;
			}

			pcmdpriv->cmd_seq++;
		if (cmd_hdl)
			pcmd->res = cmd_hdl(pcmd->padapter, pcmdbuf);
		else
			pcmd->res = H2C_DROPPED;
	} else
		pcmd->res = H2C_PARAMETERS_ERROR;

		cmd_hdl = NULL;

post_process:
	/* call callback function for post-processed */
	if (pcmd->cmdcode < (sizeof(rtw_cmd_callback) /
			     sizeof(struct _cmd_callback))) {
			pcmd_callback =
				rtw_cmd_callback[pcmd->cmdcode].callback;
		pcmd_callback =	rtw_cmd_callback[pcmd->cmdcode].callback;
		if (!pcmd_callback) {
			RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
					 ("mlme_cmd_hdl(): pcmd_callback = "
					  "0x%p, cmdcode = 0x%x\n",
				 ("mlme_cmd_hdl(): pcmd_callback = 0x%p, "
				  "cmdcode = 0x%x\n",
				  pcmd_callback, pcmd->cmdcode));
			rtw_free_cmd_obj23a(pcmd);
		} else {
@@ -491,28 +418,8 @@ int rtw_cmd_thread23a(void *context)
			  __func__, pcmd->cmdcode));
		rtw_free_cmd_obj23a(pcmd);
	}

		if (signal_pending (current))
			flush_signals(current);

		goto _next;

}
	pcmdpriv->cmdthd_running = false;

	/*  free all cmd_obj resources */
	do {
		pcmd = rtw_dequeue_cmd(pcmdpriv);
		if (!pcmd)
			break;

		rtw_free_cmd_obj23a(pcmd);
	} while(1);

	up(&pcmdpriv->terminate_cmdthread_sema);

	complete_and_exit(NULL, 0);
}

u8 rtw_sitesurvey_cmd23a(struct rtw_adapter *padapter,
			 struct cfg80211_ssid *ssid, int ssid_num,
+2 −10
Original line number Diff line number Diff line
@@ -1738,8 +1738,8 @@ void rtl8723a_set_hal_ops(struct hal_ops *pHalFunc)
		&rtl8723a_SetBeaconRelatedRegisters;

	pHalFunc->Add_RateATid = &rtl8723a_add_rateatid;
	pHalFunc->run_thread = &rtl8723a_start_thread;
	pHalFunc->cancel_thread = &rtl8723a_stop_thread;
	pHalFunc->run_thread = NULL;
	pHalFunc->cancel_thread = NULL;

	pHalFunc->read_bbreg = &PHY_QueryBBReg;
	pHalFunc->write_bbreg = &PHY_SetBBReg;
@@ -3187,11 +3187,3 @@ void rtl8723a_clone_haldata(struct rtw_adapter *dst_adapter,
	memcpy(dst_adapter->HalData, src_adapter->HalData,
	       dst_adapter->hal_data_sz);
}

void rtl8723a_start_thread(struct rtw_adapter *padapter)
{
}

void rtl8723a_stop_thread(struct rtw_adapter *padapter)
{
}
+3 −8
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#define CMDBUFF_ALIGN_SZ 512

struct cmd_obj {
	struct work_struct work;
	struct rtw_adapter *padapter;
	u16	cmdcode;
	u8	res;
@@ -41,16 +42,11 @@ struct cmd_obj {
	u32	cmdsz;
	u8	*rsp;
	u32	rspsz;
	/* struct semaphore		cmd_sem; */
	struct list_head	list;
};

struct cmd_priv {
	struct semaphore	cmd_queue_sema;
	/* struct semaphore	cmd_done_sema; */
	struct semaphore	terminate_cmdthread_sema;
	struct rtw_queue	cmd_queue;
	u8	cmd_seq;
	struct workqueue_struct *wq;
	u8	*cmd_buf;	/* shall be non-paged, and 4 bytes aligned */
	u8	*cmd_allocated_buf;
	u8	*rsp_buf;	/* shall be non-paged, and 4 bytes aligned */
@@ -58,7 +54,6 @@ struct cmd_priv {
	u32	cmd_issued_cnt;
	u32	cmd_done_cnt;
	u32	rsp_cnt;
	u8 cmdthd_running;
	struct rtw_adapter *padapter;
};

@@ -94,7 +89,7 @@ struct c2h_evt_hdr {

#define c2h_evt_exist(c2h_evt) ((c2h_evt)->id || (c2h_evt)->plen)

u32 rtw_enqueue_cmd23a(struct cmd_priv *pcmdpriv, struct cmd_obj *obj);
int rtw_enqueue_cmd23a(struct cmd_priv *pcmdpriv, struct cmd_obj *obj);
void rtw_free_cmd_obj23a(struct cmd_obj *pcmd);

int rtw_cmd_thread23a(void *context);
+3 −12
Original line number Diff line number Diff line
@@ -383,14 +383,7 @@ u32 rtw_start_drv_threads23a(struct rtw_adapter *padapter)

	RT_TRACE(_module_os_intfs_c_, _drv_info_,
		 ("+rtw_start_drv_threads23a\n"));
	padapter->cmdThread = kthread_run(rtw_cmd_thread23a, padapter,
					  "RTW_CMD_THREAD");
	if (IS_ERR(padapter->cmdThread)) {
		_status = _FAIL;
	} else {
		/* wait for cmd_thread to run */
		down(&padapter->cmdpriv.terminate_cmdthread_sema);
	}

	rtw_hal_start_thread23a(padapter);
	return _status;
}
@@ -399,10 +392,8 @@ void rtw_stop_drv_threads23a(struct rtw_adapter *padapter)
{
	RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_stop_drv_threads23a\n"));

	/* Below is to termindate rtw_cmd_thread23a & event_thread... */
	up(&padapter->cmdpriv.cmd_queue_sema);
	if (padapter->cmdThread)
		down(&padapter->cmdpriv.terminate_cmdthread_sema);
	flush_workqueue(padapter->cmdpriv.wq);

	rtw_hal_stop_thread23a(padapter);
}