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

dpaa_ethtool.c (15062B)


      1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later
      2/*
      3 * Copyright 2008 - 2016 Freescale Semiconductor Inc.
      4 */
      5
      6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      7
      8#include <linux/string.h>
      9#include <linux/of_platform.h>
     10#include <linux/net_tstamp.h>
     11#include <linux/fsl/ptp_qoriq.h>
     12
     13#include "dpaa_eth.h"
     14#include "mac.h"
     15
     16static const char dpaa_stats_percpu[][ETH_GSTRING_LEN] = {
     17	"interrupts",
     18	"rx packets",
     19	"tx packets",
     20	"tx confirm",
     21	"tx S/G",
     22	"tx error",
     23	"rx error",
     24	"rx dropped",
     25	"tx dropped",
     26};
     27
     28static char dpaa_stats_global[][ETH_GSTRING_LEN] = {
     29	/* dpa rx errors */
     30	"rx dma error",
     31	"rx frame physical error",
     32	"rx frame size error",
     33	"rx header error",
     34
     35	/* demultiplexing errors */
     36	"qman cg_tdrop",
     37	"qman wred",
     38	"qman error cond",
     39	"qman early window",
     40	"qman late window",
     41	"qman fq tdrop",
     42	"qman fq retired",
     43	"qman orp disabled",
     44
     45	/* congestion related stats */
     46	"congestion time (ms)",
     47	"entered congestion",
     48	"congested (0/1)"
     49};
     50
     51#define DPAA_STATS_PERCPU_LEN ARRAY_SIZE(dpaa_stats_percpu)
     52#define DPAA_STATS_GLOBAL_LEN ARRAY_SIZE(dpaa_stats_global)
     53
     54static int dpaa_get_link_ksettings(struct net_device *net_dev,
     55				   struct ethtool_link_ksettings *cmd)
     56{
     57	if (!net_dev->phydev)
     58		return 0;
     59
     60	phy_ethtool_ksettings_get(net_dev->phydev, cmd);
     61
     62	return 0;
     63}
     64
     65static int dpaa_set_link_ksettings(struct net_device *net_dev,
     66				   const struct ethtool_link_ksettings *cmd)
     67{
     68	int err;
     69
     70	if (!net_dev->phydev)
     71		return -ENODEV;
     72
     73	err = phy_ethtool_ksettings_set(net_dev->phydev, cmd);
     74	if (err < 0)
     75		netdev_err(net_dev, "phy_ethtool_ksettings_set() = %d\n", err);
     76
     77	return err;
     78}
     79
     80static void dpaa_get_drvinfo(struct net_device *net_dev,
     81			     struct ethtool_drvinfo *drvinfo)
     82{
     83	strlcpy(drvinfo->driver, KBUILD_MODNAME,
     84		sizeof(drvinfo->driver));
     85	strlcpy(drvinfo->bus_info, dev_name(net_dev->dev.parent->parent),
     86		sizeof(drvinfo->bus_info));
     87}
     88
     89static u32 dpaa_get_msglevel(struct net_device *net_dev)
     90{
     91	return ((struct dpaa_priv *)netdev_priv(net_dev))->msg_enable;
     92}
     93
     94static void dpaa_set_msglevel(struct net_device *net_dev,
     95			      u32 msg_enable)
     96{
     97	((struct dpaa_priv *)netdev_priv(net_dev))->msg_enable = msg_enable;
     98}
     99
    100static int dpaa_nway_reset(struct net_device *net_dev)
    101{
    102	int err;
    103
    104	if (!net_dev->phydev)
    105		return -ENODEV;
    106
    107	err = 0;
    108	if (net_dev->phydev->autoneg) {
    109		err = phy_start_aneg(net_dev->phydev);
    110		if (err < 0)
    111			netdev_err(net_dev, "phy_start_aneg() = %d\n",
    112				   err);
    113	}
    114
    115	return err;
    116}
    117
    118static void dpaa_get_pauseparam(struct net_device *net_dev,
    119				struct ethtool_pauseparam *epause)
    120{
    121	struct mac_device *mac_dev;
    122	struct dpaa_priv *priv;
    123
    124	priv = netdev_priv(net_dev);
    125	mac_dev = priv->mac_dev;
    126
    127	if (!net_dev->phydev)
    128		return;
    129
    130	epause->autoneg = mac_dev->autoneg_pause;
    131	epause->rx_pause = mac_dev->rx_pause_active;
    132	epause->tx_pause = mac_dev->tx_pause_active;
    133}
    134
    135static int dpaa_set_pauseparam(struct net_device *net_dev,
    136			       struct ethtool_pauseparam *epause)
    137{
    138	struct mac_device *mac_dev;
    139	struct phy_device *phydev;
    140	bool rx_pause, tx_pause;
    141	struct dpaa_priv *priv;
    142	int err;
    143
    144	priv = netdev_priv(net_dev);
    145	mac_dev = priv->mac_dev;
    146
    147	phydev = net_dev->phydev;
    148	if (!phydev) {
    149		netdev_err(net_dev, "phy device not initialized\n");
    150		return -ENODEV;
    151	}
    152
    153	if (!phy_validate_pause(phydev, epause))
    154		return -EINVAL;
    155
    156	/* The MAC should know how to handle PAUSE frame autonegotiation before
    157	 * adjust_link is triggered by a forced renegotiation of sym/asym PAUSE
    158	 * settings.
    159	 */
    160	mac_dev->autoneg_pause = !!epause->autoneg;
    161	mac_dev->rx_pause_req = !!epause->rx_pause;
    162	mac_dev->tx_pause_req = !!epause->tx_pause;
    163
    164	/* Determine the sym/asym advertised PAUSE capabilities from the desired
    165	 * rx/tx pause settings.
    166	 */
    167
    168	phy_set_asym_pause(phydev, epause->rx_pause, epause->tx_pause);
    169
    170	fman_get_pause_cfg(mac_dev, &rx_pause, &tx_pause);
    171	err = fman_set_mac_active_pause(mac_dev, rx_pause, tx_pause);
    172	if (err < 0)
    173		netdev_err(net_dev, "set_mac_active_pause() = %d\n", err);
    174
    175	return err;
    176}
    177
    178static int dpaa_get_sset_count(struct net_device *net_dev, int type)
    179{
    180	unsigned int total_stats, num_stats;
    181
    182	num_stats   = num_online_cpus() + 1;
    183	total_stats = num_stats * (DPAA_STATS_PERCPU_LEN + 1) +
    184			DPAA_STATS_GLOBAL_LEN;
    185
    186	switch (type) {
    187	case ETH_SS_STATS:
    188		return total_stats;
    189	default:
    190		return -EOPNOTSUPP;
    191	}
    192}
    193
    194static void copy_stats(struct dpaa_percpu_priv *percpu_priv, int num_cpus,
    195		       int crr_cpu, u64 bp_count, u64 *data)
    196{
    197	int num_values = num_cpus + 1;
    198	int crr = 0;
    199
    200	/* update current CPU's stats and also add them to the total values */
    201	data[crr * num_values + crr_cpu] = percpu_priv->in_interrupt;
    202	data[crr++ * num_values + num_cpus] += percpu_priv->in_interrupt;
    203
    204	data[crr * num_values + crr_cpu] = percpu_priv->stats.rx_packets;
    205	data[crr++ * num_values + num_cpus] += percpu_priv->stats.rx_packets;
    206
    207	data[crr * num_values + crr_cpu] = percpu_priv->stats.tx_packets;
    208	data[crr++ * num_values + num_cpus] += percpu_priv->stats.tx_packets;
    209
    210	data[crr * num_values + crr_cpu] = percpu_priv->tx_confirm;
    211	data[crr++ * num_values + num_cpus] += percpu_priv->tx_confirm;
    212
    213	data[crr * num_values + crr_cpu] = percpu_priv->tx_frag_skbuffs;
    214	data[crr++ * num_values + num_cpus] += percpu_priv->tx_frag_skbuffs;
    215
    216	data[crr * num_values + crr_cpu] = percpu_priv->stats.tx_errors;
    217	data[crr++ * num_values + num_cpus] += percpu_priv->stats.tx_errors;
    218
    219	data[crr * num_values + crr_cpu] = percpu_priv->stats.rx_errors;
    220	data[crr++ * num_values + num_cpus] += percpu_priv->stats.rx_errors;
    221
    222	data[crr * num_values + crr_cpu] = percpu_priv->stats.rx_dropped;
    223	data[crr++ * num_values + num_cpus] += percpu_priv->stats.rx_dropped;
    224
    225	data[crr * num_values + crr_cpu] = percpu_priv->stats.tx_dropped;
    226	data[crr++ * num_values + num_cpus] += percpu_priv->stats.tx_dropped;
    227
    228	data[crr * num_values + crr_cpu] = bp_count;
    229	data[crr++ * num_values + num_cpus] += bp_count;
    230}
    231
    232static void dpaa_get_ethtool_stats(struct net_device *net_dev,
    233				   struct ethtool_stats *stats, u64 *data)
    234{
    235	struct dpaa_percpu_priv *percpu_priv;
    236	struct dpaa_rx_errors rx_errors;
    237	unsigned int num_cpus, offset;
    238	u64 bp_count, cg_time, cg_num;
    239	struct dpaa_ern_cnt ern_cnt;
    240	struct dpaa_bp *dpaa_bp;
    241	struct dpaa_priv *priv;
    242	int total_stats, i;
    243	bool cg_status;
    244
    245	total_stats = dpaa_get_sset_count(net_dev, ETH_SS_STATS);
    246	priv     = netdev_priv(net_dev);
    247	num_cpus = num_online_cpus();
    248
    249	memset(&bp_count, 0, sizeof(bp_count));
    250	memset(&rx_errors, 0, sizeof(struct dpaa_rx_errors));
    251	memset(&ern_cnt, 0, sizeof(struct dpaa_ern_cnt));
    252	memset(data, 0, total_stats * sizeof(u64));
    253
    254	for_each_online_cpu(i) {
    255		percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
    256		dpaa_bp = priv->dpaa_bp;
    257		if (!dpaa_bp->percpu_count)
    258			continue;
    259		bp_count = *(per_cpu_ptr(dpaa_bp->percpu_count, i));
    260		rx_errors.dme += percpu_priv->rx_errors.dme;
    261		rx_errors.fpe += percpu_priv->rx_errors.fpe;
    262		rx_errors.fse += percpu_priv->rx_errors.fse;
    263		rx_errors.phe += percpu_priv->rx_errors.phe;
    264
    265		ern_cnt.cg_tdrop     += percpu_priv->ern_cnt.cg_tdrop;
    266		ern_cnt.wred         += percpu_priv->ern_cnt.wred;
    267		ern_cnt.err_cond     += percpu_priv->ern_cnt.err_cond;
    268		ern_cnt.early_window += percpu_priv->ern_cnt.early_window;
    269		ern_cnt.late_window  += percpu_priv->ern_cnt.late_window;
    270		ern_cnt.fq_tdrop     += percpu_priv->ern_cnt.fq_tdrop;
    271		ern_cnt.fq_retired   += percpu_priv->ern_cnt.fq_retired;
    272		ern_cnt.orp_zero     += percpu_priv->ern_cnt.orp_zero;
    273
    274		copy_stats(percpu_priv, num_cpus, i, bp_count, data);
    275	}
    276
    277	offset = (num_cpus + 1) * (DPAA_STATS_PERCPU_LEN + 1);
    278	memcpy(data + offset, &rx_errors, sizeof(struct dpaa_rx_errors));
    279
    280	offset += sizeof(struct dpaa_rx_errors) / sizeof(u64);
    281	memcpy(data + offset, &ern_cnt, sizeof(struct dpaa_ern_cnt));
    282
    283	/* gather congestion related counters */
    284	cg_num    = 0;
    285	cg_status = false;
    286	cg_time   = jiffies_to_msecs(priv->cgr_data.congested_jiffies);
    287	if (qman_query_cgr_congested(&priv->cgr_data.cgr, &cg_status) == 0) {
    288		cg_num    = priv->cgr_data.cgr_congested_count;
    289
    290		/* reset congestion stats (like QMan API does */
    291		priv->cgr_data.congested_jiffies   = 0;
    292		priv->cgr_data.cgr_congested_count = 0;
    293	}
    294
    295	offset += sizeof(struct dpaa_ern_cnt) / sizeof(u64);
    296	data[offset++] = cg_time;
    297	data[offset++] = cg_num;
    298	data[offset++] = cg_status;
    299}
    300
    301static void dpaa_get_strings(struct net_device *net_dev, u32 stringset,
    302			     u8 *data)
    303{
    304	unsigned int i, j, num_cpus, size;
    305	char string_cpu[ETH_GSTRING_LEN];
    306	u8 *strings;
    307
    308	memset(string_cpu, 0, sizeof(string_cpu));
    309	strings   = data;
    310	num_cpus  = num_online_cpus();
    311	size      = DPAA_STATS_GLOBAL_LEN * ETH_GSTRING_LEN;
    312
    313	for (i = 0; i < DPAA_STATS_PERCPU_LEN; i++) {
    314		for (j = 0; j < num_cpus; j++) {
    315			snprintf(string_cpu, ETH_GSTRING_LEN, "%s [CPU %d]",
    316				 dpaa_stats_percpu[i], j);
    317			memcpy(strings, string_cpu, ETH_GSTRING_LEN);
    318			strings += ETH_GSTRING_LEN;
    319		}
    320		snprintf(string_cpu, ETH_GSTRING_LEN, "%s [TOTAL]",
    321			 dpaa_stats_percpu[i]);
    322		memcpy(strings, string_cpu, ETH_GSTRING_LEN);
    323		strings += ETH_GSTRING_LEN;
    324	}
    325	for (j = 0; j < num_cpus; j++) {
    326		snprintf(string_cpu, ETH_GSTRING_LEN,
    327			 "bpool [CPU %d]", j);
    328		memcpy(strings, string_cpu, ETH_GSTRING_LEN);
    329		strings += ETH_GSTRING_LEN;
    330	}
    331	snprintf(string_cpu, ETH_GSTRING_LEN, "bpool [TOTAL]");
    332	memcpy(strings, string_cpu, ETH_GSTRING_LEN);
    333	strings += ETH_GSTRING_LEN;
    334
    335	memcpy(strings, dpaa_stats_global, size);
    336}
    337
    338static int dpaa_get_hash_opts(struct net_device *dev,
    339			      struct ethtool_rxnfc *cmd)
    340{
    341	struct dpaa_priv *priv = netdev_priv(dev);
    342
    343	cmd->data = 0;
    344
    345	switch (cmd->flow_type) {
    346	case TCP_V4_FLOW:
    347	case TCP_V6_FLOW:
    348	case UDP_V4_FLOW:
    349	case UDP_V6_FLOW:
    350		if (priv->keygen_in_use)
    351			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
    352		fallthrough;
    353	case IPV4_FLOW:
    354	case IPV6_FLOW:
    355	case SCTP_V4_FLOW:
    356	case SCTP_V6_FLOW:
    357	case AH_ESP_V4_FLOW:
    358	case AH_ESP_V6_FLOW:
    359	case AH_V4_FLOW:
    360	case AH_V6_FLOW:
    361	case ESP_V4_FLOW:
    362	case ESP_V6_FLOW:
    363		if (priv->keygen_in_use)
    364			cmd->data |= RXH_IP_SRC | RXH_IP_DST;
    365		break;
    366	default:
    367		cmd->data = 0;
    368		break;
    369	}
    370
    371	return 0;
    372}
    373
    374static int dpaa_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
    375			  u32 *unused)
    376{
    377	int ret = -EOPNOTSUPP;
    378
    379	switch (cmd->cmd) {
    380	case ETHTOOL_GRXFH:
    381		ret = dpaa_get_hash_opts(dev, cmd);
    382		break;
    383	default:
    384		break;
    385	}
    386
    387	return ret;
    388}
    389
    390static void dpaa_set_hash(struct net_device *net_dev, bool enable)
    391{
    392	struct mac_device *mac_dev;
    393	struct fman_port *rxport;
    394	struct dpaa_priv *priv;
    395
    396	priv = netdev_priv(net_dev);
    397	mac_dev = priv->mac_dev;
    398	rxport = mac_dev->port[0];
    399
    400	fman_port_use_kg_hash(rxport, enable);
    401	priv->keygen_in_use = enable;
    402}
    403
    404static int dpaa_set_hash_opts(struct net_device *dev,
    405			      struct ethtool_rxnfc *nfc)
    406{
    407	int ret = -EINVAL;
    408
    409	/* we support hashing on IPv4/v6 src/dest IP and L4 src/dest port */
    410	if (nfc->data &
    411	    ~(RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3))
    412		return -EINVAL;
    413
    414	switch (nfc->flow_type) {
    415	case TCP_V4_FLOW:
    416	case TCP_V6_FLOW:
    417	case UDP_V4_FLOW:
    418	case UDP_V6_FLOW:
    419	case IPV4_FLOW:
    420	case IPV6_FLOW:
    421	case SCTP_V4_FLOW:
    422	case SCTP_V6_FLOW:
    423	case AH_ESP_V4_FLOW:
    424	case AH_ESP_V6_FLOW:
    425	case AH_V4_FLOW:
    426	case AH_V6_FLOW:
    427	case ESP_V4_FLOW:
    428	case ESP_V6_FLOW:
    429		dpaa_set_hash(dev, !!nfc->data);
    430		ret = 0;
    431		break;
    432	default:
    433		break;
    434	}
    435
    436	return ret;
    437}
    438
    439static int dpaa_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
    440{
    441	int ret = -EOPNOTSUPP;
    442
    443	switch (cmd->cmd) {
    444	case ETHTOOL_SRXFH:
    445		ret = dpaa_set_hash_opts(dev, cmd);
    446		break;
    447	default:
    448		break;
    449	}
    450
    451	return ret;
    452}
    453
    454static int dpaa_get_ts_info(struct net_device *net_dev,
    455			    struct ethtool_ts_info *info)
    456{
    457	struct device *dev = net_dev->dev.parent;
    458	struct device_node *mac_node = dev->of_node;
    459	struct device_node *fman_node = NULL, *ptp_node = NULL;
    460	struct platform_device *ptp_dev = NULL;
    461	struct ptp_qoriq *ptp = NULL;
    462
    463	info->phc_index = -1;
    464
    465	fman_node = of_get_parent(mac_node);
    466	if (fman_node) {
    467		ptp_node = of_parse_phandle(fman_node, "ptimer-handle", 0);
    468		of_node_put(fman_node);
    469	}
    470
    471	if (ptp_node) {
    472		ptp_dev = of_find_device_by_node(ptp_node);
    473		of_node_put(ptp_node);
    474	}
    475
    476	if (ptp_dev)
    477		ptp = platform_get_drvdata(ptp_dev);
    478
    479	if (ptp)
    480		info->phc_index = ptp->phc_index;
    481
    482	info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
    483				SOF_TIMESTAMPING_RX_HARDWARE |
    484				SOF_TIMESTAMPING_RAW_HARDWARE;
    485	info->tx_types = (1 << HWTSTAMP_TX_OFF) |
    486			 (1 << HWTSTAMP_TX_ON);
    487	info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
    488			   (1 << HWTSTAMP_FILTER_ALL);
    489
    490	return 0;
    491}
    492
    493static int dpaa_get_coalesce(struct net_device *dev,
    494			     struct ethtool_coalesce *c,
    495			     struct kernel_ethtool_coalesce *kernel_coal,
    496			     struct netlink_ext_ack *extack)
    497{
    498	struct qman_portal *portal;
    499	u32 period;
    500	u8 thresh;
    501
    502	portal = qman_get_affine_portal(smp_processor_id());
    503	qman_portal_get_iperiod(portal, &period);
    504	qman_dqrr_get_ithresh(portal, &thresh);
    505
    506	c->rx_coalesce_usecs = period;
    507	c->rx_max_coalesced_frames = thresh;
    508
    509	return 0;
    510}
    511
    512static int dpaa_set_coalesce(struct net_device *dev,
    513			     struct ethtool_coalesce *c,
    514			     struct kernel_ethtool_coalesce *kernel_coal,
    515			     struct netlink_ext_ack *extack)
    516{
    517	const cpumask_t *cpus = qman_affine_cpus();
    518	bool needs_revert[NR_CPUS] = {false};
    519	struct qman_portal *portal;
    520	u32 period, prev_period;
    521	u8 thresh, prev_thresh;
    522	int cpu, res;
    523
    524	period = c->rx_coalesce_usecs;
    525	thresh = c->rx_max_coalesced_frames;
    526
    527	/* save previous values */
    528	portal = qman_get_affine_portal(smp_processor_id());
    529	qman_portal_get_iperiod(portal, &prev_period);
    530	qman_dqrr_get_ithresh(portal, &prev_thresh);
    531
    532	/* set new values */
    533	for_each_cpu_and(cpu, cpus, cpu_online_mask) {
    534		portal = qman_get_affine_portal(cpu);
    535		res = qman_portal_set_iperiod(portal, period);
    536		if (res)
    537			goto revert_values;
    538		res = qman_dqrr_set_ithresh(portal, thresh);
    539		if (res) {
    540			qman_portal_set_iperiod(portal, prev_period);
    541			goto revert_values;
    542		}
    543		needs_revert[cpu] = true;
    544	}
    545
    546	return 0;
    547
    548revert_values:
    549	/* restore previous values */
    550	for_each_cpu_and(cpu, cpus, cpu_online_mask) {
    551		if (!needs_revert[cpu])
    552			continue;
    553		portal = qman_get_affine_portal(cpu);
    554		/* previous values will not fail, ignore return value */
    555		qman_portal_set_iperiod(portal, prev_period);
    556		qman_dqrr_set_ithresh(portal, prev_thresh);
    557	}
    558
    559	return res;
    560}
    561
    562const struct ethtool_ops dpaa_ethtool_ops = {
    563	.supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS |
    564				     ETHTOOL_COALESCE_RX_MAX_FRAMES,
    565	.get_drvinfo = dpaa_get_drvinfo,
    566	.get_msglevel = dpaa_get_msglevel,
    567	.set_msglevel = dpaa_set_msglevel,
    568	.nway_reset = dpaa_nway_reset,
    569	.get_pauseparam = dpaa_get_pauseparam,
    570	.set_pauseparam = dpaa_set_pauseparam,
    571	.get_link = ethtool_op_get_link,
    572	.get_sset_count = dpaa_get_sset_count,
    573	.get_ethtool_stats = dpaa_get_ethtool_stats,
    574	.get_strings = dpaa_get_strings,
    575	.get_link_ksettings = dpaa_get_link_ksettings,
    576	.set_link_ksettings = dpaa_set_link_ksettings,
    577	.get_rxnfc = dpaa_get_rxnfc,
    578	.set_rxnfc = dpaa_set_rxnfc,
    579	.get_ts_info = dpaa_get_ts_info,
    580	.get_coalesce = dpaa_get_coalesce,
    581	.set_coalesce = dpaa_set_coalesce,
    582};