diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-11-28 15:24:20 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-11-28 15:24:20 -0500 |
commit | 75f5d2c9bd36047364d1fb35c0720ab37df3be02 (patch) | |
tree | 20f7bfba3397366e0f4526dcdbdb20f23559d8a5 /drivers/firewire | |
parent | 0f639a3c5ca63dd76ee07de9b02ebf0178ce9a17 (diff) | |
parent | b2268830f5cf29d94b3e4a2af0b795a8f28776fe (diff) |
Merge branch 'fwnet' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6
* 'fwnet' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6:
firewire: net: throttle TX queue before running out of tlabels
firewire: net: replace lists by counters
firewire: net: fix memory leaks
firewire: net: count stats.tx_packets and stats.tx_bytes
Diffstat (limited to 'drivers/firewire')
-rw-r--r-- | drivers/firewire/net.c | 160 |
1 files changed, 90 insertions, 70 deletions
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 18fdd9703b48..1a467a91fb0b 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c | |||
@@ -7,6 +7,7 @@ | |||
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/bug.h> | 9 | #include <linux/bug.h> |
10 | #include <linux/delay.h> | ||
10 | #include <linux/device.h> | 11 | #include <linux/device.h> |
11 | #include <linux/firewire.h> | 12 | #include <linux/firewire.h> |
12 | #include <linux/firewire-constants.h> | 13 | #include <linux/firewire-constants.h> |
@@ -26,8 +27,14 @@ | |||
26 | #include <asm/unaligned.h> | 27 | #include <asm/unaligned.h> |
27 | #include <net/arp.h> | 28 | #include <net/arp.h> |
28 | 29 | ||
29 | #define FWNET_MAX_FRAGMENTS 25 /* arbitrary limit */ | 30 | /* rx limits */ |
30 | #define FWNET_ISO_PAGE_COUNT (PAGE_SIZE < 16 * 1024 ? 4 : 2) | 31 | #define FWNET_MAX_FRAGMENTS 30 /* arbitrary, > TX queue depth */ |
32 | #define FWNET_ISO_PAGE_COUNT (PAGE_SIZE < 16*1024 ? 4 : 2) | ||
33 | |||
34 | /* tx limits */ | ||
35 | #define FWNET_MAX_QUEUED_DATAGRAMS 20 /* < 64 = number of tlabels */ | ||
36 | #define FWNET_MIN_QUEUED_DATAGRAMS 10 /* should keep AT DMA busy enough */ | ||
37 | #define FWNET_TX_QUEUE_LEN FWNET_MAX_QUEUED_DATAGRAMS /* ? */ | ||
31 | 38 | ||
32 | #define IEEE1394_BROADCAST_CHANNEL 31 | 39 | #define IEEE1394_BROADCAST_CHANNEL 31 |
33 | #define IEEE1394_ALL_NODES (0xffc0 | 0x003f) | 40 | #define IEEE1394_ALL_NODES (0xffc0 | 0x003f) |
@@ -169,15 +176,8 @@ struct fwnet_device { | |||
169 | struct fw_address_handler handler; | 176 | struct fw_address_handler handler; |
170 | u64 local_fifo; | 177 | u64 local_fifo; |
171 | 178 | ||
172 | /* List of packets to be sent */ | 179 | /* Number of tx datagrams that have been queued but not yet acked */ |
173 | struct list_head packet_list; | 180 | int queued_datagrams; |
174 | /* | ||
175 | * List of packets that were broadcasted. When we get an ISO interrupt | ||
176 | * one of them has been sent | ||
177 | */ | ||
178 | struct list_head broadcasted_list; | ||
179 | /* List of packets that have been sent but not yet acked */ | ||
180 | struct list_head sent_list; | ||
181 | 181 | ||
182 | struct list_head peer_list; | 182 | struct list_head peer_list; |
183 | struct fw_card *card; | 183 | struct fw_card *card; |
@@ -195,7 +195,7 @@ struct fwnet_peer { | |||
195 | unsigned pdg_size; /* pd_list size */ | 195 | unsigned pdg_size; /* pd_list size */ |
196 | 196 | ||
197 | u16 datagram_label; /* outgoing datagram label */ | 197 | u16 datagram_label; /* outgoing datagram label */ |
198 | unsigned max_payload; /* includes RFC2374_FRAG_HDR_SIZE overhead */ | 198 | u16 max_payload; /* includes RFC2374_FRAG_HDR_SIZE overhead */ |
199 | int node_id; | 199 | int node_id; |
200 | int generation; | 200 | int generation; |
201 | unsigned speed; | 201 | unsigned speed; |
@@ -203,22 +203,18 @@ struct fwnet_peer { | |||
203 | 203 | ||
204 | /* This is our task struct. It's used for the packet complete callback. */ | 204 | /* This is our task struct. It's used for the packet complete callback. */ |
205 | struct fwnet_packet_task { | 205 | struct fwnet_packet_task { |
206 | /* | ||
207 | * ptask can actually be on dev->packet_list, dev->broadcasted_list, | ||
208 | * or dev->sent_list depending on its current state. | ||
209 | */ | ||
210 | struct list_head pt_link; | ||
211 | struct fw_transaction transaction; | 206 | struct fw_transaction transaction; |
212 | struct rfc2734_header hdr; | 207 | struct rfc2734_header hdr; |
213 | struct sk_buff *skb; | 208 | struct sk_buff *skb; |
214 | struct fwnet_device *dev; | 209 | struct fwnet_device *dev; |
215 | 210 | ||
216 | int outstanding_pkts; | 211 | int outstanding_pkts; |
217 | unsigned max_payload; | ||
218 | u64 fifo_addr; | 212 | u64 fifo_addr; |
219 | u16 dest_node; | 213 | u16 dest_node; |
214 | u16 max_payload; | ||
220 | u8 generation; | 215 | u8 generation; |
221 | u8 speed; | 216 | u8 speed; |
217 | u8 enqueued; | ||
222 | }; | 218 | }; |
223 | 219 | ||
224 | /* | 220 | /* |
@@ -650,8 +646,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net, | |||
650 | net->stats.rx_packets++; | 646 | net->stats.rx_packets++; |
651 | net->stats.rx_bytes += skb->len; | 647 | net->stats.rx_bytes += skb->len; |
652 | } | 648 | } |
653 | if (netif_queue_stopped(net)) | ||
654 | netif_wake_queue(net); | ||
655 | 649 | ||
656 | return 0; | 650 | return 0; |
657 | 651 | ||
@@ -660,8 +654,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net, | |||
660 | net->stats.rx_dropped++; | 654 | net->stats.rx_dropped++; |
661 | 655 | ||
662 | dev_kfree_skb_any(skb); | 656 | dev_kfree_skb_any(skb); |
663 | if (netif_queue_stopped(net)) | ||
664 | netif_wake_queue(net); | ||
665 | 657 | ||
666 | return -ENOENT; | 658 | return -ENOENT; |
667 | } | 659 | } |
@@ -793,15 +785,10 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, | |||
793 | * Datagram is not complete, we're done for the | 785 | * Datagram is not complete, we're done for the |
794 | * moment. | 786 | * moment. |
795 | */ | 787 | */ |
796 | spin_unlock_irqrestore(&dev->lock, flags); | 788 | retval = 0; |
797 | |||
798 | return 0; | ||
799 | fail: | 789 | fail: |
800 | spin_unlock_irqrestore(&dev->lock, flags); | 790 | spin_unlock_irqrestore(&dev->lock, flags); |
801 | 791 | ||
802 | if (netif_queue_stopped(net)) | ||
803 | netif_wake_queue(net); | ||
804 | |||
805 | return retval; | 792 | return retval; |
806 | } | 793 | } |
807 | 794 | ||
@@ -901,11 +888,19 @@ static void fwnet_free_ptask(struct fwnet_packet_task *ptask) | |||
901 | kmem_cache_free(fwnet_packet_task_cache, ptask); | 888 | kmem_cache_free(fwnet_packet_task_cache, ptask); |
902 | } | 889 | } |
903 | 890 | ||
891 | /* Caller must hold dev->lock. */ | ||
892 | static void dec_queued_datagrams(struct fwnet_device *dev) | ||
893 | { | ||
894 | if (--dev->queued_datagrams == FWNET_MIN_QUEUED_DATAGRAMS) | ||
895 | netif_wake_queue(dev->netdev); | ||
896 | } | ||
897 | |||
904 | static int fwnet_send_packet(struct fwnet_packet_task *ptask); | 898 | static int fwnet_send_packet(struct fwnet_packet_task *ptask); |
905 | 899 | ||
906 | static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) | 900 | static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) |
907 | { | 901 | { |
908 | struct fwnet_device *dev = ptask->dev; | 902 | struct fwnet_device *dev = ptask->dev; |
903 | struct sk_buff *skb = ptask->skb; | ||
909 | unsigned long flags; | 904 | unsigned long flags; |
910 | bool free; | 905 | bool free; |
911 | 906 | ||
@@ -914,10 +909,14 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) | |||
914 | ptask->outstanding_pkts--; | 909 | ptask->outstanding_pkts--; |
915 | 910 | ||
916 | /* Check whether we or the networking TX soft-IRQ is last user. */ | 911 | /* Check whether we or the networking TX soft-IRQ is last user. */ |
917 | free = (ptask->outstanding_pkts == 0 && !list_empty(&ptask->pt_link)); | 912 | free = (ptask->outstanding_pkts == 0 && ptask->enqueued); |
913 | if (free) | ||
914 | dec_queued_datagrams(dev); | ||
918 | 915 | ||
919 | if (ptask->outstanding_pkts == 0) | 916 | if (ptask->outstanding_pkts == 0) { |
920 | list_del(&ptask->pt_link); | 917 | dev->netdev->stats.tx_packets++; |
918 | dev->netdev->stats.tx_bytes += skb->len; | ||
919 | } | ||
921 | 920 | ||
922 | spin_unlock_irqrestore(&dev->lock, flags); | 921 | spin_unlock_irqrestore(&dev->lock, flags); |
923 | 922 | ||
@@ -926,7 +925,6 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) | |||
926 | u16 fg_off; | 925 | u16 fg_off; |
927 | u16 datagram_label; | 926 | u16 datagram_label; |
928 | u16 lf; | 927 | u16 lf; |
929 | struct sk_buff *skb; | ||
930 | 928 | ||
931 | /* Update the ptask to point to the next fragment and send it */ | 929 | /* Update the ptask to point to the next fragment and send it */ |
932 | lf = fwnet_get_hdr_lf(&ptask->hdr); | 930 | lf = fwnet_get_hdr_lf(&ptask->hdr); |
@@ -953,7 +951,7 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) | |||
953 | datagram_label = fwnet_get_hdr_dgl(&ptask->hdr); | 951 | datagram_label = fwnet_get_hdr_dgl(&ptask->hdr); |
954 | break; | 952 | break; |
955 | } | 953 | } |
956 | skb = ptask->skb; | 954 | |
957 | skb_pull(skb, ptask->max_payload); | 955 | skb_pull(skb, ptask->max_payload); |
958 | if (ptask->outstanding_pkts > 1) { | 956 | if (ptask->outstanding_pkts > 1) { |
959 | fwnet_make_sf_hdr(&ptask->hdr, RFC2374_HDR_INTFRAG, | 957 | fwnet_make_sf_hdr(&ptask->hdr, RFC2374_HDR_INTFRAG, |
@@ -970,6 +968,31 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) | |||
970 | fwnet_free_ptask(ptask); | 968 | fwnet_free_ptask(ptask); |
971 | } | 969 | } |
972 | 970 | ||
971 | static void fwnet_transmit_packet_failed(struct fwnet_packet_task *ptask) | ||
972 | { | ||
973 | struct fwnet_device *dev = ptask->dev; | ||
974 | unsigned long flags; | ||
975 | bool free; | ||
976 | |||
977 | spin_lock_irqsave(&dev->lock, flags); | ||
978 | |||
979 | /* One fragment failed; don't try to send remaining fragments. */ | ||
980 | ptask->outstanding_pkts = 0; | ||
981 | |||
982 | /* Check whether we or the networking TX soft-IRQ is last user. */ | ||
983 | free = ptask->enqueued; | ||
984 | if (free) | ||
985 | dec_queued_datagrams(dev); | ||
986 | |||
987 | dev->netdev->stats.tx_dropped++; | ||
988 | dev->netdev->stats.tx_errors++; | ||
989 | |||
990 | spin_unlock_irqrestore(&dev->lock, flags); | ||
991 | |||
992 | if (free) | ||
993 | fwnet_free_ptask(ptask); | ||
994 | } | ||
995 | |||
973 | static void fwnet_write_complete(struct fw_card *card, int rcode, | 996 | static void fwnet_write_complete(struct fw_card *card, int rcode, |
974 | void *payload, size_t length, void *data) | 997 | void *payload, size_t length, void *data) |
975 | { | 998 | { |
@@ -977,11 +1000,12 @@ static void fwnet_write_complete(struct fw_card *card, int rcode, | |||
977 | 1000 | ||
978 | ptask = data; | 1001 | ptask = data; |
979 | 1002 | ||
980 | if (rcode == RCODE_COMPLETE) | 1003 | if (rcode == RCODE_COMPLETE) { |
981 | fwnet_transmit_packet_done(ptask); | 1004 | fwnet_transmit_packet_done(ptask); |
982 | else | 1005 | } else { |
983 | fw_error("fwnet_write_complete: failed: %x\n", rcode); | 1006 | fw_error("fwnet_write_complete: failed: %x\n", rcode); |
984 | /* ??? error recovery */ | 1007 | fwnet_transmit_packet_failed(ptask); |
1008 | } | ||
985 | } | 1009 | } |
986 | 1010 | ||
987 | static int fwnet_send_packet(struct fwnet_packet_task *ptask) | 1011 | static int fwnet_send_packet(struct fwnet_packet_task *ptask) |
@@ -1039,9 +1063,11 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) | |||
1039 | spin_lock_irqsave(&dev->lock, flags); | 1063 | spin_lock_irqsave(&dev->lock, flags); |
1040 | 1064 | ||
1041 | /* If the AT tasklet already ran, we may be last user. */ | 1065 | /* If the AT tasklet already ran, we may be last user. */ |
1042 | free = (ptask->outstanding_pkts == 0 && list_empty(&ptask->pt_link)); | 1066 | free = (ptask->outstanding_pkts == 0 && !ptask->enqueued); |
1043 | if (!free) | 1067 | if (!free) |
1044 | list_add_tail(&ptask->pt_link, &dev->broadcasted_list); | 1068 | ptask->enqueued = true; |
1069 | else | ||
1070 | dec_queued_datagrams(dev); | ||
1045 | 1071 | ||
1046 | spin_unlock_irqrestore(&dev->lock, flags); | 1072 | spin_unlock_irqrestore(&dev->lock, flags); |
1047 | 1073 | ||
@@ -1056,9 +1082,11 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) | |||
1056 | spin_lock_irqsave(&dev->lock, flags); | 1082 | spin_lock_irqsave(&dev->lock, flags); |
1057 | 1083 | ||
1058 | /* If the AT tasklet already ran, we may be last user. */ | 1084 | /* If the AT tasklet already ran, we may be last user. */ |
1059 | free = (ptask->outstanding_pkts == 0 && list_empty(&ptask->pt_link)); | 1085 | free = (ptask->outstanding_pkts == 0 && !ptask->enqueued); |
1060 | if (!free) | 1086 | if (!free) |
1061 | list_add_tail(&ptask->pt_link, &dev->sent_list); | 1087 | ptask->enqueued = true; |
1088 | else | ||
1089 | dec_queued_datagrams(dev); | ||
1062 | 1090 | ||
1063 | spin_unlock_irqrestore(&dev->lock, flags); | 1091 | spin_unlock_irqrestore(&dev->lock, flags); |
1064 | 1092 | ||
@@ -1224,6 +1252,15 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) | |||
1224 | struct fwnet_peer *peer; | 1252 | struct fwnet_peer *peer; |
1225 | unsigned long flags; | 1253 | unsigned long flags; |
1226 | 1254 | ||
1255 | spin_lock_irqsave(&dev->lock, flags); | ||
1256 | |||
1257 | /* Can this happen? */ | ||
1258 | if (netif_queue_stopped(dev->netdev)) { | ||
1259 | spin_unlock_irqrestore(&dev->lock, flags); | ||
1260 | |||
1261 | return NETDEV_TX_BUSY; | ||
1262 | } | ||
1263 | |||
1227 | ptask = kmem_cache_alloc(fwnet_packet_task_cache, GFP_ATOMIC); | 1264 | ptask = kmem_cache_alloc(fwnet_packet_task_cache, GFP_ATOMIC); |
1228 | if (ptask == NULL) | 1265 | if (ptask == NULL) |
1229 | goto fail; | 1266 | goto fail; |
@@ -1242,9 +1279,6 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) | |||
1242 | proto = hdr_buf.h_proto; | 1279 | proto = hdr_buf.h_proto; |
1243 | dg_size = skb->len; | 1280 | dg_size = skb->len; |
1244 | 1281 | ||
1245 | /* serialize access to peer, including peer->datagram_label */ | ||
1246 | spin_lock_irqsave(&dev->lock, flags); | ||
1247 | |||
1248 | /* | 1282 | /* |
1249 | * Set the transmission type for the packet. ARP packets and IP | 1283 | * Set the transmission type for the packet. ARP packets and IP |
1250 | * broadcast packets are sent via GASP. | 1284 | * broadcast packets are sent via GASP. |
@@ -1266,7 +1300,7 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) | |||
1266 | 1300 | ||
1267 | peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid)); | 1301 | peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid)); |
1268 | if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR) | 1302 | if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR) |
1269 | goto fail_unlock; | 1303 | goto fail; |
1270 | 1304 | ||
1271 | generation = peer->generation; | 1305 | generation = peer->generation; |
1272 | dest_node = peer->node_id; | 1306 | dest_node = peer->node_id; |
@@ -1320,18 +1354,21 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) | |||
1320 | max_payload += RFC2374_FRAG_HDR_SIZE; | 1354 | max_payload += RFC2374_FRAG_HDR_SIZE; |
1321 | } | 1355 | } |
1322 | 1356 | ||
1357 | if (++dev->queued_datagrams == FWNET_MAX_QUEUED_DATAGRAMS) | ||
1358 | netif_stop_queue(dev->netdev); | ||
1359 | |||
1323 | spin_unlock_irqrestore(&dev->lock, flags); | 1360 | spin_unlock_irqrestore(&dev->lock, flags); |
1324 | 1361 | ||
1325 | ptask->max_payload = max_payload; | 1362 | ptask->max_payload = max_payload; |
1326 | INIT_LIST_HEAD(&ptask->pt_link); | 1363 | ptask->enqueued = 0; |
1327 | 1364 | ||
1328 | fwnet_send_packet(ptask); | 1365 | fwnet_send_packet(ptask); |
1329 | 1366 | ||
1330 | return NETDEV_TX_OK; | 1367 | return NETDEV_TX_OK; |
1331 | 1368 | ||
1332 | fail_unlock: | ||
1333 | spin_unlock_irqrestore(&dev->lock, flags); | ||
1334 | fail: | 1369 | fail: |
1370 | spin_unlock_irqrestore(&dev->lock, flags); | ||
1371 | |||
1335 | if (ptask) | 1372 | if (ptask) |
1336 | kmem_cache_free(fwnet_packet_task_cache, ptask); | 1373 | kmem_cache_free(fwnet_packet_task_cache, ptask); |
1337 | 1374 | ||
@@ -1377,7 +1414,7 @@ static void fwnet_init_dev(struct net_device *net) | |||
1377 | net->addr_len = FWNET_ALEN; | 1414 | net->addr_len = FWNET_ALEN; |
1378 | net->hard_header_len = FWNET_HLEN; | 1415 | net->hard_header_len = FWNET_HLEN; |
1379 | net->type = ARPHRD_IEEE1394; | 1416 | net->type = ARPHRD_IEEE1394; |
1380 | net->tx_queue_len = 10; | 1417 | net->tx_queue_len = FWNET_TX_QUEUE_LEN; |
1381 | } | 1418 | } |
1382 | 1419 | ||
1383 | /* caller must hold fwnet_device_mutex */ | 1420 | /* caller must hold fwnet_device_mutex */ |
@@ -1457,14 +1494,9 @@ static int fwnet_probe(struct device *_dev) | |||
1457 | dev->broadcast_rcv_context = NULL; | 1494 | dev->broadcast_rcv_context = NULL; |
1458 | dev->broadcast_xmt_max_payload = 0; | 1495 | dev->broadcast_xmt_max_payload = 0; |
1459 | dev->broadcast_xmt_datagramlabel = 0; | 1496 | dev->broadcast_xmt_datagramlabel = 0; |
1460 | |||
1461 | dev->local_fifo = FWNET_NO_FIFO_ADDR; | 1497 | dev->local_fifo = FWNET_NO_FIFO_ADDR; |
1462 | 1498 | dev->queued_datagrams = 0; | |
1463 | INIT_LIST_HEAD(&dev->packet_list); | ||
1464 | INIT_LIST_HEAD(&dev->broadcasted_list); | ||
1465 | INIT_LIST_HEAD(&dev->sent_list); | ||
1466 | INIT_LIST_HEAD(&dev->peer_list); | 1499 | INIT_LIST_HEAD(&dev->peer_list); |
1467 | |||
1468 | dev->card = card; | 1500 | dev->card = card; |
1469 | dev->netdev = net; | 1501 | dev->netdev = net; |
1470 | 1502 | ||
@@ -1522,7 +1554,7 @@ static int fwnet_remove(struct device *_dev) | |||
1522 | struct fwnet_peer *peer = dev_get_drvdata(_dev); | 1554 | struct fwnet_peer *peer = dev_get_drvdata(_dev); |
1523 | struct fwnet_device *dev = peer->dev; | 1555 | struct fwnet_device *dev = peer->dev; |
1524 | struct net_device *net; | 1556 | struct net_device *net; |
1525 | struct fwnet_packet_task *ptask, *pt_next; | 1557 | int i; |
1526 | 1558 | ||
1527 | mutex_lock(&fwnet_device_mutex); | 1559 | mutex_lock(&fwnet_device_mutex); |
1528 | 1560 | ||
@@ -1540,21 +1572,9 @@ static int fwnet_remove(struct device *_dev) | |||
1540 | dev->card); | 1572 | dev->card); |
1541 | fw_iso_context_destroy(dev->broadcast_rcv_context); | 1573 | fw_iso_context_destroy(dev->broadcast_rcv_context); |
1542 | } | 1574 | } |
1543 | list_for_each_entry_safe(ptask, pt_next, | 1575 | for (i = 0; dev->queued_datagrams && i < 5; i++) |
1544 | &dev->packet_list, pt_link) { | 1576 | ssleep(1); |
1545 | dev_kfree_skb_any(ptask->skb); | 1577 | WARN_ON(dev->queued_datagrams); |
1546 | kmem_cache_free(fwnet_packet_task_cache, ptask); | ||
1547 | } | ||
1548 | list_for_each_entry_safe(ptask, pt_next, | ||
1549 | &dev->broadcasted_list, pt_link) { | ||
1550 | dev_kfree_skb_any(ptask->skb); | ||
1551 | kmem_cache_free(fwnet_packet_task_cache, ptask); | ||
1552 | } | ||
1553 | list_for_each_entry_safe(ptask, pt_next, | ||
1554 | &dev->sent_list, pt_link) { | ||
1555 | dev_kfree_skb_any(ptask->skb); | ||
1556 | kmem_cache_free(fwnet_packet_task_cache, ptask); | ||
1557 | } | ||
1558 | list_del(&dev->dev_link); | 1578 | list_del(&dev->dev_link); |
1559 | 1579 | ||
1560 | free_netdev(net); | 1580 | free_netdev(net); |