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

cvmx-helper-sgmii.c (15844B)


      1/***********************license start***************
      2 * Author: Cavium Networks
      3 *
      4 * Contact: support@caviumnetworks.com
      5 * This file is part of the OCTEON SDK
      6 *
      7 * Copyright (C) 2003-2018 Cavium, Inc.
      8 *
      9 * This file is free software; you can redistribute it and/or modify
     10 * it under the terms of the GNU General Public License, Version 2, as
     11 * published by the Free Software Foundation.
     12 *
     13 * This file is distributed in the hope that it will be useful, but
     14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
     15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
     16 * NONINFRINGEMENT.  See the GNU General Public License for more
     17 * details.
     18 *
     19 * You should have received a copy of the GNU General Public License
     20 * along with this file; if not, write to the Free Software
     21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
     22 * or visit http://www.gnu.org/licenses/.
     23 *
     24 * This file may also be available under a different license from Cavium.
     25 * Contact Cavium Networks for more information
     26 ***********************license end**************************************/
     27
     28/*
     29 * Functions for SGMII initialization, configuration,
     30 * and monitoring.
     31 */
     32
     33#include <asm/octeon/octeon.h>
     34
     35#include <asm/octeon/cvmx-config.h>
     36
     37#include <asm/octeon/cvmx-helper.h>
     38#include <asm/octeon/cvmx-helper-board.h>
     39
     40#include <asm/octeon/cvmx-gmxx-defs.h>
     41#include <asm/octeon/cvmx-pcsx-defs.h>
     42#include <asm/octeon/cvmx-pcsxx-defs.h>
     43
     44/**
     45 * Perform initialization required only once for an SGMII port.
     46 *
     47 * @interface: Interface to init
     48 * @index:     Index of prot on the interface
     49 *
     50 * Returns Zero on success, negative on failure
     51 */
     52static int __cvmx_helper_sgmii_hardware_init_one_time(int interface, int index)
     53{
     54	const uint64_t clock_mhz = cvmx_sysinfo_get()->cpu_clock_hz / 1000000;
     55	union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg;
     56	union cvmx_pcsx_linkx_timer_count_reg pcsx_linkx_timer_count_reg;
     57	union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
     58
     59	/* Disable GMX */
     60	gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
     61	gmxx_prtx_cfg.s.en = 0;
     62	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
     63
     64	/*
     65	 * Write PCS*_LINK*_TIMER_COUNT_REG[COUNT] with the
     66	 * appropriate value. 1000BASE-X specifies a 10ms
     67	 * interval. SGMII specifies a 1.6ms interval.
     68	 */
     69	pcs_misc_ctl_reg.u64 =
     70	    cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
     71	pcsx_linkx_timer_count_reg.u64 =
     72	    cvmx_read_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface));
     73	if (pcs_misc_ctl_reg.s.mode) {
     74		/* 1000BASE-X */
     75		pcsx_linkx_timer_count_reg.s.count =
     76		    (10000ull * clock_mhz) >> 10;
     77	} else {
     78		/* SGMII */
     79		pcsx_linkx_timer_count_reg.s.count =
     80		    (1600ull * clock_mhz) >> 10;
     81	}
     82	cvmx_write_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface),
     83		       pcsx_linkx_timer_count_reg.u64);
     84
     85	/*
     86	 * Write the advertisement register to be used as the
     87	 * tx_Config_Reg<D15:D0> of the autonegotiation.  In
     88	 * 1000BASE-X mode, tx_Config_Reg<D15:D0> is PCS*_AN*_ADV_REG.
     89	 * In SGMII PHY mode, tx_Config_Reg<D15:D0> is
     90	 * PCS*_SGM*_AN_ADV_REG.  In SGMII MAC mode,
     91	 * tx_Config_Reg<D15:D0> is the fixed value 0x4001, so this
     92	 * step can be skipped.
     93	 */
     94	if (pcs_misc_ctl_reg.s.mode) {
     95		/* 1000BASE-X */
     96		union cvmx_pcsx_anx_adv_reg pcsx_anx_adv_reg;
     97		pcsx_anx_adv_reg.u64 =
     98		    cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index, interface));
     99		pcsx_anx_adv_reg.s.rem_flt = 0;
    100		pcsx_anx_adv_reg.s.pause = 3;
    101		pcsx_anx_adv_reg.s.hfd = 1;
    102		pcsx_anx_adv_reg.s.fd = 1;
    103		cvmx_write_csr(CVMX_PCSX_ANX_ADV_REG(index, interface),
    104			       pcsx_anx_adv_reg.u64);
    105	} else {
    106		union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
    107		pcsx_miscx_ctl_reg.u64 =
    108		    cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
    109		if (pcsx_miscx_ctl_reg.s.mac_phy) {
    110			/* PHY Mode */
    111			union cvmx_pcsx_sgmx_an_adv_reg pcsx_sgmx_an_adv_reg;
    112			pcsx_sgmx_an_adv_reg.u64 =
    113			    cvmx_read_csr(CVMX_PCSX_SGMX_AN_ADV_REG
    114					  (index, interface));
    115			pcsx_sgmx_an_adv_reg.s.link = 1;
    116			pcsx_sgmx_an_adv_reg.s.dup = 1;
    117			pcsx_sgmx_an_adv_reg.s.speed = 2;
    118			cvmx_write_csr(CVMX_PCSX_SGMX_AN_ADV_REG
    119				       (index, interface),
    120				       pcsx_sgmx_an_adv_reg.u64);
    121		} else {
    122			/* MAC Mode - Nothing to do */
    123		}
    124	}
    125	return 0;
    126}
    127
    128/**
    129 * Initialize the SERTES link for the first time or after a loss
    130 * of link.
    131 *
    132 * @interface: Interface to init
    133 * @index:     Index of prot on the interface
    134 *
    135 * Returns Zero on success, negative on failure
    136 */
    137static int __cvmx_helper_sgmii_hardware_init_link(int interface, int index)
    138{
    139	union cvmx_pcsx_mrx_control_reg control_reg;
    140
    141	/*
    142	 * Take PCS through a reset sequence.
    143	 * PCS*_MR*_CONTROL_REG[PWR_DN] should be cleared to zero.
    144	 * Write PCS*_MR*_CONTROL_REG[RESET]=1 (while not changing the
    145	 * value of the other PCS*_MR*_CONTROL_REG bits).  Read
    146	 * PCS*_MR*_CONTROL_REG[RESET] until it changes value to
    147	 * zero.
    148	 */
    149	control_reg.u64 =
    150	    cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
    151	if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) {
    152		control_reg.s.reset = 1;
    153		cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
    154			       control_reg.u64);
    155		if (CVMX_WAIT_FOR_FIELD64
    156		    (CVMX_PCSX_MRX_CONTROL_REG(index, interface),
    157		     union cvmx_pcsx_mrx_control_reg, reset, ==, 0, 10000)) {
    158			cvmx_dprintf("SGMII%d: Timeout waiting for port %d "
    159				     "to finish reset\n",
    160			     interface, index);
    161			return -1;
    162		}
    163	}
    164
    165	/*
    166	 * Write PCS*_MR*_CONTROL_REG[RST_AN]=1 to ensure a fresh
    167	 * sgmii negotiation starts.
    168	 */
    169	control_reg.s.rst_an = 1;
    170	control_reg.s.an_en = 1;
    171	control_reg.s.pwr_dn = 0;
    172	cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
    173		       control_reg.u64);
    174
    175	/*
    176	 * Wait for PCS*_MR*_STATUS_REG[AN_CPT] to be set, indicating
    177	 * that sgmii autonegotiation is complete. In MAC mode this
    178	 * isn't an ethernet link, but a link between Octeon and the
    179	 * PHY.
    180	 */
    181	if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) &&
    182	    CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_STATUS_REG(index, interface),
    183				  union cvmx_pcsx_mrx_status_reg, an_cpt, ==, 1,
    184				  10000)) {
    185		/* cvmx_dprintf("SGMII%d: Port %d link timeout\n", interface, index); */
    186		return -1;
    187	}
    188	return 0;
    189}
    190
    191/**
    192 * Configure an SGMII link to the specified speed after the SERTES
    193 * link is up.
    194 *
    195 * @interface: Interface to init
    196 * @index:     Index of prot on the interface
    197 * @link_info: Link state to configure
    198 *
    199 * Returns Zero on success, negative on failure
    200 */
    201static int __cvmx_helper_sgmii_hardware_init_link_speed(int interface,
    202							int index,
    203							union cvmx_helper_link_info
    204							link_info)
    205{
    206	int is_enabled;
    207	union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
    208	union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
    209
    210	/* Disable GMX before we make any changes. Remember the enable state */
    211	gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
    212	is_enabled = gmxx_prtx_cfg.s.en;
    213	gmxx_prtx_cfg.s.en = 0;
    214	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
    215
    216	/* Wait for GMX to be idle */
    217	if (CVMX_WAIT_FOR_FIELD64
    218	    (CVMX_GMXX_PRTX_CFG(index, interface), union cvmx_gmxx_prtx_cfg,
    219	     rx_idle, ==, 1, 10000)
    220	    || CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface),
    221				     union cvmx_gmxx_prtx_cfg, tx_idle, ==, 1,
    222				     10000)) {
    223		cvmx_dprintf
    224		    ("SGMII%d: Timeout waiting for port %d to be idle\n",
    225		     interface, index);
    226		return -1;
    227	}
    228
    229	/* Read GMX CFG again to make sure the disable completed */
    230	gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
    231
    232	/*
    233	 * Get the misc control for PCS. We will need to set the
    234	 * duplication amount.
    235	 */
    236	pcsx_miscx_ctl_reg.u64 =
    237	    cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
    238
    239	/*
    240	 * Use GMXENO to force the link down if the status we get says
    241	 * it should be down.
    242	 */
    243	pcsx_miscx_ctl_reg.s.gmxeno = !link_info.s.link_up;
    244
    245	/* Only change the duplex setting if the link is up */
    246	if (link_info.s.link_up)
    247		gmxx_prtx_cfg.s.duplex = link_info.s.full_duplex;
    248
    249	/* Do speed based setting for GMX */
    250	switch (link_info.s.speed) {
    251	case 10:
    252		gmxx_prtx_cfg.s.speed = 0;
    253		gmxx_prtx_cfg.s.speed_msb = 1;
    254		gmxx_prtx_cfg.s.slottime = 0;
    255		/* Setting from GMX-603 */
    256		pcsx_miscx_ctl_reg.s.samp_pt = 25;
    257		cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
    258		cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
    259		break;
    260	case 100:
    261		gmxx_prtx_cfg.s.speed = 0;
    262		gmxx_prtx_cfg.s.speed_msb = 0;
    263		gmxx_prtx_cfg.s.slottime = 0;
    264		pcsx_miscx_ctl_reg.s.samp_pt = 0x5;
    265		cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
    266		cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
    267		break;
    268	case 1000:
    269		gmxx_prtx_cfg.s.speed = 1;
    270		gmxx_prtx_cfg.s.speed_msb = 0;
    271		gmxx_prtx_cfg.s.slottime = 1;
    272		pcsx_miscx_ctl_reg.s.samp_pt = 1;
    273		cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 512);
    274		cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 8192);
    275		break;
    276	default:
    277		break;
    278	}
    279
    280	/* Write the new misc control for PCS */
    281	cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
    282		       pcsx_miscx_ctl_reg.u64);
    283
    284	/* Write the new GMX settings with the port still disabled */
    285	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
    286
    287	/* Read GMX CFG again to make sure the config completed */
    288	gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
    289
    290	/* Restore the enabled / disabled state */
    291	gmxx_prtx_cfg.s.en = is_enabled;
    292	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
    293
    294	return 0;
    295}
    296
    297/**
    298 * Bring up the SGMII interface to be ready for packet I/O but
    299 * leave I/O disabled using the GMX override. This function
    300 * follows the bringup documented in 10.6.3 of the manual.
    301 *
    302 * @interface: Interface to bringup
    303 * @num_ports: Number of ports on the interface
    304 *
    305 * Returns Zero on success, negative on failure
    306 */
    307static int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports)
    308{
    309	int index;
    310
    311	__cvmx_helper_setup_gmx(interface, num_ports);
    312
    313	for (index = 0; index < num_ports; index++) {
    314		int ipd_port = cvmx_helper_get_ipd_port(interface, index);
    315		__cvmx_helper_sgmii_hardware_init_one_time(interface, index);
    316		/* Linux kernel driver will call ....link_set with the
    317		 * proper link state. In the simulator there is no
    318		 * link state polling and hence it is set from
    319		 * here.
    320		 */
    321		if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
    322			__cvmx_helper_sgmii_link_set(ipd_port,
    323				       __cvmx_helper_sgmii_link_get(ipd_port));
    324	}
    325
    326	return 0;
    327}
    328
    329int __cvmx_helper_sgmii_enumerate(int interface)
    330{
    331	return 4;
    332}
    333/**
    334 * Probe a SGMII interface and determine the number of ports
    335 * connected to it. The SGMII interface should still be down after
    336 * this call.
    337 *
    338 * @interface: Interface to probe
    339 *
    340 * Returns Number of ports on the interface. Zero to disable.
    341 */
    342int __cvmx_helper_sgmii_probe(int interface)
    343{
    344	union cvmx_gmxx_inf_mode mode;
    345
    346	/*
    347	 * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the
    348	 * interface needs to be enabled before IPD otherwise per port
    349	 * backpressure may not work properly
    350	 */
    351	mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
    352	mode.s.en = 1;
    353	cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
    354	return __cvmx_helper_sgmii_enumerate(interface);
    355}
    356
    357/**
    358 * Bringup and enable a SGMII interface. After this call packet
    359 * I/O should be fully functional. This is called with IPD
    360 * enabled but PKO disabled.
    361 *
    362 * @interface: Interface to bring up
    363 *
    364 * Returns Zero on success, negative on failure
    365 */
    366int __cvmx_helper_sgmii_enable(int interface)
    367{
    368	int num_ports = cvmx_helper_ports_on_interface(interface);
    369	int index;
    370
    371	__cvmx_helper_sgmii_hardware_init(interface, num_ports);
    372
    373	for (index = 0; index < num_ports; index++) {
    374		union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
    375		gmxx_prtx_cfg.u64 =
    376		    cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
    377		gmxx_prtx_cfg.s.en = 1;
    378		cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
    379			       gmxx_prtx_cfg.u64);
    380		__cvmx_interrupt_pcsx_intx_en_reg_enable(index, interface);
    381	}
    382	__cvmx_interrupt_pcsxx_int_en_reg_enable(interface);
    383	__cvmx_interrupt_gmxx_enable(interface);
    384	return 0;
    385}
    386
    387/**
    388 * Return the link state of an IPD/PKO port as returned by
    389 * auto negotiation. The result of this function may not match
    390 * Octeon's link config if auto negotiation has changed since
    391 * the last call to cvmx_helper_link_set().
    392 *
    393 * @ipd_port: IPD/PKO port to query
    394 *
    395 * Returns Link state
    396 */
    397union cvmx_helper_link_info __cvmx_helper_sgmii_link_get(int ipd_port)
    398{
    399	union cvmx_helper_link_info result;
    400	union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg;
    401	int interface = cvmx_helper_get_interface_num(ipd_port);
    402	int index = cvmx_helper_get_interface_index_num(ipd_port);
    403	union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg;
    404
    405	result.u64 = 0;
    406
    407	if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) {
    408		/* The simulator gives you a simulated 1Gbps full duplex link */
    409		result.s.link_up = 1;
    410		result.s.full_duplex = 1;
    411		result.s.speed = 1000;
    412		return result;
    413	}
    414
    415	pcsx_mrx_control_reg.u64 =
    416	    cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
    417	if (pcsx_mrx_control_reg.s.loopbck1) {
    418		/* Force 1Gbps full duplex link for internal loopback */
    419		result.s.link_up = 1;
    420		result.s.full_duplex = 1;
    421		result.s.speed = 1000;
    422		return result;
    423	}
    424
    425	pcs_misc_ctl_reg.u64 =
    426	    cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
    427	if (pcs_misc_ctl_reg.s.mode) {
    428		/* 1000BASE-X */
    429		/* FIXME */
    430	} else {
    431		union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
    432		pcsx_miscx_ctl_reg.u64 =
    433		    cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
    434		if (pcsx_miscx_ctl_reg.s.mac_phy) {
    435			/* PHY Mode */
    436			union cvmx_pcsx_mrx_status_reg pcsx_mrx_status_reg;
    437			union cvmx_pcsx_anx_results_reg pcsx_anx_results_reg;
    438
    439			/*
    440			 * Don't bother continuing if the SERTES low
    441			 * level link is down
    442			 */
    443			pcsx_mrx_status_reg.u64 =
    444			    cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG
    445					  (index, interface));
    446			if (pcsx_mrx_status_reg.s.lnk_st == 0) {
    447				if (__cvmx_helper_sgmii_hardware_init_link
    448				    (interface, index) != 0)
    449					return result;
    450			}
    451
    452			/* Read the autoneg results */
    453			pcsx_anx_results_reg.u64 =
    454			    cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG
    455					  (index, interface));
    456			if (pcsx_anx_results_reg.s.an_cpt) {
    457				/*
    458				 * Auto negotiation is complete. Set
    459				 * status accordingly.
    460				 */
    461				result.s.full_duplex =
    462				    pcsx_anx_results_reg.s.dup;
    463				result.s.link_up =
    464				    pcsx_anx_results_reg.s.link_ok;
    465				switch (pcsx_anx_results_reg.s.spd) {
    466				case 0:
    467					result.s.speed = 10;
    468					break;
    469				case 1:
    470					result.s.speed = 100;
    471					break;
    472				case 2:
    473					result.s.speed = 1000;
    474					break;
    475				default:
    476					result.s.speed = 0;
    477					result.s.link_up = 0;
    478					break;
    479				}
    480			} else {
    481				/*
    482				 * Auto negotiation isn't
    483				 * complete. Return link down.
    484				 */
    485				result.s.speed = 0;
    486				result.s.link_up = 0;
    487			}
    488		} else {	/* MAC Mode */
    489
    490			result = __cvmx_helper_board_link_get(ipd_port);
    491		}
    492	}
    493	return result;
    494}
    495
    496/**
    497 * Configure an IPD/PKO port for the specified link state. This
    498 * function does not influence auto negotiation at the PHY level.
    499 * The passed link state must always match the link state returned
    500 * by cvmx_helper_link_get().
    501 *
    502 * @ipd_port:  IPD/PKO port to configure
    503 * @link_info: The new link state
    504 *
    505 * Returns Zero on success, negative on failure
    506 */
    507int __cvmx_helper_sgmii_link_set(int ipd_port,
    508				 union cvmx_helper_link_info link_info)
    509{
    510	int interface = cvmx_helper_get_interface_num(ipd_port);
    511	int index = cvmx_helper_get_interface_index_num(ipd_port);
    512	__cvmx_helper_sgmii_hardware_init_link(interface, index);
    513	return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index,
    514							    link_info);
    515}