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$
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
83 static int octe_probe(device_t);
84 static int octe_attach(device_t);
85 static int octe_detach(device_t);
86 static int octe_shutdown(device_t);
87
88 static int octe_miibus_readreg(device_t, int, int);
89 static int octe_miibus_writereg(device_t, int, int, int);
90
91 static void octe_init(void *);
92 static void octe_stop(void *);
93 static int octe_transmit(struct ifnet *, struct mbuf *);
94
95 static int octe_mii_medchange(struct ifnet *);
96 static void octe_mii_medstat(struct ifnet *, struct ifmediareq *);
97
98 static int octe_medchange(struct ifnet *);
99 static void octe_medstat(struct ifnet *, struct ifmediareq *);
100
101 static int octe_ioctl(struct ifnet *, u_long, caddr_t);
102
103 static 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
117 static driver_t octe_driver = {
118 "octe",
119 octe_methods,
120 sizeof (cvm_oct_private_t),
121 };
122
123 static devclass_t octe_devclass;
124
125 DRIVER_MODULE(octe, octebus, octe_driver, octe_devclass, 0, 0);
126 DRIVER_MODULE(miibus, octe, miibus_driver, miibus_devclass, 0, 0);
127
128 static int
129 octe_probe(device_t dev)
130 {
131 return (0);
132 }
133
134 static int
135 octe_attach(device_t dev)
136 {
137 struct ifnet *ifp;
138 cvm_oct_private_t *priv;
139 device_t child;
140 unsigned qos;
141 int error;
142
143 priv = device_get_softc(dev);
144 ifp = priv->ifp;
145
146 if_initname(ifp, device_get_name(dev), device_get_unit(dev));
147
148 if (priv->phy_id != -1) {
149 if (priv->phy_device == NULL) {
150 error = mii_attach(dev, &priv->miibus, ifp,
151 octe_mii_medchange, octe_mii_medstat,
152 BMSR_DEFCAPMASK, priv->phy_id, MII_OFFSET_ANY, 0);
153 if (error != 0)
154 device_printf(dev, "attaching PHYs failed\n");
155 } else {
156 child = device_add_child(dev, priv->phy_device, -1);
157 if (child == NULL)
158 device_printf(dev, "missing phy %u device %s\n", priv->phy_id, priv->phy_device);
159 }
160 }
161
162 if (priv->miibus == NULL) {
163 ifmedia_init(&priv->media, 0, octe_medchange, octe_medstat);
164
165 ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL);
166 ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO);
167 }
168
169 /*
170 * XXX
171 * We don't support programming the multicast filter right now, although it
172 * ought to be easy enough. (Presumably it's just a matter of putting
173 * multicast addresses in the CAM?)
174 */
175 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_ALLMULTI;
176 ifp->if_init = octe_init;
177 ifp->if_ioctl = octe_ioctl;
178
179 priv->if_flags = ifp->if_flags;
180
181 mtx_init(&priv->tx_mtx, ifp->if_xname, "octe tx send queue", MTX_DEF);
182
183 for (qos = 0; qos < 16; qos++) {
184 mtx_init(&priv->tx_free_queue[qos].ifq_mtx, ifp->if_xname, "octe tx free queue", MTX_DEF);
185 IFQ_SET_MAXLEN(&priv->tx_free_queue[qos], MAX_OUT_QUEUE_DEPTH);
186 }
187
188 ether_ifattach(ifp, priv->mac);
189
190 ifp->if_transmit = octe_transmit;
191
192 ifp->if_hdrlen = sizeof(struct ether_vlan_header);
193 ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_HWCSUM;
194 ifp->if_capenable = ifp->if_capabilities;
195 ifp->if_hwassist = CSUM_TCP | CSUM_UDP;
196
197 OCTE_TX_LOCK(priv);
198 IFQ_SET_MAXLEN(&ifp->if_snd, MAX_OUT_QUEUE_DEPTH);
199 ifp->if_snd.ifq_drv_maxlen = MAX_OUT_QUEUE_DEPTH;
200 IFQ_SET_READY(&ifp->if_snd);
201 OCTE_TX_UNLOCK(priv);
202
203 return (bus_generic_attach(dev));
204 }
205
206 static int
207 octe_detach(device_t dev)
208 {
209 return (0);
210 }
211
212 static int
213 octe_shutdown(device_t dev)
214 {
215 return (octe_detach(dev));
216 }
217
218 static int
219 octe_miibus_readreg(device_t dev, int phy, int reg)
220 {
221 cvm_oct_private_t *priv;
222
223 priv = device_get_softc(dev);
224
225 /*
226 * Try interface-specific MII routine.
227 */
228 if (priv->mdio_read != NULL)
229 return (priv->mdio_read(priv->ifp, phy, reg));
230
231 /*
232 * Try generic MII routine.
233 */
234 KASSERT(phy == priv->phy_id,
235 ("read from phy %u but our phy is %u", phy, priv->phy_id));
236 return (cvm_oct_mdio_read(priv->ifp, phy, reg));
237 }
238
239 static int
240 octe_miibus_writereg(device_t dev, int phy, int reg, int val)
241 {
242 cvm_oct_private_t *priv;
243
244 priv = device_get_softc(dev);
245
246 /*
247 * Try interface-specific MII routine.
248 */
249 if (priv->mdio_write != NULL) {
250 priv->mdio_write(priv->ifp, phy, reg, val);
251 return (0);
252 }
253
254 /*
255 * Try generic MII routine.
256 */
257 KASSERT(phy == priv->phy_id,
258 ("write to phy %u but our phy is %u", phy, priv->phy_id));
259 cvm_oct_mdio_write(priv->ifp, phy, reg, val);
260
261 return (0);
262 }
263
264 static void
265 octe_init(void *arg)
266 {
267 struct ifnet *ifp;
268 cvm_oct_private_t *priv;
269
270 priv = arg;
271 ifp = priv->ifp;
272
273 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
274 octe_stop(priv);
275
276 if (priv->open != NULL)
277 priv->open(ifp);
278
279 if (((ifp->if_flags ^ priv->if_flags) & (IFF_ALLMULTI | IFF_MULTICAST | IFF_PROMISC)) != 0)
280 cvm_oct_common_set_multicast_list(ifp);
281
282 cvm_oct_common_set_mac_address(ifp, IF_LLADDR(ifp));
283
284 cvm_oct_common_poll(ifp);
285
286 if (priv->miibus != NULL)
287 mii_mediachg(device_get_softc(priv->miibus));
288
289 ifp->if_drv_flags |= IFF_DRV_RUNNING;
290 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
291 }
292
293 static void
294 octe_stop(void *arg)
295 {
296 struct ifnet *ifp;
297 cvm_oct_private_t *priv;
298
299 priv = arg;
300 ifp = priv->ifp;
301
302 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
303 return;
304
305 if (priv->stop != NULL)
306 priv->stop(ifp);
307
308 ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
309 }
310
311 static int
312 octe_transmit(struct ifnet *ifp, struct mbuf *m)
313 {
314 cvm_oct_private_t *priv;
315
316 priv = ifp->if_softc;
317
318 if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
319 IFF_DRV_RUNNING) {
320 m_freem(m);
321 return (0);
322 }
323
324 return (cvm_oct_xmit(m, ifp));
325 }
326
327 static int
328 octe_mii_medchange(struct ifnet *ifp)
329 {
330 cvm_oct_private_t *priv;
331 struct mii_data *mii;
332 struct mii_softc *miisc;
333
334 priv = ifp->if_softc;
335 mii = device_get_softc(priv->miibus);
336 LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
337 PHY_RESET(miisc);
338 mii_mediachg(mii);
339
340 return (0);
341 }
342
343 static void
344 octe_mii_medstat(struct ifnet *ifp, struct ifmediareq *ifm)
345 {
346 cvm_oct_private_t *priv;
347 struct mii_data *mii;
348
349 priv = ifp->if_softc;
350 mii = device_get_softc(priv->miibus);
351
352 mii_pollstat(mii);
353 ifm->ifm_active = mii->mii_media_active;
354 ifm->ifm_status = mii->mii_media_status;
355 }
356
357 static int
358 octe_medchange(struct ifnet *ifp)
359 {
360 return (ENOTSUP);
361 }
362
363 static void
364 octe_medstat(struct ifnet *ifp, struct ifmediareq *ifm)
365 {
366 cvm_oct_private_t *priv;
367 cvmx_helper_link_info_t link_info;
368
369 priv = ifp->if_softc;
370
371 ifm->ifm_status = IFM_AVALID;
372 ifm->ifm_active = IFT_ETHER;
373
374 if (priv->poll == NULL)
375 return;
376 priv->poll(ifp);
377
378 link_info.u64 = priv->link_info;
379
380 if (!link_info.s.link_up)
381 return;
382
383 ifm->ifm_status |= IFM_ACTIVE;
384
385 switch (link_info.s.speed) {
386 case 10:
387 ifm->ifm_active |= IFM_10_T;
388 break;
389 case 100:
390 ifm->ifm_active |= IFM_100_TX;
391 break;
392 case 1000:
393 ifm->ifm_active |= IFM_1000_T;
394 break;
395 case 10000:
396 ifm->ifm_active |= IFM_10G_T;
397 break;
398 }
399
400 if (link_info.s.full_duplex)
401 ifm->ifm_active |= IFM_FDX;
402 else
403 ifm->ifm_active |= IFM_HDX;
404 }
405
406 static int
407 octe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
408 {
409 cvm_oct_private_t *priv;
410 struct mii_data *mii;
411 struct ifreq *ifr;
412 #ifdef INET
413 struct ifaddr *ifa;
414 #endif
415 int error;
416
417 priv = ifp->if_softc;
418 ifr = (struct ifreq *)data;
419 #ifdef INET
420 ifa = (struct ifaddr *)data;
421 #endif
422
423 switch (cmd) {
424 case SIOCSIFADDR:
425 #ifdef INET
426 /*
427 * Avoid reinitialization unless it's necessary.
428 */
429 if (ifa->ifa_addr->sa_family == AF_INET) {
430 ifp->if_flags |= IFF_UP;
431 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
432 octe_init(priv);
433 arp_ifinit(ifp, ifa);
434
435 return (0);
436 }
437 #endif
438 error = ether_ioctl(ifp, cmd, data);
439 if (error != 0)
440 return (error);
441 return (0);
442
443 case SIOCSIFFLAGS:
444 if (ifp->if_flags == priv->if_flags)
445 return (0);
446 if ((ifp->if_flags & IFF_UP) != 0) {
447 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
448 octe_init(priv);
449 } else {
450 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
451 octe_stop(priv);
452 }
453 priv->if_flags = ifp->if_flags;
454 return (0);
455
456 case SIOCSIFCAP:
457 /*
458 * Just change the capabilities in software, currently none
459 * require reprogramming hardware, they just toggle whether we
460 * make use of already-present facilities in software.
461 */
462 ifp->if_capenable = ifr->ifr_reqcap;
463 return (0);
464
465 case SIOCSIFMTU:
466 error = cvm_oct_common_change_mtu(ifp, ifr->ifr_mtu);
467 if (error != 0)
468 return (EINVAL);
469 return (0);
470
471 case SIOCSIFMEDIA:
472 case SIOCGIFMEDIA:
473 if (priv->miibus != NULL) {
474 mii = device_get_softc(priv->miibus);
475 error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
476 if (error != 0)
477 return (error);
478 return (0);
479 }
480 error = ifmedia_ioctl(ifp, ifr, &priv->media, cmd);
481 if (error != 0)
482 return (error);
483 return (0);
484
485 default:
486 error = ether_ioctl(ifp, cmd, data);
487 if (error != 0)
488 return (error);
489 return (0);
490 }
491 }
Cache object: 9f534eb1e41d4e7945451cf33a8b3bc3
|