cxgbe(4): knobs to enable/disable PAUSE frame based flow control.
MFC after: 1 week
This commit is contained in:
parent
de3307644e
commit
3eb2c201a6
@ -240,8 +240,19 @@ The default is -1 which lets the driver pick a pad boundary.
|
||||
Controls the hardware response to congestion.
|
||||
-1 disables congestion feedback and is not recommended.
|
||||
0 instructs the hardware to backpressure its pipeline on congestion.
|
||||
This usually results in the port emitting pause frames.
|
||||
This usually results in the port emitting PAUSE frames.
|
||||
1 instructs the hardware to drop frames destined for congested queues.
|
||||
.It Va hw.cxgbe.pause_settings
|
||||
PAUSE frame settings.
|
||||
Bit 0 is rx_pause, bit 1 is tx_pause.
|
||||
rx_pause = 1 instructs the hardware to heed incoming PAUSE frames, 0 instructs
|
||||
it to ignore them.
|
||||
tx_pause = 1 allows the hardware to emit PAUSE frames when its receive FIFO
|
||||
reaches a high threshold, 0 prohibits the hardware from emitting PAUSE frames.
|
||||
The default is 3 (both rx_pause and tx_pause = 1).
|
||||
This tunable establishes the default PAUSE settings for all ports.
|
||||
Settings can be displayed and controlled on a per-port basis via the
|
||||
dev.cxgbe.X.pause_settings (dev.cxl.X.pause_settings for T5 cards) sysctl.
|
||||
.It Va hw.cxgbe.buffer_packing
|
||||
Allow the hardware to deliver multiple frames in the same receive buffer
|
||||
opportunistically.
|
||||
|
@ -280,6 +280,15 @@ TUNABLE_INT("hw.cxgbe.interrupt_types", &t4_intr_types);
|
||||
static char t4_cfg_file[32] = DEFAULT_CF;
|
||||
TUNABLE_STR("hw.cxgbe.config_file", t4_cfg_file, sizeof(t4_cfg_file));
|
||||
|
||||
/*
|
||||
* PAUSE settings (bit 0, 1 = rx_pause, tx_pause respectively).
|
||||
* rx_pause = 1 to heed incoming PAUSE frames, 0 to ignore them.
|
||||
* tx_pause = 1 to emit PAUSE frames when the rx FIFO reaches its high water
|
||||
* mark or when signalled to do so, 0 to never emit PAUSE.
|
||||
*/
|
||||
static int t4_pause_settings = PAUSE_TX | PAUSE_RX;
|
||||
TUNABLE_INT("hw.cxgbe.pause_settings", &t4_pause_settings);
|
||||
|
||||
/*
|
||||
* Firmware auto-install by driver during attach (0, 1, 2 = prohibited, allowed,
|
||||
* encouraged respectively).
|
||||
@ -393,6 +402,7 @@ static int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS);
|
||||
static int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS);
|
||||
static int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS);
|
||||
static int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS);
|
||||
static int sysctl_pause_settings(SYSCTL_HANDLER_ARGS);
|
||||
static int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS);
|
||||
static int sysctl_temperature(SYSCTL_HANDLER_ARGS);
|
||||
#ifdef SBUF_DRAIN
|
||||
@ -697,6 +707,12 @@ t4_attach(device_t dev)
|
||||
sc->port[i] = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
pi->link_cfg.requested_fc &= ~(PAUSE_TX | PAUSE_RX);
|
||||
pi->link_cfg.requested_fc |= t4_pause_settings;
|
||||
pi->link_cfg.fc &= ~(PAUSE_TX | PAUSE_RX);
|
||||
pi->link_cfg.fc |= t4_pause_settings;
|
||||
|
||||
rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg);
|
||||
if (rc != 0) {
|
||||
device_printf(dev, "port %d l1cfg failed: %d\n", i, rc);
|
||||
@ -4771,6 +4787,10 @@ cxgbe_sysctls(struct port_info *pi)
|
||||
CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_txq, "I",
|
||||
"tx queue size");
|
||||
|
||||
SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pause_settings",
|
||||
CTLTYPE_STRING | CTLFLAG_RW, pi, PAUSE_TX, sysctl_pause_settings,
|
||||
"A", "PAUSE settings (bit 0 = rx_pause, bit 1 = tx_pause)");
|
||||
|
||||
/*
|
||||
* dev.cxgbe.X.stats.
|
||||
*/
|
||||
@ -5151,6 +5171,65 @@ sysctl_qsize_txq(SYSCTL_HANDLER_ARGS)
|
||||
return (rc);
|
||||
}
|
||||
|
||||
static int
|
||||
sysctl_pause_settings(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
struct port_info *pi = arg1;
|
||||
struct adapter *sc = pi->adapter;
|
||||
struct link_config *lc = &pi->link_cfg;
|
||||
int rc;
|
||||
|
||||
if (req->newptr == NULL) {
|
||||
struct sbuf *sb;
|
||||
static char *bits = "\20\1PAUSE_RX\2PAUSE_TX";
|
||||
|
||||
rc = sysctl_wire_old_buffer(req, 0);
|
||||
if (rc != 0)
|
||||
return(rc);
|
||||
|
||||
sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
|
||||
if (sb == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
sbuf_printf(sb, "%b", lc->fc & (PAUSE_TX | PAUSE_RX), bits);
|
||||
rc = sbuf_finish(sb);
|
||||
sbuf_delete(sb);
|
||||
} else {
|
||||
char s[2];
|
||||
int n;
|
||||
|
||||
s[0] = '0' + (lc->requested_fc & (PAUSE_TX | PAUSE_RX));
|
||||
s[1] = 0;
|
||||
|
||||
rc = sysctl_handle_string(oidp, s, sizeof(s), req);
|
||||
if (rc != 0)
|
||||
return(rc);
|
||||
|
||||
if (s[1] != 0)
|
||||
return (EINVAL);
|
||||
if (s[0] < '0' || s[0] > '9')
|
||||
return (EINVAL); /* not a number */
|
||||
n = s[0] - '0';
|
||||
if (n & ~(PAUSE_TX | PAUSE_RX))
|
||||
return (EINVAL); /* some other bit is set too */
|
||||
|
||||
rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4PAUSE");
|
||||
if (rc)
|
||||
return (rc);
|
||||
if ((lc->requested_fc & (PAUSE_TX | PAUSE_RX)) != n) {
|
||||
int link_ok = lc->link_ok;
|
||||
|
||||
lc->requested_fc &= ~(PAUSE_TX | PAUSE_RX);
|
||||
lc->requested_fc |= n;
|
||||
rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, lc);
|
||||
lc->link_ok = link_ok; /* restore */
|
||||
}
|
||||
end_synchronized_op(sc, 0);
|
||||
}
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
static int
|
||||
sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user