NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/42100: Old Toshiba Notebooks: bus-master DMA support present, but unused (no driver support)



>Number:         42100
>Category:       kern
>Synopsis:       Old Toshiba Notebooks: bus-master DMA support present, but 
>unused (no driver support)
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sun Sep 20 00:45:01 +0000 2009
>Originator:     Dave J. Barnes
>Release:        NetBSD 5.0.1
>Organization:
Eng Consultant
>Environment:
NetBSD orbit 5.0.1 NetBSD 5.0.1 (GENERIC) #0: Thu Jul 30 01:39:11 UTC 2009  
builds%b8.netbsd.org@localhost:/home/builds/ab/netbsd-5-0-1-RELEASE/i386/200907292356Z-obj/home/builds/ab/netbsd-5-0-1-RELEASE/src/sys/arch/i386/compile/GENERIC
 i386

>Description:
pciide0 at pci0 dev 16 function 0
pciide0: Toshiba product 0x0102 (rev. 0x34)
pciide0: bus-master DMA support present, but unused (no driver support)
...
wd0 at atabus0 drive 0: <FUJITSU MHK2120AT>
wd0: drive supports 16-sector PIO transfers, LBA addressing
wd0: 11513 MB, 23392 cyl, 16 head, 63 sec, 512 bytes/sect x 23579136 sectors
wd0: drive supports PIO mode 4, DMA mode 2, Ultra-DMA mode 4 (Ultra/66)

Older Toshiba Satellite 2180CDT, AMD K6-2 laptop
For Toshiba, pci vendor 0x1179, ata devices 0x0101, 0x0102, 0x0103, and
0x0105, DMA support is present but not being used by current drivers.



>How-To-Repeat:
GENERIC kernel:

root@orbit:/root # dd if=/dev/wd0d of=/dev/null bs=1m count=100
100+0 records in
100+0 records out
104857600 bytes transferred in 34.997 secs (2996188 bytes/sec)

Slow, and takes a lot of CPU.

patched kernel with new toshide front-end to pciide:

root@orbit:/root # dd if=/dev/wd0d of=/dev/null bs=1m count=100
100+0 records in
100+0 records out
104857600 bytes transferred in 14.095 secs (7439347 bytes/sec)

Takes very little CPU.

Partial DMESG with new driver plus source files attached.

DMESG:
Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
    2006, 2007, 2008, 2009
    The NetBSD Foundation, Inc.  All rights reserved.
Copyright (c) 1982, 1986, 1989, 1991, 1993
    The Regents of the University of California.  All rights reserved.

NetBSD 5.0.1 (i386/DJB-laptop 2009/08/26) #40: Sat Sep 19 14:08:26 CDT 2009
        root@Shakeys:/Shakeys/NetBSD/src/usr/src/sys/arch/i386/compile/DJB
total memory = 319 MB
avail memory = 310 MB
timecounter: Timecounters tick every 10.000 msec
timecounter: Timecounter "i8254" frequency 1193182 Hz quality 100
TOSHIBA SATELLITE 2180CDT (Version 1.0)
mainbus0 (root)
cpu0 at mainbus0: AMD 586-class, 474MHz, id 0x58c
acpi0 at mainbus0: Intel ACPICA 20080321
acpi0: X/RSDT: OemId <TOSHIB,750     ,19980710>, AslId <TASM,04010000>
...
toshide0 at pci0 dev 16 function 0
toshide0: Toshiba Piccolo 2 IDE controller (rev. 0x34)
toshide0: bus-master DMA support present
toshide0: primary channel wired to compatibility mode
toshide0: primary channel interrupting at irq 14
...
wd0 at atabus0 drive 0: <FUJITSU MHK2120AT>
wd0: drive supports 16-sector PIO transfers, LBA addressing
wd0: 11513 MB, 23392 cyl, 16 head, 63 sec, 512 bytes/sect x 23579136 sectors
wd0: 32-bit data port
wd0: drive supports PIO mode 4, DMA mode 2, Ultra-DMA mode 4 (Ultra/66)
toshide0: UDMA want 82000000, set 92000000, got 12000000 
wd0(toshide0:0:0): using PIO mode 4, Ultra-DMA mode 2 (Ultra/33) (using DMA)


PCICTL PCI Device List:
000:00:0: Toshiba product 0x0618 (host bridge, revision 0x02)
000:08:0: S3 ViRGE/MX (VGA display, revision 0x06)
000:11:0: NEC USB Host Controller (USB serial bus, interface 0x10, revision 
0x02)
000:12:0: ESS Technology Maestro 2E PCI Audio Accelerator (audio multimedia, 
revision 0x10)
000:16:0: Toshiba product 0x0102 (IDE mass storage, interface 0xf0, revision 
0x34)
000:19:0: Toshiba ToPIC97 PCI-CardBus Bridge (CardBus bridge, revision 0x07)
000:19:1: Toshiba ToPIC97 PCI-CardBus Bridge (CardBus bridge, revision 0x07)

>Fix:
(1) Add to dev/pci/files.pci
--------------------------------
# Toshiba PICCOLO IDE controllers
device  toshide: ata, ata_dma, pciide_common, wdc_common
attach  toshide at pci
file    dev/pci/toshide.c               toshide

(2)Add Toshiba IDE controller products to dev/pci/pcidevs
(NOTE: SanRemo may be the code name for Toshiba product 0x0618)
-------------------------------- 
--- dev/pci/pcidevs.orig        2009-09-16 14:16:29.000000000 -0500
+++ dev/pci/pcidevs     2009-09-18 22:59:10.000000000 -0500
@@ -3836,11 +3836,16 @@
 
 /* Toshiba products */
 product TOSHIBA2 PORTEGE       0x0001  Portege Notebook
+product TOSHIBA2 PICCOLO        0x0101  Piccolo IDE Controller
+product TOSHIBA2 PICCOLO2       0x0102  Piccolo 2 IDE Controller
+product TOSHIBA2 PICCOLO3       0x0103  Piccolo 3 IDE Controller
+product TOSHIBA2 PICCOLO5       0x0105  Piccolo 5 IDE Controller
 product TOSHIBA2 HOST          0x0601  Host Bridge/Controller
 product TOSHIBA2 ISA           0x0602  PCI-ISA Bridge
 product TOSHIBA2 ToPIC95       0x0603  ToPIC95 PCI-CardBus Bridge
 product TOSHIBA2 ToPIC95B      0x060a  ToPIC95B PCI-CardBus Bridge
 product TOSHIBA2 ToPIC97       0x060f  ToPIC97 PCI-CardBus Bridge
+product TOSHIBA2 SANREMO       0x0618  SanRemo? Triangle Host Bridge
 product TOSHIBA2 SMCARD                0x0804  Smart Media Controller
 product TOSHIBA2 SDCARD                0x0805  Secure Digital Card Controller 
Type-A
 product TOSHIBA2 ToPIC100      0x0617  ToPIC100 PCI-CardBus Bridge

(3) Add file dev/pci/pciide_piccolo_reg.h
(Yes, most of this discovered by poking around and making educated guesses.)
---------------------------
/*      $NetBSD: pciide_piccolo.h_reg.h,v 1.0 2008/04/28 00:00:00 djb   */

/*
 * Copyright (c) 2002 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Register definitions for the Toshiba PICCOLO, by SWAG!
 */

#define PICCOLO_PIO_TIMING 0x50
#define PICCOLO_DMA_TIMING 0x5c

#define PICCOLO_PIO_MASK 0xffffe088
#define PICCOLO_DMA_MASK 0xffffe088
#define PICCOLO_UDMA_MASK 0x78ffe088

/* TIMING SWAG!!! */

/* 
 * first digit is command active, next two are front porch and back porch 
 * command active >= minimum for mode 
 * front porch + back porch + command active >= cycle time for mode
 * values below may need adjustment 
 */
static const u_int32_t piccolo_pio_times[]
    __unused = {
/*        programmed               actual       */
        0x0566,             
        0x0433,
        0x0311,
        0x0201,
        0x0200,         /* PIO 4, 150ns cycle (120ns is spec), 90ns command 
active (70ns is spec), 30ns setup and hold */
        0x0100
           
};

static const u_int32_t piccolo_sw_dma_times[]
    __unused = {
/*        programmed               actual       */
        0x0f77          
};

static const u_int32_t piccolo_mw_dma_times[]
     __unused = {
/*        programmed               actual       */
        0x0655,
        0x0200,
        0x0200,
        0x0100 
};

/* XXX Is MSB UDMA enable? Can't set it. Seems to work without being set. */
static const u_int32_t piccolo_udma_times[]
    __unused = {
/*        programmed               actual       */
        0x84000222,
        0x83000111,
        0x82000000      /* UDMA 2, 120ns cycle (117ns is spec), 60ns command 
active (55ns is spec), 30ns setup and hold */  
};
-----------------------------------

(4) New file, dev/pci/toshide.c
(Since this is a random hack on a sample size of one Toshiba IDE controller 
YMMV big time.)
--------------------------------
/*      $NetBSD: toshide.c,v 1.0 2009/09/16 00:00:00 djb Exp $  */

/*-
 * Copyright (c) 2002 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: toshide.c,v 1.0 2009/09/16 00:00:00 djb Exp $");

#include <sys/param.h>
#include <sys/systm.h>

#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
#include <dev/pci/pciidereg.h>
#include <dev/pci/pciidevar.h>
#include <dev/pci/pciide_piccolo_reg.h>

static void piccolo_chip_map(struct pciide_softc*, struct pci_attach_args*);
static void piccolo_setup_channel(struct ata_channel*);

static int  piccolo_match(device_t, cfdata_t, void *);
static void piccolo_attach(device_t, device_t, void *);

CFATTACH_DECL_NEW(toshide, sizeof(struct pciide_softc),
    piccolo_match, piccolo_attach, NULL, NULL);

static const struct pciide_product_desc pciide_toshiba2_products[] = {
        { PCI_PRODUCT_TOSHIBA2_PICCOLO,
          0,
          "Toshiba Piccolo IDE controller",
          piccolo_chip_map,
        },
        { PCI_PRODUCT_TOSHIBA2_PICCOLO2,
          0,
          "Toshiba Piccolo 2 IDE controller",
          piccolo_chip_map,
        },
        { PCI_PRODUCT_TOSHIBA2_PICCOLO3,
          0,
          "Toshiba Piccolo 3 IDE controller",
          piccolo_chip_map,
        },
        { PCI_PRODUCT_TOSHIBA2_PICCOLO5,
          0,
          "Toshiba Piccolo 5 IDE controller",
          piccolo_chip_map,
        },
        { 0,
          0,
          NULL,
          NULL,
        }
};

static int
piccolo_match(device_t parent, cfdata_t match, void *aux)
{
        struct pci_attach_args *pa = aux;

        if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_TOSHIBA2) {
                if (pciide_lookup_product(pa->pa_id, pciide_toshiba2_products))
                        return (2);
        }
        return (0);
}

static void
piccolo_attach(device_t parent, device_t self, void *aux)
{
        struct pci_attach_args *pa = aux;
        struct pciide_softc *sc = device_private(self);
        const struct pciide_product_desc *pp = NULL;

        sc->sc_wdcdev.sc_atac.atac_dev = self;

        if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_TOSHIBA2)
                pp = pciide_lookup_product(pa->pa_id, pciide_toshiba2_products);
        if (pp == NULL)
                panic("toshide_attach");
        pciide_common_attach(sc, pa, pp);
}

static void
piccolo_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
{
        struct pciide_channel *cp;
        bus_size_t cmdsize, ctlsize;
        pcireg_t interface;
        int channel;

        if (pciide_chipen(sc, pa) == 0)
                return;

        aprint_verbose_dev(sc->sc_wdcdev.sc_atac.atac_dev,
            "bus-master DMA support present");

        pciide_mapreg_dma(sc, pa);
        aprint_verbose("\n");

        sc->sc_wdcdev.sc_atac.atac_cap = ATAC_CAP_DATA32 | ATAC_CAP_DATA16;
        sc->sc_wdcdev.sc_atac.atac_pio_cap = 5;

        if (sc->sc_dma_ok) {
                sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DMA | ATAC_CAP_UDMA;
                sc->sc_wdcdev.irqack = pciide_irqack;
                sc->sc_wdcdev.sc_atac.atac_dma_cap = 3;
                sc->sc_wdcdev.sc_atac.atac_udma_cap = 2;
        }

        sc->sc_wdcdev.sc_atac.atac_set_modes = piccolo_setup_channel;

        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
        /* 
         * XXX one for now. We'll figure out how to talk to the second channel 
later, hopefully!
         * Second interface config is via the "alternate PCI Configuration 
Space" whatever that is!
         */

        interface = PCI_INTERFACE(pa->pa_class);

        wdc_allocate_regs(&sc->sc_wdcdev);

        for (channel = 0; channel < sc->sc_wdcdev.sc_atac.atac_nchannels;
             channel++) {
                cp = &sc->pciide_channels[channel];
                if (pciide_chansetup(sc, channel, interface) == 0)
                        continue;

                pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
                    pciide_pci_intr);
        }
}

static void
piccolo_setup_channel(struct ata_channel *chp)
{
        struct ata_drive_datas *drvp;
        struct pciide_channel *cp = CHAN_TO_PCHAN(chp);
        struct pciide_softc *sc = CHAN_TO_PCIIDE(chp);
        u_int32_t idedma_ctl;
        int drive, s;
        pcireg_t pxdx,pxdx_prime;

        idedma_ctl = 0;

        /* Set up DMA if needed. */
        pciide_channel_dma_setup(cp);

        for (drive = 0; drive < 2; drive++) {

                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
                if ((drvp->drive_flags & DRIVE) == 0)
                        continue;

                if (drvp->drive_flags & DRIVE_UDMA) {
                        /* use Ultra/DMA */
                        s = splbio();
                        drvp->drive_flags &= ~DRIVE_DMA;
                        splx(s);

                        /*
                         * Use UDMA - we can go up to mode 2 so no need to 
check anything
                         * since nearly all drives with UDMA are mode 2 or 
faster 
                         */
                        pxdx = pci_conf_read(sc->sc_pc, sc->sc_tag, 
PICCOLO_DMA_TIMING);
                        pxdx &= PICCOLO_UDMA_MASK;
                        pxdx |= piccolo_udma_times[2];
                        pci_conf_write(sc->sc_pc, sc->sc_tag, 
PICCOLO_DMA_TIMING, pxdx);
/* XXX sanity check */
                        pxdx_prime = pci_conf_read(sc->sc_pc, sc->sc_tag, 
PICCOLO_DMA_TIMING);
                        aprint_verbose_dev(sc->sc_wdcdev.sc_atac.atac_dev,
                            "UDMA want %x, set %x, got %x \n", 
piccolo_udma_times[2], pxdx, pxdx_prime);

                        idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);

                }
                else if (drvp->drive_flags & DRIVE_DMA) {
                        /*
                         * Use Multiword DMA
                         */
                        if (drvp->PIO_mode > (drvp->DMA_mode + 2))
                                drvp->PIO_mode = drvp->DMA_mode + 2;
                        if (drvp->DMA_mode + 2 > (drvp->PIO_mode))
                                drvp->DMA_mode = (drvp->PIO_mode > 2) ?
                                    drvp->PIO_mode - 2 : 0;

                        pxdx = pci_conf_read(sc->sc_pc, sc->sc_tag, 
PICCOLO_DMA_TIMING);
                        pxdx &= PICCOLO_DMA_MASK;
                        pxdx |= piccolo_mw_dma_times[drvp->DMA_mode];
                        pci_conf_write(sc->sc_pc, sc->sc_tag, 
PICCOLO_DMA_TIMING, pxdx);
/* XXX sanity check */
                        pxdx_prime = pci_conf_read(sc->sc_pc, sc->sc_tag, 
PICCOLO_DMA_TIMING);
                        aprint_verbose_dev(sc->sc_wdcdev.sc_atac.atac_dev,
                            "DMA %d want %x, set %x, got %x \n", 
drvp->DMA_mode, piccolo_mw_dma_times[drvp->DMA_mode], pxdx, pxdx_prime);

                        idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);

                }
                else {
                
                        pxdx = pci_conf_read(sc->sc_pc, sc->sc_tag, 
PICCOLO_PIO_TIMING);
                        pxdx &= PICCOLO_PIO_MASK;
                        pxdx |= piccolo_pio_times[drvp->PIO_mode];
                        pci_conf_write(sc->sc_pc, sc->sc_tag, 
PICCOLO_PIO_TIMING, pxdx);
/* XXX sanity check */
                        pxdx_prime = pci_conf_read(sc->sc_pc, sc->sc_tag, 
PICCOLO_PIO_TIMING);
                        aprint_verbose_dev(sc->sc_wdcdev.sc_atac.atac_dev,
                            "PIO %d want %x, set %x, got %x \n", 
drvp->PIO_mode, piccolo_pio_times[drvp->PIO_mode], pxdx, pxdx_prime);
                
                }

        }
        if (idedma_ctl != 0) {
                /* Add software bits in status register */
                bus_space_write_1(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_CTL], 0,
                    idedma_ctl);
        }
        
}
-------------------------------------------------------------------

(5) Limitations
- I don't know how to configure the second interface channel since the
PCI Configuration Space for Channel 2 is separate.  The CDROM drive
in the Toshiba Satellite I have was thrown away long ago.  I don't know
if the BIOS will enable the second channel automatically if a device is 
attached or not.  Would that give the device a second function and second 
configuration space?
- What I think is the UDMA enable bit will not set. If the interface is using 
DMA mode 2 instead of UDMA mode 2, then I don't see how it works with the wrong 
timing values for DMA mode 2. (000 instead of 0x200)  That's the reason for the 
"XXX sanity Check" in the code.

==========

djb



Home | Main Index | Thread Index | Old Index