Changeset 64cf7a3 in mainline
- Timestamp:
- 2024-05-06T18:33:22Z (8 months ago)
- Branches:
- master
- Children:
- 2791fbb7
- Parents:
- 21989e5
- Location:
- uspace/drv
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/block/ata_bd/ata_bd.c
r21989e5 r64cf7a3 1 1 /* 2 * Copyright (c) 20 13Jiri Svoboda2 * Copyright (c) 2024 Jiri Svoboda 3 3 * All rights reserved. 4 4 * … … 49 49 50 50 #include <ddi.h> 51 #include <ddf/interrupt.h> 51 52 #include <ddf/log.h> 52 53 #include <async.h> … … 73 74 #define NAME "ata_bd" 74 75 75 /** Number of defined legacy controller base addresses. */76 #define LEGACY_CTLS 477 78 76 /** 79 77 * Size of data returned from Identify Device or Identify Packet Device … … 84 82 static errno_t ata_bd_init_io(ata_ctrl_t *ctrl); 85 83 static void ata_bd_fini_io(ata_ctrl_t *ctrl); 84 static errno_t ata_bd_init_irq(ata_ctrl_t *ctrl); 85 static void ata_bd_fini_irq(ata_ctrl_t *ctrl); 86 86 87 87 static errno_t ata_bd_open(bd_srvs_t *, bd_srv_t *); … … 121 121 static errno_t wait_status(ata_ctrl_t *ctrl, unsigned set, unsigned n_reset, 122 122 uint8_t *pstatus, unsigned timeout); 123 static errno_t wait_irq(ata_ctrl_t *ctrl, uint8_t *pstatus, unsigned timeout); 124 static void ata_irq_handler(ipc_call_t *call, ddf_dev_t *dev); 123 125 124 126 bd_ops_t ata_bd_ops = { … … 133 135 }; 134 136 137 static const irq_pio_range_t ata_irq_ranges[] = { 138 { 139 .base = 0, 140 .size = sizeof(ata_cmd_t) 141 } 142 }; 143 144 /** ATA interrupt pseudo code. */ 145 static const irq_cmd_t ata_irq_cmds[] = { 146 { 147 .cmd = CMD_PIO_READ_8, 148 .addr = NULL, /* will be patched in run-time */ 149 .dstarg = 1 150 }, 151 { 152 .cmd = CMD_ACCEPT 153 } 154 }; 155 135 156 static disk_t *bd_srv_disk(bd_srv_t *bd) 136 157 { … … 144 165 145 166 /** Initialize ATA controller. */ 146 errno_t ata_ctrl_init(ata_ctrl_t *ctrl, ata_ base_t *res)167 errno_t ata_ctrl_init(ata_ctrl_t *ctrl, ata_hwres_t *res) 147 168 { 148 169 int i; 149 170 errno_t rc; 150 171 int n_disks; 172 bool irq_inited = false; 151 173 152 174 ddf_msg(LVL_DEBUG, "ata_ctrl_init()"); 153 175 154 176 fibril_mutex_initialize(&ctrl->lock); 177 fibril_mutex_initialize(&ctrl->irq_lock); 178 fibril_condvar_initialize(&ctrl->irq_cv); 155 179 ctrl->cmd_physical = res->cmd; 156 180 ctrl->ctl_physical = res->ctl; 181 ctrl->irq = res->irq; 157 182 158 183 ddf_msg(LVL_NOTE, "I/O address %p/%p", (void *) ctrl->cmd_physical, … … 162 187 if (rc != EOK) 163 188 return rc; 189 190 rc = ata_bd_init_irq(ctrl); 191 if (rc != EOK) 192 return rc; 193 194 irq_inited = true; 164 195 165 196 for (i = 0; i < MAX_DISKS; i++) { … … 205 236 } 206 237 } 238 if (irq_inited) 239 ata_bd_fini_irq(ctrl); 207 240 ata_bd_fini_io(ctrl); 208 241 return rc; … … 228 261 } 229 262 263 ata_bd_fini_irq(ctrl); 230 264 ata_bd_fini_io(ctrl); 231 265 fibril_mutex_unlock(&ctrl->lock); … … 329 363 330 364 ctrl->ctl = vaddr; 331 332 365 return EOK; 333 366 } … … 338 371 (void) ctrl; 339 372 /* XXX TODO */ 373 } 374 375 /** Initialize IRQ. */ 376 static errno_t ata_bd_init_irq(ata_ctrl_t *ctrl) 377 { 378 irq_code_t irq_code; 379 async_sess_t *parent_sess; 380 irq_pio_range_t *ranges; 381 irq_cmd_t *cmds; 382 errno_t rc; 383 384 if (ctrl->irq < 0) 385 return EOK; 386 387 ranges = malloc(sizeof(ata_irq_ranges)); 388 if (ranges == NULL) 389 return ENOMEM; 390 391 cmds = malloc(sizeof(ata_irq_cmds)); 392 if (cmds == NULL) { 393 free(cmds); 394 return ENOMEM; 395 } 396 397 memcpy(ranges, &ata_irq_ranges, sizeof(ata_irq_ranges)); 398 ranges[0].base = ctrl->cmd_physical; 399 memcpy(cmds, &ata_irq_cmds, sizeof(ata_irq_cmds)); 400 cmds[0].addr = &ctrl->cmd->status; 401 402 irq_code.rangecount = sizeof(ata_irq_ranges) / sizeof(irq_pio_range_t); 403 irq_code.ranges = ranges; 404 irq_code.cmdcount = sizeof(ata_irq_cmds) / sizeof(irq_cmd_t); 405 irq_code.cmds = cmds; 406 407 ddf_msg(LVL_NOTE, "IRQ %d", ctrl->irq); 408 rc = register_interrupt_handler(ctrl->dev, ctrl->irq, ata_irq_handler, 409 &irq_code, &ctrl->ihandle); 410 if (rc != EOK) { 411 ddf_msg(LVL_ERROR, "Error registering IRQ."); 412 goto error; 413 } 414 415 parent_sess = ddf_dev_parent_sess_get(ctrl->dev); 416 417 rc = hw_res_enable_interrupt(parent_sess, ctrl->irq); 418 if (rc != EOK) { 419 ddf_msg(LVL_ERROR, "Error enabling IRQ."); 420 (void) unregister_interrupt_handler(ctrl->dev, 421 ctrl->ihandle); 422 goto error; 423 } 424 425 free(ranges); 426 free(cmds); 427 return EOK; 428 error: 429 free(ranges); 430 free(cmds); 431 return rc; 432 } 433 434 /** Clean up IRQ. */ 435 static void ata_bd_fini_irq(ata_ctrl_t *ctrl) 436 { 437 errno_t rc; 438 async_sess_t *parent_sess; 439 440 parent_sess = ddf_dev_parent_sess_get(ctrl->dev); 441 442 rc = hw_res_disable_interrupt(parent_sess, ctrl->irq); 443 if (rc != EOK) 444 ddf_msg(LVL_ERROR, "Error disabling IRQ."); 445 446 (void) unregister_interrupt_handler(ctrl->dev, ctrl->ihandle); 340 447 } 341 448 … … 519 626 errno_t rc; 520 627 521 if (size < cnt * disk->block_size) 522 return EINVAL; 628 if (size < cnt * disk->block_size) { 629 rc = EINVAL; 630 goto error; 631 } 523 632 524 633 /* Maximum number of blocks to transfer at the same time */ … … 534 643 535 644 if (rc != EOK) 536 return rc;645 goto error; 537 646 538 647 ba += nb; … … 542 651 543 652 return EOK; 653 error: 654 ddf_msg(LVL_DEBUG, "ata_bd_read_blocks: rc=%d", rc); 655 return rc; 544 656 } 545 657 … … 622 734 size_t bidx; 623 735 uint8_t status; 736 errno_t rc; 624 737 625 738 assert(nblocks > 0); … … 628 741 bidx = 0; 629 742 while (nblocks > 0) { 630 if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) 743 if (ctrl->irq >= 0) 744 rc = wait_irq(ctrl, &status, TIMEOUT_BSY); 745 else 746 rc = wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY); 747 748 if (rc != EOK) { 749 ddf_msg(LVL_DEBUG, "wait_irq/wait_status failed"); 631 750 return EIO; 751 } 632 752 633 753 if ((status & SR_DRQ) == 0) { 754 ddf_msg(LVL_DEBUG, "DRQ == 0"); 634 755 break; 635 756 } … … 644 765 } 645 766 646 if ((status & SR_ERR) != 0) 647 return EIO; 648 if (nblocks > 0) 649 return EIO; 767 if ((status & SR_ERR) != 0) { 768 ddf_msg(LVL_DEBUG, "status & SR_ERR != 0"); 769 return EIO; 770 } 771 if (nblocks > 0) { 772 ddf_msg(LVL_DEBUG, "remaining nblocks = %zu", nblocks); 773 return EIO; 774 } 650 775 651 776 return EOK; … … 660 785 size_t bidx; 661 786 uint8_t status; 787 errno_t rc; 662 788 663 789 assert(nblocks > 0); 664 790 assert(blk_size % 2 == 0); 665 791 792 rc = wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY); 793 if (rc != EOK) 794 return EIO; 795 666 796 bidx = 0; 667 797 while (nblocks > 0) { 668 if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) 669 return EIO; 670 671 if ((status & SR_DRQ) == 0) 798 if ((status & SR_DRQ) == 0) { 799 ddf_msg(LVL_DEBUG, "pio_data_out: unexpected DRQ=0"); 672 800 break; 801 } 673 802 674 803 /* Write data to the device buffer. */ … … 678 807 } 679 808 809 if (ctrl->irq >= 0) 810 rc = wait_irq(ctrl, &status, TIMEOUT_BSY); 811 else 812 rc = wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY); 813 if (rc != EOK) 814 return EIO; 815 680 816 --nblocks; 681 817 } … … 694 830 ata_ctrl_t *ctrl = disk->ctrl; 695 831 uint8_t status; 696 697 if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) 832 errno_t rc; 833 834 if (ctrl->irq >= 0) 835 rc = wait_irq(ctrl, &status, TIMEOUT_BSY); 836 else 837 rc = wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY); 838 839 if (rc != EOK) 698 840 return EIO; 699 841 … … 738 880 pio_write_8(&ctrl->cmd->command, CMD_IDENTIFY_DRIVE); 739 881 740 if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)741 return ETIMEOUT;742 743 /*744 * If ERR is set, this may be a packet device, so return EIO to cause745 * the caller to check for one.746 */747 if ((status & SR_ERR) != 0)748 return EIO;749 750 882 /* 751 883 * For probing purposes we need to wait for some status bit to become 752 884 * active - otherwise we could be fooled just by receiving all zeroes. 753 885 */ 754 if (wait_status(ctrl, SR_DRQ, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK) 755 return ETIMEOUT; 886 if (wait_status(ctrl, SR_DRQ, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK) { 887 if ((status & SR_ERR) == 0) { 888 /* Probably no device at all */ 889 return ETIMEOUT; 890 } 891 } 756 892 757 893 return ata_pio_data_in(disk, buf, identify_data_size, … … 811 947 size_t bidx; 812 948 uint16_t val; 949 errno_t rc; 813 950 814 951 fibril_mutex_lock(&ctrl->lock); … … 848 985 remain = obuf_size; 849 986 while (remain > 0) { 850 if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) { 987 if (ctrl->irq >= 0) 988 rc = wait_irq(ctrl, &status, TIMEOUT_BSY); 989 else 990 rc = wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY); 991 992 if (rc != EOK) { 851 993 fibril_mutex_unlock(&ctrl->lock); 852 994 return EIO; … … 875 1017 remain -= data_size; 876 1018 } 1019 1020 if (ctrl->irq >= 0) 1021 rc = wait_irq(ctrl, &status, TIMEOUT_BSY); 1022 else 1023 rc = wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY); 877 1024 878 1025 fibril_mutex_unlock(&ctrl->lock); … … 1047 1194 1048 1195 /* Compute block coordinates. */ 1049 if (coord_calc(disk, ba, &bc) != EOK) 1196 if (coord_calc(disk, ba, &bc) != EOK) { 1197 ddf_msg(LVL_NOTE, "ata_rcmd_read() -> coord_calc failed"); 1050 1198 return EINVAL; 1199 } 1051 1200 1052 1201 /* New value for Drive/Head register */ … … 1062 1211 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) { 1063 1212 fibril_mutex_unlock(&ctrl->lock); 1213 ddf_msg(LVL_NOTE, "ata_rcmd_read() -> wait_status failed"); 1064 1214 return EIO; 1065 1215 } … … 1069 1219 if (wait_status(ctrl, SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) { 1070 1220 fibril_mutex_unlock(&ctrl->lock); 1221 ddf_msg(LVL_NOTE, "ata_rcmd_read() -> wait_status 2 failed"); 1071 1222 return EIO; 1072 1223 } … … 1083 1234 fibril_mutex_unlock(&ctrl->lock); 1084 1235 1236 if (rc != EOK) 1237 ddf_msg(LVL_NOTE, "ata_rcmd_read() -> pio_data_in->%d", rc); 1085 1238 return rc; 1086 1239 } … … 1355 1508 } 1356 1509 1510 /** Wait for IRQ and return status. 1511 * 1512 * @param ctrl Controller 1513 * @param pstatus Pointer where to store last read status or NULL. 1514 * @param timeout Timeout in 10ms units. 1515 * 1516 * @return EOK on success, EIO on timeout. 1517 */ 1518 static errno_t wait_irq(ata_ctrl_t *ctrl, uint8_t *pstatus, unsigned timeout) 1519 { 1520 fibril_mutex_lock(&ctrl->irq_lock); 1521 while (!ctrl->irq_fired) 1522 fibril_condvar_wait(&ctrl->irq_cv, &ctrl->irq_lock); 1523 1524 ctrl->irq_fired = false; 1525 *pstatus = ctrl->irq_status; 1526 fibril_mutex_unlock(&ctrl->irq_lock); 1527 return EOK; 1528 } 1529 1530 /** Interrupt handler. 1531 * 1532 * @param call Call data 1533 * @param dev Device that caused the interrupt 1534 */ 1535 static void ata_irq_handler(ipc_call_t *call, ddf_dev_t *dev) 1536 { 1537 ata_ctrl_t *ctrl = (ata_ctrl_t *)ddf_dev_data_get(dev); 1538 uint8_t status; 1539 async_sess_t *parent_sess; 1540 1541 status = ipc_get_arg1(call); 1542 1543 fibril_mutex_lock(&ctrl->irq_lock); 1544 ctrl->irq_fired = true; 1545 ctrl->irq_status = status; 1546 fibril_mutex_unlock(&ctrl->irq_lock); 1547 fibril_condvar_broadcast(&ctrl->irq_cv); 1548 1549 parent_sess = ddf_dev_parent_sess_get(dev); 1550 hw_res_clear_interrupt(parent_sess, ctrl->irq); 1551 } 1552 1357 1553 /** 1358 1554 * @} -
uspace/drv/block/ata_bd/ata_bd.h
r21989e5 r64cf7a3 1 1 /* 2 * Copyright (c) 20 09Jiri Svoboda2 * Copyright (c) 2024 Jiri Svoboda 3 3 * All rights reserved. 4 4 * … … 40 40 #include <ddf/driver.h> 41 41 #include <fibril_synch.h> 42 #include <stdbool.h> 42 43 #include <str.h> 43 44 #include <stdint.h> … … 47 48 #define NAME "ata_bd" 48 49 49 /** Base addresses for ATA I/O blocks.*/50 /** ATA hardware resources */ 50 51 typedef struct { 51 52 uintptr_t cmd; /**< Command block base address. */ 52 53 uintptr_t ctl; /**< Control block base address. */ 53 } ata_base_t; 54 int irq; /**< IRQ */ 55 } ata_hwres_t; 54 56 55 57 /** Timeout definitions. Unit is 10 ms. */ … … 140 142 /** Control registers */ 141 143 ata_ctl_t *ctl; 144 /** IRQ (-1 if not used) */ 145 int irq; 146 /** IRQ handle */ 147 cap_irq_handle_t ihandle; 142 148 143 149 /** Per-disk state. */ 144 150 disk_t disk[MAX_DISKS]; 145 151 152 /** Synchronize controller access */ 146 153 fibril_mutex_t lock; 154 /** Synchronize access to irq_fired/irq_status */ 155 fibril_mutex_t irq_lock; 156 /** Signalled by IRQ handler */ 157 fibril_condvar_t irq_cv; 158 /** Set to true when interrupt occurs */ 159 bool irq_fired; 160 /** Value of status register read by interrupt handler */ 161 uint8_t irq_status; 147 162 } ata_ctrl_t; 148 163 … … 153 168 } ata_fun_t; 154 169 155 extern errno_t ata_ctrl_init(ata_ctrl_t *, ata_ base_t *);170 extern errno_t ata_ctrl_init(ata_ctrl_t *, ata_hwres_t *); 156 171 extern errno_t ata_ctrl_remove(ata_ctrl_t *); 157 172 extern errno_t ata_ctrl_gone(ata_ctrl_t *); -
uspace/drv/block/ata_bd/main.c
r21989e5 r64cf7a3 1 1 /* 2 * Copyright (c) 20 13Jiri Svoboda2 * Copyright (c) 2024 Jiri Svoboda 3 3 * All rights reserved. 4 4 * … … 66 66 }; 67 67 68 static errno_t ata_get_res(ddf_dev_t *dev, ata_ base_t *ata_res)68 static errno_t ata_get_res(ddf_dev_t *dev, ata_hwres_t *ata_res) 69 69 { 70 70 async_sess_t *parent_sess; … … 86 86 } 87 87 88 /* I/O ranges */ 89 88 90 addr_range_t *cmd_rng = &hw_res.io_ranges.ranges[0]; 89 91 addr_range_t *ctl_rng = &hw_res.io_ranges.ranges[1]; … … 101 103 } 102 104 105 /* IRQ */ 106 if (hw_res.irqs.count > 0) { 107 ata_res->irq = hw_res.irqs.irqs[0]; 108 } else { 109 ata_res->irq = -1; 110 } 111 103 112 return EOK; 104 113 error: … … 115 124 { 116 125 ata_ctrl_t *ctrl; 117 ata_ base_t res;126 ata_hwres_t res; 118 127 errno_t rc; 119 128 -
uspace/drv/bus/isa/isa.dev
r21989e5 r64cf7a3 55 55 io_range 0x1f0 8 56 56 io_range 0x3f0 8 57 irq 14 57 58 58 59 ata-c2: … … 60 61 io_range 0x170 8 61 62 io_range 0x370 8 62 63 ata-c3: 64 match 100 isa/ata_bd 65 io_range 0x1e8 8 66 io_range 0x3e8 8 67 68 ata-c4: 69 match 100 isa/ata_bd 70 io_range 0x168 8 71 io_range 0x368 8 63 irq 15
Note:
See TracChangeset
for help on using the changeset viewer.