cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sja1105_vl.c (23872B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Copyright 2020 NXP
      3 */
      4#include <net/tc_act/tc_gate.h>
      5#include <linux/dsa/8021q.h>
      6#include "sja1105_vl.h"
      7
      8#define SJA1105_SIZE_VL_STATUS			8
      9
     10/* Insert into the global gate list, sorted by gate action time. */
     11static int sja1105_insert_gate_entry(struct sja1105_gating_config *gating_cfg,
     12				     struct sja1105_rule *rule,
     13				     u8 gate_state, s64 entry_time,
     14				     struct netlink_ext_ack *extack)
     15{
     16	struct sja1105_gate_entry *e;
     17	int rc;
     18
     19	e = kzalloc(sizeof(*e), GFP_KERNEL);
     20	if (!e)
     21		return -ENOMEM;
     22
     23	e->rule = rule;
     24	e->gate_state = gate_state;
     25	e->interval = entry_time;
     26
     27	if (list_empty(&gating_cfg->entries)) {
     28		list_add(&e->list, &gating_cfg->entries);
     29	} else {
     30		struct sja1105_gate_entry *p;
     31
     32		list_for_each_entry(p, &gating_cfg->entries, list) {
     33			if (p->interval == e->interval) {
     34				NL_SET_ERR_MSG_MOD(extack,
     35						   "Gate conflict");
     36				rc = -EBUSY;
     37				goto err;
     38			}
     39
     40			if (e->interval < p->interval)
     41				break;
     42		}
     43		list_add(&e->list, p->list.prev);
     44	}
     45
     46	gating_cfg->num_entries++;
     47
     48	return 0;
     49err:
     50	kfree(e);
     51	return rc;
     52}
     53
     54/* The gate entries contain absolute times in their e->interval field. Convert
     55 * that to proper intervals (i.e. "0, 5, 10, 15" to "5, 5, 5, 5").
     56 */
     57static void
     58sja1105_gating_cfg_time_to_interval(struct sja1105_gating_config *gating_cfg,
     59				    u64 cycle_time)
     60{
     61	struct sja1105_gate_entry *last_e;
     62	struct sja1105_gate_entry *e;
     63	struct list_head *prev;
     64
     65	list_for_each_entry(e, &gating_cfg->entries, list) {
     66		struct sja1105_gate_entry *p;
     67
     68		prev = e->list.prev;
     69
     70		if (prev == &gating_cfg->entries)
     71			continue;
     72
     73		p = list_entry(prev, struct sja1105_gate_entry, list);
     74		p->interval = e->interval - p->interval;
     75	}
     76	last_e = list_last_entry(&gating_cfg->entries,
     77				 struct sja1105_gate_entry, list);
     78	last_e->interval = cycle_time - last_e->interval;
     79}
     80
     81static void sja1105_free_gating_config(struct sja1105_gating_config *gating_cfg)
     82{
     83	struct sja1105_gate_entry *e, *n;
     84
     85	list_for_each_entry_safe(e, n, &gating_cfg->entries, list) {
     86		list_del(&e->list);
     87		kfree(e);
     88	}
     89}
     90
     91static int sja1105_compose_gating_subschedule(struct sja1105_private *priv,
     92					      struct netlink_ext_ack *extack)
     93{
     94	struct sja1105_gating_config *gating_cfg = &priv->tas_data.gating_cfg;
     95	struct sja1105_rule *rule;
     96	s64 max_cycle_time = 0;
     97	s64 its_base_time = 0;
     98	int i, rc = 0;
     99
    100	sja1105_free_gating_config(gating_cfg);
    101
    102	list_for_each_entry(rule, &priv->flow_block.rules, list) {
    103		if (rule->type != SJA1105_RULE_VL)
    104			continue;
    105		if (rule->vl.type != SJA1105_VL_TIME_TRIGGERED)
    106			continue;
    107
    108		if (max_cycle_time < rule->vl.cycle_time) {
    109			max_cycle_time = rule->vl.cycle_time;
    110			its_base_time = rule->vl.base_time;
    111		}
    112	}
    113
    114	if (!max_cycle_time)
    115		return 0;
    116
    117	dev_dbg(priv->ds->dev, "max_cycle_time %lld its_base_time %lld\n",
    118		max_cycle_time, its_base_time);
    119
    120	gating_cfg->base_time = its_base_time;
    121	gating_cfg->cycle_time = max_cycle_time;
    122	gating_cfg->num_entries = 0;
    123
    124	list_for_each_entry(rule, &priv->flow_block.rules, list) {
    125		s64 time;
    126		s64 rbt;
    127
    128		if (rule->type != SJA1105_RULE_VL)
    129			continue;
    130		if (rule->vl.type != SJA1105_VL_TIME_TRIGGERED)
    131			continue;
    132
    133		/* Calculate the difference between this gating schedule's
    134		 * base time, and the base time of the gating schedule with the
    135		 * longest cycle time. We call it the relative base time (rbt).
    136		 */
    137		rbt = future_base_time(rule->vl.base_time, rule->vl.cycle_time,
    138				       its_base_time);
    139		rbt -= its_base_time;
    140
    141		time = rbt;
    142
    143		for (i = 0; i < rule->vl.num_entries; i++) {
    144			u8 gate_state = rule->vl.entries[i].gate_state;
    145			s64 entry_time = time;
    146
    147			while (entry_time < max_cycle_time) {
    148				rc = sja1105_insert_gate_entry(gating_cfg, rule,
    149							       gate_state,
    150							       entry_time,
    151							       extack);
    152				if (rc)
    153					goto err;
    154
    155				entry_time += rule->vl.cycle_time;
    156			}
    157			time += rule->vl.entries[i].interval;
    158		}
    159	}
    160
    161	sja1105_gating_cfg_time_to_interval(gating_cfg, max_cycle_time);
    162
    163	return 0;
    164err:
    165	sja1105_free_gating_config(gating_cfg);
    166	return rc;
    167}
    168
    169/* The switch flow classification core implements TTEthernet, which 'thinks' in
    170 * terms of Virtual Links (VL), a concept borrowed from ARINC 664 part 7.
    171 * However it also has one other operating mode (VLLUPFORMAT=0) where it acts
    172 * somewhat closer to a pre-standard implementation of IEEE 802.1Qci
    173 * (Per-Stream Filtering and Policing), which is what the driver is going to be
    174 * implementing.
    175 *
    176 *                                 VL Lookup
    177 *        Key = {DMAC && VLANID   +---------+  Key = { (DMAC[47:16] & VLMASK ==
    178 *               && VLAN PCP      |         |                         VLMARKER)
    179 *               && INGRESS PORT} +---------+                      (both fixed)
    180 *            (exact match,            |             && DMAC[15:0] == VLID
    181 *         all specified in rule)      |                    (specified in rule)
    182 *                                     v             && INGRESS PORT }
    183 *                               ------------
    184 *                    0 (PSFP)  /            \  1 (ARINC664)
    185 *                 +-----------/  VLLUPFORMAT \----------+
    186 *                 |           \    (fixed)   /          |
    187 *                 |            \            /           |
    188 *  0 (forwarding) v             ------------            |
    189 *           ------------                                |
    190 *          /            \  1 (QoS classification)       |
    191 *     +---/  ISCRITICAL  \-----------+                  |
    192 *     |   \  (per rule)  /           |                  |
    193 *     |    \            /   VLID taken from      VLID taken from
    194 *     v     ------------     index of rule       contents of rule
    195 *  select                     that matched         that matched
    196 * DESTPORTS                          |                  |
    197 *  |                                 +---------+--------+
    198 *  |                                           |
    199 *  |                                           v
    200 *  |                                     VL Forwarding
    201 *  |                                   (indexed by VLID)
    202 *  |                                      +---------+
    203 *  |                       +--------------|         |
    204 *  |                       |  select TYPE +---------+
    205 *  |                       v
    206 *  |   0 (rate      ------------    1 (time
    207 *  |  constrained) /            \   triggered)
    208 *  |       +------/     TYPE     \------------+
    209 *  |       |      \  (per VLID)  /            |
    210 *  |       v       \            /             v
    211 *  |  VL Policing   ------------         VL Policing
    212 *  | (indexed by VLID)                (indexed by VLID)
    213 *  |  +---------+                        +---------+
    214 *  |  | TYPE=0  |                        | TYPE=1  |
    215 *  |  +---------+                        +---------+
    216 *  |  select SHARINDX                 select SHARINDX to
    217 *  |  to rate-limit                 re-enter VL Forwarding
    218 *  |  groups of VL's               with new VLID for egress
    219 *  |  to same quota                           |
    220 *  |       |                                  |
    221 *  |  select MAXLEN -> exceed => drop    select MAXLEN -> exceed => drop
    222 *  |       |                                  |
    223 *  |       v                                  v
    224 *  |  VL Forwarding                      VL Forwarding
    225 *  | (indexed by SHARINDX)             (indexed by SHARINDX)
    226 *  |  +---------+                        +---------+
    227 *  |  | TYPE=0  |                        | TYPE=1  |
    228 *  |  +---------+                        +---------+
    229 *  |  select PRIORITY,                 select PRIORITY,
    230 *  | PARTITION, DESTPORTS            PARTITION, DESTPORTS
    231 *  |       |                                  |
    232 *  |       v                                  v
    233 *  |  VL Policing                        VL Policing
    234 *  | (indexed by SHARINDX)           (indexed by SHARINDX)
    235 *  |  +---------+                        +---------+
    236 *  |  | TYPE=0  |                        | TYPE=1  |
    237 *  |  +---------+                        +---------+
    238 *  |       |                                  |
    239 *  |       v                                  |
    240 *  |  select BAG, -> exceed => drop           |
    241 *  |    JITTER                                v
    242 *  |       |             ----------------------------------------------
    243 *  |       |            /    Reception Window is open for this VL      \
    244 *  |       |           /    (the Schedule Table executes an entry i     \
    245 *  |       |          /   M <= i < N, for which these conditions hold):  \ no
    246 *  |       |    +----/                                                    \-+
    247 *  |       |    |yes \       WINST[M] == 1 && WINSTINDEX[M] == VLID       / |
    248 *  |       |    |     \     WINEND[N] == 1 && WINSTINDEX[N] == VLID      /  |
    249 *  |       |    |      \                                                /   |
    250 *  |       |    |       \ (the VL window has opened and not yet closed)/    |
    251 *  |       |    |        ----------------------------------------------     |
    252 *  |       |    v                                                           v
    253 *  |       |  dispatch to DESTPORTS when the Schedule Table               drop
    254 *  |       |  executes an entry i with TXEN == 1 && VLINDEX == i
    255 *  v       v
    256 * dispatch immediately to DESTPORTS
    257 *
    258 * The per-port classification key is always composed of {DMAC, VID, PCP} and
    259 * is non-maskable. This 'looks like' the NULL stream identification function
    260 * from IEEE 802.1CB clause 6, except for the extra VLAN PCP. When the switch
    261 * ports operate as VLAN-unaware, we do allow the user to not specify the VLAN
    262 * ID and PCP, and then the port-based defaults will be used.
    263 *
    264 * In TTEthernet, routing is something that needs to be done manually for each
    265 * Virtual Link. So the flow action must always include one of:
    266 * a. 'redirect', 'trap' or 'drop': select the egress port list
    267 * Additionally, the following actions may be applied on a Virtual Link,
    268 * turning it into 'critical' traffic:
    269 * b. 'police': turn it into a rate-constrained VL, with bandwidth limitation
    270 *    given by the maximum frame length, bandwidth allocation gap (BAG) and
    271 *    maximum jitter.
    272 * c. 'gate': turn it into a time-triggered VL, which can be only be received
    273 *    and forwarded according to a given schedule.
    274 */
    275
    276static bool sja1105_vl_key_lower(struct sja1105_vl_lookup_entry *a,
    277				 struct sja1105_vl_lookup_entry *b)
    278{
    279	if (a->macaddr < b->macaddr)
    280		return true;
    281	if (a->macaddr > b->macaddr)
    282		return false;
    283	if (a->vlanid < b->vlanid)
    284		return true;
    285	if (a->vlanid > b->vlanid)
    286		return false;
    287	if (a->port < b->port)
    288		return true;
    289	if (a->port > b->port)
    290		return false;
    291	if (a->vlanprior < b->vlanprior)
    292		return true;
    293	if (a->vlanprior > b->vlanprior)
    294		return false;
    295	/* Keys are equal */
    296	return false;
    297}
    298
    299/* FIXME: this should change when the bridge upper of the port changes. */
    300static u16 sja1105_port_get_tag_8021q_vid(struct dsa_port *dp)
    301{
    302	unsigned long bridge_num;
    303
    304	if (!dp->bridge)
    305		return dsa_tag_8021q_standalone_vid(dp);
    306
    307	bridge_num = dsa_port_bridge_num_get(dp);
    308
    309	return dsa_tag_8021q_bridge_vid(bridge_num);
    310}
    311
    312static int sja1105_init_virtual_links(struct sja1105_private *priv,
    313				      struct netlink_ext_ack *extack)
    314{
    315	struct sja1105_vl_policing_entry *vl_policing;
    316	struct sja1105_vl_forwarding_entry *vl_fwd;
    317	struct sja1105_vl_lookup_entry *vl_lookup;
    318	bool have_critical_virtual_links = false;
    319	struct sja1105_table *table;
    320	struct sja1105_rule *rule;
    321	int num_virtual_links = 0;
    322	int max_sharindx = 0;
    323	int i, j, k;
    324
    325	/* Figure out the dimensioning of the problem */
    326	list_for_each_entry(rule, &priv->flow_block.rules, list) {
    327		if (rule->type != SJA1105_RULE_VL)
    328			continue;
    329		/* Each VL lookup entry matches on a single ingress port */
    330		num_virtual_links += hweight_long(rule->port_mask);
    331
    332		if (rule->vl.type != SJA1105_VL_NONCRITICAL)
    333			have_critical_virtual_links = true;
    334		if (max_sharindx < rule->vl.sharindx)
    335			max_sharindx = rule->vl.sharindx;
    336	}
    337
    338	if (num_virtual_links > SJA1105_MAX_VL_LOOKUP_COUNT) {
    339		NL_SET_ERR_MSG_MOD(extack, "Not enough VL entries available");
    340		return -ENOSPC;
    341	}
    342
    343	if (max_sharindx + 1 > SJA1105_MAX_VL_LOOKUP_COUNT) {
    344		NL_SET_ERR_MSG_MOD(extack, "Policer index out of range");
    345		return -ENOSPC;
    346	}
    347
    348	max_sharindx = max_t(int, num_virtual_links, max_sharindx) + 1;
    349
    350	/* Discard previous VL Lookup Table */
    351	table = &priv->static_config.tables[BLK_IDX_VL_LOOKUP];
    352	if (table->entry_count) {
    353		kfree(table->entries);
    354		table->entry_count = 0;
    355	}
    356
    357	/* Discard previous VL Policing Table */
    358	table = &priv->static_config.tables[BLK_IDX_VL_POLICING];
    359	if (table->entry_count) {
    360		kfree(table->entries);
    361		table->entry_count = 0;
    362	}
    363
    364	/* Discard previous VL Forwarding Table */
    365	table = &priv->static_config.tables[BLK_IDX_VL_FORWARDING];
    366	if (table->entry_count) {
    367		kfree(table->entries);
    368		table->entry_count = 0;
    369	}
    370
    371	/* Discard previous VL Forwarding Parameters Table */
    372	table = &priv->static_config.tables[BLK_IDX_VL_FORWARDING_PARAMS];
    373	if (table->entry_count) {
    374		kfree(table->entries);
    375		table->entry_count = 0;
    376	}
    377
    378	/* Nothing to do */
    379	if (!num_virtual_links)
    380		return 0;
    381
    382	/* Pre-allocate space in the static config tables */
    383
    384	/* VL Lookup Table */
    385	table = &priv->static_config.tables[BLK_IDX_VL_LOOKUP];
    386	table->entries = kcalloc(num_virtual_links,
    387				 table->ops->unpacked_entry_size,
    388				 GFP_KERNEL);
    389	if (!table->entries)
    390		return -ENOMEM;
    391	table->entry_count = num_virtual_links;
    392	vl_lookup = table->entries;
    393
    394	k = 0;
    395
    396	list_for_each_entry(rule, &priv->flow_block.rules, list) {
    397		unsigned long port;
    398
    399		if (rule->type != SJA1105_RULE_VL)
    400			continue;
    401
    402		for_each_set_bit(port, &rule->port_mask, SJA1105_MAX_NUM_PORTS) {
    403			vl_lookup[k].format = SJA1105_VL_FORMAT_PSFP;
    404			vl_lookup[k].port = port;
    405			vl_lookup[k].macaddr = rule->key.vl.dmac;
    406			if (rule->key.type == SJA1105_KEY_VLAN_AWARE_VL) {
    407				vl_lookup[k].vlanid = rule->key.vl.vid;
    408				vl_lookup[k].vlanprior = rule->key.vl.pcp;
    409			} else {
    410				/* FIXME */
    411				struct dsa_port *dp = dsa_to_port(priv->ds, port);
    412				u16 vid = sja1105_port_get_tag_8021q_vid(dp);
    413
    414				vl_lookup[k].vlanid = vid;
    415				vl_lookup[k].vlanprior = 0;
    416			}
    417			/* For critical VLs, the DESTPORTS mask is taken from
    418			 * the VL Forwarding Table, so no point in putting it
    419			 * in the VL Lookup Table
    420			 */
    421			if (rule->vl.type == SJA1105_VL_NONCRITICAL)
    422				vl_lookup[k].destports = rule->vl.destports;
    423			else
    424				vl_lookup[k].iscritical = true;
    425			vl_lookup[k].flow_cookie = rule->cookie;
    426			k++;
    427		}
    428	}
    429
    430	/* UM10944.pdf chapter 4.2.3 VL Lookup table:
    431	 * "the entries in the VL Lookup table must be sorted in ascending
    432	 * order (i.e. the smallest value must be loaded first) according to
    433	 * the following sort order: MACADDR, VLANID, PORT, VLANPRIOR."
    434	 */
    435	for (i = 0; i < num_virtual_links; i++) {
    436		struct sja1105_vl_lookup_entry *a = &vl_lookup[i];
    437
    438		for (j = i + 1; j < num_virtual_links; j++) {
    439			struct sja1105_vl_lookup_entry *b = &vl_lookup[j];
    440
    441			if (sja1105_vl_key_lower(b, a)) {
    442				struct sja1105_vl_lookup_entry tmp = *a;
    443
    444				*a = *b;
    445				*b = tmp;
    446			}
    447		}
    448	}
    449
    450	if (!have_critical_virtual_links)
    451		return 0;
    452
    453	/* VL Policing Table */
    454	table = &priv->static_config.tables[BLK_IDX_VL_POLICING];
    455	table->entries = kcalloc(max_sharindx, table->ops->unpacked_entry_size,
    456				 GFP_KERNEL);
    457	if (!table->entries)
    458		return -ENOMEM;
    459	table->entry_count = max_sharindx;
    460	vl_policing = table->entries;
    461
    462	/* VL Forwarding Table */
    463	table = &priv->static_config.tables[BLK_IDX_VL_FORWARDING];
    464	table->entries = kcalloc(max_sharindx, table->ops->unpacked_entry_size,
    465				 GFP_KERNEL);
    466	if (!table->entries)
    467		return -ENOMEM;
    468	table->entry_count = max_sharindx;
    469	vl_fwd = table->entries;
    470
    471	/* VL Forwarding Parameters Table */
    472	table = &priv->static_config.tables[BLK_IDX_VL_FORWARDING_PARAMS];
    473	table->entries = kcalloc(1, table->ops->unpacked_entry_size,
    474				 GFP_KERNEL);
    475	if (!table->entries)
    476		return -ENOMEM;
    477	table->entry_count = 1;
    478
    479	for (i = 0; i < num_virtual_links; i++) {
    480		unsigned long cookie = vl_lookup[i].flow_cookie;
    481		struct sja1105_rule *rule = sja1105_rule_find(priv, cookie);
    482
    483		if (rule->vl.type == SJA1105_VL_NONCRITICAL)
    484			continue;
    485		if (rule->vl.type == SJA1105_VL_TIME_TRIGGERED) {
    486			int sharindx = rule->vl.sharindx;
    487
    488			vl_policing[i].type = 1;
    489			vl_policing[i].sharindx = sharindx;
    490			vl_policing[i].maxlen = rule->vl.maxlen;
    491			vl_policing[sharindx].type = 1;
    492
    493			vl_fwd[i].type = 1;
    494			vl_fwd[sharindx].type = 1;
    495			vl_fwd[sharindx].priority = rule->vl.ipv;
    496			vl_fwd[sharindx].partition = 0;
    497			vl_fwd[sharindx].destports = rule->vl.destports;
    498		}
    499	}
    500
    501	sja1105_frame_memory_partitioning(priv);
    502
    503	return 0;
    504}
    505
    506int sja1105_vl_redirect(struct sja1105_private *priv, int port,
    507			struct netlink_ext_ack *extack, unsigned long cookie,
    508			struct sja1105_key *key, unsigned long destports,
    509			bool append)
    510{
    511	struct sja1105_rule *rule = sja1105_rule_find(priv, cookie);
    512	struct dsa_port *dp = dsa_to_port(priv->ds, port);
    513	bool vlan_aware = dsa_port_is_vlan_filtering(dp);
    514	int rc;
    515
    516	if (!vlan_aware && key->type != SJA1105_KEY_VLAN_UNAWARE_VL) {
    517		NL_SET_ERR_MSG_MOD(extack,
    518				   "Can only redirect based on DMAC");
    519		return -EOPNOTSUPP;
    520	} else if (vlan_aware && key->type != SJA1105_KEY_VLAN_AWARE_VL) {
    521		NL_SET_ERR_MSG_MOD(extack,
    522				   "Can only redirect based on {DMAC, VID, PCP}");
    523		return -EOPNOTSUPP;
    524	}
    525
    526	if (!rule) {
    527		rule = kzalloc(sizeof(*rule), GFP_KERNEL);
    528		if (!rule)
    529			return -ENOMEM;
    530
    531		rule->cookie = cookie;
    532		rule->type = SJA1105_RULE_VL;
    533		rule->key = *key;
    534		list_add(&rule->list, &priv->flow_block.rules);
    535	}
    536
    537	rule->port_mask |= BIT(port);
    538	if (append)
    539		rule->vl.destports |= destports;
    540	else
    541		rule->vl.destports = destports;
    542
    543	rc = sja1105_init_virtual_links(priv, extack);
    544	if (rc) {
    545		rule->port_mask &= ~BIT(port);
    546		if (!rule->port_mask) {
    547			list_del(&rule->list);
    548			kfree(rule);
    549		}
    550	}
    551
    552	return rc;
    553}
    554
    555int sja1105_vl_delete(struct sja1105_private *priv, int port,
    556		      struct sja1105_rule *rule, struct netlink_ext_ack *extack)
    557{
    558	int rc;
    559
    560	rule->port_mask &= ~BIT(port);
    561	if (!rule->port_mask) {
    562		list_del(&rule->list);
    563		kfree(rule);
    564	}
    565
    566	rc = sja1105_compose_gating_subschedule(priv, extack);
    567	if (rc)
    568		return rc;
    569
    570	rc = sja1105_init_virtual_links(priv, extack);
    571	if (rc)
    572		return rc;
    573
    574	rc = sja1105_init_scheduling(priv);
    575	if (rc < 0)
    576		return rc;
    577
    578	return sja1105_static_config_reload(priv, SJA1105_VIRTUAL_LINKS);
    579}
    580
    581int sja1105_vl_gate(struct sja1105_private *priv, int port,
    582		    struct netlink_ext_ack *extack, unsigned long cookie,
    583		    struct sja1105_key *key, u32 index, s32 prio,
    584		    u64 base_time, u64 cycle_time, u64 cycle_time_ext,
    585		    u32 num_entries, struct action_gate_entry *entries)
    586{
    587	struct sja1105_rule *rule = sja1105_rule_find(priv, cookie);
    588	struct dsa_port *dp = dsa_to_port(priv->ds, port);
    589	bool vlan_aware = dsa_port_is_vlan_filtering(dp);
    590	int ipv = -1;
    591	int i, rc;
    592	s32 rem;
    593
    594	if (cycle_time_ext) {
    595		NL_SET_ERR_MSG_MOD(extack,
    596				   "Cycle time extension not supported");
    597		return -EOPNOTSUPP;
    598	}
    599
    600	div_s64_rem(base_time, sja1105_delta_to_ns(1), &rem);
    601	if (rem) {
    602		NL_SET_ERR_MSG_MOD(extack,
    603				   "Base time must be multiple of 200 ns");
    604		return -ERANGE;
    605	}
    606
    607	div_s64_rem(cycle_time, sja1105_delta_to_ns(1), &rem);
    608	if (rem) {
    609		NL_SET_ERR_MSG_MOD(extack,
    610				   "Cycle time must be multiple of 200 ns");
    611		return -ERANGE;
    612	}
    613
    614	if (!vlan_aware && key->type != SJA1105_KEY_VLAN_UNAWARE_VL) {
    615		NL_SET_ERR_MSG_MOD(extack,
    616				   "Can only gate based on DMAC");
    617		return -EOPNOTSUPP;
    618	} else if (vlan_aware && key->type != SJA1105_KEY_VLAN_AWARE_VL) {
    619		NL_SET_ERR_MSG_MOD(extack,
    620				   "Can only gate based on {DMAC, VID, PCP}");
    621		return -EOPNOTSUPP;
    622	}
    623
    624	if (!rule) {
    625		rule = kzalloc(sizeof(*rule), GFP_KERNEL);
    626		if (!rule)
    627			return -ENOMEM;
    628
    629		list_add(&rule->list, &priv->flow_block.rules);
    630		rule->cookie = cookie;
    631		rule->type = SJA1105_RULE_VL;
    632		rule->key = *key;
    633		rule->vl.type = SJA1105_VL_TIME_TRIGGERED;
    634		rule->vl.sharindx = index;
    635		rule->vl.base_time = base_time;
    636		rule->vl.cycle_time = cycle_time;
    637		rule->vl.num_entries = num_entries;
    638		rule->vl.entries = kcalloc(num_entries,
    639					   sizeof(struct action_gate_entry),
    640					   GFP_KERNEL);
    641		if (!rule->vl.entries) {
    642			rc = -ENOMEM;
    643			goto out;
    644		}
    645
    646		for (i = 0; i < num_entries; i++) {
    647			div_s64_rem(entries[i].interval,
    648				    sja1105_delta_to_ns(1), &rem);
    649			if (rem) {
    650				NL_SET_ERR_MSG_MOD(extack,
    651						   "Interval must be multiple of 200 ns");
    652				rc = -ERANGE;
    653				goto out;
    654			}
    655
    656			if (!entries[i].interval) {
    657				NL_SET_ERR_MSG_MOD(extack,
    658						   "Interval cannot be zero");
    659				rc = -ERANGE;
    660				goto out;
    661			}
    662
    663			if (ns_to_sja1105_delta(entries[i].interval) >
    664			    SJA1105_TAS_MAX_DELTA) {
    665				NL_SET_ERR_MSG_MOD(extack,
    666						   "Maximum interval is 52 ms");
    667				rc = -ERANGE;
    668				goto out;
    669			}
    670
    671			if (entries[i].maxoctets != -1) {
    672				NL_SET_ERR_MSG_MOD(extack,
    673						   "Cannot offload IntervalOctetMax");
    674				rc = -EOPNOTSUPP;
    675				goto out;
    676			}
    677
    678			if (ipv == -1) {
    679				ipv = entries[i].ipv;
    680			} else if (ipv != entries[i].ipv) {
    681				NL_SET_ERR_MSG_MOD(extack,
    682						   "Only support a single IPV per VL");
    683				rc = -EOPNOTSUPP;
    684				goto out;
    685			}
    686
    687			rule->vl.entries[i] = entries[i];
    688		}
    689
    690		if (ipv == -1) {
    691			if (key->type == SJA1105_KEY_VLAN_AWARE_VL)
    692				ipv = key->vl.pcp;
    693			else
    694				ipv = 0;
    695		}
    696
    697		/* TODO: support per-flow MTU */
    698		rule->vl.maxlen = VLAN_ETH_FRAME_LEN + ETH_FCS_LEN;
    699		rule->vl.ipv = ipv;
    700	}
    701
    702	rule->port_mask |= BIT(port);
    703
    704	rc = sja1105_compose_gating_subschedule(priv, extack);
    705	if (rc)
    706		goto out;
    707
    708	rc = sja1105_init_virtual_links(priv, extack);
    709	if (rc)
    710		goto out;
    711
    712	if (sja1105_gating_check_conflicts(priv, -1, extack)) {
    713		NL_SET_ERR_MSG_MOD(extack, "Conflict with tc-taprio schedule");
    714		rc = -ERANGE;
    715		goto out;
    716	}
    717
    718out:
    719	if (rc) {
    720		rule->port_mask &= ~BIT(port);
    721		if (!rule->port_mask) {
    722			list_del(&rule->list);
    723			kfree(rule->vl.entries);
    724			kfree(rule);
    725		}
    726	}
    727
    728	return rc;
    729}
    730
    731static int sja1105_find_vlid(struct sja1105_private *priv, int port,
    732			     struct sja1105_key *key)
    733{
    734	struct sja1105_vl_lookup_entry *vl_lookup;
    735	struct sja1105_table *table;
    736	int i;
    737
    738	if (WARN_ON(key->type != SJA1105_KEY_VLAN_AWARE_VL &&
    739		    key->type != SJA1105_KEY_VLAN_UNAWARE_VL))
    740		return -1;
    741
    742	table = &priv->static_config.tables[BLK_IDX_VL_LOOKUP];
    743	vl_lookup = table->entries;
    744
    745	for (i = 0; i < table->entry_count; i++) {
    746		if (key->type == SJA1105_KEY_VLAN_AWARE_VL) {
    747			if (vl_lookup[i].port == port &&
    748			    vl_lookup[i].macaddr == key->vl.dmac &&
    749			    vl_lookup[i].vlanid == key->vl.vid &&
    750			    vl_lookup[i].vlanprior == key->vl.pcp)
    751				return i;
    752		} else {
    753			if (vl_lookup[i].port == port &&
    754			    vl_lookup[i].macaddr == key->vl.dmac)
    755				return i;
    756		}
    757	}
    758
    759	return -1;
    760}
    761
    762int sja1105_vl_stats(struct sja1105_private *priv, int port,
    763		     struct sja1105_rule *rule, struct flow_stats *stats,
    764		     struct netlink_ext_ack *extack)
    765{
    766	const struct sja1105_regs *regs = priv->info->regs;
    767	u8 buf[SJA1105_SIZE_VL_STATUS] = {0};
    768	u64 unreleased;
    769	u64 timingerr;
    770	u64 lengtherr;
    771	int vlid, rc;
    772	u64 pkts;
    773
    774	if (rule->vl.type != SJA1105_VL_TIME_TRIGGERED)
    775		return 0;
    776
    777	vlid = sja1105_find_vlid(priv, port, &rule->key);
    778	if (vlid < 0)
    779		return 0;
    780
    781	rc = sja1105_xfer_buf(priv, SPI_READ, regs->vl_status + 2 * vlid, buf,
    782			      SJA1105_SIZE_VL_STATUS);
    783	if (rc) {
    784		NL_SET_ERR_MSG_MOD(extack, "SPI access failed");
    785		return rc;
    786	}
    787
    788	sja1105_unpack(buf, &timingerr,  31, 16, SJA1105_SIZE_VL_STATUS);
    789	sja1105_unpack(buf, &unreleased, 15,  0, SJA1105_SIZE_VL_STATUS);
    790	sja1105_unpack(buf, &lengtherr,  47, 32, SJA1105_SIZE_VL_STATUS);
    791
    792	pkts = timingerr + unreleased + lengtherr;
    793
    794	flow_stats_update(stats, 0, pkts - rule->vl.stats.pkts, 0,
    795			  jiffies - rule->vl.stats.lastused,
    796			  FLOW_ACTION_HW_STATS_IMMEDIATE);
    797
    798	rule->vl.stats.pkts = pkts;
    799	rule->vl.stats.lastused = jiffies;
    800
    801	return 0;
    802}