📄 if_gt.c
字号:
/* $Id: if_gt.c,v 1.8 2003/03/24 13:24:18 pefo Exp $ *//* * Copyright (c) 2001 Allegro Networks (www.allegronetworks.com) * Copyright (c) 2002 Opsycon AB. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Allegro Networks Inc. * This product includes software developed by Opsycon AB. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */#include "bpfilter.h"#include <sys/param.h>#include <sys/systm.h>#include <sys/mbuf.h>#include <sys/malloc.h>#include <sys/kernel.h>#include <sys/socket.h>#include <sys/syslog.h>#include <net/if.h>#include <net/if_dl.h>#include <net/if_media.h>#include <net/if_types.h>#ifdef INET#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/in_var.h>#include <netinet/ip.h>#endif#ifdef IPX#include <netipx/ipx.h>#include <netipx/ipx_if.h>#endif#ifdef NS#include <netns/ns.h>#include <netns/ns_if.h>#endif#if 0#if NBPFILTER > 0#include <net/bpf.h>#include <net/bpfdesc.h>#endif#endif#include <sys/ioctl.h>#include <sys/errno.h>#include <sys/device.h>#include <autoconf.h>#include <netinet/if_ether.h>#include <vm/vm.h>#include <machine/cpu.h>#include <machine/bus.h>#include <machine/intr.h>#include <dev/mii/miivar.h>#include <dev/pci/pcivar.h>#include <dev/pci/pcireg.h>#include <dev/pci/pcidevs.h>#include <dev/ic/if_gt.h>extern int _pciverbose;/* Prototypes */static int gt_match (struct device *, void *, void *);void gt_attach (struct device *, struct device *, void *);static void abort (struct gt_softc *, u_int32_t);static void reset_tx (struct gt_softc *);static void reset_rx (struct gt_softc *);static int gt_ioctl (struct ifnet *, u_long, caddr_t);static void gt_init (void *);static void gt_start (struct ifnet *);static void gt_stop (struct gt_softc *, int);static void gt_watchdog (struct ifnet *);static int gt_add_rfabuf (struct gt_softc *, struct mbuf **);static int gt_intr (void *);static int gt_rx (struct gt_softc *, u_int32_t);static void read_mib_counters (struct gt_softc *);int gt_miibus_readreg(void *, int, int);int gt_miibus_writereg(void *, int, int, int);void tgt_netstats (int);int initAddressTable (int, int, int, int);int addAddressTableEntry (int, uint, uint, uint, uint);/* Compensate for lack of a generic ether_ioctl() */static int gt_ether_ioctl (struct ifnet *, u_int32_t, caddr_t);#define ether_ioctl gt_ether_ioctlstruct cfattach gt_ca = { sizeof(struct gt_softc), gt_match, gt_attach }; struct cfdriver gt_cd = { NULL, "gt", DV_IFNET };/* Define ethernet MAC address */extern char hwethadr[]; #define RFA_ALIGNMENT_FUDGE 2/* * Check for Galileo gt642[46]0 */static intgt_match(parent, match, aux) struct device *parent; void *match, *aux;{ return(1); /* I suppose soooo... */}/* Attach the interface */void gt_attach (parent, self, aux) struct device *parent, *self; void *aux;{ struct gt_softc *sc = (struct gt_softc *)self; struct confargs *cf = aux; struct ifnet *ifp; u_int32_t macH, macL; int i, isrmii; ifp = &sc->arpcom.ac_if; bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); bcopy(hwethadr, sc->arpcom.ac_enaddr, sizeof(sc->arpcom.ac_enaddr)); sc->arpcom.ac_enaddr[5] += sc->sc_dev.dv_unit; printf(": address %s\n", ether_sprintf(sc->arpcom.ac_enaddr)); sc->port_offset = sc->sc_dev.dv_unit * ETH_IO_SIZE; sc->phy_addr = cf->ca_baseaddr; ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = gt_ioctl; ifp->if_start = gt_start; ifp->if_watchdog = gt_watchdog; /* * Allocate Tx and Rx descriptor rings */ sc->tx_ring = (TX_DESC *)(malloc(sizeof(TX_DESC) * TX_RING_SIZE, M_DEVBUF, M_NOWAIT)); sc->rx_ring = (RX_DESC *)(malloc(sizeof(RX_DESC) * RX_RING_SIZE, M_DEVBUF, M_NOWAIT)); sc->tx_m = (struct mbuf **)(malloc(sizeof(struct mbuf *) * TX_RING_SIZE, M_DEVBUF, M_NOWAIT)); sc->rx_m = (struct mbuf **)(malloc(sizeof(struct mbuf *) * RX_RING_SIZE, M_DEVBUF, M_NOWAIT)); bzero(sc->tx_m, sizeof(struct m_buf *) * TX_RING_SIZE); bzero(sc->rx_m, sizeof(struct m_buf *) * RX_RING_SIZE); /* * Allocate Tx data buffers */ sc->tx_bp = malloc(TX_BUF_SZ*TX_RING_SIZE, M_DEVBUF, M_NOWAIT); /* * Initialize hash table */ sc->hash_mode = 0; initAddressTable(sc->sc_dev.dv_unit,0,1,0); macH = (sc->arpcom.ac_enaddr[0] << 8) | (sc->arpcom.ac_enaddr[1]); macL = (sc->arpcom.ac_enaddr[5] << 0) | (sc->arpcom.ac_enaddr[4] << 8) | (sc->arpcom.ac_enaddr[3] << 16)| (sc->arpcom.ac_enaddr[2] << 24); addAddressTableEntry(sc->sc_dev.dv_unit,macH,macL,1,0); /* * Reset port */ gt_stop(sc,0); gt_miibus_writereg(sc, sc->phy_addr, 0, 0x8000); i = 100; while (i && gt_miibus_readreg(sc, sc->phy_addr, 0) & 0x8000) { delay(100); i--; } /* * Initialize Tx and Rx descriptors */ reset_tx(sc); reset_rx(sc); GTETH_WRITE(sc, ETH0_INTERRUPT_MASK_REG, 0x0); /* * Setup eth0 Port Config Extend Reg, clear the MIB registers. * When done set MIB counters clear mode to 'no effect' so each * read doesn't zero the register. */ isrmii = gt_miibus_readreg(sc, sc->phy_addr, 2) << 16; isrmii |= gt_miibus_readreg(sc, sc->phy_addr, 3) & 0xfff0; switch(isrmii) { case 0x1378e0: /* Intel LTX972A */ isrmii = 0; break; default: isrmii = pcxrRMIIen; break; } GTETH_WRITE(sc, ETH0_PORT_CONFIG_EXT_REG, isrmii | pcxrFCTL | pcxrFCTLen | pcxrFLP); read_mib_counters(sc); GTETH_WRITE(sc, ETH0_PORT_CONFIG_EXT_REG, isrmii | pcxrFCTL | pcxrFCTLen | pcxrFLP | pcxrPRIOrxOverride | pcxrMIBclrMode); /* * Big endian DMA, burst size 8 64bit words, frame boundary interrupts */#if BYTE_ORDER == LITTLE_ENDIAN GTETH_WRITE(sc, ETH0_SDMA_CONFIG_REG, sdcrBLMR | sdcrBLMT | (0xf<<sdcrRCBit) | sdcrRIFB | (3<<sdcrBSZBit));#else GTETH_WRITE(sc, ETH0_SDMA_CONFIG_REG, (0xf<<sdcrRCBit) | sdcrRIFB | (3<<sdcrBSZBit));#endif /* * Start eth0 Rx DMA */ GTETH_WRITE(sc, ETH0_SDMA_COMMAND_REG, sdcmrERD); /* * Enable eth0 with 1/2K hash size */ GTETH_WRITE(sc, ETH0_PORT_CONFIG_REG, pcrEN | pcrHS); /* * Attach the interface */ if_attach(ifp); /* * Let the system queue as many packets as we have available * Tx descriptors */ ifp->if_snd.ifq_maxlen = TX_RING_SIZE - 1; ether_ifattach(ifp);}/* * Start packet transmission on the interface. */static voidgt_start(ifp) struct ifnet *ifp;{ struct gt_softc *sc = ifp->if_softc; u_int16_t total_len; char *p; /* * Process all mbufs ready for transmit or until all available * transmit buffers are full. */ CACHESYNC(&sc->tx_ring[sc->tx_next_in], sizeof(TX_DESC), SYNC_R); if(sc->tx_ring[sc->tx_next_in].cmdstat & txOwn) { return; /* No buffers */ } while (ifp->if_snd.ifq_head != NULL) { struct mbuf *m, *mb_head; u_int32_t nextTx; /* * Grab a packet to transmit. */ IF_DEQUEUE(&ifp->if_snd, mb_head); /* * Go through each of the mbufs in the chain and copy the data * collecting fragments to the transmit descriptors data buffer. */ nextTx = sc->tx_next_in; total_len = 0; p = (char *)PA_TO_VA(sc->tx_ring[nextTx].buff_ptr); for (m = mb_head; m != NULL; m = m->m_next) { bcopy((char *)(mtod(m, vm_offset_t)), p, m->m_len); total_len += m->m_len; p += m->m_len; } sc->tx_ring[nextTx].byte_cnt_res = total_len << 16; CACHESYNC((void *)(p - total_len), total_len, SYNC_W); sc->tx_next_in = (nextTx + 1) % TX_RING_SIZE; /* * Free the mbuf chain */ m_freem(mb_head); sc->tx_ring[nextTx].cmdstat = txOwn | txFirst | txLast | txPad | txEI | txGenCRC; CACHESYNC(&sc->tx_ring[nextTx], sizeof(TX_DESC), SYNC_W); /* * Send the packet out the low priority queue */ if(!(GTETH_READ(sc, ETH0_PORT_STATUS_REG) & psrTxInProg)) { GTETH_WRITE(sc, ETH0_SDMA_COMMAND_REG, sdcmrERD | sdcmrTXDL); }#if 0 /* * Set a 5 second timer just in case we don't hear * from the card again. */ ifp->if_timer = 300;#endif } /* end while */ sc->tx_queued++;}/* * Stop the interface */voidgt_stop(struct gt_softc *sc, int drain){ /* * Disable port */ abort(sc, sdcmrAR | sdcmrAT); GTETH_WRITE(sc, ETH0_PORT_CONFIG_REG, 0);}static voidabort(struct gt_softc *sc, u_int32_t abort_bits){ /* Return if neither Rx or Tx abort bits are set */ if (!(abort_bits & (sdcmrAR | sdcmrAT))) return; /* Make sure only the Rx and Tx abort bits are set */ abort_bits &= (sdcmrAR | sdcmrAT); /* Abort any Rx and Tx DMA immediately */ GTETH_WRITE(sc, ETH0_SDMA_COMMAND_REG, abort_bits);}/* * Watchdog timeout handler. This routine is called when * transmission has started on the interface and no * interrupt was received before the timeout. */voidgt_watchdog(ifp) struct ifnet *ifp;{ struct gt_softc *sc = ifp->if_softc; log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); ifp->if_oerrors++; //gt_init(sc);}static voidreset_tx(struct gt_softc *sc){ int i; abort(sc, sdcmrAT); for (i=0; i < TX_RING_SIZE; i++) { sc->tx_ring[i].cmdstat = 0; /* CPU owns */ sc->tx_ring[i].byte_cnt_res = 0; sc->tx_ring[i].buff_ptr = (u_int32_t)VA_TO_PA(sc->tx_bp+i*TX_BUF_SZ); sc->tx_ring[i].next = (u_int32_t)VA_TO_PA(sc->tx_ring + (i+1)); } /* Wrap the ring. */ sc->tx_ring[i-1].next = VA_TO_PA(sc->tx_ring); CACHESYNC(sc->tx_ring, TX_RING_SIZE * sizeof(TX_DESC), SYNC_W); /* setup only the lowest priority TxCDP reg */ GTETH_WRITE(sc, ETH0_CURRENT_TX_DESC_PTR0, VA_TO_PA(sc->tx_ring)); GTETH_WRITE(sc, ETH0_CURRENT_TX_DESC_PTR1, 0); /* Initialize Tx indeces and packet counter */ sc->tx_next_in = 0; sc->tx_next_out = 0; sc->tx_count = 0;}static voidreset_rx(struct gt_softc *sc){ struct mbuf *m; int i; abort(sc, sdcmrAR); /* Scan and release allocated mbufs */ for (i=0; i<RX_RING_SIZE; i++) { if(sc->rx_m[i] != NULL) { m_free(sc->rx_m[i]); } } for (i=0; i < RX_RING_SIZE; i++) { RX_DESC *rx_desc; m = NULL; if(gt_add_rfabuf(sc, &m) < 0) { printf("%s: malloc failed\n", sc->sc_dev.dv_xname); break; } sc->rx_m[i] = m; rx_desc = &sc->rx_ring[i]; rx_desc->next = VA_TO_PA((sc->rx_ring + (i+1))); rx_desc->buff_ptr = VA_TO_PA(m->m_data); rx_desc->byte_sz_cnt = RX_BUF_SZ << 16; /* * Give ownership to device, set first and last, * enable interrupt */ sc->rx_ring[i].cmdstat = (rxFirst | rxLast | rxOwn | rxEI); } /* Wrap the ring */ sc->rx_ring[i-1].next = VA_TO_PA(sc->rx_ring); CACHESYNC(sc->rx_ring, RX_RING_SIZE * sizeof(RX_DESC), SYNC_W); /* Setup only the lowest priority RxFDP and RxCDP regs */ for (i=0; i<4; i++) { if (i == 0) { GTETH_WRITE(sc, ETH0_FIRST_RX_DESC_PTR0, VA_TO_PA(sc->rx_ring)); GTETH_WRITE(sc, ETH0_CURRENT_RX_DESC_PTR0, VA_TO_PA(sc->rx_ring)); } else { GTETH_WRITE(sc, ETH0_FIRST_RX_DESC_PTR0 + i*4, 0); GTETH_WRITE(sc, ETH0_CURRENT_RX_DESC_PTR0 + i*4, 0); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -