Ignore:
Timestamp:
2009-07-07T21:48:51Z (15 years ago)
Author:
Jiri Svoboda <jirik.svoboda@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
30f869d
Parents:
925be4e
Message:

Modify CUDA driver to state machine format, with one interrupt per byte transferred.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/genarch/src/drivers/via-cuda/cuda.c

    r925be4e r1f0db02e  
    4242#include <synch/spinlock.h>
    4343
    44 static void cuda_packet_handle(cuda_instance_t *instance, size_t len);
     44static void cuda_packet_handle(cuda_instance_t *instance, uint8_t *buf, size_t len);
     45static void cuda_irq_listen(irq_t *irq);
     46static void cuda_irq_receive(irq_t *irq);
     47static void cuda_irq_rcv_end(irq_t *irq, void *buf, size_t *len);
    4548
    4649/** B register fields */
     
    5356/** IER register fields */
    5457enum {
     58        IER_CLR = 0x00,
    5559        IER_SET = 0x80,
    56         SR_INT  = 0x04
     60
     61        SR_INT  = 0x04,
     62        ALL_INT = 0x7f
    5763};
    5864
     65/** ACR register fields */
     66enum {
     67        SR_OUT  = 0x10
     68};
     69
     70#include <print.h>
    5971static irq_ownership_t cuda_claim(irq_t *irq)
    6072{
     
    6577        ifr = pio_read_8(&dev->ifr);
    6678
    67         if ((ifr & SR_INT) != 0)
    68                 return IRQ_ACCEPT;
    69         else
     79        if ((ifr & SR_INT) == 0)
    7080                return IRQ_DECLINE;
     81
     82        return IRQ_ACCEPT;
    7183}
    7284
     
    7486{
    7587        cuda_instance_t *instance = irq->instance;
     88        uint8_t rbuf[CUDA_RCV_BUF_SIZE];
     89        size_t len;
     90        bool handle;
     91
     92        handle = false;
     93        len = 0;
     94
     95        spinlock_lock(&instance->dev_lock);
     96
     97        /* Lower IFR.SR_INT so that CUDA can generate next int by raising it. */
     98        pio_write_8(&instance->cuda->ifr, SR_INT);
     99
     100        switch (instance->xstate) {
     101        case cx_listen: cuda_irq_listen(irq); break;
     102        case cx_receive: cuda_irq_receive(irq); break;
     103        case cx_rcv_end: cuda_irq_rcv_end(irq, rbuf, &len);
     104            handle = true; break;
     105        }
     106
     107        spinlock_unlock(&instance->dev_lock);
     108
     109        /* Handle an incoming packet. */
     110        if (handle)
     111                cuda_packet_handle(instance, rbuf, len);
     112}
     113
     114/** Interrupt in listen state.
     115 *
     116 * Start packet reception.
     117 */
     118static void cuda_irq_listen(irq_t *irq)
     119{
     120        cuda_instance_t *instance = irq->instance;
     121        cuda_t *dev = instance->cuda;
     122        uint8_t b;
     123
     124        b = pio_read_8(&dev->b);
     125
     126        if ((b & TREQ) != 0) {
     127                printf("cuda_irq_listen: no TREQ?!\n");
     128                return;
     129        }
     130
     131        pio_read_8(&dev->sr);
     132        pio_write_8(&dev->b, pio_read_8(&dev->b) & ~TIP);
     133        instance->xstate = cx_receive;
     134}
     135
     136/** Interrupt in receive state.
     137 *
     138 * Receive next byte of packet.
     139 */
     140static void cuda_irq_receive(irq_t *irq)
     141{
     142        cuda_instance_t *instance = irq->instance;
    76143        cuda_t *dev = instance->cuda;
    77144        uint8_t b, data;
    78         size_t pos;
    79 
    80         spinlock_lock(&instance->dev_lock);
    81 
    82         /* We have received one or more CUDA packets. Process them all. */
    83         while (true) {
    84                 b = pio_read_8(&dev->b);
    85 
    86                 if ((b & TREQ) != 0)
    87                         break;  /* No data */
    88 
     145
     146        data = pio_read_8(&dev->sr);
     147        if (instance->bidx < CUDA_RCV_BUF_SIZE)
     148                instance->rcv_buf[instance->bidx++] = data;
     149
     150        b = pio_read_8(&dev->b);
     151
     152        if ((b & TREQ) == 0) {
     153                pio_write_8(&dev->b, b ^ TACK);
     154        } else {
     155                pio_write_8(&dev->b, b | TACK | TIP);
     156                instance->xstate = cx_rcv_end;
     157        }
     158}
     159
     160/** Interrupt in rcv_end state.
     161 *
     162 * Terminate packet reception. Either go back to listen state or start
     163 * receiving another packet if CUDA has one for us.
     164 */
     165static void cuda_irq_rcv_end(irq_t *irq, void *buf, size_t *len)
     166{
     167        cuda_instance_t *instance = irq->instance;
     168        cuda_t *dev = instance->cuda;
     169        uint8_t data, b;
     170
     171        b = pio_read_8(&dev->b);
     172        data = pio_read_8(&dev->sr);
     173
     174        instance->xstate = cx_listen;
     175
     176        if ((b & TREQ) == 0) {
     177                instance->xstate = cx_receive;
    89178                pio_write_8(&dev->b, b & ~TIP);
    90 
    91                 /* Read one packet. */
    92 
    93                 pos = 0;
    94                 do {
    95                         data = pio_read_8(&dev->sr);
    96                         b = pio_read_8(&dev->b);
    97                         pio_write_8(&dev->b, b ^ TACK);
    98 
    99                         if (pos < CUDA_RCV_BUF_SIZE)
    100                                 instance->rcv_buf[pos++] = data;
    101                 } while ((b & TREQ) == 0);
    102 
    103                 pio_write_8(&dev->b, b | TACK | TIP);
    104 
    105                 cuda_packet_handle(instance, pos);
    106         }
    107 
    108         spinlock_unlock(&instance->dev_lock);
    109 }
    110 
    111 static void cuda_packet_handle(cuda_instance_t *instance, size_t len)
    112 {
    113         uint8_t *data = instance->rcv_buf;
    114 
    115         if (data[0] != 0x00 || data[1] != 0x40 || data[2] != 0x2c)
     179        } else {
     180                instance->xstate = cx_listen;
     181        }
     182
     183        memcpy(buf, instance->rcv_buf, instance->bidx);
     184        *len = instance->bidx;
     185        instance->bidx = 0;
     186}
     187
     188static void cuda_packet_handle(cuda_instance_t *instance, uint8_t *data, size_t len)
     189{
     190        if (data[0] != 0x00 || data[1] != 0x40 || (data[2] != 0x2c
     191                && data[2] != 0x8c))
    116192                return;
    117193
     
    130206                instance->cuda = dev;
    131207                instance->kbrdin = NULL;
     208                instance->xstate = cx_listen;
     209                instance->bidx = 0;
    132210
    133211                spinlock_initialize(&instance->dev_lock, "cuda_dev");
     212
     213                /* Disable all interrupts from CUDA. */
     214                pio_write_8(&dev->ier, IER_CLR | ALL_INT);
    134215
    135216                irq_initialize(&instance->irq);
     
    141222                instance->irq.cir = cir;
    142223                instance->irq.cir_arg = cir_arg;
     224                instance->irq.preack = true;
    143225        }
    144226       
     
    148230void cuda_wire(cuda_instance_t *instance, indev_t *kbrdin)
    149231{
     232        cuda_t *dev = instance->cuda;
     233
    150234        ASSERT(instance);
    151235        ASSERT(kbrdin);
     
    155239
    156240        /* Enable SR interrupt. */
    157         pio_write_8(&instance->cuda->ier, IER_SET | SR_INT);
     241        pio_write_8(&dev->ier, TIP | TREQ);
     242        pio_write_8(&dev->ier, IER_SET | SR_INT);
    158243}
    159244
Note: See TracChangeset for help on using the changeset viewer.