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));
449 if (error && req->newptr != NULL)
450 bcopy(val, &utp->stats, sizeof(utp->stats));
452 /* ignore actual new value */
458 * Handle the loopback sysctl
461 utopia_sysctl_loopback(SYSCTL_HANDLER_ARGS)
463 struct utopia *utp = (struct utopia *)arg1;
467 error = SYSCTL_OUT(req, &utp->loopback, sizeof(u_int));
468 if (error != 0 || req->newptr == NULL)
471 error = SYSCTL_IN(req, &loopback, sizeof(u_int));
476 error = utopia_set_loopback(utp, loopback);
483 * Handle the type sysctl
486 utopia_sysctl_type(SYSCTL_HANDLER_ARGS)
488 struct utopia *utp = (struct utopia *)arg1;
490 return (SYSCTL_OUT(req, &utp->chip->type, sizeof(utp->chip->type)));
494 * Handle the name sysctl
497 utopia_sysctl_name(SYSCTL_HANDLER_ARGS)
499 struct utopia *utp = (struct utopia *)arg1;
501 return (SYSCTL_OUT(req, utp->chip->name, strlen(utp->chip->name) + 1));
505 * Initialize the state. This is called from the drivers attach
506 * function. The mutex must be already initialized.
509 utopia_attach(struct utopia *utp, struct ifatm *ifatm, struct ifmedia *media,
510 struct mtx *lock, struct sysctl_ctx_list *ctx,
511 struct sysctl_oid_list *children, const struct utopia_methods *m)
514 bzero(utp, sizeof(*utp));
519 utp->chip = &utopia_chip_unknown;
520 utp->stats.version = 1;
523 IFM_ATM_SDH | IFM_ATM_UNASSIGNED | IFM_ATM_NOSCRAMB,
524 utopia_media_change, utopia_media_status);
526 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_regs",
527 CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_regs, "S",
528 "phy registers") == NULL)
531 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_loopback",
532 CTLFLAG_RW | CTLTYPE_UINT, utp, 0, utopia_sysctl_loopback, "IU",
533 "phy loopback mode") == NULL)
536 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_type",
537 CTLFLAG_RD | CTLTYPE_UINT, utp, 0, utopia_sysctl_type, "IU",
541 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_name",
542 CTLFLAG_RD | CTLTYPE_STRING, utp, 0, utopia_sysctl_name, "A",
546 if (SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "phy_stats",
547 CTLFLAG_RW | CTLTYPE_OPAQUE, utp, 0, utopia_sysctl_stats, "S",
548 "phy statistics") == NULL)
551 if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_state",
552 CTLFLAG_RD, &utp->state, 0, "phy state") == NULL)
555 if (SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "phy_carrier",
556 CTLFLAG_RD, &utp->carrier, 0, "phy carrier") == NULL)
560 LIST_INSERT_HEAD(&utopia_list, utp, link);
563 utp->state |= UTP_ST_ATTACHED;
568 * Detach. We set a flag here, wakeup the daemon and let him do it.
569 * Here we need the lock for synchronisation with the daemon.
572 utopia_detach(struct utopia *utp)
575 UTP_LOCK_ASSERT(utp);
576 if (utp->state & UTP_ST_ATTACHED) {
577 utp->state |= UTP_ST_DETACH;
578 while (utp->state & UTP_ST_DETACH) {
579 wakeup(&utopia_list);
580 msleep(utp, utp->lock, PZERO, "utopia_detach", hz);
586 * The carrier state kernel proc for those adapters that do not interrupt.
588 * We assume, that utopia_attach can safely add a new utopia while we are going
589 * through the list without disturbing us (we lock the list while getting
590 * the address of the first element, adding is always done at the head).
591 * Removing is entirely handled here.
594 utopia_daemon(void *arg __unused)
596 struct utopia *utp, *next;
599 while (utopia_kproc != NULL) {
600 utp = LIST_FIRST(&utopia_list);
603 while (utp != NULL) {
604 mtx_lock(&Giant); /* XXX depend on MPSAFE */
606 next = LIST_NEXT(utp, link);
607 if (utp->state & UTP_ST_DETACH) {
608 LIST_REMOVE(utp, link);
609 utp->state &= ~UTP_ST_DETACH;
611 } else if (utp->state & UTP_ST_ACTIVE) {
612 if (utp->flags & UTP_FL_POLL_CARRIER)
613 utopia_update_carrier(utp);
614 utopia_update_stats(utp);
617 mtx_unlock(&Giant); /* XXX depend on MPSAFE */
622 msleep(&utopia_list, &utopia_list_mtx, PZERO, "*idle*", hz);
624 wakeup_one(&utopia_list);
630 * Module initialisation
633 utopia_mod_init(module_t mod, int what, void *arg)
641 mtx_init(&utopia_list_mtx, "utopia list mutex", NULL, MTX_DEF);
642 err = kthread_create(utopia_daemon, NULL, &utopia_kproc,
643 RFHIGHPID, 0, "utopia");
645 printf("cannot created utopia thread %d\n", err);
652 if ((kp = utopia_kproc) != NULL) {
654 wakeup_one(&utopia_list);
657 msleep(kp, &kp->p_mtx, PWAIT, "utopia_destroy", 0);
661 mtx_destroy(&utopia_list_mtx);
669 static moduledata_t utopia_mod = {
675 DECLARE_MODULE(utopia, utopia_mod, SI_SUB_INIT_IF, SI_ORDER_ANY);
676 MODULE_VERSION(utopia, 1);