2 * $Id: pmcc4_drv.c,v 3.1 2007/08/15 23:32:17 rickd PMCC4_3_1B $
6 /*-----------------------------------------------------------------------------
9 * Copyright (C) 2007 One Stop Systems, Inc.
10 * Copyright (C) 2002-2006 SBE, Inc.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * For further information, contact via email: support@onestopsystems.com
23 * One Stop Systems, Inc. Escondido, California U.S.A.
24 *-----------------------------------------------------------------------------
26 * RCS revision: $Revision: 3.1 $
27 * Last changed on $Date: 2007/08/15 23:32:17 $
28 * Changed by $Author: rickd $
29 *-----------------------------------------------------------------------------
30 * $Log: pmcc4_drv.c,v $
31 * Revision 3.1 2007/08/15 23:32:17 rickd
32 * Use 'if 0' instead of GNU comment delimeter to avoid line wrap induced compiler errors.
34 * Revision 3.0 2007/08/15 22:19:55 rickd
35 * Correct sizeof() castings and pi->regram to support 64bit compatibility.
37 * Revision 2.10 2006/04/21 00:56:40 rickd
38 * workqueue files now prefixed with <sbecom> prefix.
40 * Revision 2.9 2005/11/01 19:22:49 rickd
41 * Add sanity checks against max_port for ioctl functions.
43 * Revision 2.8 2005/10/27 18:59:25 rickd
44 * Code cleanup. Default channel config to HDLC_FCS16.
46 * Revision 2.7 2005/10/18 18:16:30 rickd
47 * Further NCOMM code repairs - (1) interrupt matrix usage inconsistent
48 * for indexing into nciInterrupt[][], code missing double parameters.
49 * (2) check input of ncomm interrupt registration cardID for correct
52 * Revision 2.6 2005/10/17 23:55:28 rickd
53 * Initial port of NCOMM support patches from original work found
54 * in pmc_c4t1e1 as updated by NCOMM. Ref: CONFIG_SBE_PMCC4_NCOMM.
55 * Corrected NCOMMs wanpmcC4T1E1_getBaseAddress() to correctly handle
58 * Revision 2.5 2005/10/13 23:01:28 rickd
59 * Correct panic for illegal address reference w/in get_brdinfo on
60 * first_if/last_if name acquistion under Linux 2.6
62 * Revision 2.4 2005/10/13 21:20:19 rickd
63 * Correction of c4_cleanup() wherein next should be acquired before
64 * ci_t structure is free'd.
66 * Revision 2.3 2005/10/13 19:20:10 rickd
67 * Correct driver removal cleanup code for multiple boards.
69 * Revision 2.2 2005/10/11 18:34:04 rickd
70 * New routine added to determine number of ports (comets) on board.
72 * Revision 2.1 2005/10/05 00:48:13 rickd
73 * Add some RX activation trace code.
75 * Revision 2.0 2005/09/28 00:10:06 rickd
76 * Implement 2.6 workqueue for TX/RX restart. Correction to
77 * hardware register boundary checks allows expanded access of MUSYCC.
78 * Implement new musycc reg&bits namings.
80 *-----------------------------------------------------------------------------
83 char OSSIid_pmcc4_drvc
[] =
84 "@(#)pmcc4_drv.c - $Revision: 3.1 $ (c) Copyright 2002-2007 One Stop Systems, Inc.";
86 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
88 #if defined (__FreeBSD__) || defined (__NetBSD__)
89 #include <sys/param.h>
90 #include <sys/systm.h>
91 #include <sys/errno.h>
93 #include <linux/types.h>
94 #include "pmcc4_sysdep.h"
95 #include <linux/errno.h>
96 #include <linux/kernel.h>
97 #include <linux/sched.h> /* include for timer */
98 #include <linux/timer.h> /* include for timer */
99 #include <linux/hdlc.h>
103 #include "sbecom_inline_linux.h"
105 #include "pmcc4_private.h"
107 #include "pmcc4_ioctls.h"
112 #ifdef SBE_INCLUDE_SYMBOLS
115 #define STATIC static
119 #define KERN_WARN KERN_WARNING
121 /* forward references */
122 status_t
c4_wk_chan_init (mpi_t
*, mch_t
*);
123 void c4_wq_port_cleanup (mpi_t
*);
124 status_t
c4_wq_port_init (mpi_t
*);
126 int c4_loop_port (ci_t
*, int, u_int8_t
);
127 status_t
c4_set_port (ci_t
*, int);
128 status_t
musycc_chan_down (ci_t
*, int);
130 u_int32_t
musycc_chan_proto (int);
131 status_t
musycc_dump_ring (ci_t
*, unsigned int);
132 status_t __init
musycc_init (ci_t
*);
133 void musycc_init_mdt (mpi_t
*);
134 void musycc_serv_req (mpi_t
*, u_int32_t
);
135 void musycc_update_timeslots (mpi_t
*);
137 extern void musycc_update_tx_thp (mch_t
*);
138 extern int cxt1e1_log_level
;
139 extern int cxt1e1_max_mru
;
140 extern int cxt1e1_max_mtu
;
141 extern int max_rxdesc_used
, max_rxdesc_default
;
142 extern int max_txdesc_used
, max_txdesc_default
;
144 #if defined (__powerpc__)
145 extern void *memset (void *s
, int c
, size_t n
);
149 int drvr_state
= SBE_DRVR_INIT
;
151 ci_t
*CI
; /* dummy pointer to board ZEROE's data -
156 sbecom_set_loglevel (int d
)
159 * The code within the following -if- clause is a backdoor debug facility
160 * which can be used to display the state of a board's channel.
164 unsigned int channum
= d
- (LOG_DEBUG
+ 1); /* convert to ZERO
167 (void) musycc_dump_ring ((ci_t
*) CI
, channum
); /* CI implies support
171 if (cxt1e1_log_level
!= d
)
173 pr_info("log level changed from %d to %d\n", cxt1e1_log_level
, d
);
174 cxt1e1_log_level
= d
; /* set new */
176 pr_info("log level is %d\n", cxt1e1_log_level
);
182 c4_find_chan (int channum
)
188 for (ci
= c4_list
; ci
; ci
= ci
->next
)
189 for (portnum
= 0; portnum
< ci
->max_port
; portnum
++)
190 for (gchan
= 0; gchan
< MUSYCC_NCHANS
; gchan
++)
192 if ((ch
= ci
->port
[portnum
].chan
[gchan
]))
194 if ((ch
->state
!= UNASSIGNED
) &&
195 (ch
->channum
== channum
))
209 pr_warning("c4_new() entered, ci needs %u.\n",
210 (unsigned int) sizeof (ci_t
));
213 ci
= (ci_t
*) OS_kmalloc (sizeof (ci_t
));
217 ci
->state
= C_INIT
; /* mark as hardware not available */
220 ci
->brdno
= ci
->next
? ci
->next
->brdno
+ 1 : 0;
222 pr_warning("failed CI malloc, size %u.\n",
223 (unsigned int) sizeof (ci_t
));
226 CI
= ci
; /* DEBUG, only board 0 usage */
232 * Check port state and set LED states using watchdog or ioctl...
233 * also check for in-band SF loopback commands (& cause results if they are there)
235 * Alarm function depends on comet bits indicating change in
236 * link status (linkMask) to keep the link status indication straight.
238 * Indications are only LED and system log -- except when ioctl is invoked.
240 * "alarmed" record (a.k.a. copyVal, in some cases below) decodes as:
242 * RMAI (E1 only) 0x100
245 * link returned 0x20 (link was down, now it's back and 'port get' hasn't run)
246 * change in LED 0x10 (update LED register because value has changed)
252 * note "link has returned" indication is reset on read
253 * (e.g. by use of the c4_control port get command)
256 #define sbeLinkMask 0x41 /* change in signal status (lost/recovered) +
258 #define sbeLinkChange 0x40
259 #define sbeLinkDown 0x01
260 #define sbeAlarmsMask 0x07 /* red / yellow / blue alarm conditions */
261 #define sbeE1AlarmsMask 0x107 /* alarm conditions */
263 #define COMET_LBCMD_READ 0x80 /* read only (do not set, return read value) */
266 checkPorts (ci_t
* ci
)
268 #ifndef CONFIG_SBE_PMCC4_NCOMM
270 * PORT POINT - NCOMM needs to avoid this code since the polling of
271 * alarms conflicts with NCOMM's interrupt servicing implementation.
275 volatile u_int32_t value
;
276 u_int32_t copyVal
, LEDval
;
281 for (portnum
= 0; portnum
< ci
->max_port
; portnum
++)
283 copyVal
= 0x12f & (ci
->alarmed
[portnum
]); /* port's alarm record */
284 comet
= ci
->port
[portnum
].cometbase
;
285 value
= pci_read_32 ((u_int32_t
*) &comet
->cdrc_ists
) & sbeLinkMask
; /* link loss reg */
287 if (value
& sbeLinkChange
) /* is there a change in the link stuff */
289 /* if there's been a change (above) and yet it's the same (below) */
290 if (!(((copyVal
>> 3) & sbeLinkDown
) ^ (value
& sbeLinkDown
)))
292 if (value
& sbeLinkDown
)
293 pr_warning("%s: Port %d momentarily recovered.\n",
294 ci
->devname
, portnum
);
296 pr_warning("%s: Warning: Port %d link was briefly down.\n",
297 ci
->devname
, portnum
);
298 } else if (value
& sbeLinkDown
)
299 pr_warning("%s: Warning: Port %d link is down.\n",
300 ci
->devname
, portnum
);
303 pr_warning("%s: Port %d link has recovered.\n",
304 ci
->devname
, portnum
);
305 copyVal
|= 0x20; /* record link transition to up */
307 copyVal
|= 0x10; /* change (link) --> update LEDs */
309 copyVal
&= 0x137; /* clear LED & link old history bits &
311 if (value
& sbeLinkDown
)
312 copyVal
|= 0x08; /* record link status (now) */
314 { /* if link is up, do this */
315 copyVal
|= 0x40; /* LED indicate link is up */
316 /* Alarm things & the like ... first if E1, then if T1 */
317 if (IS_FRAME_ANY_E1 (ci
->port
[portnum
].p
.port_mode
))
320 * first check Codeword (SaX) changes & CRC and
321 * sub-multi-frame errors
324 * note these errors are printed every time they are detected
327 value
= pci_read_32 ((u_int32_t
*) &comet
->e1_frmr_nat_ists
); /* codeword */
329 { /* if errors (crc or smf only) */
331 pr_warning("%s: E1 Port %d Codeword Sa4 change detected.\n",
332 ci
->devname
, portnum
);
334 pr_warning("%s: E1 Port %d Codeword Sa5 change detected.\n",
335 ci
->devname
, portnum
);
337 pr_warning("%s: E1 Port %d Codeword Sa6 change detected.\n",
338 ci
->devname
, portnum
);
340 pr_warning("%s: E1 Port %d Codeword Sa7 change detected.\n",
341 ci
->devname
, portnum
);
343 pr_warning("%s: E1 Port %d Codeword Sa8 change detected.\n",
344 ci
->devname
, portnum
);
346 value
= pci_read_32 ((u_int32_t
*) &comet
->e1_frmr_mists
); /* crc & smf */
348 { /* if errors (crc or smf only) */
349 if (value
& sbeE1CRC
)
350 pr_warning("%s: E1 Port %d CRC-4 error(s) detected.\n",
351 ci
->devname
, portnum
);
352 if (value
& sbeE1errSMF
) /* error in sub-multiframe */
353 pr_warning("%s: E1 Port %d received errored SMF.\n",
354 ci
->devname
, portnum
);
356 value
= pci_read_32 ((u_int32_t
*) &comet
->e1_frmr_masts
) & 0xcc; /* alarms */
358 * pack alarms together (bitmiser), and construct similar to
361 /* RAI,RMAI,.,.,LOF,AIS,.,. ==> RMAI,.,.,.,.,.,RAI,LOF,AIS */
363 value
= (value
>> 2);
367 value
|= 0x40; /* RAI */
369 value
|= 0x100; /* RMAI */
371 } /* finished packing alarm in handy order */
372 if (value
!= (copyVal
& sbeE1AlarmsMask
))
373 { /* if alarms changed */
374 copyVal
|= 0x10;/* change LED status */
375 if ((copyVal
& sbeRedAlm
) && !(value
& sbeRedAlm
))
377 copyVal
&= ~sbeRedAlm
;
378 pr_warning("%s: E1 Port %d LOF alarm ended.\n",
379 ci
->devname
, portnum
);
380 } else if (!(copyVal
& sbeRedAlm
) && (value
& sbeRedAlm
))
382 copyVal
|= sbeRedAlm
;
383 pr_warning("%s: E1 Warning: Port %d LOF alarm.\n",
384 ci
->devname
, portnum
);
385 } else if ((copyVal
& sbeYelAlm
) && !(value
& sbeYelAlm
))
387 copyVal
&= ~sbeYelAlm
;
388 pr_warning("%s: E1 Port %d RAI alarm ended.\n",
389 ci
->devname
, portnum
);
390 } else if (!(copyVal
& sbeYelAlm
) && (value
& sbeYelAlm
))
392 copyVal
|= sbeYelAlm
;
393 pr_warning("%s: E1 Warning: Port %d RAI alarm.\n",
394 ci
->devname
, portnum
);
395 } else if ((copyVal
& sbeE1RMAI
) && !(value
& sbeE1RMAI
))
397 copyVal
&= ~sbeE1RMAI
;
398 pr_warning("%s: E1 Port %d RMAI alarm ended.\n",
399 ci
->devname
, portnum
);
400 } else if (!(copyVal
& sbeE1RMAI
) && (value
& sbeE1RMAI
))
402 copyVal
|= sbeE1RMAI
;
403 pr_warning("%s: E1 Warning: Port %d RMAI alarm.\n",
404 ci
->devname
, portnum
);
405 } else if ((copyVal
& sbeAISAlm
) && !(value
& sbeAISAlm
))
407 copyVal
&= ~sbeAISAlm
;
408 pr_warning("%s: E1 Port %d AIS alarm ended.\n",
409 ci
->devname
, portnum
);
410 } else if (!(copyVal
& sbeAISAlm
) && (value
& sbeAISAlm
))
412 copyVal
|= sbeAISAlm
;
413 pr_warning("%s: E1 Warning: Port %d AIS alarm.\n",
414 ci
->devname
, portnum
);
417 /* end of E1 alarm code */
420 value
= pci_read_32 ((u_int32_t
*) &comet
->t1_almi_ists
); /* alarms */
421 value
&= sbeAlarmsMask
;
422 if (value
!= (copyVal
& sbeAlarmsMask
))
423 { /* if alarms changed */
424 copyVal
|= 0x10;/* change LED status */
425 if ((copyVal
& sbeRedAlm
) && !(value
& sbeRedAlm
))
427 copyVal
&= ~sbeRedAlm
;
428 pr_warning("%s: Port %d red alarm ended.\n",
429 ci
->devname
, portnum
);
430 } else if (!(copyVal
& sbeRedAlm
) && (value
& sbeRedAlm
))
432 copyVal
|= sbeRedAlm
;
433 pr_warning("%s: Warning: Port %d red alarm.\n",
434 ci
->devname
, portnum
);
435 } else if ((copyVal
& sbeYelAlm
) && !(value
& sbeYelAlm
))
437 copyVal
&= ~sbeYelAlm
;
438 pr_warning("%s: Port %d yellow (RAI) alarm ended.\n",
439 ci
->devname
, portnum
);
440 } else if (!(copyVal
& sbeYelAlm
) && (value
& sbeYelAlm
))
442 copyVal
|= sbeYelAlm
;
443 pr_warning("%s: Warning: Port %d yellow (RAI) alarm.\n",
444 ci
->devname
, portnum
);
445 } else if ((copyVal
& sbeAISAlm
) && !(value
& sbeAISAlm
))
447 copyVal
&= ~sbeAISAlm
;
448 pr_warning("%s: Port %d blue (AIS) alarm ended.\n",
449 ci
->devname
, portnum
);
450 } else if (!(copyVal
& sbeAISAlm
) && (value
& sbeAISAlm
))
452 copyVal
|= sbeAISAlm
;
453 pr_warning("%s: Warning: Port %d blue (AIS) alarm.\n",
454 ci
->devname
, portnum
);
457 } /* end T1 mode alarm checks */
459 if (copyVal
& sbeAlarmsMask
)
460 copyVal
|= 0x80; /* if alarm turn yel LED on */
462 LEDval
|= 0x100; /* tag if LED values have changed */
463 LEDval
|= ((copyVal
& 0xc0) >> (6 - (portnum
* 2)));
465 ci
->alarmed
[portnum
] &= 0xfffff000; /* out with the old (it's fff
467 ci
->alarmed
[portnum
] |= (copyVal
); /* in with the new */
470 * enough with the alarms and LED's, now let's check for loopback
474 if (IS_FRAME_ANY_T1 (ci
->port
[portnum
].p
.port_mode
))
477 * begin in-band (SF) loopback code detection -- start by reading
480 value
= pci_read_32 ((u_int32_t
*) &comet
->ibcd_ies
); /* detect reg. */
481 value
&= 0x3; /* trim to handy bits */
483 { /* activate loopback (sets for deactivate
485 copyVal
= c4_loop_port (ci
, portnum
, COMET_LBCMD_READ
); /* read line loopback
487 if (copyVal
!= COMET_MDIAG_LINELB
) /* don't do it again if
488 * already in that mode */
489 c4_loop_port (ci
, portnum
, COMET_MDIAG_LINELB
); /* put port in line
493 { /* deactivate loopback (sets for activate
495 copyVal
= c4_loop_port (ci
, portnum
, COMET_LBCMD_READ
); /* read line loopback
497 if (copyVal
!= COMET_MDIAG_LBOFF
) /* don't do it again if
498 * already in that mode */
499 c4_loop_port (ci
, portnum
, COMET_MDIAG_LBOFF
); /* take port out of any
503 if (IS_FRAME_ANY_T1ESF (ci
->port
[portnum
].p
.port_mode
))
504 { /* if a T1 ESF mode */
505 /* begin ESF loopback code */
506 value
= pci_read_32 ((u_int32_t
*) &comet
->t1_rboc_sts
) & 0x3f; /* read command */
508 c4_loop_port (ci
, portnum
, COMET_MDIAG_LINELB
); /* put port in line
511 c4_loop_port (ci
, portnum
, COMET_MDIAG_PAYLB
); /* put port in payload
513 if ((value
== 0x1c) || (value
== 0x19) || (value
== 0x12))
514 c4_loop_port (ci
, portnum
, COMET_MDIAG_LBOFF
); /* take port out of any
516 if (cxt1e1_log_level
>= LOG_DEBUG
)
518 pr_warning("%s: BOC value = %x on Port %d\n",
519 ci
->devname
, value
, portnum
);
520 /* end ESF loopback code */
524 /* if something is new, update LED's */
526 pci_write_32 ((u_int32_t
*) &ci
->cpldbase
->leds
, LEDval
& 0xff);
527 #endif /*** CONFIG_SBE_PMCC4_NCOMM ***/
532 c4_watchdog (ci_t
* ci
)
534 if (drvr_state
!= SBE_DRVR_AVAILABLE
)
536 if (cxt1e1_log_level
>= LOG_MONITOR
)
537 pr_info("drvr not available (%x)\n", drvr_state
);
556 next
= ci
->next
; /* protect <next> from upcoming <free> */
557 pci_write_32 ((u_int32_t
*) &ci
->cpldbase
->leds
, PMCC4_CPLD_LED_OFF
);
558 for (portnum
= 0; portnum
< ci
->max_port
; portnum
++)
560 pi
= &ci
->port
[portnum
];
561 c4_wq_port_cleanup (pi
);
562 for (j
= 0; j
< MUSYCC_NCHANS
; j
++)
565 OS_kfree (pi
->chan
[j
]); /* free mch_t struct */
567 OS_kfree (pi
->regram_saved
);
569 OS_kfree (ci
->iqd_p_saved
);
571 ci
= next
; /* cleanup next board, if any */
577 * This function issues a write to all comet chips and expects the same data
578 * to be returned from the subsequent read. This determines the board build
579 * to be a 1-port, 2-port, or 4-port build. The value returned represents a
580 * bit-mask of the found ports. Only certain configurations are considered
581 * VALID or LEGAL builds.
585 c4_get_portcfg (ci_t
* ci
)
589 u_int32_t wdata
, rdata
;
591 wdata
= COMET_MDIAG_LBOFF
; /* take port out of any loopback mode */
594 for (portnum
= 0; portnum
< MUSYCC_NPORTS
; portnum
++)
596 comet
= ci
->port
[portnum
].cometbase
;
597 pci_write_32 ((u_int32_t
*) &comet
->mdiag
, wdata
);
598 rdata
= pci_read_32 ((u_int32_t
*) &comet
->mdiag
) & COMET_MDIAG_LBMASK
;
600 mask
|= 1 << portnum
;
606 /* nothing herein should generate interrupts */
609 c4_init (ci_t
* ci
, u_char
*func0
, u_char
*func1
)
613 static u_int32_t count
= 0;
618 ci
->intlog
.this_status_new
= 0;
619 atomic_set (&ci
->bh_pending
, 0);
621 ci
->reg
= (struct musycc_globalr
*) func0
;
622 ci
->eeprombase
= (u_int32_t
*) (func1
+ EEPROM_OFFSET
);
623 ci
->cpldbase
= (c4cpld_t
*) ((u_int32_t
*) (func1
+ ISPLD_OFFSET
));
625 /*** PORT POINT - the following is the first access of any type to the hardware ***/
626 #ifdef CONFIG_SBE_PMCC4_NCOMM
627 /* NCOMM driver uses INTB interrupt to monitor CPLD register */
628 pci_write_32 ((u_int32_t
*) &ci
->reg
->glcd
, GCD_MAGIC
);
630 /* standard driver POLLS for INTB via CPLD register */
631 pci_write_32 ((u_int32_t
*) &ci
->reg
->glcd
, GCD_MAGIC
| MUSYCC_GCD_INTB_DISABLE
);
637 /* need comet addresses available for determination of hardware build */
638 for (portnum
= 0; portnum
< MUSYCC_NPORTS
; portnum
++)
640 pi
= &ci
->port
[portnum
];
641 pi
->cometbase
= (comet_t
*) ((u_int32_t
*) (func1
+ COMET_OFFSET (portnum
)));
642 pi
->reg
= (struct musycc_globalr
*) ((u_char
*) ci
->reg
+ (portnum
* 0x800));
643 pi
->portnum
= portnum
;
644 pi
->p
.portnum
= portnum
;
647 pr_info("Comet-%d: addr = %p\n", portnum
, pi
->cometbase
);
650 pmsk
= c4_get_portcfg (ci
);
660 case 0x7: /* not built, but could be... */
669 pr_warning("%s: illegal port configuration (%x)\n",
671 return SBE_DRVR_FAIL
;
674 pr_info(">> %s: c4_get_build - pmsk %x max_port %x\n",
675 ci
->devname
, pmsk
, ci
->max_port
);
679 for (portnum
= 0; portnum
< ci
->max_port
; portnum
++)
681 pi
= &ci
->port
[portnum
];
683 pi
->sr_last
= 0xffffffff;
684 pi
->p
.port_mode
= CFG_FRAME_SF
; /* T1 B8ZS, the default */
685 pi
->p
.portP
= (CFG_CLK_PORT_EXTERNAL
| CFG_LBO_LH0
); /* T1 defaults */
687 OS_sem_init (&pi
->sr_sem_busy
, SEM_AVAILABLE
);
688 OS_sem_init (&pi
->sr_sem_wait
, SEM_TAKEN
);
690 for (j
= 0; j
< 32; j
++)
693 pi
->tsm
[j
] = 0; /* no assignments, all available */
696 /* allocate channel structures for this port */
697 for (j
= 0; j
< MUSYCC_NCHANS
; j
++)
699 ch
= OS_kmalloc (sizeof (mch_t
));
703 ch
->state
= UNASSIGNED
;
705 ch
->gchan
= (-1); /* channel assignment not yet known */
706 ch
->channum
= (-1); /* channel assignment not yet known */
707 ch
->p
.card
= ci
->brdno
;
708 ch
->p
.port
= portnum
;
709 ch
->p
.channum
= (-1); /* channel assignment not yet known */
710 ch
->p
.mode_56k
= 0; /* default is 64kbps mode */
713 pr_warning("failed mch_t malloc, port %d channel %d size %u.\n",
714 portnum
, j
, (unsigned int) sizeof (mch_t
));
723 * Set LEDs through their paces to supply visual proof that LEDs are
724 * functional and not burnt out nor broken.
726 * YELLOW + GREEN -> OFF.
729 pci_write_32 ((u_int32_t
*) &ci
->cpldbase
->leds
,
730 PMCC4_CPLD_LED_GREEN
| PMCC4_CPLD_LED_YELLOW
);
731 OS_uwait (750000, "leds");
732 pci_write_32 ((u_int32_t
*) &ci
->cpldbase
->leds
, PMCC4_CPLD_LED_OFF
);
735 OS_init_watchdog (&ci
->wd
, (void (*) (void *)) c4_watchdog
, ci
, WATCHDOG_TIMEOUT
);
736 return SBE_DRVR_SUCCESS
;
740 /* better be fully setup to handle interrupts when you call this */
747 /* PORT POINT: this routine generates first interrupt */
748 if ((ret
= musycc_init (ci
)) != SBE_DRVR_SUCCESS
)
752 ci
->p
.framing_type
= FRAMING_CBP
;
753 ci
->p
.h110enable
= 1;
759 ci
->p
.clock
= 0; /* Use internal clocking until set to
761 c4_card_set_params (ci
, &ci
->p
);
763 OS_start_watchdog (&ci
->wd
);
764 return SBE_DRVR_SUCCESS
;
768 /* This function sets the loopback mode (or clears it, as the case may be). */
771 c4_loop_port (ci_t
* ci
, int portnum
, u_int8_t cmd
)
774 volatile u_int32_t loopValue
;
776 comet
= ci
->port
[portnum
].cometbase
;
777 loopValue
= pci_read_32 ((u_int32_t
*) &comet
->mdiag
) & COMET_MDIAG_LBMASK
;
779 if (cmd
& COMET_LBCMD_READ
)
780 return loopValue
; /* return the read value */
782 if (loopValue
!= cmd
)
786 case COMET_MDIAG_LINELB
:
787 /* set(SF)loopback down (turn off) code length to 6 bits */
788 pci_write_32 ((u_int32_t
*) &comet
->ibcd_cfg
, 0x05);
790 case COMET_MDIAG_LBOFF
:
791 /* set (SF) loopback up (turn on) code length to 5 bits */
792 pci_write_32 ((u_int32_t
*) &comet
->ibcd_cfg
, 0x00);
796 pci_write_32 ((u_int32_t
*) &comet
->mdiag
, cmd
);
797 if (cxt1e1_log_level
>= LOG_WARN
)
798 pr_info("%s: loopback mode changed to %2x from %2x on Port %d\n",
799 ci
->devname
, cmd
, loopValue
, portnum
);
800 loopValue
= pci_read_32 ((u_int32_t
*) &comet
->mdiag
) & COMET_MDIAG_LBMASK
;
801 if (loopValue
!= cmd
)
803 if (cxt1e1_log_level
>= LOG_ERROR
)
804 pr_info("%s: write to loop register failed, unknown state for Port %d\n",
805 ci
->devname
, portnum
);
809 if (cxt1e1_log_level
>= LOG_WARN
)
810 pr_info("%s: loopback already in that mode (%2x)\n",
811 ci
->devname
, loopValue
);
817 /* c4_frame_rw: read or write the comet register specified
818 * (modifies use of port_param to non-standard use of struct)
820 * pp.portnum (one guess)
821 * pp.port_mode offset of register
822 * pp.portP write (or not, i.e. read)
823 * pp.portStatus write value
825 * pp.portStatus also used to return read value
826 * pp.portP also used during write, to return old reg value
830 c4_frame_rw (ci_t
* ci
, struct sbecom_port_param
* pp
)
833 volatile u_int32_t data
;
835 if (pp
->portnum
>= ci
->max_port
)/* sanity check */
838 comet
= ci
->port
[pp
->portnum
].cometbase
;
839 data
= pci_read_32 ((u_int32_t
*) comet
+ pp
->port_mode
) & 0xff;
842 { /* control says this is a register
844 if (pp
->portStatus
== data
)
845 pr_info("%s: Port %d already that value! Writing again anyhow.\n",
846 ci
->devname
, pp
->portnum
);
847 pp
->portP
= (u_int8_t
) data
;
848 pci_write_32 ((u_int32_t
*) comet
+ pp
->port_mode
,
850 data
= pci_read_32 ((u_int32_t
*) comet
+ pp
->port_mode
) & 0xff;
852 pp
->portStatus
= (u_int8_t
) data
;
857 /* c4_pld_rw: read or write the pld register specified
858 * (modifies use of port_param to non-standard use of struct)
860 * pp.port_mode offset of register
861 * pp.portP write (or not, i.e. read)
862 * pp.portStatus write value
864 * pp.portStatus also used to return read value
865 * pp.portP also used during write, to return old reg value
869 c4_pld_rw (ci_t
* ci
, struct sbecom_port_param
* pp
)
871 volatile u_int32_t
*regaddr
;
872 volatile u_int32_t data
;
873 int regnum
= pp
->port_mode
;
875 regaddr
= (u_int32_t
*) ci
->cpldbase
+ regnum
;
876 data
= pci_read_32 ((u_int32_t
*) regaddr
) & 0xff;
879 { /* control says this is a register
881 pp
->portP
= (u_int8_t
) data
;
882 pci_write_32 ((u_int32_t
*) regaddr
, pp
->portStatus
);
883 data
= pci_read_32 ((u_int32_t
*) regaddr
) & 0xff;
885 pp
->portStatus
= (u_int8_t
) data
;
889 /* c4_musycc_rw: read or write the musycc register specified
890 * (modifies use of port_param to non-standard use of struct)
892 * mcp.RWportnum port number and write indication bit (0x80)
893 * mcp.offset offset of register
894 * mcp.value write value going in and read value returning
897 /* PORT POINT: TX Subchannel Map registers are write-only
898 * areas within the MUSYCC and always return FF */
899 /* PORT POINT: regram and reg structures are minorly different and <offset> ioctl
900 * settings are aligned with the <reg> struct musycc_globalr{} usage.
901 * Also, regram is separately allocated shared memory, allocated for each port.
902 * PORT POINT: access offsets of 0x6000 for Msg Cfg Desc Tbl are for 4-port MUSYCC
903 * only. (An 8-port MUSYCC has 0x16000 offsets for accessing its upper 4 tables.)
907 c4_musycc_rw (ci_t
* ci
, struct c4_musycc_param
* mcp
)
910 volatile u_int32_t
*dph
; /* hardware implemented register */
911 u_int32_t
*dpr
= 0; /* RAM image of registers for group command
913 int offset
= mcp
->offset
% 0x800; /* group relative address
914 * offset, mcp->portnum is
916 int portnum
, ramread
= 0;
917 volatile u_int32_t data
;
920 * Sanity check hardware accessibility. The 0x6000 portion handles port
921 * numbers associated with Msg Descr Tbl decoding.
923 portnum
= (mcp
->offset
% 0x6000) / 0x800;
924 if (portnum
>= ci
->max_port
)
926 pi
= &ci
->port
[portnum
];
927 if (mcp
->offset
>= 0x6000)
928 offset
+= 0x6000; /* put back in MsgCfgDesc address offset */
929 dph
= (u_int32_t
*) ((u_long
) pi
->reg
+ offset
);
931 /* read of TX are from RAM image, since hardware returns FF */
932 dpr
= (u_int32_t
*) ((u_long
) pi
->regram
+ offset
);
933 if (mcp
->offset
< 0x6000) /* non MsgDesc Tbl accesses might require
936 if (offset
>= 0x200 && offset
< 0x380)
938 if (offset
>= 0x10 && offset
< 0x200)
941 /* read register from RAM or hardware, depending... */
945 //pr_info("c4_musycc_rw: RAM addr %p read data %x (portno %x offset %x RAM ramread %x)\n", dpr, data, portnum, offset, ramread); /* RLD DEBUG */
948 data
= pci_read_32 ((u_int32_t
*) dph
);
949 //pr_info("c4_musycc_rw: REG addr %p read data %x (portno %x offset %x RAM ramread %x)\n", dph, data, portnum, offset, ramread); /* RLD DEBUG */
953 if (mcp
->RWportnum
& 0x80)
954 { /* control says this is a register
956 if (mcp
->value
== data
)
957 pr_info("%s: musycc grp%d already that value! writing again anyhow.\n",
958 ci
->devname
, (mcp
->RWportnum
& 0x7));
959 /* write register RAM */
962 /* write hardware register */
963 pci_write_32 ((u_int32_t
*) dph
, mcp
->value
);
965 mcp
->value
= data
; /* return the read value (or the 'old
966 * value', if is write) */
971 c4_get_port (ci_t
* ci
, int portnum
)
973 if (portnum
>= ci
->max_port
) /* sanity check */
976 SD_SEM_TAKE (&ci
->sem_wdbusy
, "_wd_"); /* only 1 thru here, per
979 ci
->port
[portnum
].p
.portStatus
= (u_int8_t
) ci
->alarmed
[portnum
];
980 ci
->alarmed
[portnum
] &= 0xdf;
981 SD_SEM_GIVE (&ci
->sem_wdbusy
); /* release per-board hold */
986 c4_set_port (ci_t
* ci
, int portnum
)
989 struct sbecom_port_param
*pp
;
994 if (portnum
>= ci
->max_port
) /* sanity check */
997 pi
= &ci
->port
[portnum
];
998 pp
= &ci
->port
[portnum
].p
;
999 e1mode
= IS_FRAME_ANY_E1 (pp
->port_mode
);
1000 if (cxt1e1_log_level
>= LOG_MONITOR2
)
1002 pr_info("%s: c4_set_port[%d]: entered, e1mode = %x, openchans %d.\n",
1004 portnum
, e1mode
, pi
->openchans
);
1007 return EBUSY
; /* group needs initialization only for
1008 * first channel of a group */
1013 if ((ret
= c4_wq_port_init (pi
))) /* create/init
1014 * workqueue_struct */
1018 init_comet (ci
, pi
->cometbase
, pp
->port_mode
, 1 /* clockmaster == true */ , pp
->portP
);
1019 clck
= pci_read_32 ((u_int32_t
*) &ci
->cpldbase
->mclk
) & PMCC4_CPLD_MCLK_MASK
;
1021 clck
|= 1 << portnum
;
1023 clck
&= 0xf ^ (1 << portnum
);
1025 pci_write_32 ((u_int32_t
*) &ci
->cpldbase
->mclk
, clck
);
1026 pci_write_32 ((u_int32_t
*) &ci
->cpldbase
->mcsr
, PMCC4_CPLD_MCSR_IND
);
1027 pci_write_32 ((u_int32_t
*) &pi
->reg
->gbp
, OS_vtophys (pi
->regram
));
1029 /*********************************************************************/
1030 /* ERRATA: If transparent mode is used, do not set OOFMP_DISABLE bit */
1031 /*********************************************************************/
1034 __constant_cpu_to_le32 (MUSYCC_GRCD_RX_ENABLE
|
1035 MUSYCC_GRCD_TX_ENABLE
|
1036 MUSYCC_GRCD_OOFMP_DISABLE
|
1037 MUSYCC_GRCD_SF_ALIGN
| /* per MUSYCC ERRATA,
1039 MUSYCC_GRCD_COFAIRQ_DISABLE
|
1040 MUSYCC_GRCD_MC_ENABLE
|
1041 (MUSYCC_GRCD_POLLTH_32
<< MUSYCC_GRCD_POLLTH_SHIFT
));
1044 __constant_cpu_to_le32 ((e1mode
? 1 : 0) |
1045 MUSYCC_PCD_TXSYNC_RISING
|
1046 MUSYCC_PCD_RXSYNC_RISING
|
1047 MUSYCC_PCD_RXDATA_RISING
);
1049 /* Message length descriptor */
1050 pi
->regram
->mld
= __constant_cpu_to_le32 (cxt1e1_max_mru
| (cxt1e1_max_mru
<< 16));
1053 for (i
= 0; i
< 32; i
++)
1056 /*** ASSIGNMENT NOTES: ***/
1057 /*** Group's channel ZERO unavailable if E1. ***/
1058 /*** Group's channel 16 unavailable if E1 CAS. ***/
1059 /*** Group's channels 24-31 unavailable if T1. ***/
1061 if (((i
== 0) && e1mode
) ||
1062 ((i
== 16) && ((pp
->port_mode
== CFG_FRAME_E1CRC_CAS
) || (pp
->port_mode
== CFG_FRAME_E1CRC_CAS_AMI
)))
1063 || ((i
> 23) && (!e1mode
)))
1065 pi
->tsm
[i
] = 0xff; /* make tslot unavailable for this mode */
1068 pi
->tsm
[i
] = 0x00; /* make tslot available for assignment */
1071 for (i
= 0; i
< MUSYCC_NCHANS
; i
++)
1073 pi
->regram
->ttsm
[i
] = 0;
1074 pi
->regram
->rtsm
[i
] = 0;
1077 musycc_serv_req (pi
, SR_GROUP_INIT
| SR_RX_DIRECTION
);
1078 musycc_serv_req (pi
, SR_GROUP_INIT
| SR_TX_DIRECTION
);
1080 musycc_init_mdt (pi
);
1082 pi
->group_is_set
= 1;
1088 unsigned int max_int
= 0;
1091 c4_new_chan (ci_t
* ci
, int portnum
, int channum
, void *user
)
1097 if (c4_find_chan (channum
)) /* a new channel shouldn't already exist */
1100 if (portnum
>= ci
->max_port
) /* sanity check */
1103 pi
= &(ci
->port
[portnum
]);
1104 /* find any available channel within this port */
1105 for (gchan
= 0; gchan
< MUSYCC_NCHANS
; gchan
++)
1107 ch
= pi
->chan
[gchan
];
1108 if (ch
&& ch
->state
== UNASSIGNED
) /* no assignment is good! */
1111 if (gchan
== MUSYCC_NCHANS
) /* exhausted table, all were assigned */
1116 /* NOTE: mch_t already cleared during OS_kmalloc() */
1120 ch
->channum
= channum
; /* mark our channel assignment */
1121 ch
->p
.channum
= channum
;
1123 ch
->p
.card
= ci
->brdno
;
1124 ch
->p
.port
= portnum
;
1126 ch
->p
.chan_mode
= CFG_CH_PROTO_HDLC_FCS16
;
1127 ch
->p
.idlecode
= CFG_CH_FLAG_7E
;
1128 ch
->p
.pad_fill_count
= 2;
1129 spin_lock_init (&ch
->ch_rxlock
);
1130 spin_lock_init (&ch
->ch_txlock
);
1135 if ((ret
= c4_wk_chan_init (pi
, ch
)))
1139 /* save off interface assignments which bound a board */
1140 if (ci
->first_if
== 0) /* first channel registered is assumed to
1141 * be the lowest channel */
1143 ci
->first_if
= ci
->last_if
= user
;
1144 ci
->first_channum
= ci
->last_channum
= channum
;
1148 if (ci
->last_channum
< channum
) /* higher number channel found */
1149 ci
->last_channum
= channum
;
1155 c4_del_chan (int channum
)
1159 if (!(ch
= c4_find_chan (channum
)))
1161 if (ch
->state
== UP
)
1162 musycc_chan_down ((ci_t
*) 0, channum
);
1163 ch
->state
= UNASSIGNED
;
1166 ch
->p
.channum
= (-1);
1171 c4_del_chan_stats (int channum
)
1175 if (!(ch
= c4_find_chan (channum
)))
1178 memset (&ch
->s
, 0, sizeof (struct sbecom_chan_stats
));
1184 c4_set_chan (int channum
, struct sbecom_chan_param
* p
)
1189 if (!(ch
= c4_find_chan (channum
)))
1193 if (ch
->p
.card
!= p
->card
||
1194 ch
->p
.port
!= p
->port
||
1195 ch
->p
.channum
!= p
->channum
)
1199 if (!(ch
->up
->group_is_set
))
1201 return EIO
; /* out of order, SET_PORT command
1202 * required prior to first group's
1203 * SET_CHAN command */
1206 * Check for change of parameter settings in order to invoke closing of
1207 * channel prior to hardware poking.
1210 if (ch
->p
.status
!= p
->status
|| ch
->p
.chan_mode
!= p
->chan_mode
||
1211 ch
->p
.data_inv
!= p
->data_inv
|| ch
->p
.intr_mask
!= p
->intr_mask
||
1212 ch
->txd_free
< ch
->txd_num
) /* to clear out queued messages */
1213 x
= 1; /* we have a change requested */
1214 for (i
= 0; i
< 32; i
++) /* check for timeslot mapping changes */
1215 if (ch
->p
.bitmask
[i
] != p
->bitmask
[i
])
1216 x
= 1; /* we have a change requested */
1218 if (x
&& (ch
->state
== UP
)) /* if change request and channel is
1223 if ((ret
= musycc_chan_down ((ci_t
*) 0, channum
)))
1225 if ((ret
= c4_chan_up (ch
->up
->up
, channum
)))
1227 sd_enable_xmit (ch
->user
); /* re-enable to catch flow controlled
1235 c4_get_chan (int channum
, struct sbecom_chan_param
* p
)
1239 if (!(ch
= c4_find_chan (channum
)))
1246 c4_get_chan_stats (int channum
, struct sbecom_chan_stats
* p
)
1250 if (!(ch
= c4_find_chan (channum
)))
1253 p
->tx_pending
= atomic_read (&ch
->tx_pending
);
1258 c4_fifo_alloc (mpi_t
* pi
, int chan
, int *len
)
1260 int i
, l
= 0, start
= 0, max
= 0, maxstart
= 0;
1262 for (i
= 0; i
< 32; i
++)
1264 if (pi
->fifomap
[i
] != -1)
1281 if (cxt1e1_log_level
>= LOG_WARN
)
1282 pr_info("%s: wanted to allocate %d fifo space, but got only %d\n",
1283 pi
->up
->devname
, *len
, max
);
1286 if (cxt1e1_log_level
>= LOG_DEBUG
)
1287 pr_info("%s: allocated %d fifo at %d for channel %d/%d\n",
1288 pi
->up
->devname
, max
, start
, chan
, pi
->p
.portnum
);
1289 for (i
= maxstart
; i
< (maxstart
+ max
); i
++)
1290 pi
->fifomap
[i
] = chan
;
1295 c4_fifo_free (mpi_t
* pi
, int chan
)
1299 if (cxt1e1_log_level
>= LOG_DEBUG
)
1300 pr_info("%s: deallocated fifo for channel %d/%d\n",
1301 pi
->up
->devname
, chan
, pi
->p
.portnum
);
1302 for (i
= 0; i
< 32; i
++)
1303 if (pi
->fifomap
[i
] == chan
)
1304 pi
->fifomap
[i
] = -1;
1309 c4_chan_up (ci_t
* ci
, int channum
)
1315 int nts
, nbuf
, txnum
, rxnum
;
1316 int addr
, i
, j
, gchan
;
1317 u_int32_t tmp
; /* for optimizing conversion across BE
1320 if (!(ch
= c4_find_chan (channum
)))
1322 if (ch
->state
== UP
)
1324 if (cxt1e1_log_level
>= LOG_MONITOR
)
1325 pr_info("%s: channel already UP, graceful early exit\n",
1331 /* find nts ('number of timeslots') */
1333 for (i
= 0; i
< 32; i
++)
1335 if (ch
->p
.bitmask
[i
] & pi
->tsm
[i
])
1337 if (1 || cxt1e1_log_level
>= LOG_WARN
)
1339 pr_info("%s: c4_chan_up[%d] EINVAL (attempt to cfg in-use or unavailable TimeSlot[%d])\n",
1340 ci
->devname
, channum
, i
);
1341 pr_info("+ ask4 %x, currently %x\n",
1342 ch
->p
.bitmask
[i
], pi
->tsm
[i
]);
1346 for (j
= 0; j
< 8; j
++)
1347 if (ch
->p
.bitmask
[i
] & (1 << j
))
1351 nbuf
= nts
/ 8 ? nts
/ 8 : 1;
1354 /* if( cxt1e1_log_level >= LOG_WARN) */
1355 pr_info("%s: c4_chan_up[%d] ENOBUFS (no TimeSlots assigned)\n",
1356 ci
->devname
, channum
);
1357 return ENOBUFS
; /* this should not happen */
1359 addr
= c4_fifo_alloc (pi
, gchan
, &nbuf
);
1362 /* Setup the Time Slot Map */
1363 musycc_update_timeslots (pi
);
1365 /* ch->tx_limit = nts; */
1366 ch
->s
.tx_pending
= 0;
1368 /* Set Channel Configuration Descriptors */
1372 ccd
= musycc_chan_proto (ch
->p
.chan_mode
) << MUSYCC_CCD_PROTO_SHIFT
;
1373 if ((ch
->p
.chan_mode
== CFG_CH_PROTO_ISLP_MODE
) ||
1374 (ch
->p
.chan_mode
== CFG_CH_PROTO_TRANS
))
1376 ccd
|= MUSYCC_CCD_FCS_XFER
; /* Non FSC Mode */
1378 ccd
|= 2 << MUSYCC_CCD_MAX_LENGTH
; /* Select second MTU */
1379 ccd
|= ch
->p
.intr_mask
;
1380 ccd
|= addr
<< MUSYCC_CCD_BUFFER_LOC
;
1381 if (ch
->p
.chan_mode
== CFG_CH_PROTO_TRANS
)
1382 ccd
|= (nbuf
) << MUSYCC_CCD_BUFFER_LENGTH
;
1384 ccd
|= (nbuf
- 1) << MUSYCC_CCD_BUFFER_LENGTH
;
1386 if (ch
->p
.data_inv
& CFG_CH_DINV_TX
)
1387 ccd
|= MUSYCC_CCD_INVERT_DATA
; /* Invert data */
1388 pi
->regram
->tcct
[gchan
] = cpu_to_le32 (ccd
);
1390 if (ch
->p
.data_inv
& CFG_CH_DINV_RX
)
1391 ccd
|= MUSYCC_CCD_INVERT_DATA
; /* Invert data */
1393 ccd
&= ~MUSYCC_CCD_INVERT_DATA
; /* take away data inversion */
1394 pi
->regram
->rcct
[gchan
] = cpu_to_le32 (ccd
);
1398 /* Reread the Channel Configuration Descriptor for this channel */
1399 musycc_serv_req (pi
, SR_CHANNEL_CONFIG
| SR_RX_DIRECTION
| gchan
);
1400 musycc_serv_req (pi
, SR_CHANNEL_CONFIG
| SR_TX_DIRECTION
| gchan
);
1403 * Figure out how many buffers we want. If the customer has changed from
1404 * the defaults, then use the changed values. Otherwise, use Transparent
1405 * mode's specific minimum default settings.
1407 if (ch
->p
.chan_mode
== CFG_CH_PROTO_TRANS
)
1409 if (max_rxdesc_used
== max_rxdesc_default
) /* use default setting */
1410 max_rxdesc_used
= MUSYCC_RXDESC_TRANS
;
1411 if (max_txdesc_used
== max_txdesc_default
) /* use default setting */
1412 max_txdesc_used
= MUSYCC_TXDESC_TRANS
;
1415 * Increase counts when hyperchanneling, since this implies an increase
1416 * in throughput per channel
1418 rxnum
= max_rxdesc_used
+ (nts
/ 4);
1419 txnum
= max_txdesc_used
+ (nts
/ 4);
1423 if (cxt1e1_log_level
>= LOG_MONITOR
)
1424 pr_info("%s: mode %x rxnum %d (rxused %d def %d) txnum %d (txused %d def %d)\n",
1425 ci
->devname
, ch
->p
.chan_mode
,
1426 rxnum
, max_rxdesc_used
, max_rxdesc_default
,
1427 txnum
, max_txdesc_used
, max_txdesc_default
);
1430 ch
->rxd_num
= rxnum
;
1431 ch
->txd_num
= txnum
;
1432 ch
->rxix_irq_srv
= 0;
1434 ch
->mdr
= OS_kmalloc (sizeof (struct mdesc
) * rxnum
);
1435 ch
->mdt
= OS_kmalloc (sizeof (struct mdesc
) * txnum
);
1436 if (ch
->p
.chan_mode
== CFG_CH_PROTO_TRANS
)
1437 tmp
= __constant_cpu_to_le32 (cxt1e1_max_mru
| EOBIRQ_ENABLE
);
1439 tmp
= __constant_cpu_to_le32 (cxt1e1_max_mru
);
1441 for (i
= 0, md
= ch
->mdr
; i
< rxnum
; i
++, md
++)
1443 if (i
== (rxnum
- 1))
1445 md
->snext
= &ch
->mdr
[0];/* wrapness */
1448 md
->snext
= &ch
->mdr
[i
+ 1];
1450 md
->next
= cpu_to_le32 (OS_vtophys (md
->snext
));
1452 if (!(m
= OS_mem_token_alloc (cxt1e1_max_mru
)))
1454 if (cxt1e1_log_level
>= LOG_MONITOR
)
1455 pr_info("%s: c4_chan_up[%d] - token alloc failure, size = %d.\n",
1456 ci
->devname
, channum
, cxt1e1_max_mru
);
1460 md
->data
= cpu_to_le32 (OS_vtophys (OS_mem_token_data (m
)));
1461 md
->status
= tmp
| MUSYCC_RX_OWNED
; /* MUSYCC owns RX descriptor **
1463 * MUSYCC_RX_OWNED = 0 so no
1464 * need to byteSwap */
1467 for (i
= 0, md
= ch
->mdt
; i
< txnum
; i
++, md
++)
1469 md
->status
= HOST_TX_OWNED
; /* Host owns TX descriptor ** CODING
1470 * NOTE: HOST_TX_OWNED = 0 so no need to
1474 if (i
== (txnum
- 1))
1476 md
->snext
= &ch
->mdt
[0];/* wrapness */
1479 md
->snext
= &ch
->mdt
[i
+ 1];
1481 md
->next
= cpu_to_le32 (OS_vtophys (md
->snext
));
1483 ch
->txd_irq_srv
= ch
->txd_usr_add
= &ch
->mdt
[0];
1484 ch
->txd_free
= txnum
;
1486 ch
->txd_required
= 0;
1488 /* Configure it into the chip */
1489 tmp
= cpu_to_le32 (OS_vtophys (&ch
->mdt
[0]));
1490 pi
->regram
->thp
[gchan
] = tmp
;
1491 pi
->regram
->tmp
[gchan
] = tmp
;
1493 tmp
= cpu_to_le32 (OS_vtophys (&ch
->mdr
[0]));
1494 pi
->regram
->rhp
[gchan
] = tmp
;
1495 pi
->regram
->rmp
[gchan
] = tmp
;
1497 /* Activate the Channel */
1499 if (ch
->p
.status
& RX_ENABLED
)
1501 #ifdef RLD_TRANS_DEBUG
1502 pr_info("++ c4_chan_up() CHAN RX ACTIVATE: chan %d\n", ch
->channum
);
1504 ch
->ch_start_rx
= 0; /* we are restarting RX... */
1505 musycc_serv_req (pi
, SR_CHANNEL_ACTIVATE
| SR_RX_DIRECTION
| gchan
);
1507 if (ch
->p
.status
& TX_ENABLED
)
1509 #ifdef RLD_TRANS_DEBUG
1510 pr_info("++ c4_chan_up() CHAN TX ACTIVATE: chan %d <delayed>\n", ch
->channum
);
1512 ch
->ch_start_tx
= CH_START_TX_1ST
; /* we are delaying start
1513 * until receipt from user of
1514 * first packet to transmit. */
1516 ch
->status
= ch
->p
.status
;
1523 /* Don't leak all the previously allocated mbufs in this loop */
1525 OS_mem_token_free (ch
->mdr
[i
].mem_token
);
1537 /* stop the hardware from servicing & interrupting */
1540 c4_stopwd (ci_t
* ci
)
1542 OS_stop_watchdog (&ci
->wd
);
1543 SD_SEM_TAKE (&ci
->sem_wdbusy
, "_stop_"); /* ensure WD not running */
1544 SD_SEM_GIVE (&ci
->sem_wdbusy
);
1549 sbecom_get_brdinfo (ci_t
* ci
, struct sbe_brd_info
* bip
, u_int8_t
*bsn
)
1555 bip
->brdno
= ci
->brdno
; /* our board number */
1556 bip
->brd_id
= ci
->brd_id
;
1557 bip
->brd_hdw_id
= ci
->hdw_bid
;
1558 bip
->brd_chan_cnt
= MUSYCC_NCHANS
* ci
->max_port
; /* number of channels
1560 bip
->brd_port_cnt
= ci
->max_port
; /* number of ports being used */
1561 bip
->brd_pci_speed
= BINFO_PCI_SPEED_unk
; /* PCI speed not yet
1567 struct net_device
*dev
;
1569 dev
= (struct net_device
*) ci
->first_if
;
1570 np
= (char *) dev
->name
;
1572 strncpy (bip
->first_iname
, np
, CHNM_STRLEN
- 1);
1574 strcpy (bip
->first_iname
, "<NULL>");
1578 struct net_device
*dev
;
1580 dev
= (struct net_device
*) ci
->last_if
;
1581 np
= (char *) dev
->name
;
1583 strncpy (bip
->last_iname
, np
, CHNM_STRLEN
- 1);
1585 strcpy (bip
->last_iname
, "<NULL>");
1589 for (i
= 0; i
< 3; i
++)
1591 bip
->brd_mac_addr
[i
] = *bsn
++;
1595 bip
->brd_mac_addr
[i
] = *bsn
;
1596 sn
= (sn
<< 8) | *bsn
++;
1600 for (i
= 0; i
< 6; i
++)
1601 bip
->brd_mac_addr
[i
] = 0;
1608 c4_get_iidinfo (ci_t
* ci
, struct sbe_iid_info
* iip
)
1610 struct net_device
*dev
;
1613 if (!(dev
= getuserbychan (iip
->channum
)))
1617 strncpy (iip
->iname
, np
, CHNM_STRLEN
- 1);
1622 #ifdef CONFIG_SBE_PMCC4_NCOMM
1623 void (*nciInterrupt
[MAX_BOARDS
][4]) (void);
1624 extern void wanpmcC4T1E1_hookInterrupt (int cardID
, int deviceID
, void *handler
);
1627 wanpmcC4T1E1_hookInterrupt (int cardID
, int deviceID
, void *handler
)
1629 if (cardID
< MAX_BOARDS
) /* sanity check */
1630 nciInterrupt
[cardID
][deviceID
] = handler
;
1634 c4_ebus_intr_th_handler (void *devp
)
1636 ci_t
*ci
= (ci_t
*) devp
;
1637 volatile u_int32_t ists
;
1641 /* which COMET caused the interrupt */
1643 ists
= pci_read_32 ((u_int32_t
*) &ci
->cpldbase
->intr
);
1644 if (ists
& PMCC4_CPLD_INTR_CMT_1
)
1647 if (nciInterrupt
[brdno
][0] != NULL
)
1648 (*nciInterrupt
[brdno
][0]) ();
1650 if (ists
& PMCC4_CPLD_INTR_CMT_2
)
1653 if (nciInterrupt
[brdno
][1] != NULL
)
1654 (*nciInterrupt
[brdno
][1]) ();
1656 if (ists
& PMCC4_CPLD_INTR_CMT_3
)
1659 if (nciInterrupt
[brdno
][2] != NULL
)
1660 (*nciInterrupt
[brdno
][2]) ();
1662 if (ists
& PMCC4_CPLD_INTR_CMT_4
)
1665 if (nciInterrupt
[brdno
][3] != NULL
)
1666 (*nciInterrupt
[brdno
][3]) ();
1669 /*** Test code just de-implements the asserted interrupt. Alternate
1670 vendor will supply COMET interrupt handling code herein or such.
1672 pci_write_32 ((u_int32_t
*) &ci
->reg
->glcd
, GCD_MAGIC
| MUSYCC_GCD_INTB_DISABLE
);
1675 return IRQ_RETVAL (handled
);
1680 wanpmcC4T1E1_getBaseAddress (int cardID
, int deviceID
)
1683 unsigned long base
= 0;
1688 if (ci
->brdno
== cardID
) /* found valid device */
1690 if (deviceID
< ci
->max_port
) /* comet is supported */
1691 base
= ((unsigned long) ci
->port
[deviceID
].cometbase
);
1694 ci
= ci
->next
; /* next board, if any */
1699 #endif /*** CONFIG_SBE_PMCC4_NCOMM ***/
1702 /*** End-of-File ***/