diff options
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r-- | drivers/net/sky2.c | 69 |
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 */ |
139 | static void gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val) | 140 | static 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 | ||
155 | static u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg) | 158 | static 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; |
169 | ready: | 175 | } |
170 | return gma_read16(hw, port, GM_SMI_DATA); | 176 | |
177 | static 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 | ||
173 | static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) | 186 | static 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 */ | ||
809 | static 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 |
796 | static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) | 847 | static 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; |