Changeset eb3683a in mainline for uspace/drv/block/ahci/ahci.c
- Timestamp:
- 2012-07-21T14:11:55Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 76c07e4
- Parents:
- 8486c07
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/block/ahci/ahci.c
r8486c07 reb3683a 49 49 #define NAME "ahci" 50 50 51 /** Number of ticks for watchdog timer. */52 #define AHCI_TIMER_TICKS 80000053 54 /** Number of ticks for timer based interrupt. */55 #define AHCI_TIMER_NO_INTR_TICKS 800056 57 51 #define LO(ptr) \ 58 52 ((uint32_t) (((uint64_t) ((uintptr_t) (ptr))) & 0xffffffff)) … … 60 54 #define HI(ptr) \ 61 55 ((uint32_t) (((uint64_t) ((uintptr_t) (ptr))) >> 32)) 56 57 /** Interrupt pseudocode for a single port 58 * 59 * The interrupt handling works as follows: 60 * 61 * 1. Port interrupt status register is read 62 * (stored as arg2). 63 * 2. If port interrupt is indicated, then: 64 * 3. Port interrupt status register is cleared. 65 * 4. Global interrupt status register is read 66 * and cleared (any potential interrupts from 67 * other ports are reasserted automatically). 68 * 5. Port number is stored as arg1. 69 * 6. The interrupt is accepted. 70 * 71 */ 72 #define AHCI_PORT_CMDS(port) \ 73 { \ 74 /* Read port interrupt status register */ \ 75 .cmd = CMD_PIO_READ_32, \ 76 .addr = NULL, \ 77 .dstarg = 2 \ 78 }, \ 79 { \ 80 /* Check if port asserted interrupt */ \ 81 .cmd = CMD_PREDICATE, \ 82 .value = 5, \ 83 .srcarg = 2, \ 84 }, \ 85 { \ 86 /* Clear port interrupt status register */ \ 87 .cmd = CMD_PIO_WRITE_A_32, \ 88 .addr = NULL, \ 89 .srcarg = 2 \ 90 }, \ 91 { \ 92 /* Read global interrupt status register */ \ 93 .cmd = CMD_PIO_READ_32, \ 94 .addr = NULL, \ 95 .dstarg = 0 \ 96 }, \ 97 { \ 98 /* Clear global interrupt status register */ \ 99 .cmd = CMD_PIO_WRITE_A_32, \ 100 .addr = NULL, \ 101 .srcarg = 0 \ 102 }, \ 103 { \ 104 /* Indicate port interrupt assertion */ \ 105 .cmd = CMD_LOAD, \ 106 .value = (port), \ 107 .dstarg = 1 \ 108 }, \ 109 { \ 110 /* Accept the interrupt */ \ 111 .cmd = CMD_ACCEPT \ 112 } 62 113 63 114 static int ahci_get_sata_device_name(ddf_fun_t *, size_t, char *); … … 243 294 /*----------------------------------------------------------------------------*/ 244 295 245 /** Get and clear AHCI port interrupt state register.296 /** Wait for interrupt event. 246 297 * 247 298 * @param sata SATA device structure. … … 250 301 * 251 302 */ 252 static ahci_port_is_t ahci_get_and_clear_pxis(sata_dev_t *sata) 253 { 254 ahci_port_is_t pxis; 255 256 fibril_mutex_lock(&sata->pxis_lock); 257 258 pxis.u32 = sata->ahci->memregs->ports[sata->port_num].pxis; 259 sata->ahci->memregs->ports[sata->port_num].pxis = pxis.u32; 303 static ahci_port_is_t ahci_wait_event(sata_dev_t *sata) 304 { 305 fibril_mutex_lock(&sata->event_lock); 306 307 while (sata->event_pxis == 0) 308 fibril_condvar_wait(&sata->event_condvar, &sata->event_lock); 309 310 ahci_port_is_t pxis = sata->event_pxis; 311 sata->event_pxis = 0; 260 312 261 313 if (ahci_port_is_permanent_error(pxis)) 262 314 sata->is_invalid_device = true; 263 315 264 fibril_mutex_unlock(&sata-> pxis_lock);316 fibril_mutex_unlock(&sata->event_lock); 265 317 266 318 return pxis; … … 275 327 static void ahci_identify_device_cmd(sata_dev_t *sata, void *phys) 276 328 { 277 /* Clear interrupt state registers */278 ahci_get_and_clear_pxis(sata);279 sata->shadow_pxis.u32 = 0;280 281 329 volatile sata_std_command_frame_t *cmd = 282 330 (sata_std_command_frame_t *) sata->cmd_table; … … 308 356 sata->cmd_header->flags = 309 357 AHCI_CMDHDR_FLAGS_CLEAR_BUSY_UPON_OK | 310 AHCI_CMDHDR_FLAGS_2DWCMD; 358 AHCI_CMDHDR_FLAGS_2DWCMD; 311 359 sata->cmd_header->bytesprocessed = 0; 312 360 … … 324 372 static void ahci_identify_packet_device_cmd(sata_dev_t *sata, void *phys) 325 373 { 326 /* Clear interrupt state registers */ 327 ahci_get_and_clear_pxis(sata); 328 sata->shadow_pxis.u32 = 0; 329 330 volatile sata_std_command_frame_t * cmd = 374 volatile sata_std_command_frame_t *cmd = 331 375 (sata_std_command_frame_t *) sata->cmd_table; 332 376 … … 355 399 356 400 sata->cmd_header->prdtl = 1; 357 sata->cmd_header->flags = 401 sata->cmd_header->flags = 358 402 AHCI_CMDHDR_FLAGS_CLEAR_BUSY_UPON_OK | 359 403 AHCI_CMDHDR_FLAGS_2DWCMD; … … 382 426 void *phys; 383 427 sata_identify_data_t *idata; 384 dmamem_map_anonymous(512, AS_AREA_READ | AS_AREA_WRITE, 0, &phys, 385 (void **) &idata); 386 bzero(idata, 512); 428 int rc = dmamem_map_anonymous(SATA_IDENTIFY_DEVICE_BUFFER_LENGTH, 429 AS_AREA_READ | AS_AREA_WRITE, 0, &phys, (void **) &idata); 430 if (rc != EOK) { 431 ddf_msg(LVL_ERROR, "Cannot allocate buffer to identify device."); 432 return rc; 433 } 434 435 bzero(idata, SATA_IDENTIFY_DEVICE_BUFFER_LENGTH); 387 436 388 437 fibril_mutex_lock(&sata->lock); 389 438 390 439 ahci_identify_device_cmd(sata, phys); 391 392 fibril_mutex_lock(&sata->event_lock); 393 fibril_condvar_wait(&sata->event_condvar, &sata->event_lock); 394 fibril_mutex_unlock(&sata->event_lock); 395 396 ahci_port_is_t pxis = sata->shadow_pxis; 397 sata->shadow_pxis.u32 &= ~pxis.u32; 440 ahci_port_is_t pxis = ahci_wait_event(sata); 398 441 399 442 if (sata->is_invalid_device) { … … 405 448 if (ahci_port_is_tfes(pxis)) { 406 449 ahci_identify_packet_device_cmd(sata, phys); 407 408 fibril_mutex_lock(&sata->event_lock); 409 fibril_condvar_wait(&sata->event_condvar, &sata->event_lock); 410 fibril_mutex_unlock(&sata->event_lock); 411 412 pxis = sata->shadow_pxis; 413 sata->shadow_pxis.u32 &= ~pxis.u32; 450 pxis = ahci_wait_event(sata); 414 451 415 452 if ((sata->is_invalid_device) || (ahci_port_is_error(pxis))) { … … 441 478 "%s: Sector length other than 512 B not supported", 442 479 sata->model); 443 goto error; 480 goto error; 444 481 } 445 482 … … 449 486 "%s: Sector length other than 512 B not supported", 450 487 sata->model); 451 goto error; 488 goto error; 452 489 } 453 490 } … … 488 525 goto error; 489 526 } else { 490 for (u nsigned int i = 0; i < 7; i++) {527 for (uint8_t i = 0; i < 7; i++) { 491 528 if (udma_mask & (1 << i)) 492 529 sata->highest_udma_mode = i; … … 515 552 static void ahci_set_mode_cmd(sata_dev_t *sata, void* phys, uint8_t mode) 516 553 { 517 /* Clear interrupt state registers */518 ahci_get_and_clear_pxis(sata);519 sata->shadow_pxis.u32 = 0;520 521 554 volatile sata_std_command_frame_t *cmd = 522 555 (sata_std_command_frame_t *) sata->cmd_table; … … 599 632 uint8_t mode = 0x40 | (sata->highest_udma_mode & 0x07); 600 633 ahci_set_mode_cmd(sata, phys, mode); 601 602 fibril_mutex_lock(&sata->event_lock); 603 fibril_condvar_wait(&sata->event_condvar, &sata->event_lock); 604 fibril_mutex_unlock(&sata->event_lock); 605 606 ahci_port_is_t pxis = sata->shadow_pxis; 607 sata->shadow_pxis.u32 &= ~pxis.u32; 634 ahci_port_is_t pxis = ahci_wait_event(sata); 608 635 609 636 if (sata->is_invalid_device) { … … 641 668 static void ahci_rb_fpdma_cmd(sata_dev_t *sata, void *phys, uint64_t blocknum) 642 669 { 643 /* Clear interrupt state registers */644 ahci_get_and_clear_pxis(sata);645 sata->shadow_pxis.u32 = 0;646 647 670 volatile sata_ncq_command_frame_t *cmd = 648 671 (sata_ncq_command_frame_t *) sata->cmd_table; … … 709 732 710 733 ahci_rb_fpdma_cmd(sata, phys, blocknum); 711 712 fibril_mutex_lock(&sata->event_lock); 713 fibril_condvar_wait(&sata->event_condvar, &sata->event_lock); 714 fibril_mutex_unlock(&sata->event_lock); 715 716 ahci_port_is_t pxis = sata->shadow_pxis; 717 sata->shadow_pxis.u32 &= ~pxis.u32; 734 ahci_port_is_t pxis = ahci_wait_event(sata); 718 735 719 736 if ((sata->is_invalid_device) || (ahci_port_is_error(pxis))) { … … 737 754 static void ahci_wb_fpdma_cmd(sata_dev_t *sata, void *phys, uint64_t blocknum) 738 755 { 739 /* Clear interrupt state registers */ 740 ahci_get_and_clear_pxis(sata); 741 sata->shadow_pxis.u32 = 0; 742 743 volatile sata_ncq_command_frame_t * cmd = 756 volatile sata_ncq_command_frame_t *cmd = 744 757 (sata_ncq_command_frame_t *) sata->cmd_table; 745 758 … … 767 780 cmd->lba5 = (blocknum >> 40) & 0xff; 768 781 769 volatile ahci_cmd_prdt_t * 782 volatile ahci_cmd_prdt_t *prdt = 770 783 (ahci_cmd_prdt_t *) (&sata->cmd_table[0x20]); 771 784 … … 806 819 807 820 ahci_wb_fpdma_cmd(sata, phys, blocknum); 808 809 fibril_mutex_lock(&sata->event_lock); 810 fibril_condvar_wait(&sata->event_condvar, &sata->event_lock); 811 fibril_mutex_unlock(&sata->event_lock); 812 813 ahci_port_is_t pxis = sata->shadow_pxis; 814 sata->shadow_pxis.u32 &= ~pxis.u32; 821 ahci_port_is_t pxis = ahci_wait_event(sata); 815 822 816 823 if ((sata->is_invalid_device) || (ahci_port_is_error(pxis))) { … … 824 831 825 832 /*----------------------------------------------------------------------------*/ 826 /*-- Interrupts and timer unified handling-----------------------------------*/833 /*-- Interrupts handling -----------------------------------------------------*/ 827 834 /*----------------------------------------------------------------------------*/ 828 835 … … 830 837 { 831 838 .base = 0, 832 .size = 32,839 .size = 0, 833 840 } 834 841 }; 835 842 836 843 static irq_cmd_t ahci_cmds[] = { 837 { 838 /* Disable interrupt - interrupt is deasserted in qemu 1.0.1 */ 839 .cmd = CMD_PIO_WRITE_32, 840 .addr = NULL, 841 .value = AHCI_GHC_GHC_AE 842 }, 843 { 844 .cmd = CMD_PIO_READ_32, 845 .addr = NULL, 846 .dstarg = 1 847 }, 848 { 849 /* Clear interrupt status register - for vbox and real hw */ 850 .cmd = CMD_PIO_WRITE_A_32, 851 .addr = NULL, 852 .srcarg = 1 853 }, 854 { 855 .cmd = CMD_ACCEPT 856 } 844 AHCI_PORT_CMDS(0), 845 AHCI_PORT_CMDS(1), 846 AHCI_PORT_CMDS(2), 847 AHCI_PORT_CMDS(3), 848 AHCI_PORT_CMDS(4), 849 AHCI_PORT_CMDS(5), 850 AHCI_PORT_CMDS(6), 851 AHCI_PORT_CMDS(7), 852 AHCI_PORT_CMDS(8), 853 AHCI_PORT_CMDS(9), 854 AHCI_PORT_CMDS(10), 855 AHCI_PORT_CMDS(11), 856 AHCI_PORT_CMDS(12), 857 AHCI_PORT_CMDS(13), 858 AHCI_PORT_CMDS(14), 859 AHCI_PORT_CMDS(15), 860 AHCI_PORT_CMDS(16), 861 AHCI_PORT_CMDS(17), 862 AHCI_PORT_CMDS(18), 863 AHCI_PORT_CMDS(19), 864 AHCI_PORT_CMDS(20), 865 AHCI_PORT_CMDS(21), 866 AHCI_PORT_CMDS(22), 867 AHCI_PORT_CMDS(23), 868 AHCI_PORT_CMDS(24), 869 AHCI_PORT_CMDS(25), 870 AHCI_PORT_CMDS(26), 871 AHCI_PORT_CMDS(27), 872 AHCI_PORT_CMDS(28), 873 AHCI_PORT_CMDS(29), 874 AHCI_PORT_CMDS(30), 875 AHCI_PORT_CMDS(31) 857 876 }; 858 859 /** Unified AHCI interrupt and timer interrupt handler.860 *861 * @param ahci AHCI device.862 * @param is_timer Indicate timer interrupt.863 *864 */865 static void ahci_interrupt_or_timer(ahci_dev_t *ahci, bool is_timer)866 {867 /*868 * Get current value of hardware interrupt state register,869 * clear hardware register (write to clear behavior).870 */871 ahci_ghc_is_t is;872 873 is.u32 = ahci->memregs->ghc.is;874 ahci->memregs->ghc.is = is.u32;875 876 if (!is_timer)877 ahci->is_hw_interrupt = true;878 else if (is.u32)879 ahci->is_hw_interrupt = false;880 881 uint32_t port_event_flags = 0;882 uint32_t port_mask = 1;883 for (unsigned int i = 0; i < 32; i++) {884 sata_dev_t *sata = (sata_dev_t *) ahci->sata_devs[i];885 if (sata != NULL) {886 ahci_port_is_t pxis = ahci_get_and_clear_pxis(sata);887 888 /* Add value to shadow copy of port interrupt state register. */889 sata->shadow_pxis.u32 |= pxis.u32;890 891 /* Evaluate port event. */892 if ((ahci_port_is_end_of_operation(pxis)) ||893 (ahci_port_is_error(pxis)))894 port_event_flags |= port_mask;895 }896 897 port_mask <<= 1;898 }899 900 port_mask = 1;901 for (unsigned int i = 0; i < 32; i++) {902 sata_dev_t *sata = (sata_dev_t *) ahci->sata_devs[i];903 if ((port_event_flags & port_mask) && (sata != NULL)) {904 fibril_mutex_lock(&sata->event_lock);905 fibril_condvar_signal(&sata->event_condvar);906 fibril_mutex_unlock(&sata->event_lock);907 }908 909 port_mask <<= 1;910 }911 }912 913 /** AHCI timer interrupt handler.914 *915 * @param arg AHCI device.916 *917 */918 static void ahci_timer(void *arg)919 {920 ahci_dev_t *ahci = (ahci_dev_t *) arg;921 922 ahci_interrupt_or_timer(ahci, 1);923 924 if (ahci->is_hw_interrupt)925 fibril_timer_set(ahci->timer, AHCI_TIMER_TICKS, ahci_timer, ahci);926 else927 fibril_timer_set(ahci->timer, AHCI_TIMER_NO_INTR_TICKS,928 ahci_timer, ahci);929 }930 877 931 878 /** AHCI interrupt handler. … … 939 886 { 940 887 ahci_dev_t *ahci = (ahci_dev_t *) dev->driver_data; 941 942 ahci_interrupt_or_timer(ahci, 0); 943 944 /* Enable interrupt. */ 945 ahci->memregs->ghc.ghc |= AHCI_GHC_GHC_IE; 888 unsigned int port = IPC_GET_ARG1(*icall); 889 ahci_port_is_t pxis = IPC_GET_ARG2(*icall); 890 891 if (port >= AHCI_MAX_PORTS) 892 return; 893 894 sata_dev_t *sata = (sata_dev_t *) ahci->sata_devs[port]; 895 if (sata == NULL) 896 return; 897 898 /* Evaluate port event */ 899 if ((ahci_port_is_end_of_operation(pxis)) || 900 (ahci_port_is_error(pxis))) { 901 fibril_mutex_lock(&sata->event_lock); 902 903 sata->event_pxis = pxis; 904 fibril_condvar_signal(&sata->event_condvar); 905 906 fibril_mutex_unlock(&sata->event_lock); 907 } 946 908 } 947 909 … … 951 913 952 914 /** Allocate SATA device structure with buffers for hardware. 953 * 915 * 954 916 * @param port AHCI port structure 955 917 * … … 960 922 { 961 923 size_t size = 4096; 962 void *phys = NULL;963 void *virt_fb = NULL;964 void *virt_cmd = NULL;965 void *virt_table = NULL;924 void *phys = NULL; 925 void *virt_fb = NULL; 926 void *virt_cmd = NULL; 927 void *virt_table = NULL; 966 928 967 929 sata_dev_t *sata = malloc(sizeof(sata_dev_t)); … … 1054 1016 1055 1017 /** Create and initialize connected SATA structure device 1056 * 1018 * 1057 1019 * @param ahci AHCI device structure. 1058 1020 * @param dev DDF device structure. … … 1078 1040 /* Initialize synchronization structures */ 1079 1041 fibril_mutex_initialize(&sata->lock); 1080 fibril_mutex_initialize(&sata->pxis_lock);1081 1042 fibril_mutex_initialize(&sata->event_lock); 1082 1043 fibril_condvar_initialize(&sata->event_condvar); 1083 1044 1084 1045 ahci_sata_hw_start(sata); 1085 1046 1086 1047 /* Identify device. */ 1087 1048 if (ahci_identify_device(sata) != EOK) … … 1150 1111 1151 1112 /** Create AHCI device structure, intialize it and register interrupt routine. 1152 * 1113 * 1153 1114 * @param dev DDF device structure. 1154 1115 * … … 1165 1126 1166 1127 ahci->dev = dev; 1167 1168 /* Create timer for AHCI. */1169 ahci->timer = fibril_timer_create();1170 if (ahci->timer == NULL)1171 goto error_create_timer;1172 1128 1173 1129 hw_res_list_parsed_t hw_res_parsed; … … 1187 1143 /* Register interrupt handler */ 1188 1144 ahci_ranges[0].base = (size_t) hw_res_parsed.mem_ranges.ranges[0].address; 1189 ahci_ranges[0].size = sizeof(ahci_dev_t); 1190 1191 ahci_cmds[0].addr = 1192 ((uint32_t *) (size_t) hw_res_parsed.mem_ranges.ranges[0].address) + 1193 AHCI_GHC_GHC_REGISTER_OFFSET; 1194 ahci_cmds[1].addr = 1195 ((uint32_t *) (size_t) hw_res_parsed.mem_ranges.ranges[0].address) + 1196 AHCI_GHC_IS_REGISTER_OFFSET; 1197 ahci_cmds[2].addr = ahci_cmds[1].addr; 1145 ahci_ranges[0].size = sizeof(ahci_memregs_t); 1146 1147 for (unsigned int port = 0; port < AHCI_MAX_PORTS; port++) { 1148 size_t base = port * 7; 1149 1150 ahci_cmds[base].addr = 1151 ((uint32_t *) (size_t) hw_res_parsed.mem_ranges.ranges[0].address) + 1152 AHCI_PORTS_REGISTERS_OFFSET + port * AHCI_PORT_REGISTERS_SIZE + 1153 AHCI_PORT_IS_REGISTER_OFFSET; 1154 ahci_cmds[base + 2].addr = ahci_cmds[base].addr; 1155 1156 ahci_cmds[base + 3].addr = 1157 ((uint32_t *) (size_t) hw_res_parsed.mem_ranges.ranges[0].address) + 1158 AHCI_GHC_IS_REGISTER_OFFSET; 1159 ahci_cmds[base + 4].addr = ahci_cmds[base + 3].addr; 1160 } 1198 1161 1199 1162 irq_code_t ct; … … 1205 1168 int rc = register_interrupt_handler(dev, hw_res_parsed.irqs.irqs[0], 1206 1169 ahci_interrupt, &ct); 1207 1208 1170 if (rc != EOK) { 1209 ddf_msg(LVL_ERROR, "Failed register _interrupt_handler function.");1171 ddf_msg(LVL_ERROR, "Failed registering interrupt handler."); 1210 1172 goto error_register_interrupt_handler; 1211 1173 } … … 1230 1192 1231 1193 error_get_res_parsed: 1232 fibril_timer_destroy(ahci->timer);1233 1234 error_create_timer:1235 1194 free(ahci); 1236 1195 return NULL; … … 1249 1208 ccc.u32 = ahci->memregs->ghc.ccc_ctl; 1250 1209 ccc.en = 0; 1251 ahci->memregs->ghc.ccc_ctl = ccc.u32; 1210 ahci->memregs->ghc.ccc_ctl = ccc.u32; 1252 1211 1253 1212 /* Set master latency timer. */ … … 1263 1222 1264 1223 /* Enable AHCI and interrupt. */ 1265 ahci->memregs->ghc.ghc = AHCI_GHC_GHC_AE | AHCI_GHC_GHC_IE; 1224 ahci->memregs->ghc.ghc = AHCI_GHC_GHC_AE | AHCI_GHC_GHC_IE; 1266 1225 } 1267 1226 … … 1290 1249 dev->driver_data = ahci; 1291 1250 1292 /* Set timer and AHCI hardware start. */ 1293 fibril_timer_set(ahci->timer, AHCI_TIMER_TICKS, ahci_timer, ahci); 1251 /* Start AHCI hardware. */ 1294 1252 ahci_ahci_hw_start(ahci); 1295 1253
Note:
See TracChangeset
for help on using the changeset viewer.