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/aceride.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: aceride.c,v 1.6 2004/01/03 22:56:53 thorpej Exp $      */
    2 
    3 /*
    4  * Copyright (c) 1999, 2000, 2001 Manuel Bouyer.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. All advertising materials mentioning features or use of this software
   15  *    must display the following acknowledgement:
   16  *      This product includes software developed by Manuel Bouyer.
   17  * 4. The name of the author may not be used to endorse or promote products
   18  *    derived from this software without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,     
   24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 
   35 #include <dev/pci/pcivar.h>
   36 #include <dev/pci/pcidevs.h>
   37 #include <dev/pci/pciidereg.h>
   38 #include <dev/pci/pciidevar.h>
   39 #include <dev/pci/pciide_acer_reg.h>
   40 
   41 static void acer_chip_map(struct pciide_softc*, struct pci_attach_args*);
   42 static void acer_setup_channel(struct wdc_channel*);
   43 static int  acer_pci_intr(void *);
   44 
   45 static int  aceride_match(struct device *, struct cfdata *, void *);
   46 static void aceride_attach(struct device *, struct device *, void *);
   47 
   48 CFATTACH_DECL(aceride, sizeof(struct pciide_softc),
   49     aceride_match, aceride_attach, NULL, NULL);
   50 
   51 static const struct pciide_product_desc pciide_acer_products[] =  {
   52         { PCI_PRODUCT_ALI_M5229,
   53           0,
   54           "Acer Labs M5229 UDMA IDE Controller",
   55           acer_chip_map,
   56         },
   57         { 0,
   58           0,
   59           NULL,
   60           NULL
   61         }
   62 };
   63 
   64 static int
   65 aceride_match(struct device *parent, struct cfdata *match, void *aux)
   66 {
   67         struct pci_attach_args *pa = aux;
   68 
   69         if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ALI &&
   70             PCI_CLASS(pa->pa_class) == PCI_CLASS_MASS_STORAGE &&
   71             PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_IDE) {
   72                 if (pciide_lookup_product(pa->pa_id, pciide_acer_products))
   73                         return (2);
   74         }
   75         return (0);
   76 }
   77 
   78 static void
   79 aceride_attach(struct device *parent, struct device *self, void *aux)
   80 {
   81         struct pci_attach_args *pa = aux;
   82         struct pciide_softc *sc = (struct pciide_softc *)self;
   83 
   84         pciide_common_attach(sc, pa,
   85             pciide_lookup_product(pa->pa_id, pciide_acer_products));
   86 
   87 }
   88 
   89 static void
   90 acer_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
   91 {
   92         struct pciide_channel *cp;
   93         int channel;
   94         pcireg_t cr, interface;
   95         bus_size_t cmdsize, ctlsize;
   96         pcireg_t rev = PCI_REVISION(pa->pa_class);
   97 
   98         if (pciide_chipen(sc, pa) == 0)
   99                 return;
  100 
  101         aprint_normal("%s: bus-master DMA support present",
  102             sc->sc_wdcdev.sc_dev.dv_xname);
  103         pciide_mapreg_dma(sc, pa);
  104         aprint_normal("\n");
  105         sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
  106             WDC_CAPABILITY_MODE;
  107         if (sc->sc_dma_ok) {
  108                 sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA;
  109                 if (rev >= 0x20) {
  110                         sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA;
  111                         if (rev >= 0xC4)
  112                                 sc->sc_wdcdev.UDMA_cap = 5;
  113                         else if (rev >= 0xC2)
  114                                 sc->sc_wdcdev.UDMA_cap = 4;
  115                         else
  116                                 sc->sc_wdcdev.UDMA_cap = 2;
  117                 }
  118                 sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
  119                 sc->sc_wdcdev.irqack = pciide_irqack;
  120         }
  121             
  122         sc->sc_wdcdev.PIO_cap = 4;
  123         sc->sc_wdcdev.DMA_cap = 2;
  124         sc->sc_wdcdev.set_modes = acer_setup_channel;
  125         sc->sc_wdcdev.channels = sc->wdc_chanarray;
  126         sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
  127 
  128         pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CDRC,
  129             (pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CDRC) |
  130                 ACER_CDRC_DMA_EN) & ~ACER_CDRC_FIFO_DISABLE);
  131 
  132         /* Enable "microsoft register bits" R/W. */
  133         pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CCAR3,
  134             pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CCAR3) | ACER_CCAR3_PI);
  135         pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CCAR1,
  136             pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CCAR1) &
  137             ~(ACER_CHANSTATUS_RO|PCIIDE_CHAN_RO(0)|PCIIDE_CHAN_RO(1)));
  138         pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CCAR2,
  139             pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CCAR2) &
  140             ~ACER_CHANSTATUSREGS_RO);
  141         cr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG);
  142         cr |= (PCIIDE_CHANSTATUS_EN << PCI_INTERFACE_SHIFT);
  143         pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG, cr);
  144         /* Don't use cr, re-read the real register content instead */
  145         interface = PCI_INTERFACE(pci_conf_read(sc->sc_pc, sc->sc_tag,
  146             PCI_CLASS_REG));
  147 
  148         /* From linux: enable "Cable Detection" */
  149         if (rev >= 0xC2) {
  150                 pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_0x4B,
  151                     pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_0x4B)
  152                     | ACER_0x4B_CDETECT);
  153         }
  154 
  155         for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
  156                 cp = &sc->pciide_channels[channel];
  157                 if (pciide_chansetup(sc, channel, interface) == 0)
  158                         continue;
  159                 if ((interface & PCIIDE_CHAN_EN(channel)) == 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                 /* newer controllers seems to lack the ACER_CHIDS. Sigh */
  166                 pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
  167                      (rev >= 0xC2) ? pciide_pci_intr : acer_pci_intr);
  168         }
  169 }
  170 
  171 static void
  172 acer_setup_channel(struct wdc_channel *chp)
  173 {
  174         struct ata_drive_datas *drvp;
  175         int drive;
  176         u_int32_t acer_fifo_udma;
  177         u_int32_t idedma_ctl;
  178         struct pciide_channel *cp = (struct pciide_channel*)chp;
  179         struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.ch_wdc;
  180 
  181         idedma_ctl = 0;
  182         acer_fifo_udma = pci_conf_read(sc->sc_pc, sc->sc_tag, ACER_FTH_UDMA);
  183         WDCDEBUG_PRINT(("acer_setup_channel: old fifo/udma reg 0x%x\n", 
  184             acer_fifo_udma), DEBUG_PROBE);
  185         /* setup DMA if needed */
  186         pciide_channel_dma_setup(cp);
  187 
  188         if ((chp->ch_drive[0].drive_flags | chp->ch_drive[1].drive_flags) &
  189             DRIVE_UDMA) { /* check 80 pins cable */
  190                 if (pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_0x4A) &
  191                     ACER_0x4A_80PIN(chp->ch_channel)) {
  192                         if (chp->ch_drive[0].UDMA_mode > 2)
  193                                 chp->ch_drive[0].UDMA_mode = 2;
  194                         if (chp->ch_drive[1].UDMA_mode > 2)
  195                                 chp->ch_drive[1].UDMA_mode = 2;
  196                 }
  197         }
  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                         continue;
  204                 WDCDEBUG_PRINT(("acer_setup_channel: old timings reg for "
  205                     "channel %d drive %d 0x%x\n", chp->ch_channel, drive,
  206                     pciide_pci_read(sc->sc_pc, sc->sc_tag,
  207                     ACER_IDETIM(chp->ch_channel, drive))), DEBUG_PROBE);
  208                 /* clear FIFO/DMA mode */
  209                 acer_fifo_udma &= ~(ACER_FTH_OPL(chp->ch_channel, drive, 0x3) |
  210                     ACER_UDMA_EN(chp->ch_channel, drive) |
  211                     ACER_UDMA_TIM(chp->ch_channel, drive, 0x7));
  212 
  213                 /* add timing values, setup DMA if needed */
  214                 if ((drvp->drive_flags & DRIVE_DMA) == 0 &&
  215                     (drvp->drive_flags & DRIVE_UDMA) == 0) {
  216                         acer_fifo_udma |=
  217                             ACER_FTH_OPL(chp->ch_channel, drive, 0x1);
  218                         goto pio;
  219                 }
  220 
  221                 acer_fifo_udma |= ACER_FTH_OPL(chp->ch_channel, drive, 0x2);
  222                 if (drvp->drive_flags & DRIVE_UDMA) {
  223                         /* use Ultra/DMA */
  224                         drvp->drive_flags &= ~DRIVE_DMA;
  225                         acer_fifo_udma |= ACER_UDMA_EN(chp->ch_channel, drive);
  226                         acer_fifo_udma |= 
  227                             ACER_UDMA_TIM(chp->ch_channel, drive,
  228                                 acer_udma[drvp->UDMA_mode]);
  229                         /* XXX disable if one drive < UDMA3 ? */
  230                         if (drvp->UDMA_mode >= 3) {
  231                                 pciide_pci_write(sc->sc_pc, sc->sc_tag,
  232                                     ACER_0x4B,
  233                                     pciide_pci_read(sc->sc_pc, sc->sc_tag,
  234                                         ACER_0x4B) | ACER_0x4B_UDMA66);
  235                         }
  236                 } else {
  237                         /*
  238                          * use Multiword DMA
  239                          * Timings will be used for both PIO and DMA,
  240                          * so adjust DMA mode if needed
  241                          */
  242                         if (drvp->PIO_mode > (drvp->DMA_mode + 2))
  243                                 drvp->PIO_mode = drvp->DMA_mode + 2;
  244                         if (drvp->DMA_mode + 2 > (drvp->PIO_mode))
  245                                 drvp->DMA_mode = (drvp->PIO_mode > 2) ?
  246                                     drvp->PIO_mode - 2 : 0;
  247                         if (drvp->DMA_mode == 0)
  248                                 drvp->PIO_mode = 0;
  249                 }
  250                 idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
  251 pio:            pciide_pci_write(sc->sc_pc, sc->sc_tag,
  252                     ACER_IDETIM(chp->ch_channel, drive),
  253                     acer_pio[drvp->PIO_mode]);
  254         }
  255         WDCDEBUG_PRINT(("acer_setup_channel: new fifo/udma reg 0x%x\n",
  256             acer_fifo_udma), DEBUG_PROBE);
  257         pci_conf_write(sc->sc_pc, sc->sc_tag, ACER_FTH_UDMA, acer_fifo_udma);
  258         if (idedma_ctl != 0) {
  259                 /* Add software bits in status register */
  260                 bus_space_write_1(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_CTL], 0,
  261                     idedma_ctl);
  262         }
  263 }
  264 
  265 static int
  266 acer_pci_intr(void *arg)
  267 {
  268         struct pciide_softc *sc = arg;
  269         struct pciide_channel *cp;
  270         struct wdc_channel *wdc_cp;
  271         int i, rv, crv; 
  272         u_int32_t chids;
  273 
  274         rv = 0;
  275         chids = pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CHIDS);
  276         for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
  277                 cp = &sc->pciide_channels[i];
  278                 wdc_cp = &cp->wdc_channel;
  279                 /* If a compat channel skip. */
  280                 if (cp->compat)
  281                         continue;
  282                 if (chids & ACER_CHIDS_INT(i)) {
  283                         crv = wdcintr(wdc_cp);
  284                         if (crv == 0)
  285                                 printf("%s:%d: bogus intr\n",
  286                                     sc->sc_wdcdev.sc_dev.dv_xname, i);
  287                         else
  288                                 rv = 1;
  289                 }
  290         }
  291         return rv;
  292 }

Cache object: edfe7f17db786032d013ed6911460ebe


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