aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sky2.c
diff options
context:
space:
mode:
authorshemminger@osdl.org <shemminger@osdl.org>2005-11-30 14:45:12 -0500
committerJeff Garzik <jgarzik@pobox.com>2005-12-01 02:20:19 -0500
commitef743d3359813795fb38c4308bff2311eb30651f (patch)
tree1e8c330cc6cd0d990a83de53c7f12c79821843a4 /drivers/net/sky2.c
parent214376434863f9ca109a7853fbbd6db284d3fba7 (diff)
[PATCH] sky2: add MII support
Add MII ioctl interface to sky2. Signed-off-by: Stephen Hemminger <shemminger@osdl.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r--drivers/net/sky2.c69
1 files changed, 61 insertions, 8 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index d7a94d62d80f..0b9b70174168 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -47,6 +47,7 @@
47#include <linux/in.h> 47#include <linux/in.h>
48#include <linux/delay.h> 48#include <linux/delay.h>
49#include <linux/if_vlan.h> 49#include <linux/if_vlan.h>
50#include <linux/mii.h>
50 51
51#include <asm/irq.h> 52#include <asm/irq.h>
52 53
@@ -136,7 +137,7 @@ static const char *yukon_name[] = {
136 137
137 138
138/* Access to external PHY */ 139/* Access to external PHY */
139static void gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val) 140static int gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val)
140{ 141{
141 int i; 142 int i;
142 143
@@ -146,13 +147,15 @@ static void gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val)
146 147
147 for (i = 0; i < PHY_RETRIES; i++) { 148 for (i = 0; i < PHY_RETRIES; i++) {
148 if (!(gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY)) 149 if (!(gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY))
149 return; 150 return 0;
150 udelay(1); 151 udelay(1);
151 } 152 }
153
152 printk(KERN_WARNING PFX "%s: phy write timeout\n", hw->dev[port]->name); 154 printk(KERN_WARNING PFX "%s: phy write timeout\n", hw->dev[port]->name);
155 return -ETIMEDOUT;
153} 156}
154 157
155static u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg) 158static int __gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg, u16 *val)
156{ 159{
157 int i; 160 int i;
158 161
@@ -160,14 +163,24 @@ static u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg)
160 | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD); 163 | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD);
161 164
162 for (i = 0; i < PHY_RETRIES; i++) { 165 for (i = 0; i < PHY_RETRIES; i++) {
163 if (gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL) 166 if (gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL) {
164 goto ready; 167 *val = gma_read16(hw, port, GM_SMI_DATA);
168 return 0;
169 }
170
165 udelay(1); 171 udelay(1);
166 } 172 }
167 173
168 printk(KERN_WARNING PFX "%s: phy read timeout\n", hw->dev[port]->name); 174 return -ETIMEDOUT;
169ready: 175}
170 return gma_read16(hw, port, GM_SMI_DATA); 176
177static u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg)
178{
179 u16 v;
180
181 if (__gm_phy_read(hw, port, reg, &v) != 0)
182 printk(KERN_WARNING PFX "%s: phy read timeout\n", hw->dev[port]->name);
183 return v;
171} 184}
172 185
173static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) 186static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
@@ -792,6 +805,44 @@ static void sky2_rx_clean(struct sky2_port *sky2)
792 } 805 }
793} 806}
794 807
808/* Basic MII support */
809static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
810{
811 struct mii_ioctl_data *data = if_mii(ifr);
812 struct sky2_port *sky2 = netdev_priv(dev);
813 struct sky2_hw *hw = sky2->hw;
814 int err = -EOPNOTSUPP;
815
816 if (!netif_running(dev))
817 return -ENODEV; /* Phy still in reset */
818
819 switch(cmd) {
820 case SIOCGMIIPHY:
821 data->phy_id = PHY_ADDR_MARV;
822
823 /* fallthru */
824 case SIOCGMIIREG: {
825 u16 val = 0;
826 spin_lock_bh(&hw->phy_lock);
827 err = __gm_phy_read(hw, sky2->port, data->reg_num & 0x1f, &val);
828 spin_unlock_bh(&hw->phy_lock);
829 data->val_out = val;
830 break;
831 }
832
833 case SIOCSMIIREG:
834 if (!capable(CAP_NET_ADMIN))
835 return -EPERM;
836
837 spin_lock_bh(&hw->phy_lock);
838 err = gm_phy_write(hw, sky2->port, data->reg_num & 0x1f,
839 data->val_in);
840 spin_unlock_bh(&hw->phy_lock);
841 break;
842 }
843 return err;
844}
845
795#ifdef SKY2_VLAN_TAG_USED 846#ifdef SKY2_VLAN_TAG_USED
796static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) 847static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
797{ 848{
@@ -2708,8 +2759,10 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
2708 2759
2709 SET_MODULE_OWNER(dev); 2760 SET_MODULE_OWNER(dev);
2710 SET_NETDEV_DEV(dev, &hw->pdev->dev); 2761 SET_NETDEV_DEV(dev, &hw->pdev->dev);
2762 dev->irq = hw->pdev->irq;
2711 dev->open = sky2_up; 2763 dev->open = sky2_up;
2712 dev->stop = sky2_down; 2764 dev->stop = sky2_down;
2765 dev->do_ioctl = sky2_ioctl;
2713 dev->hard_start_xmit = sky2_xmit_frame; 2766 dev->hard_start_xmit = sky2_xmit_frame;
2714 dev->get_stats = sky2_get_stats; 2767 dev->get_stats = sky2_get_stats;
2715 dev->set_multicast_list = sky2_set_multicast; 2768 dev->set_multicast_list = sky2_set_multicast;