Commit 5b4f4d19 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://gkernel.bkbits.net/net-drivers-2.5

into ppc970.osdl.org:/home/torvalds/v2.5/linux
parents 6a3e473e eecc0af5
......@@ -31,6 +31,7 @@ Verifying Bond Configuration
Frequently Asked Questions
High Availability
Promiscuous Sniffing notes
8021q VLAN support
Limitations
Resources and Links
......@@ -140,10 +141,6 @@ probeall bond0 eth0 eth1 bonding
Be careful not to reference bond0 itself at the end of the line, or modprobe
will die in an endless recursive loop.
To have device characteristics (such as MTU size) propagate to slave devices,
set the bond characteristics before enslaving the device. The characteristics
are propagated during the enslave process.
If running SNMP agents, the bonding driver should be loaded before any network
drivers participating in a bond. This requirement is due to the the interface
index (ipAdEntIfIndex) being associated to the first interface found with a
......@@ -601,7 +598,7 @@ Frequently Asked Questions
For ethernet cards not supporting MII status, the arp_interval and
arp_ip_target parameters must be specified for bonding to work
correctly. If packets have not been sent or received during the
specified arp_interval durration, an ARP request is sent to the
specified arp_interval duration, an ARP request is sent to the
targets to generate send and receive traffic. If after this
interval, either the successful send and/or receive count has not
incremented, the next slave in the sequence will become the active
......@@ -669,16 +666,8 @@ Frequently Asked Questions
that will be added.
To restore your slaves' MAC addresses, you need to detach them
from the bond (`ifenslave -d bond0 eth0'), set them down
(`ifconfig eth0 down'), unload the drivers (`rmmod 3c59x', for
example) and reload them to get the MAC addresses from their
eeproms. If the driver is shared by several devices, you need
to turn them all down. Another solution is to look for the MAC
address at boot time (dmesg or tail /var/log/messages) and to
reset it by hand with ifconfig :
# ifconfig eth0 down
# ifconfig eth0 hw ether 00:20:40:60:80:A0
from the bond (`ifenslave -d bond0 eth0'). The bonding driver will then
restore the MAC addresses that the slaves had before they were enslaved.
9. Which transmit polices can be used?
......@@ -843,7 +832,7 @@ point of failure" solution.
In this configuration, there is an ISL - Inter Switch Link (could be a trunk),
several servers (host1, host2 ...) attached to both switches each, and one or
more ports to the outside world (port3...). One an only one slave on each host
more ports to the outside world (port3...). One and only one slave on each host
is active at a time, while all links are still monitored (the system can
detect a failure of active and backup links).
......@@ -933,6 +922,41 @@ capacity aggregating; but it works fine for unnumbered interfaces;
just ignore all the warnings it emits.
8021q VLAN support
==================
It is possible to configure VLAN devices over a bond interface using the 8021q
driver. However, only packets coming from the 8021q driver and passing through
bonding will be tagged by default. Self generated packets, like bonding's
learning packets or ARP packets generated by either ALB mode or the ARP
monitor mechanism, are tagged internally by bonding itself. As a result,
bonding has to "learn" what VLAN IDs are configured on top of it, and it uses
those IDs to tag self generated packets.
For simplicity reasons, and to support the use of adapters that can do VLAN
hardware acceleration offloding, the bonding interface declares itself as
fully hardware offloaing capable, it gets the add_vid/kill_vid notifications
to gather the necessary information, and it propagates those actions to the
slaves.
In case of mixed adapter types, hardware accelerated tagged packets that should
go through an adapter that is not offloading capable are "un-accelerated" by the
bonding driver so the VLAN tag sits in the regular location.
VLAN interfaces *must* be added on top of a bonding interface only after
enslaving at least one slave. This is because until the first slave is added the
bonding interface has a HW address of 00:00:00:00:00:00, which will be copied by
the VLAN interface when it is created.
Notice that a problem would occur if all slaves are released from a bond that
still has VLAN interfaces on top of it. When later coming to add new slaves, the
bonding interface would get a HW address from the first slave, which might not
match that of the VLAN interfaces. It is recommended that either all VLANs are
removed and then re-added, or to manually set the bonding interface's HW
address so it matches the VLAN's. (Note: changing a VLAN interface's HW address
would set the underlying device -- i.e. the bonding interface -- to promiscouos
mode, which might not be what you want).
Limitations
===========
The main limitations are :
......
(C)Copyright 1999-2003 Marvell(R).
(C)Copyright 1999-2004 Marvell(R).
All rights reserved
===========================================================================
sk98lin.txt created 15-Dec-2003
sk98lin.txt created 13-Feb-2004
Readme File for sk98lin v6.21
Readme File for sk98lin v6.23
Marvell Yukon/SysKonnect SK-98xx Gigabit Ethernet Adapter family driver for LINUX
This file contains
......
......@@ -1985,6 +1985,7 @@ config SK98LIN
- Allied Telesyn AT-2970TX/2TX Gigabit Ethernet Adapter
- Allied Telesyn AT-2971SX Gigabit Ethernet Adapter
- Allied Telesyn AT-2971T Gigabit Ethernet Adapter
- Belkin Gigabit Desktop Card 10/100/1000Base-T Adapter, Copper RJ-45
- DGE-530T Gigabit Ethernet Adapter
- EG1032 v2 Instant Gigabit Network Adapter
- EG1064 v2 Instant Gigabit Network Adapter
......@@ -1996,6 +1997,7 @@ config SK98LIN
- Marvell 88E8001 Gigabit LOM Ethernet Adapter (Foxconn)
- Marvell 88E8001 Gigabit LOM Ethernet Adapter (Gigabyte)
- Marvell 88E8001 Gigabit LOM Ethernet Adapter (Iwill)
- Marvell 88E8050 Gigabit LOM Ethernet Adapter (Intel)
- Marvell RDK-8001 Adapter
- Marvell RDK-8002 Adapter
- Marvell RDK-8003 Adapter
......@@ -2007,6 +2009,7 @@ config SK98LIN
- Marvell RDK-8010 Adapter
- Marvell RDK-8011 Adapter
- Marvell RDK-8012 Adapter
- Marvell RDK-8052 Adapter
- Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (32 bit)
- Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (64 bit)
- N-Way PCI-Bus Giga-Card 1000/100/10Mbps(L)
......
......@@ -2362,6 +2362,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
int agg_id;
int i;
struct ad_info ad_info;
int res = 1;
/* make sure that the slaves list will
* not change during tx
......@@ -2369,12 +2370,12 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
read_lock(&bond->lock);
if (!BOND_IS_OK(bond)) {
goto free_out;
goto out;
}
if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
printk(KERN_DEBUG "ERROR: bond_3ad_get_active_agg_info failed\n");
goto free_out;
goto out;
}
slaves_in_agg = ad_info.ports;
......@@ -2383,7 +2384,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
if (slaves_in_agg == 0) {
/*the aggregator is empty*/
printk(KERN_DEBUG "ERROR: active aggregator is empty\n");
goto free_out;
goto out;
}
slave_agg_no = (data->h_dest[5]^bond->dev->dev_addr[5]) % slaves_in_agg;
......@@ -2401,7 +2402,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
if (slave_agg_no >= 0) {
printk(KERN_ERR DRV_NAME ": Error: Couldn't find a slave to tx on for aggregator ID %d\n", agg_id);
goto free_out;
goto out;
}
start_at = slave;
......@@ -2414,24 +2415,19 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
slave_agg_id = agg->aggregator_identifier;
}
if (SLAVE_IS_OK(slave) &&
agg && (slave_agg_id == agg_id)) {
skb->dev = slave->dev;
skb->priority = 1;
dev_queue_xmit(skb);
goto out;
if (SLAVE_IS_OK(slave) && agg && (slave_agg_id == agg_id)) {
res = bond_dev_queue_xmit(bond, skb, slave->dev);
break;
}
}
out:
read_unlock(&bond->lock);
return 0;
free_out:
if (res) {
/* no suitable interface, frame not sent */
dev_kfree_skb(skb);
goto out;
}
read_unlock(&bond->lock);
return 0;
}
int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype)
......
......@@ -34,6 +34,9 @@
*
* 2003/12/30 - Amir Noam <amir.noam at intel dot com>
* - Fixed: Cannot remove and re-enslave the original active slave.
*
* 2004/01/14 - Shmulik Hen <shmulik.hen at intel dot com>
* - Add capability to tag self generated packets in ALB/TLB modes.
*/
//#define BONDING_DEBUG 1
......@@ -50,6 +53,7 @@
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_bonding.h>
#include <linux/if_vlan.h>
#include <net/ipx.h>
#include <net/arp.h>
#include <asm/byteorder.h>
......@@ -79,7 +83,7 @@
#define TLB_NULL_INDEX 0xffffffff
#define MAX_LP_RETRY 3
#define MAX_LP_BURST 3
/* rlb defs */
#define RLB_HASH_TABLE_SIZE 256
......@@ -498,13 +502,33 @@ static void rlb_update_client(struct rlb_client_info *client_info)
}
for (i = 0; i < RLB_ARP_BURST_SIZE; i++) {
arp_send(ARPOP_REPLY, ETH_P_ARP,
struct sk_buff *skb;
skb = arp_create(ARPOP_REPLY, ETH_P_ARP,
client_info->ip_dst,
client_info->slave->dev,
client_info->ip_src,
client_info->mac_dst,
client_info->slave->dev->dev_addr,
client_info->mac_dst);
if (!skb) {
printk(KERN_ERR DRV_NAME
": Error: failed to create an ARP packet\n");
continue;
}
skb->dev = client_info->slave->dev;
if (client_info->tag) {
skb = vlan_put_tag(skb, client_info->vlan_id);
if (!skb) {
printk(KERN_ERR DRV_NAME
": Error: failed to insert VLAN tag\n");
continue;
}
}
arp_xmit(skb);
}
}
......@@ -603,9 +627,10 @@ static void rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip)
}
/* Caller must hold both bond and ptr locks for read */
struct slave *rlb_choose_channel(struct bonding *bond, struct arp_pkt *arp)
struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bond)
{
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct arp_pkt *arp = (struct arp_pkt *)skb->nh.raw;
struct slave *assigned_slave;
struct rlb_client_info *client_info;
u32 hash_index = 0;
......@@ -661,6 +686,15 @@ struct slave *rlb_choose_channel(struct bonding *bond, struct arp_pkt *arp)
client_info->ntt = 0;
}
if (!list_empty(&bond->vlan_list)) {
unsigned short vlan_id;
int res = vlan_get_tag(skb, &vlan_id);
if (!res) {
client_info->tag = 1;
client_info->vlan_id = vlan_id;
}
}
if (!client_info->assigned) {
u32 prev_tbl_head = bond_info->rx_hashtbl_head;
bond_info->rx_hashtbl_head = hash_index;
......@@ -691,7 +725,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
/* the arp must be sent on the selected
* rx channel
*/
tx_slave = rlb_choose_channel(bond, arp);
tx_slave = rlb_choose_channel(skb, bond);
if (tx_slave) {
memcpy(arp->mac_src,tx_slave->dev->dev_addr, ETH_ALEN);
}
......@@ -702,7 +736,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
* When the arp reply is received the entry will be updated
* with the correct unicast address of the client.
*/
rlb_choose_channel(bond, arp);
rlb_choose_channel(skb, bond);
/* The ARP relpy packets must be delayed so that
* they can cancel out the influence of the ARP request.
......@@ -808,6 +842,40 @@ static void rlb_deinitialize(struct bonding *bond)
kfree(bond_info->rx_hashtbl);
bond_info->rx_hashtbl = NULL;
bond_info->rx_hashtbl_head = RLB_NULL_INDEX;
_unlock_rx_hashtbl(bond);
}
static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id)
{
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
u32 curr_index;
_lock_rx_hashtbl(bond);
curr_index = bond_info->rx_hashtbl_head;
while (curr_index != RLB_NULL_INDEX) {
struct rlb_client_info *curr = &(bond_info->rx_hashtbl[curr_index]);
u32 next_index = bond_info->rx_hashtbl[curr_index].next;
u32 prev_index = bond_info->rx_hashtbl[curr_index].prev;
if (curr->tag && (curr->vlan_id == vlan_id)) {
if (curr_index == bond_info->rx_hashtbl_head) {
bond_info->rx_hashtbl_head = next_index;
}
if (prev_index != RLB_NULL_INDEX) {
bond_info->rx_hashtbl[prev_index].next = next_index;
}
if (next_index != RLB_NULL_INDEX) {
bond_info->rx_hashtbl[next_index].prev = prev_index;
}
rlb_init_table_entry(curr);
}
curr_index = next_index;
}
_unlock_rx_hashtbl(bond);
}
......@@ -816,6 +884,7 @@ static void rlb_deinitialize(struct bonding *bond)
static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
{
struct bonding *bond = bond_get_bond_by_slave(slave);
struct learning_pkt pkt;
int size = sizeof(struct learning_pkt);
int i;
......@@ -825,7 +894,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
memcpy(pkt.mac_src, mac_addr, ETH_ALEN);
pkt.type = __constant_htons(ETH_P_LOOP);
for (i = 0; i < MAX_LP_RETRY; i++) {
for (i = 0; i < MAX_LP_BURST; i++) {
struct sk_buff *skb;
char *data;
......@@ -843,6 +912,26 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
skb->priority = TC_PRIO_CONTROL;
skb->dev = slave->dev;
if (!list_empty(&bond->vlan_list)) {
struct vlan_entry *vlan;
vlan = bond_next_vlan(bond,
bond->alb_info.current_alb_vlan);
bond->alb_info.current_alb_vlan = vlan;
if (!vlan) {
kfree_skb(skb);
continue;
}
skb = vlan_put_tag(skb, vlan->vlan_id);
if (!skb) {
printk(KERN_ERR DRV_NAME
": Error: failed to insert VLAN tag\n");
continue;
}
}
dev_queue_xmit(skb);
}
}
......@@ -1193,6 +1282,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
int do_tx_balance = 1;
u32 hash_index = 0;
u8 *hash_start = NULL;
int res = 1;
/* make sure that the curr_active_slave and the slaves list do
* not change during tx
......@@ -1201,7 +1291,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
read_lock(&bond->curr_slave_lock);
if (!BOND_IS_OK(bond)) {
goto free_out;
goto out;
}
switch (ntohs(skb->protocol)) {
......@@ -1266,29 +1356,27 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
}
if (tx_slave && SLAVE_IS_OK(tx_slave)) {
skb->dev = tx_slave->dev;
if (tx_slave != bond->curr_active_slave) {
memcpy(eth_data->h_source,
tx_slave->dev->dev_addr,
ETH_ALEN);
}
dev_queue_xmit(skb);
res = bond_dev_queue_xmit(bond, skb, tx_slave->dev);
} else {
/* no suitable interface, frame not sent */
if (tx_slave) {
tlb_clear_slave(bond, tx_slave, 0);
}
goto free_out;
}
out:
if (res) {
/* no suitable interface, frame not sent */
dev_kfree_skb(skb);
}
read_unlock(&bond->curr_slave_lock);
read_unlock(&bond->lock);
return 0;
free_out:
dev_kfree_skb(skb);
goto out;
}
void bond_alb_monitor(struct bonding *bond)
......@@ -1589,3 +1677,15 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
return 0;
}
void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id)
{
if (bond->alb_info.current_alb_vlan &&
(bond->alb_info.current_alb_vlan->vlan_id == vlan_id)) {
bond->alb_info.current_alb_vlan = NULL;
}
if (bond->alb_info.rlb_enabled) {
rlb_clear_vlan(bond, vlan_id);
}
}
......@@ -77,6 +77,8 @@ struct rlb_client_info {
u8 assigned; /* checking whether this entry is assigned */
u8 ntt; /* flag - need to transmit client info */
struct slave *slave; /* the slave assigned to this client */
u8 tag; /* flag - need to tag skb */
unsigned short vlan_id; /* VLAN tag associated with IP address */
};
struct tlb_slave_info {
......@@ -122,6 +124,7 @@ struct alb_bond_info {
* rx traffic should be
* rebalanced
*/
struct vlan_entry *current_alb_vlan;
};
int bond_alb_initialize(struct bonding *bond, int rlb_enabled);
......@@ -133,6 +136,6 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev);
void bond_alb_monitor(struct bonding *bond);
int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr);
void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id);
#endif /* __BOND_ALB_H__ */
......@@ -455,12 +455,20 @@
*
* 2003/12/30 - Amir Noam <amir.noam at intel dot com>
* - Fixed: Cannot remove and re-enslave the original active slave.
* - Fixed: Releasing the original active slave causes mac address duplication.
* - Fixed: Releasing the original active slave causes mac address
* duplication.
* - Add support for slaves that use ethtool_ops.
* Set version to 2.5.3.
*
* 2004/01/05 - Amir Noam <amir.noam at intel dot com>
* - Save bonding parameters per bond instead of using the global values.
* Set version to 2.5.4.
*
* 2004/01/14 - Shmulik Hen <shmulik.hen at intel dot com>
* - Enhance VLAN support:
* * Add support for VLAN hardware acceleration capable slaves.
* * Add capability to tag self generated packets in ALB/TLB modes.
* Set version to 2.6.0.
*/
//#define BONDING_DEBUG 1
......@@ -502,6 +510,7 @@
#include <net/arp.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
#include <linux/if_bonding.h>
#include "bonding.h"
#include "bond_3ad.h"
......@@ -620,6 +629,371 @@ static const char *bond_mode_name(int mode)
}
}
/*---------------------------------- VLAN -----------------------------------*/
/**
* bond_add_vlan - add a new vlan id on bond
* @bond: bond that got the notification
* @vlan_id: the vlan id to add
*
* Returns -ENOMEM if allocation failed.
*/
static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id)
{
struct vlan_entry *vlan;
dprintk("bond: %s, vlan id %d\n",
(bond ? bond->dev->name: "None"), vlan_id);
vlan = kmalloc(sizeof(struct vlan_entry), GFP_KERNEL);
if (!vlan) {
return -ENOMEM;
}
INIT_LIST_HEAD(&vlan->vlan_list);
vlan->vlan_id = vlan_id;
write_lock_bh(&bond->lock);
list_add_tail(&vlan->vlan_list, &bond->vlan_list);
write_unlock_bh(&bond->lock);
dprintk("added VLAN ID %d on bond %s\n", vlan_id, bond->dev->name);
return 0;
}
/**
* bond_del_vlan - delete a vlan id from bond
* @bond: bond that got the notification
* @vlan_id: the vlan id to delete
*
* returns -ENODEV if @vlan_id was not found in @bond.
*/
static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id)
{
struct vlan_entry *vlan, *next;
int res = -ENODEV;
dprintk("bond: %s, vlan id %d\n", bond->dev->name, vlan_id);
write_lock_bh(&bond->lock);
list_for_each_entry_safe(vlan, next, &bond->vlan_list, vlan_list) {
if (vlan->vlan_id == vlan_id) {
list_del(&vlan->vlan_list);
if ((bond->params.mode == BOND_MODE_TLB) ||
(bond->params.mode == BOND_MODE_ALB)) {
bond_alb_clear_vlan(bond, vlan_id);
}
dprintk("removed VLAN ID %d from bond %s\n", vlan_id,
bond->dev->name);
kfree(vlan);
if (list_empty(&bond->vlan_list) &&
(bond->slave_cnt == 0)) {
/* Last VLAN removed and no slaves, so
* restore block on adding VLANs. This will
* be removed once new slaves that are not
* VLAN challenged will be added.
*/
bond->dev->features |= NETIF_F_VLAN_CHALLENGED;
}
res = 0;
goto out;
}
}
dprintk("couldn't find VLAN ID %d in bond %s\n", vlan_id,
bond->dev->name);
out:
write_unlock_bh(&bond->lock);
return res;
}
/**
* bond_has_challenged_slaves
* @bond: the bond we're working on
*
* Searches the slave list. Returns 1 if a vlan challenged slave
* was found, 0 otherwise.
*
* Assumes bond->lock is held.
*/
static int bond_has_challenged_slaves(struct bonding *bond)
{
struct slave *slave;
int i;
bond_for_each_slave(bond, slave, i) {
if (slave->dev->features & NETIF_F_VLAN_CHALLENGED) {
dprintk("found VLAN challenged slave - %s\n",
slave->dev->name);
return 1;
}
}
dprintk("no VLAN challenged slaves found\n");
return 0;
}
/**
* bond_next_vlan - safely skip to the next item in the vlans list.
* @bond: the bond we're working on
* @curr: item we're advancing from
*
* Returns %NULL if list is empty, bond->next_vlan if @curr is %NULL,
* or @curr->next otherwise (even if it is @curr itself again).
*
* Caller must hold bond->lock
*/
struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr)
{
struct vlan_entry *next, *last;
if (list_empty(&bond->vlan_list)) {
return NULL;
}
if (!curr) {
next = list_entry(bond->vlan_list.next,
struct vlan_entry, vlan_list);
} else {
last = list_entry(bond->vlan_list.prev,
struct vlan_entry, vlan_list);
if (last == curr) {
next = list_entry(bond->vlan_list.next,
struct vlan_entry, vlan_list);
} else {
next = list_entry(curr->vlan_list.next,
struct vlan_entry, vlan_list);
}
}
return next;
}
/**
* bond_dev_queue_xmit - Prepare skb for xmit.
*
* @bond: bond device that got this skb for tx.
* @skb: hw accel VLAN tagged skb to transmit
* @slave_dev: slave that is supposed to xmit this skbuff
*
* When the bond gets an skb to tarnsmit that is
* already hardware accelerated VLAN tagged, and it
* needs to relay this skb to a slave that is not
* hw accel capable, the skb needs to be "unaccelerated",
* i.e. strip the hwaccel tag and re-insert it as part
* of the payload.
*
* Assumption - once a VLAN device is created over the bond device, all
* packets are going to be hardware accelerated VLAN tagged since the IP
* binding is done over the VLAN device
*/
int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev)
{
unsigned short vlan_id;
int res;
if (!list_empty(&bond->vlan_list) &&
!(slave_dev->features & NETIF_F_HW_VLAN_TX)) {
res = vlan_get_tag(skb, &vlan_id);
if (res) {
return -EINVAL;
}
skb->dev = slave_dev;
skb = vlan_put_tag(skb, vlan_id);
if (!skb) {
/* vlan_put_tag() frees the skb in case of error,
* so return success here so the calling functions
* won't attempt to free is again.
*/
return 0;
}
} else {
skb->dev = slave_dev;
}
skb->priority = 1;
dev_queue_xmit(skb);
return 0;
}
/*
* In the following 3 functions, bond_vlan_rx_register(), bond_vlan_rx_add_vid
* and bond_vlan_rx_kill_vid, We don't protect the slave list iteration with a
* lock because:
* a. This operation is performed in IOCTL context,
* b. The operation is protected by the RTNL semaphore in the 8021q code,
* c. Holding a lock with BH disabled while directly calling a base driver
* entry point is generally a BAD idea.
*
* The design of synchronization/protection for this operation in the 8021q
* module is good for one or more VLAN devices over a single physical device
* and cannot be extended for a teaming solution like bonding, so there is a
* potential race condition here where a net device from the vlan group might
* be referenced (either by a base driver or the 8021q code) while it is being
* removed from the system. However, it turns out we're not making matters
* worse, and if it works for regular VLAN usage it will work here too.
*/
/**
* bond_vlan_rx_register - Propagates registration to slaves
* @bond_dev: bonding net device that got called
* @grp: vlan group being registered
*/
static void bond_vlan_rx_register(struct net_device *bond_dev, struct vlan_group *grp)
{
struct bonding *bond = bond_dev->priv;
struct slave *slave;
int i;
bond->vlgrp = grp;
bond_for_each_slave(bond, slave, i) {
struct net_device *slave_dev = slave->dev;
if ((slave_dev->features & NETIF_F_HW_VLAN_RX) &&
slave_dev->vlan_rx_register) {
slave_dev->vlan_rx_register(slave_dev, grp);
}
}
}
/**
* bond_vlan_rx_add_vid - Propagates adding an id to slaves
* @bond_dev: bonding net device that got called
* @vid: vlan id being added
*/
static void bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid)
{
struct bonding *bond = bond_dev->priv;
struct slave *slave;
int i, res;
bond_for_each_slave(bond, slave, i) {
struct net_device *slave_dev = slave->dev;
if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) &&
slave_dev->vlan_rx_add_vid) {
slave_dev->vlan_rx_add_vid(slave_dev, vid);
}
}
res = bond_add_vlan(bond, vid);
if (res) {
printk(KERN_ERR DRV_NAME
": %s: Failed to add vlan id %d\n",
bond_dev->name, vid);
}
}
/**
* bond_vlan_rx_kill_vid - Propagates deleting an id to slaves
* @bond_dev: bonding net device that got called
* @vid: vlan id being removed
*/
static void bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid)
{
struct bonding *bond = bond_dev->priv;
struct slave *slave;
struct net_device *vlan_dev;
int i, res;
bond_for_each_slave(bond, slave, i) {
struct net_device *slave_dev = slave->dev;
if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) &&
slave_dev->vlan_rx_kill_vid) {
/* Save and then restore vlan_dev in the grp array,
* since the slave's driver might clear it.
*/
vlan_dev = bond->vlgrp->vlan_devices[vid];
slave_dev->vlan_rx_kill_vid(slave_dev, vid);
bond->vlgrp->vlan_devices[vid] = vlan_dev;
}
}
res = bond_del_vlan(bond, vid);
if (res) {
printk(KERN_ERR DRV_NAME
": %s: Failed to remove vlan id %d\n",
bond_dev->name, vid);
}
}
static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *slave_dev)
{
struct vlan_entry *vlan;
write_lock_bh(&bond->lock);
if (list_empty(&bond->vlan_list)) {
goto out;
}
if ((slave_dev->features & NETIF_F_HW_VLAN_RX) &&
slave_dev->vlan_rx_register) {
slave_dev->vlan_rx_register(slave_dev, bond->vlgrp);
}
if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) ||
!(slave_dev->vlan_rx_add_vid)) {
goto out;
}
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
slave_dev->vlan_rx_add_vid(slave_dev, vlan->vlan_id);
}
out:
write_unlock_bh(&bond->lock);
}
static void bond_del_vlans_from_slave(struct bonding *bond, struct net_device *slave_dev)
{
struct vlan_entry *vlan;
struct net_device *vlan_dev;
write_lock_bh(&bond->lock);
if (list_empty(&bond->vlan_list)) {
goto out;
}
if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) ||
!(slave_dev->vlan_rx_kill_vid)) {
goto unreg;
}
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
/* Save and then restore vlan_dev in the grp array,
* since the slave's driver might clear it.
*/
vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id];
slave_dev->vlan_rx_kill_vid(slave_dev, vlan->vlan_id);
bond->vlgrp->vlan_devices[vlan->vlan_id] = vlan_dev;
}
unreg:
if ((slave_dev->features & NETIF_F_HW_VLAN_RX) &&
slave_dev->vlan_rx_register) {
slave_dev->vlan_rx_register(slave_dev, NULL);
}
out:
write_unlock_bh(&bond->lock);
}
/*------------------------------- Link status -------------------------------*/
/*
......@@ -1214,6 +1588,7 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
struct dev_mc_list *dmi;
struct sockaddr addr;
int link_reporting;
int old_features = bond_dev->features;
int res = 0;
if (slave_dev->do_ioctl == NULL) {
......@@ -1234,6 +1609,36 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
return -EBUSY;
}
/* vlan challenged mutual exclusion */
/* no need to lock since we're protected by rtnl_lock */
if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) {
dprintk("%s: NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
if (!list_empty(&bond->vlan_list)) {
printk(KERN_ERR DRV_NAME
": Error: cannot enslave VLAN "
"challenged slave %s on VLAN enabled "
"bond %s\n", slave_dev->name,
bond_dev->name);
return -EPERM;
} else {
printk(KERN_WARNING DRV_NAME
": Warning: enslaved VLAN challenged "
"slave %s. Adding VLANs will be blocked as "
"long as %s is part of bond %s\n",
slave_dev->name, slave_dev->name,
bond_dev->name);
bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
}
} else {
dprintk("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
if (bond->slave_cnt == 0) {
/* First slave, and it is not VLAN challenged,
* so remove the block of adding VLANs over the bond.
*/
bond_dev->features &= ~NETIF_F_VLAN_CHALLENGED;
}
}
if (app_abi_ver >= 1) {
/* The application is using an ABI, which requires the
* slave interface to be closed.
......@@ -1242,7 +1647,8 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
printk(KERN_ERR DRV_NAME
": Error: %s is up\n",
slave_dev->name);
return -EPERM;
res = -EPERM;
goto err_undo_flags;
}
if (slave_dev->set_mac_address == NULL) {
......@@ -1253,7 +1659,8 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
"Your kernel likely does not support slave "
"devices.\n");
return -EOPNOTSUPP;
res = -EOPNOTSUPP;
goto err_undo_flags;
}
} else {
/* The application is not using an ABI, which requires the
......@@ -1263,7 +1670,8 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
printk(KERN_ERR DRV_NAME
": Error: %s is not running\n",
slave_dev->name);
return -EINVAL;
res = -EINVAL;
goto err_undo_flags;
}
if ((bond->params.mode == BOND_MODE_8023AD) ||
......@@ -1273,13 +1681,15 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
": Error: to use %s mode, you must upgrade "
"ifenslave.\n",
bond_mode_name(bond->params.mode));
return -EOPNOTSUPP;
res = -EOPNOTSUPP;
goto err_undo_flags;
}
}
new_slave = kmalloc(sizeof(struct slave), GFP_KERNEL);
if (!new_slave) {
return -ENOMEM;
res = -ENOMEM;
goto err_undo_flags;
}
memset(new_slave, 0, sizeof(struct slave));
......@@ -1368,6 +1778,8 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
dev_mc_add(slave_dev, lacpdu_multicast, ETH_ALEN, 0);
}
bond_add_vlans_on_slave(bond, slave_dev);
write_lock_bh(&bond->lock);
bond_attach_slave(bond, new_slave);
......@@ -1576,6 +1988,10 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
err_free:
kfree(new_slave);
err_undo_flags:
bond_dev->features = old_features;
return res;
}
......@@ -1689,8 +2105,37 @@ static int bond_release(struct net_device *bond_dev, struct net_device *slave_de
}
}
if (bond->slave_cnt == 0) {
/* if the last slave was removed, zero the mac address
* of the master so it will be set by the application
* to the mac address of the first slave
*/
memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
if (list_empty(&bond->vlan_list)) {
bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
} else {
printk(KERN_WARNING DRV_NAME
": Warning: clearing HW address of %s while it "
"still has VLANs.\n",
bond_dev->name);
printk(KERN_WARNING DRV_NAME
": When re-adding slaves, make sure the bond's "
"HW address matches its VLANs'.\n");
}
} else if ((bond_dev->features & NETIF_F_VLAN_CHALLENGED) &&
!bond_has_challenged_slaves(bond)) {
printk(KERN_INFO DRV_NAME
": last VLAN challenged slave %s "
"left bond %s. VLAN blocking is removed\n",
slave_dev->name, bond_dev->name);
bond_dev->features &= ~NETIF_F_VLAN_CHALLENGED;
}
write_unlock_bh(&bond->lock);
bond_del_vlans_from_slave(bond, slave_dev);
/* If the mode USES_PRIMARY, then we should only remove its
* promisc and mc settings if it was the curr_active_slave, but that was
* already taken care of above when we detached the slave
......@@ -1732,14 +2177,6 @@ static int bond_release(struct net_device *bond_dev, struct net_device *slave_de
kfree(slave);
/* if the last slave was removed, zero the mac address
* of the master so it will be set by the application
* to the mac address of the first slave
*/
if (bond->slave_cnt == 0) {
memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
}
return 0; /* deletion OK */
}
......@@ -1788,6 +2225,8 @@ static int bond_release_all(struct net_device *bond_dev)
*/
write_unlock_bh(&bond->lock);
bond_del_vlans_from_slave(bond, slave_dev);
/* If the mode USES_PRIMARY, then we should only remove its
* promisc and mc settings if it was the curr_active_slave, but that was
* already taken care of above when we detached the slave
......@@ -1838,6 +2277,18 @@ static int bond_release_all(struct net_device *bond_dev)
*/
memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
if (list_empty(&bond->vlan_list)) {
bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
} else {
printk(KERN_WARNING DRV_NAME
": Warning: clearing HW address of %s while it "
"still has VLANs.\n",
bond_dev->name);
printk(KERN_WARNING DRV_NAME
": When re-adding slaves, make sure the bond's "
"HW address matches its VLANs'.\n");
}
printk(KERN_INFO DRV_NAME
": %s: released all slaves\n",
bond_dev->name);
......@@ -3569,11 +4020,12 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev
struct bonding *bond = bond_dev->priv;
struct slave *slave, *start_at;
int i;
int res = 1;
read_lock(&bond->lock);
if (!BOND_IS_OK(bond)) {
goto free_out;
goto out;
}
read_lock(&bond->curr_slave_lock);
......@@ -3581,33 +4033,31 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev
read_unlock(&bond->curr_slave_lock);
if (!slave) {
goto free_out;
goto out;
}
bond_for_each_slave_from(bond, slave, i, start_at) {
if (IS_UP(slave->dev) &&
(slave->link == BOND_LINK_UP) &&
(slave->state == BOND_STATE_ACTIVE)) {
skb->dev = slave->dev;
skb->priority = 1;
dev_queue_xmit(skb);
res = bond_dev_queue_xmit(bond, skb, slave->dev);
write_lock(&bond->curr_slave_lock);
bond->curr_active_slave = slave->next;
write_unlock(&bond->curr_slave_lock);
goto out;
break;
}
}
out:
read_unlock(&bond->lock);
return 0;
free_out:
out:
if (res) {
/* no suitable interface, frame not sent */
dev_kfree_skb(skb);
goto out;
}
read_unlock(&bond->lock);
return 0;
}
/*
......@@ -3617,6 +4067,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev
static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_dev)
{
struct bonding *bond = bond_dev->priv;
int res = 1;
/* if we are sending arp packets, try to at least
identify our own ip address */
......@@ -3633,26 +4084,21 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
read_lock(&bond->curr_slave_lock);
if (!BOND_IS_OK(bond)) {
goto free_out;
goto out;
}
if (bond->curr_active_slave) { /* one usable interface */
skb->dev = bond->curr_active_slave->dev;
skb->priority = 1;
dev_queue_xmit(skb);
goto out;
} else {
goto free_out;
res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev);
}
out:
if (res) {
/* no suitable interface, frame not sent */
dev_kfree_skb(skb);
}
read_unlock(&bond->curr_slave_lock);
read_unlock(&bond->lock);
return 0;
free_out:
/* no suitable interface, frame not sent */
dev_kfree_skb(skb);
goto out;
}
/*
......@@ -3667,11 +4113,12 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
struct slave *slave, *start_at;
int slave_no;
int i;
int res = 1;
read_lock(&bond->lock);
if (!BOND_IS_OK(bond)) {
goto free_out;
goto out;
}
slave_no = (data->h_dest[5]^bond_dev->dev_addr[5]) % bond->slave_cnt;
......@@ -3689,22 +4136,18 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
if (IS_UP(slave->dev) &&
(slave->link == BOND_LINK_UP) &&
(slave->state == BOND_STATE_ACTIVE)) {
skb->dev = slave->dev;
skb->priority = 1;
dev_queue_xmit(skb);
goto out;
res = bond_dev_queue_xmit(bond, skb, slave->dev);
break;
}
}
out:
read_unlock(&bond->lock);
return 0;
free_out:
if (res) {
/* no suitable interface, frame not sent */
dev_kfree_skb(skb);
goto out;
}
read_unlock(&bond->lock);
return 0;
}
/*
......@@ -3716,11 +4159,12 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
struct slave *slave, *start_at;
struct net_device *tx_dev = NULL;
int i;
int res = 1;
read_lock(&bond->lock);
if (!BOND_IS_OK(bond)) {
goto free_out;
goto out;
}
read_lock(&bond->curr_slave_lock);
......@@ -3728,7 +4172,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
read_unlock(&bond->curr_slave_lock);
if (!start_at) {
goto free_out;
goto out;
}
bond_for_each_slave_from(bond, slave, i, start_at) {
......@@ -3744,31 +4188,28 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
continue;
}
skb2->dev = tx_dev;
skb2->priority = 1;
dev_queue_xmit(skb2);
res = bond_dev_queue_xmit(bond, skb2, tx_dev);
if (res) {
dev_kfree_skb(skb2);
continue;
}
}
tx_dev = slave->dev;
}
}
if (tx_dev) {
skb->dev = tx_dev;
skb->priority = 1;
dev_queue_xmit(skb);
} else {
goto free_out;
res = bond_dev_queue_xmit(bond, skb, tx_dev);
}
out:
if (res) {
/* no suitable interface, frame not sent */
dev_kfree_skb(skb);
}
/* frame sent to all suitable interfaces */
read_unlock(&bond->lock);
return 0;
free_out:
/* no suitable interface, frame not sent */
dev_kfree_skb(skb);
goto out;
}
#ifdef CONFIG_NET_FASTROUTE
......@@ -3837,6 +4278,7 @@ static int __init bond_init(struct net_device *bond_dev, struct bond_params *par
bond->current_arp_slave = NULL;
bond->primary_slave = NULL;
bond->dev = bond_dev;
INIT_LIST_HEAD(&bond->vlan_list);
/* Initialize the device entry points */
bond_dev->open = bond_open;
......@@ -3858,6 +4300,25 @@ static int __init bond_init(struct net_device *bond_dev, struct bond_params *par
bond_dev->tx_queue_len = 0;
bond_dev->flags |= IFF_MASTER|IFF_MULTICAST;
/* At first, we block adding VLANs. That's the only way to
* prevent problems that occur when adding VLANs over an
* empty bond. The block will be removed once non-challenged
* slaves are enslaved.
*/
bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
/* By default, we declare the bond to be fully
* VLAN hardware accelerated capable. Special
* care is taken in the various xmit functions
* when there are slaves that are not hw accel
* capable
*/
bond_dev->vlan_rx_register = bond_vlan_rx_register;
bond_dev->vlan_rx_add_vid = bond_vlan_rx_add_vid;
bond_dev->vlan_rx_kill_vid = bond_vlan_rx_kill_vid;
bond_dev->features |= (NETIF_F_HW_VLAN_TX |
NETIF_F_HW_VLAN_RX |
NETIF_F_HW_VLAN_FILTER);
#ifdef CONFIG_PROC_FS
bond_create_proc_entry(bond);
......
......@@ -36,8 +36,8 @@
#include "bond_3ad.h"
#include "bond_alb.h"
#define DRV_VERSION "2.5.4"
#define DRV_RELDATE "December 30, 2003"
#define DRV_VERSION "2.6.0"
#define DRV_RELDATE "January 14, 2004"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
......@@ -147,6 +147,11 @@ struct bond_params {
u32 arp_targets[BOND_MAX_ARP_TARGETS];
};
struct vlan_entry {
struct list_head vlan_list;
unsigned short vlan_id;
};
struct slave {
struct net_device *dev; /* first - usefull for panic debug */
struct slave *next;
......@@ -196,6 +201,8 @@ struct bonding {
struct ad_bond_info ad_info;
struct alb_bond_info alb_info;
struct bond_params params;
struct list_head vlan_list;
struct vlan_group *vlgrp;
};
/**
......@@ -238,5 +245,8 @@ extern inline void bond_set_slave_active_flags(struct slave *slave)
slave->dev->flags &= ~IFF_NOARP;
}
struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
#endif /* _LINUX_BONDING_H */
......@@ -1461,7 +1461,7 @@ static int __init depca_mca_probe(struct device *device)
out_unclaim:
mca_device_set_claim(mdev, 0);
return err;;
return err;
}
#endif
......
......@@ -178,6 +178,7 @@ static inline struct sixpack *sp_alloc(void)
(sixpack_ctrls[i] = (sixpack_ctrl_t *)kmalloc(sizeof(sixpack_ctrl_t),
GFP_KERNEL)) != NULL) {
spp = sixpack_ctrls[i];
}
memset(spp, 0, sizeof(sixpack_ctrl_t));
/* Initialize channel control data */
......@@ -188,7 +189,6 @@ static inline struct sixpack *sp_alloc(void)
spp->dev.priv = (void *) &spp->ctrl;
spp->dev.next = NULL;
spp->dev.init = sixpack_init;
}
if (spp != NULL) {
/* register device so that it can be ifconfig'ed */
......
......@@ -3043,14 +3043,27 @@ static int __init hp100_module_init(void)
int err;
err = hp100_isa_init();
if (err && err != -ENODEV)
goto out;
#ifdef CONFIG_EISA
err |= eisa_driver_register(&hp100_eisa_driver);
err = eisa_driver_register(&hp100_eisa_driver);
if (err && err != -ENODEV)
goto out2;
#endif
#ifdef CONFIG_PCI
err |= pci_module_init(&hp100_pci_driver);
err = pci_module_init(&hp100_pci_driver);
if (err && err != -ENODEV)
goto out3;
#endif
out:
return err;
out3:
#ifdef CONFIG_EISA
eisa_driver_unregister (&hp100_eisa_driver);
out2:
#endif
hp100_isa_cleanup();
goto out;
}
......
......@@ -720,6 +720,8 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
lp->name = chipname;
lp->shared_irq = shared;
lp->mii_if.full_duplex = fdx;
lp->mii_if.phy_id_mask = 0x1f;
lp->mii_if.reg_num_mask = 0x1f;
lp->dxsuflo = dxsuflo;
lp->ltint = ltint;
lp->mii = mii;
......@@ -1006,9 +1008,10 @@ pcnet32_init_ring(struct net_device *dev)
}
if (lp->rx_dma_addr[i] == 0)
lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail, rx_skbuff->len, PCI_DMA_FROMDEVICE);
lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev,
rx_skbuff->tail, PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE);
lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]);
lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ);
lp->rx_ring[i].buf_length = le16_to_cpu(2-PKT_BUF_SZ);
lp->rx_ring[i].status = le16_to_cpu(0x8000);
}
/* The Tx buffer address is filled in as needed, but we do need to clear
......@@ -1079,7 +1082,7 @@ pcnet32_tx_timeout (struct net_device *dev)
pcnet32_restart(dev, 0x0042);
dev->trans_start = jiffies;
netif_start_queue(dev);
netif_wake_queue(dev);
spin_unlock_irqrestore(&lp->lock, flags);
}
......@@ -1105,9 +1108,10 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
* interrupt when that option is available to us.
*/
status = 0x8300;
entry = (lp->cur_tx - lp->dirty_tx) & TX_RING_MOD_MASK;
if ((lp->ltint) &&
((lp->cur_tx - lp->dirty_tx == TX_RING_SIZE/2) ||
(lp->cur_tx - lp->dirty_tx >= TX_RING_SIZE-2)))
((entry == TX_RING_SIZE/2) ||
(entry >= TX_RING_SIZE-2)))
{
/* Enable Successful-TxDone interrupt if we have
* 1/2 of, or nearly all of, our ring buffer Tx'd
......@@ -1122,7 +1126,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Mask to ring buffer boundary. */
entry = lp->cur_tx & TX_RING_MOD_MASK;
/* Caution: the write order is important here, set the base address
/* Caution: the write order is important here, set the status
with the "ownership" bits last. */
lp->tx_ring[entry].length = le16_to_cpu(-skb->len);
......@@ -1144,7 +1148,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0)
netif_start_queue(dev);
netif_wake_queue(dev);
else {
lp->tx_full = 1;
netif_stop_queue(dev);
......@@ -1191,8 +1195,9 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
if (csr0 & 0x0200) { /* Tx-done interrupt */
unsigned int dirty_tx = lp->dirty_tx;
int delta;
while (dirty_tx < lp->cur_tx) {
while (dirty_tx != lp->cur_tx) {
int entry = dirty_tx & TX_RING_MOD_MASK;
int status = (short)le16_to_cpu(lp->tx_ring[entry].status);
......@@ -1246,15 +1251,17 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
dirty_tx++;
}
if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
delta = (lp->cur_tx - dirty_tx) & (TX_RING_MOD_MASK + TX_RING_SIZE);
if (delta >= TX_RING_SIZE) {
printk(KERN_ERR "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
dev->name, dirty_tx, lp->cur_tx, lp->tx_full);
dirty_tx += TX_RING_SIZE;
delta -= TX_RING_SIZE;
}
if (lp->tx_full &&
netif_queue_stopped(dev) &&
dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
delta < TX_RING_SIZE - 2) {
/* The ring is no longer full, clear tbusy. */
lp->tx_full = 0;
netif_wake_queue (dev);
......@@ -1344,13 +1351,14 @@ pcnet32_rx(struct net_device *dev)
if ((newskb = dev_alloc_skb (PKT_BUF_SZ))) {
skb_reserve (newskb, 2);
skb = lp->rx_skbuff[entry];
pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[entry], skb->len, PCI_DMA_FROMDEVICE);
pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[entry],
PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE);
skb_put (skb, pkt_len);
lp->rx_skbuff[entry] = newskb;
newskb->dev = dev;
lp->rx_dma_addr[entry] =
pci_map_single(lp->pci_dev, newskb->tail,
newskb->len, PCI_DMA_FROMDEVICE);
PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE);
lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]);
rx_in_place = 1;
} else
......@@ -1379,7 +1387,7 @@ pcnet32_rx(struct net_device *dev)
skb_put(skb,pkt_len); /* Make room */
pci_dma_sync_single(lp->pci_dev,
lp->rx_dma_addr[entry],
PKT_BUF_SZ,
PKT_BUF_SZ-2,
PCI_DMA_FROMDEVICE);
eth_copy_and_sum(skb,
(unsigned char *)(lp->rx_skbuff[entry]->tail),
......@@ -1396,7 +1404,7 @@ pcnet32_rx(struct net_device *dev)
* The docs say that the buffer length isn't touched, but Andrew Boyd
* of QNX reports that some revs of the 79C965 clear it.
*/
lp->rx_ring[entry].buf_length = le16_to_cpu(-PKT_BUF_SZ);
lp->rx_ring[entry].buf_length = le16_to_cpu(2-PKT_BUF_SZ);
lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
}
......@@ -1436,7 +1444,8 @@ pcnet32_close(struct net_device *dev)
for (i = 0; i < RX_RING_SIZE; i++) {
lp->rx_ring[i].status = 0;
if (lp->rx_skbuff[i]) {
pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], lp->rx_skbuff[i]->len, PCI_DMA_FROMDEVICE);
pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2,
PCI_DMA_FROMDEVICE);
dev_kfree_skb(lp->rx_skbuff[i]);
}
lp->rx_skbuff[i] = NULL;
......@@ -1625,12 +1634,18 @@ static int pcnet32_ethtool_ioctl (struct net_device *dev, void *useraddr)
}
/* restart autonegotiation */
case ETHTOOL_NWAY_RST: {
return mii_nway_restart(&lp->mii_if);
int r;
spin_lock_irq(&lp->lock);
r = mii_nway_restart(&lp->mii_if);
spin_unlock_irq(&lp->lock);
return r;
}
/* get link status */
case ETHTOOL_GLINK: {
struct ethtool_value edata = {ETHTOOL_GLINK};
spin_lock_irq(&lp->lock);
edata.data = mii_link_ok(&lp->mii_if);
spin_unlock_irq(&lp->lock);
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
......@@ -1661,45 +1676,37 @@ static int pcnet32_ethtool_ioctl (struct net_device *dev, void *useraddr)
static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
unsigned long ioaddr = dev->base_addr;
struct pcnet32_private *lp = dev->priv;
struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
int phyaddr = lp->a.read_bcr (ioaddr, 33);
int rc;
unsigned long flags;
if (cmd == SIOCETHTOOL)
return pcnet32_ethtool_ioctl(dev, (void *) rq->ifr_data);
/* SIOC[GS]MIIxxx ioctls */
if (lp->mii) {
switch(cmd) {
case SIOCGMIIPHY: /* Get address of MII PHY in use. */
data->phy_id = (phyaddr >> 5) & 0x1f;
/* Fall Through */
case SIOCGMIIREG: /* Read MII PHY register. */
lp->a.write_bcr (ioaddr, 33, ((data->phy_id & 0x1f) << 5) | (data->reg_num & 0x1f));
data->val_out = lp->a.read_bcr (ioaddr, 34);
lp->a.write_bcr (ioaddr, 33, phyaddr);
return 0;
case SIOCSMIIREG: /* Write MII PHY register. */
if (!capable(CAP_NET_ADMIN))
return -EPERM;
lp->a.write_bcr (ioaddr, 33, ((data->phy_id & 0x1f) << 5) | (data->reg_num & 0x1f));
lp->a.write_bcr (ioaddr, 34, data->val_in);
lp->a.write_bcr (ioaddr, 33, phyaddr);
return 0;
default:
return -EOPNOTSUPP;
}
spin_lock_irqsave(&lp->lock, flags);
rc = generic_mii_ioctl(&lp->mii_if, data, cmd, NULL);
spin_unlock_irqrestore(&lp->lock, flags);
} else {
rc = -EOPNOTSUPP;
}
return -EOPNOTSUPP;
return rc;
}
static void pcnet32_watchdog(struct net_device *dev)
{
struct pcnet32_private *lp = dev->priv;
unsigned long flags;
/* Print the link status if it has changed */
if (lp->mii)
if (lp->mii) {
spin_lock_irqsave(&lp->lock, flags);
mii_check_media (&lp->mii_if, 1, 0);
spin_unlock_irqrestore(&lp->lock, flags);
}
mod_timer (&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT);
}
......
......@@ -954,8 +954,7 @@ static void
SiS190_tx_interrupt(struct net_device *dev, struct sis190_private *tp,
void *ioaddr)
{
unsigned long dirty_tx, tx_left = 0;
int entry = tp->cur_tx % NUM_TX_DESC;
unsigned long dirty_tx, tx_left;
assert(dev != NULL);
assert(tp != NULL);
......@@ -965,6 +964,8 @@ SiS190_tx_interrupt(struct net_device *dev, struct sis190_private *tp,
tx_left = tp->cur_tx - dirty_tx;
while (tx_left > 0) {
int entry = dirty_tx % NUM_TX_DESC;
if ((le32_to_cpu(tp->TxDescArray[entry].status) & OWNbit) == 0) {
struct sk_buff *skb;
......@@ -980,7 +981,6 @@ SiS190_tx_interrupt(struct net_device *dev, struct sis190_private *tp,
tp->stats.tx_packets++;
dirty_tx++;
tx_left--;
entry++;
}
}
......
......@@ -2093,7 +2093,7 @@ static void set_rx_mode(struct net_device *net_dev)
i++, mclist = mclist->next) {
unsigned int bit_nr =
sis900_mcast_bitnr(mclist->dmi_addr, revision);
mc_filter[bit_nr >> 4] |= (1 << bit_nr);
mc_filter[bit_nr >> 4] |= (1 << (bit_nr & 0xf));
}
}
......
......@@ -2,6 +2,8 @@
*
* Name: lm80.h
* Project: Gigabit Ethernet Adapters, Common Modules
* Version: $Revision: 1.6 $
* Date: $Date: 2003/05/13 17:26:52 $
* Purpose: Contains all defines for the LM80 Chip
* (National Semiconductor).
*
......
......@@ -2,6 +2,8 @@
*
* Name: skaddr.h
* Project: Gigabit Ethernet Adapters, ADDR-Modul
* Version: $Revision: 1.29 $
* Date: $Date: 2003/05/13 16:57:24 $
* Purpose: Header file for Address Management (MC, UC, Prom).
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skcsum.h
* Project: GEnesis - SysKonnect SK-NET Gigabit Ethernet (SK-98xx)
* Version: $Revision: 1.10 $
* Date: $Date: 2003/08/20 13:59:57 $
* Purpose: Store/verify Internet checksum in send/receive packets.
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skdebug.h
* Project: Gigabit Ethernet Adapters, Common Modules
* Version: $Revision: 1.14 $
* Date: $Date: 2003/05/13 17:26:00 $
* Purpose: SK specific DEBUG support
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skdrv1st.h
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.4 $
* Date: $Date: 2003/11/12 14:28:14 $
* Purpose: First header file for driver and all other modules
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skdrv2nd.h
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.10 $
* Date: $Date: 2003/12/11 16:04:45 $
* Purpose: Second header file for driver and all other modules
*
******************************************************************************/
......@@ -76,7 +78,13 @@
/* Marvell (0x11ab) */ \
} else if (pdev->vendor == 0x11ab) { \
/* Gigabit Ethernet Adapter (0x4320) */ \
if ((pdev->device == 0x4320)) { \
/* Gigabit Ethernet Adapter (0x4360) */ \
/* Gigabit Ethernet Adapter (0x4361) */ \
/* Belkin (0x5005) */ \
if ((pdev->device == 0x4320) || \
(pdev->device == 0x4360) || \
(pdev->device == 0x4361) || \
(pdev->device == 0x5005)) { \
result = SK_TRUE; \
} \
/* CNet (0x1371) */ \
......
......@@ -2,6 +2,8 @@
*
* Name: skerror.h
* Project: Gigabit Ethernet Adapters, Common Modules
* Version: $Revision: 1.7 $
* Date: $Date: 2003/05/13 17:25:13 $
* Purpose: SK specific Error log support
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skgedrv.h
* Project: Gigabit Ethernet Adapters, Common Modules
* Version: $Revision: 1.10 $
* Date: $Date: 2003/07/04 12:25:01 $
* Purpose: Interface with the driver
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skgehw.h
* Project: Gigabit Ethernet Adapters, Common Modules
* Version: $Revision: 1.56 $
* Date: $Date: 2003/09/23 09:01:00 $
* Purpose: Defines and Macros for the Gigabit Ethernet Adapter Product Family
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skhwt.h
* Project: Gigabit Ethernet Adapters, Event Scheduler Module
* Version: $Revision: 1.7 $
* Date: $Date: 2003/09/16 12:55:08 $
* Purpose: Defines for the hardware timer functions
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skgei2c.h
* Project: Gigabit Ethernet Adapters, TWSI-Module
* Version: $Revision: 1.25 $
* Date: $Date: 2003/10/20 09:06:05 $
* Purpose: Special defines for TWSI
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skgeinit.h
* Project: Gigabit Ethernet Adapters, Common Modules
* Version: $Revision: 1.83 $
* Date: $Date: 2003/09/16 14:07:37 $
* Purpose: Structures and prototypes for the GE Init Module
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skgepnm2.h
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.36 $
* Date: $Date: 2003/05/23 12:45:13 $
* Purpose: Defines for Private Network Management Interface
*
****************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skgepnmi.h
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.62 $
* Date: $Date: 2003/08/15 12:31:52 $
* Purpose: Defines for Private Network Management Interface
*
****************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skgesirq.h
* Project: Gigabit Ethernet Adapters, Common Modules
* Version: $Revision: 1.30 $
* Date: $Date: 2003/07/04 12:34:13 $
* Purpose: SK specific Gigabit Ethernet special IRQ functions
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: ski2c.h
* Project: Gigabit Ethernet Adapters, TWSI-Module
* Version: $Revision: 1.35 $
* Date: $Date: 2003/10/20 09:06:30 $
* Purpose: Defines to access Voltage and Temperature Sensor
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skqueue.h
* Project: Gigabit Ethernet Adapters, Event Scheduler Module
* Version: $Revision: 1.16 $
* Date: $Date: 2003/09/16 12:50:32 $
* Purpose: Defines for the Event queue
*
******************************************************************************/
......@@ -20,6 +22,10 @@
*
******************************************************************************/
/*
* SKQUEUE.H contains all defines and types for the event queue
*/
#ifndef _SKQUEUE_H_
#define _SKQUEUE_H_
......
......@@ -2,6 +2,8 @@
*
* Name: skrlmt.h
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.37 $
* Date: $Date: 2003/04/15 09:43:43 $
* Purpose: Header file for Redundant Link ManagemenT.
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: sktimer.h
* Project: Gigabit Ethernet Adapters, Event Scheduler Module
* Version: $Revision: 1.11 $
* Date: $Date: 2003/09/16 12:58:18 $
* Purpose: Defines for the timer functions
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: sktypes.h
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.2 $
* Date: $Date: 2003/10/07 08:16:51 $
* Purpose: Define data types for Linux
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: version.h
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.5 $
* Date: $Date: 2003/10/07 08:16:51 $
* Purpose: SK specific Error log support
*
******************************************************************************/
......@@ -23,14 +25,14 @@
#ifdef lint
static const char SysKonnectFileId[] = "@(#) (C) SysKonnect GmbH.";
static const char SysKonnectBuildNumber[] =
"@(#)SK-BUILD: 6.22 PL: 01";
"@(#)SK-BUILD: 6.23 PL: 01";
#endif /* !defined(lint) */
#define BOOT_STRING "sk98lin: Network Device Driver v6.22\n" \
#define BOOT_STRING "sk98lin: Network Device Driver v6.23\n" \
"(C)Copyright 1999-2004 Marvell(R)."
#define VER_STRING "6.22"
#define VER_STRING "6.23"
#define DRIVER_FILE_NAME "sk98lin"
#define DRIVER_REL_DATE "Jan-30-2004"
#define DRIVER_REL_DATE "Feb-13-2004"
......@@ -2,6 +2,8 @@
*
* Name: skvpd.h
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.15 $
* Date: $Date: 2003/01/13 10:39:38 $
* Purpose: Defines and Macros for VPD handling
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: xmac_ii.h
* Project: Gigabit Ethernet Adapters, Common Modules
* Version: $Revision: 1.52 $
* Date: $Date: 2003/10/02 16:35:50 $
* Purpose: Defines and Macros for Gigabit Ethernet Controller
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skaddr.c
* Project: Gigabit Ethernet Adapters, ADDR-Module
* Version: $Revision: 1.52 $
* Date: $Date: 2003/06/02 13:46:15 $
* Purpose: Manage Addresses (Multicast and Unicast) and Promiscuous Mode.
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skcsum.c
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.12 $
* Date: $Date: 2003/08/20 13:55:53 $
* Purpose: Store/verify Internet checksum in send/receive packets.
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skdim.c
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.5 $
* Date: $Date: 2003/11/28 12:55:40 $
* Purpose: All functions to maintain interrupt moderation
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skge.c
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.45 $
* Date: $Date: 2004/02/12 14:41:02 $
* Purpose: The main driver source module
*
******************************************************************************/
......@@ -294,7 +296,6 @@ static int __init skge_probe (void)
SK_BOOL BootStringCount = SK_FALSE;
int retval;
#ifdef CONFIG_PROC_FS
int proc_root_initialized = 0;
struct proc_dir_entry *pProcFile;
#endif
......@@ -311,6 +312,12 @@ static int __init skge_probe (void)
dev = NULL;
pNet = NULL;
/* Don't handle Yukon2 cards at the moment */
/* 12-feb-2004 ---- mlindner@syskonnect.de */
if (pdev->vendor == 0x11ab) {
if ( (pdev->device == 0x4360) || (pdev->device == 0x4361) )
continue;
}
SK_PCI_ISCOMPLIANT(vendor_flag, pdev);
if (!vendor_flag)
......
......@@ -2,6 +2,8 @@
*
* Name: skgehwt.c
* Project: Gigabit Ethernet Adapters, Event Scheduler Module
* Version: $Revision: 1.15 $
* Date: $Date: 2003/09/16 13:41:23 $
* Purpose: Hardware Timer
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skgeinit.c
* Project: Gigabit Ethernet Adapters, Common Modules
* Version: $Revision: 1.97 $
* Date: $Date: 2003/10/02 16:45:31 $
* Purpose: Contains functions to initialize the adapter
*
******************************************************************************/
......@@ -20,7 +22,6 @@
*
******************************************************************************/
#include "h/skdrv1st.h"
#include "h/skdrv2nd.h"
......
......@@ -2,6 +2,8 @@
*
* Name: skgemib.c
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.11 $
* Date: $Date: 2003/09/15 13:38:12 $
* Purpose: Private Network Management Interface Management Database
*
****************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skgepnmi.c
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.111 $
* Date: $Date: 2003/09/15 13:35:35 $
* Purpose: Private Network Management Interface
*
****************************************************************************/
......@@ -20,6 +22,7 @@
*
******************************************************************************/
#ifndef _lint
static const char SysKonnectFileId[] =
"@(#) $Id: skgepnmi.c,v 1.111 2003/09/15 13:35:35 tschilli Exp $ (C) Marvell.";
......
......@@ -2,6 +2,8 @@
*
* Name: skgesirq.c
* Project: Gigabit Ethernet Adapters, Common Modules
* Version: $Revision: 1.92 $
* Date: $Date: 2003/09/16 14:37:07 $
* Purpose: Special IRQ module
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: ski2c.c
* Project: Gigabit Ethernet Adapters, TWSI-Module
* Version: $Revision: 1.59 $
* Date: $Date: 2003/10/20 09:07:25 $
* Purpose: Functions to access Voltage and Temperature Sensor
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: sklm80.c
* Project: Gigabit Ethernet Adapters, TWSI-Module
* Version: $Revision: 1.22 $
* Date: $Date: 2003/10/20 09:08:21 $
* Purpose: Functions to access Voltage and Temperature Sensor (LM80)
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skproc.c
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.11 $
* Date: $Date: 2003/12/11 16:03:57 $
* Purpose: Funktions to display statictic data
*
******************************************************************************/
......@@ -22,7 +24,6 @@
* The information in this file is provided "AS IS" without warranty.
*
******************************************************************************/
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
......
......@@ -2,6 +2,8 @@
*
* Name: skqueue.c
* Project: Gigabit Ethernet Adapters, Event Scheduler Module
* Version: $Revision: 1.20 $
* Date: $Date: 2003/09/16 13:44:00 $
* Purpose: Management of an event queue.
*
******************************************************************************/
......@@ -20,6 +22,7 @@
*
******************************************************************************/
/*
* Event queue and dispatcher
*/
......
......@@ -2,6 +2,8 @@
*
* Name: skrlmt.c
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.69 $
* Date: $Date: 2003/04/15 09:39:22 $
* Purpose: Manage links on SK-NET Adapters, esp. redundant ones.
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: sktimer.c
* Project: Gigabit Ethernet Adapters, Event Scheduler Module
* Version: $Revision: 1.14 $
* Date: $Date: 2003/09/16 13:46:51 $
* Purpose: High level timer functions.
*
******************************************************************************/
......@@ -20,6 +22,7 @@
*
******************************************************************************/
/*
* Event queue and dispatcher
*/
......
......@@ -2,6 +2,8 @@
*
* Name: skvpd.c
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.37 $
* Date: $Date: 2003/01/13 10:42:45 $
* Purpose: Shared software to read and write VPD data
*
******************************************************************************/
......
......@@ -2,6 +2,8 @@
*
* Name: skxmac2.c
* Project: Gigabit Ethernet Adapters, Common Modules
* Version: $Revision: 1.102 $
* Date: $Date: 2003/10/02 16:53:58 $
* Purpose: Contains functions to initialize the MACs and PHYs
*
******************************************************************************/
......
......@@ -641,7 +641,20 @@ static int xl_open(struct net_device *dev)
*/
/* These MUST be on 8 byte boundaries */
xl_priv->xl_tx_ring = kmalloc((sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) + 7, GFP_DMA | GFP_KERNEL) ;
if (xl_priv->xl_tx_ring == NULL) {
printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers.\n",
dev->name);
free_irq(dev->irq,dev);
return -ENOMEM;
}
xl_priv->xl_rx_ring = kmalloc((sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) +7, GFP_DMA | GFP_KERNEL) ;
if (xl_priv->xl_tx_ring == NULL) {
printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers.\n",
dev->name);
free_irq(dev->irq,dev);
kfree(xl_priv->xl_tx_ring);
return -ENOMEM;
}
memset(xl_priv->xl_tx_ring,0,sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) ;
memset(xl_priv->xl_rx_ring,0,sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) ;
......
......@@ -211,10 +211,10 @@ int tulip_poll(struct net_device *dev, int *budget)
if (tp->rx_buffers[entry].mapping !=
le32_to_cpu(tp->rx_ring[entry].buffer1)) {
printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
"do not match in tulip_rx: %08x vs. %08x %p / %p.\n",
"do not match in tulip_rx: %08x vs. %llx %p / %p.\n",
dev->name,
le32_to_cpu(tp->rx_ring[entry].buffer1),
tp->rx_buffers[entry].mapping,
(unsigned long long)tp->rx_buffers[entry].mapping,
skb->head, temp);
}
#endif
......
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