Commit f11682f8 authored by Chas Williams's avatar Chas Williams Committed by David S. Miller

[ATM]: [lec] put back pressure on network stack

parent 4b76ddd9
......@@ -67,7 +67,7 @@ extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
single destination while waiting for SVC */
static int lec_open(struct net_device *dev);
static int lec_send_packet(struct sk_buff *skb, struct net_device *dev);
static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int lec_close(struct net_device *dev);
static struct net_device_stats *lec_get_stats(struct net_device *dev);
static void lec_init(struct net_device *dev);
......@@ -211,26 +211,34 @@ lec_open(struct net_device *dev)
static __inline__ void
lec_send(struct atm_vcc *vcc, struct sk_buff *skb, struct lec_priv *priv)
{
if (atm_may_send(vcc, skb->len)) {
atomic_add(skb->truesize, &vcc->sk->sk_wmem_alloc);
ATM_SKB(skb)->vcc = vcc;
ATM_SKB(skb)->atm_options = vcc->atm_options;
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb->len;
vcc->send(vcc, skb);
} else {
ATM_SKB(skb)->vcc = vcc;
ATM_SKB(skb)->atm_options = vcc->atm_options;
atomic_add(skb->truesize, &vcc->sk->sk_wmem_alloc);
if (vcc->send(vcc, skb) < 0) {
priv->stats.tx_dropped++;
dev_kfree_skb(skb);
return;
}
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb->len;
}
static void
lec_tx_timeout(struct net_device *dev)
{
printk(KERN_INFO "%s: tx timeout\n", dev->name);
dev->trans_start = jiffies;
netif_wake_queue(dev);
}
static int
lec_send_packet(struct sk_buff *skb, struct net_device *dev)
lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct sk_buff *skb2;
struct lec_priv *priv = (struct lec_priv *)dev->priv;
struct lecdatahdr_8023 *lec_h;
struct atm_vcc *send_vcc;
struct atm_vcc *vcc;
struct lec_arp_table *entry;
unsigned char *dst;
int min_frame_size;
......@@ -243,7 +251,7 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev)
int i=0;
#endif /* DUMP_PACKETS >0 */
DPRINTK("Lec_send_packet called\n");
DPRINTK("lec_start_xmit called\n");
if (!priv->lecd) {
printk("%s:No lecd attached\n",dev->name);
priv->stats.tx_errors++;
......@@ -262,7 +270,7 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev)
/* Make sure we have room for lec_id */
if (skb_headroom(skb) < 2) {
DPRINTK("lec_send_packet: reallocating skb\n");
DPRINTK("lec_start_xmit: reallocating skb\n");
skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
kfree_skb(skb);
if (skb2 == NULL) return 0;
......@@ -337,18 +345,18 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev)
}
#endif
entry = NULL;
send_vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
DPRINTK("%s:send_vcc:%p vcc_flags:%x, entry:%p\n", dev->name,
send_vcc, send_vcc?send_vcc->flags:0, entry);
if (!send_vcc || !test_bit(ATM_VF_READY,&send_vcc->flags)) {
vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
DPRINTK("%s:vcc:%p vcc_flags:%x, entry:%p\n", dev->name,
vcc, vcc?vcc->flags:0, entry);
if (!vcc || !test_bit(ATM_VF_READY,&vcc->flags)) {
if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) {
DPRINTK("%s:lec_send_packet: queuing packet, ", dev->name);
DPRINTK("%s:lec_start_xmit: queuing packet, ", dev->name);
DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
skb_queue_tail(&entry->tx_wait, skb);
} else {
DPRINTK("%s:lec_send_packet: tx queue full or no arp entry, dropping, ", dev->name);
DPRINTK("%s:lec_start_xmit: tx queue full or no arp entry, dropping, ", dev->name);
DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
......@@ -360,7 +368,7 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev)
#if DUMP_PACKETS > 0
printk("%s:sending to vpi:%d vci:%d\n", dev->name,
send_vcc->vpi, send_vcc->vci);
vcc->vpi, vcc->vci);
#endif /* DUMP_PACKETS > 0 */
while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
......@@ -368,15 +376,28 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev)
DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
lec_send(send_vcc, skb2, priv);
lec_send(vcc, skb2, priv);
}
lec_send(send_vcc, skb, priv);
lec_send(vcc, skb, priv);
#if 0
/* Should we wait for card's device driver to notify us? */
dev->tbusy=0;
#endif
if (!atm_may_send(vcc, 0)) {
struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
vpriv->xoff = 1;
netif_stop_queue(dev);
/*
* vcc->pop() might have occurred in between, making
* the vcc usuable again. Since xmit is serialized,
* this is the only situation we have to re-test.
*/
if (atm_may_send(vcc, 0))
netif_wake_queue(dev);
}
dev->trans_start = jiffies;
return 0;
}
......@@ -635,7 +656,8 @@ lec_init(struct net_device *dev)
dev->change_mtu = lec_change_mtu;
dev->open = lec_open;
dev->stop = lec_close;
dev->hard_start_xmit = lec_send_packet;
dev->hard_start_xmit = lec_start_xmit;
dev->tx_timeout = lec_tx_timeout;
dev->get_stats = lec_get_stats;
dev->set_multicast_list = lec_set_multicast_list;
......@@ -731,9 +753,30 @@ lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
}
}
void
lec_pop(struct atm_vcc *vcc, struct sk_buff *skb)
{
struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
struct net_device *dev = skb->dev;
if (vpriv == NULL) {
printk("lec_pop(): vpriv = NULL!?!?!?\n");
return;
}
vpriv->old_pop(vcc, skb);
if (vpriv->xoff && atm_may_send(vcc, 0)) {
vpriv->xoff = 0;
if (netif_running(dev) && netif_queue_stopped(dev))
netif_wake_queue(dev);
}
}
int
lec_vcc_attach(struct atm_vcc *vcc, void *arg)
{
struct lec_vcc_priv *vpriv;
int bytes_left;
struct atmlec_ioc ioc_data;
......@@ -746,6 +789,12 @@ lec_vcc_attach(struct atm_vcc *vcc, void *arg)
if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF ||
!dev_lec[ioc_data.dev_num])
return -EINVAL;
if (!(vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL)))
return -ENOMEM;
vpriv->xoff = 0;
vpriv->old_pop = vcc->pop;
LEC_VCC_PRIV(vcc) = vpriv;
vcc->pop = lec_pop;
lec_vcc_added(dev_lec[ioc_data.dev_num]->priv,
&ioc_data, vcc, vcc->push);
vcc->push = lec_push;
......@@ -1363,22 +1412,21 @@ void
lec_arp_clear_vccs(struct lec_arp_table *entry)
{
if (entry->vcc) {
entry->vcc->push = entry->old_push;
#if 0 /* August 6, 1998 */
set_bit(ATM_VF_RELEASED,&entry->vcc->flags);
clear_bit(ATM_VF_READY,&entry->vcc->flags);
entry->vcc->push(entry->vcc, NULL);
#endif
vcc_release_async(entry->vcc, -EPIPE);
entry->vcc = NULL;
struct atm_vcc *vcc = entry->vcc;
struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
struct net_device *dev = (struct net_device*) vcc->proto_data;
vcc->pop = vpriv->old_pop;
if (vpriv->xoff)
netif_wake_queue(dev);
kfree(vpriv);
LEC_VCC_PRIV(vcc) = NULL;
vcc->push = entry->old_push;
vcc_release_async(vcc, -EPIPE);
vcc = NULL;
}
if (entry->recv_vcc) {
entry->recv_vcc->push = entry->old_recv_push;
#if 0
set_bit(ATM_VF_RELEASED,&entry->recv_vcc->flags);
clear_bit(ATM_VF_READY,&entry->recv_vcc->flags);
entry->recv_vcc->push(entry->recv_vcc, NULL);
#endif
vcc_release_async(entry->recv_vcc, -EPIPE);
entry->recv_vcc = NULL;
}
......@@ -2320,11 +2368,20 @@ lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
unsigned char mac_addr[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
struct lec_arp_table *to_add;
struct lec_vcc_priv *vpriv;
if (!(vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL)))
return -ENOMEM;
vpriv->xoff = 0;
vpriv->old_pop = vcc->pop;
LEC_VCC_PRIV(vcc) = vpriv;
vcc->pop = lec_pop;
lec_arp_get(priv);
to_add = make_entry(priv, mac_addr);
if (!to_add) {
lec_arp_put(priv);
vcc->pop = vpriv->old_pop;
kfree(vpriv);
return -ENOMEM;
}
memcpy(to_add->atm_addr, vcc->remote.sas_addr.prv, ATM_ESA_LEN);
......
......@@ -139,6 +139,13 @@ struct lec_priv {
int is_trdev; /* Device type, 0 = Ethernet, 1 = TokenRing */
};
struct lec_vcc_priv {
void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb);
int xoff;
};
#define LEC_VCC_PRIV(vcc) ((struct lec_vcc_priv *)((vcc)->user_back))
int lecd_attach(struct atm_vcc *vcc, int arg);
int lec_vcc_attach(struct atm_vcc *vcc, void *arg);
int lec_mcast_attach(struct atm_vcc *vcc, int arg);
......
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