brintos

brintos / linux-shallow public Read only

0
0
Text · 4.5 KiB · 0c4fac3 Raw
159 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * This file is based on code from OCTEON SDK by Cavium Networks.4 *5 * Copyright (c) 2003-2007 Cavium Networks6 */7 8#include <linux/kernel.h>9#include <linux/netdevice.h>10#include <linux/interrupt.h>11#include <linux/phy.h>12#include <linux/ratelimit.h>13#include <net/dst.h>14 15#include "octeon-ethernet.h"16#include "ethernet-defines.h"17#include "ethernet-util.h"18#include "ethernet-mdio.h"19 20static DEFINE_SPINLOCK(global_register_lock);21 22static void cvm_oct_set_hw_preamble(struct octeon_ethernet *priv, bool enable)23{24	union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;25	union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;26	union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;27	int interface = INTERFACE(priv->port);28	int index = INDEX(priv->port);29 30	/* Set preamble checking. */31	gmxx_rxx_frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index,32								   interface));33	gmxx_rxx_frm_ctl.s.pre_chk = enable;34	cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface),35		       gmxx_rxx_frm_ctl.u64);36 37	/* Set FCS stripping. */38	ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);39	if (enable)40		ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port;41	else42		ipd_sub_port_fcs.s.port_bit &=43					0xffffffffull ^ (1ull << priv->port);44	cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);45 46	/* Clear any error bits. */47	gmxx_rxx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index,48								   interface));49	cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),50		       gmxx_rxx_int_reg.u64);51}52 53static void cvm_oct_check_preamble_errors(struct net_device *dev)54{55	struct octeon_ethernet *priv = netdev_priv(dev);56	union cvmx_helper_link_info link_info;57	unsigned long flags;58 59	link_info.u64 = priv->link_info;60 61	/*62	 * Take the global register lock since we are going to63	 * touch registers that affect more than one port.64	 */65	spin_lock_irqsave(&global_register_lock, flags);66 67	if (link_info.s.speed == 10 && priv->last_speed == 10) {68		/*69		 * Read the GMXX_RXX_INT_REG[PCTERR] bit and see if we are70		 * getting preamble errors.71		 */72		int interface = INTERFACE(priv->port);73		int index = INDEX(priv->port);74		union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;75 76		gmxx_rxx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG77							(index, interface));78		if (gmxx_rxx_int_reg.s.pcterr) {79			/*80			 * We are getting preamble errors at 10Mbps. Most81			 * likely the PHY is giving us packets with misaligned82			 * preambles. In order to get these packets we need to83			 * disable preamble checking and do it in software.84			 */85			cvm_oct_set_hw_preamble(priv, false);86			printk_ratelimited("%s: Using 10Mbps with software preamble removal\n",87					   dev->name);88		}89	} else {90		/*91		 * Since the 10Mbps preamble workaround is allowed we need to92		 * enable preamble checking, FCS stripping, and clear error93		 * bits on every speed change. If errors occur during 10Mbps94		 * operation the above code will change this stuff95		 */96		if (priv->last_speed != link_info.s.speed)97			cvm_oct_set_hw_preamble(priv, true);98		priv->last_speed = link_info.s.speed;99	}100	spin_unlock_irqrestore(&global_register_lock, flags);101}102 103static void cvm_oct_rgmii_poll(struct net_device *dev)104{105	struct octeon_ethernet *priv = netdev_priv(dev);106	union cvmx_helper_link_info link_info;107	bool status_change;108 109	link_info = cvmx_helper_link_get(priv->port);110	if (priv->link_info != link_info.u64 &&111	    cvmx_helper_link_set(priv->port, link_info))112		link_info.u64 = priv->link_info;113	status_change = priv->link_info != link_info.u64;114	priv->link_info = link_info.u64;115 116	cvm_oct_check_preamble_errors(dev);117 118	if (likely(!status_change))119		return;120 121	/* Tell core. */122	if (link_info.s.link_up) {123		if (!netif_carrier_ok(dev))124			netif_carrier_on(dev);125	} else if (netif_carrier_ok(dev)) {126		netif_carrier_off(dev);127	}128	cvm_oct_note_carrier(priv, link_info);129}130 131int cvm_oct_rgmii_open(struct net_device *dev)132{133	struct octeon_ethernet *priv = netdev_priv(dev);134	int ret;135 136	ret = cvm_oct_common_open(dev, cvm_oct_rgmii_poll);137	if (ret)138		return ret;139 140	if (dev->phydev) {141		/*142		 * In phydev mode, we need still periodic polling for the143		 * preamble error checking, and we also need to call this144		 * function on every link state change.145		 *146		 * Only true RGMII ports need to be polled. In GMII mode, port147		 * 0 is really a RGMII port.148		 */149		if ((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII &&150		     priv->port  == 0) ||151		    (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {152			priv->poll = cvm_oct_check_preamble_errors;153			cvm_oct_check_preamble_errors(dev);154		}155	}156 157	return 0;158}159