1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) Meta Platforms, Inc. and affiliates. */ 3 4 #include <linux/phy.h> 5 #include <linux/phylink.h> 6 7 #include "fbnic.h" 8 #include "fbnic_mac.h" 9 #include "fbnic_netdev.h" 10 11 static struct fbnic_net * 12 fbnic_pcs_to_net(struct phylink_pcs *pcs) 13 { 14 return container_of(pcs, struct fbnic_net, phylink_pcs); 15 } 16 17 static void 18 fbnic_phylink_pcs_get_state(struct phylink_pcs *pcs, 19 struct phylink_link_state *state) 20 { 21 struct fbnic_net *fbn = fbnic_pcs_to_net(pcs); 22 struct fbnic_dev *fbd = fbn->fbd; 23 24 /* For now we use hard-coded defaults and FW config to determine 25 * the current values. In future patches we will add support for 26 * reconfiguring these values and changing link settings. 27 */ 28 switch (fbd->fw_cap.link_speed) { 29 case FBNIC_FW_LINK_SPEED_25R1: 30 state->speed = SPEED_25000; 31 break; 32 case FBNIC_FW_LINK_SPEED_50R2: 33 state->speed = SPEED_50000; 34 break; 35 case FBNIC_FW_LINK_SPEED_100R2: 36 state->speed = SPEED_100000; 37 break; 38 default: 39 state->speed = SPEED_UNKNOWN; 40 break; 41 } 42 43 state->duplex = DUPLEX_FULL; 44 45 state->link = fbd->mac->pcs_get_link(fbd); 46 } 47 48 static int 49 fbnic_phylink_pcs_enable(struct phylink_pcs *pcs) 50 { 51 struct fbnic_net *fbn = fbnic_pcs_to_net(pcs); 52 struct fbnic_dev *fbd = fbn->fbd; 53 54 return fbd->mac->pcs_enable(fbd); 55 } 56 57 static void 58 fbnic_phylink_pcs_disable(struct phylink_pcs *pcs) 59 { 60 struct fbnic_net *fbn = fbnic_pcs_to_net(pcs); 61 struct fbnic_dev *fbd = fbn->fbd; 62 63 return fbd->mac->pcs_disable(fbd); 64 } 65 66 static int 67 fbnic_phylink_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, 68 phy_interface_t interface, 69 const unsigned long *advertising, 70 bool permit_pause_to_mac) 71 { 72 return 0; 73 } 74 75 static const struct phylink_pcs_ops fbnic_phylink_pcs_ops = { 76 .pcs_config = fbnic_phylink_pcs_config, 77 .pcs_enable = fbnic_phylink_pcs_enable, 78 .pcs_disable = fbnic_phylink_pcs_disable, 79 .pcs_get_state = fbnic_phylink_pcs_get_state, 80 }; 81 82 static struct phylink_pcs * 83 fbnic_phylink_mac_select_pcs(struct phylink_config *config, 84 phy_interface_t interface) 85 { 86 struct net_device *netdev = to_net_dev(config->dev); 87 struct fbnic_net *fbn = netdev_priv(netdev); 88 89 return &fbn->phylink_pcs; 90 } 91 92 static void 93 fbnic_phylink_mac_config(struct phylink_config *config, unsigned int mode, 94 const struct phylink_link_state *state) 95 { 96 } 97 98 static void 99 fbnic_phylink_mac_link_down(struct phylink_config *config, unsigned int mode, 100 phy_interface_t interface) 101 { 102 struct net_device *netdev = to_net_dev(config->dev); 103 struct fbnic_net *fbn = netdev_priv(netdev); 104 struct fbnic_dev *fbd = fbn->fbd; 105 106 fbd->mac->link_down(fbd); 107 108 fbn->link_down_events++; 109 } 110 111 static void 112 fbnic_phylink_mac_link_up(struct phylink_config *config, 113 struct phy_device *phy, unsigned int mode, 114 phy_interface_t interface, int speed, int duplex, 115 bool tx_pause, bool rx_pause) 116 { 117 struct net_device *netdev = to_net_dev(config->dev); 118 struct fbnic_net *fbn = netdev_priv(netdev); 119 struct fbnic_dev *fbd = fbn->fbd; 120 121 fbd->mac->link_up(fbd, tx_pause, rx_pause); 122 } 123 124 static const struct phylink_mac_ops fbnic_phylink_mac_ops = { 125 .mac_select_pcs = fbnic_phylink_mac_select_pcs, 126 .mac_config = fbnic_phylink_mac_config, 127 .mac_link_down = fbnic_phylink_mac_link_down, 128 .mac_link_up = fbnic_phylink_mac_link_up, 129 }; 130 131 int fbnic_phylink_init(struct net_device *netdev) 132 { 133 struct fbnic_net *fbn = netdev_priv(netdev); 134 struct phylink *phylink; 135 136 fbn->phylink_pcs.neg_mode = true; 137 fbn->phylink_pcs.ops = &fbnic_phylink_pcs_ops; 138 139 fbn->phylink_config.dev = &netdev->dev; 140 fbn->phylink_config.type = PHYLINK_NETDEV; 141 fbn->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE | 142 MAC_10000FD | MAC_25000FD | 143 MAC_40000FD | MAC_50000FD | 144 MAC_100000FD; 145 fbn->phylink_config.default_an_inband = true; 146 147 __set_bit(PHY_INTERFACE_MODE_XGMII, 148 fbn->phylink_config.supported_interfaces); 149 __set_bit(PHY_INTERFACE_MODE_XLGMII, 150 fbn->phylink_config.supported_interfaces); 151 152 phylink = phylink_create(&fbn->phylink_config, NULL, 153 PHY_INTERFACE_MODE_XLGMII, 154 &fbnic_phylink_mac_ops); 155 if (IS_ERR(phylink)) 156 return PTR_ERR(phylink); 157 158 fbn->phylink = phylink; 159 160 return 0; 161 } 162