| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: i82596.c,v 1.19 2008/04/04 17:03:42 tsutsui Exp $ */ | | 1 | /* $NetBSD: i82596.c,v 1.20 2009/05/05 15:47:35 tsutsui Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2003 Jochen Kunz. | | 4 | * Copyright (c) 2003 Jochen Kunz. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -33,27 +33,27 @@ | | | @@ -33,27 +33,27 @@ |
33 | * Driver for the Intel i82596CA and i82596DX/SX 10MBit/s Ethernet chips. | | 33 | * Driver for the Intel i82596CA and i82596DX/SX 10MBit/s Ethernet chips. |
34 | * | | 34 | * |
35 | * It operates the i82596 in 32-Bit Linear Mode, opposed to the old i82586 | | 35 | * It operates the i82596 in 32-Bit Linear Mode, opposed to the old i82586 |
36 | * ie(4) driver (src/sys/dev/ic/i82586.c), that degrades the i82596 to | | 36 | * ie(4) driver (src/sys/dev/ic/i82586.c), that degrades the i82596 to |
37 | * i82586 compatibility mode. | | 37 | * i82586 compatibility mode. |
38 | * | | 38 | * |
39 | * Documentation about these chips can be found at | | 39 | * Documentation about these chips can be found at |
40 | * | | 40 | * |
41 | * http://developer.intel.com/design/network/datashts/290218.htm | | 41 | * http://developer.intel.com/design/network/datashts/290218.htm |
42 | * http://developer.intel.com/design/network/datashts/290219.htm | | 42 | * http://developer.intel.com/design/network/datashts/290219.htm |
43 | */ | | 43 | */ |
44 | | | 44 | |
45 | #include <sys/cdefs.h> | | 45 | #include <sys/cdefs.h> |
46 | __KERNEL_RCSID(0, "$NetBSD: i82596.c,v 1.19 2008/04/04 17:03:42 tsutsui Exp $"); | | 46 | __KERNEL_RCSID(0, "$NetBSD: i82596.c,v 1.20 2009/05/05 15:47:35 tsutsui Exp $"); |
47 | | | 47 | |
48 | /* autoconfig and device stuff */ | | 48 | /* autoconfig and device stuff */ |
49 | #include <sys/param.h> | | 49 | #include <sys/param.h> |
50 | #include <sys/device.h> | | 50 | #include <sys/device.h> |
51 | #include <sys/conf.h> | | 51 | #include <sys/conf.h> |
52 | #include "locators.h" | | 52 | #include "locators.h" |
53 | #include "ioconf.h" | | 53 | #include "ioconf.h" |
54 | | | 54 | |
55 | /* bus_space / bus_dma etc. */ | | 55 | /* bus_space / bus_dma etc. */ |
56 | #include <sys/bus.h> | | 56 | #include <sys/bus.h> |
57 | #include <sys/intr.h> | | 57 | #include <sys/intr.h> |
58 | | | 58 | |
59 | /* general system data and functions */ | | 59 | /* general system data and functions */ |
| @@ -113,30 +113,48 @@ static void iee_cb_setup(struct iee_soft | | | @@ -113,30 +113,48 @@ static void iee_cb_setup(struct iee_soft |
113 | * chip, wait for the chip to initialize and ACK interrupts that | | 113 | * chip, wait for the chip to initialize and ACK interrupts that |
114 | * this may have caused by calling (sc->sc_iee_cmd)(sc, IEE_SCB_ACK); | | 114 | * this may have caused by calling (sc->sc_iee_cmd)(sc, IEE_SCB_ACK); |
115 | * This functions must carefully bus_dmamap_sync() all data they have touched! | | 115 | * This functions must carefully bus_dmamap_sync() all data they have touched! |
116 | * | | 116 | * |
117 | * sc_mediastatus() and sc_mediachange() are just MD hooks to the according | | 117 | * sc_mediastatus() and sc_mediachange() are just MD hooks to the according |
118 | * MI functions. The MD frontend may set this pointers to NULL when they | | 118 | * MI functions. The MD frontend may set this pointers to NULL when they |
119 | * are not needed. | | 119 | * are not needed. |
120 | * | | 120 | * |
121 | * sc->sc_type has to be set to I82596_UNKNOWN or I82596_DX or I82596_CA. | | 121 | * sc->sc_type has to be set to I82596_UNKNOWN or I82596_DX or I82596_CA. |
122 | * This is for printing out the correct chip type at attach time only. The | | 122 | * This is for printing out the correct chip type at attach time only. The |
123 | * MI backend doesn't distinguish different chip types when programming | | 123 | * MI backend doesn't distinguish different chip types when programming |
124 | * the chip. | | 124 | * the chip. |
125 | * | | 125 | * |
126 | * sc->sc_flags has to be set to 0 on little endian hardware and to | | 126 | * IEE_NEED_SWAP in sc->sc_flags has to be cleared on little endian hardware |
127 | * IEE_NEED_SWAP on big endian hardware, when endianess conversion is not | | 127 | * and set on big endian hardware, when endianess conversion is not done |
128 | * done by the bus attachment. Usually you need to set IEE_NEED_SWAP | | 128 | * by the bus attachment but done by i82596 chip itself. |
129 | * when IEE_SYSBUS_BE is set in the sysbus byte. | | 129 | * Usually you need to set IEE_NEED_SWAP on big endian machines |
| | | 130 | * where the hardware (the LE/~BE pin) is configured as BE mode. |
| | | 131 | * |
| | | 132 | * If the chip is configured as BE mode, all 8 bit (byte) and 16 bit (word) |
| | | 133 | * entities can be written in big endian. But Rev A chip doesn't support |
| | | 134 | * 32 bit (dword) entities with big endian byte ordering, so we have to |
| | | 135 | * treat all 32 bit (dword) entities as two 16 bit big endian entities. |
| | | 136 | * Rev B and C chips support big endian byte ordering for 32 bit entities, |
| | | 137 | * and this new feature is enabled by IEE_SYSBUS_BE in the sysbus byte. |
| | | 138 | * |
| | | 139 | * With the IEE_SYSBUS_BE feature, all 32 bit address ponters are |
| | | 140 | * treated as true 32 bit entities but the SCB absolute address and |
| | | 141 | * statistical counters are still treated as two 16 bit big endian entities, |
| | | 142 | * so we have to always swap high and low words for these entities. |
| | | 143 | * IEE_SWAP32() should be used for the SCB address and statistical counters, |
| | | 144 | * and IEE_SWAPA32() should be used for other 32 bit pointers in the shmem. |
| | | 145 | * |
| | | 146 | * IEE_REV_A flag must be set in sc->sc_flags if the IEE_SYSBUS_BE feature |
| | | 147 | * is disabled even on big endian machines for the old Rev A chip in backend. |
130 | * | | 148 | * |
131 | * sc->sc_cl_align must be set to 1 or to the cache line size. When set to | | 149 | * sc->sc_cl_align must be set to 1 or to the cache line size. When set to |
132 | * 1 no special alignment of DMA descriptors is done. If sc->sc_cl_align != 1 | | 150 | * 1 no special alignment of DMA descriptors is done. If sc->sc_cl_align != 1 |
133 | * it forces alignment of the data structures in the shared memory to a multiple | | 151 | * it forces alignment of the data structures in the shared memory to a multiple |
134 | * of sc->sc_cl_align. This is needed on archs like hp700 that have non DMA | | 152 | * of sc->sc_cl_align. This is needed on archs like hp700 that have non DMA |
135 | * I/O coherent caches and are unable to map the shared memory uncachable. | | 153 | * I/O coherent caches and are unable to map the shared memory uncachable. |
136 | * (At least pre PA7100LC CPUs are unable to map memory uncachable.) | | 154 | * (At least pre PA7100LC CPUs are unable to map memory uncachable.) |
137 | * | | 155 | * |
138 | * sc->sc_cl_align MUST BE INITIALIZED BEFORE THE FOLLOWING MACROS ARE USED: | | 156 | * sc->sc_cl_align MUST BE INITIALIZED BEFORE THE FOLLOWING MACROS ARE USED: |
139 | * SC_* IEE_*_SZ IEE_*_OFF IEE_SHMEM_MAX (shell style glob(3) pattern) | | 157 | * SC_* IEE_*_SZ IEE_*_OFF IEE_SHMEM_MAX (shell style glob(3) pattern) |
140 | * | | 158 | * |
141 | * The MD frontend has to allocate a piece of DMA memory at least of | | 159 | * The MD frontend has to allocate a piece of DMA memory at least of |
142 | * IEE_SHMEM_MAX bytes size. All communication with the chip is done via | | 160 | * IEE_SHMEM_MAX bytes size. All communication with the chip is done via |
| @@ -246,46 +264,49 @@ iee_intr(void *intarg) | | | @@ -246,46 +264,49 @@ iee_intr(void *intarg) |
246 | panic("%s: iee_intr: can't load RX DMA map\n", | | 264 | panic("%s: iee_intr: can't load RX DMA map\n", |
247 | device_xname(sc->sc_dev)); | | 265 | device_xname(sc->sc_dev)); |
248 | bus_dmamap_sync(sc->sc_dmat, rx_map, 0, | | 266 | bus_dmamap_sync(sc->sc_dmat, rx_map, 0, |
249 | new_mbuf->m_ext.ext_size, BUS_DMASYNC_PREREAD); | | 267 | new_mbuf->m_ext.ext_size, BUS_DMASYNC_PREREAD); |
250 | #if NBPFILTER > 0 | | 268 | #if NBPFILTER > 0 |
251 | if (ifp->if_bpf != 0) | | 269 | if (ifp->if_bpf != 0) |
252 | bpf_mtap(ifp->if_bpf, rx_mbuf); | | 270 | bpf_mtap(ifp->if_bpf, rx_mbuf); |
253 | #endif /* NBPFILTER > 0 */ | | 271 | #endif /* NBPFILTER > 0 */ |
254 | (*ifp->if_input)(ifp, rx_mbuf); | | 272 | (*ifp->if_input)(ifp, rx_mbuf); |
255 | ifp->if_ipackets++; | | 273 | ifp->if_ipackets++; |
256 | sc->sc_rx_mbuf[sc->sc_rx_done] = new_mbuf; | | 274 | sc->sc_rx_mbuf[sc->sc_rx_done] = new_mbuf; |
257 | rbd->rbd_count = 0; | | 275 | rbd->rbd_count = 0; |
258 | rbd->rbd_size = IEE_RBD_EL | rx_map->dm_segs[0].ds_len; | | 276 | rbd->rbd_size = IEE_RBD_EL | rx_map->dm_segs[0].ds_len; |
259 | rbd->rbd_rb_addr = rx_map->dm_segs[0].ds_addr; | | 277 | rbd->rbd_rb_addr = IEE_SWAPA32(rx_map->dm_segs[0].ds_addr); |
260 | sc->sc_rx_done = (sc->sc_rx_done + 1) % IEE_NRFD; | | 278 | sc->sc_rx_done = (sc->sc_rx_done + 1) % IEE_NRFD; |
261 | rfd = SC_RFD(sc->sc_rx_done); | | 279 | rfd = SC_RFD(sc->sc_rx_done); |
262 | } | | 280 | } |
263 | if ((scb_status & IEE_SCB_RUS) == IEE_SCB_RUS_NR1 | | 281 | if ((scb_status & IEE_SCB_RUS) == IEE_SCB_RUS_NR1 |
264 | || (scb_status & IEE_SCB_RUS) == IEE_SCB_RUS_NR2 | | 282 | || (scb_status & IEE_SCB_RUS) == IEE_SCB_RUS_NR2 |
265 | || (scb_status & IEE_SCB_RUS) == IEE_SCB_RUS_NR3) { | | 283 | || (scb_status & IEE_SCB_RUS) == IEE_SCB_RUS_NR3) { |
266 | /* Receive Overrun, reinit receive ring buffer. */ | | 284 | /* Receive Overrun, reinit receive ring buffer. */ |
267 | for (n = 0 ; n < IEE_NRFD ; n++) { | | 285 | for (n = 0 ; n < IEE_NRFD ; n++) { |
268 | SC_RFD(n)->rfd_cmd = IEE_RFD_SF; | | 286 | SC_RFD(n)->rfd_cmd = IEE_RFD_SF; |
269 | SC_RFD(n)->rfd_link_addr = IEE_PHYS_SHMEM(IEE_RFD_OFF | | 287 | SC_RFD(n)->rfd_link_addr = |
270 | + IEE_RFD_SZ * ((n + 1) % IEE_NRFD)); | | 288 | IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_RFD_OFF |
271 | SC_RBD(n)->rbd_next_rbd = IEE_PHYS_SHMEM(IEE_RBD_OFF | | 289 | + IEE_RFD_SZ * ((n + 1) % IEE_NRFD))); |
272 | + IEE_RBD_SZ * ((n + 1) % IEE_NRFD)); | | 290 | SC_RBD(n)->rbd_next_rbd = |
| | | 291 | IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_RBD_OFF |
| | | 292 | + IEE_RBD_SZ * ((n + 1) % IEE_NRFD))); |
273 | SC_RBD(n)->rbd_size = IEE_RBD_EL | | | 293 | SC_RBD(n)->rbd_size = IEE_RBD_EL | |
274 | sc->sc_rx_map[n]->dm_segs[0].ds_len; | | 294 | sc->sc_rx_map[n]->dm_segs[0].ds_len; |
275 | SC_RBD(n)->rbd_rb_addr = | | 295 | SC_RBD(n)->rbd_rb_addr = |
276 | sc->sc_rx_map[n]->dm_segs[0].ds_addr; | | 296 | IEE_SWAPA32(sc->sc_rx_map[n]->dm_segs[0].ds_addr); |
277 | } | | 297 | } |
278 | SC_RFD(0)->rfd_rbd_addr = IEE_PHYS_SHMEM(IEE_RBD_OFF); | | 298 | SC_RFD(0)->rfd_rbd_addr = |
| | | 299 | IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_RBD_OFF)); |
279 | sc->sc_rx_done = 0; | | 300 | sc->sc_rx_done = 0; |
280 | bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, IEE_RFD_OFF, | | 301 | bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, IEE_RFD_OFF, |
281 | IEE_RFD_LIST_SZ + IEE_RBD_LIST_SZ, BUS_DMASYNC_PREWRITE); | | 302 | IEE_RFD_LIST_SZ + IEE_RBD_LIST_SZ, BUS_DMASYNC_PREWRITE); |
282 | (sc->sc_iee_cmd)(sc, IEE_SCB_RUC_ST); | | 303 | (sc->sc_iee_cmd)(sc, IEE_SCB_RUC_ST); |
283 | printf("%s: iee_intr: receive ring buffer overrun\n", | | 304 | printf("%s: iee_intr: receive ring buffer overrun\n", |
284 | device_xname(sc->sc_dev)); | | 305 | device_xname(sc->sc_dev)); |
285 | } | | 306 | } |
286 | | | 307 | |
287 | if (sc->sc_next_cb != 0 | | 308 | if (sc->sc_next_cb != 0 |
288 | && (SC_CB(sc->sc_next_cb - 1)->cb_status & IEE_CB_C) != 0) { | | 309 | && (SC_CB(sc->sc_next_cb - 1)->cb_status & IEE_CB_C) != 0) { |
289 | /* CMD list finished */ | | 310 | /* CMD list finished */ |
290 | ifp->if_timer = 0; | | 311 | ifp->if_timer = 0; |
291 | if (sc->sc_next_tbd != 0) { | | 312 | if (sc->sc_next_tbd != 0) { |
| @@ -320,53 +341,53 @@ iee_intr(void *intarg) | | | @@ -320,53 +341,53 @@ iee_intr(void *intarg) |
320 | scb_status, scb_cmd, | | 341 | scb_status, scb_cmd, |
321 | ++sc->sc_cmd_err, n, SC_CB(n)->cb_status, | | 342 | ++sc->sc_cmd_err, n, SC_CB(n)->cb_status, |
322 | n, SC_CB(n)->cb_cmd); | | 343 | n, SC_CB(n)->cb_cmd); |
323 | } | | 344 | } |
324 | sc->sc_next_cb = 0; | | 345 | sc->sc_next_cb = 0; |
325 | if ((sc->sc_flags & IEE_WANT_MCAST) != 0) { | | 346 | if ((sc->sc_flags & IEE_WANT_MCAST) != 0) { |
326 | iee_cb_setup(sc, IEE_CB_CMD_MCS | IEE_CB_S | IEE_CB_EL | | 347 | iee_cb_setup(sc, IEE_CB_CMD_MCS | IEE_CB_S | IEE_CB_EL |
327 | | IEE_CB_I); | | 348 | | IEE_CB_I); |
328 | (sc->sc_iee_cmd)(sc, IEE_SCB_CUC_EXE); | | 349 | (sc->sc_iee_cmd)(sc, IEE_SCB_CUC_EXE); |
329 | } else | | 350 | } else |
330 | /* Try to get deferred packets going. */ | | 351 | /* Try to get deferred packets going. */ |
331 | iee_start(ifp); | | 352 | iee_start(ifp); |
332 | } | | 353 | } |
333 | if (IEE_SWAP(SC_SCB->scb_crc_err) != sc->sc_crc_err) { | | 354 | if (IEE_SWAP32(SC_SCB->scb_crc_err) != sc->sc_crc_err) { |
334 | sc->sc_crc_err = IEE_SWAP(SC_SCB->scb_crc_err); | | 355 | sc->sc_crc_err = IEE_SWAP32(SC_SCB->scb_crc_err); |
335 | printf("%s: iee_intr: crc_err=%d\n", device_xname(sc->sc_dev), | | 356 | printf("%s: iee_intr: crc_err=%d\n", device_xname(sc->sc_dev), |
336 | sc->sc_crc_err); | | 357 | sc->sc_crc_err); |
337 | } | | 358 | } |
338 | if (IEE_SWAP(SC_SCB->scb_align_err) != sc->sc_align_err) { | | 359 | if (IEE_SWAP32(SC_SCB->scb_align_err) != sc->sc_align_err) { |
339 | sc->sc_align_err = IEE_SWAP(SC_SCB->scb_align_err); | | 360 | sc->sc_align_err = IEE_SWAP32(SC_SCB->scb_align_err); |
340 | printf("%s: iee_intr: align_err=%d\n", device_xname(sc->sc_dev), | | 361 | printf("%s: iee_intr: align_err=%d\n", device_xname(sc->sc_dev), |
341 | sc->sc_align_err); | | 362 | sc->sc_align_err); |
342 | } | | 363 | } |
343 | if (IEE_SWAP(SC_SCB->scb_resource_err) != sc->sc_resource_err) { | | 364 | if (IEE_SWAP32(SC_SCB->scb_resource_err) != sc->sc_resource_err) { |
344 | sc->sc_resource_err = IEE_SWAP(SC_SCB->scb_resource_err); | | 365 | sc->sc_resource_err = IEE_SWAP32(SC_SCB->scb_resource_err); |
345 | printf("%s: iee_intr: resource_err=%d\n", | | 366 | printf("%s: iee_intr: resource_err=%d\n", |
346 | device_xname(sc->sc_dev), sc->sc_resource_err); | | 367 | device_xname(sc->sc_dev), sc->sc_resource_err); |
347 | } | | 368 | } |
348 | if (IEE_SWAP(SC_SCB->scb_overrun_err) != sc->sc_overrun_err) { | | 369 | if (IEE_SWAP32(SC_SCB->scb_overrun_err) != sc->sc_overrun_err) { |
349 | sc->sc_overrun_err = IEE_SWAP(SC_SCB->scb_overrun_err); | | 370 | sc->sc_overrun_err = IEE_SWAP32(SC_SCB->scb_overrun_err); |
350 | printf("%s: iee_intr: overrun_err=%d\n", | | 371 | printf("%s: iee_intr: overrun_err=%d\n", |
351 | device_xname(sc->sc_dev), sc->sc_overrun_err); | | 372 | device_xname(sc->sc_dev), sc->sc_overrun_err); |
352 | } | | 373 | } |
353 | if (IEE_SWAP(SC_SCB->scb_rcvcdt_err) != sc->sc_rcvcdt_err) { | | 374 | if (IEE_SWAP32(SC_SCB->scb_rcvcdt_err) != sc->sc_rcvcdt_err) { |
354 | sc->sc_rcvcdt_err = IEE_SWAP(SC_SCB->scb_rcvcdt_err); | | 375 | sc->sc_rcvcdt_err = IEE_SWAP32(SC_SCB->scb_rcvcdt_err); |
355 | printf("%s: iee_intr: rcvcdt_err=%d\n", | | 376 | printf("%s: iee_intr: rcvcdt_err=%d\n", |
356 | device_xname(sc->sc_dev), sc->sc_rcvcdt_err); | | 377 | device_xname(sc->sc_dev), sc->sc_rcvcdt_err); |
357 | } | | 378 | } |
358 | if (IEE_SWAP(SC_SCB->scb_short_fr_err) != sc->sc_short_fr_err) { | | 379 | if (IEE_SWAP32(SC_SCB->scb_short_fr_err) != sc->sc_short_fr_err) { |
359 | sc->sc_short_fr_err = IEE_SWAP(SC_SCB->scb_short_fr_err); | | 380 | sc->sc_short_fr_err = IEE_SWAP32(SC_SCB->scb_short_fr_err); |
360 | printf("%s: iee_intr: short_fr_err=%d\n", | | 381 | printf("%s: iee_intr: short_fr_err=%d\n", |
361 | device_xname(sc->sc_dev), sc->sc_short_fr_err); | | 382 | device_xname(sc->sc_dev), sc->sc_short_fr_err); |
362 | } | | 383 | } |
363 | bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, 0, IEE_SHMEM_MAX, | | 384 | bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, 0, IEE_SHMEM_MAX, |
364 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | | 385 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); |
365 | (sc->sc_iee_cmd)(sc, IEE_SCB_ACK); | | 386 | (sc->sc_iee_cmd)(sc, IEE_SCB_ACK); |
366 | return 1; | | 387 | return 1; |
367 | } | | 388 | } |
368 | | | 389 | |
369 | | | 390 | |
370 | | | 391 | |
371 | /* | | 392 | /* |
372 | * How Command Block List Processing is done. | | 393 | * How Command Block List Processing is done. |
| @@ -466,68 +487,69 @@ iee_cb_setup(struct iee_softc *sc, uint3 | | | @@ -466,68 +487,69 @@ iee_cb_setup(struct iee_softc *sc, uint3 |
466 | sc->sc_cf[11] &= ~IEE_CF_11_MCALL; | | 487 | sc->sc_cf[11] &= ~IEE_CF_11_MCALL; |
467 | } else { | | 488 | } else { |
468 | /* disable ALLMULTI and load mcast list */ | | 489 | /* disable ALLMULTI and load mcast list */ |
469 | ifp->if_flags &= ~IFF_ALLMULTI; | | 490 | ifp->if_flags &= ~IFF_ALLMULTI; |
470 | sc->sc_cf[11] |= IEE_CF_11_MCALL; | | 491 | sc->sc_cf[11] |= IEE_CF_11_MCALL; |
471 | /* Mcast setup may need more then IEE_CB_SZ bytes. */ | | 492 | /* Mcast setup may need more then IEE_CB_SZ bytes. */ |
472 | bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, | | 493 | bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, |
473 | IEE_CB_OFF, IEE_CB_LIST_SZ + IEE_TBD_LIST_SZ, | | 494 | IEE_CB_OFF, IEE_CB_LIST_SZ + IEE_TBD_LIST_SZ, |
474 | BUS_DMASYNC_PREWRITE); | | 495 | BUS_DMASYNC_PREWRITE); |
475 | } | | 496 | } |
476 | iee_cb_setup(sc, IEE_CB_CMD_CONF); | | 497 | iee_cb_setup(sc, IEE_CB_CMD_CONF); |
477 | break; | | 498 | break; |
478 | case IEE_CB_CMD_TR: /* Transmit */ | | 499 | case IEE_CB_CMD_TR: /* Transmit */ |
479 | cb->cb_transmit.tx_tbd_addr = IEE_PHYS_SHMEM(IEE_TBD_OFF | | 500 | cb->cb_transmit.tx_tbd_addr = |
480 | + IEE_TBD_SZ * sc->sc_next_tbd); | | 501 | IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_TBD_OFF |
| | | 502 | + IEE_TBD_SZ * sc->sc_next_tbd)); |
481 | cb->cb_cmd |= IEE_CB_SF; /* Always use Flexible Mode. */ | | 503 | cb->cb_cmd |= IEE_CB_SF; /* Always use Flexible Mode. */ |
482 | break; | | 504 | break; |
483 | case IEE_CB_CMD_TDR: /* Time Domain Reflectometry */ | | 505 | case IEE_CB_CMD_TDR: /* Time Domain Reflectometry */ |
484 | break; | | 506 | break; |
485 | case IEE_CB_CMD_DUMP: /* Dump */ | | 507 | case IEE_CB_CMD_DUMP: /* Dump */ |
486 | break; | | 508 | break; |
487 | case IEE_CB_CMD_DIAG: /* Diagnose */ | | 509 | case IEE_CB_CMD_DIAG: /* Diagnose */ |
488 | break; | | 510 | break; |
489 | default: | | 511 | default: |
490 | /* can't happen */ | | 512 | /* can't happen */ |
491 | break; | | 513 | break; |
492 | } | | 514 | } |
493 | cb->cb_link_addr = IEE_PHYS_SHMEM(IEE_CB_OFF + IEE_CB_SZ * | | 515 | cb->cb_link_addr = IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_CB_OFF + IEE_CB_SZ * |
494 | (sc->sc_next_cb + 1)); | | 516 | (sc->sc_next_cb + 1))); |
495 | bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, IEE_CB_OFF | | 517 | bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, IEE_CB_OFF |
496 | + IEE_CB_SZ * sc->sc_next_cb, IEE_CB_SZ, BUS_DMASYNC_PREWRITE); | | 518 | + IEE_CB_SZ * sc->sc_next_cb, IEE_CB_SZ, BUS_DMASYNC_PREWRITE); |
497 | sc->sc_next_cb++; | | 519 | sc->sc_next_cb++; |
498 | ifp->if_timer = 5; | | 520 | ifp->if_timer = 5; |
499 | return; | | 521 | return; |
500 | } | | 522 | } |
501 | | | 523 | |
502 | | | 524 | |
503 | | | 525 | |
504 | void | | 526 | void |
505 | iee_attach(struct iee_softc *sc, uint8_t *eth_addr, int *media, int nmedia, | | 527 | iee_attach(struct iee_softc *sc, uint8_t *eth_addr, int *media, int nmedia, |
506 | int defmedia) | | 528 | int defmedia) |
507 | { | | 529 | { |
508 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | | 530 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
509 | int n; | | 531 | int n; |
510 | | | 532 | |
511 | /* Set pointer to Intermediate System Configuration Pointer. */ | | 533 | /* Set pointer to Intermediate System Configuration Pointer. */ |
512 | /* Phys. addr. in big endian order. (Big endian as defined by Intel.) */ | | 534 | /* Phys. addr. in big endian order. (Big endian as defined by Intel.) */ |
513 | SC_SCP->scp_iscp_addr = IEE_SWAP(IEE_PHYS_SHMEM(IEE_ISCP_OFF)); | | 535 | SC_SCP->scp_iscp_addr = IEE_SWAP32(IEE_PHYS_SHMEM(IEE_ISCP_OFF)); |
514 | /* Set pointer to System Control Block. */ | | 536 | /* Set pointer to System Control Block. */ |
515 | /* Phys. addr. in big endian order. (Big endian as defined by Intel.) */ | | 537 | /* Phys. addr. in big endian order. (Big endian as defined by Intel.) */ |
516 | SC_ISCP->iscp_scb_addr = IEE_SWAP(IEE_PHYS_SHMEM(IEE_SCB_OFF)); | | 538 | SC_ISCP->iscp_scb_addr = IEE_SWAP32(IEE_PHYS_SHMEM(IEE_SCB_OFF)); |
517 | /* Set pointer to Receive Frame Area. (physical address) */ | | 539 | /* Set pointer to Receive Frame Area. (physical address) */ |
518 | SC_SCB->scb_rfa_addr = IEE_PHYS_SHMEM(IEE_RFD_OFF); | | 540 | SC_SCB->scb_rfa_addr = IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_RFD_OFF)); |
519 | /* Set pointer to Command Block. (physical address) */ | | 541 | /* Set pointer to Command Block. (physical address) */ |
520 | SC_SCB->scb_cmd_blk_addr = IEE_PHYS_SHMEM(IEE_CB_OFF); | | 542 | SC_SCB->scb_cmd_blk_addr = IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_CB_OFF)); |
521 | | | 543 | |
522 | ifmedia_init(&sc->sc_ifmedia, 0, iee_mediachange, iee_mediastatus); | | 544 | ifmedia_init(&sc->sc_ifmedia, 0, iee_mediachange, iee_mediastatus); |
523 | if (media != NULL) { | | 545 | if (media != NULL) { |
524 | for (n = 0 ; n < nmedia ; n++) | | 546 | for (n = 0 ; n < nmedia ; n++) |
525 | ifmedia_add(&sc->sc_ifmedia, media[n], 0, NULL); | | 547 | ifmedia_add(&sc->sc_ifmedia, media[n], 0, NULL); |
526 | ifmedia_set(&sc->sc_ifmedia, defmedia); | | 548 | ifmedia_set(&sc->sc_ifmedia, defmedia); |
527 | } else { | | 549 | } else { |
528 | ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_NONE, 0, NULL); | | 550 | ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_NONE, 0, NULL); |
529 | ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_NONE); | | 551 | ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_NONE); |
530 | } | | 552 | } |
531 | | | 553 | |
532 | ifp->if_softc = sc; | | 554 | ifp->if_softc = sc; |
533 | strcpy(ifp->if_xname, device_xname(sc->sc_dev)); | | 555 | strcpy(ifp->if_xname, device_xname(sc->sc_dev)); |
| @@ -646,32 +668,32 @@ iee_start(struct ifnet *ifp) | | | @@ -646,32 +668,32 @@ iee_start(struct ifnet *ifp) |
646 | m_freem(sc->sc_tx_mbuf[t]); | | 668 | m_freem(sc->sc_tx_mbuf[t]); |
647 | sc->sc_tx_mbuf[t] = m; | | 669 | sc->sc_tx_mbuf[t] = m; |
648 | if(bus_dmamap_load_mbuf(sc->sc_dmat, sc->sc_tx_map[t], | | 670 | if(bus_dmamap_load_mbuf(sc->sc_dmat, sc->sc_tx_map[t], |
649 | m, BUS_DMA_WRITE | BUS_DMA_NOWAIT) != 0) { | | 671 | m, BUS_DMA_WRITE | BUS_DMA_NOWAIT) != 0) { |
650 | printf("%s: iee_start: can't load TX DMA map\n", | | 672 | printf("%s: iee_start: can't load TX DMA map\n", |
651 | device_xname(sc->sc_dev)); | | 673 | device_xname(sc->sc_dev)); |
652 | m_freem(sc->sc_tx_mbuf[t]); | | 674 | m_freem(sc->sc_tx_mbuf[t]); |
653 | t--; | | 675 | t--; |
654 | continue; | | 676 | continue; |
655 | } | | 677 | } |
656 | } | | 678 | } |
657 | for (n = 0 ; n < sc->sc_tx_map[t]->dm_nsegs ; n++) { | | 679 | for (n = 0 ; n < sc->sc_tx_map[t]->dm_nsegs ; n++) { |
658 | SC_TBD(sc->sc_next_tbd + n)->tbd_tb_addr = | | 680 | SC_TBD(sc->sc_next_tbd + n)->tbd_tb_addr = |
659 | sc->sc_tx_map[t]->dm_segs[n].ds_addr; | | 681 | IEE_SWAPA32(sc->sc_tx_map[t]->dm_segs[n].ds_addr); |
660 | SC_TBD(sc->sc_next_tbd + n)->tbd_size = | | 682 | SC_TBD(sc->sc_next_tbd + n)->tbd_size = |
661 | sc->sc_tx_map[t]->dm_segs[n].ds_len; | | 683 | sc->sc_tx_map[t]->dm_segs[n].ds_len; |
662 | SC_TBD(sc->sc_next_tbd + n)->tbd_link_addr = | | 684 | SC_TBD(sc->sc_next_tbd + n)->tbd_link_addr = |
663 | IEE_PHYS_SHMEM(IEE_TBD_OFF + IEE_TBD_SZ | | 685 | IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_TBD_OFF + IEE_TBD_SZ |
664 | * (sc->sc_next_tbd + n + 1)); | | 686 | * (sc->sc_next_tbd + n + 1))); |
665 | } | | 687 | } |
666 | SC_TBD(sc->sc_next_tbd + n - 1)->tbd_size |= IEE_CB_EL; | | 688 | SC_TBD(sc->sc_next_tbd + n - 1)->tbd_size |= IEE_CB_EL; |
667 | bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_map[t], 0, | | 689 | bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_map[t], 0, |
668 | sc->sc_tx_map[t]->dm_mapsize, BUS_DMASYNC_PREWRITE); | | 690 | sc->sc_tx_map[t]->dm_mapsize, BUS_DMASYNC_PREWRITE); |
669 | IFQ_POLL(&ifp->if_snd, m); | | 691 | IFQ_POLL(&ifp->if_snd, m); |
670 | if (m == NULL) | | 692 | if (m == NULL) |
671 | iee_cb_setup(sc, IEE_CB_CMD_TR | IEE_CB_S | IEE_CB_EL | | 693 | iee_cb_setup(sc, IEE_CB_CMD_TR | IEE_CB_S | IEE_CB_EL |
672 | | IEE_CB_I); | | 694 | | IEE_CB_I); |
673 | else | | 695 | else |
674 | iee_cb_setup(sc, IEE_CB_CMD_TR); | | 696 | iee_cb_setup(sc, IEE_CB_CMD_TR); |
675 | sc->sc_next_tbd += n; | | 697 | sc->sc_next_tbd += n; |
676 | #if NBPFILTER > 0 | | 698 | #if NBPFILTER > 0 |
677 | /* Pass packet to bpf if someone listens. */ | | 699 | /* Pass packet to bpf if someone listens. */ |
| @@ -768,31 +790,33 @@ iee_init(struct ifnet *ifp) | | | @@ -768,31 +790,33 @@ iee_init(struct ifnet *ifp) |
768 | device_xname(sc->sc_dev)); | | 790 | device_xname(sc->sc_dev)); |
769 | for (n = 0 ; n < t ; n++) | | 791 | for (n = 0 ; n < t ; n++) |
770 | bus_dmamap_destroy(sc->sc_dmat, | | 792 | bus_dmamap_destroy(sc->sc_dmat, |
771 | sc->sc_tx_map[n]); | | 793 | sc->sc_tx_map[n]); |
772 | return ENOBUFS; | | 794 | return ENOBUFS; |
773 | } | | 795 | } |
774 | } | | 796 | } |
775 | /* Initialize Receive Frame and Receive Buffer Descriptors */ | | 797 | /* Initialize Receive Frame and Receive Buffer Descriptors */ |
776 | err = 0; | | 798 | err = 0; |
777 | memset(SC_RFD(0), 0, IEE_RFD_LIST_SZ); | | 799 | memset(SC_RFD(0), 0, IEE_RFD_LIST_SZ); |
778 | memset(SC_RBD(0), 0, IEE_RBD_LIST_SZ); | | 800 | memset(SC_RBD(0), 0, IEE_RBD_LIST_SZ); |
779 | for (r = 0 ; r < IEE_NRFD ; r++) { | | 801 | for (r = 0 ; r < IEE_NRFD ; r++) { |
780 | SC_RFD(r)->rfd_cmd = IEE_RFD_SF; | | 802 | SC_RFD(r)->rfd_cmd = IEE_RFD_SF; |
781 | SC_RFD(r)->rfd_link_addr = IEE_PHYS_SHMEM(IEE_RFD_OFF | | 803 | SC_RFD(r)->rfd_link_addr = |
782 | + IEE_RFD_SZ * ((r + 1) % IEE_NRFD)); | | 804 | IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_RFD_OFF |
783 | | | 805 | + IEE_RFD_SZ * ((r + 1) % IEE_NRFD))); |
784 | SC_RBD(r)->rbd_next_rbd = IEE_PHYS_SHMEM(IEE_RBD_OFF | | 806 | |
785 | + IEE_RBD_SZ * ((r + 1) % IEE_NRFD)); | | 807 | SC_RBD(r)->rbd_next_rbd = |
| | | 808 | IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_RBD_OFF |
| | | 809 | + IEE_RBD_SZ * ((r + 1) % IEE_NRFD))); |
786 | if (sc->sc_rx_mbuf[r] == NULL) { | | 810 | if (sc->sc_rx_mbuf[r] == NULL) { |
787 | MGETHDR(sc->sc_rx_mbuf[r], M_DONTWAIT, MT_DATA); | | 811 | MGETHDR(sc->sc_rx_mbuf[r], M_DONTWAIT, MT_DATA); |
788 | if (sc->sc_rx_mbuf[r] == NULL) { | | 812 | if (sc->sc_rx_mbuf[r] == NULL) { |
789 | printf("%s: iee_init: can't allocate mbuf\n", | | 813 | printf("%s: iee_init: can't allocate mbuf\n", |
790 | device_xname(sc->sc_dev)); | | 814 | device_xname(sc->sc_dev)); |
791 | err = 1; | | 815 | err = 1; |
792 | break; | | 816 | break; |
793 | } | | 817 | } |
794 | MCLAIM(sc->sc_rx_mbuf[r],&sc->sc_ethercom.ec_rx_mowner); | | 818 | MCLAIM(sc->sc_rx_mbuf[r],&sc->sc_ethercom.ec_rx_mowner); |
795 | MCLGET(sc->sc_rx_mbuf[r], M_DONTWAIT); | | 819 | MCLGET(sc->sc_rx_mbuf[r], M_DONTWAIT); |
796 | if ((sc->sc_rx_mbuf[r]->m_flags & M_EXT) == 0) { | | 820 | if ((sc->sc_rx_mbuf[r]->m_flags & M_EXT) == 0) { |
797 | printf("%s: iee_init: can't allocate mbuf" | | 821 | printf("%s: iee_init: can't allocate mbuf" |
798 | " cluster\n", device_xname(sc->sc_dev)); | | 822 | " cluster\n", device_xname(sc->sc_dev)); |
| @@ -814,29 +838,30 @@ iee_init(struct ifnet *ifp) | | | @@ -814,29 +838,30 @@ iee_init(struct ifnet *ifp) |
814 | sc->sc_rx_mbuf[r]->m_ext.ext_buf, | | 838 | sc->sc_rx_mbuf[r]->m_ext.ext_buf, |
815 | sc->sc_rx_mbuf[r]->m_ext.ext_size, NULL, | | 839 | sc->sc_rx_mbuf[r]->m_ext.ext_size, NULL, |
816 | BUS_DMA_READ | BUS_DMA_NOWAIT) != 0) { | | 840 | BUS_DMA_READ | BUS_DMA_NOWAIT) != 0) { |
817 | printf("%s: iee_init: can't load RX DMA map\n", | | 841 | printf("%s: iee_init: can't load RX DMA map\n", |
818 | device_xname(sc->sc_dev)); | | 842 | device_xname(sc->sc_dev)); |
819 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_map[r]); | | 843 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_map[r]); |
820 | m_freem(sc->sc_rx_mbuf[r]); | | 844 | m_freem(sc->sc_rx_mbuf[r]); |
821 | err = 1; | | 845 | err = 1; |
822 | break; | | 846 | break; |
823 | } | | 847 | } |
824 | bus_dmamap_sync(sc->sc_dmat, sc->sc_rx_map[r], 0, | | 848 | bus_dmamap_sync(sc->sc_dmat, sc->sc_rx_map[r], 0, |
825 | sc->sc_rx_mbuf[r]->m_ext.ext_size, BUS_DMASYNC_PREREAD); | | 849 | sc->sc_rx_mbuf[r]->m_ext.ext_size, BUS_DMASYNC_PREREAD); |
826 | SC_RBD(r)->rbd_size = sc->sc_rx_map[r]->dm_segs[0].ds_len; | | 850 | SC_RBD(r)->rbd_size = sc->sc_rx_map[r]->dm_segs[0].ds_len; |
827 | SC_RBD(r)->rbd_rb_addr= sc->sc_rx_map[r]->dm_segs[0].ds_addr; | | 851 | SC_RBD(r)->rbd_rb_addr = |
| | | 852 | IEE_SWAPA32(sc->sc_rx_map[r]->dm_segs[0].ds_addr); |
828 | } | | 853 | } |
829 | SC_RFD(0)->rfd_rbd_addr = IEE_PHYS_SHMEM(IEE_RBD_OFF); | | 854 | SC_RFD(0)->rfd_rbd_addr = IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_RBD_OFF)); |
830 | if (err != 0) { | | 855 | if (err != 0) { |
831 | for (n = 0 ; n < r; n++) { | | 856 | for (n = 0 ; n < r; n++) { |
832 | m_freem(sc->sc_rx_mbuf[n]); | | 857 | m_freem(sc->sc_rx_mbuf[n]); |
833 | sc->sc_rx_mbuf[n] = NULL; | | 858 | sc->sc_rx_mbuf[n] = NULL; |
834 | bus_dmamap_unload(sc->sc_dmat, sc->sc_rx_map[n]); | | 859 | bus_dmamap_unload(sc->sc_dmat, sc->sc_rx_map[n]); |
835 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_map[n]); | | 860 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_map[n]); |
836 | sc->sc_rx_map[n] = NULL; | | 861 | sc->sc_rx_map[n] = NULL; |
837 | } | | 862 | } |
838 | for (n = 0 ; n < t ; n++) { | | 863 | for (n = 0 ; n < t ; n++) { |
839 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_map[n]); | | 864 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_map[n]); |
840 | sc->sc_tx_map[n] = NULL; | | 865 | sc->sc_tx_map[n] = NULL; |
841 | } | | 866 | } |
842 | return ENOBUFS; | | 867 | return ENOBUFS; |
| @@ -850,27 +875,27 @@ iee_init(struct ifnet *ifp) | | | @@ -850,27 +875,27 @@ iee_init(struct ifnet *ifp) |
850 | sc->sc_cf[3] = IEE_CF_3_ADDRLEN_DEF | IEE_CF_3_NSAI | | 875 | sc->sc_cf[3] = IEE_CF_3_ADDRLEN_DEF | IEE_CF_3_NSAI |
851 | | IEE_CF_3_PREAMLEN_DEF; | | 876 | | IEE_CF_3_PREAMLEN_DEF; |
852 | sc->sc_cf[4] = IEE_CF_4_DEF; | | 877 | sc->sc_cf[4] = IEE_CF_4_DEF; |
853 | sc->sc_cf[5] = IEE_CF_5_DEF; | | 878 | sc->sc_cf[5] = IEE_CF_5_DEF; |
854 | sc->sc_cf[6] = IEE_CF_6_DEF; | | 879 | sc->sc_cf[6] = IEE_CF_6_DEF; |
855 | sc->sc_cf[7] = IEE_CF_7_DEF; | | 880 | sc->sc_cf[7] = IEE_CF_7_DEF; |
856 | sc->sc_cf[8] = IEE_CF_8_DEF; | | 881 | sc->sc_cf[8] = IEE_CF_8_DEF; |
857 | sc->sc_cf[9] = IEE_CF_9_DEF; | | 882 | sc->sc_cf[9] = IEE_CF_9_DEF; |
858 | sc->sc_cf[10] = IEE_CF_10_DEF; | | 883 | sc->sc_cf[10] = IEE_CF_10_DEF; |
859 | sc->sc_cf[11] = IEE_CF_11_DEF & ~IEE_CF_11_LNGFLD; | | 884 | sc->sc_cf[11] = IEE_CF_11_DEF & ~IEE_CF_11_LNGFLD; |
860 | sc->sc_cf[12] = IEE_CF_12_DEF; | | 885 | sc->sc_cf[12] = IEE_CF_12_DEF; |
861 | sc->sc_cf[13] = IEE_CF_13_DEF; | | 886 | sc->sc_cf[13] = IEE_CF_13_DEF; |
862 | iee_cb_setup(sc, IEE_CB_CMD_CONF | IEE_CB_S | IEE_CB_EL); | | 887 | iee_cb_setup(sc, IEE_CB_CMD_CONF | IEE_CB_S | IEE_CB_EL); |
863 | SC_SCB->scb_rfa_addr = IEE_PHYS_SHMEM(IEE_RFD_OFF); | | 888 | SC_SCB->scb_rfa_addr = IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_RFD_OFF)); |
864 | bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, 0, IEE_SHMEM_MAX, | | 889 | bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, 0, IEE_SHMEM_MAX, |
865 | BUS_DMASYNC_PREWRITE); | | 890 | BUS_DMASYNC_PREWRITE); |
866 | (sc->sc_iee_cmd)(sc, IEE_SCB_CUC_EXE | IEE_SCB_RUC_ST); | | 891 | (sc->sc_iee_cmd)(sc, IEE_SCB_CUC_EXE | IEE_SCB_RUC_ST); |
867 | /* Issue a Channel Attention to ACK interrupts we may have caused. */ | | 892 | /* Issue a Channel Attention to ACK interrupts we may have caused. */ |
868 | (sc->sc_iee_cmd)(sc, IEE_SCB_ACK); | | 893 | (sc->sc_iee_cmd)(sc, IEE_SCB_ACK); |
869 | | | 894 | |
870 | /* Mark the interface as running and ready to RX/TX packets. */ | | 895 | /* Mark the interface as running and ready to RX/TX packets. */ |
871 | ifp->if_flags |= IFF_RUNNING; | | 896 | ifp->if_flags |= IFF_RUNNING; |
872 | ifp->if_flags &= ~IFF_OACTIVE; | | 897 | ifp->if_flags &= ~IFF_OACTIVE; |
873 | return 0; | | 898 | return 0; |
874 | } | | 899 | } |
875 | | | 900 | |
876 | | | 901 | |