Blame view

drivers/staging/octeon/ethernet-rgmii.c 12.8 KB
80ff0fd3a   David Daney   Staging: Add octe...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  /*********************************************************************
   * Author: Cavium Networks
   *
   * Contact: support@caviumnetworks.com
   * This file is part of the OCTEON SDK
   *
   * Copyright (c) 2003-2007 Cavium Networks
   *
   * This file is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License, Version 2, as
   * published by the Free Software Foundation.
   *
   * This file is distributed in the hope that it will be useful, but
   * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
   * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
   * NONINFRINGEMENT.  See the GNU General Public License for more
   * details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this file; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
   * or visit http://www.gnu.org/licenses/.
   *
   * This file may also be available under a different license from Cavium.
   * Contact Cavium Networks for more information
  **********************************************************************/
  #include <linux/kernel.h>
  #include <linux/netdevice.h>
048316be7   David Daney   staging: octeon-e...
29
  #include <linux/interrupt.h>
f8c264866   David Daney   Staging: Octeon: ...
30
  #include <linux/phy.h>
7a2eaf935   Christian Dietrich   staging: octeon: ...
31
  #include <linux/ratelimit.h>
80ff0fd3a   David Daney   Staging: Add octe...
32
33
34
35
36
37
  #include <net/dst.h>
  
  #include <asm/octeon/octeon.h>
  
  #include "ethernet-defines.h"
  #include "octeon-ethernet.h"
80ff0fd3a   David Daney   Staging: Add octe...
38
  #include "ethernet-util.h"
ec3a2207c   David Daney   staging: octeon-e...
39
  #include "ethernet-mdio.h"
80ff0fd3a   David Daney   Staging: Add octe...
40

af866496c   David Daney   MIPS: Octeon: Mov...
41
  #include <asm/octeon/cvmx-helper.h>
80ff0fd3a   David Daney   Staging: Add octe...
42
43
44
  
  #include <asm/octeon/cvmx-ipd-defs.h>
  #include <asm/octeon/cvmx-npi-defs.h>
af866496c   David Daney   MIPS: Octeon: Mov...
45
  #include <asm/octeon/cvmx-gmxx-defs.h>
80ff0fd3a   David Daney   Staging: Add octe...
46

54bf917ee   Aaro Koskinen   staging: octeon-e...
47
  static DEFINE_SPINLOCK(global_register_lock);
80ff0fd3a   David Daney   Staging: Add octe...
48
49
50
51
52
53
  
  static int number_rgmii_ports;
  
  static void cvm_oct_rgmii_poll(struct net_device *dev)
  {
  	struct octeon_ethernet *priv = netdev_priv(dev);
f8c264866   David Daney   Staging: Octeon: ...
54
  	unsigned long flags = 0;
80ff0fd3a   David Daney   Staging: Add octe...
55
  	cvmx_helper_link_info_t link_info;
f8c264866   David Daney   Staging: Octeon: ...
56
  	int use_global_register_lock = (priv->phydev == NULL);
80ff0fd3a   David Daney   Staging: Add octe...
57

f8c264866   David Daney   Staging: Octeon: ...
58
59
60
61
62
63
64
65
66
67
  	BUG_ON(in_interrupt());
  	if (use_global_register_lock) {
  		/*
  		 * Take the global register lock since we are going to
  		 * touch registers that affect more than one port.
  		 */
  		spin_lock_irqsave(&global_register_lock, flags);
  	} else {
  		mutex_lock(&priv->phydev->bus->mdio_lock);
  	}
80ff0fd3a   David Daney   Staging: Add octe...
68
69
70
71
72
73
74
75
  
  	link_info = cvmx_helper_link_get(priv->port);
  	if (link_info.u64 == priv->link_info) {
  
  		/*
  		 * If the 10Mbps preamble workaround is supported and we're
  		 * at 10Mbps we may need to do some special checking.
  		 */
f09d1444e   Aybuke Ozdemir   staging/octeon:et...
76
77
  		if (USE_10MBPS_PREAMBLE_WORKAROUND &&
  				(link_info.s.speed == 10)) {
80ff0fd3a   David Daney   Staging: Add octe...
78
79
80
81
82
83
84
85
  
  			/*
  			 * Read the GMXX_RXX_INT_REG[PCTERR] bit and
  			 * see if we are getting preamble errors.
  			 */
  			int interface = INTERFACE(priv->port);
  			int index = INDEX(priv->port);
  			union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
5a2da4abe   Melike Yurtoglu   staging: octeon: ...
86

80ff0fd3a   David Daney   Staging: Add octe...
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  			gmxx_rxx_int_reg.u64 =
  			    cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
  					  (index, interface));
  			if (gmxx_rxx_int_reg.s.pcterr) {
  
  				/*
  				 * We are getting preamble errors at
  				 * 10Mbps.  Most likely the PHY is
  				 * giving us packets with mis aligned
  				 * preambles. In order to get these
  				 * packets we need to disable preamble
  				 * checking and do it in software.
  				 */
  				union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
  				union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
  
  				/* Disable preamble checking */
  				gmxx_rxx_frm_ctl.u64 =
  				    cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL
  						  (index, interface));
  				gmxx_rxx_frm_ctl.s.pre_chk = 0;
  				cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL
  					       (index, interface),
  					       gmxx_rxx_frm_ctl.u64);
  
  				/* Disable FCS stripping */
  				ipd_sub_port_fcs.u64 =
  				    cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
  				ipd_sub_port_fcs.s.port_bit &=
  				    0xffffffffull ^ (1ull << priv->port);
  				cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS,
  					       ipd_sub_port_fcs.u64);
  
  				/* Clear any error bits */
  				cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
  					       (index, interface),
  					       gmxx_rxx_int_reg.u64);
42e0e19d5   Gulsah Kose   staging: octeon: ...
124
125
  				printk_ratelimited("%s: Using 10Mbps with software preamble removal
  ",
7a2eaf935   Christian Dietrich   staging: octeon: ...
126
  						   dev->name);
80ff0fd3a   David Daney   Staging: Add octe...
127
128
  			}
  		}
f8c264866   David Daney   Staging: Octeon: ...
129
130
131
132
133
  
  		if (use_global_register_lock)
  			spin_unlock_irqrestore(&global_register_lock, flags);
  		else
  			mutex_unlock(&priv->phydev->bus->mdio_lock);
80ff0fd3a   David Daney   Staging: Add octe...
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  		return;
  	}
  
  	/* If the 10Mbps preamble workaround is allowed we need to on
  	   preamble checking, FCS stripping, and clear error bits on
  	   every speed change. If errors occur during 10Mbps operation
  	   the above code will change this stuff */
  	if (USE_10MBPS_PREAMBLE_WORKAROUND) {
  
  		union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
  		union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
  		union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
  		int interface = INTERFACE(priv->port);
  		int index = INDEX(priv->port);
  
  		/* Enable preamble checking */
  		gmxx_rxx_frm_ctl.u64 =
  		    cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface));
  		gmxx_rxx_frm_ctl.s.pre_chk = 1;
  		cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface),
  			       gmxx_rxx_frm_ctl.u64);
  		/* Enable FCS stripping */
  		ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
  		ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port;
  		cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
  		/* Clear any error bits */
  		gmxx_rxx_int_reg.u64 =
  		    cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index, interface));
  		cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
  			       gmxx_rxx_int_reg.u64);
  	}
f6ed1b3b3   David Daney   Staging: octeon-e...
165
166
167
168
  	if (priv->phydev == NULL) {
  		link_info = cvmx_helper_link_autoconf(priv->port);
  		priv->link_info = link_info.u64;
  	}
f8c264866   David Daney   Staging: Octeon: ...
169
170
171
  
  	if (use_global_register_lock)
  		spin_unlock_irqrestore(&global_register_lock, flags);
4504b1bc0   bahar sahin   Staging: octeon: ...
172
  	else
f8c264866   David Daney   Staging: Octeon: ...
173
  		mutex_unlock(&priv->phydev->bus->mdio_lock);
80ff0fd3a   David Daney   Staging: Add octe...
174

f6ed1b3b3   David Daney   Staging: octeon-e...
175
176
177
178
179
180
  	if (priv->phydev == NULL) {
  		/* Tell core. */
  		if (link_info.s.link_up) {
  			if (!netif_carrier_ok(dev))
  				netif_carrier_on(dev);
  			if (priv->queue != -1)
42e0e19d5   Gulsah Kose   staging: octeon: ...
181
182
  				printk_ratelimited("%s: %u Mbps %s duplex, port %2d, queue %2d
  ",
7a2eaf935   Christian Dietrich   staging: octeon: ...
183
184
185
186
  						   dev->name, link_info.s.speed,
  						   (link_info.s.full_duplex) ?
  						   "Full" : "Half",
  						   priv->port, priv->queue);
f6ed1b3b3   David Daney   Staging: octeon-e...
187
  			else
42e0e19d5   Gulsah Kose   staging: octeon: ...
188
189
  				printk_ratelimited("%s: %u Mbps %s duplex, port %2d, POW
  ",
7a2eaf935   Christian Dietrich   staging: octeon: ...
190
191
192
193
  						   dev->name, link_info.s.speed,
  						   (link_info.s.full_duplex) ?
  						   "Full" : "Half",
  						   priv->port);
f6ed1b3b3   David Daney   Staging: octeon-e...
194
195
196
  		} else {
  			if (netif_carrier_ok(dev))
  				netif_carrier_off(dev);
7a2eaf935   Christian Dietrich   staging: octeon: ...
197
198
  			printk_ratelimited("%s: Link down
  ", dev->name);
f6ed1b3b3   David Daney   Staging: octeon-e...
199
  		}
80ff0fd3a   David Daney   Staging: Add octe...
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  	}
  }
  
  static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
  {
  	union cvmx_npi_rsl_int_blocks rsl_int_blocks;
  	int index;
  	irqreturn_t return_status = IRQ_NONE;
  
  	rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
  
  	/* Check and see if this interrupt was caused by the GMX0 block */
  	if (rsl_int_blocks.s.gmx0) {
  
  		int interface = 0;
  		/* Loop through every port of this interface */
  		for (index = 0;
  		     index < cvmx_helper_ports_on_interface(interface);
  		     index++) {
  
  			/* Read the GMX interrupt status bits */
  			union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
5a2da4abe   Melike Yurtoglu   staging: octeon: ...
222

80ff0fd3a   David Daney   Staging: Add octe...
223
224
225
226
227
228
229
230
231
232
233
234
235
236
  			gmx_rx_int_reg.u64 =
  			    cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
  					  (index, interface));
  			gmx_rx_int_reg.u64 &=
  			    cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
  					  (index, interface));
  			/* Poll the port if inband status changed */
  			if (gmx_rx_int_reg.s.phy_dupx
  			    || gmx_rx_int_reg.s.phy_link
  			    || gmx_rx_int_reg.s.phy_spd) {
  
  				struct net_device *dev =
  				    cvm_oct_device[cvmx_helper_get_ipd_port
  						   (interface, index)];
f8c264866   David Daney   Staging: Octeon: ...
237
  				struct octeon_ethernet *priv = netdev_priv(dev);
f09d1444e   Aybuke Ozdemir   staging/octeon:et...
238
239
240
241
  				if (dev &&
  				!atomic_read(&cvm_oct_poll_queue_stopping))
  					queue_work(cvm_oct_poll_queue,
  						&priv->port_work);
f8c264866   David Daney   Staging: Octeon: ...
242

80ff0fd3a   David Daney   Staging: Add octe...
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  				gmx_rx_int_reg.u64 = 0;
  				gmx_rx_int_reg.s.phy_dupx = 1;
  				gmx_rx_int_reg.s.phy_link = 1;
  				gmx_rx_int_reg.s.phy_spd = 1;
  				cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
  					       (index, interface),
  					       gmx_rx_int_reg.u64);
  				return_status = IRQ_HANDLED;
  			}
  		}
  	}
  
  	/* Check and see if this interrupt was caused by the GMX1 block */
  	if (rsl_int_blocks.s.gmx1) {
  
  		int interface = 1;
  		/* Loop through every port of this interface */
  		for (index = 0;
  		     index < cvmx_helper_ports_on_interface(interface);
  		     index++) {
  
  			/* Read the GMX interrupt status bits */
  			union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
5a2da4abe   Melike Yurtoglu   staging: octeon: ...
266

80ff0fd3a   David Daney   Staging: Add octe...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
  			gmx_rx_int_reg.u64 =
  			    cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
  					  (index, interface));
  			gmx_rx_int_reg.u64 &=
  			    cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
  					  (index, interface));
  			/* Poll the port if inband status changed */
  			if (gmx_rx_int_reg.s.phy_dupx
  			    || gmx_rx_int_reg.s.phy_link
  			    || gmx_rx_int_reg.s.phy_spd) {
  
  				struct net_device *dev =
  				    cvm_oct_device[cvmx_helper_get_ipd_port
  						   (interface, index)];
f8c264866   David Daney   Staging: Octeon: ...
281
  				struct octeon_ethernet *priv = netdev_priv(dev);
f09d1444e   Aybuke Ozdemir   staging/octeon:et...
282
283
284
285
  				if (dev &&
  				!atomic_read(&cvm_oct_poll_queue_stopping))
  					queue_work(cvm_oct_poll_queue,
  						&priv->port_work);
f8c264866   David Daney   Staging: Octeon: ...
286

80ff0fd3a   David Daney   Staging: Add octe...
287
288
289
290
291
292
293
294
295
296
297
298
299
  				gmx_rx_int_reg.u64 = 0;
  				gmx_rx_int_reg.s.phy_dupx = 1;
  				gmx_rx_int_reg.s.phy_link = 1;
  				gmx_rx_int_reg.s.phy_spd = 1;
  				cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
  					       (index, interface),
  					       gmx_rx_int_reg.u64);
  				return_status = IRQ_HANDLED;
  			}
  		}
  	}
  	return return_status;
  }
f696a1083   David Daney   Staging: octeon-e...
300
  int cvm_oct_rgmii_open(struct net_device *dev)
80ff0fd3a   David Daney   Staging: Add octe...
301
302
303
304
305
306
  {
  	union cvmx_gmxx_prtx_cfg gmx_cfg;
  	struct octeon_ethernet *priv = netdev_priv(dev);
  	int interface = INTERFACE(priv->port);
  	int index = INDEX(priv->port);
  	cvmx_helper_link_info_t link_info;
ec3a2207c   David Daney   staging: octeon-e...
307
308
309
310
311
  	int rv;
  
  	rv = cvm_oct_phy_setup_device(dev);
  	if (rv)
  		return rv;
80ff0fd3a   David Daney   Staging: Add octe...
312
313
314
315
316
317
  
  	gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
  	gmx_cfg.s.en = 1;
  	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
  
  	if (!octeon_is_simulation()) {
ec3a2207c   David Daney   staging: octeon-e...
318
319
  		if (priv->phydev) {
  			int r = phy_read_status(priv->phydev);
5a2da4abe   Melike Yurtoglu   staging: octeon: ...
320

ec3a2207c   David Daney   staging: octeon-e...
321
322
323
324
325
326
327
328
329
  			if (r == 0 && priv->phydev->link == 0)
  				netif_carrier_off(dev);
  			cvm_oct_adjust_link(dev);
  		} else {
  			link_info = cvmx_helper_link_get(priv->port);
  			if (!link_info.s.link_up)
  				netif_carrier_off(dev);
  			priv->poll = cvm_oct_rgmii_poll;
  		}
80ff0fd3a   David Daney   Staging: Add octe...
330
331
332
333
  	}
  
  	return 0;
  }
f696a1083   David Daney   Staging: octeon-e...
334
  int cvm_oct_rgmii_stop(struct net_device *dev)
80ff0fd3a   David Daney   Staging: Add octe...
335
336
337
338
339
340
341
342
343
  {
  	union cvmx_gmxx_prtx_cfg gmx_cfg;
  	struct octeon_ethernet *priv = netdev_priv(dev);
  	int interface = INTERFACE(priv->port);
  	int index = INDEX(priv->port);
  
  	gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
  	gmx_cfg.s.en = 0;
  	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
ec3a2207c   David Daney   staging: octeon-e...
344
  	return cvm_oct_common_stop(dev);
80ff0fd3a   David Daney   Staging: Add octe...
345
  }
f8c264866   David Daney   Staging: Octeon: ...
346
347
  static void cvm_oct_rgmii_immediate_poll(struct work_struct *work)
  {
f09d1444e   Aybuke Ozdemir   staging/octeon:et...
348
349
  	struct octeon_ethernet *priv =
  		container_of(work, struct octeon_ethernet, port_work);
f8c264866   David Daney   Staging: Octeon: ...
350
351
  	cvm_oct_rgmii_poll(cvm_oct_device[priv->port]);
  }
80ff0fd3a   David Daney   Staging: Add octe...
352
353
354
355
356
357
  int cvm_oct_rgmii_init(struct net_device *dev)
  {
  	struct octeon_ethernet *priv = netdev_priv(dev);
  	int r;
  
  	cvm_oct_common_init(dev);
f696a1083   David Daney   Staging: octeon-e...
358
  	dev->netdev_ops->ndo_stop(dev);
f8c264866   David Daney   Staging: Octeon: ...
359
  	INIT_WORK(&priv->port_work, cvm_oct_rgmii_immediate_poll);
80ff0fd3a   David Daney   Staging: Add octe...
360
361
  	/*
  	 * Due to GMX errata in CN3XXX series chips, it is necessary
82c7c11fd   Roel Kluin   Staging: octeon: ...
362
  	 * to take the link down immediately when the PHY changes
80ff0fd3a   David Daney   Staging: Add octe...
363
364
365
366
367
368
369
370
  	 * state. In order to do this we call the poll function every
  	 * time the RGMII inband status changes.  This may cause
  	 * problems if the PHY doesn't implement inband status
  	 * properly.
  	 */
  	if (number_rgmii_ports == 0) {
  		r = request_irq(OCTEON_IRQ_RML, cvm_oct_rgmii_rml_interrupt,
  				IRQF_SHARED, "RGMII", &number_rgmii_ports);
82c7c11fd   Roel Kluin   Staging: octeon: ...
371
372
  		if (r != 0)
  			return r;
80ff0fd3a   David Daney   Staging: Add octe...
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
  	}
  	number_rgmii_ports++;
  
  	/*
  	 * Only true RGMII ports need to be polled. In GMII mode, port
  	 * 0 is really a RGMII port.
  	 */
  	if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
  	     && (priv->port == 0))
  	    || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
  
  		if (!octeon_is_simulation()) {
  
  			union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
  			int interface = INTERFACE(priv->port);
  			int index = INDEX(priv->port);
  
  			/*
  			 * Enable interrupts on inband status changes
  			 * for this port.
  			 */
7cc4fa1e5   Aaro Koskinen   staging: octeon-e...
394
  			gmx_rx_int_en.u64 = 0;
80ff0fd3a   David Daney   Staging: Add octe...
395
396
397
398
399
  			gmx_rx_int_en.s.phy_dupx = 1;
  			gmx_rx_int_en.s.phy_link = 1;
  			gmx_rx_int_en.s.phy_spd = 1;
  			cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
  				       gmx_rx_int_en.u64);
80ff0fd3a   David Daney   Staging: Add octe...
400
401
402
403
404
405
406
407
408
  		}
  	}
  
  	return 0;
  }
  
  void cvm_oct_rgmii_uninit(struct net_device *dev)
  {
  	struct octeon_ethernet *priv = netdev_priv(dev);
5a2da4abe   Melike Yurtoglu   staging: octeon: ...
409

80ff0fd3a   David Daney   Staging: Add octe...
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
  	cvm_oct_common_uninit(dev);
  
  	/*
  	 * Only true RGMII ports need to be polled. In GMII mode, port
  	 * 0 is really a RGMII port.
  	 */
  	if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
  	     && (priv->port == 0))
  	    || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
  
  		if (!octeon_is_simulation()) {
  
  			union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
  			int interface = INTERFACE(priv->port);
  			int index = INDEX(priv->port);
  
  			/*
  			 * Disable interrupts on inband status changes
  			 * for this port.
  			 */
  			gmx_rx_int_en.u64 =
  			    cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
  					  (index, interface));
  			gmx_rx_int_en.s.phy_dupx = 0;
  			gmx_rx_int_en.s.phy_link = 0;
  			gmx_rx_int_en.s.phy_spd = 0;
  			cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
  				       gmx_rx_int_en.u64);
  		}
  	}
  
  	/* Remove the interrupt handler when the last port is removed. */
  	number_rgmii_ports--;
  	if (number_rgmii_ports == 0)
  		free_irq(OCTEON_IRQ_RML, &number_rgmii_ports);
f8c264866   David Daney   Staging: Octeon: ...
445
  	cancel_work_sync(&priv->port_work);
80ff0fd3a   David Daney   Staging: Add octe...
446
  }