i82596.c revision 1.9 1 1.9 he /* $NetBSD: i82596.c,v 1.9 2005/06/02 14:41:26 he Exp $ */
2 1.1 jkunz
3 1.1 jkunz /*
4 1.1 jkunz * Copyright (c) 2003 Jochen Kunz.
5 1.1 jkunz * All rights reserved.
6 1.1 jkunz *
7 1.1 jkunz * Redistribution and use in source and binary forms, with or without
8 1.1 jkunz * modification, are permitted provided that the following conditions
9 1.1 jkunz * are met:
10 1.1 jkunz * 1. Redistributions of source code must retain the above copyright
11 1.1 jkunz * notice, this list of conditions and the following disclaimer.
12 1.1 jkunz * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 jkunz * notice, this list of conditions and the following disclaimer in the
14 1.1 jkunz * documentation and/or other materials provided with the distribution.
15 1.1 jkunz * 3. The name of Jochen Kunz may not be used to endorse or promote
16 1.1 jkunz * products derived from this software without specific prior
17 1.1 jkunz * written permission.
18 1.1 jkunz *
19 1.1 jkunz * THIS SOFTWARE IS PROVIDED BY JOCHEN KUNZ
20 1.1 jkunz * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 jkunz * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 jkunz * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JOCHEN KUNZ
23 1.1 jkunz * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 jkunz * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 jkunz * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 jkunz * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 jkunz * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 jkunz * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 jkunz * POSSIBILITY OF SUCH DAMAGE.
30 1.1 jkunz */
31 1.1 jkunz
32 1.1 jkunz /*
33 1.8 perry * Driver for the Intel i82596 10MBit/s Ethernet chip.
34 1.1 jkunz * It operates the i82596 in 32-Bit Linear Mode, opposed to the old i82586
35 1.8 perry * ie(4) driver (src/sys/dev/ic/i82586.c), that degrades the i82596 to
36 1.1 jkunz * i82586 compatibility mode.
37 1.1 jkunz * Documentation about this chip can be found on http://www.openpa.net/
38 1.1 jkunz * file names 29021806.pdf and 29021906.pdf
39 1.1 jkunz */
40 1.1 jkunz
41 1.1 jkunz #include <sys/cdefs.h>
42 1.9 he __KERNEL_RCSID(0, "$NetBSD: i82596.c,v 1.9 2005/06/02 14:41:26 he Exp $");
43 1.1 jkunz
44 1.1 jkunz /* autoconfig and device stuff */
45 1.1 jkunz #include <sys/param.h>
46 1.1 jkunz #include <sys/device.h>
47 1.1 jkunz #include <sys/conf.h>
48 1.1 jkunz #include "locators.h"
49 1.1 jkunz #include "ioconf.h"
50 1.1 jkunz
51 1.1 jkunz /* bus_space / bus_dma etc. */
52 1.1 jkunz #include <machine/bus.h>
53 1.1 jkunz #include <machine/intr.h>
54 1.1 jkunz
55 1.1 jkunz /* general system data and functions */
56 1.1 jkunz #include <sys/systm.h>
57 1.1 jkunz #include <sys/ioctl.h>
58 1.1 jkunz
59 1.1 jkunz /* tsleep / sleep / wakeup */
60 1.1 jkunz #include <sys/proc.h>
61 1.1 jkunz /* hz for above */
62 1.1 jkunz #include <sys/kernel.h>
63 1.1 jkunz
64 1.1 jkunz /* network stuff */
65 1.1 jkunz #include <net/if.h>
66 1.1 jkunz #include <net/if_dl.h>
67 1.1 jkunz #include <net/if_media.h>
68 1.1 jkunz #include <net/if_ether.h>
69 1.1 jkunz #include <sys/socket.h>
70 1.1 jkunz #include <sys/mbuf.h>
71 1.1 jkunz
72 1.1 jkunz #include "bpfilter.h"
73 1.8 perry #if NBPFILTER > 0
74 1.1 jkunz #include <net/bpf.h>
75 1.8 perry #endif
76 1.1 jkunz
77 1.1 jkunz #include <dev/ic/i82596reg.h>
78 1.1 jkunz #include <dev/ic/i82596var.h>
79 1.1 jkunz
80 1.1 jkunz
81 1.1 jkunz
82 1.1 jkunz /* Supported chip variants */
83 1.9 he const char *i82596_typenames[] = { "unknowen", "DX/SX", "CA" };
84 1.1 jkunz
85 1.1 jkunz
86 1.1 jkunz
87 1.1 jkunz /* media change and status callback */
88 1.1 jkunz static int iee_mediachange(struct ifnet *);
89 1.1 jkunz static void iee_mediastatus(struct ifnet *, struct ifmediareq *);
90 1.1 jkunz
91 1.1 jkunz /* interface routines to upper protocols */
92 1.1 jkunz static void iee_start(struct ifnet *); /* initiate output */
93 1.1 jkunz static int iee_ioctl(struct ifnet *, u_long, caddr_t); /* ioctl routine */
94 1.1 jkunz static int iee_init(struct ifnet *); /* init routine */
95 1.1 jkunz static void iee_stop(struct ifnet *, int); /* stop routine */
96 1.1 jkunz static void iee_watchdog(struct ifnet *); /* timer routine */
97 1.1 jkunz static void iee_drain(struct ifnet *); /* release resources */
98 1.1 jkunz
99 1.1 jkunz /* internal helper functions */
100 1.7 tsutsui static void iee_cb_setup(struct iee_softc *, uint32_t);
101 1.1 jkunz
102 1.1 jkunz /*
103 1.1 jkunz Things a MD frontend has to provide:
104 1.1 jkunz
105 1.1 jkunz The functions via function pointers in the softc:
106 1.7 tsutsui int (*sc_iee_cmd)(struct iee_softc *sc, uint32_t cmd);
107 1.1 jkunz int (*sc_iee_reset)(struct iee_softc *sc);
108 1.1 jkunz void (*sc_mediastatus)(struct ifnet *, struct ifmediareq *);
109 1.1 jkunz int (*sc_mediachange)(struct ifnet *);
110 1.1 jkunz
111 1.8 perry sc_iee_cmd(): send a command to the i82596 by writing the cmd parameter
112 1.8 perry to the SCP cmd word and issuing a Channel Attention.
113 1.8 perry sc_iee_reset(): initiate a reset, supply the address of the SCP to the
114 1.8 perry chip, wait for the chip to initialize and ACK interrupts that
115 1.8 perry this may have caused by caling (sc->sc_iee_cmd)(sc, IEE_SCB_ACK);
116 1.1 jkunz This functions must carefully bus_dmamap_sync() all data they have touched!
117 1.1 jkunz
118 1.1 jkunz sc_mediastatus() and sc_mediachange() are just MD hooks to the according
119 1.8 perry MI functions. The MD frontend may set this pointers to NULL when they
120 1.8 perry are not needed.
121 1.1 jkunz
122 1.1 jkunz sc->sc_type has to be set to I82596_UNKNOWN or I82596_DX or I82596_CA.
123 1.8 perry This is for printing out the correct chip type at attach time only. The
124 1.1 jkunz MI backend doesn't distinguish different chip types when programming
125 1.8 perry the chip.
126 1.1 jkunz
127 1.8 perry sc->sc_flags has to be set to 0 on litle endian hardware and to
128 1.1 jkunz IEE_NEED_SWAP on big endian hardware, when endianes conversion is not
129 1.1 jkunz done by the bus attachment. Usually you need to set IEE_NEED_SWAP
130 1.8 perry when IEE_SYSBUS_BE is set in the sysbus byte.
131 1.1 jkunz
132 1.8 perry sc->sc_cl_align bust be set to 1 or to the cache line size. When set to
133 1.8 perry 1 no special alignment of DMA descriptors is done. If sc->sc_cl_align != 1
134 1.8 perry it forces alignment of the data structres in the shared memory to a multiple
135 1.8 perry of sc->sc_cl_align. This is needed on archs like hp700 that have non DMA
136 1.8 perry I/O coherent caches and are unable to map the shared memory uncachable.
137 1.1 jkunz (At least pre PA7100LC CPUs are unable to map memory uncachable.)
138 1.1 jkunz
139 1.1 jkunz sc->sc_cl_align MUST BE INITIALIZED BEFORE THE FOLOWING MACROS ARE USED:
140 1.1 jkunz SC_* IEE_*_SZ IEE_*_OFF IEE_SHMEM_MAX (shell style glob(3) pattern)
141 1.1 jkunz
142 1.8 perry The MD frontend has to allocate a piece of DMA memory at least of
143 1.1 jkunz IEE_SHMEM_MAX bytes size. All communication with the chip is done via
144 1.8 perry this shared memory. If possible map this memory non-cachable on
145 1.1 jkunz archs with non DMA I/O coherent caches. The base of the memory needs
146 1.8 perry to be aligend to an even address if sc->sc_cl_align == 1 and aligend
147 1.1 jkunz to a cache line if sc->sc_cl_align != 1.
148 1.1 jkunz
149 1.1 jkunz An interrupt with iee_intr() as handler must be established.
150 1.1 jkunz
151 1.8 perry Call void iee_attach(struct iee_softc *sc, uint8_t *ether_address,
152 1.8 perry int *media, int nmedia, int defmedia); when everything is set up. First
153 1.1 jkunz parameter is a pointer to the MI softc, ether_address is an array that
154 1.8 perry contains the ethernet address. media is an array of the media types
155 1.8 perry provided by the hardware. The members of this array are supplied to
156 1.1 jkunz ifmedia_add() in sequence. nmedia is the count of elements in media.
157 1.8 perry defmedia is the default media that is set via ifmedia_set().
158 1.8 perry nmedia and defmedia are ignored when media == NULL.
159 1.1 jkunz
160 1.1 jkunz The MD backend may call iee_detach() to detach the device.
161 1.1 jkunz
162 1.1 jkunz See sys/arch/hp700/gsc/if_iee.c for an example.
163 1.1 jkunz */
164 1.1 jkunz
165 1.1 jkunz
166 1.1 jkunz /*
167 1.1 jkunz How frame reception is done:
168 1.1 jkunz Each Recieve Frame Descriptor has one associated Recieve Buffer Descriptor.
169 1.8 perry Each RBD points to the data area of a mbuf cluster. The RFDs are linked
170 1.8 perry together in a circular list. sc->sc_rx_done is the count of RFDs in the
171 1.8 perry list already processed / the number of the RFD that has to be checked for
172 1.8 perry a new frame first at the next RX interrupt. Upon successful reception of
173 1.8 perry a frame the mbuf cluster is handled to upper protocol layers, a new mbuf
174 1.1 jkunz cluster is allocated and the RFD / RBD are reinitialized accordingly.
175 1.1 jkunz
176 1.1 jkunz When a RFD list overrun occured the whole RFD and RBD lists are reinitialized
177 1.1 jkunz and frame reception is started again.
178 1.1 jkunz */
179 1.1 jkunz int
180 1.1 jkunz iee_intr(void *intarg)
181 1.1 jkunz {
182 1.1 jkunz struct iee_softc *sc = intarg;
183 1.1 jkunz struct ifnet *ifp = &sc->sc_ethercom.ec_if;
184 1.1 jkunz struct iee_rfd *rfd;
185 1.1 jkunz struct iee_rbd *rbd;
186 1.1 jkunz bus_dmamap_t rx_map;
187 1.1 jkunz struct mbuf *rx_mbuf;
188 1.1 jkunz struct mbuf *new_mbuf;
189 1.1 jkunz int scb_status;
190 1.1 jkunz int scb_cmd;
191 1.6 tsutsui int n, col;
192 1.1 jkunz
193 1.1 jkunz if ((ifp->if_flags & IFF_RUNNING) == 0) {
194 1.1 jkunz (sc->sc_iee_cmd)(sc, IEE_SCB_ACK);
195 1.1 jkunz return(1);
196 1.1 jkunz }
197 1.1 jkunz bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, 0, IEE_SHMEM_MAX,
198 1.1 jkunz BUS_DMASYNC_POSTREAD);
199 1.1 jkunz scb_status = SC_SCB->scb_status;
200 1.1 jkunz scb_cmd = SC_SCB->scb_cmd;
201 1.1 jkunz rfd = SC_RFD(sc->sc_rx_done);
202 1.2 jkunz while ((rfd->rfd_status & IEE_RFD_C) != 0) {
203 1.1 jkunz /* At least one packet was received. */
204 1.1 jkunz rbd = SC_RBD(sc->sc_rx_done);
205 1.1 jkunz rx_map = sc->sc_rx_map[sc->sc_rx_done];
206 1.1 jkunz rx_mbuf = sc->sc_rx_mbuf[sc->sc_rx_done];
207 1.1 jkunz SC_RBD((sc->sc_rx_done + IEE_NRFD - 1) % IEE_NRFD)->rbd_size
208 1.1 jkunz &= ~IEE_RBD_EL;
209 1.1 jkunz if ((rfd->rfd_status & IEE_RFD_OK) == 0
210 1.1 jkunz || (rbd->rbd_count & IEE_RBD_EOF) == 0
211 1.1 jkunz || (rbd->rbd_count & IEE_RBD_F) == 0){
212 1.1 jkunz /* Receive error, skip frame and reuse buffer. */
213 1.1 jkunz rfd->rfd_status = 0;
214 1.1 jkunz rbd->rbd_count = 0;
215 1.1 jkunz rbd->rbd_size = IEE_RBD_EL | rx_map->dm_segs[0].ds_len;
216 1.1 jkunz printf("%s: iee_intr: receive error %d, rfd_status="
217 1.8 perry "0x%.4x, rfd_count=0x%.4x\n", sc->sc_dev.dv_xname,
218 1.1 jkunz ++sc->sc_rx_err, rfd->rfd_status, rbd->rbd_count);
219 1.1 jkunz sc->sc_rx_done = (sc->sc_rx_done + 1) % IEE_NRFD;
220 1.1 jkunz continue;
221 1.1 jkunz }
222 1.1 jkunz rfd->rfd_status = 0;
223 1.1 jkunz bus_dmamap_sync(sc->sc_dmat, rx_map, 0, rx_mbuf->m_ext.ext_size,
224 1.1 jkunz BUS_DMASYNC_POSTREAD);
225 1.8 perry rx_mbuf->m_pkthdr.len = rx_mbuf->m_len =
226 1.1 jkunz rbd->rbd_count & IEE_RBD_COUNT;
227 1.1 jkunz rx_mbuf->m_pkthdr.rcvif = ifp;
228 1.1 jkunz MGETHDR(new_mbuf, M_DONTWAIT, MT_DATA);
229 1.1 jkunz if (new_mbuf == NULL) {
230 1.1 jkunz printf("%s: iee_intr: can't allocate mbuf\n",
231 1.1 jkunz sc->sc_dev.dv_xname);
232 1.1 jkunz break;
233 1.1 jkunz }
234 1.1 jkunz MCLAIM(new_mbuf, &sc->sc_ethercom.ec_rx_mowner);
235 1.1 jkunz MCLGET(new_mbuf, M_DONTWAIT);
236 1.1 jkunz if ((new_mbuf->m_flags & M_EXT) == 0) {
237 1.8 perry printf("%s: iee_intr: can't alloc mbuf cluster\n",
238 1.1 jkunz sc->sc_dev.dv_xname);
239 1.1 jkunz m_freem(new_mbuf);
240 1.1 jkunz break;
241 1.1 jkunz }
242 1.1 jkunz bus_dmamap_unload(sc->sc_dmat, rx_map);
243 1.8 perry if (bus_dmamap_load(sc->sc_dmat, rx_map,
244 1.8 perry new_mbuf->m_ext.ext_buf, new_mbuf->m_ext.ext_size,
245 1.1 jkunz NULL, BUS_DMA_READ | BUS_DMA_NOWAIT) != 0)
246 1.1 jkunz panic("%s: iee_intr: can't load RX DMA map\n",
247 1.1 jkunz sc->sc_dev.dv_xname);
248 1.1 jkunz bus_dmamap_sync(sc->sc_dmat, rx_map, 0,
249 1.1 jkunz new_mbuf->m_ext.ext_size, BUS_DMASYNC_PREREAD);
250 1.1 jkunz #if NBPFILTER > 0
251 1.1 jkunz if (ifp->if_bpf != 0)
252 1.1 jkunz bpf_mtap(ifp->if_bpf, rx_mbuf);
253 1.1 jkunz #endif /* NBPFILTER > 0 */
254 1.1 jkunz (*ifp->if_input)(ifp, rx_mbuf);
255 1.1 jkunz ifp->if_ipackets++;
256 1.1 jkunz sc->sc_rx_mbuf[sc->sc_rx_done] = new_mbuf;
257 1.1 jkunz rbd->rbd_count = 0;
258 1.1 jkunz rbd->rbd_size = IEE_RBD_EL | rx_map->dm_segs[0].ds_len;
259 1.1 jkunz rbd->rbd_rb_addr = rx_map->dm_segs[0].ds_addr;
260 1.1 jkunz sc->sc_rx_done = (sc->sc_rx_done + 1) % IEE_NRFD;
261 1.1 jkunz rfd = SC_RFD(sc->sc_rx_done);
262 1.1 jkunz }
263 1.1 jkunz if ((scb_status & IEE_SCB_RUS) == IEE_SCB_RUS_NR1
264 1.1 jkunz || (scb_status & IEE_SCB_RUS) == IEE_SCB_RUS_NR2
265 1.1 jkunz || (scb_status & IEE_SCB_RUS) == IEE_SCB_RUS_NR3) {
266 1.1 jkunz /* Receive Overrun, reinit receive ring buffer. */
267 1.1 jkunz for (n = 0 ; n < IEE_NRFD ; n++) {
268 1.1 jkunz SC_RFD(n)->rfd_cmd = IEE_RFD_SF;
269 1.1 jkunz SC_RFD(n)->rfd_link_addr = IEE_PHYS_SHMEM(IEE_RFD_OFF
270 1.1 jkunz + IEE_RFD_SZ * ((n + 1) % IEE_NRFD));
271 1.8 perry SC_RBD(n)->rbd_next_rbd = IEE_PHYS_SHMEM(IEE_RBD_OFF
272 1.1 jkunz + IEE_RBD_SZ * ((n + 1) % IEE_NRFD));
273 1.8 perry SC_RBD(n)->rbd_size = IEE_RBD_EL |
274 1.1 jkunz sc->sc_rx_map[n]->dm_segs[0].ds_len;
275 1.8 perry SC_RBD(n)->rbd_rb_addr =
276 1.1 jkunz sc->sc_rx_map[n]->dm_segs[0].ds_addr;
277 1.1 jkunz }
278 1.1 jkunz SC_RFD(0)->rfd_rbd_addr = IEE_PHYS_SHMEM(IEE_RBD_OFF);
279 1.1 jkunz sc->sc_rx_done = 0;
280 1.8 perry bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, IEE_RFD_OFF,
281 1.1 jkunz IEE_RFD_LIST_SZ + IEE_RBD_LIST_SZ, BUS_DMASYNC_PREWRITE);
282 1.1 jkunz (sc->sc_iee_cmd)(sc, IEE_SCB_RUC_ST);
283 1.8 perry printf("%s: iee_intr: receive ring buffer overrun\n",
284 1.1 jkunz sc->sc_dev.dv_xname);
285 1.2 jkunz }
286 1.1 jkunz
287 1.8 perry if (sc->sc_next_cb != 0
288 1.2 jkunz && (SC_CB(sc->sc_next_cb - 1)->cb_status & IEE_CB_C) != 0) {
289 1.1 jkunz /* CMD list finished */
290 1.1 jkunz ifp->if_timer = 0;
291 1.1 jkunz if (sc->sc_next_tbd != 0) {
292 1.1 jkunz /* A TX CMD list finished, clenup */
293 1.1 jkunz for (n = 0 ; n < sc->sc_next_cb ; n++) {
294 1.1 jkunz m_freem(sc->sc_tx_mbuf[n]);
295 1.1 jkunz sc->sc_tx_mbuf[n] = NULL;
296 1.1 jkunz bus_dmamap_unload(sc->sc_dmat,sc->sc_tx_map[n]);
297 1.8 perry if ((SC_CB(n)->cb_status & IEE_CB_COL) != 0 &&
298 1.1 jkunz (SC_CB(n)->cb_status & IEE_CB_MAXCOL) == 0)
299 1.6 tsutsui col = 16;
300 1.1 jkunz else
301 1.8 perry col = SC_CB(n)->cb_status
302 1.1 jkunz & IEE_CB_MAXCOL;
303 1.6 tsutsui sc->sc_tx_col += col;
304 1.6 tsutsui if ((SC_CB(n)->cb_status & IEE_CB_OK) != 0) {
305 1.6 tsutsui ifp->if_opackets++;
306 1.6 tsutsui ifp->if_collisions += col;
307 1.6 tsutsui }
308 1.1 jkunz }
309 1.1 jkunz sc->sc_next_tbd = 0;
310 1.1 jkunz ifp->if_flags &= ~IFF_OACTIVE;
311 1.1 jkunz }
312 1.1 jkunz for (n = 0 ; n < sc->sc_next_cb ; n++) {
313 1.1 jkunz /* Check if a CMD failed, but ignore TX errors. */
314 1.1 jkunz if ((SC_CB(n)->cb_cmd & IEE_CB_CMD) != IEE_CB_CMD_TR
315 1.2 jkunz && ((SC_CB(n)->cb_status & IEE_CB_OK) == 0))
316 1.8 perry printf("%s: iee_intr: scb_status=0x%x "
317 1.1 jkunz "scb_cmd=0x%x failed command %d: "
318 1.8 perry "cb_status[%d]=0x%.4x cb_cmd[%d]=0x%.4x\n",
319 1.8 perry sc->sc_dev.dv_xname, scb_status, scb_cmd,
320 1.1 jkunz ++sc->sc_cmd_err, n, SC_CB(n)->cb_status,
321 1.1 jkunz n, SC_CB(n)->cb_cmd);
322 1.1 jkunz }
323 1.1 jkunz sc->sc_next_cb = 0;
324 1.1 jkunz if ((sc->sc_flags & IEE_WANT_MCAST) != 0) {
325 1.8 perry iee_cb_setup(sc, IEE_CB_CMD_MCS | IEE_CB_S | IEE_CB_EL
326 1.1 jkunz | IEE_CB_I);
327 1.1 jkunz (sc->sc_iee_cmd)(sc, IEE_SCB_CUC_EXE);
328 1.1 jkunz } else
329 1.1 jkunz /* Try to get defered packets going. */
330 1.1 jkunz iee_start(ifp);
331 1.1 jkunz }
332 1.1 jkunz if (IEE_SWAP(SC_SCB->scb_crc_err) != sc->sc_crc_err) {
333 1.1 jkunz sc->sc_crc_err = IEE_SWAP(SC_SCB->scb_crc_err);
334 1.8 perry printf("%s: iee_intr: crc_err=%d\n", sc->sc_dev.dv_xname,
335 1.1 jkunz sc->sc_crc_err);
336 1.1 jkunz }
337 1.1 jkunz if (IEE_SWAP(SC_SCB->scb_align_err) != sc->sc_align_err) {
338 1.1 jkunz sc->sc_align_err = IEE_SWAP(SC_SCB->scb_align_err);
339 1.8 perry printf("%s: iee_intr: align_err=%d\n", sc->sc_dev.dv_xname,
340 1.1 jkunz sc->sc_align_err);
341 1.1 jkunz }
342 1.1 jkunz if (IEE_SWAP(SC_SCB->scb_resource_err) != sc->sc_resource_err) {
343 1.1 jkunz sc->sc_resource_err = IEE_SWAP(SC_SCB->scb_resource_err);
344 1.8 perry printf("%s: iee_intr: resource_err=%d\n", sc->sc_dev.dv_xname,
345 1.1 jkunz sc->sc_resource_err);
346 1.1 jkunz }
347 1.1 jkunz if (IEE_SWAP(SC_SCB->scb_overrun_err) != sc->sc_overrun_err) {
348 1.1 jkunz sc->sc_overrun_err = IEE_SWAP(SC_SCB->scb_overrun_err);
349 1.8 perry printf("%s: iee_intr: overrun_err=%d\n", sc->sc_dev.dv_xname,
350 1.1 jkunz sc->sc_overrun_err);
351 1.1 jkunz }
352 1.1 jkunz if (IEE_SWAP(SC_SCB->scb_rcvcdt_err) != sc->sc_rcvcdt_err) {
353 1.1 jkunz sc->sc_rcvcdt_err = IEE_SWAP(SC_SCB->scb_rcvcdt_err);
354 1.8 perry printf("%s: iee_intr: rcvcdt_err=%d\n", sc->sc_dev.dv_xname,
355 1.1 jkunz sc->sc_rcvcdt_err);
356 1.1 jkunz }
357 1.1 jkunz if (IEE_SWAP(SC_SCB->scb_short_fr_err) != sc->sc_short_fr_err) {
358 1.1 jkunz sc->sc_short_fr_err = IEE_SWAP(SC_SCB->scb_short_fr_err);
359 1.8 perry printf("%s: iee_intr: short_fr_err=%d\n", sc->sc_dev.dv_xname,
360 1.1 jkunz sc->sc_short_fr_err);
361 1.1 jkunz }
362 1.8 perry bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, 0, IEE_SHMEM_MAX,
363 1.2 jkunz BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
364 1.1 jkunz (sc->sc_iee_cmd)(sc, IEE_SCB_ACK);
365 1.1 jkunz return(1);
366 1.1 jkunz }
367 1.1 jkunz
368 1.1 jkunz
369 1.1 jkunz
370 1.1 jkunz /*
371 1.1 jkunz How Command Block List Processing is done.
372 1.1 jkunz
373 1.8 perry A runing CBL is never manipulated. If there is a CBL already runing,
374 1.8 perry further CMDs are deferd until the current list is done. A new list is
375 1.8 perry setup when the old has finished.
376 1.1 jkunz This eases programming. To manipulate a runing CBL it is neccesary to
377 1.1 jkunz suspend the Command Unit to avoid race conditions. After a suspend
378 1.8 perry is sent we have to wait for an interrupt that ACKs the suspend. Then
379 1.8 perry we can manipulate the CBL and resume operation. I am not sure that this
380 1.1 jkunz is more effective then the current, much simpler approach. => KISS
381 1.1 jkunz See i82596CA data sheet page 26.
382 1.1 jkunz
383 1.1 jkunz A CBL is runing or on the way to be set up when (sc->sc_next_cb != 0).
384 1.1 jkunz
385 1.1 jkunz A CBL may consist of TX CMDs, and _only_ TX CMDs.
386 1.8 perry A TX CBL is runing or on the way to be set up when
387 1.1 jkunz ((sc->sc_next_cb != 0) && (sc->sc_next_tbd != 0)).
388 1.1 jkunz
389 1.8 perry A CBL may consist of other non-TX CMDs like IAS or CONF, and _only_
390 1.1 jkunz non-TX CMDs.
391 1.1 jkunz
392 1.8 perry This comes mostly through the way how an Ethernet driver works and
393 1.8 perry because runing CBLs are not manipulated when they are on the way. If
394 1.8 perry if_start() is called there will be TX CMDs enqueued so we have a runing
395 1.8 perry CBL and other CMDs from e.g. if_ioctl() will be deferd and vice versa.
396 1.1 jkunz
397 1.1 jkunz The Multicast Setup Command is special. A MCS needs more space then
398 1.1 jkunz a single CB has. Actual space requiement depends on the length of the
399 1.1 jkunz multicast list. So we allways defer MCS until other CBLs are finished,
400 1.8 perry then we setup a CONF CMD in the first CB. The CONF CMD is needed to
401 1.1 jkunz turn ALLMULTI on the hardware on or off. The MCS is the 2nd CB and may
402 1.8 perry use all the remaining space in the CBL and the Transmit Buffer Descriptor
403 1.1 jkunz List. (Therefore CBL and TBDL must be continious in pysical and virtual
404 1.1 jkunz memory. This is guaranteed through the definitions of the list offsets
405 1.1 jkunz in i82596reg.h and because it is only a single DMA segment used for all
406 1.1 jkunz lists.) When ALLMULTI is enabled via the CONF CMD, the MCS is run with
407 1.1 jkunz a multicast list length of 0, thus disabling the multicast filter.
408 1.1 jkunz A defered MCS is signaled via ((sc->sc_flags & IEE_WANT_MCAST) != 0)
409 1.1 jkunz */
410 1.1 jkunz void
411 1.7 tsutsui iee_cb_setup(struct iee_softc *sc, uint32_t cmd)
412 1.1 jkunz {
413 1.1 jkunz struct iee_cb *cb = SC_CB(sc->sc_next_cb);
414 1.1 jkunz struct ifnet *ifp = &sc->sc_ethercom.ec_if;
415 1.1 jkunz struct ether_multistep step;
416 1.1 jkunz struct ether_multi *enm;
417 1.1 jkunz
418 1.1 jkunz memset(cb, 0, IEE_CB_SZ);
419 1.1 jkunz cb->cb_cmd = cmd;
420 1.1 jkunz switch(cmd & IEE_CB_CMD) {
421 1.1 jkunz case IEE_CB_CMD_NOP: /* NOP CMD */
422 1.1 jkunz break;
423 1.1 jkunz case IEE_CB_CMD_IAS: /* Individual Address Setup */
424 1.9 he memcpy(__UNVOLATILE(cb->cb_ind_addr), LLADDR(ifp->if_sadl),
425 1.1 jkunz ETHER_ADDR_LEN);
426 1.1 jkunz break;
427 1.1 jkunz case IEE_CB_CMD_CONF: /* Configure */
428 1.9 he memcpy(__UNVOLATILE(cb->cb_cf), sc->sc_cf, sc->sc_cf[0]
429 1.1 jkunz & IEE_CF_0_CNT_M);
430 1.1 jkunz break;
431 1.1 jkunz case IEE_CB_CMD_MCS: /* Multicast Setup */
432 1.1 jkunz if (sc->sc_next_cb != 0) {
433 1.1 jkunz sc->sc_flags |= IEE_WANT_MCAST;
434 1.1 jkunz return;
435 1.1 jkunz }
436 1.1 jkunz sc->sc_flags &= ~IEE_WANT_MCAST;
437 1.1 jkunz if ((sc->sc_cf[8] & IEE_CF_8_PRM) != 0) {
438 1.1 jkunz /* Need no multicast filter in promisc mode. */
439 1.8 perry iee_cb_setup(sc, IEE_CB_CMD_CONF | IEE_CB_S | IEE_CB_EL
440 1.1 jkunz | IEE_CB_I);
441 1.1 jkunz return;
442 1.1 jkunz }
443 1.1 jkunz /* Leave room for a CONF CMD to en/dis-able ALLMULTI mode */
444 1.1 jkunz cb = SC_CB(sc->sc_next_cb + 1);
445 1.1 jkunz cb->cb_cmd = cmd;
446 1.1 jkunz cb->cb_mcast.mc_size = 0;
447 1.1 jkunz ETHER_FIRST_MULTI(step, &sc->sc_ethercom, enm);
448 1.1 jkunz while (enm != NULL) {
449 1.8 perry if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
450 1.8 perry ETHER_ADDR_LEN) != 0 || cb->cb_mcast.mc_size
451 1.1 jkunz * ETHER_ADDR_LEN + 2 * IEE_CB_SZ
452 1.1 jkunz > IEE_CB_LIST_SZ + IEE_TBD_LIST_SZ) {
453 1.1 jkunz cb->cb_mcast.mc_size = 0;
454 1.1 jkunz break;
455 1.1 jkunz }
456 1.9 he memcpy(__UNVOLATILE(&cb->cb_mcast.mc_addrs[
457 1.9 he cb->cb_mcast.mc_size * ETHER_ADDR_LEN]),
458 1.1 jkunz enm->enm_addrlo, ETHER_ADDR_LEN);
459 1.1 jkunz ETHER_NEXT_MULTI(step, enm);
460 1.1 jkunz cb->cb_mcast.mc_size++;
461 1.1 jkunz }
462 1.1 jkunz if (cb->cb_mcast.mc_size == 0) {
463 1.1 jkunz /* Can't do exact mcast filtering, do ALLMULTI mode. */
464 1.1 jkunz ifp->if_flags |= IFF_ALLMULTI;
465 1.1 jkunz sc->sc_cf[11] &= ~IEE_CF_11_MCALL;
466 1.1 jkunz } else {
467 1.1 jkunz /* disable ALLMULTI and load mcast list */
468 1.1 jkunz ifp->if_flags &= ~IFF_ALLMULTI;
469 1.1 jkunz sc->sc_cf[11] |= IEE_CF_11_MCALL;
470 1.1 jkunz /* Mcast setup may need more then IEE_CB_SZ bytes. */
471 1.8 perry bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map,
472 1.8 perry IEE_CB_OFF, IEE_CB_LIST_SZ + IEE_TBD_LIST_SZ,
473 1.1 jkunz BUS_DMASYNC_PREWRITE);
474 1.1 jkunz }
475 1.1 jkunz iee_cb_setup(sc, IEE_CB_CMD_CONF);
476 1.1 jkunz break;
477 1.1 jkunz case IEE_CB_CMD_TR: /* Transmit */
478 1.1 jkunz cb->cb_transmit.tx_tbd_addr = IEE_PHYS_SHMEM(IEE_TBD_OFF
479 1.1 jkunz + IEE_TBD_SZ * sc->sc_next_tbd);
480 1.1 jkunz cb->cb_cmd |= IEE_CB_SF; /* Allways use Flexible Mode. */
481 1.1 jkunz break;
482 1.1 jkunz case IEE_CB_CMD_TDR: /* Time Domain Reflectometry */
483 1.1 jkunz break;
484 1.1 jkunz case IEE_CB_CMD_DUMP: /* Dump */
485 1.1 jkunz break;
486 1.1 jkunz case IEE_CB_CMD_DIAG: /* Diagnose */
487 1.1 jkunz break;
488 1.1 jkunz default:
489 1.1 jkunz /* can't happen */
490 1.1 jkunz break;
491 1.1 jkunz }
492 1.8 perry cb->cb_link_addr = IEE_PHYS_SHMEM(IEE_CB_OFF + IEE_CB_SZ *
493 1.1 jkunz (sc->sc_next_cb + 1));
494 1.8 perry bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, IEE_CB_OFF
495 1.1 jkunz + IEE_CB_SZ * sc->sc_next_cb, IEE_CB_SZ, BUS_DMASYNC_PREWRITE);
496 1.1 jkunz sc->sc_next_cb++;
497 1.1 jkunz ifp->if_timer = 5;
498 1.1 jkunz return;
499 1.1 jkunz }
500 1.1 jkunz
501 1.1 jkunz
502 1.1 jkunz
503 1.1 jkunz void
504 1.8 perry iee_attach(struct iee_softc *sc, uint8_t *eth_addr, int *media, int nmedia,
505 1.1 jkunz int defmedia)
506 1.1 jkunz {
507 1.1 jkunz struct ifnet *ifp = &sc->sc_ethercom.ec_if;
508 1.1 jkunz int n;
509 1.1 jkunz
510 1.1 jkunz /* Set pointer to Intermediate System Configuration Pointer. */
511 1.1 jkunz /* Phys. addr. in big endian order. (Big endian as defined by Intel.) */
512 1.1 jkunz SC_SCP->scp_iscp_addr = IEE_SWAP(IEE_PHYS_SHMEM(IEE_ISCP_OFF));
513 1.1 jkunz /* Set pointer to System Control Block. */
514 1.1 jkunz /* Phys. addr. in big endian order. (Big endian as defined by Intel.) */
515 1.1 jkunz SC_ISCP->iscp_scb_addr = IEE_SWAP(IEE_PHYS_SHMEM(IEE_SCB_OFF));
516 1.1 jkunz /* Set pointer to Receive Frame Area. (physical address) */
517 1.1 jkunz SC_SCB->scb_rfa_addr = IEE_PHYS_SHMEM(IEE_RFD_OFF);
518 1.1 jkunz /* Set pointer to Command Block. (physical address) */
519 1.1 jkunz SC_SCB->scb_cmd_blk_addr = IEE_PHYS_SHMEM(IEE_CB_OFF);
520 1.1 jkunz
521 1.1 jkunz ifmedia_init(&sc->sc_ifmedia, 0, iee_mediachange, iee_mediastatus);
522 1.1 jkunz if (media != NULL) {
523 1.1 jkunz for (n = 0 ; n < nmedia ; n++)
524 1.1 jkunz ifmedia_add(&sc->sc_ifmedia, media[n], 0, NULL);
525 1.1 jkunz ifmedia_set(&sc->sc_ifmedia, defmedia);
526 1.1 jkunz } else {
527 1.1 jkunz ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_NONE, 0, NULL);
528 1.1 jkunz ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_NONE);
529 1.1 jkunz }
530 1.1 jkunz
531 1.1 jkunz ifp->if_softc = sc;
532 1.1 jkunz strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
533 1.1 jkunz ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
534 1.1 jkunz ifp->if_start = iee_start; /* initiate output routine */
535 1.1 jkunz ifp->if_ioctl = iee_ioctl; /* ioctl routine */
536 1.1 jkunz ifp->if_init = iee_init; /* init routine */
537 1.1 jkunz ifp->if_stop = iee_stop; /* stop routine */
538 1.1 jkunz ifp->if_watchdog = iee_watchdog; /* timer routine */
539 1.1 jkunz ifp->if_drain = iee_drain; /* routine to release resources */
540 1.1 jkunz IFQ_SET_READY(&ifp->if_snd);
541 1.1 jkunz /* iee supports IEEE 802.1Q Virtual LANs, see vlan(4). */
542 1.1 jkunz sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;
543 1.1 jkunz
544 1.1 jkunz if_attach(ifp);
545 1.1 jkunz ether_ifattach(ifp, eth_addr);
546 1.1 jkunz
547 1.1 jkunz aprint_normal(": Intel 82596%s address %s\n",
548 1.1 jkunz i82596_typenames[ sc->sc_type], ether_sprintf(eth_addr));
549 1.1 jkunz
550 1.1 jkunz for (n = 0 ; n < IEE_NCB ; n++)
551 1.1 jkunz sc->sc_tx_map[n] = NULL;
552 1.1 jkunz for (n = 0 ; n < IEE_NRFD ; n++) {
553 1.1 jkunz sc->sc_rx_mbuf[n] = NULL;
554 1.1 jkunz sc->sc_rx_map[n] = NULL;
555 1.1 jkunz }
556 1.1 jkunz sc->sc_tx_timeout = 0;
557 1.1 jkunz sc->sc_setup_timeout = 0;
558 1.1 jkunz (sc->sc_iee_reset)(sc);
559 1.1 jkunz return;
560 1.1 jkunz }
561 1.1 jkunz
562 1.1 jkunz
563 1.1 jkunz
564 1.1 jkunz void
565 1.1 jkunz iee_detach(struct iee_softc *sc, int flags)
566 1.1 jkunz {
567 1.1 jkunz struct ifnet *ifp = &sc->sc_ethercom.ec_if;
568 1.1 jkunz
569 1.1 jkunz if ((ifp->if_flags & IFF_RUNNING) != 0)
570 1.1 jkunz iee_stop(ifp, 1);
571 1.1 jkunz ether_ifdetach(ifp);
572 1.1 jkunz if_detach(ifp);
573 1.1 jkunz return;
574 1.1 jkunz }
575 1.1 jkunz
576 1.1 jkunz
577 1.1 jkunz
578 1.1 jkunz /* media change and status callback */
579 1.1 jkunz int
580 1.1 jkunz iee_mediachange(struct ifnet *ifp)
581 1.1 jkunz {
582 1.1 jkunz struct iee_softc *sc = ifp->if_softc;
583 1.8 perry
584 1.1 jkunz if (sc->sc_mediachange != NULL)
585 1.1 jkunz return ((sc->sc_mediachange)(ifp));
586 1.1 jkunz return(0);
587 1.1 jkunz }
588 1.1 jkunz
589 1.1 jkunz
590 1.1 jkunz
591 1.1 jkunz void
592 1.1 jkunz iee_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmreq)
593 1.1 jkunz {
594 1.1 jkunz struct iee_softc *sc = ifp->if_softc;
595 1.1 jkunz
596 1.1 jkunz if (sc->sc_mediastatus != NULL)
597 1.1 jkunz return ((sc->sc_mediastatus)(ifp, ifmreq));
598 1.1 jkunz return;
599 1.1 jkunz }
600 1.1 jkunz
601 1.1 jkunz
602 1.1 jkunz
603 1.1 jkunz /* initiate output routine */
604 1.1 jkunz void
605 1.1 jkunz iee_start(struct ifnet *ifp)
606 1.1 jkunz {
607 1.1 jkunz struct iee_softc *sc = ifp->if_softc;
608 1.1 jkunz struct mbuf *m = NULL;
609 1.1 jkunz int t;
610 1.1 jkunz int n;
611 1.1 jkunz
612 1.1 jkunz if (sc->sc_next_cb != 0)
613 1.1 jkunz /* There is already a CMD runing. Defer packet enqueueing. */
614 1.1 jkunz return;
615 1.1 jkunz for (t = 0 ; t < IEE_NCB ; t++) {
616 1.1 jkunz IFQ_DEQUEUE(&ifp->if_snd, sc->sc_tx_mbuf[t]);
617 1.1 jkunz if (sc->sc_tx_mbuf[t] == NULL)
618 1.1 jkunz break;
619 1.1 jkunz if (bus_dmamap_load_mbuf(sc->sc_dmat, sc->sc_tx_map[t],
620 1.1 jkunz sc->sc_tx_mbuf[t], BUS_DMA_WRITE | BUS_DMA_NOWAIT) != 0) {
621 1.1 jkunz /*
622 1.8 perry * The packet needs more TBD then we support.
623 1.8 perry * Copy the packet into a mbuf cluster to get it out.
624 1.1 jkunz */
625 1.8 perry printf("%s: iee_start: failed to load DMA map\n",
626 1.1 jkunz sc->sc_dev.dv_xname);
627 1.1 jkunz MGETHDR(m, M_DONTWAIT, MT_DATA);
628 1.1 jkunz if (m == NULL) {
629 1.1 jkunz printf("%s: iee_start: can't allocate mbuf\n",
630 1.1 jkunz sc->sc_dev.dv_xname);
631 1.1 jkunz m_freem(sc->sc_tx_mbuf[t]);
632 1.1 jkunz t--;
633 1.1 jkunz continue;
634 1.1 jkunz }
635 1.1 jkunz MCLAIM(m, &sc->sc_ethercom.ec_rx_mowner);
636 1.1 jkunz MCLGET(m, M_DONTWAIT);
637 1.1 jkunz if ((m->m_flags & M_EXT) == 0) {
638 1.1 jkunz printf("%s: iee_start: can't allocate mbuf "
639 1.1 jkunz "cluster\n", sc->sc_dev.dv_xname);
640 1.1 jkunz m_freem(sc->sc_tx_mbuf[t]);
641 1.1 jkunz m_freem(m);
642 1.1 jkunz t--;
643 1.1 jkunz continue;
644 1.1 jkunz }
645 1.8 perry m_copydata(sc->sc_tx_mbuf[t], 0,
646 1.1 jkunz sc->sc_tx_mbuf[t]->m_pkthdr.len, mtod(m, caddr_t));
647 1.1 jkunz m->m_pkthdr.len = sc->sc_tx_mbuf[t]->m_pkthdr.len;
648 1.1 jkunz m->m_len = sc->sc_tx_mbuf[t]->m_pkthdr.len;
649 1.1 jkunz m_freem(sc->sc_tx_mbuf[t]);
650 1.1 jkunz sc->sc_tx_mbuf[t] = m;
651 1.1 jkunz if(bus_dmamap_load_mbuf(sc->sc_dmat, sc->sc_tx_map[t],
652 1.1 jkunz m, BUS_DMA_WRITE | BUS_DMA_NOWAIT) != 0) {
653 1.1 jkunz printf("%s: iee_start: can't load TX DMA map\n",
654 1.1 jkunz sc->sc_dev.dv_xname);
655 1.1 jkunz m_freem(sc->sc_tx_mbuf[t]);
656 1.1 jkunz t--;
657 1.1 jkunz continue;
658 1.1 jkunz }
659 1.1 jkunz }
660 1.1 jkunz for (n = 0 ; n < sc->sc_tx_map[t]->dm_nsegs ; n++) {
661 1.1 jkunz SC_TBD(sc->sc_next_tbd + n)->tbd_tb_addr =
662 1.1 jkunz sc->sc_tx_map[t]->dm_segs[n].ds_addr;
663 1.1 jkunz SC_TBD(sc->sc_next_tbd + n)->tbd_size =
664 1.1 jkunz sc->sc_tx_map[t]->dm_segs[n].ds_len;
665 1.1 jkunz SC_TBD(sc->sc_next_tbd + n)->tbd_link_addr =
666 1.8 perry IEE_PHYS_SHMEM(IEE_TBD_OFF + IEE_TBD_SZ
667 1.1 jkunz * (sc->sc_next_tbd + n + 1));
668 1.1 jkunz }
669 1.1 jkunz SC_TBD(sc->sc_next_tbd + n - 1)->tbd_size |= IEE_CB_EL;
670 1.1 jkunz bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_map[t], 0,
671 1.1 jkunz sc->sc_tx_map[t]->dm_mapsize, BUS_DMASYNC_PREWRITE);
672 1.1 jkunz IFQ_POLL(&ifp->if_snd, m);
673 1.1 jkunz if (m == NULL)
674 1.1 jkunz iee_cb_setup(sc, IEE_CB_CMD_TR | IEE_CB_S | IEE_CB_EL
675 1.1 jkunz | IEE_CB_I);
676 1.1 jkunz else
677 1.1 jkunz iee_cb_setup(sc, IEE_CB_CMD_TR);
678 1.1 jkunz sc->sc_next_tbd += n;
679 1.1 jkunz #if NBPFILTER > 0
680 1.1 jkunz /* Pass packet to bpf if someone listens. */
681 1.1 jkunz if (ifp->if_bpf)
682 1.1 jkunz bpf_mtap(ifp->if_bpf, sc->sc_tx_mbuf[t]);
683 1.1 jkunz #endif
684 1.1 jkunz }
685 1.1 jkunz if (t == 0)
686 1.1 jkunz /* No packets got set up for TX. */
687 1.1 jkunz return;
688 1.1 jkunz if (t == IEE_NCB)
689 1.1 jkunz ifp->if_flags |= IFF_OACTIVE;
690 1.1 jkunz bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, IEE_CB_SZ,
691 1.1 jkunz IEE_CB_LIST_SZ + IEE_TBD_LIST_SZ, BUS_DMASYNC_PREWRITE);
692 1.1 jkunz (sc->sc_iee_cmd)(sc, IEE_SCB_CUC_EXE);
693 1.1 jkunz return;
694 1.1 jkunz }
695 1.1 jkunz
696 1.1 jkunz
697 1.1 jkunz
698 1.1 jkunz /* ioctl routine */
699 1.1 jkunz int
700 1.1 jkunz iee_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
701 1.1 jkunz {
702 1.1 jkunz struct iee_softc *sc = ifp->if_softc;
703 1.1 jkunz int s;
704 1.1 jkunz int err;
705 1.1 jkunz
706 1.1 jkunz s = splnet();
707 1.4 thorpej switch (cmd) {
708 1.4 thorpej case SIOCSIFMEDIA:
709 1.4 thorpej case SIOCGIFMEDIA:
710 1.4 thorpej err = ifmedia_ioctl(ifp, (struct ifreq *) data,
711 1.4 thorpej &sc->sc_ifmedia, cmd);
712 1.4 thorpej break;
713 1.4 thorpej
714 1.4 thorpej default:
715 1.1 jkunz err = ether_ioctl(ifp, cmd, data);
716 1.4 thorpej if (err == ENETRESET) {
717 1.4 thorpej /*
718 1.4 thorpej * Multicast list as changed; set the hardware filter
719 1.4 thorpej * accordingly.
720 1.4 thorpej */
721 1.4 thorpej if (ifp->if_flags & IFF_RUNNING) {
722 1.4 thorpej iee_cb_setup(sc, IEE_CB_CMD_MCS | IEE_CB_S |
723 1.4 thorpej IEE_CB_EL | IEE_CB_I);
724 1.4 thorpej if ((sc->sc_flags & IEE_WANT_MCAST) == 0)
725 1.4 thorpej (*sc->sc_iee_cmd)(sc, IEE_SCB_CUC_EXE);
726 1.4 thorpej }
727 1.3 thorpej err = 0;
728 1.4 thorpej }
729 1.4 thorpej break;
730 1.1 jkunz }
731 1.1 jkunz splx(s);
732 1.1 jkunz return(err);
733 1.1 jkunz }
734 1.1 jkunz
735 1.1 jkunz
736 1.1 jkunz
737 1.1 jkunz /* init routine */
738 1.1 jkunz int
739 1.1 jkunz iee_init(struct ifnet *ifp)
740 1.1 jkunz {
741 1.1 jkunz struct iee_softc *sc = ifp->if_softc;
742 1.1 jkunz int r;
743 1.1 jkunz int t;
744 1.1 jkunz int n;
745 1.1 jkunz int err;
746 1.1 jkunz
747 1.1 jkunz sc->sc_next_cb = 0;
748 1.1 jkunz sc->sc_next_tbd = 0;
749 1.1 jkunz sc->sc_flags &= ~IEE_WANT_MCAST;
750 1.1 jkunz sc->sc_rx_done = 0;
751 1.1 jkunz SC_SCB->scb_crc_err = 0;
752 1.1 jkunz SC_SCB->scb_align_err = 0;
753 1.1 jkunz SC_SCB->scb_resource_err = 0;
754 1.1 jkunz SC_SCB->scb_overrun_err = 0;
755 1.1 jkunz SC_SCB->scb_rcvcdt_err = 0;
756 1.1 jkunz SC_SCB->scb_short_fr_err = 0;
757 1.1 jkunz sc->sc_crc_err = 0;
758 1.1 jkunz sc->sc_align_err = 0;
759 1.1 jkunz sc->sc_resource_err = 0;
760 1.1 jkunz sc->sc_overrun_err = 0;
761 1.1 jkunz sc->sc_rcvcdt_err = 0;
762 1.1 jkunz sc->sc_short_fr_err = 0;
763 1.1 jkunz sc->sc_tx_col = 0;
764 1.1 jkunz sc->sc_rx_err = 0;
765 1.1 jkunz sc->sc_cmd_err = 0;
766 1.1 jkunz /* Create Transmit DMA maps. */
767 1.1 jkunz for (t = 0 ; t < IEE_NCB ; t++) {
768 1.1 jkunz if (sc->sc_tx_map[t] == NULL && bus_dmamap_create(sc->sc_dmat,
769 1.8 perry MCLBYTES, IEE_NTBD, MCLBYTES, 0, BUS_DMA_NOWAIT,
770 1.1 jkunz &sc->sc_tx_map[t]) != 0) {
771 1.8 perry printf("%s: iee_init: can't create TX DMA map\n",
772 1.1 jkunz sc->sc_dev.dv_xname);
773 1.1 jkunz for (n = 0 ; n < t ; n++)
774 1.8 perry bus_dmamap_destroy(sc->sc_dmat,
775 1.1 jkunz sc->sc_tx_map[n]);
776 1.1 jkunz return(ENOBUFS);
777 1.1 jkunz }
778 1.1 jkunz }
779 1.1 jkunz /* Initialize Receive Frame and Receive Buffer Descriptors */
780 1.1 jkunz err = 0;
781 1.1 jkunz memset(SC_RFD(0), 0, IEE_RFD_LIST_SZ);
782 1.1 jkunz memset(SC_RBD(0), 0, IEE_RBD_LIST_SZ);
783 1.1 jkunz for (r = 0 ; r < IEE_NRFD ; r++) {
784 1.1 jkunz SC_RFD(r)->rfd_cmd = IEE_RFD_SF;
785 1.1 jkunz SC_RFD(r)->rfd_link_addr = IEE_PHYS_SHMEM(IEE_RFD_OFF
786 1.1 jkunz + IEE_RFD_SZ * ((r + 1) % IEE_NRFD));
787 1.1 jkunz
788 1.8 perry SC_RBD(r)->rbd_next_rbd = IEE_PHYS_SHMEM(IEE_RBD_OFF
789 1.1 jkunz + IEE_RBD_SZ * ((r + 1) % IEE_NRFD));
790 1.1 jkunz if (sc->sc_rx_mbuf[r] == NULL) {
791 1.1 jkunz MGETHDR(sc->sc_rx_mbuf[r], M_DONTWAIT, MT_DATA);
792 1.1 jkunz if (sc->sc_rx_mbuf[r] == NULL) {
793 1.8 perry printf("%s: iee_init: can't allocate mbuf\n",
794 1.1 jkunz sc->sc_dev.dv_xname);
795 1.1 jkunz err = 1;
796 1.1 jkunz break;
797 1.1 jkunz }
798 1.1 jkunz MCLAIM(sc->sc_rx_mbuf[r],&sc->sc_ethercom.ec_rx_mowner);
799 1.1 jkunz MCLGET(sc->sc_rx_mbuf[r], M_DONTWAIT);
800 1.1 jkunz if ((sc->sc_rx_mbuf[r]->m_flags & M_EXT) == 0) {
801 1.1 jkunz printf("%s: iee_init: can't allocate mbuf"
802 1.1 jkunz " cluster\n", sc->sc_dev.dv_xname);
803 1.1 jkunz m_freem(sc->sc_rx_mbuf[r]);
804 1.1 jkunz err = 1;
805 1.1 jkunz break;
806 1.1 jkunz }
807 1.1 jkunz }
808 1.1 jkunz if (sc->sc_rx_map[r] == NULL && bus_dmamap_create(sc->sc_dmat,
809 1.8 perry MCLBYTES, 1, MCLBYTES , 0, BUS_DMA_NOWAIT,
810 1.1 jkunz &sc->sc_rx_map[r]) != 0) {
811 1.1 jkunz printf("%s: iee_init: can't create RX "
812 1.1 jkunz "DMA map\n", sc->sc_dev.dv_xname);
813 1.1 jkunz m_freem(sc->sc_rx_mbuf[r]);
814 1.1 jkunz err = 1;
815 1.1 jkunz break;
816 1.1 jkunz }
817 1.1 jkunz if (bus_dmamap_load(sc->sc_dmat, sc->sc_rx_map[r],
818 1.8 perry sc->sc_rx_mbuf[r]->m_ext.ext_buf,
819 1.1 jkunz sc->sc_rx_mbuf[r]->m_ext.ext_size, NULL,
820 1.1 jkunz BUS_DMA_READ | BUS_DMA_NOWAIT) != 0) {
821 1.1 jkunz printf("%s: iee_init: can't load RX DMA map\n",
822 1.1 jkunz sc->sc_dev.dv_xname);
823 1.1 jkunz bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_map[r]);
824 1.1 jkunz m_freem(sc->sc_rx_mbuf[r]);
825 1.1 jkunz err = 1;
826 1.1 jkunz break;
827 1.1 jkunz }
828 1.1 jkunz bus_dmamap_sync(sc->sc_dmat, sc->sc_rx_map[r], 0,
829 1.1 jkunz sc->sc_rx_mbuf[r]->m_ext.ext_size, BUS_DMASYNC_PREREAD);
830 1.1 jkunz SC_RBD(r)->rbd_size = sc->sc_rx_map[r]->dm_segs[0].ds_len;
831 1.1 jkunz SC_RBD(r)->rbd_rb_addr= sc->sc_rx_map[r]->dm_segs[0].ds_addr;
832 1.1 jkunz }
833 1.1 jkunz SC_RFD(0)->rfd_rbd_addr = IEE_PHYS_SHMEM(IEE_RBD_OFF);
834 1.1 jkunz if (err != 0) {
835 1.1 jkunz for (n = 0 ; n < r; n++) {
836 1.1 jkunz m_freem(sc->sc_rx_mbuf[n]);
837 1.1 jkunz sc->sc_rx_mbuf[n] = NULL;
838 1.1 jkunz bus_dmamap_unload(sc->sc_dmat, sc->sc_rx_map[n]);
839 1.1 jkunz bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_map[n]);
840 1.1 jkunz sc->sc_rx_map[n] = NULL;
841 1.1 jkunz }
842 1.1 jkunz for (n = 0 ; n < t ; n++) {
843 1.1 jkunz bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_map[n]);
844 1.1 jkunz sc->sc_tx_map[n] = NULL;
845 1.1 jkunz }
846 1.1 jkunz return(ENOBUFS);
847 1.1 jkunz }
848 1.1 jkunz
849 1.1 jkunz (sc->sc_iee_reset)(sc);
850 1.1 jkunz iee_cb_setup(sc, IEE_CB_CMD_IAS);
851 1.1 jkunz sc->sc_cf[0] = IEE_CF_0_DEF | IEE_CF_0_PREF;
852 1.1 jkunz sc->sc_cf[1] = IEE_CF_1_DEF;
853 1.1 jkunz sc->sc_cf[2] = IEE_CF_2_DEF;
854 1.8 perry sc->sc_cf[3] = IEE_CF_3_ADDRLEN_DEF | IEE_CF_3_NSAI
855 1.1 jkunz | IEE_CF_3_PREAMLEN_DEF;
856 1.1 jkunz sc->sc_cf[4] = IEE_CF_4_DEF;
857 1.1 jkunz sc->sc_cf[5] = IEE_CF_5_DEF;
858 1.1 jkunz sc->sc_cf[6] = IEE_CF_6_DEF;
859 1.1 jkunz sc->sc_cf[7] = IEE_CF_7_DEF;
860 1.1 jkunz sc->sc_cf[8] = IEE_CF_8_DEF;
861 1.1 jkunz sc->sc_cf[9] = IEE_CF_9_DEF;
862 1.1 jkunz sc->sc_cf[10] = IEE_CF_10_DEF;
863 1.1 jkunz sc->sc_cf[11] = IEE_CF_11_DEF & ~IEE_CF_11_LNGFLD;
864 1.1 jkunz sc->sc_cf[12] = IEE_CF_12_DEF;
865 1.1 jkunz sc->sc_cf[13] = IEE_CF_13_DEF;
866 1.1 jkunz iee_cb_setup(sc, IEE_CB_CMD_CONF | IEE_CB_S | IEE_CB_EL);
867 1.1 jkunz SC_SCB->scb_rfa_addr = IEE_PHYS_SHMEM(IEE_RFD_OFF);
868 1.1 jkunz bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, 0, IEE_SHMEM_MAX,
869 1.1 jkunz BUS_DMASYNC_PREWRITE);
870 1.1 jkunz (sc->sc_iee_cmd)(sc, IEE_SCB_CUC_EXE | IEE_SCB_RUC_ST);
871 1.1 jkunz /* Issue a Channel Attention to ACK interrupts we may have caused. */
872 1.1 jkunz (sc->sc_iee_cmd)(sc, IEE_SCB_ACK);
873 1.1 jkunz
874 1.1 jkunz /* Mark the interface as running and ready to RX/TX packets. */
875 1.1 jkunz ifp->if_flags |= IFF_RUNNING;
876 1.1 jkunz ifp->if_flags &= ~IFF_OACTIVE;
877 1.1 jkunz return(0);
878 1.1 jkunz }
879 1.1 jkunz
880 1.1 jkunz
881 1.1 jkunz
882 1.1 jkunz /* stop routine */
883 1.1 jkunz void
884 1.1 jkunz iee_stop(struct ifnet *ifp, int disable)
885 1.1 jkunz {
886 1.1 jkunz struct iee_softc *sc = ifp->if_softc;
887 1.1 jkunz int n;
888 1.1 jkunz
889 1.1 jkunz ifp->if_flags &= ~IFF_RUNNING;
890 1.1 jkunz ifp->if_flags |= IFF_OACTIVE;
891 1.1 jkunz ifp->if_timer = 0;
892 1.1 jkunz /* Reset the chip to get it quiet. */
893 1.1 jkunz (sc->sc_iee_reset)(ifp->if_softc);
894 1.1 jkunz /* Issue a Channel Attention to ACK interrupts we may have caused. */
895 1.1 jkunz (sc->sc_iee_cmd)(ifp->if_softc, IEE_SCB_ACK);
896 1.1 jkunz /* Release any dynamically allocated ressources. */
897 1.1 jkunz for (n = 0 ; n < IEE_NCB ; n++) {
898 1.1 jkunz if (sc->sc_tx_map[n] != NULL)
899 1.1 jkunz bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_map[n]);
900 1.1 jkunz sc->sc_tx_map[n] = NULL;
901 1.1 jkunz }
902 1.1 jkunz for (n = 0 ; n < IEE_NRFD ; n++) {
903 1.1 jkunz if (sc->sc_rx_mbuf[n] != NULL)
904 1.1 jkunz m_freem(sc->sc_rx_mbuf[n]);
905 1.1 jkunz sc->sc_rx_mbuf[n] = NULL;
906 1.1 jkunz if (sc->sc_rx_map[n] != NULL) {
907 1.1 jkunz bus_dmamap_unload(sc->sc_dmat, sc->sc_rx_map[n]);
908 1.1 jkunz bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_map[n]);
909 1.1 jkunz }
910 1.1 jkunz sc->sc_rx_map[n] = NULL;
911 1.1 jkunz }
912 1.1 jkunz return;
913 1.1 jkunz }
914 1.1 jkunz
915 1.1 jkunz
916 1.1 jkunz
917 1.1 jkunz /* timer routine */
918 1.1 jkunz void
919 1.1 jkunz iee_watchdog(struct ifnet *ifp)
920 1.1 jkunz {
921 1.1 jkunz struct iee_softc *sc = ifp->if_softc;
922 1.1 jkunz
923 1.1 jkunz (sc->sc_iee_reset)(sc);
924 1.1 jkunz if (sc->sc_next_tbd != 0)
925 1.8 perry printf("%s: iee_watchdog: transmit timeout %d\n",
926 1.1 jkunz sc->sc_dev.dv_xname, ++sc->sc_tx_timeout);
927 1.1 jkunz else
928 1.8 perry printf("%s: iee_watchdog: setup timeout %d\n",
929 1.1 jkunz sc->sc_dev.dv_xname, ++sc->sc_setup_timeout);
930 1.1 jkunz iee_init(ifp);
931 1.1 jkunz return;
932 1.1 jkunz }
933 1.1 jkunz
934 1.1 jkunz
935 1.1 jkunz
936 1.1 jkunz /* routine to release res. */
937 1.1 jkunz void
938 1.1 jkunz iee_drain(struct ifnet *ifp)
939 1.1 jkunz {
940 1.1 jkunz iee_stop(ifp, 0);
941 1.1 jkunz return;
942 1.1 jkunz }
943 1.1 jkunz
944 1.1 jkunz
945 1.1 jkunz
946