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