Add maclist support. This is needed for the eth driver of the NSLU2.

Only apply this on ARM for now since the patch hasn't been forwarded
upstream yet.

svn path=/dists/trunk/linux-2.6/; revision=5434
This commit is contained in:
Martin Michlmayr 2006-01-14 02:09:24 +00:00
parent c6af46e5b4
commit be56280fef
6 changed files with 461 additions and 0 deletions

View File

@ -22,3 +22,4 @@ CONFIG_TMPFS=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
# CONFIG_MACLIST is not set

View File

@ -740,6 +740,7 @@ CONFIG_CICADA_PHY=m
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
CONFIG_MACLIST=y
CONFIG_MII=y
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set

3
debian/changelog vendored
View File

@ -22,6 +22,9 @@ linux-2.6 (2.6.15-3) UNRELEASED; urgency=low
undeclared".
* debian/patches/mtdpart-redboot-fis-byteswap.patch: recognise a foreign
endian RedBoot partition table.
* debian/patches/maclist.patch: Add support for the maclist interface.
* debian/patches/arm-nslu2-maclist.patch: Add NSLU2 maclist support.
* [arm/nslu2] Activate maclist.
-- Martin Michlmayr <tbm@cyrius.com> Tue, 10 Jan 2006 22:59:19 +0000

72
debian/patches/arm-nslu2-maclist.patch vendored Normal file
View File

@ -0,0 +1,72 @@
## DP: maclist support for nslu2
## DP: Patch author: John Bowler <jbowler@acm.org>
## DP: Upstream status: not yet submitted - depends on maclist.patch
#
--- linux-2.6.15/arch/arm/mach-ixp4xx/nslu2-setup.c 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.15/arch/arm/mach-ixp4xx/nslu2-setup.c 1970-01-01 00:00:00.000000000 +0000
@@ -16,11 +16,14 @@
#include <linux/kernel.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>
+#include <linux/mtd/mtd.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
+#include <net/maclist.h>
+
static struct flash_platform_data nslu2_flash_data = {
.map_name = "cfi_probe",
.width = 2,
@@ -112,6 +115,37 @@ static void nslu2_power_off(void)
gpio_line_set(NSLU2_PO_GPIO, IXP4XX_GPIO_HIGH);
}
+/*
+ * When the RedBoot partition is added the MAC address is read from
+ * it.
+ */
+static void nslu2_flash_add(struct mtd_info *mtd) {
+ if (strcmp(mtd->name, "RedBoot") == 0) {
+ size_t retlen;
+ u_char mac[6];
+
+ /* The MAC is at a known offset... */
+ if (mtd->read(mtd, 0x3FFB0, 6, &retlen, mac) == 0 && retlen == 6) {
+ printk(KERN_INFO "NSLU2 MAC: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ maclist_add(mac);
+ } else {
+ printk(KERN_ERR "NSLU2 MAC: read failed\n");
+ }
+ }
+}
+
+/*
+ * Nothing to do on remove at present.
+ */
+static void nslu2_flash_remove(struct mtd_info *mtd) {
+}
+
+static struct mtd_notifier nslu2_flash_notifier = {
+ .add = nslu2_flash_add,
+ .remove = nslu2_flash_remove,
+};
+
static void __init nslu2_init(void)
{
/* The NSLU2 has a 33MHz crystal on board - 1.01% different
@@ -119,6 +153,11 @@ static void __init nslu2_init(void)
*/
ixp4xx_set_board_tick_rate(66000000);
+ /* The flash has an ethernet MAC embedded in it which we need,
+ * that is all this notifier does.
+ */
+ register_mtd_user(&nslu2_flash_notifier);
+
ixp4xx_sys_init();
pm_power_off = nslu2_power_off;

382
debian/patches/maclist.patch vendored Normal file
View File

@ -0,0 +1,382 @@
## DP: maclist interface
## DP: Patch author: John Bowler <jbowler@acm.org>
## DP: Upstream status: not yet submitted!
#
--- 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,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);
+
+#endif /*_MACLIST_H*/
--- 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,314 @@
+/*
+ * drivers/net/maclist.c
+ *
+ * a simple driver to remember ethernet MAC values
+ *
+ * Some Ethernet hardware implementations have no built-in
+ * storage for allocated MAC values - an example is the Intel
+ * IXP420 chip which has support for Ethernet but no defined
+ * way of storing allocated MAC values. With such hardware
+ * different board level implementations store the allocated
+ * MAC (or MACs) in different ways. Rather than put board
+ * level code into a specific Ethernet driver this driver
+ * provides a generally accessible repository for the MACs
+ * which can be written by board level code and read by the
+ * driver.
+ *
+ * The implementation also allows user level programs to
+ * access the MAC information in /proc/net/maclist. This is
+ * useful as it allows user space code to use the MAC if it
+ * is not used by a built-in driver.
+ *
+ * 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.
+ *
+ * External interfaces:
+ * Interfaces to linux kernel (and modules)
+ * maclist_add: add a single MAC
+ * maclist_count: total number of MACs stored
+ * maclist_read: read a MAC 0..(maclist_count-1)
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/etherdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/errno.h>
+
+#include <net/maclist.h>
+
+#define MACLIST_NAME "maclist"
+
+MODULE_AUTHOR("John Bowler <jbowler@acm.org>");
+MODULE_DESCRIPTION("MAC list repository");
+MODULE_LICENSE("GPL");
+
+typedef struct maclist_entry {
+ struct maclist_entry *next; /* Linked list, first first */
+ 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.
+ */
+static maclist_entry_t *maclist_list = 0;
+
+/*
+ * External interfaces.
+ *
+ * Add a single entry, returns 0 on success else an error
+ * code. Must be single threaded.
+ */
+int maclist_add(const u8 new_id[6]) {
+ maclist_entry_t *new_entry, **tail;
+
+ if (new_id == 0 || !is_valid_ether_addr(new_id)) {
+ printk(KERN_ERR MACLIST_NAME ": invalid ethernet address\n");
+ return -EINVAL;
+ }
+ new_entry = kmalloc(sizeof *new_entry, GFP_KERNEL);
+ if (new_entry == 0)
+ return -ENOMEM;
+ new_entry->next = 0;
+ memcpy(new_entry->id, new_id, sizeof new_entry->id);
+
+ tail = &maclist_list;
+ while (*tail != 0)
+ tail = &(*tail)->next;
+ *tail = new_entry;
+ return 0;
+}
+EXPORT_SYMBOL(maclist_add);
+
+/*
+ * Return the current entry count (valid in any context).
+ */
+int maclist_count(void) {
+ maclist_entry_t *tail = maclist_list;
+ int count = 0;
+
+ while (tail != 0) {
+ tail = tail->next;
+ ++count;
+ }
+
+ 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.
+ */
+int maclist_read(u8 (*id)[6], int n) {
+ maclist_entry_t *entry = maclist_list;
+
+ while (n > 0 && entry != 0) {
+ --n;
+ entry = entry->next;
+ }
+
+ if (n == 0 && entry != 0) {
+ memcpy(id, entry->id, sizeof *id);
+ return 0;
+ }
+
+ printk(KERN_ERR MACLIST_NAME ": id does not exist\n");
+ return -EINVAL;
+}
+EXPORT_SYMBOL(maclist_read);
+
+/*
+ * Parameter parsing. The option string is a list of MAC
+ * addresses, comma separated. (The parsing really should
+ * be somewhere central...)
+ */
+static int __init maclist_setup(char *param) {
+ int bytes = 0, seen_a_digit = 0;
+ u8 id[6];
+
+ memset(id, 0, sizeof id);
+
+ if (param) do {
+ int digit = -1;
+ switch (*param) {
+ case '0': digit = 0; break;
+ case '1': digit = 1; break;
+ case '2': digit = 2; break;
+ case '3': digit = 3; break;
+ case '4': digit = 4; break;
+ case '5': digit = 5; break;
+ case '6': digit = 6; break;
+ case '7': digit = 7; break;
+ case '8': digit = 8; break;
+ case '9': digit = 9; break;
+ case 'a': case 'A': digit = 10; break;
+ case 'b': case 'B': digit = 11; break;
+ case 'c': case 'C': digit = 12; break;
+ case 'd': case 'D': digit = 13; break;
+ case 'e': case 'E': digit = 14; break;
+ case 'f': case 'F': digit = 15; break;
+ case ':':
+ if (seen_a_digit)
+ bytes = (bytes+1) & ~1;
+ else
+ bytes += 2; /* i.e. ff::ff is ff:00:ff */
+ seen_a_digit = 0;
+ break;
+ case 0:
+ if (bytes == 0) /* nothing new seen so far */
+ return 0;
+ /*fall through*/
+ case ',': case ';':
+ if (bytes > 0)
+ bytes = 12; /* i.e. all trailing bytes 0 */
+ break;
+ default:
+ printk(KERN_ERR MACLIST_NAME ": invalid character <%c[%d]>\n",
+ *param, *param);
+ return -EINVAL;
+ }
+
+ if (digit >= 0) {
+ id[bytes>>1] = (id[bytes>>1] << 4) + digit; break;
+ ++bytes;
+ seen_a_digit = 1;
+ }
+
+ if (bytes >= 12) {
+ int rc = maclist_add(id);
+ if (rc)
+ return rc;
+ bytes = 0;
+ seen_a_digit = 0;
+ memset(id, 0, sizeof id);
+ if (*param == 0)
+ return 0;
+ }
+ ++param;
+ } while (1);
+
+ return 0;
+}
+
+/*
+ * procfs support, if compiled in.
+ */
+#ifdef CONFIG_PROC_FS
+/*
+ * Character device read
+ */
+static int maclist_getchar(off_t n) {
+ static char xdigit[16] = "0123456789abcdef";
+ maclist_entry_t *head = maclist_list;
+ int b;
+
+ do {
+ if (head == 0)
+ return -1;
+ if (n < 18)
+ break;
+ head = head->next;
+ n -= 18;
+ } while (1);
+
+ if (n == 17)
+ return '\n';
+
+ b = n/3;
+ switch (n - b*3) {
+ case 0: return xdigit[head->id[b] >> 4];
+ case 1: return xdigit[head->id[b] & 0xf];
+ default: return ':';
+ }
+}
+
+/*
+ * The extensively undocumented proc_read_t callback is implemented here.
+ * Go look in fs/proc/generic.c:
+ *
+ * Prototype:
+ * int f(char *buffer, char **start, off_t offset,
+ * int count, int *peof, void *dat)
+ *
+ * Assume that the buffer is "count" bytes in size.
+ *
+ * 2) Set *start = an address within the buffer.
+ * Put the data of the requested offset at *start.
+ * Return the number of bytes of data placed there.
+ * If this number is greater than zero and you
+ * didn't signal eof and the reader is prepared to
+ * take more data you will be called again with the
+ * requested offset advanced by the number of bytes
+ * absorbed.
+ */
+static int maclist_proc_read(char *buffer, char **start, off_t offset,
+ int count, int *peof, void *dat) {
+ int total;
+
+ *start = buffer;
+ total = 0;
+
+ while (total < count) {
+ int ch = maclist_getchar(offset++);
+ if (ch == -1) {
+ *peof = 1;
+ break;
+ }
+ *buffer++ = ch;
+ ++total;
+ }
+
+ return total;
+}
+#endif
+
+/*
+ * Finally, the init/exit functions.
+ */
+static void __exit maclist_exit(void)
+{
+ maclist_entry_t *list;
+
+ remove_proc_entry(MACLIST_NAME, proc_net);
+
+ list = maclist_list;
+ maclist_list = 0;
+
+ while (list != 0) {
+ maclist_entry_t *head = list;
+ list = head->next;
+ kfree(head);
+ }
+}
+
+#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
+ if (ids[0])
+ maclist_setup(ids);
+# endif
+
+ /* Ignore failure, the module will still work. */
+ (void)create_proc_read_entry(MACLIST_NAME, S_IRUGO, proc_net, maclist_proc_read, NULL);
+
+ return 0;
+}
+
+module_init(maclist_init);
+module_exit(maclist_exit);
--- 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/
--- 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.
+
config MII
tristate "Generic Media Independent Interface device support"
depends on NET_ETHERNET

2
debian/patches/series/3-extra vendored Normal file
View File

@ -0,0 +1,2 @@
+ maclist.patch arm
+ arm-nslu2-maclist.patch arm