* Copyright (c) 1992 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc.
* %sccs.include.redist.c%
* from: $Hdr: if_en.c,v 4.300 91/06/09 06:25:54 root Rel41 $ SONY
* @(#)if_en.c 7.2 (Berkeley) %G%
* Interlan Ethernet Communications Controller interface
#include "../include/fix_machine_type.h"
#include "../include/pte.h"
#include "netinet/in_systm.h"
#include "netinet/in_var.h"
#include "netinet/if_ether.h"
#include "../if/if_news.h"
#include "../hbdev/hbvar.h"
#define iop_device hb_device
#define iop_driver hb_driver
#define ii_alive hi_alive
#include "../iop/iopvar.h"
int enprobe(), enattach(), enrint(), enxint();
struct hb_device
*eninfo
[NEN
];
struct hb_driver endriver
= { enprobe
, 0, enattach
, 0, 0, "en", eninfo
};
struct iop_device
*eninfo
[NEN
];
struct iop_driver endriver
= { enprobe
, 0, enattach
, 0, "en", eninfo
};
#define ENUNIT(x) minor(x)
int eninit(),enioctl(),enreset(),enwatch(),enstart();
extern struct ifnet loif
;
struct en_softc en_softc
[NEN
];
struct ether_addr myether
[NEN
];
* Interface exists: make available by filling in network interface
* record. System will initialize the interface when it is ready
* to accept packets. A STATUS command is done to get the ethernet
* address and other interesting data.
register struct iop_device
*ii
;
register struct en_softc
*es
= &en_softc
[ii
->ii_unit
];
register struct ifnet
*ifp
= &es
->es_if
;
extern char *ether_sprintf();
bcopy((caddr_t
)es
->es_addr
, &myether
[ii
->ii_unit
],
sizeof(struct ether_addr
));
printf("en%d: hardware address %s\n",
ii
->ii_unit
, ether_sprintf((u_char
*)es
->es_addr
));
ifp
->if_unit
= ii
->ii_unit
;
ifp
->if_output
= ether_output
;
#ifdef NOTDEF /* KU:XXX if_reset is obsolete */
ifp
->if_flags
= IFF_BROADCAST
;
static struct bpf_devp dev
=
{ DLT_EN10MB
, sizeof(struct ether_header
) };
bpfattach(&en_bpf
[ii
->ii_unit
], ifp
, &dev
);
* Reset of interface after IOP reset.
register struct iop_device
*ii
;
if (unit
>= NEN
|| (ii
= eninfo
[unit
]) == 0 || ii
->ii_alive
== 0)
en_softc
[unit
].es_if
.if_flags
&= ~(IFF_RUNNING
|IFF_OACTIVE
);
en_softc
[unit
].es_flags
&= ~ENF_RUNNING
;
* Initialization of interface; clear recorded pending
* operations, and reinitialize IOP usage.
register struct en_softc
*es
= &en_softc
[unit
];
register struct ifnet
*ifp
= &es
->es_if
;
/* not yet, if address still unknown */
if (ifp
->if_addrlist
== (struct ifaddr
*)0)
if (es
->es_flags
& ENF_RUNNING
)
if ((ifp
->if_flags
& IFF_RUNNING
) == 0) {
if (if_newsinit(&es
->es_ifnews
,
sizeof (struct en_rheader
), (int)btoc(ETHERMTU
)) == 0) {
printf("en%d: can't initialize\n", unit
);
es
->es_if
.if_flags
&= ~IFF_UP
;
ifp
->if_watchdog
= enwatch
;
es
->es_interval
= ENWATCHINTERVAL
;
ifp
->if_timer
= es
->es_interval
;
es
->es_if
.if_flags
|= IFF_RUNNING
|IFF_NOTRAILERS
;
es
->es_flags
|= ENF_RUNNING
;
* Start output on interface.
* Get another datagram to send off of the interface queue,
* and map it to the interface before starting the output.
register struct ifnet
*ifp
;
int unit
= ifp
->if_unit
, len
;
register struct en_softc
*es
= &en_softc
[unit
];
IF_DEQUEUE(&es
->es_if
.if_snd
, m
);
es
->es_ifnews
.ifn_waddr
= (caddr_t
)get_xmit_buffer(unit
);
len
= if_wnewsput(&es
->es_ifnews
, m
);
* Ensure minimum packet length.
* This makes the safe assumtion that there are no virtual holes
* For security, it might be wise to zero out the added bytes,
* but we're mainly interested in speed at the moment.
if (len
- sizeof(struct ether_header
) < ETHERMIN
)
len
= ETHERMIN
+ sizeof(struct ether_header
);
* If bpf is listening on this interface, let it
* see the packet before we commit it to the wire.
bpf_tap(en_bpf
[unit
], es
->es_ifnews
.ifn_waddr
, len
);
bpf_mtap(en_bpf
[unit
], m
);
#endif /* NBPFILTER > 0 */
es
->es_if
.if_flags
|= IFF_OACTIVE
;
* Transmit done interrupt.
_enxint(unit
, error
, collision
)
register struct en_softc
*es
= &en_softc
[unit
];
#ifdef notyet /* KU:XXX */
intrcnt
[INTR_ETHER0
+ unit
]++;
if ((es
->es_if
.if_flags
& IFF_OACTIVE
) == 0) {
printf("en%d: stray xmit interrupt\n", unit
);
es
->es_if
.if_flags
&= ~IFF_OACTIVE
;
es
->es_if
.if_collisions
++;
* Ethernet interface receiver interrupt.
* If input error just drop packet.
* Otherwise purge input buffered data path and examine
* packet to determine type. If can't determine length
* from type, then have to drop packet. Othewise decapsulate
* packet based on type and pass to type specific higher-level
register struct en_softc
*es
= &en_softc
[unit
];
register struct en_rheader
*en
;
register struct ensw
*esp
;
extern struct mbuf
*if_rnewsget();
#ifdef notyet /* KU:XXX */
intrcnt
[INTR_ETHER0
+ unit
]++;
if ((es
->es_flags
& ENF_RUNNING
) == 0)
en
= (struct en_rheader
*)(es
->es_ifnews
.ifn_raddr
);
if (len
< ETHERMIN
|| len
> ETHERMTU
) {
etherinput(unit
, en
, len
+ sizeof(struct en_rheader
));
* Check if there's a bpf filter listening on this interface.
* If so, hand off the raw packet to enet.
bpf_tap(en_bpf
[unit
], es
->es_ifnews
.ifn_raddr
,
len
+ sizeof(struct en_rheader
));
* Note that the interface cannot be in promiscuous mode if
* there are no bpf listeners. And if we are in promiscuous
* mode, we have to check if this packet is really ours.
* XXX This test does not support multicasts.
if ((es
->es_if
.if_flags
& IFF_PROMISC
)
&& bcmp(en
->enr_dhost
, es
->es_addr
,
sizeof(en
->enr_dhost
)) != 0
&& bcmp(en
->enr_dhost
, etherbroadcastaddr
,
sizeof(en
->enr_dhost
)) != 0)
#else /* NBPFILTER > 0 */
if (etherinput(unit
, en
, len
+ sizeof(struct en_rheader
)))
#endif /* NBPFILTER > 0 */
* Deal with trailer protocol: if type is trailer type
* get true type from first 16-bit word past data.
* Remember that type was trailer by setting off.
en
->enr_type
= ntohs((u_short
)en
->enr_type
);
#define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off))))
if (en
->enr_type
>= ETHERTYPE_TRAIL
&&
en
->enr_type
< ETHERTYPE_TRAIL
+ETHERTYPE_NTRAILER
) {
off
= (en
->enr_type
- ETHERTYPE_TRAIL
) * 512;
en
->enr_type
= ntohs(*endataaddr(en
, off
, u_short
*));
resid
= ntohs(*(endataaddr(en
, off
+2, u_short
*)));
* Pull packet off interface. Off is nonzero if packet
* has trailing header; m_devget will then force this header
* information to be at the front, but we still have to drop
* the type and length which are at the front of any trailer data.
m
= m_devget((char *)(en
+ 1), len
, off
, &es
->es_if
, 0);
ether_input(&es
->es_if
, (struct ether_header
*) en
->enr_dhost
, m
);
* Watchdog routine, request statistics from board.
register struct en_softc
*es
= &en_softc
[unit
];
register struct ifnet
*ifp
= &es
->es_if
;
ifp
->if_timer
= es
->es_interval
;
* Process an ioctl request.
register struct ifnet
*ifp
;
register struct ifaddr
*ifa
= (struct ifaddr
*)data
;
register struct en_softc
*es
= &en_softc
[ifp
->if_unit
];
register struct ensw
*esp
;
int s
= splimp(), error
= 0;
switch (ifa
->ifa_addr
->sa_family
) {
((struct arpcom
*)ifp
)->ac_ipaddr
=
arpwhohas((struct arpcom
*)ifp
, &IA_SIN(ifa
)->sin_addr
);
if ((ifp
->if_flags
& IFF_UP
) == 0 &&
es
->es_flags
& ENF_RUNNING
) {
es
->es_flags
&= ~ENF_RUNNING
;
} else if (ifp
->if_flags
& IFF_UP
&&
(es
->es_flags
& ENF_RUNNING
) == 0)
else if (ifp
->if_flags
& IFF_UP
&&
(ifp
->if_flags
& IFF_RUNNING
) == 0) {
en_prom_mode(ifp
->if_unit
,
ifp
->if_flags
& IFF_PROMISC
);
ifp
->if_flags
|= IFF_RUNNING
;
* set ethernet address for unit
ensetaddr(physaddr
, unit
)
register struct en_softc
*es
= &en_softc
[unit
];
if (!(es
->es_flags
& ENF_RUNNING
))
bcopy((caddr_t
)physaddr
, (caddr_t
)es
->es_addr
, sizeof es
->es_addr
);
es
->es_flags
&= ~ENF_RUNNING
;
es
->es_flags
|= ENF_SETADDR
;
* Machine dependent functions
#include "../include/cpu.h"
return (lance_probe(hi
->hi_unit
));
register struct en_softc
*es
= &en_softc
[unit
];
#if !defined(news700) && !defined(mips)
register_hb_intr4(lance_intr
, unit
, eninfo
[unit
]->ii_intr
);
if (lance_open(unit
) < 0)
printf("lance initialize error\n");
lance_get_addr(unit
, (caddr_t
)es
->es_addr
);
lance_transmit(unit
, len
);
_enxint(unit
, lance_xmit_error(unit
), lance_collision(unit
));
register struct en_softc
*es
= &en_softc
[unit
];
caddr_t
get_recv_buffer();
while (es
->es_ifnews
.ifn_raddr
= get_recv_buffer(unit
)) {
get_recv_length(unit
) - sizeof(struct en_rheader
));
lance_prom_mode(unit
, mode
);
#include "../ipc/newsipc.h"
#include "../mrx/h/lancereg.h"
#include "../mrx/h/lance.h"
int port_enxmit_iop
[NEN
];
int port_enrecv_iop
[NEN
];
int port_enctrl_iop
[NEN
];
register struct iop_device
*ii
;
extern char *make_name();
if (port_enrecv
[unit
] == 0) {
#define PT_CREATE(buf, name, unit, func) \
port_create(make_name(buf, name, unit), func, unit)
#define OB_QUERY(buf, name, unit) \
object_query(make_name(buf, name, unit))
make_name(name
, "@enrecvX", unit
);
port_enrecv
[unit
] = PT_CREATE(name
, "@enrecvX", unit
, enrint
);
port_enxmit
[unit
] = PT_CREATE(name
, "@enxmitX", unit
, enxint
);
port_enctrl
[unit
] = PT_CREATE(name
, "@enctrlX", unit
, NULL
);
/* use NULL action port */
port_enrecv_iop
[unit
] = OB_QUERY(name
, "lance_inputX", unit
);
port_enxmit_iop
[unit
] = OB_QUERY(name
, "lance_outputX", unit
);
port_enctrl_iop
[unit
] = OB_QUERY(name
, "lance_ctrlX", unit
);
if (port_enctrl_iop
[unit
] < 0)
msg_send(port_enctrl_iop
[unit
], port_enctrl
[unit
], &lance_func
,
msg_recv(port_enctrl
[unit
], NULL
, &reply
, NULL
, 0);
msg_send(port_enctrl_iop
[unit
], port_enctrl
[unit
], &lance_func
,
msg_recv(port_enctrl
[unit
], NULL
, &reply
, NULL
, 0);
register struct en_softc
*es
= &en_softc
[unit
];
struct ether_addr
*ether_addr
;
msg_send(port_enctrl_iop
[unit
], port_enctrl
[unit
], &lance_func
,
msg_recv(port_enctrl
[unit
], NULL
, ðer_addr
, NULL
, 0);
bcopy(ether_addr
, es
->es_addr
, sizeof(struct ether_addr
));
msg_free(port_enctrl
[unit
]);
register struct en_softc
*es
= &en_softc
[unit
];
struct lance_ctrl_req req
;
req
.lance_func
= EN_SETXMITBUF
;
mapsetup(&req
.lance_map
, es
->es_ifnews
.ifn_waddr
,
ETHERMTU
+ sizeof(struct en_rheader
));
msg_send(port_enctrl_iop
[unit
], port_enctrl
[unit
],
msg_recv(port_enctrl
[unit
], NULL
, &reply
, NULL
, 0);
req
.lance_func
= EN_START
;
msg_send(port_enctrl_iop
[unit
], port_enctrl
[unit
],
msg_recv(port_enctrl
[unit
], NULL
, &reply
, NULL
, 0);
msg_free(port_enctrl
[unit
]);
msg_send(port_enrecv_iop
[unit
], port_enrecv
[unit
],
ETHERMTU
+ sizeof(struct en_rheader
), MSG_INDIRECT
);
msg_send(port_enxmit_iop
[unit
], port_enxmit
[unit
], &len
, sizeof(len
), 0);
struct en_softc
*es
= &en_softc
[unit
];
if (msg_recv(port_enxmit
[unit
], NULL
, &len
, NULL
, 0) < 0) {
printf("stray enxint\n");
if (es
->es_ifnews
.ifn_mbuf
)
m_freem(es
->es_ifnews
.ifn_mbuf
);
_enxint(unit
, *len
< 0, *len
& 0x10000);
if (msg_recv(port_enrecv
[unit
], NULL
, &reply
, NULL
, 0) < 0) {
printf("stray enrint\n");
len
= *reply
- sizeof(struct en_rheader
);
msg_free(port_enrecv
[unit
]);
* cache flush address must aligned long word boundary.
clean_k2dcache((int)en_softc
[unit
].es_ifnews
.ifn_raddr
& ~03,
len
+ sizeof (struct en_rheader
) + 3);
msg_send(port_enrecv_iop
[unit
], port_enrecv
[unit
],
en_softc
[unit
].es_ifnews
.ifn_raddr
,
ETHERMTU
+ sizeof(struct en_rheader
), MSG_INDIRECT
);
struct lance_ctrl_req req
;
extern int port_enctrl_iop
[];
req
.lance_func
= EN_PROMMODE
;
msg_send(port_enctrl_iop
[unit
], 0, &req
, sizeof(req
), 0);