Re-organise lnc driver in preparation for newbusifying it.
This commit is contained in:
parent
14a8a54168
commit
9b55e84fec
|
@ -172,6 +172,8 @@ dev/isp/isp_freebsd.c optional isp
|
|||
dev/isp/isp_target.c optional isp
|
||||
dev/lmc/if_lmc.c optional lmc
|
||||
dev/lnc/if_lnc.c optional lnc
|
||||
dev/lnc/if_lnc_isa.c optional lnc isa
|
||||
dev/lnc/if_lnc_pc98.c optional lnc isa
|
||||
dev/lnc/if_lnc_pci.c optional lnc pci
|
||||
dev/mca/mca_bus.c optional mca
|
||||
dev/md/md.c optional md
|
||||
|
|
|
@ -84,40 +84,13 @@
|
|||
|
||||
#include <net/bpf.h>
|
||||
|
||||
#ifdef PC98
|
||||
#include <machine/clock.h>
|
||||
#endif
|
||||
#include <machine/md_var.h>
|
||||
|
||||
#include <i386/isa/isa_device.h>
|
||||
#include <dev/lnc/if_lncvar.h>
|
||||
#include <dev/lnc/if_lncreg.h>
|
||||
|
||||
struct lnc_softc {
|
||||
struct arpcom arpcom; /* see ../../net/if_arp.h */
|
||||
struct nic_info nic; /* NIC specific info */
|
||||
int nrdre;
|
||||
struct host_ring_entry *recv_ring; /* start of alloc'd mem */
|
||||
int recv_next;
|
||||
int ntdre;
|
||||
struct host_ring_entry *trans_ring;
|
||||
int trans_next;
|
||||
struct init_block *init_block; /* Initialisation block */
|
||||
int pending_transmits; /* No. of transmit descriptors in use */
|
||||
int next_to_send;
|
||||
struct mbuf *mbufs;
|
||||
int mbuf_count;
|
||||
int flags;
|
||||
int rap;
|
||||
int rdp;
|
||||
int bdp;
|
||||
#ifdef DEBUG
|
||||
int lnc_debug;
|
||||
#endif
|
||||
LNCSTATS_STRUCT
|
||||
};
|
||||
|
||||
static struct lnc_softc lnc_softc[NLNC];
|
||||
struct lnc_softc lnc_softc[NLNC];
|
||||
|
||||
static char const * const nic_ident[] = {
|
||||
"Unknown",
|
||||
|
@ -156,20 +129,10 @@ static __inline struct mbuf *mbuf_packet __P((struct lnc_softc *sc,
|
|||
int pkt_len));
|
||||
static __inline void lnc_rint __P((struct lnc_softc *sc));
|
||||
static __inline void lnc_tint __P((struct lnc_softc *sc));
|
||||
static int lnc_probe __P((struct isa_device *isa_dev));
|
||||
#ifdef PC98
|
||||
static int cnet98s_probe __P((struct lnc_softc *sc, unsigned iobase));
|
||||
#endif
|
||||
static int ne2100_probe __P((struct lnc_softc *sc, unsigned iobase));
|
||||
static int bicc_probe __P((struct lnc_softc *sc, unsigned iobase));
|
||||
static int dec_macaddr_extract __P((u_char ring[], struct lnc_softc *sc));
|
||||
static int depca_probe __P((struct lnc_softc *sc, unsigned iobase));
|
||||
static int lance_probe __P((struct lnc_softc *sc));
|
||||
static int pcnet_probe __P((struct lnc_softc *sc));
|
||||
static int lnc_attach_sc __P((struct lnc_softc *sc, int unit));
|
||||
static int lnc_attach __P((struct isa_device *isa_dev));
|
||||
extern int lnc_probe __P((struct isa_device *isa_dev));
|
||||
int lnc_attach_sc __P((struct lnc_softc *sc, int unit));
|
||||
extern int lnc_attach __P((struct isa_device *isa_dev));
|
||||
static void lnc_init __P((void *));
|
||||
static ointhand2_t lncintr;
|
||||
static __inline int mbuf_to_buffer __P((struct mbuf *m, char *buffer));
|
||||
static __inline struct mbuf *chain_to_cluster __P((struct mbuf *m));
|
||||
static void lnc_start __P((struct ifnet *ifp));
|
||||
|
@ -180,27 +143,10 @@ void lnc_dump_state __P((struct lnc_softc *sc));
|
|||
void mbuf_dump_chain __P((struct mbuf *m));
|
||||
#endif
|
||||
|
||||
#if NPCI > 0
|
||||
void *lnc_attach_ne2100_pci __P((int unit, unsigned iobase));
|
||||
#endif
|
||||
void lncintr_sc __P((struct lnc_softc *sc));
|
||||
|
||||
struct isa_driver lncdriver = {lnc_probe, lnc_attach, "lnc"};
|
||||
|
||||
static __inline void
|
||||
write_csr(struct lnc_softc *sc, u_short port, u_short val)
|
||||
{
|
||||
outw(sc->rap, port);
|
||||
outw(sc->rdp, val);
|
||||
}
|
||||
|
||||
static __inline u_short
|
||||
read_csr(struct lnc_softc *sc, u_short port)
|
||||
{
|
||||
outw(sc->rap, port);
|
||||
return (inw(sc->rdp));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
write_bcr(struct lnc_softc *sc, u_short port, u_short val)
|
||||
{
|
||||
|
@ -860,294 +806,7 @@ lnc_tint(struct lnc_softc *sc)
|
|||
|
||||
}
|
||||
|
||||
static int
|
||||
lnc_probe(struct isa_device * isa_dev)
|
||||
{
|
||||
int nports;
|
||||
int unit = isa_dev->id_unit;
|
||||
struct lnc_softc *sc = &lnc_softc[unit];
|
||||
unsigned iobase = isa_dev->id_iobase;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
int vsw;
|
||||
vsw = inw(isa_dev->id_iobase + PCNET_VSW);
|
||||
printf("Vendor Specific Word = %x\n", vsw);
|
||||
#endif
|
||||
|
||||
nports = bicc_probe(sc, iobase);
|
||||
if (nports == 0)
|
||||
nports = ne2100_probe(sc, iobase);
|
||||
if (nports == 0)
|
||||
nports = depca_probe(sc, iobase);
|
||||
#ifdef PC98
|
||||
if (nports == 0)
|
||||
nports = cnet98s_probe(sc, iobase);
|
||||
#endif
|
||||
return (nports);
|
||||
}
|
||||
|
||||
#ifdef PC98
|
||||
/* ISA Bus Configuration Registers */
|
||||
/* XXX - Should be in ic/Am7990.h */
|
||||
#define MSRDA 0x0000 /* ISACSR0: Master Mode Read Activity */
|
||||
#define MSWRA 0x0001 /* ISACSR1: Master Mode Write Activity */
|
||||
#define MC 0x0002 /* ISACSR2: Miscellaneous Configuration */
|
||||
|
||||
#define LED1 0x0005 /* ISACSR5: LED1 Status */
|
||||
#define LED2 0x0006 /* ISACSR6: LED2 Status */
|
||||
#define LED3 0x0007 /* ISACSR7: LED3 Status */
|
||||
|
||||
#define LED_PSE 0x0080 /* Pulse Stretcher */
|
||||
#define LED_XMTE 0x0010 /* Transmit Status */
|
||||
#define LED_RVPOLE 0x0008 /* Receive Polarity */
|
||||
#define LED_RCVE 0x0004 /* Receive Status */
|
||||
#define LED_JABE 0x0002 /* Jabber */
|
||||
#define LED_COLE 0x0001 /* Collision */
|
||||
|
||||
static int
|
||||
cnet98s_probe(struct lnc_softc *sc, unsigned iobase)
|
||||
{
|
||||
int i;
|
||||
ushort tmp;
|
||||
|
||||
sc->rap = iobase + CNET98S_RAP;
|
||||
sc->rdp = iobase + CNET98S_RDP;
|
||||
|
||||
/* Reset */
|
||||
tmp = inw(iobase + CNET98S_RESET);
|
||||
outw(iobase + CNET98S_RESET, tmp);
|
||||
DELAY(500);
|
||||
|
||||
sc->nic.ic = pcnet_probe(sc);
|
||||
if ((sc->nic.ic == UNKNOWN) || (sc->nic.ic > PCnet_32)) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
sc->nic.ident = CNET98S;
|
||||
sc->nic.mem_mode = DMA_FIXED;
|
||||
|
||||
/* XXX - For now just use the defines */
|
||||
sc->nrdre = NRDRE;
|
||||
sc->ntdre = NTDRE;
|
||||
|
||||
/* Extract MAC address from PROM */
|
||||
for (i = 0; i < ETHER_ADDR_LEN; i++) {
|
||||
sc->arpcom.ac_enaddr[i] = inb(iobase + (i * 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* ISA Configuration
|
||||
*
|
||||
* XXX - Following parameters are Contec C-NET(98)S only.
|
||||
* So, check the Ethernet address here.
|
||||
*
|
||||
* Contec uses 00 80 4c ?? ?? ??
|
||||
*/
|
||||
if (sc->arpcom.ac_enaddr[0] == (u_char)0x00
|
||||
&& sc->arpcom.ac_enaddr[1] == (u_char)0x80
|
||||
&& sc->arpcom.ac_enaddr[2] == (u_char)0x4c) {
|
||||
outw(sc->rap, MSRDA);
|
||||
outw(iobase + CNET98S_IDP, 0x0006);
|
||||
outw(sc->rap, MSWRA);
|
||||
outw(iobase + CNET98S_IDP, 0x0006);
|
||||
#ifdef DIAGNOSTIC
|
||||
outw(sc->rap, MC);
|
||||
printf("ISACSR2 = %x\n", inw(iobase + CNET98S_IDP));
|
||||
#endif
|
||||
outw(sc->rap, LED1);
|
||||
outw(iobase + CNET98S_IDP, LED_PSE | LED_XMTE);
|
||||
outw(sc->rap, LED2);
|
||||
outw(iobase + CNET98S_IDP, LED_PSE | LED_RCVE);
|
||||
outw(sc->rap, LED3);
|
||||
outw(iobase + CNET98S_IDP, LED_PSE | LED_COLE);
|
||||
}
|
||||
|
||||
return (CNET98S_IOSIZE);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
ne2100_probe(struct lnc_softc *sc, unsigned iobase)
|
||||
{
|
||||
int i;
|
||||
|
||||
sc->rap = iobase + PCNET_RAP;
|
||||
sc->rdp = iobase + PCNET_RDP;
|
||||
|
||||
sc->nic.ic = pcnet_probe(sc);
|
||||
if ((sc->nic.ic > 0) && (sc->nic.ic < PCnet_PCI)) {
|
||||
sc->nic.ident = NE2100;
|
||||
sc->nic.mem_mode = DMA_FIXED;
|
||||
|
||||
/* XXX - For now just use the defines */
|
||||
sc->nrdre = NRDRE;
|
||||
sc->ntdre = NTDRE;
|
||||
|
||||
/* Extract MAC address from PROM */
|
||||
for (i = 0; i < ETHER_ADDR_LEN; i++)
|
||||
sc->arpcom.ac_enaddr[i] = inb(iobase + i);
|
||||
return (NE2100_IOSIZE);
|
||||
} else {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
bicc_probe(struct lnc_softc *sc, unsigned iobase)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* There isn't any way to determine if a NIC is a BICC. Basically, if
|
||||
* the lance probe succeeds using the i/o addresses of the BICC then
|
||||
* we assume it's a BICC.
|
||||
*
|
||||
*/
|
||||
|
||||
sc->rap = iobase + BICC_RAP;
|
||||
sc->rdp = iobase + BICC_RDP;
|
||||
|
||||
/* I think all these cards us the Am7990 */
|
||||
|
||||
if ((sc->nic.ic = lance_probe(sc))) {
|
||||
sc->nic.ident = BICC;
|
||||
sc->nic.mem_mode = DMA_FIXED;
|
||||
|
||||
/* XXX - For now just use the defines */
|
||||
sc->nrdre = NRDRE;
|
||||
sc->ntdre = NTDRE;
|
||||
|
||||
/* Extract MAC address from PROM */
|
||||
for (i = 0; i < ETHER_ADDR_LEN; i++)
|
||||
sc->arpcom.ac_enaddr[i] = inb(iobase + (i * 2));
|
||||
|
||||
return (BICC_IOSIZE);
|
||||
} else {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* I don't have data sheets for the dec cards but it looks like the mac
|
||||
* address is contained in a 32 byte ring. Each time you read from the port
|
||||
* you get the next byte in the ring. The mac address is stored after a
|
||||
* signature so keep searching for the signature first.
|
||||
*/
|
||||
static int
|
||||
dec_macaddr_extract(u_char ring[], struct lnc_softc * sc)
|
||||
{
|
||||
const unsigned char signature[] = {0xff, 0x00, 0x55, 0xaa, 0xff, 0x00, 0x55, 0xaa};
|
||||
|
||||
int i, j, rindex;
|
||||
|
||||
for (i = 0; i < sizeof ring; i++) {
|
||||
for (j = 0, rindex = i; j < sizeof signature; j++) {
|
||||
if (ring[rindex] != signature[j])
|
||||
break;
|
||||
if (++rindex > sizeof ring)
|
||||
rindex = 0;
|
||||
}
|
||||
if (j == sizeof signature) {
|
||||
for (j = 0, rindex = i; j < ETHER_ADDR_LEN; j++) {
|
||||
sc->arpcom.ac_enaddr[j] = ring[rindex];
|
||||
if (++rindex > sizeof ring)
|
||||
rindex = 0;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
depca_probe(struct lnc_softc *sc, unsigned iobase)
|
||||
{
|
||||
int i;
|
||||
unsigned char maddr_ring[DEPCA_ADDR_ROM_SIZE];
|
||||
|
||||
sc->rap = iobase + DEPCA_RAP;
|
||||
sc->rdp = iobase + DEPCA_RDP;
|
||||
|
||||
if ((sc->nic.ic = lance_probe(sc))) {
|
||||
sc->nic.ident = DEPCA;
|
||||
sc->nic.mem_mode = SHMEM;
|
||||
|
||||
/* Extract MAC address from PROM */
|
||||
for (i = 0; i < DEPCA_ADDR_ROM_SIZE; i++)
|
||||
maddr_ring[i] = inb(iobase + DEPCA_ADP);
|
||||
if (dec_macaddr_extract(maddr_ring, sc)) {
|
||||
return (DEPCA_IOSIZE);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
lance_probe(struct lnc_softc *sc)
|
||||
{
|
||||
write_csr(sc, CSR0, STOP);
|
||||
|
||||
if ((inw(sc->rdp) & STOP) && !(read_csr(sc, CSR3))) {
|
||||
/*
|
||||
* Check to see if it's a C-LANCE. For the LANCE the INEA bit
|
||||
* cannot be set while the STOP bit is. This restriction is
|
||||
* removed for the C-LANCE.
|
||||
*/
|
||||
write_csr(sc, CSR0, INEA);
|
||||
if (read_csr(sc, CSR0) & INEA)
|
||||
return (C_LANCE);
|
||||
else
|
||||
return (LANCE);
|
||||
} else
|
||||
return (UNKNOWN);
|
||||
}
|
||||
|
||||
static int
|
||||
pcnet_probe(struct lnc_softc *sc)
|
||||
{
|
||||
u_long chip_id;
|
||||
int type;
|
||||
|
||||
/*
|
||||
* The PCnet family don't reset the RAP register on reset so we'll
|
||||
* have to write during the probe :-) It does have an ID register
|
||||
* though so the probe is just a matter of reading it.
|
||||
*/
|
||||
|
||||
if ((type = lance_probe(sc))) {
|
||||
chip_id = read_csr(sc, CSR89);
|
||||
chip_id <<= 16;
|
||||
chip_id |= read_csr(sc, CSR88);
|
||||
if (chip_id & AMD_MASK) {
|
||||
chip_id >>= 12;
|
||||
switch (chip_id & PART_MASK) {
|
||||
case Am79C960:
|
||||
return (PCnet_ISA);
|
||||
case Am79C961:
|
||||
return (PCnet_ISAplus);
|
||||
case Am79C961A:
|
||||
return (PCnet_ISA_II);
|
||||
case Am79C965:
|
||||
return (PCnet_32);
|
||||
case Am79C970:
|
||||
return (PCnet_PCI);
|
||||
case Am79C970A:
|
||||
return (PCnet_PCI_II);
|
||||
case Am79C971:
|
||||
return (PCnet_FAST);
|
||||
case Am79C972:
|
||||
return (PCnet_FASTplus);
|
||||
case Am79C978:
|
||||
return (PCnet_Home);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (type);
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
lnc_attach_sc(struct lnc_softc *sc, int unit)
|
||||
{
|
||||
int lnc_mem_size;
|
||||
|
@ -1248,72 +907,6 @@ lnc_attach_sc(struct lnc_softc *sc, int unit)
|
|||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
lnc_attach(struct isa_device * isa_dev)
|
||||
{
|
||||
int unit = isa_dev->id_unit;
|
||||
struct lnc_softc *sc = &lnc_softc[unit];
|
||||
int result;
|
||||
|
||||
isa_dev->id_ointr = lncintr;
|
||||
result = lnc_attach_sc (sc, unit);
|
||||
if (result == 0)
|
||||
return (0);
|
||||
|
||||
#ifndef PC98
|
||||
/*
|
||||
* XXX - is it safe to call isa_dmacascade() after if_attach()
|
||||
* and ether_ifattach() have been called in lnc_attach() ???
|
||||
*/
|
||||
if ((sc->nic.mem_mode != SHMEM) &&
|
||||
(sc->nic.ic < PCnet_32))
|
||||
isa_dmacascade(isa_dev->id_drq);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if NPCI > 0
|
||||
void *
|
||||
lnc_attach_ne2100_pci(int unit, unsigned iobase)
|
||||
{
|
||||
int i;
|
||||
struct lnc_softc *sc = malloc(sizeof *sc, M_DEVBUF, M_NOWAIT);
|
||||
|
||||
if (sc) {
|
||||
bzero (sc, sizeof *sc);
|
||||
|
||||
sc->rap = iobase + PCNET_RAP;
|
||||
sc->rdp = iobase + PCNET_RDP;
|
||||
sc->bdp = iobase + PCNET_BDP;
|
||||
|
||||
sc->nic.ic = pcnet_probe(sc);
|
||||
if (sc->nic.ic >= PCnet_32) {
|
||||
sc->nic.ident = NE2100;
|
||||
sc->nic.mem_mode = DMA_FIXED;
|
||||
|
||||
/* XXX - For now just use the defines */
|
||||
sc->nrdre = NRDRE;
|
||||
sc->ntdre = NTDRE;
|
||||
|
||||
/* Extract MAC address from PROM */
|
||||
for (i = 0; i < ETHER_ADDR_LEN; i++)
|
||||
sc->arpcom.ac_enaddr[i] = inb(iobase + i);
|
||||
|
||||
if (lnc_attach_sc(sc, unit) == 0) {
|
||||
free(sc, M_DEVBUF);
|
||||
sc = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
free(sc, M_DEVBUF);
|
||||
sc = NULL;
|
||||
}
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
lnc_init(xsc)
|
||||
void *xsc;
|
||||
|
@ -1580,13 +1173,6 @@ lncintr_sc(struct lnc_softc *sc)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
lncintr(int unit)
|
||||
{
|
||||
struct lnc_softc *sc = &lnc_softc[unit];
|
||||
lncintr_sc (sc);
|
||||
}
|
||||
|
||||
static __inline int
|
||||
mbuf_to_buffer(struct mbuf *m, char *buffer)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,301 @@
|
|||
/*-
|
||||
* Copyright (c) 2000
|
||||
* Paul Richards. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* verbatim and that no modifications are made prior to this
|
||||
* point in the file.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name Paul Richards may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY PAUL RICHARDS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL PAUL RICHARDS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_types.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
#include <i386/isa/isa_device.h>
|
||||
#include <dev/lnc/if_lncvar.h>
|
||||
#include <dev/lnc/if_lncreg.h>
|
||||
|
||||
int ne2100_probe __P((struct lnc_softc *, unsigned));
|
||||
int bicc_probe __P((struct lnc_softc *, unsigned));
|
||||
int depca_probe __P((struct lnc_softc *, unsigned));
|
||||
int lance_probe __P((struct lnc_softc *));
|
||||
int pcnet_probe __P((struct lnc_softc *));
|
||||
int lnc_probe __P((struct isa_device *));
|
||||
int lnc_attach __P((struct isa_device *));
|
||||
|
||||
static int dec_macaddr_extract __P((u_char[], struct lnc_softc *));
|
||||
static ointhand2_t lncintr;
|
||||
|
||||
extern struct lnc_softc lnc_softc[];
|
||||
extern int lnc_attach_sc __P((struct lnc_softc *, int));
|
||||
extern void lncintr_sc __P((struct lnc_softc *));
|
||||
|
||||
int
|
||||
ne2100_probe(struct lnc_softc *sc, unsigned iobase)
|
||||
{
|
||||
int i;
|
||||
|
||||
sc->rap = iobase + PCNET_RAP;
|
||||
sc->rdp = iobase + PCNET_RDP;
|
||||
|
||||
sc->nic.ic = pcnet_probe(sc);
|
||||
if ((sc->nic.ic > 0) && (sc->nic.ic < PCnet_PCI)) {
|
||||
sc->nic.ident = NE2100;
|
||||
sc->nic.mem_mode = DMA_FIXED;
|
||||
|
||||
/* XXX - For now just use the defines */
|
||||
sc->nrdre = NRDRE;
|
||||
sc->ntdre = NTDRE;
|
||||
|
||||
/* Extract MAC address from PROM */
|
||||
for (i = 0; i < ETHER_ADDR_LEN; i++)
|
||||
sc->arpcom.ac_enaddr[i] = inb(iobase + i);
|
||||
return (NE2100_IOSIZE);
|
||||
} else {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
bicc_probe(struct lnc_softc *sc, unsigned iobase)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* There isn't any way to determine if a NIC is a BICC. Basically, if
|
||||
* the lance probe succeeds using the i/o addresses of the BICC then
|
||||
* we assume it's a BICC.
|
||||
*
|
||||
*/
|
||||
|
||||
sc->rap = iobase + BICC_RAP;
|
||||
sc->rdp = iobase + BICC_RDP;
|
||||
|
||||
/* I think all these cards us the Am7990 */
|
||||
|
||||
if ((sc->nic.ic = lance_probe(sc))) {
|
||||
sc->nic.ident = BICC;
|
||||
sc->nic.mem_mode = DMA_FIXED;
|
||||
|
||||
/* XXX - For now just use the defines */
|
||||
sc->nrdre = NRDRE;
|
||||
sc->ntdre = NTDRE;
|
||||
|
||||
/* Extract MAC address from PROM */
|
||||
for (i = 0; i < ETHER_ADDR_LEN; i++)
|
||||
sc->arpcom.ac_enaddr[i] = inb(iobase + (i * 2));
|
||||
|
||||
return (BICC_IOSIZE);
|
||||
} else {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* I don't have data sheets for the dec cards but it looks like the mac
|
||||
* address is contained in a 32 byte ring. Each time you read from the port
|
||||
* you get the next byte in the ring. The mac address is stored after a
|
||||
* signature so keep searching for the signature first.
|
||||
*/
|
||||
static int
|
||||
dec_macaddr_extract(u_char ring[], struct lnc_softc * sc)
|
||||
{
|
||||
const unsigned char signature[] = {0xff, 0x00, 0x55, 0xaa, 0xff, 0x00, 0x55, 0xaa};
|
||||
|
||||
int i, j, rindex;
|
||||
|
||||
for (i = 0; i < sizeof ring; i++) {
|
||||
for (j = 0, rindex = i; j < sizeof signature; j++) {
|
||||
if (ring[rindex] != signature[j])
|
||||
break;
|
||||
if (++rindex > sizeof ring)
|
||||
rindex = 0;
|
||||
}
|
||||
if (j == sizeof signature) {
|
||||
for (j = 0, rindex = i; j < ETHER_ADDR_LEN; j++) {
|
||||
sc->arpcom.ac_enaddr[j] = ring[rindex];
|
||||
if (++rindex > sizeof ring)
|
||||
rindex = 0;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
depca_probe(struct lnc_softc *sc, unsigned iobase)
|
||||
{
|
||||
int i;
|
||||
unsigned char maddr_ring[DEPCA_ADDR_ROM_SIZE];
|
||||
|
||||
sc->rap = iobase + DEPCA_RAP;
|
||||
sc->rdp = iobase + DEPCA_RDP;
|
||||
|
||||
if ((sc->nic.ic = lance_probe(sc))) {
|
||||
sc->nic.ident = DEPCA;
|
||||
sc->nic.mem_mode = SHMEM;
|
||||
|
||||
/* Extract MAC address from PROM */
|
||||
for (i = 0; i < DEPCA_ADDR_ROM_SIZE; i++)
|
||||
maddr_ring[i] = inb(iobase + DEPCA_ADP);
|
||||
if (dec_macaddr_extract(maddr_ring, sc)) {
|
||||
return (DEPCA_IOSIZE);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
lance_probe(struct lnc_softc *sc)
|
||||
{
|
||||
write_csr(sc, CSR0, STOP);
|
||||
|
||||
if ((inw(sc->rdp) & STOP) && !(read_csr(sc, CSR3))) {
|
||||
/*
|
||||
* Check to see if it's a C-LANCE. For the LANCE the INEA bit
|
||||
* cannot be set while the STOP bit is. This restriction is
|
||||
* removed for the C-LANCE.
|
||||
*/
|
||||
write_csr(sc, CSR0, INEA);
|
||||
if (read_csr(sc, CSR0) & INEA)
|
||||
return (C_LANCE);
|
||||
else
|
||||
return (LANCE);
|
||||
} else
|
||||
return (UNKNOWN);
|
||||
}
|
||||
|
||||
int
|
||||
pcnet_probe(struct lnc_softc *sc)
|
||||
{
|
||||
u_long chip_id;
|
||||
int type;
|
||||
|
||||
/*
|
||||
* The PCnet family don't reset the RAP register on reset so we'll
|
||||
* have to write during the probe :-) It does have an ID register
|
||||
* though so the probe is just a matter of reading it.
|
||||
*/
|
||||
|
||||
if ((type = lance_probe(sc))) {
|
||||
chip_id = read_csr(sc, CSR89);
|
||||
chip_id <<= 16;
|
||||
chip_id |= read_csr(sc, CSR88);
|
||||
if (chip_id & AMD_MASK) {
|
||||
chip_id >>= 12;
|
||||
switch (chip_id & PART_MASK) {
|
||||
case Am79C960:
|
||||
return (PCnet_ISA);
|
||||
case Am79C961:
|
||||
return (PCnet_ISAplus);
|
||||
case Am79C961A:
|
||||
return (PCnet_ISA_II);
|
||||
case Am79C965:
|
||||
return (PCnet_32);
|
||||
case Am79C970:
|
||||
return (PCnet_PCI);
|
||||
case Am79C970A:
|
||||
return (PCnet_PCI_II);
|
||||
case Am79C971:
|
||||
return (PCnet_FAST);
|
||||
case Am79C972:
|
||||
return (PCnet_FASTplus);
|
||||
case Am79C978:
|
||||
return (PCnet_Home);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (type);
|
||||
}
|
||||
|
||||
int
|
||||
lnc_probe(struct isa_device * isa_dev)
|
||||
{
|
||||
int nports;
|
||||
int unit = isa_dev->id_unit;
|
||||
struct lnc_softc *sc = &lnc_softc[unit];
|
||||
unsigned iobase = isa_dev->id_iobase;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
int vsw;
|
||||
vsw = inw(isa_dev->id_iobase + PCNET_VSW);
|
||||
printf("Vendor Specific Word = %x\n", vsw);
|
||||
#endif
|
||||
|
||||
nports = bicc_probe(sc, iobase);
|
||||
if (nports == 0)
|
||||
nports = ne2100_probe(sc, iobase);
|
||||
if (nports == 0)
|
||||
nports = depca_probe(sc, iobase);
|
||||
#ifdef PC98
|
||||
if (nports == 0)
|
||||
nports = cnet98s_probe(sc, iobase);
|
||||
#endif
|
||||
return (nports);
|
||||
}
|
||||
|
||||
int
|
||||
lnc_attach(struct isa_device * isa_dev)
|
||||
{
|
||||
int unit = isa_dev->id_unit;
|
||||
struct lnc_softc *sc = &lnc_softc[unit];
|
||||
int result;
|
||||
|
||||
isa_dev->id_ointr = lncintr;
|
||||
result = lnc_attach_sc (sc, unit);
|
||||
if (result == 0)
|
||||
return (0);
|
||||
|
||||
#ifndef PC98
|
||||
/*
|
||||
* XXX - is it safe to call isa_dmacascade() after if_attach()
|
||||
* and ether_ifattach() have been called in lnc_attach() ???
|
||||
*/
|
||||
if ((sc->nic.mem_mode != SHMEM) &&
|
||||
(sc->nic.ic < PCnet_32))
|
||||
isa_dmacascade(isa_dev->id_drq);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
lncintr(int unit)
|
||||
{
|
||||
struct lnc_softc *sc = &lnc_softc[unit];
|
||||
lncintr_sc (sc);
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
/*-
|
||||
* Copyright (c) 2000
|
||||
* Paul Richards. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* verbatim and that no modifications are made prior to this
|
||||
* point in the file.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name Paul Richards may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY PAUL RICHARDS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL PAUL RICHARDS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifdef PC98
|
||||
#include "lnc.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <machine/clock.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_types.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
#include <i386/isa/isa_device.h>
|
||||
|
||||
#include <dev/lnc/if_lncvar.h>
|
||||
#include <dev/lnc/if_lncreg.h>
|
||||
|
||||
int pcnet_probe __P((struct lnc_softc *sc));
|
||||
static int cnet98s_probe __P((struct lnc_softc *sc, unsigned iobase));
|
||||
|
||||
/* C-NET(98)S port addresses */
|
||||
#define CNET98S_RDP 0x400 /* Register Data Port */
|
||||
#define CNET98S_RAP 0x402 /* Register Address Port */
|
||||
#define CNET98S_RESET 0x404
|
||||
#define CNET98S_IDP 0x406
|
||||
#define CNET98S_EEPROM 0x40e
|
||||
/*
|
||||
* XXX - The I/O address range is fragmented in the C-NET(98)S.
|
||||
* This is the number of regs at iobase.
|
||||
*/
|
||||
#define CNET98S_IOSIZE 16 /* # of i/o addresses used. */
|
||||
|
||||
/* ISA Bus Configuration Registers */
|
||||
/* XXX - Should be in ic/Am7990.h */
|
||||
#define MSRDA 0x0000 /* ISACSR0: Master Mode Read Activity */
|
||||
#define MSWRA 0x0001 /* ISACSR1: Master Mode Write Activity */
|
||||
#define MC 0x0002 /* ISACSR2: Miscellaneous Configuration */
|
||||
|
||||
#define LED1 0x0005 /* ISACSR5: LED1 Status */
|
||||
#define LED2 0x0006 /* ISACSR6: LED2 Status */
|
||||
#define LED3 0x0007 /* ISACSR7: LED3 Status */
|
||||
|
||||
#define LED_PSE 0x0080 /* Pulse Stretcher */
|
||||
#define LED_XMTE 0x0010 /* Transmit Status */
|
||||
#define LED_RVPOLE 0x0008 /* Receive Polarity */
|
||||
#define LED_RCVE 0x0004 /* Receive Status */
|
||||
#define LED_JABE 0x0002 /* Jabber */
|
||||
#define LED_COLE 0x0001 /* Collision */
|
||||
|
||||
static int
|
||||
cnet98s_probe(struct lnc_softc *sc, unsigned iobase)
|
||||
{
|
||||
int i;
|
||||
ushort tmp;
|
||||
|
||||
sc->rap = iobase + CNET98S_RAP;
|
||||
sc->rdp = iobase + CNET98S_RDP;
|
||||
|
||||
/* Reset */
|
||||
tmp = inw(iobase + CNET98S_RESET);
|
||||
outw(iobase + CNET98S_RESET, tmp);
|
||||
DELAY(500);
|
||||
|
||||
sc->nic.ic = pcnet_probe(sc);
|
||||
if ((sc->nic.ic == UNKNOWN) || (sc->nic.ic > PCnet_32)) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
sc->nic.ident = CNET98S;
|
||||
sc->nic.mem_mode = DMA_FIXED;
|
||||
|
||||
/* XXX - For now just use the defines */
|
||||
sc->nrdre = NRDRE;
|
||||
sc->ntdre = NTDRE;
|
||||
|
||||
/* Extract MAC address from PROM */
|
||||
for (i = 0; i < ETHER_ADDR_LEN; i++) {
|
||||
sc->arpcom.ac_enaddr[i] = inb(iobase + (i * 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* ISA Configuration
|
||||
*
|
||||
* XXX - Following parameters are Contec C-NET(98)S only.
|
||||
* So, check the Ethernet address here.
|
||||
*
|
||||
* Contec uses 00 80 4c ?? ?? ??
|
||||
*/
|
||||
if (sc->arpcom.ac_enaddr[0] == (u_char)0x00
|
||||
&& sc->arpcom.ac_enaddr[1] == (u_char)0x80
|
||||
&& sc->arpcom.ac_enaddr[2] == (u_char)0x4c) {
|
||||
outw(sc->rap, MSRDA);
|
||||
outw(iobase + CNET98S_IDP, 0x0006);
|
||||
outw(sc->rap, MSWRA);
|
||||
outw(iobase + CNET98S_IDP, 0x0006);
|
||||
#ifdef DIAGNOSTIC
|
||||
outw(sc->rap, MC);
|
||||
printf("ISACSR2 = %x\n", inw(iobase + CNET98S_IDP));
|
||||
#endif
|
||||
outw(sc->rap, LED1);
|
||||
outw(iobase + CNET98S_IDP, LED_PSE | LED_XMTE);
|
||||
outw(sc->rap, LED2);
|
||||
outw(iobase + CNET98S_IDP, LED_PSE | LED_RCVE);
|
||||
outw(sc->rap, LED3);
|
||||
outw(iobase + CNET98S_IDP, LED_PSE | LED_COLE);
|
||||
}
|
||||
|
||||
return (CNET98S_IOSIZE);
|
||||
}
|
||||
#endif
|
|
@ -27,6 +27,17 @@
|
|||
#include <pci/pcireg.h>
|
||||
#include <pci/pcivar.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_types.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
#include <dev/lnc/if_lncvar.h>
|
||||
|
||||
#include "lnc.h"
|
||||
|
||||
#ifndef COMPAT_OLDPCI
|
||||
|
@ -36,7 +47,8 @@
|
|||
#define PCI_DEVICE_ID_PCNet_PCI 0x20001022
|
||||
#define PCI_DEVICE_ID_PCHome_PCI 0x20011022
|
||||
|
||||
extern void *lnc_attach_ne2100_pci __P((int unit, unsigned iobase));
|
||||
extern int pcnet_probe __P((struct lnc_softc *sc));
|
||||
extern int lnc_attach_sc __P((struct lnc_softc *sc, int unit));
|
||||
|
||||
static const char* lnc_pci_probe __P((pcici_t tag, pcidi_t type));
|
||||
static void lnc_pci_attach __P((pcici_t config_id, int unit));
|
||||
|
@ -76,9 +88,10 @@ lnc_pci_attach(config_id, unit)
|
|||
pcici_t config_id;
|
||||
int unit;
|
||||
{
|
||||
struct lnc_softc *sc;
|
||||
unsigned iobase;
|
||||
unsigned data; /* scratch to make this device a bus master*/
|
||||
void *lnc; /* device specific data for interrupt handler ... */
|
||||
int i;
|
||||
|
||||
if ( !pci_map_port(config_id,PCI_MAP_REG_START,(u_short *)&iobase) )
|
||||
printf("lnc%d: pci_port_map_attach failed?!\n",unit);
|
||||
|
@ -91,13 +104,40 @@ lnc_pci_attach(config_id, unit)
|
|||
data |= PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN;
|
||||
pci_cfgwrite(config_id, PCIR_COMMAND, data, 4);
|
||||
|
||||
lnc = lnc_attach_ne2100_pci(unit, iobase);
|
||||
sc = malloc(sizeof *sc, M_DEVBUF, M_NOWAIT);
|
||||
|
||||
if (!lnc)
|
||||
return;
|
||||
if(!(pci_map_int(config_id, lncintr_sc, (void *)lnc, &net_imask))) {
|
||||
free (lnc, M_DEVBUF);
|
||||
return;
|
||||
if (sc) {
|
||||
bzero (sc, sizeof *sc);
|
||||
|
||||
sc->rap = iobase + PCNET_RAP;
|
||||
sc->rdp = iobase + PCNET_RDP;
|
||||
sc->bdp = iobase + PCNET_BDP;
|
||||
|
||||
sc->nic.ic = pcnet_probe(sc);
|
||||
if (sc->nic.ic >= PCnet_32) {
|
||||
sc->nic.ident = NE2100;
|
||||
sc->nic.mem_mode = DMA_FIXED;
|
||||
|
||||
/* XXX - For now just use the defines */
|
||||
sc->nrdre = NRDRE;
|
||||
sc->ntdre = NTDRE;
|
||||
|
||||
/* Extract MAC address from PROM */
|
||||
for (i = 0; i < ETHER_ADDR_LEN; i++)
|
||||
sc->arpcom.ac_enaddr[i] = inb(iobase + i);
|
||||
|
||||
if (lnc_attach_sc(sc, unit) == 0) {
|
||||
free(sc, M_DEVBUF);
|
||||
sc = NULL;
|
||||
}
|
||||
|
||||
if(!(pci_map_int(config_id, lncintr_sc, (void *)sc, &net_imask))) {
|
||||
free (sc, M_DEVBUF);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
free(sc, M_DEVBUF);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
|
@ -76,20 +76,6 @@
|
|||
/* DEPCA specific defines */
|
||||
#define DEPCA_ADDR_ROM_SIZE 32
|
||||
|
||||
#ifdef PC98
|
||||
/* C-NET(98)S port addresses */
|
||||
#define CNET98S_RDP 0x400 /* Register Data Port */
|
||||
#define CNET98S_RAP 0x402 /* Register Address Port */
|
||||
#define CNET98S_RESET 0x404
|
||||
#define CNET98S_IDP 0x406
|
||||
#define CNET98S_EEPROM 0x40e
|
||||
/*
|
||||
* XXX - The I/O address range is fragmented in the C-NET(98)S.
|
||||
* This is the number of regs at iobase.
|
||||
*/
|
||||
#define CNET98S_IOSIZE 16 /* # of i/o addresses used. */
|
||||
#endif
|
||||
|
||||
/* Chip types */
|
||||
#define LANCE 1 /* Am7990 */
|
||||
#define C_LANCE 2 /* Am79C90 */
|
||||
|
@ -199,6 +185,30 @@ struct host_ring_entry {
|
|||
#define LNCSTATS(X)
|
||||
#endif
|
||||
|
||||
struct lnc_softc {
|
||||
struct arpcom arpcom; /* see ../../net/if_arp.h */
|
||||
struct nic_info nic; /* NIC specific info */
|
||||
int nrdre;
|
||||
struct host_ring_entry *recv_ring; /* start of alloc'd mem */
|
||||
int recv_next;
|
||||
int ntdre;
|
||||
struct host_ring_entry *trans_ring;
|
||||
int trans_next;
|
||||
struct init_block *init_block; /* Initialisation block */
|
||||
int pending_transmits; /* No. of transmit descriptors in use */
|
||||
int next_to_send;
|
||||
struct mbuf *mbufs;
|
||||
int mbuf_count;
|
||||
int flags;
|
||||
int rap;
|
||||
int rdp;
|
||||
int bdp;
|
||||
#ifdef DEBUG
|
||||
int lnc_debug;
|
||||
#endif
|
||||
LNCSTATS_STRUCT
|
||||
};
|
||||
|
||||
#define NDESC(len2) (1 << len2)
|
||||
|
||||
#define INC_MD_PTR(ptr, no_entries) \
|
||||
|
@ -211,3 +221,17 @@ struct host_ring_entry {
|
|||
|
||||
#define RECV_NEXT (sc->recv_ring->base + sc->recv_next)
|
||||
#define TRANS_NEXT (sc->trans_ring->base + sc->trans_next)
|
||||
|
||||
static __inline void
|
||||
write_csr(struct lnc_softc *sc, u_short port, u_short val)
|
||||
{
|
||||
outw(sc->rap, port);
|
||||
outw(sc->rdp, val);
|
||||
}
|
||||
|
||||
static __inline u_short
|
||||
read_csr(struct lnc_softc *sc, u_short port)
|
||||
{
|
||||
outw(sc->rap, port);
|
||||
return (inw(sc->rdp));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue