Return to BSD News archive
Path: euryale.cc.adfa.oz.au!newshost.anu.edu.au!harbinger.cc.monash.edu.au!simtel!pravda.aa.msen.com!news1.best.com!shellx.best.com!hokianga.live.com!user From: finlayson@live.com (Ross Finlayson) Newsgroups: comp.unix.bsd.freebsd.misc Subject: Re: Multicast support in the 3COM 3C509B (ep0) driver? Date: Mon, 20 Nov 1995 01:51:29 -0800 Organization: Live Networks, Inc. Lines: 605 Distribution: world Message-ID: <finlayson-2011950151290001@hokianga.live.com> References: <finlayson-1811950121040001@hokianga.live.com> <48mp5g$4eh@phantom.min.ntt.jp> NNTP-Posting-Host: hokianga.live.com In article <48mp5g$4eh@phantom.min.ntt.jp>, ishizuka@isis.min.ntt.jp (Masachika ISHIZUKA) wrote: > I don't know why the 3c509b driver with 2.1.0-XXX does not > support multicast addressing, but patches for 3c509 driver > can be found by using http://www.freebsd.com/search.html. Thanks for the tip. I was able to find the following patch (by Serge Babkin@hq.icb.chel.su) in the mail archive. (I'm repeating it below, in case it didn't make it into the 2.1.0 release.) Ross. =============== CUT HERE ============================= *** if_ep.c Mon Oct 23 08:25:55 1995 --- /sys/i386/isa/if_ep.c Wed Oct 18 12:30:37 1995 *************** *** 87,92 **** --- 85,95 ---- #include <netns/ns_if.h> #endif + #ifdef IPX + #include <netipx/ipx.h> + #include <netipx/ipx_if.h> + #endif + #if NBPFILTER > 0 #include <net/bpf.h> #include <net/bpfdesc.h> *************** *** 100,105 **** --- 103,109 ---- #include <i386/isa/isa_device.h> #include <i386/isa/icu.h> #include <i386/isa/if_epreg.h> + #include <i386/isa/elink.h> static int epprobe __P((struct isa_device *)); static int epattach __P((struct isa_device *)); *************** *** 117,122 **** --- 121,127 ---- static int send_ID_sequence __P((int)); static int get_eeprom_data __P((int, int)); + static struct ep_board *ep_look_for_board_at(struct isa_device *); struct ep_softc ep_softc[NEP]; *************** *** 132,145 **** }; static struct kern_devconf kdc_ep[NEP] = { { ! 0, 0, 0, /* filled in by dev_attach */ "ep", 0, { MDDT_ISA, 0, "net" }, isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, ! &kdc_isa0, /* parent */ ! 0, /* parentdata */ ! DC_UNCONFIGURED, /* state */ "3Com 3C509 Ethernet adapter", ! DC_CLS_NETIF /* class */ } }; static inline void --- 137,150 ---- }; static struct kern_devconf kdc_ep[NEP] = { { ! 0, 0, 0, /* filled in by dev_attach */ "ep", 0, { MDDT_ISA, 0, "net" }, isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, ! &kdc_isa0, /* parent */ ! 0, /* parentdata */ ! DC_UNCONFIGURED, /* state */ "3Com 3C509 Ethernet adapter", ! DC_CLS_NETIF /* class */ } }; static inline void *************** *** 154,164 **** int ep_current_tag = EP_LAST_TAG + 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) --- 159,165 ---- int ep_current_tag = EP_LAST_TAG + 1; ! struct ep_board ep_board[EP_MAX_BOARDS + 1]; static int eeprom_rdy(is) *************** *** 174,184 **** return (1); } ! static int ep_look_for_board_at(is) struct isa_device *is; { ! int data, i, j, io_base, id_port = EP_ID_PORT; int nisa = 0, neisa = 0; if (ep_current_tag == (EP_LAST_TAG + 1)) { --- 175,185 ---- return (1); } ! static struct ep_board * ep_look_for_board_at(is) struct isa_device *is; { ! int data, i, j, io_base, id_port = ELINK_ID_PORT; int nisa = 0, neisa = 0; if (ep_current_tag == (EP_LAST_TAG + 1)) { *************** *** 203,232 **** * Once activated, all the registers are mapped in the range * x000 - x00F, where x is the slot number. */ ep_board[neisa].epb_used = 0; ep_board[neisa++].epb_addr = j * EP_EISA_START; } ep_current_tag--; /* Look for the ISA boards. Init and leave them actived */ outb(id_port, 0xc0); /* Global reset */ DELAY(10000); for (i = 0; i < EP_MAX_BOARDS; i++) { outb(id_port, 0); outb(id_port, 0); send_ID_sequence(id_port); data = get_eeprom_data(id_port, EEPROM_MFG_ID); if (data != MFG_ID) break; /* resolve contention using the Ethernet address */ for (j = 0; j < 3; j++) ! data = get_eeprom_data(id_port, j); 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--; --- 204,265 ---- * Once activated, all the registers are mapped in the range * x000 - x00F, where x is the slot number. */ + ep_board[neisa].epb_isa = 0; ep_board[neisa].epb_used = 0; ep_board[neisa++].epb_addr = j * EP_EISA_START; } ep_current_tag--; /* Look for the ISA boards. Init and leave them actived */ + outb(id_port, 0); + outb(id_port, 0); + + #if 0 + send_ID_sequence(id_port); + #else + elink_idseq(0xCF); + #endif + + #if 0 outb(id_port, 0xc0); /* Global reset */ + #else + elink_reset(); + #endif DELAY(10000); for (i = 0; i < EP_MAX_BOARDS; i++) { outb(id_port, 0); outb(id_port, 0); + #if 0 send_ID_sequence(id_port); + #else + elink_idseq(0xCF); + #endif data = get_eeprom_data(id_port, EEPROM_MFG_ID); if (data != MFG_ID) break; /* resolve contention using the Ethernet address */ + + for (j = 0; j < 3; j++) + get_eeprom_data(id_port, j); + + /* and save this address for later use */ + for (j = 0; j < 3; j++) ! ep_board[neisa+nisa].eth_addr[j] = get_eeprom_data(id_port, j); + ep_board[neisa+nisa].res_cfg = + get_eeprom_data(id_port, EEPROM_RESOURCE_CFG); + + ep_board[neisa+nisa].prod_id = + get_eeprom_data(id_port, EEPROM_PROD_ID); + + ep_board[neisa].epb_isa = 1; 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--; *************** *** 266,283 **** 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); ep_board[i].epb_used=1; ! return 1; } } --- 299,318 ---- IS_BASE=ep_board[i].epb_addr; ep_board[i].epb_used=1; ! ! return &ep_board[i]; } 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); ep_board[i].epb_used=1; ! ! return &ep_board[i]; } } *************** *** 308,327 **** ep_registerdev(is); ! if (!ep_look_for_board_at(is)) return (0); /* * The iobase was found and MFG_ID was 0x6d50. PROD_ID should be * 0x9[0-f]50 */ GO_WINDOW(0); ! k = get_e(is, EEPROM_PROD_ID); if ((k & 0xf0ff) != (PROD_ID & 0xf0ff)) { printf("epprobe: ignoring model %04x\n", k); return (0); } ! k = get_e(is, EEPROM_RESOURCE_CFG); k >>= 12; /* Now we have two cases again: --- 343,363 ---- ep_registerdev(is); ! if(( sc->epb=ep_look_for_board_at(is) )==0) return (0); /* * The iobase was found and MFG_ID was 0x6d50. PROD_ID should be * 0x9[0-f]50 */ GO_WINDOW(0); ! k = sc->epb->epb_isa ? sc->epb->prod_id : get_e(is, EEPROM_PROD_ID); if ((k & 0xf0ff) != (PROD_ID & 0xf0ff)) { printf("epprobe: ignoring model %04x\n", k); return (0); } ! k = sc->epb->epb_isa ? sc->epb->res_cfg : get_e(is, EEPROM_RESOURCE_CFG); ! k >>= 12; /* Now we have two cases again: *************** *** 396,402 **** p = (u_short *) & sc->arpcom.ac_enaddr; for (i = 0; i < 3; i++) { GO_WINDOW(0); ! p[i] = htons(get_e(is, i)); GO_WINDOW(2); outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(p[i])); } --- 432,438 ---- p = (u_short *) & sc->arpcom.ac_enaddr; for (i = 0; i < 3; i++) { GO_WINDOW(0); ! p[i] = htons( sc->epb->epb_isa ? sc->epb->eth_addr[i] : get_e(is, i) ); GO_WINDOW(2); outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(p[i])); } *************** *** 423,429 **** ifp->if_unit = is->id_unit; ifp->if_name = "ep"; ifp->if_mtu = ETHERMTU; ! ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; ifp->if_init = epinit; ifp->if_output = ether_output; ifp->if_start = epstart; --- 459,466 ---- ifp->if_unit = is->id_unit; ifp->if_name = "ep"; ifp->if_mtu = ETHERMTU; ! ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | ! IFF_SIMPLEX | IFF_NOTRAILERS; ifp->if_init = epinit; ifp->if_output = ether_output; ifp->if_start = epstart; *************** *** 432,438 **** ifp->if_timer=1; if_attach(ifp); ! kdc_ep[is->id_unit].kdc_state = DC_BUSY; /* * Fill the hardware address into ifa_addr if we find an AF_LINK entry. --- 469,477 ---- ifp->if_timer=1; if_attach(ifp); ! ! /* device attach does transition from UNCONFIGURED to IDLE state */ ! kdc_ep[is->id_unit].kdc_state=DC_IDLE; /* * Fill the hardware address into ifa_addr if we find an AF_LINK entry. *************** *** 475,481 **** #endif ep_fset(F_RX_FIRST); sc->top = sc->mcur = 0; ! #if NBPFILTER > 0 bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); #endif --- 514,520 ---- #endif ep_fset(F_RX_FIRST); sc->top = sc->mcur = 0; ! #if NBPFILTER > 0 bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); #endif *************** *** 536,547 **** outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS); ! 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); /* * S.B. --- 575,586 ---- outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS); ! 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); /* * S.B. *************** *** 814,820 **** sc->rx_no_first, sc->rx_no_mbuf, sc->rx_bpf_disc, sc->rx_overrunf, sc->rx_overrunl, sc->tx_underrun); #else ! printf("ep%d: Status: %x\n", unit, status); #endif epinit(unit); splx(x); --- 853,865 ---- sc->rx_no_first, sc->rx_no_mbuf, sc->rx_bpf_disc, sc->rx_overrunf, sc->rx_overrunl, sc->tx_underrun); #else ! ! #ifdef nightmaremessages ! printf("ep%d: Status: %x (input buffer overflow)\n", unit, status); ! #else ! ++sc->arpcom.ac_if.if_ierrors; ! #endif ! #endif epinit(unit); splx(x); *************** *** 1129,1139 **** struct ifreq *ifr = (struct ifreq *) data; int s, error = 0; ! s = splimp(); switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; switch (ifa->ifa_addr->sa_family) { #ifdef INET case AF_INET: --- 1174,1188 ---- struct ifreq *ifr = (struct ifreq *) data; int s, error = 0; ! s=splimp(); switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; + + /* netifs are BUSY when UP */ + kdc_ep[ifp->if_unit].kdc_state=DC_BUSY; + switch (ifa->ifa_addr->sa_family) { #ifdef INET case AF_INET: *************** *** 1159,1179 **** break; } #endif default: epinit(ifp->if_unit); break; } break; case SIOCGIFADDR: ! { ! struct sockaddr *sa; ! ! sa = (struct sockaddr *) & ifr->ifr_data; ! bcopy((caddr_t) sc->arpcom.ac_enaddr, (caddr_t) sa->sa_data, ETHER_ADDR_LEN); } break; case SIOCSIFFLAGS: if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { ifp->if_flags &= ~IFF_RUNNING; epstop(ifp->if_unit); --- 1208,1251 ---- break; } #endif + #ifdef IPX + case AF_IPX: + { + register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); + + if (ipx_nullhost(*ina)) + ina->x_host = + *(union ipx_host *) (sc->arpcom.ac_enaddr); + else { + ifp->if_flags &= ~IFF_RUNNING; + bcopy((caddr_t) ina->x_host.c_host, + (caddr_t) sc->arpcom.ac_enaddr, + sizeof(sc->arpcom.ac_enaddr)); + } + epinit(ifp->if_unit); + break; + } + #endif default: epinit(ifp->if_unit); break; } break; case SIOCGIFADDR: ! { ! struct sockaddr *sa; ! ! sa = (struct sockaddr *) & ifr->ifr_data; ! bcopy((caddr_t) sc->arpcom.ac_enaddr, (caddr_t) sa->sa_data, ETHER_ADDR_LEN); } break; case SIOCSIFFLAGS: + /* UP controls BUSY/IDLE */ + kdc_ep[ifp->if_unit].kdc_state= ( (ifp->if_flags & IFF_UP) + ? DC_BUSY + : DC_IDLE ); + if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { ifp->if_flags &= ~IFF_RUNNING; epstop(ifp->if_unit); *************** *** 1186,1191 **** --- 1258,1264 ---- } /* NOTREACHED */ + #if 0 if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0) epinit(ifp->if_unit); *************** *** 1198,1203 **** --- 1271,1277 ---- ep_frst(F_PROMISC); epinit(ifp->if_unit); } + #endif break; #ifdef notdef *************** *** 1216,1223 **** } else { ifp->if_mtu = ifr->ifr_mtu; } ! break; ! default: error = EINVAL; } --- 1290,1304 ---- } else { ifp->if_mtu = ifr->ifr_mtu; } ! break; ! case SIOCADDMULTI: ! case SIOCDELMULTI: ! /* Now this driver has no support for programmable ! * multicast filters. If some day it will gain this ! * support this part of code must be extended. ! */ ! error=0; ! break; default: error = EINVAL; } *** if_epreg.h Mon Oct 23 08:25:55 1995 --- /sys/i386/isa/if_epreg.h Fri Aug 4 09:00:36 1995 *************** *** 71,76 **** --- 70,77 ---- #define F_ACCESS_32_BITS 0x100 + struct ep_board *epb; + #ifdef EP_LOCAL_STATS short tx_underrun; short rx_no_first; *************** *** 80,85 **** --- 81,97 ---- short rx_overrunl; #endif }; + + struct ep_board { + int epb_addr; /* address of this board */ + char epb_used; /* was this entry already used for configuring ? */ + /* data from EEPROM for later use */ + char epb_isa; /* flag: this is an ISA card */ + u_short eth_addr[3]; /* Ethernet address */ + u_short prod_id; /* product ID */ + u_short res_cfg; /* resource configuration */ + }; + /* * Some global constants =============== CUT HERE =============================