aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/net.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firewire/net.c')
-rw-r--r--drivers/firewire/net.c54
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
894static struct kmem_cache *fwnet_packet_task_cache; 895static struct kmem_cache *fwnet_packet_task_cache;
895 896
897static 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
896static int fwnet_send_packet(struct fwnet_packet_task *ptask); 903static int fwnet_send_packet(struct fwnet_packet_task *ptask);
897 904
898static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) 905static 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
960static void fwnet_write_complete(struct fw_card *card, int rcode, 972static 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;