aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/atm/solos-pci.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index acba08df5eb0..bf59c407fec9 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -100,6 +100,7 @@ struct solos_card {
100 void __iomem *config_regs; 100 void __iomem *config_regs;
101 void __iomem *buffers; 101 void __iomem *buffers;
102 int nr_ports; 102 int nr_ports;
103 int tx_mask;
103 struct pci_dev *dev; 104 struct pci_dev *dev;
104 struct atm_dev *atmdev[4]; 105 struct atm_dev *atmdev[4];
105 struct tasklet_struct tlet; 106 struct tasklet_struct tlet;
@@ -590,15 +591,13 @@ void solos_bh(unsigned long card_arg)
590 struct solos_card *card = (void *)card_arg; 591 struct solos_card *card = (void *)card_arg;
591 int port; 592 int port;
592 uint32_t card_flags; 593 uint32_t card_flags;
593 uint32_t tx_mask;
594 uint32_t rx_done = 0; 594 uint32_t rx_done = 0;
595 595
596 card_flags = ioread32(card->config_regs + FLAGS_ADDR); 596 card_flags = ioread32(card->config_regs + FLAGS_ADDR);
597 597
598 /* The TX bits are set if the channel is busy; clear if not. We want to 598 /* The TX bits are set if the channel is busy; clear if not. We want to
599 invoke fpga_tx() unless _all_ the bits for active channels are set */ 599 invoke fpga_tx() unless _all_ the bits for active channels are set */
600 tx_mask = (1 << card->nr_ports) - 1; 600 if ((card_flags & card->tx_mask) != card->tx_mask)
601 if ((card_flags & tx_mask) != tx_mask)
602 fpga_tx(card); 601 fpga_tx(card);
603 602
604 for (port = 0; port < card->nr_ports; port++) { 603 for (port = 0; port < card->nr_ports; port++) {
@@ -887,15 +886,20 @@ static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
887 struct atm_vcc *vcc) 886 struct atm_vcc *vcc)
888{ 887{
889 int old_len; 888 int old_len;
889 unsigned long flags;
890 890
891 SKB_CB(skb)->vcc = vcc; 891 SKB_CB(skb)->vcc = vcc;
892 892
893 spin_lock(&card->tx_queue_lock); 893 spin_lock_irqsave(&card->tx_queue_lock, flags);
894 old_len = skb_queue_len(&card->tx_queue[port]); 894 old_len = skb_queue_len(&card->tx_queue[port]);
895 skb_queue_tail(&card->tx_queue[port], skb); 895 skb_queue_tail(&card->tx_queue[port], skb);
896 spin_unlock(&card->tx_queue_lock); 896 if (!old_len) {
897 card->tx_mask |= (1 << port);
898 }
899 spin_unlock_irqrestore(&card->tx_queue_lock, flags);
897 900
898 /* If TX might need to be started, do so */ 901 /* Theoretically we could just schedule the tasklet here, but
902 that introduces latency we don't want -- it's noticeable */
899 if (!old_len) 903 if (!old_len)
900 fpga_tx(card); 904 fpga_tx(card);
901} 905}
@@ -911,7 +915,7 @@ static int fpga_tx(struct solos_card *card)
911 915
912 spin_lock_irqsave(&card->tx_lock, flags); 916 spin_lock_irqsave(&card->tx_lock, flags);
913 917
914 tx_pending = ioread32(card->config_regs + FLAGS_ADDR); 918 tx_pending = ioread32(card->config_regs + FLAGS_ADDR) & card->tx_mask;
915 919
916 dev_vdbg(&card->dev->dev, "TX Flags are %X\n", tx_pending); 920 dev_vdbg(&card->dev->dev, "TX Flags are %X\n", tx_pending);
917 921
@@ -925,6 +929,8 @@ static int fpga_tx(struct solos_card *card)
925 929
926 spin_lock(&card->tx_queue_lock); 930 spin_lock(&card->tx_queue_lock);
927 skb = skb_dequeue(&card->tx_queue[port]); 931 skb = skb_dequeue(&card->tx_queue[port]);
932 if (!skb)
933 card->tx_mask &= ~(1 << port);
928 spin_unlock(&card->tx_queue_lock); 934 spin_unlock(&card->tx_queue_lock);
929 935
930 if (skb && !card->using_dma) { 936 if (skb && !card->using_dma) {