Ignore:
File:
1 edited

Legend:

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

    r3c106e88 r7922dea  
    2828 */
    2929
    30 /** @addtogroup ne2000
     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
    3141 *  @{
    3242 */
    3343
    3444/** @file
    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>
     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"
    5451#include "dp8390.h"
    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 
    70 static int irc_service = 0;
    71 static int irc_phone = -1;
    72 
    73 /** DP8390 kernel interrupt command sequence.
    74  *
    75  */
    76 static 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  */
    106 static 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  */
    119 static 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  */
    146 static 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";
     52#include "ne2000.h"
     53
     54/** Number of bytes to transfer */
     55#define N  100
     56
     57typedef int (*testf_t)(dpeth_t *dep, int pos, uint8_t *pat);
     58
     59/** Data patterns */
     60uint8_t pat0[] = {0x00, 0x00, 0x00, 0x00};
     61uint8_t pat1[] = {0xFF, 0xFF, 0xFF, 0xFF};
     62uint8_t pat2[] = {0xA5, 0x5A, 0x69, 0x96};
     63uint8_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 */
     72static 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 */
     81static int test_16(dpeth_t *dep, int pos, uint8_t *pat);
     82
     83int 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;
     91       
     92        /*
     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
     97         */
     98       
     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);
     125                }
     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 */
     153void 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
     207static 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)
    155226                        break;
    156                 case NETIF_STOPPED:
    157                         desc = "stopped";
     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 (memcmp(buf, pat, 4) == 0);
     244}
     245
     246static 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)
    158265                        break;
    159                 default:
    160                         desc = "unknown";
    161                 }
    162                
    163                 printf("%s: State changed to %s\n", NAME, desc);
    164         }
    165 }
    166 
    167 int 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 
    173 int 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 
    189 int 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 
    206 int 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 
    261 int 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 
    289 int 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 
    302 int 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;
    316        
    317         /*
    318          * Process the packet queue
    319          */
    320        
    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 
    331 int 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);
    345                 }
    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 
    354 int main(int argc, char *argv[])
    355 {
    356         /* Start the module */
    357         return netif_module_start();
     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 (memcmp(buf, pat, 4) == 0);
     283}
     284
     285/** Stop the NE2000 network interface.
     286 *
     287 *  @param[in,out] dep The network interface structure.
     288 *
     289 */
     290void 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);
    358296}
    359297
Note: See TracChangeset for help on using the changeset viewer.