1210311Sjmallett/*-
2210311Sjmallett * Copyright (c) 2010 Juli Mallett <jmallett@FreeBSD.org>
3210311Sjmallett * All rights reserved.
4210311Sjmallett *
5210311Sjmallett * Redistribution and use in source and binary forms, with or without
6210311Sjmallett * modification, are permitted provided that the following conditions
7210311Sjmallett * are met:
8210311Sjmallett * 1. Redistributions of source code must retain the above copyright
9210311Sjmallett *    notice, this list of conditions and the following disclaimer.
10210311Sjmallett * 2. Redistributions in binary form must reproduce the above copyright
11210311Sjmallett *    notice, this list of conditions and the following disclaimer in the
12210311Sjmallett *    documentation and/or other materials provided with the distribution.
13210311Sjmallett *
14210311Sjmallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15210311Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16210311Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17210311Sjmallett * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18210311Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19210311Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20210311Sjmallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21210311Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22210311Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23210311Sjmallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24210311Sjmallett * SUCH DAMAGE.
25210311Sjmallett *
26210311Sjmallett * $FreeBSD$
27210311Sjmallett */
28210311Sjmallett
29210311Sjmallett/*
30210311Sjmallett * Cavium Octeon Ethernet devices.
31210311Sjmallett *
32210311Sjmallett * XXX This file should be moved to if_octe.c
33210311Sjmallett * XXX The driver may have sufficient locking but we need locking to protect
34210311Sjmallett *     the interfaces presented here, right?
35210311Sjmallett */
36210311Sjmallett
37210311Sjmallett#include "opt_inet.h"
38210311Sjmallett
39210311Sjmallett#include <sys/param.h>
40210311Sjmallett#include <sys/systm.h>
41210311Sjmallett#include <sys/bus.h>
42210311Sjmallett#include <sys/endian.h>
43210311Sjmallett#include <sys/kernel.h>
44210311Sjmallett#include <sys/mbuf.h>
45210311Sjmallett#include <sys/lock.h>
46210311Sjmallett#include <sys/module.h>
47210311Sjmallett#include <sys/mutex.h>
48210311Sjmallett#include <sys/rman.h>
49210311Sjmallett#include <sys/socket.h>
50210311Sjmallett#include <sys/sockio.h>
51210311Sjmallett#include <sys/sysctl.h>
52210311Sjmallett
53210311Sjmallett#include <net/bpf.h>
54210311Sjmallett#include <net/ethernet.h>
55210311Sjmallett#include <net/if.h>
56210311Sjmallett#include <net/if_dl.h>
57210311Sjmallett#include <net/if_media.h>
58210311Sjmallett#include <net/if_types.h>
59210311Sjmallett#include <net/if_var.h>
60210311Sjmallett#include <net/if_vlan_var.h>
61210311Sjmallett
62210311Sjmallett#ifdef INET
63210311Sjmallett#include <netinet/in.h>
64210311Sjmallett#include <netinet/if_ether.h>
65210311Sjmallett#endif
66210311Sjmallett
67210311Sjmallett#include <dev/mii/mii.h>
68210311Sjmallett#include <dev/mii/miivar.h>
69210311Sjmallett
70210311Sjmallett#include "wrapper-cvmx-includes.h"
71210311Sjmallett#include "cavium-ethernet.h"
72210311Sjmallett
73210311Sjmallett#include "ethernet-common.h"
74210311Sjmallett#include "ethernet-defines.h"
75210311Sjmallett#include "ethernet-mdio.h"
76210311Sjmallett#include "ethernet-tx.h"
77210311Sjmallett
78210311Sjmallett#include "miibus_if.h"
79210311Sjmallett
80210311Sjmallett#define	OCTE_TX_LOCK(priv)	mtx_lock(&(priv)->tx_mtx)
81210311Sjmallett#define	OCTE_TX_UNLOCK(priv)	mtx_unlock(&(priv)->tx_mtx)
82210311Sjmallett
83210311Sjmallettstatic int		octe_probe(device_t);
84210311Sjmallettstatic int		octe_attach(device_t);
85210311Sjmallettstatic int		octe_detach(device_t);
86210311Sjmallettstatic int		octe_shutdown(device_t);
87210311Sjmallett
88210311Sjmallettstatic int		octe_miibus_readreg(device_t, int, int);
89210311Sjmallettstatic int		octe_miibus_writereg(device_t, int, int, int);
90210311Sjmallett
91210311Sjmallettstatic void		octe_init(void *);
92210311Sjmallettstatic void		octe_stop(void *);
93215957Sjmallettstatic int		octe_transmit(struct ifnet *, struct mbuf *);
94210311Sjmallett
95210311Sjmallettstatic int		octe_mii_medchange(struct ifnet *);
96210311Sjmallettstatic void		octe_mii_medstat(struct ifnet *, struct ifmediareq *);
97210311Sjmallett
98210311Sjmallettstatic int		octe_medchange(struct ifnet *);
99210311Sjmallettstatic void		octe_medstat(struct ifnet *, struct ifmediareq *);
100210311Sjmallett
101210311Sjmallettstatic int		octe_ioctl(struct ifnet *, u_long, caddr_t);
102210311Sjmallett
103210311Sjmallettstatic device_method_t octe_methods[] = {
104210311Sjmallett	/* Device interface */
105210311Sjmallett	DEVMETHOD(device_probe,		octe_probe),
106210311Sjmallett	DEVMETHOD(device_attach,	octe_attach),
107210311Sjmallett	DEVMETHOD(device_detach,	octe_detach),
108210311Sjmallett	DEVMETHOD(device_shutdown,	octe_shutdown),
109210311Sjmallett
110210311Sjmallett	/* MII interface */
111210311Sjmallett	DEVMETHOD(miibus_readreg,	octe_miibus_readreg),
112210311Sjmallett	DEVMETHOD(miibus_writereg,	octe_miibus_writereg),
113210311Sjmallett
114210311Sjmallett	{ 0, 0 }
115210311Sjmallett};
116210311Sjmallett
117210311Sjmallettstatic driver_t octe_driver = {
118210311Sjmallett	"octe",
119210311Sjmallett	octe_methods,
120210311Sjmallett	sizeof (cvm_oct_private_t),
121210311Sjmallett};
122210311Sjmallett
123210311Sjmallettstatic devclass_t octe_devclass;
124210311Sjmallett
125210311SjmallettDRIVER_MODULE(octe, octebus, octe_driver, octe_devclass, 0, 0);
126210311SjmallettDRIVER_MODULE(miibus, octe, miibus_driver, miibus_devclass, 0, 0);
127210311Sjmallett
128210311Sjmallettstatic int
129210311Sjmallettocte_probe(device_t dev)
130210311Sjmallett{
131210311Sjmallett	return (0);
132210311Sjmallett}
133210311Sjmallett
134210311Sjmallettstatic int
135210311Sjmallettocte_attach(device_t dev)
136210311Sjmallett{
137210311Sjmallett	struct ifnet *ifp;
138210311Sjmallett	cvm_oct_private_t *priv;
139213762Sjmallett	device_t child;
140210311Sjmallett	unsigned qos;
141210311Sjmallett	int error;
142210311Sjmallett
143210311Sjmallett	priv = device_get_softc(dev);
144210311Sjmallett	ifp = priv->ifp;
145210311Sjmallett
146210311Sjmallett	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
147210311Sjmallett
148210311Sjmallett	if (priv->phy_id != -1) {
149213762Sjmallett		if (priv->phy_device == NULL) {
150213893Smarius			error = mii_attach(dev, &priv->miibus, ifp,
151213893Smarius			    octe_mii_medchange, octe_mii_medstat,
152213893Smarius			    BMSR_DEFCAPMASK, priv->phy_id, MII_OFFSET_ANY, 0);
153213762Sjmallett			if (error != 0)
154213893Smarius				device_printf(dev, "attaching PHYs failed\n");
155213762Sjmallett		} else {
156213762Sjmallett			child = device_add_child(dev, priv->phy_device, -1);
157213762Sjmallett			if (child == NULL)
158213762Sjmallett				device_printf(dev, "missing phy %u device %s\n", priv->phy_id, priv->phy_device);
159210311Sjmallett		}
160210311Sjmallett	}
161210311Sjmallett
162210311Sjmallett	if (priv->miibus == NULL) {
163210311Sjmallett		ifmedia_init(&priv->media, 0, octe_medchange, octe_medstat);
164210311Sjmallett
165210311Sjmallett		ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL);
166210311Sjmallett		ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO);
167210311Sjmallett	}
168210311Sjmallett
169210311Sjmallett	/*
170210311Sjmallett	 * XXX
171210311Sjmallett	 * We don't support programming the multicast filter right now, although it
172210311Sjmallett	 * ought to be easy enough.  (Presumably it's just a matter of putting
173210311Sjmallett	 * multicast addresses in the CAM?)
174210311Sjmallett	 */
175210311Sjmallett	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_ALLMULTI;
176210311Sjmallett	ifp->if_init = octe_init;
177210311Sjmallett	ifp->if_ioctl = octe_ioctl;
178210311Sjmallett
179210311Sjmallett	priv->if_flags = ifp->if_flags;
180210311Sjmallett
181210311Sjmallett	mtx_init(&priv->tx_mtx, ifp->if_xname, "octe tx send queue", MTX_DEF);
182210311Sjmallett
183210311Sjmallett	for (qos = 0; qos < 16; qos++) {
184210311Sjmallett		mtx_init(&priv->tx_free_queue[qos].ifq_mtx, ifp->if_xname, "octe tx free queue", MTX_DEF);
185210311Sjmallett		IFQ_SET_MAXLEN(&priv->tx_free_queue[qos], MAX_OUT_QUEUE_DEPTH);
186210311Sjmallett	}
187210311Sjmallett
188210311Sjmallett	ether_ifattach(ifp, priv->mac);
189210311Sjmallett
190215957Sjmallett	ifp->if_transmit = octe_transmit;
191215957Sjmallett
192210311Sjmallett	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
193210311Sjmallett	ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_HWCSUM;
194210311Sjmallett	ifp->if_capenable = ifp->if_capabilities;
195210311Sjmallett	ifp->if_hwassist = CSUM_TCP | CSUM_UDP;
196210311Sjmallett
197210311Sjmallett	OCTE_TX_LOCK(priv);
198210311Sjmallett	IFQ_SET_MAXLEN(&ifp->if_snd, MAX_OUT_QUEUE_DEPTH);
199210311Sjmallett	ifp->if_snd.ifq_drv_maxlen = MAX_OUT_QUEUE_DEPTH;
200210311Sjmallett	IFQ_SET_READY(&ifp->if_snd);
201210311Sjmallett	OCTE_TX_UNLOCK(priv);
202210311Sjmallett
203213762Sjmallett	return (bus_generic_attach(dev));
204210311Sjmallett}
205210311Sjmallett
206210311Sjmallettstatic int
207210311Sjmallettocte_detach(device_t dev)
208210311Sjmallett{
209210311Sjmallett	return (0);
210210311Sjmallett}
211210311Sjmallett
212210311Sjmallettstatic int
213210311Sjmallettocte_shutdown(device_t dev)
214210311Sjmallett{
215210311Sjmallett	return (octe_detach(dev));
216210311Sjmallett}
217210311Sjmallett
218210311Sjmallettstatic int
219210311Sjmallettocte_miibus_readreg(device_t dev, int phy, int reg)
220210311Sjmallett{
221210311Sjmallett	cvm_oct_private_t *priv;
222210311Sjmallett
223210311Sjmallett	priv = device_get_softc(dev);
224210311Sjmallett
225213346Sjmallett	/*
226213346Sjmallett	 * Try interface-specific MII routine.
227213346Sjmallett	 */
228213346Sjmallett	if (priv->mdio_read != NULL)
229213346Sjmallett		return (priv->mdio_read(priv->ifp, phy, reg));
230213346Sjmallett
231213346Sjmallett	/*
232213346Sjmallett	 * Try generic MII routine.
233213346Sjmallett	 */
234213893Smarius	KASSERT(phy == priv->phy_id,
235213893Smarius	    ("read from phy %u but our phy is %u", phy, priv->phy_id));
236210311Sjmallett	return (cvm_oct_mdio_read(priv->ifp, phy, reg));
237210311Sjmallett}
238210311Sjmallett
239210311Sjmallettstatic int
240210311Sjmallettocte_miibus_writereg(device_t dev, int phy, int reg, int val)
241210311Sjmallett{
242210311Sjmallett	cvm_oct_private_t *priv;
243210311Sjmallett
244210311Sjmallett	priv = device_get_softc(dev);
245210311Sjmallett
246213346Sjmallett	/*
247213346Sjmallett	 * Try interface-specific MII routine.
248213346Sjmallett	 */
249213346Sjmallett	if (priv->mdio_write != NULL) {
250213346Sjmallett		priv->mdio_write(priv->ifp, phy, reg, val);
251213346Sjmallett		return (0);
252213346Sjmallett	}
253213346Sjmallett
254213346Sjmallett	/*
255213346Sjmallett	 * Try generic MII routine.
256213346Sjmallett	 */
257210311Sjmallett	KASSERT(phy == priv->phy_id,
258210311Sjmallett	    ("write to phy %u but our phy is %u", phy, priv->phy_id));
259210311Sjmallett	cvm_oct_mdio_write(priv->ifp, phy, reg, val);
260210311Sjmallett
261210311Sjmallett	return (0);
262210311Sjmallett}
263210311Sjmallett
264210311Sjmallettstatic void
265210311Sjmallettocte_init(void *arg)
266210311Sjmallett{
267210311Sjmallett	struct ifnet *ifp;
268210311Sjmallett	cvm_oct_private_t *priv;
269210311Sjmallett
270210311Sjmallett	priv = arg;
271210311Sjmallett	ifp = priv->ifp;
272210311Sjmallett
273210311Sjmallett	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
274210311Sjmallett		octe_stop(priv);
275210311Sjmallett
276210311Sjmallett	if (priv->open != NULL)
277210311Sjmallett		priv->open(ifp);
278210311Sjmallett
279210311Sjmallett	if (((ifp->if_flags ^ priv->if_flags) & (IFF_ALLMULTI | IFF_MULTICAST | IFF_PROMISC)) != 0)
280210311Sjmallett		cvm_oct_common_set_multicast_list(ifp);
281210311Sjmallett
282210311Sjmallett	cvm_oct_common_set_mac_address(ifp, IF_LLADDR(ifp));
283210311Sjmallett
284216071Sjmallett	cvm_oct_common_poll(ifp);
285216071Sjmallett
286210311Sjmallett	if (priv->miibus != NULL)
287210311Sjmallett		mii_mediachg(device_get_softc(priv->miibus));
288210311Sjmallett
289210311Sjmallett	ifp->if_drv_flags |= IFF_DRV_RUNNING;
290210311Sjmallett	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
291210311Sjmallett}
292210311Sjmallett
293210311Sjmallettstatic void
294210311Sjmallettocte_stop(void *arg)
295210311Sjmallett{
296210311Sjmallett	struct ifnet *ifp;
297210311Sjmallett	cvm_oct_private_t *priv;
298210311Sjmallett
299210311Sjmallett	priv = arg;
300210311Sjmallett	ifp = priv->ifp;
301210311Sjmallett
302210311Sjmallett	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
303210311Sjmallett		return;
304210311Sjmallett
305210311Sjmallett	if (priv->stop != NULL)
306210311Sjmallett		priv->stop(ifp);
307210311Sjmallett
308210311Sjmallett	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
309210311Sjmallett}
310210311Sjmallett
311215957Sjmallettstatic int
312215957Sjmallettocte_transmit(struct ifnet *ifp, struct mbuf *m)
313210311Sjmallett{
314210311Sjmallett	cvm_oct_private_t *priv;
315210311Sjmallett
316210311Sjmallett	priv = ifp->if_softc;
317210311Sjmallett
318215957Sjmallett	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
319215957Sjmallett	    IFF_DRV_RUNNING) {
320215957Sjmallett		m_freem(m);
321215957Sjmallett		return (0);
322215957Sjmallett	}
323210311Sjmallett
324215959Sjmallett	return (cvm_oct_xmit(m, ifp));
325210311Sjmallett}
326210311Sjmallett
327210311Sjmallettstatic int
328210311Sjmallettocte_mii_medchange(struct ifnet *ifp)
329210311Sjmallett{
330210311Sjmallett	cvm_oct_private_t *priv;
331210311Sjmallett	struct mii_data *mii;
332221407Smarius	struct mii_softc *miisc;
333210311Sjmallett
334210311Sjmallett	priv = ifp->if_softc;
335210311Sjmallett	mii = device_get_softc(priv->miibus);
336221407Smarius	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
337221407Smarius		PHY_RESET(miisc);
338210311Sjmallett	mii_mediachg(mii);
339210311Sjmallett
340210311Sjmallett	return (0);
341210311Sjmallett}
342210311Sjmallett
343210311Sjmallettstatic void
344210311Sjmallettocte_mii_medstat(struct ifnet *ifp, struct ifmediareq *ifm)
345210311Sjmallett{
346210311Sjmallett	cvm_oct_private_t *priv;
347210311Sjmallett	struct mii_data *mii;
348210311Sjmallett
349210311Sjmallett	priv = ifp->if_softc;
350210311Sjmallett	mii = device_get_softc(priv->miibus);
351210311Sjmallett
352210311Sjmallett	mii_pollstat(mii);
353210311Sjmallett	ifm->ifm_active = mii->mii_media_active;
354210311Sjmallett	ifm->ifm_status = mii->mii_media_status;
355210311Sjmallett}
356210311Sjmallett
357210311Sjmallettstatic int
358210311Sjmallettocte_medchange(struct ifnet *ifp)
359210311Sjmallett{
360210311Sjmallett	return (ENOTSUP);
361210311Sjmallett}
362210311Sjmallett
363210311Sjmallettstatic void
364210311Sjmallettocte_medstat(struct ifnet *ifp, struct ifmediareq *ifm)
365210311Sjmallett{
366210311Sjmallett	cvm_oct_private_t *priv;
367210311Sjmallett	cvmx_helper_link_info_t link_info;
368210311Sjmallett
369210311Sjmallett	priv = ifp->if_softc;
370210311Sjmallett
371210311Sjmallett	ifm->ifm_status = IFM_AVALID;
372210311Sjmallett	ifm->ifm_active = IFT_ETHER;
373210311Sjmallett
374210311Sjmallett	if (priv->poll == NULL)
375210311Sjmallett		return;
376210311Sjmallett	priv->poll(ifp);
377210311Sjmallett
378210311Sjmallett	link_info.u64 = priv->link_info;
379210311Sjmallett
380210311Sjmallett	if (!link_info.s.link_up)
381210311Sjmallett		return;
382210311Sjmallett
383210311Sjmallett	ifm->ifm_status |= IFM_ACTIVE;
384210311Sjmallett
385210311Sjmallett	switch (link_info.s.speed) {
386210311Sjmallett	case 10:
387210311Sjmallett		ifm->ifm_active |= IFM_10_T;
388210311Sjmallett		break;
389210311Sjmallett	case 100:
390210311Sjmallett		ifm->ifm_active |= IFM_100_TX;
391210311Sjmallett		break;
392210311Sjmallett	case 1000:
393210311Sjmallett		ifm->ifm_active |= IFM_1000_T;
394210311Sjmallett		break;
395210311Sjmallett	case 10000:
396210311Sjmallett		ifm->ifm_active |= IFM_10G_T;
397210311Sjmallett		break;
398210311Sjmallett	}
399210311Sjmallett
400210311Sjmallett	if (link_info.s.full_duplex)
401210311Sjmallett		ifm->ifm_active |= IFM_FDX;
402210311Sjmallett	else
403210311Sjmallett		ifm->ifm_active |= IFM_HDX;
404210311Sjmallett}
405210311Sjmallett
406210311Sjmallettstatic int
407210311Sjmallettocte_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
408210311Sjmallett{
409210311Sjmallett	cvm_oct_private_t *priv;
410210311Sjmallett	struct mii_data *mii;
411210311Sjmallett	struct ifreq *ifr;
412210311Sjmallett#ifdef INET
413210311Sjmallett	struct ifaddr *ifa;
414210311Sjmallett#endif
415210311Sjmallett	int error;
416210311Sjmallett
417210311Sjmallett	priv = ifp->if_softc;
418210311Sjmallett	ifr = (struct ifreq *)data;
419210311Sjmallett#ifdef INET
420210311Sjmallett	ifa = (struct ifaddr *)data;
421210311Sjmallett#endif
422210311Sjmallett
423210311Sjmallett	switch (cmd) {
424210311Sjmallett	case SIOCSIFADDR:
425210311Sjmallett#ifdef INET
426210311Sjmallett		/*
427210311Sjmallett		 * Avoid reinitialization unless it's necessary.
428210311Sjmallett		 */
429210311Sjmallett		if (ifa->ifa_addr->sa_family == AF_INET) {
430210311Sjmallett			ifp->if_flags |= IFF_UP;
431210311Sjmallett			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
432210311Sjmallett				octe_init(priv);
433210311Sjmallett			arp_ifinit(ifp, ifa);
434210311Sjmallett
435210311Sjmallett			return (0);
436210311Sjmallett		}
437210311Sjmallett#endif
438210311Sjmallett		error = ether_ioctl(ifp, cmd, data);
439210311Sjmallett		if (error != 0)
440210311Sjmallett			return (error);
441210311Sjmallett		return (0);
442210311Sjmallett
443210311Sjmallett	case SIOCSIFFLAGS:
444210311Sjmallett		if (ifp->if_flags == priv->if_flags)
445210311Sjmallett			return (0);
446210311Sjmallett		if ((ifp->if_flags & IFF_UP) != 0) {
447210311Sjmallett			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
448210311Sjmallett				octe_init(priv);
449210311Sjmallett		} else {
450210311Sjmallett			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
451210311Sjmallett				octe_stop(priv);
452210311Sjmallett		}
453210311Sjmallett		priv->if_flags = ifp->if_flags;
454210311Sjmallett		return (0);
455210311Sjmallett
456210311Sjmallett	case SIOCSIFCAP:
457210311Sjmallett		/*
458210311Sjmallett		 * Just change the capabilities in software, currently none
459210311Sjmallett		 * require reprogramming hardware, they just toggle whether we
460210311Sjmallett		 * make use of already-present facilities in software.
461210311Sjmallett		 */
462210311Sjmallett		ifp->if_capenable = ifr->ifr_reqcap;
463210311Sjmallett		return (0);
464210311Sjmallett
465210311Sjmallett	case SIOCSIFMTU:
466210311Sjmallett		error = cvm_oct_common_change_mtu(ifp, ifr->ifr_mtu);
467210311Sjmallett		if (error != 0)
468210311Sjmallett			return (EINVAL);
469210311Sjmallett		return (0);
470210311Sjmallett
471210311Sjmallett	case SIOCSIFMEDIA:
472210311Sjmallett	case SIOCGIFMEDIA:
473210311Sjmallett		if (priv->miibus != NULL) {
474210311Sjmallett			mii = device_get_softc(priv->miibus);
475210311Sjmallett			error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
476210311Sjmallett			if (error != 0)
477210311Sjmallett				return (error);
478210311Sjmallett			return (0);
479210311Sjmallett		}
480210311Sjmallett		error = ifmedia_ioctl(ifp, ifr, &priv->media, cmd);
481210311Sjmallett		if (error != 0)
482210311Sjmallett			return (error);
483210311Sjmallett		return (0);
484210311Sjmallett
485210311Sjmallett	default:
486210311Sjmallett		error = ether_ioctl(ifp, cmd, data);
487210311Sjmallett		if (error != 0)
488210311Sjmallett			return (error);
489210311Sjmallett		return (0);
490210311Sjmallett	}
491210311Sjmallett}
492