summaryrefslogtreecommitdiffstats
path: root/sys/dev/ep
diff options
context:
space:
mode:
authorjkh <jkh@FreeBSD.org>1995-03-31 06:41:38 +0000
committerjkh <jkh@FreeBSD.org>1995-03-31 06:41:38 +0000
commitab22dad2bd3d2a38d0c059f515f9dd9562cdfb20 (patch)
tree30900547a2959cd787db59b242b9bc879d5cec39 /sys/dev/ep
parent71b8fc1b02199deafd8b0417017ee45e4f415ee5 (diff)
downloadFreeBSD-src-ab22dad2bd3d2a38d0c059f515f9dd9562cdfb20.zip
FreeBSD-src-ab22dad2bd3d2a38d0c059f515f9dd9562cdfb20.tar.gz
* Promiscuous mode added and interrupt logic slightly changed
* to reduce the number of adapter failures. Transceiver select * logic changed to use value from EEPROM. Autoconfiguration * features added. Submitted by: "Serge A. Babkin" <babkin@hq.icb.chel.su>
Diffstat (limited to 'sys/dev/ep')
-rw-r--r--sys/dev/ep/if_ep.c207
-rw-r--r--sys/dev/ep/if_epreg.h32
2 files changed, 189 insertions, 50 deletions
diff --git a/sys/dev/ep/if_ep.c b/sys/dev/ep/if_ep.c
index 4f2175f..6169633 100644
--- a/sys/dev/ep/if_ep.c
+++ b/sys/dev/ep/if_ep.c
@@ -27,7 +27,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: if_ep.c,v 1.21 1995/03/23 07:31:08 gibbs Exp $
+ * if_ep.c,v 1.19 1995/01/24 20:53:45 davidg Exp
*/
/*
@@ -37,6 +37,19 @@
* avega@sophia.inria.fr
*/
+/*
+ * March 28 1995
+ *
+ * Promiscuous mode added and interrupt logic slightly changed
+ * to reduce the number of adapter failures. Transceiver select
+ * logic changed to use value from EEPROM. Autoconfiguration
+ * features added.
+ * Done by:
+ * Serge Babkin
+ * Chelindbank (Chelyabinsk, Russia)
+ * babkin@hq.icb.chel.su
+ */
+
#include "ep.h"
#if NEP > 0
@@ -114,7 +127,8 @@ struct ep_softc ep_softc[NEP];
struct isa_driver epdriver = {
epprobe,
epattach,
- "ep"
+ "ep",
+ 0
};
static struct kern_devconf kdc_ep[NEP] = { {
@@ -139,7 +153,11 @@ ep_registerdev(struct isa_device *id)
int ep_current_tag = EP_LAST_TAG + 1;
-int ep_board[EP_MAX_BOARDS + 1];
+struct {
+ int epb_addr; /* address of this board */
+ char epb_used; /* was this entry already used for configuring ? */
+ }
+ ep_board[EP_MAX_BOARDS + 1];
static int
eeprom_rdy(is)
@@ -184,7 +202,8 @@ ep_look_for_board_at(is)
* Once activated, all the registers are mapped in the range
* x000 - x00F, where x is the slot number.
*/
- ep_board[neisa++] = j * EP_EISA_START;
+ ep_board[neisa].epb_used = 0;
+ ep_board[neisa++].epb_addr = j * EP_EISA_START;
}
ep_current_tag--;
@@ -204,38 +223,61 @@ ep_look_for_board_at(is)
for (j = 0; j < 3; j++)
data = get_eeprom_data(id_port, j);
- ep_board[neisa+nisa++] =
+ ep_board[neisa+nisa].epb_used = 0;
+ ep_board[neisa+nisa++].epb_addr =
(get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200;
outb(id_port, ep_current_tag); /* tags board */
outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG);
ep_current_tag--;
}
- ep_board[neisa+nisa] = 0;
+ ep_board[neisa+nisa].epb_addr = 0;
if (neisa) {
printf("%d 3C5x9 board(s) on EISA found at", neisa);
- for (j = 0; ep_board[j]; j++)
- if (ep_board[j] >= EP_EISA_START)
- printf(" 0x%x", ep_board[j]);
+ for (j = 0; ep_board[j].epb_addr; j++)
+ if (ep_board[j].epb_addr >= EP_EISA_START)
+ printf(" 0x%x", ep_board[j].epb_addr);
printf("\n");
}
if (nisa) {
printf("%d 3C5x9 board(s) on ISA found at", nisa);
- for (j = 0; ep_board[j]; j++)
- if (ep_board[j] < EP_EISA_START)
- printf(" 0x%x", ep_board[j]);
+ for (j = 0; ep_board[j].epb_addr; j++)
+ if (ep_board[j].epb_addr < EP_EISA_START)
+ printf(" 0x%x", ep_board[j].epb_addr);
printf("\n");
}
}
- for (i = 0; ep_board[i] && ep_board[i] != IS_BASE; i++);
- if (ep_board[i] == IS_BASE) {
+ /* we have two cases:
+ *
+ * 1. Device was configured with 'port ?'
+ * In this case we search for the first unused card in list
+ *
+ * 2. Device was configured with 'port xxx'
+ * In this case we search for the unused card with that address
+ *
+ */
+
+ if(IS_BASE==-1) { /* port? */
+ for (i = 0; ep_board[i].epb_addr && ep_board[i].epb_used; i++);
+ if(ep_board[i].epb_addr==0)
+ return 0;
+
+ IS_BASE=ep_board[i].epb_addr;
+ ep_board[i].epb_used=1;
+ return 1;
+ } else {
+ for (i=0; ep_board[i].epb_addr && ep_board[i].epb_addr != IS_BASE; i++);
+
+ if( ep_board[i].epb_used || ep_board[i].epb_addr != IS_BASE)
+ return 0;
+
if (inw(IS_BASE + EP_W0_EEPROM_COMMAND) & EEPROM_TST_MODE)
printf("ep%d: 3c5x9 at 0x%x in test mode. Erase pencil mark!\n",
is->id_unit, IS_BASE);
- return (1);
+ ep_board[i].epb_used=1;
+ return 1;
}
- return (0);
}
/*
@@ -278,9 +320,19 @@ epprobe(is)
k = get_e(is, EEPROM_RESOURCE_CFG);
k >>= 12;
- if (is->id_irq != (1 << ((k == 2) ? 9 : k))) {
- printf("epprobe: interrupt number %d doesn't match\n",is->id_irq);
- return (0);
+
+ /* Now we have two cases again:
+ *
+ * 1. Device was configured with 'irq?'
+ * In this case we use irq read from the board
+ *
+ * 2. Device was configured with 'irq xxx'
+ * In this case we set up the board to use specified interrupt
+ *
+ */
+
+ if(is->id_irq==0) { /* irq? */
+ is->id_irq= 1 << ( (k==2) ? 9 : k );
}
if (BASE >= EP_EISA_START) /* we have an EISA board, we allow 32 bits access */
@@ -304,6 +356,7 @@ epattach(is)
u_short i, j, *p;
struct ifaddr *ifa;
struct sockaddr_dl *sdl;
+ int irq;
/* BASE = IS_BASE; */
sc->ep_io_addr = is->id_iobase;
@@ -312,7 +365,7 @@ epattach(is)
sc->ep_connectors = 0;
i = inw(IS_BASE + EP_W0_CONFIG_CTRL);
- j = inw(IS_BASE + EP_W0_ADDRESS_CFG) >> 14;
+ j = inw(IS_BASE + EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS;
if (i & IS_AUI) {
printf("aui");
sc->ep_connectors |= AUI;
@@ -344,7 +397,25 @@ epattach(is)
GO_WINDOW(2);
outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(p[i]));
}
- printf(" address %s\n", ether_sprintf(sc->arpcom.ac_enaddr));
+ printf(" address %s", ether_sprintf(sc->arpcom.ac_enaddr));
+
+ /*
+ * Write IRQ value to board
+ */
+
+ i=is->id_irq;
+ if(i==0) {
+ printf(" irq STRANGE\n");
+ return 0;
+ }
+
+ for(irq=0; !(i & 1) && irq<16 ; i>>=1, irq++);
+
+ if(irq==9)
+ irq=2;
+ printf(" irq %d\n",irq);
+ GO_WINDOW(0);
+ outw(BASE + EP_W0_RESOURCE_CFG, SET_IRQ(irq));
ifp->if_unit = is->id_unit;
ifp->if_name = "ep";
@@ -418,7 +489,7 @@ epinit(unit)
{
register struct ep_softc *sc = &ep_softc[unit];
register struct ifnet *ifp = &sc->arpcom.ac_if;
- int s, i;
+ int s, i, j;
if (ifp->if_addrlist == (struct ifaddr *) 0)
return;
@@ -427,6 +498,10 @@ epinit(unit)
while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
GO_WINDOW(0);
+ outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
+ GO_WINDOW(4);
+ outw(BASE + EP_W4_MEDIA_TYPE, DISABLE_UTP);
+ GO_WINDOW(0);
/* Disable the card */
outw(BASE + EP_W0_CONFIG_CTRL, 0);
@@ -455,39 +530,68 @@ epinit(unit)
outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS);
- if(ep_ftst(F_PROMISC))
+ if(ifp->if_flags & IFF_PROMISC)
outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
FIL_GROUP | FIL_BRDCST | FIL_ALL);
else
outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
FIL_GROUP | FIL_BRDCST);
- /*
- * you can `ifconfig ep0 (bnc|aui)' to get the following
- * behaviour:
- * bnc disable AUI/UTP. enable BNC.
- * aui disable BNC. enable AUI. if the card has a UTP
- * connector, that is enabled too. not sure, but it
- * seems you have to be careful to not plug things
- * into both AUI & UTP.
- */
-#if defined(__NetBSD__)
- if (!(ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & BNC)) {
-#else
- if (!(ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & BNC)) {
-#endif
+ /*
+ * S.B.
+ *
+ * Now behavior was slightly changed:
+ *
+ * if any of flags link[0-2] is used and its connector is
+ * physically present the following connectors are used:
+ *
+ * link0 - AUI * highest precedence
+ * link1 - BNC
+ * link2 - UTP * lowest precedence
+ *
+ * If none of them is specified then
+ * connector specified in the EEPROM is used
+ * (if present on card or AUI if not).
+ *
+ */
+
+ if(ifp->if_flags & IFF_LINK0 && sc->ep_connectors & AUI) {
+ /* nothing */
+ } else if(ifp->if_flags & IFF_LINK1 && sc->ep_connectors & BNC) {
outw(BASE + EP_COMMAND, START_TRANSCEIVER);
DELAY(1000);
- }
-#if defined(__NetBSD__)
- if ((ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & UTP)) {
-#else
- if ((ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & UTP)) {
-#endif
+ } else if(ifp->if_flags & IFF_LINK2 && sc->ep_connectors & UTP) {
GO_WINDOW(4);
outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP);
GO_WINDOW(1);
+ } else {
+ GO_WINDOW(0);
+ j = inw(BASE + EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS;
+ GO_WINDOW(1);
+ switch(j) {
+ case ACF_CONNECTOR_UTP:
+ if(sc->ep_connectors & UTP) {
+ GO_WINDOW(4);
+ outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP);
+ GO_WINDOW(1);
+ }
+ break;
+ case ACF_CONNECTOR_BNC:
+ if(sc->ep_connectors & BNC) {
+ outw(BASE + EP_COMMAND, START_TRANSCEIVER);
+ DELAY(1000);
+ }
+ break;
+ case ACF_CONNECTOR_AUI:
+ /* nothing to do */
+ break;
+ default:
+ printf("ep%d: strange connector type in EEPROM: assuming AUI\n",
+ unit);
+ break;
+ }
}
+
outw(BASE + EP_COMMAND, RX_ENABLE);
outw(BASE + EP_COMMAND, TX_ENABLE);
@@ -654,16 +758,16 @@ epintr(unit)
rescan:
while ((status = inw(BASE + EP_STATUS)) & S_5_INTS) {
+
+ /* first acknowledge all interrupt sources */
+ outw(BASE + EP_COMMAND, ACK_INTR | (status & S_MASK));
+
if (status & (S_RX_COMPLETE | S_RX_EARLY)) {
- /* we just need ACK for RX_EARLY */
- if (status & S_RX_EARLY)
- outw(BASE + EP_COMMAND, C_RX_EARLY);
epread(sc);
continue;
}
if (status & S_TX_AVAIL) {
/* we need ACK */
- outw(BASE + EP_COMMAND, C_TX_AVAIL);
sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
epstart(&sc->arpcom.ac_if);
}
@@ -722,8 +826,6 @@ rescan:
} /* while */
} /* end TX_COMPLETE */
}
- /* re-enable ints */
- /* outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS); */
outw(BASE + EP_COMMAND, C_INTR_LATCH); /* ACK int Latch */
@@ -1025,7 +1127,14 @@ epioctl(ifp, cmd, data)
epstop(ifp->if_unit);
epmbufempty(sc);
break;
+ } else {
+ /* reinitialize card on any parameter change */
+ epinit(ifp->if_unit);
+ break;
}
+
+ /* NOTREACHED */
+
if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0)
epinit(ifp->if_unit);
diff --git a/sys/dev/ep/if_epreg.h b/sys/dev/ep/if_epreg.h
index 86942a8..c91c7ac 100644
--- a/sys/dev/ep/if_epreg.h
+++ b/sys/dev/ep/if_epreg.h
@@ -19,7 +19,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: if_epreg.h,v 1.4 1994/11/13 10:12:37 gibbs Exp $ Modified by:
+ * if_epreg.h,v 1.4 1994/11/13 10:12:37 gibbs Exp Modified by:
*
October 2, 1994
@@ -30,6 +30,18 @@
finger: avega@pax.inria.fr
*/
+/*
+ * March 28 1995
+ *
+ * Promiscuous mode added and interrupt logic slightly changed
+ * to reduce the number of adapter failures. Transceiver select
+ * logic changed to use value from EEPROM. Autoconfiguration
+ * features added.
+ * Done by:
+ * Serge Babkin
+ * Chelindbank (Chelyabinsk, Russia)
+ * babkin@hq.icb.chel.su
+ */
/*
* Ethernet software status per interface.
@@ -287,6 +299,7 @@ struct ep_softc {
#define C_RX_EARLY (u_short) (ACK_INTR|0x20)
#define C_INT_RQD (u_short) (ACK_INTR|0x40)
#define C_UPD_STATS (u_short) (ACK_INTR|0x80)
+#define C_MASK (u_short) 0xFF /* mask of C_* */
/*
* Status register. All windows.
@@ -314,10 +327,27 @@ struct ep_softc {
#define S_RX_EARLY (u_short) (0x20)
#define S_INT_RQD (u_short) (0x40)
#define S_UPD_STATS (u_short) (0x80)
+#define S_MASK (u_short) 0xFF /* mask of S_* */
#define S_5_INTS (S_CARD_FAILURE|S_TX_COMPLETE|\
S_TX_AVAIL|S_RX_COMPLETE|S_RX_EARLY)
#define S_COMMAND_IN_PROGRESS (u_short) (0x1000)
+/* Address Config. Register.
+ * Window 0/Port 06
+ */
+
+#define ACF_CONNECTOR_BITS 14
+#define ACF_CONNECTOR_UTP 0
+#define ACF_CONNECTOR_AUI 1
+#define ACF_CONNECTOR_BNC 3
+
+/* Resource configuration register.
+ * Window 0/Port 08
+ *
+ */
+
+#define SET_IRQ(i) (((i)<<12) | 0xF00) /* set IRQ i */
+
/*
* FIFO Registers.
* RX Status. Window 1/Port 08
OpenPOWER on IntegriCloud