firewire.c revision 346476
1/*- 2 * Copyright (c) 2004 Hidetoshi Shimokawa <simokawa@FreeBSD.ORG> 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 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: stable/11/stand/i386/libfirewire/firewire.c 346476 2019-04-21 03:36:05Z kevans $"); 29 30/* 31 * FireWire disk device handling. 32 * 33 */ 34 35#include <stand.h> 36 37#include <machine/bootinfo.h> 38 39#include <stdarg.h> 40 41#include <bootstrap.h> 42#include <btxv86.h> 43#include <libi386.h> 44#include <dev/firewire/firewire.h> 45#include "fwohci.h" 46#include <dev/dcons/dcons.h> 47 48/* XXX */ 49#define BIT4x2(x,y) uint8_t y:4, x:4 50#define BIT16x2(x,y) uint32_t y:16, x:16 51#define _KERNEL 52#include <dev/firewire/iec13213.h> 53 54extern uint32_t dcons_paddr; 55extern struct console dconsole; 56 57struct crom_src_buf { 58 struct crom_src src; 59 struct crom_chunk root; 60 struct crom_chunk vendor; 61 struct crom_chunk hw; 62 /* for dcons */ 63 struct crom_chunk unit; 64 struct crom_chunk spec; 65 struct crom_chunk ver; 66}; 67 68static int fw_init(void); 69static int fw_strategy(void *devdata, int flag, daddr_t dblk, 70 size_t size, char *buf, size_t *rsize); 71static int fw_open(struct open_file *f, ...); 72static int fw_close(struct open_file *f); 73static int fw_print(int verbose); 74static void fw_cleanup(void); 75 76void fw_enable(void); 77 78struct devsw fwohci = { 79 "FW1394", /* 7 chars at most */ 80 DEVT_NET, 81 fw_init, 82 fw_strategy, 83 fw_open, 84 fw_close, 85 noioctl, 86 fw_print, 87 fw_cleanup 88}; 89 90static struct fwohci_softc fwinfo[MAX_OHCI]; 91static int fw_initialized = 0; 92 93static void 94fw_probe(int index, struct fwohci_softc *sc) 95{ 96 int err; 97 98 sc->state = FWOHCI_STATE_INIT; 99 err = biospci_find_devclass( 100 0x0c0010 /* Serial:FireWire:OHCI */, 101 index /* index */, 102 &sc->locator); 103 104 if (err != 0) { 105 sc->state = FWOHCI_STATE_DEAD; 106 return; 107 } 108 109 biospci_write_config(sc->locator, 110 0x4 /* command */, 111 BIOSPCI_16BITS, 112 0x6 /* enable bus master and memory mapped I/O */); 113 114 biospci_read_config(sc->locator, 0x00 /*devid*/, BIOSPCI_32BITS, 115 &sc->devid); 116 biospci_read_config(sc->locator, 0x10 /*base_addr*/, BIOSPCI_32BITS, 117 &sc->base_addr); 118 119 sc->handle = (uint32_t)PTOV(sc->base_addr); 120 sc->bus_id = OREAD(sc, OHCI_BUS_ID); 121 122 return; 123} 124 125static int 126fw_init(void) 127{ 128 int i, avail; 129 struct fwohci_softc *sc; 130 131 if (fw_initialized) 132 return (0); 133 134 avail = 0; 135 for (i = 0; i < MAX_OHCI; i ++) { 136 sc = &fwinfo[i]; 137 fw_probe(i, sc); 138 if (sc->state == FWOHCI_STATE_DEAD) 139 break; 140 avail ++; 141 break; 142 } 143 fw_initialized = 1; 144 145 return (0); 146} 147 148 149/* 150 * Print information about OHCI chips 151 */ 152static int 153fw_print(int verbose) 154{ 155 char line[80]; 156 int i, ret = 0; 157 struct fwohci_softc *sc; 158 159 printf("%s devices:", fwohci.dv_name); 160 if ((ret = pager_output("\n")) != 0) 161 return (ret); 162 163 for (i = 0; i < MAX_OHCI; i ++) { 164 sc = &fwinfo[i]; 165 if (sc->state == FWOHCI_STATE_DEAD) 166 break; 167 snprintf(line, sizeof(line), "%d: locator=0x%04x devid=0x%08x" 168 " base_addr=0x%08x handle=0x%08x bus_id=0x%08x\n", 169 i, sc->locator, sc->devid, 170 sc->base_addr, sc->handle, sc->bus_id); 171 ret = pager_output(line); 172 if (ret != 0) 173 break; 174 } 175 return (ret); 176} 177 178static int 179fw_open(struct open_file *f, ...) 180{ 181#if 0 182 va_list ap; 183 struct i386_devdesc *dev; 184 struct open_disk *od; 185 int error; 186 187 va_start(ap, f); 188 dev = va_arg(ap, struct i386_devdesc *); 189 va_end(ap); 190#endif 191 192 return (ENXIO); 193} 194 195static int 196fw_close(struct open_file *f) 197{ 198 return (0); 199} 200 201static void 202fw_cleanup() 203{ 204 struct dcons_buf *db; 205 206 /* invalidate dcons buffer */ 207 if (dcons_paddr) { 208 db = (struct dcons_buf *)PTOV(dcons_paddr); 209 db->magic = 0; 210 } 211} 212 213static int 214fw_strategy(void *devdata, int rw, daddr_t dblk, size_t size, 215 char *buf, size_t *rsize) 216{ 217 return (EIO); 218} 219 220static void 221fw_init_crom(struct fwohci_softc *sc) 222{ 223 struct crom_src *src; 224 225 printf("fw_init_crom\n"); 226 sc->crom_src_buf = (struct crom_src_buf *) 227 malloc(sizeof(struct crom_src_buf)); 228 if (sc->crom_src_buf == NULL) 229 return; 230 231 src = &sc->crom_src_buf->src; 232 bzero(src, sizeof(struct crom_src)); 233 234 /* BUS info sample */ 235 src->hdr.info_len = 4; 236 237 src->businfo.bus_name = CSR_BUS_NAME_IEEE1394; 238 239 src->businfo.irmc = 1; 240 src->businfo.cmc = 1; 241 src->businfo.isc = 1; 242 src->businfo.bmc = 1; 243 src->businfo.pmc = 0; 244 src->businfo.cyc_clk_acc = 100; 245 src->businfo.max_rec = sc->maxrec; 246 src->businfo.max_rom = MAXROM_4; 247#define FW_GENERATION_CHANGEABLE 2 248 src->businfo.generation = FW_GENERATION_CHANGEABLE; 249 src->businfo.link_spd = sc->speed; 250 251 src->businfo.eui64.hi = sc->eui.hi; 252 src->businfo.eui64.lo = sc->eui.lo; 253 254 STAILQ_INIT(&src->chunk_list); 255 256 sc->crom_src = src; 257 sc->crom_root = &sc->crom_src_buf->root; 258} 259 260static void 261fw_reset_crom(struct fwohci_softc *sc) 262{ 263 struct crom_src_buf *buf; 264 struct crom_src *src; 265 struct crom_chunk *root; 266 267 printf("fw_reset\n"); 268 if (sc->crom_src_buf == NULL) 269 fw_init_crom(sc); 270 271 buf = sc->crom_src_buf; 272 src = sc->crom_src; 273 root = sc->crom_root; 274 275 STAILQ_INIT(&src->chunk_list); 276 277 bzero(root, sizeof(struct crom_chunk)); 278 crom_add_chunk(src, NULL, root, 0); 279 crom_add_entry(root, CSRKEY_NCAP, 0x0083c0); /* XXX */ 280 /* private company_id */ 281 crom_add_entry(root, CSRKEY_VENDOR, CSRVAL_VENDOR_PRIVATE); 282#ifdef __DragonFly__ 283 crom_add_simple_text(src, root, &buf->vendor, "DragonFly Project"); 284#else 285 crom_add_simple_text(src, root, &buf->vendor, "FreeBSD Project"); 286#endif 287} 288 289 290#define ADDR_HI(x) (((x) >> 24) & 0xffffff) 291#define ADDR_LO(x) ((x) & 0xffffff) 292 293static void 294dcons_crom(struct fwohci_softc *sc) 295{ 296 struct crom_src_buf *buf; 297 struct crom_src *src; 298 struct crom_chunk *root; 299 300 buf = sc->crom_src_buf; 301 src = sc->crom_src; 302 root = sc->crom_root; 303 304 bzero(&buf->unit, sizeof(struct crom_chunk)); 305 306 crom_add_chunk(src, root, &buf->unit, CROM_UDIR); 307 crom_add_entry(&buf->unit, CSRKEY_SPEC, CSRVAL_VENDOR_PRIVATE); 308 crom_add_simple_text(src, &buf->unit, &buf->spec, "FreeBSD"); 309 crom_add_entry(&buf->unit, CSRKEY_VER, DCONS_CSR_VAL_VER); 310 crom_add_simple_text(src, &buf->unit, &buf->ver, "dcons"); 311 crom_add_entry(&buf->unit, DCONS_CSR_KEY_HI, ADDR_HI(dcons_paddr)); 312 crom_add_entry(&buf->unit, DCONS_CSR_KEY_LO, ADDR_LO(dcons_paddr)); 313} 314 315void 316fw_crom(struct fwohci_softc *sc) 317{ 318 struct crom_src *src; 319 void *newrom; 320 321 fw_reset_crom(sc); 322 dcons_crom(sc); 323 324 newrom = malloc(CROMSIZE); 325 src = &sc->crom_src_buf->src; 326 crom_load(src, (uint32_t *)newrom, CROMSIZE); 327 if (bcmp(newrom, sc->config_rom, CROMSIZE) != 0) { 328 /* Bump generation and reload. */ 329 src->businfo.generation++; 330 331 /* Handle generation count wraps. */ 332 if (src->businfo.generation < 2) 333 src->businfo.generation = 2; 334 335 /* Recalculate CRC to account for generation change. */ 336 crom_load(src, (uint32_t *)newrom, CROMSIZE); 337 bcopy(newrom, (void *)sc->config_rom, CROMSIZE); 338 } 339 free(newrom); 340} 341 342static int 343fw_busreset(struct fwohci_softc *sc) 344{ 345 int count; 346 347 if (sc->state < FWOHCI_STATE_ENABLED) { 348 printf("fwohci not enabled\n"); 349 return(CMD_OK); 350 } 351 fw_crom(sc); 352 fwohci_ibr(sc); 353 count = 0; 354 while (sc->state< FWOHCI_STATE_NORMAL) { 355 fwohci_poll(sc); 356 count ++; 357 if (count > 1000) { 358 printf("give up to wait bus initialize\n"); 359 return (-1); 360 } 361 } 362 printf("poll count = %d\n", count); 363 return (0); 364} 365 366void 367fw_enable(void) 368{ 369 struct fwohci_softc *sc; 370 int i; 371 372 if (fw_initialized == 0) 373 fw_init(); 374 375 for (i = 0; i < MAX_OHCI; i ++) { 376 sc = &fwinfo[i]; 377 if (sc->state != FWOHCI_STATE_INIT) 378 break; 379 380 sc->config_rom = (uint32_t *) 381 (((uint32_t)sc->config_rom_buf 382 + (CROMSIZE - 1)) & ~(CROMSIZE - 1)); 383#if 0 384 printf("configrom: %08p %08p\n", 385 sc->config_rom_buf, sc->config_rom); 386#endif 387 if (fwohci_init(sc, 0) == 0) { 388 sc->state = FWOHCI_STATE_ENABLED; 389 fw_busreset(sc); 390 } else 391 sc->state = FWOHCI_STATE_DEAD; 392 } 393} 394 395void 396fw_poll(void) 397{ 398 struct fwohci_softc *sc; 399 int i; 400 401 if (fw_initialized == 0) 402 return; 403 404 for (i = 0; i < MAX_OHCI; i ++) { 405 sc = &fwinfo[i]; 406 if (sc->state < FWOHCI_STATE_ENABLED) 407 break; 408 fwohci_poll(sc); 409 } 410} 411 412#if 0 /* for debug */ 413static int 414fw_busreset_cmd(int argc, char *argv[]) 415{ 416 struct fwohci_softc *sc; 417 int i; 418 419 for (i = 0; i < MAX_OHCI; i ++) { 420 sc = &fwinfo[i]; 421 if (sc->state < FWOHCI_STATE_INIT) 422 break; 423 fw_busreset(sc); 424 } 425 return(CMD_OK); 426} 427 428static int 429fw_poll_cmd(int argc, char *argv[]) 430{ 431 fw_poll(); 432 return(CMD_OK); 433} 434 435static int 436fw_enable_cmd(int argc, char *argv[]) 437{ 438 fw_print(0); 439 fw_enable(); 440 return(CMD_OK); 441} 442 443 444static int 445dcons_enable(int argc, char *argv[]) 446{ 447 dconsole.c_init(0); 448 fw_enable(); 449 dconsole.c_flags |= C_ACTIVEIN | C_ACTIVEOUT; 450 return(CMD_OK); 451} 452 453static int 454dcons_read(int argc, char *argv[]) 455{ 456 char c; 457 while (dconsole.c_ready()) { 458 c = dconsole.c_in(); 459 printf("%c", c); 460 } 461 printf("\r\n"); 462 return(CMD_OK); 463} 464 465static int 466dcons_write(int argc, char *argv[]) 467{ 468 int len, i; 469 if (argc < 2) 470 return(CMD_OK); 471 472 len = strlen(argv[1]); 473 for (i = 0; i < len; i ++) 474 dconsole.c_out(argv[1][i]); 475 dconsole.c_out('\r'); 476 dconsole.c_out('\n'); 477 return(CMD_OK); 478} 479COMMAND_SET(firewire, "firewire", "enable firewire", fw_enable_cmd); 480COMMAND_SET(fwbusreset, "fwbusreset", "firewire busreset", fw_busreset_cmd); 481COMMAND_SET(fwpoll, "fwpoll", "firewire poll", fw_poll_cmd); 482COMMAND_SET(dcons, "dcons", "enable dcons", dcons_enable); 483COMMAND_SET(dread, "dread", "read from dcons", dcons_read); 484COMMAND_SET(dwrite, "dwrite", "write to dcons", dcons_write); 485#endif 486