diff options
author | dmlb <dmlb@FreeBSD.org> | 2000-03-08 23:28:06 +0000 |
---|---|---|
committer | dmlb <dmlb@FreeBSD.org> | 2000-03-08 23:28:06 +0000 |
commit | a6fb4b16d62b04c52ae60fbaaa102aa6f62c26d6 (patch) | |
tree | c6b0ee5cd502f59a9bbac23445ba2d0549315514 /sys/dev/ray | |
parent | 11398178a84f860bce14fca072105aa0ee25b71d (diff) | |
download | FreeBSD-src-a6fb4b16d62b04c52ae60fbaaa102aa6f62c26d6.zip FreeBSD-src-a6fb4b16d62b04c52ae60fbaaa102aa6f62c26d6.tar.gz |
Mega additions of NetBSD code - most of the NetBSD code is now in here, if
not actually used yet. This created a lot of prototypes.
I moved code around so that the functions are in the same order as NetBSD - this helps diff a lot.
Things that are missing are the TX routine and ifmedia stuff and ioctls
Not all of the stuff is enabled - we are missing calls in ccs_done and ioctl.
Promiscious mode is working.
Am almost ready to use the NetBSD start up routine - essentially all I need
to do is not use a seperate timer to call download_timo.
Other misc. things:
callout_stop is a newish feature for cancelling a timer without
argument checking it.
tried to add a sysctl knob but it doesn't work in the module
enabled infrastructure code to call netbsd bits.
Diffstat (limited to 'sys/dev/ray')
-rw-r--r-- | sys/dev/ray/if_ray.c | 2617 |
1 files changed, 1785 insertions, 832 deletions
diff --git a/sys/dev/ray/if_ray.c b/sys/dev/ray/if_ray.c index 9833061..7a96b0d 100644 --- a/sys/dev/ray/if_ray.c +++ b/sys/dev/ray/if_ray.c @@ -28,10 +28,40 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: if_ray.c,v 1.7 2000/03/05 22:24:30 dmlb Exp $ + * $Id: if_ray.c,v 1.8 2000/03/08 08:53:36 dmlb Exp $ * */ +/* $NetBSD: if_ray.c,v 1.12 2000/02/07 09:36:27 augustss Exp $ */ +/* + * Copyright (c) 2000 Christian E. Hopps + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + /* * * Card configuration @@ -117,10 +147,10 @@ * TODO * * _stop - mostly done - * would be nice to understand shutdown/power save to prevent RX + * would be nice to understand shutdown/or power save to prevent RX * _reset - done * just needs calling in the right places - * converted most panic to resets + * converted panics to resets - when tx packets are the wrong length * may be needed in a couple of other places when I do more commands * havenet - mostly done * i think i've got all the places to set it right, but not so sure @@ -128,13 +158,25 @@ * _unload - done * recreated most of stop but as card is unplugged don't try and * access it + * TX bpf - done + * RX bpf - done + * I would much prefer to have the complete 802.11 packet dropped to + * the bpf tap and then have a user land program parse the headers + * as needed. This way, tcpdump -w can be used to grab the raw data. If + * needed the 802.11 aware program can "translate" the .11 to ethernet + * for tcpdump -r + * + * XXX use std timeout code for download? should only be a move to ccs_done + * when checked can remove some of the stuff in download_timo as it + * duplicates check_ccs and ccs_done + * XXX and changing mode etc. + * XXX add the start_join_net - i needed it anyway - what about the update * - * TX bpf - * RX bpf - * shutdown * promisoius * multicast + * shutdown * ifp->if_hdr length + * antennas and rxlevel * * apm * @@ -142,19 +184,32 @@ * ioctls - translation, BSS_ID, countrycode * faster TX routine * more translations - * infrastructure mode + * infrastructure mode - maybe need some of the old stuff for checking? * differeniate between parameters set in attach and init * start_join_done needs a restart in download_done * spinning in ray_issue_cmd + * fix the XXX code in start_join_done * * command tracking - really needed? if not remove SCP_ stuff * will simplify ray_issue_cmd away + * + * callout handles need rationalising. can probably remove timerh and + * use ccs_timerh for download and sj_timerh + * + * ray_update_params_done needs work + * + * make RAY_DEBUG a knob somehow - either sysctl or IFF_DEBUG + * + * might need the mode changing and update stuff */ #define XXX 0 -#define XXX_TRACKING 0 -#define XXX_INFRA 0 -#define XXX_MCASTPROM 0 +#define XXX_DOWNLOAD_STD_TIMEOUT 0 +#define XXX_MCAST 0 +#define XXX_NETBSDTX 0 +#define XXX_PROM 0 +#define XXX_IOCTL 0 +#define XXX_NETBSD_SJ_NET 0 /* * XXX build options - move to LINT @@ -172,10 +227,12 @@ * 51 MBUFs dumped/packet types reported */ #ifndef RAY_DEBUG -#define RAY_DEBUG 2 +#define RAY_DEBUG 21 #endif -#define RAY_DOWNLOAD_TIMEOUT (hz/2) /* Timeout for CCS commands - only used for downloading startup parameters */ +#define RAY_DOWNLOAD_TIMEOUT (hz/2) /* Timeout for downloading startup parameters */ +#define RAY_CCS_TIMEOUT (hz/2) /* Timeout for CCS commands */ +#define RAY_CHECK_SCHED_TIMEOUT (hz) /* Time to wait until command retry, should be > RAY_CCS_TIMEOUT */ #define RAY_NEED_STARTJOIN_TIMO 0 /* Might be needed with build 4 */ #define RAY_SJ_TIMEOUT (90*hz) /* Timeout for failing STARTJOIN commands - only used with RAY_NEED_STARTJOIN_TIMO */ @@ -188,6 +245,8 @@ #define RAY_RESET_TIMEOUT (5*hz) /* Timeout for resetting the card */ +#define RAY_USE_CALLOUT_STOP 0 /* Set for kernels with callout_stop function - 3.3 and above */ + #define RAY_SIMPLE_TX 1 /* Simple TX routine */ #define RAY_DECENT_TX 0 /* Decent TX routine - tbd */ /* @@ -255,10 +314,12 @@ #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/mbuf.h> +#include <sys/callout.h> #include <sys/select.h> #include <sys/socket.h> #include <sys/sockio.h> #include <sys/systm.h> +#include <sys/sysctl.h> #include <sys/uio.h> #include <sys/proc.h> #include <sys/ucred.h> @@ -297,6 +358,14 @@ #endif /* NAPM */ /* + * Sysctl knobs + */ +static int ray_debug = RAY_DEBUG; + +SYSCTL_NODE(_hw, OID_AUTO, ray, CTLFLAG_RW, 0, "Raylink Driver"); +SYSCTL_INT(_hw_ray, OID_AUTO, debug, CTLFLAG_RW, &ray_debug, RAY_DEBUG, ""); + +/* * One of these structures per allocated device */ struct ray_softc { @@ -305,6 +374,8 @@ struct ray_softc { struct ifmedia ifmedia; /* Ifnet common */ struct callout_handle \ timerh; /* Handle for timer */ + struct callout_handle \ + ccs_timerh; /* Handle for ccs timeouts */ #if RAY_NEED_STARTJOIN_TIMO struct callout_handle \ sj_timerh; /* Handle for start_join timer */ @@ -330,22 +401,39 @@ struct ray_softc { struct ray_ecf_startup_v5 \ sc_ecf_startup; /* Startup info from card */ - u_int8_t sc_ccsinuse[64];/* ccss' in use -- not for tx */ - size_t sc_ccs; /* ccs used by non-scheduled, */ - /* non-overlapping procedures */ - struct ray_cmd_net sc_cnet_1; /* current network params from */ - struct ray_net_params sc_cnet_2; /* starting/joining a network */ + struct ray_net_params \ + sc_cnet_2; /* starting/joining a network */ + u_int8_t sc_ap_status; /* Current operating mode */ + int sc_havenet; /* true if we have a network */ #if 0 + u_int8_t sc_oap_status; /* Old operating mode */ u_int8_t sc_cnwid[IEEE80211_NWID_LEN]; /* Last nwid */ u_int8_t sc_dnwid[IEEE80211_NWID_LEN]; /* Desired nwid */ - u_int8_t sc_omode; /* Old operating mode SC_MODE_xx */ - u_int8_t sc_mode; /* Current operating mode SC_MODE_xx */ u_int8_t sc_countrycode; /* Current country code */ u_int8_t sc_dcountrycode;/* Desired country code */ #endif - int sc_havenet; /* true if we have aquired a network */ + + int sc_promisc; /* current set value */ + int sc_running; /* things we are doing */ + int sc_scheduled; /* things we need to do */ + int sc_timoneed; /* set if timeout is sched */ + int sc_timocheck; /* set if timeout is sched */ + u_int8_t sc_ccsinuse[64];/* ccss' in use -- not for tx */ + size_t sc_startccs; /* ccs of start/join */ + u_int sc_startcmd; /* cmd (start | join) */ + + int sc_checkcounters; + u_int64_t sc_rxoverflow; /* Number of rx overflows */ + u_int64_t sc_rxcksum; /* Number of checksum errors */ + u_int64_t sc_rxhcksum; /* Number of header checksum errors */ + u_int8_t sc_rxnoise; /* Average receiver level */ + + struct ray_param_req \ + *sc_repreq; /* used to return values */ + struct ray_param_req \ + *sc_updreq; /* to the user */ }; static struct ray_softc ray_softc[NRAY]; @@ -364,7 +452,6 @@ static struct ray_softc ray_softc[NRAY]; #define sc_priv_join sc_cnet_2.p_privacy_can_join /* Remember to add to the debug macro and ioctl*/ -/* XXX might not need these */ /* Commands -- priority given to LSB */ #define SCP_FIRST 0x0001 #define SCP_UPDATESUBCMD 0x0001 @@ -374,8 +461,13 @@ static struct ray_softc ray_softc[NRAY]; /* Update sub commands -- issues are serialized priority to LSB */ #define SCP_UPD_FIRST 0x0100 +#if XXX_DOWNLOAD_STD_TIMEOUT #define SCP_UPD_STARTUP 0x0100 #define SCP_UPD_STARTJOIN 0x0200 +#else +#define SCP_UPD_STARTUP 0 +#define SCP_UPD_STARTJOIN 0 +#endif /* XXX_DOWNLOAD_STD_TIMEOUT */ #define SCP_UPD_PROMISC 0x0400 #define SCP_UPD_MCAST 0x0800 #define SCP_UPD_UPDATEPARAMS 0x1000 @@ -386,7 +478,6 @@ static struct ray_softc ray_softc[NRAY]; #define SCP_TIMOCHECK_CMD_MASK \ (SCP_UPD_UPDATEPARAMS | SCP_UPD_STARTUP | SCP_UPD_MCAST | \ SCP_UPD_PROMISC) -/*XXX might not need these */ /* * Translation types @@ -395,58 +486,102 @@ static struct ray_softc ray_softc[NRAY]; #define SC_TRANSLATE_WEBGEAR 0 /* - * PCMCIA driver definition - */ -static int ray_pccard_init __P((struct pccard_devinfo *dev_p)); -static void ray_pccard_unload __P((struct pccard_devinfo *dev_p)); -static int ray_pccard_intr __P((struct pccard_devinfo *dev_p)); - -PCCARD_MODULE(ray, ray_pccard_init, ray_pccard_unload, ray_pccard_intr, 0, net_imask); - -/* - * ISA driver definition - */ -static int ray_probe __P((struct isa_device *dev)); -static int ray_attach __P((struct isa_device *dev)); -struct isa_driver raydriver = { - ray_probe, - ray_attach, - "ray", - 1 -}; - -/* - * Network driver definition - */ -static void ray_start __P((struct ifnet *ifp)); -static int ray_ioctl __P((struct ifnet *ifp, u_long command, caddr_t data)); -static void ray_watchdog __P((struct ifnet *ifp)); -static void ray_init __P((void *xsc)); -static void ray_stop __P((struct ray_softc *sc)); - -/* - * Internal utilites + * Prototyping */ +static int ray_attach __P((struct isa_device *dev)); static int ray_alloc_ccs __P((struct ray_softc *sc, size_t *ccsp, u_int cmd, u_int track)); static void ray_ccs_done __P((struct ray_softc *sc, size_t ccs)); +static void ray_check_ccs __P((void *arg)); +static void ray_check_scheduled __P((void *arg)); +static void ray_cmd_cancel __P((struct ray_softc *sc, int cmdf)); +static void ray_cmd_done __P((struct ray_softc *sc, int cmdf)); +static int ray_cmd_is_running __P((struct ray_softc *sc, int cmdf)); +static int ray_cmd_is_scheduled __P((struct ray_softc *sc, int cmdf)); +static void ray_cmd_ran __P((struct ray_softc *sc, int cmdf)); +static void ray_cmd_schedule __P((struct ray_softc *sc, int cmdf)); static void ray_download_params __P((struct ray_softc *sc)); static void ray_download_timo __P((void *xsc)); +#if RAY_DEBUG > 50 +static void ray_dump_mbuf __P((struct ray_softc *sc, struct mbuf *m, char *s)); +#endif /* RAY_DEBUG > 50 */ static u_int8_t ray_free_ccs __P((struct ray_softc *sc, size_t ccs)); +#if XXX_NETBSDTX +static void ray_free_ccs_chain __P((struct ray_softc *sc, u_int ni)); +#endif /* XXX_NETBSDTX */ +static int ray_intr __P((struct pccard_devinfo *dev_p)); +static int ray_ioctl __P((struct ifnet *ifp, u_long command, caddr_t data)); +static void ray_init __P((void *xsc)); static int ray_issue_cmd __P((struct ray_softc *sc, size_t ccs, u_int track)); +static int ray_pccard_init __P((struct pccard_devinfo *dev_p)); +static int ray_pccard_intr __P((struct pccard_devinfo *dev_p)); +static void ray_pccard_unload __P((struct pccard_devinfo *dev_p)); +static int ray_probe __P((struct isa_device *dev)); +static void ray_rcs_intr __P((struct ray_softc *sc, size_t ccs)); + +static void ray_report_params __P((struct ray_softc *sc)); static void ray_reset __P((struct ray_softc *sc)); static void ray_reset_timo __P((void *xsc)); -static void ray_rcs_intr __P((struct ray_softc *sc, size_t ccs)); static void ray_rx __P((struct ray_softc *sc, size_t rcs)); +static void ray_set_pending __P((struct ray_softc *sc, u_int cmdf)); +static int ray_simple_cmd __P((struct ray_softc *sc, u_int cmd, u_int track)); +static void ray_start __P((struct ifnet *ifp)); +static void ray_start_assoc __P((struct ray_softc *sc)); static void ray_start_done __P((struct ray_softc *sc, size_t ccs, u_int8_t status)); +static void ray_start_sc __P((struct ray_softc *sc)); static void ray_start_timo __P((void *xsc)); static size_t ray_start_wrhdr __P((struct ray_softc *sc, struct ether_header *eh, size_t bufp)); static void ray_start_join_done __P((struct ray_softc *sc, size_t ccs, u_int8_t status)); +static void ray_start_join_net __P((struct ray_softc *sc)); #if RAY_NEED_STARTJOIN_TIMO static void ray_start_join_timo __P((void *xsc)); #endif /* RAY_NEED_STARTJOIN_TIMO */ -#if RAY_DEBUG > 50 -static void ray_dump_mbuf __P((struct ray_softc *sc, struct mbuf *m, char *s)); -#endif /* RAY_DEBUG > 50 */ +static void ray_stop __P((struct ray_softc *sc)); +static void ray_update_error_counters \ + __P((struct ray_softc *sc)); +static void ray_update_mcast __P((struct ray_softc *sc)); +static void ray_update_params __P((struct ray_softc *sc)); +static void ray_update_params_done __P((struct ray_softc *sc, size_t ccs, u_int stat)); +static void ray_update_promisc __P((struct ray_softc *sc)); +static void ray_update_subcmd __P((struct ray_softc *sc)); +static int ray_user_update_params __P((struct ray_softc *sc, struct ray_param_req *pr)); +static int ray_user_report_params __P((struct ray_softc *sc, struct ray_param_req *pr)); +static void ray_watchdog __P((struct ifnet *ifp)); + +/* + * PCMCIA driver definition + */ +PCCARD_MODULE(ray, ray_pccard_init, ray_pccard_unload, ray_pccard_intr, 0, net_imask); + +/* + * ISA driver definition + */ +struct isa_driver raydriver = { + ray_probe, + ray_attach, + "ray", + 1 +}; + +/* + * Command function tables - based on bit index in SCP_xx + */ +typedef void (*ray_cmd_func_t)(struct ray_softc *); +static ray_cmd_func_t ray_cmdtab[] = { + ray_update_subcmd, /* SCP_UPDATESUBCMD */ + ray_start_assoc, /* SCP_STARTASSOC */ + ray_report_params, /* SCP_REPORTPARAMS */ + ray_start_sc /* SCP_IFSTART */ +}; +static int ray_ncmdtab = sizeof(ray_cmdtab) / sizeof(*ray_cmdtab); + +static ray_cmd_func_t ray_subcmdtab[] = { + ray_download_params, /* SCP_UPD_STARTUP */ + ray_start_join_net, /* SCP_UPD_STARTJOIN */ + ray_update_promisc, /* SCP_UPD_PROMISC */ + ray_update_mcast, /* SCP_UPD_MCAST */ + ray_update_params /* SCP_UPD_UPDATEPARAMS */ +}; +static int ray_nsubcmdtab = sizeof(ray_subcmdtab) / sizeof(*ray_subcmdtab); /* * Indirections for reading/writing shared memory - from NetBSD/if_ray.c @@ -494,15 +629,21 @@ static void ray_dump_mbuf __P((struct ray_softc *sc, struct mbuf *m, char *s)); /* * Macro's and constants */ +#ifndef RAY_CCS_TIMEOUT +#define RAY_CCS_TIMEOUT (hz / 2) +#endif +#ifndef RAY_CHECK_SCHED_TIMEOUT +#define RAY_CHECK_SCHED_TIMEOUT (hz) +#endif #ifndef RAY_DOWNLOAD_TIMEOUT #define RAY_DOWNLOAD_TIMEOUT (hz / 2) #endif -#ifndef RAY_START_TIMEOUT -#define RAY_START_TIMEOUT (hz / 2) -#endif #ifndef RAY_RESET_TIMEOUT #define RAY_RESET_TIMEOUT (10 * hz) #endif +#ifndef RAY_START_TIMEOUT +#define RAY_START_TIMEOUT (hz / 2) +#endif #if RAY_SIMPLE_TX #define RAY_IFQ_MAXLEN (2) #else if RAY_DECENT_TX @@ -516,11 +657,9 @@ static void ray_dump_mbuf __P((struct ray_softc *sc, struct mbuf *m, char *s)); #define RAY_HCS_INTR(sc) (ray_read_reg(sc, RAY_HCSIR) & RAY_HCSIR_IRQ) /* - * XXX * As described in if_xe.c... * * Horrid stuff for accessing CIS tuples and remapping common memory... - * XXX */ #define CARD_MAJOR 50 static int ray_attr_write __P((struct ray_softc *sc, off_t offset, u_int8_t byte)); @@ -548,7 +687,7 @@ ray_pccard_init (dev_p) RAY_DPRINTFN(5, ("ray%d: PCCard probe\n", dev_p->isahd.id_unit)); if (dev_p->isahd.id_unit >= NRAY) - return(ENODEV); + return (ENODEV); sc = &ray_softc[dev_p->isahd.id_unit]; @@ -562,7 +701,7 @@ ray_pccard_init (dev_p) doRemap = 0; if (sc->md.start == 0x0) { printf("ray%d: pccardd did not map CM - giving up\n", sc->unit); - return(ENXIO); + return (ENXIO); } if (sc->md.flags != MDF_ACTIVE) { printf("ray%d: Fixing up CM flags from 0x%x to 0x40\n", @@ -601,9 +740,9 @@ ray_pccard_init (dev_p) sc->slotnum); if (ray_attach(&dev_p->isahd)) - return(ENXIO); + return (ENXIO); - return(0); + return (0); } /* @@ -628,9 +767,19 @@ ray_pccard_unload (dev_p) /* * Clear out timers and sort out driver state + * + * We use callout_stop to unconditionally kill the ccs and general + * timers as they are used with multiple arguments. */ +#if RAY_USE_CALLOUT_STOP + callout_stop(sc->ccs_timerh); + callout_stop(sc->timerh); +#else + untimeout(ray_check_ccs, sc, sc->ccs_timerh); + untimeout(ray_check_scheduled, sc, sc->ccs_timerh); untimeout(ray_download_timo, sc, sc->timerh); untimeout(ray_reset_timo, sc, sc->timerh); +#endif /* RAY_USE_CALLOUT_STOP */ #if RAY_NEED_STARTJOIN_TIMO untimeout(ray_start_join_timo, sc, sc->sj_timerh); #endif /* RAY_NEED_STARTJOIN_TIMO */ @@ -658,59 +807,13 @@ ray_pccard_unload (dev_p) } /* - * PCCard interrupt. + * process an interrupt */ static int ray_pccard_intr (dev_p) struct pccard_devinfo *dev_p; { - struct ray_softc *sc; - struct ifnet *ifp; - int ccsi, handled; - - RAY_DPRINTFN(5, ("ray%d: PCCard intr\n", dev_p->isahd.id_unit)); - - sc = &ray_softc[dev_p->isahd.id_unit]; - ifp = &sc->arpcom.ac_if; - RAY_MAP_CM(sc); - - if (sc->gone) { - printf("ray%d: unloaded before interrupt!\n", sc->unit); - return(0); - } - - /* - * Check that the interrupt was for us, if so get the rcs/ccs and vector - * on the command contained within it. - */ - if (!RAY_HCS_INTR(sc)) { - - handled = 0; - - } else { - - handled = 1; - ccsi = SRAM_READ_1(sc, RAY_SCB_RCSI); - if (ccsi <= RAY_CCS_LAST) - ray_ccs_done(sc, RAY_CCS_ADDRESS(ccsi)); - else if (ccsi <= RAY_RCS_LAST) - ray_rcs_intr(sc, RAY_CCS_ADDRESS(ccsi)); - else - printf("ray%d: ray_intr bad ccs index %d\n", sc->unit, ccsi); - - } - - if (handled) - RAY_HCS_CLEAR_INTR(sc); - - RAY_DPRINTFN(10, ("ray%d: interrupt %s handled\n", - sc->unit, handled?"was":"not")); - - /* Send any packets lying around */ - if (!(ifp->if_flags & IFF_OACTIVE) && (ifp->if_snd.ifq_head != NULL)) - ray_start(ifp); - - return(handled); + return (ray_intr(dev_p)); } /* @@ -723,7 +826,7 @@ ray_probe (dev_p) RAY_DPRINTFN(5, ("ray%d: ISA probe\n", dev_p->id_unit)); - return(0); + return (0); } /* @@ -745,7 +848,7 @@ ray_attach (dev_p) if (sc->gone) { printf("ray%d: unloaded before attach!\n", sc->unit); - return(1); + return (1); } /* @@ -767,14 +870,14 @@ ray_attach (dev_p) "\007RERSERVED1" "\008TEST_COMPLETE" ); - return(1); + return (1); } if (sc->sc_version != RAY_ECFS_BUILD_4 && sc->sc_version != RAY_ECFS_BUILD_5 ) { printf("ray%d: unsupported firmware version 0x%0x\n", sc->unit, ep->e_fw_build_string); - return(1); + return (1); } if (bootverbose || RAY_DEBUG) { @@ -847,6 +950,7 @@ ray_attach (dev_p) if (ifunit(ifname) == NULL) { callout_handle_init(&sc->timerh); + callout_handle_init(&sc->ccs_timerh); #if RAY_NEED_STARTJOIN_TIMO callout_handle_init(&sc->sj_timerh); #endif /* RAY_NEED_STARTJOIN_TIMO */ @@ -863,7 +967,379 @@ ray_attach (dev_p) #endif /* XXX */ } - return(0); + return (0); +} + +/* + * Network initialisation. + * + * Start up flow is as follows. + * The kernel calls ray_init when the interface is assigned an address. + * + * ray_init does a bit of house keeping before calling ray_download_params. + * + * ray_download_params fills the startup parameter structure out and + * sends it to the card. The download command simply completes so we + * use schedule a timeout function call to ray_download_timo instead + * of spin locking. We pass the ccs in use via sc->sc_startcss. + * + * ray_download_timo checks the ccs for command completion and/or + * errors. Then it tells the card to start an adhoc network or join a + * managed network. This should complete via the interrupt mechanism, + * but the NetBSD driver includes a timeout for some buggy stuff + * somewhere - I've left the hooks in but don't use them. The interrupt + * handler passes control to ray_start_join_done - the ccs is handled + * by the interrupt mechanism. + * + * Once ray_start_join_done has checked the ccs and uploaded/updated + * the network parameters we are ready to process packets. It is then + * safe to call ray_start which is done by the interrupt handler. + */ +static void +ray_init (xsc) + void *xsc; +{ + struct ray_softc *sc = xsc; + struct ray_ecf_startup_v5 *ep; + struct ifnet *ifp; + size_t ccs; + int i; + + RAY_DPRINTFN(5, ("ray%d: Network init\n", sc->unit)); + RAY_MAP_CM(sc); + + if (sc->gone) { + printf("ray%d: unloaded before init!\n", sc->unit); + return; + } + + ifp = &sc->arpcom.ac_if; + + if ((ifp->if_flags & IFF_RUNNING)) + ray_stop(sc); + + /* + * Reset instance variables + * + * The first set are network parameters that are fully initialised + * when the card starts or joins the network. + * + * The second set are network parameters that are downloaded to + * the card. + * + * The third set are driver parameters. + * + * All of the variables in these sets can be updated by the card or ioctls. + */ +#if XXX + see the ray_attach section for stuff to move +#endif + sc->sc_upd_param = 0; + bzero(sc->sc_bss_id, sizeof(sc->sc_bss_id)); + sc->sc_inited = 0; + sc->sc_def_txrate = 0; + sc->sc_encrypt = 0; + + sc->sc_net_type = RAY_MIB_NET_TYPE_DEFAULT; + sc->sc_ap_status = RAY_MIB_AP_STATUS_DEFAULT; + bzero(sc->sc_ssid, sizeof(sc->sc_ssid)); + strncpy(sc->sc_ssid, RAY_MIB_SSID_DEFAULT, RAY_MAXSSIDLEN); + sc->sc_priv_start = RAY_MIB_PRIVACY_MUST_START_DEFAULT; + sc->sc_priv_join = RAY_MIB_PRIVACY_CAN_JOIN_DEFAULT; + sc->sc_promisc = !!(ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)); + + sc->sc_havenet = 0; + sc->translation = SC_TRANSLATE_WEBGEAR; + + /* Set all ccs to be free */ + bzero(sc->sc_ccsinuse, sizeof(sc->sc_ccsinuse)); + sc->sc_startccs = RAY_CCS_LAST + 1; + ccs = RAY_CCS_ADDRESS(0); + for (i = 0; i < RAY_CCS_LAST; ccs += RAY_CCS_SIZE, i++) + RAY_CCS_FREE(sc, ccs); + + /* Clear any pending interrupts */ + RAY_HCS_CLEAR_INTR(sc); + +#if XXX + Not sure why I really need this - maybe best to deal with + this when resets are requested by me? +#endif /* XXX */ + /* + * Get startup results - the card may have been reset + */ + ep = &sc->sc_ecf_startup; + ray_read_region(sc, RAY_ECF_TO_HOST_BASE, ep, sizeof(sc->sc_ecf_startup)); + if (ep->e_status != RAY_ECFS_CARD_OK) { + printf("ray%d: card failed self test: status 0x%b\n", sc->unit, + ep->e_status, + "\020" /* print in hex */ + "\001RESERVED0" + "\002PROC_SELF_TEST" + "\003PROG_MEM_CHECKSUM" + "\004DATA_MEM_TEST" + "\005RX_CALIBRATION" + "\006FW_VERSION_COMPAT" + "\007RERSERVED1" + "\008TEST_COMPLETE" + ); + return; /* XXX This doesn't mark the interface as down */ + } + + /* + * Fixup tib size to be correct - on build 4 it is garbage + */ + if (sc->sc_version == RAY_ECFS_BUILD_4 && sc->sc_tibsize == 0x55) + sc->sc_tibsize = sizeof(struct ray_tx_tib); + + /* + * We are now up and running. Next we have to download network + * configuration into the card. We are busy until download is done. + */ + ifp->if_flags |= IFF_RUNNING | IFF_OACTIVE; + + ray_download_params(sc); + + return; +} + +/* + * Network stop. + * + * Assumes that a ray_init is used to restart the card. + * + */ +static void +ray_stop (sc) + struct ray_softc *sc; +{ + struct ifnet *ifp; + int s; + + RAY_DPRINTFN(5, ("ray%d: Network stop\n", sc->unit)); + RAY_MAP_CM(sc); + + if (sc->gone) { + printf("ray%d: unloaded before stop!\n", sc->unit); + return; + } + + ifp = &sc->arpcom.ac_if; + + /* + * Clear out timers and sort out driver state + */ + untimeout(ray_download_timo, sc, sc->timerh); + untimeout(ray_reset_timo, sc, sc->timerh); +#if RAY_NEED_STARTJOIN_TIMO + untimeout(ray_start_join_timo, sc, sc->sj_timerh); +#endif /* RAY_NEED_STARTJOIN_TIMO */ + untimeout(ray_start_timo, sc, sc->start_timerh); + sc->sc_havenet = 0; + + /* + * Inhibit card - if we can't prevent reception then do not worry; + * stopping a NIC only guarantees no TX. + */ + s = splimp(); + /* XXX what does the SHUTDOWN command do? Or power saving in COR */ + splx(s); + + /* + * Mark as not running + */ + ifp->if_flags &= ~IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + + return; +} + +/* + * Reset the card + * + * I'm using the soft reset command in the COR register. I'm not sure + * if the sequence is right but it does seem to do the right thing. A + * nano second after reset is written the flashing light goes out, and + * a few seconds after the default is written the main card light goes + * out. We wait a while and then re-init the card. + */ +static void +ray_reset (sc) + struct ray_softc *sc; +{ + struct ifnet *ifp; + + RAY_DPRINTFN(5, ("ray%d: ray_reset\n", sc->unit)); + RAY_MAP_CM(sc); + + ifp = &sc->arpcom.ac_if; + + if (ifp->if_flags & IFF_RUNNING) + ray_stop(sc); + + printf("ray%d: resetting card\n", sc->unit); + ray_attr_write((sc), RAY_COR, RAY_COR_RESET); + ray_attr_write((sc), RAY_COR, RAY_COR_DEFAULT); + sc->timerh = timeout(ray_reset_timo, sc, RAY_RESET_TIMEOUT); + + return; +} + +/* + * Finishing resetting and restarting the card + */ +static void +ray_reset_timo (xsc) + void *xsc; +{ + struct ray_softc *sc = xsc; + + RAY_DPRINTFN(5, ("ray%d: ray_reset_timo\n", sc->unit)); + RAY_MAP_CM(sc); + + if (!RAY_ECF_READY(sc)) { + RAY_DPRINTFN(1, ("ray%d: ray_reset_timo still busy, re-schedule\n", + sc->unit)); + sc->timerh = timeout(ray_reset_timo, sc, RAY_RESET_TIMEOUT); + return; + } + + RAY_HCS_CLEAR_INTR(sc); + ray_init(sc); + + return; +} + +static void +ray_watchdog (ifp) + register struct ifnet *ifp; +{ + struct ray_softc *sc; + + RAY_DPRINTFN(5, ("ray%d: Network watchdog\n", ifp->if_unit)); + + sc = ifp->if_softc; + RAY_MAP_CM(sc); + + if (sc->gone) { + printf("ray%d: unloaded before watchdog!\n", sc->unit); + return; + } + + printf("ray%d: watchdog timeout\n", sc->unit); + +/* XXX may need to have remedial action here + for example + ray_reset + ray_stop + ... + ray_init + + do we only use on TX? + if so then we should clear OACTIVE etc. + +*/ + + return; +} + +/* + * Network ioctl request. + */ +static int +ray_ioctl (ifp, command, data) + register struct ifnet *ifp; + u_long command; + caddr_t data; +{ + struct ray_softc *sc; + int s, error = 0; + + RAY_DPRINTFN(5, ("ray%d: Network ioctl\n", ifp->if_unit)); + + sc = ifp->if_softc; + RAY_MAP_CM(sc); + + if (sc->gone) { + printf("ray%d: unloaded before ioctl!\n", sc->unit); + ifp->if_flags &= ~IFF_RUNNING; + return (ENXIO); + } + + s = splimp(); + + switch (command) { + + case SIOCSIFADDR: + case SIOCGIFADDR: + case SIOCSIFMTU: + RAY_DPRINTFN(30, ("ray%d: ioctl SIFADDR/GIFADDR/SIFMTU\n", sc->unit)); + error = ether_ioctl(ifp, command, data); + break; + + case SIOCSIFFLAGS: + RAY_DPRINTFN(30, ("ray%d: for SIFFLAGS\n", sc->unit)); + /* + * If the interface is marked up and stopped, then start + * it. If it is marked down and running, then stop it. + */ + if (ifp->if_flags & IFF_UP) { + if (!(ifp->if_flags & IFF_RUNNING)) + ray_init(sc); + ray_update_promisc(sc); + } else { + if (ifp->if_flags & IFF_RUNNING) + ray_stop(sc); + } + /* XXX DROP THROUGH or not? */ + + case SIOCADDMULTI: + case SIOCDELMULTI: + RAY_DPRINTFN(30, ("ray%d: ioctl called for ADDMULTI/DELMULTI\n", sc->unit)); +#if XXX_MCAST + ray_setmulti(sc); +#endif /* XXX_MCAST */ + error = 0; + break; + +case SIOCGIFFLAGS: + RAY_DPRINTFN(30, ("ray%d: ioctl called for GIFFLAGS\n", sc->unit)); + error = EINVAL; + break; +case SIOCGIFMETRIC: + RAY_DPRINTFN(30, ("ray%d: ioctl called for GIFMETRIC\n", sc->unit)); + error = EINVAL; + break; +case SIOCGIFMTU: + RAY_DPRINTFN(30, ("ray%d: ioctl called for GIFMTU\n", sc->unit)); + error = EINVAL; + break; +case SIOCGIFPHYS: + RAY_DPRINTFN(30, ("ray%d: ioctl called for GIFPYHS\n", sc->unit)); + error = EINVAL; + break; +case SIOCSIFMEDIA: + RAY_DPRINTFN(30, ("ray%d: ioctl called for SIFMEDIA\n", sc->unit)); + error = EINVAL; + break; +case SIOCGIFMEDIA: + RAY_DPRINTFN(30, ("ray%d: ioctl called for GIFMEDIA\n", sc->unit)); +#if RAY_DUMP_CM_ON_GIFMEDIA + RAY_DPRINTFN(10, ("ray%d: RAY_SCB\n", sc->unit)); + RAY_DHEX8((u_int8_t *)sc->maddr + RAY_SCB_BASE, 0x20); + RAY_DPRINTFN(10, ("ray%d: RAY_STATUS\n", sc->unit)); + RAY_DNET_DUMP(sc, "."); +#endif /* RAY_DUMP_CM_ON_GIFMEDIA */ + error = EINVAL; + break; + + default: + error = EINVAL; + } + + splx(s); + + return (error); } /* @@ -880,20 +1356,29 @@ ray_attach (dev_p) */ static void ray_start (ifp) - register struct ifnet *ifp; + struct ifnet *ifp; { + RAY_DPRINTFN(5, ("ray%d: ray_start\n", ifp->if_unit)); + + ray_start_sc(ifp->if_softc); +} + +static void +ray_start_sc (sc) struct ray_softc *sc; +{ + struct ifnet *ifp; struct mbuf *m0, *m; struct ether_header *eh; size_t ccs, bufp; int i, pktlen, len; u_int8_t status; - RAY_DPRINTFN(5, ("ray%d: Network start\n", ifp->if_unit)); - - sc = ifp->if_softc; + RAY_DPRINTFN(5, ("ray%d: ray_start_sc\n", sc->unit)); RAY_MAP_CM(sc); + ifp = &sc->arpcom.ac_if; + /* * Some simple checks first */ @@ -916,10 +1401,18 @@ ray_start (ifp) * and we certainly chew CPU. However bing to windows boxes shows * a reliance on the far end too: * + * 1500k default rate + * * Libretto 50CT (75MHz Pentium) with FreeBSD-3.1 to * Nonname box Windows 95C (133MHz AMD 5x86) 996109bps * AST J30 Windows 95A (100MHz Pentium) 1307791bps * + * 2000k default rate + * + * Libretto 50CT (75MHz Pentium) with FreeBSD-3.1 to + * Nonname box Windows 95C (133MHz AMD 5x86) 1087049bps + * AST J30 Windows 95A (100MHz Pentium) 1307791bps + * * Flow is * get a ccs * build the packet @@ -995,6 +1488,18 @@ ray_start (ifp) return; } + /* XXX + * I would much prefer to have the complete 802.11 packet dropped to + * the bpf tap and then have a user land program parse the headers + * as needed. This way, tcpdump -w can be used to grab the raw data. If + * needed the 802.11 aware program can "translate" the .11 to ethernet + * for tcpdump -r. + */ +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap(ifp, m0); +#endif /* NBPFILTER */ + /* * Translation - capability as described earlier * @@ -1004,6 +1509,7 @@ ray_start (ifp) * headers as needed. * * We've pulled up the mbuf for you. + * */ if (m0->m_len < sizeof(struct ether_header)) m = m_pullup(m, sizeof(struct ether_header)); @@ -1056,6 +1562,7 @@ ray_start (ifp) bufp += len; } RAY_DMBUF_DUMP(sc, m0, "ray_start"); + m_free(m0); /* @@ -1081,18 +1588,9 @@ ray_start (ifp) ifp->if_flags |= IFF_OACTIVE; RAY_ECF_START_CMD(sc); -#if XXX -#if NBPFILTER > 0 - /* XXX but the translation code dicks around with the mbuf structure sigh */ - /* XXX and I've freed the mbuf already */ - if (ifp->if_bpf) - bpf_mtap(ifp, m0); -#endif -#endif /* XXX */ - return; } -#if XXX +#if XXX_NETBSDTX netbsd driver uses a loop @@ -1143,8 +1641,7 @@ netbsd: free lsit rework calling - -#endif +#endif XXX_NETBSDTX /* * TX completion routine. @@ -1232,7 +1729,6 @@ ray_start_wrhdr (sc, eh, bufp) bcopy(sc->sc_bss_id, header.i_addr3, ETHER_ADDR_LEN); } else { -#if XXX_INFRA if (sc->sc_ap_status == RAY_MIB_AP_STATUS_TERMINAL) { header.i_fc[1] = IEEE80211_FC1_STA_TO_AP; @@ -1241,545 +1737,17 @@ ray_start_wrhdr (sc, eh, bufp) bcopy(eh->ether_dhost, header.i_addr3, ETHER_ADDR_LEN); } else - panic("ray%d: ray_start can't be an AP yet\n", sc-.unit); -#endif /* XXX_INFRA */ + printf("ray%d: ray_start can't be an AP yet\n", sc->unit); } ray_write_region(sc, bufp, (u_int8_t *)&header, sizeof(struct ieee80211_header)); - return(bufp + sizeof(struct ieee80211_header)); -} - -/* - * Network ioctl request. - */ -static int -ray_ioctl (ifp, command, data) - register struct ifnet *ifp; - u_long command; - caddr_t data; -{ - struct ray_softc *sc; - int s, error = 0; - - RAY_DPRINTFN(5, ("ray%d: Network ioctl\n", ifp->if_unit)); - - sc = ifp->if_softc; - RAY_MAP_CM(sc); - - if (sc->gone) { - printf("ray%d: unloaded before ioctl!\n", sc->unit); - ifp->if_flags &= ~IFF_RUNNING; - return(ENXIO); - } - - s = splimp(); - - switch (command) { - - case SIOCSIFADDR: - case SIOCGIFADDR: - case SIOCSIFMTU: - RAY_DPRINTFN(30, ("ray%d: ioctl SIFADDR/GIFADDR/SIFMTU\n", sc->unit)); - error = ether_ioctl(ifp, command, data); - break; - - case SIOCSIFFLAGS: - RAY_DPRINTFN(30, ("ray%d: for SIFFLAGS\n", sc->unit)); - /* - * If the interface is marked up and stopped, then start - * it. If it is marked down and running, then stop it. - */ - if (ifp->if_flags & IFF_UP) { - if (!(ifp->if_flags & IFF_RUNNING)) - ray_init(sc); - } else { - if (ifp->if_flags & IFF_RUNNING) - ray_stop(sc); - } - /* DROP THROUGH */ - -#if XXX - case SIOCADDMULTI: - case SIOCDELMULTI: - RAY_DPRINTFN(30, ("ray%d: ioctl called for ADDMULTI/DELMULTI\n, sc->unit")); - /* - * Multicast list has (maybe) changed; set the hardware filter - * accordingly. This also serves to deal with promiscuous mode - * if we have a BPF listener active. - */ - ray_setmulti(sc); -#endif /* XXX */ - - error = 0; - break; - -case SIOCGIFFLAGS: - RAY_DPRINTFN(30, ("ray%d: ioctl called for GIFFLAGS\n", sc->unit)); - error = EINVAL; - break; -case SIOCGIFMETRIC: - RAY_DPRINTFN(30, ("ray%d: ioctl called for GIFMETRIC\n", sc->unit)); - error = EINVAL; - break; -case SIOCGIFMTU: - RAY_DPRINTFN(30, ("ray%d: ioctl called for GIFMTU\n", sc->unit)); - error = EINVAL; - break; -case SIOCGIFPHYS: - RAY_DPRINTFN(30, ("ray%d: ioctl called for GIFPYHS\n", sc->unit)); - error = EINVAL; - break; -case SIOCSIFMEDIA: - RAY_DPRINTFN(30, ("ray%d: ioctl called for SIFMEDIA\n", sc->unit)); - error = EINVAL; - break; -case SIOCGIFMEDIA: - RAY_DPRINTFN(30, ("ray%d: ioctl called for GIFMEDIA\n", sc->unit)); -#if RAY_DUMP_CM_ON_GIFMEDIA - RAY_DPRINTFN(10, ("ray%d: RAY_SCB\n", sc->unit)); - RAY_DHEX8((u_int8_t *)sc->maddr + RAY_SCB_BASE, 0x20); - RAY_DPRINTFN(10, ("ray%d: RAY_STATUS\n", sc->unit)); - RAY_DNET_DUMP(sc, "."); -#endif /* RAY_DUMP_CM_ON_GIFMEDIA */ - error = EINVAL; - break; - - default: - error = EINVAL; - } - - splx(s); - - return(error); -} - -static void -ray_watchdog (ifp) - register struct ifnet *ifp; -{ - struct ray_softc *sc; - - RAY_DPRINTFN(5, ("ray%d: Network watchdog\n", ifp->if_unit)); - - sc = ifp->if_softc; - RAY_MAP_CM(sc); - - if (sc->gone) { - printf("ray%d: unloaded before watchdog!\n", sc->unit); - return; - } - - printf("ray%d: watchdog timeout\n", sc->unit); - -/* XXX may need to have remedial action here - for example - ray_reset - ray_stop - ... - ray_init - - do we only use on TX? - if so then we should clear OACTIVE etc. - -*/ - - return; -} - -/* - * Network initialisation. - * - * Start up flow is as follows. - * The kernel calls ray_init when the interface is assigned an address. - * - * ray_init does a bit of house keeping before calling ray_download_params. - * - * ray_download_params fills the startup parameter structure out and - * sends it to the card. The download command simply completes so we - * use schedule a timeout function call to ray_download_timo instead - * of spin locking. We pass the ccs in use via sc->sc_css. - * - * ray_download_timo checks the ccs for command completion and/or - * errors. Then it tells the card to start an adhoc network or join a - * managed network. This should complete via the interrupt mechanism, - * but the NetBSD driver includes a timeout for some buggy stuff - * somewhere - I've left the hooks in but don't use them. The interrupt - * handler passes control to ray_start_join_done - the ccs is handled - * by the interrupt mechanism. - * - * Once ray_start_join_done has checked the ccs and uploaded/updated - * the network parameters we are ready to process packets. It is then - * safe to call ray_start which is done by the interrupt handler. - */ -static void -ray_init (xsc) - void *xsc; -{ - struct ray_softc *sc = xsc; - struct ray_ecf_startup_v5 *ep; - struct ifnet *ifp; - size_t ccs; - int i; - - RAY_DPRINTFN(5, ("ray%d: Network init\n", sc->unit)); - RAY_MAP_CM(sc); - - if (sc->gone) { - printf("ray%d: unloaded before init!\n", sc->unit); - return; - } - - ifp = &sc->arpcom.ac_if; - - if ((ifp->if_flags & IFF_RUNNING)) - ray_stop(sc); - - /* - * Reset instance variables - * - * The first set are network parameters that are fully initialised - * when the card starts or joins the network. - * - * The second set are network parameters that are downloaded to - * the card. - * - * The third set are driver parameters. - * - * All of the variables in these sets can be updated by the card or ioctls. - */ -#if XXX - see the ray_attach section for stuff to move -#endif - sc->sc_upd_param = 0; - bzero(sc->sc_bss_id, sizeof(sc->sc_bss_id)); - sc->sc_inited = 0; - sc->sc_def_txrate = 0; - sc->sc_encrypt = 0; - - sc->sc_net_type = RAY_MIB_NET_TYPE_DEFAULT; - bzero(sc->sc_ssid, sizeof(sc->sc_ssid)); - strncpy(sc->sc_ssid, RAY_MIB_SSID_DEFAULT, RAY_MAXSSIDLEN); - sc->sc_priv_start = RAY_MIB_PRIVACY_MUST_START_DEFAULT; - sc->sc_priv_join = RAY_MIB_PRIVACY_CAN_JOIN_DEFAULT; -#if XXX_MCASTPROM - sc->sc_promisc = !!(sc->sc_if.if_flags & (IFF_PROMISC|IFF_ALLMULTI)); -#endif /* XXX_MCASTPROM */ - - sc->sc_havenet = 0; - sc->translation = SC_TRANSLATE_WEBGEAR; - - /* Set all ccs to be free */ - bzero(sc->sc_ccsinuse, sizeof(sc->sc_ccsinuse)); - sc->sc_ccs = RAY_CCS_LAST + 1; - ccs = RAY_CCS_ADDRESS(0); - for (i = 0; i < RAY_CCS_LAST; ccs += RAY_CCS_SIZE, i++) - SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_status, RAY_CCS_STATUS_FREE); - - /* Clear any pending interrupts */ - RAY_HCS_CLEAR_INTR(sc); - -#if XXX - Not sure why I really need this - maybe best to deal with - this when resets are requested by me? -#endif /* XXX */ - /* - * Get startup results - the card may have been reset - */ - ep = &sc->sc_ecf_startup; - ray_read_region(sc, RAY_ECF_TO_HOST_BASE, ep, sizeof(sc->sc_ecf_startup)); - if (ep->e_status != RAY_ECFS_CARD_OK) { - printf("ray%d: card failed self test: status 0x%b\n", sc->unit, - ep->e_status, - "\020" /* print in hex */ - "\001RESERVED0" - "\002PROC_SELF_TEST" - "\003PROG_MEM_CHECKSUM" - "\004DATA_MEM_TEST" - "\005RX_CALIBRATION" - "\006FW_VERSION_COMPAT" - "\007RERSERVED1" - "\008TEST_COMPLETE" - ); - return; /* XXX This doesn't mark the interface as down */ - } - - /* - * Fixup tib size to be correct - on build 4 it is garbage - */ - if (sc->sc_version == RAY_ECFS_BUILD_4 && sc->sc_tibsize == 0x55) - sc->sc_tibsize = sizeof(struct ray_tx_tib); - - /* - * We are now up and running. Next we have to download network - * configuration into the card. We are busy until download is done. - */ - ifp->if_flags |= IFF_RUNNING | IFF_OACTIVE; - - ray_download_params(sc); - - return; -} - -/* - * Network stop. - * - * Assumes that a ray_init is used to restart the card. - * - */ -static void -ray_stop (sc) - struct ray_softc *sc; -{ - struct ifnet *ifp; - int s; - - RAY_DPRINTFN(5, ("ray%d: Network stop\n", sc->unit)); - RAY_MAP_CM(sc); - - if (sc->gone) { - printf("ray%d: unloaded before stop!\n", sc->unit); - return; - } - - ifp = &sc->arpcom.ac_if; - - /* - * Clear out timers and sort out driver state - */ - untimeout(ray_download_timo, sc, sc->timerh); - untimeout(ray_reset_timo, sc, sc->timerh); -#if RAY_NEED_STARTJOIN_TIMO - untimeout(ray_start_join_timo, sc, sc->sj_timerh); -#endif /* RAY_NEED_STARTJOIN_TIMO */ - untimeout(ray_start_timo, sc, sc->start_timerh); - sc->sc_havenet = 0; - - /* - * Inhibit card - if we can't prevent reception then do not worry; - * stopping a NIC only guarantees no TX. - */ - s = splimp(); - /* XXX what does the SHUTDOWN command do? Or power saving in COR */ - splx(s); - - /* - * Mark as not running - */ - ifp->if_flags &= ~IFF_RUNNING; - ifp->if_flags &= ~IFF_OACTIVE; - - return; -} - -/* - * Reset the card - * - * I'm using the soft reset command in the COR register. I'm not sure - * if the sequence is right but it does seem to do the right thing. A - * nano second after reset is written the flashing light goes out, and - * a few seconds after the default is written the main card light goes - * out. We wait a while and then re-init the card. - */ -static void -ray_reset (sc) - struct ray_softc *sc; -{ - struct ifnet *ifp; - - RAY_DPRINTFN(5, ("ray%d: ray_reset\n", sc->unit)); - RAY_MAP_CM(sc); - - ifp = &sc->arpcom.ac_if; - - if (ifp->if_flags & IFF_RUNNING) - ray_stop(sc); - - printf("ray%d: resetting card\n", sc->unit); - ray_attr_write((sc), RAY_COR, RAY_COR_RESET); - ray_attr_write((sc), RAY_COR, RAY_COR_DEFAULT); - sc->timerh = timeout(ray_reset_timo, sc, RAY_RESET_TIMEOUT); - - return; -} - -/* - * Finishing resetting and restarting the card - */ -static void -ray_reset_timo (xsc) - void *xsc; -{ - struct ray_softc *sc = xsc; - - RAY_DPRINTFN(5, ("ray%d: ray_reset_timo\n", sc->unit)); - RAY_MAP_CM(sc); - - if (!RAY_ECF_READY(sc)) { - RAY_DPRINTFN(1, ("ray%d: ray_reset_timo still busy, re-schedule\n", - sc->unit)); - sc->timerh = timeout(ray_reset_timo, sc, RAY_RESET_TIMEOUT); - return; - } - - RAY_HCS_CLEAR_INTR(sc); - ray_init(sc); - - return; -} - -/* - * Process CCS command completion - called from ray_intr - */ -static void -ray_ccs_done (sc, ccs) - struct ray_softc *sc; - size_t ccs; -{ - u_int cmd, status; - - RAY_DPRINTFN(5, ("ray%d: ray_ccs_done\n", sc->unit)); - RAY_MAP_CM(sc); - - cmd = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_cmd); - status = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_status); - RAY_DPRINTFN(20, ("ray%d: ccs idx %d ccs 0x%x cmd 0x%x status %d\n", - sc->unit, RAY_CCS_INDEX(ccs), ccs, cmd, status)); - - switch (cmd) { - case RAY_CMD_START_PARAMS: - printf("ray%d: ray_ccs_done got START_PARAMS - why?\n", sc->unit); - break; - - case RAY_CMD_UPDATE_PARAMS: - RAY_DPRINTFN(20, ("ray%d: ray_ccs_done got UPDATE_PARAMS\n", - sc->unit)); - XXX; - break; - - case RAY_CMD_REPORT_PARAMS: - RAY_DPRINTFN(20, ("ray%d: ray_ccs_done got REPORT_PARAMS\n", - sc->unit)); - XXX; - break; - - case RAY_CMD_UPDATE_MCAST: - RAY_DPRINTFN(20, ("ray%d: ray_ccs_done got UPDATE_MCAST\n", - sc->unit)); - XXX; - break; - - case RAY_CMD_UPDATE_APM: - RAY_DPRINTFN(20, ("ray%d: ray_ccs_done got UPDATE_APM\n", - sc->unit)); - XXX; - break; - - case RAY_CMD_START_NET: - case RAY_CMD_JOIN_NET: - RAY_DPRINTFN(20, ("ray%d: ray_ccs_done got START|JOIN_NET\n", - sc->unit)); - ray_start_join_done(sc, ccs, status); - break; - - case RAY_CMD_START_ASSOC: - RAY_DPRINTFN(20, ("ray%d: ray_ccs_done got START_ASSOC\n", - sc->unit)); - sc->sc_havenet = 1; /* Should not be here but in function */ - XXX; - break; - - case RAY_CMD_TX_REQ: - RAY_DPRINTFN(20, ("ray%d: ray_ccs_done got TX_REQ\n", - sc->unit)); - ray_start_done(sc, ccs, status); - return; - - case RAY_CMD_TEST_MEM: - printf("ray%d: ray_ccs_done got TEST_MEM - why?\n", sc->unit); - break; - - case RAY_CMD_SHUTDOWN: - printf("ray%d: ray_ccs_done got SHUTDOWN - why?\n", sc->unit); - break; - - case RAY_CMD_DUMP_MEM: - printf("ray%d: ray_ccs_done got DUMP_MEM - why?\n", sc->unit); - break; - - case RAY_CMD_START_TIMER: - printf("ray%d: ray_ccs_done got START_TIMER - why?\n", sc->unit); - break; - - default: - printf("ray%d: ray_ccs_done unknown command 0x%x\n", sc->unit, cmd); - break; - } - - ray_free_ccs(sc, ccs); - - return; -} - -/* - * Process ECF command request - called from ray_intr - */ -static void -ray_rcs_intr (sc, rcs) - struct ray_softc *sc; - size_t rcs; -{ - struct ifnet *ifp; - u_int cmd, status; - - RAY_DPRINTFN(5, ("ray%d: ray_rcs_intr\n", sc->unit)); - RAY_MAP_CM(sc); - - ifp = &sc->arpcom.ac_if; - - cmd = SRAM_READ_FIELD_1(sc, rcs, ray_cmd, c_cmd); - status = SRAM_READ_FIELD_1(sc, rcs, ray_cmd, c_status); - RAY_DPRINTFN(20, ("ray%d: rcs idx %d rcs 0x%x cmd 0x%x status %d\n", - sc->unit, RAY_CCS_INDEX(rcs), rcs, cmd, status)); - - switch (cmd) { - case RAY_ECMD_RX_DONE: - RAY_DPRINTFN(20, ("ray%d: ray_rcs_intr got RX_DONE\n", sc->unit)); - ray_rx(sc, rcs); - break; - - case RAY_ECMD_REJOIN_DONE: - RAY_DPRINTFN(20, ("ray%d: ray_rcs_intr got REJOIN_DONE\n", - sc->unit)); - sc->sc_havenet = 1; /* Should not be here but in function */ - XXX; - break; - - case RAY_ECMD_ROAM_START: - RAY_DPRINTFN(20, ("ray%d: ray_rcs_intr got ROAM_START\n", - sc->unit)); - sc->sc_havenet = 0; /* Should not be here but in function */ - XXX; - break; - - case RAY_ECMD_JAPAN_CALL_SIGNAL: - printf("ray%d: ray_rcs_intr got JAPAN_CALL_SIGNAL - why?\n", - sc->unit); - break; - - default: - printf("ray%d: ray_rcs_intr unknown command 0x%x\n", sc->unit, cmd); - break; - } - - SRAM_WRITE_FIELD_1(sc, rcs, ray_cmd, c_status, RAY_CCS_STATUS_FREE); - - return; + return (bufp + sizeof(struct ieee80211_header)); } /* - * Receive a packet + * recevice a packet from the card */ static void ray_rx (sc, rcs) @@ -1893,7 +1861,7 @@ skip_read: while ((i = ni) && (i != RAY_CCS_LINK_NULL)) { rcs = RAY_CCS_ADDRESS(i); ni = SRAM_READ_FIELD_1(sc, rcs, ray_cmd_rx, c_nextfrag); - SRAM_WRITE_FIELD_1(sc, rcs, ray_cmd, c_status, RAY_CCS_STATUS_FREE); + RAY_CCS_FREE(sc, rcs); } if (m0 == NULL) @@ -2014,7 +1982,7 @@ skip_read: if (ifp->if_bpf) bpf_mtap(ifp, m0); #endif /* NBPFILTER */ -#if XXX +#if XXX_PROM if_wi.c - might be needed if we hear our own broadcasts in promiscuous mode but will not be if we dont see them if ((ifp->if_flags & IFF_PROMISC) && @@ -2024,7 +1992,7 @@ but will not be if we dont see them m_freem(m0); return; } -#endif /* XXX */ +#endif /* XXX_PROM */ eh = mtod(m0, struct ether_header *); m_adj(m0, sizeof(struct ether_header)); ether_input(ifp, eh, m0); @@ -2032,6 +2000,807 @@ but will not be if we dont see them return; } +/****************************************************************************** + * XXX NOT KNF FROM HERE UP + ******************************************************************************/ +/* + * an update params command has completed lookup which command and + * the status + * + * XXX this isn't finished yet, we need to grok the command used + */ +static void +ray_update_params_done(struct ray_softc *sc, size_t ccs, u_int stat) +{ + RAY_DPRINTFN(5, ("ray%d: ray_update_params_done\n", sc->unit)); + RAY_MAP_CM(sc); + + RAY_DPRINTFN(20, ("ray%d: ray_update_params_done stat %d\n", + sc->unit, stat)); + + /* this will get more complex as we add commands */ + if (stat == RAY_CCS_STATUS_FAIL) { + printf("ray%d: failed to update a promisc\n", sc->unit); + /* XXX should probably reset */ + /* rcmd = ray_reset; */ + } + + if (sc->sc_running & SCP_UPD_PROMISC) { + ray_cmd_done(sc, SCP_UPD_PROMISC); + sc->sc_promisc = SRAM_READ_1(sc, RAY_HOST_TO_ECF_BASE); + RAY_DPRINTFN(20, ("ray%d: new promisc value %d\n", sc->unit, + sc->sc_promisc)); + } else if (sc->sc_updreq) { + ray_cmd_done(sc, SCP_UPD_UPDATEPARAMS); + /* get the update parameter */ + sc->sc_updreq->r_failcause = + SRAM_READ_FIELD_1(sc, ccs, ray_cmd_update, c_failcause); + sc->sc_updreq = 0; + wakeup(ray_update_params); + ray_start_join_net(sc); + } +} + +/* + * check too see if we have any pending commands. + */ +static void +ray_check_scheduled(void *arg) +{ + struct ray_softc *sc; + int s, i, mask; + + s = splnet(); + sc = arg; + + RAY_DPRINTFN(5, ("ray%d: ray_check_scheduled\n", sc->unit)); + RAY_MAP_CM(sc); + + RAY_DPRINTFN(20, ( + "ray%d: ray_check_scheduled schd 0x%x running 0x%x ready %d\n", + sc->unit, sc->sc_scheduled, sc->sc_running, RAY_ECF_READY(sc))); + + if (sc->sc_timoneed) { + untimeout(ray_check_scheduled, sc, sc->ccs_timerh); + sc->sc_timoneed = 0; + } + + /* if update subcmd is running -- clear it in scheduled */ + if (sc->sc_running & SCP_UPDATESUBCMD) + sc->sc_scheduled &= ~SCP_UPDATESUBCMD; + + mask = SCP_FIRST; + for (i = 0; i < ray_ncmdtab; mask <<= 1, i++) { + if ((sc->sc_scheduled & ~SCP_UPD_MASK) == 0) + break; + if (!RAY_ECF_READY(sc)) + break; + if (sc->sc_scheduled & mask) + (*ray_cmdtab[i])(sc); + } + + RAY_DPRINTFN(20, ( + "ray%d: ray_check_scheduled sched 0x%x running 0x%x ready %d\n", + sc->unit, sc->sc_scheduled, sc->sc_running, RAY_ECF_READY(sc))); + + if (sc->sc_scheduled & ~SCP_UPD_MASK) + ray_set_pending(sc, sc->sc_scheduled); + + splx(s); +} + +/* + * check for unreported returns + * + * this routine is coded to only expect one outstanding request for the + * timed out requests at a time, but thats all that can be outstanding + * per hardware limitations + */ +static void +ray_check_ccs(void *arg) +{ + struct ray_softc *sc; + u_int i, cmd, stat; + size_t ccs; + int s; + + s = splnet(); + sc = arg; + + RAY_DPRINTFN(5, ("ray%d: ray_check_ccs\n", sc->unit)); + RAY_MAP_CM(sc); + + ccs = 0; + stat = RAY_CCS_STATUS_FAIL; + sc->sc_timocheck = 0; + for (i = RAY_CCS_CMD_FIRST; i <= RAY_CCS_CMD_LAST; i++) { + if (!sc->sc_ccsinuse[i]) + continue; + ccs = RAY_CCS_ADDRESS(i); + cmd = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_cmd); + switch (cmd) { + case RAY_CMD_START_PARAMS: + case RAY_CMD_UPDATE_MCAST: + case RAY_CMD_UPDATE_PARAMS: + stat = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_status); + RAY_DPRINTFN(20, ("ray%d: check ccs idx %d ccs 0x%x " + "cmd 0x%x stat %d\n", sc->unit, i, + ccs, cmd, stat)); + goto breakout; + } + } +breakout: + /* see if we got one of the commands we are looking for */ + if (i > RAY_CCS_CMD_LAST) + ; /* nothign */ + else if (stat == RAY_CCS_STATUS_FREE) { + stat = RAY_CCS_STATUS_COMPLETE; + ray_ccs_done(sc, ccs); + } else if (stat != RAY_CCS_STATUS_BUSY) { + if (sc->sc_ccsinuse[i] == 1) { + /* give a chance for the interrupt to occur */ + sc->sc_ccsinuse[i] = 2; + if (!sc->sc_timocheck) { + sc->ccs_timerh = timeout(ray_check_ccs, sc, 1); + sc->sc_timocheck = 1; + } + } else + ray_ccs_done(sc, ccs); + } else { + sc->ccs_timerh = timeout(ray_check_ccs, sc, RAY_CCS_TIMEOUT); + sc->sc_timocheck = 1; + } + splx(s); +} + +/* + * read the counters, the card implements the following protocol + * to keep the values from being changed while read: It checks + * the `own' bit and if zero writes the current internal counter + * value, it then sets the `own' bit to 1. If the `own' bit was 1 it + * incremenets its internal counter. The user thus reads the counter + * if the `own' bit is one and then sets the own bit to 0. + */ +static void +ray_update_error_counters(struct ray_softc *sc) +{ + size_t csc; + + RAY_DPRINTFN(5, ("ray%d: ray_update_error_counters\n", sc->unit)); + RAY_MAP_CM(sc); + + /* try and update the error counters */ + csc = RAY_STATUS_BASE; + if (SRAM_READ_FIELD_1(sc, csc, ray_csc, csc_mrxo_own)) { + sc->sc_rxoverflow += + SRAM_READ_FIELD_2(sc, csc, ray_csc, csc_mrx_overflow); + SRAM_WRITE_FIELD_1(sc, csc, ray_csc, csc_mrxo_own, 0); + } + if (SRAM_READ_FIELD_1(sc, csc, ray_csc, csc_mrxc_own)) { + sc->sc_rxcksum += + SRAM_READ_FIELD_2(sc, csc, ray_csc, csc_mrx_overflow); + SRAM_WRITE_FIELD_1(sc, csc, ray_csc, csc_mrxc_own, 0); + } + if (SRAM_READ_FIELD_1(sc, csc, ray_csc, csc_rxhc_own)) { + sc->sc_rxhcksum += + SRAM_READ_FIELD_2(sc, csc, ray_csc, csc_rx_hcksum); + SRAM_WRITE_FIELD_1(sc, csc, ray_csc, csc_rxhc_own, 0); + } + sc->sc_rxnoise = SRAM_READ_FIELD_1(sc, csc, ray_csc, csc_rx_noise); +} + +/****************************************************************************** + * XXX NOT KNF FROM HERE DOWN * + ******************************************************************************/ + +/* + * Process CCS command completion - called from ray_intr + */ +static void +ray_ccs_done (sc, ccs) + struct ray_softc *sc; + size_t ccs; +{ + u_int cmd, stat; + + RAY_DPRINTFN(5, ("ray%d: ray_ccs_done\n", sc->unit)); + RAY_MAP_CM(sc); + + cmd = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_cmd); + stat = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_status); + + RAY_DPRINTFN(20, ("ray%d: ccs idx %d ccs 0x%x cmd 0x%x status %d\n", + sc->unit, RAY_CCS_INDEX(ccs), ccs, cmd, stat)); + + switch (cmd) { + case RAY_CMD_START_PARAMS: +#if XXX_DOWNLOAD_STD_TIMEOUT + RAY_DPRINTFN(20, "ray%d: ray_ccs_done got START_PARAMS - why?\n", + sc->unit); + ray_cmd_done(sc, SCP_UPD_STARTUP); + ray_download_timo(sc); +#else + printf("ray%d: ray_ccs_done got START_PARAMS - why?\n", sc->unit); +#endif /* XXX_DOWNLOAD_STD_TIMEOUT */ + break; + + case RAY_CMD_UPDATE_PARAMS: + RAY_DPRINTFN(20, ("ray%d: ray_ccs_done got UPDATE_PARAMS\n", + sc->unit)); + ray_update_params_done(sc, ccs, stat); + break; + + case RAY_CMD_REPORT_PARAMS: + RAY_DPRINTFN(20, ("ray%d: ray_ccs_done got REPORT_PARAMS\n", + sc->unit)); + XXX; + break; + + case RAY_CMD_UPDATE_MCAST: + RAY_DPRINTFN(20, ("ray%d: ray_ccs_done got UPDATE_MCAST\n", + sc->unit)); + XXX; + break; + + case RAY_CMD_START_NET: + case RAY_CMD_JOIN_NET: + RAY_DPRINTFN(20, ("ray%d: ray_ccs_done got START|JOIN_NET\n", + sc->unit)); + ray_start_join_done(sc, ccs, stat); + break; + + case RAY_CMD_TX_REQ: + RAY_DPRINTFN(20, ("ray%d: ray_ccs_done got TX_REQ\n", + sc->unit)); + ray_start_done(sc, ccs, stat); + goto done; + + case RAY_CMD_START_ASSOC: + RAY_DPRINTFN(20, ("ray%d: ray_ccs_done got START_ASSOC\n", + sc->unit)); + sc->sc_havenet = 1; /* Should not be here but in function */ + XXX; + break; + + case RAY_CMD_UPDATE_APM: + RAY_DPRINTFN(20, ("ray%d: ray_ccs_done got UPDATE_APM\n", + sc->unit)); + XXX; + break; + + case RAY_CMD_TEST_MEM: + printf("ray%d: ray_ccs_done got TEST_MEM - why?\n", sc->unit); + break; + + case RAY_CMD_SHUTDOWN: + printf("ray%d: ray_ccs_done got SHUTDOWN - why?\n", sc->unit); + break; + + case RAY_CMD_DUMP_MEM: + printf("ray%d: ray_ccs_done got DUMP_MEM - why?\n", sc->unit); + break; + + case RAY_CMD_START_TIMER: + printf("ray%d: ray_ccs_done got START_TIMER - why?\n", sc->unit); + break; + + default: + printf("ray%d: ray_ccs_done unknown command 0x%x\n", sc->unit, cmd); + break; + } + + ray_free_ccs(sc, ccs); +done: + /* + * see if needed things can be done now that a command + * has completed + */ + ray_check_scheduled(sc); + + return; +} + +/* + * Process ECF command request - called from ray_intr + */ +static void +ray_rcs_intr (sc, rcs) + struct ray_softc *sc; + size_t rcs; +{ + struct ifnet *ifp; + u_int cmd, status; + + RAY_DPRINTFN(5, ("ray%d: ray_rcs_intr\n", sc->unit)); + RAY_MAP_CM(sc); + + ifp = &sc->arpcom.ac_if; + + cmd = SRAM_READ_FIELD_1(sc, rcs, ray_cmd, c_cmd); + status = SRAM_READ_FIELD_1(sc, rcs, ray_cmd, c_status); + RAY_DPRINTFN(20, ("ray%d: rcs idx %d rcs 0x%x cmd 0x%x status %d\n", + sc->unit, RAY_CCS_INDEX(rcs), rcs, cmd, status)); + + switch (cmd) { + case RAY_ECMD_RX_DONE: + RAY_DPRINTFN(20, ("ray%d: ray_rcs_intr got RX_DONE\n", sc->unit)); + ray_rx(sc, rcs); + break; + + case RAY_ECMD_REJOIN_DONE: + RAY_DPRINTFN(20, ("ray%d: ray_rcs_intr got REJOIN_DONE\n", + sc->unit)); + sc->sc_havenet = 1; /* Should not be here but in function */ + XXX; + break; + + case RAY_ECMD_ROAM_START: + RAY_DPRINTFN(20, ("ray%d: ray_rcs_intr got ROAM_START\n", + sc->unit)); + sc->sc_havenet = 0; /* Should not be here but in function */ + XXX; + break; + + case RAY_ECMD_JAPAN_CALL_SIGNAL: + printf("ray%d: ray_rcs_intr got JAPAN_CALL_SIGNAL - why?\n", + sc->unit); + break; + + default: + printf("ray%d: ray_rcs_intr unknown command 0x%x\n", sc->unit, cmd); + break; + } + + RAY_CCS_FREE(sc, rcs); + + return; +} +/****************************************************************************** + * XXX NOT KNF FROM HERE UP + ******************************************************************************/ + +/* + * process an interrupt + */ +static int +ray_intr(struct pccard_devinfo *dev_p) +{ + struct ray_softc *sc; + struct ifnet *ifp; + int i, count; + + sc = &ray_softc[dev_p->isahd.id_unit]; + + RAY_DPRINTFN(5, ("ray%d: ray_intr\n", sc->unit)); + RAY_MAP_CM(sc); + + ifp = &sc->arpcom.ac_if; + + if (sc->gone) { + printf("ray%d: unloaded before interrupt!\n", sc->unit); + return (0); + } + + if ((++sc->sc_checkcounters % 32) == 0) + ray_update_error_counters(sc); + + /* + * Check that the interrupt was for us, if so get the rcs/ccs + * and vector on the command contained within it. + */ + if (!RAY_HCS_INTR(sc)) + count = 0; + else { + count = 1; + i = SRAM_READ_1(sc, RAY_SCB_RCSI); + if (i <= RAY_CCS_LAST) + ray_ccs_done(sc, RAY_CCS_ADDRESS(i)); + else if (i <= RAY_RCS_LAST) + ray_rcs_intr(sc, RAY_CCS_ADDRESS(i)); + else + printf("ray%d: ray_intr bad ccs index %d\n", sc->unit, i); + } + + if (count) + RAY_HCS_CLEAR_INTR(sc); + + RAY_DPRINTFN(10, ("ray%d: interrupt %s handled\n", + sc->unit, count?"was":"not")); + + /* Send any packets lying around */ + if (!(ifp->if_flags & IFF_OACTIVE) && (ifp->if_snd.ifq_head != NULL)) + ray_start(ifp); + + return (count); +} + +/* + * Generic CCS handling + */ + +#if XXX_NETBSDTX +/* + * free the chain of descriptors -- used for freeing allocated tx chains + */ +static void +ray_free_ccs_chain(struct ray_softc *sc, u_int ni) +{ + u_int i; + + RAY_DPRINTFN(5, ("ray%d: ray_free_ccs_chain\n", sc->unit)); + RAY_MAP_CM(sc); + + while ((i = ni) != RAY_CCS_LINK_NULL) { + ni = SRAM_READ_FIELD_1(sc, RAY_CCS_ADDRESS(i), ray_cmd, c_link); + RAY_CCS_FREE(sc, RAY_CCS_ADDRESS(i)); + } +} +#endif XXX_NETBSDTX + +/* + * free up a cmd and return the old status. + * this routine is only used for commands. + */ +static u_int8_t +ray_free_ccs(struct ray_softc *sc, size_t ccs) +{ + u_int8_t stat; + + RAY_DPRINTFN(5, ("ray%d: ray_free_ccs\n", sc->unit)); + RAY_MAP_CM(sc); + + stat = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_status); + RAY_CCS_FREE(sc, ccs); + if (ccs <= RAY_CCS_ADDRESS(RAY_CCS_LAST)) + sc->sc_ccsinuse[RAY_CCS_INDEX(ccs)] = 0; + RAY_DPRINTFN(20, ("ray%d: ray_free_ccs freed 0x%02x\n", + sc->unit, RAY_CCS_INDEX(ccs))); + + return (stat); +} + +/* + * Obtain a free ccs buffer. + * + * returns 1 and in `ccsp' the bus offset of the free ccs + * or 0 if none are free + * + * If `track' is not zero, handles tracking this command + * possibly indicating a callback is needed and setting a timeout + * also if ECF isn't ready we terminate earlier to avoid overhead. + * + * this routine is only used for commands + */ +static int +ray_alloc_ccs(struct ray_softc *sc, size_t *ccsp, u_int cmd, u_int track) +{ + size_t ccs; + u_int i; + + RAY_DPRINTFN(5, ("ray%d: ray_alloc_ccs\n", sc->unit)); + RAY_MAP_CM(sc); + + /* for tracked commands, if not ready just set pending */ + if (track && !RAY_ECF_READY(sc)) { + ray_cmd_schedule(sc, track); + return (0); + } + + for (i = RAY_CCS_CMD_FIRST; i <= RAY_CCS_CMD_LAST; i++) { + /* probe here to make the card go */ + (void)SRAM_READ_FIELD_1(sc, RAY_CCS_ADDRESS(i), ray_cmd, + c_status); + if (!sc->sc_ccsinuse[i]) + break; + } + if (i > RAY_CCS_CMD_LAST) { + if (track) + ray_cmd_schedule(sc, track); + return (0); + } + sc->sc_ccsinuse[i] = 1; + ccs = RAY_CCS_ADDRESS(i); + SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_status, RAY_CCS_STATUS_BUSY); + SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_cmd, cmd); + SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_link, RAY_CCS_LINK_NULL); + + *ccsp = ccs; + return (1); +} + +/* + * this function sets the pending bit for the command given in 'need' + * and schedules a timeout if none is scheduled already. Any command + * that uses the `host to ecf' region must be serialized. + */ +static void +ray_set_pending(struct ray_softc *sc, u_int cmdf) +{ + RAY_DPRINTFN(5, ("ray%d: ray_set_pending\n", sc->unit)); + RAY_MAP_CM(sc); + RAY_DPRINTFN(20, ("ray%d: ray_set_pending 0x%0x\n", sc->unit, cmdf)); + + sc->sc_scheduled |= cmdf; + if (!sc->sc_timoneed) { + RAY_DPRINTFN(20, ("ray%d: ray_set_pending new timo\n", + sc->unit)); + sc->ccs_timerh = timeout(ray_check_scheduled, sc, + RAY_CHECK_SCHED_TIMEOUT); + sc->sc_timoneed = 1; + } +} + +/* + * schedule the `cmdf' for completion later + */ +static void +ray_cmd_schedule(struct ray_softc *sc, int cmdf) +{ + int track; + + RAY_DPRINTFN(5, ("ray%d: ray_cmd_schedule\n", sc->unit)); + RAY_MAP_CM(sc); + RAY_DPRINTFN(20, ("ray%d: ray_cmd_schedule 0x%x\n", sc->unit, cmdf)); + + track = cmdf; + if ((cmdf & SCP_UPD_MASK) == 0) + ray_set_pending(sc, track); + else if (ray_cmd_is_running(sc, SCP_UPDATESUBCMD)) { + /* don't do timeout mechaniscm if subcmd already going */ + sc->sc_scheduled |= cmdf; + } else + ray_set_pending(sc, cmdf | SCP_UPDATESUBCMD); +} + +/* + * check to see if `cmdf' has been scheduled + */ +static int +ray_cmd_is_scheduled(struct ray_softc *sc, int cmdf) +{ + RAY_DPRINTFN(5, ("ray%d: ray_cmd_is_scheduled\n", sc->unit)); + RAY_MAP_CM(sc); + RAY_DPRINTFN(20, ("ray%d: ray_cmd_is_scheduled 0x%x\n", + sc->unit, cmdf)); + + return ((sc->sc_scheduled & cmdf) ? 1 : 0); +} + +/* + * cancel a scheduled command (not a running one though!) + */ +static void +ray_cmd_cancel(struct ray_softc *sc, int cmdf) +{ + RAY_DPRINTFN(5, ("ray%d: ray_cmd_cancel\n", sc->unit)); + RAY_MAP_CM(sc); + RAY_DPRINTFN(20, ("ray%d: ray_cmd_cancel 0x%x\n", sc->unit, cmdf)); + + sc->sc_scheduled &= ~cmdf; + if ((cmdf & SCP_UPD_MASK) && (sc->sc_scheduled & SCP_UPD_MASK) == 0) + sc->sc_scheduled &= ~SCP_UPDATESUBCMD; + + /* if nothing else needed cancel the timer */ + if (sc->sc_scheduled == 0 && sc->sc_timoneed) { + untimeout(ray_check_scheduled, sc, sc->ccs_timerh); + sc->sc_timoneed = 0; + } +} + +/* + * called to indicate the 'cmdf' has been issued + */ +static void +ray_cmd_ran(struct ray_softc *sc, int cmdf) +{ + RAY_DPRINTFN(5, ("ray%d: ray_cmd_ran\n", sc->unit)); + RAY_MAP_CM(sc); + RAY_DPRINTFN(20, ("ray%d: ray_cmd_ran 0x%x\n", sc->unit, cmdf)); + + if (cmdf & SCP_UPD_MASK) + sc->sc_running |= cmdf | SCP_UPDATESUBCMD; + else + sc->sc_running |= cmdf; + + if ((cmdf & SCP_TIMOCHECK_CMD_MASK) && !sc->sc_timocheck) { + sc->ccs_timerh = timeout(ray_check_ccs, sc, RAY_CCS_TIMEOUT); + sc->sc_timocheck = 1; + } +} + +/* + * check to see if `cmdf' has been issued + */ +static int +ray_cmd_is_running(struct ray_softc *sc, int cmdf) +{ + RAY_DPRINTFN(5, ("ray%d: ray_cmd_is_running\n", sc->unit)); + RAY_MAP_CM(sc); + RAY_DPRINTFN(20, ("ray%d: ray_cmd_is_running 0x%x\n", sc->unit, cmdf)); + + return ((sc->sc_running & cmdf) ? 1 : 0); +} + +/* + * the given `cmdf' that was issued has completed + */ +static void +ray_cmd_done(struct ray_softc *sc, int cmdf) +{ + RAY_DPRINTFN(5, ("ray%d: ray_cmd_done\n", sc->unit)); + RAY_MAP_CM(sc); + RAY_DPRINTFN(20, ("ray%d: ray_cmd_done 0x%x\n", sc->unit, cmdf)); + + sc->sc_running &= ~cmdf; + if (cmdf & SCP_UPD_MASK) { + sc->sc_running &= ~SCP_UPDATESUBCMD; + if (sc->sc_scheduled & SCP_UPD_MASK) + ray_cmd_schedule(sc, sc->sc_scheduled & SCP_UPD_MASK); + } + if ((sc->sc_running & SCP_TIMOCHECK_CMD_MASK) == 0 && sc->sc_timocheck){ + untimeout(ray_check_ccs, sc, sc->ccs_timerh); + sc->sc_timocheck = 0; + } +} + +/* + * issue the command + * only used for commands not tx + */ +static int +ray_issue_cmd(struct ray_softc *sc, size_t ccs, u_int track) +{ + u_int i; + + RAY_DPRINTFN(5, ("ray%d: ray_cmd_issue\n", sc->unit)); + RAY_MAP_CM(sc); + + /* + * XXX other drivers did this, but I think + * what we really want to do is just make sure we don't + * get here or that spinning is ok + */ + i = 0; + while (!RAY_ECF_READY(sc)) + if (++i > 50) { + printf("\n"); + (void)ray_free_ccs(sc, ccs); + if (track) + ray_cmd_schedule(sc, track); + return (0); + } else if (i == 1) + printf("ray%d: ray_issue_cmd spinning", sc->unit); + else + printf("."); + + SRAM_WRITE_1(sc, RAY_SCB_CCSI, RAY_CCS_INDEX(ccs)); + RAY_ECF_START_CMD(sc); + ray_cmd_ran(sc, track); + + return (1); +} + +/* + * send a simple command if we can + */ +static int +ray_simple_cmd(struct ray_softc *sc, u_int cmd, u_int track) +{ + size_t ccs; + + RAY_DPRINTFN(5, ("ray%d: ray_simple_cmd\n", sc->unit)); + RAY_MAP_CM(sc); + + return (ray_alloc_ccs(sc, &ccs, cmd, track) && + ray_issue_cmd(sc, ccs, track)); +} + +/* + * Functions based on CCS commands + */ + +/* + * run a update subcommand + */ +static void +ray_update_subcmd(struct ray_softc *sc) +{ + struct ifnet *ifp; + int submask, i; + + RAY_DPRINTFN(5, ("ray%d: ray_update_subcmd\n", sc->unit)); + RAY_MAP_CM(sc); + + ray_cmd_cancel(sc, SCP_UPDATESUBCMD); + + ifp = &sc->arpcom.ac_if; + if ((ifp->if_flags & IFF_RUNNING) == 0) + return; + submask = SCP_UPD_FIRST; + for (i = 0; i < ray_nsubcmdtab; submask <<= 1, i++) { + if ((sc->sc_scheduled & SCP_UPD_MASK) == 0) + break; + /* when done the next command will be scheduled */ + if (ray_cmd_is_running(sc, SCP_UPDATESUBCMD)) + break; + if (!RAY_ECF_READY(sc)) + break; + /* + * give priority to LSB -- e.g., if previous loop reschuled + * doing this command after calling the function won't catch + * if a later command sets an earlier bit + */ + if (sc->sc_scheduled & ((submask - 1) & SCP_UPD_MASK)) + break; + if (sc->sc_scheduled & submask) + (*ray_subcmdtab[i])(sc); + } +} + +/* + * report a parameter + */ +static void +ray_report_params(struct ray_softc *sc) +{ + struct ifnet *ifp; + size_t ccs; + + RAY_DPRINTFN(5, ("ray%d: ray_report_params\n", sc->unit)); + RAY_MAP_CM(sc); + + ray_cmd_cancel(sc, SCP_REPORTPARAMS); + + ifp = &sc->arpcom.ac_if; + + if (!sc->sc_repreq) + return; + + /* do the issue check before equality check */ + if ((ifp->if_flags & IFF_RUNNING) == 0) + return; + else if (ray_cmd_is_running(sc, SCP_REPORTPARAMS)) { + ray_cmd_schedule(sc, SCP_REPORTPARAMS); + return; + } else if (!ray_alloc_ccs(sc, &ccs, RAY_CMD_REPORT_PARAMS, + SCP_REPORTPARAMS)) + return; + + SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_report, c_paramid, + sc->sc_repreq->r_paramid); + SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_report, c_nparam, 1); + (void)ray_issue_cmd(sc, ccs, SCP_REPORTPARAMS); +} + +/* + * start an association + */ +static void +ray_start_assoc(struct ray_softc *sc) +{ + struct ifnet *ifp; + + RAY_DPRINTFN(5, ("ray%d: ray_start_assoc\n", sc->unit)); + RAY_MAP_CM(sc); + + ifp = &sc->arpcom.ac_if; + + ray_cmd_cancel(sc, SCP_STARTASSOC); + if ((ifp->if_flags & IFF_RUNNING) == 0) + return; + else if (ray_cmd_is_running(sc, SCP_STARTASSOC)) + return; + (void)ray_simple_cmd(sc, RAY_CMD_START_ASSOC, SCP_STARTASSOC); +} + +/****************************************************************************** + * XXX NOT KNF FROM HERE DOWN * + ******************************************************************************/ +/* + * Subcommand functions that use the SCP_UPDATESUBCMD command + * (and are serialized with respect to other update sub commands + */ + /* * Download start up structures to card. * @@ -2047,9 +2816,11 @@ ray_download_params (sc) RAY_DPRINTFN(5, ("ray%d: Downloading startup parameters\n", sc->unit)); RAY_MAP_CM(sc); -#if XXX_TRACKING +#if XXX_DOWNLOAD_STD_TIMEOUT ray_cmd_cancel(sc, SCP_UPD_STARTUP); -#endif /* XXX_TRACKING */ +#else + /* XXX cancel timeouts ? */ +#endif /* XXX_DOWNLOAD_STD_TIMEOUT */ #define MIB4(m) ray_mib_4_default.##m #define MIB5(m) ray_mib_5_default.##m @@ -2060,7 +2831,7 @@ ray_download_params (sc) * Firmware version 4 defaults - see if_raymib.h for details */ MIB4(mib_net_type) = sc->sc_net_type; - MIB4(mib_ap_status) = RAY_MIB_AP_STATUS_DEFAULT; + MIB4(mib_ap_status) = sc->sc_ap_status; strncpy(MIB4(mib_ssid), sc->sc_ssid, RAY_MAXSSIDLEN); MIB4(mib_scan_mode) = RAY_MIB_SCAN_MODE_DEFAULT; MIB4(mib_apm_mode) = RAY_MIB_APM_MODE_DEFAULT; @@ -2106,7 +2877,7 @@ PUT2(MIB4(mib_uniq_word), RAY_MIB_UNIQ_WORD_DEFAULT); * Firmware version 5 defaults - see if_raymib.h for details */ MIB5(mib_net_type) = sc->sc_net_type; - MIB5(mib_ap_status) = RAY_MIB_AP_STATUS_DEFAULT; + MIB4(mib_ap_status) = sc->sc_ap_status; strncpy(MIB5(mib_ssid), sc->sc_ssid, RAY_MAXSSIDLEN); MIB5(mib_scan_mode) = RAY_MIB_SCAN_MODE_DEFAULT; MIB5(mib_apm_mode) = RAY_MIB_APM_MODE_DEFAULT; @@ -2171,18 +2942,26 @@ PUT2(MIB5(mib_cw_min), RAY_MIB_CW_MIN_V5); * command just gets serviced, so we use a timeout to complete the * sequence. */ - if (!ray_alloc_ccs(sc, &sc->sc_ccs, +#if XXX_DOWNLOAD_STD_TIMEOUT + if (!ray_simple_cmd(sc, RAY_CMD_START_PARAMS, SCP_UPD_STARTUP)) + printf("ray%d: ray_download_params can't issue command\n", sc->unit); +#else +/* XXX do we go back to using the std. timeout code? */ +/* XXX use ray_simple_cmd */ + if (!ray_alloc_ccs(sc, &sc->sc_startccs, RAY_CMD_START_PARAMS, SCP_UPD_STARTUP)) { printf("ray%d: ray_download_params can't get a CCS\n", sc->unit); ray_reset(sc); } - - if (!ray_issue_cmd(sc, sc->sc_ccs, SCP_UPD_STARTUP)) { + if (!ray_issue_cmd(sc, sc->sc_startccs, SCP_UPD_STARTUP)) { printf("ray%d: ray_download_params can't issue command\n", sc->unit); ray_reset(sc); } +/* XXX use ray_simple_cmd */ +/* XXX do we go back to using the std. timeout code? */ sc->timerh = timeout(ray_download_timo, sc, RAY_DOWNLOAD_TIMEOUT); +#endif /* XXX_DOWNLOAD_STD_TIMEOUT */ RAY_DPRINTFN(15, ("ray%d: Download now awaiting timeout\n", sc->unit)); return; @@ -2204,10 +2983,11 @@ ray_download_timo (xsc) RAY_DPRINTFN(5, ("ray%d: ray_download_timo\n", sc->unit)); RAY_MAP_CM(sc); - status = SRAM_READ_FIELD_1(sc, sc->sc_ccs, ray_cmd, c_status); - cmd = SRAM_READ_FIELD_1(sc, sc->sc_ccs, ray_cmd, c_cmd); + status = SRAM_READ_FIELD_1(sc, sc->sc_startccs, ray_cmd, c_status); + cmd = SRAM_READ_FIELD_1(sc, sc->sc_startccs, ray_cmd, c_cmd); RAY_DPRINTFN(20, ("ray%d: check rayidx %d ccs 0x%x cmd 0x%x status %d\n", - sc->unit, RAY_CCS_INDEX(sc->sc_ccs), sc->sc_ccs, cmd, status)); + sc->unit, RAY_CCS_INDEX(sc->sc_startccs), sc->sc_startccs, + cmd, status)); if ((cmd != RAY_CMD_START_PARAMS) || ((status != RAY_CCS_STATUS_FREE) && (status != RAY_CCS_STATUS_BUSY)) ) { @@ -2227,8 +3007,8 @@ ray_download_timo (xsc) } /* Clear the ccs */ - (void)ray_free_ccs(sc, sc->sc_ccs); - sc->sc_ccs = RAY_CCS_LAST + 1; + (void)ray_free_ccs(sc, sc->sc_startccs); + sc->sc_startccs = RAY_CCS_LAST + 1; /* * Grab a ccs and don't bother updating the network parameters. @@ -2263,6 +3043,83 @@ ray_download_timo (xsc) } /* + * start or join a network + */ +static void +ray_start_join_net(sc) + struct ray_softc *sc; +{ +#if XXX_NETBSD_SJ_NET + struct ray_net_params np; + struct ifnet *ifp; + size_t ccs; + int cmd; +#endif /* XXX_NETBSD_SJ_NET */ + + RAY_DPRINTFN(5, ("ray%d: ray_start_join_net\n", sc->unit)); + RAY_MAP_CM(sc); +#if XXX_NETBSD_SJ_NET + + ifp = &sc->arpcom.ac_if; + + ray_cmd_cancel(sc, SCP_UPD_STARTJOIN); + if ((ifp->if_flags & IFF_RUNNING) == 0) + return; + + /* XXX check we may not want to re-issue */ + if (ray_cmd_is_running(sc, SCP_UPDATESUBCMD)) { + ray_cmd_schedule(sc, SCP_UPD_STARTJOIN); + return; + } + + if (sc->sc_mode == SC_MODE_ADHOC) + cmd = RAY_CMD_START_NET; + else + cmd = RAY_CMD_JOIN_NET; + + if (!ray_alloc_ccs(sc, &ccs, cmd, SCP_UPD_STARTJOIN)) + return; + sc->sc_startccs = ccs; + sc->sc_startcmd = cmd; + if (!memcmp(sc->sc_cnwid, sc->sc_dnwid, sizeof(sc->sc_cnwid)) + && sc->sc_omode == sc->sc_mode) + SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_net, c_upd_param, 0); + else { + sc->sc_havenet = 0; + memset(&np, 0, sizeof(np)); + np.p_net_type = sc->sc_mode; + memcpy(np.p_ssid, sc->sc_dnwid, sizeof(np.p_ssid)); + ray_write_region(sc, RAY_HOST_TO_ECF_BASE, &np, sizeof(np)); + SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_net, c_upd_param, 1); + } + if (ray_issue_cmd(sc, ccs, SCP_UPD_STARTJOIN)) + timeout(ray_start_join_timo, sc, RAY_START_TIMEOUT); +#endif /* XXX_NETBSD_SJ_NET */ +} + +#if RAY_NEED_STARTJOIN_TIMO +/* + * Back stop catcher for start_join command. The NetBSD driver + * suggests that they need it to catch a bug in the firmware or the + * parameters they use - they are not sure. I'll just panic as I seem + * to get interrupts back fine and I have version 4 firmware. + */ +static void +ray_start_join_timo (xsc) + void *xsc; +{ + struct ray_softc *sc = xsc; + + RAY_DPRINTFN(5, ("ray%d: ray_start_join_timo\n", sc->unit)); + RAY_MAP_CM(sc); + + panic("ray%d: ray-start_join_timo occured\n", sc->unit); + + return; +} +#endif /* RAY_NEED_STARTJOIN_TIMO */ + +/* * Complete start or join command. * * Part of ray_init, download, start_join control flow. @@ -2285,9 +3142,11 @@ ray_start_join_done (sc, ccs, status) untimeout(ray_start_join_timo, sc, sc->sj_timerh); #endif /* RAY_NEED_STARTJOIN_TIMO */ -#if XXX_TRACKING +#if XXX_DOWNLOAD_STD_TIMEOUT ray_cmd_done(sc, SCP_UPD_STARTJOIN); -#endif /* XXX_TRACKING */ +#else + /* XXX cancel timeouts ? */ +#endif /* XXX_DOWNLOAD_STD_TIMEOUT */ /* * XXX This switch and the following test are badly done. I @@ -2336,7 +3195,7 @@ ray_start_join_done (sc, ccs, status) /* adjust values for buggy build 4 */ if (sc->sc_def_txrate == 0x55) - sc->sc_def_txrate = RAY_MIB_BASIC_RATE_SET_1500K; + sc->sc_def_txrate = RAY_MIB_BASIC_RATE_SET_2000K; if (sc->sc_encrypt == 0x55) sc->sc_encrypt = 0; @@ -2365,15 +3224,12 @@ ray_start_join_done (sc, ccs, status) * Just before we return from the interrupt context we check to * see if packets have been queued. */ -#if XXX_MCASTPROM + ray_cmd_schedule(sc, SCP_UPD_PROMISC); +#if XXX_MCAST ray_cmd_schedule(sc, SCP_UPD_MCAST|SCP_UPD_PROMISC); -#endif /* XXX_MCASTPROM */ +#endif /* XXX_MCAST */ if (SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_cmd) == RAY_CMD_JOIN_NET) -#if XXX_INFRA ray_start_assoc(sc); -#else - RAY_DPRINTFN(1, ("wanted to join a NET!\n")); -#endif /* XXX_INFRA */ else { sc->sc_havenet = 1; ifp->if_flags &= ~IFF_OACTIVE; @@ -2382,182 +3238,246 @@ ray_start_join_done (sc, ccs, status) return; } -#if RAY_NEED_STARTJOIN_TIMO +/****************************************************************************** + * XXX NOT KNF FROM HERE UP + ******************************************************************************/ + /* - * Back stop catcher for start_join command. The NetBSD driver - * suggests that they need it to catch a bug in the firmware or the - * parameters they use - they are not sure. I'll just panic as I seem - * to get interrupts back fine and I have version 4 firmware. + * set the card in/out of promiscuous mode */ static void -ray_start_join_timo (xsc) - void *xsc; +ray_update_promisc(struct ray_softc *sc) { - struct ray_softc *sc = xsc; - - RAY_DPRINTFN(5, ("ray%d: ray_start_join_timo\n", sc->unit)); - RAY_MAP_CM(sc); - - panic("ray%d: ray-start_join_timo occured\n", sc->unit); - - return; + struct ifnet *ifp; + size_t ccs; + int promisc; + + RAY_DPRINTFN(5, ("ray%d: ray_update_promisc\n", sc->unit)); + RAY_MAP_CM(sc); + + ifp = &sc->arpcom.ac_if; + ray_cmd_cancel(sc, SCP_UPD_PROMISC); + + /* do the issue check before equality check */ + promisc = !!(ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)); + if ((ifp->if_flags & IFF_RUNNING) == 0) + return; + else if (ray_cmd_is_running(sc, SCP_UPDATESUBCMD)) { + ray_cmd_schedule(sc, SCP_UPD_PROMISC); + return; + } else if (promisc == sc->sc_promisc) + return; + else if (!ray_alloc_ccs(sc,&ccs,RAY_CMD_UPDATE_PARAMS, SCP_UPD_PROMISC)) + return; + SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_update, c_paramid, RAY_MIB_PROMISC); + SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_update, c_nparam, 1); + SRAM_WRITE_1(sc, RAY_HOST_TO_ECF_BASE, promisc); + (void)ray_issue_cmd(sc, ccs, SCP_UPD_PROMISC); } -#endif /* RAY_NEED_STARTJOIN_TIMO */ /* - * Obtain a free ccs buffer. - * - * Returns 1 and in `ccsp' the bus offset of the free ccs - * or 0 if none are free - * - * If `track' is not zero, handles tracking this command - * possibly indicating a callback is needed and setting a timeout - * also if ECF isn't ready we terminate earlier to avoid overhead. - * - * This routine is only used for commands + * update the parameter based on what the user passed in */ -static int -ray_alloc_ccs (sc, ccsp, cmd, track) - struct ray_softc *sc; - size_t *ccsp; - u_int cmd, track; +static void +ray_update_params(struct ray_softc *sc) { - size_t ccs; - u_int i; + struct ifnet *ifp; + size_t ccs; - RAY_DPRINTFN(5, ("ray%d: ray_alloc_ccs\n", sc->unit)); - RAY_MAP_CM(sc); + RAY_DPRINTFN(5, ("ray%d: ray_update_params\n", sc->unit)); + RAY_MAP_CM(sc); -#if XXX_TRACKING - /* for tracked commands, if not ready just set pending */ - if (track && !RAY_ECF_READY(sc)) { - ray_cmd_schedule(sc, track); - return(0); - } -#endif /* XXX_TRACKING */ + ifp = &sc->arpcom.ac_if; - for (i = RAY_CCS_CMD_FIRST; i <= RAY_CCS_CMD_LAST; i++) { - /* probe here to make the card go */ - (void)SRAM_READ_FIELD_1(sc, RAY_CCS_ADDRESS(i), ray_cmd, c_status); - if (!sc->sc_ccsinuse[i]) - break; - } - if (i > RAY_CCS_CMD_LAST) { -#if XXX_TRACKING - if (track) - ray_cmd_schedule(sc, track); -#endif /* XXX_TRACKING */ - return(0); - } - sc->sc_ccsinuse[i] = 1; - ccs = RAY_CCS_ADDRESS(i); - SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_status, RAY_CCS_STATUS_BUSY); - SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_cmd, cmd); - SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_link, RAY_CCS_LINK_NULL); + ray_cmd_cancel(sc, SCP_UPD_UPDATEPARAMS); + if (!sc->sc_updreq) { + /* XXX do we need to wakeup here? */ + return; + } - *ccsp = ccs; - return(1); + /* do the issue check before equality check */ + if ((ifp->if_flags & IFF_RUNNING) == 0) + return; + else if (ray_cmd_is_running(sc, SCP_UPDATESUBCMD)) { + ray_cmd_schedule(sc, SCP_UPD_UPDATEPARAMS); + return; + } else if (!ray_alloc_ccs(sc, &ccs, RAY_CMD_UPDATE_PARAMS, + SCP_UPD_UPDATEPARAMS)) + return; + + SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_update, c_paramid, + sc->sc_updreq->r_paramid); + SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_update, c_nparam, 1); + ray_write_region(sc, RAY_HOST_TO_ECF_BASE, sc->sc_updreq->r_data, + sc->sc_updreq->r_len); + + (void)ray_issue_cmd(sc, ccs, SCP_UPD_UPDATEPARAMS); } /* - * Free up a ccs/cmd and return the old status. - * This routine is only used for commands. + * set the multicast filter list */ -static u_int8_t -ray_free_ccs (sc, ccs) - struct ray_softc *sc; - size_t ccs; +static void +ray_update_mcast(struct ray_softc *sc) { - u_int8_t status; +#if XXX_MCAST + size_t ccs; + struct ether_multistep step; + struct ether_multi *enm; + struct ethercom *ec; + size_t bufp; + int count; +#endif - RAY_DPRINTFN(5, ("ray%d: ray_free_ccs\n", sc->unit)); - RAY_MAP_CM(sc); + RAY_DPRINTFN(5, ("ray%d: ray_update_mcast\n", sc->unit)); + RAY_MAP_CM(sc); +#if XXX_MCAST + + ec = &sc->sc_ec; + ray_cmd_cancel(sc, SCP_UPD_MCAST); + + /* see if we have any ranges */ + if ((count = sc->sc_ec.ec_multicnt) < 17) { + ETHER_FIRST_MULTI(step, ec, enm); + while (enm) { + /* see if this is a range */ + if (memcmp(enm->enm_addrlo, enm->enm_addrhi, + ETHER_ADDR_LEN)) { + count = 17; + break; + } + ETHER_NEXT_MULTI(step, enm); + } + } - status = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_status); - RAY_CCS_FREE(sc, ccs); - if (ccs <= RAY_CCS_ADDRESS(RAY_CCS_LAST)) - sc->sc_ccsinuse[RAY_CCS_INDEX(ccs)] = 0; - RAY_DPRINTFN(20, ("ray%d: ray_free_ccs freed 0x%02x\n", - sc->unit, RAY_CCS_INDEX(ccs))); + /* track this stuff even when not running */ + if (count > 16) { + sc->sc_if.if_flags |= IFF_ALLMULTI; + ray_update_promisc(sc); + return; + } else if (sc->sc_if.if_flags & IFF_ALLMULTI) { + sc->sc_if.if_flags &= ~IFF_ALLMULTI; + ray_update_promisc(sc); + } - return(status); + if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) + return; + else if (ray_cmd_is_running(sc, SCP_UPDATESUBCMD)) { + ray_cmd_schedule(sc, SCP_UPD_MCAST); + return; + } else if (!ray_alloc_ccs(sc,&ccs, RAY_CMD_UPDATE_MCAST, SCP_UPD_MCAST)) + return; + SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_update_mcast, c_nmcast, count); + bufp = RAY_HOST_TO_ECF_BASE; + ETHER_FIRST_MULTI(step, ec, enm); + while (enm) { + ray_write_region(sc, bufp, enm->enm_addrlo, ETHER_ADDR_LEN); + bufp += ETHER_ADDR_LEN; + ETHER_NEXT_MULTI(step, enm); + } + (void)ray_issue_cmd(sc, ccs, SCP_UPD_MCAST); +#endif XXX_MCAST } /* - * Issue a command by writing the mailbox and tickling the card. - * Only used for commands not transmitted packets. + * User issued commands + */ + +/* + * issue a update params + * + * expected to be called in sleapable context -- intended for user stuff */ static int -ray_issue_cmd(sc, ccs, track) - struct ray_softc *sc; - size_t ccs; - u_int track; +ray_user_update_params(struct ray_softc *sc, struct ray_param_req *pr) { - u_int i; + struct ifnet *ifp; + int rv; - RAY_DPRINTFN(5, ("ray%d: ray_cmd_issue\n", sc->unit)); - RAY_MAP_CM(sc); + RAY_DPRINTFN(5, ("ray%d: ray_user_update_params\n", sc->unit)); + RAY_MAP_CM(sc); - /* - * XXX other drivers did this, but I think - * what we really want to do is just make sure we don't - * get here or that spinning is ok - */ - i = 0; - while (!RAY_ECF_READY(sc)) - if (++i > 50) { - printf("\n"); - (void)ray_free_ccs(sc, ccs); -#if XXX_TRACKING - if (track) - ray_cmd_schedule(sc, track); -#endif /* XXX_TRACKING */ - return(0); - } else if (i == 1) - printf("ray%d: ray_issue_cmd spinning", sc->unit); - else - printf("."); + ifp = &sc->arpcom.ac_if; - SRAM_WRITE_1(sc, RAY_SCB_CCSI, RAY_CCS_INDEX(ccs)); - RAY_ECF_START_CMD(sc); -#if XXX_TRACKING - ray_cmd_ran(sc, track); -#endif /* XXX_TRACKING */ + if ((ifp->if_flags & IFF_RUNNING) == 0) { + pr->r_failcause = RAY_FAILCAUSE_EDEVSTOP; + return (EIO); + } - return(1); + /* wait to be able to issue the command */ + rv = 0; + while (ray_cmd_is_running(sc, SCP_UPD_UPDATEPARAMS) || + ray_cmd_is_scheduled(sc, SCP_UPD_UPDATEPARAMS)) { + rv = tsleep(ray_update_params, 0|PCATCH, "cmd in use", 0); + if (rv) + return (rv); + if ((ifp->if_flags & IFF_RUNNING) == 0) { + pr->r_failcause = RAY_FAILCAUSE_EDEVSTOP; + return (EIO); + } + } + + pr->r_failcause = RAY_FAILCAUSE_WAITING; + sc->sc_updreq = pr; + ray_cmd_schedule(sc, SCP_UPD_UPDATEPARAMS); + ray_check_scheduled(sc); + + while (pr->r_failcause == RAY_FAILCAUSE_WAITING) + (void)tsleep(ray_update_params, 0, "waiting cmd", 0); + wakeup(ray_update_params); + + return (0); } -#if RAY_DEBUG > 50 -static void -ray_dump_mbuf(sc, m, s) - struct ray_softc *sc; - struct mbuf *m; - char *s; +/* + * issue a report params + * + * expected to be called in sleapable context -- intended for user stuff + */ +static int +ray_user_report_params(struct ray_softc *sc, struct ray_param_req *pr) { - u_int8_t *d, *ed; - u_int i; - char p[17]; + struct ifnet *ifp; + int rv; - printf("ray%d: %s mbuf dump:", sc->unit, s); - i = 0; - bzero(p, 17); - for (; m; m = m->m_next) { - d = mtod(m, u_int8_t *); - ed = d + m->m_len; + RAY_DPRINTFN(5, ("ray%d: ray_user_report_params\n", sc->unit)); + RAY_MAP_CM(sc); - for (; d < ed; i++, d++) { - if ((i % 16) == 0) { - printf(" %s\n\t", p); - } else if ((i % 8) == 0) - printf(" "); - printf(" %02x", *d); - p[i % 16] = ((*d >= 0x20) && (*d < 0x80)) ? *d : '.'; + ifp = &sc->arpcom.ac_if; + + if ((ifp->if_flags & IFF_RUNNING) == 0) { + pr->r_failcause = RAY_FAILCAUSE_EDEVSTOP; + return (EIO); } - } - if ((i - 1) % 16) - printf("%s\n", p); + + /* wait to be able to issue the command */ + rv = 0; + while (ray_cmd_is_running(sc, SCP_REPORTPARAMS) + || ray_cmd_is_scheduled(sc, SCP_REPORTPARAMS)) { + rv = tsleep(ray_report_params, 0|PCATCH, "cmd in use", 0); + if (rv) + return (rv); + if ((ifp->if_flags & IFF_RUNNING) == 0) { + pr->r_failcause = RAY_FAILCAUSE_EDEVSTOP; + return (EIO); + } + } + + pr->r_failcause = RAY_FAILCAUSE_WAITING; + sc->sc_repreq = pr; + ray_cmd_schedule(sc, SCP_REPORTPARAMS); + ray_check_scheduled(sc); + + while (pr->r_failcause == RAY_FAILCAUSE_WAITING) + (void)tsleep(ray_report_params, 0, "waiting cmd", 0); + wakeup(ray_report_params); + + return (0); } -#endif /* RAY_DEBUG > 50 */ + +/****************************************************************************** + * XXX NOT KNF FROM HERE DOWN + ******************************************************************************/ /* * Routines to read from/write to the attribute memory. @@ -2646,7 +3566,7 @@ ray_attr_write (struct ray_softc *sc, off_t offset, u_int8_t byte) ray_attr_cm(sc); #endif /* RAY_NEED_CM_REMAPPING */ - return(err); + return (err); } static int @@ -2673,7 +3593,7 @@ ray_attr_read (struct ray_softc *sc, off_t offset, u_int8_t *buf, int size) ray_attr_cm(sc); #endif /* RAY_NEED_CM_REMAPPING */ - return(err); + return (err); } static u_int8_t @@ -2685,7 +3605,40 @@ ray_read_reg (sc, reg) ray_attr_read(sc, reg, &byte, 1); - return(byte); + return (byte); } +#if RAY_DEBUG > 50 +static void +ray_dump_mbuf(sc, m, s) + struct ray_softc *sc; + struct mbuf *m; + char *s; +{ + u_int8_t *d, *ed; + u_int i; + char p[17]; + + printf("ray%d: %s mbuf dump:", sc->unit, s); + i = 0; + bzero(p, 17); + for (; m; m = m->m_next) { + d = mtod(m, u_int8_t *); + ed = d + m->m_len; + + for (; d < ed; i++, d++) { + if ((i % 16) == 0) { + printf(" %s\n\t", p); + } else if ((i % 8) == 0) + printf(" "); + printf(" %02x", *d); + p[i % 16] = ((*d >= 0x20) && (*d < 0x80)) ? *d : '.'; + } + } + if ((i - 1) % 16) + printf("%s\n", p); +} +#endif /* RAY_DEBUG > 50 */ + + #endif /* NRAY */
\ No newline at end of file |