octe.c revision 330897
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: stable/11/sys/mips/cavium/octe/octe.c 330897 2018-03-14 03:19:51Z eadler $
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
85static int		octe_probe(device_t);
86static int		octe_attach(device_t);
87static int		octe_detach(device_t);
88static int		octe_shutdown(device_t);
89
90static int		octe_miibus_readreg(device_t, int, int);
91static int		octe_miibus_writereg(device_t, int, int, int);
92
93static void		octe_init(void *);
94static void		octe_stop(void *);
95static int		octe_transmit(struct ifnet *, struct mbuf *);
96
97static int		octe_mii_medchange(struct ifnet *);
98static void		octe_mii_medstat(struct ifnet *, struct ifmediareq *);
99
100static int		octe_medchange(struct ifnet *);
101static void		octe_medstat(struct ifnet *, struct ifmediareq *);
102
103static int		octe_ioctl(struct ifnet *, u_long, caddr_t);
104
105static 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
119static driver_t octe_driver = {
120	"octe",
121	octe_methods,
122	sizeof (cvm_oct_private_t),
123};
124
125static devclass_t octe_devclass;
126
127DRIVER_MODULE(octe, octebus, octe_driver, octe_devclass, 0, 0);
128DRIVER_MODULE(miibus, octe, miibus_driver, miibus_devclass, 0, 0);
129
130static int
131octe_probe(device_t dev)
132{
133	return (0);
134}
135
136static int
137octe_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
208static int
209octe_detach(device_t dev)
210{
211	return (0);
212}
213
214static int
215octe_shutdown(device_t dev)
216{
217	return (octe_detach(dev));
218}
219
220static int
221octe_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
241static int
242octe_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
266static void
267octe_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
295static void
296octe_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
313static int
314octe_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
329static int
330octe_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
345static void
346octe_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
359static int
360octe_medchange(struct ifnet *ifp)
361{
362	return (ENOTSUP);
363}
364
365static void
366octe_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
408static int
409octe_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}
494