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