mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-31 05:54:26 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			87 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			87 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| --- a/drivers/net/ethernet/ar231x/ar231x.c
 | |
| +++ b/drivers/net/ethernet/ar231x/ar231x.c
 | |
| @@ -150,6 +150,7 @@ static int ar231x_mdiobus_write(struct m
 | |
|  static int ar231x_mdiobus_reset(struct mii_bus *bus);
 | |
|  static int ar231x_mdiobus_probe (struct net_device *dev);
 | |
|  static void ar231x_adjust_link(struct net_device *dev);
 | |
| +static bool no_phy = false;
 | |
|  
 | |
|  #ifndef ERR
 | |
|  #define ERR(fmt, args...) printk("%s: " fmt, __func__, ##args)
 | |
| @@ -182,6 +183,30 @@ static const struct net_device_ops ar231
 | |
|  #endif
 | |
|  };
 | |
|  
 | |
| +static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id)
 | |
| +{
 | |
| +	int phy_reg;
 | |
| +
 | |
| +	/* Grab the bits from PHYIR1, and put them
 | |
| +	 * in the upper half */
 | |
| +	phy_reg = mdiobus_read(bus, addr, MII_PHYSID1);
 | |
| +
 | |
| +	if (phy_reg < 0)
 | |
| +		return -EIO;
 | |
| +
 | |
| +	*phy_id = (phy_reg & 0xffff) << 16;
 | |
| +
 | |
| +	/* Grab the bits from PHYIR2, and put them in the lower half */
 | |
| +	phy_reg = mdiobus_read(bus, addr, MII_PHYSID2);
 | |
| +
 | |
| +	if (phy_reg < 0)
 | |
| +		return -EIO;
 | |
| +
 | |
| +	*phy_id |= (phy_reg & 0xffff);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
|  int ar231x_probe(struct platform_device *pdev)
 | |
|  {
 | |
|  	struct net_device *dev;
 | |
| @@ -299,6 +324,21 @@ int ar231x_probe(struct platform_device
 | |
|  
 | |
|  	mdiobus_register(sp->mii_bus);
 | |
|  
 | |
| +	/* Workaround for Micrel switch, which is only available on
 | |
| +	 * one PHY and cannot be configured through MDIO */
 | |
| +	if (!no_phy) {
 | |
| +		u32 phy_id = 0;
 | |
| +		get_phy_id(sp->mii_bus, 1, &phy_id);
 | |
| +		if (phy_id == 0x00221450)
 | |
| +			no_phy = true;
 | |
| +	}
 | |
| +	if (no_phy) {
 | |
| +		sp->link = 1;
 | |
| +		netif_carrier_on(dev);
 | |
| +		return 0;
 | |
| +	}
 | |
| +	no_phy = true;
 | |
| +
 | |
|  	if (ar231x_mdiobus_probe(dev) != 0) {
 | |
|  		printk(KERN_ERR "%s: mdiobus_probe failed\n", dev->name);
 | |
|  		rx_tasklet_cleanup(dev);
 | |
| @@ -355,8 +395,10 @@ static int ar231x_remove(struct platform
 | |
|  	rx_tasklet_cleanup(dev);
 | |
|  	ar231x_init_cleanup(dev);
 | |
|  	unregister_netdev(dev);
 | |
| -	mdiobus_unregister(sp->mii_bus);
 | |
| -	mdiobus_free(sp->mii_bus);
 | |
| +	if (sp->mii_bus) {
 | |
| +		mdiobus_unregister(sp->mii_bus);
 | |
| +		mdiobus_free(sp->mii_bus);
 | |
| +	}
 | |
|  	kfree(dev);
 | |
|  	return 0;
 | |
|  }
 | |
| @@ -1132,6 +1174,9 @@ static int ar231x_ioctl(struct net_devic
 | |
|  	struct ar231x_private *sp = netdev_priv(dev);
 | |
|  	int ret;
 | |
|  
 | |
| +	if (!sp->phy_dev)
 | |
| +		return -ENODEV;
 | |
| +
 | |
|  	switch (cmd) {
 | |
|  
 | |
|  	case SIOCETHTOOL:
 |