Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e0c6d1d8 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'cxgb4-SGE-doorbell-queue-timer'



Vishal Kulkarni says:

====================
cxgb4/cxgb4vfSupport for SGE doorbell queue timer

This series of patchs add SGE doorbell queue timer for faster DMA completions.

Patch 1 Implements SGE doorbell queue timer

Patch 2 Adds ethtool capability to set/get SGE doorbell queue timer tick

v2
- Reverse christmas tree formatting for local variables.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f694be27 543a1b85
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -617,6 +617,7 @@ enum { /* adapter flags */
	FW_OFLD_CONN       = (1 << 9),
	ROOT_NO_RELAXED_ORDERING = (1 << 10),
	SHUTTING_DOWN	   = (1 << 11),
	SGE_DBQ_TIMER      = (1 << 12),
};

enum {
@@ -756,6 +757,8 @@ struct sge_eth_txq { /* state for an SGE Ethernet Tx queue */
#ifdef CONFIG_CHELSIO_T4_DCB
	u8 dcb_prio;		    /* DCB Priority bound to queue */
#endif
	u8 dbqt;                    /* SGE Doorbell Queue Timer in use */
	unsigned int dbqtimerix;    /* SGE Doorbell Queue Timer Index */
	unsigned long tso;          /* # of TSO requests */
	unsigned long tx_cso;       /* # of Tx checksum offloads */
	unsigned long vlan_ins;     /* # of Tx VLAN insertions */
@@ -816,6 +819,8 @@ struct sge {
	u16 nqs_per_uld;	    /* # of Rx queues per ULD */
	u16 timer_val[SGE_NTIMERS];
	u8 counter_val[SGE_NCOUNTERS];
	u16 dbqtimer_tick;
	u16 dbqtimer_val[SGE_NDBQTIMERS];
	u32 fl_pg_order;            /* large page allocation size */
	u32 stat_len;               /* length of status page at ring end */
	u32 pktshift;               /* padding between CPL & packet data */
@@ -1402,7 +1407,7 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
		     rspq_flush_handler_t flush_handler, int cong);
int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
			 struct net_device *dev, struct netdev_queue *netdevq,
			 unsigned int iqid);
			 unsigned int iqid, u8 dbqt);
int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq,
			  struct net_device *dev, unsigned int iqid,
			  unsigned int cmplqid);
@@ -1415,6 +1420,8 @@ irqreturn_t t4_sge_intr_msix(int irq, void *cookie);
int t4_sge_init(struct adapter *adap);
void t4_sge_start(struct adapter *adap);
void t4_sge_stop(struct adapter *adap);
int t4_sge_eth_txq_egress_update(struct adapter *adap, struct sge_eth_txq *q,
				 int maxreclaim);
void cxgb4_set_ethtool_ops(struct net_device *netdev);
int cxgb4_write_rss(const struct port_info *pi, const u16 *queues);
enum cpl_tx_tnl_lso_type cxgb_encap_offload_supported(struct sk_buff *skb);
@@ -1821,6 +1828,8 @@ int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
		    unsigned int vf, unsigned int eqid);
int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox, int ctxt_type);
int t4_read_sge_dbqtimers(struct adapter *adap, unsigned int ndbqtimers,
			  u16 *dbqtimers);
void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl);
int t4_update_port_info(struct port_info *pi);
int t4_get_link_params(struct port_info *pi, unsigned int *link_okp,
+185 −4
Original line number Diff line number Diff line
@@ -932,11 +932,190 @@ static int get_adaptive_rx_setting(struct net_device *dev)
	return q->rspq.adaptive_rx;
}

static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
/* Return the current global Adapter SGE Doorbell Queue Timer Tick for all
 * Ethernet TX Queues.
 */
static int get_dbqtimer_tick(struct net_device *dev)
{
	struct port_info *pi = netdev_priv(dev);
	struct adapter *adap = pi->adapter;

	if (!(adap->flags & SGE_DBQ_TIMER))
		return 0;

	return adap->sge.dbqtimer_tick;
}

/* Return the SGE Doorbell Queue Timer Value for the Ethernet TX Queues
 * associated with a Network Device.
 */
static int get_dbqtimer(struct net_device *dev)
{
	struct port_info *pi = netdev_priv(dev);
	struct adapter *adap = pi->adapter;
	struct sge_eth_txq *txq;

	txq = &adap->sge.ethtxq[pi->first_qset];

	if (!(adap->flags & SGE_DBQ_TIMER))
		return 0;

	/* all of the TX Queues use the same Timer Index */
	return adap->sge.dbqtimer_val[txq->dbqtimerix];
}

/* Set the global Adapter SGE Doorbell Queue Timer Tick for all Ethernet TX
 * Queues.  This is the fundamental "Tick" that sets the scale of values which
 * can be used.  Individual Ethernet TX Queues index into a relatively small
 * array of Tick Multipliers.  Changing the base Tick will thus change all of
 * the resulting Timer Values associated with those multipliers for all
 * Ethernet TX Queues.
 */
static int set_dbqtimer_tick(struct net_device *dev, int usecs)
{
	struct port_info *pi = netdev_priv(dev);
	struct adapter *adap = pi->adapter;
	struct sge *s = &adap->sge;
	u32 param, val;
	int ret;

	if (!(adap->flags & SGE_DBQ_TIMER))
		return 0;

	/* return early if it's the same Timer Tick we're already using */
	if (s->dbqtimer_tick == usecs)
		return 0;

	/* attempt to set the new Timer Tick value */
	param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
		 FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DBQ_TIMERTICK));
	val = usecs;
	ret = t4_set_params(adap, adap->mbox, adap->pf, 0, 1, &param, &val);
	if (ret)
		return ret;
	s->dbqtimer_tick = usecs;

	/* if successful, reread resulting dependent Timer values */
	ret = t4_read_sge_dbqtimers(adap, ARRAY_SIZE(s->dbqtimer_val),
				    s->dbqtimer_val);
	return ret;
}

/* Set the SGE Doorbell Queue Timer Value for the Ethernet TX Queues
 * associated with a Network Device.  There is a relatively small array of
 * possible Timer Values so we need to pick the closest value available.
 */
static int set_dbqtimer(struct net_device *dev, int usecs)
{
	set_adaptive_rx_setting(dev, c->use_adaptive_rx_coalesce);
	return set_rx_intr_params(dev, c->rx_coalesce_usecs,
				  c->rx_max_coalesced_frames);
	int qix, timerix, min_timerix, delta, min_delta;
	struct port_info *pi = netdev_priv(dev);
	struct adapter *adap = pi->adapter;
	struct sge *s = &adap->sge;
	struct sge_eth_txq *txq;
	u32 param, val;
	int ret;

	if (!(adap->flags & SGE_DBQ_TIMER))
		return 0;

	/* Find the SGE Doorbell Timer Value that's closest to the requested
	 * value.
	 */
	min_delta = INT_MAX;
	min_timerix = 0;
	for (timerix = 0; timerix < ARRAY_SIZE(s->dbqtimer_val); timerix++) {
		delta = s->dbqtimer_val[timerix] - usecs;
		if (delta < 0)
			delta = -delta;
		if (delta < min_delta) {
			min_delta = delta;
			min_timerix = timerix;
		}
	}

	/* Return early if it's the same Timer Index we're already using.
	 * We use the same Timer Index for all of the TX Queues for an
	 * interface so it's only necessary to check the first one.
	 */
	txq = &s->ethtxq[pi->first_qset];
	if (txq->dbqtimerix == min_timerix)
		return 0;

	for (qix = 0; qix < pi->nqsets; qix++, txq++) {
		if (adap->flags & FULL_INIT_DONE) {
			param =
			 (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DMAQ) |
			  FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DMAQ_EQ_TIMERIX) |
			  FW_PARAMS_PARAM_YZ_V(txq->q.cntxt_id));
			val = min_timerix;
			ret = t4_set_params(adap, adap->mbox, adap->pf, 0,
					    1, &param, &val);
			if (ret)
				return ret;
		}
		txq->dbqtimerix = min_timerix;
	}
	return 0;
}

/* Set the global Adapter SGE Doorbell Queue Timer Tick for all Ethernet TX
 * Queues and the Timer Value for the Ethernet TX Queues associated with a
 * Network Device.  Since changing the global Tick changes all of the
 * available Timer Values, we need to do this first before selecting the
 * resulting closest Timer Value.  Moreover, since the Tick is global,
 * changing it affects the Timer Values for all Network Devices on the
 * adapter.  So, before changing the Tick, we grab all of the current Timer
 * Values for other Network Devices on this Adapter and then attempt to select
 * new Timer Values which are close to the old values ...
 */
static int set_dbqtimer_tickval(struct net_device *dev,
				int tick_usecs, int timer_usecs)
{
	struct port_info *pi = netdev_priv(dev);
	struct adapter *adap = pi->adapter;
	int timer[MAX_NPORTS];
	unsigned int port;
	int ret;

	/* Grab the other adapter Network Interface current timers and fill in
	 * the new one for this Network Interface.
	 */
	for_each_port(adap, port)
		if (port == pi->port_id)
			timer[port] = timer_usecs;
		else
			timer[port] = get_dbqtimer(adap->port[port]);

	/* Change the global Tick first ... */
	ret = set_dbqtimer_tick(dev, tick_usecs);
	if (ret)
		return ret;

	/* ... and then set all of the Network Interface Timer Values ... */
	for_each_port(adap, port) {
		ret = set_dbqtimer(adap->port[port], timer[port]);
		if (ret)
			return ret;
	}

	return 0;
}

static int set_coalesce(struct net_device *dev,
			struct ethtool_coalesce *coalesce)
{
	int ret;

	set_adaptive_rx_setting(dev, coalesce->use_adaptive_rx_coalesce);

	ret = set_rx_intr_params(dev, coalesce->rx_coalesce_usecs,
				 coalesce->rx_max_coalesced_frames);
	if (ret)
		return ret;

	return set_dbqtimer_tickval(dev,
				    coalesce->tx_coalesce_usecs_irq,
				    coalesce->tx_coalesce_usecs);
}

static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
@@ -949,6 +1128,8 @@ static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
	c->rx_max_coalesced_frames = (rq->intr_params & QINTR_CNT_EN_F) ?
		adap->sge.counter_val[rq->pktcnt_idx] : 0;
	c->use_adaptive_rx_coalesce = get_adaptive_rx_setting(dev);
	c->tx_coalesce_usecs_irq = get_dbqtimer_tick(dev);
	c->tx_coalesce_usecs = get_dbqtimer(dev);
	return 0;
}

+25 −4
Original line number Diff line number Diff line
@@ -575,7 +575,7 @@ static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp,
			struct sge_eth_txq *eq;

			eq = container_of(txq, struct sge_eth_txq, q);
			netif_tx_wake_queue(eq->txq);
			t4_sge_eth_txq_egress_update(q->adap, eq, -1);
		} else {
			struct sge_uld_txq *oq;

@@ -933,10 +933,13 @@ static int setup_sge_queues(struct adapter *adap)
			q->rspq.idx = j;
			memset(&q->stats, 0, sizeof(q->stats));
		}
		for (j = 0; j < pi->nqsets; j++, t++) {

		q = &s->ethrxq[pi->first_qset];
		for (j = 0; j < pi->nqsets; j++, t++, q++) {
			err = t4_sge_alloc_eth_txq(adap, t, dev,
					netdev_get_tx_queue(dev, j),
					s->fw_evtq.cntxt_id);
					q->rspq.cntxt_id,
					!!(adap->flags & SGE_DBQ_TIMER));
			if (err)
				goto freeout;
		}
@@ -958,7 +961,7 @@ static int setup_sge_queues(struct adapter *adap)
	if (!is_t4(adap->params.chip)) {
		err = t4_sge_alloc_eth_txq(adap, &s->ptptxq, adap->port[0],
					   netdev_get_tx_queue(adap->port[0], 0)
					   , s->fw_evtq.cntxt_id);
					   , s->fw_evtq.cntxt_id, false);
		if (err)
			goto freeout;
	}
@@ -4325,6 +4328,24 @@ static int adap_init0(struct adapter *adap)
	if (ret < 0)
		goto bye;

	/* Grab the SGE Doorbell Queue Timer values.  If successful, that
	 * indicates that the Firmware and Hardware support this.
	 */
	params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
		    FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DBQ_TIMERTICK));
	ret = t4_query_params(adap, adap->mbox, adap->pf, 0,
			      1, params, val);

	if (!ret) {
		adap->sge.dbqtimer_tick = val[0];
		ret = t4_read_sge_dbqtimers(adap,
					    ARRAY_SIZE(adap->sge.dbqtimer_val),
					    adap->sge.dbqtimer_val);
	}

	if (!ret)
		adap->flags |= SGE_DBQ_TIMER;

	if (is_bypass_device(adap->pdev->device))
		adap->params.bypass = 1;

+266 −56

File changed.

Preview size limit exceeded, changes collapsed.

+41 −0
Original line number Diff line number Diff line
@@ -6712,6 +6712,47 @@ int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox, int ctxt_type)
	return ret;
}

/**
 *	t4_read_sge_dbqtimers - reag SGE Doorbell Queue Timer values
 *	@adap - the adapter
 *	@ndbqtimers: size of the provided SGE Doorbell Queue Timer table
 *	@dbqtimers: SGE Doorbell Queue Timer table
 *
 *	Reads the SGE Doorbell Queue Timer values into the provided table.
 *	Returns 0 on success (Firmware and Hardware support this feature),
 *	an error on failure.
 */
int t4_read_sge_dbqtimers(struct adapter *adap, unsigned int ndbqtimers,
			  u16 *dbqtimers)
{
	int ret, dbqtimerix;

	ret = 0;
	dbqtimerix = 0;
	while (dbqtimerix < ndbqtimers) {
		int nparams, param;
		u32 params[7], vals[7];

		nparams = ndbqtimers - dbqtimerix;
		if (nparams > ARRAY_SIZE(params))
			nparams = ARRAY_SIZE(params);

		for (param = 0; param < nparams; param++)
			params[param] =
			  (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
			   FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DBQ_TIMER) |
			   FW_PARAMS_PARAM_Y_V(dbqtimerix + param));
		ret = t4_query_params(adap, adap->mbox, adap->pf, 0,
				      nparams, params, vals);
		if (ret)
			break;

		for (param = 0; param < nparams; param++)
			dbqtimers[dbqtimerix++] = vals[param];
	}
	return ret;
}

/**
 *      t4_fw_hello - establish communication with FW
 *      @adap: the adapter
Loading