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

sparx5_phylink.c (4136B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/* Microchip Sparx5 Switch driver
      3 *
      4 * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
      5 */
      6
      7#include <linux/module.h>
      8#include <linux/phylink.h>
      9#include <linux/device.h>
     10#include <linux/netdevice.h>
     11#include <linux/sfp.h>
     12
     13#include "sparx5_main_regs.h"
     14#include "sparx5_main.h"
     15#include "sparx5_port.h"
     16
     17static bool port_conf_has_changed(struct sparx5_port_config *a, struct sparx5_port_config *b)
     18{
     19	if (a->speed != b->speed ||
     20	    a->portmode != b->portmode ||
     21	    a->autoneg != b->autoneg ||
     22	    a->pause_adv != b->pause_adv ||
     23	    a->power_down != b->power_down ||
     24	    a->media != b->media)
     25		return true;
     26	return false;
     27}
     28
     29static struct phylink_pcs *
     30sparx5_phylink_mac_select_pcs(struct phylink_config *config,
     31			      phy_interface_t interface)
     32{
     33	struct sparx5_port *port = netdev_priv(to_net_dev(config->dev));
     34
     35	return &port->phylink_pcs;
     36}
     37
     38static void sparx5_phylink_mac_config(struct phylink_config *config,
     39				      unsigned int mode,
     40				      const struct phylink_link_state *state)
     41{
     42	/* Currently not used */
     43}
     44
     45static void sparx5_phylink_mac_link_up(struct phylink_config *config,
     46				       struct phy_device *phy,
     47				       unsigned int mode,
     48				       phy_interface_t interface,
     49				       int speed, int duplex,
     50				       bool tx_pause, bool rx_pause)
     51{
     52	struct sparx5_port *port = netdev_priv(to_net_dev(config->dev));
     53	struct sparx5_port_config conf;
     54	int err;
     55
     56	conf = port->conf;
     57	conf.duplex = duplex;
     58	conf.pause = 0;
     59	conf.pause |= tx_pause ? MLO_PAUSE_TX : 0;
     60	conf.pause |= rx_pause ? MLO_PAUSE_RX : 0;
     61	conf.speed = speed;
     62	/* Configure the port to speed/duplex/pause */
     63	err = sparx5_port_config(port->sparx5, port, &conf);
     64	if (err)
     65		netdev_err(port->ndev, "port config failed: %d\n", err);
     66}
     67
     68static void sparx5_phylink_mac_link_down(struct phylink_config *config,
     69					 unsigned int mode,
     70					 phy_interface_t interface)
     71{
     72	/* Currently not used */
     73}
     74
     75static struct sparx5_port *sparx5_pcs_to_port(struct phylink_pcs *pcs)
     76{
     77	return container_of(pcs, struct sparx5_port, phylink_pcs);
     78}
     79
     80static void sparx5_pcs_get_state(struct phylink_pcs *pcs,
     81				 struct phylink_link_state *state)
     82{
     83	struct sparx5_port *port = sparx5_pcs_to_port(pcs);
     84	struct sparx5_port_status status;
     85
     86	sparx5_get_port_status(port->sparx5, port, &status);
     87	state->link = status.link && !status.link_down;
     88	state->an_complete = status.an_complete;
     89	state->speed = status.speed;
     90	state->duplex = status.duplex;
     91	state->pause = status.pause;
     92}
     93
     94static int sparx5_pcs_config(struct phylink_pcs *pcs,
     95			     unsigned int mode,
     96			     phy_interface_t interface,
     97			     const unsigned long *advertising,
     98			     bool permit_pause_to_mac)
     99{
    100	struct sparx5_port *port = sparx5_pcs_to_port(pcs);
    101	struct sparx5_port_config conf;
    102	int ret = 0;
    103
    104	conf = port->conf;
    105	conf.power_down = false;
    106	conf.portmode = interface;
    107	conf.inband = phylink_autoneg_inband(mode);
    108	conf.autoneg = phylink_test(advertising, Autoneg);
    109	conf.pause_adv = 0;
    110	if (phylink_test(advertising, Pause))
    111		conf.pause_adv |= ADVERTISE_1000XPAUSE;
    112	if (phylink_test(advertising, Asym_Pause))
    113		conf.pause_adv |= ADVERTISE_1000XPSE_ASYM;
    114	if (sparx5_is_baser(interface)) {
    115		if (phylink_test(advertising, FIBRE))
    116			conf.media = PHY_MEDIA_SR;
    117		else
    118			conf.media = PHY_MEDIA_DAC;
    119	}
    120	if (!port_conf_has_changed(&port->conf, &conf))
    121		return ret;
    122	/* Enable the PCS matching this interface type */
    123	ret = sparx5_port_pcs_set(port->sparx5, port, &conf);
    124	if (ret)
    125		netdev_err(port->ndev, "port PCS config failed: %d\n", ret);
    126	return ret;
    127}
    128
    129static void sparx5_pcs_aneg_restart(struct phylink_pcs *pcs)
    130{
    131	/* Currently not used */
    132}
    133
    134const struct phylink_pcs_ops sparx5_phylink_pcs_ops = {
    135	.pcs_get_state = sparx5_pcs_get_state,
    136	.pcs_config = sparx5_pcs_config,
    137	.pcs_an_restart = sparx5_pcs_aneg_restart,
    138};
    139
    140const struct phylink_mac_ops sparx5_phylink_mac_ops = {
    141	.validate = phylink_generic_validate,
    142	.mac_select_pcs = sparx5_phylink_mac_select_pcs,
    143	.mac_config = sparx5_phylink_mac_config,
    144	.mac_link_down = sparx5_phylink_mac_link_down,
    145	.mac_link_up = sparx5_phylink_mac_link_up,
    146};