Commit b8c17f70 authored by Lin Yun Sheng's avatar Lin Yun Sheng Committed by David S. Miller

net: hns: Add self-adaptive interrupt coalesce support in hns driver

When deal with low and high throughput, it is hard to achiece both
high performance and low latency. In order to achiece that, this patch
calculates the rx rate, and adjust the interrupt coalesce parameter
accordingly.
Signed-off-by: default avatarYunsheng Lin <linyunsheng@huawei.com>
Tested-by: default avatarWeiwei Deng <dengweiwei@huawei.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e9e6c232
......@@ -202,6 +202,7 @@ hnae_init_ring(struct hnae_queue *q, struct hnae_ring *ring, int flags)
ring->q = q;
ring->flags = flags;
spin_lock_init(&ring->lock);
ring->coal_param = q->handle->coal_param;
assert(!ring->desc && !ring->desc_cb && !ring->desc_dma_addr);
/* not matter for tx or rx ring, the ntc and ntc start from 0 */
......
......@@ -89,6 +89,10 @@ do { \
#define RCB_RING_NAME_LEN 16
#define HNAE_LOWEST_LATENCY_COAL_PARAM 30
#define HNAE_LOW_LATENCY_COAL_PARAM 80
#define HNAE_BULK_LATENCY_COAL_PARAM 150
enum hnae_led_state {
HNAE_LED_INACTIVE,
HNAE_LED_ACTIVE,
......@@ -292,6 +296,12 @@ struct hnae_ring {
int flags; /* ring attribute */
int irq_init_flag;
/* total rx bytes after last rx rate calucated */
u64 coal_last_rx_bytes;
unsigned long coal_last_jiffies;
u32 coal_param;
u32 coal_rx_rate; /* rx rate in MB */
};
#define ring_ptr_move_fw(ring, p) \
......@@ -548,8 +558,13 @@ struct hnae_handle {
u32 if_support;
int q_num;
int vf_id;
unsigned long coal_last_jiffies;
u32 coal_param; /* self adapt coalesce param */
/* the ring index of last ring that set coal param */
u32 coal_ring_idx;
u32 eport_id;
u32 dport_id; /* v2 tx bd should fill the dport_id */
bool coal_adapt_en;
enum hnae_port_type port_type;
enum hnae_media_type media_type;
struct list_head node; /* list to hnae_ae_dev->handle_list */
......
......@@ -99,6 +99,7 @@ struct hnae_handle *hns_ae_get_handle(struct hnae_ae_dev *dev,
ae_handle->owner_dev = dsaf_dev->dev;
ae_handle->dev = dev;
ae_handle->q_num = qnum_per_vf;
ae_handle->coal_param = HNAE_LOWEST_LATENCY_COAL_PARAM;
/* find ring pair, and set vf id*/
for (ae_handle->vf_id = 0;
......
......@@ -812,6 +812,112 @@ static int hns_desc_unused(struct hnae_ring *ring)
return ((ntc >= ntu) ? 0 : ring->desc_num) + ntc - ntu;
}
#define HNS_LOWEST_LATENCY_RATE 27 /* 27 MB/s */
#define HNS_LOW_LATENCY_RATE 80 /* 80 MB/s */
#define HNS_COAL_BDNUM 3
static u32 hns_coal_rx_bdnum(struct hnae_ring *ring)
{
bool coal_enable = ring->q->handle->coal_adapt_en;
if (coal_enable &&
ring->coal_last_rx_bytes > HNS_LOWEST_LATENCY_RATE)
return HNS_COAL_BDNUM;
else
return 0;
}
static void hns_update_rx_rate(struct hnae_ring *ring)
{
bool coal_enable = ring->q->handle->coal_adapt_en;
u32 time_passed_ms;
u64 total_bytes;
if (!coal_enable ||
time_before(jiffies, ring->coal_last_jiffies + (HZ >> 4)))
return;
/* ring->stats.rx_bytes overflowed */
if (ring->coal_last_rx_bytes > ring->stats.rx_bytes) {
ring->coal_last_rx_bytes = ring->stats.rx_bytes;
ring->coal_last_jiffies = jiffies;
return;
}
total_bytes = ring->stats.rx_bytes - ring->coal_last_rx_bytes;
time_passed_ms = jiffies_to_msecs(jiffies - ring->coal_last_jiffies);
ring->coal_rx_rate = (total_bytes / time_passed_ms) >> 10;
ring->coal_last_rx_bytes = ring->stats.rx_bytes;
ring->coal_last_jiffies = jiffies;
}
/**
* smooth_alg - smoothing algrithm for adjusting coalesce parameter
**/
static u32 smooth_alg(u32 new_param, u32 old_param)
{
u32 gap = (new_param > old_param) ? new_param - old_param
: old_param - new_param;
if (gap > 8)
gap >>= 3;
if (new_param > old_param)
return old_param + gap;
else
return old_param - gap;
}
/**
* hns_nic_adp_coalesce - self adapte coalesce according to rx rate
* @ring_data: pointer to hns_nic_ring_data
**/
static void hns_nic_adpt_coalesce(struct hns_nic_ring_data *ring_data)
{
struct hnae_ring *ring = ring_data->ring;
struct hnae_handle *handle = ring->q->handle;
u32 new_coal_param, old_coal_param = ring->coal_param;
if (ring->coal_rx_rate < HNS_LOWEST_LATENCY_RATE)
new_coal_param = HNAE_LOWEST_LATENCY_COAL_PARAM;
else if (ring->coal_rx_rate < HNS_LOW_LATENCY_RATE)
new_coal_param = HNAE_LOW_LATENCY_COAL_PARAM;
else
new_coal_param = HNAE_BULK_LATENCY_COAL_PARAM;
if (new_coal_param == old_coal_param &&
new_coal_param == handle->coal_param)
return;
new_coal_param = smooth_alg(new_coal_param, old_coal_param);
ring->coal_param = new_coal_param;
/**
* Because all ring in one port has one coalesce param, when one ring
* calculate its own coalesce param, it cannot write to hardware at
* once. There are three conditions as follows:
* 1. current ring's coalesce param is larger than the hardware.
* 2. or ring which adapt last time can change again.
* 3. timeout.
*/
if (new_coal_param == handle->coal_param) {
handle->coal_last_jiffies = jiffies;
handle->coal_ring_idx = ring_data->queue_index;
} else if (new_coal_param > handle->coal_param ||
handle->coal_ring_idx == ring_data->queue_index ||
time_after(jiffies, handle->coal_last_jiffies + (HZ >> 4))) {
handle->dev->ops->set_coalesce_usecs(handle,
new_coal_param);
handle->dev->ops->set_coalesce_frames(handle,
1, new_coal_param);
handle->coal_param = new_coal_param;
handle->coal_ring_idx = ring_data->queue_index;
handle->coal_last_jiffies = jiffies;
}
}
static int hns_nic_rx_poll_one(struct hns_nic_ring_data *ring_data,
int budget, void *v)
{
......@@ -868,20 +974,27 @@ static bool hns_nic_rx_fini_pro(struct hns_nic_ring_data *ring_data)
{
struct hnae_ring *ring = ring_data->ring;
int num = 0;
bool rx_stopped;
ring_data->ring->q->handle->dev->ops->toggle_ring_irq(ring, 0);
hns_update_rx_rate(ring);
/* for hardware bug fixed */
ring_data->ring->q->handle->dev->ops->toggle_ring_irq(ring, 0);
num = readl_relaxed(ring->io_base + RCB_REG_FBDNUM);
if (num > 0) {
if (num <= hns_coal_rx_bdnum(ring)) {
if (ring->q->handle->coal_adapt_en)
hns_nic_adpt_coalesce(ring_data);
rx_stopped = true;
} else {
ring_data->ring->q->handle->dev->ops->toggle_ring_irq(
ring_data->ring, 1);
return false;
} else {
return true;
rx_stopped = false;
}
return rx_stopped;
}
static bool hns_nic_rx_fini_pro_v2(struct hns_nic_ring_data *ring_data)
......@@ -889,11 +1002,16 @@ static bool hns_nic_rx_fini_pro_v2(struct hns_nic_ring_data *ring_data)
struct hnae_ring *ring = ring_data->ring;
int num;
hns_update_rx_rate(ring);
num = readl_relaxed(ring->io_base + RCB_REG_FBDNUM);
if (!num)
if (num <= hns_coal_rx_bdnum(ring)) {
if (ring->q->handle->coal_adapt_en)
hns_nic_adpt_coalesce(ring_data);
return true;
else
}
return false;
}
......
......@@ -38,7 +38,7 @@ struct hns_nic_ring_data {
struct hnae_ring *ring;
struct napi_struct napi;
cpumask_t mask; /* affinity mask */
int queue_index;
u32 queue_index;
int (*poll_one)(struct hns_nic_ring_data *, int, void *);
void (*ex_process)(struct hns_nic_ring_data *, struct sk_buff *);
bool (*fini_process)(struct hns_nic_ring_data *);
......
......@@ -735,8 +735,8 @@ static int hns_get_coalesce(struct net_device *net_dev,
ops = priv->ae_handle->dev->ops;
ec->use_adaptive_rx_coalesce = 1;
ec->use_adaptive_tx_coalesce = 1;
ec->use_adaptive_rx_coalesce = priv->ae_handle->coal_adapt_en;
ec->use_adaptive_tx_coalesce = priv->ae_handle->coal_adapt_en;
if ((!ops->get_coalesce_usecs) ||
(!ops->get_max_coalesced_frames))
......@@ -787,6 +787,9 @@ static int hns_set_coalesce(struct net_device *net_dev,
(!ops->set_coalesce_frames))
return -ESRCH;
if (ec->use_adaptive_rx_coalesce != priv->ae_handle->coal_adapt_en)
priv->ae_handle->coal_adapt_en = ec->use_adaptive_rx_coalesce;
rc1 = ops->set_coalesce_usecs(priv->ae_handle,
ec->rx_coalesce_usecs);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment