utopia.c revision 116258
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 116258 2003-06-12 14:28:32Z 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 644static int 645unknown_reset(struct utopia *utp __unused) 646{ 647 return (EIO); 648} 649 650static int 651unknown_update_carrier(struct utopia *utp) 652{ 653 utp->carrier = UTP_CARR_UNKNOWN; 654 return (0); 655} 656 657static int 658unknown_set_loopback(struct utopia *utp __unused, u_int mode __unused) 659{ 660 return (EINVAL); 661} 662 663static void 664unknown_intr(struct utopia *utp __unused) 665{ 666} 667 668static const struct utopia_chip chip_unknown = { 669 UTP_TYPE_UNKNOWN, 670 "unknown", 671 0, 672 unknown_reset, 673 unknown_inval, 674 unknown_inval, 675 unknown_inval, 676 unknown_update_carrier, 677 unknown_set_loopback, 678 unknown_intr, 679}; 680 681/* 682 * Callbacks for the ifmedia infrastructure. 683 */ 684static int 685utopia_media_change(struct ifnet *ifp) 686{ 687 struct ifatm *ifatm = (struct ifatm *)ifp->if_softc; 688 struct utopia *utp = ifatm->phy; 689 int error = 0; 690 691 UTP_LOCK(utp); 692 if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) { 693 if (utp->media->ifm_media & IFM_ATM_SDH) { 694 if (!(utp->state & UTP_ST_SDH)) 695 error = utopia_set_sdh(utp, 1); 696 } else { 697 if (utp->state & UTP_ST_SDH) 698 error = utopia_set_sdh(utp, 0); 699 } 700 if (utp->media->ifm_media & IFM_ATM_UNASSIGNED) { 701 if (!(utp->state & UTP_ST_UNASS)) 702 error = utopia_set_unass(utp, 1); 703 } else { 704 if (utp->state & UTP_ST_UNASS) 705 error = utopia_set_unass(utp, 0); 706 } 707 if (utp->media->ifm_media & IFM_ATM_NOSCRAMB) { 708 if (!(utp->state & UTP_ST_NOSCRAMB)) 709 error = utopia_set_noscramb(utp, 1); 710 } else { 711 if (utp->state & UTP_ST_NOSCRAMB) 712 error = utopia_set_noscramb(utp, 0); 713 } 714 } else 715 error = EIO; 716 UTP_UNLOCK(utp); 717 return (error); 718} 719 720/* 721 * Look at the carrier status. 722 */ 723static void 724utopia_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 725{ 726 struct utopia *utp = ((struct ifatm *)ifp->if_softc)->phy; 727 728 UTP_LOCK(utp); 729 if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) { 730 ifmr->ifm_active = IFM_ATM | utp->ifatm->mib.media; 731 732 switch (utp->carrier) { 733 734 case UTP_CARR_OK: 735 ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; 736 break; 737 738 case UTP_CARR_LOST: 739 ifmr->ifm_status = IFM_AVALID; 740 break; 741 742 default: 743 ifmr->ifm_status = 0; 744 break; 745 } 746 if (utp->state & UTP_ST_SDH) { 747 ifmr->ifm_active |= IFM_ATM_SDH; 748 ifmr->ifm_current |= IFM_ATM_SDH; 749 } 750 if (utp->state & UTP_ST_UNASS) { 751 ifmr->ifm_active |= IFM_ATM_UNASSIGNED; 752 ifmr->ifm_current |= IFM_ATM_UNASSIGNED; 753 } 754 if (utp->state & UTP_ST_NOSCRAMB) { 755 ifmr->ifm_active |= IFM_ATM_NOSCRAMB; 756 ifmr->ifm_current |= IFM_ATM_NOSCRAMB; 757 } 758 } else { 759 ifmr->ifm_active = 0; 760 ifmr->ifm_status = 0; 761 } 762 UTP_UNLOCK(utp); 763} 764 765/* 766 * Initialize media from the mib 767 */ 768void 769utopia_init_media(struct utopia *utp) 770{ 771 772 ifmedia_removeall(utp->media); 773 ifmedia_add(utp->media, IFM_ATM | utp->ifatm->mib.media, 0, NULL); 774 ifmedia_set(utp->media, IFM_ATM | utp->ifatm->mib.media); 775} 776 777/* 778 * Reset all media 779 */ 780void 781utopia_reset_media(struct utopia *utp) 782{ 783 784 ifmedia_removeall(utp->media); 785} 786 787/* 788 * This is called by the driver as soon as the SUNI registers are accessible. 789 * This may be either in the attach routine or the init routine of the driver. 790 */ 791int 792utopia_start(struct utopia *utp) 793{ 794 uint8_t reg; 795 int err; 796 u_int n = 1; 797 798 if ((err = READREGS(utp, SUNI_REGO_MRESET, ®, &n)) != 0) 799 return (err); 800 801 switch (reg & SUNI_REGM_MRESET_TYPE) { 802 803 case SUNI_REGM_MRESET_TYPE_622: 804 utp->chip = &chip_622; 805 break; 806 807 case SUNI_REGM_MRESET_TYPE_LITE: 808 utp->chip = &chip_lite; 809 break; 810 811 case SUNI_REGM_MRESET_TYPE_ULTRA: 812 utp->chip = &chip_ultra; 813 break; 814 815 default: 816 if (reg == (IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI)) 817 utp->chip = &chip_idt77105; 818 else { 819 if_printf(&utp->ifatm->ifnet, 820 "unknown ATM-PHY chip %#x\n", reg); 821 utp->chip = &chip_unknown; 822 } 823 break; 824 } 825 utp->state |= UTP_ST_ACTIVE; 826 return (0); 827} 828 829/* 830 * Stop the chip 831 */ 832void 833utopia_stop(struct utopia *utp) 834{ 835 utp->state &= ~UTP_ST_ACTIVE; 836} 837 838/* 839 * Handle the sysctls 840 */ 841static int 842utopia_sysctl_regs(SYSCTL_HANDLER_ARGS) 843{ 844 struct utopia *utp = (struct utopia *)arg1; 845 int error; 846 u_int n; 847 uint8_t *val; 848 uint8_t new[3]; 849 850 if ((n = utp->chip->nregs) == 0) 851 return (EIO); 852 val = malloc(sizeof(uint8_t) * n, M_TEMP, M_WAITOK); 853 854 UTP_LOCK(utp); 855 error = READREGS(utp, 0, val, &n); 856 UTP_UNLOCK(utp); 857 858 if (error) { 859 free(val, M_TEMP); 860 return (error); 861 } 862 863 error = SYSCTL_OUT(req, val, sizeof(uint8_t) * n); 864 free(val, M_TEMP); 865 if (error != 0 || req->newptr == NULL) 866 return (error); 867 868 error = SYSCTL_IN(req, new, sizeof(new)); 869 if (error) 870 return (error); 871 872 UTP_LOCK(utp); 873 error = WRITEREG(utp, new[0], new[1], new[2]); 874 UTP_UNLOCK(utp); 875 876 return (error); 877} 878 879/* 880 * Handle the loopback sysctl 881 */ 882static int 883utopia_sysctl_loopback(SYSCTL_HANDLER_ARGS) 884{ 885 struct utopia *utp = (struct utopia *)arg1; 886 int error; 887 u_int loopback; 888 889 error = SYSCTL_OUT(req, &utp->loopback, sizeof(u_int)); 890 if (error != 0 || req->newptr == NULL) 891 return (error); 892 893 error = SYSCTL_IN(req, &loopback, sizeof(u_int)); 894 if (error) 895 return (error); 896 897 UTP_LOCK(utp); 898 error = utopia_set_loopback(utp, loopback); 899 UTP_UNLOCK(utp); 900 901 return (error); 902} 903 904/* 905 * Handle the type sysctl 906 */ 907static int 908utopia_sysctl_type(SYSCTL_HANDLER_ARGS) 909{ 910 struct utopia *utp = (struct utopia *)arg1; 911 912 return (SYSCTL_OUT(req, &utp->chip->type, sizeof(utp->chip->type))); 913} 914 915/* 916 * Handle the name sysctl 917 */ 918static int 919utopia_sysctl_name(SYSCTL_HANDLER_ARGS) 920{ 921 struct utopia *utp = (struct utopia *)arg1; 922 923 return (SYSCTL_OUT(req, utp->chip->name, strlen(utp->chip->name) + 1)); 924} 925 926/* 927 * Initialize the state. This is called from the drivers attach 928 * function. The mutex must be already initialized. 929 */ 930int 931utopia_attach(struct utopia *utp, struct ifatm *ifatm, struct ifmedia *media, 932 struct mtx *lock, struct sysctl_ctx_list *ctx, 933 struct sysctl_oid_list *children, const struct utopia_methods *m) 934{ 935 936 bzero(utp, sizeof(*utp)); 937 utp->ifatm = ifatm; 938 utp->methods = m; 939 utp->media = media; 940 utp->lock = lock; 941 utp->chip = &chip_unknown; 942 943 ifmedia_init(media, 944 IFM_ATM_SDH | IFM_ATM_UNASSIGNED | IFM_ATM_NOSCRAMB, 945 utopia_media_change, utopia_media_status); 946 947 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_regs", 948 CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_regs, "S", 949 "phy registers") == NULL) 950 return (-1); 951 952 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_loopback", 953 CTLFLAG_RW | CTLTYPE_UINT, utp, 0, utopia_sysctl_loopback, "IU", 954 "phy loopback mode") == NULL) 955 return (-1); 956 957 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_type", 958 CTLFLAG_RD | CTLTYPE_UINT, utp, 0, utopia_sysctl_type, "IU", 959 "phy type") == NULL) 960 return (-1); 961 962 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_name", 963 CTLFLAG_RD | CTLTYPE_STRING, utp, 0, utopia_sysctl_name, "A", 964 "phy name") == NULL) 965 return (-1); 966 967 UTP_WLOCK_LIST(); 968 LIST_INSERT_HEAD(&utopia_list, utp, link); 969 UTP_WUNLOCK_LIST(); 970 971 utp->state |= UTP_ST_ATTACHED; 972 return (0); 973} 974 975/* 976 * Detach. We set a flag here, wakeup the daemon and let him do it. 977 * Here we need the lock for synchronisation with the daemon. 978 */ 979void 980utopia_detach(struct utopia *utp) 981{ 982 983 UTP_LOCK_ASSERT(utp); 984 if (utp->state & UTP_ST_ATTACHED) { 985 utp->state |= UTP_ST_DETACH; 986 while (utp->state & UTP_ST_DETACH) { 987 wakeup(&utopia_list); 988 msleep(utp, utp->lock, PZERO, "utopia_detach", hz); 989 } 990 } 991} 992 993/* 994 * The carrier state kernel proc for those adapters that do not interrupt. 995 * 996 * We assume, that utopia_attach can safely add a new utopia while we are going 997 * through the list without disturbing us (we lock the list while getting 998 * the address of the first element, adding is always done at the head). 999 * Removing is entirely handled here. 1000 */ 1001static void 1002utopia_daemon(void *arg __unused) 1003{ 1004 struct utopia *utp, *next; 1005 1006 UTP_RLOCK_LIST(); 1007 while (utopia_kproc != NULL) { 1008 utp = LIST_FIRST(&utopia_list); 1009 UTP_RUNLOCK_LIST(); 1010 1011 while (utp != NULL) { 1012 mtx_lock(&Giant); /* XXX depend on MPSAFE */ 1013 UTP_LOCK(utp); 1014 next = LIST_NEXT(utp, link); 1015 if (utp->state & UTP_ST_DETACH) { 1016 LIST_REMOVE(utp, link); 1017 utp->state &= ~UTP_ST_DETACH; 1018 wakeup_one(utp); 1019 } else if ((utp->state & UTP_ST_ACTIVE) && 1020 (utp->flags & UTP_FL_POLL_CARRIER)) { 1021 utopia_update_carrier(utp); 1022 } 1023 UTP_UNLOCK(utp); 1024 mtx_unlock(&Giant); /* XXX depend on MPSAFE */ 1025 utp = next; 1026 } 1027 1028 UTP_RLOCK_LIST(); 1029 msleep(&utopia_list, &utopia_list_mtx, PZERO, "utopia", hz); 1030 } 1031 wakeup_one(&utopia_list); 1032 UTP_RUNLOCK_LIST(); 1033 mtx_lock(&Giant); 1034 kthread_exit(0); 1035} 1036 1037/* 1038 * Module initialisation 1039 */ 1040static int 1041utopia_mod_init(module_t mod, int what, void *arg) 1042{ 1043 int err; 1044 struct proc *kp; 1045 1046 switch (what) { 1047 1048 case MOD_LOAD: 1049 mtx_init(&utopia_list_mtx, "utopia list mutex", NULL, MTX_DEF); 1050 err = kthread_create(utopia_daemon, NULL, &utopia_kproc, 1051 RFHIGHPID, 0, "utopia"); 1052 if (err != 0) { 1053 printf("cannot created utopia thread %d\n", err); 1054 return (err); 1055 } 1056 break; 1057 1058 case MOD_UNLOAD: 1059 UTP_WLOCK_LIST(); 1060 if ((kp = utopia_kproc) != NULL) { 1061 utopia_kproc = NULL; 1062 wakeup_one(&utopia_list); 1063 PROC_LOCK(kp); 1064 UTP_WUNLOCK_LIST(); 1065 msleep(kp, &kp->p_mtx, PWAIT, "utopia_destroy", 0); 1066 PROC_UNLOCK(kp); 1067 } else 1068 UTP_WUNLOCK_LIST(); 1069 mtx_destroy(&utopia_list_mtx); 1070 break; 1071 } 1072 return (0); 1073} 1074 1075static moduledata_t utopia_mod = { 1076 "utopia", 1077 utopia_mod_init, 1078 0 1079}; 1080 1081DECLARE_MODULE(utopia, utopia_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 1082MODULE_VERSION(utopia, 1); 1083