summaryrefslogtreecommitdiffstats
path: root/drivers/net/defxx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/defxx.c')
-rw-r--r--drivers/net/defxx.c86
1 files changed, 77 insertions, 9 deletions
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 5e50cbfa5..659e71f32 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -226,6 +226,11 @@ static const char *version = "defxx.c:v1.04 09/16/96 Lawrence V. Stefani (stefa
#include "defxx.h"
+#define DYNAMIC_BUFFERS 1
+
+#define SKBUFF_RX_COPYBREAK 200
+#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX)
+
/* Define global routines */
int dfx_probe(struct device *dev);
@@ -1083,7 +1088,9 @@ __initfunc(int dfx_driver_init(
alloc_size = sizeof(PI_DESCR_BLOCK) +
PI_CMD_REQ_K_SIZE_MAX +
PI_CMD_RSP_K_SIZE_MAX +
+#ifndef DYNAMIC_BUFFERS
(bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) +
+#endif
sizeof(PI_CONSUMER_BLOCK) +
(PI_ALIGN_K_DESC_BLK - 1);
top_v = (char *) kmalloc(alloc_size, GFP_KERNEL);
@@ -1135,8 +1142,11 @@ __initfunc(int dfx_driver_init(
bp->rcv_block_virt = curr_v;
bp->rcv_block_phys = curr_p;
+
+#ifndef DYNAMIC_BUFFERS
curr_v += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX);
curr_p += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX);
+#endif
/* Reserve space for the consumer block */
@@ -2926,6 +2936,22 @@ void dfx_rcv_init(
* driver initialization when we allocated memory for the receive buffers.
*/
+#ifdef DYNAMIC_BUFFERS
+ for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++)
+ for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post)
+ {
+ struct sk_buff *newskb;
+ bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP |
+ ((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN));
+ newskb = dev_alloc_skb(NEW_SKB_SIZE);
+ bp->descr_block_virt->rcv_data[i+j].long_1 = virt_to_bus(newskb->data);
+ /*
+ * p_rcv_buff_va is only used inside the
+ * kernel so we put the skb pointer here.
+ */
+ bp->p_rcv_buff_va[i+j] = (char *) newskb;
+ }
+#else
for (i=0; i < (int)(bp->rcv_bufs_to_post); i++)
for (j=0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post)
{
@@ -2934,6 +2960,7 @@ void dfx_rcv_init(
bp->descr_block_virt->rcv_data[i+j].long_1 = (u32) (bp->rcv_block_phys + (i * PI_RCV_DATA_K_SIZE_MAX));
bp->p_rcv_buff_va[i+j] = (char *) (bp->rcv_block_virt + (i * PI_RCV_DATA_K_SIZE_MAX));
}
+#endif
/* Update receive producer and Type 2 register */
@@ -2985,6 +3012,8 @@ void dfx_rcv_queue_process(
u32 descr, pkt_len; /* FMC descriptor field and packet length */
struct sk_buff *skb; /* pointer to a sk_buff to hold incoming packet data */
+ static int testing_dyn;
+
/* Service all consumed LLC receive frames */
p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data);
@@ -2992,7 +3021,14 @@ void dfx_rcv_queue_process(
{
/* Process any errors */
- p_buff = (char *) bp->p_rcv_buff_va[bp->rcv_xmt_reg.index.rcv_comp];
+ int entry;
+
+ entry = bp->rcv_xmt_reg.index.rcv_comp;
+#ifdef DYNAMIC_BUFFERS
+ p_buff = (char *) (((struct sk_buff *)bp->p_rcv_buff_va[entry])->data);
+#else
+ p_buff = (char *) bp->p_rcv_buff_va[entry];
+#endif
memcpy(&descr, p_buff + RCV_BUFF_K_DESCR, sizeof(u32));
if (descr & PI_FMC_DESCR_M_RCC_FLUSH)
@@ -3003,29 +3039,60 @@ void dfx_rcv_queue_process(
bp->rcv_frame_status_errors++;
}
else
- {
+ {
+ int rx_in_place = 0;
+
/* The frame was received without errors - verify packet length */
pkt_len = (u32)((descr & PI_FMC_DESCR_M_LEN) >> PI_FMC_DESCR_V_LEN);
pkt_len -= 4; /* subtract 4 byte CRC */
if (!IN_RANGE(pkt_len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN))
bp->rcv_length_errors++;
- else
- {
- skb = dev_alloc_skb(pkt_len+3); /* alloc new buffer to pass up, add room for PRH */
+ else{
+#ifdef DYNAMIC_BUFFERS
+ if (pkt_len > SKBUFF_RX_COPYBREAK) {
+ struct sk_buff *newskb;
+
+ newskb = dev_alloc_skb(NEW_SKB_SIZE);
+ if (newskb){
+ rx_in_place = 1;
+#define JES_TESTING
+#ifdef JES_TESTING
+ if(testing_dyn++ < 5)
+ printk("Skipping a memcpy\n");
+ skb = (struct sk_buff *)bp->p_rcv_buff_va[entry];
+ skb->data += RCV_BUFF_K_PADDING;
+ bp->p_rcv_buff_va[entry] = (char *)newskb;
+ bp->descr_block_virt->rcv_data[entry].long_1 = virt_to_bus(newskb->data);
+#else
+ memcpy(newskb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3);
+ skb = newskb;
+#endif
+ } else
+ skb = 0;
+ } else
+#endif
+ skb = dev_alloc_skb(pkt_len+3); /* alloc new buffer to pass up, add room for PRH */
if (skb == NULL)
{
printk("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name);
bp->rcv_discards++;
+ break;
}
- else
+ else {
+#ifndef DYNAMIC_BUFFERS
+ if (! rx_in_place)
+#endif
{
- /* Receive buffer allocated, pass receive packet up */
+ /* Receive buffer allocated, pass receive packet up */
+
+ memcpy(skb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3);
+ }
- memcpy(skb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3);
skb->data += 3; /* adjust data field so that it points to FC byte */
skb->len = pkt_len; /* pass up packet length, NOT including CRC */
skb->dev = bp->dev; /* pass up device pointer */
+
skb->protocol = fddi_type_trans(skb, bp->dev);
netif_rx(skb);
@@ -3034,9 +3101,9 @@ void dfx_rcv_queue_process(
bp->rcv_total_frames++;
if (*(p_buff + RCV_BUFF_K_DA) & 0x01)
bp->rcv_multicast_frames++;
- }
}
}
+ }
/*
* Advance the producer (for recycling) and advance the completion
@@ -3140,6 +3207,7 @@ int dfx_xmt_queue_pkt(
dev->name, skb->len);
bp->xmt_length_errors++; /* bump error counter */
dev_tint(dev); /* dequeue packets from xmt queue and send them */
+ dev_kfree_skb(skb, FREE_WRITE);
return(0); /* return "success" */
}
/*