@@ -94,6 +94,7 @@ struct pkt_hdr {
struct solos_skb_cb {
struct atm_vcc *vcc;
uint32_t dma_addr;
+ struct completion *c;
};
@@ -868,6 +869,7 @@ static void pclose(struct atm_vcc *vcc)
struct solos_card *card = vcc->dev->dev_data;
struct sk_buff *skb;
struct pkt_hdr *header;
+ DECLARE_COMPLETION_ONSTACK(c);
skb = alloc_skb(sizeof(*header), GFP_ATOMIC);
if (!skb) {
@@ -881,11 +883,15 @@ static void pclose(struct atm_vcc *vcc)
header->vci = cpu_to_le16(vcc->vci);
header->type = cpu_to_le16(PKT_PCLOSE);
+ SKB_CB(skb)->c = &c;
+
fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL);
clear_bit(ATM_VF_ADDR, &vcc->flags);
clear_bit(ATM_VF_READY, &vcc->flags);
+ wait_for_completion(&c);
+
/* 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 +1017,12 @@ static uint32_t fpga_tx(struct solos_card *card)
if (vcc) {
atomic_inc(&vcc->stats->tx);
solos_pop(vcc, oldskb);
- } else
+ } else {
+ struct pkt_hdr *header = (void *)oldskb->data;
+ if (le16_to_cpu(header->type) == PKT_PCLOSE)
+ complete(SKB_CB(oldskb)->c);
dev_kfree_skb_irq(oldskb);
-
+ }
}
}
/* For non-DMA TX, write the 'TX start' bit for all four ports simultaneously */