diff options
Diffstat (limited to 'bsps/powerpc/beatnik/net/porting/if_xxx_rtems.c')
-rw-r--r-- | bsps/powerpc/beatnik/net/porting/if_xxx_rtems.c | 500 |
1 files changed, 500 insertions, 0 deletions
diff --git a/bsps/powerpc/beatnik/net/porting/if_xxx_rtems.c b/bsps/powerpc/beatnik/net/porting/if_xxx_rtems.c new file mode 100644 index 0000000000..a0d459ff47 --- /dev/null +++ b/bsps/powerpc/beatnik/net/porting/if_xxx_rtems.c @@ -0,0 +1,500 @@ +#include "rtemscompat.h" + +/* Template for driver task, setup and attach routines. To be instantiated + * by defining the relevant symbols in header files. + */ + +/* Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005; + * License: see LICENSE file. + */ + +#include <rtems/irq.h> + +#include <stdio.h> +#include <string.h> +#include <inttypes.h> + +#include <sys/cdefs.h> + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/sockio.h> + +#include <net/if.h> +#include <net/if_arp.h> + +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <net/if_media.h> + +#ifdef IF_REG_HEADER +#include IF_REG_HEADER +#endif +#ifdef IF_VAR_HEADER +#include IF_VAR_HEADER +#endif + +#include "rtemscompat1.h" + +#define EX_EVENT RTEMS_EVENT_1 +#undef IRQ_AT_8259 + +NETDEV_DECL = { /*[0]:*/{ /* softc: */ { /* arpcom: */{ /* ac_if: */ { 0 }}}}}; + +static void net_daemon(void *arg); + +#ifdef HAVE_LIBBSPEXT +#include <bsp/bspExt.h> +static void the_net_isr(void *); +#else +static void noop(const rtems_irq_connect_data *unused) {} +static int noop1(const rtems_irq_connect_data *unused) { return 0;} +#if ISMINVERSION(4,6,99) +static void the_net_isr(rtems_irq_hdl_param); +#else +static void the_net_isr(); +#if NETDRIVER_SLOTS > 1 +#error only one instance supported (stupid IRQ API) +#else +static struct NET_SOFTC *thesc; +#endif +#endif +#endif + +#if defined(NETDRIVER_PCI) +/* Public setup routine for PCI devices; + * TODO: currently doesn't work for subsystem vendor/id , i.e. + * devices behind a standard PCI interface... + */ +int +NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_pci_setup)(int inst); +#endif + +static unsigned +NET_EMBEMB(,NETDRIVER_PREFIX,_net_driver_ticks_per_sec) = 0; + +/* other drivers may already have this created */ +extern unsigned net_driver_ticks_per_sec +__attribute__((weak, alias(NET_STRSTR(NETDRIVER_PREFIX)"_net_driver_ticks_per_sec") )); + +#ifdef DEBUG_MODULAR +net_drv_tbl_t * volatile METHODSPTR = 0; +#endif + + +int +NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_attach) + (struct rtems_bsdnet_ifconfig *config, int attaching) +{ + int error = 0; + device_t dev = net_dev_get(config); + struct NET_SOFTC *sc; + struct ifnet *ifp; +#ifndef HAVE_LIBBSPEXT + rtems_irq_connect_data irq_data = { + 0, + the_net_isr, +#if ISMINVERSION(4,6,99) + 0, +#endif + noop, + noop, + noop1 }; +#endif + + if ( !dev ) + return 1; + + if ( !dev->d_softc.NET_SOFTC_BHANDLE_FIELD ) { +#if defined(NETDRIVER_PCI) + device_printf(dev,NETDRIVER" unit not configured; executing setup..."); + /* setup should really be performed prior to attaching. + * Wipe the device; setup and re-obtain the device... + */ + memset(dev,0,sizeof(*dev)); + error = NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_pci_setup)(-1); + /* re-obtain the device */ + dev = net_dev_get(config); + if ( !dev ) { + printk("Unable to re-assign device structure???\n"); + return 1; + } + if (error <= 0) { + device_printf(dev,NETDRIVER" FAILED; unable to attach interface, sorry\n"); + return 1; + } + device_printf(dev,"success\n"); +#else + device_printf(dev,NETDRIVER" unit not configured; use 'rtems_"NETDRIVER"_setup()'\n"); + return 1; +#endif + } + + if ( !net_driver_ticks_per_sec ) + net_driver_ticks_per_sec = rtems_clock_get_ticks_per_second(); + + sc = device_get_softc( dev ); + ifp = &sc->arpcom.ac_if; + +#ifdef DEBUG_MODULAR + if (!METHODSPTR) { + device_printf(dev,NETDRIVER": method pointer not set\n"); + return -1; + } +#endif + + if ( attaching ) { + if ( ifp->if_init ) { + device_printf(dev,NETDRIVER" Driver already attached.\n"); + return -1; + } + if ( config->hardware_address ) { + /* use configured MAC address */ + memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); + } else { +#ifdef NET_READ_MAC_ADDR + NET_READ_MAC_ADDR(sc); +#endif + } + if ( METHODSPTR->n_attach(dev) ) { + device_printf(dev,NETDRIVER"_attach() failed\n"); + return -1; + } + } else { + if ( !ifp->if_init ) { + device_printf(dev,NETDRIVER" Driver not attached.\n"); + return -1; + } + if ( METHODSPTR->n_detach ) { + if ( METHODSPTR->n_detach(dev) ) { + device_printf(dev,NETDRIVER"_detach() failed\n"); + return -1; + } + } else { + device_printf(dev,NETDRIVER"_detach() not implemented\n"); + return -1; + } + } + + + if ( !sc->tid ) + sc->tid = rtems_bsdnet_newproc(NETDRIVER"d", 4096, net_daemon, sc); + + if (attaching) { +#ifdef DEBUG + printf("Installing IRQ # %i\n",sc->irq_no); +#endif +#ifdef HAVE_LIBBSPEXT + if ( bspExtInstallSharedISR(sc->irq_no, the_net_isr, sc, 0) ) +#else + /* BSP dependent :-( */ + irq_data.name = sc->irq_no; +#if ISMINVERSION(4,6,99) + irq_data.handle = (rtems_irq_hdl_param)sc; +#else + thesc = sc; +#endif + if ( ! BSP_install_rtems_irq_handler( &irq_data ) ) +#endif + { + fprintf(stderr,NETDRIVER": unable to install ISR\n"); + error = -1; + } + } else { + if ( sc->irq_no ) { +#ifdef DEBUG + printf("Removing IRQ # %i\n",sc->irq_no); +#endif +#ifdef HAVE_LIBBSPEXT + if (bspExtRemoveSharedISR(sc->irq_no, the_net_isr, sc)) +#else + /* BSP dependent :-( */ + irq_data.name = sc->irq_no; +#if ISMINVERSION(4,6,99) + irq_data.handle = (rtems_irq_hdl_param)sc; +#endif + if ( ! BSP_remove_rtems_irq_handler( &irq_data ) ) +#endif + { + fprintf(stderr,NETDRIVER": unable to uninstall ISR\n"); + error = -1; + } + } + } + return error; +} + +static void +the_net_isr( +#ifdef HAVE_LIBBSPEXT +void *thesc +#elif ISMINVERSION(4,6,99) +rtems_irq_hdl_param thesc +#endif +) +{ +struct NET_SOFTC *sc = thesc; + + /* disable interrupts */ + NET_DISABLE_IRQS(sc); + + rtems_bsdnet_event_send( sc->tid, EX_EVENT ); +} + +static void net_daemon(void *arg) +{ +struct NET_SOFTC *sc = arg; +rtems_event_set evs; + + for (;;) { + rtems_bsdnet_event_receive( + EX_EVENT, + RTEMS_WAIT | RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &evs); + + METHODSPTR->n_intr(sc); + + /* re-enable interrupts */ + NET_ENABLE_IRQS(sc); + } +} + +static struct NET_SOFTC * +net_drv_check_unit(int unit) +{ + unit--; + if ( unit < 0 || unit >= NETDRIVER_SLOTS ) { + fprintf(stderr,"Invalid unit # %i (not in %i..%i)\n", unit+1, 1, NETDRIVER_SLOTS); + return 0; + } + + if ( THEDEVS[unit].d_name ) { + fprintf(stderr,"Unit %i already set up\n", unit+1); + return 0; + } + + memset( &THEDEVS[unit], 0, sizeof(THEDEVS[0]) ); + + return &THEDEVS[unit].d_softc; +} + +struct rtems_bsdnet_ifconfig NET_EMBEMB(NETDRIVER_PREFIX,_dbg,_config) = { + NETDRIVER"1", + NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_attach), + 0 +}; + +#ifdef DEBUG +void +NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringup)(char *ipaddr) +{ +short flags; +struct sockaddr_in addr; +char *mask; + + + if (!ipaddr) { + printf("Need an ip[/mask] argument (dot notation)\n"); + return; + } + + ipaddr = strdup(ipaddr); + + if ( (mask = strchr(ipaddr,'/')) ) { + *mask++=0; + } else { + mask = "255.255.255.0"; + } + +#if defined(NETDRIVER_PCI) + /* this fails if already setup */ + NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_pci_setup)(-1); +#endif + rtems_bsdnet_attach(&NET_EMBEMB(NETDRIVER_PREFIX,_dbg,_config)); + + flags = IFF_UP /*| IFF_PROMISC*/; + if ( rtems_bsdnet_ifconfig(NETDRIVER"1",SIOCSIFFLAGS,&flags) < 0 ) { + printf("Can't bring '"NETDRIVER"1' up\n"); + goto cleanup; + } + memset(&addr,0,sizeof(addr)); + addr.sin_len = sizeof(addr); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(mask); + if ( rtems_bsdnet_ifconfig(NETDRIVER"1",SIOCSIFNETMASK,&addr) < 0 ) { + printf("Unable to set netmask on '"NETDRIVER"1'\n"); + goto cleanup; + } + addr.sin_addr.s_addr = inet_addr(ipaddr); + if ( rtems_bsdnet_ifconfig(NETDRIVER"1",SIOCSIFADDR,&addr) < 0 ) { + printf("Unable to set address on '"NETDRIVER"1'\n"); + goto cleanup; + } +cleanup: + the_real_free (ipaddr); +} + +int +NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringdown)() +{ +short flags; + flags = 0; + if ( rtems_bsdnet_ifconfig(NETDRIVER"1",SIOCSIFFLAGS,&flags) < 0 ) { + printf("Can't bring '"NETDRIVER"1' down\n"); + return -1; + } + + rtems_bsdnet_detach(&NET_EMBEMB(NETDRIVER_PREFIX,_dbg,_config)); + return 0; +} +#endif + + +#if defined(NETDRIVER_PCI) && !defined(NETDRIVER_OWN_SETUP) +/* Public setup routine for PCI devices; + * TODO: currently doesn't work for subsystem vendor/id , i.e. + * devices behind a standard PCI interface... + * passing 'inst' > only sets-up the 'inst'th card; passing + * 'inst' == 0 sets-up all matching cards. + */ +int +NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_pci_setup)(int inst) +{ +unsigned b,d,f,i,isio,unit; +rtemscompat_32_t base; +unsigned short cmd,id; +unsigned char h; +struct NET_SOFTC *sc; +unsigned try[] = { PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, 0 }; + +#ifdef DEBUG_MODULAR + if ( !METHODSPTR ) { + fprintf(stderr,NETDRIVER": Methods pointer not set\n"); + return -1; + } +#endif + + /* 0 can be reached when looking for the desired instance */ + if ( 0 == inst ) + inst = -1; + +#ifdef HAVE_LIBBSPEXT + /* make sure it's initialized */ + bspExtInit(); +#endif + + /* scan PCI for supported devices */ + for ( b=0, sc=0, unit=0; b<pci_bus_count(); b++ ) { + for ( d=0; d<PCI_MAX_DEVICES; d++ ) { + pci_read_config_word(b,d,0,PCI_VENDOR_ID,&id); + if ( 0xffff == id ) + continue; /* empty slot */ + + pci_read_config_byte(b,d,0,PCI_HEADER_TYPE,&h); + h = h&0x80 ? PCI_MAX_FUNCTIONS : 1; /* multifunction device ? */ + + for ( f=0; f<h; f++ ) { + if ( !sc && !(sc=net_drv_check_unit(unit+1))) { + fprintf(stderr,"Not enough driver slots; stop looking for more devices...\n"); + return unit; + } + pci_read_config_word(b,d,f,PCI_VENDOR_ID,&id); + if ( 0xffff == id ) + continue; /* empty slot */ + + pci_read_config_word(b,d,f,PCI_CLASS_DEVICE,&id); + if ( PCI_CLASS_NETWORK_ETHERNET != id ) + continue; /* only look at ethernet devices */ + + sc->b = b; + sc->d = d; + sc->f = f; + + for ( i=0, base=0, isio=0; try[i]; i++ ) { + pci_read_config_dword(b,d,f,try[i],&base); + if ( base ) { + if ( (isio = (PCI_BASE_ADDRESS_SPACE_IO == (base & PCI_BASE_ADDRESS_SPACE )) ) ) { +#ifdef NET_CHIP_PORT_IO + base &= PCI_BASE_ADDRESS_IO_MASK; + sc->NET_SOFTC_BHANDLE_FIELD = PCI_IO_2LOCAL(base,b); +#ifdef DEBUG + printf("Found PCI I/O Base 0x%08x\n", (unsigned)base); +#endif +#else + base = 0; + continue; +#endif + } else { +#ifdef NET_CHIP_MEM_IO + base &= PCI_BASE_ADDRESS_MEM_MASK; + sc->NET_SOFTC_BHANDLE_FIELD = PCI2LOCAL(base,b); +#ifdef DEBUG + printf("Found PCI MEM Base 0x%08x\n", (unsigned)base); +#endif +#else + base = 0; + continue; +#endif + } + break; + } + } + if ( !base ) { +#ifdef DEBUG + fprintf(stderr, NETDRIVER": (warning) Neither PCI base address 0 nor 1 are configured; skipping bus %i, slot %i, fn %i...\n",b,d,f); +#endif + continue; + } + + if ( 0 == METHODSPTR->n_probe(&THEDEVS[unit]) && (inst < 0 || !--inst) ) { + pci_read_config_word(b,d,f,PCI_COMMAND,&cmd); + pci_write_config_word(b,d,f,PCI_COMMAND, + cmd | (isio ? PCI_COMMAND_IO : PCI_COMMAND_MEMORY) | PCI_COMMAND_MASTER ); + pci_read_config_byte(b,d,f,PCI_INTERRUPT_LINE,&sc->irq_no); + printf(NETDRIVER": card found @PCI[%s] 0x%08x (local 0x%08x), IRQ %i\n", + (isio ? "io" : "mem"), (unsigned)base, sc->NET_SOFTC_BHANDLE_FIELD, sc->irq_no); + + sc = 0; /* need to allocate a new slot */ + unit++; + + if ( 0 == inst ) { + /* found desired instance */ + goto terminated; + } + } + } + } + } + +terminated: + return unit; +} +#else + +/* simple skeleton +int +NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_setup)( + int unit, + void *base_addr, + int irq_no) +{ +struct NET_SOFTC *sc; + if ( !(sc=net_drv_check_unit(unit)) ) { + fprintf(stderr,"Bad unit number -- (not enought driver slots?)\n"); + return 0; + } + sc->NET_SOFTC_BHANDLE_FIELD = base_addr; + if ( 0 == METHODSPTR->n_probe(&THEDEVS[unit-1]) ) { + sc->irq_no = irq_no; + printf(NETDRIVER": Unit %i set up\n", unit); + return unit; + } + return 0; +} +*/ + +#endif |