Newbusify.
Temporarily disable PC98 until I bring it up to date.
This commit is contained in:
parent
6aa623bf53
commit
232b06012c
@ -30,15 +30,12 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
#define DIAGNOSTIC
|
||||
#define DEBUG
|
||||
/*
|
||||
*
|
||||
* TODO ----
|
||||
*
|
||||
* This driver will need bounce buffer support when dma'ing to mbufs above the
|
||||
* 16Mb mark.
|
||||
*
|
||||
* Check all the XXX comments -- some of them are just things I've left
|
||||
* unfinished rather than "difficult" problems that were hacked around.
|
||||
*
|
||||
@ -65,13 +62,18 @@
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
@ -85,14 +87,9 @@
|
||||
|
||||
#include <machine/md_var.h>
|
||||
|
||||
#include <i386/isa/isa_device.h>
|
||||
#include <dev/lnc/if_lncvar.h>
|
||||
#include <dev/lnc/if_lncreg.h>
|
||||
|
||||
#ifndef COMPAT_OLDISA
|
||||
#error "The lnc device requires the old isa compatibility shims"
|
||||
#endif
|
||||
|
||||
static char const * const nic_ident[] = {
|
||||
"Unknown",
|
||||
"BICC",
|
||||
@ -116,23 +113,20 @@ static char const * const ic_ident[] = {
|
||||
"PCnet-Home",
|
||||
};
|
||||
|
||||
static void lnc_setladrf __P((lnc_softc_t *sc));
|
||||
static void lnc_stop __P((lnc_softc_t *sc));
|
||||
static void lnc_reset __P((lnc_softc_t *sc));
|
||||
static void lnc_free_mbufs __P((lnc_softc_t *sc));
|
||||
static __inline int alloc_mbuf_cluster __P((lnc_softc_t *sc,
|
||||
static void lnc_setladrf __P((struct lnc_softc *sc));
|
||||
static void lnc_reset __P((struct lnc_softc *sc));
|
||||
static void lnc_free_mbufs __P((struct lnc_softc *sc));
|
||||
static __inline int alloc_mbuf_cluster __P((struct lnc_softc *sc,
|
||||
struct host_ring_entry *desc));
|
||||
static __inline struct mbuf *chain_mbufs __P((lnc_softc_t *sc,
|
||||
static __inline struct mbuf *chain_mbufs __P((struct lnc_softc *sc,
|
||||
int start_of_packet,
|
||||
int pkt_len));
|
||||
static __inline struct mbuf *mbuf_packet __P((lnc_softc_t *sc,
|
||||
static __inline struct mbuf *mbuf_packet __P((struct lnc_softc *sc,
|
||||
int start_of_packet,
|
||||
int pkt_len));
|
||||
static __inline void lnc_rint __P((lnc_softc_t *sc));
|
||||
static __inline void lnc_tint __P((lnc_softc_t *sc));
|
||||
extern int lnc_probe __P((struct isa_device *isa_dev));
|
||||
int lnc_attach_sc __P((lnc_softc_t *sc, int unit));
|
||||
extern int lnc_attach __P((struct isa_device *isa_dev));
|
||||
static __inline void lnc_rint __P((struct lnc_softc *sc));
|
||||
static __inline void lnc_tint __P((struct lnc_softc *sc));
|
||||
|
||||
static void lnc_init __P((void *));
|
||||
static __inline int mbuf_to_buffer __P((struct mbuf *m, char *buffer));
|
||||
static __inline struct mbuf *chain_to_cluster __P((struct mbuf *m));
|
||||
@ -140,29 +134,40 @@ static void lnc_start __P((struct ifnet *ifp));
|
||||
static int lnc_ioctl __P((struct ifnet *ifp, u_long command, caddr_t data));
|
||||
static void lnc_watchdog __P((struct ifnet *ifp));
|
||||
#ifdef DEBUG
|
||||
void lnc_dump_state __P((lnc_softc_t *sc));
|
||||
void lnc_dump_state __P((struct lnc_softc *sc));
|
||||
void mbuf_dump_chain __P((struct mbuf *m));
|
||||
#endif
|
||||
|
||||
void lncintr_sc __P((lnc_softc_t *sc));
|
||||
void write_csr(struct lnc_softc *, u_short, u_short);
|
||||
u_short read_csr(struct lnc_softc *, u_short);
|
||||
void lnc_release_resources(device_t);
|
||||
|
||||
struct isa_driver lncdriver = {
|
||||
INTR_TYPE_NET,
|
||||
lnc_probe,
|
||||
lnc_attach,
|
||||
"lnc"
|
||||
};
|
||||
COMPAT_ISA_DRIVER(lnc, lncdriver);
|
||||
u_short
|
||||
read_csr(struct lnc_softc *sc, u_short port)
|
||||
{
|
||||
bus_space_write_2(sc->lnc_btag, sc->lnc_bhandle, sc->rap, port);
|
||||
return(bus_space_read_2(sc->lnc_btag, sc->lnc_bhandle, sc->rdp));
|
||||
}
|
||||
|
||||
void
|
||||
write_csr(struct lnc_softc *sc, u_short port, u_short val)
|
||||
{
|
||||
bus_space_write_2(sc->lnc_btag, sc->lnc_bhandle, sc->rap, port);
|
||||
bus_space_write_2(sc->lnc_btag, sc->lnc_bhandle, sc->rdp, val);
|
||||
}
|
||||
|
||||
#define inw(port) bus_space_read_2(sc->lnc_btag, sc->lnc_bhandle, port)
|
||||
#define outw(port, val) bus_space_write_2(sc->lnc_btag, sc->lnc_bhandle, port, val)
|
||||
|
||||
static __inline void
|
||||
write_bcr(lnc_softc_t *sc, u_short port, u_short val)
|
||||
write_bcr(struct lnc_softc *sc, u_short port, u_short val)
|
||||
{
|
||||
outw(sc->rap, port);
|
||||
outw(sc->bdp, val);
|
||||
}
|
||||
|
||||
static __inline u_short
|
||||
read_bcr(lnc_softc_t *sc, u_short port)
|
||||
read_bcr(struct lnc_softc *sc, u_short port)
|
||||
{
|
||||
outw(sc->rap, port);
|
||||
return (inw(sc->bdp));
|
||||
@ -186,11 +191,36 @@ ether_crc(const u_char *ether_addr)
|
||||
#undef POLYNOMIAL
|
||||
}
|
||||
|
||||
void
|
||||
lnc_release_resources(device_t dev)
|
||||
{
|
||||
lnc_softc_t *sc = device_get_softc(dev);
|
||||
|
||||
if (sc->irqres) {
|
||||
bus_teardown_intr(dev, sc->irqres, sc->intrhand);
|
||||
bus_release_resource(dev, SYS_RES_IRQ, sc->irqrid, sc->irqres);
|
||||
}
|
||||
|
||||
if (sc->portres)
|
||||
bus_release_resource(dev, SYS_RES_IOPORT,
|
||||
sc->portrid, sc->portres);
|
||||
if (sc->drqres)
|
||||
bus_release_resource(dev, SYS_RES_DRQ, sc->drqrid, sc->drqres);
|
||||
|
||||
if (sc->dmat) {
|
||||
if (sc->dmamap) {
|
||||
bus_dmamap_unload(sc->dmat, sc->dmamap);
|
||||
bus_dmamem_free(sc->dmat, sc->recv_ring, sc->dmamap);
|
||||
}
|
||||
bus_dma_tag_destroy(sc->dmat);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the logical address filter for multicast packets
|
||||
*/
|
||||
static __inline void
|
||||
lnc_setladrf(lnc_softc_t *sc)
|
||||
lnc_setladrf(struct lnc_softc *sc)
|
||||
{
|
||||
struct ifnet *ifp = &sc->arpcom.ac_if;
|
||||
struct ifmultiaddr *ifma;
|
||||
@ -222,20 +252,20 @@ lnc_setladrf(lnc_softc_t *sc)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
lnc_stop(lnc_softc_t *sc)
|
||||
void
|
||||
lnc_stop(struct lnc_softc *sc)
|
||||
{
|
||||
write_csr(sc, CSR0, STOP);
|
||||
}
|
||||
|
||||
static void
|
||||
lnc_reset(lnc_softc_t *sc)
|
||||
lnc_reset(struct lnc_softc *sc)
|
||||
{
|
||||
lnc_init(sc);
|
||||
}
|
||||
|
||||
static void
|
||||
lnc_free_mbufs(lnc_softc_t *sc)
|
||||
lnc_free_mbufs(struct lnc_softc *sc)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -257,7 +287,7 @@ lnc_free_mbufs(lnc_softc_t *sc)
|
||||
}
|
||||
|
||||
static __inline int
|
||||
alloc_mbuf_cluster(lnc_softc_t *sc, struct host_ring_entry *desc)
|
||||
alloc_mbuf_cluster(struct lnc_softc *sc, struct host_ring_entry *desc)
|
||||
{
|
||||
register struct mds *md = desc->md;
|
||||
struct mbuf *m=0;
|
||||
@ -290,7 +320,7 @@ alloc_mbuf_cluster(lnc_softc_t *sc, struct host_ring_entry *desc)
|
||||
}
|
||||
|
||||
static __inline struct mbuf *
|
||||
chain_mbufs(lnc_softc_t *sc, int start_of_packet, int pkt_len)
|
||||
chain_mbufs(struct lnc_softc *sc, int start_of_packet, int pkt_len)
|
||||
{
|
||||
struct mbuf *head, *m;
|
||||
struct host_ring_entry *desc;
|
||||
@ -325,7 +355,7 @@ chain_mbufs(lnc_softc_t *sc, int start_of_packet, int pkt_len)
|
||||
}
|
||||
|
||||
static __inline struct mbuf *
|
||||
mbuf_packet(lnc_softc_t *sc, int start_of_packet, int pkt_len)
|
||||
mbuf_packet(struct lnc_softc *sc, int start_of_packet, int pkt_len)
|
||||
{
|
||||
|
||||
struct host_ring_entry *start;
|
||||
@ -400,7 +430,7 @@ mbuf_packet(lnc_softc_t *sc, int start_of_packet, int pkt_len)
|
||||
|
||||
|
||||
static __inline void
|
||||
lnc_rint(lnc_softc_t *sc)
|
||||
lnc_rint(struct lnc_softc *sc)
|
||||
{
|
||||
struct host_ring_entry *next, *start;
|
||||
int start_of_packet;
|
||||
@ -552,19 +582,18 @@ lnc_rint(lnc_softc_t *sc)
|
||||
* vmware ethernet hardware emulation loops
|
||||
* packets back to itself, violates IFF_SIMPLEX.
|
||||
* drop it if it is from myself.
|
||||
*/
|
||||
*/
|
||||
if (bcmp(eh->ether_shost,
|
||||
sc->arpcom.ac_enaddr, ETHER_ADDR_LEN) == 0) {
|
||||
m_freem(head);
|
||||
m_freem(head);
|
||||
} else {
|
||||
/* Skip over the ether header */
|
||||
head->m_data += sizeof *eh;
|
||||
head->m_len -= sizeof *eh;
|
||||
head->m_pkthdr.len -= sizeof *eh;
|
||||
/* Skip over the ether header */
|
||||
head->m_data += sizeof *eh;
|
||||
head->m_len -= sizeof *eh;
|
||||
head->m_pkthdr.len -= sizeof *eh;
|
||||
|
||||
ether_input(&sc->arpcom.ac_if, eh, head);
|
||||
ether_input(&sc->arpcom.ac_if, eh, head);
|
||||
}
|
||||
|
||||
} else {
|
||||
int unit = sc->arpcom.ac_if.if_unit;
|
||||
log(LOG_ERR,"lnc%d: Packet dropped, no mbufs\n",unit);
|
||||
@ -585,7 +614,7 @@ lnc_rint(lnc_softc_t *sc)
|
||||
}
|
||||
|
||||
static __inline void
|
||||
lnc_tint(lnc_softc_t *sc)
|
||||
lnc_tint(struct lnc_softc *sc)
|
||||
{
|
||||
struct host_ring_entry *next, *start;
|
||||
int start_of_packet;
|
||||
@ -817,71 +846,20 @@ lnc_tint(lnc_softc_t *sc)
|
||||
*/
|
||||
|
||||
outw(sc->rdp, TINT | INEA);
|
||||
|
||||
/* XXX only while doing if_is comparisons */
|
||||
if (!(sc->arpcom.ac_if.if_flags & IFF_OACTIVE))
|
||||
lnc_start(&sc->arpcom.ac_if);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
lnc_attach_sc(lnc_softc_t *sc, int unit)
|
||||
lnc_attach_common(device_t dev)
|
||||
{
|
||||
int lnc_mem_size;
|
||||
int unit = device_get_unit(dev);
|
||||
lnc_softc_t *sc = device_get_softc(dev);
|
||||
int i;
|
||||
int skip;
|
||||
|
||||
/*
|
||||
* Allocate memory for use by the controller.
|
||||
*
|
||||
* XXX -- the Am7990 and Am79C960 only have 24 address lines and so can
|
||||
* only access the lower 16Mb of physical memory. For the moment we
|
||||
* assume that malloc will allocate memory within the lower 16Mb
|
||||
* range. This is not a very valid assumption but there's nothing
|
||||
* that can be done about it yet. For shared memory NICs this isn't
|
||||
* relevant.
|
||||
*
|
||||
*/
|
||||
|
||||
lnc_mem_size = ((NDESC(sc->nrdre) + NDESC(sc->ntdre)) *
|
||||
sizeof(struct host_ring_entry));
|
||||
|
||||
if (sc->nic.mem_mode != SHMEM)
|
||||
lnc_mem_size += sizeof(struct init_block) + (sizeof(struct mds) *
|
||||
(NDESC(sc->nrdre) + NDESC(sc->ntdre))) +
|
||||
MEM_SLEW;
|
||||
|
||||
/* If using DMA to fixed host buffers then allocate memory for them */
|
||||
|
||||
if (sc->nic.mem_mode == DMA_FIXED)
|
||||
lnc_mem_size += (NDESC(sc->nrdre) * RECVBUFSIZE) + (NDESC(sc->ntdre) * TRANSBUFSIZE);
|
||||
|
||||
if (sc->nic.mem_mode != SHMEM) {
|
||||
if (sc->nic.ic < PCnet_32) {
|
||||
/* ISA based cards */
|
||||
sc->recv_ring = contigmalloc(lnc_mem_size, M_DEVBUF, M_NOWAIT,
|
||||
0ul, 0xfffffful, 4ul, 0x1000000);
|
||||
} else {
|
||||
/* Non-ISA based cards, 32 bit capable */
|
||||
#ifdef notyet
|
||||
/*
|
||||
* For the 32 bit driver we're not fussed where we DMA to
|
||||
* though it'll still need to be contiguous
|
||||
*/
|
||||
sc->recv_ring = malloc(lnc_mem_size, M_DEVBUF, M_NOWAIT);
|
||||
#else
|
||||
/*
|
||||
* For now it still needs to be below 16MB because the
|
||||
* descriptor's can only hold 16 bit addresses.
|
||||
*/
|
||||
sc->recv_ring = contigmalloc(lnc_mem_size, M_DEVBUF, M_NOWAIT,
|
||||
0ul, 0xfffffful, 4ul, 0x1000000);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (!sc->recv_ring) {
|
||||
log(LOG_ERR, "lnc%d: Couldn't allocate memory for NIC\n", unit);
|
||||
return (0); /* XXX -- attach failed -- not tested in
|
||||
* calling routines */
|
||||
if (sc->nic.ident == BICC) {
|
||||
skip = 2;
|
||||
} else {
|
||||
skip = 1;
|
||||
}
|
||||
|
||||
/* Set default mode */
|
||||
@ -890,9 +868,8 @@ lnc_attach_sc(lnc_softc_t *sc, int unit)
|
||||
/* Fill in arpcom structure entries */
|
||||
|
||||
sc->arpcom.ac_if.if_softc = sc;
|
||||
sc->arpcom.ac_if.if_name = lncdriver.name;
|
||||
sc->arpcom.ac_if.if_name = "lnc";
|
||||
sc->arpcom.ac_if.if_unit = unit;
|
||||
sc->arpcom.ac_if.if_mtu = ETHERMTU;
|
||||
sc->arpcom.ac_if.if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
|
||||
sc->arpcom.ac_if.if_timer = 0;
|
||||
sc->arpcom.ac_if.if_output = ether_output;
|
||||
@ -900,11 +877,16 @@ lnc_attach_sc(lnc_softc_t *sc, int unit)
|
||||
sc->arpcom.ac_if.if_ioctl = lnc_ioctl;
|
||||
sc->arpcom.ac_if.if_watchdog = lnc_watchdog;
|
||||
sc->arpcom.ac_if.if_init = lnc_init;
|
||||
sc->arpcom.ac_if.if_type = IFT_ETHER;
|
||||
sc->arpcom.ac_if.if_addrlen = ETHER_ADDR_LEN;
|
||||
sc->arpcom.ac_if.if_hdrlen = ETHER_HDR_LEN;
|
||||
sc->arpcom.ac_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
|
||||
|
||||
/* Extract MAC address from PROM */
|
||||
for (i = 0; i < ETHER_ADDR_LEN; i++)
|
||||
sc->arpcom.ac_enaddr[i] = inb(sc->iobase + (i * skip));
|
||||
|
||||
/*
|
||||
* XXX -- should check return status of if_attach
|
||||
*/
|
||||
|
||||
ether_ifattach(&sc->arpcom.ac_if, ETHER_BPF_SUPPORTED);
|
||||
|
||||
printf("lnc%d: ", unit);
|
||||
@ -922,14 +904,16 @@ static void
|
||||
lnc_init(xsc)
|
||||
void *xsc;
|
||||
{
|
||||
lnc_softc_t *sc = xsc;
|
||||
struct lnc_softc *sc = xsc;
|
||||
int s, i;
|
||||
char *lnc_mem;
|
||||
|
||||
/* Check that interface has valid address */
|
||||
|
||||
if (TAILQ_EMPTY(&sc->arpcom.ac_if.if_addrhead)) /* XXX unlikely */
|
||||
if (TAILQ_EMPTY(&sc->arpcom.ac_if.if_addrhead)) { /* XXX unlikely */
|
||||
printf("XXX no address?\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Shut down interface */
|
||||
|
||||
@ -947,8 +931,6 @@ lnc_init(xsc)
|
||||
* The alignment tests are particularly paranoid.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
sc->recv_next = 0;
|
||||
sc->trans_ring = sc->recv_ring + NDESC(sc->nrdre);
|
||||
sc->trans_next = 0;
|
||||
@ -1066,11 +1048,11 @@ lnc_init(xsc)
|
||||
write_csr(sc, CSR3, 0);
|
||||
|
||||
/* Let's see if it starts */
|
||||
|
||||
write_csr(sc, CSR0, INIT);
|
||||
for (i = 0; i < 1000; i++)
|
||||
if (read_csr(sc, CSR0) & IDON)
|
||||
break;
|
||||
/*
|
||||
printf("Enabling lnc interrupts\n");
|
||||
sc->arpcom.ac_if.if_timer = 10;
|
||||
write_csr(sc, CSR0, INIT|INEA);
|
||||
*/
|
||||
|
||||
/*
|
||||
* Now that the initialisation is complete there's no reason to
|
||||
@ -1079,6 +1061,11 @@ lnc_init(xsc)
|
||||
* time.
|
||||
*/
|
||||
|
||||
write_csr(sc, CSR0, INIT);
|
||||
for(i=0; i < 1000; i++)
|
||||
if (read_csr(sc, CSR0) & IDON)
|
||||
break;
|
||||
|
||||
if (read_csr(sc, CSR0) & IDON) {
|
||||
/*
|
||||
* Enable interrupts, start the LANCE, mark the interface as
|
||||
@ -1117,8 +1104,9 @@ lnc_init(xsc)
|
||||
*/
|
||||
|
||||
void
|
||||
lncintr_sc(lnc_softc_t *sc)
|
||||
lncintr(void *arg)
|
||||
{
|
||||
lnc_softc_t *sc = arg;
|
||||
int unit = sc->arpcom.ac_if.if_unit;
|
||||
u_short csr0;
|
||||
|
||||
@ -1137,10 +1125,20 @@ lncintr_sc(lnc_softc_t *sc)
|
||||
* be missed.
|
||||
*/
|
||||
|
||||
/* outw(sc->rdp, IDON | CERR | BABL | MISS | MERR | RINT | TINT | INEA); */
|
||||
outw(sc->rdp, csr0);
|
||||
/*outw(sc->rdp, IDON | CERR | BABL | MISS | MERR | RINT | TINT | INEA);*/
|
||||
|
||||
/* We don't do anything with the IDON flag */
|
||||
#ifdef notyet
|
||||
if (csr0 & IDON) {
|
||||
printf("IDON\n");
|
||||
sc->arpcom.ac_if.if_timer = 0;
|
||||
write_csr(sc, CSR0, STRT | INEA);
|
||||
sc->arpcom.ac_if.if_flags |= IFF_RUNNING;
|
||||
sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
|
||||
lnc_start(&sc->arpcom.ac_if);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (csr0 & ERR) {
|
||||
if (csr0 & CERR) {
|
||||
@ -1228,7 +1226,7 @@ static void
|
||||
lnc_start(struct ifnet *ifp)
|
||||
{
|
||||
|
||||
lnc_softc_t *sc = ifp->if_softc;
|
||||
struct lnc_softc *sc = ifp->if_softc;
|
||||
struct host_ring_entry *desc;
|
||||
int tmp;
|
||||
int end_of_packet;
|
||||
@ -1384,7 +1382,7 @@ static int
|
||||
lnc_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
|
||||
{
|
||||
|
||||
lnc_softc_t *sc = ifp->if_softc;
|
||||
struct lnc_softc *sc = ifp->if_softc;
|
||||
int s, error = 0;
|
||||
|
||||
s = splimp();
|
||||
@ -1462,7 +1460,7 @@ lnc_watchdog(struct ifnet *ifp)
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
lnc_dump_state(lnc_softc_t *sc)
|
||||
lnc_dump_state(struct lnc_softc *sc)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*-
|
||||
* Copyright (c) 2000
|
||||
* Paul Richards. All rights reserved.
|
||||
/*
|
||||
* Copyright (c) 1994-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
|
||||
@ -31,190 +31,41 @@
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <machine/bus_memio.h>
|
||||
#include <machine/bus_pio.h>
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/if_arp.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#include <isa/isavar.h>
|
||||
|
||||
#include <i386/isa/isa_device.h>
|
||||
#include <dev/lnc/if_lncvar.h>
|
||||
#include <dev/lnc/if_lncreg.h>
|
||||
#include <dev/lnc/if_lnc.h>
|
||||
|
||||
int ne2100_probe __P((lnc_softc_t *, unsigned));
|
||||
int bicc_probe __P((lnc_softc_t *, unsigned));
|
||||
int depca_probe __P((lnc_softc_t *, unsigned));
|
||||
#ifdef PC98
|
||||
int cnet98s_probe __P((lnc_softc_t *, unsigned));
|
||||
#endif
|
||||
int lance_probe __P((lnc_softc_t *));
|
||||
int pcnet_probe __P((lnc_softc_t *));
|
||||
int lnc_probe __P((struct isa_device *));
|
||||
int lnc_attach __P((struct isa_device *));
|
||||
static struct isa_pnp_id lnc_pnp_ids[] = {
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
static int dec_macaddr_extract __P((u_char[], lnc_softc_t *));
|
||||
static ointhand2_t lncintr;
|
||||
extern void write_csr(struct lnc_softc *, u_short, u_short);
|
||||
extern u_short read_csr(struct lnc_softc *, u_short);
|
||||
extern void lnc_release_resources(device_t);
|
||||
|
||||
extern int lnc_attach_sc __P((lnc_softc_t *, int));
|
||||
extern void lncintr_sc __P((lnc_softc_t *));
|
||||
|
||||
static lnc_softc_t *
|
||||
lnc_getsoftc(int unit)
|
||||
{
|
||||
static lnc_softc_t **sc;
|
||||
static int units;
|
||||
|
||||
if (unit >= units) {
|
||||
/* Reallocate more softc pointers */
|
||||
|
||||
lnc_softc_t **nsc;
|
||||
int n;
|
||||
|
||||
n = unit + 1;
|
||||
nsc = malloc(sizeof(lnc_softc_t *) * n, M_DEVBUF, M_WAITOK);
|
||||
if (units)
|
||||
bcopy(sc, nsc, sizeof(lnc_softc_t *) * units);
|
||||
bzero(nsc + units, sizeof(lnc_softc_t *) * (n - units));
|
||||
if (sc)
|
||||
free(sc, M_DEVBUF);
|
||||
units = n;
|
||||
sc = nsc;
|
||||
}
|
||||
|
||||
if (sc[unit] == NULL)
|
||||
sc[unit] = malloc(sizeof(lnc_softc_t), M_DEVBUF, M_WAITOK);
|
||||
|
||||
return sc[unit];
|
||||
}
|
||||
|
||||
int
|
||||
ne2100_probe(lnc_softc_t *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(lnc_softc_t *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[], lnc_softc_t * 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(lnc_softc_t *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(lnc_softc_t *sc)
|
||||
lance_probe(struct lnc_softc *sc)
|
||||
{
|
||||
write_csr(sc, CSR0, STOP);
|
||||
|
||||
if ((inw(sc->rdp) & STOP) && !(read_csr(sc, CSR3))) {
|
||||
if ((bus_space_read_2(sc->lnc_btag, sc->lnc_bhandle, 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
|
||||
@ -229,105 +80,237 @@ lance_probe(lnc_softc_t *sc)
|
||||
return (UNKNOWN);
|
||||
}
|
||||
|
||||
int
|
||||
pcnet_probe(lnc_softc_t *sc)
|
||||
static int
|
||||
lnc_legacy_probe(device_t dev)
|
||||
{
|
||||
u_long chip_id;
|
||||
int type;
|
||||
struct lnc_softc *sc = device_get_softc(dev);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
sc->portrid = 0;
|
||||
sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->portrid,
|
||||
0, ~0, 1, RF_ACTIVE);
|
||||
|
||||
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:
|
||||
case Am79C973:
|
||||
return (PCnet_FASTplus);
|
||||
case Am79C978:
|
||||
return (PCnet_Home);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! sc->portres) {
|
||||
device_printf(dev, "Failed to allocate I/O ports\n");
|
||||
lnc_release_resources(dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
return (type);
|
||||
}
|
||||
|
||||
int
|
||||
lnc_probe(struct isa_device * isa_dev)
|
||||
{
|
||||
int nports;
|
||||
int unit = isa_dev->id_unit;
|
||||
lnc_softc_t *sc = lnc_getsoftc(unit);
|
||||
unsigned iobase = isa_dev->id_iobase;
|
||||
sc->lnc_btag = rman_get_bustag(sc->portres);
|
||||
sc->lnc_bhandle = rman_get_bushandle(sc->portres);
|
||||
|
||||
#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;
|
||||
lnc_softc_t *sc = lnc_getsoftc(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
|
||||
* ether_ifattach() has been called in lnc_attach() ???
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
if ((sc->nic.mem_mode != SHMEM) &&
|
||||
(sc->nic.ic < PCnet_32))
|
||||
isa_dmacascade(isa_dev->id_drq);
|
||||
#endif
|
||||
sc->rap = BICC_RAP;
|
||||
sc->rdp = BICC_RDP;
|
||||
sc->nic.mem_mode = DMA_FIXED;
|
||||
/* XXX Should set BICC_IOSIZE et al somewhere to alloc
|
||||
resources correctly */
|
||||
|
||||
return result;
|
||||
if ((sc->nic.ic = lance_probe(sc))) {
|
||||
device_set_desc(dev, "BICC Isolan");
|
||||
sc->nic.ident = BICC;
|
||||
lnc_release_resources(dev);
|
||||
return (0);
|
||||
} else {
|
||||
/* It's not a BICC so try the standard NE2100 ports */
|
||||
sc->rap = PCNET_RAP;
|
||||
sc->rdp = PCNET_RDP;
|
||||
if ((sc->nic.ic = lance_probe(sc))) {
|
||||
sc->nic.ident = NE2100;
|
||||
device_set_desc(dev, "NE2100");
|
||||
lnc_release_resources(dev);
|
||||
return (0);
|
||||
} else {
|
||||
lnc_release_resources(dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
lnc_isa_probe(device_t dev)
|
||||
{
|
||||
int pnp;
|
||||
|
||||
pnp = ISA_PNP_PROBE(device_get_parent(dev), dev, lnc_pnp_ids);
|
||||
if (pnp == ENOENT) {
|
||||
/* It's not a PNP card, see if we support it by probing it */
|
||||
return (lnc_legacy_probe(dev));
|
||||
} else if (pnp == ENXIO) {
|
||||
return (ENXIO);
|
||||
} else {
|
||||
/* Found PNP card we support */
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
lncintr(int unit)
|
||||
lnc_alloc_callback(void *arg, bus_dma_segment_t *seg, int nseg, int error)
|
||||
{
|
||||
lncintr_sc(lnc_getsoftc(unit));
|
||||
/* Do nothing */
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
lnc_isa_attach(device_t dev)
|
||||
{
|
||||
lnc_softc_t *sc = device_get_softc(dev);
|
||||
int err = 0;
|
||||
bus_size_t lnc_mem_size;
|
||||
|
||||
device_printf(dev, "Attaching %s\n", device_get_desc(dev));
|
||||
|
||||
sc->portrid = 0;
|
||||
sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->portrid,
|
||||
0, ~0, 1, RF_ACTIVE);
|
||||
|
||||
if (! sc->portres) {
|
||||
device_printf(dev, "Failed to allocate I/O ports\n");
|
||||
lnc_release_resources(dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
sc->drqrid = 0;
|
||||
sc->drqres = bus_alloc_resource(dev, SYS_RES_DRQ, &sc->drqrid,
|
||||
0, ~0, 1, RF_ACTIVE);
|
||||
|
||||
if (! sc->drqres) {
|
||||
device_printf(dev, "Failed to allocate DMA channel\n");
|
||||
lnc_release_resources(dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
if (isa_get_irq(dev) == -1)
|
||||
bus_set_resource(dev, SYS_RES_IRQ, 0, 10, 1);
|
||||
|
||||
sc->irqrid = 0;
|
||||
sc->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqrid, 0, ~0, 1,
|
||||
RF_ACTIVE);
|
||||
|
||||
if (! sc->irqres) {
|
||||
device_printf(dev, "Failed to allocate irq\n");
|
||||
lnc_release_resources(dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
err = bus_setup_intr(dev, sc->irqres, INTR_TYPE_NET, lncintr,
|
||||
sc, &sc->intrhand);
|
||||
|
||||
if (err) {
|
||||
device_printf(dev, "Failed to setup irq handler\n");
|
||||
lnc_release_resources(dev);
|
||||
return (err);
|
||||
}
|
||||
|
||||
/* XXX temp setting for nic */
|
||||
sc->nic.mem_mode = DMA_FIXED;
|
||||
sc->nrdre = NRDRE;
|
||||
sc->ntdre = NTDRE;
|
||||
|
||||
if (sc->nic.ident == NE2100) {
|
||||
sc->rap = PCNET_RAP;
|
||||
sc->rdp = PCNET_RDP;
|
||||
sc->bdp = PCNET_BDP;
|
||||
} else {
|
||||
sc->rap = BICC_RAP;
|
||||
sc->rdp = BICC_RDP;
|
||||
}
|
||||
|
||||
printf("rap = %x\n", sc->rap);
|
||||
|
||||
/* Create a DMA tag describing the ring memory we need */
|
||||
|
||||
lnc_mem_size = ((NDESC(sc->nrdre) + NDESC(sc->ntdre)) *
|
||||
sizeof(struct host_ring_entry));
|
||||
|
||||
lnc_mem_size += (NDESC(sc->nrdre) * RECVBUFSIZE) +
|
||||
(NDESC(sc->ntdre) * TRANSBUFSIZE);
|
||||
|
||||
err = bus_dma_tag_create(NULL, /* parent */
|
||||
4, /* alignement */
|
||||
0, /* boundary */
|
||||
BUS_SPACE_MAXADDR_24BIT, /* lowaddr */
|
||||
BUS_SPACE_MAXADDR, /* highaddr */
|
||||
NULL, NULL, /* filter, filterarg */
|
||||
lnc_mem_size, /* segsize */
|
||||
1, /* nsegments */
|
||||
BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
|
||||
0, /* flags */
|
||||
&sc->dmat);
|
||||
|
||||
if (err) {
|
||||
device_printf(dev, "Can't create DMA tag\n");
|
||||
lnc_release_resources(dev);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
err = bus_dmamem_alloc(sc->dmat, (void **)&sc->recv_ring,
|
||||
BUS_DMA_NOWAIT, &sc->dmamap);
|
||||
|
||||
if (err) {
|
||||
device_printf(dev, "Couldn't allocate memory\n");
|
||||
lnc_release_resources(dev);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
err = bus_dmamap_load(sc->dmat, sc->dmamap, sc->recv_ring, lnc_mem_size,
|
||||
lnc_alloc_callback, sc->recv_ring, BUS_DMA_NOWAIT);
|
||||
|
||||
if (err) {
|
||||
device_printf(dev, "Couldn't load DMA map\n");
|
||||
lnc_release_resources(dev);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
isa_dmacascade(rman_get_start(sc->drqres));
|
||||
|
||||
/* Call generic attach code */
|
||||
if (! lnc_attach_common(dev)) {
|
||||
device_printf(dev, "Generic attach code failed\n");
|
||||
lnc_release_resources(dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
lnc_isa_detach(device_t dev)
|
||||
{
|
||||
lnc_softc_t *sc = device_get_softc(dev);
|
||||
int s = splimp();
|
||||
|
||||
ether_ifdetach(&sc->arpcom.ac_if, ETHER_BPF_SUPPORTED);
|
||||
splx(s);
|
||||
|
||||
lnc_stop(sc);
|
||||
lnc_release_resources(dev);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t lnc_isa_methods[] = {
|
||||
/* DEVMETHOD(device_identify, lnc_isa_identify), */
|
||||
DEVMETHOD(device_probe, lnc_isa_probe),
|
||||
DEVMETHOD(device_attach, lnc_isa_attach),
|
||||
DEVMETHOD(device_detach, lnc_isa_detach),
|
||||
#ifdef notyet
|
||||
DEVMETHOD(device_suspend, lnc_isa_suspend),
|
||||
DEVMETHOD(device_resume, lnc_isa_resume),
|
||||
DEVMETHOD(device_shutdown, lnc_isa_shutdown),
|
||||
#endif
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t lnc_isa_driver = {
|
||||
"lnc",
|
||||
lnc_isa_methods,
|
||||
sizeof(struct lnc_softc),
|
||||
};
|
||||
|
||||
static devclass_t lnc_devclass;
|
||||
|
||||
DRIVER_MODULE(lnc_isa, isa, lnc_isa_driver, lnc_devclass, 0, 0);
|
||||
|
@ -30,6 +30,8 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifdef notyet
|
||||
|
||||
#ifdef PC98
|
||||
#include "lnc.h"
|
||||
|
||||
@ -55,35 +57,6 @@
|
||||
int pcnet_probe __P((lnc_softc_t *sc));
|
||||
int cnet98s_probe __P((lnc_softc_t *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 */
|
||||
|
||||
int
|
||||
cnet98s_probe(lnc_softc_t *sc, unsigned iobase)
|
||||
{
|
||||
@ -144,4 +117,7 @@ cnet98s_probe(lnc_softc_t *sc, unsigned iobase)
|
||||
|
||||
return (CNET98S_IOSIZE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* notyet */
|
||||
|
@ -1,142 +1,220 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1996 Stefan Esser <se@freebsd.org>
|
||||
* All rights reserved.
|
||||
* Copyright (c) 1994-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 immediately at the beginning of the file, without modification,
|
||||
* this list of conditions, and the following disclaimer.
|
||||
* 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. Absolutely no warranty of function or purpose is made by the author
|
||||
* Stefan Esser.
|
||||
* 4. Modifications may be freely made to this file if the above conditions
|
||||
* are met.
|
||||
* 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 <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
|
||||
#include <machine/bus_memio.h>
|
||||
#include <machine/bus_pio.h>
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_arp.h>
|
||||
|
||||
#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 <dev/lnc/if_lnc.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#define AMD_VENDOR_ID 0x1022
|
||||
#define PCI_DEVICE_ID_PCNet_PCI 0x2000
|
||||
#define PCI_DEVICE_ID_PCHome_PCI 0x2001
|
||||
|
||||
#include <dev/lnc/if_lncvar.h>
|
||||
|
||||
#include "lnc.h"
|
||||
|
||||
#ifndef COMPAT_OLDPCI
|
||||
#error "The lnc device requires the old pci compatibility shims"
|
||||
#endif
|
||||
|
||||
#define PCI_DEVICE_ID_PCNet_PCI 0x20001022
|
||||
#define PCI_DEVICE_ID_PCHome_PCI 0x20011022
|
||||
|
||||
extern int pcnet_probe __P((lnc_softc_t *sc));
|
||||
extern int lnc_attach_sc __P((lnc_softc_t *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));
|
||||
|
||||
static u_long lnc_pci_count = NLNC;
|
||||
|
||||
static struct pci_device lnc_pci_driver = {
|
||||
"lnc",
|
||||
lnc_pci_probe,
|
||||
lnc_pci_attach,
|
||||
&lnc_pci_count,
|
||||
NULL
|
||||
};
|
||||
|
||||
COMPAT_PCI_DRIVER (lnc_pci, lnc_pci_driver);
|
||||
|
||||
static const char*
|
||||
lnc_pci_probe (pcici_t tag, pcidi_t type)
|
||||
static int
|
||||
lnc_pci_probe(device_t dev)
|
||||
{
|
||||
switch(type) {
|
||||
if (pci_get_vendor(dev) != AMD_VENDOR_ID)
|
||||
return (ENXIO);
|
||||
|
||||
switch(pci_get_device(dev)) {
|
||||
case PCI_DEVICE_ID_PCNet_PCI:
|
||||
return ("PCNet/PCI Ethernet adapter");
|
||||
device_set_desc(dev, "PCNet/PCI Ethernet adapter");
|
||||
return(0);
|
||||
break;
|
||||
case PCI_DEVICE_ID_PCHome_PCI:
|
||||
return ("PCHome/PCI Ethernet adapter");
|
||||
device_set_desc(dev, "PCHome/PCI Ethernet adapter");
|
||||
return(0);
|
||||
break;
|
||||
default:
|
||||
return (ENXIO);
|
||||
break;
|
||||
}
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
static void
|
||||
lnc_alloc_callback(void *arg, bus_dma_segment_t *seg, int nseg, int error)
|
||||
{
|
||||
/* Do nothing */
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
lnc_pci_attach(device_t dev)
|
||||
{
|
||||
lnc_softc_t *sc = device_get_softc(dev);
|
||||
unsigned command;
|
||||
int rid = 0;
|
||||
int err = 0;
|
||||
bus_size_t lnc_mem_size;
|
||||
|
||||
device_printf(dev, "Attaching %s\n", device_get_desc(dev));
|
||||
|
||||
command = pci_read_config(dev, PCIR_COMMAND, 4);
|
||||
command |= PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN;
|
||||
pci_write_config(dev, PCIR_COMMAND, command, 4);
|
||||
|
||||
rid = PCIR_MAPS;
|
||||
sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
|
||||
RF_ACTIVE);
|
||||
|
||||
if (! sc->portres)
|
||||
device_printf(dev, "Cannot allocate I/O ports\n");
|
||||
|
||||
rid = 0;
|
||||
sc->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
|
||||
RF_ACTIVE|RF_SHAREABLE);
|
||||
|
||||
if (! sc->irqres)
|
||||
device_printf(dev, "Cannot allocate irq\n");
|
||||
|
||||
err = bus_setup_intr(dev, sc->irqres, INTR_TYPE_NET, lncintr,
|
||||
sc, &sc->intrhand);
|
||||
if (err)
|
||||
device_printf(dev, "Cannot setup irq handler\n");
|
||||
|
||||
sc->iobase = rman_get_start(sc->portres);
|
||||
|
||||
/* XXX temp setting for nic */
|
||||
sc->nic.ic = PCnet_PCI;
|
||||
sc->nic.ident = NE2100;
|
||||
sc->nic.mem_mode = DMA_FIXED;
|
||||
sc->nrdre = NRDRE;
|
||||
sc->ntdre = NTDRE;
|
||||
sc->rap = sc->iobase + PCNET_RAP;
|
||||
sc->rdp = sc->iobase + PCNET_RDP;
|
||||
sc->bdp = sc->iobase + PCNET_BDP;
|
||||
|
||||
/* Create a DMA tag describing the ring memory we need */
|
||||
|
||||
lnc_mem_size = ((NDESC(sc->nrdre) + NDESC(sc->ntdre)) *
|
||||
sizeof(struct host_ring_entry));
|
||||
|
||||
lnc_mem_size += (NDESC(sc->nrdre) * RECVBUFSIZE) +
|
||||
(NDESC(sc->ntdre) * TRANSBUFSIZE);
|
||||
|
||||
err = bus_dma_tag_create(NULL, /* parent */
|
||||
1, /* alignement */
|
||||
0, /* boundary */
|
||||
BUS_SPACE_MAXADDR, /* lowaddr */
|
||||
BUS_SPACE_MAXADDR, /* highaddr */
|
||||
NULL, NULL, /* filter, filterarg */
|
||||
lnc_mem_size, /* segsize */
|
||||
1, /* nsegments */
|
||||
BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
|
||||
0, /* flags */
|
||||
&sc->dmat);
|
||||
|
||||
if (err) {
|
||||
device_printf(dev, "Can't create DMA tag\n");
|
||||
/* XXX need to free currently allocated resources here */
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
err = bus_dmamem_alloc(sc->dmat, (void **)&sc->recv_ring,
|
||||
BUS_DMA_NOWAIT, &sc->dmamap);
|
||||
|
||||
if (err) {
|
||||
device_printf(dev, "Couldn't allocate memory\n");
|
||||
/* XXX need to free currently allocated resources here */
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
bus_dmamap_load(sc->dmat, sc->dmamap, sc->recv_ring, lnc_mem_size,
|
||||
lnc_alloc_callback, sc->recv_ring, BUS_DMA_NOWAIT);
|
||||
|
||||
/* Call generic attach code */
|
||||
if (! lnc_attach_common(dev)) {
|
||||
device_printf(dev, "Generic attach code failed\n");
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void lncintr_sc (void*);
|
||||
|
||||
static void
|
||||
lnc_pci_attach(config_id, unit)
|
||||
pcici_t config_id;
|
||||
int unit;
|
||||
static int
|
||||
lnc_pci_detach(device_t dev)
|
||||
{
|
||||
lnc_softc_t *sc;
|
||||
unsigned iobase;
|
||||
unsigned data; /* scratch to make this device a bus master*/
|
||||
int i;
|
||||
lnc_softc_t *sc = device_get_softc(dev);
|
||||
int s = splimp();
|
||||
|
||||
if ( !pci_map_port(config_id,PCI_MAP_REG_START,(u_short *)&iobase) )
|
||||
printf("lnc%d: pci_port_map_attach failed?!\n",unit);
|
||||
ether_ifdetach(&sc->arpcom.ac_if, ETHER_BPF_SUPPORTED);
|
||||
|
||||
lnc_stop(sc);
|
||||
bus_teardown_intr(dev, sc->irqres, sc->intrhand);
|
||||
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irqres);
|
||||
bus_release_resource(dev, SYS_RES_IOPORT, PCIR_MAPS, sc->portres);
|
||||
|
||||
/* Make this device a bus master. This was implictly done by
|
||||
pci_map_port under 2.2.x -- tvf */
|
||||
bus_dmamap_unload(sc->dmat, sc->dmamap);
|
||||
bus_dmamem_free(sc->dmat, sc->recv_ring, sc->dmamap);
|
||||
bus_dma_tag_destroy(sc->dmat);
|
||||
|
||||
data = pci_cfgread(config_id, PCIR_COMMAND, 4);
|
||||
data |= PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN;
|
||||
pci_cfgwrite(config_id, PCIR_COMMAND, data, 4);
|
||||
|
||||
sc = malloc(sizeof *sc, M_DEVBUF, M_NOWAIT | M_ZERO);
|
||||
|
||||
if (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;
|
||||
splx(s);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t lnc_pci_methods[] = {
|
||||
DEVMETHOD(device_probe, lnc_pci_probe),
|
||||
DEVMETHOD(device_attach, lnc_pci_attach),
|
||||
DEVMETHOD(device_detach, lnc_pci_detach),
|
||||
#ifdef notyet
|
||||
DEVMETHOD(device_suspend, lnc_pci_suspend),
|
||||
DEVMETHOD(device_resume, lnc_pci_resume),
|
||||
DEVMETHOD(device_shutdown, lnc_pci_shutdown),
|
||||
#endif
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t lnc_pci_driver = {
|
||||
"lnc",
|
||||
lnc_pci_methods,
|
||||
sizeof(struct lnc_softc),
|
||||
};
|
||||
|
||||
static devclass_t lnc_devclass;
|
||||
|
||||
DRIVER_MODULE(lnc_pci, pci, lnc_pci_driver, lnc_devclass, 0, 0);
|
||||
|
@ -192,3 +192,31 @@ struct mds {
|
||||
#define RTRY 0x0400 /* Tried 16 times */
|
||||
#define TDR 0x03FF /* Time domain reflectometry */
|
||||
|
||||
/* 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 */
|
||||
|
@ -33,6 +33,8 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <dev/lnc/if_lncreg.h>
|
||||
|
||||
/*
|
||||
* Initialize multicast address hashing registers to accept
|
||||
* all multicasts (only used when in promiscuous mode)
|
||||
@ -76,6 +78,20 @@
|
||||
/* 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 */
|
||||
@ -101,7 +117,7 @@
|
||||
#define Am79C970A 0x2621
|
||||
#define Am79C971 0x2623
|
||||
#define Am79C972 0x2624
|
||||
#define Am79C973 0x2625
|
||||
#define Am79C972 0x2625
|
||||
#define Am79C978 0x2626
|
||||
|
||||
/* Board types */
|
||||
@ -135,22 +151,6 @@
|
||||
#define TRANS_MD3 \
|
||||
"\20\6BUFF\5UFLO\4RES\3LCOL\2LCAR\1RTRY"
|
||||
|
||||
struct nic_info {
|
||||
int ident; /* Type of card */
|
||||
int ic; /* Type of ic, Am7990, Am79C960 etc. */
|
||||
int mem_mode;
|
||||
int iobase;
|
||||
int mode; /* Mode setting at initialization */
|
||||
};
|
||||
|
||||
struct host_ring_entry {
|
||||
struct mds *md;
|
||||
union {
|
||||
struct mbuf *mbuf;
|
||||
char *data;
|
||||
}buff;
|
||||
};
|
||||
|
||||
#ifdef LNC_KEEP_STATS
|
||||
#define LNCSTATS_STRUCT \
|
||||
struct lnc_stats { \
|
||||
@ -186,17 +186,38 @@ struct host_ring_entry {
|
||||
#define LNCSTATS(X)
|
||||
#endif
|
||||
|
||||
struct nic_info {
|
||||
int ident; /* Type of card */
|
||||
int ic; /* Type of ic, Am7990, Am79C960 etc. */
|
||||
int mem_mode;
|
||||
int iobase;
|
||||
int mode; /* Mode setting at initialization */
|
||||
};
|
||||
|
||||
typedef struct lnc_softc {
|
||||
struct arpcom arpcom; /* see ../../net/if_arp.h */
|
||||
struct nic_info nic; /* NIC specific info */
|
||||
struct resource *irqres;
|
||||
int irqrid;
|
||||
struct resource *drqres;
|
||||
int drqrid;
|
||||
struct resource *portres;
|
||||
int portrid;
|
||||
int iobase;
|
||||
bus_space_tag_t lnc_btag;
|
||||
bus_space_handle_t lnc_bhandle;
|
||||
void *intrhand;
|
||||
bus_dma_tag_t dmat;
|
||||
bus_dmamap_t dmamap;
|
||||
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 */
|
||||
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;
|
||||
@ -204,12 +225,20 @@ typedef struct lnc_softc {
|
||||
int rap;
|
||||
int rdp;
|
||||
int bdp;
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG
|
||||
int lnc_debug;
|
||||
#endif
|
||||
#endif
|
||||
LNCSTATS_STRUCT
|
||||
} lnc_softc_t;
|
||||
|
||||
struct host_ring_entry {
|
||||
struct mds *md;
|
||||
union {
|
||||
struct mbuf *mbuf;
|
||||
char *data;
|
||||
}buff;
|
||||
};
|
||||
|
||||
#define NDESC(len2) (1 << len2)
|
||||
|
||||
#define INC_MD_PTR(ptr, no_entries) \
|
||||
@ -223,16 +252,7 @@ typedef struct lnc_softc {
|
||||
#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(lnc_softc_t *sc, u_short port, u_short val)
|
||||
{
|
||||
outw(sc->rap, port);
|
||||
outw(sc->rdp, val);
|
||||
}
|
||||
|
||||
static __inline u_short
|
||||
read_csr(lnc_softc_t *sc, u_short port)
|
||||
{
|
||||
outw(sc->rap, port);
|
||||
return (inw(sc->rdp));
|
||||
}
|
||||
/* Functional declarations */
|
||||
extern int lnc_attach_common __P((device_t));
|
||||
extern void lnc_stop __P((struct lnc_softc *));
|
||||
extern driver_intr_t lncintr;
|
||||
|
Loading…
x
Reference in New Issue
Block a user