From 7ad3eadebcb1778c11bbf0fe059d0804173a8123 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 27 Nov 2012 23:49:24 +0000 Subject: solos-pci: wait for pending TX to complete when releasing vcc We should no longer be calling the old pop routine for the vcc, after vcc_release() has completed. Make sure we wait for any pending TX skbs to complete, by waiting for our own PKT_PCLOSE control skb to be sent. Signed-off-by: David Woodhouse --- drivers/atm/solos-pci.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers/atm') diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 98510931c815..026bdc1dfcc6 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -866,6 +866,7 @@ static int popen(struct atm_vcc *vcc) static void pclose(struct atm_vcc *vcc) { struct solos_card *card = vcc->dev->dev_data; + unsigned char port = SOLOS_CHAN(vcc->dev); struct sk_buff *skb; struct pkt_hdr *header; @@ -881,11 +882,18 @@ static void pclose(struct atm_vcc *vcc) header->vci = cpu_to_le16(vcc->vci); header->type = cpu_to_le16(PKT_PCLOSE); - fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL); + skb_get(skb); + fpga_queue(card, port, skb, NULL); clear_bit(ATM_VF_ADDR, &vcc->flags); clear_bit(ATM_VF_READY, &vcc->flags); + if (!wait_event_timeout(card->param_wq, !skb_shared(skb), 5 * HZ)) + dev_warn(&card->dev->dev, + "Timeout waiting for VCC close on port %d\n", port); + + dev_kfree_skb(skb); + /* Hold up vcc_destroy_socket() (our caller) until solos_bh() in the tasklet has finished processing any incoming packets (and, more to the point, using the vcc pointer). */ @@ -1011,9 +1019,10 @@ static uint32_t fpga_tx(struct solos_card *card) if (vcc) { atomic_inc(&vcc->stats->tx); solos_pop(vcc, oldskb); - } else + } else { dev_kfree_skb_irq(oldskb); - + wake_up(&card->param_wq); + } } } /* For non-DMA TX, write the 'TX start' bit for all four ports simultaneously */ @@ -1345,6 +1354,8 @@ static struct pci_driver fpga_driver = { static int __init solos_pci_init(void) { + BUILD_BUG_ON(sizeof(struct solos_skb_cb) > sizeof(((struct sk_buff *)0)->cb)); + printk(KERN_INFO "Solos PCI Driver Version %s\n", VERSION); return pci_register_driver(&fpga_driver); } -- cgit v1.2.3 From 007ef52be171b9eee6f4099d3e5706e8068d31ef Mon Sep 17 00:00:00 2001 From: Nathan Williams Date: Tue, 27 Nov 2012 17:34:09 +1100 Subject: solos-pci: Fix leak of skb received for unknown vcc ... and ensure that the next skb is set up for RX in the DMA case. Signed-off-by: Nathan Williams Signed-off-by: David Woodhouse --- drivers/atm/solos-pci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/atm') diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 026bdc1dfcc6..f0863b443762 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -710,7 +710,8 @@ void solos_bh(unsigned long card_arg) dev_warn(&card->dev->dev, "Received packet for unknown VPI.VCI %d.%d on port %d\n", le16_to_cpu(header->vpi), le16_to_cpu(header->vci), port); - continue; + dev_kfree_skb_any(skb); + break; } atm_charge(vcc, skb->truesize); vcc->push(vcc, skb); -- cgit v1.2.3 From 213e85d389124f49c82d52cfb4473b8bb672f7c1 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 29 Nov 2012 23:15:30 +0000 Subject: solos-pci: clean up pclose() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Flush pending TX skbs from the queue rather than waiting for them all to complete (suggested by Krzysztof Mazur ). - Clear ATM_VF_ADDR only when the PKT_PCLOSE packet has been submitted. - Don't clear ATM_VF_READY at all — vcc_destroy_socket() does that for us. Signed-off-by: David Woodhouse --- drivers/atm/solos-pci.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers/atm') diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index f0863b443762..3f7c4ef1e111 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -868,9 +868,19 @@ static void pclose(struct atm_vcc *vcc) { struct solos_card *card = vcc->dev->dev_data; unsigned char port = SOLOS_CHAN(vcc->dev); - struct sk_buff *skb; + struct sk_buff *skb, *tmpskb; struct pkt_hdr *header; + /* Remove any yet-to-be-transmitted packets from the pending queue */ + spin_lock(&card->tx_queue_lock); + skb_queue_walk_safe(&card->tx_queue[port], skb, tmpskb) { + if (SKB_CB(skb)->vcc == vcc) { + skb_unlink(skb, &card->tx_queue[port]); + solos_pop(vcc, skb); + } + } + spin_unlock(&card->tx_queue_lock); + skb = alloc_skb(sizeof(*header), GFP_ATOMIC); if (!skb) { dev_warn(&card->dev->dev, "Failed to allocate sk_buff in pclose()\n"); @@ -886,9 +896,6 @@ static void pclose(struct atm_vcc *vcc) skb_get(skb); fpga_queue(card, port, skb, NULL); - clear_bit(ATM_VF_ADDR, &vcc->flags); - clear_bit(ATM_VF_READY, &vcc->flags); - if (!wait_event_timeout(card->param_wq, !skb_shared(skb), 5 * HZ)) dev_warn(&card->dev->dev, "Timeout waiting for VCC close on port %d\n", port); @@ -899,6 +906,9 @@ static void pclose(struct atm_vcc *vcc) tasklet has finished processing any incoming packets (and, more to the point, using the vcc pointer). */ tasklet_unlock_wait(&card->tlet); + + clear_bit(ATM_VF_ADDR, &vcc->flags); + return; } -- cgit v1.2.3 From a1db5c5b75d6781e8e4dcd6621d5c10463bee0ef Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 29 Nov 2012 23:27:20 +0000 Subject: solos-pci: use GFP_KERNEL where possible, not GFP_ATOMIC Signed-off-by: David Woodhouse --- drivers/atm/solos-pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/atm') diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 3f7c4ef1e111..e3c25dc9edc1 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -841,7 +841,7 @@ static int popen(struct atm_vcc *vcc) return -EINVAL; } - skb = alloc_skb(sizeof(*header), GFP_ATOMIC); + skb = alloc_skb(sizeof(*header), GFP_KERNEL); if (!skb) { if (net_ratelimit()) dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n"); @@ -881,7 +881,7 @@ static void pclose(struct atm_vcc *vcc) } spin_unlock(&card->tx_queue_lock); - skb = alloc_skb(sizeof(*header), GFP_ATOMIC); + skb = alloc_skb(sizeof(*header), GFP_KERNEL); if (!skb) { dev_warn(&card->dev->dev, "Failed to allocate sk_buff in pclose()\n"); return; @@ -1268,7 +1268,7 @@ static int atm_init(struct solos_card *card, struct device *parent) card->atmdev[i]->phy_data = (void *)(unsigned long)i; atm_dev_signal_change(card->atmdev[i], ATM_PHY_SIG_FOUND); - skb = alloc_skb(sizeof(*header), GFP_ATOMIC); + skb = alloc_skb(sizeof(*header), GFP_KERNEL); if (!skb) { dev_warn(&card->dev->dev, "Failed to allocate sk_buff in atm_init()\n"); continue; -- cgit v1.2.3 From c48d49aab0b5b48b40e00fe43927efed5fc09d88 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 29 Nov 2012 23:28:30 +0000 Subject: solos-pci: remove list_vccs() debugging function No idea why we've gone so long dumping a list of VCCs with vci==0 on every ->open() call... Signed-off-by: David Woodhouse --- drivers/atm/solos-pci.c | 41 ----------------------------------------- 1 file changed, 41 deletions(-) (limited to 'drivers/atm') diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index e3c25dc9edc1..6619a8a9607c 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -164,7 +164,6 @@ static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, static uint32_t fpga_tx(struct solos_card *); 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 int list_vccs(int vci); static int atm_init(struct solos_card *, struct device *); static void atm_remove(struct solos_card *); static int send_command(struct solos_card *card, int dev, const char *buf, size_t size); @@ -791,44 +790,6 @@ static struct atm_vcc *find_vcc(struct atm_dev *dev, short vpi, int vci) return vcc; } -static int list_vccs(int vci) -{ - struct hlist_head *head; - struct atm_vcc *vcc; - struct hlist_node *node; - struct sock *s; - int num_found = 0; - int i; - - read_lock(&vcc_sklist_lock); - if (vci != 0){ - head = &vcc_hash[vci & (VCC_HTABLE_SIZE -1)]; - sk_for_each(s, node, head) { - num_found ++; - vcc = atm_sk(s); - printk(KERN_DEBUG "Device: %d Vpi: %d Vci: %d\n", - vcc->dev->number, - vcc->vpi, - vcc->vci); - } - } else { - for(i = 0; i < VCC_HTABLE_SIZE; i++){ - head = &vcc_hash[i]; - sk_for_each(s, node, head) { - num_found ++; - vcc = atm_sk(s); - printk(KERN_DEBUG "Device: %d Vpi: %d Vci: %d\n", - vcc->dev->number, - vcc->vpi, - vcc->vci); - } - } - } - read_unlock(&vcc_sklist_lock); - return num_found; -} - - static int popen(struct atm_vcc *vcc) { struct solos_card *card = vcc->dev->dev_data; @@ -858,8 +819,6 @@ static int popen(struct atm_vcc *vcc) set_bit(ATM_VF_ADDR, &vcc->flags); set_bit(ATM_VF_READY, &vcc->flags); - list_vccs(0); - return 0; } -- cgit v1.2.3