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