Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 278068
b: refs/heads/master
c: f2f9219
h: refs/heads/master
v: v3
  • Loading branch information
Kalle Valo committed Nov 11, 2011
1 parent 3cc1101 commit 29034b9
Show file tree
Hide file tree
Showing 6 changed files with 296 additions and 303 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 3c3703987a43b969e2f1e54c4e28f1fc8594c9d8
refs/heads/master: f2f921950d6a066f6e4a84c52fc69292bc877aa7
10 changes: 0 additions & 10 deletions trunk/drivers/net/wireless/ath/ath6kl/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,6 @@ struct ath6kl;
enum htc_credit_dist_reason;
struct ath6kl_htc_credit_info;

int ath6kl_setup_credit_dist(void *htc_handle,
struct ath6kl_htc_credit_info *cred_info);
void ath6kl_credit_distribute(struct ath6kl_htc_credit_info *cred_inf,
struct list_head *epdist_list,
enum htc_credit_dist_reason reason);
void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_inf,
struct list_head *ep_list,
int tot_credits);
void ath6kl_seek_credits(struct ath6kl_htc_credit_info *cred_inf,
struct htc_endpoint_credit_dist *ep_dist);
struct ath6kl *ath6kl_core_alloc(struct device *sdev);
int ath6kl_core_init(struct ath6kl *ar);
void ath6kl_core_cleanup(struct ath6kl *ar);
Expand Down
10 changes: 0 additions & 10 deletions trunk/drivers/net/wireless/ath/ath6kl/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -570,16 +570,6 @@ static inline void *ath6kl_priv(struct net_device *dev)
return ((struct ath6kl_vif *) netdev_priv(dev))->ar;
}

static inline void ath6kl_deposit_credit_to_ep(struct ath6kl_htc_credit_info
*cred_info,
struct htc_endpoint_credit_dist
*ep_dist, int credits)
{
ep_dist->credits += credits;
ep_dist->cred_assngd += credits;
cred_info->cur_free_credits -= credits;
}

static inline u32 ath6kl_get_hi_item_addr(struct ath6kl *ar,
u32 item_offset)
{
Expand Down
292 changes: 292 additions & 0 deletions trunk/drivers/net/wireless/ath/ath6kl/htc.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,298 @@

#define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask))

/* Functions for Tx credit handling */
static void ath6kl_deposit_credit_to_ep(struct ath6kl_htc_credit_info
*cred_info,
struct htc_endpoint_credit_dist
*ep_dist, int credits)
{
ep_dist->credits += credits;
ep_dist->cred_assngd += credits;
cred_info->cur_free_credits -= credits;
}

static void ath6kl_credit_init(struct ath6kl_htc_credit_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 */
/* FIXME: this looks fishy, check */
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 ath6kl_setup_credit_dist(void *htc_handle,
struct ath6kl_htc_credit_info *cred_info)
{
u16 servicepriority[5];

memset(cred_info, 0, sizeof(struct ath6kl_htc_credit_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 ath6kl_reduce_credits(struct ath6kl_htc_credit_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 ath6kl_credit_update(struct ath6kl_htc_credit_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)
ath6kl_reduce_credits(cred_info,
cur_dist_list,
cur_dist_list->cred_assngd);

if (cur_dist_list->credits >
cur_dist_list->cred_norm)
ath6kl_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)
ath6kl_reduce_credits(cred_info,
cur_dist_list, 0);
}
}
}
}

/*
* HTC has an endpoint that needs credits, ep_dist is the endpoint in
* question.
*/
static void ath6kl_seek_credits(struct ath6kl_htc_credit_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.
*/
ath6kl_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 ath6kl_redistribute_credits(struct ath6kl_htc_credit_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)
ath6kl_reduce_credits(info, curdist_list, 0);
else
ath6kl_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.
*/
static void ath6kl_credit_distribute(struct ath6kl_htc_credit_info *cred_info,
struct list_head *ep_dist_list,
enum htc_credit_dist_reason reason)
{
switch (reason) {
case HTC_CREDIT_DIST_SEND_COMPLETE:
ath6kl_credit_update(cred_info, ep_dist_list);
break;
case HTC_CREDIT_DIST_ACTIVITY_CHANGE:
ath6kl_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);
}

static void ath6kl_htc_tx_buf_align(u8 **buf, unsigned long len)
{
u8 *align_addr;
Expand Down
3 changes: 3 additions & 0 deletions trunk/drivers/net/wireless/ath/ath6kl/htc.h
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,9 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
u32 msg_look_ahead, int *n_pkts);

int ath6kl_setup_credit_dist(void *htc_handle,
struct ath6kl_htc_credit_info *cred_info);

static inline void set_htc_pkt_info(struct htc_packet *packet, void *context,
u8 *buf, unsigned int len,
enum htc_endpoint_id eid, u16 tag)
Expand Down
Loading

0 comments on commit 29034b9

Please sign in to comment.