diff options
author | David S. Miller <davem@davemloft.net> | 2012-12-01 20:45:24 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-12-01 20:45:24 -0500 |
commit | ddb303301bed80f700db6f36870642a08016f266 (patch) | |
tree | e332b17c20732b22192e2ddec7762c90c19f73b4 /drivers/atm | |
parent | 577b981714b0b3530817569bf705bd74881efc83 (diff) | |
parent | c48d49aab0b5b48b40e00fe43927efed5fc09d88 (diff) |
Merge git://git.infradead.org/users/dwmw2/atm
David Woodhouse says:
====================
This is the result of pulling on the thread started by Krzysztof Mazur's
original patch 'pppoatm: don't send frames to destroyed vcc'.
Various problems in the pppoatm and br2684 code are solved, some of which
were easily triggered and would panic the kernel.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/atm')
-rw-r--r-- | drivers/atm/solos-pci.c | 83 |
1 files changed, 32 insertions, 51 deletions
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 98510931c815..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, | |||
164 | static uint32_t fpga_tx(struct solos_card *); | 164 | static uint32_t fpga_tx(struct solos_card *); |
165 | static irqreturn_t solos_irq(int irq, void *dev_id); | 165 | static irqreturn_t solos_irq(int irq, void *dev_id); |
166 | static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci); | 166 | static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci); |
167 | static int list_vccs(int vci); | ||
168 | static int atm_init(struct solos_card *, struct device *); | 167 | static int atm_init(struct solos_card *, struct device *); |
169 | static void atm_remove(struct solos_card *); | 168 | static void atm_remove(struct solos_card *); |
170 | static int send_command(struct solos_card *card, int dev, const char *buf, size_t size); | 169 | static int send_command(struct solos_card *card, int dev, const char *buf, size_t size); |
@@ -710,7 +709,8 @@ void solos_bh(unsigned long card_arg) | |||
710 | dev_warn(&card->dev->dev, "Received packet for unknown VPI.VCI %d.%d on port %d\n", | 709 | dev_warn(&card->dev->dev, "Received packet for unknown VPI.VCI %d.%d on port %d\n", |
711 | le16_to_cpu(header->vpi), le16_to_cpu(header->vci), | 710 | le16_to_cpu(header->vpi), le16_to_cpu(header->vci), |
712 | port); | 711 | port); |
713 | continue; | 712 | dev_kfree_skb_any(skb); |
713 | break; | ||
714 | } | 714 | } |
715 | atm_charge(vcc, skb->truesize); | 715 | atm_charge(vcc, skb->truesize); |
716 | vcc->push(vcc, skb); | 716 | vcc->push(vcc, skb); |
@@ -790,44 +790,6 @@ static struct atm_vcc *find_vcc(struct atm_dev *dev, short vpi, int vci) | |||
790 | return vcc; | 790 | return vcc; |
791 | } | 791 | } |
792 | 792 | ||
793 | static int list_vccs(int vci) | ||
794 | { | ||
795 | struct hlist_head *head; | ||
796 | struct atm_vcc *vcc; | ||
797 | struct hlist_node *node; | ||
798 | struct sock *s; | ||
799 | int num_found = 0; | ||
800 | int i; | ||
801 | |||
802 | read_lock(&vcc_sklist_lock); | ||
803 | if (vci != 0){ | ||
804 | head = &vcc_hash[vci & (VCC_HTABLE_SIZE -1)]; | ||
805 | sk_for_each(s, node, head) { | ||
806 | num_found ++; | ||
807 | vcc = atm_sk(s); | ||
808 | printk(KERN_DEBUG "Device: %d Vpi: %d Vci: %d\n", | ||
809 | vcc->dev->number, | ||
810 | vcc->vpi, | ||
811 | vcc->vci); | ||
812 | } | ||
813 | } else { | ||
814 | for(i = 0; i < VCC_HTABLE_SIZE; i++){ | ||
815 | head = &vcc_hash[i]; | ||
816 | sk_for_each(s, node, head) { | ||
817 | num_found ++; | ||
818 | vcc = atm_sk(s); | ||
819 | printk(KERN_DEBUG "Device: %d Vpi: %d Vci: %d\n", | ||
820 | vcc->dev->number, | ||
821 | vcc->vpi, | ||
822 | vcc->vci); | ||
823 | } | ||
824 | } | ||
825 | } | ||
826 | read_unlock(&vcc_sklist_lock); | ||
827 | return num_found; | ||
828 | } | ||
829 | |||
830 | |||
831 | static int popen(struct atm_vcc *vcc) | 793 | static int popen(struct atm_vcc *vcc) |
832 | { | 794 | { |
833 | struct solos_card *card = vcc->dev->dev_data; | 795 | struct solos_card *card = vcc->dev->dev_data; |
@@ -840,7 +802,7 @@ static int popen(struct atm_vcc *vcc) | |||
840 | return -EINVAL; | 802 | return -EINVAL; |
841 | } | 803 | } |
842 | 804 | ||
843 | skb = alloc_skb(sizeof(*header), GFP_ATOMIC); | 805 | skb = alloc_skb(sizeof(*header), GFP_KERNEL); |
844 | if (!skb) { | 806 | if (!skb) { |
845 | if (net_ratelimit()) | 807 | if (net_ratelimit()) |
846 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n"); | 808 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n"); |
@@ -857,8 +819,6 @@ static int popen(struct atm_vcc *vcc) | |||
857 | 819 | ||
858 | set_bit(ATM_VF_ADDR, &vcc->flags); | 820 | set_bit(ATM_VF_ADDR, &vcc->flags); |
859 | set_bit(ATM_VF_READY, &vcc->flags); | 821 | set_bit(ATM_VF_READY, &vcc->flags); |
860 | list_vccs(0); | ||
861 | |||
862 | 822 | ||
863 | return 0; | 823 | return 0; |
864 | } | 824 | } |
@@ -866,10 +826,21 @@ static int popen(struct atm_vcc *vcc) | |||
866 | static void pclose(struct atm_vcc *vcc) | 826 | static void pclose(struct atm_vcc *vcc) |
867 | { | 827 | { |
868 | struct solos_card *card = vcc->dev->dev_data; | 828 | struct solos_card *card = vcc->dev->dev_data; |
869 | struct sk_buff *skb; | 829 | unsigned char port = SOLOS_CHAN(vcc->dev); |
830 | struct sk_buff *skb, *tmpskb; | ||
870 | struct pkt_hdr *header; | 831 | struct pkt_hdr *header; |
871 | 832 | ||
872 | skb = alloc_skb(sizeof(*header), GFP_ATOMIC); | 833 | /* Remove any yet-to-be-transmitted packets from the pending queue */ |
834 | spin_lock(&card->tx_queue_lock); | ||
835 | skb_queue_walk_safe(&card->tx_queue[port], skb, tmpskb) { | ||
836 | if (SKB_CB(skb)->vcc == vcc) { | ||
837 | skb_unlink(skb, &card->tx_queue[port]); | ||
838 | solos_pop(vcc, skb); | ||
839 | } | ||
840 | } | ||
841 | spin_unlock(&card->tx_queue_lock); | ||
842 | |||
843 | skb = alloc_skb(sizeof(*header), GFP_KERNEL); | ||
873 | if (!skb) { | 844 | if (!skb) { |
874 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in pclose()\n"); | 845 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in pclose()\n"); |
875 | return; | 846 | return; |
@@ -881,15 +852,22 @@ static void pclose(struct atm_vcc *vcc) | |||
881 | header->vci = cpu_to_le16(vcc->vci); | 852 | header->vci = cpu_to_le16(vcc->vci); |
882 | header->type = cpu_to_le16(PKT_PCLOSE); | 853 | header->type = cpu_to_le16(PKT_PCLOSE); |
883 | 854 | ||
884 | fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL); | 855 | skb_get(skb); |
856 | fpga_queue(card, port, skb, NULL); | ||
885 | 857 | ||
886 | clear_bit(ATM_VF_ADDR, &vcc->flags); | 858 | if (!wait_event_timeout(card->param_wq, !skb_shared(skb), 5 * HZ)) |
887 | clear_bit(ATM_VF_READY, &vcc->flags); | 859 | dev_warn(&card->dev->dev, |
860 | "Timeout waiting for VCC close on port %d\n", port); | ||
861 | |||
862 | dev_kfree_skb(skb); | ||
888 | 863 | ||
889 | /* Hold up vcc_destroy_socket() (our caller) until solos_bh() in the | 864 | /* Hold up vcc_destroy_socket() (our caller) until solos_bh() in the |
890 | tasklet has finished processing any incoming packets (and, more to | 865 | tasklet has finished processing any incoming packets (and, more to |
891 | the point, using the vcc pointer). */ | 866 | the point, using the vcc pointer). */ |
892 | tasklet_unlock_wait(&card->tlet); | 867 | tasklet_unlock_wait(&card->tlet); |
868 | |||
869 | clear_bit(ATM_VF_ADDR, &vcc->flags); | ||
870 | |||
893 | return; | 871 | return; |
894 | } | 872 | } |
895 | 873 | ||
@@ -1011,9 +989,10 @@ static uint32_t fpga_tx(struct solos_card *card) | |||
1011 | if (vcc) { | 989 | if (vcc) { |
1012 | atomic_inc(&vcc->stats->tx); | 990 | atomic_inc(&vcc->stats->tx); |
1013 | solos_pop(vcc, oldskb); | 991 | solos_pop(vcc, oldskb); |
1014 | } else | 992 | } else { |
1015 | dev_kfree_skb_irq(oldskb); | 993 | dev_kfree_skb_irq(oldskb); |
1016 | 994 | wake_up(&card->param_wq); | |
995 | } | ||
1017 | } | 996 | } |
1018 | } | 997 | } |
1019 | /* For non-DMA TX, write the 'TX start' bit for all four ports simultaneously */ | 998 | /* For non-DMA TX, write the 'TX start' bit for all four ports simultaneously */ |
@@ -1248,7 +1227,7 @@ static int atm_init(struct solos_card *card, struct device *parent) | |||
1248 | card->atmdev[i]->phy_data = (void *)(unsigned long)i; | 1227 | card->atmdev[i]->phy_data = (void *)(unsigned long)i; |
1249 | atm_dev_signal_change(card->atmdev[i], ATM_PHY_SIG_FOUND); | 1228 | atm_dev_signal_change(card->atmdev[i], ATM_PHY_SIG_FOUND); |
1250 | 1229 | ||
1251 | skb = alloc_skb(sizeof(*header), GFP_ATOMIC); | 1230 | skb = alloc_skb(sizeof(*header), GFP_KERNEL); |
1252 | if (!skb) { | 1231 | if (!skb) { |
1253 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in atm_init()\n"); | 1232 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in atm_init()\n"); |
1254 | continue; | 1233 | continue; |
@@ -1345,6 +1324,8 @@ static struct pci_driver fpga_driver = { | |||
1345 | 1324 | ||
1346 | static int __init solos_pci_init(void) | 1325 | static int __init solos_pci_init(void) |
1347 | { | 1326 | { |
1327 | BUILD_BUG_ON(sizeof(struct solos_skb_cb) > sizeof(((struct sk_buff *)0)->cb)); | ||
1328 | |||
1348 | printk(KERN_INFO "Solos PCI Driver Version %s\n", VERSION); | 1329 | printk(KERN_INFO "Solos PCI Driver Version %s\n", VERSION); |
1349 | return pci_register_driver(&fpga_driver); | 1330 | return pci_register_driver(&fpga_driver); |
1350 | } | 1331 | } |