summaryrefslogtreecommitdiffstats
path: root/drivers/net/eql.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/eql.c')
-rw-r--r--drivers/net/eql.c1153
1 files changed, 1153 insertions, 0 deletions
diff --git a/drivers/net/eql.c b/drivers/net/eql.c
new file mode 100644
index 000000000..c11876cdb
--- /dev/null
+++ b/drivers/net/eql.c
@@ -0,0 +1,1153 @@
+/*
+ * Equalizer Load-balancer for serial network interfaces.
+ *
+ * (c) Copyright 1995 Simon "Guru Aleph-Null" Janes
+ * NCM: Network and Communications Mangement, Inc.
+ *
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License, incorporated herein by reference.
+ *
+ * The author may be reached as simon@ncm.com, or C/O
+ * NCM
+ * Attn: Simon Janes
+ * 6803 Whittier Ave
+ * McLean VA 22101
+ * Phone: 1-703-847-0040 ext 103
+ */
+
+static char *version =
+ "Equalizer: $Revision: 3.12 $ $Date: 1995/01/19 $ Simon Janes (simon@ncm.com)\n";
+
+#include <linux/config.h>
+
+/*
+ * Sources:
+ * skeleton.c by Donald Becker.
+ * Inspirations:
+ * The Harried and Overworked Alan Cox
+ * Conspiracies:
+ * The Alan Cox and Arisian plot to get someone else to do the code, which
+ * turned out to be me.
+ */
+
+/*
+ * $Log: eql.c,v $
+ * Revision 3.12 1995/03/22 21:07:51 anarchy
+ * Added suser() checks on configuration.
+ * Moved header file.
+ *
+ * Revision 3.11 1995/01/19 23:14:31 guru
+ * slave_load = (ULONG_MAX - (ULONG_MAX / 2)) -
+ * (priority_Bps) + bytes_queued * 8;
+ *
+ * Revision 3.10 1995/01/19 23:07:53 guru
+ * back to
+ * slave_load = (ULONG_MAX - (ULONG_MAX / 2)) -
+ * (priority_Bps) + bytes_queued;
+ *
+ * Revision 3.9 1995/01/19 22:38:20 guru
+ * slave_load = (ULONG_MAX - (ULONG_MAX / 2)) -
+ * (priority_Bps) + bytes_queued * 4;
+ *
+ * Revision 3.8 1995/01/19 22:30:55 guru
+ * slave_load = (ULONG_MAX - (ULONG_MAX / 2)) -
+ * (priority_Bps) + bytes_queued * 2;
+ *
+ * Revision 3.7 1995/01/19 21:52:35 guru
+ * printk's trimmed out.
+ *
+ * Revision 3.6 1995/01/19 21:49:56 guru
+ * This is working pretty well. I gained 1 K/s in speed.. now its just
+ * robustness and printk's to be diked out.
+ *
+ * Revision 3.5 1995/01/18 22:29:59 guru
+ * still crashes the kernel when the lock_wait thing is woken up.
+ *
+ * Revision 3.4 1995/01/18 21:59:47 guru
+ * Broken set-bit locking snapshot
+ *
+ * Revision 3.3 1995/01/17 22:09:18 guru
+ * infinite sleep in a lock somewhere..
+ *
+ * Revision 3.2 1995/01/15 16:46:06 guru
+ * Log trimmed of non-pertinant 1.x branch messages
+ *
+ * Revision 3.1 1995/01/15 14:41:45 guru
+ * New Scheduler and timer stuff...
+ *
+ * Revision 1.15 1995/01/15 14:29:02 guru
+ * Will make 1.14 (now 1.15) the 3.0 branch, and the 1.12 the 2.0 branch, the one
+ * with the dumber scheduler
+ *
+ * Revision 1.14 1995/01/15 02:37:08 guru
+ * shock.. the kept-new-versions could have zonked working
+ * stuff.. shudder
+ *
+ * Revision 1.13 1995/01/15 02:36:31 guru
+ * big changes
+ *
+ * scheduler was torn out and replaced with something smarter
+ *
+ * global names not prefixed with eql_ were renamed to protect
+ * against namespace collisions
+ *
+ * a few more abstract interfaces were added to facilitate any
+ * potential change of datastructure. the driver is still using
+ * a linked list of slaves. going to a heap would be a bit of
+ * an overkill.
+ *
+ * this compiles fine with no warnings.
+ *
+ * the locking mechanism and timer stuff must be written however,
+ * this version will not work otherwise
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/timer.h>
+
+#include <linux/if_eql.h>
+
+#ifndef EQL_DEBUG
+/* #undef EQL_DEBUG -* print nothing at all, not even a boot-banner */
+/* #define EQL_DEBUG 1 -* print only the boot-banner */
+/* #define EQL_DEBUG 5 -* print major function entries */
+/* #define EQL_DEBUG 20 -* print subfunction entries */
+/* #define EQL_DEBUG 50 -* print utility entries */
+/* #define EQL_DEBUG 100 -* print voluminous function entries */
+#define EQL_DEBUG 1
+#endif
+static unsigned int eql_debug = EQL_DEBUG;
+
+int eql_init(struct device *dev); /* */
+static int eql_open(struct device *dev); /* */
+static int eql_close(struct device *dev); /* */
+static int eql_ioctl(struct device *dev, struct ifreq *ifr, int cmd); /* */
+static int eql_slave_xmit(struct sk_buff *skb, struct device *dev); /* */
+
+static struct enet_statistics *eql_get_stats(struct device *dev); /* */
+static int eql_header(unsigned char *buff, struct device *dev,
+ unsigned short type, void *daddr, void *saddr,
+ unsigned len, struct sk_buff *skb); /* */
+static int eql_rebuild_header(void *buff, struct device *dev,
+ unsigned long raddr, struct sk_buff *skb); /* */
+static unsigned short eql_type_trans (struct sk_buff *skb,
+ struct device *dev); /* */
+
+/* ioctl() handlers
+ ---------------- */
+static int eql_enslave(struct device *dev, slaving_request_t *srq); /* */
+static int eql_emancipate(struct device *dev, slaving_request_t *srq); /* */
+
+static int eql_g_slave_cfg(struct device *dev, slave_config_t *sc); /* */
+static int eql_s_slave_cfg(struct device *dev, slave_config_t *sc); /* */
+
+static int eql_g_master_cfg(struct device *dev, master_config_t *mc); /* */
+static int eql_s_master_cfg(struct device *dev, master_config_t *mc); /* */
+
+static inline int eql_is_slave(struct device *dev); /* */
+static inline int eql_is_master(struct device *dev); /* */
+
+static slave_t *eql_new_slave(void); /* */
+static void eql_delete_slave(slave_t *slave); /* */
+
+/* static long eql_slave_priority(slave_t *slave); -* */
+static inline int eql_number_slaves(slave_queue_t *queue); /* */
+
+static inline int eql_is_empty(slave_queue_t *queue); /* */
+static inline int eql_is_full(slave_queue_t *queue); /* */
+
+static slave_queue_t *eql_new_slave_queue(struct device *dev); /* */
+static void eql_delete_slave_queue(slave_queue_t *queue); /* */
+
+static int eql_insert_slave(slave_queue_t *queue, slave_t *slave); /* */
+static slave_t *eql_remove_slave(slave_queue_t *queue, slave_t *slave); /* */
+
+/* static int eql_insert_slave_dev(slave_queue_t *queue, struct device *dev); -* */
+static int eql_remove_slave_dev(slave_queue_t *queue, struct device *dev); /* */
+
+static inline struct device *eql_best_slave_dev(slave_queue_t *queue); /* */
+static inline slave_t *eql_best_slave(slave_queue_t *queue); /* */
+static inline slave_t *eql_first_slave(slave_queue_t *queue); /* */
+static inline slave_t *eql_next_slave(slave_queue_t *queue, slave_t *slave); /* */
+
+static inline void eql_set_best_slave(slave_queue_t *queue, slave_t *slave); /* */
+static inline void eql_schedule_slaves(slave_queue_t *queue); /* */
+
+static slave_t *eql_find_slave_dev(slave_queue_t *queue, struct device *dev); /* */
+
+/* static inline eql_lock_slave_queue(slave_queue_t *queue); -* */
+/* static inline eql_unlock_slave_queue(slave_queue_t *queue); -* */
+
+static void eql_timer(unsigned long param); /* */
+
+/* struct device * interface functions
+ ---------------------------------------------------------
+ */
+
+int
+eql_init(struct device *dev)
+{
+ static unsigned version_printed = 0;
+ /* static unsigned num_masters = 0; */
+ equalizer_t *eql = 0;
+ int i;
+
+ if ( version_printed++ == 0 && eql_debug > 0)
+ printk(version);
+
+ /* Initialize the device structure. */
+ dev->priv = kmalloc (sizeof (equalizer_t), GFP_KERNEL);
+ memset (dev->priv, 0, sizeof (equalizer_t));
+ eql = (equalizer_t *) dev->priv;
+
+ eql->stats = kmalloc (sizeof (struct enet_statistics), GFP_KERNEL);
+ memset (eql->stats, 0, sizeof (struct enet_statistics));
+
+ init_timer (&eql->timer);
+ eql->timer.data = (unsigned long) dev->priv;
+ eql->timer.expires = EQL_DEFAULT_RESCHED_IVAL;
+ eql->timer.function = &eql_timer;
+ eql->timer_on = 0;
+
+ dev->open = eql_open;
+ dev->stop = eql_close;
+ dev->do_ioctl = eql_ioctl;
+ dev->hard_start_xmit = eql_slave_xmit;
+ dev->get_stats = eql_get_stats;
+
+ /* Fill in the fields of the device structure with ethernet-generic values.
+ This should be in a common file instead of per-driver. */
+
+ for (i = 0; i < DEV_NUMBUFFS; i++)
+ skb_queue_head_init(&dev->buffs[i]);
+
+ dev->hard_header = eql_header;
+ dev->rebuild_header = eql_rebuild_header;
+
+ /* now we undo some of the things that eth_setup does that we don't like */
+ dev->mtu = EQL_DEFAULT_MTU; /* set to 576 in eql.h */
+ dev->flags = IFF_MASTER;
+
+ dev->family = AF_INET;
+ dev->pa_addr = 0;
+ dev->pa_brdaddr = 0;
+ dev->pa_mask = 0;
+ dev->pa_alen = sizeof (unsigned long);
+
+ dev->type = ARPHRD_SLIP;
+
+ return 0;
+}
+
+
+static
+int
+eql_open(struct device *dev)
+{
+ equalizer_t *eql = (equalizer_t *) dev->priv;
+ slave_queue_t *new_queue;
+
+#ifdef EQL_DEBUG
+ if (eql_debug >= 5)
+ printk ("%s: open\n", dev->name);
+#endif
+
+ new_queue = eql_new_slave_queue (dev);
+
+ if (new_queue != 0)
+ {
+ new_queue->master_dev = dev;
+ eql->queue = new_queue;
+ eql->queue->lock = 0;
+ eql->min_slaves = 1;
+ eql->max_slaves = EQL_DEFAULT_MAX_SLAVES; /* 4 usually... */
+
+ printk ("%s: adding timer\n", dev->name);
+ eql->timer_on = 1;
+ add_timer (&eql->timer);
+
+ return 0;
+ }
+ return 1;
+}
+
+
+static
+int
+eql_close(struct device *dev)
+{
+ equalizer_t *eql = (equalizer_t *) dev->priv;
+
+#ifdef EQL_DEBUG
+ if ( eql_debug >= 5)
+ printk ("%s: close\n", dev->name);
+#endif
+ /* The timer has to be stopped first before we start hacking away
+ at the data structure it scans every so often... */
+ printk ("%s: stopping timer\n", dev->name);
+ eql->timer_on = 0;
+ del_timer (&eql->timer);
+
+ eql_delete_slave_queue (eql->queue);
+
+ return 0;
+}
+
+
+static
+int
+eql_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+ if(!suser() && cmd!=EQL_GETMASTRCFG && cmd!=EQL_GETSLAVECFG)
+ return -EPERM;
+ switch (cmd)
+ {
+ case EQL_ENSLAVE:
+ return eql_enslave (dev, (slaving_request_t *) ifr->ifr_data);
+ case EQL_EMANCIPATE:
+ return eql_emancipate (dev, (slaving_request_t *) ifr->ifr_data);
+
+ case EQL_GETSLAVECFG:
+ return eql_g_slave_cfg (dev, (slave_config_t *) ifr->ifr_data);
+ case EQL_SETSLAVECFG:
+ return eql_s_slave_cfg (dev, (slave_config_t *) ifr->ifr_data);
+
+ case EQL_GETMASTRCFG:
+ return eql_g_master_cfg (dev, (master_config_t *) ifr->ifr_data);
+ case EQL_SETMASTRCFG:
+ return eql_s_master_cfg (dev, (master_config_t *) ifr->ifr_data);
+
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+
+static
+int
+eql_slave_xmit(struct sk_buff *skb, struct device *dev)
+{
+ equalizer_t *eql = (equalizer_t *) dev->priv;
+ struct device *slave_dev = 0;
+ slave_t *slave;
+
+ if (skb == NULL)
+ {
+ return 0;
+ }
+
+ eql_schedule_slaves (eql->queue);
+
+ slave_dev = eql_best_slave_dev (eql->queue);
+ slave = eql_best_slave (eql->queue);
+
+ if ( slave_dev != 0 )
+ {
+#ifdef EQL_DEBUG
+ if (eql_debug >= 100)
+ printk ("%s: %d slaves xmitng %ld B %s\n",
+ dev->name, eql_number_slaves (eql->queue), skb->len,
+ slave_dev->name);
+#endif
+
+ dev_queue_xmit (skb, slave_dev, 1);
+ eql->stats->tx_packets++;
+ slave->bytes_queued += skb->len;
+ }
+ else
+ {
+ /* The alternative for this is the return 1 and have
+ dev_queue_xmit just queue it up on the eql's queue. */
+
+ eql->stats->tx_dropped++;
+ dev_kfree_skb(skb, FREE_WRITE);
+ }
+ return 0;
+}
+
+
+static
+struct enet_statistics *
+eql_get_stats(struct device *dev)
+{
+ equalizer_t *eql = (equalizer_t *) dev->priv;
+
+ return eql->stats;
+}
+
+
+static
+int
+eql_header(unsigned char *buff, struct device *dev,
+ unsigned short type, void *daddr, void *saddr,
+ unsigned len, struct sk_buff *skb)
+{
+ return 0;
+}
+
+
+static
+int
+eql_rebuild_header(void *buff, struct device *dev,
+ unsigned long raddr, struct sk_buff *skb)
+{
+ return 0;
+}
+
+
+static
+unsigned short
+eql_type_trans (struct sk_buff *skb, struct device *dev)
+{
+ return htons (ETH_P_IP);
+}
+
+
+/* private ioctl functions
+ -----------------------------------------------------------------
+ */
+
+static int
+eql_enslave(struct device *dev, slaving_request_t *srqp)
+{
+ struct device *master_dev;
+ struct device *slave_dev;
+ slaving_request_t srq;
+
+ memcpy_fromfs (&srq, srqp, sizeof (slaving_request_t));
+
+#ifdef EQL_DEBUG
+ if (eql_debug >= 20)
+ printk ("%s: enslave '%s' %ld bps\n", dev->name,
+ srq.slave_name, srq.priority);
+#endif
+
+ master_dev = dev; /* for "clarity" */
+ slave_dev = dev_get (srq.slave_name);
+
+ if (master_dev != 0 && slave_dev != 0)
+ {
+ if (! eql_is_master (slave_dev) && /* slave is not a master */
+ ! eql_is_slave (slave_dev) ) /* slave is not already a slave */
+ {
+ slave_t *s = eql_new_slave ();
+ equalizer_t *eql = (equalizer_t *) master_dev->priv;
+
+ s->dev = slave_dev;
+ s->priority = srq.priority;
+ s->priority_bps = srq.priority;
+ s->priority_Bps = srq.priority / 8;
+
+ slave_dev->flags |= IFF_SLAVE;
+
+ eql_insert_slave (eql->queue, s);
+
+ return 0;
+ }
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
+
+
+static
+int
+eql_emancipate(struct device *dev, slaving_request_t *srqp)
+{
+ struct device *master_dev;
+ struct device *slave_dev;
+ slaving_request_t srq;
+
+ memcpy_fromfs (&srq, srqp, sizeof (slaving_request_t));
+
+#ifdef EQL_DEBUG
+ if (eql_debug >= 20)
+ printk ("%s: emancipate `%s`\n", dev->name, srq.slave_name);
+#endif
+
+
+ master_dev = dev; /* for "clarity" */
+ slave_dev = dev_get (srq.slave_name);
+
+ if ( eql_is_slave (slave_dev) ) /* really is a slave */
+ {
+ equalizer_t *eql = (equalizer_t *) master_dev->priv;
+ slave_dev->flags = slave_dev->flags & ~IFF_SLAVE;
+
+ eql_remove_slave_dev (eql->queue, slave_dev);
+
+ return 0;
+ }
+ return -EINVAL;
+}
+
+
+static
+int
+eql_g_slave_cfg(struct device *dev, slave_config_t *scp)
+{
+ slave_t *slave;
+ equalizer_t *eql;
+ struct device *slave_dev;
+ slave_config_t sc;
+
+ memcpy_fromfs (&sc, scp, sizeof (slave_config_t));
+
+#ifdef EQL_DEBUG
+ if (eql_debug >= 20)
+ printk ("%s: get config for slave `%s'\n", dev->name, sc.slave_name);
+#endif
+
+ eql = (equalizer_t *) dev->priv;
+ slave_dev = dev_get (sc.slave_name);
+
+ if ( eql_is_slave (slave_dev) )
+ {
+ slave = eql_find_slave_dev (eql->queue, slave_dev);
+ if (slave != 0)
+ {
+ sc.priority = slave->priority;
+ memcpy_tofs (scp, &sc, sizeof (slave_config_t));
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+
+static
+int
+eql_s_slave_cfg(struct device *dev, slave_config_t *scp)
+{
+ slave_t *slave;
+ equalizer_t *eql;
+ struct device *slave_dev;
+ slave_config_t sc;
+
+#ifdef EQL_DEBUG
+ if (eql_debug >= 20)
+ printk ("%s: set config for slave `%s'\n", dev->name, sc.slave_name);
+#endif
+
+ memcpy_fromfs (&sc, scp, sizeof (slave_config_t));
+
+ eql = (equalizer_t *) dev->priv;
+ slave_dev = dev_get (sc.slave_name);
+
+ if ( eql_is_slave (slave_dev) )
+ {
+ slave = eql_find_slave_dev (eql->queue, slave_dev);
+ if (slave != 0)
+ {
+ slave->priority = sc.priority;
+ slave->priority_bps = sc.priority;
+ slave->priority_Bps = sc.priority / 8;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+
+static
+int
+eql_g_master_cfg(struct device *dev, master_config_t *mcp)
+{
+ equalizer_t *eql;
+ master_config_t mc;
+
+#if EQL_DEBUG
+ if (eql_debug >= 20)
+ printk ("%s: get master config\n", dev->name);
+#endif
+
+ if ( eql_is_master (dev) )
+ {
+ eql = (equalizer_t *) dev->priv;
+ mc.max_slaves = eql->max_slaves;
+ mc.min_slaves = eql->min_slaves;
+ memcpy_tofs (mcp, &mc, sizeof (master_config_t));
+ return 0;
+ }
+ return -EINVAL;
+}
+
+
+static
+int
+eql_s_master_cfg(struct device *dev, master_config_t *mcp)
+{
+ equalizer_t *eql;
+ master_config_t mc;
+
+#if EQL_DEBUG
+ if (eql_debug >= 20)
+ printk ("%s: set master config\n", dev->name);
+#endif
+
+ memcpy_fromfs (&mc, mcp, sizeof (master_config_t));
+
+ if ( eql_is_master (dev) )
+ {
+ eql = (equalizer_t *) dev->priv;
+ eql->max_slaves = mc.max_slaves;
+ eql->min_slaves = mc.min_slaves;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/* private device support functions
+ ------------------------------------------------------------------
+ */
+
+static inline
+int
+eql_is_slave(struct device *dev)
+{
+ if (dev)
+ {
+ if ((dev->flags & IFF_SLAVE) == IFF_SLAVE)
+ return 1;
+ }
+ return 0;
+}
+
+
+static inline
+int
+eql_is_master(struct device *dev)
+{
+ if (dev)
+ {
+ if ((dev->flags & IFF_MASTER) == IFF_MASTER)
+ return 1;
+ }
+ return 0;
+}
+
+
+static
+slave_t *
+eql_new_slave(void)
+{
+ slave_t *slave;
+
+ slave = (slave_t *) kmalloc (sizeof (slave_t), GFP_KERNEL);
+ if (slave)
+ {
+ memset(slave, 0, sizeof (slave_t));
+ return slave;
+ }
+ return 0;
+}
+
+
+static
+void
+eql_delete_slave(slave_t *slave)
+{
+ kfree (slave);
+}
+
+
+#if 0 /* not currently used, will be used
+ when we realy use a priority queue */
+static
+long
+slave_Bps(slave_t *slave)
+{
+ return (slave->priority_Bps);
+}
+
+static
+long
+slave_bps(slave_t *slave)
+{
+ return (slave->priority_bps);
+}
+#endif
+
+
+static inline
+int
+eql_number_slaves(slave_queue_t *queue)
+{
+ return queue->num_slaves;
+}
+
+
+static inline
+int
+eql_is_empty(slave_queue_t *queue)
+{
+ if (eql_number_slaves (queue) == 0)
+ return 1;
+ return 0;
+}
+
+
+static inline
+int
+eql_is_full(slave_queue_t *queue)
+{
+ equalizer_t *eql = (equalizer_t *) queue->master_dev->priv;
+
+ if (eql_number_slaves (queue) == eql->max_slaves)
+ return 1;
+ return 0;
+}
+
+
+static
+slave_queue_t *
+eql_new_slave_queue(struct device *dev)
+{
+ slave_queue_t *queue;
+ slave_t *head_slave;
+ slave_t *tail_slave;
+
+ queue = (slave_queue_t *) kmalloc (sizeof (slave_queue_t), GFP_KERNEL);
+ memset (queue, 0, sizeof (slave_queue_t));
+
+ head_slave = eql_new_slave ();
+ tail_slave = eql_new_slave ();
+
+ if ( head_slave != 0 &&
+ tail_slave != 0 )
+ {
+ head_slave->next = tail_slave;
+ tail_slave->next = 0;
+ queue->head = head_slave;
+ queue->num_slaves = 0;
+ queue->master_dev = dev;
+ }
+ else
+ {
+ kfree (queue);
+ return 0;
+ }
+ return queue;
+}
+
+
+static
+void
+eql_delete_slave_queue(slave_queue_t *queue)
+{
+ slave_t *zapped;
+
+ /* this should only be called when there isn't a timer running that scans
+ the data periodicaly.. dev_close stops the timer... */
+
+ while ( ! eql_is_empty (queue) )
+ {
+ zapped = eql_remove_slave (queue, queue->head->next);
+ eql_delete_slave (zapped);
+ }
+ kfree (queue->head->next);
+ kfree (queue->head);
+ kfree (queue);
+}
+
+
+static
+int
+eql_insert_slave(slave_queue_t *queue, slave_t *slave)
+{
+ cli ();
+
+ if ( ! eql_is_full (queue) )
+ {
+ slave_t *duplicate_slave = 0;
+
+ duplicate_slave = eql_find_slave_dev (queue, slave->dev);
+
+ if (duplicate_slave != 0)
+ {
+/* printk ("%s: found a duplicate, killing it and replacing\n",
+ queue->master_dev->name); */
+ eql_delete_slave (eql_remove_slave (queue, duplicate_slave));
+ }
+
+ slave->next = queue->head->next;
+ queue->head->next = slave;
+ queue->num_slaves++;
+ sti ();
+ return 0;
+ }
+
+ sti ();
+
+ return 1;
+}
+
+
+static
+slave_t *
+eql_remove_slave(slave_queue_t *queue, slave_t *slave)
+{
+ slave_t *prev;
+ slave_t *current;
+
+ cli ();
+
+ prev = queue->head;
+ current = queue->head->next;
+ while (current != slave &&
+ current->dev != 0 )
+ {
+/* printk ("%s: remove_slave; searching...\n", queue->master_dev->name); */
+ prev = current;
+ current = current->next;
+ }
+
+ if (current == slave)
+ {
+ prev->next = current->next;
+ queue->num_slaves--;
+ return current;
+ }
+
+ sti ();
+
+ return 0; /* not found */
+}
+
+
+#if 0
+static
+int
+eql_insert_slave_dev(slave_queue_t *queue, struct device *dev)
+{
+ slave_t *slave;
+
+ cli ();
+
+ if ( ! eql_is_full (queue) )
+ {
+ slave = eql_new_slave ();
+ slave->dev = dev;
+ slave->priority = EQL_DEFAULT_SLAVE_PRIORITY;
+ slave->priority_bps = EQL_DEFAULT_SLAVE_PRIORITY;
+ slave->priority_Bps = EQL_DEFAULT_SLAVE_PRIORITY / 8;
+ slave->next = queue->head->next;
+ queue->head->next = slave;
+ sti ();
+ return 0;
+ }
+ sti ();
+ return 1;
+}
+#endif
+
+
+static
+int
+eql_remove_slave_dev(slave_queue_t *queue, struct device *dev)
+{
+ slave_t *prev;
+ slave_t *current;
+ slave_t *target;
+
+ target = eql_find_slave_dev (queue, dev);
+
+ if (target != 0)
+ {
+ cli ();
+
+ prev = queue->head;
+ current = prev->next;
+ while (current != target)
+ {
+ prev = current;
+ current = current->next;
+ }
+ prev->next = current->next;
+ queue->num_slaves--;
+
+ sti ();
+
+ eql_delete_slave (current);
+ return 0;
+ }
+ return 1;
+}
+
+
+static inline
+struct device *
+eql_best_slave_dev(slave_queue_t *queue)
+{
+ if (queue->best_slave != 0)
+ {
+ if (queue->best_slave->dev != 0)
+ return queue->best_slave->dev;
+ else
+ return 0;
+ }
+ else
+ return 0;
+}
+
+
+static inline
+slave_t *
+eql_best_slave(slave_queue_t *queue)
+{
+ return queue->best_slave;
+}
+
+static inline
+void
+eql_schedule_slaves(slave_queue_t *queue)
+{
+ struct device *master_dev = queue->master_dev;
+ slave_t *best_slave = 0;
+ slave_t *slave_corpse = 0;
+
+#ifdef EQL_DEBUG
+ if (eql_debug >= 100)
+ printk ("%s: schedule %d slaves\n",
+ master_dev->name, eql_number_slaves (queue));
+#endif
+
+ if ( eql_is_empty (queue) )
+ {
+ /* no slaves to play with */
+ eql_set_best_slave (queue, (slave_t *) 0);
+ return;
+ }
+ else
+ { /* make a pass to set the best slave */
+ unsigned long best_load = (unsigned long) ULONG_MAX;
+ slave_t *slave = 0;
+ int i;
+
+ cli ();
+
+ for (i = 1, slave = eql_first_slave (queue);
+ i <= eql_number_slaves (queue);
+ i++, slave = eql_next_slave (queue, slave))
+ {
+ /* go through the slave list once, updating best_slave
+ whenever a new best_load is found, whenever a dead
+ slave is found, it is marked to be pulled out of the
+ queue */
+
+ unsigned long slave_load;
+ unsigned long bytes_queued;
+ unsigned long priority_Bps;
+
+ if (slave != 0)
+ {
+ bytes_queued = slave->bytes_queued;
+ priority_Bps = slave->priority_Bps;
+
+ if ( slave->dev != 0)
+ {
+ if ( slave->dev->flags & IFF_UP == IFF_UP )
+ {
+ slave_load = (ULONG_MAX - (ULONG_MAX / 2)) -
+ (priority_Bps) + bytes_queued * 8;
+
+ if (slave_load < best_load)
+ {
+ best_load = slave_load;
+ best_slave = slave;
+ }
+ }
+ else /* we found a dead slave */
+ {
+ /* we only bury one slave at a time, if more than
+ one slave dies, we will bury him on the next
+ reschedule. slaves don't die all at once that much
+ anyway */
+ slave_corpse = slave;
+ }
+ }
+ }
+ } /* for */
+
+ sti ();
+
+ eql_set_best_slave (queue, best_slave);
+ } /* else */
+
+ if (slave_corpse != 0)
+ {
+ printk ("eql: scheduler found dead slave, burying...\n");
+ eql_delete_slave (eql_remove_slave (queue, slave_corpse));
+ }
+
+ return;
+}
+
+
+static
+slave_t *
+eql_find_slave_dev(slave_queue_t *queue, struct device *dev)
+{
+ slave_t *slave = 0;
+
+ slave = eql_first_slave(queue);
+
+ while (slave != 0 && slave->dev != dev && slave != 0)
+ {
+#if 0
+ if (slave->dev != 0)
+ printk ("eql: find_slave_dev; looked at '%s'...\n", slave->dev->name);
+ else
+ printk ("eql: find_slave_dev; looked at nothing...\n");
+#endif
+
+ slave = slave->next;
+ }
+
+ return slave;
+}
+
+
+static inline
+slave_t *
+eql_first_slave(slave_queue_t *queue)
+{
+ return queue->head->next;
+}
+
+
+static inline
+slave_t *
+eql_next_slave(slave_queue_t *queue, slave_t *slave)
+{
+ return slave->next;
+}
+
+
+static inline
+void
+eql_set_best_slave(slave_queue_t *queue, slave_t *slave)
+{
+ queue->best_slave = slave;
+}
+
+
+#if 0
+static inline
+int
+eql_lock_slave_queue(slave_queue_t *queue)
+{
+ int result = 0;
+
+ printk ("eql: lock == %d\n", queue->lock);
+ if (queue->lock)
+ {
+ printk ("eql: lock_slave-q sleeping for lock\n");
+ sleep_on (&eql_queue_lock);
+ printk ("eql: lock_slave-q woken up\n");
+ queue->lock = 1;
+ }
+ queue->lock = 1;
+ return result;
+}
+
+static inline
+int
+eql_unlock_slave_queue(slave_queue_t *queue)
+{
+ int result = 0;
+
+ if (queue->lock != 0)
+ {
+ queue->lock = 0;
+ printk ("eql: unlock_slave-q waking up lock waiters\n");
+ wake_up (&eql_queue_lock);
+ }
+ return result;
+}
+#endif
+
+static inline
+int
+eql_is_locked_slave_queue(slave_queue_t *queue)
+{
+ return test_bit(1, (void *) &queue->lock);
+}
+
+static
+void
+eql_timer(unsigned long param)
+{
+ equalizer_t *eql = (equalizer_t *) param;
+ slave_t *slave;
+ slave_t *slave_corpse = 0;
+ int i;
+
+ if ( ! eql_is_empty (eql->queue) )
+ {
+ cli ();
+
+ for (i = 1, slave = eql_first_slave (eql->queue);
+ i <= eql_number_slaves (eql->queue);
+ i++, slave = eql_next_slave (eql->queue, slave))
+ {
+ if (slave != 0)
+ {
+ if ( slave->dev->flags & IFF_UP == IFF_UP )
+ {
+ slave->bytes_queued -= slave->priority_Bps;
+
+ if (slave->bytes_queued < 0)
+ slave->bytes_queued = 0;
+ }
+ else
+ {
+ slave_corpse = slave;
+ }
+ }
+ }
+
+ sti ();
+
+ if (slave_corpse != 0)
+ {
+ printk ("eql: timer found dead slave, burying...\n");
+ eql_delete_slave (eql_remove_slave (eql->queue, slave_corpse));
+ }
+
+ }
+
+ if (eql->timer_on != 0)
+ {
+ eql->timer.expires = EQL_DEFAULT_RESCHED_IVAL;
+ add_timer (&eql->timer);
+ }
+}
+
+/*
+ * Local Variables:
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c eql.c"
+ * version-control: t
+ * kept-new-versions: 20
+ * End:
+ */