mirror of
https://github.com/open-sdr/openwifi.git
synced 2025-04-12 13:17:59 +00:00
The improved tx queue handling mechanism between openwifi_tx() and openwifi_tx_interrupt():
1. Consider more corner cases: interrupt missing will cause a bd in the driver ring will never be cleaned. this need to be considered in the openwifi_tx() 2. Another corner case in openwifi_tx_interrupt: a packet is just sent and an interrupt calls the routine, but it finds that the bd in the driver ring has been cleared somehow 3. The driver ring and FPGA queue are always 1 on 1 mapping. User needs to map the higher level Linux priority to the driver ring idx instead of FPGA queue idx 4. Record the information about which FPGA queue (driver ring) has stopped which Linux priority before, and do exhausted search after a packet is sent (in the interrupt routine) to wake that Linux priority queue (in mac80211) up 5. Reserve more room before the FPGA queue full to adopt the last packet before we decide to stop the mac80211 queue. In this way, the last packet before the queue stop will still be put into FPGA and is expected to be sent (not lost/drop actively)
This commit is contained in:
parent
2c78ef135f
commit
8b7c849019
216
driver/sdr.c
216
driver/sdr.c
@ -273,7 +273,7 @@ static int openwifi_init_tx_ring(struct openwifi_priv *priv, int ring_idx)
|
||||
struct openwifi_ring *ring = &(priv->tx_ring[ring_idx]);
|
||||
int i;
|
||||
|
||||
ring->stop_flag = 0;
|
||||
ring->stop_flag = -1;
|
||||
ring->bd_wr_idx = 0;
|
||||
ring->bd_rd_idx = 0;
|
||||
ring->bds = kmalloc(sizeof(struct openwifi_buffer_descriptor)*NUM_TX_BD,GFP_KERNEL);
|
||||
@ -283,10 +283,12 @@ static int openwifi_init_tx_ring(struct openwifi_priv *priv, int ring_idx)
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_TX_BD; i++) {
|
||||
ring->bds[i].skb_linked=0; // for tx, skb is from upper layer
|
||||
ring->bds[i].skb_linked=NULL; // for tx, skb is from upper layer
|
||||
//at first right after skb allocated, head, data, tail are the same.
|
||||
ring->bds[i].dma_mapping_addr = 0; // for tx, mapping is done after skb is received from upper layer in tx routine
|
||||
ring->bds[i].seq_no = 0;
|
||||
ring->bds[i].seq_no = 0xffff; // invalid value
|
||||
ring->bds[i].prio = 0xff; // invalid value
|
||||
ring->bds[i].len_mpdu = 0; // invalid value
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -297,7 +299,7 @@ static void openwifi_free_tx_ring(struct openwifi_priv *priv, int ring_idx)
|
||||
struct openwifi_ring *ring = &(priv->tx_ring[ring_idx]);
|
||||
int i;
|
||||
|
||||
ring->stop_flag = 0;
|
||||
ring->stop_flag = -1;
|
||||
ring->bd_wr_idx = 0;
|
||||
ring->bd_rd_idx = 0;
|
||||
for (i = 0; i < NUM_TX_BD; i++) {
|
||||
@ -312,9 +314,11 @@ static void openwifi_free_tx_ring(struct openwifi_priv *priv, int ring_idx)
|
||||
printk("%s openwifi_free_tx_ring: WARNING ring %d i %d skb_linked %p dma_mapping_addr %08x\n", sdr_compatible_str,
|
||||
ring_idx, i, (void*)(ring->bds[i].skb_linked), (unsigned int)(ring->bds[i].dma_mapping_addr));
|
||||
|
||||
ring->bds[i].skb_linked=0;
|
||||
ring->bds[i].skb_linked=NULL;
|
||||
ring->bds[i].dma_mapping_addr = 0;
|
||||
ring->bds[i].seq_no = 0;
|
||||
ring->bds[i].seq_no = 0xffff; // invalid value
|
||||
ring->bds[i].prio = 0xff; // invalid value
|
||||
ring->bds[i].len_mpdu = 0; // invalid value
|
||||
}
|
||||
if (ring->bds)
|
||||
kfree(ring->bds);
|
||||
@ -552,16 +556,17 @@ static irqreturn_t openwifi_tx_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct ieee80211_hw *dev = dev_id;
|
||||
struct openwifi_priv *priv = dev->priv;
|
||||
struct openwifi_ring *ring;
|
||||
struct openwifi_ring *ring, *drv_ring_tmp;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_tx_info *info;
|
||||
u32 reg_val1, hw_queue_len, reg_val2, prio, queue_idx, dma_fifo_no_room_flag, num_slot_random, cw, loop_count=0;
|
||||
struct ieee80211_hdr *hdr;
|
||||
u32 reg_val1, hw_queue_len, reg_val2, dma_fifo_no_room_flag, num_slot_random, cw, loop_count=0, addr1_low32, mcs_for_sysfs;
|
||||
u16 seq_no, pkt_cnt, blk_ack_ssn, start_idx;
|
||||
u8 nof_retx=-1, last_bd_rd_idx, i;
|
||||
u8 nof_retx=-1, last_bd_rd_idx, i, prio, queue_idx, nof_retx_stat;
|
||||
u64 blk_ack_bitmap;
|
||||
// u16 prio_rd_idx_store[64]={0};
|
||||
bool tx_fail=false;
|
||||
bool use_ht_aggr;
|
||||
bool tx_fail=false, fpga_queue_has_room=false;
|
||||
bool use_ht_aggr, pkt_need_ack, use_ht_rate, prio_wake_up_flag = false;
|
||||
|
||||
spin_lock(&priv->lock);
|
||||
|
||||
@ -585,27 +590,49 @@ static irqreturn_t openwifi_tx_interrupt(int irq, void *dev_id)
|
||||
pkt_cnt = (reg_val2&0x3F);
|
||||
blk_ack_ssn = ((reg_val2>>6)&0xFFF);
|
||||
|
||||
ring = &(priv->tx_ring[prio]);
|
||||
queue_idx = ((reg_val1>>15)&(MAX_NUM_HW_QUEUE-1));
|
||||
dma_fifo_no_room_flag = tx_intf_api->TX_INTF_REG_S_AXIS_FIFO_NO_ROOM_read();
|
||||
hw_queue_len = tx_intf_api->TX_INTF_REG_QUEUE_FIFO_DATA_COUNT_read();
|
||||
// check which linux prio is stopped by this queue (queue_idx)
|
||||
for (i=0; i<MAX_NUM_SW_QUEUE; i++) {
|
||||
drv_ring_tmp = &(priv->tx_ring[i]);
|
||||
if ( drv_ring_tmp->stop_flag == prio ) {
|
||||
|
||||
if ( ring->stop_flag == 1) {
|
||||
// Wake up Linux queue if FPGA and driver ring have room
|
||||
queue_idx = ((reg_val1>>15)&(MAX_NUM_HW_QUEUE-1));
|
||||
dma_fifo_no_room_flag = tx_intf_api->TX_INTF_REG_S_AXIS_FIFO_NO_ROOM_read();
|
||||
hw_queue_len = tx_intf_api->TX_INTF_REG_QUEUE_FIFO_DATA_COUNT_read();
|
||||
if ( ((dma_fifo_no_room_flag>>i)&1)==0 && (NUM_TX_BD-((hw_queue_len>>(i*8))&0xFF))>=RING_ROOM_THRESHOLD )
|
||||
fpga_queue_has_room=true;
|
||||
else
|
||||
fpga_queue_has_room=false;
|
||||
|
||||
if ( ((dma_fifo_no_room_flag>>queue_idx)&1)==0 && (NUM_TX_BD-((hw_queue_len>>(queue_idx*8))&0xFF))>=RING_ROOM_THRESHOLD ) {
|
||||
// printk("%s openwifi_tx_interrupt: WARNING ieee80211_wake_queue loop %d call %d\n", sdr_compatible_str, loop_count, priv->call_counter);
|
||||
printk("%s openwifi_tx_interrupt: WARNING ieee80211_wake_queue prio %d queue %d no room flag %x hw queue len %08x wr %d rd %d\n", sdr_compatible_str,
|
||||
prio, queue_idx, dma_fifo_no_room_flag, hw_queue_len, ring->bd_wr_idx, last_bd_rd_idx);
|
||||
ieee80211_wake_queue(dev, prio);
|
||||
ring->stop_flag = 0;
|
||||
// Wake up Linux queue due to the current fpga queue releases some room
|
||||
if( priv->drv_tx_reg_val[DRV_TX_REG_IDX_PRINT_CFG]&DMESG_LOG_NORMAL_QUEUE_STOP )
|
||||
printk("%s openwifi_tx_interrupt: WARNING ieee80211_wake_queue prio%d i%d queue%d no room flag%x hwq len%08x wr%d rd%d\n", sdr_compatible_str,
|
||||
prio, i, queue_idx, dma_fifo_no_room_flag, hw_queue_len, drv_ring_tmp->bd_wr_idx, last_bd_rd_idx);
|
||||
|
||||
if (fpga_queue_has_room) {
|
||||
prio_wake_up_flag = true;
|
||||
drv_ring_tmp->stop_flag = -1;
|
||||
|
||||
} else {
|
||||
if( priv->drv_tx_reg_val[DRV_TX_REG_IDX_PRINT_CFG]&DMESG_LOG_NORMAL_QUEUE_STOP )
|
||||
printk("%s openwifi_tx_interrupt: WARNING no room! prio_wake_up_flag%d\n", sdr_compatible_str, prio_wake_up_flag);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (prio_wake_up_flag)
|
||||
ieee80211_wake_queue(dev, prio);
|
||||
|
||||
ring = &(priv->tx_ring[queue_idx]);
|
||||
for(i = 1; i <= pkt_cnt; i++)
|
||||
{
|
||||
ring->bd_rd_idx = (last_bd_rd_idx + i - pkt_cnt + 64)%64;
|
||||
seq_no = ring->bds[ring->bd_rd_idx].seq_no;
|
||||
|
||||
if (seq_no == 0xffff) {// it has been forced cleared by the openwifi_tx (due to out-of-order Tx of different queues to the air?)
|
||||
printk("%s openwifi_tx_interrupt: WARNING wr%d rd%d last_bd_rd_idx%d i%d pkt_cnt%d prio%d fpga q%d hwq len%d bd prio%d len_mpdu%d seq_no%d skb_linked%p dma_mapping_addr%llu\n", sdr_compatible_str,
|
||||
ring->bd_wr_idx, ring->bd_rd_idx, last_bd_rd_idx, i, pkt_cnt, prio, queue_idx, hw_queue_len, ring->bds[ring->bd_rd_idx].prio, ring->bds[ring->bd_rd_idx].len_mpdu, seq_no, ring->bds[ring->bd_rd_idx].skb_linked, ring->bds[ring->bd_rd_idx].dma_mapping_addr);
|
||||
continue;
|
||||
}
|
||||
|
||||
skb = ring->bds[ring->bd_rd_idx].skb_linked;
|
||||
|
||||
dma_unmap_single(priv->tx_chan->device->dev,ring->bds[ring->bd_rd_idx].dma_mapping_addr,
|
||||
@ -634,21 +661,28 @@ static irqreturn_t openwifi_tx_interrupt(int irq, void *dev_id)
|
||||
info->flags &= (~IEEE80211_TX_CTL_AMPDU);
|
||||
}
|
||||
|
||||
pkt_need_ack = (!(info->flags & IEEE80211_TX_CTL_NO_ACK));
|
||||
if (tx_fail == false)
|
||||
info->flags |= IEEE80211_TX_STAT_ACK;
|
||||
|
||||
info->status.rates[0].count = nof_retx + 1; //according to our test, the 1st rate is the most important. we only do retry on the 1st rate
|
||||
info->status.rates[1].idx = -1;
|
||||
info->status.rates[2].idx = -1;
|
||||
info->status.rates[3].idx = -1;//in mac80211.h: #define IEEE80211_TX_MAX_RATES 4
|
||||
// info->status.rates[2].idx = -1;
|
||||
// info->status.rates[3].idx = -1;//in mac80211.h: #define IEEE80211_TX_MAX_RATES 4
|
||||
info->status.antenna = priv->runtime_tx_ant_cfg;
|
||||
|
||||
if ( tx_fail && ((priv->drv_tx_reg_val[DRV_TX_REG_IDX_PRINT_CFG])&1) )
|
||||
printk("%s openwifi_tx_interrupt: WARNING pkt_no %d/%d tx_result [nof_retx %d pass %d] prio%d wr%d rd%d\n", sdr_compatible_str, i, pkt_cnt, nof_retx+1, !tx_fail, prio, ring->bd_wr_idx, ring->bd_rd_idx);
|
||||
if ( ( (!(info->flags & IEEE80211_TX_CTL_NO_ACK))||(priv->drv_tx_reg_val[DRV_TX_REG_IDX_PRINT_CFG]&4) ) && ((priv->drv_tx_reg_val[DRV_TX_REG_IDX_PRINT_CFG])&2) )
|
||||
printk("%s openwifi_tx_interrupt: tx_result [nof_retx %d pass %d] prio%d wr%d rd%d num_rand_slot %d cw %d \n", sdr_compatible_str, nof_retx+1, !tx_fail, prio, ring->bd_wr_idx, ring->bd_rd_idx, num_slot_random, cw);
|
||||
if ( ( (!pkt_need_ack)&&(priv->drv_tx_reg_val[DRV_TX_REG_IDX_PRINT_CFG]&DMESG_LOG_BROADCAST) ) || ( (pkt_need_ack)&&(priv->drv_tx_reg_val[DRV_TX_REG_IDX_PRINT_CFG]&DMESG_LOG_UNICAST) ) ){
|
||||
printk("%s openwifi_tx_interrupt: tx_result [nof_retx %d pass %d] SC%d prio%d q%d wr%d rd%d num_slot%d cw%d hwq len%08x no_room_flag%x\n", sdr_compatible_str,
|
||||
nof_retx+1, !tx_fail, seq_no, prio, queue_idx, ring->bd_wr_idx, ring->bd_rd_idx, num_slot_random, cw, hw_queue_len, dma_fifo_no_room_flag);
|
||||
}
|
||||
|
||||
ieee80211_tx_status_irqsafe(dev, skb);
|
||||
|
||||
ring->bds[ring->bd_rd_idx].prio = 0xff; // invalid value
|
||||
ring->bds[ring->bd_rd_idx].len_mpdu = 0; // invalid value
|
||||
ring->bds[ring->bd_rd_idx].seq_no = 0xffff;
|
||||
ring->bds[ring->bd_rd_idx].skb_linked = NULL;
|
||||
ring->bds[ring->bd_rd_idx].dma_mapping_addr = 0;
|
||||
}
|
||||
|
||||
loop_count++;
|
||||
@ -658,7 +692,7 @@ static irqreturn_t openwifi_tx_interrupt(int irq, void *dev_id)
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if ( loop_count!=1 && ((priv->drv_tx_reg_val[DRV_TX_REG_IDX_PRINT_CFG])&1) )
|
||||
if ( loop_count!=1 && ((priv->drv_tx_reg_val[DRV_TX_REG_IDX_PRINT_CFG])&DMESG_LOG_ERROR) )
|
||||
printk("%s openwifi_tx_interrupt: WARNING loop_count %d\n", sdr_compatible_str, loop_count);
|
||||
|
||||
spin_unlock(&priv->lock);
|
||||
@ -776,6 +810,19 @@ inline __le16 gen_ht_duration_id(__le16 frame_control, __le16 aid, u8 qos_hdr, b
|
||||
return dur;
|
||||
}
|
||||
|
||||
inline void report_pkt_loss_due_to_driver_drop(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct openwifi_priv *priv = dev->priv;
|
||||
struct ieee80211_tx_info *info;
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
ieee80211_tx_info_clear_status(info);
|
||||
info->status.rates[0].count = 1;
|
||||
info->status.rates[1].idx = -1;
|
||||
info->status.antenna = priv->runtime_tx_ant_cfg;
|
||||
ieee80211_tx_status_irqsafe(dev, skb);
|
||||
}
|
||||
|
||||
static void openwifi_tx(struct ieee80211_hw *dev,
|
||||
struct ieee80211_tx_control *control,
|
||||
struct sk_buff *skb)
|
||||
@ -786,12 +833,13 @@ static void openwifi_tx(struct ieee80211_hw *dev,
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct openwifi_ring *ring = NULL;
|
||||
struct sk_buff *skb_new; // temp skb for internal use
|
||||
struct ieee80211_tx_info *info_skipped;
|
||||
dma_addr_t dma_mapping_addr;
|
||||
unsigned int i;
|
||||
unsigned int i, j, empty_bd_idx = 0;
|
||||
u16 rate_signal_value, rate_hw_value, len_mpdu, len_psdu, num_dma_symbol, len_mpdu_delim_pad=0, num_byte_pad;
|
||||
u32 num_dma_byte, addr1_low32, addr2_low32=0, addr3_low32=0, tx_config, cts_reg, phy_hdr_config;//, openofdm_state_history;
|
||||
u16 addr1_high16, addr2_high16=0, addr3_high16=0, sc, seq_no=0, cts_duration=0, cts_rate_hw_value=0, cts_rate_signal_value=0, sifs, ack_duration=0, traffic_pkt_duration, n_dbps;
|
||||
u8 pkt_need_ack, retry_limit_raw,use_short_gi,*dma_buf,retry_limit_hw_value,rc_flags,qos_hdr,prio,queue_idx;
|
||||
u8 pkt_need_ack, retry_limit_raw,use_short_gi,*dma_buf,retry_limit_hw_value,rc_flags,qos_hdr,prio,queue_idx,drv_ring_idx;
|
||||
bool drv_seqno=false, use_rts_cts, use_cts_protect, ht_aggr_start=false, use_ht_rate, use_ht_aggr, cts_use_traffic_rate=false, force_use_cts_protect=false;
|
||||
__le16 frame_control,duration_id;
|
||||
u32 dma_fifo_no_room_flag, hw_queue_len, delay_count=0;
|
||||
@ -833,23 +881,73 @@ static void openwifi_tx(struct ieee80211_hw *dev,
|
||||
}
|
||||
|
||||
addr1_low32 = *((u32*)(hdr->addr1+2));
|
||||
ring = &(priv->tx_ring[prio]);
|
||||
|
||||
// -------------- DO your idea here! Map Linux/SW "prio" to hardware "queue_idx" -----------
|
||||
// ---- DO your idea here! Map Linux/SW "prio" to driver "drv_ring_idx" (then 1on1 to FPGA queue_idx) ---
|
||||
if (priv->slice_idx == 0xFFFFFFFF) {// use Linux default prio setting, if there isn't any slice config
|
||||
queue_idx = prio;
|
||||
} else {// customized prio to queue_idx mapping
|
||||
//if (fc_type==2 && fc_subtype==0 && (!addr_flag)) { // for unicast data packet only
|
||||
drv_ring_idx = prio;
|
||||
} else {// customized prio to drv_ring_idx mapping
|
||||
// check current packet belonging to which slice/hw-queue
|
||||
for (i=0; i<MAX_NUM_HW_QUEUE; i++) {
|
||||
if ( priv->dest_mac_addr_queue_map[i] == addr1_low32 ) {
|
||||
break;
|
||||
}
|
||||
for (i=0; i<MAX_NUM_HW_QUEUE; i++) {
|
||||
if ( priv->dest_mac_addr_queue_map[i] == addr1_low32 ) {
|
||||
break;
|
||||
}
|
||||
//}
|
||||
queue_idx = (i>=MAX_NUM_HW_QUEUE?2:i); // if no address is hit, use FPGA queue 2. because the queue 2 is the longest.
|
||||
}
|
||||
drv_ring_idx = (i>=MAX_NUM_HW_QUEUE?prio:i); // if no address is hit
|
||||
}
|
||||
// -------------------- end of Map Linux/SW "prio" to hardware "queue_idx" ------------------
|
||||
|
||||
ring = &(priv->tx_ring[drv_ring_idx]);
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
if (ring->bds[ring->bd_wr_idx].seq_no != 0xffff) { // not cleared yet by interrupt
|
||||
for (i=1; i<NUM_TX_BD; i++) {
|
||||
if (ring->bds[(ring->bd_wr_idx+i)&(NUM_TX_BD-1)].seq_no == 0xffff) {
|
||||
empty_bd_idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
hw_queue_len = tx_intf_api->TX_INTF_REG_QUEUE_FIFO_DATA_COUNT_read();
|
||||
if (empty_bd_idx) { // clear all bds before the empty bd and report failure to Linux
|
||||
for (i=0; i<empty_bd_idx; i++) {
|
||||
j = ( (ring->bd_wr_idx+i)&(NUM_TX_BD-1) );
|
||||
printk("%s openwifi_tx: WARNING fake stop queue empty_bd_idx%d i%d lnx prio%d map to q%d stop%d hwq len%d wr%d rd%d bd prio%d len_mpdu%d seq_no%d skb_linked%p dma_mapping_addr%llu\n", sdr_compatible_str,
|
||||
empty_bd_idx, i, prio, drv_ring_idx, ring->stop_flag, hw_queue_len, ring->bd_wr_idx, ring->bd_rd_idx, ring->bds[j].prio, ring->bds[j].len_mpdu, ring->bds[j].seq_no, ring->bds[j].skb_linked, ring->bds[j].dma_mapping_addr);
|
||||
// tell Linux this skb failed
|
||||
skb_new = ring->bds[j].skb_linked;
|
||||
dma_unmap_single(priv->tx_chan->device->dev,ring->bds[j].dma_mapping_addr,
|
||||
skb_new->len, DMA_MEM_TO_DEV);
|
||||
info_skipped = IEEE80211_SKB_CB(skb_new);
|
||||
ieee80211_tx_info_clear_status(info_skipped);
|
||||
info_skipped->status.rates[0].count = 1;
|
||||
info_skipped->status.rates[1].idx = -1;
|
||||
info_skipped->status.antenna = priv->runtime_tx_ant_cfg;
|
||||
ieee80211_tx_status_irqsafe(dev, skb_new);
|
||||
|
||||
ring->bds[j].prio = 0xff; // invalid value
|
||||
ring->bds[j].len_mpdu = 0; // invalid value
|
||||
ring->bds[j].seq_no = 0xffff;
|
||||
ring->bds[j].skb_linked = NULL;
|
||||
ring->bds[j].dma_mapping_addr = 0;
|
||||
|
||||
}
|
||||
if (ring->stop_flag != -1) { //the interrupt seems will never come, we need to wake up the queue in case the interrupt will never wake it up
|
||||
ieee80211_wake_queue(dev, ring->stop_flag);
|
||||
ring->stop_flag = -1;
|
||||
}
|
||||
} else {
|
||||
j = ring->bd_wr_idx;
|
||||
printk("%s openwifi_tx: WARNING real stop queue lnx prio%d map to q%d stop%d hwq len%d wr%d rd%d bd prio%d len_mpdu%d seq_no%d skb_linked%p dma_mapping_addr%llu\n", sdr_compatible_str,
|
||||
prio, drv_ring_idx, ring->stop_flag, hw_queue_len, ring->bd_wr_idx, ring->bd_rd_idx, ring->bds[j].prio, ring->bds[j].len_mpdu, ring->bds[j].seq_no, ring->bds[j].skb_linked, ring->bds[j].dma_mapping_addr);
|
||||
|
||||
ieee80211_stop_queue(dev, prio); // here we should stop those prio related to the queue idx flag set in TX_INTF_REG_S_AXIS_FIFO_NO_ROOM_read
|
||||
ring->stop_flag = prio;
|
||||
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
goto openwifi_tx_early_out;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
// -------------------- end of Map Linux/SW "prio" to driver "drv_ring_idx" ------------------
|
||||
|
||||
// get other info from packet header
|
||||
addr1_high16 = *((u16*)(hdr->addr1));
|
||||
if (len_mpdu>=20) {
|
||||
@ -1007,11 +1105,11 @@ static void openwifi_tx(struct ieee80211_hw *dev,
|
||||
}
|
||||
num_dma_symbol = (len_psdu>>TX_INTF_NUM_BYTE_PER_DMA_SYMBOL_IN_BITS) + ((len_psdu&(TX_INTF_NUM_BYTE_PER_DMA_SYMBOL-1))!=0);
|
||||
|
||||
if ( ( (!pkt_need_ack)||(priv->drv_tx_reg_val[DRV_TX_REG_IDX_PRINT_CFG]&4) ) && (priv->drv_tx_reg_val[DRV_TX_REG_IDX_PRINT_CFG]&2) )
|
||||
printk("%s openwifi_tx: %4dbytes ht%d aggr%d %3dM FC%04x DI%04x addr1/2/3:%04x%08x/%04x%08x/%04x%08x SC%04x flag%08x retr%d ack%d prio%d q%d wr%d rd%d\n", sdr_compatible_str,
|
||||
len_mpdu, (use_ht_rate == false ? 0 : 1), (use_ht_aggr == false ? 0 : 1), (use_ht_rate == false ? wifi_rate_all[rate_hw_value] : wifi_rate_all[rate_hw_value + 12]),frame_control,duration_id,
|
||||
if ( ( (!pkt_need_ack)&&(priv->drv_tx_reg_val[DRV_TX_REG_IDX_PRINT_CFG]&DMESG_LOG_BROADCAST) ) || ( (pkt_need_ack)&&(priv->drv_tx_reg_val[DRV_TX_REG_IDX_PRINT_CFG]&DMESG_LOG_UNICAST) ) )
|
||||
printk("%s openwifi_tx: %dB RC%x %dM FC%04x DI%04x ADDR%04x%08x/%04x%08x/%04x%08x flag%08x QoS%02x SC%d_%d retr%d ack%d prio%d q%d wr%d rd%d\n", sdr_compatible_str,
|
||||
len_mpdu, rc_flags, (use_ht_rate == false ? wifi_rate_all[rate_hw_value] : wifi_rate_all[rate_hw_value + 12]),frame_control,duration_id,
|
||||
reverse16(addr1_high16), reverse32(addr1_low32), reverse16(addr2_high16), reverse32(addr2_low32), reverse16(addr3_high16), reverse32(addr3_low32),
|
||||
seq_no, info->flags, retry_limit_raw, pkt_need_ack, prio, queue_idx,
|
||||
info->flags, qos_hdr, seq_no, drv_seqno, retry_limit_raw, pkt_need_ack, prio, drv_ring_idx,
|
||||
// use_rts_cts,use_cts_protect|force_use_cts_protect,wifi_rate_all[cts_rate_hw_value],cts_duration,
|
||||
ring->bd_wr_idx,ring->bd_rd_idx);
|
||||
|
||||
@ -1100,6 +1198,8 @@ static void openwifi_tx(struct ieee80211_hw *dev,
|
||||
|
||||
retry_limit_hw_value = ( retry_limit_raw==0?0:((retry_limit_raw - 1)&0xF) );
|
||||
|
||||
queue_idx = drv_ring_idx; // from driver ring idx to FPGA queue_idx mapping
|
||||
|
||||
cts_rate_signal_value = wifi_mcs_table_11b_force_up[cts_rate_hw_value];
|
||||
cts_reg = ((use_cts_protect|force_use_cts_protect)<<31 | cts_use_traffic_rate<<30 | cts_duration<<8 | cts_rate_signal_value<<4 | rate_signal_value);
|
||||
tx_config = ( prio<<26 | ring->bd_wr_idx<<20 | queue_idx<<18 | retry_limit_hw_value<<14 | pkt_need_ack<<13 | num_dma_symbol );
|
||||
@ -1121,12 +1221,14 @@ static void openwifi_tx(struct ieee80211_hw *dev,
|
||||
// -------------check whether FPGA dma fifo and queue (queue_idx) has enough room-------------
|
||||
dma_fifo_no_room_flag = tx_intf_api->TX_INTF_REG_S_AXIS_FIFO_NO_ROOM_read();
|
||||
hw_queue_len = tx_intf_api->TX_INTF_REG_QUEUE_FIFO_DATA_COUNT_read();
|
||||
if ( ((dma_fifo_no_room_flag>>queue_idx)&1) || ((NUM_TX_BD-((hw_queue_len>>(queue_idx*8))&0xFF))<RING_ROOM_THRESHOLD) || ring->stop_flag==1 ) {
|
||||
if ( ((dma_fifo_no_room_flag>>queue_idx)&1) || ((NUM_TX_BD-((hw_queue_len>>(queue_idx*8))&0xFF))<=RING_ROOM_THRESHOLD) || ring->stop_flag>=0 ) {
|
||||
if( priv->drv_tx_reg_val[DRV_TX_REG_IDX_PRINT_CFG]&DMESG_LOG_NORMAL_QUEUE_STOP )
|
||||
printk("%s openwifi_tx: WARNING ieee80211_stop_queue prio%d queue%d no room flag%x hwq len%08x request%d wr%d rd%d\n", sdr_compatible_str,
|
||||
prio, queue_idx, dma_fifo_no_room_flag, hw_queue_len, num_dma_symbol, ring->bd_wr_idx, ring->bd_rd_idx);
|
||||
|
||||
ieee80211_stop_queue(dev, prio); // here we should stop those prio related to the queue idx flag set in TX_INTF_REG_S_AXIS_FIFO_NO_ROOM_read
|
||||
printk("%s openwifi_tx: WARNING ieee80211_stop_queue prio %d queue %d no room flag %x hw queue len %08x request %d wr %d rd %d\n", sdr_compatible_str,
|
||||
prio, queue_idx, dma_fifo_no_room_flag, hw_queue_len, num_dma_symbol, ring->bd_wr_idx, ring->bd_rd_idx);
|
||||
ring->stop_flag = 1;
|
||||
goto openwifi_tx_early_out_after_lock;
|
||||
ring->stop_flag = prio;
|
||||
// goto openwifi_tx_early_out_after_lock;
|
||||
}
|
||||
// --------end of check whether FPGA fifo (queue_idx) has enough room------------
|
||||
|
||||
@ -1173,6 +1275,8 @@ static void openwifi_tx(struct ieee80211_hw *dev,
|
||||
}
|
||||
|
||||
// seems everything is ok. let's mark this pkt in bd descriptor ring
|
||||
ring->bds[ring->bd_wr_idx].prio = prio;
|
||||
ring->bds[ring->bd_wr_idx].len_mpdu = len_mpdu;
|
||||
ring->bds[ring->bd_wr_idx].seq_no = seq_no;
|
||||
ring->bds[ring->bd_wr_idx].skb_linked = skb;
|
||||
ring->bds[ring->bd_wr_idx].dma_mapping_addr = dma_mapping_addr;
|
||||
@ -1189,13 +1293,15 @@ openwifi_tx_after_dma_mapping:
|
||||
dma_unmap_single(priv->tx_chan->device->dev, dma_mapping_addr, num_dma_byte, DMA_MEM_TO_DEV);
|
||||
|
||||
openwifi_tx_early_out_after_lock:
|
||||
dev_kfree_skb(skb);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
report_pkt_loss_due_to_driver_drop(dev, skb);
|
||||
// dev_kfree_skb(skb);
|
||||
// printk("%s openwifi_tx: WARNING openwifi_tx_after_dma_mapping phy_tx_sn %d queue %d\n", sdr_compatible_str,priv->phy_tx_sn,queue_idx);
|
||||
return;
|
||||
|
||||
openwifi_tx_early_out:
|
||||
//dev_kfree_skb(skb);
|
||||
report_pkt_loss_due_to_driver_drop(dev, skb);
|
||||
// dev_kfree_skb(skb);
|
||||
// printk("%s openwifi_tx: WARNING openwifi_tx_early_out phy_tx_sn %d queue %d\n", sdr_compatible_str,priv->phy_tx_sn,queue_idx);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user