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