[673] in linux-net channel archive
Re: Checksum problem fixed
daemon@ATHENA.MIT.EDU (Paul Gortmaker)
Fri Jul 14 02:29:12 1995
From: Paul Gortmaker <gpg109@rsphy1.anu.edu.au>
To: iialan@iifeak.swan.ac.uk (Alan Cox)
Date: Fri, 14 Jul 1995 06:49:09 +1000 (EST)
Cc: linux-net@vger.rutgers.edu
In-Reply-To: <m0sWPac-00013zC@iiit.swan.ac.uk> from "Alan Cox" at Jul 13, 95 03:50:09 pm
> > Now that eth_copy_and_sum() works, I will work on converting shared
> > memory 8390 cards to use it. The only snag will be if the packet
> > is wrapped around the Rx ring boundary (and thus in 2 chunks) then
> > we won't be able to use eth_copy_and_sum(). In that case, the csum
> > will be done later by the upper layers as it is now.
>
> Benchmark it if you do. Its a win on a 386 lance as the bus mastering
> DMA means the packet isn't cached.
Got an ultra card? :-) I just took a quick swipe at it and have all
the changes into the 8390 core and the ultra driver, and it even works.
I don't have any useful net benchmarks other than ftp installed here.
Of course I still have to do the other 7 or so 8390 card-specific
drivers now. :-( The wd and 3c503 will be next. Stay tuned.
Paul.
diff -ur /var/tmp/linux/drivers/net/8390.c linux/drivers/net/8390.c
--- /var/tmp/linux/drivers/net/8390.c Wed Jul 5 20:06:26 1995
+++ linux/drivers/net/8390.c Fri Jul 14 05:45:36 1995
@@ -19,6 +19,7 @@
Changelog:
Paul Gortmaker : remove set_bit lock, other cleanups.
+ Paul Gortmaker : support for eth_copy_and_sum() for shmem cards.
*/
@@ -70,15 +71,18 @@
int start_page)
Write the COUNT bytes of BUF to the packet buffer at START_PAGE. The
"page" value uses the 8390's 256-byte pages.
- int block_input(struct device *dev, int count, char *buf, int ring_offset)
- Read COUNT bytes from the packet buffer into BUF. Start reading from
- RING_OFFSET, the address as the 8390 sees it. The first read will
- always be the 4 byte, page aligned 8390 header. *If* there is a
+ void get_8390_hdr(struct device *dev, struct e8390_hdr *hdr, int ring_offset)
+ Read the 4 byte, page aligned 8390 header. *If* there is a
subsequent read, it will be of the rest of the packet.
+ int block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
+ Read COUNT bytes from the packet buffer into the skb data area. Start
+ reading from RING_OFFSET, the address as the 8390 sees it. This will always
+ follow the read of the 8390 header.
*/
#define ei_reset_8390 (ei_local->reset_8390)
#define ei_block_output (ei_local->block_output)
#define ei_block_input (ei_local->block_input)
+#define ei_get_8390_hdr (ei_local->get_8390_hdr)
/* use 0 for production, 1 for verification, >2 for debug */
#ifdef EI_DEBUG
@@ -426,8 +430,7 @@
break; /* Done for now */
current_offset = this_frame << 8;
- ei_block_input(dev, sizeof(rx_frame), (char *)&rx_frame,
- current_offset);
+ ei_get_8390_hdr(dev, &rx_frame, current_offset);
pkt_len = rx_frame.count - sizeof(rx_frame);
@@ -465,9 +468,8 @@
} else {
skb_reserve(skb,2); /* IP headers on 16 byte boundaries */
skb->dev = dev;
-
- ei_block_input(dev, pkt_len, skb_put(skb,pkt_len),
- current_offset + sizeof(rx_frame));
+ skb_put(skb,pkt_len); /* Make room */
+ ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame));
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
ei_local->stat.rx_packets++;
diff -ur /var/tmp/linux/drivers/net/8390.h linux/drivers/net/8390.h
--- /var/tmp/linux/drivers/net/8390.h Mon Jun 19 01:11:37 1995
+++ linux/drivers/net/8390.h Fri Jul 14 05:57:01 1995
@@ -9,6 +9,7 @@
#include <linux/if_ether.h>
#include <linux/ioport.h>
+#include <linux/skbuff.h>
#define TX_2X_PAGES 12
#define TX_1X_PAGES 6
@@ -16,6 +17,13 @@
#define ETHER_ADDR_LEN 6
+/* The 8390 specific per-packet-header format. */
+struct e8390_pkt_hdr {
+ unsigned char status; /* status */
+ unsigned char next; /* pointer to next packet. */
+ unsigned short count; /* header + packet length in bytes */
+};
+
/* From 8390.c */
extern int ei_debug;
extern struct sigaction ei_sigaction;
@@ -39,8 +47,9 @@
struct ei_device {
char *name;
void (*reset_8390)(struct device *);
+ void (*get_8390_hdr)(struct device *, struct e8390_pkt_hdr *, int);
void (*block_output)(struct device *, int, const unsigned char *, int);
- int (*block_input)(struct device *, int, char *, int);
+ int (*block_input)(struct device *, int, struct sk_buff *, int);
unsigned open:1;
unsigned word16:1; /* We have the 16-bit (vs 8-bit) version of the card. */
unsigned txing:1; /* Transmit Active */
@@ -155,10 +164,4 @@
#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */
#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */
-/* The per-packet-header format. */
-struct e8390_pkt_hdr {
- unsigned char status; /* status */
- unsigned char next; /* pointer to next packet. */
- unsigned short count; /* header + packet length in bytes */
-};
#endif /* _8390_h */
diff -ur /var/tmp/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c
--- /var/tmp/linux/drivers/net/smc-ultra.c Fri Jan 20 20:34:39 1995
+++ linux/drivers/net/smc-ultra.c Fri Jul 14 06:02:31 1995
@@ -48,6 +48,7 @@
#include <asm/system.h>
#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
#include "8390.h"
extern struct device *init_etherdev(struct device *dev, int sizeof_private,
unsigned long *mem_startp);
@@ -61,8 +62,10 @@
static int ultra_open(struct device *dev);
static void ultra_reset_8390(struct device *dev);
+static void ultra_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
+ int ring_offset);
static int ultra_block_input(struct device *dev, int count,
- char *buf, int ring_offset);
+ struct sk_buff *skb, int ring_offset);
static void ultra_block_output(struct device *dev, int count,
const unsigned char *buf, const start_page);
static int ultra_close_card(struct device *dev);
@@ -204,6 +207,7 @@
ei_status.reset_8390 = &ultra_reset_8390;
ei_status.block_input = &ultra_block_input;
ei_status.block_output = &ultra_block_output;
+ ei_status.get_8390_hdr = &ultra_get_8390_hdr;
dev->open = &ultra_open;
dev->stop = &ultra_close_card;
NS8390_init(dev, 0);
@@ -240,11 +244,26 @@
return;
}
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+ we don't need to be concerned with ring wrap as the header will be at
+ the start of a page, so we optimize accordingly */
+
+static void
+ultra_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_offset)
+{
+
+ void *hdr_start = (void *)(dev->mem_start + ring_offset - (START_PG<<8));
+
+ outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET); /* shmem on */
+ memcpy(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
+ outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* shmem off */
+}
+
/* Block input and output are easy on shared memory ethercards, the only
complication is when the ring buffer wraps. */
static int
-ultra_block_input(struct device *dev, int count, char *buf, int ring_offset)
+ultra_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
{
void *xfer_start = (void *)(dev->mem_start + ring_offset
- (START_PG<<8));
@@ -255,13 +274,14 @@
if (xfer_start + count > (void*) dev->rmem_end) {
/* We must wrap the input move. */
int semi_count = (void*)dev->rmem_end - xfer_start;
+ void *buf = (void*)skb->data;
memcpy(buf, xfer_start, semi_count);
count -= semi_count;
memcpy(buf + semi_count, (char *)dev->rmem_start, count);
outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */
return dev->rmem_start + count;
}
- memcpy(buf, xfer_start, count);
+ eth_copy_and_sum(skb, xfer_start, count, 0); /* Copy and csum it */
outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */
return ring_offset + count;