0001
0002
0003
0004
0005
0006
0007 #include <linux/module.h>
0008 #include <linux/phylink.h>
0009 #include <linux/device.h>
0010 #include <linux/netdevice.h>
0011 #include <linux/sfp.h>
0012
0013 #include "sparx5_main_regs.h"
0014 #include "sparx5_main.h"
0015 #include "sparx5_port.h"
0016
0017 static bool port_conf_has_changed(struct sparx5_port_config *a, struct sparx5_port_config *b)
0018 {
0019 if (a->speed != b->speed ||
0020 a->portmode != b->portmode ||
0021 a->autoneg != b->autoneg ||
0022 a->pause_adv != b->pause_adv ||
0023 a->power_down != b->power_down ||
0024 a->media != b->media)
0025 return true;
0026 return false;
0027 }
0028
0029 static struct phylink_pcs *
0030 sparx5_phylink_mac_select_pcs(struct phylink_config *config,
0031 phy_interface_t interface)
0032 {
0033 struct sparx5_port *port = netdev_priv(to_net_dev(config->dev));
0034
0035 return &port->phylink_pcs;
0036 }
0037
0038 static void sparx5_phylink_mac_config(struct phylink_config *config,
0039 unsigned int mode,
0040 const struct phylink_link_state *state)
0041 {
0042
0043 }
0044
0045 static void sparx5_phylink_mac_link_up(struct phylink_config *config,
0046 struct phy_device *phy,
0047 unsigned int mode,
0048 phy_interface_t interface,
0049 int speed, int duplex,
0050 bool tx_pause, bool rx_pause)
0051 {
0052 struct sparx5_port *port = netdev_priv(to_net_dev(config->dev));
0053 struct sparx5_port_config conf;
0054 int err;
0055
0056 conf = port->conf;
0057 conf.duplex = duplex;
0058 conf.pause = 0;
0059 conf.pause |= tx_pause ? MLO_PAUSE_TX : 0;
0060 conf.pause |= rx_pause ? MLO_PAUSE_RX : 0;
0061 conf.speed = speed;
0062
0063 err = sparx5_port_config(port->sparx5, port, &conf);
0064 if (err)
0065 netdev_err(port->ndev, "port config failed: %d\n", err);
0066 }
0067
0068 static void sparx5_phylink_mac_link_down(struct phylink_config *config,
0069 unsigned int mode,
0070 phy_interface_t interface)
0071 {
0072
0073 }
0074
0075 static struct sparx5_port *sparx5_pcs_to_port(struct phylink_pcs *pcs)
0076 {
0077 return container_of(pcs, struct sparx5_port, phylink_pcs);
0078 }
0079
0080 static void sparx5_pcs_get_state(struct phylink_pcs *pcs,
0081 struct phylink_link_state *state)
0082 {
0083 struct sparx5_port *port = sparx5_pcs_to_port(pcs);
0084 struct sparx5_port_status status;
0085
0086 sparx5_get_port_status(port->sparx5, port, &status);
0087 state->link = status.link && !status.link_down;
0088 state->an_complete = status.an_complete;
0089 state->speed = status.speed;
0090 state->duplex = status.duplex;
0091 state->pause = status.pause;
0092 }
0093
0094 static int sparx5_pcs_config(struct phylink_pcs *pcs,
0095 unsigned int mode,
0096 phy_interface_t interface,
0097 const unsigned long *advertising,
0098 bool permit_pause_to_mac)
0099 {
0100 struct sparx5_port *port = sparx5_pcs_to_port(pcs);
0101 struct sparx5_port_config conf;
0102 int ret = 0;
0103
0104 conf = port->conf;
0105 conf.power_down = false;
0106 conf.portmode = interface;
0107 conf.inband = phylink_autoneg_inband(mode);
0108 conf.autoneg = phylink_test(advertising, Autoneg);
0109 conf.pause_adv = 0;
0110 if (phylink_test(advertising, Pause))
0111 conf.pause_adv |= ADVERTISE_1000XPAUSE;
0112 if (phylink_test(advertising, Asym_Pause))
0113 conf.pause_adv |= ADVERTISE_1000XPSE_ASYM;
0114 if (sparx5_is_baser(interface)) {
0115 if (phylink_test(advertising, FIBRE))
0116 conf.media = PHY_MEDIA_SR;
0117 else
0118 conf.media = PHY_MEDIA_DAC;
0119 }
0120 if (!port_conf_has_changed(&port->conf, &conf))
0121 return ret;
0122
0123 ret = sparx5_port_pcs_set(port->sparx5, port, &conf);
0124 if (ret)
0125 netdev_err(port->ndev, "port PCS config failed: %d\n", ret);
0126 return ret;
0127 }
0128
0129 static void sparx5_pcs_aneg_restart(struct phylink_pcs *pcs)
0130 {
0131
0132 }
0133
0134 const struct phylink_pcs_ops sparx5_phylink_pcs_ops = {
0135 .pcs_get_state = sparx5_pcs_get_state,
0136 .pcs_config = sparx5_pcs_config,
0137 .pcs_an_restart = sparx5_pcs_aneg_restart,
0138 };
0139
0140 const struct phylink_mac_ops sparx5_phylink_mac_ops = {
0141 .validate = phylink_generic_validate,
0142 .mac_select_pcs = sparx5_phylink_mac_select_pcs,
0143 .mac_config = sparx5_phylink_mac_config,
0144 .mac_link_down = sparx5_phylink_mac_link_down,
0145 .mac_link_up = sparx5_phylink_mac_link_up,
0146 };