ide: fix IDE port slots reservation and freeing (take 2)
authorBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Wed, 23 Jul 2008 17:55:57 +0000 (19:55 +0200)
committerBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Wed, 23 Jul 2008 17:55:57 +0000 (19:55 +0200)
* Make ide_find_port_slot() return port slot index.

* Add ide_free_port_slot() helper.

* Move ide_init_port_data() call and error printk() from
  ide_find_port_slot() to ide_host_alloc_all().

* Make ide_{find,free}_port_slot() take ide_cfg_mtx mutex
  and convert them use ide_indexes bitmap to keep track of
  reserved port slots.

* Don't set hwif->chipset in ide_host_alloc_all() as it is
  no longer necessary.

v2:
* Pass the correct slot index to ide_init_port_data().

Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
drivers/ide/ide-probe.c

index 32261282371ad55711b59f6ef539bc1bde9986ce..fdf00cde9fcecf46f2138859c0cf1ba16fcdb87d 100644 (file)
@@ -1470,18 +1470,20 @@ static int ide_sysfs_register_port(ide_hwif_t *hwif)
        return rc;
 }
 
+static unsigned int ide_indexes;
+
 /**
- *     ide_find_port_slot      -       find free ide_hwifs[] slot
+ *     ide_find_port_slot      -       find free port slot
  *     @d: IDE port info
  *
- *     Return the new hwif.  If we are out of free slots return NULL.
+ *     Return the new port slot index or -ENOENT if we are out of free slots.
  */
 
-static ide_hwif_t *ide_find_port_slot(const struct ide_port_info *d)
+static int ide_find_port_slot(const struct ide_port_info *d)
 {
-       ide_hwif_t *hwif;
-       int i;
+       int idx = -ENOENT;
        u8 bootable = (d && (d->host_flags & IDE_HFLAG_NON_BOOTABLE)) ? 0 : 1;
+       u8 i = (d && (d->host_flags & IDE_HFLAG_QD_2ND_PORT)) ? 1 : 0;;
 
        /*
         * Claim an unassigned slot.
@@ -1493,35 +1495,33 @@ static ide_hwif_t *ide_find_port_slot(const struct ide_port_info *d)
         * Unless there is a bootable card that does not use the standard
         * ports 0x1f0/0x170 (the ide0/ide1 defaults).
         */
-       if (bootable) {
-               i = (d && (d->host_flags & IDE_HFLAG_QD_2ND_PORT)) ? 1 : 0;
-
-               for (; i < MAX_HWIFS; i++) {
-                       hwif = &ide_hwifs[i];
-                       if (hwif->chipset == ide_unknown)
-                               goto out_found;
-               }
+       mutex_lock(&ide_cfg_mtx);
+       if (MAX_HWIFS == 1) {
+               if (ide_indexes == 0 && i == 0)
+                       idx = 1;
        } else {
-               for (i = 2; i < MAX_HWIFS; i++) {
-                       hwif = &ide_hwifs[i];
-                       if (hwif->chipset == ide_unknown)
-                               goto out_found;
-               }
-               for (i = 0; i < 2 && i < MAX_HWIFS; i++) {
-                       hwif = &ide_hwifs[i];
-                       if (hwif->chipset == ide_unknown)
-                               goto out_found;
+               if (bootable) {
+                       if ((ide_indexes | i) != (1 << MAX_HWIFS) - 1)
+                               idx = ffz(ide_indexes | i);
+               } else {
+                       if ((ide_indexes | 3) != (1 << MAX_HWIFS) - 1)
+                               idx = ffz(ide_indexes | 3);
+                       else if ((ide_indexes & 3) != 3)
+                               idx = ffz(ide_indexes);
                }
        }
+       if (idx >= 0)
+               ide_indexes |= (1 << idx);
+       mutex_unlock(&ide_cfg_mtx);
 
-       printk(KERN_ERR "%s: no free slot for interface\n",
-                       d ? d->name : "ide");
-
-       return NULL;
+       return idx;
+}
 
-out_found:
-       ide_init_port_data(hwif, i);
-       return hwif;
+static void ide_free_port_slot(int idx)
+{
+       mutex_lock(&ide_cfg_mtx);
+       ide_indexes &= ~(1 << idx);
+       mutex_unlock(&ide_cfg_mtx);
 }
 
 struct ide_host *ide_host_alloc_all(const struct ide_port_info *d,
@@ -1536,17 +1536,24 @@ struct ide_host *ide_host_alloc_all(const struct ide_port_info *d,
 
        for (i = 0; i < MAX_HWIFS; i++) {
                ide_hwif_t *hwif;
+               int idx;
 
                if (hws[i] == NULL)
                        continue;
 
-               hwif = ide_find_port_slot(d);
-               if (hwif) {
-                       hwif->chipset = hws[i]->chipset;
-
-                       host->ports[i] = hwif;
-                       host->n_ports++;
+               idx = ide_find_port_slot(d);
+               if (idx < 0) {
+                       printk(KERN_ERR "%s: no free slot for interface\n",
+                                       d ? d->name : "ide");
+                       continue;
                }
+
+               hwif = &ide_hwifs[idx];
+
+               ide_init_port_data(hwif, idx);
+
+               host->ports[i] = hwif;
+               host->n_ports++;
        }
 
        if (host->n_ports == 0) {
@@ -1695,11 +1702,17 @@ EXPORT_SYMBOL_GPL(ide_host_add);
 
 void ide_host_remove(struct ide_host *host)
 {
+       ide_hwif_t *hwif;
        int i;
 
        for (i = 0; i < MAX_HWIFS; i++) {
-               if (host->ports[i])
-                       ide_unregister(host->ports[i]);
+               hwif = host->ports[i];
+
+               if (hwif == NULL)
+                       continue;
+
+               ide_unregister(hwif);
+               ide_free_port_slot(hwif->index);
        }
 
        kfree(host);