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/pci/optiide.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: optiide.c,v 1.5 2004/01/03 22:56:53 thorpej Exp $      */
    2 
    3 /*-
    4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Steve C. Woodford.
    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 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 
   42 #include <dev/pci/pcivar.h>
   43 #include <dev/pci/pcidevs.h>
   44 #include <dev/pci/pciidereg.h>
   45 #include <dev/pci/pciidevar.h>
   46 #include <dev/pci/pciide_opti_reg.h>
   47 
   48 static void opti_chip_map(struct pciide_softc*, struct pci_attach_args*);
   49 static void opti_setup_channel(struct wdc_channel*);
   50 
   51 static int  optiide_match(struct device *, struct cfdata *, void *);
   52 static void optiide_attach(struct device *, struct device *, void *);
   53 
   54 CFATTACH_DECL(optiide, sizeof(struct pciide_softc),
   55     optiide_match, optiide_attach, NULL, NULL);
   56 
   57 static const struct pciide_product_desc pciide_opti_products[] =  {
   58         { PCI_PRODUCT_OPTI_82C621,
   59           0,
   60           "OPTi 82c621 PCI IDE controller",
   61           opti_chip_map,
   62         },
   63         { PCI_PRODUCT_OPTI_82C568,
   64           0,
   65           "OPTi 82c568 (82c621 compatible) PCI IDE controller",
   66           opti_chip_map,
   67         },
   68         { PCI_PRODUCT_OPTI_82D568,
   69           0,
   70           "OPTi 82d568 (82c621 compatible) PCI IDE controller",
   71           opti_chip_map,
   72         },
   73         { 0,
   74           0,
   75           NULL,
   76           NULL
   77         }
   78 };
   79 
   80 static int
   81 optiide_match(struct device *parent, struct cfdata *match, void *aux)
   82 {
   83         struct pci_attach_args *pa = aux;
   84 
   85         if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_OPTI &&
   86             PCI_CLASS(pa->pa_class) == PCI_CLASS_MASS_STORAGE &&
   87             PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_IDE) {
   88                 if (pciide_lookup_product(pa->pa_id, pciide_opti_products))
   89                         return (2);
   90         }
   91         return (0);
   92 }
   93 
   94 static void
   95 optiide_attach(struct device *parent, struct device *self, void *aux)
   96 {
   97         struct pci_attach_args *pa = aux;
   98         struct pciide_softc *sc = (struct pciide_softc *)self;
   99 
  100         pciide_common_attach(sc, pa,
  101             pciide_lookup_product(pa->pa_id, pciide_opti_products));
  102 
  103 }
  104 
  105 static void
  106 opti_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
  107 {
  108         struct pciide_channel *cp;
  109         bus_size_t cmdsize, ctlsize;
  110         pcireg_t interface;
  111         u_int8_t init_ctrl;
  112         int channel;
  113 
  114         if (pciide_chipen(sc, pa) == 0)
  115                 return;
  116 
  117         aprint_normal("%s: bus-master DMA support present",
  118             sc->sc_wdcdev.sc_dev.dv_xname);
  119 
  120         /*
  121          * XXXSCW:
  122          * There seem to be a couple of buggy revisions/implementations
  123          * of the OPTi pciide chipset. This kludge seems to fix one of
  124          * the reported problems (PR/11644) but still fails for the
  125          * other (PR/13151), although the latter may be due to other
  126          * issues too...
  127          */
  128         if (PCI_REVISION(pa->pa_class) <= 0x12) {
  129                 aprint_normal(" but disabled due to chip rev. <= 0x12");
  130                 sc->sc_dma_ok = 0;
  131         } else
  132                 pciide_mapreg_dma(sc, pa);
  133 
  134         aprint_normal("\n");
  135 
  136         sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA32 | WDC_CAPABILITY_DATA16 |
  137                 WDC_CAPABILITY_MODE;
  138         sc->sc_wdcdev.PIO_cap = 4;
  139         if (sc->sc_dma_ok) {
  140                 sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
  141                 sc->sc_wdcdev.irqack = pciide_irqack;
  142                 sc->sc_wdcdev.DMA_cap = 2;
  143         }
  144         sc->sc_wdcdev.set_modes = opti_setup_channel;
  145 
  146         sc->sc_wdcdev.channels = sc->wdc_chanarray;
  147         sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
  148 
  149         init_ctrl = pciide_pci_read(sc->sc_pc, sc->sc_tag,
  150             OPTI_REG_INIT_CONTROL);
  151 
  152         interface = PCI_INTERFACE(pa->pa_class);
  153 
  154         for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
  155                 cp = &sc->pciide_channels[channel];
  156                 if (pciide_chansetup(sc, channel, interface) == 0)
  157                         continue;
  158                 if (channel == 1 &&
  159                     (init_ctrl & OPTI_INIT_CONTROL_CH2_DISABLE) != 0) {
  160                         aprint_normal("%s: %s channel ignored (disabled)\n",
  161                             sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
  162                         cp->wdc_channel.ch_flags |= WDCF_DISABLED;
  163                         continue;
  164                 }
  165                 pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
  166                     pciide_pci_intr);
  167         }
  168 }
  169 
  170 static void
  171 opti_setup_channel(struct wdc_channel *chp)
  172 {
  173         struct ata_drive_datas *drvp;
  174         struct pciide_channel *cp = (struct pciide_channel*)chp;
  175         struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.ch_wdc;
  176         int drive, spd;
  177         int mode[2];
  178         u_int8_t rv, mr;
  179 
  180         /*
  181          * The `Delay' and `Address Setup Time' fields of the
  182          * Miscellaneous Register are always zero initially.
  183          */
  184         mr = opti_read_config(chp, OPTI_REG_MISC) & ~OPTI_MISC_INDEX_MASK;
  185         mr &= ~(OPTI_MISC_DELAY_MASK |
  186                 OPTI_MISC_ADDR_SETUP_MASK |
  187                 OPTI_MISC_INDEX_MASK);
  188 
  189         /* Prime the control register before setting timing values */
  190         opti_write_config(chp, OPTI_REG_CONTROL, OPTI_CONTROL_DISABLE);
  191 
  192         /* Determine the clockrate of the PCIbus the chip is attached to */
  193         spd = (int) opti_read_config(chp, OPTI_REG_STRAP);
  194         spd &= OPTI_STRAP_PCI_SPEED_MASK;
  195 
  196         /* setup DMA if needed */
  197         pciide_channel_dma_setup(cp);
  198 
  199         for (drive = 0; drive < 2; drive++) {
  200                 drvp = &chp->ch_drive[drive];
  201                 /* If no drive, skip */
  202                 if ((drvp->drive_flags & DRIVE) == 0) {
  203                         mode[drive] = -1;
  204                         continue;
  205                 }
  206 
  207                 if ((drvp->drive_flags & DRIVE_DMA)) {
  208                         /*
  209                          * Timings will be used for both PIO and DMA,
  210                          * so adjust DMA mode if needed
  211                          */
  212                         if (drvp->PIO_mode > (drvp->DMA_mode + 2))
  213                                 drvp->PIO_mode = drvp->DMA_mode + 2;
  214                         if (drvp->DMA_mode + 2 > (drvp->PIO_mode))
  215                                 drvp->DMA_mode = (drvp->PIO_mode > 2) ?
  216                                     drvp->PIO_mode - 2 : 0;
  217                         if (drvp->DMA_mode == 0)
  218                                 drvp->PIO_mode = 0;
  219 
  220                         mode[drive] = drvp->DMA_mode + 5;
  221                 } else
  222                         mode[drive] = drvp->PIO_mode;
  223 
  224                 if (drive && mode[0] >= 0 &&
  225                     (opti_tim_as[spd][mode[0]] != opti_tim_as[spd][mode[1]])) {
  226                         /*
  227                          * Can't have two drives using different values
  228                          * for `Address Setup Time'.
  229                          * Slow down the faster drive to compensate.
  230                          */
  231                         int d = (opti_tim_as[spd][mode[0]] >
  232                                  opti_tim_as[spd][mode[1]]) ?  0 : 1;
  233 
  234                         mode[d] = mode[1-d];
  235                         chp->ch_drive[d].PIO_mode = chp->ch_drive[1-d].PIO_mode;
  236                         chp->ch_drive[d].DMA_mode = 0;
  237                         chp->ch_drive[d].drive_flags &= ~DRIVE_DMA;
  238                 }
  239         }
  240 
  241         for (drive = 0; drive < 2; drive++) {
  242                 int m;
  243                 if ((m = mode[drive]) < 0)
  244                         continue;
  245 
  246                 /* Set the Address Setup Time and select appropriate index */
  247                 rv = opti_tim_as[spd][m] << OPTI_MISC_ADDR_SETUP_SHIFT;
  248                 rv |= OPTI_MISC_INDEX(drive);
  249                 opti_write_config(chp, OPTI_REG_MISC, mr | rv);
  250 
  251                 /* Set the pulse width and recovery timing parameters */
  252                 rv  = opti_tim_cp[spd][m] << OPTI_PULSE_WIDTH_SHIFT;
  253                 rv |= opti_tim_rt[spd][m] << OPTI_RECOVERY_TIME_SHIFT;
  254                 opti_write_config(chp, OPTI_REG_READ_CYCLE_TIMING, rv);
  255                 opti_write_config(chp, OPTI_REG_WRITE_CYCLE_TIMING, rv);
  256 
  257                 /* Set the Enhanced Mode register appropriately */
  258                 rv = pciide_pci_read(sc->sc_pc, sc->sc_tag, OPTI_REG_ENH_MODE);
  259                 rv &= ~OPTI_ENH_MODE_MASK(chp->ch_channel, drive);
  260                 rv |= OPTI_ENH_MODE(chp->ch_channel, drive, opti_tim_em[m]);
  261                 pciide_pci_write(sc->sc_pc, sc->sc_tag, OPTI_REG_ENH_MODE, rv);
  262         }
  263 
  264         /* Finally, enable the timings */
  265         opti_write_config(chp, OPTI_REG_CONTROL, OPTI_CONTROL_ENABLE);
  266 }

Cache object: 3f307f3cc75ccc4a88ac3652cc2f2eef


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