siisata_pci.c revision 1.14
11.14Smsaitoh/* $NetBSD: siisata_pci.c,v 1.14 2016/07/14 04:19:27 msaitoh 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.14Smsaitoh__KERNEL_RCSID(0, "$NetBSD: siisata_pci.c,v 1.14 2016/07/14 04:19:27 msaitoh 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 <dev/pci/pcivar.h>
631.1Sjnemeth#include <dev/pci/pcidevs.h>
641.1Sjnemeth#include <dev/ic/siisatavar.h>
651.1Sjnemeth
661.1Sjnemethstruct siisata_pci_softc {
671.1Sjnemeth	struct siisata_softc si_sc;
681.1Sjnemeth	pci_chipset_tag_t sc_pc;
691.1Sjnemeth	pcitag_t sc_pcitag;
701.3Sjakllsch	void * sc_ih;
711.1Sjnemeth};
721.1Sjnemeth
731.1Sjnemethstatic int siisata_pci_match(device_t, cfdata_t, void *);
741.1Sjnemethstatic void siisata_pci_attach(device_t, device_t, void *);
751.3Sjakllschstatic int siisata_pci_detach(device_t, int);
761.8Sdyoungstatic bool siisata_pci_resume(device_t, const pmf_qual_t *);
771.1Sjnemeth
781.4Sjakllschstruct siisata_pci_board {
791.4Sjakllsch	pci_vendor_id_t		spb_vend;
801.4Sjakllsch	pci_product_id_t	spb_prod;
811.4Sjakllsch	uint16_t		spb_port;
821.4Sjakllsch	uint16_t		spb_chip;
831.4Sjakllsch};
841.1Sjnemeth
851.4Sjakllschstatic const struct siisata_pci_board siisata_pci_boards[] = {
861.1Sjnemeth	{
871.4Sjakllsch		.spb_vend = PCI_VENDOR_CMDTECH,
881.4Sjakllsch		.spb_prod = PCI_PRODUCT_CMDTECH_3124,
891.4Sjakllsch		.spb_port = 4,
901.4Sjakllsch		.spb_chip = 3124,
911.1Sjnemeth	},
921.1Sjnemeth	{
931.4Sjakllsch		.spb_vend = PCI_VENDOR_CMDTECH,
941.4Sjakllsch		.spb_prod = PCI_PRODUCT_CMDTECH_3132,
951.14Smsaitoh		.spb_port = 2,
961.4Sjakllsch		.spb_chip = 3132,
971.1Sjnemeth	},
981.1Sjnemeth	{
991.4Sjakllsch		.spb_vend = PCI_VENDOR_CMDTECH,
1001.4Sjakllsch		.spb_prod = PCI_PRODUCT_CMDTECH_3531,
1011.4Sjakllsch		.spb_port = 1,
1021.4Sjakllsch		.spb_chip = 3531,
1031.1Sjnemeth	},
1041.1Sjnemeth};
1051.1Sjnemeth
1061.1SjnemethCFATTACH_DECL_NEW(siisata_pci, sizeof(struct siisata_pci_softc),
1071.3Sjakllsch    siisata_pci_match, siisata_pci_attach, siisata_pci_detach, NULL);
1081.1Sjnemeth
1091.4Sjakllschstatic const struct siisata_pci_board *
1101.1Sjnemethsiisata_pci_lookup(const struct pci_attach_args * pa)
1111.1Sjnemeth{
1121.4Sjakllsch	int i;
1131.1Sjnemeth
1141.4Sjakllsch	for (i = 0; i < __arraycount(siisata_pci_boards); i++) {
1151.4Sjakllsch		if (siisata_pci_boards[i].spb_vend != PCI_VENDOR(pa->pa_id))
1161.4Sjakllsch			continue;
1171.4Sjakllsch		if (siisata_pci_boards[i].spb_prod == PCI_PRODUCT(pa->pa_id))
1181.4Sjakllsch			return &siisata_pci_boards[i];
1191.1Sjnemeth	}
1201.4Sjakllsch
1211.1Sjnemeth	return NULL;
1221.1Sjnemeth}
1231.1Sjnemeth
1241.1Sjnemethstatic int
1251.1Sjnemethsiisata_pci_match(device_t parent, cfdata_t match, void *aux)
1261.1Sjnemeth{
1271.1Sjnemeth	struct pci_attach_args *pa = aux;
1281.1Sjnemeth
1291.1Sjnemeth	if (siisata_pci_lookup(pa) != NULL)
1301.1Sjnemeth		return 3;
1311.1Sjnemeth
1321.1Sjnemeth	return 0;
1331.1Sjnemeth}
1341.1Sjnemeth
1351.1Sjnemethstatic void
1361.1Sjnemethsiisata_pci_attach(device_t parent, device_t self, void *aux)
1371.1Sjnemeth{
1381.1Sjnemeth	struct pci_attach_args *pa = aux;
1391.1Sjnemeth	struct siisata_pci_softc *psc = device_private(self);
1401.1Sjnemeth	struct siisata_softc *sc = &psc->si_sc;
1411.1Sjnemeth	const char *intrstr;
1421.1Sjnemeth	pcireg_t csr, memtype;
1431.4Sjakllsch	const struct siisata_pci_board *spbp;
1441.3Sjakllsch	pci_intr_handle_t intrhandle;
1451.1Sjnemeth	bus_space_tag_t memt;
1461.1Sjnemeth	bus_space_handle_t memh;
1471.1Sjnemeth	uint32_t gcreg;
1481.1Sjnemeth	int memh_valid;
1491.1Sjnemeth	bus_size_t grsize, prsize;
1501.13Schristos	char intrbuf[PCI_INTRSTR_LEN];
1511.1Sjnemeth
1521.1Sjnemeth	sc->sc_atac.atac_dev = self;
1531.14Smsaitoh
1541.1Sjnemeth	psc->sc_pc = pa->pa_pc;
1551.1Sjnemeth	psc->sc_pcitag = pa->pa_tag;
1561.1Sjnemeth
1571.10Sdrochner	pci_aprint_devinfo(pa, "SATA-II HBA");
1581.1Sjnemeth
1591.4Sjakllsch	/* map BAR 0, global registers */
1601.1Sjnemeth	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, SIISATA_PCI_BAR0);
1611.1Sjnemeth	switch (memtype) {
1621.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
1631.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
1641.1Sjnemeth		memh_valid = (pci_mapreg_map(pa, SIISATA_PCI_BAR0,
1651.1Sjnemeth			memtype, 0, &memt, &memh, NULL, &grsize) == 0);
1661.1Sjnemeth		break;
1671.1Sjnemeth	default:
1681.1Sjnemeth		memh_valid = 0;
1691.1Sjnemeth	}
1701.1Sjnemeth	if (memh_valid) {
1711.1Sjnemeth		sc->sc_grt = memt;
1721.1Sjnemeth		sc->sc_grh = memh;
1731.3Sjakllsch		sc->sc_grs = grsize;
1741.1Sjnemeth	} else {
1751.4Sjakllsch		aprint_error_dev(self, "couldn't map global registers\n");
1761.1Sjnemeth		return;
1771.1Sjnemeth	}
1781.1Sjnemeth
1791.4Sjakllsch	/* map BAR 1, port registers */
1801.1Sjnemeth	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, SIISATA_PCI_BAR1);
1811.1Sjnemeth	switch (memtype) {
1821.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
1831.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
1841.1Sjnemeth		memh_valid = (pci_mapreg_map(pa, SIISATA_PCI_BAR1,
1851.1Sjnemeth			memtype, 0, &memt, &memh, NULL, &prsize) == 0);
1861.1Sjnemeth		break;
1871.1Sjnemeth	default:
1881.1Sjnemeth		memh_valid = 0;
1891.1Sjnemeth	}
1901.1Sjnemeth	if (memh_valid) {
1911.1Sjnemeth		sc->sc_prt = memt;
1921.1Sjnemeth		sc->sc_prh = memh;
1931.3Sjakllsch		sc->sc_prs = prsize;
1941.1Sjnemeth	} else {
1951.1Sjnemeth		bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize);
1961.4Sjakllsch		aprint_error_dev(self, "couldn't map port registers\n");
1971.1Sjnemeth		return;
1981.1Sjnemeth	}
1991.1Sjnemeth
2001.4Sjakllsch	if (pci_dma64_available(pa))
2011.1Sjnemeth		sc->sc_dmat = pa->pa_dmat64;
2021.4Sjakllsch	else
2031.1Sjnemeth		sc->sc_dmat = pa->pa_dmat;
2041.1Sjnemeth
2051.1Sjnemeth	/* map interrupt */
2061.1Sjnemeth	if (pci_intr_map(pa, &intrhandle) != 0) {
2071.1Sjnemeth		bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize);
2081.1Sjnemeth		bus_space_unmap(sc->sc_prt, sc->sc_prh, prsize);
2091.4Sjakllsch		aprint_error_dev(self, "couldn't map interrupt\n");
2101.1Sjnemeth		return;
2111.1Sjnemeth	}
2121.14Smsaitoh	intrstr = pci_intr_string(pa->pa_pc, intrhandle, intrbuf,
2131.14Smsaitoh	    sizeof(intrbuf));
2141.3Sjakllsch	psc->sc_ih = pci_intr_establish(pa->pa_pc, intrhandle,
2151.1Sjnemeth	    IPL_BIO, siisata_intr, sc);
2161.3Sjakllsch	if (psc->sc_ih == NULL) {
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 establish interrupt at %s\n",
2201.4Sjakllsch			intrstr);
2211.1Sjnemeth		return;
2221.1Sjnemeth	}
2231.4Sjakllsch	aprint_normal_dev(self, "interrupting at %s\n",
2241.4Sjakllsch		intrstr ? intrstr : "unknown interrupt");
2251.1Sjnemeth
2261.1Sjnemeth	/* fill in number of ports on this device */
2271.4Sjakllsch	spbp = siisata_pci_lookup(pa);
2281.4Sjakllsch	KASSERT(spbp != NULL);
2291.4Sjakllsch	sc->sc_atac.atac_nchannels = spbp->spb_port;
2301.1Sjnemeth
2311.2Sjakllsch	/* set the necessary bits in case the firmware didn't */
2321.2Sjakllsch	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
2331.2Sjakllsch	csr |= PCI_COMMAND_MASTER_ENABLE;
2341.2Sjakllsch	csr |= PCI_COMMAND_MEM_ENABLE;
2351.2Sjakllsch	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, csr);
2361.2Sjakllsch
2371.1Sjnemeth	gcreg = GRREAD(sc, GR_GC);
2381.1Sjnemeth
2391.4Sjakllsch	aprint_verbose_dev(self, "SiI%d, %sGb/s\n",
2401.4Sjakllsch		spbp->spb_chip, (gcreg & GR_GC_3GBPS) ? "3.0" : "1.5" );
2411.4Sjakllsch	if (spbp->spb_chip == 3124) {
2421.4Sjakllsch		short width;
2431.4Sjakllsch		short speed;
2441.4Sjakllsch		char pcix = 1;
2451.4Sjakllsch
2461.4Sjakllsch		width = (gcreg & GR_GC_REQ64) ? 64 : 32;
2471.4Sjakllsch
2481.1Sjnemeth		switch (gcreg & (GR_GC_DEVSEL | GR_GC_STOP | GR_GC_TRDY)) {
2491.1Sjnemeth		case 0:
2501.4Sjakllsch			speed = (gcreg & GR_GC_M66EN) ? 66 : 33;
2511.4Sjakllsch			pcix = 0;
2521.1Sjnemeth			break;
2531.1Sjnemeth		case GR_GC_TRDY:
2541.4Sjakllsch			speed = 66;
2551.1Sjnemeth			break;
2561.1Sjnemeth		case GR_GC_STOP:
2571.4Sjakllsch			speed = 100;
2581.1Sjnemeth			break;
2591.1Sjnemeth		case GR_GC_STOP | GR_GC_TRDY:
2601.4Sjakllsch			speed = 133;
2611.1Sjnemeth			break;
2621.1Sjnemeth		default:
2631.4Sjakllsch			speed = -1;
2641.1Sjnemeth			break;
2651.1Sjnemeth		}
2661.4Sjakllsch		aprint_verbose_dev(self, "%hd-bit %hdMHz PCI%s\n",
2671.4Sjakllsch			width, speed, pcix ? "-X" : "");
2681.1Sjnemeth	}
2691.1Sjnemeth
2701.1Sjnemeth	siisata_attach(sc);
2711.1Sjnemeth
2721.1Sjnemeth	if (!pmf_device_register(self, NULL, siisata_pci_resume))
2731.1Sjnemeth		aprint_error_dev(self, "couldn't establish power handler\n");
2741.1Sjnemeth}
2751.1Sjnemeth
2761.3Sjakllschstatic int
2771.3Sjakllschsiisata_pci_detach(device_t dv, int flags)
2781.3Sjakllsch{
2791.3Sjakllsch	struct siisata_pci_softc *psc = device_private(dv);
2801.3Sjakllsch	struct siisata_softc *sc = &psc->si_sc;
2811.3Sjakllsch	int rv;
2821.3Sjakllsch
2831.3Sjakllsch	rv = siisata_detach(sc, flags);
2841.3Sjakllsch	if (rv)
2851.3Sjakllsch		return rv;
2861.3Sjakllsch
2871.3Sjakllsch	if (psc->sc_ih != NULL) {
2881.3Sjakllsch		pci_intr_disestablish(psc->sc_pc, psc->sc_ih);
2891.3Sjakllsch	}
2901.3Sjakllsch
2911.3Sjakllsch	bus_space_unmap(sc->sc_prt, sc->sc_prh, sc->sc_prs);
2921.3Sjakllsch	bus_space_unmap(sc->sc_grt, sc->sc_grh, sc->sc_grs);
2931.14Smsaitoh
2941.3Sjakllsch	return 0;
2951.3Sjakllsch}
2961.3Sjakllsch
2971.3Sjakllschstatic bool
2981.8Sdyoungsiisata_pci_resume(device_t dv, const pmf_qual_t *qual)
2991.3Sjakllsch{
3001.3Sjakllsch	struct siisata_pci_softc *psc = device_private(dv);
3011.3Sjakllsch	struct siisata_softc *sc = &psc->si_sc;
3021.3Sjakllsch	int s;
3031.3Sjakllsch
3041.3Sjakllsch	s = splbio();
3051.3Sjakllsch	siisata_resume(sc);
3061.3Sjakllsch	splx(s);
3071.14Smsaitoh
3081.3Sjakllsch	return true;
3091.3Sjakllsch}
310