Commit a616b849 authored by David S. Miller's avatar David S. Miller

Merge branch 'cxgb4-tx-rate-limiting'

Rahul Lakkireddy says:

====================
TX max rate limiting for Chelsio T4/T5 adapters

This series of patches implement tx max rate limiting per queue on
Chelsio T4/T5 hardware.  This is achieved by first creating a tx
scheduling class with the specified max rate.  The queue is then
bound to the newly created class.  If a scheduling class with similar
max rate already exists, then the queue is bound to the matching class.

Patch 1 adds support for setting tx scheduling classes.
Patch 2 adds support to bind/unbind queues to/from the scheduling classes.
Patch 3 implements the set_tx_maxrate NDO.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f7257f65 10a2604e
......@@ -4,7 +4,7 @@
obj-$(CONFIG_CHELSIO_T4) += cxgb4.o
cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o cxgb4_uld.o
cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o cxgb4_uld.o sched.o
cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o
cxgb4-$(CONFIG_CHELSIO_T4_FCOE) += cxgb4_fcoe.o
cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o
/*
* This file is part of the Chelsio T4 Ethernet driver for Linux.
*
* Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved.
* Copyright (c) 2003-2016 Chelsio Communications, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
......@@ -347,6 +347,7 @@ struct adapter_params {
unsigned int ofldq_wr_cred;
bool ulptx_memwrite_dsgl; /* use of T5 DSGL allowed */
unsigned int nsched_cls; /* number of traffic classes */
unsigned int max_ordird_qp; /* Max read depth per RDMA QP */
unsigned int max_ird_adapter; /* Max read depth per adapter */
};
......@@ -495,6 +496,7 @@ struct port_info {
#endif /* CONFIG_CHELSIO_T4_FCOE */
bool rxtstamp; /* Enable TS */
struct hwtstamp_config tstamp_config;
struct sched_table *sched_tbl;
};
struct dentry;
......@@ -858,6 +860,55 @@ struct adapter {
spinlock_t win0_lock ____cacheline_aligned_in_smp;
};
/* Support for "sched-class" command to allow a TX Scheduling Class to be
* programmed with various parameters.
*/
struct ch_sched_params {
s8 type; /* packet or flow */
union {
struct {
s8 level; /* scheduler hierarchy level */
s8 mode; /* per-class or per-flow */
s8 rateunit; /* bit or packet rate */
s8 ratemode; /* %port relative or kbps absolute */
s8 channel; /* scheduler channel [0..N] */
s8 class; /* scheduler class [0..N] */
s32 minrate; /* minimum rate */
s32 maxrate; /* maximum rate */
s16 weight; /* percent weight */
s16 pktsize; /* average packet size */
} params;
} u;
};
enum {
SCHED_CLASS_TYPE_PACKET = 0, /* class type */
};
enum {
SCHED_CLASS_LEVEL_CL_RL = 0, /* class rate limiter */
};
enum {
SCHED_CLASS_MODE_CLASS = 0, /* per-class scheduling */
};
enum {
SCHED_CLASS_RATEUNIT_BITS = 0, /* bit rate scheduling */
};
enum {
SCHED_CLASS_RATEMODE_ABS = 1, /* Kb/s */
};
/* Support for "sched_queue" command to allow one or more NIC TX Queues
* to be bound to a TX Scheduling Class.
*/
struct ch_sched_queue {
s8 queue; /* queue index */
s8 class; /* class index */
};
/* Defined bit width of user definable filter tuples
*/
#define ETHTYPE_BITWIDTH 16
......@@ -1563,6 +1614,9 @@ void t4_get_trace_filter(struct adapter *adapter, struct trace_params *tp,
int filter_index, int *enabled);
int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
u32 addr, u32 val);
int t4_sched_params(struct adapter *adapter, int type, int level, int mode,
int rateunit, int ratemode, int channel, int class,
int minrate, int maxrate, int weight, int pktsize);
void t4_sge_decode_idma_state(struct adapter *adapter, int state);
void t4_free_mem(void *addr);
void t4_idma_monitor_init(struct adapter *adapter,
......
/*
* This file is part of the Chelsio T4 Ethernet driver for Linux.
*
* Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved.
* Copyright (c) 2003-2016 Chelsio Communications, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
......@@ -76,6 +76,7 @@
#include "cxgb4_debugfs.h"
#include "clip_tbl.h"
#include "l2t.h"
#include "sched.h"
char cxgb4_driver_name[] = KBUILD_MODNAME;
......@@ -3139,6 +3140,87 @@ static void cxgb_netpoll(struct net_device *dev)
}
#endif
static int cxgb_set_tx_maxrate(struct net_device *dev, int index, u32 rate)
{
struct port_info *pi = netdev_priv(dev);
struct adapter *adap = pi->adapter;
struct sched_class *e;
struct ch_sched_params p;
struct ch_sched_queue qe;
u32 req_rate;
int err = 0;
if (!can_sched(dev))
return -ENOTSUPP;
if (index < 0 || index > pi->nqsets - 1)
return -EINVAL;
if (!(adap->flags & FULL_INIT_DONE)) {
dev_err(adap->pdev_dev,
"Failed to rate limit on queue %d. Link Down?\n",
index);
return -EINVAL;
}
/* Convert from Mbps to Kbps */
req_rate = rate << 10;
/* Max rate is 10 Gbps */
if (req_rate >= SCHED_MAX_RATE_KBPS) {
dev_err(adap->pdev_dev,
"Invalid rate %u Mbps, Max rate is %u Gbps\n",
rate, SCHED_MAX_RATE_KBPS);
return -ERANGE;
}
/* First unbind the queue from any existing class */
memset(&qe, 0, sizeof(qe));
qe.queue = index;
qe.class = SCHED_CLS_NONE;
err = cxgb4_sched_class_unbind(dev, (void *)(&qe), SCHED_QUEUE);
if (err) {
dev_err(adap->pdev_dev,
"Unbinding Queue %d on port %d fail. Err: %d\n",
index, pi->port_id, err);
return err;
}
/* Queue already unbound */
if (!req_rate)
return 0;
/* Fetch any available unused or matching scheduling class */
memset(&p, 0, sizeof(p));
p.type = SCHED_CLASS_TYPE_PACKET;
p.u.params.level = SCHED_CLASS_LEVEL_CL_RL;
p.u.params.mode = SCHED_CLASS_MODE_CLASS;
p.u.params.rateunit = SCHED_CLASS_RATEUNIT_BITS;
p.u.params.ratemode = SCHED_CLASS_RATEMODE_ABS;
p.u.params.channel = pi->tx_chan;
p.u.params.class = SCHED_CLS_NONE;
p.u.params.minrate = 0;
p.u.params.maxrate = req_rate;
p.u.params.weight = 0;
p.u.params.pktsize = dev->mtu;
e = cxgb4_sched_class_alloc(dev, &p);
if (!e)
return -ENOMEM;
/* Bind the queue to a scheduling class */
memset(&qe, 0, sizeof(qe));
qe.queue = index;
qe.class = e->idx;
err = cxgb4_sched_class_bind(dev, (void *)(&qe), SCHED_QUEUE);
if (err)
dev_err(adap->pdev_dev,
"Queue rate limiting failed. Err: %d\n", err);
return err;
}
static const struct net_device_ops cxgb4_netdev_ops = {
.ndo_open = cxgb_open,
.ndo_stop = cxgb_close,
......@@ -3161,6 +3243,7 @@ static const struct net_device_ops cxgb4_netdev_ops = {
#ifdef CONFIG_NET_RX_BUSY_POLL
.ndo_busy_poll = cxgb_busy_poll,
#endif
.ndo_set_tx_maxrate = cxgb_set_tx_maxrate,
};
static const struct net_device_ops cxgb4_mgmt_netdev_ops = {
......@@ -4024,6 +4107,12 @@ static int adap_init0(struct adapter *adap)
adap->clipt_start = val[0];
adap->clipt_end = val[1];
/* We don't yet have a PARAMs calls to retrieve the number of Traffic
* Classes supported by the hardware/firmware so we hard code it here
* for now.
*/
adap->params.nsched_cls = is_t4(adap->params.chip) ? 15 : 16;
/* query params related to active filter region */
params[0] = FW_PARAM_PFVF(ACTIVE_FILTER_START);
params[1] = FW_PARAM_PFVF(ACTIVE_FILTER_END);
......@@ -4882,6 +4971,7 @@ static void free_some_resources(struct adapter *adapter)
unsigned int i;
t4_free_mem(adapter->l2t);
t4_cleanup_sched(adapter);
t4_free_mem(adapter->tids.tid_tab);
kfree(adapter->sge.egr_map);
kfree(adapter->sge.ingr_map);
......@@ -5249,6 +5339,16 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
#endif
for_each_port(adapter, i) {
pi = adap2pinfo(adapter, i);
pi->sched_tbl = t4_init_sched(adapter->params.nsched_cls);
if (!pi->sched_tbl)
dev_warn(&pdev->dev,
"could not activate scheduling on port %d\n",
i);
}
if (is_offload(adapter) && tid_init(&adapter->tids) < 0) {
dev_warn(&pdev->dev, "could not allocate TID table, "
"continuing\n");
......
/*
* This file is part of the Chelsio T4 Ethernet driver for Linux.
*
* Copyright (c) 2016 Chelsio Communications, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/module.h>
#include <linux/netdevice.h>
#include "cxgb4.h"
#include "sched.h"
/* Spinlock must be held by caller */
static int t4_sched_class_fw_cmd(struct port_info *pi,
struct ch_sched_params *p,
enum sched_fw_ops op)
{
struct adapter *adap = pi->adapter;
struct sched_table *s = pi->sched_tbl;
struct sched_class *e;
int err = 0;
e = &s->tab[p->u.params.class];
switch (op) {
case SCHED_FW_OP_ADD:
err = t4_sched_params(adap, p->type,
p->u.params.level, p->u.params.mode,
p->u.params.rateunit,
p->u.params.ratemode,
p->u.params.channel, e->idx,
p->u.params.minrate, p->u.params.maxrate,
p->u.params.weight, p->u.params.pktsize);
break;
default:
err = -ENOTSUPP;
break;
}
return err;
}
/* Spinlock must be held by caller */
static int t4_sched_bind_unbind_op(struct port_info *pi, void *arg,
enum sched_bind_type type, bool bind)
{
struct adapter *adap = pi->adapter;
u32 fw_mnem, fw_class, fw_param;
unsigned int pf = adap->pf;
unsigned int vf = 0;
int err = 0;
switch (type) {
case SCHED_QUEUE: {
struct sched_queue_entry *qe;
qe = (struct sched_queue_entry *)arg;
/* Create a template for the FW_PARAMS_CMD mnemonic and
* value (TX Scheduling Class in this case).
*/
fw_mnem = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DMAQ) |
FW_PARAMS_PARAM_X_V(
FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH));
fw_class = bind ? qe->param.class : FW_SCHED_CLS_NONE;
fw_param = (fw_mnem | FW_PARAMS_PARAM_YZ_V(qe->cntxt_id));
pf = adap->pf;
vf = 0;
break;
}
default:
err = -ENOTSUPP;
goto out;
}
err = t4_set_params(adap, adap->mbox, pf, vf, 1, &fw_param, &fw_class);
out:
return err;
}
static struct sched_class *t4_sched_queue_lookup(struct port_info *pi,
const unsigned int qid,
int *index)
{
struct sched_table *s = pi->sched_tbl;
struct sched_class *e, *end;
struct sched_class *found = NULL;
int i;
/* Look for a class with matching bound queue parameters */
end = &s->tab[s->sched_size];
for (e = &s->tab[0]; e != end; ++e) {
struct sched_queue_entry *qe;
i = 0;
if (e->state == SCHED_STATE_UNUSED)
continue;
list_for_each_entry(qe, &e->queue_list, list) {
if (qe->cntxt_id == qid) {
found = e;
if (index)
*index = i;
break;
}
i++;
}
if (found)
break;
}
return found;
}
static int t4_sched_queue_unbind(struct port_info *pi, struct ch_sched_queue *p)
{
struct adapter *adap = pi->adapter;
struct sched_class *e;
struct sched_queue_entry *qe = NULL;
struct sge_eth_txq *txq;
unsigned int qid;
int index = -1;
int err = 0;
if (p->queue < 0 || p->queue >= pi->nqsets)
return -ERANGE;
txq = &adap->sge.ethtxq[pi->first_qset + p->queue];
qid = txq->q.cntxt_id;
/* Find the existing class that the queue is bound to */
e = t4_sched_queue_lookup(pi, qid, &index);
if (e && index >= 0) {
int i = 0;
spin_lock(&e->lock);
list_for_each_entry(qe, &e->queue_list, list) {
if (i == index)
break;
i++;
}
err = t4_sched_bind_unbind_op(pi, (void *)qe, SCHED_QUEUE,
false);
if (err) {
spin_unlock(&e->lock);
goto out;
}
list_del(&qe->list);
t4_free_mem(qe);
if (atomic_dec_and_test(&e->refcnt)) {
e->state = SCHED_STATE_UNUSED;
memset(&e->info, 0, sizeof(e->info));
}
spin_unlock(&e->lock);
}
out:
return err;
}
static int t4_sched_queue_bind(struct port_info *pi, struct ch_sched_queue *p)
{
struct adapter *adap = pi->adapter;
struct sched_table *s = pi->sched_tbl;
struct sched_class *e;
struct sched_queue_entry *qe = NULL;
struct sge_eth_txq *txq;
unsigned int qid;
int err = 0;
if (p->queue < 0 || p->queue >= pi->nqsets)
return -ERANGE;
qe = t4_alloc_mem(sizeof(struct sched_queue_entry));
if (!qe)
return -ENOMEM;
txq = &adap->sge.ethtxq[pi->first_qset + p->queue];
qid = txq->q.cntxt_id;
/* Unbind queue from any existing class */
err = t4_sched_queue_unbind(pi, p);
if (err)
goto out;
/* Bind queue to specified class */
memset(qe, 0, sizeof(*qe));
qe->cntxt_id = qid;
memcpy(&qe->param, p, sizeof(qe->param));
e = &s->tab[qe->param.class];
spin_lock(&e->lock);
err = t4_sched_bind_unbind_op(pi, (void *)qe, SCHED_QUEUE, true);
if (err) {
t4_free_mem(qe);
spin_unlock(&e->lock);
goto out;
}
list_add_tail(&qe->list, &e->queue_list);
atomic_inc(&e->refcnt);
spin_unlock(&e->lock);
out:
return err;
}
static void t4_sched_class_unbind_all(struct port_info *pi,
struct sched_class *e,
enum sched_bind_type type)
{
if (!e)
return;
switch (type) {
case SCHED_QUEUE: {
struct sched_queue_entry *qe;
list_for_each_entry(qe, &e->queue_list, list)
t4_sched_queue_unbind(pi, &qe->param);
break;
}
default:
break;
}
}
static int t4_sched_class_bind_unbind_op(struct port_info *pi, void *arg,
enum sched_bind_type type, bool bind)
{
int err = 0;
if (!arg)
return -EINVAL;
switch (type) {
case SCHED_QUEUE: {
struct ch_sched_queue *qe = (struct ch_sched_queue *)arg;
if (bind)
err = t4_sched_queue_bind(pi, qe);
else
err = t4_sched_queue_unbind(pi, qe);
break;
}
default:
err = -ENOTSUPP;
break;
}
return err;
}
/**
* cxgb4_sched_class_bind - Bind an entity to a scheduling class
* @dev: net_device pointer
* @arg: Entity opaque data
* @type: Entity type (Queue)
*
* Binds an entity (queue) to a scheduling class. If the entity
* is bound to another class, it will be unbound from the other class
* and bound to the class specified in @arg.
*/
int cxgb4_sched_class_bind(struct net_device *dev, void *arg,
enum sched_bind_type type)
{
struct port_info *pi = netdev2pinfo(dev);
struct sched_table *s;
int err = 0;
u8 class_id;
if (!can_sched(dev))
return -ENOTSUPP;
if (!arg)
return -EINVAL;
switch (type) {
case SCHED_QUEUE: {
struct ch_sched_queue *qe = (struct ch_sched_queue *)arg;
class_id = qe->class;
break;
}
default:
return -ENOTSUPP;
}
if (!valid_class_id(dev, class_id))
return -EINVAL;
if (class_id == SCHED_CLS_NONE)
return -ENOTSUPP;
s = pi->sched_tbl;
write_lock(&s->rw_lock);
err = t4_sched_class_bind_unbind_op(pi, arg, type, true);
write_unlock(&s->rw_lock);
return err;
}
/**
* cxgb4_sched_class_unbind - Unbind an entity from a scheduling class
* @dev: net_device pointer
* @arg: Entity opaque data
* @type: Entity type (Queue)
*
* Unbinds an entity (queue) from a scheduling class.
*/
int cxgb4_sched_class_unbind(struct net_device *dev, void *arg,
enum sched_bind_type type)
{
struct port_info *pi = netdev2pinfo(dev);
struct sched_table *s;
int err = 0;
u8 class_id;
if (!can_sched(dev))
return -ENOTSUPP;
if (!arg)
return -EINVAL;
switch (type) {
case SCHED_QUEUE: {
struct ch_sched_queue *qe = (struct ch_sched_queue *)arg;
class_id = qe->class;
break;
}
default:
return -ENOTSUPP;
}
if (!valid_class_id(dev, class_id))
return -EINVAL;
s = pi->sched_tbl;
write_lock(&s->rw_lock);
err = t4_sched_class_bind_unbind_op(pi, arg, type, false);
write_unlock(&s->rw_lock);
return err;
}
/* If @p is NULL, fetch any available unused class */
static struct sched_class *t4_sched_class_lookup(struct port_info *pi,
const struct ch_sched_params *p)
{
struct sched_table *s = pi->sched_tbl;
struct sched_class *e, *end;
struct sched_class *found = NULL;
if (!p) {
/* Get any available unused class */
end = &s->tab[s->sched_size];
for (e = &s->tab[0]; e != end; ++e) {
if (e->state == SCHED_STATE_UNUSED) {
found = e;
break;
}
}
} else {
/* Look for a class with matching scheduling parameters */
struct ch_sched_params info;
struct ch_sched_params tp;
memset(&info, 0, sizeof(info));
memset(&tp, 0, sizeof(tp));
memcpy(&tp, p, sizeof(tp));
/* Don't try to match class parameter */
tp.u.params.class = SCHED_CLS_NONE;
end = &s->tab[s->sched_size];
for (e = &s->tab[0]; e != end; ++e) {
if (e->state == SCHED_STATE_UNUSED)
continue;
memset(&info, 0, sizeof(info));
memcpy(&info, &e->info, sizeof(info));
/* Don't try to match class parameter */
info.u.params.class = SCHED_CLS_NONE;
if ((info.type == tp.type) &&
(!memcmp(&info.u.params, &tp.u.params,
sizeof(info.u.params)))) {
found = e;
break;
}
}
}
return found;
}
static struct sched_class *t4_sched_class_alloc(struct port_info *pi,
struct ch_sched_params *p)
{
struct sched_table *s = pi->sched_tbl;
struct sched_class *e;
u8 class_id;
int err;
if (!p)
return NULL;
class_id = p->u.params.class;
/* Only accept search for existing class with matching params
* or allocation of new class with specified params
*/
if (class_id != SCHED_CLS_NONE)
return NULL;
write_lock(&s->rw_lock);
/* See if there's an exisiting class with same
* requested sched params
*/
e = t4_sched_class_lookup(pi, p);
if (!e) {
struct ch_sched_params np;
/* Fetch any available unused class */
e = t4_sched_class_lookup(pi, NULL);
if (!e)
goto out;
memset(&np, 0, sizeof(np));
memcpy(&np, p, sizeof(np));
np.u.params.class = e->idx;
spin_lock(&e->lock);
/* New class */
err = t4_sched_class_fw_cmd(pi, &np, SCHED_FW_OP_ADD);
if (err) {
spin_unlock(&e->lock);
e = NULL;
goto out;
}
memcpy(&e->info, &np, sizeof(e->info));
atomic_set(&e->refcnt, 0);
e->state = SCHED_STATE_ACTIVE;
spin_unlock(&e->lock);
}
out:
write_unlock(&s->rw_lock);
return e;
}
/**
* cxgb4_sched_class_alloc - allocate a scheduling class
* @dev: net_device pointer
* @p: new scheduling class to create.
*
* Returns pointer to the scheduling class created. If @p is NULL, then
* it allocates and returns any available unused scheduling class. If a
* scheduling class with matching @p is found, then the matching class is
* returned.
*/
struct sched_class *cxgb4_sched_class_alloc(struct net_device *dev,
struct ch_sched_params *p)
{
struct port_info *pi = netdev2pinfo(dev);
u8 class_id;
if (!can_sched(dev))
return NULL;
class_id = p->u.params.class;
if (!valid_class_id(dev, class_id))
return NULL;
return t4_sched_class_alloc(pi, p);
}
static void t4_sched_class_free(struct port_info *pi, struct sched_class *e)
{
t4_sched_class_unbind_all(pi, e, SCHED_QUEUE);
}
struct sched_table *t4_init_sched(unsigned int sched_size)
{
struct sched_table *s;
unsigned int i;
s = t4_alloc_mem(sizeof(*s) + sched_size * sizeof(struct sched_class));
if (!s)
return NULL;
s->sched_size = sched_size;
rwlock_init(&s->rw_lock);
for (i = 0; i < s->sched_size; i++) {
memset(&s->tab[i], 0, sizeof(struct sched_class));
s->tab[i].idx = i;
s->tab[i].state = SCHED_STATE_UNUSED;
INIT_LIST_HEAD(&s->tab[i].queue_list);
spin_lock_init(&s->tab[i].lock);
atomic_set(&s->tab[i].refcnt, 0);
}
return s;
}
void t4_cleanup_sched(struct adapter *adap)
{
struct sched_table *s;
unsigned int i;
for_each_port(adap, i) {
struct port_info *pi = netdev2pinfo(adap->port[i]);
s = pi->sched_tbl;
for (i = 0; i < s->sched_size; i++) {
struct sched_class *e;
write_lock(&s->rw_lock);
e = &s->tab[i];
if (e->state == SCHED_STATE_ACTIVE)
t4_sched_class_free(pi, e);
write_unlock(&s->rw_lock);
}
t4_free_mem(s);
}
}
/*
* This file is part of the Chelsio T4 Ethernet driver for Linux.
*
* Copyright (c) 2016 Chelsio Communications, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __CXGB4_SCHED_H
#define __CXGB4_SCHED_H
#include <linux/spinlock.h>
#include <linux/atomic.h>
#define SCHED_CLS_NONE 0xff
#define FW_SCHED_CLS_NONE 0xffffffff
/* Max rate that can be set to a scheduling class is 10 Gbps */
#define SCHED_MAX_RATE_KBPS 10000000U
enum {
SCHED_STATE_ACTIVE,
SCHED_STATE_UNUSED,
};
enum sched_fw_ops {
SCHED_FW_OP_ADD,
};
enum sched_bind_type {
SCHED_QUEUE,
};
struct sched_queue_entry {
struct list_head list;
unsigned int cntxt_id;
struct ch_sched_queue param;
};
struct sched_class {
u8 state;
u8 idx;
struct ch_sched_params info;
struct list_head queue_list;
spinlock_t lock; /* Per class lock */
atomic_t refcnt;
};
struct sched_table { /* per port scheduling table */
u8 sched_size;
rwlock_t rw_lock; /* Table lock */
struct sched_class tab[0];
};
static inline bool can_sched(struct net_device *dev)
{
struct port_info *pi = netdev2pinfo(dev);
return !pi->sched_tbl ? false : true;
}
static inline bool valid_class_id(struct net_device *dev, u8 class_id)
{
struct port_info *pi = netdev2pinfo(dev);
if ((class_id > pi->sched_tbl->sched_size - 1) &&
(class_id != SCHED_CLS_NONE))
return false;
return true;
}
int cxgb4_sched_class_bind(struct net_device *dev, void *arg,
enum sched_bind_type type);
int cxgb4_sched_class_unbind(struct net_device *dev, void *arg,
enum sched_bind_type type);
struct sched_class *cxgb4_sched_class_alloc(struct net_device *dev,
struct ch_sched_params *p);
struct sched_table *t4_init_sched(unsigned int size);
void t4_cleanup_sched(struct adapter *adap);
#endif /* __CXGB4_SCHED_H */
/*
* This file is part of the Chelsio T4 Ethernet driver for Linux.
*
* Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved.
* Copyright (c) 2003-2016 Chelsio Communications, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
......@@ -8305,3 +8305,32 @@ int t4_set_vf_mac_acl(struct adapter *adapter, unsigned int vf,
return t4_wr_mbox(adapter, adapter->mbox, &cmd, sizeof(cmd), &cmd);
}
int t4_sched_params(struct adapter *adapter, int type, int level, int mode,
int rateunit, int ratemode, int channel, int class,
int minrate, int maxrate, int weight, int pktsize)
{
struct fw_sched_cmd cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.op_to_write = cpu_to_be32(FW_CMD_OP_V(FW_SCHED_CMD) |
FW_CMD_REQUEST_F |
FW_CMD_WRITE_F);
cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
cmd.u.params.sc = FW_SCHED_SC_PARAMS;
cmd.u.params.type = type;
cmd.u.params.level = level;
cmd.u.params.mode = mode;
cmd.u.params.ch = channel;
cmd.u.params.cl = class;
cmd.u.params.unit = rateunit;
cmd.u.params.rate = ratemode;
cmd.u.params.min = cpu_to_be32(minrate);
cmd.u.params.max = cpu_to_be32(maxrate);
cmd.u.params.weight = cpu_to_be16(weight);
cmd.u.params.pktsize = cpu_to_be16(pktsize);
return t4_wr_mbox_meat(adapter, adapter->mbox, &cmd, sizeof(cmd),
NULL, 1);
}
/*
* This file is part of the Chelsio T4 Ethernet driver for Linux.
*
* Copyright (c) 2009-2014 Chelsio Communications, Inc. All rights reserved.
* Copyright (c) 2009-2016 Chelsio Communications, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
......@@ -681,6 +681,7 @@ enum fw_cmd_opcodes {
FW_RSS_IND_TBL_CMD = 0x20,
FW_RSS_GLB_CONFIG_CMD = 0x22,
FW_RSS_VI_CONFIG_CMD = 0x23,
FW_SCHED_CMD = 0x24,
FW_DEVLOG_CMD = 0x25,
FW_CLIP_CMD = 0x28,
FW_LASTC2E_CMD = 0x40,
......@@ -2962,6 +2963,41 @@ struct fw_rss_vi_config_cmd {
#define FW_RSS_VI_CONFIG_CMD_UDPEN_V(x) ((x) << FW_RSS_VI_CONFIG_CMD_UDPEN_S)
#define FW_RSS_VI_CONFIG_CMD_UDPEN_F FW_RSS_VI_CONFIG_CMD_UDPEN_V(1U)
enum fw_sched_sc {
FW_SCHED_SC_PARAMS = 1,
};
struct fw_sched_cmd {
__be32 op_to_write;
__be32 retval_len16;
union fw_sched {
struct fw_sched_config {
__u8 sc;
__u8 type;
__u8 minmaxen;
__u8 r3[5];
__u8 nclasses[4];
__be32 r4;
} config;
struct fw_sched_params {
__u8 sc;
__u8 type;
__u8 level;
__u8 mode;
__u8 unit;
__u8 rate;
__u8 ch;
__u8 cl;
__be32 min;
__be32 max;
__be16 weight;
__be16 pktsize;
__be16 burstsize;
__be16 r4;
} params;
} u;
};
struct fw_clip_cmd {
__be32 op_to_write;
__be32 alloc_to_len16;
......
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