From owner-svn-src-projects@FreeBSD.ORG Wed Jun 24 18:54:54 2009 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id E5874106566C; Wed, 24 Jun 2009 18:54:54 +0000 (UTC) (envelope-from lulf@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id D02DC8FC19; Wed, 24 Jun 2009 18:54:54 +0000 (UTC) (envelope-from lulf@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n5OIssBc025101; Wed, 24 Jun 2009 18:54:54 GMT (envelope-from lulf@svn.freebsd.org) Received: (from lulf@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n5OIssWP025091; Wed, 24 Jun 2009 18:54:54 GMT (envelope-from lulf@svn.freebsd.org) Message-Id: <200906241854.n5OIssWP025091@svn.freebsd.org> From: Ulf Lilleengen Date: Wed, 24 Jun 2009 18:54:54 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r194885 - in projects/libprocstat/sys: . arm/conf arm/mv arm/mv/discovery arm/mv/kirkwood arm/mv/orion cddl/dev/dtrace/amd64 compat/freebsd32 conf contrib/ngatm/netnatm/sig dev/ata dev/... X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2009 18:54:55 -0000 Author: lulf Date: Wed Jun 24 18:54:54 2009 New Revision: 194885 URL: http://svn.freebsd.org/changeset/base/194885 Log: - MFH Added: projects/libprocstat/sys/arm/mv/mv_sata.c - copied unchanged from r194883, head/sys/arm/mv/mv_sata.c Modified: projects/libprocstat/sys/ (props changed) projects/libprocstat/sys/arm/conf/DB-78XXX projects/libprocstat/sys/arm/conf/DB-88F5XXX projects/libprocstat/sys/arm/conf/DB-88F6XXX projects/libprocstat/sys/arm/mv/discovery/discovery.c projects/libprocstat/sys/arm/mv/files.mv projects/libprocstat/sys/arm/mv/kirkwood/kirkwood.c projects/libprocstat/sys/arm/mv/mvreg.h projects/libprocstat/sys/arm/mv/orion/orion.c projects/libprocstat/sys/cddl/dev/dtrace/amd64/dtrace_isa.c projects/libprocstat/sys/cddl/dev/dtrace/amd64/dtrace_subr.c projects/libprocstat/sys/compat/freebsd32/syscalls.master projects/libprocstat/sys/conf/files projects/libprocstat/sys/contrib/ngatm/netnatm/sig/sig_uni.c projects/libprocstat/sys/dev/ata/ata-all.h projects/libprocstat/sys/dev/ata/ata-dma.c projects/libprocstat/sys/dev/ata/ata-pci.h projects/libprocstat/sys/dev/ata/ata-sata.c projects/libprocstat/sys/dev/e1000/e1000_82540.c projects/libprocstat/sys/dev/e1000/e1000_82541.c projects/libprocstat/sys/dev/e1000/e1000_82571.c projects/libprocstat/sys/dev/e1000/e1000_82575.c projects/libprocstat/sys/dev/e1000/e1000_82575.h projects/libprocstat/sys/dev/e1000/e1000_api.c projects/libprocstat/sys/dev/e1000/e1000_defines.h projects/libprocstat/sys/dev/e1000/e1000_hw.h projects/libprocstat/sys/dev/e1000/e1000_ich8lan.c projects/libprocstat/sys/dev/e1000/e1000_ich8lan.h projects/libprocstat/sys/dev/e1000/e1000_mac.c projects/libprocstat/sys/dev/e1000/e1000_osdep.c projects/libprocstat/sys/dev/e1000/e1000_phy.c projects/libprocstat/sys/dev/e1000/e1000_phy.h projects/libprocstat/sys/dev/e1000/e1000_regs.h projects/libprocstat/sys/dev/e1000/if_em.c projects/libprocstat/sys/dev/e1000/if_em.h projects/libprocstat/sys/dev/e1000/if_igb.c projects/libprocstat/sys/dev/e1000/if_igb.h projects/libprocstat/sys/dev/ixgbe/ixgbe.c projects/libprocstat/sys/dev/ixgbe/ixgbe.h projects/libprocstat/sys/dev/ixgbe/ixgbe_82598.c projects/libprocstat/sys/dev/ixgbe/ixgbe_82599.c projects/libprocstat/sys/dev/ixgbe/ixgbe_api.c projects/libprocstat/sys/dev/ixgbe/ixgbe_api.h projects/libprocstat/sys/dev/ixgbe/ixgbe_common.c projects/libprocstat/sys/dev/ixgbe/ixgbe_osdep.h projects/libprocstat/sys/dev/ixgbe/ixgbe_phy.c projects/libprocstat/sys/dev/ixgbe/ixgbe_phy.h projects/libprocstat/sys/dev/ixgbe/ixgbe_type.h projects/libprocstat/sys/dev/mfi/mfi.c projects/libprocstat/sys/dev/mxge/if_mxge.c projects/libprocstat/sys/dev/sound/pci/hda/hdac.c projects/libprocstat/sys/dev/xen/netfront/ (props changed) projects/libprocstat/sys/dev/xen/xenpci/ (props changed) projects/libprocstat/sys/kern/kern_descrip.c projects/libprocstat/sys/kern/kern_vimage.c projects/libprocstat/sys/kern/makesyscalls.sh projects/libprocstat/sys/kern/subr_stack.c projects/libprocstat/sys/kern/syscalls.master projects/libprocstat/sys/kern/sysv_msg.c projects/libprocstat/sys/kern/sysv_sem.c projects/libprocstat/sys/kern/sysv_shm.c projects/libprocstat/sys/modules/dtrace/dtnfsclient/ (props changed) projects/libprocstat/sys/modules/igb/Makefile projects/libprocstat/sys/modules/ip6_mroute_mod/ (props changed) projects/libprocstat/sys/modules/ipmi/ipmi_linux/ (props changed) projects/libprocstat/sys/modules/ixgbe/Makefile projects/libprocstat/sys/netgraph/atm/uni/ng_uni.c projects/libprocstat/sys/netinet/if_ether.c projects/libprocstat/sys/netinet/ip_input.c projects/libprocstat/sys/netinet/ipfw/ip_dummynet.c (props changed) projects/libprocstat/sys/netinet/ipfw/ip_fw2.c (props changed) projects/libprocstat/sys/netinet/ipfw/ip_fw_pfil.c (props changed) projects/libprocstat/sys/netipx/ipx.c projects/libprocstat/sys/powerpc/mpc85xx/ds1553_bus_lbc.c projects/libprocstat/sys/rpc/rpcsec_gss/rpcsec_gss.c projects/libprocstat/sys/sparc64/sparc64/pmap.c projects/libprocstat/sys/sys/jail.h projects/libprocstat/sys/sys/stack.h Modified: projects/libprocstat/sys/arm/conf/DB-78XXX ============================================================================== --- projects/libprocstat/sys/arm/conf/DB-78XXX Wed Jun 24 18:50:41 2009 (r194884) +++ projects/libprocstat/sys/arm/conf/DB-78XXX Wed Jun 24 18:54:54 2009 (r194885) @@ -77,3 +77,7 @@ device da device iic device iicbus device ds133x + +# SATA +device ata +device atadisk Modified: projects/libprocstat/sys/arm/conf/DB-88F5XXX ============================================================================== --- projects/libprocstat/sys/arm/conf/DB-88F5XXX Wed Jun 24 18:50:41 2009 (r194884) +++ projects/libprocstat/sys/arm/conf/DB-88F5XXX Wed Jun 24 18:54:54 2009 (r194885) @@ -79,3 +79,7 @@ device umass device scbus device pass device da + +# SATA +device ata +device atadisk Modified: projects/libprocstat/sys/arm/conf/DB-88F6XXX ============================================================================== --- projects/libprocstat/sys/arm/conf/DB-88F6XXX Wed Jun 24 18:50:41 2009 (r194884) +++ projects/libprocstat/sys/arm/conf/DB-88F6XXX Wed Jun 24 18:54:54 2009 (r194885) @@ -76,3 +76,7 @@ device da # I2C (TWSI) device iic device iicbus + +# SATA +device ata +device atadisk Modified: projects/libprocstat/sys/arm/mv/discovery/discovery.c ============================================================================== --- projects/libprocstat/sys/arm/mv/discovery/discovery.c Wed Jun 24 18:50:41 2009 (r194884) +++ projects/libprocstat/sys/arm/mv/discovery/discovery.c Wed Jun 24 18:54:54 2009 (r194885) @@ -130,6 +130,11 @@ struct obio_device obio_devices[] = { { -1 }, { -1 }, CPU_PM_CTRL_NONE }, + { "sata", MV_SATAHC_BASE, MV_SATAHC_SIZE, + { MV_INT_SATA, -1 }, + { -1 }, + CPU_PM_CTRL_SATA0 | CPU_PM_CTRL_SATA1 + }, { NULL, 0, 0, { 0 }, { 0 }, 0 } }; Modified: projects/libprocstat/sys/arm/mv/files.mv ============================================================================== --- projects/libprocstat/sys/arm/mv/files.mv Wed Jun 24 18:50:41 2009 (r194884) +++ projects/libprocstat/sys/arm/mv/files.mv Wed Jun 24 18:54:54 2009 (r194885) @@ -24,6 +24,7 @@ arm/mv/gpio.c standard arm/mv/ic.c standard arm/mv/mv_machdep.c standard arm/mv/mv_pci.c optional pci +arm/mv/mv_sata.c optional ata | atamvsata arm/mv/obio.c standard arm/mv/timer.c standard arm/mv/twsi.c optional iicbus Modified: projects/libprocstat/sys/arm/mv/kirkwood/kirkwood.c ============================================================================== --- projects/libprocstat/sys/arm/mv/kirkwood/kirkwood.c Wed Jun 24 18:50:41 2009 (r194884) +++ projects/libprocstat/sys/arm/mv/kirkwood/kirkwood.c Wed Jun 24 18:54:54 2009 (r194885) @@ -99,6 +99,11 @@ struct obio_device obio_devices[] = { { -1 }, { -1 }, CPU_PM_CTRL_NONE }, + { "sata", MV_SATAHC_BASE, MV_SATAHC_SIZE, + { MV_INT_SATA, -1 }, + { -1 }, + CPU_PM_CTRL_SATA0 | CPU_PM_CTRL_SATA1 + }, { NULL, 0, 0, { 0 }, { 0 }, 0 } }; Copied: projects/libprocstat/sys/arm/mv/mv_sata.c (from r194883, head/sys/arm/mv/mv_sata.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/libprocstat/sys/arm/mv/mv_sata.c Wed Jun 24 18:54:54 2009 (r194885, copy of r194883, head/sys/arm/mv/mv_sata.c) @@ -0,0 +1,862 @@ +/*- + * Copyright (C) 2008-2009 Semihalf + * All rights reserved. + * + * Initial version developed by Ilya Bakulin. Full functionality and bringup + * by Piotr Ziecik. + * + * 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 AUTHOR 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 AUTHOR 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ata_if.h" + +#include "mvreg.h" +#include "mvvar.h" + +/* Useful macros */ +#define EDMA_TIMEOUT 100000 /* 100 ms */ +#define SATA_INL(sc, reg) ATA_INL((sc)->sc_mem_res, reg) +#define SATA_OUTL(sc, reg, val) ATA_OUTL((sc)->sc_mem_res, reg, val) + +/* HW-related data structures */ +struct sata_prdentry { + uint32_t prd_addrlo; + uint32_t prd_count; + uint32_t prd_addrhi; + uint32_t prd_reserved; +}; + +struct sata_crqb { + uint32_t crqb_prdlo; + uint32_t crqb_prdhi; + uint32_t crqb_flags; + uint16_t crqb_count; + uint16_t crqb_reserved1[2]; + uint8_t crqb_ata_command; + uint8_t crqb_ata_feature; + uint8_t crqb_ata_lba_low; + uint8_t crqb_ata_lba_mid; + uint8_t crqb_ata_lba_high; + uint8_t crqb_ata_device; + uint8_t crqb_ata_lba_low_p; + uint8_t crqb_ata_lba_mid_p; + uint8_t crqb_ata_lba_high_p; + uint8_t crqb_ata_feature_p; + uint8_t crqb_ata_count; + uint8_t crqb_ata_count_p; + uint16_t crqb_reserved2; +}; + +struct sata_crpb { + uint8_t crpb_tag; + uint8_t crpb_reserved; + uint8_t crpb_edma_status; + uint8_t crpb_dev_status; + uint32_t crpb_timestamp; +}; + +/* Identification section. */ +struct sata_softc { + device_t sc_dev; + unsigned int sc_version; + unsigned int sc_edma_qlen; + uint32_t sc_edma_reqis_mask; + uint32_t sc_edma_resos_mask; + struct resource *sc_mem_res; + bus_space_tag_t sc_mem_res_bustag; + bus_space_handle_t sc_mem_res_bushdl; + struct resource *sc_irq_res; + void *sc_irq_cookiep; + struct { + void (*function)(void *); + void *argument; + } sc_interrupt[SATA_CHAN_NUM]; +}; + +/* Controller functions */ +static int sata_probe(device_t dev); +static int sata_attach(device_t dev); +static int sata_detach(device_t dev); +static void sata_intr(void*); +static struct resource * sata_alloc_resource(device_t dev, device_t child, + int type, int *rid, u_long start, u_long end, u_long count, u_int flags); +static int sata_release_resource(device_t dev, device_t child, int type, + int rid, struct resource *r); +static int sata_setup_intr(device_t dev, device_t child, + struct resource *irq, int flags, driver_filter_t *filt, + driver_intr_t *function, void *argument, void **cookiep); +static int sata_teardown_intr(device_t dev, device_t child, + struct resource *irq, void *cookie); + +/* Channel functions */ +static int sata_channel_probe(device_t dev); +static int sata_channel_attach(device_t dev); +static int sata_channel_detach(device_t dev); +static int sata_channel_begin_transaction(struct ata_request *request); +static int sata_channel_end_transaction(struct ata_request *request); +static int sata_channel_status(device_t dev); +static void sata_channel_setmode(device_t parent, device_t dev); +static void sata_channel_reset(device_t dev); +static void sata_channel_dmasetprd(void *xsc, bus_dma_segment_t *segs, + int nsegs, int error); + +/* EDMA functions */ +static int sata_edma_ctrl(device_t dev, int on); +static int sata_edma_is_running(device_t); + +static device_method_t sata_methods[] = { + /* Device method */ + DEVMETHOD(device_probe, sata_probe), + DEVMETHOD(device_attach, sata_attach), + DEVMETHOD(device_detach, sata_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* ATA bus methods. */ + DEVMETHOD(bus_alloc_resource, sata_alloc_resource), + DEVMETHOD(bus_release_resource, sata_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_setup_intr, sata_setup_intr), + DEVMETHOD(bus_teardown_intr, sata_teardown_intr), + { 0, 0 }, +}; + +static driver_t sata_driver = { + "sata", + sata_methods, + sizeof(struct sata_softc), +}; + +devclass_t sata_devclass; + +DRIVER_MODULE(sata, mbus, sata_driver, sata_devclass, 0, 0); +MODULE_VERSION(sata, 1); +MODULE_DEPEND(sata, ata, 1, 1, 1); + +static int +sata_probe(device_t dev) +{ + struct sata_softc *sc; + uint32_t d, r; + + soc_id(&d, &r); + sc = device_get_softc(dev); + + /* No SATA controller on the 88F5281 SoC */ + if (d == MV_DEV_88F5281) + return (ENXIO); + + switch(d) { + case MV_DEV_88F5182: + sc->sc_version = 1; + sc->sc_edma_qlen = 128; + break; + case MV_DEV_88F6281: + case MV_DEV_MV78100: + case MV_DEV_MV78100_Z0: + sc->sc_version = 2; + sc->sc_edma_qlen = 32; + break; + default: + device_printf(dev, "unsupported SoC (ID: 0x%08X)!\n", d); + return (ENXIO); + } + + sc->sc_edma_reqis_mask = (sc->sc_edma_qlen - 1) << SATA_EDMA_REQIS_OFS; + sc->sc_edma_resos_mask = (sc->sc_edma_qlen - 1) << SATA_EDMA_RESOS_OFS; + + device_set_desc(dev, "Marvell Integrated SATA Controller"); + return (0); +} + +static int +sata_attach(device_t dev) +{ + struct sata_softc *sc; + int mem_id, irq_id, error, i; + device_t ata_chan; + uint32_t reg; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + mem_id = 0; + irq_id = 0; + + /* Allocate resources */ + sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &mem_id, RF_ACTIVE); + if (sc->sc_mem_res == NULL) { + device_printf(dev, "could not allocate memory.\n"); + return (ENOMEM); + } + + sc->sc_mem_res_bustag = rman_get_bustag(sc->sc_mem_res); + sc->sc_mem_res_bushdl = rman_get_bushandle(sc->sc_mem_res); + KASSERT(sc->sc_mem_res_bustag && sc->sc_mem_res_bushdl, + ("cannot get bus handle or tag.")); + + sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &irq_id, + RF_ACTIVE); + if (sc->sc_irq_res == NULL) { + device_printf(dev, "could not allocate IRQ.\n"); + error = ENOMEM; + goto err; + } + + error = bus_setup_intr(dev, sc->sc_irq_res, + INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY, + NULL, sata_intr, sc, &sc->sc_irq_cookiep); + if (error != 0) { + device_printf(dev, "could not setup interrupt.\n"); + goto err; + } + + /* Attach channels */ + for (i = 0; i < SATA_CHAN_NUM; i++) { + ata_chan = device_add_child(dev, "ata", + devclass_find_free_unit(ata_devclass, 0)); + + if (!ata_chan) { + device_printf(dev, "cannot add channel %d.\n", i); + error = ENOMEM; + goto err; + } + } + + /* Disable interrupt coalescing */ + reg = SATA_INL(sc, SATA_CR); + for (i = 0; i < SATA_CHAN_NUM; i++) + reg |= SATA_CR_COALDIS(i); + + /* Disable DMA byte swapping */ + if (sc->sc_version == 2) + reg |= SATA_CR_NODMABS | SATA_CR_NOEDMABS | + SATA_CR_NOPRDPBS; + + SATA_OUTL(sc, SATA_CR, reg); + + /* Clear and mask all interrupts */ + SATA_OUTL(sc, SATA_ICR, 0); + SATA_OUTL(sc, SATA_MIMR, 0); + + return(bus_generic_attach(dev)); + +err: + sata_detach(dev); + return (error); +} + +static int +sata_detach(device_t dev) +{ + struct sata_softc *sc; + + sc = device_get_softc(dev); + + if (device_is_attached(dev)) + bus_generic_detach(dev); + + if (sc->sc_mem_res != NULL) { + bus_release_resource(dev, SYS_RES_MEMORY, + rman_get_rid(sc->sc_mem_res), sc->sc_mem_res); + sc->sc_mem_res = NULL; + } + + if (sc->sc_irq_res != NULL) { + bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_cookiep); + bus_release_resource(dev, SYS_RES_IRQ, + rman_get_rid(sc->sc_irq_res), sc->sc_irq_res); + sc->sc_irq_res = NULL; + } + + return (0); +} + +static struct resource * +sata_alloc_resource(device_t dev, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct sata_softc *sc; + + sc = device_get_softc(dev); + + KASSERT(type == SYS_RES_IRQ && *rid == ATA_IRQ_RID, + ("illegal resource request (type %u, rid %u).", + type, *rid)); + + return (sc->sc_irq_res); +} + +static int +sata_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + + KASSERT(type == SYS_RES_IRQ && rid == ATA_IRQ_RID, + ("strange type %u and/or rid %u while releasing resource.", type, + rid)); + + return (0); +} + +static int +sata_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, + driver_filter_t *filt, driver_intr_t *function, void *argument, + void **cookiep) +{ + struct sata_softc *sc; + struct ata_channel *ch; + + sc = device_get_softc(dev); + ch = device_get_softc(child); + + if (filt != NULL) { + device_printf(dev, "filter interrupts are not supported.\n"); + return (EINVAL); + } + + sc->sc_interrupt[ch->unit].function = function; + sc->sc_interrupt[ch->unit].argument = argument; + *cookiep = sc; + + return (0); +} + +static int +sata_teardown_intr(device_t dev, device_t child, struct resource *irq, + void *cookie) +{ + struct sata_softc *sc; + struct ata_channel *ch; + + sc = device_get_softc(dev); + ch = device_get_softc(child); + + sc->sc_interrupt[ch->unit].function = NULL; + sc->sc_interrupt[ch->unit].argument = NULL; + + return (0); +} + +static void +sata_intr(void *xsc) +{ + struct sata_softc *sc; + int unit; + + sc = xsc; + + /* + * Behave like ata_generic_intr() for PCI controllers. + * Simply invoke ISRs on all channels. + */ + for (unit = 0; unit < SATA_CHAN_NUM; unit++) + if (sc->sc_interrupt[unit].function != NULL) + sc->sc_interrupt[unit].function( + sc->sc_interrupt[unit].argument); +} + +static int +sata_channel_probe(device_t dev) +{ + + device_set_desc(dev, "Marvell Integrated SATA Channel"); + return (ata_probe(dev)); +} + +static int +sata_channel_attach(device_t dev) +{ + struct sata_softc *sc; + struct ata_channel *ch; + uint64_t work; + int error, i; + + sc = device_get_softc(device_get_parent(dev)); + ch = device_get_softc(dev); + + if (ch->attached) + return (0); + + ch->dev = dev; + ch->unit = device_get_unit(dev); + ch->flags |= ATA_USE_16BIT | ATA_NO_SLAVE; + + /* Set legacy ATA resources. */ + for (i = ATA_DATA; i <= ATA_COMMAND; i++) { + ch->r_io[i].res = sc->sc_mem_res; + ch->r_io[i].offset = SATA_SHADOWR_BASE(ch->unit) + (i << 2); + } + + ch->r_io[ATA_CONTROL].res = sc->sc_mem_res; + ch->r_io[ATA_CONTROL].offset = SATA_SHADOWR_CONTROL(ch->unit); + + ch->r_io[ATA_IDX_ADDR].res = sc->sc_mem_res; + ata_default_registers(dev); + + /* Set SATA resources. */ + ch->r_io[ATA_SSTATUS].res = sc->sc_mem_res; + ch->r_io[ATA_SSTATUS].offset = SATA_SATA_SSTATUS(ch->unit); + ch->r_io[ATA_SERROR].res = sc->sc_mem_res; + ch->r_io[ATA_SERROR].offset = SATA_SATA_SERROR(ch->unit); + ch->r_io[ATA_SCONTROL].res = sc->sc_mem_res; + ch->r_io[ATA_SCONTROL].offset = SATA_SATA_SCONTROL(ch->unit); + ata_generic_hw(dev); + + ch->hw.begin_transaction = sata_channel_begin_transaction; + ch->hw.end_transaction = sata_channel_end_transaction; + ch->hw.status = sata_channel_status; + + /* Set DMA resources */ + ata_dmainit(dev); + ch->dma.setprd = sata_channel_dmasetprd; + + /* Clear work area */ + KASSERT(sc->sc_edma_qlen * (sizeof(struct sata_crqb) + + sizeof(struct sata_crpb)) <= ch->dma.max_iosize, + ("insufficient DMA memory for request/response queues.\n")); + bzero(ch->dma.work, sc->sc_edma_qlen * (sizeof(struct sata_crqb) + + sizeof(struct sata_crpb))); + bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + /* Turn off EDMA engine */ + error = sata_edma_ctrl(dev, 0); + if (error) { + ata_dmafini(dev); + return (error); + } + + /* + * Initialize EDMA engine: + * - Native Command Queuing off, + * - Non-Queued operation, + * - Host Queue Cache enabled. + */ + SATA_OUTL(sc, SATA_EDMA_CFG(ch->unit), SATA_EDMA_CFG_HQCACHE | + (sc->sc_version == 1) ? SATA_EDMA_CFG_QL128 : 0); + + /* Set request queue pointers */ + work = ch->dma.work_bus; + SATA_OUTL(sc, SATA_EDMA_REQBAHR(ch->unit), work >> 32); + SATA_OUTL(sc, SATA_EDMA_REQIPR(ch->unit), work & 0xFFFFFFFF); + SATA_OUTL(sc, SATA_EDMA_REQOPR(ch->unit), work & 0xFFFFFFFF); + + /* Set response queue pointers */ + work += sc->sc_edma_qlen * sizeof(struct sata_crqb); + SATA_OUTL(sc, SATA_EDMA_RESBAHR(ch->unit), work >> 32); + SATA_OUTL(sc, SATA_EDMA_RESIPR(ch->unit), work & 0xFFFFFFFF); + SATA_OUTL(sc, SATA_EDMA_RESOPR(ch->unit), work & 0xFFFFFFFF); + + /* Clear any outstanding interrupts */ + ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR)); + SATA_OUTL(sc, SATA_SATA_FISICR(ch->unit), 0); + SATA_OUTL(sc, SATA_EDMA_IECR(ch->unit), 0); + SATA_OUTL(sc, SATA_ICR, + ~(SATA_ICR_DEV(ch->unit) | SATA_ICR_DMADONE(ch->unit))); + + /* Umask channel interrupts */ + SATA_OUTL(sc, SATA_EDMA_IEMR(ch->unit), 0xFFFFFFFF); + SATA_OUTL(sc, SATA_MIMR, SATA_INL(sc, SATA_MIMR) | + SATA_MICR_DONE(ch->unit) | SATA_MICR_DMADONE(ch->unit) | + SATA_MICR_ERR(ch->unit)); + + ch->attached = 1; + + return (ata_attach(dev)); +} + +static int +sata_channel_detach(device_t dev) +{ + struct sata_softc *sc; + struct ata_channel *ch; + int error; + + sc = device_get_softc(device_get_parent(dev)); + ch = device_get_softc(dev); + + if (!ch->attached) + return (0); + + /* Turn off EDMA engine */ + sata_edma_ctrl(dev, 0); + + /* Mask chanel interrupts */ + SATA_OUTL(sc, SATA_EDMA_IEMR(ch->unit), 0); + SATA_OUTL(sc, SATA_MIMR, SATA_INL(sc, SATA_MIMR) & ~( + SATA_MICR_DONE(ch->unit) | SATA_MICR_DMADONE(ch->unit) | + SATA_MICR_ERR(ch->unit))); + + error = ata_detach(dev); + ata_dmafini(dev); + + ch->attached = 0; + + return (error); +} + +static int +sata_channel_begin_transaction(struct ata_request *request) +{ + struct sata_softc *sc; + struct ata_channel *ch; + struct sata_crqb *crqb; + uint32_t req_in; + int error, slot; + + sc = device_get_softc(GRANDPARENT(request->dev)); + ch = device_get_softc(request->parent); + + mtx_assert(&ch->state_mtx, MA_OWNED); + + /* Only DMA R/W goes through the EDMA machine. */ + if (request->u.ata.command != ATA_READ_DMA && + request->u.ata.command != ATA_WRITE_DMA) { + + /* Disable EDMA before accessing legacy registers */ + if (sata_edma_is_running(request->parent)) { + error = sata_edma_ctrl(request->parent, 0); + if (error) { + request->result = error; + return (ATA_OP_FINISHED); + } + } + + return (ata_begin_transaction(request)); + } + + /* Check for 48 bit access and convert if needed */ + ata_modify_if_48bit(request); + + /* Prepare data for DMA */ + if ((error = ch->dma.load(request, NULL, NULL))) { + device_printf(request->dev, "setting up DMA failed!\n"); + request->result = error; + return ATA_OP_FINISHED; + } + + /* Get next free queue slot */ + req_in = SATA_INL(sc, SATA_EDMA_REQIPR(ch->unit)); + slot = (req_in & sc->sc_edma_reqis_mask) >> SATA_EDMA_REQIS_OFS; + crqb = (struct sata_crqb *)(ch->dma.work + + (slot << SATA_EDMA_REQIS_OFS)); + + /* Fill in request */ + bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + crqb->crqb_prdlo = htole32((uint64_t)request->dma->sg_bus & 0xFFFFFFFF); + crqb->crqb_prdhi = htole32((uint64_t)request->dma->sg_bus >> 32); + crqb->crqb_flags = htole32((request->flags & ATA_R_READ ? 0x01 : 0x00) | + (request->tag << 1)); + + crqb->crqb_ata_command = request->u.ata.command; + crqb->crqb_ata_feature = request->u.ata.feature; + crqb->crqb_ata_lba_low = request->u.ata.lba; + crqb->crqb_ata_lba_mid = request->u.ata.lba >> 8; + crqb->crqb_ata_lba_high = request->u.ata.lba >> 16; + crqb->crqb_ata_device = ((request->u.ata.lba >> 24) & 0x0F) | (1 << 6); + crqb->crqb_ata_count = request->u.ata.count; + + bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + /* Enable EDMA if disabled */ + if (!sata_edma_is_running(request->parent)) { + error = sata_edma_ctrl(request->parent, 1); + if (error) { + ch->dma.unload(request); + request->result = error; + return (ATA_OP_FINISHED); + } + } + + /* Tell EDMA about new request */ + req_in = (req_in & ~sc->sc_edma_reqis_mask) | (((slot + 1) << + SATA_EDMA_REQIS_OFS) & sc->sc_edma_reqis_mask); + + SATA_OUTL(sc, SATA_EDMA_REQIPR(ch->unit), req_in); + + return (ATA_OP_CONTINUES); +} + +static int +sata_channel_end_transaction(struct ata_request *request) +{ + struct sata_softc *sc; + struct ata_channel *ch; + struct sata_crpb *crpb; + uint32_t res_in, res_out, icr; + int slot; + + sc = device_get_softc(GRANDPARENT(request->dev)); + ch = device_get_softc(request->parent); + + mtx_assert(&ch->state_mtx, MA_OWNED); + + icr = SATA_INL(sc, SATA_ICR); + if (icr & SATA_ICR_DMADONE(ch->unit)) { + /* Get current response slot */ + res_out = SATA_INL(sc, SATA_EDMA_RESOPR(ch->unit)); + slot = (res_out & sc->sc_edma_resos_mask) >> + SATA_EDMA_RESOS_OFS; + crpb = (struct sata_crpb *)(ch->dma.work + + (sc->sc_edma_qlen * sizeof(struct sata_crqb)) + + (slot << SATA_EDMA_RESOS_OFS)); + + /* Record this request status */ + bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + request->status = crpb->crpb_dev_status; + request->error = 0; + + bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + /* Update response queue pointer */ + res_out = (res_out & ~sc->sc_edma_resos_mask) | (((slot + 1) << + SATA_EDMA_RESOS_OFS) & sc->sc_edma_resos_mask); + + SATA_OUTL(sc, SATA_EDMA_RESOPR(ch->unit), res_out); + + /* Ack DMA interrupt if there is nothing more to do */ + res_in = SATA_INL(sc, SATA_EDMA_RESIPR(ch->unit)); + res_in &= sc->sc_edma_resos_mask; + res_out &= sc->sc_edma_resos_mask; + + if (res_in == res_out) + SATA_OUTL(sc, SATA_ICR, + ~SATA_ICR_DMADONE(ch->unit)); + + /* Update progress */ + if (!(request->status & ATA_S_ERROR) && + !(request->flags & ATA_R_TIMEOUT)) + request->donecount = request->bytecount; + + /* Unload DMA data */ + ch->dma.unload(request); + + return(ATA_OP_FINISHED); + } + + /* Legacy ATA interrupt */ + return (ata_end_transaction(request)); +} + +static int +sata_channel_status(device_t dev) +{ + struct sata_softc *sc; + struct ata_channel *ch; + uint32_t icr, iecr; + + sc = device_get_softc(device_get_parent(dev)); + ch = device_get_softc(dev); + + icr = SATA_INL(sc, SATA_ICR); + iecr = SATA_INL(sc, SATA_EDMA_IECR(ch->unit)); + + if ((icr & SATA_ICR_DEV(ch->unit)) || iecr) { + /* Disable EDMA before accessing SATA registers */ + sata_edma_ctrl(dev, 0); + ata_sata_phy_check_events(dev); + + /* Ack device and error interrupt */ + SATA_OUTL(sc, SATA_ICR, ~SATA_ICR_DEV(ch->unit)); + SATA_OUTL(sc, SATA_EDMA_IECR(ch->unit), 0); + } + + icr &= SATA_ICR_DEV(ch->unit) | SATA_ICR_DMADONE(ch->unit); + return (icr); +} + +static void +sata_channel_reset(device_t dev) +{ + struct sata_softc *sc; + struct ata_channel *ch; + + sc = device_get_softc(device_get_parent(dev)); + ch = device_get_softc(dev); + + /* Disable EDMA before using legacy registers */ + sata_edma_ctrl(dev, 0); + + /* Mask all EDMA interrups */ + SATA_OUTL(sc, SATA_EDMA_IEMR(ch->unit), 0); + + /* Reset EDMA */ + SATA_OUTL(sc, SATA_EDMA_CMD(ch->unit), SATA_EDMA_CMD_RESET); + DELAY(25); + SATA_OUTL(sc, SATA_EDMA_CMD(ch->unit), 0); + + /* Reset PHY and device */ + if (ata_sata_phy_reset(dev, -1, 1)) + ata_generic_reset(dev); + else + ch->devices = 0; + + /* Clear EDMA errors */ + SATA_OUTL(sc, SATA_SATA_FISICR(ch->unit), 0); + SATA_OUTL(sc, SATA_EDMA_IECR(ch->unit), 0); + + /* Unmask all EDMA interrups */ + SATA_OUTL(sc, SATA_EDMA_IEMR(ch->unit), 0xFFFFFFFF); +} + +static void +sata_channel_setmode(device_t parent, device_t dev) +{ + struct ata_device *atadev; + + atadev = device_get_softc(dev); + + /* Disable EDMA before using legacy registers */ + sata_edma_ctrl(parent, 0); + + ata_sata_setmode(dev, ATA_PIO_MAX); + if (atadev->mode >= ATA_DMA) + ata_sata_setmode(dev, atadev->mode); +} + +static void +sata_channel_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, + int error) +{ + struct ata_dmasetprd_args *args; + struct sata_prdentry *prd; + int i; + + args = xsc; + prd = args->dmatab; + + if ((args->error = error)) + return; + + for (i = 0; i < nsegs; i++) { + prd[i].prd_addrlo = htole32(segs[i].ds_addr); + prd[i].prd_addrhi = htole32((uint64_t)segs[i].ds_addr >> 32); + prd[i].prd_count = htole32(segs[i].ds_len); + } + + prd[i - 1].prd_count |= htole32(ATA_DMA_EOT); + KASSERT(nsegs <= ATA_DMA_ENTRIES, ("too many DMA segment entries.\n")); + args->nsegs = nsegs; +} + +static int +sata_edma_ctrl(device_t dev, int on) +{ + struct sata_softc *sc; + struct ata_channel *ch; + int bit, timeout; + uint32_t reg; + + sc = device_get_softc(device_get_parent(dev)); + ch = device_get_softc(dev); + bit = on ? SATA_EDMA_CMD_ENABLE : SATA_EDMA_CMD_DISABLE; + timeout = EDMA_TIMEOUT; + + SATA_OUTL(sc, SATA_EDMA_CMD(ch->unit), bit); + + while (1) { + DELAY(1); + + reg = SATA_INL(sc, SATA_EDMA_CMD(ch->unit)); + + /* Enable bit will be 1 after disable command completion */ + if (on && (reg & SATA_EDMA_CMD_ENABLE)) + break; + + /* Disable bit will be 0 after disable command completion */ + if (!on && !(reg & SATA_EDMA_CMD_DISABLE)) + break; + + if (timeout-- <= 0) { + device_printf(dev, "EDMA command timeout!\n"); + return (ETIMEDOUT); + } + } + + return (0); +} + +static int +sata_edma_is_running(device_t dev) +{ + struct sata_softc *sc; + struct ata_channel *ch; + + sc = device_get_softc(device_get_parent(dev)); + ch = device_get_softc(dev); + + return (SATA_INL(sc, SATA_EDMA_CMD(ch->unit)) & SATA_EDMA_CMD_ENABLE); +} + +static device_method_t sata_channel_methods[] = { + /* Device interface. */ + DEVMETHOD(device_probe, sata_channel_probe), + DEVMETHOD(device_attach, sata_channel_attach), + DEVMETHOD(device_detach, sata_channel_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, ata_suspend), + DEVMETHOD(device_resume, ata_resume), + + /* ATA channel interface */ + DEVMETHOD(ata_reset, sata_channel_reset), + DEVMETHOD(ata_setmode, sata_channel_setmode), + { 0, 0 } +}; + +driver_t sata_channel_driver = { + "ata", + sata_channel_methods, + sizeof(struct ata_channel), +}; + +DRIVER_MODULE(ata, sata, sata_channel_driver, ata_devclass, 0, 0); Modified: projects/libprocstat/sys/arm/mv/mvreg.h ============================================================================== --- projects/libprocstat/sys/arm/mv/mvreg.h Wed Jun 24 18:50:41 2009 (r194884) +++ projects/libprocstat/sys/arm/mv/mvreg.h Wed Jun 24 18:54:54 2009 (r194885) @@ -274,6 +274,75 @@ #define CPU_TIMER0 0x14 /* + * SATA + */ +#define SATA_CHAN_NUM 2 + +#define EDMA_REGISTERS_OFFSET 0x2000 +#define EDMA_REGISTERS_SIZE 0x2000 +#define SATA_EDMA_BASE(ch) (EDMA_REGISTERS_OFFSET + \ + ((ch) * EDMA_REGISTERS_SIZE)) + +/* SATAHC registers */ +#define SATA_CR 0x000 /* Configuration Reg. */ +#define SATA_CR_NODMABS (1 << 8) +#define SATA_CR_NOEDMABS (1 << 9) +#define SATA_CR_NOPRDPBS (1 << 10) +#define SATA_CR_COALDIS(ch) (1 << (24 + ch)) + +#define SATA_ICR 0x014 /* Interrupt Cause Reg. */ +#define SATA_ICR_DMADONE(ch) (1 << (ch)) +#define SATA_ICR_COAL (1 << 4) +#define SATA_ICR_DEV(ch) (1 << (8 + ch)) + +#define SATA_MICR 0x020 /* Main Interrupt Cause Reg. */ +#define SATA_MICR_ERR(ch) (1 << (2 * ch)) +#define SATA_MICR_DONE(ch) (1 << ((2 * ch) + 1)) +#define SATA_MICR_DMADONE(ch) (1 << (4 + ch)) +#define SATA_MICR_COAL (1 << 8) + +#define SATA_MIMR 0x024 /* Main Interrupt Mask Reg. */ + +/* Shadow registers */ +#define SATA_SHADOWR_BASE(ch) (SATA_EDMA_BASE(ch) + 0x100) +#define SATA_SHADOWR_CONTROL(ch) (SATA_EDMA_BASE(ch) + 0x120) + +/* SATA registers */ +#define SATA_SATA_SSTATUS(ch) (SATA_EDMA_BASE(ch) + 0x300) +#define SATA_SATA_SERROR(ch) (SATA_EDMA_BASE(ch) + 0x304) +#define SATA_SATA_SCONTROL(ch) (SATA_EDMA_BASE(ch) + 0x308) +#define SATA_SATA_FISICR(ch) (SATA_EDMA_BASE(ch) + 0x364) + +/* EDMA registers */ +#define SATA_EDMA_CFG(ch) (SATA_EDMA_BASE(ch) + 0x000) +#define SATA_EDMA_CFG_QL128 (1 << 19) +#define SATA_EDMA_CFG_HQCACHE (1 << 22) + +#define SATA_EDMA_IECR(ch) (SATA_EDMA_BASE(ch) + 0x008) + +#define SATA_EDMA_IEMR(ch) (SATA_EDMA_BASE(ch) + 0x00C) +#define SATA_EDMA_REQBAHR(ch) (SATA_EDMA_BASE(ch) + 0x010) +#define SATA_EDMA_REQIPR(ch) (SATA_EDMA_BASE(ch) + 0x014) +#define SATA_EDMA_REQOPR(ch) (SATA_EDMA_BASE(ch) + 0x018) +#define SATA_EDMA_RESBAHR(ch) (SATA_EDMA_BASE(ch) + 0x01C) +#define SATA_EDMA_RESIPR(ch) (SATA_EDMA_BASE(ch) + 0x020) +#define SATA_EDMA_RESOPR(ch) (SATA_EDMA_BASE(ch) + 0x024) + +#define SATA_EDMA_CMD(ch) (SATA_EDMA_BASE(ch) + 0x028) +#define SATA_EDMA_CMD_ENABLE (1 << 0) +#define SATA_EDMA_CMD_DISABLE (1 << 1) +#define SATA_EDMA_CMD_RESET (1 << 2) + +#define SATA_EDMA_STATUS(ch) (SATA_EDMA_BASE(ch) + 0x030) +#define SATA_EDMA_STATUS_IDLE (1 << 7) *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***