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