Deleted Added
full compact
octe.c (213156) octe.c (213346)
1/*-
2 * Copyright (c) 2010 Juli Mallett <jmallett@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
1/*-
2 * Copyright (c) 2010 Juli Mallett <jmallett@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/mips/cavium/octe/octe.c 213156 2010-09-25 04:39:12Z jmallett $
26 * $FreeBSD: head/sys/mips/cavium/octe/octe.c 213346 2010-10-02 05:43:17Z jmallett $
27 */
28
29/*
30 * Cavium Octeon Ethernet devices.
31 *
32 * XXX This file should be moved to if_octe.c
33 * XXX The driver may have sufficient locking but we need locking to protect
34 * the interfaces presented here, right?
35 */
36
37#include "opt_inet.h"
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/bus.h>
42#include <sys/endian.h>
43#include <sys/kernel.h>
44#include <sys/mbuf.h>
45#include <sys/lock.h>
46#include <sys/module.h>
47#include <sys/mutex.h>
48#include <sys/rman.h>
49#include <sys/socket.h>
50#include <sys/sockio.h>
51#include <sys/sysctl.h>
52
53#include <net/bpf.h>
54#include <net/ethernet.h>
55#include <net/if.h>
56#include <net/if_dl.h>
57#include <net/if_media.h>
58#include <net/if_types.h>
59#include <net/if_var.h>
60#include <net/if_vlan_var.h>
61
62#ifdef INET
63#include <netinet/in.h>
64#include <netinet/if_ether.h>
65#endif
66
67#include <dev/mii/mii.h>
68#include <dev/mii/miivar.h>
69
70#include "wrapper-cvmx-includes.h"
71#include "cavium-ethernet.h"
72
73#include "ethernet-common.h"
74#include "ethernet-defines.h"
75#include "ethernet-mdio.h"
76#include "ethernet-tx.h"
77
78#include "miibus_if.h"
79
80#define OCTE_TX_LOCK(priv) mtx_lock(&(priv)->tx_mtx)
81#define OCTE_TX_UNLOCK(priv) mtx_unlock(&(priv)->tx_mtx)
82
83static int octe_probe(device_t);
84static int octe_attach(device_t);
85static int octe_detach(device_t);
86static int octe_shutdown(device_t);
87
88static int octe_miibus_readreg(device_t, int, int);
89static int octe_miibus_writereg(device_t, int, int, int);
90
91static void octe_init(void *);
92static void octe_stop(void *);
93static void octe_start(struct ifnet *);
94
95static int octe_mii_medchange(struct ifnet *);
96static void octe_mii_medstat(struct ifnet *, struct ifmediareq *);
97
98static int octe_medchange(struct ifnet *);
99static void octe_medstat(struct ifnet *, struct ifmediareq *);
100
101static int octe_ioctl(struct ifnet *, u_long, caddr_t);
102
103static device_method_t octe_methods[] = {
104 /* Device interface */
105 DEVMETHOD(device_probe, octe_probe),
106 DEVMETHOD(device_attach, octe_attach),
107 DEVMETHOD(device_detach, octe_detach),
108 DEVMETHOD(device_shutdown, octe_shutdown),
109
110 /* MII interface */
111 DEVMETHOD(miibus_readreg, octe_miibus_readreg),
112 DEVMETHOD(miibus_writereg, octe_miibus_writereg),
113
114 { 0, 0 }
115};
116
117static driver_t octe_driver = {
118 "octe",
119 octe_methods,
120 sizeof (cvm_oct_private_t),
121};
122
123static devclass_t octe_devclass;
124
125DRIVER_MODULE(octe, octebus, octe_driver, octe_devclass, 0, 0);
126DRIVER_MODULE(miibus, octe, miibus_driver, miibus_devclass, 0, 0);
127
128static driver_t pow_driver = {
129 "pow",
130 octe_methods,
131 sizeof (cvm_oct_private_t),
132};
133
134static devclass_t pow_devclass;
135
136DRIVER_MODULE(pow, octebus, pow_driver, pow_devclass, 0, 0);
137
138static int
139octe_probe(device_t dev)
140{
141 return (0);
142}
143
144static int
145octe_attach(device_t dev)
146{
147 struct ifnet *ifp;
148 cvm_oct_private_t *priv;
149 unsigned qos;
150 int error;
151
152 priv = device_get_softc(dev);
153 ifp = priv->ifp;
154
155 if_initname(ifp, device_get_name(dev), device_get_unit(dev));
156
157 if (priv->phy_id != -1) {
158 error = mii_phy_probe(dev, &priv->miibus, octe_mii_medchange,
159 octe_mii_medstat);
160 if (error != 0) {
161 device_printf(dev, "missing phy %u\n", priv->phy_id);
162 }
163 }
164
165 if (priv->miibus == NULL) {
166 ifmedia_init(&priv->media, 0, octe_medchange, octe_medstat);
167
168 ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL);
169 ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO);
170 }
171
172 /*
173 * XXX
174 * We don't support programming the multicast filter right now, although it
175 * ought to be easy enough. (Presumably it's just a matter of putting
176 * multicast addresses in the CAM?)
177 */
178 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_ALLMULTI;
179 ifp->if_init = octe_init;
180 ifp->if_ioctl = octe_ioctl;
181 ifp->if_start = octe_start;
182
183 priv->if_flags = ifp->if_flags;
184
185 mtx_init(&priv->tx_mtx, ifp->if_xname, "octe tx send queue", MTX_DEF);
186
187 for (qos = 0; qos < 16; qos++) {
188 mtx_init(&priv->tx_free_queue[qos].ifq_mtx, ifp->if_xname, "octe tx free queue", MTX_DEF);
189 IFQ_SET_MAXLEN(&priv->tx_free_queue[qos], MAX_OUT_QUEUE_DEPTH);
190 }
191
192 ether_ifattach(ifp, priv->mac);
193
194 ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
195 ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_HWCSUM;
196 ifp->if_capenable = ifp->if_capabilities;
197 ifp->if_hwassist = CSUM_TCP | CSUM_UDP;
198
199 OCTE_TX_LOCK(priv);
200 IFQ_SET_MAXLEN(&ifp->if_snd, MAX_OUT_QUEUE_DEPTH);
201 ifp->if_snd.ifq_drv_maxlen = MAX_OUT_QUEUE_DEPTH;
202 IFQ_SET_READY(&ifp->if_snd);
203 OCTE_TX_UNLOCK(priv);
204
205 return (0);
206}
207
208static int
209octe_detach(device_t dev)
210{
211 return (0);
212}
213
214static int
215octe_shutdown(device_t dev)
216{
217 return (octe_detach(dev));
218}
219
220static int
221octe_miibus_readreg(device_t dev, int phy, int reg)
222{
223 cvm_oct_private_t *priv;
224
225 priv = device_get_softc(dev);
226
27 */
28
29/*
30 * Cavium Octeon Ethernet devices.
31 *
32 * XXX This file should be moved to if_octe.c
33 * XXX The driver may have sufficient locking but we need locking to protect
34 * the interfaces presented here, right?
35 */
36
37#include "opt_inet.h"
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/bus.h>
42#include <sys/endian.h>
43#include <sys/kernel.h>
44#include <sys/mbuf.h>
45#include <sys/lock.h>
46#include <sys/module.h>
47#include <sys/mutex.h>
48#include <sys/rman.h>
49#include <sys/socket.h>
50#include <sys/sockio.h>
51#include <sys/sysctl.h>
52
53#include <net/bpf.h>
54#include <net/ethernet.h>
55#include <net/if.h>
56#include <net/if_dl.h>
57#include <net/if_media.h>
58#include <net/if_types.h>
59#include <net/if_var.h>
60#include <net/if_vlan_var.h>
61
62#ifdef INET
63#include <netinet/in.h>
64#include <netinet/if_ether.h>
65#endif
66
67#include <dev/mii/mii.h>
68#include <dev/mii/miivar.h>
69
70#include "wrapper-cvmx-includes.h"
71#include "cavium-ethernet.h"
72
73#include "ethernet-common.h"
74#include "ethernet-defines.h"
75#include "ethernet-mdio.h"
76#include "ethernet-tx.h"
77
78#include "miibus_if.h"
79
80#define OCTE_TX_LOCK(priv) mtx_lock(&(priv)->tx_mtx)
81#define OCTE_TX_UNLOCK(priv) mtx_unlock(&(priv)->tx_mtx)
82
83static int octe_probe(device_t);
84static int octe_attach(device_t);
85static int octe_detach(device_t);
86static int octe_shutdown(device_t);
87
88static int octe_miibus_readreg(device_t, int, int);
89static int octe_miibus_writereg(device_t, int, int, int);
90
91static void octe_init(void *);
92static void octe_stop(void *);
93static void octe_start(struct ifnet *);
94
95static int octe_mii_medchange(struct ifnet *);
96static void octe_mii_medstat(struct ifnet *, struct ifmediareq *);
97
98static int octe_medchange(struct ifnet *);
99static void octe_medstat(struct ifnet *, struct ifmediareq *);
100
101static int octe_ioctl(struct ifnet *, u_long, caddr_t);
102
103static device_method_t octe_methods[] = {
104 /* Device interface */
105 DEVMETHOD(device_probe, octe_probe),
106 DEVMETHOD(device_attach, octe_attach),
107 DEVMETHOD(device_detach, octe_detach),
108 DEVMETHOD(device_shutdown, octe_shutdown),
109
110 /* MII interface */
111 DEVMETHOD(miibus_readreg, octe_miibus_readreg),
112 DEVMETHOD(miibus_writereg, octe_miibus_writereg),
113
114 { 0, 0 }
115};
116
117static driver_t octe_driver = {
118 "octe",
119 octe_methods,
120 sizeof (cvm_oct_private_t),
121};
122
123static devclass_t octe_devclass;
124
125DRIVER_MODULE(octe, octebus, octe_driver, octe_devclass, 0, 0);
126DRIVER_MODULE(miibus, octe, miibus_driver, miibus_devclass, 0, 0);
127
128static driver_t pow_driver = {
129 "pow",
130 octe_methods,
131 sizeof (cvm_oct_private_t),
132};
133
134static devclass_t pow_devclass;
135
136DRIVER_MODULE(pow, octebus, pow_driver, pow_devclass, 0, 0);
137
138static int
139octe_probe(device_t dev)
140{
141 return (0);
142}
143
144static int
145octe_attach(device_t dev)
146{
147 struct ifnet *ifp;
148 cvm_oct_private_t *priv;
149 unsigned qos;
150 int error;
151
152 priv = device_get_softc(dev);
153 ifp = priv->ifp;
154
155 if_initname(ifp, device_get_name(dev), device_get_unit(dev));
156
157 if (priv->phy_id != -1) {
158 error = mii_phy_probe(dev, &priv->miibus, octe_mii_medchange,
159 octe_mii_medstat);
160 if (error != 0) {
161 device_printf(dev, "missing phy %u\n", priv->phy_id);
162 }
163 }
164
165 if (priv->miibus == NULL) {
166 ifmedia_init(&priv->media, 0, octe_medchange, octe_medstat);
167
168 ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL);
169 ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO);
170 }
171
172 /*
173 * XXX
174 * We don't support programming the multicast filter right now, although it
175 * ought to be easy enough. (Presumably it's just a matter of putting
176 * multicast addresses in the CAM?)
177 */
178 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_ALLMULTI;
179 ifp->if_init = octe_init;
180 ifp->if_ioctl = octe_ioctl;
181 ifp->if_start = octe_start;
182
183 priv->if_flags = ifp->if_flags;
184
185 mtx_init(&priv->tx_mtx, ifp->if_xname, "octe tx send queue", MTX_DEF);
186
187 for (qos = 0; qos < 16; qos++) {
188 mtx_init(&priv->tx_free_queue[qos].ifq_mtx, ifp->if_xname, "octe tx free queue", MTX_DEF);
189 IFQ_SET_MAXLEN(&priv->tx_free_queue[qos], MAX_OUT_QUEUE_DEPTH);
190 }
191
192 ether_ifattach(ifp, priv->mac);
193
194 ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
195 ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_HWCSUM;
196 ifp->if_capenable = ifp->if_capabilities;
197 ifp->if_hwassist = CSUM_TCP | CSUM_UDP;
198
199 OCTE_TX_LOCK(priv);
200 IFQ_SET_MAXLEN(&ifp->if_snd, MAX_OUT_QUEUE_DEPTH);
201 ifp->if_snd.ifq_drv_maxlen = MAX_OUT_QUEUE_DEPTH;
202 IFQ_SET_READY(&ifp->if_snd);
203 OCTE_TX_UNLOCK(priv);
204
205 return (0);
206}
207
208static int
209octe_detach(device_t dev)
210{
211 return (0);
212}
213
214static int
215octe_shutdown(device_t dev)
216{
217 return (octe_detach(dev));
218}
219
220static int
221octe_miibus_readreg(device_t dev, int phy, int reg)
222{
223 cvm_oct_private_t *priv;
224
225 priv = device_get_softc(dev);
226
227 /*
228 * Try interface-specific MII routine.
229 */
230 if (priv->mdio_read != NULL)
231 return (priv->mdio_read(priv->ifp, phy, reg));
232
233 /*
234 * Try generic MII routine.
235 */
227 if (phy != priv->phy_id)
228 return (0);
229
230 return (cvm_oct_mdio_read(priv->ifp, phy, reg));
231}
232
233static int
234octe_miibus_writereg(device_t dev, int phy, int reg, int val)
235{
236 cvm_oct_private_t *priv;
237
238 priv = device_get_softc(dev);
239
236 if (phy != priv->phy_id)
237 return (0);
238
239 return (cvm_oct_mdio_read(priv->ifp, phy, reg));
240}
241
242static int
243octe_miibus_writereg(device_t dev, int phy, int reg, int val)
244{
245 cvm_oct_private_t *priv;
246
247 priv = device_get_softc(dev);
248
249 /*
250 * Try interface-specific MII routine.
251 */
252 if (priv->mdio_write != NULL) {
253 priv->mdio_write(priv->ifp, phy, reg, val);
254 return (0);
255 }
256
257 /*
258 * Try generic MII routine.
259 */
240 KASSERT(phy == priv->phy_id,
241 ("write to phy %u but our phy is %u", phy, priv->phy_id));
260 KASSERT(phy == priv->phy_id,
261 ("write to phy %u but our phy is %u", phy, priv->phy_id));
242
243 cvm_oct_mdio_write(priv->ifp, phy, reg, val);
244
245 return (0);
246}
247
248static void
249octe_init(void *arg)
250{
251 struct ifnet *ifp;
252 cvm_oct_private_t *priv;
253
254 priv = arg;
255 ifp = priv->ifp;
256
257 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
258 octe_stop(priv);
259
260 if (priv->open != NULL)
261 priv->open(ifp);
262
263 if (((ifp->if_flags ^ priv->if_flags) & (IFF_ALLMULTI | IFF_MULTICAST | IFF_PROMISC)) != 0)
264 cvm_oct_common_set_multicast_list(ifp);
265
266 cvm_oct_common_set_mac_address(ifp, IF_LLADDR(ifp));
267
268 if (priv->poll != NULL)
269 priv->poll(ifp);
270 if (priv->miibus != NULL)
271 mii_mediachg(device_get_softc(priv->miibus));
272
273 ifp->if_drv_flags |= IFF_DRV_RUNNING;
274 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
275}
276
277static void
278octe_stop(void *arg)
279{
280 struct ifnet *ifp;
281 cvm_oct_private_t *priv;
282
283 priv = arg;
284 ifp = priv->ifp;
285
286 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
287 return;
288
289 if (priv->stop != NULL)
290 priv->stop(ifp);
291
292 ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
293}
294
295static void
296octe_start(struct ifnet *ifp)
297{
298 cvm_oct_private_t *priv;
299 struct mbuf *m;
300 int error;
301
302 priv = ifp->if_softc;
303
304 if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING)
305 return;
306
307 OCTE_TX_LOCK(priv);
308 while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
309 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
310
311 OCTE_TX_UNLOCK(priv);
312
313 if (priv->queue != -1) {
314 error = cvm_oct_xmit(m, ifp);
315 } else {
316 error = cvm_oct_xmit_pow(m, ifp);
317 }
318
319 if (error != 0) {
320 ifp->if_drv_flags |= IFF_DRV_OACTIVE;
321 return;
322 }
323
324 OCTE_TX_LOCK(priv);
325 }
326 OCTE_TX_UNLOCK(priv);
327}
328
329static int
330octe_mii_medchange(struct ifnet *ifp)
331{
332 cvm_oct_private_t *priv;
333 struct mii_data *mii;
334
335 priv = ifp->if_softc;
336 mii = device_get_softc(priv->miibus);
337
338 if (mii->mii_instance) {
339 struct mii_softc *miisc;
340
341 LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
342 mii_phy_reset(miisc);
343 }
344 mii_mediachg(mii);
345
346 return (0);
347}
348
349static void
350octe_mii_medstat(struct ifnet *ifp, struct ifmediareq *ifm)
351{
352 cvm_oct_private_t *priv;
353 struct mii_data *mii;
354
355 priv = ifp->if_softc;
356 mii = device_get_softc(priv->miibus);
357
358 mii_pollstat(mii);
359 ifm->ifm_active = mii->mii_media_active;
360 ifm->ifm_status = mii->mii_media_status;
361}
362
363static int
364octe_medchange(struct ifnet *ifp)
365{
366 return (ENOTSUP);
367}
368
369static void
370octe_medstat(struct ifnet *ifp, struct ifmediareq *ifm)
371{
372 cvm_oct_private_t *priv;
373 cvmx_helper_link_info_t link_info;
374
375 priv = ifp->if_softc;
376
377 ifm->ifm_status = IFM_AVALID;
378 ifm->ifm_active = IFT_ETHER;
379
380 if (priv->poll == NULL)
381 return;
382 priv->poll(ifp);
383
384 link_info.u64 = priv->link_info;
385
386 if (!link_info.s.link_up)
387 return;
388
389 ifm->ifm_status |= IFM_ACTIVE;
390
391 switch (link_info.s.speed) {
392 case 10:
393 ifm->ifm_active |= IFM_10_T;
394 break;
395 case 100:
396 ifm->ifm_active |= IFM_100_TX;
397 break;
398 case 1000:
399 ifm->ifm_active |= IFM_1000_T;
400 break;
401 case 10000:
402 ifm->ifm_active |= IFM_10G_T;
403 break;
404 }
405
406 if (link_info.s.full_duplex)
407 ifm->ifm_active |= IFM_FDX;
408 else
409 ifm->ifm_active |= IFM_HDX;
410}
411
412static int
413octe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
414{
415 cvm_oct_private_t *priv;
416 struct mii_data *mii;
417 struct ifreq *ifr;
418#ifdef INET
419 struct ifaddr *ifa;
420#endif
421 int error;
422
423 priv = ifp->if_softc;
424 ifr = (struct ifreq *)data;
425#ifdef INET
426 ifa = (struct ifaddr *)data;
427#endif
428
429 switch (cmd) {
430 case SIOCSIFADDR:
431#ifdef INET
432 /*
433 * Avoid reinitialization unless it's necessary.
434 */
435 if (ifa->ifa_addr->sa_family == AF_INET) {
436 ifp->if_flags |= IFF_UP;
437 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
438 octe_init(priv);
439 arp_ifinit(ifp, ifa);
440
441 return (0);
442 }
443#endif
444 error = ether_ioctl(ifp, cmd, data);
445 if (error != 0)
446 return (error);
447 return (0);
448
449 case SIOCSIFFLAGS:
450 if (ifp->if_flags == priv->if_flags)
451 return (0);
452 if ((ifp->if_flags & IFF_UP) != 0) {
453 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
454 octe_init(priv);
455 } else {
456 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
457 octe_stop(priv);
458 }
459 priv->if_flags = ifp->if_flags;
460 return (0);
461
462 case SIOCSIFCAP:
463 /*
464 * Just change the capabilities in software, currently none
465 * require reprogramming hardware, they just toggle whether we
466 * make use of already-present facilities in software.
467 */
468 ifp->if_capenable = ifr->ifr_reqcap;
469 return (0);
470
471 case SIOCSIFMTU:
472 error = cvm_oct_common_change_mtu(ifp, ifr->ifr_mtu);
473 if (error != 0)
474 return (EINVAL);
475 return (0);
476
477 case SIOCSIFMEDIA:
478 case SIOCGIFMEDIA:
479 if (priv->miibus != NULL) {
480 mii = device_get_softc(priv->miibus);
481 error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
482 if (error != 0)
483 return (error);
484 return (0);
485 }
486 error = ifmedia_ioctl(ifp, ifr, &priv->media, cmd);
487 if (error != 0)
488 return (error);
489 return (0);
490
491 default:
492 error = ether_ioctl(ifp, cmd, data);
493 if (error != 0)
494 return (error);
495 return (0);
496 }
497}
262 cvm_oct_mdio_write(priv->ifp, phy, reg, val);
263
264 return (0);
265}
266
267static void
268octe_init(void *arg)
269{
270 struct ifnet *ifp;
271 cvm_oct_private_t *priv;
272
273 priv = arg;
274 ifp = priv->ifp;
275
276 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
277 octe_stop(priv);
278
279 if (priv->open != NULL)
280 priv->open(ifp);
281
282 if (((ifp->if_flags ^ priv->if_flags) & (IFF_ALLMULTI | IFF_MULTICAST | IFF_PROMISC)) != 0)
283 cvm_oct_common_set_multicast_list(ifp);
284
285 cvm_oct_common_set_mac_address(ifp, IF_LLADDR(ifp));
286
287 if (priv->poll != NULL)
288 priv->poll(ifp);
289 if (priv->miibus != NULL)
290 mii_mediachg(device_get_softc(priv->miibus));
291
292 ifp->if_drv_flags |= IFF_DRV_RUNNING;
293 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
294}
295
296static void
297octe_stop(void *arg)
298{
299 struct ifnet *ifp;
300 cvm_oct_private_t *priv;
301
302 priv = arg;
303 ifp = priv->ifp;
304
305 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
306 return;
307
308 if (priv->stop != NULL)
309 priv->stop(ifp);
310
311 ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
312}
313
314static void
315octe_start(struct ifnet *ifp)
316{
317 cvm_oct_private_t *priv;
318 struct mbuf *m;
319 int error;
320
321 priv = ifp->if_softc;
322
323 if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING)
324 return;
325
326 OCTE_TX_LOCK(priv);
327 while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
328 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
329
330 OCTE_TX_UNLOCK(priv);
331
332 if (priv->queue != -1) {
333 error = cvm_oct_xmit(m, ifp);
334 } else {
335 error = cvm_oct_xmit_pow(m, ifp);
336 }
337
338 if (error != 0) {
339 ifp->if_drv_flags |= IFF_DRV_OACTIVE;
340 return;
341 }
342
343 OCTE_TX_LOCK(priv);
344 }
345 OCTE_TX_UNLOCK(priv);
346}
347
348static int
349octe_mii_medchange(struct ifnet *ifp)
350{
351 cvm_oct_private_t *priv;
352 struct mii_data *mii;
353
354 priv = ifp->if_softc;
355 mii = device_get_softc(priv->miibus);
356
357 if (mii->mii_instance) {
358 struct mii_softc *miisc;
359
360 LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
361 mii_phy_reset(miisc);
362 }
363 mii_mediachg(mii);
364
365 return (0);
366}
367
368static void
369octe_mii_medstat(struct ifnet *ifp, struct ifmediareq *ifm)
370{
371 cvm_oct_private_t *priv;
372 struct mii_data *mii;
373
374 priv = ifp->if_softc;
375 mii = device_get_softc(priv->miibus);
376
377 mii_pollstat(mii);
378 ifm->ifm_active = mii->mii_media_active;
379 ifm->ifm_status = mii->mii_media_status;
380}
381
382static int
383octe_medchange(struct ifnet *ifp)
384{
385 return (ENOTSUP);
386}
387
388static void
389octe_medstat(struct ifnet *ifp, struct ifmediareq *ifm)
390{
391 cvm_oct_private_t *priv;
392 cvmx_helper_link_info_t link_info;
393
394 priv = ifp->if_softc;
395
396 ifm->ifm_status = IFM_AVALID;
397 ifm->ifm_active = IFT_ETHER;
398
399 if (priv->poll == NULL)
400 return;
401 priv->poll(ifp);
402
403 link_info.u64 = priv->link_info;
404
405 if (!link_info.s.link_up)
406 return;
407
408 ifm->ifm_status |= IFM_ACTIVE;
409
410 switch (link_info.s.speed) {
411 case 10:
412 ifm->ifm_active |= IFM_10_T;
413 break;
414 case 100:
415 ifm->ifm_active |= IFM_100_TX;
416 break;
417 case 1000:
418 ifm->ifm_active |= IFM_1000_T;
419 break;
420 case 10000:
421 ifm->ifm_active |= IFM_10G_T;
422 break;
423 }
424
425 if (link_info.s.full_duplex)
426 ifm->ifm_active |= IFM_FDX;
427 else
428 ifm->ifm_active |= IFM_HDX;
429}
430
431static int
432octe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
433{
434 cvm_oct_private_t *priv;
435 struct mii_data *mii;
436 struct ifreq *ifr;
437#ifdef INET
438 struct ifaddr *ifa;
439#endif
440 int error;
441
442 priv = ifp->if_softc;
443 ifr = (struct ifreq *)data;
444#ifdef INET
445 ifa = (struct ifaddr *)data;
446#endif
447
448 switch (cmd) {
449 case SIOCSIFADDR:
450#ifdef INET
451 /*
452 * Avoid reinitialization unless it's necessary.
453 */
454 if (ifa->ifa_addr->sa_family == AF_INET) {
455 ifp->if_flags |= IFF_UP;
456 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
457 octe_init(priv);
458 arp_ifinit(ifp, ifa);
459
460 return (0);
461 }
462#endif
463 error = ether_ioctl(ifp, cmd, data);
464 if (error != 0)
465 return (error);
466 return (0);
467
468 case SIOCSIFFLAGS:
469 if (ifp->if_flags == priv->if_flags)
470 return (0);
471 if ((ifp->if_flags & IFF_UP) != 0) {
472 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
473 octe_init(priv);
474 } else {
475 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
476 octe_stop(priv);
477 }
478 priv->if_flags = ifp->if_flags;
479 return (0);
480
481 case SIOCSIFCAP:
482 /*
483 * Just change the capabilities in software, currently none
484 * require reprogramming hardware, they just toggle whether we
485 * make use of already-present facilities in software.
486 */
487 ifp->if_capenable = ifr->ifr_reqcap;
488 return (0);
489
490 case SIOCSIFMTU:
491 error = cvm_oct_common_change_mtu(ifp, ifr->ifr_mtu);
492 if (error != 0)
493 return (EINVAL);
494 return (0);
495
496 case SIOCSIFMEDIA:
497 case SIOCGIFMEDIA:
498 if (priv->miibus != NULL) {
499 mii = device_get_softc(priv->miibus);
500 error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
501 if (error != 0)
502 return (error);
503 return (0);
504 }
505 error = ifmedia_ioctl(ifp, ifr, &priv->media, cmd);
506 if (error != 0)
507 return (error);
508 return (0);
509
510 default:
511 error = ether_ioctl(ifp, cmd, data);
512 if (error != 0)
513 return (error);
514 return (0);
515 }
516}