CRIS v10: Update kernel/io_interface_mux.c
[linux-2.6.git] / arch / cris / arch-v10 / kernel / io_interface_mux.c
index f3b327d..add98e0 100644 (file)
@@ -1,10 +1,9 @@
 /* IO interface mux allocator for ETRAX100LX.
- * Copyright 2004, Axis Communications AB
- * $Id: io_interface_mux.c,v 1.2 2004/12/21 12:08:38 starvik Exp $
+ * Copyright 2004-2007, Axis Communications AB
  */
 
 
-/* C.f. ETRAX100LX Designer's Reference 20.9 */
+/* C.f. ETRAX100LX Designer's Reference chapter 19.9 */
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -45,17 +44,39 @@ struct watcher
 struct if_group
 {
        enum io_if_group        group;
-       unsigned char           used;
-       enum cris_io_interface  owner;
+       /* name - the name of the group 'A' to 'F' */
+       char                   *name;
+       /* used - a bit mask of all pins in the group in the order listed
+        * in the tables in 19.9.1 to 19.9.6.  Note that no
+        * distinction is made between in, out and in/out pins. */
+       unsigned int            used;
 };
 
 
 struct interface
 {
        enum cris_io_interface   ioif;
+       /* name - the name of the interface */
+       char                    *name;
+       /* groups - OR'ed together io_if_group flags describing what pin groups
+        * the interface uses pins in. */
        unsigned char            groups;
+       /* used - set when the interface is allocated. */
        unsigned char            used;
        char                    *owner;
+       /* group_a through group_f - bit masks describing what pins in the
+        * pin groups the interface uses. */
+       unsigned int             group_a;
+       unsigned int             group_b;
+       unsigned int             group_c;
+       unsigned int             group_d;
+       unsigned int             group_e;
+       unsigned int             group_f;
+
+       /* gpio_g_in, gpio_g_out, gpio_b - bit masks telling what pins in the
+        * GPIO ports the interface uses.  This could be reconstucted using
+        * the group_X masks and a table of what pins the GPIO ports use,
+        * but that would be messy. */
        unsigned int             gpio_g_in;
        unsigned int             gpio_g_out;
        unsigned char            gpio_b;
@@ -64,26 +85,32 @@ struct interface
 static struct if_group if_groups[6] = {
        {
                .group = group_a,
+               .name = "A",
                .used = 0,
        },
        {
                .group = group_b,
+               .name = "B",
                .used = 0,
        },
        {
                .group = group_c,
+               .name = "C",
                .used = 0,
        },
        {
                .group = group_d,
+               .name = "D",
                .used = 0,
        },
        {
                .group = group_e,
+               .name = "E",
                .used = 0,
        },
        {
                .group = group_f,
+               .name = "F",
                .used = 0,
        }
 };
@@ -94,14 +121,32 @@ static struct interface interfaces[] = {
        /* Begin Non-multiplexed interfaces */
        {
                .ioif = if_eth,
+               .name = "ethernet",
                .groups = 0,
+
+               .group_a = 0,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0,
+               .group_e = 0,
+               .group_f = 0,
+
                .gpio_g_in = 0,
                .gpio_g_out = 0,
                .gpio_b = 0
        },
        {
                .ioif = if_serial_0,
+               .name = "serial_0",
                .groups = 0,
+
+               .group_a = 0,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0,
+               .group_e = 0,
+               .group_f = 0,
+
                .gpio_g_in = 0,
                .gpio_g_out = 0,
                .gpio_b = 0
@@ -109,172 +154,385 @@ static struct interface interfaces[] = {
        /* End Non-multiplexed interfaces */
        {
                .ioif = if_serial_1,
+               .name = "serial_1",
                .groups = group_e,
+
+               .group_a = 0,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0,
+               .group_e = 0x0f,
+               .group_f = 0,
+
                .gpio_g_in =  0x00000000,
                .gpio_g_out = 0x00000000,
                .gpio_b = 0x00
        },
        {
                .ioif = if_serial_2,
+               .name = "serial_2",
                .groups = group_b,
+
+               .group_a = 0,
+               .group_b = 0x0f,
+               .group_c = 0,
+               .group_d = 0,
+               .group_e = 0,
+               .group_f = 0,
+
                .gpio_g_in =  0x000000c0,
                .gpio_g_out = 0x000000c0,
                .gpio_b = 0x00
        },
        {
                .ioif = if_serial_3,
+               .name = "serial_3",
                .groups = group_c,
+
+               .group_a = 0,
+               .group_b = 0,
+               .group_c = 0x0f,
+               .group_d = 0,
+               .group_e = 0,
+               .group_f = 0,
+
                .gpio_g_in =  0xc0000000,
                .gpio_g_out = 0xc0000000,
                .gpio_b = 0x00
        },
        {
                .ioif = if_sync_serial_1,
-               .groups = group_e | group_f, /* if_sync_serial_1 and if_sync_serial_3
-                                              can be used simultaneously */
+               .name = "sync_serial_1",
+               .groups = group_e | group_f,
+
+               .group_a = 0,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0,
+               .group_e = 0x0f,
+               .group_f = 0x10,
+
                .gpio_g_in =  0x00000000,
                .gpio_g_out = 0x00000000,
                .gpio_b = 0x10
        },
        {
                .ioif = if_sync_serial_3,
+               .name = "sync_serial_3",
                .groups = group_c | group_f,
+
+               .group_a = 0,
+               .group_b = 0,
+               .group_c = 0x0f,
+               .group_d = 0,
+               .group_e = 0,
+               .group_f = 0x80,
+
                .gpio_g_in =  0xc0000000,
                .gpio_g_out = 0xc0000000,
                .gpio_b = 0x80
        },
        {
                .ioif = if_shared_ram,
+               .name = "shared_ram",
                .groups = group_a,
+
+               .group_a = 0x7f8ff,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0,
+               .group_e = 0,
+               .group_f = 0,
+
                .gpio_g_in =  0x0000ff3e,
                .gpio_g_out = 0x0000ff38,
                .gpio_b = 0x00
        },
        {
                .ioif = if_shared_ram_w,
+               .name = "shared_ram_w",
                .groups = group_a | group_d,
+
+               .group_a = 0x7f8ff,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0xff,
+               .group_e = 0,
+               .group_f = 0,
+
                .gpio_g_in =  0x00ffff3e,
                .gpio_g_out = 0x00ffff38,
                .gpio_b = 0x00
        },
        {
                .ioif = if_par_0,
+               .name = "par_0",
                .groups = group_a,
+
+               .group_a = 0x7fbff,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0,
+               .group_e = 0,
+               .group_f = 0,
+
                .gpio_g_in =  0x0000ff3e,
                .gpio_g_out = 0x0000ff3e,
                .gpio_b = 0x00
        },
        {
                .ioif = if_par_1,
+               .name = "par_1",
                .groups = group_d,
+
+               .group_a = 0,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0x7feff,
+               .group_e = 0,
+               .group_f = 0,
+
                .gpio_g_in =  0x3eff0000,
                .gpio_g_out = 0x3eff0000,
                .gpio_b = 0x00
        },
        {
                .ioif = if_par_w,
+               .name = "par_w",
                .groups = group_a | group_d,
+
+               .group_a = 0x7fbff,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0xff,
+               .group_e = 0,
+               .group_f = 0,
+
                .gpio_g_in =  0x00ffff3e,
                .gpio_g_out = 0x00ffff3e,
                .gpio_b = 0x00
        },
        {
                .ioif = if_scsi8_0,
-               .groups = group_a | group_b | group_f, /* if_scsi8_0 and if_scsi8_1
-                                                         can be used simultaneously */
+               .name = "scsi8_0",
+               .groups = group_a | group_b | group_f,
+
+               .group_a = 0x7ffff,
+               .group_b = 0x0f,
+               .group_c = 0,
+               .group_d = 0,
+               .group_e = 0,
+               .group_f = 0x10,
+
                .gpio_g_in =  0x0000ffff,
                .gpio_g_out = 0x0000ffff,
                .gpio_b = 0x10
        },
        {
                .ioif = if_scsi8_1,
-               .groups = group_c | group_d | group_f, /* if_scsi8_0 and if_scsi8_1
-                                                         can be used simultaneously */
+               .name = "scsi8_1",
+               .groups = group_c | group_d | group_f,
+
+               .group_a = 0,
+               .group_b = 0,
+               .group_c = 0x0f,
+               .group_d = 0x7ffff,
+               .group_e = 0,
+               .group_f = 0x80,
+
                .gpio_g_in =  0xffff0000,
                .gpio_g_out = 0xffff0000,
                .gpio_b = 0x80
        },
        {
                .ioif = if_scsi_w,
+               .name = "scsi_w",
                .groups = group_a | group_b | group_d | group_f,
+
+               .group_a = 0x7ffff,
+               .group_b = 0x0f,
+               .group_c = 0,
+               .group_d = 0x601ff,
+               .group_e = 0,
+               .group_f = 0x90,
+
                .gpio_g_in =  0x01ffffff,
                .gpio_g_out = 0x07ffffff,
                .gpio_b = 0x80
        },
        {
                .ioif = if_ata,
+               .name = "ata",
                .groups = group_a | group_b | group_c | group_d,
+
+               .group_a = 0x7ffff,
+               .group_b = 0x0f,
+               .group_c = 0x0f,
+               .group_d = 0x7cfff,
+               .group_e = 0,
+               .group_f = 0,
+
                .gpio_g_in =  0xf9ffffff,
                .gpio_g_out = 0xffffffff,
                .gpio_b = 0x80
        },
        {
                .ioif = if_csp,
-               .groups = group_f, /* if_csp and if_i2c can be used simultaneously */
+               .name = "csp",
+               .groups = group_f,
+
+               .group_a = 0,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0,
+               .group_e = 0,
+               .group_f = 0xfc,
+
                .gpio_g_in =  0x00000000,
                .gpio_g_out = 0x00000000,
                .gpio_b = 0xfc
        },
        {
                .ioif = if_i2c,
-               .groups = group_f, /* if_csp and if_i2c can be used simultaneously */
+               .name = "i2c",
+               .groups = group_f,
+
+               .group_a = 0,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0,
+               .group_e = 0,
+               .group_f = 0x03,
+
                .gpio_g_in =  0x00000000,
                .gpio_g_out = 0x00000000,
                .gpio_b = 0x03
        },
        {
                .ioif = if_usb_1,
+               .name = "usb_1",
                .groups = group_e | group_f,
+
+               .group_a = 0,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0,
+               .group_e = 0x0f,
+               .group_f = 0x2c,
+
                .gpio_g_in =  0x00000000,
                .gpio_g_out = 0x00000000,
                .gpio_b = 0x2c
        },
        {
                .ioif = if_usb_2,
+               .name = "usb_2",
                .groups = group_d,
-               .gpio_g_in =  0x0e000000,
-               .gpio_g_out = 0x3c000000,
+
+               .group_a = 0,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0,
+               .group_e = 0x33e00,
+               .group_f = 0,
+
+               .gpio_g_in =  0x3e000000,
+               .gpio_g_out = 0x0c000000,
                .gpio_b = 0x00
        },
        /* GPIO pins */
        {
                .ioif = if_gpio_grp_a,
+               .name = "gpio_a",
                .groups = group_a,
+
+               .group_a = 0,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0,
+               .group_e = 0,
+               .group_f = 0,
+
                .gpio_g_in =  0x0000ff3f,
                .gpio_g_out = 0x0000ff3f,
                .gpio_b = 0x00
        },
        {
                .ioif = if_gpio_grp_b,
+               .name = "gpio_b",
                .groups = group_b,
+
+               .group_a = 0,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0,
+               .group_e = 0,
+               .group_f = 0,
+
                .gpio_g_in =  0x000000c0,
                .gpio_g_out = 0x000000c0,
                .gpio_b = 0x00
        },
        {
                .ioif = if_gpio_grp_c,
+               .name = "gpio_c",
                .groups = group_c,
+
+               .group_a = 0,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0,
+               .group_e = 0,
+               .group_f = 0,
+
                .gpio_g_in =  0xc0000000,
                .gpio_g_out = 0xc0000000,
                .gpio_b = 0x00
        },
        {
                .ioif = if_gpio_grp_d,
+               .name = "gpio_d",
                .groups = group_d,
+
+               .group_a = 0,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0,
+               .group_e = 0,
+               .group_f = 0,
+
                .gpio_g_in =  0x3fff0000,
                .gpio_g_out = 0x3fff0000,
                .gpio_b = 0x00
        },
        {
                .ioif = if_gpio_grp_e,
+               .name = "gpio_e",
                .groups = group_e,
+
+               .group_a = 0,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0,
+               .group_e = 0,
+               .group_f = 0,
+
                .gpio_g_in =  0x00000000,
                .gpio_g_out = 0x00000000,
                .gpio_b = 0x00
        },
        {
                .ioif = if_gpio_grp_f,
+               .name = "gpio_f",
                .groups = group_f,
+
+               .group_a = 0,
+               .group_b = 0,
+               .group_c = 0,
+               .group_d = 0,
+               .group_e = 0,
+               .group_f = 0,
+
                .gpio_g_in =  0x00000000,
                .gpio_g_out = 0x00000000,
                .gpio_b = 0xff
@@ -284,11 +542,13 @@ static struct interface interfaces[] = {
 
 static struct watcher *watchers = NULL;
 
+/* The pins that are free to use in the GPIO ports. */
 static unsigned int gpio_in_pins =  0xffffffff;
 static unsigned int gpio_out_pins = 0xffffffff;
 static unsigned char gpio_pb_pins = 0xff;
 static unsigned char gpio_pa_pins = 0xff;
 
+/* Identifiers for the owners of the GPIO pins. */
 static enum cris_io_interface gpio_pa_owners[8];
 static enum cris_io_interface gpio_pb_owners[8];
 static enum cris_io_interface gpio_pg_owners[32];
@@ -338,13 +598,15 @@ int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id
        struct if_group *grp;
        unsigned char group_set;
        unsigned long flags;
+       int res = 0;
 
        (void)cris_io_interface_init();
 
        DBG(printk("cris_request_io_interface(%d, \"%s\")\n", ioif, device_id));
 
        if ((ioif >= if_max_interfaces) || (ioif < 0)) {
-               printk(KERN_CRIT "cris_request_io_interface: Bad interface %u submitted for %s\n",
+               printk(KERN_CRIT "cris_request_io_interface: Bad interface "
+                       "%u submitted for %s\n",
                       ioif,
                       device_id);
                return -EINVAL;
@@ -353,59 +615,69 @@ int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id
        local_irq_save(flags);
 
        if (interfaces[ioif].used) {
-               local_irq_restore(flags);
-               printk(KERN_CRIT "cris_io_interface: Cannot allocate interface for %s, in use by %s\n",
+               printk(KERN_CRIT "cris_io_interface: Cannot allocate interface "
+                       "%s for %s, in use by %s\n",
+                      interfaces[ioif].name,
                       device_id,
                       interfaces[ioif].owner);
-               return -EBUSY;
+               res = -EBUSY;
+               goto exit;
        }
 
-       /* Check that all required groups are free before allocating, */
+       /* Check that all required pins in the used groups are free
+        * before allocating. */
        group_set = interfaces[ioif].groups;
        while (NULL != (grp = get_group(group_set))) {
-               if (grp->used) {
-                       if (grp->group == group_f) {
-                               if ((if_sync_serial_1 ==  ioif) ||
-                                   (if_sync_serial_3 ==  ioif)) {
-                                       if ((grp->owner != if_sync_serial_1) &&
-                                           (grp->owner != if_sync_serial_3)) {
-                                               local_irq_restore(flags);
-                                               return -EBUSY;
-                                       }
-                               } else if ((if_scsi8_0 == ioif) ||
-                                          (if_scsi8_1 == ioif)) {
-                                       if ((grp->owner != if_scsi8_0) &&
-                                           (grp->owner != if_scsi8_1)) {
-                                               local_irq_restore(flags);
-                                               return -EBUSY;
-                                       }
-                               }
-                       } else {
-                               local_irq_restore(flags);
-                               return -EBUSY;
-                       }
+               unsigned int if_group_use = 0;
+
+               switch (grp->group) {
+               case group_a:
+                       if_group_use = interfaces[ioif].group_a;
+                       break;
+               case group_b:
+                       if_group_use = interfaces[ioif].group_b;
+                       break;
+               case group_c:
+                       if_group_use = interfaces[ioif].group_c;
+                       break;
+               case group_d:
+                       if_group_use = interfaces[ioif].group_d;
+                       break;
+               case group_e:
+                       if_group_use = interfaces[ioif].group_e;
+                       break;
+               case group_f:
+                       if_group_use = interfaces[ioif].group_f;
+                       break;
+               default:
+                       BUG_ON(1);
                }
+
+               if (if_group_use & grp->used) {
+                       printk(KERN_INFO "cris_request_io_interface: group "
+                               "%s needed by %s not available\n",
+                               grp->name, interfaces[ioif].name);
+                       res = -EBUSY;
+                       goto exit;
+               }
+
                group_set = clear_group_from_set(group_set, grp);
        }
 
        /* Are the required GPIO pins available too? */
-       if (((interfaces[ioif].gpio_g_in & gpio_in_pins) != interfaces[ioif].gpio_g_in) ||
-           ((interfaces[ioif].gpio_g_out & gpio_out_pins) != interfaces[ioif].gpio_g_out) ||
-           ((interfaces[ioif].gpio_b & gpio_pb_pins) != interfaces[ioif].gpio_b)) {
-               local_irq_restore(flags);
-               printk(KERN_CRIT "cris_request_io_interface: Could not get required pins for interface %u\n",
-                      ioif);
-               return -EBUSY;
-       }
-
-       /* All needed I/O pins and pin groups are free, allocate. */
-       group_set = interfaces[ioif].groups;
-       while (NULL != (grp = get_group(group_set))) {
-               grp->used = 1;
-               grp->owner = ioif;
-               group_set = clear_group_from_set(group_set, grp);
+       if (((interfaces[ioif].gpio_g_in & gpio_in_pins) !=
+                       interfaces[ioif].gpio_g_in) ||
+               ((interfaces[ioif].gpio_g_out & gpio_out_pins) !=
+                       interfaces[ioif].gpio_g_out) ||
+               ((interfaces[ioif].gpio_b & gpio_pb_pins) !=
+                       interfaces[ioif].gpio_b)) {
+               printk(KERN_CRIT "cris_request_io_interface: Could not get "
+                       "required pins for interface %u\n", ioif);
+               res = -EBUSY;
+               goto exit;
        }
 
+       /* Check which registers need to be reconfigured. */
        gens = genconfig_shadow;
        gens_ii = gen_config_ii_shadow;
 
@@ -495,9 +767,43 @@ int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id
                set_gen_config = 0;
                break;
        default:
-               panic("cris_request_io_interface: Bad interface %u submitted for %s\n",
-                     ioif,
-                     device_id);
+               printk(KERN_INFO "cris_request_io_interface: Bad interface "
+                       "%u submitted for %s\n",
+                       ioif, device_id);
+               res = -EBUSY;
+               goto exit;
+       }
+
+       /* All needed I/O pins and pin groups are free, allocate. */
+       group_set = interfaces[ioif].groups;
+       while (NULL != (grp = get_group(group_set))) {
+               unsigned int if_group_use = 0;
+
+               switch (grp->group) {
+               case group_a:
+                       if_group_use = interfaces[ioif].group_a;
+                       break;
+               case group_b:
+                       if_group_use = interfaces[ioif].group_b;
+                       break;
+               case group_c:
+                       if_group_use = interfaces[ioif].group_c;
+                       break;
+               case group_d:
+                       if_group_use = interfaces[ioif].group_d;
+                       break;
+               case group_e:
+                       if_group_use = interfaces[ioif].group_e;
+                       break;
+               case group_f:
+                       if_group_use = interfaces[ioif].group_f;
+                       break;
+               default:
+                       BUG_ON(1);
+               }
+               grp->used |= if_group_use;
+
+               group_set = clear_group_from_set(group_set, grp);
        }
 
        interfaces[ioif].used = 1;
@@ -516,25 +822,28 @@ int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id
                *R_GEN_CONFIG_II = gen_config_ii_shadow;
        }
 
-       DBG(printk("GPIO pins: available before: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
-                  gpio_in_pins, gpio_out_pins, gpio_pb_pins));
-       DBG(printk("grabbing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
-                  interfaces[ioif].gpio_g_in,
-                  interfaces[ioif].gpio_g_out,
-                  interfaces[ioif].gpio_b));
+       DBG(printk(KERN_DEBUG "GPIO pins: available before: "
+               "g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
+               gpio_in_pins, gpio_out_pins, gpio_pb_pins));
+       DBG(printk(KERN_DEBUG
+               "grabbing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
+               interfaces[ioif].gpio_g_in,
+               interfaces[ioif].gpio_g_out,
+               interfaces[ioif].gpio_b));
 
        gpio_in_pins &= ~interfaces[ioif].gpio_g_in;
        gpio_out_pins &= ~interfaces[ioif].gpio_g_out;
        gpio_pb_pins &= ~interfaces[ioif].gpio_b;
 
-       DBG(printk("GPIO pins: available after: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
-                  gpio_in_pins, gpio_out_pins, gpio_pb_pins));
+       DBG(printk(KERN_DEBUG "GPIO pins: available after: "
+               "g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
+               gpio_in_pins, gpio_out_pins, gpio_pb_pins));
 
+exit:
        local_irq_restore(flags);
-
-       notify_watchers();
-
-       return 0;
+       if (res == 0)
+               notify_watchers();
+       return res;
 }
 
 
@@ -560,43 +869,35 @@ void cris_free_io_interface(enum cris_io_interface ioif)
        }
        group_set = interfaces[ioif].groups;
        while (NULL != (grp = get_group(group_set))) {
-               if (grp->group == group_f) {
-                       switch (ioif)
-                       {
-                       case if_sync_serial_1:
-                               if ((grp->owner == if_sync_serial_1) &&
-                                   interfaces[if_sync_serial_3].used) {
-                                       grp->owner = if_sync_serial_3;
-                               } else
-                                       grp->used = 0;
-                               break;
-                       case if_sync_serial_3:
-                               if ((grp->owner == if_sync_serial_3) &&
-                                   interfaces[if_sync_serial_1].used) {
-                                       grp->owner = if_sync_serial_1;
-                               } else
-                                       grp->used = 0;
-                               break;
-                       case if_scsi8_0:
-                               if ((grp->owner == if_scsi8_0) &&
-                                   interfaces[if_scsi8_1].used) {
-                                       grp->owner = if_scsi8_1;
-                               } else
-                                       grp->used = 0;
-                               break;
-                       case if_scsi8_1:
-                               if ((grp->owner == if_scsi8_1) &&
-                                   interfaces[if_scsi8_0].used) {
-                                       grp->owner = if_scsi8_0;
-                               } else
-                                       grp->used = 0;
-                               break;
-                       default:
-                               grp->used = 0;
-                       }
-               } else {
-                       grp->used = 0;
+               unsigned int if_group_use = 0;
+
+               switch (grp->group) {
+               case group_a:
+                       if_group_use = interfaces[ioif].group_a;
+                       break;
+               case group_b:
+                       if_group_use = interfaces[ioif].group_b;
+                       break;
+               case group_c:
+                       if_group_use = interfaces[ioif].group_c;
+                       break;
+               case group_d:
+                       if_group_use = interfaces[ioif].group_d;
+                       break;
+               case group_e:
+                       if_group_use = interfaces[ioif].group_e;
+                       break;
+               case group_f:
+                       if_group_use = interfaces[ioif].group_f;
+                       break;
+               default:
+                       BUG_ON(1);
                }
+
+               if ((grp->used & if_group_use) != if_group_use)
+                       BUG_ON(1);
+               grp->used = grp->used & ~if_group_use;
+
                group_set = clear_group_from_set(group_set, grp);
        }
        interfaces[ioif].used = 0;