siisata_pci.c revision 1.3
11.3Sjakllsch/* $NetBSD: siisata_pci.c,v 1.3 2009/06/17 04:37:57 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.3Sjakllsch	void * sc_ih;
801.1Sjnemeth};
811.1Sjnemeth
821.1Sjnemethstatic int siisata_pci_match(device_t, cfdata_t, void *);
831.1Sjnemethstatic void siisata_pci_attach(device_t, device_t, void *);
841.3Sjakllschstatic int siisata_pci_detach(device_t, int);
851.1Sjnemethstatic bool siisata_pci_resume(device_t PMF_FN_PROTO);
861.1Sjnemeth
871.1Sjnemethstatic const struct siisata_pci_product {
881.1Sjnemeth	pci_vendor_id_t spp_vendor;
891.1Sjnemeth	pci_product_id_t spp_product;
901.1Sjnemeth	int spp_ports;
911.1Sjnemeth	int spp_chip;
921.1Sjnemeth
931.1Sjnemeth}                   siisata_pci_products[] = {
941.1Sjnemeth	{
951.1Sjnemeth		PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_3124,
961.1Sjnemeth		4, 3124
971.1Sjnemeth	},
981.1Sjnemeth	{
991.1Sjnemeth		PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_3132,
1001.1Sjnemeth		2, 3132
1011.1Sjnemeth	},
1021.1Sjnemeth	{
1031.1Sjnemeth		PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_3531,
1041.1Sjnemeth		1, 3531
1051.1Sjnemeth	},
1061.1Sjnemeth	{
1071.1Sjnemeth		0, 0,
1081.1Sjnemeth		0, 0
1091.1Sjnemeth	},
1101.1Sjnemeth};
1111.1Sjnemeth
1121.1SjnemethCFATTACH_DECL_NEW(siisata_pci, sizeof(struct siisata_pci_softc),
1131.3Sjakllsch    siisata_pci_match, siisata_pci_attach, siisata_pci_detach, NULL);
1141.1Sjnemeth
1151.1Sjnemethstatic const struct siisata_pci_product *
1161.1Sjnemethsiisata_pci_lookup(const struct pci_attach_args * pa)
1171.1Sjnemeth{
1181.1Sjnemeth	const struct siisata_pci_product *spp;
1191.1Sjnemeth
1201.1Sjnemeth	for (spp = siisata_pci_products; spp->spp_ports > 0; spp++) {
1211.1Sjnemeth		if (PCI_VENDOR(pa->pa_id) == spp->spp_vendor &&
1221.1Sjnemeth		    PCI_PRODUCT(pa->pa_id) == spp->spp_product)
1231.1Sjnemeth			return spp;
1241.1Sjnemeth	}
1251.1Sjnemeth	return NULL;
1261.1Sjnemeth}
1271.1Sjnemeth
1281.1Sjnemethstatic int
1291.1Sjnemethsiisata_pci_match(device_t parent, cfdata_t match, void *aux)
1301.1Sjnemeth{
1311.1Sjnemeth	struct pci_attach_args *pa = aux;
1321.1Sjnemeth
1331.1Sjnemeth	if (siisata_pci_lookup(pa) != NULL)
1341.1Sjnemeth		return 3;
1351.1Sjnemeth
1361.1Sjnemeth	return 0;
1371.1Sjnemeth}
1381.1Sjnemeth
1391.1Sjnemethstatic void
1401.1Sjnemethsiisata_pci_attach(device_t parent, device_t self, void *aux)
1411.1Sjnemeth{
1421.1Sjnemeth	struct pci_attach_args *pa = aux;
1431.1Sjnemeth	struct siisata_pci_softc *psc = device_private(self);
1441.1Sjnemeth	struct siisata_softc *sc = &psc->si_sc;
1451.1Sjnemeth	char devinfo[256];
1461.1Sjnemeth	const char *intrstr;
1471.1Sjnemeth	pcireg_t csr, memtype;
1481.1Sjnemeth	const struct siisata_pci_product *spp;
1491.3Sjakllsch	pci_intr_handle_t intrhandle;
1501.1Sjnemeth	bus_space_tag_t memt;
1511.1Sjnemeth	bus_space_handle_t memh;
1521.1Sjnemeth	uint32_t gcreg;
1531.1Sjnemeth	int memh_valid;
1541.1Sjnemeth	bus_size_t grsize, prsize;
1551.1Sjnemeth
1561.1Sjnemeth	sc->sc_atac.atac_dev = self;
1571.1Sjnemeth
1581.1Sjnemeth	psc->sc_pc = pa->pa_pc;
1591.1Sjnemeth	psc->sc_pcitag = pa->pa_tag;
1601.1Sjnemeth
1611.1Sjnemeth	pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo, sizeof(devinfo));
1621.1Sjnemeth	aprint_naive(": SATA-II HBA\n");
1631.1Sjnemeth	aprint_normal(": %s\n", devinfo);
1641.1Sjnemeth
1651.1Sjnemeth	/* map bar0 */
1661.1Sjnemeth#if 1
1671.1Sjnemeth	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, SIISATA_PCI_BAR0);
1681.1Sjnemeth#else
1691.1Sjnemeth	memtype = PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT;
1701.1Sjnemeth#endif
1711.1Sjnemeth	switch (memtype) {
1721.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
1731.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
1741.1Sjnemeth		memh_valid = (pci_mapreg_map(pa, SIISATA_PCI_BAR0,
1751.1Sjnemeth			memtype, 0, &memt, &memh, NULL, &grsize) == 0);
1761.1Sjnemeth		break;
1771.1Sjnemeth	default:
1781.1Sjnemeth		memh_valid = 0;
1791.1Sjnemeth	}
1801.1Sjnemeth	if (memh_valid) {
1811.1Sjnemeth		sc->sc_grt = memt;
1821.1Sjnemeth		sc->sc_grh = memh;
1831.3Sjakllsch		sc->sc_grs = grsize;
1841.1Sjnemeth	} else {
1851.1Sjnemeth		aprint_error("%s: unable to map device global registers\n",
1861.1Sjnemeth		    SIISATANAME(sc));
1871.1Sjnemeth		return;
1881.1Sjnemeth	}
1891.1Sjnemeth
1901.1Sjnemeth	/* map bar1 */
1911.1Sjnemeth#if 1
1921.1Sjnemeth	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, SIISATA_PCI_BAR1);
1931.1Sjnemeth#else
1941.1Sjnemeth	memtype = PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT;
1951.1Sjnemeth#endif
1961.1Sjnemeth	switch (memtype) {
1971.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
1981.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
1991.1Sjnemeth		memh_valid = (pci_mapreg_map(pa, SIISATA_PCI_BAR1,
2001.1Sjnemeth			memtype, 0, &memt, &memh, NULL, &prsize) == 0);
2011.1Sjnemeth		break;
2021.1Sjnemeth	default:
2031.1Sjnemeth		memh_valid = 0;
2041.1Sjnemeth	}
2051.1Sjnemeth	if (memh_valid) {
2061.1Sjnemeth		sc->sc_prt = memt;
2071.1Sjnemeth		sc->sc_prh = memh;
2081.3Sjakllsch		sc->sc_prs = prsize;
2091.1Sjnemeth	} else {
2101.1Sjnemeth		bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize);
2111.1Sjnemeth		aprint_error("%s: unable to map device port registers\n",
2121.1Sjnemeth		    SIISATANAME(sc));
2131.1Sjnemeth		return;
2141.1Sjnemeth	}
2151.1Sjnemeth
2161.1Sjnemeth	if (pci_dma64_available(pa)) {
2171.1Sjnemeth		sc->sc_dmat = pa->pa_dmat64;
2181.1Sjnemeth		sc->sc_have_dma64 = 1;
2191.1Sjnemeth		aprint_debug("64-bit PCI DMA available\n");
2201.1Sjnemeth	} else {
2211.1Sjnemeth		sc->sc_dmat = pa->pa_dmat;
2221.1Sjnemeth		sc->sc_have_dma64 = 0;
2231.1Sjnemeth	}
2241.1Sjnemeth
2251.1Sjnemeth	/* map interrupt */
2261.1Sjnemeth	if (pci_intr_map(pa, &intrhandle) != 0) {
2271.1Sjnemeth		bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize);
2281.1Sjnemeth		bus_space_unmap(sc->sc_prt, sc->sc_prh, prsize);
2291.1Sjnemeth		aprint_error("%s: couldn't map interrupt\n", SIISATANAME(sc));
2301.1Sjnemeth		return;
2311.1Sjnemeth	}
2321.1Sjnemeth	intrstr = pci_intr_string(pa->pa_pc, intrhandle);
2331.3Sjakllsch	psc->sc_ih = pci_intr_establish(pa->pa_pc, intrhandle,
2341.1Sjnemeth	    IPL_BIO, siisata_intr, sc);
2351.3Sjakllsch	if (psc->sc_ih == NULL) {
2361.1Sjnemeth		bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize);
2371.1Sjnemeth		bus_space_unmap(sc->sc_prt, sc->sc_prh, prsize);
2381.1Sjnemeth		aprint_error("%s: couldn't establish interrupt"
2391.1Sjnemeth		    "at %s\n", SIISATANAME(sc), intrstr);
2401.1Sjnemeth		return;
2411.1Sjnemeth	}
2421.1Sjnemeth	aprint_normal("%s: interrupting at %s\n", SIISATANAME(sc),
2431.1Sjnemeth	    intrstr ? intrstr : "unknown interrupt");
2441.1Sjnemeth
2451.1Sjnemeth	/* fill in number of ports on this device */
2461.1Sjnemeth	spp = siisata_pci_lookup(pa);
2471.1Sjnemeth	if (spp != NULL) {
2481.1Sjnemeth		sc->sc_atac.atac_nchannels = spp->spp_ports;
2491.1Sjnemeth		sc->sc_chip = spp->spp_chip;
2501.1Sjnemeth	} else
2511.1Sjnemeth		/* _match() should prevent us from getting here */
2521.1Sjnemeth		panic("siisata: the universe might be falling apart!\n");
2531.1Sjnemeth
2541.2Sjakllsch	/* set the necessary bits in case the firmware didn't */
2551.2Sjakllsch	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
2561.2Sjakllsch	csr |= PCI_COMMAND_MASTER_ENABLE;
2571.2Sjakllsch	csr |= PCI_COMMAND_MEM_ENABLE;
2581.2Sjakllsch	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, csr);
2591.2Sjakllsch
2601.1Sjnemeth	gcreg = GRREAD(sc, GR_GC);
2611.1Sjnemeth
2621.1Sjnemeth	aprint_normal("%s: SiI%d on ", SIISATANAME(sc), sc->sc_chip);
2631.1Sjnemeth	if (sc->sc_chip == 3124) {
2641.1Sjnemeth		aprint_normal("%d-bit, ", (gcreg & GR_GC_REQ64) ? 64 : 32);
2651.1Sjnemeth		switch (gcreg & (GR_GC_DEVSEL | GR_GC_STOP | GR_GC_TRDY)) {
2661.1Sjnemeth		case 0:
2671.1Sjnemeth			aprint_normal("%d", (gcreg & GR_GC_M66EN) ? 66 : 33);
2681.1Sjnemeth			break;
2691.1Sjnemeth		case GR_GC_TRDY:
2701.1Sjnemeth			aprint_normal("%d", 66);
2711.1Sjnemeth			break;
2721.1Sjnemeth		case GR_GC_STOP:
2731.1Sjnemeth			aprint_normal("%d", 100);
2741.1Sjnemeth			break;
2751.1Sjnemeth		case GR_GC_STOP | GR_GC_TRDY:
2761.1Sjnemeth			aprint_normal("%d", 133);
2771.1Sjnemeth			break;
2781.1Sjnemeth		default:
2791.1Sjnemeth			break;
2801.1Sjnemeth		}
2811.1Sjnemeth		aprint_normal("MHz PCI%s bus.", (gcreg & (GR_GC_DEVSEL | GR_GC_STOP | GR_GC_TRDY)) ? "-X" : "");
2821.1Sjnemeth	} else {
2831.1Sjnemeth		/* XXX - but only x1 devices so far */
2841.1Sjnemeth		aprint_normal("PCI-Express x1 port.");
2851.1Sjnemeth	}
2861.1Sjnemeth	if (gcreg & GR_GC_3GBPS)
2871.1Sjnemeth		aprint_normal(" 3.0Gb/s capable.\n");
2881.1Sjnemeth	else
2891.1Sjnemeth		aprint_normal("\n");
2901.1Sjnemeth
2911.1Sjnemeth	siisata_attach(sc);
2921.1Sjnemeth
2931.1Sjnemeth	if (!pmf_device_register(self, NULL, siisata_pci_resume))
2941.1Sjnemeth		aprint_error_dev(self, "couldn't establish power handler\n");
2951.1Sjnemeth}
2961.1Sjnemeth
2971.3Sjakllschstatic int
2981.3Sjakllschsiisata_pci_detach(device_t dv, int flags)
2991.3Sjakllsch{
3001.3Sjakllsch	struct siisata_pci_softc *psc = device_private(dv);
3011.3Sjakllsch	struct siisata_softc *sc = &psc->si_sc;
3021.3Sjakllsch	int rv;
3031.3Sjakllsch
3041.3Sjakllsch	rv = siisata_detach(sc, flags);
3051.3Sjakllsch	if (rv)
3061.3Sjakllsch		return rv;
3071.3Sjakllsch
3081.3Sjakllsch	if (psc->sc_ih != NULL) {
3091.3Sjakllsch		pci_intr_disestablish(psc->sc_pc, psc->sc_ih);
3101.3Sjakllsch	}
3111.3Sjakllsch
3121.3Sjakllsch	bus_space_unmap(sc->sc_prt, sc->sc_prh, sc->sc_prs);
3131.3Sjakllsch	bus_space_unmap(sc->sc_grt, sc->sc_grh, sc->sc_grs);
3141.3Sjakllsch
3151.3Sjakllsch	return 0;
3161.3Sjakllsch}
3171.3Sjakllsch
3181.3Sjakllschstatic bool
3191.3Sjakllschsiisata_pci_resume(device_t dv PMF_FN_ARGS)
3201.3Sjakllsch{
3211.3Sjakllsch	struct siisata_pci_softc *psc = device_private(dv);
3221.3Sjakllsch	struct siisata_softc *sc = &psc->si_sc;
3231.3Sjakllsch	int s;
3241.3Sjakllsch
3251.3Sjakllsch	s = splbio();
3261.3Sjakllsch	siisata_resume(sc);
3271.3Sjakllsch	splx(s);
3281.3Sjakllsch
3291.3Sjakllsch	return true;
3301.3Sjakllsch}
331