siisata_pci.c revision 1.2
11.2Sjakllsch/* $NetBSD: siisata_pci.c,v 1.2 2008/12/16 02:46:47 jakllsch Exp $ */
21.1Sjnemeth/* Id: siisata_pci.c,v 1.11 2008/05/21 16:20:11 jakllsch Exp  */
31.1Sjnemeth
41.1Sjnemeth/*
51.1Sjnemeth * Copyright (c) 2006 Manuel Bouyer.
61.1Sjnemeth *
71.1Sjnemeth * Redistribution and use in source and binary forms, with or without
81.1Sjnemeth * modification, are permitted provided that the following conditions
91.1Sjnemeth * are met:
101.1Sjnemeth * 1. Redistributions of source code must retain the above copyright
111.1Sjnemeth *    notice, this list of conditions and the following disclaimer.
121.1Sjnemeth * 2. Redistributions in binary form must reproduce the above copyright
131.1Sjnemeth *    notice, this list of conditions and the following disclaimer in the
141.1Sjnemeth *    documentation and/or other materials provided with the distribution.
151.1Sjnemeth * 3. All advertising materials mentioning features or use of this software
161.1Sjnemeth *    must display the following acknowledgement:
171.1Sjnemeth *	This product includes software developed by Manuel Bouyer.
181.1Sjnemeth * 4. The name of the author may not be used to endorse or promote products
191.1Sjnemeth *    derived from this software without specific prior written permission.
201.1Sjnemeth *
211.1Sjnemeth * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
221.1Sjnemeth * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
231.1Sjnemeth * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
241.1Sjnemeth * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
251.1Sjnemeth * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
261.1Sjnemeth * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
271.1Sjnemeth * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
281.1Sjnemeth * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
291.1Sjnemeth * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
301.1Sjnemeth * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
311.1Sjnemeth *
321.1Sjnemeth */
331.1Sjnemeth
341.1Sjnemeth/*-
351.1Sjnemeth * Copyright (c) 2007, 2008 Jonathan A. Kollasch.
361.1Sjnemeth * All rights reserved.
371.1Sjnemeth *
381.1Sjnemeth * Redistribution and use in source and binary forms, with or without
391.1Sjnemeth * modification, are permitted provided that the following conditions
401.1Sjnemeth * are met:
411.1Sjnemeth * 1. Redistributions of source code must retain the above copyright
421.1Sjnemeth *    notice, this list of conditions and the following disclaimer.
431.1Sjnemeth * 2. Redistributions in binary form must reproduce the above copyright
441.1Sjnemeth *    notice, this list of conditions and the following disclaimer in the
451.1Sjnemeth *    documentation and/or other materials provided with the distribution.
461.1Sjnemeth *
471.1Sjnemeth * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
481.1Sjnemeth * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
491.1Sjnemeth * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
501.1Sjnemeth * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
511.1Sjnemeth * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
521.1Sjnemeth * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
531.1Sjnemeth * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
541.1Sjnemeth * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
551.1Sjnemeth * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
561.1Sjnemeth * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
571.1Sjnemeth *
581.1Sjnemeth */
591.1Sjnemeth
601.1Sjnemeth#include <sys/cdefs.h>
611.1Sjnemeth
621.1Sjnemeth
631.1Sjnemeth#include <sys/types.h>
641.1Sjnemeth#include <sys/malloc.h>
651.1Sjnemeth#include <sys/param.h>
661.1Sjnemeth#include <sys/kernel.h>
671.1Sjnemeth#include <sys/systm.h>
681.1Sjnemeth
691.1Sjnemeth#include <uvm/uvm_extern.h>
701.1Sjnemeth
711.1Sjnemeth#include <dev/pci/pcivar.h>
721.1Sjnemeth#include <dev/pci/pcidevs.h>
731.1Sjnemeth#include <dev/ic/siisatavar.h>
741.1Sjnemeth
751.1Sjnemethstruct siisata_pci_softc {
761.1Sjnemeth	struct siisata_softc si_sc;
771.1Sjnemeth	pci_chipset_tag_t sc_pc;
781.1Sjnemeth	pcitag_t sc_pcitag;
791.1Sjnemeth};
801.1Sjnemeth
811.1Sjnemethstatic int siisata_pci_match(device_t, cfdata_t, void *);
821.1Sjnemethstatic void siisata_pci_attach(device_t, device_t, void *);
831.1Sjnemethstatic bool siisata_pci_resume(device_t PMF_FN_PROTO);
841.1Sjnemeth
851.1Sjnemethstatic const struct siisata_pci_product {
861.1Sjnemeth	pci_vendor_id_t spp_vendor;
871.1Sjnemeth	pci_product_id_t spp_product;
881.1Sjnemeth	int spp_ports;
891.1Sjnemeth	int spp_chip;
901.1Sjnemeth
911.1Sjnemeth}                   siisata_pci_products[] = {
921.1Sjnemeth	{
931.1Sjnemeth		PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_3124,
941.1Sjnemeth		4, 3124
951.1Sjnemeth	},
961.1Sjnemeth	{
971.1Sjnemeth		PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_3132,
981.1Sjnemeth		2, 3132
991.1Sjnemeth	},
1001.1Sjnemeth	{
1011.1Sjnemeth		PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_3531,
1021.1Sjnemeth		1, 3531
1031.1Sjnemeth	},
1041.1Sjnemeth	{
1051.1Sjnemeth		0, 0,
1061.1Sjnemeth		0, 0
1071.1Sjnemeth	},
1081.1Sjnemeth};
1091.1Sjnemeth
1101.1SjnemethCFATTACH_DECL_NEW(siisata_pci, sizeof(struct siisata_pci_softc),
1111.1Sjnemeth    siisata_pci_match, siisata_pci_attach, NULL, NULL);
1121.1Sjnemeth
1131.1Sjnemethstatic const struct siisata_pci_product *
1141.1Sjnemethsiisata_pci_lookup(const struct pci_attach_args * pa)
1151.1Sjnemeth{
1161.1Sjnemeth	const struct siisata_pci_product *spp;
1171.1Sjnemeth
1181.1Sjnemeth	for (spp = siisata_pci_products; spp->spp_ports > 0; spp++) {
1191.1Sjnemeth		if (PCI_VENDOR(pa->pa_id) == spp->spp_vendor &&
1201.1Sjnemeth		    PCI_PRODUCT(pa->pa_id) == spp->spp_product)
1211.1Sjnemeth			return spp;
1221.1Sjnemeth	}
1231.1Sjnemeth	return NULL;
1241.1Sjnemeth}
1251.1Sjnemeth
1261.1Sjnemethstatic int
1271.1Sjnemethsiisata_pci_match(device_t parent, cfdata_t match, void *aux)
1281.1Sjnemeth{
1291.1Sjnemeth	struct pci_attach_args *pa = aux;
1301.1Sjnemeth
1311.1Sjnemeth	if (siisata_pci_lookup(pa) != NULL)
1321.1Sjnemeth		return 3;
1331.1Sjnemeth
1341.1Sjnemeth	return 0;
1351.1Sjnemeth}
1361.1Sjnemeth
1371.1Sjnemethstatic bool
1381.1Sjnemethsiisata_pci_resume(device_t dv PMF_FN_ARGS)
1391.1Sjnemeth{
1401.1Sjnemeth	struct siisata_pci_softc *psc = device_private(dv);
1411.1Sjnemeth	struct siisata_softc *sc = &psc->si_sc;
1421.1Sjnemeth	int s;
1431.1Sjnemeth
1441.1Sjnemeth	s = splbio();
1451.1Sjnemeth	siisata_resume(sc);
1461.1Sjnemeth	splx(s);
1471.1Sjnemeth
1481.1Sjnemeth	return true;
1491.1Sjnemeth}
1501.1Sjnemeth
1511.1Sjnemethstatic void
1521.1Sjnemethsiisata_pci_attach(device_t parent, device_t self, void *aux)
1531.1Sjnemeth{
1541.1Sjnemeth	struct pci_attach_args *pa = aux;
1551.1Sjnemeth	struct siisata_pci_softc *psc = device_private(self);
1561.1Sjnemeth	struct siisata_softc *sc = &psc->si_sc;
1571.1Sjnemeth	char devinfo[256];
1581.1Sjnemeth	const char *intrstr;
1591.1Sjnemeth	pci_intr_handle_t intrhandle;
1601.1Sjnemeth	pcireg_t csr, memtype;
1611.1Sjnemeth	const struct siisata_pci_product *spp;
1621.1Sjnemeth	void *ih;
1631.1Sjnemeth	bus_space_tag_t memt;
1641.1Sjnemeth	bus_space_handle_t memh;
1651.1Sjnemeth	uint32_t gcreg;
1661.1Sjnemeth	int memh_valid;
1671.1Sjnemeth	bus_size_t grsize, prsize;
1681.1Sjnemeth
1691.1Sjnemeth	sc->sc_atac.atac_dev = self;
1701.1Sjnemeth
1711.1Sjnemeth	psc->sc_pc = pa->pa_pc;
1721.1Sjnemeth	psc->sc_pcitag = pa->pa_tag;
1731.1Sjnemeth
1741.1Sjnemeth	pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo, sizeof(devinfo));
1751.1Sjnemeth	aprint_naive(": SATA-II HBA\n");
1761.1Sjnemeth	aprint_normal(": %s\n", devinfo);
1771.1Sjnemeth
1781.1Sjnemeth	/* map bar0 */
1791.1Sjnemeth#if 1
1801.1Sjnemeth	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, SIISATA_PCI_BAR0);
1811.1Sjnemeth#else
1821.1Sjnemeth	memtype = PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT;
1831.1Sjnemeth#endif
1841.1Sjnemeth	switch (memtype) {
1851.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
1861.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
1871.1Sjnemeth		memh_valid = (pci_mapreg_map(pa, SIISATA_PCI_BAR0,
1881.1Sjnemeth			memtype, 0, &memt, &memh, NULL, &grsize) == 0);
1891.1Sjnemeth		break;
1901.1Sjnemeth	default:
1911.1Sjnemeth		memh_valid = 0;
1921.1Sjnemeth	}
1931.1Sjnemeth	if (memh_valid) {
1941.1Sjnemeth		sc->sc_grt = memt;
1951.1Sjnemeth		sc->sc_grh = memh;
1961.1Sjnemeth	} else {
1971.1Sjnemeth		aprint_error("%s: unable to map device global registers\n",
1981.1Sjnemeth		    SIISATANAME(sc));
1991.1Sjnemeth		return;
2001.1Sjnemeth	}
2011.1Sjnemeth
2021.1Sjnemeth	/* map bar1 */
2031.1Sjnemeth#if 1
2041.1Sjnemeth	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, SIISATA_PCI_BAR1);
2051.1Sjnemeth#else
2061.1Sjnemeth	memtype = PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT;
2071.1Sjnemeth#endif
2081.1Sjnemeth	switch (memtype) {
2091.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
2101.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
2111.1Sjnemeth		memh_valid = (pci_mapreg_map(pa, SIISATA_PCI_BAR1,
2121.1Sjnemeth			memtype, 0, &memt, &memh, NULL, &prsize) == 0);
2131.1Sjnemeth		break;
2141.1Sjnemeth	default:
2151.1Sjnemeth		memh_valid = 0;
2161.1Sjnemeth	}
2171.1Sjnemeth	if (memh_valid) {
2181.1Sjnemeth		sc->sc_prt = memt;
2191.1Sjnemeth		sc->sc_prh = memh;
2201.1Sjnemeth	} else {
2211.1Sjnemeth		bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize);
2221.1Sjnemeth		aprint_error("%s: unable to map device port registers\n",
2231.1Sjnemeth		    SIISATANAME(sc));
2241.1Sjnemeth		return;
2251.1Sjnemeth	}
2261.1Sjnemeth
2271.1Sjnemeth	if (pci_dma64_available(pa)) {
2281.1Sjnemeth		sc->sc_dmat = pa->pa_dmat64;
2291.1Sjnemeth		sc->sc_have_dma64 = 1;
2301.1Sjnemeth		aprint_debug("64-bit PCI DMA available\n");
2311.1Sjnemeth	} else {
2321.1Sjnemeth		sc->sc_dmat = pa->pa_dmat;
2331.1Sjnemeth		sc->sc_have_dma64 = 0;
2341.1Sjnemeth	}
2351.1Sjnemeth
2361.1Sjnemeth	/* map interrupt */
2371.1Sjnemeth	if (pci_intr_map(pa, &intrhandle) != 0) {
2381.1Sjnemeth		bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize);
2391.1Sjnemeth		bus_space_unmap(sc->sc_prt, sc->sc_prh, prsize);
2401.1Sjnemeth		aprint_error("%s: couldn't map interrupt\n", SIISATANAME(sc));
2411.1Sjnemeth		return;
2421.1Sjnemeth	}
2431.1Sjnemeth	intrstr = pci_intr_string(pa->pa_pc, intrhandle);
2441.1Sjnemeth	ih = pci_intr_establish(pa->pa_pc, intrhandle,
2451.1Sjnemeth	    IPL_BIO, siisata_intr, sc);
2461.1Sjnemeth	if (ih == NULL) {
2471.1Sjnemeth		bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize);
2481.1Sjnemeth		bus_space_unmap(sc->sc_prt, sc->sc_prh, prsize);
2491.1Sjnemeth		aprint_error("%s: couldn't establish interrupt"
2501.1Sjnemeth		    "at %s\n", SIISATANAME(sc), intrstr);
2511.1Sjnemeth		return;
2521.1Sjnemeth	}
2531.1Sjnemeth	aprint_normal("%s: interrupting at %s\n", SIISATANAME(sc),
2541.1Sjnemeth	    intrstr ? intrstr : "unknown interrupt");
2551.1Sjnemeth
2561.1Sjnemeth	/* fill in number of ports on this device */
2571.1Sjnemeth	spp = siisata_pci_lookup(pa);
2581.1Sjnemeth	if (spp != NULL) {
2591.1Sjnemeth		sc->sc_atac.atac_nchannels = spp->spp_ports;
2601.1Sjnemeth		sc->sc_chip = spp->spp_chip;
2611.1Sjnemeth	} else
2621.1Sjnemeth		/* _match() should prevent us from getting here */
2631.1Sjnemeth		panic("siisata: the universe might be falling apart!\n");
2641.1Sjnemeth
2651.2Sjakllsch	/* set the necessary bits in case the firmware didn't */
2661.2Sjakllsch	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
2671.2Sjakllsch	csr |= PCI_COMMAND_MASTER_ENABLE;
2681.2Sjakllsch	csr |= PCI_COMMAND_MEM_ENABLE;
2691.2Sjakllsch	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, csr);
2701.2Sjakllsch
2711.1Sjnemeth	gcreg = GRREAD(sc, GR_GC);
2721.1Sjnemeth
2731.1Sjnemeth	aprint_normal("%s: SiI%d on ", SIISATANAME(sc), sc->sc_chip);
2741.1Sjnemeth	if (sc->sc_chip == 3124) {
2751.1Sjnemeth		aprint_normal("%d-bit, ", (gcreg & GR_GC_REQ64) ? 64 : 32);
2761.1Sjnemeth		switch (gcreg & (GR_GC_DEVSEL | GR_GC_STOP | GR_GC_TRDY)) {
2771.1Sjnemeth		case 0:
2781.1Sjnemeth			aprint_normal("%d", (gcreg & GR_GC_M66EN) ? 66 : 33);
2791.1Sjnemeth			break;
2801.1Sjnemeth		case GR_GC_TRDY:
2811.1Sjnemeth			aprint_normal("%d", 66);
2821.1Sjnemeth			break;
2831.1Sjnemeth		case GR_GC_STOP:
2841.1Sjnemeth			aprint_normal("%d", 100);
2851.1Sjnemeth			break;
2861.1Sjnemeth		case GR_GC_STOP | GR_GC_TRDY:
2871.1Sjnemeth			aprint_normal("%d", 133);
2881.1Sjnemeth			break;
2891.1Sjnemeth		default:
2901.1Sjnemeth			break;
2911.1Sjnemeth		}
2921.1Sjnemeth		aprint_normal("MHz PCI%s bus.", (gcreg & (GR_GC_DEVSEL | GR_GC_STOP | GR_GC_TRDY)) ? "-X" : "");
2931.1Sjnemeth	} else {
2941.1Sjnemeth		/* XXX - but only x1 devices so far */
2951.1Sjnemeth		aprint_normal("PCI-Express x1 port.");
2961.1Sjnemeth	}
2971.1Sjnemeth	if (gcreg & GR_GC_3GBPS)
2981.1Sjnemeth		aprint_normal(" 3.0Gb/s capable.\n");
2991.1Sjnemeth	else
3001.1Sjnemeth		aprint_normal("\n");
3011.1Sjnemeth
3021.1Sjnemeth	siisata_attach(sc);
3031.1Sjnemeth
3041.1Sjnemeth	if (!pmf_device_register(self, NULL, siisata_pci_resume))
3051.1Sjnemeth		aprint_error_dev(self, "couldn't establish power handler\n");
3061.1Sjnemeth}
3071.1Sjnemeth
308