Commit 6e251174 authored by Avinash Patil's avatar Avinash Patil Committed by John W. Linville
Browse files

mwifiex: add rx workqueue support



This patch adds RX work queue support to mwifiex.
Packets received are queued to internal queue which are then
processed by scheduling a work item for RX process.

RX work is enabled only on SMP systems.

Reviewed-by: default avatarJames Cameron <quozl@laptop.org>
Signed-off-by: default avatarAvinash Patil <patila@marvell.com>
Signed-off-by: default avatarMarc Yang <yangyang@marvell.com>
Signed-off-by: default avatarCathy Luo <cluo@marvell.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent d8d91253
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -183,6 +183,15 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
	if (!tbl)
		return;

	spin_lock_irqsave(&priv->adapter->rx_proc_lock, flags);
	priv->adapter->rx_locked = true;
	if (priv->adapter->rx_processing) {
		spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
		flush_workqueue(priv->adapter->rx_workqueue);
	} else {
		spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
	}

	start_win = (tbl->start_win + tbl->win_size) & (MAX_TID_VALUE - 1);
	mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win);

@@ -194,6 +203,11 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,

	kfree(tbl->rx_reorder_ptr);
	kfree(tbl);

	spin_lock_irqsave(&priv->adapter->rx_proc_lock, flags);
	priv->adapter->rx_locked = false;
	spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);

}

/*
+19 −0
Original line number Diff line number Diff line
@@ -447,8 +447,11 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
	spin_lock_init(&adapter->cmd_free_q_lock);
	spin_lock_init(&adapter->cmd_pending_q_lock);
	spin_lock_init(&adapter->scan_pending_q_lock);
	spin_lock_init(&adapter->rx_q_lock);
	spin_lock_init(&adapter->rx_proc_lock);

	skb_queue_head_init(&adapter->usb_rx_data_q);
	skb_queue_head_init(&adapter->rx_data_q);

	for (i = 0; i < adapter->priv_num; ++i) {
		INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head);
@@ -614,6 +617,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
	int ret = -EINPROGRESS;
	struct mwifiex_private *priv;
	s32 i;
	unsigned long flags;
	struct sk_buff *skb;

	/* mwifiex already shutdown */
@@ -648,6 +652,21 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
		}
	}

	spin_lock_irqsave(&adapter->rx_proc_lock, flags);

	while ((skb = skb_dequeue(&adapter->rx_data_q))) {
		struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);

		atomic_dec(&adapter->rx_pending);
		priv = adapter->priv[rx_info->bss_num];
		if (priv)
			priv->stats.rx_dropped++;

		dev_kfree_skb_any(skb);
	}

	spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);

	spin_lock(&adapter->mwifiex_lock);

	if (adapter->if_ops.data_complete) {
+91 −0
Original line number Diff line number Diff line
@@ -126,6 +126,42 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter)
	return 0;
}

static int mwifiex_process_rx(struct mwifiex_adapter *adapter)
{
	unsigned long flags;
	struct sk_buff *skb;
	bool delay_main_work = adapter->delay_main_work;

	spin_lock_irqsave(&adapter->rx_proc_lock, flags);
	if (adapter->rx_processing || adapter->rx_locked) {
		spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
		goto exit_rx_proc;
	} else {
		adapter->rx_processing = true;
		spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
	}

	/* Check for Rx data */
	while ((skb = skb_dequeue(&adapter->rx_data_q))) {
		atomic_dec(&adapter->rx_pending);
		if (adapter->delay_main_work &&
		    (atomic_dec_return(&adapter->rx_pending) <
		     LOW_RX_PENDING)) {
			adapter->delay_main_work = false;
			queue_work(adapter->rx_workqueue, &adapter->rx_work);
		}
		mwifiex_handle_rx_packet(adapter, skb);
	}
	spin_lock_irqsave(&adapter->rx_proc_lock, flags);
	adapter->rx_processing = false;
	spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);

	if (delay_main_work)
		queue_work(adapter->workqueue, &adapter->main_work);
exit_rx_proc:
	return 0;
}

/*
 * The main process.
 *
@@ -163,6 +199,19 @@ process_start:
		    (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY))
			break;

		/* If we process interrupts first, it would increase RX pending
		 * even further. Avoid this by checking if rx_pending has
		 * crossed high threshold and schedule rx work queue
		 * and then process interrupts
		 */
		if (atomic_read(&adapter->rx_pending) >= HIGH_RX_PENDING) {
			adapter->delay_main_work = true;
			if (!adapter->rx_processing)
				queue_work(adapter->rx_workqueue,
					   &adapter->rx_work);
			break;
		}

		/* Handle pending interrupt if any */
		if (adapter->int_status) {
			if (adapter->hs_activated)
@@ -171,6 +220,9 @@ process_start:
				adapter->if_ops.process_int_status(adapter);
		}

		if (adapter->rx_work_enabled && adapter->data_received)
			queue_work(adapter->rx_workqueue, &adapter->rx_work);

		/* Need to wake up the card ? */
		if ((adapter->ps_state == PS_STATE_SLEEP) &&
		    (adapter->pm_wakeup_card_req &&
@@ -183,6 +235,7 @@ process_start:
		}

		if (IS_CARD_RX_RCVD(adapter)) {
			adapter->data_received = false;
			adapter->pm_wakeup_fw_try = false;
			if (adapter->ps_state == PS_STATE_SLEEP)
				adapter->ps_state = PS_STATE_AWAKE;
@@ -318,6 +371,12 @@ static void mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter)
	flush_workqueue(adapter->workqueue);
	destroy_workqueue(adapter->workqueue);
	adapter->workqueue = NULL;

	if (adapter->rx_workqueue) {
		flush_workqueue(adapter->rx_workqueue);
		destroy_workqueue(adapter->rx_workqueue);
		adapter->rx_workqueue = NULL;
	}
}

/*
@@ -731,6 +790,21 @@ int is_command_pending(struct mwifiex_adapter *adapter)
	return !is_cmd_pend_q_empty;
}

/*
 * This is the RX work queue function.
 *
 * It handles the RX operations.
 */
static void mwifiex_rx_work_queue(struct work_struct *work)
{
	struct mwifiex_adapter *adapter =
		container_of(work, struct mwifiex_adapter, rx_work);

	if (adapter->surprise_removed)
		return;
	mwifiex_process_rx(adapter);
}

/*
 * This is the main work queue function.
 *
@@ -787,6 +861,11 @@ mwifiex_add_card(void *card, struct semaphore *sem,
	adapter->cmd_wait_q.status = 0;
	adapter->scan_wait_q_woken = false;

	if (num_possible_cpus() > 1) {
		adapter->rx_work_enabled = true;
		pr_notice("rx work enabled, cpus %d\n", num_possible_cpus());
	}

	adapter->workqueue =
		alloc_workqueue("MWIFIEX_WORK_QUEUE",
				WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
@@ -794,6 +873,18 @@ mwifiex_add_card(void *card, struct semaphore *sem,
		goto err_kmalloc;

	INIT_WORK(&adapter->main_work, mwifiex_main_work_queue);

	if (adapter->rx_work_enabled) {
		adapter->rx_workqueue = alloc_workqueue("MWIFIEX_RX_WORK_QUEUE",
							WQ_HIGHPRI |
							WQ_MEM_RECLAIM |
							WQ_UNBOUND, 1);
		if (!adapter->rx_workqueue)
			goto err_kmalloc;

		INIT_WORK(&adapter->rx_work, mwifiex_rx_work_queue);
	}

	if (adapter->if_ops.iface_work)
		INIT_WORK(&adapter->iface_work, adapter->if_ops.iface_work);

+14 −0
Original line number Diff line number Diff line
@@ -58,6 +58,9 @@ enum {
#define MAX_TX_PENDING      100
#define LOW_TX_PENDING      80

#define HIGH_RX_PENDING     50
#define LOW_RX_PENDING      20

#define MWIFIEX_UPLD_SIZE               (2312)

#define MAX_EVENT_SIZE                  2048
@@ -714,6 +717,12 @@ struct mwifiex_adapter {
	atomic_t cmd_pending;
	struct workqueue_struct *workqueue;
	struct work_struct main_work;
	struct workqueue_struct *rx_workqueue;
	struct work_struct rx_work;
	bool rx_work_enabled;
	bool rx_processing;
	bool delay_main_work;
	bool rx_locked;
	struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM];
	/* spin lock for init/shutdown */
	spinlock_t mwifiex_lock;
@@ -754,6 +763,10 @@ struct mwifiex_adapter {
	struct list_head scan_pending_q;
	/* spin lock for scan_pending_q */
	spinlock_t scan_pending_q_lock;
	/* spin lock for RX queue */
	spinlock_t rx_q_lock;
	/* spin lock for RX processing routine */
	spinlock_t rx_proc_lock;
	struct sk_buff_head usb_rx_data_q;
	u32 scan_processing;
	u16 region_code;
@@ -831,6 +844,7 @@ struct mwifiex_adapter {
	u8 num_mem_types;
	u8 curr_mem_idx;
	bool scan_chan_gap_enabled;
	struct sk_buff_head rx_data_q;
};

int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
+11 −1
Original line number Diff line number Diff line
@@ -1233,6 +1233,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
	struct sk_buff *skb_tmp = NULL;
	struct mwifiex_pcie_buf_desc *desc;
	struct mwifiex_pfu_buf_desc *desc2;
	unsigned long flags;

	if (!mwifiex_pcie_ok_to_access_hw(adapter))
		mwifiex_pm_wakeup_card(adapter);
@@ -1283,8 +1284,17 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
				"info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n",
				card->rxbd_rdptr, wrptr, rx_len);
			skb_pull(skb_data, INTF_HEADER_LEN);
			if (adapter->rx_work_enabled) {
				spin_lock_irqsave(&adapter->rx_q_lock, flags);
				skb_queue_tail(&adapter->rx_data_q, skb_data);
				spin_unlock_irqrestore(&adapter->rx_q_lock,
						       flags);
				adapter->data_received = true;
				atomic_inc(&adapter->rx_pending);
			} else {
				mwifiex_handle_rx_packet(adapter, skb_data);
			}
		}

		skb_tmp = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
		if (!skb_tmp) {
Loading