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

Commit a7af530d authored by Samuel Ortiz's avatar Samuel Ortiz Committed by John W. Linville
Browse files

iwmc3200wifi: 802.11n Tx aggregation support



To support 802.11n Tx aggregation support with iwmc3200 wifi, we have to
handle the UMAC_CMD_OPCODE_STOP_RESUME_STA_TX notification from the UMAC.
Before sending an AddBA, the UMAC synchronizes with the host in order to
know what is the last Tx frame it's supposed to receive before it will be
able to start the actual aggregation session.
We thus have to keep track of the last sequence number that is scheduled
for transmission on a particular RAxTID, send an answer to the UMAC with
this sequence number. The UMAC then does the BA negociation and once it's
done with it sends a new UMAC_CMD_OPCODE_STOP_RESUME_STA_TX notification
to let us know that we can resume the Tx flow on the specified RAxTID.

Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
Reviewed-by: default avatarZhu Yi <yi.zhu@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 2351178c
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -929,3 +929,34 @@ int iwm_target_reset(struct iwm_priv *iwm)

	return iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
}

int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm,
				 struct iwm_umac_notif_stop_resume_tx *ntf)
{
	struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
	struct iwm_umac_cmd umac_cmd;
	struct iwm_umac_cmd_stop_resume_tx stp_res_cmd;
	struct iwm_sta_info *sta_info;
	u8 sta_id = STA_ID_N_COLOR_ID(ntf->sta_id);
	int i;

	sta_info = &iwm->sta_table[sta_id];
	if (!sta_info->valid) {
		IWM_ERR(iwm, "Invalid STA: %d\n", sta_id);
		return -EINVAL;
	}

	umac_cmd.id = UMAC_CMD_OPCODE_STOP_RESUME_STA_TX;
	umac_cmd.resp = 0;

	stp_res_cmd.flags = ntf->flags;
	stp_res_cmd.sta_id = ntf->sta_id;
	stp_res_cmd.stop_resume_tid_msk = ntf->stop_resume_tid_msk;
	for (i = 0; i < IWM_UMAC_TID_NR; i++)
		stp_res_cmd.last_seq_num[i] =
			sta_info->tid_info[i].last_seq_num;

	return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stp_res_cmd,
				 sizeof(struct iwm_umac_cmd_stop_resume_tx));

}
+10 −0
Original line number Diff line number Diff line
@@ -450,6 +450,14 @@ struct iwm_umac_cmd_stats_req {
	__le32 flags;
} __attribute__ ((packed));

struct iwm_umac_cmd_stop_resume_tx {
	u8 flags;
	u8 sta_id;
	__le16 stop_resume_tid_msk;
	__le16 last_seq_num[IWM_UMAC_TID_NR];
	u16 reserved;
} __attribute__ ((packed));

/* LMAC commands */
int iwm_read_mac(struct iwm_priv *iwm, u8 *mac);
int iwm_send_prio_table(struct iwm_priv *iwm);
@@ -478,6 +486,8 @@ int iwm_send_umac_channel_list(struct iwm_priv *iwm);
int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
		   int ssid_num);
int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len);
int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm,
				 struct iwm_umac_notif_stop_resume_tx *ntf);

/* UDMA commands */
int iwm_target_reset(struct iwm_priv *iwm);
+10 −0
Original line number Diff line number Diff line
@@ -131,11 +131,18 @@ struct iwm_notif {
	unsigned long buf_size;
};

struct iwm_tid_info {
	__le16 last_seq_num;
	bool stopped;
	struct mutex mutex;
};

struct iwm_sta_info {
	u8 addr[ETH_ALEN];
	bool valid;
	bool qos;
	u8 color;
	struct iwm_tid_info tid_info[IWM_UMAC_TID_NR];
};

struct iwm_tx_info {
@@ -185,6 +192,8 @@ struct iwm_key {
struct iwm_tx_queue {
	int id;
	struct sk_buff_head queue;
	struct sk_buff_head stopped_queue;
	spinlock_t lock;
	struct workqueue_struct *wq;
	struct work_struct worker;
	u8 concat_buf[IWM_HAL_CONCATENATE_BUF_SIZE];
@@ -341,6 +350,7 @@ int iwm_up(struct iwm_priv *iwm);
int iwm_down(struct iwm_priv *iwm);

/* TX API */
u16 iwm_tid_to_queue(u16 tid);
void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages);
void iwm_tx_worker(struct work_struct *work);
int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
+10 −1
Original line number Diff line number Diff line
@@ -248,7 +248,7 @@ static void iwm_watchdog(unsigned long data)

int iwm_priv_init(struct iwm_priv *iwm)
{
	int i;
	int i, j;
	char name[32];

	iwm->status = 0;
@@ -292,6 +292,8 @@ int iwm_priv_init(struct iwm_priv *iwm)
			return -EAGAIN;

		skb_queue_head_init(&iwm->txq[i].queue);
		skb_queue_head_init(&iwm->txq[i].stopped_queue);
		spin_lock_init(&iwm->txq[i].lock);
	}

	for (i = 0; i < IWM_NUM_KEYS; i++)
@@ -299,6 +301,12 @@ int iwm_priv_init(struct iwm_priv *iwm)

	iwm->default_key = -1;

	for (i = 0; i < IWM_STA_TABLE_NUM; i++)
		for (j = 0; j < IWM_UMAC_TID_NR; j++) {
			mutex_init(&iwm->sta_table[i].tid_info[j].mutex);
			iwm->sta_table[i].tid_info[j].stopped = false;
		}

	init_timer(&iwm->watchdog);
	iwm->watchdog.function = iwm_watchdog;
	iwm->watchdog.data = (unsigned long)iwm;
@@ -572,6 +580,7 @@ void iwm_link_off(struct iwm_priv *iwm)

	for (i = 0; i < IWM_TX_QUEUES; i++) {
		skb_queue_purge(&iwm->txq[i].queue);
		skb_queue_purge(&iwm->txq[i].stopped_queue);

		iwm->txq[i].concat_count = 0;
		iwm->txq[i].concat_ptr = iwm->txq[i].concat_buf;
+8 −0
Original line number Diff line number Diff line
@@ -76,6 +76,14 @@ static int iwm_stop(struct net_device *ndev)
 */
static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };

u16 iwm_tid_to_queue(u16 tid)
{
	if (tid > IWM_UMAC_TID_NR - 2)
		return -EINVAL;

	return iwm_1d_to_queue[tid];
}

static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb)
{
	skb->priority = cfg80211_classify8021d(skb);
Loading