1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) Meta Platforms, Inc. and affiliates. */
5 #include <linux/phylink.h>
9 #include "fbnic_netdev.h"
11 static struct fbnic_net
*
12 fbnic_pcs_to_net(struct phylink_pcs
*pcs
)
14 return container_of(pcs
, struct fbnic_net
, phylink_pcs
);
18 fbnic_phylink_pcs_get_state(struct phylink_pcs
*pcs
,
19 struct phylink_link_state
*state
)
21 struct fbnic_net
*fbn
= fbnic_pcs_to_net(pcs
);
22 struct fbnic_dev
*fbd
= fbn
->fbd
;
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.
28 switch (fbd
->fw_cap
.link_speed
) {
29 case FBNIC_FW_LINK_SPEED_25R1
:
30 state
->speed
= SPEED_25000
;
32 case FBNIC_FW_LINK_SPEED_50R2
:
33 state
->speed
= SPEED_50000
;
35 case FBNIC_FW_LINK_SPEED_100R2
:
36 state
->speed
= SPEED_100000
;
39 state
->speed
= SPEED_UNKNOWN
;
43 state
->duplex
= DUPLEX_FULL
;
45 state
->link
= fbd
->mac
->pcs_get_link(fbd
);
49 fbnic_phylink_pcs_enable(struct phylink_pcs
*pcs
)
51 struct fbnic_net
*fbn
= fbnic_pcs_to_net(pcs
);
52 struct fbnic_dev
*fbd
= fbn
->fbd
;
54 return fbd
->mac
->pcs_enable(fbd
);
58 fbnic_phylink_pcs_disable(struct phylink_pcs
*pcs
)
60 struct fbnic_net
*fbn
= fbnic_pcs_to_net(pcs
);
61 struct fbnic_dev
*fbd
= fbn
->fbd
;
63 return fbd
->mac
->pcs_disable(fbd
);
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
)
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
,
82 static struct phylink_pcs
*
83 fbnic_phylink_mac_select_pcs(struct phylink_config
*config
,
84 phy_interface_t interface
)
86 struct net_device
*netdev
= to_net_dev(config
->dev
);
87 struct fbnic_net
*fbn
= netdev_priv(netdev
);
89 return &fbn
->phylink_pcs
;
93 fbnic_phylink_mac_config(struct phylink_config
*config
, unsigned int mode
,
94 const struct phylink_link_state
*state
)
99 fbnic_phylink_mac_link_down(struct phylink_config
*config
, unsigned int mode
,
100 phy_interface_t interface
)
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
;
106 fbd
->mac
->link_down(fbd
);
108 fbn
->link_down_events
++;
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
)
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
;
121 fbd
->mac
->link_up(fbd
, tx_pause
, rx_pause
);
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
,
131 int fbnic_phylink_init(struct net_device
*netdev
)
133 struct fbnic_net
*fbn
= netdev_priv(netdev
);
134 struct phylink
*phylink
;
136 fbn
->phylink_pcs
.neg_mode
= true;
137 fbn
->phylink_pcs
.ops
= &fbnic_phylink_pcs_ops
;
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
|
145 fbn
->phylink_config
.default_an_inband
= true;
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
);
152 phylink
= phylink_create(&fbn
->phylink_config
, NULL
,
153 PHY_INTERFACE_MODE_XLGMII
,
154 &fbnic_phylink_mac_ops
);
156 return PTR_ERR(phylink
);
158 fbn
->phylink
= phylink
;