Changeset 3c106e88 in mainline for uspace/srv/hw/netif/dp8390/ne2000.c


Ignore:
Timestamp:
2011-01-09T23:09:02Z (14 years ago)
Author:
martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
774e6d1a
Parents:
7ea7db31
Message:

complete rewrite of the NE2000 network interface driver

  • remove almost all stuff which was not directly related to NE2000 ISA to improve readability (optional support for NE1000, already defunct host DMA support, etc.)
  • correct input and output buffering and correct synchronization w.r.t. fibrils (the only remaining fibril-related question is whether multiple overlaping IRQ notifications can cause any troubles)

this implementation finally provides solid foundations for the next lowest networking layers (ARP, IP) and provide a way to debug UDP and TCP

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/hw/netif/dp8390/ne2000.c

    r7ea7db31 r3c106e88  
    2828 */
    2929
    30 /*
    31  * This code is based upon the NE2000 driver for MINIX,
    32  * distributed according to a BSD-style license.
    33  *
    34  * Copyright (c) 1987, 1997, 2006 Vrije Universiteit
    35  * Copyright (c) 1992, 1994 Philip Homburg
    36  * Copyright (c) 1996 G. Falzoni
    37  *
    38  */
    39 
    40 /** @addtogroup ne2k
     30/** @addtogroup ne2000
    4131 *  @{
    4232 */
    4333
    4434/** @file
    45  *  NE1000 and NE2000 network interface initialization and probe functions implementation.
    46  */
    47 
    48 #include <stdio.h>
    49 #include <unistd.h>
    50 #include "dp8390_port.h"
     35 *  NE2000 network interface implementation.
     36 */
     37
     38#include <assert.h>
     39#include <async.h>
     40#include <ddi.h>
     41#include <errno.h>
     42#include <err.h>
     43#include <malloc.h>
     44#include <sysinfo.h>
     45#include <ipc/ipc.h>
     46#include <ipc/services.h>
     47#include <ipc/irc.h>
     48#include <net/modules.h>
     49#include <packet_client.h>
     50#include <adt/measured_strings.h>
     51#include <net/device.h>
     52#include <netif_skel.h>
     53#include <nil_interface.h>
    5154#include "dp8390.h"
    52 #include "ne2000.h"
    53 
    54 /** Number of bytes to transfer */
    55 #define N  100
    56 
    57 typedef int (*testf_t)(dpeth_t *dep, int pos, uint8_t *pat);
    58 
    59 /** Data patterns */
    60 uint8_t pat0[] = {0x00, 0x00, 0x00, 0x00};
    61 uint8_t pat1[] = {0xFF, 0xFF, 0xFF, 0xFF};
    62 uint8_t pat2[] = {0xA5, 0x5A, 0x69, 0x96};
    63 uint8_t pat3[] = {0x96, 0x69, 0x5A, 0xA5};
    64 
    65 /** Tests 8 bit NE2000 network interface.
    66  *  @param[in,out] dep The network interface structure.
    67  *  @param[in] pos The starting position.
    68  *  @param[in] pat The data pattern to be written.
    69  *  @returns True on success.
    70  *  @returns false otherwise.
    71  */
    72 static int test_8(dpeth_t *dep, int pos, uint8_t *pat);
    73 
    74 /** Tests 16 bit NE2000 network interface.
    75  *  @param[in,out] dep The network interface structure.
    76  *  @param[in] pos The starting position.
    77  *  @param[in] pat The data pattern to be written.
    78  *  @returns True on success.
    79  *  @returns false otherwise.
    80  */
    81 static int test_16(dpeth_t *dep, int pos, uint8_t *pat);
    82 
    83 int ne_probe(dpeth_t *dep)
    84 {
    85         int byte;
    86         int i;
    87         int loc1, loc2;
    88         testf_t f;
    89        
    90         dep->de_dp8390_port = dep->de_base_port + NE_DP8390;
     55
     56/** Return the device from the interrupt call.
     57 *
     58 *  @param[in] call The interrupt call.
     59 *
     60 */
     61#define IRQ_GET_DEVICE(call)  ((device_id_t) IPC_GET_IMETHOD(call))
     62
     63/** Return the ISR from the interrupt call.
     64 *
     65 * @param[in] call The interrupt call.
     66 *
     67 */
     68#define IRQ_GET_ISR(call)  ((int) IPC_GET_ARG2(call))
     69
     70static int irc_service = 0;
     71static int irc_phone = -1;
     72
     73/** DP8390 kernel interrupt command sequence.
     74 *
     75 */
     76static irq_cmd_t ne2k_cmds[] = {
     77        {
     78                .cmd = CMD_PIO_READ_8,
     79                .addr = NULL,
     80                .dstarg = 2
     81        },
     82        {
     83                .cmd = CMD_BTEST,
     84                .value = 0x7f,
     85                .srcarg = 2,
     86                .dstarg = 3,
     87        },
     88        {
     89                .cmd = CMD_PREDICATE,
     90                .value = 2,
     91                .srcarg = 3
     92        },
     93        {
     94                .cmd = CMD_PIO_WRITE_A_8,
     95                .addr = NULL,
     96                .srcarg = 3
     97        },
     98        {
     99                .cmd = CMD_ACCEPT
     100        }
     101};
     102
     103/** DP8390 kernel interrupt code.
     104 *
     105 */
     106static irq_code_t ne2k_code = {
     107        sizeof(ne2k_cmds) / sizeof(irq_cmd_t),
     108        ne2k_cmds
     109};
     110
     111/** Handle the interrupt notification.
     112 *
     113 * This is the interrupt notification function.
     114 *
     115 * @param[in] iid  Interrupt notification identifier.
     116 * @param[in] call Interrupt notification.
     117 *
     118 */
     119static void irq_handler(ipc_callid_t iid, ipc_call_t *call)
     120{
     121        device_id_t device_id = IRQ_GET_DEVICE(*call);
     122        netif_device_t *device;
     123        int nil_phone;
     124        ne2k_t *ne2k;
     125       
     126        fibril_rwlock_read_lock(&netif_globals.lock);
     127       
     128        if (find_device(device_id, &device) == EOK) {
     129                nil_phone = device->nil_phone;
     130                ne2k = (ne2k_t *) device->specific;
     131        } else
     132                ne2k = NULL;
     133       
     134        fibril_rwlock_read_unlock(&netif_globals.lock);
     135       
     136        if (ne2k != NULL)
     137                ne2k_interrupt(ne2k, IRQ_GET_ISR(*call), nil_phone, device_id);
     138}
     139
     140/** Change the network interface state.
     141 *
     142 * @param[in,out] device Network interface.
     143 * @param[in]     state  New state.
     144 *
     145 */
     146static void change_state(netif_device_t *device, device_state_t state)
     147{
     148        if (device->state != state) {
     149                device->state = state;
     150               
     151                const char *desc;
     152                switch (state) {
     153                case NETIF_ACTIVE:
     154                        desc = "active";
     155                        break;
     156                case NETIF_STOPPED:
     157                        desc = "stopped";
     158                        break;
     159                default:
     160                        desc = "unknown";
     161                }
     162               
     163                printf("%s: State changed to %s\n", NAME, desc);
     164        }
     165}
     166
     167int netif_specific_message(ipc_callid_t callid, ipc_call_t *call,
     168    ipc_call_t *answer, size_t *count)
     169{
     170        return ENOTSUP;
     171}
     172
     173int netif_get_device_stats(device_id_t device_id, device_stats_t *stats)
     174{
     175        if (!stats)
     176                return EBADMEM;
     177       
     178        netif_device_t *device;
     179        int rc = find_device(device_id, &device);
     180        if (rc != EOK)
     181                return rc;
     182       
     183        ne2k_t *ne2k = (ne2k_t *) device->specific;
     184       
     185        memcpy(stats, &ne2k->stats, sizeof(device_stats_t));
     186        return EOK;
     187}
     188
     189int netif_get_addr_message(device_id_t device_id, measured_string_t *address)
     190{
     191        if (!address)
     192                return EBADMEM;
     193       
     194        netif_device_t *device;
     195        int rc = find_device(device_id, &device);
     196        if (rc != EOK)
     197                return rc;
     198       
     199        ne2k_t *ne2k = (ne2k_t *) device->specific;
     200       
     201        address->value = ne2k->mac;
     202        address->length = ETH_ADDR;
     203        return EOK;
     204}
     205
     206int netif_probe_message(device_id_t device_id, int irq, void *io)
     207{
     208        netif_device_t *device =
     209            (netif_device_t *) malloc(sizeof(netif_device_t));
     210        if (!device)
     211                return ENOMEM;
     212       
     213        ne2k_t *ne2k = (ne2k_t *) malloc(sizeof(ne2k_t));
     214        if (!ne2k) {
     215                free(device);
     216                return ENOMEM;
     217        }
     218       
     219        void *port;
     220        int rc = pio_enable((void *) io, NE2K_IO_SIZE, &port);
     221        if (rc != EOK) {
     222                free(ne2k);
     223                free(device);
     224                return rc;
     225        }
     226       
     227        bzero(device, sizeof(netif_device_t));
     228        bzero(ne2k, sizeof(ne2k_t));
     229       
     230        device->device_id = device_id;
     231        device->nil_phone = -1;
     232        device->specific = (void *) ne2k;
     233        device->state = NETIF_STOPPED;
     234       
     235        rc = ne2k_probe(ne2k, port, irq);
     236        if (rc != EOK) {
     237                printf("%s: No ethernet card found at I/O address %p\n",
     238                    NAME, port);
     239                free(ne2k);
     240                free(device);
     241                return rc;
     242        }
     243       
     244        rc = netif_device_map_add(&netif_globals.device_map, device->device_id, device);
     245        if (rc != EOK) {
     246                free(ne2k);
     247                free(device);
     248                return rc;
     249        }
     250       
     251        printf("%s: Ethernet card at I/O address %p, IRQ %d, MAC ",
     252            NAME, port, irq);
     253       
     254        unsigned int i;
     255        for (i = 0; i < ETH_ADDR; i++)
     256                printf("%02x%c", ne2k->mac[i], i < 5 ? ':' : '\n');
     257       
     258        return EOK;
     259}
     260
     261int netif_start_message(netif_device_t *device)
     262{
     263        if (device->state != NETIF_ACTIVE) {
     264                ne2k_t *ne2k = (ne2k_t *) device->specific;
     265               
     266                ne2k_cmds[0].addr = ne2k->port + DP_ISR;
     267                ne2k_cmds[3].addr = ne2k_cmds[0].addr;
     268               
     269                int rc = ipc_register_irq(ne2k->irq, device->device_id,
     270                    device->device_id, &ne2k_code);
     271                if (rc != EOK)
     272                        return rc;
     273               
     274                rc = ne2k_up(ne2k);
     275                if (rc != EOK) {
     276                        ipc_unregister_irq(ne2k->irq, device->device_id);
     277                        return rc;
     278                }
     279               
     280                if (irc_service)
     281                        async_msg_1(irc_phone, IRC_ENABLE_INTERRUPT, ne2k->irq);
     282               
     283                change_state(device, NETIF_ACTIVE);
     284        }
     285       
     286        return device->state;
     287}
     288
     289int netif_stop_message(netif_device_t *device)
     290{
     291        if (device->state != NETIF_STOPPED) {
     292                ne2k_t *ne2k = (ne2k_t *) device->specific;
     293               
     294                ne2k_down(ne2k);
     295                ipc_unregister_irq(ne2k->irq, device->device_id);
     296                change_state(device, NETIF_STOPPED);
     297        }
     298       
     299        return EOK;
     300}
     301
     302int netif_send_message(device_id_t device_id, packet_t *packet,
     303    services_t sender)
     304{
     305        netif_device_t *device;
     306        int rc = find_device(device_id, &device);
     307        if (rc != EOK)
     308                return rc;
     309       
     310        if (device->state != NETIF_ACTIVE) {
     311                netif_pq_release(packet_get_id(packet));
     312                return EFORWARD;
     313        }
     314       
     315        ne2k_t *ne2k = (ne2k_t *) device->specific;
    91316       
    92317        /*
    93          * We probe for an ne1000 or an ne2000 by testing whether the
    94          * on board is reachable through the dp8390. Note that the
    95          * ne1000 is an 8bit card and has a memory region distict from
    96          * the 16bit ne2000
     318         * Process the packet queue
    97319         */
    98320       
    99         for (dep->de_16bit = 0; dep->de_16bit < 2; dep->de_16bit++) {
    100                 /* Reset the ethernet card */
    101                 byte= inb_ne(dep, NE_RESET);
    102                 usleep(2000);
    103                 outb_ne(dep, NE_RESET, byte);
    104                 usleep(2000);
    105                
    106                 /* Reset the dp8390 */
    107                 outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT);
    108                 for (i = 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); i++)
    109                         ; /* Do nothing */
    110                
    111                 /* Check if the dp8390 is really there */
    112                 if ((inb_reg0(dep, DP_CR) & (CR_STP | CR_DM_ABORT)) !=
    113                     (CR_STP | CR_DM_ABORT))
    114                         return 0;
    115                
    116                 /* Disable the receiver and init TCR and DCR. */
    117                 outb_reg0(dep, DP_RCR, RCR_MON);
    118                 outb_reg0(dep, DP_TCR, TCR_NORMAL);
    119                 if (dep->de_16bit) {
    120                         outb_reg0(dep, DP_DCR, DCR_WORDWIDE | DCR_8BYTES |
    121                             DCR_BMS);
    122                 } else {
    123                         outb_reg0(dep, DP_DCR, DCR_BYTEWIDE | DCR_8BYTES |
    124                             DCR_BMS);
     321        do {
     322                packet_t *next = pq_detach(packet);
     323                ne2k_send(ne2k, packet);
     324                netif_pq_release(packet_get_id(packet));
     325                packet = next;
     326        } while (packet);
     327       
     328        return EOK;
     329}
     330
     331int netif_initialize(void)
     332{
     333        sysarg_t apic;
     334        sysarg_t i8259;
     335       
     336        if ((sysinfo_get_value("apic", &apic) == EOK) && (apic))
     337                irc_service = SERVICE_APIC;
     338        else if ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259))
     339                irc_service = SERVICE_I8259;
     340       
     341        if (irc_service) {
     342                while (irc_phone < 0) {
     343                        irc_phone = ipc_connect_me_to_blocking(PHONE_NS, irc_service,
     344                            0, 0);
    125345                }
    126                
    127                 if (dep->de_16bit) {
    128                         loc1 = NE2000_START;
    129                         loc2 = NE2000_START + NE2000_SIZE - 4;
    130                         f = test_16;
    131                 } else {
    132                         loc1 = NE1000_START;
    133                         loc2 = NE1000_START + NE1000_SIZE - 4;
    134                         f = test_8;
    135                 }
    136                
    137                 if (f(dep, loc1, pat0) && f(dep, loc1, pat1) &&
    138                     f(dep, loc1, pat2) && f(dep, loc1, pat3) &&
    139                     f(dep, loc2, pat0) && f(dep, loc2, pat1) &&
    140                     f(dep, loc2, pat2) && f(dep, loc2, pat3)) {
    141                         return 1;
    142                 }
    143         }
    144        
    145         return 0;
    146 }
    147 
    148 /** Initializes the NE2000 network interface.
    149  *
    150  *  @param[in,out] dep The network interface structure.
    151  *
    152  */
    153 void ne_init(dpeth_t *dep)
    154 {
    155         int i;
    156         int word, sendq_nr;
    157        
    158         /* Setup a transfer to get the ethernet address. */
    159         if (dep->de_16bit)
    160                 outb_reg0(dep, DP_RBCR0, 6*2);
    161         else
    162                 outb_reg0(dep, DP_RBCR0, 6);
    163        
    164         outb_reg0(dep, DP_RBCR1, 0);
    165         outb_reg0(dep, DP_RSAR0, 0);
    166         outb_reg0(dep, DP_RSAR1, 0);
    167         outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
    168        
    169         for (i = 0; i < 6; i++) {
    170                 if (dep->de_16bit) {
    171                         word = inw_ne(dep, NE_DATA);
    172                         dep->de_address.ea_addr[i] = word;
    173                 } else
    174                         dep->de_address.ea_addr[i] = inb_ne(dep, NE_DATA);
    175         }
    176        
    177         dep->de_data_port= dep->de_base_port + NE_DATA;
    178         if (dep->de_16bit) {
    179                 dep->de_ramsize = NE2000_SIZE;
    180                 dep->de_offset_page = NE2000_START / DP_PAGESIZE;
    181         } else {
    182                 dep->de_ramsize = NE1000_SIZE;
    183                 dep->de_offset_page = NE1000_START / DP_PAGESIZE;
    184         }
    185        
    186         /* Allocate one send buffer (1.5KB) per 8KB of on board memory. */
    187         sendq_nr = dep->de_ramsize / 0x2000;
    188        
    189         if (sendq_nr < 1)
    190                 sendq_nr = 1;
    191         else if (sendq_nr > SENDQ_NR)
    192                 sendq_nr = SENDQ_NR;
    193        
    194         dep->de_sendq_nr = sendq_nr;
    195         for (i = 0; i < sendq_nr; i++)
    196                 dep->de_sendq[i].sq_sendpage = dep->de_offset_page + i * SENDQ_PAGES;
    197        
    198         dep->de_startpage = dep->de_offset_page + i * SENDQ_PAGES;
    199         dep->de_stoppage = dep->de_offset_page + dep->de_ramsize / DP_PAGESIZE;
    200        
    201         printf("Novell NE%d000 ethernet card at I/O address "
    202             "%#lx, memory size %#lx, irq %d\n",
    203             dep->de_16bit ? 2 : 1, dep->de_base_port, dep->de_ramsize,
    204             dep->de_irq);
    205 }
    206 
    207 static int test_8(dpeth_t *dep, int pos, uint8_t *pat)
    208 {
    209         uint8_t buf[4];
    210         int i;
    211        
    212         outb_reg0(dep, DP_ISR, 0xff);
    213        
    214         /* Setup a transfer to put the pattern. */
    215         outb_reg0(dep, DP_RBCR0, 4);
    216         outb_reg0(dep, DP_RBCR1, 0);
    217         outb_reg0(dep, DP_RSAR0, pos & 0xff);
    218         outb_reg0(dep, DP_RSAR1, pos >> 8);
    219         outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
    220        
    221         for (i = 0; i < 4; i++)
    222                 outb_ne(dep, NE_DATA, pat[i]);
    223        
    224         for (i = 0; i < N; i++) {
    225                 if (inb_reg0(dep, DP_ISR) & ISR_RDC)
    226                         break;
    227         }
    228        
    229         if (i == N) {
    230                 printf("NE1000 remote DMA test failed\n");
    231                 return 0;
    232         }
    233        
    234         outb_reg0(dep, DP_RBCR0, 4);
    235         outb_reg0(dep, DP_RBCR1, 0);
    236         outb_reg0(dep, DP_RSAR0, pos & 0xff);
    237         outb_reg0(dep, DP_RSAR1, pos >> 8);
    238         outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
    239        
    240         for (i = 0; i < 4; i++)
    241                 buf[i] = inb_ne(dep, NE_DATA);
    242        
    243         return (bcmp(buf, pat, 4) == 0);
    244 }
    245 
    246 static int test_16(dpeth_t *dep, int pos, uint8_t *pat)
    247 {
    248         uint8_t buf[4];
    249         int i;
    250        
    251         outb_reg0(dep, DP_ISR, 0xff);
    252        
    253         /* Setup a transfer to put the pattern. */
    254         outb_reg0(dep, DP_RBCR0, 4);
    255         outb_reg0(dep, DP_RBCR1, 0);
    256         outb_reg0(dep, DP_RSAR0, pos & 0xff);
    257         outb_reg0(dep, DP_RSAR1, pos >> 8);
    258         outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
    259        
    260         for (i = 0; i < 4; i += 2)
    261                 outw_ne(dep, NE_DATA, *(uint16_t *)(pat + i));
    262        
    263         for (i = 0; i < N; i++) {
    264                 if (inb_reg0(dep, DP_ISR) &ISR_RDC)
    265                         break;
    266         }
    267        
    268         if (i == N) {
    269                 printf("NE2000 remote DMA test failed\n");
    270                 return 0;
    271         }
    272        
    273         outb_reg0(dep, DP_RBCR0, 4);
    274         outb_reg0(dep, DP_RBCR1, 0);
    275         outb_reg0(dep, DP_RSAR0, pos & 0xff);
    276         outb_reg0(dep, DP_RSAR1, pos >> 8);
    277         outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
    278        
    279         for (i = 0; i < 4; i += 2)
    280                 *(uint16_t *)(buf + i) = inw_ne(dep, NE_DATA);
    281        
    282         return (bcmp(buf, pat, 4) == 0);
    283 }
    284 
    285 /** Stop the NE2000 network interface.
    286  *
    287  *  @param[in,out] dep The network interface structure.
    288  *
    289  */
    290 void ne_stop(dpeth_t *dep)
    291 {
    292         /* Reset the ethernet card */
    293         int byte = inb_ne(dep, NE_RESET);
    294         usleep(2000);
    295         outb_ne(dep, NE_RESET, byte);
     346        }
     347       
     348        async_set_interrupt_received(irq_handler);
     349       
     350        sysarg_t phonehash;
     351        return ipc_connect_to_me(PHONE_NS, SERVICE_DP8390, 0, 0, &phonehash);
     352}
     353
     354int main(int argc, char *argv[])
     355{
     356        /* Start the module */
     357        return netif_module_start();
    296358}
    297359
Note: See TracChangeset for help on using the changeset viewer.