brintos

brintos / linux-shallow public Read only

0
0
Text · 11.9 KiB · 4a439b3 Raw
506 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* 10G controller driver for Samsung SoCs3 *4 * Copyright (C) 2013 Samsung Electronics Co., Ltd.5 *		http://www.samsung.com6 *7 * Author: Siva Reddy Kallam <siva.kallam@samsung.com>8 */9 10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt11 12#include <linux/clk.h>13#include <linux/interrupt.h>14#include <linux/kernel.h>15#include <linux/netdevice.h>16#include <linux/net_tstamp.h>17#include <linux/phy.h>18#include <linux/ptp_clock_kernel.h>19 20#include "sxgbe_common.h"21#include "sxgbe_reg.h"22#include "sxgbe_dma.h"23 24struct sxgbe_stats {25	char stat_string[ETH_GSTRING_LEN];26	int sizeof_stat;27	int stat_offset;28};29 30#define SXGBE_STAT(m)						\31{								\32	#m,							\33	sizeof_field(struct sxgbe_extra_stats, m),		\34	offsetof(struct sxgbe_priv_data, xstats.m)		\35}36 37static const struct sxgbe_stats sxgbe_gstrings_stats[] = {38	/* TX/RX IRQ events */39	SXGBE_STAT(tx_process_stopped_irq),40	SXGBE_STAT(tx_ctxt_desc_err),41	SXGBE_STAT(tx_threshold),42	SXGBE_STAT(rx_threshold),43	SXGBE_STAT(tx_pkt_n),44	SXGBE_STAT(rx_pkt_n),45	SXGBE_STAT(normal_irq_n),46	SXGBE_STAT(tx_normal_irq_n),47	SXGBE_STAT(rx_normal_irq_n),48	SXGBE_STAT(napi_poll),49	SXGBE_STAT(tx_clean),50	SXGBE_STAT(tx_reset_ic_bit),51	SXGBE_STAT(rx_process_stopped_irq),52	SXGBE_STAT(rx_underflow_irq),53 54	/* Bus access errors */55	SXGBE_STAT(fatal_bus_error_irq),56	SXGBE_STAT(tx_read_transfer_err),57	SXGBE_STAT(tx_write_transfer_err),58	SXGBE_STAT(tx_desc_access_err),59	SXGBE_STAT(tx_buffer_access_err),60	SXGBE_STAT(tx_data_transfer_err),61	SXGBE_STAT(rx_read_transfer_err),62	SXGBE_STAT(rx_write_transfer_err),63	SXGBE_STAT(rx_desc_access_err),64	SXGBE_STAT(rx_buffer_access_err),65	SXGBE_STAT(rx_data_transfer_err),66 67	/* EEE-LPI stats */68	SXGBE_STAT(tx_lpi_entry_n),69	SXGBE_STAT(tx_lpi_exit_n),70	SXGBE_STAT(rx_lpi_entry_n),71	SXGBE_STAT(rx_lpi_exit_n),72	SXGBE_STAT(eee_wakeup_error_n),73 74	/* RX specific */75	/* L2 error */76	SXGBE_STAT(rx_code_gmii_err),77	SXGBE_STAT(rx_watchdog_err),78	SXGBE_STAT(rx_crc_err),79	SXGBE_STAT(rx_gaint_pkt_err),80	SXGBE_STAT(ip_hdr_err),81	SXGBE_STAT(ip_payload_err),82	SXGBE_STAT(overflow_error),83 84	/* L2 Pkt type */85	SXGBE_STAT(len_pkt),86	SXGBE_STAT(mac_ctl_pkt),87	SXGBE_STAT(dcb_ctl_pkt),88	SXGBE_STAT(arp_pkt),89	SXGBE_STAT(oam_pkt),90	SXGBE_STAT(untag_okt),91	SXGBE_STAT(other_pkt),92	SXGBE_STAT(svlan_tag_pkt),93	SXGBE_STAT(cvlan_tag_pkt),94	SXGBE_STAT(dvlan_ocvlan_icvlan_pkt),95	SXGBE_STAT(dvlan_osvlan_isvlan_pkt),96	SXGBE_STAT(dvlan_osvlan_icvlan_pkt),97	SXGBE_STAT(dvan_ocvlan_icvlan_pkt),98 99	/* L3/L4 Pkt type */100	SXGBE_STAT(not_ip_pkt),101	SXGBE_STAT(ip4_tcp_pkt),102	SXGBE_STAT(ip4_udp_pkt),103	SXGBE_STAT(ip4_icmp_pkt),104	SXGBE_STAT(ip4_unknown_pkt),105	SXGBE_STAT(ip6_tcp_pkt),106	SXGBE_STAT(ip6_udp_pkt),107	SXGBE_STAT(ip6_icmp_pkt),108	SXGBE_STAT(ip6_unknown_pkt),109 110	/* Filter specific */111	SXGBE_STAT(vlan_filter_match),112	SXGBE_STAT(sa_filter_fail),113	SXGBE_STAT(da_filter_fail),114	SXGBE_STAT(hash_filter_pass),115	SXGBE_STAT(l3_filter_match),116	SXGBE_STAT(l4_filter_match),117 118	/* RX context specific */119	SXGBE_STAT(timestamp_dropped),120	SXGBE_STAT(rx_msg_type_no_ptp),121	SXGBE_STAT(rx_ptp_type_sync),122	SXGBE_STAT(rx_ptp_type_follow_up),123	SXGBE_STAT(rx_ptp_type_delay_req),124	SXGBE_STAT(rx_ptp_type_delay_resp),125	SXGBE_STAT(rx_ptp_type_pdelay_req),126	SXGBE_STAT(rx_ptp_type_pdelay_resp),127	SXGBE_STAT(rx_ptp_type_pdelay_follow_up),128	SXGBE_STAT(rx_ptp_announce),129	SXGBE_STAT(rx_ptp_mgmt),130	SXGBE_STAT(rx_ptp_signal),131	SXGBE_STAT(rx_ptp_resv_msg_type),132};133#define SXGBE_STATS_LEN ARRAY_SIZE(sxgbe_gstrings_stats)134 135static int sxgbe_get_eee(struct net_device *dev,136			 struct ethtool_keee *edata)137{138	struct sxgbe_priv_data *priv = netdev_priv(dev);139 140	if (!priv->hw_cap.eee)141		return -EOPNOTSUPP;142 143	edata->tx_lpi_timer = priv->tx_lpi_timer;144 145	return phy_ethtool_get_eee(dev->phydev, edata);146}147 148static int sxgbe_set_eee(struct net_device *dev,149			 struct ethtool_keee *edata)150{151	struct sxgbe_priv_data *priv = netdev_priv(dev);152 153	priv->eee_enabled = edata->eee_enabled;154 155	if (!priv->eee_enabled) {156		sxgbe_disable_eee_mode(priv);157	} else {158		/* We are asking for enabling the EEE but it is safe159		 * to verify all by invoking the eee_init function.160		 * In case of failure it will return an error.161		 */162		priv->eee_enabled = sxgbe_eee_init(priv);163		if (!priv->eee_enabled)164			return -EOPNOTSUPP;165 166		/* Do not change tx_lpi_timer in case of failure */167		priv->tx_lpi_timer = edata->tx_lpi_timer;168	}169 170	return phy_ethtool_set_eee(dev->phydev, edata);171}172 173static void sxgbe_getdrvinfo(struct net_device *dev,174			     struct ethtool_drvinfo *info)175{176	strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));177	strscpy(info->version, DRV_VERSION, sizeof(info->version));178}179 180static u32 sxgbe_getmsglevel(struct net_device *dev)181{182	struct sxgbe_priv_data *priv = netdev_priv(dev);183	return priv->msg_enable;184}185 186static void sxgbe_setmsglevel(struct net_device *dev, u32 level)187{188	struct sxgbe_priv_data *priv = netdev_priv(dev);189	priv->msg_enable = level;190}191 192static void sxgbe_get_strings(struct net_device *dev, u32 stringset, u8 *data)193{194	int i;195	u8 *p = data;196 197	switch (stringset) {198	case ETH_SS_STATS:199		for (i = 0; i < SXGBE_STATS_LEN; i++) {200			memcpy(p, sxgbe_gstrings_stats[i].stat_string,201			       ETH_GSTRING_LEN);202			p += ETH_GSTRING_LEN;203		}204		break;205	default:206		WARN_ON(1);207		break;208	}209}210 211static int sxgbe_get_sset_count(struct net_device *netdev, int sset)212{213	int len;214 215	switch (sset) {216	case ETH_SS_STATS:217		len = SXGBE_STATS_LEN;218		return len;219	default:220		return -EINVAL;221	}222}223 224static void sxgbe_get_ethtool_stats(struct net_device *dev,225				    struct ethtool_stats *dummy, u64 *data)226{227	struct sxgbe_priv_data *priv = netdev_priv(dev);228	int i;229	char *p;230 231	if (priv->eee_enabled) {232		int val = phy_get_eee_err(dev->phydev);233 234		if (val)235			priv->xstats.eee_wakeup_error_n = val;236	}237 238	for (i = 0; i < SXGBE_STATS_LEN; i++) {239		p = (char *)priv + sxgbe_gstrings_stats[i].stat_offset;240		data[i] = (sxgbe_gstrings_stats[i].sizeof_stat == sizeof(u64))241			? (*(u64 *)p) : (*(u32 *)p);242	}243}244 245static void sxgbe_get_channels(struct net_device *dev,246			       struct ethtool_channels *channel)247{248	channel->max_rx = SXGBE_MAX_RX_CHANNELS;249	channel->max_tx = SXGBE_MAX_TX_CHANNELS;250	channel->rx_count = SXGBE_RX_QUEUES;251	channel->tx_count = SXGBE_TX_QUEUES;252}253 254static u32 sxgbe_riwt2usec(u32 riwt, struct sxgbe_priv_data *priv)255{256	unsigned long clk = clk_get_rate(priv->sxgbe_clk);257 258	if (!clk)259		return 0;260 261	return (riwt * 256) / (clk / 1000000);262}263 264static u32 sxgbe_usec2riwt(u32 usec, struct sxgbe_priv_data *priv)265{266	unsigned long clk = clk_get_rate(priv->sxgbe_clk);267 268	if (!clk)269		return 0;270 271	return (usec * (clk / 1000000)) / 256;272}273 274static int sxgbe_get_coalesce(struct net_device *dev,275			      struct ethtool_coalesce *ec,276			      struct kernel_ethtool_coalesce *kernel_coal,277			      struct netlink_ext_ack *extack)278{279	struct sxgbe_priv_data *priv = netdev_priv(dev);280 281	if (priv->use_riwt)282		ec->rx_coalesce_usecs = sxgbe_riwt2usec(priv->rx_riwt, priv);283 284	return 0;285}286 287static int sxgbe_set_coalesce(struct net_device *dev,288			      struct ethtool_coalesce *ec,289			      struct kernel_ethtool_coalesce *kernel_coal,290			      struct netlink_ext_ack *extack)291{292	struct sxgbe_priv_data *priv = netdev_priv(dev);293	unsigned int rx_riwt;294 295	if (!ec->rx_coalesce_usecs)296		return -EINVAL;297 298	rx_riwt = sxgbe_usec2riwt(ec->rx_coalesce_usecs, priv);299 300	if ((rx_riwt > SXGBE_MAX_DMA_RIWT) || (rx_riwt < SXGBE_MIN_DMA_RIWT))301		return -EINVAL;302	else if (!priv->use_riwt)303		return -EOPNOTSUPP;304 305	priv->rx_riwt = rx_riwt;306	priv->hw->dma->rx_watchdog(priv->ioaddr, priv->rx_riwt);307 308	return 0;309}310 311static int sxgbe_get_rss_hash_opts(struct sxgbe_priv_data *priv,312				   struct ethtool_rxnfc *cmd)313{314	cmd->data = 0;315 316	/* Report default options for RSS on sxgbe */317	switch (cmd->flow_type) {318	case TCP_V4_FLOW:319	case UDP_V4_FLOW:320		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;321		fallthrough;322	case SCTP_V4_FLOW:323	case AH_ESP_V4_FLOW:324	case AH_V4_FLOW:325	case ESP_V4_FLOW:326	case IPV4_FLOW:327		cmd->data |= RXH_IP_SRC | RXH_IP_DST;328		break;329	case TCP_V6_FLOW:330	case UDP_V6_FLOW:331		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;332		fallthrough;333	case SCTP_V6_FLOW:334	case AH_ESP_V6_FLOW:335	case AH_V6_FLOW:336	case ESP_V6_FLOW:337	case IPV6_FLOW:338		cmd->data |= RXH_IP_SRC | RXH_IP_DST;339		break;340	default:341		return -EINVAL;342	}343 344	return 0;345}346 347static int sxgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,348			   u32 *rule_locs)349{350	struct sxgbe_priv_data *priv = netdev_priv(dev);351	int ret = -EOPNOTSUPP;352 353	switch (cmd->cmd) {354	case ETHTOOL_GRXFH:355		ret = sxgbe_get_rss_hash_opts(priv, cmd);356		break;357	default:358		break;359	}360 361	return ret;362}363 364static int sxgbe_set_rss_hash_opt(struct sxgbe_priv_data *priv,365				  struct ethtool_rxnfc *cmd)366{367	u32 reg_val = 0;368 369	/* RSS does not support anything other than hashing370	 * to queues on src and dst IPs and ports371	 */372	if (cmd->data & ~(RXH_IP_SRC | RXH_IP_DST |373			  RXH_L4_B_0_1 | RXH_L4_B_2_3))374		return -EINVAL;375 376	switch (cmd->flow_type) {377	case TCP_V4_FLOW:378	case TCP_V6_FLOW:379		if (!(cmd->data & RXH_IP_SRC) ||380		    !(cmd->data & RXH_IP_DST) ||381		    !(cmd->data & RXH_L4_B_0_1) ||382		    !(cmd->data & RXH_L4_B_2_3))383			return -EINVAL;384		reg_val = SXGBE_CORE_RSS_CTL_TCP4TE;385		break;386	case UDP_V4_FLOW:387	case UDP_V6_FLOW:388		if (!(cmd->data & RXH_IP_SRC) ||389		    !(cmd->data & RXH_IP_DST) ||390		    !(cmd->data & RXH_L4_B_0_1) ||391		    !(cmd->data & RXH_L4_B_2_3))392			return -EINVAL;393		reg_val = SXGBE_CORE_RSS_CTL_UDP4TE;394		break;395	case SCTP_V4_FLOW:396	case AH_ESP_V4_FLOW:397	case AH_V4_FLOW:398	case ESP_V4_FLOW:399	case AH_ESP_V6_FLOW:400	case AH_V6_FLOW:401	case ESP_V6_FLOW:402	case SCTP_V6_FLOW:403	case IPV4_FLOW:404	case IPV6_FLOW:405		if (!(cmd->data & RXH_IP_SRC) ||406		    !(cmd->data & RXH_IP_DST) ||407		    (cmd->data & RXH_L4_B_0_1) ||408		    (cmd->data & RXH_L4_B_2_3))409			return -EINVAL;410		reg_val = SXGBE_CORE_RSS_CTL_IP2TE;411		break;412	default:413		return -EINVAL;414	}415 416	/* Read SXGBE RSS control register and update */417	reg_val |= readl(priv->ioaddr + SXGBE_CORE_RSS_CTL_REG);418	writel(reg_val, priv->ioaddr + SXGBE_CORE_RSS_CTL_REG);419	readl(priv->ioaddr + SXGBE_CORE_RSS_CTL_REG);420 421	return 0;422}423 424static int sxgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)425{426	struct sxgbe_priv_data *priv = netdev_priv(dev);427	int ret = -EOPNOTSUPP;428 429	switch (cmd->cmd) {430	case ETHTOOL_SRXFH:431		ret = sxgbe_set_rss_hash_opt(priv, cmd);432		break;433	default:434		break;435	}436 437	return ret;438}439 440static void sxgbe_get_regs(struct net_device *dev,441			   struct ethtool_regs *regs, void *space)442{443	struct sxgbe_priv_data *priv = netdev_priv(dev);444	u32 *reg_space = (u32 *)space;445	int reg_offset;446	int reg_ix = 0;447	void __iomem *ioaddr = priv->ioaddr;448 449	memset(reg_space, 0x0, REG_SPACE_SIZE);450 451	/* MAC registers */452	for (reg_offset = START_MAC_REG_OFFSET;453	     reg_offset <= MAX_MAC_REG_OFFSET; reg_offset += 4) {454		reg_space[reg_ix] = readl(ioaddr + reg_offset);455		reg_ix++;456	}457 458	/* MTL registers */459	for (reg_offset = START_MTL_REG_OFFSET;460	     reg_offset <= MAX_MTL_REG_OFFSET; reg_offset += 4) {461		reg_space[reg_ix] = readl(ioaddr + reg_offset);462		reg_ix++;463	}464 465	/* DMA registers */466	for (reg_offset = START_DMA_REG_OFFSET;467	     reg_offset <= MAX_DMA_REG_OFFSET; reg_offset += 4) {468		reg_space[reg_ix] = readl(ioaddr + reg_offset);469		reg_ix++;470	}471 472	BUG_ON(reg_ix * 4 > REG_SPACE_SIZE);473}474 475static int sxgbe_get_regs_len(struct net_device *dev)476{477	return REG_SPACE_SIZE;478}479 480static const struct ethtool_ops sxgbe_ethtool_ops = {481	.supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS,482	.get_drvinfo = sxgbe_getdrvinfo,483	.get_msglevel = sxgbe_getmsglevel,484	.set_msglevel = sxgbe_setmsglevel,485	.get_link = ethtool_op_get_link,486	.get_strings = sxgbe_get_strings,487	.get_ethtool_stats = sxgbe_get_ethtool_stats,488	.get_sset_count = sxgbe_get_sset_count,489	.get_channels = sxgbe_get_channels,490	.get_coalesce = sxgbe_get_coalesce,491	.set_coalesce = sxgbe_set_coalesce,492	.get_rxnfc = sxgbe_get_rxnfc,493	.set_rxnfc = sxgbe_set_rxnfc,494	.get_regs = sxgbe_get_regs,495	.get_regs_len = sxgbe_get_regs_len,496	.get_eee = sxgbe_get_eee,497	.set_eee = sxgbe_set_eee,498	.get_link_ksettings = phy_ethtool_get_link_ksettings,499	.set_link_ksettings = phy_ethtool_set_link_ksettings,500};501 502void sxgbe_set_ethtool_ops(struct net_device *netdev)503{504	netdev->ethtool_ops = &sxgbe_ethtool_ops;505}506