1 /*-----------------------------------------------------------------------------
4 * Copyright (C) 2007 One Stop Systems, Inc.
5 * Copyright (C) 2002-2006 SBE, Inc.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * For further information, contact via email: support@onestopsystems.com
18 * One Stop Systems, Inc. Escondido, California U.S.A.
19 *-----------------------------------------------------------------------------
22 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
24 #include <linux/types.h>
25 #include "pmcc4_sysdep.h"
26 #include <linux/errno.h>
27 #include <linux/kernel.h>
28 #include <linux/sched.h> /* include for timer */
29 #include <linux/timer.h> /* include for timer */
30 #include <linux/hdlc.h>
33 #include "sbecom_inline_linux.h"
35 #include "pmcc4_private.h"
37 #include "pmcc4_ioctls.h"
42 #ifdef SBE_INCLUDE_SYMBOLS
49 #define KERN_WARN KERN_WARNING
51 /* forward references */
52 status_t
c4_wk_chan_init (mpi_t
*, mch_t
*);
53 void c4_wq_port_cleanup (mpi_t
*);
54 status_t
c4_wq_port_init (mpi_t
*);
56 int c4_loop_port (ci_t
*, int, u_int8_t
);
57 status_t
c4_set_port (ci_t
*, int);
58 status_t
musycc_chan_down (ci_t
*, int);
60 u_int32_t
musycc_chan_proto (int);
61 status_t
musycc_dump_ring (ci_t
*, unsigned int);
62 status_t __init
musycc_init (ci_t
*);
63 void musycc_init_mdt (mpi_t
*);
64 void musycc_serv_req (mpi_t
*, u_int32_t
);
65 void musycc_update_timeslots (mpi_t
*);
67 extern void musycc_update_tx_thp (mch_t
*);
68 extern int cxt1e1_log_level
;
69 extern int cxt1e1_max_mru
;
70 extern int cxt1e1_max_mtu
;
71 extern int max_rxdesc_used
, max_rxdesc_default
;
72 extern int max_txdesc_used
, max_txdesc_default
;
74 #if defined (__powerpc__)
75 extern void *memset (void *s
, int c
, size_t n
);
79 int drvr_state
= SBE_DRVR_INIT
;
81 ci_t
*CI
; /* dummy pointer to board ZEROE's data -
86 sbecom_set_loglevel (int d
)
89 * The code within the following -if- clause is a backdoor debug facility
90 * which can be used to display the state of a board's channel.
94 unsigned int channum
= d
- (LOG_DEBUG
+ 1); /* convert to ZERO
97 (void) musycc_dump_ring ((ci_t
*) CI
, channum
); /* CI implies support
101 if (cxt1e1_log_level
!= d
)
103 pr_info("log level changed from %d to %d\n", cxt1e1_log_level
, d
);
104 cxt1e1_log_level
= d
; /* set new */
106 pr_info("log level is %d\n", cxt1e1_log_level
);
112 c4_find_chan (int channum
)
118 for (ci
= c4_list
; ci
; ci
= ci
->next
)
119 for (portnum
= 0; portnum
< ci
->max_port
; portnum
++)
120 for (gchan
= 0; gchan
< MUSYCC_NCHANS
; gchan
++)
122 if ((ch
= ci
->port
[portnum
].chan
[gchan
]))
124 if ((ch
->state
!= UNASSIGNED
) &&
125 (ch
->channum
== channum
))
139 pr_warning("c4_new() entered, ci needs %u.\n",
140 (unsigned int) sizeof (ci_t
));
143 ci
= (ci_t
*) OS_kmalloc (sizeof (ci_t
));
147 ci
->state
= C_INIT
; /* mark as hardware not available */
150 ci
->brdno
= ci
->next
? ci
->next
->brdno
+ 1 : 0;
152 pr_warning("failed CI malloc, size %u.\n",
153 (unsigned int) sizeof (ci_t
));
156 CI
= ci
; /* DEBUG, only board 0 usage */
162 * Check port state and set LED states using watchdog or ioctl...
163 * also check for in-band SF loopback commands (& cause results if they are there)
165 * Alarm function depends on comet bits indicating change in
166 * link status (linkMask) to keep the link status indication straight.
168 * Indications are only LED and system log -- except when ioctl is invoked.
170 * "alarmed" record (a.k.a. copyVal, in some cases below) decodes as:
172 * RMAI (E1 only) 0x100
175 * link returned 0x20 (link was down, now it's back and 'port get' hasn't run)
176 * change in LED 0x10 (update LED register because value has changed)
182 * note "link has returned" indication is reset on read
183 * (e.g. by use of the c4_control port get command)
186 #define sbeLinkMask 0x41 /* change in signal status (lost/recovered) +
188 #define sbeLinkChange 0x40
189 #define sbeLinkDown 0x01
190 #define sbeAlarmsMask 0x07 /* red / yellow / blue alarm conditions */
191 #define sbeE1AlarmsMask 0x107 /* alarm conditions */
193 #define COMET_LBCMD_READ 0x80 /* read only (do not set, return read value) */
196 checkPorts (ci_t
* ci
)
198 #ifndef CONFIG_SBE_PMCC4_NCOMM
200 * PORT POINT - NCOMM needs to avoid this code since the polling of
201 * alarms conflicts with NCOMM's interrupt servicing implementation.
205 volatile u_int32_t value
;
206 u_int32_t copyVal
, LEDval
;
211 for (portnum
= 0; portnum
< ci
->max_port
; portnum
++)
213 copyVal
= 0x12f & (ci
->alarmed
[portnum
]); /* port's alarm record */
214 comet
= ci
->port
[portnum
].cometbase
;
215 value
= pci_read_32 ((u_int32_t
*) &comet
->cdrc_ists
) & sbeLinkMask
; /* link loss reg */
217 if (value
& sbeLinkChange
) /* is there a change in the link stuff */
219 /* if there's been a change (above) and yet it's the same (below) */
220 if (!(((copyVal
>> 3) & sbeLinkDown
) ^ (value
& sbeLinkDown
)))
222 if (value
& sbeLinkDown
)
223 pr_warning("%s: Port %d momentarily recovered.\n",
224 ci
->devname
, portnum
);
226 pr_warning("%s: Warning: Port %d link was briefly down.\n",
227 ci
->devname
, portnum
);
228 } else if (value
& sbeLinkDown
)
229 pr_warning("%s: Warning: Port %d link is down.\n",
230 ci
->devname
, portnum
);
233 pr_warning("%s: Port %d link has recovered.\n",
234 ci
->devname
, portnum
);
235 copyVal
|= 0x20; /* record link transition to up */
237 copyVal
|= 0x10; /* change (link) --> update LEDs */
239 copyVal
&= 0x137; /* clear LED & link old history bits &
241 if (value
& sbeLinkDown
)
242 copyVal
|= 0x08; /* record link status (now) */
244 { /* if link is up, do this */
245 copyVal
|= 0x40; /* LED indicate link is up */
246 /* Alarm things & the like ... first if E1, then if T1 */
247 if (IS_FRAME_ANY_E1 (ci
->port
[portnum
].p
.port_mode
))
250 * first check Codeword (SaX) changes & CRC and
251 * sub-multi-frame errors
254 * note these errors are printed every time they are detected
257 value
= pci_read_32 ((u_int32_t
*) &comet
->e1_frmr_nat_ists
); /* codeword */
259 { /* if errors (crc or smf only) */
261 pr_warning("%s: E1 Port %d Codeword Sa4 change detected.\n",
262 ci
->devname
, portnum
);
264 pr_warning("%s: E1 Port %d Codeword Sa5 change detected.\n",
265 ci
->devname
, portnum
);
267 pr_warning("%s: E1 Port %d Codeword Sa6 change detected.\n",
268 ci
->devname
, portnum
);
270 pr_warning("%s: E1 Port %d Codeword Sa7 change detected.\n",
271 ci
->devname
, portnum
);
273 pr_warning("%s: E1 Port %d Codeword Sa8 change detected.\n",
274 ci
->devname
, portnum
);
276 value
= pci_read_32 ((u_int32_t
*) &comet
->e1_frmr_mists
); /* crc & smf */
278 { /* if errors (crc or smf only) */
279 if (value
& sbeE1CRC
)
280 pr_warning("%s: E1 Port %d CRC-4 error(s) detected.\n",
281 ci
->devname
, portnum
);
282 if (value
& sbeE1errSMF
) /* error in sub-multiframe */
283 pr_warning("%s: E1 Port %d received errored SMF.\n",
284 ci
->devname
, portnum
);
286 value
= pci_read_32 ((u_int32_t
*) &comet
->e1_frmr_masts
) & 0xcc; /* alarms */
288 * pack alarms together (bitmiser), and construct similar to
291 /* RAI,RMAI,.,.,LOF,AIS,.,. ==> RMAI,.,.,.,.,.,RAI,LOF,AIS */
293 value
= (value
>> 2);
297 value
|= 0x40; /* RAI */
299 value
|= 0x100; /* RMAI */
301 } /* finished packing alarm in handy order */
302 if (value
!= (copyVal
& sbeE1AlarmsMask
))
303 { /* if alarms changed */
304 copyVal
|= 0x10;/* change LED status */
305 if ((copyVal
& sbeRedAlm
) && !(value
& sbeRedAlm
))
307 copyVal
&= ~sbeRedAlm
;
308 pr_warning("%s: E1 Port %d LOF alarm ended.\n",
309 ci
->devname
, portnum
);
310 } else if (!(copyVal
& sbeRedAlm
) && (value
& sbeRedAlm
))
312 copyVal
|= sbeRedAlm
;
313 pr_warning("%s: E1 Warning: Port %d LOF alarm.\n",
314 ci
->devname
, portnum
);
315 } else if ((copyVal
& sbeYelAlm
) && !(value
& sbeYelAlm
))
317 copyVal
&= ~sbeYelAlm
;
318 pr_warning("%s: E1 Port %d RAI alarm ended.\n",
319 ci
->devname
, portnum
);
320 } else if (!(copyVal
& sbeYelAlm
) && (value
& sbeYelAlm
))
322 copyVal
|= sbeYelAlm
;
323 pr_warning("%s: E1 Warning: Port %d RAI alarm.\n",
324 ci
->devname
, portnum
);
325 } else if ((copyVal
& sbeE1RMAI
) && !(value
& sbeE1RMAI
))
327 copyVal
&= ~sbeE1RMAI
;
328 pr_warning("%s: E1 Port %d RMAI alarm ended.\n",
329 ci
->devname
, portnum
);
330 } else if (!(copyVal
& sbeE1RMAI
) && (value
& sbeE1RMAI
))
332 copyVal
|= sbeE1RMAI
;
333 pr_warning("%s: E1 Warning: Port %d RMAI alarm.\n",
334 ci
->devname
, portnum
);
335 } else if ((copyVal
& sbeAISAlm
) && !(value
& sbeAISAlm
))
337 copyVal
&= ~sbeAISAlm
;
338 pr_warning("%s: E1 Port %d AIS alarm ended.\n",
339 ci
->devname
, portnum
);
340 } else if (!(copyVal
& sbeAISAlm
) && (value
& sbeAISAlm
))
342 copyVal
|= sbeAISAlm
;
343 pr_warning("%s: E1 Warning: Port %d AIS alarm.\n",
344 ci
->devname
, portnum
);
347 /* end of E1 alarm code */
350 value
= pci_read_32 ((u_int32_t
*) &comet
->t1_almi_ists
); /* alarms */
351 value
&= sbeAlarmsMask
;
352 if (value
!= (copyVal
& sbeAlarmsMask
))
353 { /* if alarms changed */
354 copyVal
|= 0x10;/* change LED status */
355 if ((copyVal
& sbeRedAlm
) && !(value
& sbeRedAlm
))
357 copyVal
&= ~sbeRedAlm
;
358 pr_warning("%s: Port %d red alarm ended.\n",
359 ci
->devname
, portnum
);
360 } else if (!(copyVal
& sbeRedAlm
) && (value
& sbeRedAlm
))
362 copyVal
|= sbeRedAlm
;
363 pr_warning("%s: Warning: Port %d red alarm.\n",
364 ci
->devname
, portnum
);
365 } else if ((copyVal
& sbeYelAlm
) && !(value
& sbeYelAlm
))
367 copyVal
&= ~sbeYelAlm
;
368 pr_warning("%s: Port %d yellow (RAI) alarm ended.\n",
369 ci
->devname
, portnum
);
370 } else if (!(copyVal
& sbeYelAlm
) && (value
& sbeYelAlm
))
372 copyVal
|= sbeYelAlm
;
373 pr_warning("%s: Warning: Port %d yellow (RAI) alarm.\n",
374 ci
->devname
, portnum
);
375 } else if ((copyVal
& sbeAISAlm
) && !(value
& sbeAISAlm
))
377 copyVal
&= ~sbeAISAlm
;
378 pr_warning("%s: Port %d blue (AIS) alarm ended.\n",
379 ci
->devname
, portnum
);
380 } else if (!(copyVal
& sbeAISAlm
) && (value
& sbeAISAlm
))
382 copyVal
|= sbeAISAlm
;
383 pr_warning("%s: Warning: Port %d blue (AIS) alarm.\n",
384 ci
->devname
, portnum
);
387 } /* end T1 mode alarm checks */
389 if (copyVal
& sbeAlarmsMask
)
390 copyVal
|= 0x80; /* if alarm turn yel LED on */
392 LEDval
|= 0x100; /* tag if LED values have changed */
393 LEDval
|= ((copyVal
& 0xc0) >> (6 - (portnum
* 2)));
395 ci
->alarmed
[portnum
] &= 0xfffff000; /* out with the old (it's fff
397 ci
->alarmed
[portnum
] |= (copyVal
); /* in with the new */
400 * enough with the alarms and LED's, now let's check for loopback
404 if (IS_FRAME_ANY_T1 (ci
->port
[portnum
].p
.port_mode
))
407 * begin in-band (SF) loopback code detection -- start by reading
410 value
= pci_read_32 ((u_int32_t
*) &comet
->ibcd_ies
); /* detect reg. */
411 value
&= 0x3; /* trim to handy bits */
413 { /* activate loopback (sets for deactivate
415 copyVal
= c4_loop_port (ci
, portnum
, COMET_LBCMD_READ
); /* read line loopback
417 if (copyVal
!= COMET_MDIAG_LINELB
) /* don't do it again if
418 * already in that mode */
419 c4_loop_port (ci
, portnum
, COMET_MDIAG_LINELB
); /* put port in line
423 { /* deactivate loopback (sets for activate
425 copyVal
= c4_loop_port (ci
, portnum
, COMET_LBCMD_READ
); /* read line loopback
427 if (copyVal
!= COMET_MDIAG_LBOFF
) /* don't do it again if
428 * already in that mode */
429 c4_loop_port (ci
, portnum
, COMET_MDIAG_LBOFF
); /* take port out of any
433 if (IS_FRAME_ANY_T1ESF (ci
->port
[portnum
].p
.port_mode
))
434 { /* if a T1 ESF mode */
435 /* begin ESF loopback code */
436 value
= pci_read_32 ((u_int32_t
*) &comet
->t1_rboc_sts
) & 0x3f; /* read command */
438 c4_loop_port (ci
, portnum
, COMET_MDIAG_LINELB
); /* put port in line
441 c4_loop_port (ci
, portnum
, COMET_MDIAG_PAYLB
); /* put port in payload
443 if ((value
== 0x1c) || (value
== 0x19) || (value
== 0x12))
444 c4_loop_port (ci
, portnum
, COMET_MDIAG_LBOFF
); /* take port out of any
446 if (cxt1e1_log_level
>= LOG_DEBUG
)
448 pr_warning("%s: BOC value = %x on Port %d\n",
449 ci
->devname
, value
, portnum
);
450 /* end ESF loopback code */
454 /* if something is new, update LED's */
456 pci_write_32 ((u_int32_t
*) &ci
->cpldbase
->leds
, LEDval
& 0xff);
457 #endif /*** CONFIG_SBE_PMCC4_NCOMM ***/
462 c4_watchdog (ci_t
* ci
)
464 if (drvr_state
!= SBE_DRVR_AVAILABLE
)
466 if (cxt1e1_log_level
>= LOG_MONITOR
)
467 pr_info("drvr not available (%x)\n", drvr_state
);
486 next
= ci
->next
; /* protect <next> from upcoming <free> */
487 pci_write_32 ((u_int32_t
*) &ci
->cpldbase
->leds
, PMCC4_CPLD_LED_OFF
);
488 for (portnum
= 0; portnum
< ci
->max_port
; portnum
++)
490 pi
= &ci
->port
[portnum
];
491 c4_wq_port_cleanup (pi
);
492 for (j
= 0; j
< MUSYCC_NCHANS
; j
++)
495 OS_kfree (pi
->chan
[j
]); /* free mch_t struct */
497 OS_kfree (pi
->regram_saved
);
499 OS_kfree (ci
->iqd_p_saved
);
501 ci
= next
; /* cleanup next board, if any */
507 * This function issues a write to all comet chips and expects the same data
508 * to be returned from the subsequent read. This determines the board build
509 * to be a 1-port, 2-port, or 4-port build. The value returned represents a
510 * bit-mask of the found ports. Only certain configurations are considered
511 * VALID or LEGAL builds.
515 c4_get_portcfg (ci_t
* ci
)
519 u_int32_t wdata
, rdata
;
521 wdata
= COMET_MDIAG_LBOFF
; /* take port out of any loopback mode */
524 for (portnum
= 0; portnum
< MUSYCC_NPORTS
; portnum
++)
526 comet
= ci
->port
[portnum
].cometbase
;
527 pci_write_32 ((u_int32_t
*) &comet
->mdiag
, wdata
);
528 rdata
= pci_read_32 ((u_int32_t
*) &comet
->mdiag
) & COMET_MDIAG_LBMASK
;
530 mask
|= 1 << portnum
;
536 /* nothing herein should generate interrupts */
539 c4_init (ci_t
* ci
, u_char
*func0
, u_char
*func1
)
543 static u_int32_t count
= 0;
548 ci
->intlog
.this_status_new
= 0;
549 atomic_set (&ci
->bh_pending
, 0);
551 ci
->reg
= (struct musycc_globalr
*) func0
;
552 ci
->eeprombase
= (u_int32_t
*) (func1
+ EEPROM_OFFSET
);
553 ci
->cpldbase
= (c4cpld_t
*) ((u_int32_t
*) (func1
+ ISPLD_OFFSET
));
555 /*** PORT POINT - the following is the first access of any type to the hardware ***/
556 #ifdef CONFIG_SBE_PMCC4_NCOMM
557 /* NCOMM driver uses INTB interrupt to monitor CPLD register */
558 pci_write_32 ((u_int32_t
*) &ci
->reg
->glcd
, GCD_MAGIC
);
560 /* standard driver POLLS for INTB via CPLD register */
561 pci_write_32 ((u_int32_t
*) &ci
->reg
->glcd
, GCD_MAGIC
| MUSYCC_GCD_INTB_DISABLE
);
567 /* need comet addresses available for determination of hardware build */
568 for (portnum
= 0; portnum
< MUSYCC_NPORTS
; portnum
++)
570 pi
= &ci
->port
[portnum
];
571 pi
->cometbase
= (comet_t
*) ((u_int32_t
*) (func1
+ COMET_OFFSET (portnum
)));
572 pi
->reg
= (struct musycc_globalr
*) ((u_char
*) ci
->reg
+ (portnum
* 0x800));
573 pi
->portnum
= portnum
;
574 pi
->p
.portnum
= portnum
;
577 pr_info("Comet-%d: addr = %p\n", portnum
, pi
->cometbase
);
580 pmsk
= c4_get_portcfg (ci
);
590 case 0x7: /* not built, but could be... */
599 pr_warning("%s: illegal port configuration (%x)\n",
601 return SBE_DRVR_FAIL
;
604 pr_info(">> %s: c4_get_build - pmsk %x max_port %x\n",
605 ci
->devname
, pmsk
, ci
->max_port
);
609 for (portnum
= 0; portnum
< ci
->max_port
; portnum
++)
611 pi
= &ci
->port
[portnum
];
613 pi
->sr_last
= 0xffffffff;
614 pi
->p
.port_mode
= CFG_FRAME_SF
; /* T1 B8ZS, the default */
615 pi
->p
.portP
= (CFG_CLK_PORT_EXTERNAL
| CFG_LBO_LH0
); /* T1 defaults */
617 OS_sem_init (&pi
->sr_sem_busy
, SEM_AVAILABLE
);
618 OS_sem_init (&pi
->sr_sem_wait
, SEM_TAKEN
);
620 for (j
= 0; j
< 32; j
++)
623 pi
->tsm
[j
] = 0; /* no assignments, all available */
626 /* allocate channel structures for this port */
627 for (j
= 0; j
< MUSYCC_NCHANS
; j
++)
629 ch
= OS_kmalloc (sizeof (mch_t
));
633 ch
->state
= UNASSIGNED
;
635 ch
->gchan
= (-1); /* channel assignment not yet known */
636 ch
->channum
= (-1); /* channel assignment not yet known */
637 ch
->p
.card
= ci
->brdno
;
638 ch
->p
.port
= portnum
;
639 ch
->p
.channum
= (-1); /* channel assignment not yet known */
640 ch
->p
.mode_56k
= 0; /* default is 64kbps mode */
643 pr_warning("failed mch_t malloc, port %d channel %d size %u.\n",
644 portnum
, j
, (unsigned int) sizeof (mch_t
));
653 * Set LEDs through their paces to supply visual proof that LEDs are
654 * functional and not burnt out nor broken.
656 * YELLOW + GREEN -> OFF.
659 pci_write_32 ((u_int32_t
*) &ci
->cpldbase
->leds
,
660 PMCC4_CPLD_LED_GREEN
| PMCC4_CPLD_LED_YELLOW
);
661 OS_uwait (750000, "leds");
662 pci_write_32 ((u_int32_t
*) &ci
->cpldbase
->leds
, PMCC4_CPLD_LED_OFF
);
665 OS_init_watchdog (&ci
->wd
, (void (*) (void *)) c4_watchdog
, ci
, WATCHDOG_TIMEOUT
);
666 return SBE_DRVR_SUCCESS
;
670 /* better be fully setup to handle interrupts when you call this */
677 /* PORT POINT: this routine generates first interrupt */
678 if ((ret
= musycc_init (ci
)) != SBE_DRVR_SUCCESS
)
682 ci
->p
.framing_type
= FRAMING_CBP
;
683 ci
->p
.h110enable
= 1;
689 ci
->p
.clock
= 0; /* Use internal clocking until set to
691 c4_card_set_params (ci
, &ci
->p
);
693 OS_start_watchdog (&ci
->wd
);
694 return SBE_DRVR_SUCCESS
;
698 /* This function sets the loopback mode (or clears it, as the case may be). */
701 c4_loop_port (ci_t
* ci
, int portnum
, u_int8_t cmd
)
704 volatile u_int32_t loopValue
;
706 comet
= ci
->port
[portnum
].cometbase
;
707 loopValue
= pci_read_32 ((u_int32_t
*) &comet
->mdiag
) & COMET_MDIAG_LBMASK
;
709 if (cmd
& COMET_LBCMD_READ
)
710 return loopValue
; /* return the read value */
712 if (loopValue
!= cmd
)
716 case COMET_MDIAG_LINELB
:
717 /* set(SF)loopback down (turn off) code length to 6 bits */
718 pci_write_32 ((u_int32_t
*) &comet
->ibcd_cfg
, 0x05);
720 case COMET_MDIAG_LBOFF
:
721 /* set (SF) loopback up (turn on) code length to 5 bits */
722 pci_write_32 ((u_int32_t
*) &comet
->ibcd_cfg
, 0x00);
726 pci_write_32 ((u_int32_t
*) &comet
->mdiag
, cmd
);
727 if (cxt1e1_log_level
>= LOG_WARN
)
728 pr_info("%s: loopback mode changed to %2x from %2x on Port %d\n",
729 ci
->devname
, cmd
, loopValue
, portnum
);
730 loopValue
= pci_read_32 ((u_int32_t
*) &comet
->mdiag
) & COMET_MDIAG_LBMASK
;
731 if (loopValue
!= cmd
)
733 if (cxt1e1_log_level
>= LOG_ERROR
)
734 pr_info("%s: write to loop register failed, unknown state for Port %d\n",
735 ci
->devname
, portnum
);
739 if (cxt1e1_log_level
>= LOG_WARN
)
740 pr_info("%s: loopback already in that mode (%2x)\n",
741 ci
->devname
, loopValue
);
747 /* c4_frame_rw: read or write the comet register specified
748 * (modifies use of port_param to non-standard use of struct)
750 * pp.portnum (one guess)
751 * pp.port_mode offset of register
752 * pp.portP write (or not, i.e. read)
753 * pp.portStatus write value
755 * pp.portStatus also used to return read value
756 * pp.portP also used during write, to return old reg value
760 c4_frame_rw (ci_t
* ci
, struct sbecom_port_param
* pp
)
763 volatile u_int32_t data
;
765 if (pp
->portnum
>= ci
->max_port
)/* sanity check */
768 comet
= ci
->port
[pp
->portnum
].cometbase
;
769 data
= pci_read_32 ((u_int32_t
*) comet
+ pp
->port_mode
) & 0xff;
772 { /* control says this is a register
774 if (pp
->portStatus
== data
)
775 pr_info("%s: Port %d already that value! Writing again anyhow.\n",
776 ci
->devname
, pp
->portnum
);
777 pp
->portP
= (u_int8_t
) data
;
778 pci_write_32 ((u_int32_t
*) comet
+ pp
->port_mode
,
780 data
= pci_read_32 ((u_int32_t
*) comet
+ pp
->port_mode
) & 0xff;
782 pp
->portStatus
= (u_int8_t
) data
;
787 /* c4_pld_rw: read or write the pld register specified
788 * (modifies use of port_param to non-standard use of struct)
790 * pp.port_mode offset of register
791 * pp.portP write (or not, i.e. read)
792 * pp.portStatus write value
794 * pp.portStatus also used to return read value
795 * pp.portP also used during write, to return old reg value
799 c4_pld_rw (ci_t
* ci
, struct sbecom_port_param
* pp
)
801 volatile u_int32_t
*regaddr
;
802 volatile u_int32_t data
;
803 int regnum
= pp
->port_mode
;
805 regaddr
= (u_int32_t
*) ci
->cpldbase
+ regnum
;
806 data
= pci_read_32 ((u_int32_t
*) regaddr
) & 0xff;
809 { /* control says this is a register
811 pp
->portP
= (u_int8_t
) data
;
812 pci_write_32 ((u_int32_t
*) regaddr
, pp
->portStatus
);
813 data
= pci_read_32 ((u_int32_t
*) regaddr
) & 0xff;
815 pp
->portStatus
= (u_int8_t
) data
;
819 /* c4_musycc_rw: read or write the musycc register specified
820 * (modifies use of port_param to non-standard use of struct)
822 * mcp.RWportnum port number and write indication bit (0x80)
823 * mcp.offset offset of register
824 * mcp.value write value going in and read value returning
827 /* PORT POINT: TX Subchannel Map registers are write-only
828 * areas within the MUSYCC and always return FF */
829 /* PORT POINT: regram and reg structures are minorly different and <offset> ioctl
830 * settings are aligned with the <reg> struct musycc_globalr{} usage.
831 * Also, regram is separately allocated shared memory, allocated for each port.
832 * PORT POINT: access offsets of 0x6000 for Msg Cfg Desc Tbl are for 4-port MUSYCC
833 * only. (An 8-port MUSYCC has 0x16000 offsets for accessing its upper 4 tables.)
837 c4_musycc_rw (ci_t
* ci
, struct c4_musycc_param
* mcp
)
840 volatile u_int32_t
*dph
; /* hardware implemented register */
841 u_int32_t
*dpr
= 0; /* RAM image of registers for group command
843 int offset
= mcp
->offset
% 0x800; /* group relative address
844 * offset, mcp->portnum is
846 int portnum
, ramread
= 0;
847 volatile u_int32_t data
;
850 * Sanity check hardware accessibility. The 0x6000 portion handles port
851 * numbers associated with Msg Descr Tbl decoding.
853 portnum
= (mcp
->offset
% 0x6000) / 0x800;
854 if (portnum
>= ci
->max_port
)
856 pi
= &ci
->port
[portnum
];
857 if (mcp
->offset
>= 0x6000)
858 offset
+= 0x6000; /* put back in MsgCfgDesc address offset */
859 dph
= (u_int32_t
*) ((u_long
) pi
->reg
+ offset
);
861 /* read of TX are from RAM image, since hardware returns FF */
862 dpr
= (u_int32_t
*) ((u_long
) pi
->regram
+ offset
);
863 if (mcp
->offset
< 0x6000) /* non MsgDesc Tbl accesses might require
866 if (offset
>= 0x200 && offset
< 0x380)
868 if (offset
>= 0x10 && offset
< 0x200)
871 /* read register from RAM or hardware, depending... */
875 //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 */
878 data
= pci_read_32 ((u_int32_t
*) dph
);
879 //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 */
883 if (mcp
->RWportnum
& 0x80)
884 { /* control says this is a register
886 if (mcp
->value
== data
)
887 pr_info("%s: musycc grp%d already that value! writing again anyhow.\n",
888 ci
->devname
, (mcp
->RWportnum
& 0x7));
889 /* write register RAM */
892 /* write hardware register */
893 pci_write_32 ((u_int32_t
*) dph
, mcp
->value
);
895 mcp
->value
= data
; /* return the read value (or the 'old
896 * value', if is write) */
901 c4_get_port (ci_t
* ci
, int portnum
)
903 if (portnum
>= ci
->max_port
) /* sanity check */
906 SD_SEM_TAKE (&ci
->sem_wdbusy
, "_wd_"); /* only 1 thru here, per
909 ci
->port
[portnum
].p
.portStatus
= (u_int8_t
) ci
->alarmed
[portnum
];
910 ci
->alarmed
[portnum
] &= 0xdf;
911 SD_SEM_GIVE (&ci
->sem_wdbusy
); /* release per-board hold */
916 c4_set_port (ci_t
* ci
, int portnum
)
919 struct sbecom_port_param
*pp
;
924 if (portnum
>= ci
->max_port
) /* sanity check */
927 pi
= &ci
->port
[portnum
];
928 pp
= &ci
->port
[portnum
].p
;
929 e1mode
= IS_FRAME_ANY_E1 (pp
->port_mode
);
930 if (cxt1e1_log_level
>= LOG_MONITOR2
)
932 pr_info("%s: c4_set_port[%d]: entered, e1mode = %x, openchans %d.\n",
934 portnum
, e1mode
, pi
->openchans
);
937 return EBUSY
; /* group needs initialization only for
938 * first channel of a group */
943 if ((ret
= c4_wq_port_init (pi
))) /* create/init
944 * workqueue_struct */
948 init_comet (ci
, pi
->cometbase
, pp
->port_mode
, 1 /* clockmaster == true */ , pp
->portP
);
949 clck
= pci_read_32 ((u_int32_t
*) &ci
->cpldbase
->mclk
) & PMCC4_CPLD_MCLK_MASK
;
951 clck
|= 1 << portnum
;
953 clck
&= 0xf ^ (1 << portnum
);
955 pci_write_32 ((u_int32_t
*) &ci
->cpldbase
->mclk
, clck
);
956 pci_write_32 ((u_int32_t
*) &ci
->cpldbase
->mcsr
, PMCC4_CPLD_MCSR_IND
);
957 pci_write_32 ((u_int32_t
*) &pi
->reg
->gbp
, OS_vtophys (pi
->regram
));
959 /*********************************************************************/
960 /* ERRATA: If transparent mode is used, do not set OOFMP_DISABLE bit */
961 /*********************************************************************/
964 __constant_cpu_to_le32 (MUSYCC_GRCD_RX_ENABLE
|
965 MUSYCC_GRCD_TX_ENABLE
|
966 MUSYCC_GRCD_OOFMP_DISABLE
|
967 MUSYCC_GRCD_SF_ALIGN
| /* per MUSYCC ERRATA,
969 MUSYCC_GRCD_COFAIRQ_DISABLE
|
970 MUSYCC_GRCD_MC_ENABLE
|
971 (MUSYCC_GRCD_POLLTH_32
<< MUSYCC_GRCD_POLLTH_SHIFT
));
974 __constant_cpu_to_le32 ((e1mode
? 1 : 0) |
975 MUSYCC_PCD_TXSYNC_RISING
|
976 MUSYCC_PCD_RXSYNC_RISING
|
977 MUSYCC_PCD_RXDATA_RISING
);
979 /* Message length descriptor */
980 pi
->regram
->mld
= __constant_cpu_to_le32 (cxt1e1_max_mru
| (cxt1e1_max_mru
<< 16));
983 for (i
= 0; i
< 32; i
++)
986 /*** ASSIGNMENT NOTES: ***/
987 /*** Group's channel ZERO unavailable if E1. ***/
988 /*** Group's channel 16 unavailable if E1 CAS. ***/
989 /*** Group's channels 24-31 unavailable if T1. ***/
991 if (((i
== 0) && e1mode
) ||
992 ((i
== 16) && ((pp
->port_mode
== CFG_FRAME_E1CRC_CAS
) || (pp
->port_mode
== CFG_FRAME_E1CRC_CAS_AMI
)))
993 || ((i
> 23) && (!e1mode
)))
995 pi
->tsm
[i
] = 0xff; /* make tslot unavailable for this mode */
998 pi
->tsm
[i
] = 0x00; /* make tslot available for assignment */
1001 for (i
= 0; i
< MUSYCC_NCHANS
; i
++)
1003 pi
->regram
->ttsm
[i
] = 0;
1004 pi
->regram
->rtsm
[i
] = 0;
1007 musycc_serv_req (pi
, SR_GROUP_INIT
| SR_RX_DIRECTION
);
1008 musycc_serv_req (pi
, SR_GROUP_INIT
| SR_TX_DIRECTION
);
1010 musycc_init_mdt (pi
);
1012 pi
->group_is_set
= 1;
1018 unsigned int max_int
= 0;
1021 c4_new_chan (ci_t
* ci
, int portnum
, int channum
, void *user
)
1027 if (c4_find_chan (channum
)) /* a new channel shouldn't already exist */
1030 if (portnum
>= ci
->max_port
) /* sanity check */
1033 pi
= &(ci
->port
[portnum
]);
1034 /* find any available channel within this port */
1035 for (gchan
= 0; gchan
< MUSYCC_NCHANS
; gchan
++)
1037 ch
= pi
->chan
[gchan
];
1038 if (ch
&& ch
->state
== UNASSIGNED
) /* no assignment is good! */
1041 if (gchan
== MUSYCC_NCHANS
) /* exhausted table, all were assigned */
1046 /* NOTE: mch_t already cleared during OS_kmalloc() */
1050 ch
->channum
= channum
; /* mark our channel assignment */
1051 ch
->p
.channum
= channum
;
1053 ch
->p
.card
= ci
->brdno
;
1054 ch
->p
.port
= portnum
;
1056 ch
->p
.chan_mode
= CFG_CH_PROTO_HDLC_FCS16
;
1057 ch
->p
.idlecode
= CFG_CH_FLAG_7E
;
1058 ch
->p
.pad_fill_count
= 2;
1059 spin_lock_init (&ch
->ch_rxlock
);
1060 spin_lock_init (&ch
->ch_txlock
);
1065 if ((ret
= c4_wk_chan_init (pi
, ch
)))
1069 /* save off interface assignments which bound a board */
1070 if (ci
->first_if
== 0) /* first channel registered is assumed to
1071 * be the lowest channel */
1073 ci
->first_if
= ci
->last_if
= user
;
1074 ci
->first_channum
= ci
->last_channum
= channum
;
1078 if (ci
->last_channum
< channum
) /* higher number channel found */
1079 ci
->last_channum
= channum
;
1085 c4_del_chan (int channum
)
1089 if (!(ch
= c4_find_chan (channum
)))
1091 if (ch
->state
== UP
)
1092 musycc_chan_down ((ci_t
*) 0, channum
);
1093 ch
->state
= UNASSIGNED
;
1096 ch
->p
.channum
= (-1);
1101 c4_del_chan_stats (int channum
)
1105 if (!(ch
= c4_find_chan (channum
)))
1108 memset (&ch
->s
, 0, sizeof (struct sbecom_chan_stats
));
1114 c4_set_chan (int channum
, struct sbecom_chan_param
* p
)
1119 if (!(ch
= c4_find_chan (channum
)))
1123 if (ch
->p
.card
!= p
->card
||
1124 ch
->p
.port
!= p
->port
||
1125 ch
->p
.channum
!= p
->channum
)
1129 if (!(ch
->up
->group_is_set
))
1131 return EIO
; /* out of order, SET_PORT command
1132 * required prior to first group's
1133 * SET_CHAN command */
1136 * Check for change of parameter settings in order to invoke closing of
1137 * channel prior to hardware poking.
1140 if (ch
->p
.status
!= p
->status
|| ch
->p
.chan_mode
!= p
->chan_mode
||
1141 ch
->p
.data_inv
!= p
->data_inv
|| ch
->p
.intr_mask
!= p
->intr_mask
||
1142 ch
->txd_free
< ch
->txd_num
) /* to clear out queued messages */
1143 x
= 1; /* we have a change requested */
1144 for (i
= 0; i
< 32; i
++) /* check for timeslot mapping changes */
1145 if (ch
->p
.bitmask
[i
] != p
->bitmask
[i
])
1146 x
= 1; /* we have a change requested */
1148 if (x
&& (ch
->state
== UP
)) /* if change request and channel is
1153 if ((ret
= musycc_chan_down ((ci_t
*) 0, channum
)))
1155 if ((ret
= c4_chan_up (ch
->up
->up
, channum
)))
1157 sd_enable_xmit (ch
->user
); /* re-enable to catch flow controlled
1165 c4_get_chan (int channum
, struct sbecom_chan_param
* p
)
1169 if (!(ch
= c4_find_chan (channum
)))
1176 c4_get_chan_stats (int channum
, struct sbecom_chan_stats
* p
)
1180 if (!(ch
= c4_find_chan (channum
)))
1183 p
->tx_pending
= atomic_read (&ch
->tx_pending
);
1188 c4_fifo_alloc (mpi_t
* pi
, int chan
, int *len
)
1190 int i
, l
= 0, start
= 0, max
= 0, maxstart
= 0;
1192 for (i
= 0; i
< 32; i
++)
1194 if (pi
->fifomap
[i
] != -1)
1211 if (cxt1e1_log_level
>= LOG_WARN
)
1212 pr_info("%s: wanted to allocate %d fifo space, but got only %d\n",
1213 pi
->up
->devname
, *len
, max
);
1216 if (cxt1e1_log_level
>= LOG_DEBUG
)
1217 pr_info("%s: allocated %d fifo at %d for channel %d/%d\n",
1218 pi
->up
->devname
, max
, start
, chan
, pi
->p
.portnum
);
1219 for (i
= maxstart
; i
< (maxstart
+ max
); i
++)
1220 pi
->fifomap
[i
] = chan
;
1225 c4_fifo_free (mpi_t
* pi
, int chan
)
1229 if (cxt1e1_log_level
>= LOG_DEBUG
)
1230 pr_info("%s: deallocated fifo for channel %d/%d\n",
1231 pi
->up
->devname
, chan
, pi
->p
.portnum
);
1232 for (i
= 0; i
< 32; i
++)
1233 if (pi
->fifomap
[i
] == chan
)
1234 pi
->fifomap
[i
] = -1;
1239 c4_chan_up (ci_t
* ci
, int channum
)
1245 int nts
, nbuf
, txnum
, rxnum
;
1246 int addr
, i
, j
, gchan
;
1247 u_int32_t tmp
; /* for optimizing conversion across BE
1250 if (!(ch
= c4_find_chan (channum
)))
1252 if (ch
->state
== UP
)
1254 if (cxt1e1_log_level
>= LOG_MONITOR
)
1255 pr_info("%s: channel already UP, graceful early exit\n",
1261 /* find nts ('number of timeslots') */
1263 for (i
= 0; i
< 32; i
++)
1265 if (ch
->p
.bitmask
[i
] & pi
->tsm
[i
])
1267 if (1 || cxt1e1_log_level
>= LOG_WARN
)
1269 pr_info("%s: c4_chan_up[%d] EINVAL (attempt to cfg in-use or unavailable TimeSlot[%d])\n",
1270 ci
->devname
, channum
, i
);
1271 pr_info("+ ask4 %x, currently %x\n",
1272 ch
->p
.bitmask
[i
], pi
->tsm
[i
]);
1276 for (j
= 0; j
< 8; j
++)
1277 if (ch
->p
.bitmask
[i
] & (1 << j
))
1281 nbuf
= nts
/ 8 ? nts
/ 8 : 1;
1284 /* if( cxt1e1_log_level >= LOG_WARN) */
1285 pr_info("%s: c4_chan_up[%d] ENOBUFS (no TimeSlots assigned)\n",
1286 ci
->devname
, channum
);
1287 return ENOBUFS
; /* this should not happen */
1289 addr
= c4_fifo_alloc (pi
, gchan
, &nbuf
);
1292 /* Setup the Time Slot Map */
1293 musycc_update_timeslots (pi
);
1295 /* ch->tx_limit = nts; */
1296 ch
->s
.tx_pending
= 0;
1298 /* Set Channel Configuration Descriptors */
1302 ccd
= musycc_chan_proto (ch
->p
.chan_mode
) << MUSYCC_CCD_PROTO_SHIFT
;
1303 if ((ch
->p
.chan_mode
== CFG_CH_PROTO_ISLP_MODE
) ||
1304 (ch
->p
.chan_mode
== CFG_CH_PROTO_TRANS
))
1306 ccd
|= MUSYCC_CCD_FCS_XFER
; /* Non FSC Mode */
1308 ccd
|= 2 << MUSYCC_CCD_MAX_LENGTH
; /* Select second MTU */
1309 ccd
|= ch
->p
.intr_mask
;
1310 ccd
|= addr
<< MUSYCC_CCD_BUFFER_LOC
;
1311 if (ch
->p
.chan_mode
== CFG_CH_PROTO_TRANS
)
1312 ccd
|= (nbuf
) << MUSYCC_CCD_BUFFER_LENGTH
;
1314 ccd
|= (nbuf
- 1) << MUSYCC_CCD_BUFFER_LENGTH
;
1316 if (ch
->p
.data_inv
& CFG_CH_DINV_TX
)
1317 ccd
|= MUSYCC_CCD_INVERT_DATA
; /* Invert data */
1318 pi
->regram
->tcct
[gchan
] = cpu_to_le32 (ccd
);
1320 if (ch
->p
.data_inv
& CFG_CH_DINV_RX
)
1321 ccd
|= MUSYCC_CCD_INVERT_DATA
; /* Invert data */
1323 ccd
&= ~MUSYCC_CCD_INVERT_DATA
; /* take away data inversion */
1324 pi
->regram
->rcct
[gchan
] = cpu_to_le32 (ccd
);
1328 /* Reread the Channel Configuration Descriptor for this channel */
1329 musycc_serv_req (pi
, SR_CHANNEL_CONFIG
| SR_RX_DIRECTION
| gchan
);
1330 musycc_serv_req (pi
, SR_CHANNEL_CONFIG
| SR_TX_DIRECTION
| gchan
);
1333 * Figure out how many buffers we want. If the customer has changed from
1334 * the defaults, then use the changed values. Otherwise, use Transparent
1335 * mode's specific minimum default settings.
1337 if (ch
->p
.chan_mode
== CFG_CH_PROTO_TRANS
)
1339 if (max_rxdesc_used
== max_rxdesc_default
) /* use default setting */
1340 max_rxdesc_used
= MUSYCC_RXDESC_TRANS
;
1341 if (max_txdesc_used
== max_txdesc_default
) /* use default setting */
1342 max_txdesc_used
= MUSYCC_TXDESC_TRANS
;
1345 * Increase counts when hyperchanneling, since this implies an increase
1346 * in throughput per channel
1348 rxnum
= max_rxdesc_used
+ (nts
/ 4);
1349 txnum
= max_txdesc_used
+ (nts
/ 4);
1353 if (cxt1e1_log_level
>= LOG_MONITOR
)
1354 pr_info("%s: mode %x rxnum %d (rxused %d def %d) txnum %d (txused %d def %d)\n",
1355 ci
->devname
, ch
->p
.chan_mode
,
1356 rxnum
, max_rxdesc_used
, max_rxdesc_default
,
1357 txnum
, max_txdesc_used
, max_txdesc_default
);
1360 ch
->rxd_num
= rxnum
;
1361 ch
->txd_num
= txnum
;
1362 ch
->rxix_irq_srv
= 0;
1364 ch
->mdr
= OS_kmalloc (sizeof (struct mdesc
) * rxnum
);
1365 ch
->mdt
= OS_kmalloc (sizeof (struct mdesc
) * txnum
);
1366 if (ch
->p
.chan_mode
== CFG_CH_PROTO_TRANS
)
1367 tmp
= __constant_cpu_to_le32 (cxt1e1_max_mru
| EOBIRQ_ENABLE
);
1369 tmp
= __constant_cpu_to_le32 (cxt1e1_max_mru
);
1371 for (i
= 0, md
= ch
->mdr
; i
< rxnum
; i
++, md
++)
1373 if (i
== (rxnum
- 1))
1375 md
->snext
= &ch
->mdr
[0];/* wrapness */
1378 md
->snext
= &ch
->mdr
[i
+ 1];
1380 md
->next
= cpu_to_le32 (OS_vtophys (md
->snext
));
1382 if (!(m
= OS_mem_token_alloc (cxt1e1_max_mru
)))
1384 if (cxt1e1_log_level
>= LOG_MONITOR
)
1385 pr_info("%s: c4_chan_up[%d] - token alloc failure, size = %d.\n",
1386 ci
->devname
, channum
, cxt1e1_max_mru
);
1390 md
->data
= cpu_to_le32 (OS_vtophys (OS_mem_token_data (m
)));
1391 md
->status
= tmp
| MUSYCC_RX_OWNED
; /* MUSYCC owns RX descriptor **
1393 * MUSYCC_RX_OWNED = 0 so no
1394 * need to byteSwap */
1397 for (i
= 0, md
= ch
->mdt
; i
< txnum
; i
++, md
++)
1399 md
->status
= HOST_TX_OWNED
; /* Host owns TX descriptor ** CODING
1400 * NOTE: HOST_TX_OWNED = 0 so no need to
1404 if (i
== (txnum
- 1))
1406 md
->snext
= &ch
->mdt
[0];/* wrapness */
1409 md
->snext
= &ch
->mdt
[i
+ 1];
1411 md
->next
= cpu_to_le32 (OS_vtophys (md
->snext
));
1413 ch
->txd_irq_srv
= ch
->txd_usr_add
= &ch
->mdt
[0];
1414 ch
->txd_free
= txnum
;
1416 ch
->txd_required
= 0;
1418 /* Configure it into the chip */
1419 tmp
= cpu_to_le32 (OS_vtophys (&ch
->mdt
[0]));
1420 pi
->regram
->thp
[gchan
] = tmp
;
1421 pi
->regram
->tmp
[gchan
] = tmp
;
1423 tmp
= cpu_to_le32 (OS_vtophys (&ch
->mdr
[0]));
1424 pi
->regram
->rhp
[gchan
] = tmp
;
1425 pi
->regram
->rmp
[gchan
] = tmp
;
1427 /* Activate the Channel */
1429 if (ch
->p
.status
& RX_ENABLED
)
1431 #ifdef RLD_TRANS_DEBUG
1432 pr_info("++ c4_chan_up() CHAN RX ACTIVATE: chan %d\n", ch
->channum
);
1434 ch
->ch_start_rx
= 0; /* we are restarting RX... */
1435 musycc_serv_req (pi
, SR_CHANNEL_ACTIVATE
| SR_RX_DIRECTION
| gchan
);
1437 if (ch
->p
.status
& TX_ENABLED
)
1439 #ifdef RLD_TRANS_DEBUG
1440 pr_info("++ c4_chan_up() CHAN TX ACTIVATE: chan %d <delayed>\n", ch
->channum
);
1442 ch
->ch_start_tx
= CH_START_TX_1ST
; /* we are delaying start
1443 * until receipt from user of
1444 * first packet to transmit. */
1446 ch
->status
= ch
->p
.status
;
1453 /* Don't leak all the previously allocated mbufs in this loop */
1455 OS_mem_token_free (ch
->mdr
[i
].mem_token
);
1467 /* stop the hardware from servicing & interrupting */
1470 c4_stopwd (ci_t
* ci
)
1472 OS_stop_watchdog (&ci
->wd
);
1473 SD_SEM_TAKE (&ci
->sem_wdbusy
, "_stop_"); /* ensure WD not running */
1474 SD_SEM_GIVE (&ci
->sem_wdbusy
);
1479 sbecom_get_brdinfo (ci_t
* ci
, struct sbe_brd_info
* bip
, u_int8_t
*bsn
)
1485 bip
->brdno
= ci
->brdno
; /* our board number */
1486 bip
->brd_id
= ci
->brd_id
;
1487 bip
->brd_hdw_id
= ci
->hdw_bid
;
1488 bip
->brd_chan_cnt
= MUSYCC_NCHANS
* ci
->max_port
; /* number of channels
1490 bip
->brd_port_cnt
= ci
->max_port
; /* number of ports being used */
1491 bip
->brd_pci_speed
= BINFO_PCI_SPEED_unk
; /* PCI speed not yet
1497 struct net_device
*dev
;
1499 dev
= (struct net_device
*) ci
->first_if
;
1500 np
= (char *) dev
->name
;
1502 strncpy (bip
->first_iname
, np
, CHNM_STRLEN
- 1);
1504 strcpy (bip
->first_iname
, "<NULL>");
1508 struct net_device
*dev
;
1510 dev
= (struct net_device
*) ci
->last_if
;
1511 np
= (char *) dev
->name
;
1513 strncpy (bip
->last_iname
, np
, CHNM_STRLEN
- 1);
1515 strcpy (bip
->last_iname
, "<NULL>");
1519 for (i
= 0; i
< 3; i
++)
1521 bip
->brd_mac_addr
[i
] = *bsn
++;
1525 bip
->brd_mac_addr
[i
] = *bsn
;
1526 sn
= (sn
<< 8) | *bsn
++;
1530 for (i
= 0; i
< 6; i
++)
1531 bip
->brd_mac_addr
[i
] = 0;
1538 c4_get_iidinfo (ci_t
* ci
, struct sbe_iid_info
* iip
)
1540 struct net_device
*dev
;
1543 if (!(dev
= getuserbychan (iip
->channum
)))
1547 strncpy (iip
->iname
, np
, CHNM_STRLEN
- 1);
1552 #ifdef CONFIG_SBE_PMCC4_NCOMM
1553 void (*nciInterrupt
[MAX_BOARDS
][4]) (void);
1554 extern void wanpmcC4T1E1_hookInterrupt (int cardID
, int deviceID
, void *handler
);
1557 wanpmcC4T1E1_hookInterrupt (int cardID
, int deviceID
, void *handler
)
1559 if (cardID
< MAX_BOARDS
) /* sanity check */
1560 nciInterrupt
[cardID
][deviceID
] = handler
;
1564 c4_ebus_intr_th_handler (void *devp
)
1566 ci_t
*ci
= (ci_t
*) devp
;
1567 volatile u_int32_t ists
;
1571 /* which COMET caused the interrupt */
1573 ists
= pci_read_32 ((u_int32_t
*) &ci
->cpldbase
->intr
);
1574 if (ists
& PMCC4_CPLD_INTR_CMT_1
)
1577 if (nciInterrupt
[brdno
][0] != NULL
)
1578 (*nciInterrupt
[brdno
][0]) ();
1580 if (ists
& PMCC4_CPLD_INTR_CMT_2
)
1583 if (nciInterrupt
[brdno
][1] != NULL
)
1584 (*nciInterrupt
[brdno
][1]) ();
1586 if (ists
& PMCC4_CPLD_INTR_CMT_3
)
1589 if (nciInterrupt
[brdno
][2] != NULL
)
1590 (*nciInterrupt
[brdno
][2]) ();
1592 if (ists
& PMCC4_CPLD_INTR_CMT_4
)
1595 if (nciInterrupt
[brdno
][3] != NULL
)
1596 (*nciInterrupt
[brdno
][3]) ();
1599 /*** Test code just de-implements the asserted interrupt. Alternate
1600 vendor will supply COMET interrupt handling code herein or such.
1602 pci_write_32 ((u_int32_t
*) &ci
->reg
->glcd
, GCD_MAGIC
| MUSYCC_GCD_INTB_DISABLE
);
1605 return IRQ_RETVAL (handled
);
1610 wanpmcC4T1E1_getBaseAddress (int cardID
, int deviceID
)
1613 unsigned long base
= 0;
1618 if (ci
->brdno
== cardID
) /* found valid device */
1620 if (deviceID
< ci
->max_port
) /* comet is supported */
1621 base
= ((unsigned long) ci
->port
[deviceID
].cometbase
);
1624 ci
= ci
->next
; /* next board, if any */
1629 #endif /*** CONFIG_SBE_PMCC4_NCOMM ***/
1632 /*** End-of-File ***/