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