1/* $OpenBSD: sili_pci.c,v 1.16 2024/05/24 06:02:58 jsg Exp $ */ 2 3/* 4 * Copyright (c) 2007 David Gwynne <dlg@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/param.h> 20#include <sys/systm.h> 21#include <sys/device.h> 22#include <sys/timeout.h> 23 24#include <machine/bus.h> 25 26#include <dev/pci/pcireg.h> 27#include <dev/pci/pcivar.h> 28#include <dev/pci/pcidevs.h> 29 30#include <dev/ata/atascsi.h> 31 32#include <dev/ic/silireg.h> 33#include <dev/ic/silivar.h> 34 35int sili_pci_match(struct device *, void *, void *); 36void sili_pci_attach(struct device *, struct device *, void *); 37int sili_pci_detach(struct device *, int); 38int sili_pci_activate(struct device *, int); 39 40struct sili_pci_softc { 41 struct sili_softc psc_sili; 42 43 pci_chipset_tag_t psc_pc; 44 pcitag_t psc_tag; 45 46 void *psc_ih; 47}; 48 49const struct cfattach sili_pci_ca = { 50 sizeof(struct sili_pci_softc), 51 sili_pci_match, 52 sili_pci_attach, 53 sili_pci_detach, 54 sili_pci_activate 55}; 56 57struct sili_device { 58 pci_vendor_id_t sd_vendor; 59 pci_product_id_t sd_product; 60 u_int sd_nports; 61}; 62 63const struct sili_device *sili_lookup(struct pci_attach_args *); 64 65static const struct sili_device sili_devices[] = { 66 { PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_3124, 4 }, 67 { PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_3131, 1 }, 68 { PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_3132, 2 }, 69 { PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_3531, 1 }, 70 { PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_AAR_1220SA, 2 }, 71 { PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_AAR_1225SA, 2 }, 72 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_3124, 4 } 73}; 74 75const struct sili_device * 76sili_lookup(struct pci_attach_args *pa) 77{ 78 int i; 79 const struct sili_device *sd; 80 81 for (i = 0; i < nitems(sili_devices); i++) { 82 sd = &sili_devices[i]; 83 if (sd->sd_vendor == PCI_VENDOR(pa->pa_id) && 84 sd->sd_product == PCI_PRODUCT(pa->pa_id)) 85 return (sd); 86 } 87 88 return (NULL); 89} 90 91int 92sili_pci_match(struct device *parent, void *match, void *aux) 93{ 94 return (sili_lookup((struct pci_attach_args *)aux) != NULL); 95} 96 97void 98sili_pci_attach(struct device *parent, struct device *self, void *aux) 99{ 100 struct sili_pci_softc *psc = (void *)self; 101 struct sili_softc *sc = &psc->psc_sili; 102 struct pci_attach_args *pa = aux; 103 const struct sili_device *sd; 104 pcireg_t memtype; 105 pci_intr_handle_t ih; 106 const char *intrstr; 107 108 sd = sili_lookup(pa); 109 110 psc->psc_pc = pa->pa_pc; 111 psc->psc_tag = pa->pa_tag; 112 psc->psc_ih = NULL; 113 sc->sc_dmat = pa->pa_dmat; 114 sc->sc_ios_global = 0; 115 sc->sc_ios_port = 0; 116 sc->sc_nports = sd->sd_nports; 117 118 memtype = pci_mapreg_type(psc->psc_pc, psc->psc_tag, 119 SILI_PCI_BAR_GLOBAL); 120 if (pci_mapreg_map(pa, SILI_PCI_BAR_GLOBAL, memtype, 0, 121 &sc->sc_iot_global, &sc->sc_ioh_global, 122 NULL, &sc->sc_ios_global, 0) != 0) { 123 printf(": unable to map global registers\n"); 124 return; 125 } 126 127 memtype = pci_mapreg_type(psc->psc_pc, psc->psc_tag, 128 SILI_PCI_BAR_PORT); 129 if (pci_mapreg_map(pa, SILI_PCI_BAR_PORT, memtype, 0, 130 &sc->sc_iot_port, &sc->sc_ioh_port, 131 NULL, &sc->sc_ios_port, 0) != 0) { 132 printf(": unable to map port registers\n"); 133 goto unmap_global; 134 } 135 136 /* hook up the interrupt */ 137 if (pci_intr_map(pa, &ih)) { 138 printf(": unable to map interrupt\n"); 139 goto unmap_port; 140 } 141 intrstr = pci_intr_string(psc->psc_pc, ih); 142 psc->psc_ih = pci_intr_establish(psc->psc_pc, ih, IPL_BIO, 143 sili_intr, sc, sc->sc_dev.dv_xname); 144 if (psc->psc_ih == NULL) { 145 printf(": unable to map interrupt%s%s\n", 146 intrstr == NULL ? "" : " at ", 147 intrstr == NULL ? "" : intrstr); 148 goto unmap_port; 149 } 150 printf(": %s", intrstr); 151 152 if (sili_attach(sc) != 0) { 153 /* error printed by sili_attach */ 154 goto deintr; 155 } 156 157 return; 158 159deintr: 160 pci_intr_disestablish(psc->psc_pc, psc->psc_ih); 161 psc->psc_ih = NULL; 162unmap_port: 163 bus_space_unmap(sc->sc_iot_port, sc->sc_ioh_port, sc->sc_ios_port); 164 sc->sc_ios_port = 0; 165unmap_global: 166 bus_space_unmap(sc->sc_iot_global, sc->sc_ioh_global, 167 sc->sc_ios_global); 168 sc->sc_ios_global = 0; 169} 170 171int 172sili_pci_detach(struct device *self, int flags) 173{ 174 struct sili_pci_softc *psc = (struct sili_pci_softc *)self; 175 struct sili_softc *sc = &psc->psc_sili; 176 int rv; 177 178 rv = sili_detach(sc, flags); 179 if (rv != 0) 180 return (rv); 181 182 if (psc->psc_ih != NULL) { 183 pci_intr_disestablish(psc->psc_pc, psc->psc_ih); 184 psc->psc_ih = NULL; 185 } 186 if (sc->sc_ios_port != 0) { 187 bus_space_unmap(sc->sc_iot_port, sc->sc_ioh_port, 188 sc->sc_ios_port); 189 sc->sc_ios_port = 0; 190 } 191 if (sc->sc_ios_global != 0) { 192 bus_space_unmap(sc->sc_iot_global, sc->sc_ioh_global, 193 sc->sc_ios_global); 194 sc->sc_ios_global = 0; 195 } 196 197 return (0); 198} 199 200int 201sili_pci_activate(struct device *self, int act) 202{ 203 struct sili_softc *sc = (struct sili_softc *)self; 204 int rv = 0; 205 206 switch (act) { 207 case DVACT_RESUME: 208 sili_resume(sc); 209 rv = config_activate_children(self, act); 210 break; 211 default: 212 rv = config_activate_children(self, act); 213 break; 214 } 215 return (rv); 216} 217