diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2009-01-28 22:08:27 -0500 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-01-28 22:24:55 -0500 |
commit | 35c2221ba1093af77cc2164d5785a88f08a9fc57 (patch) | |
tree | bbc520759e2ebe7a7fde3efbc519376f3f607764 /drivers/atm | |
parent | c6428e52facd03dfac971a44abca4bc058104fec (diff) |
solos: Clean up handling of card->tx_mask a little
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/atm')
-rw-r--r-- | drivers/atm/solos-pci.c | 53 |
1 files changed, 28 insertions, 25 deletions
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 5e228a3f7502..e7691b3328f9 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c | |||
@@ -140,7 +140,7 @@ module_param(fpga_upgrade, int, 0444); | |||
140 | 140 | ||
141 | static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, | 141 | static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, |
142 | struct atm_vcc *vcc); | 142 | struct atm_vcc *vcc); |
143 | static int fpga_tx(struct solos_card *); | 143 | static uint32_t fpga_tx(struct solos_card *); |
144 | static irqreturn_t solos_irq(int irq, void *dev_id); | 144 | static irqreturn_t solos_irq(int irq, void *dev_id); |
145 | static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci); | 145 | static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci); |
146 | static int list_vccs(int vci); | 146 | static int list_vccs(int vci); |
@@ -438,8 +438,6 @@ static int send_command(struct solos_card *card, int dev, const char *buf, size_ | |||
438 | struct sk_buff *skb; | 438 | struct sk_buff *skb; |
439 | struct pkt_hdr *header; | 439 | struct pkt_hdr *header; |
440 | 440 | ||
441 | // dev_dbg(&card->dev->dev, "size: %d\n", size); | ||
442 | |||
443 | if (size > (BUF_SIZE - sizeof(*header))) { | 441 | if (size > (BUF_SIZE - sizeof(*header))) { |
444 | dev_dbg(&card->dev->dev, "Command is too big. Dropping request\n"); | 442 | dev_dbg(&card->dev->dev, "Command is too big. Dropping request\n"); |
445 | return 0; | 443 | return 0; |
@@ -574,9 +572,9 @@ static irqreturn_t solos_irq(int irq, void *dev_id) | |||
574 | struct solos_card *card = dev_id; | 572 | struct solos_card *card = dev_id; |
575 | int handled = 1; | 573 | int handled = 1; |
576 | 574 | ||
577 | //ACK IRQ | ||
578 | iowrite32(0, card->config_regs + IRQ_CLEAR); | 575 | iowrite32(0, card->config_regs + IRQ_CLEAR); |
579 | 576 | ||
577 | /* If we're up and running, just kick the tasklet to process TX/RX */ | ||
580 | if (card->atmdev[0]) | 578 | if (card->atmdev[0]) |
581 | tasklet_schedule(&card->tlet); | 579 | tasklet_schedule(&card->tlet); |
582 | else | 580 | else |
@@ -588,16 +586,16 @@ static irqreturn_t solos_irq(int irq, void *dev_id) | |||
588 | void solos_bh(unsigned long card_arg) | 586 | void solos_bh(unsigned long card_arg) |
589 | { | 587 | { |
590 | struct solos_card *card = (void *)card_arg; | 588 | struct solos_card *card = (void *)card_arg; |
591 | int port; | ||
592 | uint32_t card_flags; | 589 | uint32_t card_flags; |
593 | uint32_t rx_done = 0; | 590 | uint32_t rx_done = 0; |
591 | int port; | ||
594 | 592 | ||
595 | card_flags = ioread32(card->config_regs + FLAGS_ADDR); | 593 | /* |
596 | 594 | * Since fpga_tx() is going to need to read the flags under its lock, | |
597 | /* The TX bits are set if the channel is busy; clear if not. We want to | 595 | * it can return them to us so that we don't have to hit PCI MMIO |
598 | invoke fpga_tx() unless _all_ the bits for active channels are set */ | 596 | * again for the same information |
599 | if ((card_flags & card->tx_mask) != card->tx_mask) | 597 | */ |
600 | fpga_tx(card); | 598 | card_flags = fpga_tx(card); |
601 | 599 | ||
602 | for (port = 0; port < card->nr_ports; port++) { | 600 | for (port = 0; port < card->nr_ports; port++) { |
603 | if (card_flags & (0x10 << port)) { | 601 | if (card_flags & (0x10 << port)) { |
@@ -892,9 +890,8 @@ static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, | |||
892 | spin_lock_irqsave(&card->tx_queue_lock, flags); | 890 | spin_lock_irqsave(&card->tx_queue_lock, flags); |
893 | old_len = skb_queue_len(&card->tx_queue[port]); | 891 | old_len = skb_queue_len(&card->tx_queue[port]); |
894 | skb_queue_tail(&card->tx_queue[port], skb); | 892 | skb_queue_tail(&card->tx_queue[port], skb); |
895 | if (!old_len) { | 893 | if (!old_len) |
896 | card->tx_mask |= (1 << port); | 894 | card->tx_mask |= (1 << port); |
897 | } | ||
898 | spin_unlock_irqrestore(&card->tx_queue_lock, flags); | 895 | spin_unlock_irqrestore(&card->tx_queue_lock, flags); |
899 | 896 | ||
900 | /* Theoretically we could just schedule the tasklet here, but | 897 | /* Theoretically we could just schedule the tasklet here, but |
@@ -903,9 +900,9 @@ static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, | |||
903 | fpga_tx(card); | 900 | fpga_tx(card); |
904 | } | 901 | } |
905 | 902 | ||
906 | static int fpga_tx(struct solos_card *card) | 903 | static uint32_t fpga_tx(struct solos_card *card) |
907 | { | 904 | { |
908 | uint32_t tx_pending; | 905 | uint32_t tx_pending, card_flags; |
909 | uint32_t tx_started = 0; | 906 | uint32_t tx_started = 0; |
910 | struct sk_buff *skb; | 907 | struct sk_buff *skb; |
911 | struct atm_vcc *vcc; | 908 | struct atm_vcc *vcc; |
@@ -913,19 +910,24 @@ static int fpga_tx(struct solos_card *card) | |||
913 | unsigned long flags; | 910 | unsigned long flags; |
914 | 911 | ||
915 | spin_lock_irqsave(&card->tx_lock, flags); | 912 | spin_lock_irqsave(&card->tx_lock, flags); |
916 | 913 | ||
917 | tx_pending = ioread32(card->config_regs + FLAGS_ADDR) & card->tx_mask; | 914 | card_flags = ioread32(card->config_regs + FLAGS_ADDR); |
918 | 915 | /* | |
919 | dev_vdbg(&card->dev->dev, "TX Flags are %X\n", tx_pending); | 916 | * The queue lock is required for _writing_ to tx_mask, but we're |
920 | 917 | * OK to read it here without locking. The only potential update | |
921 | for (port = 0; port < card->nr_ports; port++) { | 918 | * that we could race with is in fpga_queue() where it sets a bit |
922 | if (card->atmdev[port] && !(tx_pending & (1 << port))) { | 919 | * for a new port... but it's going to call this function again if |
920 | * it's doing that, anyway. | ||
921 | */ | ||
922 | tx_pending = card->tx_mask & ~card_flags; | ||
923 | |||
924 | for (port = 0; tx_pending; tx_pending >>= 1, port++) { | ||
925 | if (tx_pending & 1) { | ||
923 | struct sk_buff *oldskb = card->tx_skb[port]; | 926 | struct sk_buff *oldskb = card->tx_skb[port]; |
924 | |||
925 | if (oldskb) | 927 | if (oldskb) |
926 | pci_unmap_single(card->dev, SKB_CB(oldskb)->dma_addr, | 928 | pci_unmap_single(card->dev, SKB_CB(oldskb)->dma_addr, |
927 | oldskb->len, PCI_DMA_TODEVICE); | 929 | oldskb->len, PCI_DMA_TODEVICE); |
928 | 930 | ||
929 | spin_lock(&card->tx_queue_lock); | 931 | spin_lock(&card->tx_queue_lock); |
930 | skb = skb_dequeue(&card->tx_queue[port]); | 932 | skb = skb_dequeue(&card->tx_queue[port]); |
931 | if (!skb) | 933 | if (!skb) |
@@ -966,8 +968,9 @@ static int fpga_tx(struct solos_card *card) | |||
966 | if (tx_started) | 968 | if (tx_started) |
967 | iowrite32(tx_started, card->config_regs + FLAGS_ADDR); | 969 | iowrite32(tx_started, card->config_regs + FLAGS_ADDR); |
968 | 970 | ||
971 | out: | ||
969 | spin_unlock_irqrestore(&card->tx_lock, flags); | 972 | spin_unlock_irqrestore(&card->tx_lock, flags); |
970 | return 0; | 973 | return card_flags; |
971 | } | 974 | } |
972 | 975 | ||
973 | static int psend(struct atm_vcc *vcc, struct sk_buff *skb) | 976 | static int psend(struct atm_vcc *vcc, struct sk_buff *skb) |