1150849Sscottl/*
2150849Sscottl * $FreeBSD$
3150849Sscottl *
4150849Sscottl * Copyright (c) 2002-2004 David Boggs. <boggs@boggs.palo-alto.ca.us>
5150849Sscottl * All rights reserved.
6150849Sscottl *
7150849Sscottl * BSD License:
8150849Sscottl *
9150849Sscottl * Redistribution and use in source and binary forms, with or without
10150849Sscottl * modification, are permitted provided that the following conditions
11150849Sscottl * are met:
12150849Sscottl * 1. Redistributions of source code must retain the above copyright
13150849Sscottl *    notice, this list of conditions and the following disclaimer.
14150849Sscottl * 2. Redistributions in binary form must reproduce the above copyright
15150849Sscottl *    notice, this list of conditions and the following disclaimer in the
16150849Sscottl *    documentation and/or other materials provided with the distribution.
17150849Sscottl *
18150849Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19150849Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20150849Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21150849Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22150849Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23150849Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24150849Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25150849Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26150849Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27150849Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28150849Sscottl * SUCH DAMAGE.
29150849Sscottl *
30150849Sscottl * GNU General Public License:
31150849Sscottl *
32150849Sscottl * This program is free software; you can redistribute it and/or modify it
33150849Sscottl * under the terms of the GNU General Public License as published by the Free
34150849Sscottl * Software Foundation; either version 2 of the License, or (at your option)
35150849Sscottl * any later version.
36150849Sscottl *
37150849Sscottl * This program is distributed in the hope that it will be useful, but WITHOUT
38150849Sscottl * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
39150849Sscottl * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
40150849Sscottl * more details.
41150849Sscottl *
42150849Sscottl * You should have received a copy of the GNU General Public License along with
43150849Sscottl * this program; if not, write to the Free Software Foundation, Inc., 59
44150849Sscottl * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
45150849Sscottl *
46150849Sscottl * Description:
47150849Sscottl *
48150849Sscottl * This is an open-source Unix device driver for PCI-bus WAN interface cards.
49150849Sscottl * It sends and receives packets in HDLC frames over synchronous links.
50150849Sscottl * A generic PC plus Unix plus some SBE/LMC cards makes an OPEN router.
51150849Sscottl * This driver works with FreeBSD, NetBSD, OpenBSD, BSD/OS and Linux.
52150849Sscottl * It has been tested on i386 (32-bit little-end), Sparc (64-bit big-end),
53150849Sscottl * and Alpha (64-bit little-end) architectures.
54150849Sscottl *
55150849Sscottl * History and Authors:
56150849Sscottl *
57150849Sscottl * Ron Crane had the neat idea to use a Fast Ethernet chip as a PCI
58150849Sscottl * interface and add an Ethernet-to-HDLC gate array to make a WAN card.
59150849Sscottl * David Boggs designed the Ethernet-to-HDLC gate arrays and PC cards.
60150849Sscottl * We did this at our company, LAN Media Corporation (LMC).
61170035Srwatson * SBE Corp acquired LMC and continues to make the cards.
62150849Sscottl *
63150849Sscottl * Since the cards use Tulip Ethernet chips, we started with Matt Thomas'
64150849Sscottl * ubiquitous "de" driver.  Michael Graff stripped out the Ethernet stuff
65150849Sscottl * and added HSSI stuff.  Basil Gunn ported it to Solaris (lost) and
66150849Sscottl * Rob Braun ported it to Linux.  Andrew Stanley-Jones added support
67150849Sscottl * for three more cards and wrote the first version of lmcconfig.
68150849Sscottl * During 2002-5 David Boggs rewrote it and now feels responsible for it.
69150849Sscottl *
70150849Sscottl * Responsible Individual:
71150849Sscottl *
72150849Sscottl * Send bug reports and improvements to <boggs@boggs.palo-alto.ca.us>.
73150849Sscottl */
74153084Sru#ifdef __FreeBSD__
75150849Sscottl# include <sys/param.h>	/* OS version */
76150849Sscottl# define  IFNET 1
77150849Sscottl# include "opt_inet.h"	/* INET */
78150849Sscottl# include "opt_inet6.h"	/* INET6 */
79150849Sscottl# include "opt_netgraph.h" /* NETGRAPH */
80150967Sglebius# ifdef HAVE_KERNEL_OPTION_HEADERS
81150967Sglebius# include "opt_device_polling.h" /* DEVICE_POLLING */
82150967Sglebius# endif
83182112Sbz# ifndef INET
84182112Sbz#  define INET 0
85182112Sbz# endif
86182112Sbz# ifndef INET6
87182112Sbz#  define INET6 0
88182112Sbz# endif
89150849Sscottl# ifndef NETGRAPH
90150849Sscottl#  define NETGRAPH 0
91150849Sscottl# endif
92150849Sscottl# define  P2P 0		/* not in FreeBSD */
93150849Sscottl# if (__FreeBSD_version >= 500000)
94150849Sscottl#  define NSPPP 1	/* No count devices in FreeBSD 5 */
95150849Sscottl#  include "opt_bpf.h"	/* DEV_BPF */
96150849Sscottl#  define NBPFILTER DEV_BPF
97150849Sscottl# else  /* FreeBSD-4 */
98150849Sscottl# include "sppp.h"	/* NSPPP */
99150849Sscottl#  include "bpf.h"	/* NBPF */
100150849Sscottl#  define NBPFILTER NBPF
101150849Sscottl# endif
102150849Sscottl# define  GEN_HDLC 0	/* not in FreeBSD */
103150849Sscottl#
104150849Sscottl# include <sys/systm.h>
105150849Sscottl# include <sys/kernel.h>
106150849Sscottl# include <sys/malloc.h>
107150849Sscottl# include <sys/mbuf.h>
108150849Sscottl# include <sys/socket.h>
109150849Sscottl# include <sys/sockio.h>
110150849Sscottl# include <sys/module.h>
111150849Sscottl# include <sys/bus.h>
112150849Sscottl# include <sys/lock.h>
113150849Sscottl# include <net/if.h>
114150849Sscottl# include <net/if_types.h>
115150849Sscottl# include <net/if_media.h>
116150849Sscottl# include <net/netisr.h>
117191148Skmacy# include <net/route.h>
118150849Sscottl# include <machine/bus.h>
119150849Sscottl# include <machine/resource.h>
120150849Sscottl# include <sys/rman.h>
121150849Sscottl# include <vm/vm.h>
122150849Sscottl# include <vm/pmap.h>
123164033Srwatson# if (__FreeBSD_version >= 700000)
124164033Srwatson#  include <sys/priv.h>
125164033Srwatson# endif
126150849Sscottl# if (__FreeBSD_version >= 500000)
127150849Sscottl#  include <sys/mutex.h>
128150849Sscottl#  include <dev/pci/pcivar.h>
129150849Sscottl# else /* FreeBSD-4 */
130150849Sscottl#  include <sys/proc.h>
131150849Sscottl#  include <pci/pcivar.h>
132150849Sscottl# endif
133150849Sscottl# if NETGRAPH
134150849Sscottl#  include <netgraph/ng_message.h>
135150849Sscottl#  include <netgraph/netgraph.h>
136150849Sscottl# endif
137150849Sscottl# if (INET || INET6)
138150849Sscottl#  include <netinet/in.h>
139150849Sscottl#  include <netinet/in_var.h>
140150849Sscottl# endif
141150849Sscottl# if NSPPP
142150849Sscottl#  include <net/if_sppp.h>
143150849Sscottl# endif
144150849Sscottl# if NBPFILTER
145150849Sscottl#  include <net/bpf.h>
146150849Sscottl# endif
147150849Sscottl/* and finally... */
148150849Sscottl# include <dev/lmc/if_lmc.h>
149150849Sscottl#endif /*__FreeBSD__*/
150150849Sscottl
151153084Sru#ifdef __NetBSD__
152150849Sscottl# include <sys/param.h>	/* OS version */
153150849Sscottl# define  IFNET 1
154150849Sscottl# include "opt_inet.h"	/* INET6, INET */
155150849Sscottl# define  NETGRAPH 0	/* not in NetBSD */
156150849Sscottl# include "sppp.h"	/* NSPPP */
157150849Sscottl# define  P2P 0		/* not in NetBSD */
158150849Sscottl# include "opt_altq_enabled.h" /* ALTQ */
159150849Sscottl# include "bpfilter.h"	/* NBPFILTER */
160150849Sscottl# define  GEN_HDLC 0	/* not in NetBSD */
161150849Sscottl#
162150849Sscottl# include <sys/systm.h>
163150849Sscottl# include <sys/kernel.h>
164150849Sscottl# include <sys/lkm.h>
165150849Sscottl# include <sys/mbuf.h>
166150849Sscottl# include <sys/socket.h>
167150849Sscottl# include <sys/sockio.h>
168150849Sscottl# include <sys/device.h>
169150849Sscottl# include <sys/lock.h>
170150849Sscottl# include <net/if.h>
171150849Sscottl# include <net/if_types.h>
172150849Sscottl# include <net/if_media.h>
173150849Sscottl# include <net/netisr.h>
174150849Sscottl# include <machine/bus.h>
175150849Sscottl# include <machine/intr.h>
176150849Sscottl# include <dev/pci/pcivar.h>
177150849Sscottl# if (__NetBSD_Version__ >= 106000000)
178150849Sscottl#  include <uvm/uvm_extern.h>
179150849Sscottl# else
180150849Sscottl#  include <vm/vm.h>
181150849Sscottl# endif
182150849Sscottl# if (INET || INET6)
183150849Sscottl#  include <netinet/in.h>
184150849Sscottl#  include <netinet/in_var.h>
185150849Sscottl# endif
186150849Sscottl# if NSPPP
187150849Sscottl#  if (__NetBSD_Version__ >= 106000000)
188150849Sscottl#   include <net/if_spppvar.h>
189150849Sscottl#  else
190150849Sscottl#   include <net/if_sppp.h>
191150849Sscottl#  endif
192150849Sscottl# endif
193150849Sscottl# if NBPFILTER
194150849Sscottl#  include <net/bpf.h>
195150849Sscottl# endif
196150849Sscottl/* and finally... */
197150849Sscottl# include "if_lmc.h"
198150849Sscottl#endif /*__NetBSD__*/
199150849Sscottl
200153084Sru#ifdef __OpenBSD__
201150849Sscottl# include <sys/param.h>	/* OS version */
202150849Sscottl# define  IFNET 1
203150849Sscottl/* -DINET  is passed on the compiler command line */
204150849Sscottl/* -DINET6 is passed on the compiler command line */
205150849Sscottl# define  NETGRAPH 0	/* not in OpenBSD */
206150849Sscottl# include "sppp.h"	/* NSPPP */
207150849Sscottl# define  P2P 0		/* not in OpenBSD */
208150849Sscottl/* -DALTQ  is passed on the compiler command line */
209150849Sscottl# include "bpfilter.h"	/* NBPFILTER */
210150849Sscottl# define  GEN_HDLC 0	/* not in OpenBSD */
211150849Sscottl#
212150849Sscottl# include <sys/systm.h>
213150849Sscottl# include <sys/kernel.h>
214150849Sscottl# include <sys/conf.h>
215150849Sscottl# include <sys/exec.h>
216150849Sscottl# include <sys/lkm.h>
217150849Sscottl# include <sys/mbuf.h>
218150849Sscottl# include <sys/socket.h>
219150849Sscottl# include <sys/sockio.h>
220150849Sscottl# include <sys/device.h>
221150849Sscottl# include <sys/lock.h>
222150849Sscottl# include <net/if.h>
223150849Sscottl# include <net/if_types.h>
224150849Sscottl# include <net/if_media.h>
225150849Sscottl# include <net/netisr.h>
226150849Sscottl# include <machine/bus.h>
227150849Sscottl# include <machine/intr.h>
228150849Sscottl# include <dev/pci/pcivar.h>
229150849Sscottl# if (OpenBSD >= 200206)
230150849Sscottl#  include <uvm/uvm_extern.h>
231150849Sscottl# else
232150849Sscottl#  include <vm/vm.h>
233150849Sscottl# endif
234150849Sscottl# if (INET || INET6)
235150849Sscottl#  include <netinet/in.h>
236150849Sscottl#  include <netinet/in_var.h>
237150849Sscottl# endif
238150849Sscottl# if NSPPP
239150849Sscottl#  include <net/if_sppp.h>
240150849Sscottl# endif
241150849Sscottl# if NBPFILTER
242150849Sscottl#  include <net/bpf.h>
243150849Sscottl# endif
244150849Sscottl/* and finally... */
245150849Sscottl# include "if_lmc.h"
246150849Sscottl#endif /*__OpenBSD__*/
247150849Sscottl
248153084Sru#ifdef __bsdi__
249150849Sscottl# include <sys/param.h>	/* OS version */
250150849Sscottl# define  IFNET 1
251150849Sscottl/* -DINET  is passed on the compiler command line */
252150849Sscottl/* -DINET6 is passed on the compiler command line */
253150849Sscottl# define  NETGRAPH 0	/* not in BSD/OS */
254150849Sscottl# define  NSPPP 0	/* not in BSD/OS */
255150849Sscottl/* -DPPP   is passed on the compiler command line */
256150849Sscottl/* -DCISCO_HDLC is passed on the compiler command line */
257150849Sscottl/* -DFR    is passed on the compiler command line */
258150849Sscottl# if (PPP || CISCO_HDLC || FR)
259150849Sscottl#  define P2P 1
260150849Sscottl# else
261150849Sscottl#  define P2P 0
262150849Sscottl# endif
263150849Sscottl# define  ALTQ 0	/* not in BSD/OS */
264150849Sscottl# include "bpfilter.h"	/* NBPFILTER */
265150849Sscottl# define  GEN_HDLC 0	/* not in BSD/OS */
266150849Sscottl#
267150849Sscottl# include <sys/kernel.h>
268150849Sscottl# include <sys/malloc.h>
269150849Sscottl# include <sys/mbuf.h>
270150849Sscottl# include <sys/socket.h>
271150849Sscottl# include <sys/sockio.h>
272150849Sscottl# include <sys/device.h>
273150849Sscottl# include <sys/lock.h>
274150849Sscottl# include <net/if.h>
275150849Sscottl# include <net/if_types.h>
276150849Sscottl# include <net/if_media.h>
277150849Sscottl# include <net/netisr.h>
278150849Sscottl# include <vm/vm.h>
279150849Sscottl# include <i386/isa/dma.h>
280150849Sscottl# include <i386/isa/isavar.h>
281150849Sscottl# include <i386/include/cpu.h>
282150849Sscottl# include <i386/pci/pci.h>
283150849Sscottl# if (INET || INET6)
284150849Sscottl#  include <netinet/in.h>
285150849Sscottl#  include <netinet/in_var.h>
286150849Sscottl# endif
287150849Sscottl# if P2P
288150849Sscottl#  include <net/if_p2p.h>
289150849Sscottl#  include <sys/ttycom.h>
290150849Sscottl# endif
291150849Sscottl# if NBPFILTER
292150849Sscottl#  include <net/bpf.h>
293150849Sscottl# endif
294150849Sscottl/* and finally... */
295150849Sscottl# include "if_lmc.h"
296150849Sscottl#endif /*__bsdi__*/
297150849Sscottl
298153084Sru#ifdef __linux__
299150849Sscottl# include <linux/config.h>
300150849Sscottl# if (CONFIG_HDLC || CONFIG_HDLC_MODULE)
301150849Sscottl#  define GEN_HDLC 1
302150849Sscottl# else
303150849Sscottl#  define GEN_HDLC 0
304150849Sscottl# endif
305150849Sscottl# define IFNET 0	/* different in Linux */
306150849Sscottl# define NETGRAPH 0	/* not in Linux */
307150849Sscottl# define NSPPP 0	/* different in Linux */
308150849Sscottl# define P2P 0		/* not in Linux */
309150849Sscottl# define ALTQ 0		/* different in Linux */
310150849Sscottl# define NBPFILTER 0	/* different in Linux */
311150849Sscottl#
312150849Sscottl# include <linux/pci.h>
313150849Sscottl# include <linux/delay.h>
314150849Sscottl# include <linux/netdevice.h>
315150849Sscottl# include <linux/if_arp.h>
316150849Sscottl# if GEN_HDLC
317150849Sscottl#  include <linux/hdlc.h>
318150849Sscottl# endif
319150849Sscottl/* and finally... */
320150849Sscottl# include "if_lmc.h"
321150849Sscottl#endif /* __linux__ */
322150849Sscottl
323150849Sscottl/* The SROM is a generic 93C46 serial EEPROM (64 words by 16 bits). */
324150849Sscottl/* Data is set up before the RISING edge of CLK; CLK is parked low. */
325150849Sscottlstatic void
326150849Sscottlshift_srom_bits(softc_t *sc, u_int32_t data, u_int32_t len)
327150849Sscottl  {
328150849Sscottl  u_int32_t csr = READ_CSR(TLP_SROM_MII);
329150849Sscottl  for (; len>0; len--)
330150849Sscottl    {  /* MSB first */
331150849Sscottl    if (data & (1<<(len-1)))
332150849Sscottl      csr |=  TLP_SROM_DIN;	/* DIN setup */
333150849Sscottl    else
334150849Sscottl      csr &= ~TLP_SROM_DIN;	/* DIN setup */
335150849Sscottl    WRITE_CSR(TLP_SROM_MII, csr);
336150849Sscottl    csr |=  TLP_SROM_CLK;	/* CLK rising edge */
337150849Sscottl    WRITE_CSR(TLP_SROM_MII, csr);
338150849Sscottl    csr &= ~TLP_SROM_CLK;	/* CLK falling edge */
339150849Sscottl    WRITE_CSR(TLP_SROM_MII, csr);
340150849Sscottl    }
341150849Sscottl  }
342150849Sscottl
343150849Sscottl/* Data is sampled on the RISING edge of CLK; CLK is parked low. */
344150849Sscottlstatic u_int16_t
345150849Sscottlread_srom(softc_t *sc, u_int8_t addr)
346150849Sscottl  {
347150849Sscottl  int i;
348150849Sscottl  u_int32_t csr;
349150849Sscottl  u_int16_t data;
350150849Sscottl
351150849Sscottl  /* Enable SROM access. */
352150849Sscottl  csr = (TLP_SROM_SEL | TLP_SROM_RD | TLP_MII_MDOE);
353150849Sscottl  WRITE_CSR(TLP_SROM_MII, csr);
354150849Sscottl  /* CS rising edge prepares SROM for a new cycle. */
355150849Sscottl  csr |= TLP_SROM_CS;
356150849Sscottl  WRITE_CSR(TLP_SROM_MII, csr);	/* assert CS */
357150849Sscottl  shift_srom_bits(sc,  6,   4);		/* issue read cmd */
358150849Sscottl  shift_srom_bits(sc, addr, 6);		/* issue address */
359150849Sscottl  for (data=0, i=16; i>=0; i--)		/* read ->17<- bits of data */
360150849Sscottl    {  /* MSB first */
361150849Sscottl    csr = READ_CSR(TLP_SROM_MII);	/* DOUT sampled */
362150849Sscottl    data = (data<<1) | ((csr & TLP_SROM_DOUT) ? 1:0);
363150849Sscottl    csr |=  TLP_SROM_CLK;		/* CLK rising edge */
364150849Sscottl    WRITE_CSR(TLP_SROM_MII, csr);
365150849Sscottl    csr &= ~TLP_SROM_CLK;		/* CLK falling edge */
366150849Sscottl    WRITE_CSR(TLP_SROM_MII, csr);
367150849Sscottl    }
368150849Sscottl  /* Disable SROM access. */
369150849Sscottl  WRITE_CSR(TLP_SROM_MII, TLP_MII_MDOE);
370150849Sscottl
371150849Sscottl  return data;
372150849Sscottl  }
373150849Sscottl
374150849Sscottl/* The SROM is formatted by the mfgr and should NOT be written! */
375150849Sscottl/* But lmcconfig can rewrite it in case it gets overwritten somehow. */
376150849Sscottl/* IOCTL SYSCALL: can sleep. */
377150849Sscottlstatic void
378150849Sscottlwrite_srom(softc_t *sc, u_int8_t addr, u_int16_t data)
379150849Sscottl  {
380150849Sscottl  u_int32_t csr;
381150849Sscottl  int i;
382150849Sscottl
383150849Sscottl  /* Enable SROM access. */
384150849Sscottl  csr = (TLP_SROM_SEL | TLP_SROM_RD | TLP_MII_MDOE);
385150849Sscottl  WRITE_CSR(TLP_SROM_MII, csr);
386150849Sscottl
387150849Sscottl  /* Issue write-enable command. */
388150849Sscottl  csr |= TLP_SROM_CS;
389150849Sscottl  WRITE_CSR(TLP_SROM_MII, csr);	/* assert CS */
390150849Sscottl  shift_srom_bits(sc,  4, 4);		/* issue write enable cmd */
391150849Sscottl  shift_srom_bits(sc, 63, 6);		/* issue address */
392150849Sscottl  csr &= ~TLP_SROM_CS;
393150849Sscottl  WRITE_CSR(TLP_SROM_MII, csr);	/* deassert CS */
394150849Sscottl
395150849Sscottl  /* Issue erase command. */
396150849Sscottl  csr |= TLP_SROM_CS;
397150849Sscottl  WRITE_CSR(TLP_SROM_MII, csr);	/* assert CS */
398150849Sscottl  shift_srom_bits(sc, 7, 4);		/* issue erase cmd */
399150849Sscottl  shift_srom_bits(sc, addr, 6);		/* issue address */
400150849Sscottl  csr &= ~TLP_SROM_CS;
401150849Sscottl  WRITE_CSR(TLP_SROM_MII, csr);	/* deassert CS */
402150849Sscottl
403150849Sscottl  /* Issue write command. */
404150849Sscottl  csr |= TLP_SROM_CS;
405150849Sscottl  WRITE_CSR(TLP_SROM_MII, csr);	/* assert CS */
406150849Sscottl  for (i=0; i<10; i++)  /* 100 ms max wait */
407150849Sscottl    if ((READ_CSR(TLP_SROM_MII) & TLP_SROM_DOUT)==0) SLEEP(10000);
408150849Sscottl  shift_srom_bits(sc, 5, 4);		/* issue write cmd */
409150849Sscottl  shift_srom_bits(sc, addr, 6);		/* issue address */
410150849Sscottl  shift_srom_bits(sc, data, 16);	/* issue data */
411150849Sscottl  csr &= ~TLP_SROM_CS;
412150849Sscottl  WRITE_CSR(TLP_SROM_MII, csr);	/* deassert CS */
413150849Sscottl
414150849Sscottl  /* Issue write-disable command. */
415150849Sscottl  csr |= TLP_SROM_CS;
416150849Sscottl  WRITE_CSR(TLP_SROM_MII, csr);	/* assert CS */
417150849Sscottl  for (i=0; i<10; i++)  /* 100 ms max wait */
418150849Sscottl    if ((READ_CSR(TLP_SROM_MII) & TLP_SROM_DOUT)==0) SLEEP(10000);
419150849Sscottl  shift_srom_bits(sc, 4, 4);		/* issue write disable cmd */
420150849Sscottl  shift_srom_bits(sc, 0, 6);		/* issue address */
421150849Sscottl  csr &= ~TLP_SROM_CS;
422150849Sscottl  WRITE_CSR(TLP_SROM_MII, csr);	/* deassert CS */
423150849Sscottl
424150849Sscottl  /* Disable SROM access. */
425150849Sscottl  WRITE_CSR(TLP_SROM_MII, TLP_MII_MDOE);
426150849Sscottl  }
427150849Sscottl
428150849Sscottl/* Not all boards have BIOS roms. */
429150849Sscottl/* The BIOS ROM is an AMD 29F010 1Mbit (128K by 8) EEPROM. */
430150849Sscottlstatic u_int8_t
431150849Sscottlread_bios(softc_t *sc, u_int32_t addr)
432150849Sscottl  {
433150849Sscottl  u_int32_t srom_mii;
434150849Sscottl
435150849Sscottl  /* Load the BIOS rom address register. */
436150849Sscottl  WRITE_CSR(TLP_BIOS_ROM, addr);
437150849Sscottl
438150849Sscottl  /* Enable the BIOS rom. */
439150849Sscottl  srom_mii = TLP_BIOS_SEL | TLP_BIOS_RD | TLP_MII_MDOE;
440150849Sscottl  WRITE_CSR(TLP_SROM_MII, srom_mii);
441150849Sscottl
442150849Sscottl  /* Wait at least 20 PCI cycles. */
443150849Sscottl  DELAY(20);
444150849Sscottl
445150849Sscottl  /* Read the BIOS rom data. */
446150849Sscottl  srom_mii = READ_CSR(TLP_SROM_MII);
447150849Sscottl
448150849Sscottl  /* Disable the BIOS rom. */
449150849Sscottl  WRITE_CSR(TLP_SROM_MII, TLP_MII_MDOE);
450150849Sscottl
451150849Sscottl  return (u_int8_t)srom_mii & 0xFF;
452150849Sscottl  }
453150849Sscottl
454150849Sscottlstatic void
455150849Sscottlwrite_bios_phys(softc_t *sc, u_int32_t addr, u_int8_t data)
456150849Sscottl  {
457150849Sscottl  u_int32_t srom_mii;
458150849Sscottl
459150849Sscottl  /* Load the BIOS rom address register. */
460150849Sscottl  WRITE_CSR(TLP_BIOS_ROM, addr);
461150849Sscottl
462150849Sscottl  /* Enable the BIOS rom. */
463150849Sscottl  srom_mii = TLP_BIOS_SEL | TLP_BIOS_WR | TLP_MII_MDOE;
464150849Sscottl
465150849Sscottl  /* Load the data into the data register. */
466150849Sscottl  srom_mii = (srom_mii & 0xFFFFFF00) | (data & 0xFF);
467150849Sscottl  WRITE_CSR(TLP_SROM_MII, srom_mii);
468150849Sscottl
469150849Sscottl  /* Wait at least 20 PCI cycles. */
470150849Sscottl  DELAY(20);
471150849Sscottl
472150849Sscottl  /* Disable the BIOS rom. */
473150849Sscottl  WRITE_CSR(TLP_SROM_MII, TLP_MII_MDOE);
474150849Sscottl  }
475150849Sscottl
476150849Sscottl/* IOCTL SYSCALL: can sleep. */
477150849Sscottlstatic void
478150849Sscottlwrite_bios(softc_t *sc, u_int32_t addr, u_int8_t data)
479150849Sscottl  {
480150849Sscottl  u_int8_t read_data;
481150849Sscottl
482150849Sscottl  /* this sequence enables writing */
483150849Sscottl  write_bios_phys(sc, 0x5555, 0xAA);
484150849Sscottl  write_bios_phys(sc, 0x2AAA, 0x55);
485150849Sscottl  write_bios_phys(sc, 0x5555, 0xA0);
486150849Sscottl  write_bios_phys(sc, addr,   data);
487150849Sscottl
488150849Sscottl  /* Wait for the write operation to complete. */
489150849Sscottl  for (;;)  /* interruptable syscall */
490150849Sscottl    {
491150849Sscottl    for (;;)
492150849Sscottl      {
493150849Sscottl      read_data = read_bios(sc, addr);
494150849Sscottl      if ((read_data & 0x80) == (data & 0x80)) break;
495150849Sscottl      if  (read_data & 0x20)
496150849Sscottl        {  /* Data sheet says read it again. */
497150849Sscottl        read_data = read_bios(sc, addr);
498150849Sscottl        if ((read_data & 0x80) == (data & 0x80)) break;
499150849Sscottl        if (DRIVER_DEBUG)
500150849Sscottl          printf("%s: write_bios() failed; rom addr=0x%x\n",
501150849Sscottl           NAME_UNIT, addr);
502150849Sscottl        return;
503150849Sscottl        }
504150849Sscottl      }
505150849Sscottl    read_data = read_bios(sc, addr);
506150849Sscottl    if (read_data == data) break;
507150849Sscottl    }
508150849Sscottl  }
509150849Sscottl
510150849Sscottl/* IOCTL SYSCALL: can sleep. */
511150849Sscottlstatic void
512150849Sscottlerase_bios(softc_t *sc)
513150849Sscottl  {
514150849Sscottl  unsigned char read_data;
515150849Sscottl
516150849Sscottl  /* This sequence enables erasing: */
517150849Sscottl  write_bios_phys(sc, 0x5555, 0xAA);
518150849Sscottl  write_bios_phys(sc, 0x2AAA, 0x55);
519150849Sscottl  write_bios_phys(sc, 0x5555, 0x80);
520150849Sscottl  write_bios_phys(sc, 0x5555, 0xAA);
521150849Sscottl  write_bios_phys(sc, 0x2AAA, 0x55);
522150849Sscottl  write_bios_phys(sc, 0x5555, 0x10);
523150849Sscottl
524150849Sscottl  /* Wait for the erase operation to complete. */
525150849Sscottl  for (;;) /* interruptable syscall */
526150849Sscottl    {
527150849Sscottl    for (;;)
528150849Sscottl      {
529150849Sscottl      read_data = read_bios(sc, 0);
530150849Sscottl      if (read_data & 0x80) break;
531150849Sscottl      if (read_data & 0x20)
532150849Sscottl        {  /* Data sheet says read it again. */
533150849Sscottl        read_data = read_bios(sc, 0);
534150849Sscottl        if (read_data & 0x80) break;
535150849Sscottl        if (DRIVER_DEBUG)
536150849Sscottl          printf("%s: erase_bios() failed\n", NAME_UNIT);
537150849Sscottl        return;
538150849Sscottl        }
539150849Sscottl      }
540150849Sscottl    read_data = read_bios(sc, 0);
541150849Sscottl    if (read_data == 0xFF) break;
542150849Sscottl    }
543150849Sscottl  }
544150849Sscottl
545150849Sscottl/* MDIO is 3-stated between tranactions. */
546150849Sscottl/* MDIO is set up before the RISING edge of MDC; MDC is parked low. */
547150849Sscottlstatic void
548150849Sscottlshift_mii_bits(softc_t *sc, u_int32_t data, u_int32_t len)
549150849Sscottl  {
550150849Sscottl  u_int32_t csr = READ_CSR(TLP_SROM_MII);
551150849Sscottl  for (; len>0; len--)
552150849Sscottl    {  /* MSB first */
553150849Sscottl    if (data & (1<<(len-1)))
554150849Sscottl      csr |=  TLP_MII_MDOUT; /* MDOUT setup */
555150849Sscottl    else
556150849Sscottl      csr &= ~TLP_MII_MDOUT; /* MDOUT setup */
557150849Sscottl    WRITE_CSR(TLP_SROM_MII, csr);
558150849Sscottl    csr |=  TLP_MII_MDC;     /* MDC rising edge */
559150849Sscottl    WRITE_CSR(TLP_SROM_MII, csr);
560150849Sscottl    csr &= ~TLP_MII_MDC;     /* MDC falling edge */
561150849Sscottl    WRITE_CSR(TLP_SROM_MII, csr);
562150849Sscottl    }
563150849Sscottl  }
564150849Sscottl
565150849Sscottl/* The specification for the MII is IEEE Std 802.3 clause 22. */
566150849Sscottl/* MDIO is sampled on the RISING edge of MDC; MDC is parked low. */
567150849Sscottlstatic u_int16_t
568150849Sscottlread_mii(softc_t *sc, u_int8_t regad)
569150849Sscottl  {
570150849Sscottl  int i;
571150849Sscottl  u_int32_t csr;
572150849Sscottl  u_int16_t data = 0;
573150849Sscottl
574150849Sscottl  WRITE_CSR(TLP_SROM_MII, TLP_MII_MDOUT);
575150849Sscottl
576150849Sscottl  shift_mii_bits(sc, 0xFFFFF, 20);	/* preamble */
577150849Sscottl  shift_mii_bits(sc, 0xFFFFF, 20);	/* preamble */
578150849Sscottl  shift_mii_bits(sc, 1, 2);		/* start symbol */
579150849Sscottl  shift_mii_bits(sc, 2, 2);		/* read op */
580150849Sscottl  shift_mii_bits(sc, 0, 5);		/* phyad=0 */
581150849Sscottl  shift_mii_bits(sc, regad, 5);		/* regad */
582150849Sscottl  csr = READ_CSR(TLP_SROM_MII);
583150849Sscottl  csr |= TLP_MII_MDOE;
584150849Sscottl  WRITE_CSR(TLP_SROM_MII, csr);
585150849Sscottl  shift_mii_bits(sc, 0, 2);		/* turn-around */
586150849Sscottl  for (i=15; i>=0; i--)			/* data */
587150849Sscottl    {  /* MSB first */
588150849Sscottl    csr = READ_CSR(TLP_SROM_MII);	/* MDIN sampled */
589150849Sscottl    data = (data<<1) | ((csr & TLP_MII_MDIN) ? 1:0);
590150849Sscottl    csr |=  TLP_MII_MDC;		/* MDC rising edge */
591150849Sscottl    WRITE_CSR(TLP_SROM_MII, csr);
592150849Sscottl    csr &= ~TLP_MII_MDC;		/* MDC falling edge */
593150849Sscottl    WRITE_CSR(TLP_SROM_MII, csr);
594150849Sscottl    }
595150849Sscottl  return data;
596150849Sscottl  }
597150849Sscottl
598150849Sscottlstatic void
599150849Sscottlwrite_mii(softc_t *sc, u_int8_t regad, u_int16_t data)
600150849Sscottl  {
601150849Sscottl  WRITE_CSR(TLP_SROM_MII, TLP_MII_MDOUT);
602150849Sscottl  shift_mii_bits(sc, 0xFFFFF, 20);	/* preamble */
603150849Sscottl  shift_mii_bits(sc, 0xFFFFF, 20);	/* preamble */
604150849Sscottl  shift_mii_bits(sc, 1, 2);		/* start symbol */
605150849Sscottl  shift_mii_bits(sc, 1, 2);		/* write op */
606150849Sscottl  shift_mii_bits(sc, 0, 5);		/* phyad=0 */
607150849Sscottl  shift_mii_bits(sc, regad, 5);		/* regad */
608150849Sscottl  shift_mii_bits(sc, 2, 2);		/* turn-around */
609150849Sscottl  shift_mii_bits(sc, data, 16);		/* data */
610150849Sscottl  WRITE_CSR(TLP_SROM_MII, TLP_MII_MDOE);
611150849Sscottl  if (regad == 16) sc->led_state = data; /* a small optimization */
612150849Sscottl  }
613150849Sscottl
614150849Sscottlstatic void
615150849Sscottlset_mii16_bits(softc_t *sc, u_int16_t bits)
616150849Sscottl  {
617150849Sscottl  u_int16_t mii16 = read_mii(sc, 16);
618150849Sscottl  mii16 |= bits;
619150849Sscottl  write_mii(sc, 16, mii16);
620150849Sscottl  }
621150849Sscottl
622150849Sscottlstatic void
623150849Sscottlclr_mii16_bits(softc_t *sc, u_int16_t bits)
624150849Sscottl  {
625150849Sscottl  u_int16_t mii16 = read_mii(sc, 16);
626150849Sscottl  mii16 &= ~bits;
627150849Sscottl  write_mii(sc, 16, mii16);
628150849Sscottl  }
629150849Sscottl
630150849Sscottlstatic void
631150849Sscottlset_mii17_bits(softc_t *sc, u_int16_t bits)
632150849Sscottl  {
633150849Sscottl  u_int16_t mii17 = read_mii(sc, 17);
634150849Sscottl  mii17 |= bits;
635150849Sscottl  write_mii(sc, 17, mii17);
636150849Sscottl  }
637150849Sscottl
638150849Sscottlstatic void
639150849Sscottlclr_mii17_bits(softc_t *sc, u_int16_t bits)
640150849Sscottl  {
641150849Sscottl  u_int16_t mii17 = read_mii(sc, 17);
642150849Sscottl  mii17 &= ~bits;
643150849Sscottl  write_mii(sc, 17, mii17);
644150849Sscottl  }
645150849Sscottl
646150849Sscottl/*
647150849Sscottl * Watchdog code is more readable if it refreshes LEDs
648150849Sscottl *  once a second whether they need it or not.
649150849Sscottl * But MII refs take 150 uSecs each, so remember the last value
650150849Sscottl *  written to MII16 and avoid LED writes that do nothing.
651150849Sscottl */
652150849Sscottl
653150849Sscottlstatic void
654150849Sscottlled_off(softc_t *sc, u_int16_t led)
655150849Sscottl  {
656150849Sscottl  if ((led & sc->led_state) == led) return;
657150849Sscottl  set_mii16_bits(sc, led);
658150849Sscottl  }
659150849Sscottl
660150849Sscottlstatic void
661150849Sscottlled_on(softc_t *sc, u_int16_t led)
662150849Sscottl  {
663150849Sscottl  if ((led & sc->led_state) == 0) return;
664150849Sscottl  clr_mii16_bits(sc, led);
665150849Sscottl  }
666150849Sscottl
667150849Sscottlstatic void
668150849Sscottlled_inv(softc_t *sc, u_int16_t led)
669150849Sscottl  {
670150849Sscottl  u_int16_t mii16 = read_mii(sc, 16);
671150849Sscottl  mii16 ^= led;
672150849Sscottl  write_mii(sc, 16, mii16);
673150849Sscottl  }
674150849Sscottl
675150849Sscottl/*
676150849Sscottl * T1 & T3 framer registers are accessed through MII regs 17 & 18.
677150849Sscottl * Write the address to MII reg 17 then R/W data through MII reg 18.
678150849Sscottl * The hardware interface is an Intel-style 8-bit muxed A/D bus.
679150849Sscottl */
680150849Sscottlstatic void
681150849Sscottlwrite_framer(softc_t *sc, u_int16_t addr, u_int8_t data)
682150849Sscottl  {
683150849Sscottl  write_mii(sc, 17, addr);
684150849Sscottl  write_mii(sc, 18, data);
685150849Sscottl  }
686150849Sscottl
687150849Sscottlstatic u_int8_t
688150849Sscottlread_framer(softc_t *sc, u_int16_t addr)
689150849Sscottl  {
690150849Sscottl  write_mii(sc, 17, addr);
691150849Sscottl  return (u_int8_t)read_mii(sc, 18);
692150849Sscottl  }
693150849Sscottl
694150849Sscottl/* Tulip's hardware implementation of General Purpose IO
695150849Sscottl *   (GPIO) pins makes life difficult for software.
696150849Sscottl * Bits 7-0 in the Tulip GPIO CSR are used for two purposes
697150849Sscottl *   depending on the state of bit 8.
698150849Sscottl * If bit 8 is 0 then bits 7-0 are "data" bits.
699150849Sscottl * If bit 8 is 1 then bits 7-0 are "direction" bits.
700150849Sscottl * If a direction bit is one, the data bit is an output.
701150849Sscottl * The problem is that the direction bits are WRITE-ONLY.
702150849Sscottl * Software must remember the direction bits in a shadow copy.
703150849Sscottl * (sc->gpio_dir) in order to change some but not all of the bits.
704150849Sscottl * All accesses to the Tulip GPIO register use these five procedures.
705150849Sscottl */
706150849Sscottl
707150849Sscottlstatic void
708150849Sscottlmake_gpio_input(softc_t *sc, u_int32_t bits)
709150849Sscottl  {
710150849Sscottl  sc->gpio_dir &= ~bits;
711150849Sscottl  WRITE_CSR(TLP_GPIO, TLP_GPIO_DIR | (sc->gpio_dir));
712150849Sscottl  }
713150849Sscottl
714150849Sscottlstatic void
715150849Sscottlmake_gpio_output(softc_t *sc, u_int32_t bits)
716150849Sscottl  {
717150849Sscottl  sc->gpio_dir |= bits;
718150849Sscottl  WRITE_CSR(TLP_GPIO, TLP_GPIO_DIR | (sc->gpio_dir));
719150849Sscottl  }
720150849Sscottl
721150849Sscottlstatic u_int32_t
722150849Sscottlread_gpio(softc_t *sc)
723150849Sscottl  {
724150849Sscottl  return READ_CSR(TLP_GPIO);
725150849Sscottl  }
726150849Sscottl
727150849Sscottlstatic void
728150849Sscottlset_gpio_bits(softc_t *sc, u_int32_t bits)
729150849Sscottl  {
730150849Sscottl  WRITE_CSR(TLP_GPIO, (read_gpio(sc) |  bits) & 0xFF);
731150849Sscottl  }
732150849Sscottl
733150849Sscottlstatic void
734150849Sscottlclr_gpio_bits(softc_t *sc, u_int32_t bits)
735150849Sscottl  {
736150849Sscottl  WRITE_CSR(TLP_GPIO, (read_gpio(sc) & ~bits) & 0xFF);
737150849Sscottl  }
738150849Sscottl
739150849Sscottl/* Reset ALL of the flip-flops in the gate array to zero. */
740150849Sscottl/* This does NOT change the gate array programming. */
741150849Sscottl/* Called during initialization so it must not sleep. */
742150849Sscottlstatic void
743150849Sscottlreset_xilinx(softc_t *sc)
744150849Sscottl  {
745150849Sscottl  /* Drive RESET low to force initialization. */
746150849Sscottl  clr_gpio_bits(sc, GPIO_RESET);
747150849Sscottl  make_gpio_output(sc, GPIO_RESET);
748150849Sscottl
749150849Sscottl  /* Hold RESET low for more than 10 uSec. */
750150849Sscottl  DELAY(50);
751150849Sscottl
752150849Sscottl  /* Done with RESET; make it an input. */
753150849Sscottl  make_gpio_input(sc,  GPIO_RESET);
754150849Sscottl  }
755150849Sscottl
756150849Sscottl/* Load Xilinx gate array program from on-board rom. */
757150849Sscottl/* This changes the gate array programming. */
758150849Sscottl/* IOCTL SYSCALL: can sleep. */
759150849Sscottlstatic void
760150849Sscottlload_xilinx_from_rom(softc_t *sc)
761150849Sscottl  {
762150849Sscottl  int i;
763150849Sscottl
764150849Sscottl  /* Drive MODE low to load from ROM rather than GPIO. */
765150849Sscottl  clr_gpio_bits(sc, GPIO_MODE);
766150849Sscottl  make_gpio_output(sc, GPIO_MODE);
767150849Sscottl
768150849Sscottl  /* Drive DP & RESET low to force configuration. */
769150849Sscottl  clr_gpio_bits(sc, GPIO_RESET | GPIO_DP);
770150849Sscottl  make_gpio_output(sc, GPIO_RESET | GPIO_DP);
771150849Sscottl
772150849Sscottl  /* Hold RESET & DP low for more than 10 uSec. */
773150849Sscottl  DELAY(50);
774150849Sscottl
775150849Sscottl  /* Done with RESET & DP; make them inputs. */
776150849Sscottl  make_gpio_input(sc, GPIO_DP | GPIO_RESET);
777150849Sscottl
778150849Sscottl  /* BUSY-WAIT for Xilinx chip to configure itself from ROM bits. */
779150849Sscottl  for (i=0; i<100; i++) /* 1 sec max delay */
780150849Sscottl    if ((read_gpio(sc) & GPIO_DP) == 0) SLEEP(10000);
781150849Sscottl
782150849Sscottl  /* Done with MODE; make it an input. */
783150849Sscottl  make_gpio_input(sc, GPIO_MODE);
784150849Sscottl  }
785150849Sscottl
786150849Sscottl/* Load the Xilinx gate array program from userland bits. */
787150849Sscottl/* This changes the gate array programming. */
788150849Sscottl/* IOCTL SYSCALL: can sleep. */
789150849Sscottlstatic int
790150849Sscottlload_xilinx_from_file(softc_t *sc, char *addr, u_int32_t len)
791150849Sscottl  {
792150849Sscottl  char *data;
793150849Sscottl  int i, j, error;
794150849Sscottl
795150849Sscottl  /* Get some pages to hold the Xilinx bits; biggest file is < 6 KB. */
796150849Sscottl  if (len > 8192) return EFBIG;  /* too big */
797150849Sscottl  data = malloc(len, M_DEVBUF, M_WAITOK);
798150849Sscottl  if (data == NULL) return ENOMEM;
799150849Sscottl
800150849Sscottl  /* Copy the Xilinx bits from userland. */
801150849Sscottl  if ((error = copyin(addr, data, len)))
802150849Sscottl    {
803150849Sscottl    free(data, M_DEVBUF);
804150849Sscottl    return error;
805150849Sscottl    }
806150849Sscottl
807150849Sscottl  /* Drive MODE high to load from GPIO rather than ROM. */
808150849Sscottl  set_gpio_bits(sc, GPIO_MODE);
809150849Sscottl  make_gpio_output(sc, GPIO_MODE);
810150849Sscottl
811150849Sscottl  /* Drive DP & RESET low to force configuration. */
812150849Sscottl  clr_gpio_bits(sc, GPIO_RESET | GPIO_DP);
813150849Sscottl  make_gpio_output(sc, GPIO_RESET | GPIO_DP);
814150849Sscottl
815150849Sscottl  /* Hold RESET & DP low for more than 10 uSec. */
816150849Sscottl  DELAY(50);
817150849Sscottl
818150849Sscottl  /* Done with RESET & DP; make them inputs. */
819150849Sscottl  make_gpio_input(sc, GPIO_RESET | GPIO_DP);
820150849Sscottl
821150849Sscottl  /* BUSY-WAIT for Xilinx chip to clear its config memory. */
822150849Sscottl  make_gpio_input(sc, GPIO_INIT);
823150849Sscottl  for (i=0; i<10000; i++) /* 1 sec max delay */
824150849Sscottl    if ((read_gpio(sc) & GPIO_INIT)==0) SLEEP(10000);
825150849Sscottl
826150849Sscottl  /* Configure CLK and DATA as outputs. */
827150849Sscottl  set_gpio_bits(sc, GPIO_CLK);  /* park CLK high */
828150849Sscottl  make_gpio_output(sc, GPIO_CLK | GPIO_DATA);
829150849Sscottl
830150849Sscottl  /* Write bits to Xilinx; CLK is parked HIGH. */
831150849Sscottl  /* DATA is set up before the RISING edge of CLK. */
832150849Sscottl  for (i=0; i<len; i++)
833150849Sscottl    for (j=0; j<8; j++)
834150849Sscottl      {  /* LSB first */
835150849Sscottl      if ((data[i] & (1<<j)) != 0)
836150849Sscottl        set_gpio_bits(sc, GPIO_DATA); /* DATA setup */
837150849Sscottl      else
838150849Sscottl        clr_gpio_bits(sc, GPIO_DATA); /* DATA setup */
839150849Sscottl      clr_gpio_bits(sc, GPIO_CLK); /* CLK falling edge */
840150849Sscottl      set_gpio_bits(sc, GPIO_CLK); /* CLK rising edge */
841150849Sscottl      }
842150849Sscottl
843150849Sscottl  /* Stop driving all Xilinx-related signals. */
844150849Sscottl  /* Pullup and pulldown resistors take over. */
845150849Sscottl  make_gpio_input(sc, GPIO_CLK | GPIO_DATA | GPIO_MODE);
846150849Sscottl
847150849Sscottl  free(data, M_DEVBUF);
848150849Sscottl  return 0;
849150849Sscottl  }
850150849Sscottl
851150849Sscottl/* Write fragments of a command into the synthesized oscillator. */
852150849Sscottl/* DATA is set up before the RISING edge of CLK.  CLK is parked low. */
853150849Sscottlstatic void
854150849Sscottlshift_synth_bits(softc_t *sc, u_int32_t data, u_int32_t len)
855150849Sscottl  {
856150849Sscottl  int i;
857150849Sscottl
858150849Sscottl  for (i=0; i<len; i++)
859150849Sscottl    { /* LSB first */
860150849Sscottl    if ((data & (1<<i)) != 0)
861150849Sscottl      set_gpio_bits(sc, GPIO_DATA); /* DATA setup */
862150849Sscottl    else
863150849Sscottl      clr_gpio_bits(sc, GPIO_DATA); /* DATA setup */
864150849Sscottl    set_gpio_bits(sc, GPIO_CLK);    /* CLK rising edge */
865150849Sscottl    clr_gpio_bits(sc, GPIO_CLK);    /* CLK falling edge */
866150849Sscottl    }
867150849Sscottl  }
868150849Sscottl
869150849Sscottl/* Write a command to the synthesized oscillator on SSI and HSSIc. */
870150849Sscottlstatic void
871150849Sscottlwrite_synth(softc_t *sc, struct synth *synth)
872150849Sscottl  {
873150849Sscottl  /* SSI cards have a programmable prescaler */
874150849Sscottl  if (sc->status.card_type == TLP_CSID_SSI)
875150849Sscottl    {
876150849Sscottl    if (synth->prescale == 9) /* divide by 512 */
877150849Sscottl      set_mii17_bits(sc, MII17_SSI_PRESCALE);
878150849Sscottl    else                      /* divide by  32 */
879150849Sscottl      clr_mii17_bits(sc, MII17_SSI_PRESCALE);
880150849Sscottl    }
881150849Sscottl
882150849Sscottl  clr_gpio_bits(sc,    GPIO_DATA | GPIO_CLK);
883150849Sscottl  make_gpio_output(sc, GPIO_DATA | GPIO_CLK);
884150849Sscottl
885150849Sscottl  /* SYNTH is a low-true chip enable for the AV9110 chip. */
886150849Sscottl  set_gpio_bits(sc,    GPIO_SSI_SYNTH);
887150849Sscottl  make_gpio_output(sc, GPIO_SSI_SYNTH);
888150849Sscottl  clr_gpio_bits(sc,    GPIO_SSI_SYNTH);
889150849Sscottl
890150849Sscottl  /* Serially shift the command into the AV9110 chip. */
891150849Sscottl  shift_synth_bits(sc, synth->n, 7);
892150849Sscottl  shift_synth_bits(sc, synth->m, 7);
893150849Sscottl  shift_synth_bits(sc, synth->v, 1);
894150849Sscottl  shift_synth_bits(sc, synth->x, 2);
895150849Sscottl  shift_synth_bits(sc, synth->r, 2);
896150849Sscottl  shift_synth_bits(sc, 0x16, 5); /* enable clk/x output */
897150849Sscottl
898150849Sscottl  /* SYNTH (chip enable) going high ends the command. */
899150849Sscottl  set_gpio_bits(sc,   GPIO_SSI_SYNTH);
900150849Sscottl  make_gpio_input(sc, GPIO_SSI_SYNTH);
901150849Sscottl
902150849Sscottl  /* Stop driving serial-related signals; pullups/pulldowns take over. */
903150849Sscottl  make_gpio_input(sc, GPIO_DATA | GPIO_CLK);
904150849Sscottl
905150849Sscottl  /* remember the new synthesizer parameters */
906150849Sscottl  if (&sc->config.synth != synth) sc->config.synth = *synth;
907150849Sscottl  }
908150849Sscottl
909150849Sscottl/* Write a command to the DAC controlling the VCXO on some T3 adapters. */
910150849Sscottl/* The DAC is a TI-TLV5636: 12-bit resolution and a serial interface. */
911150849Sscottl/* DATA is set up before the FALLING edge of CLK.  CLK is parked HIGH. */
912150849Sscottlstatic void
913150849Sscottlwrite_dac(softc_t *sc, u_int16_t data)
914150849Sscottl  {
915150849Sscottl  int i;
916150849Sscottl
917150849Sscottl  /* Prepare to use DATA and CLK. */
918150849Sscottl  set_gpio_bits(sc,    GPIO_DATA | GPIO_CLK);
919150849Sscottl  make_gpio_output(sc, GPIO_DATA | GPIO_CLK);
920150849Sscottl
921150849Sscottl  /* High-to-low transition prepares DAC for new value. */
922150849Sscottl  set_gpio_bits(sc,    GPIO_T3_DAC);
923150849Sscottl  make_gpio_output(sc, GPIO_T3_DAC);
924150849Sscottl  clr_gpio_bits(sc,    GPIO_T3_DAC);
925150849Sscottl
926150849Sscottl  /* Serially shift command bits into DAC. */
927150849Sscottl  for (i=0; i<16; i++)
928150849Sscottl    { /* MSB first */
929150849Sscottl    if ((data & (1<<(15-i))) != 0)
930150849Sscottl      set_gpio_bits(sc, GPIO_DATA); /* DATA setup */
931150849Sscottl    else
932150849Sscottl      clr_gpio_bits(sc, GPIO_DATA); /* DATA setup */
933150849Sscottl    clr_gpio_bits(sc, GPIO_CLK);    /* CLK falling edge */
934150849Sscottl    set_gpio_bits(sc, GPIO_CLK);    /* CLK rising edge */
935150849Sscottl    }
936150849Sscottl
937150849Sscottl  /* Done with DAC; make it an input; loads new value into DAC. */
938150849Sscottl  set_gpio_bits(sc,   GPIO_T3_DAC);
939150849Sscottl  make_gpio_input(sc, GPIO_T3_DAC);
940150849Sscottl
941150849Sscottl  /* Stop driving serial-related signals; pullups/pulldowns take over. */
942150849Sscottl  make_gpio_input(sc, GPIO_DATA | GPIO_CLK);
943150849Sscottl  }
944150849Sscottl
945150849Sscottl/* begin HSSI card code */
946150849Sscottl
947150849Sscottl/* Must not sleep. */
948150849Sscottlstatic void
949150849Sscottlhssi_config(softc_t *sc)
950150849Sscottl  {
951150849Sscottl  if (sc->status.card_type == 0)
952150849Sscottl    { /* defaults */
953150849Sscottl    sc->status.card_type  = READ_PCI_CFG(sc, TLP_CSID);
954150849Sscottl    sc->config.crc_len    = CFG_CRC_16;
955150849Sscottl    sc->config.loop_back  = CFG_LOOP_NONE;
956150849Sscottl    sc->config.tx_clk_src = CFG_CLKMUX_ST;
957150849Sscottl    sc->config.dte_dce    = CFG_DTE;
958150849Sscottl    sc->config.synth.n    = 52; /* 52.000 Mbs */
959150849Sscottl    sc->config.synth.m    = 5;
960150849Sscottl    sc->config.synth.v    = 0;
961150849Sscottl    sc->config.synth.x    = 0;
962150849Sscottl    sc->config.synth.r    = 0;
963150849Sscottl    sc->config.synth.prescale = 2;
964150849Sscottl    }
965150849Sscottl
966150849Sscottl  /* set CRC length */
967150849Sscottl  if (sc->config.crc_len == CFG_CRC_32)
968150849Sscottl    set_mii16_bits(sc, MII16_HSSI_CRC32);
969150849Sscottl  else
970150849Sscottl    clr_mii16_bits(sc, MII16_HSSI_CRC32);
971150849Sscottl
972150849Sscottl  /* Assert pin LA in HSSI conn: ask modem for local loop. */
973150849Sscottl  if (sc->config.loop_back == CFG_LOOP_LL)
974150849Sscottl    set_mii16_bits(sc, MII16_HSSI_LA);
975150849Sscottl  else
976150849Sscottl    clr_mii16_bits(sc, MII16_HSSI_LA);
977150849Sscottl
978150849Sscottl  /* Assert pin LB in HSSI conn: ask modem for remote loop. */
979150849Sscottl  if (sc->config.loop_back == CFG_LOOP_RL)
980150849Sscottl    set_mii16_bits(sc, MII16_HSSI_LB);
981150849Sscottl  else
982150849Sscottl    clr_mii16_bits(sc, MII16_HSSI_LB);
983150849Sscottl
984150849Sscottl  if (sc->status.card_type == TLP_CSID_HSSI)
985150849Sscottl    {
986150849Sscottl    /* set TXCLK src */
987150849Sscottl    if (sc->config.tx_clk_src == CFG_CLKMUX_ST)
988150849Sscottl      set_gpio_bits(sc, GPIO_HSSI_TXCLK);
989150849Sscottl    else
990150849Sscottl      clr_gpio_bits(sc, GPIO_HSSI_TXCLK);
991150849Sscottl    make_gpio_output(sc, GPIO_HSSI_TXCLK);
992150849Sscottl    }
993150849Sscottl  else if (sc->status.card_type == TLP_CSID_HSSIc)
994150849Sscottl    {  /* cPCI HSSI rev C has extra features */
995150849Sscottl    /* Set TXCLK source. */
996150849Sscottl    u_int16_t mii16 = read_mii(sc, 16);
997150849Sscottl    mii16 &= ~MII16_HSSI_CLKMUX;
998150849Sscottl    mii16 |= (sc->config.tx_clk_src&3)<<13;
999150849Sscottl    write_mii(sc, 16, mii16);
1000150849Sscottl
1001150849Sscottl    /* cPCI HSSI implements loopback towards the net. */
1002150849Sscottl    if (sc->config.loop_back == CFG_LOOP_LINE)
1003150849Sscottl      set_mii16_bits(sc, MII16_HSSI_LOOP);
1004150849Sscottl    else
1005150849Sscottl      clr_mii16_bits(sc, MII16_HSSI_LOOP);
1006150849Sscottl
1007150849Sscottl    /* Set DTE/DCE mode. */
1008150849Sscottl    if (sc->config.dte_dce == CFG_DCE)
1009150849Sscottl      set_gpio_bits(sc, GPIO_HSSI_DCE);
1010150849Sscottl    else
1011150849Sscottl      clr_gpio_bits(sc, GPIO_HSSI_DCE);
1012150849Sscottl    make_gpio_output(sc, GPIO_HSSI_DCE);
1013150849Sscottl
1014150849Sscottl    /* Program the synthesized oscillator. */
1015150849Sscottl    write_synth(sc, &sc->config.synth);
1016150849Sscottl    }
1017150849Sscottl  }
1018150849Sscottl
1019150849Sscottlstatic void
1020150849Sscottlhssi_ident(softc_t *sc)
1021150849Sscottl  {
1022150849Sscottl  }
1023150849Sscottl
1024150849Sscottl/* Called once a second; must not sleep. */
1025150849Sscottlstatic int
1026150849Sscottlhssi_watchdog(softc_t *sc)
1027150849Sscottl  {
1028150849Sscottl  u_int16_t mii16 = read_mii(sc, 16) & MII16_HSSI_MODEM;
1029150849Sscottl  int link_status = STATUS_UP;
1030150849Sscottl
1031150849Sscottl  led_inv(sc, MII16_HSSI_LED_UL);  /* Software is alive. */
1032150849Sscottl  led_on(sc, MII16_HSSI_LED_LL);  /* always on (SSI cable) */
1033150849Sscottl
1034150849Sscottl  /* Check the transmit clock. */
1035150849Sscottl  if (sc->status.tx_speed == 0)
1036150849Sscottl    {
1037150849Sscottl    led_on(sc, MII16_HSSI_LED_UR);
1038150849Sscottl    link_status = STATUS_DOWN;
1039150849Sscottl    }
1040150849Sscottl  else
1041150849Sscottl    led_off(sc, MII16_HSSI_LED_UR);
1042150849Sscottl
1043150849Sscottl  /* Is the modem ready? */
1044150849Sscottl  if ((mii16 & MII16_HSSI_CA) == 0)
1045150849Sscottl    {
1046150849Sscottl    led_off(sc, MII16_HSSI_LED_LR);
1047150849Sscottl    link_status = STATUS_DOWN;
1048150849Sscottl    }
1049150849Sscottl  else
1050150849Sscottl    led_on(sc, MII16_HSSI_LED_LR);
1051150849Sscottl
1052150849Sscottl  /* Print the modem control signals if they changed. */
1053150849Sscottl  if ((DRIVER_DEBUG) && (mii16 != sc->last_mii16))
1054150849Sscottl    {
1055150849Sscottl    char *on = "ON ", *off = "OFF";
1056150849Sscottl    printf("%s: TA=%s CA=%s LA=%s LB=%s LC=%s TM=%s\n", NAME_UNIT,
1057150849Sscottl     (mii16 & MII16_HSSI_TA) ? on : off,
1058150849Sscottl     (mii16 & MII16_HSSI_CA) ? on : off,
1059150849Sscottl     (mii16 & MII16_HSSI_LA) ? on : off,
1060150849Sscottl     (mii16 & MII16_HSSI_LB) ? on : off,
1061150849Sscottl     (mii16 & MII16_HSSI_LC) ? on : off,
1062150849Sscottl     (mii16 & MII16_HSSI_TM) ? on : off);
1063150849Sscottl    }
1064150849Sscottl
1065150849Sscottl  /* SNMP one-second-report */
1066150849Sscottl  sc->status.snmp.hssi.sigs = mii16 & MII16_HSSI_MODEM;
1067150849Sscottl
1068150849Sscottl  /* Remember this state until next time. */
1069150849Sscottl  sc->last_mii16 = mii16;
1070150849Sscottl
1071150849Sscottl  /* If a loop back is in effect, link status is UP */
1072150849Sscottl  if (sc->config.loop_back != CFG_LOOP_NONE)
1073150849Sscottl    link_status = STATUS_UP;
1074150849Sscottl
1075150849Sscottl  return link_status;
1076150849Sscottl  }
1077150849Sscottl
1078150849Sscottl/* IOCTL SYSCALL: can sleep (but doesn't). */
1079150849Sscottlstatic int
1080150849Sscottlhssi_ioctl(softc_t *sc, struct ioctl *ioctl)
1081150849Sscottl  {
1082150849Sscottl  int error = 0;
1083150849Sscottl
1084150849Sscottl  if (ioctl->cmd == IOCTL_SNMP_SIGS)
1085150849Sscottl    {
1086150849Sscottl    u_int16_t mii16 = read_mii(sc, 16);
1087150849Sscottl    mii16 &= ~MII16_HSSI_MODEM;
1088150849Sscottl    mii16 |= (MII16_HSSI_MODEM & ioctl->data);
1089150849Sscottl    write_mii(sc, 16, mii16);
1090150849Sscottl    }
1091150849Sscottl  else if (ioctl->cmd == IOCTL_SET_STATUS)
1092150849Sscottl    {
1093150849Sscottl    if (ioctl->data != 0)
1094150849Sscottl      set_mii16_bits(sc, MII16_HSSI_TA);
1095150849Sscottl    else
1096150849Sscottl      clr_mii16_bits(sc, MII16_HSSI_TA);
1097150849Sscottl    }
1098150849Sscottl  else
1099150849Sscottl    error = EINVAL;
1100150849Sscottl
1101150849Sscottl  return error;
1102150849Sscottl  }
1103150849Sscottl
1104150849Sscottl/* begin DS3 card code */
1105150849Sscottl
1106150849Sscottl/* Must not sleep. */
1107150849Sscottlstatic void
1108150849Sscottlt3_config(softc_t *sc)
1109150849Sscottl  {
1110150849Sscottl  int i;
1111150849Sscottl  u_int8_t ctl1;
1112150849Sscottl
1113150849Sscottl  if (sc->status.card_type == 0)
1114150849Sscottl    { /* defaults */
1115150849Sscottl    sc->status.card_type  = TLP_CSID_T3;
1116150849Sscottl    sc->config.crc_len    = CFG_CRC_16;
1117150849Sscottl    sc->config.loop_back  = CFG_LOOP_NONE;
1118150849Sscottl    sc->config.format     = CFG_FORMAT_T3CPAR;
1119150849Sscottl    sc->config.cable_len  = 10; /* meters */
1120150849Sscottl    sc->config.scrambler  = CFG_SCRAM_DL_KEN;
1121150849Sscottl    sc->config.tx_clk_src = CFG_CLKMUX_INT;
1122150849Sscottl
1123150849Sscottl    /* Center the VCXO -- get within 20 PPM of 44736000. */
1124150849Sscottl    write_dac(sc, 0x9002); /* set Vref = 2.048 volts */
1125150849Sscottl    write_dac(sc, 2048); /* range is 0..4095 */
1126150849Sscottl    }
1127150849Sscottl
1128150849Sscottl  /* Set cable length. */
1129150849Sscottl  if (sc->config.cable_len > 30)
1130150849Sscottl    clr_mii16_bits(sc, MII16_DS3_ZERO);
1131150849Sscottl  else
1132150849Sscottl    set_mii16_bits(sc, MII16_DS3_ZERO);
1133150849Sscottl
1134150849Sscottl  /* Set payload scrambler polynomial. */
1135150849Sscottl  if (sc->config.scrambler == CFG_SCRAM_LARS)
1136150849Sscottl    set_mii16_bits(sc, MII16_DS3_POLY);
1137150849Sscottl  else
1138150849Sscottl    clr_mii16_bits(sc, MII16_DS3_POLY);
1139150849Sscottl
1140150849Sscottl  /* Set payload scrambler on/off. */
1141150849Sscottl  if (sc->config.scrambler == CFG_SCRAM_OFF)
1142150849Sscottl    clr_mii16_bits(sc, MII16_DS3_SCRAM);
1143150849Sscottl  else
1144150849Sscottl    set_mii16_bits(sc, MII16_DS3_SCRAM);
1145150849Sscottl
1146150849Sscottl  /* Set CRC length. */
1147150849Sscottl  if (sc->config.crc_len == CFG_CRC_32)
1148150849Sscottl    set_mii16_bits(sc, MII16_DS3_CRC32);
1149150849Sscottl  else
1150150849Sscottl    clr_mii16_bits(sc, MII16_DS3_CRC32);
1151150849Sscottl
1152150849Sscottl  /* Loopback towards host thru the line interface. */
1153150849Sscottl  if (sc->config.loop_back == CFG_LOOP_OTHER)
1154150849Sscottl    set_mii16_bits(sc, MII16_DS3_TRLBK);
1155150849Sscottl  else
1156150849Sscottl    clr_mii16_bits(sc, MII16_DS3_TRLBK);
1157150849Sscottl
1158150849Sscottl  /* Loopback towards network thru the line interface. */
1159150849Sscottl  if (sc->config.loop_back == CFG_LOOP_LINE)
1160150849Sscottl    set_mii16_bits(sc, MII16_DS3_LNLBK);
1161150849Sscottl  else if (sc->config.loop_back == CFG_LOOP_DUAL)
1162150849Sscottl    set_mii16_bits(sc, MII16_DS3_LNLBK);
1163150849Sscottl  else
1164150849Sscottl    clr_mii16_bits(sc, MII16_DS3_LNLBK);
1165150849Sscottl
1166150849Sscottl  /* Configure T3 framer chip; write EVERY writeable register. */
1167150849Sscottl  ctl1 = CTL1_SER | CTL1_XTX;
1168150849Sscottl  if (sc->config.loop_back == CFG_LOOP_INWARD) ctl1 |= CTL1_3LOOP;
1169150849Sscottl  if (sc->config.loop_back == CFG_LOOP_DUAL)   ctl1 |= CTL1_3LOOP;
1170150849Sscottl  if (sc->config.format == CFG_FORMAT_T3M13)   ctl1 |= CTL1_M13MODE;
1171150849Sscottl  write_framer(sc, T3CSR_CTL1,     ctl1);
1172150849Sscottl  write_framer(sc, T3CSR_TX_FEAC,  CTL5_EMODE);
1173150849Sscottl  write_framer(sc, T3CSR_CTL8,     CTL8_FBEC);
1174150849Sscottl  write_framer(sc, T3CSR_CTL12,    CTL12_DLCB1 | CTL12_C21 | CTL12_MCB1);
1175150849Sscottl  write_framer(sc, T3CSR_DBL_FEAC, 0);
1176150849Sscottl  write_framer(sc, T3CSR_CTL14,    CTL14_RGCEN | CTL14_TGCEN);
1177150849Sscottl  write_framer(sc, T3CSR_INTEN,    0);
1178150849Sscottl  write_framer(sc, T3CSR_CTL20,    CTL20_CVEN);
1179150849Sscottl
1180150849Sscottl  /* Clear error counters and latched error bits */
1181150849Sscottl  /*  that may have happened while initializing. */
1182150849Sscottl  for (i=0; i<21; i++) read_framer(sc, i);
1183150849Sscottl  }
1184150849Sscottl
1185150849Sscottlstatic void
1186150849Sscottlt3_ident(softc_t *sc)
1187150849Sscottl  {
1188150849Sscottl  printf(", TXC03401 rev B");
1189150849Sscottl  }
1190150849Sscottl
1191150849Sscottl/* Called once a second; must not sleep. */
1192150849Sscottlstatic int
1193150849Sscottlt3_watchdog(softc_t *sc)
1194150849Sscottl  {
1195150849Sscottl  u_int16_t CV;
1196150849Sscottl  u_int8_t CERR, PERR, MERR, FERR, FEBE;
1197150849Sscottl  u_int8_t ctl1, stat16, feac;
1198150849Sscottl  int link_status = STATUS_UP;
1199150849Sscottl  u_int16_t mii16;
1200150849Sscottl
1201150849Sscottl  /* Read the alarm registers. */
1202150849Sscottl  ctl1   = read_framer(sc, T3CSR_CTL1);
1203150849Sscottl  stat16 = read_framer(sc, T3CSR_STAT16);
1204150849Sscottl  mii16  = read_mii(sc, 16);
1205150849Sscottl
1206150849Sscottl  /* Always ignore the RTLOC alarm bit. */
1207150849Sscottl  stat16 &= ~STAT16_RTLOC;
1208150849Sscottl
1209150849Sscottl  /* Software is alive. */
1210150849Sscottl  led_inv(sc, MII16_DS3_LED_GRN);
1211150849Sscottl
1212150849Sscottl  /* Receiving Alarm Indication Signal (AIS). */
1213150849Sscottl  if ((stat16 & STAT16_RAIS) != 0) /* receiving ais */
1214150849Sscottl    led_on(sc, MII16_DS3_LED_BLU);
1215150849Sscottl  else if (ctl1 & CTL1_TXAIS) /* sending ais */
1216150849Sscottl    led_inv(sc, MII16_DS3_LED_BLU);
1217150849Sscottl  else
1218150849Sscottl    led_off(sc, MII16_DS3_LED_BLU);
1219150849Sscottl
1220150849Sscottl  /* Receiving Remote Alarm Indication (RAI). */
1221150849Sscottl  if ((stat16 & STAT16_XERR) != 0) /* receiving rai */
1222150849Sscottl    led_on(sc, MII16_DS3_LED_YEL);
1223150849Sscottl  else if ((ctl1 & CTL1_XTX) == 0) /* sending rai */
1224150849Sscottl    led_inv(sc, MII16_DS3_LED_YEL);
1225150849Sscottl  else
1226150849Sscottl    led_off(sc, MII16_DS3_LED_YEL);
1227150849Sscottl
1228150849Sscottl  /* If certain status bits are set then the link is 'down'. */
1229150849Sscottl  /* The bad bits are: rxlos rxoof rxais rxidl xerr. */
1230150849Sscottl  if ((stat16 & ~(STAT16_FEAC | STAT16_SEF)) != 0)
1231150849Sscottl    link_status = STATUS_DOWN;
1232150849Sscottl
1233150849Sscottl  /* Declare local Red Alarm if the link is down. */
1234150849Sscottl  if (link_status == STATUS_DOWN)
1235150849Sscottl    led_on(sc, MII16_DS3_LED_RED);
1236150849Sscottl  else if (sc->loop_timer != 0) /* loopback is active */
1237150849Sscottl    led_inv(sc, MII16_DS3_LED_RED);
1238150849Sscottl  else
1239150849Sscottl    led_off(sc, MII16_DS3_LED_RED);
1240150849Sscottl
1241150849Sscottl  /* Print latched error bits if they changed. */
1242150849Sscottl  if ((DRIVER_DEBUG) && ((stat16 & ~STAT16_FEAC) != sc->last_stat16))
1243150849Sscottl    {
1244150849Sscottl    char *on = "ON ", *off = "OFF";
1245150849Sscottl    printf("%s: RLOS=%s ROOF=%s RAIS=%s RIDL=%s SEF=%s XERR=%s\n",
1246150849Sscottl     NAME_UNIT,
1247150849Sscottl     (stat16 & STAT16_RLOS) ? on : off,
1248150849Sscottl     (stat16 & STAT16_ROOF) ? on : off,
1249150849Sscottl     (stat16 & STAT16_RAIS) ? on : off,
1250150849Sscottl     (stat16 & STAT16_RIDL) ? on : off,
1251150849Sscottl     (stat16 & STAT16_SEF)  ? on : off,
1252150849Sscottl     (stat16 & STAT16_XERR) ? on : off);
1253150849Sscottl    }
1254150849Sscottl
1255150849Sscottl  /* Check and print error counters if non-zero. */
1256150849Sscottl  CV   = read_framer(sc, T3CSR_CVHI)<<8;
1257150849Sscottl  CV  += read_framer(sc, T3CSR_CVLO);
1258150849Sscottl  PERR = read_framer(sc, T3CSR_PERR);
1259150849Sscottl  CERR = read_framer(sc, T3CSR_CERR);
1260150849Sscottl  FERR = read_framer(sc, T3CSR_FERR);
1261150849Sscottl  MERR = read_framer(sc, T3CSR_MERR);
1262150849Sscottl  FEBE = read_framer(sc, T3CSR_FEBE);
1263150849Sscottl
1264150849Sscottl  /* CV is invalid during LOS. */
1265150849Sscottl  if ((stat16 & STAT16_RLOS)!=0) CV = 0;
1266150849Sscottl  /* CERR & FEBE are invalid in M13 mode */
1267150849Sscottl  if (sc->config.format == CFG_FORMAT_T3M13) CERR = FEBE = 0;
1268150849Sscottl  /* FEBE is invalid during AIS. */
1269150849Sscottl  if ((stat16 & STAT16_RAIS)!=0) FEBE = 0;
1270150849Sscottl  if (DRIVER_DEBUG && (CV || PERR || CERR || FERR || MERR || FEBE))
1271150849Sscottl    printf("%s: CV=%u PERR=%u CERR=%u FERR=%u MERR=%u FEBE=%u\n",
1272150849Sscottl     NAME_UNIT, CV,   PERR,   CERR,   FERR,   MERR,   FEBE);
1273150849Sscottl
1274150849Sscottl  /* Driver keeps crude link-level error counters (SNMP is better). */
1275150849Sscottl  sc->status.cntrs.lcv_errs  += CV;
1276150849Sscottl  sc->status.cntrs.par_errs  += PERR;
1277150849Sscottl  sc->status.cntrs.cpar_errs += CERR;
1278150849Sscottl  sc->status.cntrs.frm_errs  += FERR;
1279150849Sscottl  sc->status.cntrs.mfrm_errs += MERR;
1280150849Sscottl  sc->status.cntrs.febe_errs += FEBE;
1281150849Sscottl
1282150849Sscottl  /* Check for FEAC messages (FEAC not defined in M13 mode). */
1283150849Sscottl  if (FORMAT_T3CPAR && (stat16 & STAT16_FEAC)) do
1284150849Sscottl    {
1285150849Sscottl    feac = read_framer(sc, T3CSR_FEAC_STK);
1286150849Sscottl    if ((feac & FEAC_STK_VALID)==0) break;
1287150849Sscottl    /* Ignore RxFEACs while a far end loopback has been requested. */
1288150849Sscottl    if ((sc->status.snmp.t3.line & TLOOP_FAR_LINE)!=0) continue;
1289150849Sscottl    switch (feac & FEAC_STK_FEAC)
1290150849Sscottl      {
1291150849Sscottl      case T3BOP_LINE_UP:   break;
1292150849Sscottl      case T3BOP_LINE_DOWN: break;
1293150849Sscottl      case T3BOP_LOOP_DS3:
1294150849Sscottl        {
1295150849Sscottl        if (sc->last_FEAC == T3BOP_LINE_DOWN)
1296150849Sscottl          {
1297150849Sscottl          if (DRIVER_DEBUG)
1298150849Sscottl            printf("%s: Received a 'line loopback deactivate' FEAC msg\n", NAME_UNIT);
1299150849Sscottl          clr_mii16_bits(sc, MII16_DS3_LNLBK);
1300150849Sscottl          sc->loop_timer = 0;
1301150849Sscottl	  }
1302150849Sscottl        if (sc->last_FEAC == T3BOP_LINE_UP)
1303150849Sscottl          {
1304150849Sscottl          if (DRIVER_DEBUG)
1305150849Sscottl            printf("%s: Received a 'line loopback activate' FEAC msg\n", NAME_UNIT);
1306150849Sscottl          set_mii16_bits(sc, MII16_DS3_LNLBK);
1307150849Sscottl          sc->loop_timer = 300;
1308150849Sscottl	  }
1309150849Sscottl        break;
1310150849Sscottl        }
1311150849Sscottl      case T3BOP_OOF:
1312150849Sscottl        {
1313150849Sscottl        if (DRIVER_DEBUG)
1314150849Sscottl          printf("%s: Received a 'far end LOF' FEAC msg\n", NAME_UNIT);
1315150849Sscottl        break;
1316150849Sscottl	}
1317150849Sscottl      case T3BOP_IDLE:
1318150849Sscottl        {
1319150849Sscottl        if (DRIVER_DEBUG)
1320150849Sscottl          printf("%s: Received a 'far end IDL' FEAC msg\n", NAME_UNIT);
1321150849Sscottl        break;
1322150849Sscottl	}
1323150849Sscottl      case T3BOP_AIS:
1324150849Sscottl        {
1325150849Sscottl        if (DRIVER_DEBUG)
1326150849Sscottl          printf("%s: Received a 'far end AIS' FEAC msg\n", NAME_UNIT);
1327150849Sscottl        break;
1328150849Sscottl	}
1329150849Sscottl      case T3BOP_LOS:
1330150849Sscottl        {
1331150849Sscottl        if (DRIVER_DEBUG)
1332150849Sscottl          printf("%s: Received a 'far end LOS' FEAC msg\n", NAME_UNIT);
1333150849Sscottl        break;
1334150849Sscottl	}
1335150849Sscottl      default:
1336150849Sscottl        {
1337150849Sscottl        if (DRIVER_DEBUG)
1338150849Sscottl          printf("%s: Received a 'type 0x%02X' FEAC msg\n", NAME_UNIT, feac & FEAC_STK_FEAC);
1339150849Sscottl        break;
1340150849Sscottl	}
1341150849Sscottl      }
1342150849Sscottl    sc->last_FEAC = feac & FEAC_STK_FEAC;
1343150849Sscottl    } while ((feac & FEAC_STK_MORE) != 0);
1344150849Sscottl  stat16 &= ~STAT16_FEAC;
1345150849Sscottl
1346150849Sscottl  /* Send Service-Affecting priority FEAC messages */
1347150849Sscottl  if (((sc->last_stat16 ^ stat16) & 0xF0) && (FORMAT_T3CPAR))
1348150849Sscottl    {
1349150849Sscottl    /* Transmit continuous FEACs */
1350150849Sscottl    write_framer(sc, T3CSR_CTL14,
1351150849Sscottl     read_framer(sc, T3CSR_CTL14) & ~CTL14_FEAC10);
1352150849Sscottl    if      ((stat16 & STAT16_RLOS)!=0)
1353150849Sscottl      write_framer(sc, T3CSR_TX_FEAC, 0xC0 + T3BOP_LOS);
1354150849Sscottl    else if ((stat16 & STAT16_ROOF)!=0)
1355150849Sscottl      write_framer(sc, T3CSR_TX_FEAC, 0xC0 + T3BOP_OOF);
1356150849Sscottl    else if ((stat16 & STAT16_RAIS)!=0)
1357150849Sscottl      write_framer(sc, T3CSR_TX_FEAC, 0xC0 + T3BOP_AIS);
1358150849Sscottl    else if ((stat16 & STAT16_RIDL)!=0)
1359150849Sscottl      write_framer(sc, T3CSR_TX_FEAC, 0xC0 + T3BOP_IDLE);
1360150849Sscottl    else
1361150849Sscottl      write_framer(sc, T3CSR_TX_FEAC, CTL5_EMODE);
1362150849Sscottl    }
1363150849Sscottl
1364150849Sscottl  /* Start sending RAI, Remote Alarm Indication. */
1365150849Sscottl  if (((stat16 & STAT16_ROOF)!=0) && ((stat16 & STAT16_RLOS)==0) &&
1366150849Sscottl   ((sc->last_stat16 & STAT16_ROOF)==0))
1367150849Sscottl    write_framer(sc, T3CSR_CTL1, ctl1 &= ~CTL1_XTX);
1368150849Sscottl  /* Stop sending RAI, Remote Alarm Indication. */
1369150849Sscottl  else if (((stat16 & STAT16_ROOF)==0) && ((sc->last_stat16 & STAT16_ROOF)!=0))
1370150849Sscottl    write_framer(sc, T3CSR_CTL1, ctl1 |=  CTL1_XTX);
1371150849Sscottl
1372150849Sscottl  /* Start sending AIS, Alarm Indication Signal */
1373150849Sscottl  if (((stat16 & STAT16_RLOS)!=0) && ((sc->last_stat16 & STAT16_RLOS)==0))
1374150849Sscottl    {
1375150849Sscottl    set_mii16_bits(sc, MII16_DS3_FRAME);
1376150849Sscottl    write_framer(sc, T3CSR_CTL1, ctl1 |  CTL1_TXAIS);
1377150849Sscottl    }
1378150849Sscottl  /* Stop sending AIS, Alarm Indication Signal */
1379150849Sscottl  else if (((stat16 & STAT16_RLOS)==0) && ((sc->last_stat16 & STAT16_RLOS)!=0))
1380150849Sscottl    {
1381150849Sscottl    clr_mii16_bits(sc, MII16_DS3_FRAME);
1382150849Sscottl    write_framer(sc, T3CSR_CTL1, ctl1 & ~CTL1_TXAIS);
1383150849Sscottl    }
1384150849Sscottl
1385150849Sscottl  /* Time out loopback requests. */
1386150849Sscottl  if (sc->loop_timer != 0)
1387150849Sscottl    if (--sc->loop_timer == 0)
1388150849Sscottl      if ((mii16 & MII16_DS3_LNLBK)!=0)
1389150849Sscottl        {
1390150849Sscottl        if (DRIVER_DEBUG)
1391150849Sscottl          printf("%s: Timeout: Loop Down after 300 seconds\n", NAME_UNIT);
1392150849Sscottl        clr_mii16_bits(sc, MII16_DS3_LNLBK); /* line loopback off */
1393150849Sscottl        }
1394150849Sscottl
1395150849Sscottl  /* SNMP error counters */
1396150849Sscottl  sc->status.snmp.t3.lcv  = CV;
1397150849Sscottl  sc->status.snmp.t3.pcv  = PERR;
1398150849Sscottl  sc->status.snmp.t3.ccv  = CERR;
1399150849Sscottl  sc->status.snmp.t3.febe = FEBE;
1400150849Sscottl
1401150849Sscottl  /* SNMP Line Status */
1402150849Sscottl  sc->status.snmp.t3.line = 0;
1403150849Sscottl  if ((ctl1  & CTL1_XTX)==0)   sc->status.snmp.t3.line |= TLINE_TX_RAI;
1404150849Sscottl  if (stat16 & STAT16_XERR)    sc->status.snmp.t3.line |= TLINE_RX_RAI;
1405150849Sscottl  if (ctl1   & CTL1_TXAIS)     sc->status.snmp.t3.line |= TLINE_TX_AIS;
1406150849Sscottl  if (stat16 & STAT16_RAIS)    sc->status.snmp.t3.line |= TLINE_RX_AIS;
1407150849Sscottl  if (stat16 & STAT16_ROOF)    sc->status.snmp.t3.line |= TLINE_LOF;
1408150849Sscottl  if (stat16 & STAT16_RLOS)    sc->status.snmp.t3.line |= TLINE_LOS;
1409150849Sscottl  if (stat16 & STAT16_SEF)     sc->status.snmp.t3.line |= T3LINE_SEF;
1410150849Sscottl
1411150849Sscottl  /* SNMP Loopback Status */
1412150849Sscottl  sc->status.snmp.t3.loop &= ~TLOOP_FAR_LINE;
1413150849Sscottl  if (sc->config.loop_back == CFG_LOOP_TULIP)
1414150849Sscottl                               sc->status.snmp.t3.loop |= TLOOP_NEAR_OTHER;
1415150849Sscottl  if (ctl1  & CTL1_3LOOP)      sc->status.snmp.t3.loop |= TLOOP_NEAR_INWARD;
1416150849Sscottl  if (mii16 & MII16_DS3_TRLBK) sc->status.snmp.t3.loop |= TLOOP_NEAR_OTHER;
1417150849Sscottl  if (mii16 & MII16_DS3_LNLBK) sc->status.snmp.t3.loop |= TLOOP_NEAR_LINE;
1418150849Sscottl/*if (ctl12 & CTL12_RTPLOOP)   sc->status.snmp.t3.loop |= TLOOP_NEAR_PAYLOAD; */
1419150849Sscottl
1420150849Sscottl  /* Remember this state until next time. */
1421150849Sscottl  sc->last_stat16 = stat16;
1422150849Sscottl
1423150849Sscottl  /* If an INWARD loopback is in effect, link status is UP */
1424150849Sscottl  if (sc->config.loop_back != CFG_LOOP_NONE) /* XXX INWARD ONLY */
1425150849Sscottl    link_status = STATUS_UP;
1426150849Sscottl
1427150849Sscottl  return link_status;
1428150849Sscottl  }
1429150849Sscottl
1430150849Sscottl/* IOCTL SYSCALL: can sleep. */
1431150849Sscottlstatic void
1432150849Sscottlt3_send_dbl_feac(softc_t *sc, int feac1, int feac2)
1433150849Sscottl  {
1434150849Sscottl  u_int8_t tx_feac;
1435150849Sscottl  int i;
1436150849Sscottl
1437150849Sscottl  /* The FEAC transmitter could be sending a continuous */
1438150849Sscottl  /*  FEAC msg when told to send a double FEAC message. */
1439150849Sscottl  /* So save the current state of the FEAC transmitter. */
1440150849Sscottl  tx_feac = read_framer(sc, T3CSR_TX_FEAC);
1441150849Sscottl  /* Load second FEAC code and stop FEAC transmitter. */
1442150849Sscottl  write_framer(sc, T3CSR_TX_FEAC,  CTL5_EMODE + feac2);
1443150849Sscottl  /* FEAC transmitter sends 10 more FEACs and then stops. */
1444150849Sscottl  SLEEP(20000); /* sending one FEAC takes 1700 uSecs */
1445150849Sscottl  /* Load first FEAC code and start FEAC transmitter. */
1446150849Sscottl  write_framer(sc, T3CSR_DBL_FEAC, CTL13_DFEXEC + feac1);
1447150849Sscottl  /* Wait for double FEAC sequence to complete -- about 70 ms. */
1448150849Sscottl  for (i=0; i<10; i++) /* max delay 100 ms */
1449150849Sscottl    if (read_framer(sc, T3CSR_DBL_FEAC) & CTL13_DFEXEC) SLEEP(10000);
1450150849Sscottl  /* Flush received FEACS; don't respond to our own loop cmd! */
1451150849Sscottl  while (read_framer(sc, T3CSR_FEAC_STK) & FEAC_STK_VALID) DELAY(1); /* XXX HANG */
1452150849Sscottl  /* Restore previous state of the FEAC transmitter. */
1453150849Sscottl  /* If it was sending a continous FEAC, it will resume. */
1454150849Sscottl  write_framer(sc, T3CSR_TX_FEAC, tx_feac);
1455150849Sscottl  }
1456150849Sscottl
1457150849Sscottl/* IOCTL SYSCALL: can sleep. */
1458150849Sscottlstatic int
1459150849Sscottlt3_ioctl(softc_t *sc, struct ioctl *ioctl)
1460150849Sscottl  {
1461150849Sscottl  int error = 0;
1462150849Sscottl
1463150849Sscottl  switch (ioctl->cmd)
1464150849Sscottl    {
1465150849Sscottl    case IOCTL_SNMP_SEND:  /* set opstatus? */
1466150849Sscottl      {
1467150849Sscottl      if (sc->config.format != CFG_FORMAT_T3CPAR)
1468150849Sscottl        error = EINVAL;
1469150849Sscottl      else if (ioctl->data == TSEND_LINE)
1470150849Sscottl        {
1471150849Sscottl        sc->status.snmp.t3.loop |= TLOOP_FAR_LINE;
1472150849Sscottl        t3_send_dbl_feac(sc, T3BOP_LINE_UP, T3BOP_LOOP_DS3);
1473150849Sscottl        }
1474150849Sscottl      else if (ioctl->data == TSEND_RESET)
1475150849Sscottl        {
1476150849Sscottl        t3_send_dbl_feac(sc, T3BOP_LINE_DOWN, T3BOP_LOOP_DS3);
1477150849Sscottl        sc->status.snmp.t3.loop &= ~TLOOP_FAR_LINE;
1478150849Sscottl        }
1479150849Sscottl      else
1480150849Sscottl        error = EINVAL;
1481150849Sscottl      break;
1482150849Sscottl      }
1483150849Sscottl    case IOCTL_SNMP_LOOP:  /* set opstatus = test? */
1484150849Sscottl      {
1485150849Sscottl      if (ioctl->data == CFG_LOOP_NONE)
1486150849Sscottl        {
1487150849Sscottl        clr_mii16_bits(sc, MII16_DS3_FRAME);
1488150849Sscottl        clr_mii16_bits(sc, MII16_DS3_TRLBK);
1489150849Sscottl        clr_mii16_bits(sc, MII16_DS3_LNLBK);
1490150849Sscottl        write_framer(sc, T3CSR_CTL1,
1491150849Sscottl         read_framer(sc, T3CSR_CTL1) & ~CTL1_3LOOP);
1492150849Sscottl        write_framer(sc, T3CSR_CTL12,
1493150849Sscottl         read_framer(sc, T3CSR_CTL12) & ~(CTL12_RTPLOOP | CTL12_RTPLLEN));
1494150849Sscottl	}
1495150849Sscottl      else if (ioctl->data == CFG_LOOP_LINE)
1496150849Sscottl        set_mii16_bits(sc, MII16_DS3_LNLBK);
1497150849Sscottl      else if (ioctl->data == CFG_LOOP_OTHER)
1498150849Sscottl        set_mii16_bits(sc, MII16_DS3_TRLBK);
1499150849Sscottl      else if (ioctl->data == CFG_LOOP_INWARD)
1500150849Sscottl        write_framer(sc, T3CSR_CTL1,
1501150849Sscottl         read_framer(sc, T3CSR_CTL1) | CTL1_3LOOP);
1502150849Sscottl      else if (ioctl->data == CFG_LOOP_DUAL)
1503150849Sscottl        {
1504150849Sscottl        set_mii16_bits(sc, MII16_DS3_LNLBK);
1505150849Sscottl        write_framer(sc, T3CSR_CTL1,
1506150849Sscottl         read_framer(sc, T3CSR_CTL1) | CTL1_3LOOP);
1507150849Sscottl	}
1508150849Sscottl      else if (ioctl->data == CFG_LOOP_PAYLOAD)
1509150849Sscottl        {
1510150849Sscottl        set_mii16_bits(sc, MII16_DS3_FRAME);
1511150849Sscottl        write_framer(sc, T3CSR_CTL12,
1512150849Sscottl         read_framer(sc, T3CSR_CTL12) |  CTL12_RTPLOOP);
1513150849Sscottl        write_framer(sc, T3CSR_CTL12,
1514150849Sscottl         read_framer(sc, T3CSR_CTL12) |  CTL12_RTPLLEN);
1515150849Sscottl        DELAY(25); /* at least two frames (22 uS) */
1516150849Sscottl        write_framer(sc, T3CSR_CTL12,
1517150849Sscottl         read_framer(sc, T3CSR_CTL12) & ~CTL12_RTPLLEN);
1518150849Sscottl	}
1519150849Sscottl      else
1520150849Sscottl        error = EINVAL;
1521150849Sscottl      break;
1522150849Sscottl      }
1523150849Sscottl    default:
1524150849Sscottl      error = EINVAL;
1525150849Sscottl      break;
1526150849Sscottl    }
1527150849Sscottl
1528150849Sscottl  return error;
1529150849Sscottl  }
1530150849Sscottl
1531150849Sscottl/* begin SSI card code */
1532150849Sscottl
1533150849Sscottl/* Must not sleep. */
1534150849Sscottlstatic void
1535150849Sscottlssi_config(softc_t *sc)
1536150849Sscottl  {
1537150849Sscottl  if (sc->status.card_type == 0)
1538150849Sscottl    { /* defaults */
1539150849Sscottl    sc->status.card_type  = TLP_CSID_SSI;
1540150849Sscottl    sc->config.crc_len    = CFG_CRC_16;
1541150849Sscottl    sc->config.loop_back  = CFG_LOOP_NONE;
1542150849Sscottl    sc->config.tx_clk_src = CFG_CLKMUX_ST;
1543150849Sscottl    sc->config.dte_dce    = CFG_DTE;
1544150849Sscottl    sc->config.synth.n    = 51; /* 1.536 MHz */
1545150849Sscottl    sc->config.synth.m    = 83;
1546150849Sscottl    sc->config.synth.v    =  1;
1547150849Sscottl    sc->config.synth.x    =  1;
1548150849Sscottl    sc->config.synth.r    =  1;
1549150849Sscottl    sc->config.synth.prescale = 4;
1550150849Sscottl    }
1551150849Sscottl
1552150849Sscottl  /* Disable the TX clock driver while programming the oscillator. */
1553150849Sscottl  clr_gpio_bits(sc, GPIO_SSI_DCE);
1554150849Sscottl  make_gpio_output(sc, GPIO_SSI_DCE);
1555150849Sscottl
1556150849Sscottl  /* Program the synthesized oscillator. */
1557150849Sscottl  write_synth(sc, &sc->config.synth);
1558150849Sscottl
1559150849Sscottl  /* Set DTE/DCE mode. */
1560150849Sscottl  /* If DTE mode then DCD & TXC are received. */
1561150849Sscottl  /* If DCE mode then DCD & TXC are driven. */
1562150849Sscottl  /* Boards with MII rev=4.0 don't drive DCD. */
1563150849Sscottl  if (sc->config.dte_dce == CFG_DCE)
1564150849Sscottl    set_gpio_bits(sc, GPIO_SSI_DCE);
1565150849Sscottl  else
1566150849Sscottl    clr_gpio_bits(sc, GPIO_SSI_DCE);
1567150849Sscottl  make_gpio_output(sc, GPIO_SSI_DCE);
1568150849Sscottl
1569150849Sscottl  /* Set CRC length. */
1570150849Sscottl  if (sc->config.crc_len == CFG_CRC_32)
1571150849Sscottl    set_mii16_bits(sc, MII16_SSI_CRC32);
1572150849Sscottl  else
1573150849Sscottl    clr_mii16_bits(sc, MII16_SSI_CRC32);
1574150849Sscottl
1575150849Sscottl  /* Loop towards host thru cable drivers and receivers. */
1576150849Sscottl  /* Asserts DCD at the far end of a null modem cable. */
1577150849Sscottl  if (sc->config.loop_back == CFG_LOOP_PINS)
1578150849Sscottl    set_mii16_bits(sc, MII16_SSI_LOOP);
1579150849Sscottl  else
1580150849Sscottl    clr_mii16_bits(sc, MII16_SSI_LOOP);
1581150849Sscottl
1582150849Sscottl  /* Assert pin LL in modem conn: ask modem for local loop. */
1583150849Sscottl  /* Asserts TM at the far end of a null modem cable. */
1584150849Sscottl  if (sc->config.loop_back == CFG_LOOP_LL)
1585150849Sscottl    set_mii16_bits(sc, MII16_SSI_LL);
1586150849Sscottl  else
1587150849Sscottl    clr_mii16_bits(sc, MII16_SSI_LL);
1588150849Sscottl
1589150849Sscottl  /* Assert pin RL in modem conn: ask modem for remote loop. */
1590150849Sscottl  if (sc->config.loop_back == CFG_LOOP_RL)
1591150849Sscottl    set_mii16_bits(sc, MII16_SSI_RL);
1592150849Sscottl  else
1593150849Sscottl    clr_mii16_bits(sc, MII16_SSI_RL);
1594150849Sscottl  }
1595150849Sscottl
1596150849Sscottlstatic void
1597150849Sscottlssi_ident(softc_t *sc)
1598150849Sscottl  {
1599150849Sscottl  printf(", LTC1343/44");
1600150849Sscottl  }
1601150849Sscottl
1602150849Sscottl/* Called once a second; must not sleep. */
1603150849Sscottlstatic int
1604150849Sscottlssi_watchdog(softc_t *sc)
1605150849Sscottl  {
1606150849Sscottl  u_int16_t cable;
1607150849Sscottl  u_int16_t mii16 = read_mii(sc, 16) & MII16_SSI_MODEM;
1608150849Sscottl  int link_status = STATUS_UP;
1609150849Sscottl
1610150849Sscottl  /* Software is alive. */
1611150849Sscottl  led_inv(sc, MII16_SSI_LED_UL);
1612150849Sscottl
1613150849Sscottl  /* Check the transmit clock. */
1614150849Sscottl  if (sc->status.tx_speed == 0)
1615150849Sscottl    {
1616150849Sscottl    led_on(sc, MII16_SSI_LED_UR);
1617150849Sscottl    link_status = STATUS_DOWN;
1618150849Sscottl    }
1619150849Sscottl  else
1620150849Sscottl    led_off(sc, MII16_SSI_LED_UR);
1621150849Sscottl
1622150849Sscottl  /* Check the external cable. */
1623150849Sscottl  cable = read_mii(sc, 17);
1624150849Sscottl  cable = cable &  MII17_SSI_CABLE_MASK;
1625150849Sscottl  cable = cable >> MII17_SSI_CABLE_SHIFT;
1626150849Sscottl  if (cable == 7)
1627150849Sscottl    {
1628150849Sscottl    led_off(sc, MII16_SSI_LED_LL); /* no cable */
1629150849Sscottl    link_status = STATUS_DOWN;
1630150849Sscottl    }
1631150849Sscottl  else
1632150849Sscottl    led_on(sc, MII16_SSI_LED_LL);
1633150849Sscottl
1634150849Sscottl  /* The unit at the other end of the cable is ready if: */
1635150849Sscottl  /*  DTE mode and DCD pin is asserted */
1636150849Sscottl  /*  DCE mode and DSR pin is asserted */
1637150849Sscottl  if (((sc->config.dte_dce == CFG_DTE) && ((mii16 & MII16_SSI_DCD)==0)) ||
1638150849Sscottl      ((sc->config.dte_dce == CFG_DCE) && ((mii16 & MII16_SSI_DSR)==0)))
1639150849Sscottl    {
1640150849Sscottl    led_off(sc, MII16_SSI_LED_LR);
1641150849Sscottl    link_status = STATUS_DOWN;
1642150849Sscottl    }
1643150849Sscottl  else
1644150849Sscottl    led_on(sc, MII16_SSI_LED_LR);
1645150849Sscottl
1646150849Sscottl  if (DRIVER_DEBUG && (cable != sc->status.cable_type))
1647150849Sscottl    printf("%s: SSI cable type changed to '%s'\n",
1648150849Sscottl     NAME_UNIT, ssi_cables[cable]);
1649150849Sscottl  sc->status.cable_type = cable;
1650150849Sscottl
1651150849Sscottl  /* Print the modem control signals if they changed. */
1652150849Sscottl  if ((DRIVER_DEBUG) && (mii16 != sc->last_mii16))
1653150849Sscottl    {
1654150849Sscottl    char *on = "ON ", *off = "OFF";
1655150849Sscottl    printf("%s: DTR=%s DSR=%s RTS=%s CTS=%s DCD=%s RI=%s LL=%s RL=%s TM=%s\n",
1656150849Sscottl     NAME_UNIT,
1657150849Sscottl     (mii16 & MII16_SSI_DTR) ? on : off,
1658150849Sscottl     (mii16 & MII16_SSI_DSR) ? on : off,
1659150849Sscottl     (mii16 & MII16_SSI_RTS) ? on : off,
1660150849Sscottl     (mii16 & MII16_SSI_CTS) ? on : off,
1661150849Sscottl     (mii16 & MII16_SSI_DCD) ? on : off,
1662150849Sscottl     (mii16 & MII16_SSI_RI)  ? on : off,
1663150849Sscottl     (mii16 & MII16_SSI_LL)  ? on : off,
1664150849Sscottl     (mii16 & MII16_SSI_RL)  ? on : off,
1665150849Sscottl     (mii16 & MII16_SSI_TM)  ? on : off);
1666150849Sscottl    }
1667150849Sscottl
1668150849Sscottl  /* SNMP one-second report */
1669150849Sscottl  sc->status.snmp.ssi.sigs = mii16 & MII16_SSI_MODEM;
1670150849Sscottl
1671150849Sscottl  /* Remember this state until next time. */
1672150849Sscottl  sc->last_mii16 = mii16;
1673150849Sscottl
1674150849Sscottl  /* If a loop back is in effect, link status is UP */
1675150849Sscottl  if (sc->config.loop_back != CFG_LOOP_NONE)
1676150849Sscottl    link_status = STATUS_UP;
1677150849Sscottl
1678150849Sscottl  return link_status;
1679150849Sscottl  }
1680150849Sscottl
1681150849Sscottl/* IOCTL SYSCALL: can sleep (but doesn't). */
1682150849Sscottlstatic int
1683150849Sscottlssi_ioctl(softc_t *sc, struct ioctl *ioctl)
1684150849Sscottl  {
1685150849Sscottl  int error = 0;
1686150849Sscottl
1687150849Sscottl  if (ioctl->cmd == IOCTL_SNMP_SIGS)
1688150849Sscottl    {
1689150849Sscottl    u_int16_t mii16 = read_mii(sc, 16);
1690150849Sscottl    mii16 &= ~MII16_SSI_MODEM;
1691150849Sscottl    mii16 |= (MII16_SSI_MODEM & ioctl->data);
1692150849Sscottl    write_mii(sc, 16, mii16);
1693150849Sscottl    }
1694150849Sscottl  else if (ioctl->cmd == IOCTL_SET_STATUS)
1695150849Sscottl    {
1696150849Sscottl    if (ioctl->data != 0)
1697150849Sscottl      set_mii16_bits(sc, (MII16_SSI_DTR | MII16_SSI_RTS | MII16_SSI_DCD));
1698150849Sscottl    else
1699150849Sscottl      clr_mii16_bits(sc, (MII16_SSI_DTR | MII16_SSI_RTS | MII16_SSI_DCD));
1700150849Sscottl    }
1701150849Sscottl  else
1702150849Sscottl    error = EINVAL;
1703150849Sscottl
1704150849Sscottl  return error;
1705150849Sscottl  }
1706150849Sscottl
1707150849Sscottl/* begin T1E1 card code */
1708150849Sscottl
1709150849Sscottl/* Must not sleep. */
1710150849Sscottlstatic void
1711150849Sscottlt1_config(softc_t *sc)
1712150849Sscottl  {
1713150849Sscottl  int i;
1714150849Sscottl  u_int8_t pulse, lbo, gain;
1715150849Sscottl
1716150849Sscottl  if (sc->status.card_type == 0)
1717150849Sscottl    {  /* defaults */
1718150849Sscottl    sc->status.card_type   = TLP_CSID_T1E1;
1719150849Sscottl    sc->config.crc_len     = CFG_CRC_16;
1720150849Sscottl    sc->config.loop_back   = CFG_LOOP_NONE;
1721150849Sscottl    sc->config.tx_clk_src  = CFG_CLKMUX_INT;
1722150849Sscottl    sc->config.format      = CFG_FORMAT_T1ESF;
1723150849Sscottl    sc->config.cable_len   = 10;
1724150849Sscottl    sc->config.time_slots  = 0x01FFFFFE;
1725150849Sscottl    sc->config.tx_pulse    = CFG_PULSE_AUTO;
1726150849Sscottl    sc->config.rx_gain     = CFG_GAIN_AUTO;
1727150849Sscottl    sc->config.tx_lbo      = CFG_LBO_AUTO;
1728150849Sscottl
1729150849Sscottl    /* Bt8370 occasionally powers up in a loopback mode. */
1730150849Sscottl    /* Data sheet says zero LOOP reg and do a s/w reset. */
1731150849Sscottl    write_framer(sc, Bt8370_LOOP, 0x00); /* no loopback */
1732150849Sscottl    write_framer(sc, Bt8370_CR0,  0x80); /* s/w reset */
1733150849Sscottl    for (i=0; i<10; i++) /* max delay 10 ms */
1734150849Sscottl      if (read_framer(sc, Bt8370_CR0) & 0x80) DELAY(1000);
1735150849Sscottl    }
1736150849Sscottl
1737150849Sscottl  /* Set CRC length. */
1738150849Sscottl  if (sc->config.crc_len == CFG_CRC_32)
1739150849Sscottl    set_mii16_bits(sc, MII16_T1_CRC32);
1740150849Sscottl  else
1741150849Sscottl    clr_mii16_bits(sc, MII16_T1_CRC32);
1742150849Sscottl
1743150849Sscottl  /* Invert HDLC payload data in SF/AMI mode. */
1744150849Sscottl  /* HDLC stuff bits satisfy T1 pulse density. */
1745150849Sscottl  if (FORMAT_T1SF)
1746150849Sscottl    set_mii16_bits(sc, MII16_T1_INVERT);
1747150849Sscottl  else
1748150849Sscottl    clr_mii16_bits(sc, MII16_T1_INVERT);
1749150849Sscottl
1750150849Sscottl  /* Set the transmitter output impedance. */
1751150849Sscottl  if (FORMAT_E1ANY) set_mii16_bits(sc, MII16_T1_Z);
1752150849Sscottl
1753150849Sscottl  /* 001:CR0 -- Control Register 0 - T1/E1 and frame format */
1754150849Sscottl  write_framer(sc, Bt8370_CR0, sc->config.format);
1755150849Sscottl
1756150849Sscottl  /* 002:JAT_CR -- Jitter Attenuator Control Register */
1757150849Sscottl  if (sc->config.tx_clk_src == CFG_CLKMUX_RT) /* loop timing */
1758150849Sscottl    write_framer(sc, Bt8370_JAT_CR, 0xA3); /* JAT in RX path */
1759150849Sscottl  else
1760150849Sscottl    { /* 64-bit elastic store; free-running JCLK and CLADO */
1761150849Sscottl    write_framer(sc, Bt8370_JAT_CR, 0x4B); /* assert jcenter */
1762150849Sscottl    write_framer(sc, Bt8370_JAT_CR, 0x43); /* release jcenter */
1763150849Sscottl    }
1764150849Sscottl
1765150849Sscottl  /* 00C-013:IERn -- Interrupt Enable Registers */
1766150849Sscottl  for (i=Bt8370_IER7; i<=Bt8370_IER0; i++)
1767150849Sscottl    write_framer(sc, i, 0); /* no interrupts; polled */
1768150849Sscottl
1769150849Sscottl  /* 014:LOOP -- loopbacks */
1770150849Sscottl  if      (sc->config.loop_back == CFG_LOOP_PAYLOAD)
1771150849Sscottl    write_framer(sc, Bt8370_LOOP, LOOP_PAYLOAD);
1772150849Sscottl  else if (sc->config.loop_back == CFG_LOOP_LINE)
1773150849Sscottl    write_framer(sc, Bt8370_LOOP, LOOP_LINE);
1774150849Sscottl  else if (sc->config.loop_back == CFG_LOOP_OTHER)
1775150849Sscottl    write_framer(sc, Bt8370_LOOP, LOOP_ANALOG);
1776150849Sscottl  else if (sc->config.loop_back == CFG_LOOP_INWARD)
1777150849Sscottl    write_framer(sc, Bt8370_LOOP, LOOP_FRAMER);
1778150849Sscottl  else if (sc->config.loop_back == CFG_LOOP_DUAL)
1779150849Sscottl    write_framer(sc, Bt8370_LOOP, LOOP_DUAL);
1780150849Sscottl  else
1781150849Sscottl    write_framer(sc, Bt8370_LOOP, 0x00); /* no loopback */
1782150849Sscottl
1783150849Sscottl  /* 015:DL3_TS -- Data Link 3 */
1784150849Sscottl  write_framer(sc, Bt8370_DL3_TS, 0x00); /* disabled */
1785150849Sscottl
1786150849Sscottl  /* 018:PIO -- Programmable I/O */
1787150849Sscottl  write_framer(sc, Bt8370_PIO, 0xFF); /* all pins are outputs */
1788150849Sscottl
1789150849Sscottl  /* 019:POE -- Programmable Output Enable */
1790150849Sscottl  write_framer(sc, Bt8370_POE, 0x00); /* all outputs are enabled */
1791150849Sscottl
1792150849Sscottl  /* 01A;CMUX -- Clock Input Mux */
1793150849Sscottl  if (sc->config.tx_clk_src == CFG_CLKMUX_EXT)
1794150849Sscottl    write_framer(sc, Bt8370_CMUX, 0x0C); /* external timing */
1795150849Sscottl  else
1796150849Sscottl    write_framer(sc, Bt8370_CMUX, 0x0F); /* internal timing */
1797150849Sscottl
1798150849Sscottl  /* 020:LIU_CR -- Line Interface Unit Config Register */
1799150849Sscottl  write_framer(sc, Bt8370_LIU_CR, 0xC1); /* reset LIU, squelch */
1800150849Sscottl
1801150849Sscottl  /* 022:RLIU_CR -- RX Line Interface Unit Config Reg */
1802150849Sscottl  /* Errata sheet says don't use freeze-short, but we do anyway! */
1803150849Sscottl  write_framer(sc, Bt8370_RLIU_CR, 0xB1); /* AGC=2048, Long Eye */
1804150849Sscottl
1805150849Sscottl  /* Select Rx sensitivity based on cable length. */
1806150849Sscottl  if ((gain = sc->config.rx_gain) == CFG_GAIN_AUTO)
1807150849Sscottl    {
1808150849Sscottl    if      (sc->config.cable_len > 2000)
1809150849Sscottl      gain = CFG_GAIN_EXTEND;
1810150849Sscottl    else if (sc->config.cable_len > 1000)
1811150849Sscottl      gain = CFG_GAIN_LONG;
1812150849Sscottl    else if (sc->config.cable_len > 100)
1813150849Sscottl      gain = CFG_GAIN_MEDIUM;
1814150849Sscottl    else
1815150849Sscottl      gain = CFG_GAIN_SHORT;
1816150849Sscottl    }
1817150849Sscottl
1818150849Sscottl  /* 024:VGA_MAX -- Variable Gain Amplifier Max gain */
1819150849Sscottl  write_framer(sc, Bt8370_VGA_MAX, gain);
1820150849Sscottl
1821150849Sscottl  /* 028:PRE_EQ -- Pre Equalizer */
1822150849Sscottl  if (gain == CFG_GAIN_EXTEND)
1823150849Sscottl    write_framer(sc, Bt8370_PRE_EQ, 0xE6);  /* ON; thresh 6 */
1824150849Sscottl  else
1825150849Sscottl    write_framer(sc, Bt8370_PRE_EQ, 0xA6);  /* OFF; thresh 6 */
1826150849Sscottl
1827150849Sscottl  /* 038-03C:GAINn -- RX Equalizer gain thresholds */
1828150849Sscottl  write_framer(sc, Bt8370_GAIN0, 0x24);
1829150849Sscottl  write_framer(sc, Bt8370_GAIN1, 0x28);
1830150849Sscottl  write_framer(sc, Bt8370_GAIN2, 0x2C);
1831150849Sscottl  write_framer(sc, Bt8370_GAIN3, 0x30);
1832150849Sscottl  write_framer(sc, Bt8370_GAIN4, 0x34);
1833150849Sscottl
1834150849Sscottl  /* 040:RCR0 -- Receiver Control Register 0 */
1835150849Sscottl  if      (FORMAT_T1ESF)
1836150849Sscottl    write_framer(sc, Bt8370_RCR0, 0x05); /* B8ZS, 2/5 FErrs */
1837150849Sscottl  else if (FORMAT_T1SF)
1838150849Sscottl    write_framer(sc, Bt8370_RCR0, 0x84); /* AMI,  2/5 FErrs */
1839150849Sscottl  else if (FORMAT_E1NONE)
1840150849Sscottl    write_framer(sc, Bt8370_RCR0, 0x41); /* HDB3, rabort */
1841150849Sscottl  else if (FORMAT_E1CRC)
1842150849Sscottl    write_framer(sc, Bt8370_RCR0, 0x09); /* HDB3, 3 FErrs or 915 CErrs */
1843150849Sscottl  else  /* E1 no CRC */
1844150849Sscottl    write_framer(sc, Bt8370_RCR0, 0x19); /* HDB3, 3 FErrs */
1845150849Sscottl
1846150849Sscottl  /* 041:RPATT -- Receive Test Pattern configuration */
1847150849Sscottl  write_framer(sc, Bt8370_RPATT, 0x3E); /* looking for framed QRSS */
1848150849Sscottl
1849150849Sscottl  /* 042:RLB -- Receive Loop Back code detector config */
1850150849Sscottl  write_framer(sc, Bt8370_RLB, 0x09); /* 6 bits down; 5 bits up */
1851150849Sscottl
1852150849Sscottl  /* 043:LBA -- Loop Back Activate code */
1853150849Sscottl  write_framer(sc, Bt8370_LBA, 0x08); /* 10000 10000 10000 ... */
1854150849Sscottl
1855150849Sscottl  /* 044:LBD -- Loop Back Deactivate code */
1856150849Sscottl  write_framer(sc, Bt8370_LBD, 0x24); /* 100100 100100 100100 ... */
1857150849Sscottl
1858150849Sscottl  /* 045:RALM -- Receive Alarm signal configuration */
1859150849Sscottl  write_framer(sc, Bt8370_RALM, 0x0C); /* yel_intg rlof_intg */
1860150849Sscottl
1861150849Sscottl  /* 046:LATCH -- Alarm/Error/Counter Latch register */
1862150849Sscottl  write_framer(sc, Bt8370_LATCH, 0x1F); /* stop_cnt latch_{cnt,err,alm} */
1863150849Sscottl
1864150849Sscottl  /* Select Pulse Shape based on cable length (T1 only). */
1865150849Sscottl  if ((pulse = sc->config.tx_pulse) == CFG_PULSE_AUTO)
1866150849Sscottl    {
1867150849Sscottl    if (FORMAT_T1ANY)
1868150849Sscottl      {
1869150849Sscottl      if      (sc->config.cable_len > 200)
1870150849Sscottl        pulse = CFG_PULSE_T1CSU;
1871150849Sscottl      else if (sc->config.cable_len > 160)
1872150849Sscottl        pulse = CFG_PULSE_T1DSX4;
1873150849Sscottl      else if (sc->config.cable_len > 120)
1874150849Sscottl        pulse = CFG_PULSE_T1DSX3;
1875150849Sscottl      else if (sc->config.cable_len > 80)
1876150849Sscottl        pulse = CFG_PULSE_T1DSX2;
1877150849Sscottl      else if (sc->config.cable_len > 40)
1878150849Sscottl        pulse = CFG_PULSE_T1DSX1;
1879150849Sscottl      else
1880150849Sscottl        pulse = CFG_PULSE_T1DSX0;
1881150849Sscottl      }
1882150849Sscottl    else
1883150849Sscottl      pulse = CFG_PULSE_E1TWIST;
1884150849Sscottl    }
1885150849Sscottl
1886150849Sscottl  /* Select Line Build Out based on cable length (T1CSU only). */
1887150849Sscottl  if ((lbo = sc->config.tx_lbo) == CFG_LBO_AUTO)
1888150849Sscottl    {
1889150849Sscottl    if (pulse == CFG_PULSE_T1CSU)
1890150849Sscottl      {
1891150849Sscottl      if      (sc->config.cable_len > 1500)
1892150849Sscottl        lbo = CFG_LBO_0DB;
1893150849Sscottl      else if (sc->config.cable_len > 1000)
1894150849Sscottl        lbo = CFG_LBO_7DB;
1895150849Sscottl      else if (sc->config.cable_len >  500)
1896150849Sscottl        lbo = CFG_LBO_15DB;
1897150849Sscottl      else
1898150849Sscottl        lbo = CFG_LBO_22DB;
1899150849Sscottl      }
1900150849Sscottl    else
1901150849Sscottl      lbo = 0;
1902150849Sscottl    }
1903150849Sscottl
1904150849Sscottl  /* 068:TLIU_CR -- Transmit LIU Control Register */
1905150849Sscottl  write_framer(sc, Bt8370_TLIU_CR, (0x40 | (lbo & 0x30) | (pulse & 0x0E)));
1906150849Sscottl
1907150849Sscottl  /* 070:TCR0 -- Transmit Framer Configuration */
1908150849Sscottl  write_framer(sc, Bt8370_TCR0, sc->config.format>>1);
1909150849Sscottl
1910150849Sscottl  /* 071:TCR1 -- Transmitter Configuration */
1911150849Sscottl  if (FORMAT_T1SF)
1912150849Sscottl    write_framer(sc, Bt8370_TCR1, 0x43); /* tabort, AMI PDV enforced */
1913150849Sscottl  else
1914150849Sscottl    write_framer(sc, Bt8370_TCR1, 0x41); /* tabort, B8ZS or HDB3 */
1915150849Sscottl
1916150849Sscottl  /* 072:TFRM -- Transmit Frame format       MYEL YEL MF FE CRC FBIT */
1917150849Sscottl  if      (sc->config.format == CFG_FORMAT_T1ESF)
1918150849Sscottl    write_framer(sc, Bt8370_TFRM, 0x0B); /*  -   YEL MF -  CRC FBIT */
1919150849Sscottl  else if (sc->config.format == CFG_FORMAT_T1SF)
1920150849Sscottl    write_framer(sc, Bt8370_TFRM, 0x19); /*  -   YEL MF -   -  FBIT */
1921150849Sscottl  else if (sc->config.format == CFG_FORMAT_E1FAS)
1922150849Sscottl    write_framer(sc, Bt8370_TFRM, 0x11); /*  -   YEL -  -   -  FBIT */
1923150849Sscottl  else if (sc->config.format == CFG_FORMAT_E1FASCRC)
1924150849Sscottl    write_framer(sc, Bt8370_TFRM, 0x1F); /*  -   YEL MF FE CRC FBIT */
1925150849Sscottl  else if (sc->config.format == CFG_FORMAT_E1FASCAS)
1926150849Sscottl    write_framer(sc, Bt8370_TFRM, 0x31); /* MYEL YEL -  -   -  FBIT */
1927150849Sscottl  else if (sc->config.format == CFG_FORMAT_E1FASCRCCAS)
1928150849Sscottl    write_framer(sc, Bt8370_TFRM, 0x3F); /* MYEL YEL MF FE CRC FBIT */
1929150849Sscottl  else if (sc->config.format == CFG_FORMAT_E1NONE)
1930150849Sscottl    write_framer(sc, Bt8370_TFRM, 0x00); /* NO FRAMING BITS AT ALL! */
1931150849Sscottl
1932150849Sscottl  /* 073:TERROR -- Transmit Error Insert */
1933150849Sscottl  write_framer(sc, Bt8370_TERROR, 0x00); /* no errors, please! */
1934150849Sscottl
1935150849Sscottl  /* 074:TMAN -- Transmit Manual Sa-byte/FEBE configuration */
1936150849Sscottl  write_framer(sc, Bt8370_TMAN, 0x00); /* none */
1937150849Sscottl
1938150849Sscottl  /* 075:TALM -- Transmit Alarm Signal Configuration */
1939150849Sscottl  if (FORMAT_E1ANY)
1940150849Sscottl    write_framer(sc, Bt8370_TALM, 0x38); /* auto_myel auto_yel auto_ais */
1941150849Sscottl  else if (FORMAT_T1ANY)
1942150849Sscottl    write_framer(sc, Bt8370_TALM, 0x18); /* auto_yel auto_ais */
1943150849Sscottl
1944150849Sscottl  /* 076:TPATT -- Transmit Test Pattern Configuration */
1945150849Sscottl  write_framer(sc, Bt8370_TPATT, 0x00); /* disabled */
1946150849Sscottl
1947150849Sscottl  /* 077:TLB -- Transmit Inband Loopback Code Configuration */
1948150849Sscottl  write_framer(sc, Bt8370_TLB, 0x00); /* disabled */
1949150849Sscottl
1950150849Sscottl  /* 090:CLAD_CR -- Clack Rate Adapter Configuration */
1951150849Sscottl  if (FORMAT_T1ANY)
1952150849Sscottl    write_framer(sc, Bt8370_CLAD_CR, 0x06); /* loop filter gain 1/2^6 */
1953150849Sscottl  else
1954150849Sscottl    write_framer(sc, Bt8370_CLAD_CR, 0x08); /* loop filter gain 1/2^8 */
1955150849Sscottl
1956150849Sscottl  /* 091:CSEL -- CLAD frequency Select */
1957150849Sscottl  if (FORMAT_T1ANY)
1958150849Sscottl    write_framer(sc, Bt8370_CSEL, 0x55); /* 1544 kHz */
1959150849Sscottl  else
1960150849Sscottl    write_framer(sc, Bt8370_CSEL, 0x11); /* 2048 kHz */
1961150849Sscottl
1962150849Sscottl  /* 092:CPHASE -- CLAD Phase detector */
1963150849Sscottl  if (FORMAT_T1ANY)
1964150849Sscottl    write_framer(sc, Bt8370_CPHASE, 0x22); /* phase compare @  386 kHz */
1965150849Sscottl  else
1966150849Sscottl    write_framer(sc, Bt8370_CPHASE, 0x00); /* phase compare @ 2048 kHz */
1967150849Sscottl
1968150849Sscottl  if (FORMAT_T1ESF) /* BOP & PRM are enabled in T1ESF mode only. */
1969150849Sscottl    {
1970150849Sscottl    /* 0A0:BOP -- Bit Oriented Protocol messages */
1971150849Sscottl    write_framer(sc, Bt8370_BOP, RBOP_25 | TBOP_OFF);
1972150849Sscottl    /* 0A4:DL1_TS -- Data Link 1 Time Slot Enable */
1973150849Sscottl    write_framer(sc, Bt8370_DL1_TS, 0x40); /* FDL bits in odd frames */
1974150849Sscottl    /* 0A6:DL1_CTL -- Data Link 1 Control */
1975150849Sscottl    write_framer(sc, Bt8370_DL1_CTL, 0x03); /* FCS mode, TX on, RX on */
1976150849Sscottl    /* 0A7:RDL1_FFC -- Rx Data Link 1 Fifo Fill Control */
1977150849Sscottl    write_framer(sc, Bt8370_RDL1_FFC, 0x30); /* assert "near full" at 48 */
1978150849Sscottl    /* 0AA:PRM -- Performance Report Messages */
1979150849Sscottl    write_framer(sc, Bt8370_PRM, 0x80);
1980150849Sscottl    }
1981150849Sscottl
1982150849Sscottl  /* 0D0:SBI_CR -- System Bus Interface Configuration Register */
1983150849Sscottl  if (FORMAT_T1ANY)
1984150849Sscottl    write_framer(sc, Bt8370_SBI_CR, 0x47); /* 1.544 with 24 TS +Fbits */
1985150849Sscottl  else
1986150849Sscottl    write_framer(sc, Bt8370_SBI_CR, 0x46); /* 2.048 with 32 TS */
1987150849Sscottl
1988150849Sscottl  /* 0D1:RSB_CR -- Receive System Bus Configuration Register */
1989150849Sscottl  /* Change RINDO & RFSYNC on falling edge of RSBCLKI. */
1990150849Sscottl  write_framer(sc, Bt8370_RSB_CR, 0x70);
1991150849Sscottl
1992150849Sscottl  /* 0D2,0D3:RSYNC_{TS,BIT} -- Receive frame Sync offset */
1993150849Sscottl  write_framer(sc, Bt8370_RSYNC_BIT, 0x00);
1994150849Sscottl  write_framer(sc, Bt8370_RSYNC_TS,  0x00);
1995150849Sscottl
1996150849Sscottl  /* 0D4:TSB_CR -- Transmit System Bus Configuration Register */
1997150849Sscottl  /* Change TINDO & TFSYNC on falling edge of TSBCLKI. */
1998150849Sscottl  write_framer(sc, Bt8370_TSB_CR, 0x30);
1999150849Sscottl
2000150849Sscottl  /* 0D5,0D6:TSYNC_{TS,BIT} -- Transmit frame Sync offset */
2001150849Sscottl  write_framer(sc, Bt8370_TSYNC_BIT, 0x00);
2002150849Sscottl  write_framer(sc, Bt8370_TSYNC_TS,  0x00);
2003150849Sscottl
2004150849Sscottl  /* 0D7:RSIG_CR -- Receive SIGnalling Configuratin Register */
2005150849Sscottl  write_framer(sc, Bt8370_RSIG_CR, 0x00);
2006150849Sscottl
2007150849Sscottl  /* Assign and configure 64Kb TIME SLOTS. */
2008150849Sscottl  /* TS24..TS1 must be assigned for T1, TS31..TS0 for E1. */
2009150849Sscottl  /* Timeslots with no user data have RINDO and TINDO off. */
2010150849Sscottl  for (i=0; i<32; i++)
2011150849Sscottl    {
2012150849Sscottl    /* 0E0-0FF:SBCn -- System Bus Per-Channel Control */
2013150849Sscottl    if      (FORMAT_T1ANY && (i==0 || i>24))
2014150849Sscottl      write_framer(sc, Bt8370_SBCn +i, 0x00); /* not assigned in T1 mode */
2015150849Sscottl    else if (FORMAT_E1ANY && (i==0)  && !FORMAT_E1NONE)
2016150849Sscottl      write_framer(sc, Bt8370_SBCn +i, 0x01); /* assigned, TS0  o/h bits */
2017150849Sscottl    else if (FORMAT_E1CAS && (i==16) && !FORMAT_E1NONE)
2018150849Sscottl      write_framer(sc, Bt8370_SBCn +i, 0x01); /* assigned, TS16 o/h bits */
2019150849Sscottl    else if ((sc->config.time_slots & (1<<i)) != 0)
2020150849Sscottl      write_framer(sc, Bt8370_SBCn +i, 0x0D); /* assigned, RINDO, TINDO */
2021150849Sscottl    else
2022150849Sscottl      write_framer(sc, Bt8370_SBCn +i, 0x01); /* assigned, idle */
2023150849Sscottl
2024150849Sscottl    /* 100-11F:TPCn -- Transmit Per-Channel Control */
2025150849Sscottl    if      (FORMAT_E1CAS && (i==0))
2026150849Sscottl      write_framer(sc, Bt8370_TPCn +i, 0x30); /* tidle, sig=0000 (MAS) */
2027150849Sscottl    else if (FORMAT_E1CAS && (i==16))
2028150849Sscottl      write_framer(sc, Bt8370_TPCn +i, 0x3B); /* tidle, sig=1011 (XYXX) */
2029150849Sscottl    else if ((sc->config.time_slots & (1<<i)) == 0)
2030150849Sscottl      write_framer(sc, Bt8370_TPCn +i, 0x20); /* tidle: use TSLIP_LOn */
2031150849Sscottl    else
2032150849Sscottl      write_framer(sc, Bt8370_TPCn +i, 0x00); /* nothing special */
2033150849Sscottl
2034150849Sscottl    /* 140-15F:TSLIP_LOn -- Transmit PCM Slip Buffer */
2035150849Sscottl    write_framer(sc, Bt8370_TSLIP_LOn +i, 0x7F); /* idle chan data */
2036150849Sscottl    /* 180-19F:RPCn -- Receive Per-Channel Control */
2037150849Sscottl    write_framer(sc, Bt8370_RPCn +i, 0x00);   /* nothing special */
2038150849Sscottl    }
2039150849Sscottl
2040150849Sscottl  /* Enable transmitter output drivers. */
2041150849Sscottl  set_mii16_bits(sc, MII16_T1_XOE);
2042150849Sscottl  }
2043150849Sscottl
2044150849Sscottlstatic void
2045150849Sscottlt1_ident(softc_t *sc)
2046150849Sscottl  {
2047150849Sscottl  printf(", Bt837%x rev %x",
2048150849Sscottl   read_framer(sc, Bt8370_DID)>>4,
2049150849Sscottl   read_framer(sc, Bt8370_DID)&0x0F);
2050150849Sscottl  }
2051150849Sscottl
2052150849Sscottl/* Called once a second; must not sleep. */
2053150849Sscottlstatic int
2054150849Sscottlt1_watchdog(softc_t *sc)
2055150849Sscottl  {
2056150849Sscottl  u_int16_t LCV = 0, FERR = 0, CRC = 0, FEBE = 0;
2057150849Sscottl  u_int8_t alm1, alm3, loop, isr0;
2058150849Sscottl  int link_status = STATUS_UP;
2059150849Sscottl  int i;
2060150849Sscottl
2061150849Sscottl  /* Read the alarm registers */
2062150849Sscottl  alm1 = read_framer(sc, Bt8370_ALM1);
2063150849Sscottl  alm3 = read_framer(sc, Bt8370_ALM3);
2064150849Sscottl  loop = read_framer(sc, Bt8370_LOOP);
2065150849Sscottl  isr0 = read_framer(sc, Bt8370_ISR0);
2066150849Sscottl
2067150849Sscottl  /* Always ignore the SIGFRZ alarm bit, */
2068150849Sscottl  alm1 &= ~ALM1_SIGFRZ;
2069150849Sscottl  if (FORMAT_T1ANY)  /* ignore RYEL in T1 modes */
2070150849Sscottl    alm1 &= ~ALM1_RYEL;
2071150849Sscottl  else if (FORMAT_E1NONE) /* ignore all alarms except LOS */
2072150849Sscottl    alm1 &= ALM1_RLOS;
2073150849Sscottl
2074150849Sscottl  /* Software is alive. */
2075150849Sscottl  led_inv(sc, MII16_T1_LED_GRN);
2076150849Sscottl
2077150849Sscottl  /* Receiving Alarm Indication Signal (AIS). */
2078150849Sscottl  if ((alm1 & ALM1_RAIS)!=0) /* receiving ais */
2079150849Sscottl    led_on(sc, MII16_T1_LED_BLU);
2080150849Sscottl  else if ((alm1 & ALM1_RLOS)!=0) /* sending ais */
2081150849Sscottl    led_inv(sc, MII16_T1_LED_BLU);
2082150849Sscottl  else
2083150849Sscottl    led_off(sc, MII16_T1_LED_BLU);
2084150849Sscottl
2085150849Sscottl  /* Receiving Remote Alarm Indication (RAI). */
2086150849Sscottl  if ((alm1 & (ALM1_RMYEL | ALM1_RYEL))!=0) /* receiving rai */
2087150849Sscottl    led_on(sc, MII16_T1_LED_YEL);
2088150849Sscottl  else if ((alm1 & ALM1_RLOF)!=0) /* sending rai */
2089150849Sscottl    led_inv(sc, MII16_T1_LED_YEL);
2090150849Sscottl  else
2091150849Sscottl    led_off(sc, MII16_T1_LED_YEL);
2092150849Sscottl
2093150849Sscottl  /* If any alarm bits are set then the link is 'down'. */
2094150849Sscottl  /* The bad bits are: rmyel ryel rais ralos rlos rlof. */
2095150849Sscottl  /* Some alarm bits have been masked by this point. */
2096150849Sscottl  if (alm1 != 0) link_status = STATUS_DOWN;
2097150849Sscottl
2098150849Sscottl  /* Declare local Red Alarm if the link is down. */
2099150849Sscottl  if (link_status == STATUS_DOWN)
2100150849Sscottl    led_on(sc, MII16_T1_LED_RED);
2101150849Sscottl  else if (sc->loop_timer != 0) /* loopback is active */
2102150849Sscottl    led_inv(sc, MII16_T1_LED_RED);
2103150849Sscottl  else
2104150849Sscottl    led_off(sc, MII16_T1_LED_RED);
2105150849Sscottl
2106150849Sscottl  /* Print latched error bits if they changed. */
2107150849Sscottl  if ((DRIVER_DEBUG) && (alm1 != sc->last_alm1))
2108150849Sscottl    {
2109150849Sscottl    char *on = "ON ", *off = "OFF";
2110150849Sscottl    printf("%s: RLOF=%s RLOS=%s RALOS=%s RAIS=%s RYEL=%s RMYEL=%s\n",
2111150849Sscottl     NAME_UNIT,
2112150849Sscottl     (alm1 & ALM1_RLOF)  ? on : off,
2113150849Sscottl     (alm1 & ALM1_RLOS)  ? on : off,
2114150849Sscottl     (alm1 & ALM1_RALOS) ? on : off,
2115150849Sscottl     (alm1 & ALM1_RAIS)  ? on : off,
2116150849Sscottl     (alm1 & ALM1_RYEL)  ? on : off,
2117150849Sscottl     (alm1 & ALM1_RMYEL) ? on : off);
2118150849Sscottl    }
2119150849Sscottl
2120150849Sscottl  /* Check and print error counters if non-zero. */
2121150849Sscottl  LCV = read_framer(sc, Bt8370_LCV_LO)  +
2122150849Sscottl        (read_framer(sc, Bt8370_LCV_HI)<<8);
2123150849Sscottl  if (!FORMAT_E1NONE)
2124150849Sscottl    FERR = read_framer(sc, Bt8370_FERR_LO) +
2125150849Sscottl          (read_framer(sc, Bt8370_FERR_HI)<<8);
2126150849Sscottl  if (FORMAT_E1CRC || FORMAT_T1ESF)
2127150849Sscottl    CRC  = read_framer(sc, Bt8370_CRC_LO)  +
2128150849Sscottl          (read_framer(sc, Bt8370_CRC_HI)<<8);
2129150849Sscottl  if (FORMAT_E1CRC)
2130150849Sscottl    FEBE = read_framer(sc, Bt8370_FEBE_LO) +
2131150849Sscottl          (read_framer(sc, Bt8370_FEBE_HI)<<8);
2132150849Sscottl  /* Only LCV is valid if Out-Of-Frame */
2133150849Sscottl  if (FORMAT_E1NONE) FERR = CRC = FEBE = 0;
2134150849Sscottl  if ((DRIVER_DEBUG) && (LCV || FERR || CRC || FEBE))
2135150849Sscottl    printf("%s: LCV=%u FERR=%u CRC=%u FEBE=%u\n",
2136150849Sscottl     NAME_UNIT, LCV,   FERR,   CRC,   FEBE);
2137150849Sscottl
2138150849Sscottl  /* Driver keeps crude link-level error counters (SNMP is better). */
2139150849Sscottl  sc->status.cntrs.lcv_errs  += LCV;
2140150849Sscottl  sc->status.cntrs.frm_errs  += FERR;
2141150849Sscottl  sc->status.cntrs.crc_errs  += CRC;
2142150849Sscottl  sc->status.cntrs.febe_errs += FEBE;
2143150849Sscottl
2144150849Sscottl  /* Check for BOP messages in the ESF Facility Data Link. */
2145150849Sscottl  if ((FORMAT_T1ESF) && (read_framer(sc, Bt8370_ISR1) & 0x80))
2146150849Sscottl    {
2147150849Sscottl    u_int8_t bop_code = read_framer(sc, Bt8370_RBOP) & 0x3F;
2148150849Sscottl
2149150849Sscottl    switch (bop_code)
2150150849Sscottl      {
2151150849Sscottl      case T1BOP_OOF:
2152150849Sscottl        {
2153150849Sscottl        if ((DRIVER_DEBUG) && ((sc->last_alm1 & ALM1_RMYEL)==0))
2154150849Sscottl          printf("%s: Receiving a 'yellow alarm' BOP msg\n", NAME_UNIT);
2155150849Sscottl        break;
2156150849Sscottl        }
2157150849Sscottl      case T1BOP_LINE_UP:
2158150849Sscottl        {
2159150849Sscottl        if (DRIVER_DEBUG)
2160150849Sscottl          printf("%s: Received a 'line loopback activate' BOP msg\n", NAME_UNIT);
2161150849Sscottl        write_framer(sc, Bt8370_LOOP, LOOP_LINE);
2162150849Sscottl        sc->loop_timer = 305;
2163150849Sscottl        break;
2164150849Sscottl        }
2165150849Sscottl      case T1BOP_LINE_DOWN:
2166150849Sscottl        {
2167150849Sscottl        if (DRIVER_DEBUG)
2168150849Sscottl          printf("%s: Received a 'line loopback deactivate' BOP msg\n", NAME_UNIT);
2169150849Sscottl        write_framer(sc, Bt8370_LOOP,
2170150849Sscottl         read_framer(sc, Bt8370_LOOP) & ~LOOP_LINE);
2171150849Sscottl        sc->loop_timer = 0;
2172150849Sscottl        break;
2173150849Sscottl        }
2174150849Sscottl      case T1BOP_PAY_UP:
2175150849Sscottl        {
2176150849Sscottl        if (DRIVER_DEBUG)
2177150849Sscottl          printf("%s: Received a 'payload loopback activate' BOP msg\n", NAME_UNIT);
2178150849Sscottl        write_framer(sc, Bt8370_LOOP, LOOP_PAYLOAD);
2179150849Sscottl        sc->loop_timer = 305;
2180150849Sscottl        break;
2181150849Sscottl        }
2182150849Sscottl      case T1BOP_PAY_DOWN:
2183150849Sscottl        {
2184150849Sscottl        if (DRIVER_DEBUG)
2185150849Sscottl          printf("%s: Received a 'payload loopback deactivate' BOP msg\n", NAME_UNIT);
2186150849Sscottl        write_framer(sc, Bt8370_LOOP,
2187150849Sscottl         read_framer(sc, Bt8370_LOOP) & ~LOOP_PAYLOAD);
2188150849Sscottl        sc->loop_timer = 0;
2189150849Sscottl        break;
2190150849Sscottl        }
2191150849Sscottl      default:
2192150849Sscottl        {
2193150849Sscottl        if (DRIVER_DEBUG)
2194150849Sscottl          printf("%s: Received a type 0x%02X BOP msg\n", NAME_UNIT, bop_code);
2195150849Sscottl        break;
2196150849Sscottl        }
2197150849Sscottl      }
2198150849Sscottl    }
2199150849Sscottl
2200150849Sscottl  /* Check for HDLC pkts in the ESF Facility Data Link. */
2201150849Sscottl  if ((FORMAT_T1ESF) && (read_framer(sc, Bt8370_ISR2) & 0x70))
2202150849Sscottl    {
2203150849Sscottl    /* while (not fifo-empty && not start-of-msg) flush fifo */
2204150849Sscottl    while ((read_framer(sc, Bt8370_RDL1_STAT) & 0x0C) == 0)
2205150849Sscottl      read_framer(sc, Bt8370_RDL1);
2206150849Sscottl    /* If (not fifo-empty), then begin processing fifo contents. */
2207150849Sscottl    if ((read_framer(sc, Bt8370_RDL1_STAT) & 0x0C) == 0x08)
2208150849Sscottl      {
2209150849Sscottl      u_int8_t msg[64];
2210150849Sscottl      u_int8_t stat = read_framer(sc, Bt8370_RDL1);
2211150849Sscottl      sc->status.cntrs.fdl_pkts++;
2212150849Sscottl      for (i=0; i<(stat & 0x3F); i++)
2213150849Sscottl        msg[i] = read_framer(sc, Bt8370_RDL1);
2214150849Sscottl      /* Is this FDL message a T1.403 performance report? */
2215150849Sscottl      if (((stat & 0x3F)==11) &&
2216150849Sscottl          ((msg[0]==0x38) || (msg[0]==0x3A)) &&
2217150849Sscottl           (msg[1]==1)   &&  (msg[2]==3))
2218150849Sscottl        /* Copy 4 PRs from FDL pkt to SNMP struct. */
2219150849Sscottl        memcpy(sc->status.snmp.t1.prm, msg+3, 8);
2220150849Sscottl      }
2221150849Sscottl    }
2222150849Sscottl
2223150849Sscottl  /* Check for inband loop up/down commands. */
2224150849Sscottl  if (FORMAT_T1ANY)
2225150849Sscottl    {
2226150849Sscottl    u_int8_t isr6   = read_framer(sc, Bt8370_ISR6);
2227150849Sscottl    u_int8_t alarm2 = read_framer(sc, Bt8370_ALM2);
2228150849Sscottl    u_int8_t tlb    = read_framer(sc, Bt8370_TLB);
2229150849Sscottl
2230150849Sscottl    /* Inband Code == Loop Up && On Transition && Inband Tx Inactive */
2231150849Sscottl    if ((isr6 & 0x40) && (alarm2 & 0x40) && ((tlb & 1)==0))
2232150849Sscottl      { /* CSU loop up is 10000 10000 ... */
2233150849Sscottl      if (DRIVER_DEBUG)
2234150849Sscottl        printf("%s: Received a 'CSU Loop Up' inband msg\n", NAME_UNIT);
2235150849Sscottl      write_framer(sc, Bt8370_LOOP, LOOP_LINE); /* Loop up */
2236150849Sscottl      sc->loop_timer = 305;
2237150849Sscottl      }
2238150849Sscottl    /* Inband Code == Loop Down && On Transition && Inband Tx Inactive */
2239150849Sscottl    if ((isr6 & 0x80) && (alarm2 & 0x80) && ((tlb & 1)==0))
2240150849Sscottl      { /* CSU loop down is 100 100 100 ... */
2241150849Sscottl      if (DRIVER_DEBUG)
2242150849Sscottl        printf("%s: Received a 'CSU Loop Down' inband msg\n", NAME_UNIT);
2243150849Sscottl      write_framer(sc, Bt8370_LOOP,
2244150849Sscottl       read_framer(sc, Bt8370_LOOP) & ~LOOP_LINE); /* loop down */
2245150849Sscottl      sc->loop_timer = 0;
2246150849Sscottl      }
2247150849Sscottl    }
2248150849Sscottl
2249150849Sscottl  /* Manually send Yellow Alarm BOP msgs. */
2250150849Sscottl  if (FORMAT_T1ESF)
2251150849Sscottl    {
2252150849Sscottl    u_int8_t isr7 = read_framer(sc, Bt8370_ISR7);
2253150849Sscottl
2254150849Sscottl    if ((isr7 & 0x02) && (alm1 & 0x02)) /* RLOF on-transition */
2255150849Sscottl      { /* Start sending continuous Yellow Alarm BOP messages. */
2256150849Sscottl      write_framer(sc, Bt8370_BOP,  RBOP_25 | TBOP_CONT);
2257150849Sscottl      write_framer(sc, Bt8370_TBOP, 0x00); /* send BOP; order matters */
2258150849Sscottl      }
2259150849Sscottl    else if ((isr7 & 0x02) && ((alm1 & 0x02)==0)) /* RLOF off-transition */
2260150849Sscottl      { /* Stop sending continuous Yellow Alarm BOP messages. */
2261150849Sscottl      write_framer(sc, Bt8370_BOP,  RBOP_25 | TBOP_OFF);
2262150849Sscottl      }
2263150849Sscottl    }
2264150849Sscottl
2265150849Sscottl  /* Time out loopback requests. */
2266150849Sscottl  if (sc->loop_timer != 0)
2267150849Sscottl    if (--sc->loop_timer == 0)
2268150849Sscottl      if (loop != 0)
2269150849Sscottl        {
2270150849Sscottl        if (DRIVER_DEBUG)
2271150849Sscottl          printf("%s: Timeout: Loop Down after 300 seconds\n", NAME_UNIT);
2272150849Sscottl        write_framer(sc, Bt8370_LOOP, loop & ~(LOOP_PAYLOAD | LOOP_LINE));
2273150849Sscottl        }
2274150849Sscottl
2275150849Sscottl  /* RX Test Pattern status */
2276150849Sscottl  if ((DRIVER_DEBUG) && (isr0 & 0x10))
2277150849Sscottl    printf("%s: RX Test Pattern Sync\n", NAME_UNIT);
2278150849Sscottl
2279150849Sscottl  /* SNMP Error Counters */
2280150849Sscottl  sc->status.snmp.t1.lcv  = LCV;
2281150849Sscottl  sc->status.snmp.t1.fe   = FERR;
2282150849Sscottl  sc->status.snmp.t1.crc  = CRC;
2283150849Sscottl  sc->status.snmp.t1.febe = FEBE;
2284150849Sscottl
2285150849Sscottl  /* SNMP Line Status */
2286150849Sscottl  sc->status.snmp.t1.line = 0;
2287150849Sscottl  if  (alm1 & ALM1_RMYEL)  sc->status.snmp.t1.line |= TLINE_RX_RAI;
2288150849Sscottl  if  (alm1 & ALM1_RYEL)   sc->status.snmp.t1.line |= TLINE_RX_RAI;
2289150849Sscottl  if  (alm1 & ALM1_RLOF)   sc->status.snmp.t1.line |= TLINE_TX_RAI;
2290150849Sscottl  if  (alm1 & ALM1_RAIS)   sc->status.snmp.t1.line |= TLINE_RX_AIS;
2291150849Sscottl  if  (alm1 & ALM1_RLOS)   sc->status.snmp.t1.line |= TLINE_TX_AIS;
2292150849Sscottl  if  (alm1 & ALM1_RLOF)   sc->status.snmp.t1.line |= TLINE_LOF;
2293150849Sscottl  if  (alm1 & ALM1_RLOS)   sc->status.snmp.t1.line |= TLINE_LOS;
2294150849Sscottl  if  (alm3 & ALM3_RMAIS)  sc->status.snmp.t1.line |= T1LINE_RX_TS16_AIS;
2295150849Sscottl  if  (alm3 & ALM3_SRED)   sc->status.snmp.t1.line |= T1LINE_TX_TS16_LOMF;
2296150849Sscottl  if  (alm3 & ALM3_SEF)    sc->status.snmp.t1.line |= T1LINE_SEF;
2297150849Sscottl  if  (isr0 & 0x10)        sc->status.snmp.t1.line |= T1LINE_RX_TEST;
2298150849Sscottl  if ((alm1 & ALM1_RMYEL) && (FORMAT_E1CAS))
2299150849Sscottl                           sc->status.snmp.t1.line |= T1LINE_RX_TS16_LOMF;
2300150849Sscottl
2301150849Sscottl  /* SNMP Loopback Status */
2302150849Sscottl  sc->status.snmp.t1.loop &= ~(TLOOP_FAR_LINE | TLOOP_FAR_PAYLOAD);
2303150849Sscottl  if (sc->config.loop_back == CFG_LOOP_TULIP)
2304150849Sscottl                           sc->status.snmp.t1.loop |= TLOOP_NEAR_OTHER;
2305150849Sscottl  if (loop & LOOP_PAYLOAD) sc->status.snmp.t1.loop |= TLOOP_NEAR_PAYLOAD;
2306150849Sscottl  if (loop & LOOP_LINE)    sc->status.snmp.t1.loop |= TLOOP_NEAR_LINE;
2307150849Sscottl  if (loop & LOOP_ANALOG)  sc->status.snmp.t1.loop |= TLOOP_NEAR_OTHER;
2308150849Sscottl  if (loop & LOOP_FRAMER)  sc->status.snmp.t1.loop |= TLOOP_NEAR_INWARD;
2309150849Sscottl
2310150849Sscottl  /* Remember this state until next time. */
2311150849Sscottl  sc->last_alm1 = alm1;
2312150849Sscottl
2313150849Sscottl  /* If an INWARD loopback is in effect, link status is UP */
2314150849Sscottl  if (sc->config.loop_back != CFG_LOOP_NONE) /* XXX INWARD ONLY */
2315150849Sscottl    link_status = STATUS_UP;
2316150849Sscottl
2317150849Sscottl  return link_status;
2318150849Sscottl  }
2319150849Sscottl
2320150849Sscottl/* IOCTL SYSCALL: can sleep. */
2321150849Sscottlstatic void
2322150849Sscottlt1_send_bop(softc_t *sc, int bop_code)
2323150849Sscottl  {
2324150849Sscottl  u_int8_t bop;
2325150849Sscottl  int i;
2326150849Sscottl
2327150849Sscottl  /* The BOP transmitter could be sending a continuous */
2328150849Sscottl  /*  BOP msg when told to send this BOP_25 message. */
2329150849Sscottl  /* So save and restore the state of the BOP machine. */
2330150849Sscottl  bop = read_framer(sc, Bt8370_BOP);
2331150849Sscottl  write_framer(sc, Bt8370_BOP, RBOP_OFF | TBOP_OFF);
2332150849Sscottl  for (i=0; i<40; i++) /* max delay 400 ms. */
2333150849Sscottl    if (read_framer(sc, Bt8370_BOP_STAT) & 0x80) SLEEP(10000);
2334150849Sscottl  /* send 25 repetitions of bop_code */
2335150849Sscottl  write_framer(sc, Bt8370_BOP, RBOP_OFF | TBOP_25);
2336150849Sscottl  write_framer(sc, Bt8370_TBOP, bop_code); /* order matters */
2337150849Sscottl  /* wait for tx to stop */
2338150849Sscottl  for (i=0; i<40; i++) /* max delay 400 ms. */
2339150849Sscottl    if (read_framer(sc, Bt8370_BOP_STAT) & 0x80) SLEEP(10000);
2340150849Sscottl  /* Restore previous state of the BOP machine. */
2341150849Sscottl  write_framer(sc, Bt8370_BOP, bop);
2342150849Sscottl  }
2343150849Sscottl
2344150849Sscottl/* IOCTL SYSCALL: can sleep. */
2345150849Sscottlstatic int
2346150849Sscottlt1_ioctl(softc_t *sc, struct ioctl *ioctl)
2347150849Sscottl  {
2348150849Sscottl  int error = 0;
2349150849Sscottl
2350150849Sscottl  switch (ioctl->cmd)
2351150849Sscottl    {
2352150849Sscottl    case IOCTL_SNMP_SEND:  /* set opstatus? */
2353150849Sscottl      {
2354150849Sscottl      switch (ioctl->data)
2355150849Sscottl        {
2356150849Sscottl        case TSEND_NORMAL:
2357150849Sscottl          {
2358150849Sscottl          write_framer(sc, Bt8370_TPATT, 0x00); /* tx pattern generator off */
2359150849Sscottl          write_framer(sc, Bt8370_RPATT, 0x00); /* rx pattern detector off */
2360150849Sscottl          write_framer(sc, Bt8370_TLB,   0x00); /* tx inband generator off */
2361150849Sscottl          break;
2362150849Sscottl	  }
2363150849Sscottl        case TSEND_LINE:
2364150849Sscottl          {
2365150849Sscottl          if (FORMAT_T1ESF)
2366150849Sscottl            t1_send_bop(sc, T1BOP_LINE_UP);
2367150849Sscottl          else if (FORMAT_T1SF)
2368150849Sscottl            {
2369150849Sscottl            write_framer(sc, Bt8370_LBP, 0x08); /* 10000 10000 ... */
2370150849Sscottl            write_framer(sc, Bt8370_TLB, 0x05); /* 5 bits, framed, start */
2371150849Sscottl	    }
2372150849Sscottl          sc->status.snmp.t1.loop |= TLOOP_FAR_LINE;
2373150849Sscottl          break;
2374150849Sscottl	  }
2375150849Sscottl        case TSEND_PAYLOAD:
2376150849Sscottl          {
2377150849Sscottl          t1_send_bop(sc, T1BOP_PAY_UP);
2378150849Sscottl          sc->status.snmp.t1.loop |= TLOOP_FAR_PAYLOAD;
2379150849Sscottl          break;
2380150849Sscottl	  }
2381150849Sscottl        case TSEND_RESET:
2382150849Sscottl          {
2383150849Sscottl          if (sc->status.snmp.t1.loop == TLOOP_FAR_LINE)
2384150849Sscottl            {
2385150849Sscottl            if (FORMAT_T1ESF)
2386150849Sscottl              t1_send_bop(sc, T1BOP_LINE_DOWN);
2387150849Sscottl            else if (FORMAT_T1SF)
2388150849Sscottl              {
2389150849Sscottl              write_framer(sc, Bt8370_LBP, 0x24); /* 100100 100100 ... */
2390150849Sscottl              write_framer(sc, Bt8370_TLB, 0x09); /* 6 bits, framed, start */
2391150849Sscottl	      }
2392150849Sscottl            sc->status.snmp.t1.loop &= ~TLOOP_FAR_LINE;
2393150849Sscottl	    }
2394150849Sscottl          if (sc->status.snmp.t1.loop == TLOOP_FAR_PAYLOAD)
2395150849Sscottl            {
2396150849Sscottl            t1_send_bop(sc, T1BOP_PAY_DOWN);
2397150849Sscottl            sc->status.snmp.t1.loop &= ~TLOOP_FAR_PAYLOAD;
2398150849Sscottl	    }
2399150849Sscottl          break;
2400150849Sscottl	  }
2401150849Sscottl        case TSEND_QRS:
2402150849Sscottl          {
2403150849Sscottl          write_framer(sc, Bt8370_TPATT, 0x1E); /* framed QRSS */
2404150849Sscottl          break;
2405150849Sscottl	  }
2406150849Sscottl        default:
2407150849Sscottl          {
2408150849Sscottl          error = EINVAL;
2409150849Sscottl          break;
2410150849Sscottl	  }
2411150849Sscottl	}
2412150849Sscottl      break;
2413150849Sscottl      }
2414150849Sscottl    case IOCTL_SNMP_LOOP:  /* set opstatus = test? */
2415150849Sscottl      {
2416150849Sscottl      u_int8_t new_loop = 0;
2417150849Sscottl
2418150849Sscottl      if (ioctl->data == CFG_LOOP_NONE)
2419150849Sscottl        new_loop = 0;
2420150849Sscottl      else if (ioctl->data == CFG_LOOP_PAYLOAD)
2421150849Sscottl        new_loop = LOOP_PAYLOAD;
2422150849Sscottl      else if (ioctl->data == CFG_LOOP_LINE)
2423150849Sscottl        new_loop = LOOP_LINE;
2424150849Sscottl      else if (ioctl->data == CFG_LOOP_OTHER)
2425150849Sscottl        new_loop = LOOP_ANALOG;
2426150849Sscottl      else if (ioctl->data == CFG_LOOP_INWARD)
2427150849Sscottl        new_loop = LOOP_FRAMER;
2428150849Sscottl      else if (ioctl->data == CFG_LOOP_DUAL)
2429150849Sscottl        new_loop = LOOP_DUAL;
2430150849Sscottl      else
2431150849Sscottl        error = EINVAL;
2432150849Sscottl      if (error == 0)
2433150849Sscottl        {
2434150849Sscottl        write_framer(sc, Bt8370_LOOP, new_loop);
2435150849Sscottl        sc->config.loop_back = ioctl->data;
2436150849Sscottl	}
2437150849Sscottl      break;
2438150849Sscottl      }
2439150849Sscottl    default:
2440150849Sscottl      error = EINVAL;
2441150849Sscottl      break;
2442150849Sscottl    }
2443150849Sscottl
2444150849Sscottl  return error;
2445150849Sscottl  }
2446150849Sscottl
2447150849Sscottlstatic
2448150849Sscottlstruct card hssi_card =
2449150849Sscottl  {
2450150849Sscottl  .config   = hssi_config,
2451150849Sscottl  .ident    = hssi_ident,
2452150849Sscottl  .watchdog = hssi_watchdog,
2453150849Sscottl  .ioctl    = hssi_ioctl,
2454150849Sscottl  };
2455150849Sscottl
2456150849Sscottlstatic
2457150849Sscottlstruct card t3_card =
2458150849Sscottl  {
2459150849Sscottl  .config   = t3_config,
2460150849Sscottl  .ident    = t3_ident,
2461150849Sscottl  .watchdog = t3_watchdog,
2462150849Sscottl  .ioctl    = t3_ioctl,
2463150849Sscottl  };
2464150849Sscottl
2465150849Sscottlstatic
2466150849Sscottlstruct card ssi_card =
2467150849Sscottl  {
2468150849Sscottl  .config   = ssi_config,
2469150849Sscottl  .ident    = ssi_ident,
2470150849Sscottl  .watchdog = ssi_watchdog,
2471150849Sscottl  .ioctl    = ssi_ioctl,
2472150849Sscottl  };
2473150849Sscottl
2474150849Sscottlstatic
2475150849Sscottlstruct card t1_card =
2476150849Sscottl  {
2477150849Sscottl  .config   = t1_config,
2478150849Sscottl  .ident    = t1_ident,
2479150849Sscottl  .watchdog = t1_watchdog,
2480150849Sscottl  .ioctl    = t1_ioctl,
2481150849Sscottl  };
2482150849Sscottl
2483150849Sscottl/* RAWIP is raw IP packets (v4 or v6) in HDLC frames with NO HEADERS. */
2484150849Sscottl/* No HDLC Address/Control fields!  No line control protocol at all!  */
2485150849Sscottl/* This code is BSD/ifnet-specific; Linux and Netgraph also do RAWIP. */
2486150849Sscottl
2487150849Sscottl#if IFNET
2488150849Sscottl
2489153084Sru# if ((defined(__FreeBSD__) && (__FreeBSD_version < 500000)) ||\
2490153084Sru        defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__))
2491150849Sscottlstatic void
2492150849Sscottlnetisr_dispatch(int isr, struct mbuf *mbuf)
2493150849Sscottl  {
2494150849Sscottl  struct ifqueue *intrq = NULL;
2495150849Sscottl  int qfull = 0;
2496150849Sscottl
2497150849Sscottl#if INET
2498150849Sscottl  if (isr == NETISR_IP)   intrq = &ipintrq;
2499150849Sscottl#endif
2500150849Sscottl#if INET6
2501150849Sscottl  if (isr == NETISR_IPV6) intrq = &ip6intrq;
2502150849Sscottl#endif
2503150849Sscottl
2504150849Sscottl  if ((intrq != NULL) && ((qfull = IF_QFULL(intrq)) == 0))
2505150849Sscottl    {
2506150849Sscottl    /* rxintr_cleanup() ENQUEUES in a hard interrupt. */
2507150849Sscottl    /* networking code DEQUEUES in a soft interrupt. */
2508150849Sscottl    /* Some BSD QUEUE routines are not interrupt-safe. */
2509150849Sscottl    DISABLE_INTR; /* noop in FreeBSD */
2510150849Sscottl    IF_ENQUEUE(intrq, mbuf);
2511150849Sscottl    ENABLE_INTR;
2512150849Sscottl    schednetisr(isr); /* schedule a soft interrupt */
2513150849Sscottl    }
2514150849Sscottl  else
2515150849Sscottl    {
2516150849Sscottl    m_freem(mbuf);
2517150849Sscottl    if ((intrq != NULL) && (qfull != 0))
2518150849Sscottl      IF_DROP(intrq);
2519150849Sscottl    }
2520150849Sscottl  }
2521150849Sscottl# endif /* ((__FreeBSD__ && (__FreeBSD_version < 500000)) || */
2522150849Sscottl           /* __NetBSD__ || __OpenBSD__ || __bsdi__) */
2523150849Sscottl
2524150849Sscottl/* rxintr_cleanup calls this to give a newly arrived pkt to higher levels. */
2525150849Sscottlstatic void
2526180304Srwatsonlmc_raw_input(struct ifnet *ifp, struct mbuf *mbuf)
2527150849Sscottl  {
2528150849Sscottl  softc_t *sc = IFP2SC(ifp);
2529150849Sscottl
2530223741Sbz  M_SETFIB(mbuf, ifp->if_fib);
2531150849Sscottl# if INET
2532150849Sscottl  if (mbuf->m_data[0]>>4 == 4)
2533150849Sscottl    netisr_dispatch(NETISR_IP,   mbuf);
2534150849Sscottl  else
2535150849Sscottl# endif
2536150849Sscottl# if INET6
2537150849Sscottl  if (mbuf->m_data[0]>>4 == 6)
2538150849Sscottl    netisr_dispatch(NETISR_IPV6, mbuf);
2539150849Sscottl  else
2540150849Sscottl# endif
2541150849Sscottl    {
2542150849Sscottl    m_freem(mbuf);
2543150849Sscottl    sc->status.cntrs.idiscards++;
2544150849Sscottl    if (DRIVER_DEBUG)
2545180304Srwatson      printf("%s: lmc_raw_input: rx pkt discarded: not IPv4 or IPv6\n",
2546180304Srwatson	NAME_UNIT);
2547150849Sscottl    }
2548150849Sscottl  }
2549150849Sscottl
2550150849Sscottl#endif /* IFNET */
2551150849Sscottl
2552150849Sscottl/* There are TWO VERSIONS of interrupt/DMA code: Linux & BSD.
2553150849Sscottl * Handling Linux and the BSDs with CPP directives would
2554150849Sscottl *  make the code unreadable, so there are two versions.
2555150849Sscottl * Conceptually, the two versions do the same thing and
2556150849Sscottl *  core_interrupt() doesn't know they are different.
2557150849Sscottl *
2558150849Sscottl * We are "standing on the head of a pin" in these routines.
2559150849Sscottl * Tulip CSRs can be accessed, but nothing else is interrupt-safe!
2560150849Sscottl * Do NOT access: MII, GPIO, SROM, BIOSROM, XILINX, SYNTH, or DAC.
2561150849Sscottl */
2562150849Sscottl
2563150849Sscottl#if BSD /* BSD version of interrupt/DMA code */
2564150849Sscottl
2565150849Sscottl/* Singly-linked tail-queues hold mbufs with active DMA.
2566150849Sscottl * For RX, single mbuf clusters; for TX, mbuf chains are queued.
2567150849Sscottl * NB: mbufs are linked through their m_nextpkt field.
2568150849Sscottl * Callers must hold sc->bottom_lock; not otherwise locked.
2569150849Sscottl */
2570150849Sscottl
2571150849Sscottl/* Put an mbuf (chain) on the tail of the descriptor ring queue. */
2572150849Sscottlstatic void  /* BSD version */
2573150849Sscottlmbuf_enqueue(struct desc_ring *ring, struct mbuf *m)
2574150849Sscottl  {
2575150849Sscottl  m->m_nextpkt = NULL;
2576150849Sscottl  if (ring->tail == NULL)
2577150849Sscottl    ring->head = m;
2578150849Sscottl  else
2579150849Sscottl    ring->tail->m_nextpkt = m;
2580150849Sscottl  ring->tail = m;
2581150849Sscottl  }
2582150849Sscottl
2583150849Sscottl/* Get an mbuf (chain) from the head of the descriptor ring queue. */
2584150849Sscottlstatic struct mbuf*  /* BSD version */
2585150849Sscottlmbuf_dequeue(struct desc_ring *ring)
2586150849Sscottl  {
2587150849Sscottl  struct mbuf *m = ring->head;
2588150849Sscottl  if (m != NULL)
2589150849Sscottl    if ((ring->head = m->m_nextpkt) == NULL)
2590150849Sscottl      ring->tail = NULL;
2591150849Sscottl  return m;
2592150849Sscottl  }
2593150849Sscottl
2594153084Sru# ifdef __FreeBSD__
2595150849Sscottlstatic void /* *** FreeBSD ONLY *** Callout from bus_dmamap_load() */
2596150849Sscottlfbsd_dmamap_load(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
2597150849Sscottl  {
2598150849Sscottl  struct desc_ring *ring = arg;
2599150849Sscottl  ring->nsegs = error ? 0 : nsegs;
2600150849Sscottl  ring->segs[0] = segs[0];
2601150849Sscottl  ring->segs[1] = segs[1];
2602150849Sscottl  }
2603150849Sscottl# endif
2604150849Sscottl
2605150849Sscottl/* Initialize a DMA descriptor ring. */
2606150849Sscottlstatic int  /* BSD version */
2607150849Sscottlcreate_ring(softc_t *sc, struct desc_ring *ring, int num_descs)
2608150849Sscottl  {
2609150849Sscottl  struct dma_desc *descs;
2610150849Sscottl  int size_descs = sizeof(struct dma_desc)*num_descs;
2611150849Sscottl  int i, error = 0;
2612150849Sscottl
2613150849Sscottl  /* The DMA descriptor array must not cross a page boundary. */
2614150849Sscottl  if (size_descs > PAGE_SIZE)
2615150849Sscottl    {
2616150899Sscottl    printf("%s: DMA descriptor array > PAGE_SIZE (%d)\n", NAME_UNIT,
2617150899Sscottl     (u_int)PAGE_SIZE);
2618150849Sscottl    return EINVAL;
2619150849Sscottl    }
2620150849Sscottl
2621153084Sru#ifdef __FreeBSD__
2622150849Sscottl
2623150849Sscottl  /* Create a DMA tag for descriptors and buffers. */
2624232874Sscottl  if ((error = bus_dma_tag_create(bus_get_dma_tag(sc->dev),
2625232874Sscottl   4, 0, BUS_SPACE_MAXADDR_32BIT,
2626150849Sscottl   BUS_SPACE_MAXADDR, NULL, NULL, PAGE_SIZE, 2, PAGE_SIZE, BUS_DMA_ALLOCNOW,
2627150849Sscottl# if (__FreeBSD_version >= 502000)
2628150849Sscottl   NULL, NULL,
2629150849Sscottl# endif
2630150849Sscottl   &ring->tag)))
2631150849Sscottl    {
2632150849Sscottl    printf("%s: bus_dma_tag_create() failed: error %d\n", NAME_UNIT, error);
2633150849Sscottl    return error;
2634150849Sscottl    }
2635150849Sscottl
2636150849Sscottl  /* Allocate wired physical memory for DMA descriptor array */
2637150849Sscottl  /*  and map physical address to kernel virtual address. */
2638150849Sscottl  if ((error = bus_dmamem_alloc(ring->tag, (void**)&ring->first,
2639150849Sscottl   BUS_DMA_NOWAIT | BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->map)))
2640150849Sscottl    {
2641150849Sscottl    printf("%s: bus_dmamem_alloc() failed; error %d\n", NAME_UNIT, error);
2642150849Sscottl    return error;
2643150849Sscottl    }
2644150849Sscottl  descs = ring->first;
2645150849Sscottl
2646150849Sscottl  /* Map kernel virtual address to PCI address for DMA descriptor array. */
2647150849Sscottl  if ((error = bus_dmamap_load(ring->tag, ring->map, descs, size_descs,
2648150849Sscottl   fbsd_dmamap_load, ring, 0)))
2649150849Sscottl    {
2650150849Sscottl    printf("%s: bus_dmamap_load() failed; error %d\n", NAME_UNIT, error);
2651150849Sscottl    return error;
2652150849Sscottl    }
2653150849Sscottl  ring->dma_addr = ring->segs[0].ds_addr;
2654150849Sscottl
2655150849Sscottl  /* Allocate dmamaps for each DMA descriptor. */
2656150849Sscottl  for (i=0; i<num_descs; i++)
2657150849Sscottl    if ((error = bus_dmamap_create(ring->tag, 0, &descs[i].map)))
2658150849Sscottl      {
2659150849Sscottl      printf("%s: bus_dmamap_create() failed; error %d\n", NAME_UNIT, error);
2660150849Sscottl      return error;
2661150849Sscottl      }
2662150849Sscottl
2663153084Sru#elif (defined(__NetBSD__) || defined(__OpenBSD__))
2664150849Sscottl
2665150849Sscottl  /* Use the DMA tag passed to attach() for descriptors and buffers. */
2666150849Sscottl  ring->tag = sc->pa_dmat;
2667150849Sscottl
2668150849Sscottl  /* Allocate wired physical memory for DMA descriptor array. */
2669150849Sscottl  if ((error = bus_dmamem_alloc(ring->tag, size_descs, PAGE_SIZE, 0,
2670150849Sscottl   ring->segs, 1, &ring->nsegs, BUS_DMA_NOWAIT)))
2671150849Sscottl    {
2672150849Sscottl    printf("%s: bus_dmamem_alloc() failed; error %d\n", NAME_UNIT, error);
2673150849Sscottl    return error;
2674150849Sscottl    }
2675150849Sscottl
2676150849Sscottl  /* Map physical address to kernel virtual address. */
2677150849Sscottl  if ((error = bus_dmamem_map(ring->tag, ring->segs, ring->nsegs,
2678150849Sscottl   size_descs, (caddr_t *)&ring->first, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)))
2679150849Sscottl    {
2680150849Sscottl    printf("%s: bus_dmamem_map() failed; error %d\n", NAME_UNIT, error);
2681150849Sscottl    return error;
2682150849Sscottl    }
2683150849Sscottl  descs = ring->first; /* suppress compiler warning about aliasing */
2684150849Sscottl  memset(descs, 0, size_descs);
2685150849Sscottl
2686150849Sscottl  /* Allocate dmamap for PCI access to DMA descriptor array. */
2687150849Sscottl  if ((error = bus_dmamap_create(ring->tag, size_descs, 1,
2688150849Sscottl   size_descs, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ring->map)))
2689150849Sscottl    {
2690150849Sscottl    printf("%s: bus_dmamap_create() failed; error %d\n", NAME_UNIT, error);
2691150849Sscottl    return error;
2692150849Sscottl    }
2693150849Sscottl
2694150849Sscottl  /* Map kernel virtual address to PCI address for DMA descriptor array. */
2695150849Sscottl  if ((error = bus_dmamap_load(ring->tag, ring->map, descs, size_descs,
2696150849Sscottl   0, BUS_DMA_NOWAIT)))
2697150849Sscottl    {
2698150849Sscottl    printf("%s: bus_dmamap_load() failed; error %d\n", NAME_UNIT, error);
2699150849Sscottl    return error;
2700150849Sscottl    }
2701150849Sscottl  ring->dma_addr = ring->map->dm_segs[0].ds_addr;
2702150849Sscottl
2703150849Sscottl  /* Allocate dmamaps for each DMA descriptor. */
2704150849Sscottl  for (i=0; i<num_descs; i++)
2705150849Sscottl    if ((error = bus_dmamap_create(ring->tag, MAX_DESC_LEN, 2,
2706150849Sscottl     MAX_CHUNK_LEN, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &descs[i].map)))
2707150849Sscottl      {
2708150849Sscottl      printf("%s: bus_dmamap_create() failed; error %d\n", NAME_UNIT, error);
2709150849Sscottl      return error;
2710150849Sscottl      }
2711150849Sscottl
2712153084Sru#elif defined(__bsdi__)
2713150849Sscottl
2714150849Sscottl  /* Allocate wired physical memory for DMA descriptor array. */
2715150849Sscottl  if ((ring->first = malloc(size_descs, M_DEVBUF, M_NOWAIT)) == NULL)
2716150849Sscottl    {
2717150849Sscottl    printf("%s: malloc() failed for DMA descriptor array\n", NAME_UNIT);
2718150849Sscottl    return ENOMEM;
2719150849Sscottl    }
2720150849Sscottl  descs = ring->first;
2721150849Sscottl  memset(descs, 0, size_descs);
2722150849Sscottl
2723150849Sscottl  /* Map kernel virtual address to PCI address for DMA descriptor array. */
2724150849Sscottl  ring->dma_addr = vtophys(descs); /* Relax! BSD/OS only. */
2725150849Sscottl
2726150849Sscottl#endif
2727150849Sscottl
2728150849Sscottl  ring->read  = descs;
2729150849Sscottl  ring->write = descs;
2730150849Sscottl  ring->first = descs;
2731150849Sscottl  ring->last  = descs + num_descs -1;
2732150849Sscottl  ring->last->control = TLP_DCTL_END_RING;
2733150849Sscottl  ring->num_descs = num_descs;
2734150849Sscottl  ring->size_descs = size_descs;
2735150849Sscottl  ring->head = NULL;
2736150849Sscottl  ring->tail = NULL;
2737150849Sscottl
2738150849Sscottl  return 0;
2739150849Sscottl  }
2740150849Sscottl
2741150849Sscottl/* Destroy a DMA descriptor ring */
2742150849Sscottlstatic void  /* BSD version */
2743150849Sscottldestroy_ring(softc_t *sc, struct desc_ring *ring)
2744150849Sscottl  {
2745150849Sscottl  struct dma_desc *desc;
2746150849Sscottl  struct mbuf *m;
2747150849Sscottl
2748150849Sscottl  /* Free queued mbufs. */
2749150849Sscottl  while ((m = mbuf_dequeue(ring)) != NULL)
2750150849Sscottl    m_freem(m);
2751150849Sscottl
2752150849Sscottl  /* TX may have one pkt that is not on any queue. */
2753150849Sscottl  if (sc->tx_mbuf != NULL)
2754150849Sscottl    {
2755150849Sscottl    m_freem(sc->tx_mbuf);
2756150849Sscottl    sc->tx_mbuf = NULL;
2757150849Sscottl    }
2758150849Sscottl
2759150849Sscottl  /* Unmap active DMA descriptors. */
2760150849Sscottl  while (ring->read != ring->write)
2761150849Sscottl    {
2762150849Sscottl    bus_dmamap_unload(ring->tag, ring->read->map);
2763150849Sscottl    if (ring->read++ == ring->last) ring->read = ring->first;
2764150849Sscottl    }
2765150849Sscottl
2766153084Sru#ifdef __FreeBSD__
2767150849Sscottl
2768150849Sscottl  /* Free the dmamaps of all DMA descriptors. */
2769150849Sscottl  for (desc=ring->first; desc!=ring->last+1; desc++)
2770150849Sscottl    if (desc->map != NULL)
2771150849Sscottl      bus_dmamap_destroy(ring->tag, desc->map);
2772150849Sscottl
2773150849Sscottl  /* Unmap PCI address for DMA descriptor array. */
2774150849Sscottl  if (ring->dma_addr != 0)
2775150849Sscottl    bus_dmamap_unload(ring->tag, ring->map);
2776150849Sscottl  /* Free kernel memory for DMA descriptor array. */
2777150849Sscottl  if (ring->first != NULL)
2778150849Sscottl    bus_dmamem_free(ring->tag, ring->first, ring->map);
2779150849Sscottl  /* Free the DMA tag created for this ring. */
2780150849Sscottl  if (ring->tag != NULL)
2781150849Sscottl    bus_dma_tag_destroy(ring->tag);
2782150849Sscottl
2783153084Sru#elif (defined(__NetBSD__) || defined(__OpenBSD__))
2784150849Sscottl
2785150849Sscottl  /* Free the dmamaps of all DMA descriptors. */
2786150849Sscottl  for (desc=ring->first; desc!=ring->last+1; desc++)
2787150849Sscottl    if (desc->map != NULL)
2788150849Sscottl      bus_dmamap_destroy(ring->tag, desc->map);
2789150849Sscottl
2790150849Sscottl  /* Unmap PCI address for DMA descriptor array. */
2791150849Sscottl  if (ring->dma_addr != 0)
2792150849Sscottl    bus_dmamap_unload(ring->tag, ring->map);
2793150849Sscottl  /* Free dmamap for DMA descriptor array. */
2794150849Sscottl  if (ring->map != NULL)
2795150849Sscottl    bus_dmamap_destroy(ring->tag, ring->map);
2796150849Sscottl  /* Unmap kernel address for DMA descriptor array. */
2797150849Sscottl  if (ring->first != NULL)
2798150849Sscottl    bus_dmamem_unmap(ring->tag, (caddr_t)ring->first, ring->size_descs);
2799150849Sscottl  /* Free kernel memory for DMA descriptor array. */
2800150849Sscottl  if (ring->segs[0].ds_addr != 0)
2801150849Sscottl    bus_dmamem_free(ring->tag, ring->segs, ring->nsegs);
2802150849Sscottl
2803153084Sru#elif defined(__bsdi__)
2804150849Sscottl
2805150849Sscottl  /* Free kernel memory for DMA descriptor array. */
2806150849Sscottl  if (ring->first != NULL)
2807150849Sscottl    free(ring->first, M_DEVBUF);
2808150849Sscottl
2809150849Sscottl#endif
2810150849Sscottl  }
2811150849Sscottl
2812150849Sscottl/* Clean up after a packet has been received. */
2813150849Sscottlstatic int  /* BSD version */
2814150849Sscottlrxintr_cleanup(softc_t *sc)
2815150849Sscottl  {
2816150849Sscottl  struct desc_ring *ring = &sc->rxring;
2817150849Sscottl  struct dma_desc *first_desc, *last_desc;
2818150849Sscottl  struct mbuf *first_mbuf=NULL, *last_mbuf=NULL;
2819150849Sscottl  struct mbuf *new_mbuf;
2820150849Sscottl  int pkt_len, desc_len;
2821150849Sscottl
2822153110Sru#if (defined(__FreeBSD__) && defined(DEVICE_POLLING))
2823150849Sscottl  /* Input packet flow control (livelock prevention): */
2824150849Sscottl  /* Give pkts to higher levels only if quota is > 0. */
2825150849Sscottl  if (sc->quota <= 0) return 0;
2826150849Sscottl#endif
2827150849Sscottl
2828150849Sscottl  /* This looks complicated, but remember: typically packets up */
2829150849Sscottl  /*  to 2048 bytes long fit in one mbuf and use one descriptor. */
2830150849Sscottl
2831150849Sscottl  first_desc = last_desc = ring->read;
2832150849Sscottl
2833150849Sscottl  /* ASSERTION: If there is a descriptor in the ring and the hardware has */
2834150849Sscottl  /*  finished with it, then that descriptor will have RX_FIRST_DESC set. */
2835150849Sscottl  if ((ring->read != ring->write) && /* descriptor ring not empty */
2836150849Sscottl     ((ring->read->status & TLP_DSTS_OWNER) == 0) && /* hardware done */
2837150849Sscottl     ((ring->read->status & TLP_DSTS_RX_FIRST_DESC) == 0)) /* should be set */
2838150849Sscottl    panic("%s: rxintr_cleanup: rx-first-descriptor not set.\n", NAME_UNIT);
2839150849Sscottl
2840150849Sscottl  /* First decide if a complete packet has arrived. */
2841150849Sscottl  /* Run down DMA descriptors looking for one marked "last". */
2842150849Sscottl  /* Bail out if an active descriptor is encountered. */
2843150849Sscottl  /* Accumulate most significant bits of packet length. */
2844150849Sscottl  pkt_len = 0;
2845150849Sscottl  for (;;)
2846150849Sscottl    {
2847150849Sscottl    if (last_desc == ring->write) return 0;  /* no more descs */
2848150849Sscottl    if (last_desc->status & TLP_DSTS_OWNER) return 0; /* still active */
2849150849Sscottl    if (last_desc->status & TLP_DSTS_RX_LAST_DESC) break; /* end of packet */
2850150849Sscottl    pkt_len += last_desc->length1 + last_desc->length2; /* entire desc filled */
2851150849Sscottl    if (last_desc++->control & TLP_DCTL_END_RING) last_desc = ring->first; /* ring wrap */
2852150849Sscottl    }
2853150849Sscottl
2854150849Sscottl  /* A complete packet has arrived; how long is it? */
2855150849Sscottl  /* H/w ref man shows RX pkt length as a 14-bit field. */
2856150849Sscottl  /* An experiment found that only the 12 LSBs work. */
2857150849Sscottl  if (((last_desc->status>>16)&0xFFF) == 0) pkt_len += 4096; /* carry-bit */
2858150849Sscottl  pkt_len = (pkt_len & 0xF000) + ((last_desc->status>>16) & 0x0FFF);
2859150849Sscottl  /* Subtract the CRC length unless doing so would underflow. */
2860150849Sscottl  if (pkt_len >= sc->config.crc_len) pkt_len -= sc->config.crc_len;
2861150849Sscottl
2862150849Sscottl  /* Run down DMA descriptors again doing the following:
2863150849Sscottl   *  1) put pkt info in pkthdr of first mbuf,
2864150849Sscottl   *  2) link mbufs,
2865150849Sscottl   *  3) set mbuf lengths.
2866150849Sscottl   */
2867150849Sscottl  first_desc = ring->read;
2868150849Sscottl  do
2869150849Sscottl    {
2870150849Sscottl    /* Read a DMA descriptor from the ring. */
2871150849Sscottl    last_desc = ring->read;
2872150849Sscottl    /* Advance the ring read pointer. */
2873150849Sscottl    if (ring->read++ == ring->last) ring->read = ring->first;
2874150849Sscottl
2875150849Sscottl    /* Dequeue the corresponding cluster mbuf. */
2876150849Sscottl    new_mbuf = mbuf_dequeue(ring);
2877150849Sscottl    if (new_mbuf == NULL)
2878150849Sscottl      panic("%s: rxintr_cleanup: expected an mbuf\n", NAME_UNIT);
2879150849Sscottl
2880150849Sscottl    desc_len = last_desc->length1 + last_desc->length2;
2881150849Sscottl    /* If bouncing, copy bounce buf to mbuf. */
2882150849Sscottl    DMA_SYNC(last_desc->map, desc_len, BUS_DMASYNC_POSTREAD);
2883150849Sscottl    /* Unmap kernel virtual address to PCI address. */
2884150849Sscottl    bus_dmamap_unload(ring->tag, last_desc->map);
2885150849Sscottl
2886150849Sscottl    /* 1) Put pkt info in pkthdr of first mbuf. */
2887150849Sscottl    if (last_desc == first_desc)
2888150849Sscottl      {
2889150849Sscottl      first_mbuf = new_mbuf;
2890150849Sscottl      first_mbuf->m_pkthdr.len   = pkt_len; /* total pkt length */
2891150849Sscottl#if IFNET
2892150849Sscottl      first_mbuf->m_pkthdr.rcvif = sc->ifp; /* how it got here */
2893150849Sscottl#else
2894150849Sscottl      first_mbuf->m_pkthdr.rcvif = NULL;
2895150849Sscottl#endif
2896150849Sscottl      }
2897150849Sscottl    else /* 2) link mbufs. */
2898150849Sscottl      {
2899150849Sscottl      last_mbuf->m_next = new_mbuf;
2900150849Sscottl      /* M_PKTHDR should be set in the first mbuf only. */
2901150849Sscottl      new_mbuf->m_flags &= ~M_PKTHDR;
2902150849Sscottl      }
2903150849Sscottl    last_mbuf = new_mbuf;
2904150849Sscottl
2905150849Sscottl    /* 3) Set mbuf lengths. */
2906150849Sscottl    new_mbuf->m_len = (pkt_len >= desc_len) ? desc_len : pkt_len;
2907150849Sscottl    pkt_len -= new_mbuf->m_len;
2908150849Sscottl    } while ((last_desc->status & TLP_DSTS_RX_LAST_DESC) == 0);
2909150849Sscottl
2910150849Sscottl  /* Decide whether to accept or to discard this packet. */
2911150849Sscottl  /* RxHDLC sets MIIERR for bad CRC, abort and partial byte at pkt end. */
2912150849Sscottl  if (((last_desc->status & TLP_DSTS_RX_BAD) == 0) &&
2913150849Sscottl   (sc->status.oper_status == STATUS_UP) &&
2914150849Sscottl   (first_mbuf->m_pkthdr.len > 0))
2915150849Sscottl    {
2916150849Sscottl    /* Optimization: copy a small pkt into a small mbuf. */
2917150849Sscottl    if (first_mbuf->m_pkthdr.len <= COPY_BREAK)
2918150849Sscottl      {
2919243857Sglebius      MGETHDR(new_mbuf, M_NOWAIT, MT_DATA);
2920150849Sscottl      if (new_mbuf != NULL)
2921150849Sscottl        {
2922150849Sscottl        new_mbuf->m_pkthdr.rcvif = first_mbuf->m_pkthdr.rcvif;
2923150849Sscottl        new_mbuf->m_pkthdr.len   = first_mbuf->m_pkthdr.len;
2924150849Sscottl        new_mbuf->m_len          = first_mbuf->m_len;
2925150849Sscottl        memcpy(new_mbuf->m_data,   first_mbuf->m_data,
2926150849Sscottl         first_mbuf->m_pkthdr.len);
2927150849Sscottl        m_freem(first_mbuf);
2928150849Sscottl        first_mbuf = new_mbuf;
2929150849Sscottl        }
2930150849Sscottl      }
2931150849Sscottl    /* Include CRC and one flag byte in input byte count. */
2932150849Sscottl    sc->status.cntrs.ibytes += first_mbuf->m_pkthdr.len + sc->config.crc_len +1;
2933150849Sscottl    sc->status.cntrs.ipackets++;
2934150849Sscottl#if IFNET
2935150849Sscottl    sc->ifp->if_ipackets++;
2936150849Sscottl    LMC_BPF_MTAP(first_mbuf);
2937150849Sscottl#endif
2938153110Sru#if (defined(__FreeBSD__) && defined(DEVICE_POLLING))
2939150849Sscottl    sc->quota--;
2940150849Sscottl#endif
2941150849Sscottl
2942150849Sscottl    /* Give this good packet to the network stacks. */
2943150849Sscottl#if NETGRAPH
2944150849Sscottl    if (sc->ng_hook != NULL) /* is hook connected? */
2945150849Sscottl      {
2946150849Sscottl# if (__FreeBSD_version >= 500000)
2947150849Sscottl      int error;  /* ignore error */
2948150849Sscottl      NG_SEND_DATA_ONLY(error, sc->ng_hook, first_mbuf);
2949150849Sscottl# else /* FreeBSD-4 */
2950150849Sscottl      ng_queue_data(sc->ng_hook, first_mbuf, NULL);
2951150849Sscottl# endif
2952150849Sscottl      return 1;  /* did something */
2953150849Sscottl      }
2954150849Sscottl#endif /* NETGRAPH */
2955150849Sscottl    if (sc->config.line_pkg == PKG_RAWIP)
2956180304Srwatson      lmc_raw_input(sc->ifp, first_mbuf);
2957150849Sscottl    else
2958150849Sscottl      {
2959150849Sscottl#if NSPPP
2960150849Sscottl      sppp_input(sc->ifp, first_mbuf);
2961150849Sscottl#elif P2P
2962150849Sscottl      new_mbuf = first_mbuf;
2963150849Sscottl      while (new_mbuf != NULL)
2964150849Sscottl        {
2965150849Sscottl        sc->p2p->p2p_hdrinput(sc->p2p, new_mbuf->m_data, new_mbuf->m_len);
2966150849Sscottl        new_mbuf = new_mbuf->m_next;
2967150849Sscottl        }
2968150849Sscottl      sc->p2p->p2p_input(sc->p2p, NULL);
2969150849Sscottl      m_freem(first_mbuf);
2970150849Sscottl#else
2971150849Sscottl      m_freem(first_mbuf);
2972150849Sscottl      sc->status.cntrs.idiscards++;
2973150849Sscottl#endif
2974150849Sscottl      }
2975150849Sscottl    }
2976150849Sscottl  else if (sc->status.oper_status != STATUS_UP)
2977150849Sscottl    {
2978150849Sscottl    /* If the link is down, this packet is probably noise. */
2979150849Sscottl    m_freem(first_mbuf);
2980150849Sscottl    sc->status.cntrs.idiscards++;
2981150849Sscottl    if (DRIVER_DEBUG)
2982150849Sscottl      printf("%s: rxintr_cleanup: rx pkt discarded: link down\n", NAME_UNIT);
2983150849Sscottl    }
2984150849Sscottl  else /* Log and discard this bad packet. */
2985150849Sscottl    {
2986150849Sscottl    if (DRIVER_DEBUG)
2987150849Sscottl      printf("%s: RX bad pkt; len=%d %s%s%s%s\n",
2988150849Sscottl       NAME_UNIT, first_mbuf->m_pkthdr.len,
2989150849Sscottl       (last_desc->status & TLP_DSTS_RX_MII_ERR)  ? " miierr"  : "",
2990150849Sscottl       (last_desc->status & TLP_DSTS_RX_DRIBBLE)  ? " dribble" : "",
2991150849Sscottl       (last_desc->status & TLP_DSTS_RX_DESC_ERR) ? " descerr" : "",
2992150849Sscottl       (last_desc->status & TLP_DSTS_RX_OVERRUN)  ? " overrun" : "");
2993150849Sscottl    if (last_desc->status & TLP_DSTS_RX_OVERRUN)
2994150849Sscottl      sc->status.cntrs.fifo_over++;
2995150849Sscottl    else
2996150849Sscottl      sc->status.cntrs.ierrors++;
2997150849Sscottl    m_freem(first_mbuf);
2998150849Sscottl    }
2999150849Sscottl
3000150849Sscottl  return 1; /* did something */
3001150849Sscottl  }
3002150849Sscottl
3003150849Sscottl/* Setup (prepare) to receive a packet. */
3004150849Sscottl/* Try to keep the RX descriptor ring full of empty buffers. */
3005150849Sscottlstatic int  /* BSD version */
3006150849Sscottlrxintr_setup(softc_t *sc)
3007150849Sscottl  {
3008150849Sscottl  struct desc_ring *ring = &sc->rxring;
3009150849Sscottl  struct dma_desc *desc;
3010150849Sscottl  struct mbuf *m;
3011150849Sscottl  int desc_len;
3012150849Sscottl  int error;
3013150849Sscottl
3014150849Sscottl  /* Ring is full if (wrap(write+1)==read) */
3015150849Sscottl  if (((ring->write == ring->last) ? ring->first : ring->write+1) == ring->read)
3016150849Sscottl    return 0;  /* ring is full; nothing to do */
3017150849Sscottl
3018150849Sscottl  /* Allocate a small mbuf and attach an mbuf cluster. */
3019243857Sglebius  MGETHDR(m, M_NOWAIT, MT_DATA);
3020150849Sscottl  if (m == NULL)
3021150849Sscottl    {
3022150849Sscottl    sc->status.cntrs.rxdma++;
3023150849Sscottl    if (DRIVER_DEBUG)
3024150849Sscottl      printf("%s: rxintr_setup: MGETHDR() failed\n", NAME_UNIT);
3025150849Sscottl    return 0;
3026150849Sscottl    }
3027243857Sglebius  MCLGET(m, M_NOWAIT);
3028150849Sscottl  if ((m->m_flags & M_EXT) == 0)
3029150849Sscottl    {
3030150849Sscottl    m_freem(m);
3031150849Sscottl    sc->status.cntrs.rxdma++;
3032150849Sscottl    if (DRIVER_DEBUG)
3033150849Sscottl      printf("%s: rxintr_setup: MCLGET() failed\n", NAME_UNIT);
3034150849Sscottl    return 0;
3035150849Sscottl    }
3036150849Sscottl
3037150849Sscottl  /* Queue the mbuf for later processing by rxintr_cleanup. */
3038150849Sscottl  mbuf_enqueue(ring, m);
3039150849Sscottl
3040150849Sscottl  /* Write a DMA descriptor into the ring. */
3041150849Sscottl  /* Hardware won't see it until the OWNER bit is set. */
3042150849Sscottl  desc = ring->write;
3043150849Sscottl  /* Advance the ring write pointer. */
3044150849Sscottl  if (ring->write++ == ring->last) ring->write = ring->first;
3045150849Sscottl
3046150849Sscottl  desc_len = (MCLBYTES < MAX_DESC_LEN) ? MCLBYTES : MAX_DESC_LEN;
3047150849Sscottl  /* Map kernel virtual address to PCI address. */
3048150849Sscottl  if ((error = DMA_LOAD(desc->map, m->m_data, desc_len)))
3049150849Sscottl    printf("%s: bus_dmamap_load(rx) failed; error %d\n", NAME_UNIT, error);
3050150849Sscottl  /* Invalidate the cache for this mbuf. */
3051150849Sscottl  DMA_SYNC(desc->map, desc_len, BUS_DMASYNC_PREREAD);
3052150849Sscottl
3053150849Sscottl  /* Set up the DMA descriptor. */
3054153084Sru#ifdef __FreeBSD__
3055150849Sscottl  desc->address1 = ring->segs[0].ds_addr;
3056153084Sru#elif (defined(__NetBSD__) || defined(__OpenBSD__))
3057150849Sscottl  desc->address1 = desc->map->dm_segs[0].ds_addr;
3058153084Sru#elif defined(__bsdi__)
3059150849Sscottl  desc->address1 = vtophys(m->m_data); /* Relax! BSD/OS only. */
3060150849Sscottl#endif
3061150849Sscottl  desc->length1  = desc_len>>1;
3062150849Sscottl  desc->address2 = desc->address1 + desc->length1;
3063150849Sscottl  desc->length2  = desc_len>>1;
3064150849Sscottl
3065150849Sscottl  /* Before setting the OWNER bit, flush the cache (memory barrier). */
3066150849Sscottl  DMA_SYNC(ring->map, ring->size_descs, BUS_DMASYNC_PREWRITE);
3067150849Sscottl
3068150849Sscottl  /* Commit the DMA descriptor to the hardware. */
3069150849Sscottl  desc->status = TLP_DSTS_OWNER;
3070150849Sscottl
3071150849Sscottl  /* Notify the receiver that there is another buffer available. */
3072150849Sscottl  WRITE_CSR(TLP_RX_POLL, 1);
3073150849Sscottl
3074150849Sscottl  return 1; /* did something */
3075150849Sscottl  }
3076150849Sscottl
3077150849Sscottl/* Clean up after a packet has been transmitted. */
3078150849Sscottl/* Free the mbuf chain and update the DMA descriptor ring. */
3079150849Sscottlstatic int  /* BSD version */
3080150849Sscottltxintr_cleanup(softc_t *sc)
3081150849Sscottl  {
3082150849Sscottl  struct desc_ring *ring = &sc->txring;
3083150849Sscottl  struct dma_desc *desc;
3084150849Sscottl
3085150849Sscottl  while ((ring->read != ring->write) && /* while ring is not empty */
3086150849Sscottl        ((ring->read->status & TLP_DSTS_OWNER) == 0))
3087150849Sscottl    {
3088150849Sscottl    /* Read a DMA descriptor from the ring. */
3089150849Sscottl    desc = ring->read;
3090150849Sscottl    /* Advance the ring read pointer. */
3091150849Sscottl    if (ring->read++ == ring->last) ring->read = ring->first;
3092150849Sscottl
3093150849Sscottl    /* This is a no-op on most architectures. */
3094150849Sscottl    DMA_SYNC(desc->map, desc->length1 + desc->length2, BUS_DMASYNC_POSTWRITE);
3095150849Sscottl    /* Unmap kernel virtual address to PCI address. */
3096150849Sscottl    bus_dmamap_unload(ring->tag, desc->map);
3097150849Sscottl
3098150849Sscottl    /* If this descriptor is the last segment of a packet, */
3099150849Sscottl    /*  then dequeue and free the corresponding mbuf chain. */
3100150849Sscottl    if ((desc->control & TLP_DCTL_TX_LAST_SEG) != 0)
3101150849Sscottl      {
3102150849Sscottl      struct mbuf *m;
3103150849Sscottl      if ((m = mbuf_dequeue(ring)) == NULL)
3104150849Sscottl        panic("%s: txintr_cleanup: expected an mbuf\n", NAME_UNIT);
3105150849Sscottl
3106150849Sscottl      /* Include CRC and one flag byte in output byte count. */
3107150849Sscottl      sc->status.cntrs.obytes += m->m_pkthdr.len + sc->config.crc_len +1;
3108150849Sscottl      sc->status.cntrs.opackets++;
3109150849Sscottl#if IFNET
3110150849Sscottl      sc->ifp->if_opackets++;
3111150849Sscottl      LMC_BPF_MTAP(m);
3112150849Sscottl#endif
3113150849Sscottl      /* The only bad TX status is fifo underrun. */
3114150849Sscottl      if ((desc->status & TLP_DSTS_TX_UNDERRUN) != 0)
3115150849Sscottl        sc->status.cntrs.fifo_under++;
3116150849Sscottl
3117150849Sscottl      m_freem(m);
3118150849Sscottl      return 1;  /* did something */
3119150849Sscottl      }
3120150849Sscottl    }
3121150849Sscottl
3122150849Sscottl  return 0;
3123150849Sscottl  }
3124150849Sscottl
3125150849Sscottl/* Build DMA descriptors for a transmit packet mbuf chain. */
3126150849Sscottlstatic int /* 0=success; 1=error */ /* BSD version */
3127150849Sscottltxintr_setup_mbuf(softc_t *sc, struct mbuf *m)
3128150849Sscottl  {
3129150849Sscottl  struct desc_ring *ring = &sc->txring;
3130150849Sscottl  struct dma_desc *desc;
3131150849Sscottl  unsigned int desc_len;
3132150849Sscottl
3133150849Sscottl  /* build DMA descriptors for a chain of mbufs. */
3134150849Sscottl  while (m != NULL)
3135150849Sscottl    {
3136150849Sscottl    char *data = m->m_data;
3137150849Sscottl    int length = m->m_len; /* zero length mbufs happen! */
3138150849Sscottl
3139150849Sscottl    /* Build DMA descriptors for one mbuf. */
3140150849Sscottl    while (length > 0)
3141150849Sscottl      {
3142150849Sscottl      int error;
3143150849Sscottl
3144150849Sscottl      /* Ring is full if (wrap(write+1)==read) */
3145150849Sscottl      if (((ring->temp==ring->last) ? ring->first : ring->temp+1) == ring->read)
3146150849Sscottl        { /* Not enough DMA descriptors; try later. */
3147150849Sscottl        for (; ring->temp!=ring->write;
3148150849Sscottl         ring->temp = (ring->temp==ring->first)? ring->last : ring->temp-1)
3149150849Sscottl          bus_dmamap_unload(ring->tag, ring->temp->map);
3150150849Sscottl        sc->status.cntrs.txdma++;
3151150849Sscottl        return 1;
3152150849Sscottl	}
3153150849Sscottl
3154150849Sscottl      /* Provisionally, write a descriptor into the ring. */
3155150849Sscottl      /* But don't change the REAL ring write pointer. */
3156150849Sscottl      /* Hardware won't see it until the OWNER bit is set. */
3157150849Sscottl      desc = ring->temp;
3158150849Sscottl      /* Advance the temporary ring write pointer. */
3159150849Sscottl      if (ring->temp++ == ring->last) ring->temp = ring->first;
3160150849Sscottl
3161150849Sscottl      /* Clear all control bits except the END_RING bit. */
3162150849Sscottl      desc->control &= TLP_DCTL_END_RING;
3163150849Sscottl      /* Don't pad short packets up to 64 bytes. */
3164150849Sscottl      desc->control |= TLP_DCTL_TX_NO_PAD;
3165150849Sscottl      /* Use Tulip's CRC-32 generator, if appropriate. */
3166150849Sscottl      if (sc->config.crc_len != CFG_CRC_32)
3167150849Sscottl        desc->control |= TLP_DCTL_TX_NO_CRC;
3168150849Sscottl      /* Set the OWNER bit, except in the first descriptor. */
3169150849Sscottl      if (desc != ring->write)
3170150849Sscottl        desc->status = TLP_DSTS_OWNER;
3171150849Sscottl
3172150849Sscottl      desc_len = (length > MAX_CHUNK_LEN) ? MAX_CHUNK_LEN : length;
3173150849Sscottl      /* Map kernel virtual address to PCI address. */
3174150849Sscottl      if ((error = DMA_LOAD(desc->map, data, desc_len)))
3175150849Sscottl        printf("%s: bus_dmamap_load(tx) failed; error %d\n", NAME_UNIT, error);
3176150849Sscottl      /* Flush the cache and if bouncing, copy mbuf to bounce buf. */
3177150849Sscottl      DMA_SYNC(desc->map, desc_len, BUS_DMASYNC_PREWRITE);
3178150849Sscottl
3179150849Sscottl      /* Prevent wild fetches if mapping fails (nsegs==0). */
3180150849Sscottl      desc->length1  = desc->length2  = 0;
3181150849Sscottl      desc->address1 = desc->address2 = 0;
3182153084Sru#if (defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__))
3183150849Sscottl        {
3184153084Sru# ifdef __FreeBSD__
3185150849Sscottl        bus_dma_segment_t *segs = ring->segs;
3186150849Sscottl        int nsegs = ring->nsegs;
3187153084Sru# elif (defined(__NetBSD__) || defined(__OpenBSD__))
3188150849Sscottl        bus_dma_segment_t *segs = desc->map->dm_segs;
3189150849Sscottl        int nsegs = desc->map->dm_nsegs;
3190150849Sscottl# endif
3191150849Sscottl        if (nsegs >= 1)
3192150849Sscottl          {
3193150849Sscottl          desc->address1 = segs[0].ds_addr;
3194150849Sscottl          desc->length1  = segs[0].ds_len;
3195150849Sscottl          }
3196150849Sscottl        if (nsegs == 2)
3197150849Sscottl          {
3198150849Sscottl          desc->address2 = segs[1].ds_addr;
3199150849Sscottl          desc->length2  = segs[1].ds_len;
3200150849Sscottl          }
3201150849Sscottl        }
3202153084Sru#elif defined(__bsdi__)
3203150849Sscottl      desc->address1 = vtophys(data); /* Relax! BSD/OS only. */
3204150849Sscottl      desc->length1  = desc_len;
3205150849Sscottl#endif
3206150849Sscottl
3207150849Sscottl      data   += desc_len;
3208150849Sscottl      length -= desc_len;
3209150849Sscottl      } /* while (length > 0) */
3210150849Sscottl
3211150849Sscottl    m = m->m_next;
3212150849Sscottl    } /* while (m != NULL) */
3213150849Sscottl
3214150849Sscottl  return 0; /* success */
3215150849Sscottl  }
3216150849Sscottl
3217150849Sscottl/* Setup (prepare) to transmit a packet. */
3218150849Sscottl/* Select a packet, build DMA descriptors and give packet to hardware. */
3219150849Sscottl/* If DMA descriptors run out, abandon the attempt and return 0. */
3220150849Sscottlstatic int  /* BSD version */
3221150849Sscottltxintr_setup(softc_t *sc)
3222150849Sscottl  {
3223150849Sscottl  struct desc_ring *ring = &sc->txring;
3224150849Sscottl  struct dma_desc *first_desc, *last_desc;
3225150849Sscottl
3226150849Sscottl  /* Protect against half-up links: Don't transmit */
3227150849Sscottl  /*  if the receiver can't hear the far end. */
3228150849Sscottl  if (sc->status.oper_status != STATUS_UP) return 0;
3229150849Sscottl
3230150849Sscottl  /* Pick a packet to transmit. */
3231150849Sscottl#if NETGRAPH
3232150849Sscottl  if ((sc->ng_hook != NULL) && (sc->tx_mbuf == NULL))
3233150849Sscottl    {
3234150849Sscottl    if (!IFQ_IS_EMPTY(&sc->ng_fastq))
3235150849Sscottl      IFQ_DEQUEUE(&sc->ng_fastq, sc->tx_mbuf);
3236150849Sscottl    else
3237150849Sscottl      IFQ_DEQUEUE(&sc->ng_sndq,  sc->tx_mbuf);
3238150849Sscottl    }
3239150849Sscottl  else
3240150849Sscottl#endif
3241150849Sscottl  if (sc->tx_mbuf == NULL)
3242150849Sscottl    {
3243150849Sscottl    if (sc->config.line_pkg == PKG_RAWIP)
3244150849Sscottl      IFQ_DEQUEUE(&sc->ifp->if_snd, sc->tx_mbuf);
3245150849Sscottl    else
3246150849Sscottl      {
3247150849Sscottl#if NSPPP
3248150849Sscottl      sc->tx_mbuf = sppp_dequeue(sc->ifp);
3249150849Sscottl#elif P2P
3250150849Sscottl      if (!IFQ_IS_EMPTY(&sc->p2p->p2p_isnd))
3251150849Sscottl        IFQ_DEQUEUE(&sc->p2p->p2p_isnd, sc->tx_mbuf);
3252150849Sscottl      else
3253150849Sscottl        IFQ_DEQUEUE(&sc->ifp->if_snd, sc->tx_mbuf);
3254150849Sscottl#endif
3255150849Sscottl      }
3256150849Sscottl    }
3257150849Sscottl  if (sc->tx_mbuf == NULL) return 0;  /* no pkt to transmit */
3258150849Sscottl
3259150849Sscottl  /* Build DMA descriptors for an outgoing mbuf chain. */
3260150849Sscottl  ring->temp = ring->write; /* temporary ring write pointer */
3261150849Sscottl  if (txintr_setup_mbuf(sc, sc->tx_mbuf) != 0) return 0;
3262150849Sscottl
3263150849Sscottl  /* Enqueue the mbuf; txintr_cleanup will free it. */
3264150849Sscottl  mbuf_enqueue(ring, sc->tx_mbuf);
3265150849Sscottl
3266150849Sscottl  /* The transmitter has room for another packet. */
3267150849Sscottl  sc->tx_mbuf = NULL;
3268150849Sscottl
3269150849Sscottl  /* Set first & last segment bits. */
3270150849Sscottl  /* last_desc is the desc BEFORE the one pointed to by ring->temp. */
3271150849Sscottl  first_desc = ring->write;
3272150849Sscottl  first_desc->control |= TLP_DCTL_TX_FIRST_SEG;
3273150849Sscottl  last_desc = (ring->temp==ring->first)? ring->last : ring->temp-1;
3274150849Sscottl   last_desc->control |= TLP_DCTL_TX_LAST_SEG;
3275150849Sscottl  /* Interrupt at end-of-transmission?  Why bother the poor computer! */
3276150849Sscottl/* last_desc->control |= TLP_DCTL_TX_INTERRUPT; */
3277150849Sscottl
3278150849Sscottl  /* Make sure the OWNER bit is not set in the next descriptor. */
3279150849Sscottl  /* The OWNER bit may have been set if a previous call aborted. */
3280150849Sscottl  ring->temp->status = 0;
3281150849Sscottl
3282150849Sscottl  /* Commit the DMA descriptors to the software. */
3283150849Sscottl  ring->write = ring->temp;
3284150849Sscottl
3285150849Sscottl  /* Before setting the OWNER bit, flush the cache (memory barrier). */
3286150849Sscottl  DMA_SYNC(ring->map, ring->size_descs, BUS_DMASYNC_PREWRITE);
3287150849Sscottl
3288150849Sscottl  /* Commit the DMA descriptors to the hardware. */
3289150849Sscottl  first_desc->status = TLP_DSTS_OWNER;
3290150849Sscottl
3291150849Sscottl  /* Notify the transmitter that there is another packet to send. */
3292150849Sscottl  WRITE_CSR(TLP_TX_POLL, 1);
3293150849Sscottl
3294150849Sscottl  return 1; /* did something */
3295150849Sscottl  }
3296150849Sscottl
3297150849Sscottl#endif /* BSD */
3298150849Sscottl
3299153084Sru#ifdef __linux__
3300150849Sscottl/* NOTE: this is the LINUX version of the interrupt/DMA code, */
3301150849Sscottl
3302150849Sscottl/* Singly-linked tail-queues hold sk_buffs with active DMA.
3303150849Sscottl * skbuffs are linked through their sk_buff.next field.
3304150849Sscottl * Callers must hold sc->bottom_lock; not otherwise locked.
3305150849Sscottl */
3306150849Sscottl
3307150849Sscottl/* Put an skbuff on the tail of the descriptor ring queue. */
3308150849Sscottlstatic void  /* Linux version */
3309150849Sscottlskbuff_enqueue(struct desc_ring *ring, struct sk_buff *skb)
3310150849Sscottl  {
3311150849Sscottl  skb->next = NULL;
3312150849Sscottl  if (ring->tail == NULL)
3313150849Sscottl    ring->head = skb;
3314150849Sscottl  else
3315150849Sscottl    ring->tail->next = skb;
3316150849Sscottl  ring->tail = skb;
3317150849Sscottl  }
3318150849Sscottl
3319150849Sscottl/* Get an skbuff from the head of the descriptor ring queue. */
3320150849Sscottlstatic struct sk_buff*  /* Linux version */
3321150849Sscottlskbuff_dequeue(struct desc_ring *ring)
3322150849Sscottl  {
3323150849Sscottl  struct sk_buff *skb = ring->head;
3324150849Sscottl  if (skb != NULL)
3325150849Sscottl    if ((ring->head = skb->next) == NULL)
3326150849Sscottl      ring->tail = NULL;
3327150849Sscottl  return skb;
3328150849Sscottl  }
3329150849Sscottl
3330150849Sscottl/* Initialize a DMA descriptor ring. */
3331150849Sscottlstatic int  /* Linux version */
3332150849Sscottlcreate_ring(softc_t *sc, struct desc_ring *ring, int num_descs)
3333150849Sscottl  {
3334150849Sscottl  struct dma_desc *descs;
3335150849Sscottl  int size_descs = sizeof(struct dma_desc)*num_descs;
3336150849Sscottl
3337150849Sscottl  /* Allocate and map memory for DMA descriptor array. */
3338150849Sscottl  if ((descs = pci_alloc_consistent(sc->pci_dev, size_descs,
3339150849Sscottl   &ring->dma_addr)) == NULL)
3340150849Sscottl    {
3341150849Sscottl    printk("%s: pci_alloc_consistent() failed\n", NAME_UNIT);
3342150849Sscottl    return ENOMEM;
3343150849Sscottl    }
3344150849Sscottl  memset(descs, 0, size_descs);
3345150849Sscottl
3346150849Sscottl  ring->read  = descs;
3347150849Sscottl  ring->write = descs;
3348150849Sscottl  ring->first = descs;
3349150849Sscottl  ring->last  = descs + num_descs -1;
3350150849Sscottl  ring->last->control = TLP_DCTL_END_RING;
3351150849Sscottl  ring->num_descs = num_descs;
3352150849Sscottl  ring->size_descs = size_descs;
3353150849Sscottl  ring->head = NULL;
3354150849Sscottl  ring->tail = NULL;
3355150849Sscottl
3356150849Sscottl  return 0;
3357150849Sscottl  }
3358150849Sscottl
3359150849Sscottl/* Destroy a DMA descriptor ring */
3360150849Sscottlstatic void  /* Linux version */
3361150849Sscottldestroy_ring(softc_t *sc, struct desc_ring *ring)
3362150849Sscottl  {
3363150849Sscottl  struct sk_buff *skb;
3364150849Sscottl
3365150849Sscottl  /* Free queued skbuffs. */
3366150849Sscottl  while ((skb = skbuff_dequeue(ring)) != NULL)
3367150849Sscottl    dev_kfree_skb(skb);
3368150849Sscottl
3369150849Sscottl  /* TX may have one pkt that is not on any queue. */
3370150849Sscottl  if (sc->tx_skb != NULL)
3371150849Sscottl    {
3372150849Sscottl    dev_kfree_skb(sc->tx_skb);
3373150849Sscottl    sc->tx_skb = NULL;
3374150849Sscottl    }
3375150849Sscottl
3376150849Sscottl  if (ring->first != NULL)
3377150849Sscottl    {
3378150849Sscottl    /* Unmap active DMA descriptors. */
3379150849Sscottl    while (ring->read != ring->write)
3380150849Sscottl      {
3381150849Sscottl      pci_unmap_single(sc->pci_dev, ring->read->address1,
3382150849Sscottl       ring->read->length1 + ring->read->length2, PCI_DMA_BIDIRECTIONAL);
3383150849Sscottl      if (ring->read++ == ring->last) ring->read = ring->first;
3384150849Sscottl      }
3385150849Sscottl
3386150849Sscottl    /* Unmap and free memory for DMA descriptor array. */
3387150849Sscottl    pci_free_consistent(sc->pci_dev, ring->size_descs, ring->first,
3388150849Sscottl     ring->dma_addr);
3389150849Sscottl    }
3390150849Sscottl  }
3391150849Sscottl
3392150849Sscottlstatic int  /* Linux version */
3393150849Sscottlrxintr_cleanup(softc_t *sc)
3394150849Sscottl  {
3395150849Sscottl  struct desc_ring *ring = &sc->rxring;
3396150849Sscottl  struct dma_desc *first_desc, *last_desc;
3397150849Sscottl  struct sk_buff *first_skb=NULL, *last_skb=NULL;
3398150849Sscottl  struct sk_buff *new_skb;
3399150849Sscottl  int pkt_len, desc_len;
3400150849Sscottl
3401150849Sscottl  /* Input packet flow control (livelock prevention): */
3402150849Sscottl  /* Give pkts to higher levels only if quota is > 0. */
3403150849Sscottl  if (sc->quota <= 0) return 0;
3404150849Sscottl
3405150849Sscottl  /* This looks complicated, but remember: packets up to 4032 */
3406150849Sscottl  /*  bytes long fit in one skbuff and use one DMA descriptor. */
3407150849Sscottl
3408150849Sscottl  first_desc = last_desc = ring->read;
3409150849Sscottl
3410150849Sscottl  /* ASSERTION: If there is a descriptor in the ring and the hardware has */
3411150849Sscottl  /*  finished with it, then that descriptor will have RX_FIRST_DESC set. */
3412150849Sscottl  if ((ring->read != ring->write) && /* descriptor ring not empty */
3413150849Sscottl     ((ring->read->status & TLP_DSTS_OWNER) == 0) && /* hardware done */
3414150849Sscottl     ((ring->read->status & TLP_DSTS_RX_FIRST_DESC) == 0)) /* should be set */
3415150849Sscottl    panic("%s: rxintr_cleanup: rx-first-descriptor not set.\n", NAME_UNIT);
3416150849Sscottl
3417150849Sscottl  /* First decide if a complete packet has arrived. */
3418150849Sscottl  /* Run down DMA descriptors looking for one marked "last". */
3419150849Sscottl  /* Bail out if an active descriptor is encountered. */
3420150849Sscottl  /* Accumulate most significant bits of packet length. */
3421150849Sscottl  pkt_len = 0;
3422150849Sscottl  for (;;)
3423150849Sscottl    {
3424150849Sscottl    if (last_desc == ring->write) return 0;  /* no more descs */
3425150849Sscottl    if (last_desc->status & TLP_DSTS_OWNER) return 0; /* still active */
3426150849Sscottl    if (last_desc->status & TLP_DSTS_RX_LAST_DESC) break; /* end of packet */
3427150849Sscottl    pkt_len += last_desc->length1 + last_desc->length2; /* entire desc filled */
3428150849Sscottl    if (last_desc++->control & TLP_DCTL_END_RING) last_desc = ring->first; /* ring wrap */
3429150849Sscottl    }
3430150849Sscottl
3431150849Sscottl  /* A complete packet has arrived; how long is it? */
3432150849Sscottl  /* H/w ref man shows RX pkt length as a 14-bit field. */
3433150849Sscottl  /* An experiment found that only the 12 LSBs work. */
3434150849Sscottl  if (((last_desc->status>>16)&0xFFF) == 0) pkt_len += 4096; /* carry-bit */
3435150849Sscottl  pkt_len = (pkt_len & 0xF000) + ((last_desc->status>>16) & 0x0FFF);
3436150849Sscottl  /* Subtract the CRC length unless doing so would underflow. */
3437150849Sscottl  if (pkt_len >= sc->config.crc_len) pkt_len -= sc->config.crc_len;
3438150849Sscottl
3439150849Sscottl  /* Run down DMA descriptors again doing the following:
3440150849Sscottl   *  1) put pkt info in hdr of first skbuff.
3441150849Sscottl   *  2) put additional skbuffs on frag_list.
3442150849Sscottl   *  3) set skbuff lengths.
3443150849Sscottl   */
3444150849Sscottl  first_desc = ring->read;
3445150849Sscottl  do
3446150849Sscottl    {
3447150849Sscottl    /* Read a DMA descriptor from the ring. */
3448150849Sscottl    last_desc = ring->read;
3449150849Sscottl    /* Advance the ring read pointer. */
3450150849Sscottl    if (ring->read++ == ring->last) ring->read = ring->first;
3451150849Sscottl
3452150849Sscottl    /* Dequeue the corresponding skbuff. */
3453150849Sscottl    new_skb = skbuff_dequeue(ring);
3454150849Sscottl    if (new_skb == NULL)
3455150849Sscottl      panic("%s: rxintr_cleanup: expected an skbuff\n", NAME_UNIT);
3456150849Sscottl
3457150849Sscottl    desc_len = last_desc->length1 + last_desc->length2;
3458150849Sscottl    /* Unmap kernel virtual addresss to PCI address. */
3459150849Sscottl    pci_unmap_single(sc->pci_dev, last_desc->address1,
3460150849Sscottl     desc_len, PCI_DMA_FROMDEVICE);
3461150849Sscottl
3462150849Sscottl    /* Set skbuff length. */
3463150849Sscottl    skb_put(new_skb, (pkt_len >= desc_len) ? desc_len : pkt_len);
3464150849Sscottl    pkt_len -= new_skb->len;
3465150849Sscottl
3466150849Sscottl    /* 1) Put pkt info in hdr of first skbuff. */
3467150849Sscottl    if (last_desc == first_desc)
3468150849Sscottl      {
3469150849Sscottl      first_skb = new_skb;
3470150849Sscottl      if (sc->config.line_pkg == PKG_RAWIP)
3471150849Sscottl        {
3472150849Sscottl        if      (first_skb->data[0]>>4 == 4)
3473150849Sscottl          first_skb->protocol = htons(ETH_P_IP);
3474150849Sscottl        else if (first_skb->data[0]>>4 == 6)
3475150849Sscottl          first_skb->protocol = htons(ETH_P_IPV6);
3476150849Sscottl	}
3477150849Sscottl      else
3478150849Sscottl#if GEN_HDLC
3479150849Sscottl        first_skb->protocol = hdlc_type_trans(first_skb, sc->net_dev);
3480150849Sscottl#else
3481150849Sscottl        first_skb->protocol = htons(ETH_P_HDLC);
3482150849Sscottl#endif
3483150849Sscottl      first_skb->mac.raw = first_skb->data;
3484150849Sscottl      first_skb->dev = sc->net_dev;
3485150849Sscottl      do_gettimeofday(&first_skb->stamp);
3486150849Sscottl      sc->net_dev->last_rx = jiffies;
3487150849Sscottl      }
3488150849Sscottl    else /* 2) link skbuffs. */
3489150849Sscottl      {
3490150849Sscottl      /* Put this skbuff on the frag_list of the first skbuff. */
3491150849Sscottl      new_skb->next = NULL;
3492150849Sscottl      if (skb_shinfo(first_skb)->frag_list == NULL)
3493150849Sscottl        skb_shinfo(first_skb)->frag_list = new_skb;
3494150849Sscottl      else
3495150849Sscottl        last_skb->next = new_skb;
3496150849Sscottl      /* 3) set skbuff lengths. */
3497150849Sscottl      first_skb->len      += new_skb->len;
3498150849Sscottl      first_skb->data_len += new_skb->len;
3499150849Sscottl      }
3500150849Sscottl    last_skb = new_skb;
3501150849Sscottl    } while ((last_desc->status & TLP_DSTS_RX_LAST_DESC) == 0);
3502150849Sscottl
3503150849Sscottl  /* Decide whether to accept or to discard this packet. */
3504150849Sscottl  /* RxHDLC sets MIIERR for bad CRC, abort and partial byte at pkt end. */
3505150849Sscottl  if (((last_desc->status & TLP_DSTS_RX_BAD) == 0) &&
3506150849Sscottl   (sc->status.oper_status == STATUS_UP) &&
3507150849Sscottl   (first_skb->len > 0))
3508150849Sscottl    {
3509150849Sscottl    /* Optimization: copy a small pkt into a small skbuff. */
3510150849Sscottl    if (first_skb->len <= COPY_BREAK)
3511150849Sscottl      if ((new_skb = skb_copy(first_skb, GFP_ATOMIC)) != NULL)
3512150849Sscottl        {
3513150849Sscottl        dev_kfree_skb_any(first_skb);
3514150849Sscottl        first_skb = new_skb;
3515150849Sscottl	}
3516150849Sscottl
3517150849Sscottl    /* Include CRC and one flag byte in input byte count. */
3518150849Sscottl    sc->status.cntrs.ibytes += first_skb->len + sc->config.crc_len +1;
3519150849Sscottl    sc->status.cntrs.ipackets++;
3520150849Sscottl
3521150849Sscottl    /* Give this good packet to the network stacks. */
3522150849Sscottl    netif_receive_skb(first_skb);  /* NAPI */
3523150849Sscottl    sc->quota--;
3524150849Sscottl    }
3525150849Sscottl  else if (sc->status.oper_status != STATUS_UP)
3526150849Sscottl    {
3527150849Sscottl    /* If the link is down, this packet is probably noise. */
3528150849Sscottl    sc->status.cntrs.idiscards++;
3529150849Sscottl    dev_kfree_skb_any(first_skb);
3530150849Sscottl    if (DRIVER_DEBUG)
3531150849Sscottl      printk("%s: rxintr_cleanup: rx pkt discarded: link down\n", NAME_UNIT);
3532150849Sscottl    }
3533150849Sscottl  else /* Log and discard this bad packet. */
3534150849Sscottl    {
3535150849Sscottl    if (DRIVER_DEBUG)
3536150849Sscottl      printk("%s: RX bad pkt; len=%d %s%s%s%s\n",
3537150849Sscottl       NAME_UNIT, first_skb->len,
3538150849Sscottl       (last_desc->status & TLP_DSTS_RX_MII_ERR)  ? " miierr"  : "",
3539150849Sscottl       (last_desc->status & TLP_DSTS_RX_DRIBBLE)  ? " dribble" : "",
3540150849Sscottl       (last_desc->status & TLP_DSTS_RX_DESC_ERR) ? " descerr" : "",
3541150849Sscottl       (last_desc->status & TLP_DSTS_RX_OVERRUN)  ? " overrun" : "");
3542150849Sscottl    if (last_desc->status & TLP_DSTS_RX_OVERRUN)
3543150849Sscottl      sc->status.cntrs.fifo_over++;
3544150849Sscottl    else
3545150849Sscottl      sc->status.cntrs.ierrors++;
3546150849Sscottl    dev_kfree_skb_any(first_skb);
3547150849Sscottl    }
3548150849Sscottl
3549150849Sscottl  return 1; /* did something */
3550150849Sscottl  }
3551150849Sscottl
3552150849Sscottl/* Setup (prepare) to receive a packet. */
3553150849Sscottl/* Try to keep the RX descriptor ring full of empty buffers. */
3554150849Sscottlstatic int  /* Linux version */
3555150849Sscottlrxintr_setup(softc_t *sc)
3556150849Sscottl  {
3557150849Sscottl  struct desc_ring *ring = &sc->rxring;
3558150849Sscottl  struct dma_desc *desc;
3559150849Sscottl  struct sk_buff *skb;
3560150849Sscottl  u_int32_t dma_addr;
3561150849Sscottl
3562150849Sscottl  /* Ring is full if (wrap(write+1)==read) */
3563150849Sscottl  if (((ring->write == ring->last) ? ring->first : ring->write+1) == ring->read)
3564150849Sscottl    return 0;  /* ring is full; nothing to do */
3565150849Sscottl
3566150849Sscottl  /* Allocate an skbuff. */
3567150849Sscottl  if ((skb = dev_alloc_skb(MAX_DESC_LEN)) == NULL)
3568150849Sscottl    {
3569150849Sscottl    sc->status.cntrs.rxdma++;
3570150849Sscottl    if (DRIVER_DEBUG)
3571150849Sscottl      printk("%s: rxintr_setup: dev_alloc_skb() failed\n", NAME_UNIT);
3572150849Sscottl    return 0;
3573150849Sscottl    }
3574150849Sscottl  skb->dev = sc->net_dev;
3575150849Sscottl
3576150849Sscottl  /* Queue the skbuff for later processing by rxintr_cleanup. */
3577150849Sscottl  skbuff_enqueue(ring, skb);
3578150849Sscottl
3579150849Sscottl  /* Write a DMA descriptor into the ring. */
3580150849Sscottl  /* Hardware won't see it until the OWNER bit is set. */
3581150849Sscottl  desc = ring->write;
3582150849Sscottl  /* Advance the ring write pointer. */
3583150849Sscottl  if (ring->write++ == ring->last) ring->write = ring->first;
3584150849Sscottl
3585150849Sscottl  /* Map kernel virtual addresses to PCI addresses. */
3586150849Sscottl  dma_addr = pci_map_single(sc->pci_dev, skb->data,
3587150849Sscottl   MAX_DESC_LEN, PCI_DMA_FROMDEVICE);
3588150849Sscottl  /* Set up the DMA descriptor. */
3589150849Sscottl  desc->address1 = dma_addr;
3590150849Sscottl  desc->length1  = MAX_CHUNK_LEN;
3591150849Sscottl  desc->address2 = desc->address1 + desc->length1;
3592150849Sscottl  desc->length2  = MAX_CHUNK_LEN;
3593150849Sscottl
3594150849Sscottl  /* Before setting the OWNER bit, flush the cache (memory barrier). */
3595150849Sscottl  wmb(); /* write memory barrier */
3596150849Sscottl
3597150849Sscottl  /* Commit the DMA descriptor to the hardware. */
3598150849Sscottl  desc->status = TLP_DSTS_OWNER;
3599150849Sscottl
3600150849Sscottl  /* Notify the receiver that there is another buffer available. */
3601150849Sscottl  WRITE_CSR(TLP_RX_POLL, 1);
3602150849Sscottl
3603150849Sscottl  return 1; /* did something */
3604150849Sscottl  }
3605150849Sscottl
3606150849Sscottl/* Clean up after a packet has been transmitted. */
3607150849Sscottl/* Free the sk_buff and update the DMA descriptor ring. */
3608150849Sscottlstatic int  /* Linux version */
3609150849Sscottltxintr_cleanup(softc_t *sc)
3610150849Sscottl  {
3611150849Sscottl  struct desc_ring *ring = &sc->txring;
3612150849Sscottl  struct dma_desc *desc;
3613150849Sscottl
3614150849Sscottl  while ((ring->read != ring->write) && /* ring is not empty */
3615150849Sscottl        ((ring->read->status & TLP_DSTS_OWNER) == 0))
3616150849Sscottl    {
3617150849Sscottl    /* Read a DMA descriptor from the ring. */
3618150849Sscottl    desc = ring->read;
3619150849Sscottl    /* Advance the ring read pointer. */
3620150849Sscottl    if (ring->read++ == ring->last) ring->read = ring->first;
3621150849Sscottl    /* Unmap kernel virtual address to PCI address. */
3622150849Sscottl    pci_unmap_single(sc->pci_dev, desc->address1,
3623150849Sscottl     desc->length1 + desc->length2, PCI_DMA_TODEVICE);
3624150849Sscottl
3625150849Sscottl    /* If this descriptor is the last segment of a packet, */
3626150849Sscottl    /*  then dequeue and free the corresponding skbuff. */
3627150849Sscottl    if ((desc->control & TLP_DCTL_TX_LAST_SEG) != 0)
3628150849Sscottl      {
3629150849Sscottl      struct sk_buff *skb;
3630150849Sscottl      if ((skb = skbuff_dequeue(ring)) == NULL)
3631150849Sscottl        panic("%s: txintr_cleanup: expected an sk_buff\n", NAME_UNIT);
3632150849Sscottl
3633150849Sscottl      /* Include CRC and one flag byte in output byte count. */
3634150849Sscottl      sc->status.cntrs.obytes += skb->len + sc->config.crc_len +1;
3635150849Sscottl      sc->status.cntrs.opackets++;
3636150849Sscottl
3637150849Sscottl      /* The only bad TX status is fifo underrun. */
3638150849Sscottl      if ((desc->status & TLP_DSTS_TX_UNDERRUN) != 0)
3639150849Sscottl        {
3640150849Sscottl        sc->status.cntrs.fifo_under++; /* also increment oerrors? */
3641150849Sscottl        if (DRIVER_DEBUG)
3642150849Sscottl          printk("%s: txintr_cleanup: tx fifo underrun\n", NAME_UNIT);
3643150849Sscottl	}
3644150849Sscottl
3645150849Sscottl      dev_kfree_skb_any(skb);
3646150849Sscottl      return 1;  /* did something */
3647150849Sscottl      }
3648150849Sscottl    }
3649150849Sscottl
3650150849Sscottl  return 0;
3651150849Sscottl  }
3652150849Sscottl
3653150849Sscottl/* Build DMA descriptors for a tranmit packet fragment, */
3654150849Sscottl/* Assertion: fragment is contiguous in physical memory. */
3655150849Sscottlstatic int /* 0=success; 1=error */ /* linux version */
3656150849Sscottltxintr_setup_frag(softc_t *sc, char *data, int length)
3657150849Sscottl  {
3658150849Sscottl  struct desc_ring *ring = &sc->txring;
3659150849Sscottl  struct dma_desc *desc;
3660150849Sscottl  unsigned int desc_len;
3661150849Sscottl  u_int32_t dma_addr;
3662150849Sscottl
3663150849Sscottl  while (length > 0)
3664150849Sscottl    {
3665150849Sscottl    /* Ring is full if (wrap(write+1)==read) */
3666150849Sscottl    if (((ring->temp==ring->last) ? ring->first : ring->temp+1) == ring->read)
3667150849Sscottl      { /* Not enough DMA descriptors; try later. */
3668150849Sscottl      for (; ring->temp!=ring->write;
3669150849Sscottl       ring->temp = (ring->temp==ring->first)? ring->last : ring->temp-1)
3670150849Sscottl        pci_unmap_single(sc->pci_dev, ring->temp->address1,
3671150849Sscottl         ring->temp->length1 + ring->temp->length2, PCI_DMA_FROMDEVICE);
3672150849Sscottl      sc->status.cntrs.txdma++;
3673150849Sscottl      return 1;
3674150849Sscottl      }
3675150849Sscottl
3676150849Sscottl    /* Provisionally, write a DMA descriptor into the ring. */
3677150849Sscottl    /* But don't change the REAL ring write pointer. */
3678150849Sscottl    /* Hardware won't see it until the OWNER bit is set. */
3679150849Sscottl    desc = ring->temp;
3680150849Sscottl    /* Advance the temporary ring write pointer. */
3681150849Sscottl    if (ring->temp++ == ring->last) ring->temp = ring->first;
3682150849Sscottl
3683150849Sscottl    /* Clear all control bits except the END_RING bit. */
3684150849Sscottl    desc->control &= TLP_DCTL_END_RING;
3685150849Sscottl    /* Don't pad short packets up to 64 bytes */
3686150849Sscottl    desc->control |= TLP_DCTL_TX_NO_PAD;
3687150849Sscottl    /* Use Tulip's CRC-32 generator, if appropriate. */
3688150849Sscottl    if (sc->config.crc_len != CFG_CRC_32)
3689150849Sscottl      desc->control |= TLP_DCTL_TX_NO_CRC;
3690150849Sscottl    /* Set the OWNER bit, except in the first descriptor. */
3691150849Sscottl    if (desc != ring->write)
3692150849Sscottl      desc->status = TLP_DSTS_OWNER;
3693150849Sscottl
3694150849Sscottl    desc_len = (length >= MAX_DESC_LEN) ? MAX_DESC_LEN : length;
3695150849Sscottl    /* Map kernel virtual address to PCI address. */
3696150849Sscottl    dma_addr = pci_map_single(sc->pci_dev, data, desc_len, PCI_DMA_TODEVICE);
3697150849Sscottl    /* If it will fit in one chunk, do so, otherwise split it. */
3698150849Sscottl    if (desc_len <= MAX_CHUNK_LEN)
3699150849Sscottl      {
3700150849Sscottl      desc->address1 = dma_addr;
3701150849Sscottl      desc->length1  = desc_len;
3702150849Sscottl      desc->address2 = 0;
3703150849Sscottl      desc->length2  = 0;
3704150849Sscottl      }
3705150849Sscottl    else
3706150849Sscottl      {
3707150849Sscottl      desc->address1 = dma_addr;
3708150849Sscottl      desc->length1  = desc_len>>1;
3709150849Sscottl      desc->address2 = desc->address1 + desc->length1;
3710150849Sscottl      desc->length2  = desc_len>>1;
3711150849Sscottl      if (desc_len & 1) desc->length2++;
3712150849Sscottl      }
3713150849Sscottl
3714150849Sscottl    data   += desc_len;
3715150849Sscottl    length -= desc_len;
3716150849Sscottl    } /* while (length > 0) */
3717150849Sscottl
3718150849Sscottl  return 0; /* success */
3719150849Sscottl  }
3720150849Sscottl
3721150849Sscottl/* NB: this procedure is recursive! */
3722150849Sscottlstatic int /* 0=success; 1=error */
3723150849Sscottltxintr_setup_skb(softc_t *sc, struct sk_buff *skb)
3724150849Sscottl  {
3725150849Sscottl  struct sk_buff *list;
3726150849Sscottl  int i;
3727150849Sscottl
3728150849Sscottl  /* First, handle the data in the skbuff itself. */
3729150849Sscottl  if (txintr_setup_frag(sc, skb->data, skb_headlen(skb)))
3730150849Sscottl    return 1;
3731150849Sscottl
3732150849Sscottl  /* Next, handle the VM pages in the Scatter/Gather list. */
3733150849Sscottl  if (skb_shinfo(skb)->nr_frags != 0)
3734150849Sscottl    for (i=0; i<skb_shinfo(skb)->nr_frags; i++)
3735150849Sscottl      {
3736150849Sscottl      skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
3737150849Sscottl      if (txintr_setup_frag(sc, page_address(frag->page) +
3738150849Sscottl       frag->page_offset, frag->size))
3739150849Sscottl        return 1;
3740150849Sscottl      }
3741150849Sscottl
3742150849Sscottl  /* Finally, handle the skbuffs in the frag_list. */
3743150849Sscottl  if ((list = skb_shinfo(skb)->frag_list) != NULL)
3744150849Sscottl    for (; list; list=list->next)
3745150849Sscottl      if (txintr_setup_skb(sc, list)) /* recursive! */
3746150849Sscottl        return 1;
3747150849Sscottl
3748150849Sscottl  return 0;
3749150849Sscottl  }
3750150849Sscottl
3751150849Sscottl/* Setup (prepare) to transmit a packet. */
3752150849Sscottl/* Select a packet, build DMA descriptors and give packet to hardware. */
3753150849Sscottl/* If DMA descriptors run out, abandon the attempt and return 0. */
3754150849Sscottlstatic int  /* Linux version */
3755150849Sscottltxintr_setup(softc_t *sc)
3756150849Sscottl  {
3757150849Sscottl  struct desc_ring *ring = &sc->txring;
3758150849Sscottl  struct dma_desc *first_desc, *last_desc;
3759150849Sscottl
3760150849Sscottl  /* Protect against half-up links: Don't transmit */
3761150849Sscottl  /*  if the receiver can't hear the far end. */
3762150849Sscottl  if (sc->status.oper_status != STATUS_UP) return 0;
3763150849Sscottl
3764150849Sscottl  /* Pick a packet to transmit. */
3765150849Sscottl  /* linux_start() puts packets in sc->tx_skb. */
3766150849Sscottl  if (sc->tx_skb == NULL)
3767150849Sscottl    {
3768150849Sscottl    if (netif_queue_stopped(sc->net_dev) != 0)
3769150849Sscottl      netif_wake_queue(sc->net_dev);
3770150849Sscottl    return 0; /* no pkt to transmit */
3771150849Sscottl    }
3772150849Sscottl
3773150849Sscottl  /* Build DMA descriptors for an outgoing skbuff. */
3774150849Sscottl  ring->temp = ring->write; /* temporary ring write pointer */
3775150849Sscottl  if (txintr_setup_skb(sc, sc->tx_skb) != 0) return 0;
3776150849Sscottl
3777150849Sscottl  /* Enqueue the skbuff; txintr_cleanup will free it. */
3778150849Sscottl  skbuff_enqueue(ring, sc->tx_skb);
3779150849Sscottl
3780150849Sscottl  /* The transmitter has room for another packet. */
3781150849Sscottl  sc->tx_skb = NULL;
3782150849Sscottl
3783150849Sscottl  /* Set first & last segment bits. */
3784150849Sscottl  /* last_desc is the desc BEFORE the one pointed to by ring->temp. */
3785150849Sscottl  first_desc = ring->write;
3786150849Sscottl  first_desc->control |= TLP_DCTL_TX_FIRST_SEG;
3787150849Sscottl  last_desc = (ring->temp==ring->first)? ring->last : ring->temp-1;
3788150849Sscottl   last_desc->control |= TLP_DCTL_TX_LAST_SEG;
3789150849Sscottl  /* Interrupt at end-of-transmission?  Why bother the poor computer! */
3790150849Sscottl/* last_desc->control |= TLP_DCTL_TX_INTERRUPT; */
3791150849Sscottl
3792150849Sscottl  /* Make sure the OWNER bit is not set in the next descriptor. */
3793150849Sscottl  /* The OWNER bit may have been set if a previous call aborted. */
3794150849Sscottl  ring->temp->status = 0;
3795150849Sscottl
3796150849Sscottl  /* Commit the DMA descriptors to the software. */
3797150849Sscottl  ring->write = ring->temp;
3798150849Sscottl
3799150849Sscottl  /* Before setting the OWNER bit, flush the cache (memory barrier). */
3800150849Sscottl  wmb(); /* write memory barrier */
3801150849Sscottl
3802150849Sscottl  /* Commit the DMA descriptors to the hardware. */
3803150849Sscottl  first_desc->status = TLP_DSTS_OWNER;
3804150849Sscottl
3805150849Sscottl  /* Notify the transmitter that there is another packet to send. */
3806150849Sscottl  WRITE_CSR(TLP_TX_POLL, 1);
3807150849Sscottl
3808150849Sscottl  sc->net_dev->trans_start = jiffies;
3809150849Sscottl
3810150849Sscottl  return 1; /* did something */
3811150849Sscottl  }
3812150849Sscottl
3813150849Sscottl#endif /* __linux__ */
3814150849Sscottl
3815150849Sscottlstatic void
3816150849Sscottlcheck_intr_status(softc_t *sc)
3817150849Sscottl  {
3818150849Sscottl  u_int32_t status, cfcs, op_mode;
3819150849Sscottl  u_int32_t missed, overruns;
3820150849Sscottl
3821150849Sscottl  /* Check for four unusual events:
3822150849Sscottl   *  1) fatal PCI bus errors       - some are recoverable
3823150849Sscottl   *  2) transmitter FIFO underruns - increase fifo threshold
3824150849Sscottl   *  3) receiver FIFO overruns     - clear potential hangup
3825150849Sscottl   *  4) no receive descs or bufs   - count missed packets
3826150849Sscottl   */
3827150849Sscottl
3828150849Sscottl  /* 1) A fatal bus error causes a Tulip to stop initiating bus cycles. */
3829150849Sscottl  /* Module unload/load or boot are the only fixes for Parity Errors. */
3830150849Sscottl  /* Master and Target Aborts can be cleared and life may continue. */
3831150849Sscottl  status = READ_CSR(TLP_STATUS);
3832150849Sscottl  if ((status & TLP_STAT_FATAL_ERROR) != 0)
3833150849Sscottl    {
3834150849Sscottl    u_int32_t fatal = (status & TLP_STAT_FATAL_BITS)>>TLP_STAT_FATAL_SHIFT;
3835150849Sscottl    printf("%s: FATAL PCI BUS ERROR: %s%s%s%s\n", NAME_UNIT,
3836150849Sscottl     (fatal == 0) ? "PARITY ERROR" : "",
3837150849Sscottl     (fatal == 1) ? "MASTER ABORT" : "",
3838150849Sscottl     (fatal == 2) ? "TARGET ABORT" : "",
3839150849Sscottl     (fatal >= 3) ? "RESERVED (?)" : "");
3840150849Sscottl    cfcs = READ_PCI_CFG(sc, TLP_CFCS);  /* try to clear it */
3841150849Sscottl    cfcs &= ~(TLP_CFCS_MSTR_ABORT | TLP_CFCS_TARG_ABORT);
3842150849Sscottl    WRITE_PCI_CFG(sc, TLP_CFCS, cfcs);
3843150849Sscottl    }
3844150849Sscottl
3845150849Sscottl  /* 2) If the transmitter fifo underruns, increase the transmit fifo */
3846150849Sscottl  /*  threshold: the number of bytes required to be in the fifo */
3847150849Sscottl  /*  before starting the transmitter (cost: increased tx delay). */
3848150849Sscottl  /* The TX_FSM must be stopped to change this parameter. */
3849150849Sscottl  if ((status & TLP_STAT_TX_UNDERRUN) != 0)
3850150849Sscottl    {
3851150849Sscottl    op_mode = READ_CSR(TLP_OP_MODE);
3852150849Sscottl    /* enable store-and-forward mode if tx_threshold tops out? */
3853150849Sscottl    if ((op_mode & TLP_OP_TX_THRESH) < TLP_OP_TX_THRESH)
3854150849Sscottl      {
3855150849Sscottl      op_mode += 0x4000;  /* increment TX_THRESH field; can't overflow */
3856150849Sscottl      WRITE_CSR(TLP_OP_MODE, op_mode & ~TLP_OP_TX_RUN);
3857150849Sscottl      /* Wait for the TX FSM to stop; it might be processing a pkt. */
3858150849Sscottl      while (READ_CSR(TLP_STATUS) & TLP_STAT_TX_FSM); /* XXX HANG */
3859150849Sscottl      WRITE_CSR(TLP_OP_MODE, op_mode); /* restart tx */
3860150849Sscottl      if (DRIVER_DEBUG)
3861150849Sscottl        printf("%s: tx underrun; tx fifo threshold now %d bytes\n",
3862150849Sscottl         NAME_UNIT, 128<<((op_mode>>TLP_OP_TR_SHIFT)&3));
3863150849Sscottl      }
3864150849Sscottl    }
3865150849Sscottl
3866150849Sscottl  /* 3) Errata memo from Digital Equipment Corp warns that 21140A */
3867150849Sscottl  /* receivers through rev 2.2 can hang if the fifo overruns. */
3868150849Sscottl  /* Recommended fix: stop and start the RX FSM after an overrun. */
3869150849Sscottl  missed = READ_CSR(TLP_MISSED);
3870150849Sscottl  if ((overruns = ((missed & TLP_MISS_OVERRUN)>>TLP_OVERRUN_SHIFT)) != 0)
3871150849Sscottl    {
3872150849Sscottl    if (DRIVER_DEBUG)
3873150849Sscottl      printf("%s: rx overrun cntr=%d\n", NAME_UNIT, overruns);
3874150849Sscottl    sc->status.cntrs.overruns += overruns;
3875150849Sscottl    if ((READ_PCI_CFG(sc, TLP_CFRV) & 0xFF) <= 0x22)
3876150849Sscottl      {
3877150849Sscottl      op_mode = READ_CSR(TLP_OP_MODE);
3878150849Sscottl      WRITE_CSR(TLP_OP_MODE, op_mode & ~TLP_OP_RX_RUN);
3879150849Sscottl      /* Wait for the RX FSM to stop; it might be processing a pkt. */
3880150849Sscottl      while (READ_CSR(TLP_STATUS) & TLP_STAT_RX_FSM); /* XXX HANG */
3881150849Sscottl      WRITE_CSR(TLP_OP_MODE, op_mode);  /* restart rx */
3882150849Sscottl      }
3883150849Sscottl    }
3884150849Sscottl
3885150849Sscottl  /* 4) When the receiver is enabled and a packet arrives, but no DMA */
3886150849Sscottl  /*  descriptor is available, the packet is counted as 'missed'. */
3887150849Sscottl  /* The receiver should never miss packets; warn if it happens. */
3888150849Sscottl  if ((missed = (missed & TLP_MISS_MISSED)) != 0)
3889150849Sscottl    {
3890150849Sscottl    if (DRIVER_DEBUG)
3891150849Sscottl      printf("%s: rx missed %d pkts\n", NAME_UNIT, missed);
3892150849Sscottl    sc->status.cntrs.missed += missed;
3893150849Sscottl    }
3894150849Sscottl  }
3895150849Sscottl
3896150849Sscottlstatic void /* This is where the work gets done. */
3897150849Sscottlcore_interrupt(void *arg, int check_status)
3898150849Sscottl  {
3899150849Sscottl  softc_t *sc = arg;
3900150849Sscottl  int activity;
3901150849Sscottl
3902150849Sscottl  /* If any CPU is inside this critical section, then */
3903150849Sscottl  /* other CPUs should go away without doing anything. */
3904150849Sscottl  if (BOTTOM_TRYLOCK == 0)
3905150849Sscottl    {
3906150849Sscottl    sc->status.cntrs.lck_intr++;
3907150849Sscottl    return;
3908150849Sscottl    }
3909150849Sscottl
3910150849Sscottl  /* Clear pending card interrupts. */
3911150849Sscottl  WRITE_CSR(TLP_STATUS, READ_CSR(TLP_STATUS));
3912150849Sscottl
3913150849Sscottl  /* In Linux, pci_alloc_consistent() means DMA descriptors */
3914150849Sscottl  /*  don't need explicit syncing. */
3915150849Sscottl#if BSD
3916150849Sscottl  {
3917150849Sscottl  struct desc_ring *ring = &sc->txring;
3918150849Sscottl  DMA_SYNC(sc->txring.map, sc->txring.size_descs,
3919150849Sscottl   BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
3920150849Sscottl  ring = &sc->rxring;
3921150849Sscottl  DMA_SYNC(sc->rxring.map, sc->rxring.size_descs,
3922150849Sscottl   BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
3923150849Sscottl  }
3924150849Sscottl#endif
3925150849Sscottl
3926150849Sscottl  do  /* This is the main loop for interrupt processing. */
3927150849Sscottl    {
3928150849Sscottl    activity  = txintr_cleanup(sc);
3929150849Sscottl    activity += txintr_setup(sc);
3930150849Sscottl    activity += rxintr_cleanup(sc);
3931150849Sscottl    activity += rxintr_setup(sc);
3932150849Sscottl    } while (activity);
3933150849Sscottl
3934150849Sscottl#if BSD
3935150849Sscottl  {
3936150849Sscottl  struct desc_ring *ring = &sc->txring;
3937150849Sscottl  DMA_SYNC(sc->txring.map, sc->txring.size_descs,
3938150849Sscottl   BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
3939150849Sscottl  ring = &sc->rxring;
3940150849Sscottl  DMA_SYNC(sc->rxring.map, sc->rxring.size_descs,
3941150849Sscottl   BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
3942150849Sscottl  }
3943150849Sscottl#endif
3944150849Sscottl
3945150849Sscottl  /* As the interrupt is dismissed, check for four unusual events. */
3946150849Sscottl  if (check_status) check_intr_status(sc);
3947150849Sscottl
3948150849Sscottl  BOTTOM_UNLOCK;
3949150849Sscottl  }
3950150849Sscottl
3951150849Sscottl/* user_interrupt() may be called from a syscall or a softirq */
3952150849Sscottlstatic void
3953150849Sscottluser_interrupt(softc_t *sc, int check_status)
3954150849Sscottl  {
3955150849Sscottl  DISABLE_INTR; /* noop on FreeBSD-5 and Linux */
3956150849Sscottl  core_interrupt(sc, check_status);
3957150849Sscottl  ENABLE_INTR;  /* noop on FreeBSD-5 and Linux */
3958150849Sscottl  }
3959150849Sscottl
3960150849Sscottl#if BSD
3961150849Sscottl
3962153110Sru# if (defined(__FreeBSD__) && defined(DEVICE_POLLING))
3963150849Sscottl
3964150849Sscottl/* Service the card from the kernel idle loop without interrupts. */
3965193096Sattiliostatic int
3966150849Sscottlfbsd_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
3967150849Sscottl  {
3968150849Sscottl  softc_t *sc = IFP2SC(ifp);
3969150849Sscottl
3970150899Sscottl#if (__FreeBSD_version < 700000)
3971150849Sscottl  if ((ifp->if_capenable & IFCAP_POLLING) == 0)
3972150849Sscottl    {
3973150849Sscottl    ether_poll_deregister(ifp);
3974150849Sscottl    cmd = POLL_DEREGISTER;
3975150849Sscottl    }
3976150849Sscottl
3977150849Sscottl  if (cmd == POLL_DEREGISTER)
3978150849Sscottl    {
3979150849Sscottl    /* Last call -- reenable card interrupts. */
3980150849Sscottl    WRITE_CSR(TLP_INT_ENBL, TLP_INT_TXRX);
3981193105Sattilio    return 0;
3982150849Sscottl    }
3983150849Sscottl#endif
3984150849Sscottl
3985150849Sscottl  sc->quota = count;
3986150849Sscottl  core_interrupt(sc, (cmd==POLL_AND_CHECK_STATUS));
3987193105Sattilio  return 0;
3988150849Sscottl  }
3989150849Sscottl
3990150849Sscottl# endif  /* (__FreeBSD__ && DEVICE_POLLING) */
3991150849Sscottl
3992150849Sscottl/* BSD kernels call this procedure when an interrupt happens. */
3993150849Sscottlstatic intr_return_t
3994150849Sscottlbsd_interrupt(void *arg)
3995150849Sscottl  {
3996150849Sscottl  softc_t *sc = arg;
3997150849Sscottl
3998150849Sscottl  /* Cut losses early if this is not our interrupt. */
3999150849Sscottl  if ((READ_CSR(TLP_STATUS) & TLP_INT_TXRX) == 0)
4000150849Sscottl    return IRQ_NONE;
4001150849Sscottl
4002153110Sru# if (defined(__FreeBSD__) && defined(DEVICE_POLLING))
4003150849Sscottl  if (sc->ifp->if_capenable & IFCAP_POLLING)
4004150849Sscottl    return IRQ_NONE;
4005150849Sscottl
4006150849Sscottl  if ((sc->ifp->if_capabilities & IFCAP_POLLING) &&
4007150849Sscottl   (ether_poll_register(fbsd_poll, sc->ifp)))
4008150849Sscottl    {
4009150849Sscottl    WRITE_CSR(TLP_INT_ENBL, TLP_INT_DISABLE);
4010150849Sscottl    return IRQ_NONE;
4011150849Sscottl    }
4012150849Sscottl  else
4013150849Sscottl    sc->quota = sc->rxring.num_descs; /* input flow control */
4014150849Sscottl# endif  /* (__FreeBSD__ && DEVICE_POLLING) */
4015150849Sscottl
4016150849Sscottl  /* Disable card interrupts. */
4017150849Sscottl  WRITE_CSR(TLP_INT_ENBL, TLP_INT_DISABLE);
4018150849Sscottl
4019150849Sscottl  core_interrupt(sc, 0);
4020150849Sscottl
4021150849Sscottl  /* Enable card interrupts. */
4022150849Sscottl  WRITE_CSR(TLP_INT_ENBL, TLP_INT_TXRX);
4023150849Sscottl
4024150849Sscottl  return IRQ_HANDLED;
4025150849Sscottl  }
4026150849Sscottl
4027150849Sscottl#endif /* BSD */
4028150849Sscottl
4029150849Sscottl/* Administrative status of the driver (UP or DOWN) has changed. */
4030150849Sscottl/* A card-specific action may be required: T1 and T3 cards: no-op. */
4031150849Sscottl/* HSSI and SSI cards change the state of modem ready signals. */
4032150849Sscottlstatic void
4033150849Sscottlset_status(softc_t *sc, int status)
4034150849Sscottl  {
4035150849Sscottl  struct ioctl ioctl;
4036150849Sscottl
4037150849Sscottl  ioctl.cmd = IOCTL_SET_STATUS;
4038150849Sscottl  ioctl.data = status;
4039150849Sscottl
4040150849Sscottl  sc->card->ioctl(sc, &ioctl);
4041150849Sscottl  }
4042150849Sscottl
4043150849Sscottl#if P2P
4044150849Sscottl
4045150849Sscottl/* Callout from P2P: */
4046150849Sscottl/* Get the state of DCD (Data Carrier Detect). */
4047150849Sscottlstatic int
4048150849Sscottlp2p_getmdm(struct p2pcom *p2p, caddr_t result)
4049150849Sscottl  {
4050150849Sscottl  softc_t *sc = IFP2SC(&p2p->p2p_if);
4051150849Sscottl
4052150849Sscottl  /* Non-zero isn't good enough; TIOCM_CAR is 0x40. */
4053150849Sscottl  *(int *)result = (sc->status.oper_status==STATUS_UP) ? TIOCM_CAR : 0;
4054150849Sscottl
4055150849Sscottl  return 0;
4056150849Sscottl  }
4057150849Sscottl
4058150849Sscottl/* Callout from P2P: */
4059150849Sscottl/* Set the state of DTR (Data Terminal Ready). */
4060150849Sscottlstatic int
4061150849Sscottlp2p_mdmctl(struct p2pcom *p2p, int flag)
4062150849Sscottl  {
4063150849Sscottl  softc_t *sc = IFP2SC(&p2p->p2p_if);
4064150849Sscottl
4065150849Sscottl  set_status(sc, flag);
4066150849Sscottl
4067150849Sscottl  return 0;
4068150849Sscottl  }
4069150849Sscottl
4070150849Sscottl#endif /* P2P */
4071150849Sscottl
4072150849Sscottl#if NSPPP
4073150849Sscottl
4074150849Sscottl# ifndef PP_FR
4075150849Sscottl#  define PP_FR 0
4076150849Sscottl# endif
4077150849Sscottl
4078150849Sscottl/* Callout from SPPP: */
4079150849Sscottlstatic void
4080150849Sscottlsppp_tls(struct sppp *sppp)
4081150849Sscottl  {
4082153084Sru# ifdef __FreeBSD__
4083150849Sscottl  if (!(sppp->pp_mode  & IFF_LINK2) &&
4084150849Sscottl      !(sppp->pp_flags & PP_FR))
4085153084Sru# elif defined(__NetBSD__) || defined(__OpenBSD__)
4086150849Sscottl  if (!(sppp->pp_flags & PP_CISCO))
4087150849Sscottl# endif
4088150849Sscottl    sppp->pp_up(sppp);
4089150849Sscottl  }
4090150849Sscottl
4091150849Sscottl/* Callout from SPPP: */
4092150849Sscottlstatic void
4093150849Sscottlsppp_tlf(struct sppp *sppp)
4094150849Sscottl  {
4095153084Sru# ifdef __FreeBSD__
4096150849Sscottl  if (!(sppp->pp_mode  & IFF_LINK2) &&
4097150849Sscottl      !(sppp->pp_flags & PP_FR))
4098153084Sru# elif defined(__NetBSD__) || defined(__OpenBSD__)
4099150849Sscottl  if (!(sppp->pp_flags & PP_CISCO))
4100150849Sscottl# endif
4101150849Sscottl    sppp->pp_down(sppp);
4102150849Sscottl  }
4103150849Sscottl
4104150849Sscottl#endif /* NSPPP */
4105150849Sscottl
4106150849Sscottl/* Configure line protocol stuff.
4107150849Sscottl * Called by attach_card() during module init.
4108150849Sscottl * Called by core_ioctl()  when lmcconfig writes sc->config.
4109150849Sscottl * Called by detach_card() during module shutdown.
4110150849Sscottl */
4111150849Sscottlstatic void
4112150849Sscottlconfig_proto(softc_t *sc, struct config *config)
4113150849Sscottl  {
4114150849Sscottl  /* Use line protocol stack instead of RAWIP mode. */
4115150849Sscottl  if ((sc->config.line_pkg == PKG_RAWIP) &&
4116150849Sscottl         (config->line_pkg != PKG_RAWIP))
4117150849Sscottl    {
4118150849Sscottl#if NSPPP
4119150849Sscottl    LMC_BPF_DETACH;
4120150849Sscottl    sppp_attach(sc->ifp);
4121150849Sscottl    LMC_BPF_ATTACH(DLT_PPP, 4);
4122150849Sscottl    sc->sppp->pp_tls = sppp_tls;
4123150849Sscottl    sc->sppp->pp_tlf = sppp_tlf;
4124150849Sscottl    /* Force reconfiguration of SPPP params. */
4125150849Sscottl    sc->config.line_prot = 0;
4126150849Sscottl    sc->config.keep_alive = config->keep_alive ? 0:1;
4127150849Sscottl#elif P2P
4128150849Sscottl    int error = 0;
4129150849Sscottl    sc->p2p->p2p_proto = 0; /* force p2p_attach */
4130150849Sscottl    if ((error = p2p_attach(sc->p2p))) /* calls bpfattach() */
4131150849Sscottl      {
4132150849Sscottl      printf("%s: p2p_attach() failed; error %d\n", NAME_UNIT, error);
4133150849Sscottl      config->line_pkg = PKG_RAWIP;  /* still in RAWIP mode */
4134150849Sscottl      }
4135150849Sscottl    else
4136150849Sscottl      {
4137150849Sscottl      sc->p2p->p2p_mdmctl = p2p_mdmctl; /* set DTR */
4138150849Sscottl      sc->p2p->p2p_getmdm = p2p_getmdm; /* get DCD */
4139150849Sscottl      }
4140150849Sscottl#elif GEN_HDLC
4141150849Sscottl    int error = 0;
4142150849Sscottl    sc->net_dev->mtu = HDLC_MAX_MTU;
4143150849Sscottl    if ((error = hdlc_open(sc->net_dev)))
4144150849Sscottl      {
4145150849Sscottl      printf("%s: hdlc_open() failed; error %d\n", NAME_UNIT, error);
4146150849Sscottl      printf("%s: Try 'sethdlc %s ppp'\n", NAME_UNIT, NAME_UNIT);
4147150849Sscottl      config->line_pkg = PKG_RAWIP;  /* still in RAWIP mode */
4148150849Sscottl      }
4149150849Sscottl#else /* no line protocol stack was configured */
4150150849Sscottl    config->line_pkg = PKG_RAWIP;  /* still in RAWIP mode */
4151150849Sscottl#endif
4152150849Sscottl    }
4153150849Sscottl
4154150849Sscottl  /* Bypass line protocol stack and return to RAWIP mode. */
4155150849Sscottl  if ((sc->config.line_pkg != PKG_RAWIP) &&
4156150849Sscottl         (config->line_pkg == PKG_RAWIP))
4157150849Sscottl    {
4158150849Sscottl#if NSPPP
4159150849Sscottl    LMC_BPF_DETACH;
4160150849Sscottl    sppp_flush(sc->ifp);
4161150849Sscottl    sppp_detach(sc->ifp);
4162150849Sscottl    setup_ifnet(sc->ifp);
4163150849Sscottl    LMC_BPF_ATTACH(DLT_RAW, 0);
4164150849Sscottl#elif P2P
4165150849Sscottl    int error = 0;
4166150849Sscottl    if_qflush(&sc->p2p->p2p_isnd);
4167150849Sscottl    if ((error = p2p_detach(sc->p2p)))
4168150849Sscottl      {
4169150849Sscottl      printf("%s: p2p_detach() failed; error %d\n",  NAME_UNIT, error);
4170150849Sscottl      printf("%s: Try 'ifconfig %s down -remove'\n", NAME_UNIT, NAME_UNIT);
4171150849Sscottl      config->line_pkg = PKG_P2P; /* not in RAWIP mode; still attached to P2P */
4172150849Sscottl      }
4173150849Sscottl    else
4174150849Sscottl      {
4175150849Sscottl      setup_ifnet(sc->ifp);
4176150849Sscottl      LMC_BPF_ATTACH(DLT_RAW, 0);
4177150849Sscottl      }
4178150849Sscottl#elif GEN_HDLC
4179150849Sscottl    hdlc_proto_detach(sc->hdlc_dev);
4180150849Sscottl    hdlc_close(sc->net_dev);
4181150849Sscottl    setup_netdev(sc->net_dev);
4182150849Sscottl#endif
4183150849Sscottl    }
4184150849Sscottl
4185150849Sscottl#if NSPPP
4186150849Sscottl
4187150849Sscottl  if (config->line_pkg != PKG_RAWIP)
4188150849Sscottl    {
4189150849Sscottl    /* Check for change to PPP protocol. */
4190150849Sscottl    if ((sc->config.line_prot != PROT_PPP) &&
4191150849Sscottl           (config->line_prot == PROT_PPP))
4192150849Sscottl      {
4193150849Sscottl      LMC_BPF_DETACH;
4194153084Sru# if (defined(__NetBSD__) || defined(__OpenBSD__))
4195150849Sscottl      sc->sppp->pp_flags &= ~PP_CISCO;
4196153084Sru# elif defined(__FreeBSD__)
4197150849Sscottl      sc->ifp->if_flags  &= ~IFF_LINK2;
4198150849Sscottl      sc->sppp->pp_flags &= ~PP_FR;
4199150849Sscottl# endif
4200150849Sscottl      LMC_BPF_ATTACH(DLT_PPP, 4);
4201150849Sscottl      sppp_ioctl(sc->ifp, SIOCSIFFLAGS, NULL);
4202150849Sscottl      }
4203150849Sscottl
4204150849Sscottl# ifndef DLT_C_HDLC
4205150849Sscottl#  define DLT_C_HDLC DLT_PPP
4206150849Sscottl# endif
4207150849Sscottl
4208150849Sscottl    /* Check for change to C_HDLC protocol. */
4209150849Sscottl    if ((sc->config.line_prot != PROT_C_HDLC) &&
4210150849Sscottl           (config->line_prot == PROT_C_HDLC))
4211150849Sscottl      {
4212150849Sscottl      LMC_BPF_DETACH;
4213153084Sru# if (defined(__NetBSD__) || defined(__OpenBSD__))
4214150849Sscottl      sc->sppp->pp_flags |=  PP_CISCO;
4215153084Sru# elif defined(__FreeBSD__)
4216150849Sscottl      sc->ifp->if_flags  |=  IFF_LINK2;
4217150849Sscottl      sc->sppp->pp_flags &= ~PP_FR;
4218150849Sscottl# endif
4219150849Sscottl      LMC_BPF_ATTACH(DLT_C_HDLC, 4);
4220150849Sscottl      sppp_ioctl(sc->ifp, SIOCSIFFLAGS, NULL);
4221150849Sscottl      }
4222150849Sscottl
4223150849Sscottl    /* Check for change to Frame Relay protocol. */
4224150849Sscottl    if ((sc->config.line_prot != PROT_FRM_RLY) &&
4225150849Sscottl           (config->line_prot == PROT_FRM_RLY))
4226150849Sscottl      {
4227150849Sscottl      LMC_BPF_DETACH;
4228153084Sru# if (defined(__NetBSD__) || defined(__OpenBSD__))
4229150849Sscottl      sc->sppp->pp_flags &= ~PP_CISCO;
4230153084Sru# elif defined(__FreeBSD__)
4231150849Sscottl      sc->ifp->if_flags  &= ~IFF_LINK2;
4232150849Sscottl      sc->sppp->pp_flags |= PP_FR;
4233150849Sscottl# endif
4234150849Sscottl      LMC_BPF_ATTACH(DLT_FRELAY, 4);
4235150849Sscottl      sppp_ioctl(sc->ifp, SIOCSIFFLAGS, NULL);
4236150849Sscottl      }
4237150849Sscottl
4238150849Sscottl    /* Check for disabling keep-alives. */
4239150849Sscottl    if ((sc->config.keep_alive != 0) &&
4240150849Sscottl           (config->keep_alive == 0))
4241150849Sscottl      sc->sppp->pp_flags &= ~PP_KEEPALIVE;
4242150849Sscottl
4243150849Sscottl    /* Check for enabling keep-alives. */
4244150849Sscottl    if ((sc->config.keep_alive == 0) &&
4245150849Sscottl           (config->keep_alive != 0))
4246150849Sscottl      sc->sppp->pp_flags |=  PP_KEEPALIVE;
4247150849Sscottl    }
4248150849Sscottl
4249150849Sscottl#endif /* NSPPP */
4250150849Sscottl
4251150849Sscottl  /* Loop back through the TULIP Ethernet chip; (no CRC). */
4252150849Sscottl  /* Data sheet says stop DMA before changing OPMODE register. */
4253150849Sscottl  /* But that's not as simple as it sounds; works anyway. */
4254150849Sscottl  /* Check for enabling loopback thru Tulip chip. */
4255150849Sscottl  if ((sc->config.loop_back != CFG_LOOP_TULIP) &&
4256150849Sscottl         (config->loop_back == CFG_LOOP_TULIP))
4257150849Sscottl    {
4258150849Sscottl    u_int32_t op_mode = READ_CSR(TLP_OP_MODE);
4259150849Sscottl    op_mode |= TLP_OP_INT_LOOP;
4260150849Sscottl    WRITE_CSR(TLP_OP_MODE, op_mode);
4261150849Sscottl    config->crc_len = CFG_CRC_0;
4262150849Sscottl    }
4263150849Sscottl
4264150849Sscottl  /* Check for disabling loopback thru Tulip chip. */
4265150849Sscottl  if ((sc->config.loop_back == CFG_LOOP_TULIP) &&
4266150849Sscottl         (config->loop_back != CFG_LOOP_TULIP))
4267150849Sscottl    {
4268150849Sscottl    u_int32_t op_mode = READ_CSR(TLP_OP_MODE);
4269150849Sscottl    op_mode &= ~TLP_OP_LOOP_MODE;
4270150849Sscottl    WRITE_CSR(TLP_OP_MODE, op_mode);
4271150849Sscottl    config->crc_len = CFG_CRC_16;
4272150849Sscottl    }
4273150849Sscottl  }
4274150849Sscottl
4275150849Sscottl/* This is the core ioctl procedure. */
4276150849Sscottl/* It handles IOCTLs from lmcconfig(8). */
4277150849Sscottl/* It must not run when card watchdogs run. */
4278150849Sscottl/* Called from a syscall (user context; no spinlocks). */
4279150849Sscottl/* This procedure can SLEEP. */
4280150849Sscottlstatic int
4281150849Sscottlcore_ioctl(softc_t *sc, u_long cmd, caddr_t data)
4282150849Sscottl  {
4283150849Sscottl  struct iohdr  *iohdr  = (struct iohdr  *) data;
4284150849Sscottl  struct ioctl  *ioctl  = (struct ioctl  *) data;
4285150849Sscottl  struct status *status = (struct status *) data;
4286150849Sscottl  struct config *config = (struct config *) data;
4287150849Sscottl  int error = 0;
4288150849Sscottl
4289150849Sscottl  /* All structs start with a string and a cookie. */
4290150849Sscottl  if (((struct iohdr *)data)->cookie != NGM_LMC_COOKIE)
4291150849Sscottl    return EINVAL;
4292150849Sscottl
4293150849Sscottl  while (TOP_TRYLOCK == 0)
4294150849Sscottl    {
4295150849Sscottl    sc->status.cntrs.lck_ioctl++;
4296150849Sscottl    SLEEP(10000); /* yield? */
4297150849Sscottl    }
4298150849Sscottl  switch (cmd)
4299150849Sscottl    {
4300150849Sscottl    case LMCIOCGSTAT:
4301150849Sscottl      {
4302150849Sscottl      *status = sc->status;
4303150849Sscottl      iohdr->cookie = NGM_LMC_COOKIE;
4304150849Sscottl      break;
4305150849Sscottl      }
4306150849Sscottl    case LMCIOCGCFG:
4307150849Sscottl      {
4308150849Sscottl      *config = sc->config;
4309150849Sscottl      iohdr->cookie = NGM_LMC_COOKIE;
4310150849Sscottl      break;
4311150849Sscottl      }
4312150849Sscottl    case LMCIOCSCFG:
4313150849Sscottl      {
4314150849Sscottl      if ((error = CHECK_CAP)) break;
4315150849Sscottl      config_proto(sc, config);
4316150849Sscottl      sc->config = *config;
4317150849Sscottl      sc->card->config(sc);
4318150849Sscottl      break;
4319150849Sscottl      }
4320150849Sscottl    case LMCIOCREAD:
4321150849Sscottl      {
4322150849Sscottl      if (ioctl->cmd == IOCTL_RW_PCI)
4323150849Sscottl        {
4324150849Sscottl        if (ioctl->address > 252) { error = EFAULT; break; }
4325150849Sscottl        ioctl->data = READ_PCI_CFG(sc, ioctl->address);
4326150849Sscottl	}
4327150849Sscottl      else if (ioctl->cmd == IOCTL_RW_CSR)
4328150849Sscottl        {
4329150849Sscottl        if (ioctl->address > 15) { error = EFAULT; break; }
4330150849Sscottl        ioctl->data = READ_CSR(ioctl->address*TLP_CSR_STRIDE);
4331150849Sscottl	}
4332150849Sscottl      else if (ioctl->cmd == IOCTL_RW_SROM)
4333150849Sscottl        {
4334150849Sscottl        if (ioctl->address > 63)  { error = EFAULT; break; }
4335150849Sscottl        ioctl->data = read_srom(sc, ioctl->address);
4336150849Sscottl	}
4337150849Sscottl      else if (ioctl->cmd == IOCTL_RW_BIOS)
4338150849Sscottl        ioctl->data = read_bios(sc, ioctl->address);
4339150849Sscottl      else if (ioctl->cmd == IOCTL_RW_MII)
4340150849Sscottl        ioctl->data = read_mii(sc, ioctl->address);
4341150849Sscottl      else if (ioctl->cmd == IOCTL_RW_FRAME)
4342150849Sscottl        ioctl->data = read_framer(sc, ioctl->address);
4343150849Sscottl      else
4344150849Sscottl        error = EINVAL;
4345150849Sscottl      break;
4346150849Sscottl      }
4347150849Sscottl    case LMCIOCWRITE:
4348150849Sscottl      {
4349150849Sscottl      if ((error = CHECK_CAP)) break;
4350150849Sscottl      if (ioctl->cmd == IOCTL_RW_PCI)
4351150849Sscottl        {
4352150849Sscottl        if (ioctl->address > 252) { error = EFAULT; break; }
4353150849Sscottl        WRITE_PCI_CFG(sc, ioctl->address, ioctl->data);
4354150849Sscottl	}
4355150849Sscottl      else if (ioctl->cmd == IOCTL_RW_CSR)
4356150849Sscottl        {
4357150849Sscottl        if (ioctl->address > 15) { error = EFAULT; break; }
4358150849Sscottl        WRITE_CSR(ioctl->address*TLP_CSR_STRIDE, ioctl->data);
4359150849Sscottl	}
4360150849Sscottl      else if (ioctl->cmd == IOCTL_RW_SROM)
4361150849Sscottl        {
4362150849Sscottl        if (ioctl->address > 63)  { error = EFAULT; break; }
4363150849Sscottl        write_srom(sc, ioctl->address, ioctl->data); /* can sleep */
4364150849Sscottl	}
4365150849Sscottl      else if (ioctl->cmd == IOCTL_RW_BIOS)
4366150849Sscottl        {
4367150849Sscottl        if (ioctl->address == 0) erase_bios(sc);
4368150849Sscottl        write_bios(sc, ioctl->address, ioctl->data); /* can sleep */
4369150849Sscottl	}
4370150849Sscottl      else if (ioctl->cmd == IOCTL_RW_MII)
4371150849Sscottl        write_mii(sc, ioctl->address, ioctl->data);
4372150849Sscottl      else if (ioctl->cmd == IOCTL_RW_FRAME)
4373150849Sscottl        write_framer(sc, ioctl->address, ioctl->data);
4374150849Sscottl      else if (ioctl->cmd == IOCTL_WO_SYNTH)
4375150849Sscottl        write_synth(sc, (struct synth *)&ioctl->data);
4376150849Sscottl      else if (ioctl->cmd == IOCTL_WO_DAC)
4377150849Sscottl        {
4378150849Sscottl        write_dac(sc, 0x9002); /* set Vref = 2.048 volts */
4379150849Sscottl        write_dac(sc, ioctl->data & 0xFFF);
4380150849Sscottl	}
4381150849Sscottl      else
4382150849Sscottl        error = EINVAL;
4383150849Sscottl      break;
4384150849Sscottl      }
4385150849Sscottl    case LMCIOCTL:
4386150849Sscottl      {
4387150849Sscottl      if ((error = CHECK_CAP)) break;
4388150849Sscottl      if (ioctl->cmd == IOCTL_XILINX_RESET)
4389150849Sscottl        {
4390150849Sscottl        reset_xilinx(sc);
4391150849Sscottl        sc->card->config(sc);
4392150849Sscottl	}
4393150849Sscottl      else if (ioctl->cmd == IOCTL_XILINX_ROM)
4394150849Sscottl        {
4395150849Sscottl        load_xilinx_from_rom(sc); /* can sleep */
4396150849Sscottl        sc->card->config(sc);
4397150849Sscottl	}
4398150849Sscottl      else if (ioctl->cmd == IOCTL_XILINX_FILE)
4399150849Sscottl        {
4400150849Sscottl        /* load_xilinx_from_file() can sleep. */
4401150849Sscottl        error = load_xilinx_from_file(sc, ioctl->ucode, ioctl->data);
4402150849Sscottl        if (error != 0) load_xilinx_from_rom(sc); /* try the rom */
4403150849Sscottl        sc->card->config(sc);
4404150849Sscottl        set_status(sc, (error==0));  /* XXX */
4405150849Sscottl	}
4406150849Sscottl      else if (ioctl->cmd == IOCTL_RESET_CNTRS)
4407150849Sscottl        {
4408150849Sscottl        memset(&sc->status.cntrs, 0, sizeof(struct event_cntrs));
4409150849Sscottl        microtime(&sc->status.cntrs.reset_time);
4410150849Sscottl        }
4411150849Sscottl      else
4412150849Sscottl        error = sc->card->ioctl(sc, ioctl); /* can sleep */
4413150849Sscottl      break;
4414150849Sscottl      }
4415150849Sscottl    default:
4416150849Sscottl      error = EINVAL;
4417150849Sscottl      break;
4418150849Sscottl    }
4419150849Sscottl  TOP_UNLOCK;
4420150849Sscottl
4421150849Sscottl  return error;
4422150849Sscottl  }
4423150849Sscottl
4424150849Sscottl/* This is the core watchdog procedure. */
4425150849Sscottl/* It calculates link speed, and calls the card-specific watchdog code. */
4426150849Sscottl/* Calls interrupt() in case one got lost; also kick-starts the device. */
4427150849Sscottl/* ioctl syscalls and card watchdog routines must be interlocked.       */
4428150849Sscottl/* This procedure must not sleep. */
4429150849Sscottlstatic void
4430150849Sscottlcore_watchdog(softc_t *sc)
4431150849Sscottl  {
4432150849Sscottl  /* Read and restart the Tulip timer. */
4433150849Sscottl  u_int32_t tx_speed = READ_CSR(TLP_TIMER);
4434150849Sscottl  WRITE_CSR(TLP_TIMER, 0xFFFF);
4435150849Sscottl
4436150849Sscottl  /* Measure MII clock using a timer in the Tulip chip.
4437150849Sscottl   * This timer counts transmitter bits divided by 4096.
4438150849Sscottl   * Since this is called once a second the math is easy.
4439150849Sscottl   * This is only correct when the link is NOT sending pkts.
4440150849Sscottl   * On a fully-loaded link, answer will be HALF actual rate.
4441150849Sscottl   * Clock rate during pkt is HALF clk rate between pkts.
4442150849Sscottl   * Measuring clock rate really measures link utilization!
4443150849Sscottl   */
4444150849Sscottl  sc->status.tx_speed = (0xFFFF - (tx_speed & 0xFFFF)) << 12;
4445150849Sscottl
4446150849Sscottl  /* The first status reset time is when the calendar clock is set. */
4447150849Sscottl  if (sc->status.cntrs.reset_time.tv_sec < 1000)
4448150849Sscottl    microtime(&sc->status.cntrs.reset_time);
4449150849Sscottl
4450150849Sscottl  /* Update hardware (operational) status. */
4451150849Sscottl  /* Call the card-specific watchdog routines. */
4452150849Sscottl  if (TOP_TRYLOCK != 0)
4453150849Sscottl    {
4454150849Sscottl    sc->status.oper_status = sc->card->watchdog(sc);
4455150849Sscottl
4456150849Sscottl    /* Increment a counter which tells user-land */
4457150849Sscottl    /*  observers that SNMP state has been updated. */
4458150849Sscottl    sc->status.ticks++;
4459150849Sscottl
4460150849Sscottl    TOP_UNLOCK;
4461150849Sscottl    }
4462150849Sscottl  else
4463150849Sscottl    sc->status.cntrs.lck_watch++;
4464150849Sscottl
4465150849Sscottl  /* In case an interrupt gets lost... */
4466150849Sscottl  user_interrupt(sc, 1);
4467150849Sscottl  }
4468150849Sscottl
4469150849Sscottl#if IFNET
4470150849Sscottl
4471150849Sscottl/* Called from a syscall (user context; no spinlocks). */
4472150849Sscottlstatic int
4473180304Srwatsonlmc_raw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
4474150849Sscottl  {
4475150849Sscottl  struct ifreq *ifr = (struct ifreq *) data;
4476150849Sscottl  int error = 0;
4477150849Sscottl
4478150849Sscottl  switch (cmd)
4479150849Sscottl    {
4480153110Sru# if (defined(__FreeBSD__) && defined(DEVICE_POLLING))  /* XXX necessary? */
4481150849Sscottl    case SIOCSIFCAP:
4482150849Sscottl# endif
4483150849Sscottl    case SIOCAIFADDR:
4484150849Sscottl    case SIOCSIFFLAGS:
4485150849Sscottl#if 0
4486150849Sscottl    case SIOCADDMULTI:
4487150849Sscottl    case SIOCDELMULTI:
4488150849Sscottl      break;
4489150849Sscottl#endif
4490150849Sscottl    case SIOCSIFADDR:
4491150849Sscottl      ifp->if_flags |= IFF_UP;	/* a Unix tradition */
4492150849Sscottl      break;
4493150849Sscottl    case SIOCSIFMTU:
4494150849Sscottl      ifp->if_mtu = ifr->ifr_mtu;
4495150849Sscottl      break;
4496150849Sscottl    default:
4497150849Sscottl      error = EINVAL;
4498150849Sscottl      break;
4499150849Sscottl    }
4500150849Sscottl  return error;
4501150849Sscottl  }
4502150849Sscottl
4503150849Sscottl/* Called from a syscall (user context; no spinlocks). */
4504150849Sscottlstatic int
4505180304Srwatsonlmc_ifnet_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
4506150849Sscottl  {
4507150849Sscottl  softc_t *sc = IFP2SC(ifp);
4508153084Sru# ifdef __OpenBSD__
4509150849Sscottl  struct ifreq *ifr = (struct ifreq *) data;
4510150849Sscottl# endif
4511150849Sscottl  int error = 0;
4512150849Sscottl
4513150849Sscottl  switch (cmd)
4514150849Sscottl    {
4515150849Sscottl    /* Catch the IOCTLs used by lmcconfig. */
4516150849Sscottl    case LMCIOCGSTAT:
4517150849Sscottl    case LMCIOCGCFG:
4518150849Sscottl    case LMCIOCSCFG:
4519150849Sscottl    case LMCIOCREAD:
4520150849Sscottl    case LMCIOCWRITE:
4521150849Sscottl    case LMCIOCTL:
4522150849Sscottl      error = core_ioctl(sc, cmd, data);
4523150849Sscottl      break;
4524153084Sru# ifdef __OpenBSD__
4525150849Sscottl    /* Catch the IOCTLs used by ifconfig. */
4526150849Sscottl    case SIOCSIFMEDIA:
4527150849Sscottl      if ((error = CHECK_CAP)) break;
4528150849Sscottl    case SIOCGIFMEDIA:
4529150849Sscottl      error = ifmedia_ioctl(ifp, ifr, &sc->ifm, cmd);
4530150849Sscottl      break;
4531150849Sscottl    case SIOCSIFTIMESLOT:
4532150849Sscottl      if ((error = CHECK_CAP)) break;
4533150849Sscottl      if (sc->status.card_type == TLP_CSID_T1E1)
4534150849Sscottl        {
4535150849Sscottl        struct config config = sc->config;
4536150849Sscottl        if ((error = copyin(ifr->ifr_data, &config.time_slots,
4537150849Sscottl         sizeof config.time_slots))) break;
4538150849Sscottl        config.iohdr.cookie = NGM_LMC_COOKIE;
4539150849Sscottl        error = core_ioctl(sc, LMCIOCSCFG, (caddr_t)&config);
4540150849Sscottl	}
4541150849Sscottl      else
4542150849Sscottl        error = EINVAL;
4543150849Sscottl      break;
4544150849Sscottl    case SIOCGIFTIMESLOT:
4545150849Sscottl      if (sc->status.card_type == TLP_CSID_T1E1)
4546150849Sscottl        error = copyout(&sc->config.time_slots, ifr->ifr_data,
4547150849Sscottl         sizeof sc->config.time_slots);
4548150849Sscottl      else
4549150849Sscottl        error = EINVAL;
4550150849Sscottl      break;
4551150849Sscottl# endif
4552150849Sscottl    /* Pass the rest to the line protocol. */
4553150849Sscottl    default:
4554150849Sscottl      if (sc->config.line_pkg == PKG_RAWIP)
4555180304Srwatson        error =  lmc_raw_ioctl(ifp, cmd, data);
4556150849Sscottl      else
4557150849Sscottl# if NSPPP
4558150849Sscottl        error = sppp_ioctl(ifp, cmd, data);
4559150849Sscottl# elif P2P
4560150849Sscottl        error =  p2p_ioctl(ifp, cmd, data);
4561150849Sscottl# else
4562150849Sscottl        error = EINVAL;
4563150849Sscottl# endif
4564150849Sscottl      break;
4565150849Sscottl    }
4566150849Sscottl
4567150849Sscottl  if (DRIVER_DEBUG && (error!=0))
4568180304Srwatson    printf("%s: lmc_ifnet_ioctl; cmd=0x%08lx error=%d\n",
4569150849Sscottl     NAME_UNIT, cmd, error);
4570150849Sscottl
4571150849Sscottl  return error;
4572150849Sscottl  }
4573150849Sscottl
4574150849Sscottl/* Called from a syscall (user context; no spinlocks). */
4575150849Sscottlstatic void
4576180304Srwatsonlmc_ifnet_start(struct ifnet *ifp)
4577150849Sscottl  {
4578150849Sscottl  softc_t *sc = IFP2SC(ifp);
4579150849Sscottl
4580150849Sscottl  /* Start the transmitter; incoming pkts are NOT processed. */
4581150849Sscottl  user_interrupt(sc, 0);
4582150849Sscottl  }
4583150849Sscottl
4584150849Sscottl/* sppp and p2p replace this with their own proc. */
4585150849Sscottl/* RAWIP mode is the only time this is used. */
4586150849Sscottl/* Called from a syscall (user context; no spinlocks). */
4587150849Sscottlstatic int
4588180304Srwatsonlmc_raw_output(struct ifnet *ifp, struct mbuf *m,
4589249925Sglebius const struct sockaddr *dst, struct route *ro)
4590150849Sscottl  {
4591150849Sscottl  softc_t *sc = IFP2SC(ifp);
4592150849Sscottl  int error = 0;
4593150849Sscottl
4594150849Sscottl  /* Fail if the link is down. */
4595150849Sscottl  if (sc->status.oper_status != STATUS_UP)
4596150849Sscottl    {
4597150849Sscottl    m_freem(m);
4598150849Sscottl    sc->status.cntrs.odiscards++;
4599150849Sscottl    if (DRIVER_DEBUG)
4600180304Srwatson      printf("%s: lmc_raw_output: tx pkt discarded: link down\n", NAME_UNIT);
4601150849Sscottl    return ENETDOWN;
4602150849Sscottl    }
4603150849Sscottl
4604150849Sscottl# if NETGRAPH
4605150849Sscottl  /* Netgraph has priority over the ifnet kernel interface. */
4606150849Sscottl  if (sc->ng_hook != NULL)
4607150849Sscottl    {
4608150849Sscottl    m_freem(m);
4609150849Sscottl    sc->status.cntrs.odiscards++;
4610150849Sscottl    if (DRIVER_DEBUG)
4611180304Srwatson      printf("%s: lmc_raw_output: tx pkt discarded: netgraph active\n",
4612180304Srwatson	NAME_UNIT);
4613150849Sscottl    return EBUSY;
4614150849Sscottl    }
4615150849Sscottl# endif
4616150849Sscottl
4617180304Srwatson  /* lmc_raw_output() ENQUEUEs in a syscall or softirq. */
4618150849Sscottl  /* txintr_setup() DEQUEUEs in a hard interrupt. */
4619150849Sscottl  /* Some BSD QUEUE routines are not interrupt-safe. */
4620150849Sscottl  {
4621150849Sscottl  DISABLE_INTR;
4622150849Sscottl# if (__FreeBSD_version >= 503000)
4623150849Sscottl  IFQ_ENQUEUE(&ifp->if_snd, m, error);
4624150849Sscottl# else
4625150849Sscottl  IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
4626150849Sscottl# endif
4627150849Sscottl  ENABLE_INTR;
4628150849Sscottl  }
4629150849Sscottl
4630150849Sscottl  if (error==0)
4631150849Sscottl    user_interrupt(sc, 0); /* start the transmitter */
4632150849Sscottl  else
4633150849Sscottl    {
4634150849Sscottl    m_freem(m);
4635150849Sscottl    sc->status.cntrs.odiscards++;
4636150849Sscottl    if (DRIVER_DEBUG)
4637180304Srwatson      printf("%s: lmc_raw_output: IFQ_ENQUEUE() failed; error %d\n",
4638150849Sscottl       NAME_UNIT, error);
4639150849Sscottl    }
4640150849Sscottl
4641150849Sscottl  return error;
4642150849Sscottl  }
4643150849Sscottl
4644150849Sscottl/* Called from a softirq once a second. */
4645150849Sscottlstatic void
4646199538Sjhblmc_watchdog(void *arg)
4647150849Sscottl  {
4648199538Sjhb  struct ifnet *ifp = arg;
4649150849Sscottl  softc_t *sc = IFP2SC(ifp);
4650150849Sscottl  u_int8_t old_oper_status = sc->status.oper_status;
4651150849Sscottl  struct event_cntrs *cntrs = &sc->status.cntrs;
4652150849Sscottl
4653150849Sscottl  core_watchdog(sc); /* updates oper_status */
4654150849Sscottl
4655150849Sscottl#if NETGRAPH
4656150849Sscottl  if (sc->ng_hook != NULL)
4657150849Sscottl    {
4658150849Sscottl    sc->status.line_pkg  = PKG_NG;
4659150849Sscottl    sc->status.line_prot = 0;
4660150849Sscottl    }
4661150849Sscottl  else
4662150849Sscottl#endif
4663150849Sscottl  if (sc->config.line_pkg == PKG_RAWIP)
4664150849Sscottl    {
4665150849Sscottl    sc->status.line_pkg  = PKG_RAWIP;
4666150849Sscottl    sc->status.line_prot = PROT_IP_HDLC;
4667150849Sscottl    }
4668150849Sscottl  else
4669150849Sscottl    {
4670150849Sscottl# if P2P
4671150849Sscottl    /* Notice change in link status. */
4672150849Sscottl    if ((old_oper_status != sc->status.oper_status) && (sc->p2p->p2p_modem))
4673150849Sscottl      (*sc->p2p->p2p_modem)(sc->p2p, sc->status.oper_status==STATUS_UP);
4674150849Sscottl
4675150849Sscottl    /* Notice change in line protocol. */
4676150849Sscottl    sc->status.line_pkg = PKG_P2P;
4677150849Sscottl    switch (sc->ifp->if_type)
4678150849Sscottl      {
4679150849Sscottl      case IFT_PPP:
4680150849Sscottl        sc->status.line_prot = PROT_PPP;
4681150849Sscottl        break;
4682150849Sscottl      case IFT_PTPSERIAL:
4683150849Sscottl        sc->status.line_prot = PROT_C_HDLC;
4684150849Sscottl        break;
4685150849Sscottl      case IFT_FRELAY:
4686150849Sscottl        sc->status.line_prot = PROT_FRM_RLY;
4687150849Sscottl        break;
4688150849Sscottl      default:
4689150849Sscottl        sc->status.line_prot = 0;
4690150849Sscottl        break;
4691150849Sscottl      }
4692150849Sscottl
4693150849Sscottl# elif NSPPP
4694150849Sscottl    /* Notice change in link status. */
4695150849Sscottl    if     ((old_oper_status != STATUS_UP) &&
4696150849Sscottl     (sc->status.oper_status == STATUS_UP))  /* link came up */
4697150849Sscottl      sppp_tls(sc->sppp);
4698150849Sscottl    if     ((old_oper_status == STATUS_UP) &&
4699150849Sscottl     (sc->status.oper_status != STATUS_UP))  /* link went down */
4700150849Sscottl      sppp_tlf(sc->sppp);
4701150849Sscottl
4702150849Sscottl    /* Notice change in line protocol. */
4703150849Sscottl    sc->status.line_pkg = PKG_SPPP;
4704153084Sru#  ifdef __FreeBSD__
4705150849Sscottl    if (sc->sppp->pp_flags & PP_FR)
4706150849Sscottl      sc->status.line_prot = PROT_FRM_RLY;
4707150849Sscottl    else if (sc->ifp->if_flags  & IFF_LINK2)
4708153084Sru#  elif (defined(__NetBSD__) || defined(__OpenBSD__))
4709150849Sscottl    if (sc->sppp->pp_flags & PP_CISCO)
4710150849Sscottl#  endif
4711150849Sscottl      sc->status.line_prot = PROT_C_HDLC;
4712150849Sscottl    else
4713150849Sscottl      sc->status.line_prot = PROT_PPP;
4714150849Sscottl
4715150849Sscottl# else
4716150849Sscottl    /* Suppress compiler warning. */
4717150849Sscottl    if (old_oper_status == STATUS_UP);
4718150849Sscottl# endif
4719150849Sscottl    }
4720150849Sscottl
4721150849Sscottl  /* Copy statistics from sc to ifp. */
4722150849Sscottl  ifp->if_baudrate = sc->status.tx_speed;
4723150849Sscottl  ifp->if_ipackets = cntrs->ipackets;
4724150849Sscottl  ifp->if_opackets = cntrs->opackets;
4725150849Sscottl  ifp->if_ibytes   = cntrs->ibytes;
4726150849Sscottl  ifp->if_obytes   = cntrs->obytes;
4727150849Sscottl  ifp->if_ierrors  = cntrs->ierrors;
4728150849Sscottl  ifp->if_oerrors  = cntrs->oerrors;
4729150849Sscottl  ifp->if_iqdrops  = cntrs->idiscards;
4730150849Sscottl
4731153084Sru# if ((__FreeBSD_version >= 500000) || defined(__OpenBSD__) || defined(__NetBSD__))
4732150849Sscottl  if (sc->status.oper_status == STATUS_UP)
4733150849Sscottl    ifp->if_link_state = LINK_STATE_UP;
4734150849Sscottl  else
4735150849Sscottl    ifp->if_link_state = LINK_STATE_DOWN;
4736150849Sscottl# endif
4737150849Sscottl
4738150849Sscottl  /* Call this procedure again after one second. */
4739199538Sjhb  callout_reset(&sc->callout, hz, lmc_watchdog, ifp);
4740150849Sscottl  }
4741150849Sscottl
4742153084Sru# ifdef __OpenBSD__
4743150849Sscottl
4744150849Sscottl/* Callback from ifmedia. */
4745150849Sscottlstatic int
4746150849Sscottlifmedia_change(struct ifnet *ifp)
4747150849Sscottl  {
4748150849Sscottl  softc_t *sc = IFP2SC(ifp);
4749150849Sscottl  struct config config = sc->config;
4750150849Sscottl  int media = sc->ifm.ifm_media;
4751150849Sscottl  int error;
4752150849Sscottl
4753150849Sscottl  /* ifconfig lmc0 media t1 */
4754150849Sscottl  if      (sc->status.card_type == TLP_CSID_T3)
4755150849Sscottl    {
4756150849Sscottl    if      ((media & IFM_TMASK) == IFM_TDM_T3)
4757150849Sscottl      config.format = CFG_FORMAT_T3CPAR;
4758150849Sscottl    else if ((media & IFM_TMASK) == IFM_TDM_T3_M13)
4759150849Sscottl      config.format = CFG_FORMAT_T3M13;
4760150849Sscottl    }
4761150849Sscottl  else if (sc->status.card_type == TLP_CSID_T1E1)
4762150849Sscottl    {
4763150849Sscottl    if      ((media & IFM_TMASK) == IFM_TDM_T1)
4764150849Sscottl      config.format = CFG_FORMAT_T1ESF;
4765150849Sscottl    else if ((media & IFM_TMASK) == IFM_TDM_T1_AMI)
4766150849Sscottl      config.format = CFG_FORMAT_T1SF;
4767150849Sscottl    else if ((media & IFM_TMASK) == IFM_TDM_E1)
4768150849Sscottl      config.format = CFG_FORMAT_E1NONE;
4769150849Sscottl    else if ((media & IFM_TMASK) == IFM_TDM_E1_G704)
4770150849Sscottl      config.format = CFG_FORMAT_E1FASCRC;
4771150849Sscottl    }
4772150849Sscottl
4773150849Sscottl  /* ifconfig lmc0 mediaopt loopback */
4774150849Sscottl  if (media & IFM_LOOP)
4775150849Sscottl    config.loop_back = CFG_LOOP_TULIP;
4776150849Sscottl  else
4777150849Sscottl    config.loop_back = CFG_LOOP_NONE;
4778150849Sscottl
4779150849Sscottl  /* ifconfig lmc0 mediaopt crc16 */
4780150849Sscottl  if (media & IFM_TDM_HDLC_CRC16)
4781150849Sscottl    config.crc_len = CFG_CRC_16;
4782150849Sscottl  else
4783150849Sscottl    config.crc_len = CFG_CRC_32;
4784150849Sscottl
4785150849Sscottl  /* Set ConFiGuration. */
4786150849Sscottl  config.iohdr.cookie = NGM_LMC_COOKIE;
4787150849Sscottl  error = core_ioctl(sc, LMCIOCSCFG, (caddr_t)&config);
4788150849Sscottl
4789150849Sscottl  return error;
4790150849Sscottl  }
4791150849Sscottl
4792150849Sscottl/* Callback from ifmedia. */
4793150849Sscottlstatic void
4794150849Sscottlifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr)
4795150849Sscottl  {
4796150849Sscottl  softc_t *sc = IFP2SC(ifp);
4797150849Sscottl
4798150849Sscottl  /* ifconfig wants to know if the hardware link is up. */
4799150849Sscottl  ifmr->ifm_status = IFM_AVALID;
4800150849Sscottl  if (sc->status.oper_status == STATUS_UP)
4801150849Sscottl    ifmr->ifm_status |= IFM_ACTIVE;
4802150849Sscottl
4803150849Sscottl  ifmr->ifm_active = sc->ifm.ifm_cur->ifm_media;
4804150849Sscottl
4805150849Sscottl  if (sc->config.loop_back != CFG_LOOP_NONE)
4806150849Sscottl    ifmr->ifm_active |= IFM_LOOP;
4807150849Sscottl
4808150849Sscottl  if (sc->config.crc_len == CFG_CRC_16)
4809150849Sscottl    ifmr->ifm_active |= IFM_TDM_HDLC_CRC16;
4810150849Sscottl  }
4811150849Sscottl
4812150849Sscottl# endif  /* __OpenBSD__ */
4813150849Sscottl
4814150849Sscottlstatic void
4815150849Sscottlsetup_ifnet(struct ifnet *ifp)
4816150849Sscottl  {
4817150849Sscottl  softc_t *sc = ifp->if_softc;
4818150849Sscottl
4819150849Sscottl  /* Initialize the generic network interface. */
4820150849Sscottl  /* Note similarity to linux's setup_netdev(). */
4821150849Sscottl  ifp->if_flags    = IFF_POINTOPOINT;
4822150849Sscottl  ifp->if_flags   |= IFF_RUNNING;
4823180304Srwatson  ifp->if_ioctl    = lmc_ifnet_ioctl;
4824180304Srwatson  ifp->if_start    = lmc_ifnet_start;	/* sppp changes this */
4825180304Srwatson  ifp->if_output   = lmc_raw_output;	/* sppp & p2p change this */
4826180304Srwatson  ifp->if_input    = lmc_raw_input;
4827150849Sscottl  ifp->if_mtu      = MAX_DESC_LEN;	/* sppp & p2p change this */
4828150849Sscottl  ifp->if_type     = IFT_PTPSERIAL;	/* p2p changes this */
4829150849Sscottl
4830153110Sru# if (defined(__FreeBSD__) && defined(DEVICE_POLLING))
4831150849Sscottl  ifp->if_capabilities |= IFCAP_POLLING;
4832193096Sattilio  ifp->if_capenable    |= IFCAP_POLLING_NOCOUNT;
4833150849Sscottl# if (__FreeBSD_version < 500000)
4834150849Sscottl  ifp->if_capenable    |= IFCAP_POLLING;
4835150849Sscottl# endif
4836150849Sscottl# endif
4837150849Sscottl
4838150849Sscottl  /* Every OS does it differently! */
4839153084Sru# if (defined(__FreeBSD__) && (__FreeBSD_version < 502000))
4840150849Sscottl  (const char *)ifp->if_name = device_get_name(sc->dev);
4841150849Sscottl  ifp->if_unit  = device_get_unit(sc->dev);
4842150849Sscottl# elif (__FreeBSD_version >= 502000)
4843160375Sbrooks  if_initname(ifp, device_get_name(sc->dev), device_get_unit(sc->dev));
4844153084Sru# elif defined(__NetBSD__)
4845150849Sscottl  strcpy(ifp->if_xname, sc->dev.dv_xname);
4846201799Strasz# elif defined(__OpenBSD__)
4847150849Sscottl  bcopy(sc->dev.dv_xname, ifp->if_xname, IFNAMSIZ);
4848153084Sru# elif defined(__bsdi__)
4849150849Sscottl  ifp->if_name  = sc->dev.dv_cfdata->cf_driver->cd_name;
4850150849Sscottl  ifp->if_unit  = sc->dev.dv_unit;
4851150849Sscottl# endif
4852150849Sscottl  }
4853150849Sscottl
4854150849Sscottlstatic int
4855180304Srwatsonlmc_ifnet_attach(softc_t *sc)
4856150849Sscottl  {
4857150849Sscottl# if (__FreeBSD_version >= 600000)
4858150849Sscottl  sc->ifp  = if_alloc(NSPPP ? IFT_PPP : IFT_OTHER);
4859150849Sscottl  if (sc->ifp == NULL) return ENOMEM;
4860150849Sscottl# endif
4861150849Sscottl# if NSPPP
4862150849Sscottl#  if (__FreeBSD_version >= 600000)
4863150849Sscottl  sc->sppp = sc->ifp->if_l2com;
4864150849Sscottl#  else
4865150849Sscottl  sc->ifp  = &sc->spppcom.pp_if;
4866150849Sscottl  sc->sppp = &sc->spppcom;
4867150849Sscottl#  endif
4868150849Sscottl# elif P2P
4869150849Sscottl  sc->ifp  = &sc->p2pcom.p2p_if;
4870150849Sscottl  sc->p2p  = &sc->p2pcom;
4871150849Sscottl# elif (__FreeBSD_version < 600000)
4872150849Sscottl  sc->ifp  = &sc->ifnet;
4873150849Sscottl# endif
4874150849Sscottl
4875150849Sscottl  /* Initialize the network interface struct. */
4876150849Sscottl  sc->ifp->if_softc = sc;
4877150849Sscottl  setup_ifnet(sc->ifp);
4878150849Sscottl
4879150849Sscottl  /* ALTQ output queue initialization. */
4880150849Sscottl  IFQ_SET_MAXLEN(&sc->ifp->if_snd, SNDQ_MAXLEN);
4881150849Sscottl  IFQ_SET_READY(&sc->ifp->if_snd);
4882150849Sscottl
4883150849Sscottl  /* Attach to the ifnet kernel interface. */
4884150849Sscottl  if_attach(sc->ifp);
4885150849Sscottl
4886153084Sru# if ((defined(__NetBSD__) && __NetBSD_Version__ >= 106000000) || \
4887153084Sru     (defined(__OpenBSD__) && OpenBSD >= 200211))
4888150849Sscottl  if_alloc_sadl(sc->ifp);
4889150849Sscottl# endif
4890150849Sscottl
4891150849Sscottl  /* Attach Berkeley Packet Filter. */
4892150849Sscottl  LMC_BPF_ATTACH(DLT_RAW, 0);
4893150849Sscottl
4894153084Sru# ifdef __OpenBSD__
4895150849Sscottl  /* Initialize ifmedia mechanism. */
4896150849Sscottl  ifmedia_init(&sc->ifm, IFM_OMASK | IFM_GMASK | IFM_IMASK,
4897150849Sscottl   ifmedia_change, ifmedia_status);
4898150849Sscottl  if       (sc->status.card_type == TLP_CSID_T3)
4899150849Sscottl    {
4900150849Sscottl    ifmedia_add(&sc->ifm, IFM_TDM | IFM_TDM_T3, 0, NULL);
4901150849Sscottl    ifmedia_add(&sc->ifm, IFM_TDM | IFM_TDM_T3_M13, 0, NULL);
4902150849Sscottl    ifmedia_set(&sc->ifm, IFM_TDM | IFM_TDM_T3);
4903150849Sscottl    }
4904150849Sscottl  else if  (sc->status.card_type == TLP_CSID_T1E1)
4905150849Sscottl    {
4906150849Sscottl    ifmedia_add(&sc->ifm, IFM_TDM | IFM_TDM_T1, 0, NULL);
4907150849Sscottl    ifmedia_add(&sc->ifm, IFM_TDM | IFM_TDM_T1_AMI, 0, NULL);
4908150849Sscottl    ifmedia_add(&sc->ifm, IFM_TDM | IFM_TDM_E1, 0, NULL);
4909150849Sscottl    ifmedia_add(&sc->ifm, IFM_TDM | IFM_TDM_E1_G704, 0, NULL);
4910150849Sscottl    ifmedia_set(&sc->ifm, IFM_TDM | IFM_TDM_T1);
4911150849Sscottl    }
4912150849Sscottl  else if ((sc->status.card_type == TLP_CSID_HSSI) ||
4913150849Sscottl           (sc->status.card_type == TLP_CSID_SSI))
4914150849Sscottl    {
4915150849Sscottl    ifmedia_add(&sc->ifm, IFM_TDM | IFM_NONE, 0, NULL);
4916150849Sscottl    ifmedia_set(&sc->ifm, IFM_TDM | IFM_NONE);
4917150849Sscottl    }
4918150849Sscottl# endif  /* __OpenBSD__ */
4919150849Sscottl
4920199538Sjhb  callout_reset(&sc->callout, hz, lmc_watchdog, sc);
4921199538Sjhb
4922150849Sscottl  return 0;
4923150849Sscottl  }
4924150849Sscottl
4925150849Sscottlstatic void
4926180304Srwatsonlmc_ifnet_detach(softc_t *sc)
4927150849Sscottl  {
4928153084Sru# ifdef __OpenBSD__
4929150849Sscottl  ifmedia_delete_instance(&sc->ifm, IFM_INST_ANY);
4930150849Sscottl# endif
4931150849Sscottl
4932153110Sru# if (defined(__FreeBSD__) && defined(DEVICE_POLLING))
4933150849Sscottl  if (sc->ifp->if_capenable & IFCAP_POLLING)
4934150849Sscottl    ether_poll_deregister(sc->ifp);
4935150849Sscottl# endif
4936150849Sscottl
4937150849Sscottl  /* Detach Berkeley Packet Filter. */
4938150849Sscottl  LMC_BPF_DETACH;
4939150849Sscottl
4940153084Sru# if ((defined(__NetBSD__) && __NetBSD_Version__ >= 106000000) || \
4941153084Sru     (defined(__OpenBSD__) && OpenBSD >= 200211))
4942150849Sscottl  if_free_sadl(sc->ifp);
4943150849Sscottl# endif
4944150849Sscottl
4945150849Sscottl  /* Detach from the ifnet kernel interface. */
4946150849Sscottl  if_detach(sc->ifp);
4947150849Sscottl
4948227459Sbrooks# if (defined(__FreeBSD__) && __FreeBSD_version >= 800082)
4949227459Sbrooks  if_free(sc->ifp);
4950227459Sbrooks# elif (defined(__FreeBSD__) && __FreeBSD_version >= 600000)
4951150849Sscottl  if_free_type(sc->ifp, NSPPP ? IFT_PPP : IFT_OTHER);
4952150849Sscottl# endif
4953150849Sscottl  }
4954150849Sscottl
4955150849Sscottl#endif  /* IFNET */
4956150849Sscottl
4957150849Sscottl#if NETGRAPH
4958150849Sscottl
4959150849Sscottl/* Netgraph changed significantly between FreeBSD-4 and -5. */
4960150849Sscottl/* These are backward compatibility hacks for FreeBSD-4. */
4961150849Sscottl# if (__FreeBSD_version >= 500000)
4962150849Sscottl/* These next two macros should be added to netgraph */
4963150849Sscottl#  define NG_TYPE_REF(type) atomic_add_int(&(type)->refs, 1)
4964150849Sscottl#  define NG_TYPE_UNREF(type)	\
4965150849Sscottldo {				\
4966150849Sscottl  if ((type)->refs == 1)	\
4967150849Sscottl    ng_rmtype(type);		\
4968150849Sscottl  else				\
4969150849Sscottl    atomic_subtract_int(&(type)->refs, 1); \
4970150849Sscottl   } while (0)
4971150849Sscottl# else /* FreeBSD-4 */
4972150849Sscottl#  define NGI_GET_MSG(item, msg)	/* nothing */
4973150849Sscottl#  define NG_HOOK_FORCE_QUEUE(hook)	/* nothing */
4974150849Sscottl#  define NG_TYPE_REF(type) atomic_add_int(&(type)->refs, 1)
4975150849Sscottl#  define NG_TYPE_UNREF(type)	\
4976150849Sscottldo {				\
4977150849Sscottl  if ((type)->refs == 1)	\
4978150849Sscottl    LIST_REMOVE(type, types);	\
4979150849Sscottl  else				\
4980150849Sscottl    atomic_subtract_int(&(type)->refs, 1); \
4981150849Sscottl   } while (0)
4982150849Sscottl# endif
4983150849Sscottl
4984150849Sscottl/* It is an error to construct new copies of this Netgraph node. */
4985150849Sscottl/* All instances are constructed by ng_attach and are persistent. */
4986150849Sscottl# if (__FreeBSD_version >= 500000)
4987150849Sscottlstatic int ng_constructor(node_p  node) { return EINVAL; }
4988150849Sscottl# else /* FreeBSD-4 */
4989150849Sscottlstatic int ng_constructor(node_p *node) { return EINVAL; }
4990150849Sscottl# endif
4991150849Sscottl
4992150849Sscottl/* Incoming Netgraph control message. */
4993150849Sscottl# if (__FreeBSD_version >= 500000)
4994150849Sscottlstatic int
4995150849Sscottlng_rcvmsg(node_p node, item_p item, hook_p lasthook)
4996150849Sscottl  {
4997150849Sscottl  struct ng_mesg *msg;
4998150849Sscottl# else /* FreeBSD-4 */
4999150849Sscottlstatic int
5000150849Sscottlng_rcvmsg(node_p node, struct ng_mesg *msg,
5001150849Sscottl const char *retaddr,  struct ng_mesg **rptr)
5002150849Sscottl  {
5003150849Sscottl# endif
5004150849Sscottl  struct ng_mesg *resp = NULL;
5005150849Sscottl  softc_t *sc = NG_NODE_PRIVATE(node);
5006150849Sscottl  int error = 0;
5007150849Sscottl
5008150849Sscottl  NGI_GET_MSG(item, msg);
5009150849Sscottl  if (msg->header.typecookie == NGM_LMC_COOKIE)
5010150849Sscottl    {
5011150849Sscottl    switch (msg->header.cmd)
5012150849Sscottl      {
5013150849Sscottl      case LMCIOCGSTAT:
5014150849Sscottl      case LMCIOCGCFG:
5015150849Sscottl      case LMCIOCSCFG:
5016150849Sscottl      case LMCIOCREAD:
5017150849Sscottl      case LMCIOCWRITE:
5018150849Sscottl      case LMCIOCTL:
5019150849Sscottl        {
5020150849Sscottl        /* Call the core ioctl procedure. */
5021150849Sscottl        error = core_ioctl(sc, msg->header.cmd, msg->data);
5022150849Sscottl        if ((msg->header.cmd & IOC_OUT) != 0)
5023150849Sscottl          { /* synchronous response */
5024150849Sscottl          NG_MKRESPONSE(resp, msg, sizeof(struct ng_mesg) +
5025150849Sscottl           IOCPARM_LEN(msg->header.cmd), M_NOWAIT);
5026150849Sscottl          if (resp == NULL)
5027150849Sscottl            error = ENOMEM;
5028150849Sscottl          else
5029150849Sscottl            memcpy(resp->data, msg->data, IOCPARM_LEN(msg->header.cmd));
5030150849Sscottl          }
5031150849Sscottl        break;
5032150849Sscottl        }
5033150849Sscottl      default:
5034150849Sscottl        error = EINVAL;
5035150849Sscottl        break;
5036150849Sscottl      }
5037150849Sscottl    }
5038150849Sscottl  else if ((msg->header.typecookie == NGM_GENERIC_COOKIE) &&
5039150849Sscottl           (msg->header.cmd == NGM_TEXT_STATUS))
5040150849Sscottl    {  /* synchronous response */
5041150849Sscottl    NG_MKRESPONSE(resp, msg, sizeof(struct ng_mesg) +
5042150849Sscottl     NG_TEXTRESPONSE, M_NOWAIT);
5043150849Sscottl    if (resp == NULL)
5044150849Sscottl      error = ENOMEM;
5045150849Sscottl    else
5046150849Sscottl      {
5047150849Sscottl      char *s = resp->data;
5048150849Sscottl      sprintf(s, "Card type = <%s>\n"
5049150849Sscottl       "This driver considers the link to be %s.\n"
5050150849Sscottl       "Use lmcconfig to configure this interface.\n",
5051150849Sscottl       sc->dev_desc, (sc->status.oper_status==STATUS_UP) ? "UP" : "DOWN");
5052150849Sscottl      resp->header.arglen = strlen(s) +1;
5053150849Sscottl      }
5054150849Sscottl    }
5055150849Sscottl  else
5056150849Sscottl/* Netgraph should be able to read and write these
5057150849Sscottl *  parameters with text-format control messages:
5058150849Sscottl *  SSI	     HSSI     T1E1     T3
5059150849Sscottl *  crc	     crc      crc      crc
5060150849Sscottl *  loop     loop     loop     loop
5061150849Sscottl *           clksrc   clksrc
5062150849Sscottl *  dte	     dte      format   format
5063150849Sscottl *  synth    synth    cablen   cablen
5064150849Sscottl *  cable             timeslot scram
5065150849Sscottl *                    gain
5066150849Sscottl *                    pulse
5067150849Sscottl *                    lbo
5068150849Sscottl * Someday I'll implement this...
5069150849Sscottl */
5070150849Sscottl    error = EINVAL;
5071150849Sscottl
5072150849Sscottl  /* Handle synchronous response. */
5073150849Sscottl# if (__FreeBSD_version >= 500000)
5074150849Sscottl  NG_RESPOND_MSG(error, node, item, resp);
5075150849Sscottl  NG_FREE_MSG(msg);
5076150849Sscottl# else /* FreeBSD-4 */
5077150849Sscottl  if (rptr != NULL)
5078150849Sscottl    *rptr = resp;
5079150849Sscottl  else if (resp != NULL)
5080184205Sdes    free(resp, M_NETGRAPH);
5081184205Sdes  free(msg, M_NETGRAPH);
5082150849Sscottl# endif
5083150849Sscottl
5084150849Sscottl  return error;
5085150849Sscottl  }
5086150849Sscottl
5087150849Sscottl/* This is a persistent netgraph node. */
5088150849Sscottlstatic int
5089150849Sscottlng_shutdown(node_p node)
5090150849Sscottl  {
5091150849Sscottl# if (__FreeBSD_version >= 500000)
5092150849Sscottl  /* unless told to really die, bounce back to life */
5093150849Sscottl  if ((node->nd_flags & NG_REALLY_DIE)==0)
5094150849Sscottl    node->nd_flags &= ~NG_INVALID; /* bounce back to life */
5095150849Sscottl# else /* FreeBSD-4 */
5096150849Sscottl  ng_cutlinks(node);
5097150849Sscottl  node->flags &= ~NG_INVALID;  /* bounce back to life */
5098150849Sscottl# endif
5099150849Sscottl
5100150849Sscottl  return 0;
5101150849Sscottl  }
5102150849Sscottl
5103150849Sscottl/* ng_disconnect is the opposite of this procedure. */
5104150849Sscottlstatic int
5105150849Sscottlng_newhook(node_p node, hook_p hook, const char *name)
5106150849Sscottl  {
5107150849Sscottl  softc_t *sc = NG_NODE_PRIVATE(node);
5108150849Sscottl
5109150849Sscottl  /* Hook name must be 'rawdata'. */
5110150849Sscottl  if (strncmp(name, "rawdata", 7) != 0)	return EINVAL;
5111150849Sscottl
5112150849Sscottl  /* Is our hook connected? */
5113150849Sscottl  if (sc->ng_hook != NULL) return EBUSY;
5114150849Sscottl
5115150849Sscottl  /* Accept the hook. */
5116150849Sscottl  sc->ng_hook = hook;
5117150849Sscottl
5118150849Sscottl  return 0;
5119150849Sscottl  }
5120150849Sscottl
5121150849Sscottl/* Both ends have accepted their hooks and the links have been made. */
5122150849Sscottl/* This is the last chance to reject the connection request. */
5123150849Sscottlstatic int
5124150849Sscottlng_connect(hook_p hook)
5125150849Sscottl  {
5126150849Sscottl  /* Probably not at splnet, force outward queueing. (huh?) */
5127150849Sscottl  NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
5128150849Sscottl  return 0; /* always accept */
5129150849Sscottl  }
5130150849Sscottl
5131150849Sscottl/* Receive data in mbufs from another Netgraph node. */
5132150849Sscottl/* Transmit an mbuf-chain on the communication link. */
5133180304Srwatson/* This procedure is very similar to lmc_raw_output(). */
5134150849Sscottl/* Called from a syscall (user context; no spinlocks). */
5135150849Sscottl# if (__FreeBSD_version >= 500000)
5136150849Sscottlstatic int
5137150849Sscottlng_rcvdata(hook_p hook, item_p item)
5138150849Sscottl  {
5139150849Sscottl  softc_t *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
5140150849Sscottl  int error = 0;
5141150849Sscottl  struct mbuf *m;
5142150849Sscottl  meta_p meta = NULL;
5143150849Sscottl
5144150849Sscottl  NGI_GET_M(item, m);
5145150849Sscottl  NGI_GET_META(item, meta);
5146150849Sscottl  NG_FREE_ITEM(item);
5147150849Sscottl# else /* FreeBSD-4 */
5148150849Sscottlstatic int
5149150849Sscottlng_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
5150150849Sscottl  {
5151150849Sscottl  softc_t *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
5152150849Sscottl  int error = 0;
5153150849Sscottl# endif
5154150849Sscottl
5155150849Sscottl  /* This macro must not store into meta! */
5156150849Sscottl  NG_FREE_META(meta);
5157150849Sscottl
5158150849Sscottl  /* Fail if the link is down. */
5159150849Sscottl  if (sc->status.oper_status  != STATUS_UP)
5160150849Sscottl    {
5161150849Sscottl    m_freem(m);
5162150849Sscottl    sc->status.cntrs.odiscards++;
5163150849Sscottl    if (DRIVER_DEBUG)
5164150849Sscottl      printf("%s: ng_rcvdata: tx pkt discarded: link down\n", NAME_UNIT);
5165150849Sscottl    return ENETDOWN;
5166150849Sscottl    }
5167150849Sscottl
5168150849Sscottl  /* ng_rcvdata() ENQUEUEs in a syscall or softirq. */
5169150849Sscottl  /* txintr_setup() DEQUEUEs in a hard interrupt. */
5170150849Sscottl  /* Some BSD QUEUE routines are not interrupt-safe. */
5171150849Sscottl  {
5172150849Sscottl  DISABLE_INTR;
5173150849Sscottl# if (__FreeBSD_version >= 503000)
5174150849Sscottl  if (meta==NULL)
5175150849Sscottl    IFQ_ENQUEUE(&sc->ng_sndq, m, error);
5176150849Sscottl  else
5177150849Sscottl    IFQ_ENQUEUE(&sc->ng_fastq, m, error);
5178150849Sscottl# else
5179150849Sscottl  if (meta==NULL)
5180150849Sscottl    IFQ_ENQUEUE(&sc->ng_sndq, m, NULL, error);
5181150849Sscottl  else
5182150849Sscottl    IFQ_ENQUEUE(&sc->ng_fastq, m, NULL, error);
5183150849Sscottl# endif
5184150849Sscottl  ENABLE_INTR;
5185150849Sscottl  }
5186150849Sscottl
5187150849Sscottl  if (error==0)
5188150849Sscottl    user_interrupt(sc, 0); /* start the transmitter */
5189150849Sscottl  else
5190150849Sscottl    {
5191150849Sscottl    m_freem(m);
5192150849Sscottl    sc->status.cntrs.odiscards++;
5193150849Sscottl    if (DRIVER_DEBUG)
5194150849Sscottl      printf("%s: ng_rcvdata: IFQ_ENQUEUE() failed; error %d\n",
5195150849Sscottl       NAME_UNIT, error);
5196150849Sscottl    }
5197150849Sscottl
5198150849Sscottl  return error;
5199150849Sscottl  }
5200150849Sscottl
5201150849Sscottl/* ng_newhook is the opposite of this procedure, not */
5202150849Sscottl/*  ng_connect, as you might expect from the names. */
5203150849Sscottlstatic int
5204150849Sscottlng_disconnect(hook_p hook)
5205150849Sscottl  {
5206150849Sscottl  softc_t *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
5207150849Sscottl
5208150849Sscottl  /* Disconnect the hook. */
5209150849Sscottl  sc->ng_hook = NULL;
5210150849Sscottl
5211150849Sscottl  return 0;
5212150849Sscottl  }
5213150849Sscottl
5214150849Sscottlstatic
5215150849Sscottlstruct ng_type ng_type =
5216150849Sscottl  {
5217150849Sscottl  .version	= NG_ABI_VERSION,
5218150849Sscottl  .name		= NG_LMC_NODE_TYPE,
5219150849Sscottl  .mod_event	= NULL,
5220150849Sscottl  .constructor	= ng_constructor,
5221150849Sscottl  .rcvmsg	= ng_rcvmsg,
5222150849Sscottl# if (__FreeBSD_version >=503000)
5223150849Sscottl  .close	= NULL,
5224150849Sscottl# endif
5225150849Sscottl  .shutdown	= ng_shutdown,
5226150849Sscottl  .newhook	= ng_newhook,
5227150849Sscottl  .findhook	= NULL,
5228150849Sscottl  .connect	= ng_connect,
5229150849Sscottl  .rcvdata	= ng_rcvdata,
5230153084Sru# if (defined(__FreeBSD__) && (__FreeBSD_version < 500000))
5231150849Sscottl  .rcvdataq	= ng_rcvdata,
5232150849Sscottl# endif
5233150849Sscottl  .disconnect	= ng_disconnect,
5234150849Sscottl  };
5235150849Sscottl
5236150849Sscottl# if (IFNET == 0)
5237150849Sscottl/* Called from a softirq once a second. */
5238150849Sscottlstatic void
5239150849Sscottlng_watchdog(void *arg)
5240150849Sscottl  {
5241150849Sscottl  softc_t *sc = arg;
5242150849Sscottl
5243150849Sscottl  /* Call the core watchdog procedure. */
5244150849Sscottl  core_watchdog(sc);
5245150849Sscottl
5246150849Sscottl  /* Set line protocol and package status. */
5247150849Sscottl  sc->status.line_pkg  = PKG_NG;
5248150849Sscottl  sc->status.line_prot = 0;
5249150849Sscottl
5250150849Sscottl  /* Call this procedure again after one second. */
5251199538Sjhb  callout_reset(&sc->callout, hz, ng_watchdog, sc);
5252150849Sscottl  }
5253150849Sscottl# endif
5254150849Sscottl
5255150849Sscottl/* Attach to the Netgraph kernel interface (/sys/netgraph).
5256150849Sscottl * It is called once for each physical card during device attach.
5257150849Sscottl * This is effectively ng_constructor.
5258150849Sscottl */
5259150849Sscottlstatic int
5260150849Sscottlng_attach(softc_t *sc)
5261150849Sscottl  {
5262150849Sscottl  int error;
5263150849Sscottl
5264150849Sscottl  /* If this node type is not known to Netgraph then register it. */
5265150849Sscottl  if (ng_type.refs == 0) /* or: if (ng_findtype(&ng_type) == NULL) */
5266150849Sscottl    {
5267150849Sscottl    if ((error = ng_newtype(&ng_type)))
5268150849Sscottl      {
5269150849Sscottl      printf("%s: ng_newtype() failed; error %d\n", NAME_UNIT, error);
5270150849Sscottl      return error;
5271150849Sscottl      }
5272150849Sscottl    }
5273150849Sscottl  else
5274150849Sscottl    NG_TYPE_REF(&ng_type);
5275150849Sscottl
5276150849Sscottl  /* Call the superclass node constructor. */
5277150849Sscottl  if ((error = ng_make_node_common(&ng_type, &sc->ng_node)))
5278150849Sscottl    {
5279150849Sscottl    NG_TYPE_UNREF(&ng_type);
5280150849Sscottl    printf("%s: ng_make_node_common() failed; error %d\n", NAME_UNIT, error);
5281150849Sscottl    return error;
5282150849Sscottl    }
5283150849Sscottl
5284150849Sscottl  /* Associate a name with this netgraph node. */
5285150849Sscottl  if ((error = ng_name_node(sc->ng_node, NAME_UNIT)))
5286150849Sscottl    {
5287150849Sscottl    NG_NODE_UNREF(sc->ng_node);
5288150849Sscottl    NG_TYPE_UNREF(&ng_type);
5289150849Sscottl    printf("%s: ng_name_node() failed; error %d\n", NAME_UNIT, error);
5290150849Sscottl    return error;
5291150849Sscottl    }
5292150849Sscottl
5293150849Sscottl# if (__FreeBSD_version >= 500000)
5294150849Sscottl  /* Initialize the send queue mutexes. */
5295150849Sscottl  mtx_init(&sc->ng_sndq.ifq_mtx,  NAME_UNIT, "sndq",  MTX_DEF);
5296150849Sscottl  mtx_init(&sc->ng_fastq.ifq_mtx, NAME_UNIT, "fastq", MTX_DEF);
5297150849Sscottl# endif
5298150849Sscottl
5299150849Sscottl  /* Put a backpointer to the softc in the netgraph node. */
5300150849Sscottl  NG_NODE_SET_PRIVATE(sc->ng_node, sc);
5301150849Sscottl
5302150849Sscottl  /* ALTQ output queue initialization. */
5303150849Sscottl  IFQ_SET_MAXLEN(&sc->ng_fastq, SNDQ_MAXLEN);
5304150849Sscottl  IFQ_SET_READY(&sc->ng_fastq);
5305150849Sscottl  IFQ_SET_MAXLEN(&sc->ng_sndq,  SNDQ_MAXLEN);
5306150849Sscottl  IFQ_SET_READY(&sc->ng_sndq);
5307150849Sscottl
5308150849Sscottl# if (IFNET == 0)
5309150849Sscottl  /* Arrange to call ng_watchdog() once a second. */
5310199538Sjhb  callout_reset(&sc->callout, hz, ng_watchdog, sc);
5311150849Sscottl# endif
5312150849Sscottl
5313150849Sscottl  return 0;
5314150849Sscottl  }
5315150849Sscottl
5316150849Sscottlstatic void
5317150849Sscottlng_detach(softc_t *sc)
5318150849Sscottl  {
5319199538Sjhb  callout_drain(&sc->callout);
5320150849Sscottl# if (__FreeBSD_version >= 500000)
5321150849Sscottl  mtx_destroy(&sc->ng_sndq.ifq_mtx);
5322150849Sscottl  mtx_destroy(&sc->ng_fastq.ifq_mtx);
5323150849Sscottl  ng_rmnode_self(sc->ng_node); /* free hook */
5324150849Sscottl  NG_NODE_UNREF(sc->ng_node);  /* free node */
5325150849Sscottl  NG_TYPE_UNREF(&ng_type);
5326150849Sscottl# else /* FreeBSD-4 */
5327150849Sscottl  ng_unname(sc->ng_node);      /* free name */
5328150849Sscottl  ng_cutlinks(sc->ng_node);    /* free hook */
5329150849Sscottl  NG_NODE_UNREF(sc->ng_node);  /* free node */
5330150849Sscottl  NG_TYPE_UNREF(&ng_type);
5331150849Sscottl# endif
5332150849Sscottl  }
5333150849Sscottl
5334150849Sscottl#endif /* NETGRAPH */
5335150849Sscottl
5336150849Sscottl/* The next few procedures initialize the card. */
5337150849Sscottl
5338150849Sscottl/* Returns 0 on success; error code on failure. */
5339150849Sscottlstatic int
5340150849Sscottlstartup_card(softc_t *sc)
5341150849Sscottl  {
5342150849Sscottl  int num_rx_descs, error = 0;
5343150849Sscottl  u_int32_t tlp_bus_pbl, tlp_bus_cal, tlp_op_tr;
5344150849Sscottl  u_int32_t tlp_cfdd, tlp_cfcs;
5345150849Sscottl  u_int32_t tlp_cflt, tlp_csid, tlp_cfit;
5346150849Sscottl
5347150849Sscottl  /* Make sure the COMMAND bits are reasonable. */
5348150849Sscottl  tlp_cfcs = READ_PCI_CFG(sc, TLP_CFCS);
5349150849Sscottl  tlp_cfcs &= ~TLP_CFCS_MWI_ENABLE;
5350150849Sscottl  tlp_cfcs |=  TLP_CFCS_BUS_MASTER;
5351150849Sscottl  tlp_cfcs |=  TLP_CFCS_MEM_ENABLE;
5352150849Sscottl  tlp_cfcs |=  TLP_CFCS_IO_ENABLE;
5353150849Sscottl  tlp_cfcs |=  TLP_CFCS_PAR_ERROR;
5354150849Sscottl  tlp_cfcs |=  TLP_CFCS_SYS_ERROR;
5355150849Sscottl  WRITE_PCI_CFG(sc, TLP_CFCS, tlp_cfcs);
5356150849Sscottl
5357150849Sscottl  /* Set the LATENCY TIMER to the recommended value, */
5358150849Sscottl  /*  and make sure the CACHE LINE SIZE is reasonable. */
5359150849Sscottl  tlp_cfit = READ_PCI_CFG(sc, TLP_CFIT);
5360150849Sscottl  tlp_cflt = READ_PCI_CFG(sc, TLP_CFLT);
5361150849Sscottl  tlp_cflt &= ~TLP_CFLT_LATENCY;
5362150849Sscottl  tlp_cflt |= (tlp_cfit & TLP_CFIT_MAX_LAT)>>16;
5363150849Sscottl  /* "prgmbl burst length" and "cache alignment" used below. */
5364150849Sscottl  switch(tlp_cflt & TLP_CFLT_CACHE)
5365150849Sscottl    {
5366150849Sscottl    case 8: /* 8 bytes per cache line */
5367150849Sscottl      { tlp_bus_pbl = 32; tlp_bus_cal = 1; break; }
5368150849Sscottl    case 16:
5369150849Sscottl      { tlp_bus_pbl = 32; tlp_bus_cal = 2; break; }
5370150849Sscottl    case 32:
5371150849Sscottl      { tlp_bus_pbl = 32; tlp_bus_cal = 3; break; }
5372150849Sscottl    default:
5373150849Sscottl      {
5374150849Sscottl      tlp_bus_pbl = 32; tlp_bus_cal = 1;
5375150849Sscottl      tlp_cflt &= ~TLP_CFLT_CACHE;
5376150849Sscottl      tlp_cflt |= 8;
5377150849Sscottl      break;
5378150849Sscottl      }
5379150849Sscottl    }
5380150849Sscottl  WRITE_PCI_CFG(sc, TLP_CFLT, tlp_cflt);
5381150849Sscottl
5382150849Sscottl  /* Make sure SNOOZE and SLEEP modes are disabled. */
5383150849Sscottl  tlp_cfdd = READ_PCI_CFG(sc, TLP_CFDD);
5384150849Sscottl  tlp_cfdd &= ~TLP_CFDD_SLEEP;
5385150849Sscottl  tlp_cfdd &= ~TLP_CFDD_SNOOZE;
5386150849Sscottl  WRITE_PCI_CFG(sc, TLP_CFDD, tlp_cfdd);
5387150849Sscottl  DELAY(11*1000); /* Tulip wakes up in 10 ms max */
5388150849Sscottl
5389150849Sscottl  /* Software Reset the Tulip chip; stops DMA and Interrupts. */
5390150849Sscottl  /* This does not change the PCI config regs just set above. */
5391150849Sscottl  WRITE_CSR(TLP_BUS_MODE, TLP_BUS_RESET); /* self-clearing */
5392150849Sscottl  DELAY(5);  /* Tulip is dead for 50 PCI cycles after reset. */
5393150849Sscottl
5394150849Sscottl  /* Reset the Xilinx Field Programmable Gate Array. */
5395150849Sscottl  reset_xilinx(sc); /* side effect: turns on all four LEDs */
5396150849Sscottl
5397150849Sscottl  /* Configure card-specific stuff (framers, line interfaces, etc.). */
5398150849Sscottl  sc->card->config(sc);
5399150849Sscottl
5400150849Sscottl  /* Initializing cards can glitch clocks and upset fifos. */
5401150849Sscottl  /* Reset the FIFOs between the Tulip and Xilinx chips. */
5402150849Sscottl  set_mii16_bits(sc, MII16_FIFO);
5403150849Sscottl  clr_mii16_bits(sc, MII16_FIFO);
5404150849Sscottl
5405150849Sscottl  /* Initialize the PCI busmode register. */
5406150849Sscottl  /* The PCI bus cycle type "Memory Write and Invalidate" does NOT */
5407150849Sscottl  /*  work cleanly in any version of the 21140A, so don't enable it! */
5408150849Sscottl  WRITE_CSR(TLP_BUS_MODE,
5409150849Sscottl        (tlp_bus_cal ? TLP_BUS_READ_LINE : 0) |
5410150849Sscottl        (tlp_bus_cal ? TLP_BUS_READ_MULT : 0) |
5411150849Sscottl        (tlp_bus_pbl<<TLP_BUS_PBL_SHIFT) |
5412150849Sscottl        (tlp_bus_cal<<TLP_BUS_CAL_SHIFT) |
5413150849Sscottl   ((BYTE_ORDER == BIG_ENDIAN) ? TLP_BUS_DESC_BIGEND : 0) |
5414150849Sscottl   ((BYTE_ORDER == BIG_ENDIAN) ? TLP_BUS_DATA_BIGEND : 0) |
5415150849Sscottl                TLP_BUS_DSL_VAL |
5416150849Sscottl                TLP_BUS_ARB);
5417150849Sscottl
5418150849Sscottl  /* Pick number of RX descriptors and TX fifo threshold. */
5419150849Sscottl  /* tx_threshold in bytes: 0=128, 1=256, 2=512, 3=1024 */
5420150849Sscottl  tlp_csid = READ_PCI_CFG(sc, TLP_CSID);
5421150849Sscottl  switch(tlp_csid)
5422150849Sscottl    {
5423150849Sscottl    case TLP_CSID_HSSI:		/* 52 Mb/s */
5424150849Sscottl    case TLP_CSID_HSSIc:	/* 52 Mb/s */
5425150849Sscottl    case TLP_CSID_T3:		/* 45 Mb/s */
5426150849Sscottl      { num_rx_descs = 48; tlp_op_tr = 2; break; }
5427150849Sscottl    case TLP_CSID_SSI:		/* 10 Mb/s */
5428150849Sscottl      { num_rx_descs = 32; tlp_op_tr = 1; break; }
5429150849Sscottl    case TLP_CSID_T1E1:		/*  2 Mb/s */
5430150849Sscottl      { num_rx_descs = 16; tlp_op_tr = 0; break; }
5431150849Sscottl    default:
5432150849Sscottl      { num_rx_descs = 16; tlp_op_tr = 0; break; }
5433150849Sscottl    }
5434150849Sscottl
5435150849Sscottl  /* Create DMA descriptors and initialize list head registers. */
5436150849Sscottl  if ((error = create_ring(sc, &sc->txring, NUM_TX_DESCS))) return error;
5437150849Sscottl  WRITE_CSR(TLP_TX_LIST, sc->txring.dma_addr);
5438150849Sscottl  if ((error = create_ring(sc, &sc->rxring, num_rx_descs))) return error;
5439150849Sscottl  WRITE_CSR(TLP_RX_LIST, sc->rxring.dma_addr);
5440150849Sscottl
5441150849Sscottl  /* Initialize the operating mode register. */
5442150849Sscottl  WRITE_CSR(TLP_OP_MODE, TLP_OP_INIT | (tlp_op_tr<<TLP_OP_TR_SHIFT));
5443150849Sscottl
5444150849Sscottl  /* Read the missed frame register (result ignored) to zero it. */
5445150849Sscottl  error = READ_CSR( TLP_MISSED); /* error is used as a bit-dump */
5446150849Sscottl
5447150849Sscottl  /* Disable rx watchdog and tx jabber features. */
5448150849Sscottl  WRITE_CSR(TLP_WDOG, TLP_WDOG_INIT);
5449150849Sscottl
5450150849Sscottl  /* Enable card interrupts. */
5451150849Sscottl  WRITE_CSR(TLP_INT_ENBL, TLP_INT_TXRX);
5452150849Sscottl
5453150849Sscottl  return 0;
5454150849Sscottl  }
5455150849Sscottl
5456150849Sscottl/* Stop DMA and Interrupts; free descriptors and buffers. */
5457150849Sscottlstatic void
5458150849Sscottlshutdown_card(void *arg)
5459150849Sscottl  {
5460150849Sscottl  softc_t *sc = arg;
5461150849Sscottl
5462150849Sscottl  /* Leave the LEDs in the state they were in after power-on. */
5463150849Sscottl  led_on(sc, MII16_LED_ALL);
5464150849Sscottl
5465150849Sscottl  /* Software reset the Tulip chip; stops DMA and Interrupts */
5466150849Sscottl  WRITE_CSR(TLP_BUS_MODE, TLP_BUS_RESET); /* self-clearing */
5467150849Sscottl  DELAY(5);  /* Tulip is dead for 50 PCI cycles after reset. */
5468150849Sscottl
5469150849Sscottl  /* Disconnect from the PCI bus except for config cycles. */
5470150849Sscottl  /* Hmmm; Linux syslogs a warning that IO and MEM are disabled. */
5471150849Sscottl  WRITE_PCI_CFG(sc, TLP_CFCS, TLP_CFCS_MEM_ENABLE | TLP_CFCS_IO_ENABLE);
5472150849Sscottl
5473150849Sscottl  /* Free the DMA descriptor rings. */
5474150849Sscottl  destroy_ring(sc, &sc->txring);
5475150849Sscottl  destroy_ring(sc, &sc->rxring);
5476150849Sscottl  }
5477150849Sscottl
5478150849Sscottl/* Start the card and attach a kernel interface and line protocol. */
5479150849Sscottlstatic int
5480150849Sscottlattach_card(softc_t *sc, const char *intrstr)
5481150849Sscottl  {
5482150849Sscottl  struct config config;
5483150849Sscottl  u_int32_t tlp_cfrv;
5484150849Sscottl  u_int16_t mii3;
5485150849Sscottl  u_int8_t *ieee;
5486150849Sscottl  int i, error = 0;
5487150849Sscottl
5488150849Sscottl  /* Start the card. */
5489150849Sscottl  if ((error = startup_card(sc))) return error;
5490150849Sscottl
5491199538Sjhb#  if (__FreeBSD_version >= 500000)
5492199538Sjhb  callout_init(&sc->callout, 0);
5493199538Sjhb#  else  /* FreeBSD-4 */
5494199538Sjhb  callout_init(&sc->callout);
5495199538Sjhb#  endif
5496199538Sjhb
5497150849Sscottl  /* Attach a kernel interface. */
5498150849Sscottl#if NETGRAPH
5499150849Sscottl  if ((error = ng_attach(sc))) return error;
5500150849Sscottl  sc->flags |= FLAG_NETGRAPH;
5501150849Sscottl#endif
5502150849Sscottl#if IFNET
5503180304Srwatson  if ((error = lmc_ifnet_attach(sc))) return error;
5504150849Sscottl  sc->flags |= FLAG_IFNET;
5505150849Sscottl#endif
5506150849Sscottl
5507150849Sscottl  /* Attach a line protocol stack. */
5508150849Sscottl  sc->config.line_pkg = PKG_RAWIP;
5509150849Sscottl  config = sc->config;	/* get current config */
5510150849Sscottl  config.line_pkg = 0;	/* select external stack */
5511150849Sscottl  config.line_prot = PROT_C_HDLC;
5512150849Sscottl  config.keep_alive = 1;
5513150849Sscottl  config_proto(sc, &config); /* reconfigure */
5514150849Sscottl  sc->config = config;	/* save new configuration */
5515150849Sscottl
5516150849Sscottl  /* Print interesting hardware-related things. */
5517150849Sscottl  mii3 = read_mii(sc, 3);
5518150849Sscottl  tlp_cfrv = READ_PCI_CFG(sc, TLP_CFRV);
5519150849Sscottl  printf("%s: PCI rev %d.%d, MII rev %d.%d", NAME_UNIT,
5520150849Sscottl   (tlp_cfrv>>4) & 0xF, tlp_cfrv & 0xF, (mii3>>4) & 0xF, mii3 & 0xF);
5521150849Sscottl  ieee = (u_int8_t *)sc->status.ieee;
5522150849Sscottl  for (i=0; i<3; i++) sc->status.ieee[i] = read_srom(sc, 10+i);
5523150849Sscottl  printf(", IEEE addr %02x:%02x:%02x:%02x:%02x:%02x",
5524150849Sscottl   ieee[0], ieee[1], ieee[2], ieee[3], ieee[4], ieee[5]);
5525150849Sscottl  sc->card->ident(sc);
5526150849Sscottl  printf(" %s\n", intrstr);
5527150849Sscottl
5528150849Sscottl  /* Print interesting software-related things. */
5529150849Sscottl  printf("%s: Driver rev %d.%d.%d", NAME_UNIT,
5530150849Sscottl   DRIVER_MAJOR_VERSION, DRIVER_MINOR_VERSION, DRIVER_SUB_VERSION);
5531150849Sscottl  printf(", Options %s%s%s%s%s%s%s%s%s\n",
5532150849Sscottl   NETGRAPH ? "NETGRAPH " : "", GEN_HDLC ? "GEN_HDLC " : "",
5533150849Sscottl   NSPPP ? "SPPP " : "", P2P ? "P2P " : "",
5534150849Sscottl   ALTQ_PRESENT ? "ALTQ " : "", NBPFILTER ? "BPF " : "",
5535150849Sscottl   DEV_POLL ? "POLL " : "", IOREF_CSR ? "IO_CSR " : "MEM_CSR ",
5536150849Sscottl   (BYTE_ORDER == BIG_ENDIAN) ? "BIG_END " : "LITTLE_END ");
5537150849Sscottl
5538150849Sscottl  /* Make the local hardware ready. */
5539150849Sscottl  set_status(sc, 1);
5540150849Sscottl
5541150849Sscottl  return 0;
5542150849Sscottl  }
5543150849Sscottl
5544150849Sscottl/* Detach from the kernel in all ways. */
5545150849Sscottlstatic void
5546150849Sscottldetach_card(softc_t *sc)
5547150849Sscottl  {
5548150849Sscottl  struct config config;
5549150849Sscottl
5550150849Sscottl  /* Make the local hardware NOT ready. */
5551150849Sscottl  set_status(sc, 0);
5552150849Sscottl
5553150849Sscottl  /* Detach external line protocol stack. */
5554150849Sscottl  if (sc->config.line_pkg != PKG_RAWIP)
5555150849Sscottl    {
5556150849Sscottl    config = sc->config;
5557150849Sscottl    config.line_pkg = PKG_RAWIP;
5558150849Sscottl    config_proto(sc, &config);
5559150849Sscottl    sc->config = config;
5560150849Sscottl    }
5561150849Sscottl
5562150849Sscottl  /* Detach kernel interfaces. */
5563150849Sscottl#if NETGRAPH
5564150849Sscottl  if (sc->flags & FLAG_NETGRAPH)
5565150849Sscottl    {
5566150849Sscottl    IFQ_PURGE(&sc->ng_fastq);
5567150849Sscottl    IFQ_PURGE(&sc->ng_sndq);
5568150849Sscottl    ng_detach(sc);
5569150849Sscottl    sc->flags &= ~FLAG_NETGRAPH;
5570150849Sscottl    }
5571150849Sscottl#endif
5572150849Sscottl#if IFNET
5573150849Sscottl  if (sc->flags & FLAG_IFNET)
5574150849Sscottl    {
5575150849Sscottl    IFQ_PURGE(&sc->ifp->if_snd);
5576180304Srwatson    lmc_ifnet_detach(sc);
5577150849Sscottl    sc->flags &= ~FLAG_IFNET;
5578150849Sscottl    }
5579150849Sscottl#endif
5580150849Sscottl
5581150849Sscottl  /* Reset the Tulip chip; stops DMA and Interrupts. */
5582150849Sscottl  shutdown_card(sc);
5583150849Sscottl  }
5584150849Sscottl
5585150849Sscottl/* This is the I/O configuration interface for FreeBSD */
5586150849Sscottl
5587153084Sru#ifdef __FreeBSD__
5588150849Sscottl
5589150849Sscottlstatic int
5590150849Sscottlfbsd_probe(device_t dev)
5591150849Sscottl  {
5592150849Sscottl  u_int32_t cfid = pci_read_config(dev, TLP_CFID, 4);
5593150849Sscottl  u_int32_t csid = pci_read_config(dev, TLP_CSID, 4);
5594150849Sscottl
5595150849Sscottl  /* Looking for a DEC 21140A chip on any Lan Media Corp card. */
5596150849Sscottl  if (cfid != TLP_CFID_TULIP) return ENXIO;
5597150849Sscottl  switch (csid)
5598150849Sscottl    {
5599150849Sscottl    case TLP_CSID_HSSI:
5600150849Sscottl    case TLP_CSID_HSSIc:
5601150849Sscottl      device_set_desc(dev, HSSI_DESC);
5602150849Sscottl      break;
5603150849Sscottl    case TLP_CSID_T3:
5604150849Sscottl      device_set_desc(dev,   T3_DESC);
5605150849Sscottl      break;
5606150849Sscottl    case TLP_CSID_SSI:
5607150849Sscottl      device_set_desc(dev,  SSI_DESC);
5608150849Sscottl      break;
5609150849Sscottl    case TLP_CSID_T1E1:
5610150849Sscottl      device_set_desc(dev, T1E1_DESC);
5611150849Sscottl      break;
5612150849Sscottl    default:
5613150849Sscottl      return ENXIO;
5614150849Sscottl    }
5615150849Sscottl  return 0;
5616150849Sscottl  }
5617150849Sscottl
5618150849Sscottlstatic int
5619150849Sscottlfbsd_detach(device_t dev)
5620150849Sscottl  {
5621150849Sscottl  softc_t *sc = device_get_softc(dev);
5622150849Sscottl
5623150849Sscottl  /* Stop the card and detach from the kernel. */
5624150849Sscottl  detach_card(sc);
5625150849Sscottl
5626150849Sscottl  /* Release resources. */
5627150849Sscottl  if (sc->irq_cookie != NULL)
5628150849Sscottl    {
5629150849Sscottl    bus_teardown_intr(dev, sc->irq_res, sc->irq_cookie);
5630150849Sscottl    sc->irq_cookie = NULL;
5631150849Sscottl    }
5632150849Sscottl  if (sc->irq_res != NULL)
5633150849Sscottl    {
5634150849Sscottl    bus_release_resource(dev, SYS_RES_IRQ, sc->irq_res_id, sc->irq_res);
5635150849Sscottl    sc->irq_res = NULL;
5636150849Sscottl    }
5637150849Sscottl  if (sc->csr_res != NULL)
5638150849Sscottl    {
5639150849Sscottl    bus_release_resource(dev, sc->csr_res_type, sc->csr_res_id, sc->csr_res);
5640150849Sscottl    sc->csr_res = NULL;
5641150849Sscottl    }
5642150849Sscottl
5643150849Sscottl# if (__FreeBSD_version >= 500000)
5644150849Sscottl  mtx_destroy(&sc->top_mtx);
5645150849Sscottl  mtx_destroy(&sc->bottom_mtx);
5646150849Sscottl# endif
5647150849Sscottl  return 0; /* no error */
5648150849Sscottl  }
5649150849Sscottl
5650188178Simpstatic int
5651150849Sscottlfbsd_shutdown(device_t dev)
5652150849Sscottl  {
5653150849Sscottl  shutdown_card(device_get_softc(dev));
5654188178Simp  return 0;
5655150849Sscottl  }
5656150849Sscottl
5657150849Sscottlstatic int
5658150849Sscottlfbsd_attach(device_t dev)
5659150849Sscottl  {
5660150849Sscottl  softc_t *sc = device_get_softc(dev);
5661150849Sscottl  int error;
5662150849Sscottl
5663150849Sscottl  /* READ/WRITE_PCI_CFG need this. */
5664150849Sscottl  sc->dev = dev;
5665150849Sscottl
5666150849Sscottl  /* What kind of card are we driving? */
5667150849Sscottl  switch (READ_PCI_CFG(sc, TLP_CSID))
5668150849Sscottl    {
5669150849Sscottl    case TLP_CSID_HSSI:
5670150849Sscottl    case TLP_CSID_HSSIc:
5671150849Sscottl      sc->card = &hssi_card;
5672150849Sscottl      break;
5673150849Sscottl    case TLP_CSID_T3:
5674150849Sscottl      sc->card =   &t3_card;
5675150849Sscottl      break;
5676150849Sscottl    case TLP_CSID_SSI:
5677150849Sscottl      sc->card =  &ssi_card;
5678150849Sscottl      break;
5679150849Sscottl    case TLP_CSID_T1E1:
5680150849Sscottl      sc->card =   &t1_card;
5681150849Sscottl      break;
5682150849Sscottl    default:
5683150849Sscottl      return ENXIO;
5684150849Sscottl    }
5685150849Sscottl  sc->dev_desc = device_get_desc(dev);
5686150849Sscottl
5687150849Sscottl  /* Allocate PCI memory or IO resources to access the Tulip chip CSRs. */
5688150849Sscottl# if IOREF_CSR
5689150849Sscottl  sc->csr_res_id   = TLP_CBIO;
5690150849Sscottl  sc->csr_res_type = SYS_RES_IOPORT;
5691150849Sscottl# else
5692150849Sscottl  sc->csr_res_id   = TLP_CBMA;
5693150849Sscottl  sc->csr_res_type = SYS_RES_MEMORY;
5694150849Sscottl# endif
5695150849Sscottl  sc->csr_res = bus_alloc_resource(dev, sc->csr_res_type, &sc->csr_res_id,
5696150849Sscottl   0, ~0, 1, RF_ACTIVE);
5697150849Sscottl  if (sc->csr_res == NULL)
5698150849Sscottl    {
5699150849Sscottl    printf("%s: bus_alloc_resource(csr) failed.\n", NAME_UNIT);
5700150849Sscottl    return ENXIO;
5701150849Sscottl    }
5702150849Sscottl  sc->csr_tag    = rman_get_bustag(sc->csr_res);
5703150849Sscottl  sc->csr_handle = rman_get_bushandle(sc->csr_res);
5704150849Sscottl
5705150849Sscottl  /* Allocate PCI interrupt resources for the card. */
5706150849Sscottl  sc->irq_res_id = 0;
5707150849Sscottl  sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_res_id,
5708150849Sscottl   0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
5709150849Sscottl  if (sc->irq_res == NULL)
5710150849Sscottl    {
5711150849Sscottl    printf("%s: bus_alloc_resource(irq) failed.\n", NAME_UNIT);
5712150849Sscottl    fbsd_detach(dev);
5713150849Sscottl    return ENXIO;
5714150849Sscottl    }
5715150849Sscottl  if ((error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE,
5716166901Spiso   NULL, bsd_interrupt, sc, &sc->irq_cookie)))
5717150849Sscottl    {
5718150849Sscottl    printf("%s: bus_setup_intr() failed; error %d\n", NAME_UNIT, error);
5719150849Sscottl    fbsd_detach(dev);
5720150849Sscottl    return error;
5721150849Sscottl    }
5722150849Sscottl
5723150849Sscottl# if (__FreeBSD_version >= 500000)
5724150849Sscottl  /* Initialize the top-half and bottom-half locks. */
5725150849Sscottl  mtx_init(&sc->top_mtx,    NAME_UNIT, "top half lock",    MTX_DEF);
5726150849Sscottl  mtx_init(&sc->bottom_mtx, NAME_UNIT, "bottom half lock", MTX_DEF);
5727150849Sscottl# endif
5728150849Sscottl
5729150849Sscottl  /* Start the card and attach a kernel interface and line protocol. */
5730150849Sscottl  if ((error = attach_card(sc, ""))) detach_card(sc);
5731150849Sscottl  return error;
5732150849Sscottl  }
5733150849Sscottl
5734150849Sscottlstatic device_method_t methods[] =
5735150849Sscottl  {
5736150849Sscottl  DEVMETHOD(device_probe,    fbsd_probe),
5737150849Sscottl  DEVMETHOD(device_attach,   fbsd_attach),
5738150849Sscottl  DEVMETHOD(device_detach,   fbsd_detach),
5739150849Sscottl  DEVMETHOD(device_shutdown, fbsd_shutdown),
5740150849Sscottl  /* This driver does not suspend and resume. */
5741150849Sscottl  { 0, 0 }
5742150849Sscottl  };
5743150849Sscottl
5744150849Sscottlstatic driver_t driver =
5745150849Sscottl  {
5746150849Sscottl  .name    = DEVICE_NAME,
5747150849Sscottl  .methods = methods,
5748150849Sscottl# if (__FreeBSD_version >= 500000)
5749150849Sscottl  .size    = sizeof(softc_t),
5750150849Sscottl# else /* FreeBSD-4 */
5751150849Sscottl  .softc   = sizeof(softc_t),
5752150849Sscottl# endif
5753150849Sscottl  };
5754150849Sscottl
5755150849Sscottlstatic devclass_t devclass;
5756150849Sscottl
5757192147SimpDRIVER_MODULE(lmc, pci, driver, devclass, 0, 0);
5758192147SimpMODULE_VERSION(lmc, 2);
5759192147SimpMODULE_DEPEND(lmc, pci, 1, 1, 1);
5760150849Sscottl# if NETGRAPH
5761192147SimpMODULE_DEPEND(lmc, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION);
5762150849Sscottl# endif
5763150849Sscottl# if NSPPP
5764192147SimpMODULE_DEPEND(lmc, sppp, 1, 1, 1);
5765150849Sscottl# endif
5766150849Sscottl
5767150849Sscottl#endif  /* __FreeBSD__ */
5768150849Sscottl
5769150849Sscottl/* This is the I/O configuration interface for NetBSD. */
5770150849Sscottl
5771153084Sru#ifdef __NetBSD__
5772150849Sscottl
5773150849Sscottlstatic int
5774150849Sscottlnbsd_match(struct device *parent, struct cfdata *match, void *aux)
5775150849Sscottl  {
5776150849Sscottl  struct pci_attach_args *pa = aux;
5777150849Sscottl  u_int32_t cfid = pci_conf_read(pa->pa_pc, pa->pa_tag, TLP_CFID);
5778150849Sscottl  u_int32_t csid = pci_conf_read(pa->pa_pc, pa->pa_tag, TLP_CSID);
5779150849Sscottl
5780150849Sscottl  /* Looking for a DEC 21140A chip on any Lan Media Corp card. */
5781150849Sscottl  if (cfid != TLP_CFID_TULIP) return 0;
5782150849Sscottl  switch (csid)
5783150849Sscottl    {
5784150849Sscottl    case TLP_CSID_HSSI:
5785150849Sscottl    case TLP_CSID_HSSIc:
5786150849Sscottl    case TLP_CSID_T3:
5787150849Sscottl    case TLP_CSID_SSI:
5788150849Sscottl    case TLP_CSID_T1E1:
5789150849Sscottl      return 100;
5790150849Sscottl    default:
5791150849Sscottl      return 0;
5792150849Sscottl    }
5793150849Sscottl  }
5794150849Sscottl
5795150849Sscottlstatic int
5796150849Sscottlnbsd_detach(struct device *self, int flags)
5797150849Sscottl  {
5798150849Sscottl  softc_t *sc = (softc_t *)self; /* device is first in softc */
5799150849Sscottl
5800150849Sscottl  /* Stop the card and detach from the kernel. */
5801150849Sscottl  detach_card(sc);
5802150849Sscottl
5803150849Sscottl  /* Release resources. */
5804150849Sscottl  if (sc->sdh_cookie != NULL)
5805150849Sscottl    {
5806150849Sscottl    shutdownhook_disestablish(sc->sdh_cookie);
5807150849Sscottl    sc->sdh_cookie = NULL;
5808150849Sscottl    }
5809150849Sscottl  if (sc->irq_cookie != NULL)
5810150849Sscottl    {
5811150849Sscottl    pci_intr_disestablish(sc->pa_pc, sc->irq_cookie);
5812150849Sscottl    sc->irq_cookie = NULL;
5813150849Sscottl    }
5814150849Sscottl  if (sc->csr_handle)
5815150849Sscottl    {
5816150849Sscottl    bus_space_unmap(sc->csr_tag, sc->csr_handle, TLP_CSR_SIZE);
5817150849Sscottl    sc->csr_handle = 0;
5818150849Sscottl    }
5819150849Sscottl
5820150849Sscottl  return 0; /* no error */
5821150849Sscottl  }
5822150849Sscottl
5823150849Sscottlstatic void
5824150849Sscottlnbsd_attach(struct device *parent, struct device *self, void *aux)
5825150849Sscottl  {
5826150849Sscottl  softc_t *sc = (softc_t *)self; /* device is first in softc */
5827150849Sscottl  struct pci_attach_args *pa = aux;
5828150849Sscottl  const char *intrstr;
5829150849Sscottl  bus_addr_t csr_addr;
5830150849Sscottl  int error;
5831150849Sscottl
5832150849Sscottl  /* READ/WRITE_PCI_CFG need these. */
5833150849Sscottl  sc->pa_pc   = pa->pa_pc;
5834150849Sscottl  sc->pa_tag  = pa->pa_tag;
5835150849Sscottl  /* bus_dma needs this. */
5836150849Sscottl  sc->pa_dmat = pa->pa_dmat;
5837150849Sscottl
5838150849Sscottl  /* What kind of card are we driving? */
5839150849Sscottl  switch (READ_PCI_CFG(sc, TLP_CSID))
5840150849Sscottl    {
5841150849Sscottl    case TLP_CSID_HSSI:
5842150849Sscottl    case TLP_CSID_HSSIc:
5843150849Sscottl      sc->dev_desc =  HSSI_DESC;
5844150849Sscottl      sc->card     = &hssi_card;
5845150849Sscottl      break;
5846150849Sscottl    case TLP_CSID_T3:
5847150849Sscottl      sc->dev_desc =    T3_DESC;
5848150849Sscottl      sc->card     =   &t3_card;
5849150849Sscottl      break;
5850150849Sscottl    case TLP_CSID_SSI:
5851150849Sscottl      sc->dev_desc =   SSI_DESC;
5852150849Sscottl      sc->card     =  &ssi_card;
5853150849Sscottl      break;
5854150849Sscottl    case TLP_CSID_T1E1:
5855150849Sscottl      sc->dev_desc =  T1E1_DESC;
5856150849Sscottl      sc->card     =   &t1_card;
5857150849Sscottl      break;
5858150849Sscottl    default:
5859150849Sscottl      return;
5860150849Sscottl    }
5861150849Sscottl  printf(": %s\n", sc->dev_desc);
5862150849Sscottl
5863150849Sscottl  /* Allocate PCI resources to access the Tulip chip CSRs. */
5864150849Sscottl# if IOREF_CSR
5865150849Sscottl  csr_addr = (bus_addr_t)READ_PCI_CFG(sc, TLP_CBIO) & -2;
5866150849Sscottl  sc->csr_tag = pa->pa_iot;	/* bus_space tag for IO refs */
5867150849Sscottl# else
5868150849Sscottl  csr_addr = (bus_addr_t)READ_PCI_CFG(sc, TLP_CBMA);
5869150849Sscottl  sc->csr_tag = pa->pa_memt;	/* bus_space tag for MEM refs */
5870150849Sscottl# endif
5871150849Sscottl  if ((error = bus_space_map(sc->csr_tag, csr_addr,
5872150849Sscottl   TLP_CSR_SIZE, 0, &sc->csr_handle)))
5873150849Sscottl    {
5874150849Sscottl    printf("%s: bus_space_map() failed; error %d\n", NAME_UNIT, error);
5875150849Sscottl    return;
5876150849Sscottl    }
5877150849Sscottl
5878150849Sscottl  /* Allocate PCI interrupt resources. */
5879150849Sscottl  if ((error = pci_intr_map(pa, &sc->intr_handle)))
5880150849Sscottl    {
5881150849Sscottl    printf("%s: pci_intr_map() failed; error %d\n", NAME_UNIT, error);
5882150849Sscottl    nbsd_detach(self, 0);
5883150849Sscottl    return;
5884150849Sscottl    }
5885150849Sscottl  sc->irq_cookie = pci_intr_establish(pa->pa_pc, sc->intr_handle,
5886150849Sscottl   IPL_NET, bsd_interrupt, sc);
5887150849Sscottl  if (sc->irq_cookie == NULL)
5888150849Sscottl    {
5889150849Sscottl    printf("%s: pci_intr_establish() failed\n", NAME_UNIT);
5890150849Sscottl    nbsd_detach(self, 0);
5891150849Sscottl    return;
5892150849Sscottl    }
5893150849Sscottl  intrstr = pci_intr_string(pa->pa_pc, sc->intr_handle);
5894150849Sscottl
5895150849Sscottl  /* Install a shutdown hook. */
5896150849Sscottl  sc->sdh_cookie = shutdownhook_establish(shutdown_card, sc);
5897150849Sscottl  if (sc->sdh_cookie == NULL)
5898150849Sscottl    {
5899150849Sscottl    printf("%s: shutdown_hook_establish() failed\n", NAME_UNIT);
5900150849Sscottl    nbsd_detach(self, 0);
5901150849Sscottl    return;
5902150849Sscottl    }
5903150849Sscottl
5904150849Sscottl  /* Initialize the top-half and bottom-half locks. */
5905150849Sscottl  simple_lock_init(&sc->top_lock);
5906150849Sscottl  simple_lock_init(&sc->bottom_lock);
5907150849Sscottl
5908150849Sscottl  /* Start the card and attach a kernel interface and line protocol. */
5909150849Sscottl  if ((error = attach_card(sc, intrstr))) detach_card(sc);
5910150849Sscottl  }
5911150849Sscottl
5912150849Sscottl# if (__NetBSD_Version__ >= 106080000) /* 1.6H */
5913150849SscottlCFATTACH_DECL(lmc, sizeof(softc_t),
5914150849Sscottl nbsd_match, nbsd_attach, nbsd_detach, NULL);
5915150849Sscottl# else
5916150849Sscottlstruct cfattach lmc_ca =
5917150849Sscottl  {
5918150849Sscottl/*.ca_name	= DEVICE_NAME, */
5919150849Sscottl  .ca_devsize	= sizeof(softc_t),
5920150849Sscottl  .ca_match	= nbsd_match,
5921150849Sscottl  .ca_attach	= nbsd_attach,
5922150849Sscottl  .ca_detach	= nbsd_detach,
5923150849Sscottl  .ca_activate	= NULL,
5924150849Sscottl  };
5925150849Sscottl# endif
5926150849Sscottl
5927150849Sscottl# if (__NetBSD_Version__ >= 106080000)
5928150849SscottlCFDRIVER_DECL(lmc, DV_IFNET, NULL);
5929150849Sscottl# else
5930150849Sscottlstatic struct cfdriver lmc_cd =
5931150849Sscottl  {
5932150849Sscottl  .cd_name	= DEVICE_NAME,
5933150849Sscottl  .cd_class	= DV_IFNET,
5934150849Sscottl  .cd_ndevs	= 0,
5935150849Sscottl  .cd_devs	= NULL,
5936150849Sscottl  };
5937150849Sscottl# endif
5938150849Sscottl
5939150849Sscottl/* cfdata is declared static, unseen outside this module. */
5940150849Sscottl/* It is used for LKM; config builds its own in ioconf.c. */
5941150849Sscottlstatic struct cfdata lmc_cf =
5942150849Sscottl  {
5943150849Sscottl# if (__NetBSD_Version__ >= 106080000)
5944150849Sscottl  .cf_name	= DEVICE_NAME,
5945150849Sscottl  .cf_atname    = DEVICE_NAME,
5946150849Sscottl# else
5947150849Sscottl  .cf_driver	= &lmc_cd,
5948150849Sscottl  .cf_attach	= &lmc_ca,
5949150849Sscottl# endif
5950150849Sscottl  .cf_unit	= 0,
5951150849Sscottl  .cf_fstate	= FSTATE_STAR,
5952150849Sscottl  };
5953150849Sscottl
5954150849Sscottl# if (__NetBSD_Version__ >= 106080000)
5955150849SscottlMOD_MISC(DEVICE_NAME)
5956150849Sscottl# else
5957150849Sscottlstatic struct lkm_misc _module =
5958150849Sscottl  {
5959150849Sscottl  .lkm_name	= DEVICE_NAME,
5960150849Sscottl  .lkm_type	= LM_MISC,
5961150849Sscottl  .lkm_offset	= 0,
5962150849Sscottl  .lkm_ver	= LKM_VERSION,
5963150849Sscottl  };
5964150849Sscottl# endif
5965150849Sscottl
5966150849Sscottl/* From /sys/dev/pci/pci.c (no public prototype). */
5967150849Sscottlint pciprint(void *, const char *);
5968150849Sscottl
5969150849Sscottlstatic int lkm_nbsd_match(struct pci_attach_args *pa)
5970150849Sscottl  { return nbsd_match(0, 0, pa); }
5971150849Sscottl
5972150849Sscottl/* LKM loader finds this by appending "_lkmentry" to filename "if_lmc". */
5973150849Sscottlint if_lmc_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)
5974150849Sscottl  {
5975150849Sscottl  int i, error = 0;
5976150849Sscottl
5977150849Sscottl  if (ver != LKM_VERSION) return EINVAL;
5978150849Sscottl  switch (cmd)
5979150849Sscottl    {
5980150849Sscottl    case LKM_E_LOAD:
5981150849Sscottl      {
5982150849Sscottl      struct cfdriver* pcicd;
5983150849Sscottl
5984150849Sscottl      lkmtp->private.lkm_misc = &_module;
5985150849Sscottl      if ((pcicd = config_cfdriver_lookup("pci")) == NULL)
5986150849Sscottl        {
5987150849Sscottl        printf("%s: config_cfdriver_lookup(pci) failed; error %d\n",
5988150849Sscottl         lmc_cd.cd_name, error);
5989150849Sscottl        return error;
5990150849Sscottl	}
5991150849Sscottl# if (__NetBSD_Version__ >= 106080000)
5992150849Sscottl      if ((error = config_cfdriver_attach(&lmc_cd)))
5993150849Sscottl        {
5994150849Sscottl        printf("%s: config_cfdriver_attach() failed; error %d\n",
5995150849Sscottl         lmc_cd.cd_name, error);
5996150849Sscottl        return error;
5997150849Sscottl        }
5998150849Sscottl      if ((error = config_cfattach_attach(lmc_cd.cd_name, &lmc_ca)))
5999150849Sscottl        {
6000150849Sscottl        printf("%s: config_cfattach_attach() failed; error %d\n",
6001150849Sscottl         lmc_cd.cd_name, error);
6002150849Sscottl        config_cfdriver_detach(&lmc_cd);
6003150849Sscottl        return error;
6004150849Sscottl        }
6005150849Sscottl# endif
6006150849Sscottl      for (i=0; i<pcicd->cd_ndevs; i++)
6007150849Sscottl        {
6008150849Sscottl        int dev;
6009150849Sscottl        /* A pointer to a device is a pointer to its softc. */
6010150849Sscottl        struct pci_softc *sc = pcicd->cd_devs[i];
6011150849Sscottl        if (sc == NULL) continue;
6012150849Sscottl        for (dev=0; dev<sc->sc_maxndevs; dev++)
6013150849Sscottl          {
6014150849Sscottl          struct pci_attach_args pa;
6015150849Sscottl          pcitag_t tag = pci_make_tag(sc->sc_pc, sc->sc_bus, dev, 0);
6016150849Sscottl          if (pci_probe_device(sc, tag, lkm_nbsd_match, &pa) != 0)
6017150849Sscottl            config_attach(pcicd->cd_devs[i], &lmc_cf, &pa, pciprint);
6018150849Sscottl            /* config_attach doesn't return on failure; it calls panic. */
6019150849Sscottl          }
6020150849Sscottl	}
6021150849Sscottl      break;
6022150849Sscottl      }
6023150849Sscottl    case LKM_E_UNLOAD:
6024150849Sscottl      {
6025150849Sscottl      for (i=lmc_cd.cd_ndevs-1; i>=0; i--)
6026150849Sscottl        {
6027150849Sscottl        struct device *dev = lmc_cd.cd_devs[i];
6028150849Sscottl        if (dev == NULL) continue;
6029150849Sscottl        if ((error = config_detach(dev, 0)))
6030150849Sscottl          {
6031150849Sscottl          printf("%s: config_detach() failed; error %d\n",
6032150849Sscottl           dev->dv_xname, error);
6033150849Sscottl          return error;
6034150849Sscottl	  }
6035150849Sscottl	}
6036150849Sscottl# if (__NetBSD_Version__ >= 106080000)
6037150849Sscottl      if ((error = config_cfattach_detach(lmc_cd.cd_name, &lmc_ca)))
6038150849Sscottl        {
6039150849Sscottl        printf("%s: config_cfattach_detach() failed; error %d\n",
6040150849Sscottl         lmc_cd.cd_name, error);
6041150849Sscottl        return error;
6042150849Sscottl        }
6043150849Sscottl      if ((error = config_cfdriver_detach(&lmc_cd)))
6044150849Sscottl        {
6045150849Sscottl        printf("%s: config_cfdriver_detach() failed; error %d\n",
6046150849Sscottl         lmc_cd.cd_name, error);
6047150849Sscottl        return error;
6048150849Sscottl        }
6049150849Sscottl# endif
6050150849Sscottl      break;
6051150849Sscottl      }
6052150849Sscottl    case LKM_E_STAT:
6053150849Sscottl      break;
6054150849Sscottl    }
6055150849Sscottl
6056150849Sscottl  return error;
6057150849Sscottl  }
6058150849Sscottl
6059150849Sscottl#endif  /* __NetBSD__ */
6060150849Sscottl
6061150849Sscottl/* This is the I/O configuration interface for OpenBSD. */
6062150849Sscottl
6063153084Sru#ifdef __OpenBSD__
6064150849Sscottl
6065150849Sscottlstatic int
6066150849Sscottlobsd_match(struct device *parent, void *match, void *aux)
6067150849Sscottl  {
6068150849Sscottl  struct pci_attach_args *pa = aux;
6069150849Sscottl  u_int32_t cfid = pci_conf_read(pa->pa_pc, pa->pa_tag, TLP_CFID);
6070150849Sscottl  u_int32_t csid = pci_conf_read(pa->pa_pc, pa->pa_tag, TLP_CSID);
6071150849Sscottl
6072150849Sscottl  /* Looking for a DEC 21140A chip on any Lan Media Corp card. */
6073150849Sscottl  if (cfid != TLP_CFID_TULIP) return 0;
6074150849Sscottl  switch (csid)
6075150849Sscottl    {
6076150849Sscottl    case TLP_CSID_HSSI:
6077150849Sscottl    case TLP_CSID_HSSIc:
6078150849Sscottl    case TLP_CSID_T3:
6079150849Sscottl    case TLP_CSID_SSI:
6080150849Sscottl    case TLP_CSID_T1E1:
6081150849Sscottl      return 100; /* match better than other 21140 drivers */
6082150849Sscottl    default:
6083150849Sscottl      return 0;
6084150849Sscottl    }
6085150849Sscottl  }
6086150849Sscottl
6087150849Sscottlstatic int
6088150849Sscottlobsd_detach(struct device *self, int flags)
6089150849Sscottl  {
6090150849Sscottl  softc_t *sc = (softc_t *)self; /* device is first in softc */
6091150849Sscottl
6092150849Sscottl  /* Stop the card and detach from the kernel. */
6093150849Sscottl  detach_card(sc);
6094150849Sscottl
6095150849Sscottl  /* Release resources. */
6096150849Sscottl  if (sc->sdh_cookie != NULL)
6097150849Sscottl    {
6098150849Sscottl    shutdownhook_disestablish(sc->sdh_cookie);
6099150849Sscottl    sc->sdh_cookie = NULL;
6100150849Sscottl    }
6101150849Sscottl  if (sc->irq_cookie != NULL)
6102150849Sscottl    {
6103150849Sscottl    pci_intr_disestablish(sc->pa_pc, sc->irq_cookie);
6104150849Sscottl    sc->irq_cookie = NULL;
6105150849Sscottl    }
6106150849Sscottl  if (sc->csr_handle)
6107150849Sscottl    {
6108150849Sscottl    bus_space_unmap(sc->csr_tag, sc->csr_handle, TLP_CSR_SIZE);
6109150849Sscottl    sc->csr_handle = 0;
6110150849Sscottl    }
6111150849Sscottl
6112150849Sscottl  return 0; /* no error */
6113150849Sscottl  }
6114150849Sscottl
6115150849Sscottlstatic void
6116150849Sscottlobsd_attach(struct device *parent, struct device *self, void *aux)
6117150849Sscottl  {
6118150849Sscottl  softc_t *sc = (softc_t *)self; /* device is first in softc */
6119150849Sscottl  struct pci_attach_args *pa = aux;
6120150849Sscottl  const char *intrstr;
6121150849Sscottl  bus_addr_t csr_addr;
6122150849Sscottl  int error;
6123150849Sscottl
6124150849Sscottl  /* READ/WRITE_PCI_CFG need these. */
6125150849Sscottl  sc->pa_pc   = pa->pa_pc;
6126150849Sscottl  sc->pa_tag  = pa->pa_tag;
6127150849Sscottl  /* bus_dma needs this. */
6128150849Sscottl  sc->pa_dmat = pa->pa_dmat;
6129150849Sscottl
6130150849Sscottl  /* What kind of card are we driving? */
6131150849Sscottl  switch (READ_PCI_CFG(sc, TLP_CSID))
6132150849Sscottl    {
6133150849Sscottl    case TLP_CSID_HSSI:
6134150849Sscottl    case TLP_CSID_HSSIc:
6135150849Sscottl      sc->dev_desc =  HSSI_DESC;
6136150849Sscottl      sc->card     = &hssi_card;
6137150849Sscottl      break;
6138150849Sscottl    case TLP_CSID_T3:
6139150849Sscottl      sc->dev_desc =    T3_DESC;
6140150849Sscottl      sc->card     =   &t3_card;
6141150849Sscottl      break;
6142150849Sscottl    case TLP_CSID_SSI:
6143150849Sscottl      sc->dev_desc =   SSI_DESC;
6144150849Sscottl      sc->card     =  &ssi_card;
6145150849Sscottl      break;
6146150849Sscottl    case TLP_CSID_T1E1:
6147150849Sscottl      sc->dev_desc =  T1E1_DESC;
6148150849Sscottl      sc->card     =   &t1_card;
6149150849Sscottl      break;
6150150849Sscottl    default:
6151150849Sscottl      return;
6152150849Sscottl    }
6153150849Sscottl  printf(": %s\n", sc->dev_desc);
6154150849Sscottl
6155150849Sscottl  /* Allocate PCI resources to access the Tulip chip CSRs. */
6156150849Sscottl# if IOREF_CSR
6157150849Sscottl  csr_addr = (bus_addr_t)READ_PCI_CFG(sc, TLP_CBIO) & -2;
6158150849Sscottl  sc->csr_tag = pa->pa_iot;	/* bus_space tag for IO refs */
6159150849Sscottl# else
6160150849Sscottl  csr_addr = (bus_addr_t)READ_PCI_CFG(sc, TLP_CBMA);
6161150849Sscottl  sc->csr_tag = pa->pa_memt;	/* bus_space tag for MEM refs */
6162150849Sscottl# endif
6163150849Sscottl  if ((error = bus_space_map(sc->csr_tag, csr_addr,
6164150849Sscottl   TLP_CSR_SIZE, 0, &sc->csr_handle)))
6165150849Sscottl    {
6166150849Sscottl    printf("%s: bus_space_map() failed; error %d\n", NAME_UNIT, error);
6167150849Sscottl    return;
6168150849Sscottl    }
6169150849Sscottl
6170150849Sscottl  /* Allocate PCI interrupt resources. */
6171150849Sscottl  if ((error = pci_intr_map(pa, &sc->intr_handle)))
6172150849Sscottl    {
6173150849Sscottl    printf("%s: pci_intr_map() failed; error %d\n", NAME_UNIT, error);
6174150849Sscottl    obsd_detach(self, 0);
6175150849Sscottl    return;
6176150849Sscottl    }
6177150849Sscottl  sc->irq_cookie = pci_intr_establish(pa->pa_pc, sc->intr_handle,
6178150849Sscottl   IPL_NET, bsd_interrupt, sc, self->dv_xname);
6179150849Sscottl  if (sc->irq_cookie == NULL)
6180150849Sscottl    {
6181150849Sscottl    printf("%s: pci_intr_establish() failed\n", NAME_UNIT);
6182150849Sscottl    obsd_detach(self, 0);
6183150849Sscottl    return;
6184150849Sscottl    }
6185150849Sscottl  intrstr = pci_intr_string(pa->pa_pc, sc->intr_handle);
6186150849Sscottl
6187150849Sscottl  /* Install a shutdown hook. */
6188150849Sscottl  sc->sdh_cookie = shutdownhook_establish(shutdown_card, sc);
6189150849Sscottl  if (sc->sdh_cookie == NULL)
6190150849Sscottl    {
6191150849Sscottl    printf("%s: shutdown_hook_establish() failed\n", NAME_UNIT);
6192150849Sscottl    obsd_detach(self, 0);
6193150849Sscottl    return;
6194150849Sscottl    }
6195150849Sscottl
6196150849Sscottl  /* Initialize the top-half and bottom-half locks. */
6197150849Sscottl  simple_lock_init(&sc->top_lock);
6198150849Sscottl  simple_lock_init(&sc->bottom_lock);
6199150849Sscottl
6200150849Sscottl  /* Start the card and attach a kernel interface and line protocol. */
6201150849Sscottl  if ((error = attach_card(sc, intrstr))) detach_card(sc);
6202150849Sscottl  }
6203150849Sscottl
6204150849Sscottlstruct cfattach lmc_ca =
6205150849Sscottl  {
6206150849Sscottl  .ca_devsize	= sizeof(softc_t),
6207150849Sscottl  .ca_match	= obsd_match,
6208150849Sscottl  .ca_attach	= obsd_attach,
6209150849Sscottl  .ca_detach	= obsd_detach,
6210150849Sscottl  .ca_activate	= NULL,
6211150849Sscottl  };
6212150849Sscottl
6213150849Sscottlstruct cfdriver lmc_cd =
6214150849Sscottl  {
6215150849Sscottl  .cd_name	= DEVICE_NAME,
6216150849Sscottl  .cd_devs	= NULL,
6217150849Sscottl  .cd_class	= DV_IFNET,
6218150849Sscottl  .cd_indirect	= 0,
6219150849Sscottl  .cd_ndevs	= 0,
6220150849Sscottl  };
6221150849Sscottl
6222150849Sscottl/* cfdata is declared static, unseen outside this module. */
6223150849Sscottl/* It is used for LKM; config builds its own in ioconf.c. */
6224150849Sscottlstatic struct cfdata lmc_cfdata =
6225150849Sscottl  {
6226150849Sscottl  .cf_attach	= &lmc_ca,
6227150849Sscottl  .cf_driver	= &lmc_cd,
6228150849Sscottl  .cf_unit	= 0,
6229150849Sscottl  .cf_fstate	= FSTATE_STAR,
6230150849Sscottl  };
6231150849Sscottl
6232150849Sscottlstatic struct lkm_any _module =
6233150849Sscottl  {
6234150849Sscottl  .lkm_name	= DEVICE_NAME,
6235150849Sscottl  .lkm_type	= LM_MISC,
6236150849Sscottl  .lkm_offset	= 0,
6237150849Sscottl  .lkm_ver	= LKM_VERSION,
6238150849Sscottl  };
6239150849Sscottl
6240150849Sscottl/* From /sys/dev/pci/pci.c (no public prototype). */
6241150849Sscottlint pciprint(void *, const char *);
6242150849Sscottl
6243150849Sscottlextern struct cfdriver pci_cd;
6244150849Sscottl
6245150849Sscottl/* LKM loader finds this by appending "_lkmentry" to filename "if_lmc". */
6246150849Sscottlint if_lmc_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)
6247150849Sscottl  {
6248150849Sscottl  int i, error = 0;
6249150849Sscottl
6250150849Sscottl  if (ver != LKM_VERSION) return EINVAL;
6251150849Sscottl  switch (cmd)
6252150849Sscottl    {
6253150849Sscottl    case LKM_E_LOAD:
6254150849Sscottl      {  /* XXX This works for ONE card on pci0 of a i386 machine! XXX */
6255150849Sscottl      lkmtp->private.lkm_any = &_module;
6256150849Sscottl      for (i=0; i<pci_cd.cd_ndevs; i++)
6257150849Sscottl        {
6258150849Sscottl        struct pci_attach_args pa;
6259150849Sscottl        struct device *parent = pci_cd.cd_devs[i];
6260150849Sscottl        if (parent == NULL) continue; /* dead clone? */
6261150849Sscottl        if ((parent->dv_unit)!=0) continue; /* only bus zero */
6262150849Sscottl        /* XXX For machine independence, need: pcibus_attach_args. XXX */
6263150849Sscottl        /* XXX See NetBSD's sys/dev/pci/pci.c/pci_probe_device.    XXX */
6264150849Sscottl        /* XXX Why isn't there an LKM network interface module?    XXX */
6265150849Sscottl        pa.pa_pc    = NULL;					/* XXX */
6266150849Sscottl        pa.pa_bus   = 0;					/* XXX */
6267216592Stijl        pa.pa_iot   = X86_BUS_SPACE_IO;				/* XXX */
6268216592Stijl        pa.pa_memt  = X86_BUS_SPACE_MEM;			/* XXX */
6269150849Sscottl        pa.pa_dmat  = &pci_bus_dma_tag;				/* XXX */
6270150849Sscottl        for (pa.pa_device=0; pa.pa_device<32; pa.pa_device++)	/* XXX */
6271150849Sscottl          {
6272150849Sscottl          int intr;
6273150849Sscottl          pa.pa_function = 0; /* DEC-21140A has function 0 only    XXX */
6274150849Sscottl          pa.pa_tag = pci_make_tag(pa.pa_pc, pa.pa_bus, pa.pa_device, 0);
6275150849Sscottl          pa.pa_id = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_ID_REG);
6276150849Sscottl          if ((pa.pa_id & 0xFFFF) == 0xFFFF) continue;
6277150849Sscottl          if ((pa.pa_id & 0xFFFF) == 0) continue;
6278150849Sscottl          /* XXX this only works for pci0 -- no swizzelling        XXX */
6279150849Sscottl          pa.pa_intrswiz = 0;
6280150849Sscottl          pa.pa_intrtag = pa.pa_tag;
6281150849Sscottl          intr = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_INTERRUPT_REG);
6282150849Sscottl          pa.pa_intrline = PCI_INTERRUPT_LINE(intr);
6283150849Sscottl          pa.pa_intrpin = ((PCI_INTERRUPT_PIN(intr) -1) % 4) +1;
6284150849Sscottl          if (obsd_match(parent, &lmc_cfdata, &pa))
6285150849Sscottl            config_attach(parent, &lmc_cfdata, &pa, pciprint);
6286150849Sscottl          /* config_attach doesn't return on failure; it calls panic. */
6287150849Sscottl          }
6288150849Sscottl	}
6289150849Sscottl      break;
6290150849Sscottl      }
6291150849Sscottl    case LKM_E_UNLOAD:
6292150849Sscottl      {
6293150849Sscottl      for (i=lmc_cd.cd_ndevs-1; i>=0; i--)
6294150849Sscottl        {
6295150849Sscottl        struct device *dev = lmc_cd.cd_devs[i];
6296150849Sscottl        if (dev == NULL) continue;
6297150849Sscottl        if ((error = config_detach(dev, 0)))
6298150849Sscottl          printf("%s: config_detach() failed; error %d\n", dev->dv_xname, error);
6299150849Sscottl        }
6300150849Sscottl      break;
6301150849Sscottl      }
6302150849Sscottl    case LKM_E_STAT:
6303150849Sscottl      break;
6304150849Sscottl    }
6305150849Sscottl
6306150849Sscottl  return error;
6307150849Sscottl  }
6308150849Sscottl
6309150849Sscottl#endif  /* __OpenBSD__ */
6310150849Sscottl
6311150849Sscottl/* This is the I/O configuration interface for BSD/OS. */
6312150849Sscottl
6313153084Sru#ifdef __bsdi__
6314150849Sscottl
6315150849Sscottlstatic int
6316150849Sscottlbsdi_match(pci_devaddr_t *pa)
6317150849Sscottl  {
6318150849Sscottl  u_int32_t cfid = pci_inl(pa, TLP_CFID);
6319150849Sscottl  u_int32_t csid = pci_inl(pa, TLP_CSID);
6320150849Sscottl
6321150849Sscottl  /* Looking for a DEC 21140A chip on any Lan Media Corp card. */
6322150849Sscottl  if (cfid != TLP_CFID_TULIP) return 0;
6323150849Sscottl  switch (csid)
6324150849Sscottl    {
6325150849Sscottl    case TLP_CSID_HSSI:
6326150849Sscottl    case TLP_CSID_HSSIc:
6327150849Sscottl    case TLP_CSID_T3:
6328150849Sscottl    case TLP_CSID_SSI:
6329150849Sscottl    case TLP_CSID_T1E1:
6330150849Sscottl      return 1;
6331150849Sscottl    default:
6332150849Sscottl      return 0;
6333150849Sscottl    }
6334150849Sscottl  }
6335150849Sscottl
6336150849Sscottlstatic int
6337150849Sscottlbsdi_probe(struct device *parent, struct cfdata *cf, void *aux)
6338150849Sscottl  {
6339150849Sscottl  struct isa_attach_args *ia = aux;
6340150849Sscottl  pci_devaddr_t *pa = NULL;
6341150849Sscottl  pci_devres_t res;
6342150849Sscottl
6343150849Sscottl  /* This must be a PCI bus. */
6344150849Sscottl  if (ia->ia_bustype != BUS_PCI) return 0;
6345150849Sscottl
6346150849Sscottl  /* Scan PCI bus for our boards. */
6347150849Sscottl  if ((pa = pci_scan(bsdi_match)) == 0) return 0;
6348150849Sscottl
6349150849Sscottl  /* Scan config space for IO and MEM base registers and IRQ info. */
6350150849Sscottl  pci_getres(pa, &res, 1, ia);
6351150849Sscottl
6352150849Sscottl  /* Crucial: pass pci_devaddr to bsdi_attach in ia_aux. */
6353150849Sscottl  ia->ia_aux = (void *)pa;
6354150849Sscottl
6355150849Sscottl  return 1;
6356150849Sscottl  }
6357150849Sscottl
6358150849Sscottlstatic void
6359150849Sscottlbsdi_attach(struct device *parent, struct device *self, void *aux)
6360150849Sscottl  {
6361150849Sscottl  softc_t *sc = (softc_t *)self; /* device is first in softc */
6362150849Sscottl  struct isa_attach_args *ia = aux;
6363150849Sscottl  pci_devaddr_t *pa = ia->ia_aux; /* this is crucial! */
6364150849Sscottl  int error;
6365150849Sscottl
6366150849Sscottl  /* READ/WRITE_PCI_CFG need this. */
6367150849Sscottl  sc->cfgbase = *pa;
6368150849Sscottl
6369150849Sscottl  /* What kind of card are we driving? */
6370150849Sscottl  switch (READ_PCI_CFG(sc, TLP_CSID))
6371150849Sscottl    {
6372150849Sscottl    case TLP_CSID_HSSI:
6373150849Sscottl    case TLP_CSID_HSSIc:
6374150849Sscottl      sc->dev_desc =  HSSI_DESC;
6375150849Sscottl      sc->card     = &hssi_card;
6376150849Sscottl      break;
6377150849Sscottl    case TLP_CSID_T3:
6378150849Sscottl      sc->dev_desc =    T3_DESC;
6379150849Sscottl      sc->card     =   &t3_card;
6380150849Sscottl      break;
6381150849Sscottl    case TLP_CSID_SSI:
6382150849Sscottl      sc->dev_desc =   SSI_DESC;
6383150849Sscottl      sc->card     =  &ssi_card;
6384150849Sscottl      break;
6385150849Sscottl    case TLP_CSID_T1E1:
6386150849Sscottl      sc->dev_desc =  T1E1_DESC;
6387150849Sscottl      sc->card     =   &t1_card;
6388150849Sscottl      break;
6389150849Sscottl    default:
6390150849Sscottl      return;
6391150849Sscottl    }
6392150849Sscottl  printf(": %s\n", sc->dev_desc);
6393150849Sscottl
6394150849Sscottl  /* Allocate PCI memory or IO resources to access the Tulip chip CSRs. */
6395150849Sscottl  sc->csr_iobase  = ia->ia_iobase;
6396150849Sscottl  sc->csr_membase = (u_int32_t *)mapphys((vm_offset_t)ia->ia_maddr, TLP_CSR_SIZE);
6397150849Sscottl
6398150849Sscottl  /* Attach to the PCI bus. */
6399150849Sscottl  isa_establish(&sc->id, &sc->dev);
6400150849Sscottl
6401150849Sscottl  /* Allocate PCI interrupt resources for the card. */
6402150849Sscottl  sc->ih.ih_fun = bsd_interrupt;
6403150849Sscottl  sc->ih.ih_arg = sc;
6404150849Sscottl  intr_establish(ia->ia_irq, &sc->ih, DV_NET);
6405150849Sscottl
6406150849Sscottl  /* Install a shutdown hook. */
6407150849Sscottl  sc->ats.func = shutdown_card;
6408150849Sscottl  sc->ats.arg = sc;
6409150849Sscottl  atshutdown(&sc->ats, ATSH_ADD);
6410150849Sscottl
6411150849Sscottl  /* Initialize the top-half and bottom-half locks. */
6412150849Sscottl  simple_lock_init(&sc->top_lock);
6413150849Sscottl  simple_lock_init(&sc->bottom_lock);
6414150849Sscottl
6415150849Sscottl  /* Start the card and attach a kernel interface and line protocol. */
6416150849Sscottl  if ((error = attach_card(sc, ""))) detach_card(sc);
6417150849Sscottl  }
6418150849Sscottl
6419150849Sscottlstruct cfdriver lmccd =
6420150849Sscottl  {
6421150849Sscottl  .cd_devs	= NULL,
6422150849Sscottl  .cd_name	= DEVICE_NAME,
6423150849Sscottl  .cd_match	= bsdi_probe,
6424150849Sscottl  .cd_attach	= bsdi_attach,
6425150849Sscottl  .cd_class	= DV_IFNET,
6426150849Sscottl  .cd_devsize	= sizeof(softc_t),
6427150849Sscottl  };
6428150849Sscottl#endif  /* __bsdi__ */
6429150849Sscottl
6430153084Sru#ifdef __linux__
6431150849Sscottl
6432150849Sscottl/* The kernel calls this procedure when an interrupt happens. */
6433150849Sscottlstatic irqreturn_t
6434150849Sscottllinux_interrupt(int irq, void *dev, struct pt_regs *regs)
6435150849Sscottl  {
6436150849Sscottl  struct net_device *net_dev = dev;
6437150849Sscottl  softc_t *sc = dev_to_hdlc(net_dev)->priv;
6438150849Sscottl
6439150849Sscottl  /* Cut losses early if this is not our interrupt. */
6440150849Sscottl  if ((READ_CSR(TLP_STATUS) & TLP_INT_TXRX) == 0)
6441150849Sscottl    return IRQ_NONE;
6442150849Sscottl
6443150849Sscottl  /* Disable card interrupts. */
6444150849Sscottl  WRITE_CSR(TLP_INT_ENBL, TLP_INT_DISABLE);
6445150849Sscottl
6446150849Sscottl  /* Handle the card interrupt with the dev->poll method. */
6447150849Sscottl  if (netif_rx_schedule_prep(net_dev))
6448150849Sscottl    __netif_rx_schedule(net_dev);  /* NAPI - add to poll list */
6449150849Sscottl  else
6450150849Sscottl    printk("%s: interrupt while on poll list\n", NAME_UNIT);
6451150849Sscottl
6452150849Sscottl  return IRQ_HANDLED;
6453150849Sscottl  }
6454150849Sscottl
6455150849Sscottl/* This net_device method services interrupts in a softirq. */
6456150849Sscottl/* With rxintr_cleanup(), it implements input flow control. */
6457150849Sscottlstatic int
6458150849Sscottllinux_poll(struct net_device *net_dev, int *budget)
6459150849Sscottl  {
6460150849Sscottl  softc_t *sc = dev_to_hdlc(net_dev)->priv;
6461150849Sscottl  int received;
6462150849Sscottl
6463150849Sscottl  /* Yes, we do NAPI. */
6464150849Sscottl  /* Allow processing up to net_dev->quota incoming packets. */
6465150849Sscottl  /* This is the ONLY time core_interrupt() may process rx pkts. */
6466150849Sscottl  /* Otherwise (sc->quota == 0) and rxintr_cleanup() is a NOOP. */
6467150849Sscottl  sc->quota = net_dev->quota;
6468150849Sscottl
6469150849Sscottl  /* Handle the card interrupt with kernel ints enabled. */
6470150849Sscottl  /* Process rx pkts (and tx pkts, too). */
6471150849Sscottl  /* Card interrupts are disabled. */
6472150849Sscottl  core_interrupt(sc, 0);
6473150849Sscottl
6474150849Sscottl  /* Report number of rx packets processed. */
6475150849Sscottl  received = net_dev->quota - sc->quota;
6476150849Sscottl  net_dev->quota -= received;
6477150849Sscottl  *budget        -= received;
6478150849Sscottl
6479150849Sscottl  /* if quota prevented processing all rx pkts, leave rx ints disabled */
6480150849Sscottl  if (sc->quota == 0)  /* this is off by one...but harmless */
6481150849Sscottl    {
6482150849Sscottl    WRITE_CSR(TLP_INT_ENBL, TLP_INT_TX);
6483150849Sscottl    return 1; /* more pkts to handle -- reschedule */
6484150849Sscottl    }
6485150849Sscottl
6486150849Sscottl  sc->quota = 0;  /* disable rx pkt processing by rxintr_cleanup() */
6487150849Sscottl  netif_rx_complete(net_dev); /* NAPI - remove from poll list */
6488150849Sscottl
6489150849Sscottl  /* Enable card interrupts. */
6490150849Sscottl  WRITE_CSR(TLP_INT_ENBL, TLP_INT_TXRX);
6491150849Sscottl  return 0;
6492150849Sscottl  }
6493150849Sscottl
6494150849Sscottl/* These next routines are similar to BSD's ifnet kernel/driver interface. */
6495150849Sscottl
6496150849Sscottl/* This net_device method hands outgoing packets to the transmitter. */
6497150849Sscottl/* With txintr_setup(), it implements output flow control. */
6498150849Sscottl/* Called from a syscall (user context; no spinlocks). */
6499150849Sscottlstatic int
6500150849Sscottllinux_start(struct sk_buff *skb, struct net_device *net_dev)
6501150849Sscottl  {
6502150849Sscottl  softc_t *sc = dev_to_hdlc(net_dev)->priv;
6503150849Sscottl
6504150849Sscottl  if (sc->tx_skb == NULL)
6505150849Sscottl    {
6506150849Sscottl    /* Put this skb where the transmitter will see it. */
6507150849Sscottl    sc->tx_skb = skb;
6508150849Sscottl
6509150849Sscottl    /* Start the transmitter; incoming pkts are NOT processed. */
6510150849Sscottl    user_interrupt(sc, 0);
6511150849Sscottl
6512150849Sscottl    /* If the tx didn't take the skb then stop the queue. */
6513150849Sscottl    /* This can happen if another CPU is in core_interrupt(). */
6514150849Sscottl    if (sc->tx_skb != NULL) netif_stop_queue(net_dev);
6515150849Sscottl
6516150849Sscottl    return 0;
6517150849Sscottl    }
6518150849Sscottl
6519150849Sscottl  /* This shouldn't happen; skb is NOT consumed. */
6520150849Sscottl  if (netif_queue_stopped(net_dev))
6521150849Sscottl    printk("%s: dev->start() called with queue stopped\n", NAME_UNIT);
6522150849Sscottl  else
6523150849Sscottl    netif_stop_queue(net_dev);
6524150849Sscottl
6525150849Sscottl  return 1;
6526150849Sscottl  }
6527150849Sscottl
6528150849Sscottl/* This net_device method restarts the transmitter if it hangs. */
6529150849Sscottl/* Called from a softirq. */
6530150849Sscottlstatic void
6531150849Sscottllinux_timeout(struct net_device *net_dev)
6532150849Sscottl  {
6533150849Sscottl  softc_t *sc = dev_to_hdlc(net_dev)->priv;
6534150849Sscottl
6535150849Sscottl  /* Start the transmitter; incoming packets are NOT processed. */
6536150849Sscottl  user_interrupt(sc, 1);
6537150849Sscottl  }
6538150849Sscottl
6539150849Sscottl/* This net_device method handles IOCTL syscalls. */
6540150849Sscottl/* Called from a syscall (user context; no spinlocks; can sleep). */
6541150849Sscottlstatic int
6542150849Sscottllinux_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
6543150849Sscottl  {
6544150849Sscottl  softc_t *sc = dev_to_hdlc(net_dev)->priv;
6545150849Sscottl  int error = 0;
6546150849Sscottl
6547150849Sscottl  if ((cmd >= SIOCDEVPRIVATE) && (cmd <= SIOCDEVPRIVATE+15))
6548150849Sscottl    {
6549150849Sscottl    struct iohdr *iohdr = (struct iohdr *)ifr;
6550150849Sscottl    u_int16_t direction = iohdr->direction;
6551150849Sscottl    u_int16_t length = iohdr->length;
6552150849Sscottl    char *user_addr = (char *)iohdr->iohdr;
6553150849Sscottl    char *kern_addr;
6554150849Sscottl
6555150849Sscottl    if (iohdr->cookie != NGM_LMC_COOKIE) return -EINVAL;
6556150849Sscottl
6557150849Sscottl    /* Emulate a BSD-style IOCTL syscall. */
6558150849Sscottl    kern_addr = kmalloc(length, GFP_KERNEL);
6559150849Sscottl    if (kern_addr == NULL)
6560150849Sscottl      error = -ENOMEM;
6561150849Sscottl    if ((error == 0) && ((direction & DIR_IOW) != 0))
6562150849Sscottl      error = copy_from_user(kern_addr, user_addr, length);
6563150849Sscottl    if (error == 0)
6564150849Sscottl      error = -core_ioctl(sc, (unsigned long)cmd, kern_addr);
6565150849Sscottl    if ((error == 0) && ((direction & DIR_IOR) != 0))
6566150849Sscottl      error = copy_to_user(user_addr, kern_addr, length);
6567150849Sscottl    kfree(kern_addr);
6568150849Sscottl    }
6569150849Sscottl# if GEN_HDLC
6570150849Sscottl  else if (cmd == SIOCWANDEV)
6571150849Sscottl    {
6572150849Sscottl    const size_t size = sizeof(sync_serial_settings);
6573150849Sscottl
6574150849Sscottl    switch (ifr->ifr_settings.type)
6575150849Sscottl      {
6576150849Sscottl      case IF_GET_IFACE: /* get interface config */
6577150849Sscottl        {
6578150849Sscottl        ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL;
6579150849Sscottl        if (ifr->ifr_settings.size < size)
6580150849Sscottl          {
6581150849Sscottl          ifr->ifr_settings.size = size;
6582150849Sscottl          error = -ENOBUFS;
6583150849Sscottl	  }
6584150849Sscottl        else
6585150849Sscottl          {
6586150849Sscottl          if (sc->config.tx_clk_src == CFG_CLKMUX_ST)
6587150849Sscottl            sc->hdlc_settings.clock_type = CLOCK_EXT;
6588150849Sscottl          if (sc->config.tx_clk_src == CFG_CLKMUX_INT)
6589150849Sscottl            sc->hdlc_settings.clock_type = CLOCK_TXINT;
6590150849Sscottl          if (sc->config.tx_clk_src == CFG_CLKMUX_RT)
6591150849Sscottl            sc->hdlc_settings.clock_type = CLOCK_TXFROMRX;
6592150849Sscottl          sc->hdlc_settings.loopback = (sc->config.loop_back != CFG_LOOP_NONE) ? 1:0;
6593150849Sscottl          sc->hdlc_settings.clock_rate = sc->status.tx_speed;
6594150849Sscottl          error = copy_to_user(ifr->ifr_settings.ifs_ifsu.sync,
6595150849Sscottl           &sc->hdlc_settings, size);
6596150849Sscottl	  }
6597150849Sscottl        break;
6598150849Sscottl	}
6599150849Sscottl      case IF_IFACE_SYNC_SERIAL: /* set interface config */
6600150849Sscottl        {
6601150849Sscottl        if (!capable(CAP_NET_ADMIN))
6602150849Sscottl          error = -EPERM;
6603150849Sscottl        if (error == 0)
6604150849Sscottl          error = copy_from_user(&sc->hdlc_settings,
6605150849Sscottl          ifr->ifr_settings.ifs_ifsu.sync, size);
6606150849Sscottl        /* hdlc_settings are currently ignored. */
6607150849Sscottl        break;
6608150849Sscottl	}
6609150849Sscottl      default:  /* Pass the rest to the line protocol code. */
6610150849Sscottl        {
6611150849Sscottl        error = hdlc_ioctl(net_dev, ifr, cmd);
6612150849Sscottl        break;
6613150849Sscottl	}
6614150849Sscottl      }
6615150849Sscottl    }
6616150849Sscottl# endif /* GEN_HDLC */
6617150849Sscottl  else /* unknown IOCTL command */
6618150849Sscottl    error = -EINVAL;
6619150849Sscottl
6620150849Sscottl  if (DRIVER_DEBUG)
6621150849Sscottl    printk("%s: linux_ioctl; cmd=0x%08x error=%d\n",
6622150849Sscottl     NAME_UNIT, cmd, error);
6623150849Sscottl
6624150849Sscottl  return error;
6625150849Sscottl  }
6626150849Sscottl
6627150849Sscottl/* This net_device method returns a pointer to device statistics. */
6628150849Sscottlstatic struct net_device_stats *
6629150849Sscottllinux_stats(struct net_device *net_dev)
6630150849Sscottl  {
6631150849Sscottl# if GEN_HDLC
6632150849Sscottl  return &dev_to_hdlc(net_dev)->stats;
6633150849Sscottl# else
6634150849Sscottl  softc_t *sc = net_dev->priv;
6635150849Sscottl  return &sc->net_stats;
6636150849Sscottl# endif
6637150849Sscottl  }
6638150849Sscottl
6639150849Sscottl/* Called from a softirq once a second. */
6640150849Sscottlstatic void
6641150849Sscottllinux_watchdog(unsigned long softc)
6642150849Sscottl  {
6643150849Sscottl  softc_t *sc = (softc_t *)softc;
6644150849Sscottl  u_int8_t old_oper_status = sc->status.oper_status;
6645150849Sscottl  struct event_cntrs *cntrs = &sc->status.cntrs;
6646150849Sscottl  struct net_device_stats *stats = linux_stats(sc->net_dev);
6647150849Sscottl
6648150849Sscottl  core_watchdog(sc); /* updates oper_status */
6649150849Sscottl
6650150849Sscottl  /* Notice change in link status. */
6651150849Sscottl  if     ((old_oper_status != STATUS_UP) &&
6652150849Sscottl   (sc->status.oper_status == STATUS_UP))  /* link came up */
6653150849Sscottl    {
6654150849Sscottl    hdlc_set_carrier(1, sc->net_dev);
6655150849Sscottl    netif_wake_queue(sc->net_dev);
6656150849Sscottl    }
6657150849Sscottl  if     ((old_oper_status == STATUS_UP) &&
6658150849Sscottl   (sc->status.oper_status != STATUS_UP))  /* link went down */
6659150849Sscottl    {
6660150849Sscottl    hdlc_set_carrier(0, sc->net_dev);
6661150849Sscottl    netif_stop_queue(sc->net_dev);
6662150849Sscottl    }
6663150849Sscottl
6664150849Sscottl  /* Notice change in line protocol. */
6665150849Sscottl  if (sc->config.line_pkg == PKG_RAWIP)
6666150849Sscottl    {
6667150849Sscottl    sc->status.line_pkg  = PKG_RAWIP;
6668150849Sscottl    sc->status.line_prot = PROT_IP_HDLC;
6669150849Sscottl    }
6670150849Sscottl# if GEN_HDLC
6671150849Sscottl  else
6672150849Sscottl    {
6673150849Sscottl    sc->status.line_pkg  = PKG_GEN_HDLC;
6674150849Sscottl    switch (sc->hdlc_dev->proto.id)
6675150849Sscottl      {
6676150849Sscottl      case IF_PROTO_PPP:
6677150849Sscottl        sc->status.line_prot = PROT_PPP;
6678150849Sscottl        break;
6679150849Sscottl      case IF_PROTO_CISCO:
6680150849Sscottl        sc->status.line_prot = PROT_C_HDLC;
6681150849Sscottl        break;
6682150849Sscottl      case IF_PROTO_FR:
6683150849Sscottl        sc->status.line_prot = PROT_FRM_RLY;
6684150849Sscottl        break;
6685150849Sscottl      case IF_PROTO_HDLC:
6686150849Sscottl        sc->status.line_prot = PROT_IP_HDLC;
6687150849Sscottl        break;
6688150849Sscottl      case IF_PROTO_X25:
6689150849Sscottl        sc->status.line_prot = PROT_X25;
6690150849Sscottl        break;
6691150849Sscottl      case IF_PROTO_HDLC_ETH:
6692150849Sscottl        sc->status.line_prot = PROT_ETH_HDLC;
6693150849Sscottl        break;
6694150849Sscottl      default:
6695150849Sscottl        sc->status.line_prot = 0;
6696150849Sscottl        break;
6697150849Sscottl      }
6698150849Sscottl    }
6699150849Sscottl# endif /* GEN_HDLC */
6700150849Sscottl
6701150849Sscottl  /* Copy statistics from sc to net_dev for get_stats(). */
6702150849Sscottl  stats->rx_packets       = cntrs->ipackets;
6703150849Sscottl  stats->tx_packets       = cntrs->opackets;
6704150849Sscottl  stats->rx_bytes         = cntrs->ibytes;
6705150849Sscottl  stats->tx_bytes         = cntrs->obytes;
6706150849Sscottl  stats->rx_errors        = cntrs->ierrors;
6707150849Sscottl  stats->tx_errors        = cntrs->oerrors;
6708150849Sscottl  stats->rx_dropped       = cntrs->idiscards;
6709150849Sscottl  stats->tx_dropped       = cntrs->odiscards;
6710150849Sscottl  stats->rx_fifo_errors   = cntrs->fifo_over;
6711150849Sscottl  stats->tx_fifo_errors   = cntrs->fifo_under;
6712150849Sscottl  stats->rx_missed_errors = cntrs->missed;
6713150849Sscottl  stats->rx_over_errors   = cntrs->overruns;
6714150849Sscottl
6715150849Sscottl  /* Call this procedure again after one second. */
6716150849Sscottl  sc->wd_timer.expires = jiffies + HZ; /* now plus one second */
6717150849Sscottl  add_timer(&sc->wd_timer);
6718150849Sscottl  }
6719150849Sscottl
6720150849Sscottl/* This is the I/O configuration interface for Linux. */
6721150849Sscottl
6722150849Sscottl/* This net_device method is called when IFF_UP goes false. */
6723150849Sscottlstatic int
6724150849Sscottllinux_stop(struct net_device *net_dev)
6725150849Sscottl  {
6726150849Sscottl  softc_t *sc = dev_to_hdlc(net_dev)->priv;
6727150849Sscottl
6728150849Sscottl  /* Stop the card and detach from the kernel. */
6729150849Sscottl  detach_card(sc);  /* doesn't fail */
6730150849Sscottl
6731150849Sscottl  free_irq(net_dev->irq, net_dev); /* doesn't fail */
6732150849Sscottl
6733150849Sscottl  del_timer(&sc->wd_timer); /* return value ignored */
6734150849Sscottl
6735150849Sscottl  return 0;
6736150849Sscottl  }
6737150849Sscottl
6738150849Sscottl/* This net_device method is called when IFF_UP goes true. */
6739150849Sscottlstatic int
6740150849Sscottllinux_open(struct net_device *net_dev)
6741150849Sscottl  {
6742150849Sscottl  softc_t *sc = dev_to_hdlc(net_dev)->priv;
6743150849Sscottl  int error;
6744150849Sscottl
6745150849Sscottl  /* Allocate PCI interrupt resources for the card. */
6746150849Sscottl  if ((error = request_irq(net_dev->irq, &linux_interrupt, SA_SHIRQ,
6747150849Sscottl   NAME_UNIT, net_dev)))
6748150849Sscottl    {
6749150849Sscottl    printk("%s: request_irq() failed; error %d\n", NAME_UNIT, error);
6750150849Sscottl    return error;
6751150849Sscottl    }
6752150849Sscottl
6753150849Sscottl  /* Arrange to call linux_watchdog() once a second. */
6754150849Sscottl  init_timer(&sc->wd_timer);
6755150849Sscottl  sc->wd_timer.expires  = jiffies + HZ; /* now plus one second */
6756150849Sscottl  sc->wd_timer.function = &linux_watchdog;
6757150849Sscottl  sc->wd_timer.data     = (unsigned long) sc;
6758150849Sscottl  add_timer(&sc->wd_timer);
6759150849Sscottl
6760150849Sscottl  /* Start the card and attach a kernel interface and line protocol. */
6761150849Sscottl  if ((error = -attach_card(sc, "")))
6762150849Sscottl    linux_stop(net_dev);
6763150849Sscottl  else
6764150849Sscottl    {
6765150849Sscottl    net_dev->weight = sc->rxring.num_descs; /* input flow control */
6766150849Sscottl    netif_start_queue(net_dev);            /* output flow control */
6767150849Sscottl    }
6768150849Sscottl
6769150849Sscottl  return error;
6770150849Sscottl  }
6771150849Sscottl
6772150849Sscottl# if GEN_HDLC
6773150849Sscottlstatic int
6774150849Sscottlhdlc_attach(struct net_device *net_dev,
6775150849Sscottl unsigned short encoding, unsigned short parity)
6776150849Sscottl  { return 0; }
6777150849Sscottl# endif
6778150849Sscottl
6779150849Sscottl/* This pci_driver method is called during shutdown or module-unload. */
6780150849Sscottl/* This is called from user context; can sleep; no spinlocks! */
6781150849Sscottlstatic void __exit
6782150849Sscottllinux_remove(struct pci_dev *pci_dev)
6783150849Sscottl  {
6784150849Sscottl  struct net_device *net_dev = (struct net_device *)pci_get_drvdata(pci_dev);
6785150849Sscottl  softc_t *sc = dev_to_hdlc(net_dev)->priv;
6786150849Sscottl
6787150849Sscottl  if (net_dev == NULL) return;
6788150849Sscottl
6789150849Sscottl  /* Assume that linux_stop() has already been called. */
6790150849Sscottl  if (sc->flags & FLAG_NETDEV)
6791150849Sscottl# if GEN_HDLC
6792150849Sscottl    unregister_hdlc_device(net_dev);
6793150849Sscottl# else
6794150849Sscottl    unregister_netdev(net_dev);
6795150849Sscottl# endif
6796150849Sscottl
6797150849Sscottl# if (IOREF_CSR == 0)
6798150849Sscottl  if (sc->csr_membase != NULL)
6799150849Sscottl    iounmap(sc->csr_membase);
6800150849Sscottl# endif
6801150849Sscottl
6802150849Sscottl  pci_disable_device(pci_dev);
6803150849Sscottl
6804150849Sscottl  if (sc->csr_iobase != 0)
6805150849Sscottl    pci_release_regions(pci_dev);
6806150849Sscottl
6807150849Sscottl  pci_set_drvdata(pci_dev, NULL);
6808150849Sscottl
6809150849Sscottl  kfree(sc);
6810150849Sscottl  free_netdev(net_dev);
6811150849Sscottl  }
6812150849Sscottl
6813150849Sscottlstatic void
6814150849Sscottlsetup_netdev(struct net_device *net_dev)
6815150849Sscottl  {
6816150849Sscottl  /* Initialize the generic network device. */
6817180304Srwatson  /* Note similarity to BSD's lmc_ifnet_attach(). */
6818150849Sscottl  net_dev->flags           = IFF_POINTOPOINT;
6819150849Sscottl  net_dev->flags          |= IFF_RUNNING;
6820150849Sscottl  net_dev->open            = linux_open;
6821150849Sscottl  net_dev->stop            = linux_stop;
6822150849Sscottl  net_dev->hard_start_xmit = linux_start;
6823150849Sscottl  net_dev->do_ioctl        = linux_ioctl;
6824150849Sscottl  net_dev->get_stats       = linux_stats;
6825150849Sscottl  net_dev->tx_timeout      = linux_timeout;
6826150849Sscottl  net_dev->poll            = linux_poll;
6827150849Sscottl  net_dev->watchdog_timeo  = 1 * HZ;
6828150849Sscottl  net_dev->tx_queue_len    = SNDQ_MAXLEN;
6829150849Sscottl  net_dev->mtu             = MAX_DESC_LEN;
6830150849Sscottl  net_dev->type            = ARPHRD_RAWHDLC;
6831150849Sscottl/* The receiver generates frag-lists for packets >4032 bytes.   */
6832150849Sscottl/* The transmitter accepts scatter/gather lists and frag-lists. */
6833150849Sscottl/* However Linux linearizes outgoing packets since our hardware */
6834150849Sscottl/*  doesn't compute soft checksums.  All that work for nothing! */
6835150849Sscottl/*net_dev->features       |= NETIF_F_SG; */
6836150849Sscottl/*net_dev->features       |= NETIF_F_FRAGLIST; */
6837150849Sscottl  }
6838150849Sscottl
6839150849Sscottl/* This pci_driver method is called during boot or module-load. */
6840150849Sscottl/* This is called from user context; can sleep; no spinlocks! */
6841150849Sscottlstatic int __init
6842150849Sscottllinux_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
6843150849Sscottl  {
6844150849Sscottl  u_int32_t cfid, csid;
6845150849Sscottl  struct net_device *net_dev;
6846150849Sscottl  softc_t *sc;
6847150849Sscottl  int error;
6848150849Sscottl
6849150849Sscottl  /* Looking for a DEC 21140A chip on any Lan Media Corp card. */
6850150849Sscottl  pci_read_config_dword(pci_dev, TLP_CFID, &cfid);
6851150849Sscottl  if (cfid != TLP_CFID_TULIP) return -ENXIO;
6852150849Sscottl  pci_read_config_dword(pci_dev, TLP_CSID, &csid);
6853150849Sscottl  switch (csid)
6854150849Sscottl    {
6855150849Sscottl    case TLP_CSID_HSSI:
6856150849Sscottl    case TLP_CSID_HSSIc:
6857150849Sscottl    case TLP_CSID_T3:
6858150849Sscottl    case TLP_CSID_SSI:
6859150849Sscottl    case TLP_CSID_T1E1:
6860150849Sscottl      break;
6861150849Sscottl    default:
6862150849Sscottl      return -ENXIO;
6863150849Sscottl    }
6864150849Sscottl
6865150849Sscottl  /* Declare that these cards use 32-bit single-address PCI cycles. */
6866150849Sscottl  if ((error = pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)))
6867150849Sscottl    {
6868150849Sscottl    printk("%s: pci_set_dma_mask() failed; error %d\n", DEVICE_NAME, error);
6869150849Sscottl    return error;
6870150849Sscottl    }
6871150849Sscottl  pci_set_consistent_dma_mask(pci_dev, DMA_32BIT_MASK); /* can't fail */
6872150849Sscottl
6873150849Sscottl# if GEN_HDLC /* generic-hdlc line protocols */
6874150849Sscottl
6875150849Sscottl  /* device driver instance data, aka Soft Context or sc */
6876150849Sscottl  if ((sc = kmalloc(sizeof(softc_t), GFP_KERNEL)) == NULL)
6877150849Sscottl    {
6878150849Sscottl    printk("%s: kmalloc() failed\n", DEVICE_NAME);
6879150849Sscottl    return -ENOMEM;
6880150849Sscottl    }
6881150849Sscottl  memset(sc, 0, sizeof(softc_t));
6882150849Sscottl
6883150849Sscottl  /* Allocate space for the HDLC network device struct. */
6884150849Sscottl  if ((net_dev = alloc_hdlcdev(sc)) == NULL)
6885150849Sscottl    {
6886150849Sscottl    printk("%s: alloc_hdlcdev() failed\n", DEVICE_NAME);
6887150849Sscottl    kfree(sc);
6888150849Sscottl    return -ENOMEM;
6889150849Sscottl    }
6890150849Sscottl
6891150849Sscottl  /* Initialize the network device struct. */
6892150849Sscottl  setup_netdev(net_dev);
6893150849Sscottl
6894150849Sscottl  /* Initialize the HDLC extension to the network device. */
6895150849Sscottl  sc->hdlc_dev         = dev_to_hdlc(net_dev);
6896150849Sscottl  sc->hdlc_dev->attach = hdlc_attach; /* noop for this driver */
6897150849Sscottl  sc->hdlc_dev->xmit   = linux_start; /* the REAL hard_start_xmit() */
6898150849Sscottl
6899150849Sscottl# else /* GEN_HDLC */ /* no line protocol. */
6900150849Sscottl
6901150849Sscottl  /* Allocate space for the bare network device struct. */
6902150849Sscottl  net_dev = alloc_netdev(sizeof(softc_t), DEVICE_NAME"%d", setup_netdev);
6903150849Sscottl  if (net_dev == NULL)
6904150849Sscottl    {
6905150849Sscottl    printk("%s: alloc_netdev() failed\n", DEVICE_NAME);
6906150849Sscottl    return -ENOMEM;
6907150849Sscottl    }
6908150849Sscottl  /* device driver instance data, aka Soft Context or sc */
6909150849Sscottl  sc = net_dev->priv;
6910150849Sscottl
6911150849Sscottl# endif /* GEN_HDLC */
6912150849Sscottl
6913150849Sscottl  sc->net_dev = net_dev;  /* NAME_UNIT macro needs this */
6914150849Sscottl  sc->pci_dev = pci_dev;  /* READ/WRITE_PCI_CFG macros need this */
6915150849Sscottl
6916150849Sscottl  /* Cross-link pci_dev and net_dev. */
6917150849Sscottl  pci_set_drvdata(pci_dev, net_dev);      /* pci_dev->driver_data = net_dev */
6918150849Sscottl  SET_NETDEV_DEV(net_dev, &pci_dev->dev); /* net_dev->class_dev.dev = &pci_dev->dev */
6919150849Sscottl  SET_MODULE_OWNER(net_dev);              /* ??? NOOP in linux-2.6.3. ??? */
6920150849Sscottl
6921150849Sscottl  /* Sets cfcs.io and cfcs.mem; sets pci_dev->irq based on cfit.int */
6922150849Sscottl  if ((error = pci_enable_device(pci_dev)))
6923150849Sscottl    {
6924150849Sscottl    printk("%s: pci_enable_device() failed; error %d\n", DEVICE_NAME, error);
6925150849Sscottl    linux_remove(pci_dev);
6926150849Sscottl    return error;
6927150849Sscottl    }
6928150849Sscottl  net_dev->irq = pci_dev->irq; /* linux_open/stop need this */
6929150849Sscottl
6930150849Sscottl  /* Allocate PCI memory and IO resources to access the Tulip chip CSRs. */
6931150849Sscottl  if ((error = pci_request_regions(pci_dev, DEVICE_NAME)))
6932150849Sscottl    {
6933150849Sscottl    printk("%s: pci_request_regions() failed; error %d\n", DEVICE_NAME, error);
6934150849Sscottl    linux_remove(pci_dev);
6935150849Sscottl    return error;
6936150849Sscottl    }
6937150849Sscottl  net_dev->base_addr = pci_resource_start(pci_dev, 0);
6938150849Sscottl  net_dev->mem_start = pci_resource_start(pci_dev, 1);
6939150849Sscottl  net_dev->mem_end   = pci_resource_end(pci_dev, 1);
6940150849Sscottl  sc->csr_iobase     = net_dev->base_addr;
6941150849Sscottl
6942150849Sscottl# if (IOREF_CSR == 0)
6943150849Sscottl  sc->csr_membase = ioremap_nocache(net_dev->mem_start, TLP_CSR_SIZE);
6944150849Sscottl  if (sc->csr_membase == NULL)
6945150849Sscottl    {
6946150849Sscottl    printk("%s: ioremap_nocache() failed\n", DEVICE_NAME);
6947150849Sscottl    linux_remove(pci_dev);
6948150849Sscottl    return -EFAULT;
6949150849Sscottl    }
6950150849Sscottl# endif
6951150849Sscottl
6952150849Sscottl  /* Sets cfcs.master, enabling PCI DMA; checks latency timer value. */
6953150849Sscottl  pci_set_master(pci_dev); /* Later, attach_card() does this too. */
6954150849Sscottl
6955150849Sscottl  /* Initialize the top-half and bottom-half locks. */
6956150849Sscottl  /* Top_lock must be initialized before net_dev is registered. */
6957150849Sscottl  init_MUTEX(&sc->top_lock);
6958150849Sscottl  spin_lock_init(&sc->bottom_lock);
6959150849Sscottl
6960150849Sscottl# if GEN_HDLC
6961150849Sscottl  if ((error = register_hdlc_device(net_dev)))
6962150849Sscottl    {
6963150849Sscottl    printk("%s: register_hdlc_device() failed; error %d\n", DEVICE_NAME, error);
6964150849Sscottl    linux_remove(pci_dev);
6965150849Sscottl    return error;
6966150849Sscottl    }
6967150849Sscottl# else
6968150849Sscottl  if ((error = register_netdev(net_dev)))
6969150849Sscottl    {
6970150849Sscottl    printk("%s: register_netdev() failed; error %d\n", DEVICE_NAME, error);
6971150849Sscottl    linux_remove(pci_dev);
6972150849Sscottl    return error;
6973150849Sscottl    }
6974150849Sscottl# endif
6975150849Sscottl  /* The NAME_UNIT macro now works.  Use DEVICE_NAME before this. */
6976150849Sscottl  sc->flags |= FLAG_NETDEV;
6977150849Sscottl
6978150849Sscottl  /* What kind of card are we driving? */
6979150849Sscottl  switch (READ_PCI_CFG(sc, TLP_CSID))
6980150849Sscottl    {
6981150849Sscottl    case TLP_CSID_HSSI:
6982150849Sscottl    case TLP_CSID_HSSIc:
6983150849Sscottl      sc->dev_desc =  HSSI_DESC;
6984150849Sscottl      sc->card     = &hssi_card;
6985150849Sscottl      break;
6986150849Sscottl    case TLP_CSID_T3:
6987150849Sscottl      sc->dev_desc =    T3_DESC;
6988150849Sscottl      sc->card     =   &t3_card;
6989150849Sscottl      break;
6990150849Sscottl    case TLP_CSID_SSI:
6991150849Sscottl      sc->dev_desc =   SSI_DESC;
6992150849Sscottl      sc->card     =  &ssi_card;
6993150849Sscottl      break;
6994150849Sscottl    case TLP_CSID_T1E1:
6995150849Sscottl      sc->dev_desc =  T1E1_DESC;
6996150849Sscottl      sc->card     =   &t1_card;
6997150849Sscottl      break;
6998150849Sscottl    default: /* shouldn't happen! */
6999150849Sscottl      linux_remove(pci_dev);
7000150849Sscottl      return -ENXIO;
7001150849Sscottl    }
7002150849Sscottl
7003150849Sscottl  /* Announce the hardware on the console. */
7004150849Sscottl  printk("%s: <%s> io 0x%04lx/9 mem 0x%08lx/25 rom 0x%08lx/14 irq %d pci %s\n",
7005150849Sscottl   NAME_UNIT, sc->dev_desc, pci_resource_start(pci_dev, 0),
7006150849Sscottl   pci_resource_start(pci_dev, 1), pci_resource_start(pci_dev, 6),
7007150849Sscottl   pci_dev->irq, pci_name(pci_dev));
7008150849Sscottl
7009150849Sscottl  return 0;
7010150849Sscottl  }
7011150849Sscottl
7012150849Sscottl/* This pci driver knows how to drive these devices: */
7013150849Sscottlstatic __initdata struct pci_device_id pci_device_id_tbl[] =
7014150849Sscottl  {
7015150849Sscottl  /* Looking for a DEC 21140A chip on any Lan Media Corp card. */
7016150849Sscottl    { 0x1011, 0x0009, 0x1376, PCI_ANY_ID, 0, 0, 0 },
7017150849Sscottl    {      0,      0,      0,          0, 0, 0, 0 }
7018150849Sscottl  };
7019150849SscottlMODULE_DEVICE_TABLE(pci, pci_device_id_tbl);
7020150849Sscottl
7021150849Sscottlstatic struct pci_driver pci_driver =
7022150849Sscottl  {
7023150849Sscottl  .name	    = DEVICE_NAME,
7024150849Sscottl  .id_table = pci_device_id_tbl,
7025150849Sscottl  .probe    = linux_probe,
7026150849Sscottl  .remove   = __devexit_p(linux_remove),
7027150849Sscottl  /* This driver does not suspend and resume. */
7028150849Sscottl  };
7029150849Sscottl
7030150849Sscottl/* This ultimately calls our pci_driver.probe() method. */
7031150849Sscottlstatic int  __init linux_modload(void)
7032150849Sscottl  { return pci_module_init(&pci_driver); }
7033150849Sscottlmodule_init(linux_modload);
7034150849Sscottl
7035150849Sscottl/* This ultimately calls our pci_driver.remove() method. */
7036150849Sscottlstatic void __exit linux_modunload(void)
7037150849Sscottl  { pci_unregister_driver(&pci_driver); }
7038150849Sscottlmodule_exit(linux_modunload);
7039150849Sscottl
7040150849SscottlMODULE_LICENSE("Dual BSD/GPL");
7041150849SscottlMODULE_DESCRIPTION("Device driver for SBE/LMC Wide-Area Network cards");
7042150849SscottlMODULE_AUTHOR("David Boggs <boggs@boggs.palo-alto.ca.us>");
7043150849Sscottl
7044150849Sscottl#endif /* __linux__ */
7045