Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs...
[pandora-kernel.git] / drivers / staging / cxt1e1 / pmcc4_drv.c
1 /*
2  * $Id: pmcc4_drv.c,v 3.1 2007/08/15 23:32:17 rickd PMCC4_3_1B $
3  */
4
5
6 /*-----------------------------------------------------------------------------
7  * pmcc4_drv.c -
8  *
9  * Copyright (C) 2007  One Stop Systems, Inc.
10  * Copyright (C) 2002-2006  SBE, Inc.
11  *
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.
16  *
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.
21  *
22  * For further information, contact via email: support@onestopsystems.com
23  * One Stop Systems, Inc.  Escondido, California  U.S.A.
24  *-----------------------------------------------------------------------------
25  * RCS info:
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.
33  *
34  * Revision 3.0  2007/08/15 22:19:55  rickd
35  * Correct sizeof() castings and pi->regram to support 64bit compatibility.
36  *
37  * Revision 2.10  2006/04/21 00:56:40  rickd
38  * workqueue files now prefixed with <sbecom> prefix.
39  *
40  * Revision 2.9  2005/11/01 19:22:49  rickd
41  * Add sanity checks against max_port for ioctl functions.
42  *
43  * Revision 2.8  2005/10/27 18:59:25  rickd
44  * Code cleanup.  Default channel config to HDLC_FCS16.
45  *
46  * Revision 2.7  2005/10/18 18:16:30  rickd
47  * Further NCOMM code repairs - (1) interrupt matrix usage inconsistant
48  * for indexing into nciInterrupt[][], code missing double parameters.
49  * (2) check input of ncomm interrupt registration cardID for correct
50  * boundary values.
51  *
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
56  * multiple boards.
57  *
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
61  *
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.
65  *
66  * Revision 2.3  2005/10/13 19:20:10  rickd
67  * Correct driver removal cleanup code for multiple boards.
68  *
69  * Revision 2.2  2005/10/11 18:34:04  rickd
70  * New routine added to determine number of ports (comets) on board.
71  *
72  * Revision 2.1  2005/10/05 00:48:13  rickd
73  * Add some RX activation trace code.
74  *
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.
79  *
80  *-----------------------------------------------------------------------------
81  */
82
83 char        OSSIid_pmcc4_drvc[] =
84 "@(#)pmcc4_drv.c - $Revision: 3.1 $   (c) Copyright 2002-2007 One Stop Systems, Inc.";
85
86 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
87
88 #if defined (__FreeBSD__) || defined (__NetBSD__)
89 #include <sys/param.h>
90 #include <sys/systm.h>
91 #include <sys/errno.h>
92 #else
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>
100 #include <asm/io.h>
101 #endif
102
103 #include "sbecom_inline_linux.h"
104 #include "libsbew.h"
105 #include "pmcc4_private.h"
106 #include "pmcc4.h"
107 #include "pmcc4_ioctls.h"
108 #include "musycc.h"
109 #include "comet.h"
110 #include "sbe_bid.h"
111
112 #ifdef SBE_INCLUDE_SYMBOLS
113 #define STATIC
114 #else
115 #define STATIC  static
116 #endif
117
118
119 #define KERN_WARN KERN_WARNING
120
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 *);
125
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);
129
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 *);
136
137 extern void musycc_update_tx_thp (mch_t *);
138 extern int  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;
143
144 #if defined (__powerpc__)
145 extern void *memset (void *s, int c, size_t n);
146
147 #endif
148
149 int         drvr_state = SBE_DRVR_INIT;
150 ci_t       *c4_list = 0;
151 ci_t       *CI;                 /* dummy pointer to board ZEROE's data -
152                                  * DEBUG USAGE */
153
154
155 void
156 sbecom_set_loglevel (int d)
157 {
158     /*
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.
161      */
162     if (d > LOG_DEBUG)
163     {
164         unsigned int channum = d - (LOG_DEBUG + 1);     /* convert to ZERO
165                                                          * relativity */
166
167         (void) musycc_dump_ring ((ci_t *) CI, channum); /* CI implies support
168                                                          * for card 0 only */
169     } else
170     {
171         if (log_level != d)
172         {
173             pr_info("log level changed from %d to %d\n", log_level, d);
174             log_level = d;          /* set new */
175         } else
176             pr_info("log level is %d\n", log_level);
177     }
178 }
179
180
181 mch_t      *
182 c4_find_chan (int channum)
183 {
184     ci_t       *ci;
185     mch_t      *ch;
186     int         portnum, gchan;
187
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++)
191             {
192                 if ((ch = ci->port[portnum].chan[gchan]))
193                 {
194                     if ((ch->state != UNASSIGNED) &&
195                         (ch->channum == channum))
196                         return (ch);
197                 }
198             }
199     return 0;
200 }
201
202
203 ci_t       *__init
204 c4_new (void *hi)
205 {
206     ci_t       *ci;
207
208 #ifdef SBE_MAP_DEBUG
209     pr_warning("c4_new() entered, ci needs %u.\n",
210                (unsigned int) sizeof (ci_t));
211 #endif
212
213     ci = (ci_t *) OS_kmalloc (sizeof (ci_t));
214     if (ci)
215     {
216         ci->hdw_info = hi;
217         ci->state = C_INIT;         /* mark as hardware not available */
218         ci->next = c4_list;
219         c4_list = ci;
220         ci->brdno = ci->next ? ci->next->brdno + 1 : 0;
221     } else
222         pr_warning("failed CI malloc, size %u.\n",
223                    (unsigned int) sizeof (ci_t));
224
225     if (CI == 0)
226         CI = ci;                    /* DEBUG, only board 0 usage */
227     return ci;
228 }
229
230
231 /***
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)
234  *
235  * Alarm function depends on comet bits indicating change in
236  * link status (linkMask) to keep the link status indication straight.
237  *
238  * Indications are only LED and system log -- except when ioctl is invoked.
239  *
240  * "alarmed" record (a.k.a. copyVal, in some cases below) decodes as:
241  *
242  *   RMAI  (E1 only) 0x100
243  *   alarm LED on    0x80
244  *   link LED on     0x40
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)
247  *   link is down    0x08
248  *   YelAlm(RAI)     0x04
249  *   RedAlm          0x02
250  *   AIS(blue)Alm    0x01
251  *
252  * note "link has returned" indication is reset on read
253  * (e.g. by use of the c4_control port get command)
254  */
255
256 #define sbeLinkMask       0x41  /* change in signal status (lost/recovered) +
257                                  * state */
258 #define sbeLinkChange     0x40
259 #define sbeLinkDown       0x01
260 #define sbeAlarmsMask     0x07  /* red / yellow / blue alarm conditions */
261 #define sbeE1AlarmsMask   0x107 /* alarm conditions */
262
263 #define COMET_LBCMD_READ  0x80  /* read only (do not set, return read value) */
264
265 void
266 checkPorts (ci_t * ci)
267 {
268 #ifndef CONFIG_SBE_PMCC4_NCOMM
269     /*
270      * PORT POINT - NCOMM needs to avoid this code since the polling of
271      * alarms conflicts with NCOMM's interrupt servicing implementation.
272      */
273
274     comet_t    *comet;
275     volatile u_int32_t value;
276     u_int32_t   copyVal, LEDval;
277
278     u_int8_t portnum;
279
280     LEDval = 0;
281     for (portnum = 0; portnum < ci->max_port; portnum++)
282     {
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 */
286
287         if (value & sbeLinkChange)  /* is there a change in the link stuff */
288         {
289             /* if there's been a change (above) and yet it's the same (below) */
290             if (!(((copyVal >> 3) & sbeLinkDown) ^ (value & sbeLinkDown)))
291             {
292                 if (value & sbeLinkDown)
293                     pr_warning("%s: Port %d momentarily recovered.\n",
294                                ci->devname, portnum);
295                 else
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);
301             else
302             {
303                 pr_warning("%s: Port %d link has recovered.\n",
304                            ci->devname, portnum);
305                 copyVal |= 0x20;    /* record link transition to up */
306             }
307             copyVal |= 0x10;        /* change (link) --> update LEDs  */
308         }
309         copyVal &= 0x137;           /* clear LED & link old history bits &
310                                      * save others */
311         if (value & sbeLinkDown)
312             copyVal |= 0x08;        /* record link status (now) */
313         else
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))
318             {
319                 /*
320                  * first check Codeword (SaX) changes & CRC and
321                  * sub-multi-frame errors
322                  */
323                 /*
324                  * note these errors are printed every time they are detected
325                  * vs. alarms
326                  */
327                 value = pci_read_32 ((u_int32_t *) &comet->e1_frmr_nat_ists);   /* codeword */
328                 if (value & 0x1f)
329                 {                   /* if errors (crc or smf only) */
330                     if (value & 0x10)
331                         pr_warning("%s: E1 Port %d Codeword Sa4 change detected.\n",
332                                    ci->devname, portnum);
333                     if (value & 0x08)
334                         pr_warning("%s: E1 Port %d Codeword Sa5 change detected.\n",
335                                    ci->devname, portnum);
336                     if (value & 0x04)
337                         pr_warning("%s: E1 Port %d Codeword Sa6 change detected.\n",
338                                    ci->devname, portnum);
339                     if (value & 0x02)
340                         pr_warning("%s: E1 Port %d Codeword Sa7 change detected.\n",
341                                    ci->devname, portnum);
342                     if (value & 0x01)
343                         pr_warning("%s: E1 Port %d Codeword Sa8 change detected.\n",
344                                    ci->devname, portnum);
345                 }
346                 value = pci_read_32 ((u_int32_t *) &comet->e1_frmr_mists);      /* crc & smf */
347                 if (value & 0x3)
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);
355                 }
356                 value = pci_read_32 ((u_int32_t *) &comet->e1_frmr_masts) & 0xcc; /* alarms */
357                 /*
358                  * pack alarms together (bitmiser), and construct similar to
359                  * T1
360                  */
361                 /* RAI,RMAI,.,.,LOF,AIS,.,. ==>  RMAI,.,.,.,.,.,RAI,LOF,AIS */
362                 /* see 0x97 */
363                 value = (value >> 2);
364                 if (value & 0x30)
365                 {
366                     if (value & 0x20)
367                         value |= 0x40;  /* RAI */
368                     if (value & 0x10)
369                         value |= 0x100; /* RMAI */
370                     value &= ~0x30;
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))
376                     {
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))
381                     {
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))
386                     {
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))
391                     {
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))
396                     {
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))
401                     {
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))
406                     {
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))
411                     {
412                         copyVal |= sbeAISAlm;
413                         pr_warning("%s: E1 Warning: Port %d AIS alarm.\n",
414                                    ci->devname, portnum);
415                     }
416                 }
417                 /* end of E1 alarm code */
418             } else
419             {                       /* if a T1 mode */
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))
426                     {
427                         copyVal &= ~sbeRedAlm;
428                         pr_warning("%s: Port %d red alarm ended.\n",
429                                    ci->devname, portnum);
430                     } else if (!(copyVal & sbeRedAlm) && (value & sbeRedAlm))
431                     {
432                         copyVal |= sbeRedAlm;
433                         pr_warning("%s: Warning: Port %d red alarm.\n",
434                                    ci->devname, portnum);
435                     } else if ((copyVal & sbeYelAlm) && !(value & sbeYelAlm))
436                     {
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))
441                     {
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))
446                     {
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))
451                     {
452                         copyVal |= sbeAISAlm;
453                         pr_warning("%s: Warning: Port %d blue (AIS) alarm.\n",
454                                    ci->devname, portnum);
455                     }
456                 }
457             }                       /* end T1 mode alarm checks */
458         }
459         if (copyVal & sbeAlarmsMask)
460             copyVal |= 0x80;        /* if alarm turn yel LED on */
461         if (copyVal & 0x10)
462             LEDval |= 0x100;        /* tag if LED values have changed  */
463         LEDval |= ((copyVal & 0xc0) >> (6 - (portnum * 2)));
464
465         ci->alarmed[portnum] &= 0xfffff000;     /* out with the old (it's fff
466                                                  * ... foo) */
467         ci->alarmed[portnum] |= (copyVal);      /* in with the new */
468
469         /*
470          * enough with the alarms and LED's, now let's check for loopback
471          * requests
472          */
473
474         if (IS_FRAME_ANY_T1 (ci->port[portnum].p.port_mode))
475         {                           /* if a T1 mode  */
476             /*
477              * begin in-band (SF) loopback code detection -- start by reading
478              * command
479              */
480             value = pci_read_32 ((u_int32_t *) &comet->ibcd_ies);       /* detect reg. */
481             value &= 0x3;           /* trim to handy bits */
482             if (value & 0x2)
483             {                       /* activate loopback (sets for deactivate
484                                      * code length) */
485                 copyVal = c4_loop_port (ci, portnum, COMET_LBCMD_READ); /* read line loopback
486                                                                          * mode */
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
490                                                                          * loopback mode */
491             }
492             if (value & 0x1)
493             {                       /* deactivate loopback (sets for activate
494                                      * code length) */
495                 copyVal = c4_loop_port (ci, portnum, COMET_LBCMD_READ); /* read line loopback
496                                                                          * mode */
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
500                                                                          * loopback mode */
501             }
502         }
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 */
507             if (value == 0x07)
508                 c4_loop_port (ci, portnum, COMET_MDIAG_LINELB); /* put port in line
509                                                                  * loopback mode */
510             if (value == 0x0a)
511                 c4_loop_port (ci, portnum, COMET_MDIAG_PAYLB);  /* put port in payload
512                                                                  * loopbk mode */
513             if ((value == 0x1c) || (value == 0x19) || (value == 0x12))
514                 c4_loop_port (ci, portnum, COMET_MDIAG_LBOFF);  /* take port out of any
515                                                                  * loopbk mode */
516             if (log_level >= LOG_DEBUG)
517                 if (value != 0x3f)
518                     pr_warning("%s: BOC value = %x on Port %d\n",
519                                ci->devname, value, portnum);
520             /* end ESF loopback code */
521         }
522     }
523
524     /* if something is new, update LED's */
525     if (LEDval & 0x100)
526         pci_write_32 ((u_int32_t *) &ci->cpldbase->leds, LEDval & 0xff);
527 #endif                              /*** CONFIG_SBE_PMCC4_NCOMM ***/
528 }
529
530
531 STATIC void
532 c4_watchdog (ci_t * ci)
533 {
534     if (drvr_state != SBE_DRVR_AVAILABLE)
535     {
536         if (log_level >= LOG_MONITOR)
537             pr_info("drvr not available (%x)\n", drvr_state);
538         return;
539     }
540     ci->wdcount++;
541     checkPorts (ci);
542     ci->wd_notify = 0;
543 }
544
545
546 void
547 c4_cleanup (void)
548 {
549     ci_t       *ci, *next;
550     mpi_t      *pi;
551     int         portnum, j;
552
553     ci = c4_list;
554     while (ci)
555     {
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++)
559         {
560             pi = &ci->port[portnum];
561             c4_wq_port_cleanup (pi);
562             for (j = 0; j < MUSYCC_NCHANS; j++)
563             {
564                 if (pi->chan[j])
565                     OS_kfree (pi->chan[j]);     /* free mch_t struct */
566             }
567             OS_kfree (pi->regram_saved);
568         }
569         OS_kfree (ci->iqd_p_saved);
570         OS_kfree (ci);
571         ci = next;                  /* cleanup next board, if any */
572     }
573 }
574
575
576 /*
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.
582  */
583
584 int
585 c4_get_portcfg (ci_t * ci)
586 {
587     comet_t    *comet;
588     int         portnum, mask;
589     u_int32_t   wdata, rdata;
590
591     wdata = COMET_MDIAG_LBOFF;      /* take port out of any loopback mode */
592
593     mask = 0;
594     for (portnum = 0; portnum < MUSYCC_NPORTS; portnum++)
595     {
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;
599         if (wdata == rdata)
600             mask |= 1 << portnum;
601     }
602     return mask;
603 }
604
605
606 /* nothing herein should generate interrupts */
607
608 status_t    __init
609 c4_init (ci_t * ci, u_char *func0, u_char *func1)
610 {
611     mpi_t      *pi;
612     mch_t      *ch;
613     static u_int32_t count = 0;
614     int         portnum, j;
615
616     ci->state = C_INIT;
617     ci->brdno = count++;
618     ci->intlog.this_status_new = 0;
619     atomic_set (&ci->bh_pending, 0);
620
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));
624
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);
629 #else
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);
632 #endif
633
634     {
635         int         pmsk;
636
637         /* need comet addresses available for determination of hardware build */
638         for (portnum = 0; portnum < MUSYCC_NPORTS; portnum++)
639         {
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;
645             pi->openchans = 0;
646 #ifdef SBE_MAP_DEBUG
647             pr_info("Comet-%d: addr = %p\n", portnum, pi->cometbase);
648 #endif
649         }
650         pmsk = c4_get_portcfg (ci);
651         switch (pmsk)
652         {
653         case 0x1:
654             ci->max_port = 1;
655             break;
656         case 0x3:
657             ci->max_port = 2;
658             break;
659 #if 0
660         case 0x7:                   /* not built, but could be... */
661             ci->max_port = 3;
662             break;
663 #endif
664         case 0xf:
665             ci->max_port = 4;
666             break;
667         default:
668             ci->max_port = 0;
669             pr_warning("%s: illegal port configuration (%x)\n",
670                        ci->devname, pmsk);
671             return SBE_DRVR_FAIL;
672         }
673 #ifdef SBE_MAP_DEBUG
674         pr_info(">> %s: c4_get_build - pmsk %x max_port %x\n",
675                 ci->devname, pmsk, ci->max_port);
676 #endif
677     }
678
679     for (portnum = 0; portnum < ci->max_port; portnum++)
680     {
681         pi = &ci->port[portnum];
682         pi->up = ci;
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 */
686
687         OS_sem_init (&pi->sr_sem_busy, SEM_AVAILABLE);
688         OS_sem_init (&pi->sr_sem_wait, SEM_TAKEN);
689
690         for (j = 0; j < 32; j++)
691         {
692             pi->fifomap[j] = -1;
693             pi->tsm[j] = 0;         /* no assignments, all available */
694         }
695
696         /* allocate channel structures for this port */
697         for (j = 0; j < MUSYCC_NCHANS; j++)
698         {
699             ch = OS_kmalloc (sizeof (mch_t));
700             if (ch)
701             {
702                 pi->chan[j] = ch;
703                 ch->state = UNASSIGNED;
704                 ch->up = pi;
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 */
711             } else
712             {
713                 pr_warning("failed mch_t malloc, port %d channel %d size %u.\n",
714                            portnum, j, (unsigned int) sizeof (mch_t));
715                 break;
716             }
717         }
718     }
719
720
721     {
722         /*
723          * Set LEDs through their paces to supply visual proof that LEDs are
724          * functional and not burnt out nor broken.
725          *
726          * YELLOW + GREEN -> OFF.
727          */
728
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);
733     }
734
735     OS_init_watchdog (&ci->wd, (void (*) (void *)) c4_watchdog, ci, WATCHDOG_TIMEOUT);
736     return SBE_DRVR_SUCCESS;
737 }
738
739
740 /* better be fully setup to handle interrupts when you call this */
741
742 status_t    __init
743 c4_init2 (ci_t * ci)
744 {
745     status_t    ret;
746
747     /* PORT POINT: this routine generates first interrupt */
748     if ((ret = musycc_init (ci)) != SBE_DRVR_SUCCESS)
749         return ret;
750
751 #if 0
752     ci->p.framing_type = FRAMING_CBP;
753     ci->p.h110enable = 1;
754 #if 0
755     ci->p.hypersize = 0;
756 #else
757     hyperdummy = 0;
758 #endif
759     ci->p.clock = 0;                /* Use internal clocking until set to
760                                      * external */
761     c4_card_set_params (ci, &ci->p);
762 #endif
763     OS_start_watchdog (&ci->wd);
764     return SBE_DRVR_SUCCESS;
765 }
766
767
768 /* This function sets the loopback mode (or clears it, as the case may be). */
769
770 int
771 c4_loop_port (ci_t * ci, int portnum, u_int8_t cmd)
772 {
773     comet_t    *comet;
774     volatile u_int32_t loopValue;
775
776     comet = ci->port[portnum].cometbase;
777     loopValue = pci_read_32 ((u_int32_t *) &comet->mdiag) & COMET_MDIAG_LBMASK;
778
779     if (cmd & COMET_LBCMD_READ)
780         return loopValue;           /* return the read value */
781
782     if (loopValue != cmd)
783     {
784         switch (cmd)
785         {
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);
789             break;
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);
793             break;
794         }
795
796         pci_write_32 ((u_int32_t *) &comet->mdiag, cmd);
797         if (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)
802         {
803             if (log_level >= LOG_ERROR)
804                 pr_info("%s: write to loop register failed, unknown state for Port %d\n",
805                         ci->devname, portnum);
806         }
807     } else
808     {
809         if (log_level >= LOG_WARN)
810             pr_info("%s: loopback already in that mode (%2x)\n",
811                     ci->devname, loopValue);
812     }
813     return 0;
814 }
815
816
817 /* c4_frame_rw: read or write the comet register specified
818  * (modifies use of port_param to non-standard use of struct)
819  * Specifically:
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
824  * BTW:
825  *   pp.portStatus  also used to return read value
826  *   pp.portP       also used during write, to return old reg value
827  */
828
829 status_t
830 c4_frame_rw (ci_t * ci, struct sbecom_port_param * pp)
831 {
832     comet_t    *comet;
833     volatile u_int32_t data;
834
835     if (pp->portnum >= ci->max_port)/* sanity check */
836         return ENXIO;
837
838     comet = ci->port[pp->portnum].cometbase;
839     data = pci_read_32 ((u_int32_t *) comet + pp->port_mode) & 0xff;
840
841     if (pp->portP)
842     {                               /* control says this is a register
843                                      * _write_ */
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,
849                       pp->portStatus);
850         data = pci_read_32 ((u_int32_t *) comet + pp->port_mode) & 0xff;
851     }
852     pp->portStatus = (u_int8_t) data;
853     return 0;
854 }
855
856
857 /* c4_pld_rw: read or write the pld register specified
858  * (modifies use of port_param to non-standard use of struct)
859  * Specifically:
860  *   pp.port_mode   offset of register
861  *   pp.portP       write (or not, i.e. read)
862  *   pp.portStatus  write value
863  * BTW:
864  *   pp.portStatus  also used to return read value
865  *   pp.portP       also used during write, to return old reg value
866  */
867
868 status_t
869 c4_pld_rw (ci_t * ci, struct sbecom_port_param * pp)
870 {
871     volatile u_int32_t *regaddr;
872     volatile u_int32_t data;
873     int         regnum = pp->port_mode;
874
875     regaddr = (u_int32_t *) ci->cpldbase + regnum;
876     data = pci_read_32 ((u_int32_t *) regaddr) & 0xff;
877
878     if (pp->portP)
879     {                               /* control says this is a register
880                                      * _write_ */
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;
884     }
885     pp->portStatus = (u_int8_t) data;
886     return 0;
887 }
888
889 /* c4_musycc_rw: read or write the musycc register specified
890  * (modifies use of port_param to non-standard use of struct)
891  * Specifically:
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
895  */
896
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.)
904  */
905
906 status_t
907 c4_musycc_rw (ci_t * ci, struct c4_musycc_param * mcp)
908 {
909     mpi_t      *pi;
910     volatile u_int32_t *dph;    /* hardware implemented register */
911     u_int32_t  *dpr = 0;        /* RAM image of registers for group command
912                                  * usage */
913     int         offset = mcp->offset % 0x800;   /* group relative address
914                                                  * offset, mcp->portnum is
915                                                  * not used */
916     int         portnum, ramread = 0;
917     volatile u_int32_t data;
918
919     /*
920      * Sanity check hardware accessibility.  The 0x6000 portion handles port
921      * numbers associated with Msg Descr Tbl decoding.
922      */
923     portnum = (mcp->offset % 0x6000) / 0x800;
924     if (portnum >= ci->max_port)
925         return ENXIO;
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);
930
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
934                                      * RAM access */
935     {
936         if (offset >= 0x200 && offset < 0x380)
937             ramread = 1;
938         if (offset >= 0x10 && offset < 0x200)
939             ramread = 1;
940     }
941     /* read register from RAM or hardware, depending... */
942     if (ramread)
943     {
944         data = *dpr;
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 */
946     } else
947     {
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 */
950     }
951
952
953     if (mcp->RWportnum & 0x80)
954     {                               /* control says this is a register
955                                      * _write_ */
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 */
960         if (ramread)
961             *dpr = mcp->value;
962         /* write hardware register */
963         pci_write_32 ((u_int32_t *) dph, mcp->value);
964     }
965     mcp->value = data;              /* return the read value (or the 'old
966                                      * value', if is write) */
967     return 0;
968 }
969
970 status_t
971 c4_get_port (ci_t * ci, int portnum)
972 {
973     if (portnum >= ci->max_port)    /* sanity check */
974         return ENXIO;
975
976     SD_SEM_TAKE (&ci->sem_wdbusy, "_wd_");      /* only 1 thru here, per
977                                                  * board */
978     checkPorts (ci);
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 */
982     return 0;
983 }
984
985 status_t
986 c4_set_port (ci_t * ci, int portnum)
987 {
988     mpi_t      *pi;
989     struct sbecom_port_param *pp;
990     int         e1mode;
991     u_int8_t    clck;
992     int         i;
993
994     if (portnum >= ci->max_port)    /* sanity check */
995         return ENXIO;
996
997     pi = &ci->port[portnum];
998     pp = &ci->port[portnum].p;
999     e1mode = IS_FRAME_ANY_E1 (pp->port_mode);
1000     if (log_level >= LOG_MONITOR2)
1001     {
1002         pr_info("%s: c4_set_port[%d]:  entered, e1mode = %x, openchans %d.\n",
1003                 ci->devname,
1004                 portnum, e1mode, pi->openchans);
1005     }
1006     if (pi->openchans)
1007         return EBUSY;               /* group needs initialization only for
1008                                      * first channel of a group */
1009
1010     {
1011         status_t    ret;
1012
1013         if ((ret = c4_wq_port_init (pi)))       /* create/init
1014                                                  * workqueue_struct */
1015             return (ret);
1016     }
1017
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;
1020     if (e1mode)
1021         clck |= 1 << portnum;
1022     else
1023         clck &= 0xf ^ (1 << portnum);
1024
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));
1028
1029     /*********************************************************************/
1030     /* ERRATA: If transparent mode is used, do not set OOFMP_DISABLE bit */
1031     /*********************************************************************/
1032
1033     pi->regram->grcd =
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,
1038                                                          * for T1 * fix */
1039                                 MUSYCC_GRCD_COFAIRQ_DISABLE |
1040                                 MUSYCC_GRCD_MC_ENABLE |
1041                        (MUSYCC_GRCD_POLLTH_32 << MUSYCC_GRCD_POLLTH_SHIFT));
1042
1043     pi->regram->pcd =
1044         __constant_cpu_to_le32 ((e1mode ? 1 : 0) |
1045                                 MUSYCC_PCD_TXSYNC_RISING |
1046                                 MUSYCC_PCD_RXSYNC_RISING |
1047                                 MUSYCC_PCD_RXDATA_RISING);
1048
1049     /* Message length descriptor */
1050        pi->regram->mld = __constant_cpu_to_le32 (cxt1e1_max_mru | (cxt1e1_max_mru << 16));
1051
1052     /* tsm algorithm */
1053     for (i = 0; i < 32; i++)
1054     {
1055
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.     ***/
1060
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)))
1064         {
1065             pi->tsm[i] = 0xff;      /* make tslot unavailable for this mode */
1066         } else
1067         {
1068             pi->tsm[i] = 0x00;      /* make tslot available for assignment */
1069         }
1070     }
1071     for (i = 0; i < MUSYCC_NCHANS; i++)
1072     {
1073         pi->regram->ttsm[i] = 0;
1074         pi->regram->rtsm[i] = 0;
1075     }
1076     FLUSH_MEM_WRITE ();
1077     musycc_serv_req (pi, SR_GROUP_INIT | SR_RX_DIRECTION);
1078     musycc_serv_req (pi, SR_GROUP_INIT | SR_TX_DIRECTION);
1079
1080     musycc_init_mdt (pi);
1081
1082     pi->group_is_set = 1;
1083     pi->p = *pp;
1084     return 0;
1085 }
1086
1087
1088 unsigned int max_int = 0;
1089
1090 status_t
1091 c4_new_chan (ci_t * ci, int portnum, int channum, void *user)
1092 {
1093     mpi_t      *pi;
1094     mch_t      *ch;
1095     int         gchan;
1096
1097     if (c4_find_chan (channum))     /* a new channel shouldn't already exist */
1098         return EEXIST;
1099
1100     if (portnum >= ci->max_port)    /* sanity check */
1101         return ENXIO;
1102
1103     pi = &(ci->port[portnum]);
1104     /* find any available channel within this port */
1105     for (gchan = 0; gchan < MUSYCC_NCHANS; gchan++)
1106     {
1107         ch = pi->chan[gchan];
1108         if (ch && ch->state == UNASSIGNED)      /* no assignment is good! */
1109             break;
1110     }
1111     if (gchan == MUSYCC_NCHANS)     /* exhausted table, all were assigned */
1112         return ENFILE;
1113
1114     ch->up = pi;
1115
1116     /* NOTE: mch_t already cleared during OS_kmalloc() */
1117     ch->state = DOWN;
1118     ch->user = user;
1119     ch->gchan = gchan;
1120     ch->channum = channum;          /* mark our channel assignment */
1121     ch->p.channum = channum;
1122 #if 1
1123     ch->p.card = ci->brdno;
1124     ch->p.port = portnum;
1125 #endif
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);
1131
1132     {
1133         status_t    ret;
1134
1135         if ((ret = c4_wk_chan_init (pi, ch)))
1136             return ret;
1137     }
1138
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 */
1142     {
1143         ci->first_if = ci->last_if = user;
1144         ci->first_channum = ci->last_channum = channum;
1145     } else
1146     {
1147         ci->last_if = user;
1148         if (ci->last_channum < channum) /* higher number channel found */
1149             ci->last_channum = channum;
1150     }
1151     return 0;
1152 }
1153
1154 status_t
1155 c4_del_chan (int channum)
1156 {
1157     mch_t      *ch;
1158
1159     if (!(ch = c4_find_chan (channum)))
1160         return ENOENT;
1161     if (ch->state == UP)
1162         musycc_chan_down ((ci_t *) 0, channum);
1163     ch->state = UNASSIGNED;
1164     ch->gchan = (-1);
1165     ch->channum = (-1);
1166     ch->p.channum = (-1);
1167     return 0;
1168 }
1169
1170 status_t
1171 c4_del_chan_stats (int channum)
1172 {
1173     mch_t      *ch;
1174
1175     if (!(ch = c4_find_chan (channum)))
1176         return ENOENT;
1177
1178     memset (&ch->s, 0, sizeof (struct sbecom_chan_stats));
1179     return 0;
1180 }
1181
1182
1183 status_t
1184 c4_set_chan (int channum, struct sbecom_chan_param * p)
1185 {
1186     mch_t      *ch;
1187     int         i, x = 0;
1188
1189     if (!(ch = c4_find_chan (channum)))
1190         return ENOENT;
1191
1192 #if 1
1193     if (ch->p.card != p->card ||
1194         ch->p.port != p->port ||
1195         ch->p.channum != p->channum)
1196         return EINVAL;
1197 #endif
1198
1199     if (!(ch->up->group_is_set))
1200     {
1201         return EIO;                 /* out of order, SET_PORT command
1202                                      * required prior to first group's
1203                                      * SET_CHAN command */
1204     }
1205     /*
1206      * Check for change of parameter settings in order to invoke closing of
1207      * channel prior to hardware poking.
1208      */
1209
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 */
1217     ch->p = *p;
1218     if (x && (ch->state == UP))     /* if change request and channel is
1219                                      * open... */
1220     {
1221         status_t    ret;
1222
1223         if ((ret = musycc_chan_down ((ci_t *) 0, channum)))
1224             return ret;
1225         if ((ret = c4_chan_up (ch->up->up, channum)))
1226             return ret;
1227         sd_enable_xmit (ch->user);  /* re-enable to catch flow controlled
1228                                      * channel */
1229     }
1230     return 0;
1231 }
1232
1233
1234 status_t
1235 c4_get_chan (int channum, struct sbecom_chan_param * p)
1236 {
1237     mch_t      *ch;
1238
1239     if (!(ch = c4_find_chan (channum)))
1240         return ENOENT;
1241     *p = ch->p;
1242     return 0;
1243 }
1244
1245 status_t
1246 c4_get_chan_stats (int channum, struct sbecom_chan_stats * p)
1247 {
1248     mch_t      *ch;
1249
1250     if (!(ch = c4_find_chan (channum)))
1251         return ENOENT;
1252     *p = ch->s;
1253     p->tx_pending = atomic_read (&ch->tx_pending);
1254     return 0;
1255 }
1256
1257 STATIC int
1258 c4_fifo_alloc (mpi_t * pi, int chan, int *len)
1259 {
1260     int         i, l = 0, start = 0, max = 0, maxstart = 0;
1261
1262     for (i = 0; i < 32; i++)
1263     {
1264         if (pi->fifomap[i] != -1)
1265         {
1266             l = 0;
1267             start = i + 1;
1268             continue;
1269         }
1270         ++l;
1271         if (l > max)
1272         {
1273             max = l;
1274             maxstart = start;
1275         }
1276         if (max == *len)
1277             break;
1278     }
1279     if (max != *len)
1280     {
1281         if (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);
1284         *len = max;
1285     }
1286     if (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;
1291     return start;
1292 }
1293
1294 void
1295 c4_fifo_free (mpi_t * pi, int chan)
1296 {
1297     int         i;
1298
1299     if (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;
1305 }
1306
1307
1308 status_t
1309 c4_chan_up (ci_t * ci, int channum)
1310 {
1311     mpi_t      *pi;
1312     mch_t      *ch;
1313     struct mbuf *m;
1314     struct mdesc *md;
1315     int         nts, nbuf, txnum, rxnum;
1316     int         addr, i, j, gchan;
1317     u_int32_t   tmp;            /* for optimizing conversion across BE
1318                                  * platform */
1319
1320     if (!(ch = c4_find_chan (channum)))
1321         return ENOENT;
1322     if (ch->state == UP)
1323     {
1324         if (log_level >= LOG_MONITOR)
1325             pr_info("%s: channel already UP, graceful early exit\n",
1326                     ci->devname);
1327         return 0;
1328     }
1329     pi = ch->up;
1330     gchan = ch->gchan;
1331     /* find nts ('number of timeslots') */
1332     nts = 0;
1333     for (i = 0; i < 32; i++)
1334     {
1335         if (ch->p.bitmask[i] & pi->tsm[i])
1336         {
1337             if (1 || log_level >= LOG_WARN)
1338             {
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]);
1343             }
1344             return EINVAL;
1345         }
1346         for (j = 0; j < 8; j++)
1347             if (ch->p.bitmask[i] & (1 << j))
1348                 nts++;
1349     }
1350
1351     nbuf = nts / 8 ? nts / 8 : 1;
1352     if (!nbuf)
1353     {
1354         /* if( 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 */
1358     }
1359     addr = c4_fifo_alloc (pi, gchan, &nbuf);
1360     ch->state = UP;
1361
1362     /* Setup the Time Slot Map */
1363     musycc_update_timeslots (pi);
1364
1365     /* ch->tx_limit = nts; */
1366     ch->s.tx_pending = 0;
1367
1368     /* Set Channel Configuration Descriptors */
1369     {
1370         u_int32_t   ccd;
1371
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))
1375         {
1376             ccd |= MUSYCC_CCD_FCS_XFER; /* Non FSC Mode */
1377         }
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;
1383         else
1384             ccd |= (nbuf - 1) << MUSYCC_CCD_BUFFER_LENGTH;
1385
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);
1389
1390         if (ch->p.data_inv & CFG_CH_DINV_RX)
1391             ccd |= MUSYCC_CCD_INVERT_DATA;      /* Invert data */
1392         else
1393             ccd &= ~MUSYCC_CCD_INVERT_DATA;     /* take away data inversion */
1394         pi->regram->rcct[gchan] = cpu_to_le32 (ccd);
1395         FLUSH_MEM_WRITE ();
1396     }
1397
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);
1401
1402     /*
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.
1406      */
1407     if (ch->p.chan_mode == CFG_CH_PROTO_TRANS)
1408     {
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;
1413     }
1414     /*
1415      * Increase counts when hyperchanneling, since this implies an increase
1416      * in throughput per channel
1417      */
1418     rxnum = max_rxdesc_used + (nts / 4);
1419     txnum = max_txdesc_used + (nts / 4);
1420
1421 #if 0
1422     /* DEBUG INFO */
1423     if (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);
1428 #endif
1429
1430     ch->rxd_num = rxnum;
1431     ch->txd_num = txnum;
1432     ch->rxix_irq_srv = 0;
1433
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);
1438     else
1439                tmp = __constant_cpu_to_le32 (cxt1e1_max_mru);
1440
1441     for (i = 0, md = ch->mdr; i < rxnum; i++, md++)
1442     {
1443         if (i == (rxnum - 1))
1444         {
1445             md->snext = &ch->mdr[0];/* wrapness */
1446         } else
1447         {
1448             md->snext = &ch->mdr[i + 1];
1449         }
1450         md->next = cpu_to_le32 (OS_vtophys (md->snext));
1451
1452                if (!(m = OS_mem_token_alloc (cxt1e1_max_mru)))
1453         {
1454             if (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);
1457             goto errfree;
1458         }
1459         md->mem_token = m;
1460         md->data = cpu_to_le32 (OS_vtophys (OS_mem_token_data (m)));
1461         md->status = tmp | MUSYCC_RX_OWNED;     /* MUSYCC owns RX descriptor **
1462                                                  * CODING NOTE:
1463                                                  * MUSYCC_RX_OWNED = 0 so no
1464                                                  * need to byteSwap */
1465     }
1466
1467     for (i = 0, md = ch->mdt; i < txnum; i++, md++)
1468     {
1469         md->status = HOST_TX_OWNED; /* Host owns TX descriptor ** CODING
1470                                      * NOTE: HOST_TX_OWNED = 0 so no need to
1471                                      * byteSwap */
1472         md->mem_token = 0;
1473         md->data = 0;
1474         if (i == (txnum - 1))
1475         {
1476             md->snext = &ch->mdt[0];/* wrapness */
1477         } else
1478         {
1479             md->snext = &ch->mdt[i + 1];
1480         }
1481         md->next = cpu_to_le32 (OS_vtophys (md->snext));
1482     }
1483     ch->txd_irq_srv = ch->txd_usr_add = &ch->mdt[0];
1484     ch->txd_free = txnum;
1485     ch->tx_full = 0;
1486     ch->txd_required = 0;
1487
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;
1492
1493     tmp = cpu_to_le32 (OS_vtophys (&ch->mdr[0]));
1494     pi->regram->rhp[gchan] = tmp;
1495     pi->regram->rmp[gchan] = tmp;
1496
1497     /* Activate the Channel */
1498     FLUSH_MEM_WRITE ();
1499     if (ch->p.status & RX_ENABLED)
1500     {
1501 #ifdef RLD_TRANS_DEBUG
1502         pr_info("++ c4_chan_up() CHAN RX ACTIVATE: chan %d\n", ch->channum);
1503 #endif
1504         ch->ch_start_rx = 0;        /* we are restarting RX... */
1505         musycc_serv_req (pi, SR_CHANNEL_ACTIVATE | SR_RX_DIRECTION | gchan);
1506     }
1507     if (ch->p.status & TX_ENABLED)
1508     {
1509 #ifdef RLD_TRANS_DEBUG
1510         pr_info("++ c4_chan_up() CHAN TX ACTIVATE: chan %d <delayed>\n", ch->channum);
1511 #endif
1512         ch->ch_start_tx = CH_START_TX_1ST;      /* we are delaying start
1513                                                  * until receipt from user of
1514                                                  * first packet to transmit. */
1515     }
1516     ch->status = ch->p.status;
1517     pi->openchans++;
1518     return 0;
1519
1520 errfree:
1521     while (i > 0)
1522     {
1523         /* Don't leak all the previously allocated mbufs in this loop */
1524         i--;
1525         OS_mem_token_free (ch->mdr[i].mem_token);
1526     }
1527     OS_kfree (ch->mdt);
1528     ch->mdt = 0;
1529     ch->txd_num = 0;
1530     OS_kfree (ch->mdr);
1531     ch->mdr = 0;
1532     ch->rxd_num = 0;
1533     ch->state = DOWN;
1534     return ENOBUFS;
1535 }
1536
1537 /* stop the hardware from servicing & interrupting */
1538
1539 void
1540 c4_stopwd (ci_t * ci)
1541 {
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);
1545 }
1546
1547
1548 void
1549 sbecom_get_brdinfo (ci_t * ci, struct sbe_brd_info * bip, u_int8_t *bsn)
1550 {
1551     char       *np;
1552     u_int32_t   sn = 0;
1553     int         i;
1554
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
1559                                                          * being used */
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
1562                                                  * determinable */
1563
1564     if (ci->first_if)
1565     {
1566         {
1567             struct net_device *dev;
1568
1569             dev = (struct net_device *) ci->first_if;
1570             np = (char *) dev->name;
1571         }
1572         strncpy (bip->first_iname, np, CHNM_STRLEN - 1);
1573     } else
1574         strcpy (bip->first_iname, "<NULL>");
1575     if (ci->last_if)
1576     {
1577         {
1578             struct net_device *dev;
1579
1580             dev = (struct net_device *) ci->last_if;
1581             np = (char *) dev->name;
1582         }
1583         strncpy (bip->last_iname, np, CHNM_STRLEN - 1);
1584     } else
1585         strcpy (bip->last_iname, "<NULL>");
1586
1587     if (bsn)
1588     {
1589         for (i = 0; i < 3; i++)
1590         {
1591             bip->brd_mac_addr[i] = *bsn++;
1592         }
1593         for (; i < 6; i++)
1594         {
1595             bip->brd_mac_addr[i] = *bsn;
1596             sn = (sn << 8) | *bsn++;
1597         }
1598     } else
1599     {
1600         for (i = 0; i < 6; i++)
1601             bip->brd_mac_addr[i] = 0;
1602     }
1603     bip->brd_sn = sn;
1604 }
1605
1606
1607 status_t
1608 c4_get_iidinfo (ci_t * ci, struct sbe_iid_info * iip)
1609 {
1610     struct net_device *dev;
1611     char       *np;
1612
1613     if (!(dev = getuserbychan (iip->channum)))
1614         return ENOENT;
1615
1616     np = dev->name;
1617     strncpy (iip->iname, np, CHNM_STRLEN - 1);
1618     return 0;
1619 }
1620
1621
1622 #ifdef CONFIG_SBE_PMCC4_NCOMM
1623 void        (*nciInterrupt[MAX_BOARDS][4]) (void);
1624 extern void wanpmcC4T1E1_hookInterrupt (int cardID, int deviceID, void *handler);
1625
1626 void
1627 wanpmcC4T1E1_hookInterrupt (int cardID, int deviceID, void *handler)
1628 {
1629     if (cardID < MAX_BOARDS)    /* sanity check */
1630         nciInterrupt[cardID][deviceID] = handler;
1631 }
1632
1633 irqreturn_t
1634 c4_ebus_intr_th_handler (void *devp)
1635 {
1636     ci_t       *ci = (ci_t *) devp;
1637     volatile u_int32_t ists;
1638     int         handled = 0;
1639     int         brdno;
1640
1641     /* which COMET caused the interrupt */
1642     brdno = ci->brdno;
1643     ists = pci_read_32 ((u_int32_t *) &ci->cpldbase->intr);
1644     if (ists & PMCC4_CPLD_INTR_CMT_1)
1645     {
1646         handled = 0x1;
1647         if (nciInterrupt[brdno][0] != NULL)
1648             (*nciInterrupt[brdno][0]) ();
1649     }
1650     if (ists & PMCC4_CPLD_INTR_CMT_2)
1651     {
1652         handled |= 0x2;
1653         if (nciInterrupt[brdno][1] != NULL)
1654             (*nciInterrupt[brdno][1]) ();
1655     }
1656     if (ists & PMCC4_CPLD_INTR_CMT_3)
1657     {
1658         handled |= 0x4;
1659         if (nciInterrupt[brdno][2] != NULL)
1660             (*nciInterrupt[brdno][2]) ();
1661     }
1662     if (ists & PMCC4_CPLD_INTR_CMT_4)
1663     {
1664         handled |= 0x8;
1665         if (nciInterrupt[brdno][3] != NULL)
1666             (*nciInterrupt[brdno][3]) ();
1667     }
1668 #if 0
1669     /*** Test code just de-implements the asserted interrupt.  Alternate
1670     vendor will supply COMET interrupt handling code herein or such.
1671     ***/
1672     pci_write_32 ((u_int32_t *) &ci->reg->glcd, GCD_MAGIC | MUSYCC_GCD_INTB_DISABLE);
1673 #endif
1674
1675     return IRQ_RETVAL (handled);
1676 }
1677
1678
1679 unsigned long
1680 wanpmcC4T1E1_getBaseAddress (int cardID, int deviceID)
1681 {
1682     ci_t       *ci;
1683     unsigned long base = 0;
1684
1685     ci = c4_list;
1686     while (ci)
1687     {
1688         if (ci->brdno == cardID)    /* found valid device */
1689         {
1690             if (deviceID < ci->max_port)        /* comet is supported */
1691                 base = ((unsigned long) ci->port[deviceID].cometbase);
1692             break;
1693         }
1694         ci = ci->next;              /* next board, if any */
1695     }
1696     return (base);
1697 }
1698
1699 #endif                          /*** CONFIG_SBE_PMCC4_NCOMM ***/
1700
1701
1702 /***  End-of-File  ***/