diff options
author | jkh <jkh@FreeBSD.org> | 1995-03-31 06:41:38 +0000 |
---|---|---|
committer | jkh <jkh@FreeBSD.org> | 1995-03-31 06:41:38 +0000 |
commit | ab22dad2bd3d2a38d0c059f515f9dd9562cdfb20 (patch) | |
tree | 30900547a2959cd787db59b242b9bc879d5cec39 /sys/dev/ep | |
parent | 71b8fc1b02199deafd8b0417017ee45e4f415ee5 (diff) | |
download | FreeBSD-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.c | 207 | ||||
-rw-r--r-- | sys/dev/ep/if_epreg.h | 32 |
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 |