X-Git-Url: http://git.cascardo.info/?a=blobdiff_plain;f=drivers%2Fnet%2Fwireless%2Fath%2Fath6kl%2Fmain.c;h=717ed22abc31d576375cca3d707e304f1dc6797b;hb=5fe4dffbc12b22507d2416667720cbd4b27c693b;hp=17cabdce62dc813080981fea5212cd2ee92db6b6;hpb=990bd9151927ad55c7e3da3b05cf13ecfe7a31bf;p=cascardo%2Flinux.git diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 17cabdce62dc..717ed22abc31 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -555,287 +555,6 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, netif_wake_queue(vif->ndev); } -/* Functions for Tx credit handling */ -void ath6k_credit_init(struct htc_credit_state_info *cred_info, - struct list_head *ep_list, - int tot_credits) -{ - struct htc_endpoint_credit_dist *cur_ep_dist; - int count; - - cred_info->cur_free_credits = tot_credits; - cred_info->total_avail_credits = tot_credits; - - list_for_each_entry(cur_ep_dist, ep_list, list) { - if (cur_ep_dist->endpoint == ENDPOINT_0) - continue; - - cur_ep_dist->cred_min = cur_ep_dist->cred_per_msg; - - if (tot_credits > 4) - if ((cur_ep_dist->svc_id == WMI_DATA_BK_SVC) || - (cur_ep_dist->svc_id == WMI_DATA_BE_SVC)) { - ath6kl_deposit_credit_to_ep(cred_info, - cur_ep_dist, - cur_ep_dist->cred_min); - cur_ep_dist->dist_flags |= HTC_EP_ACTIVE; - } - - if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) { - ath6kl_deposit_credit_to_ep(cred_info, cur_ep_dist, - cur_ep_dist->cred_min); - /* - * Control service is always marked active, it - * never goes inactive EVER. - */ - cur_ep_dist->dist_flags |= HTC_EP_ACTIVE; - } else if (cur_ep_dist->svc_id == WMI_DATA_BK_SVC) - /* this is the lowest priority data endpoint */ - cred_info->lowestpri_ep_dist = cur_ep_dist->list; - - /* - * Streams have to be created (explicit | implicit) for all - * kinds of traffic. BE endpoints are also inactive in the - * beginning. When BE traffic starts it creates implicit - * streams that redistributes credits. - * - * Note: all other endpoints have minimums set but are - * initially given NO credits. credits will be distributed - * as traffic activity demands - */ - } - - WARN_ON(cred_info->cur_free_credits <= 0); - - list_for_each_entry(cur_ep_dist, ep_list, list) { - if (cur_ep_dist->endpoint == ENDPOINT_0) - continue; - - if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) - cur_ep_dist->cred_norm = cur_ep_dist->cred_per_msg; - else { - /* - * For the remaining data endpoints, we assume that - * each cred_per_msg are the same. We use a simple - * calculation here, we take the remaining credits - * and determine how many max messages this can - * cover and then set each endpoint's normal value - * equal to 3/4 this amount. - */ - count = (cred_info->cur_free_credits / - cur_ep_dist->cred_per_msg) - * cur_ep_dist->cred_per_msg; - count = (count * 3) >> 2; - count = max(count, cur_ep_dist->cred_per_msg); - cur_ep_dist->cred_norm = count; - - } - } -} - -/* initialize and setup credit distribution */ -int ath6k_setup_credit_dist(void *htc_handle, - struct htc_credit_state_info *cred_info) -{ - u16 servicepriority[5]; - - memset(cred_info, 0, sizeof(struct htc_credit_state_info)); - - servicepriority[0] = WMI_CONTROL_SVC; /* highest */ - servicepriority[1] = WMI_DATA_VO_SVC; - servicepriority[2] = WMI_DATA_VI_SVC; - servicepriority[3] = WMI_DATA_BE_SVC; - servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */ - - /* set priority list */ - ath6kl_htc_set_credit_dist(htc_handle, cred_info, servicepriority, 5); - - return 0; -} - -/* reduce an ep's credits back to a set limit */ -static void ath6k_reduce_credits(struct htc_credit_state_info *cred_info, - struct htc_endpoint_credit_dist *ep_dist, - int limit) -{ - int credits; - - ep_dist->cred_assngd = limit; - - if (ep_dist->credits <= limit) - return; - - credits = ep_dist->credits - limit; - ep_dist->credits -= credits; - cred_info->cur_free_credits += credits; -} - -static void ath6k_credit_update(struct htc_credit_state_info *cred_info, - struct list_head *epdist_list) -{ - struct htc_endpoint_credit_dist *cur_dist_list; - - list_for_each_entry(cur_dist_list, epdist_list, list) { - if (cur_dist_list->endpoint == ENDPOINT_0) - continue; - - if (cur_dist_list->cred_to_dist > 0) { - cur_dist_list->credits += - cur_dist_list->cred_to_dist; - cur_dist_list->cred_to_dist = 0; - if (cur_dist_list->credits > - cur_dist_list->cred_assngd) - ath6k_reduce_credits(cred_info, - cur_dist_list, - cur_dist_list->cred_assngd); - - if (cur_dist_list->credits > - cur_dist_list->cred_norm) - ath6k_reduce_credits(cred_info, cur_dist_list, - cur_dist_list->cred_norm); - - if (!(cur_dist_list->dist_flags & HTC_EP_ACTIVE)) { - if (cur_dist_list->txq_depth == 0) - ath6k_reduce_credits(cred_info, - cur_dist_list, 0); - } - } - } -} - -/* - * HTC has an endpoint that needs credits, ep_dist is the endpoint in - * question. - */ -void ath6k_seek_credits(struct htc_credit_state_info *cred_info, - struct htc_endpoint_credit_dist *ep_dist) -{ - struct htc_endpoint_credit_dist *curdist_list; - int credits = 0; - int need; - - if (ep_dist->svc_id == WMI_CONTROL_SVC) - goto out; - - if ((ep_dist->svc_id == WMI_DATA_VI_SVC) || - (ep_dist->svc_id == WMI_DATA_VO_SVC)) - if ((ep_dist->cred_assngd >= ep_dist->cred_norm)) - goto out; - - /* - * For all other services, we follow a simple algorithm of: - * - * 1. checking the free pool for credits - * 2. checking lower priority endpoints for credits to take - */ - - credits = min(cred_info->cur_free_credits, ep_dist->seek_cred); - - if (credits >= ep_dist->seek_cred) - goto out; - - /* - * We don't have enough in the free pool, try taking away from - * lower priority services The rule for taking away credits: - * - * 1. Only take from lower priority endpoints - * 2. Only take what is allocated above the minimum (never - * starve an endpoint completely) - * 3. Only take what you need. - */ - - list_for_each_entry_reverse(curdist_list, - &cred_info->lowestpri_ep_dist, - list) { - if (curdist_list == ep_dist) - break; - - need = ep_dist->seek_cred - cred_info->cur_free_credits; - - if ((curdist_list->cred_assngd - need) >= - curdist_list->cred_min) { - /* - * The current one has been allocated more than - * it's minimum and it has enough credits assigned - * above it's minimum to fulfill our need try to - * take away just enough to fulfill our need. - */ - ath6k_reduce_credits(cred_info, curdist_list, - curdist_list->cred_assngd - need); - - if (cred_info->cur_free_credits >= - ep_dist->seek_cred) - break; - } - - if (curdist_list->endpoint == ENDPOINT_0) - break; - } - - credits = min(cred_info->cur_free_credits, ep_dist->seek_cred); - -out: - /* did we find some credits? */ - if (credits) - ath6kl_deposit_credit_to_ep(cred_info, ep_dist, credits); - - ep_dist->seek_cred = 0; -} - -/* redistribute credits based on activity change */ -static void ath6k_redistribute_credits(struct htc_credit_state_info *info, - struct list_head *ep_dist_list) -{ - struct htc_endpoint_credit_dist *curdist_list; - - list_for_each_entry(curdist_list, ep_dist_list, list) { - if (curdist_list->endpoint == ENDPOINT_0) - continue; - - if ((curdist_list->svc_id == WMI_DATA_BK_SVC) || - (curdist_list->svc_id == WMI_DATA_BE_SVC)) - curdist_list->dist_flags |= HTC_EP_ACTIVE; - - if ((curdist_list->svc_id != WMI_CONTROL_SVC) && - !(curdist_list->dist_flags & HTC_EP_ACTIVE)) { - if (curdist_list->txq_depth == 0) - ath6k_reduce_credits(info, - curdist_list, 0); - else - ath6k_reduce_credits(info, - curdist_list, - curdist_list->cred_min); - } - } -} - -/* - * - * This function is invoked whenever endpoints require credit - * distributions. A lock is held while this function is invoked, this - * function shall NOT block. The ep_dist_list is a list of distribution - * structures in prioritized order as defined by the call to the - * htc_set_credit_dist() api. - */ -void ath6k_credit_distribute(struct htc_credit_state_info *cred_info, - struct list_head *ep_dist_list, - enum htc_credit_dist_reason reason) -{ - switch (reason) { - case HTC_CREDIT_DIST_SEND_COMPLETE: - ath6k_credit_update(cred_info, ep_dist_list); - break; - case HTC_CREDIT_DIST_ACTIVITY_CHANGE: - ath6k_redistribute_credits(cred_info, ep_dist_list); - break; - default: - break; - } - - WARN_ON(cred_info->cur_free_credits > cred_info->total_avail_credits); - WARN_ON(cred_info->cur_free_credits < 0); -} - void disconnect_timer_handler(unsigned long ptr) { struct net_device *dev = (struct net_device *)ptr; @@ -954,10 +673,12 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver) set_bit(WMI_READY, &ar->flag); wake_up(&ar->event_wq); - ath6kl_info("hw %s fw %s%s\n", - get_hw_id_string(ar->wiphy->hw_version), - ar->wiphy->fw_version, - test_bit(TESTMODE, &ar->flag) ? " testmode" : ""); + if (test_and_clear_bit(FIRST_BOOT, &ar->flag)) { + ath6kl_info("hw %s fw %s%s\n", + get_hw_id_string(ar->wiphy->hw_version), + ar->wiphy->fw_version, + test_bit(TESTMODE, &ar->flag) ? " testmode" : ""); + } } void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status) @@ -972,7 +693,7 @@ void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status) NONE_BSS_FILTER, 0); } - ath6kl_dbg(ATH6KL_DBG_WLAN_SCAN, "scan complete: %d\n", status); + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "scan complete: %d\n", status); } void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid, @@ -1332,8 +1053,7 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, del_timer(&vif->disconnect_timer); - ath6kl_dbg(ATH6KL_DBG_WLAN_CONNECT, - "disconnect reason is %d\n", reason); + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "disconnect reason is %d\n", reason); /* * If the event is due to disconnect cmd from the host, only they @@ -1394,6 +1114,12 @@ struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar) static int ath6kl_open(struct net_device *dev) { struct ath6kl_vif *vif = netdev_priv(dev); + int ret; + + /* FIXME: how to handle multi vif support? */ + ret = ath6kl_init_hw_start(vif->ar); + if (ret) + return ret; set_bit(WLAN_ENABLED, &vif->flags); @@ -1410,6 +1136,7 @@ static int ath6kl_close(struct net_device *dev) { struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); + int ret; netif_stop_queue(dev); @@ -1425,6 +1152,11 @@ static int ath6kl_close(struct net_device *dev) ath6kl_cfg80211_scan_complete_event(vif, -ECANCELED); + /* FIXME: how to handle multi vif support? */ + ret = ath6kl_init_hw_stop(ar); + if (ret) + return ret; + return 0; } @@ -1445,6 +1177,7 @@ static struct net_device_ops ath6kl_netdev_ops = { void init_netdev(struct net_device *dev) { dev->netdev_ops = &ath6kl_netdev_ops; + dev->destructor = free_netdev; dev->watchdog_timeo = ATH6KL_TX_TIMEOUT; dev->needed_headroom = ETH_HLEN;