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/mca/if_elmc_mca.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 /*      $NetBSD: if_elmc_mca.c,v 1.14 2003/10/25 20:19:01 mycroft Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Rafal K. Boni and Jaromir Dolecek.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed by the NetBSD
   21  *      Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 /*
   40  * 3Com 3c523 EtherLink/MC Ethernet card driver (uses i82586 Ethernet chip).
   41  *
   42  * The 3c523-specific hooks were derived from Linux driver (file
   43  * drivers/net/3c523.[ch]).
   44  *
   45  * This driver uses generic i82586 stuff. See also ai(4), ef(4), ix(4).
   46  */
   47 
   48 #include <sys/cdefs.h>
   49 __KERNEL_RCSID(0, "$NetBSD: if_elmc_mca.c,v 1.14 2003/10/25 20:19:01 mycroft Exp $");
   50 
   51 #include <sys/param.h>
   52 #include <sys/systm.h>
   53 #include <sys/mbuf.h>
   54 #include <sys/errno.h>
   55 #include <sys/device.h>
   56 #include <sys/protosw.h>
   57 #include <sys/socket.h>
   58 
   59 #include <net/if.h>
   60 #include <net/if_types.h>
   61 #include <net/if_media.h>
   62 #include <net/if_ether.h>
   63 
   64 #include <machine/bus.h>
   65 
   66 #include <dev/ic/i82586reg.h>
   67 #include <dev/ic/i82586var.h>
   68 #include <dev/mca/mcadevs.h>
   69 #include <dev/mca/mcavar.h>
   70 
   71 #include <dev/mca/3c523reg.h>
   72 
   73 struct elmc_mca_softc {
   74         struct ie_softc sc_ie;
   75 
   76         bus_space_tag_t sc_regt;        /* space tag for registers */
   77         bus_space_handle_t sc_regh;     /* space handle for registers */
   78 
   79         void            *sc_ih;         /* interrupt handle */
   80 };
   81 
   82 int     elmc_mca_match __P((struct device *, struct cfdata *, void *));
   83 void    elmc_mca_attach __P((struct device *, struct device *, void *));
   84 
   85 static void     elmc_mca_copyin __P((struct ie_softc *, void *, int, size_t));
   86 static void     elmc_mca_copyout __P((struct ie_softc *, const void *, int, size_t));
   87 static u_int16_t elmc_mca_read_16 __P((struct ie_softc *, int));
   88 static void     elmc_mca_write_16 __P((struct ie_softc *, int, u_int16_t));
   89 static void     elmc_mca_write_24 __P((struct ie_softc *, int, int));
   90 static void     elmc_mca_attn __P((struct ie_softc *, int));
   91 static void     elmc_mca_hwreset __P((struct ie_softc *, int));
   92 static int      elmc_mca_intrhook __P((struct ie_softc *, int));
   93 
   94 int
   95 elmc_mca_match(struct device *parent, struct cfdata *cf, void *aux)
   96 {
   97         struct mca_attach_args *ma = aux;
   98 
   99         switch (ma->ma_id) {
  100         case MCA_PRODUCT_3C523:
  101                 return 1;
  102         }
  103 
  104         return 0;
  105 }
  106 
  107 void
  108 elmc_mca_attach(struct device *parent, struct device *self, void *aux)
  109 {
  110         struct elmc_mca_softc *asc = (void *) self;
  111         struct ie_softc *sc = &asc->sc_ie;
  112         struct mca_attach_args *ma = aux;
  113         int pos2, pos3, i, revision;
  114         int iobase, irq, pbram_addr;
  115         bus_space_handle_t ioh, memh;
  116         u_int8_t myaddr[ETHER_ADDR_LEN];
  117 
  118         pos2 = mca_conf_read(ma->ma_mc, ma->ma_slot, 2);
  119         pos3 = mca_conf_read(ma->ma_mc, ma->ma_slot, 3);
  120 
  121         /*
  122          * POS register 2: (adf pos0)
  123          * 
  124          * 7 6 5 4 3 2 1 0
  125          *     \ \_/ \_/ \__ enable: 0=adapter disabled, 1=adapter enabled
  126          *      \  \   \____ I/O Address Range: 00=300-307, 01=1300-1307,
  127          *       \  \                           10=2300-2307, 11=3300-3307
  128          *        \  \______ Packet Buffer RAM Address Range:
  129          *         \            00=0x0c0000-0x0c5fff 01=0x0c8000-0x0cdfff
  130          *          \           10=0x0d0000-0x0d5fff 11=0x0d8000-0x0ddfff
  131          *           \______ Transceiver Type: 0=onboard(BNC) 1=ext(DIX)
  132          *
  133          * POS register 3: (adf pos1)
  134          * 
  135          * 7 6 5 4 3 2 1 0
  136          *          \____/
  137          *               \__ Interrupt level: 0100=3, 0010=7, 1000=9, 0001=12
  138          */
  139 
  140         iobase = ELMC_IOADDR_BASE + (0x1000 * ((pos2 & 0x6) >> 1));
  141 
  142         /* get irq */
  143         switch (pos3 & 0x1f) {
  144         case 4: irq = 3; break;
  145         case 2: irq = 7; break;
  146         case 8: irq = 9; break;
  147         case 1: irq = 12; break;
  148         default:
  149                 printf("%s: cannot determine irq\n", sc->sc_dev.dv_xname);
  150                 return;
  151         }
  152 
  153         pbram_addr = ELMC_MADDR_BASE + (((pos2 & 24) >> 3) * 0x8000);
  154 
  155         printf(" slot %d irq %d: 3Com EtherLink/MC Ethernet Adapter (3C523)\n",
  156                 ma->ma_slot + 1, irq);
  157 
  158         /* map the pio registers */
  159         if (bus_space_map(ma->ma_iot, iobase, ELMC_IOADDR_SIZE, 0, &ioh)) {
  160                 printf("%s: unable to map i/o space\n", sc->sc_dev.dv_xname);
  161                 return;
  162         }
  163 
  164         /*
  165          * 3c523 has a 24K memory. The first 16K is the shared memory, while
  166          * the last 8K is for the EtherStart BIOS ROM, which we don't care
  167          * about. Just use the first 16K.
  168          */
  169         if (bus_space_map(ma->ma_memt, pbram_addr, ELMC_MADDR_SIZE, 0, &memh)) {
  170                 printf("%s: unable to map memory space\n", sc->sc_dev.dv_xname);
  171                 if (pbram_addr == 0xc0000) {
  172                         printf("%s: memory space 0xc0000 may conflict with vga\n",
  173                                 sc->sc_dev.dv_xname);
  174                 }
  175                                 
  176                 bus_space_unmap(ma->ma_iot, ioh, ELMC_IOADDR_SIZE);
  177                 return;
  178         }
  179 
  180         asc->sc_regt = ma->ma_iot;
  181         asc->sc_regh = ioh;
  182 
  183         sc->hwinit = NULL;
  184         sc->intrhook = elmc_mca_intrhook;
  185         sc->hwreset = elmc_mca_hwreset;
  186         sc->chan_attn = elmc_mca_attn;
  187 
  188         sc->ie_bus_barrier = NULL;
  189 
  190         sc->memcopyin = elmc_mca_copyin;
  191         sc->memcopyout = elmc_mca_copyout;
  192         sc->ie_bus_read16 = elmc_mca_read_16;
  193         sc->ie_bus_write16 = elmc_mca_write_16;
  194         sc->ie_bus_write24 = elmc_mca_write_24;
  195 
  196         sc->do_xmitnopchain = 0;
  197 
  198         sc->sc_mediachange = NULL;
  199         sc->sc_mediastatus = NULL;
  200 
  201         sc->bt = ma->ma_memt;
  202         sc->bh = memh;
  203 
  204         /* Map i/o space. */
  205         sc->sc_msize = ELMC_MADDR_SIZE;
  206         sc->sc_maddr = (void *)memh;
  207         sc->sc_iobase = (char *)sc->sc_maddr + sc->sc_msize - (1 << 24);
  208 
  209         /* set up pointers to important on-card control structures */
  210         sc->iscp = 0;
  211         sc->scb = IE_ISCP_SZ;
  212         sc->scp = sc->sc_msize + IE_SCP_ADDR - (1 << 24);
  213 
  214         sc->buf_area = sc->scb + IE_SCB_SZ;
  215         sc->buf_area_sz = sc->sc_msize - IE_ISCP_SZ - IE_SCB_SZ - IE_SCP_SZ;
  216 
  217         /*
  218          * According to docs, we might need to read the interrupt number and
  219          * write it back to the IRQ select register, since the POST might not
  220          * configure the IRQ properly.
  221          */
  222         (void) mca_conf_write(ma->ma_mc, ma->ma_slot, 3, pos3 & 0x1f);
  223 
  224         /* reset the card first */
  225         elmc_mca_hwreset(sc, CARD_RESET);
  226         delay(1000000 / ( 1<< 5));
  227 
  228         /* zero card memory */
  229         bus_space_set_region_1(sc->bt, sc->bh, 0, 0, sc->sc_msize);
  230 
  231         /* set card to 16-bit bus mode */
  232         bus_space_write_1(sc->bt, sc->bh, IE_SCP_BUS_USE((u_long)sc->scp),
  233                           IE_SYSBUS_16BIT);
  234 
  235         /* set up pointers to key structures */
  236         elmc_mca_write_24(sc, IE_SCP_ISCP((u_long)sc->scp), (u_long) sc->iscp);
  237         elmc_mca_write_16(sc, IE_ISCP_SCB((u_long)sc->iscp), (u_long) sc->scb);
  238         elmc_mca_write_24(sc, IE_ISCP_BASE((u_long)sc->iscp), (u_long) sc->iscp);
  239 
  240         /* flush setup of pointers, check if chip answers */
  241         bus_space_barrier(sc->bt, sc->bh, 0, sc->sc_msize,
  242                           BUS_SPACE_BARRIER_WRITE);
  243         if (!i82586_proberam(sc)) {
  244                 printf("%s: can't talk to i82586!\n", sc->sc_dev.dv_xname);
  245 
  246                 bus_space_unmap(asc->sc_regt, asc->sc_regh, ELMC_IOADDR_SIZE);
  247                 bus_space_unmap(sc->bt, sc->bh, ELMC_MADDR_SIZE);
  248                 return;
  249         }
  250 
  251         /* revision is stored in the first 4 bits of the revision register */
  252         revision = (int) bus_space_read_1(asc->sc_regt, asc->sc_regh,
  253                                 ELMC_REVISION) & ELMC_REVISION_MASK;
  254 
  255         /* dump known info */
  256         printf("%s: rev %d, i/o %#04x-%#04x, mem %#06x-%#06x, %sternal xcvr\n",
  257                 sc->sc_dev.dv_xname, revision,
  258                 iobase, iobase + ELMC_IOADDR_SIZE - 1,
  259                 pbram_addr, pbram_addr + ELMC_MADDR_SIZE - 1,
  260                 (pos2 & 0x20) ? "ex" : "in");
  261 
  262         /*
  263          * Hardware ethernet address is stored in the first six bytes
  264          * of the IO space.
  265          */
  266         for(i=0; i < MIN(6, ETHER_ADDR_LEN); i++)
  267                 myaddr[i] = bus_space_read_1(asc->sc_regt, asc->sc_regh, i);
  268 
  269         printf("%s:", sc->sc_dev.dv_xname);
  270         i82586_attach((void *)sc, "3C523", myaddr, NULL, 0, 0);
  271 
  272         /* establish interrupt handler */
  273         asc->sc_ih = mca_intr_establish(ma->ma_mc, irq, IPL_NET, i82586_intr,
  274                         sc);
  275         if (asc->sc_ih == NULL) {
  276                 printf("%s: couldn't establish interrupt handler\n",
  277                        sc->sc_dev.dv_xname);
  278                 return;
  279         }
  280 }
  281 
  282 static void
  283 elmc_mca_copyin (sc, dst, offset, size)
  284         struct ie_softc *sc;
  285         void *dst;
  286         int offset;
  287         size_t size;
  288 {
  289         int dribble;
  290         u_int8_t* bptr = dst;
  291 
  292         bus_space_barrier(sc->bt, sc->bh, offset, size,
  293                           BUS_SPACE_BARRIER_READ);
  294 
  295         if (offset % 2) {
  296                 *bptr = bus_space_read_1(sc->bt, sc->bh, offset);
  297                 offset++; bptr++; size--;
  298         }
  299 
  300         dribble = size % 2;
  301         bus_space_read_region_2(sc->bt, sc->bh, offset, (u_int16_t *) bptr,
  302                                 size >> 1);
  303 
  304         if (dribble) {
  305                 bptr += size - 1;
  306                 offset += size - 1;
  307                 *bptr = bus_space_read_1(sc->bt, sc->bh, offset);
  308         }
  309 }
  310 
  311 static void
  312 elmc_mca_copyout (sc, src, offset, size)
  313         struct ie_softc *sc;
  314         const void *src;
  315         int offset;
  316         size_t size;
  317 {
  318         int dribble;
  319         int osize = size;
  320         int ooffset = offset;
  321         const u_int8_t* bptr = src;
  322 
  323         if (offset % 2) {
  324                 bus_space_write_1(sc->bt, sc->bh, offset, *bptr);
  325                 offset++; bptr++; size--;
  326         }
  327 
  328         dribble = size % 2;
  329         bus_space_write_region_2(sc->bt, sc->bh, offset, (u_int16_t *)bptr,
  330                                  size >> 1);
  331         if (dribble) {
  332                 bptr += size - 1;
  333                 offset += size - 1;
  334                 bus_space_write_1(sc->bt, sc->bh, offset, *bptr);
  335         }
  336 
  337         bus_space_barrier(sc->bt, sc->bh, ooffset, osize,
  338                           BUS_SPACE_BARRIER_WRITE);
  339 }
  340 
  341 static u_int16_t
  342 elmc_mca_read_16 (sc, offset)
  343         struct ie_softc *sc;
  344         int offset;
  345 {
  346         bus_space_barrier(sc->bt, sc->bh, offset, 2, BUS_SPACE_BARRIER_READ);
  347         return bus_space_read_2(sc->bt, sc->bh, offset);
  348 }
  349 
  350 static void
  351 elmc_mca_write_16 (sc, offset, value)
  352         struct ie_softc *sc;
  353         int offset;
  354         u_int16_t value;
  355 {
  356         bus_space_write_2(sc->bt, sc->bh, offset, value);
  357         bus_space_barrier(sc->bt, sc->bh, offset, 2, BUS_SPACE_BARRIER_WRITE);
  358 }
  359 
  360 static void
  361 elmc_mca_write_24 (sc, offset, addr)
  362         struct ie_softc *sc;
  363         int offset, addr;
  364 {
  365         bus_space_write_4(sc->bt, sc->bh, offset, addr +
  366                                 (u_long) sc->sc_maddr - (u_long) sc->sc_iobase);
  367         bus_space_barrier(sc->bt, sc->bh, offset, 4, BUS_SPACE_BARRIER_WRITE);
  368 }
  369 
  370 /*
  371  * Channel attention hook.
  372  */
  373 static void
  374 elmc_mca_attn(sc, why)
  375         struct ie_softc *sc;
  376         int why;
  377 {
  378     struct elmc_mca_softc* asc = (struct elmc_mca_softc *) sc;
  379     int intr = 0;
  380 
  381     switch (why) {
  382     case CHIP_PROBE:
  383         intr = 0;
  384         break;
  385     case CARD_RESET:
  386         intr = ELMC_CTRL_INT;
  387         break;
  388     }
  389 
  390     bus_space_write_1(asc->sc_regt, asc->sc_regh, ELMC_CTRL,
  391                 ELMC_CTRL_RST | ELMC_CTRL_BS3 | ELMC_CTRL_CHA | intr);
  392     delay(1);   /* should be > 500 ns */
  393     bus_space_write_1(asc->sc_regt, asc->sc_regh, ELMC_CTRL,
  394                 ELMC_CTRL_RST | ELMC_CTRL_BS3 | intr);
  395 }
  396 
  397 /*
  398  * Do full card hardware reset. 
  399  */
  400 static void
  401 elmc_mca_hwreset(sc, why)
  402         struct ie_softc *sc;
  403         int why;
  404 {
  405     struct elmc_mca_softc* asc = (struct elmc_mca_softc *) sc;
  406 
  407     /* toggle the RST bit low then high */
  408     bus_space_write_1(asc->sc_regt, asc->sc_regh, ELMC_CTRL,
  409                 ELMC_CTRL_BS3 | ELMC_CTRL_LOOP);
  410     delay(1);   /* should be > 500 ns */
  411     bus_space_write_1(asc->sc_regt, asc->sc_regh, ELMC_CTRL,
  412                 ELMC_CTRL_BS3 | ELMC_CTRL_LOOP | ELMC_CTRL_RST);
  413 
  414     elmc_mca_attn(sc, why);
  415 }
  416 
  417 /*
  418  * Interrupt hook.
  419  */
  420 static int
  421 elmc_mca_intrhook(sc, why)
  422         struct ie_softc *sc;
  423         int why;
  424 {
  425         switch (why) {
  426         case INTR_ACK:
  427                 elmc_mca_attn(sc, CHIP_PROBE);
  428                 break;
  429         default:
  430                 /* do nothing */
  431                 break;
  432         }
  433 
  434         return (0);
  435 }
  436 
  437 CFATTACH_DECL(elmc_mca, sizeof(struct elmc_mca_softc),
  438     elmc_mca_match, elmc_mca_attach, NULL, NULL);

Cache object: 31630b04260f94c5edd527f7793ed7de


[ 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.