Changeset eb3683a in mainline for uspace/drv/block/ahci/ahci.c


Ignore:
Timestamp:
2012-07-21T14:11:55Z (12 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
76c07e4
Parents:
8486c07
Message:

AHCI improvements

  • avoid interrupt lockups by properly detecting and clearing SATA ports interrupt events
  • remove timer-based polling (interrupt handling should be reliable now)
  • simplify several declarations and get rid of some infamous bit fields
  • cstyle improvements
File:
1 edited

Legend:

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

    r8486c07 reb3683a  
    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 
    5751#define LO(ptr) \
    5852        ((uint32_t) (((uint64_t) ((uintptr_t) (ptr))) & 0xffffffff))
     
    6054#define HI(ptr) \
    6155        ((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        }
    62113
    63114static int ahci_get_sata_device_name(ddf_fun_t *, size_t, char *);
     
    243294/*----------------------------------------------------------------------------*/
    244295
    245 /** Get and clear AHCI port interrupt state register.
     296/** Wait for interrupt event.
    246297 *
    247298 * @param sata SATA device structure.
     
    250301 *
    251302 */
    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;
     303static 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;
    260312       
    261313        if (ahci_port_is_permanent_error(pxis))
    262314                sata->is_invalid_device = true;
    263315       
    264         fibril_mutex_unlock(&sata->pxis_lock);
     316        fibril_mutex_unlock(&sata->event_lock);
    265317       
    266318        return pxis;
     
    275327static void ahci_identify_device_cmd(sata_dev_t *sata, void *phys)
    276328{
    277         /* Clear interrupt state registers */
    278         ahci_get_and_clear_pxis(sata);
    279         sata->shadow_pxis.u32 = 0;
    280        
    281329        volatile sata_std_command_frame_t *cmd =
    282330            (sata_std_command_frame_t *) sata->cmd_table;
     
    308356        sata->cmd_header->flags =
    309357            AHCI_CMDHDR_FLAGS_CLEAR_BUSY_UPON_OK |
    310             AHCI_CMDHDR_FLAGS_2DWCMD; 
     358            AHCI_CMDHDR_FLAGS_2DWCMD;
    311359        sata->cmd_header->bytesprocessed = 0;
    312360       
     
    324372static void ahci_identify_packet_device_cmd(sata_dev_t *sata, void *phys)
    325373{
    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 =
    331375            (sata_std_command_frame_t *) sata->cmd_table;
    332376       
     
    355399       
    356400        sata->cmd_header->prdtl = 1;
    357         sata->cmd_header->flags = 
     401        sata->cmd_header->flags =
    358402            AHCI_CMDHDR_FLAGS_CLEAR_BUSY_UPON_OK |
    359403            AHCI_CMDHDR_FLAGS_2DWCMD;
     
    382426        void *phys;
    383427        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);
    387436       
    388437        fibril_mutex_lock(&sata->lock);
    389438       
    390439        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);
    398441       
    399442        if (sata->is_invalid_device) {
     
    405448        if (ahci_port_is_tfes(pxis)) {
    406449                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);
    414451               
    415452                if ((sata->is_invalid_device) || (ahci_port_is_error(pxis))) {
     
    441478                            "%s: Sector length other than 512 B not supported",
    442479                            sata->model);
    443                         goto error;     
     480                        goto error;
    444481                }
    445482               
     
    449486                            "%s: Sector length other than 512 B not supported",
    450487                            sata->model);
    451                         goto error;     
     488                        goto error;
    452489                }
    453490        }
     
    488525                goto error;
    489526        } else {
    490                 for (unsigned int i = 0; i < 7; i++) {
     527                for (uint8_t i = 0; i < 7; i++) {
    491528                        if (udma_mask & (1 << i))
    492529                                sata->highest_udma_mode = i;
     
    515552static void ahci_set_mode_cmd(sata_dev_t *sata, void* phys, uint8_t mode)
    516553{
    517         /* Clear interrupt state registers */
    518         ahci_get_and_clear_pxis(sata);
    519         sata->shadow_pxis.u32 = 0;
    520        
    521554        volatile sata_std_command_frame_t *cmd =
    522555            (sata_std_command_frame_t *) sata->cmd_table;
     
    599632        uint8_t mode = 0x40 | (sata->highest_udma_mode & 0x07);
    600633        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);
    608635       
    609636        if (sata->is_invalid_device) {
     
    641668static void ahci_rb_fpdma_cmd(sata_dev_t *sata, void *phys, uint64_t blocknum)
    642669{
    643         /* Clear interrupt state registers */
    644         ahci_get_and_clear_pxis(sata);
    645         sata->shadow_pxis.u32 = 0;
    646        
    647670        volatile sata_ncq_command_frame_t *cmd =
    648671            (sata_ncq_command_frame_t *) sata->cmd_table;
     
    709732       
    710733        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);
    718735       
    719736        if ((sata->is_invalid_device) || (ahci_port_is_error(pxis))) {
     
    737754static void ahci_wb_fpdma_cmd(sata_dev_t *sata, void *phys, uint64_t blocknum)
    738755{
    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 =
    744757            (sata_ncq_command_frame_t *) sata->cmd_table;
    745758       
     
    767780        cmd->lba5 = (blocknum >> 40) & 0xff;
    768781       
    769         volatile ahci_cmd_prdt_t * prdt =
     782        volatile ahci_cmd_prdt_t *prdt =
    770783            (ahci_cmd_prdt_t *) (&sata->cmd_table[0x20]);
    771784       
     
    806819       
    807820        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);
    815822       
    816823        if ((sata->is_invalid_device) || (ahci_port_is_error(pxis))) {
     
    824831
    825832/*----------------------------------------------------------------------------*/
    826 /*-- Interrupts and timer unified handling -----------------------------------*/
     833/*-- Interrupts handling -----------------------------------------------------*/
    827834/*----------------------------------------------------------------------------*/
    828835
     
    830837        {
    831838                .base = 0,
    832                 .size = 32,
     839                .size = 0,
    833840        }
    834841};
    835842
    836843static 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)
    857876};
    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 }
    930877
    931878/** AHCI interrupt handler.
     
    939886{
    940887        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        }
    946908}
    947909
     
    951913
    952914/** Allocate SATA device structure with buffers for hardware.
    953  * 
     915 *
    954916 * @param port AHCI port structure
    955917 *
     
    960922{
    961923        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;
    966928       
    967929        sata_dev_t *sata = malloc(sizeof(sata_dev_t));
     
    10541016
    10551017/** Create and initialize connected SATA structure device
    1056  * 
     1018 *
    10571019 * @param ahci     AHCI device structure.
    10581020 * @param dev      DDF device structure.
     
    10781040        /* Initialize synchronization structures */
    10791041        fibril_mutex_initialize(&sata->lock);
    1080         fibril_mutex_initialize(&sata->pxis_lock);
    10811042        fibril_mutex_initialize(&sata->event_lock);
    10821043        fibril_condvar_initialize(&sata->event_condvar);
    1083 
     1044       
    10841045        ahci_sata_hw_start(sata);
    1085 
     1046       
    10861047        /* Identify device. */
    10871048        if (ahci_identify_device(sata) != EOK)
     
    11501111
    11511112/** Create AHCI device structure, intialize it and register interrupt routine.
    1152  * 
     1113 *
    11531114 * @param dev DDF device structure.
    11541115 *
     
    11651126       
    11661127        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;
    11721128       
    11731129        hw_res_list_parsed_t hw_res_parsed;
     
    11871143        /* Register interrupt handler */
    11881144        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        }
    11981161       
    11991162        irq_code_t ct;
     
    12051168        int rc = register_interrupt_handler(dev, hw_res_parsed.irqs.irqs[0],
    12061169            ahci_interrupt, &ct);
    1207        
    12081170        if (rc != EOK) {
    1209                 ddf_msg(LVL_ERROR, "Failed register_interrupt_handler function.");
     1171                ddf_msg(LVL_ERROR, "Failed registering interrupt handler.");
    12101172                goto error_register_interrupt_handler;
    12111173        }
     
    12301192       
    12311193error_get_res_parsed:
    1232         fibril_timer_destroy(ahci->timer);
    1233        
    1234 error_create_timer:
    12351194        free(ahci);
    12361195        return NULL;
     
    12491208        ccc.u32 = ahci->memregs->ghc.ccc_ctl;
    12501209        ccc.en = 0;
    1251         ahci->memregs->ghc.ccc_ctl = ccc.u32;   
     1210        ahci->memregs->ghc.ccc_ctl = ccc.u32;
    12521211       
    12531212        /* Set master latency timer. */
     
    12631222       
    12641223        /* 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;
    12661225}
    12671226
     
    12901249        dev->driver_data = ahci;
    12911250       
    1292         /* Set timer and AHCI hardware start. */
    1293         fibril_timer_set(ahci->timer, AHCI_TIMER_TICKS, ahci_timer, ahci);
     1251        /* Start AHCI hardware. */
    12941252        ahci_ahci_hw_start(ahci);
    12951253       
Note: See TracChangeset for help on using the changeset viewer.