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};