diff options
author | Dhananjay Phadke <dhananjay@netxen.com> | 2008-03-17 22:59:49 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2008-03-25 23:16:16 -0400 |
commit | 05aaa02d799e8e9548d57ac92fcb05e783027341 (patch) | |
tree | becfc839727f798364c13549e332de0830d7676f /drivers/net/netxen/netxen_nic_main.c | |
parent | 443be7960be77f3345b44491c700ae4471b0fe57 (diff) |
netxen: napi and irq cleanup
o separate and simpler irq handler for msi interrupts, avoids few checks
than legacy mode.
o avoid redudant tx_has_work() and rx_has_work() checks in interrupt
and napi, which can uncork irq based on racy (lockless) access to tx
and rx ring indices. If we get interrupt, there's sufficient reason to
schedule napi.
o replenish rx ring more often, remove self-imposed threshold rcv_free
that prevents posting rx desc to card. This improves performance in
low memory.
Signed-off-by: Dhananjay Phadke <dhananjay@netxen.com>
Tested-by: Vernon Mauery <mauery@us.ibm.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/netxen/netxen_nic_main.c')
-rw-r--r-- | drivers/net/netxen/netxen_nic_main.c | 113 |
1 files changed, 39 insertions, 74 deletions
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index cd665da85c7..95955204ef5 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c | |||
@@ -63,12 +63,12 @@ static int netxen_nic_xmit_frame(struct sk_buff *, struct net_device *); | |||
63 | static void netxen_tx_timeout(struct net_device *netdev); | 63 | static void netxen_tx_timeout(struct net_device *netdev); |
64 | static void netxen_tx_timeout_task(struct work_struct *work); | 64 | static void netxen_tx_timeout_task(struct work_struct *work); |
65 | static void netxen_watchdog(unsigned long); | 65 | static void netxen_watchdog(unsigned long); |
66 | static int netxen_handle_int(struct netxen_adapter *, struct net_device *); | ||
67 | static int netxen_nic_poll(struct napi_struct *napi, int budget); | 66 | static int netxen_nic_poll(struct napi_struct *napi, int budget); |
68 | #ifdef CONFIG_NET_POLL_CONTROLLER | 67 | #ifdef CONFIG_NET_POLL_CONTROLLER |
69 | static void netxen_nic_poll_controller(struct net_device *netdev); | 68 | static void netxen_nic_poll_controller(struct net_device *netdev); |
70 | #endif | 69 | #endif |
71 | static irqreturn_t netxen_intr(int irq, void *data); | 70 | static irqreturn_t netxen_intr(int irq, void *data); |
71 | static irqreturn_t netxen_msi_intr(int irq, void *data); | ||
72 | 72 | ||
73 | int physical_port[] = {0, 1, 2, 3}; | 73 | int physical_port[] = {0, 1, 2, 3}; |
74 | 74 | ||
@@ -405,7 +405,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
405 | netdev->set_mac_address = netxen_nic_set_mac; | 405 | netdev->set_mac_address = netxen_nic_set_mac; |
406 | netdev->change_mtu = netxen_nic_change_mtu; | 406 | netdev->change_mtu = netxen_nic_change_mtu; |
407 | netdev->tx_timeout = netxen_tx_timeout; | 407 | netdev->tx_timeout = netxen_tx_timeout; |
408 | netdev->watchdog_timeo = HZ; | 408 | netdev->watchdog_timeo = 2*HZ; |
409 | 409 | ||
410 | netxen_nic_change_mtu(netdev, netdev->mtu); | 410 | netxen_nic_change_mtu(netdev, netdev->mtu); |
411 | 411 | ||
@@ -823,6 +823,8 @@ static int netxen_nic_open(struct net_device *netdev) | |||
823 | struct netxen_adapter *adapter = (struct netxen_adapter *)netdev->priv; | 823 | struct netxen_adapter *adapter = (struct netxen_adapter *)netdev->priv; |
824 | int err = 0; | 824 | int err = 0; |
825 | int ctx, ring; | 825 | int ctx, ring; |
826 | irq_handler_t handler; | ||
827 | unsigned long flags = IRQF_SAMPLE_RANDOM; | ||
826 | 828 | ||
827 | if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) { | 829 | if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) { |
828 | err = netxen_init_firmware(adapter); | 830 | err = netxen_init_firmware(adapter); |
@@ -846,9 +848,14 @@ static int netxen_nic_open(struct net_device *netdev) | |||
846 | netxen_post_rx_buffers(adapter, ctx, ring); | 848 | netxen_post_rx_buffers(adapter, ctx, ring); |
847 | } | 849 | } |
848 | adapter->irq = adapter->ahw.pdev->irq; | 850 | adapter->irq = adapter->ahw.pdev->irq; |
849 | err = request_irq(adapter->ahw.pdev->irq, netxen_intr, | 851 | if (adapter->flags & NETXEN_NIC_MSI_ENABLED) |
850 | IRQF_SHARED|IRQF_SAMPLE_RANDOM, netdev->name, | 852 | handler = netxen_msi_intr; |
851 | adapter); | 853 | else { |
854 | flags |= IRQF_SHARED; | ||
855 | handler = netxen_intr; | ||
856 | } | ||
857 | err = request_irq(adapter->irq, handler, | ||
858 | flags, netdev->name, adapter); | ||
852 | if (err) { | 859 | if (err) { |
853 | printk(KERN_ERR "request_irq failed with: %d\n", err); | 860 | printk(KERN_ERR "request_irq failed with: %d\n", err); |
854 | netxen_free_hw_resources(adapter); | 861 | netxen_free_hw_resources(adapter); |
@@ -857,21 +864,12 @@ static int netxen_nic_open(struct net_device *netdev) | |||
857 | 864 | ||
858 | adapter->is_up = NETXEN_ADAPTER_UP_MAGIC; | 865 | adapter->is_up = NETXEN_ADAPTER_UP_MAGIC; |
859 | } | 866 | } |
860 | if (!adapter->driver_mismatch) | ||
861 | mod_timer(&adapter->watchdog_timer, jiffies); | ||
862 | |||
863 | napi_enable(&adapter->napi); | ||
864 | |||
865 | netxen_nic_enable_int(adapter); | ||
866 | |||
867 | /* Done here again so that even if phantom sw overwrote it, | 867 | /* Done here again so that even if phantom sw overwrote it, |
868 | * we set it */ | 868 | * we set it */ |
869 | if (adapter->init_port | 869 | if (adapter->init_port |
870 | && adapter->init_port(adapter, adapter->portnum) != 0) { | 870 | && adapter->init_port(adapter, adapter->portnum) != 0) { |
871 | del_timer_sync(&adapter->watchdog_timer); | ||
872 | printk(KERN_ERR "%s: Failed to initialize port %d\n", | 871 | printk(KERN_ERR "%s: Failed to initialize port %d\n", |
873 | netxen_nic_driver_name, adapter->portnum); | 872 | netxen_nic_driver_name, adapter->portnum); |
874 | napi_disable(&adapter->napi); | ||
875 | return -EIO; | 873 | return -EIO; |
876 | } | 874 | } |
877 | if (adapter->macaddr_set) | 875 | if (adapter->macaddr_set) |
@@ -884,6 +882,12 @@ static int netxen_nic_open(struct net_device *netdev) | |||
884 | adapter->set_mtu(adapter, netdev->mtu); | 882 | adapter->set_mtu(adapter, netdev->mtu); |
885 | 883 | ||
886 | if (!adapter->driver_mismatch) | 884 | if (!adapter->driver_mismatch) |
885 | mod_timer(&adapter->watchdog_timer, jiffies); | ||
886 | |||
887 | napi_enable(&adapter->napi); | ||
888 | netxen_nic_enable_int(adapter); | ||
889 | |||
890 | if (!adapter->driver_mismatch) | ||
887 | netif_start_queue(netdev); | 891 | netif_start_queue(netdev); |
888 | 892 | ||
889 | return 0; | 893 | return 0; |
@@ -1196,81 +1200,50 @@ static void netxen_tx_timeout_task(struct work_struct *work) | |||
1196 | netif_wake_queue(adapter->netdev); | 1200 | netif_wake_queue(adapter->netdev); |
1197 | } | 1201 | } |
1198 | 1202 | ||
1199 | static int | 1203 | static inline void |
1200 | netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev) | 1204 | netxen_handle_int(struct netxen_adapter *adapter) |
1201 | { | 1205 | { |
1202 | u32 ret = 0; | ||
1203 | |||
1204 | DPRINTK(INFO, "Entered handle ISR\n"); | ||
1205 | adapter->stats.ints++; | ||
1206 | |||
1207 | netxen_nic_disable_int(adapter); | 1206 | netxen_nic_disable_int(adapter); |
1208 | 1207 | napi_schedule(&adapter->napi); | |
1209 | if (netxen_nic_rx_has_work(adapter) || netxen_nic_tx_has_work(adapter)) { | ||
1210 | if (netif_rx_schedule_prep(netdev, &adapter->napi)) { | ||
1211 | /* | ||
1212 | * Interrupts are already disabled. | ||
1213 | */ | ||
1214 | __netif_rx_schedule(netdev, &adapter->napi); | ||
1215 | } else { | ||
1216 | static unsigned int intcount = 0; | ||
1217 | if ((++intcount & 0xfff) == 0xfff) | ||
1218 | DPRINTK(KERN_ERR | ||
1219 | "%s: %s interrupt %d while in poll\n", | ||
1220 | netxen_nic_driver_name, netdev->name, | ||
1221 | intcount); | ||
1222 | } | ||
1223 | ret = 1; | ||
1224 | } | ||
1225 | |||
1226 | if (ret == 0) { | ||
1227 | netxen_nic_enable_int(adapter); | ||
1228 | } | ||
1229 | |||
1230 | return ret; | ||
1231 | } | 1208 | } |
1232 | 1209 | ||
1233 | /* | ||
1234 | * netxen_intr - Interrupt Handler | ||
1235 | * @irq: interrupt number | ||
1236 | * data points to adapter stucture (which may be handling more than 1 port | ||
1237 | */ | ||
1238 | irqreturn_t netxen_intr(int irq, void *data) | 1210 | irqreturn_t netxen_intr(int irq, void *data) |
1239 | { | 1211 | { |
1240 | struct netxen_adapter *adapter = data; | 1212 | struct netxen_adapter *adapter = data; |
1241 | struct net_device *netdev = adapter->netdev; | ||
1242 | u32 our_int = 0; | 1213 | u32 our_int = 0; |
1243 | 1214 | ||
1244 | if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) { | 1215 | our_int = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR)); |
1245 | our_int = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR)); | 1216 | /* not our interrupt */ |
1246 | /* not our interrupt */ | 1217 | if ((our_int & (0x80 << adapter->portnum)) == 0) |
1247 | if ((our_int & (0x80 << adapter->portnum)) == 0) | 1218 | return IRQ_NONE; |
1248 | return IRQ_NONE; | ||
1249 | } | ||
1250 | 1219 | ||
1251 | if (adapter->intr_scheme == INTR_SCHEME_PERPORT) { | 1220 | if (adapter->intr_scheme == INTR_SCHEME_PERPORT) { |
1252 | /* claim interrupt */ | 1221 | /* claim interrupt */ |
1253 | if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) { | 1222 | writel(our_int & ~((u32)(0x80 << adapter->portnum)), |
1254 | writel(our_int & ~((u32)(0x80 << adapter->portnum)), | ||
1255 | NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR)); | 1223 | NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR)); |
1256 | } | ||
1257 | } | 1224 | } |
1258 | 1225 | ||
1259 | if (netif_running(netdev)) | 1226 | netxen_handle_int(adapter); |
1260 | netxen_handle_int(adapter, netdev); | ||
1261 | 1227 | ||
1262 | return IRQ_HANDLED; | 1228 | return IRQ_HANDLED; |
1263 | } | 1229 | } |
1264 | 1230 | ||
1231 | irqreturn_t netxen_msi_intr(int irq, void *data) | ||
1232 | { | ||
1233 | struct netxen_adapter *adapter = data; | ||
1234 | |||
1235 | netxen_handle_int(adapter); | ||
1236 | return IRQ_HANDLED; | ||
1237 | } | ||
1238 | |||
1265 | static int netxen_nic_poll(struct napi_struct *napi, int budget) | 1239 | static int netxen_nic_poll(struct napi_struct *napi, int budget) |
1266 | { | 1240 | { |
1267 | struct netxen_adapter *adapter = container_of(napi, struct netxen_adapter, napi); | 1241 | struct netxen_adapter *adapter = container_of(napi, struct netxen_adapter, napi); |
1268 | struct net_device *netdev = adapter->netdev; | 1242 | int tx_complete; |
1269 | int done = 1; | ||
1270 | int ctx; | 1243 | int ctx; |
1271 | int work_done; | 1244 | int work_done; |
1272 | 1245 | ||
1273 | DPRINTK(INFO, "polling for %d descriptors\n", *budget); | 1246 | tx_complete = netxen_process_cmd_ring(adapter); |
1274 | 1247 | ||
1275 | work_done = 0; | 1248 | work_done = 0; |
1276 | for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { | 1249 | for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { |
@@ -1290,16 +1263,8 @@ static int netxen_nic_poll(struct napi_struct *napi, int budget) | |||
1290 | budget / MAX_RCV_CTX); | 1263 | budget / MAX_RCV_CTX); |
1291 | } | 1264 | } |
1292 | 1265 | ||
1293 | if (work_done >= budget) | 1266 | if ((work_done < budget) && tx_complete) { |
1294 | done = 0; | 1267 | netif_rx_complete(adapter->netdev, &adapter->napi); |
1295 | |||
1296 | if (netxen_process_cmd_ring((unsigned long)adapter) == 0) | ||
1297 | done = 0; | ||
1298 | |||
1299 | DPRINTK(INFO, "new work_done: %d work_to_do: %d\n", | ||
1300 | work_done, work_to_do); | ||
1301 | if (done) { | ||
1302 | netif_rx_complete(netdev, napi); | ||
1303 | netxen_nic_enable_int(adapter); | 1268 | netxen_nic_enable_int(adapter); |
1304 | } | 1269 | } |
1305 | 1270 | ||