Commit 35c2221b authored by David Woodhouse's avatar David Woodhouse

solos: Clean up handling of card->tx_mask a little

Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent c6428e52
...@@ -140,7 +140,7 @@ module_param(fpga_upgrade, int, 0444); ...@@ -140,7 +140,7 @@ module_param(fpga_upgrade, int, 0444);
static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
struct atm_vcc *vcc); struct atm_vcc *vcc);
static int fpga_tx(struct solos_card *); static uint32_t fpga_tx(struct solos_card *);
static irqreturn_t solos_irq(int irq, void *dev_id); static irqreturn_t solos_irq(int irq, void *dev_id);
static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci); static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci);
static int list_vccs(int vci); 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,8 +438,6 @@ static int send_command(struct solos_card *card, int dev, const char *buf, size_
struct sk_buff *skb; struct sk_buff *skb;
struct pkt_hdr *header; struct pkt_hdr *header;
// dev_dbg(&card->dev->dev, "size: %d\n", size);
if (size > (BUF_SIZE - sizeof(*header))) { if (size > (BUF_SIZE - sizeof(*header))) {
dev_dbg(&card->dev->dev, "Command is too big. Dropping request\n"); dev_dbg(&card->dev->dev, "Command is too big. Dropping request\n");
return 0; return 0;
...@@ -574,9 +572,9 @@ static irqreturn_t solos_irq(int irq, void *dev_id) ...@@ -574,9 +572,9 @@ static irqreturn_t solos_irq(int irq, void *dev_id)
struct solos_card *card = dev_id; struct solos_card *card = dev_id;
int handled = 1; int handled = 1;
//ACK IRQ
iowrite32(0, card->config_regs + IRQ_CLEAR); iowrite32(0, card->config_regs + IRQ_CLEAR);
/* If we're up and running, just kick the tasklet to process TX/RX */
if (card->atmdev[0]) if (card->atmdev[0])
tasklet_schedule(&card->tlet); tasklet_schedule(&card->tlet);
else else
...@@ -588,16 +586,16 @@ static irqreturn_t solos_irq(int irq, void *dev_id) ...@@ -588,16 +586,16 @@ static irqreturn_t solos_irq(int irq, void *dev_id)
void solos_bh(unsigned long card_arg) void solos_bh(unsigned long card_arg)
{ {
struct solos_card *card = (void *)card_arg; struct solos_card *card = (void *)card_arg;
int port;
uint32_t card_flags; uint32_t card_flags;
uint32_t rx_done = 0; uint32_t rx_done = 0;
int port;
card_flags = ioread32(card->config_regs + FLAGS_ADDR); /*
* Since fpga_tx() is going to need to read the flags under its lock,
/* The TX bits are set if the channel is busy; clear if not. We want to * it can return them to us so that we don't have to hit PCI MMIO
invoke fpga_tx() unless _all_ the bits for active channels are set */ * again for the same information
if ((card_flags & card->tx_mask) != card->tx_mask) */
fpga_tx(card); card_flags = fpga_tx(card);
for (port = 0; port < card->nr_ports; port++) { for (port = 0; port < card->nr_ports; port++) {
if (card_flags & (0x10 << port)) { if (card_flags & (0x10 << port)) {
...@@ -892,9 +890,8 @@ static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, ...@@ -892,9 +890,8 @@ static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
spin_lock_irqsave(&card->tx_queue_lock, flags); spin_lock_irqsave(&card->tx_queue_lock, flags);
old_len = skb_queue_len(&card->tx_queue[port]); old_len = skb_queue_len(&card->tx_queue[port]);
skb_queue_tail(&card->tx_queue[port], skb); skb_queue_tail(&card->tx_queue[port], skb);
if (!old_len) { if (!old_len)
card->tx_mask |= (1 << port); card->tx_mask |= (1 << port);
}
spin_unlock_irqrestore(&card->tx_queue_lock, flags); spin_unlock_irqrestore(&card->tx_queue_lock, flags);
/* Theoretically we could just schedule the tasklet here, but /* 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,9 +900,9 @@ static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
fpga_tx(card); fpga_tx(card);
} }
static int fpga_tx(struct solos_card *card) static uint32_t fpga_tx(struct solos_card *card)
{ {
uint32_t tx_pending; uint32_t tx_pending, card_flags;
uint32_t tx_started = 0; uint32_t tx_started = 0;
struct sk_buff *skb; struct sk_buff *skb;
struct atm_vcc *vcc; struct atm_vcc *vcc;
...@@ -913,19 +910,24 @@ static int fpga_tx(struct solos_card *card) ...@@ -913,19 +910,24 @@ static int fpga_tx(struct solos_card *card)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&card->tx_lock, flags); spin_lock_irqsave(&card->tx_lock, flags);
tx_pending = ioread32(card->config_regs + FLAGS_ADDR) & card->tx_mask; card_flags = ioread32(card->config_regs + FLAGS_ADDR);
/*
dev_vdbg(&card->dev->dev, "TX Flags are %X\n", tx_pending); * The queue lock is required for _writing_ to tx_mask, but we're
* OK to read it here without locking. The only potential update
for (port = 0; port < card->nr_ports; port++) { * that we could race with is in fpga_queue() where it sets a bit
if (card->atmdev[port] && !(tx_pending & (1 << port))) { * for a new port... but it's going to call this function again if
* it's doing that, anyway.
*/
tx_pending = card->tx_mask & ~card_flags;
for (port = 0; tx_pending; tx_pending >>= 1, port++) {
if (tx_pending & 1) {
struct sk_buff *oldskb = card->tx_skb[port]; struct sk_buff *oldskb = card->tx_skb[port];
if (oldskb) if (oldskb)
pci_unmap_single(card->dev, SKB_CB(oldskb)->dma_addr, pci_unmap_single(card->dev, SKB_CB(oldskb)->dma_addr,
oldskb->len, PCI_DMA_TODEVICE); oldskb->len, PCI_DMA_TODEVICE);
spin_lock(&card->tx_queue_lock); spin_lock(&card->tx_queue_lock);
skb = skb_dequeue(&card->tx_queue[port]); skb = skb_dequeue(&card->tx_queue[port]);
if (!skb) if (!skb)
...@@ -966,8 +968,9 @@ static int fpga_tx(struct solos_card *card) ...@@ -966,8 +968,9 @@ static int fpga_tx(struct solos_card *card)
if (tx_started) if (tx_started)
iowrite32(tx_started, card->config_regs + FLAGS_ADDR); iowrite32(tx_started, card->config_regs + FLAGS_ADDR);
out:
spin_unlock_irqrestore(&card->tx_lock, flags); spin_unlock_irqrestore(&card->tx_lock, flags);
return 0; return card_flags;
} }
static int psend(struct atm_vcc *vcc, struct sk_buff *skb) static int psend(struct atm_vcc *vcc, struct sk_buff *skb)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment