1 1.17 tsutsui /* $NetBSD: we.c,v 1.17 2010/03/19 15:59:22 tsutsui Exp $ */ 2 1.1 jdolecek 3 1.1 jdolecek /*- 4 1.1 jdolecek * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 5 1.1 jdolecek * All rights reserved. 6 1.1 jdolecek * 7 1.1 jdolecek * This code is derived from software contributed to The NetBSD Foundation 8 1.1 jdolecek * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 1.1 jdolecek * NASA Ames Research Center. 10 1.1 jdolecek * 11 1.1 jdolecek * Redistribution and use in source and binary forms, with or without 12 1.1 jdolecek * modification, are permitted provided that the following conditions 13 1.1 jdolecek * are met: 14 1.1 jdolecek * 1. Redistributions of source code must retain the above copyright 15 1.1 jdolecek * notice, this list of conditions and the following disclaimer. 16 1.1 jdolecek * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 jdolecek * notice, this list of conditions and the following disclaimer in the 18 1.1 jdolecek * documentation and/or other materials provided with the distribution. 19 1.1 jdolecek * 20 1.1 jdolecek * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.1 jdolecek * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.1 jdolecek * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.1 jdolecek * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.1 jdolecek * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.1 jdolecek * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.1 jdolecek * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.1 jdolecek * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.1 jdolecek * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.1 jdolecek * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.1 jdolecek * POSSIBILITY OF SUCH DAMAGE. 31 1.1 jdolecek */ 32 1.1 jdolecek 33 1.1 jdolecek /* 34 1.1 jdolecek * Device driver for National Semiconductor DS8390/WD83C690 based ethernet 35 1.1 jdolecek * adapters. 36 1.1 jdolecek * 37 1.1 jdolecek * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. 38 1.1 jdolecek * 39 1.1 jdolecek * Copyright (C) 1993, David Greenman. This software may be used, modified, 40 1.1 jdolecek * copied, distributed, and sold, in both source and binary form provided that 41 1.1 jdolecek * the above copyright and these terms are retained. Under no circumstances is 42 1.1 jdolecek * the author responsible for the proper functioning of this software, nor does 43 1.1 jdolecek * the author assume any responsibility for damages incurred with its use. 44 1.1 jdolecek */ 45 1.1 jdolecek 46 1.1 jdolecek /* 47 1.1 jdolecek * Device driver for the Western Digital/SMC 8003 and 8013 series, 48 1.1 jdolecek * and the SMC Elite Ultra (8216). 49 1.1 jdolecek */ 50 1.4 lukem 51 1.4 lukem #include <sys/cdefs.h> 52 1.17 tsutsui __KERNEL_RCSID(0, "$NetBSD: we.c,v 1.17 2010/03/19 15:59:22 tsutsui Exp $"); 53 1.1 jdolecek 54 1.1 jdolecek #include <sys/param.h> 55 1.1 jdolecek #include <sys/systm.h> 56 1.1 jdolecek #include <sys/device.h> 57 1.1 jdolecek #include <sys/socket.h> 58 1.1 jdolecek #include <sys/mbuf.h> 59 1.1 jdolecek #include <sys/syslog.h> 60 1.1 jdolecek 61 1.1 jdolecek #include <net/if.h> 62 1.1 jdolecek #include <net/if_dl.h> 63 1.1 jdolecek #include <net/if_types.h> 64 1.1 jdolecek #include <net/if_media.h> 65 1.1 jdolecek 66 1.1 jdolecek #include <net/if_ether.h> 67 1.1 jdolecek 68 1.13 ad #include <sys/bus.h> 69 1.10 dsl #include <sys/bswap.h> 70 1.13 ad #include <sys/intr.h> 71 1.1 jdolecek 72 1.1 jdolecek #include <dev/isa/isareg.h> 73 1.1 jdolecek #include <dev/isa/isavar.h> 74 1.1 jdolecek 75 1.1 jdolecek #include <dev/ic/dp8390reg.h> 76 1.1 jdolecek #include <dev/ic/dp8390var.h> 77 1.1 jdolecek #include <dev/ic/wereg.h> 78 1.1 jdolecek #include <dev/ic/wevar.h> 79 1.1 jdolecek 80 1.1 jdolecek #ifndef __BUS_SPACE_HAS_STREAM_METHODS 81 1.1 jdolecek #define bus_space_read_region_stream_2 bus_space_read_region_2 82 1.1 jdolecek #define bus_space_write_stream_2 bus_space_write_2 83 1.1 jdolecek #define bus_space_write_region_stream_2 bus_space_write_region_2 84 1.1 jdolecek #endif 85 1.1 jdolecek 86 1.6 perry static void we_set_media(struct we_softc *, int); 87 1.1 jdolecek 88 1.6 perry static void we_media_init(struct dp8390_softc *); 89 1.1 jdolecek 90 1.6 perry static int we_mediachange(struct dp8390_softc *); 91 1.6 perry static void we_mediastatus(struct dp8390_softc *, struct ifmediareq *); 92 1.1 jdolecek 93 1.6 perry static void we_recv_int(struct dp8390_softc *); 94 1.6 perry static void we_init_card(struct dp8390_softc *); 95 1.6 perry static int we_write_mbuf(struct dp8390_softc *, struct mbuf *, int); 96 1.12 christos static int we_ring_copy(struct dp8390_softc *, int, void *, u_short); 97 1.6 perry static void we_read_hdr(struct dp8390_softc *, int, struct dp8390_ring *); 98 1.6 perry static int we_test_mem(struct dp8390_softc *); 99 1.1 jdolecek 100 1.16 tsutsui static inline void we_readmem(struct we_softc *, int, uint8_t *, int); 101 1.1 jdolecek 102 1.1 jdolecek /* 103 1.1 jdolecek * Delay needed when switching 16-bit access to shared memory. 104 1.1 jdolecek */ 105 1.1 jdolecek #define WE_DELAY(wsc) delay(3) 106 1.1 jdolecek 107 1.1 jdolecek /* 108 1.1 jdolecek * Enable card RAM, and 16-bit access. 109 1.1 jdolecek */ 110 1.1 jdolecek #define WE_MEM_ENABLE(wsc) \ 111 1.7 jdolecek if (((wsc)->sc_flags & WE_16BIT_NOTOGGLE) == 0) { \ 112 1.7 jdolecek if ((wsc)->sc_flags & WE_16BIT_ENABLE) \ 113 1.7 jdolecek bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \ 114 1.7 jdolecek WE_LAAR, (wsc)->sc_laar_proto | WE_LAAR_M16EN); \ 115 1.7 jdolecek bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \ 116 1.7 jdolecek WE_MSR, wsc->sc_msr_proto | WE_MSR_MENB); \ 117 1.7 jdolecek WE_DELAY((wsc)); \ 118 1.7 jdolecek } 119 1.1 jdolecek 120 1.1 jdolecek /* 121 1.1 jdolecek * Disable card RAM, and 16-bit access. 122 1.1 jdolecek */ 123 1.1 jdolecek #define WE_MEM_DISABLE(wsc) \ 124 1.7 jdolecek if (((wsc)->sc_flags & WE_16BIT_NOTOGGLE) == 0) { \ 125 1.7 jdolecek bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \ 126 1.7 jdolecek WE_MSR, (wsc)->sc_msr_proto); \ 127 1.7 jdolecek if ((wsc)->sc_flags & WE_16BIT_ENABLE) \ 128 1.7 jdolecek bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \ 129 1.7 jdolecek WE_LAAR, (wsc)->sc_laar_proto); \ 130 1.7 jdolecek WE_DELAY((wsc)); \ 131 1.7 jdolecek } 132 1.1 jdolecek 133 1.1 jdolecek int 134 1.14 cube we_config(device_t self, struct we_softc *wsc, const char *typestr) 135 1.1 jdolecek { 136 1.1 jdolecek struct dp8390_softc *sc = &wsc->sc_dp8390; 137 1.16 tsutsui uint8_t x; 138 1.1 jdolecek int i, forced_16bit = 0; 139 1.1 jdolecek 140 1.1 jdolecek /* 141 1.1 jdolecek * Allow user to override 16-bit mode. 8-bit takes precedence. 142 1.1 jdolecek */ 143 1.11 thorpej if (device_cfdata(self)->cf_flags & DP8390_FORCE_16BIT_MODE) { 144 1.7 jdolecek wsc->sc_flags |= WE_16BIT_ENABLE; 145 1.1 jdolecek forced_16bit = 1; 146 1.1 jdolecek } 147 1.11 thorpej if (device_cfdata(self)->cf_flags & DP8390_FORCE_8BIT_MODE) 148 1.7 jdolecek wsc->sc_flags &= ~WE_16BIT_ENABLE; 149 1.1 jdolecek 150 1.1 jdolecek /* Registers are linear. */ 151 1.1 jdolecek for (i = 0; i < 16; i++) 152 1.1 jdolecek sc->sc_reg_map[i] = i; 153 1.1 jdolecek 154 1.1 jdolecek /* Now we can use the NIC_{GET,PUT}() macros. */ 155 1.1 jdolecek 156 1.14 cube aprint_normal_dev(self, "%s Ethernet (%s-bit)\n", 157 1.7 jdolecek typestr, wsc->sc_flags & WE_16BIT_ENABLE ? "16" : "8"); 158 1.1 jdolecek 159 1.1 jdolecek /* Get station address from EEPROM. */ 160 1.1 jdolecek for (i = 0; i < ETHER_ADDR_LEN; i++) 161 1.16 tsutsui sc->sc_enaddr[i] = 162 1.16 tsutsui bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE_PROM + i); 163 1.1 jdolecek 164 1.1 jdolecek /* 165 1.1 jdolecek * Set upper address bits and 8/16 bit access to shared memory. 166 1.1 jdolecek */ 167 1.1 jdolecek if (sc->is790) { 168 1.1 jdolecek wsc->sc_laar_proto = 169 1.1 jdolecek bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE_LAAR) & 170 1.1 jdolecek ~WE_LAAR_M16EN; 171 1.1 jdolecek bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE_LAAR, 172 1.16 tsutsui wsc->sc_laar_proto | 173 1.16 tsutsui (wsc->sc_flags & WE_16BIT_ENABLE ? WE_LAAR_M16EN : 0)); 174 1.1 jdolecek } else if ((wsc->sc_type & WE_SOFTCONFIG) || 175 1.1 jdolecek #ifdef TOSH_ETHER 176 1.1 jdolecek (wsc->sc_type == WE_TYPE_TOSHIBA1) || 177 1.1 jdolecek (wsc->sc_type == WE_TYPE_TOSHIBA4) || 178 1.1 jdolecek #endif 179 1.1 jdolecek (forced_16bit) || 180 1.1 jdolecek (wsc->sc_type == WE_TYPE_WD8013EBT)) { 181 1.1 jdolecek wsc->sc_laar_proto = (wsc->sc_maddr >> 19) & WE_LAAR_ADDRHI; 182 1.7 jdolecek if (wsc->sc_flags & WE_16BIT_ENABLE) 183 1.1 jdolecek wsc->sc_laar_proto |= WE_LAAR_L16EN; 184 1.1 jdolecek bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE_LAAR, 185 1.16 tsutsui wsc->sc_laar_proto | 186 1.16 tsutsui (wsc->sc_flags & WE_16BIT_ENABLE ? WE_LAAR_M16EN : 0)); 187 1.1 jdolecek } 188 1.1 jdolecek 189 1.1 jdolecek /* 190 1.1 jdolecek * Set address and enable interface shared memory. 191 1.1 jdolecek */ 192 1.1 jdolecek if (sc->is790) { 193 1.17 tsutsui x = bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE790_HWR); 194 1.17 tsutsui bus_space_write_1(wsc->sc_asict, wsc->sc_asich, 195 1.17 tsutsui WE790_HWR, x | WE790_HWR_SWH); 196 1.17 tsutsui bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE790_RAR, 197 1.17 tsutsui ((wsc->sc_maddr >> WE790_RAR_OFF_SHIFT) & WE790_RAR_OFF) | 198 1.17 tsutsui ((wsc->sc_maddr & (1 << WE790_RAR_BASE_SHIFT)) != 0 ? 199 1.17 tsutsui WE790_RAR_BASE1 : WE790_RAR_BASE0) | 200 1.17 tsutsui (bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE790_RAR) & 201 1.17 tsutsui ~(WE790_RAR_OFF | WE790_RAR_BASE))); 202 1.17 tsutsui bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE790_HWR, x); 203 1.1 jdolecek wsc->sc_msr_proto = 0x00; 204 1.1 jdolecek sc->cr_proto = 0x00; 205 1.1 jdolecek } else { 206 1.1 jdolecek #ifdef TOSH_ETHER 207 1.1 jdolecek if (wsc->sc_type == WE_TYPE_TOSHIBA1 || 208 1.1 jdolecek wsc->sc_type == WE_TYPE_TOSHIBA4) { 209 1.17 tsutsui /* XXX MAGIC CONSTANTS XXX */ 210 1.1 jdolecek bus_space_write_1(wsc->sc_asict, wsc->sc_asich, 211 1.1 jdolecek WE_MSR + 1, 212 1.1 jdolecek ((wsc->sc_maddr >> 8) & 0xe0) | 0x04); 213 1.1 jdolecek bus_space_write_1(wsc->sc_asict, wsc->sc_asich, 214 1.1 jdolecek WE_MSR + 2, 215 1.1 jdolecek ((wsc->sc_maddr >> 16) & 0x0f)); 216 1.1 jdolecek wsc->sc_msr_proto = WE_MSR_POW; 217 1.1 jdolecek } else 218 1.1 jdolecek #endif 219 1.1 jdolecek wsc->sc_msr_proto = (wsc->sc_maddr >> 13) & 220 1.1 jdolecek WE_MSR_ADDR; 221 1.1 jdolecek 222 1.1 jdolecek sc->cr_proto = ED_CR_RD2; 223 1.1 jdolecek } 224 1.1 jdolecek 225 1.1 jdolecek bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE_MSR, 226 1.1 jdolecek wsc->sc_msr_proto | WE_MSR_MENB); 227 1.1 jdolecek WE_DELAY(wsc); 228 1.1 jdolecek 229 1.1 jdolecek /* 230 1.1 jdolecek * DCR gets: 231 1.1 jdolecek * 232 1.1 jdolecek * FIFO threshold to 8, No auto-init Remote DMA, 233 1.1 jdolecek * byte order=80x86. 234 1.1 jdolecek * 235 1.1 jdolecek * 16-bit cards also get word-wide DMA transfers. 236 1.1 jdolecek */ 237 1.1 jdolecek sc->dcr_reg = ED_DCR_FT1 | ED_DCR_LS | 238 1.7 jdolecek (wsc->sc_flags & WE_16BIT_ENABLE ? ED_DCR_WTS : 0); 239 1.1 jdolecek 240 1.1 jdolecek sc->test_mem = we_test_mem; 241 1.1 jdolecek sc->ring_copy = we_ring_copy; 242 1.1 jdolecek sc->write_mbuf = we_write_mbuf; 243 1.1 jdolecek sc->read_hdr = we_read_hdr; 244 1.1 jdolecek sc->recv_int = we_recv_int; 245 1.1 jdolecek sc->init_card = we_init_card; 246 1.1 jdolecek 247 1.1 jdolecek sc->sc_mediachange = we_mediachange; 248 1.1 jdolecek sc->sc_mediastatus = we_mediastatus; 249 1.1 jdolecek 250 1.1 jdolecek sc->mem_start = 0; 251 1.1 jdolecek /* sc->mem_size has to be set by frontend */ 252 1.1 jdolecek 253 1.11 thorpej sc->sc_flags = device_cfdata(self)->cf_flags; 254 1.1 jdolecek 255 1.1 jdolecek /* Do generic parts of attach. */ 256 1.1 jdolecek if (wsc->sc_type & WE_SOFTCONFIG) 257 1.1 jdolecek sc->sc_media_init = we_media_init; 258 1.1 jdolecek else 259 1.1 jdolecek sc->sc_media_init = dp8390_media_init; 260 1.1 jdolecek if (dp8390_config(sc)) { 261 1.14 cube aprint_error_dev(self, "configuration failed\n"); 262 1.16 tsutsui return 1; 263 1.1 jdolecek } 264 1.1 jdolecek 265 1.1 jdolecek /* 266 1.1 jdolecek * Disable 16-bit access to shared memory - we leave it disabled 267 1.1 jdolecek * so that: 268 1.1 jdolecek * 269 1.1 jdolecek * (1) machines reboot properly when the board is set to 270 1.1 jdolecek * 16-bit mode and there are conflicting 8-bit devices 271 1.1 jdolecek * within the same 128k address space as this board's 272 1.1 jdolecek * shared memory, and 273 1.1 jdolecek * 274 1.1 jdolecek * (2) so that other 8-bit devices with shared memory 275 1.1 jdolecek * in this same 128k address space will work. 276 1.1 jdolecek */ 277 1.1 jdolecek WE_MEM_DISABLE(wsc); 278 1.1 jdolecek 279 1.16 tsutsui return 0; 280 1.1 jdolecek } 281 1.1 jdolecek 282 1.1 jdolecek static int 283 1.14 cube we_test_mem(struct dp8390_softc *sc) 284 1.1 jdolecek { 285 1.1 jdolecek struct we_softc *wsc = (struct we_softc *)sc; 286 1.1 jdolecek bus_space_tag_t memt = sc->sc_buft; 287 1.1 jdolecek bus_space_handle_t memh = sc->sc_bufh; 288 1.1 jdolecek bus_size_t memsize = sc->mem_size; 289 1.1 jdolecek int i; 290 1.1 jdolecek 291 1.7 jdolecek if (wsc->sc_flags & WE_16BIT_ENABLE) 292 1.1 jdolecek bus_space_set_region_2(memt, memh, 0, 0, memsize >> 1); 293 1.1 jdolecek else 294 1.1 jdolecek bus_space_set_region_1(memt, memh, 0, 0, memsize); 295 1.1 jdolecek 296 1.7 jdolecek if (wsc->sc_flags & WE_16BIT_ENABLE) { 297 1.1 jdolecek for (i = 0; i < memsize; i += 2) { 298 1.1 jdolecek if (bus_space_read_2(memt, memh, i) != 0) 299 1.1 jdolecek goto fail; 300 1.1 jdolecek } 301 1.1 jdolecek } else { 302 1.1 jdolecek for (i = 0; i < memsize; i++) { 303 1.1 jdolecek if (bus_space_read_1(memt, memh, i) != 0) 304 1.1 jdolecek goto fail; 305 1.1 jdolecek } 306 1.1 jdolecek } 307 1.1 jdolecek 308 1.16 tsutsui return 0; 309 1.1 jdolecek 310 1.1 jdolecek fail: 311 1.14 cube aprint_error_dev(sc->sc_dev, 312 1.14 cube "failed to clear shared memory at offset 0x%x\n", i); 313 1.1 jdolecek WE_MEM_DISABLE(wsc); 314 1.16 tsutsui return 1; 315 1.1 jdolecek } 316 1.1 jdolecek 317 1.1 jdolecek /* 318 1.1 jdolecek * Given a NIC memory source address and a host memory destination address, 319 1.1 jdolecek * copy 'len' from NIC to host using shared memory. The 'len' is rounded 320 1.1 jdolecek * up to a word - ok as long as mbufs are word-sized. 321 1.1 jdolecek */ 322 1.9 perry static inline void 323 1.16 tsutsui we_readmem(struct we_softc *wsc, int from, uint8_t *to, int len) 324 1.1 jdolecek { 325 1.1 jdolecek bus_space_tag_t memt = wsc->sc_dp8390.sc_buft; 326 1.1 jdolecek bus_space_handle_t memh = wsc->sc_dp8390.sc_bufh; 327 1.1 jdolecek 328 1.1 jdolecek if (len & 1) 329 1.1 jdolecek ++len; 330 1.1 jdolecek 331 1.7 jdolecek if (wsc->sc_flags & WE_16BIT_ENABLE) 332 1.1 jdolecek bus_space_read_region_stream_2(memt, memh, from, 333 1.16 tsutsui (uint16_t *)to, len >> 1); 334 1.1 jdolecek else 335 1.1 jdolecek bus_space_read_region_1(memt, memh, from, 336 1.1 jdolecek to, len); 337 1.1 jdolecek } 338 1.1 jdolecek 339 1.1 jdolecek static int 340 1.14 cube we_write_mbuf(struct dp8390_softc *sc, struct mbuf *m, int buf) 341 1.1 jdolecek { 342 1.1 jdolecek struct we_softc *wsc = (struct we_softc *)sc; 343 1.1 jdolecek bus_space_tag_t memt = wsc->sc_dp8390.sc_buft; 344 1.1 jdolecek bus_space_handle_t memh = wsc->sc_dp8390.sc_bufh; 345 1.16 tsutsui uint8_t *data, savebyte[2]; 346 1.1 jdolecek int savelen, len, leftover; 347 1.1 jdolecek #ifdef DIAGNOSTIC 348 1.16 tsutsui uint8_t *lim; 349 1.1 jdolecek #endif 350 1.1 jdolecek 351 1.1 jdolecek savelen = m->m_pkthdr.len; 352 1.1 jdolecek 353 1.1 jdolecek WE_MEM_ENABLE(wsc); 354 1.1 jdolecek 355 1.1 jdolecek /* 356 1.1 jdolecek * 8-bit boards are simple; no alignment tricks are necessary. 357 1.1 jdolecek */ 358 1.7 jdolecek if ((wsc->sc_flags & WE_16BIT_ENABLE) == 0) { 359 1.1 jdolecek for (; m != NULL; buf += m->m_len, m = m->m_next) 360 1.1 jdolecek bus_space_write_region_1(memt, memh, 361 1.16 tsutsui buf, mtod(m, uint8_t *), m->m_len); 362 1.5 bouyer if (savelen < ETHER_MIN_LEN - ETHER_CRC_LEN) { 363 1.5 bouyer bus_space_set_region_1(memt, memh, 364 1.5 bouyer buf, 0, ETHER_MIN_LEN - ETHER_CRC_LEN - savelen); 365 1.5 bouyer savelen = ETHER_MIN_LEN - ETHER_CRC_LEN; 366 1.5 bouyer } 367 1.1 jdolecek goto out; 368 1.1 jdolecek } 369 1.1 jdolecek 370 1.1 jdolecek /* Start out with no leftover data. */ 371 1.1 jdolecek leftover = 0; 372 1.1 jdolecek savebyte[0] = savebyte[1] = 0; 373 1.1 jdolecek 374 1.1 jdolecek for (; m != NULL; m = m->m_next) { 375 1.1 jdolecek len = m->m_len; 376 1.1 jdolecek if (len == 0) 377 1.1 jdolecek continue; 378 1.16 tsutsui data = mtod(m, uint8_t *); 379 1.1 jdolecek #ifdef DIAGNOSTIC 380 1.1 jdolecek lim = data + len; 381 1.1 jdolecek #endif 382 1.1 jdolecek while (len > 0) { 383 1.1 jdolecek if (leftover) { 384 1.1 jdolecek /* 385 1.1 jdolecek * Data left over (from mbuf or realignment). 386 1.1 jdolecek * Buffer the next byte, and write it and 387 1.1 jdolecek * the leftover data out. 388 1.1 jdolecek */ 389 1.1 jdolecek savebyte[1] = *data++; 390 1.1 jdolecek len--; 391 1.1 jdolecek bus_space_write_stream_2(memt, memh, buf, 392 1.16 tsutsui *(uint16_t *)savebyte); 393 1.1 jdolecek buf += 2; 394 1.1 jdolecek leftover = 0; 395 1.16 tsutsui } else if (BUS_SPACE_ALIGNED_POINTER(data, uint16_t) 396 1.16 tsutsui == 0) { 397 1.1 jdolecek /* 398 1.1 jdolecek * Unaligned dta; buffer the next byte. 399 1.1 jdolecek */ 400 1.1 jdolecek savebyte[0] = *data++; 401 1.1 jdolecek len--; 402 1.1 jdolecek leftover = 1; 403 1.1 jdolecek } else { 404 1.1 jdolecek /* 405 1.1 jdolecek * Aligned data; output contiguous words as 406 1.1 jdolecek * much as we can, then buffer the remaining 407 1.1 jdolecek * byte, if any. 408 1.1 jdolecek */ 409 1.1 jdolecek leftover = len & 1; 410 1.1 jdolecek len &= ~1; 411 1.1 jdolecek bus_space_write_region_stream_2(memt, memh, 412 1.16 tsutsui buf, (uint16_t *)data, len >> 1); 413 1.1 jdolecek data += len; 414 1.1 jdolecek buf += len; 415 1.1 jdolecek if (leftover) 416 1.1 jdolecek savebyte[0] = *data++; 417 1.1 jdolecek len = 0; 418 1.1 jdolecek } 419 1.1 jdolecek } 420 1.1 jdolecek if (len < 0) 421 1.1 jdolecek panic("we_write_mbuf: negative len"); 422 1.1 jdolecek #ifdef DIAGNOSTIC 423 1.1 jdolecek if (data != lim) 424 1.1 jdolecek panic("we_write_mbuf: data != lim"); 425 1.1 jdolecek #endif 426 1.1 jdolecek } 427 1.1 jdolecek if (leftover) { 428 1.1 jdolecek savebyte[1] = 0; 429 1.1 jdolecek bus_space_write_stream_2(memt, memh, buf, 430 1.16 tsutsui *(uint16_t *)savebyte); 431 1.5 bouyer buf += 2; 432 1.5 bouyer } 433 1.5 bouyer if (savelen < ETHER_MIN_LEN - ETHER_CRC_LEN) { 434 1.5 bouyer bus_space_set_region_2(memt, memh, 435 1.5 bouyer buf, 0, (ETHER_MIN_LEN - ETHER_CRC_LEN - savelen) >> 1); 436 1.5 bouyer savelen = ETHER_MIN_LEN - ETHER_CRC_LEN; 437 1.1 jdolecek } 438 1.1 jdolecek 439 1.1 jdolecek out: 440 1.1 jdolecek WE_MEM_DISABLE(wsc); 441 1.1 jdolecek 442 1.16 tsutsui return savelen; 443 1.1 jdolecek } 444 1.1 jdolecek 445 1.1 jdolecek static int 446 1.14 cube we_ring_copy(struct dp8390_softc *sc, int src, void *dstv, u_short amount) 447 1.1 jdolecek { 448 1.16 tsutsui uint8_t *dst = dstv; 449 1.1 jdolecek struct we_softc *wsc = (struct we_softc *)sc; 450 1.1 jdolecek u_short tmp_amount; 451 1.1 jdolecek 452 1.1 jdolecek /* Does copy wrap to lower addr in ring buffer? */ 453 1.1 jdolecek if (src + amount > sc->mem_end) { 454 1.1 jdolecek tmp_amount = sc->mem_end - src; 455 1.1 jdolecek 456 1.1 jdolecek /* Copy amount up to end of NIC memory. */ 457 1.1 jdolecek we_readmem(wsc, src, dst, tmp_amount); 458 1.1 jdolecek 459 1.1 jdolecek amount -= tmp_amount; 460 1.1 jdolecek src = sc->mem_ring; 461 1.1 jdolecek dst += tmp_amount; 462 1.1 jdolecek } 463 1.1 jdolecek 464 1.1 jdolecek we_readmem(wsc, src, dst, amount); 465 1.1 jdolecek 466 1.16 tsutsui return src + amount; 467 1.1 jdolecek } 468 1.1 jdolecek 469 1.1 jdolecek static void 470 1.14 cube we_read_hdr(struct dp8390_softc *sc, int packet_ptr, 471 1.14 cube struct dp8390_ring *packet_hdrp) 472 1.1 jdolecek { 473 1.1 jdolecek struct we_softc *wsc = (struct we_softc *)sc; 474 1.1 jdolecek 475 1.16 tsutsui we_readmem(wsc, packet_ptr, (uint8_t *)packet_hdrp, 476 1.1 jdolecek sizeof(struct dp8390_ring)); 477 1.1 jdolecek #if BYTE_ORDER == BIG_ENDIAN 478 1.1 jdolecek packet_hdrp->count = bswap16(packet_hdrp->count); 479 1.1 jdolecek #endif 480 1.1 jdolecek } 481 1.1 jdolecek 482 1.1 jdolecek static void 483 1.14 cube we_recv_int(struct dp8390_softc *sc) 484 1.1 jdolecek { 485 1.1 jdolecek struct we_softc *wsc = (struct we_softc *)sc; 486 1.1 jdolecek 487 1.1 jdolecek WE_MEM_ENABLE(wsc); 488 1.1 jdolecek dp8390_rint(sc); 489 1.1 jdolecek WE_MEM_DISABLE(wsc); 490 1.1 jdolecek } 491 1.1 jdolecek 492 1.1 jdolecek static void 493 1.1 jdolecek we_media_init(struct dp8390_softc *sc) 494 1.1 jdolecek { 495 1.16 tsutsui struct we_softc *wsc = (struct we_softc *)sc; 496 1.1 jdolecek int defmedia = IFM_ETHER; 497 1.16 tsutsui uint8_t x; 498 1.1 jdolecek 499 1.1 jdolecek if (sc->is790) { 500 1.1 jdolecek x = bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE790_HWR); 501 1.1 jdolecek bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE790_HWR, 502 1.1 jdolecek x | WE790_HWR_SWH); 503 1.1 jdolecek if (bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE790_GCR) & 504 1.1 jdolecek WE790_GCR_GPOUT) 505 1.1 jdolecek defmedia |= IFM_10_2; 506 1.1 jdolecek else 507 1.1 jdolecek defmedia |= IFM_10_5; 508 1.1 jdolecek bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE790_HWR, 509 1.1 jdolecek x & ~WE790_HWR_SWH); 510 1.1 jdolecek } else { 511 1.1 jdolecek x = bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE_IRR); 512 1.1 jdolecek if (x & WE_IRR_OUT2) 513 1.1 jdolecek defmedia |= IFM_10_2; 514 1.1 jdolecek else 515 1.1 jdolecek defmedia |= IFM_10_5; 516 1.1 jdolecek } 517 1.1 jdolecek 518 1.1 jdolecek ifmedia_init(&sc->sc_media, 0, dp8390_mediachange, dp8390_mediastatus); 519 1.16 tsutsui ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_2, 0, NULL); 520 1.16 tsutsui ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_5, 0, NULL); 521 1.1 jdolecek ifmedia_set(&sc->sc_media, defmedia); 522 1.1 jdolecek } 523 1.1 jdolecek 524 1.1 jdolecek static int 525 1.14 cube we_mediachange(struct dp8390_softc *sc) 526 1.1 jdolecek { 527 1.1 jdolecek 528 1.1 jdolecek /* 529 1.1 jdolecek * Current media is already set up. Just reset the interface 530 1.1 jdolecek * to let the new value take hold. The new media will be 531 1.1 jdolecek * set up in we_init_card() called via dp8390_init(). 532 1.1 jdolecek */ 533 1.1 jdolecek dp8390_reset(sc); 534 1.16 tsutsui return 0; 535 1.1 jdolecek } 536 1.1 jdolecek 537 1.1 jdolecek static void 538 1.14 cube we_mediastatus(struct dp8390_softc *sc, struct ifmediareq *ifmr) 539 1.1 jdolecek { 540 1.1 jdolecek struct ifmedia *ifm = &sc->sc_media; 541 1.1 jdolecek 542 1.1 jdolecek /* 543 1.1 jdolecek * The currently selected media is always the active media. 544 1.1 jdolecek */ 545 1.1 jdolecek ifmr->ifm_active = ifm->ifm_cur->ifm_media; 546 1.1 jdolecek } 547 1.1 jdolecek 548 1.1 jdolecek static void 549 1.14 cube we_init_card(struct dp8390_softc *sc) 550 1.1 jdolecek { 551 1.1 jdolecek struct we_softc *wsc = (struct we_softc *)sc; 552 1.1 jdolecek struct ifmedia *ifm = &sc->sc_media; 553 1.1 jdolecek 554 1.1 jdolecek if (wsc->sc_init_hook) 555 1.1 jdolecek (*wsc->sc_init_hook)(wsc); 556 1.1 jdolecek 557 1.1 jdolecek we_set_media(wsc, ifm->ifm_cur->ifm_media); 558 1.1 jdolecek } 559 1.1 jdolecek 560 1.1 jdolecek static void 561 1.14 cube we_set_media(struct we_softc *wsc, int media) 562 1.1 jdolecek { 563 1.1 jdolecek struct dp8390_softc *sc = &wsc->sc_dp8390; 564 1.1 jdolecek bus_space_tag_t asict = wsc->sc_asict; 565 1.1 jdolecek bus_space_handle_t asich = wsc->sc_asich; 566 1.16 tsutsui uint8_t hwr, gcr, irr; 567 1.1 jdolecek 568 1.1 jdolecek if (sc->is790) { 569 1.1 jdolecek hwr = bus_space_read_1(asict, asich, WE790_HWR); 570 1.1 jdolecek bus_space_write_1(asict, asich, WE790_HWR, 571 1.1 jdolecek hwr | WE790_HWR_SWH); 572 1.1 jdolecek gcr = bus_space_read_1(asict, asich, WE790_GCR); 573 1.1 jdolecek if (IFM_SUBTYPE(media) == IFM_10_2) 574 1.1 jdolecek gcr |= WE790_GCR_GPOUT; 575 1.1 jdolecek else 576 1.1 jdolecek gcr &= ~WE790_GCR_GPOUT; 577 1.1 jdolecek bus_space_write_1(asict, asich, WE790_GCR, 578 1.1 jdolecek gcr | WE790_GCR_LIT); 579 1.1 jdolecek bus_space_write_1(asict, asich, WE790_HWR, 580 1.1 jdolecek hwr & ~WE790_HWR_SWH); 581 1.1 jdolecek return; 582 1.1 jdolecek } 583 1.1 jdolecek 584 1.1 jdolecek irr = bus_space_read_1(wsc->sc_asict, wsc->sc_asich, WE_IRR); 585 1.1 jdolecek if (IFM_SUBTYPE(media) == IFM_10_2) 586 1.1 jdolecek irr |= WE_IRR_OUT2; 587 1.1 jdolecek else 588 1.1 jdolecek irr &= ~WE_IRR_OUT2; 589 1.1 jdolecek bus_space_write_1(wsc->sc_asict, wsc->sc_asich, WE_IRR, irr); 590 1.1 jdolecek } 591