1 /* 2 * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the acknowledgement as bellow: 15 * 16 * This product includes software developed by K. Kobayashi and H. SHimokawa 17 * 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 * 33 * $FreeBSD$ 34 * 35 */ 36 #include "opt_bus.h" 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/module.h> 42 #include <sys/bus.h> 43 #include <sys/queue.h> 44 #include <machine/bus.h> 45 #include <sys/rman.h> 46 #include <machine/resource.h> 47 48 #include <pci/pcivar.h> 49 #include <pci/pcireg.h> 50 51 #include <dev/firewire/firewire.h> 52 #include <dev/firewire/firewirebusreg.h> 53 #include <dev/firewire/firewirereg.h> 54 55 #include <dev/firewire/fwohcireg.h> 56 #include <dev/firewire/fwohcivar.h> 57 58 static int fwohci_pci_attach(device_t self); 59 static int fwohci_pci_detach(device_t self); 60 61 /* 62 * The probe routine. 63 */ 64 static int 65 fwohci_pci_probe( device_t dev ) 66 { 67 #if 1 68 if ((pci_get_vendor(dev) == FW_VENDORID_NEC) && 69 (pci_get_device(dev) == FW_DEVICE_UPD861)) { 70 device_set_desc(dev, "NEC uPD72861"); 71 return 0; 72 } 73 if ((pci_get_vendor(dev) == FW_VENDORID_TI) && 74 (pci_get_device(dev) == FW_DEVICE_TITSB22)) { 75 device_set_desc(dev, "Texas Instruments TSB12LV22"); 76 return 0; 77 } 78 if ((pci_get_vendor(dev) == FW_VENDORID_TI) && 79 (pci_get_device(dev) == FW_DEVICE_TITSB23)) { 80 device_set_desc(dev, "Texas Instruments TSB12LV23"); 81 return 0; 82 } 83 if ((pci_get_vendor(dev) == FW_VENDORID_TI) && 84 (pci_get_device(dev) == FW_DEVICE_TITSB26)) { 85 device_set_desc(dev, "Texas Instruments TSB12LV26"); 86 return 0; 87 } 88 if ((pci_get_vendor(dev) == FW_VENDORID_TI) && 89 (pci_get_device(dev) == FW_DEVICE_TITSB43)) { 90 device_set_desc(dev, "Texas Instruments TSB43AA22"); 91 return 0; 92 } 93 if ((pci_get_vendor(dev) == FW_VENDORID_SONY) && 94 (pci_get_device(dev) == FW_DEVICE_CX3022)) { 95 device_set_desc(dev, "SONY CX3022"); 96 return 0; 97 } 98 if ((pci_get_vendor(dev) == FW_VENDORID_VIA) && 99 (pci_get_device(dev) == FW_DEVICE_VT6306)) { 100 device_set_desc(dev, "VIA VT6306"); 101 return 0; 102 } 103 if ((pci_get_vendor(dev) == FW_VENDORID_RICOH) && 104 (pci_get_device(dev) == FW_DEVICE_R5C552)) { 105 device_set_desc(dev, "Ricoh R5C552"); 106 return 0; 107 } 108 if ((pci_get_vendor(dev) == FW_VENDORID_APPLE) && 109 (pci_get_device(dev) == FW_DEVICE_PANGEA)) { 110 device_set_desc(dev, "Apple Pangea"); 111 return 0; 112 } 113 if ((pci_get_vendor(dev) == FW_VENDORID_APPLE) && 114 (pci_get_device(dev) == FW_DEVICE_UNINORTH)) { 115 device_set_desc(dev, "Apple UniNorth"); 116 return 0; 117 } 118 if ((pci_get_vendor(dev) == FW_VENDORID_LUCENT) && 119 (pci_get_device(dev) == FW_DEVICE_FW322)) { 120 device_set_desc(dev, "Lucent FW322/323"); 121 return 0; 122 } 123 #endif 124 if (pci_get_class(dev) == PCIC_SERIALBUS 125 && pci_get_subclass(dev) == PCIS_SERIALBUS_FW 126 && pci_get_progif(dev) == PCI_INTERFACE_OHCI) { 127 printf("XXXfw: vendid=%x, dev=%x\n", pci_get_vendor(dev), 128 pci_get_device(dev)); 129 device_set_desc(dev, "1394 Open Host Controller Interface"); 130 return 0; 131 } 132 133 return ENXIO; 134 } 135 136 #if __FreeBSD_version < 500000 137 static void 138 fwohci_dummy_intr(void *arg) 139 { 140 /* XXX do nothing */ 141 } 142 #endif 143 144 static int 145 fwohci_pci_attach(device_t self) 146 { 147 fwohci_softc_t *sc = device_get_softc(self); 148 int err; 149 int rid; 150 int intr; 151 int latency, cache_line; 152 u_int16_t cmd; 153 /* For the moment, put in a message stating what is wrong */ 154 intr = pci_read_config(self, PCIR_INTLINE, 1); 155 if (intr == 0 || intr == 255) { 156 device_printf(self, "Invalid irq %d\n", intr); 157 #ifdef __i386__ 158 device_printf(self, "Please switch PNP-OS to 'No' in BIOS\n"); 159 #endif 160 return ENXIO; 161 } 162 163 cmd = pci_read_config(self, PCIR_COMMAND, 2); 164 cmd |= PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MWRICEN; 165 pci_write_config(self, PCIR_COMMAND, cmd, 2); 166 167 latency = pci_read_config(self, PCIR_LATTIMER, 1); 168 #define DEF_LATENCY 250 /* Derived from Max Bulk Transfer size 512 Bytes*/ 169 if( latency < DEF_LATENCY ) { 170 latency = DEF_LATENCY; 171 device_printf(self, "PCI bus latency was changing to"); 172 pci_write_config(self, PCIR_LATTIMER,latency, 1); 173 } else 174 { 175 device_printf(self, "PCI bus latency is"); 176 } 177 printf(" %d.\n", (int) latency); 178 cache_line = pci_read_config(self, PCIR_CACHELNSZ, 1); 179 #if 0 180 #define DEF_CACHE_LINE 0xc 181 cache_line = DEF_CACHE_LINE; 182 pci_write_config(self, PCIR_CACHELNSZ, cache_line, 1); 183 #endif 184 printf("cache size %d.\n", (int) cache_line); 185 /**/ 186 rid = PCI_CBMEM; 187 sc->bsr = bus_alloc_resource(self, SYS_RES_MEMORY, &rid, 188 0, ~0, 1, RF_ACTIVE); 189 if (!sc->bsr) { 190 device_printf(self, "Could not map memory\n"); 191 return ENXIO; 192 } 193 194 sc->bst = rman_get_bustag(sc->bsr); 195 sc->bsh = rman_get_bushandle(sc->bsr); 196 197 rid = 0; 198 sc->irq_res = bus_alloc_resource(self, SYS_RES_IRQ, &rid, 0, ~0, 1, 199 RF_SHAREABLE | RF_ACTIVE); 200 if (sc->irq_res == NULL) { 201 device_printf(self, "Could not allocate irq\n"); 202 fwohci_pci_detach(self); 203 return ENXIO; 204 } 205 206 sc->fc.bdev = device_add_child(self, "firewire", -1); 207 if (!sc->fc.bdev) { 208 device_printf(self, "Could not add firewire device\n"); 209 fwohci_pci_detach(self); 210 return ENOMEM; 211 } 212 device_set_ivars(sc->fc.bdev, sc); 213 214 err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_NET, 215 (driver_intr_t *) fwohci_intr, sc, &sc->ih); 216 #if __FreeBSD_version < 500000 217 /* XXX splcam() should mask this irq for sbp.c*/ 218 err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_CAM, 219 (driver_intr_t *) fwohci_dummy_intr, sc, &sc->ih_cam); 220 #endif 221 if (err) { 222 device_printf(self, "Could not setup irq, %d\n", err); 223 fwohci_pci_detach(self); 224 return ENXIO; 225 } 226 227 err = fwohci_init(sc, self); 228 229 if (!err) 230 err = device_probe_and_attach(sc->fc.bdev); 231 232 if (err) { 233 device_printf(self, "Firewire init failed\n"); 234 fwohci_pci_detach(self); 235 return EIO; 236 } 237 238 return 0; 239 } 240 241 static int 242 fwohci_pci_detach(device_t self) 243 { 244 fwohci_softc_t *sc = device_get_softc(self); 245 int s; 246 247 248 s = splfw(); 249 bus_generic_detach(self); 250 251 /* disable interrupts that might have been switched on */ 252 if (sc->bst && sc->bsh) 253 bus_space_write_4(sc->bst, sc->bsh, 254 FWOHCI_INTMASKCLR, OHCI_INT_EN); 255 256 if (sc->irq_res) { 257 int err = bus_teardown_intr(self, sc->irq_res, sc->ih); 258 if (err) 259 /* XXX or should we panic? */ 260 device_printf(self, "Could not tear down irq, %d\n", 261 err); 262 #if __FreeBSD_version < 500000 263 err = bus_teardown_intr(self, sc->irq_res, sc->ih_cam); 264 #endif 265 sc->ih = NULL; 266 } 267 268 if (sc->fc.bdev) { 269 device_delete_child(self, sc->fc.bdev); 270 sc->fc.bdev = NULL; 271 } 272 273 if (sc->irq_res) { 274 bus_release_resource(self, SYS_RES_IRQ, 0, sc->irq_res); 275 sc->irq_res = NULL; 276 } 277 278 if (sc->bsr) { 279 bus_release_resource(self, SYS_RES_MEMORY,PCI_CBMEM,sc->bsr); 280 sc->bsr = NULL; 281 sc->bst = 0; 282 sc->bsh = 0; 283 } 284 splx(s); 285 286 return 0; 287 } 288 289 static device_method_t fwohci_methods[] = { 290 /* Device interface */ 291 DEVMETHOD(device_probe, fwohci_pci_probe), 292 DEVMETHOD(device_attach, fwohci_pci_attach), 293 DEVMETHOD(device_detach, fwohci_pci_detach), 294 DEVMETHOD(device_shutdown, bus_generic_shutdown), 295 296 /* Bus interface */ 297 DEVMETHOD(bus_print_child, bus_generic_print_child), 298 299 { 0, 0 } 300 }; 301 302 static driver_t fwohci_driver = { 303 "fwohci", 304 fwohci_methods, 305 sizeof(fwohci_softc_t), 306 }; 307 308 static devclass_t fwohci_devclass; 309 310 DRIVER_MODULE(fwohci, pci, fwohci_driver, fwohci_devclass, 0, 0); 311 DRIVER_MODULE(fwohci, cardbus, fwohci_driver, fwohci_devclass, 0, 0); 312