diff options
author | Dhananjay Phadke <dhananjay@netxen.com> | 2009-03-09 04:50:54 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-10 08:10:02 -0400 |
commit | 9f5bc7f1908665d7cf379f698c7bdc53bc10da85 (patch) | |
tree | d55c0e6646af2c1f4093d3909329752110c3a54b /drivers/net/netxen | |
parent | d32cc3d24eace8a271a39ffe8aeae1861f400d2d (diff) |
netxen: refactor netdev open close
rearrange open and close into hardware attach(), detach() and
nic up() and down(). this will be used for suspend/resume
subsequently.
Signed-off-by: Dhananjay Phadke <dhananjay@netxen.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/netxen')
-rw-r--r-- | drivers/net/netxen/netxen_nic_main.c | 302 |
1 files changed, 166 insertions, 136 deletions
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index c9519843f8c..2953a83bc85 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c | |||
@@ -94,20 +94,6 @@ static struct pci_device_id netxen_pci_tbl[] __devinitdata = { | |||
94 | 94 | ||
95 | MODULE_DEVICE_TABLE(pci, netxen_pci_tbl); | 95 | MODULE_DEVICE_TABLE(pci, netxen_pci_tbl); |
96 | 96 | ||
97 | /* | ||
98 | * In netxen_nic_down(), we must wait for any pending callback requests into | ||
99 | * netxen_watchdog_task() to complete; eg otherwise the watchdog_timer could be | ||
100 | * reenabled right after it is deleted in netxen_nic_down(). | ||
101 | * FLUSH_SCHEDULED_WORK() does this synchronization. | ||
102 | * | ||
103 | * Normally, schedule_work()/flush_scheduled_work() could have worked, but | ||
104 | * netxen_nic_close() is invoked with kernel rtnl lock held. netif_carrier_off() | ||
105 | * call in netxen_nic_close() triggers a schedule_work(&linkwatch_work), and a | ||
106 | * subsequent call to flush_scheduled_work() in netxen_nic_down() would cause | ||
107 | * linkwatch_event() to be executed which also attempts to acquire the rtnl | ||
108 | * lock thus causing a deadlock. | ||
109 | */ | ||
110 | |||
111 | static struct workqueue_struct *netxen_workq; | 97 | static struct workqueue_struct *netxen_workq; |
112 | #define SCHEDULE_WORK(tp) queue_work(netxen_workq, tp) | 98 | #define SCHEDULE_WORK(tp) queue_work(netxen_workq, tp) |
113 | #define FLUSH_SCHEDULED_WORK() flush_workqueue(netxen_workq) | 99 | #define FLUSH_SCHEDULED_WORK() flush_workqueue(netxen_workq) |
@@ -722,6 +708,163 @@ netxen_start_firmware(struct netxen_adapter *adapter) | |||
722 | return 0; | 708 | return 0; |
723 | } | 709 | } |
724 | 710 | ||
711 | static int | ||
712 | netxen_nic_request_irq(struct netxen_adapter *adapter) | ||
713 | { | ||
714 | irq_handler_t handler; | ||
715 | unsigned long flags = IRQF_SAMPLE_RANDOM; | ||
716 | struct net_device *netdev = adapter->netdev; | ||
717 | |||
718 | if ((adapter->msi_mode != MSI_MODE_MULTIFUNC) || | ||
719 | (adapter->intr_scheme != INTR_SCHEME_PERPORT)) { | ||
720 | printk(KERN_ERR "%s: Firmware interrupt scheme is " | ||
721 | "incompatible with driver\n", | ||
722 | netdev->name); | ||
723 | adapter->driver_mismatch = 1; | ||
724 | return -EINVAL; | ||
725 | } | ||
726 | |||
727 | if (adapter->flags & NETXEN_NIC_MSIX_ENABLED) | ||
728 | handler = netxen_msix_intr; | ||
729 | else if (adapter->flags & NETXEN_NIC_MSI_ENABLED) | ||
730 | handler = netxen_msi_intr; | ||
731 | else { | ||
732 | flags |= IRQF_SHARED; | ||
733 | handler = netxen_intr; | ||
734 | } | ||
735 | adapter->irq = netdev->irq; | ||
736 | |||
737 | return request_irq(adapter->irq, handler, | ||
738 | flags, netdev->name, adapter); | ||
739 | } | ||
740 | |||
741 | static int | ||
742 | netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) | ||
743 | { | ||
744 | int err; | ||
745 | |||
746 | err = adapter->init_port(adapter, adapter->physical_port); | ||
747 | if (err) { | ||
748 | printk(KERN_ERR "%s: Failed to initialize port %d\n", | ||
749 | netxen_nic_driver_name, adapter->portnum); | ||
750 | return err; | ||
751 | } | ||
752 | adapter->macaddr_set(adapter, netdev->dev_addr); | ||
753 | |||
754 | netxen_nic_set_link_parameters(adapter); | ||
755 | |||
756 | netxen_set_multicast_list(netdev); | ||
757 | if (adapter->set_mtu) | ||
758 | adapter->set_mtu(adapter, netdev->mtu); | ||
759 | |||
760 | adapter->ahw.linkup = 0; | ||
761 | mod_timer(&adapter->watchdog_timer, jiffies); | ||
762 | |||
763 | napi_enable(&adapter->napi); | ||
764 | netxen_nic_enable_int(adapter); | ||
765 | |||
766 | return 0; | ||
767 | } | ||
768 | |||
769 | static void | ||
770 | netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) | ||
771 | { | ||
772 | netif_carrier_off(netdev); | ||
773 | netif_stop_queue(netdev); | ||
774 | napi_disable(&adapter->napi); | ||
775 | |||
776 | if (adapter->stop_port) | ||
777 | adapter->stop_port(adapter); | ||
778 | |||
779 | netxen_nic_disable_int(adapter); | ||
780 | |||
781 | netxen_release_tx_buffers(adapter); | ||
782 | |||
783 | FLUSH_SCHEDULED_WORK(); | ||
784 | del_timer_sync(&adapter->watchdog_timer); | ||
785 | } | ||
786 | |||
787 | |||
788 | static int | ||
789 | netxen_nic_attach(struct netxen_adapter *adapter) | ||
790 | { | ||
791 | struct net_device *netdev = adapter->netdev; | ||
792 | struct pci_dev *pdev = adapter->pdev; | ||
793 | int err, ctx, ring; | ||
794 | |||
795 | err = netxen_init_firmware(adapter); | ||
796 | if (err != 0) { | ||
797 | printk(KERN_ERR "Failed to init firmware\n"); | ||
798 | return -EIO; | ||
799 | } | ||
800 | |||
801 | if (adapter->fw_major < 4) | ||
802 | adapter->max_rds_rings = 3; | ||
803 | else | ||
804 | adapter->max_rds_rings = 2; | ||
805 | |||
806 | err = netxen_alloc_sw_resources(adapter); | ||
807 | if (err) { | ||
808 | printk(KERN_ERR "%s: Error in setting sw resources\n", | ||
809 | netdev->name); | ||
810 | return err; | ||
811 | } | ||
812 | |||
813 | netxen_nic_clear_stats(adapter); | ||
814 | |||
815 | err = netxen_alloc_hw_resources(adapter); | ||
816 | if (err) { | ||
817 | printk(KERN_ERR "%s: Error in setting hw resources\n", | ||
818 | netdev->name); | ||
819 | goto err_out_free_sw; | ||
820 | } | ||
821 | |||
822 | if (adapter->fw_major < 4) { | ||
823 | adapter->crb_addr_cmd_producer = | ||
824 | crb_cmd_producer[adapter->portnum]; | ||
825 | adapter->crb_addr_cmd_consumer = | ||
826 | crb_cmd_consumer[adapter->portnum]; | ||
827 | |||
828 | netxen_nic_update_cmd_producer(adapter, 0); | ||
829 | netxen_nic_update_cmd_consumer(adapter, 0); | ||
830 | } | ||
831 | |||
832 | for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { | ||
833 | for (ring = 0; ring < adapter->max_rds_rings; ring++) | ||
834 | netxen_post_rx_buffers(adapter, ctx, ring); | ||
835 | } | ||
836 | |||
837 | err = netxen_nic_request_irq(adapter); | ||
838 | if (err) { | ||
839 | dev_err(&pdev->dev, "%s: failed to setup interrupt\n", | ||
840 | netdev->name); | ||
841 | goto err_out_free_rxbuf; | ||
842 | } | ||
843 | |||
844 | adapter->is_up = NETXEN_ADAPTER_UP_MAGIC; | ||
845 | return 0; | ||
846 | |||
847 | err_out_free_rxbuf: | ||
848 | netxen_release_rx_buffers(adapter); | ||
849 | netxen_free_hw_resources(adapter); | ||
850 | err_out_free_sw: | ||
851 | netxen_free_sw_resources(adapter); | ||
852 | return err; | ||
853 | } | ||
854 | |||
855 | static void | ||
856 | netxen_nic_detach(struct netxen_adapter *adapter) | ||
857 | { | ||
858 | if (adapter->irq) | ||
859 | free_irq(adapter->irq, adapter); | ||
860 | |||
861 | netxen_release_rx_buffers(adapter); | ||
862 | netxen_free_hw_resources(adapter); | ||
863 | netxen_free_sw_resources(adapter); | ||
864 | |||
865 | adapter->is_up = 0; | ||
866 | } | ||
867 | |||
725 | static int __devinit | 868 | static int __devinit |
726 | netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 869 | netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
727 | { | 870 | { |
@@ -973,9 +1116,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) | |||
973 | unregister_netdev(netdev); | 1116 | unregister_netdev(netdev); |
974 | 1117 | ||
975 | if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) { | 1118 | if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) { |
976 | netxen_free_hw_resources(adapter); | 1119 | netxen_nic_detach(adapter); |
977 | netxen_release_rx_buffers(adapter); | ||
978 | netxen_free_sw_resources(adapter); | ||
979 | 1120 | ||
980 | if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) | 1121 | if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) |
981 | netxen_p3_free_mac_list(adapter); | 1122 | netxen_p3_free_mac_list(adapter); |
@@ -984,9 +1125,6 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) | |||
984 | if (adapter->portnum == 0) | 1125 | if (adapter->portnum == 0) |
985 | netxen_free_adapter_offload(adapter); | 1126 | netxen_free_adapter_offload(adapter); |
986 | 1127 | ||
987 | if (adapter->irq) | ||
988 | free_irq(adapter->irq, adapter); | ||
989 | |||
990 | netxen_teardown_intr(adapter); | 1128 | netxen_teardown_intr(adapter); |
991 | 1129 | ||
992 | netxen_cleanup_pci_map(adapter); | 1130 | netxen_cleanup_pci_map(adapter); |
@@ -998,125 +1136,30 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) | |||
998 | free_netdev(netdev); | 1136 | free_netdev(netdev); |
999 | } | 1137 | } |
1000 | 1138 | ||
1001 | /* | ||
1002 | * Called when a network interface is made active | ||
1003 | * @returns 0 on success, negative value on failure | ||
1004 | */ | ||
1005 | static int netxen_nic_open(struct net_device *netdev) | 1139 | static int netxen_nic_open(struct net_device *netdev) |
1006 | { | 1140 | { |
1007 | struct netxen_adapter *adapter = netdev_priv(netdev); | 1141 | struct netxen_adapter *adapter = netdev_priv(netdev); |
1008 | int err = 0; | 1142 | int err = 0; |
1009 | int ctx, ring; | ||
1010 | irq_handler_t handler; | ||
1011 | unsigned long flags = IRQF_SAMPLE_RANDOM; | ||
1012 | 1143 | ||
1013 | if (adapter->driver_mismatch) | 1144 | if (adapter->driver_mismatch) |
1014 | return -EIO; | 1145 | return -EIO; |
1015 | 1146 | ||
1016 | if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) { | 1147 | if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) { |
1017 | err = netxen_init_firmware(adapter); | 1148 | err = netxen_nic_attach(adapter); |
1018 | if (err != 0) { | 1149 | if (err) |
1019 | printk(KERN_ERR "Failed to init firmware\n"); | ||
1020 | return -EIO; | ||
1021 | } | ||
1022 | |||
1023 | if (adapter->fw_major < 4) | ||
1024 | adapter->max_rds_rings = 3; | ||
1025 | else | ||
1026 | adapter->max_rds_rings = 2; | ||
1027 | |||
1028 | err = netxen_alloc_sw_resources(adapter); | ||
1029 | if (err) { | ||
1030 | printk(KERN_ERR "%s: Error in setting sw resources\n", | ||
1031 | netdev->name); | ||
1032 | return err; | 1150 | return err; |
1033 | } | ||
1034 | |||
1035 | netxen_nic_clear_stats(adapter); | ||
1036 | |||
1037 | err = netxen_alloc_hw_resources(adapter); | ||
1038 | if (err) { | ||
1039 | printk(KERN_ERR "%s: Error in setting hw resources\n", | ||
1040 | netdev->name); | ||
1041 | goto err_out_free_sw; | ||
1042 | } | ||
1043 | |||
1044 | if ((adapter->msi_mode != MSI_MODE_MULTIFUNC) || | ||
1045 | (adapter->intr_scheme != INTR_SCHEME_PERPORT)) { | ||
1046 | printk(KERN_ERR "%s: Firmware interrupt scheme is " | ||
1047 | "incompatible with driver\n", | ||
1048 | netdev->name); | ||
1049 | adapter->driver_mismatch = 1; | ||
1050 | goto err_out_free_hw; | ||
1051 | } | ||
1052 | |||
1053 | if (adapter->fw_major < 4) { | ||
1054 | adapter->crb_addr_cmd_producer = | ||
1055 | crb_cmd_producer[adapter->portnum]; | ||
1056 | adapter->crb_addr_cmd_consumer = | ||
1057 | crb_cmd_consumer[adapter->portnum]; | ||
1058 | |||
1059 | netxen_nic_update_cmd_producer(adapter, 0); | ||
1060 | netxen_nic_update_cmd_consumer(adapter, 0); | ||
1061 | } | ||
1062 | |||
1063 | for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { | ||
1064 | for (ring = 0; ring < adapter->max_rds_rings; ring++) | ||
1065 | netxen_post_rx_buffers(adapter, ctx, ring); | ||
1066 | } | ||
1067 | if (adapter->flags & NETXEN_NIC_MSIX_ENABLED) | ||
1068 | handler = netxen_msix_intr; | ||
1069 | else if (adapter->flags & NETXEN_NIC_MSI_ENABLED) | ||
1070 | handler = netxen_msi_intr; | ||
1071 | else { | ||
1072 | flags |= IRQF_SHARED; | ||
1073 | handler = netxen_intr; | ||
1074 | } | ||
1075 | adapter->irq = netdev->irq; | ||
1076 | err = request_irq(adapter->irq, handler, | ||
1077 | flags, netdev->name, adapter); | ||
1078 | if (err) { | ||
1079 | printk(KERN_ERR "request_irq failed with: %d\n", err); | ||
1080 | goto err_out_free_rxbuf; | ||
1081 | } | ||
1082 | |||
1083 | adapter->is_up = NETXEN_ADAPTER_UP_MAGIC; | ||
1084 | } | 1151 | } |
1085 | 1152 | ||
1086 | /* Done here again so that even if phantom sw overwrote it, | 1153 | err = netxen_nic_up(adapter, netdev); |
1087 | * we set it */ | 1154 | if (err) |
1088 | err = adapter->init_port(adapter, adapter->physical_port); | 1155 | goto err_out; |
1089 | if (err) { | ||
1090 | printk(KERN_ERR "%s: Failed to initialize port %d\n", | ||
1091 | netxen_nic_driver_name, adapter->portnum); | ||
1092 | goto err_out_free_irq; | ||
1093 | } | ||
1094 | adapter->macaddr_set(adapter, netdev->dev_addr); | ||
1095 | |||
1096 | netxen_nic_set_link_parameters(adapter); | ||
1097 | |||
1098 | netxen_set_multicast_list(netdev); | ||
1099 | if (adapter->set_mtu) | ||
1100 | adapter->set_mtu(adapter, netdev->mtu); | ||
1101 | |||
1102 | adapter->ahw.linkup = 0; | ||
1103 | mod_timer(&adapter->watchdog_timer, jiffies); | ||
1104 | |||
1105 | napi_enable(&adapter->napi); | ||
1106 | netxen_nic_enable_int(adapter); | ||
1107 | 1156 | ||
1108 | netif_start_queue(netdev); | 1157 | netif_start_queue(netdev); |
1109 | 1158 | ||
1110 | return 0; | 1159 | return 0; |
1111 | 1160 | ||
1112 | err_out_free_irq: | 1161 | err_out: |
1113 | free_irq(adapter->irq, adapter); | 1162 | netxen_nic_detach(adapter); |
1114 | err_out_free_rxbuf: | ||
1115 | netxen_release_rx_buffers(adapter); | ||
1116 | err_out_free_hw: | ||
1117 | netxen_free_hw_resources(adapter); | ||
1118 | err_out_free_sw: | ||
1119 | netxen_free_sw_resources(adapter); | ||
1120 | return err; | 1163 | return err; |
1121 | } | 1164 | } |
1122 | 1165 | ||
@@ -1127,20 +1170,7 @@ static int netxen_nic_close(struct net_device *netdev) | |||
1127 | { | 1170 | { |
1128 | struct netxen_adapter *adapter = netdev_priv(netdev); | 1171 | struct netxen_adapter *adapter = netdev_priv(netdev); |
1129 | 1172 | ||
1130 | netif_carrier_off(netdev); | 1173 | netxen_nic_down(adapter, netdev); |
1131 | netif_stop_queue(netdev); | ||
1132 | napi_disable(&adapter->napi); | ||
1133 | |||
1134 | if (adapter->stop_port) | ||
1135 | adapter->stop_port(adapter); | ||
1136 | |||
1137 | netxen_nic_disable_int(adapter); | ||
1138 | |||
1139 | netxen_release_tx_buffers(adapter); | ||
1140 | |||
1141 | FLUSH_SCHEDULED_WORK(); | ||
1142 | del_timer_sync(&adapter->watchdog_timer); | ||
1143 | |||
1144 | return 0; | 1174 | return 0; |
1145 | } | 1175 | } |
1146 | 1176 | ||