diff options
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.patch | 405 |
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*/ |