1141586Simp/*- 2141586Simp * Copyright (c) 2005, M. Warner Losh 3141586Simp * All rights reserved. 4141586Simp * Copyright (c) 1995, David Greenman 5141586Simp * All rights reserved. 6141586Simp * 7141586Simp * Redistribution and use in source and binary forms, with or without 8141586Simp * modification, are permitted provided that the following conditions 9141586Simp * are met: 10141586Simp * 1. Redistributions of source code must retain the above copyright 11141586Simp * notice unmodified, this list of conditions, and the following 12141586Simp * disclaimer. 13141586Simp * 2. Redistributions in binary form must reproduce the above copyright 14141586Simp * notice, this list of conditions and the following disclaimer in the 15141586Simp * documentation and/or other materials provided with the distribution. 16141586Simp * 17141586Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18141586Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19141586Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20141586Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21141586Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22141586Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23141586Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24141586Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25141586Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26141586Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27141586Simp * SUCH DAMAGE. 28141586Simp */ 29141586Simp 30141586Simp#include <sys/cdefs.h> 31141586Simp__FBSDID("$FreeBSD$"); 32141586Simp 33141586Simp#include "opt_ed.h" 34141586Simp 35141586Simp#ifdef ED_HPP 36141586Simp 37141586Simp#include <sys/param.h> 38141586Simp#include <sys/systm.h> 39141586Simp#include <sys/sockio.h> 40141586Simp#include <sys/mbuf.h> 41141586Simp#include <sys/kernel.h> 42141586Simp#include <sys/socket.h> 43141586Simp#include <sys/syslog.h> 44141586Simp 45141586Simp#include <sys/bus.h> 46141586Simp 47141586Simp#include <machine/bus.h> 48141586Simp#include <sys/rman.h> 49141586Simp#include <machine/resource.h> 50141586Simp 51141586Simp#include <net/ethernet.h> 52141586Simp#include <net/if.h> 53257176Sglebius#include <net/if_var.h> /* XXX: ed_hpp_set_physical_link() */ 54141586Simp#include <net/if_arp.h> 55141586Simp#include <net/if_dl.h> 56141586Simp#include <net/if_mib.h> 57141586Simp#include <net/if_media.h> 58141586Simp 59141586Simp#include <net/bpf.h> 60141586Simp 61141586Simp#include <dev/ed/if_edreg.h> 62141586Simp#include <dev/ed/if_edvar.h> 63141586Simp 64154924Simpstatic void ed_hpp_readmem(struct ed_softc *, bus_size_t, uint8_t *, 65154924Simp uint16_t); 66141586Simpstatic void ed_hpp_writemem(struct ed_softc *, uint8_t *, uint16_t, 67141586Simp uint16_t); 68154895Simpstatic void ed_hpp_set_physical_link(struct ed_softc *sc); 69154924Simpstatic u_short ed_hpp_write_mbufs(struct ed_softc *, struct mbuf *, 70154924Simp bus_size_t); 71141586Simp 72141586Simp/* 73141586Simp * Interrupt conversion table for the HP PC LAN+ 74141586Simp */ 75141586Simpstatic uint16_t ed_hpp_intr_val[] = { 76141586Simp 0, /* 0 */ 77141586Simp 0, /* 1 */ 78141586Simp 0, /* 2 */ 79141586Simp 3, /* 3 */ 80141586Simp 4, /* 4 */ 81141586Simp 5, /* 5 */ 82141586Simp 6, /* 6 */ 83141586Simp 7, /* 7 */ 84141586Simp 0, /* 8 */ 85141586Simp 9, /* 9 */ 86141586Simp 10, /* 10 */ 87141586Simp 11, /* 11 */ 88141586Simp 12, /* 12 */ 89141586Simp 0, /* 13 */ 90141586Simp 0, /* 14 */ 91141586Simp 15 /* 15 */ 92141586Simp}; 93141586Simp 94141586Simp#define ED_HPP_TEST_SIZE 16 95141586Simp 96141586Simp/* 97141586Simp * Probe and vendor specific initialization for the HP PC Lan+ Cards. 98141586Simp * (HP Part nos: 27247B and 27252A). 99141586Simp * 100141586Simp * The card has an asic wrapper around a DS8390 core. The asic handles 101141586Simp * host accesses and offers both standard register IO and memory mapped 102141586Simp * IO. Memory mapped I/O allows better performance at the expense of greater 103141586Simp * chance of an incompatibility with existing ISA cards. 104141586Simp * 105141586Simp * The card has a few caveats: it isn't tolerant of byte wide accesses, only 106141586Simp * short (16 bit) or word (32 bit) accesses are allowed. Some card revisions 107141586Simp * don't allow 32 bit accesses; these are indicated by a bit in the software 108141586Simp * ID register (see if_edreg.h). 109141586Simp * 110141586Simp * Other caveats are: we should read the MAC address only when the card 111141586Simp * is inactive. 112141586Simp * 113141586Simp * For more information; please consult the CRYNWR packet driver. 114141586Simp * 115141586Simp * The AUI port is turned on using the "link2" option on the ifconfig 116141586Simp * command line. 117141586Simp */ 118141586Simpint 119141586Simped_probe_HP_pclanp(device_t dev, int port_rid, int flags) 120141586Simp{ 121141586Simp struct ed_softc *sc = device_get_softc(dev); 122141586Simp int error; 123141586Simp int n; /* temp var */ 124141586Simp int memsize; /* mem on board */ 125141586Simp u_char checksum; /* checksum of board address */ 126141586Simp u_char irq; /* board configured IRQ */ 127141586Simp uint8_t test_pattern[ED_HPP_TEST_SIZE]; /* read/write areas for */ 128141586Simp uint8_t test_buffer[ED_HPP_TEST_SIZE]; /* probing card */ 129294883Sjhibbits rman_res_t conf_maddr, conf_msize, conf_irq, junk; 130141586Simp 131141586Simp error = ed_alloc_port(dev, 0, ED_HPP_IO_PORTS); 132141586Simp if (error) 133141586Simp return (error); 134141586Simp 135141586Simp /* Fill in basic information */ 136141586Simp sc->asic_offset = ED_HPP_ASIC_OFFSET; 137141586Simp sc->nic_offset = ED_HPP_NIC_OFFSET; 138141586Simp 139141586Simp sc->chip_type = ED_CHIP_TYPE_DP8390; 140141586Simp sc->isa16bit = 0; /* the 8390 core needs to be in byte mode */ 141141586Simp 142141586Simp /* 143141586Simp * Look for the HP PCLAN+ signature: "0x50,0x48,0x00,0x53" 144141586Simp */ 145141586Simp 146141586Simp if ((ed_asic_inb(sc, ED_HPP_ID) != 0x50) || 147141586Simp (ed_asic_inb(sc, ED_HPP_ID + 1) != 0x48) || 148141586Simp ((ed_asic_inb(sc, ED_HPP_ID + 2) & 0xF0) != 0) || 149141586Simp (ed_asic_inb(sc, ED_HPP_ID + 3) != 0x53)) 150154894Simp return (ENXIO); 151141586Simp 152141586Simp /* 153141586Simp * Read the MAC address and verify checksum on the address. 154141586Simp */ 155141586Simp 156141586Simp ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_MAC); 157141586Simp for (n = 0, checksum = 0; n < ETHER_ADDR_LEN; n++) 158147256Sbrooks checksum += (sc->enaddr[n] = 159141586Simp ed_asic_inb(sc, ED_HPP_MAC_ADDR + n)); 160141586Simp 161141586Simp checksum += ed_asic_inb(sc, ED_HPP_MAC_ADDR + ETHER_ADDR_LEN); 162141586Simp 163141586Simp if (checksum != 0xFF) 164154894Simp return (ENXIO); 165141586Simp 166141586Simp /* 167141586Simp * Verify that the software model number is 0. 168141586Simp */ 169141586Simp 170141586Simp ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_ID); 171141586Simp if (((sc->hpp_id = ed_asic_inw(sc, ED_HPP_PAGE_4)) & 172141586Simp ED_HPP_ID_SOFT_MODEL_MASK) != 0x0000) 173154894Simp return (ENXIO); 174141586Simp 175141586Simp /* 176141586Simp * Read in and save the current options configured on card. 177141586Simp */ 178141586Simp 179141586Simp sc->hpp_options = ed_asic_inw(sc, ED_HPP_OPTION); 180141586Simp 181141586Simp sc->hpp_options |= (ED_HPP_OPTION_NIC_RESET | 182141586Simp ED_HPP_OPTION_CHIP_RESET | ED_HPP_OPTION_ENABLE_IRQ); 183141586Simp 184141586Simp /* 185141586Simp * Reset the chip. This requires writing to the option register 186141586Simp * so take care to preserve the other bits. 187141586Simp */ 188141586Simp 189141586Simp ed_asic_outw(sc, ED_HPP_OPTION, 190141586Simp (sc->hpp_options & ~(ED_HPP_OPTION_NIC_RESET | 191141586Simp ED_HPP_OPTION_CHIP_RESET))); 192141586Simp 193141586Simp DELAY(5000); /* wait for chip reset to complete */ 194141586Simp 195141586Simp ed_asic_outw(sc, ED_HPP_OPTION, 196141586Simp (sc->hpp_options | (ED_HPP_OPTION_NIC_RESET | 197141586Simp ED_HPP_OPTION_CHIP_RESET | 198141586Simp ED_HPP_OPTION_ENABLE_IRQ))); 199141586Simp 200141586Simp DELAY(5000); 201141586Simp 202141586Simp if (!(ed_nic_inb(sc, ED_P0_ISR) & ED_ISR_RST)) 203154894Simp return (ENXIO); /* reset did not complete */ 204141586Simp 205141586Simp /* 206141586Simp * Read out configuration information. 207141586Simp */ 208141586Simp 209141586Simp ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_HW); 210141586Simp 211141586Simp irq = ed_asic_inb(sc, ED_HPP_HW_IRQ); 212141586Simp 213141586Simp /* 214141586Simp * Check for impossible IRQ. 215141586Simp */ 216141586Simp 217298435Spfg if (irq >= nitems(ed_hpp_intr_val)) 218154894Simp return (ENXIO); 219141586Simp 220141586Simp /* 221141586Simp * If the kernel IRQ was specified with a '?' use the cards idea 222141586Simp * of the IRQ. If the kernel IRQ was explicitly specified, it 223141586Simp * should match that of the hardware. 224141586Simp */ 225141586Simp error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk); 226141586Simp if (error) 227141586Simp bus_set_resource(dev, SYS_RES_IRQ, 0, ed_hpp_intr_val[irq], 1); 228141586Simp else { 229141586Simp if (conf_irq != ed_hpp_intr_val[irq]) 230141586Simp return (ENXIO); 231141586Simp } 232141586Simp 233141586Simp /* 234141586Simp * Fill in softconfig info. 235141586Simp */ 236141586Simp 237141586Simp sc->vendor = ED_VENDOR_HP; 238141586Simp sc->type = ED_TYPE_HP_PCLANPLUS; 239141586Simp sc->type_str = "HP-PCLAN+"; 240141586Simp 241141586Simp sc->mem_shared = 0; /* we DON'T have dual ported RAM */ 242141586Simp sc->mem_start = 0; /* we use offsets inside the card RAM */ 243141586Simp 244141586Simp sc->hpp_mem_start = NULL;/* no memory mapped I/O by default */ 245141586Simp 246141586Simp /* 247141586Simp * The board has 32KB of memory. Is there a way to determine 248141586Simp * this programmatically? 249141586Simp */ 250141586Simp 251141586Simp memsize = 32768; 252141586Simp 253141586Simp /* 254141586Simp * Check if memory mapping of the I/O registers possible. 255141586Simp */ 256141586Simp if (sc->hpp_options & ED_HPP_OPTION_MEM_ENABLE) { 257141586Simp u_long mem_addr; 258141586Simp 259141586Simp /* 260141586Simp * determine the memory address from the board. 261141586Simp */ 262141586Simp 263141586Simp ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_HW); 264141586Simp mem_addr = (ed_asic_inw(sc, ED_HPP_HW_MEM_MAP) << 8); 265141586Simp 266141586Simp /* 267141586Simp * Check that the kernel specified start of memory and 268141586Simp * hardware's idea of it match. 269141586Simp */ 270141586Simp error = bus_get_resource(dev, SYS_RES_MEMORY, 0, 271141586Simp &conf_maddr, &conf_msize); 272141586Simp if (error) 273141586Simp return (error); 274141586Simp 275141586Simp if (mem_addr != conf_maddr) 276154894Simp return (ENXIO); 277141586Simp 278141586Simp error = ed_alloc_memory(dev, 0, memsize); 279141586Simp if (error) 280141586Simp return (error); 281141586Simp 282141586Simp sc->hpp_mem_start = rman_get_virtual(sc->mem_res); 283141586Simp } 284141586Simp 285141586Simp /* 286141586Simp * Fill in the rest of the soft config structure. 287141586Simp */ 288141586Simp 289141586Simp /* 290141586Simp * The transmit page index. 291141586Simp */ 292141586Simp 293141586Simp sc->tx_page_start = ED_HPP_TX_PAGE_OFFSET; 294141586Simp 295141586Simp if (device_get_flags(dev) & ED_FLAGS_NO_MULTI_BUFFERING) 296141586Simp sc->txb_cnt = 1; 297141586Simp else 298141586Simp sc->txb_cnt = 2; 299141586Simp 300141586Simp /* 301141586Simp * Memory description 302141586Simp */ 303141586Simp 304141586Simp sc->mem_size = memsize; 305141586Simp sc->mem_ring = sc->mem_start + 306141586Simp (sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE); 307141586Simp sc->mem_end = sc->mem_start + sc->mem_size; 308141586Simp 309141586Simp /* 310141586Simp * Receive area starts after the transmit area and 311141586Simp * continues till the end of memory. 312141586Simp */ 313141586Simp 314141586Simp sc->rec_page_start = sc->tx_page_start + 315141586Simp (sc->txb_cnt * ED_TXBUF_SIZE); 316141586Simp sc->rec_page_stop = (sc->mem_size / ED_PAGE_SIZE); 317141586Simp 318141586Simp 319141586Simp sc->cr_proto = 0; /* value works */ 320141586Simp 321141586Simp /* 322141586Simp * Set the wrap registers for string I/O reads. 323141586Simp */ 324141586Simp 325141586Simp ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_HW); 326141586Simp ed_asic_outw(sc, ED_HPP_HW_WRAP, 327141586Simp ((sc->rec_page_start / ED_PAGE_SIZE) | 328141586Simp (((sc->rec_page_stop / ED_PAGE_SIZE) - 1) << 8))); 329141586Simp 330141586Simp /* 331141586Simp * Reset the register page to normal operation. 332141586Simp */ 333141586Simp 334141586Simp ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_PERF); 335141586Simp 336141586Simp /* 337141586Simp * Verify that we can read/write from adapter memory. 338141586Simp * Create test pattern. 339141586Simp */ 340141586Simp 341141586Simp for (n = 0; n < ED_HPP_TEST_SIZE; n++) 342141586Simp test_pattern[n] = (n*n) ^ ~n; 343141586Simp 344141586Simp#undef ED_HPP_TEST_SIZE 345141586Simp 346141586Simp /* 347141586Simp * Check that the memory is accessible thru the I/O ports. 348141586Simp * Write out the contents of "test_pattern", read back 349141586Simp * into "test_buffer" and compare the two for any 350141586Simp * mismatch. 351141586Simp */ 352141586Simp 353141586Simp for (n = 0; n < (32768 / ED_PAGE_SIZE); n ++) { 354141586Simp ed_hpp_writemem(sc, test_pattern, (n * ED_PAGE_SIZE), 355141586Simp sizeof(test_pattern)); 356141586Simp ed_hpp_readmem(sc, (n * ED_PAGE_SIZE), 357141586Simp test_buffer, sizeof(test_pattern)); 358141586Simp 359141586Simp if (bcmp(test_pattern, test_buffer, 360141586Simp sizeof(test_pattern))) 361154894Simp return (ENXIO); 362141586Simp } 363141586Simp 364154895Simp sc->sc_mediachg = ed_hpp_set_physical_link; 365154924Simp sc->sc_write_mbufs = ed_hpp_write_mbufs; 366154924Simp sc->readmem = ed_hpp_readmem; 367141586Simp return (0); 368141586Simp} 369141586Simp 370141586Simp/* 371141586Simp * HP PC Lan+ : Set the physical link to use AUI or TP/TL. 372141586Simp */ 373141586Simp 374154895Simpstatic void 375141586Simped_hpp_set_physical_link(struct ed_softc *sc) 376141586Simp{ 377147256Sbrooks struct ifnet *ifp = sc->ifp; 378141586Simp int lan_page; 379141586Simp 380141586Simp ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_LAN); 381141586Simp lan_page = ed_asic_inw(sc, ED_HPP_PAGE_0); 382141586Simp 383154892Simp if (ifp->if_flags & IFF_LINK2) { 384141586Simp /* 385141586Simp * Use the AUI port. 386141586Simp */ 387141586Simp 388141586Simp lan_page |= ED_HPP_LAN_AUI; 389141586Simp ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_LAN); 390141586Simp ed_asic_outw(sc, ED_HPP_PAGE_0, lan_page); 391141586Simp } else { 392141586Simp /* 393141586Simp * Use the ThinLan interface 394141586Simp */ 395141586Simp 396141586Simp lan_page &= ~ED_HPP_LAN_AUI; 397141586Simp ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_LAN); 398141586Simp ed_asic_outw(sc, ED_HPP_PAGE_0, lan_page); 399141586Simp } 400141586Simp 401141586Simp /* 402141586Simp * Wait for the lan card to re-initialize itself 403141586Simp */ 404141586Simp DELAY(150000); /* wait 150 ms */ 405141586Simp 406141586Simp /* 407141586Simp * Restore normal pages. 408141586Simp */ 409141586Simp ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_PERF); 410141586Simp} 411141586Simp 412141586Simp/* 413141586Simp * Support routines to handle the HP PC Lan+ card. 414141586Simp */ 415141586Simp 416141586Simp/* 417141586Simp * HP PC Lan+: Read from NIC memory, using either PIO or memory mapped 418141586Simp * IO. 419141586Simp */ 420141586Simp 421154924Simpstatic void 422149558Simped_hpp_readmem(struct ed_softc *sc, bus_size_t src, uint8_t *dst, 423149558Simp uint16_t amount) 424141586Simp{ 425141586Simp int use_32bit_access = !(sc->hpp_id & ED_HPP_ID_16_BIT_ACCESS); 426141586Simp 427141586Simp /* Program the source address in RAM */ 428141586Simp ed_asic_outw(sc, ED_HPP_PAGE_2, src); 429141586Simp 430141586Simp /* 431141586Simp * The HP PC Lan+ card supports word reads as well as 432141586Simp * a memory mapped i/o port that is aliased to every 433141586Simp * even address on the board. 434141586Simp */ 435141586Simp if (sc->hpp_mem_start) { 436141586Simp /* Enable memory mapped access. */ 437141586Simp ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options & 438141586Simp ~(ED_HPP_OPTION_MEM_DISABLE | 439141586Simp ED_HPP_OPTION_BOOT_ROM_ENB)); 440141586Simp 441141586Simp if (use_32bit_access && (amount > 3)) { 442141586Simp uint32_t *dl = (uint32_t *) dst; 443141586Simp volatile uint32_t *const sl = 444141586Simp (uint32_t *) sc->hpp_mem_start; 445141586Simp uint32_t *const fence = dl + (amount >> 2); 446141586Simp 447149558Simp /* 448149558Simp * Copy out NIC data. We could probably write this 449149558Simp * as a `movsl'. The currently generated code is lousy. 450149558Simp */ 451141586Simp while (dl < fence) 452141586Simp *dl++ = *sl; 453141586Simp 454141586Simp dst += (amount & ~3); 455141586Simp amount &= 3; 456141586Simp 457141586Simp } 458141586Simp 459141586Simp /* Finish off any words left, as a series of short reads */ 460141586Simp if (amount > 1) { 461141586Simp u_short *d = (u_short *) dst; 462141586Simp volatile u_short *const s = 463141586Simp (u_short *) sc->hpp_mem_start; 464141586Simp u_short *const fence = d + (amount >> 1); 465141586Simp 466141586Simp /* Copy out NIC data. */ 467141586Simp while (d < fence) 468141586Simp *d++ = *s; 469141586Simp 470141586Simp dst += (amount & ~1); 471141586Simp amount &= 1; 472141586Simp } 473141586Simp 474141586Simp /* 475141586Simp * read in a byte; however we need to always read 16 bits 476141586Simp * at a time or the hardware gets into a funny state 477141586Simp */ 478141586Simp 479141586Simp if (amount == 1) { 480141586Simp /* need to read in a short and copy LSB */ 481141586Simp volatile u_short *const s = 482141586Simp (volatile u_short *) sc->hpp_mem_start; 483141586Simp *dst = (*s) & 0xFF; 484141586Simp } 485141586Simp 486141586Simp /* Restore Boot ROM access. */ 487141586Simp ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options); 488141586Simp } else { 489141586Simp /* Read in data using the I/O port */ 490141586Simp if (use_32bit_access && (amount > 3)) { 491141586Simp ed_asic_insl(sc, ED_HPP_PAGE_4, dst, amount >> 2); 492141586Simp dst += (amount & ~3); 493141586Simp amount &= 3; 494141586Simp } 495141586Simp if (amount > 1) { 496141586Simp ed_asic_insw(sc, ED_HPP_PAGE_4, dst, amount >> 1); 497141586Simp dst += (amount & ~1); 498141586Simp amount &= 1; 499141586Simp } 500141586Simp if (amount == 1) { /* read in a short and keep the LSB */ 501141586Simp *dst = ed_asic_inw(sc, ED_HPP_PAGE_4) & 0xFF; 502141586Simp } 503141586Simp } 504141586Simp} 505141586Simp 506141586Simp/* 507141586Simp * HP PC Lan+: Write to NIC memory, using either PIO or memory mapped 508141586Simp * IO. 509141586Simp * Only used in the probe routine to test the memory. 'len' must 510141586Simp * be even. 511141586Simp */ 512141586Simpstatic void 513141586Simped_hpp_writemem(struct ed_softc *sc, uint8_t *src, uint16_t dst, uint16_t len) 514141586Simp{ 515141586Simp /* reset remote DMA complete flag */ 516141586Simp ed_nic_outb(sc, ED_P0_ISR, ED_ISR_RDC); 517141586Simp 518141586Simp /* program the write address in RAM */ 519141586Simp ed_asic_outw(sc, ED_HPP_PAGE_0, dst); 520141586Simp 521141586Simp if (sc->hpp_mem_start) { 522141586Simp u_short *s = (u_short *) src; 523141586Simp volatile u_short *d = (u_short *) sc->hpp_mem_start; 524141586Simp u_short *const fence = s + (len >> 1); 525141586Simp 526141586Simp /* 527141586Simp * Enable memory mapped access. 528141586Simp */ 529141586Simp ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options & 530141586Simp ~(ED_HPP_OPTION_MEM_DISABLE | 531141586Simp ED_HPP_OPTION_BOOT_ROM_ENB)); 532141586Simp 533141586Simp /* 534141586Simp * Copy to NIC memory. 535141586Simp */ 536141586Simp while (s < fence) 537141586Simp *d = *s++; 538141586Simp 539141586Simp /* 540141586Simp * Restore Boot ROM access. 541141586Simp */ 542141586Simp ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options); 543141586Simp } else { 544141586Simp /* write data using I/O writes */ 545141586Simp ed_asic_outsw(sc, ED_HPP_PAGE_4, src, len / 2); 546141586Simp } 547141586Simp} 548141586Simp 549141586Simp/* 550141586Simp * Write to HP PC Lan+ NIC memory. Access to the NIC can be by using 551141586Simp * outsw() or via the memory mapped interface to the same register. 552141586Simp * Writes have to be in word units; byte accesses won't work and may cause 553141586Simp * the NIC to behave weirdly. Long word accesses are permitted if the ASIC 554141586Simp * allows it. 555141586Simp */ 556141586Simp 557154924Simpstatic u_short 558154924Simped_hpp_write_mbufs(struct ed_softc *sc, struct mbuf *m, bus_size_t dst) 559141586Simp{ 560141586Simp int len, wantbyte; 561141586Simp unsigned short total_len; 562141586Simp unsigned char savebyte[2]; 563141586Simp volatile u_short * const d = 564141586Simp (volatile u_short *) sc->hpp_mem_start; 565141586Simp int use_32bit_accesses = !(sc->hpp_id & ED_HPP_ID_16_BIT_ACCESS); 566141586Simp 567141586Simp /* select page 0 registers */ 568261528Smarius ed_nic_barrier(sc, ED_P0_CR, 1, 569261528Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 570141586Simp ed_nic_outb(sc, ED_P0_CR, sc->cr_proto | ED_CR_STA); 571261528Smarius ed_nic_barrier(sc, ED_P0_CR, 1, 572261528Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 573141586Simp 574141586Simp /* reset remote DMA complete flag */ 575141586Simp ed_nic_outb(sc, ED_P0_ISR, ED_ISR_RDC); 576141586Simp 577141586Simp /* program the write address in RAM */ 578141586Simp ed_asic_outw(sc, ED_HPP_PAGE_0, dst); 579141586Simp 580141586Simp if (sc->hpp_mem_start) /* enable memory mapped I/O */ 581141586Simp ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options & 582141586Simp ~(ED_HPP_OPTION_MEM_DISABLE | 583141586Simp ED_HPP_OPTION_BOOT_ROM_ENB)); 584141586Simp 585141586Simp wantbyte = 0; 586141586Simp total_len = 0; 587141586Simp 588141586Simp if (sc->hpp_mem_start) { /* Memory mapped I/O port */ 589141586Simp while (m) { 590141586Simp total_len += (len = m->m_len); 591141586Simp if (len) { 592141586Simp caddr_t data = mtod(m, caddr_t); 593141586Simp /* finish the last word of the previous mbuf */ 594141586Simp if (wantbyte) { 595141586Simp savebyte[1] = *data; 596141586Simp *d = *((u_short *) savebyte); 597141586Simp data++; len--; wantbyte = 0; 598141586Simp } 599141586Simp /* output contiguous words */ 600141586Simp if ((len > 3) && (use_32bit_accesses)) { 601141586Simp volatile uint32_t *const dl = 602141586Simp (volatile uint32_t *) d; 603141586Simp uint32_t *sl = (uint32_t *) data; 604141586Simp uint32_t *fence = sl + (len >> 2); 605141586Simp 606141586Simp while (sl < fence) 607141586Simp *dl = *sl++; 608141586Simp 609141586Simp data += (len & ~3); 610141586Simp len &= 3; 611141586Simp } 612141586Simp /* finish off remain 16 bit writes */ 613141586Simp if (len > 1) { 614141586Simp u_short *s = (u_short *) data; 615141586Simp u_short *fence = s + (len >> 1); 616141586Simp 617141586Simp while (s < fence) 618141586Simp *d = *s++; 619141586Simp 620141586Simp data += (len & ~1); 621141586Simp len &= 1; 622141586Simp } 623141586Simp /* save last byte if needed */ 624141586Simp if ((wantbyte = (len == 1)) != 0) 625141586Simp savebyte[0] = *data; 626141586Simp } 627141586Simp m = m->m_next; /* to next mbuf */ 628141586Simp } 629141586Simp if (wantbyte) /* write last byte */ 630141586Simp *d = *((u_short *) savebyte); 631141586Simp } else { 632141586Simp /* use programmed I/O */ 633141586Simp while (m) { 634141586Simp total_len += (len = m->m_len); 635141586Simp if (len) { 636141586Simp caddr_t data = mtod(m, caddr_t); 637141586Simp /* finish the last word of the previous mbuf */ 638141586Simp if (wantbyte) { 639141586Simp savebyte[1] = *data; 640141586Simp ed_asic_outw(sc, ED_HPP_PAGE_4, 641141586Simp *((u_short *)savebyte)); 642141586Simp data++; 643141586Simp len--; 644141586Simp wantbyte = 0; 645141586Simp } 646141586Simp /* output contiguous words */ 647141586Simp if ((len > 3) && use_32bit_accesses) { 648141586Simp ed_asic_outsl(sc, ED_HPP_PAGE_4, 649141586Simp data, len >> 2); 650141586Simp data += (len & ~3); 651141586Simp len &= 3; 652141586Simp } 653141586Simp /* finish off remaining 16 bit accesses */ 654141586Simp if (len > 1) { 655141586Simp ed_asic_outsw(sc, ED_HPP_PAGE_4, 656141586Simp data, len >> 1); 657141586Simp data += (len & ~1); 658141586Simp len &= 1; 659141586Simp } 660141586Simp if ((wantbyte = (len == 1)) != 0) 661141586Simp savebyte[0] = *data; 662141586Simp 663141586Simp } /* if len != 0 */ 664141586Simp m = m->m_next; 665141586Simp } 666141586Simp if (wantbyte) /* spit last byte */ 667141586Simp ed_asic_outw(sc, ED_HPP_PAGE_4, *(u_short *)savebyte); 668141586Simp 669141586Simp } 670141586Simp 671141586Simp if (sc->hpp_mem_start) /* turn off memory mapped i/o */ 672141586Simp ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options); 673141586Simp 674141586Simp return (total_len); 675141586Simp} 676141586Simp 677141586Simp#endif /* ED_HPP */ 678