3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Author: Hartmut Brandt <harti@freebsd.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
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>
40 #include <sys/malloc.h>
41 #include <sys/module.h>
42 #include <sys/sysctl.h>
44 #include <sys/mutex.h>
45 #include <sys/socket.h>
48 #include <net/if_var.h>
49 #include <net/if_media.h>
50 #include <net/if_atm.h>
52 #include <dev/utopia/suni.h>
53 #include <dev/utopia/idtphy.h>
54 #include <dev/utopia/utopia.h>
55 #include <dev/utopia/utopia_priv.h>
58 extern const struct utopia_chip utopia_chip_idt77155;
59 extern const struct utopia_chip utopia_chip_idt77105;
60 extern const struct utopia_chip utopia_chip_lite;
61 extern const struct utopia_chip utopia_chip_ultra;
62 extern const struct utopia_chip utopia_chip_622;
65 * Global list of all registered interfaces
67 static struct mtx utopia_list_mtx;
68 static LIST_HEAD(, utopia) utopia_list = LIST_HEAD_INITIALIZER(utopia_list);
70 #define UTP_RLOCK_LIST() mtx_lock(&utopia_list_mtx)
71 #define UTP_RUNLOCK_LIST() mtx_unlock(&utopia_list_mtx)
72 #define UTP_WLOCK_LIST() mtx_lock(&utopia_list_mtx)
73 #define UTP_WUNLOCK_LIST() mtx_unlock(&utopia_list_mtx)
75 #define UTP_LOCK(UTP) mtx_lock((UTP)->lock)
76 #define UTP_UNLOCK(UTP) mtx_unlock((UTP)->lock)
77 #define UTP_LOCK_ASSERT(UTP) mtx_assert((UTP)->lock, MA_OWNED)
79 static struct proc *utopia_kproc;
81 static void utopia_dump(struct utopia *) __unused;
84 * Read a multi-register value.
87 utopia_update(struct utopia *utp, u_int reg, u_int nreg, uint32_t mask)
95 if ((err = UTP_READREGS(utp, reg, regs, &n)) != 0) {
97 printf("%s: register read error %s(%u,%u): %d\n", __func__,
98 utp->chip->name, reg, nreg, err);
104 printf("%s: got only %u regs %s(%u,%u): %d\n", __func__, n,
105 utp->chip->name, reg, nreg, err);
110 for (n = nreg; n > 0; n--) {
118 * Debugging - dump all registers.
121 utopia_dump(struct utopia *utp)
127 if ((err = UTP_READREGS(utp, 0, regs, &n)) != 0) {
128 printf("UTOPIA reg read error %d\n", err);
131 for (i = 0; i < n; i++) {
136 printf(" %02x", regs[i]);
145 * Update the carrier status
148 utopia_check_carrier(struct utopia *utp, u_int carr_ok)
155 utp->carrier = UTP_CARR_OK;
156 if (old != UTP_CARR_OK) {
157 if_printf(utp->ifatm->ifp, "carrier detected\n");
158 ATMEV_SEND_IFSTATE_CHANGED(utp->ifatm, 1);
162 utp->carrier = UTP_CARR_LOST;
163 if (old == UTP_CARR_OK) {
164 if_printf(utp->ifatm->ifp, "carrier lost\n");
165 ATMEV_SEND_IFSTATE_CHANGED(utp->ifatm, 0);
171 unknown_inval(struct utopia *utp, int what __unused)
178 unknown_reset(struct utopia *utp __unused)
184 unknown_update_carrier(struct utopia *utp)
186 utp->carrier = UTP_CARR_UNKNOWN;
191 unknown_set_loopback(struct utopia *utp __unused, u_int mode __unused)
197 unknown_intr(struct utopia *utp __unused)
202 unknown_update_stats(struct utopia *utp __unused)
206 static const struct utopia_chip utopia_chip_unknown = {
214 unknown_update_carrier,
215 unknown_set_loopback,
217 unknown_update_stats,
221 * Callbacks for the ifmedia infrastructure.
224 utopia_media_change(struct ifnet *ifp)
226 struct ifatm *ifatm = IFP2IFATM(ifp);
227 struct utopia *utp = ifatm->phy;
231 if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) {
232 if (utp->media->ifm_media & IFM_ATM_SDH) {
233 if (!(utp->state & UTP_ST_SDH))
234 error = utopia_set_sdh(utp, 1);
236 if (utp->state & UTP_ST_SDH)
237 error = utopia_set_sdh(utp, 0);
239 if (utp->media->ifm_media & IFM_ATM_UNASSIGNED) {
240 if (!(utp->state & UTP_ST_UNASS))
241 error = utopia_set_unass(utp, 1);
243 if (utp->state & UTP_ST_UNASS)
244 error = utopia_set_unass(utp, 0);
246 if (utp->media->ifm_media & IFM_ATM_NOSCRAMB) {
247 if (!(utp->state & UTP_ST_NOSCRAMB))
248 error = utopia_set_noscramb(utp, 1);
250 if (utp->state & UTP_ST_NOSCRAMB)
251 error = utopia_set_noscramb(utp, 0);
260 * Look at the carrier status.
263 utopia_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
265 struct utopia *utp = IFP2IFATM(ifp)->phy;
268 if (utp->chip->type != UTP_TYPE_UNKNOWN && utp->state & UTP_ST_ACTIVE) {
269 ifmr->ifm_active = IFM_ATM | utp->ifatm->mib.media;
271 switch (utp->carrier) {
274 ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
278 ifmr->ifm_status = IFM_AVALID;
282 ifmr->ifm_status = 0;
285 if (utp->state & UTP_ST_SDH) {
286 ifmr->ifm_active |= IFM_ATM_SDH;
287 ifmr->ifm_current |= IFM_ATM_SDH;
289 if (utp->state & UTP_ST_UNASS) {
290 ifmr->ifm_active |= IFM_ATM_UNASSIGNED;
291 ifmr->ifm_current |= IFM_ATM_UNASSIGNED;
293 if (utp->state & UTP_ST_NOSCRAMB) {
294 ifmr->ifm_active |= IFM_ATM_NOSCRAMB;
295 ifmr->ifm_current |= IFM_ATM_NOSCRAMB;
298 ifmr->ifm_active = 0;
299 ifmr->ifm_status = 0;
305 * Initialize media from the mib
308 utopia_init_media(struct utopia *utp)
311 ifmedia_removeall(utp->media);
312 ifmedia_add(utp->media, IFM_ATM | utp->ifatm->mib.media, 0, NULL);
313 ifmedia_set(utp->media, IFM_ATM | utp->ifatm->mib.media);
320 utopia_reset_media(struct utopia *utp)
323 ifmedia_removeall(utp->media);
327 * This is called by the driver as soon as the SUNI registers are accessible.
328 * This may be either in the attach routine or the init routine of the driver.
331 utopia_start(struct utopia *utp)
338 * Try to find out what chip we have
340 if ((err = UTP_READREGS(utp, SUNI_REGO_MRESET, ®, &n)) != 0)
343 switch (reg & SUNI_REGM_MRESET_TYPE) {
345 case SUNI_REGM_MRESET_TYPE_622:
346 utp->chip = &utopia_chip_622;
349 case SUNI_REGM_MRESET_TYPE_LITE:
350 /* this may be either a SUNI LITE or a IDT77155 *
351 * Read register 0x70. The SUNI doesn't have it */
353 if ((err = UTP_READREGS(utp, IDTPHY_REGO_RBER, ®, &n)) != 0)
355 if ((reg & ~IDTPHY_REGM_RBER_RESV) ==
356 (IDTPHY_REGM_RBER_FAIL | IDTPHY_REGM_RBER_WARN))
357 utp->chip = &utopia_chip_idt77155;
359 utp->chip = &utopia_chip_lite;
362 case SUNI_REGM_MRESET_TYPE_ULTRA:
363 utp->chip = &utopia_chip_ultra;
367 if (reg == (IDTPHY_REGM_MCR_DRIC | IDTPHY_REGM_MCR_EI))
368 utp->chip = &utopia_chip_idt77105;
370 if_printf(utp->ifatm->ifp,
371 "unknown ATM-PHY chip %#x\n", reg);
372 utp->chip = &utopia_chip_unknown;
376 utp->state |= UTP_ST_ACTIVE;
384 utopia_stop(struct utopia *utp)
386 utp->state &= ~UTP_ST_ACTIVE;
393 utopia_sysctl_regs(SYSCTL_HANDLER_ARGS)
395 struct utopia *utp = (struct utopia *)arg1;
401 if ((n = utp->chip->nregs) == 0)
403 val = malloc(sizeof(uint8_t) * n, M_TEMP, M_WAITOK);
406 error = UTP_READREGS(utp, 0, val, &n);
414 error = SYSCTL_OUT(req, val, sizeof(uint8_t) * n);
416 if (error != 0 || req->newptr == NULL)
419 error = SYSCTL_IN(req, new, sizeof(new));
424 error = UTP_WRITEREG(utp, new[0], new[1], new[2]);
431 utopia_sysctl_stats(SYSCTL_HANDLER_ARGS)
433 struct utopia *utp = (struct utopia *)arg1;
437 val = malloc(sizeof(utp->stats), M_TEMP, M_WAITOK);
440 bcopy(&utp->stats, val, sizeof(utp->stats));
441 if (req->newptr != NULL)
442 bzero((char *)&utp->stats + sizeof(utp->stats.version),
443 sizeof(utp->stats) - sizeof(utp->stats.version));
446 error = SYSCTL_OUT(req, val, sizeof(utp->stats));
447 if (error && req->newptr != NULL)
448 bcopy(val, &utp->stats, sizeof(utp->stats));
451 /* ignore actual new value */
457 * Handle the loopback sysctl
460 utopia_sysctl_loopback(SYSCTL_HANDLER_ARGS)
462 struct utopia *utp = (struct utopia *)arg1;
466 error = SYSCTL_OUT(req, &utp->loopback, sizeof(u_int));
467 if (error != 0 || req->newptr == NULL)
470 error = SYSCTL_IN(req, &loopback, sizeof(u_int));
475 error = utopia_set_loopback(utp, loopback);
482 * Handle the type sysctl
485 utopia_sysctl_type(SYSCTL_HANDLER_ARGS)
487 struct utopia *utp = (struct utopia *)arg1;
489 return (SYSCTL_OUT(req, &utp->chip->type, sizeof(utp->chip->type)));
493 * Handle the name sysctl
496 utopia_sysctl_name(SYSCTL_HANDLER_ARGS)
498 struct utopia *utp = (struct utopia *)arg1;
500 return (SYSCTL_OUT(req, utp->chip->name, strlen(utp->chip->name) + 1));
504 * Initialize the state. This is called from the drivers attach
505 * function. The mutex must be already initialized.
508 utopia_attach(struct utopia *utp, struct ifatm *ifatm, struct ifmedia *media,
509 struct mtx *lock, struct sysctl_ctx_list *ctx,
510 struct sysctl_oid_list *children, const struct utopia_methods *m)
513 bzero(utp, sizeof(*utp));
518 utp->chip = &utopia_chip_unknown;
519 utp->stats.version = 1;
522 IFM_ATM_SDH | IFM_ATM_UNASSIGNED | IFM_ATM_NOSCRAMB,
523 utopia_media_change, utopia_media_status);
525 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_regs",
526 CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_regs, "S",
527 "phy registers") == NULL)
530 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_loopback",
531 CTLFLAG_RW | CTLTYPE_UINT, utp, 0, utopia_sysctl_loopback, "IU",
532 "phy loopback mode") == NULL)
535 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_type",
536 CTLFLAG_RD | CTLTYPE_UINT, utp, 0, utopia_sysctl_type, "IU",
540 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_name",
541 CTLFLAG_RD | CTLTYPE_STRING, utp, 0, utopia_sysctl_name, "A",
545 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_stats",
546 CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_stats, "S",
547 "phy statistics") == NULL)
550 if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_state",
551 CTLFLAG_RD, &utp->state, 0, "phy state") == NULL)
554 if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_carrier",
555 CTLFLAG_RD, &utp->carrier, 0, "phy carrier") == NULL)
559 LIST_INSERT_HEAD(&utopia_list, utp, link);
562 utp->state |= UTP_ST_ATTACHED;
567 * Detach. We set a flag here, wakeup the daemon and let him do it.
568 * Here we need the lock for synchronisation with the daemon.
571 utopia_detach(struct utopia *utp)
574 UTP_LOCK_ASSERT(utp);
575 if (utp->state & UTP_ST_ATTACHED) {
576 utp->state |= UTP_ST_DETACH;
577 while (utp->state & UTP_ST_DETACH) {
578 wakeup(&utopia_list);
579 msleep(utp, utp->lock, PZERO, "utopia_detach", hz);
585 * The carrier state kernel proc for those adapters that do not interrupt.
587 * We assume, that utopia_attach can safely add a new utopia while we are going
588 * through the list without disturbing us (we lock the list while getting
589 * the address of the first element, adding is always done at the head).
590 * Removing is entirely handled here.
593 utopia_daemon(void *arg __unused)
595 struct utopia *utp, *next;
598 while (utopia_kproc != NULL) {
599 utp = LIST_FIRST(&utopia_list);
602 while (utp != NULL) {
603 mtx_lock(&Giant); /* XXX depend on MPSAFE */
605 next = LIST_NEXT(utp, link);
606 if (utp->state & UTP_ST_DETACH) {
607 LIST_REMOVE(utp, link);
608 utp->state &= ~UTP_ST_DETACH;
610 } else if (utp->state & UTP_ST_ACTIVE) {
611 if (utp->flags & UTP_FL_POLL_CARRIER)
612 utopia_update_carrier(utp);
613 utopia_update_stats(utp);
616 mtx_unlock(&Giant); /* XXX depend on MPSAFE */
621 msleep(&utopia_list, &utopia_list_mtx, PZERO, "*idle*", hz);
623 wakeup_one(&utopia_list);
629 * Module initialisation
632 utopia_mod_init(module_t mod, int what, void *arg)
640 mtx_init(&utopia_list_mtx, "utopia list mutex", NULL, MTX_DEF);
641 err = kproc_create(utopia_daemon, NULL, &utopia_kproc,
642 RFHIGHPID, 0, "utopia");
644 printf("cannot created utopia thread %d\n", err);
651 if ((kp = utopia_kproc) != NULL) {
653 wakeup_one(&utopia_list);
656 msleep(kp, &kp->p_mtx, PWAIT, "utopia_destroy", 0);
660 mtx_destroy(&utopia_list_mtx);
668 static moduledata_t utopia_mod = {
674 DECLARE_MODULE(utopia, utopia_mod, SI_SUB_INIT_IF, SI_ORDER_ANY);
675 MODULE_VERSION(utopia, 1);