File Index
Files and directories
Sign in
FILE

ngbe_mdio.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2019 - 2022 Beijing WangXun Technology Co., Ltd. */
  3
  4#include <linux/ethtool.h>
  5#include <linux/iopoll.h>
  6#include <linux/pci.h>
  7#include <linux/phy.h>
  8
  9#include "../libwx/wx_type.h"
 10#include "../libwx/wx_ptp.h"
 11#include "../libwx/wx_hw.h"
 12#include "../libwx/wx_sriov.h"
 13#include "ngbe_type.h"
 14#include "ngbe_mdio.h"
 15
 16static int ngbe_phy_read_reg_internal(struct mii_bus *bus, int phy_addr, int regnum)
 17{
 18	struct wx *wx = bus->priv;
 19
 20	if (phy_addr != 0)
 21		return 0xffff;
 22	return (u16)rd32(wx, NGBE_PHY_CONFIG(regnum));
 23}
 24
 25static int ngbe_phy_write_reg_internal(struct mii_bus *bus, int phy_addr, int regnum, u16 value)
 26{
 27	struct wx *wx = bus->priv;
 28
 29	if (phy_addr == 0)
 30		wr32(wx, NGBE_PHY_CONFIG(regnum), value);
 31	return 0;
 32}
 33
 34static int ngbe_phy_read_reg_c22(struct mii_bus *bus, int phy_addr, int regnum)
 35{
 36	struct wx *wx = bus->priv;
 37	u16 phy_data;
 38
 39	if (wx->mac_type == em_mac_type_mdi)
 40		phy_data = ngbe_phy_read_reg_internal(bus, phy_addr, regnum);
 41	else
 42		phy_data = wx_phy_read_reg_mdi_c22(bus, phy_addr, regnum);
 43
 44	return phy_data;
 45}
 46
 47static int ngbe_phy_write_reg_c22(struct mii_bus *bus, int phy_addr,
 48				  int regnum, u16 value)
 49{
 50	struct wx *wx = bus->priv;
 51	int ret;
 52
 53	if (wx->mac_type == em_mac_type_mdi)
 54		ret = ngbe_phy_write_reg_internal(bus, phy_addr, regnum, value);
 55	else
 56		ret = wx_phy_write_reg_mdi_c22(bus, phy_addr, regnum, value);
 57
 58	return ret;
 59}
 60
 61static void ngbe_mac_config(struct phylink_config *config, unsigned int mode,
 62			    const struct phylink_link_state *state)
 63{
 64}
 65
 66static void ngbe_mac_link_down(struct phylink_config *config,
 67			       unsigned int mode, phy_interface_t interface)
 68{
 69	struct wx *wx = phylink_to_wx(config);
 70
 71	wx->speed = SPEED_UNKNOWN;
 72	if (test_bit(WX_STATE_PTP_RUNNING, wx->state))
 73		wx_ptp_reset_cyclecounter(wx);
 74	/* ping all the active vfs to let them know we are going down */
 75	wx_ping_all_vfs_with_link_status(wx, false);
 76}
 77
 78static void ngbe_mac_link_up(struct phylink_config *config,
 79			     struct phy_device *phy,
 80			     unsigned int mode, phy_interface_t interface,
 81			     int speed, int duplex,
 82			     bool tx_pause, bool rx_pause)
 83{
 84	struct wx *wx = phylink_to_wx(config);
 85	u32 lan_speed, reg;
 86
 87	wx_fc_enable(wx, tx_pause, rx_pause);
 88
 89	switch (speed) {
 90	case SPEED_10:
 91		lan_speed = 0;
 92		break;
 93	case SPEED_100:
 94		lan_speed = 1;
 95		break;
 96	case SPEED_1000:
 97	default:
 98		lan_speed = 2;
 99		break;
100	}
101
102	wr32m(wx, NGBE_CFG_LAN_SPEED, 0x3, lan_speed);
103
104	reg = rd32(wx, WX_MAC_TX_CFG);
105	reg &= ~WX_MAC_TX_CFG_SPEED_MASK;
106	reg |= WX_MAC_TX_CFG_SPEED_1G | WX_MAC_TX_CFG_TE;
107	wr32(wx, WX_MAC_TX_CFG, reg);
108
109	/* Re configure MAC Rx */
110	reg = rd32(wx, WX_MAC_RX_CFG);
111	wr32(wx, WX_MAC_RX_CFG, reg);
112	wr32(wx, WX_MAC_PKT_FLT, WX_MAC_PKT_FLT_PR);
113	reg = rd32(wx, WX_MAC_WDG_TIMEOUT);
114	wr32(wx, WX_MAC_WDG_TIMEOUT, reg);
115
116	wx->speed = speed;
117	wx->last_rx_ptp_check = jiffies;
118	if (test_bit(WX_STATE_PTP_RUNNING, wx->state))
119		wx_ptp_reset_cyclecounter(wx);
120	/* ping all the active vfs to let them know we are going up */
121	wx_ping_all_vfs_with_link_status(wx, true);
122}
123
124static const struct phylink_mac_ops ngbe_mac_ops = {
125	.mac_config = ngbe_mac_config,
126	.mac_link_down = ngbe_mac_link_down,
127	.mac_link_up = ngbe_mac_link_up,
128};
129
130static int ngbe_phylink_init(struct wx *wx)
131{
132	struct phylink_config *config;
133	phy_interface_t phy_mode;
134	struct phylink *phylink;
135
136	config = &wx->phylink_config;
137	config->dev = &wx->netdev->dev;
138	config->type = PHYLINK_NETDEV;
139	config->mac_capabilities = MAC_1000FD | MAC_100FD | MAC_10FD |
140				   MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
141	config->mac_managed_pm = true;
142
143	/* The MAC only has add the Tx delay and it can not be modified.
144	 * So just disable TX delay in PHY, and it is does not matter to
145	 * internal phy.
146	 */
147	phy_mode = PHY_INTERFACE_MODE_RGMII_RXID;
148	__set_bit(PHY_INTERFACE_MODE_RGMII_RXID, config->supported_interfaces);
149
150	phylink = phylink_create(config, NULL, phy_mode, &ngbe_mac_ops);
151	if (IS_ERR(phylink))
152		return PTR_ERR(phylink);
153
154	wx->phylink = phylink;
155
156	return 0;
157}
158
159int ngbe_mdio_init(struct wx *wx)
160{
161	struct pci_dev *pdev = wx->pdev;
162	struct mii_bus *mii_bus;
163	int ret;
164
165	mii_bus = devm_mdiobus_alloc(&pdev->dev);
166	if (!mii_bus)
167		return -ENOMEM;
168
169	mii_bus->name = "ngbe_mii_bus";
170	mii_bus->read = ngbe_phy_read_reg_c22;
171	mii_bus->write = ngbe_phy_write_reg_c22;
172	mii_bus->phy_mask = GENMASK(31, 4);
173	mii_bus->parent = &pdev->dev;
174	mii_bus->priv = wx;
175
176	if (wx->mac_type == em_mac_type_rgmii) {
177		mii_bus->read_c45 = wx_phy_read_reg_mdi_c45;
178		mii_bus->write_c45 = wx_phy_write_reg_mdi_c45;
179	}
180
181	snprintf(mii_bus->id, MII_BUS_ID_SIZE, "ngbe-%x", pci_dev_id(pdev));
182	ret = devm_mdiobus_register(&pdev->dev, mii_bus);
183	if (ret)
184		return ret;
185
186	wx->phydev = phy_find_first(mii_bus);
187	if (!wx->phydev)
188		return -ENODEV;
189
190	phy_attached_info(wx->phydev);
191
192	wx->link = 0;
193	wx->speed = 0;
194	wx->duplex = 0;
195
196	ret = ngbe_phylink_init(wx);
197	if (ret) {
198		wx_err(wx, "failed to init phylink: %d\n", ret);
199		return ret;
200	}
201
202	return 0;
203}
~/ Read-only file preview.