siisata_pci.c revision 1.18
11.18Sjdolecek/* $NetBSD: siisata_pci.c,v 1.18 2018/10/22 21:40:45 jdolecek 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.18Sjdolecek__KERNEL_RCSID(0, "$NetBSD: siisata_pci.c,v 1.18 2018/10/22 21:40:45 jdolecek 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.17Sjdolecek	pci_intr_handle_t *sc_pihp;
711.17Sjdolecek	void *sc_ih;
721.1Sjnemeth};
731.1Sjnemeth
741.1Sjnemethstatic int siisata_pci_match(device_t, cfdata_t, void *);
751.1Sjnemethstatic void siisata_pci_attach(device_t, device_t, void *);
761.3Sjakllschstatic int siisata_pci_detach(device_t, int);
771.8Sdyoungstatic bool siisata_pci_resume(device_t, const pmf_qual_t *);
781.1Sjnemeth
791.4Sjakllschstruct siisata_pci_board {
801.4Sjakllsch	pci_vendor_id_t		spb_vend;
811.4Sjakllsch	pci_product_id_t	spb_prod;
821.4Sjakllsch	uint16_t		spb_port;
831.4Sjakllsch	uint16_t		spb_chip;
841.4Sjakllsch};
851.1Sjnemeth
861.4Sjakllschstatic const struct siisata_pci_board siisata_pci_boards[] = {
871.1Sjnemeth	{
881.4Sjakllsch		.spb_vend = PCI_VENDOR_CMDTECH,
891.4Sjakllsch		.spb_prod = PCI_PRODUCT_CMDTECH_3124,
901.4Sjakllsch		.spb_port = 4,
911.4Sjakllsch		.spb_chip = 3124,
921.1Sjnemeth	},
931.1Sjnemeth	{
941.4Sjakllsch		.spb_vend = PCI_VENDOR_CMDTECH,
951.4Sjakllsch		.spb_prod = PCI_PRODUCT_CMDTECH_3132,
961.14Smsaitoh		.spb_port = 2,
971.4Sjakllsch		.spb_chip = 3132,
981.1Sjnemeth	},
991.1Sjnemeth	{
1001.4Sjakllsch		.spb_vend = PCI_VENDOR_CMDTECH,
1011.15Sjdolecek		.spb_prod = PCI_PRODUCT_CMDTECH_AAR_1220SA,
1021.15Sjdolecek		.spb_port = 2,
1031.15Sjdolecek		.spb_chip = 3132,
1041.15Sjdolecek	},
1051.15Sjdolecek	{
1061.15Sjdolecek		.spb_vend = PCI_VENDOR_CMDTECH,
1071.4Sjakllsch		.spb_prod = PCI_PRODUCT_CMDTECH_3531,
1081.4Sjakllsch		.spb_port = 1,
1091.4Sjakllsch		.spb_chip = 3531,
1101.1Sjnemeth	},
1111.1Sjnemeth};
1121.1Sjnemeth
1131.1SjnemethCFATTACH_DECL_NEW(siisata_pci, sizeof(struct siisata_pci_softc),
1141.3Sjakllsch    siisata_pci_match, siisata_pci_attach, siisata_pci_detach, NULL);
1151.1Sjnemeth
1161.4Sjakllschstatic const struct siisata_pci_board *
1171.1Sjnemethsiisata_pci_lookup(const struct pci_attach_args * pa)
1181.1Sjnemeth{
1191.4Sjakllsch	int i;
1201.1Sjnemeth
1211.4Sjakllsch	for (i = 0; i < __arraycount(siisata_pci_boards); i++) {
1221.4Sjakllsch		if (siisata_pci_boards[i].spb_vend != PCI_VENDOR(pa->pa_id))
1231.4Sjakllsch			continue;
1241.4Sjakllsch		if (siisata_pci_boards[i].spb_prod == PCI_PRODUCT(pa->pa_id))
1251.4Sjakllsch			return &siisata_pci_boards[i];
1261.1Sjnemeth	}
1271.4Sjakllsch
1281.1Sjnemeth	return NULL;
1291.1Sjnemeth}
1301.1Sjnemeth
1311.1Sjnemethstatic int
1321.1Sjnemethsiisata_pci_match(device_t parent, cfdata_t match, void *aux)
1331.1Sjnemeth{
1341.1Sjnemeth	struct pci_attach_args *pa = aux;
1351.1Sjnemeth
1361.1Sjnemeth	if (siisata_pci_lookup(pa) != NULL)
1371.1Sjnemeth		return 3;
1381.1Sjnemeth
1391.1Sjnemeth	return 0;
1401.1Sjnemeth}
1411.1Sjnemeth
1421.1Sjnemethstatic void
1431.1Sjnemethsiisata_pci_attach(device_t parent, device_t self, void *aux)
1441.1Sjnemeth{
1451.1Sjnemeth	struct pci_attach_args *pa = aux;
1461.1Sjnemeth	struct siisata_pci_softc *psc = device_private(self);
1471.1Sjnemeth	struct siisata_softc *sc = &psc->si_sc;
1481.1Sjnemeth	const char *intrstr;
1491.1Sjnemeth	pcireg_t csr, memtype;
1501.4Sjakllsch	const struct siisata_pci_board *spbp;
1511.1Sjnemeth	bus_space_tag_t memt;
1521.1Sjnemeth	bus_space_handle_t memh;
1531.1Sjnemeth	uint32_t gcreg;
1541.1Sjnemeth	int memh_valid;
1551.1Sjnemeth	bus_size_t grsize, prsize;
1561.13Schristos	char intrbuf[PCI_INTRSTR_LEN];
1571.1Sjnemeth
1581.1Sjnemeth	sc->sc_atac.atac_dev = self;
1591.14Smsaitoh
1601.1Sjnemeth	psc->sc_pc = pa->pa_pc;
1611.1Sjnemeth	psc->sc_pcitag = pa->pa_tag;
1621.1Sjnemeth
1631.10Sdrochner	pci_aprint_devinfo(pa, "SATA-II HBA");
1641.1Sjnemeth
1651.4Sjakllsch	/* map BAR 0, global registers */
1661.1Sjnemeth	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, SIISATA_PCI_BAR0);
1671.1Sjnemeth	switch (memtype) {
1681.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
1691.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
1701.1Sjnemeth		memh_valid = (pci_mapreg_map(pa, SIISATA_PCI_BAR0,
1711.1Sjnemeth			memtype, 0, &memt, &memh, NULL, &grsize) == 0);
1721.1Sjnemeth		break;
1731.1Sjnemeth	default:
1741.1Sjnemeth		memh_valid = 0;
1751.1Sjnemeth	}
1761.1Sjnemeth	if (memh_valid) {
1771.1Sjnemeth		sc->sc_grt = memt;
1781.1Sjnemeth		sc->sc_grh = memh;
1791.3Sjakllsch		sc->sc_grs = grsize;
1801.1Sjnemeth	} else {
1811.4Sjakllsch		aprint_error_dev(self, "couldn't map global registers\n");
1821.1Sjnemeth		return;
1831.1Sjnemeth	}
1841.1Sjnemeth
1851.4Sjakllsch	/* map BAR 1, port registers */
1861.1Sjnemeth	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, SIISATA_PCI_BAR1);
1871.1Sjnemeth	switch (memtype) {
1881.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
1891.1Sjnemeth	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
1901.1Sjnemeth		memh_valid = (pci_mapreg_map(pa, SIISATA_PCI_BAR1,
1911.1Sjnemeth			memtype, 0, &memt, &memh, NULL, &prsize) == 0);
1921.1Sjnemeth		break;
1931.1Sjnemeth	default:
1941.1Sjnemeth		memh_valid = 0;
1951.1Sjnemeth	}
1961.1Sjnemeth	if (memh_valid) {
1971.1Sjnemeth		sc->sc_prt = memt;
1981.1Sjnemeth		sc->sc_prh = memh;
1991.3Sjakllsch		sc->sc_prs = prsize;
2001.1Sjnemeth	} else {
2011.1Sjnemeth		bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize);
2021.4Sjakllsch		aprint_error_dev(self, "couldn't map port registers\n");
2031.1Sjnemeth		return;
2041.1Sjnemeth	}
2051.1Sjnemeth
2061.4Sjakllsch	if (pci_dma64_available(pa))
2071.1Sjnemeth		sc->sc_dmat = pa->pa_dmat64;
2081.4Sjakllsch	else
2091.1Sjnemeth		sc->sc_dmat = pa->pa_dmat;
2101.1Sjnemeth
2111.1Sjnemeth	/* map interrupt */
2121.17Sjdolecek	if (pci_intr_alloc(pa, &psc->sc_pihp, NULL, 0) != 0) {
2131.1Sjnemeth		bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize);
2141.1Sjnemeth		bus_space_unmap(sc->sc_prt, sc->sc_prh, prsize);
2151.4Sjakllsch		aprint_error_dev(self, "couldn't map interrupt\n");
2161.1Sjnemeth		return;
2171.1Sjnemeth	}
2181.17Sjdolecek	intrstr = pci_intr_string(pa->pa_pc, psc->sc_pihp[0], intrbuf,
2191.14Smsaitoh	    sizeof(intrbuf));
2201.17Sjdolecek	psc->sc_ih = pci_intr_establish_xname(pa->pa_pc, psc->sc_pihp[0],
2211.16Sjdolecek	    IPL_BIO, siisata_intr, sc, device_xname(self));
2221.3Sjakllsch	if (psc->sc_ih == NULL) {
2231.1Sjnemeth		bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize);
2241.1Sjnemeth		bus_space_unmap(sc->sc_prt, sc->sc_prh, prsize);
2251.4Sjakllsch		aprint_error_dev(self, "couldn't establish interrupt at %s\n",
2261.4Sjakllsch			intrstr);
2271.1Sjnemeth		return;
2281.1Sjnemeth	}
2291.4Sjakllsch	aprint_normal_dev(self, "interrupting at %s\n",
2301.4Sjakllsch		intrstr ? intrstr : "unknown interrupt");
2311.1Sjnemeth
2321.1Sjnemeth	/* fill in number of ports on this device */
2331.4Sjakllsch	spbp = siisata_pci_lookup(pa);
2341.4Sjakllsch	KASSERT(spbp != NULL);
2351.4Sjakllsch	sc->sc_atac.atac_nchannels = spbp->spb_port;
2361.1Sjnemeth
2371.2Sjakllsch	/* set the necessary bits in case the firmware didn't */
2381.2Sjakllsch	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
2391.2Sjakllsch	csr |= PCI_COMMAND_MASTER_ENABLE;
2401.2Sjakllsch	csr |= PCI_COMMAND_MEM_ENABLE;
2411.2Sjakllsch	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, csr);
2421.2Sjakllsch
2431.1Sjnemeth	gcreg = GRREAD(sc, GR_GC);
2441.1Sjnemeth
2451.4Sjakllsch	aprint_verbose_dev(self, "SiI%d, %sGb/s\n",
2461.4Sjakllsch		spbp->spb_chip, (gcreg & GR_GC_3GBPS) ? "3.0" : "1.5" );
2471.4Sjakllsch	if (spbp->spb_chip == 3124) {
2481.4Sjakllsch		short width;
2491.4Sjakllsch		short speed;
2501.4Sjakllsch		char pcix = 1;
2511.4Sjakllsch
2521.4Sjakllsch		width = (gcreg & GR_GC_REQ64) ? 64 : 32;
2531.4Sjakllsch
2541.1Sjnemeth		switch (gcreg & (GR_GC_DEVSEL | GR_GC_STOP | GR_GC_TRDY)) {
2551.1Sjnemeth		case 0:
2561.4Sjakllsch			speed = (gcreg & GR_GC_M66EN) ? 66 : 33;
2571.4Sjakllsch			pcix = 0;
2581.1Sjnemeth			break;
2591.1Sjnemeth		case GR_GC_TRDY:
2601.4Sjakllsch			speed = 66;
2611.1Sjnemeth			break;
2621.1Sjnemeth		case GR_GC_STOP:
2631.4Sjakllsch			speed = 100;
2641.1Sjnemeth			break;
2651.1Sjnemeth		case GR_GC_STOP | GR_GC_TRDY:
2661.4Sjakllsch			speed = 133;
2671.1Sjnemeth			break;
2681.1Sjnemeth		default:
2691.4Sjakllsch			speed = -1;
2701.1Sjnemeth			break;
2711.1Sjnemeth		}
2721.4Sjakllsch		aprint_verbose_dev(self, "%hd-bit %hdMHz PCI%s\n",
2731.4Sjakllsch			width, speed, pcix ? "-X" : "");
2741.1Sjnemeth	}
2751.1Sjnemeth
2761.1Sjnemeth	siisata_attach(sc);
2771.1Sjnemeth
2781.1Sjnemeth	if (!pmf_device_register(self, NULL, siisata_pci_resume))
2791.1Sjnemeth		aprint_error_dev(self, "couldn't establish power handler\n");
2801.1Sjnemeth}
2811.1Sjnemeth
2821.3Sjakllschstatic int
2831.3Sjakllschsiisata_pci_detach(device_t dv, int flags)
2841.3Sjakllsch{
2851.3Sjakllsch	struct siisata_pci_softc *psc = device_private(dv);
2861.3Sjakllsch	struct siisata_softc *sc = &psc->si_sc;
2871.3Sjakllsch	int rv;
2881.3Sjakllsch
2891.3Sjakllsch	rv = siisata_detach(sc, flags);
2901.3Sjakllsch	if (rv)
2911.3Sjakllsch		return rv;
2921.3Sjakllsch
2931.18Sjdolecek	if (psc->sc_ih != NULL) {
2941.18Sjdolecek		pci_intr_disestablish(psc->sc_pc, psc->sc_ih);
2951.18Sjdolecek		psc->sc_ih = NULL;
2961.18Sjdolecek	}
2971.18Sjdolecek
2981.17Sjdolecek	if (psc->sc_pihp != NULL) {
2991.17Sjdolecek		pci_intr_release(psc->sc_pc, psc->sc_pihp, 1);
3001.17Sjdolecek		psc->sc_pihp = NULL;
3011.17Sjdolecek	}
3021.17Sjdolecek
3031.3Sjakllsch	bus_space_unmap(sc->sc_prt, sc->sc_prh, sc->sc_prs);
3041.3Sjakllsch	bus_space_unmap(sc->sc_grt, sc->sc_grh, sc->sc_grs);
3051.14Smsaitoh
3061.3Sjakllsch	return 0;
3071.3Sjakllsch}
3081.3Sjakllsch
3091.3Sjakllschstatic bool
3101.8Sdyoungsiisata_pci_resume(device_t dv, const pmf_qual_t *qual)
3111.3Sjakllsch{
3121.3Sjakllsch	struct siisata_pci_softc *psc = device_private(dv);
3131.3Sjakllsch	struct siisata_softc *sc = &psc->si_sc;
3141.3Sjakllsch	int s;
3151.3Sjakllsch
3161.3Sjakllsch	s = splbio();
3171.3Sjakllsch	siisata_resume(sc);
3181.3Sjakllsch	splx(s);
3191.14Smsaitoh
3201.3Sjakllsch	return true;
3211.3Sjakllsch}
322