Changes in uspace/drv/block/ahci/ahci.c [76c07e4:ae3ff9f5] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/block/ahci/ahci.c
r76c07e4 rae3ff9f5 49 49 #define NAME "ahci" 50 50 51 /** Number of ticks for watchdog timer. */ 52 #define AHCI_TIMER_TICKS 800000 53 54 /** Number of ticks for timer based interrupt. */ 55 #define AHCI_TIMER_NO_INTR_TICKS 8000 56 51 57 #define LO(ptr) \ 52 58 ((uint32_t) (((uint64_t) ((uintptr_t) (ptr))) & 0xffffffff)) … … 54 60 #define HI(ptr) \ 55 61 ((uint32_t) (((uint64_t) ((uintptr_t) (ptr))) >> 32)) 56 57 /** Interrupt pseudocode for a single port58 *59 * The interrupt handling works as follows:60 *61 * 1. Port interrupt status register is read62 * (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 read66 * and cleared (any potential interrupts from67 * 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 }113 62 114 63 static int ahci_get_sata_device_name(ddf_fun_t *, size_t, char *); … … 294 243 /*----------------------------------------------------------------------------*/ 295 244 296 /** Wait for interrupt event.245 /** Get and clear AHCI port interrupt state register. 297 246 * 298 247 * @param sata SATA device structure. … … 301 250 * 302 251 */ 303 static ahci_port_is_t ahci_wait_event(sata_dev_t *sata) 304 { 305 fibril_mutex_lock(&sata->event_lock); 306 307 sata->event_pxis = 0; 308 while (sata->event_pxis == 0) 309 fibril_condvar_wait(&sata->event_condvar, &sata->event_lock); 310 311 ahci_port_is_t pxis = sata->event_pxis; 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; 312 260 313 261 if (ahci_port_is_permanent_error(pxis)) 314 262 sata->is_invalid_device = true; 315 263 316 fibril_mutex_unlock(&sata-> event_lock);264 fibril_mutex_unlock(&sata->pxis_lock); 317 265 318 266 return pxis; … … 327 275 static void ahci_identify_device_cmd(sata_dev_t *sata, void *phys) 328 276 { 277 /* Clear interrupt state registers */ 278 ahci_get_and_clear_pxis(sata); 279 sata->shadow_pxis.u32 = 0; 280 329 281 volatile sata_std_command_frame_t *cmd = 330 282 (sata_std_command_frame_t *) sata->cmd_table; … … 356 308 sata->cmd_header->flags = 357 309 AHCI_CMDHDR_FLAGS_CLEAR_BUSY_UPON_OK | 358 AHCI_CMDHDR_FLAGS_2DWCMD; 310 AHCI_CMDHDR_FLAGS_2DWCMD; 359 311 sata->cmd_header->bytesprocessed = 0; 360 312 … … 372 324 static void ahci_identify_packet_device_cmd(sata_dev_t *sata, void *phys) 373 325 { 374 volatile sata_std_command_frame_t *cmd = 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 = 375 331 (sata_std_command_frame_t *) sata->cmd_table; 376 332 … … 399 355 400 356 sata->cmd_header->prdtl = 1; 401 sata->cmd_header->flags = 357 sata->cmd_header->flags = 402 358 AHCI_CMDHDR_FLAGS_CLEAR_BUSY_UPON_OK | 403 359 AHCI_CMDHDR_FLAGS_2DWCMD; … … 426 382 void *phys; 427 383 sata_identify_data_t *idata; 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); 384 dmamem_map_anonymous(512, AS_AREA_READ | AS_AREA_WRITE, 0, &phys, 385 (void **) &idata); 386 bzero(idata, 512); 436 387 437 388 fibril_mutex_lock(&sata->lock); 438 389 439 390 ahci_identify_device_cmd(sata, phys); 440 ahci_port_is_t pxis = ahci_wait_event(sata); 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; 441 398 442 399 if (sata->is_invalid_device) { … … 448 405 if (ahci_port_is_tfes(pxis)) { 449 406 ahci_identify_packet_device_cmd(sata, phys); 450 pxis = ahci_wait_event(sata); 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; 451 414 452 415 if ((sata->is_invalid_device) || (ahci_port_is_error(pxis))) { … … 478 441 "%s: Sector length other than 512 B not supported", 479 442 sata->model); 480 goto error; 443 goto error; 481 444 } 482 445 … … 486 449 "%s: Sector length other than 512 B not supported", 487 450 sata->model); 488 goto error; 451 goto error; 489 452 } 490 453 } … … 525 488 goto error; 526 489 } else { 527 for (u int8_t i = 0; i < 7; i++) {490 for (unsigned int i = 0; i < 7; i++) { 528 491 if (udma_mask & (1 << i)) 529 492 sata->highest_udma_mode = i; … … 552 515 static void ahci_set_mode_cmd(sata_dev_t *sata, void* phys, uint8_t mode) 553 516 { 517 /* Clear interrupt state registers */ 518 ahci_get_and_clear_pxis(sata); 519 sata->shadow_pxis.u32 = 0; 520 554 521 volatile sata_std_command_frame_t *cmd = 555 522 (sata_std_command_frame_t *) sata->cmd_table; … … 632 599 uint8_t mode = 0x40 | (sata->highest_udma_mode & 0x07); 633 600 ahci_set_mode_cmd(sata, phys, mode); 634 ahci_port_is_t pxis = ahci_wait_event(sata); 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; 635 608 636 609 if (sata->is_invalid_device) { … … 668 641 static void ahci_rb_fpdma_cmd(sata_dev_t *sata, void *phys, uint64_t blocknum) 669 642 { 643 /* Clear interrupt state registers */ 644 ahci_get_and_clear_pxis(sata); 645 sata->shadow_pxis.u32 = 0; 646 670 647 volatile sata_ncq_command_frame_t *cmd = 671 648 (sata_ncq_command_frame_t *) sata->cmd_table; … … 732 709 733 710 ahci_rb_fpdma_cmd(sata, phys, blocknum); 734 ahci_port_is_t pxis = ahci_wait_event(sata); 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; 735 718 736 719 if ((sata->is_invalid_device) || (ahci_port_is_error(pxis))) { … … 754 737 static void ahci_wb_fpdma_cmd(sata_dev_t *sata, void *phys, uint64_t blocknum) 755 738 { 756 volatile sata_ncq_command_frame_t *cmd = 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 = 757 744 (sata_ncq_command_frame_t *) sata->cmd_table; 758 745 … … 780 767 cmd->lba5 = (blocknum >> 40) & 0xff; 781 768 782 volatile ahci_cmd_prdt_t * prdt =769 volatile ahci_cmd_prdt_t * prdt = 783 770 (ahci_cmd_prdt_t *) (&sata->cmd_table[0x20]); 784 771 … … 819 806 820 807 ahci_wb_fpdma_cmd(sata, phys, blocknum); 821 ahci_port_is_t pxis = ahci_wait_event(sata); 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; 822 815 823 816 if ((sata->is_invalid_device) || (ahci_port_is_error(pxis))) { … … 831 824 832 825 /*----------------------------------------------------------------------------*/ 833 /*-- Interrupts handling -----------------------------------------------------*/826 /*-- Interrupts and timer unified handling -----------------------------------*/ 834 827 /*----------------------------------------------------------------------------*/ 835 828 … … 837 830 { 838 831 .base = 0, 839 .size = 0,832 .size = 32, 840 833 } 841 834 }; 842 835 843 836 static irq_cmd_t ahci_cmds[] = { 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) 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 } 876 857 }; 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 else 927 fibril_timer_set(ahci->timer, AHCI_TIMER_NO_INTR_TICKS, 928 ahci_timer, ahci); 929 } 877 930 878 931 /** AHCI interrupt handler. … … 886 939 { 887 940 ahci_dev_t *ahci = (ahci_dev_t *) dev->driver_data; 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 } 941 942 ahci_interrupt_or_timer(ahci, 0); 943 944 /* Enable interrupt. */ 945 ahci->memregs->ghc.ghc |= AHCI_GHC_GHC_IE; 908 946 } 909 947 … … 913 951 914 952 /** Allocate SATA device structure with buffers for hardware. 915 * 953 * 916 954 * @param port AHCI port structure 917 955 * … … 922 960 { 923 961 size_t size = 4096; 924 void *phys = NULL;925 void *virt_fb = NULL;926 void *virt_cmd = NULL;927 void *virt_table = NULL;962 void* phys = NULL; 963 void* virt_fb = NULL; 964 void* virt_cmd = NULL; 965 void* virt_table = NULL; 928 966 929 967 sata_dev_t *sata = malloc(sizeof(sata_dev_t)); … … 1016 1054 1017 1055 /** Create and initialize connected SATA structure device 1018 * 1056 * 1019 1057 * @param ahci AHCI device structure. 1020 1058 * @param dev DDF device structure. … … 1040 1078 /* Initialize synchronization structures */ 1041 1079 fibril_mutex_initialize(&sata->lock); 1080 fibril_mutex_initialize(&sata->pxis_lock); 1042 1081 fibril_mutex_initialize(&sata->event_lock); 1043 1082 fibril_condvar_initialize(&sata->event_condvar); 1044 1083 1045 1084 ahci_sata_hw_start(sata); 1046 1085 1047 1086 /* Identify device. */ 1048 1087 if (ahci_identify_device(sata) != EOK) … … 1111 1150 1112 1151 /** Create AHCI device structure, intialize it and register interrupt routine. 1113 * 1152 * 1114 1153 * @param dev DDF device structure. 1115 1154 * … … 1126 1165 1127 1166 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; 1128 1172 1129 1173 hw_res_list_parsed_t hw_res_parsed; … … 1143 1187 /* Register interrupt handler */ 1144 1188 ahci_ranges[0].base = (size_t) hw_res_parsed.mem_ranges.ranges[0].address; 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 } 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; 1161 1198 1162 1199 irq_code_t ct; … … 1168 1205 int rc = register_interrupt_handler(dev, hw_res_parsed.irqs.irqs[0], 1169 1206 ahci_interrupt, &ct); 1207 1170 1208 if (rc != EOK) { 1171 ddf_msg(LVL_ERROR, "Failed register ing interrupt handler.");1209 ddf_msg(LVL_ERROR, "Failed register_interrupt_handler function."); 1172 1210 goto error_register_interrupt_handler; 1173 1211 } … … 1192 1230 1193 1231 error_get_res_parsed: 1232 fibril_timer_destroy(ahci->timer); 1233 1234 error_create_timer: 1194 1235 free(ahci); 1195 1236 return NULL; … … 1208 1249 ccc.u32 = ahci->memregs->ghc.ccc_ctl; 1209 1250 ccc.en = 0; 1210 ahci->memregs->ghc.ccc_ctl = ccc.u32; 1251 ahci->memregs->ghc.ccc_ctl = ccc.u32; 1211 1252 1212 1253 /* Set master latency timer. */ … … 1222 1263 1223 1264 /* Enable AHCI and interrupt. */ 1224 ahci->memregs->ghc.ghc = AHCI_GHC_GHC_AE | AHCI_GHC_GHC_IE; 1265 ahci->memregs->ghc.ghc = AHCI_GHC_GHC_AE | AHCI_GHC_GHC_IE; 1225 1266 } 1226 1267 … … 1249 1290 dev->driver_data = ahci; 1250 1291 1251 /* Start AHCI hardware. */ 1292 /* Set timer and AHCI hardware start. */ 1293 fibril_timer_set(ahci->timer, AHCI_TIMER_TICKS, ahci_timer, ahci); 1252 1294 ahci_ahci_hw_start(ahci); 1253 1295
Note:
See TracChangeset
for help on using the changeset viewer.