diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-06-20 00:33:16 (GMT) |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-06-20 00:34:58 (GMT) |
commit | 95edd09ec3b15b165e2c7ba1e54cc508eafb2321 (patch) | |
tree | 7fb38c96bdc89f409e0ba5afcf1a703b01c482ca /drivers/staging/csr/unifi_pdu_processing.c | |
parent | 635d2b00e5070378e7bf812acf47fb135c6ab928 (diff) | |
download | linux-fsl-qoriq-95edd09ec3b15b165e2c7ba1e54cc508eafb2321.tar.xz |
Staging: csr: update to version 5.1.0 of the driver
This brings the in-kernel driver up to the level of the
csr-linux-wifi-5.1.0-oss.tar.gz tarball.
Cc: Mikko Virkkilä <mikko.virkkila@bluegiga.com>
Cc: Lauri Hintsala <Lauri.Hintsala@bluegiga.com>
Cc: Riku Mettälä <riku.mettala@bluegiga.com>
Cc: Veli-Pekka Peltola <veli-pekka.peltola@bluegiga.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/csr/unifi_pdu_processing.c')
-rw-r--r-- | drivers/staging/csr/unifi_pdu_processing.c | 1551 |
1 files changed, 787 insertions, 764 deletions
diff --git a/drivers/staging/csr/unifi_pdu_processing.c b/drivers/staging/csr/unifi_pdu_processing.c index 36b871e..e35747c 100644 --- a/drivers/staging/csr/unifi_pdu_processing.c +++ b/drivers/staging/csr/unifi_pdu_processing.c @@ -32,22 +32,23 @@ static void _update_buffered_pkt_params_after_alignment(unifi_priv_t *priv, bulk_data_param_t *bulkdata, tx_buffered_packets_t* buffered_pkt) { - struct sk_buff *skb ; CsrUint32 align_offset; if (priv == NULL || bulkdata == NULL || buffered_pkt == NULL){ return; } + skb = (struct sk_buff*)bulkdata->d[0].os_net_buf_ptr; align_offset = (CsrUint32)(long)(bulkdata->d[0].os_data_ptr) & (CSR_WIFI_ALIGN_BYTES-1); if(align_offset){ skb_pull(skb,align_offset); } - buffered_pkt->bulkdata.os_data_ptr = skb->data; - buffered_pkt->bulkdata.data_length = skb->len; - + buffered_pkt->bulkdata.os_data_ptr = bulkdata->d[0].os_data_ptr; + buffered_pkt->bulkdata.data_length = bulkdata->d[0].data_length; + buffered_pkt->bulkdata.os_net_buf_ptr = bulkdata->d[0].os_net_buf_ptr; + buffered_pkt->bulkdata.net_buf_length = bulkdata->d[0].net_buf_length; } #endif @@ -122,7 +123,7 @@ unifi_frame_ma_packet_req(unifi_priv_t *priv, CSR_PRIORITY priority, #ifdef CSR_SUPPORT_SME #define TRANSMISSION_CONTROL_TRIGGER_MASK 0x0001 -#define TRANSMISSION_CONTROL_ESOP_MASK 0x0002 +#define TRANSMISSION_CONTROL_EOSP_MASK 0x0002 static int frame_and_send_queued_pdu(unifi_priv_t* priv,tx_buffered_packets_t* buffered_pkt, @@ -167,34 +168,27 @@ int frame_and_send_queued_pdu(unifi_priv_t* priv,tx_buffered_packets_t* buffered case IEEE802_11_FC_TYPE_QOS_DATA & IEEE80211_FC_SUBTYPE_MASK: case IEEE802_11_FC_TYPE_QOS_NULL & IEEE80211_FC_SUBTYPE_MASK: /* If both are set then the Address4 exists (only for AP) */ - if (fromDs && toDs) - { + if (fromDs && toDs) { /* 6 is the size of Address4 field */ macHeaderLengthInBytes += (QOS_CONTROL_HEADER_SIZE + 6); - } - else - { + } else { macHeaderLengthInBytes += QOS_CONTROL_HEADER_SIZE; } /* If order bit set then HT control field is the part of MAC header */ if (*fc & cpu_to_le16(IEEE80211_FC_ORDER_MASK)) { macHeaderLengthInBytes += HT_CONTROL_HEADER_SIZE; + qc = (CsrUint8*)(buffered_pkt->bulkdata.os_data_ptr + (macHeaderLengthInBytes-6)); + } else { + qc = (CsrUint8*)(buffered_pkt->bulkdata.os_data_ptr + (macHeaderLengthInBytes-2)); } + *qc = eosp ? *qc | (1 << 4) : *qc & (~(1 << 4)); break; default: if (fromDs && toDs) macHeaderLengthInBytes += 6; - break; } - if (*fc & cpu_to_le16(IEEE80211_FC_ORDER_MASK)) { - qc = (CsrUint8*)(buffered_pkt->bulkdata.os_data_ptr + (macHeaderLengthInBytes-6)); - } else { - qc = (CsrUint8*)(buffered_pkt->bulkdata.os_data_ptr + (macHeaderLengthInBytes-2)); - } - - *qc = eosp ? *qc | (1 << 4) : *qc & (~(1 << 4)); } result = ul_send_signal_unpacked(priv, &signal, &bulkdata); if(result){ @@ -254,7 +248,7 @@ void set_eosp_transmit_ctrl(unifi_priv_t *priv, struct list_head *txList) spin_lock_irqsave(&priv->tx_q_lock,lock_flags); list_for_each_prev_safe(listHead, placeHolder, txList) { tx_q_item = list_entry(listHead, tx_buffered_packets_t, q); - tx_q_item->transmissionControl |= TRANSMISSION_CONTROL_ESOP_MASK; + tx_q_item->transmissionControl |= TRANSMISSION_CONTROL_EOSP_MASK; tx_q_item->transmissionControl = (tx_q_item->transmissionControl & ~(CSR_NO_CONFIRM_REQUIRED)); unifi_trace(priv, UDBG1, "set_eosp_transmit_ctrl Transmission Control = 0x%x hostTag = 0x%x \n",tx_q_item->transmissionControl,tx_q_item->hostTag); @@ -275,6 +269,8 @@ void send_vif_availibility_rsp(unifi_priv_t *priv,CSR_VIF_IDENTIFIER vif,CSR_RES bulk_data_param_t *bulkdata = NULL; int r; + unifi_trace(priv, UDBG3, "send_vif_availibility_rsp : invoked with resultCode = %d \n", resultCode); + memset(&signal,0,sizeof(CSR_SIGNAL)); rsp = &signal.u.MaVifAvailabilityResponse; rsp->VirtualInterfaceIdentifier = vif; @@ -288,6 +284,9 @@ void send_vif_availibility_rsp(unifi_priv_t *priv,CSR_VIF_IDENTIFIER vif,CSR_RES if(r) { unifi_error(priv,"Availibility response sending failed %x status %d\n",vif,r); } + else { + unifi_trace(priv, UDBG3, "send_vif_availibility_rsp : status = %d \n", r); + } } #endif @@ -354,14 +353,14 @@ void verify_and_accomodate_tx_packet(unifi_priv_t *priv) list_for_each_safe(listHead, placeHolder, &interfacePriv->genericMulticastOrBroadCastFrames) { tx_q_item = list_entry(listHead, tx_buffered_packets_t, q); if(eospFramedeleted){ - tx_q_item->transmissionControl |= TRANSMISSION_CONTROL_ESOP_MASK; + tx_q_item->transmissionControl |= TRANSMISSION_CONTROL_EOSP_MASK; tx_q_item->transmissionControl = (tx_q_item->transmissionControl & ~(CSR_NO_CONFIRM_REQUIRED)); unifi_trace(priv, UDBG1,"updating eosp for next packet hostTag:= 0x%x ",tx_q_item->hostTag); eospFramedeleted =0; break; } - if(tx_q_item->transmissionControl & TRANSMISSION_CONTROL_ESOP_MASK ){ + if(tx_q_item->transmissionControl & TRANSMISSION_CONTROL_EOSP_MASK ){ eospFramedeleted = 1; } unifi_trace(priv,UDBG1, "freeing of multicast packets ToC = 0x%x hostTag = 0x%x \n",tx_q_item->transmissionControl,tx_q_item->hostTag); @@ -445,66 +444,162 @@ CsrResult enque_tx_data_pdu(unifi_priv_t *priv, bulk_data_param_t *bulkdata, unifi_trace(priv, UDBG5, "leaving enque_tx_data_pdu\n"); return CSR_RESULT_SUCCESS; } -static -CsrResult enque_direceted_ma_pkt_cfm_data_pdu(unifi_priv_t *priv, bulk_data_param_t *bulkdata, - struct list_head *list, CSR_SIGNAL *signal, - CsrBool requeueOnSamePos) + +#ifdef CSR_WIFI_REQUEUE_PACKET_TO_HAL +CsrResult unifi_reque_ma_packet_request (void *ospriv, CsrUint32 host_tag, + CsrUint16 txStatus, bulk_data_desc_t *bulkDataDesc) { + CsrResult status = CSR_RESULT_SUCCESS; + unifi_priv_t *priv = (unifi_priv_t*)ospriv; + netInterface_priv_t *interfacePriv; + struct list_head *list = NULL; + CsrWifiRouterCtrlStaInfo_t *staRecord = NULL; + bulk_data_param_t bulkData; + CSR_SIGNAL signal; + CSR_PRIORITY priority = 0; + CsrUint16 interfaceTag = 0; + unifi_TrafficQueue priority_q; + CsrUint16 frameControl = 0, frameType = 0; + unsigned long lock_flags; - /* queue the tx data packets on to appropriate queue */ - CSR_MA_PACKET_REQUEST *req = &signal->u.MaPacketRequest; - tx_buffered_packets_t *tx_q_item; + interfacePriv = priv->interfacePriv[interfaceTag]; + /* If the current mode is not AP or P2PGO then just return failure + * to clear the hip slot + */ + if(!((interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP) || + (interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO))) { + return CSR_RESULT_FAILURE; + } - unifi_trace(priv, UDBG5, "entering enque_tx_data_pdu\n"); - if(!list ) { - unifi_error(priv,"List is not specified\n"); - return CSR_RESULT_FAILURE; + unifi_trace(priv, UDBG6, "unifi_reque_ma_packet_request: host_tag = 0x%x\n", host_tag); + + staRecord = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv, + (((CsrUint8 *) bulkDataDesc->os_data_ptr) + 4), + interfaceTag); + if (NULL == staRecord) { + unifi_trace(priv, UDBG5, "unifi_reque_ma_packet_request: Invalid STA record \n"); + return CSR_RESULT_FAILURE; } - if(!requeueOnSamePos && !list->prev){ - unifi_error(priv,"List prev is NULL so don't requeu it\n"); - return CSR_RESULT_FAILURE; + /* Update TIM if MA-PACKET.cfm fails with status as Tx-retry-limit or No-BSS and then just return failure + * to clear the hip slot associated with the Packet + */ + if (CSR_TX_RETRY_LIMIT == txStatus || CSR_TX_NO_BSS == txStatus) { + if (staRecord->timSet == CSR_WIFI_TIM_RESET || staRecord->timSet == CSR_WIFI_TIM_RESETTING) + { + unifi_trace(priv, UDBG2, "unifi_reque_ma_packet_request: CFM failed with Retry Limit or No BSS-->update TIM\n"); + if (!staRecord->timRequestPendingFlag) { + update_tim(priv, staRecord->aid, 1, interfaceTag, staRecord->assignedHandle); + } + else { + /* Cache the TimSet value so that it will processed immidiatly after + * completing the current setTim Request + */ + staRecord->updateTimReqQueued = 1; + unifi_trace(priv, UDBG6, "unifi_reque_ma_packet_request: One more UpdateTim Request(:%d)Queued for AID %x\n", + staRecord->updateTimReqQueued, staRecord->aid); + } + } + return CSR_RESULT_FAILURE; } + else if ((CSR_TX_LIFETIME == txStatus) || (CSR_TX_BLOCK_ACK_TIMEOUT == txStatus) || + (CSR_TX_FAIL_TRANSMISSION_VIF_INTERRUPTED == txStatus) || + (CSR_TX_REJECTED_PEER_STATION_SLEEPING == txStatus) || + (CSR_TX_REJECTED_DTIM_STARTED == txStatus)) { + /* Extract the Frame control and the frame type */ + frameControl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(bulkDataDesc->os_data_ptr); + frameType = ((frameControl & IEEE80211_FC_TYPE_MASK) >> FRAME_CONTROL_TYPE_FIELD_OFFSET); + /* Mgmt frames will not be re-queued for Tx + * so just return failure to clear the hip slot + */ + if (IEEE802_11_FRAMETYPE_MANAGEMENT == frameType) { + return CSR_RESULT_FAILURE; + } + else if (IEEE802_11_FRAMETYPE_DATA == frameType) { + /* QOS NULL and DATA NULL frames will not be re-queued for Tx + * so just return failure to clear the hip slot + */ + if ((((frameControl & IEEE80211_FC_SUBTYPE_MASK) >> FRAME_CONTROL_SUBTYPE_FIELD_OFFSET) == QOS_DATA_NULL) || + (((frameControl & IEEE80211_FC_SUBTYPE_MASK) >> FRAME_CONTROL_SUBTYPE_FIELD_OFFSET)== DATA_NULL )) { + return CSR_RESULT_FAILURE; + } + } + /* Extract the Packet priority */ + if (TRUE == staRecord->wmmOrQosEnabled) { + CsrUint16 qosControl = 0; + CsrUint8 dataFrameType = 0; - tx_q_item = (tx_buffered_packets_t *)kmalloc(sizeof(tx_buffered_packets_t), GFP_ATOMIC); - if (tx_q_item == NULL) { - unifi_error(priv, - "Failed to allocate %d bytes for tx packet record\n", - sizeof(tx_buffered_packets_t)); - func_exit(); - return CSR_RESULT_FAILURE; - } - /* disable the preemption */ - INIT_LIST_HEAD(&tx_q_item->q); - /* fill the tx_q structure members */ - tx_q_item->bulkdata.os_data_ptr = bulkdata->d[0].os_data_ptr; - tx_q_item->bulkdata.data_length = bulkdata->d[0].data_length; - tx_q_item->bulkdata.os_net_buf_ptr = bulkdata->d[0].os_net_buf_ptr; - tx_q_item->bulkdata.net_buf_length = bulkdata->d[0].net_buf_length; - tx_q_item->interfaceTag = req->VirtualInterfaceIdentifier & 0xff; - tx_q_item->hostTag = req->HostTag; - tx_q_item->leSenderProcessId = signal->SignalPrimitiveHeader.SenderProcessId; - tx_q_item->transmissionControl = req->TransmissionControl; - tx_q_item->priority = req->Priority; - tx_q_item->rate = req->TransmitRate; - memcpy(tx_q_item->peerMacAddress.a, req->Ra.x, ETH_ALEN); + dataFrameType =((frameControl & IEEE80211_FC_SUBTYPE_MASK) >> 4); + if (dataFrameType == QOS_DATA) { + /* QoS control field is offset from frame control by 2 (frame control) + * + 2 (duration/ID) + 2 (sequence control) + 3*ETH_ALEN or 4*ETH_ALEN + */ + if((frameControl & IEEE802_11_FC_TO_DS_MASK) && (frameControl & IEEE802_11_FC_FROM_DS_MASK)) { + qosControl= CSR_GET_UINT16_FROM_LITTLE_ENDIAN(bulkDataDesc->os_data_ptr + 30); + } + else { + qosControl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(bulkDataDesc->os_data_ptr + 24); + } + } + priority = (CSR_PRIORITY)(qosControl & IEEE802_11_QC_TID_MASK); - if (requeueOnSamePos) { - list_add(&tx_q_item->q, list); - } else { - list_add_tail(&tx_q_item->q, list); + if (priority < CSR_QOS_UP0 || priority > CSR_QOS_UP7) { + unifi_trace(priv, UDBG5, "unifi_reque_ma_packet_request: Invalid priority:%x \n", priority); + return CSR_RESULT_FAILURE; + } + } + else { + priority = CSR_CONTENTION; + } + + /* Frame Bulk data to requeue it back to HAL Queues */ + bulkData.d[0].os_data_ptr = bulkDataDesc->os_data_ptr; + bulkData.d[0].data_length = bulkDataDesc->data_length; + bulkData.d[0].os_net_buf_ptr = bulkDataDesc->os_net_buf_ptr; + bulkData.d[0].net_buf_length = bulkDataDesc->net_buf_length; + + bulkData.d[1].os_data_ptr = NULL; + bulkData.d[1].os_net_buf_ptr = NULL; + bulkData.d[1].data_length = bulkData.d[1].net_buf_length = 0; + + /* Initialize signal to zero */ + memset(&signal, 0, sizeof(CSR_SIGNAL)); + + /* Frame MA Packet Req */ + unifi_frame_ma_packet_req(priv, priority, 0, host_tag, + interfaceTag, CSR_NO_CONFIRM_REQUIRED, + priv->netdev_client->sender_id, + staRecord->peerMacAddress.a, &signal); + + /* Find the Q-Priority */ + priority_q = unifi_frame_priority_to_queue(priority); + list = &staRecord->dataPdu[priority_q]; + + /* Place the Packet on to HAL Queue */ + status = enque_tx_data_pdu(priv, &bulkData, list, &signal, TRUE); + + /* Update the Per-station queued packet counter */ + if (!status) { + spin_lock_irqsave(&priv->staRecord_lock, lock_flags); + staRecord->noOfPktQueued++; + spin_unlock_irqrestore(&priv->staRecord_lock, lock_flags); + } + } + else { + /* Packet will not be re-queued for any of the other MA Packet Tx failure + * reasons so just return failure to clear the hip slot + */ + return CSR_RESULT_FAILURE; } - /* Count of packet queued in driver */ - priv->noOfPktQueuedInDriver++; - unifi_trace(priv, UDBG5, "leaving enque_tx_data_pdu\n"); - return CSR_RESULT_SUCCESS; + return status; } +#endif static void is_all_ac_deliver_enabled_and_moredata(CsrWifiRouterCtrlStaInfo_t *staRecord, CsrUint8 *allDeliveryEnabled, CsrUint8 *dataAvailable) { @@ -601,12 +696,53 @@ void uf_handle_tim_cfm(unifi_priv_t *priv, CSR_MLME_SET_TIM_CONFIRM *cfm, CsrUin unifi_trace(priv, UDBG3, "receiver processID = %x, success: request & confirm states are not matching in TIM cfm: Debug status = %x, staRecord->timSet = %x, handle = %x\n", receiverProcessId, timSetStatus, staRecord->timSet, handle); } + + /* Reset TIM pending flag to send next TIM request */ + staRecord->timRequestPendingFlag = FALSE; + + /* Make sure that one more UpdateTim request is queued, if Queued its value + * should be CSR_WIFI_TIM_SET or CSR_WIFI_TIM_RESET + */ + if (0xFF != staRecord->updateTimReqQueued) + { + /* Process the UpdateTim Request which is queued while previous UpdateTim was in progress */ + if (staRecord->timSet != staRecord->updateTimReqQueued) + { + unifi_trace(priv, UDBG2, "uf_handle_tim_cfm : Processing Queued UpdateTimReq \n"); + + update_tim(priv, staRecord->aid, staRecord->updateTimReqQueued, interfaceTag, handle); + + staRecord->updateTimReqQueued = 0xFF; + } + } } else { + + interfacePriv->bcTimSet = timSetValue; /* fh_cmd_q can also be full at some point of time!, * resetting count as queue is cleaned by firmware at this point */ retryCount = 0; unifi_trace(priv, UDBG3, "tim (%s) successfully for broadcast frame in firmware\n", (timSetValue)?"SET":"RESET"); + + /* Reset DTIM pending flag to send next DTIM request */ + interfacePriv->bcTimSetReqPendingFlag = FALSE; + + /* Make sure that one more UpdateDTim request is queued, if Queued its value + * should be CSR_WIFI_TIM_SET or CSR_WIFI_TIM_RESET + */ + if (0xFF != interfacePriv->bcTimSetReqQueued) + { + /* Process the UpdateTim Request which is queued while previous UpdateTim was in progress */ + if (interfacePriv->bcTimSet != interfacePriv->bcTimSetReqQueued) + { + unifi_trace(priv, UDBG2, "uf_handle_tim_cfm : Processing Queued UpdateDTimReq \n"); + + update_tim(priv, 0, interfacePriv->bcTimSetReqQueued, interfaceTag, 0xFFFFFFFF); + + interfacePriv->bcTimSetReqQueued = 0xFF; + } + } + } break; case CSR_RC_INVALID_PARAMETERS: @@ -684,6 +820,7 @@ void uf_handle_tim_cfm(unifi_priv_t *priv, CSR_MLME_SET_TIM_CONFIRM *cfm, CsrUin default: unifi_warning(priv, "tim update request failed resultcode = %x\n", cfm->ResultCode); } + unifi_trace(priv, UDBG2, "leaving %s\n", __FUNCTION__); } @@ -733,8 +870,14 @@ void update_tim(unifi_priv_t * priv, CsrUint16 aid, CsrUint8 setTim, CsrUint16 i unifi_trace(priv, UDBG5, "entering the update_tim routine\n"); + if (handle == 0xFFFFFFFF) { handle &= CSR_WIFI_BROADCAST_OR_MULTICAST_HANDLE; + if (setTim == interfacePriv->bcTimSet) + { + unifi_trace(priv, UDBG3, "update_tim, Drop:Hdl=%x, timval=%d, globalTim=%d\n", handle, setTim, interfacePriv->bcTimSet); + return; + } } else if ((handle != 0xFFFFFFFF) && (handle >= UNIFI_MAX_CONNECTIONS)) { unifi_warning(priv, "bad station Handle = %x\n", handle); return; @@ -785,6 +928,25 @@ void update_tim(unifi_priv_t * priv, CsrUint16 aid, CsrUint8 setTim, CsrUint16 i if (staRecord) { staRecord->timSet = oldTimSetStatus ; } + else + { + /* MLME_SET_TIM.req sending failed here for AID0, so revert back our bcTimSet status */ + interfacePriv->bcTimSet = !setTim; + } + } + else { + /* Update tim request pending flag and ensure no more TIM set requests are send + for the same station until TIM confirm is received */ + if (staRecord) { + staRecord->timRequestPendingFlag = TRUE; + } + else + { + /* Update tim request (for AID 0) pending flag and ensure no more DTIM set requests are send + * for the same station until TIM confirm is received + */ + interfacePriv->bcTimSetReqPendingFlag = TRUE; + } } unifi_trace(priv, UDBG5, "leaving the update_tim routine\n"); } @@ -804,12 +966,30 @@ void process_peer_active_transition(unifi_priv_t * priv, if(IS_DTIM_ACTIVE(interfacePriv->dtimActive,interfacePriv->multicastPduHostTag)) { /* giving more priority to multicast packets so delaying unicast packets*/ - unifi_trace(priv,UDBG2," multicast transmission is going on so resume unicast transmission after DTIM over\n"); + unifi_trace(priv,UDBG2, "Multicast transmission is going on so resume unicast transmission after DTIM over\n"); + + /* As station is active now, even though AP is not able to send frames to it + * because of DTIM, it needs to reset the TIM here + */ + if (!staRecord->timRequestPendingFlag){ + if((staRecord->timSet == CSR_WIFI_TIM_SET) || (staRecord->timSet == CSR_WIFI_TIM_SETTING)){ + update_tim(priv, staRecord->aid, 0, interfaceTag, staRecord->assignedHandle); + } + } + else + { + /* Cache the TimSet value so that it will processed immidiatly after + * completing the current setTim Request + */ + staRecord->updateTimReqQueued = 0; + unifi_trace(priv, UDBG6, "update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x\n", staRecord->updateTimReqQueued, + staRecord->aid); + } return; } while((buffered_pkt=dequeue_tx_data_pdu(priv, &staRecord->mgtFrames))) { buffered_pkt->transmissionControl &= - ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_ESOP_MASK); + ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_EOSP_MASK); if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staRecord,0,FALSE)) == -ENOSPC) { unifi_trace(priv, UDBG2, "p_p_a_t:(ENOSPC) Mgt Frame queueing \n"); /* Enqueue at the head of the queue */ @@ -828,11 +1008,22 @@ void process_peer_active_transition(unifi_priv_t * priv, kfree(buffered_pkt); } } - if (staRecord->txSuspend) { - if(staRecord->timSet == CSR_WIFI_TIM_SET) { - update_tim(priv,staRecord->aid,0,interfaceTag, staRecord->assignedHandle); + if (!staRecord->timRequestPendingFlag) { + if (staRecord->txSuspend) { + if(staRecord->timSet == CSR_WIFI_TIM_SET) { + update_tim(priv,staRecord->aid,0,interfaceTag, staRecord->assignedHandle); + } + return; } - return; + } + else + { + /* Cache the TimSet value so that it will processed immidiatly after + * completing the current setTim Request + */ + staRecord->updateTimReqQueued = 0; + unifi_trace(priv, UDBG6, "update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x\n", staRecord->updateTimReqQueued, + staRecord->aid); } for(i=3;i>=0;i--) { if(!spaceAvail[i]) @@ -840,7 +1031,7 @@ void process_peer_active_transition(unifi_priv_t * priv, unifi_trace(priv, UDBG6, "p_p_a_t:data pkt sending for AC %d \n",i); while((buffered_pkt=dequeue_tx_data_pdu(priv, &staRecord->dataPdu[i]))) { buffered_pkt->transmissionControl &= - ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_ESOP_MASK); + ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_EOSP_MASK); if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staRecord,0,FALSE)) == -ENOSPC) { /* Clear the trigger bit transmission control*/ /* Enqueue at the head of the queue */ @@ -859,9 +1050,20 @@ void process_peer_active_transition(unifi_priv_t * priv, } } } - if((staRecord->timSet == CSR_WIFI_TIM_SET) || (staRecord->timSet == CSR_WIFI_TIM_SETTING)){ - unifi_trace(priv, UDBG3, "p_p_a_t:resetting tim .....\n"); - update_tim(priv,staRecord->aid,0,interfaceTag, staRecord->assignedHandle); + if (!staRecord->timRequestPendingFlag){ + if((staRecord->timSet == CSR_WIFI_TIM_SET) || (staRecord->timSet == CSR_WIFI_TIM_SETTING)) { + unifi_trace(priv, UDBG3, "p_p_a_t:resetting tim .....\n"); + update_tim(priv,staRecord->aid,0,interfaceTag, staRecord->assignedHandle); + } + } + else + { + /* Cache the TimSet value so that it will processed immidiatly after + * completing the current setTim Request + */ + staRecord->updateTimReqQueued = 0; + unifi_trace(priv, UDBG6, "update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x\n", staRecord->updateTimReqQueued, + staRecord->aid); } unifi_trace(priv, UDBG5, "leaving process_peer_active_transition\n"); } @@ -873,14 +1075,6 @@ void uf_process_ma_pkt_cfm_for_ap(unifi_priv_t *priv,CsrUint16 interfaceTag, con netInterface_priv_t *interfacePriv; CsrUint8 i; CsrWifiRouterCtrlStaInfo_t *staRecord = NULL; - struct list_head *listHeadMaPktreq,*listHeadStaQueue; - struct list_head *placeHolderMaPktreq,*placeHolderStaQueue; - unsigned long lock_flags; - unsigned long lock_flags1; - maPktReqList_t *maPktreq = NULL; - tx_buffered_packets_t *tx_q_item = NULL; - bulk_data_param_t bulkdata; - CsrBool entryFound = FALSE; interfacePriv = priv->interfacePriv[interfaceTag]; @@ -892,260 +1086,113 @@ void uf_process_ma_pkt_cfm_for_ap(unifi_priv_t *priv,CsrUint16 interfaceTag, con if(list_empty(&interfacePriv->genericMulticastOrBroadCastMgtFrames) && list_empty(&interfacePriv->genericMulticastOrBroadCastFrames)) { unifi_trace(priv,UDBG1,"Resetting multicastTIM"); - update_tim(priv,0,0,interfaceTag, 0xFFFFFFFF); - } - return; - } - - /* Check if a copy of the same frame (identified by host tag) is queued in driver */ - spin_lock_irqsave(&priv->tx_q_lock,lock_flags); - list_for_each_safe(listHeadMaPktreq, placeHolderMaPktreq, &interfacePriv->directedMaPktReq) { - maPktreq = list_entry(listHeadMaPktreq, maPktReqList_t, q); - if(maPktreq->hostTag == pkt_cfm->HostTag){ - entryFound = TRUE; - break; - } - } - spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags); - - if(entryFound){ - - /* Monitor the time difference between the MA-PACKET.req and MA-PACKET.cfm */ - unsigned long timeout; - timeout = (long)jiffies - (long)maPktreq->jiffeTime; - - /* convert into milliseconds */ - timeout = jiffies_to_msecs(timeout); - unifi_trace(priv, UDBG3, "Jiffies Time: Host Tag(%x) --> Req(%u) Cfm(%u) Diff (in ms): %u\n",maPktreq->hostTag,maPktreq->jiffeTime, jiffies, timeout); - - if( (timeout/1000) > 1) - { - unifi_trace(priv, UDBG1, "Confirm time > 2 Seconds: time = %u Status = %x\n", (timeout/1000), pkt_cfm->TransmissionStatus); - } - - if( CSR_TX_LIFETIME == pkt_cfm->TransmissionStatus || - CSR_TX_BLOCK_ACK_TIMEOUT== pkt_cfm->TransmissionStatus || - CSR_TX_FAIL_TRANSMISSION_VIF_INTERRUPTED== pkt_cfm->TransmissionStatus || - CSR_TX_REJECTED_PEER_STATION_SLEEPING== pkt_cfm->TransmissionStatus || - CSR_TX_REJECTED_DTIM_STARTED== pkt_cfm->TransmissionStatus ){ - - CsrWifiRouterCtrlStaInfo_t *staRecord = interfacePriv->staInfo[maPktreq->staHandler]; - unifi_TrafficQueue priority_q; - struct list_head *list; - CsrResult result; - CSR_MA_PACKET_REQUEST *req = &maPktreq->signal.u.MaPacketRequest; - CsrUint16 ii=0; - CsrBool locationFound = FALSE; - CsrUint8 *sigbuffer; - - sigbuffer = (CsrUint8*)&maPktreq->signal; - if(req->Priority == CSR_MANAGEMENT){ - list = &staRecord->mgtFrames; - unifi_trace(priv,UDBG5,"mgmt list priority %d\n",req->Priority); - } - else{ - priority_q= unifi_frame_priority_to_queue(req->Priority); - list = &staRecord->dataPdu[priority_q]; - unifi_trace(priv,UDBG5,"data list priority %d\n",req->Priority); - } - - spin_lock_irqsave(&priv->tx_q_lock,lock_flags); - list_for_each_safe(listHeadStaQueue, placeHolderStaQueue, list){ - tx_q_item = list_entry(listHeadStaQueue, tx_buffered_packets_t, q); - COMPARE_HOST_TAG_TO_ENQUEUE(tx_q_item->hostTag ,maPktreq->hostTag) - - - } - if(sigbuffer[SIZEOF_SIGNAL_HEADER + 1]){ - skb_pull(maPktreq->skb,sigbuffer[SIZEOF_SIGNAL_HEADER + 1]); - } - - /* enqueue the failed packet sta queue*/ - bulkdata.d[0].os_net_buf_ptr= (unsigned char*)maPktreq->skb; - bulkdata.d[0].os_data_ptr = maPktreq->skb->data; - bulkdata.d[0].data_length = bulkdata.d[0].net_buf_length = maPktreq->skb->len; - bulkdata.d[1].os_data_ptr = NULL; - bulkdata.d[1].os_net_buf_ptr = NULL; - bulkdata.d[1].data_length = bulkdata.d[0].net_buf_length = 0; - unifi_trace(priv,UDBG4,"Cfm Fail for HosTag = %x with status %d so requeue it\n",maPktreq->hostTag,pkt_cfm->TransmissionStatus ); - req->TransmissionControl = 0; - - if(!locationFound){ - - if(list_empty(list)){ - result = enque_direceted_ma_pkt_cfm_data_pdu(priv, &bulkdata, list,&maPktreq->signal,1); - } - else{ - unifi_trace(priv,UDBG4,"did not find location so add to end of list \n"); - result = enque_direceted_ma_pkt_cfm_data_pdu(priv, &bulkdata, list,&maPktreq->signal,0); - } - - - } - - else { - if(ii > 1){ - unifi_trace(priv,UDBG4,"find the location in the middle of list \n"); - result = enque_direceted_ma_pkt_cfm_data_pdu(priv, &bulkdata, listHeadStaQueue,&maPktreq->signal,0); - - } - else{ - unifi_trace(priv,UDBG4," add at begining of list \n"); - result = enque_direceted_ma_pkt_cfm_data_pdu(priv, &bulkdata, list,&maPktreq->signal,1); + if (!interfacePriv->bcTimSetReqPendingFlag) + { + update_tim(priv,0,CSR_WIFI_TIM_RESET,interfaceTag, 0xFFFFFFFF); } - } - - spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags); - - /* Increment the counter */ - spin_lock_irqsave(&priv->staRecord_lock,lock_flags1); - staRecord->noOfPktQueued++; - spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags1); - - - - - /* after enqueuing update the TIM */ - if(CSR_RESULT_SUCCESS == result){ - if(CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE == staRecord->currentPeerState) { - if(staRecord->timSet == CSR_WIFI_TIM_RESET || staRecord->timSet == CSR_WIFI_TIM_RESETTING) { - if(!staRecord->wmmOrQosEnabled) { - unifi_trace(priv, UDBG3, "uf_process_ma_pkt_cfm_for_ap :tim set due to unicast pkt & peer in powersave\n"); - update_tim(priv,staRecord->aid,1,interfaceTag, staRecord->assignedHandle); - } - else { - /* Check for non delivery enable(i.e trigger enable), all delivery enable & legacy AC for TIM update in firmware */ - CsrUint8 allDeliveryEnabled = 0, dataAvailable = 0; - /* Check if all AC's are Delivery Enabled */ - is_all_ac_deliver_enabled_and_moredata(staRecord, &allDeliveryEnabled, &dataAvailable); - if (uf_is_more_data_for_non_delivery_ac(staRecord) || (allDeliveryEnabled && dataAvailable)) { - update_tim(priv,staRecord->aid,1,interfaceTag, staRecord->assignedHandle); - } - } - } - } - } - else{ - dev_kfree_skb(maPktreq->skb); - } - } - else - { - CsrWifiRouterCtrlStaInfo_t *staRecord = interfacePriv->staInfo[maPktreq->staHandler]; - if (CSR_TX_RETRY_LIMIT == pkt_cfm->TransmissionStatus || - CSR_TX_NO_BSS == pkt_cfm->TransmissionStatus) - { - if (staRecord->timSet == CSR_WIFI_TIM_RESET || staRecord->timSet == CSR_WIFI_TIM_RESETTING) + else { - unifi_trace(priv, UDBG2, "CFM failed with Retry Limit or No BSS --> update TIM\n"); - update_tim(priv, staRecord->aid, 1, interfaceTag, staRecord->assignedHandle); + /* Cache the DTimSet value so that it will processed immidiatly after + * completing the current setDTim Request + */ + interfacePriv->bcTimSetReqQueued = CSR_WIFI_TIM_RESET; + unifi_trace(priv, UDBG2, "uf_process_ma_pkt_cfm_for_ap : One more UpdateDTim Request(%d) Queued \n", + interfacePriv->bcTimSetReqQueued); } + } - else if (CSR_TX_SUCCESSFUL == pkt_cfm->TransmissionStatus) - { - staRecord->activity_flag = TRUE; - } - unifi_trace(priv, UDBG5, "CFM for HosTag = %x Status = %d, Free SKB reference\n", - maPktreq->hostTag, - pkt_cfm->TransmissionStatus ); + return; + } - dev_kfree_skb(maPktreq->skb); + /* Check if it is a Confirm for null data frame used + * for probing station activity + */ + for(i =0; i < UNIFI_MAX_CONNECTIONS; i++) { + staRecord = (CsrWifiRouterCtrlStaInfo_t *) (interfacePriv->staInfo[i]); + if (staRecord && (staRecord->nullDataHostTag == pkt_cfm->HostTag)) { + + unifi_trace(priv, UDBG1, "CFM for Inactive probe Null frame (tag = %x, status = %d)\n", + pkt_cfm->HostTag, + pkt_cfm->TransmissionStatus + ); + staRecord->nullDataHostTag = INVALID_HOST_TAG; + + if(pkt_cfm->TransmissionStatus == CSR_TX_RETRY_LIMIT){ + CsrTime now; + CsrTime inactive_time; + + unifi_trace(priv, UDBG1, "Nulldata to probe STA ALIVE Failed with retry limit\n"); + /* Recheck if there is some activity after null data is sent. + * + * If still there is no activity then send a disconnected indication + * to SME to delete the station record. + */ + if (staRecord->activity_flag){ + return; + } + now = CsrTimeGet(NULL); - } - list_del(listHeadMaPktreq); - kfree(maPktreq); + if (staRecord->lastActivity > now) + { + /* simple timer wrap (for 1 wrap) */ + inactive_time = CsrTimeAdd((CsrTime)CsrTimeSub(CSR_SCHED_TIME_MAX, staRecord->lastActivity), + now); + } + else + { + inactive_time = (CsrTime)CsrTimeSub(now, staRecord->lastActivity); + } - }else{ - /* Check if it is a Confirm for null data frame used - * for probing station activity - */ - for(i =0; i < UNIFI_MAX_CONNECTIONS; i++) { - staRecord = (CsrWifiRouterCtrlStaInfo_t *) (interfacePriv->staInfo[i]); - if (staRecord && (staRecord->nullDataHostTag == pkt_cfm->HostTag)) { - - unifi_trace(priv, UDBG1, "CFM for Inactive probe Null frame (tag = %x, status = %d)\n", - pkt_cfm->HostTag, - pkt_cfm->TransmissionStatus - ); - staRecord->nullDataHostTag = INVALID_HOST_TAG; - - if(pkt_cfm->TransmissionStatus == CSR_TX_RETRY_LIMIT){ - CsrTime now; - CsrTime inactive_time; - - unifi_trace(priv, UDBG1, "Nulldata to probe STA ALIVE Failed with retry limit\n"); - /* Recheck if there is some activity after null data is sent. - * - * If still there is no activity then send a disconnected indication - * to SME to delete the station record. - */ - if (staRecord->activity_flag){ - return; - } - now = CsrTimeGet(NULL); + if (inactive_time >= STA_INACTIVE_TIMEOUT_VAL) + { + struct list_head send_cfm_list; + CsrUint8 j; + + /* The SME/NME may be waiting for confirmation for requested frames to this station. + * Though this is --VERY UNLIKELY-- in case of station in active mode. But still as a + * a defensive check, it loops through buffered frames for this station and if confirmation + * is requested, send auto confirmation with failure status. Also flush the frames so + * that these are not processed again in PEER_DEL_REQ handler. + */ + INIT_LIST_HEAD(&send_cfm_list); - if (staRecord->lastActivity > now) - { - /* simple timer wrap (for 1 wrap) */ - inactive_time = CsrTimeAdd((CsrTime)CsrTimeSub(CSR_SCHED_TIME_MAX, staRecord->lastActivity), - now); - } - else - { - inactive_time = (CsrTime)CsrTimeSub(now, staRecord->lastActivity); - } + uf_prepare_send_cfm_list_for_queued_pkts(priv, + &send_cfm_list, + &(staRecord->mgtFrames)); - if (inactive_time >= STA_INACTIVE_TIMEOUT_VAL) - { - struct list_head send_cfm_list; - CsrUint8 j; - - /* The SME/NME may be waiting for confirmation for requested frames to this station. - * Though this is --VERY UNLIKELY-- in case of station in active mode. But still as a - * a defensive check, it loops through buffered frames for this station and if confirmation - * is requested, send auto confirmation with failure status. Also flush the frames so - * that these are not processed again in PEER_DEL_REQ handler. - */ - INIT_LIST_HEAD(&send_cfm_list); + uf_flush_list(priv, &(staRecord->mgtFrames)); + for(j = 0; j < MAX_ACCESS_CATOGORY; j++){ uf_prepare_send_cfm_list_for_queued_pkts(priv, &send_cfm_list, - &(staRecord->mgtFrames)); - - uf_flush_list(priv, &(staRecord->mgtFrames)); + &(staRecord->dataPdu[j])); - for(j = 0; j < MAX_ACCESS_CATOGORY; j++){ - uf_prepare_send_cfm_list_for_queued_pkts(priv, - &send_cfm_list, - &(staRecord->dataPdu[j])); - - uf_flush_list(priv,&(staRecord->dataPdu[j])); - } - - send_auto_ma_packet_confirm(priv, staRecord->interfacePriv, &send_cfm_list); + uf_flush_list(priv,&(staRecord->dataPdu[j])); + } + send_auto_ma_packet_confirm(priv, staRecord->interfacePriv, &send_cfm_list); - unifi_warning(priv, "uf_process_ma_pkt_cfm_for_ap: Router Disconnected IND Peer (%x-%x-%x-%x-%x-%x)\n", - staRecord->peerMacAddress.a[0], - staRecord->peerMacAddress.a[1], - staRecord->peerMacAddress.a[2], - staRecord->peerMacAddress.a[3], - staRecord->peerMacAddress.a[4], - staRecord->peerMacAddress.a[5]); - CsrWifiRouterCtrlConnectedIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, - 0, - staRecord->interfacePriv->InterfaceTag, - staRecord->peerMacAddress, - CSR_WIFI_ROUTER_CTRL_PEER_DISCONNECTED); - } + unifi_warning(priv, "uf_process_ma_pkt_cfm_for_ap: Router Disconnected IND Peer (%x-%x-%x-%x-%x-%x)\n", + staRecord->peerMacAddress.a[0], + staRecord->peerMacAddress.a[1], + staRecord->peerMacAddress.a[2], + staRecord->peerMacAddress.a[3], + staRecord->peerMacAddress.a[4], + staRecord->peerMacAddress.a[5]); + CsrWifiRouterCtrlConnectedIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, + 0, + staRecord->interfacePriv->InterfaceTag, + staRecord->peerMacAddress, + CSR_WIFI_ROUTER_CTRL_PEER_DISCONNECTED); } - else if (pkt_cfm->TransmissionStatus == CSR_TX_SUCCESSFUL) - { - staRecord->activity_flag = TRUE; - } + + } + else if (pkt_cfm->TransmissionStatus == CSR_TX_SUCCESSFUL) + { + staRecord->activity_flag = TRUE; } } } @@ -1336,16 +1383,16 @@ static int update_macheader(unifi_priv_t *priv, struct sk_buff *skb, CsrResult csrResult; unifi_trace(priv, UDBG5, "normal Data packet, NO QOS \n"); - *priority = CSR_CONTENTION; if (qosDestination) { CsrUint8 qc = 0; unifi_trace(priv, UDBG3, "destination is QOS station \n"); - /* prepare the qos control field */ - qc |= CSR_QOS_UP0; + /* Set Ma-Packet.req UP to UP0 */ + *priority = CSR_QOS_UP0; + /* prepare the qos control field */ + qc |= CSR_QOS_UP0; /* no Amsdu is in ap buffer so eosp is left 0 */ - if (da[0] & 0x1) { /* multicast/broadcast frames, no acknowledgement needed */ qc |= 1 << 5; @@ -1763,9 +1810,6 @@ CsrResult uf_process_ma_packet_req(unifi_priv_t *priv, */ list = &interfacePriv->genericMulticastOrBroadCastMgtFrames; - spin_lock_irqsave(&priv->staRecord_lock,lock_flags); - interfacePriv->noOfbroadcastPktQueued++; - spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags); if((interfacePriv->interfaceMode != CSR_WIFI_ROUTER_CTRL_MODE_IBSS) && (list_empty(&interfacePriv->genericMulticastOrBroadCastMgtFrames))) { setBcTim=TRUE; @@ -1789,11 +1833,9 @@ CsrResult uf_process_ma_packet_req(unifi_priv_t *priv, /* if multicast traffic is going on, buffet the unicast packets */ unifi_trace(priv, UDBG2, "Enqueued to staRecord->dataPdu[%d] queuePacketDozing=%d,\ Buffering enabled = %d \n", priority_q,queuePacketDozing,isRouterBufferEnabled(priv,priority_q)); - signal.u.MaPacketRequest.TransmissionControl &= ~(CSR_NO_CONFIRM_REQUIRED); list = &staRecord->dataPdu[priority_q]; } else { unifi_trace(priv, UDBG5, "staRecord->dataPdu[%d] list is empty uf_process_ma_packet_req \n", priority_q); - signal.u.MaPacketRequest.TransmissionControl &= ~(CSR_NO_CONFIRM_REQUIRED); /* Pdu allowed to send to unifi */ result = ul_send_signal_unpacked(priv, &signal, bulkdata); if(result == -ENOSPC) { @@ -1816,9 +1858,6 @@ CsrResult uf_process_ma_packet_req(unifi_priv_t *priv, * will be sent when we receive VIF AVAILABILITY from firmware as part of DTIM */ list = &interfacePriv->genericMulticastOrBroadCastFrames; - spin_lock_irqsave(&priv->staRecord_lock,lock_flags); - interfacePriv->noOfbroadcastPktQueued++; - spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags); if(list_empty(&interfacePriv->genericMulticastOrBroadCastFrames)) { setBcTim = TRUE; } @@ -1838,10 +1877,30 @@ CsrResult uf_process_ma_packet_req(unifi_priv_t *priv, staRecord->noOfPktQueued++; spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags); } + else if ((pktType == CSR_WIFI_MULTICAST_PDU) && (!status)) + { + /* If broadcast Tim is set && queuing is successfull, then only update TIM */ + spin_lock_irqsave(&priv->staRecord_lock,lock_flags); + interfacePriv->noOfbroadcastPktQueued++; + spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags); + } } - if(setBcTim) { + /* If broadcast Tim is set && queuing is successfull, then only update TIM */ + if(setBcTim && !status) { unifi_trace(priv, UDBG3, "tim set due to broadcast pkt\n"); - update_tim(priv,0,1,interfaceTag, handle); + if (!interfacePriv->bcTimSetReqPendingFlag) + { + update_tim(priv,0,CSR_WIFI_TIM_SET,interfaceTag, handle); + } + else + { + /* Cache the TimSet value so that it will processed immidiatly after + * completing the current setTim Request + */ + interfacePriv->bcTimSetReqQueued = CSR_WIFI_TIM_SET; + unifi_trace(priv, UDBG2, "uf_process_ma_packet_req : One more UpdateDTim Request(:%d) Queued \n", + interfacePriv->bcTimSetReqQueued); + } } else if(staRecord && staRecord->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE) { if(staRecord->timSet == CSR_WIFI_TIM_RESET || staRecord->timSet == CSR_WIFI_TIM_RESETTING) { @@ -1850,15 +1909,38 @@ CsrResult uf_process_ma_packet_req(unifi_priv_t *priv, !list_empty(&staRecord->dataPdu[3]) || !list_empty(&staRecord->dataPdu[UNIFI_TRAFFIC_Q_CONTENTION])) { unifi_trace(priv, UDBG3, "tim set due to unicast pkt & peer in powersave\n"); - update_tim(priv,staRecord->aid,1,interfaceTag, handle); + if (!staRecord->timRequestPendingFlag){ + update_tim(priv,staRecord->aid,1,interfaceTag, handle); + } + else + { + /* Cache the TimSet value so that it will processed immidiatly after + * completing the current setTim Request + */ + staRecord->updateTimReqQueued = 1; + unifi_trace(priv, UDBG6, "update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x\n", staRecord->updateTimReqQueued, + staRecord->aid); + } } } else { /* Check for non delivery enable(i.e trigger enable), all delivery enable & legacy AC for TIM update in firmware */ CsrUint8 allDeliveryEnabled = 0, dataAvailable = 0; /* Check if all AC's are Delivery Enabled */ is_all_ac_deliver_enabled_and_moredata(staRecord, &allDeliveryEnabled, &dataAvailable); - if (uf_is_more_data_for_non_delivery_ac(staRecord) || (allDeliveryEnabled && dataAvailable)) { - update_tim(priv,staRecord->aid,1,interfaceTag, handle); + if (uf_is_more_data_for_non_delivery_ac(staRecord) || (allDeliveryEnabled && dataAvailable) + || (!list_empty(&staRecord->mgtFrames))) { + if (!staRecord->timRequestPendingFlag) { + update_tim(priv,staRecord->aid,1,interfaceTag, handle); + } + else + { + /* Cache the TimSet value so that it will processed immidiatly after + * completing the current setTim Request + */ + staRecord->updateTimReqQueued = 1; + unifi_trace(priv, UDBG6, "update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x\n", staRecord->updateTimReqQueued, + staRecord->aid); + } } } } @@ -1945,7 +2027,7 @@ CsrUint8 send_multicast_frames(unifi_priv_t *priv, CsrUint16 interfaceTag) if(!isRouterBufferEnabled(priv,UNIFI_TRAFFIC_Q_VO)) { while((interfacePriv->dtimActive)&& (buffered_pkt=dequeue_tx_data_pdu(priv,&interfacePriv->genericMulticastOrBroadCastMgtFrames))) { buffered_pkt->transmissionControl |= (TRANSMISSION_CONTROL_TRIGGER_MASK); - moreData = (buffered_pkt->transmissionControl & TRANSMISSION_CONTROL_ESOP_MASK)?FALSE:TRUE; + moreData = (buffered_pkt->transmissionControl & TRANSMISSION_CONTROL_EOSP_MASK)?FALSE:TRUE; unifi_trace(priv,UDBG2,"DTIM Occurred for interface:sending Mgt packet %d\n",interfaceTag); @@ -1986,7 +2068,7 @@ CsrUint8 send_multicast_frames(unifi_priv_t *priv, CsrUint16 interfaceTag) if(!isRouterBufferEnabled(priv,UNIFI_TRAFFIC_Q_CONTENTION)) { while((interfacePriv->dtimActive)&& (buffered_pkt=dequeue_tx_data_pdu(priv,&interfacePriv->genericMulticastOrBroadCastFrames))) { buffered_pkt->transmissionControl |= TRANSMISSION_CONTROL_TRIGGER_MASK; - moreData = (buffered_pkt->transmissionControl & TRANSMISSION_CONTROL_ESOP_MASK)?FALSE:TRUE; + moreData = (buffered_pkt->transmissionControl & TRANSMISSION_CONTROL_EOSP_MASK)?FALSE:TRUE; if((r=frame_and_send_queued_pdu(priv,buffered_pkt,NULL,moreData,FALSE)) == -ENOSPC) { @@ -2076,7 +2158,19 @@ void uf_process_ma_vif_availibility_ind(unifi_priv_t *priv,CsrUint8 *sigdata, if(interfacePriv->multicastPduHostTag == 0xffffffff) { unifi_notice(priv,"ma_vif_availibility_ind recevied for multicast but queues are empty%d\n",interfaceTag); /* This may be an extra request in very rare race conditions but it is fine as it would atleast remove the potential lock up */ - update_tim(priv,0,0,interfaceTag, 0xFFFFFFFF); + if (!interfacePriv->bcTimSetReqPendingFlag) + { + update_tim(priv,0,CSR_WIFI_TIM_RESET,interfaceTag, 0xFFFFFFFF); + } + else + { + /* Cache the TimSet value so that it will processed immidiatly after + * completing the current setTim Request + */ + interfacePriv->bcTimSetReqQueued = CSR_WIFI_TIM_RESET; + unifi_trace(priv, UDBG2, "uf_process_ma_vif_availibility_ind : One more UpdateDTim Request(%d) Queued \n", + interfacePriv->bcTimSetReqQueued); + } } return; } @@ -2105,59 +2199,62 @@ void uf_process_ma_vif_availibility_ind(unifi_priv_t *priv,CsrUint8 *sigdata, #define GET_ACTIVE_INTERFACE_TAG(priv) 0 - -void uf_continue_uapsd(unifi_priv_t *priv, CsrWifiRouterCtrlStaInfo_t * staInfo) +static CsrBool uf_is_more_data_for_delivery_ac(unifi_priv_t *priv, CsrWifiRouterCtrlStaInfo_t *staRecord) { - CsrInt8 i; - func_enter(); - - if(((staInfo->powersaveMode[UNIFI_TRAFFIC_Q_VO]==CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED)|| - (staInfo->powersaveMode[UNIFI_TRAFFIC_Q_VO]==CSR_WIFI_AC_DELIVERY_ONLY_ENABLE)) - &&(!list_empty(&staInfo->mgtFrames))){ - - unifi_trace(priv, UDBG5, "uf_continue_uapsd : U-APSD ACTIVE and sending buffered mgt frames\n"); - uf_send_buffered_data_from_delivery_ac(priv, staInfo, UNIFI_TRAFFIC_Q_VO, &staInfo->mgtFrames); - - /*This may happen because U-APSD was completed - with previous AC transfer*/ - - if(staInfo->uapsdActive == FALSE) { - return; + for(i=UNIFI_TRAFFIC_Q_VO; i >= UNIFI_TRAFFIC_Q_BK; i--) + { + if(((staRecord->powersaveMode[i]==CSR_WIFI_AC_DELIVERY_ONLY_ENABLE) + ||(staRecord->powersaveMode[i]==CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED)) + &&(!list_empty(&staRecord->dataPdu[i]))) { + unifi_trace(priv,UDBG2,"uf_is_more_data_for_delivery_ac: Data Available AC = %d\n", i); + return TRUE; } } - for(i=3;i>=0;i--) { + unifi_trace(priv,UDBG2,"uf_is_more_data_for_delivery_ac: Data NOT Available \n"); + return FALSE; +} - if(((staInfo->powersaveMode[i]== CSR_WIFI_AC_DELIVERY_ONLY_ENABLE) - ||(staInfo->powersaveMode[i] == CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED)) - &&(!list_empty(&staInfo->dataPdu[i]))) { - unifi_trace(priv, UDBG5, "uf_continue_uapsd : U-APSD ACTIVE and sending buffered data frames\n"); - uf_send_buffered_data_from_delivery_ac(priv, staInfo, i, &staInfo->dataPdu[i]); - } +static CsrBool uf_is_more_data_for_usp_delivery(unifi_priv_t *priv, CsrWifiRouterCtrlStaInfo_t *staRecord, unifi_TrafficQueue queue) +{ + CsrInt8 i; - /*This may happen because U-APSD was completed - with previous AC transfer*/ - if (staInfo->uapsdActive == FALSE) { - return; + for(i = queue; i >= UNIFI_TRAFFIC_Q_BK; i--) + { + if(((staRecord->powersaveMode[i]==CSR_WIFI_AC_DELIVERY_ONLY_ENABLE) + ||(staRecord->powersaveMode[i]==CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED)) + &&(!list_empty(&staRecord->dataPdu[i]))) { + unifi_trace(priv,UDBG2,"uf_is_more_data_for_usp_delivery: Data Available AC = %d\n", i); + return TRUE; } } - if (staInfo->uapsdActive && !uf_is_more_data_for_delivery_ac(priv, staInfo, TRUE)) { - /* If last packet not able to transfer due to ENOSPC & buffer management algorithm - * would have removed last packet. Then we wont update staInfo->UapsdActive = FALSE (suppose - * to update as we dont have packet to transfer at this USP) because above if loop fails as list is empty & - * update of UAPSD activity done in uf_send_buffered_data_from_delivery_ac(). - * In this situation we send QOS null & mean time update UapsdActive to FALSE here - */ - staInfo->uapsdActive = FALSE; - uf_send_qos_null(priv, GET_ACTIVE_INTERFACE_TAG(priv), staInfo->peerMacAddress.a, CSR_QOS_UP0 , staInfo); - } - func_exit(); + unifi_trace(priv,UDBG2,"uf_is_more_data_for_usp_delivery: Data NOT Available \n"); + return FALSE; } - +/* + * --------------------------------------------------------------------------- + * uf_send_buffered_data_from_delivery_ac + * + * This function takes care of + * -> Parsing the delivery enabled queue & sending frame down to HIP + * -> Setting EOSP=1 when USP to be terminated + * -> Depending on MAX SP length services the USP + * + * NOTE:This function always called from uf_handle_uspframes_delivery(), Dont + * call this function from any other location in code + * + * Arguments: + * priv Pointer to device private context struct + * vif interface specific HIP vif instance + * staInfo peer for which UAPSD to be scheduled + * queue AC from which Data to be sent in USP + * txList access category for processing list + * --------------------------------------------------------------------------- + */ void uf_send_buffered_data_from_delivery_ac(unifi_priv_t *priv, CsrWifiRouterCtrlStaInfo_t * staInfo, CsrUint8 queue, @@ -2170,117 +2267,94 @@ void uf_send_buffered_data_from_delivery_ac(unifi_priv_t *priv, CsrBool eosp=FALSE; CsrInt8 r =0; CsrBool moreData = FALSE; + netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag]; - CsrUint8 allDeliveryEnabled = 0, dataAvailable = 0; - netInterface_priv_t *interfacePriv; - interfacePriv = priv->interfacePriv[interfaceTag]; - func_enter(); - - /*Check U-APSD conditions if not met return from here*/ - if((staInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE)&& - (staInfo->uapsdActive == TRUE)&& - (!IS_DELIVERY_AND_TRIGGER_ENABLED(staInfo->powersaveMode[queue]))){ - - unifi_trace(priv,UDBG4,"uf_send_buffered_data_from_queue : U-APSD active. %d :Queue NOT delivery enbaled.return %\n",queue); + unifi_trace(priv, UDBG2, "++uf_send_buffered_data_from_delivery_ac, active=%x\n", staInfo->uapsdActive); + if (queue > UNIFI_TRAFFIC_Q_VO) + { return; - } + } + while((buffered_pkt=dequeue_tx_data_pdu(priv, txList))) { + if((IS_DTIM_ACTIVE(interfacePriv->dtimActive,interfacePriv->multicastPduHostTag))) { + unifi_trace(priv, UDBG2, "uf_send_buffered_data_from_delivery_ac: DTIM Active, suspend UAPSD, staId: 0x%x\n", + staInfo->aid); - while(!isRouterBufferEnabled(priv,queue) && - ((buffered_pkt=dequeue_tx_data_pdu(priv, txList))!=NULL)){ - if((IS_DTIM_ACTIVE(interfacePriv->dtimActive,interfacePriv->multicastPduHostTag))){ + /* Once resume called, the U-APSD delivery operation will resume */ spin_lock_irqsave(&priv->staRecord_lock,lock_flags); - staInfo->uapsdSuspended = TRUE; - staInfo->uapsdActive = FALSE; + staInfo->uspSuspend = TRUE; spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags); /* re-queueing the packet as DTIM started */ spin_lock_irqsave(&priv->tx_q_lock,lock_flags); list_add(&buffered_pkt->q,txList); spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags); - unifi_trace(priv, UDBG3, "%s: DTIM Active while UAPSD in progress for staId: 0x%x\n",__FUNCTION__,staInfo->aid); break; } buffered_pkt->transmissionControl &= - ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_ESOP_MASK); - + ~(TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK); - if((staInfo->wmmOrQosEnabled == TRUE)&&(staInfo->uapsdActive == TRUE)){ - moreData = uf_is_more_data_for_delivery_ac(priv,staInfo,TRUE); + if((staInfo->wmmOrQosEnabled == TRUE)&&(staInfo->uapsdActive == TRUE)) { buffered_pkt->transmissionControl = TRANSMISSION_CONTROL_TRIGGER_MASK; - if(staInfo->noOfSpFramesSent == (staInfo->maxSpLength-1)){ - moreData = FALSE; - } - - if(moreData == FALSE){ - eosp = TRUE; - staInfo->uapsdActive = FALSE; - staInfo->noOfSpFramesSent = FALSE; - buffered_pkt->transmissionControl = - (TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_ESOP_MASK); + /* Check All delivery enables Ac for more data, because caller of this + * function not aware about last packet + * (First check in moreData fetching helps in draining out Mgt frames Q) + */ + moreData = (!list_empty(txList) || uf_is_more_data_for_usp_delivery(priv, staInfo, queue)); - /* Check if all AC's are Delivery Enabled */ - is_all_ac_deliver_enabled_and_moredata(staInfo, &allDeliveryEnabled, &dataAvailable); - if ((allDeliveryEnabled && !dataAvailable)) { - update_tim(priv,staInfo->aid,0,interfaceTag, staInfo->assignedHandle); - } - /* check the moer data for non delivery ac and update accordingly */ - else if(uf_is_more_data_for_non_delivery_ac(staInfo) ) { - update_tim(priv,staInfo->aid,1,interfaceTag, staInfo->assignedHandle); - } - else if(!uf_is_more_data_for_non_delivery_ac(staInfo) ){ - unifi_trace(priv, UDBG3, "more data = NULL, set tim to 0 in uf_send_buffered_data_from_delivery_ac\n"); - update_tim(priv,staInfo->aid,0,interfaceTag, staInfo->assignedHandle); - } + if(staInfo->noOfSpFramesSent == (staInfo->maxSpLength - 1)) { + moreData = FALSE; + } - } - } - else - { - /*Non QoS and non U-APSD.*/ - eosp = FALSE; - moreData = FALSE; - unifi_warning(priv,"uf_send_buffered_data_from_delivery_ac :non U-APSD !!! \n"); + if(moreData == FALSE) { + eosp = TRUE; + buffered_pkt->transmissionControl = + (TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK); + } + } else { + /* Non QoS and non U-APSD */ + unifi_warning(priv, "uf_send_buffered_data_from_delivery_ac: non U-APSD !!! \n"); } unifi_trace(priv,UDBG2,"uf_send_buffered_data_from_delivery_ac : MoreData:%d, EOSP:%d\n",moreData,eosp); if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staInfo,moreData,eosp)) == -ENOSPC) { - /* Enqueue at the head of the queue */ - spin_lock_irqsave(&priv->tx_q_lock,lock_flags); - list_add(&buffered_pkt->q,txList); - spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags); - priv->pausedStaHandle[queue]=(CsrUint8)(staInfo->assignedHandle); - unifi_notice (priv," U-APSD: PDU sending failed .. no space for queue %d \n",queue); - /*Break the loop for this queue.Try for next available Delivery enabled - Queue*/ - break; + + unifi_trace(priv, UDBG2, "uf_send_buffered_data_from_delivery_ac: UASPD suspended, ENOSPC in hipQ=%x\n", queue); + + /* Once resume called, the U-APSD delivery operation will resume */ + spin_lock_irqsave(&priv->staRecord_lock,lock_flags); + staInfo->uspSuspend = TRUE; + spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags); + + spin_lock_irqsave(&priv->tx_q_lock,lock_flags); + list_add(&buffered_pkt->q,txList); + spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags); + priv->pausedStaHandle[queue]=(CsrUint8)(staInfo->assignedHandle); + break; } else { if(r){ /* the PDU failed where we can't do any thing so free the storage */ unifi_net_data_free(priv, &buffered_pkt->bulkdata); } - kfree(buffered_pkt); - if(staInfo->uapsdActive == TRUE){ - spin_lock_irqsave(&priv->staRecord_lock,lock_flags); - staInfo->noOfSpFramesSent = staInfo->noOfSpFramesSent + 1; - if(staInfo->noOfSpFramesSent == staInfo->maxSpLength){ - staInfo->uapsdActive = FALSE; - staInfo->noOfSpFramesSent = FALSE; - spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags); - break; - } + spin_lock_irqsave(&priv->staRecord_lock,lock_flags); + staInfo->noOfSpFramesSent++; + if((!moreData) || (staInfo->noOfSpFramesSent == staInfo->maxSpLength)) { + unifi_trace(priv, UDBG2, "uf_send_buffered_data_from_delivery_ac: Terminating USP\n"); + staInfo->uapsdActive = FALSE; + staInfo->uspSuspend = FALSE; + staInfo->noOfSpFramesSent = 0; spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags); + break; } + spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags); } } - - func_exit(); - + unifi_trace(priv, UDBG2, "--uf_send_buffered_data_from_delivery_ac, active=%x\n", staInfo->uapsdActive); } void uf_send_buffered_data_from_ac(unifi_priv_t *priv, @@ -2302,7 +2376,7 @@ void uf_send_buffered_data_from_ac(unifi_priv_t *priv, ((buffered_pkt=dequeue_tx_data_pdu(priv, txList))!=NULL)){ buffered_pkt->transmissionControl &= - ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_ESOP_MASK); + ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_EOSP_MASK); unifi_trace(priv,UDBG3,"uf_send_buffered_data_from_ac : MoreData:%d, EOSP:%d\n",moreData,eosp); @@ -2352,7 +2426,19 @@ void uf_send_buffered_frames(unifi_priv_t *priv,unifi_TrafficQueue q) moreData = (!list_empty(&interfacePriv->genericMulticastOrBroadCastMgtFrames) || !list_empty(&interfacePriv->genericMulticastOrBroadCastFrames)); if(!moreData) { - update_tim(priv,0,0,interfaceTag, 0XFFFFFFFF); + if (!interfacePriv->bcTimSetReqPendingFlag) + { + update_tim(priv,0,CSR_WIFI_TIM_RESET,interfaceTag, 0XFFFFFFFF); + } + else + { + /* Cache the TimSet value so that it will processed immidiatly after + * completing the current setTim Request + */ + interfacePriv->bcTimSetReqQueued = CSR_WIFI_TIM_RESET; + unifi_trace(priv, UDBG2, "uf_send_buffered_frames : One more UpdateDTim Request(%d) Queued \n", + interfacePriv->bcTimSetReqQueued); + } } } else { moreData = (!list_empty(&interfacePriv->genericMulticastOrBroadCastMgtFrames) || @@ -2391,33 +2477,17 @@ void uf_send_buffered_frames(unifi_priv_t *priv,unifi_TrafficQueue q) uf_send_buffered_data_from_ac(priv,staInfo, UNIFI_TRAFFIC_Q_VO, &staInfo->mgtFrames); } } - else if((staInfo != NULL)&&(staInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE) - &&(staInfo->uapsdActive == TRUE)&&(IS_DELIVERY_AND_TRIGGER_ENABLED(staInfo->powersaveMode[UNIFI_TRAFFIC_Q_VO]))){ - - - if(!list_empty(&staInfo->mgtFrames)){ - /*UNIFI_TRAFFIC_Q_VO is delivery enabled push the managment frames out*/ - uf_send_buffered_data_from_delivery_ac(priv, staInfo, UNIFI_TRAFFIC_Q_VO, &staInfo->mgtFrames); - - } - } if(isRouterBufferEnabled(priv,queue)) { unifi_notice(priv,"uf_send_buffered_frames : No space Left for queue = %d\n",queue); break; } } - - /*push generic management frames out*/ - - if(!list_empty(&interfacePriv->genericMgtFrames)){ - - unifi_trace(priv,UDBG2,"uf_send_buffered_frames : trying generic mgt from queue=%d\n",queue); - uf_send_buffered_data_from_ac(priv,staInfo, UNIFI_TRAFFIC_Q_VO, &interfacePriv->genericMgtFrames); - + if(!list_empty(&interfacePriv->genericMgtFrames)) { + unifi_trace(priv,UDBG2,"uf_send_buffered_frames : trying generic mgt from queue=%d\n",queue); + uf_send_buffered_data_from_ac(priv,staInfo, UNIFI_TRAFFIC_Q_VO, &interfacePriv->genericMgtFrames); } - } @@ -2431,14 +2501,14 @@ void uf_send_buffered_frames(unifi_priv_t *priv,unifi_TrafficQueue q) staInfo = CsrWifiRouterCtrlGetStationRecordFromHandle(priv,startIndex,interfaceTag); if(!staInfo) { startIndex ++; - if(startIndex >= UNIFI_MAX_CONNECTIONS){ + if(startIndex >= UNIFI_MAX_CONNECTIONS) { startIndex = 0; } continue; } else if((staInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE) - &&(staInfo->uapsdActive == FALSE)){ + &&(staInfo->uapsdActive == FALSE)) { startIndex ++; - if(startIndex >= UNIFI_MAX_CONNECTIONS){ + if(startIndex >= UNIFI_MAX_CONNECTIONS) { startIndex = 0; } continue; @@ -2448,23 +2518,15 @@ void uf_send_buffered_frames(unifi_priv_t *priv,unifi_TrafficQueue q) if((staInfo != NULL)&&(staInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE) - &&(staInfo->uapsdActive == FALSE)){ + &&(staInfo->uapsdActive == FALSE)) { + if(!list_empty(&staInfo->dataPdu[queue])) { - if(!list_empty(&staInfo->dataPdu[queue])){ - - /*Non-UAPSD case push the AC frames out*/ - uf_send_buffered_data_from_ac(priv, staInfo, queue, (&staInfo->dataPdu[queue])); + /*Non-UAPSD case push the AC frames out*/ + uf_send_buffered_data_from_ac(priv, staInfo, queue, (&staInfo->dataPdu[queue])); } } - else if((staInfo != NULL)&&(staInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE) - &&(staInfo->uapsdActive == TRUE)&&(IS_DELIVERY_AND_TRIGGER_ENABLED(staInfo->powersaveMode[queue]))){ - if(!list_empty(&staInfo->dataPdu[queue])){ - uf_send_buffered_data_from_delivery_ac(priv, staInfo, queue, &staInfo->dataPdu[queue]); - } - } - startIndex ++; - if(startIndex >= UNIFI_MAX_CONNECTIONS){ + if(startIndex >= UNIFI_MAX_CONNECTIONS) { startIndex = 0; } } @@ -2474,47 +2536,14 @@ void uf_send_buffered_frames(unifi_priv_t *priv,unifi_TrafficQueue q) priv->pausedStaHandle[queue] = 0; } - /*U-APSD might have stopped because of pause.So restart it if U-APSD - was active with any of the station*/ - for(startIndex= 0; startIndex < UNIFI_MAX_CONNECTIONS;startIndex++) { - staInfo = CsrWifiRouterCtrlGetStationRecordFromHandle(priv,startIndex,interfaceTag); - if(!staInfo ) { - continue; - } else if((staInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE) - &&(staInfo->uapsdActive == TRUE)) { - - /*U-APSD Still active, it means trigger frame is received,so continue U-APSD by - sending data from remaining delivery enabled queues*/ - uf_continue_uapsd(priv,staInfo); - } - } + /* U-APSD might have stopped because of ENOSPC in lib_hip (pause activity). + * So restart it if U-APSD was active with any of the station + */ + unifi_trace(priv, UDBG4, "csrWifiHipSendBufferedFrames: UAPSD Resume Q=%x\n", queue); + resume_suspended_uapsd(priv, interfaceTag); func_exit(); } -CsrBool uf_is_more_data_for_delivery_ac(unifi_priv_t *priv,CsrWifiRouterCtrlStaInfo_t *staRecord,CsrBool mgtCheck) -{ - CsrUint8 i; - - for(i=0;i<=3;i++) - { - if(((staRecord->powersaveMode[i]==CSR_WIFI_AC_DELIVERY_ONLY_ENABLE) - ||(staRecord->powersaveMode[i]==CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED)) - &&(!list_empty(&staRecord->dataPdu[i]))){ - unifi_trace(priv,UDBG2,"uf_is_more_data_for_delivery_ac: Data Available \n"); - return TRUE; - } - } - if((mgtCheck == TRUE)&&(IS_DELIVERY_AND_TRIGGER_ENABLED(staRecord->powersaveMode[UNIFI_TRAFFIC_Q_VO])) - &&(!list_empty(&staRecord->mgtFrames))){ - - unifi_trace(priv,UDBG2,"uf_is_more_data_for_delivery_ac: Management Data Available \n"); - - return TRUE; - } - - unifi_trace(priv,UDBG2,"uf_is_more_data_for_delivery_ac: Data NOT Available \n"); - return FALSE; -} CsrBool uf_is_more_data_for_non_delivery_ac(CsrWifiRouterCtrlStaInfo_t *staRecord) { @@ -2584,101 +2613,148 @@ int uf_process_station_records_for_sending_data(unifi_priv_t *priv,CsrUint16 int return 0; } -void uf_process_wmm_deliver_ac_uapsd(unifi_priv_t * priv, - CsrWifiRouterCtrlStaInfo_t * srcStaInfo, - CsrUint16 qosControl, - CsrUint16 interfaceTag) + +/* + * --------------------------------------------------------------------------- + * uf_handle_uspframes_delivery + * + * This function takes care of handling USP session for peer, when + * -> trigger frame from peer + * -> suspended USP to be processed (resumed) + * + * NOTE: uf_send_buffered_data_from_delivery_ac() always called from this function, Dont + * make a direct call to uf_send_buffered_data_from_delivery_ac() from any other part of + * code + * + * Arguments: + * priv Pointer to device private context struct + * staInfo peer for which UAPSD to be scheduled + * interfaceTag virtual interface tag + * --------------------------------------------------------------------------- + */ +static void uf_handle_uspframes_delivery(unifi_priv_t * priv, CsrWifiRouterCtrlStaInfo_t *staInfo, CsrUint16 interfaceTag) { - CSR_PRIORITY priority; CsrInt8 i; - unifi_TrafficQueue priority_q; + CsrUint8 allDeliveryEnabled = 0, dataAvailable = 0; + netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag]; unsigned long lock_flags; - func_enter(); - - /* start the U-APSD operation only if it not active*/ - if(srcStaInfo->uapsdActive == FALSE){ - /*if recceived Frames trigger Frame and Devlivery enabled AC has data - then transmit from High priorty delivery enabled AC*/ - - - priority = (CSR_PRIORITY)(qosControl & IEEE802_11_QC_TID_MASK); + unifi_trace(priv, UDBG2, " ++ uf_handle_uspframes_delivery, uapsd active=%x, suspended?=%x\n", + staInfo->uapsdActive, staInfo->uspSuspend); - priority_q = unifi_frame_priority_to_queue((CSR_PRIORITY) priority); + /* Check for Buffered frames according to priority order & deliver it + * 1. AC_VO delivery enable & Mgt frames available + * 2. Process remaining Ac's from order AC_VO to AC_BK + */ - if((srcStaInfo->powersaveMode[priority_q]==CSR_WIFI_AC_TRIGGER_ONLY_ENABLED) - ||(srcStaInfo->powersaveMode[priority_q]==CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED)){ + /* USP initiated by WMMPS enabled peer & SET the status flag to TRUE */ + if (!staInfo->uspSuspend && staInfo->uapsdActive) + { + unifi_notice(priv, "uf_handle_uspframes_delivery: U-APSD already active! STA=%x:%x:%x:%x:%x:%x\n", + staInfo->peerMacAddress.a[0], staInfo->peerMacAddress.a[1], + staInfo->peerMacAddress.a[2], staInfo->peerMacAddress.a[3], + staInfo->peerMacAddress.a[4], staInfo->peerMacAddress.a[5]); + return; + } - unifi_trace(priv, UDBG3, "uf_process_wmm_deliver_ac_uapsd starting U-APSD operations\n"); + spin_lock_irqsave(&priv->staRecord_lock,lock_flags); + staInfo->uapsdActive = TRUE; + staInfo->uspSuspend = FALSE; + spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags); - /*Received Frame is trigger frame*/ - unifi_trace(priv, UDBG5, "uf_process_wmm_deliver_ac_uapsd : Received Frame is trigger frame %d\n",priority_q); + if(((staInfo->powersaveMode[UNIFI_TRAFFIC_Q_VO]==CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED)|| + (staInfo->powersaveMode[UNIFI_TRAFFIC_Q_VO]==CSR_WIFI_AC_DELIVERY_ONLY_ENABLE)) + && (!list_empty(&staInfo->mgtFrames))) { - if(((srcStaInfo->powersaveMode[UNIFI_TRAFFIC_Q_VO]==CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED)|| - (srcStaInfo->powersaveMode[UNIFI_TRAFFIC_Q_VO]==CSR_WIFI_AC_DELIVERY_ONLY_ENABLE)) - &&(!list_empty(&srcStaInfo->mgtFrames))){ + /* Management queue has data && UNIFI_TRAFFIC_Q_VO is delivery enable */ + unifi_trace(priv, UDBG4, "uf_handle_uspframes_delivery: Sending buffered management frames\n"); + uf_send_buffered_data_from_delivery_ac(priv, staInfo, UNIFI_TRAFFIC_Q_VO, &staInfo->mgtFrames); + } - /*Trigger frame received and Data available in Delivery enabled AC - or in Management queue when UNIFI_TRAFFIC_Q_VO is delivery enabled*/ + if (!uf_is_more_data_for_delivery_ac(priv, staInfo)) { + /* All delivery enable AC's are empty, so QNULL to be sent to terminate the USP + * NOTE: If we have sent Mgt frame also, we must send QNULL followed to terminate USP + */ + if (!staInfo->uspSuspend) { spin_lock_irqsave(&priv->staRecord_lock,lock_flags); - srcStaInfo->uapsdActive = TRUE; + staInfo->uapsdActive = FALSE; spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags); - unifi_trace(priv, UDBG5, "uf_process_wmm_deliver_ac_uapsd : U-APSD ACTIVE and sending buffered mgt frames\n"); - - /* uf_send_buffered_frames(priv, priority_q); */ - uf_send_buffered_data_from_delivery_ac(priv, srcStaInfo, UNIFI_TRAFFIC_Q_VO, &srcStaInfo->mgtFrames); - - - /*This may happen because U-APSD was completed - with previous AC transfer*/ - - if(srcStaInfo->uapsdActive == FALSE){ - return; - } - - } - - - for(i=3;i>=0;i--){ - - if(((srcStaInfo->powersaveMode[i]==CSR_WIFI_AC_DELIVERY_ONLY_ENABLE) - ||(srcStaInfo->powersaveMode[i]==CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED)) - &&(!list_empty(&srcStaInfo->dataPdu[i]))){ - - - /*Trigger frame received and Data available in Delivery enabled AC - or in Management queue when UNIFI_TRAFFIC_Q_VO is delivery enabled*/ - spin_lock_irqsave(&priv->staRecord_lock,lock_flags); - srcStaInfo->uapsdActive = TRUE; - spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags); - - unifi_trace(priv, UDBG5, "uf_process_wmm_deliver_ac_uapsd : U-APSD ACTIVE and sending buffered data frames\n"); - - uf_send_buffered_data_from_delivery_ac(priv, srcStaInfo, i, &srcStaInfo->dataPdu[i]); + unifi_trace(priv, UDBG2, "uf_handle_uspframes_delivery: sending QNull for trigger\n"); + uf_send_qos_null(priv, interfaceTag, staInfo->peerMacAddress.a, (CSR_PRIORITY) staInfo->triggerFramePriority, staInfo); + staInfo->triggerFramePriority = CSR_QOS_UP0; + } else { + unifi_trace(priv, UDBG2, "uf_handle_uspframes_delivery: MgtQ xfer suspended\n"); + } + } else { + for(i = UNIFI_TRAFFIC_Q_VO; i >= UNIFI_TRAFFIC_Q_BK; i--) { + if(((staInfo->powersaveMode[i]==CSR_WIFI_AC_DELIVERY_ONLY_ENABLE) + ||(staInfo->powersaveMode[i]==CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED)) + && (!list_empty(&staInfo->dataPdu[i]))) { + /* Deliver Data according to AC priority (from VO to BK) as part of USP */ + unifi_trace(priv, UDBG4, "uf_handle_uspframes_delivery: Buffered data frames from Queue (%d) for USP\n", i); + uf_send_buffered_data_from_delivery_ac(priv, staInfo, i, &staInfo->dataPdu[i]); + } - /*This may happen because U-APSD was completed - with previous AC transfer*/ + if ((!staInfo->uapsdActive) || + (staInfo->uspSuspend && IS_DTIM_ACTIVE(interfacePriv->dtimActive,interfacePriv->multicastPduHostTag))) { + /* If DTIM active found on one AC, No need to parse the remaining AC's + * as USP suspended. Break out of loop + */ + unifi_trace(priv, UDBG2, "uf_handle_uspframes_delivery: suspend=%x, DTIM=%x, USP terminated=%s\n", + staInfo->uspSuspend, IS_DTIM_ACTIVE(interfacePriv->dtimActive,interfacePriv->multicastPduHostTag), + staInfo->uapsdActive?"NO":"YES"); + break; + } + } + } - if(srcStaInfo->uapsdActive == FALSE){ - return; - } + /* Depending on the USP status, update the TIM accordingly for delivery enabled AC only + * (since we are not manipulating any Non-delivery list(AC)) + */ + is_all_ac_deliver_enabled_and_moredata(staInfo, &allDeliveryEnabled, &dataAvailable); + if ((allDeliveryEnabled && !dataAvailable)) { + if ((staInfo->timSet != CSR_WIFI_TIM_RESET) || (staInfo->timSet != CSR_WIFI_TIM_RESETTING)) { + staInfo->updateTimReqQueued = (CsrUint8) CSR_WIFI_TIM_RESET; + unifi_trace(priv, UDBG4, " --uf_handle_uspframes_delivery, UAPSD timset\n"); + if (!staInfo->timRequestPendingFlag) { + update_tim(priv, staInfo->aid, 0, interfaceTag, staInfo->assignedHandle); } + } + } + unifi_trace(priv, UDBG2, " --uf_handle_uspframes_delivery, uapsd active=%x, suspend?=%x\n", + staInfo->uapsdActive, staInfo->uspSuspend); +} - } - if(srcStaInfo->uapsdActive == FALSE && !(uf_is_more_data_for_delivery_ac(priv,srcStaInfo,TRUE))){ - unifi_trace(priv, UDBG3, "uf_process_wmm_deliver_ac_uapsd : No buffer frames so sending QOS Null in response of trigger frame\n"); - uf_send_qos_null(priv,interfaceTag,srcStaInfo->peerMacAddress.a,priority,srcStaInfo); - } +void uf_process_wmm_deliver_ac_uapsd(unifi_priv_t * priv, + CsrWifiRouterCtrlStaInfo_t * srcStaInfo, + CsrUint16 qosControl, + CsrUint16 interfaceTag) +{ + CSR_PRIORITY priority; + unifi_TrafficQueue priority_q; + unsigned long lock_flags; - } + unifi_trace(priv, UDBG2, "++uf_process_wmm_deliver_ac_uapsd: uapsdactive?=%x\n", srcStaInfo->uapsdActive); + /* If recceived Frames trigger Frame and Devlivery enabled AC has data + * then transmit from High priorty delivery enabled AC + */ + priority = (CSR_PRIORITY)(qosControl & IEEE802_11_QC_TID_MASK); + priority_q = unifi_frame_priority_to_queue((CSR_PRIORITY) priority); - } + if((srcStaInfo->powersaveMode[priority_q]==CSR_WIFI_AC_TRIGGER_ONLY_ENABLED) + ||(srcStaInfo->powersaveMode[priority_q]==CSR_WIFI_AC_TRIGGER_AND_DELIVERY_ENABLED)) { + spin_lock_irqsave(&priv->staRecord_lock,lock_flags); + srcStaInfo->triggerFramePriority = priority; + spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags); + unifi_trace(priv, UDBG2, "uf_process_wmm_deliver_ac_uapsd: trigger frame, Begin U-APSD, triggerQ=%x\n", priority_q); + uf_handle_uspframes_delivery(priv, srcStaInfo, interfaceTag); + } + unifi_trace(priv, UDBG2, "--uf_process_wmm_deliver_ac_uapsd: uapsdactive?=%x\n", srcStaInfo->uapsdActive); +} - func_exit(); -} void uf_send_qos_null(unifi_priv_t * priv,CsrUint16 interfaceTag, const CsrUint8 *da,CSR_PRIORITY priority,CsrWifiRouterCtrlStaInfo_t * srcStaInfo) { bulk_data_param_t bulkdata; @@ -2686,7 +2762,7 @@ void uf_send_qos_null(unifi_priv_t * priv,CsrUint16 interfaceTag, const CsrUint8 struct sk_buff *skb, *newSkb = NULL; CsrWifiMacAddress peerAddress; netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag]; - CSR_TRANSMISSION_CONTROL transmissionControl = (TRANSMISSION_CONTROL_ESOP_MASK | TRANSMISSION_CONTROL_TRIGGER_MASK); + CSR_TRANSMISSION_CONTROL transmissionControl = (TRANSMISSION_CONTROL_EOSP_MASK | TRANSMISSION_CONTROL_TRIGGER_MASK); int r; CSR_SIGNAL signal; CsrUint32 priority_q; @@ -2928,7 +3004,19 @@ CsrBool uf_process_pm_bit_for_peer(unifi_priv_t * priv, CsrWifiRouterCtrlStaInfo !list_empty(&srcStaInfo->dataPdu[UNIFI_TRAFFIC_Q_CONTENTION])); if(moreData && (srcStaInfo->timSet == CSR_WIFI_TIM_RESET)) { unifi_trace(priv, UDBG3, "This condition should not occur\n"); - update_tim(priv,srcStaInfo->aid,1,interfaceTag, srcStaInfo->assignedHandle); + if (!srcStaInfo->timRequestPendingFlag){ + update_tim(priv,srcStaInfo->aid,1,interfaceTag, srcStaInfo->assignedHandle); + } + else + { + /* Cache the TimSet value so that it will processed immidiatly after + * completing the current setTim Request + */ + srcStaInfo->updateTimReqQueued = 1; + unifi_trace(priv, UDBG6, "update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x\n", srcStaInfo->updateTimReqQueued, + srcStaInfo->aid); + } + } } else { CsrUint8 allDeliveryEnabled = 0, dataAvailable = 0; @@ -2939,7 +3027,18 @@ CsrBool uf_process_pm_bit_for_peer(unifi_priv_t * priv, CsrWifiRouterCtrlStaInfo moreData = (uf_is_more_data_for_non_delivery_ac(srcStaInfo) || (allDeliveryEnabled && dataAvailable)); if(moreData && (srcStaInfo->timSet == CSR_WIFI_TIM_RESET)) { - update_tim(priv,srcStaInfo->aid,1,interfaceTag, srcStaInfo->assignedHandle); + if (!srcStaInfo->timRequestPendingFlag){ + update_tim(priv,srcStaInfo->aid,1,interfaceTag, srcStaInfo->assignedHandle); + } + else + { + /* Cache the TimSet value so that it will processed immidiatly after + * completing the current setTim Request + */ + srcStaInfo->updateTimReqQueued = 1; + unifi_trace(priv, UDBG6, "update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x\n", srcStaInfo->updateTimReqQueued, + srcStaInfo->aid); + } } } } @@ -2993,10 +3092,10 @@ void uf_process_ps_poll(unifi_priv_t *priv,CsrUint8* sa,CsrUint8* da,CsrUint8 pm !list_empty(&staRecord->dataPdu[UNIFI_TRAFFIC_Q_VO]) || !list_empty(&staRecord->mgtFrames)); - buffered_pkt->transmissionControl |= (TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_ESOP_MASK); + buffered_pkt->transmissionControl |= (TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK); if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staRecord,moreData,FALSE)) == -ENOSPC) { /* Clear the trigger bit transmission control*/ - buffered_pkt->transmissionControl &= ~(TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_ESOP_MASK); + buffered_pkt->transmissionControl &= ~(TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK); /* Enqueue at the head of the queue */ spin_lock_irqsave(&priv->tx_q_lock,lock_flags); list_add(&buffered_pkt->q, &staRecord->mgtFrames); @@ -3016,10 +3115,10 @@ void uf_process_ps_poll(unifi_priv_t *priv,CsrUint8* sa,CsrUint8* da,CsrUint8 pm moreData = (!list_empty(&staRecord->dataPdu[UNIFI_TRAFFIC_Q_CONTENTION]) || !list_empty(&staRecord->dataPdu[UNIFI_TRAFFIC_Q_VO])); - buffered_pkt->transmissionControl |= (TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_ESOP_MASK); + buffered_pkt->transmissionControl |= (TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK); if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staRecord,moreData,FALSE)) == -ENOSPC) { /* Clear the trigger bit transmission control*/ - buffered_pkt->transmissionControl &= ~(TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_ESOP_MASK); + buffered_pkt->transmissionControl &= ~(TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK); /* Enqueue at the head of the queue */ spin_lock_irqsave(&priv->tx_q_lock,lock_flags); list_add(&buffered_pkt->q, &staRecord->dataPdu[UNIFI_TRAFFIC_Q_VO]); @@ -3038,10 +3137,10 @@ void uf_process_ps_poll(unifi_priv_t *priv,CsrUint8* sa,CsrUint8* da,CsrUint8 pm buffered_pkt->transmissionControl |= TRANSMISSION_CONTROL_TRIGGER_MASK; moreData = !list_empty(&staRecord->dataPdu[UNIFI_TRAFFIC_Q_CONTENTION]); - buffered_pkt->transmissionControl |= (TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_ESOP_MASK); + buffered_pkt->transmissionControl |= (TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK); if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staRecord,moreData,FALSE)) == -ENOSPC) { /* Clear the trigger bit transmission control*/ - buffered_pkt->transmissionControl &= ~(TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_ESOP_MASK); + buffered_pkt->transmissionControl &= ~(TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK); /* Enqueue at the head of the queue */ spin_lock_irqsave(&priv->tx_q_lock,lock_flags); list_add(&buffered_pkt->q, &staRecord->dataPdu[UNIFI_TRAFFIC_Q_CONTENTION]); @@ -3065,7 +3164,18 @@ void uf_process_ps_poll(unifi_priv_t *priv,CsrUint8* sa,CsrUint8* da,CsrUint8 pm !list_empty(&staRecord->mgtFrames)); if(!moreData && (staRecord->timSet == CSR_WIFI_TIM_SET)) { unifi_trace(priv, UDBG3, "more data = NULL, set tim to 0 in uf_process_ps_poll\n"); - update_tim(priv,staRecord->aid,0,interfaceTag, staRecord->assignedHandle); + if (!staRecord->timRequestPendingFlag){ + update_tim(priv,staRecord->aid,0,interfaceTag, staRecord->assignedHandle); + } + else + { + /* Cache the TimSet value so that it will processed immidiatly after + * completing the current setTim Request + */ + staRecord->updateTimReqQueued = 0; + unifi_trace(priv, UDBG6, "update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x\n", staRecord->updateTimReqQueued, + staRecord->aid); + } } } else { @@ -3074,9 +3184,9 @@ void uf_process_ps_poll(unifi_priv_t *priv,CsrUint8* sa,CsrUint8* da,CsrUint8 pm /*Send Data From Management Frames*/ /* Priority orders for delivering the buffered packets are - * 1. UNIFI_TRAFFIC_Q_VO, if its non delivery enabled - * 2. management frames - * 3. Other access catagory frames which are non deliver enable + * 1. Deliver the Management frames if there + * 2. Other access catagory frames which are non deliver enable including UNIFI_TRAFFIC_Q_VO + * priority is from VO->BK */ /* Check if all AC's are Delivery Enabled */ @@ -3088,42 +3198,18 @@ void uf_process_ps_poll(unifi_priv_t *priv,CsrUint8* sa,CsrUint8* da,CsrUint8 pm return; } - if ((!IS_DELIVERY_ENABLED(staRecord->powersaveMode[UNIFI_TRAFFIC_Q_VO])) && - (!list_empty(&staRecord->dataPdu[UNIFI_TRAFFIC_Q_VO]) || !list_empty(&staRecord->mgtFrames))) { - /* UNIFI_TRAFFIC_Q_VO is non delivery enabled, & check for packets are there to send from this AC */ - if((buffered_pkt=dequeue_tx_data_pdu(priv, &staRecord->dataPdu[UNIFI_TRAFFIC_Q_VO]))) { - moreData = uf_is_more_data_for_non_delivery_ac(staRecord); - buffered_pkt->transmissionControl |= (TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_ESOP_MASK); - - /* Last parameter is EOSP & its false always for PS-POLL processing */ - if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staRecord,moreData,FALSE)) == -ENOSPC) { - /* Clear the trigger bit transmission control*/ - buffered_pkt->transmissionControl &= ~(TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_ESOP_MASK); - /* Enqueue at the head of the queue */ - spin_lock_irqsave(&priv->tx_q_lock,lock_flags); - list_add(&buffered_pkt->q, &staRecord->dataPdu[UNIFI_TRAFFIC_Q_VO]); - spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags); - priv->pausedStaHandle[0]=(CsrUint8)(staRecord->assignedHandle); - unifi_trace(priv, UDBG1, "(ENOSPC) PS-POLL received : PDU sending failed \n"); - } else { - if(r){ - unifi_trace (priv, UDBG1, " HIP validation failure : PDU sending failed \n"); - /* the PDU failed where we can't do any thing so free the storage */ - unifi_net_data_free(priv, &buffered_pkt->bulkdata); - } - kfree(buffered_pkt); - } - } else if ((buffered_pkt=dequeue_tx_data_pdu(priv, &staRecord->mgtFrames))) { + if (!list_empty(&staRecord->mgtFrames)) { + if ((buffered_pkt=dequeue_tx_data_pdu(priv, &staRecord->mgtFrames))) { /* We dont have packets in non delivery enabled UNIFI_TRAFFIC_Q_VO, So we are looking in management * queue of the station record */ moreData = uf_is_more_data_for_non_delivery_ac(staRecord); - buffered_pkt->transmissionControl |= (TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_ESOP_MASK); + buffered_pkt->transmissionControl |= (TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK); /* Last parameter is EOSP & its false always for PS-POLL processing */ if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staRecord,moreData,FALSE)) == -ENOSPC) { /* Clear the trigger bit transmission control*/ - buffered_pkt->transmissionControl &= ~(TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_ESOP_MASK); + buffered_pkt->transmissionControl &= ~(TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK); /* Enqueue at the head of the queue */ spin_lock_irqsave(&priv->tx_q_lock,lock_flags); list_add(&buffered_pkt->q, &staRecord->mgtFrames); @@ -3138,24 +3224,27 @@ void uf_process_ps_poll(unifi_priv_t *priv,CsrUint8* sa,CsrUint8* da,CsrUint8 pm } kfree(buffered_pkt); } + } else { + unifi_error(priv, "uf_process_ps_poll: Mgt frame list empty!! \n"); } + } else { CsrInt8 i; - /* We dont have buffered packet in UNIFI_TRAFFIC_Q_VO & mangement frame queue (1 & 2 failed), So proceed with 3 condition - * UNIFI_TRAFFIC_Q_VO is taken care so start with i index = 2 + /* We dont have buffered packet in mangement frame queue (1 failed), So proceed with condition 2 + * UNIFI_TRAFFIC_Q_VO -> VI -> BE -> BK */ - for(i= 2; i>=0; i--) { + for(i= 3; i>=0; i--) { if (!IS_DELIVERY_ENABLED(staRecord->powersaveMode[i])) { /* Send One packet, if queue is NULL then continue */ if((buffered_pkt=dequeue_tx_data_pdu(priv, &staRecord->dataPdu[i]))) { moreData = uf_is_more_data_for_non_delivery_ac(staRecord); - buffered_pkt->transmissionControl |= (TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_ESOP_MASK); + buffered_pkt->transmissionControl |= (TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK); /* Last parameter is EOSP & its false always for PS-POLL processing */ if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staRecord,moreData,FALSE)) == -ENOSPC) { /* Clear the trigger bit transmission control*/ - buffered_pkt->transmissionControl &= ~(TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_ESOP_MASK); + buffered_pkt->transmissionControl &= ~(TRANSMISSION_CONTROL_TRIGGER_MASK | TRANSMISSION_CONTROL_EOSP_MASK); /* Enqueue at the head of the queue */ spin_lock_irqsave(&priv->tx_q_lock,lock_flags); list_add(&buffered_pkt->q, &staRecord->dataPdu[i]); @@ -3181,7 +3270,19 @@ void uf_process_ps_poll(unifi_priv_t *priv,CsrUint8* sa,CsrUint8* da,CsrUint8 pm moreData = (uf_is_more_data_for_non_delivery_ac(staRecord) || (allDeliveryEnabled && dataAvailable)); if(!moreData && (staRecord->timSet == CSR_WIFI_TIM_SET)) { unifi_trace(priv, UDBG3, "more data = NULL, set tim to 0 in uf_process_ps_poll\n"); - update_tim(priv,staRecord->aid,0,interfaceTag, staRecord->assignedHandle); + if (!staRecord->timRequestPendingFlag){ + update_tim(priv,staRecord->aid,0,interfaceTag, staRecord->assignedHandle); + } + else + { + /* Cache the TimSet value so that it will processed immidiatly after + * completing the current setTim Request + */ + staRecord->updateTimReqQueued = 0; + unifi_trace(priv, UDBG6, "update_tim : One more UpdateTim Request (Tim value:%d) Queued for AID %x\n", staRecord->updateTimReqQueued, + staRecord->aid); + } + } } @@ -3297,31 +3398,7 @@ void uf_flush_list(unifi_priv_t * priv, struct list_head * list) } spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags); } -void uf_flush_maPktlist(unifi_priv_t * priv, struct list_head * list) -{ - struct list_head *listHeadMaPktreq,*placeHolderMaPktreq; - maPktReqList_t *maPktreq; - unsigned long lock_flags; - - unifi_trace(priv, UDBG5, "entering the uf_flush_maPktlist \n"); - - spin_lock_irqsave(&priv->tx_q_lock,lock_flags); - /* go through list, delete & free memory */ - list_for_each_safe(listHeadMaPktreq, placeHolderMaPktreq, list) { - maPktreq = list_entry(listHeadMaPktreq, maPktReqList_t, q); - - if(!maPktreq) { - unifi_error(priv, "entry should exists, otherwise crashes (bug)\n"); - } - /* free the allocated memory */ - dev_kfree_skb(maPktreq->skb); - list_del(listHeadMaPktreq); - kfree(maPktreq); - maPktreq = NULL; - } - spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags); -} tx_buffered_packets_t *dequeue_tx_data_pdu(unifi_priv_t *priv, struct list_head *txList) { /* dequeue the tx data packets from the appropriate queue */ @@ -3521,7 +3598,7 @@ void resume_unicast_buffered_frames(unifi_priv_t *priv, CsrUint16 interfaceTag) while(!isRouterBufferEnabled(priv,3) && ((buffered_pkt=dequeue_tx_data_pdu(priv,&interfacePriv->genericMgtFrames))!=NULL)) { buffered_pkt->transmissionControl &= - ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_ESOP_MASK); + ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_EOSP_MASK); if((r=frame_and_send_queued_pdu(priv,buffered_pkt,NULL,0,FALSE)) == -ENOSPC) { /* Enqueue at the head of the queue */ spin_lock_irqsave(&priv->tx_q_lock,lock_flags); @@ -3547,7 +3624,7 @@ void resume_unicast_buffered_frames(unifi_priv_t *priv, CsrUint16 interfaceTag) if (staInfo && (staInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE)) { while((( TRUE == hipslotFree[3] ) && (buffered_pkt=dequeue_tx_data_pdu(priv, &staInfo->mgtFrames)))) { buffered_pkt->transmissionControl &= - ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_ESOP_MASK); + ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_EOSP_MASK); if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staInfo,0,FALSE)) == -ENOSPC) { unifi_trace(priv, UDBG3, "(ENOSPC) in resume_unicast_buffered_frames:: hip slots are full for voice queue\n"); /* Enqueue at the head of the queue */ @@ -3573,7 +3650,7 @@ void resume_unicast_buffered_frames(unifi_priv_t *priv, CsrUint16 interfaceTag) while((buffered_pkt=dequeue_tx_data_pdu(priv, &staInfo->dataPdu[j]))) { buffered_pkt->transmissionControl &= - ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_ESOP_MASK); + ~(TRANSMISSION_CONTROL_TRIGGER_MASK|TRANSMISSION_CONTROL_EOSP_MASK); if((r=frame_and_send_queued_pdu(priv,buffered_pkt,staInfo,0,FALSE)) == -ENOSPC) { /* Enqueue at the head of the queue */ spin_lock_irqsave(&priv->tx_q_lock,lock_flags); @@ -3615,7 +3692,7 @@ void update_eosp_to_head_of_broadcast_list_head(unifi_priv_t *priv,CsrUint16 int spin_lock_irqsave(&priv->tx_q_lock,lock_flags); list_for_each_safe(listHead, placeHolder, &interfacePriv->genericMulticastOrBroadCastFrames) { tx_q_item = list_entry(listHead, tx_buffered_packets_t, q); - tx_q_item->transmissionControl |= TRANSMISSION_CONTROL_ESOP_MASK; + tx_q_item->transmissionControl |= TRANSMISSION_CONTROL_EOSP_MASK; tx_q_item->transmissionControl = (tx_q_item->transmissionControl & ~(CSR_NO_CONFIRM_REQUIRED)); unifi_trace(priv, UDBG1,"updating eosp for list Head hostTag:= 0x%x ",tx_q_item->hostTag); break; @@ -3624,105 +3701,51 @@ void update_eosp_to_head_of_broadcast_list_head(unifi_priv_t *priv,CsrUint16 int } func_exit(); } + +/* + * --------------------------------------------------------------------------- + * resume_suspended_uapsd + * + * This function takes care processing packets of Unscheduled Service Period, + * which been suspended earlier due to DTIM/HIP ENOSPC scenarios + * + * Arguments: + * priv Pointer to device private context struct + * interfaceTag For which resume should happen + * --------------------------------------------------------------------------- + */ void resume_suspended_uapsd(unifi_priv_t* priv,CsrUint16 interfaceTag) { CsrUint8 startIndex; CsrWifiRouterCtrlStaInfo_t * staInfo = NULL; - unsigned long lock_flags; - /*U-APSD might have stopped because of multicast. So restart it if U-APSD - was active with any of the station*/ + unsigned long lock_flags; + + unifi_trace(priv, UDBG2, "++resume_suspended_uapsd: \n"); for(startIndex= 0; startIndex < UNIFI_MAX_CONNECTIONS;startIndex++) { staInfo = CsrWifiRouterCtrlGetStationRecordFromHandle(priv,startIndex,interfaceTag); - if(!staInfo ) { + + if(!staInfo || !staInfo->wmmOrQosEnabled) { continue; } else if((staInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_POWER_SAVE) - &&(staInfo->uapsdSuspended == TRUE)) { - - /*U-APSD Still active, it means trigger frame is received,so continue U-APSD by - sending data from remaining delivery enabled queues*/ - spin_lock_irqsave(&priv->staRecord_lock,lock_flags); - staInfo->uapsdActive = TRUE; - staInfo->uapsdSuspended = FALSE; - spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags); - uf_continue_uapsd(priv,staInfo); - } - } - -} -void uf_store_directed_ma_packet_referenece(unifi_priv_t *priv, bulk_data_param_t *bulkdata, - CSR_SIGNAL *sigptr, CsrUint32 alignOffset) -{ - - maPktReqList_t *maPktreq = NULL; - CSR_MA_PACKET_REQUEST *req = &sigptr->u.MaPacketRequest; - CsrWifiRouterCtrlStaInfo_t *staRecord = NULL; - CsrUint16 frmCtrl,interfaceTag = 0; - const CsrUint8* macHdrLocation; - struct sk_buff *skb ; - unsigned long lock_flags; - netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag]; - CsrUint8 *sigbuffer; - CsrUint8 frameType = 0; - func_enter(); - - if(bulkdata == NULL || (0 == bulkdata->d[0].data_length )){ - unifi_trace (priv, UDBG3, "uf_store_directed_ma_packet_referenece:bulk data NULL \n"); - func_exit(); - return; - } - macHdrLocation = bulkdata->d[0].os_data_ptr; - skb = (struct sk_buff*)bulkdata->d[0].os_net_buf_ptr; - /* fectch the frame control value from mac header */ - frmCtrl = CSR_GET_UINT16_FROM_LITTLE_ENDIAN(macHdrLocation); - - /* Processing done according to Frame/Packet type */ - frameType = ((frmCtrl & 0x000c) >> FRAME_CONTROL_TYPE_FIELD_OFFSET); - - if( (((frmCtrl & 0xff) == IEEE802_11_FC_TYPE_QOS_NULL) || - ((frmCtrl & 0xff) == IEEE802_11_FC_TYPE_NULL ) ) || - ( IEEE802_11_FRAMETYPE_MANAGEMENT== frameType)){ - - /* if packet is NULL or Qos Null no need of retransmit so dont queue it*/ - unifi_trace (priv, UDBG3, "uf_store_directed_ma_packet_referenece: NULL data Pkt or mgmt\n"); - func_exit(); - return; - } - - /* fetch the station record for corresponding peer mac address */ - if ((staRecord = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv, req->Ra.x, interfaceTag))) { - maPktreq = (maPktReqList_t*)kmalloc(sizeof(maPktReqList_t),GFP_ATOMIC); - if(maPktreq == NULL){ - unifi_error(priv, - "uf_store_directed_ma_packet_referenece :: Failed to allocate %d byter for maPktreq\n", - sizeof(maPktReqList_t)); - func_exit(); - return; + &&staInfo->uapsdActive && staInfo->uspSuspend) { + /* U-APSD Still active & previously suspended either ENOSPC of FH queues OR + * due to DTIM activity + */ + uf_handle_uspframes_delivery(priv, staInfo, interfaceTag); + } else { + unifi_trace(priv, UDBG2, "resume_suspended_uapsd: PS state=%x, uapsdActive?=%x, suspend?=%x\n", + staInfo->currentPeerState, staInfo->uapsdActive, staInfo->uspSuspend); + if (staInfo->currentPeerState == CSR_WIFI_ROUTER_CTRL_PEER_CONNECTED_ACTIVE) + { + spin_lock_irqsave(&priv->staRecord_lock,lock_flags); + staInfo->uapsdActive = FALSE; + staInfo->uspSuspend = FALSE; + spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags); + } } } - - /* staRecord not present that means packet is multicast or generic mgmt so no need to queue it */ - else{ - unifi_trace (priv, UDBG3, "uf_store_directed_ma_packet_referenece: multicast pkt \n"); - func_exit(); - return ; - } - - /* disbale preemption */ - spin_lock_irqsave(&priv->tx_q_lock,lock_flags); - INIT_LIST_HEAD(&maPktreq->q); - maPktreq->staHandler = staRecord->assignedHandle; - memcpy(&maPktreq->signal,sigptr,sizeof(CSR_SIGNAL_PRIMITIVE_HEADER) + sizeof(CSR_MA_PACKET_REQUEST)); - sigbuffer = (CsrUint8*)&maPktreq->signal; - sigbuffer[SIZEOF_SIGNAL_HEADER + 1] = alignOffset; - maPktreq->skb = skb_get(skb); - maPktreq->hostTag = req->HostTag; - maPktreq->jiffeTime = jiffies; - list_add_tail(&maPktreq->q,&interfacePriv->directedMaPktReq); - - spin_unlock_irqrestore(&priv->tx_q_lock,lock_flags); - func_exit(); - + unifi_trace(priv, UDBG2, "--resume_suspended_uapsd:\n"); } #endif |