1139749Simp/*- 2116258Sharti * Copyright (c) 2003 3116258Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4116258Sharti * All rights reserved. 5116258Sharti * 6142384Sharti * Author: Hartmut Brandt <harti@freebsd.org> 7142384Sharti * 8116258Sharti * Redistribution and use in source and binary forms, with or without 9116258Sharti * modification, are permitted provided that the following conditions 10116258Sharti * are met: 11116258Sharti * 1. Redistributions of source code must retain the above copyright 12116258Sharti * notice, this list of conditions and the following disclaimer. 13116258Sharti * 2. Redistributions in binary form must reproduce the above copyright 14116258Sharti * notice, this list of conditions and the following disclaimer in the 15116258Sharti * documentation and/or other materials provided with the distribution. 16116258Sharti * 17116258Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18116258Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19116258Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20116258Sharti * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21116258Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22116258Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23116258Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24116258Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25116258Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26116258Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27116258Sharti * SUCH DAMAGE. 28116258Sharti */ 29116258Sharti 30116258Sharti#include <sys/cdefs.h> 31116258Sharti__FBSDID("$FreeBSD$"); 32116258Sharti 33116258Sharti#include <sys/param.h> 34116258Sharti#include <sys/systm.h> 35116258Sharti#include <sys/unistd.h> 36116258Sharti#include <sys/kernel.h> 37116258Sharti#include <sys/kthread.h> 38116258Sharti#include <sys/proc.h> 39116258Sharti#include <sys/bus.h> 40116258Sharti#include <sys/malloc.h> 41129879Sphk#include <sys/module.h> 42116258Sharti#include <sys/sysctl.h> 43116258Sharti#include <sys/lock.h> 44116258Sharti#include <sys/mutex.h> 45116258Sharti#include <sys/socket.h> 46116258Sharti 47116258Sharti#include <net/if.h> 48116258Sharti#include <net/if_var.h> 49116258Sharti#include <net/if_media.h> 50116258Sharti#include <net/if_atm.h> 51116258Sharti 52116258Sharti#include <dev/utopia/suni.h> 53116258Sharti#include <dev/utopia/idtphy.h> 54116258Sharti#include <dev/utopia/utopia.h> 55142384Sharti#include <dev/utopia/utopia_priv.h> 56116258Sharti 57142384Sharti/* known chips */ 58142384Shartiextern const struct utopia_chip utopia_chip_idt77155; 59142384Shartiextern const struct utopia_chip utopia_chip_idt77105; 60142384Shartiextern const struct utopia_chip utopia_chip_lite; 61142384Shartiextern const struct utopia_chip utopia_chip_ultra; 62142384Shartiextern const struct utopia_chip utopia_chip_622; 63116258Sharti 64116258Sharti/* 65116258Sharti * Global list of all registered interfaces 66116258Sharti */ 67116258Shartistatic struct mtx utopia_list_mtx; 68116258Shartistatic LIST_HEAD(, utopia) utopia_list = LIST_HEAD_INITIALIZER(utopia_list); 69116258Sharti 70116258Sharti#define UTP_RLOCK_LIST() mtx_lock(&utopia_list_mtx) 71116258Sharti#define UTP_RUNLOCK_LIST() mtx_unlock(&utopia_list_mtx) 72116258Sharti#define UTP_WLOCK_LIST() mtx_lock(&utopia_list_mtx) 73116258Sharti#define UTP_WUNLOCK_LIST() mtx_unlock(&utopia_list_mtx) 74116258Sharti 75116258Sharti#define UTP_LOCK(UTP) mtx_lock((UTP)->lock) 76116258Sharti#define UTP_UNLOCK(UTP) mtx_unlock((UTP)->lock) 77116258Sharti#define UTP_LOCK_ASSERT(UTP) mtx_assert((UTP)->lock, MA_OWNED) 78116258Sharti 79116258Shartistatic struct proc *utopia_kproc; 80116258Sharti 81116258Shartistatic void utopia_dump(struct utopia *) __unused; 82116258Sharti 83116258Sharti/* 84142384Sharti * Read a multi-register value. 85117552Sharti */ 86142384Shartiuint32_t 87142384Shartiutopia_update(struct utopia *utp, u_int reg, u_int nreg, uint32_t mask) 88117552Sharti{ 89117552Sharti int err; 90117552Sharti u_int n; 91117552Sharti uint8_t regs[4]; 92117552Sharti uint32_t val; 93117552Sharti 94117552Sharti n = nreg; 95142384Sharti if ((err = UTP_READREGS(utp, reg, regs, &n)) != 0) { 96117552Sharti#ifdef DIAGNOSTIC 97117552Sharti printf("%s: register read error %s(%u,%u): %d\n", __func__, 98117552Sharti utp->chip->name, reg, nreg, err); 99117552Sharti#endif 100117552Sharti return (0); 101117552Sharti } 102117552Sharti if (n < nreg) { 103117552Sharti#ifdef DIAGNOSTIC 104117552Sharti printf("%s: got only %u regs %s(%u,%u): %d\n", __func__, n, 105117552Sharti utp->chip->name, reg, nreg, err); 106117552Sharti#endif 107117552Sharti return (0); 108117552Sharti } 109117552Sharti val = 0; 110117552Sharti for (n = nreg; n > 0; n--) { 111117552Sharti val <<= 8; 112117552Sharti val |= regs[n - 1]; 113117552Sharti } 114117552Sharti return (val & mask); 115117552Sharti} 116117552Sharti 117117552Sharti/* 118116258Sharti * Debugging - dump all registers. 119116258Sharti */ 120116258Shartistatic void 121116258Shartiutopia_dump(struct utopia *utp) 122116258Sharti{ 123116258Sharti uint8_t regs[256]; 124116258Sharti u_int n = 256, i; 125116258Sharti int err; 126116258Sharti 127142384Sharti if ((err = UTP_READREGS(utp, 0, regs, &n)) != 0) { 128142384Sharti printf("UTOPIA reg read error %d\n", err); 129116258Sharti return; 130116258Sharti } 131116258Sharti for (i = 0; i < n; i++) { 132116258Sharti if (i % 16 == 0) 133116258Sharti printf("%02x:", i); 134116258Sharti if (i % 16 == 8) 135116258Sharti printf(" "); 136116258Sharti printf(" %02x", regs[i]); 137116258Sharti if (i % 16 == 15) 138116258Sharti printf("\n"); 139116258Sharti } 140116258Sharti if (i % 16 != 0) 141116258Sharti printf("\n"); 142116258Sharti} 143116258Sharti 144116258Sharti/* 145116258Sharti * Update the carrier status 146116258Sharti */ 147142384Shartivoid 148116258Shartiutopia_check_carrier(struct utopia *utp, u_int carr_ok) 149116258Sharti{ 150116258Sharti int old; 151116258Sharti 152116258Sharti old = utp->carrier; 153116258Sharti if (carr_ok) { 154116258Sharti /* carrier */ 155116258Sharti utp->carrier = UTP_CARR_OK; 156116258Sharti if (old != UTP_CARR_OK) { 157147256Sbrooks if_printf(utp->ifatm->ifp, "carrier detected\n"); 158118202Sharti ATMEV_SEND_IFSTATE_CHANGED(utp->ifatm, 1); 159116258Sharti } 160116258Sharti } else { 161116258Sharti /* no carrier */ 162116258Sharti utp->carrier = UTP_CARR_LOST; 163116258Sharti if (old == UTP_CARR_OK) { 164147256Sbrooks if_printf(utp->ifatm->ifp, "carrier lost\n"); 165118202Sharti ATMEV_SEND_IFSTATE_CHANGED(utp->ifatm, 0); 166116258Sharti } 167116258Sharti } 168116258Sharti} 169116258Sharti 170116258Shartistatic int 171142384Shartiunknown_inval(struct utopia *utp, int what __unused) 172116258Sharti{ 173116258Sharti 174116258Sharti return (EINVAL); 175116258Sharti} 176116258Sharti 177116258Shartistatic int 178116258Shartiunknown_reset(struct utopia *utp __unused) 179116258Sharti{ 180116258Sharti return (EIO); 181116258Sharti} 182116258Sharti 183116258Shartistatic int 184116258Shartiunknown_update_carrier(struct utopia *utp) 185116258Sharti{ 186116258Sharti utp->carrier = UTP_CARR_UNKNOWN; 187116258Sharti return (0); 188116258Sharti} 189116258Sharti 190116258Shartistatic int 191116258Shartiunknown_set_loopback(struct utopia *utp __unused, u_int mode __unused) 192116258Sharti{ 193116258Sharti return (EINVAL); 194116258Sharti} 195116258Sharti 196116258Shartistatic void 197116258Shartiunknown_intr(struct utopia *utp __unused) 198116258Sharti{ 199116258Sharti} 200116258Sharti 201117552Shartistatic void 202117552Shartiunknown_update_stats(struct utopia *utp __unused) 203117552Sharti{ 204117552Sharti} 205117552Sharti 206142384Shartistatic const struct utopia_chip utopia_chip_unknown = { 207116258Sharti UTP_TYPE_UNKNOWN, 208116258Sharti "unknown", 209116258Sharti 0, 210116258Sharti unknown_reset, 211116258Sharti unknown_inval, 212116258Sharti unknown_inval, 213116258Sharti unknown_inval, 214116258Sharti unknown_update_carrier, 215116258Sharti unknown_set_loopback, 216116258Sharti unknown_intr, 217117552Sharti unknown_update_stats, 218116258Sharti}; 219116258Sharti 220116258Sharti/* 221116258Sharti * Callbacks for the ifmedia infrastructure. 222116258Sharti */ 223116258Shartistatic int 224116258Shartiutopia_media_change(struct ifnet *ifp) 225116258Sharti{ 226147526Sharti struct ifatm *ifatm = IFP2IFATM(ifp); 227116258Sharti struct utopia *utp = ifatm->phy; 228116258Sharti int error = 0; 229116258Sharti 230116258Sharti UTP_LOCK(utp); 231116258Sharti if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) { 232116258Sharti if (utp->media->ifm_media & IFM_ATM_SDH) { 233116258Sharti if (!(utp->state & UTP_ST_SDH)) 234116258Sharti error = utopia_set_sdh(utp, 1); 235116258Sharti } else { 236116258Sharti if (utp->state & UTP_ST_SDH) 237116258Sharti error = utopia_set_sdh(utp, 0); 238116258Sharti } 239116258Sharti if (utp->media->ifm_media & IFM_ATM_UNASSIGNED) { 240116258Sharti if (!(utp->state & UTP_ST_UNASS)) 241116258Sharti error = utopia_set_unass(utp, 1); 242116258Sharti } else { 243116258Sharti if (utp->state & UTP_ST_UNASS) 244116258Sharti error = utopia_set_unass(utp, 0); 245116258Sharti } 246116258Sharti if (utp->media->ifm_media & IFM_ATM_NOSCRAMB) { 247116258Sharti if (!(utp->state & UTP_ST_NOSCRAMB)) 248116258Sharti error = utopia_set_noscramb(utp, 1); 249116258Sharti } else { 250116258Sharti if (utp->state & UTP_ST_NOSCRAMB) 251116258Sharti error = utopia_set_noscramb(utp, 0); 252116258Sharti } 253116258Sharti } else 254116258Sharti error = EIO; 255116258Sharti UTP_UNLOCK(utp); 256116258Sharti return (error); 257116258Sharti} 258116258Sharti 259116258Sharti/* 260116258Sharti * Look at the carrier status. 261116258Sharti */ 262116258Shartistatic void 263116258Shartiutopia_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 264116258Sharti{ 265147526Sharti struct utopia *utp = IFP2IFATM(ifp)->phy; 266116258Sharti 267116258Sharti UTP_LOCK(utp); 268116258Sharti if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) { 269116258Sharti ifmr->ifm_active = IFM_ATM | utp->ifatm->mib.media; 270116258Sharti 271116258Sharti switch (utp->carrier) { 272116258Sharti 273116258Sharti case UTP_CARR_OK: 274116258Sharti ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; 275116258Sharti break; 276116258Sharti 277116258Sharti case UTP_CARR_LOST: 278116258Sharti ifmr->ifm_status = IFM_AVALID; 279116258Sharti break; 280116258Sharti 281116258Sharti default: 282116258Sharti ifmr->ifm_status = 0; 283116258Sharti break; 284116258Sharti } 285116258Sharti if (utp->state & UTP_ST_SDH) { 286116258Sharti ifmr->ifm_active |= IFM_ATM_SDH; 287116258Sharti ifmr->ifm_current |= IFM_ATM_SDH; 288116258Sharti } 289116258Sharti if (utp->state & UTP_ST_UNASS) { 290116258Sharti ifmr->ifm_active |= IFM_ATM_UNASSIGNED; 291116258Sharti ifmr->ifm_current |= IFM_ATM_UNASSIGNED; 292116258Sharti } 293116258Sharti if (utp->state & UTP_ST_NOSCRAMB) { 294116258Sharti ifmr->ifm_active |= IFM_ATM_NOSCRAMB; 295116258Sharti ifmr->ifm_current |= IFM_ATM_NOSCRAMB; 296116258Sharti } 297116258Sharti } else { 298116258Sharti ifmr->ifm_active = 0; 299116258Sharti ifmr->ifm_status = 0; 300116258Sharti } 301116258Sharti UTP_UNLOCK(utp); 302116258Sharti} 303116258Sharti 304116258Sharti/* 305116258Sharti * Initialize media from the mib 306116258Sharti */ 307116258Shartivoid 308116258Shartiutopia_init_media(struct utopia *utp) 309116258Sharti{ 310116258Sharti 311116258Sharti ifmedia_removeall(utp->media); 312116258Sharti ifmedia_add(utp->media, IFM_ATM | utp->ifatm->mib.media, 0, NULL); 313116258Sharti ifmedia_set(utp->media, IFM_ATM | utp->ifatm->mib.media); 314116258Sharti} 315116258Sharti 316116258Sharti/* 317116258Sharti * Reset all media 318116258Sharti */ 319116258Shartivoid 320116258Shartiutopia_reset_media(struct utopia *utp) 321116258Sharti{ 322116258Sharti 323116258Sharti ifmedia_removeall(utp->media); 324116258Sharti} 325116258Sharti 326116258Sharti/* 327116258Sharti * This is called by the driver as soon as the SUNI registers are accessible. 328116258Sharti * This may be either in the attach routine or the init routine of the driver. 329116258Sharti */ 330116258Shartiint 331116258Shartiutopia_start(struct utopia *utp) 332116258Sharti{ 333116258Sharti uint8_t reg; 334116258Sharti int err; 335116258Sharti u_int n = 1; 336116258Sharti 337142384Sharti /* 338142384Sharti * Try to find out what chip we have 339142384Sharti */ 340142384Sharti if ((err = UTP_READREGS(utp, SUNI_REGO_MRESET, ®, &n)) != 0) 341116258Sharti return (err); 342116258Sharti 343116258Sharti switch (reg & SUNI_REGM_MRESET_TYPE) { 344116258Sharti 345116258Sharti case SUNI_REGM_MRESET_TYPE_622: 346142384Sharti utp->chip = &utopia_chip_622; 347116258Sharti break; 348116258Sharti 349116258Sharti case SUNI_REGM_MRESET_TYPE_LITE: 350117546Sharti /* this may be either a SUNI LITE or a IDT77155 * 351117546Sharti * Read register 0x70. The SUNI doesn't have it */ 352117546Sharti n = 1; 353142384Sharti if ((err = UTP_READREGS(utp, IDTPHY_REGO_RBER, ®, &n)) != 0) 354117546Sharti return (err); 355117546Sharti if ((reg & ~IDTPHY_REGM_RBER_RESV) == 356117546Sharti (IDTPHY_REGM_RBER_FAIL | IDTPHY_REGM_RBER_WARN)) 357142384Sharti utp->chip = &utopia_chip_idt77155; 358117546Sharti else 359142384Sharti utp->chip = &utopia_chip_lite; 360116258Sharti break; 361116258Sharti 362116258Sharti case SUNI_REGM_MRESET_TYPE_ULTRA: 363142384Sharti utp->chip = &utopia_chip_ultra; 364116258Sharti break; 365116258Sharti 366116258Sharti default: 367116258Sharti if (reg == (IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI)) 368142384Sharti utp->chip = &utopia_chip_idt77105; 369116258Sharti else { 370147256Sbrooks if_printf(utp->ifatm->ifp, 371116258Sharti "unknown ATM-PHY chip %#x\n", reg); 372142384Sharti utp->chip = &utopia_chip_unknown; 373116258Sharti } 374116258Sharti break; 375116258Sharti } 376116258Sharti utp->state |= UTP_ST_ACTIVE; 377116258Sharti return (0); 378116258Sharti} 379116258Sharti 380116258Sharti/* 381116258Sharti * Stop the chip 382116258Sharti */ 383116258Shartivoid 384116258Shartiutopia_stop(struct utopia *utp) 385116258Sharti{ 386116258Sharti utp->state &= ~UTP_ST_ACTIVE; 387116258Sharti} 388116258Sharti 389116258Sharti/* 390116258Sharti * Handle the sysctls 391116258Sharti */ 392116258Shartistatic int 393116258Shartiutopia_sysctl_regs(SYSCTL_HANDLER_ARGS) 394116258Sharti{ 395116258Sharti struct utopia *utp = (struct utopia *)arg1; 396116258Sharti int error; 397116258Sharti u_int n; 398116258Sharti uint8_t *val; 399116258Sharti uint8_t new[3]; 400116258Sharti 401116258Sharti if ((n = utp->chip->nregs) == 0) 402116258Sharti return (EIO); 403116258Sharti val = malloc(sizeof(uint8_t) * n, M_TEMP, M_WAITOK); 404116258Sharti 405116258Sharti UTP_LOCK(utp); 406142384Sharti error = UTP_READREGS(utp, 0, val, &n); 407116258Sharti UTP_UNLOCK(utp); 408116258Sharti 409116258Sharti if (error) { 410116258Sharti free(val, M_TEMP); 411116258Sharti return (error); 412116258Sharti } 413116258Sharti 414116258Sharti error = SYSCTL_OUT(req, val, sizeof(uint8_t) * n); 415116258Sharti free(val, M_TEMP); 416116258Sharti if (error != 0 || req->newptr == NULL) 417116258Sharti return (error); 418116258Sharti 419116258Sharti error = SYSCTL_IN(req, new, sizeof(new)); 420116258Sharti if (error) 421116258Sharti return (error); 422116258Sharti 423116258Sharti UTP_LOCK(utp); 424142384Sharti error = UTP_WRITEREG(utp, new[0], new[1], new[2]); 425116258Sharti UTP_UNLOCK(utp); 426116258Sharti 427116258Sharti return (error); 428116258Sharti} 429116258Sharti 430117552Shartistatic int 431117552Shartiutopia_sysctl_stats(SYSCTL_HANDLER_ARGS) 432117552Sharti{ 433117552Sharti struct utopia *utp = (struct utopia *)arg1; 434117552Sharti void *val; 435117552Sharti int error; 436117552Sharti 437117552Sharti val = malloc(sizeof(utp->stats), M_TEMP, M_WAITOK); 438117552Sharti 439117552Sharti UTP_LOCK(utp); 440117552Sharti bcopy(&utp->stats, val, sizeof(utp->stats)); 441117552Sharti if (req->newptr != NULL) 442117552Sharti bzero((char *)&utp->stats + sizeof(utp->stats.version), 443117552Sharti sizeof(utp->stats) - sizeof(utp->stats.version)); 444117552Sharti UTP_UNLOCK(utp); 445117552Sharti 446117552Sharti error = SYSCTL_OUT(req, val, sizeof(utp->stats)); 447117552Sharti if (error && req->newptr != NULL) 448117552Sharti bcopy(val, &utp->stats, sizeof(utp->stats)); 449174318Sphilip free(val, M_TEMP); 450117552Sharti 451117552Sharti /* ignore actual new value */ 452117552Sharti 453117552Sharti return (error); 454117552Sharti} 455117552Sharti 456116258Sharti/* 457116258Sharti * Handle the loopback sysctl 458116258Sharti */ 459116258Shartistatic int 460116258Shartiutopia_sysctl_loopback(SYSCTL_HANDLER_ARGS) 461116258Sharti{ 462116258Sharti struct utopia *utp = (struct utopia *)arg1; 463116258Sharti int error; 464116258Sharti u_int loopback; 465116258Sharti 466116258Sharti error = SYSCTL_OUT(req, &utp->loopback, sizeof(u_int)); 467116258Sharti if (error != 0 || req->newptr == NULL) 468116258Sharti return (error); 469116258Sharti 470116258Sharti error = SYSCTL_IN(req, &loopback, sizeof(u_int)); 471116258Sharti if (error) 472116258Sharti return (error); 473116258Sharti 474116258Sharti UTP_LOCK(utp); 475116258Sharti error = utopia_set_loopback(utp, loopback); 476116258Sharti UTP_UNLOCK(utp); 477116258Sharti 478116258Sharti return (error); 479116258Sharti} 480116258Sharti 481116258Sharti/* 482116258Sharti * Handle the type sysctl 483116258Sharti */ 484116258Shartistatic int 485116258Shartiutopia_sysctl_type(SYSCTL_HANDLER_ARGS) 486116258Sharti{ 487116258Sharti struct utopia *utp = (struct utopia *)arg1; 488116258Sharti 489116258Sharti return (SYSCTL_OUT(req, &utp->chip->type, sizeof(utp->chip->type))); 490116258Sharti} 491116258Sharti 492116258Sharti/* 493116258Sharti * Handle the name sysctl 494116258Sharti */ 495116258Shartistatic int 496116258Shartiutopia_sysctl_name(SYSCTL_HANDLER_ARGS) 497116258Sharti{ 498116258Sharti struct utopia *utp = (struct utopia *)arg1; 499116258Sharti 500116258Sharti return (SYSCTL_OUT(req, utp->chip->name, strlen(utp->chip->name) + 1)); 501116258Sharti} 502116258Sharti 503116258Sharti/* 504116258Sharti * Initialize the state. This is called from the drivers attach 505116258Sharti * function. The mutex must be already initialized. 506116258Sharti */ 507116258Shartiint 508116258Shartiutopia_attach(struct utopia *utp, struct ifatm *ifatm, struct ifmedia *media, 509116258Sharti struct mtx *lock, struct sysctl_ctx_list *ctx, 510116258Sharti struct sysctl_oid_list *children, const struct utopia_methods *m) 511116258Sharti{ 512116258Sharti 513116258Sharti bzero(utp, sizeof(*utp)); 514116258Sharti utp->ifatm = ifatm; 515116258Sharti utp->methods = m; 516116258Sharti utp->media = media; 517116258Sharti utp->lock = lock; 518142384Sharti utp->chip = &utopia_chip_unknown; 519117552Sharti utp->stats.version = 1; 520116258Sharti 521116258Sharti ifmedia_init(media, 522116258Sharti IFM_ATM_SDH | IFM_ATM_UNASSIGNED | IFM_ATM_NOSCRAMB, 523116258Sharti utopia_media_change, utopia_media_status); 524116258Sharti 525116258Sharti if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_regs", 526116258Sharti CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_regs, "S", 527116258Sharti "phy registers") == NULL) 528116258Sharti return (-1); 529116258Sharti 530116258Sharti if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_loopback", 531116258Sharti CTLFLAG_RW | CTLTYPE_UINT, utp, 0, utopia_sysctl_loopback, "IU", 532116258Sharti "phy loopback mode") == NULL) 533116258Sharti return (-1); 534116258Sharti 535116258Sharti if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_type", 536116258Sharti CTLFLAG_RD | CTLTYPE_UINT, utp, 0, utopia_sysctl_type, "IU", 537116258Sharti "phy type") == NULL) 538116258Sharti return (-1); 539116258Sharti 540116258Sharti if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_name", 541116258Sharti CTLFLAG_RD | CTLTYPE_STRING, utp, 0, utopia_sysctl_name, "A", 542116258Sharti "phy name") == NULL) 543116258Sharti return (-1); 544116258Sharti 545117552Sharti if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_stats", 546117552Sharti CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_stats, "S", 547117552Sharti "phy statistics") == NULL) 548117552Sharti return (-1); 549117552Sharti 550118202Sharti if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_state", 551118202Sharti CTLFLAG_RD, &utp->state, 0, "phy state") == NULL) 552118202Sharti return (-1); 553118202Sharti 554118202Sharti if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_carrier", 555118202Sharti CTLFLAG_RD, &utp->carrier, 0, "phy carrier") == NULL) 556118202Sharti return (-1); 557118202Sharti 558116258Sharti UTP_WLOCK_LIST(); 559116258Sharti LIST_INSERT_HEAD(&utopia_list, utp, link); 560116258Sharti UTP_WUNLOCK_LIST(); 561116258Sharti 562116258Sharti utp->state |= UTP_ST_ATTACHED; 563116258Sharti return (0); 564116258Sharti} 565116258Sharti 566116258Sharti/* 567116258Sharti * Detach. We set a flag here, wakeup the daemon and let him do it. 568116258Sharti * Here we need the lock for synchronisation with the daemon. 569116258Sharti */ 570116258Shartivoid 571116258Shartiutopia_detach(struct utopia *utp) 572116258Sharti{ 573116258Sharti 574116258Sharti UTP_LOCK_ASSERT(utp); 575116258Sharti if (utp->state & UTP_ST_ATTACHED) { 576116258Sharti utp->state |= UTP_ST_DETACH; 577116258Sharti while (utp->state & UTP_ST_DETACH) { 578116258Sharti wakeup(&utopia_list); 579116258Sharti msleep(utp, utp->lock, PZERO, "utopia_detach", hz); 580116258Sharti } 581116258Sharti } 582116258Sharti} 583116258Sharti 584116258Sharti/* 585116258Sharti * The carrier state kernel proc for those adapters that do not interrupt. 586116258Sharti * 587116258Sharti * We assume, that utopia_attach can safely add a new utopia while we are going 588116258Sharti * through the list without disturbing us (we lock the list while getting 589116258Sharti * the address of the first element, adding is always done at the head). 590116258Sharti * Removing is entirely handled here. 591116258Sharti */ 592116258Shartistatic void 593116258Shartiutopia_daemon(void *arg __unused) 594116258Sharti{ 595116258Sharti struct utopia *utp, *next; 596116258Sharti 597116258Sharti UTP_RLOCK_LIST(); 598116258Sharti while (utopia_kproc != NULL) { 599116258Sharti utp = LIST_FIRST(&utopia_list); 600116258Sharti UTP_RUNLOCK_LIST(); 601116258Sharti 602116258Sharti while (utp != NULL) { 603116258Sharti mtx_lock(&Giant); /* XXX depend on MPSAFE */ 604116258Sharti UTP_LOCK(utp); 605116258Sharti next = LIST_NEXT(utp, link); 606116258Sharti if (utp->state & UTP_ST_DETACH) { 607116258Sharti LIST_REMOVE(utp, link); 608116258Sharti utp->state &= ~UTP_ST_DETACH; 609116258Sharti wakeup_one(utp); 610117552Sharti } else if (utp->state & UTP_ST_ACTIVE) { 611117552Sharti if (utp->flags & UTP_FL_POLL_CARRIER) 612117552Sharti utopia_update_carrier(utp); 613117552Sharti utopia_update_stats(utp); 614116258Sharti } 615116258Sharti UTP_UNLOCK(utp); 616116258Sharti mtx_unlock(&Giant); /* XXX depend on MPSAFE */ 617116258Sharti utp = next; 618116258Sharti } 619116258Sharti 620116258Sharti UTP_RLOCK_LIST(); 621117552Sharti msleep(&utopia_list, &utopia_list_mtx, PZERO, "*idle*", hz); 622116258Sharti } 623116258Sharti wakeup_one(&utopia_list); 624116258Sharti UTP_RUNLOCK_LIST(); 625172836Sjulian kproc_exit(0); 626116258Sharti} 627116258Sharti 628116258Sharti/* 629116258Sharti * Module initialisation 630116258Sharti */ 631116258Shartistatic int 632116258Shartiutopia_mod_init(module_t mod, int what, void *arg) 633116258Sharti{ 634116258Sharti int err; 635116258Sharti struct proc *kp; 636116258Sharti 637116258Sharti switch (what) { 638116258Sharti 639116258Sharti case MOD_LOAD: 640116258Sharti mtx_init(&utopia_list_mtx, "utopia list mutex", NULL, MTX_DEF); 641172836Sjulian err = kproc_create(utopia_daemon, NULL, &utopia_kproc, 642116258Sharti RFHIGHPID, 0, "utopia"); 643116258Sharti if (err != 0) { 644116258Sharti printf("cannot created utopia thread %d\n", err); 645116258Sharti return (err); 646116258Sharti } 647116258Sharti break; 648116258Sharti 649116258Sharti case MOD_UNLOAD: 650116258Sharti UTP_WLOCK_LIST(); 651116258Sharti if ((kp = utopia_kproc) != NULL) { 652116258Sharti utopia_kproc = NULL; 653116258Sharti wakeup_one(&utopia_list); 654116258Sharti PROC_LOCK(kp); 655116258Sharti UTP_WUNLOCK_LIST(); 656116258Sharti msleep(kp, &kp->p_mtx, PWAIT, "utopia_destroy", 0); 657116258Sharti PROC_UNLOCK(kp); 658116258Sharti } else 659116258Sharti UTP_WUNLOCK_LIST(); 660116258Sharti mtx_destroy(&utopia_list_mtx); 661116258Sharti break; 662132199Sphk default: 663132199Sphk return (EOPNOTSUPP); 664116258Sharti } 665116258Sharti return (0); 666116258Sharti} 667116258Sharti 668116258Shartistatic moduledata_t utopia_mod = { 669116258Sharti "utopia", 670116258Sharti utopia_mod_init, 671241394Skevlo 0 672116258Sharti}; 673116258Sharti 674116258ShartiDECLARE_MODULE(utopia, utopia_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 675116258ShartiMODULE_VERSION(utopia, 1); 676