octe.c revision 215957
168673Sobrien/*- 278828Sobrien * Copyright (c) 2010 Juli Mallett <jmallett@FreeBSD.org> 368673Sobrien * All rights reserved. 468673Sobrien * 568673Sobrien * Redistribution and use in source and binary forms, with or without 668673Sobrien * modification, are permitted provided that the following conditions 768673Sobrien * are met: 868673Sobrien * 1. Redistributions of source code must retain the above copyright 968673Sobrien * notice, this list of conditions and the following disclaimer. 1068673Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1168673Sobrien * notice, this list of conditions and the following disclaimer in the 1268673Sobrien * documentation and/or other materials provided with the distribution. 1368673Sobrien * 1468673Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1568673Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1668673Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1768673Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18218822Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1968673Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2068673Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2168673Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2268673Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2368673Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2468673Sobrien * SUCH DAMAGE. 2568673Sobrien * 2668673Sobrien * $FreeBSD: head/sys/mips/cavium/octe/octe.c 215957 2010-11-27 22:42:41Z jmallett $ 2768673Sobrien */ 2868673Sobrien 2968673Sobrien/* 3068673Sobrien * Cavium Octeon Ethernet devices. 3168673Sobrien * 3268673Sobrien * XXX This file should be moved to if_octe.c 3368673Sobrien * XXX The driver may have sufficient locking but we need locking to protect 3468673Sobrien * the interfaces presented here, right? 3568673Sobrien */ 3668673Sobrien 3768673Sobrien#include "opt_inet.h" 3868673Sobrien 3968673Sobrien#include <sys/param.h> 4077298Sobrien#include <sys/systm.h> 4168673Sobrien#include <sys/bus.h> 4268673Sobrien#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 driver_t pow_driver = { 129 "pow", 130 octe_methods, 131 sizeof (cvm_oct_private_t), 132}; 133 134static devclass_t pow_devclass; 135 136DRIVER_MODULE(pow, octebus, pow_driver, pow_devclass, 0, 0); 137 138static int 139octe_probe(device_t dev) 140{ 141 return (0); 142} 143 144static int 145octe_attach(device_t dev) 146{ 147 struct ifnet *ifp; 148 cvm_oct_private_t *priv; 149 device_t child; 150 unsigned qos; 151 int error; 152 153 priv = device_get_softc(dev); 154 ifp = priv->ifp; 155 156 if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 157 158 if (priv->phy_id != -1) { 159 if (priv->phy_device == NULL) { 160 error = mii_attach(dev, &priv->miibus, ifp, 161 octe_mii_medchange, octe_mii_medstat, 162 BMSR_DEFCAPMASK, priv->phy_id, MII_OFFSET_ANY, 0); 163 if (error != 0) 164 device_printf(dev, "attaching PHYs failed\n"); 165 } else { 166 child = device_add_child(dev, priv->phy_device, -1); 167 if (child == NULL) 168 device_printf(dev, "missing phy %u device %s\n", priv->phy_id, priv->phy_device); 169 } 170 } 171 172 if (priv->miibus == NULL) { 173 ifmedia_init(&priv->media, 0, octe_medchange, octe_medstat); 174 175 ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL); 176 ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO); 177 } 178 179 /* 180 * XXX 181 * We don't support programming the multicast filter right now, although it 182 * ought to be easy enough. (Presumably it's just a matter of putting 183 * multicast addresses in the CAM?) 184 */ 185 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_ALLMULTI; 186 ifp->if_init = octe_init; 187 ifp->if_ioctl = octe_ioctl; 188 189 priv->if_flags = ifp->if_flags; 190 191 mtx_init(&priv->tx_mtx, ifp->if_xname, "octe tx send queue", MTX_DEF); 192 193 for (qos = 0; qos < 16; qos++) { 194 mtx_init(&priv->tx_free_queue[qos].ifq_mtx, ifp->if_xname, "octe tx free queue", MTX_DEF); 195 IFQ_SET_MAXLEN(&priv->tx_free_queue[qos], MAX_OUT_QUEUE_DEPTH); 196 } 197 198 ether_ifattach(ifp, priv->mac); 199 200 ifp->if_transmit = octe_transmit; 201 202 ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 203 ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_HWCSUM; 204 ifp->if_capenable = ifp->if_capabilities; 205 ifp->if_hwassist = CSUM_TCP | CSUM_UDP; 206 207 OCTE_TX_LOCK(priv); 208 IFQ_SET_MAXLEN(&ifp->if_snd, MAX_OUT_QUEUE_DEPTH); 209 ifp->if_snd.ifq_drv_maxlen = MAX_OUT_QUEUE_DEPTH; 210 IFQ_SET_READY(&ifp->if_snd); 211 OCTE_TX_UNLOCK(priv); 212 213 return (bus_generic_attach(dev)); 214} 215 216static int 217octe_detach(device_t dev) 218{ 219 return (0); 220} 221 222static int 223octe_shutdown(device_t dev) 224{ 225 return (octe_detach(dev)); 226} 227 228static int 229octe_miibus_readreg(device_t dev, int phy, int reg) 230{ 231 cvm_oct_private_t *priv; 232 233 priv = device_get_softc(dev); 234 235 /* 236 * Try interface-specific MII routine. 237 */ 238 if (priv->mdio_read != NULL) 239 return (priv->mdio_read(priv->ifp, phy, reg)); 240 241 /* 242 * Try generic MII routine. 243 */ 244 KASSERT(phy == priv->phy_id, 245 ("read from phy %u but our phy is %u", phy, priv->phy_id)); 246 return (cvm_oct_mdio_read(priv->ifp, phy, reg)); 247} 248 249static int 250octe_miibus_writereg(device_t dev, int phy, int reg, int val) 251{ 252 cvm_oct_private_t *priv; 253 254 priv = device_get_softc(dev); 255 256 /* 257 * Try interface-specific MII routine. 258 */ 259 if (priv->mdio_write != NULL) { 260 priv->mdio_write(priv->ifp, phy, reg, val); 261 return (0); 262 } 263 264 /* 265 * Try generic MII routine. 266 */ 267 KASSERT(phy == priv->phy_id, 268 ("write to phy %u but our phy is %u", phy, priv->phy_id)); 269 cvm_oct_mdio_write(priv->ifp, phy, reg, val); 270 271 return (0); 272} 273 274static void 275octe_init(void *arg) 276{ 277 struct ifnet *ifp; 278 cvm_oct_private_t *priv; 279 280 priv = arg; 281 ifp = priv->ifp; 282 283 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 284 octe_stop(priv); 285 286 if (priv->open != NULL) 287 priv->open(ifp); 288 289 if (((ifp->if_flags ^ priv->if_flags) & (IFF_ALLMULTI | IFF_MULTICAST | IFF_PROMISC)) != 0) 290 cvm_oct_common_set_multicast_list(ifp); 291 292 cvm_oct_common_set_mac_address(ifp, IF_LLADDR(ifp)); 293 294 if (priv->poll != NULL) 295 priv->poll(ifp); 296 if (priv->miibus != NULL) 297 mii_mediachg(device_get_softc(priv->miibus)); 298 299 ifp->if_drv_flags |= IFF_DRV_RUNNING; 300 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 301} 302 303static void 304octe_stop(void *arg) 305{ 306 struct ifnet *ifp; 307 cvm_oct_private_t *priv; 308 309 priv = arg; 310 ifp = priv->ifp; 311 312 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 313 return; 314 315 if (priv->stop != NULL) 316 priv->stop(ifp); 317 318 ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 319} 320 321static int 322octe_transmit(struct ifnet *ifp, struct mbuf *m) 323{ 324 cvm_oct_private_t *priv; 325 int error; 326 327 priv = ifp->if_softc; 328 329 if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 330 IFF_DRV_RUNNING) { 331 m_freem(m); 332 return (0); 333 } 334 335 if (priv->queue != -1) { 336 error = cvm_oct_xmit(m, ifp); 337 } else { 338 error = cvm_oct_xmit_pow(m, ifp); 339 } 340 return (error); 341} 342 343static int 344octe_mii_medchange(struct ifnet *ifp) 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 if (mii->mii_instance) { 353 struct mii_softc *miisc; 354 355 LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 356 mii_phy_reset(miisc); 357 } 358 mii_mediachg(mii); 359 360 return (0); 361} 362 363static void 364octe_mii_medstat(struct ifnet *ifp, struct ifmediareq *ifm) 365{ 366 cvm_oct_private_t *priv; 367 struct mii_data *mii; 368 369 priv = ifp->if_softc; 370 mii = device_get_softc(priv->miibus); 371 372 mii_pollstat(mii); 373 ifm->ifm_active = mii->mii_media_active; 374 ifm->ifm_status = mii->mii_media_status; 375} 376 377static int 378octe_medchange(struct ifnet *ifp) 379{ 380 return (ENOTSUP); 381} 382 383static void 384octe_medstat(struct ifnet *ifp, struct ifmediareq *ifm) 385{ 386 cvm_oct_private_t *priv; 387 cvmx_helper_link_info_t link_info; 388 389 priv = ifp->if_softc; 390 391 ifm->ifm_status = IFM_AVALID; 392 ifm->ifm_active = IFT_ETHER; 393 394 if (priv->poll == NULL) 395 return; 396 priv->poll(ifp); 397 398 link_info.u64 = priv->link_info; 399 400 if (!link_info.s.link_up) 401 return; 402 403 ifm->ifm_status |= IFM_ACTIVE; 404 405 switch (link_info.s.speed) { 406 case 10: 407 ifm->ifm_active |= IFM_10_T; 408 break; 409 case 100: 410 ifm->ifm_active |= IFM_100_TX; 411 break; 412 case 1000: 413 ifm->ifm_active |= IFM_1000_T; 414 break; 415 case 10000: 416 ifm->ifm_active |= IFM_10G_T; 417 break; 418 } 419 420 if (link_info.s.full_duplex) 421 ifm->ifm_active |= IFM_FDX; 422 else 423 ifm->ifm_active |= IFM_HDX; 424} 425 426static int 427octe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 428{ 429 cvm_oct_private_t *priv; 430 struct mii_data *mii; 431 struct ifreq *ifr; 432#ifdef INET 433 struct ifaddr *ifa; 434#endif 435 int error; 436 437 priv = ifp->if_softc; 438 ifr = (struct ifreq *)data; 439#ifdef INET 440 ifa = (struct ifaddr *)data; 441#endif 442 443 switch (cmd) { 444 case SIOCSIFADDR: 445#ifdef INET 446 /* 447 * Avoid reinitialization unless it's necessary. 448 */ 449 if (ifa->ifa_addr->sa_family == AF_INET) { 450 ifp->if_flags |= IFF_UP; 451 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 452 octe_init(priv); 453 arp_ifinit(ifp, ifa); 454 455 return (0); 456 } 457#endif 458 error = ether_ioctl(ifp, cmd, data); 459 if (error != 0) 460 return (error); 461 return (0); 462 463 case SIOCSIFFLAGS: 464 if (ifp->if_flags == priv->if_flags) 465 return (0); 466 if ((ifp->if_flags & IFF_UP) != 0) { 467 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 468 octe_init(priv); 469 } else { 470 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 471 octe_stop(priv); 472 } 473 priv->if_flags = ifp->if_flags; 474 return (0); 475 476 case SIOCSIFCAP: 477 /* 478 * Just change the capabilities in software, currently none 479 * require reprogramming hardware, they just toggle whether we 480 * make use of already-present facilities in software. 481 */ 482 ifp->if_capenable = ifr->ifr_reqcap; 483 return (0); 484 485 case SIOCSIFMTU: 486 error = cvm_oct_common_change_mtu(ifp, ifr->ifr_mtu); 487 if (error != 0) 488 return (EINVAL); 489 return (0); 490 491 case SIOCSIFMEDIA: 492 case SIOCGIFMEDIA: 493 if (priv->miibus != NULL) { 494 mii = device_get_softc(priv->miibus); 495 error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 496 if (error != 0) 497 return (error); 498 return (0); 499 } 500 error = ifmedia_ioctl(ifp, ifr, &priv->media, cmd); 501 if (error != 0) 502 return (error); 503 return (0); 504 505 default: 506 error = ether_ioctl(ifp, cmd, data); 507 if (error != 0) 508 return (error); 509 return (0); 510 } 511} 512