utopia.c revision 117546
1/* 2 * Copyright (c) 2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * Author: Hartmut Brandt <harti@freebsd.org> 28 */ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: head/sys/dev/utopia/utopia.c 117546 2003-07-14 12:12:50Z harti $"); 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/unistd.h> 36#include <sys/kernel.h> 37#include <sys/kthread.h> 38#include <sys/proc.h> 39#include <sys/bus.h> 40#include <sys/malloc.h> 41#include <sys/sysctl.h> 42#include <sys/lock.h> 43#include <sys/mutex.h> 44#include <sys/socket.h> 45 46#include <net/if.h> 47#include <net/if_var.h> 48#include <net/if_media.h> 49#include <net/if_atm.h> 50 51#include <dev/utopia/suni.h> 52#include <dev/utopia/idtphy.h> 53#include <dev/utopia/utopia.h> 54 55#define READREGS(UTOPIA, REG, VALP, NP) \ 56 (UTOPIA)->methods->readregs((UTOPIA)->ifatm, REG, VALP, NP) 57#define WRITEREG(UTOPIA, REG, MASK, VAL) \ 58 (UTOPIA)->methods->writereg((UTOPIA)->ifatm, REG, MASK, VAL) 59 60/* 61 * Global list of all registered interfaces 62 */ 63static struct mtx utopia_list_mtx; 64static LIST_HEAD(, utopia) utopia_list = LIST_HEAD_INITIALIZER(utopia_list); 65 66#define UTP_RLOCK_LIST() mtx_lock(&utopia_list_mtx) 67#define UTP_RUNLOCK_LIST() mtx_unlock(&utopia_list_mtx) 68#define UTP_WLOCK_LIST() mtx_lock(&utopia_list_mtx) 69#define UTP_WUNLOCK_LIST() mtx_unlock(&utopia_list_mtx) 70 71#define UTP_LOCK(UTP) mtx_lock((UTP)->lock) 72#define UTP_UNLOCK(UTP) mtx_unlock((UTP)->lock) 73#define UTP_LOCK_ASSERT(UTP) mtx_assert((UTP)->lock, MA_OWNED) 74 75static struct proc *utopia_kproc; 76 77static void utopia_dump(struct utopia *) __unused; 78 79/* 80 * Debugging - dump all registers. 81 */ 82static void 83utopia_dump(struct utopia *utp) 84{ 85 uint8_t regs[256]; 86 u_int n = 256, i; 87 int err; 88 89 if ((err = READREGS(utp, SUNI_REGO_MRESET, regs, &n)) != 0) { 90 printf("SUNI read error %d\n", err); 91 return; 92 } 93 for (i = 0; i < n; i++) { 94 if (i % 16 == 0) 95 printf("%02x:", i); 96 if (i % 16 == 8) 97 printf(" "); 98 printf(" %02x", regs[i]); 99 if (i % 16 == 15) 100 printf("\n"); 101 } 102 if (i % 16 != 0) 103 printf("\n"); 104} 105 106/* 107 * Update the carrier status 108 */ 109static void 110utopia_check_carrier(struct utopia *utp, u_int carr_ok) 111{ 112 int old; 113 114 old = utp->carrier; 115 if (carr_ok) { 116 /* carrier */ 117 utp->carrier = UTP_CARR_OK; 118 if (old != UTP_CARR_OK) { 119 if_printf(&utp->ifatm->ifnet, "carrier detected\n"); 120 } 121 } else { 122 /* no carrier */ 123 utp->carrier = UTP_CARR_LOST; 124 if (old == UTP_CARR_OK) { 125 if_printf(&utp->ifatm->ifnet, "carrier lost\n"); 126 } 127 } 128} 129 130static int 131utopia_update_carrier_default(struct utopia *utp) 132{ 133 int err; 134 uint8_t reg; 135 u_int n = 1; 136 137 if ((err = READREGS(utp, SUNI_REGO_RSOPSIS, ®, &n)) != 0) { 138 utp->carrier = UTP_CARR_UNKNOWN; 139 return (err); 140 } 141 utopia_check_carrier(utp, !(reg & SUNI_REGM_RSOPSIS_LOSV)); 142 return (0); 143} 144 145/* 146 * enable/disable scrambling 147 */ 148static int 149utopia_set_noscramb_default(struct utopia *utp, int noscramb) 150{ 151 int err; 152 153 if (noscramb) { 154 err = WRITEREG(utp, SUNI_REGO_TACPCTRL, 155 SUNI_REGM_TACPCTRL_DSCR, SUNI_REGM_TACPCTRL_DSCR); 156 if (err) 157 return (err); 158 err = WRITEREG(utp, SUNI_REGO_RACPCTRL, 159 SUNI_REGM_RACPCTRL_DDSCR, SUNI_REGM_RACPCTRL_DDSCR); 160 if (err) 161 return (err); 162 utp->state |= UTP_ST_NOSCRAMB; 163 } else { 164 err = WRITEREG(utp, SUNI_REGO_TACPCTRL, 165 SUNI_REGM_TACPCTRL_DSCR, 0); 166 if (err) 167 return (err); 168 err = WRITEREG(utp, SUNI_REGO_RACPCTRL, 169 SUNI_REGM_RACPCTRL_DDSCR, 0); 170 if (err) 171 return (err); 172 utp->state &= ~UTP_ST_NOSCRAMB; 173 } 174 return (0); 175} 176 177/* 178 * set SONET/SDH mode 179 */ 180static int 181utopia_set_sdh_default(struct utopia *utp, int sdh) 182{ 183 int err; 184 185 if (sdh) 186 err = WRITEREG(utp, SUNI_REGO_TPOPAPTR + 1, 187 SUNI_REGM_TPOPAPTR_S, 188 SUNI_REGM_SDH << SUNI_REGS_TPOPAPTR_S); 189 else 190 err = WRITEREG(utp, SUNI_REGO_TPOPAPTR + 1, 191 SUNI_REGM_TPOPAPTR_S, 192 SUNI_REGM_SONET << SUNI_REGS_TPOPAPTR_S); 193 if (err != 0) 194 return (err); 195 196 utp->state &= ~UTP_ST_SDH; 197 if (sdh) 198 utp->state |= UTP_ST_SDH; 199 200 return (0); 201} 202 203/* 204 * set idle/unassigned cells 205 */ 206static int 207utopia_set_unass_default(struct utopia *utp, int unass) 208{ 209 int err; 210 211 if (unass) 212 err = WRITEREG(utp, SUNI_REGO_TACPIDLEH, 213 0xff, (0 << SUNI_REGS_TACPIDLEH_CLP)); 214 else 215 err = WRITEREG(utp, SUNI_REGO_TACPIDLEH, 216 0xff, (1 << SUNI_REGS_TACPIDLEH_CLP)); 217 if (err != 0) 218 return (err); 219 220 utp->state &= ~UTP_ST_UNASS; 221 if (unass) 222 utp->state |= UTP_ST_UNASS; 223 224 return (0); 225} 226 227/* 228 * Set loopback mode for the Lite 229 */ 230static int 231utopia_set_loopback_lite(struct utopia *utp, u_int mode) 232{ 233 int err; 234 uint32_t val; 235 u_int nmode; 236 237 val = 0; 238 nmode = mode; 239 if (mode & UTP_LOOP_TIME) { 240 nmode &= ~UTP_LOOP_TIME; 241 val |= SUNI_REGM_MCTRL_LOOPT; 242 } 243 if (mode & UTP_LOOP_DIAG) { 244 nmode &= ~UTP_LOOP_DIAG; 245 val |= SUNI_REGM_MCTRL_DLE; 246 } 247 if (mode & UTP_LOOP_LINE) { 248 nmode &= ~UTP_LOOP_LINE; 249 if (val & SUNI_REGM_MCTRL_DLE) 250 return (EINVAL); 251 val |= SUNI_REGM_MCTRL_LLE; 252 } 253 if (nmode != 0) 254 return (EINVAL); 255 256 err = WRITEREG(utp, SUNI_REGO_MCTRL, 257 SUNI_REGM_MCTRL_LLE | SUNI_REGM_MCTRL_DLE | SUNI_REGM_MCTRL_LOOPT, 258 val); 259 if (err) 260 return (err); 261 utp->loopback = mode; 262 263 return (0); 264} 265 266/* 267 * Set loopback mode for the Ultra 268 */ 269static int 270utopia_set_loopback_ultra(struct utopia *utp, u_int mode) 271{ 272 int err; 273 uint32_t val; 274 u_int nmode; 275 276 val = 0; 277 nmode = mode; 278 if (mode & UTP_LOOP_TIME) { 279 nmode &= ~UTP_LOOP_TIME; 280 val |= SUNI_REGM_MCTRL_LOOPT; 281 } 282 if (mode & UTP_LOOP_DIAG) { 283 nmode &= ~UTP_LOOP_DIAG; 284 if (val & SUNI_REGM_MCTRL_LOOPT) 285 return (EINVAL); 286 val |= SUNI_REGM_MCTRL_SDLE; 287 } 288 if (mode & UTP_LOOP_LINE) { 289 nmode &= ~UTP_LOOP_LINE; 290 if (val & (SUNI_REGM_MCTRL_LOOPT | SUNI_REGM_MCTRL_SDLE)) 291 return (EINVAL); 292 val |= SUNI_REGM_MCTRL_LLE; 293 } 294 if (mode & UTP_LOOP_PARAL) { 295 nmode &= ~UTP_LOOP_PARAL; 296 val |= SUNI_REGM_MCTRL_PDLE; 297 } 298 if (mode & UTP_LOOP_TWIST) { 299 nmode &= ~UTP_LOOP_TWIST; 300 val |= SUNI_REGM_MCTRL_TPLE; 301 } 302 if (nmode != 0) 303 return (EINVAL); 304 305 err = WRITEREG(utp, SUNI_REGO_MCTRL, 306 SUNI_REGM_MCTRL_LLE | SUNI_REGM_MCTRL_SDLE | SUNI_REGM_MCTRL_LOOPT | 307 SUNI_REGM_MCTRL_PDLE | SUNI_REGM_MCTRL_TPLE, val); 308 if (err) 309 return (err); 310 utp->loopback = mode; 311 312 return (0); 313} 314 315/* 316 * Set loopback mode for the Ultra 317 */ 318static int 319utopia_set_loopback_622(struct utopia *utp, u_int mode) 320{ 321 int err; 322 uint32_t val; 323 uint8_t config; 324 int smode; 325 u_int nmode; 326 u_int n = 1; 327 328 val = 0; 329 nmode = mode; 330 if (mode & UTP_LOOP_PATH) { 331 nmode &= ~UTP_LOOP_PATH; 332 val |= SUNI_REGM_MCTRLM_DPLE; 333 } 334 335 err = READREGS(utp, SUNI_REGO_MCONFIG, &config, &n); 336 if (err != 0) 337 return (err); 338 smode = ((config & SUNI_REGM_MCONFIG_TMODE_622) == 339 SUNI_REGM_MCONFIG_TMODE_STS1_BIT && 340 (config & SUNI_REGM_MCONFIG_RMODE_622) == 341 SUNI_REGM_MCONFIG_RMODE_STS1_BIT); 342 343 if (mode & UTP_LOOP_TIME) { 344 if (!smode) 345 return (EINVAL); 346 nmode &= ~UTP_LOOP_TIME; 347 val |= SUNI_REGM_MCTRLM_LOOPT; 348 } 349 if (mode & UTP_LOOP_DIAG) { 350 nmode &= ~UTP_LOOP_DIAG; 351 if (val & SUNI_REGM_MCTRLM_LOOPT) 352 return (EINVAL); 353 val |= SUNI_REGM_MCTRLM_DLE; 354 } 355 if (mode & UTP_LOOP_LINE) { 356 nmode &= ~UTP_LOOP_LINE; 357 if (val & (SUNI_REGM_MCTRLM_LOOPT | SUNI_REGM_MCTRLM_DLE)) 358 return (EINVAL); 359 val |= SUNI_REGM_MCTRLM_LLE; 360 } 361 if (nmode != 0) 362 return (EINVAL); 363 364 err = WRITEREG(utp, SUNI_REGO_MCTRLM, 365 SUNI_REGM_MCTRLM_LLE | SUNI_REGM_MCTRLM_DLE | 366 SUNI_REGM_MCTRLM_DPLE | SUNI_REGM_MCTRL_LOOPT, val); 367 if (err) 368 return (err); 369 utp->loopback = mode; 370 371 return (0); 372} 373 374/* 375 * Set the SUNI chip to reflect the current state in utopia. 376 * Assume, that the chip has been reset. 377 */ 378static int 379utopia_set_chip(struct utopia *utp) 380{ 381 int err = 0; 382 383 /* set sonet/sdh */ 384 err |= utopia_set_sdh(utp, utp->state & UTP_ST_SDH); 385 386 /* unassigned or idle cells */ 387 err |= utopia_set_unass(utp, utp->state & UTP_ST_UNASS); 388 err |= WRITEREG(utp, SUNI_REGO_TACPIDLEP, 0xff, 0x6a); 389 390 /* loopback */ 391 err |= utopia_set_loopback(utp, utp->loopback); 392 393 /* update carrier state */ 394 err |= utopia_update_carrier(utp); 395 396 /* enable interrupts on LOS */ 397 err |= WRITEREG(utp, SUNI_REGO_RSOPCIE, 398 SUNI_REGM_RSOPCIE_LOSE, SUNI_REGM_RSOPCIE_LOSE); 399 400 return (err ? EIO : 0); 401} 402 403/* 404 * Reset the SUNI chip to reflect the current state of utopia. 405 */ 406static int 407utopia_reset_default(struct utopia *utp) 408{ 409 int err = 0; 410 411 if (!(utp->flags & UTP_FL_NORESET)) { 412 err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET, 413 SUNI_REGM_MRESET_RESET); 414 err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET, 415 0); 416 } 417 418 /* disable test mode */ 419 err |= WRITEREG(utp, SUNI_REGO_MTEST, 0xff, 0x00); 420 421 err |= utopia_set_chip(utp); 422 423 return (err ? EIO : 0); 424} 425 426/* 427 * Reset the SUNI chip to reflect the current state of utopia. 428 */ 429static int 430utopia_reset_622(struct utopia *utp) 431{ 432 int err = 0; 433 434 if (!(utp->flags & UTP_FL_NORESET)) { 435 err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET, 436 SUNI_REGM_MRESET_RESET); 437 err |= WRITEREG(utp, SUNI_REGO_MRESET, SUNI_REGM_MRESET_RESET, 438 0); 439 } 440 441 /* disable test mode */ 442 err |= WRITEREG(utp, SUNI_REGO_MTEST, 0xff, 443 SUNI_REGM_MTEST_DS27_53_622); 444 445 err |= utopia_set_chip(utp); 446 447 return (err ? EIO : 0); 448} 449 450/* 451 * Handle interrupt on lite chip 452 */ 453static void 454utopia_intr_default(struct utopia *utp) 455{ 456 uint8_t regs[SUNI_REGO_MTEST]; 457 u_int n = SUNI_REGO_MTEST; 458 int err; 459 460 /* Read all registers. This acks the interrupts */ 461 if ((err = READREGS(utp, SUNI_REGO_MRESET, regs, &n)) != 0) { 462 printf("SUNI read error %d\n", err); 463 return; 464 } 465 if (n <= SUNI_REGO_RSOPSIS) { 466 printf("%s: could not read RSOPSIS", __func__); 467 return; 468 } 469 /* check for LOSI (loss of signal) */ 470 if ((regs[SUNI_REGO_MISTATUS] & SUNI_REGM_MISTATUS_RSOPI) && 471 (regs[SUNI_REGO_RSOPSIS] & SUNI_REGM_RSOPSIS_LOSI)) 472 utopia_check_carrier(utp, !(regs[SUNI_REGO_RSOPSIS] 473 & SUNI_REGM_RSOPSIS_LOSV)); 474} 475 476static const struct utopia_chip chip_622 = { 477 UTP_TYPE_SUNI_622, 478 "Suni/622 (PMC-5355)", 479 256, 480 utopia_reset_622, 481 utopia_set_sdh_default, 482 utopia_set_unass_default, 483 utopia_set_noscramb_default, 484 utopia_update_carrier_default, 485 utopia_set_loopback_622, 486 utopia_intr_default, 487}; 488static const struct utopia_chip chip_lite = { 489 UTP_TYPE_SUNI_LITE, 490 "Suni/Lite (PMC-5346)", 491 256, 492 utopia_reset_default, 493 utopia_set_sdh_default, 494 utopia_set_unass_default, 495 utopia_set_noscramb_default, 496 utopia_update_carrier_default, 497 utopia_set_loopback_lite, 498 utopia_intr_default, 499}; 500static const struct utopia_chip chip_ultra = { 501 UTP_TYPE_SUNI_ULTRA, 502 "Suni/Ultra (PMC-5350)", 503 256, 504 utopia_reset_default, 505 utopia_set_sdh_default, 506 utopia_set_unass_default, 507 utopia_set_noscramb_default, 508 utopia_update_carrier_default, 509 utopia_set_loopback_ultra, 510 utopia_intr_default, 511}; 512 513/* 514 * Reset IDT77105. There is really no way to reset this thing by acessing 515 * the registers. Load the registers with default values. 516 */ 517static int 518idt77105_reset(struct utopia *utp) 519{ 520 int err = 0; 521 u_int n; 522 uint8_t val[2]; 523 524 err |= WRITEREG(utp, IDTPHY_REGO_MCR, 0xff, 525 IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI); 526 n = 1; 527 err |= READREGS(utp, IDTPHY_REGO_ISTAT, val, &n); 528 err |= WRITEREG(utp, IDTPHY_REGO_DIAG, 0xff, 0); 529 err |= WRITEREG(utp, IDTPHY_REGO_LHEC, 0xff, 0); 530 531 err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_SEC); 532 n = 2; 533 err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n); 534 535 err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_TX); 536 n = 2; 537 err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n); 538 539 err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_RX); 540 n = 2; 541 err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n); 542 543 err |= WRITEREG(utp, IDTPHY_REGO_CNTS, 0xff, IDTPHY_REGM_CNTS_HECE); 544 n = 2; 545 err |= READREGS(utp, IDTPHY_REGO_CNT, val, &n); 546 547 err |= WRITEREG(utp, IDTPHY_REGO_MCR, IDTPHY_REGM_MCR_DREC, 548 IDTPHY_REGM_MCR_DREC); 549 err |= WRITEREG(utp, IDTPHY_REGO_DIAG, IDTPHY_REGM_DIAG_RFLUSH, 550 IDTPHY_REGM_DIAG_RFLUSH); 551 552 /* loopback */ 553 err |= utopia_set_loopback(utp, utp->loopback); 554 555 /* update carrier state */ 556 err |= utopia_update_carrier(utp); 557 558 return (err ? EIO : 0); 559} 560 561static int 562unknown_inval(struct utopia *utp, int what __unused) 563{ 564 return (EINVAL); 565} 566 567static int 568idt77105_update_carrier(struct utopia *utp) 569{ 570 int err; 571 uint8_t reg; 572 u_int n = 1; 573 574 if ((err = READREGS(utp, IDTPHY_REGO_ISTAT, ®, &n)) != 0) { 575 utp->carrier = UTP_CARR_UNKNOWN; 576 return (err); 577 } 578 utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD); 579 return (0); 580} 581 582static int 583idt77105_set_loopback(struct utopia *utp, u_int mode) 584{ 585 int err; 586 587 switch (mode) { 588 case UTP_LOOP_NONE: 589 err = WRITEREG(utp, IDTPHY_REGO_DIAG, 590 IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_NONE); 591 break; 592 593 case UTP_LOOP_DIAG: 594 err = WRITEREG(utp, IDTPHY_REGO_DIAG, 595 IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_PHY); 596 break; 597 598 case UTP_LOOP_LINE: 599 err = WRITEREG(utp, IDTPHY_REGO_DIAG, 600 IDTPHY_REGM_DIAG_LOOP, IDTPHY_REGM_DIAG_LOOP_LINE); 601 break; 602 603 default: 604 return (EINVAL); 605 } 606 if (err) 607 return (err); 608 utp->loopback = mode; 609 return (0); 610} 611 612/* 613 * Handle interrupt on IDT77105 chip 614 */ 615static void 616idt77105_intr(struct utopia *utp) 617{ 618 uint8_t reg; 619 u_int n = 1; 620 int err; 621 622 /* Interrupt status and ack the interrupt */ 623 if ((err = READREGS(utp, IDTPHY_REGO_ISTAT, ®, &n)) != 0) { 624 printf("IDT77105 read error %d\n", err); 625 return; 626 } 627 /* check for signal condition */ 628 utopia_check_carrier(utp, reg & IDTPHY_REGM_ISTAT_GOOD); 629} 630 631static const struct utopia_chip chip_idt77105 = { 632 UTP_TYPE_IDT77105, 633 "IDT77105", 634 7, 635 idt77105_reset, 636 unknown_inval, 637 unknown_inval, 638 unknown_inval, 639 idt77105_update_carrier, 640 idt77105_set_loopback, 641 idt77105_intr, 642}; 643 644/* 645 * Update the carrier status 646 */ 647static int 648idt77155_update_carrier(struct utopia *utp) 649{ 650 int err; 651 uint8_t reg; 652 u_int n = 1; 653 654 if ((err = READREGS(utp, IDTPHY_REGO_RSOS, ®, &n)) != 0) { 655 utp->carrier = UTP_CARR_UNKNOWN; 656 return (err); 657 } 658 utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS)); 659 return (0); 660} 661 662/* 663 * Handle interrupt on IDT77155 chip 664 */ 665static void 666idt77155_intr(struct utopia *utp) 667{ 668 uint8_t reg; 669 u_int n = 1; 670 int err; 671 672 if ((err = READREGS(utp, IDTPHY_REGO_RSOS, ®, &n)) != 0) { 673 printf("IDT77105 read error %d\n", err); 674 return; 675 } 676 utopia_check_carrier(utp, !(reg & IDTPHY_REGM_RSOS_LOS)); 677} 678 679/* 680 * set SONET/SDH mode 681 */ 682static int 683idt77155_set_sdh(struct utopia *utp, int sdh) 684{ 685 int err; 686 687 if (sdh) 688 err = WRITEREG(utp, IDTPHY_REGO_PTRM, 689 IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SDH); 690 else 691 err = WRITEREG(utp, IDTPHY_REGO_PTRM, 692 IDTPHY_REGM_PTRM_SS, IDTPHY_REGM_PTRM_SONET); 693 if (err != 0) 694 return (err); 695 696 utp->state &= ~UTP_ST_SDH; 697 if (sdh) 698 utp->state |= UTP_ST_SDH; 699 700 return (0); 701} 702 703/* 704 * set idle/unassigned cells 705 */ 706static int 707idt77155_set_unass(struct utopia *utp, int unass) 708{ 709 int err; 710 711 if (unass) 712 err = WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 0); 713 else 714 err = WRITEREG(utp, IDTPHY_REGO_TCHP, 0xff, 1); 715 if (err != 0) 716 return (err); 717 718 utp->state &= ~UTP_ST_UNASS; 719 if (unass) 720 utp->state |= UTP_ST_UNASS; 721 722 return (0); 723} 724 725/* 726 * enable/disable scrambling 727 */ 728static int 729idt77155_set_noscramb(struct utopia *utp, int noscramb) 730{ 731 int err; 732 733 if (noscramb) { 734 err = WRITEREG(utp, IDTPHY_REGO_TCC, 735 IDTPHY_REGM_TCC_DSCR, IDTPHY_REGM_TCC_DSCR); 736 if (err) 737 return (err); 738 err = WRITEREG(utp, IDTPHY_REGO_RCC, 739 IDTPHY_REGM_RCC_DSCR, IDTPHY_REGM_RCC_DSCR); 740 if (err) 741 return (err); 742 utp->state |= UTP_ST_NOSCRAMB; 743 } else { 744 err = WRITEREG(utp, IDTPHY_REGO_TCC, 745 IDTPHY_REGM_TCC_DSCR, 0); 746 if (err) 747 return (err); 748 err = WRITEREG(utp, IDTPHY_REGO_RCC, 749 IDTPHY_REGM_RCC_DSCR, 0); 750 if (err) 751 return (err); 752 utp->state &= ~UTP_ST_NOSCRAMB; 753 } 754 return (0); 755} 756 757/* 758 * Set loopback mode for the 77155 759 */ 760static int 761idt77155_set_loopback(struct utopia *utp, u_int mode) 762{ 763 int err; 764 uint32_t val; 765 u_int nmode; 766 767 val = 0; 768 nmode = mode; 769 if (mode & UTP_LOOP_TIME) { 770 nmode &= ~UTP_LOOP_TIME; 771 val |= IDTPHY_REGM_MCTL_TLOOP; 772 } 773 if (mode & UTP_LOOP_DIAG) { 774 nmode &= ~UTP_LOOP_DIAG; 775 val |= IDTPHY_REGM_MCTL_DLOOP; 776 } 777 if (mode & UTP_LOOP_LINE) { 778 nmode &= ~UTP_LOOP_LINE; 779 val |= IDTPHY_REGM_MCTL_LLOOP; 780 } 781 if (nmode != 0) 782 return (EINVAL); 783 784 err = WRITEREG(utp, IDTPHY_REGO_MCTL, IDTPHY_REGM_MCTL_TLOOP | 785 IDTPHY_REGM_MCTL_DLOOP | IDTPHY_REGM_MCTL_LLOOP, val); 786 if (err) 787 return (err); 788 utp->loopback = mode; 789 790 return (0); 791} 792 793/* 794 * Set the chip to reflect the current state in utopia. 795 * Assume, that the chip has been reset. 796 */ 797static int 798idt77155_set_chip(struct utopia *utp) 799{ 800 int err = 0; 801 802 /* set sonet/sdh */ 803 err |= idt77155_set_sdh(utp, utp->state & UTP_ST_SDH); 804 805 /* unassigned or idle cells */ 806 err |= idt77155_set_unass(utp, utp->state & UTP_ST_UNASS); 807 808 /* loopback */ 809 err |= idt77155_set_loopback(utp, utp->loopback); 810 811 /* update carrier state */ 812 err |= idt77155_update_carrier(utp); 813 814 /* enable interrupts on LOS */ 815 err |= WRITEREG(utp, IDTPHY_REGO_INT, 816 IDTPHY_REGM_INT_RXSOHI, IDTPHY_REGM_INT_RXSOHI); 817 err |= WRITEREG(utp, IDTPHY_REGO_RSOC, 818 IDTPHY_REGM_RSOC_LOSI, IDTPHY_REGM_RSOC_LOSI); 819 820 return (err ? EIO : 0); 821} 822 823/* 824 * Reset the chip to reflect the current state of utopia. 825 */ 826static int 827idt77155_reset(struct utopia *utp) 828{ 829 int err = 0; 830 831 if (!(utp->flags & UTP_FL_NORESET)) { 832 err |= WRITEREG(utp, IDTPHY_REGO_MRID, IDTPHY_REGM_MRID_RESET, 833 IDTPHY_REGM_MRID_RESET); 834 err |= WRITEREG(utp, IDTPHY_REGO_MRID, IDTPHY_REGM_MRID_RESET, 835 0); 836 } 837 838 err |= idt77155_set_chip(utp); 839 840 return (err ? EIO : 0); 841} 842 843static const struct utopia_chip chip_idt77155 = { 844 UTP_TYPE_IDT77155, 845 "IDT77155", 846 0x80, 847 idt77155_reset, 848 idt77155_set_sdh, 849 idt77155_set_unass, 850 idt77155_set_noscramb, 851 idt77155_update_carrier, 852 idt77155_set_loopback, 853 idt77155_intr, 854}; 855 856static int 857unknown_reset(struct utopia *utp __unused) 858{ 859 return (EIO); 860} 861 862static int 863unknown_update_carrier(struct utopia *utp) 864{ 865 utp->carrier = UTP_CARR_UNKNOWN; 866 return (0); 867} 868 869static int 870unknown_set_loopback(struct utopia *utp __unused, u_int mode __unused) 871{ 872 return (EINVAL); 873} 874 875static void 876unknown_intr(struct utopia *utp __unused) 877{ 878} 879 880static const struct utopia_chip chip_unknown = { 881 UTP_TYPE_UNKNOWN, 882 "unknown", 883 0, 884 unknown_reset, 885 unknown_inval, 886 unknown_inval, 887 unknown_inval, 888 unknown_update_carrier, 889 unknown_set_loopback, 890 unknown_intr, 891}; 892 893/* 894 * Callbacks for the ifmedia infrastructure. 895 */ 896static int 897utopia_media_change(struct ifnet *ifp) 898{ 899 struct ifatm *ifatm = (struct ifatm *)ifp->if_softc; 900 struct utopia *utp = ifatm->phy; 901 int error = 0; 902 903 UTP_LOCK(utp); 904 if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) { 905 if (utp->media->ifm_media & IFM_ATM_SDH) { 906 if (!(utp->state & UTP_ST_SDH)) 907 error = utopia_set_sdh(utp, 1); 908 } else { 909 if (utp->state & UTP_ST_SDH) 910 error = utopia_set_sdh(utp, 0); 911 } 912 if (utp->media->ifm_media & IFM_ATM_UNASSIGNED) { 913 if (!(utp->state & UTP_ST_UNASS)) 914 error = utopia_set_unass(utp, 1); 915 } else { 916 if (utp->state & UTP_ST_UNASS) 917 error = utopia_set_unass(utp, 0); 918 } 919 if (utp->media->ifm_media & IFM_ATM_NOSCRAMB) { 920 if (!(utp->state & UTP_ST_NOSCRAMB)) 921 error = utopia_set_noscramb(utp, 1); 922 } else { 923 if (utp->state & UTP_ST_NOSCRAMB) 924 error = utopia_set_noscramb(utp, 0); 925 } 926 } else 927 error = EIO; 928 UTP_UNLOCK(utp); 929 return (error); 930} 931 932/* 933 * Look at the carrier status. 934 */ 935static void 936utopia_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 937{ 938 struct utopia *utp = ((struct ifatm *)ifp->if_softc)->phy; 939 940 UTP_LOCK(utp); 941 if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) { 942 ifmr->ifm_active = IFM_ATM | utp->ifatm->mib.media; 943 944 switch (utp->carrier) { 945 946 case UTP_CARR_OK: 947 ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; 948 break; 949 950 case UTP_CARR_LOST: 951 ifmr->ifm_status = IFM_AVALID; 952 break; 953 954 default: 955 ifmr->ifm_status = 0; 956 break; 957 } 958 if (utp->state & UTP_ST_SDH) { 959 ifmr->ifm_active |= IFM_ATM_SDH; 960 ifmr->ifm_current |= IFM_ATM_SDH; 961 } 962 if (utp->state & UTP_ST_UNASS) { 963 ifmr->ifm_active |= IFM_ATM_UNASSIGNED; 964 ifmr->ifm_current |= IFM_ATM_UNASSIGNED; 965 } 966 if (utp->state & UTP_ST_NOSCRAMB) { 967 ifmr->ifm_active |= IFM_ATM_NOSCRAMB; 968 ifmr->ifm_current |= IFM_ATM_NOSCRAMB; 969 } 970 } else { 971 ifmr->ifm_active = 0; 972 ifmr->ifm_status = 0; 973 } 974 UTP_UNLOCK(utp); 975} 976 977/* 978 * Initialize media from the mib 979 */ 980void 981utopia_init_media(struct utopia *utp) 982{ 983 984 ifmedia_removeall(utp->media); 985 ifmedia_add(utp->media, IFM_ATM | utp->ifatm->mib.media, 0, NULL); 986 ifmedia_set(utp->media, IFM_ATM | utp->ifatm->mib.media); 987} 988 989/* 990 * Reset all media 991 */ 992void 993utopia_reset_media(struct utopia *utp) 994{ 995 996 ifmedia_removeall(utp->media); 997} 998 999/* 1000 * This is called by the driver as soon as the SUNI registers are accessible. 1001 * This may be either in the attach routine or the init routine of the driver. 1002 */ 1003int 1004utopia_start(struct utopia *utp) 1005{ 1006 uint8_t reg; 1007 int err; 1008 u_int n = 1; 1009 1010 if ((err = READREGS(utp, SUNI_REGO_MRESET, ®, &n)) != 0) 1011 return (err); 1012 1013 switch (reg & SUNI_REGM_MRESET_TYPE) { 1014 1015 case SUNI_REGM_MRESET_TYPE_622: 1016 utp->chip = &chip_622; 1017 break; 1018 1019 case SUNI_REGM_MRESET_TYPE_LITE: 1020 /* this may be either a SUNI LITE or a IDT77155 * 1021 * Read register 0x70. The SUNI doesn't have it */ 1022 n = 1; 1023 if ((err = READREGS(utp, IDTPHY_REGO_RBER, ®, &n)) != 0) 1024 return (err); 1025 if ((reg & ~IDTPHY_REGM_RBER_RESV) == 1026 (IDTPHY_REGM_RBER_FAIL | IDTPHY_REGM_RBER_WARN)) 1027 utp->chip = &chip_idt77155; 1028 else 1029 utp->chip = &chip_lite; 1030 break; 1031 1032 case SUNI_REGM_MRESET_TYPE_ULTRA: 1033 utp->chip = &chip_ultra; 1034 break; 1035 1036 default: 1037 if (reg == (IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI)) 1038 utp->chip = &chip_idt77105; 1039 else { 1040 if_printf(&utp->ifatm->ifnet, 1041 "unknown ATM-PHY chip %#x\n", reg); 1042 utp->chip = &chip_unknown; 1043 } 1044 break; 1045 } 1046 utp->state |= UTP_ST_ACTIVE; 1047 return (0); 1048} 1049 1050/* 1051 * Stop the chip 1052 */ 1053void 1054utopia_stop(struct utopia *utp) 1055{ 1056 utp->state &= ~UTP_ST_ACTIVE; 1057} 1058 1059/* 1060 * Handle the sysctls 1061 */ 1062static int 1063utopia_sysctl_regs(SYSCTL_HANDLER_ARGS) 1064{ 1065 struct utopia *utp = (struct utopia *)arg1; 1066 int error; 1067 u_int n; 1068 uint8_t *val; 1069 uint8_t new[3]; 1070 1071 if ((n = utp->chip->nregs) == 0) 1072 return (EIO); 1073 val = malloc(sizeof(uint8_t) * n, M_TEMP, M_WAITOK); 1074 1075 UTP_LOCK(utp); 1076 error = READREGS(utp, 0, val, &n); 1077 UTP_UNLOCK(utp); 1078 1079 if (error) { 1080 free(val, M_TEMP); 1081 return (error); 1082 } 1083 1084 error = SYSCTL_OUT(req, val, sizeof(uint8_t) * n); 1085 free(val, M_TEMP); 1086 if (error != 0 || req->newptr == NULL) 1087 return (error); 1088 1089 error = SYSCTL_IN(req, new, sizeof(new)); 1090 if (error) 1091 return (error); 1092 1093 UTP_LOCK(utp); 1094 error = WRITEREG(utp, new[0], new[1], new[2]); 1095 UTP_UNLOCK(utp); 1096 1097 return (error); 1098} 1099 1100/* 1101 * Handle the loopback sysctl 1102 */ 1103static int 1104utopia_sysctl_loopback(SYSCTL_HANDLER_ARGS) 1105{ 1106 struct utopia *utp = (struct utopia *)arg1; 1107 int error; 1108 u_int loopback; 1109 1110 error = SYSCTL_OUT(req, &utp->loopback, sizeof(u_int)); 1111 if (error != 0 || req->newptr == NULL) 1112 return (error); 1113 1114 error = SYSCTL_IN(req, &loopback, sizeof(u_int)); 1115 if (error) 1116 return (error); 1117 1118 UTP_LOCK(utp); 1119 error = utopia_set_loopback(utp, loopback); 1120 UTP_UNLOCK(utp); 1121 1122 return (error); 1123} 1124 1125/* 1126 * Handle the type sysctl 1127 */ 1128static int 1129utopia_sysctl_type(SYSCTL_HANDLER_ARGS) 1130{ 1131 struct utopia *utp = (struct utopia *)arg1; 1132 1133 return (SYSCTL_OUT(req, &utp->chip->type, sizeof(utp->chip->type))); 1134} 1135 1136/* 1137 * Handle the name sysctl 1138 */ 1139static int 1140utopia_sysctl_name(SYSCTL_HANDLER_ARGS) 1141{ 1142 struct utopia *utp = (struct utopia *)arg1; 1143 1144 return (SYSCTL_OUT(req, utp->chip->name, strlen(utp->chip->name) + 1)); 1145} 1146 1147/* 1148 * Initialize the state. This is called from the drivers attach 1149 * function. The mutex must be already initialized. 1150 */ 1151int 1152utopia_attach(struct utopia *utp, struct ifatm *ifatm, struct ifmedia *media, 1153 struct mtx *lock, struct sysctl_ctx_list *ctx, 1154 struct sysctl_oid_list *children, const struct utopia_methods *m) 1155{ 1156 1157 bzero(utp, sizeof(*utp)); 1158 utp->ifatm = ifatm; 1159 utp->methods = m; 1160 utp->media = media; 1161 utp->lock = lock; 1162 utp->chip = &chip_unknown; 1163 1164 ifmedia_init(media, 1165 IFM_ATM_SDH | IFM_ATM_UNASSIGNED | IFM_ATM_NOSCRAMB, 1166 utopia_media_change, utopia_media_status); 1167 1168 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_regs", 1169 CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_regs, "S", 1170 "phy registers") == NULL) 1171 return (-1); 1172 1173 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_loopback", 1174 CTLFLAG_RW | CTLTYPE_UINT, utp, 0, utopia_sysctl_loopback, "IU", 1175 "phy loopback mode") == NULL) 1176 return (-1); 1177 1178 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_type", 1179 CTLFLAG_RD | CTLTYPE_UINT, utp, 0, utopia_sysctl_type, "IU", 1180 "phy type") == NULL) 1181 return (-1); 1182 1183 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_name", 1184 CTLFLAG_RD | CTLTYPE_STRING, utp, 0, utopia_sysctl_name, "A", 1185 "phy name") == NULL) 1186 return (-1); 1187 1188 UTP_WLOCK_LIST(); 1189 LIST_INSERT_HEAD(&utopia_list, utp, link); 1190 UTP_WUNLOCK_LIST(); 1191 1192 utp->state |= UTP_ST_ATTACHED; 1193 return (0); 1194} 1195 1196/* 1197 * Detach. We set a flag here, wakeup the daemon and let him do it. 1198 * Here we need the lock for synchronisation with the daemon. 1199 */ 1200void 1201utopia_detach(struct utopia *utp) 1202{ 1203 1204 UTP_LOCK_ASSERT(utp); 1205 if (utp->state & UTP_ST_ATTACHED) { 1206 utp->state |= UTP_ST_DETACH; 1207 while (utp->state & UTP_ST_DETACH) { 1208 wakeup(&utopia_list); 1209 msleep(utp, utp->lock, PZERO, "utopia_detach", hz); 1210 } 1211 } 1212} 1213 1214/* 1215 * The carrier state kernel proc for those adapters that do not interrupt. 1216 * 1217 * We assume, that utopia_attach can safely add a new utopia while we are going 1218 * through the list without disturbing us (we lock the list while getting 1219 * the address of the first element, adding is always done at the head). 1220 * Removing is entirely handled here. 1221 */ 1222static void 1223utopia_daemon(void *arg __unused) 1224{ 1225 struct utopia *utp, *next; 1226 1227 UTP_RLOCK_LIST(); 1228 while (utopia_kproc != NULL) { 1229 utp = LIST_FIRST(&utopia_list); 1230 UTP_RUNLOCK_LIST(); 1231 1232 while (utp != NULL) { 1233 mtx_lock(&Giant); /* XXX depend on MPSAFE */ 1234 UTP_LOCK(utp); 1235 next = LIST_NEXT(utp, link); 1236 if (utp->state & UTP_ST_DETACH) { 1237 LIST_REMOVE(utp, link); 1238 utp->state &= ~UTP_ST_DETACH; 1239 wakeup_one(utp); 1240 } else if ((utp->state & UTP_ST_ACTIVE) && 1241 (utp->flags & UTP_FL_POLL_CARRIER)) { 1242 utopia_update_carrier(utp); 1243 } 1244 UTP_UNLOCK(utp); 1245 mtx_unlock(&Giant); /* XXX depend on MPSAFE */ 1246 utp = next; 1247 } 1248 1249 UTP_RLOCK_LIST(); 1250 msleep(&utopia_list, &utopia_list_mtx, PZERO, "utopia", hz); 1251 } 1252 wakeup_one(&utopia_list); 1253 UTP_RUNLOCK_LIST(); 1254 mtx_lock(&Giant); 1255 kthread_exit(0); 1256} 1257 1258/* 1259 * Module initialisation 1260 */ 1261static int 1262utopia_mod_init(module_t mod, int what, void *arg) 1263{ 1264 int err; 1265 struct proc *kp; 1266 1267 switch (what) { 1268 1269 case MOD_LOAD: 1270 mtx_init(&utopia_list_mtx, "utopia list mutex", NULL, MTX_DEF); 1271 err = kthread_create(utopia_daemon, NULL, &utopia_kproc, 1272 RFHIGHPID, 0, "utopia"); 1273 if (err != 0) { 1274 printf("cannot created utopia thread %d\n", err); 1275 return (err); 1276 } 1277 break; 1278 1279 case MOD_UNLOAD: 1280 UTP_WLOCK_LIST(); 1281 if ((kp = utopia_kproc) != NULL) { 1282 utopia_kproc = NULL; 1283 wakeup_one(&utopia_list); 1284 PROC_LOCK(kp); 1285 UTP_WUNLOCK_LIST(); 1286 msleep(kp, &kp->p_mtx, PWAIT, "utopia_destroy", 0); 1287 PROC_UNLOCK(kp); 1288 } else 1289 UTP_WUNLOCK_LIST(); 1290 mtx_destroy(&utopia_list_mtx); 1291 break; 1292 } 1293 return (0); 1294} 1295 1296static moduledata_t utopia_mod = { 1297 "utopia", 1298 utopia_mod_init, 1299 0 1300}; 1301 1302DECLARE_MODULE(utopia, utopia_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 1303MODULE_VERSION(utopia, 1); 1304