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

igc_tsn.c (6539B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Copyright (c)  2019 Intel Corporation */
      3
      4#include "igc.h"
      5#include "igc_tsn.h"
      6
      7static bool is_any_launchtime(struct igc_adapter *adapter)
      8{
      9	int i;
     10
     11	for (i = 0; i < adapter->num_tx_queues; i++) {
     12		struct igc_ring *ring = adapter->tx_ring[i];
     13
     14		if (ring->launchtime_enable)
     15			return true;
     16	}
     17
     18	return false;
     19}
     20
     21static bool is_cbs_enabled(struct igc_adapter *adapter)
     22{
     23	int i;
     24
     25	for (i = 0; i < adapter->num_tx_queues; i++) {
     26		struct igc_ring *ring = adapter->tx_ring[i];
     27
     28		if (ring->cbs_enable)
     29			return true;
     30	}
     31
     32	return false;
     33}
     34
     35static unsigned int igc_tsn_new_flags(struct igc_adapter *adapter)
     36{
     37	unsigned int new_flags = adapter->flags & ~IGC_FLAG_TSN_ANY_ENABLED;
     38
     39	if (adapter->base_time)
     40		new_flags |= IGC_FLAG_TSN_QBV_ENABLED;
     41
     42	if (is_any_launchtime(adapter))
     43		new_flags |= IGC_FLAG_TSN_QBV_ENABLED;
     44
     45	if (is_cbs_enabled(adapter))
     46		new_flags |= IGC_FLAG_TSN_QAV_ENABLED;
     47
     48	return new_flags;
     49}
     50
     51/* Returns the TSN specific registers to their default values after
     52 * the adapter is reset.
     53 */
     54static int igc_tsn_disable_offload(struct igc_adapter *adapter)
     55{
     56	struct igc_hw *hw = &adapter->hw;
     57	u32 tqavctrl;
     58	int i;
     59
     60	wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT);
     61	wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_DEFAULT);
     62
     63	tqavctrl = rd32(IGC_TQAVCTRL);
     64	tqavctrl &= ~(IGC_TQAVCTRL_TRANSMIT_MODE_TSN |
     65		      IGC_TQAVCTRL_ENHANCED_QAV);
     66	wr32(IGC_TQAVCTRL, tqavctrl);
     67
     68	for (i = 0; i < adapter->num_tx_queues; i++) {
     69		wr32(IGC_TXQCTL(i), 0);
     70		wr32(IGC_STQT(i), 0);
     71		wr32(IGC_ENDQT(i), NSEC_PER_SEC);
     72	}
     73
     74	wr32(IGC_QBVCYCLET_S, 0);
     75	wr32(IGC_QBVCYCLET, NSEC_PER_SEC);
     76
     77	adapter->flags &= ~IGC_FLAG_TSN_QBV_ENABLED;
     78
     79	return 0;
     80}
     81
     82static int igc_tsn_enable_offload(struct igc_adapter *adapter)
     83{
     84	struct igc_hw *hw = &adapter->hw;
     85	u32 tqavctrl, baset_l, baset_h;
     86	u32 sec, nsec, cycle;
     87	ktime_t base_time, systim;
     88	int i;
     89
     90	cycle = adapter->cycle_time;
     91	base_time = adapter->base_time;
     92
     93	wr32(IGC_TSAUXC, 0);
     94	wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_TSN);
     95	wr32(IGC_TXPBS, IGC_TXPBSIZE_TSN);
     96
     97	tqavctrl = rd32(IGC_TQAVCTRL);
     98	tqavctrl |= IGC_TQAVCTRL_TRANSMIT_MODE_TSN | IGC_TQAVCTRL_ENHANCED_QAV;
     99	wr32(IGC_TQAVCTRL, tqavctrl);
    100
    101	wr32(IGC_QBVCYCLET_S, cycle);
    102	wr32(IGC_QBVCYCLET, cycle);
    103
    104	for (i = 0; i < adapter->num_tx_queues; i++) {
    105		struct igc_ring *ring = adapter->tx_ring[i];
    106		u32 txqctl = 0;
    107		u16 cbs_value;
    108		u32 tqavcc;
    109
    110		wr32(IGC_STQT(i), ring->start_time);
    111		wr32(IGC_ENDQT(i), ring->end_time);
    112
    113		if (adapter->base_time) {
    114			/* If we have a base_time we are in "taprio"
    115			 * mode and we need to be strict about the
    116			 * cycles: only transmit a packet if it can be
    117			 * completed during that cycle.
    118			 */
    119			txqctl |= IGC_TXQCTL_STRICT_CYCLE |
    120				IGC_TXQCTL_STRICT_END;
    121		}
    122
    123		if (ring->launchtime_enable)
    124			txqctl |= IGC_TXQCTL_QUEUE_MODE_LAUNCHT;
    125
    126		/* Skip configuring CBS for Q2 and Q3 */
    127		if (i > 1)
    128			goto skip_cbs;
    129
    130		if (ring->cbs_enable) {
    131			if (i == 0)
    132				txqctl |= IGC_TXQCTL_QAV_SEL_CBS0;
    133			else
    134				txqctl |= IGC_TXQCTL_QAV_SEL_CBS1;
    135
    136			/* According to i225 datasheet section 7.5.2.7, we
    137			 * should set the 'idleSlope' field from TQAVCC
    138			 * register following the equation:
    139			 *
    140			 * value = link-speed   0x7736 * BW * 0.2
    141			 *         ---------- *  -----------------         (E1)
    142			 *          100Mbps            2.5
    143			 *
    144			 * Note that 'link-speed' is in Mbps.
    145			 *
    146			 * 'BW' is the percentage bandwidth out of full
    147			 * link speed which can be found with the
    148			 * following equation. Note that idleSlope here
    149			 * is the parameter from this function
    150			 * which is in kbps.
    151			 *
    152			 *     BW =     idleSlope
    153			 *          -----------------                      (E2)
    154			 *          link-speed * 1000
    155			 *
    156			 * That said, we can come up with a generic
    157			 * equation to calculate the value we should set
    158			 * it TQAVCC register by replacing 'BW' in E1 by E2.
    159			 * The resulting equation is:
    160			 *
    161			 * value = link-speed * 0x7736 * idleSlope * 0.2
    162			 *         -------------------------------------   (E3)
    163			 *             100 * 2.5 * link-speed * 1000
    164			 *
    165			 * 'link-speed' is present in both sides of the
    166			 * fraction so it is canceled out. The final
    167			 * equation is the following:
    168			 *
    169			 *     value = idleSlope * 61036
    170			 *             -----------------                   (E4)
    171			 *                  2500000
    172			 *
    173			 * NOTE: For i225, given the above, we can see
    174			 *       that idleslope is represented in
    175			 *       40.959433 kbps units by the value at
    176			 *       the TQAVCC register (2.5Gbps / 61036),
    177			 *       which reduces the granularity for
    178			 *       idleslope increments.
    179			 *
    180			 * In i225 controller, the sendSlope and loCredit
    181			 * parameters from CBS are not configurable
    182			 * by software so we don't do any
    183			 * 'controller configuration' in respect to
    184			 * these parameters.
    185			 */
    186			cbs_value = DIV_ROUND_UP_ULL(ring->idleslope
    187						     * 61036ULL, 2500000);
    188
    189			tqavcc = rd32(IGC_TQAVCC(i));
    190			tqavcc &= ~IGC_TQAVCC_IDLESLOPE_MASK;
    191			tqavcc |= cbs_value | IGC_TQAVCC_KEEP_CREDITS;
    192			wr32(IGC_TQAVCC(i), tqavcc);
    193
    194			wr32(IGC_TQAVHC(i),
    195			     0x80000000 + ring->hicredit * 0x7735);
    196		} else {
    197			/* Disable any CBS for the queue */
    198			txqctl &= ~(IGC_TXQCTL_QAV_SEL_MASK);
    199
    200			/* Set idleSlope to zero. */
    201			tqavcc = rd32(IGC_TQAVCC(i));
    202			tqavcc &= ~(IGC_TQAVCC_IDLESLOPE_MASK |
    203				    IGC_TQAVCC_KEEP_CREDITS);
    204			wr32(IGC_TQAVCC(i), tqavcc);
    205
    206			/* Set hiCredit to zero. */
    207			wr32(IGC_TQAVHC(i), 0);
    208		}
    209skip_cbs:
    210		wr32(IGC_TXQCTL(i), txqctl);
    211	}
    212
    213	nsec = rd32(IGC_SYSTIML);
    214	sec = rd32(IGC_SYSTIMH);
    215
    216	systim = ktime_set(sec, nsec);
    217
    218	if (ktime_compare(systim, base_time) > 0) {
    219		s64 n;
    220
    221		n = div64_s64(ktime_sub_ns(systim, base_time), cycle);
    222		base_time = ktime_add_ns(base_time, (n + 1) * cycle);
    223	}
    224
    225	baset_h = div_s64_rem(base_time, NSEC_PER_SEC, &baset_l);
    226
    227	wr32(IGC_BASET_H, baset_h);
    228	wr32(IGC_BASET_L, baset_l);
    229
    230	return 0;
    231}
    232
    233int igc_tsn_reset(struct igc_adapter *adapter)
    234{
    235	unsigned int new_flags;
    236	int err = 0;
    237
    238	new_flags = igc_tsn_new_flags(adapter);
    239
    240	if (!(new_flags & IGC_FLAG_TSN_ANY_ENABLED))
    241		return igc_tsn_disable_offload(adapter);
    242
    243	err = igc_tsn_enable_offload(adapter);
    244	if (err < 0)
    245		return err;
    246
    247	adapter->flags = new_flags;
    248
    249	return err;
    250}
    251
    252int igc_tsn_offload_apply(struct igc_adapter *adapter)
    253{
    254	int err;
    255
    256	if (netif_running(adapter->netdev)) {
    257		schedule_work(&adapter->reset_task);
    258		return 0;
    259	}
    260
    261	err = igc_tsn_enable_offload(adapter);
    262	if (err < 0)
    263		return err;
    264
    265	adapter->flags = igc_tsn_new_flags(adapter);
    266	return 0;
    267}