ixp4xx-kernel: clean up maclist code in 2.6.15
authorJohn Bowler <jbowler@nslu2-linux.org>
Thu, 26 Jan 2006 23:43:09 +0000 (23:43 +0000)
committerOpenEmbedded Project <openembedded-devel@lists.openembedded.org>
Thu, 26 Jan 2006 23:43:09 +0000 (23:43 +0000)
ixp400-eth: merge clean up to maclist_read in 1.5
 - maclist_read is now (void), it always succeeds

packages/ixp425-eth/ixp400-eth-1.5/mac-address.patch
packages/ixp425-eth/ixp400-eth_1.5.bb
packages/linux/ixp4xx-kernel/2.6.15/91-maclist.patch
packages/linux/ixp4xx-kernel_2.6.15.1.bb

index 471967f..e23eaf5 100644 (file)
@@ -1,3 +1,8 @@
+Patch to use maclist - get the MAC to use from the board level
+MAC repository based on the device portId.
+
+Signed-off-by: John Bowler <jbowler@acm.org>
+
 --- ixp400-eth/ixp400_eth.c    1970-01-01 00:00:00.000000000 +0000
 +++ ixp400-eth/ixp400_eth.c    1970-01-01 00:00:00.000000000 +0000
 @@ -23,10 +23,10 @@
@@ -32,7 +37,7 @@
  #endif
  
  #ifndef CONFIG_IXP400_NAPI
-@@ -621,21 +624,6 @@ static phy_cfg_t default_phy_cfg[] =
+@@ -614,21 +617,6 @@ static phy_cfg_t default_phy_cfg[] =
  #endif
  };
  
@@ -54,7 +59,7 @@
  /* Default mapping of  NpeImageIds for EthAcc Ports 
   * Default is 
   *   IX_ETH_PORT_1 -> IX_ETH_NPE_B
-@@ -3337,28 +3325,13 @@ static int __devinit dev_eth_probe(struc
+@@ -3325,28 +3313,10 @@ static int __devinit dev_eth_probe(struc
  
      /* Defines the unicast MAC address
       *
 -     *
 +     * The code reads from the maclist API.
       */
-+    if (maclist_read((u8(*)[6])&ndev->dev_addr, priv->port_id) ||
-+                  !is_valid_ether_addr(ndev->dev_addr))
-+          random_ether_addr(ndev->dev_addr);
+-
 -    memcpy(ndev->dev_addr, 
 -         &default_mac_addr[priv->port_id].macAddress,
 -         IX_IEEE803_MAC_ADDRESS_SIZE);
 -    if (is_valid_ether_addr(ndev->dev_addr))
 -    {
 -      P_WARN("Use default MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x for port %d\n",
++    maclist_read((u8(*)[6])&ndev->dev_addr, priv->port_id);
 +    P_INFO("Use MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x for port %d\n",
               (unsigned)ndev->dev_addr[0],
               (unsigned)ndev->dev_addr[1],
               (unsigned)ndev->dev_addr[2],
-@@ -3366,7 +3339,6 @@ static int __devinit dev_eth_probe(struc
+@@ -3354,7 +3324,6 @@ static int __devinit dev_eth_probe(struc
               (unsigned)ndev->dev_addr[4],
               (unsigned)ndev->dev_addr[5],
               priv->port_id);
@@ -96,7 +99,7 @@
      
      /* Set/update the internal packet size 
       * This can be overriden later by the command
-@@ -3584,12 +3556,15 @@ static int __init ixp400_eth_init(void)
+@@ -3562,12 +3531,15 @@ static int __init ixp400_eth_init(void)
  
      TRACE;
  
index 8833b85..e540774 100644 (file)
@@ -4,7 +4,7 @@
 MAINTAINER = "NSLU2 Linux <nslu2-linux@yahoogroups.com>"
 HOMEPAGE = "http://www.intel.com/design/network/products/npfamily/ixp420.htm"
 LICENSE = "GPL"
-PR = "r7"
+PR = "r8"
 
 DEPENDS = "ixp4xx-csr"
 RDEPENDS = "ixp4xx-csr"
index 27af1ea..72b9fa9 100644 (file)
@@ -1,32 +1,55 @@
---- 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);
+Ethernet MAC repository.
+
+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*/
+ 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,314 @@
+@@ -0,0 +1,465 @@
 +/*
 + * drivers/net/maclist.c
 + *
 + * 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>
 +
 +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;
 +      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;
 +
 +
 +      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);
 +
 + * 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];
 +
 +
 +              if (bytes >= 12) {
 +                      int rc = maclist_add(id);
-+                      if (rc)
++                      if (unlikely(rc))
 +                              return rc;
 +                      bytes = 0;
 +                      seen_a_digit = 0;
 +      return 0;
 +}
 +
-+/*
-+ * procfs support, if compiled in.
-+ */
-+#ifdef CONFIG_PROC_FS
++#if (defined CONFIG_PROC_FS) || (defined MODULE)
 +/*
 + * Character device read
 + */
 +      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:
 + *
 +#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)
 +
 +      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;
 +      }
 +}
 +
-+#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
 +
 +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.
+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*/
index add6718..f9d08c0 100644 (file)
@@ -8,7 +8,7 @@ PR_CONFIG = "0"
 # Increment the number below (i.e. the digits after PR) when
 # making changes within this file or for changes to the patches
 # applied to the kernel.
-PR = "r14.${PR_CONFIG}"
+PR = "r15.${PR_CONFIG}"
 
 include ixp4xx-kernel.inc