brintos

brintos / linux-shallow public Read only

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