siisata_pci.c revision 1.7
11.7Sjakllsch/* $NetBSD: siisata_pci.c,v 1.7 2010/01/30 16:16:35 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 *
151.1Sjnemeth * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
161.1Sjnemeth * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
171.1Sjnemeth * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
181.1Sjnemeth * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
191.1Sjnemeth * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
201.1Sjnemeth * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
211.1Sjnemeth * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
221.1Sjnemeth * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
231.1Sjnemeth * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
241.1Sjnemeth * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
251.1Sjnemeth *
261.1Sjnemeth */
271.1Sjnemeth
281.7Sjakllsch/*
291.4Sjakllsch * Copyright (c) 2007, 2008, 2009 Jonathan A. Kollasch.
301.1Sjnemeth * All rights reserved.
311.1Sjnemeth *
321.1Sjnemeth * Redistribution and use in source and binary forms, with or without
331.1Sjnemeth * modification, are permitted provided that the following conditions
341.1Sjnemeth * are met:
351.1Sjnemeth * 1. Redistributions of source code must retain the above copyright
361.1Sjnemeth *    notice, this list of conditions and the following disclaimer.
371.1Sjnemeth * 2. Redistributions in binary form must reproduce the above copyright
381.1Sjnemeth *    notice, this list of conditions and the following disclaimer in the
391.1Sjnemeth *    documentation and/or other materials provided with the distribution.
401.1Sjnemeth *
411.1Sjnemeth * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
421.1Sjnemeth * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
431.1Sjnemeth * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
441.1Sjnemeth * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
451.1Sjnemeth * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
461.1Sjnemeth * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
471.1Sjnemeth * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
481.1Sjnemeth * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
491.1Sjnemeth * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
501.1Sjnemeth * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
511.1Sjnemeth */
521.1Sjnemeth
531.1Sjnemeth#include <sys/cdefs.h>
541.7Sjakllsch__KERNEL_RCSID(0, "$NetBSD: siisata_pci.c,v 1.7 2010/01/30 16:16:35 jakllsch Exp $");
551.1Sjnemeth
561.1Sjnemeth#include <sys/types.h>
571.1Sjnemeth#include <sys/malloc.h>
581.1Sjnemeth#include <sys/param.h>
591.1Sjnemeth#include <sys/kernel.h>
601.1Sjnemeth#include <sys/systm.h>
611.1Sjnemeth
621.1Sjnemeth#include <uvm/uvm_extern.h>
631.1Sjnemeth
641.1Sjnemeth#include <dev/pci/pcivar.h>
651.1Sjnemeth#include <dev/pci/pcidevs.h>
661.1Sjnemeth#include <dev/ic/siisatavar.h>
671.1Sjnemeth
681.1Sjnemethstruct siisata_pci_softc {
691.1Sjnemeth	struct siisata_softc si_sc;
701.1Sjnemeth	pci_chipset_tag_t sc_pc;
711.1Sjnemeth	pcitag_t sc_pcitag;
721.3Sjakllsch	void * sc_ih;
731.1Sjnemeth};
741.1Sjnemeth
751.1Sjnemethstatic int siisata_pci_match(device_t, cfdata_t, void *);
761.1Sjnemethstatic void siisata_pci_attach(device_t, device_t, void *);
771.3Sjakllschstatic int siisata_pci_detach(device_t, int);
781.6Sdyoungstatic bool siisata_pci_resume(device_t, pmf_qual_t);
791.1Sjnemeth
801.4Sjakllschstruct siisata_pci_board {
811.4Sjakllsch	pci_vendor_id_t		spb_vend;
821.4Sjakllsch	pci_product_id_t	spb_prod;
831.4Sjakllsch	uint16_t		spb_port;
841.4Sjakllsch	uint16_t		spb_chip;
851.4Sjakllsch};
861.1Sjnemeth
871.4Sjakllschstatic const struct siisata_pci_board siisata_pci_boards[] = {
881.1Sjnemeth	{
891.4Sjakllsch		.spb_vend = PCI_VENDOR_CMDTECH,
901.4Sjakllsch		.spb_prod = PCI_PRODUCT_CMDTECH_3124,
911.4Sjakllsch		.spb_port = 4,
921.4Sjakllsch		.spb_chip = 3124,
931.1Sjnemeth	},
941.1Sjnemeth	{
951.4Sjakllsch		.spb_vend = PCI_VENDOR_CMDTECH,
961.4Sjakllsch		.spb_prod = PCI_PRODUCT_CMDTECH_3132,
971.4Sjakllsch		.spb_port = 2,
981.4Sjakllsch		.spb_chip = 3132,
991.1Sjnemeth	},
1001.1Sjnemeth	{
1011.4Sjakllsch		.spb_vend = PCI_VENDOR_CMDTECH,
1021.4Sjakllsch		.spb_prod = PCI_PRODUCT_CMDTECH_3531,
1031.4Sjakllsch		.spb_port = 1,
1041.4Sjakllsch		.spb_chip = 3531,
1051.1Sjnemeth	},
1061.1Sjnemeth};
1071.1Sjnemeth
1081.1SjnemethCFATTACH_DECL_NEW(siisata_pci, sizeof(struct siisata_pci_softc),
1091.3Sjakllsch    siisata_pci_match, siisata_pci_attach, siisata_pci_detach, NULL);
1101.1Sjnemeth
1111.4Sjakllschstatic const struct siisata_pci_board *
1121.1Sjnemethsiisata_pci_lookup(const struct pci_attach_args * pa)
1131.1Sjnemeth{
1141.4Sjakllsch	int i;
1151.1Sjnemeth
1161.4Sjakllsch	for (i = 0; i < __arraycount(siisata_pci_boards); i++) {
1171.4Sjakllsch		if (siisata_pci_boards[i].spb_vend != PCI_VENDOR(pa->pa_id))
1181.4Sjakllsch			continue;
1191.4Sjakllsch		if (siisata_pci_boards[i].spb_prod == PCI_PRODUCT(pa->pa_id))
1201.4Sjakllsch			return &siisata_pci_boards[i];
1211.1Sjnemeth	}
1221.4Sjakllsch
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 void
1381.1Sjnemethsiisata_pci_attach(device_t parent, device_t self, void *aux)
1391.1Sjnemeth{
1401.1Sjnemeth	struct pci_attach_args *pa = aux;
1411.1Sjnemeth	struct siisata_pci_softc *psc = device_private(self);
1421.1Sjnemeth	struct siisata_softc *sc = &psc->si_sc;
1431.1Sjnemeth	char devinfo[256];
1441.1Sjnemeth	const char *intrstr;
1451.1Sjnemeth	pcireg_t csr, memtype;
1461.4Sjakllsch	const struct siisata_pci_board *spbp;
1471.3Sjakllsch	pci_intr_handle_t intrhandle;
1481.1Sjnemeth	bus_space_tag_t memt;
1491.1Sjnemeth	bus_space_handle_t memh;
1501.1Sjnemeth	uint32_t gcreg;
1511.1Sjnemeth	int memh_valid;
1521.1Sjnemeth	bus_size_t grsize, prsize;
1531.1Sjnemeth
1541.1Sjnemeth	sc->sc_atac.atac_dev = self;
1551.1Sjnemeth
1561.1Sjnemeth	psc->sc_pc = pa->pa_pc;
1571.1Sjnemeth	psc->sc_pcitag = pa->pa_tag;
1581.1Sjnemeth
1591.1Sjnemeth	pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo, sizeof(devinfo));
1601.1Sjnemeth	aprint_naive(": SATA-II HBA\n");
1611.1Sjnemeth	aprint_normal(": %s\n", devinfo);
1621.1Sjnemeth
1631.4Sjakllsch	/* map BAR 0, global registers */
1641.1Sjnemeth	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, SIISATA_PCI_BAR0);
1651.1Sjnemeth	switch (memtype) {
1661.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
1671.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
1681.1Sjnemeth		memh_valid = (pci_mapreg_map(pa, SIISATA_PCI_BAR0,
1691.1Sjnemeth			memtype, 0, &memt, &memh, NULL, &grsize) == 0);
1701.1Sjnemeth		break;
1711.1Sjnemeth	default:
1721.1Sjnemeth		memh_valid = 0;
1731.1Sjnemeth	}
1741.1Sjnemeth	if (memh_valid) {
1751.1Sjnemeth		sc->sc_grt = memt;
1761.1Sjnemeth		sc->sc_grh = memh;
1771.3Sjakllsch		sc->sc_grs = grsize;
1781.1Sjnemeth	} else {
1791.4Sjakllsch		aprint_error_dev(self, "couldn't map global registers\n");
1801.1Sjnemeth		return;
1811.1Sjnemeth	}
1821.1Sjnemeth
1831.4Sjakllsch	/* map BAR 1, port registers */
1841.1Sjnemeth	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, SIISATA_PCI_BAR1);
1851.1Sjnemeth	switch (memtype) {
1861.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
1871.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
1881.1Sjnemeth		memh_valid = (pci_mapreg_map(pa, SIISATA_PCI_BAR1,
1891.1Sjnemeth			memtype, 0, &memt, &memh, NULL, &prsize) == 0);
1901.1Sjnemeth		break;
1911.1Sjnemeth	default:
1921.1Sjnemeth		memh_valid = 0;
1931.1Sjnemeth	}
1941.1Sjnemeth	if (memh_valid) {
1951.1Sjnemeth		sc->sc_prt = memt;
1961.1Sjnemeth		sc->sc_prh = memh;
1971.3Sjakllsch		sc->sc_prs = prsize;
1981.1Sjnemeth	} else {
1991.1Sjnemeth		bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize);
2001.4Sjakllsch		aprint_error_dev(self, "couldn't map port registers\n");
2011.1Sjnemeth		return;
2021.1Sjnemeth	}
2031.1Sjnemeth
2041.4Sjakllsch	if (pci_dma64_available(pa))
2051.1Sjnemeth		sc->sc_dmat = pa->pa_dmat64;
2061.4Sjakllsch	else
2071.1Sjnemeth		sc->sc_dmat = pa->pa_dmat;
2081.1Sjnemeth
2091.1Sjnemeth	/* map interrupt */
2101.1Sjnemeth	if (pci_intr_map(pa, &intrhandle) != 0) {
2111.1Sjnemeth		bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize);
2121.1Sjnemeth		bus_space_unmap(sc->sc_prt, sc->sc_prh, prsize);
2131.4Sjakllsch		aprint_error_dev(self, "couldn't map interrupt\n");
2141.1Sjnemeth		return;
2151.1Sjnemeth	}
2161.1Sjnemeth	intrstr = pci_intr_string(pa->pa_pc, intrhandle);
2171.3Sjakllsch	psc->sc_ih = pci_intr_establish(pa->pa_pc, intrhandle,
2181.1Sjnemeth	    IPL_BIO, siisata_intr, sc);
2191.3Sjakllsch	if (psc->sc_ih == NULL) {
2201.1Sjnemeth		bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize);
2211.1Sjnemeth		bus_space_unmap(sc->sc_prt, sc->sc_prh, prsize);
2221.4Sjakllsch		aprint_error_dev(self, "couldn't establish interrupt at %s\n",
2231.4Sjakllsch			intrstr);
2241.1Sjnemeth		return;
2251.1Sjnemeth	}
2261.4Sjakllsch	aprint_normal_dev(self, "interrupting at %s\n",
2271.4Sjakllsch		intrstr ? intrstr : "unknown interrupt");
2281.1Sjnemeth
2291.1Sjnemeth	/* fill in number of ports on this device */
2301.4Sjakllsch	spbp = siisata_pci_lookup(pa);
2311.4Sjakllsch	KASSERT(spbp != NULL);
2321.4Sjakllsch	sc->sc_atac.atac_nchannels = spbp->spb_port;
2331.1Sjnemeth
2341.2Sjakllsch	/* set the necessary bits in case the firmware didn't */
2351.2Sjakllsch	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
2361.2Sjakllsch	csr |= PCI_COMMAND_MASTER_ENABLE;
2371.2Sjakllsch	csr |= PCI_COMMAND_MEM_ENABLE;
2381.2Sjakllsch	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, csr);
2391.2Sjakllsch
2401.1Sjnemeth	gcreg = GRREAD(sc, GR_GC);
2411.1Sjnemeth
2421.4Sjakllsch	aprint_verbose_dev(self, "SiI%d, %sGb/s\n",
2431.4Sjakllsch		spbp->spb_chip, (gcreg & GR_GC_3GBPS) ? "3.0" : "1.5" );
2441.4Sjakllsch	if (spbp->spb_chip == 3124) {
2451.4Sjakllsch		short width;
2461.4Sjakllsch		short speed;
2471.4Sjakllsch		char pcix = 1;
2481.4Sjakllsch
2491.4Sjakllsch		width = (gcreg & GR_GC_REQ64) ? 64 : 32;
2501.4Sjakllsch
2511.1Sjnemeth		switch (gcreg & (GR_GC_DEVSEL | GR_GC_STOP | GR_GC_TRDY)) {
2521.1Sjnemeth		case 0:
2531.4Sjakllsch			speed = (gcreg & GR_GC_M66EN) ? 66 : 33;
2541.4Sjakllsch			pcix = 0;
2551.1Sjnemeth			break;
2561.1Sjnemeth		case GR_GC_TRDY:
2571.4Sjakllsch			speed = 66;
2581.1Sjnemeth			break;
2591.1Sjnemeth		case GR_GC_STOP:
2601.4Sjakllsch			speed = 100;
2611.1Sjnemeth			break;
2621.1Sjnemeth		case GR_GC_STOP | GR_GC_TRDY:
2631.4Sjakllsch			speed = 133;
2641.1Sjnemeth			break;
2651.1Sjnemeth		default:
2661.4Sjakllsch			speed = -1;
2671.1Sjnemeth			break;
2681.1Sjnemeth		}
2691.4Sjakllsch		aprint_verbose_dev(self, "%hd-bit %hdMHz PCI%s\n",
2701.4Sjakllsch			width, speed, pcix ? "-X" : "");
2711.1Sjnemeth	}
2721.1Sjnemeth
2731.1Sjnemeth	siisata_attach(sc);
2741.1Sjnemeth
2751.1Sjnemeth	if (!pmf_device_register(self, NULL, siisata_pci_resume))
2761.1Sjnemeth		aprint_error_dev(self, "couldn't establish power handler\n");
2771.1Sjnemeth}
2781.1Sjnemeth
2791.3Sjakllschstatic int
2801.3Sjakllschsiisata_pci_detach(device_t dv, int flags)
2811.3Sjakllsch{
2821.3Sjakllsch	struct siisata_pci_softc *psc = device_private(dv);
2831.3Sjakllsch	struct siisata_softc *sc = &psc->si_sc;
2841.3Sjakllsch	int rv;
2851.3Sjakllsch
2861.3Sjakllsch	rv = siisata_detach(sc, flags);
2871.3Sjakllsch	if (rv)
2881.3Sjakllsch		return rv;
2891.3Sjakllsch
2901.3Sjakllsch	if (psc->sc_ih != NULL) {
2911.3Sjakllsch		pci_intr_disestablish(psc->sc_pc, psc->sc_ih);
2921.3Sjakllsch	}
2931.3Sjakllsch
2941.3Sjakllsch	bus_space_unmap(sc->sc_prt, sc->sc_prh, sc->sc_prs);
2951.3Sjakllsch	bus_space_unmap(sc->sc_grt, sc->sc_grh, sc->sc_grs);
2961.3Sjakllsch
2971.3Sjakllsch	return 0;
2981.3Sjakllsch}
2991.3Sjakllsch
3001.3Sjakllschstatic bool
3011.6Sdyoungsiisata_pci_resume(device_t dv, pmf_qual_t qual)
3021.3Sjakllsch{
3031.3Sjakllsch	struct siisata_pci_softc *psc = device_private(dv);
3041.3Sjakllsch	struct siisata_softc *sc = &psc->si_sc;
3051.3Sjakllsch	int s;
3061.3Sjakllsch
3071.3Sjakllsch	s = splbio();
3081.3Sjakllsch	siisata_resume(sc);
3091.3Sjakllsch	splx(s);
3101.3Sjakllsch
3111.3Sjakllsch	return true;
3121.3Sjakllsch}
313