Changeset 80 for trunk/src/os2ahci/ahci.c
- Timestamp:
- Mar 1, 2011, 10:10:11 AM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/os2ahci/ahci.c
r79 r80 135 135 for (i = 0; i < HOST_CAP2; i += sizeof(u32)) { 136 136 ai->bios_config[i / sizeof(u32)] = readl(ai->mmio + i); 137 } 138 139 if ((ai->bios_config[HOST_CTL / sizeof(u32)] & HOST_AHCI_EN) == 0 && 140 ai->pci->vendor == PCI_VENDOR_ID_INTEL) { 141 /* Adapter is not in AHCI mode and the spec says a COMRESET is 142 * required when switching from SATA to AHCI mode and vice versa. 143 */ 144 init_reset = 1; 137 145 } 138 146 … … 184 192 if (val & HOST_CAP2_NVMHCI) printf(" nvmhci"); 185 193 if (val & HOST_CAP2_APST) printf(" apst"); 186 187 194 } 188 195 printf("\n"); … … 277 284 ddprintf("restoring AHCI BIOS configuration\n"); 278 285 279 /* restore saved BIOS configuration */ 280 writel(ai->mmio + HOST_CTL, ai->bios_config[HOST_CTL / sizeof(u32)]); 286 /* Restore saved BIOS configuration; please note that HOST_CTL is restored 287 * last because it may cause AHCI mode to be turned off again. 288 */ 281 289 writel(ai->mmio + HOST_CCC, ai->bios_config[HOST_CCC / sizeof(u32)]); 282 290 writel(ai->mmio + HOST_CCC_PORTS, ai->bios_config[HOST_CCC_PORTS / sizeof(u32)]); 283 291 writel(ai->mmio + HOST_EM_CTL, ai->bios_config[HOST_EM_CTL / sizeof(u32)]); 292 writel(ai->mmio + HOST_CTL, ai->bios_config[HOST_CTL / sizeof(u32)]); 284 293 285 294 /* flush PCI MMIO delayed write buffers */ 286 readl(ai->mmio + HOST_EM_CTL); 295 readl(ai->mmio + HOST_CTL); 296 297 if ((ai->bios_config[HOST_CTL / sizeof(u32)] & HOST_AHCI_EN) == 0 && 298 ai->pci->vendor == PCI_VENDOR_ID_INTEL) { 299 300 /* This BIOS apparently accesses this controller via SATA registers and 301 * the AHCI spec says that we should issue a COMRESET on each port after 302 * disabling AHCI mode to allow the SATA controller to re-recognize attached 303 * devices. How to do this depends on the controller, of course, but so 304 * far I've only seen Dell notebook BIOSs with Intel chipsets to behave 305 * like this; all other BIOS implementations I've seen so far seem to take 306 * AHCI mode literally and operate the controller in AHCI mode from the 307 * beginning. 308 * 309 * We'll use a feature on Intel ICH7/8 controllers which provides MMIO 310 * mappings for the AHCI SCR registers even when not in AHCI mode. 311 */ 312 int p; 313 314 for (p = 0; p < AHCI_MAX_PORTS; p++) { 315 if (ai->port_map & (1UL << p)) { 316 u8 _far *port_mmio = port_base(ai, p); 317 u32 tmp; 318 319 tmp = readl(port_mmio + PORT_SCR_CTL) & ~0x0000000fUL; 320 writel(port_mmio + PORT_SCR_CTL, tmp | 1); 321 readl(port_mmio + PORT_SCR_CTL); /* flush */ 322 323 /* spec says "leave reset bit on for at least 1ms"; make it 2ms */ 324 mdelay(2); 325 326 writel(port_mmio + PORT_SCR_CTL, tmp); 327 readl(port_mmio + PORT_SCR_CTL); /* flush */ 328 } 329 } 330 331 /* Wait some time to give the COMRESET a chance to complete (usually, at 332 * least hard disks complete the reset within a few milliseonds) 333 */ 334 mdelay(20); 335 } 287 336 288 337 return(0); … … 298 347 299 348 /* restore saved BIOS configuration */ 300 writel(ai->mmio + HOST_CTL, ai->bios_config[HOST_CTL / sizeof(u32)]);301 349 writel(ai->mmio + HOST_CCC, ai->bios_config[HOST_CCC / sizeof(u32)]); 302 350 writel(ai->mmio + HOST_CCC_PORTS, ai->bios_config[HOST_CCC_PORTS / sizeof(u32)]); 303 351 writel(ai->mmio + HOST_EM_CTL, ai->bios_config[HOST_EM_CTL / sizeof(u32)]); 352 writel(ai->mmio + HOST_CTL, ai->bios_config[HOST_CTL / sizeof(u32)]); 304 353 305 354 /* flush PCI MMIO delayed write buffers */ 306 readl(ai->mmio + HOST_ EM_CTL);355 readl(ai->mmio + HOST_CTL); 307 356 308 357 /* (re-)enable AHCI mode */ … … 333 382 pc->fis_rx_h = readl(port_mmio + PORT_FIS_ADDR_HI); 334 383 pc->irq_mask = readl(port_mmio + PORT_IRQ_MASK); 384 pc->port_cmd = readl(port_mmio + PORT_CMD); 335 385 336 386 return(pc); … … 341 391 * configuration (command list and FIS buffers and the IRQ mask). 342 392 * 343 * The port configuration automatically freed.393 * The port configuration is automatically freed. 344 394 */ 345 395 void ahci_restore_port_config(AD_INFO *ai, int p, AHCI_PORT_CFG *pc) … … 347 397 u8 _far *port_mmio = port_base(ai, p); 348 398 349 writel(port_mmio + PORT_LST_ADDR, pc->cmd_list); 350 writel(port_mmio + PORT_LST_ADDR_HI, pc->cmd_list_h); 351 writel(port_mmio + PORT_FIS_ADDR, pc->fis_rx); 352 writel(port_mmio + PORT_FIS_ADDR_HI, pc->fis_rx_h); 353 writel(port_mmio + PORT_IRQ_MASK, pc->irq_mask); 354 355 readl(port_base(ai, p) + PORT_IRQ_MASK); /* flush */ 399 /* stop the port, first */ 400 ahci_stop_port(ai, p); 401 402 if (ai->bios_config[HOST_CTL / sizeof(u32)] & HOST_AHCI_EN) { 403 /* BIOS uses AHCI, too, so we need to restore the port settings; 404 * restoring PORT_CMD way well start the port again but that's what 405 * this function is all about. 406 */ 407 writel(port_mmio + PORT_LST_ADDR, pc->cmd_list); 408 writel(port_mmio + PORT_LST_ADDR_HI, pc->cmd_list_h); 409 writel(port_mmio + PORT_FIS_ADDR, pc->fis_rx); 410 writel(port_mmio + PORT_FIS_ADDR_HI, pc->fis_rx_h); 411 writel(port_mmio + PORT_IRQ_MASK, pc->irq_mask); 412 writel(port_mmio + PORT_CMD, pc->port_cmd); 413 414 readl(port_base(ai, p) + PORT_IRQ_MASK); /* flush */ 415 } 356 416 357 417 free(pc); … … 439 499 /* start/reset port; if no device is attached, this is expected to fail */ 440 500 if (init_reset) { 441 ddprintf("init-resetting port #%d\n", p);442 501 rc = ahci_reset_port(ai, p, 0); 443 502 } else { … … 547 606 for (p = 0; p < AHCI_MAX_PORTS; p++) { 548 607 if (ai->port_map & (1UL << p)) { 549 dprintf("restarting port #%d\n", p); 550 ahci_stop_port(ai, p); 551 ahci_start_port(ai, p, 1); 608 if (init_reset) { 609 ahci_reset_port(ai, p, 1); 610 } else { 611 dprintf("restarting port #%d\n", p); 612 ahci_stop_port(ai, p); 613 ahci_start_port(ai, p, 1); 614 } 552 615 } 553 616 } … … 561 624 readl(ai->mmio + HOST_CTL); /* flush */ 562 625 563 /* enable interrupts on PCI-level (PCI 2.3 added a feature to disable ints) */626 /* enable interrupts on PCI-level (PCI 2.3 added a feature to disable INTs) */ 564 627 /* pci_enable_int(ai->bus, ai->dev_func); */ 565 628 … … 586 649 587 650 dprintf("resetting port %d.%d\n", ad_no(ai), p); 588 ddprintf(" PORT_CMD_ISSUE = 0x%lx\n", readl(port_mmio + PORT_CMD_ISSUE)); 589 ddprintf(" PORT_SCR_ACT = 0x%lx\n", readl(port_mmio + PORT_SCR_ACT)); 590 ddprintf(" PORT_SCR_ERR = 0x%lx\n", readl(port_mmio + PORT_SCR_ERR)); 591 ddprintf(" PORT_TFDATA = 0x%lx\n", readl(port_mmio + PORT_TFDATA)); 592 ddprintf(" PORT_IRQ_STAT = 0x%lx\n", readl(port_mmio + PORT_IRQ_STAT)); 593 ddprintf(" PORT_IRQ_MASK = 0x%lx\n", readl(port_mmio + PORT_IRQ_MASK)); 594 ddprintf(" HOST_IRQ_STAT = 0x%lx\n", readl(ai->mmio + HOST_IRQ_STAT)); 651 if (debug > 1) { 652 printf("command engine status:\n"); 653 printf(" PORT_SCR_ACT = 0x%lx\n", readl(port_mmio + PORT_SCR_ACT)); 654 printf(" PORT_CMD_ISSUE = 0x%lx\n", readl(port_mmio + PORT_CMD_ISSUE)); 655 printf("link/device status:\n"); 656 printf(" PORT_SCR_STAT = 0x%lx\n", readl(port_mmio + PORT_SCR_STAT)); 657 printf(" PORT_SCR_CTL = 0x%lx\n", readl(port_mmio + PORT_SCR_CTL)); 658 printf(" PORT_SCR_ERR = 0x%lx\n", readl(port_mmio + PORT_SCR_ERR)); 659 printf(" PORT_TFDATA = 0x%lx\n", readl(port_mmio + PORT_TFDATA)); 660 printf("interrupt status:\n"); 661 printf(" PORT_IRQ_STAT = 0x%lx\n", readl(port_mmio + PORT_IRQ_STAT)); 662 printf(" PORT_IRQ_MASK = 0x%lx\n", readl(port_mmio + PORT_IRQ_MASK)); 663 printf(" HOST_IRQ_STAT = 0x%lx\n", readl(ai->mmio + HOST_IRQ_STAT)); 664 } 595 665 596 666 /* stop port engines (we don't care whether there is an error doing so) */ … … 600 670 tmp = readl(port_mmio + PORT_SCR_ERR); 601 671 writel(port_mmio + PORT_SCR_ERR, tmp); 602 603 /* clear pending port IRQs */604 tmp = readl(port_mmio + PORT_IRQ_STAT);605 if (tmp) {606 writel(port_mmio + PORT_IRQ_STAT, tmp);607 }608 writel(ai->mmio + HOST_IRQ_STAT, 1UL << p);609 672 610 673 /* set link speed and power management options */ … … 721 784 u32 tmp; 722 785 723 /* set com and header and FIS address registers */786 /* set command header and FIS address registers */ 724 787 writel(port_mmio + PORT_LST_ADDR, port_dma + offsetof(AHCI_PORT_DMA, cmd_hdr)); 725 788 writel(port_mmio + PORT_LST_ADDR_HI, 0); … … 757 820 { 758 821 u8 _far *port_mmio = port_base(ai, p); 822 u32 tmp; 759 823 int rc; 760 824 … … 773 837 return(rc); 774 838 } 839 840 /* clear any pending port IRQs */ 841 tmp = readl(port_mmio + PORT_IRQ_STAT); 842 if (tmp) { 843 writel(port_mmio + PORT_IRQ_STAT, tmp); 844 } 845 writel(ai->mmio + HOST_IRQ_STAT, 1UL << p); 775 846 776 847 /* reset PxSACT register (tagged command queues, not reset by COMRESET) */ … … 1023 1094 } 1024 1095 1025 /* restart port (includes the necessary port configuration) */ 1026 if (ahci_stop_port(ai, p) || ahci_start_port(ai, p, 0)) { 1096 /* restart/reset port (includes the necessary port configuration) */ 1097 if ((ai->bios_config[HOST_CTL / sizeof(u32)] & HOST_AHCI_EN) == 0 && 1098 ai->pci->vendor == PCI_VENDOR_ID_INTEL) { 1099 /* As outlined in ahci_restore_bios_config(), switching back and 1100 * forth between SATA and AHCI mode requires a COMRESET to force 1101 * the corresponding controller subsystem to rediscover attached 1102 * devices. Thus, we'll reset the port instead of stopping and 1103 * starting it. 1104 */ 1105 if (ahci_reset_port(ai, p, 0)) { 1106 iorb_seterr(iorb, IOERR_ADAPTER_NONSPECIFIC); 1107 goto restore_bios_config; 1108 } 1109 1110 } else if (ahci_stop_port(ai, p) || ahci_start_port(ai, p, 0)) { 1027 1111 iorb_seterr(iorb, IOERR_ADAPTER_NONSPECIFIC); 1028 1112 goto restore_bios_config; … … 1500 1584 } else { 1501 1585 /* complete ATA-specific device information */ 1502 if (disable_ncq[ad_no(ai)][p]) { 1503 /* MT: set ncq_max to 1 if NCQ is disabled for this port */ 1586 if (enable_ncq[ad_no(ai)][p]) { 1587 ai->ports[p].devs[d].ncq_max = id_buf[ATA_ID_QUEUE_DEPTH] & 0x001fU; 1588 } 1589 if (ai->ports[p].devs[d].ncq_max < 1) { 1590 /* NCQ not enabled for this device, or device doesn't support NCQ */ 1504 1591 ai->ports[p].devs[d].ncq_max = 1; 1505 dprintf("NCQ off for a:%d p:%d\n", (int) ad_no(ai), p); 1506 } else { 1507 ai->ports[p].devs[d].ncq_max = max(id_buf[ATA_ID_QUEUE_DEPTH] & 0x001fU, 1); 1508 dprintf("NCQ max=%d for a:%d p:%d\n", ai->ports[p].devs[d].ncq_max, 1509 (int) ad_no(ai), p); 1510 } 1511 1592 } 1512 1593 if (id_buf[ATA_ID_CFS_ENABLE_2] & 0x0400U) { 1513 1594 ai->ports[p].devs[d].lba48 = 1; … … 1515 1596 } 1516 1597 1517 dprintf("found device %d.%d.%d: removable = %d, dev_type = %d, atapi = %d \n",1518 ad_no(ai), p, d,1598 dprintf("found device %d.%d.%d: removable = %d, dev_type = %d, atapi = %d, " 1599 "ncq_max = %d\n", ad_no(ai), p, d, 1519 1600 ai->ports[p].devs[d].removable, 1520 1601 ai->ports[p].devs[d].dev_type, 1521 ai->ports[p].devs[d].atapi); 1602 ai->ports[p].devs[d].atapi, 1603 ai->ports[p].devs[d].ncq_max); 1522 1604 1523 1605 /* add device to resource manager; we don't really care about errors here */
Note:
See TracChangeset
for help on using the changeset viewer.