octe.c revision 302408
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: stable/11/sys/mips/cavium/octe/octe.c 270856 2014-08-30 19:55:54Z glebius $ 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_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