summaryrefslogtreecommitdiff
path: root/packages/linux/ixp4xx-kernel/2.6.16/91-maclist.patch
diff options
context:
space:
mode:
Diffstat (limited to 'packages/linux/ixp4xx-kernel/2.6.16/91-maclist.patch')
-rw-r--r--packages/linux/ixp4xx-kernel/2.6.16/91-maclist.patch405
1 files changed, 296 insertions, 109 deletions
diff --git a/packages/linux/ixp4xx-kernel/2.6.16/91-maclist.patch b/packages/linux/ixp4xx-kernel/2.6.16/91-maclist.patch
index 3915c50cb7..72b9fa9a7d 100644
--- a/packages/linux/ixp4xx-kernel/2.6.16/91-maclist.patch
+++ b/packages/linux/ixp4xx-kernel/2.6.16/91-maclist.patch
@@ -1,38 +1,55 @@
- drivers/net/Kconfig | 15 ++
- drivers/net/Makefile | 1
- drivers/net/maclist.c | 314 ++++++++++++++++++++++++++++++++++++++++++++++++++
- include/net/maclist.h | 23 +++
- 4 files changed, 353 insertions(+)
+Ethernet MAC repository.
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-nslu2/include/net/maclist.h 2006-02-06 22:35:23.000000000 +0100
-@@ -0,0 +1,23 @@
-+#ifndef _MACLIST_H
-+#define _MACLIST_H 1
-+/*
-+ * Interfaces to the MAC repository
-+ */
-+/*
-+ * Add a single entry, returns 0 on success else an error
-+ * code. Must *not* be called from an interrupt handler.
-+ */
-+extern int maclist_add(const u8 id_to_add[6]);
-+
-+/*
-+ * Return the current entry count (valid in any context).
-+ */
-+extern int maclist_count(void);
-+
-+/*
-+ * Return the ID from the n'th entry (valid in any context),
-+ * returns 0 on success, -EINVAL if 'n' is out of range.
-+ */
-+extern int maclist_read(u8 (*buffer_for_id)[6], int index_of_id_to_return);
+Some ethernet controllers have no built-in way of obtaining an
+appropriate Ethernet MAC address. Such controllers have to be
+initialised in a board-specific way, depending on how the allocated
+MAC is stored. The MAC repository provides a set of APIs and a
+proc entry (/proc/net/maclist) to store MAC values from the board
+so that such drivers can obtain a MAC address without board-specific
+code.
+
+Signed-off-by: John Bowler <jbowler@acm.org>
+
+diff -rup linux-2.6.15.1/.pc/91-maclist.patch/drivers/net/Kconfig linux-2.6.15.1/drivers/net/Kconfig
+--- linux-2.6.15/drivers/net/Kconfig 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/net/Kconfig 1970-01-01 00:00:00.000000000 +0000
+@@ -166,6 +166,21 @@ config NET_ETHERNET
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Ethernet network cards. If unsure, say N.
+
++config MACLIST
++ tristate "Ethernet MAC repository"
++ depends on NET_ETHERNET
++ help
++ Some ethernet controllers have no built-in way of obtaining an
++ appropriate Ethernet MAC address. Such controllers have to be
++ initialised in a board-specific way, depending on how the allocated
++ MAC is stored. The MAC repository provides a set of APIs and a
++ proc entry (/proc/net/maclist) to store MAC values from the board
++ so that such drivers can obtain a MAC address without board-specific
++ code. You do not need to enable this device - it will be selected
++ automatically by any device which requires it. It is only useful
++ to enable it manually when building a device driver independently
++ of the kernel build.
+
-+#endif /*_MACLIST_H*/
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-nslu2/drivers/net/maclist.c 2006-02-06 22:35:23.000000000 +0100
-@@ -0,0 +1,314 @@
+ config MII
+ tristate "Generic Media Independent Interface device support"
+ depends on NET_ETHERNET
+diff -rup linux-2.6.15.1/.pc/91-maclist.patch/drivers/net/Makefile linux-2.6.15.1/drivers/net/Makefile
+--- linux-2.6.15/drivers/net/Makefile 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/net/Makefile 1970-01-01 00:00:00.000000000 +0000
+@@ -70,6 +70,7 @@ obj-$(CONFIG_RIONET) += rionet.o
+ # end link order section
+ #
+
++obj-$(CONFIG_MACLIST) += maclist.o
+ obj-$(CONFIG_MII) += mii.o
+ obj-$(CONFIG_PHYLIB) += phy/
+
+diff -rup linux-2.6.15.1/.pc/91-maclist.patch/drivers/net/maclist.c linux-2.6.15.1/drivers/net/maclist.c
+--- linux-2.6.15/drivers/net/maclist.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/net/maclist.c 1970-01-01 00:00:00.000000000 +0000
+@@ -0,0 +1,465 @@
+/*
+ * drivers/net/maclist.c
+ *
@@ -61,15 +78,70 @@
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
-+ *
++ */
++
++/*
+ * External interfaces:
+ * Interfaces to linux kernel (and modules)
-+ * maclist_add: add a single MAC
++ * maclist_add: add a single MAC, sequenced with a single
++ * writer lock (reads may happen simultaneously
++ * because of the way the list is built)
+ * maclist_count: total number of MACs stored
-+ * maclist_read: read a MAC 0..(maclist_count-1)
++ * maclist_read: read a MAC 0..(maclist_count-1). Call this
++ * to get a specific MAC. If the argument is
++ * a new key and all the allocaed MACs have been
++ * assigned a random but valid MAC will be return
++ * (and this will be stored for later retrieval
++ * under the given key.)
++ *
++ * Sequencing:
++ * The MAC ids must be added before any driver tries to use them
++ * (this is obvious isn't it?) This can be made to happen by
++ * sequencing the initcalls correctly. The module or kernel
++ * parameters have been handled before any init call happens.
++ * The important trick here is to ensure that the platform
++ * initialises any devices with MAC ids *before* any devices
++ * which might use them.
++ *
++ * When this code is a module any other module which adds a
++ * MAC should be modprobed before modules for ethernet
++ * devices.
++ *
++ * The failure case is 'soft' - the device will get a valid, but
++ * random, MAC and the real allocated MACs will never get used.
++ * This can be seen by looking at the list of ids in sysfs (there
++ * will be extra, random, ones after the allocated ones).
++ *
++ * Recommendations:
++ * For ethernet drivers which are known to be the sole driver on
++ * the board (without a built in MAC) and where the number of
++ * devices driven is known simply use an index 0..(n-1) as a
++ * key for each of the n devices.
++ *
++ * This is the common case, it works where one driver handles
++ * multiple devices so long as the total number of devices can
++ * be determined reliably. It is sufficient merely to maintain
++ * a global count of the number of devices initialised so far,
++ * just so long as the initialisation order is consistent.
++ *
++ * When the driver is generic and the board may be populated with
++ * other devices which allocate MACs from the maclist pool and
++ * use different drivers create a random key and compile this into
++ * the code. Use this as the base for all devices from the driver
++ * (using a global device count for this driver if necessary).
++ *
++ * With the second strategy the assignment of MACs will depend on
++ * the order of initialisation of the different drivers. To avoid
++ * this provide a kernel (or module) command line parameter to
++ * specify a base index and (optional) count for each driver or
++ * pass in a (struct resource) with the start and end of the keys
++ * to pass to maclist_read. Either method allows the higher levels
++ * (boot loader or machine description) to specify which MACs in
++ * the list to assign to each device.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
++#include <linux/spinlock.h>
+#include <linux/etherdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/errno.h>
@@ -84,22 +156,27 @@
+
+typedef struct maclist_entry {
+ struct maclist_entry *next; /* Linked list, first first */
++ u32 key; /* count or key for this entry */
++ u16 flags;
+ u8 id[6]; /* 6 byte Ethernet MAC */
+} maclist_entry_t;
+
-+/* Access to this list is possible at any time - entries in
-+ * the list are never destroyed. Modification of the list is
-+ * safe only from the init code (i.e. modification must be
-+ * single threaded), but read from an interrupt at the same
-+ * time is possible and safe.
++/*
++ * flag definitions
+ */
++#define MACLIST_ALLOCATED 1
++#define MACLIST_RANDOM 2
++
++/* Access to this list is protected by a standard rwlock_t. */
+static maclist_entry_t *maclist_list = 0;
+
++static DEFINE_RWLOCK(maclist_lock);
++
+/*
+ * External interfaces.
+ *
+ * Add a single entry, returns 0 on success else an error
-+ * code. Must be single threaded.
++ * code. Checks for invalid addresses.
+ */
+int maclist_add(const u8 new_id[6]) {
+ maclist_entry_t *new_entry, **tail;
@@ -111,21 +188,27 @@
+ new_entry = kmalloc(sizeof *new_entry, GFP_KERNEL);
+ if (new_entry == 0)
+ return -ENOMEM;
-+ new_entry->next = 0;
++ new_entry->next = 0;
++ new_entry->key = 0;
++ new_entry->flags = 0;
+ memcpy(new_entry->id, new_id, sizeof new_entry->id);
+
+ tail = &maclist_list;
++
++ write_lock(&maclist_lock);
+ while (*tail != 0)
+ tail = &(*tail)->next;
+ *tail = new_entry;
++ write_unlock(&maclist_lock);
++
+ return 0;
+}
+EXPORT_SYMBOL(maclist_add);
+
+/*
-+ * Return the current entry count (valid in any context).
++ * Return the current entry count.
+ */
-+int maclist_count(void) {
++static int maclist_count_unlocked(void) {
+ maclist_entry_t *tail = maclist_list;
+ int count = 0;
+
@@ -136,27 +219,73 @@
+
+ return count;
+}
++
++int maclist_count(void) {
++ int count;
++
++ read_lock(&maclist_lock);
++ count = maclist_count_unlocked();
++ read_unlock(&maclist_lock);
++
++ return count;
++}
+EXPORT_SYMBOL(maclist_count);
+
+/*
-+ * Return the ID from the n'th entry (valid in any context),
-+ * returns 0 on success, -EINVAL if 'n' is out of range.
++ * Return the ID with the given key (the key is allocated
++ * to an entry if not found).
+ */
-+int maclist_read(u8 (*id)[6], int n) {
-+ maclist_entry_t *entry = maclist_list;
-+
-+ while (n > 0 && entry != 0) {
-+ --n;
-+ entry = entry->next;
-+ }
++void maclist_read(u8 (*id)[6], u32 key) {
++ int count, index;
++ maclist_entry_t *entry, *entry_to_allocate;
++
++ /* Do this under a write lock to avoid the SMP race
++ * where we find the key isn't assigned, drop the lock,
++ * have another CPU assign it, then assign it on this
++ * CPU too - very bad...
++ */
++ write_lock(&maclist_lock);
++ count = maclist_count_unlocked();
++ index = key % count; /* index of entry to allocate */
++ entry_to_allocate = 0;
++
++ entry = maclist_list;
++ while (entry != 0) {
++ if ((entry->flags & MACLIST_ALLOCATED) != 0) {
++ if (entry->key == key) {
++ /* Found it, use this entry. */
++ entry_to_allocate = entry;
++ break;
++ }
++ } else if (entry_to_allocate == 0 || count <= index) {
++ /* The algorithm is to try for entry
++ * (key % count), but if this isn't possible
++ * return the prior unallocated entry.
++ */
++ entry_to_allocate = entry;
++ }
++
++ ++count;
++ entry = entry->next;
++ }
+
-+ if (n == 0 && entry != 0) {
-+ memcpy(id, entry->id, sizeof *id);
-+ return 0;
++ /* Use entry_to_allocate, allocating it if necessary. */
++ if (entry_to_allocate != 0) {
++ if ((entry_to_allocate->flags & MACLIST_ALLOCATED) == 0) {
++ entry_to_allocate->key = key;
++ entry_to_allocate->flags |= MACLIST_ALLOCATED;
++ }
++ memcpy(id, entry_to_allocate->id, sizeof *id);
++ }
++ write_unlock(&maclist_lock);
++
++ if (entry_to_allocate == 0) {
++ /* No unallocated entries. Make a new one and return it. */
++ printk(KERN_INFO MACLIST_NAME ": adding random MAC for key 0x%x\n", key);
++ random_ether_addr(*id);
++ if (maclist_add(*id) == 0)
++ maclist_read(id, key);
+ }
-+
-+ printk(KERN_ERR MACLIST_NAME ": id does not exist\n");
-+ return -EINVAL;
+}
+EXPORT_SYMBOL(maclist_read);
+
@@ -165,7 +294,7 @@
+ * addresses, comma separated. (The parsing really should
+ * be somewhere central...)
+ */
-+static int __init maclist_setup(char *param) {
++static int __init maclist_setup(const char *param) {
+ int bytes = 0, seen_a_digit = 0;
+ u8 id[6];
+
@@ -219,7 +348,7 @@
+
+ if (bytes >= 12) {
+ int rc = maclist_add(id);
-+ if (rc)
++ if (unlikely(rc))
+ return rc;
+ bytes = 0;
+ seen_a_digit = 0;
@@ -233,10 +362,7 @@
+ return 0;
+}
+
-+/*
-+ * procfs support, if compiled in.
-+ */
-+#ifdef CONFIG_PROC_FS
++#if (defined CONFIG_PROC_FS) || (defined MODULE)
+/*
+ * Character device read
+ */
@@ -264,8 +390,13 @@
+ default: return ':';
+ }
+}
++#endif
+
+/*
++ * procfs support, if compiled in.
++ */
++#ifdef CONFIG_PROC_FS
++/*
+ * The extensively undocumented proc_read_t callback is implemented here.
+ * Go look in fs/proc/generic.c:
+ *
@@ -306,6 +437,49 @@
+#endif
+
+/*
++ * set works once, at init time (the param is set to 0444 below),
++ * get works any time.
++ */
++static int param_set_maclist(const char *val, struct kernel_param *kp)
++{
++ if (maclist_list == 0)
++ return maclist_setup(val);
++
++ printk(KERN_ERR MACLIST_NAME ": call to set parameters too late\n");
++ return -EINVAL;
++}
++
++static int param_get_maclist(char *buffer, struct kernel_param *kp)
++{
++#ifdef MODULE
++ off_t offset = 0;
++
++ /* buffer is only 4k! */
++ while (offset < 4096) {
++ int ch = maclist_getchar(offset++);
++ if (ch < 0) {
++ *buffer = 0;
++ return 0;
++ }
++ *buffer++ = ch;
++ }
++
++ *--buffer = 0;
++ return -ENOMEM;
++#else
++ return -EINVAL;
++#endif
++}
++
++/*
++ * module: the argument is ids=mac,mac,mac
++ * kernel command line: maclist.ids=mac,mac,mac
++ */
++#define param_check_maclist(name, p) __param_check(name, p, maclist_entry_t*)
++module_param_named(ids, maclist_list, maclist, 0444);
++MODULE_PARM_DESC(ids, "comma separated list of MAC ids\n");
++
++/*
+ * Finally, the init/exit functions.
+ */
+static void __exit maclist_exit(void)
@@ -314,8 +488,10 @@
+
+ remove_proc_entry(MACLIST_NAME, proc_net);
+
-+ list = maclist_list;
-+ maclist_list = 0;
++ write_lock(&maclist_lock);
++ list = maclist_list;
++ maclist_list = 0;
++ write_unlock(&maclist_lock);
+
+ while (list != 0) {
+ maclist_entry_t *head = list;
@@ -324,14 +500,6 @@
+ }
+}
+
-+#ifdef MODULE
-+static char ids[256];
-+module_param_string(ids, ids, sizeof ids, 0);
-+MODULE_PARM_DESC(ids, "comma separated list of MAC ids\n");
-+#else
-+__setup("maclist_ids=", maclist_setup);
-+#endif
-+
+static int __init maclist_init(void)
+{
+# ifdef MODULE
@@ -347,37 +515,56 @@
+
+module_init(maclist_init);
+module_exit(maclist_exit);
---- linux-nslu2.orig/drivers/net/Makefile 2006-02-06 22:35:18.000000000 +0100
-+++ linux-nslu2/drivers/net/Makefile 2006-02-06 22:35:23.000000000 +0100
-@@ -74,6 +74,7 @@ obj-$(CONFIG_RIONET) += rionet.o
- # end link order section
- #
-
-+obj-$(CONFIG_MACLIST) += maclist.o
- obj-$(CONFIG_MII) += mii.o
- obj-$(CONFIG_PHYLIB) += phy/
-
---- linux-nslu2.orig/drivers/net/Kconfig 2006-02-06 22:35:18.000000000 +0100
-+++ linux-nslu2/drivers/net/Kconfig 2006-02-06 22:35:23.000000000 +0100
-@@ -180,6 +180,21 @@ config NET_ETHERNET
- kernel: saying N will just cause the configurator to skip all
- the questions about Ethernet network cards. If unsure, say N.
-
-+config MACLIST
-+ tristate "Ethernet MAC repository"
-+ depends on NET_ETHERNET
-+ help
-+ Some ethernet controllers have no built-in way of obtaining an
-+ appropriate Ethernet MAC address. Such controllers have to be
-+ initialised in a board-specific way, depending on how the allocated
-+ MAC is stored. The MAC repository provides a set of APIs and a
-+ proc entry (/proc/net/maclist) to store MAC values from the board
-+ so that such drivers can obtain a MAC address without board-specific
-+ code. You do not need to enable this device - it will be selected
-+ automatically by any device which requires it. It is only useful
-+ to enable it manually when building a device driver independently
-+ of the kernel build.
+diff -rup linux-2.6.15.1/.pc/91-maclist.patch/include/net/maclist.h linux-2.6.15.1/include/net/maclist.h
+--- linux-2.6.15/include/net/maclist.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/include/net/maclist.h 1970-01-01 00:00:00.000000000 +0000
+@@ -0,0 +1,49 @@
++#ifndef _MACLIST_H
++#define _MACLIST_H 1
++/*
++ * Interfaces to the MAC repository
++ *
++ * Copyright (C) 2005 John Bowler
++ * Author: John Bowler <jbowler@acm.org>
++ * Maintainers: http://www.nslu2-linux.org/
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ */
+
- config MII
- tristate "Generic Media Independent Interface device support"
- depends on NET_ETHERNET
++/*
++ * Add a single entry, returns 0 on success else an error
++ * code. Allocates memory, claims and releases a write
++ * lock.
++ */
++extern int maclist_add(const u8 id_to_add[6]);
++
++/*
++ * Return the current entry count, claims and releases a
++ * read lock.
++ */
++extern int maclist_count(void);
++
++/*
++ * Return the ID from the given entry. Always succeeds.
++ * Claims and releases a write lock.
++ *
++ * If any entry has not been allocated for this key one
++ * is allocated. If there are no remaining unallocated
++ * entries a new one is created.
++ *
++ * If the value of the key is less than maclist_count()
++ * the entry indexed by the key (i.e. for key 'n' the
++ * n'th entry starting at 0) will be returned if available.
++ * Otherwise the entry to be returned will be unpredictable
++ * but consistent for a given value of maclist_count().
++ */
++extern void maclist_read(u8 (*buffer_for_id)[6],
++ u32 key_of_entry_to_return);
++
++/*
++ * See the implementation in drivers/net/maclist.c for
++ * more information.
++ */
++#endif /*_MACLIST_H*/