utopia.c revision 118202
1258945Sroberto/* 2258945Sroberto * Copyright (c) 2003 3258945Sroberto * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4258945Sroberto * All rights reserved. 5258945Sroberto * 6258945Sroberto * Redistribution and use in source and binary forms, with or without 7258945Sroberto * modification, are permitted provided that the following conditions 8258945Sroberto * are met: 9258945Sroberto * 1. Redistributions of source code must retain the above copyright 10258945Sroberto * notice, this list of conditions and the following disclaimer. 11258945Sroberto * 2. Redistributions in binary form must reproduce the above copyright 12258945Sroberto * notice, this list of conditions and the following disclaimer in the 13258945Sroberto * documentation and/or other materials provided with the distribution. 14258945Sroberto * 15258945Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16258945Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17258945Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18258945Sroberto * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19258945Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20258945Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21258945Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22258945Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23258945Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24258945Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25258945Sroberto * SUCH DAMAGE. 26258945Sroberto * 27258945Sroberto * Author: Hartmut Brandt <harti@freebsd.org> 28258945Sroberto */ 29258945Sroberto 30258945Sroberto#include <sys/cdefs.h> 31258945Sroberto__FBSDID("$FreeBSD: head/sys/dev/utopia/utopia.c 118202 2003-07-30 08:35:58Z harti $"); 32258945Sroberto 33258945Sroberto#include <sys/param.h> 34258945Sroberto#include <sys/systm.h> 35258945Sroberto#include <sys/unistd.h> 36258945Sroberto#include <sys/kernel.h> 37258945Sroberto#include <sys/kthread.h> 38258945Sroberto#include <sys/proc.h> 39258945Sroberto#include <sys/bus.h> 40258945Sroberto#include <sys/malloc.h> 41258945Sroberto#include <sys/sysctl.h> 42258945Sroberto#include <sys/lock.h> 43258945Sroberto#include <sys/mutex.h> 44258945Sroberto#include <sys/socket.h> 45258945Sroberto 46258945Sroberto#include <net/if.h> 47258945Sroberto#include <net/if_var.h> 48258945Sroberto#include <net/if_media.h> 49258945Sroberto#include <net/if_atm.h> 50258945Sroberto 51258945Sroberto#include <dev/utopia/suni.h> 52258945Sroberto#include <dev/utopia/idtphy.h> 53258945Sroberto#include <dev/utopia/utopia.h> 54258945Sroberto 55258945Sroberto#define READREGS(UTOPIA, REG, VALP, NP) \ 56258945Sroberto (UTOPIA)->methods->readregs((UTOPIA)->ifatm, REG, VALP, NP) 57258945Sroberto#define WRITEREG(UTOPIA, REG, MASK, VAL) \ 58258945Sroberto (UTOPIA)->methods->writereg((UTOPIA)->ifatm, REG, MASK, VAL) 59258945Sroberto 60258945Sroberto/* 61258945Sroberto * Global list of all registered interfaces 62258945Sroberto */ 63258945Srobertostatic struct mtx utopia_list_mtx; 64258945Srobertostatic LIST_HEAD(, utopia) utopia_list = LIST_HEAD_INITIALIZER(utopia_list); 65258945Sroberto 66258945Sroberto#define UTP_RLOCK_LIST() mtx_lock(&utopia_list_mtx) 67258945Sroberto#define UTP_RUNLOCK_LIST() mtx_unlock(&utopia_list_mtx) 68258945Sroberto#define UTP_WLOCK_LIST() mtx_lock(&utopia_list_mtx) 69258945Sroberto#define UTP_WUNLOCK_LIST() mtx_unlock(&utopia_list_mtx) 70258945Sroberto 71258945Sroberto#define UTP_LOCK(UTP) mtx_lock((UTP)->lock) 72258945Sroberto#define UTP_UNLOCK(UTP) mtx_unlock((UTP)->lock) 73258945Sroberto#define UTP_LOCK_ASSERT(UTP) mtx_assert((UTP)->lock, MA_OWNED) 74258945Sroberto 75258945Srobertostatic struct proc *utopia_kproc; 76258945Sroberto 77258945Srobertostatic void utopia_dump(struct utopia *) __unused; 78258945Sroberto 79258945Sroberto/* 80258945Sroberto * Statistics update inlines 81258945Sroberto */ 82258945Srobertostatic uint32_t 83258945Srobertoutp_update(struct utopia *utp, u_int reg, u_int nreg, uint32_t mask) 84258945Sroberto{ 85258945Sroberto int err; 86258945Sroberto u_int n; 87258945Sroberto uint8_t regs[4]; 88258945Sroberto uint32_t val; 89258945Sroberto 90 n = nreg; 91 if ((err = READREGS(utp, reg, regs, &n)) != 0) { 92#ifdef DIAGNOSTIC 93 printf("%s: register read error %s(%u,%u): %d\n", __func__, 94 utp->chip->name, reg, nreg, err); 95#endif 96 return (0); 97 } 98 if (n < nreg) { 99#ifdef DIAGNOSTIC 100 printf("%s: got only %u regs %s(%u,%u): %d\n", __func__, n, 101 utp->chip->name, reg, nreg, err); 102#endif 103 return (0); 104 } 105 val = 0; 106 for (n = nreg; n > 0; n--) { 107 val <<= 8; 108 val |= regs[n - 1]; 109 } 110 return (val & mask); 111} 112 113#define UPDATE8(UTP, REG) utp_update(UTP, REG, 1, 0xff) 114#define UPDATE12(UTP, REG) utp_update(UTP, REG, 2, 0xfff) 115#define UPDATE16(UTP, REG) utp_update(UTP, REG, 2, 0xffff) 116#define UPDATE19(UTP, REG) utp_update(UTP, REG, 3, 0x7ffff) 117#define UPDATE20(UTP, REG) utp_update(UTP, REG, 3, 0xfffff) 118#define UPDATE21(UTP, REG) utp_update(UTP, REG, 3, 0x1fffff) 119 120/* 121 * Debugging - dump all registers. 122 */ 123static void 124utopia_dump(struct utopia *utp) 125{ 126 uint8_t regs[256]; 127 u_int n = 256, i; 128 int err; 129 130 if ((err = READREGS(utp, SUNI_REGO_MRESET, regs, &n)) != 0) { 131 printf("SUNI read error %d\n", err); 132 return; 133 } 134 for (i = 0; i < n; i++) { 135 if (i % 16 == 0) 136 printf("%02x:", i); 137 if (i % 16 == 8) 138 printf(" "); 139 printf(" %02x", regs[i]); 140 if (i % 16 == 15) 141 printf("\n"); 142 } 143 if (i % 16 != 0) 144 printf("\n"); 145} 146 147/* 148 * Update the carrier status 149 */ 150static void 151utopia_check_carrier(struct utopia *utp, u_int carr_ok) 152{ 153 int old; 154 155 old = utp->carrier; 156 if (carr_ok) { 157 /* carrier */ 158 utp->carrier = UTP_CARR_OK; 159 if (old != UTP_CARR_OK) { 160 if_printf(&utp->ifatm->ifnet, "carrier detected\n"); 161 ATMEV_SEND_IFSTATE_CHANGED(utp->ifatm, 1); 162 } 163 } else { 164 /* no carrier */ 165 utp->carrier = UTP_CARR_LOST; 166 if (old == UTP_CARR_OK) { 167 if_printf(&utp->ifatm->ifnet, "carrier lost\n"); 168 ATMEV_SEND_IFSTATE_CHANGED(utp->ifatm, 0); 169 } 170 } 171} 172 173static int 174utopia_update_carrier_default(struct utopia *utp) 175{ 176 int err; 177 uint8_t reg; 178 u_int n = 1; 179 180 if ((err = READREGS(utp, SUNI_REGO_RSOPSIS, ®, &n)) != 0) { 181 utp->carrier = UTP_CARR_UNKNOWN; 182 return (err); 183 } 184 utopia_check_carrier(utp, !(reg & SUNI_REGM_RSOPSIS_LOSV)); 185 return (0); 186} 187 188/* 189 * enable/disable scrambling 190 */ 191static int 192utopia_set_noscramb_default(struct utopia *utp, int noscramb) 193{ 194 int err; 195 196 if (noscramb) { 197 err = WRITEREG(utp, SUNI_REGO_TACPCTRL, 198 SUNI_REGM_TACPCTRL_DSCR, SUNI_REGM_TACPCTRL_DSCR); 199 if (err) 200 return (err); 201 err = WRITEREG(utp, SUNI_REGO_RACPCTRL, 202 SUNI_REGM_RACPCTRL_DDSCR, SUNI_REGM_RACPCTRL_DDSCR); 203 if (err) 204 return (err); 205 utp->state |= UTP_ST_NOSCRAMB; 206 } else { 207 err = WRITEREG(utp, SUNI_REGO_TACPCTRL, 208 SUNI_REGM_TACPCTRL_DSCR, 0); 209 if (err) 210 return (err); 211 err = WRITEREG(utp, SUNI_REGO_RACPCTRL, 212 SUNI_REGM_RACPCTRL_DDSCR, 0); 213 if (err) 214 return (err); 215 utp->state &= ~UTP_ST_NOSCRAMB; 216 } 217 return (0); 218} 219 220/* 221 * set SONET/SDH mode 222 */ 223static int 224utopia_set_sdh_default(struct utopia *utp, int sdh) 225{ 226 int err; 227 228 if (sdh) 229 err = WRITEREG(utp, SUNI_REGO_TPOPAPTR + 1, 230 SUNI_REGM_TPOPAPTR_S, 231 SUNI_REGM_SDH << SUNI_REGS_TPOPAPTR_S); 232 else 233 err = WRITEREG(utp, SUNI_REGO_TPOPAPTR + 1, 234 SUNI_REGM_TPOPAPTR_S, 235 SUNI_REGM_SONET << SUNI_REGS_TPOPAPTR_S); 236 if (err != 0) 237 return (err); 238 239 utp->state &= ~UTP_ST_SDH; 240 if (sdh) 241 utp->state |= UTP_ST_SDH; 242 243 return (0); 244} 245 246/* 247 * set idle/unassigned cells 248 */ 249static int 250utopia_set_unass_default(struct utopia *utp, int unass) 251{ 252 int err; 253 254 if (unass) 255 err = WRITEREG(utp, SUNI_REGO_TACPIDLEH, 256 0xff, (0 << SUNI_REGS_TACPIDLEH_CLP)); 257 else 258 err = WRITEREG(utp, SUNI_REGO_TACPIDLEH, 259 0xff, (1 << SUNI_REGS_TACPIDLEH_CLP)); 260 if (err != 0) 261 return (err); 262 263 utp->state &= ~UTP_ST_UNASS; 264 if (unass) 265 utp->state |= UTP_ST_UNASS; 266 267 return (0); 268} 269 270/* 271 * Set loopback mode for the Lite 272 */ 273static int 274utopia_set_loopback_lite(struct utopia *utp, u_int mode) 275{ 276 int err; 277 uint32_t val; 278 u_int nmode; 279 280 val = 0; 281 nmode = mode; 282 if (mode & UTP_LOOP_TIME) { 283 nmode &= ~UTP_LOOP_TIME; 284 val |= SUNI_REGM_MCTRL_LOOPT; 285 } 286 if (mode & UTP_LOOP_DIAG) { 287 nmode &= ~UTP_LOOP_DIAG; 288 val |= SUNI_REGM_MCTRL_DLE; 289 } 290 if (mode & UTP_LOOP_LINE) { 291 nmode &= ~UTP_LOOP_LINE; 292 if (val & SUNI_REGM_MCTRL_DLE) 293 return (EINVAL); 294 val |= SUNI_REGM_MCTRL_LLE; 295 } 296 if (nmode != 0) 297 return (EINVAL); 298 299 err = WRITEREG(utp, SUNI_REGO_MCTRL, 300 SUNI_REGM_MCTRL_LLE | SUNI_REGM_MCTRL_DLE | SUNI_REGM_MCTRL_LOOPT, 301 val); 302 if (err) 303 return (err); 304 utp->loopback = mode; 305 306 return (0); 307} 308 309/* 310 * Set loopback mode for the Ultra 311 */ 312static int 313utopia_set_loopback_ultra(struct utopia *utp, u_int mode) 314{ 315 int err; 316 uint32_t val; 317 u_int nmode; 318 319 val = 0; 320 nmode = mode; 321 if (mode & UTP_LOOP_TIME) { 322 nmode &= ~UTP_LOOP_TIME; 323 val |= SUNI_REGM_MCTRL_LOOPT; 324 } 325 if (mode & UTP_LOOP_DIAG) { 326 nmode &= ~UTP_LOOP_DIAG; 327 if (val & SUNI_REGM_MCTRL_LOOPT) 328 return (EINVAL); 329 val |= SUNI_REGM_MCTRL_SDLE; 330 } 331 if (mode & UTP_LOOP_LINE) { 332 nmode &= ~UTP_LOOP_LINE; 333 if (val & (SUNI_REGM_MCTRL_LOOPT | SUNI_REGM_MCTRL_SDLE)) 334 return (EINVAL); 335 val |= SUNI_REGM_MCTRL_LLE; 336 } 337 if (mode & UTP_LOOP_PARAL) { 338 nmode &= ~UTP_LOOP_PARAL; 339 val |= SUNI_REGM_MCTRL_PDLE; 340 } 341 if (mode & UTP_LOOP_TWIST) { 342 nmode &= ~UTP_LOOP_TWIST; 343 val |= SUNI_REGM_MCTRL_TPLE; 344 } 345 if (nmode != 0) 346 return (EINVAL); 347 348 err = WRITEREG(utp, SUNI_REGO_MCTRL, 349 SUNI_REGM_MCTRL_LLE | SUNI_REGM_MCTRL_SDLE | SUNI_REGM_MCTRL_LOOPT | 350 SUNI_REGM_MCTRL_PDLE | SUNI_REGM_MCTRL_TPLE, val); 351 if (err) 352 return (err); 353 utp->loopback = mode; 354 355 return (0); 356} 357 358/* 359 * Set loopback mode for the Ultra 360 */ 361static int 362utopia_set_loopback_622(struct utopia *utp, u_int mode) 363{ 364 int err; 365 uint32_t val; 366 uint8_t config; 367 int smode; 368 u_int nmode; 369 u_int n = 1; 370 371 val = 0; 372 nmode = mode; 373 if (mode & UTP_LOOP_PATH) { 374 nmode &= ~UTP_LOOP_PATH; 375 val |= SUNI_REGM_MCTRLM_DPLE; 376 } 377 378 err = READREGS(utp, SUNI_REGO_MCONFIG, &config, &n); 379 if (err != 0) 380 return (err); 381 smode = ((config & SUNI_REGM_MCONFIG_TMODE_622) == 382 SUNI_REGM_MCONFIG_TMODE_STS1_BIT && 383 (config & SUNI_REGM_MCONFIG_RMODE_622) == 384 SUNI_REGM_MCONFIG_RMODE_STS1_BIT); 385 386 if (mode & UTP_LOOP_TIME) { 387 if (!smode) 388 return (EINVAL); 389 nmode &= ~UTP_LOOP_TIME; 390 val |= SUNI_REGM_MCTRLM_LOOPT; 391 } 392 if (mode & UTP_LOOP_DIAG) { 393 nmode &= ~UTP_LOOP_DIAG; 394 if (val & SUNI_REGM_MCTRLM_LOOPT) 395 return (EINVAL); 396 val |= SUNI_REGM_MCTRLM_DLE; 397 } 398 if (mode & UTP_LOOP_LINE) { 399 nmode &= ~UTP_LOOP_LINE; 400 if (val & (SUNI_REGM_MCTRLM_LOOPT | SUNI_REGM_MCTRLM_DLE)) 401 return (EINVAL); 402 val |= SUNI_REGM_MCTRLM_LLE; 403 } 404 if (nmode != 0) 405 return (EINVAL); 406 407 err = WRITEREG(utp, SUNI_REGO_MCTRLM, 408 SUNI_REGM_MCTRLM_LLE | SUNI_REGM_MCTRLM_DLE | 409 SUNI_REGM_MCTRLM_DPLE | SUNI_REGM_MCTRL_LOOPT, val); 410 if (err) 411 return (err); 412 utp->loopback = mode; 413 414 return (0); 415} 416 417/* 418 * Set the SUNI chip to reflect the current state in utopia. 419 * Assume, that the chip has been reset. 420 */ 421static int 422utopia_set_chip(struct utopia *utp) 423{ 424 int err = 0; 425 426 /* set sonet/sdh */ 427 err |= utopia_set_sdh(utp, utp->state & UTP_ST_SDH); 428 429 /* unassigned or idle cells */ 430 err |= utopia_set_unass(utp, utp->state & UTP_ST_UNASS); 431 err |= WRITEREG(utp, SUNI_REGO_TACPIDLEP, 0xff, 0x6a); 432 433 /* loopback */ 434 err |= utopia_set_loopback(utp, utp->loopback); 435 436 /* update carrier state */ 437 err |= utopia_update_carrier(utp); 438 439 /* enable interrupts on LOS */ 440 err |= WRITEREG(utp, SUNI_REGO_RSOPCIE, 441 SUNI_REGM_RSOPCIE_LOSE, SUNI_REGM_RSOPCIE_LOSE); 442 443 return (err ? EIO : 0); 444} 445 446/* 447 * Reset the SUNI chip to reflect the current state of utopia. 448 */ 449static int 450utopia_reset_default(struct utopia *utp) 451{ 452 int err = 0; 453 454 if (!(utp->flags & UTP_FL_NORESET)) { 455 err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET, 456 SUNI_REGM_MRESET_RESET); 457 err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET, 458 0); 459 } 460 461 /* disable test mode */ 462 err |= WRITEREG(utp, SUNI_REGO_MTEST, 0xff, 0x00); 463 464 err |= utopia_set_chip(utp); 465 466 return (err ? EIO : 0); 467} 468 469/* 470 * Reset the SUNI chip to reflect the current state of utopia. 471 */ 472static int 473utopia_reset_622(struct utopia *utp) 474{ 475 int err = 0; 476 477 if (!(utp->flags & UTP_FL_NORESET)) { 478 err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET, 479 SUNI_REGM_MRESET_RESET); 480 err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET, 481 0); 482 } 483 484 /* disable test mode */ 485 err |= WRITEREG(utp, SUNI_REGO_MTEST, 0xff, 486 SUNI_REGM_MTEST_DS27_53_622); 487 488 err |= utopia_set_chip(utp); 489 490 return (err ? EIO : 0); 491} 492 493/* 494 * Handle interrupt on lite chip 495 */ 496static void 497utopia_intr_default(struct utopia *utp) 498{ 499 uint8_t regs[SUNI_REGO_MTEST]; 500 u_int n = SUNI_REGO_MTEST; 501 int err; 502 503 /* Read all registers. This acks the interrupts */ 504 if ((err = READREGS(utp, SUNI_REGO_MRESET, regs, &n)) != 0) { 505 printf("SUNI read error %d\n", err); 506 return; 507 } 508 if (n <= SUNI_REGO_RSOPSIS) { 509 printf("%s: could not read RSOPSIS", __func__); 510 return; 511 } 512 /* check for LOSI (loss of signal) */ 513 if ((regs[SUNI_REGO_MISTATUS] & SUNI_REGM_MISTATUS_RSOPI) && 514 (regs[SUNI_REGO_RSOPSIS] & SUNI_REGM_RSOPSIS_LOSI)) 515 utopia_check_carrier(utp, !(regs[SUNI_REGO_RSOPSIS] 516 & SUNI_REGM_RSOPSIS_LOSV)); 517} 518 519/* 520 * Update statistics from a SUNI/LITE or SUNI/ULTRA 521 */ 522static void 523suni_lite_update_stats(struct utopia *utp) 524{ 525 int err; 526 527 /* write to the master if we can */ 528 if (!(utp->flags & UTP_FL_NORESET)) { 529 err = WRITEREG(utp, SUNI_REGO_MRESET, 0, 0); 530 } else { 531 err = WRITEREG(utp, SUNI_REGO_RSOP_BIP8, 0, 0); 532 err |= WRITEREG(utp, SUNI_REGO_RLOPBIP8_24, 0, 0); 533 err |= WRITEREG(utp, SUNI_REGO_RPOPBIP8, 0, 0); 534 err |= WRITEREG(utp, SUNI_REGO_RACPCHCS, 0, 0); 535 err |= WRITEREG(utp, SUNI_REGO_TACPCNT, 0, 0); 536 537 } 538 if (err) { 539#ifdef DIAGNOSTIC 540 printf("%s: register write error %s: %d\n", __func__, 541 utp->chip->name, err); 542#endif 543 return; 544 } 545 546 DELAY(8); 547 548 utp->stats.rx_sbip += UPDATE16(utp, SUNI_REGO_RSOP_BIP8); 549 utp->stats.rx_lbip += UPDATE20(utp, SUNI_REGO_RLOPBIP8_24); 550 utp->stats.rx_lfebe += UPDATE20(utp, SUNI_REGO_RLOPFEBE); 551 utp->stats.rx_pbip += UPDATE16(utp, SUNI_REGO_RPOPBIP8); 552 utp->stats.rx_pfebe += UPDATE16(utp, SUNI_REGO_RPOPFEBE); 553 utp->stats.rx_corr += UPDATE8(utp, SUNI_REGO_RACPCHCS); 554 utp->stats.rx_uncorr += UPDATE8(utp, SUNI_REGO_RACPUHCS); 555 utp->stats.rx_cells += UPDATE19(utp, SUNI_REGO_RACPCNT); 556 utp->stats.tx_cells += UPDATE19(utp, SUNI_REGO_TACPCNT); 557} 558 559/* 560 * Update statistics from a SUNI/622 561 */ 562static void 563suni_622_update_stats(struct utopia *utp) 564{ 565 int err; 566 567 /* write to the master if we can */ 568 if (!(utp->flags & UTP_FL_NORESET)) { 569 err = WRITEREG(utp, SUNI_REGO_MRESET, 0, 0); 570 } else { 571 err = WRITEREG(utp, SUNI_REGO_RSOP_BIP8, 0, 0); 572 err |= WRITEREG(utp, SUNI_REGO_RLOPBIP8_24, 0, 0); 573 err |= WRITEREG(utp, SUNI_REGO_RPOPBIP8, 0, 0); 574 err |= WRITEREG(utp, SUNI_REGO_RACPCHCS, 0, 0); 575 err |= WRITEREG(utp, SUNI_REGO_TACPCNT, 0, 0); 576 } 577 if (err) { 578#ifdef DIAGNOSTIC 579 printf("%s: register write error %s: %d\n", __func__, 580 utp->chip->name, err); 581#endif 582 return; 583 } 584 585 DELAY(8); 586 587 utp->stats.rx_sbip += UPDATE16(utp, SUNI_REGO_RSOP_BIP8); 588 utp->stats.rx_lbip += UPDATE20(utp, SUNI_REGO_RLOPBIP8_24); 589 utp->stats.rx_lfebe += UPDATE20(utp, SUNI_REGO_RLOPFEBE); 590 utp->stats.rx_pbip += UPDATE16(utp, SUNI_REGO_RPOPBIP8); 591 utp->stats.rx_pfebe += UPDATE16(utp, SUNI_REGO_RPOPFEBE); 592 utp->stats.rx_corr += UPDATE12(utp, SUNI_REGO_RACPCHCS_622); 593 utp->stats.rx_uncorr += UPDATE12(utp, SUNI_REGO_RACPUHCS_622); 594 utp->stats.rx_cells += UPDATE21(utp, SUNI_REGO_RACPCNT_622); 595 utp->stats.tx_cells += UPDATE21(utp, SUNI_REGO_TACPCNT); 596} 597 598static const struct utopia_chip chip_622 = { 599 UTP_TYPE_SUNI_622, 600 "Suni/622 (PMC-5355)", 601 256, 602 utopia_reset_622, 603 utopia_set_sdh_default, 604 utopia_set_unass_default, 605 utopia_set_noscramb_default, 606 utopia_update_carrier_default, 607 utopia_set_loopback_622, 608 utopia_intr_default, 609 suni_622_update_stats, 610}; 611static const struct utopia_chip chip_lite = { 612 UTP_TYPE_SUNI_LITE, 613 "Suni/Lite (PMC-5346)", 614 256, 615 utopia_reset_default, 616 utopia_set_sdh_default, 617 utopia_set_unass_default, 618 utopia_set_noscramb_default, 619 utopia_update_carrier_default, 620 utopia_set_loopback_lite, 621 utopia_intr_default, 622 suni_lite_update_stats, 623}; 624static const struct utopia_chip chip_ultra = { 625 UTP_TYPE_SUNI_ULTRA, 626 "Suni/Ultra (PMC-5350)", 627 256, 628 utopia_reset_default, 629 utopia_set_sdh_default, 630 utopia_set_unass_default, 631 utopia_set_noscramb_default, 632 utopia_update_carrier_default, 633 utopia_set_loopback_ultra, 634 utopia_intr_default, 635 suni_lite_update_stats, 636}; 637 638/* 639 * Reset IDT77105. There is really no way to reset this thing by acessing 640 * the registers. Load the registers with default values. 641 */ 642static int 643idt77105_reset(struct utopia *utp) 644{ 645 int err = 0; 646 u_int n; 647 uint8_t val[2]; 648 649 err |= WRITEREG(utp, IDTPHY_REGO_MCR, 0xff, 650 IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI); 651 n = 1; 652 err |= READREGS(utp, IDTPHY_REGO_ISTAT, val, &n); 653 err |= WRITEREG(utp, IDTPHY_REGO_DIAG, 0xff, 0); 654 err |= WRITEREG(utp, IDTPHY_REGO_LHEC, 0xff, 0); 655 656 err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_SEC); 657 n = 2; 658 err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n); 659 660 err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_TX); 661 n = 2; 662 err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n); 663 664 err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_RX); 665 n = 2; 666 err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n); 667 668 err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_HECE); 669 n = 2; 670 err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n); 671 672 err |= WRITEREG(utp, IDTPHY_REGO_MCR, IDTPHY_REGM_MCR_DREC, 673 IDTPHY_REGM_MCR_DREC); 674 err |= WRITEREG(utp, IDTPHY_REGO_DIAG, IDTPHY_REGM_DIAG_RFLUSH, 675 IDTPHY_REGM_DIAG_RFLUSH); 676 677 /* loopback */ 678 err |= utopia_set_loopback(utp, utp->loopback); 679 680 /* update carrier state */ 681 err |= utopia_update_carrier(utp); 682 683 return (err ? EIO : 0); 684} 685 686static int 687unknown_inval(struct utopia *utp, int what __unused) 688{ 689 return (EINVAL); 690} 691 692static int 693idt77105_update_carrier(struct utopia *utp) 694{ 695 int err; 696 uint8_t reg; 697 u_int n = 1; 698 699 if ((err = READREGS(utp, IDTPHY_REGO_ISTAT, ®, &n)) != 0) { 700 utp->carrier = UTP_CARR_UNKNOWN; 701 return (err); 702 } 703 utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD); 704 return (0); 705} 706 707static int 708idt77105_set_loopback(struct utopia *utp, u_int mode) 709{ 710 int err; 711 712 switch (mode) { 713 case UTP_LOOP_NONE: 714 err = WRITEREG(utp, IDTPHY_REGO_DIAG, 715 IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_NONE); 716 break; 717 718 case UTP_LOOP_DIAG: 719 err = WRITEREG(utp, IDTPHY_REGO_DIAG, 720 IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_PHY); 721 break; 722 723 case UTP_LOOP_LINE: 724 err = WRITEREG(utp, IDTPHY_REGO_DIAG, 725 IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_LINE); 726 break; 727 728 default: 729 return (EINVAL); 730 } 731 if (err) 732 return (err); 733 utp->loopback = mode; 734 return (0); 735} 736 737/* 738 * Handle interrupt on IDT77105 chip 739 */ 740static void 741idt77105_intr(struct utopia *utp) 742{ 743 uint8_t reg; 744 u_int n = 1; 745 int err; 746 747 /* Interrupt status and ack the interrupt */ 748 if ((err = READREGS(utp, IDTPHY_REGO_ISTAT, ®, &n)) != 0) { 749 printf("IDT77105 read error %d\n", err); 750 return; 751 } 752 /* check for signal condition */ 753 utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD); 754} 755 756static void 757idt77105_update_stats(struct utopia *utp) 758{ 759 int err = 0; 760 uint8_t regs[2]; 761 u_int n; 762 763#ifdef DIAGNOSTIC 764#define UDIAG(F,A,B) printf(F, A, B) 765#else 766#define UDIAG(F,A,B) do { } while (0) 767#endif 768 769#define UPD(FIELD, CODE, N, MASK) \ 770 err = WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, CODE); \ 771 if (err != 0) { \ 772 UDIAG("%s: cannot write CNTS: %d\n", __func__, err); \ 773 return; \ 774 } \ 775 n = N; \ 776 err = READREGS(utp, IDTPHY_REGO_CNT, regs, &n); \ 777 if (err != 0) { \ 778 UDIAG("%s: cannot read CNT: %d\n", __func__, err); \ 779 return; \ 780 } \ 781 if (n != N) { \ 782 UDIAG("%s: got only %u registers\n", __func__, n); \ 783 return; \ 784 } \ 785 if (N == 1) \ 786 utp->stats.FIELD += (regs[0] & MASK); \ 787 else \ 788 utp->stats.FIELD += (regs[0] | (regs[1] << 8)) & MASK; 789 790 UPD(rx_symerr, IDTPHY_REGM_CNTS_SEC, 1, 0xff); 791 UPD(tx_cells, IDTPHY_REGM_CNTS_TX, 2, 0xffff); 792 UPD(rx_cells, IDTPHY_REGM_CNTS_RX, 2, 0xffff); 793 UPD(rx_uncorr, IDTPHY_REGM_CNTS_HECE, 1, 0x1f); 794 795#undef UDIAG 796#undef UPD 797} 798 799static const struct utopia_chip chip_idt77105 = { 800 UTP_TYPE_IDT77105, 801 "IDT77105", 802 7, 803 idt77105_reset, 804 unknown_inval, 805 unknown_inval, 806 unknown_inval, 807 idt77105_update_carrier, 808 idt77105_set_loopback, 809 idt77105_intr, 810 idt77105_update_stats, 811}; 812 813/* 814 * Update the carrier status 815 */ 816static int 817idt77155_update_carrier(struct utopia *utp) 818{ 819 int err; 820 uint8_t reg; 821 u_int n = 1; 822 823 if ((err = READREGS(utp, IDTPHY_REGO_RSOS, ®, &n)) != 0) { 824 utp->carrier = UTP_CARR_UNKNOWN; 825 return (err); 826 } 827 utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS)); 828 return (0); 829} 830 831/* 832 * Handle interrupt on IDT77155 chip 833 */ 834static void 835idt77155_intr(struct utopia *utp) 836{ 837 uint8_t reg; 838 u_int n = 1; 839 int err; 840 841 if ((err = READREGS(utp, IDTPHY_REGO_RSOS, ®, &n)) != 0) { 842 printf("IDT77105 read error %d\n", err); 843 return; 844 } 845 utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS)); 846} 847 848/* 849 * set SONET/SDH mode 850 */ 851static int 852idt77155_set_sdh(struct utopia *utp, int sdh) 853{ 854 int err; 855 856 if (sdh) 857 err = WRITEREG(utp, IDTPHY_REGO_PTRM, 858 IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SDH); 859 else 860 err = WRITEREG(utp, IDTPHY_REGO_PTRM, 861 IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SONET); 862 if (err != 0) 863 return (err); 864 865 utp->state &= ~UTP_ST_SDH; 866 if (sdh) 867 utp->state |= UTP_ST_SDH; 868 869 return (0); 870} 871 872/* 873 * set idle/unassigned cells 874 */ 875static int 876idt77155_set_unass(struct utopia *utp, int unass) 877{ 878 int err; 879 880 if (unass) 881 err = WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 0); 882 else 883 err = WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 1); 884 if (err != 0) 885 return (err); 886 887 utp->state &= ~UTP_ST_UNASS; 888 if (unass) 889 utp->state |= UTP_ST_UNASS; 890 891 return (0); 892} 893 894/* 895 * enable/disable scrambling 896 */ 897static int 898idt77155_set_noscramb(struct utopia *utp, int noscramb) 899{ 900 int err; 901 902 if (noscramb) { 903 err = WRITEREG(utp, IDTPHY_REGO_TCC, 904 IDTPHY_REGM_TCC_DSCR, IDTPHY_REGM_TCC_DSCR); 905 if (err) 906 return (err); 907 err = WRITEREG(utp, IDTPHY_REGO_RCC, 908 IDTPHY_REGM_RCC_DSCR, IDTPHY_REGM_RCC_DSCR); 909 if (err) 910 return (err); 911 utp->state |= UTP_ST_NOSCRAMB; 912 } else { 913 err = WRITEREG(utp, IDTPHY_REGO_TCC, 914 IDTPHY_REGM_TCC_DSCR, 0); 915 if (err) 916 return (err); 917 err = WRITEREG(utp, IDTPHY_REGO_RCC, 918 IDTPHY_REGM_RCC_DSCR, 0); 919 if (err) 920 return (err); 921 utp->state &= ~UTP_ST_NOSCRAMB; 922 } 923 return (0); 924} 925 926/* 927 * Set loopback mode for the 77155 928 */ 929static int 930idt77155_set_loopback(struct utopia *utp, u_int mode) 931{ 932 int err; 933 uint32_t val; 934 u_int nmode; 935 936 val = 0; 937 nmode = mode; 938 if (mode & UTP_LOOP_TIME) { 939 nmode &= ~UTP_LOOP_TIME; 940 val |= IDTPHY_REGM_MCTL_TLOOP; 941 } 942 if (mode & UTP_LOOP_DIAG) { 943 nmode &= ~UTP_LOOP_DIAG; 944 val |= IDTPHY_REGM_MCTL_DLOOP; 945 } 946 if (mode & UTP_LOOP_LINE) { 947 nmode &= ~UTP_LOOP_LINE; 948 val |= IDTPHY_REGM_MCTL_LLOOP; 949 } 950 if (nmode != 0) 951 return (EINVAL); 952 953 err = WRITEREG(utp, IDTPHY_REGO_MCTL, IDTPHY_REGM_MCTL_TLOOP | 954 IDTPHY_REGM_MCTL_DLOOP | IDTPHY_REGM_MCTL_LLOOP, val); 955 if (err) 956 return (err); 957 utp->loopback = mode; 958 959 return (0); 960} 961 962/* 963 * Set the chip to reflect the current state in utopia. 964 * Assume, that the chip has been reset. 965 */ 966static int 967idt77155_set_chip(struct utopia *utp) 968{ 969 int err = 0; 970 971 /* set sonet/sdh */ 972 err |= idt77155_set_sdh(utp, utp->state & UTP_ST_SDH); 973 974 /* unassigned or idle cells */ 975 err |= idt77155_set_unass(utp, utp->state & UTP_ST_UNASS); 976 977 /* loopback */ 978 err |= idt77155_set_loopback(utp, utp->loopback); 979 980 /* update carrier state */ 981 err |= idt77155_update_carrier(utp); 982 983 /* enable interrupts on LOS */ 984 err |= WRITEREG(utp, IDTPHY_REGO_INT, 985 IDTPHY_REGM_INT_RXSOHI, IDTPHY_REGM_INT_RXSOHI); 986 err |= WRITEREG(utp, IDTPHY_REGO_RSOC, 987 IDTPHY_REGM_RSOC_LOSI, IDTPHY_REGM_RSOC_LOSI); 988 989 return (err ? EIO : 0); 990} 991 992/* 993 * Reset the chip to reflect the current state of utopia. 994 */ 995static int 996idt77155_reset(struct utopia *utp) 997{ 998 int err = 0; 999 1000 if (!(utp->flags & UTP_FL_NORESET)) { 1001 err |= WRITEREG(utp, IDTPHY_REGO_MRID, IDTPHY_REGM_MRID_RESET, 1002 IDTPHY_REGM_MRID_RESET); 1003 err |= WRITEREG(utp, IDTPHY_REGO_MRID, IDTPHY_REGM_MRID_RESET, 1004 0); 1005 } 1006 1007 err |= idt77155_set_chip(utp); 1008 1009 return (err ? EIO : 0); 1010} 1011 1012/* 1013 * Update statistics from a IDT77155 1014 * This appears to be the same as for the Suni/Lite and Ultra. IDT however 1015 * makes no assessment about the transfer time. Assume 7us. 1016 */ 1017static void 1018idt77155_update_stats(struct utopia *utp) 1019{ 1020 int err; 1021 1022 /* write to the master if we can */ 1023 if (!(utp->flags & UTP_FL_NORESET)) { 1024 err = WRITEREG(utp, IDTPHY_REGO_MRID, 0, 0); 1025 } else { 1026 err = WRITEREG(utp, IDTPHY_REGO_BIPC, 0, 0); 1027 err |= WRITEREG(utp, IDTPHY_REGO_B2EC, 0, 0); 1028 err |= WRITEREG(utp, IDTPHY_REGO_B3EC, 0, 0); 1029 err |= WRITEREG(utp, IDTPHY_REGO_CEC, 0, 0); 1030 err |= WRITEREG(utp, IDTPHY_REGO_TXCNT, 0, 0); 1031 1032 } 1033 if (err) { 1034#ifdef DIAGNOSTIC 1035 printf("%s: register write error %s: %d\n", __func__, 1036 utp->chip->name, err); 1037#endif 1038 return; 1039 } 1040 1041 DELAY(8); 1042 1043 utp->stats.rx_sbip += UPDATE16(utp, IDTPHY_REGO_BIPC); 1044 utp->stats.rx_lbip += UPDATE20(utp, IDTPHY_REGO_B2EC); 1045 utp->stats.rx_lfebe += UPDATE20(utp, IDTPHY_REGO_FEBEC); 1046 utp->stats.rx_pbip += UPDATE16(utp, IDTPHY_REGO_B3EC); 1047 utp->stats.rx_pfebe += UPDATE16(utp, IDTPHY_REGO_PFEBEC); 1048 utp->stats.rx_corr += UPDATE8(utp, IDTPHY_REGO_CEC); 1049 utp->stats.rx_uncorr += UPDATE8(utp, IDTPHY_REGO_UEC); 1050 utp->stats.rx_cells += UPDATE19(utp, IDTPHY_REGO_RCCNT); 1051 utp->stats.tx_cells += UPDATE19(utp, IDTPHY_REGO_TXCNT); 1052} 1053 1054 1055static const struct utopia_chip chip_idt77155 = { 1056 UTP_TYPE_IDT77155, 1057 "IDT77155", 1058 0x80, 1059 idt77155_reset, 1060 idt77155_set_sdh, 1061 idt77155_set_unass, 1062 idt77155_set_noscramb, 1063 idt77155_update_carrier, 1064 idt77155_set_loopback, 1065 idt77155_intr, 1066 idt77155_update_stats, 1067}; 1068 1069static int 1070unknown_reset(struct utopia *utp __unused) 1071{ 1072 return (EIO); 1073} 1074 1075static int 1076unknown_update_carrier(struct utopia *utp) 1077{ 1078 utp->carrier = UTP_CARR_UNKNOWN; 1079 return (0); 1080} 1081 1082static int 1083unknown_set_loopback(struct utopia *utp __unused, u_int mode __unused) 1084{ 1085 return (EINVAL); 1086} 1087 1088static void 1089unknown_intr(struct utopia *utp __unused) 1090{ 1091} 1092 1093static void 1094unknown_update_stats(struct utopia *utp __unused) 1095{ 1096} 1097 1098static const struct utopia_chip chip_unknown = { 1099 UTP_TYPE_UNKNOWN, 1100 "unknown", 1101 0, 1102 unknown_reset, 1103 unknown_inval, 1104 unknown_inval, 1105 unknown_inval, 1106 unknown_update_carrier, 1107 unknown_set_loopback, 1108 unknown_intr, 1109 unknown_update_stats, 1110}; 1111 1112/* 1113 * Callbacks for the ifmedia infrastructure. 1114 */ 1115static int 1116utopia_media_change(struct ifnet *ifp) 1117{ 1118 struct ifatm *ifatm = (struct ifatm *)ifp->if_softc; 1119 struct utopia *utp = ifatm->phy; 1120 int error = 0; 1121 1122 UTP_LOCK(utp); 1123 if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) { 1124 if (utp->media->ifm_media & IFM_ATM_SDH) { 1125 if (!(utp->state & UTP_ST_SDH)) 1126 error = utopia_set_sdh(utp, 1); 1127 } else { 1128 if (utp->state & UTP_ST_SDH) 1129 error = utopia_set_sdh(utp, 0); 1130 } 1131 if (utp->media->ifm_media & IFM_ATM_UNASSIGNED) { 1132 if (!(utp->state & UTP_ST_UNASS)) 1133 error = utopia_set_unass(utp, 1); 1134 } else { 1135 if (utp->state & UTP_ST_UNASS) 1136 error = utopia_set_unass(utp, 0); 1137 } 1138 if (utp->media->ifm_media & IFM_ATM_NOSCRAMB) { 1139 if (!(utp->state & UTP_ST_NOSCRAMB)) 1140 error = utopia_set_noscramb(utp, 1); 1141 } else { 1142 if (utp->state & UTP_ST_NOSCRAMB) 1143 error = utopia_set_noscramb(utp, 0); 1144 } 1145 } else 1146 error = EIO; 1147 UTP_UNLOCK(utp); 1148 return (error); 1149} 1150 1151/* 1152 * Look at the carrier status. 1153 */ 1154static void 1155utopia_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 1156{ 1157 struct utopia *utp = ((struct ifatm *)ifp->if_softc)->phy; 1158 1159 UTP_LOCK(utp); 1160 if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) { 1161 ifmr->ifm_active = IFM_ATM | utp->ifatm->mib.media; 1162 1163 switch (utp->carrier) { 1164 1165 case UTP_CARR_OK: 1166 ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; 1167 break; 1168 1169 case UTP_CARR_LOST: 1170 ifmr->ifm_status = IFM_AVALID; 1171 break; 1172 1173 default: 1174 ifmr->ifm_status = 0; 1175 break; 1176 } 1177 if (utp->state & UTP_ST_SDH) { 1178 ifmr->ifm_active |= IFM_ATM_SDH; 1179 ifmr->ifm_current |= IFM_ATM_SDH; 1180 } 1181 if (utp->state & UTP_ST_UNASS) { 1182 ifmr->ifm_active |= IFM_ATM_UNASSIGNED; 1183 ifmr->ifm_current |= IFM_ATM_UNASSIGNED; 1184 } 1185 if (utp->state & UTP_ST_NOSCRAMB) { 1186 ifmr->ifm_active |= IFM_ATM_NOSCRAMB; 1187 ifmr->ifm_current |= IFM_ATM_NOSCRAMB; 1188 } 1189 } else { 1190 ifmr->ifm_active = 0; 1191 ifmr->ifm_status = 0; 1192 } 1193 UTP_UNLOCK(utp); 1194} 1195 1196/* 1197 * Initialize media from the mib 1198 */ 1199void 1200utopia_init_media(struct utopia *utp) 1201{ 1202 1203 ifmedia_removeall(utp->media); 1204 ifmedia_add(utp->media, IFM_ATM | utp->ifatm->mib.media, 0, NULL); 1205 ifmedia_set(utp->media, IFM_ATM | utp->ifatm->mib.media); 1206} 1207 1208/* 1209 * Reset all media 1210 */ 1211void 1212utopia_reset_media(struct utopia *utp) 1213{ 1214 1215 ifmedia_removeall(utp->media); 1216} 1217 1218/* 1219 * This is called by the driver as soon as the SUNI registers are accessible. 1220 * This may be either in the attach routine or the init routine of the driver. 1221 */ 1222int 1223utopia_start(struct utopia *utp) 1224{ 1225 uint8_t reg; 1226 int err; 1227 u_int n = 1; 1228 1229 if ((err = READREGS(utp, SUNI_REGO_MRESET, ®, &n)) != 0) 1230 return (err); 1231 1232 switch (reg & SUNI_REGM_MRESET_TYPE) { 1233 1234 case SUNI_REGM_MRESET_TYPE_622: 1235 utp->chip = &chip_622; 1236 break; 1237 1238 case SUNI_REGM_MRESET_TYPE_LITE: 1239 /* this may be either a SUNI LITE or a IDT77155 * 1240 * Read register 0x70. The SUNI doesn't have it */ 1241 n = 1; 1242 if ((err = READREGS(utp, IDTPHY_REGO_RBER, ®, &n)) != 0) 1243 return (err); 1244 if ((reg & ~IDTPHY_REGM_RBER_RESV) == 1245 (IDTPHY_REGM_RBER_FAIL | IDTPHY_REGM_RBER_WARN)) 1246 utp->chip = &chip_idt77155; 1247 else 1248 utp->chip = &chip_lite; 1249 break; 1250 1251 case SUNI_REGM_MRESET_TYPE_ULTRA: 1252 utp->chip = &chip_ultra; 1253 break; 1254 1255 default: 1256 if (reg == (IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI)) 1257 utp->chip = &chip_idt77105; 1258 else { 1259 if_printf(&utp->ifatm->ifnet, 1260 "unknown ATM-PHY chip %#x\n", reg); 1261 utp->chip = &chip_unknown; 1262 } 1263 break; 1264 } 1265 utp->state |= UTP_ST_ACTIVE; 1266 return (0); 1267} 1268 1269/* 1270 * Stop the chip 1271 */ 1272void 1273utopia_stop(struct utopia *utp) 1274{ 1275 utp->state &= ~UTP_ST_ACTIVE; 1276} 1277 1278/* 1279 * Handle the sysctls 1280 */ 1281static int 1282utopia_sysctl_regs(SYSCTL_HANDLER_ARGS) 1283{ 1284 struct utopia *utp = (struct utopia *)arg1; 1285 int error; 1286 u_int n; 1287 uint8_t *val; 1288 uint8_t new[3]; 1289 1290 if ((n = utp->chip->nregs) == 0) 1291 return (EIO); 1292 val = malloc(sizeof(uint8_t) * n, M_TEMP, M_WAITOK); 1293 1294 UTP_LOCK(utp); 1295 error = READREGS(utp, 0, val, &n); 1296 UTP_UNLOCK(utp); 1297 1298 if (error) { 1299 free(val, M_TEMP); 1300 return (error); 1301 } 1302 1303 error = SYSCTL_OUT(req, val, sizeof(uint8_t) * n); 1304 free(val, M_TEMP); 1305 if (error != 0 || req->newptr == NULL) 1306 return (error); 1307 1308 error = SYSCTL_IN(req, new, sizeof(new)); 1309 if (error) 1310 return (error); 1311 1312 UTP_LOCK(utp); 1313 error = WRITEREG(utp, new[0], new[1], new[2]); 1314 UTP_UNLOCK(utp); 1315 1316 return (error); 1317} 1318 1319static int 1320utopia_sysctl_stats(SYSCTL_HANDLER_ARGS) 1321{ 1322 struct utopia *utp = (struct utopia *)arg1; 1323 void *val; 1324 int error; 1325 1326 val = malloc(sizeof(utp->stats), M_TEMP, M_WAITOK); 1327 1328 UTP_LOCK(utp); 1329 bcopy(&utp->stats, val, sizeof(utp->stats)); 1330 if (req->newptr != NULL) 1331 bzero((char *)&utp->stats + sizeof(utp->stats.version), 1332 sizeof(utp->stats) - sizeof(utp->stats.version)); 1333 UTP_UNLOCK(utp); 1334 1335 error = SYSCTL_OUT(req, val, sizeof(utp->stats)); 1336 free(val, M_TEMP); 1337 1338 if (error && req->newptr != NULL) 1339 bcopy(val, &utp->stats, sizeof(utp->stats)); 1340 1341 /* ignore actual new value */ 1342 1343 return (error); 1344} 1345 1346/* 1347 * Handle the loopback sysctl 1348 */ 1349static int 1350utopia_sysctl_loopback(SYSCTL_HANDLER_ARGS) 1351{ 1352 struct utopia *utp = (struct utopia *)arg1; 1353 int error; 1354 u_int loopback; 1355 1356 error = SYSCTL_OUT(req, &utp->loopback, sizeof(u_int)); 1357 if (error != 0 || req->newptr == NULL) 1358 return (error); 1359 1360 error = SYSCTL_IN(req, &loopback, sizeof(u_int)); 1361 if (error) 1362 return (error); 1363 1364 UTP_LOCK(utp); 1365 error = utopia_set_loopback(utp, loopback); 1366 UTP_UNLOCK(utp); 1367 1368 return (error); 1369} 1370 1371/* 1372 * Handle the type sysctl 1373 */ 1374static int 1375utopia_sysctl_type(SYSCTL_HANDLER_ARGS) 1376{ 1377 struct utopia *utp = (struct utopia *)arg1; 1378 1379 return (SYSCTL_OUT(req, &utp->chip->type, sizeof(utp->chip->type))); 1380} 1381 1382/* 1383 * Handle the name sysctl 1384 */ 1385static int 1386utopia_sysctl_name(SYSCTL_HANDLER_ARGS) 1387{ 1388 struct utopia *utp = (struct utopia *)arg1; 1389 1390 return (SYSCTL_OUT(req, utp->chip->name, strlen(utp->chip->name) + 1)); 1391} 1392 1393/* 1394 * Initialize the state. This is called from the drivers attach 1395 * function. The mutex must be already initialized. 1396 */ 1397int 1398utopia_attach(struct utopia *utp, struct ifatm *ifatm, struct ifmedia *media, 1399 struct mtx *lock, struct sysctl_ctx_list *ctx, 1400 struct sysctl_oid_list *children, const struct utopia_methods *m) 1401{ 1402 1403 bzero(utp, sizeof(*utp)); 1404 utp->ifatm = ifatm; 1405 utp->methods = m; 1406 utp->media = media; 1407 utp->lock = lock; 1408 utp->chip = &chip_unknown; 1409 utp->stats.version = 1; 1410 1411 ifmedia_init(media, 1412 IFM_ATM_SDH | IFM_ATM_UNASSIGNED | IFM_ATM_NOSCRAMB, 1413 utopia_media_change, utopia_media_status); 1414 1415 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_regs", 1416 CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_regs, "S", 1417 "phy registers") == NULL) 1418 return (-1); 1419 1420 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_loopback", 1421 CTLFLAG_RW | CTLTYPE_UINT, utp, 0, utopia_sysctl_loopback, "IU", 1422 "phy loopback mode") == NULL) 1423 return (-1); 1424 1425 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_type", 1426 CTLFLAG_RD | CTLTYPE_UINT, utp, 0, utopia_sysctl_type, "IU", 1427 "phy type") == NULL) 1428 return (-1); 1429 1430 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_name", 1431 CTLFLAG_RD | CTLTYPE_STRING, utp, 0, utopia_sysctl_name, "A", 1432 "phy name") == NULL) 1433 return (-1); 1434 1435 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_stats", 1436 CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_stats, "S", 1437 "phy statistics") == NULL) 1438 return (-1); 1439 1440 if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_state", 1441 CTLFLAG_RD, &utp->state, 0, "phy state") == NULL) 1442 return (-1); 1443 1444 if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_carrier", 1445 CTLFLAG_RD, &utp->carrier, 0, "phy carrier") == NULL) 1446 return (-1); 1447 1448 UTP_WLOCK_LIST(); 1449 LIST_INSERT_HEAD(&utopia_list, utp, link); 1450 UTP_WUNLOCK_LIST(); 1451 1452 utp->state |= UTP_ST_ATTACHED; 1453 return (0); 1454} 1455 1456/* 1457 * Detach. We set a flag here, wakeup the daemon and let him do it. 1458 * Here we need the lock for synchronisation with the daemon. 1459 */ 1460void 1461utopia_detach(struct utopia *utp) 1462{ 1463 1464 UTP_LOCK_ASSERT(utp); 1465 if (utp->state & UTP_ST_ATTACHED) { 1466 utp->state |= UTP_ST_DETACH; 1467 while (utp->state & UTP_ST_DETACH) { 1468 wakeup(&utopia_list); 1469 msleep(utp, utp->lock, PZERO, "utopia_detach", hz); 1470 } 1471 } 1472} 1473 1474/* 1475 * The carrier state kernel proc for those adapters that do not interrupt. 1476 * 1477 * We assume, that utopia_attach can safely add a new utopia while we are going 1478 * through the list without disturbing us (we lock the list while getting 1479 * the address of the first element, adding is always done at the head). 1480 * Removing is entirely handled here. 1481 */ 1482static void 1483utopia_daemon(void *arg __unused) 1484{ 1485 struct utopia *utp, *next; 1486 1487 UTP_RLOCK_LIST(); 1488 while (utopia_kproc != NULL) { 1489 utp = LIST_FIRST(&utopia_list); 1490 UTP_RUNLOCK_LIST(); 1491 1492 while (utp != NULL) { 1493 mtx_lock(&Giant); /* XXX depend on MPSAFE */ 1494 UTP_LOCK(utp); 1495 next = LIST_NEXT(utp, link); 1496 if (utp->state & UTP_ST_DETACH) { 1497 LIST_REMOVE(utp, link); 1498 utp->state &= ~UTP_ST_DETACH; 1499 wakeup_one(utp); 1500 } else if (utp->state & UTP_ST_ACTIVE) { 1501 if (utp->flags & UTP_FL_POLL_CARRIER) 1502 utopia_update_carrier(utp); 1503 utopia_update_stats(utp); 1504 } 1505 UTP_UNLOCK(utp); 1506 mtx_unlock(&Giant); /* XXX depend on MPSAFE */ 1507 utp = next; 1508 } 1509 1510 UTP_RLOCK_LIST(); 1511 msleep(&utopia_list, &utopia_list_mtx, PZERO, "*idle*", hz); 1512 } 1513 wakeup_one(&utopia_list); 1514 UTP_RUNLOCK_LIST(); 1515 mtx_lock(&Giant); 1516 kthread_exit(0); 1517} 1518 1519/* 1520 * Module initialisation 1521 */ 1522static int 1523utopia_mod_init(module_t mod, int what, void *arg) 1524{ 1525 int err; 1526 struct proc *kp; 1527 1528 switch (what) { 1529 1530 case MOD_LOAD: 1531 mtx_init(&utopia_list_mtx, "utopia list mutex", NULL, MTX_DEF); 1532 err = kthread_create(utopia_daemon, NULL, &utopia_kproc, 1533 RFHIGHPID, 0, "utopia"); 1534 if (err != 0) { 1535 printf("cannot created utopia thread %d\n", err); 1536 return (err); 1537 } 1538 break; 1539 1540 case MOD_UNLOAD: 1541 UTP_WLOCK_LIST(); 1542 if ((kp = utopia_kproc) != NULL) { 1543 utopia_kproc = NULL; 1544 wakeup_one(&utopia_list); 1545 PROC_LOCK(kp); 1546 UTP_WUNLOCK_LIST(); 1547 msleep(kp, &kp->p_mtx, PWAIT, "utopia_destroy", 0); 1548 PROC_UNLOCK(kp); 1549 } else 1550 UTP_WUNLOCK_LIST(); 1551 mtx_destroy(&utopia_list_mtx); 1552 break; 1553 } 1554 return (0); 1555} 1556 1557static moduledata_t utopia_mod = { 1558 "utopia", 1559 utopia_mod_init, 1560 0 1561}; 1562 1563DECLARE_MODULE(utopia, utopia_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 1564MODULE_VERSION(utopia, 1); 1565