]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/cavium/octe/octe.c
Update tcpdump to 4.9.2
[FreeBSD/FreeBSD.git] / sys / mips / cavium / octe / octe.c
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 }