Changeset 8136102 in mainline


Ignore:
Timestamp:
2011-01-11T01:33:58Z (13 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
6b22c97
Parents:
6643a19 (diff), 7300c37 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

improve correctness of the NE2000 driver w.r.t. parallelism of the interrupt notification handler

  • by masking off interrupts in the kernel interrupt handler, the core of the interrupt notification handler (fetching frames from the network card itself) always runs single-threaded (thus avoiding the issues with fetching of frames multiple times from different fibrils, causing ICMP replies to be duplicated)
  • the received frames are buffered locally and then sent to the NIL module with the interrupts unmasked again (thus another notification handler will be scheduled if the sending of the frames to the NIL module blocks)

there is still a synchronization issue without any clear root cause when the network card is flood-pinged even before it is being initialized

Location:
uspace
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/net/netif/netif_skel.c

    r6643a19 r8136102  
    130130        if (result > NETIF_NULL) {
    131131                int phone = device->nil_phone;
     132                nil_device_state_msg(phone, device_id, result);
    132133                fibril_rwlock_write_unlock(&netif_globals.lock);
    133                 nil_device_state_msg(phone, device_id, result);
    134134                return EOK;
    135135        }
     
    166166        if (result > NETIF_NULL) {
    167167                int phone = device->nil_phone;
     168                nil_device_state_msg(phone, device_id, result);
    168169                fibril_rwlock_write_unlock(&netif_globals.lock);
    169                 nil_device_state_msg(phone, device_id, result);
    170170                return EOK;
    171171        }
  • uspace/srv/hw/netif/dp8390/dp8390.c

    r6643a19 r8136102  
    5454#include <errno.h>
    5555#include <libarch/ddi.h>
    56 #include <netif_skel.h>
    5756#include <net/packet.h>
    58 #include <nil_interface.h>
    5957#include <packet_client.h>
    6058#include "dp8390.h"
     
    8179
    8280/** NE2000 retry count */
    83 #define NE2K_RETRY  100
     81#define NE2K_RETRY  0x1000
    8482
    8583/** NE2000 error messages rate limiting */
     
    186184                memcpy(&word, buf, 1);
    187185                pio_write_16(ne2k->data_port, word);
     186        }
     187}
     188
     189static void ne2k_init(ne2k_t *ne2k)
     190{
     191        unsigned int i;
     192       
     193        /* Reset the ethernet card */
     194        uint8_t val = pio_read_8(ne2k->port + NE2K_RESET);
     195        usleep(2000);
     196        pio_write_8(ne2k->port + NE2K_RESET, val);
     197        usleep(2000);
     198       
     199        /* Reset the DP8390 */
     200        pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
     201        for (i = 0; i < NE2K_RETRY; i++) {
     202                if (pio_read_8(ne2k->port + DP_ISR) != 0)
     203                        break;
    188204        }
    189205}
     
    210226        ne2k->up = false;
    211227       
    212         /* Reset the ethernet card */
    213         uint8_t val = pio_read_8(ne2k->port + NE2K_RESET);
    214         usleep(2000);
    215         pio_write_8(ne2k->port + NE2K_RESET, val);
    216         usleep(2000);
    217        
    218         /* Reset the DP8390 */
    219         pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
    220         for (i = 0; i < 0x1000; i++) {
    221                 if (pio_read_8(ne2k->port + DP_ISR) != 0)
    222                         break;
    223         }
     228        ne2k_init(ne2k);
    224229       
    225230        /* Check if the DP8390 is really there */
    226         val = pio_read_8(ne2k->port + DP_CR);
     231        uint8_t val = pio_read_8(ne2k->port + DP_CR);
    227232        if ((val & (CR_STP | CR_DM_ABORT)) != (CR_STP | CR_DM_ABORT))
    228233                return EXDEV;
     
    242247        for (i = 0; i < ETH_ADDR; i++)
    243248                ne2k->mac[i] = pio_read_16(ne2k->data_port);
     249       
     250        ne2k->probed = true;
     251        return EOK;
     252}
     253
     254/** Start the network interface.
     255 *
     256 * @param[in,out] ne2k Network interface structure.
     257 *
     258 * @return EOK on success.
     259 * @return EXDEV if the network interface is disabled.
     260 *
     261 */
     262int ne2k_up(ne2k_t *ne2k)
     263{
     264        if (!ne2k->probed)
     265                return EXDEV;
     266       
     267        ne2k_init(ne2k);
    244268       
    245269        /*
     
    318342       
    319343        /* Step 10: */
    320         pio_write_8(ne2k->port + DP_CR, CR_DM_ABORT | CR_STA);
     344        pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_DM_ABORT | CR_STA);
    321345       
    322346        /* Step 11: */
     
    329353       
    330354        /* Finish the initialization */
    331         ne2k->probed = true;
    332         return EOK;
    333 }
    334 
    335 /** Start the network interface.
    336  *
    337  * @param[in,out] ne2k Network interface structure.
    338  *
    339  * @return EOK on success.
    340  * @return EXDEV if the network interface is disabled.
    341  *
    342  */
    343 int ne2k_up(ne2k_t *ne2k)
    344 {
    345         if (!ne2k->probed)
    346                 return EXDEV;
    347        
    348         pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_STA);
    349         pio_write_8(ne2k->port + DP_RCR, RCR_AB);
    350        
    351355        ne2k->up = true;
    352356        return EOK;
     
    362366        if ((ne2k->probed) && (ne2k->up)) {
    363367                pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
    364                
    365                 /* Reset the ethernet card */
    366                 uint8_t val = pio_read_8(ne2k->port + NE2K_RESET);
    367                 usleep(2000);
    368                 pio_write_8(ne2k->port + NE2K_RESET, val);
    369                
     368                ne2k_init(ne2k);
    370369                ne2k->up = false;
    371370        }
     
    420419        pio_write_8(ne2k->port + DP_RBCR1, 0);
    421420       
    422         for (i = 0; i < 0x1000; i++) {
     421        for (i = 0; i < NE2K_RETRY; i++) {
    423422                if ((pio_read_8(ne2k->port + DP_ISR) & ISR_RST) != 0)
    424423                        break;
     
    430429       
    431430        /* Acknowledge the ISR_RDC (remote DMA) interrupt */
    432         for (i = 0; i < 0x1000; i++) {
     431        for (i = 0; i < NE2K_RETRY; i++) {
    433432                if ((pio_read_8(ne2k->port + DP_ISR) & ISR_RDC) != 0)
    434433                        break;
     
    448447}
    449448
    450 static uint8_t ne2k_isr_ack(ne2k_t *ne2k)
    451 {
    452         uint8_t isr = pio_read_8(ne2k->port + DP_ISR);
    453         if (isr != 0)
    454                 pio_write_8(ne2k->port + DP_ISR, isr);
    455        
    456         return isr;
    457 }
    458 
    459 static void ne2k_receive_frame(ne2k_t *ne2k, uint8_t page, size_t length,
    460     int nil_phone, device_id_t device_id)
    461 {
    462         packet_t *packet = netif_packet_get_1(length);
    463         if (!packet)
    464                 return;
    465        
    466         void *buf = packet_suffix(packet, length);
     449static frame_t *ne2k_receive_frame(ne2k_t *ne2k, uint8_t page, size_t length)
     450{
     451        frame_t *frame = (frame_t *) malloc(sizeof(frame_t));
     452        if (frame == NULL)
     453                return NULL;
     454       
     455        link_initialize(&frame->link);
     456       
     457        frame->packet = netif_packet_get_1(length);
     458        if (frame->packet == NULL) {
     459                free(frame);
     460                return NULL;
     461        }
     462       
     463        void *buf = packet_suffix(frame->packet, length);
    467464        bzero(buf, length);
    468465        uint8_t last = page + length / DP_PAGE;
     
    481478       
    482479        ne2k->stats.receive_packets++;
    483         nil_received_msg(nil_phone, device_id, packet, SERVICE_NONE);
    484 }
    485 
    486 static void ne2k_receive(ne2k_t *ne2k, int nil_phone, device_id_t device_id)
    487 {
     480        return frame;
     481}
     482
     483static link_t *ne2k_receive(ne2k_t *ne2k)
     484{
     485        /*
     486         * Allocate memory for the list of received frames.
     487         * If the allocation fails here we still receive the
     488         * frames from the network, but they will be lost.
     489         */
     490        link_t *frames = (link_t *) malloc(sizeof(link_t));
     491        if (frames != NULL)
     492                list_initialize(frames);
     493       
    488494        while (true) {
    489495                uint8_t boundary = pio_read_8(ne2k->port + DP_BNRY) + 1;
     
    534540                        ne2k->overruns++;
    535541                        next = current;
    536                 } else if ((header.status & RSR_PRX) && (ne2k->up))
    537                         ne2k_receive_frame(ne2k, boundary, length, nil_phone, device_id);
     542                } else if ((header.status & RSR_PRX) && (ne2k->up)) {
     543                        frame_t *frame = ne2k_receive_frame(ne2k, boundary, length);
     544                        if ((frame != NULL) && (frames != NULL))
     545                                list_append(&frame->link, frames);
     546                }
    538547               
    539548                /*
     
    550559                pio_write_8(ne2k->port + DP_BNRY, next);
    551560        }
    552 }
    553 
    554 void ne2k_interrupt(ne2k_t *ne2k, uint8_t isr, int nil_phone, device_id_t device_id)
    555 {
    556         bool signal = false;
    557         bool stopped = false;
    558        
    559         for (; (isr & 0x7f) != 0; isr = ne2k_isr_ack(ne2k)) {
    560                 if (isr & (ISR_PTX | ISR_TXE)) {
    561                         if (isr & ISR_TXE)
    562                                 ne2k->stats.send_errors++;
    563                         else {
    564                                 uint8_t tsr = pio_read_8(ne2k->port + DP_TSR);
    565                                
    566                                 if (tsr & TSR_PTX)
    567                                         ne2k->stats.send_packets++;
    568                                
    569                                 if (tsr & TSR_COL)
    570                                         ne2k->stats.collisions++;
    571                                
    572                                 if (tsr & TSR_ABT)
    573                                         ne2k->stats.send_aborted_errors++;
    574                                
    575                                 if (tsr & TSR_CRS)
    576                                         ne2k->stats.send_carrier_errors++;
    577                                
    578                                 if (tsr & TSR_FU) {
    579                                         ne2k->underruns++;
    580                                         if (ne2k->underruns < NE2K_ERL)
    581                                                 fprintf(stderr, "%s: FIFO underrun\n", NAME);
    582                                 }
    583                                
    584                                 if (tsr & TSR_CDH) {
    585                                         ne2k->stats.send_heartbeat_errors++;
    586                                         if (ne2k->stats.send_heartbeat_errors < NE2K_ERL)
    587                                                 fprintf(stderr, "%s: CD heartbeat failure\n", NAME);
    588                                 }
    589                                
    590                                 if (tsr & TSR_OWC)
    591                                         ne2k->stats.send_window_errors++;
     561       
     562        return frames;
     563}
     564
     565link_t *ne2k_interrupt(ne2k_t *ne2k, uint8_t isr, uint8_t tsr)
     566{
     567        /* List of received frames */
     568        link_t *frames = NULL;
     569       
     570        if (isr & (ISR_PTX | ISR_TXE)) {
     571                if (isr & ISR_TXE)
     572                        ne2k->stats.send_errors++;
     573                else {
     574                        if (tsr & TSR_PTX)
     575                                ne2k->stats.send_packets++;
     576                       
     577                        if (tsr & TSR_COL)
     578                                ne2k->stats.collisions++;
     579                       
     580                        if (tsr & TSR_ABT)
     581                                ne2k->stats.send_aborted_errors++;
     582                       
     583                        if (tsr & TSR_CRS)
     584                                ne2k->stats.send_carrier_errors++;
     585                       
     586                        if (tsr & TSR_FU) {
     587                                ne2k->underruns++;
     588                                if (ne2k->underruns < NE2K_ERL)
     589                                        fprintf(stderr, "%s: FIFO underrun\n", NAME);
    592590                        }
    593591                       
    594                         fibril_mutex_lock(&ne2k->sq_mutex);
    595                        
    596                         if (ne2k->sq.dirty) {
    597                                 /* Prepare the buffer for next packet */
    598                                 ne2k->sq.dirty = false;
    599                                 ne2k->sq.size = 0;
    600                                 signal = true;
    601                         } else {
    602                                 ne2k->misses++;
    603                                 if (ne2k->misses < NE2K_ERL)
    604                                         fprintf(stderr, "%s: Spurious PTX interrupt\n", NAME);
     592                        if (tsr & TSR_CDH) {
     593                                ne2k->stats.send_heartbeat_errors++;
     594                                if (ne2k->stats.send_heartbeat_errors < NE2K_ERL)
     595                                        fprintf(stderr, "%s: CD heartbeat failure\n", NAME);
    605596                        }
    606597                       
    607                         fibril_mutex_unlock(&ne2k->sq_mutex);
     598                        if (tsr & TSR_OWC)
     599                                ne2k->stats.send_window_errors++;
    608600                }
    609601               
    610                 if (isr & ISR_PRX)
    611                         ne2k_receive(ne2k, nil_phone, device_id);
    612                
    613                 if (isr & ISR_RXE)
    614                         ne2k->stats.receive_errors++;
    615                
    616                 if (isr & ISR_CNT) {
    617                         ne2k->stats.receive_crc_errors +=
    618                             pio_read_8(ne2k->port + DP_CNTR0);
    619                         ne2k->stats.receive_frame_errors +=
    620                             pio_read_8(ne2k->port + DP_CNTR1);
    621                         ne2k->stats.receive_missed_errors +=
    622                             pio_read_8(ne2k->port + DP_CNTR2);
     602                fibril_mutex_lock(&ne2k->sq_mutex);
     603               
     604                if (ne2k->sq.dirty) {
     605                        /* Prepare the buffer for next packet */
     606                        ne2k->sq.dirty = false;
     607                        ne2k->sq.size = 0;
     608                       
     609                        /* Signal a next frame to be sent */
     610                        fibril_condvar_broadcast(&ne2k->sq_cv);
     611                } else {
     612                        ne2k->misses++;
     613                        if (ne2k->misses < NE2K_ERL)
     614                                fprintf(stderr, "%s: Spurious PTX interrupt\n", NAME);
    623615                }
    624616               
    625                 if (isr & ISR_RST) {
    626                         /*
    627                          * This means we got an interrupt but the ethernet
    628                          * chip is shutdown. We set the flag 'stopped'
    629                          * and continue processing arrived packets. When the
    630                          * receive buffer is empty, we reset the DP8390.
    631                          */
    632                         stopped = true;
    633                 }
    634         }
    635        
    636         if (stopped) {
     617                fibril_mutex_unlock(&ne2k->sq_mutex);
     618        }
     619       
     620        if (isr & ISR_RXE)
     621                ne2k->stats.receive_errors++;
     622       
     623        if (isr & ISR_CNT) {
     624                ne2k->stats.receive_crc_errors +=
     625                    pio_read_8(ne2k->port + DP_CNTR0);
     626                ne2k->stats.receive_frame_errors +=
     627                    pio_read_8(ne2k->port + DP_CNTR1);
     628                ne2k->stats.receive_missed_errors +=
     629                    pio_read_8(ne2k->port + DP_CNTR2);
     630        }
     631       
     632        if (isr & ISR_PRX)
     633                frames = ne2k_receive(ne2k);
     634       
     635        if (isr & ISR_RST) {
    637636                /*
    638637                 * The chip is stopped, and all arrived
     
    642641        }
    643642       
    644         /* Signal a next frame to be sent */
    645         if (signal)
    646                 fibril_condvar_broadcast(&ne2k->sq_cv);
     643        /* Unmask interrupts to be processed in the next round */
     644        pio_write_8(ne2k->port + DP_IMR,
     645            IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE);
     646       
     647        return frames;
    647648}
    648649
  • uspace/srv/hw/netif/dp8390/dp8390.h

    r6643a19 r8136102  
    5050
    5151#include <fibril_synch.h>
     52#include <adt/list.h>
    5253#include <net/packet.h>
     54#include <netif_skel.h>
    5355
    5456/** Module name */
     
    230232} ne2k_t;
    231233
     234typedef struct {
     235        link_t link;
     236        packet_t *packet;
     237} frame_t;
     238
    232239extern int ne2k_probe(ne2k_t *, void *, int);
    233240extern int ne2k_up(ne2k_t *);
    234241extern void ne2k_down(ne2k_t *);
    235242extern void ne2k_send(ne2k_t *, packet_t *);
    236 extern void ne2k_interrupt(ne2k_t *, uint8_t isr, int, device_id_t);
     243extern link_t *ne2k_interrupt(ne2k_t *, uint8_t, uint8_t);
    237244
    238245#endif
  • uspace/srv/hw/netif/dp8390/ne2000.c

    r6643a19 r8136102  
    6868#define IRQ_GET_ISR(call)  ((int) IPC_GET_ARG2(call))
    6969
     70/** Return the TSR from the interrupt call.
     71 *
     72 * @param[in] call The interrupt call.
     73 *
     74 */
     75#define IRQ_GET_TSR(call)  ((int) IPC_GET_ARG3(call))
     76
    7077static int irc_service = 0;
    7178static int irc_phone = -1;
     
    7683static irq_cmd_t ne2k_cmds[] = {
    7784        {
     85                /* Read Interrupt Status Register */
    7886                .cmd = CMD_PIO_READ_8,
    7987                .addr = NULL,
     
    8189        },
    8290        {
     91                /* Mask supported interrupt causes */
    8392                .cmd = CMD_BTEST,
    84                 .value = 0x7f,
     93                .value = (ISR_PRX | ISR_PTX | ISR_RXE | ISR_TXE | ISR_OVW |
     94                    ISR_CNT | ISR_RDC),
    8595                .srcarg = 2,
    8696                .dstarg = 3,
    8797        },
    8898        {
     99                /* Predicate for accepting the interrupt */
    89100                .cmd = CMD_PREDICATE,
    90                 .value = 2,
     101                .value = 4,
    91102                .srcarg = 3
    92103        },
    93104        {
     105                /*
     106                 * Mask future interrupts via
     107                 * Interrupt Mask Register
     108                 */
     109                .cmd = CMD_PIO_WRITE_8,
     110                .addr = NULL,
     111                .value = 0
     112        },
     113        {
     114                /* Acknowledge the current interrupt */
    94115                .cmd = CMD_PIO_WRITE_A_8,
    95116                .addr = NULL,
    96117                .srcarg = 3
     118        },
     119        {
     120                /* Read Transmit Status Register */
     121                .cmd = CMD_PIO_READ_8,
     122                .addr = NULL,
     123                .dstarg = 3
    97124        },
    98125        {
     
    111138/** Handle the interrupt notification.
    112139 *
    113  * This is the interrupt notification function.
     140 * This is the interrupt notification function. It is quarantied
     141 * that there is only a single instance of this notification
     142 * function running at one time until the return from the
     143 * ne2k_interrupt() function (where the interrupts are unmasked
     144 * again).
    114145 *
    115146 * @param[in] iid  Interrupt notification identifier.
     
    134165        fibril_rwlock_read_unlock(&netif_globals.lock);
    135166       
    136         if (ne2k != NULL)
    137                 ne2k_interrupt(ne2k, IRQ_GET_ISR(*call), nil_phone, device_id);
     167        if (ne2k != NULL) {
     168                link_t *frames =
     169                    ne2k_interrupt(ne2k, IRQ_GET_ISR(*call), IRQ_GET_TSR(*call));
     170               
     171                if (frames != NULL) {
     172                        while (!list_empty(frames)) {
     173                                frame_t *frame =
     174                                    list_get_instance(frames->next, frame_t, link);
     175                               
     176                                list_remove(&frame->link);
     177                                nil_received_msg(nil_phone, device_id, frame->packet,
     178                                    SERVICE_NONE);
     179                                free(frame);
     180                        }
     181                       
     182                        free(frames);
     183                }
     184        }
    138185}
    139186
     
    265312               
    266313                ne2k_cmds[0].addr = ne2k->port + DP_ISR;
    267                 ne2k_cmds[3].addr = ne2k_cmds[0].addr;
     314                ne2k_cmds[3].addr = ne2k->port + DP_IMR;
     315                ne2k_cmds[4].addr = ne2k_cmds[0].addr;
    268316               
    269317                int rc = ipc_register_irq(ne2k->irq, device->device_id,
     
    278326                }
    279327               
     328                change_state(device, NETIF_ACTIVE);
     329               
    280330                if (irc_service)
    281331                        async_msg_1(irc_phone, IRC_ENABLE_INTERRUPT, ne2k->irq);
    282                
    283                 change_state(device, NETIF_ACTIVE);
    284332        }
    285333       
Note: See TracChangeset for help on using the changeset viewer.