The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ed/if_ed_hpp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2005, M. Warner Losh
    3  * All rights reserved.
    4  * Copyright (c) 1995, David Greenman 
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice unmodified, this list of conditions, and the following
   12  *    disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include "opt_ed.h"
   34 
   35 #ifdef ED_HPP
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/sockio.h>
   40 #include <sys/mbuf.h>
   41 #include <sys/kernel.h>
   42 #include <sys/socket.h>
   43 #include <sys/syslog.h>
   44 
   45 #include <sys/bus.h>
   46 
   47 #include <machine/bus.h>
   48 #include <sys/rman.h>
   49 #include <machine/resource.h>
   50 
   51 #include <net/ethernet.h>
   52 #include <net/if.h>
   53 #include <net/if_arp.h>
   54 #include <net/if_dl.h>
   55 #include <net/if_mib.h>
   56 #include <net/if_media.h>
   57 
   58 #include <net/bpf.h>
   59 
   60 #include <dev/ed/if_edreg.h>
   61 #include <dev/ed/if_edvar.h>
   62 
   63 static void     ed_hpp_readmem(struct ed_softc *, bus_size_t, uint8_t *,
   64                     uint16_t);
   65 static void     ed_hpp_writemem(struct ed_softc *, uint8_t *, uint16_t,
   66                     uint16_t);
   67 static void     ed_hpp_set_physical_link(struct ed_softc *sc);
   68 static u_short  ed_hpp_write_mbufs(struct ed_softc *, struct mbuf *,
   69                     bus_size_t);
   70 
   71 /*
   72  * Interrupt conversion table for the HP PC LAN+
   73  */
   74 static uint16_t ed_hpp_intr_val[] = {
   75         0,              /* 0 */
   76         0,              /* 1 */
   77         0,              /* 2 */
   78         3,              /* 3 */
   79         4,              /* 4 */
   80         5,              /* 5 */
   81         6,              /* 6 */
   82         7,              /* 7 */
   83         0,              /* 8 */
   84         9,              /* 9 */
   85         10,             /* 10 */
   86         11,             /* 11 */
   87         12,             /* 12 */
   88         0,              /* 13 */
   89         0,              /* 14 */
   90         15              /* 15 */
   91 };
   92 
   93 #define ED_HPP_TEST_SIZE        16
   94 
   95 /*
   96  * Probe and vendor specific initialization for the HP PC Lan+ Cards.
   97  * (HP Part nos: 27247B and 27252A).
   98  *
   99  * The card has an asic wrapper around a DS8390 core.  The asic handles 
  100  * host accesses and offers both standard register IO and memory mapped 
  101  * IO.  Memory mapped I/O allows better performance at the expense of greater
  102  * chance of an incompatibility with existing ISA cards.
  103  *
  104  * The card has a few caveats: it isn't tolerant of byte wide accesses, only
  105  * short (16 bit) or word (32 bit) accesses are allowed.  Some card revisions
  106  * don't allow 32 bit accesses; these are indicated by a bit in the software
  107  * ID register (see if_edreg.h).
  108  * 
  109  * Other caveats are: we should read the MAC address only when the card
  110  * is inactive.
  111  *
  112  * For more information; please consult the CRYNWR packet driver.
  113  *
  114  * The AUI port is turned on using the "link2" option on the ifconfig 
  115  * command line.
  116  */
  117 int
  118 ed_probe_HP_pclanp(device_t dev, int port_rid, int flags)
  119 {
  120         struct ed_softc *sc = device_get_softc(dev);
  121         int error;
  122         int n;                          /* temp var */
  123         int memsize;                    /* mem on board */
  124         u_char checksum;                /* checksum of board address */
  125         u_char irq;                     /* board configured IRQ */
  126         uint8_t test_pattern[ED_HPP_TEST_SIZE]; /* read/write areas for */
  127         uint8_t test_buffer[ED_HPP_TEST_SIZE];  /* probing card */
  128         u_long conf_maddr, conf_msize, conf_irq, junk;
  129 
  130         error = ed_alloc_port(dev, 0, ED_HPP_IO_PORTS);
  131         if (error)
  132                 return (error);
  133 
  134         /* Fill in basic information */
  135         sc->asic_offset = ED_HPP_ASIC_OFFSET;
  136         sc->nic_offset  = ED_HPP_NIC_OFFSET;
  137 
  138         sc->chip_type = ED_CHIP_TYPE_DP8390;
  139         sc->isa16bit = 0;       /* the 8390 core needs to be in byte mode */
  140 
  141         /* 
  142          * Look for the HP PCLAN+ signature: "0x50,0x48,0x00,0x53" 
  143          */
  144         
  145         if ((ed_asic_inb(sc, ED_HPP_ID) != 0x50) || 
  146             (ed_asic_inb(sc, ED_HPP_ID + 1) != 0x48) ||
  147             ((ed_asic_inb(sc, ED_HPP_ID + 2) & 0xF0) != 0) ||
  148             (ed_asic_inb(sc, ED_HPP_ID + 3) != 0x53))
  149                 return (ENXIO);
  150 
  151         /* 
  152          * Read the MAC address and verify checksum on the address.
  153          */
  154 
  155         ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_MAC);
  156         for (n  = 0, checksum = 0; n < ETHER_ADDR_LEN; n++)
  157                 checksum += (sc->enaddr[n] = 
  158                     ed_asic_inb(sc, ED_HPP_MAC_ADDR + n));
  159         
  160         checksum += ed_asic_inb(sc, ED_HPP_MAC_ADDR + ETHER_ADDR_LEN);
  161 
  162         if (checksum != 0xFF)
  163                 return (ENXIO);
  164 
  165         /*
  166          * Verify that the software model number is 0.
  167          */
  168         
  169         ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_ID);
  170         if (((sc->hpp_id = ed_asic_inw(sc, ED_HPP_PAGE_4)) & 
  171                 ED_HPP_ID_SOFT_MODEL_MASK) != 0x0000)
  172                 return (ENXIO);
  173 
  174         /*
  175          * Read in and save the current options configured on card.
  176          */
  177 
  178         sc->hpp_options = ed_asic_inw(sc, ED_HPP_OPTION);
  179 
  180         sc->hpp_options |= (ED_HPP_OPTION_NIC_RESET | 
  181             ED_HPP_OPTION_CHIP_RESET | ED_HPP_OPTION_ENABLE_IRQ);
  182 
  183         /* 
  184          * Reset the chip.  This requires writing to the option register
  185          * so take care to preserve the other bits.
  186          */
  187 
  188         ed_asic_outw(sc, ED_HPP_OPTION, 
  189             (sc->hpp_options & ~(ED_HPP_OPTION_NIC_RESET | 
  190             ED_HPP_OPTION_CHIP_RESET)));
  191 
  192         DELAY(5000);    /* wait for chip reset to complete */
  193 
  194         ed_asic_outw(sc, ED_HPP_OPTION,
  195             (sc->hpp_options | (ED_HPP_OPTION_NIC_RESET |
  196             ED_HPP_OPTION_CHIP_RESET |
  197             ED_HPP_OPTION_ENABLE_IRQ)));
  198 
  199         DELAY(5000);
  200 
  201         if (!(ed_nic_inb(sc, ED_P0_ISR) & ED_ISR_RST))
  202                 return (ENXIO); /* reset did not complete */
  203 
  204         /*
  205          * Read out configuration information.
  206          */
  207 
  208         ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_HW);
  209 
  210         irq = ed_asic_inb(sc, ED_HPP_HW_IRQ);
  211 
  212         /*
  213          * Check for impossible IRQ.
  214          */
  215 
  216         if (irq >= (sizeof(ed_hpp_intr_val) / sizeof(ed_hpp_intr_val[0])))
  217                 return (ENXIO);
  218 
  219         /* 
  220          * If the kernel IRQ was specified with a '?' use the cards idea
  221          * of the IRQ.  If the kernel IRQ was explicitly specified, it
  222          * should match that of the hardware.
  223          */
  224         error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
  225         if (error)
  226                 bus_set_resource(dev, SYS_RES_IRQ, 0, ed_hpp_intr_val[irq], 1);
  227         else {
  228                 if (conf_irq != ed_hpp_intr_val[irq])
  229                         return (ENXIO);
  230         }
  231 
  232         /*
  233          * Fill in softconfig info.
  234          */
  235 
  236         sc->vendor = ED_VENDOR_HP;
  237         sc->type = ED_TYPE_HP_PCLANPLUS;
  238         sc->type_str = "HP-PCLAN+";
  239 
  240         sc->mem_shared = 0;     /* we DON'T have dual ported RAM */
  241         sc->mem_start = 0;      /* we use offsets inside the card RAM */
  242 
  243         sc->hpp_mem_start = NULL;/* no memory mapped I/O by default */
  244 
  245         /*
  246          * The board has 32KB of memory.  Is there a way to determine
  247          * this programmatically?
  248          */
  249         
  250         memsize = 32768;
  251 
  252         /*
  253          * Check if memory mapping of the I/O registers possible.
  254          */
  255         if (sc->hpp_options & ED_HPP_OPTION_MEM_ENABLE) {
  256                 u_long mem_addr;
  257 
  258                 /*
  259                  * determine the memory address from the board.
  260                  */
  261                 
  262                 ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_HW);
  263                 mem_addr = (ed_asic_inw(sc, ED_HPP_HW_MEM_MAP) << 8);
  264 
  265                 /*
  266                  * Check that the kernel specified start of memory and
  267                  * hardware's idea of it match.
  268                  */
  269                 error = bus_get_resource(dev, SYS_RES_MEMORY, 0,
  270                                          &conf_maddr, &conf_msize);
  271                 if (error)
  272                         return (error);
  273                 
  274                 if (mem_addr != conf_maddr)
  275                         return (ENXIO);
  276 
  277                 error = ed_alloc_memory(dev, 0, memsize);
  278                 if (error)
  279                         return (error);
  280 
  281                 sc->hpp_mem_start = rman_get_virtual(sc->mem_res);
  282         }
  283 
  284         /*
  285          * Fill in the rest of the soft config structure.
  286          */
  287 
  288         /*
  289          * The transmit page index.
  290          */
  291 
  292         sc->tx_page_start = ED_HPP_TX_PAGE_OFFSET;
  293 
  294         if (device_get_flags(dev) & ED_FLAGS_NO_MULTI_BUFFERING)
  295                 sc->txb_cnt = 1;
  296         else
  297                 sc->txb_cnt = 2;
  298 
  299         /*
  300          * Memory description
  301          */
  302 
  303         sc->mem_size = memsize;
  304         sc->mem_ring = sc->mem_start + 
  305                 (sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE);
  306         sc->mem_end = sc->mem_start + sc->mem_size;
  307 
  308         /*
  309          * Receive area starts after the transmit area and 
  310          * continues till the end of memory.
  311          */
  312 
  313         sc->rec_page_start = sc->tx_page_start + 
  314                                 (sc->txb_cnt * ED_TXBUF_SIZE);
  315         sc->rec_page_stop = (sc->mem_size / ED_PAGE_SIZE);
  316 
  317 
  318         sc->cr_proto = 0;       /* value works */
  319 
  320         /*
  321          * Set the wrap registers for string I/O reads.
  322          */
  323 
  324         ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_HW);
  325         ed_asic_outw(sc, ED_HPP_HW_WRAP,
  326             ((sc->rec_page_start / ED_PAGE_SIZE) |
  327             (((sc->rec_page_stop / ED_PAGE_SIZE) - 1) << 8)));
  328 
  329         /*
  330          * Reset the register page to normal operation.
  331          */
  332 
  333         ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_PERF);
  334 
  335         /*
  336          * Verify that we can read/write from adapter memory.
  337          * Create test pattern.
  338          */
  339 
  340         for (n = 0; n < ED_HPP_TEST_SIZE; n++)
  341                 test_pattern[n] = (n*n) ^ ~n;
  342 
  343 #undef  ED_HPP_TEST_SIZE
  344 
  345         /*
  346          * Check that the memory is accessible thru the I/O ports.
  347          * Write out the contents of "test_pattern", read back
  348          * into "test_buffer" and compare the two for any
  349          * mismatch.
  350          */
  351 
  352         for (n = 0; n < (32768 / ED_PAGE_SIZE); n ++) {
  353                 ed_hpp_writemem(sc, test_pattern, (n * ED_PAGE_SIZE), 
  354                                 sizeof(test_pattern));
  355                 ed_hpp_readmem(sc, (n * ED_PAGE_SIZE), 
  356                         test_buffer, sizeof(test_pattern));
  357 
  358                 if (bcmp(test_pattern, test_buffer, 
  359                         sizeof(test_pattern)))
  360                         return (ENXIO);
  361         }
  362 
  363         sc->sc_mediachg = ed_hpp_set_physical_link;
  364         sc->sc_write_mbufs = ed_hpp_write_mbufs;
  365         sc->readmem = ed_hpp_readmem;
  366         return (0);
  367 }
  368 
  369 /*
  370  * HP PC Lan+ : Set the physical link to use AUI or TP/TL.
  371  */
  372 
  373 static void
  374 ed_hpp_set_physical_link(struct ed_softc *sc)
  375 {
  376         struct ifnet *ifp = sc->ifp;
  377         int lan_page;
  378 
  379         ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_LAN);
  380         lan_page = ed_asic_inw(sc, ED_HPP_PAGE_0);
  381 
  382         if (ifp->if_flags & IFF_LINK2) {
  383                 /*
  384                  * Use the AUI port.
  385                  */
  386 
  387                 lan_page |= ED_HPP_LAN_AUI;
  388                 ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_LAN);
  389                 ed_asic_outw(sc, ED_HPP_PAGE_0, lan_page);
  390         } else {
  391                 /*
  392                  * Use the ThinLan interface
  393                  */
  394 
  395                 lan_page &= ~ED_HPP_LAN_AUI;
  396                 ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_LAN);
  397                 ed_asic_outw(sc, ED_HPP_PAGE_0, lan_page);
  398         }
  399 
  400         /*
  401          * Wait for the lan card to re-initialize itself
  402          */
  403         DELAY(150000);  /* wait 150 ms */
  404 
  405         /*
  406          * Restore normal pages.
  407          */
  408         ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_PERF);
  409 }
  410 
  411 /*
  412  * Support routines to handle the HP PC Lan+ card.
  413  */
  414 
  415 /*
  416  * HP PC Lan+: Read from NIC memory, using either PIO or memory mapped
  417  * IO.
  418  */
  419 
  420 static void
  421 ed_hpp_readmem(struct ed_softc *sc, bus_size_t src, uint8_t *dst,
  422     uint16_t amount)
  423 {
  424         int use_32bit_access = !(sc->hpp_id & ED_HPP_ID_16_BIT_ACCESS);
  425 
  426         /* Program the source address in RAM */
  427         ed_asic_outw(sc, ED_HPP_PAGE_2, src);
  428 
  429         /*
  430          * The HP PC Lan+ card supports word reads as well as
  431          * a memory mapped i/o port that is aliased to every 
  432          * even address on the board.
  433          */
  434         if (sc->hpp_mem_start) {
  435                 /* Enable memory mapped access.  */
  436                 ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options & 
  437                         ~(ED_HPP_OPTION_MEM_DISABLE | 
  438                           ED_HPP_OPTION_BOOT_ROM_ENB));
  439 
  440                 if (use_32bit_access && (amount > 3)) {
  441                         uint32_t *dl = (uint32_t *) dst;        
  442                         volatile uint32_t *const sl = 
  443                                 (uint32_t *) sc->hpp_mem_start;
  444                         uint32_t *const fence = dl + (amount >> 2);
  445                         
  446                         /*
  447                          * Copy out NIC data.  We could probably write this
  448                          * as a `movsl'. The currently generated code is lousy.
  449                          */
  450                         while (dl < fence)
  451                                 *dl++ = *sl;
  452                 
  453                         dst += (amount & ~3);
  454                         amount &= 3;
  455 
  456                 } 
  457 
  458                 /* Finish off any words left, as a series of short reads */
  459                 if (amount > 1) {
  460                         u_short *d = (u_short *) dst;   
  461                         volatile u_short *const s = 
  462                                 (u_short *) sc->hpp_mem_start;
  463                         u_short *const fence = d + (amount >> 1);
  464                         
  465                         /* Copy out NIC data.  */
  466                         while (d < fence)
  467                                 *d++ = *s;
  468         
  469                         dst += (amount & ~1);
  470                         amount &= 1;
  471                 }
  472 
  473                 /*
  474                  * read in a byte; however we need to always read 16 bits
  475                  * at a time or the hardware gets into a funny state
  476                  */
  477 
  478                 if (amount == 1) {
  479                         /* need to read in a short and copy LSB */
  480                         volatile u_short *const s = 
  481                                 (volatile u_short *) sc->hpp_mem_start;
  482                         *dst = (*s) & 0xFF;     
  483                 }
  484 
  485                 /* Restore Boot ROM access.  */
  486                 ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options);
  487         } else { 
  488                 /* Read in data using the I/O port */
  489                 if (use_32bit_access && (amount > 3)) {
  490                         ed_asic_insl(sc, ED_HPP_PAGE_4, dst, amount >> 2);
  491                         dst += (amount & ~3);
  492                         amount &= 3;
  493                 }
  494                 if (amount > 1) {
  495                         ed_asic_insw(sc, ED_HPP_PAGE_4, dst, amount >> 1);
  496                         dst += (amount & ~1);
  497                         amount &= 1;
  498                 }
  499                 if (amount == 1) { /* read in a short and keep the LSB */
  500                         *dst = ed_asic_inw(sc, ED_HPP_PAGE_4) & 0xFF;
  501                 }
  502         }
  503 }
  504 
  505 /*
  506  * HP PC Lan+: Write to NIC memory, using either PIO or memory mapped
  507  * IO.
  508  *      Only used in the probe routine to test the memory. 'len' must
  509  *      be even.
  510  */
  511 static void
  512 ed_hpp_writemem(struct ed_softc *sc, uint8_t *src, uint16_t dst, uint16_t len)
  513 {
  514         /* reset remote DMA complete flag */
  515         ed_nic_outb(sc, ED_P0_ISR, ED_ISR_RDC);
  516 
  517         /* program the write address in RAM */
  518         ed_asic_outw(sc, ED_HPP_PAGE_0, dst);
  519 
  520         if (sc->hpp_mem_start) {
  521                 u_short *s = (u_short *) src;
  522                 volatile u_short *d = (u_short *) sc->hpp_mem_start;
  523                 u_short *const fence = s + (len >> 1);
  524 
  525                 /*
  526                  * Enable memory mapped access.
  527                  */
  528                 ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options & 
  529                         ~(ED_HPP_OPTION_MEM_DISABLE | 
  530                           ED_HPP_OPTION_BOOT_ROM_ENB));
  531 
  532                 /*
  533                  * Copy to NIC memory.
  534                  */
  535                 while (s < fence)
  536                         *d = *s++;
  537 
  538                 /*
  539                  * Restore Boot ROM access.
  540                  */
  541                 ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options);
  542         } else {
  543                 /* write data using I/O writes */
  544                 ed_asic_outsw(sc, ED_HPP_PAGE_4, src, len / 2);
  545         }
  546 }
  547 
  548 /*
  549  * Write to HP PC Lan+ NIC memory.  Access to the NIC can be by using 
  550  * outsw() or via the memory mapped interface to the same register.
  551  * Writes have to be in word units; byte accesses won't work and may cause
  552  * the NIC to behave weirdly. Long word accesses are permitted if the ASIC
  553  * allows it.
  554  */
  555 
  556 static u_short
  557 ed_hpp_write_mbufs(struct ed_softc *sc, struct mbuf *m, bus_size_t dst)
  558 {
  559         int len, wantbyte;
  560         unsigned short total_len;
  561         unsigned char savebyte[2];
  562         volatile u_short * const d = 
  563                 (volatile u_short *) sc->hpp_mem_start;
  564         int use_32bit_accesses = !(sc->hpp_id & ED_HPP_ID_16_BIT_ACCESS);
  565 
  566         /* select page 0 registers */
  567         ed_nic_outb(sc, ED_P0_CR, sc->cr_proto | ED_CR_STA);
  568 
  569         /* reset remote DMA complete flag */
  570         ed_nic_outb(sc, ED_P0_ISR, ED_ISR_RDC);
  571 
  572         /* program the write address in RAM */
  573         ed_asic_outw(sc, ED_HPP_PAGE_0, dst);
  574 
  575         if (sc->hpp_mem_start)  /* enable memory mapped I/O */
  576                 ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options & 
  577                         ~(ED_HPP_OPTION_MEM_DISABLE |
  578                         ED_HPP_OPTION_BOOT_ROM_ENB));
  579 
  580         wantbyte = 0;
  581         total_len = 0;
  582 
  583         if (sc->hpp_mem_start) {        /* Memory mapped I/O port */
  584                 while (m) {
  585                         total_len += (len = m->m_len);
  586                         if (len) {
  587                                 caddr_t data = mtod(m, caddr_t);
  588                                 /* finish the last word of the previous mbuf */
  589                                 if (wantbyte) {
  590                                         savebyte[1] = *data;
  591                                         *d = *((u_short *) savebyte);
  592                                         data++; len--; wantbyte = 0;
  593                                 }
  594                                 /* output contiguous words */
  595                                 if ((len > 3) && (use_32bit_accesses)) {
  596                                         volatile uint32_t *const dl = 
  597                                                 (volatile uint32_t *) d;
  598                                         uint32_t *sl = (uint32_t *) data;
  599                                         uint32_t *fence = sl + (len >> 2);
  600 
  601                                         while (sl < fence)
  602                                                 *dl = *sl++;
  603 
  604                                         data += (len & ~3);
  605                                         len &= 3;
  606                                 }
  607                                 /* finish off remain 16 bit writes */
  608                                 if (len > 1) {
  609                                         u_short *s = (u_short *) data;
  610                                         u_short *fence = s + (len >> 1);
  611 
  612                                         while (s < fence)
  613                                                 *d = *s++;
  614 
  615                                         data += (len & ~1); 
  616                                         len &= 1;
  617                                 }
  618                                 /* save last byte if needed */
  619                                 if ((wantbyte = (len == 1)) != 0)
  620                                         savebyte[0] = *data;
  621                         }
  622                         m = m->m_next;  /* to next mbuf */
  623                 }
  624                 if (wantbyte) /* write last byte */
  625                         *d = *((u_short *) savebyte);
  626         } else {
  627                 /* use programmed I/O */
  628                 while (m) {
  629                         total_len += (len = m->m_len);
  630                         if (len) {
  631                                 caddr_t data = mtod(m, caddr_t);
  632                                 /* finish the last word of the previous mbuf */
  633                                 if (wantbyte) {
  634                                         savebyte[1] = *data;
  635                                         ed_asic_outw(sc, ED_HPP_PAGE_4,
  636                                                      *((u_short *)savebyte));
  637                                         data++; 
  638                                         len--; 
  639                                         wantbyte = 0;
  640                                 }
  641                                 /* output contiguous words */
  642                                 if ((len > 3) && use_32bit_accesses) {
  643                                         ed_asic_outsl(sc, ED_HPP_PAGE_4,
  644                                                       data, len >> 2);
  645                                         data += (len & ~3);
  646                                         len &= 3;
  647                                 }
  648                                 /* finish off remaining 16 bit accesses */
  649                                 if (len > 1) {
  650                                         ed_asic_outsw(sc, ED_HPP_PAGE_4,
  651                                                       data, len >> 1);
  652                                         data += (len & ~1);
  653                                         len &= 1;
  654                                 }
  655                                 if ((wantbyte = (len == 1)) != 0)
  656                                         savebyte[0] = *data;
  657 
  658                         } /* if len != 0 */
  659                         m = m->m_next;
  660                 }
  661                 if (wantbyte) /* spit last byte */
  662                         ed_asic_outw(sc, ED_HPP_PAGE_4, *(u_short *)savebyte);
  663 
  664         }
  665 
  666         if (sc->hpp_mem_start)  /* turn off memory mapped i/o */
  667                 ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options);
  668 
  669         return (total_len);
  670 }
  671 
  672 #endif /* ED_HPP */

Cache object: a38decff62a225e531f02da14a2e4a4b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.