This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / drivers / ieee1394 / ieee1394_core.c
index 65a796e..c6fa4c8 100644 (file)
@@ -400,31 +400,35 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
 void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
                       int ackcode)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->pending_packet_queue.lock, flags);
+
        packet->ack_code = ackcode;
 
-       if (packet->no_waiter) {
-               /* must not have a tlabel allocated */
+       if (packet->no_waiter || packet->state == hpsb_complete) {
+               /* if packet->no_waiter, must not have a tlabel allocated */
+               spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
                hpsb_free_packet(packet);
                return;
        }
 
+       atomic_dec(&packet->refcnt);    /* drop HC's reference */
+       /* here the packet must be on the host->pending_packet_queue */
+
        if (ackcode != ACK_PENDING || !packet->expect_response) {
-               atomic_dec(&packet->refcnt);
-               skb_unlink(packet->skb);
                packet->state = hpsb_complete;
+               __skb_unlink(packet->skb, &host->pending_packet_queue);
+               spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
                queue_packet_complete(packet);
                return;
        }
 
-       if (packet->state == hpsb_complete) {
-               hpsb_free_packet(packet);
-               return;
-       }
-
-       atomic_dec(&packet->refcnt);
        packet->state = hpsb_pending;
        packet->sendtime = jiffies;
 
+       spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
+
        mod_timer(&host->timeout, jiffies + host->timeout_interval);
 }
 
@@ -658,14 +662,13 @@ static void handle_packet_response(struct hpsb_host *host, int tcode,
         }
 
         if (!tcode_match) {
+               spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
                 HPSB_INFO("unsolicited response packet received - tcode mismatch");
                 dump_packet("contents:", data, 16);
-               spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
                 return;
         }
 
        __skb_unlink(skb, skb->list);
-       spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
 
        if (packet->state == hpsb_queued) {
                packet->sendtime = jiffies;
@@ -673,6 +676,8 @@ static void handle_packet_response(struct hpsb_host *host, int tcode,
        }
 
        packet->state = hpsb_complete;
+       spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
+
        queue_packet_complete(packet);
 }
 
@@ -1002,6 +1007,10 @@ static DECLARE_MUTEX_LOCKED(khpsbpkt_sig);
 
 static void queue_packet_complete(struct hpsb_packet *packet)
 {
+       if (packet->no_waiter) {
+               hpsb_free_packet(packet);
+               return;
+       }
        if (packet->complete_routine != NULL) {
                skb_queue_tail(&hpsbpkt_queue, packet->skb);
 
@@ -1042,10 +1051,11 @@ static int hpsbpkt_thread(void *__hi)
 
 static int __init ieee1394_init(void)
 {
-       int i;
+       int i, ret;
 
        skb_queue_head_init(&hpsbpkt_queue);
 
+       /* non-fatal error */
        if (hpsb_init_config_roms()) {
                HPSB_ERR("Failed to initialize some config rom entries.\n");
                HPSB_ERR("Some features may not be available\n");
@@ -1054,32 +1064,85 @@ static int __init ieee1394_init(void)
        khpsbpkt_pid = kernel_thread(hpsbpkt_thread, NULL, CLONE_KERNEL);
        if (khpsbpkt_pid < 0) {
                HPSB_ERR("Failed to start hpsbpkt thread!\n");
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto exit_cleanup_config_roms;
        }
 
-       devfs_mk_dir("ieee1394");
-
        if (register_chrdev_region(IEEE1394_CORE_DEV, 256, "ieee1394")) {
                HPSB_ERR("unable to register character device major %d!\n", IEEE1394_MAJOR);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto exit_release_kernel_thread;
        }
 
-       devfs_mk_dir("ieee1394");
+       /* actually this is a non-fatal error */
+       ret = devfs_mk_dir("ieee1394");
+       if (ret < 0) {
+               HPSB_ERR("unable to make devfs dir for device major %d!\n", IEEE1394_MAJOR);
+               goto release_chrdev;
+       }
 
-       bus_register(&ieee1394_bus_type);
-       for (i = 0; fw_bus_attrs[i]; i++)
-               bus_create_file(&ieee1394_bus_type, fw_bus_attrs[i]);
-       class_register(&hpsb_host_class);
+       ret = bus_register(&ieee1394_bus_type);
+       if (ret < 0) {
+               HPSB_INFO("bus register failed");
+               goto release_devfs;
+       }
 
-       if (init_csr())
-               return -ENOMEM;
+       for (i = 0; fw_bus_attrs[i]; i++) {
+               ret = bus_create_file(&ieee1394_bus_type, fw_bus_attrs[i]);
+               if (ret < 0) {
+                       while (i >= 0) {
+                               bus_remove_file(&ieee1394_bus_type,
+                                               fw_bus_attrs[i--]);
+                       }
+                       bus_unregister(&ieee1394_bus_type);
+                       goto release_devfs;
+               }
+       }
 
-       if (!disable_nodemgr)
-               init_ieee1394_nodemgr();
-       else
+       ret = class_register(&hpsb_host_class);
+       if (ret < 0)
+               goto release_all_bus;
+
+       ret = init_csr();
+       if (ret) {
+               HPSB_INFO("init csr failed");
+               ret = -ENOMEM;
+               goto release_class;
+       }
+
+       if (disable_nodemgr) {
                HPSB_INFO("nodemgr functionality disabled");
+               return 0;
+       }
+
+       ret = init_ieee1394_nodemgr();
+       if (ret < 0) {
+               HPSB_INFO("init nodemgr failed");
+               goto cleanup_csr;
+       }
 
        return 0;
+
+cleanup_csr:
+       cleanup_csr();
+release_class:
+       class_unregister(&hpsb_host_class);
+release_all_bus:
+       for (i = 0; fw_bus_attrs[i]; i++)
+               bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
+       bus_unregister(&ieee1394_bus_type);
+release_devfs:
+       devfs_remove("ieee1394");
+release_chrdev:
+       unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
+exit_release_kernel_thread:
+       if (khpsbpkt_pid >= 0) {
+               kill_proc(khpsbpkt_pid, SIGTERM, 1);
+               wait_for_completion(&khpsbpkt_complete);
+       }
+exit_cleanup_config_roms:
+       hpsb_cleanup_config_roms();
+       return ret;
 }
 
 static void __exit ieee1394_cleanup(void)