diff -ur --new-file old/linux/Documentation/Configure.help new/linux/Documentation/Configure.help --- old/linux/Documentation/Configure.help Wed Jan 29 22:33:04 1997 +++ new/linux/Documentation/Configure.help Wed Jan 29 22:33:36 1997 @@ -1311,9 +1311,7 @@ IDT 77201 (NICStAR) CONFIG_ATM_NICSTAR Driver for the IDT 77201 (NICStAR) ATM adapter. Written by Matt Welsh - and Stuart Daniel . Note that this driver - currently only works with native ATM (i.e. not with IP over ATM or - LANE). + and Stuart Daniel . SCSI support? CONFIG_SCSI diff -ur --new-file old/linux/drivers/atm/nicstar.c new/linux/drivers/atm/nicstar.c --- old/linux/drivers/atm/nicstar.c Wed Jan 29 22:33:05 1997 +++ new/linux/drivers/atm/nicstar.c Wed Jan 29 22:33:37 1997 @@ -6,6 +6,22 @@ * expects the Linux ATM stack to support scatter-gather lists * (skb->atm.iovcnt != 0) for Rx skb's passed to vcc->push. * + * Implementing minimal-copy of received data: + * IDT always receives data into a small buffer, then large buffers + * as needed. This means that data must always be copied to create + * the linear buffer needed by most non-ATM protocol stacks (e.g. IP) + * Fix is simple: make large buffers large enough to hold entire + * SDU, and leave bytes empty at the start. Then + * copy small buffer contents to head of large buffer. + * Trick is to avoid fragmenting Linux, due to need for a lot of large + * buffers. This is done by 2 things: + * 1) skb->destructor / skb->atm.recycle_buffer + * combined, allow nicstar_free_rx_skb to be called to + * recycle large data buffers + * 2) skb_clone of received buffers + * See nicstar_free_rx_skb and linearize_buffer for implementation + * details. + * * Copyright (c) 1996 University of Cambridge Computer Laboratory * * This program is free software; you can redistribute it and/or modify @@ -25,8 +41,9 @@ * M. Welsh, 6 July 1996 * */ - -static char _modversion[] = "@(#) nicstar.c, $Id: nicstar.c,v 1.31 1996/11/25 21:05:54 swdaniel Exp $"; +/* +static char _modversion[] = "@(#) nicstar.c, $Id: nicstar.c,v 1.35 1997/01/08 22:27:12 swdaniel Exp $"; +*/ #include #include @@ -52,13 +69,14 @@ #include #include - #include char kernel_version[] = UTS_RELEASE; #include "nicstar.h" +#include "../../net/atm/protocols.h" /* hack! */ #undef NICSTAR_DEBUG /* Define for verbose debugging output */ +#define NICSTAR_RC_FLAG 1 #ifdef NICSTAR_DEBUG #define PRINTK(args...) printk(args) @@ -121,6 +139,8 @@ static void close_cbr_final (nicstar_devp node, struct atm_vcc *vcc); #endif static int create_scq (struct nicstar_scq **scq, int size); +static u32 linearize_buffer (struct nicstar_dev *node, struct sk_buff *skb, + struct atm_vcc *vcc); /* Module entry points *****************************************************/ @@ -983,24 +1003,32 @@ return -ENOMEM; } - node->lg_bufs = (caddr_t)kmalloc(LG_BUFSZ * NUM_LG_BUFS, GFP_KERNEL); +#if 0 + /* Old code for handling large buffers */ + node->lg_bufs = (caddr_t)kmalloc((SM_BUFSZ + LG_BUFSZ) * NUM_LG_BUFS, GFP_KERNEL); if (!node->lg_bufs) { printk("nicstar%d: Can't allocate %d %d-byte large buffers!\n", node->index, NUM_LG_BUFS, LG_BUFSZ); return -ENOMEM; } - - printk("nicstar%d: Small buffers at 0x%x, Large buffers at 0x%x.\n", - node->index, (u32)node->sm_bufs, (u32)node->lg_bufs); + p = node->lg_bufs + SM_BUFSZ; +#endif + for (i = 0; i < NUM_LG_BUFS; i++) { + node->rx_lg_skb[i] = alloc_skb(SM_BUFSZ + LG_BUFSZ, GFP_KERNEL); + skb_reserve(node->rx_lg_skb[i],SM_BUFSZ); + } #if NICSTAR_RCQ - node->rcq.rcq_head = (u32) node->lg_bufs; - node->rcq.rcq_base = (u32) node->lg_bufs; + node->rcq.rcq_head = (u32) rx_lg_skb[0]->data; + node->rcq.rcq_base = (u32) rx_lg_skb[0]->data; /* Manual says we should check head vs tail here; but tail reg isn't updated until after we turn on RX path. Moved check to end of init_module... */ #endif +#if NICSTAR_LBUFCNT + node->lbuf_cnt = NUM_LG_BUFS - 1; +#endif for (i = 0; i < NUM_SM_BUFS; i+=2) { push_rxbufs(node, 0, (u32)(node->sm_bufs + (i*SM_BUFSZ) + 4), @@ -1011,16 +1039,19 @@ for (i = 0; i < NUM_LG_BUFS; i+=2) { push_rxbufs(node, 1, - (u32)(node->lg_bufs + (i*LG_BUFSZ)), - (u32)(node->lg_bufs + (i*LG_BUFSZ)), - (u32)(node->lg_bufs + ((i+1)*LG_BUFSZ)), - (u32)(node->lg_bufs + ((i+1)*LG_BUFSZ))); + (u32)(node->rx_lg_skb[i]->data), + (u32)(node->rx_lg_skb[i]->data), + (u32)(node->rx_lg_skb[i+1]->data), + (u32)(node->rx_lg_skb[i+1]->data)); } skb_queue_head_init(&node->rx_skb_queue); for (i = 0; i < NUM_RX_SKB; i++) { struct sk_buff *skb; - skb = alloc_skb(MAX_SDU_BUFS * sizeof(struct iovec), GFP_KERNEL); + skb = alloc_skb( + SM_BUFSZ > MAX_SDU_BUFS * sizeof(struct iovec) ? + SM_BUFSZ : MAX_SDU_BUFS * sizeof(struct iovec), + GFP_KERNEL); if (!skb) { printk("nicstar%d: Can't allocate Rx skb!\n",node->index); return -ENOMEM; @@ -1085,12 +1116,12 @@ #if NICSTAR_RCQ /* Turn on everything */ - writel(0x21801c38 | CFG_VPIVCI | 0x200 | 0x800, node->membase+CFG); + writel(0x21801c38 | LG_BUFMSK | CFG_VPIVCI | 0x200 | 0x800, node->membase+CFG); /* | 0x800 turns on raw cell interrupts */ /* | 0x200 for raw cell receive */ /* | 0x8000 to receive cells that don't map via RCT (not there/closed) */ #else - writel(0x21801c38 | CFG_VPIVCI, node->membase+CFG); /* Turn on everything */ + writel(0x21801c38 | LG_BUFMSK | CFG_VPIVCI, node->membase+CFG); /* Turn on everything */ #endif while(CMD_BUSY(node)); @@ -1572,6 +1603,10 @@ lg_buf = buf_addr; } else { u32 buf; + +#ifdef NICSTAR_LBUFCNT + node->lbuf_cnt += 2; +#endif buf = buf_addr; push_rxbufs(node, 1, lg_buf, lg_buf, buf, buf); lg_buf = 0x0; @@ -1643,7 +1678,12 @@ skb->atm.iovcnt++; vcc->stats->rx++; skb->atm.timestamp = xtime; - vcc->push(vcc, skb); + if ((u32) vcc->push != (u32) atm_push_raw) { + skb = (struct sk_buff *) linearize_buffer(node,skb,vcc); + } + if (skb) { + vcc->push(vcc, skb); + } mapval->rx_skb = NULL; return; } @@ -1660,9 +1700,22 @@ iov->iov_len = aal5_len - skb->len; skb->len = aal5_len; skb->atm.iovcnt++; +#ifdef NICSTAR_LBUFCNT + node->lbuf_cnt -= (skb->atm.iovcnt - 1); +#endif + PRINTK("Received %d-buffer message %x\n",skb->atm.iovcnt,skb); vcc->stats->rx++; - - vcc->push(vcc, skb); + + + if ((u32) vcc->push != (u32) atm_push_raw) { + skb = (struct sk_buff *) linearize_buffer(node,skb,vcc); + PRINTK("rcv %d-buf len %d\n",skb->atm.iovcnt,skb->len); + } + PRINTK("after is rcv %d-buf len %d\n",skb->atm.iovcnt,skb->len); + + if (skb) { + vcc->push(vcc, skb); + } mapval->rx_skb = NULL; } else { iov->iov_len = (entry->status & 0x1ff) * 48; @@ -1686,6 +1739,15 @@ return; } +static void nicstar_rx_skb_destructor (struct sk_buff *skb) { + if (skb->count > 1) return; +#if NICSTAR_RC_FLAG + nicstar_free_rx_skb((struct atm_vcc *) skb->atm.recycle_buffer,skb); +#else + nicstar_free_rx_skb((struct atm_vcc *) skb->atm.vcc,skb); +#endif +} + static void nicstar_free_rx_skb(struct atm_vcc *vcc, struct sk_buff *skb) { nicstar_devp node = vcc->dev->dev_data; struct iovec *iov; @@ -1693,37 +1755,52 @@ u32 ptr_chk; if (!skb->atm.iovcnt) { - /* XXX mdw: Eventually support this for single-cell transfers */ - printk("nicstar%d: free_rx_skb on non-iovec skb?\n", - node->index); - return; + for (i = 0; i < NUM_LG_BUFS; i++) { + if (node->rx_lg_skb[i]->head == skb->head) break; + } + if (i < NUM_LG_BUFS) { + /* this had better be a large buffer on the rebound (SWD) */ + /* restore data pointers */ + (node->rx_lg_skb[i])->data = (node->rx_lg_skb[i])->head + SM_BUF_DATALEN; + (node->rx_lg_skb[i])->len = 0; + (node->rx_lg_skb[i])->tail = (node->rx_lg_skb[i])->data; + free_rx_buf(node, 1, (u32)((node->rx_lg_skb[i])->data)); + return; + } + else { + /* i > NUM_LG_BUFS ==> small buffer, which has already */ + /* been recycled; just requeue this skb after resetting */ + /* tail */ + return; + } } - - iov = (struct iovec *)skb->data; - for (i = 0; i < skb->atm.iovcnt; i++) { - if (((unsigned char *)iov[i].iov_base >= (unsigned char *)node->sm_bufs) && - ((unsigned char *)iov[i].iov_base < (unsigned char *)node->sm_bufs + SM_BUFSZ * NUM_SM_BUFS)) { - ptr_chk = (u32)iov[i].iov_base == (u32)node->sm_bufs ? 48 : - ((u32)iov[i].iov_base - ((u32)node->sm_bufs + 4)) % SM_BUFSZ; - if (ptr_chk) { - iov[0].iov_base += 4; -#ifdef NICSTAR_PARANOID - if (ptr_chk != 48) { - printk ("nicstar%d: Misaligned buffer pointer (offset %d)!\n", - node->index,ptr_chk); - } + else { /* handle s-g buffer */ + iov = (struct iovec *)skb->data; + for (i = 0; i < skb->atm.iovcnt; i++) { + if (((unsigned char *)iov[i].iov_base >= (unsigned char *)node->sm_bufs) && + ((unsigned char *)iov[i].iov_base < (unsigned char *)node->sm_bufs + SM_BUFSZ * NUM_SM_BUFS)) { ptr_chk = (u32)iov[i].iov_base == (u32)node->sm_bufs ? 48 : ((u32)iov[i].iov_base - ((u32)node->sm_bufs + 4)) % SM_BUFSZ; if (ptr_chk) { - printk("nicstar%d: Misaligned pointer STILL NOT FIXED!!! %x %d\n", - node->index,(u32)iov[i].iov_base,ptr_chk); - } + iov[0].iov_base += 4; +#ifdef NICSTAR_PARANOID + if (ptr_chk != 48) { + printk ("nicstar%d: Misaligned buffer pointer (offset %d)!\n", + node->index,ptr_chk); + } + ptr_chk = (u32)iov[i].iov_base == (u32)node->sm_bufs ? 48 : + ((u32)iov[i].iov_base - ((u32)node->sm_bufs + 4)) % SM_BUFSZ; + if (ptr_chk) { + printk("nicstar%d: Misaligned pointer STILL NOT FIXED!!! %x %d\n", + node->index,(u32)iov[i].iov_base,ptr_chk); + } #endif + } + free_rx_buf(node, 0, (u32)(iov[i].iov_base)); + } else { + /* Large buffer */ + free_rx_buf(node, 1, (u32)(iov[i].iov_base)); } - free_rx_buf(node, 0, (u32)(iov[i].iov_base)); - } else { - /* Large buffer */ - free_rx_buf(node, 1, (u32)(iov[i].iov_base)); } } @@ -1832,15 +1909,6 @@ } slots--; } -#if 0 /* dumps TST */ - for (i = 0; i < TST_SIZE; i+=4) { - printk("%d %08x %08x %08x %08x\n",i, - read_sram(node, NICSTAR_TST_REGION + i), - read_sram(node, NICSTAR_TST_REGION + i + 1), - read_sram(node, NICSTAR_TST_REGION + i + 2), - read_sram(node, NICSTAR_TST_REGION + i + 3)); - } -#endif } /* Closes down a CBR connection. */ @@ -1904,7 +1972,7 @@ kfree(((nicstar_vcimap *)vcc->dev_data)->scq->orig); kfree(((nicstar_vcimap *)vcc->dev_data)->scq); } -#endif +#endif /* NICSTAR_CBR */ /* General function for creating transmission SCQs */ static int create_scq (struct nicstar_scq **scq, int size) { @@ -1923,4 +1991,84 @@ memset (((*scq)->scq_shadow), 0, (SCQ_ENTRIES) * (sizeof(struct nicstar_scq_shadow))); return 0; +} + +static u32 linearize_buffer (struct nicstar_dev *node, struct sk_buff *skb, struct atm_vcc *vcc) { + struct iovec *iov = (struct iovec *)skb->data; + struct sk_buff *skb_new; + + if (skb->atm.iovcnt > 2) { /* huge buffer */ + int el, cnt; + unsigned char *p; + + /* copy data to new skb (brute force), only for huge SDUs */ + skb_new = alloc_skb(skb->len,GFP_ATOMIC); + if (!skb_new) { + printk("nicstar%d: Can't get skbuff for s-g ip receive of huge buffer (%d bytes)\n",node->index,(u32)skb->len); + nicstar_free_rx_skb(vcc, skb); + return 0; + } + p = skb_new->data; + el = skb->len; + skb_put(skb_new,skb->len); + skb_new->free = 1; + for (cnt = 0; (cnt < skb->atm.iovcnt) && el; cnt++) { + memcpy(p, iov->iov_base, + (iov->iov_len > el) ? el : iov->iov_len); + p += iov->iov_len; + el -= (iov->iov_len > el)?el:iov->iov_len; + iov++; + } + nicstar_free_rx_skb(vcc, skb); + return (u32) skb_new; + } + else if (skb->atm.iovcnt == 2) { + /* simply copy small buffer to free space at start of large */ + int i; + + /* which large buffer are we? */ + iov++; + for (i = 0; i < NUM_LG_BUFS ; i++) { + if ((node->rx_lg_skb[i])->data == iov->iov_base) { + break; + } + } + if (i >= NUM_LG_BUFS) { + /* should probably copy instead */ + printk("nicstar%d: Corresponding large buffer not found! dropping packet. i %d vcc %x skb %x data %x\n", + node->index, i,vcc,skb,skb->data); + nicstar_free_rx_skb(vcc,skb); + return 0; + } + skb_put(node->rx_lg_skb[i],iov->iov_len); + iov--; + skb_push(node->rx_lg_skb[i],SM_BUF_DATALEN); + memcpy((node->rx_lg_skb[i])->data,iov->iov_base,SM_BUF_DATALEN); + skb->atm.iovcnt--; +#ifdef NICSTAR_LBUFCNT + PRINTK("2-buffer receive (IP?) len %d old %x new %x node %x cnt %d vcc %x\n",skb->len,skb,node->rx_lg_skb[i],node,node->lbuf_cnt,vcc); +#endif + nicstar_free_rx_skb(vcc,skb); + skb_new = skb_clone(node->rx_lg_skb[i], GFP_ATOMIC); +#ifdef NICSTAR_RC_FLAG + skb_new->atm.recycle_buffer = (void *) vcc; +#endif + skb_new->destructor = nicstar_rx_skb_destructor; + return (u32) skb_new; + } + else { + caddr_t p = iov->iov_base; /* make a copy of pointer to data */ + + /* put small buffer contents in skb->data */ + memcpy(skb->data,p,skb->len); + free_rx_buf(node,0,(u32)p); + skb->atm.iovcnt = 0; + skb->tail = skb->data + skb->len; + skb_new = skb_clone(skb,GFP_ATOMIC); + skb_new->destructor = nicstar_rx_skb_destructor; +#ifdef NICSTAR_RC_FLAG + skb_new->atm.recycle_buffer = (void *) vcc; +#endif + return (u32) skb_new; + } } diff -ur --new-file old/linux/drivers/atm/nicstar.h new/linux/drivers/atm/nicstar.h --- old/linux/drivers/atm/nicstar.h Wed Jan 29 22:33:05 1997 +++ new/linux/drivers/atm/nicstar.h Wed Jan 29 22:33:37 1997 @@ -54,8 +54,9 @@ #define NICSTAR_CBR 1 /* Constant bit rate support */ #undef NICSTAR_RCQ /* Raw cell queue support; just prints out raw cells */ #define NICSTAR_PARANOID 1 /* adds some extra checks */ -#undef TEST_LOOPBACK /* enables PHY-level loopback */ -#undef ATM_013 +#undef TEST_LOOPBACK /* enables PHY-level loopback */ +#undef ATM_013 /* should be removed soon; compat w/ ATM rel 0.13 */ +#undef NICSTAR_LBUFCNT /* for debugging; keeps count of length of LGBUF_Q */ /* Kernel definitions ******************************************************/ @@ -65,8 +66,13 @@ #define NICSTAR_IO_SIZE (4*1024) #define SM_BUFSZ 52 +#define SM_BUF_DATALEN (SM_BUFSZ - 4) #define NUM_SM_BUFS 170 -#define LG_BUFSZ 2048 +#define LG_BUFSZ 16384 +#define LG_BUFMSK 0x06000000 /* 16k = 0x06000000 + 8k = 0x04000000 + 4k = 0x02000000 + 2k = 0x00000000 */ #define RAWCELLSZ 64 #define NUM_LG_BUFS 32 #define MAX_SDU_BUFS 32 /* Max number of buffers in an AAL5 SDU */ @@ -264,6 +270,8 @@ } nicstar_rcq; #endif +typedef struct sk_buff *skb_ptr; + typedef struct nicstar_dev { int index; /* Device index */ @@ -294,9 +302,15 @@ nicstar_scq *scq; caddr_t scq_orig; + skb_ptr rx_lg_skb[NUM_LG_BUFS]; + struct atm_dev *dev; nicstar_vcimap vci_map[NUM_VPI * NUM_VCI]; unsigned char tmp_cell[48]; + +#ifdef NICSTAR_LBUFCNT + int lbuf_cnt; +#endif } nicstar_dev, *nicstar_devp; diff -ur --new-file old/linux/include/linux/skbuff.h new/linux/include/linux/skbuff.h --- old/linux/include/linux/skbuff.h Wed Jan 29 22:33:05 1997 +++ new/linux/include/linux/skbuff.h Wed Jan 29 22:33:37 1997 @@ -119,6 +119,10 @@ struct atm_vcc *vcc; /* ATM VCC */ int iovcnt; /* 0 for "normal" operation */ struct timeval timestamp; /* timestamp or 0,x */ +#ifdef CONFIG_ATM_NICSTAR + void *recycle_buffer; /* set when buffer should be */ + /* recycled; points to vcc */ +#endif int encap; /* non-zero if encapsulated */ /* for ATMARP */ #ifdef CONFIG_AREQUIPA diff -ur --new-file old/linux/net/atm/arequipa.c new/linux/net/atm/arequipa.c --- old/linux/net/atm/arequipa.c Wed Jan 29 22:33:05 1997 +++ new/linux/net/atm/arequipa.c Wed Jan 29 22:33:37 1997 @@ -1,6 +1,6 @@ /* net/atm/arequipa.c - Application requested IP over ATM */ -/* Written 1996 by Jean-Michel Pittet and Werner Almesberger, EPFL LRC */ +/* Written 1996,1997 by Jean-Michel Pittet and Werner Almesberger, EPFL LRC */ #include @@ -132,7 +132,7 @@ void arequipa_close_vcc(struct atm_vcc *vcc) { if (!(vcc->flags & ATM_VF_AQREL)) { - printk(KERN_CRIT "arequipa_close_3rd_party: VCC %p doesn't " + printk(KERN_CRIT "arequipa_close_vcc: VCC %p doesn't " "have ATM_VF_AQREL set\n",vcc); return; } @@ -433,6 +433,10 @@ vcc->peek = NULL; /* crash */ vcc->pop = NULL; /* crash */ vcc->push_oam = NULL; /* crash */ + /* + * Now that we have an arequipad, we should check for stale Arequipa + * connections and prune them. @@@ + */ return 0; } diff -ur --new-file old/linux/net/atm/atmarp.c new/linux/net/atm/atmarp.c --- old/linux/net/atm/atmarp.c Wed Jan 29 22:33:05 1997 +++ new/linux/net/atm/atmarp.c Wed Jan 29 22:33:37 1997 @@ -141,7 +141,7 @@ } -static inline void time_out_entry(struct atmarp_entry **entry) +static inline int time_out_entry(struct atmarp_entry **entry) { struct atmarp_entry *next; @@ -149,18 +149,19 @@ if ((*entry)->vcc) { (*entry)->vcc->flags |= ATM_VF_RELEASED; (*entry)->vcc->flags &= ~ATM_VF_READY; + wake_up(&(*entry)->vcc->sleep); + return 0; } - else { - if ((*entry)->queued) { - dev_kfree_skb((*entry)->queued,FREE_WRITE); - DPRINTK("discarding queued skb\n"); - } - else printk(KERN_CRIT "atmarp: weird - incomplete entry, but " - "nothing queued\n"); - next = (*entry)->next; - kfree(*entry); - *entry = next; - } + if ((*entry)->queued) { + dev_kfree_skb((*entry)->queued,FREE_WRITE); + DPRINTK("discarding queued skb\n"); + } + else printk(KERN_CRIT "atmarp: weird - incomplete entry, but " + "nothing queued\n"); + next = (*entry)->next; + kfree(*entry); + *entry = next; + return 1; } @@ -178,8 +179,7 @@ expire = (*entry)->last_use+(*entry)-> idle_timeout; if (expire < jiffies) { - time_out_entry(entry); - continue; + if (time_out_entry(entry)) continue; } else if (expire < idle_timer.expires) idle_timer.expires = expire; @@ -475,6 +475,7 @@ dev->tbusy = 0; /* @@@ check */ dev->hard_header = clip_hard_header; dev->do_ioctl = NULL; + dev->change_mtu = NULL; dev->ip_arp = atmarp_ioctl; dev->rebuild_header = clip_rebuild_header; dev->get_stats = atm_clip_get_stats; diff -ur --new-file old/linux/net/atm/common.c new/linux/net/atm/common.c --- old/linux/net/atm/common.c Wed Jan 29 22:33:05 1997 +++ new/linux/net/atm/common.c Wed Jan 29 22:33:37 1997 @@ -423,7 +423,8 @@ } #endif memcpy_tofs(buff,skb->data,eff_len); - kfree_skb(skb,FREE_READ); + if (!vcc->dev->ops->free_rx_skb) kfree_skb(skb,FREE_READ); + else vcc->dev->ops->free_rx_skb(vcc, skb); } return eff_len; } diff -ur --new-file old/linux/net/atm/ipcommon.c new/linux/net/atm/ipcommon.c --- old/linux/net/atm/ipcommon.c Wed Jan 29 22:33:05 1997 +++ new/linux/net/atm/ipcommon.c Wed Jan 29 22:33:37 1997 @@ -169,6 +169,7 @@ dev->tbusy = 0; /* @@@ check */ dev->hard_header = clip_hard_header; dev->do_ioctl = clip_ioctl; + dev->change_mtu = NULL; dev->rebuild_header = clip_rebuild_header; dev->get_stats = atm_clip_get_stats; dev->hard_header_len = RFC1483LLC_LEN; diff -ur --new-file old/linux/net/core/skbuff.c new/linux/net/core/skbuff.c --- old/linux/net/core/skbuff.c Wed Jan 29 22:33:06 1997 +++ new/linux/net/core/skbuff.c Wed Jan 29 22:33:38 1997 @@ -704,6 +704,9 @@ skb->destructor=NULL; #ifdef CONFIG_ATM skb->atm.iovcnt = 0; +#ifdef CONFIG_ATM_NICSTAR + skb->atm.recycle_buffer = NULL; +#endif #endif return skb; } @@ -765,6 +768,12 @@ n->tries = 0; n->lock = 0; n->users = 0; +#ifdef CONFIG_ATM_NICSTAR + if (n->atm.recycle_buffer) { + n->atm.recycle_buffer = NULL; + n->destructor = NULL; + } +#endif return n; } @@ -823,6 +832,12 @@ n->users=0; n->pkt_type=skb->pkt_type; n->stamp=skb->stamp; +#ifdef CONFIG_ATM_NICSTAR + if (n->atm.recycle_buffer) { + n->atm.recycle_buffer = NULL; + n->destructor = NULL; + } +#endif IS_SKB(n); return n; .