if_pcn.c revision 122625
1235783Skib/* 2235783Skib * Copyright (c) 2000 Berkeley Software Design, Inc. 3235783Skib * Copyright (c) 1997, 1998, 1999, 2000 4235783Skib * Bill Paul <wpaul@osd.bsdi.com>. All rights reserved. 5235783Skib * 6235783Skib * Redistribution and use in source and binary forms, with or without 7235783Skib * modification, are permitted provided that the following conditions 8235783Skib * are met: 9235783Skib * 1. Redistributions of source code must retain the above copyright 10235783Skib * notice, this list of conditions and the following disclaimer. 11235783Skib * 2. Redistributions in binary form must reproduce the above copyright 12235783Skib * notice, this list of conditions and the following disclaimer in the 13235783Skib * documentation and/or other materials provided with the distribution. 14235783Skib * 3. All advertising materials mentioning features or use of this software 15235783Skib * must display the following acknowledgement: 16235783Skib * This product includes software developed by Bill Paul. 17235783Skib * 4. Neither the name of the author nor the names of any co-contributors 18235783Skib * may be used to endorse or promote products derived from this software 19235783Skib * without specific prior written permission. 20235783Skib * 21235783Skib * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 22235783Skib * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23235783Skib * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24235783Skib * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 25235783Skib * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26235783Skib * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27235783Skib * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28235783Skib * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29235783Skib * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30235783Skib * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31235783Skib * THE POSSIBILITY OF SUCH DAMAGE. 32235783Skib */ 33235783Skib 34235783Skib/* 35235783Skib * AMD Am79c972 fast ethernet PCI NIC driver. Datatheets are available 36235783Skib * from http://www.amd.com. 37235783Skib * 38235783Skib * The AMD PCnet/PCI controllers are more advanced and functional 39235783Skib * versions of the venerable 7990 LANCE. The PCnet/PCI chips retain 40235783Skib * backwards compatibility with the LANCE and thus can be made 41235783Skib * to work with older LANCE drivers. This is in fact how the 42235783Skib * PCnet/PCI chips were supported in FreeBSD originally. The trouble 43235783Skib * is that the PCnet/PCI devices offer several performance enhancements 44235783Skib * which can't be exploited in LANCE compatibility mode. Chief among 45235783Skib * these enhancements is the ability to perform PCI DMA operations 46235783Skib * using 32-bit addressing (which eliminates the need for ISA 47235783Skib * bounce-buffering), and special receive buffer alignment (which 48235783Skib * allows the receive handler to pass packets to the upper protocol 49235783Skib * layers without copying on both the x86 and alpha platforms). 50235783Skib */ 51235783Skib 52235783Skib#include <sys/cdefs.h> 53235783Skib__FBSDID("$FreeBSD: head/sys/pci/if_pcn.c 122625 2003-11-13 20:55:53Z obrien $"); 54235783Skib 55235783Skib#include <sys/param.h> 56235783Skib#include <sys/systm.h> 57235783Skib#include <sys/sockio.h> 58235783Skib#include <sys/mbuf.h> 59235783Skib#include <sys/malloc.h> 60235783Skib#include <sys/kernel.h> 61235783Skib#include <sys/socket.h> 62235783Skib 63235783Skib#include <net/if.h> 64235783Skib#include <net/if_arp.h> 65235783Skib#include <net/ethernet.h> 66235783Skib#include <net/if_dl.h> 67235783Skib#include <net/if_media.h> 68235783Skib 69235783Skib#include <net/bpf.h> 70235783Skib 71235783Skib#include <vm/vm.h> /* for vtophys */ 72235783Skib#include <vm/pmap.h> /* for vtophys */ 73235783Skib#include <machine/bus_pio.h> 74235783Skib#include <machine/bus_memio.h> 75235783Skib#include <machine/bus.h> 76235783Skib#include <machine/resource.h> 77235783Skib#include <sys/bus.h> 78235783Skib#include <sys/rman.h> 79235783Skib 80235783Skib#include <dev/mii/mii.h> 81235783Skib#include <dev/mii/miivar.h> 82235783Skib 83235783Skib#include <dev/pci/pcireg.h> 84235783Skib#include <dev/pci/pcivar.h> 85235783Skib 86235783Skib#define PCN_USEIOSPACE 87235783Skib 88235783Skib#include <pci/if_pcnreg.h> 89235783Skib 90235783SkibMODULE_DEPEND(pcn, pci, 1, 1, 1); 91235783SkibMODULE_DEPEND(pcn, ether, 1, 1, 1); 92235783SkibMODULE_DEPEND(pcn, miibus, 1, 1, 1); 93235783Skib 94235783Skib/* "controller miibus0" required. See GENERIC if you get errors here. */ 95235783Skib#include "miibus_if.h" 96235783Skib 97235783Skib/* 98235783Skib * Various supported device vendors/types and their names. 99235783Skib */ 100235783Skibstatic struct pcn_type pcn_devs[] = { 101235783Skib { PCN_VENDORID, PCN_DEVICEID_PCNET, "AMD PCnet/PCI 10/100BaseTX" }, 102235783Skib { PCN_VENDORID, PCN_DEVICEID_HOME, "AMD PCnet/Home HomePNA" }, 103235783Skib { 0, 0, NULL } 104235783Skib}; 105235783Skib 106235783Skibstatic u_int32_t pcn_csr_read (struct pcn_softc *, int); 107235783Skibstatic u_int16_t pcn_csr_read16 (struct pcn_softc *, int); 108235783Skibstatic u_int16_t pcn_bcr_read16 (struct pcn_softc *, int); 109235783Skibstatic void pcn_csr_write (struct pcn_softc *, int, int); 110235783Skibstatic u_int32_t pcn_bcr_read (struct pcn_softc *, int); 111235783Skibstatic void pcn_bcr_write (struct pcn_softc *, int, int); 112235783Skib 113235783Skibstatic int pcn_probe (device_t); 114235783Skibstatic int pcn_attach (device_t); 115235783Skibstatic int pcn_detach (device_t); 116235783Skib 117235783Skibstatic int pcn_newbuf (struct pcn_softc *, int, struct mbuf *); 118235783Skibstatic int pcn_encap (struct pcn_softc *, 119235783Skib struct mbuf *, u_int32_t *); 120235783Skibstatic void pcn_rxeof (struct pcn_softc *); 121235783Skibstatic void pcn_txeof (struct pcn_softc *); 122235783Skibstatic void pcn_intr (void *); 123235783Skibstatic void pcn_tick (void *); 124235783Skibstatic void pcn_start (struct ifnet *); 125235783Skibstatic int pcn_ioctl (struct ifnet *, u_long, caddr_t); 126235783Skibstatic void pcn_init (void *); 127235783Skibstatic void pcn_stop (struct pcn_softc *); 128235783Skibstatic void pcn_watchdog (struct ifnet *); 129235783Skibstatic void pcn_shutdown (device_t); 130235783Skibstatic int pcn_ifmedia_upd (struct ifnet *); 131235783Skibstatic void pcn_ifmedia_sts (struct ifnet *, struct ifmediareq *); 132235783Skib 133235783Skibstatic int pcn_miibus_readreg (device_t, int, int); 134235783Skibstatic int pcn_miibus_writereg (device_t, int, int, int); 135235783Skibstatic void pcn_miibus_statchg (device_t); 136235783Skib 137235783Skibstatic void pcn_setfilt (struct ifnet *); 138235783Skibstatic void pcn_setmulti (struct pcn_softc *); 139235783Skibstatic u_int32_t pcn_mchash (caddr_t); 140235783Skibstatic void pcn_reset (struct pcn_softc *); 141235783Skibstatic int pcn_list_rx_init (struct pcn_softc *); 142235783Skibstatic int pcn_list_tx_init (struct pcn_softc *); 143235783Skib 144235783Skib#ifdef PCN_USEIOSPACE 145235783Skib#define PCN_RES SYS_RES_IOPORT 146235783Skib#define PCN_RID PCN_PCI_LOIO 147235783Skib#else 148235783Skib#define PCN_RES SYS_RES_MEMORY 149235783Skib#define PCN_RID PCN_PCI_LOMEM 150235783Skib#endif 151235783Skib 152235783Skibstatic device_method_t pcn_methods[] = { 153235783Skib /* Device interface */ 154235783Skib DEVMETHOD(device_probe, pcn_probe), 155235783Skib DEVMETHOD(device_attach, pcn_attach), 156235783Skib DEVMETHOD(device_detach, pcn_detach), 157235783Skib DEVMETHOD(device_shutdown, pcn_shutdown), 158235783Skib 159235783Skib /* bus interface */ 160235783Skib DEVMETHOD(bus_print_child, bus_generic_print_child), 161235783Skib DEVMETHOD(bus_driver_added, bus_generic_driver_added), 162235783Skib 163235783Skib /* MII interface */ 164235783Skib DEVMETHOD(miibus_readreg, pcn_miibus_readreg), 165235783Skib DEVMETHOD(miibus_writereg, pcn_miibus_writereg), 166235783Skib DEVMETHOD(miibus_statchg, pcn_miibus_statchg), 167235783Skib 168235783Skib { 0, 0 } 169235783Skib}; 170235783Skib 171235783Skibstatic driver_t pcn_driver = { 172235783Skib "pcn", 173235783Skib pcn_methods, 174235783Skib sizeof(struct pcn_softc) 175235783Skib}; 176235783Skib 177235783Skibstatic devclass_t pcn_devclass; 178235783Skib 179235783SkibDRIVER_MODULE(pcn, pci, pcn_driver, pcn_devclass, 0, 0); 180235783SkibDRIVER_MODULE(miibus, pcn, miibus_driver, miibus_devclass, 0, 0); 181235783Skib 182235783Skib#define PCN_CSR_SETBIT(sc, reg, x) \ 183235783Skib pcn_csr_write(sc, reg, pcn_csr_read(sc, reg) | (x)) 184235783Skib 185235783Skib#define PCN_CSR_CLRBIT(sc, reg, x) \ 186235783Skib pcn_csr_write(sc, reg, pcn_csr_read(sc, reg) & ~(x)) 187235783Skib 188235783Skib#define PCN_BCR_SETBIT(sc, reg, x) \ 189235783Skib pcn_bcr_write(sc, reg, pcn_bcr_read(sc, reg) | (x)) 190235783Skib 191235783Skib#define PCN_BCR_CLRBIT(sc, reg, x) \ 192235783Skib pcn_bcr_write(sc, reg, pcn_bcr_read(sc, reg) & ~(x)) 193235783Skib 194235783Skibstatic u_int32_t 195235783Skibpcn_csr_read(sc, reg) 196235783Skib struct pcn_softc *sc; 197235783Skib int reg; 198235783Skib{ 199235783Skib CSR_WRITE_4(sc, PCN_IO32_RAP, reg); 200235783Skib return(CSR_READ_4(sc, PCN_IO32_RDP)); 201235783Skib} 202235783Skib 203235783Skibstatic u_int16_t 204235783Skibpcn_csr_read16(sc, reg) 205235783Skib struct pcn_softc *sc; 206235783Skib int reg; 207235783Skib{ 208235783Skib CSR_WRITE_2(sc, PCN_IO16_RAP, reg); 209235783Skib return(CSR_READ_2(sc, PCN_IO16_RDP)); 210235783Skib} 211235783Skib 212235783Skibstatic void 213235783Skibpcn_csr_write(sc, reg, val) 214235783Skib struct pcn_softc *sc; 215235783Skib int reg; 216235783Skib int val; 217235783Skib{ 218235783Skib CSR_WRITE_4(sc, PCN_IO32_RAP, reg); 219235783Skib CSR_WRITE_4(sc, PCN_IO32_RDP, val); 220235783Skib return; 221235783Skib} 222235783Skib 223235783Skibstatic u_int32_t 224235783Skibpcn_bcr_read(sc, reg) 225235783Skib struct pcn_softc *sc; 226235783Skib int reg; 227235783Skib{ 228235783Skib CSR_WRITE_4(sc, PCN_IO32_RAP, reg); 229235783Skib return(CSR_READ_4(sc, PCN_IO32_BDP)); 230235783Skib} 231235783Skib 232235783Skibstatic u_int16_t 233235783Skibpcn_bcr_read16(sc, reg) 234235783Skib struct pcn_softc *sc; 235235783Skib int reg; 236235783Skib{ 237235783Skib CSR_WRITE_2(sc, PCN_IO16_RAP, reg); 238235783Skib return(CSR_READ_2(sc, PCN_IO16_BDP)); 239235783Skib} 240235783Skib 241235783Skibstatic void 242235783Skibpcn_bcr_write(sc, reg, val) 243235783Skib struct pcn_softc *sc; 244235783Skib int reg; 245235783Skib int val; 246235783Skib{ 247235783Skib CSR_WRITE_4(sc, PCN_IO32_RAP, reg); 248235783Skib CSR_WRITE_4(sc, PCN_IO32_BDP, val); 249235783Skib return; 250235783Skib} 251235783Skib 252235783Skibstatic int 253235783Skibpcn_miibus_readreg(dev, phy, reg) 254235783Skib device_t dev; 255235783Skib int phy, reg; 256235783Skib{ 257235783Skib struct pcn_softc *sc; 258235783Skib int val; 259235783Skib 260235783Skib sc = device_get_softc(dev); 261235783Skib 262235783Skib if (sc->pcn_phyaddr && phy > sc->pcn_phyaddr) 263235783Skib return(0); 264235783Skib 265235783Skib pcn_bcr_write(sc, PCN_BCR_MIIADDR, reg | (phy << 5)); 266235783Skib val = pcn_bcr_read(sc, PCN_BCR_MIIDATA) & 0xFFFF; 267235783Skib if (val == 0xFFFF) 268235783Skib return(0); 269235783Skib 270235783Skib sc->pcn_phyaddr = phy; 271235783Skib 272235783Skib return(val); 273235783Skib} 274235783Skib 275235783Skibstatic int 276235783Skibpcn_miibus_writereg(dev, phy, reg, data) 277235783Skib device_t dev; 278235783Skib int phy, reg, data; 279235783Skib{ 280235783Skib struct pcn_softc *sc; 281235783Skib 282235783Skib sc = device_get_softc(dev); 283235783Skib 284235783Skib pcn_bcr_write(sc, PCN_BCR_MIIADDR, reg | (phy << 5)); 285235783Skib pcn_bcr_write(sc, PCN_BCR_MIIDATA, data); 286235783Skib 287235783Skib return(0); 288235783Skib} 289235783Skib 290235783Skibstatic void 291235783Skibpcn_miibus_statchg(dev) 292235783Skib device_t dev; 293235783Skib{ 294235783Skib struct pcn_softc *sc; 295235783Skib struct mii_data *mii; 296235783Skib 297235783Skib sc = device_get_softc(dev); 298235783Skib mii = device_get_softc(sc->pcn_miibus); 299235783Skib 300235783Skib if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { 301235783Skib PCN_BCR_SETBIT(sc, PCN_BCR_DUPLEX, PCN_DUPLEX_FDEN); 302235783Skib } else { 303235783Skib PCN_BCR_CLRBIT(sc, PCN_BCR_DUPLEX, PCN_DUPLEX_FDEN); 304235783Skib } 305235783Skib 306235783Skib return; 307235783Skib} 308235783Skib 309235783Skib#define DC_POLY 0xEDB88320 310235783Skib 311235783Skibstatic u_int32_t 312235783Skibpcn_mchash(addr) 313235783Skib caddr_t addr; 314235783Skib{ 315235783Skib u_int32_t crc; 316235783Skib int idx, bit; 317235783Skib u_int8_t data; 318235783Skib 319235783Skib /* Compute CRC for the address value. */ 320235783Skib crc = 0xFFFFFFFF; /* initial value */ 321235783Skib 322235783Skib for (idx = 0; idx < 6; idx++) { 323235783Skib for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) 324235783Skib crc = (crc >> 1) ^ (((crc ^ data) & 1) ? DC_POLY : 0); 325235783Skib } 326235783Skib 327235783Skib return ((crc >> 26) & 0x3F); 328235783Skib} 329235783Skib 330235783Skibstatic void 331235783Skibpcn_setmulti(sc) 332235783Skib struct pcn_softc *sc; 333235783Skib{ 334235783Skib struct ifnet *ifp; 335235783Skib struct ifmultiaddr *ifma; 336235783Skib u_int32_t h, i; 337235783Skib u_int16_t hashes[4] = { 0, 0, 0, 0 }; 338235783Skib 339235783Skib ifp = &sc->arpcom.ac_if; 340235783Skib 341235783Skib PCN_CSR_SETBIT(sc, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SPND); 342235783Skib 343235783Skib if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 344235783Skib for (i = 0; i < 4; i++) 345235783Skib pcn_csr_write(sc, PCN_CSR_MAR0 + i, 0xFFFF); 346235783Skib PCN_CSR_CLRBIT(sc, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SPND); 347235783Skib return; 348235783Skib } 349235783Skib 350235783Skib /* first, zot all the existing hash bits */ 351235783Skib for (i = 0; i < 4; i++) 352235783Skib pcn_csr_write(sc, PCN_CSR_MAR0 + i, 0); 353235783Skib 354235783Skib /* now program new ones */ 355235783Skib TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 356235783Skib if (ifma->ifma_addr->sa_family != AF_LINK) 357235783Skib continue; 358235783Skib h = pcn_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 359235783Skib hashes[h >> 4] |= 1 << (h & 0xF); 360235783Skib } 361235783Skib 362235783Skib for (i = 0; i < 4; i++) 363235783Skib pcn_csr_write(sc, PCN_CSR_MAR0 + i, hashes[i]); 364235783Skib 365235783Skib PCN_CSR_CLRBIT(sc, PCN_CSR_EXTCTL1, PCN_EXTCTL1_SPND); 366235783Skib 367235783Skib return; 368235783Skib} 369235783Skib 370235783Skibstatic void 371235783Skibpcn_reset(sc) 372235783Skib struct pcn_softc *sc; 373235783Skib{ 374235783Skib /* 375235783Skib * Issue a reset by reading from the RESET register. 376235783Skib * Note that we don't know if the chip is operating in 377235783Skib * 16-bit or 32-bit mode at this point, so we attempt 378235783Skib * to reset the chip both ways. If one fails, the other 379235783Skib * will succeed. 380235783Skib */ 381235783Skib CSR_READ_2(sc, PCN_IO16_RESET); 382235783Skib CSR_READ_4(sc, PCN_IO32_RESET); 383235783Skib 384235783Skib /* Wait a little while for the chip to get its brains in order. */ 385235783Skib DELAY(1000); 386235783Skib 387235783Skib /* Select 32-bit (DWIO) mode */ 388235783Skib CSR_WRITE_4(sc, PCN_IO32_RDP, 0); 389235783Skib 390235783Skib /* Select software style 3. */ 391235783Skib pcn_bcr_write(sc, PCN_BCR_SSTYLE, PCN_SWSTYLE_PCNETPCI_BURST); 392235783Skib 393235783Skib return; 394235783Skib} 395235783Skib 396235783Skib/* 397235783Skib * Probe for an AMD chip. Check the PCI vendor and device 398235783Skib * IDs against our list and return a device name if we find a match. 399235783Skib */ 400235783Skibstatic int 401235783Skibpcn_probe(dev) 402235783Skib device_t dev; 403235783Skib{ 404235783Skib struct pcn_type *t; 405235783Skib struct pcn_softc *sc; 406235783Skib int rid; 407235783Skib u_int32_t chip_id; 408235783Skib 409235783Skib t = pcn_devs; 410235783Skib sc = device_get_softc(dev); 411235783Skib 412235783Skib while(t->pcn_name != NULL) { 413235783Skib if ((pci_get_vendor(dev) == t->pcn_vid) && 414235783Skib (pci_get_device(dev) == t->pcn_did)) { 415235783Skib /* 416235783Skib * Temporarily map the I/O space 417235783Skib * so we can read the chip ID register. 418235783Skib */ 419235783Skib rid = PCN_RID; 420235783Skib sc->pcn_res = bus_alloc_resource(dev, PCN_RES, &rid, 421235783Skib 0, ~0, 1, RF_ACTIVE); 422235783Skib if (sc->pcn_res == NULL) { 423235783Skib device_printf(dev, 424235783Skib "couldn't map ports/memory\n"); 425235783Skib return(ENXIO); 426235783Skib } 427235783Skib sc->pcn_btag = rman_get_bustag(sc->pcn_res); 428235783Skib sc->pcn_bhandle = rman_get_bushandle(sc->pcn_res); 429235783Skib mtx_init(&sc->pcn_mtx, 430235783Skib device_get_nameunit(dev), MTX_NETWORK_LOCK, 431235783Skib MTX_DEF); 432235783Skib PCN_LOCK(sc); 433235783Skib /* 434235783Skib * Note: we can *NOT* put the chip into 435235783Skib * 32-bit mode yet. The lnc driver will only 436235783Skib * work in 16-bit mode, and once the chip 437235783Skib * goes into 32-bit mode, the only way to 438235783Skib * get it out again is with a hardware reset. 439235783Skib * So if pcn_probe() is called before the 440235783Skib * lnc driver's probe routine, the chip will 441235783Skib * be locked into 32-bit operation and the lnc 442235783Skib * driver will be unable to attach to it. 443235783Skib * Note II: if the chip happens to already 444235783Skib * be in 32-bit mode, we still need to check 445235783Skib * the chip ID, but first we have to detect 446235783Skib * 32-bit mode using only 16-bit operations. 447235783Skib * The safest way to do this is to read the 448235783Skib * PCI subsystem ID from BCR23/24 and compare 449235783Skib * that with the value read from PCI config 450235783Skib * space. 451235783Skib */ 452235783Skib chip_id = pcn_bcr_read16(sc, PCN_BCR_PCISUBSYSID); 453235783Skib chip_id <<= 16; 454235783Skib chip_id |= pcn_bcr_read16(sc, PCN_BCR_PCISUBVENID); 455235783Skib /* 456235783Skib * Note III: the test for 0x10001000 is a hack to 457235783Skib * pacify VMware, who's pseudo-PCnet interface is 458235783Skib * broken. Reading the subsystem register from PCI 459235783Skib * config space yeilds 0x00000000 while reading the 460235783Skib * same value from I/O space yeilds 0x10001000. It's 461235783Skib * not supposed to be that way. 462235783Skib */ 463235783Skib if (chip_id == pci_read_config(dev, 464235783Skib PCIR_SUBVEND_0, 4) || chip_id == 0x10001000) { 465235783Skib /* We're in 16-bit mode. */ 466235783Skib chip_id = pcn_csr_read16(sc, PCN_CSR_CHIPID1); 467235783Skib chip_id <<= 16; 468235783Skib chip_id |= pcn_csr_read16(sc, PCN_CSR_CHIPID0); 469235783Skib } else { 470235783Skib /* We're in 32-bit mode. */ 471235783Skib chip_id = pcn_csr_read(sc, PCN_CSR_CHIPID1); 472235783Skib chip_id <<= 16; 473235783Skib chip_id |= pcn_csr_read(sc, PCN_CSR_CHIPID0); 474235783Skib } 475235783Skib bus_release_resource(dev, PCN_RES, 476235783Skib PCN_RID, sc->pcn_res); 477235783Skib PCN_UNLOCK(sc); 478235783Skib mtx_destroy(&sc->pcn_mtx); 479235783Skib chip_id >>= 12; 480235783Skib sc->pcn_type = chip_id & PART_MASK; 481235783Skib switch(sc->pcn_type) { 482235783Skib case Am79C971: 483235783Skib case Am79C972: 484235783Skib case Am79C973: 485235783Skib case Am79C975: 486235783Skib case Am79C976: 487235783Skib case Am79C978: 488235783Skib break; 489235783Skib default: 490235783Skib return(ENXIO); 491235783Skib } 492235783Skib device_set_desc(dev, t->pcn_name); 493235783Skib return(0); 494235783Skib } 495235783Skib t++; 496235783Skib } 497235783Skib 498235783Skib return(ENXIO); 499235783Skib} 500235783Skib 501235783Skib/* 502235783Skib * Attach the interface. Allocate softc structures, do ifmedia 503235783Skib * setup and ethernet/BPF attach. 504235783Skib */ 505235783Skibstatic int 506235783Skibpcn_attach(dev) 507235783Skib device_t dev; 508235783Skib{ 509235783Skib u_int32_t eaddr[2]; 510235783Skib struct pcn_softc *sc; 511235783Skib struct ifnet *ifp; 512235783Skib int unit, error = 0, rid; 513235783Skib 514235783Skib sc = device_get_softc(dev); 515235783Skib unit = device_get_unit(dev); 516235783Skib 517235783Skib /* Initialize our mutex. */ 518235783Skib mtx_init(&sc->pcn_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 519235783Skib MTX_DEF | MTX_RECURSE); 520235783Skib#ifndef BURN_BRIDGES 521235783Skib /* 522235783Skib * Handle power management nonsense. 523235783Skib */ 524235783Skib if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 525235783Skib u_int32_t iobase, membase, irq; 526235783Skib 527235783Skib /* Save important PCI config data. */ 528235783Skib iobase = pci_read_config(dev, PCN_PCI_LOIO, 4); 529235783Skib membase = pci_read_config(dev, PCN_PCI_LOMEM, 4); 530235783Skib irq = pci_read_config(dev, PCN_PCI_INTLINE, 4); 531235783Skib 532235783Skib /* Reset the power state. */ 533235783Skib printf("pcn%d: chip is in D%d power mode " 534235783Skib "-- setting to D0\n", unit, 535235783Skib pci_get_powerstate(dev)); 536235783Skib pci_set_powerstate(dev, PCI_POWERSTATE_D0); 537235783Skib 538235783Skib /* Restore PCI config data. */ 539235783Skib pci_write_config(dev, PCN_PCI_LOIO, iobase, 4); 540235783Skib pci_write_config(dev, PCN_PCI_LOMEM, membase, 4); 541235783Skib pci_write_config(dev, PCN_PCI_INTLINE, irq, 4); 542235783Skib } 543235783Skib#endif 544235783Skib /* 545235783Skib * Map control/status registers. 546235783Skib */ 547235783Skib pci_enable_busmaster(dev); 548235783Skib 549235783Skib rid = PCN_RID; 550235783Skib sc->pcn_res = bus_alloc_resource(dev, PCN_RES, &rid, 551235783Skib 0, ~0, 1, RF_ACTIVE); 552235783Skib 553235783Skib if (sc->pcn_res == NULL) { 554235783Skib printf("pcn%d: couldn't map ports/memory\n", unit); 555235783Skib error = ENXIO; 556235783Skib goto fail; 557235783Skib } 558235783Skib 559235783Skib sc->pcn_btag = rman_get_bustag(sc->pcn_res); 560235783Skib sc->pcn_bhandle = rman_get_bushandle(sc->pcn_res); 561235783Skib 562235783Skib /* Allocate interrupt */ 563235783Skib rid = 0; 564235783Skib sc->pcn_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 565235783Skib RF_SHAREABLE | RF_ACTIVE); 566235783Skib 567235783Skib if (sc->pcn_irq == NULL) { 568235783Skib printf("pcn%d: couldn't map interrupt\n", unit); 569235783Skib error = ENXIO; 570235783Skib goto fail; 571235783Skib } 572235783Skib 573235783Skib /* Reset the adapter. */ 574235783Skib pcn_reset(sc); 575235783Skib 576235783Skib /* 577235783Skib * Get station address from the EEPROM. 578235783Skib */ 579235783Skib eaddr[0] = CSR_READ_4(sc, PCN_IO32_APROM00); 580235783Skib eaddr[1] = CSR_READ_4(sc, PCN_IO32_APROM01); 581235783Skib bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 582235783Skib 583235783Skib /* 584235783Skib * An AMD chip was detected. Inform the world. 585235783Skib */ 586235783Skib printf("pcn%d: Ethernet address: %6D\n", unit, 587235783Skib sc->arpcom.ac_enaddr, ":"); 588235783Skib 589235783Skib sc->pcn_unit = unit; 590235783Skib callout_handle_init(&sc->pcn_stat_ch); 591235783Skib 592235783Skib sc->pcn_ldata = contigmalloc(sizeof(struct pcn_list_data), M_DEVBUF, 593235783Skib M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 594235783Skib 595235783Skib if (sc->pcn_ldata == NULL) { 596235783Skib printf("pcn%d: no memory for list buffers!\n", unit); 597235783Skib error = ENXIO; 598235783Skib goto fail; 599235783Skib } 600235783Skib bzero(sc->pcn_ldata, sizeof(struct pcn_list_data)); 601235783Skib 602235783Skib ifp = &sc->arpcom.ac_if; 603235783Skib ifp->if_softc = sc; 604235783Skib if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 605235783Skib ifp->if_mtu = ETHERMTU; 606235783Skib ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 607235783Skib ifp->if_ioctl = pcn_ioctl; 608235783Skib ifp->if_output = ether_output; 609235783Skib ifp->if_start = pcn_start; 610235783Skib ifp->if_watchdog = pcn_watchdog; 611235783Skib ifp->if_init = pcn_init; 612235783Skib ifp->if_baudrate = 10000000; 613235783Skib ifp->if_snd.ifq_maxlen = PCN_TX_LIST_CNT - 1; 614235783Skib 615235783Skib /* 616235783Skib * Do MII setup. 617235783Skib */ 618235783Skib if (mii_phy_probe(dev, &sc->pcn_miibus, 619235783Skib pcn_ifmedia_upd, pcn_ifmedia_sts)) { 620235783Skib printf("pcn%d: MII without any PHY!\n", sc->pcn_unit); 621235783Skib error = ENXIO; 622235783Skib goto fail; 623235783Skib } 624235783Skib 625235783Skib /* 626235783Skib * Call MI attach routine. 627235783Skib */ 628235783Skib ether_ifattach(ifp, (u_int8_t *) eaddr); 629235783Skib 630235783Skib /* Hook interrupt last to avoid having to lock softc */ 631235783Skib error = bus_setup_intr(dev, sc->pcn_irq, INTR_TYPE_NET, 632235783Skib pcn_intr, sc, &sc->pcn_intrhand); 633235783Skib 634235783Skib if (error) { 635235783Skib printf("pcn%d: couldn't set up irq\n", unit); 636235783Skib ether_ifdetach(ifp); 637235783Skib goto fail; 638235783Skib } 639235783Skib 640235783Skibfail: 641235783Skib if (error) 642235783Skib pcn_detach(dev); 643235783Skib 644235783Skib return(error); 645235783Skib} 646235783Skib 647235783Skib/* 648235783Skib * Shutdown hardware and free up resources. This can be called any 649235783Skib * time after the mutex has been initialized. It is called in both 650235783Skib * the error case in attach and the normal detach case so it needs 651235783Skib * to be careful about only freeing resources that have actually been 652235783Skib * allocated. 653235783Skib */ 654235783Skibstatic int 655235783Skibpcn_detach(dev) 656235783Skib device_t dev; 657235783Skib{ 658235783Skib struct pcn_softc *sc; 659235783Skib struct ifnet *ifp; 660235783Skib 661235783Skib sc = device_get_softc(dev); 662235783Skib ifp = &sc->arpcom.ac_if; 663235783Skib 664235783Skib KASSERT(mtx_initialized(&sc->pcn_mtx), ("pcn mutex not initialized")); 665235783Skib PCN_LOCK(sc); 666235783Skib 667235783Skib /* These should only be active if attach succeeded */ 668235783Skib if (device_is_attached(dev)) { 669235783Skib pcn_reset(sc); 670235783Skib pcn_stop(sc); 671235783Skib ether_ifdetach(ifp); 672235783Skib } 673235783Skib if (sc->pcn_miibus) 674235783Skib device_delete_child(dev, sc->pcn_miibus); 675235783Skib bus_generic_detach(dev); 676235783Skib 677235783Skib if (sc->pcn_intrhand) 678235783Skib bus_teardown_intr(dev, sc->pcn_irq, sc->pcn_intrhand); 679235783Skib if (sc->pcn_irq) 680235783Skib bus_release_resource(dev, SYS_RES_IRQ, 0, sc->pcn_irq); 681235783Skib if (sc->pcn_res) 682235783Skib bus_release_resource(dev, PCN_RES, PCN_RID, sc->pcn_res); 683235783Skib 684235783Skib if (sc->pcn_ldata) { 685235783Skib contigfree(sc->pcn_ldata, sizeof(struct pcn_list_data), 686235783Skib M_DEVBUF); 687235783Skib } 688235783Skib PCN_UNLOCK(sc); 689235783Skib 690235783Skib mtx_destroy(&sc->pcn_mtx); 691235783Skib 692235783Skib return(0); 693235783Skib} 694235783Skib 695235783Skib/* 696235783Skib * Initialize the transmit descriptors. 697235783Skib */ 698235783Skibstatic int 699235783Skibpcn_list_tx_init(sc) 700235783Skib struct pcn_softc *sc; 701235783Skib{ 702235783Skib struct pcn_list_data *ld; 703235783Skib struct pcn_ring_data *cd; 704235783Skib int i; 705235783Skib 706235783Skib cd = &sc->pcn_cdata; 707235783Skib ld = sc->pcn_ldata; 708235783Skib 709235783Skib for (i = 0; i < PCN_TX_LIST_CNT; i++) { 710235783Skib cd->pcn_tx_chain[i] = NULL; 711235783Skib ld->pcn_tx_list[i].pcn_tbaddr = 0; 712235783Skib ld->pcn_tx_list[i].pcn_txctl = 0; 713235783Skib ld->pcn_tx_list[i].pcn_txstat = 0; 714235783Skib } 715235783Skib 716235783Skib cd->pcn_tx_prod = cd->pcn_tx_cons = cd->pcn_tx_cnt = 0; 717235783Skib 718235783Skib return(0); 719235783Skib} 720235783Skib 721235783Skib 722235783Skib/* 723235783Skib * Initialize the RX descriptors and allocate mbufs for them. 724235783Skib */ 725235783Skibstatic int 726235783Skibpcn_list_rx_init(sc) 727235783Skib struct pcn_softc *sc; 728235783Skib{ 729235783Skib struct pcn_ring_data *cd; 730235783Skib int i; 731235783Skib 732235783Skib cd = &sc->pcn_cdata; 733235783Skib 734235783Skib for (i = 0; i < PCN_RX_LIST_CNT; i++) { 735235783Skib if (pcn_newbuf(sc, i, NULL) == ENOBUFS) 736235783Skib return(ENOBUFS); 737235783Skib } 738235783Skib 739235783Skib cd->pcn_rx_prod = 0; 740235783Skib 741235783Skib return(0); 742235783Skib} 743235783Skib 744235783Skib/* 745235783Skib * Initialize an RX descriptor and attach an MBUF cluster. 746235783Skib */ 747235783Skibstatic int 748235783Skibpcn_newbuf(sc, idx, m) 749235783Skib struct pcn_softc *sc; 750235783Skib int idx; 751235783Skib struct mbuf *m; 752235783Skib{ 753235783Skib struct mbuf *m_new = NULL; 754235783Skib struct pcn_rx_desc *c; 755235783Skib 756235783Skib c = &sc->pcn_ldata->pcn_rx_list[idx]; 757235783Skib 758235783Skib if (m == NULL) { 759235783Skib MGETHDR(m_new, M_DONTWAIT, MT_DATA); 760235783Skib if (m_new == NULL) 761235783Skib return(ENOBUFS); 762235783Skib 763235783Skib MCLGET(m_new, M_DONTWAIT); 764235783Skib if (!(m_new->m_flags & M_EXT)) { 765235783Skib m_freem(m_new); 766235783Skib return(ENOBUFS); 767235783Skib } 768235783Skib m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 769235783Skib } else { 770235783Skib m_new = m; 771235783Skib m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 772235783Skib m_new->m_data = m_new->m_ext.ext_buf; 773235783Skib } 774235783Skib 775235783Skib m_adj(m_new, ETHER_ALIGN); 776235783Skib 777235783Skib sc->pcn_cdata.pcn_rx_chain[idx] = m_new; 778235783Skib c->pcn_rbaddr = vtophys(mtod(m_new, caddr_t)); 779235783Skib c->pcn_bufsz = (~(PCN_RXLEN) + 1) & PCN_RXLEN_BUFSZ; 780235783Skib c->pcn_bufsz |= PCN_RXLEN_MBO; 781235783Skib c->pcn_rxstat = PCN_RXSTAT_STP|PCN_RXSTAT_ENP|PCN_RXSTAT_OWN; 782235783Skib 783235783Skib return(0); 784235783Skib} 785235783Skib 786235783Skib/* 787235783Skib * A frame has been uploaded: pass the resulting mbuf chain up to 788235783Skib * the higher level protocols. 789235783Skib */ 790235783Skibstatic void 791235783Skibpcn_rxeof(sc) 792235783Skib struct pcn_softc *sc; 793235783Skib{ 794235783Skib struct mbuf *m; 795235783Skib struct ifnet *ifp; 796235783Skib struct pcn_rx_desc *cur_rx; 797235783Skib int i; 798235783Skib 799235783Skib ifp = &sc->arpcom.ac_if; 800235783Skib i = sc->pcn_cdata.pcn_rx_prod; 801235783Skib 802235783Skib while(PCN_OWN_RXDESC(&sc->pcn_ldata->pcn_rx_list[i])) { 803235783Skib cur_rx = &sc->pcn_ldata->pcn_rx_list[i]; 804235783Skib m = sc->pcn_cdata.pcn_rx_chain[i]; 805235783Skib sc->pcn_cdata.pcn_rx_chain[i] = NULL; 806235783Skib 807235783Skib /* 808235783Skib * If an error occurs, update stats, clear the 809235783Skib * status word and leave the mbuf cluster in place: 810235783Skib * it should simply get re-used next time this descriptor 811235783Skib * comes up in the ring. 812235783Skib */ 813235783Skib if (cur_rx->pcn_rxstat & PCN_RXSTAT_ERR) { 814235783Skib ifp->if_ierrors++; 815235783Skib pcn_newbuf(sc, i, m); 816235783Skib PCN_INC(i, PCN_RX_LIST_CNT); 817235783Skib continue; 818235783Skib } 819235783Skib 820235783Skib if (pcn_newbuf(sc, i, NULL)) { 821235783Skib /* Ran out of mbufs; recycle this one. */ 822235783Skib pcn_newbuf(sc, i, m); 823235783Skib ifp->if_ierrors++; 824235783Skib PCN_INC(i, PCN_RX_LIST_CNT); 825235783Skib continue; 826235783Skib } 827235783Skib 828235783Skib PCN_INC(i, PCN_RX_LIST_CNT); 829235783Skib 830235783Skib /* No errors; receive the packet. */ 831235783Skib ifp->if_ipackets++; 832235783Skib m->m_len = m->m_pkthdr.len = 833235783Skib cur_rx->pcn_rxlen - ETHER_CRC_LEN; 834235783Skib m->m_pkthdr.rcvif = ifp; 835235783Skib 836235783Skib (*ifp->if_input)(ifp, m); 837235783Skib } 838235783Skib 839235783Skib sc->pcn_cdata.pcn_rx_prod = i; 840235783Skib 841235783Skib return; 842235783Skib} 843235783Skib 844235783Skib/* 845235783Skib * A frame was downloaded to the chip. It's safe for us to clean up 846235783Skib * the list buffers. 847235783Skib */ 848235783Skib 849235783Skibstatic void 850235783Skibpcn_txeof(sc) 851235783Skib struct pcn_softc *sc; 852235783Skib{ 853235783Skib struct pcn_tx_desc *cur_tx = NULL; 854235783Skib struct ifnet *ifp; 855235783Skib u_int32_t idx; 856235783Skib 857235783Skib ifp = &sc->arpcom.ac_if; 858235783Skib 859235783Skib /* 860235783Skib * Go through our tx list and free mbufs for those 861235783Skib * frames that have been transmitted. 862235783Skib */ 863235783Skib idx = sc->pcn_cdata.pcn_tx_cons; 864235783Skib while (idx != sc->pcn_cdata.pcn_tx_prod) { 865235783Skib cur_tx = &sc->pcn_ldata->pcn_tx_list[idx]; 866235783Skib 867235783Skib if (!PCN_OWN_TXDESC(cur_tx)) 868235783Skib break; 869235783Skib 870235783Skib if (!(cur_tx->pcn_txctl & PCN_TXCTL_ENP)) { 871235783Skib sc->pcn_cdata.pcn_tx_cnt--; 872235783Skib PCN_INC(idx, PCN_TX_LIST_CNT); 873235783Skib continue; 874235783Skib } 875235783Skib 876235783Skib if (cur_tx->pcn_txctl & PCN_TXCTL_ERR) { 877235783Skib ifp->if_oerrors++; 878235783Skib if (cur_tx->pcn_txstat & PCN_TXSTAT_EXDEF) 879235783Skib ifp->if_collisions++; 880235783Skib if (cur_tx->pcn_txstat & PCN_TXSTAT_RTRY) 881235783Skib ifp->if_collisions++; 882235783Skib } 883235783Skib 884235783Skib ifp->if_collisions += 885235783Skib cur_tx->pcn_txstat & PCN_TXSTAT_TRC; 886235783Skib 887235783Skib ifp->if_opackets++; 888235783Skib if (sc->pcn_cdata.pcn_tx_chain[idx] != NULL) { 889235783Skib m_freem(sc->pcn_cdata.pcn_tx_chain[idx]); 890235783Skib sc->pcn_cdata.pcn_tx_chain[idx] = NULL; 891235783Skib } 892235783Skib 893235783Skib sc->pcn_cdata.pcn_tx_cnt--; 894235783Skib PCN_INC(idx, PCN_TX_LIST_CNT); 895235783Skib } 896235783Skib 897235783Skib if (idx != sc->pcn_cdata.pcn_tx_cons) { 898235783Skib /* Some buffers have been freed. */ 899235783Skib sc->pcn_cdata.pcn_tx_cons = idx; 900235783Skib ifp->if_flags &= ~IFF_OACTIVE; 901235783Skib } 902235783Skib ifp->if_timer = (sc->pcn_cdata.pcn_tx_cnt == 0) ? 0 : 5; 903235783Skib 904235783Skib return; 905235783Skib} 906235783Skib 907235783Skibstatic void 908235783Skibpcn_tick(xsc) 909235783Skib void *xsc; 910235783Skib{ 911235783Skib struct pcn_softc *sc; 912235783Skib struct mii_data *mii; 913235783Skib struct ifnet *ifp; 914235783Skib 915235783Skib sc = xsc; 916235783Skib ifp = &sc->arpcom.ac_if; 917235783Skib PCN_LOCK(sc); 918235783Skib 919235783Skib mii = device_get_softc(sc->pcn_miibus); 920235783Skib mii_tick(mii); 921235783Skib 922235783Skib /* link just died */ 923235783Skib if (sc->pcn_link & !(mii->mii_media_status & IFM_ACTIVE)) 924235783Skib sc->pcn_link = 0; 925235783Skib 926235783Skib /* link just came up, restart */ 927235783Skib if (!sc->pcn_link && mii->mii_media_status & IFM_ACTIVE && 928235783Skib IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 929235783Skib sc->pcn_link++; 930235783Skib if (ifp->if_snd.ifq_head != NULL) 931235783Skib pcn_start(ifp); 932235783Skib } 933235783Skib 934235783Skib sc->pcn_stat_ch = timeout(pcn_tick, sc, hz); 935235783Skib 936235783Skib PCN_UNLOCK(sc); 937235783Skib 938235783Skib return; 939235783Skib} 940235783Skib 941235783Skibstatic void 942235783Skibpcn_intr(arg) 943235783Skib void *arg; 944235783Skib{ 945235783Skib struct pcn_softc *sc; 946235783Skib struct ifnet *ifp; 947235783Skib u_int32_t status; 948235783Skib 949235783Skib sc = arg; 950235783Skib ifp = &sc->arpcom.ac_if; 951235783Skib 952235783Skib /* Supress unwanted interrupts */ 953235783Skib if (!(ifp->if_flags & IFF_UP)) { 954235783Skib pcn_stop(sc); 955235783Skib return; 956235783Skib } 957235783Skib 958235783Skib PCN_LOCK(sc); 959235783Skib 960235783Skib CSR_WRITE_4(sc, PCN_IO32_RAP, PCN_CSR_CSR); 961235783Skib 962235783Skib while ((status = CSR_READ_4(sc, PCN_IO32_RDP)) & PCN_CSR_INTR) { 963235783Skib CSR_WRITE_4(sc, PCN_IO32_RDP, status); 964235783Skib 965235783Skib if (status & PCN_CSR_RINT) 966235783Skib pcn_rxeof(sc); 967235783Skib 968235783Skib if (status & PCN_CSR_TINT) 969235783Skib pcn_txeof(sc); 970235783Skib 971235783Skib if (status & PCN_CSR_ERR) { 972235783Skib pcn_init(sc); 973235783Skib break; 974235783Skib } 975235783Skib } 976235783Skib 977235783Skib if (ifp->if_snd.ifq_head != NULL) 978235783Skib pcn_start(ifp); 979235783Skib 980235783Skib PCN_UNLOCK(sc); 981235783Skib return; 982235783Skib} 983235783Skib 984235783Skib/* 985235783Skib * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 986235783Skib * pointers to the fragment pointers. 987235783Skib */ 988235783Skibstatic int 989235783Skibpcn_encap(sc, m_head, txidx) 990235783Skib struct pcn_softc *sc; 991235783Skib struct mbuf *m_head; 992235783Skib u_int32_t *txidx; 993235783Skib{ 994235783Skib struct pcn_tx_desc *f = NULL; 995235783Skib struct mbuf *m; 996235783Skib int frag, cur, cnt = 0; 997235783Skib 998235783Skib /* 999235783Skib * Start packing the mbufs in this chain into 1000235783Skib * the fragment pointers. Stop when we run out 1001235783Skib * of fragments or hit the end of the mbuf chain. 1002235783Skib */ 1003235783Skib m = m_head; 1004235783Skib cur = frag = *txidx; 1005235783Skib 1006235783Skib for (m = m_head; m != NULL; m = m->m_next) { 1007235783Skib if (m->m_len != 0) { 1008235783Skib if ((PCN_TX_LIST_CNT - 1009235783Skib (sc->pcn_cdata.pcn_tx_cnt + cnt)) < 2) 1010235783Skib return(ENOBUFS); 1011235783Skib f = &sc->pcn_ldata->pcn_tx_list[frag]; 1012235783Skib f->pcn_txctl = (~(m->m_len) + 1) & PCN_TXCTL_BUFSZ; 1013235783Skib f->pcn_txctl |= PCN_TXCTL_MBO; 1014235783Skib f->pcn_tbaddr = vtophys(mtod(m, vm_offset_t)); 1015235783Skib if (cnt == 0) 1016235783Skib f->pcn_txctl |= PCN_TXCTL_STP; 1017235783Skib else 1018235783Skib f->pcn_txctl |= PCN_TXCTL_OWN; 1019235783Skib cur = frag; 1020235783Skib PCN_INC(frag, PCN_TX_LIST_CNT); 1021235783Skib cnt++; 1022235783Skib } 1023235783Skib } 1024235783Skib 1025235783Skib if (m != NULL) 1026235783Skib return(ENOBUFS); 1027235783Skib 1028235783Skib sc->pcn_cdata.pcn_tx_chain[cur] = m_head; 1029235783Skib sc->pcn_ldata->pcn_tx_list[cur].pcn_txctl |= 1030235783Skib PCN_TXCTL_ENP|PCN_TXCTL_ADD_FCS|PCN_TXCTL_MORE_LTINT; 1031235783Skib sc->pcn_ldata->pcn_tx_list[*txidx].pcn_txctl |= PCN_TXCTL_OWN; 1032235783Skib sc->pcn_cdata.pcn_tx_cnt += cnt; 1033235783Skib *txidx = frag; 1034235783Skib 1035235783Skib return(0); 1036235783Skib} 1037235783Skib 1038235783Skib/* 1039235783Skib * Main transmit routine. To avoid having to do mbuf copies, we put pointers 1040235783Skib * to the mbuf data regions directly in the transmit lists. We also save a 1041235783Skib * copy of the pointers since the transmit list fragment pointers are 1042235783Skib * physical addresses. 1043235783Skib */ 1044235783Skibstatic void 1045235783Skibpcn_start(ifp) 1046235783Skib struct ifnet *ifp; 1047235783Skib{ 1048235783Skib struct pcn_softc *sc; 1049235783Skib struct mbuf *m_head = NULL; 1050235783Skib u_int32_t idx; 1051235783Skib 1052235783Skib sc = ifp->if_softc; 1053235783Skib 1054235783Skib PCN_LOCK(sc); 1055235783Skib 1056235783Skib if (!sc->pcn_link) { 1057235783Skib PCN_UNLOCK(sc); 1058235783Skib return; 1059235783Skib } 1060235783Skib 1061235783Skib idx = sc->pcn_cdata.pcn_tx_prod; 1062235783Skib 1063235783Skib if (ifp->if_flags & IFF_OACTIVE) { 1064235783Skib PCN_UNLOCK(sc); 1065235783Skib return; 1066235783Skib } 1067235783Skib 1068235783Skib while(sc->pcn_cdata.pcn_tx_chain[idx] == NULL) { 1069235783Skib IF_DEQUEUE(&ifp->if_snd, m_head); 1070235783Skib if (m_head == NULL) 1071235783Skib break; 1072235783Skib 1073235783Skib if (pcn_encap(sc, m_head, &idx)) { 1074235783Skib IF_PREPEND(&ifp->if_snd, m_head); 1075235783Skib ifp->if_flags |= IFF_OACTIVE; 1076235783Skib break; 1077235783Skib } 1078235783Skib 1079235783Skib /* 1080235783Skib * If there's a BPF listener, bounce a copy of this frame 1081235783Skib * to him. 1082235783Skib */ 1083235783Skib BPF_MTAP(ifp, m_head); 1084235783Skib 1085235783Skib } 1086235783Skib 1087235783Skib /* Transmit */ 1088235783Skib sc->pcn_cdata.pcn_tx_prod = idx; 1089235783Skib pcn_csr_write(sc, PCN_CSR_CSR, PCN_CSR_TX|PCN_CSR_INTEN); 1090235783Skib 1091235783Skib /* 1092235783Skib * Set a timeout in case the chip goes out to lunch. 1093235783Skib */ 1094235783Skib ifp->if_timer = 5; 1095235783Skib 1096235783Skib PCN_UNLOCK(sc); 1097235783Skib 1098235783Skib return; 1099235783Skib} 1100235783Skib 1101235783Skibstatic void 1102235783Skibpcn_setfilt(ifp) 1103235783Skib struct ifnet *ifp; 1104235783Skib{ 1105235783Skib struct pcn_softc *sc; 1106235783Skib 1107235783Skib sc = ifp->if_softc; 1108235783Skib 1109235783Skib /* If we want promiscuous mode, set the allframes bit. */ 1110235783Skib if (ifp->if_flags & IFF_PROMISC) { 1111235783Skib PCN_CSR_SETBIT(sc, PCN_CSR_MODE, PCN_MODE_PROMISC); 1112235783Skib } else { 1113235783Skib PCN_CSR_CLRBIT(sc, PCN_CSR_MODE, PCN_MODE_PROMISC); 1114235783Skib } 1115235783Skib 1116235783Skib /* Set the capture broadcast bit to capture broadcast frames. */ 1117235783Skib if (ifp->if_flags & IFF_BROADCAST) { 1118235783Skib PCN_CSR_CLRBIT(sc, PCN_CSR_MODE, PCN_MODE_RXNOBROAD); 1119235783Skib } else { 1120235783Skib PCN_CSR_SETBIT(sc, PCN_CSR_MODE, PCN_MODE_RXNOBROAD); 1121235783Skib } 1122235783Skib 1123235783Skib return; 1124235783Skib} 1125235783Skib 1126235783Skibstatic void 1127235783Skibpcn_init(xsc) 1128235783Skib void *xsc; 1129235783Skib{ 1130235783Skib struct pcn_softc *sc = xsc; 1131235783Skib struct ifnet *ifp = &sc->arpcom.ac_if; 1132235783Skib struct mii_data *mii = NULL; 1133235783Skib 1134235783Skib PCN_LOCK(sc); 1135235783Skib 1136235783Skib /* 1137235783Skib * Cancel pending I/O and free all RX/TX buffers. 1138235783Skib */ 1139235783Skib pcn_stop(sc); 1140235783Skib pcn_reset(sc); 1141235783Skib 1142235783Skib mii = device_get_softc(sc->pcn_miibus); 1143235783Skib 1144235783Skib /* Set MAC address */ 1145235783Skib pcn_csr_write(sc, PCN_CSR_PAR0, 1146235783Skib ((u_int16_t *)sc->arpcom.ac_enaddr)[0]); 1147235783Skib pcn_csr_write(sc, PCN_CSR_PAR1, 1148235783Skib ((u_int16_t *)sc->arpcom.ac_enaddr)[1]); 1149235783Skib pcn_csr_write(sc, PCN_CSR_PAR2, 1150235783Skib ((u_int16_t *)sc->arpcom.ac_enaddr)[2]); 1151235783Skib 1152235783Skib /* Init circular RX list. */ 1153235783Skib if (pcn_list_rx_init(sc) == ENOBUFS) { 1154235783Skib printf("pcn%d: initialization failed: no " 1155235783Skib "memory for rx buffers\n", sc->pcn_unit); 1156235783Skib pcn_stop(sc); 1157235783Skib PCN_UNLOCK(sc); 1158235783Skib return; 1159235783Skib } 1160235783Skib 1161235783Skib /* 1162235783Skib * Init tx descriptors. 1163235783Skib */ 1164235783Skib pcn_list_tx_init(sc); 1165235783Skib 1166235783Skib /* Set up the mode register. */ 1167235783Skib pcn_csr_write(sc, PCN_CSR_MODE, PCN_PORT_MII); 1168235783Skib 1169235783Skib /* Set up RX filter. */ 1170235783Skib pcn_setfilt(ifp); 1171235783Skib 1172235783Skib /* 1173235783Skib * Load the multicast filter. 1174235783Skib */ 1175235783Skib pcn_setmulti(sc); 1176235783Skib 1177235783Skib /* 1178235783Skib * Load the addresses of the RX and TX lists. 1179235783Skib */ 1180235783Skib pcn_csr_write(sc, PCN_CSR_RXADDR0, 1181235783Skib vtophys(&sc->pcn_ldata->pcn_rx_list[0]) & 0xFFFF); 1182235783Skib pcn_csr_write(sc, PCN_CSR_RXADDR1, 1183235783Skib (vtophys(&sc->pcn_ldata->pcn_rx_list[0]) >> 16) & 0xFFFF); 1184235783Skib pcn_csr_write(sc, PCN_CSR_TXADDR0, 1185235783Skib vtophys(&sc->pcn_ldata->pcn_tx_list[0]) & 0xFFFF); 1186235783Skib pcn_csr_write(sc, PCN_CSR_TXADDR1, 1187235783Skib (vtophys(&sc->pcn_ldata->pcn_tx_list[0]) >> 16) & 0xFFFF); 1188235783Skib 1189235783Skib /* Set the RX and TX ring sizes. */ 1190235783Skib pcn_csr_write(sc, PCN_CSR_RXRINGLEN, (~PCN_RX_LIST_CNT) + 1); 1191235783Skib pcn_csr_write(sc, PCN_CSR_TXRINGLEN, (~PCN_TX_LIST_CNT) + 1); 1192235783Skib 1193235783Skib /* We're not using the initialization block. */ 1194235783Skib pcn_csr_write(sc, PCN_CSR_IAB1, 0); 1195235783Skib 1196235783Skib /* Enable fast suspend mode. */ 1197235783Skib PCN_CSR_SETBIT(sc, PCN_CSR_EXTCTL2, PCN_EXTCTL2_FASTSPNDE); 1198235783Skib 1199235783Skib /* 1200235783Skib * Enable burst read and write. Also set the no underflow 1201235783Skib * bit. This will avoid transmit underruns in certain 1202235783Skib * conditions while still providing decent performance. 1203235783Skib */ 1204235783Skib PCN_BCR_SETBIT(sc, PCN_BCR_BUSCTL, PCN_BUSCTL_NOUFLOW| 1205235783Skib PCN_BUSCTL_BREAD|PCN_BUSCTL_BWRITE); 1206235783Skib 1207235783Skib /* Enable graceful recovery from underflow. */ 1208235783Skib PCN_CSR_SETBIT(sc, PCN_CSR_IMR, PCN_IMR_DXSUFLO); 1209235783Skib 1210235783Skib /* Enable auto-padding of short TX frames. */ 1211235783Skib PCN_CSR_SETBIT(sc, PCN_CSR_TFEAT, PCN_TFEAT_PAD_TX); 1212235783Skib 1213235783Skib /* Disable MII autoneg (we handle this ourselves). */ 1214235783Skib PCN_BCR_SETBIT(sc, PCN_BCR_MIICTL, PCN_MIICTL_DANAS); 1215235783Skib 1216235783Skib if (sc->pcn_type == Am79C978) 1217235783Skib pcn_bcr_write(sc, PCN_BCR_PHYSEL, 1218235783Skib PCN_PHYSEL_PCNET|PCN_PHY_HOMEPNA); 1219235783Skib 1220235783Skib /* Enable interrupts and start the controller running. */ 1221235783Skib pcn_csr_write(sc, PCN_CSR_CSR, PCN_CSR_INTEN|PCN_CSR_START); 1222235783Skib 1223235783Skib mii_mediachg(mii); 1224235783Skib 1225235783Skib ifp->if_flags |= IFF_RUNNING; 1226235783Skib ifp->if_flags &= ~IFF_OACTIVE; 1227235783Skib 1228235783Skib sc->pcn_stat_ch = timeout(pcn_tick, sc, hz); 1229235783Skib PCN_UNLOCK(sc); 1230235783Skib 1231235783Skib return; 1232235783Skib} 1233235783Skib 1234235783Skib/* 1235235783Skib * Set media options. 1236235783Skib */ 1237235783Skibstatic int 1238235783Skibpcn_ifmedia_upd(ifp) 1239235783Skib struct ifnet *ifp; 1240235783Skib{ 1241235783Skib struct pcn_softc *sc; 1242235783Skib struct mii_data *mii; 1243235783Skib 1244235783Skib sc = ifp->if_softc; 1245235783Skib mii = device_get_softc(sc->pcn_miibus); 1246235783Skib 1247235783Skib sc->pcn_link = 0; 1248235783Skib if (mii->mii_instance) { 1249235783Skib struct mii_softc *miisc; 1250235783Skib LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 1251235783Skib mii_phy_reset(miisc); 1252235783Skib } 1253235783Skib mii_mediachg(mii); 1254235783Skib 1255235783Skib return(0); 1256235783Skib} 1257235783Skib 1258235783Skib/* 1259235783Skib * Report current media status. 1260235783Skib */ 1261235783Skibstatic void 1262235783Skibpcn_ifmedia_sts(ifp, ifmr) 1263235783Skib struct ifnet *ifp; 1264235783Skib struct ifmediareq *ifmr; 1265235783Skib{ 1266235783Skib struct pcn_softc *sc; 1267235783Skib struct mii_data *mii; 1268235783Skib 1269235783Skib sc = ifp->if_softc; 1270235783Skib 1271235783Skib mii = device_get_softc(sc->pcn_miibus); 1272235783Skib mii_pollstat(mii); 1273235783Skib ifmr->ifm_active = mii->mii_media_active; 1274235783Skib ifmr->ifm_status = mii->mii_media_status; 1275235783Skib 1276235783Skib return; 1277235783Skib} 1278235783Skib 1279235783Skibstatic int 1280235783Skibpcn_ioctl(ifp, command, data) 1281235783Skib struct ifnet *ifp; 1282235783Skib u_long command; 1283235783Skib caddr_t data; 1284235783Skib{ 1285235783Skib struct pcn_softc *sc = ifp->if_softc; 1286235783Skib struct ifreq *ifr = (struct ifreq *) data; 1287235783Skib struct mii_data *mii = NULL; 1288235783Skib int error = 0; 1289235783Skib 1290235783Skib PCN_LOCK(sc); 1291235783Skib 1292235783Skib switch(command) { 1293235783Skib case SIOCSIFFLAGS: 1294235783Skib if (ifp->if_flags & IFF_UP) { 1295235783Skib if (ifp->if_flags & IFF_RUNNING && 1296235783Skib ifp->if_flags & IFF_PROMISC && 1297235783Skib !(sc->pcn_if_flags & IFF_PROMISC)) { 1298235783Skib PCN_CSR_SETBIT(sc, PCN_CSR_EXTCTL1, 1299235783Skib PCN_EXTCTL1_SPND); 1300235783Skib pcn_setfilt(ifp); 1301235783Skib PCN_CSR_CLRBIT(sc, PCN_CSR_EXTCTL1, 1302235783Skib PCN_EXTCTL1_SPND); 1303235783Skib pcn_csr_write(sc, PCN_CSR_CSR, 1304235783Skib PCN_CSR_INTEN|PCN_CSR_START); 1305235783Skib } else if (ifp->if_flags & IFF_RUNNING && 1306235783Skib !(ifp->if_flags & IFF_PROMISC) && 1307235783Skib sc->pcn_if_flags & IFF_PROMISC) { 1308235783Skib PCN_CSR_SETBIT(sc, PCN_CSR_EXTCTL1, 1309235783Skib PCN_EXTCTL1_SPND); 1310235783Skib pcn_setfilt(ifp); 1311235783Skib PCN_CSR_CLRBIT(sc, PCN_CSR_EXTCTL1, 1312235783Skib PCN_EXTCTL1_SPND); 1313235783Skib pcn_csr_write(sc, PCN_CSR_CSR, 1314235783Skib PCN_CSR_INTEN|PCN_CSR_START); 1315235783Skib } else if (!(ifp->if_flags & IFF_RUNNING)) 1316235783Skib pcn_init(sc); 1317235783Skib } else { 1318235783Skib if (ifp->if_flags & IFF_RUNNING) 1319235783Skib pcn_stop(sc); 1320235783Skib } 1321235783Skib sc->pcn_if_flags = ifp->if_flags; 1322235783Skib error = 0; 1323235783Skib break; 1324235783Skib case SIOCADDMULTI: 1325235783Skib case SIOCDELMULTI: 1326235783Skib pcn_setmulti(sc); 1327235783Skib error = 0; 1328235783Skib break; 1329235783Skib case SIOCGIFMEDIA: 1330235783Skib case SIOCSIFMEDIA: 1331235783Skib mii = device_get_softc(sc->pcn_miibus); 1332235783Skib error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 1333235783Skib break; 1334235783Skib default: 1335235783Skib error = ether_ioctl(ifp, command, data); 1336235783Skib break; 1337235783Skib } 1338235783Skib 1339235783Skib PCN_UNLOCK(sc); 1340235783Skib 1341235783Skib return(error); 1342235783Skib} 1343235783Skib 1344235783Skibstatic void 1345235783Skibpcn_watchdog(ifp) 1346235783Skib struct ifnet *ifp; 1347235783Skib{ 1348235783Skib struct pcn_softc *sc; 1349235783Skib 1350235783Skib sc = ifp->if_softc; 1351235783Skib 1352235783Skib PCN_LOCK(sc); 1353235783Skib 1354235783Skib ifp->if_oerrors++; 1355235783Skib printf("pcn%d: watchdog timeout\n", sc->pcn_unit); 1356235783Skib 1357235783Skib pcn_stop(sc); 1358235783Skib pcn_reset(sc); 1359235783Skib pcn_init(sc); 1360235783Skib 1361235783Skib if (ifp->if_snd.ifq_head != NULL) 1362235783Skib pcn_start(ifp); 1363235783Skib 1364235783Skib PCN_UNLOCK(sc); 1365235783Skib 1366235783Skib return; 1367235783Skib} 1368235783Skib 1369235783Skib/* 1370235783Skib * Stop the adapter and free any mbufs allocated to the 1371235783Skib * RX and TX lists. 1372235783Skib */ 1373235783Skibstatic void 1374235783Skibpcn_stop(sc) 1375235783Skib struct pcn_softc *sc; 1376235783Skib{ 1377235783Skib register int i; 1378235783Skib struct ifnet *ifp; 1379235783Skib 1380235783Skib ifp = &sc->arpcom.ac_if; 1381235783Skib PCN_LOCK(sc); 1382235783Skib ifp->if_timer = 0; 1383235783Skib 1384235783Skib untimeout(pcn_tick, sc, sc->pcn_stat_ch); 1385235783Skib 1386235783Skib /* Turn off interrupts */ 1387235783Skib PCN_CSR_CLRBIT(sc, PCN_CSR_CSR, PCN_CSR_INTEN); 1388235783Skib /* Stop adapter */ 1389235783Skib PCN_CSR_SETBIT(sc, PCN_CSR_CSR, PCN_CSR_STOP); 1390235783Skib sc->pcn_link = 0; 1391235783Skib 1392235783Skib /* 1393235783Skib * Free data in the RX lists. 1394235783Skib */ 1395235783Skib for (i = 0; i < PCN_RX_LIST_CNT; i++) { 1396235783Skib if (sc->pcn_cdata.pcn_rx_chain[i] != NULL) { 1397235783Skib m_freem(sc->pcn_cdata.pcn_rx_chain[i]); 1398235783Skib sc->pcn_cdata.pcn_rx_chain[i] = NULL; 1399235783Skib } 1400235783Skib } 1401235783Skib bzero((char *)&sc->pcn_ldata->pcn_rx_list, 1402235783Skib sizeof(sc->pcn_ldata->pcn_rx_list)); 1403235783Skib 1404235783Skib /* 1405235783Skib * Free the TX list buffers. 1406235783Skib */ 1407235783Skib for (i = 0; i < PCN_TX_LIST_CNT; i++) { 1408235783Skib if (sc->pcn_cdata.pcn_tx_chain[i] != NULL) { 1409235783Skib m_freem(sc->pcn_cdata.pcn_tx_chain[i]); 1410235783Skib sc->pcn_cdata.pcn_tx_chain[i] = NULL; 1411235783Skib } 1412235783Skib } 1413235783Skib 1414235783Skib bzero((char *)&sc->pcn_ldata->pcn_tx_list, 1415235783Skib sizeof(sc->pcn_ldata->pcn_tx_list)); 1416235783Skib 1417235783Skib ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 1418235783Skib PCN_UNLOCK(sc); 1419235783Skib 1420235783Skib return; 1421235783Skib} 1422235783Skib 1423235783Skib/* 1424235783Skib * Stop all chip I/O so that the kernel's probe routines don't 1425235783Skib * get confused by errant DMAs when rebooting. 1426235783Skib */ 1427235783Skibstatic void 1428235783Skibpcn_shutdown(dev) 1429235783Skib device_t dev; 1430235783Skib{ 1431235783Skib struct pcn_softc *sc; 1432235783Skib 1433235783Skib sc = device_get_softc(dev); 1434235783Skib 1435235783Skib PCN_LOCK(sc); 1436235783Skib pcn_reset(sc); 1437235783Skib pcn_stop(sc); 1438235783Skib PCN_UNLOCK(sc); 1439235783Skib 1440235783Skib return; 1441235783Skib} 1442235783Skib