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