diff options
Diffstat (limited to 'drivers/firewire/net.c')
-rw-r--r-- | drivers/firewire/net.c | 54 |
1 files changed, 40 insertions, 14 deletions
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index cbaf420c36c5..7142eeec8074 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/mutex.h> | 21 | #include <linux/mutex.h> |
22 | #include <linux/netdevice.h> | 22 | #include <linux/netdevice.h> |
23 | #include <linux/skbuff.h> | 23 | #include <linux/skbuff.h> |
24 | #include <linux/slab.h> | ||
24 | #include <linux/spinlock.h> | 25 | #include <linux/spinlock.h> |
25 | 26 | ||
26 | #include <asm/unaligned.h> | 27 | #include <asm/unaligned.h> |
@@ -893,20 +894,31 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context, | |||
893 | 894 | ||
894 | static struct kmem_cache *fwnet_packet_task_cache; | 895 | static struct kmem_cache *fwnet_packet_task_cache; |
895 | 896 | ||
897 | static void fwnet_free_ptask(struct fwnet_packet_task *ptask) | ||
898 | { | ||
899 | dev_kfree_skb_any(ptask->skb); | ||
900 | kmem_cache_free(fwnet_packet_task_cache, ptask); | ||
901 | } | ||
902 | |||
896 | static int fwnet_send_packet(struct fwnet_packet_task *ptask); | 903 | static int fwnet_send_packet(struct fwnet_packet_task *ptask); |
897 | 904 | ||
898 | static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) | 905 | static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) |
899 | { | 906 | { |
900 | struct fwnet_device *dev; | 907 | struct fwnet_device *dev = ptask->dev; |
901 | unsigned long flags; | 908 | unsigned long flags; |
902 | 909 | bool free; | |
903 | dev = ptask->dev; | ||
904 | 910 | ||
905 | spin_lock_irqsave(&dev->lock, flags); | 911 | spin_lock_irqsave(&dev->lock, flags); |
906 | list_del(&ptask->pt_link); | ||
907 | spin_unlock_irqrestore(&dev->lock, flags); | ||
908 | 912 | ||
909 | ptask->outstanding_pkts--; /* FIXME access inside lock */ | 913 | ptask->outstanding_pkts--; |
914 | |||
915 | /* Check whether we or the networking TX soft-IRQ is last user. */ | ||
916 | free = (ptask->outstanding_pkts == 0 && !list_empty(&ptask->pt_link)); | ||
917 | |||
918 | if (ptask->outstanding_pkts == 0) | ||
919 | list_del(&ptask->pt_link); | ||
920 | |||
921 | spin_unlock_irqrestore(&dev->lock, flags); | ||
910 | 922 | ||
911 | if (ptask->outstanding_pkts > 0) { | 923 | if (ptask->outstanding_pkts > 0) { |
912 | u16 dg_size; | 924 | u16 dg_size; |
@@ -951,10 +963,10 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) | |||
951 | ptask->max_payload = skb->len + RFC2374_FRAG_HDR_SIZE; | 963 | ptask->max_payload = skb->len + RFC2374_FRAG_HDR_SIZE; |
952 | } | 964 | } |
953 | fwnet_send_packet(ptask); | 965 | fwnet_send_packet(ptask); |
954 | } else { | ||
955 | dev_kfree_skb_any(ptask->skb); | ||
956 | kmem_cache_free(fwnet_packet_task_cache, ptask); | ||
957 | } | 966 | } |
967 | |||
968 | if (free) | ||
969 | fwnet_free_ptask(ptask); | ||
958 | } | 970 | } |
959 | 971 | ||
960 | static void fwnet_write_complete(struct fw_card *card, int rcode, | 972 | static void fwnet_write_complete(struct fw_card *card, int rcode, |
@@ -977,6 +989,7 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) | |||
977 | unsigned tx_len; | 989 | unsigned tx_len; |
978 | struct rfc2734_header *bufhdr; | 990 | struct rfc2734_header *bufhdr; |
979 | unsigned long flags; | 991 | unsigned long flags; |
992 | bool free; | ||
980 | 993 | ||
981 | dev = ptask->dev; | 994 | dev = ptask->dev; |
982 | tx_len = ptask->max_payload; | 995 | tx_len = ptask->max_payload; |
@@ -1022,12 +1035,16 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) | |||
1022 | generation, SCODE_100, 0ULL, ptask->skb->data, | 1035 | generation, SCODE_100, 0ULL, ptask->skb->data, |
1023 | tx_len + 8, fwnet_write_complete, ptask); | 1036 | tx_len + 8, fwnet_write_complete, ptask); |
1024 | 1037 | ||
1025 | /* FIXME race? */ | ||
1026 | spin_lock_irqsave(&dev->lock, flags); | 1038 | spin_lock_irqsave(&dev->lock, flags); |
1027 | list_add_tail(&ptask->pt_link, &dev->broadcasted_list); | 1039 | |
1040 | /* If the AT tasklet already ran, we may be last user. */ | ||
1041 | free = (ptask->outstanding_pkts == 0 && list_empty(&ptask->pt_link)); | ||
1042 | if (!free) | ||
1043 | list_add_tail(&ptask->pt_link, &dev->broadcasted_list); | ||
1044 | |||
1028 | spin_unlock_irqrestore(&dev->lock, flags); | 1045 | spin_unlock_irqrestore(&dev->lock, flags); |
1029 | 1046 | ||
1030 | return 0; | 1047 | goto out; |
1031 | } | 1048 | } |
1032 | 1049 | ||
1033 | fw_send_request(dev->card, &ptask->transaction, | 1050 | fw_send_request(dev->card, &ptask->transaction, |
@@ -1035,12 +1052,19 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) | |||
1035 | ptask->generation, ptask->speed, ptask->fifo_addr, | 1052 | ptask->generation, ptask->speed, ptask->fifo_addr, |
1036 | ptask->skb->data, tx_len, fwnet_write_complete, ptask); | 1053 | ptask->skb->data, tx_len, fwnet_write_complete, ptask); |
1037 | 1054 | ||
1038 | /* FIXME race? */ | ||
1039 | spin_lock_irqsave(&dev->lock, flags); | 1055 | spin_lock_irqsave(&dev->lock, flags); |
1040 | list_add_tail(&ptask->pt_link, &dev->sent_list); | 1056 | |
1057 | /* If the AT tasklet already ran, we may be last user. */ | ||
1058 | free = (ptask->outstanding_pkts == 0 && list_empty(&ptask->pt_link)); | ||
1059 | if (!free) | ||
1060 | list_add_tail(&ptask->pt_link, &dev->sent_list); | ||
1061 | |||
1041 | spin_unlock_irqrestore(&dev->lock, flags); | 1062 | spin_unlock_irqrestore(&dev->lock, flags); |
1042 | 1063 | ||
1043 | dev->netdev->trans_start = jiffies; | 1064 | dev->netdev->trans_start = jiffies; |
1065 | out: | ||
1066 | if (free) | ||
1067 | fwnet_free_ptask(ptask); | ||
1044 | 1068 | ||
1045 | return 0; | 1069 | return 0; |
1046 | } | 1070 | } |
@@ -1298,6 +1322,8 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) | |||
1298 | spin_unlock_irqrestore(&dev->lock, flags); | 1322 | spin_unlock_irqrestore(&dev->lock, flags); |
1299 | 1323 | ||
1300 | ptask->max_payload = max_payload; | 1324 | ptask->max_payload = max_payload; |
1325 | INIT_LIST_HEAD(&ptask->pt_link); | ||
1326 | |||
1301 | fwnet_send_packet(ptask); | 1327 | fwnet_send_packet(ptask); |
1302 | 1328 | ||
1303 | return NETDEV_TX_OK; | 1329 | return NETDEV_TX_OK; |