patch-2.3.42 linux/drivers/ap1000/plc.c
Next file: linux/drivers/ap1000/plc.h
Previous file: linux/drivers/ap1000/mac.h
Back to the patch index
Back to the overall index
- Lines: 394
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
v2.3.41/linux/drivers/ap1000/plc.c
- Orig date:
Sun Jan 26 02:07:10 1997
diff -u --recursive --new-file v2.3.41/linux/drivers/ap1000/plc.c linux/drivers/ap1000/plc.c
@@ -1,393 +0,0 @@
- /*
- * Copyright 1996 The Australian National University.
- * Copyright 1996 Fujitsu Laboratories Limited
- *
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- */
-/*
- * Routines for controlling the Am79c864 physical layer controller.
- *
- * This chip implements some parts of the FDDI SMT standard
- * (PCM: physical connection management, LEM: link error monitor, etc.)
- * as well as the FDDI PHY standard.
- */
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include "apfddi.h"
-#include "smt-types.h"
-#include "am79c864.h"
-#include "plc.h"
-#include "apfddi-reg.h"
-
-typedef enum {
- off,
- signalling,
- doing_lct,
- joining,
- active
-} PlcPhase;
-
-struct plc_state {
- LoopbackType loopback;
- char t_val[16];
- char r_val[16];
- int n;
- PortType peer_type;
- PlcPhase phase;
-};
-
-struct plc_info *this_plc_info;
-struct plc_state this_plc_state;
-
-void plc_init(struct plc_info *pip)
-{
- int class, x;
- struct plc_state *psp = &this_plc_state;
-
- this_plc_info = pip;
-
- /* first turn it off, clear registers */
- class = pip->port_type == pt_s? CB_CLASS_S: 0;
- plc->ctrl_b = CB_PC_STOP + class;
- plc->intr_mask = IE_NP_ERROR;
- x = plc->intr_event; /* these register clear when read */
- x = plc->viol_sym_ct;
- x = plc->min_idle_ct;
- x = plc->link_err_ct;
-
- /* initialize registers */
- plc->ctrl_a = 0;
- plc->ctrl_b = class;
- plc->c_min = pip->c_min >> 8;
- plc->tl_min = pip->tl_min >> 8;
- plc->tb_min = pip->tb_min >> 8;
- plc->t_out = pip->t_out >> 8;
- plc->t_scrub = pip->t_scrub >> 8;
- plc->ns_max = pip->ns_max >> 2;
-
- psp->phase = off;
-}
-
-int
-plc_inited(struct plc_info *pip)
-{
- int class, x;
- struct plc_state *psp = &this_plc_state;
-
- class = pip->port_type == pt_s? CB_CLASS_S: 0;
- if ((plc->ctrl_a & (CA_LOOPBACK|CA_FOT_OFF|CA_EB_LOOP|CA_LM_LOOP)) != 0)
- return 1;
- if ((plc->ctrl_b & (CB_CONFIG_CTRL|CB_CLASS_S|CB_PC_MAINT)) != class)
- return 2;
- if (plc->status_a & SA_SIG_DETECT)
- return 3;
- if ((plc->status_b & (SB_PCI_STATE|SB_PCM_STATE))
- != (SB_PCI_STATE_INSERTED|SB_PCM_STATE_ACTIVE))
- return 4;
-
- /* all seems OK, reset the timers and counters just to be sure */
- plc->intr_mask = IE_NP_ERROR;
- x = plc->intr_event; /* these register clear when read */
- x = plc->viol_sym_ct;
- x = plc->min_idle_ct;
- x = plc->link_err_ct;
-
- plc->c_min = pip->c_min >> 8;
- plc->tl_min = pip->tl_min >> 8;
- plc->tb_min = pip->tb_min >> 8;
- plc->t_out = pip->t_out >> 8;
- plc->t_scrub = pip->t_scrub >> 8;
- plc->ns_max = pip->ns_max >> 2;
-
- psp->phase = active;
- /* XXX should initialize other fields of this_plc_state */
-
- return 0;
-}
-
-void plc_sleep(void)
-{
-}
-
-void pc_start(LoopbackType loopback)
-{
- int x;
- struct plc_info *pip = this_plc_info;
- struct plc_state *psp = &this_plc_state;
-
- /* make sure it's off */
- plc->ctrl_b &= ~CB_PCM_CTRL;
- plc->ctrl_b |= CB_PC_STOP;
-
- /* set up loopback required */
- psp->loopback = loopback;
- x = 0;
- switch (loopback) {
- case loop_plc_lm:
- x = CA_LM_LOOP;
- break;
- case loop_plc_eb:
- x = CA_EB_LOOP;
- break;
- case loop_pdx:
- x = CA_LOOPBACK;
- break;
- default:
- x = 0;
- }
- plc->ctrl_a = x;
-
- /* set up bits to be exchanged */
- psp->t_val[0] = 0;
- psp->t_val[1] = ((int) pip->port_type >> 1) & 1;
- psp->t_val[2] = (int) pip->port_type & 1;
- psp->t_val[4] = 0; /* XXX assume we want short LCT */
- psp->t_val[5] = 0;
- psp->t_val[6] = 0; /* XXX too lazy to fire up my MAC for LCT */
- psp->t_val[8] = 0; /* XXX don't wanna local loop */
- psp->t_val[9] = 1; /* gotta MAC on port output */
-
- pc_restart();
-}
-
-void pc_restart(void)
-{
- struct plc_state *psp = &this_plc_state;
-
- if (psp->phase != off)
- printk("restarting pcm\n");
- if (psp->phase == active)
- set_cf_join(0); /* we're down :-( */
-
- psp->n = 0;
- plc->vec_length = 3 - 1;
- plc->xmit_vector = psp->t_val[0] + (psp->t_val[1] << 1)
- + (psp->t_val[2] << 2);
-
- plc->intr_mask = IE_NP_ERROR | IE_PCM_BREAK | IE_PCM_CODE;
- plc->ctrl_b &= ~CB_PCM_CTRL;
- plc->ctrl_b |= CB_PC_START; /* light blue paper and stand clear */
-
- psp->phase = signalling;
-}
-
-void pc_stop(void)
-{
- struct plc_state *psp = &this_plc_state;
-
- if (psp->phase == active)
- set_cf_join(0);
- plc->ctrl_b &= ~CB_PCM_CTRL;
- plc->ctrl_b |= CB_PC_STOP;
- plc->intr_mask = IE_NP_ERROR;
- psp->phase = off;
-}
-
-void plc_poll(void)
-{
- struct plc_state *psp = &this_plc_state;
- int events, i;
-
- if ((*csr0 & CS0_PHY_IRQ) == 0)
- return;
- events = plc->intr_event & plc->intr_mask;
- if (events & IE_NP_ERROR) {
- printk("plc: NP error!\n");
- }
- if (events & IE_PCM_BREAK) {
- i = plc->status_b & SB_BREAK_REASON;
- if (i > SB_BREAK_REASON_START) {
- if (psp->phase == signalling || psp->phase == doing_lct)
- pcm_dump_rtcodes();
- printk("pcm: break reason %d\n", i);
- if (psp->phase != off)
- pc_restart();
- /* XXX need to check for trace? */
- }
- }
- if (events & IE_PCM_CODE) {
- if (psp->phase == signalling)
- pcm_pseudo_code();
- else if (psp->phase == doing_lct)
- pcm_lct_done();
- else
- printk("XXX pcm_code interrupt in phase %d?\n", psp->phase);
- }
- if (events & IE_PCM_ENABLED) {
- if (psp->phase == joining)
- pcm_enabled();
- else
- printk("XXX pcm_enabled interrupt in phase %d?\n", psp->phase);
- }
- if (events & IE_TRACE_PROP) {
- if (psp->phase == active)
- pcm_trace_prop();
- else
- printk("XXX trace_prop interrupt in phase %d\n", psp->phase);
- }
-}
-
-void pcm_pseudo_code(void)
-{
- struct plc_info *pip = this_plc_info;
- struct plc_state *psp = &this_plc_state;
- int i, nb, lct, hislct;
-
- /* unpack the bits from the peer */
- nb = plc->vec_length + 1;
- i = plc->rcv_vector;
- do {
- psp->r_val[psp->n++] = i & 1;
- i >>= 1;
- } while (--nb > 0);
-
- /* send some more, do LCT, whatever */
- switch (psp->n) {
- case 3:
- /*
- * Got escape flag, port type; send compatibility,
- * LCT duration, MAC for LCT flag.
- */
- if (psp->r_val[0]) {
- /* help! what do I do now? */
- pcm_dump_rtcodes();
- pc_restart();
- break;
- }
- psp->peer_type = (PortType) ((psp->r_val[1] << 1) + psp->r_val[2]);
- /* XXX we're type S, we talk to anybody */
- psp->t_val[3] = 1;
-
- plc->vec_length = 4 - 1;
- plc->xmit_vector = psp->t_val[3] + (psp->t_val[4] << 1)
- + (psp->t_val[5] << 2) + (psp->t_val[6] << 3);
- break;
-
- case 7:
- /*
- * Got compatibility, LCT duration, MAC for LCT flag;
- * time to do the LCT.
- */
- lct = (psp->t_val[4] << 1) + psp->t_val[5];
- hislct = (psp->r_val[4] << 1) + psp->r_val[5];
- if (hislct > lct)
- lct = hislct;
-
- /* set LCT duration */
- switch (lct) {
- case 0:
- plc->lc_length = pip->lc_short >> 8;
- plc->ctrl_b &= ~CB_LONG_LCT;
- break;
- case 1:
- plc->lc_length = pip->lc_medium >> 8;
- plc->ctrl_b &= ~CB_LONG_LCT;
- break;
- case 2:
- plc->ctrl_b |= CB_LONG_LCT;
- /* XXX set up a timeout for pip->lc_long */
- break;
- case 3:
- plc->ctrl_b |= CB_LONG_LCT;
- /* XXX set up a timeout for pip->lc_extended */
- break;
- }
-
- /* start the LCT */
- i = plc->link_err_ct; /* clear the register */
- plc->ctrl_b &= ~CB_PC_LCT;
- /* XXX assume we're not using the MAC for LCT;
- if he's got a MAC, loop his stuff back, otherwise send idle. */
- if (psp->r_val[6])
- plc->ctrl_b |= CB_PC_LCT_LOOP;
- else
- plc->ctrl_b |= CB_PC_LCT_IDLE;
- psp->phase = doing_lct;
- break;
-
- case 8:
- /*
- * Got LCT result, send MAC for local loop and MAC on port
- * output flags.
- */
- if (psp->t_val[7] || psp->r_val[7]) {
- printk("LCT failed, restarting.\n");
- /* LCT failed - do at least a medium length test next time. */
- if (psp->t_val[4] == 0 && psp->t_val[5] == 0)
- psp->t_val[5] = 1;
- pcm_dump_rtcodes();
- pc_restart();
- break;
- }
- plc->vec_length = 2 - 1;
- plc->xmit_vector = psp->t_val[8] + (psp->t_val[9] << 1);
- break;
-
- case 10:
- /*
- * Got MAC for local loop and MAC on port output flags.
- * Let's join.
- */
- plc->intr_mask = IE_NP_ERROR | IE_PCM_BREAK | IE_PCM_ENABLED;
- plc->ctrl_b |= CB_PC_JOIN;
- psp->phase = joining;
- /* printk("pcm: joining\n"); */
- break;
-
- default:
- printk("pcm_pseudo_code bug: n = %d\n", psp->n);
- }
-}
-
-void pcm_lct_done(void)
-{
- struct plc_state *psp = &this_plc_state;
- int i;
-
- i = plc->link_err_ct;
- psp->t_val[7] = i > 0;
- printk("pcm: lct %s (%d errors)\n", psp->t_val[7]? "failed": "passed", i);
- plc->ctrl_b &= ~(CB_PC_LCT | CB_LONG_LCT);
- plc->vec_length = 1 - 1;
- plc->xmit_vector = psp->t_val[7];
- psp->phase = signalling;
-}
-
-void pcm_dump_rtcodes(void)
-{
- struct plc_state *psp = &this_plc_state;
- int i;
-
- if (psp->n > 0) {
- printk("pcm signalling interrupted after %d bits:\nt_val:", psp->n);
- for (i = 0; i < psp->n; ++i)
- printk(" %d", psp->t_val[i]);
- printk("\nr_val:");
- for (i = 0; i < psp->n; ++i)
- printk(" %d", psp->r_val[i]);
- printk("\n");
- }
-}
-
-void pcm_enabled(void)
-{
- struct plc_state *psp = &this_plc_state;
- int i;
-
- printk("pcm: enabled\n");
- psp->phase = active;
- i = plc->link_err_ct; /* clear the register */
- /* XXX should set up LEM here */
- /* XXX do we want to count violation symbols, minimum idle gaps,
- or elasticity buffer errors? */
- plc->intr_mask = IE_NP_ERROR | IE_PCM_BREAK | IE_TRACE_PROP;
- set_cf_join(1); /* we're up :-) */
-}
-
-void pcm_trace_prop(void)
-{
- /* XXX help! what do I do now? */
- pc_stop();
-}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)