siisata_pci.c revision 1.4
11.4Sjakllsch/* $NetBSD: siisata_pci.c,v 1.4 2009/07/04 20:36:57 jakllsch Exp $ */
21.1Sjnemeth
31.1Sjnemeth/*
41.1Sjnemeth * Copyright (c) 2006 Manuel Bouyer.
51.1Sjnemeth *
61.1Sjnemeth * Redistribution and use in source and binary forms, with or without
71.1Sjnemeth * modification, are permitted provided that the following conditions
81.1Sjnemeth * are met:
91.1Sjnemeth * 1. Redistributions of source code must retain the above copyright
101.1Sjnemeth *    notice, this list of conditions and the following disclaimer.
111.1Sjnemeth * 2. Redistributions in binary form must reproduce the above copyright
121.1Sjnemeth *    notice, this list of conditions and the following disclaimer in the
131.1Sjnemeth *    documentation and/or other materials provided with the distribution.
141.1Sjnemeth * 3. All advertising materials mentioning features or use of this software
151.1Sjnemeth *    must display the following acknowledgement:
161.1Sjnemeth *	This product includes software developed by Manuel Bouyer.
171.1Sjnemeth * 4. The name of the author may not be used to endorse or promote products
181.1Sjnemeth *    derived from this software without specific prior written permission.
191.1Sjnemeth *
201.1Sjnemeth * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
211.1Sjnemeth * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
221.1Sjnemeth * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
231.1Sjnemeth * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
241.1Sjnemeth * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
251.1Sjnemeth * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
261.1Sjnemeth * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
271.1Sjnemeth * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
281.1Sjnemeth * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
291.1Sjnemeth * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
301.1Sjnemeth *
311.1Sjnemeth */
321.1Sjnemeth
331.1Sjnemeth/*-
341.4Sjakllsch * Copyright (c) 2007, 2008, 2009 Jonathan A. Kollasch.
351.1Sjnemeth * All rights reserved.
361.1Sjnemeth *
371.1Sjnemeth * Redistribution and use in source and binary forms, with or without
381.1Sjnemeth * modification, are permitted provided that the following conditions
391.1Sjnemeth * are met:
401.1Sjnemeth * 1. Redistributions of source code must retain the above copyright
411.1Sjnemeth *    notice, this list of conditions and the following disclaimer.
421.1Sjnemeth * 2. Redistributions in binary form must reproduce the above copyright
431.1Sjnemeth *    notice, this list of conditions and the following disclaimer in the
441.1Sjnemeth *    documentation and/or other materials provided with the distribution.
451.1Sjnemeth *
461.1Sjnemeth * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
471.1Sjnemeth * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
481.1Sjnemeth * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
491.1Sjnemeth * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
501.1Sjnemeth * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
511.1Sjnemeth * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
521.1Sjnemeth * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
531.1Sjnemeth * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
541.1Sjnemeth * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
551.1Sjnemeth * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
561.1Sjnemeth *
571.1Sjnemeth */
581.1Sjnemeth
591.1Sjnemeth#include <sys/cdefs.h>
601.1Sjnemeth
611.1Sjnemeth
621.1Sjnemeth#include <sys/types.h>
631.1Sjnemeth#include <sys/malloc.h>
641.1Sjnemeth#include <sys/param.h>
651.1Sjnemeth#include <sys/kernel.h>
661.1Sjnemeth#include <sys/systm.h>
671.1Sjnemeth
681.1Sjnemeth#include <uvm/uvm_extern.h>
691.1Sjnemeth
701.1Sjnemeth#include <dev/pci/pcivar.h>
711.1Sjnemeth#include <dev/pci/pcidevs.h>
721.1Sjnemeth#include <dev/ic/siisatavar.h>
731.1Sjnemeth
741.1Sjnemethstruct siisata_pci_softc {
751.1Sjnemeth	struct siisata_softc si_sc;
761.1Sjnemeth	pci_chipset_tag_t sc_pc;
771.1Sjnemeth	pcitag_t sc_pcitag;
781.3Sjakllsch	void * sc_ih;
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.3Sjakllschstatic int siisata_pci_detach(device_t, int);
841.1Sjnemethstatic bool siisata_pci_resume(device_t PMF_FN_PROTO);
851.1Sjnemeth
861.4Sjakllschstruct siisata_pci_board {
871.4Sjakllsch	pci_vendor_id_t		spb_vend;
881.4Sjakllsch	pci_product_id_t	spb_prod;
891.4Sjakllsch	uint16_t		spb_port;
901.4Sjakllsch	uint16_t		spb_chip;
911.4Sjakllsch};
921.1Sjnemeth
931.4Sjakllschstatic const struct siisata_pci_board siisata_pci_boards[] = {
941.1Sjnemeth	{
951.4Sjakllsch		.spb_vend = PCI_VENDOR_CMDTECH,
961.4Sjakllsch		.spb_prod = PCI_PRODUCT_CMDTECH_3124,
971.4Sjakllsch		.spb_port = 4,
981.4Sjakllsch		.spb_chip = 3124,
991.1Sjnemeth	},
1001.1Sjnemeth	{
1011.4Sjakllsch		.spb_vend = PCI_VENDOR_CMDTECH,
1021.4Sjakllsch		.spb_prod = PCI_PRODUCT_CMDTECH_3132,
1031.4Sjakllsch		.spb_port = 2,
1041.4Sjakllsch		.spb_chip = 3132,
1051.1Sjnemeth	},
1061.1Sjnemeth	{
1071.4Sjakllsch		.spb_vend = PCI_VENDOR_CMDTECH,
1081.4Sjakllsch		.spb_prod = PCI_PRODUCT_CMDTECH_3531,
1091.4Sjakllsch		.spb_port = 1,
1101.4Sjakllsch		.spb_chip = 3531,
1111.1Sjnemeth	},
1121.1Sjnemeth};
1131.1Sjnemeth
1141.1SjnemethCFATTACH_DECL_NEW(siisata_pci, sizeof(struct siisata_pci_softc),
1151.3Sjakllsch    siisata_pci_match, siisata_pci_attach, siisata_pci_detach, NULL);
1161.1Sjnemeth
1171.4Sjakllschstatic const struct siisata_pci_board *
1181.1Sjnemethsiisata_pci_lookup(const struct pci_attach_args * pa)
1191.1Sjnemeth{
1201.4Sjakllsch	int i;
1211.1Sjnemeth
1221.4Sjakllsch	for (i = 0; i < __arraycount(siisata_pci_boards); i++) {
1231.4Sjakllsch		if (siisata_pci_boards[i].spb_vend != PCI_VENDOR(pa->pa_id))
1241.4Sjakllsch			continue;
1251.4Sjakllsch		if (siisata_pci_boards[i].spb_prod == PCI_PRODUCT(pa->pa_id))
1261.4Sjakllsch			return &siisata_pci_boards[i];
1271.1Sjnemeth	}
1281.4Sjakllsch
1291.1Sjnemeth	return NULL;
1301.1Sjnemeth}
1311.1Sjnemeth
1321.1Sjnemethstatic int
1331.1Sjnemethsiisata_pci_match(device_t parent, cfdata_t match, void *aux)
1341.1Sjnemeth{
1351.1Sjnemeth	struct pci_attach_args *pa = aux;
1361.1Sjnemeth
1371.1Sjnemeth	if (siisata_pci_lookup(pa) != NULL)
1381.1Sjnemeth		return 3;
1391.1Sjnemeth
1401.1Sjnemeth	return 0;
1411.1Sjnemeth}
1421.1Sjnemeth
1431.1Sjnemethstatic void
1441.1Sjnemethsiisata_pci_attach(device_t parent, device_t self, void *aux)
1451.1Sjnemeth{
1461.1Sjnemeth	struct pci_attach_args *pa = aux;
1471.1Sjnemeth	struct siisata_pci_softc *psc = device_private(self);
1481.1Sjnemeth	struct siisata_softc *sc = &psc->si_sc;
1491.1Sjnemeth	char devinfo[256];
1501.1Sjnemeth	const char *intrstr;
1511.1Sjnemeth	pcireg_t csr, memtype;
1521.4Sjakllsch	const struct siisata_pci_board *spbp;
1531.3Sjakllsch	pci_intr_handle_t intrhandle;
1541.1Sjnemeth	bus_space_tag_t memt;
1551.1Sjnemeth	bus_space_handle_t memh;
1561.1Sjnemeth	uint32_t gcreg;
1571.1Sjnemeth	int memh_valid;
1581.1Sjnemeth	bus_size_t grsize, prsize;
1591.1Sjnemeth
1601.1Sjnemeth	sc->sc_atac.atac_dev = self;
1611.1Sjnemeth
1621.1Sjnemeth	psc->sc_pc = pa->pa_pc;
1631.1Sjnemeth	psc->sc_pcitag = pa->pa_tag;
1641.1Sjnemeth
1651.1Sjnemeth	pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo, sizeof(devinfo));
1661.1Sjnemeth	aprint_naive(": SATA-II HBA\n");
1671.1Sjnemeth	aprint_normal(": %s\n", devinfo);
1681.1Sjnemeth
1691.4Sjakllsch	/* map BAR 0, global registers */
1701.1Sjnemeth	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, SIISATA_PCI_BAR0);
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.4Sjakllsch		aprint_error_dev(self, "couldn't map global registers\n");
1861.1Sjnemeth		return;
1871.1Sjnemeth	}
1881.1Sjnemeth
1891.4Sjakllsch	/* map BAR 1, port registers */
1901.1Sjnemeth	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, SIISATA_PCI_BAR1);
1911.1Sjnemeth	switch (memtype) {
1921.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
1931.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
1941.1Sjnemeth		memh_valid = (pci_mapreg_map(pa, SIISATA_PCI_BAR1,
1951.1Sjnemeth			memtype, 0, &memt, &memh, NULL, &prsize) == 0);
1961.1Sjnemeth		break;
1971.1Sjnemeth	default:
1981.1Sjnemeth		memh_valid = 0;
1991.1Sjnemeth	}
2001.1Sjnemeth	if (memh_valid) {
2011.1Sjnemeth		sc->sc_prt = memt;
2021.1Sjnemeth		sc->sc_prh = memh;
2031.3Sjakllsch		sc->sc_prs = prsize;
2041.1Sjnemeth	} else {
2051.1Sjnemeth		bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize);
2061.4Sjakllsch		aprint_error_dev(self, "couldn't map port registers\n");
2071.1Sjnemeth		return;
2081.1Sjnemeth	}
2091.1Sjnemeth
2101.4Sjakllsch	if (pci_dma64_available(pa))
2111.1Sjnemeth		sc->sc_dmat = pa->pa_dmat64;
2121.4Sjakllsch	else
2131.1Sjnemeth		sc->sc_dmat = pa->pa_dmat;
2141.1Sjnemeth
2151.1Sjnemeth	/* map interrupt */
2161.1Sjnemeth	if (pci_intr_map(pa, &intrhandle) != 0) {
2171.1Sjnemeth		bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize);
2181.1Sjnemeth		bus_space_unmap(sc->sc_prt, sc->sc_prh, prsize);
2191.4Sjakllsch		aprint_error_dev(self, "couldn't map interrupt\n");
2201.1Sjnemeth		return;
2211.1Sjnemeth	}
2221.1Sjnemeth	intrstr = pci_intr_string(pa->pa_pc, intrhandle);
2231.3Sjakllsch	psc->sc_ih = pci_intr_establish(pa->pa_pc, intrhandle,
2241.1Sjnemeth	    IPL_BIO, siisata_intr, sc);
2251.3Sjakllsch	if (psc->sc_ih == NULL) {
2261.1Sjnemeth		bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize);
2271.1Sjnemeth		bus_space_unmap(sc->sc_prt, sc->sc_prh, prsize);
2281.4Sjakllsch		aprint_error_dev(self, "couldn't establish interrupt at %s\n",
2291.4Sjakllsch			intrstr);
2301.1Sjnemeth		return;
2311.1Sjnemeth	}
2321.4Sjakllsch	aprint_normal_dev(self, "interrupting at %s\n",
2331.4Sjakllsch		intrstr ? intrstr : "unknown interrupt");
2341.1Sjnemeth
2351.1Sjnemeth	/* fill in number of ports on this device */
2361.4Sjakllsch	spbp = siisata_pci_lookup(pa);
2371.4Sjakllsch	KASSERT(spbp != NULL);
2381.4Sjakllsch	sc->sc_atac.atac_nchannels = spbp->spb_port;
2391.1Sjnemeth
2401.2Sjakllsch	/* set the necessary bits in case the firmware didn't */
2411.2Sjakllsch	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
2421.2Sjakllsch	csr |= PCI_COMMAND_MASTER_ENABLE;
2431.2Sjakllsch	csr |= PCI_COMMAND_MEM_ENABLE;
2441.2Sjakllsch	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, csr);
2451.2Sjakllsch
2461.1Sjnemeth	gcreg = GRREAD(sc, GR_GC);
2471.1Sjnemeth
2481.4Sjakllsch	aprint_verbose_dev(self, "SiI%d, %sGb/s\n",
2491.4Sjakllsch		spbp->spb_chip, (gcreg & GR_GC_3GBPS) ? "3.0" : "1.5" );
2501.4Sjakllsch	if (spbp->spb_chip == 3124) {
2511.4Sjakllsch		short width;
2521.4Sjakllsch		short speed;
2531.4Sjakllsch		char pcix = 1;
2541.4Sjakllsch
2551.4Sjakllsch		width = (gcreg & GR_GC_REQ64) ? 64 : 32;
2561.4Sjakllsch
2571.1Sjnemeth		switch (gcreg & (GR_GC_DEVSEL | GR_GC_STOP | GR_GC_TRDY)) {
2581.1Sjnemeth		case 0:
2591.4Sjakllsch			speed = (gcreg & GR_GC_M66EN) ? 66 : 33;
2601.4Sjakllsch			pcix = 0;
2611.1Sjnemeth			break;
2621.1Sjnemeth		case GR_GC_TRDY:
2631.4Sjakllsch			speed = 66;
2641.1Sjnemeth			break;
2651.1Sjnemeth		case GR_GC_STOP:
2661.4Sjakllsch			speed = 100;
2671.1Sjnemeth			break;
2681.1Sjnemeth		case GR_GC_STOP | GR_GC_TRDY:
2691.4Sjakllsch			speed = 133;
2701.1Sjnemeth			break;
2711.1Sjnemeth		default:
2721.4Sjakllsch			speed = -1;
2731.1Sjnemeth			break;
2741.1Sjnemeth		}
2751.4Sjakllsch		aprint_verbose_dev(self, "%hd-bit %hdMHz PCI%s\n",
2761.4Sjakllsch			width, speed, pcix ? "-X" : "");
2771.1Sjnemeth	}
2781.1Sjnemeth
2791.1Sjnemeth	siisata_attach(sc);
2801.1Sjnemeth
2811.1Sjnemeth	if (!pmf_device_register(self, NULL, siisata_pci_resume))
2821.1Sjnemeth		aprint_error_dev(self, "couldn't establish power handler\n");
2831.1Sjnemeth}
2841.1Sjnemeth
2851.3Sjakllschstatic int
2861.3Sjakllschsiisata_pci_detach(device_t dv, int flags)
2871.3Sjakllsch{
2881.3Sjakllsch	struct siisata_pci_softc *psc = device_private(dv);
2891.3Sjakllsch	struct siisata_softc *sc = &psc->si_sc;
2901.3Sjakllsch	int rv;
2911.3Sjakllsch
2921.3Sjakllsch	rv = siisata_detach(sc, flags);
2931.3Sjakllsch	if (rv)
2941.3Sjakllsch		return rv;
2951.3Sjakllsch
2961.3Sjakllsch	if (psc->sc_ih != NULL) {
2971.3Sjakllsch		pci_intr_disestablish(psc->sc_pc, psc->sc_ih);
2981.3Sjakllsch	}
2991.3Sjakllsch
3001.3Sjakllsch	bus_space_unmap(sc->sc_prt, sc->sc_prh, sc->sc_prs);
3011.3Sjakllsch	bus_space_unmap(sc->sc_grt, sc->sc_grh, sc->sc_grs);
3021.3Sjakllsch
3031.3Sjakllsch	return 0;
3041.3Sjakllsch}
3051.3Sjakllsch
3061.3Sjakllschstatic bool
3071.3Sjakllschsiisata_pci_resume(device_t dv PMF_FN_ARGS)
3081.3Sjakllsch{
3091.3Sjakllsch	struct siisata_pci_softc *psc = device_private(dv);
3101.3Sjakllsch	struct siisata_softc *sc = &psc->si_sc;
3111.3Sjakllsch	int s;
3121.3Sjakllsch
3131.3Sjakllsch	s = splbio();
3141.3Sjakllsch	siisata_resume(sc);
3151.3Sjakllsch	splx(s);
3161.3Sjakllsch
3171.3Sjakllsch	return true;
3181.3Sjakllsch}
319