Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/block/ahci/ahci.c

    r76c07e4 rae3ff9f5  
    4949#define NAME  "ahci"
    5050
     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
    5157#define LO(ptr) \
    5258        ((uint32_t) (((uint64_t) ((uintptr_t) (ptr))) & 0xffffffff))
     
    5460#define HI(ptr) \
    5561        ((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         }
    11362
    11463static int ahci_get_sata_device_name(ddf_fun_t *, size_t, char *);
     
    294243/*----------------------------------------------------------------------------*/
    295244
    296 /** Wait for interrupt event.
     245/** Get and clear AHCI port interrupt state register.
    297246 *
    298247 * @param sata SATA device structure.
     
    301250 *
    302251 */
    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;
     252static 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;
    312260       
    313261        if (ahci_port_is_permanent_error(pxis))
    314262                sata->is_invalid_device = true;
    315263       
    316         fibril_mutex_unlock(&sata->event_lock);
     264        fibril_mutex_unlock(&sata->pxis_lock);
    317265       
    318266        return pxis;
     
    327275static void ahci_identify_device_cmd(sata_dev_t *sata, void *phys)
    328276{
     277        /* Clear interrupt state registers */
     278        ahci_get_and_clear_pxis(sata);
     279        sata->shadow_pxis.u32 = 0;
     280       
    329281        volatile sata_std_command_frame_t *cmd =
    330282            (sata_std_command_frame_t *) sata->cmd_table;
     
    356308        sata->cmd_header->flags =
    357309            AHCI_CMDHDR_FLAGS_CLEAR_BUSY_UPON_OK |
    358             AHCI_CMDHDR_FLAGS_2DWCMD;
     310            AHCI_CMDHDR_FLAGS_2DWCMD; 
    359311        sata->cmd_header->bytesprocessed = 0;
    360312       
     
    372324static void ahci_identify_packet_device_cmd(sata_dev_t *sata, void *phys)
    373325{
    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 =
    375331            (sata_std_command_frame_t *) sata->cmd_table;
    376332       
     
    399355       
    400356        sata->cmd_header->prdtl = 1;
    401         sata->cmd_header->flags =
     357        sata->cmd_header->flags = 
    402358            AHCI_CMDHDR_FLAGS_CLEAR_BUSY_UPON_OK |
    403359            AHCI_CMDHDR_FLAGS_2DWCMD;
     
    426382        void *phys;
    427383        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);
    436387       
    437388        fibril_mutex_lock(&sata->lock);
    438389       
    439390        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;
    441398       
    442399        if (sata->is_invalid_device) {
     
    448405        if (ahci_port_is_tfes(pxis)) {
    449406                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;
    451414               
    452415                if ((sata->is_invalid_device) || (ahci_port_is_error(pxis))) {
     
    478441                            "%s: Sector length other than 512 B not supported",
    479442                            sata->model);
    480                         goto error;
     443                        goto error;     
    481444                }
    482445               
     
    486449                            "%s: Sector length other than 512 B not supported",
    487450                            sata->model);
    488                         goto error;
     451                        goto error;     
    489452                }
    490453        }
     
    525488                goto error;
    526489        } else {
    527                 for (uint8_t i = 0; i < 7; i++) {
     490                for (unsigned int i = 0; i < 7; i++) {
    528491                        if (udma_mask & (1 << i))
    529492                                sata->highest_udma_mode = i;
     
    552515static void ahci_set_mode_cmd(sata_dev_t *sata, void* phys, uint8_t mode)
    553516{
     517        /* Clear interrupt state registers */
     518        ahci_get_and_clear_pxis(sata);
     519        sata->shadow_pxis.u32 = 0;
     520       
    554521        volatile sata_std_command_frame_t *cmd =
    555522            (sata_std_command_frame_t *) sata->cmd_table;
     
    632599        uint8_t mode = 0x40 | (sata->highest_udma_mode & 0x07);
    633600        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;
    635608       
    636609        if (sata->is_invalid_device) {
     
    668641static void ahci_rb_fpdma_cmd(sata_dev_t *sata, void *phys, uint64_t blocknum)
    669642{
     643        /* Clear interrupt state registers */
     644        ahci_get_and_clear_pxis(sata);
     645        sata->shadow_pxis.u32 = 0;
     646       
    670647        volatile sata_ncq_command_frame_t *cmd =
    671648            (sata_ncq_command_frame_t *) sata->cmd_table;
     
    732709       
    733710        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;
    735718       
    736719        if ((sata->is_invalid_device) || (ahci_port_is_error(pxis))) {
     
    754737static void ahci_wb_fpdma_cmd(sata_dev_t *sata, void *phys, uint64_t blocknum)
    755738{
    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 =
    757744            (sata_ncq_command_frame_t *) sata->cmd_table;
    758745       
     
    780767        cmd->lba5 = (blocknum >> 40) & 0xff;
    781768       
    782         volatile ahci_cmd_prdt_t *prdt =
     769        volatile ahci_cmd_prdt_t * prdt =
    783770            (ahci_cmd_prdt_t *) (&sata->cmd_table[0x20]);
    784771       
     
    819806       
    820807        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;
    822815       
    823816        if ((sata->is_invalid_device) || (ahci_port_is_error(pxis))) {
     
    831824
    832825/*----------------------------------------------------------------------------*/
    833 /*-- Interrupts handling -----------------------------------------------------*/
     826/*-- Interrupts and timer unified handling -----------------------------------*/
    834827/*----------------------------------------------------------------------------*/
    835828
     
    837830        {
    838831                .base = 0,
    839                 .size = 0,
     832                .size = 32,
    840833        }
    841834};
    842835
    843836static 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        }
    876857};
     858
     859/** Unified AHCI interrupt and timer interrupt handler.
     860 *
     861 * @param ahci     AHCI device.
     862 * @param is_timer Indicate timer interrupt.
     863 *
     864 */
     865static 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 */
     918static 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}
    877930
    878931/** AHCI interrupt handler.
     
    886939{
    887940        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;
    908946}
    909947
     
    913951
    914952/** Allocate SATA device structure with buffers for hardware.
    915  *
     953 * 
    916954 * @param port AHCI port structure
    917955 *
     
    922960{
    923961        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;
    928966       
    929967        sata_dev_t *sata = malloc(sizeof(sata_dev_t));
     
    10161054
    10171055/** Create and initialize connected SATA structure device
    1018  *
     1056 * 
    10191057 * @param ahci     AHCI device structure.
    10201058 * @param dev      DDF device structure.
     
    10401078        /* Initialize synchronization structures */
    10411079        fibril_mutex_initialize(&sata->lock);
     1080        fibril_mutex_initialize(&sata->pxis_lock);
    10421081        fibril_mutex_initialize(&sata->event_lock);
    10431082        fibril_condvar_initialize(&sata->event_condvar);
    1044        
     1083
    10451084        ahci_sata_hw_start(sata);
    1046        
     1085
    10471086        /* Identify device. */
    10481087        if (ahci_identify_device(sata) != EOK)
     
    11111150
    11121151/** Create AHCI device structure, intialize it and register interrupt routine.
    1113  *
     1152 * 
    11141153 * @param dev DDF device structure.
    11151154 *
     
    11261165       
    11271166        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;
    11281172       
    11291173        hw_res_list_parsed_t hw_res_parsed;
     
    11431187        /* Register interrupt handler */
    11441188        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;
    11611198       
    11621199        irq_code_t ct;
     
    11681205        int rc = register_interrupt_handler(dev, hw_res_parsed.irqs.irqs[0],
    11691206            ahci_interrupt, &ct);
     1207       
    11701208        if (rc != EOK) {
    1171                 ddf_msg(LVL_ERROR, "Failed registering interrupt handler.");
     1209                ddf_msg(LVL_ERROR, "Failed register_interrupt_handler function.");
    11721210                goto error_register_interrupt_handler;
    11731211        }
     
    11921230       
    11931231error_get_res_parsed:
     1232        fibril_timer_destroy(ahci->timer);
     1233       
     1234error_create_timer:
    11941235        free(ahci);
    11951236        return NULL;
     
    12081249        ccc.u32 = ahci->memregs->ghc.ccc_ctl;
    12091250        ccc.en = 0;
    1210         ahci->memregs->ghc.ccc_ctl = ccc.u32;
     1251        ahci->memregs->ghc.ccc_ctl = ccc.u32;   
    12111252       
    12121253        /* Set master latency timer. */
     
    12221263       
    12231264        /* 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; 
    12251266}
    12261267
     
    12491290        dev->driver_data = ahci;
    12501291       
    1251         /* Start AHCI hardware. */
     1292        /* Set timer and AHCI hardware start. */
     1293        fibril_timer_set(ahci->timer, AHCI_TIMER_TICKS, ahci_timer, ahci);
    12521294        ahci_ahci_hw_start(ahci);
    12531295       
Note: See TracChangeset for help on using the changeset viewer.