From 81975cac396888d5c7ad4b7387a895e0bf8e1be6 Mon Sep 17 00:00:00 2001 From: glebius Date: Thu, 25 Sep 2014 06:47:38 +0000 Subject: Run through unifdef(1) with slight hand-editing after. It is obvious, that the driver is not going to be ever improved in terms of hardware support, it is going to be only maintained as our kernel APIs change. Carrying all the compatibility with ancient versions of NetBSD, OpenBSD, Linux and BSDI, as well as obsoleted FreeBSD versions has no reason. --- sys/dev/lmc/if_lmc.c | 4855 +++++++++++++------------------------------------- sys/dev/lmc/if_lmc.h | 288 +-- 2 files changed, 1197 insertions(+), 3946 deletions(-) diff --git a/sys/dev/lmc/if_lmc.c b/sys/dev/lmc/if_lmc.c index f7cdac5..ac255fe 100644 --- a/sys/dev/lmc/if_lmc.c +++ b/sys/dev/lmc/if_lmc.c @@ -71,7 +71,6 @@ * * Send bug reports and improvements to . */ -#ifdef __FreeBSD__ # include /* OS version */ # define IFNET 1 # include "opt_inet.h" /* INET */ @@ -90,15 +89,9 @@ # define NETGRAPH 0 # endif # define P2P 0 /* not in FreeBSD */ -# if (__FreeBSD_version >= 500000) -# define NSPPP 1 /* No count devices in FreeBSD 5 */ -# include "opt_bpf.h" /* DEV_BPF */ -# define NBPFILTER DEV_BPF -# else /* FreeBSD-4 */ -# include "sppp.h" /* NSPPP */ -# include "bpf.h" /* NBPF */ -# define NBPFILTER NBPF -# endif +# define NSPPP 1 /* No count devices in FreeBSD 5 */ +# include "opt_bpf.h" /* DEV_BPF */ +# define NBPFILTER DEV_BPF # define GEN_HDLC 0 /* not in FreeBSD */ # # include @@ -121,16 +114,9 @@ # include # include # include -# if (__FreeBSD_version >= 700000) -# include -# endif -# if (__FreeBSD_version >= 500000) +# include # include # include -# else /* FreeBSD-4 */ -# include -# include -# endif # if NETGRAPH # include # include @@ -147,180 +133,10 @@ # endif /* and finally... */ # include -#endif /*__FreeBSD__*/ -#ifdef __NetBSD__ -# include /* OS version */ -# define IFNET 1 -# include "opt_inet.h" /* INET6, INET */ -# define NETGRAPH 0 /* not in NetBSD */ -# include "sppp.h" /* NSPPP */ -# define P2P 0 /* not in NetBSD */ -# include "opt_altq_enabled.h" /* ALTQ */ -# include "bpfilter.h" /* NBPFILTER */ -# define GEN_HDLC 0 /* not in NetBSD */ -# -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# if (__NetBSD_Version__ >= 106000000) -# include -# else -# include -# endif -# if (INET || INET6) -# include -# include -# endif -# if NSPPP -# if (__NetBSD_Version__ >= 106000000) -# include -# else -# include -# endif -# endif -# if NBPFILTER -# include -# endif -/* and finally... */ -# include "if_lmc.h" -#endif /*__NetBSD__*/ -#ifdef __OpenBSD__ -# include /* OS version */ -# define IFNET 1 -/* -DINET is passed on the compiler command line */ -/* -DINET6 is passed on the compiler command line */ -# define NETGRAPH 0 /* not in OpenBSD */ -# include "sppp.h" /* NSPPP */ -# define P2P 0 /* not in OpenBSD */ -/* -DALTQ is passed on the compiler command line */ -# include "bpfilter.h" /* NBPFILTER */ -# define GEN_HDLC 0 /* not in OpenBSD */ -# -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# if (OpenBSD >= 200206) -# include -# else -# include -# endif -# if (INET || INET6) -# include -# include -# endif -# if NSPPP -# include -# endif -# if NBPFILTER -# include -# endif -/* and finally... */ -# include "if_lmc.h" -#endif /*__OpenBSD__*/ -#ifdef __bsdi__ -# include /* OS version */ -# define IFNET 1 -/* -DINET is passed on the compiler command line */ -/* -DINET6 is passed on the compiler command line */ -# define NETGRAPH 0 /* not in BSD/OS */ -# define NSPPP 0 /* not in BSD/OS */ -/* -DPPP is passed on the compiler command line */ -/* -DCISCO_HDLC is passed on the compiler command line */ -/* -DFR is passed on the compiler command line */ -# if (PPP || CISCO_HDLC || FR) -# define P2P 1 -# else -# define P2P 0 -# endif -# define ALTQ 0 /* not in BSD/OS */ -# include "bpfilter.h" /* NBPFILTER */ -# define GEN_HDLC 0 /* not in BSD/OS */ -# -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# if (INET || INET6) -# include -# include -# endif -# if P2P -# include -# include -# endif -# if NBPFILTER -# include -# endif -/* and finally... */ -# include "if_lmc.h" -#endif /*__bsdi__*/ -#ifdef __linux__ -# include -# if (CONFIG_HDLC || CONFIG_HDLC_MODULE) -# define GEN_HDLC 1 -# else -# define GEN_HDLC 0 -# endif -# define IFNET 0 /* different in Linux */ -# define NETGRAPH 0 /* not in Linux */ -# define NSPPP 0 /* different in Linux */ -# define P2P 0 /* not in Linux */ -# define ALTQ 0 /* different in Linux */ -# define NBPFILTER 0 /* different in Linux */ -# -# include -# include -# include -# include -# if GEN_HDLC -# include -# endif -/* and finally... */ -# include "if_lmc.h" -#endif /* __linux__ */ /* The SROM is a generic 93C46 serial EEPROM (64 words by 16 bits). */ /* Data is set up before the RISING edge of CLK; CLK is parked low. */ @@ -2484,44 +2300,6 @@ struct card t1_card = /* RAWIP is raw IP packets (v4 or v6) in HDLC frames with NO HEADERS. */ /* No HDLC Address/Control fields! No line control protocol at all! */ -/* This code is BSD/ifnet-specific; Linux and Netgraph also do RAWIP. */ - -#if IFNET - -# if ((defined(__FreeBSD__) && (__FreeBSD_version < 500000)) ||\ - defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)) -static void -netisr_dispatch(int isr, struct mbuf *mbuf) - { - struct ifqueue *intrq = NULL; - int qfull = 0; - -#if INET - if (isr == NETISR_IP) intrq = &ipintrq; -#endif -#if INET6 - if (isr == NETISR_IPV6) intrq = &ip6intrq; -#endif - - if ((intrq != NULL) && ((qfull = IF_QFULL(intrq)) == 0)) - { - /* rxintr_cleanup() ENQUEUES in a hard interrupt. */ - /* networking code DEQUEUES in a soft interrupt. */ - /* Some BSD QUEUE routines are not interrupt-safe. */ - DISABLE_INTR; /* noop in FreeBSD */ - IF_ENQUEUE(intrq, mbuf); - ENABLE_INTR; - schednetisr(isr); /* schedule a soft interrupt */ - } - else - { - m_freem(mbuf); - if ((intrq != NULL) && (qfull != 0)) - IF_DROP(intrq); - } - } -# endif /* ((__FreeBSD__ && (__FreeBSD_version < 500000)) || */ - /* __NetBSD__ || __OpenBSD__ || __bsdi__) */ /* rxintr_cleanup calls this to give a newly arrived pkt to higher levels. */ static void @@ -2549,20 +2327,12 @@ lmc_raw_input(struct ifnet *ifp, struct mbuf *mbuf) } } -#endif /* IFNET */ - -/* There are TWO VERSIONS of interrupt/DMA code: Linux & BSD. - * Handling Linux and the BSDs with CPP directives would - * make the code unreadable, so there are two versions. - * Conceptually, the two versions do the same thing and - * core_interrupt() doesn't know they are different. - * +/* * We are "standing on the head of a pin" in these routines. * Tulip CSRs can be accessed, but nothing else is interrupt-safe! * Do NOT access: MII, GPIO, SROM, BIOSROM, XILINX, SYNTH, or DAC. */ -#if BSD /* BSD version of interrupt/DMA code */ /* Singly-linked tail-queues hold mbufs with active DMA. * For RX, single mbuf clusters; for TX, mbuf chains are queued. @@ -2593,7 +2363,6 @@ mbuf_dequeue(struct desc_ring *ring) return m; } -# ifdef __FreeBSD__ static void /* *** FreeBSD ONLY *** Callout from bus_dmamap_load() */ fbsd_dmamap_load(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { @@ -2602,7 +2371,6 @@ fbsd_dmamap_load(void *arg, bus_dma_segment_t *segs, int nsegs, int error) ring->segs[0] = segs[0]; ring->segs[1] = segs[1]; } -# endif /* Initialize a DMA descriptor ring. */ static int /* BSD version */ @@ -2620,15 +2388,12 @@ create_ring(softc_t *sc, struct desc_ring *ring, int num_descs) return EINVAL; } -#ifdef __FreeBSD__ /* Create a DMA tag for descriptors and buffers. */ if ((error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 4, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, PAGE_SIZE, 2, PAGE_SIZE, BUS_DMA_ALLOCNOW, -# if (__FreeBSD_version >= 502000) NULL, NULL, -# endif &ring->tag))) { printf("%s: bus_dma_tag_create() failed: error %d\n", NAME_UNIT, error); @@ -2662,70 +2427,6 @@ create_ring(softc_t *sc, struct desc_ring *ring, int num_descs) return error; } -#elif (defined(__NetBSD__) || defined(__OpenBSD__)) - - /* Use the DMA tag passed to attach() for descriptors and buffers. */ - ring->tag = sc->pa_dmat; - - /* Allocate wired physical memory for DMA descriptor array. */ - if ((error = bus_dmamem_alloc(ring->tag, size_descs, PAGE_SIZE, 0, - ring->segs, 1, &ring->nsegs, BUS_DMA_NOWAIT))) - { - printf("%s: bus_dmamem_alloc() failed; error %d\n", NAME_UNIT, error); - return error; - } - - /* Map physical address to kernel virtual address. */ - if ((error = bus_dmamem_map(ring->tag, ring->segs, ring->nsegs, - size_descs, (caddr_t *)&ring->first, BUS_DMA_NOWAIT | BUS_DMA_COHERENT))) - { - printf("%s: bus_dmamem_map() failed; error %d\n", NAME_UNIT, error); - return error; - } - descs = ring->first; /* suppress compiler warning about aliasing */ - memset(descs, 0, size_descs); - - /* Allocate dmamap for PCI access to DMA descriptor array. */ - if ((error = bus_dmamap_create(ring->tag, size_descs, 1, - size_descs, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ring->map))) - { - printf("%s: bus_dmamap_create() failed; error %d\n", NAME_UNIT, error); - return error; - } - - /* Map kernel virtual address to PCI address for DMA descriptor array. */ - if ((error = bus_dmamap_load(ring->tag, ring->map, descs, size_descs, - 0, BUS_DMA_NOWAIT))) - { - printf("%s: bus_dmamap_load() failed; error %d\n", NAME_UNIT, error); - return error; - } - ring->dma_addr = ring->map->dm_segs[0].ds_addr; - - /* Allocate dmamaps for each DMA descriptor. */ - for (i=0; itag, MAX_DESC_LEN, 2, - MAX_CHUNK_LEN, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &descs[i].map))) - { - printf("%s: bus_dmamap_create() failed; error %d\n", NAME_UNIT, error); - return error; - } - -#elif defined(__bsdi__) - - /* Allocate wired physical memory for DMA descriptor array. */ - if ((ring->first = malloc(size_descs, M_DEVBUF, M_NOWAIT)) == NULL) - { - printf("%s: malloc() failed for DMA descriptor array\n", NAME_UNIT); - return ENOMEM; - } - descs = ring->first; - memset(descs, 0, size_descs); - - /* Map kernel virtual address to PCI address for DMA descriptor array. */ - ring->dma_addr = vtophys(descs); /* Relax! BSD/OS only. */ - -#endif ring->read = descs; ring->write = descs; @@ -2765,7 +2466,6 @@ destroy_ring(softc_t *sc, struct desc_ring *ring) if (ring->read++ == ring->last) ring->read = ring->first; } -#ifdef __FreeBSD__ /* Free the dmamaps of all DMA descriptors. */ for (desc=ring->first; desc!=ring->last+1; desc++) @@ -2782,33 +2482,6 @@ destroy_ring(softc_t *sc, struct desc_ring *ring) if (ring->tag != NULL) bus_dma_tag_destroy(ring->tag); -#elif (defined(__NetBSD__) || defined(__OpenBSD__)) - - /* Free the dmamaps of all DMA descriptors. */ - for (desc=ring->first; desc!=ring->last+1; desc++) - if (desc->map != NULL) - bus_dmamap_destroy(ring->tag, desc->map); - - /* Unmap PCI address for DMA descriptor array. */ - if (ring->dma_addr != 0) - bus_dmamap_unload(ring->tag, ring->map); - /* Free dmamap for DMA descriptor array. */ - if (ring->map != NULL) - bus_dmamap_destroy(ring->tag, ring->map); - /* Unmap kernel address for DMA descriptor array. */ - if (ring->first != NULL) - bus_dmamem_unmap(ring->tag, (caddr_t)ring->first, ring->size_descs); - /* Free kernel memory for DMA descriptor array. */ - if (ring->segs[0].ds_addr != 0) - bus_dmamem_free(ring->tag, ring->segs, ring->nsegs); - -#elif defined(__bsdi__) - - /* Free kernel memory for DMA descriptor array. */ - if (ring->first != NULL) - free(ring->first, M_DEVBUF); - -#endif } /* Clean up after a packet has been received. */ @@ -2821,7 +2494,7 @@ rxintr_cleanup(softc_t *sc) struct mbuf *new_mbuf; int pkt_len, desc_len; -#if (defined(__FreeBSD__) && defined(DEVICE_POLLING)) +#if defined(DEVICE_POLLING) /* Input packet flow control (livelock prevention): */ /* Give pkts to higher levels only if quota is > 0. */ if (sc->quota <= 0) return 0; @@ -2890,11 +2563,7 @@ rxintr_cleanup(softc_t *sc) { first_mbuf = new_mbuf; first_mbuf->m_pkthdr.len = pkt_len; /* total pkt length */ -#if IFNET first_mbuf->m_pkthdr.rcvif = sc->ifp; /* how it got here */ -#else - first_mbuf->m_pkthdr.rcvif = NULL; -#endif } else /* 2) link mbufs. */ { @@ -2933,11 +2602,9 @@ rxintr_cleanup(softc_t *sc) /* Include CRC and one flag byte in input byte count. */ sc->status.cntrs.ibytes += first_mbuf->m_pkthdr.len + sc->config.crc_len +1; sc->status.cntrs.ipackets++; -#if IFNET sc->ifp->if_ipackets++; LMC_BPF_MTAP(first_mbuf); -#endif -#if (defined(__FreeBSD__) && defined(DEVICE_POLLING)) +#if defined(DEVICE_POLLING) sc->quota--; #endif @@ -2945,12 +2612,8 @@ rxintr_cleanup(softc_t *sc) #if NETGRAPH if (sc->ng_hook != NULL) /* is hook connected? */ { -# if (__FreeBSD_version >= 500000) int error; /* ignore error */ NG_SEND_DATA_ONLY(error, sc->ng_hook, first_mbuf); -# else /* FreeBSD-4 */ - ng_queue_data(sc->ng_hook, first_mbuf, NULL); -# endif return 1; /* did something */ } #endif /* NETGRAPH */ @@ -3053,13 +2716,7 @@ rxintr_setup(softc_t *sc) DMA_SYNC(desc->map, desc_len, BUS_DMASYNC_PREREAD); /* Set up the DMA descriptor. */ -#ifdef __FreeBSD__ desc->address1 = ring->segs[0].ds_addr; -#elif (defined(__NetBSD__) || defined(__OpenBSD__)) - desc->address1 = desc->map->dm_segs[0].ds_addr; -#elif defined(__bsdi__) - desc->address1 = vtophys(m->m_data); /* Relax! BSD/OS only. */ -#endif desc->length1 = desc_len>>1; desc->address2 = desc->address1 + desc->length1; desc->length2 = desc_len>>1; @@ -3108,10 +2765,8 @@ txintr_cleanup(softc_t *sc) /* Include CRC and one flag byte in output byte count. */ sc->status.cntrs.obytes += m->m_pkthdr.len + sc->config.crc_len +1; sc->status.cntrs.opackets++; -#if IFNET sc->ifp->if_opackets++; LMC_BPF_MTAP(m); -#endif /* The only bad TX status is fifo underrun. */ if ((desc->status & TLP_DSTS_TX_UNDERRUN) != 0) sc->status.cntrs.fifo_under++; @@ -3181,15 +2836,9 @@ txintr_setup_mbuf(softc_t *sc, struct mbuf *m) /* Prevent wild fetches if mapping fails (nsegs==0). */ desc->length1 = desc->length2 = 0; desc->address1 = desc->address2 = 0; -#if (defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) { -# ifdef __FreeBSD__ bus_dma_segment_t *segs = ring->segs; int nsegs = ring->nsegs; -# elif (defined(__NetBSD__) || defined(__OpenBSD__)) - bus_dma_segment_t *segs = desc->map->dm_segs; - int nsegs = desc->map->dm_nsegs; -# endif if (nsegs >= 1) { desc->address1 = segs[0].ds_addr; @@ -3201,10 +2850,6 @@ txintr_setup_mbuf(softc_t *sc, struct mbuf *m) desc->length2 = segs[1].ds_len; } } -#elif defined(__bsdi__) - desc->address1 = vtophys(data); /* Relax! BSD/OS only. */ - desc->length1 = desc_len; -#endif data += desc_len; length -= desc_len; @@ -3296,1016 +2941,460 @@ txintr_setup(softc_t *sc) return 1; /* did something */ } -#endif /* BSD */ - -#ifdef __linux__ -/* NOTE: this is the LINUX version of the interrupt/DMA code, */ - -/* Singly-linked tail-queues hold sk_buffs with active DMA. - * skbuffs are linked through their sk_buff.next field. - * Callers must hold sc->bottom_lock; not otherwise locked. - */ - -/* Put an skbuff on the tail of the descriptor ring queue. */ -static void /* Linux version */ -skbuff_enqueue(struct desc_ring *ring, struct sk_buff *skb) - { - skb->next = NULL; - if (ring->tail == NULL) - ring->head = skb; - else - ring->tail->next = skb; - ring->tail = skb; - } - -/* Get an skbuff from the head of the descriptor ring queue. */ -static struct sk_buff* /* Linux version */ -skbuff_dequeue(struct desc_ring *ring) - { - struct sk_buff *skb = ring->head; - if (skb != NULL) - if ((ring->head = skb->next) == NULL) - ring->tail = NULL; - return skb; - } - -/* Initialize a DMA descriptor ring. */ -static int /* Linux version */ -create_ring(softc_t *sc, struct desc_ring *ring, int num_descs) - { - struct dma_desc *descs; - int size_descs = sizeof(struct dma_desc)*num_descs; - - /* Allocate and map memory for DMA descriptor array. */ - if ((descs = pci_alloc_consistent(sc->pci_dev, size_descs, - &ring->dma_addr)) == NULL) - { - printk("%s: pci_alloc_consistent() failed\n", NAME_UNIT); - return ENOMEM; - } - memset(descs, 0, size_descs); - - ring->read = descs; - ring->write = descs; - ring->first = descs; - ring->last = descs + num_descs -1; - ring->last->control = TLP_DCTL_END_RING; - ring->num_descs = num_descs; - ring->size_descs = size_descs; - ring->head = NULL; - ring->tail = NULL; - return 0; - } -/* Destroy a DMA descriptor ring */ -static void /* Linux version */ -destroy_ring(softc_t *sc, struct desc_ring *ring) +static void +check_intr_status(softc_t *sc) { - struct sk_buff *skb; + u_int32_t status, cfcs, op_mode; + u_int32_t missed, overruns; - /* Free queued skbuffs. */ - while ((skb = skbuff_dequeue(ring)) != NULL) - dev_kfree_skb(skb); + /* Check for four unusual events: + * 1) fatal PCI bus errors - some are recoverable + * 2) transmitter FIFO underruns - increase fifo threshold + * 3) receiver FIFO overruns - clear potential hangup + * 4) no receive descs or bufs - count missed packets + */ - /* TX may have one pkt that is not on any queue. */ - if (sc->tx_skb != NULL) + /* 1) A fatal bus error causes a Tulip to stop initiating bus cycles. */ + /* Module unload/load or boot are the only fixes for Parity Errors. */ + /* Master and Target Aborts can be cleared and life may continue. */ + status = READ_CSR(TLP_STATUS); + if ((status & TLP_STAT_FATAL_ERROR) != 0) { - dev_kfree_skb(sc->tx_skb); - sc->tx_skb = NULL; + u_int32_t fatal = (status & TLP_STAT_FATAL_BITS)>>TLP_STAT_FATAL_SHIFT; + printf("%s: FATAL PCI BUS ERROR: %s%s%s%s\n", NAME_UNIT, + (fatal == 0) ? "PARITY ERROR" : "", + (fatal == 1) ? "MASTER ABORT" : "", + (fatal == 2) ? "TARGET ABORT" : "", + (fatal >= 3) ? "RESERVED (?)" : ""); + cfcs = READ_PCI_CFG(sc, TLP_CFCS); /* try to clear it */ + cfcs &= ~(TLP_CFCS_MSTR_ABORT | TLP_CFCS_TARG_ABORT); + WRITE_PCI_CFG(sc, TLP_CFCS, cfcs); } - if (ring->first != NULL) + /* 2) If the transmitter fifo underruns, increase the transmit fifo */ + /* threshold: the number of bytes required to be in the fifo */ + /* before starting the transmitter (cost: increased tx delay). */ + /* The TX_FSM must be stopped to change this parameter. */ + if ((status & TLP_STAT_TX_UNDERRUN) != 0) { - /* Unmap active DMA descriptors. */ - while (ring->read != ring->write) + op_mode = READ_CSR(TLP_OP_MODE); + /* enable store-and-forward mode if tx_threshold tops out? */ + if ((op_mode & TLP_OP_TX_THRESH) < TLP_OP_TX_THRESH) { - pci_unmap_single(sc->pci_dev, ring->read->address1, - ring->read->length1 + ring->read->length2, PCI_DMA_BIDIRECTIONAL); - if (ring->read++ == ring->last) ring->read = ring->first; + op_mode += 0x4000; /* increment TX_THRESH field; can't overflow */ + WRITE_CSR(TLP_OP_MODE, op_mode & ~TLP_OP_TX_RUN); + /* Wait for the TX FSM to stop; it might be processing a pkt. */ + while (READ_CSR(TLP_STATUS) & TLP_STAT_TX_FSM); /* XXX HANG */ + WRITE_CSR(TLP_OP_MODE, op_mode); /* restart tx */ + if (DRIVER_DEBUG) + printf("%s: tx underrun; tx fifo threshold now %d bytes\n", + NAME_UNIT, 128<<((op_mode>>TLP_OP_TR_SHIFT)&3)); } - - /* Unmap and free memory for DMA descriptor array. */ - pci_free_consistent(sc->pci_dev, ring->size_descs, ring->first, - ring->dma_addr); } - } - -static int /* Linux version */ -rxintr_cleanup(softc_t *sc) - { - struct desc_ring *ring = &sc->rxring; - struct dma_desc *first_desc, *last_desc; - struct sk_buff *first_skb=NULL, *last_skb=NULL; - struct sk_buff *new_skb; - int pkt_len, desc_len; - /* Input packet flow control (livelock prevention): */ - /* Give pkts to higher levels only if quota is > 0. */ - if (sc->quota <= 0) return 0; - - /* This looks complicated, but remember: packets up to 4032 */ - /* bytes long fit in one skbuff and use one DMA descriptor. */ - - first_desc = last_desc = ring->read; - - /* ASSERTION: If there is a descriptor in the ring and the hardware has */ - /* finished with it, then that descriptor will have RX_FIRST_DESC set. */ - if ((ring->read != ring->write) && /* descriptor ring not empty */ - ((ring->read->status & TLP_DSTS_OWNER) == 0) && /* hardware done */ - ((ring->read->status & TLP_DSTS_RX_FIRST_DESC) == 0)) /* should be set */ - panic("%s: rxintr_cleanup: rx-first-descriptor not set.\n", NAME_UNIT); - - /* First decide if a complete packet has arrived. */ - /* Run down DMA descriptors looking for one marked "last". */ - /* Bail out if an active descriptor is encountered. */ - /* Accumulate most significant bits of packet length. */ - pkt_len = 0; - for (;;) - { - if (last_desc == ring->write) return 0; /* no more descs */ - if (last_desc->status & TLP_DSTS_OWNER) return 0; /* still active */ - if (last_desc->status & TLP_DSTS_RX_LAST_DESC) break; /* end of packet */ - pkt_len += last_desc->length1 + last_desc->length2; /* entire desc filled */ - if (last_desc++->control & TLP_DCTL_END_RING) last_desc = ring->first; /* ring wrap */ - } - - /* A complete packet has arrived; how long is it? */ - /* H/w ref man shows RX pkt length as a 14-bit field. */ - /* An experiment found that only the 12 LSBs work. */ - if (((last_desc->status>>16)&0xFFF) == 0) pkt_len += 4096; /* carry-bit */ - pkt_len = (pkt_len & 0xF000) + ((last_desc->status>>16) & 0x0FFF); - /* Subtract the CRC length unless doing so would underflow. */ - if (pkt_len >= sc->config.crc_len) pkt_len -= sc->config.crc_len; - - /* Run down DMA descriptors again doing the following: - * 1) put pkt info in hdr of first skbuff. - * 2) put additional skbuffs on frag_list. - * 3) set skbuff lengths. - */ - first_desc = ring->read; - do + /* 3) Errata memo from Digital Equipment Corp warns that 21140A */ + /* receivers through rev 2.2 can hang if the fifo overruns. */ + /* Recommended fix: stop and start the RX FSM after an overrun. */ + missed = READ_CSR(TLP_MISSED); + if ((overruns = ((missed & TLP_MISS_OVERRUN)>>TLP_OVERRUN_SHIFT)) != 0) { - /* Read a DMA descriptor from the ring. */ - last_desc = ring->read; - /* Advance the ring read pointer. */ - if (ring->read++ == ring->last) ring->read = ring->first; - - /* Dequeue the corresponding skbuff. */ - new_skb = skbuff_dequeue(ring); - if (new_skb == NULL) - panic("%s: rxintr_cleanup: expected an skbuff\n", NAME_UNIT); - - desc_len = last_desc->length1 + last_desc->length2; - /* Unmap kernel virtual addresss to PCI address. */ - pci_unmap_single(sc->pci_dev, last_desc->address1, - desc_len, PCI_DMA_FROMDEVICE); - - /* Set skbuff length. */ - skb_put(new_skb, (pkt_len >= desc_len) ? desc_len : pkt_len); - pkt_len -= new_skb->len; - - /* 1) Put pkt info in hdr of first skbuff. */ - if (last_desc == first_desc) - { - first_skb = new_skb; - if (sc->config.line_pkg == PKG_RAWIP) - { - if (first_skb->data[0]>>4 == 4) - first_skb->protocol = htons(ETH_P_IP); - else if (first_skb->data[0]>>4 == 6) - first_skb->protocol = htons(ETH_P_IPV6); - } - else -#if GEN_HDLC - first_skb->protocol = hdlc_type_trans(first_skb, sc->net_dev); -#else - first_skb->protocol = htons(ETH_P_HDLC); -#endif - first_skb->mac.raw = first_skb->data; - first_skb->dev = sc->net_dev; - do_gettimeofday(&first_skb->stamp); - sc->net_dev->last_rx = jiffies; - } - else /* 2) link skbuffs. */ + if (DRIVER_DEBUG) + printf("%s: rx overrun cntr=%d\n", NAME_UNIT, overruns); + sc->status.cntrs.overruns += overruns; + if ((READ_PCI_CFG(sc, TLP_CFRV) & 0xFF) <= 0x22) { - /* Put this skbuff on the frag_list of the first skbuff. */ - new_skb->next = NULL; - if (skb_shinfo(first_skb)->frag_list == NULL) - skb_shinfo(first_skb)->frag_list = new_skb; - else - last_skb->next = new_skb; - /* 3) set skbuff lengths. */ - first_skb->len += new_skb->len; - first_skb->data_len += new_skb->len; + op_mode = READ_CSR(TLP_OP_MODE); + WRITE_CSR(TLP_OP_MODE, op_mode & ~TLP_OP_RX_RUN); + /* Wait for the RX FSM to stop; it might be processing a pkt. */ + while (READ_CSR(TLP_STATUS) & TLP_STAT_RX_FSM); /* XXX HANG */ + WRITE_CSR(TLP_OP_MODE, op_mode); /* restart rx */ } - last_skb = new_skb; - } while ((last_desc->status & TLP_DSTS_RX_LAST_DESC) == 0); - - /* Decide whether to accept or to discard this packet. */ - /* RxHDLC sets MIIERR for bad CRC, abort and partial byte at pkt end. */ - if (((last_desc->status & TLP_DSTS_RX_BAD) == 0) && - (sc->status.oper_status == STATUS_UP) && - (first_skb->len > 0)) - { - /* Optimization: copy a small pkt into a small skbuff. */ - if (first_skb->len <= COPY_BREAK) - if ((new_skb = skb_copy(first_skb, GFP_ATOMIC)) != NULL) - { - dev_kfree_skb_any(first_skb); - first_skb = new_skb; - } - - /* Include CRC and one flag byte in input byte count. */ - sc->status.cntrs.ibytes += first_skb->len + sc->config.crc_len +1; - sc->status.cntrs.ipackets++; - - /* Give this good packet to the network stacks. */ - netif_receive_skb(first_skb); /* NAPI */ - sc->quota--; } - else if (sc->status.oper_status != STATUS_UP) - { - /* If the link is down, this packet is probably noise. */ - sc->status.cntrs.idiscards++; - dev_kfree_skb_any(first_skb); - if (DRIVER_DEBUG) - printk("%s: rxintr_cleanup: rx pkt discarded: link down\n", NAME_UNIT); - } - else /* Log and discard this bad packet. */ + + /* 4) When the receiver is enabled and a packet arrives, but no DMA */ + /* descriptor is available, the packet is counted as 'missed'. */ + /* The receiver should never miss packets; warn if it happens. */ + if ((missed = (missed & TLP_MISS_MISSED)) != 0) { if (DRIVER_DEBUG) - printk("%s: RX bad pkt; len=%d %s%s%s%s\n", - NAME_UNIT, first_skb->len, - (last_desc->status & TLP_DSTS_RX_MII_ERR) ? " miierr" : "", - (last_desc->status & TLP_DSTS_RX_DRIBBLE) ? " dribble" : "", - (last_desc->status & TLP_DSTS_RX_DESC_ERR) ? " descerr" : "", - (last_desc->status & TLP_DSTS_RX_OVERRUN) ? " overrun" : ""); - if (last_desc->status & TLP_DSTS_RX_OVERRUN) - sc->status.cntrs.fifo_over++; - else - sc->status.cntrs.ierrors++; - dev_kfree_skb_any(first_skb); + printf("%s: rx missed %d pkts\n", NAME_UNIT, missed); + sc->status.cntrs.missed += missed; } - - return 1; /* did something */ } -/* Setup (prepare) to receive a packet. */ -/* Try to keep the RX descriptor ring full of empty buffers. */ -static int /* Linux version */ -rxintr_setup(softc_t *sc) +static void /* This is where the work gets done. */ +core_interrupt(void *arg, int check_status) { - struct desc_ring *ring = &sc->rxring; - struct dma_desc *desc; - struct sk_buff *skb; - u_int32_t dma_addr; - - /* Ring is full if (wrap(write+1)==read) */ - if (((ring->write == ring->last) ? ring->first : ring->write+1) == ring->read) - return 0; /* ring is full; nothing to do */ + softc_t *sc = arg; + int activity; - /* Allocate an skbuff. */ - if ((skb = dev_alloc_skb(MAX_DESC_LEN)) == NULL) + /* If any CPU is inside this critical section, then */ + /* other CPUs should go away without doing anything. */ + if (BOTTOM_TRYLOCK == 0) { - sc->status.cntrs.rxdma++; - if (DRIVER_DEBUG) - printk("%s: rxintr_setup: dev_alloc_skb() failed\n", NAME_UNIT); - return 0; + sc->status.cntrs.lck_intr++; + return; } - skb->dev = sc->net_dev; - - /* Queue the skbuff for later processing by rxintr_cleanup. */ - skbuff_enqueue(ring, skb); - /* Write a DMA descriptor into the ring. */ - /* Hardware won't see it until the OWNER bit is set. */ - desc = ring->write; - /* Advance the ring write pointer. */ - if (ring->write++ == ring->last) ring->write = ring->first; + /* Clear pending card interrupts. */ + WRITE_CSR(TLP_STATUS, READ_CSR(TLP_STATUS)); - /* Map kernel virtual addresses to PCI addresses. */ - dma_addr = pci_map_single(sc->pci_dev, skb->data, - MAX_DESC_LEN, PCI_DMA_FROMDEVICE); - /* Set up the DMA descriptor. */ - desc->address1 = dma_addr; - desc->length1 = MAX_CHUNK_LEN; - desc->address2 = desc->address1 + desc->length1; - desc->length2 = MAX_CHUNK_LEN; + /* In Linux, pci_alloc_consistent() means DMA descriptors */ + /* don't need explicit syncing. */ + { + struct desc_ring *ring = &sc->txring; + DMA_SYNC(sc->txring.map, sc->txring.size_descs, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + ring = &sc->rxring; + DMA_SYNC(sc->rxring.map, sc->rxring.size_descs, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + } - /* Before setting the OWNER bit, flush the cache (memory barrier). */ - wmb(); /* write memory barrier */ + do /* This is the main loop for interrupt processing. */ + { + activity = txintr_cleanup(sc); + activity += txintr_setup(sc); + activity += rxintr_cleanup(sc); + activity += rxintr_setup(sc); + } while (activity); - /* Commit the DMA descriptor to the hardware. */ - desc->status = TLP_DSTS_OWNER; + { + struct desc_ring *ring = &sc->txring; + DMA_SYNC(sc->txring.map, sc->txring.size_descs, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + ring = &sc->rxring; + DMA_SYNC(sc->rxring.map, sc->rxring.size_descs, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + } - /* Notify the receiver that there is another buffer available. */ - WRITE_CSR(TLP_RX_POLL, 1); + /* As the interrupt is dismissed, check for four unusual events. */ + if (check_status) check_intr_status(sc); - return 1; /* did something */ + BOTTOM_UNLOCK; } -/* Clean up after a packet has been transmitted. */ -/* Free the sk_buff and update the DMA descriptor ring. */ -static int /* Linux version */ -txintr_cleanup(softc_t *sc) +/* user_interrupt() may be called from a syscall or a softirq */ +static void +user_interrupt(softc_t *sc, int check_status) { - struct desc_ring *ring = &sc->txring; - struct dma_desc *desc; - - while ((ring->read != ring->write) && /* ring is not empty */ - ((ring->read->status & TLP_DSTS_OWNER) == 0)) - { - /* Read a DMA descriptor from the ring. */ - desc = ring->read; - /* Advance the ring read pointer. */ - if (ring->read++ == ring->last) ring->read = ring->first; - /* Unmap kernel virtual address to PCI address. */ - pci_unmap_single(sc->pci_dev, desc->address1, - desc->length1 + desc->length2, PCI_DMA_TODEVICE); + DISABLE_INTR; /* noop on FreeBSD-5 and Linux */ + core_interrupt(sc, check_status); + ENABLE_INTR; /* noop on FreeBSD-5 and Linux */ + } - /* If this descriptor is the last segment of a packet, */ - /* then dequeue and free the corresponding skbuff. */ - if ((desc->control & TLP_DCTL_TX_LAST_SEG) != 0) - { - struct sk_buff *skb; - if ((skb = skbuff_dequeue(ring)) == NULL) - panic("%s: txintr_cleanup: expected an sk_buff\n", NAME_UNIT); - /* Include CRC and one flag byte in output byte count. */ - sc->status.cntrs.obytes += skb->len + sc->config.crc_len +1; - sc->status.cntrs.opackets++; +# if defined(DEVICE_POLLING) - /* The only bad TX status is fifo underrun. */ - if ((desc->status & TLP_DSTS_TX_UNDERRUN) != 0) - { - sc->status.cntrs.fifo_under++; /* also increment oerrors? */ - if (DRIVER_DEBUG) - printk("%s: txintr_cleanup: tx fifo underrun\n", NAME_UNIT); - } +/* Service the card from the kernel idle loop without interrupts. */ +static int +fbsd_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) + { + softc_t *sc = IFP2SC(ifp); - dev_kfree_skb_any(skb); - return 1; /* did something */ - } - } + sc->quota = count; + core_interrupt(sc, (cmd==POLL_AND_CHECK_STATUS)); return 0; } -/* Build DMA descriptors for a tranmit packet fragment, */ -/* Assertion: fragment is contiguous in physical memory. */ -static int /* 0=success; 1=error */ /* linux version */ -txintr_setup_frag(softc_t *sc, char *data, int length) +# endif /* DEVICE_POLLING */ + +/* BSD kernels call this procedure when an interrupt happens. */ +static intr_return_t +bsd_interrupt(void *arg) { - struct desc_ring *ring = &sc->txring; - struct dma_desc *desc; - unsigned int desc_len; - u_int32_t dma_addr; + softc_t *sc = arg; - while (length > 0) + /* Cut losses early if this is not our interrupt. */ + if ((READ_CSR(TLP_STATUS) & TLP_INT_TXRX) == 0) + return IRQ_NONE; + +# if defined(DEVICE_POLLING) + if (sc->ifp->if_capenable & IFCAP_POLLING) + return IRQ_NONE; + + if ((sc->ifp->if_capabilities & IFCAP_POLLING) && + (ether_poll_register(fbsd_poll, sc->ifp))) { - /* Ring is full if (wrap(write+1)==read) */ - if (((ring->temp==ring->last) ? ring->first : ring->temp+1) == ring->read) - { /* Not enough DMA descriptors; try later. */ - for (; ring->temp!=ring->write; - ring->temp = (ring->temp==ring->first)? ring->last : ring->temp-1) - pci_unmap_single(sc->pci_dev, ring->temp->address1, - ring->temp->length1 + ring->temp->length2, PCI_DMA_FROMDEVICE); - sc->status.cntrs.txdma++; - return 1; - } + WRITE_CSR(TLP_INT_ENBL, TLP_INT_DISABLE); + return IRQ_NONE; + } + else + sc->quota = sc->rxring.num_descs; /* input flow control */ +# endif /* DEVICE_POLLING */ - /* Provisionally, write a DMA descriptor into the ring. */ - /* But don't change the REAL ring write pointer. */ - /* Hardware won't see it until the OWNER bit is set. */ - desc = ring->temp; - /* Advance the temporary ring write pointer. */ - if (ring->temp++ == ring->last) ring->temp = ring->first; - - /* Clear all control bits except the END_RING bit. */ - desc->control &= TLP_DCTL_END_RING; - /* Don't pad short packets up to 64 bytes */ - desc->control |= TLP_DCTL_TX_NO_PAD; - /* Use Tulip's CRC-32 generator, if appropriate. */ - if (sc->config.crc_len != CFG_CRC_32) - desc->control |= TLP_DCTL_TX_NO_CRC; - /* Set the OWNER bit, except in the first descriptor. */ - if (desc != ring->write) - desc->status = TLP_DSTS_OWNER; - - desc_len = (length >= MAX_DESC_LEN) ? MAX_DESC_LEN : length; - /* Map kernel virtual address to PCI address. */ - dma_addr = pci_map_single(sc->pci_dev, data, desc_len, PCI_DMA_TODEVICE); - /* If it will fit in one chunk, do so, otherwise split it. */ - if (desc_len <= MAX_CHUNK_LEN) - { - desc->address1 = dma_addr; - desc->length1 = desc_len; - desc->address2 = 0; - desc->length2 = 0; - } - else - { - desc->address1 = dma_addr; - desc->length1 = desc_len>>1; - desc->address2 = desc->address1 + desc->length1; - desc->length2 = desc_len>>1; - if (desc_len & 1) desc->length2++; - } + /* Disable card interrupts. */ + WRITE_CSR(TLP_INT_ENBL, TLP_INT_DISABLE); - data += desc_len; - length -= desc_len; - } /* while (length > 0) */ + core_interrupt(sc, 0); - return 0; /* success */ - } + /* Enable card interrupts. */ + WRITE_CSR(TLP_INT_ENBL, TLP_INT_TXRX); -/* NB: this procedure is recursive! */ -static int /* 0=success; 1=error */ -txintr_setup_skb(softc_t *sc, struct sk_buff *skb) - { - struct sk_buff *list; - int i; + return IRQ_HANDLED; + } - /* First, handle the data in the skbuff itself. */ - if (txintr_setup_frag(sc, skb->data, skb_headlen(skb))) - return 1; - /* Next, handle the VM pages in the Scatter/Gather list. */ - if (skb_shinfo(skb)->nr_frags != 0) - for (i=0; inr_frags; i++) - { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - if (txintr_setup_frag(sc, page_address(frag->page) + - frag->page_offset, frag->size)) - return 1; - } - - /* Finally, handle the skbuffs in the frag_list. */ - if ((list = skb_shinfo(skb)->frag_list) != NULL) - for (; list; list=list->next) - if (txintr_setup_skb(sc, list)) /* recursive! */ - return 1; - - return 0; - } - -/* Setup (prepare) to transmit a packet. */ -/* Select a packet, build DMA descriptors and give packet to hardware. */ -/* If DMA descriptors run out, abandon the attempt and return 0. */ -static int /* Linux version */ -txintr_setup(softc_t *sc) +/* Administrative status of the driver (UP or DOWN) has changed. */ +/* A card-specific action may be required: T1 and T3 cards: no-op. */ +/* HSSI and SSI cards change the state of modem ready signals. */ +static void +set_status(softc_t *sc, int status) { - struct desc_ring *ring = &sc->txring; - struct dma_desc *first_desc, *last_desc; + struct ioctl ioctl; - /* Protect against half-up links: Don't transmit */ - /* if the receiver can't hear the far end. */ - if (sc->status.oper_status != STATUS_UP) return 0; + ioctl.cmd = IOCTL_SET_STATUS; + ioctl.data = status; - /* Pick a packet to transmit. */ - /* linux_start() puts packets in sc->tx_skb. */ - if (sc->tx_skb == NULL) - { - if (netif_queue_stopped(sc->net_dev) != 0) - netif_wake_queue(sc->net_dev); - return 0; /* no pkt to transmit */ - } + sc->card->ioctl(sc, &ioctl); + } - /* Build DMA descriptors for an outgoing skbuff. */ - ring->temp = ring->write; /* temporary ring write pointer */ - if (txintr_setup_skb(sc, sc->tx_skb) != 0) return 0; +#if P2P - /* Enqueue the skbuff; txintr_cleanup will free it. */ - skbuff_enqueue(ring, sc->tx_skb); +/* Callout from P2P: */ +/* Get the state of DCD (Data Carrier Detect). */ +static int +p2p_getmdm(struct p2pcom *p2p, caddr_t result) + { + softc_t *sc = IFP2SC(&p2p->p2p_if); - /* The transmitter has room for another packet. */ - sc->tx_skb = NULL; + /* Non-zero isn't good enough; TIOCM_CAR is 0x40. */ + *(int *)result = (sc->status.oper_status==STATUS_UP) ? TIOCM_CAR : 0; - /* Set first & last segment bits. */ - /* last_desc is the desc BEFORE the one pointed to by ring->temp. */ - first_desc = ring->write; - first_desc->control |= TLP_DCTL_TX_FIRST_SEG; - last_desc = (ring->temp==ring->first)? ring->last : ring->temp-1; - last_desc->control |= TLP_DCTL_TX_LAST_SEG; - /* Interrupt at end-of-transmission? Why bother the poor computer! */ -/* last_desc->control |= TLP_DCTL_TX_INTERRUPT; */ + return 0; + } - /* Make sure the OWNER bit is not set in the next descriptor. */ - /* The OWNER bit may have been set if a previous call aborted. */ - ring->temp->status = 0; +/* Callout from P2P: */ +/* Set the state of DTR (Data Terminal Ready). */ +static int +p2p_mdmctl(struct p2pcom *p2p, int flag) + { + softc_t *sc = IFP2SC(&p2p->p2p_if); - /* Commit the DMA descriptors to the software. */ - ring->write = ring->temp; + set_status(sc, flag); - /* Before setting the OWNER bit, flush the cache (memory barrier). */ - wmb(); /* write memory barrier */ + return 0; + } - /* Commit the DMA descriptors to the hardware. */ - first_desc->status = TLP_DSTS_OWNER; +#endif /* P2P */ - /* Notify the transmitter that there is another packet to send. */ - WRITE_CSR(TLP_TX_POLL, 1); +#if NSPPP - sc->net_dev->trans_start = jiffies; +# ifndef PP_FR +# define PP_FR 0 +# endif - return 1; /* did something */ +/* Callout from SPPP: */ +static void +sppp_tls(struct sppp *sppp) + { + if (!(sppp->pp_mode & IFF_LINK2) && + !(sppp->pp_flags & PP_FR)) + sppp->pp_up(sppp); } -#endif /* __linux__ */ - +/* Callout from SPPP: */ static void -check_intr_status(softc_t *sc) +sppp_tlf(struct sppp *sppp) { - u_int32_t status, cfcs, op_mode; - u_int32_t missed, overruns; - - /* Check for four unusual events: - * 1) fatal PCI bus errors - some are recoverable - * 2) transmitter FIFO underruns - increase fifo threshold - * 3) receiver FIFO overruns - clear potential hangup - * 4) no receive descs or bufs - count missed packets - */ + if (!(sppp->pp_mode & IFF_LINK2) && + !(sppp->pp_flags & PP_FR)) + sppp->pp_down(sppp); + } - /* 1) A fatal bus error causes a Tulip to stop initiating bus cycles. */ - /* Module unload/load or boot are the only fixes for Parity Errors. */ - /* Master and Target Aborts can be cleared and life may continue. */ - status = READ_CSR(TLP_STATUS); - if ((status & TLP_STAT_FATAL_ERROR) != 0) - { - u_int32_t fatal = (status & TLP_STAT_FATAL_BITS)>>TLP_STAT_FATAL_SHIFT; - printf("%s: FATAL PCI BUS ERROR: %s%s%s%s\n", NAME_UNIT, - (fatal == 0) ? "PARITY ERROR" : "", - (fatal == 1) ? "MASTER ABORT" : "", - (fatal == 2) ? "TARGET ABORT" : "", - (fatal >= 3) ? "RESERVED (?)" : ""); - cfcs = READ_PCI_CFG(sc, TLP_CFCS); /* try to clear it */ - cfcs &= ~(TLP_CFCS_MSTR_ABORT | TLP_CFCS_TARG_ABORT); - WRITE_PCI_CFG(sc, TLP_CFCS, cfcs); - } +#endif /* NSPPP */ - /* 2) If the transmitter fifo underruns, increase the transmit fifo */ - /* threshold: the number of bytes required to be in the fifo */ - /* before starting the transmitter (cost: increased tx delay). */ - /* The TX_FSM must be stopped to change this parameter. */ - if ((status & TLP_STAT_TX_UNDERRUN) != 0) +/* Configure line protocol stuff. + * Called by attach_card() during module init. + * Called by core_ioctl() when lmcconfig writes sc->config. + * Called by detach_card() during module shutdown. + */ +static void +config_proto(softc_t *sc, struct config *config) + { + /* Use line protocol stack instead of RAWIP mode. */ + if ((sc->config.line_pkg == PKG_RAWIP) && + (config->line_pkg != PKG_RAWIP)) { - op_mode = READ_CSR(TLP_OP_MODE); - /* enable store-and-forward mode if tx_threshold tops out? */ - if ((op_mode & TLP_OP_TX_THRESH) < TLP_OP_TX_THRESH) +#if NSPPP + LMC_BPF_DETACH; + sppp_attach(sc->ifp); + LMC_BPF_ATTACH(DLT_PPP, 4); + sc->sppp->pp_tls = sppp_tls; + sc->sppp->pp_tlf = sppp_tlf; + /* Force reconfiguration of SPPP params. */ + sc->config.line_prot = 0; + sc->config.keep_alive = config->keep_alive ? 0:1; +#elif P2P + int error = 0; + sc->p2p->p2p_proto = 0; /* force p2p_attach */ + if ((error = p2p_attach(sc->p2p))) /* calls bpfattach() */ { - op_mode += 0x4000; /* increment TX_THRESH field; can't overflow */ - WRITE_CSR(TLP_OP_MODE, op_mode & ~TLP_OP_TX_RUN); - /* Wait for the TX FSM to stop; it might be processing a pkt. */ - while (READ_CSR(TLP_STATUS) & TLP_STAT_TX_FSM); /* XXX HANG */ - WRITE_CSR(TLP_OP_MODE, op_mode); /* restart tx */ - if (DRIVER_DEBUG) - printf("%s: tx underrun; tx fifo threshold now %d bytes\n", - NAME_UNIT, 128<<((op_mode>>TLP_OP_TR_SHIFT)&3)); + printf("%s: p2p_attach() failed; error %d\n", NAME_UNIT, error); + config->line_pkg = PKG_RAWIP; /* still in RAWIP mode */ } - } - - /* 3) Errata memo from Digital Equipment Corp warns that 21140A */ - /* receivers through rev 2.2 can hang if the fifo overruns. */ - /* Recommended fix: stop and start the RX FSM after an overrun. */ - missed = READ_CSR(TLP_MISSED); - if ((overruns = ((missed & TLP_MISS_OVERRUN)>>TLP_OVERRUN_SHIFT)) != 0) - { - if (DRIVER_DEBUG) - printf("%s: rx overrun cntr=%d\n", NAME_UNIT, overruns); - sc->status.cntrs.overruns += overruns; - if ((READ_PCI_CFG(sc, TLP_CFRV) & 0xFF) <= 0x22) + else { - op_mode = READ_CSR(TLP_OP_MODE); - WRITE_CSR(TLP_OP_MODE, op_mode & ~TLP_OP_RX_RUN); - /* Wait for the RX FSM to stop; it might be processing a pkt. */ - while (READ_CSR(TLP_STATUS) & TLP_STAT_RX_FSM); /* XXX HANG */ - WRITE_CSR(TLP_OP_MODE, op_mode); /* restart rx */ + sc->p2p->p2p_mdmctl = p2p_mdmctl; /* set DTR */ + sc->p2p->p2p_getmdm = p2p_getmdm; /* get DCD */ + } +#elif GEN_HDLC + int error = 0; + sc->net_dev->mtu = HDLC_MAX_MTU; + if ((error = hdlc_open(sc->net_dev))) + { + printf("%s: hdlc_open() failed; error %d\n", NAME_UNIT, error); + printf("%s: Try 'sethdlc %s ppp'\n", NAME_UNIT, NAME_UNIT); + config->line_pkg = PKG_RAWIP; /* still in RAWIP mode */ } +#else /* no line protocol stack was configured */ + config->line_pkg = PKG_RAWIP; /* still in RAWIP mode */ +#endif } - /* 4) When the receiver is enabled and a packet arrives, but no DMA */ - /* descriptor is available, the packet is counted as 'missed'. */ - /* The receiver should never miss packets; warn if it happens. */ - if ((missed = (missed & TLP_MISS_MISSED)) != 0) + /* Bypass line protocol stack and return to RAWIP mode. */ + if ((sc->config.line_pkg != PKG_RAWIP) && + (config->line_pkg == PKG_RAWIP)) { - if (DRIVER_DEBUG) - printf("%s: rx missed %d pkts\n", NAME_UNIT, missed); - sc->status.cntrs.missed += missed; +#if NSPPP + LMC_BPF_DETACH; + sppp_flush(sc->ifp); + sppp_detach(sc->ifp); + setup_ifnet(sc->ifp); + LMC_BPF_ATTACH(DLT_RAW, 0); +#elif P2P + int error = 0; + if_qflush(&sc->p2p->p2p_isnd); + if ((error = p2p_detach(sc->p2p))) + { + printf("%s: p2p_detach() failed; error %d\n", NAME_UNIT, error); + printf("%s: Try 'ifconfig %s down -remove'\n", NAME_UNIT, NAME_UNIT); + config->line_pkg = PKG_P2P; /* not in RAWIP mode; still attached to P2P */ + } + else + { + setup_ifnet(sc->ifp); + LMC_BPF_ATTACH(DLT_RAW, 0); + } +#elif GEN_HDLC + hdlc_proto_detach(sc->hdlc_dev); + hdlc_close(sc->net_dev); + setup_netdev(sc->net_dev); +#endif } - } -static void /* This is where the work gets done. */ -core_interrupt(void *arg, int check_status) - { - softc_t *sc = arg; - int activity; +#if NSPPP - /* If any CPU is inside this critical section, then */ - /* other CPUs should go away without doing anything. */ - if (BOTTOM_TRYLOCK == 0) + if (config->line_pkg != PKG_RAWIP) { - sc->status.cntrs.lck_intr++; - return; - } + /* Check for change to PPP protocol. */ + if ((sc->config.line_prot != PROT_PPP) && + (config->line_prot == PROT_PPP)) + { + LMC_BPF_DETACH; + sc->ifp->if_flags &= ~IFF_LINK2; + sc->sppp->pp_flags &= ~PP_FR; + LMC_BPF_ATTACH(DLT_PPP, 4); + sppp_ioctl(sc->ifp, SIOCSIFFLAGS, NULL); + } - /* Clear pending card interrupts. */ - WRITE_CSR(TLP_STATUS, READ_CSR(TLP_STATUS)); +# ifndef DLT_C_HDLC +# define DLT_C_HDLC DLT_PPP +# endif - /* In Linux, pci_alloc_consistent() means DMA descriptors */ - /* don't need explicit syncing. */ -#if BSD - { - struct desc_ring *ring = &sc->txring; - DMA_SYNC(sc->txring.map, sc->txring.size_descs, - BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - ring = &sc->rxring; - DMA_SYNC(sc->rxring.map, sc->rxring.size_descs, - BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - } -#endif - - do /* This is the main loop for interrupt processing. */ - { - activity = txintr_cleanup(sc); - activity += txintr_setup(sc); - activity += rxintr_cleanup(sc); - activity += rxintr_setup(sc); - } while (activity); - -#if BSD - { - struct desc_ring *ring = &sc->txring; - DMA_SYNC(sc->txring.map, sc->txring.size_descs, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - ring = &sc->rxring; - DMA_SYNC(sc->rxring.map, sc->rxring.size_descs, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - } -#endif - - /* As the interrupt is dismissed, check for four unusual events. */ - if (check_status) check_intr_status(sc); - - BOTTOM_UNLOCK; - } + /* Check for change to C_HDLC protocol. */ + if ((sc->config.line_prot != PROT_C_HDLC) && + (config->line_prot == PROT_C_HDLC)) + { + LMC_BPF_DETACH; + sc->ifp->if_flags |= IFF_LINK2; + sc->sppp->pp_flags &= ~PP_FR; + LMC_BPF_ATTACH(DLT_C_HDLC, 4); + sppp_ioctl(sc->ifp, SIOCSIFFLAGS, NULL); + } -/* user_interrupt() may be called from a syscall or a softirq */ -static void -user_interrupt(softc_t *sc, int check_status) - { - DISABLE_INTR; /* noop on FreeBSD-5 and Linux */ - core_interrupt(sc, check_status); - ENABLE_INTR; /* noop on FreeBSD-5 and Linux */ - } + /* Check for change to Frame Relay protocol. */ + if ((sc->config.line_prot != PROT_FRM_RLY) && + (config->line_prot == PROT_FRM_RLY)) + { + LMC_BPF_DETACH; + sc->ifp->if_flags &= ~IFF_LINK2; + sc->sppp->pp_flags |= PP_FR; + LMC_BPF_ATTACH(DLT_FRELAY, 4); + sppp_ioctl(sc->ifp, SIOCSIFFLAGS, NULL); + } -#if BSD + /* Check for disabling keep-alives. */ + if ((sc->config.keep_alive != 0) && + (config->keep_alive == 0)) + sc->sppp->pp_flags &= ~PP_KEEPALIVE; -# if (defined(__FreeBSD__) && defined(DEVICE_POLLING)) + /* Check for enabling keep-alives. */ + if ((sc->config.keep_alive == 0) && + (config->keep_alive != 0)) + sc->sppp->pp_flags |= PP_KEEPALIVE; + } -/* Service the card from the kernel idle loop without interrupts. */ -static int -fbsd_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) - { - softc_t *sc = IFP2SC(ifp); +#endif /* NSPPP */ -#if (__FreeBSD_version < 700000) - if ((ifp->if_capenable & IFCAP_POLLING) == 0) + /* Loop back through the TULIP Ethernet chip; (no CRC). */ + /* Data sheet says stop DMA before changing OPMODE register. */ + /* But that's not as simple as it sounds; works anyway. */ + /* Check for enabling loopback thru Tulip chip. */ + if ((sc->config.loop_back != CFG_LOOP_TULIP) && + (config->loop_back == CFG_LOOP_TULIP)) { - ether_poll_deregister(ifp); - cmd = POLL_DEREGISTER; + u_int32_t op_mode = READ_CSR(TLP_OP_MODE); + op_mode |= TLP_OP_INT_LOOP; + WRITE_CSR(TLP_OP_MODE, op_mode); + config->crc_len = CFG_CRC_0; } - if (cmd == POLL_DEREGISTER) + /* Check for disabling loopback thru Tulip chip. */ + if ((sc->config.loop_back == CFG_LOOP_TULIP) && + (config->loop_back != CFG_LOOP_TULIP)) { - /* Last call -- reenable card interrupts. */ - WRITE_CSR(TLP_INT_ENBL, TLP_INT_TXRX); - return 0; + u_int32_t op_mode = READ_CSR(TLP_OP_MODE); + op_mode &= ~TLP_OP_LOOP_MODE; + WRITE_CSR(TLP_OP_MODE, op_mode); + config->crc_len = CFG_CRC_16; } -#endif - - sc->quota = count; - core_interrupt(sc, (cmd==POLL_AND_CHECK_STATUS)); - return 0; } -# endif /* (__FreeBSD__ && DEVICE_POLLING) */ - -/* BSD kernels call this procedure when an interrupt happens. */ -static intr_return_t -bsd_interrupt(void *arg) +/* This is the core ioctl procedure. */ +/* It handles IOCTLs from lmcconfig(8). */ +/* It must not run when card watchdogs run. */ +/* Called from a syscall (user context; no spinlocks). */ +/* This procedure can SLEEP. */ +static int +core_ioctl(softc_t *sc, u_long cmd, caddr_t data) { - softc_t *sc = arg; - - /* Cut losses early if this is not our interrupt. */ - if ((READ_CSR(TLP_STATUS) & TLP_INT_TXRX) == 0) - return IRQ_NONE; + struct iohdr *iohdr = (struct iohdr *) data; + struct ioctl *ioctl = (struct ioctl *) data; + struct status *status = (struct status *) data; + struct config *config = (struct config *) data; + int error = 0; -# if (defined(__FreeBSD__) && defined(DEVICE_POLLING)) - if (sc->ifp->if_capenable & IFCAP_POLLING) - return IRQ_NONE; + /* All structs start with a string and a cookie. */ + if (((struct iohdr *)data)->cookie != NGM_LMC_COOKIE) + return EINVAL; - if ((sc->ifp->if_capabilities & IFCAP_POLLING) && - (ether_poll_register(fbsd_poll, sc->ifp))) + while (TOP_TRYLOCK == 0) { - WRITE_CSR(TLP_INT_ENBL, TLP_INT_DISABLE); - return IRQ_NONE; + sc->status.cntrs.lck_ioctl++; + SLEEP(10000); /* yield? */ } - else - sc->quota = sc->rxring.num_descs; /* input flow control */ -# endif /* (__FreeBSD__ && DEVICE_POLLING) */ - - /* Disable card interrupts. */ - WRITE_CSR(TLP_INT_ENBL, TLP_INT_DISABLE); - - core_interrupt(sc, 0); - - /* Enable card interrupts. */ - WRITE_CSR(TLP_INT_ENBL, TLP_INT_TXRX); - - return IRQ_HANDLED; - } - -#endif /* BSD */ - -/* Administrative status of the driver (UP or DOWN) has changed. */ -/* A card-specific action may be required: T1 and T3 cards: no-op. */ -/* HSSI and SSI cards change the state of modem ready signals. */ -static void -set_status(softc_t *sc, int status) - { - struct ioctl ioctl; - - ioctl.cmd = IOCTL_SET_STATUS; - ioctl.data = status; - - sc->card->ioctl(sc, &ioctl); - } - -#if P2P - -/* Callout from P2P: */ -/* Get the state of DCD (Data Carrier Detect). */ -static int -p2p_getmdm(struct p2pcom *p2p, caddr_t result) - { - softc_t *sc = IFP2SC(&p2p->p2p_if); - - /* Non-zero isn't good enough; TIOCM_CAR is 0x40. */ - *(int *)result = (sc->status.oper_status==STATUS_UP) ? TIOCM_CAR : 0; - - return 0; - } - -/* Callout from P2P: */ -/* Set the state of DTR (Data Terminal Ready). */ -static int -p2p_mdmctl(struct p2pcom *p2p, int flag) - { - softc_t *sc = IFP2SC(&p2p->p2p_if); - - set_status(sc, flag); - - return 0; - } - -#endif /* P2P */ - -#if NSPPP - -# ifndef PP_FR -# define PP_FR 0 -# endif - -/* Callout from SPPP: */ -static void -sppp_tls(struct sppp *sppp) - { -# ifdef __FreeBSD__ - if (!(sppp->pp_mode & IFF_LINK2) && - !(sppp->pp_flags & PP_FR)) -# elif defined(__NetBSD__) || defined(__OpenBSD__) - if (!(sppp->pp_flags & PP_CISCO)) -# endif - sppp->pp_up(sppp); - } - -/* Callout from SPPP: */ -static void -sppp_tlf(struct sppp *sppp) - { -# ifdef __FreeBSD__ - if (!(sppp->pp_mode & IFF_LINK2) && - !(sppp->pp_flags & PP_FR)) -# elif defined(__NetBSD__) || defined(__OpenBSD__) - if (!(sppp->pp_flags & PP_CISCO)) -# endif - sppp->pp_down(sppp); - } - -#endif /* NSPPP */ - -/* Configure line protocol stuff. - * Called by attach_card() during module init. - * Called by core_ioctl() when lmcconfig writes sc->config. - * Called by detach_card() during module shutdown. - */ -static void -config_proto(softc_t *sc, struct config *config) - { - /* Use line protocol stack instead of RAWIP mode. */ - if ((sc->config.line_pkg == PKG_RAWIP) && - (config->line_pkg != PKG_RAWIP)) + switch (cmd) { -#if NSPPP - LMC_BPF_DETACH; - sppp_attach(sc->ifp); - LMC_BPF_ATTACH(DLT_PPP, 4); - sc->sppp->pp_tls = sppp_tls; - sc->sppp->pp_tlf = sppp_tlf; - /* Force reconfiguration of SPPP params. */ - sc->config.line_prot = 0; - sc->config.keep_alive = config->keep_alive ? 0:1; -#elif P2P - int error = 0; - sc->p2p->p2p_proto = 0; /* force p2p_attach */ - if ((error = p2p_attach(sc->p2p))) /* calls bpfattach() */ + case LMCIOCGSTAT: { - printf("%s: p2p_attach() failed; error %d\n", NAME_UNIT, error); - config->line_pkg = PKG_RAWIP; /* still in RAWIP mode */ + *status = sc->status; + iohdr->cookie = NGM_LMC_COOKIE; + break; } - else - { - sc->p2p->p2p_mdmctl = p2p_mdmctl; /* set DTR */ - sc->p2p->p2p_getmdm = p2p_getmdm; /* get DCD */ - } -#elif GEN_HDLC - int error = 0; - sc->net_dev->mtu = HDLC_MAX_MTU; - if ((error = hdlc_open(sc->net_dev))) - { - printf("%s: hdlc_open() failed; error %d\n", NAME_UNIT, error); - printf("%s: Try 'sethdlc %s ppp'\n", NAME_UNIT, NAME_UNIT); - config->line_pkg = PKG_RAWIP; /* still in RAWIP mode */ - } -#else /* no line protocol stack was configured */ - config->line_pkg = PKG_RAWIP; /* still in RAWIP mode */ -#endif - } - - /* Bypass line protocol stack and return to RAWIP mode. */ - if ((sc->config.line_pkg != PKG_RAWIP) && - (config->line_pkg == PKG_RAWIP)) - { -#if NSPPP - LMC_BPF_DETACH; - sppp_flush(sc->ifp); - sppp_detach(sc->ifp); - setup_ifnet(sc->ifp); - LMC_BPF_ATTACH(DLT_RAW, 0); -#elif P2P - int error = 0; - if_qflush(&sc->p2p->p2p_isnd); - if ((error = p2p_detach(sc->p2p))) - { - printf("%s: p2p_detach() failed; error %d\n", NAME_UNIT, error); - printf("%s: Try 'ifconfig %s down -remove'\n", NAME_UNIT, NAME_UNIT); - config->line_pkg = PKG_P2P; /* not in RAWIP mode; still attached to P2P */ - } - else - { - setup_ifnet(sc->ifp); - LMC_BPF_ATTACH(DLT_RAW, 0); - } -#elif GEN_HDLC - hdlc_proto_detach(sc->hdlc_dev); - hdlc_close(sc->net_dev); - setup_netdev(sc->net_dev); -#endif - } - -#if NSPPP - - if (config->line_pkg != PKG_RAWIP) - { - /* Check for change to PPP protocol. */ - if ((sc->config.line_prot != PROT_PPP) && - (config->line_prot == PROT_PPP)) - { - LMC_BPF_DETACH; -# if (defined(__NetBSD__) || defined(__OpenBSD__)) - sc->sppp->pp_flags &= ~PP_CISCO; -# elif defined(__FreeBSD__) - sc->ifp->if_flags &= ~IFF_LINK2; - sc->sppp->pp_flags &= ~PP_FR; -# endif - LMC_BPF_ATTACH(DLT_PPP, 4); - sppp_ioctl(sc->ifp, SIOCSIFFLAGS, NULL); - } - -# ifndef DLT_C_HDLC -# define DLT_C_HDLC DLT_PPP -# endif - - /* Check for change to C_HDLC protocol. */ - if ((sc->config.line_prot != PROT_C_HDLC) && - (config->line_prot == PROT_C_HDLC)) - { - LMC_BPF_DETACH; -# if (defined(__NetBSD__) || defined(__OpenBSD__)) - sc->sppp->pp_flags |= PP_CISCO; -# elif defined(__FreeBSD__) - sc->ifp->if_flags |= IFF_LINK2; - sc->sppp->pp_flags &= ~PP_FR; -# endif - LMC_BPF_ATTACH(DLT_C_HDLC, 4); - sppp_ioctl(sc->ifp, SIOCSIFFLAGS, NULL); - } - - /* Check for change to Frame Relay protocol. */ - if ((sc->config.line_prot != PROT_FRM_RLY) && - (config->line_prot == PROT_FRM_RLY)) - { - LMC_BPF_DETACH; -# if (defined(__NetBSD__) || defined(__OpenBSD__)) - sc->sppp->pp_flags &= ~PP_CISCO; -# elif defined(__FreeBSD__) - sc->ifp->if_flags &= ~IFF_LINK2; - sc->sppp->pp_flags |= PP_FR; -# endif - LMC_BPF_ATTACH(DLT_FRELAY, 4); - sppp_ioctl(sc->ifp, SIOCSIFFLAGS, NULL); - } - - /* Check for disabling keep-alives. */ - if ((sc->config.keep_alive != 0) && - (config->keep_alive == 0)) - sc->sppp->pp_flags &= ~PP_KEEPALIVE; - - /* Check for enabling keep-alives. */ - if ((sc->config.keep_alive == 0) && - (config->keep_alive != 0)) - sc->sppp->pp_flags |= PP_KEEPALIVE; - } - -#endif /* NSPPP */ - - /* Loop back through the TULIP Ethernet chip; (no CRC). */ - /* Data sheet says stop DMA before changing OPMODE register. */ - /* But that's not as simple as it sounds; works anyway. */ - /* Check for enabling loopback thru Tulip chip. */ - if ((sc->config.loop_back != CFG_LOOP_TULIP) && - (config->loop_back == CFG_LOOP_TULIP)) - { - u_int32_t op_mode = READ_CSR(TLP_OP_MODE); - op_mode |= TLP_OP_INT_LOOP; - WRITE_CSR(TLP_OP_MODE, op_mode); - config->crc_len = CFG_CRC_0; - } - - /* Check for disabling loopback thru Tulip chip. */ - if ((sc->config.loop_back == CFG_LOOP_TULIP) && - (config->loop_back != CFG_LOOP_TULIP)) - { - u_int32_t op_mode = READ_CSR(TLP_OP_MODE); - op_mode &= ~TLP_OP_LOOP_MODE; - WRITE_CSR(TLP_OP_MODE, op_mode); - config->crc_len = CFG_CRC_16; - } - } - -/* This is the core ioctl procedure. */ -/* It handles IOCTLs from lmcconfig(8). */ -/* It must not run when card watchdogs run. */ -/* Called from a syscall (user context; no spinlocks). */ -/* This procedure can SLEEP. */ -static int -core_ioctl(softc_t *sc, u_long cmd, caddr_t data) - { - struct iohdr *iohdr = (struct iohdr *) data; - struct ioctl *ioctl = (struct ioctl *) data; - struct status *status = (struct status *) data; - struct config *config = (struct config *) data; - int error = 0; - - /* All structs start with a string and a cookie. */ - if (((struct iohdr *)data)->cookie != NGM_LMC_COOKIE) - return EINVAL; - - while (TOP_TRYLOCK == 0) - { - sc->status.cntrs.lck_ioctl++; - SLEEP(10000); /* yield? */ - } - switch (cmd) - { - case LMCIOCGSTAT: - { - *status = sc->status; - iohdr->cookie = NGM_LMC_COOKIE; - break; - } - case LMCIOCGCFG: + case LMCIOCGCFG: { *config = sc->config; iohdr->cookie = NGM_LMC_COOKIE; @@ -4384,2664 +3473,1098 @@ core_ioctl(softc_t *sc, u_long cmd, caddr_t data) error = EINVAL; break; } - case LMCIOCTL: - { - if ((error = CHECK_CAP)) break; - if (ioctl->cmd == IOCTL_XILINX_RESET) - { - reset_xilinx(sc); - sc->card->config(sc); - } - else if (ioctl->cmd == IOCTL_XILINX_ROM) - { - load_xilinx_from_rom(sc); /* can sleep */ - sc->card->config(sc); - } - else if (ioctl->cmd == IOCTL_XILINX_FILE) - { - /* load_xilinx_from_file() can sleep. */ - error = load_xilinx_from_file(sc, ioctl->ucode, ioctl->data); - if (error != 0) load_xilinx_from_rom(sc); /* try the rom */ - sc->card->config(sc); - set_status(sc, (error==0)); /* XXX */ - } - else if (ioctl->cmd == IOCTL_RESET_CNTRS) - { - memset(&sc->status.cntrs, 0, sizeof(struct event_cntrs)); - microtime(&sc->status.cntrs.reset_time); - } - else - error = sc->card->ioctl(sc, ioctl); /* can sleep */ - break; - } - default: - error = EINVAL; - break; - } - TOP_UNLOCK; - - return error; - } - -/* This is the core watchdog procedure. */ -/* It calculates link speed, and calls the card-specific watchdog code. */ -/* Calls interrupt() in case one got lost; also kick-starts the device. */ -/* ioctl syscalls and card watchdog routines must be interlocked. */ -/* This procedure must not sleep. */ -static void -core_watchdog(softc_t *sc) - { - /* Read and restart the Tulip timer. */ - u_int32_t tx_speed = READ_CSR(TLP_TIMER); - WRITE_CSR(TLP_TIMER, 0xFFFF); - - /* Measure MII clock using a timer in the Tulip chip. - * This timer counts transmitter bits divided by 4096. - * Since this is called once a second the math is easy. - * This is only correct when the link is NOT sending pkts. - * On a fully-loaded link, answer will be HALF actual rate. - * Clock rate during pkt is HALF clk rate between pkts. - * Measuring clock rate really measures link utilization! - */ - sc->status.tx_speed = (0xFFFF - (tx_speed & 0xFFFF)) << 12; - - /* The first status reset time is when the calendar clock is set. */ - if (sc->status.cntrs.reset_time.tv_sec < 1000) - microtime(&sc->status.cntrs.reset_time); - - /* Update hardware (operational) status. */ - /* Call the card-specific watchdog routines. */ - if (TOP_TRYLOCK != 0) - { - sc->status.oper_status = sc->card->watchdog(sc); - - /* Increment a counter which tells user-land */ - /* observers that SNMP state has been updated. */ - sc->status.ticks++; - - TOP_UNLOCK; - } - else - sc->status.cntrs.lck_watch++; - - /* In case an interrupt gets lost... */ - user_interrupt(sc, 1); - } - -#if IFNET - -/* Called from a syscall (user context; no spinlocks). */ -static int -lmc_raw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) - { - struct ifreq *ifr = (struct ifreq *) data; - int error = 0; - - switch (cmd) - { -# if (defined(__FreeBSD__) && defined(DEVICE_POLLING)) /* XXX necessary? */ - case SIOCSIFCAP: -# endif - case SIOCAIFADDR: - case SIOCSIFFLAGS: -#if 0 - case SIOCADDMULTI: - case SIOCDELMULTI: - break; -#endif - case SIOCSIFADDR: - ifp->if_flags |= IFF_UP; /* a Unix tradition */ - break; - case SIOCSIFMTU: - ifp->if_mtu = ifr->ifr_mtu; - break; - default: - error = EINVAL; - break; - } - return error; - } - -/* Called from a syscall (user context; no spinlocks). */ -static int -lmc_ifnet_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) - { - softc_t *sc = IFP2SC(ifp); -# ifdef __OpenBSD__ - struct ifreq *ifr = (struct ifreq *) data; -# endif - int error = 0; - - switch (cmd) - { - /* Catch the IOCTLs used by lmcconfig. */ - case LMCIOCGSTAT: - case LMCIOCGCFG: - case LMCIOCSCFG: - case LMCIOCREAD: - case LMCIOCWRITE: - case LMCIOCTL: - error = core_ioctl(sc, cmd, data); - break; -# ifdef __OpenBSD__ - /* Catch the IOCTLs used by ifconfig. */ - case SIOCSIFMEDIA: - if ((error = CHECK_CAP)) break; - case SIOCGIFMEDIA: - error = ifmedia_ioctl(ifp, ifr, &sc->ifm, cmd); - break; - case SIOCSIFTIMESLOT: - if ((error = CHECK_CAP)) break; - if (sc->status.card_type == TLP_CSID_T1E1) - { - struct config config = sc->config; - if ((error = copyin(ifr->ifr_data, &config.time_slots, - sizeof config.time_slots))) break; - config.iohdr.cookie = NGM_LMC_COOKIE; - error = core_ioctl(sc, LMCIOCSCFG, (caddr_t)&config); - } - else - error = EINVAL; - break; - case SIOCGIFTIMESLOT: - if (sc->status.card_type == TLP_CSID_T1E1) - error = copyout(&sc->config.time_slots, ifr->ifr_data, - sizeof sc->config.time_slots); - else - error = EINVAL; - break; -# endif - /* Pass the rest to the line protocol. */ - default: - if (sc->config.line_pkg == PKG_RAWIP) - error = lmc_raw_ioctl(ifp, cmd, data); - else -# if NSPPP - error = sppp_ioctl(ifp, cmd, data); -# elif P2P - error = p2p_ioctl(ifp, cmd, data); -# else - error = EINVAL; -# endif - break; - } - - if (DRIVER_DEBUG && (error!=0)) - printf("%s: lmc_ifnet_ioctl; cmd=0x%08lx error=%d\n", - NAME_UNIT, cmd, error); - - return error; - } - -/* Called from a syscall (user context; no spinlocks). */ -static void -lmc_ifnet_start(struct ifnet *ifp) - { - softc_t *sc = IFP2SC(ifp); - - /* Start the transmitter; incoming pkts are NOT processed. */ - user_interrupt(sc, 0); - } - -/* sppp and p2p replace this with their own proc. */ -/* RAWIP mode is the only time this is used. */ -/* Called from a syscall (user context; no spinlocks). */ -static int -lmc_raw_output(struct ifnet *ifp, struct mbuf *m, - const struct sockaddr *dst, struct route *ro) - { - softc_t *sc = IFP2SC(ifp); - int error = 0; - - /* Fail if the link is down. */ - if (sc->status.oper_status != STATUS_UP) - { - m_freem(m); - sc->status.cntrs.odiscards++; - if (DRIVER_DEBUG) - printf("%s: lmc_raw_output: tx pkt discarded: link down\n", NAME_UNIT); - return ENETDOWN; - } - -# if NETGRAPH - /* Netgraph has priority over the ifnet kernel interface. */ - if (sc->ng_hook != NULL) - { - m_freem(m); - sc->status.cntrs.odiscards++; - if (DRIVER_DEBUG) - printf("%s: lmc_raw_output: tx pkt discarded: netgraph active\n", - NAME_UNIT); - return EBUSY; - } -# endif - - /* lmc_raw_output() ENQUEUEs in a syscall or softirq. */ - /* txintr_setup() DEQUEUEs in a hard interrupt. */ - /* Some BSD QUEUE routines are not interrupt-safe. */ - { - DISABLE_INTR; -# if (__FreeBSD_version >= 503000) - IFQ_ENQUEUE(&ifp->if_snd, m, error); -# else - IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error); -# endif - ENABLE_INTR; - } - - if (error==0) - user_interrupt(sc, 0); /* start the transmitter */ - else - { - m_freem(m); - sc->status.cntrs.odiscards++; - ifp->if_oqdrops++; - if (DRIVER_DEBUG) - printf("%s: lmc_raw_output: IFQ_ENQUEUE() failed; error %d\n", - NAME_UNIT, error); - } - - return error; - } - -/* Called from a softirq once a second. */ -static void -lmc_watchdog(void *arg) - { - struct ifnet *ifp = arg; - softc_t *sc = IFP2SC(ifp); - u_int8_t old_oper_status = sc->status.oper_status; - struct event_cntrs *cntrs = &sc->status.cntrs; - - core_watchdog(sc); /* updates oper_status */ - -#if NETGRAPH - if (sc->ng_hook != NULL) - { - sc->status.line_pkg = PKG_NG; - sc->status.line_prot = 0; - } - else -#endif - if (sc->config.line_pkg == PKG_RAWIP) - { - sc->status.line_pkg = PKG_RAWIP; - sc->status.line_prot = PROT_IP_HDLC; - } - else - { -# if P2P - /* Notice change in link status. */ - if ((old_oper_status != sc->status.oper_status) && (sc->p2p->p2p_modem)) - (*sc->p2p->p2p_modem)(sc->p2p, sc->status.oper_status==STATUS_UP); - - /* Notice change in line protocol. */ - sc->status.line_pkg = PKG_P2P; - switch (sc->ifp->if_type) - { - case IFT_PPP: - sc->status.line_prot = PROT_PPP; - break; - case IFT_PTPSERIAL: - sc->status.line_prot = PROT_C_HDLC; - break; - case IFT_FRELAY: - sc->status.line_prot = PROT_FRM_RLY; - break; - default: - sc->status.line_prot = 0; - break; - } - -# elif NSPPP - /* Notice change in link status. */ - if ((old_oper_status != STATUS_UP) && - (sc->status.oper_status == STATUS_UP)) /* link came up */ - sppp_tls(sc->sppp); - if ((old_oper_status == STATUS_UP) && - (sc->status.oper_status != STATUS_UP)) /* link went down */ - sppp_tlf(sc->sppp); - - /* Notice change in line protocol. */ - sc->status.line_pkg = PKG_SPPP; -# ifdef __FreeBSD__ - if (sc->sppp->pp_flags & PP_FR) - sc->status.line_prot = PROT_FRM_RLY; - else if (sc->ifp->if_flags & IFF_LINK2) -# elif (defined(__NetBSD__) || defined(__OpenBSD__)) - if (sc->sppp->pp_flags & PP_CISCO) -# endif - sc->status.line_prot = PROT_C_HDLC; - else - sc->status.line_prot = PROT_PPP; - -# else - /* Suppress compiler warning. */ - if (old_oper_status == STATUS_UP); -# endif - } - - /* Copy statistics from sc to ifp. */ - ifp->if_baudrate = sc->status.tx_speed; - ifp->if_ipackets = cntrs->ipackets; - ifp->if_opackets = cntrs->opackets; - ifp->if_ibytes = cntrs->ibytes; - ifp->if_obytes = cntrs->obytes; - ifp->if_ierrors = cntrs->ierrors; - ifp->if_oerrors = cntrs->oerrors; - ifp->if_iqdrops = cntrs->idiscards; - -# if ((__FreeBSD_version >= 500000) || defined(__OpenBSD__) || defined(__NetBSD__)) - if (sc->status.oper_status == STATUS_UP) - ifp->if_link_state = LINK_STATE_UP; - else - ifp->if_link_state = LINK_STATE_DOWN; -# endif - - /* Call this procedure again after one second. */ - callout_reset(&sc->callout, hz, lmc_watchdog, ifp); - } - -# ifdef __OpenBSD__ - -/* Callback from ifmedia. */ -static int -ifmedia_change(struct ifnet *ifp) - { - softc_t *sc = IFP2SC(ifp); - struct config config = sc->config; - int media = sc->ifm.ifm_media; - int error; - - /* ifconfig lmc0 media t1 */ - if (sc->status.card_type == TLP_CSID_T3) - { - if ((media & IFM_TMASK) == IFM_TDM_T3) - config.format = CFG_FORMAT_T3CPAR; - else if ((media & IFM_TMASK) == IFM_TDM_T3_M13) - config.format = CFG_FORMAT_T3M13; - } - else if (sc->status.card_type == TLP_CSID_T1E1) - { - if ((media & IFM_TMASK) == IFM_TDM_T1) - config.format = CFG_FORMAT_T1ESF; - else if ((media & IFM_TMASK) == IFM_TDM_T1_AMI) - config.format = CFG_FORMAT_T1SF; - else if ((media & IFM_TMASK) == IFM_TDM_E1) - config.format = CFG_FORMAT_E1NONE; - else if ((media & IFM_TMASK) == IFM_TDM_E1_G704) - config.format = CFG_FORMAT_E1FASCRC; - } - - /* ifconfig lmc0 mediaopt loopback */ - if (media & IFM_LOOP) - config.loop_back = CFG_LOOP_TULIP; - else - config.loop_back = CFG_LOOP_NONE; - - /* ifconfig lmc0 mediaopt crc16 */ - if (media & IFM_TDM_HDLC_CRC16) - config.crc_len = CFG_CRC_16; - else - config.crc_len = CFG_CRC_32; - - /* Set ConFiGuration. */ - config.iohdr.cookie = NGM_LMC_COOKIE; - error = core_ioctl(sc, LMCIOCSCFG, (caddr_t)&config); - - return error; - } - -/* Callback from ifmedia. */ -static void -ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr) - { - softc_t *sc = IFP2SC(ifp); - - /* ifconfig wants to know if the hardware link is up. */ - ifmr->ifm_status = IFM_AVALID; - if (sc->status.oper_status == STATUS_UP) - ifmr->ifm_status |= IFM_ACTIVE; - - ifmr->ifm_active = sc->ifm.ifm_cur->ifm_media; - - if (sc->config.loop_back != CFG_LOOP_NONE) - ifmr->ifm_active |= IFM_LOOP; - - if (sc->config.crc_len == CFG_CRC_16) - ifmr->ifm_active |= IFM_TDM_HDLC_CRC16; - } - -# endif /* __OpenBSD__ */ - -static void -setup_ifnet(struct ifnet *ifp) - { - softc_t *sc = ifp->if_softc; - - /* Initialize the generic network interface. */ - /* Note similarity to linux's setup_netdev(). */ - ifp->if_flags = IFF_POINTOPOINT; - ifp->if_flags |= IFF_RUNNING; - ifp->if_ioctl = lmc_ifnet_ioctl; - ifp->if_start = lmc_ifnet_start; /* sppp changes this */ - ifp->if_output = lmc_raw_output; /* sppp & p2p change this */ - ifp->if_input = lmc_raw_input; - ifp->if_mtu = MAX_DESC_LEN; /* sppp & p2p change this */ - ifp->if_type = IFT_PTPSERIAL; /* p2p changes this */ - -# if (defined(__FreeBSD__) && defined(DEVICE_POLLING)) - ifp->if_capabilities |= IFCAP_POLLING; - ifp->if_capenable |= IFCAP_POLLING_NOCOUNT; -# if (__FreeBSD_version < 500000) - ifp->if_capenable |= IFCAP_POLLING; -# endif -# endif - - /* Every OS does it differently! */ -# if (defined(__FreeBSD__) && (__FreeBSD_version < 502000)) - (const char *)ifp->if_name = device_get_name(sc->dev); - ifp->if_unit = device_get_unit(sc->dev); -# elif (__FreeBSD_version >= 502000) - if_initname(ifp, device_get_name(sc->dev), device_get_unit(sc->dev)); -# elif defined(__NetBSD__) - strcpy(ifp->if_xname, sc->dev.dv_xname); -# elif defined(__OpenBSD__) - bcopy(sc->dev.dv_xname, ifp->if_xname, IFNAMSIZ); -# elif defined(__bsdi__) - ifp->if_name = sc->dev.dv_cfdata->cf_driver->cd_name; - ifp->if_unit = sc->dev.dv_unit; -# endif - } - -static int -lmc_ifnet_attach(softc_t *sc) - { -# if (__FreeBSD_version >= 600000) - sc->ifp = if_alloc(NSPPP ? IFT_PPP : IFT_OTHER); - if (sc->ifp == NULL) return ENOMEM; -# endif -# if NSPPP -# if (__FreeBSD_version >= 600000) - sc->sppp = sc->ifp->if_l2com; -# else - sc->ifp = &sc->spppcom.pp_if; - sc->sppp = &sc->spppcom; -# endif -# elif P2P - sc->ifp = &sc->p2pcom.p2p_if; - sc->p2p = &sc->p2pcom; -# elif (__FreeBSD_version < 600000) - sc->ifp = &sc->ifnet; -# endif - - /* Initialize the network interface struct. */ - sc->ifp->if_softc = sc; - setup_ifnet(sc->ifp); - - /* ALTQ output queue initialization. */ - IFQ_SET_MAXLEN(&sc->ifp->if_snd, SNDQ_MAXLEN); - IFQ_SET_READY(&sc->ifp->if_snd); - - /* Attach to the ifnet kernel interface. */ - if_attach(sc->ifp); - -# if ((defined(__NetBSD__) && __NetBSD_Version__ >= 106000000) || \ - (defined(__OpenBSD__) && OpenBSD >= 200211)) - if_alloc_sadl(sc->ifp); -# endif - - /* Attach Berkeley Packet Filter. */ - LMC_BPF_ATTACH(DLT_RAW, 0); - -# ifdef __OpenBSD__ - /* Initialize ifmedia mechanism. */ - ifmedia_init(&sc->ifm, IFM_OMASK | IFM_GMASK | IFM_IMASK, - ifmedia_change, ifmedia_status); - if (sc->status.card_type == TLP_CSID_T3) - { - ifmedia_add(&sc->ifm, IFM_TDM | IFM_TDM_T3, 0, NULL); - ifmedia_add(&sc->ifm, IFM_TDM | IFM_TDM_T3_M13, 0, NULL); - ifmedia_set(&sc->ifm, IFM_TDM | IFM_TDM_T3); - } - else if (sc->status.card_type == TLP_CSID_T1E1) - { - ifmedia_add(&sc->ifm, IFM_TDM | IFM_TDM_T1, 0, NULL); - ifmedia_add(&sc->ifm, IFM_TDM | IFM_TDM_T1_AMI, 0, NULL); - ifmedia_add(&sc->ifm, IFM_TDM | IFM_TDM_E1, 0, NULL); - ifmedia_add(&sc->ifm, IFM_TDM | IFM_TDM_E1_G704, 0, NULL); - ifmedia_set(&sc->ifm, IFM_TDM | IFM_TDM_T1); - } - else if ((sc->status.card_type == TLP_CSID_HSSI) || - (sc->status.card_type == TLP_CSID_SSI)) - { - ifmedia_add(&sc->ifm, IFM_TDM | IFM_NONE, 0, NULL); - ifmedia_set(&sc->ifm, IFM_TDM | IFM_NONE); - } -# endif /* __OpenBSD__ */ - - callout_reset(&sc->callout, hz, lmc_watchdog, sc); - - return 0; - } - -static void -lmc_ifnet_detach(softc_t *sc) - { -# ifdef __OpenBSD__ - ifmedia_delete_instance(&sc->ifm, IFM_INST_ANY); -# endif - -# if (defined(__FreeBSD__) && defined(DEVICE_POLLING)) - if (sc->ifp->if_capenable & IFCAP_POLLING) - ether_poll_deregister(sc->ifp); -# endif - - /* Detach Berkeley Packet Filter. */ - LMC_BPF_DETACH; - -# if ((defined(__NetBSD__) && __NetBSD_Version__ >= 106000000) || \ - (defined(__OpenBSD__) && OpenBSD >= 200211)) - if_free_sadl(sc->ifp); -# endif - - /* Detach from the ifnet kernel interface. */ - if_detach(sc->ifp); - -# if (defined(__FreeBSD__) && __FreeBSD_version >= 800082) - if_free(sc->ifp); -# elif (defined(__FreeBSD__) && __FreeBSD_version >= 600000) - if_free_type(sc->ifp, NSPPP ? IFT_PPP : IFT_OTHER); -# endif - } - -#endif /* IFNET */ - -#if NETGRAPH - -/* Netgraph changed significantly between FreeBSD-4 and -5. */ -/* These are backward compatibility hacks for FreeBSD-4. */ -# if (__FreeBSD_version >= 500000) -/* These next two macros should be added to netgraph */ -# define NG_TYPE_REF(type) atomic_add_int(&(type)->refs, 1) -# define NG_TYPE_UNREF(type) \ -do { \ - if ((type)->refs == 1) \ - ng_rmtype(type); \ - else \ - atomic_subtract_int(&(type)->refs, 1); \ - } while (0) -# else /* FreeBSD-4 */ -# define NGI_GET_MSG(item, msg) /* nothing */ -# define NG_HOOK_FORCE_QUEUE(hook) /* nothing */ -# define NG_TYPE_REF(type) atomic_add_int(&(type)->refs, 1) -# define NG_TYPE_UNREF(type) \ -do { \ - if ((type)->refs == 1) \ - LIST_REMOVE(type, types); \ - else \ - atomic_subtract_int(&(type)->refs, 1); \ - } while (0) -# endif - -/* It is an error to construct new copies of this Netgraph node. */ -/* All instances are constructed by ng_attach and are persistent. */ -# if (__FreeBSD_version >= 500000) -static int ng_constructor(node_p node) { return EINVAL; } -# else /* FreeBSD-4 */ -static int ng_constructor(node_p *node) { return EINVAL; } -# endif - -/* Incoming Netgraph control message. */ -# if (__FreeBSD_version >= 500000) -static int -ng_rcvmsg(node_p node, item_p item, hook_p lasthook) - { - struct ng_mesg *msg; -# else /* FreeBSD-4 */ -static int -ng_rcvmsg(node_p node, struct ng_mesg *msg, - const char *retaddr, struct ng_mesg **rptr) - { -# endif - struct ng_mesg *resp = NULL; - softc_t *sc = NG_NODE_PRIVATE(node); - int error = 0; - - NGI_GET_MSG(item, msg); - if (msg->header.typecookie == NGM_LMC_COOKIE) - { - switch (msg->header.cmd) - { - case LMCIOCGSTAT: - case LMCIOCGCFG: - case LMCIOCSCFG: - case LMCIOCREAD: - case LMCIOCWRITE: - case LMCIOCTL: - { - /* Call the core ioctl procedure. */ - error = core_ioctl(sc, msg->header.cmd, msg->data); - if ((msg->header.cmd & IOC_OUT) != 0) - { /* synchronous response */ - NG_MKRESPONSE(resp, msg, sizeof(struct ng_mesg) + - IOCPARM_LEN(msg->header.cmd), M_NOWAIT); - if (resp == NULL) - error = ENOMEM; - else - memcpy(resp->data, msg->data, IOCPARM_LEN(msg->header.cmd)); - } - break; - } - default: - error = EINVAL; - break; - } - } - else if ((msg->header.typecookie == NGM_GENERIC_COOKIE) && - (msg->header.cmd == NGM_TEXT_STATUS)) - { /* synchronous response */ - NG_MKRESPONSE(resp, msg, sizeof(struct ng_mesg) + - NG_TEXTRESPONSE, M_NOWAIT); - if (resp == NULL) - error = ENOMEM; - else - { - char *s = resp->data; - sprintf(s, "Card type = <%s>\n" - "This driver considers the link to be %s.\n" - "Use lmcconfig to configure this interface.\n", - sc->dev_desc, (sc->status.oper_status==STATUS_UP) ? "UP" : "DOWN"); - resp->header.arglen = strlen(s) +1; - } - } - else -/* Netgraph should be able to read and write these - * parameters with text-format control messages: - * SSI HSSI T1E1 T3 - * crc crc crc crc - * loop loop loop loop - * clksrc clksrc - * dte dte format format - * synth synth cablen cablen - * cable timeslot scram - * gain - * pulse - * lbo - * Someday I'll implement this... - */ - error = EINVAL; - - /* Handle synchronous response. */ -# if (__FreeBSD_version >= 500000) - NG_RESPOND_MSG(error, node, item, resp); - NG_FREE_MSG(msg); -# else /* FreeBSD-4 */ - if (rptr != NULL) - *rptr = resp; - else if (resp != NULL) - free(resp, M_NETGRAPH); - free(msg, M_NETGRAPH); -# endif - - return error; - } - -/* This is a persistent netgraph node. */ -static int -ng_shutdown(node_p node) - { -# if (__FreeBSD_version >= 500000) - /* unless told to really die, bounce back to life */ - if ((node->nd_flags & NG_REALLY_DIE)==0) - node->nd_flags &= ~NG_INVALID; /* bounce back to life */ -# else /* FreeBSD-4 */ - ng_cutlinks(node); - node->flags &= ~NG_INVALID; /* bounce back to life */ -# endif - - return 0; - } - -/* ng_disconnect is the opposite of this procedure. */ -static int -ng_newhook(node_p node, hook_p hook, const char *name) - { - softc_t *sc = NG_NODE_PRIVATE(node); - - /* Hook name must be 'rawdata'. */ - if (strncmp(name, "rawdata", 7) != 0) return EINVAL; - - /* Is our hook connected? */ - if (sc->ng_hook != NULL) return EBUSY; - - /* Accept the hook. */ - sc->ng_hook = hook; - - return 0; - } - -/* Both ends have accepted their hooks and the links have been made. */ -/* This is the last chance to reject the connection request. */ -static int -ng_connect(hook_p hook) - { - /* Probably not at splnet, force outward queueing. (huh?) */ - NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); - return 0; /* always accept */ - } - -/* Receive data in mbufs from another Netgraph node. */ -/* Transmit an mbuf-chain on the communication link. */ -/* This procedure is very similar to lmc_raw_output(). */ -/* Called from a syscall (user context; no spinlocks). */ -# if (__FreeBSD_version >= 500000) -static int -ng_rcvdata(hook_p hook, item_p item) - { - softc_t *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); - int error = 0; - struct mbuf *m; - meta_p meta = NULL; - - NGI_GET_M(item, m); - NGI_GET_META(item, meta); - NG_FREE_ITEM(item); -# else /* FreeBSD-4 */ -static int -ng_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) - { - softc_t *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); - int error = 0; -# endif - - /* This macro must not store into meta! */ - NG_FREE_META(meta); - - /* Fail if the link is down. */ - if (sc->status.oper_status != STATUS_UP) - { - m_freem(m); - sc->status.cntrs.odiscards++; - if (DRIVER_DEBUG) - printf("%s: ng_rcvdata: tx pkt discarded: link down\n", NAME_UNIT); - return ENETDOWN; - } - - /* ng_rcvdata() ENQUEUEs in a syscall or softirq. */ - /* txintr_setup() DEQUEUEs in a hard interrupt. */ - /* Some BSD QUEUE routines are not interrupt-safe. */ - { - DISABLE_INTR; -# if (__FreeBSD_version >= 503000) - if (meta==NULL) - IFQ_ENQUEUE(&sc->ng_sndq, m, error); - else - IFQ_ENQUEUE(&sc->ng_fastq, m, error); -# else - if (meta==NULL) - IFQ_ENQUEUE(&sc->ng_sndq, m, NULL, error); - else - IFQ_ENQUEUE(&sc->ng_fastq, m, NULL, error); -# endif - ENABLE_INTR; - } - - if (error==0) - user_interrupt(sc, 0); /* start the transmitter */ - else - { - m_freem(m); - sc->status.cntrs.odiscards++; - if (DRIVER_DEBUG) - printf("%s: ng_rcvdata: IFQ_ENQUEUE() failed; error %d\n", - NAME_UNIT, error); - } - - return error; - } - -/* ng_newhook is the opposite of this procedure, not */ -/* ng_connect, as you might expect from the names. */ -static int -ng_disconnect(hook_p hook) - { - softc_t *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); - - /* Disconnect the hook. */ - sc->ng_hook = NULL; - - return 0; - } - -static -struct ng_type ng_type = - { - .version = NG_ABI_VERSION, - .name = NG_LMC_NODE_TYPE, - .mod_event = NULL, - .constructor = ng_constructor, - .rcvmsg = ng_rcvmsg, -# if (__FreeBSD_version >=503000) - .close = NULL, -# endif - .shutdown = ng_shutdown, - .newhook = ng_newhook, - .findhook = NULL, - .connect = ng_connect, - .rcvdata = ng_rcvdata, -# if (defined(__FreeBSD__) && (__FreeBSD_version < 500000)) - .rcvdataq = ng_rcvdata, -# endif - .disconnect = ng_disconnect, - }; - -# if (IFNET == 0) -/* Called from a softirq once a second. */ -static void -ng_watchdog(void *arg) - { - softc_t *sc = arg; - - /* Call the core watchdog procedure. */ - core_watchdog(sc); - - /* Set line protocol and package status. */ - sc->status.line_pkg = PKG_NG; - sc->status.line_prot = 0; - - /* Call this procedure again after one second. */ - callout_reset(&sc->callout, hz, ng_watchdog, sc); - } -# endif - -/* Attach to the Netgraph kernel interface (/sys/netgraph). - * It is called once for each physical card during device attach. - * This is effectively ng_constructor. - */ -static int -ng_attach(softc_t *sc) - { - int error; - - /* If this node type is not known to Netgraph then register it. */ - if (ng_type.refs == 0) /* or: if (ng_findtype(&ng_type) == NULL) */ - { - if ((error = ng_newtype(&ng_type))) - { - printf("%s: ng_newtype() failed; error %d\n", NAME_UNIT, error); - return error; - } - } - else - NG_TYPE_REF(&ng_type); - - /* Call the superclass node constructor. */ - if ((error = ng_make_node_common(&ng_type, &sc->ng_node))) - { - NG_TYPE_UNREF(&ng_type); - printf("%s: ng_make_node_common() failed; error %d\n", NAME_UNIT, error); - return error; - } - - /* Associate a name with this netgraph node. */ - if ((error = ng_name_node(sc->ng_node, NAME_UNIT))) - { - NG_NODE_UNREF(sc->ng_node); - NG_TYPE_UNREF(&ng_type); - printf("%s: ng_name_node() failed; error %d\n", NAME_UNIT, error); - return error; - } - -# if (__FreeBSD_version >= 500000) - /* Initialize the send queue mutexes. */ - mtx_init(&sc->ng_sndq.ifq_mtx, NAME_UNIT, "sndq", MTX_DEF); - mtx_init(&sc->ng_fastq.ifq_mtx, NAME_UNIT, "fastq", MTX_DEF); -# endif - - /* Put a backpointer to the softc in the netgraph node. */ - NG_NODE_SET_PRIVATE(sc->ng_node, sc); - - /* ALTQ output queue initialization. */ - IFQ_SET_MAXLEN(&sc->ng_fastq, SNDQ_MAXLEN); - IFQ_SET_READY(&sc->ng_fastq); - IFQ_SET_MAXLEN(&sc->ng_sndq, SNDQ_MAXLEN); - IFQ_SET_READY(&sc->ng_sndq); - -# if (IFNET == 0) - /* Arrange to call ng_watchdog() once a second. */ - callout_reset(&sc->callout, hz, ng_watchdog, sc); -# endif - - return 0; - } - -static void -ng_detach(softc_t *sc) - { - callout_drain(&sc->callout); -# if (__FreeBSD_version >= 500000) - mtx_destroy(&sc->ng_sndq.ifq_mtx); - mtx_destroy(&sc->ng_fastq.ifq_mtx); - ng_rmnode_self(sc->ng_node); /* free hook */ - NG_NODE_UNREF(sc->ng_node); /* free node */ - NG_TYPE_UNREF(&ng_type); -# else /* FreeBSD-4 */ - ng_unname(sc->ng_node); /* free name */ - ng_cutlinks(sc->ng_node); /* free hook */ - NG_NODE_UNREF(sc->ng_node); /* free node */ - NG_TYPE_UNREF(&ng_type); -# endif - } - -#endif /* NETGRAPH */ - -/* The next few procedures initialize the card. */ - -/* Returns 0 on success; error code on failure. */ -static int -startup_card(softc_t *sc) - { - int num_rx_descs, error = 0; - u_int32_t tlp_bus_pbl, tlp_bus_cal, tlp_op_tr; - u_int32_t tlp_cfdd, tlp_cfcs; - u_int32_t tlp_cflt, tlp_csid, tlp_cfit; - - /* Make sure the COMMAND bits are reasonable. */ - tlp_cfcs = READ_PCI_CFG(sc, TLP_CFCS); - tlp_cfcs &= ~TLP_CFCS_MWI_ENABLE; - tlp_cfcs |= TLP_CFCS_BUS_MASTER; - tlp_cfcs |= TLP_CFCS_MEM_ENABLE; - tlp_cfcs |= TLP_CFCS_IO_ENABLE; - tlp_cfcs |= TLP_CFCS_PAR_ERROR; - tlp_cfcs |= TLP_CFCS_SYS_ERROR; - WRITE_PCI_CFG(sc, TLP_CFCS, tlp_cfcs); - - /* Set the LATENCY TIMER to the recommended value, */ - /* and make sure the CACHE LINE SIZE is reasonable. */ - tlp_cfit = READ_PCI_CFG(sc, TLP_CFIT); - tlp_cflt = READ_PCI_CFG(sc, TLP_CFLT); - tlp_cflt &= ~TLP_CFLT_LATENCY; - tlp_cflt |= (tlp_cfit & TLP_CFIT_MAX_LAT)>>16; - /* "prgmbl burst length" and "cache alignment" used below. */ - switch(tlp_cflt & TLP_CFLT_CACHE) - { - case 8: /* 8 bytes per cache line */ - { tlp_bus_pbl = 32; tlp_bus_cal = 1; break; } - case 16: - { tlp_bus_pbl = 32; tlp_bus_cal = 2; break; } - case 32: - { tlp_bus_pbl = 32; tlp_bus_cal = 3; break; } - default: + case LMCIOCTL: { - tlp_bus_pbl = 32; tlp_bus_cal = 1; - tlp_cflt &= ~TLP_CFLT_CACHE; - tlp_cflt |= 8; + if ((error = CHECK_CAP)) break; + if (ioctl->cmd == IOCTL_XILINX_RESET) + { + reset_xilinx(sc); + sc->card->config(sc); + } + else if (ioctl->cmd == IOCTL_XILINX_ROM) + { + load_xilinx_from_rom(sc); /* can sleep */ + sc->card->config(sc); + } + else if (ioctl->cmd == IOCTL_XILINX_FILE) + { + /* load_xilinx_from_file() can sleep. */ + error = load_xilinx_from_file(sc, ioctl->ucode, ioctl->data); + if (error != 0) load_xilinx_from_rom(sc); /* try the rom */ + sc->card->config(sc); + set_status(sc, (error==0)); /* XXX */ + } + else if (ioctl->cmd == IOCTL_RESET_CNTRS) + { + memset(&sc->status.cntrs, 0, sizeof(struct event_cntrs)); + microtime(&sc->status.cntrs.reset_time); + } + else + error = sc->card->ioctl(sc, ioctl); /* can sleep */ break; } - } - WRITE_PCI_CFG(sc, TLP_CFLT, tlp_cflt); - - /* Make sure SNOOZE and SLEEP modes are disabled. */ - tlp_cfdd = READ_PCI_CFG(sc, TLP_CFDD); - tlp_cfdd &= ~TLP_CFDD_SLEEP; - tlp_cfdd &= ~TLP_CFDD_SNOOZE; - WRITE_PCI_CFG(sc, TLP_CFDD, tlp_cfdd); - DELAY(11*1000); /* Tulip wakes up in 10 ms max */ - - /* Software Reset the Tulip chip; stops DMA and Interrupts. */ - /* This does not change the PCI config regs just set above. */ - WRITE_CSR(TLP_BUS_MODE, TLP_BUS_RESET); /* self-clearing */ - DELAY(5); /* Tulip is dead for 50 PCI cycles after reset. */ - - /* Reset the Xilinx Field Programmable Gate Array. */ - reset_xilinx(sc); /* side effect: turns on all four LEDs */ - - /* Configure card-specific stuff (framers, line interfaces, etc.). */ - sc->card->config(sc); - - /* Initializing cards can glitch clocks and upset fifos. */ - /* Reset the FIFOs between the Tulip and Xilinx chips. */ - set_mii16_bits(sc, MII16_FIFO); - clr_mii16_bits(sc, MII16_FIFO); - - /* Initialize the PCI busmode register. */ - /* The PCI bus cycle type "Memory Write and Invalidate" does NOT */ - /* work cleanly in any version of the 21140A, so don't enable it! */ - WRITE_CSR(TLP_BUS_MODE, - (tlp_bus_cal ? TLP_BUS_READ_LINE : 0) | - (tlp_bus_cal ? TLP_BUS_READ_MULT : 0) | - (tlp_bus_pbl<txring, NUM_TX_DESCS))) return error; - WRITE_CSR(TLP_TX_LIST, sc->txring.dma_addr); - if ((error = create_ring(sc, &sc->rxring, num_rx_descs))) return error; - WRITE_CSR(TLP_RX_LIST, sc->rxring.dma_addr); - - /* Initialize the operating mode register. */ - WRITE_CSR(TLP_OP_MODE, TLP_OP_INIT | (tlp_op_tr<txring); - destroy_ring(sc, &sc->rxring); - } - -/* Start the card and attach a kernel interface and line protocol. */ -static int -attach_card(softc_t *sc, const char *intrstr) +core_watchdog(softc_t *sc) { - struct config config; - u_int32_t tlp_cfrv; - u_int16_t mii3; - u_int8_t *ieee; - int i, error = 0; - - /* Start the card. */ - if ((error = startup_card(sc))) return error; - -# if (__FreeBSD_version >= 500000) - callout_init(&sc->callout, 0); -# else /* FreeBSD-4 */ - callout_init(&sc->callout); -# endif - - /* Attach a kernel interface. */ -#if NETGRAPH - if ((error = ng_attach(sc))) return error; - sc->flags |= FLAG_NETGRAPH; -#endif -#if IFNET - if ((error = lmc_ifnet_attach(sc))) return error; - sc->flags |= FLAG_IFNET; -#endif - - /* Attach a line protocol stack. */ - sc->config.line_pkg = PKG_RAWIP; - config = sc->config; /* get current config */ - config.line_pkg = 0; /* select external stack */ - config.line_prot = PROT_C_HDLC; - config.keep_alive = 1; - config_proto(sc, &config); /* reconfigure */ - sc->config = config; /* save new configuration */ - - /* Print interesting hardware-related things. */ - mii3 = read_mii(sc, 3); - tlp_cfrv = READ_PCI_CFG(sc, TLP_CFRV); - printf("%s: PCI rev %d.%d, MII rev %d.%d", NAME_UNIT, - (tlp_cfrv>>4) & 0xF, tlp_cfrv & 0xF, (mii3>>4) & 0xF, mii3 & 0xF); - ieee = (u_int8_t *)sc->status.ieee; - for (i=0; i<3; i++) sc->status.ieee[i] = read_srom(sc, 10+i); - printf(", IEEE addr %02x:%02x:%02x:%02x:%02x:%02x", - ieee[0], ieee[1], ieee[2], ieee[3], ieee[4], ieee[5]); - sc->card->ident(sc); - printf(" %s\n", intrstr); - - /* Print interesting software-related things. */ - printf("%s: Driver rev %d.%d.%d", NAME_UNIT, - DRIVER_MAJOR_VERSION, DRIVER_MINOR_VERSION, DRIVER_SUB_VERSION); - printf(", Options %s%s%s%s%s%s%s%s%s\n", - NETGRAPH ? "NETGRAPH " : "", GEN_HDLC ? "GEN_HDLC " : "", - NSPPP ? "SPPP " : "", P2P ? "P2P " : "", - ALTQ_PRESENT ? "ALTQ " : "", NBPFILTER ? "BPF " : "", - DEV_POLL ? "POLL " : "", IOREF_CSR ? "IO_CSR " : "MEM_CSR ", - (BYTE_ORDER == BIG_ENDIAN) ? "BIG_END " : "LITTLE_END "); - - /* Make the local hardware ready. */ - set_status(sc, 1); - - return 0; - } + /* Read and restart the Tulip timer. */ + u_int32_t tx_speed = READ_CSR(TLP_TIMER); + WRITE_CSR(TLP_TIMER, 0xFFFF); -/* Detach from the kernel in all ways. */ -static void -detach_card(softc_t *sc) - { - struct config config; + /* Measure MII clock using a timer in the Tulip chip. + * This timer counts transmitter bits divided by 4096. + * Since this is called once a second the math is easy. + * This is only correct when the link is NOT sending pkts. + * On a fully-loaded link, answer will be HALF actual rate. + * Clock rate during pkt is HALF clk rate between pkts. + * Measuring clock rate really measures link utilization! + */ + sc->status.tx_speed = (0xFFFF - (tx_speed & 0xFFFF)) << 12; - /* Make the local hardware NOT ready. */ - set_status(sc, 0); + /* The first status reset time is when the calendar clock is set. */ + if (sc->status.cntrs.reset_time.tv_sec < 1000) + microtime(&sc->status.cntrs.reset_time); - /* Detach external line protocol stack. */ - if (sc->config.line_pkg != PKG_RAWIP) + /* Update hardware (operational) status. */ + /* Call the card-specific watchdog routines. */ + if (TOP_TRYLOCK != 0) { - config = sc->config; - config.line_pkg = PKG_RAWIP; - config_proto(sc, &config); - sc->config = config; - } + sc->status.oper_status = sc->card->watchdog(sc); - /* Detach kernel interfaces. */ -#if NETGRAPH - if (sc->flags & FLAG_NETGRAPH) - { - IFQ_PURGE(&sc->ng_fastq); - IFQ_PURGE(&sc->ng_sndq); - ng_detach(sc); - sc->flags &= ~FLAG_NETGRAPH; - } -#endif -#if IFNET - if (sc->flags & FLAG_IFNET) - { - IFQ_PURGE(&sc->ifp->if_snd); - lmc_ifnet_detach(sc); - sc->flags &= ~FLAG_IFNET; + /* Increment a counter which tells user-land */ + /* observers that SNMP state has been updated. */ + sc->status.ticks++; + + TOP_UNLOCK; } -#endif + else + sc->status.cntrs.lck_watch++; - /* Reset the Tulip chip; stops DMA and Interrupts. */ - shutdown_card(sc); + /* In case an interrupt gets lost... */ + user_interrupt(sc, 1); } -/* This is the I/O configuration interface for FreeBSD */ - -#ifdef __FreeBSD__ +/* Called from a syscall (user context; no spinlocks). */ static int -fbsd_probe(device_t dev) +lmc_raw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - u_int32_t cfid = pci_read_config(dev, TLP_CFID, 4); - u_int32_t csid = pci_read_config(dev, TLP_CSID, 4); + struct ifreq *ifr = (struct ifreq *) data; + int error = 0; - /* Looking for a DEC 21140A chip on any Lan Media Corp card. */ - if (cfid != TLP_CFID_TULIP) return ENXIO; - switch (csid) + switch (cmd) { - case TLP_CSID_HSSI: - case TLP_CSID_HSSIc: - device_set_desc(dev, HSSI_DESC); - break; - case TLP_CSID_T3: - device_set_desc(dev, T3_DESC); - break; - case TLP_CSID_SSI: - device_set_desc(dev, SSI_DESC); + case SIOCAIFADDR: + case SIOCSIFFLAGS: + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; /* a Unix tradition */ break; - case TLP_CSID_T1E1: - device_set_desc(dev, T1E1_DESC); + case SIOCSIFMTU: + ifp->if_mtu = ifr->ifr_mtu; break; default: - return ENXIO; + error = EINVAL; + break; } - return 0; + return error; } +/* Called from a syscall (user context; no spinlocks). */ static int -fbsd_detach(device_t dev) +lmc_ifnet_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - softc_t *sc = device_get_softc(dev); - - /* Stop the card and detach from the kernel. */ - detach_card(sc); + softc_t *sc = IFP2SC(ifp); + int error = 0; - /* Release resources. */ - if (sc->irq_cookie != NULL) - { - bus_teardown_intr(dev, sc->irq_res, sc->irq_cookie); - sc->irq_cookie = NULL; - } - if (sc->irq_res != NULL) - { - bus_release_resource(dev, SYS_RES_IRQ, sc->irq_res_id, sc->irq_res); - sc->irq_res = NULL; - } - if (sc->csr_res != NULL) + switch (cmd) { - bus_release_resource(dev, sc->csr_res_type, sc->csr_res_id, sc->csr_res); - sc->csr_res = NULL; + /* Catch the IOCTLs used by lmcconfig. */ + case LMCIOCGSTAT: + case LMCIOCGCFG: + case LMCIOCSCFG: + case LMCIOCREAD: + case LMCIOCWRITE: + case LMCIOCTL: + error = core_ioctl(sc, cmd, data); + break; + /* Pass the rest to the line protocol. */ + default: + if (sc->config.line_pkg == PKG_RAWIP) + error = lmc_raw_ioctl(ifp, cmd, data); + else +# if NSPPP + error = sppp_ioctl(ifp, cmd, data); +# elif P2P + error = p2p_ioctl(ifp, cmd, data); +# else + error = EINVAL; +# endif + break; } -# if (__FreeBSD_version >= 500000) - mtx_destroy(&sc->top_mtx); - mtx_destroy(&sc->bottom_mtx); -# endif - return 0; /* no error */ + if (DRIVER_DEBUG && (error!=0)) + printf("%s: lmc_ifnet_ioctl; cmd=0x%08lx error=%d\n", + NAME_UNIT, cmd, error); + + return error; } -static int -fbsd_shutdown(device_t dev) +/* Called from a syscall (user context; no spinlocks). */ +static void +lmc_ifnet_start(struct ifnet *ifp) { - shutdown_card(device_get_softc(dev)); - return 0; + softc_t *sc = IFP2SC(ifp); + + /* Start the transmitter; incoming pkts are NOT processed. */ + user_interrupt(sc, 0); } +/* sppp and p2p replace this with their own proc. */ +/* RAWIP mode is the only time this is used. */ +/* Called from a syscall (user context; no spinlocks). */ static int -fbsd_attach(device_t dev) +lmc_raw_output(struct ifnet *ifp, struct mbuf *m, + const struct sockaddr *dst, struct route *ro) { - softc_t *sc = device_get_softc(dev); - int error; - - /* READ/WRITE_PCI_CFG need this. */ - sc->dev = dev; + softc_t *sc = IFP2SC(ifp); + int error = 0; - /* What kind of card are we driving? */ - switch (READ_PCI_CFG(sc, TLP_CSID)) + /* Fail if the link is down. */ + if (sc->status.oper_status != STATUS_UP) { - case TLP_CSID_HSSI: - case TLP_CSID_HSSIc: - sc->card = &hssi_card; - break; - case TLP_CSID_T3: - sc->card = &t3_card; - break; - case TLP_CSID_SSI: - sc->card = &ssi_card; - break; - case TLP_CSID_T1E1: - sc->card = &t1_card; - break; - default: - return ENXIO; + m_freem(m); + sc->status.cntrs.odiscards++; + if (DRIVER_DEBUG) + printf("%s: lmc_raw_output: tx pkt discarded: link down\n", NAME_UNIT); + return ENETDOWN; } - sc->dev_desc = device_get_desc(dev); - /* Allocate PCI memory or IO resources to access the Tulip chip CSRs. */ -# if IOREF_CSR - sc->csr_res_id = TLP_CBIO; - sc->csr_res_type = SYS_RES_IOPORT; -# else - sc->csr_res_id = TLP_CBMA; - sc->csr_res_type = SYS_RES_MEMORY; +# if NETGRAPH + /* Netgraph has priority over the ifnet kernel interface. */ + if (sc->ng_hook != NULL) + { + m_freem(m); + sc->status.cntrs.odiscards++; + if (DRIVER_DEBUG) + printf("%s: lmc_raw_output: tx pkt discarded: netgraph active\n", + NAME_UNIT); + return EBUSY; + } # endif - sc->csr_res = bus_alloc_resource(dev, sc->csr_res_type, &sc->csr_res_id, - 0, ~0, 1, RF_ACTIVE); - if (sc->csr_res == NULL) + + /* lmc_raw_output() ENQUEUEs in a syscall or softirq. */ + /* txintr_setup() DEQUEUEs in a hard interrupt. */ + /* Some BSD QUEUE routines are not interrupt-safe. */ + { + DISABLE_INTR; + IFQ_ENQUEUE(&ifp->if_snd, m, error); + ENABLE_INTR; + } + + if (error==0) + user_interrupt(sc, 0); /* start the transmitter */ + else { - printf("%s: bus_alloc_resource(csr) failed.\n", NAME_UNIT); - return ENXIO; + m_freem(m); + sc->status.cntrs.odiscards++; + ifp->if_oqdrops++; + if (DRIVER_DEBUG) + printf("%s: lmc_raw_output: IFQ_ENQUEUE() failed; error %d\n", + NAME_UNIT, error); } - sc->csr_tag = rman_get_bustag(sc->csr_res); - sc->csr_handle = rman_get_bushandle(sc->csr_res); - /* Allocate PCI interrupt resources for the card. */ - sc->irq_res_id = 0; - sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_res_id, - 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); - if (sc->irq_res == NULL) + return error; + } + +/* Called from a softirq once a second. */ +static void +lmc_watchdog(void *arg) + { + struct ifnet *ifp = arg; + softc_t *sc = IFP2SC(ifp); + u_int8_t old_oper_status = sc->status.oper_status; + struct event_cntrs *cntrs = &sc->status.cntrs; + + core_watchdog(sc); /* updates oper_status */ + +#if NETGRAPH + if (sc->ng_hook != NULL) { - printf("%s: bus_alloc_resource(irq) failed.\n", NAME_UNIT); - fbsd_detach(dev); - return ENXIO; + sc->status.line_pkg = PKG_NG; + sc->status.line_prot = 0; } - if ((error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE, - NULL, bsd_interrupt, sc, &sc->irq_cookie))) + else +#endif + if (sc->config.line_pkg == PKG_RAWIP) { - printf("%s: bus_setup_intr() failed; error %d\n", NAME_UNIT, error); - fbsd_detach(dev); - return error; + sc->status.line_pkg = PKG_RAWIP; + sc->status.line_prot = PROT_IP_HDLC; } + else + { +# if P2P + /* Notice change in link status. */ + if ((old_oper_status != sc->status.oper_status) && (sc->p2p->p2p_modem)) + (*sc->p2p->p2p_modem)(sc->p2p, sc->status.oper_status==STATUS_UP); + + /* Notice change in line protocol. */ + sc->status.line_pkg = PKG_P2P; + switch (sc->ifp->if_type) + { + case IFT_PPP: + sc->status.line_prot = PROT_PPP; + break; + case IFT_PTPSERIAL: + sc->status.line_prot = PROT_C_HDLC; + break; + case IFT_FRELAY: + sc->status.line_prot = PROT_FRM_RLY; + break; + default: + sc->status.line_prot = 0; + break; + } + +# elif NSPPP + /* Notice change in link status. */ + if ((old_oper_status != STATUS_UP) && + (sc->status.oper_status == STATUS_UP)) /* link came up */ + sppp_tls(sc->sppp); + if ((old_oper_status == STATUS_UP) && + (sc->status.oper_status != STATUS_UP)) /* link went down */ + sppp_tlf(sc->sppp); + + /* Notice change in line protocol. */ + sc->status.line_pkg = PKG_SPPP; + if (sc->sppp->pp_flags & PP_FR) + sc->status.line_prot = PROT_FRM_RLY; + else if (sc->ifp->if_flags & IFF_LINK2) + sc->status.line_prot = PROT_C_HDLC; + else + sc->status.line_prot = PROT_PPP; -# if (__FreeBSD_version >= 500000) - /* Initialize the top-half and bottom-half locks. */ - mtx_init(&sc->top_mtx, NAME_UNIT, "top half lock", MTX_DEF); - mtx_init(&sc->bottom_mtx, NAME_UNIT, "bottom half lock", MTX_DEF); +# else + /* Suppress compiler warning. */ + if (old_oper_status == STATUS_UP); # endif + } - /* Start the card and attach a kernel interface and line protocol. */ - if ((error = attach_card(sc, ""))) detach_card(sc); - return error; + /* Copy statistics from sc to ifp. */ + ifp->if_baudrate = sc->status.tx_speed; + ifp->if_ipackets = cntrs->ipackets; + ifp->if_opackets = cntrs->opackets; + ifp->if_ibytes = cntrs->ibytes; + ifp->if_obytes = cntrs->obytes; + ifp->if_ierrors = cntrs->ierrors; + ifp->if_oerrors = cntrs->oerrors; + ifp->if_iqdrops = cntrs->idiscards; + + if (sc->status.oper_status == STATUS_UP) + ifp->if_link_state = LINK_STATE_UP; + else + ifp->if_link_state = LINK_STATE_DOWN; + + /* Call this procedure again after one second. */ + callout_reset(&sc->callout, hz, lmc_watchdog, ifp); } -static device_method_t methods[] = - { - DEVMETHOD(device_probe, fbsd_probe), - DEVMETHOD(device_attach, fbsd_attach), - DEVMETHOD(device_detach, fbsd_detach), - DEVMETHOD(device_shutdown, fbsd_shutdown), - /* This driver does not suspend and resume. */ - { 0, 0 } - }; -static driver_t driver = +static void +setup_ifnet(struct ifnet *ifp) { - .name = DEVICE_NAME, - .methods = methods, -# if (__FreeBSD_version >= 500000) - .size = sizeof(softc_t), -# else /* FreeBSD-4 */ - .softc = sizeof(softc_t), -# endif - }; + softc_t *sc = ifp->if_softc; -static devclass_t devclass; + /* Initialize the generic network interface. */ + ifp->if_flags = IFF_POINTOPOINT; + ifp->if_flags |= IFF_RUNNING; + ifp->if_ioctl = lmc_ifnet_ioctl; + ifp->if_start = lmc_ifnet_start; /* sppp changes this */ + ifp->if_output = lmc_raw_output; /* sppp & p2p change this */ + ifp->if_input = lmc_raw_input; + ifp->if_mtu = MAX_DESC_LEN; /* sppp & p2p change this */ + ifp->if_type = IFT_PTPSERIAL; /* p2p changes this */ -DRIVER_MODULE(lmc, pci, driver, devclass, 0, 0); -MODULE_VERSION(lmc, 2); -MODULE_DEPEND(lmc, pci, 1, 1, 1); -# if NETGRAPH -MODULE_DEPEND(lmc, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); -# endif -# if NSPPP -MODULE_DEPEND(lmc, sppp, 1, 1, 1); +# if defined(DEVICE_POLLING) + ifp->if_capabilities |= IFCAP_POLLING; + ifp->if_capenable |= IFCAP_POLLING_NOCOUNT; # endif -#endif /* __FreeBSD__ */ - -/* This is the I/O configuration interface for NetBSD. */ - -#ifdef __NetBSD__ + if_initname(ifp, device_get_name(sc->dev), device_get_unit(sc->dev)); + } static int -nbsd_match(struct device *parent, struct cfdata *match, void *aux) +lmc_ifnet_attach(softc_t *sc) { - struct pci_attach_args *pa = aux; - u_int32_t cfid = pci_conf_read(pa->pa_pc, pa->pa_tag, TLP_CFID); - u_int32_t csid = pci_conf_read(pa->pa_pc, pa->pa_tag, TLP_CSID); + sc->ifp = if_alloc(NSPPP ? IFT_PPP : IFT_OTHER); + if (sc->ifp == NULL) return ENOMEM; +# if NSPPP + sc->sppp = sc->ifp->if_l2com; +# elif P2P + sc->ifp = &sc->p2pcom.p2p_if; + sc->p2p = &sc->p2pcom; +# endif - /* Looking for a DEC 21140A chip on any Lan Media Corp card. */ - if (cfid != TLP_CFID_TULIP) return 0; - switch (csid) - { - case TLP_CSID_HSSI: - case TLP_CSID_HSSIc: - case TLP_CSID_T3: - case TLP_CSID_SSI: - case TLP_CSID_T1E1: - return 100; - default: - return 0; - } - } + /* Initialize the network interface struct. */ + sc->ifp->if_softc = sc; + setup_ifnet(sc->ifp); -static int -nbsd_detach(struct device *self, int flags) - { - softc_t *sc = (softc_t *)self; /* device is first in softc */ + /* ALTQ output queue initialization. */ + IFQ_SET_MAXLEN(&sc->ifp->if_snd, SNDQ_MAXLEN); + IFQ_SET_READY(&sc->ifp->if_snd); - /* Stop the card and detach from the kernel. */ - detach_card(sc); + /* Attach to the ifnet kernel interface. */ + if_attach(sc->ifp); - /* Release resources. */ - if (sc->sdh_cookie != NULL) - { - shutdownhook_disestablish(sc->sdh_cookie); - sc->sdh_cookie = NULL; - } - if (sc->irq_cookie != NULL) - { - pci_intr_disestablish(sc->pa_pc, sc->irq_cookie); - sc->irq_cookie = NULL; - } - if (sc->csr_handle) - { - bus_space_unmap(sc->csr_tag, sc->csr_handle, TLP_CSR_SIZE); - sc->csr_handle = 0; - } + /* Attach Berkeley Packet Filter. */ + LMC_BPF_ATTACH(DLT_RAW, 0); - return 0; /* no error */ + callout_reset(&sc->callout, hz, lmc_watchdog, sc); + + return 0; } static void -nbsd_attach(struct device *parent, struct device *self, void *aux) +lmc_ifnet_detach(softc_t *sc) { - softc_t *sc = (softc_t *)self; /* device is first in softc */ - struct pci_attach_args *pa = aux; - const char *intrstr; - bus_addr_t csr_addr; - int error; - - /* READ/WRITE_PCI_CFG need these. */ - sc->pa_pc = pa->pa_pc; - sc->pa_tag = pa->pa_tag; - /* bus_dma needs this. */ - sc->pa_dmat = pa->pa_dmat; - - /* What kind of card are we driving? */ - switch (READ_PCI_CFG(sc, TLP_CSID)) - { - case TLP_CSID_HSSI: - case TLP_CSID_HSSIc: - sc->dev_desc = HSSI_DESC; - sc->card = &hssi_card; - break; - case TLP_CSID_T3: - sc->dev_desc = T3_DESC; - sc->card = &t3_card; - break; - case TLP_CSID_SSI: - sc->dev_desc = SSI_DESC; - sc->card = &ssi_card; - break; - case TLP_CSID_T1E1: - sc->dev_desc = T1E1_DESC; - sc->card = &t1_card; - break; - default: - return; - } - printf(": %s\n", sc->dev_desc); - /* Allocate PCI resources to access the Tulip chip CSRs. */ -# if IOREF_CSR - csr_addr = (bus_addr_t)READ_PCI_CFG(sc, TLP_CBIO) & -2; - sc->csr_tag = pa->pa_iot; /* bus_space tag for IO refs */ -# else - csr_addr = (bus_addr_t)READ_PCI_CFG(sc, TLP_CBMA); - sc->csr_tag = pa->pa_memt; /* bus_space tag for MEM refs */ +# if defined(DEVICE_POLLING) + if (sc->ifp->if_capenable & IFCAP_POLLING) + ether_poll_deregister(sc->ifp); # endif - if ((error = bus_space_map(sc->csr_tag, csr_addr, - TLP_CSR_SIZE, 0, &sc->csr_handle))) - { - printf("%s: bus_space_map() failed; error %d\n", NAME_UNIT, error); - return; - } - - /* Allocate PCI interrupt resources. */ - if ((error = pci_intr_map(pa, &sc->intr_handle))) - { - printf("%s: pci_intr_map() failed; error %d\n", NAME_UNIT, error); - nbsd_detach(self, 0); - return; - } - sc->irq_cookie = pci_intr_establish(pa->pa_pc, sc->intr_handle, - IPL_NET, bsd_interrupt, sc); - if (sc->irq_cookie == NULL) - { - printf("%s: pci_intr_establish() failed\n", NAME_UNIT); - nbsd_detach(self, 0); - return; - } - intrstr = pci_intr_string(pa->pa_pc, sc->intr_handle); - /* Install a shutdown hook. */ - sc->sdh_cookie = shutdownhook_establish(shutdown_card, sc); - if (sc->sdh_cookie == NULL) - { - printf("%s: shutdown_hook_establish() failed\n", NAME_UNIT); - nbsd_detach(self, 0); - return; - } + /* Detach Berkeley Packet Filter. */ + LMC_BPF_DETACH; - /* Initialize the top-half and bottom-half locks. */ - simple_lock_init(&sc->top_lock); - simple_lock_init(&sc->bottom_lock); + /* Detach from the ifnet kernel interface. */ + if_detach(sc->ifp); - /* Start the card and attach a kernel interface and line protocol. */ - if ((error = attach_card(sc, intrstr))) detach_card(sc); + if_free(sc->ifp); } -# if (__NetBSD_Version__ >= 106080000) /* 1.6H */ -CFATTACH_DECL(lmc, sizeof(softc_t), - nbsd_match, nbsd_attach, nbsd_detach, NULL); -# else -struct cfattach lmc_ca = - { -/*.ca_name = DEVICE_NAME, */ - .ca_devsize = sizeof(softc_t), - .ca_match = nbsd_match, - .ca_attach = nbsd_attach, - .ca_detach = nbsd_detach, - .ca_activate = NULL, - }; -# endif - -# if (__NetBSD_Version__ >= 106080000) -CFDRIVER_DECL(lmc, DV_IFNET, NULL); -# else -static struct cfdriver lmc_cd = - { - .cd_name = DEVICE_NAME, - .cd_class = DV_IFNET, - .cd_ndevs = 0, - .cd_devs = NULL, - }; -# endif - -/* cfdata is declared static, unseen outside this module. */ -/* It is used for LKM; config builds its own in ioconf.c. */ -static struct cfdata lmc_cf = - { -# if (__NetBSD_Version__ >= 106080000) - .cf_name = DEVICE_NAME, - .cf_atname = DEVICE_NAME, -# else - .cf_driver = &lmc_cd, - .cf_attach = &lmc_ca, -# endif - .cf_unit = 0, - .cf_fstate = FSTATE_STAR, - }; -# if (__NetBSD_Version__ >= 106080000) -MOD_MISC(DEVICE_NAME) -# else -static struct lkm_misc _module = - { - .lkm_name = DEVICE_NAME, - .lkm_type = LM_MISC, - .lkm_offset = 0, - .lkm_ver = LKM_VERSION, - }; -# endif +#if NETGRAPH -/* From /sys/dev/pci/pci.c (no public prototype). */ -int pciprint(void *, const char *); +/* These next two macros should be added to netgraph */ +# define NG_TYPE_REF(type) atomic_add_int(&(type)->refs, 1) +# define NG_TYPE_UNREF(type) \ +do { \ + if ((type)->refs == 1) \ + ng_rmtype(type); \ + else \ + atomic_subtract_int(&(type)->refs, 1); \ + } while (0) -static int lkm_nbsd_match(struct pci_attach_args *pa) - { return nbsd_match(0, 0, pa); } +/* It is an error to construct new copies of this Netgraph node. */ +/* All instances are constructed by ng_attach and are persistent. */ +static int ng_constructor(node_p node) { return EINVAL; } -/* LKM loader finds this by appending "_lkmentry" to filename "if_lmc". */ -int if_lmc_lkmentry(struct lkm_table *lkmtp, int cmd, int ver) +/* Incoming Netgraph control message. */ +static int +ng_rcvmsg(node_p node, item_p item, hook_p lasthook) { - int i, error = 0; + struct ng_mesg *msg; + struct ng_mesg *resp = NULL; + softc_t *sc = NG_NODE_PRIVATE(node); + int error = 0; - if (ver != LKM_VERSION) return EINVAL; - switch (cmd) + NGI_GET_MSG(item, msg); + if (msg->header.typecookie == NGM_LMC_COOKIE) { - case LKM_E_LOAD: + switch (msg->header.cmd) { - struct cfdriver* pcicd; - - lkmtp->private.lkm_misc = &_module; - if ((pcicd = config_cfdriver_lookup("pci")) == NULL) - { - printf("%s: config_cfdriver_lookup(pci) failed; error %d\n", - lmc_cd.cd_name, error); - return error; - } -# if (__NetBSD_Version__ >= 106080000) - if ((error = config_cfdriver_attach(&lmc_cd))) - { - printf("%s: config_cfdriver_attach() failed; error %d\n", - lmc_cd.cd_name, error); - return error; - } - if ((error = config_cfattach_attach(lmc_cd.cd_name, &lmc_ca))) - { - printf("%s: config_cfattach_attach() failed; error %d\n", - lmc_cd.cd_name, error); - config_cfdriver_detach(&lmc_cd); - return error; - } -# endif - for (i=0; icd_ndevs; i++) + case LMCIOCGSTAT: + case LMCIOCGCFG: + case LMCIOCSCFG: + case LMCIOCREAD: + case LMCIOCWRITE: + case LMCIOCTL: { - int dev; - /* A pointer to a device is a pointer to its softc. */ - struct pci_softc *sc = pcicd->cd_devs[i]; - if (sc == NULL) continue; - for (dev=0; devsc_maxndevs; dev++) - { - struct pci_attach_args pa; - pcitag_t tag = pci_make_tag(sc->sc_pc, sc->sc_bus, dev, 0); - if (pci_probe_device(sc, tag, lkm_nbsd_match, &pa) != 0) - config_attach(pcicd->cd_devs[i], &lmc_cf, &pa, pciprint); - /* config_attach doesn't return on failure; it calls panic. */ + /* Call the core ioctl procedure. */ + error = core_ioctl(sc, msg->header.cmd, msg->data); + if ((msg->header.cmd & IOC_OUT) != 0) + { /* synchronous response */ + NG_MKRESPONSE(resp, msg, sizeof(struct ng_mesg) + + IOCPARM_LEN(msg->header.cmd), M_NOWAIT); + if (resp == NULL) + error = ENOMEM; + else + memcpy(resp->data, msg->data, IOCPARM_LEN(msg->header.cmd)); } - } - break; + break; + } + default: + error = EINVAL; + break; } - case LKM_E_UNLOAD: + } + else if ((msg->header.typecookie == NGM_GENERIC_COOKIE) && + (msg->header.cmd == NGM_TEXT_STATUS)) + { /* synchronous response */ + NG_MKRESPONSE(resp, msg, sizeof(struct ng_mesg) + + NG_TEXTRESPONSE, M_NOWAIT); + if (resp == NULL) + error = ENOMEM; + else { - for (i=lmc_cd.cd_ndevs-1; i>=0; i--) - { - struct device *dev = lmc_cd.cd_devs[i]; - if (dev == NULL) continue; - if ((error = config_detach(dev, 0))) - { - printf("%s: config_detach() failed; error %d\n", - dev->dv_xname, error); - return error; - } - } -# if (__NetBSD_Version__ >= 106080000) - if ((error = config_cfattach_detach(lmc_cd.cd_name, &lmc_ca))) - { - printf("%s: config_cfattach_detach() failed; error %d\n", - lmc_cd.cd_name, error); - return error; - } - if ((error = config_cfdriver_detach(&lmc_cd))) - { - printf("%s: config_cfdriver_detach() failed; error %d\n", - lmc_cd.cd_name, error); - return error; - } -# endif - break; + char *s = resp->data; + sprintf(s, "Card type = <%s>\n" + "This driver considers the link to be %s.\n" + "Use lmcconfig to configure this interface.\n", + sc->dev_desc, (sc->status.oper_status==STATUS_UP) ? "UP" : "DOWN"); + resp->header.arglen = strlen(s) +1; } - case LKM_E_STAT: - break; } + else +/* Netgraph should be able to read and write these + * parameters with text-format control messages: + * SSI HSSI T1E1 T3 + * crc crc crc crc + * loop loop loop loop + * clksrc clksrc + * dte dte format format + * synth synth cablen cablen + * cable timeslot scram + * gain + * pulse + * lbo + * Someday I'll implement this... + */ + error = EINVAL; + + /* Handle synchronous response. */ + NG_RESPOND_MSG(error, node, item, resp); + NG_FREE_MSG(msg); return error; } -#endif /* __NetBSD__ */ - -/* This is the I/O configuration interface for OpenBSD. */ - -#ifdef __OpenBSD__ - +/* This is a persistent netgraph node. */ static int -obsd_match(struct device *parent, void *match, void *aux) +ng_shutdown(node_p node) { - struct pci_attach_args *pa = aux; - u_int32_t cfid = pci_conf_read(pa->pa_pc, pa->pa_tag, TLP_CFID); - u_int32_t csid = pci_conf_read(pa->pa_pc, pa->pa_tag, TLP_CSID); + /* unless told to really die, bounce back to life */ + if ((node->nd_flags & NG_REALLY_DIE)==0) + node->nd_flags &= ~NG_INVALID; /* bounce back to life */ - /* Looking for a DEC 21140A chip on any Lan Media Corp card. */ - if (cfid != TLP_CFID_TULIP) return 0; - switch (csid) - { - case TLP_CSID_HSSI: - case TLP_CSID_HSSIc: - case TLP_CSID_T3: - case TLP_CSID_SSI: - case TLP_CSID_T1E1: - return 100; /* match better than other 21140 drivers */ - default: - return 0; - } + return 0; } +/* ng_disconnect is the opposite of this procedure. */ static int -obsd_detach(struct device *self, int flags) - { - softc_t *sc = (softc_t *)self; /* device is first in softc */ - - /* Stop the card and detach from the kernel. */ - detach_card(sc); - - /* Release resources. */ - if (sc->sdh_cookie != NULL) - { - shutdownhook_disestablish(sc->sdh_cookie); - sc->sdh_cookie = NULL; - } - if (sc->irq_cookie != NULL) - { - pci_intr_disestablish(sc->pa_pc, sc->irq_cookie); - sc->irq_cookie = NULL; - } - if (sc->csr_handle) - { - bus_space_unmap(sc->csr_tag, sc->csr_handle, TLP_CSR_SIZE); - sc->csr_handle = 0; - } - - return 0; /* no error */ - } - -static void -obsd_attach(struct device *parent, struct device *self, void *aux) +ng_newhook(node_p node, hook_p hook, const char *name) { - softc_t *sc = (softc_t *)self; /* device is first in softc */ - struct pci_attach_args *pa = aux; - const char *intrstr; - bus_addr_t csr_addr; - int error; - - /* READ/WRITE_PCI_CFG need these. */ - sc->pa_pc = pa->pa_pc; - sc->pa_tag = pa->pa_tag; - /* bus_dma needs this. */ - sc->pa_dmat = pa->pa_dmat; - - /* What kind of card are we driving? */ - switch (READ_PCI_CFG(sc, TLP_CSID)) - { - case TLP_CSID_HSSI: - case TLP_CSID_HSSIc: - sc->dev_desc = HSSI_DESC; - sc->card = &hssi_card; - break; - case TLP_CSID_T3: - sc->dev_desc = T3_DESC; - sc->card = &t3_card; - break; - case TLP_CSID_SSI: - sc->dev_desc = SSI_DESC; - sc->card = &ssi_card; - break; - case TLP_CSID_T1E1: - sc->dev_desc = T1E1_DESC; - sc->card = &t1_card; - break; - default: - return; - } - printf(": %s\n", sc->dev_desc); - - /* Allocate PCI resources to access the Tulip chip CSRs. */ -# if IOREF_CSR - csr_addr = (bus_addr_t)READ_PCI_CFG(sc, TLP_CBIO) & -2; - sc->csr_tag = pa->pa_iot; /* bus_space tag for IO refs */ -# else - csr_addr = (bus_addr_t)READ_PCI_CFG(sc, TLP_CBMA); - sc->csr_tag = pa->pa_memt; /* bus_space tag for MEM refs */ -# endif - if ((error = bus_space_map(sc->csr_tag, csr_addr, - TLP_CSR_SIZE, 0, &sc->csr_handle))) - { - printf("%s: bus_space_map() failed; error %d\n", NAME_UNIT, error); - return; - } + softc_t *sc = NG_NODE_PRIVATE(node); - /* Allocate PCI interrupt resources. */ - if ((error = pci_intr_map(pa, &sc->intr_handle))) - { - printf("%s: pci_intr_map() failed; error %d\n", NAME_UNIT, error); - obsd_detach(self, 0); - return; - } - sc->irq_cookie = pci_intr_establish(pa->pa_pc, sc->intr_handle, - IPL_NET, bsd_interrupt, sc, self->dv_xname); - if (sc->irq_cookie == NULL) - { - printf("%s: pci_intr_establish() failed\n", NAME_UNIT); - obsd_detach(self, 0); - return; - } - intrstr = pci_intr_string(pa->pa_pc, sc->intr_handle); + /* Hook name must be 'rawdata'. */ + if (strncmp(name, "rawdata", 7) != 0) return EINVAL; - /* Install a shutdown hook. */ - sc->sdh_cookie = shutdownhook_establish(shutdown_card, sc); - if (sc->sdh_cookie == NULL) - { - printf("%s: shutdown_hook_establish() failed\n", NAME_UNIT); - obsd_detach(self, 0); - return; - } + /* Is our hook connected? */ + if (sc->ng_hook != NULL) return EBUSY; - /* Initialize the top-half and bottom-half locks. */ - simple_lock_init(&sc->top_lock); - simple_lock_init(&sc->bottom_lock); + /* Accept the hook. */ + sc->ng_hook = hook; - /* Start the card and attach a kernel interface and line protocol. */ - if ((error = attach_card(sc, intrstr))) detach_card(sc); + return 0; } -struct cfattach lmc_ca = - { - .ca_devsize = sizeof(softc_t), - .ca_match = obsd_match, - .ca_attach = obsd_attach, - .ca_detach = obsd_detach, - .ca_activate = NULL, - }; - -struct cfdriver lmc_cd = +/* Both ends have accepted their hooks and the links have been made. */ +/* This is the last chance to reject the connection request. */ +static int +ng_connect(hook_p hook) { - .cd_name = DEVICE_NAME, - .cd_devs = NULL, - .cd_class = DV_IFNET, - .cd_indirect = 0, - .cd_ndevs = 0, - }; + /* Probably not at splnet, force outward queueing. (huh?) */ + NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); + return 0; /* always accept */ + } -/* cfdata is declared static, unseen outside this module. */ -/* It is used for LKM; config builds its own in ioconf.c. */ -static struct cfdata lmc_cfdata = +/* Receive data in mbufs from another Netgraph node. */ +/* Transmit an mbuf-chain on the communication link. */ +/* This procedure is very similar to lmc_raw_output(). */ +/* Called from a syscall (user context; no spinlocks). */ +static int +ng_rcvdata(hook_p hook, item_p item) { - .cf_attach = &lmc_ca, - .cf_driver = &lmc_cd, - .cf_unit = 0, - .cf_fstate = FSTATE_STAR, - }; + softc_t *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); + int error = 0; + struct mbuf *m; + meta_p meta = NULL; -static struct lkm_any _module = - { - .lkm_name = DEVICE_NAME, - .lkm_type = LM_MISC, - .lkm_offset = 0, - .lkm_ver = LKM_VERSION, - }; + NGI_GET_M(item, m); + NGI_GET_META(item, meta); + NG_FREE_ITEM(item); -/* From /sys/dev/pci/pci.c (no public prototype). */ -int pciprint(void *, const char *); + /* This macro must not store into meta! */ + NG_FREE_META(meta); -extern struct cfdriver pci_cd; + /* Fail if the link is down. */ + if (sc->status.oper_status != STATUS_UP) + { + m_freem(m); + sc->status.cntrs.odiscards++; + if (DRIVER_DEBUG) + printf("%s: ng_rcvdata: tx pkt discarded: link down\n", NAME_UNIT); + return ENETDOWN; + } -/* LKM loader finds this by appending "_lkmentry" to filename "if_lmc". */ -int if_lmc_lkmentry(struct lkm_table *lkmtp, int cmd, int ver) + /* ng_rcvdata() ENQUEUEs in a syscall or softirq. */ + /* txintr_setup() DEQUEUEs in a hard interrupt. */ + /* Some BSD QUEUE routines are not interrupt-safe. */ { - int i, error = 0; + DISABLE_INTR; + if (meta==NULL) + IFQ_ENQUEUE(&sc->ng_sndq, m, error); + else + IFQ_ENQUEUE(&sc->ng_fastq, m, error); + ENABLE_INTR; + } - if (ver != LKM_VERSION) return EINVAL; - switch (cmd) + if (error==0) + user_interrupt(sc, 0); /* start the transmitter */ + else { - case LKM_E_LOAD: - { /* XXX This works for ONE card on pci0 of a i386 machine! XXX */ - lkmtp->private.lkm_any = &_module; - for (i=0; idv_unit)!=0) continue; /* only bus zero */ - /* XXX For machine independence, need: pcibus_attach_args. XXX */ - /* XXX See NetBSD's sys/dev/pci/pci.c/pci_probe_device. XXX */ - /* XXX Why isn't there an LKM network interface module? XXX */ - pa.pa_pc = NULL; /* XXX */ - pa.pa_bus = 0; /* XXX */ - pa.pa_iot = X86_BUS_SPACE_IO; /* XXX */ - pa.pa_memt = X86_BUS_SPACE_MEM; /* XXX */ - pa.pa_dmat = &pci_bus_dma_tag; /* XXX */ - for (pa.pa_device=0; pa.pa_device<32; pa.pa_device++) /* XXX */ - { - int intr; - pa.pa_function = 0; /* DEC-21140A has function 0 only XXX */ - pa.pa_tag = pci_make_tag(pa.pa_pc, pa.pa_bus, pa.pa_device, 0); - pa.pa_id = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_ID_REG); - if ((pa.pa_id & 0xFFFF) == 0xFFFF) continue; - if ((pa.pa_id & 0xFFFF) == 0) continue; - /* XXX this only works for pci0 -- no swizzelling XXX */ - pa.pa_intrswiz = 0; - pa.pa_intrtag = pa.pa_tag; - intr = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_INTERRUPT_REG); - pa.pa_intrline = PCI_INTERRUPT_LINE(intr); - pa.pa_intrpin = ((PCI_INTERRUPT_PIN(intr) -1) % 4) +1; - if (obsd_match(parent, &lmc_cfdata, &pa)) - config_attach(parent, &lmc_cfdata, &pa, pciprint); - /* config_attach doesn't return on failure; it calls panic. */ - } - } - break; - } - case LKM_E_UNLOAD: - { - for (i=lmc_cd.cd_ndevs-1; i>=0; i--) - { - struct device *dev = lmc_cd.cd_devs[i]; - if (dev == NULL) continue; - if ((error = config_detach(dev, 0))) - printf("%s: config_detach() failed; error %d\n", dev->dv_xname, error); - } - break; - } - case LKM_E_STAT: - break; + m_freem(m); + sc->status.cntrs.odiscards++; + if (DRIVER_DEBUG) + printf("%s: ng_rcvdata: IFQ_ENQUEUE() failed; error %d\n", + NAME_UNIT, error); } return error; } -#endif /* __OpenBSD__ */ - -/* This is the I/O configuration interface for BSD/OS. */ - -#ifdef __bsdi__ - +/* ng_newhook is the opposite of this procedure, not */ +/* ng_connect, as you might expect from the names. */ static int -bsdi_match(pci_devaddr_t *pa) +ng_disconnect(hook_p hook) { - u_int32_t cfid = pci_inl(pa, TLP_CFID); - u_int32_t csid = pci_inl(pa, TLP_CSID); + softc_t *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); - /* Looking for a DEC 21140A chip on any Lan Media Corp card. */ - if (cfid != TLP_CFID_TULIP) return 0; - switch (csid) - { - case TLP_CSID_HSSI: - case TLP_CSID_HSSIc: - case TLP_CSID_T3: - case TLP_CSID_SSI: - case TLP_CSID_T1E1: - return 1; - default: - return 0; - } + /* Disconnect the hook. */ + sc->ng_hook = NULL; + + return 0; } -static int -bsdi_probe(struct device *parent, struct cfdata *cf, void *aux) +static +struct ng_type ng_type = { - struct isa_attach_args *ia = aux; - pci_devaddr_t *pa = NULL; - pci_devres_t res; - - /* This must be a PCI bus. */ - if (ia->ia_bustype != BUS_PCI) return 0; - - /* Scan PCI bus for our boards. */ - if ((pa = pci_scan(bsdi_match)) == 0) return 0; - - /* Scan config space for IO and MEM base registers and IRQ info. */ - pci_getres(pa, &res, 1, ia); - - /* Crucial: pass pci_devaddr to bsdi_attach in ia_aux. */ - ia->ia_aux = (void *)pa; + .version = NG_ABI_VERSION, + .name = NG_LMC_NODE_TYPE, + .mod_event = NULL, + .constructor = ng_constructor, + .rcvmsg = ng_rcvmsg, + .close = NULL, + .shutdown = ng_shutdown, + .newhook = ng_newhook, + .findhook = NULL, + .connect = ng_connect, + .rcvdata = ng_rcvdata, + .disconnect = ng_disconnect, + }; - return 1; - } -static void -bsdi_attach(struct device *parent, struct device *self, void *aux) +/* Attach to the Netgraph kernel interface (/sys/netgraph). + * It is called once for each physical card during device attach. + * This is effectively ng_constructor. + */ +static int +ng_attach(softc_t *sc) { - softc_t *sc = (softc_t *)self; /* device is first in softc */ - struct isa_attach_args *ia = aux; - pci_devaddr_t *pa = ia->ia_aux; /* this is crucial! */ int error; - /* READ/WRITE_PCI_CFG need this. */ - sc->cfgbase = *pa; + /* If this node type is not known to Netgraph then register it. */ + if (ng_type.refs == 0) /* or: if (ng_findtype(&ng_type) == NULL) */ + { + if ((error = ng_newtype(&ng_type))) + { + printf("%s: ng_newtype() failed; error %d\n", NAME_UNIT, error); + return error; + } + } + else + NG_TYPE_REF(&ng_type); - /* What kind of card are we driving? */ - switch (READ_PCI_CFG(sc, TLP_CSID)) + /* Call the superclass node constructor. */ + if ((error = ng_make_node_common(&ng_type, &sc->ng_node))) { - case TLP_CSID_HSSI: - case TLP_CSID_HSSIc: - sc->dev_desc = HSSI_DESC; - sc->card = &hssi_card; - break; - case TLP_CSID_T3: - sc->dev_desc = T3_DESC; - sc->card = &t3_card; - break; - case TLP_CSID_SSI: - sc->dev_desc = SSI_DESC; - sc->card = &ssi_card; - break; - case TLP_CSID_T1E1: - sc->dev_desc = T1E1_DESC; - sc->card = &t1_card; - break; - default: - return; + NG_TYPE_UNREF(&ng_type); + printf("%s: ng_make_node_common() failed; error %d\n", NAME_UNIT, error); + return error; } - printf(": %s\n", sc->dev_desc); - /* Allocate PCI memory or IO resources to access the Tulip chip CSRs. */ - sc->csr_iobase = ia->ia_iobase; - sc->csr_membase = (u_int32_t *)mapphys((vm_offset_t)ia->ia_maddr, TLP_CSR_SIZE); + /* Associate a name with this netgraph node. */ + if ((error = ng_name_node(sc->ng_node, NAME_UNIT))) + { + NG_NODE_UNREF(sc->ng_node); + NG_TYPE_UNREF(&ng_type); + printf("%s: ng_name_node() failed; error %d\n", NAME_UNIT, error); + return error; + } - /* Attach to the PCI bus. */ - isa_establish(&sc->id, &sc->dev); + /* Initialize the send queue mutexes. */ + mtx_init(&sc->ng_sndq.ifq_mtx, NAME_UNIT, "sndq", MTX_DEF); + mtx_init(&sc->ng_fastq.ifq_mtx, NAME_UNIT, "fastq", MTX_DEF); - /* Allocate PCI interrupt resources for the card. */ - sc->ih.ih_fun = bsd_interrupt; - sc->ih.ih_arg = sc; - intr_establish(ia->ia_irq, &sc->ih, DV_NET); + /* Put a backpointer to the softc in the netgraph node. */ + NG_NODE_SET_PRIVATE(sc->ng_node, sc); - /* Install a shutdown hook. */ - sc->ats.func = shutdown_card; - sc->ats.arg = sc; - atshutdown(&sc->ats, ATSH_ADD); + /* ALTQ output queue initialization. */ + IFQ_SET_MAXLEN(&sc->ng_fastq, SNDQ_MAXLEN); + IFQ_SET_READY(&sc->ng_fastq); + IFQ_SET_MAXLEN(&sc->ng_sndq, SNDQ_MAXLEN); + IFQ_SET_READY(&sc->ng_sndq); - /* Initialize the top-half and bottom-half locks. */ - simple_lock_init(&sc->top_lock); - simple_lock_init(&sc->bottom_lock); - /* Start the card and attach a kernel interface and line protocol. */ - if ((error = attach_card(sc, ""))) detach_card(sc); + return 0; } -struct cfdriver lmccd = - { - .cd_devs = NULL, - .cd_name = DEVICE_NAME, - .cd_match = bsdi_probe, - .cd_attach = bsdi_attach, - .cd_class = DV_IFNET, - .cd_devsize = sizeof(softc_t), - }; -#endif /* __bsdi__ */ - -#ifdef __linux__ - -/* The kernel calls this procedure when an interrupt happens. */ -static irqreturn_t -linux_interrupt(int irq, void *dev, struct pt_regs *regs) +static void +ng_detach(softc_t *sc) { - struct net_device *net_dev = dev; - softc_t *sc = dev_to_hdlc(net_dev)->priv; - - /* Cut losses early if this is not our interrupt. */ - if ((READ_CSR(TLP_STATUS) & TLP_INT_TXRX) == 0) - return IRQ_NONE; - - /* Disable card interrupts. */ - WRITE_CSR(TLP_INT_ENBL, TLP_INT_DISABLE); + callout_drain(&sc->callout); + mtx_destroy(&sc->ng_sndq.ifq_mtx); + mtx_destroy(&sc->ng_fastq.ifq_mtx); + ng_rmnode_self(sc->ng_node); /* free hook */ + NG_NODE_UNREF(sc->ng_node); /* free node */ + NG_TYPE_UNREF(&ng_type); + } - /* Handle the card interrupt with the dev->poll method. */ - if (netif_rx_schedule_prep(net_dev)) - __netif_rx_schedule(net_dev); /* NAPI - add to poll list */ - else - printk("%s: interrupt while on poll list\n", NAME_UNIT); +#endif /* NETGRAPH */ - return IRQ_HANDLED; - } +/* The next few procedures initialize the card. */ -/* This net_device method services interrupts in a softirq. */ -/* With rxintr_cleanup(), it implements input flow control. */ +/* Returns 0 on success; error code on failure. */ static int -linux_poll(struct net_device *net_dev, int *budget) +startup_card(softc_t *sc) { - softc_t *sc = dev_to_hdlc(net_dev)->priv; - int received; - - /* Yes, we do NAPI. */ - /* Allow processing up to net_dev->quota incoming packets. */ - /* This is the ONLY time core_interrupt() may process rx pkts. */ - /* Otherwise (sc->quota == 0) and rxintr_cleanup() is a NOOP. */ - sc->quota = net_dev->quota; - - /* Handle the card interrupt with kernel ints enabled. */ - /* Process rx pkts (and tx pkts, too). */ - /* Card interrupts are disabled. */ - core_interrupt(sc, 0); + int num_rx_descs, error = 0; + u_int32_t tlp_bus_pbl, tlp_bus_cal, tlp_op_tr; + u_int32_t tlp_cfdd, tlp_cfcs; + u_int32_t tlp_cflt, tlp_csid, tlp_cfit; - /* Report number of rx packets processed. */ - received = net_dev->quota - sc->quota; - net_dev->quota -= received; - *budget -= received; + /* Make sure the COMMAND bits are reasonable. */ + tlp_cfcs = READ_PCI_CFG(sc, TLP_CFCS); + tlp_cfcs &= ~TLP_CFCS_MWI_ENABLE; + tlp_cfcs |= TLP_CFCS_BUS_MASTER; + tlp_cfcs |= TLP_CFCS_MEM_ENABLE; + tlp_cfcs |= TLP_CFCS_IO_ENABLE; + tlp_cfcs |= TLP_CFCS_PAR_ERROR; + tlp_cfcs |= TLP_CFCS_SYS_ERROR; + WRITE_PCI_CFG(sc, TLP_CFCS, tlp_cfcs); - /* if quota prevented processing all rx pkts, leave rx ints disabled */ - if (sc->quota == 0) /* this is off by one...but harmless */ + /* Set the LATENCY TIMER to the recommended value, */ + /* and make sure the CACHE LINE SIZE is reasonable. */ + tlp_cfit = READ_PCI_CFG(sc, TLP_CFIT); + tlp_cflt = READ_PCI_CFG(sc, TLP_CFLT); + tlp_cflt &= ~TLP_CFLT_LATENCY; + tlp_cflt |= (tlp_cfit & TLP_CFIT_MAX_LAT)>>16; + /* "prgmbl burst length" and "cache alignment" used below. */ + switch(tlp_cflt & TLP_CFLT_CACHE) { - WRITE_CSR(TLP_INT_ENBL, TLP_INT_TX); - return 1; /* more pkts to handle -- reschedule */ + case 8: /* 8 bytes per cache line */ + { tlp_bus_pbl = 32; tlp_bus_cal = 1; break; } + case 16: + { tlp_bus_pbl = 32; tlp_bus_cal = 2; break; } + case 32: + { tlp_bus_pbl = 32; tlp_bus_cal = 3; break; } + default: + { + tlp_bus_pbl = 32; tlp_bus_cal = 1; + tlp_cflt &= ~TLP_CFLT_CACHE; + tlp_cflt |= 8; + break; + } } + WRITE_PCI_CFG(sc, TLP_CFLT, tlp_cflt); - sc->quota = 0; /* disable rx pkt processing by rxintr_cleanup() */ - netif_rx_complete(net_dev); /* NAPI - remove from poll list */ - - /* Enable card interrupts. */ - WRITE_CSR(TLP_INT_ENBL, TLP_INT_TXRX); - return 0; - } + /* Make sure SNOOZE and SLEEP modes are disabled. */ + tlp_cfdd = READ_PCI_CFG(sc, TLP_CFDD); + tlp_cfdd &= ~TLP_CFDD_SLEEP; + tlp_cfdd &= ~TLP_CFDD_SNOOZE; + WRITE_PCI_CFG(sc, TLP_CFDD, tlp_cfdd); + DELAY(11*1000); /* Tulip wakes up in 10 ms max */ -/* These next routines are similar to BSD's ifnet kernel/driver interface. */ + /* Software Reset the Tulip chip; stops DMA and Interrupts. */ + /* This does not change the PCI config regs just set above. */ + WRITE_CSR(TLP_BUS_MODE, TLP_BUS_RESET); /* self-clearing */ + DELAY(5); /* Tulip is dead for 50 PCI cycles after reset. */ -/* This net_device method hands outgoing packets to the transmitter. */ -/* With txintr_setup(), it implements output flow control. */ -/* Called from a syscall (user context; no spinlocks). */ -static int -linux_start(struct sk_buff *skb, struct net_device *net_dev) - { - softc_t *sc = dev_to_hdlc(net_dev)->priv; + /* Reset the Xilinx Field Programmable Gate Array. */ + reset_xilinx(sc); /* side effect: turns on all four LEDs */ - if (sc->tx_skb == NULL) - { - /* Put this skb where the transmitter will see it. */ - sc->tx_skb = skb; + /* Configure card-specific stuff (framers, line interfaces, etc.). */ + sc->card->config(sc); - /* Start the transmitter; incoming pkts are NOT processed. */ - user_interrupt(sc, 0); + /* Initializing cards can glitch clocks and upset fifos. */ + /* Reset the FIFOs between the Tulip and Xilinx chips. */ + set_mii16_bits(sc, MII16_FIFO); + clr_mii16_bits(sc, MII16_FIFO); - /* If the tx didn't take the skb then stop the queue. */ - /* This can happen if another CPU is in core_interrupt(). */ - if (sc->tx_skb != NULL) netif_stop_queue(net_dev); + /* Initialize the PCI busmode register. */ + /* The PCI bus cycle type "Memory Write and Invalidate" does NOT */ + /* work cleanly in any version of the 21140A, so don't enable it! */ + WRITE_CSR(TLP_BUS_MODE, + (tlp_bus_cal ? TLP_BUS_READ_LINE : 0) | + (tlp_bus_cal ? TLP_BUS_READ_MULT : 0) | + (tlp_bus_pbl<start() called with queue stopped\n", NAME_UNIT); - else - netif_stop_queue(net_dev); + /* Create DMA descriptors and initialize list head registers. */ + if ((error = create_ring(sc, &sc->txring, NUM_TX_DESCS))) return error; + WRITE_CSR(TLP_TX_LIST, sc->txring.dma_addr); + if ((error = create_ring(sc, &sc->rxring, num_rx_descs))) return error; + WRITE_CSR(TLP_RX_LIST, sc->rxring.dma_addr); - return 1; - } + /* Initialize the operating mode register. */ + WRITE_CSR(TLP_OP_MODE, TLP_OP_INIT | (tlp_op_tr<priv; + /* Read the missed frame register (result ignored) to zero it. */ + error = READ_CSR( TLP_MISSED); /* error is used as a bit-dump */ - /* Start the transmitter; incoming packets are NOT processed. */ - user_interrupt(sc, 1); + /* Disable rx watchdog and tx jabber features. */ + WRITE_CSR(TLP_WDOG, TLP_WDOG_INIT); + + /* Enable card interrupts. */ + WRITE_CSR(TLP_INT_ENBL, TLP_INT_TXRX); + + return 0; } -/* This net_device method handles IOCTL syscalls. */ -/* Called from a syscall (user context; no spinlocks; can sleep). */ -static int -linux_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd) +/* Stop DMA and Interrupts; free descriptors and buffers. */ +static void +shutdown_card(void *arg) { - softc_t *sc = dev_to_hdlc(net_dev)->priv; - int error = 0; - - if ((cmd >= SIOCDEVPRIVATE) && (cmd <= SIOCDEVPRIVATE+15)) - { - struct iohdr *iohdr = (struct iohdr *)ifr; - u_int16_t direction = iohdr->direction; - u_int16_t length = iohdr->length; - char *user_addr = (char *)iohdr->iohdr; - char *kern_addr; - - if (iohdr->cookie != NGM_LMC_COOKIE) return -EINVAL; - - /* Emulate a BSD-style IOCTL syscall. */ - kern_addr = kmalloc(length, GFP_KERNEL); - if (kern_addr == NULL) - error = -ENOMEM; - if ((error == 0) && ((direction & DIR_IOW) != 0)) - error = copy_from_user(kern_addr, user_addr, length); - if (error == 0) - error = -core_ioctl(sc, (unsigned long)cmd, kern_addr); - if ((error == 0) && ((direction & DIR_IOR) != 0)) - error = copy_to_user(user_addr, kern_addr, length); - kfree(kern_addr); - } -# if GEN_HDLC - else if (cmd == SIOCWANDEV) - { - const size_t size = sizeof(sync_serial_settings); + softc_t *sc = arg; - switch (ifr->ifr_settings.type) - { - case IF_GET_IFACE: /* get interface config */ - { - ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; - if (ifr->ifr_settings.size < size) - { - ifr->ifr_settings.size = size; - error = -ENOBUFS; - } - else - { - if (sc->config.tx_clk_src == CFG_CLKMUX_ST) - sc->hdlc_settings.clock_type = CLOCK_EXT; - if (sc->config.tx_clk_src == CFG_CLKMUX_INT) - sc->hdlc_settings.clock_type = CLOCK_TXINT; - if (sc->config.tx_clk_src == CFG_CLKMUX_RT) - sc->hdlc_settings.clock_type = CLOCK_TXFROMRX; - sc->hdlc_settings.loopback = (sc->config.loop_back != CFG_LOOP_NONE) ? 1:0; - sc->hdlc_settings.clock_rate = sc->status.tx_speed; - error = copy_to_user(ifr->ifr_settings.ifs_ifsu.sync, - &sc->hdlc_settings, size); - } - break; - } - case IF_IFACE_SYNC_SERIAL: /* set interface config */ - { - if (!capable(CAP_NET_ADMIN)) - error = -EPERM; - if (error == 0) - error = copy_from_user(&sc->hdlc_settings, - ifr->ifr_settings.ifs_ifsu.sync, size); - /* hdlc_settings are currently ignored. */ - break; - } - default: /* Pass the rest to the line protocol code. */ - { - error = hdlc_ioctl(net_dev, ifr, cmd); - break; - } - } - } -# endif /* GEN_HDLC */ - else /* unknown IOCTL command */ - error = -EINVAL; + /* Leave the LEDs in the state they were in after power-on. */ + led_on(sc, MII16_LED_ALL); - if (DRIVER_DEBUG) - printk("%s: linux_ioctl; cmd=0x%08x error=%d\n", - NAME_UNIT, cmd, error); + /* Software reset the Tulip chip; stops DMA and Interrupts */ + WRITE_CSR(TLP_BUS_MODE, TLP_BUS_RESET); /* self-clearing */ + DELAY(5); /* Tulip is dead for 50 PCI cycles after reset. */ - return error; - } + /* Disconnect from the PCI bus except for config cycles. */ + /* Hmmm; Linux syslogs a warning that IO and MEM are disabled. */ + WRITE_PCI_CFG(sc, TLP_CFCS, TLP_CFCS_MEM_ENABLE | TLP_CFCS_IO_ENABLE); -/* This net_device method returns a pointer to device statistics. */ -static struct net_device_stats * -linux_stats(struct net_device *net_dev) - { -# if GEN_HDLC - return &dev_to_hdlc(net_dev)->stats; -# else - softc_t *sc = net_dev->priv; - return &sc->net_stats; -# endif + /* Free the DMA descriptor rings. */ + destroy_ring(sc, &sc->txring); + destroy_ring(sc, &sc->rxring); } -/* Called from a softirq once a second. */ -static void -linux_watchdog(unsigned long softc) +/* Start the card and attach a kernel interface and line protocol. */ +static int +attach_card(softc_t *sc, const char *intrstr) { - softc_t *sc = (softc_t *)softc; - u_int8_t old_oper_status = sc->status.oper_status; - struct event_cntrs *cntrs = &sc->status.cntrs; - struct net_device_stats *stats = linux_stats(sc->net_dev); - - core_watchdog(sc); /* updates oper_status */ - - /* Notice change in link status. */ - if ((old_oper_status != STATUS_UP) && - (sc->status.oper_status == STATUS_UP)) /* link came up */ - { - hdlc_set_carrier(1, sc->net_dev); - netif_wake_queue(sc->net_dev); - } - if ((old_oper_status == STATUS_UP) && - (sc->status.oper_status != STATUS_UP)) /* link went down */ - { - hdlc_set_carrier(0, sc->net_dev); - netif_stop_queue(sc->net_dev); - } + struct config config; + u_int32_t tlp_cfrv; + u_int16_t mii3; + u_int8_t *ieee; + int i, error = 0; - /* Notice change in line protocol. */ - if (sc->config.line_pkg == PKG_RAWIP) - { - sc->status.line_pkg = PKG_RAWIP; - sc->status.line_prot = PROT_IP_HDLC; - } -# if GEN_HDLC - else - { - sc->status.line_pkg = PKG_GEN_HDLC; - switch (sc->hdlc_dev->proto.id) - { - case IF_PROTO_PPP: - sc->status.line_prot = PROT_PPP; - break; - case IF_PROTO_CISCO: - sc->status.line_prot = PROT_C_HDLC; - break; - case IF_PROTO_FR: - sc->status.line_prot = PROT_FRM_RLY; - break; - case IF_PROTO_HDLC: - sc->status.line_prot = PROT_IP_HDLC; - break; - case IF_PROTO_X25: - sc->status.line_prot = PROT_X25; - break; - case IF_PROTO_HDLC_ETH: - sc->status.line_prot = PROT_ETH_HDLC; - break; - default: - sc->status.line_prot = 0; - break; - } - } -# endif /* GEN_HDLC */ - - /* Copy statistics from sc to net_dev for get_stats(). */ - stats->rx_packets = cntrs->ipackets; - stats->tx_packets = cntrs->opackets; - stats->rx_bytes = cntrs->ibytes; - stats->tx_bytes = cntrs->obytes; - stats->rx_errors = cntrs->ierrors; - stats->tx_errors = cntrs->oerrors; - stats->rx_dropped = cntrs->idiscards; - stats->tx_dropped = cntrs->odiscards; - stats->rx_fifo_errors = cntrs->fifo_over; - stats->tx_fifo_errors = cntrs->fifo_under; - stats->rx_missed_errors = cntrs->missed; - stats->rx_over_errors = cntrs->overruns; + /* Start the card. */ + if ((error = startup_card(sc))) return error; - /* Call this procedure again after one second. */ - sc->wd_timer.expires = jiffies + HZ; /* now plus one second */ - add_timer(&sc->wd_timer); - } + callout_init(&sc->callout, 0); -/* This is the I/O configuration interface for Linux. */ + /* Attach a kernel interface. */ +#if NETGRAPH + if ((error = ng_attach(sc))) return error; + sc->flags |= FLAG_NETGRAPH; +#endif + if ((error = lmc_ifnet_attach(sc))) return error; + sc->flags |= FLAG_IFNET; -/* This net_device method is called when IFF_UP goes false. */ -static int -linux_stop(struct net_device *net_dev) - { - softc_t *sc = dev_to_hdlc(net_dev)->priv; + /* Attach a line protocol stack. */ + sc->config.line_pkg = PKG_RAWIP; + config = sc->config; /* get current config */ + config.line_pkg = 0; /* select external stack */ + config.line_prot = PROT_C_HDLC; + config.keep_alive = 1; + config_proto(sc, &config); /* reconfigure */ + sc->config = config; /* save new configuration */ - /* Stop the card and detach from the kernel. */ - detach_card(sc); /* doesn't fail */ + /* Print interesting hardware-related things. */ + mii3 = read_mii(sc, 3); + tlp_cfrv = READ_PCI_CFG(sc, TLP_CFRV); + printf("%s: PCI rev %d.%d, MII rev %d.%d", NAME_UNIT, + (tlp_cfrv>>4) & 0xF, tlp_cfrv & 0xF, (mii3>>4) & 0xF, mii3 & 0xF); + ieee = (u_int8_t *)sc->status.ieee; + for (i=0; i<3; i++) sc->status.ieee[i] = read_srom(sc, 10+i); + printf(", IEEE addr %02x:%02x:%02x:%02x:%02x:%02x", + ieee[0], ieee[1], ieee[2], ieee[3], ieee[4], ieee[5]); + sc->card->ident(sc); + printf(" %s\n", intrstr); - free_irq(net_dev->irq, net_dev); /* doesn't fail */ + /* Print interesting software-related things. */ + printf("%s: Driver rev %d.%d.%d", NAME_UNIT, + DRIVER_MAJOR_VERSION, DRIVER_MINOR_VERSION, DRIVER_SUB_VERSION); + printf(", Options %s%s%s%s%s%s%s%s%s\n", + NETGRAPH ? "NETGRAPH " : "", GEN_HDLC ? "GEN_HDLC " : "", + NSPPP ? "SPPP " : "", P2P ? "P2P " : "", + ALTQ_PRESENT ? "ALTQ " : "", NBPFILTER ? "BPF " : "", + DEV_POLL ? "POLL " : "", IOREF_CSR ? "IO_CSR " : "MEM_CSR ", + (BYTE_ORDER == BIG_ENDIAN) ? "BIG_END " : "LITTLE_END "); - del_timer(&sc->wd_timer); /* return value ignored */ + /* Make the local hardware ready. */ + set_status(sc, 1); return 0; } -/* This net_device method is called when IFF_UP goes true. */ -static int -linux_open(struct net_device *net_dev) +/* Detach from the kernel in all ways. */ +static void +detach_card(softc_t *sc) { - softc_t *sc = dev_to_hdlc(net_dev)->priv; - int error; + struct config config; - /* Allocate PCI interrupt resources for the card. */ - if ((error = request_irq(net_dev->irq, &linux_interrupt, SA_SHIRQ, - NAME_UNIT, net_dev))) + /* Make the local hardware NOT ready. */ + set_status(sc, 0); + + /* Detach external line protocol stack. */ + if (sc->config.line_pkg != PKG_RAWIP) { - printk("%s: request_irq() failed; error %d\n", NAME_UNIT, error); - return error; + config = sc->config; + config.line_pkg = PKG_RAWIP; + config_proto(sc, &config); + sc->config = config; } - /* Arrange to call linux_watchdog() once a second. */ - init_timer(&sc->wd_timer); - sc->wd_timer.expires = jiffies + HZ; /* now plus one second */ - sc->wd_timer.function = &linux_watchdog; - sc->wd_timer.data = (unsigned long) sc; - add_timer(&sc->wd_timer); - - /* Start the card and attach a kernel interface and line protocol. */ - if ((error = -attach_card(sc, ""))) - linux_stop(net_dev); - else + /* Detach kernel interfaces. */ +#if NETGRAPH + if (sc->flags & FLAG_NETGRAPH) + { + IFQ_PURGE(&sc->ng_fastq); + IFQ_PURGE(&sc->ng_sndq); + ng_detach(sc); + sc->flags &= ~FLAG_NETGRAPH; + } +#endif + if (sc->flags & FLAG_IFNET) { - net_dev->weight = sc->rxring.num_descs; /* input flow control */ - netif_start_queue(net_dev); /* output flow control */ + IFQ_PURGE(&sc->ifp->if_snd); + lmc_ifnet_detach(sc); + sc->flags &= ~FLAG_IFNET; } - return error; + /* Reset the Tulip chip; stops DMA and Interrupts. */ + shutdown_card(sc); } -# if GEN_HDLC -static int -hdlc_attach(struct net_device *net_dev, - unsigned short encoding, unsigned short parity) - { return 0; } -# endif - -/* This pci_driver method is called during shutdown or module-unload. */ -/* This is called from user context; can sleep; no spinlocks! */ -static void __exit -linux_remove(struct pci_dev *pci_dev) - { - struct net_device *net_dev = (struct net_device *)pci_get_drvdata(pci_dev); - softc_t *sc = dev_to_hdlc(net_dev)->priv; - - if (net_dev == NULL) return; - - /* Assume that linux_stop() has already been called. */ - if (sc->flags & FLAG_NETDEV) -# if GEN_HDLC - unregister_hdlc_device(net_dev); -# else - unregister_netdev(net_dev); -# endif - -# if (IOREF_CSR == 0) - if (sc->csr_membase != NULL) - iounmap(sc->csr_membase); -# endif - - pci_disable_device(pci_dev); - - if (sc->csr_iobase != 0) - pci_release_regions(pci_dev); - - pci_set_drvdata(pci_dev, NULL); - - kfree(sc); - free_netdev(net_dev); - } +/* This is the I/O configuration interface for FreeBSD */ -static void -setup_netdev(struct net_device *net_dev) - { - /* Initialize the generic network device. */ - /* Note similarity to BSD's lmc_ifnet_attach(). */ - net_dev->flags = IFF_POINTOPOINT; - net_dev->flags |= IFF_RUNNING; - net_dev->open = linux_open; - net_dev->stop = linux_stop; - net_dev->hard_start_xmit = linux_start; - net_dev->do_ioctl = linux_ioctl; - net_dev->get_stats = linux_stats; - net_dev->tx_timeout = linux_timeout; - net_dev->poll = linux_poll; - net_dev->watchdog_timeo = 1 * HZ; - net_dev->tx_queue_len = SNDQ_MAXLEN; - net_dev->mtu = MAX_DESC_LEN; - net_dev->type = ARPHRD_RAWHDLC; -/* The receiver generates frag-lists for packets >4032 bytes. */ -/* The transmitter accepts scatter/gather lists and frag-lists. */ -/* However Linux linearizes outgoing packets since our hardware */ -/* doesn't compute soft checksums. All that work for nothing! */ -/*net_dev->features |= NETIF_F_SG; */ -/*net_dev->features |= NETIF_F_FRAGLIST; */ - } -/* This pci_driver method is called during boot or module-load. */ -/* This is called from user context; can sleep; no spinlocks! */ -static int __init -linux_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) +static int +fbsd_probe(device_t dev) { - u_int32_t cfid, csid; - struct net_device *net_dev; - softc_t *sc; - int error; + u_int32_t cfid = pci_read_config(dev, TLP_CFID, 4); + u_int32_t csid = pci_read_config(dev, TLP_CSID, 4); /* Looking for a DEC 21140A chip on any Lan Media Corp card. */ - pci_read_config_dword(pci_dev, TLP_CFID, &cfid); - if (cfid != TLP_CFID_TULIP) return -ENXIO; - pci_read_config_dword(pci_dev, TLP_CSID, &csid); + if (cfid != TLP_CFID_TULIP) return ENXIO; switch (csid) { case TLP_CSID_HSSI: case TLP_CSID_HSSIc: + device_set_desc(dev, HSSI_DESC); + break; case TLP_CSID_T3: + device_set_desc(dev, T3_DESC); + break; case TLP_CSID_SSI: + device_set_desc(dev, SSI_DESC); + break; case TLP_CSID_T1E1: + device_set_desc(dev, T1E1_DESC); break; default: - return -ENXIO; - } - - /* Declare that these cards use 32-bit single-address PCI cycles. */ - if ((error = pci_set_dma_mask(pci_dev, DMA_32BIT_MASK))) - { - printk("%s: pci_set_dma_mask() failed; error %d\n", DEVICE_NAME, error); - return error; + return ENXIO; } - pci_set_consistent_dma_mask(pci_dev, DMA_32BIT_MASK); /* can't fail */ + return 0; + } -# if GEN_HDLC /* generic-hdlc line protocols */ +static int +fbsd_detach(device_t dev) + { + softc_t *sc = device_get_softc(dev); - /* device driver instance data, aka Soft Context or sc */ - if ((sc = kmalloc(sizeof(softc_t), GFP_KERNEL)) == NULL) - { - printk("%s: kmalloc() failed\n", DEVICE_NAME); - return -ENOMEM; - } - memset(sc, 0, sizeof(softc_t)); + /* Stop the card and detach from the kernel. */ + detach_card(sc); - /* Allocate space for the HDLC network device struct. */ - if ((net_dev = alloc_hdlcdev(sc)) == NULL) + /* Release resources. */ + if (sc->irq_cookie != NULL) { - printk("%s: alloc_hdlcdev() failed\n", DEVICE_NAME); - kfree(sc); - return -ENOMEM; + bus_teardown_intr(dev, sc->irq_res, sc->irq_cookie); + sc->irq_cookie = NULL; } - - /* Initialize the network device struct. */ - setup_netdev(net_dev); - - /* Initialize the HDLC extension to the network device. */ - sc->hdlc_dev = dev_to_hdlc(net_dev); - sc->hdlc_dev->attach = hdlc_attach; /* noop for this driver */ - sc->hdlc_dev->xmit = linux_start; /* the REAL hard_start_xmit() */ - -# else /* GEN_HDLC */ /* no line protocol. */ - - /* Allocate space for the bare network device struct. */ - net_dev = alloc_netdev(sizeof(softc_t), DEVICE_NAME"%d", setup_netdev); - if (net_dev == NULL) + if (sc->irq_res != NULL) { - printk("%s: alloc_netdev() failed\n", DEVICE_NAME); - return -ENOMEM; + bus_release_resource(dev, SYS_RES_IRQ, sc->irq_res_id, sc->irq_res); + sc->irq_res = NULL; } - /* device driver instance data, aka Soft Context or sc */ - sc = net_dev->priv; - -# endif /* GEN_HDLC */ - - sc->net_dev = net_dev; /* NAME_UNIT macro needs this */ - sc->pci_dev = pci_dev; /* READ/WRITE_PCI_CFG macros need this */ - - /* Cross-link pci_dev and net_dev. */ - pci_set_drvdata(pci_dev, net_dev); /* pci_dev->driver_data = net_dev */ - SET_NETDEV_DEV(net_dev, &pci_dev->dev); /* net_dev->class_dev.dev = &pci_dev->dev */ - SET_MODULE_OWNER(net_dev); /* ??? NOOP in linux-2.6.3. ??? */ - - /* Sets cfcs.io and cfcs.mem; sets pci_dev->irq based on cfit.int */ - if ((error = pci_enable_device(pci_dev))) + if (sc->csr_res != NULL) { - printk("%s: pci_enable_device() failed; error %d\n", DEVICE_NAME, error); - linux_remove(pci_dev); - return error; + bus_release_resource(dev, sc->csr_res_type, sc->csr_res_id, sc->csr_res); + sc->csr_res = NULL; } - net_dev->irq = pci_dev->irq; /* linux_open/stop need this */ - /* Allocate PCI memory and IO resources to access the Tulip chip CSRs. */ - if ((error = pci_request_regions(pci_dev, DEVICE_NAME))) - { - printk("%s: pci_request_regions() failed; error %d\n", DEVICE_NAME, error); - linux_remove(pci_dev); - return error; - } - net_dev->base_addr = pci_resource_start(pci_dev, 0); - net_dev->mem_start = pci_resource_start(pci_dev, 1); - net_dev->mem_end = pci_resource_end(pci_dev, 1); - sc->csr_iobase = net_dev->base_addr; - -# if (IOREF_CSR == 0) - sc->csr_membase = ioremap_nocache(net_dev->mem_start, TLP_CSR_SIZE); - if (sc->csr_membase == NULL) - { - printk("%s: ioremap_nocache() failed\n", DEVICE_NAME); - linux_remove(pci_dev); - return -EFAULT; - } -# endif + mtx_destroy(&sc->top_mtx); + mtx_destroy(&sc->bottom_mtx); + return 0; /* no error */ + } - /* Sets cfcs.master, enabling PCI DMA; checks latency timer value. */ - pci_set_master(pci_dev); /* Later, attach_card() does this too. */ +static int +fbsd_shutdown(device_t dev) + { + shutdown_card(device_get_softc(dev)); + return 0; + } - /* Initialize the top-half and bottom-half locks. */ - /* Top_lock must be initialized before net_dev is registered. */ - init_MUTEX(&sc->top_lock); - spin_lock_init(&sc->bottom_lock); +static int +fbsd_attach(device_t dev) + { + softc_t *sc = device_get_softc(dev); + int error; -# if GEN_HDLC - if ((error = register_hdlc_device(net_dev))) - { - printk("%s: register_hdlc_device() failed; error %d\n", DEVICE_NAME, error); - linux_remove(pci_dev); - return error; - } -# else - if ((error = register_netdev(net_dev))) - { - printk("%s: register_netdev() failed; error %d\n", DEVICE_NAME, error); - linux_remove(pci_dev); - return error; - } -# endif - /* The NAME_UNIT macro now works. Use DEVICE_NAME before this. */ - sc->flags |= FLAG_NETDEV; + /* READ/WRITE_PCI_CFG need this. */ + sc->dev = dev; /* What kind of card are we driving? */ switch (READ_PCI_CFG(sc, TLP_CSID)) { case TLP_CSID_HSSI: case TLP_CSID_HSSIc: - sc->dev_desc = HSSI_DESC; - sc->card = &hssi_card; + sc->card = &hssi_card; break; case TLP_CSID_T3: - sc->dev_desc = T3_DESC; - sc->card = &t3_card; + sc->card = &t3_card; break; case TLP_CSID_SSI: - sc->dev_desc = SSI_DESC; - sc->card = &ssi_card; + sc->card = &ssi_card; break; case TLP_CSID_T1E1: - sc->dev_desc = T1E1_DESC; - sc->card = &t1_card; + sc->card = &t1_card; break; - default: /* shouldn't happen! */ - linux_remove(pci_dev); - return -ENXIO; + default: + return ENXIO; + } + sc->dev_desc = device_get_desc(dev); + + /* Allocate PCI memory or IO resources to access the Tulip chip CSRs. */ +# if IOREF_CSR + sc->csr_res_id = TLP_CBIO; + sc->csr_res_type = SYS_RES_IOPORT; +# else + sc->csr_res_id = TLP_CBMA; + sc->csr_res_type = SYS_RES_MEMORY; +# endif + sc->csr_res = bus_alloc_resource(dev, sc->csr_res_type, &sc->csr_res_id, + 0, ~0, 1, RF_ACTIVE); + if (sc->csr_res == NULL) + { + printf("%s: bus_alloc_resource(csr) failed.\n", NAME_UNIT); + return ENXIO; + } + sc->csr_tag = rman_get_bustag(sc->csr_res); + sc->csr_handle = rman_get_bushandle(sc->csr_res); + + /* Allocate PCI interrupt resources for the card. */ + sc->irq_res_id = 0; + sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_res_id, + 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); + if (sc->irq_res == NULL) + { + printf("%s: bus_alloc_resource(irq) failed.\n", NAME_UNIT); + fbsd_detach(dev); + return ENXIO; + } + if ((error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE, + NULL, bsd_interrupt, sc, &sc->irq_cookie))) + { + printf("%s: bus_setup_intr() failed; error %d\n", NAME_UNIT, error); + fbsd_detach(dev); + return error; } - /* Announce the hardware on the console. */ - printk("%s: <%s> io 0x%04lx/9 mem 0x%08lx/25 rom 0x%08lx/14 irq %d pci %s\n", - NAME_UNIT, sc->dev_desc, pci_resource_start(pci_dev, 0), - pci_resource_start(pci_dev, 1), pci_resource_start(pci_dev, 6), - pci_dev->irq, pci_name(pci_dev)); + /* Initialize the top-half and bottom-half locks. */ + mtx_init(&sc->top_mtx, NAME_UNIT, "top half lock", MTX_DEF); + mtx_init(&sc->bottom_mtx, NAME_UNIT, "bottom half lock", MTX_DEF); - return 0; + /* Start the card and attach a kernel interface and line protocol. */ + if ((error = attach_card(sc, ""))) detach_card(sc); + return error; } -/* This pci driver knows how to drive these devices: */ -static __initdata struct pci_device_id pci_device_id_tbl[] = +static device_method_t methods[] = { - /* Looking for a DEC 21140A chip on any Lan Media Corp card. */ - { 0x1011, 0x0009, 0x1376, PCI_ANY_ID, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0 } + DEVMETHOD(device_probe, fbsd_probe), + DEVMETHOD(device_attach, fbsd_attach), + DEVMETHOD(device_detach, fbsd_detach), + DEVMETHOD(device_shutdown, fbsd_shutdown), + /* This driver does not suspend and resume. */ + { 0, 0 } }; -MODULE_DEVICE_TABLE(pci, pci_device_id_tbl); -static struct pci_driver pci_driver = +static driver_t driver = { - .name = DEVICE_NAME, - .id_table = pci_device_id_tbl, - .probe = linux_probe, - .remove = __devexit_p(linux_remove), - /* This driver does not suspend and resume. */ + .name = DEVICE_NAME, + .methods = methods, + .size = sizeof(softc_t), }; -/* This ultimately calls our pci_driver.probe() method. */ -static int __init linux_modload(void) - { return pci_module_init(&pci_driver); } -module_init(linux_modload); +static devclass_t devclass; + +DRIVER_MODULE(lmc, pci, driver, devclass, 0, 0); +MODULE_VERSION(lmc, 2); +MODULE_DEPEND(lmc, pci, 1, 1, 1); +# if NETGRAPH +MODULE_DEPEND(lmc, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); +# endif +# if NSPPP +MODULE_DEPEND(lmc, sppp, 1, 1, 1); +# endif + + +/* This is the I/O configuration interface for NetBSD. */ + -/* This ultimately calls our pci_driver.remove() method. */ -static void __exit linux_modunload(void) - { pci_unregister_driver(&pci_driver); } -module_exit(linux_modunload); +/* This is the I/O configuration interface for OpenBSD. */ + + +/* This is the I/O configuration interface for BSD/OS. */ -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_DESCRIPTION("Device driver for SBE/LMC Wide-Area Network cards"); -MODULE_AUTHOR("David Boggs "); -#endif /* __linux__ */ diff --git a/sys/dev/lmc/if_lmc.h b/sys/dev/lmc/if_lmc.h index e89c739..fe4e7d0 100644 --- a/sys/dev/lmc/if_lmc.h +++ b/sys/dev/lmc/if_lmc.h @@ -620,13 +620,6 @@ # define LMCIOCREAD _IOWR('i', 243, struct ioctl) # define LMCIOCWRITE _IOW('i', 244, struct ioctl) # define LMCIOCTL _IOWR('i', 245, struct ioctl) -#elif defined(__linux__) /* sigh */ -# define LMCIOCGSTAT SIOCDEVPRIVATE+0 -# define LMCIOCGCFG SIOCDEVPRIVATE+1 -# define LMCIOCSCFG SIOCDEVPRIVATE+2 -# define LMCIOCREAD SIOCDEVPRIVATE+3 -# define LMCIOCWRITE SIOCDEVPRIVATE+4 -# define LMCIOCTL SIOCDEVPRIVATE+5 #endif struct iohdr /* all LMCIOCs begin with this */ @@ -984,12 +977,8 @@ struct dma_desc #endif u_int32_t address1; /* buffer1 bus address */ u_int32_t address2; /* buffer2 bus address */ -#if (defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) bus_dmamap_t map; /* bus dmamap for this descriptor */ # define TLP_BUS_DSL_VAL (sizeof(bus_dmamap_t) & TLP_BUS_DSL) -#else -# define TLP_BUS_DSL_VAL 0 -#endif } __attribute__ ((packed)); /* Tulip DMA descriptor status bits */ @@ -1029,18 +1018,13 @@ struct desc_ring u_int32_t dma_addr; /* bus address for desc array */ int size_descs; /* bus_dmamap_sync needs this */ int num_descs; /* used to set rx quota */ -#ifdef __linux__ - struct sk_buff *head; /* tail-queue of skbuffs */ - struct sk_buff *tail; -#elif BSD +#if BSD struct mbuf *head; /* tail-queue of mbufs */ struct mbuf *tail; -# if (defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) bus_dma_tag_t tag; /* bus_dma tag for desc array */ bus_dmamap_t map; /* bus_dma map for desc array */ bus_dma_segment_t segs[2]; /* bus_dmamap_load() or bus_dmamem_alloc() */ int nsegs; /* bus_dmamap_load() or bus_dmamem_alloc() */ -# endif #endif }; @@ -1085,33 +1069,7 @@ struct card /* FreeBSD wants struct ifnet first in the softc. */ struct softc { -#if (defined(__NetBSD__) || defined(__OpenBSD__)) - struct device dev; /* base device -- must be first in softc */ - pcitag_t pa_tag; /* pci_conf_read/write need this */ - pci_chipset_tag_t pa_pc; /* pci_conf_read/write need this */ - bus_dma_tag_t pa_dmat; /* bus_dma needs this */ - bus_space_tag_t csr_tag; /* bus_space needs this */ - bus_space_handle_t csr_handle;/* bus_space needs this */ - pci_intr_handle_t intr_handle;/* interrupt handle */ - void *irq_cookie; /* pci_intr_disestablish needs this */ - void *sdh_cookie; /* shutdownhook_disestablish needs this */ - struct simplelock top_lock; /* lock card->watchdog vs core_ioctl */ - struct simplelock bottom_lock;/* lock for buf queues & descriptor rings */ - struct mbuf *tx_mbuf; /* hang mbuf here while building dma descs */ -#endif /* __NetBSD__ || __OpenBSD__ */ - -#ifdef __bsdi__ - struct device dev; /* base device -- must be first in softc */ - struct isadev id; /* bus resource */ - struct intrhand ih; /* interrupt vectoring */ - struct atshutdown ats; /* shutdown hook */ - pci_devaddr_t cfgbase; /* base address of PCI config regs */ - u_int16_t csr_iobase; /* io base address of Tulip CSRs */ - u_int32_t *csr_membase; /* kv mem base address of Tulip CSRs */ - struct simplelock top_lock; /* lock card->watchdog vs core_ioctl */ - struct simplelock bottom_lock;/* lock for buf queues & descriptor rings */ - struct mbuf *tx_mbuf; /* hang mbuf here while building dma descs */ -#endif /* __bsdi__ */ + /* State for kernel-resident Line Protocols */ #if IFNET @@ -1130,14 +1088,6 @@ struct softc # endif #endif -#ifdef __linux__ -# if GEN_HDLC - hdlc_device *hdlc_dev; /* state for HDLC code */ - sync_serial_settings hdlc_settings; /* state set by sethdlc program */ -# else - struct net_device_stats net_stats; /* linux_stats storage */ -# endif -#endif #if NETGRAPH node_p ng_node; /* pointer to our node struct */ @@ -1151,7 +1101,6 @@ struct softc # endif #endif -#ifdef __FreeBSD__ struct callout callout; /* watchdog needs this */ struct device *dev; /* base device pointer */ bus_space_tag_t csr_tag; /* bus_space needs this */ @@ -1173,19 +1122,7 @@ struct softc int top_spl; /* lock card->watchdog vs core_ioctl */ int bottom_spl; /* lock for buf queues & descriptor rings */ # endif -#endif /* __FreeBSD__ */ - -#ifdef __linux__ - struct pci_dev *pci_dev; /* READ/WRITE_PCI_CFG macros need this */ - struct net_device *net_dev; /* NAME_UNIT macro needs this */ - struct timer_list wd_timer; /* timer calls watchdog() once a second */ - u_int32_t csr_iobase; /* io base address of Tulip CSRs */ - void *csr_membase; /* kv mem base address of Tulip CSRs */ - struct sk_buff *tx_skb; /* hang skb here while building dma descs */ - int quota; /* used for incoming packet flow control */ - struct semaphore top_lock; /* lock card->watchdog vs core_ioctl */ - spinlock_t bottom_lock; /* lock for buf queues & descriptor rings */ -#endif /* __linux__ */ + /* Top-half state used by all card types; lock with top_lock, */ const char *dev_desc; /* string describing type of board */ @@ -1210,7 +1147,6 @@ struct softc /* Hide the minor differences between OS versions */ -#ifdef __FreeBSD__ typedef void intr_return_t; # define READ_PCI_CFG(sc, addr) pci_read_config ((sc)->dev, addr, 4) # define WRITE_PCI_CFG(sc, addr, data) pci_write_config((sc)->dev, addr, data, 4) @@ -1264,162 +1200,10 @@ struct softc # if (__FreeBSD_version >= 600000) # define IFF_RUNNING IFF_DRV_RUNNING # endif -#endif /* __FreeBSD__ */ -#ifdef __NetBSD__ - typedef int intr_return_t; -# define READ_PCI_CFG(sc, addr) pci_conf_read ((sc)->pa_pc, (sc)->pa_tag, addr) -# define WRITE_PCI_CFG(sc, addr, data) pci_conf_write((sc)->pa_pc, (sc)->pa_tag, addr, data) -# define READ_CSR(csr) bus_space_read_4 (sc->csr_tag, sc->csr_handle, csr) -# define WRITE_CSR(csr, val) bus_space_write_4(sc->csr_tag, sc->csr_handle, csr, val) -# define NAME_UNIT sc->dev.dv_xname -# define DRIVER_DEBUG ((sc->config.debug) || (sc->ifp->if_flags & IFF_DEBUG)) -# define TOP_TRYLOCK simple_lock_try(&sc->top_lock) -# define TOP_UNLOCK simple_unlock (&sc->top_lock) -# define BOTTOM_TRYLOCK simple_lock_try(&sc->bottom_lock) -# define BOTTOM_UNLOCK simple_unlock (&sc->bottom_lock) -# define CHECK_CAP suser(curproc->p_ucred, &curproc->p_acflag) -# define DISABLE_INTR int spl = splnet() -# define ENABLE_INTR splx(spl) -# define IRQ_NONE 0 -# define IRQ_HANDLED 1 -# define IFP2SC(ifp) (ifp)->if_softc -# define COPY_BREAK MHLEN -# define SLEEP(usecs) tsleep(sc, PCATCH | PZERO, DEVICE_NAME, 1+(usecs/tick)) -# define DMA_SYNC(map, size, flags) bus_dmamap_sync(ring->tag, map, 0, size, flags) -# define DMA_LOAD(map, addr, size) bus_dmamap_load(ring->tag, map, addr, size, 0, BUS_DMA_NOWAIT) -# if (NBPFILTER != 0) -# define LMC_BPF_MTAP(mbuf) if (sc->ifp->if_bpf) bpf_mtap(sc->ifp->if_bpf, mbuf) -# define LMC_BPF_ATTACH(dlt, len) bpfattach(sc->ifp, dlt, len) -# define LMC_BPF_DETACH bpfdetach(sc->ifp) -# endif -#endif /* __NetBSD__ */ -#ifdef __OpenBSD__ - typedef int intr_return_t; -# define READ_PCI_CFG(sc, addr) pci_conf_read ((sc)->pa_pc, (sc)->pa_tag, addr) -# define WRITE_PCI_CFG(sc, addr, data) pci_conf_write((sc)->pa_pc, (sc)->pa_tag, addr, data) -# define READ_CSR(csr) bus_space_read_4 (sc->csr_tag, sc->csr_handle, csr) -# define WRITE_CSR(csr, val) bus_space_write_4(sc->csr_tag, sc->csr_handle, csr, val) -# define NAME_UNIT sc->dev.dv_xname -# define DRIVER_DEBUG ((sc->config.debug) || (sc->ifp->if_flags & IFF_DEBUG)) -# define TOP_TRYLOCK simple_lock_try(&sc->top_lock) -# define TOP_UNLOCK simple_unlock (&sc->top_lock) -# define BOTTOM_TRYLOCK simple_lock_try(&sc->bottom_lock) -# define BOTTOM_UNLOCK simple_unlock (&sc->bottom_lock) -# define CHECK_CAP suser(curproc, 0) -# define DISABLE_INTR int spl = splnet() -# define ENABLE_INTR splx(spl) -# define IRQ_NONE 0 -# define IRQ_HANDLED 1 -# define IFP2SC(ifp) (ifp)->if_softc -# define COPY_BREAK MHLEN -# define SLEEP(usecs) tsleep(sc, PCATCH | PZERO, DEVICE_NAME, 1+(usecs/tick)) -# define DMA_SYNC(map, size, flags) bus_dmamap_sync(ring->tag, map, 0, size, flags) -# define DMA_LOAD(map, addr, size) bus_dmamap_load(ring->tag, map, addr, size, 0, BUS_DMA_NOWAIT) -# if (NBPFILTER != 0) -# define LMC_BPF_MTAP(mbuf) if (sc->ifp->if_bpf) bpf_mtap(sc->ifp->if_bpf, mbuf) -# define LMC_BPF_ATTACH(dlt, len) bpfattach(&sc->ifp->if_bpf, sc->ifp, dlt, len) -# define LMC_BPF_DETACH bpfdetach(sc->ifp) -# endif -#endif /* __OpenBSD__ */ - -#ifdef __bsdi__ - typedef int intr_return_t; -# define READ_PCI_CFG(sc, addr) pci_inl(&(sc)->cfgbase, addr) -# define WRITE_PCI_CFG(sc, addr, data) pci_outl(&(sc)->cfgbase, addr, data) -# if IOREF_CSR -# define READ_CSR(csr) inl(sc->csr_iobase+(csr)) -# define WRITE_CSR(csr, val) outl(sc->csr_iobase+(csr), (val)) -# else -# error Memory refs to Tulip CSRs cause page faults in BSD/OS -# define READ_CSR(csr) (0 + *(sc->csr_membase+(csr))) -# define WRITE_CSR(csr, val) ((void)(*(sc->csr_membase+(csr)) = (val))) -# endif -# define NAME_UNIT sc->dev.dv_xname -# define DRIVER_DEBUG ((sc->config.debug) || (sc->ifp->if_flags & IFF_DEBUG)) -# define TOP_TRYLOCK simple_lock_try(&sc->top_lock) -# define TOP_UNLOCK simple_unlock (&sc->top_lock) -# define BOTTOM_TRYLOCK simple_lock_try(&sc->bottom_lock) -# define BOTTOM_UNLOCK simple_unlock (&sc->bottom_lock) -# define CHECK_CAP suser(PCPU(curproc)->p_ucred, &PCPU(curproc)->p_acflag) -# define DISABLE_INTR int spl = splimp() -# define ENABLE_INTR splx(spl) -# define IRQ_NONE 1 /* XXX 0 */ -# define IRQ_HANDLED 1 -# define IFP2SC(ifp) (ifp)->if_softc -# define COPY_BREAK MHLEN -# define SLEEP(usecs) tsleep(sc, PCATCH | PZERO, DEVICE_NAME, 1+(usecs/tick)) -# define DMA_SYNC(map, size, flags) /* nothing */ -# define DMA_LOAD(map, addr, size) 0 -# define bus_dmamap_unload(tag, map) /* nothing */ -# define bus_dmamap_destroy(tag, map) /* nothing */ -# if (NBPFILTER != 0) -# define LMC_BPF_MTAP(mbuf) if (sc->ifp->if_bpf) bpf_mtap(sc->ifp->if_bpf, mbuf) -# define LMC_BPF_ATTACH(dlt, len) bpfattach(&sc->ifp->if_bpf, sc->ifp, dlt, len) -# define LMC_BPF_DETACH /* bpfdetach(sc->ifp) */ -# endif -# define memcpy(dst, src, len) bcopy(src, dst, len) -# define if_detach(ifp) /* nothing */ - -/* BSD/OS-4.1 doesn't have a back pointer to softc in struct ifnet, */ -/* and it passes a unit number not a struct ifnet* to watchdog. */ -# if (_BSDI_VERSION <= 199910) - extern struct cfdriver lmccd; -# undef IFP2SC -# define UNIT2SC(unit) ((softc_t *)lmccd.cd_devs[unit]) -# define IFP2SC(ifp) (UNIT2SC((ifp)->if_unit)) -# endif -#endif /* __bsdi__ */ -#ifdef __linux__ -static u_int32_t /* inline? so rare it doesn't matter */ -READ_PCI_CFG(softc_t *sc, u_int32_t addr) - { - u_int32_t data; - pci_read_config_dword(sc->pci_dev, addr, &data); - return data; - } -# define WRITE_PCI_CFG(sc, addr, data) pci_write_config_dword(sc->pci_dev, addr, data) -# if IOREF_CSR -# define READ_CSR(csr) inl((sc->csr_iobase+(csr))) -# define WRITE_CSR(csr, val) outl((val),(sc->csr_iobase+(csr))) -# else -# define READ_CSR(csr) readl((sc->csr_membase+(csr))) -# define WRITE_CSR(csr, val) writel((val),(sc->csr_membase+(csr))) -# endif -# define NAME_UNIT sc->net_dev->name -# define DRIVER_DEBUG ((sc->config.debug) || (sc->net_dev->flags & IFF_DEBUG)) -# define TOP_TRYLOCK ((down_trylock(&sc->top_lock)==0) ? 1:0) -# define TOP_UNLOCK up(&sc->top_lock) -# define BOTTOM_TRYLOCK spin_trylock_bh(&sc->bottom_lock) -# define BOTTOM_UNLOCK spin_unlock_bh(&sc->bottom_lock) -# define CHECK_CAP capable(CAP_NET_ADMIN)? 0 : -EPERM -# define DISABLE_INTR /* nothing */ -# define ENABLE_INTR /* nothing */ -# define COPY_BREAK 200 -# define DELAY(usecs) udelay(usecs) -# define SLEEP(usecs) do { set_current_state(TASK_INTERRUPTIBLE);\ - schedule_timeout(1+(usecs*HZ)/1000000UL); } while (0) -# define printf printk -# define copyin(u, k, len) copy_from_user(k, u, len) -# define microtime(time) do_gettimeofday(time) -# define malloc(len, t, f) kmalloc(len, GFP_KERNEL) -# define free(addr, t) kfree(addr) -# define LITTLE_ENDIAN 4321 -# define BIG_ENDIAN 1234 -# if defined(__LITTLE_ENDIAN) -# define BYTE_ORDER LITTLE_ENDIAN -# elif defined(__BIG_ENDIAN) -# define BYTE_ORDER BIG_ENDIAN -# else -# error "asm/byteorder.h is wrong" -# endif -# if (GEN_HDLC == 0) -# define dev_to_hdlc(net_dev) net_dev -# define hdlc_set_carrier(val, net_dev) /* nothing */ -# endif -#endif /* __linux__ */ + #if (NBPFILTER == 0) # define LMC_BPF_MTAP(mbuf) /* nothing */ @@ -1541,9 +1325,7 @@ static void lmc_raw_input(struct ifnet *, struct mbuf *); #if BSD static void mbuf_enqueue(struct desc_ring *, struct mbuf *); static struct mbuf* mbuf_dequeue(struct desc_ring *); -# ifdef __FreeBSD__ static void fbsd_dmamap_load(void *, bus_dma_segment_t *, int, int); -# endif static int create_ring(softc_t *, struct desc_ring *, int); static void destroy_ring(softc_t *, struct desc_ring *); static int rxintr_cleanup(softc_t *); @@ -1553,18 +1335,6 @@ static int txintr_setup_mbuf(softc_t *, struct mbuf *); static int txintr_setup(softc_t *); #endif /* BSD */ -#ifdef __linux__ -static void skbuff_enqueue(struct desc_ring *, struct sk_buff *); -static struct sk_buff* skbuff_dequeue(struct desc_ring *); -static int create_ring(softc_t *, struct desc_ring *, int); -static void destroy_ring(softc_t *, struct desc_ring *); -static int rxintr_cleanup(softc_t *); -static int rxintr_setup(softc_t *); -static int txintr_cleanup(softc_t *sc); -static int txintr_setup_frag(softc_t *, char *, int); -static int txintr_setup_skb(softc_t *, struct sk_buff *); -static int txintr_setup(softc_t *); -#endif /* __linux__ */ static void check_intr_status(softc_t *); static void core_interrupt(void *, int); @@ -1596,10 +1366,6 @@ static int lmc_ifnet_ioctl(struct ifnet *, u_long, caddr_t); static void lmc_ifnet_start(struct ifnet *); static int lmc_raw_output(struct ifnet *, struct mbuf *, const struct sockaddr *, struct route *); -# ifdef __OpenBSD__ -static int ifmedia_change(struct ifnet *); -static void ifmedia_status(struct ifnet *, struct ifmediareq *); -# endif /* __OpenBSD__ */ static void setup_ifnet(struct ifnet *); static int lmc_ifnet_attach(softc_t *); static void lmc_ifnet_detach(softc_t *); @@ -1638,52 +1404,14 @@ static void shutdown_card(void *); static int attach_card(softc_t *, const char *); static void detach_card(softc_t *); -#ifdef __FreeBSD__ static int fbsd_probe(device_t); static int fbsd_detach(device_t); static int fbsd_shutdown(device_t); static int fbsd_attach(device_t); -#endif /* __FreeBSD__ */ - -#ifdef __NetBSD__ -static int nbsd_match(struct device *t, struct cfdata *, void *); -static int nbsd_detach(struct device *, int); -static void nbsd_attach(struct device *, struct device *, void *); -static int lkm_nbsd_match(struct pci_attach_args *); -int if_lmc_lkmentry(struct lkm_table *, int, int); -#endif /* __NetBSD__ */ - -#ifdef __OpenBSD__ -static int obsd_match(struct device *, void *, void *); -static int obsd_detach(struct device *, int); -static void obsd_attach(struct device *, struct device *, void *); -int if_lmc_lkmentry(struct lkm_table *, int, int); -#endif /* __OpenBSD__ */ - -#ifdef __bsdi__ -static int bsdi_match(pci_devaddr_t *); -static int bsdi_probe(struct device *, struct cfdata *, void *); -static void bsdi_attach(struct device *, struct device *, void *); -#endif /* __bsdi__ */ - -#ifdef __linux__ -static irqreturn_t linux_interrupt(int, void *, struct pt_regs *); -static int linux_poll(struct net_device *, int *); -static int linux_start(struct sk_buff *, struct net_device *); -static void linux_timeout(struct net_device *); -static int linux_ioctl(struct net_device *, struct ifreq *, int); -static struct net_device_stats * linux_stats(struct net_device *); -static void linux_watchdog(unsigned long); -static int linux_stop(struct net_device *); -static int linux_open(struct net_device *); -# if GEN_HDLC -static int hdlc_attach(struct net_device *, - unsigned short, unsigned short); -# endif -static void __exit linux_remove(struct pci_dev *); -static void setup_netdev(struct net_device *); -static int __init linux_probe(struct pci_dev *, const struct pci_device_id *); -#endif /* __linux__ */ + + + + #endif /* KERNEL */ -- cgit v1.1