1 1.35 andvar /* $NetBSD: mb86950.c,v 1.35 2021/07/31 14:36:33 andvar Exp $ */ 2 1.1 jdolecek 3 1.1 jdolecek /* 4 1.1 jdolecek * All Rights Reserved, Copyright (C) Fujitsu Limited 1995 5 1.1 jdolecek * 6 1.1 jdolecek * This software may be used, modified, copied, distributed, and sold, in 7 1.1 jdolecek * both source and binary form provided that the above copyright, these 8 1.1 jdolecek * terms and the following disclaimer are retained. The name of the author 9 1.1 jdolecek * and/or the contributor may not be used to endorse or promote products 10 1.1 jdolecek * derived from this software without specific prior written permission. 11 1.1 jdolecek * 12 1.1 jdolecek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND THE CONTRIBUTOR ``AS IS'' AND 13 1.1 jdolecek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 1.1 jdolecek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15 1.1 jdolecek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTOR BE LIABLE 16 1.1 jdolecek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17 1.1 jdolecek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 18 1.1 jdolecek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION. 19 1.1 jdolecek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 20 1.1 jdolecek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 21 1.1 jdolecek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 22 1.1 jdolecek * SUCH DAMAGE. 23 1.1 jdolecek */ 24 1.1 jdolecek 25 1.1 jdolecek /* 26 1.1 jdolecek * Portions copyright (C) 1993, David Greenman. This software may be used, 27 1.1 jdolecek * modified, copied, distributed, and sold, in both source and binary form 28 1.1 jdolecek * provided that the above copyright and these terms are retained. Under no 29 1.1 jdolecek * circumstances is the author responsible for the proper functioning of this 30 1.1 jdolecek * software, nor does the author assume any responsibility for damages 31 1.1 jdolecek * incurred with its use. 32 1.1 jdolecek */ 33 1.1 jdolecek 34 1.1 jdolecek /* 35 1.1 jdolecek * Portions copyright (c) 1995 Mika Kortelainen 36 1.1 jdolecek * All rights reserved. 37 1.1 jdolecek * 38 1.1 jdolecek * Redistribution and use in source and binary forms, with or without 39 1.1 jdolecek * modification, are permitted provided that the following conditions 40 1.1 jdolecek * are met: 41 1.1 jdolecek * 1. Redistributions of source code must retain the above copyright 42 1.1 jdolecek * notice, this list of conditions and the following disclaimer. 43 1.1 jdolecek * 2. Redistributions in binary form must reproduce the above copyright 44 1.1 jdolecek * notice, this list of conditions and the following disclaimer in the 45 1.1 jdolecek * documentation and/or other materials provided with the distribution. 46 1.1 jdolecek * 3. All advertising materials mentioning features or use of this software 47 1.1 jdolecek * must display the following acknowledgement: 48 1.1 jdolecek * This product includes software developed by Mika Kortelainen 49 1.1 jdolecek * 4. The name of the author may not be used to endorse or promote products 50 1.1 jdolecek * derived from this software without specific prior written permission 51 1.1 jdolecek * 52 1.1 jdolecek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 53 1.1 jdolecek * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 54 1.1 jdolecek * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 55 1.1 jdolecek * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 56 1.1 jdolecek * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 57 1.1 jdolecek * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 58 1.1 jdolecek * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 59 1.1 jdolecek * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 60 1.1 jdolecek * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 61 1.1 jdolecek * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 1.1 jdolecek */ 63 1.1 jdolecek 64 1.1 jdolecek /* 65 1.1 jdolecek * Device driver for Fujitsu MB86960A/MB86965A based Ethernet cards. 66 1.1 jdolecek * Contributed by M.S. <seki (at) sysrap.cs.fujitsu.co.jp> 67 1.1 jdolecek */ 68 1.1 jdolecek 69 1.1 jdolecek #include <sys/cdefs.h> 70 1.35 andvar __KERNEL_RCSID(0, "$NetBSD: mb86950.c,v 1.35 2021/07/31 14:36:33 andvar Exp $"); 71 1.1 jdolecek 72 1.1 jdolecek /* 73 1.1 jdolecek * Device driver for Fujitsu mb86950 based Ethernet cards. 74 1.1 jdolecek * Adapted by Dave J. Barnes from various Internet sources including 75 1.1 jdolecek * mb86960.c (NetBSD), if_qn.c (NetBSD/Amiga), DOS Packet Driver (Brian Fisher, 76 1.1 jdolecek * Queens University), EtherBoot Driver (Ken Yap). 77 1.1 jdolecek */ 78 1.1 jdolecek 79 1.1 jdolecek /* XXX There are still rough edges...... 80 1.2 jdolecek * 81 1.1 jdolecek * (1) There is no watchdog timer for the transmitter. It's doubtful that 82 1.2 jdolecek * transmit from the chip could be restarted without a hardware reset 83 1.2 jdolecek * though. (Fixed - not fully tested) 84 1.2 jdolecek * 85 1.1 jdolecek * (2) The media interface callback goo is broke. No big deal since to change 86 1.2 jdolecek * from aui to bnc on the old Tiara LANCard requires moving 8 board jumpers. 87 1.2 jdolecek * Other cards (SMC ?) using the EtherStar chip may support media change 88 1.2 jdolecek * via software. (Fixed - tested) 89 1.2 jdolecek * 90 1.2 jdolecek * (3) The maximum outstanding transmit packets is set to 4. What 91 1.2 jdolecek * is a good limit of outstanding transmit packets for the EtherStar? 92 1.2 jdolecek * Is there a way to tell how many bytes are remaining to be 93 1.2 jdolecek * transmitted? [no] 94 1.1 jdolecek --- 95 1.2 jdolecek When the EtherStar was designed, CPU power was a fraction 96 1.2 jdolecek of what it is now. The single EtherStar transmit buffer 97 1.2 jdolecek was fine. It was unlikely that the CPU could outrun the 98 1.2 jdolecek EtherStar. However, things in 2004 are quite different. 99 1.2 jdolecek sc->txb_size is used to keep the CPU from overrunning the 100 1.2 jdolecek EtherStar. At most allow one packet transmitting and one 101 1.2 jdolecek going into the fifo. 102 1.2 jdolecek 103 1.1 jdolecek --- 104 1.1 jdolecek No, that isn't right either :( 105 1.1 jdolecek 106 1.2 jdolecek * (4) Multicast isn't supported. Feel free to add multicast code 107 1.2 jdolecek * if you know how to make the EtherStar do multicast. Otherwise 108 1.2 jdolecek * you'd have to use promiscuous mode and do multicast in software. OUCH! 109 1.2 jdolecek * 110 1.1 jdolecek * (5) There are no bus_space_barrier calls used. Are they needed? Maybe not. 111 1.2 jdolecek * 112 1.2 jdolecek * (6) Access to the fifo assumes word (16 bit) mode. Cards configured for 113 1.2 jdolecek * byte wide fifo access will require driver code changes. 114 1.2 jdolecek * 115 1.2 jdolecek * Only the minimum code necessary to make the Tiara LANCard work 116 1.2 jdolecek * has been tested. Other cards may require more work, especially 117 1.2 jdolecek * byte mode fifo and if DMA is used. 118 1.2 jdolecek * 119 1.1 jdolecek * djb / 2004 120 1.1 jdolecek */ 121 1.1 jdolecek 122 1.1 jdolecek #include "opt_inet.h" 123 1.1 jdolecek 124 1.1 jdolecek #include <sys/param.h> 125 1.1 jdolecek #include <sys/systm.h> 126 1.1 jdolecek #include <sys/errno.h> 127 1.1 jdolecek #include <sys/ioctl.h> 128 1.1 jdolecek #include <sys/mbuf.h> 129 1.1 jdolecek #include <sys/socket.h> 130 1.1 jdolecek #include <sys/syslog.h> 131 1.1 jdolecek #include <sys/device.h> 132 1.22 riastrad #include <sys/rndsource.h> 133 1.1 jdolecek 134 1.1 jdolecek #include <net/if.h> 135 1.1 jdolecek #include <net/if_dl.h> 136 1.1 jdolecek #include <net/if_types.h> 137 1.1 jdolecek #include <net/if_media.h> 138 1.1 jdolecek #include <net/if_ether.h> 139 1.27 msaitoh #include <net/bpf.h> 140 1.1 jdolecek 141 1.1 jdolecek #ifdef INET 142 1.1 jdolecek #include <netinet/in.h> 143 1.1 jdolecek #include <netinet/in_systm.h> 144 1.1 jdolecek #include <netinet/in_var.h> 145 1.1 jdolecek #include <netinet/ip.h> 146 1.1 jdolecek #include <netinet/if_inarp.h> 147 1.1 jdolecek #endif 148 1.1 jdolecek 149 1.10 ad #include <sys/bus.h> 150 1.1 jdolecek 151 1.1 jdolecek #include <dev/ic/mb86950reg.h> 152 1.1 jdolecek #include <dev/ic/mb86950var.h> 153 1.1 jdolecek 154 1.1 jdolecek #ifndef __BUS_SPACE_HAS_STREAM_METHODS 155 1.1 jdolecek #define bus_space_write_stream_2 bus_space_write_2 156 1.1 jdolecek #define bus_space_write_multi_stream_2 bus_space_write_multi_2 157 1.1 jdolecek #define bus_space_read_multi_stream_2 bus_space_read_multi_2 158 1.1 jdolecek #endif /* __BUS_SPACE_HAS_STREAM_METHODS */ 159 1.1 jdolecek 160 1.1 jdolecek /* Standard driver entry points. These can be static. */ 161 1.13 dsl int mb86950_ioctl(struct ifnet *, u_long, void *); 162 1.13 dsl void mb86950_init(struct mb86950_softc *); 163 1.13 dsl void mb86950_start(struct ifnet *); 164 1.13 dsl void mb86950_watchdog(struct ifnet *); 165 1.13 dsl void mb86950_reset(struct mb86950_softc *); 166 1.1 jdolecek 167 1.1 jdolecek /* Local functions. */ 168 1.13 dsl void mb86950_stop(struct mb86950_softc *); 169 1.13 dsl void mb86950_tint(struct mb86950_softc *, u_int8_t); 170 1.13 dsl void mb86950_rint(struct mb86950_softc *, u_int8_t); 171 1.13 dsl int mb86950_get_fifo(struct mb86950_softc *, u_int); 172 1.13 dsl ushort mb86950_put_fifo(struct mb86950_softc *, struct mbuf *); 173 1.13 dsl void mb86950_drain_fifo(struct mb86950_softc *); 174 1.1 jdolecek 175 1.13 dsl int mb86950_mediachange(struct ifnet *); 176 1.13 dsl void mb86950_mediastatus(struct ifnet *, struct ifmediareq *); 177 1.1 jdolecek 178 1.1 jdolecek 179 1.1 jdolecek #if ESTAR_DEBUG >= 1 180 1.13 dsl void mb86950_dump(int, struct mb86950_softc *); 181 1.1 jdolecek #endif 182 1.1 jdolecek 183 1.1 jdolecek /********************************************************************/ 184 1.1 jdolecek 185 1.1 jdolecek void 186 1.14 dsl mb86950_attach(struct mb86950_softc *sc, u_int8_t *myea) 187 1.1 jdolecek { 188 1.1 jdolecek 189 1.1 jdolecek #ifdef DIAGNOSTIC 190 1.1 jdolecek if (myea == NULL) { 191 1.1 jdolecek printf("%s: ethernet address shouldn't be NULL\n", 192 1.20 chs device_xname(sc->sc_dev)); 193 1.1 jdolecek panic("NULL ethernet address"); 194 1.1 jdolecek } 195 1.1 jdolecek #endif 196 1.1 jdolecek 197 1.1 jdolecek /* Initialize 86950. */ 198 1.1 jdolecek mb86950_stop(sc); 199 1.1 jdolecek 200 1.1 jdolecek memcpy(sc->sc_enaddr, myea, sizeof(sc->sc_enaddr)); 201 1.1 jdolecek 202 1.1 jdolecek sc->sc_stat |= ESTAR_STAT_ENABLED; 203 1.1 jdolecek } 204 1.1 jdolecek 205 1.1 jdolecek /* 206 1.1 jdolecek * Stop everything on the interface. 207 1.1 jdolecek * 208 1.1 jdolecek * All buffered packets, both transmitting and receiving, 209 1.1 jdolecek * if any, will be lost by stopping the interface. 210 1.1 jdolecek */ 211 1.1 jdolecek void 212 1.14 dsl mb86950_stop(struct mb86950_softc *sc) 213 1.1 jdolecek { 214 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst; 215 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh; 216 1.1 jdolecek 217 1.1 jdolecek /* Stop interface hardware. */ 218 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_CONFIG, DISABLE_DLC); 219 1.1 jdolecek delay(200); 220 1.1 jdolecek 221 1.1 jdolecek /* Disable interrupts. */ 222 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, 0); 223 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, 0); 224 1.1 jdolecek 225 1.1 jdolecek /* Ack / Clear all interrupt status. */ 226 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_TX_STAT, 0xff); 227 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_RX_STAT, 0xff); 228 1.1 jdolecek 229 1.1 jdolecek /* Clear DMA Bit */ 230 1.30 msaitoh bus_space_write_2(bst, bsh, BMPR_DMA, 0); 231 1.1 jdolecek 232 1.30 msaitoh /* accept no packets */ 233 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_TX_MODE, 0); 234 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_RX_MODE, 0); 235 1.1 jdolecek 236 1.30 msaitoh mb86950_drain_fifo(sc); 237 1.1 jdolecek } 238 1.1 jdolecek 239 1.1 jdolecek void 240 1.14 dsl mb86950_drain_fifo(struct mb86950_softc *sc) 241 1.1 jdolecek { 242 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst; 243 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh; 244 1.1 jdolecek 245 1.1 jdolecek /* Read data until bus read error (i.e. buffer empty). */ 246 1.2 jdolecek /* XXX There ought to be a better way, eats CPU and bothers the chip */ 247 1.1 jdolecek while (!(bus_space_read_1(bst, bsh, DLCR_RX_STAT) & RX_BUS_RD_ERR)) 248 1.1 jdolecek bus_space_read_2(bst, bsh, BMPR_FIFO); 249 1.2 jdolecek /* XXX */ 250 1.1 jdolecek 251 1.1 jdolecek /* Clear Bus Rd Error */ 252 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_RX_STAT, RX_BUS_RD_ERR); 253 1.1 jdolecek } 254 1.1 jdolecek 255 1.1 jdolecek /* 256 1.1 jdolecek * Install interface into kernel networking data structures 257 1.1 jdolecek */ 258 1.1 jdolecek void 259 1.30 msaitoh mb86950_config(struct mb86950_softc *sc, int *media, int nmedia, int defmedia) 260 1.1 jdolecek { 261 1.1 jdolecek struct ifnet *ifp = &sc->sc_ec.ec_if; 262 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst; 263 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh; 264 1.1 jdolecek 265 1.1 jdolecek /* Initialize ifnet structure. */ 266 1.20 chs strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); 267 1.1 jdolecek ifp->if_softc = sc; 268 1.1 jdolecek ifp->if_start = mb86950_start; 269 1.1 jdolecek ifp->if_ioctl = mb86950_ioctl; 270 1.1 jdolecek ifp->if_watchdog = mb86950_watchdog; 271 1.29 msaitoh ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 272 1.1 jdolecek 273 1.1 jdolecek IFQ_SET_READY(&ifp->if_snd); 274 1.1 jdolecek 275 1.1 jdolecek /* Initialize media goo. */ 276 1.1 jdolecek /* XXX The Tiara LANCard uses board jumpers to change media. 277 1.1 jdolecek * This code may have to be changed for other cards. 278 1.1 jdolecek */ 279 1.32 msaitoh sc->sc_ec.ec_ifmedia = &sc->sc_media; 280 1.30 msaitoh ifmedia_init(&sc->sc_media, 0, mb86950_mediachange, 281 1.30 msaitoh mb86950_mediastatus); 282 1.1 jdolecek ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_MANUAL, 0, NULL); 283 1.1 jdolecek ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_MANUAL); 284 1.1 jdolecek 285 1.1 jdolecek /* Attach the interface. */ 286 1.1 jdolecek if_attach(ifp); 287 1.26 ozaki if_deferred_start_init(ifp, NULL); 288 1.1 jdolecek 289 1.1 jdolecek /* Feed the chip the station address. */ 290 1.30 msaitoh bus_space_write_region_1(bst, bsh, DLCR_NODE_ID, sc->sc_enaddr, 291 1.30 msaitoh ETHER_ADDR_LEN); 292 1.1 jdolecek 293 1.1 jdolecek ether_ifattach(ifp, sc->sc_enaddr); 294 1.1 jdolecek 295 1.20 chs rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), 296 1.21 tls RND_TYPE_NET, RND_FLAG_DEFAULT); 297 1.1 jdolecek 298 1.1 jdolecek /* XXX No! This doesn't work - DLCR6 of the mb86950 is different 299 1.1 jdolecek 300 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_CONFIG, 0x0f); 301 1.1 jdolecek buf_config = bus_space_read_1(bst, bsh, DLCR_CONFIG); 302 1.1 jdolecek 303 1.1 jdolecek sc->txb_count = ((buf_config & 0x0c) ? 2 : 1); 304 1.1 jdolecek sc->txb_size = 1024 * (2 << ((buf_config & 0x0c) ? (((buf_config & 0x0c) >> 2) - 1) : 0)); 305 1.1 jdolecek sc->txb_free = (sc->txb_size * sc->txb_count) / 1500; 306 1.1 jdolecek 307 1.31 msaitoh sc->rxb_size = ((8 << (buf_config & 3)) * 1024) - (sc->txb_size * sc->txb_count); 308 1.1 jdolecek sc->rxb_max = sc->rxb_size / 64; 309 1.1 jdolecek 310 1.1 jdolecek printf("mb86950: Buffer Size %dKB with %d transmit buffer(s) %dKB each.\n", 311 1.1 jdolecek (8 << (buf_config & 3)), sc->txb_count, (sc->txb_size / 1024)); 312 1.1 jdolecek printf(" Transmit Buffer Space for %d maximum sized packet(s).\n",sc->txb_free); 313 1.1 jdolecek printf(" System Bus Width %d bits, Buffer Memory %d bits.\n", 314 1.1 jdolecek ((buf_config & 0x20) ? 8 : 16), 315 1.1 jdolecek ((buf_config & 0x10) ? 8 : 16)); 316 1.1 jdolecek 317 1.1 jdolecek */ 318 1.1 jdolecek 319 1.2 jdolecek /* Set reasonable values for number of packet flow control if not 320 1.2 jdolecek * set elsewhere */ 321 1.1 jdolecek if (sc->txb_num_pkt == 0) sc->txb_num_pkt = 1; 322 1.1 jdolecek if (sc->rxb_num_pkt == 0) sc->rxb_num_pkt = 100; 323 1.1 jdolecek 324 1.1 jdolecek /* Print additional info when attached. */ 325 1.20 chs printf("%s: Ethernet address %s\n", device_xname(sc->sc_dev), 326 1.2 jdolecek ether_sprintf(sc->sc_enaddr)); 327 1.1 jdolecek 328 1.1 jdolecek /* The attach is successful. */ 329 1.1 jdolecek sc->sc_stat |= ESTAR_STAT_ATTACHED; 330 1.1 jdolecek } 331 1.1 jdolecek 332 1.1 jdolecek /* 333 1.1 jdolecek * Media change callback. 334 1.1 jdolecek */ 335 1.1 jdolecek int 336 1.14 dsl mb86950_mediachange(struct ifnet *ifp) 337 1.1 jdolecek { 338 1.1 jdolecek 339 1.1 jdolecek struct mb86950_softc *sc = ifp->if_softc; 340 1.1 jdolecek 341 1.1 jdolecek if (sc->sc_mediachange) 342 1.30 msaitoh return (*sc->sc_mediachange)(sc); 343 1.1 jdolecek 344 1.30 msaitoh return 0; 345 1.1 jdolecek } 346 1.1 jdolecek 347 1.1 jdolecek /* 348 1.1 jdolecek * Media status callback. 349 1.1 jdolecek */ 350 1.1 jdolecek void 351 1.14 dsl mb86950_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 352 1.1 jdolecek { 353 1.1 jdolecek struct mb86950_softc *sc = ifp->if_softc; 354 1.1 jdolecek 355 1.1 jdolecek if ((sc->sc_stat & ESTAR_STAT_ENABLED) == 0) { 356 1.1 jdolecek ifmr->ifm_active = IFM_ETHER | IFM_NONE; 357 1.1 jdolecek ifmr->ifm_status = 0; 358 1.1 jdolecek return; 359 1.1 jdolecek } 360 1.1 jdolecek 361 1.1 jdolecek if (sc->sc_mediastatus) 362 1.1 jdolecek (*sc->sc_mediastatus)(sc, ifmr); 363 1.1 jdolecek 364 1.1 jdolecek } 365 1.1 jdolecek 366 1.1 jdolecek /* 367 1.1 jdolecek * Reset interface. 368 1.1 jdolecek */ 369 1.1 jdolecek void 370 1.14 dsl mb86950_reset(struct mb86950_softc *sc) 371 1.1 jdolecek { 372 1.1 jdolecek int s; 373 1.1 jdolecek 374 1.1 jdolecek s = splnet(); 375 1.20 chs log(LOG_ERR, "%s: device reset\n", device_xname(sc->sc_dev)); 376 1.1 jdolecek mb86950_stop(sc); 377 1.1 jdolecek mb86950_init(sc); 378 1.1 jdolecek splx(s); 379 1.1 jdolecek } 380 1.1 jdolecek 381 1.1 jdolecek /* 382 1.1 jdolecek * Device timeout/watchdog routine. Entered if the device neglects to 383 1.1 jdolecek * generate an interrupt after a transmit has been started on it. 384 1.1 jdolecek */ 385 1.1 jdolecek void 386 1.14 dsl mb86950_watchdog(struct ifnet *ifp) 387 1.1 jdolecek { 388 1.1 jdolecek struct mb86950_softc *sc = ifp->if_softc; 389 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst; 390 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh; 391 1.1 jdolecek u_int8_t tstat; 392 1.1 jdolecek 393 1.30 msaitoh /* Verbose watchdog messages for debugging timeouts */ 394 1.30 msaitoh if ((tstat = bus_space_read_1(bst, bsh, DLCR_TX_STAT)) != 0) { 395 1.1 jdolecek if (tstat & TX_CR_LOST) { 396 1.2 jdolecek if ((tstat & (TX_COL | TX_16COL)) == 0) { 397 1.2 jdolecek log(LOG_ERR, "%s: carrier lost\n", 398 1.20 chs device_xname(sc->sc_dev)); 399 1.2 jdolecek } else { 400 1.2 jdolecek log(LOG_ERR, "%s: excessive collisions\n", 401 1.20 chs device_xname(sc->sc_dev)); 402 1.2 jdolecek } 403 1.2 jdolecek } 404 1.2 jdolecek else if ((tstat & (TX_UNDERFLO | TX_BUS_WR_ERR)) != 0) { 405 1.2 jdolecek log(LOG_ERR, "%s: tx fifo underflow/overflow\n", 406 1.20 chs device_xname(sc->sc_dev)); 407 1.2 jdolecek } else { 408 1.2 jdolecek log(LOG_ERR, "%s: transmit error\n", 409 1.20 chs device_xname(sc->sc_dev)); 410 1.1 jdolecek } 411 1.30 msaitoh } else 412 1.20 chs log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev)); 413 1.1 jdolecek 414 1.30 msaitoh /* 415 1.30 msaitoh * Don't know how many packets are lost by this accident. 416 1.1 jdolecek * ... So just errors = errors + 1 417 1.1 jdolecek */ 418 1.33 thorpej if_statinc(ifp, if_oerrors); 419 1.1 jdolecek 420 1.1 jdolecek mb86950_reset(sc); 421 1.1 jdolecek } 422 1.1 jdolecek 423 1.1 jdolecek /* 424 1.1 jdolecek ******************** IOCTL 425 1.1 jdolecek * Process an ioctl request. 426 1.1 jdolecek */ 427 1.1 jdolecek int 428 1.12 dyoung mb86950_ioctl(struct ifnet *ifp, unsigned long cmd, void *data) 429 1.1 jdolecek { 430 1.1 jdolecek struct mb86950_softc *sc = ifp->if_softc; 431 1.1 jdolecek struct ifaddr *ifa = (struct ifaddr *)data; 432 1.1 jdolecek 433 1.1 jdolecek int s, error = 0; 434 1.1 jdolecek 435 1.1 jdolecek s = splnet(); 436 1.1 jdolecek 437 1.1 jdolecek switch (cmd) { 438 1.12 dyoung case SIOCINITIFADDR: 439 1.12 dyoung /* XXX deprecated ? What should I use instead? */ 440 1.1 jdolecek if ((error = mb86950_enable(sc)) != 0) 441 1.1 jdolecek break; 442 1.1 jdolecek 443 1.1 jdolecek ifp->if_flags |= IFF_UP; 444 1.1 jdolecek 445 1.12 dyoung mb86950_init(sc); 446 1.1 jdolecek switch (ifa->ifa_addr->sa_family) { 447 1.1 jdolecek 448 1.1 jdolecek #ifdef INET 449 1.1 jdolecek case AF_INET: 450 1.1 jdolecek arp_ifinit(ifp, ifa); 451 1.1 jdolecek break; 452 1.1 jdolecek #endif 453 1.1 jdolecek 454 1.1 jdolecek 455 1.1 jdolecek default: 456 1.1 jdolecek break; 457 1.1 jdolecek } 458 1.1 jdolecek break; 459 1.1 jdolecek 460 1.1 jdolecek case SIOCSIFFLAGS: 461 1.12 dyoung if ((error = ifioctl_common(ifp, cmd, data)) != 0) 462 1.12 dyoung break; 463 1.12 dyoung /* XXX re-use ether_ioctl() */ 464 1.12 dyoung switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) { 465 1.12 dyoung case IFF_RUNNING: 466 1.1 jdolecek /* 467 1.1 jdolecek * If interface is marked down and it is running, then 468 1.1 jdolecek * stop it. 469 1.1 jdolecek */ 470 1.1 jdolecek mb86950_stop(sc); 471 1.1 jdolecek ifp->if_flags &= ~IFF_RUNNING; 472 1.1 jdolecek mb86950_disable(sc); 473 1.12 dyoung break; 474 1.12 dyoung case IFF_UP: 475 1.1 jdolecek /* 476 1.1 jdolecek * If interface is marked up and it is stopped, then 477 1.1 jdolecek * start it. 478 1.1 jdolecek */ 479 1.1 jdolecek if ((error = mb86950_enable(sc)) != 0) 480 1.1 jdolecek break; 481 1.1 jdolecek mb86950_init(sc); 482 1.12 dyoung break; 483 1.12 dyoung case IFF_UP|IFF_RUNNING: 484 1.1 jdolecek /* 485 1.1 jdolecek * Reset the interface to pick up changes in any other 486 1.1 jdolecek * flags that affect hardware registers. 487 1.1 jdolecek */ 488 1.12 dyoung #if 0 489 1.12 dyoung /* Setmode not supported */ 490 1.1 jdolecek mb86950_setmode(sc); 491 1.12 dyoung #endif 492 1.12 dyoung break; 493 1.12 dyoung case 0: 494 1.12 dyoung break; 495 1.1 jdolecek } 496 1.1 jdolecek 497 1.1 jdolecek #if ESTAR_DEBUG >= 1 498 1.1 jdolecek /* "ifconfig fe0 debug" to print register dump. */ 499 1.1 jdolecek if (ifp->if_flags & IFF_DEBUG) { 500 1.1 jdolecek log(LOG_INFO, "%s: SIOCSIFFLAGS(DEBUG)\n", 501 1.20 chs device_xname(sc->sc_dev)); 502 1.1 jdolecek mb86950_dump(LOG_DEBUG, sc); 503 1.1 jdolecek } 504 1.1 jdolecek #endif 505 1.1 jdolecek break; 506 1.1 jdolecek 507 1.1 jdolecek default: 508 1.12 dyoung error = ether_ioctl(ifp, cmd, data); 509 1.1 jdolecek break; 510 1.1 jdolecek } 511 1.1 jdolecek 512 1.1 jdolecek splx(s); 513 1.30 msaitoh return error; 514 1.1 jdolecek } 515 1.1 jdolecek 516 1.1 jdolecek /* 517 1.1 jdolecek * Initialize device. 518 1.1 jdolecek */ 519 1.1 jdolecek void 520 1.14 dsl mb86950_init(struct mb86950_softc *sc) 521 1.1 jdolecek { 522 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst; 523 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh; 524 1.1 jdolecek struct ifnet *ifp = &sc->sc_ec.ec_if; 525 1.1 jdolecek 526 1.1 jdolecek /* Reset transmitter flags. */ 527 1.1 jdolecek ifp->if_flags &= ~IFF_OACTIVE; 528 1.1 jdolecek ifp->if_timer = 0; 529 1.1 jdolecek sc->txb_sched = 0; 530 1.1 jdolecek 531 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_TX_MODE, LBC); 532 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_RX_MODE, NORMAL_MODE); 533 1.1 jdolecek 534 1.1 jdolecek /* Enable interrupts. */ 535 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, TX_MASK); 536 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, RX_MASK); 537 1.1 jdolecek 538 1.1 jdolecek /* Enable transmitter and receiver. */ 539 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_CONFIG, ENABLE_DLC); 540 1.1 jdolecek delay(200); 541 1.1 jdolecek 542 1.1 jdolecek /* Set 'running' flag. */ 543 1.1 jdolecek ifp->if_flags |= IFF_RUNNING; 544 1.1 jdolecek 545 1.1 jdolecek /* ...and attempt to start output. */ 546 1.1 jdolecek mb86950_start(ifp); 547 1.1 jdolecek } 548 1.1 jdolecek 549 1.1 jdolecek void 550 1.14 dsl mb86950_start(struct ifnet *ifp) 551 1.1 jdolecek { 552 1.1 jdolecek struct mb86950_softc *sc = ifp->if_softc; 553 1.30 msaitoh bus_space_tag_t bst = sc->sc_bst; 554 1.30 msaitoh bus_space_handle_t bsh = sc->sc_bsh; 555 1.1 jdolecek struct mbuf *m; 556 1.1 jdolecek int len; 557 1.1 jdolecek 558 1.1 jdolecek if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) 559 1.1 jdolecek return; 560 1.1 jdolecek 561 1.1 jdolecek IF_DEQUEUE(&ifp->if_snd, m); 562 1.1 jdolecek if (m == 0) 563 1.1 jdolecek return; 564 1.1 jdolecek 565 1.1 jdolecek /* Tap off here if there is a BPF listener. */ 566 1.28 msaitoh bpf_mtap(ifp, m, BPF_D_OUT); 567 1.1 jdolecek 568 1.2 jdolecek /* Send the packet to the mb86950 */ 569 1.1 jdolecek len = mb86950_put_fifo(sc,m); 570 1.1 jdolecek m_freem(m); 571 1.1 jdolecek 572 1.2 jdolecek /* XXX bus_space_barrier here ? */ 573 1.30 msaitoh if (bus_space_read_1(bst, bsh, DLCR_TX_STAT) 574 1.30 msaitoh & (TX_UNDERFLO | TX_BUS_WR_ERR)) { 575 1.30 msaitoh log(LOG_ERR, "%s: tx fifo underflow/overflow\n", 576 1.30 msaitoh device_xname(sc->sc_dev)); 577 1.1 jdolecek } 578 1.1 jdolecek 579 1.1 jdolecek bus_space_write_2(bst, bsh, BMPR_TX_LENGTH, len | TRANSMIT_START); 580 1.1 jdolecek 581 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, TX_MASK); 582 1.2 jdolecek /* XXX */ 583 1.1 jdolecek sc->txb_sched++; 584 1.1 jdolecek 585 1.1 jdolecek /* We have space for 'n' transmit packets of size 'mtu. */ 586 1.1 jdolecek if (sc->txb_sched > sc->txb_num_pkt) { 587 1.1 jdolecek ifp->if_flags |= IFF_OACTIVE; 588 1.1 jdolecek ifp->if_timer = 2; 589 1.1 jdolecek } 590 1.1 jdolecek } 591 1.1 jdolecek 592 1.1 jdolecek /* 593 1.2 jdolecek * Send packet - copy packet from mbuf to the fifo 594 1.1 jdolecek */ 595 1.1 jdolecek u_short 596 1.14 dsl mb86950_put_fifo(struct mb86950_softc *sc, struct mbuf *m) 597 1.1 jdolecek { 598 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst; 599 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh; 600 1.1 jdolecek u_short *data; 601 1.1 jdolecek u_char savebyte[2]; 602 1.1 jdolecek int len, len1, wantbyte; 603 1.1 jdolecek u_short totlen; 604 1.1 jdolecek 605 1.5 mrg memset(savebyte, 0, sizeof(savebyte)); /* XXX gcc */ 606 1.5 mrg 607 1.1 jdolecek totlen = wantbyte = 0; 608 1.1 jdolecek 609 1.1 jdolecek for (; m != NULL; m = m->m_next) { 610 1.1 jdolecek data = mtod(m, u_short *); 611 1.1 jdolecek len = m->m_len; 612 1.1 jdolecek if (len > 0) { 613 1.1 jdolecek totlen += len; 614 1.1 jdolecek 615 1.1 jdolecek /* Finish the last word. */ 616 1.1 jdolecek if (wantbyte) { 617 1.1 jdolecek savebyte[1] = *((u_char *)data); 618 1.30 msaitoh bus_space_write_2(bst, bsh, BMPR_FIFO, 619 1.30 msaitoh *savebyte); 620 1.4 skrll data = (u_short *)((u_char *)data + 1); 621 1.1 jdolecek len--; 622 1.1 jdolecek wantbyte = 0; 623 1.1 jdolecek } 624 1.1 jdolecek /* Output contiguous words. */ 625 1.1 jdolecek if (len > 1) { 626 1.1 jdolecek len1 = len/2; 627 1.30 msaitoh bus_space_write_multi_stream_2(bst, bsh, 628 1.30 msaitoh BMPR_FIFO, data, len1); 629 1.1 jdolecek data += len1; 630 1.1 jdolecek len &= 1; 631 1.1 jdolecek } 632 1.1 jdolecek /* Save last byte, if necessary. */ 633 1.1 jdolecek if (len == 1) { 634 1.1 jdolecek savebyte[0] = *((u_char *)data); 635 1.1 jdolecek wantbyte = 1; 636 1.1 jdolecek } 637 1.1 jdolecek } 638 1.1 jdolecek } 639 1.1 jdolecek 640 1.1 jdolecek if (wantbyte) { 641 1.1 jdolecek savebyte[1] = 0; 642 1.1 jdolecek bus_space_write_2(bst, bsh, BMPR_FIFO, *savebyte); 643 1.1 jdolecek } 644 1.1 jdolecek 645 1.1 jdolecek if (totlen < (ETHER_MIN_LEN - ETHER_CRC_LEN)) { 646 1.1 jdolecek 647 1.1 jdolecek /* Fill the rest of the packet with zeros. */ 648 1.2 jdolecek /* XXX Replace this mess with something else, eats CPU */ 649 1.2 jdolecek /* The zero fill and last byte ought to be combined somehow */ 650 1.30 msaitoh for (len = totlen + 1; len < (ETHER_MIN_LEN - ETHER_CRC_LEN); 651 1.30 msaitoh len += 2) 652 1.31 msaitoh bus_space_write_2(bst, bsh, BMPR_FIFO, 0); 653 1.2 jdolecek /* XXX */ 654 1.1 jdolecek 655 1.1 jdolecek totlen = (ETHER_MIN_LEN - ETHER_CRC_LEN); 656 1.1 jdolecek } 657 1.1 jdolecek 658 1.30 msaitoh return totlen; 659 1.1 jdolecek } 660 1.1 jdolecek 661 1.1 jdolecek /* 662 1.2 jdolecek * Handle interrupts. 663 1.1 jdolecek * Ethernet interface interrupt processor 664 1.1 jdolecek */ 665 1.1 jdolecek int 666 1.14 dsl mb86950_intr(void *arg) 667 1.1 jdolecek { 668 1.1 jdolecek struct mb86950_softc *sc = arg; 669 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst; 670 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh; 671 1.1 jdolecek struct ifnet *ifp = &sc->sc_ec.ec_if; 672 1.1 jdolecek u_int8_t tstat, rstat; 673 1.1 jdolecek 674 1.1 jdolecek /* Get interrupt status. */ 675 1.1 jdolecek tstat = bus_space_read_1(bst, bsh, DLCR_TX_STAT); 676 1.1 jdolecek rstat = bus_space_read_1(bst, bsh, DLCR_RX_STAT); 677 1.1 jdolecek 678 1.30 msaitoh if (tstat == 0 && rstat == 0) return 0; 679 1.1 jdolecek 680 1.1 jdolecek /* Disable etherstar interrupts so that we won't miss anything. */ 681 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, 0); 682 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, 0); 683 1.1 jdolecek 684 1.1 jdolecek /* 685 1.1 jdolecek * Handle transmitter interrupts. Handle these first because 686 1.1 jdolecek * the receiver will reset the board under some conditions. 687 1.1 jdolecek */ 688 1.1 jdolecek if (tstat != 0) { 689 1.1 jdolecek 690 1.1 jdolecek mb86950_tint(sc, tstat); 691 1.1 jdolecek 692 1.1 jdolecek /* acknowledge transmit interrupt status. */ 693 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_TX_STAT, tstat); 694 1.1 jdolecek 695 1.1 jdolecek } 696 1.1 jdolecek 697 1.1 jdolecek /* Handle receiver interrupts. */ 698 1.1 jdolecek if (rstat != 0) { 699 1.1 jdolecek 700 1.1 jdolecek mb86950_rint(sc, rstat); 701 1.1 jdolecek 702 1.1 jdolecek /* acknowledge receive interrupt status. */ 703 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_RX_STAT, rstat); 704 1.1 jdolecek 705 1.1 jdolecek } 706 1.1 jdolecek 707 1.1 jdolecek /* If tx still pending reset tx interrupt mask */ 708 1.2 jdolecek if (sc->txb_sched > 0) 709 1.2 jdolecek bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, TX_MASK); 710 1.1 jdolecek 711 1.1 jdolecek /* 712 1.1 jdolecek * If it looks like the transmitter can take more data, 713 1.1 jdolecek * attempt to start output on the interface. This is done 714 1.1 jdolecek * after handling the receiver interrupt to give the 715 1.1 jdolecek * receive operation priority. 716 1.1 jdolecek */ 717 1.1 jdolecek 718 1.1 jdolecek if ((ifp->if_flags & IFF_OACTIVE) == 0) 719 1.26 ozaki if_schedule_deferred_start(ifp); 720 1.1 jdolecek 721 1.1 jdolecek /* Set receive interrupts back */ 722 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, RX_MASK); 723 1.1 jdolecek 724 1.30 msaitoh return 1; 725 1.1 jdolecek } 726 1.1 jdolecek 727 1.1 jdolecek /* Transmission interrupt handler */ 728 1.1 jdolecek void 729 1.14 dsl mb86950_tint(struct mb86950_softc *sc, u_int8_t tstat) 730 1.1 jdolecek { 731 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst; 732 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh; 733 1.1 jdolecek struct ifnet *ifp = &sc->sc_ec.ec_if; 734 1.1 jdolecek int col; 735 1.1 jdolecek 736 1.1 jdolecek if (tstat & (TX_UNDERFLO | TX_BUS_WR_ERR)) { 737 1.1 jdolecek /* XXX What do we need to do here? reset ? */ 738 1.33 thorpej if_statinc(ifp, if_oerrors); 739 1.1 jdolecek } 740 1.1 jdolecek 741 1.30 msaitoh /* Excessive collision */ 742 1.1 jdolecek if (tstat & TX_16COL) { 743 1.33 thorpej if_statadd(ifp, if_collisions, 16); 744 1.1 jdolecek /* 16 collisions means that the packet has been thrown away. */ 745 1.2 jdolecek if (sc->txb_sched > 0) 746 1.2 jdolecek sc->txb_sched--; 747 1.1 jdolecek } 748 1.1 jdolecek 749 1.30 msaitoh /* Transmission complete. */ 750 1.1 jdolecek if (tstat & TX_DONE) { 751 1.30 msaitoh /* Successfully transmitted packets ++. */ 752 1.33 thorpej if_statinc(ifp, if_opackets); 753 1.2 jdolecek if (sc->txb_sched > 0) 754 1.2 jdolecek sc->txb_sched--; 755 1.1 jdolecek 756 1.1 jdolecek /* Collision count valid only when TX_DONE is set */ 757 1.1 jdolecek if (tstat & TX_COL) { 758 1.30 msaitoh col = (bus_space_read_1(bst, bsh, DLCR_TX_MODE) 759 1.30 msaitoh & COL_MASK) >> 4; 760 1.33 thorpej if_statadd(ifp, if_collisions, col); 761 1.1 jdolecek } 762 1.1 jdolecek } 763 1.1 jdolecek 764 1.1 jdolecek if (sc->txb_sched == 0) { 765 1.1 jdolecek /* Reset output active flag and stop timer. */ 766 1.1 jdolecek ifp->if_flags &= ~IFF_OACTIVE; 767 1.1 jdolecek ifp->if_timer = 0; 768 1.1 jdolecek } 769 1.1 jdolecek } 770 1.1 jdolecek 771 1.30 msaitoh /* Receiver interrupt. */ 772 1.1 jdolecek void 773 1.14 dsl mb86950_rint(struct mb86950_softc *sc, u_int8_t rstat) 774 1.1 jdolecek { 775 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst; 776 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh; 777 1.1 jdolecek struct ifnet *ifp = &sc->sc_ec.ec_if; 778 1.1 jdolecek u_int status, len; 779 1.1 jdolecek int i; 780 1.1 jdolecek 781 1.1 jdolecek /* Update statistics if this interrupt is caused by an error. */ 782 1.1 jdolecek if (rstat & RX_ERR_MASK) { 783 1.1 jdolecek 784 1.30 msaitoh /* 785 1.30 msaitoh * Tried to read past end of fifo, should be harmless 786 1.1 jdolecek * count everything else 787 1.1 jdolecek */ 788 1.1 jdolecek if ((rstat & RX_BUS_RD_ERR) == 0) { 789 1.33 thorpej if_statinc(ifp, if_ierrors); 790 1.1 jdolecek } 791 1.1 jdolecek } 792 1.1 jdolecek 793 1.1 jdolecek /* 794 1.1 jdolecek * mb86950 has a flag indicating "receive buffer empty." 795 1.1 jdolecek * We just loop checking the flag to pull out all received 796 1.1 jdolecek * packets. 797 1.1 jdolecek * 798 1.35 andvar * We limit the number of iterations to avoid infinite loop. 799 1.1 jdolecek * It can be caused by a very slow CPU (some broken 800 1.1 jdolecek * peripheral may insert incredible number of wait cycles) 801 1.1 jdolecek * or, worse, by a broken mb86950 chip. 802 1.1 jdolecek */ 803 1.1 jdolecek for (i = 0; i < sc->rxb_num_pkt; i++) { 804 1.35 andvar /* Stop the iteration if 86950 indicates no packets. */ 805 1.1 jdolecek if (bus_space_read_1(bst, bsh, DLCR_RX_MODE) & RX_BUF_EMTY) 806 1.1 jdolecek break; 807 1.1 jdolecek 808 1.30 msaitoh /* Receive packet status */ 809 1.1 jdolecek status = bus_space_read_2(bst, bsh, BMPR_FIFO); 810 1.1 jdolecek 811 1.30 msaitoh /* Bad packet? */ 812 1.1 jdolecek if ((status & GOOD_PKT) == 0) { 813 1.33 thorpej if_statinc(ifp, if_ierrors); 814 1.1 jdolecek mb86950_drain_fifo(sc); 815 1.1 jdolecek continue; 816 1.1 jdolecek } 817 1.1 jdolecek 818 1.1 jdolecek /* Length valid ? */ 819 1.1 jdolecek len = bus_space_read_2(bst, bsh, BMPR_FIFO); 820 1.1 jdolecek 821 1.30 msaitoh if (len > (ETHER_MAX_LEN - ETHER_CRC_LEN) 822 1.30 msaitoh || len < ETHER_HDR_LEN) { 823 1.33 thorpej if_statinc(ifp, if_ierrors); 824 1.1 jdolecek mb86950_drain_fifo(sc); 825 1.1 jdolecek continue; 826 1.1 jdolecek } 827 1.1 jdolecek 828 1.1 jdolecek if (mb86950_get_fifo(sc, len) != 0) { 829 1.1 jdolecek /* No mbufs? Drop packet. */ 830 1.33 thorpej if_statinc(ifp, if_ierrors); 831 1.1 jdolecek mb86950_drain_fifo(sc); 832 1.1 jdolecek return; 833 1.1 jdolecek } 834 1.1 jdolecek } 835 1.1 jdolecek } 836 1.1 jdolecek 837 1.1 jdolecek /* 838 1.2 jdolecek * Receive packet. 839 1.1 jdolecek * Retrieve packet from receive buffer and send to the next level up via 840 1.25 ozaki * ether_input(). 841 1.1 jdolecek * Returns 0 if success, -1 if error (i.e., mbuf allocation failure). 842 1.1 jdolecek */ 843 1.1 jdolecek int 844 1.14 dsl mb86950_get_fifo(struct mb86950_softc *sc, u_int len) 845 1.1 jdolecek { 846 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst; 847 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh; 848 1.1 jdolecek struct ifnet *ifp = &sc->sc_ec.ec_if; 849 1.1 jdolecek struct mbuf *m; 850 1.1 jdolecek 851 1.1 jdolecek /* Allocate a header mbuf. */ 852 1.1 jdolecek MGETHDR(m, M_DONTWAIT, MT_DATA); 853 1.1 jdolecek if (m == 0) 854 1.30 msaitoh return -1; 855 1.1 jdolecek 856 1.30 msaitoh /* Round len to even value. */ 857 1.1 jdolecek if (len & 1) 858 1.1 jdolecek len++; 859 1.1 jdolecek 860 1.24 ozaki m_set_rcvif(m, ifp); 861 1.1 jdolecek m->m_pkthdr.len = len; 862 1.1 jdolecek 863 1.1 jdolecek /* The following silliness is to make NFS happy. */ 864 1.1 jdolecek #define EROUND ((sizeof(struct ether_header) + 3) & ~3) 865 1.1 jdolecek #define EOFF (EROUND - sizeof(struct ether_header)) 866 1.1 jdolecek 867 1.1 jdolecek /* 868 1.1 jdolecek * Our strategy has one more problem. There is a policy on 869 1.1 jdolecek * mbuf cluster allocation. It says that we must have at 870 1.1 jdolecek * least MINCLSIZE (208 bytes) to allocate a cluster. For a 871 1.1 jdolecek * packet of a size between (MHLEN - 2) to (MINCLSIZE - 2), 872 1.1 jdolecek * our code violates the rule... 873 1.1 jdolecek * On the other hand, the current code is short, simple, 874 1.1 jdolecek * and fast, however. It does no harmful thing, just wastes 875 1.1 jdolecek * some memory. Any comments? FIXME. 876 1.1 jdolecek */ 877 1.1 jdolecek 878 1.1 jdolecek /* Attach a cluster if this packet doesn't fit in a normal mbuf. */ 879 1.1 jdolecek if (len > MHLEN - EOFF) { 880 1.1 jdolecek MCLGET(m, M_DONTWAIT); 881 1.1 jdolecek if ((m->m_flags & M_EXT) == 0) { 882 1.1 jdolecek m_freem(m); 883 1.30 msaitoh return -1; 884 1.1 jdolecek } 885 1.1 jdolecek } 886 1.1 jdolecek 887 1.1 jdolecek /* 888 1.1 jdolecek * The following assumes there is room for the ether header in the 889 1.1 jdolecek * header mbuf. 890 1.1 jdolecek */ 891 1.1 jdolecek m->m_data += EOFF; 892 1.1 jdolecek 893 1.1 jdolecek /* Set the length of this packet. */ 894 1.1 jdolecek m->m_len = len; 895 1.1 jdolecek 896 1.1 jdolecek /* Get a packet. */ 897 1.30 msaitoh bus_space_read_multi_stream_2(bst, bsh, BMPR_FIFO, 898 1.30 msaitoh mtod(m, u_int16_t *), (len + 1) >> 1); 899 1.1 jdolecek 900 1.23 ozaki if_percpuq_enqueue(ifp->if_percpuq, m); 901 1.30 msaitoh return 0; 902 1.1 jdolecek } 903 1.1 jdolecek 904 1.1 jdolecek /* 905 1.1 jdolecek * Enable power on the interface. 906 1.1 jdolecek */ 907 1.1 jdolecek int 908 1.14 dsl mb86950_enable(struct mb86950_softc *sc) 909 1.1 jdolecek { 910 1.1 jdolecek 911 1.1 jdolecek if ((sc->sc_stat & ESTAR_STAT_ENABLED) == 0 && sc->sc_enable != NULL) { 912 1.1 jdolecek if ((*sc->sc_enable)(sc) != 0) { 913 1.20 chs aprint_error_dev(sc->sc_dev, "device enable failed\n"); 914 1.30 msaitoh return EIO; 915 1.1 jdolecek } 916 1.1 jdolecek } 917 1.1 jdolecek 918 1.1 jdolecek sc->sc_stat |= ESTAR_STAT_ENABLED; 919 1.30 msaitoh return 0; 920 1.1 jdolecek } 921 1.1 jdolecek 922 1.1 jdolecek /* 923 1.1 jdolecek * Disable power on the interface. 924 1.1 jdolecek */ 925 1.1 jdolecek void 926 1.14 dsl mb86950_disable(struct mb86950_softc *sc) 927 1.1 jdolecek { 928 1.1 jdolecek 929 1.1 jdolecek if ((sc->sc_stat & ESTAR_STAT_ENABLED) != 0 && sc->sc_disable != NULL) { 930 1.1 jdolecek (*sc->sc_disable)(sc); 931 1.1 jdolecek sc->sc_stat &= ~ESTAR_STAT_ENABLED; 932 1.1 jdolecek } 933 1.1 jdolecek } 934 1.1 jdolecek 935 1.1 jdolecek /* 936 1.1 jdolecek * mbe_activate: 937 1.1 jdolecek * 938 1.1 jdolecek * Handle device activation/deactivation requests. 939 1.1 jdolecek */ 940 1.1 jdolecek int 941 1.15 cegger mb86950_activate(device_t self, enum devact act) 942 1.1 jdolecek { 943 1.16 dyoung struct mb86950_softc *sc = device_private(self); 944 1.1 jdolecek 945 1.1 jdolecek switch (act) { 946 1.1 jdolecek case DVACT_DEACTIVATE: 947 1.1 jdolecek if_deactivate(&sc->sc_ec.ec_if); 948 1.16 dyoung return 0; 949 1.16 dyoung default: 950 1.16 dyoung return EOPNOTSUPP; 951 1.1 jdolecek } 952 1.1 jdolecek } 953 1.1 jdolecek 954 1.1 jdolecek /* 955 1.1 jdolecek * mb86950_detach: 956 1.1 jdolecek * 957 1.1 jdolecek * Detach a mb86950 interface. 958 1.1 jdolecek */ 959 1.1 jdolecek int 960 1.14 dsl mb86950_detach(struct mb86950_softc *sc) 961 1.1 jdolecek { 962 1.1 jdolecek struct ifnet *ifp = &sc->sc_ec.ec_if; 963 1.1 jdolecek 964 1.1 jdolecek /* Succeed now if there's no work to do. */ 965 1.1 jdolecek if ((sc->sc_stat & ESTAR_STAT_ATTACHED) == 0) 966 1.30 msaitoh return 0; 967 1.1 jdolecek 968 1.1 jdolecek /* Unhook the entropy source. */ 969 1.1 jdolecek rnd_detach_source(&sc->rnd_source); 970 1.19 tls 971 1.1 jdolecek ether_ifdetach(ifp); 972 1.1 jdolecek if_detach(ifp); 973 1.1 jdolecek 974 1.34 thorpej /* Delete all media. */ 975 1.34 thorpej ifmedia_fini(&sc->sc_media); 976 1.34 thorpej 977 1.30 msaitoh return 0; 978 1.1 jdolecek } 979 1.1 jdolecek 980 1.1 jdolecek #if ESTAR_DEBUG >= 1 981 1.1 jdolecek void 982 1.14 dsl mb86950_dump(int level, struct mb86950_softc *sc) 983 1.1 jdolecek { 984 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst; 985 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh; 986 1.1 jdolecek 987 1.1 jdolecek log(level, "\tDLCR = %02x %02x %02x %02x %02x %02x %02x\n", 988 1.1 jdolecek bus_space_read_1(bst, bsh, DLCR_TX_STAT), 989 1.1 jdolecek bus_space_read_1(bst, bsh, DLCR_TX_INT_EN), 990 1.1 jdolecek bus_space_read_1(bst, bsh, DLCR_RX_STAT), 991 1.1 jdolecek bus_space_read_1(bst, bsh, DLCR_RX_INT_EN), 992 1.1 jdolecek bus_space_read_1(bst, bsh, DLCR_TX_MODE), 993 1.1 jdolecek bus_space_read_1(bst, bsh, DLCR_RX_MODE), 994 1.1 jdolecek bus_space_read_1(bst, bsh, DLCR_CONFIG)); 995 1.1 jdolecek 996 1.2 jdolecek /* XXX BMPR2, 4 write only ? 997 1.1 jdolecek log(level, "\tBMPR = xxxx %04x %04x\n", 998 1.1 jdolecek bus_space_read_2(bst, bsh, BMPR_TX_LENGTH), 999 1.1 jdolecek bus_space_read_2(bst, bsh, BMPR_DMA)); 1000 1.2 jdolecek */ 1001 1.1 jdolecek } 1002 1.1 jdolecek #endif 1003