aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDavid Daney <ddaney@caviumnetworks.com>2009-10-14 15:04:42 -0400
committerRalf Baechle <ralf@linux-mips.org>2009-12-16 20:57:00 -0500
commitf6ed1b3b3579db5c8c3aaf6fd3010c706973a35d (patch)
tree82957dab3ed4653fe83236fa839fe639294672ff /drivers
parentd6aa60a10b2f5068e331ca2936b1e6c248ae37c1 (diff)
Staging: octeon-ethernet: Convert to use PHY Abstraction Layer.
The octeon-ethernet driver shares an mdio bus with the octeon-mgmt driver. Here we convert the octeon-ethernet driver to use the PHY Abstraction Layer. Signed-off-by: David Daney <ddaney@caviumnetworks.com> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/staging/octeon/Kconfig3
-rw-r--r--drivers/staging/octeon/ethernet-mdio.c204
-rw-r--r--drivers/staging/octeon/ethernet-mdio.h2
-rw-r--r--drivers/staging/octeon/ethernet-proc.c112
-rw-r--r--drivers/staging/octeon/ethernet-rgmii.c52
-rw-r--r--drivers/staging/octeon/ethernet-sgmii.c2
-rw-r--r--drivers/staging/octeon/ethernet-xaui.c2
-rw-r--r--drivers/staging/octeon/ethernet.c23
-rw-r--r--drivers/staging/octeon/octeon-ethernet.h6
9 files changed, 125 insertions, 281 deletions
diff --git a/drivers/staging/octeon/Kconfig b/drivers/staging/octeon/Kconfig
index 536e2382de54..638ad6b35891 100644
--- a/drivers/staging/octeon/Kconfig
+++ b/drivers/staging/octeon/Kconfig
@@ -1,7 +1,8 @@
1config OCTEON_ETHERNET 1config OCTEON_ETHERNET
2 tristate "Cavium Networks Octeon Ethernet support" 2 tristate "Cavium Networks Octeon Ethernet support"
3 depends on CPU_CAVIUM_OCTEON 3 depends on CPU_CAVIUM_OCTEON
4 select MII 4 select PHYLIB
5 select MDIO_OCTEON
5 help 6 help
6 This driver supports the builtin ethernet ports on Cavium 7 This driver supports the builtin ethernet ports on Cavium
7 Networks' products in the Octeon family. This driver supports the 8 Networks' products in the Octeon family. This driver supports the
diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c
index 31a58e508924..05a5cc0f43ed 100644
--- a/drivers/staging/octeon/ethernet-mdio.c
+++ b/drivers/staging/octeon/ethernet-mdio.c
@@ -26,7 +26,8 @@
26**********************************************************************/ 26**********************************************************************/
27#include <linux/kernel.h> 27#include <linux/kernel.h>
28#include <linux/ethtool.h> 28#include <linux/ethtool.h>
29#include <linux/mii.h> 29#include <linux/phy.h>
30
30#include <net/dst.h> 31#include <net/dst.h>
31 32
32#include <asm/octeon/octeon.h> 33#include <asm/octeon/octeon.h>
@@ -34,86 +35,12 @@
34#include "ethernet-defines.h" 35#include "ethernet-defines.h"
35#include "octeon-ethernet.h" 36#include "octeon-ethernet.h"
36#include "ethernet-mdio.h" 37#include "ethernet-mdio.h"
38#include "ethernet-util.h"
37 39
38#include "cvmx-helper-board.h" 40#include "cvmx-helper-board.h"
39 41
40#include "cvmx-smix-defs.h" 42#include "cvmx-smix-defs.h"
41 43
42DECLARE_MUTEX(mdio_sem);
43
44/**
45 * Perform an MII read. Called by the generic MII routines
46 *
47 * @dev: Device to perform read for
48 * @phy_id: The MII phy id
49 * @location: Register location to read
50 * Returns Result from the read or zero on failure
51 */
52static int cvm_oct_mdio_read(struct net_device *dev, int phy_id, int location)
53{
54 union cvmx_smix_cmd smi_cmd;
55 union cvmx_smix_rd_dat smi_rd;
56
57 smi_cmd.u64 = 0;
58 smi_cmd.s.phy_op = 1;
59 smi_cmd.s.phy_adr = phy_id;
60 smi_cmd.s.reg_adr = location;
61 cvmx_write_csr(CVMX_SMIX_CMD(0), smi_cmd.u64);
62
63 do {
64 if (!in_interrupt())
65 yield();
66 smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(0));
67 } while (smi_rd.s.pending);
68
69 if (smi_rd.s.val)
70 return smi_rd.s.dat;
71 else
72 return 0;
73}
74
75static int cvm_oct_mdio_dummy_read(struct net_device *dev, int phy_id,
76 int location)
77{
78 return 0xffff;
79}
80
81/**
82 * Perform an MII write. Called by the generic MII routines
83 *
84 * @dev: Device to perform write for
85 * @phy_id: The MII phy id
86 * @location: Register location to write
87 * @val: Value to write
88 */
89static void cvm_oct_mdio_write(struct net_device *dev, int phy_id, int location,
90 int val)
91{
92 union cvmx_smix_cmd smi_cmd;
93 union cvmx_smix_wr_dat smi_wr;
94
95 smi_wr.u64 = 0;
96 smi_wr.s.dat = val;
97 cvmx_write_csr(CVMX_SMIX_WR_DAT(0), smi_wr.u64);
98
99 smi_cmd.u64 = 0;
100 smi_cmd.s.phy_op = 0;
101 smi_cmd.s.phy_adr = phy_id;
102 smi_cmd.s.reg_adr = location;
103 cvmx_write_csr(CVMX_SMIX_CMD(0), smi_cmd.u64);
104
105 do {
106 if (!in_interrupt())
107 yield();
108 smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(0));
109 } while (smi_wr.s.pending);
110}
111
112static void cvm_oct_mdio_dummy_write(struct net_device *dev, int phy_id,
113 int location, int val)
114{
115}
116
117static void cvm_oct_get_drvinfo(struct net_device *dev, 44static void cvm_oct_get_drvinfo(struct net_device *dev,
118 struct ethtool_drvinfo *info) 45 struct ethtool_drvinfo *info)
119{ 46{
@@ -125,49 +52,37 @@ static void cvm_oct_get_drvinfo(struct net_device *dev,
125static int cvm_oct_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) 52static int cvm_oct_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
126{ 53{
127 struct octeon_ethernet *priv = netdev_priv(dev); 54 struct octeon_ethernet *priv = netdev_priv(dev);
128 int ret;
129 55
130 down(&mdio_sem); 56 if (priv->phydev)
131 ret = mii_ethtool_gset(&priv->mii_info, cmd); 57 return phy_ethtool_gset(priv->phydev, cmd);
132 up(&mdio_sem);
133 58
134 return ret; 59 return -EINVAL;
135} 60}
136 61
137static int cvm_oct_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) 62static int cvm_oct_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
138{ 63{
139 struct octeon_ethernet *priv = netdev_priv(dev); 64 struct octeon_ethernet *priv = netdev_priv(dev);
140 int ret;
141 65
142 down(&mdio_sem); 66 if (!capable(CAP_NET_ADMIN))
143 ret = mii_ethtool_sset(&priv->mii_info, cmd); 67 return -EPERM;
144 up(&mdio_sem); 68
69 if (priv->phydev)
70 return phy_ethtool_sset(priv->phydev, cmd);
145 71
146 return ret; 72 return -EINVAL;
147} 73}
148 74
149static int cvm_oct_nway_reset(struct net_device *dev) 75static int cvm_oct_nway_reset(struct net_device *dev)
150{ 76{
151 struct octeon_ethernet *priv = netdev_priv(dev); 77 struct octeon_ethernet *priv = netdev_priv(dev);
152 int ret;
153 78
154 down(&mdio_sem); 79 if (!capable(CAP_NET_ADMIN))
155 ret = mii_nway_restart(&priv->mii_info); 80 return -EPERM;
156 up(&mdio_sem);
157 81
158 return ret; 82 if (priv->phydev)
159} 83 return phy_start_aneg(priv->phydev);
160 84
161static u32 cvm_oct_get_link(struct net_device *dev) 85 return -EINVAL;
162{
163 struct octeon_ethernet *priv = netdev_priv(dev);
164 u32 ret;
165
166 down(&mdio_sem);
167 ret = mii_link_ok(&priv->mii_info);
168 up(&mdio_sem);
169
170 return ret;
171} 86}
172 87
173const struct ethtool_ops cvm_oct_ethtool_ops = { 88const struct ethtool_ops cvm_oct_ethtool_ops = {
@@ -175,7 +90,7 @@ const struct ethtool_ops cvm_oct_ethtool_ops = {
175 .get_settings = cvm_oct_get_settings, 90 .get_settings = cvm_oct_get_settings,
176 .set_settings = cvm_oct_set_settings, 91 .set_settings = cvm_oct_set_settings,
177 .nway_reset = cvm_oct_nway_reset, 92 .nway_reset = cvm_oct_nway_reset,
178 .get_link = cvm_oct_get_link, 93 .get_link = ethtool_op_get_link,
179 .get_sg = ethtool_op_get_sg, 94 .get_sg = ethtool_op_get_sg,
180 .get_tx_csum = ethtool_op_get_tx_csum, 95 .get_tx_csum = ethtool_op_get_tx_csum,
181}; 96};
@@ -191,41 +106,78 @@ const struct ethtool_ops cvm_oct_ethtool_ops = {
191int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 106int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
192{ 107{
193 struct octeon_ethernet *priv = netdev_priv(dev); 108 struct octeon_ethernet *priv = netdev_priv(dev);
194 struct mii_ioctl_data *data = if_mii(rq);
195 unsigned int duplex_chg;
196 int ret;
197 109
198 down(&mdio_sem); 110 if (!netif_running(dev))
199 ret = generic_mii_ioctl(&priv->mii_info, data, cmd, &duplex_chg); 111 return -EINVAL;
200 up(&mdio_sem); 112
113 if (!priv->phydev)
114 return -EINVAL;
115
116 return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
117}
201 118
202 return ret; 119static void cvm_oct_adjust_link(struct net_device *dev)
120{
121 struct octeon_ethernet *priv = netdev_priv(dev);
122 cvmx_helper_link_info_t link_info;
123
124 if (priv->last_link != priv->phydev->link) {
125 priv->last_link = priv->phydev->link;
126 link_info.u64 = 0;
127 link_info.s.link_up = priv->last_link ? 1 : 0;
128 link_info.s.full_duplex = priv->phydev->duplex ? 1 : 0;
129 link_info.s.speed = priv->phydev->speed;
130 cvmx_helper_link_set( priv->port, link_info);
131 if (priv->last_link) {
132 netif_carrier_on(dev);
133 if (priv->queue != -1)
134 DEBUGPRINT("%s: %u Mbps %s duplex, "
135 "port %2d, queue %2d\n",
136 dev->name, priv->phydev->speed,
137 priv->phydev->duplex ?
138 "Full" : "Half",
139 priv->port, priv->queue);
140 else
141 DEBUGPRINT("%s: %u Mbps %s duplex, "
142 "port %2d, POW\n",
143 dev->name, priv->phydev->speed,
144 priv->phydev->duplex ?
145 "Full" : "Half",
146 priv->port);
147 } else {
148 netif_carrier_off(dev);
149 DEBUGPRINT("%s: Link down\n", dev->name);
150 }
151 }
203} 152}
204 153
154
205/** 155/**
206 * Setup the MDIO device structures 156 * Setup the PHY
207 * 157 *
208 * @dev: Device to setup 158 * @dev: Device to setup
209 * 159 *
210 * Returns Zero on success, negative on failure 160 * Returns Zero on success, negative on failure
211 */ 161 */
212int cvm_oct_mdio_setup_device(struct net_device *dev) 162int cvm_oct_phy_setup_device(struct net_device *dev)
213{ 163{
214 struct octeon_ethernet *priv = netdev_priv(dev); 164 struct octeon_ethernet *priv = netdev_priv(dev);
215 int phy_id = cvmx_helper_board_get_mii_address(priv->port); 165
216 if (phy_id != -1) { 166 int phy_addr = cvmx_helper_board_get_mii_address(priv->port);
217 priv->mii_info.dev = dev; 167 if (phy_addr != -1) {
218 priv->mii_info.phy_id = phy_id; 168 char phy_id[20];
219 priv->mii_info.phy_id_mask = 0xff; 169
220 priv->mii_info.supports_gmii = 1; 170 snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, "0", phy_addr);
221 priv->mii_info.reg_num_mask = 0x1f; 171
222 priv->mii_info.mdio_read = cvm_oct_mdio_read; 172 priv->phydev = phy_connect(dev, phy_id, cvm_oct_adjust_link, 0,
223 priv->mii_info.mdio_write = cvm_oct_mdio_write; 173 PHY_INTERFACE_MODE_GMII);
224 } else { 174
225 /* Supply dummy MDIO routines so the kernel won't crash 175 if (IS_ERR(priv->phydev)) {
226 if the user tries to read them */ 176 priv->phydev = NULL;
227 priv->mii_info.mdio_read = cvm_oct_mdio_dummy_read; 177 return -1;
228 priv->mii_info.mdio_write = cvm_oct_mdio_dummy_write; 178 }
179 priv->last_link = 0;
180 phy_start_aneg(priv->phydev);
229 } 181 }
230 return 0; 182 return 0;
231} 183}
diff --git a/drivers/staging/octeon/ethernet-mdio.h b/drivers/staging/octeon/ethernet-mdio.h
index b3328aeec2df..55d0614a7cd9 100644
--- a/drivers/staging/octeon/ethernet-mdio.h
+++ b/drivers/staging/octeon/ethernet-mdio.h
@@ -43,4 +43,4 @@
43 43
44extern const struct ethtool_ops cvm_oct_ethtool_ops; 44extern const struct ethtool_ops cvm_oct_ethtool_ops;
45int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); 45int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
46int cvm_oct_mdio_setup_device(struct net_device *dev); 46int cvm_oct_phy_setup_device(struct net_device *dev);
diff --git a/drivers/staging/octeon/ethernet-proc.c b/drivers/staging/octeon/ethernet-proc.c
index 8fa88fc419b7..16308d484d3b 100644
--- a/drivers/staging/octeon/ethernet-proc.c
+++ b/drivers/staging/octeon/ethernet-proc.c
@@ -25,7 +25,6 @@
25 * Contact Cavium Networks for more information 25 * Contact Cavium Networks for more information
26**********************************************************************/ 26**********************************************************************/
27#include <linux/kernel.h> 27#include <linux/kernel.h>
28#include <linux/mii.h>
29#include <linux/seq_file.h> 28#include <linux/seq_file.h>
30#include <linux/proc_fs.h> 29#include <linux/proc_fs.h>
31#include <net/dst.h> 30#include <net/dst.h>
@@ -38,112 +37,6 @@
38#include "cvmx-helper.h" 37#include "cvmx-helper.h"
39#include "cvmx-pip.h" 38#include "cvmx-pip.h"
40 39
41static unsigned long long cvm_oct_stats_read_switch(struct net_device *dev,
42 int phy_id, int offset)
43{
44 struct octeon_ethernet *priv = netdev_priv(dev);
45
46 priv->mii_info.mdio_write(dev, phy_id, 0x1d, 0xcc00 | offset);
47 return ((uint64_t) priv->mii_info.
48 mdio_read(dev, phy_id,
49 0x1e) << 16) | (uint64_t) priv->mii_info.
50 mdio_read(dev, phy_id, 0x1f);
51}
52
53static int cvm_oct_stats_switch_show(struct seq_file *m, void *v)
54{
55 static const int ports[] = { 0, 1, 2, 3, 9, -1 };
56 struct net_device *dev = cvm_oct_device[0];
57 int index = 0;
58
59 while (ports[index] != -1) {
60
61 /* Latch port */
62 struct octeon_ethernet *priv = netdev_priv(dev);
63
64 priv->mii_info.mdio_write(dev, 0x1b, 0x1d,
65 0xdc00 | ports[index]);
66 seq_printf(m, "\nSwitch Port %d\n", ports[index]);
67 seq_printf(m, "InGoodOctets: %12llu\t"
68 "OutOctets: %12llu\t"
69 "64 Octets: %12llu\n",
70 cvm_oct_stats_read_switch(dev, 0x1b,
71 0x00) |
72 (cvm_oct_stats_read_switch(dev, 0x1b, 0x01) << 32),
73 cvm_oct_stats_read_switch(dev, 0x1b,
74 0x0E) |
75 (cvm_oct_stats_read_switch(dev, 0x1b, 0x0F) << 32),
76 cvm_oct_stats_read_switch(dev, 0x1b, 0x08));
77
78 seq_printf(m, "InBadOctets: %12llu\t"
79 "OutUnicast: %12llu\t"
80 "65-127 Octets: %12llu\n",
81 cvm_oct_stats_read_switch(dev, 0x1b, 0x02),
82 cvm_oct_stats_read_switch(dev, 0x1b, 0x10),
83 cvm_oct_stats_read_switch(dev, 0x1b, 0x09));
84
85 seq_printf(m, "InUnicast: %12llu\t"
86 "OutBroadcasts: %12llu\t"
87 "128-255 Octets: %12llu\n",
88 cvm_oct_stats_read_switch(dev, 0x1b, 0x04),
89 cvm_oct_stats_read_switch(dev, 0x1b, 0x13),
90 cvm_oct_stats_read_switch(dev, 0x1b, 0x0A));
91
92 seq_printf(m, "InBroadcasts: %12llu\t"
93 "OutMulticasts: %12llu\t"
94 "256-511 Octets: %12llu\n",
95 cvm_oct_stats_read_switch(dev, 0x1b, 0x06),
96 cvm_oct_stats_read_switch(dev, 0x1b, 0x12),
97 cvm_oct_stats_read_switch(dev, 0x1b, 0x0B));
98
99 seq_printf(m, "InMulticasts: %12llu\t"
100 "OutPause: %12llu\t"
101 "512-1023 Octets:%12llu\n",
102 cvm_oct_stats_read_switch(dev, 0x1b, 0x07),
103 cvm_oct_stats_read_switch(dev, 0x1b, 0x15),
104 cvm_oct_stats_read_switch(dev, 0x1b, 0x0C));
105
106 seq_printf(m, "InPause: %12llu\t"
107 "Excessive: %12llu\t"
108 "1024-Max Octets:%12llu\n",
109 cvm_oct_stats_read_switch(dev, 0x1b, 0x16),
110 cvm_oct_stats_read_switch(dev, 0x1b, 0x11),
111 cvm_oct_stats_read_switch(dev, 0x1b, 0x0D));
112
113 seq_printf(m, "InUndersize: %12llu\t"
114 "Collisions: %12llu\n",
115 cvm_oct_stats_read_switch(dev, 0x1b, 0x18),
116 cvm_oct_stats_read_switch(dev, 0x1b, 0x1E));
117
118 seq_printf(m, "InFragments: %12llu\t"
119 "Deferred: %12llu\n",
120 cvm_oct_stats_read_switch(dev, 0x1b, 0x19),
121 cvm_oct_stats_read_switch(dev, 0x1b, 0x05));
122
123 seq_printf(m, "InOversize: %12llu\t"
124 "Single: %12llu\n",
125 cvm_oct_stats_read_switch(dev, 0x1b, 0x1A),
126 cvm_oct_stats_read_switch(dev, 0x1b, 0x14));
127
128 seq_printf(m, "InJabber: %12llu\t"
129 "Multiple: %12llu\n",
130 cvm_oct_stats_read_switch(dev, 0x1b, 0x1B),
131 cvm_oct_stats_read_switch(dev, 0x1b, 0x17));
132
133 seq_printf(m, "In RxErr: %12llu\t"
134 "OutFCSErr: %12llu\n",
135 cvm_oct_stats_read_switch(dev, 0x1b, 0x1C),
136 cvm_oct_stats_read_switch(dev, 0x1b, 0x03));
137
138 seq_printf(m, "InFCSErr: %12llu\t"
139 "Late: %12llu\n",
140 cvm_oct_stats_read_switch(dev, 0x1b, 0x1D),
141 cvm_oct_stats_read_switch(dev, 0x1b, 0x1F));
142 index++;
143 }
144 return 0;
145}
146
147/** 40/**
148 * User is reading /proc/octeon_ethernet_stats 41 * User is reading /proc/octeon_ethernet_stats
149 * 42 *
@@ -215,11 +108,6 @@ static int cvm_oct_stats_show(struct seq_file *m, void *v)
215 } 108 }
216 } 109 }
217 110
218 if (cvm_oct_device[0]) {
219 priv = netdev_priv(cvm_oct_device[0]);
220 if (priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
221 cvm_oct_stats_switch_show(m, v);
222 }
223 return 0; 111 return 0;
224} 112}
225 113
diff --git a/drivers/staging/octeon/ethernet-rgmii.c b/drivers/staging/octeon/ethernet-rgmii.c
index fbaa465d2fac..3820f1ec11d1 100644
--- a/drivers/staging/octeon/ethernet-rgmii.c
+++ b/drivers/staging/octeon/ethernet-rgmii.c
@@ -147,32 +147,36 @@ static void cvm_oct_rgmii_poll(struct net_device *dev)
147 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface), 147 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
148 gmxx_rxx_int_reg.u64); 148 gmxx_rxx_int_reg.u64);
149 } 149 }
150 150 if (priv->phydev == NULL) {
151 link_info = cvmx_helper_link_autoconf(priv->port); 151 link_info = cvmx_helper_link_autoconf(priv->port);
152 priv->link_info = link_info.u64; 152 priv->link_info = link_info.u64;
153 }
153 spin_unlock_irqrestore(&global_register_lock, flags); 154 spin_unlock_irqrestore(&global_register_lock, flags);
154 155
155 /* Tell Linux */ 156 if (priv->phydev == NULL) {
156 if (link_info.s.link_up) { 157 /* Tell core. */
157 158 if (link_info.s.link_up) {
158 if (!netif_carrier_ok(dev)) 159 if (!netif_carrier_ok(dev))
159 netif_carrier_on(dev); 160 netif_carrier_on(dev);
160 if (priv->queue != -1) 161 if (priv->queue != -1)
161 DEBUGPRINT 162 DEBUGPRINT("%s: %u Mbps %s duplex, "
162 ("%s: %u Mbps %s duplex, port %2d, queue %2d\n", 163 "port %2d, queue %2d\n",
163 dev->name, link_info.s.speed, 164 dev->name, link_info.s.speed,
164 (link_info.s.full_duplex) ? "Full" : "Half", 165 (link_info.s.full_duplex) ?
165 priv->port, priv->queue); 166 "Full" : "Half",
166 else 167 priv->port, priv->queue);
167 DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, POW\n", 168 else
168 dev->name, link_info.s.speed, 169 DEBUGPRINT("%s: %u Mbps %s duplex, "
169 (link_info.s.full_duplex) ? "Full" : "Half", 170 "port %2d, POW\n",
170 priv->port); 171 dev->name, link_info.s.speed,
171 } else { 172 (link_info.s.full_duplex) ?
172 173 "Full" : "Half",
173 if (netif_carrier_ok(dev)) 174 priv->port);
174 netif_carrier_off(dev); 175 } else {
175 DEBUGPRINT("%s: Link down\n", dev->name); 176 if (netif_carrier_ok(dev))
177 netif_carrier_off(dev);
178 DEBUGPRINT("%s: Link down\n", dev->name);
179 }
176 } 180 }
177} 181}
178 182
diff --git a/drivers/staging/octeon/ethernet-sgmii.c b/drivers/staging/octeon/ethernet-sgmii.c
index 2b54996bd85d..6061d01eca2d 100644
--- a/drivers/staging/octeon/ethernet-sgmii.c
+++ b/drivers/staging/octeon/ethernet-sgmii.c
@@ -113,7 +113,7 @@ int cvm_oct_sgmii_init(struct net_device *dev)
113 struct octeon_ethernet *priv = netdev_priv(dev); 113 struct octeon_ethernet *priv = netdev_priv(dev);
114 cvm_oct_common_init(dev); 114 cvm_oct_common_init(dev);
115 dev->netdev_ops->ndo_stop(dev); 115 dev->netdev_ops->ndo_stop(dev);
116 if (!octeon_is_simulation()) 116 if (!octeon_is_simulation() && priv->phydev == NULL)
117 priv->poll = cvm_oct_sgmii_poll; 117 priv->poll = cvm_oct_sgmii_poll;
118 118
119 /* FIXME: Need autoneg logic */ 119 /* FIXME: Need autoneg logic */
diff --git a/drivers/staging/octeon/ethernet-xaui.c b/drivers/staging/octeon/ethernet-xaui.c
index 0c2e7cc40f35..ee3dc41b2c53 100644
--- a/drivers/staging/octeon/ethernet-xaui.c
+++ b/drivers/staging/octeon/ethernet-xaui.c
@@ -112,7 +112,7 @@ int cvm_oct_xaui_init(struct net_device *dev)
112 struct octeon_ethernet *priv = netdev_priv(dev); 112 struct octeon_ethernet *priv = netdev_priv(dev);
113 cvm_oct_common_init(dev); 113 cvm_oct_common_init(dev);
114 dev->netdev_ops->ndo_stop(dev); 114 dev->netdev_ops->ndo_stop(dev);
115 if (!octeon_is_simulation()) 115 if (!octeon_is_simulation() && priv->phydev == NULL)
116 priv->poll = cvm_oct_xaui_poll; 116 priv->poll = cvm_oct_xaui_poll;
117 117
118 return 0; 118 return 0;
diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c
index 492c5029992d..4cfd4b136b32 100644
--- a/drivers/staging/octeon/ethernet.c
+++ b/drivers/staging/octeon/ethernet.c
@@ -30,7 +30,7 @@
30#include <linux/netdevice.h> 30#include <linux/netdevice.h>
31#include <linux/etherdevice.h> 31#include <linux/etherdevice.h>
32#include <linux/delay.h> 32#include <linux/delay.h>
33#include <linux/mii.h> 33#include <linux/phy.h>
34 34
35#include <net/dst.h> 35#include <net/dst.h>
36 36
@@ -132,8 +132,6 @@ static struct timer_list cvm_oct_poll_timer;
132 */ 132 */
133struct net_device *cvm_oct_device[TOTAL_NUMBER_OF_PORTS]; 133struct net_device *cvm_oct_device[TOTAL_NUMBER_OF_PORTS];
134 134
135extern struct semaphore mdio_sem;
136
137/** 135/**
138 * Periodic timer tick for slow management operations 136 * Periodic timer tick for slow management operations
139 * 137 *
@@ -160,13 +158,8 @@ static void cvm_do_timer(unsigned long arg)
160 goto out; 158 goto out;
161 159
162 priv = netdev_priv(cvm_oct_device[port]); 160 priv = netdev_priv(cvm_oct_device[port]);
163 if (priv->poll) { 161 if (priv->poll)
164 /* skip polling if we don't get the lock */ 162 priv->poll(cvm_oct_device[port]);
165 if (!down_trylock(&mdio_sem)) {
166 priv->poll(cvm_oct_device[port]);
167 up(&mdio_sem);
168 }
169 }
170 163
171 queues_per_port = cvmx_pko_get_num_queues(port); 164 queues_per_port = cvmx_pko_get_num_queues(port);
172 /* Drain any pending packets in the free list */ 165 /* Drain any pending packets in the free list */
@@ -524,7 +517,7 @@ int cvm_oct_common_init(struct net_device *dev)
524 dev->features |= NETIF_F_LLTX; 517 dev->features |= NETIF_F_LLTX;
525 SET_ETHTOOL_OPS(dev, &cvm_oct_ethtool_ops); 518 SET_ETHTOOL_OPS(dev, &cvm_oct_ethtool_ops);
526 519
527 cvm_oct_mdio_setup_device(dev); 520 cvm_oct_phy_setup_device(dev);
528 dev->netdev_ops->ndo_set_mac_address(dev, &sa); 521 dev->netdev_ops->ndo_set_mac_address(dev, &sa);
529 dev->netdev_ops->ndo_change_mtu(dev, dev->mtu); 522 dev->netdev_ops->ndo_change_mtu(dev, dev->mtu);
530 523
@@ -540,7 +533,10 @@ int cvm_oct_common_init(struct net_device *dev)
540 533
541void cvm_oct_common_uninit(struct net_device *dev) 534void cvm_oct_common_uninit(struct net_device *dev)
542{ 535{
543 /* Currently nothing to do */ 536 struct octeon_ethernet *priv = netdev_priv(dev);
537
538 if (priv->phydev)
539 phy_disconnect(priv->phydev);
544} 540}
545 541
546static const struct net_device_ops cvm_oct_npi_netdev_ops = { 542static const struct net_device_ops cvm_oct_npi_netdev_ops = {
@@ -627,6 +623,8 @@ static const struct net_device_ops cvm_oct_pow_netdev_ops = {
627#endif 623#endif
628}; 624};
629 625
626extern void octeon_mdiobus_force_mod_depencency(void);
627
630/** 628/**
631 * Module/ driver initialization. Creates the linux network 629 * Module/ driver initialization. Creates the linux network
632 * devices. 630 * devices.
@@ -640,6 +638,7 @@ static int __init cvm_oct_init_module(void)
640 int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE; 638 int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE;
641 int qos; 639 int qos;
642 640
641 octeon_mdiobus_force_mod_depencency();
643 pr_notice("cavium-ethernet %s\n", OCTEON_ETHERNET_VERSION); 642 pr_notice("cavium-ethernet %s\n", OCTEON_ETHERNET_VERSION);
644 643
645 if (OCTEON_IS_MODEL(OCTEON_CN52XX)) 644 if (OCTEON_IS_MODEL(OCTEON_CN52XX))
diff --git a/drivers/staging/octeon/octeon-ethernet.h b/drivers/staging/octeon/octeon-ethernet.h
index 3aef9878fc0a..402a15b9bb0e 100644
--- a/drivers/staging/octeon/octeon-ethernet.h
+++ b/drivers/staging/octeon/octeon-ethernet.h
@@ -50,9 +50,9 @@ struct octeon_ethernet {
50 /* List of outstanding tx buffers per queue */ 50 /* List of outstanding tx buffers per queue */
51 struct sk_buff_head tx_free_list[16]; 51 struct sk_buff_head tx_free_list[16];
52 /* Device statistics */ 52 /* Device statistics */
53 struct net_device_stats stats 53 struct net_device_stats stats;
54; /* Generic MII info structure */ 54 struct phy_device *phydev;
55 struct mii_if_info mii_info; 55 unsigned int last_link;
56 /* Last negotiated link state */ 56 /* Last negotiated link state */
57 uint64_t link_info; 57 uint64_t link_info;
58 /* Called periodically to check link status */ 58 /* Called periodically to check link status */