aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--xen/drivers/net/tg3.c3
-rw-r--r--xen/include/hypervisor-ifs/network.h25
-rw-r--r--xen/include/xeno/vif.h6
-rw-r--r--xen/net/dev.c33
-rw-r--r--xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/network/network.c36
5 files changed, 57 insertions, 46 deletions
diff --git a/xen/drivers/net/tg3.c b/xen/drivers/net/tg3.c
index cb1d1e512b..c11c743109 100644
--- a/xen/drivers/net/tg3.c
+++ b/xen/drivers/net/tg3.c
@@ -6338,12 +6338,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->dev->hard_start_xmit = tg3_start_xmit;
tp->rx_offset = 2;
-/* XXX Xen: we trust our ASICs, for better or worse ;-) */
-#if 0
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
(tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0)
tp->rx_offset = 0;
-#endif
/* By default, disable wake-on-lan. User can change this
* using ETHTOOL_SWOL.
diff --git a/xen/include/hypervisor-ifs/network.h b/xen/include/hypervisor-ifs/network.h
index 1e4e7e1c53..56a8f92881 100644
--- a/xen/include/hypervisor-ifs/network.h
+++ b/xen/include/hypervisor-ifs/network.h
@@ -15,15 +15,17 @@
#include <linux/types.h>
typedef struct tx_entry_st {
- unsigned long addr; /* machine address of packet */
- unsigned short size; /* in bytes */
- unsigned short status; /* per descriptor status. */
+ unsigned long addr; /* machine address of packet (IN VAR) */
+ unsigned short size; /* in bytes (IN VAR) */
+ unsigned char status; /* per descriptor status (OUT VAR) */
+ unsigned char _unused;
} tx_entry_t;
typedef struct rx_entry_st {
- unsigned long addr; /* machine address of PTE to swizzle */
- unsigned short size; /* in bytes */
- unsigned short status; /* per descriptor status. */
+ unsigned long addr; /* machine address of PTE to swizzle (IN VAR) */
+ unsigned short size; /* in bytes (OUT VAR) */
+ unsigned char status; /* per descriptor status (OUT VAR) */
+ unsigned char offset; /* offset in page of received pkt (OUT VAR) */
} rx_entry_t;
#define TX_RING_SIZE 256
@@ -120,12 +122,9 @@ typedef struct net_rule_ent_st
/* Drop a new rule down to the network tables. */
int add_net_rule(net_rule_t *rule);
-
-/* Descriptor status values:
- */
-
-#define RING_STATUS_OK 0 // Everything is gravy.
-#define RING_STATUS_ERR_CFU -1 // Copy from user problems.
-#define RING_STATUS_BAD_PAGE -2 // What they gave us was pure evil.
+/* Descriptor status values */
+#define RING_STATUS_OK 0 /* Everything is gravy. */
+#define RING_STATUS_ERR_CFU 1 /* Copy from user problems. */
+#define RING_STATUS_BAD_PAGE 2 /* What they gave us was pure evil */
#endif
diff --git a/xen/include/xeno/vif.h b/xen/include/xeno/vif.h
index 7b56caaabe..c9d73a5ff1 100644
--- a/xen/include/xeno/vif.h
+++ b/xen/include/xeno/vif.h
@@ -28,7 +28,8 @@
typedef struct rx_shadow_entry_st {
unsigned long addr;
unsigned short size;
- unsigned short status;
+ unsigned char status;
+ unsigned char offset;
unsigned long flush_count;
} rx_shadow_entry_t;
@@ -36,7 +37,8 @@ typedef struct tx_shadow_entry_st {
void *header;
unsigned long payload;
unsigned short size;
- unsigned short status;
+ unsigned char status;
+ unsigned char _unused;
} tx_shadow_entry_t;
typedef struct net_shadow_ring_st {
diff --git a/xen/net/dev.c b/xen/net/dev.c
index 51d9ef66e0..c992cfab04 100644
--- a/xen/net/dev.c
+++ b/xen/net/dev.c
@@ -506,9 +506,10 @@ void deliver_packet(struct sk_buff *skb, net_vif_t *vif)
}
rx = shadow_ring->rx_ring + i;
- if ( (skb->len + ETH_HLEN) < rx->size )
- rx->size = skb->len + ETH_HLEN;
-
+ ASSERT(skb->len <= PAGE_SIZE);
+ rx->size = skb->len;
+ rx->offset = (unsigned char)((unsigned long)skb->data & ~PAGE_MASK);
+
spin_lock_irqsave(&vif->domain->page_lock, flags);
g_pte = map_domain_mem(rx->addr);
@@ -559,7 +560,7 @@ void deliver_packet(struct sk_buff *skb, net_vif_t *vif)
int netif_rx(struct sk_buff *skb)
{
unsigned long cpu_mask;
- int this_cpu = smp_processor_id();
+ int offset, this_cpu = smp_processor_id();
unsigned long flags;
net_vif_t *vif;
@@ -567,23 +568,25 @@ int netif_rx(struct sk_buff *skb)
ASSERT(skb->skb_type == SKB_ZERO_COPY);
ASSERT((skb->data - skb->head) == (18 + ETH_HLEN));
-
+
+ /*
+ * Offset will include 16 bytes padding from dev_alloc_skb, 14 bytes for
+ * ethernet header, plus any other alignment padding added by the driver.
+ */
+ offset = (int)skb->data & ~PAGE_MASK;
skb->head = (u8 *)map_domain_mem(((skb->pf - frame_table) << PAGE_SHIFT));
- skb->data = skb->head;
- skb_reserve(skb,18); /* 18 is the 16 from dev_alloc_skb plus 2 for
- IP header alignment. */
+ skb->data = skb->nh.raw = skb->head + offset;
+ skb->tail = skb->data + skb->len;
+ skb_push(skb, ETH_HLEN);
skb->mac.raw = skb->data;
- skb->data += ETH_HLEN;
- skb->nh.raw = skb->data;
-
+
netdev_rx_stat[this_cpu].total++;
if ( skb->src_vif == VIF_UNKNOWN_INTERFACE )
skb->src_vif = VIF_PHYSICAL_INTERFACE;
if ( skb->dst_vif == VIF_UNKNOWN_INTERFACE )
- skb->dst_vif = __net_get_target_vif(skb->mac.raw,
- skb->len, skb->src_vif);
+ skb->dst_vif = __net_get_target_vif(skb->data, skb->len, skb->src_vif);
if ( ((vif = sys_vif_list[skb->dst_vif]) == NULL) ||
(skb->dst_vif <= VIF_PHYSICAL_INTERFACE) )
@@ -1959,8 +1962,8 @@ long do_net_update(void)
* This copy assumes that rx_shadow_entry_t is an extension of
* rx_net_entry_t extra fields must be tacked on to the end.
*/
- if ( copy_from_user( shadow_ring->rx_ring+i, net_ring->rx_ring+i,
- sizeof (rx_entry_t) ) )
+ if ( copy_from_user(shadow_ring->rx_ring+i, net_ring->rx_ring+i,
+ sizeof (rx_entry_t) ) )
{
DPRINTK("Bad copy_from_user for rx ring\n");
shadow_ring->rx_ring[i].status = RING_STATUS_ERR_CFU;
diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/network/network.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/network/network.c
index 86bbeb921a..01e81e0cf0 100644
--- a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/network/network.c
+++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/network/network.c
@@ -230,7 +230,6 @@ static void network_alloc_rx_buffers(struct net_device *dev)
skb = dev_alloc_skb(RX_BUF_SIZE);
if ( skb == NULL ) break;
skb->dev = dev;
- skb_reserve(skb, 2); /* word align the IP header */
np->rx_skb_ring[i] = skb;
np->net_ring->rx_ring[i].addr = get_ppte((unsigned long)skb->head);
np->net_ring->rx_ring[i].size = RX_BUF_SIZE - 16; /* arbitrary */
@@ -317,25 +316,20 @@ static void network_rx_int(int irq, void *dev_id, struct pt_regs *ptregs)
struct net_device *dev = (struct net_device *)dev_id;
struct net_private *np = dev->priv;
struct sk_buff *skb;
+ rx_entry_t *rx;
again:
for ( i = np->rx_idx; i != np->net_ring->rx_cons; i = RX_RING_INC(i) )
{
- if (np->net_ring->rx_ring[i].status != RING_STATUS_OK)
+ rx = &np->net_ring->rx_ring[i];
+ skb = np->rx_skb_ring[i];
+
+ if ( rx->status != RING_STATUS_OK )
{
- printk(KERN_ALERT "bad buffer on RX ring!(%d)\n",
- np->net_ring->rx_ring[i].status);
+ printk(KERN_ALERT "bad buffer on RX ring!(%d)\n", rx->status);
+ dev_kfree_skb_any(skb);
continue;
}
- skb = np->rx_skb_ring[i];
-
- phys_to_machine_mapping[virt_to_phys(skb->head) >> PAGE_SHIFT] =
- (*(unsigned long *)phys_to_virt(
- machine_to_phys(np->net_ring->rx_ring[i].addr))
- ) >> PAGE_SHIFT;
-
- skb_put(skb, np->net_ring->rx_ring[i].size);
- skb->protocol = eth_type_trans(skb, dev);
/*
* Set up shinfo -- from alloc_skb This was particularily nasty: the
@@ -346,6 +340,22 @@ static void network_rx_int(int irq, void *dev_id, struct pt_regs *ptregs)
skb_shinfo(skb)->nr_frags = 0;
skb_shinfo(skb)->frag_list = NULL;
+ phys_to_machine_mapping[virt_to_phys(skb->head) >> PAGE_SHIFT] =
+ (*(unsigned long *)phys_to_virt(machine_to_phys(rx->addr))
+ ) >> PAGE_SHIFT;
+
+ if ( rx->offset < 16 )
+ {
+ printk(KERN_ALERT "need pkt offset >= 16 (got %d)\n", rx->offset);
+ dev_kfree_skb_any(skb);
+ continue;
+ }
+
+ skb_reserve(skb, rx->offset - 16);
+
+ skb_put(skb, np->net_ring->rx_ring[i].size);
+ skb->protocol = eth_type_trans(skb, dev);
+
np->stats.rx_packets++;
np->stats.rx_bytes += np->net_ring->rx_ring[i].size;