David van Moolenbroek f7df02e747 libnetdriver: rewrite
This is a driver-breaking update to the netdriver library, which is
used by all network drivers.  The aim of this change is to make the
library more compatible with NetBSD, and in particular with various
features that are expected to be supported by the NetBSD userland.
The main changes made by this patch are the following:

- each network driver now has a NetBSD-style short device name;
- drivers are not expected to receive packets right after startup;
- extended support for receipt modes, including multicast lists;
- support for multiple parallel send, receive requests;
- embedding of I/O vectors in send and receive requests;
- support for capabilities, including checksum offloading;
- support for reporting link status updates to the TCP/IP stack;
- support for setting and retrieving media status;
- support for changing the hardware (MAC) address;
- support for NetBSD interface flags IFF_DEBUG, IFF_LINK[0-2];
- support for NetBSD error statistics;
- support for regular time-based ("tick") callbacks.

IMPORTANT: this patch applies a minimal update to the existing drivers
in order to make them work at all with the new netdriver library.  It
however does *not* change all drivers to make use of the new features.
In fact, strictly speaking, all drivers are now violating requirements
imposed by the new library in one way or another, most notably by
enabling packet receipt when starting the driver.  Changing all the
drivers to be compliant, and to support the newly added options, is
left to future patches.  The existing drivers should currently *not*
be taken as examples of how to implement a new network driver!

With that said, a few drivers have already been changed to make use of
some of the new features: fxp, e1000, rtl8139, and rtl8169 now report
link and media status, and the last three of those now support setting
the hardware MAC address on the fly.  In addition, dp8390 has been
changed to default to PCI autoconfiguration if no configuration is
specified through environment variables.

Change-Id: I4b3ea9c0b9bc25d5b0609c6ff256fb0db71cdc42
2017-04-30 13:15:28 +00:00

308 lines
7.0 KiB
C

/*
** File: dp.c Version 1.01, Oct. 17, 2007
** Original: eth.c Version 1.00, Jan. 14, 1997
**
** Author: Giovanni Falzoni <gfalzoni@inwind.it>
**
** This file contains the ethernet device driver main task.
** It has to be integrated with the board specific drivers.
** It is a rewriting of Minix 2.0.0 ethernet driver (dp8390.c)
** to remove bord specific code. It should operate (I hope)
** with any board driver.
*/
#include <minix/drivers.h>
#include <minix/netdriver.h>
#include <minix/endpoint.h>
#include <sys/mman.h>
#include <assert.h>
#include "dp.h"
/*
** Local data
*/
static dpeth_t de_state;
typedef struct dp_conf { /* Configuration description structure */
port_t dpc_port;
int dpc_irq;
phys_bytes dpc_mem;
} dp_conf_t;
/* Device default configuration */
#define DP_CONF_NR 3
static dp_conf_t dp_conf[DP_CONF_NR] = {
/* I/O port, IRQ, Buff addr, Env. var */
{ 0x300, 5, 0xC8000, },
{ 0x280, 10, 0xCC000, },
{ 0x000, 0, 0x00000, },
};
static int do_init(unsigned int instance, netdriver_addr_t *addr,
uint32_t *caps, unsigned int *ticks);
static void do_stop(void);
static void do_set_mode(unsigned int mode, const netdriver_addr_t *mcast_list,
unsigned int mcast_count);
static int do_send(struct netdriver_data *data, size_t size);
static ssize_t do_recv(struct netdriver_data *data, size_t max);
static void do_intr(unsigned int mask);
static void do_tick(void);
static void do_other(const message *m_ptr, int ipc_status);
static const struct netdriver dp_table = {
.ndr_name = "dpe",
.ndr_init = do_init,
.ndr_stop = do_stop,
.ndr_set_mode = do_set_mode,
.ndr_recv = do_recv,
.ndr_send = do_send,
.ndr_intr = do_intr,
.ndr_tick = do_tick,
.ndr_other = do_other
};
/*
** Name: update_conf
** Function: Gets the default settings from 'dp_conf' table and
** modifies them from the environment.
*/
static void update_conf(dpeth_t * dep, const dp_conf_t * dcp,
unsigned int instance)
{
static char dpc_fmt[] = "x:d:x";
char ec_key[16];
long val;
strlcpy(ec_key, "DPETH0", sizeof(ec_key));
ec_key[5] += instance;
val = dcp->dpc_port; /* Get I/O port address */
env_parse(ec_key, dpc_fmt, 0, &val, 0x000L, 0x3FFL);
dep->de_base_port = val;
val = dcp->dpc_irq | DEI_DEFAULT; /* Get Interrupt line (IRQ) */
env_parse(ec_key, dpc_fmt, 1, &val, 0L, (long) NR_IRQ_VECTORS - 1);
dep->de_irq = val;
val = dcp->dpc_mem; /* Get shared memory address */
env_parse(ec_key, dpc_fmt, 2, &val, 0L, LONG_MAX);
dep->de_linmem = val;
}
/*
** Name: do_dump
** Function: Displays statistics on screen (SFx key from console)
*/
static void do_dump(void)
{
dpeth_t *dep;
dep = &de_state;
printf("\n\n");
printf("%s statistics:\t\t", netdriver_name());
/* Network interface status */
printf("Status: 0x%04x\n\n", dep->de_flags);
(*dep->de_dumpstatsf)(dep);
/* Transmitted/received bytes */
printf("Tx bytes:%10ld\t", dep->bytes_Tx);
printf("Rx bytes:%10ld\n", dep->bytes_Rx);
}
/*
** Name: do_first_init
** Function: Init action to setup task
*/
static void do_first_init(dpeth_t *dep, const dp_conf_t *dcp)
{
dep->de_linmem = 0xFFFF0000; /* FIXME: this overrides update_conf, why? */
/* Device specific initialization */
(*dep->de_initf)(dep);
/* Map memory if requested */
if (dep->de_linmem != 0) {
assert(dep->de_ramsize > 0);
dep->de_locmem =
vm_map_phys(SELF, (void *)dep->de_linmem, dep->de_ramsize);
if (dep->de_locmem == MAP_FAILED)
panic("unable to map memory");
}
/* Set the interrupt handler policy. Request interrupts not to be reenabled
* automatically. Return the IRQ line number when an interrupt occurs.
*/
dep->de_hook = dep->de_irq;
if (sys_irqsetpolicy(dep->de_irq, 0 /*IRQ_REENABLE*/, &dep->de_hook) != OK)
panic("unable to set IRQ policy");
sys_irqenable(&dep->de_hook);
}
/*
** Name: do_init
** Function: Checks for hardware presence.
** Initialize hardware and data structures.
** Return status and ethernet address.
*/
static int do_init(unsigned int instance, netdriver_addr_t *addr,
uint32_t *caps, unsigned int *ticks)
{
dpeth_t *dep;
dp_conf_t *dcp;
int confnr, fkeys, sfkeys;
dep = &de_state;
/* Pick a default configuration for this instance. */
confnr = MIN(instance, DP_CONF_NR-1);
dcp = &dp_conf[confnr];
update_conf(dep, dcp, instance);
if (!el1_probe(dep) && /* Probe for 3c501 */
!wdeth_probe(dep) && /* Probe for WD80x3 */
!ne_probe(dep) && /* Probe for NEx000 */
!el2_probe(dep) && /* Probe for 3c503 */
!el3_probe(dep)) { /* Probe for 3c509 */
printf("%s: warning no ethernet card found at 0x%04X\n",
netdriver_name(), dep->de_base_port);
return ENXIO;
}
do_first_init(dep, dcp);
/* Request function key for debug dumps */
fkeys = sfkeys = 0; bit_set(sfkeys, 7);
if (fkey_map(&fkeys, &sfkeys) != OK)
printf("%s: couldn't bind Shift+F7 key (%d)\n",
netdriver_name(), errno);
memcpy(addr, dep->de_address.na_addr, sizeof(*addr));
*caps = NDEV_CAP_MCAST | NDEV_CAP_BCAST; /* ..is this even accurate? */
*ticks = sys_hz(); /* update statistics once a second */
return OK;
}
/*
** Name: de_set_mode
** Function: Sets packet receipt mode.
*/
static void do_set_mode(unsigned int mode,
const netdriver_addr_t * mcast_list __unused,
unsigned int mcast_count __unused)
{
dpeth_t *dep;
dep = &de_state;
dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD);
if (mode & NDEV_MODE_PROMISC)
dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD;
if (mode & (NDEV_MODE_MCAST_LIST | NDEV_MODE_MCAST_ALL))
dep->de_flags |= DEF_MULTI;
if (mode & NDEV_MODE_BCAST)
dep->de_flags |= DEF_BROAD;
(*dep->de_flagsf)(dep);
}
/*
** Name: do_send
** Function: Send a packet, if possible.
*/
static int do_send(struct netdriver_data *data, size_t size)
{
dpeth_t *dep;
dep = &de_state;
return (*dep->de_sendf)(dep, data, size);
}
/*
** Name: do_recv
** Function: Receive a packet, if possible.
*/
static ssize_t do_recv(struct netdriver_data *data, size_t max)
{
dpeth_t *dep;
dep = &de_state;
return (*dep->de_recvf)(dep, data, max);
}
/*
** Name: do_stop
** Function: Stops network interface.
*/
static void do_stop(void)
{
dpeth_t *dep;
dep = &de_state;
/* Stop device */
(dep->de_stopf)(dep);
}
/*
** Name: do_intr
** Function; Handles interrupts.
*/
static void do_intr(unsigned int __unused mask)
{
dpeth_t *dep;
dep = &de_state;
/* If device is enabled and interrupt pending */
(*dep->de_interruptf)(dep);
sys_irqenable(&dep->de_hook);
}
/*
** Name: do_tick
** Function: perform regular processing.
*/
static void do_tick(void)
{
dpeth_t *dep;
dep = &de_state;
if (dep->de_getstatsf != NULL)
(*dep->de_getstatsf)(dep);
}
/*
** Name: do_other
** Function: Processes miscellaneous messages.
*/
static void do_other(const message *m_ptr, int ipc_status)
{
if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR)
do_dump();
}
/*
** Name: main
** Function: Main entry for dp task
*/
int main(int argc, char **argv)
{
env_setargs(argc, argv);
netdriver_task(&dp_table);
return 0;
}