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
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 int		octe_transmit(struct ifnet *, struct mbuf *);
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 int
129octe_probe(device_t dev)
130{
131	return (0);
132}
133
134static int
135octe_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_data.ifi_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
206static int
207octe_detach(device_t dev)
208{
209	return (0);
210}
211
212static int
213octe_shutdown(device_t dev)
214{
215	return (octe_detach(dev));
216}
217
218static int
219octe_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
239static int
240octe_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
264static void
265octe_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
293static void
294octe_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
311static int
312octe_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
327static int
328octe_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
343static void
344octe_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
357static int
358octe_medchange(struct ifnet *ifp)
359{
360	return (ENOTSUP);
361}
362
363static void
364octe_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
406static int
407octe_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}
492