G_LIKELY 和G_UNLIKELY

  1. #define G_LIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 1))  
  2. #define G_UNLIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 0))  
if (__builtin_expect (x, 0))的目的只是告诉编译器我们期望表达式x的值为0,这样其实是告诉编译器我们不期望if 紧接着的语句被执行,而是期望else后面的语句被执行,这样编译器就会帮我们把else后面的语句优化到if语句的后面
同理if (__builtin_expect (x, 1))的目的只是告诉编译器我们期望表达式x的值为1,即期望if紧接着的语句被执行。
static bool wlan_dcs_wlan_interference_process( struct wlan_host_dcs_im_tgt_stats *curr_stats, struct dcs_pdev_priv_obj *dcs_pdev_priv) { struct wlan_host_dcs_im_tgt_stats *prev_stats; struct pdev_dcs_params dcs_host_params; struct pdev_dcs_im_stats *p_dcs_im_stats; bool start_dcs_cbk_handler = false; uint32_t reg_tsf_delta = 0; uint32_t scaled_reg_tsf_delta; uint32_t rxclr_delta = 0; uint32_t rxclr_ext_delta = 0; uint32_t cycle_count_delta = 0; uint32_t scaled_cycle_count_delta; uint32_t tx_frame_delta = 0; uint32_t rx_frame_delta = 0; uint32_t my_bss_rx_delta = 0; uint32_t reg_total_cu = 0; uint32_t reg_tx_cu = 0; uint32_t reg_rx_cu = 0; uint32_t obss_rx_cu = 0; uint32_t reg_unused_cu = 0; uint32_t rx_time_cu = 0; uint32_t reg_ofdm_phyerr_delta = 0; uint32_t reg_cck_phyerr_delta = 0; uint32_t reg_ofdm_phyerr_cu = 0; uint32_t ofdm_phy_err_rate = 0; uint32_t cck_phy_err_rate = 0; uint32_t max_phy_err_rate = 0; uint32_t max_phy_err_count = 0; uint32_t total_wasted_cu = 0; uint32_t wasted_tx_cu = 0; uint32_t tx_err = 0; uint32_t too_many_phy_errors = 0; if (!curr_stats) { dcs_err("curr_stats is NULL"); goto end; } if (!dcs_pdev_priv) { dcs_err("dcs pdev private object is NULL"); goto end; } dcs_host_params = dcs_pdev_priv->dcs_host_params; p_dcs_im_stats = &dcs_pdev_priv->dcs_im_stats; prev_stats = &dcs_pdev_priv->dcs_im_stats.prev_dcs_im_stats; if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) wlan_dcs_im_print_stats(prev_stats, curr_stats); /* * Counters would have wrapped. Ideally we should be able to figure this * out, but we never know how many times counters wrapped, just ignore. */ if ((curr_stats->mib_stats.listen_time <= 0) || (curr_stats->reg_tsf32 <= prev_stats->reg_tsf32)) { if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) dcs_debug("ignoring due to negative TSF value"); goto copy_stats; } reg_tsf_delta = curr_stats->reg_tsf32 - prev_stats->reg_tsf32; /* * Do nothing if current stats are not seeming good, probably * a reset happened on chip, force cleared */ if (prev_stats->mib_stats.reg_rxclr_cnt > curr_stats->mib_stats.reg_rxclr_cnt) { if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) dcs_debug("ignoring due to negative rxclr count"); goto copy_stats; } rxclr_delta = curr_stats->mib_stats.reg_rxclr_cnt - prev_stats->mib_stats.reg_rxclr_cnt; rxclr_ext_delta = curr_stats->mib_stats.reg_rxclr_ext_cnt - prev_stats->mib_stats.reg_rxclr_ext_cnt; tx_frame_delta = curr_stats->mib_stats.reg_tx_frame_cnt - prev_stats->mib_stats.reg_tx_frame_cnt; rx_frame_delta = curr_stats->mib_stats.reg_rx_frame_cnt - prev_stats->mib_stats.reg_rx_frame_cnt; cycle_count_delta = curr_stats->mib_stats.reg_cycle_cnt - prev_stats->mib_stats.reg_cycle_cnt; my_bss_rx_delta = curr_stats->my_bss_rx_cycle_count - prev_stats->my_bss_rx_cycle_count; if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) dcs_debug("rxclr_delta: %u, rxclr_ext_delta: %u, tx_frame_delta: %u, rx_frame_delta: %u, cycle_count_delta: %u, my_bss_rx_delta: %u", rxclr_delta, rxclr_ext_delta, tx_frame_delta, rx_frame_delta, cycle_count_delta, my_bss_rx_delta); /* Update user stats */ wlan_dcs_pdev_obj_lock(dcs_pdev_priv); if (dcs_pdev_priv->dcs_host_params.user_request_count) { struct wlan_host_dcs_im_user_stats *p_user_stats = &p_dcs_im_stats->user_dcs_im_stats; p_user_stats->cycle_count += cycle_count_delta; p_user_stats->rxclr_count += rxclr_delta; p_user_stats->rx_frame_count += rx_frame_delta; p_user_stats->my_bss_rx_cycle_count += my_bss_rx_delta; if (0 == p_user_stats->max_rssi && 0 == p_user_stats->min_rssi) { p_user_stats->max_rssi = curr_stats->last_ack_rssi; p_user_stats->min_rssi = curr_stats->last_ack_rssi; } else { if (curr_stats->last_ack_rssi > p_user_stats->max_rssi) p_user_stats->max_rssi = curr_stats->last_ack_rssi; if (curr_stats->last_ack_rssi < p_user_stats->min_rssi) p_user_stats->min_rssi = curr_stats->last_ack_rssi; } dcs_pdev_priv->dcs_host_params.user_request_count--; if (0 == dcs_pdev_priv->dcs_host_params.user_request_count) dcs_pdev_priv->dcs_host_params.notify_user = 1; } wlan_dcs_pdev_obj_unlock(dcs_pdev_priv); /* * Total channel utiliztaion is the amount of time RXCLR is * counted. RXCLR is counted, when 'RX is NOT clear', please * refer to mac documentation. It means either TX or RX is ON * * Why shift by 8 ? after multiplication it could overflow. At one * second rate, normally neither cycle_count_delta nor the tsf_delta * would be zero after shift by 8 bits. In corner case, host resets * dcs stats, and at the same time tsf counters is wrapped. * Then all the variable in prev_stats are 0, and the variable in * curr_stats may be a small value, so add check for cycle_count_delta * and the tsf_delta after shift by 8 bits. */ scaled_cycle_count_delta = cycle_count_delta >> 8; scaled_reg_tsf_delta = reg_tsf_delta >> 8; if (!scaled_cycle_count_delta || !scaled_reg_tsf_delta) { if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) dcs_debug("cycle count or TSF NULL --Investigate--"); goto copy_stats; } reg_total_cu = ((rxclr_delta >> 8) * 100) / scaled_cycle_count_delta; reg_tx_cu = ((tx_frame_delta >> 8) * 100) / scaled_cycle_count_delta; reg_rx_cu = ((rx_frame_delta >> 8) * 100) / scaled_cycle_count_delta; rx_time_cu = ((curr_stats->rx_time >> 8) * 100) / scaled_reg_tsf_delta; obss_rx_cu = (((rx_frame_delta - my_bss_rx_delta) >> 8) * 100) / scaled_cycle_count_delta; wlan_dcs_update_chan_util(p_dcs_im_stats, reg_rx_cu, reg_tx_cu, obss_rx_cu, reg_total_cu, curr_stats->chan_nf); /* * Amount of the time AP received cannot go higher than the receive * cycle count delta. If at all it is, there should have been a * computation error, ceil it to receive_cycle_count_diff */ if (rx_time_cu > reg_rx_cu) rx_time_cu = reg_rx_cu; if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) dcs_debug("reg_total_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u, rx_time_cu: %u, obss_rx_cu: %u dcs_algorithm: %d", reg_total_cu, reg_tx_cu, reg_rx_cu, rx_time_cu, obss_rx_cu, dcs_host_params.dcs_algorithm_process); /* * For below scenario, will ignore dcs event data and won't do * interference detection algorithm calculation: * 1: Current SAP channel isn't on 5G band * 2: In the process of ACS * 3: In the process of dcs disabling dcs_restart_delay time duration */ if (!dcs_host_params.dcs_algorithm_process) goto copy_stats; /* * Unusable channel utilization is amount of time that we * spent in backoff or waiting for other transmit/receive to * complete. If there is interference it is more likely that * we overshoot the limit. In case of multiple stations, we * still see increased channel utilization. This assumption may * not be true for the VOW scenario where either multicast or * unicast-UDP is used ( mixed traffic would still cause high * channel utilization). */ wasted_tx_cu = ((curr_stats->tx_waste_time >> 8) * 100) / scaled_reg_tsf_delta; /* * Transmit channel utilization cannot go higher than the amount of time * wasted, if so cap the wastage to transmit channel utillzation. This * could happen to compution error. */ if (reg_tx_cu < wasted_tx_cu) wasted_tx_cu = reg_tx_cu; tx_err = (reg_tx_cu && wasted_tx_cu) ? (wasted_tx_cu * 100) / reg_tx_cu : 0; /* * The below actually gives amount of time we are not using, or the * interferer is active. * rx_time_cu is what computed receive time *NOT* rx_cycle_count * rx_cycle_count is our receive+interferer's transmit * un-used is really total_cycle_counts - * (our_rx_time(rx_time_cu) + our_receive_time) */ reg_unused_cu = (reg_total_cu >= (reg_tx_cu + rx_time_cu)) ? (reg_total_cu - (reg_tx_cu + rx_time_cu)) : 0; /* If any retransmissions are there, count them as wastage */ total_wasted_cu = reg_unused_cu + wasted_tx_cu; /* Check ofdm and cck errors */ if (unlikely(curr_stats->mib_stats.reg_ofdm_phyerr_cnt < prev_stats->mib_stats.reg_ofdm_phyerr_cnt)) reg_ofdm_phyerr_delta = curr_stats->mib_stats.reg_ofdm_phyerr_cnt; else reg_ofdm_phyerr_delta = curr_stats->mib_stats.reg_ofdm_phyerr_cnt - prev_stats->mib_stats.reg_ofdm_phyerr_cnt; if (unlikely(curr_stats->mib_stats.reg_cck_phyerr_cnt < prev_stats->mib_stats.reg_cck_phyerr_cnt)) reg_cck_phyerr_delta = curr_stats->mib_stats.reg_cck_phyerr_cnt; else reg_cck_phyerr_delta = curr_stats->mib_stats.reg_cck_phyerr_cnt - prev_stats->mib_stats.reg_cck_phyerr_cnt; /* * Add the influence of ofdm phy errors to the wasted channel * utillization, this computed through time wasted in errors */ reg_ofdm_phyerr_cu = reg_ofdm_phyerr_delta * dcs_host_params.phy_err_penalty; total_wasted_cu += (reg_ofdm_phyerr_cu > 0) ? (((reg_ofdm_phyerr_cu >> 8) * 100) / scaled_reg_tsf_delta) : 0; ofdm_phy_err_rate = (curr_stats->mib_stats.reg_ofdm_phyerr_cnt * 1000) / curr_stats->mib_stats.listen_time; cck_phy_err_rate = (curr_stats->mib_stats.reg_cck_phyerr_cnt * 1000) / curr_stats->mib_stats.listen_time; if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) { dcs_debug("reg_unused_cu: %u, reg_ofdm_phyerr_delta: %u, reg_cck_phyerr_delta: %u, reg_ofdm_phyerr_cu: %u", reg_unused_cu, reg_ofdm_phyerr_delta, reg_cck_phyerr_delta, reg_ofdm_phyerr_cu); dcs_debug("total_wasted_cu: %u, ofdm_phy_err_rate: %u, cck_phy_err_rate: %u", total_wasted_cu, ofdm_phy_err_rate, cck_phy_err_rate); dcs_debug("new_unused_cu: %u, reg_ofdm_phy_error_cu: %u", reg_unused_cu, (curr_stats->mib_stats.reg_ofdm_phyerr_cnt * 100) / curr_stats->mib_stats.listen_time); } /* Check if the error rates are higher than the thresholds */ max_phy_err_rate = QDF_MAX(ofdm_phy_err_rate, cck_phy_err_rate); max_phy_err_count = QDF_MAX(curr_stats->mib_stats.reg_ofdm_phyerr_cnt, curr_stats->mib_stats.reg_cck_phyerr_cnt); if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) dcs_debug("max_phy_err_rate: %u, max_phy_err_count: %u", max_phy_err_rate, max_phy_err_count); if (((max_phy_err_rate >= dcs_host_params.phy_err_threshold) && (max_phy_err_count > dcs_host_params.phy_err_threshold)) || (curr_stats->phyerr_cnt > dcs_host_params.radar_err_threshold)) too_many_phy_errors = 1; if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_CRITICAL)) { dcs_debug("total_cu: %u, tx_cu: %u, rx_cu: %u, rx_time_cu: %u, unused cu: %u", reg_total_cu, reg_tx_cu, reg_rx_cu, rx_time_cu, reg_unused_cu); dcs_debug("phyerr: %u, total_wasted_cu: %u, phyerror_cu: %u, wasted_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u", too_many_phy_errors, total_wasted_cu, reg_ofdm_phyerr_cu, wasted_tx_cu, reg_tx_cu, reg_rx_cu); dcs_debug("tx_err: %u", tx_err); } if (reg_unused_cu >= dcs_host_params.coch_intfr_threshold) /* Quickly reach to decision */ p_dcs_im_stats->im_intfr_cnt += 2; else if (too_many_phy_errors && (((total_wasted_cu > (dcs_host_params.coch_intfr_threshold + 10)) && ((reg_tx_cu + reg_rx_cu) > dcs_host_params.user_max_cu)) || ((reg_tx_cu > DCS_TX_MAX_CU) && (tx_err >= dcs_host_params.tx_err_threshold)))) p_dcs_im_stats->im_intfr_cnt++; if (p_dcs_im_stats->im_intfr_cnt >= dcs_host_params.intfr_detection_threshold) { if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_CRITICAL)) { dcs_debug("interference threshold exceeded"); dcs_debug("unused_cu: %u, too_any_phy_errors: %u, total_wasted_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u", reg_unused_cu, too_many_phy_errors, total_wasted_cu, reg_tx_cu, reg_rx_cu); } p_dcs_im_stats->im_intfr_cnt = 0; p_dcs_im_stats->im_samp_cnt = 0; /* * Once the interference is detected, change the channel, as on * today this is common routine for wirelesslan and * non-wirelesslan interference. Name as such kept the same * because of the DA code, which is using the same function. */ start_dcs_cbk_handler = true; } else if (0 == p_dcs_im_stats->im_intfr_cnt || p_dcs_im_stats->im_samp_cnt >= dcs_host_params.intfr_detection_window) { p_dcs_im_stats->im_intfr_cnt = 0; p_dcs_im_stats->im_samp_cnt = 0; } /* Count the current run too */ p_dcs_im_stats->im_samp_cnt++; if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) dcs_debug("intfr_count: %u, sample_count: %u", p_dcs_im_stats->im_intfr_cnt, p_dcs_im_stats->im_samp_cnt); copy_stats: /* Copy the stats for next cycle */ wlan_dcs_im_copy_stats(prev_stats, curr_stats); end: return start_dcs_cbk_handler; } 请详细分析这个函数,它是如何评估干扰信道利用率的?
09-17
extern int tcp_v4_rcv(struct sk_buff *skb); #if IS_ENABLED(CONFIG_IPV6) /*even though we are checking IPV6 for both Built-in and module, * but when built as module this will casue build error as * BLOG_LOCALIN_TCP is always Built-in */ extern int tcp_v6_rcv(struct sk_buff *skb); #else int tcp_v6_rcv(struct sk_buff *skb) { /* when IPv6 is not enabled we dont expect any packets here */ BUG(); } #endif static inline struct sk_buff *bcm_find_skb_by_flowid(uint32_t flowid) { /* TODO add this function later,needed for coalescing */ return NULL; } static inline int set_skb_fields(struct sk_buff *skb, BlogFcArgs_t *fc_args) { struct net_device *dev_p; struct dst_entry *dst_p; dev_p = bcm_get_netdev_by_id_nohold(fc_args->local_rx_devid); dst_p = blog_get_dstentry_by_id(fc_args->dst_entry_id); if(!dev_p || !dst_p) return -1; skb->dev = dev_p; skb_dst_set(skb, dst_p); skb->skb_iif = dev_p->ifindex; return 0; } static inline void position_skb_ptrs_to_transport(struct sk_buff *skb, BlogFcArgs_t *fc_args) { /*initialize ip & tcp header related fields in skb */ skb_set_mac_header(skb, 0); skb_set_network_header(skb, fc_args->tx_l3_offset); skb_set_transport_header(skb, fc_args->tx_l4_offset); /*position data pointer to start of TCP hdr */ skb_pull(skb,fc_args->tx_l4_offset); skb->pkt_type = PACKET_HOST; return; } static inline struct sk_buff * __bcm_tcp_prep_skb(pNBuff_t pNBuff, BlogFcArgs_t *fc_args) { struct sk_buff *skb; if(IS_FKBUFF_PTR(pNBuff)) { FkBuff_t *fkb = PNBUFF_2_FKBUFF(pNBuff); /* Translate the fkb to skb */ /* find the skb for flowid or allocate a new skb */ skb = bcm_find_skb_by_flowid(fkb->flowid); if(!skb) { skb = skb_xlate_dp(fkb, NULL); if(!skb) { goto fail; } } skb->mark=0; skb->priority=0; } else { skb = PNBUFF_2_SKBUFF(pNBuff); /* Remove any debris in the socket control block * used by IPCB,IP6CB and TCP_SKB_CB * note: not needed for fkb's as entire skb is cleared in skb_xlate_dp above */ memset(skb->cb, 0, sizeof(skb->cb)); } if (unlikely(set_skb_fields(skb, fc_args) != 0)) goto fail; position_skb_ptrs_to_transport(skb, fc_args); return skb; fail: if (skb) dev_kfree_skb_any(skb); else nbuff_free(pNBuff); return NULL; } struct sk_buff * bcm_tcp_prep_skb(pNBuff_t pNBuff, BlogFcArgs_t *fc_args) { return __bcm_tcp_prep_skb(pNBuff, fc_args); } EXPORT_SYMBOL(bcm_tcp_prep_skb); #ifdef BCM_TCP_V4_TASK static int g_bcm_tcp_task_en = 1; typedef struct { spinlock_t lock; struct sk_buff_head input_q; struct sk_buff_head process_q; struct task_struct *task; wait_queue_head_t thread_wqh; int work_avail; } bcm_tcp_queue_t; typedef struct { struct sk_buff *skb_p; } bcm_tcp_item_t; #define TCP_RCVTSK_LOCK(_c) spin_lock_bh(&((_c)->lock)) #define TCP_RCVTSK_UNLK(_c) spin_unlock_bh(&((_c)->lock)) #define MAX_BCM_TCP_INPUT_LEN (1024) #define MAX_BCM_TCP_BUDGET (256) static bcm_tcp_queue_t bcm_tcp_async_q; #define WAKEUP_BCM_TCP_TASK() do { \ wake_up_interruptible(&(bcm_tcp_async_q.thread_wqh)); \ } while (0) static inline void __bcm_tcp_enqueue(struct sk_buff *skb) { if (skb) { bcm_tcp_queue_t *async_q = (bcm_tcp_queue_t *) (&bcm_tcp_async_q); TCP_RCVTSK_LOCK(async_q); if(likely(skb_queue_len(&(async_q->input_q))< MAX_BCM_TCP_INPUT_LEN )) { skb_queue_tail(&(async_q->input_q),skb); skb = NULL; if(!(async_q->work_avail)) { async_q->work_avail = 1; WAKEUP_BCM_TCP_TASK(); } } TCP_RCVTSK_UNLK(async_q); } if(skb) __kfree_skb(skb); } void bcm_tcp_enqueue(struct sk_buff *skb) { __bcm_tcp_enqueue(skb); } EXPORT_SYMBOL(bcm_tcp_enqueue); /* inject the packet into ipv4_tcp_stack directly from the network driver */ static inline int bcm_tcp_v4_recv_queue(pNBuff_t pNBuff, struct net_device *txdev, BlogFcArgs_t *fc_args) { struct sk_buff *skb; skb = __bcm_tcp_prep_skb(pNBuff, fc_args); if(skb) { skb->protocol = htons(ETH_P_IP); if(g_bcm_tcp_task_en) /*hand over pkt to bcm_tcp_task()*/ __bcm_tcp_enqueue(skb); else { /* * bh_disable is needed to prevent deadlock on sock_lock when TCP timers * are executed */ local_bh_disable(); tcp_v4_rcv(skb); local_bh_enable(); } } return 0; } /* inject the packet into ipv6_tcp_stack directly from the network driver */ static inline int bcm_tcp_v6_recv_queue(pNBuff_t pNBuff, struct net_device *txdev, BlogFcArgs_t *fc_args) { struct sk_buff *skb; skb = __bcm_tcp_prep_skb(pNBuff, fc_args); if(skb) { skb->protocol = htons(ETH_P_IPV6); IP6CB(skb)->iif = skb->dev->ifindex; IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); if(g_bcm_tcp_task_en) /*hand over pkt to bcm_tcp_task()*/ __bcm_tcp_enqueue(skb); else { /* * bh_disable is needed to prevent deadlock on sock_lock when TCP timers * are executed */ local_bh_disable(); tcp_v6_rcv(skb); local_bh_enable(); } } return 0; } static int bcm_tcp_recv_thread_func(void *thread_data) { unsigned int budget; struct sk_buff *skb; bcm_tcp_queue_t *async_q = NULL; async_q = (bcm_tcp_queue_t *) thread_data; while (1) { wait_event_interruptible( (async_q->thread_wqh), kthread_should_stop() || (async_q->work_avail) ); if (kthread_should_stop()) { printk(KERN_INFO "kthread_should_stop detected in wfd\n"); break; } budget = MAX_BCM_TCP_BUDGET; if(skb_queue_len(&(async_q->process_q))<= MAX_BCM_TCP_BUDGET) { TCP_RCVTSK_LOCK(async_q); if(!skb_queue_empty(&(async_q->input_q))) { skb_queue_splice_tail_init(&(async_q->input_q),&(async_q->process_q)); } TCP_RCVTSK_UNLK(async_q); } /* * bh_disable is needed to prevent deadlock on sock_lock when TCP timers * are executed */ local_bh_disable(); while(likely(budget-- && (skb = __skb_dequeue(&(async_q->process_q))) )) { if(skb->protocol == htons(ETH_P_IPV6)) tcp_v6_rcv(skb); else tcp_v4_rcv(skb); } local_bh_enable(); async_q->work_avail = (!skb_queue_empty(&(async_q->process_q))) ? 1 : 0; // No more work in process queue , double check input queue. if(!async_q->work_avail) { TCP_RCVTSK_LOCK(async_q); if(!skb_queue_empty(&(async_q->input_q))) { async_q->work_avail = 1; } TCP_RCVTSK_UNLK(async_q); } /* we still have packets in Q, reschedule the task */ if (async_q->work_avail){ schedule(); } } return 0; } struct task_struct *create_bcm_tcp_task(bcm_tcp_queue_t *async_q) { struct task_struct *tsk; int cpu_num = num_online_cpus(); unsigned int bind_mask = 0x00; spin_lock_init(&async_q->lock); async_q->work_avail = 0; init_waitqueue_head(&(async_q->thread_wqh)); skb_queue_head_init(&(async_q->input_q)); skb_queue_head_init(&(async_q->process_q)); tsk = kthread_create(bcm_tcp_recv_thread_func, async_q, "bcm_tcp_task"); if (IS_ERR(tsk)) { printk(KERN_EMERG "bcm_tcp_task creation failed\n"); return NULL; } async_q->task = tsk; //AFFINITY with non-1st (wl0) and Non-last (Archer) CORE if(cpu_num>2) { struct cpumask aff_mask; int cpuid; cpumask_clear(&aff_mask); for(cpuid = 1; cpuid<=cpu_num ;cpuid++) { if(cpuid != 1 && cpuid != cpu_num) { cpumask_or(&aff_mask,&aff_mask,(cpumask_of(cpuid-1))); bind_mask |= (1<<(cpuid-1)); } } printk(" %s:%d bind_mask:0x%X\n",__FUNCTION__,__LINE__,bind_mask); set_cpus_allowed_ptr(async_q->task,&aff_mask); } wake_up_process(tsk); printk(KERN_EMERG "bcm_tcp_task created successfully with budget %d ,cpumask:0x%X\n", MAX_BCM_TCP_BUDGET,bind_mask); return tsk; } static struct proc_dir_entry *proc_bcm_tcp_recv_dir = NULL; /* /proc/bcm_tcp_recv */ static struct proc_dir_entry *proc_bcm_tcp_recv_ops_file = NULL; /* /proc/bcm_tcp_recv/operate */ static ssize_t bcm_tcp_recv_file_write(struct file *file, const char __user *buf, size_t cnt, loff_t *ppos); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,20,0)) static const struct proc_ops bcm_tcp_recv_fops = { .proc_write = bcm_tcp_recv_file_write, }; #else static const struct file_operations bcm_tcp_recv_fops = { .owner = THIS_MODULE, .write = bcm_tcp_recv_file_write, }; #endif static ssize_t bcm_tcp_recv_file_write(struct file *file, const char __user *buf, size_t cnt, loff_t *ppos) { char input[64]=""; char ACT=' '; if(cnt < 1) return -EFAULT; if (cnt > 64) cnt = 64; if (copy_from_user(input, buf, cnt) != 0) return -EFAULT; input[cnt-1] = '\0'; /* Command format : Enable : 1 Disable : 0 */ ACT = input[0]; switch(ACT) { case '1': g_bcm_tcp_task_en= 1 ; printk("g_bcm_tcp_task_en:%d \n",g_bcm_tcp_task_en); break; case '0': g_bcm_tcp_task_en= 0; printk("g_bcm_tcp_task_en:%d \n",g_bcm_tcp_task_en); break; default: printk("g_bcm_tcp_task_en:%d \n",g_bcm_tcp_task_en); break; } return cnt; } /** * ----------------------------------------------------------------------------- * Function : initialize the proc entry * ----------------------------------------------------------------------------- */ int bcm_tcp_recv_proc_init(void) { if (!(proc_bcm_tcp_recv_dir = proc_mkdir("bcm_tcp_recv_task", NULL))) goto fail; if (!(proc_bcm_tcp_recv_ops_file = proc_create("bcm_tcp_recv_task/operate", 0644, NULL, &bcm_tcp_recv_fops))) goto fail; return 0; fail: printk("%s %s: Failed to create proc /bcm_tcp_recv_task\n", __FILE__, __FUNCTION__); remove_proc_entry("bcm_tcp_recv_task" ,NULL); return (-1); } EXPORT_SYMBOL(bcm_tcp_recv_proc_init); /** * ----------------------------------------------------------------------------- * Function : initialize the proc entry * ----------------------------------------------------------------------------- */ void bcm_tcp_recv_proc_fini(void) { remove_proc_entry("operate", proc_bcm_tcp_recv_dir); remove_proc_entry("bcm_tcp_recv", NULL); } EXPORT_SYMBOL(bcm_tcp_recv_proc_fini); static int __init bcm_tcp_init(void) { bcm_tcp_async_q.task = create_bcm_tcp_task(&bcm_tcp_async_q); if(bcm_tcp_async_q.task == NULL) BUG(); else { bcm_tcp_recv_proc_init(); } return 0; } subsys_initcall(bcm_tcp_init); #endif /* inject the packet into ipv4_tcp_stack directly from the network driver */ static inline int bcm_tcp_v4_recv(pNBuff_t pNBuff, struct net_device *txdev, BlogFcArgs_t *fc_args) { struct sk_buff *skb; skb = __bcm_tcp_prep_skb(pNBuff, fc_args); if (skb) { skb->protocol = htons(ETH_P_IP); /* * bh_disable is needed to prevent deadlock on sock_lock when TCP timers * are executed */ local_bh_disable(); tcp_v4_rcv(skb); local_bh_enable(); } return 0; } /* inject the packet into ipv6_tcp_stack directly from the network driver */ static inline int bcm_tcp_v6_recv(pNBuff_t pNBuff, struct net_device *txdev, BlogFcArgs_t *fc_args) { struct sk_buff *skb; skb = __bcm_tcp_prep_skb(pNBuff, fc_args); if (skb) { skb->protocol = htons(ETH_P_IPV6); /* always use ifindex of skb->dev as skb_dst can be set in tcp_v6_early_demux * and it's possible skb_dst is different from skb->dev, when Src IP used * for creating socket/route is not part of the outgoing interface */ IP6CB(skb)->iif = skb->dev->ifindex; IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); /*TODO check if we need to consider any IPV6 options */ /* * bh_disable is needed to prevent deadlock on sock_lock when TCP timers * are executed */ local_bh_disable(); tcp_v6_rcv(skb); local_bh_enable(); } return 0; } static int bcm_tcp_recv(pNBuff_t pNBuff, struct net_device *txdev) { /* The expectation is that this dev_hard_xmit() function will never be called. Instead the function with args parameter (i.e. bcm_tcp_recv_args) would be invoked */ BUG(); return 0; } int bcm_tcp_recv_args(pNBuff_t pNBuff, struct net_device *txdev, BlogFcArgs_t *fc_args) { if (fc_args->tx_is_ipv4) { if (fc_args->use_tcplocal_xmit_enq_fn) { return bcm_tcp_v4_recv_queue(pNBuff, txdev, fc_args); } else { return bcm_tcp_v4_recv(pNBuff, txdev, fc_args); } } else { if (fc_args->use_tcplocal_xmit_enq_fn) { return bcm_tcp_v6_recv_queue(pNBuff, txdev, fc_args); } else { return bcm_tcp_v6_recv(pNBuff, txdev, fc_args); } } return 0; } static const struct net_device_ops bcm_tcp_netdev_ops = { .ndo_open = NULL, .ndo_stop = NULL, .ndo_start_xmit = (HardStartXmitFuncP)bcm_tcp_recv, .ndo_set_mac_address = NULL, .ndo_do_ioctl = NULL, .ndo_tx_timeout = NULL, .ndo_get_stats = NULL, .ndo_change_mtu = NULL }; struct net_device *blogtcp_local_dev=NULL; static void bcm_blogtcp_dev_setup(struct net_device *dev) { dev->type = ARPHRD_RAWIP; dev->mtu = BCM_MAX_MTU_PAYLOAD_SIZE; dev->netdev_ops = &bcm_tcp_netdev_ops; bcm_netdev_ext_field_set(dev, blog_stats_flags, BLOG_DEV_STAT_FLAG_INCLUDE_ALL); bcm_netdev_ext_field_set(dev, dev_xmit_args, bcm_tcp_recv_args); netdev_accel_tx_fkb_set(dev); } void bcm_tcp_register_netdev(void) { int ret; blogtcp_local_dev = alloc_netdev(0, "blogtcp_local", NET_NAME_UNKNOWN, bcm_blogtcp_dev_setup); if ( blogtcp_local_dev ) { ret = register_netdev(blogtcp_local_dev); if (ret) { printk(KERN_ERR "blogtcp_local register_netdev failed\n"); free_netdev(blogtcp_local_dev); blogtcp_local_dev = NULL; } else printk("blogtcp_local netdev registered successfully \n"); } } inline static int encap_offset(struct sk_buff *skb, uint32_t * encap) { /*start from innermost IP always */ int offset = skb->transport_header - skb->network_header; *encap = TYPE_IP; return offset; } int bcm_tcp_blog_emit(struct sk_buff *skb, struct sock *sk) { if(skb->blog_p && skb->blog_p->l2_mode) { blog_skip(skb,blog_skip_reason_l2_local_termination); } else if( (sk && sk->sk_state == TCP_ESTABLISHED) && skb->blog_p && (skb->blog_p->rx.info.bmap.ETH_802x == 1)) { struct net_device *tmpdev; uint32_t encap ; int offset = encap_offset(skb, &encap); if(skb->dev == NULL) { /* Error */ return -1; } skb_push(skb,offset); tmpdev = skb->dev; skb->dev = blogtcp_local_dev; skb->blog_p->local_rx_devid = bcm_netdev_ext_field_get(tmpdev, devid); skb->blog_p->use_xmit_args = 1; #if (LINUX_VERSION_CODE < KERNEL_VERSION(5,15,0)) { struct tcp_sock *tp = tcp_sk(sk); if(tp->tcp_discard) { skb->blog_p->tcp_discard = 1; skb->blog_p->fro = 1; } } #endif skb->blog_p->local_tcp = 1; skb->blog_p->hw_cso = 1; if (is_netdev_accel_gdx_tx(blogtcp_local_dev)) { blog_emit_generic(skb, blogtcp_local_dev, BLOG_GENPHY); } else { blog_emit(skb, blogtcp_local_dev, encap, 0, BLOG_TCP_LOCALPHY); } skb->dev = tmpdev; skb_pull(skb,offset); } else{ /*unsupported local tcp */ blog_skip(skb, blog_skip_reason_local_tcp_termination); } return 0; } extern int bcmnet_configure_gdx_accel(struct net_device *dev, bcmnet_accel_t *accel_p); static int bcm_tcp_module_load_notify(struct notifier_block *self, unsigned long val, void *data) { bcmnet_accel_t accel={}; int bp3_htoa_license; if (!strcmp("gdx", ((struct module *)data)->name)) { bp3_htoa_license = bcm_license_check(BP3_FEATURE_HTOA); if (bp3_htoa_license <= 0) { /* No valid htoa license. Do not enable GDX */ printk("%s: ***No valid HTOA license. Do not enable GDX for local tcp acceleration***\n", __func__); return 0; } printk("%s: ***HTOA license present. Enable GDX for local tcp acceleration***\n", __func__); switch (val) { case MODULE_STATE_LIVE: #if defined(CONFIG_BCM_GDX_HW) accel.gdx_hw = 1; #endif accel.gdx_tx = 1; bcmnet_configure_gdx_accel(blogtcp_local_dev, &accel); break; case MODULE_STATE_GOING: #if defined(CONFIG_BCM_GDX_HW) accel.gdx_hw = 0; #endif accel.gdx_tx = 0; bcmnet_configure_gdx_accel(blogtcp_local_dev, &accel); break; default: return 0; } } return 0; } static struct notifier_block bcm_tcp_module_load_nb = { .notifier_call = bcm_tcp_module_load_notify, }; static int __init bcm_tcp_accel_init(void) { bcm_tcp_register_netdev(); register_module_notifier(&bcm_tcp_module_load_nb); return 0; } fs_initcall(bcm_tcp_accel_init);继续结合分析localin加速 并分析如何针对FTP报文关闭Localin加速
11-18
简单给我一份中文理解后简化注释的代码:static __always_inline int __pthread_rwlock_rdlock_full64 (pthread_rwlock_t *rwlock, clockid_t clockid, const struct __timespec64 *abstime) { unsigned int r; /* Make sure any passed in clockid and timeout value are valid. Note that the previous implementation assumed that this check *must* not be performed if there would in fact be no blocking; however, POSIX only requires that "the validity of the abstime parameter need not be checked if the lock can be immediately acquired" (i.e., we need not but may check it). */ if (abstime && __glibc_unlikely (!futex_abstimed_supported_clockid (clockid) || ! valid_nanoseconds (abstime->tv_nsec))) return EINVAL; /* Make sure we are not holding the rwlock as a writer. This is a deadlock situation we recognize and report. */ if (__glibc_unlikely (atomic_load_relaxed (&rwlock->__data.__cur_writer) == THREAD_GETMEM (THREAD_SELF, tid))) return EDEADLK; /* If we prefer writers, recursive rdlock is disallowed, we are in a read phase, and there are other readers present, we try to wait without extending the read phase. We will be unblocked by either one of the other active readers, or if the writer gives up WRLOCKED (e.g., on timeout). If there are no other readers, we simply race with any existing primary writer; it would have been a race anyway, and changing the odds slightly will likely not make a big difference. */ if (rwlock->__data.__flags == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) { r = atomic_load_relaxed (&rwlock->__data.__readers); while ((r & PTHREAD_RWLOCK_WRPHASE) == 0 && (r & PTHREAD_RWLOCK_WRLOCKED) != 0 && (r >> PTHREAD_RWLOCK_READER_SHIFT) > 0) { /* TODO Spin first. */ /* Try setting the flag signaling that we are waiting without having incremented the number of readers. Relaxed MO is fine because this is just about waiting for a state change in __readers. */ if (atomic_compare_exchange_weak_relaxed (&rwlock->__data.__readers, &r, r | PTHREAD_RWLOCK_RWAITING)) { /* Wait for as long as the flag is set. An ABA situation is harmless because the flag is just about the state of __readers, and all threads set the flag under the same conditions. */ while (((r = atomic_load_relaxed (&rwlock->__data.__readers)) & PTHREAD_RWLOCK_RWAITING) != 0) { int private = __pthread_rwlock_get_private (rwlock); int err = __futex_abstimed_wait64 (&rwlock->__data.__readers, r, clockid, abstime, private); /* We ignore EAGAIN and EINTR. On time-outs, we can just return because we don't need to clean up anything. */ if (err == ETIMEDOUT || err == EOVERFLOW) return err; } /* It makes sense to not break out of the outer loop here because we might be in the same situation again. */ } else { /* TODO Back-off. */ } } } /* Register as a reader, using an add-and-fetch so that R can be used as expected value for future operations. Acquire MO so we synchronize with prior writers as well as the last reader of the previous read phase (see below). */ r = (atomic_fetch_add_acquire (&rwlock->__data.__readers, (1 << PTHREAD_RWLOCK_READER_SHIFT)) + (1 << PTHREAD_RWLOCK_READER_SHIFT));
最新发布
11-25
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值