mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net: txgbe: support copper NIC with external PHY
Wangxun SP chip supports to connect with external PHY (marvell 88x3310), which links to 10GBASE-T/1000BASE-T/100BASE-T. Add the identification of media types from subsystem device IDs. For sp_media_copper, register mdio bus for the external PHY. Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									a4414dd13f
								
							
						
					
					
						commit
						02b2a6f91b
					
				
					 5 changed files with 221 additions and 22 deletions
				
			
		| 
						 | 
					@ -41,6 +41,7 @@ config TXGBE
 | 
				
			||||||
	tristate "Wangxun(R) 10GbE PCI Express adapters support"
 | 
						tristate "Wangxun(R) 10GbE PCI Express adapters support"
 | 
				
			||||||
	depends on PCI
 | 
						depends on PCI
 | 
				
			||||||
	depends on COMMON_CLK
 | 
						depends on COMMON_CLK
 | 
				
			||||||
 | 
						select MARVELL_10G_PHY
 | 
				
			||||||
	select REGMAP
 | 
						select REGMAP
 | 
				
			||||||
	select I2C
 | 
						select I2C
 | 
				
			||||||
	select I2C_DESIGNWARE_PLATFORM
 | 
						select I2C_DESIGNWARE_PLATFORM
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -233,6 +233,24 @@
 | 
				
			||||||
#define WX_MAC_WDG_TIMEOUT           0x1100C
 | 
					#define WX_MAC_WDG_TIMEOUT           0x1100C
 | 
				
			||||||
#define WX_MAC_RX_FLOW_CTRL          0x11090
 | 
					#define WX_MAC_RX_FLOW_CTRL          0x11090
 | 
				
			||||||
#define WX_MAC_RX_FLOW_CTRL_RFE      BIT(0) /* receive fc enable */
 | 
					#define WX_MAC_RX_FLOW_CTRL_RFE      BIT(0) /* receive fc enable */
 | 
				
			||||||
 | 
					/* MDIO Registers */
 | 
				
			||||||
 | 
					#define WX_MSCA                      0x11200
 | 
				
			||||||
 | 
					#define WX_MSCA_RA(v)                FIELD_PREP(U16_MAX, v)
 | 
				
			||||||
 | 
					#define WX_MSCA_PA(v)                FIELD_PREP(GENMASK(20, 16), v)
 | 
				
			||||||
 | 
					#define WX_MSCA_DA(v)                FIELD_PREP(GENMASK(25, 21), v)
 | 
				
			||||||
 | 
					#define WX_MSCC                      0x11204
 | 
				
			||||||
 | 
					#define WX_MSCC_CMD(v)               FIELD_PREP(GENMASK(17, 16), v)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum WX_MSCA_CMD_value {
 | 
				
			||||||
 | 
						WX_MSCA_CMD_RSV = 0,
 | 
				
			||||||
 | 
						WX_MSCA_CMD_WRITE,
 | 
				
			||||||
 | 
						WX_MSCA_CMD_POST_READ,
 | 
				
			||||||
 | 
						WX_MSCA_CMD_READ,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define WX_MSCC_SADDR                BIT(18)
 | 
				
			||||||
 | 
					#define WX_MSCC_BUSY                 BIT(22)
 | 
				
			||||||
 | 
					#define WX_MDIO_CLK(v)               FIELD_PREP(GENMASK(21, 19), v)
 | 
				
			||||||
#define WX_MMC_CONTROL               0x11800
 | 
					#define WX_MMC_CONTROL               0x11800
 | 
				
			||||||
#define WX_MMC_CONTROL_RSTONRD       BIT(2) /* reset on read */
 | 
					#define WX_MMC_CONTROL_RSTONRD       BIT(2) /* reset on read */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -582,6 +600,13 @@ enum wx_mac_type {
 | 
				
			||||||
	wx_mac_em
 | 
						wx_mac_em
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum sp_media_type {
 | 
				
			||||||
 | 
						sp_media_unknown = 0,
 | 
				
			||||||
 | 
						sp_media_fiber,
 | 
				
			||||||
 | 
						sp_media_copper,
 | 
				
			||||||
 | 
						sp_media_backplane
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum em_mac_type {
 | 
					enum em_mac_type {
 | 
				
			||||||
	em_mac_type_unknown = 0,
 | 
						em_mac_type_unknown = 0,
 | 
				
			||||||
	em_mac_type_mdi,
 | 
						em_mac_type_mdi,
 | 
				
			||||||
| 
						 | 
					@ -829,6 +854,7 @@ struct wx {
 | 
				
			||||||
	struct wx_bus_info bus;
 | 
						struct wx_bus_info bus;
 | 
				
			||||||
	struct wx_mac_info mac;
 | 
						struct wx_mac_info mac;
 | 
				
			||||||
	enum em_mac_type mac_type;
 | 
						enum em_mac_type mac_type;
 | 
				
			||||||
 | 
						enum sp_media_type media_type;
 | 
				
			||||||
	struct wx_eeprom_info eeprom;
 | 
						struct wx_eeprom_info eeprom;
 | 
				
			||||||
	struct wx_addr_filter_info addr_ctrl;
 | 
						struct wx_addr_filter_info addr_ctrl;
 | 
				
			||||||
	struct wx_mac_addr *mac_table;
 | 
						struct wx_mac_addr *mac_table;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -285,17 +285,20 @@ static void txgbe_reset_misc(struct wx *wx)
 | 
				
			||||||
int txgbe_reset_hw(struct wx *wx)
 | 
					int txgbe_reset_hw(struct wx *wx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int status;
 | 
						int status;
 | 
				
			||||||
	u32 val;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Call adapter stop to disable tx/rx and clear interrupts */
 | 
						/* Call adapter stop to disable tx/rx and clear interrupts */
 | 
				
			||||||
	status = wx_stop_adapter(wx);
 | 
						status = wx_stop_adapter(wx);
 | 
				
			||||||
	if (status != 0)
 | 
						if (status != 0)
 | 
				
			||||||
		return status;
 | 
							return status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	val = WX_MIS_RST_LAN_RST(wx->bus.func);
 | 
						if (wx->media_type != sp_media_copper) {
 | 
				
			||||||
	wr32(wx, WX_MIS_RST, val | rd32(wx, WX_MIS_RST));
 | 
							u32 val;
 | 
				
			||||||
	WX_WRITE_FLUSH(wx);
 | 
					
 | 
				
			||||||
	usleep_range(10, 100);
 | 
							val = WX_MIS_RST_LAN_RST(wx->bus.func);
 | 
				
			||||||
 | 
							wr32(wx, WX_MIS_RST, val | rd32(wx, WX_MIS_RST));
 | 
				
			||||||
 | 
							WX_WRITE_FLUSH(wx);
 | 
				
			||||||
 | 
							usleep_range(10, 100);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	status = wx_check_flash_load(wx, TXGBE_SPI_ILDR_STATUS_LAN_SW_RST(wx->bus.func));
 | 
						status = wx_check_flash_load(wx, TXGBE_SPI_ILDR_STATUS_LAN_SW_RST(wx->bus.func));
 | 
				
			||||||
	if (status != 0)
 | 
						if (status != 0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -300,6 +300,49 @@ static void txgbe_down(struct wx *wx)
 | 
				
			||||||
	wx_clean_all_rx_rings(wx);
 | 
						wx_clean_all_rx_rings(wx);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 *  txgbe_init_type_code - Initialize the shared code
 | 
				
			||||||
 | 
					 *  @wx: pointer to hardware structure
 | 
				
			||||||
 | 
					 **/
 | 
				
			||||||
 | 
					static void txgbe_init_type_code(struct wx *wx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 device_type = wx->subsystem_device_id & 0xF0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (wx->device_id) {
 | 
				
			||||||
 | 
						case TXGBE_DEV_ID_SP1000:
 | 
				
			||||||
 | 
						case TXGBE_DEV_ID_WX1820:
 | 
				
			||||||
 | 
							wx->mac.type = wx_mac_sp;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							wx->mac.type = wx_mac_unknown;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (device_type) {
 | 
				
			||||||
 | 
						case TXGBE_ID_SFP:
 | 
				
			||||||
 | 
							wx->media_type = sp_media_fiber;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case TXGBE_ID_XAUI:
 | 
				
			||||||
 | 
						case TXGBE_ID_SGMII:
 | 
				
			||||||
 | 
							wx->media_type = sp_media_copper;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case TXGBE_ID_KR_KX_KX4:
 | 
				
			||||||
 | 
						case TXGBE_ID_MAC_XAUI:
 | 
				
			||||||
 | 
						case TXGBE_ID_MAC_SGMII:
 | 
				
			||||||
 | 
							wx->media_type = sp_media_backplane;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case TXGBE_ID_SFI_XAUI:
 | 
				
			||||||
 | 
							if (wx->bus.func == 0)
 | 
				
			||||||
 | 
								wx->media_type = sp_media_fiber;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								wx->media_type = sp_media_copper;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							wx->media_type = sp_media_unknown;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * txgbe_sw_init - Initialize general software structures (struct wx)
 | 
					 * txgbe_sw_init - Initialize general software structures (struct wx)
 | 
				
			||||||
 * @wx: board private structure to initialize
 | 
					 * @wx: board private structure to initialize
 | 
				
			||||||
| 
						 | 
					@ -324,15 +367,7 @@ static int txgbe_sw_init(struct wx *wx)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (wx->device_id) {
 | 
						txgbe_init_type_code(wx);
 | 
				
			||||||
	case TXGBE_DEV_ID_SP1000:
 | 
					 | 
				
			||||||
	case TXGBE_DEV_ID_WX1820:
 | 
					 | 
				
			||||||
		wx->mac.type = wx_mac_sp;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		wx->mac.type = wx_mac_unknown;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Set common capability flags and settings */
 | 
						/* Set common capability flags and settings */
 | 
				
			||||||
	wx->max_q_vectors = TXGBE_MAX_MSIX_VECTORS;
 | 
						wx->max_q_vectors = TXGBE_MAX_MSIX_VECTORS;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -161,7 +161,10 @@ static struct phylink_pcs *txgbe_phylink_mac_select(struct phylink_config *confi
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct txgbe *txgbe = netdev_to_txgbe(to_net_dev(config->dev));
 | 
						struct txgbe *txgbe = netdev_to_txgbe(to_net_dev(config->dev));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &txgbe->xpcs->pcs;
 | 
						if (interface == PHY_INTERFACE_MODE_10GBASER)
 | 
				
			||||||
 | 
							return &txgbe->xpcs->pcs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void txgbe_mac_config(struct phylink_config *config, unsigned int mode,
 | 
					static void txgbe_mac_config(struct phylink_config *config, unsigned int mode,
 | 
				
			||||||
| 
						 | 
					@ -244,8 +247,8 @@ static const struct phylink_mac_ops txgbe_mac_ops = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int txgbe_phylink_init(struct txgbe *txgbe)
 | 
					static int txgbe_phylink_init(struct txgbe *txgbe)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct fwnode_handle *fwnode = NULL;
 | 
				
			||||||
	struct phylink_config *config;
 | 
						struct phylink_config *config;
 | 
				
			||||||
	struct fwnode_handle *fwnode;
 | 
					 | 
				
			||||||
	struct wx *wx = txgbe->wx;
 | 
						struct wx *wx = txgbe->wx;
 | 
				
			||||||
	phy_interface_t phy_mode;
 | 
						phy_interface_t phy_mode;
 | 
				
			||||||
	struct phylink *phylink;
 | 
						struct phylink *phylink;
 | 
				
			||||||
| 
						 | 
					@ -256,16 +259,34 @@ static int txgbe_phylink_init(struct txgbe *txgbe)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config->dev = &wx->netdev->dev;
 | 
						config->dev = &wx->netdev->dev;
 | 
				
			||||||
	config->type = PHYLINK_NETDEV;
 | 
						config->type = PHYLINK_NETDEV;
 | 
				
			||||||
	config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
 | 
						config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_100FD |
 | 
				
			||||||
	phy_mode = PHY_INTERFACE_MODE_10GBASER;
 | 
									   MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
 | 
				
			||||||
	__set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces);
 | 
					
 | 
				
			||||||
	__set_bit(PHY_INTERFACE_MODE_1000BASEX, config->supported_interfaces);
 | 
						if (wx->media_type == sp_media_copper) {
 | 
				
			||||||
	__set_bit(PHY_INTERFACE_MODE_SGMII, config->supported_interfaces);
 | 
							phy_mode = PHY_INTERFACE_MODE_XAUI;
 | 
				
			||||||
	fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_PHYLINK]);
 | 
							__set_bit(PHY_INTERFACE_MODE_XAUI, config->supported_interfaces);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							phy_mode = PHY_INTERFACE_MODE_10GBASER;
 | 
				
			||||||
 | 
							fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_PHYLINK]);
 | 
				
			||||||
 | 
							__set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces);
 | 
				
			||||||
 | 
							__set_bit(PHY_INTERFACE_MODE_1000BASEX, config->supported_interfaces);
 | 
				
			||||||
 | 
							__set_bit(PHY_INTERFACE_MODE_SGMII, config->supported_interfaces);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	phylink = phylink_create(config, fwnode, phy_mode, &txgbe_mac_ops);
 | 
						phylink = phylink_create(config, fwnode, phy_mode, &txgbe_mac_ops);
 | 
				
			||||||
	if (IS_ERR(phylink))
 | 
						if (IS_ERR(phylink))
 | 
				
			||||||
		return PTR_ERR(phylink);
 | 
							return PTR_ERR(phylink);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (wx->phydev) {
 | 
				
			||||||
 | 
							int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ret = phylink_connect_phy(phylink, wx->phydev);
 | 
				
			||||||
 | 
							if (ret) {
 | 
				
			||||||
 | 
								phylink_destroy(phylink);
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	txgbe->phylink = phylink;
 | 
						txgbe->phylink = phylink;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -626,10 +647,117 @@ static int txgbe_sfp_register(struct txgbe *txgbe)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int txgbe_phy_read(struct mii_bus *bus, int phy_addr,
 | 
				
			||||||
 | 
								  int devnum, int regnum)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct wx *wx = bus->priv;
 | 
				
			||||||
 | 
						u32 val, command;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* setup and write the address cycle command */
 | 
				
			||||||
 | 
						command = WX_MSCA_RA(regnum) |
 | 
				
			||||||
 | 
							  WX_MSCA_PA(phy_addr) |
 | 
				
			||||||
 | 
							  WX_MSCA_DA(devnum);
 | 
				
			||||||
 | 
						wr32(wx, WX_MSCA, command);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						command = WX_MSCC_CMD(WX_MSCA_CMD_READ) | WX_MSCC_BUSY;
 | 
				
			||||||
 | 
						wr32(wx, WX_MSCC, command);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* wait to complete */
 | 
				
			||||||
 | 
						ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
 | 
				
			||||||
 | 
									100000, false, wx, WX_MSCC);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							wx_err(wx, "Mdio read c45 command did not complete.\n");
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return (u16)rd32(wx, WX_MSCC);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int txgbe_phy_write(struct mii_bus *bus, int phy_addr,
 | 
				
			||||||
 | 
								   int devnum, int regnum, u16 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct wx *wx = bus->priv;
 | 
				
			||||||
 | 
						int ret, command;
 | 
				
			||||||
 | 
						u16 val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* setup and write the address cycle command */
 | 
				
			||||||
 | 
						command = WX_MSCA_RA(regnum) |
 | 
				
			||||||
 | 
							  WX_MSCA_PA(phy_addr) |
 | 
				
			||||||
 | 
							  WX_MSCA_DA(devnum);
 | 
				
			||||||
 | 
						wr32(wx, WX_MSCA, command);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						command = value | WX_MSCC_CMD(WX_MSCA_CMD_WRITE) | WX_MSCC_BUSY;
 | 
				
			||||||
 | 
						wr32(wx, WX_MSCC, command);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* wait to complete */
 | 
				
			||||||
 | 
						ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
 | 
				
			||||||
 | 
									100000, false, wx, WX_MSCC);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							wx_err(wx, "Mdio write c45 command did not complete.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int txgbe_ext_phy_init(struct txgbe *txgbe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct phy_device *phydev;
 | 
				
			||||||
 | 
						struct mii_bus *mii_bus;
 | 
				
			||||||
 | 
						struct pci_dev *pdev;
 | 
				
			||||||
 | 
						struct wx *wx;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wx = txgbe->wx;
 | 
				
			||||||
 | 
						pdev = wx->pdev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mii_bus = devm_mdiobus_alloc(&pdev->dev);
 | 
				
			||||||
 | 
						if (!mii_bus)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mii_bus->name = "txgbe_mii_bus";
 | 
				
			||||||
 | 
						mii_bus->read_c45 = &txgbe_phy_read;
 | 
				
			||||||
 | 
						mii_bus->write_c45 = &txgbe_phy_write;
 | 
				
			||||||
 | 
						mii_bus->parent = &pdev->dev;
 | 
				
			||||||
 | 
						mii_bus->phy_mask = GENMASK(31, 1);
 | 
				
			||||||
 | 
						mii_bus->priv = wx;
 | 
				
			||||||
 | 
						snprintf(mii_bus->id, MII_BUS_ID_SIZE, "txgbe-%x",
 | 
				
			||||||
 | 
							 (pdev->bus->number << 8) | pdev->devfn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = devm_mdiobus_register(&pdev->dev, mii_bus);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							wx_err(wx, "failed to register MDIO bus: %d\n", ret);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						phydev = phy_find_first(mii_bus);
 | 
				
			||||||
 | 
						if (!phydev) {
 | 
				
			||||||
 | 
							wx_err(wx, "no PHY found\n");
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						phy_attached_info(phydev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wx->link = 0;
 | 
				
			||||||
 | 
						wx->speed = 0;
 | 
				
			||||||
 | 
						wx->duplex = 0;
 | 
				
			||||||
 | 
						wx->phydev = phydev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = txgbe_phylink_init(txgbe);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							wx_err(wx, "failed to init phylink: %d\n", ret);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int txgbe_init_phy(struct txgbe *txgbe)
 | 
					int txgbe_init_phy(struct txgbe *txgbe)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (txgbe->wx->media_type == sp_media_copper)
 | 
				
			||||||
 | 
							return txgbe_ext_phy_init(txgbe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = txgbe_swnodes_register(txgbe);
 | 
						ret = txgbe_swnodes_register(txgbe);
 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
		wx_err(txgbe->wx, "failed to register software nodes\n");
 | 
							wx_err(txgbe->wx, "failed to register software nodes\n");
 | 
				
			||||||
| 
						 | 
					@ -691,6 +819,12 @@ int txgbe_init_phy(struct txgbe *txgbe)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void txgbe_remove_phy(struct txgbe *txgbe)
 | 
					void txgbe_remove_phy(struct txgbe *txgbe)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						if (txgbe->wx->media_type == sp_media_copper) {
 | 
				
			||||||
 | 
							phylink_disconnect_phy(txgbe->phylink);
 | 
				
			||||||
 | 
							phylink_destroy(txgbe->phylink);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	platform_device_unregister(txgbe->sfp_dev);
 | 
						platform_device_unregister(txgbe->sfp_dev);
 | 
				
			||||||
	platform_device_unregister(txgbe->i2c_dev);
 | 
						platform_device_unregister(txgbe->i2c_dev);
 | 
				
			||||||
	clkdev_drop(txgbe->clock);
 | 
						clkdev_drop(txgbe->clock);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue