utopia.c revision 118202
1116258Sharti/* 2116258Sharti * Copyright (c) 2003 3116258Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4116258Sharti * All rights reserved. 5116258Sharti * 6116258Sharti * Redistribution and use in source and binary forms, with or without 7116258Sharti * modification, are permitted provided that the following conditions 8116258Sharti * are met: 9116258Sharti * 1. Redistributions of source code must retain the above copyright 10116258Sharti * notice, this list of conditions and the following disclaimer. 11116258Sharti * 2. Redistributions in binary form must reproduce the above copyright 12116258Sharti * notice, this list of conditions and the following disclaimer in the 13116258Sharti * documentation and/or other materials provided with the distribution. 14116258Sharti * 15116258Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16116258Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17116258Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18116258Sharti * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19116258Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20116258Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21116258Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22116258Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23116258Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24116258Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25116258Sharti * SUCH DAMAGE. 26116258Sharti * 27116258Sharti * Author: Hartmut Brandt <harti@freebsd.org> 28116258Sharti */ 29116258Sharti 30116258Sharti#include <sys/cdefs.h> 31116258Sharti__FBSDID("$FreeBSD: head/sys/dev/utopia/utopia.c 118202 2003-07-30 08:35:58Z harti $"); 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> 41116258Sharti#include <sys/sysctl.h> 42116258Sharti#include <sys/lock.h> 43116258Sharti#include <sys/mutex.h> 44116258Sharti#include <sys/socket.h> 45116258Sharti 46116258Sharti#include <net/if.h> 47116258Sharti#include <net/if_var.h> 48116258Sharti#include <net/if_media.h> 49116258Sharti#include <net/if_atm.h> 50116258Sharti 51116258Sharti#include <dev/utopia/suni.h> 52116258Sharti#include <dev/utopia/idtphy.h> 53116258Sharti#include <dev/utopia/utopia.h> 54116258Sharti 55116258Sharti#define READREGS(UTOPIA, REG, VALP, NP) \ 56116258Sharti (UTOPIA)->methods->readregs((UTOPIA)->ifatm, REG, VALP, NP) 57116258Sharti#define WRITEREG(UTOPIA, REG, MASK, VAL) \ 58116258Sharti (UTOPIA)->methods->writereg((UTOPIA)->ifatm, REG, MASK, VAL) 59116258Sharti 60116258Sharti/* 61116258Sharti * Global list of all registered interfaces 62116258Sharti */ 63116258Shartistatic struct mtx utopia_list_mtx; 64116258Shartistatic LIST_HEAD(, utopia) utopia_list = LIST_HEAD_INITIALIZER(utopia_list); 65116258Sharti 66116258Sharti#define UTP_RLOCK_LIST() mtx_lock(&utopia_list_mtx) 67116258Sharti#define UTP_RUNLOCK_LIST() mtx_unlock(&utopia_list_mtx) 68116258Sharti#define UTP_WLOCK_LIST() mtx_lock(&utopia_list_mtx) 69116258Sharti#define UTP_WUNLOCK_LIST() mtx_unlock(&utopia_list_mtx) 70116258Sharti 71116258Sharti#define UTP_LOCK(UTP) mtx_lock((UTP)->lock) 72116258Sharti#define UTP_UNLOCK(UTP) mtx_unlock((UTP)->lock) 73116258Sharti#define UTP_LOCK_ASSERT(UTP) mtx_assert((UTP)->lock, MA_OWNED) 74116258Sharti 75116258Shartistatic struct proc *utopia_kproc; 76116258Sharti 77116258Shartistatic void utopia_dump(struct utopia *) __unused; 78116258Sharti 79116258Sharti/* 80117552Sharti * Statistics update inlines 81117552Sharti */ 82117552Shartistatic uint32_t 83117552Shartiutp_update(struct utopia *utp, u_int reg, u_int nreg, uint32_t mask) 84117552Sharti{ 85117552Sharti int err; 86117552Sharti u_int n; 87117552Sharti uint8_t regs[4]; 88117552Sharti uint32_t val; 89117552Sharti 90117552Sharti n = nreg; 91117552Sharti if ((err = READREGS(utp, reg, regs, &n)) != 0) { 92117552Sharti#ifdef DIAGNOSTIC 93117552Sharti printf("%s: register read error %s(%u,%u): %d\n", __func__, 94117552Sharti utp->chip->name, reg, nreg, err); 95117552Sharti#endif 96117552Sharti return (0); 97117552Sharti } 98117552Sharti if (n < nreg) { 99117552Sharti#ifdef DIAGNOSTIC 100117552Sharti printf("%s: got only %u regs %s(%u,%u): %d\n", __func__, n, 101117552Sharti utp->chip->name, reg, nreg, err); 102117552Sharti#endif 103117552Sharti return (0); 104117552Sharti } 105117552Sharti val = 0; 106117552Sharti for (n = nreg; n > 0; n--) { 107117552Sharti val <<= 8; 108117552Sharti val |= regs[n - 1]; 109117552Sharti } 110117552Sharti return (val & mask); 111117552Sharti} 112117552Sharti 113117552Sharti#define UPDATE8(UTP, REG) utp_update(UTP, REG, 1, 0xff) 114117552Sharti#define UPDATE12(UTP, REG) utp_update(UTP, REG, 2, 0xfff) 115117552Sharti#define UPDATE16(UTP, REG) utp_update(UTP, REG, 2, 0xffff) 116117552Sharti#define UPDATE19(UTP, REG) utp_update(UTP, REG, 3, 0x7ffff) 117117552Sharti#define UPDATE20(UTP, REG) utp_update(UTP, REG, 3, 0xfffff) 118117552Sharti#define UPDATE21(UTP, REG) utp_update(UTP, REG, 3, 0x1fffff) 119117552Sharti 120117552Sharti/* 121116258Sharti * Debugging - dump all registers. 122116258Sharti */ 123116258Shartistatic void 124116258Shartiutopia_dump(struct utopia *utp) 125116258Sharti{ 126116258Sharti uint8_t regs[256]; 127116258Sharti u_int n = 256, i; 128116258Sharti int err; 129116258Sharti 130116258Sharti if ((err = READREGS(utp, SUNI_REGO_MRESET, regs, &n)) != 0) { 131116258Sharti printf("SUNI read error %d\n", err); 132116258Sharti return; 133116258Sharti } 134116258Sharti for (i = 0; i < n; i++) { 135116258Sharti if (i % 16 == 0) 136116258Sharti printf("%02x:", i); 137116258Sharti if (i % 16 == 8) 138116258Sharti printf(" "); 139116258Sharti printf(" %02x", regs[i]); 140116258Sharti if (i % 16 == 15) 141116258Sharti printf("\n"); 142116258Sharti } 143116258Sharti if (i % 16 != 0) 144116258Sharti printf("\n"); 145116258Sharti} 146116258Sharti 147116258Sharti/* 148116258Sharti * Update the carrier status 149116258Sharti */ 150116258Shartistatic void 151116258Shartiutopia_check_carrier(struct utopia *utp, u_int carr_ok) 152116258Sharti{ 153116258Sharti int old; 154116258Sharti 155116258Sharti old = utp->carrier; 156116258Sharti if (carr_ok) { 157116258Sharti /* carrier */ 158116258Sharti utp->carrier = UTP_CARR_OK; 159116258Sharti if (old != UTP_CARR_OK) { 160116258Sharti if_printf(&utp->ifatm->ifnet, "carrier detected\n"); 161118202Sharti ATMEV_SEND_IFSTATE_CHANGED(utp->ifatm, 1); 162116258Sharti } 163116258Sharti } else { 164116258Sharti /* no carrier */ 165116258Sharti utp->carrier = UTP_CARR_LOST; 166116258Sharti if (old == UTP_CARR_OK) { 167116258Sharti if_printf(&utp->ifatm->ifnet, "carrier lost\n"); 168118202Sharti ATMEV_SEND_IFSTATE_CHANGED(utp->ifatm, 0); 169116258Sharti } 170116258Sharti } 171116258Sharti} 172116258Sharti 173116258Shartistatic int 174116258Shartiutopia_update_carrier_default(struct utopia *utp) 175116258Sharti{ 176116258Sharti int err; 177116258Sharti uint8_t reg; 178116258Sharti u_int n = 1; 179116258Sharti 180116258Sharti if ((err = READREGS(utp, SUNI_REGO_RSOPSIS, ®, &n)) != 0) { 181116258Sharti utp->carrier = UTP_CARR_UNKNOWN; 182116258Sharti return (err); 183116258Sharti } 184116258Sharti utopia_check_carrier(utp, !(reg & SUNI_REGM_RSOPSIS_LOSV)); 185116258Sharti return (0); 186116258Sharti} 187116258Sharti 188116258Sharti/* 189116258Sharti * enable/disable scrambling 190116258Sharti */ 191116258Shartistatic int 192116258Shartiutopia_set_noscramb_default(struct utopia *utp, int noscramb) 193116258Sharti{ 194116258Sharti int err; 195116258Sharti 196116258Sharti if (noscramb) { 197116258Sharti err = WRITEREG(utp, SUNI_REGO_TACPCTRL, 198116258Sharti SUNI_REGM_TACPCTRL_DSCR, SUNI_REGM_TACPCTRL_DSCR); 199116258Sharti if (err) 200116258Sharti return (err); 201116258Sharti err = WRITEREG(utp, SUNI_REGO_RACPCTRL, 202116258Sharti SUNI_REGM_RACPCTRL_DDSCR, SUNI_REGM_RACPCTRL_DDSCR); 203116258Sharti if (err) 204116258Sharti return (err); 205116258Sharti utp->state |= UTP_ST_NOSCRAMB; 206116258Sharti } else { 207116258Sharti err = WRITEREG(utp, SUNI_REGO_TACPCTRL, 208116258Sharti SUNI_REGM_TACPCTRL_DSCR, 0); 209116258Sharti if (err) 210116258Sharti return (err); 211116258Sharti err = WRITEREG(utp, SUNI_REGO_RACPCTRL, 212116258Sharti SUNI_REGM_RACPCTRL_DDSCR, 0); 213116258Sharti if (err) 214116258Sharti return (err); 215116258Sharti utp->state &= ~UTP_ST_NOSCRAMB; 216116258Sharti } 217116258Sharti return (0); 218116258Sharti} 219116258Sharti 220116258Sharti/* 221116258Sharti * set SONET/SDH mode 222116258Sharti */ 223116258Shartistatic int 224116258Shartiutopia_set_sdh_default(struct utopia *utp, int sdh) 225116258Sharti{ 226116258Sharti int err; 227116258Sharti 228116258Sharti if (sdh) 229116258Sharti err = WRITEREG(utp, SUNI_REGO_TPOPAPTR + 1, 230116258Sharti SUNI_REGM_TPOPAPTR_S, 231116258Sharti SUNI_REGM_SDH << SUNI_REGS_TPOPAPTR_S); 232116258Sharti else 233116258Sharti err = WRITEREG(utp, SUNI_REGO_TPOPAPTR + 1, 234116258Sharti SUNI_REGM_TPOPAPTR_S, 235116258Sharti SUNI_REGM_SONET << SUNI_REGS_TPOPAPTR_S); 236116258Sharti if (err != 0) 237116258Sharti return (err); 238116258Sharti 239116258Sharti utp->state &= ~UTP_ST_SDH; 240116258Sharti if (sdh) 241116258Sharti utp->state |= UTP_ST_SDH; 242116258Sharti 243116258Sharti return (0); 244116258Sharti} 245116258Sharti 246116258Sharti/* 247116258Sharti * set idle/unassigned cells 248116258Sharti */ 249116258Shartistatic int 250116258Shartiutopia_set_unass_default(struct utopia *utp, int unass) 251116258Sharti{ 252116258Sharti int err; 253116258Sharti 254116258Sharti if (unass) 255116258Sharti err = WRITEREG(utp, SUNI_REGO_TACPIDLEH, 256116258Sharti 0xff, (0 << SUNI_REGS_TACPIDLEH_CLP)); 257116258Sharti else 258116258Sharti err = WRITEREG(utp, SUNI_REGO_TACPIDLEH, 259116258Sharti 0xff, (1 << SUNI_REGS_TACPIDLEH_CLP)); 260116258Sharti if (err != 0) 261116258Sharti return (err); 262116258Sharti 263116258Sharti utp->state &= ~UTP_ST_UNASS; 264116258Sharti if (unass) 265116258Sharti utp->state |= UTP_ST_UNASS; 266116258Sharti 267116258Sharti return (0); 268116258Sharti} 269116258Sharti 270116258Sharti/* 271116258Sharti * Set loopback mode for the Lite 272116258Sharti */ 273116258Shartistatic int 274116258Shartiutopia_set_loopback_lite(struct utopia *utp, u_int mode) 275116258Sharti{ 276116258Sharti int err; 277116258Sharti uint32_t val; 278116258Sharti u_int nmode; 279116258Sharti 280116258Sharti val = 0; 281116258Sharti nmode = mode; 282116258Sharti if (mode & UTP_LOOP_TIME) { 283116258Sharti nmode &= ~UTP_LOOP_TIME; 284116258Sharti val |= SUNI_REGM_MCTRL_LOOPT; 285116258Sharti } 286116258Sharti if (mode & UTP_LOOP_DIAG) { 287116258Sharti nmode &= ~UTP_LOOP_DIAG; 288116258Sharti val |= SUNI_REGM_MCTRL_DLE; 289116258Sharti } 290116258Sharti if (mode & UTP_LOOP_LINE) { 291116258Sharti nmode &= ~UTP_LOOP_LINE; 292116258Sharti if (val & SUNI_REGM_MCTRL_DLE) 293116258Sharti return (EINVAL); 294116258Sharti val |= SUNI_REGM_MCTRL_LLE; 295116258Sharti } 296116258Sharti if (nmode != 0) 297116258Sharti return (EINVAL); 298116258Sharti 299116258Sharti err = WRITEREG(utp, SUNI_REGO_MCTRL, 300116258Sharti SUNI_REGM_MCTRL_LLE | SUNI_REGM_MCTRL_DLE | SUNI_REGM_MCTRL_LOOPT, 301116258Sharti val); 302116258Sharti if (err) 303116258Sharti return (err); 304116258Sharti utp->loopback = mode; 305116258Sharti 306116258Sharti return (0); 307116258Sharti} 308116258Sharti 309116258Sharti/* 310116258Sharti * Set loopback mode for the Ultra 311116258Sharti */ 312116258Shartistatic int 313116258Shartiutopia_set_loopback_ultra(struct utopia *utp, u_int mode) 314116258Sharti{ 315116258Sharti int err; 316116258Sharti uint32_t val; 317116258Sharti u_int nmode; 318116258Sharti 319116258Sharti val = 0; 320116258Sharti nmode = mode; 321116258Sharti if (mode & UTP_LOOP_TIME) { 322116258Sharti nmode &= ~UTP_LOOP_TIME; 323116258Sharti val |= SUNI_REGM_MCTRL_LOOPT; 324116258Sharti } 325116258Sharti if (mode & UTP_LOOP_DIAG) { 326116258Sharti nmode &= ~UTP_LOOP_DIAG; 327116258Sharti if (val & SUNI_REGM_MCTRL_LOOPT) 328116258Sharti return (EINVAL); 329116258Sharti val |= SUNI_REGM_MCTRL_SDLE; 330116258Sharti } 331116258Sharti if (mode & UTP_LOOP_LINE) { 332116258Sharti nmode &= ~UTP_LOOP_LINE; 333116258Sharti if (val & (SUNI_REGM_MCTRL_LOOPT | SUNI_REGM_MCTRL_SDLE)) 334116258Sharti return (EINVAL); 335116258Sharti val |= SUNI_REGM_MCTRL_LLE; 336116258Sharti } 337116258Sharti if (mode & UTP_LOOP_PARAL) { 338116258Sharti nmode &= ~UTP_LOOP_PARAL; 339116258Sharti val |= SUNI_REGM_MCTRL_PDLE; 340116258Sharti } 341116258Sharti if (mode & UTP_LOOP_TWIST) { 342116258Sharti nmode &= ~UTP_LOOP_TWIST; 343116258Sharti val |= SUNI_REGM_MCTRL_TPLE; 344116258Sharti } 345116258Sharti if (nmode != 0) 346116258Sharti return (EINVAL); 347116258Sharti 348116258Sharti err = WRITEREG(utp, SUNI_REGO_MCTRL, 349116258Sharti SUNI_REGM_MCTRL_LLE | SUNI_REGM_MCTRL_SDLE | SUNI_REGM_MCTRL_LOOPT | 350116258Sharti SUNI_REGM_MCTRL_PDLE | SUNI_REGM_MCTRL_TPLE, val); 351116258Sharti if (err) 352116258Sharti return (err); 353116258Sharti utp->loopback = mode; 354116258Sharti 355116258Sharti return (0); 356116258Sharti} 357116258Sharti 358116258Sharti/* 359116258Sharti * Set loopback mode for the Ultra 360116258Sharti */ 361116258Shartistatic int 362116258Shartiutopia_set_loopback_622(struct utopia *utp, u_int mode) 363116258Sharti{ 364116258Sharti int err; 365116258Sharti uint32_t val; 366116258Sharti uint8_t config; 367116258Sharti int smode; 368116258Sharti u_int nmode; 369116258Sharti u_int n = 1; 370116258Sharti 371116258Sharti val = 0; 372116258Sharti nmode = mode; 373116258Sharti if (mode & UTP_LOOP_PATH) { 374116258Sharti nmode &= ~UTP_LOOP_PATH; 375116258Sharti val |= SUNI_REGM_MCTRLM_DPLE; 376116258Sharti } 377116258Sharti 378116258Sharti err = READREGS(utp, SUNI_REGO_MCONFIG, &config, &n); 379116258Sharti if (err != 0) 380116258Sharti return (err); 381116258Sharti smode = ((config & SUNI_REGM_MCONFIG_TMODE_622) == 382116258Sharti SUNI_REGM_MCONFIG_TMODE_STS1_BIT && 383116258Sharti (config & SUNI_REGM_MCONFIG_RMODE_622) == 384116258Sharti SUNI_REGM_MCONFIG_RMODE_STS1_BIT); 385116258Sharti 386116258Sharti if (mode & UTP_LOOP_TIME) { 387116258Sharti if (!smode) 388116258Sharti return (EINVAL); 389116258Sharti nmode &= ~UTP_LOOP_TIME; 390116258Sharti val |= SUNI_REGM_MCTRLM_LOOPT; 391116258Sharti } 392116258Sharti if (mode & UTP_LOOP_DIAG) { 393116258Sharti nmode &= ~UTP_LOOP_DIAG; 394116258Sharti if (val & SUNI_REGM_MCTRLM_LOOPT) 395116258Sharti return (EINVAL); 396116258Sharti val |= SUNI_REGM_MCTRLM_DLE; 397116258Sharti } 398116258Sharti if (mode & UTP_LOOP_LINE) { 399116258Sharti nmode &= ~UTP_LOOP_LINE; 400116258Sharti if (val & (SUNI_REGM_MCTRLM_LOOPT | SUNI_REGM_MCTRLM_DLE)) 401116258Sharti return (EINVAL); 402116258Sharti val |= SUNI_REGM_MCTRLM_LLE; 403116258Sharti } 404116258Sharti if (nmode != 0) 405116258Sharti return (EINVAL); 406116258Sharti 407116258Sharti err = WRITEREG(utp, SUNI_REGO_MCTRLM, 408116258Sharti SUNI_REGM_MCTRLM_LLE | SUNI_REGM_MCTRLM_DLE | 409116258Sharti SUNI_REGM_MCTRLM_DPLE | SUNI_REGM_MCTRL_LOOPT, val); 410116258Sharti if (err) 411116258Sharti return (err); 412116258Sharti utp->loopback = mode; 413116258Sharti 414116258Sharti return (0); 415116258Sharti} 416116258Sharti 417116258Sharti/* 418116258Sharti * Set the SUNI chip to reflect the current state in utopia. 419116258Sharti * Assume, that the chip has been reset. 420116258Sharti */ 421116258Shartistatic int 422116258Shartiutopia_set_chip(struct utopia *utp) 423116258Sharti{ 424116258Sharti int err = 0; 425116258Sharti 426116258Sharti /* set sonet/sdh */ 427116258Sharti err |= utopia_set_sdh(utp, utp->state & UTP_ST_SDH); 428116258Sharti 429116258Sharti /* unassigned or idle cells */ 430116258Sharti err |= utopia_set_unass(utp, utp->state & UTP_ST_UNASS); 431116258Sharti err |= WRITEREG(utp, SUNI_REGO_TACPIDLEP, 0xff, 0x6a); 432116258Sharti 433116258Sharti /* loopback */ 434116258Sharti err |= utopia_set_loopback(utp, utp->loopback); 435116258Sharti 436116258Sharti /* update carrier state */ 437116258Sharti err |= utopia_update_carrier(utp); 438116258Sharti 439116258Sharti /* enable interrupts on LOS */ 440116258Sharti err |= WRITEREG(utp, SUNI_REGO_RSOPCIE, 441116258Sharti SUNI_REGM_RSOPCIE_LOSE, SUNI_REGM_RSOPCIE_LOSE); 442116258Sharti 443116258Sharti return (err ? EIO : 0); 444116258Sharti} 445116258Sharti 446116258Sharti/* 447116258Sharti * Reset the SUNI chip to reflect the current state of utopia. 448116258Sharti */ 449116258Shartistatic int 450116258Shartiutopia_reset_default(struct utopia *utp) 451116258Sharti{ 452116258Sharti int err = 0; 453116258Sharti 454116258Sharti if (!(utp->flags & UTP_FL_NORESET)) { 455116258Sharti err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET, 456116258Sharti SUNI_REGM_MRESET_RESET); 457116258Sharti err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET, 458116258Sharti 0); 459116258Sharti } 460116258Sharti 461116258Sharti /* disable test mode */ 462116258Sharti err |= WRITEREG(utp, SUNI_REGO_MTEST, 0xff, 0x00); 463116258Sharti 464116258Sharti err |= utopia_set_chip(utp); 465116258Sharti 466116258Sharti return (err ? EIO : 0); 467116258Sharti} 468116258Sharti 469116258Sharti/* 470116258Sharti * Reset the SUNI chip to reflect the current state of utopia. 471116258Sharti */ 472116258Shartistatic int 473116258Shartiutopia_reset_622(struct utopia *utp) 474116258Sharti{ 475116258Sharti int err = 0; 476116258Sharti 477116258Sharti if (!(utp->flags & UTP_FL_NORESET)) { 478116258Sharti err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET, 479116258Sharti SUNI_REGM_MRESET_RESET); 480116258Sharti err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET, 481116258Sharti 0); 482116258Sharti } 483116258Sharti 484116258Sharti /* disable test mode */ 485116258Sharti err |= WRITEREG(utp, SUNI_REGO_MTEST, 0xff, 486116258Sharti SUNI_REGM_MTEST_DS27_53_622); 487116258Sharti 488116258Sharti err |= utopia_set_chip(utp); 489116258Sharti 490116258Sharti return (err ? EIO : 0); 491116258Sharti} 492116258Sharti 493116258Sharti/* 494116258Sharti * Handle interrupt on lite chip 495116258Sharti */ 496116258Shartistatic void 497116258Shartiutopia_intr_default(struct utopia *utp) 498116258Sharti{ 499116258Sharti uint8_t regs[SUNI_REGO_MTEST]; 500116258Sharti u_int n = SUNI_REGO_MTEST; 501116258Sharti int err; 502116258Sharti 503116258Sharti /* Read all registers. This acks the interrupts */ 504116258Sharti if ((err = READREGS(utp, SUNI_REGO_MRESET, regs, &n)) != 0) { 505116258Sharti printf("SUNI read error %d\n", err); 506116258Sharti return; 507116258Sharti } 508116258Sharti if (n <= SUNI_REGO_RSOPSIS) { 509116258Sharti printf("%s: could not read RSOPSIS", __func__); 510116258Sharti return; 511116258Sharti } 512116258Sharti /* check for LOSI (loss of signal) */ 513116258Sharti if ((regs[SUNI_REGO_MISTATUS] & SUNI_REGM_MISTATUS_RSOPI) && 514116258Sharti (regs[SUNI_REGO_RSOPSIS] & SUNI_REGM_RSOPSIS_LOSI)) 515116258Sharti utopia_check_carrier(utp, !(regs[SUNI_REGO_RSOPSIS] 516116258Sharti & SUNI_REGM_RSOPSIS_LOSV)); 517116258Sharti} 518116258Sharti 519117552Sharti/* 520117552Sharti * Update statistics from a SUNI/LITE or SUNI/ULTRA 521117552Sharti */ 522117552Shartistatic void 523117552Shartisuni_lite_update_stats(struct utopia *utp) 524117552Sharti{ 525117552Sharti int err; 526117552Sharti 527117552Sharti /* write to the master if we can */ 528117552Sharti if (!(utp->flags & UTP_FL_NORESET)) { 529117552Sharti err = WRITEREG(utp, SUNI_REGO_MRESET, 0, 0); 530117552Sharti } else { 531117552Sharti err = WRITEREG(utp, SUNI_REGO_RSOP_BIP8, 0, 0); 532117552Sharti err |= WRITEREG(utp, SUNI_REGO_RLOPBIP8_24, 0, 0); 533117552Sharti err |= WRITEREG(utp, SUNI_REGO_RPOPBIP8, 0, 0); 534117552Sharti err |= WRITEREG(utp, SUNI_REGO_RACPCHCS, 0, 0); 535117552Sharti err |= WRITEREG(utp, SUNI_REGO_TACPCNT, 0, 0); 536117552Sharti 537117552Sharti } 538117552Sharti if (err) { 539117552Sharti#ifdef DIAGNOSTIC 540117552Sharti printf("%s: register write error %s: %d\n", __func__, 541117552Sharti utp->chip->name, err); 542117552Sharti#endif 543117552Sharti return; 544117552Sharti } 545117552Sharti 546117552Sharti DELAY(8); 547117552Sharti 548117552Sharti utp->stats.rx_sbip += UPDATE16(utp, SUNI_REGO_RSOP_BIP8); 549117552Sharti utp->stats.rx_lbip += UPDATE20(utp, SUNI_REGO_RLOPBIP8_24); 550117552Sharti utp->stats.rx_lfebe += UPDATE20(utp, SUNI_REGO_RLOPFEBE); 551117552Sharti utp->stats.rx_pbip += UPDATE16(utp, SUNI_REGO_RPOPBIP8); 552117552Sharti utp->stats.rx_pfebe += UPDATE16(utp, SUNI_REGO_RPOPFEBE); 553117552Sharti utp->stats.rx_corr += UPDATE8(utp, SUNI_REGO_RACPCHCS); 554117552Sharti utp->stats.rx_uncorr += UPDATE8(utp, SUNI_REGO_RACPUHCS); 555117552Sharti utp->stats.rx_cells += UPDATE19(utp, SUNI_REGO_RACPCNT); 556117552Sharti utp->stats.tx_cells += UPDATE19(utp, SUNI_REGO_TACPCNT); 557117552Sharti} 558117552Sharti 559117552Sharti/* 560117552Sharti * Update statistics from a SUNI/622 561117552Sharti */ 562117552Shartistatic void 563117552Shartisuni_622_update_stats(struct utopia *utp) 564117552Sharti{ 565117552Sharti int err; 566117552Sharti 567117552Sharti /* write to the master if we can */ 568117552Sharti if (!(utp->flags & UTP_FL_NORESET)) { 569117552Sharti err = WRITEREG(utp, SUNI_REGO_MRESET, 0, 0); 570117552Sharti } else { 571117552Sharti err = WRITEREG(utp, SUNI_REGO_RSOP_BIP8, 0, 0); 572117552Sharti err |= WRITEREG(utp, SUNI_REGO_RLOPBIP8_24, 0, 0); 573117552Sharti err |= WRITEREG(utp, SUNI_REGO_RPOPBIP8, 0, 0); 574117552Sharti err |= WRITEREG(utp, SUNI_REGO_RACPCHCS, 0, 0); 575117552Sharti err |= WRITEREG(utp, SUNI_REGO_TACPCNT, 0, 0); 576117552Sharti } 577117552Sharti if (err) { 578117552Sharti#ifdef DIAGNOSTIC 579117552Sharti printf("%s: register write error %s: %d\n", __func__, 580117552Sharti utp->chip->name, err); 581117552Sharti#endif 582117552Sharti return; 583117552Sharti } 584117552Sharti 585117552Sharti DELAY(8); 586117552Sharti 587117552Sharti utp->stats.rx_sbip += UPDATE16(utp, SUNI_REGO_RSOP_BIP8); 588117552Sharti utp->stats.rx_lbip += UPDATE20(utp, SUNI_REGO_RLOPBIP8_24); 589117552Sharti utp->stats.rx_lfebe += UPDATE20(utp, SUNI_REGO_RLOPFEBE); 590117552Sharti utp->stats.rx_pbip += UPDATE16(utp, SUNI_REGO_RPOPBIP8); 591117552Sharti utp->stats.rx_pfebe += UPDATE16(utp, SUNI_REGO_RPOPFEBE); 592117552Sharti utp->stats.rx_corr += UPDATE12(utp, SUNI_REGO_RACPCHCS_622); 593117552Sharti utp->stats.rx_uncorr += UPDATE12(utp, SUNI_REGO_RACPUHCS_622); 594117552Sharti utp->stats.rx_cells += UPDATE21(utp, SUNI_REGO_RACPCNT_622); 595117552Sharti utp->stats.tx_cells += UPDATE21(utp, SUNI_REGO_TACPCNT); 596117552Sharti} 597117552Sharti 598116258Shartistatic const struct utopia_chip chip_622 = { 599116258Sharti UTP_TYPE_SUNI_622, 600116258Sharti "Suni/622 (PMC-5355)", 601116258Sharti 256, 602116258Sharti utopia_reset_622, 603116258Sharti utopia_set_sdh_default, 604116258Sharti utopia_set_unass_default, 605116258Sharti utopia_set_noscramb_default, 606116258Sharti utopia_update_carrier_default, 607116258Sharti utopia_set_loopback_622, 608116258Sharti utopia_intr_default, 609117552Sharti suni_622_update_stats, 610116258Sharti}; 611116258Shartistatic const struct utopia_chip chip_lite = { 612116258Sharti UTP_TYPE_SUNI_LITE, 613116258Sharti "Suni/Lite (PMC-5346)", 614116258Sharti 256, 615116258Sharti utopia_reset_default, 616116258Sharti utopia_set_sdh_default, 617116258Sharti utopia_set_unass_default, 618116258Sharti utopia_set_noscramb_default, 619116258Sharti utopia_update_carrier_default, 620116258Sharti utopia_set_loopback_lite, 621116258Sharti utopia_intr_default, 622117552Sharti suni_lite_update_stats, 623116258Sharti}; 624116258Shartistatic const struct utopia_chip chip_ultra = { 625116258Sharti UTP_TYPE_SUNI_ULTRA, 626116258Sharti "Suni/Ultra (PMC-5350)", 627116258Sharti 256, 628116258Sharti utopia_reset_default, 629116258Sharti utopia_set_sdh_default, 630116258Sharti utopia_set_unass_default, 631116258Sharti utopia_set_noscramb_default, 632116258Sharti utopia_update_carrier_default, 633116258Sharti utopia_set_loopback_ultra, 634116258Sharti utopia_intr_default, 635117552Sharti suni_lite_update_stats, 636116258Sharti}; 637116258Sharti 638116258Sharti/* 639116258Sharti * Reset IDT77105. There is really no way to reset this thing by acessing 640116258Sharti * the registers. Load the registers with default values. 641116258Sharti */ 642116258Shartistatic int 643116258Shartiidt77105_reset(struct utopia *utp) 644116258Sharti{ 645116258Sharti int err = 0; 646116258Sharti u_int n; 647116258Sharti uint8_t val[2]; 648116258Sharti 649116258Sharti err |= WRITEREG(utp, IDTPHY_REGO_MCR, 0xff, 650116258Sharti IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI); 651116258Sharti n = 1; 652116258Sharti err |= READREGS(utp, IDTPHY_REGO_ISTAT, val, &n); 653116258Sharti err |= WRITEREG(utp, IDTPHY_REGO_DIAG, 0xff, 0); 654116258Sharti err |= WRITEREG(utp, IDTPHY_REGO_LHEC, 0xff, 0); 655116258Sharti 656116258Sharti err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_SEC); 657116258Sharti n = 2; 658116258Sharti err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n); 659116258Sharti 660116258Sharti err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_TX); 661116258Sharti n = 2; 662116258Sharti err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n); 663116258Sharti 664116258Sharti err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_RX); 665116258Sharti n = 2; 666116258Sharti err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n); 667116258Sharti 668116258Sharti err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_HECE); 669116258Sharti n = 2; 670116258Sharti err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n); 671116258Sharti 672116258Sharti err |= WRITEREG(utp, IDTPHY_REGO_MCR, IDTPHY_REGM_MCR_DREC, 673116258Sharti IDTPHY_REGM_MCR_DREC); 674116258Sharti err |= WRITEREG(utp, IDTPHY_REGO_DIAG, IDTPHY_REGM_DIAG_RFLUSH, 675116258Sharti IDTPHY_REGM_DIAG_RFLUSH); 676116258Sharti 677116258Sharti /* loopback */ 678116258Sharti err |= utopia_set_loopback(utp, utp->loopback); 679116258Sharti 680116258Sharti /* update carrier state */ 681116258Sharti err |= utopia_update_carrier(utp); 682116258Sharti 683116258Sharti return (err ? EIO : 0); 684116258Sharti} 685116258Sharti 686116258Shartistatic int 687116258Shartiunknown_inval(struct utopia *utp, int what __unused) 688116258Sharti{ 689116258Sharti return (EINVAL); 690116258Sharti} 691116258Sharti 692116258Shartistatic int 693116258Shartiidt77105_update_carrier(struct utopia *utp) 694116258Sharti{ 695116258Sharti int err; 696116258Sharti uint8_t reg; 697116258Sharti u_int n = 1; 698116258Sharti 699116258Sharti if ((err = READREGS(utp, IDTPHY_REGO_ISTAT, ®, &n)) != 0) { 700116258Sharti utp->carrier = UTP_CARR_UNKNOWN; 701116258Sharti return (err); 702116258Sharti } 703116258Sharti utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD); 704116258Sharti return (0); 705116258Sharti} 706116258Sharti 707116258Shartistatic int 708116258Shartiidt77105_set_loopback(struct utopia *utp, u_int mode) 709116258Sharti{ 710116258Sharti int err; 711116258Sharti 712116258Sharti switch (mode) { 713116258Sharti case UTP_LOOP_NONE: 714116258Sharti err = WRITEREG(utp, IDTPHY_REGO_DIAG, 715116258Sharti IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_NONE); 716116258Sharti break; 717116258Sharti 718116258Sharti case UTP_LOOP_DIAG: 719116258Sharti err = WRITEREG(utp, IDTPHY_REGO_DIAG, 720116258Sharti IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_PHY); 721116258Sharti break; 722116258Sharti 723116258Sharti case UTP_LOOP_LINE: 724116258Sharti err = WRITEREG(utp, IDTPHY_REGO_DIAG, 725116258Sharti IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_LINE); 726116258Sharti break; 727116258Sharti 728116258Sharti default: 729116258Sharti return (EINVAL); 730116258Sharti } 731116258Sharti if (err) 732116258Sharti return (err); 733116258Sharti utp->loopback = mode; 734116258Sharti return (0); 735116258Sharti} 736116258Sharti 737116258Sharti/* 738116258Sharti * Handle interrupt on IDT77105 chip 739116258Sharti */ 740116258Shartistatic void 741116258Shartiidt77105_intr(struct utopia *utp) 742116258Sharti{ 743116258Sharti uint8_t reg; 744116258Sharti u_int n = 1; 745116258Sharti int err; 746116258Sharti 747116258Sharti /* Interrupt status and ack the interrupt */ 748116258Sharti if ((err = READREGS(utp, IDTPHY_REGO_ISTAT, ®, &n)) != 0) { 749116258Sharti printf("IDT77105 read error %d\n", err); 750116258Sharti return; 751116258Sharti } 752116258Sharti /* check for signal condition */ 753116258Sharti utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD); 754116258Sharti} 755116258Sharti 756117552Shartistatic void 757117552Shartiidt77105_update_stats(struct utopia *utp) 758117552Sharti{ 759117552Sharti int err = 0; 760117552Sharti uint8_t regs[2]; 761117552Sharti u_int n; 762117552Sharti 763117552Sharti#ifdef DIAGNOSTIC 764117552Sharti#define UDIAG(F,A,B) printf(F, A, B) 765117552Sharti#else 766117552Sharti#define UDIAG(F,A,B) do { } while (0) 767117552Sharti#endif 768117552Sharti 769117552Sharti#define UPD(FIELD, CODE, N, MASK) \ 770117552Sharti err = WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, CODE); \ 771117552Sharti if (err != 0) { \ 772117552Sharti UDIAG("%s: cannot write CNTS: %d\n", __func__, err); \ 773117552Sharti return; \ 774117552Sharti } \ 775117552Sharti n = N; \ 776117552Sharti err = READREGS(utp, IDTPHY_REGO_CNT, regs, &n); \ 777117552Sharti if (err != 0) { \ 778117552Sharti UDIAG("%s: cannot read CNT: %d\n", __func__, err); \ 779117552Sharti return; \ 780117552Sharti } \ 781117552Sharti if (n != N) { \ 782117552Sharti UDIAG("%s: got only %u registers\n", __func__, n); \ 783117552Sharti return; \ 784117552Sharti } \ 785117552Sharti if (N == 1) \ 786117552Sharti utp->stats.FIELD += (regs[0] & MASK); \ 787117552Sharti else \ 788117552Sharti utp->stats.FIELD += (regs[0] | (regs[1] << 8)) & MASK; 789117552Sharti 790117552Sharti UPD(rx_symerr, IDTPHY_REGM_CNTS_SEC, 1, 0xff); 791117552Sharti UPD(tx_cells, IDTPHY_REGM_CNTS_TX, 2, 0xffff); 792117552Sharti UPD(rx_cells, IDTPHY_REGM_CNTS_RX, 2, 0xffff); 793117552Sharti UPD(rx_uncorr, IDTPHY_REGM_CNTS_HECE, 1, 0x1f); 794117552Sharti 795117552Sharti#undef UDIAG 796117552Sharti#undef UPD 797117552Sharti} 798117552Sharti 799116258Shartistatic const struct utopia_chip chip_idt77105 = { 800116258Sharti UTP_TYPE_IDT77105, 801116258Sharti "IDT77105", 802116258Sharti 7, 803116258Sharti idt77105_reset, 804116258Sharti unknown_inval, 805116258Sharti unknown_inval, 806116258Sharti unknown_inval, 807116258Sharti idt77105_update_carrier, 808116258Sharti idt77105_set_loopback, 809116258Sharti idt77105_intr, 810117552Sharti idt77105_update_stats, 811116258Sharti}; 812116258Sharti 813117546Sharti/* 814117546Sharti * Update the carrier status 815117546Sharti */ 816116258Shartistatic int 817117546Shartiidt77155_update_carrier(struct utopia *utp) 818117546Sharti{ 819117546Sharti int err; 820117546Sharti uint8_t reg; 821117546Sharti u_int n = 1; 822117546Sharti 823117546Sharti if ((err = READREGS(utp, IDTPHY_REGO_RSOS, ®, &n)) != 0) { 824117546Sharti utp->carrier = UTP_CARR_UNKNOWN; 825117546Sharti return (err); 826117546Sharti } 827117546Sharti utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS)); 828117546Sharti return (0); 829117546Sharti} 830117546Sharti 831117546Sharti/* 832117546Sharti * Handle interrupt on IDT77155 chip 833117546Sharti */ 834117546Shartistatic void 835117546Shartiidt77155_intr(struct utopia *utp) 836117546Sharti{ 837117546Sharti uint8_t reg; 838117546Sharti u_int n = 1; 839117546Sharti int err; 840117546Sharti 841117546Sharti if ((err = READREGS(utp, IDTPHY_REGO_RSOS, ®, &n)) != 0) { 842117546Sharti printf("IDT77105 read error %d\n", err); 843117546Sharti return; 844117546Sharti } 845117546Sharti utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS)); 846117546Sharti} 847117546Sharti 848117546Sharti/* 849117546Sharti * set SONET/SDH mode 850117546Sharti */ 851117546Shartistatic int 852117546Shartiidt77155_set_sdh(struct utopia *utp, int sdh) 853117546Sharti{ 854117546Sharti int err; 855117546Sharti 856117546Sharti if (sdh) 857117546Sharti err = WRITEREG(utp, IDTPHY_REGO_PTRM, 858117546Sharti IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SDH); 859117546Sharti else 860117546Sharti err = WRITEREG(utp, IDTPHY_REGO_PTRM, 861117546Sharti IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SONET); 862117546Sharti if (err != 0) 863117546Sharti return (err); 864117546Sharti 865117546Sharti utp->state &= ~UTP_ST_SDH; 866117546Sharti if (sdh) 867117546Sharti utp->state |= UTP_ST_SDH; 868117546Sharti 869117546Sharti return (0); 870117546Sharti} 871117546Sharti 872117546Sharti/* 873117546Sharti * set idle/unassigned cells 874117546Sharti */ 875117546Shartistatic int 876117546Shartiidt77155_set_unass(struct utopia *utp, int unass) 877117546Sharti{ 878117546Sharti int err; 879117546Sharti 880117546Sharti if (unass) 881117546Sharti err = WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 0); 882117546Sharti else 883117546Sharti err = WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 1); 884117546Sharti if (err != 0) 885117546Sharti return (err); 886117546Sharti 887117546Sharti utp->state &= ~UTP_ST_UNASS; 888117546Sharti if (unass) 889117546Sharti utp->state |= UTP_ST_UNASS; 890117546Sharti 891117546Sharti return (0); 892117546Sharti} 893117546Sharti 894117546Sharti/* 895117546Sharti * enable/disable scrambling 896117546Sharti */ 897117546Shartistatic int 898117546Shartiidt77155_set_noscramb(struct utopia *utp, int noscramb) 899117546Sharti{ 900117546Sharti int err; 901117546Sharti 902117546Sharti if (noscramb) { 903117546Sharti err = WRITEREG(utp, IDTPHY_REGO_TCC, 904117546Sharti IDTPHY_REGM_TCC_DSCR, IDTPHY_REGM_TCC_DSCR); 905117546Sharti if (err) 906117546Sharti return (err); 907117546Sharti err = WRITEREG(utp, IDTPHY_REGO_RCC, 908117546Sharti IDTPHY_REGM_RCC_DSCR, IDTPHY_REGM_RCC_DSCR); 909117546Sharti if (err) 910117546Sharti return (err); 911117546Sharti utp->state |= UTP_ST_NOSCRAMB; 912117546Sharti } else { 913117546Sharti err = WRITEREG(utp, IDTPHY_REGO_TCC, 914117546Sharti IDTPHY_REGM_TCC_DSCR, 0); 915117546Sharti if (err) 916117546Sharti return (err); 917117546Sharti err = WRITEREG(utp, IDTPHY_REGO_RCC, 918117546Sharti IDTPHY_REGM_RCC_DSCR, 0); 919117546Sharti if (err) 920117546Sharti return (err); 921117546Sharti utp->state &= ~UTP_ST_NOSCRAMB; 922117546Sharti } 923117546Sharti return (0); 924117546Sharti} 925117546Sharti 926117546Sharti/* 927117546Sharti * Set loopback mode for the 77155 928117546Sharti */ 929117546Shartistatic int 930117546Shartiidt77155_set_loopback(struct utopia *utp, u_int mode) 931117546Sharti{ 932117546Sharti int err; 933117546Sharti uint32_t val; 934117546Sharti u_int nmode; 935117546Sharti 936117546Sharti val = 0; 937117546Sharti nmode = mode; 938117546Sharti if (mode & UTP_LOOP_TIME) { 939117546Sharti nmode &= ~UTP_LOOP_TIME; 940117546Sharti val |= IDTPHY_REGM_MCTL_TLOOP; 941117546Sharti } 942117546Sharti if (mode & UTP_LOOP_DIAG) { 943117546Sharti nmode &= ~UTP_LOOP_DIAG; 944117546Sharti val |= IDTPHY_REGM_MCTL_DLOOP; 945117546Sharti } 946117546Sharti if (mode & UTP_LOOP_LINE) { 947117546Sharti nmode &= ~UTP_LOOP_LINE; 948117546Sharti val |= IDTPHY_REGM_MCTL_LLOOP; 949117546Sharti } 950117546Sharti if (nmode != 0) 951117546Sharti return (EINVAL); 952117546Sharti 953117546Sharti err = WRITEREG(utp, IDTPHY_REGO_MCTL, IDTPHY_REGM_MCTL_TLOOP | 954117546Sharti IDTPHY_REGM_MCTL_DLOOP | IDTPHY_REGM_MCTL_LLOOP, val); 955117546Sharti if (err) 956117546Sharti return (err); 957117546Sharti utp->loopback = mode; 958117546Sharti 959117546Sharti return (0); 960117546Sharti} 961117546Sharti 962117546Sharti/* 963117546Sharti * Set the chip to reflect the current state in utopia. 964117546Sharti * Assume, that the chip has been reset. 965117546Sharti */ 966117546Shartistatic int 967117546Shartiidt77155_set_chip(struct utopia *utp) 968117546Sharti{ 969117546Sharti int err = 0; 970117546Sharti 971117546Sharti /* set sonet/sdh */ 972117546Sharti err |= idt77155_set_sdh(utp, utp->state & UTP_ST_SDH); 973117546Sharti 974117546Sharti /* unassigned or idle cells */ 975117546Sharti err |= idt77155_set_unass(utp, utp->state & UTP_ST_UNASS); 976117546Sharti 977117546Sharti /* loopback */ 978117546Sharti err |= idt77155_set_loopback(utp, utp->loopback); 979117546Sharti 980117546Sharti /* update carrier state */ 981117546Sharti err |= idt77155_update_carrier(utp); 982117546Sharti 983117546Sharti /* enable interrupts on LOS */ 984117546Sharti err |= WRITEREG(utp, IDTPHY_REGO_INT, 985117546Sharti IDTPHY_REGM_INT_RXSOHI, IDTPHY_REGM_INT_RXSOHI); 986117546Sharti err |= WRITEREG(utp, IDTPHY_REGO_RSOC, 987117546Sharti IDTPHY_REGM_RSOC_LOSI, IDTPHY_REGM_RSOC_LOSI); 988117546Sharti 989117546Sharti return (err ? EIO : 0); 990117546Sharti} 991117546Sharti 992117546Sharti/* 993117546Sharti * Reset the chip to reflect the current state of utopia. 994117546Sharti */ 995117546Shartistatic int 996117546Shartiidt77155_reset(struct utopia *utp) 997117546Sharti{ 998117546Sharti int err = 0; 999117546Sharti 1000117546Sharti if (!(utp->flags & UTP_FL_NORESET)) { 1001117546Sharti err |= WRITEREG(utp, IDTPHY_REGO_MRID, IDTPHY_REGM_MRID_RESET, 1002117546Sharti IDTPHY_REGM_MRID_RESET); 1003117546Sharti err |= WRITEREG(utp, IDTPHY_REGO_MRID, IDTPHY_REGM_MRID_RESET, 1004117546Sharti 0); 1005117546Sharti } 1006117546Sharti 1007117546Sharti err |= idt77155_set_chip(utp); 1008117546Sharti 1009117546Sharti return (err ? EIO : 0); 1010117546Sharti} 1011117546Sharti 1012117552Sharti/* 1013117552Sharti * Update statistics from a IDT77155 1014117552Sharti * This appears to be the same as for the Suni/Lite and Ultra. IDT however 1015117552Sharti * makes no assessment about the transfer time. Assume 7us. 1016117552Sharti */ 1017117552Shartistatic void 1018117552Shartiidt77155_update_stats(struct utopia *utp) 1019117552Sharti{ 1020117552Sharti int err; 1021117552Sharti 1022117552Sharti /* write to the master if we can */ 1023117552Sharti if (!(utp->flags & UTP_FL_NORESET)) { 1024117552Sharti err = WRITEREG(utp, IDTPHY_REGO_MRID, 0, 0); 1025117552Sharti } else { 1026117552Sharti err = WRITEREG(utp, IDTPHY_REGO_BIPC, 0, 0); 1027117552Sharti err |= WRITEREG(utp, IDTPHY_REGO_B2EC, 0, 0); 1028117552Sharti err |= WRITEREG(utp, IDTPHY_REGO_B3EC, 0, 0); 1029117552Sharti err |= WRITEREG(utp, IDTPHY_REGO_CEC, 0, 0); 1030117552Sharti err |= WRITEREG(utp, IDTPHY_REGO_TXCNT, 0, 0); 1031117552Sharti 1032117552Sharti } 1033117552Sharti if (err) { 1034117552Sharti#ifdef DIAGNOSTIC 1035117552Sharti printf("%s: register write error %s: %d\n", __func__, 1036117552Sharti utp->chip->name, err); 1037117552Sharti#endif 1038117552Sharti return; 1039117552Sharti } 1040117552Sharti 1041117552Sharti DELAY(8); 1042117552Sharti 1043117552Sharti utp->stats.rx_sbip += UPDATE16(utp, IDTPHY_REGO_BIPC); 1044117552Sharti utp->stats.rx_lbip += UPDATE20(utp, IDTPHY_REGO_B2EC); 1045117552Sharti utp->stats.rx_lfebe += UPDATE20(utp, IDTPHY_REGO_FEBEC); 1046117552Sharti utp->stats.rx_pbip += UPDATE16(utp, IDTPHY_REGO_B3EC); 1047117552Sharti utp->stats.rx_pfebe += UPDATE16(utp, IDTPHY_REGO_PFEBEC); 1048117552Sharti utp->stats.rx_corr += UPDATE8(utp, IDTPHY_REGO_CEC); 1049117552Sharti utp->stats.rx_uncorr += UPDATE8(utp, IDTPHY_REGO_UEC); 1050117552Sharti utp->stats.rx_cells += UPDATE19(utp, IDTPHY_REGO_RCCNT); 1051117552Sharti utp->stats.tx_cells += UPDATE19(utp, IDTPHY_REGO_TXCNT); 1052117552Sharti} 1053117552Sharti 1054117552Sharti 1055117546Shartistatic const struct utopia_chip chip_idt77155 = { 1056117546Sharti UTP_TYPE_IDT77155, 1057117546Sharti "IDT77155", 1058117546Sharti 0x80, 1059117546Sharti idt77155_reset, 1060117546Sharti idt77155_set_sdh, 1061117546Sharti idt77155_set_unass, 1062117546Sharti idt77155_set_noscramb, 1063117546Sharti idt77155_update_carrier, 1064117546Sharti idt77155_set_loopback, 1065117546Sharti idt77155_intr, 1066117552Sharti idt77155_update_stats, 1067117546Sharti}; 1068117546Sharti 1069117546Shartistatic int 1070116258Shartiunknown_reset(struct utopia *utp __unused) 1071116258Sharti{ 1072116258Sharti return (EIO); 1073116258Sharti} 1074116258Sharti 1075116258Shartistatic int 1076116258Shartiunknown_update_carrier(struct utopia *utp) 1077116258Sharti{ 1078116258Sharti utp->carrier = UTP_CARR_UNKNOWN; 1079116258Sharti return (0); 1080116258Sharti} 1081116258Sharti 1082116258Shartistatic int 1083116258Shartiunknown_set_loopback(struct utopia *utp __unused, u_int mode __unused) 1084116258Sharti{ 1085116258Sharti return (EINVAL); 1086116258Sharti} 1087116258Sharti 1088116258Shartistatic void 1089116258Shartiunknown_intr(struct utopia *utp __unused) 1090116258Sharti{ 1091116258Sharti} 1092116258Sharti 1093117552Shartistatic void 1094117552Shartiunknown_update_stats(struct utopia *utp __unused) 1095117552Sharti{ 1096117552Sharti} 1097117552Sharti 1098116258Shartistatic const struct utopia_chip chip_unknown = { 1099116258Sharti UTP_TYPE_UNKNOWN, 1100116258Sharti "unknown", 1101116258Sharti 0, 1102116258Sharti unknown_reset, 1103116258Sharti unknown_inval, 1104116258Sharti unknown_inval, 1105116258Sharti unknown_inval, 1106116258Sharti unknown_update_carrier, 1107116258Sharti unknown_set_loopback, 1108116258Sharti unknown_intr, 1109117552Sharti unknown_update_stats, 1110116258Sharti}; 1111116258Sharti 1112116258Sharti/* 1113116258Sharti * Callbacks for the ifmedia infrastructure. 1114116258Sharti */ 1115116258Shartistatic int 1116116258Shartiutopia_media_change(struct ifnet *ifp) 1117116258Sharti{ 1118116258Sharti struct ifatm *ifatm = (struct ifatm *)ifp->if_softc; 1119116258Sharti struct utopia *utp = ifatm->phy; 1120116258Sharti int error = 0; 1121116258Sharti 1122116258Sharti UTP_LOCK(utp); 1123116258Sharti if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) { 1124116258Sharti if (utp->media->ifm_media & IFM_ATM_SDH) { 1125116258Sharti if (!(utp->state & UTP_ST_SDH)) 1126116258Sharti error = utopia_set_sdh(utp, 1); 1127116258Sharti } else { 1128116258Sharti if (utp->state & UTP_ST_SDH) 1129116258Sharti error = utopia_set_sdh(utp, 0); 1130116258Sharti } 1131116258Sharti if (utp->media->ifm_media & IFM_ATM_UNASSIGNED) { 1132116258Sharti if (!(utp->state & UTP_ST_UNASS)) 1133116258Sharti error = utopia_set_unass(utp, 1); 1134116258Sharti } else { 1135116258Sharti if (utp->state & UTP_ST_UNASS) 1136116258Sharti error = utopia_set_unass(utp, 0); 1137116258Sharti } 1138116258Sharti if (utp->media->ifm_media & IFM_ATM_NOSCRAMB) { 1139116258Sharti if (!(utp->state & UTP_ST_NOSCRAMB)) 1140116258Sharti error = utopia_set_noscramb(utp, 1); 1141116258Sharti } else { 1142116258Sharti if (utp->state & UTP_ST_NOSCRAMB) 1143116258Sharti error = utopia_set_noscramb(utp, 0); 1144116258Sharti } 1145116258Sharti } else 1146116258Sharti error = EIO; 1147116258Sharti UTP_UNLOCK(utp); 1148116258Sharti return (error); 1149116258Sharti} 1150116258Sharti 1151116258Sharti/* 1152116258Sharti * Look at the carrier status. 1153116258Sharti */ 1154116258Shartistatic void 1155116258Shartiutopia_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 1156116258Sharti{ 1157116258Sharti struct utopia *utp = ((struct ifatm *)ifp->if_softc)->phy; 1158116258Sharti 1159116258Sharti UTP_LOCK(utp); 1160116258Sharti if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) { 1161116258Sharti ifmr->ifm_active = IFM_ATM | utp->ifatm->mib.media; 1162116258Sharti 1163116258Sharti switch (utp->carrier) { 1164116258Sharti 1165116258Sharti case UTP_CARR_OK: 1166116258Sharti ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; 1167116258Sharti break; 1168116258Sharti 1169116258Sharti case UTP_CARR_LOST: 1170116258Sharti ifmr->ifm_status = IFM_AVALID; 1171116258Sharti break; 1172116258Sharti 1173116258Sharti default: 1174116258Sharti ifmr->ifm_status = 0; 1175116258Sharti break; 1176116258Sharti } 1177116258Sharti if (utp->state & UTP_ST_SDH) { 1178116258Sharti ifmr->ifm_active |= IFM_ATM_SDH; 1179116258Sharti ifmr->ifm_current |= IFM_ATM_SDH; 1180116258Sharti } 1181116258Sharti if (utp->state & UTP_ST_UNASS) { 1182116258Sharti ifmr->ifm_active |= IFM_ATM_UNASSIGNED; 1183116258Sharti ifmr->ifm_current |= IFM_ATM_UNASSIGNED; 1184116258Sharti } 1185116258Sharti if (utp->state & UTP_ST_NOSCRAMB) { 1186116258Sharti ifmr->ifm_active |= IFM_ATM_NOSCRAMB; 1187116258Sharti ifmr->ifm_current |= IFM_ATM_NOSCRAMB; 1188116258Sharti } 1189116258Sharti } else { 1190116258Sharti ifmr->ifm_active = 0; 1191116258Sharti ifmr->ifm_status = 0; 1192116258Sharti } 1193116258Sharti UTP_UNLOCK(utp); 1194116258Sharti} 1195116258Sharti 1196116258Sharti/* 1197116258Sharti * Initialize media from the mib 1198116258Sharti */ 1199116258Shartivoid 1200116258Shartiutopia_init_media(struct utopia *utp) 1201116258Sharti{ 1202116258Sharti 1203116258Sharti ifmedia_removeall(utp->media); 1204116258Sharti ifmedia_add(utp->media, IFM_ATM | utp->ifatm->mib.media, 0, NULL); 1205116258Sharti ifmedia_set(utp->media, IFM_ATM | utp->ifatm->mib.media); 1206116258Sharti} 1207116258Sharti 1208116258Sharti/* 1209116258Sharti * Reset all media 1210116258Sharti */ 1211116258Shartivoid 1212116258Shartiutopia_reset_media(struct utopia *utp) 1213116258Sharti{ 1214116258Sharti 1215116258Sharti ifmedia_removeall(utp->media); 1216116258Sharti} 1217116258Sharti 1218116258Sharti/* 1219116258Sharti * This is called by the driver as soon as the SUNI registers are accessible. 1220116258Sharti * This may be either in the attach routine or the init routine of the driver. 1221116258Sharti */ 1222116258Shartiint 1223116258Shartiutopia_start(struct utopia *utp) 1224116258Sharti{ 1225116258Sharti uint8_t reg; 1226116258Sharti int err; 1227116258Sharti u_int n = 1; 1228116258Sharti 1229116258Sharti if ((err = READREGS(utp, SUNI_REGO_MRESET, ®, &n)) != 0) 1230116258Sharti return (err); 1231116258Sharti 1232116258Sharti switch (reg & SUNI_REGM_MRESET_TYPE) { 1233116258Sharti 1234116258Sharti case SUNI_REGM_MRESET_TYPE_622: 1235116258Sharti utp->chip = &chip_622; 1236116258Sharti break; 1237116258Sharti 1238116258Sharti case SUNI_REGM_MRESET_TYPE_LITE: 1239117546Sharti /* this may be either a SUNI LITE or a IDT77155 * 1240117546Sharti * Read register 0x70. The SUNI doesn't have it */ 1241117546Sharti n = 1; 1242117546Sharti if ((err = READREGS(utp, IDTPHY_REGO_RBER, ®, &n)) != 0) 1243117546Sharti return (err); 1244117546Sharti if ((reg & ~IDTPHY_REGM_RBER_RESV) == 1245117546Sharti (IDTPHY_REGM_RBER_FAIL | IDTPHY_REGM_RBER_WARN)) 1246117546Sharti utp->chip = &chip_idt77155; 1247117546Sharti else 1248117546Sharti utp->chip = &chip_lite; 1249116258Sharti break; 1250116258Sharti 1251116258Sharti case SUNI_REGM_MRESET_TYPE_ULTRA: 1252116258Sharti utp->chip = &chip_ultra; 1253116258Sharti break; 1254116258Sharti 1255116258Sharti default: 1256116258Sharti if (reg == (IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI)) 1257116258Sharti utp->chip = &chip_idt77105; 1258116258Sharti else { 1259116258Sharti if_printf(&utp->ifatm->ifnet, 1260116258Sharti "unknown ATM-PHY chip %#x\n", reg); 1261116258Sharti utp->chip = &chip_unknown; 1262116258Sharti } 1263116258Sharti break; 1264116258Sharti } 1265116258Sharti utp->state |= UTP_ST_ACTIVE; 1266116258Sharti return (0); 1267116258Sharti} 1268116258Sharti 1269116258Sharti/* 1270116258Sharti * Stop the chip 1271116258Sharti */ 1272116258Shartivoid 1273116258Shartiutopia_stop(struct utopia *utp) 1274116258Sharti{ 1275116258Sharti utp->state &= ~UTP_ST_ACTIVE; 1276116258Sharti} 1277116258Sharti 1278116258Sharti/* 1279116258Sharti * Handle the sysctls 1280116258Sharti */ 1281116258Shartistatic int 1282116258Shartiutopia_sysctl_regs(SYSCTL_HANDLER_ARGS) 1283116258Sharti{ 1284116258Sharti struct utopia *utp = (struct utopia *)arg1; 1285116258Sharti int error; 1286116258Sharti u_int n; 1287116258Sharti uint8_t *val; 1288116258Sharti uint8_t new[3]; 1289116258Sharti 1290116258Sharti if ((n = utp->chip->nregs) == 0) 1291116258Sharti return (EIO); 1292116258Sharti val = malloc(sizeof(uint8_t) * n, M_TEMP, M_WAITOK); 1293116258Sharti 1294116258Sharti UTP_LOCK(utp); 1295116258Sharti error = READREGS(utp, 0, val, &n); 1296116258Sharti UTP_UNLOCK(utp); 1297116258Sharti 1298116258Sharti if (error) { 1299116258Sharti free(val, M_TEMP); 1300116258Sharti return (error); 1301116258Sharti } 1302116258Sharti 1303116258Sharti error = SYSCTL_OUT(req, val, sizeof(uint8_t) * n); 1304116258Sharti free(val, M_TEMP); 1305116258Sharti if (error != 0 || req->newptr == NULL) 1306116258Sharti return (error); 1307116258Sharti 1308116258Sharti error = SYSCTL_IN(req, new, sizeof(new)); 1309116258Sharti if (error) 1310116258Sharti return (error); 1311116258Sharti 1312116258Sharti UTP_LOCK(utp); 1313116258Sharti error = WRITEREG(utp, new[0], new[1], new[2]); 1314116258Sharti UTP_UNLOCK(utp); 1315116258Sharti 1316116258Sharti return (error); 1317116258Sharti} 1318116258Sharti 1319117552Shartistatic int 1320117552Shartiutopia_sysctl_stats(SYSCTL_HANDLER_ARGS) 1321117552Sharti{ 1322117552Sharti struct utopia *utp = (struct utopia *)arg1; 1323117552Sharti void *val; 1324117552Sharti int error; 1325117552Sharti 1326117552Sharti val = malloc(sizeof(utp->stats), M_TEMP, M_WAITOK); 1327117552Sharti 1328117552Sharti UTP_LOCK(utp); 1329117552Sharti bcopy(&utp->stats, val, sizeof(utp->stats)); 1330117552Sharti if (req->newptr != NULL) 1331117552Sharti bzero((char *)&utp->stats + sizeof(utp->stats.version), 1332117552Sharti sizeof(utp->stats) - sizeof(utp->stats.version)); 1333117552Sharti UTP_UNLOCK(utp); 1334117552Sharti 1335117552Sharti error = SYSCTL_OUT(req, val, sizeof(utp->stats)); 1336117552Sharti free(val, M_TEMP); 1337117552Sharti 1338117552Sharti if (error && req->newptr != NULL) 1339117552Sharti bcopy(val, &utp->stats, sizeof(utp->stats)); 1340117552Sharti 1341117552Sharti /* ignore actual new value */ 1342117552Sharti 1343117552Sharti return (error); 1344117552Sharti} 1345117552Sharti 1346116258Sharti/* 1347116258Sharti * Handle the loopback sysctl 1348116258Sharti */ 1349116258Shartistatic int 1350116258Shartiutopia_sysctl_loopback(SYSCTL_HANDLER_ARGS) 1351116258Sharti{ 1352116258Sharti struct utopia *utp = (struct utopia *)arg1; 1353116258Sharti int error; 1354116258Sharti u_int loopback; 1355116258Sharti 1356116258Sharti error = SYSCTL_OUT(req, &utp->loopback, sizeof(u_int)); 1357116258Sharti if (error != 0 || req->newptr == NULL) 1358116258Sharti return (error); 1359116258Sharti 1360116258Sharti error = SYSCTL_IN(req, &loopback, sizeof(u_int)); 1361116258Sharti if (error) 1362116258Sharti return (error); 1363116258Sharti 1364116258Sharti UTP_LOCK(utp); 1365116258Sharti error = utopia_set_loopback(utp, loopback); 1366116258Sharti UTP_UNLOCK(utp); 1367116258Sharti 1368116258Sharti return (error); 1369116258Sharti} 1370116258Sharti 1371116258Sharti/* 1372116258Sharti * Handle the type sysctl 1373116258Sharti */ 1374116258Shartistatic int 1375116258Shartiutopia_sysctl_type(SYSCTL_HANDLER_ARGS) 1376116258Sharti{ 1377116258Sharti struct utopia *utp = (struct utopia *)arg1; 1378116258Sharti 1379116258Sharti return (SYSCTL_OUT(req, &utp->chip->type, sizeof(utp->chip->type))); 1380116258Sharti} 1381116258Sharti 1382116258Sharti/* 1383116258Sharti * Handle the name sysctl 1384116258Sharti */ 1385116258Shartistatic int 1386116258Shartiutopia_sysctl_name(SYSCTL_HANDLER_ARGS) 1387116258Sharti{ 1388116258Sharti struct utopia *utp = (struct utopia *)arg1; 1389116258Sharti 1390116258Sharti return (SYSCTL_OUT(req, utp->chip->name, strlen(utp->chip->name) + 1)); 1391116258Sharti} 1392116258Sharti 1393116258Sharti/* 1394116258Sharti * Initialize the state. This is called from the drivers attach 1395116258Sharti * function. The mutex must be already initialized. 1396116258Sharti */ 1397116258Shartiint 1398116258Shartiutopia_attach(struct utopia *utp, struct ifatm *ifatm, struct ifmedia *media, 1399116258Sharti struct mtx *lock, struct sysctl_ctx_list *ctx, 1400116258Sharti struct sysctl_oid_list *children, const struct utopia_methods *m) 1401116258Sharti{ 1402116258Sharti 1403116258Sharti bzero(utp, sizeof(*utp)); 1404116258Sharti utp->ifatm = ifatm; 1405116258Sharti utp->methods = m; 1406116258Sharti utp->media = media; 1407116258Sharti utp->lock = lock; 1408116258Sharti utp->chip = &chip_unknown; 1409117552Sharti utp->stats.version = 1; 1410116258Sharti 1411116258Sharti ifmedia_init(media, 1412116258Sharti IFM_ATM_SDH | IFM_ATM_UNASSIGNED | IFM_ATM_NOSCRAMB, 1413116258Sharti utopia_media_change, utopia_media_status); 1414116258Sharti 1415116258Sharti if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_regs", 1416116258Sharti CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_regs, "S", 1417116258Sharti "phy registers") == NULL) 1418116258Sharti return (-1); 1419116258Sharti 1420116258Sharti if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_loopback", 1421116258Sharti CTLFLAG_RW | CTLTYPE_UINT, utp, 0, utopia_sysctl_loopback, "IU", 1422116258Sharti "phy loopback mode") == NULL) 1423116258Sharti return (-1); 1424116258Sharti 1425116258Sharti if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_type", 1426116258Sharti CTLFLAG_RD | CTLTYPE_UINT, utp, 0, utopia_sysctl_type, "IU", 1427116258Sharti "phy type") == NULL) 1428116258Sharti return (-1); 1429116258Sharti 1430116258Sharti if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_name", 1431116258Sharti CTLFLAG_RD | CTLTYPE_STRING, utp, 0, utopia_sysctl_name, "A", 1432116258Sharti "phy name") == NULL) 1433116258Sharti return (-1); 1434116258Sharti 1435117552Sharti if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_stats", 1436117552Sharti CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_stats, "S", 1437117552Sharti "phy statistics") == NULL) 1438117552Sharti return (-1); 1439117552Sharti 1440118202Sharti if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_state", 1441118202Sharti CTLFLAG_RD, &utp->state, 0, "phy state") == NULL) 1442118202Sharti return (-1); 1443118202Sharti 1444118202Sharti if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_carrier", 1445118202Sharti CTLFLAG_RD, &utp->carrier, 0, "phy carrier") == NULL) 1446118202Sharti return (-1); 1447118202Sharti 1448116258Sharti UTP_WLOCK_LIST(); 1449116258Sharti LIST_INSERT_HEAD(&utopia_list, utp, link); 1450116258Sharti UTP_WUNLOCK_LIST(); 1451116258Sharti 1452116258Sharti utp->state |= UTP_ST_ATTACHED; 1453116258Sharti return (0); 1454116258Sharti} 1455116258Sharti 1456116258Sharti/* 1457116258Sharti * Detach. We set a flag here, wakeup the daemon and let him do it. 1458116258Sharti * Here we need the lock for synchronisation with the daemon. 1459116258Sharti */ 1460116258Shartivoid 1461116258Shartiutopia_detach(struct utopia *utp) 1462116258Sharti{ 1463116258Sharti 1464116258Sharti UTP_LOCK_ASSERT(utp); 1465116258Sharti if (utp->state & UTP_ST_ATTACHED) { 1466116258Sharti utp->state |= UTP_ST_DETACH; 1467116258Sharti while (utp->state & UTP_ST_DETACH) { 1468116258Sharti wakeup(&utopia_list); 1469116258Sharti msleep(utp, utp->lock, PZERO, "utopia_detach", hz); 1470116258Sharti } 1471116258Sharti } 1472116258Sharti} 1473116258Sharti 1474116258Sharti/* 1475116258Sharti * The carrier state kernel proc for those adapters that do not interrupt. 1476116258Sharti * 1477116258Sharti * We assume, that utopia_attach can safely add a new utopia while we are going 1478116258Sharti * through the list without disturbing us (we lock the list while getting 1479116258Sharti * the address of the first element, adding is always done at the head). 1480116258Sharti * Removing is entirely handled here. 1481116258Sharti */ 1482116258Shartistatic void 1483116258Shartiutopia_daemon(void *arg __unused) 1484116258Sharti{ 1485116258Sharti struct utopia *utp, *next; 1486116258Sharti 1487116258Sharti UTP_RLOCK_LIST(); 1488116258Sharti while (utopia_kproc != NULL) { 1489116258Sharti utp = LIST_FIRST(&utopia_list); 1490116258Sharti UTP_RUNLOCK_LIST(); 1491116258Sharti 1492116258Sharti while (utp != NULL) { 1493116258Sharti mtx_lock(&Giant); /* XXX depend on MPSAFE */ 1494116258Sharti UTP_LOCK(utp); 1495116258Sharti next = LIST_NEXT(utp, link); 1496116258Sharti if (utp->state & UTP_ST_DETACH) { 1497116258Sharti LIST_REMOVE(utp, link); 1498116258Sharti utp->state &= ~UTP_ST_DETACH; 1499116258Sharti wakeup_one(utp); 1500117552Sharti } else if (utp->state & UTP_ST_ACTIVE) { 1501117552Sharti if (utp->flags & UTP_FL_POLL_CARRIER) 1502117552Sharti utopia_update_carrier(utp); 1503117552Sharti utopia_update_stats(utp); 1504116258Sharti } 1505116258Sharti UTP_UNLOCK(utp); 1506116258Sharti mtx_unlock(&Giant); /* XXX depend on MPSAFE */ 1507116258Sharti utp = next; 1508116258Sharti } 1509116258Sharti 1510116258Sharti UTP_RLOCK_LIST(); 1511117552Sharti msleep(&utopia_list, &utopia_list_mtx, PZERO, "*idle*", hz); 1512116258Sharti } 1513116258Sharti wakeup_one(&utopia_list); 1514116258Sharti UTP_RUNLOCK_LIST(); 1515116258Sharti mtx_lock(&Giant); 1516116258Sharti kthread_exit(0); 1517116258Sharti} 1518116258Sharti 1519116258Sharti/* 1520116258Sharti * Module initialisation 1521116258Sharti */ 1522116258Shartistatic int 1523116258Shartiutopia_mod_init(module_t mod, int what, void *arg) 1524116258Sharti{ 1525116258Sharti int err; 1526116258Sharti struct proc *kp; 1527116258Sharti 1528116258Sharti switch (what) { 1529116258Sharti 1530116258Sharti case MOD_LOAD: 1531116258Sharti mtx_init(&utopia_list_mtx, "utopia list mutex", NULL, MTX_DEF); 1532116258Sharti err = kthread_create(utopia_daemon, NULL, &utopia_kproc, 1533116258Sharti RFHIGHPID, 0, "utopia"); 1534116258Sharti if (err != 0) { 1535116258Sharti printf("cannot created utopia thread %d\n", err); 1536116258Sharti return (err); 1537116258Sharti } 1538116258Sharti break; 1539116258Sharti 1540116258Sharti case MOD_UNLOAD: 1541116258Sharti UTP_WLOCK_LIST(); 1542116258Sharti if ((kp = utopia_kproc) != NULL) { 1543116258Sharti utopia_kproc = NULL; 1544116258Sharti wakeup_one(&utopia_list); 1545116258Sharti PROC_LOCK(kp); 1546116258Sharti UTP_WUNLOCK_LIST(); 1547116258Sharti msleep(kp, &kp->p_mtx, PWAIT, "utopia_destroy", 0); 1548116258Sharti PROC_UNLOCK(kp); 1549116258Sharti } else 1550116258Sharti UTP_WUNLOCK_LIST(); 1551116258Sharti mtx_destroy(&utopia_list_mtx); 1552116258Sharti break; 1553116258Sharti } 1554116258Sharti return (0); 1555116258Sharti} 1556116258Sharti 1557116258Shartistatic moduledata_t utopia_mod = { 1558116258Sharti "utopia", 1559116258Sharti utopia_mod_init, 1560116258Sharti 0 1561116258Sharti}; 1562116258Sharti 1563116258ShartiDECLARE_MODULE(utopia, utopia_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 1564116258ShartiMODULE_VERSION(utopia, 1); 1565