cxgbe(4): Overhaul the shared code that deals with the chip's TP block,

which is responsible for filtering and RSS.

Add the ability to use filters that match on PF/VF (aka "VNIC id") while
here.  This is mutually exclusive with filtering on outer VLAN tag with
Q-in-Q.

Sponsored by:	Chelsio Communications
This commit is contained in:
Navdeep Parhar 2016-03-08 02:04:05 +00:00
parent 9610c89750
commit 700cfba72d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=296481
6 changed files with 443 additions and 180 deletions

View File

@ -1026,6 +1026,17 @@ tx_resume_threshold(struct sge_eq *eq)
return (eq->sidx / 4);
}
static inline int
t4_use_ldst(struct adapter *sc)
{
#ifdef notyet
return (sc->flags & FW_OK || !sc->use_bd);
#else
return (0);
#endif
}
/* t4_main.c */
int t4_os_find_pci_capability(struct adapter *, int);
int t4_os_pci_save_state(struct adapter *);

View File

@ -234,17 +234,25 @@ struct sge_params {
};
struct tp_params {
unsigned int ntxchan; /* # of Tx channels */
unsigned int tre; /* log2 of core clocks per TP tick */
unsigned int dack_re; /* DACK timer resolution */
unsigned int la_mask; /* what events are recorded by TP LA */
unsigned short tx_modq[MAX_NCHAN]; /* channel to modulation queue map */
uint32_t vlan_pri_map;
uint32_t ingress_config;
int8_t vlan_shift;
int8_t vnic_shift;
uint32_t rx_pkt_encap;
int8_t fcoe_shift;
int8_t port_shift;
int8_t vnic_shift;
int8_t vlan_shift;
int8_t tos_shift;
int8_t protocol_shift;
int8_t ethertype_shift;
int8_t macmatch_shift;
int8_t matchtype_shift;
int8_t frag_shift;
};
struct vpd_params {
@ -492,7 +500,6 @@ int t4_init_sge_params(struct adapter *adapter);
int t4_init_tp_params(struct adapter *adap);
int t4_filter_field_shift(const struct adapter *adap, int filter_sel);
int t4_port_init(struct port_info *p, int mbox, int pf, int vf);
int t4_reinit_adapter(struct adapter *adap);
void t4_fatal_err(struct adapter *adapter);
int t4_set_trace_filter(struct adapter *adapter, const struct trace_params *tp,
int filter_index, int enable);
@ -505,8 +512,10 @@ int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode,
int t4_config_vi_rss(struct adapter *adapter, int mbox, unsigned int viid,
unsigned int flags, unsigned int defq);
int t4_read_rss(struct adapter *adapter, u16 *entries);
void t4_fw_tp_pio_rw(struct adapter *adap, u32 *vals, unsigned int nregs,
unsigned int start_index, unsigned int rw);
void t4_read_rss_key(struct adapter *adapter, u32 *key);
void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx);
void t4_write_rss_key(struct adapter *adap, u32 *key, int idx);
void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index, u32 *valp);
void t4_write_rss_pf_config(struct adapter *adapter, unsigned int index, u32 val);
void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index,

View File

@ -4866,6 +4866,42 @@ int t4_read_rss(struct adapter *adapter, u16 *map)
return 0;
}
/**
* t4_fw_tp_pio_rw - Access TP PIO through LDST
* @adap: the adapter
* @vals: where the indirect register values are stored/written
* @nregs: how many indirect registers to read/write
* @start_idx: index of first indirect register to read/write
* @rw: Read (1) or Write (0)
*
* Access TP PIO registers through LDST
*/
void t4_fw_tp_pio_rw(struct adapter *adap, u32 *vals, unsigned int nregs,
unsigned int start_index, unsigned int rw)
{
int ret, i;
int cmd = FW_LDST_ADDRSPC_TP_PIO;
struct fw_ldst_cmd c;
for (i = 0 ; i < nregs; i++) {
memset(&c, 0, sizeof(c));
c.op_to_addrspace = cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) |
F_FW_CMD_REQUEST |
(rw ? F_FW_CMD_READ :
F_FW_CMD_WRITE) |
V_FW_LDST_CMD_ADDRSPACE(cmd));
c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c));
c.u.addrval.addr = cpu_to_be32(start_index + i);
c.u.addrval.val = rw ? 0 : cpu_to_be32(vals[i]);
ret = t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), &c);
if (ret == 0) {
if (rw)
vals[i] = be32_to_cpu(c.u.addrval.val);
}
}
}
/**
* t4_read_rss_key - read the global RSS key
* @adap: the adapter
@ -4875,8 +4911,11 @@ int t4_read_rss(struct adapter *adapter, u16 *map)
*/
void t4_read_rss_key(struct adapter *adap, u32 *key)
{
t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, key, 10,
A_TP_RSS_SECRET_KEY0);
if (t4_use_ldst(adap))
t4_fw_tp_pio_rw(adap, key, 10, A_TP_RSS_SECRET_KEY0, 1);
else
t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, key, 10,
A_TP_RSS_SECRET_KEY0);
}
/**
@ -4889,13 +4928,35 @@ void t4_read_rss_key(struct adapter *adap, u32 *key)
* 0..15 the corresponding entry in the RSS key table is written,
* otherwise the global RSS key is written.
*/
void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx)
void t4_write_rss_key(struct adapter *adap, u32 *key, int idx)
{
t4_write_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, key, 10,
A_TP_RSS_SECRET_KEY0);
if (idx >= 0 && idx < 16)
t4_write_reg(adap, A_TP_RSS_CONFIG_VRT,
V_KEYWRADDR(idx) | F_KEYWREN);
u8 rss_key_addr_cnt = 16;
u32 vrt = t4_read_reg(adap, A_TP_RSS_CONFIG_VRT);
/*
* T6 and later: for KeyMode 3 (per-vf and per-vf scramble),
* allows access to key addresses 16-63 by using KeyWrAddrX
* as index[5:4](upper 2) into key table
*/
if ((chip_id(adap) > CHELSIO_T5) &&
(vrt & F_KEYEXTEND) && (G_KEYMODE(vrt) == 3))
rss_key_addr_cnt = 32;
if (t4_use_ldst(adap))
t4_fw_tp_pio_rw(adap, key, 10, A_TP_RSS_SECRET_KEY0, 0);
else
t4_write_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, key, 10,
A_TP_RSS_SECRET_KEY0);
if (idx >= 0 && idx < rss_key_addr_cnt) {
if (rss_key_addr_cnt > 16)
t4_write_reg(adap, A_TP_RSS_CONFIG_VRT,
V_KEYWRADDRX(idx >> 4) |
V_T6_VFWRADDR(idx) | F_KEYWREN);
else
t4_write_reg(adap, A_TP_RSS_CONFIG_VRT,
V_KEYWRADDR(idx) | F_KEYWREN);
}
}
/**
@ -4907,10 +4968,15 @@ void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx)
* Reads the PF RSS Configuration Table at the specified index and returns
* the value found there.
*/
void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index, u32 *valp)
void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index,
u32 *valp)
{
t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
valp, 1, A_TP_RSS_PF0_CONFIG + index);
if (t4_use_ldst(adapter))
t4_fw_tp_pio_rw(adapter, valp, 1,
A_TP_RSS_PF0_CONFIG + index, 1);
else
t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
valp, 1, A_TP_RSS_PF0_CONFIG + index);
}
/**
@ -4922,10 +4988,15 @@ void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index, u32 *val
* Writes the PF RSS Configuration Table at the specified index with the
* specified value.
*/
void t4_write_rss_pf_config(struct adapter *adapter, unsigned int index, u32 val)
void t4_write_rss_pf_config(struct adapter *adapter, unsigned int index,
u32 val)
{
t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
&val, 1, A_TP_RSS_PF0_CONFIG + index);
if (t4_use_ldst(adapter))
t4_fw_tp_pio_rw(adapter, &val, 1,
A_TP_RSS_PF0_CONFIG + index, 0);
else
t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
&val, 1, A_TP_RSS_PF0_CONFIG + index);
}
/**
@ -4941,28 +5012,40 @@ void t4_write_rss_pf_config(struct adapter *adapter, unsigned int index, u32 val
void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index,
u32 *vfl, u32 *vfh)
{
u32 vrt;
u32 vrt, mask, data;
if (chip_id(adapter) <= CHELSIO_T5) {
mask = V_VFWRADDR(M_VFWRADDR);
data = V_VFWRADDR(index);
} else {
mask = V_T6_VFWRADDR(M_T6_VFWRADDR);
data = V_T6_VFWRADDR(index);
}
/*
* Request that the index'th VF Table values be read into VFL/VFH.
*/
vrt = t4_read_reg(adapter, A_TP_RSS_CONFIG_VRT);
vrt &= ~(F_VFRDRG | V_VFWRADDR(M_VFWRADDR) | F_VFWREN | F_KEYWREN);
vrt |= V_VFWRADDR(index) | F_VFRDEN;
vrt &= ~(F_VFRDRG | F_VFWREN | F_KEYWREN | mask);
vrt |= data | F_VFRDEN;
t4_write_reg(adapter, A_TP_RSS_CONFIG_VRT, vrt);
/*
* Grab the VFL/VFH values ...
*/
t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
vfl, 1, A_TP_RSS_VFL_CONFIG);
t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
vfh, 1, A_TP_RSS_VFH_CONFIG);
if (t4_use_ldst(adapter)) {
t4_fw_tp_pio_rw(adapter, vfl, 1, A_TP_RSS_VFL_CONFIG, 1);
t4_fw_tp_pio_rw(adapter, vfh, 1, A_TP_RSS_VFH_CONFIG, 1);
} else {
t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
vfl, 1, A_TP_RSS_VFL_CONFIG);
t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
vfh, 1, A_TP_RSS_VFH_CONFIG);
}
}
/**
* t4_write_rss_vf_config - write VF RSS Configuration Table
*
*
* @adapter: the adapter
* @index: the entry in the VF RSS table to write
* @vfl: the VFL to store
@ -4974,22 +5057,35 @@ void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index,
void t4_write_rss_vf_config(struct adapter *adapter, unsigned int index,
u32 vfl, u32 vfh)
{
u32 vrt;
u32 vrt, mask, data;
if (chip_id(adapter) <= CHELSIO_T5) {
mask = V_VFWRADDR(M_VFWRADDR);
data = V_VFWRADDR(index);
} else {
mask = V_T6_VFWRADDR(M_T6_VFWRADDR);
data = V_T6_VFWRADDR(index);
}
/*
* Load up VFL/VFH with the values to be written ...
*/
t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
&vfl, 1, A_TP_RSS_VFL_CONFIG);
t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
&vfh, 1, A_TP_RSS_VFH_CONFIG);
if (t4_use_ldst(adapter)) {
t4_fw_tp_pio_rw(adapter, &vfl, 1, A_TP_RSS_VFL_CONFIG, 0);
t4_fw_tp_pio_rw(adapter, &vfh, 1, A_TP_RSS_VFH_CONFIG, 0);
} else {
t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
&vfl, 1, A_TP_RSS_VFL_CONFIG);
t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
&vfh, 1, A_TP_RSS_VFH_CONFIG);
}
/*
* Write the VFL/VFH into the VF Table at index'th location.
*/
vrt = t4_read_reg(adapter, A_TP_RSS_CONFIG_VRT);
vrt &= ~(F_VFRDRG | F_VFRDEN | V_VFWRADDR(M_VFWRADDR) | F_KEYWREN);
vrt |= V_VFWRADDR(index) | F_VFWREN;
vrt &= ~(F_VFRDRG | F_VFWREN | F_KEYWREN | mask);
vrt |= data | F_VFRDEN;
t4_write_reg(adapter, A_TP_RSS_CONFIG_VRT, vrt);
}
@ -5003,8 +5099,11 @@ u32 t4_read_rss_pf_map(struct adapter *adapter)
{
u32 pfmap;
t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
&pfmap, 1, A_TP_RSS_PF_MAP);
if (t4_use_ldst(adapter))
t4_fw_tp_pio_rw(adapter, &pfmap, 1, A_TP_RSS_PF_MAP, 1);
else
t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
&pfmap, 1, A_TP_RSS_PF_MAP);
return pfmap;
}
@ -5017,8 +5116,11 @@ u32 t4_read_rss_pf_map(struct adapter *adapter)
*/
void t4_write_rss_pf_map(struct adapter *adapter, u32 pfmap)
{
t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
&pfmap, 1, A_TP_RSS_PF_MAP);
if (t4_use_ldst(adapter))
t4_fw_tp_pio_rw(adapter, &pfmap, 1, A_TP_RSS_PF_MAP, 0);
else
t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
&pfmap, 1, A_TP_RSS_PF_MAP);
}
/**
@ -5031,8 +5133,11 @@ u32 t4_read_rss_pf_mask(struct adapter *adapter)
{
u32 pfmask;
t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
&pfmask, 1, A_TP_RSS_PF_MSK);
if (t4_use_ldst(adapter))
t4_fw_tp_pio_rw(adapter, &pfmask, 1, A_TP_RSS_PF_MSK, 1);
else
t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
&pfmask, 1, A_TP_RSS_PF_MSK);
return pfmask;
}
@ -5045,61 +5150,11 @@ u32 t4_read_rss_pf_mask(struct adapter *adapter)
*/
void t4_write_rss_pf_mask(struct adapter *adapter, u32 pfmask)
{
t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
&pfmask, 1, A_TP_RSS_PF_MSK);
}
static void refresh_vlan_pri_map(struct adapter *adap)
{
t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA,
&adap->params.tp.vlan_pri_map, 1,
A_TP_VLAN_PRI_MAP);
/*
* Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field
* shift positions of several elements of the Compressed Filter Tuple
* for this adapter which we need frequently ...
*/
adap->params.tp.vlan_shift = t4_filter_field_shift(adap, F_VLAN);
adap->params.tp.vnic_shift = t4_filter_field_shift(adap, F_VNIC_ID);
adap->params.tp.port_shift = t4_filter_field_shift(adap, F_PORT);
adap->params.tp.protocol_shift = t4_filter_field_shift(adap, F_PROTOCOL);
/*
* If TP_INGRESS_CONFIG.VNID == 0, then TP_VLAN_PRI_MAP.VNIC_ID
* represents the presense of an Outer VLAN instead of a VNIC ID.
*/
if ((adap->params.tp.ingress_config & F_VNIC) == 0)
adap->params.tp.vnic_shift = -1;
}
/**
* t4_set_filter_mode - configure the optional components of filter tuples
* @adap: the adapter
* @mode_map: a bitmap selcting which optional filter components to enable
*
* Sets the filter mode by selecting the optional components to enable
* in filter tuples. Returns 0 on success and a negative error if the
* requested mode needs more bits than are available for optional
* components.
*/
int t4_set_filter_mode(struct adapter *adap, unsigned int mode_map)
{
static u8 width[] = { 1, 3, 17, 17, 8, 8, 16, 9, 3, 1 };
int i, nbits = 0;
for (i = S_FCOE; i <= S_FRAGMENTATION; i++)
if (mode_map & (1 << i))
nbits += width[i];
if (nbits > FILTER_OPT_LEN)
return -EINVAL;
t4_write_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, &mode_map, 1,
A_TP_VLAN_PRI_MAP);
refresh_vlan_pri_map(adap);
return 0;
if (t4_use_ldst(adapter))
t4_fw_tp_pio_rw(adapter, &pfmask, 1, A_TP_RSS_PF_MSK, 0);
else
t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
&pfmask, 1, A_TP_RSS_PF_MSK);
}
/**
@ -7700,41 +7755,91 @@ int t4_init_sge_params(struct adapter *adapter)
return 0;
}
/**
* t4_init_tp_params - initialize adap->params.tp
* @adap: the adapter
*
* Initialize various fields of the adapter's TP Parameters structure.
/*
* Read and cache the adapter's compressed filter mode and ingress config.
*/
int __devinit t4_init_tp_params(struct adapter *adap)
static void read_filter_mode_and_ingress_config(struct adapter *adap)
{
struct tp_params *tpp = &adap->params.tp;
if (t4_use_ldst(adap)) {
t4_fw_tp_pio_rw(adap, &tpp->vlan_pri_map, 1,
A_TP_VLAN_PRI_MAP, 1);
t4_fw_tp_pio_rw(adap, &tpp->ingress_config, 1,
A_TP_INGRESS_CONFIG, 1);
} else {
t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA,
&tpp->vlan_pri_map, 1, A_TP_VLAN_PRI_MAP);
t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA,
&tpp->ingress_config, 1, A_TP_INGRESS_CONFIG);
}
/*
* Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field
* shift positions of several elements of the Compressed Filter Tuple
* for this adapter which we need frequently ...
*/
tpp->fcoe_shift = t4_filter_field_shift(adap, F_FCOE);
tpp->port_shift = t4_filter_field_shift(adap, F_PORT);
tpp->vnic_shift = t4_filter_field_shift(adap, F_VNIC_ID);
tpp->vlan_shift = t4_filter_field_shift(adap, F_VLAN);
tpp->tos_shift = t4_filter_field_shift(adap, F_TOS);
tpp->protocol_shift = t4_filter_field_shift(adap, F_PROTOCOL);
tpp->ethertype_shift = t4_filter_field_shift(adap, F_ETHERTYPE);
tpp->macmatch_shift = t4_filter_field_shift(adap, F_MACMATCH);
tpp->matchtype_shift = t4_filter_field_shift(adap, F_MPSHITTYPE);
tpp->frag_shift = t4_filter_field_shift(adap, F_FRAGMENTATION);
/*
* If TP_INGRESS_CONFIG.VNID == 0, then TP_VLAN_PRI_MAP.VNIC_ID
* represents the presense of an Outer VLAN instead of a VNIC ID.
*/
if ((tpp->ingress_config & F_VNIC) == 0)
tpp->vnic_shift = -1;
}
/**
* t4_init_tp_params - initialize adap->params.tp
* @adap: the adapter
*
* Initialize various fields of the adapter's TP Parameters structure.
*/
int t4_init_tp_params(struct adapter *adap)
{
int chan;
u32 v;
struct tp_params *tpp = &adap->params.tp;
v = t4_read_reg(adap, A_TP_TIMER_RESOLUTION);
adap->params.tp.tre = G_TIMERRESOLUTION(v);
adap->params.tp.dack_re = G_DELAYEDACKRESOLUTION(v);
tpp->tre = G_TIMERRESOLUTION(v);
tpp->dack_re = G_DELAYEDACKRESOLUTION(v);
/* MODQ_REQ_MAP defaults to setting queues 0-3 to chan 0-3 */
for (chan = 0; chan < MAX_NCHAN; chan++)
adap->params.tp.tx_modq[chan] = chan;
tpp->tx_modq[chan] = chan;
t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA,
&adap->params.tp.ingress_config, 1,
A_TP_INGRESS_CONFIG);
refresh_vlan_pri_map(adap);
read_filter_mode_and_ingress_config(adap);
/*
* For T6, cache the adapter's compressed error vector
* and passing outer header info for encapsulated packets.
*/
if (chip_id(adap) > CHELSIO_T5) {
v = t4_read_reg(adap, A_TP_OUT_CONFIG);
tpp->rx_pkt_encap = (v & F_CRXPKTENC) ? 1 : 0;
}
return 0;
}
/**
* t4_filter_field_shift - calculate filter field shift
* @adap: the adapter
* @filter_sel: the desired field (from TP_VLAN_PRI_MAP bits)
* t4_filter_field_shift - calculate filter field shift
* @adap: the adapter
* @filter_sel: the desired field (from TP_VLAN_PRI_MAP bits)
*
* Return the shift position of a filter field within the Compressed
* Filter Tuple. The filter field is specified via its selection bit
* within TP_VLAN_PRI_MAL (filter mode). E.g. F_VLAN.
* Return the shift position of a filter field within the Compressed
* Filter Tuple. The filter field is specified via its selection bit
* within TP_VLAN_PRI_MAL (filter mode). E.g. F_VLAN.
*/
int t4_filter_field_shift(const struct adapter *adap, int filter_sel)
{
@ -7746,18 +7851,38 @@ int t4_filter_field_shift(const struct adapter *adap, int filter_sel)
return -1;
for (sel = 1, field_shift = 0; sel < filter_sel; sel <<= 1) {
switch (filter_mode & sel) {
case F_FCOE: field_shift += W_FT_FCOE; break;
case F_PORT: field_shift += W_FT_PORT; break;
case F_VNIC_ID: field_shift += W_FT_VNIC_ID; break;
case F_VLAN: field_shift += W_FT_VLAN; break;
case F_TOS: field_shift += W_FT_TOS; break;
case F_PROTOCOL: field_shift += W_FT_PROTOCOL; break;
case F_ETHERTYPE: field_shift += W_FT_ETHERTYPE; break;
case F_MACMATCH: field_shift += W_FT_MACMATCH; break;
case F_MPSHITTYPE: field_shift += W_FT_MPSHITTYPE; break;
case F_FRAGMENTATION: field_shift += W_FT_FRAGMENTATION; break;
}
switch (filter_mode & sel) {
case F_FCOE:
field_shift += W_FT_FCOE;
break;
case F_PORT:
field_shift += W_FT_PORT;
break;
case F_VNIC_ID:
field_shift += W_FT_VNIC_ID;
break;
case F_VLAN:
field_shift += W_FT_VLAN;
break;
case F_TOS:
field_shift += W_FT_TOS;
break;
case F_PROTOCOL:
field_shift += W_FT_PROTOCOL;
break;
case F_ETHERTYPE:
field_shift += W_FT_ETHERTYPE;
break;
case F_MACMATCH:
field_shift += W_FT_MACMATCH;
break;
case F_MPSHITTYPE:
field_shift += W_FT_MPSHITTYPE;
break;
case F_FRAGMENTATION:
field_shift += W_FT_FRAGMENTATION;
break;
}
}
return field_shift;
}
@ -7822,6 +7947,37 @@ int __devinit t4_port_init(struct port_info *p, int mbox, int pf, int vf)
return 0;
}
/**
* t4_set_filter_mode - configure the optional components of filter tuples
* @adap: the adapter
* @mode_map: a bitmap selcting which optional filter components to enable
*
* Sets the filter mode by selecting the optional components to enable
* in filter tuples. Returns 0 on success and a negative error if the
* requested mode needs more bits than are available for optional
* components.
*/
int t4_set_filter_mode(struct adapter *adap, unsigned int mode_map)
{
static u8 width[] = { 1, 3, 17, 17, 8, 8, 16, 9, 3, 1 };
int i, nbits = 0;
for (i = S_FCOE; i <= S_FRAGMENTATION; i++)
if (mode_map & (1 << i))
nbits += width[i];
if (nbits > FILTER_OPT_LEN)
return -EINVAL;
if (t4_use_ldst(adap))
t4_fw_tp_pio_rw(adap, &mode_map, 1, A_TP_VLAN_PRI_MAP, 0);
else
t4_write_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, &mode_map,
1, A_TP_VLAN_PRI_MAP);
read_filter_mode_and_ingress_config(adap);
return 0;
}
int t4_sched_config(struct adapter *adapter, int type, int minmaxen,
int sleep_ok)
{

View File

@ -105,6 +105,12 @@ struct t4_i2c_data {
#define T4_FILTER_MPS_HIT_TYPE 0x4000 /* MPS match type */
#define T4_FILTER_IP_FRAGMENT 0x8000 /* IP fragment */
#define T4_FILTER_IC_VNIC 0x80000000 /* TP Ingress Config's F_VNIC
bit. It indicates whether
T4_FILTER_VNIC bit means VNIC
id (PF/VF) or outer VLAN.
0 = oVLAN, 1 = VNIC */
/* Filter action */
enum {
FILTER_PASS = 0, /* default */
@ -154,7 +160,7 @@ struct t4_filter_tuple {
* is used to select the global mode and all filters are limited to the
* set of fields allowed by the global mode.
*/
uint16_t vnic; /* VNIC id or outer VLAN tag */
uint16_t vnic; /* VNIC id (PF/VF) or outer VLAN tag */
uint16_t vlan; /* VLAN tag */
uint16_t ethtype; /* Ethernet type */
uint8_t tos; /* TOS/Traffic Type */
@ -165,7 +171,8 @@ struct t4_filter_tuple {
uint32_t frag:1; /* fragmentation extension header */
uint32_t macidx:9; /* exact match MAC index */
uint32_t vlan_vld:1; /* VLAN valid */
uint32_t vnic_vld:1; /* VNIC id/outer VLAN tag valid */
uint32_t ovlan_vld:1; /* outer VLAN tag valid, value in "vnic" */
uint32_t pfvf_vld:1; /* VNIC id (PF/VF) valid, value in "vnic" */
};
struct t4_filter_specification {

View File

@ -476,9 +476,11 @@ static int sysctl_tx_rate(SYSCTL_HANDLER_ARGS);
static int sysctl_ulprx_la(SYSCTL_HANDLER_ARGS);
static int sysctl_wcwr_stats(SYSCTL_HANDLER_ARGS);
#endif
static uint32_t fconf_to_mode(uint32_t);
static uint32_t fconf_iconf_to_mode(uint32_t, uint32_t);
static uint32_t mode_to_fconf(uint32_t);
static uint32_t fspec_to_fconf(struct t4_filter_specification *);
static uint32_t mode_to_iconf(uint32_t);
static int check_fspec_against_fconf_iconf(struct adapter *,
struct t4_filter_specification *);
static int get_filter_mode(struct adapter *, uint32_t *);
static int set_filter_mode(struct adapter *, uint32_t);
static inline uint64_t get_filter_hits(struct adapter *, uint32_t);
@ -3917,7 +3919,7 @@ vi_full_init(struct vi_info *vi)
for (i = 0; i < nitems(rss_key); i++) {
rss_key[i] = htobe32(raw_rss_key[nitems(rss_key) - 1 - i]);
}
t4_write_rss_key(sc, (void *)&rss_key[0], -1);
t4_write_rss_key(sc, &rss_key[0], -1);
#endif
rss = malloc(vi->rss_size * sizeof (*rss), M_CXGBE, M_ZERO | M_WAITOK);
for (i = 0; i < vi->rss_size;) {
@ -7210,7 +7212,7 @@ sysctl_wcwr_stats(SYSCTL_HANDLER_ARGS)
#endif
static uint32_t
fconf_to_mode(uint32_t fconf)
fconf_iconf_to_mode(uint32_t fconf, uint32_t iconf)
{
uint32_t mode;
@ -7238,8 +7240,11 @@ fconf_to_mode(uint32_t fconf)
if (fconf & F_VLAN)
mode |= T4_FILTER_VLAN;
if (fconf & F_VNIC_ID)
if (fconf & F_VNIC_ID) {
mode |= T4_FILTER_VNIC;
if (iconf & F_VNIC)
mode |= T4_FILTER_IC_VNIC;
}
if (fconf & F_PORT)
mode |= T4_FILTER_PORT;
@ -7289,8 +7294,18 @@ mode_to_fconf(uint32_t mode)
}
static uint32_t
fspec_to_fconf(struct t4_filter_specification *fs)
mode_to_iconf(uint32_t mode)
{
if (mode & T4_FILTER_IC_VNIC)
return (F_VNIC);
return (0);
}
static int check_fspec_against_fconf_iconf(struct adapter *sc,
struct t4_filter_specification *fs)
{
struct tp_params *tpp = &sc->params.tp;
uint32_t fconf = 0;
if (fs->val.frag || fs->mask.frag)
@ -7314,8 +7329,17 @@ fspec_to_fconf(struct t4_filter_specification *fs)
if (fs->val.vlan_vld || fs->mask.vlan_vld)
fconf |= F_VLAN;
if (fs->val.vnic_vld || fs->mask.vnic_vld)
if (fs->val.ovlan_vld || fs->mask.ovlan_vld) {
fconf |= F_VNIC_ID;
if (tpp->ingress_config & F_VNIC)
return (EINVAL);
}
if (fs->val.pfvf_vld || fs->mask.pfvf_vld) {
fconf |= F_VNIC_ID;
if ((tpp->ingress_config & F_VNIC) == 0)
return (EINVAL);
}
if (fs->val.iport || fs->mask.iport)
fconf |= F_PORT;
@ -7323,41 +7347,45 @@ fspec_to_fconf(struct t4_filter_specification *fs)
if (fs->val.fcoe || fs->mask.fcoe)
fconf |= F_FCOE;
return (fconf);
if ((tpp->vlan_pri_map | fconf) != tpp->vlan_pri_map)
return (E2BIG);
return (0);
}
static int
get_filter_mode(struct adapter *sc, uint32_t *mode)
{
int rc;
uint32_t fconf;
struct tp_params *tpp = &sc->params.tp;
rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
"t4getfm");
if (rc)
return (rc);
/*
* We trust the cached values of the relevant TP registers. This means
* things work reliably only if writes to those registers are always via
* t4_set_filter_mode.
*/
*mode = fconf_iconf_to_mode(tpp->vlan_pri_map, tpp->ingress_config);
t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &fconf, 1,
A_TP_VLAN_PRI_MAP);
if (sc->params.tp.vlan_pri_map != fconf) {
log(LOG_WARNING, "%s: cached filter mode out of sync %x %x.\n",
device_get_nameunit(sc->dev), sc->params.tp.vlan_pri_map,
fconf);
}
*mode = fconf_to_mode(fconf);
end_synchronized_op(sc, LOCK_HELD);
return (0);
}
static int
set_filter_mode(struct adapter *sc, uint32_t mode)
{
uint32_t fconf;
struct tp_params *tpp = &sc->params.tp;
uint32_t fconf, iconf;
int rc;
iconf = mode_to_iconf(mode);
if ((iconf ^ tpp->ingress_config) & F_VNIC) {
/*
* For now we just complain if A_TP_INGRESS_CONFIG is not
* already set to the correct value for the requested filter
* mode. It's not clear if it's safe to write to this register
* on the fly. (And we trust the cached value of the register).
*/
return (EBUSY);
}
fconf = mode_to_fconf(mode);
rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
@ -7390,6 +7418,7 @@ get_filter_hits(struct adapter *sc, uint32_t fid)
uint64_t hits;
memwin_info(sc, 0, &mw_base, NULL);
off = position_memwin(sc, 0,
tcb_base + (fid + sc->tids.ftid_base) * TCB_SIZE);
if (is_t4(sc)) {
@ -7471,12 +7500,10 @@ set_filter(struct adapter *sc, struct t4_filter *t)
goto done;
}
/* Validate against the global filter mode */
if ((sc->params.tp.vlan_pri_map | fspec_to_fconf(&t->fs)) !=
sc->params.tp.vlan_pri_map) {
rc = E2BIG;
/* Validate against the global filter mode and ingress config */
rc = check_fspec_against_fconf_iconf(sc, &t->fs);
if (rc != 0)
goto done;
}
if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports) {
rc = EINVAL;
@ -7639,7 +7666,7 @@ set_filter_wr(struct adapter *sc, int fidx)
{
struct filter_entry *f = &sc->tids.ftid_tab[fidx];
struct fw_filter_wr *fwr;
unsigned int ftid;
unsigned int ftid, vnic_vld, vnic_vld_mask;
struct wrq_cookie cookie;
ASSERT_SYNCHRONIZED_OP(sc);
@ -7657,6 +7684,18 @@ set_filter_wr(struct adapter *sc, int fidx)
}
}
/* Already validated against fconf, iconf */
MPASS((f->fs.val.pfvf_vld & f->fs.val.ovlan_vld) == 0);
MPASS((f->fs.mask.pfvf_vld & f->fs.mask.ovlan_vld) == 0);
if (f->fs.val.pfvf_vld || f->fs.val.ovlan_vld)
vnic_vld = 1;
else
vnic_vld = 0;
if (f->fs.mask.pfvf_vld || f->fs.mask.ovlan_vld)
vnic_vld_mask = 1;
else
vnic_vld_mask = 0;
ftid = sc->tids.ftid_base + fidx;
fwr = start_wrq_wr(&sc->sge.mgmtq, howmany(sizeof(*fwr), 16), &cookie);
@ -7694,9 +7733,9 @@ set_filter_wr(struct adapter *sc, int fidx)
(V_FW_FILTER_WR_FRAG(f->fs.val.frag) |
V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) |
V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.vlan_vld) |
V_FW_FILTER_WR_OVLAN_VLD(f->fs.val.vnic_vld) |
V_FW_FILTER_WR_OVLAN_VLD(vnic_vld) |
V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.vlan_vld) |
V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.vnic_vld));
V_FW_FILTER_WR_OVLAN_VLDM(vnic_vld_mask));
fwr->smac_sel = 0;
fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) |
V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id));

View File

@ -532,7 +532,10 @@ do_show_info_header(uint32_t mode)
break;
case T4_FILTER_VNIC:
printf(" vld:VNIC");
if (mode & T4_FILTER_IC_VNIC)
printf(" VFvld:PF:VF");
else
printf(" vld:oVLAN");
break;
case T4_FILTER_VLAN:
@ -789,11 +792,19 @@ do_show_one_filter_info(struct t4_filter *t, uint32_t mode)
break;
case T4_FILTER_VNIC:
printf(" %1d:%1x:%02x/%1d:%1x:%02x",
t->fs.val.vnic_vld, (t->fs.val.vnic >> 7) & 0x7,
t->fs.val.vnic & 0x7f, t->fs.mask.vnic_vld,
(t->fs.mask.vnic >> 7) & 0x7,
t->fs.mask.vnic & 0x7f);
if (mode & T4_FILTER_IC_VNIC) {
printf(" %1d:%1x:%02x/%1d:%1x:%02x",
t->fs.val.pfvf_vld,
(t->fs.val.vnic >> 13) & 0x7,
t->fs.val.vnic & 0x1fff,
t->fs.mask.pfvf_vld,
(t->fs.mask.vnic >> 13) & 0x7,
t->fs.mask.vnic & 0x1fff);
} else {
printf(" %1d:%04x/%1d:%04x",
t->fs.val.ovlan_vld, t->fs.val.vnic,
t->fs.mask.ovlan_vld, t->fs.mask.vnic);
}
break;
case T4_FILTER_VLAN:
@ -971,8 +982,12 @@ get_filter_mode(void)
if (mode & T4_FILTER_VLAN)
printf("vlan ");
if (mode & T4_FILTER_VNIC)
printf("vnic/ovlan ");
if (mode & T4_FILTER_VNIC) {
if (mode & T4_FILTER_IC_VNIC)
printf("vnic_id ");
else
printf("ovlan ");
}
if (mode & T4_FILTER_PORT)
printf("iport ");
@ -989,6 +1004,7 @@ static int
set_filter_mode(int argc, const char *argv[])
{
uint32_t mode = 0;
int vnic = 0, ovlan = 0;
for (; argc; argc--, argv++) {
if (!strcmp(argv[0], "frag"))
@ -1012,9 +1028,16 @@ set_filter_mode(int argc, const char *argv[])
if (!strcmp(argv[0], "vlan"))
mode |= T4_FILTER_VLAN;
if (!strcmp(argv[0], "ovlan") ||
!strcmp(argv[0], "vnic"))
if (!strcmp(argv[0], "ovlan")) {
mode |= T4_FILTER_VNIC;
ovlan++;
}
if (!strcmp(argv[0], "vnic_id")) {
mode |= T4_FILTER_VNIC;
mode |= T4_FILTER_IC_VNIC;
vnic++;
}
if (!strcmp(argv[0], "iport"))
mode |= T4_FILTER_PORT;
@ -1023,6 +1046,11 @@ set_filter_mode(int argc, const char *argv[])
mode |= T4_FILTER_FCoE;
}
if (vnic > 0 && ovlan > 0) {
warnx("\"vnic_id\" and \"ovlan\" are mutually exclusive.");
return (EINVAL);
}
return doit(CHELSIO_T4_SET_FILTER_MODE, &mode);
}
@ -1081,18 +1109,27 @@ set_filter(uint32_t idx, int argc, const char *argv[])
} else if (!parse_val_mask("ovlan", args, &val, &mask)) {
t.fs.val.vnic = val;
t.fs.mask.vnic = mask;
t.fs.val.vnic_vld = 1;
t.fs.mask.vnic_vld = 1;
} else if (!parse_val_mask("vnic", args, &val, &mask)) {
t.fs.val.vnic = val;
t.fs.mask.vnic = mask;
t.fs.val.vnic_vld = 1;
t.fs.mask.vnic_vld = 1;
t.fs.val.ovlan_vld = 1;
t.fs.mask.ovlan_vld = 1;
} else if (!parse_val_mask("ivlan", args, &val, &mask)) {
t.fs.val.vlan = val;
t.fs.mask.vlan = mask;
t.fs.val.vlan_vld = 1;
t.fs.mask.vlan_vld = 1;
} else if (!parse_val_mask("pf", args, &val, &mask)) {
t.fs.val.vnic &= 0x1fff;
t.fs.val.vnic |= (val & 0x7) << 13;
t.fs.mask.vnic &= 0x1fff;
t.fs.mask.vnic |= (mask & 0x7) << 13;
t.fs.val.pfvf_vld = 1;
t.fs.mask.pfvf_vld = 1;
} else if (!parse_val_mask("vf", args, &val, &mask)) {
t.fs.val.vnic &= 0xe000;
t.fs.val.vnic |= val & 0x1fff;
t.fs.mask.vnic &= 0xe000;
t.fs.mask.vnic |= mask & 0x1fff;
t.fs.val.pfvf_vld = 1;
t.fs.mask.pfvf_vld = 1;
} else if (!parse_val_mask("tos", args, &val, &mask)) {
t.fs.val.tos = val;
t.fs.mask.tos = mask;
@ -1228,6 +1265,10 @@ set_filter(uint32_t idx, int argc, const char *argv[])
" action \"drop\" or \"switch\"");
return (EINVAL);
}
if (t.fs.val.ovlan_vld && t.fs.val.pfvf_vld) {
warnx("ovlan and vnic_id (pf/vf) are mutually exclusive");
return (EINVAL);
}
t.fs.type = (af == AF_INET6 ? 1 : 0); /* default IPv4 */
return doit(CHELSIO_T4_SET_FILTER, &t);