Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6

This commit is contained in:
Linus Torvalds 2006-01-04 16:31:56 -08:00
commit d779188d2b
67 changed files with 11406 additions and 2392 deletions

View file

@ -0,0 +1,72 @@
The Gianfar Ethernet Driver
Sysfs File description
Author: Andy Fleming <afleming@freescale.com>
Updated: 2005-07-28
SYSFS
Several of the features of the gianfar driver are controlled
through sysfs files. These are:
bd_stash:
To stash RX Buffer Descriptors in the L2, echo 'on' or '1' to
bd_stash, echo 'off' or '0' to disable
rx_stash_len:
To stash the first n bytes of the packet in L2, echo the number
of bytes to buf_stash_len. echo 0 to disable.
WARNING: You could really screw these up if you set them too low or high!
fifo_threshold:
To change the number of bytes the controller needs in the
fifo before it starts transmission, echo the number of bytes to
fifo_thresh. Range should be 0-511.
fifo_starve:
When the FIFO has less than this many bytes during a transmit, it
enters starve mode, and increases the priority of TX memory
transactions. To change, echo the number of bytes to
fifo_starve. Range should be 0-511.
fifo_starve_off:
Once in starve mode, the FIFO remains there until it has this
many bytes. To change, echo the number of bytes to
fifo_starve_off. Range should be 0-511.
CHECKSUM OFFLOADING
The eTSEC controller (first included in parts from late 2005 like
the 8548) has the ability to perform TCP, UDP, and IP checksums
in hardware. The Linux kernel only offloads the TCP and UDP
checksums (and always performs the pseudo header checksums), so
the driver only supports checksumming for TCP/IP and UDP/IP
packets. Use ethtool to enable or disable this feature for RX
and TX.
VLAN
In order to use VLAN, please consult Linux documentation on
configuring VLANs. The gianfar driver supports hardware insertion and
extraction of VLAN headers, but not filtering. Filtering will be
done by the kernel.
MULTICASTING
The gianfar driver supports using the group hash table on the
TSEC (and the extended hash table on the eTSEC) for multicast
filtering. On the eTSEC, the exact-match MAC registers are used
before the hash tables. See Linux documentation on how to join
multicast groups.
PADDING
The gianfar driver supports padding received frames with 2 bytes
to align the IP header to a 16-byte boundary, when supported by
hardware.
ETHTOOL
The gianfar driver supports the use of ethtool for many
configuration options. You must run ethtool only on currently
open interfaces. See ethtool documentation for details.

View file

@ -586,16 +586,16 @@ struct rtl8139_private {
dma_addr_t tx_bufs_dma;
signed char phys[4]; /* MII device addresses. */
char twistie, twist_row, twist_col; /* Twister tune state. */
unsigned int default_port:4; /* Last dev->if_port value. */
unsigned int default_port : 4; /* Last dev->if_port value. */
unsigned int have_thread : 1;
spinlock_t lock;
spinlock_t rx_lock;
chip_t chipset;
pid_t thr_pid;
wait_queue_head_t thr_wait;
struct completion thr_exited;
u32 rx_config;
struct rtl_extra_stats xstats;
int time_to_die;
struct work_struct thread;
struct mii_if_info mii;
unsigned int regs_len;
unsigned long fifo_copy_timeout;
@ -620,7 +620,7 @@ static int rtl8139_open (struct net_device *dev);
static int mdio_read (struct net_device *dev, int phy_id, int location);
static void mdio_write (struct net_device *dev, int phy_id, int location,
int val);
static void rtl8139_start_thread(struct net_device *dev);
static void rtl8139_start_thread(struct rtl8139_private *tp);
static void rtl8139_tx_timeout (struct net_device *dev);
static void rtl8139_init_ring (struct net_device *dev);
static int rtl8139_start_xmit (struct sk_buff *skb,
@ -637,6 +637,7 @@ static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);
static void rtl8139_set_rx_mode (struct net_device *dev);
static void __set_rx_mode (struct net_device *dev);
static void rtl8139_hw_start (struct net_device *dev);
static void rtl8139_thread (void *_data);
static struct ethtool_ops rtl8139_ethtool_ops;
/* write MMIO register, with flush */
@ -1007,8 +1008,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
(debug < 0 ? RTL8139_DEF_MSG_ENABLE : ((1 << debug) - 1));
spin_lock_init (&tp->lock);
spin_lock_init (&tp->rx_lock);
init_waitqueue_head (&tp->thr_wait);
init_completion (&tp->thr_exited);
INIT_WORK(&tp->thread, rtl8139_thread, dev);
tp->mii.dev = dev;
tp->mii.mdio_read = mdio_read;
tp->mii.mdio_write = mdio_write;
@ -1345,7 +1345,7 @@ static int rtl8139_open (struct net_device *dev)
dev->irq, RTL_R8 (MediaStatus),
tp->mii.full_duplex ? "full" : "half");
rtl8139_start_thread(dev);
rtl8139_start_thread(tp);
return 0;
}
@ -1594,55 +1594,43 @@ static inline void rtl8139_thread_iter (struct net_device *dev,
RTL_R8 (Config1));
}
static int rtl8139_thread (void *data)
static void rtl8139_thread (void *_data)
{
struct net_device *dev = data;
struct net_device *dev = _data;
struct rtl8139_private *tp = netdev_priv(dev);
unsigned long timeout;
unsigned long thr_delay;
daemonize("%s", dev->name);
allow_signal(SIGTERM);
while (1) {
timeout = next_tick;
do {
timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout);
/* make swsusp happy with our thread */
try_to_freeze();
} while (!signal_pending (current) && (timeout > 0));
if (signal_pending (current)) {
flush_signals(current);
}
if (tp->time_to_die)
break;
if (rtnl_lock_interruptible ())
break;
if (rtnl_shlock_nowait() == 0) {
rtl8139_thread_iter (dev, tp, tp->mmio_addr);
rtnl_unlock ();
thr_delay = next_tick;
} else {
/* unlikely race. mitigate with fast poll. */
thr_delay = HZ / 2;
}
complete_and_exit (&tp->thr_exited, 0);
schedule_delayed_work(&tp->thread, thr_delay);
}
static void rtl8139_start_thread(struct net_device *dev)
static void rtl8139_start_thread(struct rtl8139_private *tp)
{
struct rtl8139_private *tp = netdev_priv(dev);
tp->thr_pid = -1;
tp->twistie = 0;
tp->time_to_die = 0;
if (tp->chipset == CH_8139_K)
tp->twistie = 1;
else if (tp->drv_flags & HAS_LNK_CHNG)
return;
tp->thr_pid = kernel_thread(rtl8139_thread, dev, CLONE_FS|CLONE_FILES);
if (tp->thr_pid < 0) {
printk (KERN_WARNING "%s: unable to start kernel thread\n",
dev->name);
tp->have_thread = 1;
schedule_delayed_work(&tp->thread, next_tick);
}
static void rtl8139_stop_thread(struct rtl8139_private *tp)
{
if (tp->have_thread) {
cancel_rearming_delayed_work(&tp->thread);
tp->have_thread = 0;
}
}
@ -2224,22 +2212,12 @@ static int rtl8139_close (struct net_device *dev)
{
struct rtl8139_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
int ret = 0;
unsigned long flags;
netif_stop_queue (dev);
if (tp->thr_pid >= 0) {
tp->time_to_die = 1;
wmb();
ret = kill_proc (tp->thr_pid, SIGTERM, 1);
if (ret) {
printk (KERN_ERR "%s: unable to signal thread\n", dev->name);
return ret;
}
wait_for_completion (&tp->thr_exited);
}
rtl8139_stop_thread(tp);
if (netif_msg_ifdown(tp))
printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n",
dev->name, RTL_R16 (IntrStatus));

View file

@ -1901,6 +1901,8 @@ config E1000_NAPI
If in doubt, say N.
source "drivers/net/ixp2000/Kconfig"
config MYRI_SBUS
tristate "MyriCOM Gigabit Ethernet support"
depends on SBUS
@ -2008,7 +2010,18 @@ config SKGE
It does not support the link failover and network management
features that "portable" vendor supplied sk98lin driver does.
config SKY2
tristate "SysKonnect Yukon2 support (EXPERIMENTAL)"
depends on PCI && EXPERIMENTAL
select CRC32
---help---
This driver support the Marvell Yukon 2 Gigabit Ethernet adapter.
To compile this driver as a module, choose M here: the module
will be called sky2. This is recommended.
config SK98LIN
tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support"
depends on PCI
@ -2120,7 +2133,7 @@ config BNX2
config SPIDER_NET
tristate "Spider Gigabit Ethernet driver"
depends on PCI && PPC_BPA
depends on PCI && PPC_CELL
help
This driver supports the Gigabit Ethernet chips present on the
Cell Processor-Based Blades from IBM.

View file

@ -13,7 +13,10 @@ obj-$(CONFIG_CHELSIO_T1) += chelsio/
obj-$(CONFIG_BONDING) += bonding/
obj-$(CONFIG_GIANFAR) += gianfar_driver.o
gianfar_driver-objs := gianfar.o gianfar_ethtool.o gianfar_mii.o
gianfar_driver-objs := gianfar.o \
gianfar_ethtool.o \
gianfar_mii.o \
gianfar_sysfs.o
#
# link order important here
@ -59,6 +62,7 @@ spidernet-y += spider_net.o spider_net_ethtool.o sungem_phy.o
obj-$(CONFIG_SPIDER_NET) += spidernet.o
obj-$(CONFIG_TC35815) += tc35815.o
obj-$(CONFIG_SKGE) += skge.o
obj-$(CONFIG_SKY2) += sky2.o
obj-$(CONFIG_SK98LIN) += sk98lin/
obj-$(CONFIG_SKFP) += skfp/
obj-$(CONFIG_VIA_RHINE) += via-rhine.o
@ -202,6 +206,7 @@ obj-$(CONFIG_NET_TULIP) += tulip/
obj-$(CONFIG_HAMRADIO) += hamradio/
obj-$(CONFIG_IRDA) += irda/
obj-$(CONFIG_ETRAX_ETHERNET) += cris/
obj-$(CONFIG_ENP2611_MSF_NET) += ixp2000/
obj-$(CONFIG_NETCONSOLE) += netconsole.o

View file

@ -4,5 +4,5 @@
obj-$(CONFIG_BONDING) += bonding.o
bonding-objs := bond_main.o bond_3ad.o bond_alb.o
bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o

View file

@ -18,38 +18,6 @@
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
*
* Changes:
*
* 2003/05/01 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and
* Amir Noam <amir.noam at intel dot com>
* - Added support for lacp_rate module param.
*
* 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com>
* - Based on discussion on mailing list, changed locking scheme
* to use lock/unlock or lock_bh/unlock_bh appropriately instead
* of lock_irqsave/unlock_irqrestore. The new scheme helps exposing
* hidden bugs and solves system hangs that occurred due to the fact
* that holding lock_irqsave doesn't prevent softirqs from running.
* This also increases total throughput since interrupts are not
* blocked on each transmitted packets or monitor timeout.
*
* 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com>
* - Renamed bond_3ad_link_status_changed() to
* bond_3ad_handle_link_change() for compatibility with TLB.
*
* 2003/05/20 - Amir Noam <amir.noam at intel dot com>
* - Fix long fail over time when releasing last slave of an active
* aggregator - send LACPDU on unbind of slave to tell partner this
* port is no longer aggregatable.
*
* 2003/06/25 - Tsippy Mendelson <tsippy.mendelson at intel dot com>
* - Send LACPDU as highest priority packet to further fix the above
* problem on very high Tx traffic load where packets may get dropped
* by the slave.
*
* 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
* - Code cleanup and style changes
*/
//#define BONDING_DEBUG 1
@ -1198,10 +1166,10 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
// detect loopback situation
if (!MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->actor_system))) {
// INFO_RECEIVED_LOOPBACK_FRAMES
printk(KERN_ERR DRV_NAME ": An illegal loopback occurred on adapter (%s)\n",
port->slave->dev->name);
printk(KERN_ERR "Check the configuration to verify that all Adapters "
"are connected to 802.3ad compliant switch ports\n");
printk(KERN_ERR DRV_NAME ": %s: An illegal loopback occurred on "
"adapter (%s). Check the configuration to verify that all "
"Adapters are connected to 802.3ad compliant switch ports\n",
port->slave->dev->master->name, port->slave->dev->name);
__release_rx_machine_lock(port);
return;
}
@ -1378,8 +1346,9 @@ static void ad_port_selection_logic(struct port *port)
}
}
if (!curr_port) { // meaning: the port was related to an aggregator but was not on the aggregator port list
printk(KERN_WARNING DRV_NAME ": Warning: Port %d (on %s) was "
printk(KERN_WARNING DRV_NAME ": %s: Warning: Port %d (on %s) was "
"related to aggregator %d but was not on its port list\n",
port->slave->dev->master->name,
port->actor_port_number, port->slave->dev->name,
port->aggregator->aggregator_identifier);
}
@ -1450,7 +1419,8 @@ static void ad_port_selection_logic(struct port *port)
dprintk("Port %d joined LAG %d(new LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier);
} else {
printk(KERN_ERR DRV_NAME ": Port %d (on %s) did not find a suitable aggregator\n",
printk(KERN_ERR DRV_NAME ": %s: Port %d (on %s) did not find a suitable aggregator\n",
port->slave->dev->master->name,
port->actor_port_number, port->slave->dev->name);
}
}
@ -1582,8 +1552,9 @@ static void ad_agg_selection_logic(struct aggregator *aggregator)
// check if any partner replys
if (best_aggregator->is_individual) {
printk(KERN_WARNING DRV_NAME ": Warning: No 802.3ad response from the link partner "
"for any adapters in the bond\n");
printk(KERN_WARNING DRV_NAME ": %s: Warning: No 802.3ad response from "
"the link partner for any adapters in the bond\n",
best_aggregator->slave->dev->master->name);
}
// check if there are more than one aggregator
@ -1915,7 +1886,8 @@ int bond_3ad_bind_slave(struct slave *slave)
struct aggregator *aggregator;
if (bond == NULL) {
printk(KERN_ERR "The slave %s is not attached to its bond\n", slave->dev->name);
printk(KERN_ERR DRV_NAME ": %s: The slave %s is not attached to its bond\n",
slave->dev->master->name, slave->dev->name);
return -1;
}
@ -1990,7 +1962,9 @@ void bond_3ad_unbind_slave(struct slave *slave)
// if slave is null, the whole port is not initialized
if (!port->slave) {
printk(KERN_WARNING DRV_NAME ": Trying to unbind an uninitialized port on %s\n", slave->dev->name);
printk(KERN_WARNING DRV_NAME ": Warning: %s: Trying to "
"unbind an uninitialized port on %s\n",
slave->dev->master->name, slave->dev->name);
return;
}
@ -2021,7 +1995,8 @@ void bond_3ad_unbind_slave(struct slave *slave)
dprintk("Some port(s) related to LAG %d - replaceing with LAG %d\n", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier);
if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) {
printk(KERN_INFO DRV_NAME ": Removing an active aggregator\n");
printk(KERN_INFO DRV_NAME ": %s: Removing an active aggregator\n",
aggregator->slave->dev->master->name);
// select new active aggregator
select_new_active_agg = 1;
}
@ -2051,15 +2026,17 @@ void bond_3ad_unbind_slave(struct slave *slave)
ad_agg_selection_logic(__get_first_agg(port));
}
} else {
printk(KERN_WARNING DRV_NAME ": Warning: unbinding aggregator, "
"and could not find a new aggregator for its ports\n");
printk(KERN_WARNING DRV_NAME ": %s: Warning: unbinding aggregator, "
"and could not find a new aggregator for its ports\n",
slave->dev->master->name);
}
} else { // in case that the only port related to this aggregator is the one we want to remove
select_new_active_agg = aggregator->is_active;
// clear the aggregator
ad_clear_agg(aggregator);
if (select_new_active_agg) {
printk(KERN_INFO "Removing an active aggregator\n");
printk(KERN_INFO DRV_NAME ": %s: Removing an active aggregator\n",
slave->dev->master->name);
// select new active aggregator
ad_agg_selection_logic(__get_first_agg(port));
}
@ -2085,7 +2062,8 @@ void bond_3ad_unbind_slave(struct slave *slave)
// clear the aggregator
ad_clear_agg(temp_aggregator);
if (select_new_active_agg) {
printk(KERN_INFO "Removing an active aggregator\n");
printk(KERN_INFO DRV_NAME ": %s: Removing an active aggregator\n",
slave->dev->master->name);
// select new active aggregator
ad_agg_selection_logic(__get_first_agg(port));
}
@ -2131,7 +2109,8 @@ void bond_3ad_state_machine_handler(struct bonding *bond)
// select the active aggregator for the bond
if ((port = __get_first_port(bond))) {
if (!port->slave) {
printk(KERN_WARNING DRV_NAME ": Warning: bond's first port is uninitialized\n");
printk(KERN_WARNING DRV_NAME ": %s: Warning: bond's first port is "
"uninitialized\n", bond->dev->name);
goto re_arm;
}
@ -2143,7 +2122,8 @@ void bond_3ad_state_machine_handler(struct bonding *bond)
// for each port run the state machines
for (port = __get_first_port(bond); port; port = __get_next_port(port)) {
if (!port->slave) {
printk(KERN_WARNING DRV_NAME ": Warning: Found an uninitialized port\n");
printk(KERN_WARNING DRV_NAME ": %s: Warning: Found an uninitialized "
"port\n", bond->dev->name);
goto re_arm;
}
@ -2184,7 +2164,8 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u
port = &(SLAVE_AD_INFO(slave).port);
if (!port->slave) {
printk(KERN_WARNING DRV_NAME ": Warning: port of slave %s is uninitialized\n", slave->dev->name);
printk(KERN_WARNING DRV_NAME ": %s: Warning: port of slave %s is "
"uninitialized\n", slave->dev->name, slave->dev->master->name);
return;
}
@ -2230,8 +2211,9 @@ void bond_3ad_adapter_speed_changed(struct slave *slave)
// if slave is null, the whole port is not initialized
if (!port->slave) {
printk(KERN_WARNING DRV_NAME ": Warning: speed changed for uninitialized port on %s\n",
slave->dev->name);
printk(KERN_WARNING DRV_NAME ": Warning: %s: speed "
"changed for uninitialized port on %s\n",
slave->dev->master->name, slave->dev->name);
return;
}
@ -2257,8 +2239,9 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave)
// if slave is null, the whole port is not initialized
if (!port->slave) {
printk(KERN_WARNING DRV_NAME ": Warning: duplex changed for uninitialized port on %s\n",
slave->dev->name);
printk(KERN_WARNING DRV_NAME ": %s: Warning: duplex changed "
"for uninitialized port on %s\n",
slave->dev->master->name, slave->dev->name);
return;
}
@ -2285,8 +2268,9 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
// if slave is null, the whole port is not initialized
if (!port->slave) {
printk(KERN_WARNING DRV_NAME ": Warning: link status changed for uninitialized port on %s\n",
slave->dev->name);
printk(KERN_WARNING DRV_NAME ": Warning: %s: link status changed for "
"uninitialized port on %s\n",
slave->dev->master->name, slave->dev->name);
return;
}
@ -2363,7 +2347,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
}
if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
printk(KERN_DEBUG "ERROR: bond_3ad_get_active_agg_info failed\n");
printk(KERN_DEBUG DRV_NAME ": %s: Error: "
"bond_3ad_get_active_agg_info failed\n", dev->name);
goto out;
}
@ -2372,7 +2357,9 @@ 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");
printk(KERN_DEBUG DRV_NAME ": %s: Error: active "
"aggregator is empty\n",
dev->name);
goto out;
}
@ -2390,7 +2377,8 @@ 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);
printk(KERN_ERR DRV_NAME ": %s: Error: Couldn't find a slave to tx on "
"for aggregator ID %d\n", dev->name, agg_id);
goto out;
}

View file

@ -18,19 +18,6 @@
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
*
* Changes:
*
* 2003/05/01 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and
* Amir Noam <amir.noam at intel dot com>
* - Added support for lacp_rate module param.
*
* 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com>
* - Renamed bond_3ad_link_status_changed() to
* bond_3ad_handle_link_change() for compatibility with TLB.
*
* 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
* - Code cleanup and style changes
*/
#ifndef __BOND_3AD_H__

View file

@ -18,25 +18,6 @@
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
*
* Changes:
*
* 2003/06/25 - Shmulik Hen <shmulik.hen at intel dot com>
* - Fixed signed/unsigned calculation errors that caused load sharing
* to collapse to one slave under very heavy UDP Tx stress.
*
* 2003/08/06 - Amir Noam <amir.noam at intel dot com>
* - Add support for setting bond's MAC address with special
* handling required for ALB/TLB.
*
* 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
* - Code cleanup and style changes
*
* 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
@ -198,20 +179,21 @@ static int tlb_initialize(struct bonding *bond)
{
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
int size = TLB_HASH_TABLE_SIZE * sizeof(struct tlb_client_info);
struct tlb_client_info *new_hashtbl;
int i;
spin_lock_init(&(bond_info->tx_hashtbl_lock));
_lock_tx_hashtbl(bond);
bond_info->tx_hashtbl = kmalloc(size, GFP_KERNEL);
if (!bond_info->tx_hashtbl) {
new_hashtbl = kmalloc(size, GFP_KERNEL);
if (!new_hashtbl) {
printk(KERN_ERR DRV_NAME
": Error: %s: Failed to allocate TLB hash table\n",
": %s: Error: Failed to allocate TLB hash table\n",
bond->dev->name);
_unlock_tx_hashtbl(bond);
return -1;
}
_lock_tx_hashtbl(bond);
bond_info->tx_hashtbl = new_hashtbl;
memset(bond_info->tx_hashtbl, 0, size);
@ -513,7 +495,8 @@ static void rlb_update_client(struct rlb_client_info *client_info)
client_info->mac_dst);
if (!skb) {
printk(KERN_ERR DRV_NAME
": Error: failed to create an ARP packet\n");
": %s: Error: failed to create an ARP packet\n",
client_info->slave->dev->master->name);
continue;
}
@ -523,7 +506,8 @@ static void rlb_update_client(struct rlb_client_info *client_info)
skb = vlan_put_tag(skb, client_info->vlan_id);
if (!skb) {
printk(KERN_ERR DRV_NAME
": Error: failed to insert VLAN tag\n");
": %s: Error: failed to insert VLAN tag\n",
client_info->slave->dev->master->name);
continue;
}
}
@ -606,8 +590,9 @@ static void rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip)
if (!client_info->slave) {
printk(KERN_ERR DRV_NAME
": Error: found a client with no channel in "
"the client's hash table\n");
": %s: Error: found a client with no channel in "
"the client's hash table\n",
bond->dev->name);
continue;
}
/*update all clients using this src_ip, that are not assigned
@ -797,21 +782,22 @@ static int rlb_initialize(struct bonding *bond)
{
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct packet_type *pk_type = &(BOND_ALB_INFO(bond).rlb_pkt_type);
struct rlb_client_info *new_hashtbl;
int size = RLB_HASH_TABLE_SIZE * sizeof(struct rlb_client_info);
int i;
spin_lock_init(&(bond_info->rx_hashtbl_lock));
_lock_rx_hashtbl(bond);
bond_info->rx_hashtbl = kmalloc(size, GFP_KERNEL);
if (!bond_info->rx_hashtbl) {
new_hashtbl = kmalloc(size, GFP_KERNEL);
if (!new_hashtbl) {
printk(KERN_ERR DRV_NAME
": Error: %s: Failed to allocate RLB hash table\n",
": %s: Error: Failed to allocate RLB hash table\n",
bond->dev->name);
_unlock_rx_hashtbl(bond);
return -1;
}
_lock_rx_hashtbl(bond);
bond_info->rx_hashtbl = new_hashtbl;
bond_info->rx_hashtbl_head = RLB_NULL_INDEX;
@ -927,7 +913,8 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
skb = vlan_put_tag(skb, vlan->vlan_id);
if (!skb) {
printk(KERN_ERR DRV_NAME
": Error: failed to insert VLAN tag\n");
": %s: Error: failed to insert VLAN tag\n",
bond->dev->name);
continue;
}
}
@ -956,11 +943,11 @@ static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw)
s_addr.sa_family = dev->type;
if (dev_set_mac_address(dev, &s_addr)) {
printk(KERN_ERR DRV_NAME
": Error: dev_set_mac_address of dev %s failed! ALB "
": %s: Error: dev_set_mac_address of dev %s failed! ALB "
"mode requires that the base driver support setting "
"the hw address also when the network device's "
"interface is open\n",
dev->name);
dev->master->name, dev->name);
return -EOPNOTSUPP;
}
return 0;
@ -1153,16 +1140,16 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
bond->alb_info.rlb_enabled);
printk(KERN_WARNING DRV_NAME
": Warning: the hw address of slave %s is in use by "
": %s: Warning: the hw address of slave %s is in use by "
"the bond; giving it the hw address of %s\n",
slave->dev->name, free_mac_slave->dev->name);
bond->dev->name, slave->dev->name, free_mac_slave->dev->name);
} else if (has_bond_addr) {
printk(KERN_ERR DRV_NAME
": Error: the hw address of slave %s is in use by the "
": %s: Error: the hw address of slave %s is in use by the "
"bond; couldn't find a slave with a free hw address to "
"give it (this should not have happened)\n",
slave->dev->name);
bond->dev->name, slave->dev->name);
return -EFAULT;
}
@ -1250,6 +1237,8 @@ int bond_alb_initialize(struct bonding *bond, int rlb_enabled)
tlb_deinitialize(bond);
return res;
}
} else {
bond->alb_info.rlb_enabled = 0;
}
return 0;
@ -1409,7 +1398,7 @@ void bond_alb_monitor(struct bonding *bond)
read_lock(&bond->curr_slave_lock);
bond_for_each_slave(bond, slave, i) {
alb_send_learning_packets(slave,slave->dev->dev_addr);
alb_send_learning_packets(slave, slave->dev->dev_addr);
}
read_unlock(&bond->curr_slave_lock);

View file

@ -18,15 +18,6 @@
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
*
* Changes:
*
* 2003/08/06 - Amir Noam <amir.noam at intel dot com>
* - Add support for setting bond's MAC address with special
* handling required for ALB/TLB.
*
* 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
* - Code cleanup and style changes
*/
#ifndef __BOND_ALB_H__

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -10,25 +10,6 @@
* This software may be used and distributed according to the terms
* of the GNU Public License, incorporated herein by reference.
*
*
* 2003/03/18 - Amir Noam <amir.noam at intel dot com>,
* Tsippy Mendelson <tsippy.mendelson at intel dot com> and
* Shmulik Hen <shmulik.hen at intel dot com>
* - Added support for IEEE 802.3ad Dynamic link aggregation mode.
*
* 2003/05/01 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and
* Amir Noam <amir.noam at intel dot com>
* - Code beautification and style changes (mainly in comments).
*
* 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com>
* - Added support for Transmit load balancing mode.
*
* 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
* - Code cleanup and style changes
*
* 2005/05/05 - Jason Gabler <jygabler at lbl dot gov>
* - added "xmit_policy" kernel parameter for alternate hashing policy
* support for mode 2
*/
#ifndef _LINUX_BONDING_H
@ -37,11 +18,12 @@
#include <linux/timer.h>
#include <linux/proc_fs.h>
#include <linux/if_bonding.h>
#include <linux/kobject.h>
#include "bond_3ad.h"
#include "bond_alb.h"
#define DRV_VERSION "2.6.5"
#define DRV_RELDATE "November 4, 2005"
#define DRV_VERSION "3.0.0"
#define DRV_RELDATE "November 8, 2005"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
@ -152,6 +134,11 @@ struct bond_params {
u32 arp_targets[BOND_MAX_ARP_TARGETS];
};
struct bond_parm_tbl {
char *modename;
int mode;
};
struct vlan_entry {
struct list_head vlan_list;
u32 vlan_ip;
@ -159,7 +146,7 @@ struct vlan_entry {
};
struct slave {
struct net_device *dev; /* first - usefull for panic debug */
struct net_device *dev; /* first - useful for panic debug */
struct slave *next;
struct slave *prev;
s16 delay;
@ -185,7 +172,7 @@ struct slave {
* beforehand.
*/
struct bonding {
struct net_device *dev; /* first - usefull for panic debug */
struct net_device *dev; /* first - useful for panic debug */
struct slave *first_slave;
struct slave *curr_active_slave;
struct slave *current_arp_slave;
@ -255,6 +242,25 @@ extern inline void bond_set_slave_active_flags(struct slave *slave)
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);
int bond_create(char *name, struct bond_params *params, struct bonding **newbond);
void bond_deinit(struct net_device *bond_dev);
int bond_create_sysfs(void);
void bond_destroy_sysfs(void);
void bond_destroy_sysfs_entry(struct bonding *bond);
int bond_create_sysfs_entry(struct bonding *bond);
int bond_create_slave_symlinks(struct net_device *master, struct net_device *slave);
void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *slave);
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev);
int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev);
void bond_mii_monitor(struct net_device *bond_dev);
void bond_loadbalance_arp_mon(struct net_device *bond_dev);
void bond_activebackup_arp_mon(struct net_device *bond_dev);
void bond_set_mode_ops(struct bonding *bond, int mode);
int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl);
const char *bond_mode_name(int mode);
void bond_select_active_slave(struct bonding *bond);
void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
#endif /* _LINUX_BONDING_H */

View file

@ -1332,8 +1332,8 @@ intr_handler_t t1_select_intr_handler(adapter_t *adapter)
*
* This runs with softirqs disabled.
*/
unsigned int t1_sge_tx(struct sk_buff *skb, struct adapter *adapter,
unsigned int qid, struct net_device *dev)
static int t1_sge_tx(struct sk_buff *skb, struct adapter *adapter,
unsigned int qid, struct net_device *dev)
{
struct sge *sge = adapter->sge;
struct cmdQ *q = &sge->cmdQ[qid];
@ -1352,9 +1352,10 @@ unsigned int t1_sge_tx(struct sk_buff *skb, struct adapter *adapter,
set_bit(dev->if_port, &sge->stopped_tx_queues);
sge->stats.cmdQ_full[3]++;
spin_unlock(&q->lock);
CH_ERR("%s: Tx ring full while queue awake!\n",
adapter->name);
return 1;
if (!netif_queue_stopped(dev))
CH_ERR("%s: Tx ring full while queue awake!\n",
adapter->name);
return NETDEV_TX_BUSY;
}
if (unlikely(credits - count < q->stop_thres)) {
sge->stats.cmdQ_full[3]++;
@ -1389,7 +1390,7 @@ unsigned int t1_sge_tx(struct sk_buff *skb, struct adapter *adapter,
writel(F_CMDQ0_ENABLE, adapter->regs + A_SG_DOORBELL);
}
}
return 0;
return NETDEV_TX_OK;
}
#define MK_ETH_TYPE_MSS(type, mss) (((mss) & 0x3FFF) | ((type) << 14))
@ -1449,7 +1450,7 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(skb->len < ETH_HLEN ||
skb->len > dev->mtu + eth_hdr_len(skb->data))) {
dev_kfree_skb_any(skb);
return NET_XMIT_SUCCESS;
return NETDEV_TX_OK;
}
/*
@ -1467,7 +1468,7 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb = skb_realloc_headroom(skb, sizeof(*cpl));
dev_kfree_skb_any(orig_skb);
if (!skb)
return -ENOMEM;
return NETDEV_TX_OK;
}
if (!(adapter->flags & UDP_CSUM_CAPABLE) &&
@ -1475,7 +1476,7 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb->nh.iph->protocol == IPPROTO_UDP)
if (unlikely(skb_checksum_help(skb, 0))) {
dev_kfree_skb_any(skb);
return -ENOMEM;
return NETDEV_TX_OK;
}
/* Hmmm, assuming to catch the gratious arp... and we'll use

View file

@ -89,8 +89,6 @@ int t1_sge_configure(struct sge *, struct sge_params *);
int t1_sge_set_coalesce_params(struct sge *, struct sge_params *);
void t1_sge_destroy(struct sge *);
intr_handler_t t1_select_intr_handler(adapter_t *adapter);
unsigned int t1_sge_tx(struct sk_buff *skb, struct adapter *adapter,
unsigned int qid, struct net_device *netdev);
int t1_start_xmit(struct sk_buff *skb, struct net_device *dev);
void t1_set_vlan_accel(struct adapter *adapter, int on_off);
void t1_sge_start(struct sge *);

View file

@ -188,11 +188,13 @@ struct e1000_tx_ring {
/* array of buffer information structs */
struct e1000_buffer *buffer_info;
struct e1000_buffer previous_buffer_info;
spinlock_t tx_lock;
uint16_t tdh;
uint16_t tdt;
uint64_t pkt;
boolean_t last_tx_tso;
};
struct e1000_rx_ring {

View file

@ -562,10 +562,29 @@ e1000_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
char firmware_version[32];
uint16_t eeprom_data;
strncpy(drvinfo->driver, e1000_driver_name, 32);
strncpy(drvinfo->version, e1000_driver_version, 32);
strncpy(drvinfo->fw_version, "N/A", 32);
/* EEPROM image version # is reported as firware version # for
* 8257{1|2|3} controllers */
e1000_read_eeprom(&adapter->hw, 5, 1, &eeprom_data);
switch (adapter->hw.mac_type) {
case e1000_82571:
case e1000_82572:
case e1000_82573:
sprintf(firmware_version, "%d.%d-%d",
(eeprom_data & 0xF000) >> 12,
(eeprom_data & 0x0FF0) >> 4,
eeprom_data & 0x000F);
break;
default:
sprintf(firmware_version, "n/a");
}
strncpy(drvinfo->fw_version, firmware_version, 32);
strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
drvinfo->n_stats = E1000_STATS_LEN;
drvinfo->testinfo_len = E1000_TEST_LEN;
@ -960,13 +979,21 @@ e1000_free_desc_rings(struct e1000_adapter *adapter)
}
}
if(txdr->desc)
if(txdr->desc) {
pci_free_consistent(pdev, txdr->size, txdr->desc, txdr->dma);
if(rxdr->desc)
txdr->desc = NULL;
}
if(rxdr->desc) {
pci_free_consistent(pdev, rxdr->size, rxdr->desc, rxdr->dma);
rxdr->desc = NULL;
}
kfree(txdr->buffer_info);
txdr->buffer_info = NULL;
kfree(rxdr->buffer_info);
rxdr->buffer_info = NULL;
return;
}
@ -1301,21 +1328,32 @@ static int
e1000_setup_loopback_test(struct e1000_adapter *adapter)
{
uint32_t rctl;
struct e1000_hw *hw = &adapter->hw;
if(adapter->hw.media_type == e1000_media_type_fiber ||
adapter->hw.media_type == e1000_media_type_internal_serdes) {
if(adapter->hw.mac_type == e1000_82545 ||
adapter->hw.mac_type == e1000_82546 ||
adapter->hw.mac_type == e1000_82545_rev_3 ||
adapter->hw.mac_type == e1000_82546_rev_3)
if (hw->media_type == e1000_media_type_fiber ||
hw->media_type == e1000_media_type_internal_serdes) {
switch (hw->mac_type) {
case e1000_82545:
case e1000_82546:
case e1000_82545_rev_3:
case e1000_82546_rev_3:
return e1000_set_phy_loopback(adapter);
else {
rctl = E1000_READ_REG(&adapter->hw, RCTL);
break;
case e1000_82571:
case e1000_82572:
#define E1000_SERDES_LB_ON 0x410
e1000_set_phy_loopback(adapter);
E1000_WRITE_REG(hw, SCTL, E1000_SERDES_LB_ON);
msec_delay(10);
return 0;
break;
default:
rctl = E1000_READ_REG(hw, RCTL);
rctl |= E1000_RCTL_LBM_TCVR;
E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
E1000_WRITE_REG(hw, RCTL, rctl);
return 0;
}
} else if(adapter->hw.media_type == e1000_media_type_copper)
} else if (hw->media_type == e1000_media_type_copper)
return e1000_set_phy_loopback(adapter);
return 7;
@ -1326,25 +1364,36 @@ e1000_loopback_cleanup(struct e1000_adapter *adapter)
{
uint32_t rctl;
uint16_t phy_reg;
struct e1000_hw *hw = &adapter->hw;
rctl = E1000_READ_REG(&adapter->hw, RCTL);
rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
if(adapter->hw.media_type == e1000_media_type_copper ||
((adapter->hw.media_type == e1000_media_type_fiber ||
adapter->hw.media_type == e1000_media_type_internal_serdes) &&
(adapter->hw.mac_type == e1000_82545 ||
adapter->hw.mac_type == e1000_82546 ||
adapter->hw.mac_type == e1000_82545_rev_3 ||
adapter->hw.mac_type == e1000_82546_rev_3))) {
adapter->hw.autoneg = TRUE;
e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg);
if(phy_reg & MII_CR_LOOPBACK) {
phy_reg &= ~MII_CR_LOOPBACK;
e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg);
e1000_phy_reset(&adapter->hw);
switch (hw->mac_type) {
case e1000_82571:
case e1000_82572:
if (hw->media_type == e1000_media_type_fiber ||
hw->media_type == e1000_media_type_internal_serdes){
#define E1000_SERDES_LB_OFF 0x400
E1000_WRITE_REG(hw, SCTL, E1000_SERDES_LB_OFF);
msec_delay(10);
break;
}
/* fall thru for Cu adapters */
case e1000_82545:
case e1000_82546:
case e1000_82545_rev_3:
case e1000_82546_rev_3:
default:
hw->autoneg = TRUE;
e1000_read_phy_reg(hw, PHY_CTRL, &phy_reg);
if (phy_reg & MII_CR_LOOPBACK) {
phy_reg &= ~MII_CR_LOOPBACK;
e1000_write_phy_reg(hw, PHY_CTRL, phy_reg);
e1000_phy_reset(hw);
}
break;
}
}
@ -1440,9 +1489,11 @@ static int
e1000_loopback_test(struct e1000_adapter *adapter, uint64_t *data)
{
if((*data = e1000_setup_desc_rings(adapter))) goto err_loopback;
if((*data = e1000_setup_loopback_test(adapter))) goto err_loopback;
if((*data = e1000_setup_loopback_test(adapter)))
goto err_loopback_setup;
*data = e1000_run_loopback_test(adapter);
e1000_loopback_cleanup(adapter);
err_loopback_setup:
e1000_free_desc_rings(adapter);
err_loopback:
return *data;
@ -1671,6 +1722,14 @@ e1000_phys_id(struct net_device *netdev, uint32_t data)
msleep_interruptible(data * 1000);
del_timer_sync(&adapter->blink_timer);
}
else if(adapter->hw.mac_type < e1000_82573) {
E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE |
E1000_LEDCTL_LED0_BLINK | E1000_LEDCTL_LED2_BLINK |
(E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) |
(E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED0_MODE_SHIFT) |
(E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED1_MODE_SHIFT)));
msleep_interruptible(data * 1000);
}
else {
E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE |
E1000_LEDCTL_LED1_BLINK | E1000_LEDCTL_LED2_BLINK |

View file

@ -563,11 +563,13 @@ e1000_reset_hw(struct e1000_hw *hw)
msec_delay(20);
break;
case e1000_82573:
udelay(10);
ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
ctrl_ext |= E1000_CTRL_EXT_EE_RST;
E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
E1000_WRITE_FLUSH(hw);
if (e1000_is_onboard_nvm_eeprom(hw) == FALSE) {
udelay(10);
ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
ctrl_ext |= E1000_CTRL_EXT_EE_RST;
E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
E1000_WRITE_FLUSH(hw);
}
/* fall through */
case e1000_82571:
case e1000_82572:
@ -844,19 +846,27 @@ e1000_setup_link(struct e1000_hw *hw)
* control setting, then the variable hw->fc will
* be initialized based on a value in the EEPROM.
*/
if(e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data)) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
if(hw->fc == e1000_fc_default) {
if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
hw->fc = e1000_fc_none;
else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) ==
EEPROM_WORD0F_ASM_DIR)
hw->fc = e1000_fc_tx_pause;
else
if (hw->fc == e1000_fc_default) {
switch (hw->mac_type) {
case e1000_82573:
hw->fc = e1000_fc_full;
break;
default:
ret_val = e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG,
1, &eeprom_data);
if (ret_val) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
hw->fc = e1000_fc_none;
else if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) ==
EEPROM_WORD0F_ASM_DIR)
hw->fc = e1000_fc_tx_pause;
else
hw->fc = e1000_fc_full;
break;
}
}
/* We want to save off the original Flow Control configuration just
@ -2962,13 +2972,22 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
if(hw->mac_type > e1000_82543) {
/* Read the device control register and assert the E1000_CTRL_PHY_RST
* bit. Then, take it out of reset.
* For pre-e1000_82571 hardware, we delay for 10ms between the assert
* and deassert. For e1000_82571 hardware and later, we instead delay
* for 10ms after the deassertion.
*/
ctrl = E1000_READ_REG(hw, CTRL);
E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST);
E1000_WRITE_FLUSH(hw);
msec_delay(10);
if (hw->mac_type < e1000_82571)
msec_delay(10);
E1000_WRITE_REG(hw, CTRL, ctrl);
E1000_WRITE_FLUSH(hw);
if (hw->mac_type >= e1000_82571)
msec_delay(10);
} else {
/* Read the Extended Device Control Register, assert the PHY_RESET_DIR
* bit to put the PHY into reset. Then, take it out of reset.
@ -5278,9 +5297,13 @@ e1000_get_bus_info(struct e1000_hw *hw)
hw->bus_speed = e1000_bus_speed_unknown;
hw->bus_width = e1000_bus_width_unknown;
break;
case e1000_82571:
case e1000_82572:
case e1000_82573:
hw->bus_type = e1000_bus_type_pci_express;
hw->bus_speed = e1000_bus_speed_2500;
hw->bus_width = e1000_bus_width_pciex_1;
break;
case e1000_82571:
hw->bus_type = e1000_bus_type_pci_express;
hw->bus_speed = e1000_bus_speed_2500;
hw->bus_width = e1000_bus_width_pciex_4;
@ -6650,6 +6673,12 @@ e1000_get_auto_rd_done(struct e1000_hw *hw)
break;
}
/* PHY configuration from NVM just starts after EECD_AUTO_RD sets to high.
* Need to wait for PHY configuration completion before accessing NVM
* and PHY. */
if (hw->mac_type == e1000_82573)
msec_delay(25);
return E1000_SUCCESS;
}

View file

@ -123,6 +123,7 @@ typedef enum {
e1000_bus_width_32,
e1000_bus_width_64,
e1000_bus_width_pciex_1,
e1000_bus_width_pciex_2,
e1000_bus_width_pciex_4,
e1000_bus_width_reserved
} e1000_bus_width;
@ -149,6 +150,7 @@ typedef enum {
e1000_igp_cable_length_90 = 90,
e1000_igp_cable_length_100 = 100,
e1000_igp_cable_length_110 = 110,
e1000_igp_cable_length_115 = 115,
e1000_igp_cable_length_120 = 120,
e1000_igp_cable_length_130 = 130,
e1000_igp_cable_length_140 = 140,
@ -1457,6 +1459,7 @@ struct e1000_hw {
#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */
#define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */
#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */
#define E1000_EECD_SECVAL_SHIFT 22
#define E1000_STM_OPCODE 0xDB00
#define E1000_HICR_FW_RESET 0xC0
@ -1951,7 +1954,6 @@ struct e1000_host_command_info {
#define E1000_MDALIGN 4096
#define E1000_GCR_BEM32 0x00400000
#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
/* Function Active and Power State to MNG */
#define E1000_FACTPS_FUNC0_POWER_STATE_MASK 0x00000003

View file

@ -711,6 +711,7 @@ e1000_probe(struct pci_dev *pdev,
break;
case e1000_82546:
case e1000_82546_rev_3:
case e1000_82571:
if((E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_FUNC_1)
&& (adapter->hw.media_type == e1000_media_type_copper)) {
e1000_read_eeprom(&adapter->hw,
@ -1158,7 +1159,6 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter,
return -ENOMEM;
}
memset(txdr->buffer_info, 0, size);
memset(&txdr->previous_buffer_info, 0, sizeof(struct e1000_buffer));
/* round up to nearest 4K */
@ -1813,11 +1813,6 @@ e1000_clean_tx_ring(struct e1000_adapter *adapter,
/* Free all the Tx ring sk_buffs */
if (likely(tx_ring->previous_buffer_info.skb != NULL)) {
e1000_unmap_and_free_tx_resource(adapter,
&tx_ring->previous_buffer_info);
}
for(i = 0; i < tx_ring->count; i++) {
buffer_info = &tx_ring->buffer_info[i];
e1000_unmap_and_free_tx_resource(adapter, buffer_info);
@ -1832,6 +1827,7 @@ e1000_clean_tx_ring(struct e1000_adapter *adapter,
tx_ring->next_to_use = 0;
tx_ring->next_to_clean = 0;
tx_ring->last_tx_tso = 0;
writel(0, adapter->hw.hw_addr + tx_ring->tdh);
writel(0, adapter->hw.hw_addr + tx_ring->tdt);
@ -2437,6 +2433,16 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
buffer_info = &tx_ring->buffer_info[i];
size = min(len, max_per_txd);
#ifdef NETIF_F_TSO
/* Workaround for Controller erratum --
* descriptor for non-tso packet in a linear SKB that follows a
* tso gets written back prematurely before the data is fully
* DMAd to the controller */
if (!skb->data_len && tx_ring->last_tx_tso &&
!skb_shinfo(skb)->tso_size) {
tx_ring->last_tx_tso = 0;
size -= 4;
}
/* Workaround for premature desc write-backs
* in TSO mode. Append 4-byte sentinel desc */
if(unlikely(mss && !nr_frags && size == len && size > 8))
@ -2693,6 +2699,14 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if(skb->ip_summed == CHECKSUM_HW)
count++;
#endif
#ifdef NETIF_F_TSO
/* Controller Erratum workaround */
if (!skb->data_len && tx_ring->last_tx_tso &&
!skb_shinfo(skb)->tso_size)
count++;
#endif
count += TXD_USE_COUNT(len, max_txd_pwr);
if(adapter->pcix_82544)
@ -2774,9 +2788,10 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
return NETDEV_TX_OK;
}
if (likely(tso))
if (likely(tso)) {
tx_ring->last_tx_tso = 1;
tx_flags |= E1000_TX_FLAGS_TSO;
else if (likely(e1000_tx_csum(adapter, tx_ring, skb)))
} else if (likely(e1000_tx_csum(adapter, tx_ring, skb)))
tx_flags |= E1000_TX_FLAGS_CSUM;
/* Old method was to assume IPv4 packet by default if TSO was enabled.
@ -3227,37 +3242,12 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
eop_desc = E1000_TX_DESC(*tx_ring, eop);
while (eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
/* Premature writeback of Tx descriptors clear (free buffers
* and unmap pci_mapping) previous_buffer_info */
if (likely(tx_ring->previous_buffer_info.skb != NULL)) {
e1000_unmap_and_free_tx_resource(adapter,
&tx_ring->previous_buffer_info);
}
for(cleaned = FALSE; !cleaned; ) {
tx_desc = E1000_TX_DESC(*tx_ring, i);
buffer_info = &tx_ring->buffer_info[i];
cleaned = (i == eop);
#ifdef NETIF_F_TSO
if (!(netdev->features & NETIF_F_TSO)) {
#endif
e1000_unmap_and_free_tx_resource(adapter,
buffer_info);
#ifdef NETIF_F_TSO
} else {
if (cleaned) {
memcpy(&tx_ring->previous_buffer_info,
buffer_info,
sizeof(struct e1000_buffer));
memset(buffer_info, 0,
sizeof(struct e1000_buffer));
} else {
e1000_unmap_and_free_tx_resource(
adapter, buffer_info);
}
}
#endif
e1000_unmap_and_free_tx_resource(adapter, buffer_info);
tx_desc->buffer_addr = 0;
tx_desc->lower.data = 0;
@ -3318,12 +3308,6 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
netif_stop_queue(netdev);
}
}
#ifdef NETIF_F_TSO
if (unlikely(!(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) &&
time_after(jiffies, tx_ring->previous_buffer_info.time_stamp + HZ)))
e1000_unmap_and_free_tx_resource(
adapter, &tx_ring->previous_buffer_info);
#endif
return cleaned;
}

View file

@ -2,7 +2,8 @@
* drivers/net/gianfar.c
*
* Gianfar Ethernet Driver
* Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560
* This driver is designed for the non-CPM ethernet controllers
* on the 85xx and 83xx family of integrated processors
* Based on 8260_io/fcc_enet.c
*
* Author: Andy Fleming
@ -22,8 +23,6 @@
* B-V +1.62
*
* Theory of operation
* This driver is designed for the non-CPM ethernet controllers
* on the 85xx and 83xx family of integrated processors
*
* The driver is initialized through platform_device. Structures which
* define the configuration needed by the board are defined in a
@ -110,7 +109,7 @@
#endif
const char gfar_driver_name[] = "Gianfar Ethernet";
const char gfar_driver_version[] = "1.2";
const char gfar_driver_version[] = "1.3";
static int gfar_enet_open(struct net_device *dev);
static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev);
@ -139,6 +138,10 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int l
static void gfar_vlan_rx_register(struct net_device *netdev,
struct vlan_group *grp);
static void gfar_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
void gfar_halt(struct net_device *dev);
void gfar_start(struct net_device *dev);
static void gfar_clear_exact_match(struct net_device *dev);
static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr);
extern struct ethtool_ops gfar_ethtool_ops;
@ -146,12 +149,10 @@ MODULE_AUTHOR("Freescale Semiconductor, Inc");
MODULE_DESCRIPTION("Gianfar Ethernet Driver");
MODULE_LICENSE("GPL");
int gfar_uses_fcb(struct gfar_private *priv)
/* Returns 1 if incoming frames use an FCB */
static inline int gfar_uses_fcb(struct gfar_private *priv)
{
if (priv->vlan_enable || priv->rx_csum_enable)
return 1;
else
return 0;
return (priv->vlan_enable || priv->rx_csum_enable);
}
/* Set up the ethernet device structure, private data,
@ -320,15 +321,10 @@ static int gfar_probe(struct platform_device *pdev)
else
priv->padding = 0;
dev->hard_header_len += priv->padding;
if (dev->features & NETIF_F_IP_CSUM)
dev->hard_header_len += GMAC_FCB_LEN;
priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE;
#ifdef CONFIG_GFAR_BUFSTASH
priv->rx_stash_size = STASH_LENGTH;
#endif
priv->tx_ring_size = DEFAULT_TX_RING_SIZE;
priv->rx_ring_size = DEFAULT_RX_RING_SIZE;
@ -350,6 +346,9 @@ static int gfar_probe(struct platform_device *pdev)
goto register_fail;
}
/* Create all the sysfs files */
gfar_init_sysfs(dev);
/* Print out the device info */
printk(KERN_INFO DEVICE_NAME, dev->name);
for (idx = 0; idx < 6; idx++)
@ -357,8 +356,7 @@ static int gfar_probe(struct platform_device *pdev)
printk("\n");
/* Even more device info helps when determining which kernel */
/* provided which set of benchmarks. Since this is global for all */
/* devices, we only print it once */
/* provided which set of benchmarks. */
#ifdef CONFIG_GFAR_NAPI
printk(KERN_INFO "%s: Running with NAPI enabled\n", dev->name);
#else
@ -463,19 +461,9 @@ static void init_registers(struct net_device *dev)
/* Initialize the max receive buffer length */
gfar_write(&priv->regs->mrblr, priv->rx_buffer_size);
#ifdef CONFIG_GFAR_BUFSTASH
/* If we are stashing buffers, we need to set the
* extraction length to the size of the buffer */
gfar_write(&priv->regs->attreli, priv->rx_stash_size << 16);
#endif
/* Initialize the Minimum Frame Length Register */
gfar_write(&priv->regs->minflr, MINFLR_INIT_SETTINGS);
/* Setup Attributes so that snooping is on for rx */
gfar_write(&priv->regs->attr, ATTR_INIT_SETTINGS);
gfar_write(&priv->regs->attreli, ATTRELI_INIT_SETTINGS);
/* Assign the TBI an address which won't conflict with the PHYs */
gfar_write(&priv->regs->tbipa, TBIPA_VALUE);
}
@ -577,8 +565,7 @@ static void free_skb_resources(struct gfar_private *priv)
for (i = 0; i < priv->rx_ring_size; i++) {
if (priv->rx_skbuff[i]) {
dma_unmap_single(NULL, rxbdp->bufPtr,
priv->rx_buffer_size
+ RXBUF_ALIGNMENT,
priv->rx_buffer_size,
DMA_FROM_DEVICE);
dev_kfree_skb_any(priv->rx_skbuff[i]);
@ -636,6 +623,7 @@ int startup_gfar(struct net_device *dev)
struct gfar *regs = priv->regs;
int err = 0;
u32 rctrl = 0;
u32 attrs = 0;
gfar_write(&regs->imask, IMASK_INIT_CLEAR);
@ -795,18 +783,50 @@ int startup_gfar(struct net_device *dev)
if (priv->rx_csum_enable)
rctrl |= RCTRL_CHECKSUMMING;
if (priv->extended_hash)
if (priv->extended_hash) {
rctrl |= RCTRL_EXTHASH;
gfar_clear_exact_match(dev);
rctrl |= RCTRL_EMEN;
}
if (priv->vlan_enable)
rctrl |= RCTRL_VLAN;
if (priv->padding) {
rctrl &= ~RCTRL_PAL_MASK;
rctrl |= RCTRL_PADDING(priv->padding);
}
/* Init rctrl based on our settings */
gfar_write(&priv->regs->rctrl, rctrl);
if (dev->features & NETIF_F_IP_CSUM)
gfar_write(&priv->regs->tctrl, TCTRL_INIT_CSUM);
/* Set the extraction length and index */
attrs = ATTRELI_EL(priv->rx_stash_size) |
ATTRELI_EI(priv->rx_stash_index);
gfar_write(&priv->regs->attreli, attrs);
/* Start with defaults, and add stashing or locking
* depending on the approprate variables */
attrs = ATTR_INIT_SETTINGS;
if (priv->bd_stash_en)
attrs |= ATTR_BDSTASH;
if (priv->rx_stash_size != 0)
attrs |= ATTR_BUFSTASH;
gfar_write(&priv->regs->attr, attrs);
gfar_write(&priv->regs->fifo_tx_thr, priv->fifo_threshold);
gfar_write(&priv->regs->fifo_tx_starve, priv->fifo_starve);
gfar_write(&priv->regs->fifo_tx_starve_shutoff, priv->fifo_starve_off);
/* Start the controller */
gfar_start(dev);
return 0;
@ -851,34 +871,32 @@ static int gfar_enet_open(struct net_device *dev)
return err;
}
static struct txfcb *gfar_add_fcb(struct sk_buff *skb, struct txbd8 *bdp)
static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb, struct txbd8 *bdp)
{
struct txfcb *fcb = (struct txfcb *)skb_push (skb, GMAC_FCB_LEN);
memset(fcb, 0, GMAC_FCB_LEN);
/* Flag the bd so the controller looks for the FCB */
bdp->status |= TXBD_TOE;
return fcb;
}
static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
{
int len;
u8 flags = 0;
/* If we're here, it's a IP packet with a TCP or UDP
* payload. We set it to checksum, using a pseudo-header
* we provide
*/
fcb->ip = 1;
fcb->tup = 1;
fcb->ctu = 1;
fcb->nph = 1;
flags = TXFCB_DEFAULT;
/* Notify the controller what the protocol is */
if (skb->nh.iph->protocol == IPPROTO_UDP)
fcb->udp = 1;
/* Tell the controller what the protocol is */
/* And provide the already calculated phcs */
if (skb->nh.iph->protocol == IPPROTO_UDP) {
flags |= TXFCB_UDP;
fcb->phcs = skb->h.uh->check;
} else
fcb->phcs = skb->h.th->check;
/* l3os is the distance between the start of the
* frame (skb->data) and the start of the IP hdr.
@ -887,17 +905,12 @@ static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
fcb->l3os = (u16)(skb->nh.raw - skb->data - GMAC_FCB_LEN);
fcb->l4os = (u16)(skb->h.raw - skb->nh.raw);
len = skb->nh.iph->tot_len - fcb->l4os;
/* Provide the pseudoheader csum */
fcb->phcs = ~csum_tcpudp_magic(skb->nh.iph->saddr,
skb->nh.iph->daddr, len,
skb->nh.iph->protocol, 0);
fcb->flags = flags;
}
void gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb)
void inline gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb)
{
fcb->vln = 1;
fcb->flags |= TXFCB_VLN;
fcb->vlctl = vlan_tx_tag_get(skb);
}
@ -908,6 +921,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct gfar_private *priv = netdev_priv(dev);
struct txfcb *fcb = NULL;
struct txbd8 *txbdp;
u16 status;
/* Update transmit stats */
priv->stats.tx_bytes += skb->len;
@ -919,19 +933,22 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
txbdp = priv->cur_tx;
/* Clear all but the WRAP status flags */
txbdp->status &= TXBD_WRAP;
status = txbdp->status & TXBD_WRAP;
/* Set up checksumming */
if ((dev->features & NETIF_F_IP_CSUM)
&& (CHECKSUM_HW == skb->ip_summed)) {
if (likely((dev->features & NETIF_F_IP_CSUM)
&& (CHECKSUM_HW == skb->ip_summed))) {
fcb = gfar_add_fcb(skb, txbdp);
status |= TXBD_TOE;
gfar_tx_checksum(skb, fcb);
}
if (priv->vlan_enable &&
unlikely(priv->vlgrp && vlan_tx_tag_present(skb))) {
if (NULL == fcb)
if (unlikely(NULL == fcb)) {
fcb = gfar_add_fcb(skb, txbdp);
status |= TXBD_TOE;
}
gfar_tx_vlan(skb, fcb);
}
@ -949,14 +966,16 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
(priv->skb_curtx + 1) & TX_RING_MOD_MASK(priv->tx_ring_size);
/* Flag the BD as interrupt-causing */
txbdp->status |= TXBD_INTERRUPT;
status |= TXBD_INTERRUPT;
/* Flag the BD as ready to go, last in frame, and */
/* in need of CRC */
txbdp->status |= (TXBD_READY | TXBD_LAST | TXBD_CRC);
status |= (TXBD_READY | TXBD_LAST | TXBD_CRC);
dev->trans_start = jiffies;
txbdp->status = status;
/* If this was the last BD in the ring, the next one */
/* is at the beginning of the ring */
if (txbdp->status & TXBD_WRAP)
@ -1010,21 +1029,7 @@ static struct net_device_stats * gfar_get_stats(struct net_device *dev)
/* Changes the mac address if the controller is not running. */
int gfar_set_mac_address(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
int i;
char tmpbuf[MAC_ADDR_LEN];
u32 tempval;
/* Now copy it into the mac registers backwards, cuz */
/* little endian is silly */
for (i = 0; i < MAC_ADDR_LEN; i++)
tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->dev_addr[i];
gfar_write(&priv->regs->macstnaddr1, *((u32 *) (tmpbuf)));
tempval = *((u32 *) (tmpbuf + 4));
gfar_write(&priv->regs->macstnaddr2, tempval);
gfar_set_mac_for_addr(dev, 0, dev->dev_addr);
return 0;
}
@ -1110,7 +1115,7 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
INCREMENTAL_BUFFER_SIZE;
/* Only stop and start the controller if it isn't already
* stopped */
* stopped, and we changed something */
if ((oldsize != tempsize) && (dev->flags & IFF_UP))
stop_gfar(dev);
@ -1220,6 +1225,7 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs)
struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
{
unsigned int alignamount;
struct gfar_private *priv = netdev_priv(dev);
struct sk_buff *skb = NULL;
unsigned int timeout = SKB_ALLOC_TIMEOUT;
@ -1231,18 +1237,18 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
if (NULL == skb)
return NULL;
alignamount = RXBUF_ALIGNMENT -
(((unsigned) skb->data) & (RXBUF_ALIGNMENT - 1));
/* We need the data buffer to be aligned properly. We will reserve
* as many bytes as needed to align the data properly
*/
skb_reserve(skb,
RXBUF_ALIGNMENT -
(((unsigned) skb->data) & (RXBUF_ALIGNMENT - 1)));
skb_reserve(skb, alignamount);
skb->dev = dev;
bdp->bufPtr = dma_map_single(NULL, skb->data,
priv->rx_buffer_size + RXBUF_ALIGNMENT,
DMA_FROM_DEVICE);
priv->rx_buffer_size, DMA_FROM_DEVICE);
bdp->length = 0;
@ -1350,7 +1356,7 @@ static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)
/* If valid headers were found, and valid sums
* were verified, then we tell the kernel that no
* checksumming is necessary. Otherwise, it is */
if (fcb->cip && !fcb->eip && fcb->ctu && !fcb->etu)
if ((fcb->flags & RXFCB_CSUM_MASK) == (RXFCB_CIP | RXFCB_CTU))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb->ip_summed = CHECKSUM_NONE;
@ -1401,7 +1407,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
skb->protocol = eth_type_trans(skb, dev);
/* Send the packet up the stack */
if (unlikely(priv->vlgrp && fcb->vln))
if (unlikely(priv->vlgrp && (fcb->flags & RXFCB_VLN)))
ret = gfar_rx_vlan(skb, priv->vlgrp, fcb->vlctl);
else
ret = RECEIVE(skb);
@ -1620,6 +1626,7 @@ static void adjust_link(struct net_device *dev)
spin_lock_irqsave(&priv->lock, flags);
if (phydev->link) {
u32 tempval = gfar_read(&regs->maccfg2);
u32 ecntrl = gfar_read(&regs->ecntrl);
/* Now we make sure that we can be in full duplex mode.
* If not, we operate in half-duplex mode. */
@ -1644,6 +1651,13 @@ static void adjust_link(struct net_device *dev)
case 10:
tempval =
((tempval & ~(MACCFG2_IF)) | MACCFG2_MII);
/* Reduced mode distinguishes
* between 10 and 100 */
if (phydev->speed == SPEED_100)
ecntrl |= ECNTRL_R100;
else
ecntrl &= ~(ECNTRL_R100);
break;
default:
if (netif_msg_link(priv))
@ -1657,6 +1671,7 @@ static void adjust_link(struct net_device *dev)
}
gfar_write(&regs->maccfg2, tempval);
gfar_write(&regs->ecntrl, ecntrl);
if (!priv->oldlink) {
new_state = 1;
@ -1721,6 +1736,9 @@ static void gfar_set_multi(struct net_device *dev)
gfar_write(&regs->gaddr6, 0xffffffff);
gfar_write(&regs->gaddr7, 0xffffffff);
} else {
int em_num;
int idx;
/* zero out the hash */
gfar_write(&regs->igaddr0, 0x0);
gfar_write(&regs->igaddr1, 0x0);
@ -1739,18 +1757,47 @@ static void gfar_set_multi(struct net_device *dev)
gfar_write(&regs->gaddr6, 0x0);
gfar_write(&regs->gaddr7, 0x0);
/* If we have extended hash tables, we need to
* clear the exact match registers to prepare for
* setting them */
if (priv->extended_hash) {
em_num = GFAR_EM_NUM + 1;
gfar_clear_exact_match(dev);
idx = 1;
} else {
idx = 0;
em_num = 0;
}
if(dev->mc_count == 0)
return;
/* Parse the list, and set the appropriate bits */
for(mc_ptr = dev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
gfar_set_hash_for_addr(dev, mc_ptr->dmi_addr);
if (idx < em_num) {
gfar_set_mac_for_addr(dev, idx,
mc_ptr->dmi_addr);
idx++;
} else
gfar_set_hash_for_addr(dev, mc_ptr->dmi_addr);
}
}
return;
}
/* Clears each of the exact match registers to zero, so they
* don't interfere with normal reception */
static void gfar_clear_exact_match(struct net_device *dev)
{
int idx;
u8 zero_arr[MAC_ADDR_LEN] = {0,0,0,0,0,0};
for(idx = 1;idx < GFAR_EM_NUM + 1;idx++)
gfar_set_mac_for_addr(dev, idx, (u8 *)zero_arr);
}
/* Set the appropriate hash bit for the given addr */
/* The algorithm works like so:
* 1) Take the Destination Address (ie the multicast address), and
@ -1781,6 +1828,32 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr)
return;
}
/* There are multiple MAC Address register pairs on some controllers
* This function sets the numth pair to a given address
*/
static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr)
{
struct gfar_private *priv = netdev_priv(dev);
int idx;
char tmpbuf[MAC_ADDR_LEN];
u32 tempval;
u32 *macptr = &priv->regs->macstnaddr1;
macptr += num*2;
/* Now copy it into the mac registers backwards, cuz */
/* little endian is silly */
for (idx = 0; idx < MAC_ADDR_LEN; idx++)
tmpbuf[MAC_ADDR_LEN - 1 - idx] = addr[idx];
gfar_write(macptr, *((u32 *) (tmpbuf)));
tempval = *((u32 *) (tmpbuf + 4));
gfar_write(macptr+1, tempval);
}
/* GFAR error interrupt handler */
static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
{

View file

@ -90,12 +90,26 @@ extern const char gfar_driver_version[];
#define GFAR_RX_MAX_RING_SIZE 256
#define GFAR_TX_MAX_RING_SIZE 256
#define GFAR_MAX_FIFO_THRESHOLD 511
#define GFAR_MAX_FIFO_STARVE 511
#define GFAR_MAX_FIFO_STARVE_OFF 511
#define DEFAULT_RX_BUFFER_SIZE 1536
#define TX_RING_MOD_MASK(size) (size-1)
#define RX_RING_MOD_MASK(size) (size-1)
#define JUMBO_BUFFER_SIZE 9728
#define JUMBO_FRAME_SIZE 9600
#define DEFAULT_FIFO_TX_THR 0x100
#define DEFAULT_FIFO_TX_STARVE 0x40
#define DEFAULT_FIFO_TX_STARVE_OFF 0x80
#define DEFAULT_BD_STASH 1
#define DEFAULT_STASH_LENGTH 64
#define DEFAULT_STASH_INDEX 0
/* The number of Exact Match registers */
#define GFAR_EM_NUM 15
/* Latency of interface clock in nanoseconds */
/* Interface clock latency , in this case, means the
* time described by a value of 1 in the interrupt
@ -112,11 +126,11 @@ extern const char gfar_driver_version[];
#define DEFAULT_TX_COALESCE 1
#define DEFAULT_TXCOUNT 16
#define DEFAULT_TXTIME 400
#define DEFAULT_TXTIME 4
#define DEFAULT_RX_COALESCE 1
#define DEFAULT_RXCOUNT 16
#define DEFAULT_RXTIME 400
#define DEFAULT_RXTIME 4
#define TBIPA_VALUE 0x1f
#define MIIMCFG_INIT_VALUE 0x00000007
@ -147,6 +161,7 @@ extern const char gfar_driver_version[];
#define ECNTRL_INIT_SETTINGS 0x00001000
#define ECNTRL_TBI_MODE 0x00000020
#define ECNTRL_R100 0x00000008
#define MRBLR_INIT_SETTINGS DEFAULT_RX_BUFFER_SIZE
@ -181,10 +196,12 @@ extern const char gfar_driver_version[];
#define RCTRL_PRSDEP_MASK 0x000000c0
#define RCTRL_PRSDEP_INIT 0x000000c0
#define RCTRL_PROM 0x00000008
#define RCTRL_EMEN 0x00000002
#define RCTRL_CHECKSUMMING (RCTRL_IPCSEN \
| RCTRL_TUCSEN | RCTRL_PRSDEP_INIT)
#define RCTRL_EXTHASH (RCTRL_GHTX)
#define RCTRL_VLAN (RCTRL_PRSDEP_INIT)
#define RCTRL_PADDING(x) ((x << 16) & RCTRL_PAL_MASK)
#define RSTAT_CLEAR_RHALT 0x00800000
@ -251,28 +268,26 @@ extern const char gfar_driver_version[];
IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \
| IMASK_PERR)
/* Fifo management */
#define FIFO_TX_THR_MASK 0x01ff
#define FIFO_TX_STARVE_MASK 0x01ff
#define FIFO_TX_STARVE_OFF_MASK 0x01ff
/* Attribute fields */
/* This enables rx snooping for buffers and descriptors */
#ifdef CONFIG_GFAR_BDSTASH
#define ATTR_BDSTASH 0x00000800
#else
#define ATTR_BDSTASH 0x00000000
#endif
#ifdef CONFIG_GFAR_BUFSTASH
#define ATTR_BUFSTASH 0x00004000
#define STASH_LENGTH 64
#else
#define ATTR_BUFSTASH 0x00000000
#endif
#define ATTR_SNOOPING 0x000000c0
#define ATTR_INIT_SETTINGS (ATTR_SNOOPING \
| ATTR_BDSTASH | ATTR_BUFSTASH)
#define ATTR_INIT_SETTINGS ATTR_SNOOPING
#define ATTRELI_INIT_SETTINGS 0x0
#define ATTRELI_EL_MASK 0x3fff0000
#define ATTRELI_EL(x) (x << 16)
#define ATTRELI_EI_MASK 0x00003fff
#define ATTRELI_EI(x) (x)
/* TxBD status field bits */
@ -328,6 +343,7 @@ extern const char gfar_driver_version[];
#define RXFCB_CTU 0x0400
#define RXFCB_EIP 0x0200
#define RXFCB_ETU 0x0100
#define RXFCB_CSUM_MASK 0x0f00
#define RXFCB_PERR_MASK 0x000c
#define RXFCB_PERR_BADL3 0x0008
@ -339,14 +355,7 @@ struct txbd8
};
struct txfcb {
u8 vln:1,
ip:1,
ip6:1,
tup:1,
udp:1,
cip:1,
ctu:1,
nph:1;
u8 flags;
u8 reserved;
u8 l4os; /* Level 4 Header Offset */
u8 l3os; /* Level 3 Header Offset */
@ -362,14 +371,7 @@ struct rxbd8
};
struct rxfcb {
u16 vln:1,
ip:1,
ip6:1,
tup:1,
cip:1,
ctu:1,
eip:1,
etu:1;
u16 flags;
u8 rq; /* Receive Queue index */
u8 pro; /* Layer 4 Protocol */
u16 reserved;
@ -688,12 +690,17 @@ struct gfar_private {
spinlock_t lock;
unsigned int rx_buffer_size;
unsigned int rx_stash_size;
unsigned int rx_stash_index;
unsigned int tx_ring_size;
unsigned int rx_ring_size;
unsigned int fifo_threshold;
unsigned int fifo_starve;
unsigned int fifo_starve_off;
unsigned char vlan_enable:1,
rx_csum_enable:1,
extended_hash:1;
extended_hash:1,
bd_stash_en:1;
unsigned short padding;
struct vlan_group *vlgrp;
/* Info structure initialized by board setup code */
@ -731,6 +738,6 @@ extern void stop_gfar(struct net_device *dev);
extern void gfar_halt(struct net_device *dev);
extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev,
int enable, u32 regnum, u32 read);
void gfar_setup_stashing(struct net_device *dev);
void gfar_init_sysfs(struct net_device *dev);
#endif /* __GIANFAR_H */

View file

@ -125,7 +125,7 @@ static char stat_gstrings[][ETH_GSTRING_LEN] = {
static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
{
struct gfar_private *priv = netdev_priv(dev);
if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
else

View file

@ -24,6 +24,7 @@
#define MII_READ_COMMAND 0x00000001
#define GFAR_SUPPORTED (SUPPORTED_10baseT_Half \
| SUPPORTED_10baseT_Full \
| SUPPORTED_100baseT_Half \
| SUPPORTED_100baseT_Full \
| SUPPORTED_Autoneg \

311
drivers/net/gianfar_sysfs.c Normal file
View file

@ -0,0 +1,311 @@
/*
* drivers/net/gianfar_sysfs.c
*
* Gianfar Ethernet Driver
* This driver is designed for the non-CPM ethernet controllers
* on the 85xx and 83xx family of integrated processors
* Based on 8260_io/fcc_enet.c
*
* Author: Andy Fleming
* Maintainer: Kumar Gala (kumar.gala@freescale.com)
*
* Copyright (c) 2002-2005 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* Sysfs file creation and management
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <linux/module.h>
#include <linux/version.h>
#include "gianfar.h"
#define GFAR_ATTR(_name) \
static ssize_t gfar_show_##_name(struct class_device *cdev, char *buf); \
static ssize_t gfar_set_##_name(struct class_device *cdev, \
const char *buf, size_t count); \
static CLASS_DEVICE_ATTR(_name, 0644, gfar_show_##_name, gfar_set_##_name)
#define GFAR_CREATE_FILE(_dev, _name) \
class_device_create_file(&_dev->class_dev, &class_device_attr_##_name)
GFAR_ATTR(bd_stash);
GFAR_ATTR(rx_stash_size);
GFAR_ATTR(rx_stash_index);
GFAR_ATTR(fifo_threshold);
GFAR_ATTR(fifo_starve);
GFAR_ATTR(fifo_starve_off);
#define to_net_dev(cd) container_of(cd, struct net_device, class_dev)
static ssize_t gfar_show_bd_stash(struct class_device *cdev, char *buf)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
return sprintf(buf, "%s\n", priv->bd_stash_en? "on" : "off");
}
static ssize_t gfar_set_bd_stash(struct class_device *cdev,
const char *buf, size_t count)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
int new_setting = 0;
u32 temp;
unsigned long flags;
/* Find out the new setting */
if (!strncmp("on", buf, count-1) || !strncmp("1", buf, count-1))
new_setting = 1;
else if (!strncmp("off", buf, count-1) || !strncmp("0", buf, count-1))
new_setting = 0;
else
return count;
spin_lock_irqsave(&priv->lock, flags);
/* Set the new stashing value */
priv->bd_stash_en = new_setting;
temp = gfar_read(&priv->regs->attr);
if (new_setting)
temp |= ATTR_BDSTASH;
else
temp &= ~(ATTR_BDSTASH);
gfar_write(&priv->regs->attr, temp);
spin_unlock_irqrestore(&priv->lock, flags);
return count;
}
static ssize_t gfar_show_rx_stash_size(struct class_device *cdev, char *buf)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
return sprintf(buf, "%d\n", priv->rx_stash_size);
}
static ssize_t gfar_set_rx_stash_size(struct class_device *cdev,
const char *buf, size_t count)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
unsigned int length = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
if (length > priv->rx_buffer_size)
return count;
if (length == priv->rx_stash_size)
return count;
priv->rx_stash_size = length;
temp = gfar_read(&priv->regs->attreli);
temp &= ~ATTRELI_EL_MASK;
temp |= ATTRELI_EL(length);
gfar_write(&priv->regs->attreli, temp);
/* Turn stashing on/off as appropriate */
temp = gfar_read(&priv->regs->attr);
if (length)
temp |= ATTR_BUFSTASH;
else
temp &= ~(ATTR_BUFSTASH);
gfar_write(&priv->regs->attr, temp);
spin_unlock_irqrestore(&priv->lock, flags);
return count;
}
/* Stashing will only be enabled when rx_stash_size != 0 */
static ssize_t gfar_show_rx_stash_index(struct class_device *cdev, char *buf)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
return sprintf(buf, "%d\n", priv->rx_stash_index);
}
static ssize_t gfar_set_rx_stash_index(struct class_device *cdev,
const char *buf, size_t count)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
unsigned short index = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
if (index > priv->rx_stash_size)
return count;
if (index == priv->rx_stash_index)
return count;
priv->rx_stash_index = index;
temp = gfar_read(&priv->regs->attreli);
temp &= ~ATTRELI_EI_MASK;
temp |= ATTRELI_EI(index);
gfar_write(&priv->regs->attreli, flags);
spin_unlock_irqrestore(&priv->lock, flags);
return count;
}
static ssize_t gfar_show_fifo_threshold(struct class_device *cdev, char *buf)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
return sprintf(buf, "%d\n", priv->fifo_threshold);
}
static ssize_t gfar_set_fifo_threshold(struct class_device *cdev,
const char *buf, size_t count)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
unsigned int length = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
if (length > GFAR_MAX_FIFO_THRESHOLD)
return count;
spin_lock_irqsave(&priv->lock, flags);
priv->fifo_threshold = length;
temp = gfar_read(&priv->regs->fifo_tx_thr);
temp &= ~FIFO_TX_THR_MASK;
temp |= length;
gfar_write(&priv->regs->fifo_tx_thr, temp);
spin_unlock_irqrestore(&priv->lock, flags);
return count;
}
static ssize_t gfar_show_fifo_starve(struct class_device *cdev, char *buf)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
return sprintf(buf, "%d\n", priv->fifo_starve);
}
static ssize_t gfar_set_fifo_starve(struct class_device *cdev,
const char *buf, size_t count)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
unsigned int num = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
if (num > GFAR_MAX_FIFO_STARVE)
return count;
spin_lock_irqsave(&priv->lock, flags);
priv->fifo_starve = num;
temp = gfar_read(&priv->regs->fifo_tx_starve);
temp &= ~FIFO_TX_STARVE_MASK;
temp |= num;
gfar_write(&priv->regs->fifo_tx_starve, temp);
spin_unlock_irqrestore(&priv->lock, flags);
return count;
}
static ssize_t gfar_show_fifo_starve_off(struct class_device *cdev, char *buf)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
return sprintf(buf, "%d\n", priv->fifo_starve_off);
}
static ssize_t gfar_set_fifo_starve_off(struct class_device *cdev,
const char *buf, size_t count)
{
struct net_device *dev = to_net_dev(cdev);
struct gfar_private *priv = netdev_priv(dev);
unsigned int num = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
if (num > GFAR_MAX_FIFO_STARVE_OFF)
return count;
spin_lock_irqsave(&priv->lock, flags);
priv->fifo_starve_off = num;
temp = gfar_read(&priv->regs->fifo_tx_starve_shutoff);
temp &= ~FIFO_TX_STARVE_OFF_MASK;
temp |= num;
gfar_write(&priv->regs->fifo_tx_starve_shutoff, temp);
spin_unlock_irqrestore(&priv->lock, flags);
return count;
}
void gfar_init_sysfs(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
/* Initialize the default values */
priv->rx_stash_size = DEFAULT_STASH_LENGTH;
priv->rx_stash_index = DEFAULT_STASH_INDEX;
priv->fifo_threshold = DEFAULT_FIFO_TX_THR;
priv->fifo_starve = DEFAULT_FIFO_TX_STARVE;
priv->fifo_starve_off = DEFAULT_FIFO_TX_STARVE_OFF;
priv->bd_stash_en = DEFAULT_BD_STASH;
/* Create our sysfs files */
GFAR_CREATE_FILE(dev, bd_stash);
GFAR_CREATE_FILE(dev, rx_stash_size);
GFAR_CREATE_FILE(dev, rx_stash_index);
GFAR_CREATE_FILE(dev, fifo_threshold);
GFAR_CREATE_FILE(dev, fifo_starve);
GFAR_CREATE_FILE(dev, fifo_starve_off);
}

View file

@ -0,0 +1,6 @@
config ENP2611_MSF_NET
tristate "Radisys ENP2611 MSF network interface support"
depends on ARCH_ENP2611
help
This is a driver for the MSF network interface unit in
the IXP2400 on the Radisys ENP2611 platform.

View file

@ -0,0 +1,3 @@
obj-$(CONFIG_ENP2611_MSF_NET) += enp2611_mod.o
enp2611_mod-objs := caleb.o enp2611.o ixp2400-msf.o ixpdev.o pm3386.o

137
drivers/net/ixp2000/caleb.c Normal file
View file

@ -0,0 +1,137 @@
/*
* Helper functions for the SPI-3 bridge FPGA on the Radisys ENP2611
* Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
* Dedicated to Marija Kulikova.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <asm/io.h>
#include "caleb.h"
#define CALEB_IDLO 0x00
#define CALEB_IDHI 0x01
#define CALEB_RID 0x02
#define CALEB_RESET 0x03
#define CALEB_INTREN0 0x04
#define CALEB_INTREN1 0x05
#define CALEB_INTRSTAT0 0x06
#define CALEB_INTRSTAT1 0x07
#define CALEB_PORTEN 0x08
#define CALEB_BURST 0x09
#define CALEB_PORTPAUS 0x0A
#define CALEB_PORTPAUSD 0x0B
#define CALEB_PHY0RX 0x10
#define CALEB_PHY1RX 0x11
#define CALEB_PHY0TX 0x12
#define CALEB_PHY1TX 0x13
#define CALEB_IXPRX_HI_CNTR 0x15
#define CALEB_PHY0RX_HI_CNTR 0x16
#define CALEB_PHY1RX_HI_CNTR 0x17
#define CALEB_IXPRX_CNTR 0x18
#define CALEB_PHY0RX_CNTR 0x19
#define CALEB_PHY1RX_CNTR 0x1A
#define CALEB_IXPTX_CNTR 0x1B
#define CALEB_PHY0TX_CNTR 0x1C
#define CALEB_PHY1TX_CNTR 0x1D
#define CALEB_DEBUG0 0x1E
#define CALEB_DEBUG1 0x1F
static u8 caleb_reg_read(int reg)
{
u8 value;
value = *((volatile u8 *)(ENP2611_CALEB_VIRT_BASE + reg));
// printk(KERN_INFO "caleb_reg_read(%d) = %.2x\n", reg, value);
return value;
}
static void caleb_reg_write(int reg, u8 value)
{
u8 dummy;
// printk(KERN_INFO "caleb_reg_write(%d, %.2x)\n", reg, value);
*((volatile u8 *)(ENP2611_CALEB_VIRT_BASE + reg)) = value;
dummy = *((volatile u8 *)ENP2611_CALEB_VIRT_BASE);
__asm__ __volatile__("mov %0, %0" : "+r" (dummy));
}
void caleb_reset(void)
{
/*
* Perform a chip reset.
*/
caleb_reg_write(CALEB_RESET, 0x02);
udelay(1);
/*
* Enable all interrupt sources. This is needed to get
* meaningful results out of the status bits (register 6
* and 7.)
*/
caleb_reg_write(CALEB_INTREN0, 0xff);
caleb_reg_write(CALEB_INTREN1, 0x07);
/*
* Set RX and TX FIFO thresholds to 1.5kb.
*/
caleb_reg_write(CALEB_PHY0RX, 0x11);
caleb_reg_write(CALEB_PHY1RX, 0x11);
caleb_reg_write(CALEB_PHY0TX, 0x11);
caleb_reg_write(CALEB_PHY1TX, 0x11);
/*
* Program SPI-3 burst size.
*/
caleb_reg_write(CALEB_BURST, 0); // 64-byte RBUF mpackets
// caleb_reg_write(CALEB_BURST, 1); // 128-byte RBUF mpackets
// caleb_reg_write(CALEB_BURST, 2); // 256-byte RBUF mpackets
}
void caleb_enable_rx(int port)
{
u8 temp;
temp = caleb_reg_read(CALEB_PORTEN);
temp |= 1 << port;
caleb_reg_write(CALEB_PORTEN, temp);
}
void caleb_disable_rx(int port)
{
u8 temp;
temp = caleb_reg_read(CALEB_PORTEN);
temp &= ~(1 << port);
caleb_reg_write(CALEB_PORTEN, temp);
}
void caleb_enable_tx(int port)
{
u8 temp;
temp = caleb_reg_read(CALEB_PORTEN);
temp |= 1 << (port + 4);
caleb_reg_write(CALEB_PORTEN, temp);
}
void caleb_disable_tx(int port)
{
u8 temp;
temp = caleb_reg_read(CALEB_PORTEN);
temp &= ~(1 << (port + 4));
caleb_reg_write(CALEB_PORTEN, temp);
}

View file

@ -0,0 +1,22 @@
/*
* Helper functions for the SPI-3 bridge FPGA on the Radisys ENP2611
* Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
* Dedicated to Marija Kulikova.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __CALEB_H
#define __CALEB_H
void caleb_reset(void);
void caleb_enable_rx(int port);
void caleb_disable_rx(int port);
void caleb_enable_tx(int port);
void caleb_disable_tx(int port);
#endif

View file

@ -0,0 +1,245 @@
/*
* IXP2400 MSF network device driver for the Radisys ENP2611
* Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
* Dedicated to Marija Kulikova.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <asm/arch/uengine.h>
#include <asm/mach-types.h>
#include <asm/io.h>
#include "ixpdev.h"
#include "caleb.h"
#include "ixp2400-msf.h"
#include "pm3386.h"
/***********************************************************************
* The Radisys ENP2611 is a PCI form factor board with three SFP GBIC
* slots, connected via two PMC/Sierra 3386s and an SPI-3 bridge FPGA
* to the IXP2400.
*
* +-------------+
* SFP GBIC #0 ---+ | +---------+
* | PM3386 #0 +-------+ |
* SFP GBIC #1 ---+ | | "Caleb" | +---------+
* +-------------+ | | | |
* | SPI-3 +---------+ IXP2400 |
* +-------------+ | bridge | | |
* SFP GBIC #2 ---+ | | FPGA | +---------+
* | PM3386 #1 +-------+ |
* | | +---------+
* +-------------+
* ^ ^ ^
* | 1.25Gbaud | 104MHz | 104MHz
* | SERDES ea. | SPI-3 ea. | SPI-3
*
***********************************************************************/
static struct ixp2400_msf_parameters enp2611_msf_parameters =
{
.rx_mode = IXP2400_RX_MODE_UTOPIA_POS |
IXP2400_RX_MODE_1x32 |
IXP2400_RX_MODE_MPHY |
IXP2400_RX_MODE_MPHY_32 |
IXP2400_RX_MODE_MPHY_POLLED_STATUS |
IXP2400_RX_MODE_MPHY_LEVEL3 |
IXP2400_RX_MODE_RBUF_SIZE_64,
.rxclk01_multiplier = IXP2400_PLL_MULTIPLIER_16,
.rx_poll_ports = 3,
.rx_channel_mode = {
IXP2400_PORT_RX_MODE_MASTER |
IXP2400_PORT_RX_MODE_POS_PHY |
IXP2400_PORT_RX_MODE_POS_PHY_L3 |
IXP2400_PORT_RX_MODE_ODD_PARITY |
IXP2400_PORT_RX_MODE_2_CYCLE_DECODE,
IXP2400_PORT_RX_MODE_MASTER |
IXP2400_PORT_RX_MODE_POS_PHY |
IXP2400_PORT_RX_MODE_POS_PHY_L3 |
IXP2400_PORT_RX_MODE_ODD_PARITY |
IXP2400_PORT_RX_MODE_2_CYCLE_DECODE,
IXP2400_PORT_RX_MODE_MASTER |
IXP2400_PORT_RX_MODE_POS_PHY |
IXP2400_PORT_RX_MODE_POS_PHY_L3 |
IXP2400_PORT_RX_MODE_ODD_PARITY |
IXP2400_PORT_RX_MODE_2_CYCLE_DECODE,
IXP2400_PORT_RX_MODE_MASTER |
IXP2400_PORT_RX_MODE_POS_PHY |
IXP2400_PORT_RX_MODE_POS_PHY_L3 |
IXP2400_PORT_RX_MODE_ODD_PARITY |
IXP2400_PORT_RX_MODE_2_CYCLE_DECODE
},
.tx_mode = IXP2400_TX_MODE_UTOPIA_POS |
IXP2400_TX_MODE_1x32 |
IXP2400_TX_MODE_MPHY |
IXP2400_TX_MODE_MPHY_32 |
IXP2400_TX_MODE_MPHY_POLLED_STATUS |
IXP2400_TX_MODE_MPHY_LEVEL3 |
IXP2400_TX_MODE_TBUF_SIZE_64,
.txclk01_multiplier = IXP2400_PLL_MULTIPLIER_16,
.tx_poll_ports = 3,
.tx_channel_mode = {
IXP2400_PORT_TX_MODE_MASTER |
IXP2400_PORT_TX_MODE_POS_PHY |
IXP2400_PORT_TX_MODE_ODD_PARITY |
IXP2400_PORT_TX_MODE_2_CYCLE_DECODE,
IXP2400_PORT_TX_MODE_MASTER |
IXP2400_PORT_TX_MODE_POS_PHY |
IXP2400_PORT_TX_MODE_ODD_PARITY |
IXP2400_PORT_TX_MODE_2_CYCLE_DECODE,
IXP2400_PORT_TX_MODE_MASTER |
IXP2400_PORT_TX_MODE_POS_PHY |
IXP2400_PORT_TX_MODE_ODD_PARITY |
IXP2400_PORT_TX_MODE_2_CYCLE_DECODE,
IXP2400_PORT_TX_MODE_MASTER |
IXP2400_PORT_TX_MODE_POS_PHY |
IXP2400_PORT_TX_MODE_ODD_PARITY |
IXP2400_PORT_TX_MODE_2_CYCLE_DECODE
}
};
struct enp2611_ixpdev_priv
{
struct ixpdev_priv ixpdev_priv;
struct net_device_stats stats;
};
static struct net_device *nds[3];
static struct timer_list link_check_timer;
static struct net_device_stats *enp2611_get_stats(struct net_device *dev)
{
struct enp2611_ixpdev_priv *ip = netdev_priv(dev);
pm3386_get_stats(ip->ixpdev_priv.channel, &(ip->stats));
return &(ip->stats);
}
/* @@@ Poll the SFP moddef0 line too. */
/* @@@ Try to use the pm3386 DOOL interrupt as well. */
static void enp2611_check_link_status(unsigned long __dummy)
{
int i;
for (i = 0; i < 3; i++) {
struct net_device *dev;
int status;
dev = nds[i];
status = pm3386_is_link_up(i);
if (status && !netif_carrier_ok(dev)) {
/* @@@ Should report autonegotiation status. */
printk(KERN_INFO "%s: NIC Link is Up\n", dev->name);
pm3386_enable_tx(i);
caleb_enable_tx(i);
netif_carrier_on(dev);
} else if (!status && netif_carrier_ok(dev)) {
printk(KERN_INFO "%s: NIC Link is Down\n", dev->name);
netif_carrier_off(dev);
caleb_disable_tx(i);
pm3386_disable_tx(i);
}
}
link_check_timer.expires = jiffies + HZ / 10;
add_timer(&link_check_timer);
}
static void enp2611_set_port_admin_status(int port, int up)
{
if (up) {
caleb_enable_rx(port);
pm3386_set_carrier(port, 1);
pm3386_enable_rx(port);
} else {
caleb_disable_tx(port);
pm3386_disable_tx(port);
/* @@@ Flush out pending packets. */
pm3386_set_carrier(port, 0);
pm3386_disable_rx(port);
caleb_disable_rx(port);
}
}
static int __init enp2611_init_module(void)
{
int i;
if (!machine_is_enp2611())
return -ENODEV;
caleb_reset();
pm3386_reset();
for (i = 0; i < 3; i++) {
nds[i] = ixpdev_alloc(i, sizeof(struct enp2611_ixpdev_priv));
if (nds[i] == NULL) {
while (--i >= 0)
free_netdev(nds[i]);
return -ENOMEM;
}
SET_MODULE_OWNER(nds[i]);
nds[i]->get_stats = enp2611_get_stats;
pm3386_init_port(i);
pm3386_get_mac(i, nds[i]->dev_addr);
}
ixp2400_msf_init(&enp2611_msf_parameters);
if (ixpdev_init(3, nds, enp2611_set_port_admin_status)) {
for (i = 0; i < 3; i++)
free_netdev(nds[i]);
return -EINVAL;
}
init_timer(&link_check_timer);
link_check_timer.function = enp2611_check_link_status;
link_check_timer.expires = jiffies;
add_timer(&link_check_timer);
return 0;
}
static void __exit enp2611_cleanup_module(void)
{
int i;
del_timer_sync(&link_check_timer);
ixpdev_deinit();
for (i = 0; i < 3; i++)
free_netdev(nds[i]);
}
module_init(enp2611_init_module);
module_exit(enp2611_cleanup_module);
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,213 @@
/*
* Generic library functions for the MSF (Media and Switch Fabric) unit
* found on the Intel IXP2400 network processor.
*
* Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
* Dedicated to Marija Kulikova.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/arch/ixp2000-regs.h>
#include <asm/delay.h>
#include <asm/io.h>
#include "ixp2400-msf.h"
/*
* This is the Intel recommended PLL init procedure as described on
* page 340 of the IXP2400/IXP2800 Programmer's Reference Manual.
*/
static void ixp2400_pll_init(struct ixp2400_msf_parameters *mp)
{
int rx_dual_clock;
int tx_dual_clock;
u32 value;
/*
* If the RX mode is not 1x32, we have to enable both RX PLLs
* (#0 and #1.) The same thing for the TX direction.
*/
rx_dual_clock = !!(mp->rx_mode & IXP2400_RX_MODE_WIDTH_MASK);
tx_dual_clock = !!(mp->tx_mode & IXP2400_TX_MODE_WIDTH_MASK);
/*
* Read initial value.
*/
value = ixp2000_reg_read(IXP2000_MSF_CLK_CNTRL);
/*
* Put PLLs in powerdown and bypass mode.
*/
value |= 0x0000f0f0;
ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value);
/*
* Set single or dual clock mode bits.
*/
value &= ~0x03000000;
value |= (rx_dual_clock << 24) | (tx_dual_clock << 25);
/*
* Set multipliers.
*/
value &= ~0x00ff0000;
value |= mp->rxclk01_multiplier << 16;
value |= mp->rxclk23_multiplier << 18;
value |= mp->txclk01_multiplier << 20;
value |= mp->txclk23_multiplier << 22;
/*
* And write value.
*/
ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value);
/*
* Disable PLL bypass mode.
*/
value &= ~(0x00005000 | rx_dual_clock << 13 | tx_dual_clock << 15);
ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value);
/*
* Turn on PLLs.
*/
value &= ~(0x00000050 | rx_dual_clock << 5 | tx_dual_clock << 7);
ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value);
/*
* Wait for PLLs to lock. There are lock status bits, but IXP2400
* erratum #65 says that these lock bits should not be relied upon
* as they might not accurately reflect the true state of the PLLs.
*/
udelay(100);
}
/*
* Needed according to p480 of Programmer's Reference Manual.
*/
static void ixp2400_msf_free_rbuf_entries(struct ixp2400_msf_parameters *mp)
{
int size_bits;
int i;
/*
* Work around IXP2400 erratum #69 (silent RBUF-to-DRAM transfer
* corruption) in the Intel-recommended way: do not add the RBUF
* elements susceptible to corruption to the freelist.
*/
size_bits = mp->rx_mode & IXP2400_RX_MODE_RBUF_SIZE_MASK;
if (size_bits == IXP2400_RX_MODE_RBUF_SIZE_64) {
for (i = 1; i < 128; i++) {
if (i == 9 || i == 18 || i == 27)
continue;
ixp2000_reg_write(IXP2000_MSF_RBUF_ELEMENT_DONE, i);
}
} else if (size_bits == IXP2400_RX_MODE_RBUF_SIZE_128) {
for (i = 1; i < 64; i++) {
if (i == 4 || i == 9 || i == 13)
continue;
ixp2000_reg_write(IXP2000_MSF_RBUF_ELEMENT_DONE, i);
}
} else if (size_bits == IXP2400_RX_MODE_RBUF_SIZE_256) {
for (i = 1; i < 32; i++) {
if (i == 2 || i == 4 || i == 6)
continue;
ixp2000_reg_write(IXP2000_MSF_RBUF_ELEMENT_DONE, i);
}
}
}
static u32 ixp2400_msf_valid_channels(u32 reg)
{
u32 channels;
channels = 0;
switch (reg & IXP2400_RX_MODE_WIDTH_MASK) {
case IXP2400_RX_MODE_1x32:
channels = 0x1;
if (reg & IXP2400_RX_MODE_MPHY &&
!(reg & IXP2400_RX_MODE_MPHY_32))
channels = 0xf;
break;
case IXP2400_RX_MODE_2x16:
channels = 0x5;
break;
case IXP2400_RX_MODE_4x8:
channels = 0xf;
break;
case IXP2400_RX_MODE_1x16_2x8:
channels = 0xd;
break;
}
return channels;
}
static void ixp2400_msf_enable_rx(struct ixp2400_msf_parameters *mp)
{
u32 value;
value = ixp2000_reg_read(IXP2000_MSF_RX_CONTROL) & 0x0fffffff;
value |= ixp2400_msf_valid_channels(mp->rx_mode) << 28;
ixp2000_reg_write(IXP2000_MSF_RX_CONTROL, value);
}
static void ixp2400_msf_enable_tx(struct ixp2400_msf_parameters *mp)
{
u32 value;
value = ixp2000_reg_read(IXP2000_MSF_TX_CONTROL) & 0x0fffffff;
value |= ixp2400_msf_valid_channels(mp->tx_mode) << 28;
ixp2000_reg_write(IXP2000_MSF_TX_CONTROL, value);
}
void ixp2400_msf_init(struct ixp2400_msf_parameters *mp)
{
u32 value;
int i;
/*
* Init the RX/TX PLLs based on the passed parameter block.
*/
ixp2400_pll_init(mp);
/*
* Reset MSF. Bit 7 in IXP_RESET_0 resets the MSF.
*/
value = ixp2000_reg_read(IXP2000_RESET0);
ixp2000_reg_write(IXP2000_RESET0, value | 0x80);
ixp2000_reg_write(IXP2000_RESET0, value & ~0x80);
/*
* Initialise the RX section.
*/
ixp2000_reg_write(IXP2000_MSF_RX_MPHY_POLL_LIMIT, mp->rx_poll_ports - 1);
ixp2000_reg_write(IXP2000_MSF_RX_CONTROL, mp->rx_mode);
for (i = 0; i < 4; i++) {
ixp2000_reg_write(IXP2000_MSF_RX_UP_CONTROL_0 + i,
mp->rx_channel_mode[i]);
}
ixp2400_msf_free_rbuf_entries(mp);
ixp2400_msf_enable_rx(mp);
/*
* Initialise the TX section.
*/
ixp2000_reg_write(IXP2000_MSF_TX_MPHY_POLL_LIMIT, mp->tx_poll_ports - 1);
ixp2000_reg_write(IXP2000_MSF_TX_CONTROL, mp->tx_mode);
for (i = 0; i < 4; i++) {
ixp2000_reg_write(IXP2000_MSF_TX_UP_CONTROL_0 + i,
mp->tx_channel_mode[i]);
}
ixp2400_msf_enable_tx(mp);
}

View file

@ -0,0 +1,115 @@
/*
* Generic library functions for the MSF (Media and Switch Fabric) unit
* found on the Intel IXP2400 network processor.
*
* Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
* Dedicated to Marija Kulikova.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*/
#ifndef __IXP2400_MSF_H
#define __IXP2400_MSF_H
struct ixp2400_msf_parameters
{
u32 rx_mode;
unsigned rxclk01_multiplier:2;
unsigned rxclk23_multiplier:2;
unsigned rx_poll_ports:6;
u32 rx_channel_mode[4];
u32 tx_mode;
unsigned txclk01_multiplier:2;
unsigned txclk23_multiplier:2;
unsigned tx_poll_ports:6;
u32 tx_channel_mode[4];
};
void ixp2400_msf_init(struct ixp2400_msf_parameters *mp);
#define IXP2400_PLL_MULTIPLIER_48 0x00
#define IXP2400_PLL_MULTIPLIER_24 0x01
#define IXP2400_PLL_MULTIPLIER_16 0x02
#define IXP2400_PLL_MULTIPLIER_12 0x03
#define IXP2400_RX_MODE_CSIX 0x00400000
#define IXP2400_RX_MODE_UTOPIA_POS 0x00000000
#define IXP2400_RX_MODE_WIDTH_MASK 0x00300000
#define IXP2400_RX_MODE_1x16_2x8 0x00300000
#define IXP2400_RX_MODE_4x8 0x00200000
#define IXP2400_RX_MODE_2x16 0x00100000
#define IXP2400_RX_MODE_1x32 0x00000000
#define IXP2400_RX_MODE_MPHY 0x00080000
#define IXP2400_RX_MODE_SPHY 0x00000000
#define IXP2400_RX_MODE_MPHY_32 0x00040000
#define IXP2400_RX_MODE_MPHY_4 0x00000000
#define IXP2400_RX_MODE_MPHY_POLLED_STATUS 0x00020000
#define IXP2400_RX_MODE_MPHY_DIRECT_STATUS 0x00000000
#define IXP2400_RX_MODE_CBUS_FULL_DUPLEX 0x00010000
#define IXP2400_RX_MODE_CBUS_SIMPLEX 0x00000000
#define IXP2400_RX_MODE_MPHY_LEVEL2 0x00004000
#define IXP2400_RX_MODE_MPHY_LEVEL3 0x00000000
#define IXP2400_RX_MODE_CBUS_8BIT 0x00002000
#define IXP2400_RX_MODE_CBUS_4BIT 0x00000000
#define IXP2400_RX_MODE_CSIX_SINGLE_FREELIST 0x00000200
#define IXP2400_RX_MODE_CSIX_SPLIT_FREELISTS 0x00000000
#define IXP2400_RX_MODE_RBUF_SIZE_MASK 0x0000000c
#define IXP2400_RX_MODE_RBUF_SIZE_256 0x00000008
#define IXP2400_RX_MODE_RBUF_SIZE_128 0x00000004
#define IXP2400_RX_MODE_RBUF_SIZE_64 0x00000000
#define IXP2400_PORT_RX_MODE_SLAVE 0x00000040
#define IXP2400_PORT_RX_MODE_MASTER 0x00000000
#define IXP2400_PORT_RX_MODE_POS_PHY_L3 0x00000020
#define IXP2400_PORT_RX_MODE_POS_PHY_L2 0x00000000
#define IXP2400_PORT_RX_MODE_POS_PHY 0x00000010
#define IXP2400_PORT_RX_MODE_UTOPIA 0x00000000
#define IXP2400_PORT_RX_MODE_EVEN_PARITY 0x0000000c
#define IXP2400_PORT_RX_MODE_ODD_PARITY 0x00000008
#define IXP2400_PORT_RX_MODE_NO_PARITY 0x00000000
#define IXP2400_PORT_RX_MODE_UTOPIA_BIG_CELLS 0x00000002
#define IXP2400_PORT_RX_MODE_UTOPIA_NORMAL_CELLS 0x00000000
#define IXP2400_PORT_RX_MODE_2_CYCLE_DECODE 0x00000001
#define IXP2400_PORT_RX_MODE_1_CYCLE_DECODE 0x00000000
#define IXP2400_TX_MODE_CSIX 0x00400000
#define IXP2400_TX_MODE_UTOPIA_POS 0x00000000
#define IXP2400_TX_MODE_WIDTH_MASK 0x00300000
#define IXP2400_TX_MODE_1x16_2x8 0x00300000
#define IXP2400_TX_MODE_4x8 0x00200000
#define IXP2400_TX_MODE_2x16 0x00100000
#define IXP2400_TX_MODE_1x32 0x00000000
#define IXP2400_TX_MODE_MPHY 0x00080000
#define IXP2400_TX_MODE_SPHY 0x00000000
#define IXP2400_TX_MODE_MPHY_32 0x00040000
#define IXP2400_TX_MODE_MPHY_4 0x00000000
#define IXP2400_TX_MODE_MPHY_POLLED_STATUS 0x00020000
#define IXP2400_TX_MODE_MPHY_DIRECT_STATUS 0x00000000
#define IXP2400_TX_MODE_CBUS_FULL_DUPLEX 0x00010000
#define IXP2400_TX_MODE_CBUS_SIMPLEX 0x00000000
#define IXP2400_TX_MODE_MPHY_LEVEL2 0x00004000
#define IXP2400_TX_MODE_MPHY_LEVEL3 0x00000000
#define IXP2400_TX_MODE_CBUS_8BIT 0x00002000
#define IXP2400_TX_MODE_CBUS_4BIT 0x00000000
#define IXP2400_TX_MODE_TBUF_SIZE_MASK 0x0000000c
#define IXP2400_TX_MODE_TBUF_SIZE_256 0x00000008
#define IXP2400_TX_MODE_TBUF_SIZE_128 0x00000004
#define IXP2400_TX_MODE_TBUF_SIZE_64 0x00000000
#define IXP2400_PORT_TX_MODE_SLAVE 0x00000040
#define IXP2400_PORT_TX_MODE_MASTER 0x00000000
#define IXP2400_PORT_TX_MODE_POS_PHY 0x00000010
#define IXP2400_PORT_TX_MODE_UTOPIA 0x00000000
#define IXP2400_PORT_TX_MODE_EVEN_PARITY 0x0000000c
#define IXP2400_PORT_TX_MODE_ODD_PARITY 0x00000008
#define IXP2400_PORT_TX_MODE_NO_PARITY 0x00000000
#define IXP2400_PORT_TX_MODE_UTOPIA_BIG_CELLS 0x00000002
#define IXP2400_PORT_TX_MODE_2_CYCLE_DECODE 0x00000001
#define IXP2400_PORT_TX_MODE_1_CYCLE_DECODE 0x00000000
#endif

View file

@ -0,0 +1,408 @@
/*
* RX ucode for the Intel IXP2400 in POS-PHY mode.
* Copyright (C) 2004, 2005 Lennert Buytenhek
* Dedicated to Marija Kulikova.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Assumptions made in this code:
* - The IXP2400 MSF is configured for POS-PHY mode, in a mode where
* only one full element list is used. This includes, for example,
* 1x32 SPHY and 1x32 MPHY32, but not 4x8 SPHY or 1x32 MPHY4. (This
* is not an exhaustive list.)
* - The RBUF uses 64-byte mpackets.
* - RX descriptors reside in SRAM, and have the following format:
* struct rx_desc
* {
* // to uengine
* u32 buf_phys_addr;
* u32 buf_length;
*
* // from uengine
* u32 channel;
* u32 pkt_length;
* };
* - Packet data resides in DRAM.
* - Packet buffer addresses are 8-byte aligned.
* - Scratch ring 0 is rx_pending.
* - Scratch ring 1 is rx_done, and has status condition 'full'.
* - The host triggers rx_done flush and rx_pending refill on seeing INTA.
* - This code is run on all eight threads of the microengine it runs on.
*
* Local memory is used for per-channel RX state.
*/
#define RX_THREAD_FREELIST_0 0x0030
#define RBUF_ELEMENT_DONE 0x0044
#define CHANNEL_FLAGS *l$index0[0]
#define CHANNEL_FLAG_RECEIVING 1
#define PACKET_LENGTH *l$index0[1]
#define PACKET_CHECKSUM *l$index0[2]
#define BUFFER_HANDLE *l$index0[3]
#define BUFFER_START *l$index0[4]
#define BUFFER_LENGTH *l$index0[5]
#define CHANNEL_STATE_SIZE 24 // in bytes
#define CHANNEL_STATE_SHIFT 5 // ceil(log2(state size))
.sig volatile sig1
.sig volatile sig2
.sig volatile sig3
.sig mpacket_arrived
.reg add_to_rx_freelist
.reg read $rsw0, $rsw1
.xfer_order $rsw0 $rsw1
.reg zero
/*
* Initialise add_to_rx_freelist.
*/
.begin
.reg temp
.reg temp2
immed[add_to_rx_freelist, RX_THREAD_FREELIST_0]
immed_w1[add_to_rx_freelist, (&$rsw0 | (&mpacket_arrived << 12))]
local_csr_rd[ACTIVE_CTX_STS]
immed[temp, 0]
alu[temp2, temp, and, 0x1f]
alu_shf[add_to_rx_freelist, add_to_rx_freelist, or, temp2, <<20]
alu[temp2, temp, and, 0x80]
alu_shf[add_to_rx_freelist, add_to_rx_freelist, or, temp2, <<18]
.end
immed[zero, 0]
/*
* Skip context 0 initialisation?
*/
.begin
br!=ctx[0, mpacket_receive_loop#]
.end
/*
* Initialise local memory.
*/
.begin
.reg addr
.reg temp
immed[temp, 0]
init_local_mem_loop#:
alu_shf[addr, --, b, temp, <<CHANNEL_STATE_SHIFT]
local_csr_wr[ACTIVE_LM_ADDR_0, addr]
nop
nop
nop
immed[CHANNEL_FLAGS, 0]
alu[temp, temp, +, 1]
alu[--, temp, and, 0x20]
beq[init_local_mem_loop#]
.end
/*
* Initialise signal pipeline.
*/
.begin
local_csr_wr[SAME_ME_SIGNAL, (&sig1 << 3)]
.set_sig sig1
local_csr_wr[SAME_ME_SIGNAL, (&sig2 << 3)]
.set_sig sig2
local_csr_wr[SAME_ME_SIGNAL, (&sig3 << 3)]
.set_sig sig3
.end
mpacket_receive_loop#:
/*
* Synchronise and wait for mpacket.
*/
.begin
ctx_arb[sig1]
local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig1 << 3))]
msf[fast_wr, --, add_to_rx_freelist, 0]
.set_sig mpacket_arrived
ctx_arb[mpacket_arrived]
.set $rsw0 $rsw1
.end
/*
* We halt if we see {inbparerr,parerr,null,soperror}.
*/
.begin
alu_shf[--, 0x1b, and, $rsw0, >>8]
bne[abort_rswerr#]
.end
/*
* Point local memory pointer to this channel's state area.
*/
.begin
.reg chanaddr
alu[chanaddr, $rsw0, and, 0x1f]
alu_shf[chanaddr, --, b, chanaddr, <<CHANNEL_STATE_SHIFT]
local_csr_wr[ACTIVE_LM_ADDR_0, chanaddr]
nop
nop
nop
.end
/*
* Check whether we received a SOP mpacket while we were already
* working on a packet, or a non-SOP mpacket while there was no
* packet pending. (SOP == RECEIVING -> abort) If everything's
* okay, update the RECEIVING flag to reflect our new state.
*/
.begin
.reg temp
.reg eop
#if CHANNEL_FLAG_RECEIVING != 1
#error CHANNEL_FLAG_RECEIVING is not 1
#endif
alu_shf[temp, 1, and, $rsw0, >>15]
alu[temp, temp, xor, CHANNEL_FLAGS]
alu[--, temp, and, CHANNEL_FLAG_RECEIVING]
beq[abort_proterr#]
alu_shf[eop, 1, and, $rsw0, >>14]
alu[CHANNEL_FLAGS, temp, xor, eop]
.end
/*
* Copy the mpacket into the right spot, and in case of EOP,
* write back the descriptor and pass the packet on.
*/
.begin
.reg buffer_offset
.reg _packet_length
.reg _packet_checksum
.reg _buffer_handle
.reg _buffer_start
.reg _buffer_length
/*
* Determine buffer_offset, _packet_length and
* _packet_checksum.
*/
.begin
.reg temp
alu[--, 1, and, $rsw0, >>15]
beq[not_sop#]
immed[PACKET_LENGTH, 0]
immed[PACKET_CHECKSUM, 0]
not_sop#:
alu[buffer_offset, --, b, PACKET_LENGTH]
alu_shf[temp, 0xff, and, $rsw0, >>16]
alu[_packet_length, buffer_offset, +, temp]
alu[PACKET_LENGTH, --, b, _packet_length]
immed[temp, 0xffff]
alu[temp, $rsw1, and, temp]
alu[_packet_checksum, PACKET_CHECKSUM, +, temp]
alu[PACKET_CHECKSUM, --, b, _packet_checksum]
.end
/*
* Allocate buffer in case of SOP.
*/
.begin
.reg temp
alu[temp, 1, and, $rsw0, >>15]
beq[skip_buffer_alloc#]
.begin
.sig zzz
.reg read $stemp $stemp2
.xfer_order $stemp $stemp2
rx_nobufs#:
scratch[get, $stemp, zero, 0, 1], ctx_swap[zzz]
alu[_buffer_handle, --, b, $stemp]
beq[rx_nobufs#]
sram[read, $stemp, _buffer_handle, 0, 2],
ctx_swap[zzz]
alu[_buffer_start, --, b, $stemp]
alu[_buffer_length, --, b, $stemp2]
.end
skip_buffer_alloc#:
.end
/*
* Resynchronise.
*/
.begin
ctx_arb[sig2]
local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig2 << 3))]
.end
/*
* Synchronise buffer state.
*/
.begin
.reg temp
alu[temp, 1, and, $rsw0, >>15]
beq[copy_from_local_mem#]
alu[BUFFER_HANDLE, --, b, _buffer_handle]
alu[BUFFER_START, --, b, _buffer_start]
alu[BUFFER_LENGTH, --, b, _buffer_length]
br[sync_state_done#]
copy_from_local_mem#:
alu[_buffer_handle, --, b, BUFFER_HANDLE]
alu[_buffer_start, --, b, BUFFER_START]
alu[_buffer_length, --, b, BUFFER_LENGTH]
sync_state_done#:
.end
#if 0
/*
* Debug buffer state management.
*/
.begin
.reg temp
alu[temp, 1, and, $rsw0, >>14]
beq[no_poison#]
immed[BUFFER_HANDLE, 0xdead]
immed[BUFFER_START, 0xdead]
immed[BUFFER_LENGTH, 0xdead]
no_poison#:
immed[temp, 0xdead]
alu[--, _buffer_handle, -, temp]
beq[state_corrupted#]
alu[--, _buffer_start, -, temp]
beq[state_corrupted#]
alu[--, _buffer_length, -, temp]
beq[state_corrupted#]
.end
#endif
/*
* Check buffer length.
*/
.begin
alu[--, _buffer_length, -, _packet_length]
blo[buffer_overflow#]
.end
/*
* Copy the mpacket and give back the RBUF element.
*/
.begin
.reg element
.reg xfer_size
.reg temp
.sig copy_sig
alu_shf[element, 0x7f, and, $rsw0, >>24]
alu_shf[xfer_size, 0xff, and, $rsw0, >>16]
alu[xfer_size, xfer_size, -, 1]
alu_shf[xfer_size, 0x10, or, xfer_size, >>3]
alu_shf[temp, 0x10, or, xfer_size, <<21]
alu_shf[temp, temp, or, element, <<11]
alu_shf[--, temp, or, 1, <<18]
dram[rbuf_rd, --, _buffer_start, buffer_offset, max_8],
indirect_ref, sig_done[copy_sig]
ctx_arb[copy_sig]
alu[temp, RBUF_ELEMENT_DONE, or, element, <<16]
msf[fast_wr, --, temp, 0]
.end
/*
* If EOP, write back the packet descriptor.
*/
.begin
.reg write $stemp $stemp2
.xfer_order $stemp $stemp2
.sig zzz
alu_shf[--, 1, and, $rsw0, >>14]
beq[no_writeback#]
alu[$stemp, $rsw0, and, 0x1f]
alu[$stemp2, --, b, _packet_length]
sram[write, $stemp, _buffer_handle, 8, 2], ctx_swap[zzz]
no_writeback#:
.end
/*
* Resynchronise.
*/
.begin
ctx_arb[sig3]
local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig3 << 3))]
.end
/*
* If EOP, put the buffer back onto the scratch ring.
*/
.begin
.reg write $stemp
.sig zzz
br_inp_state[SCR_Ring1_Status, rx_done_ring_overflow#]
alu_shf[--, 1, and, $rsw0, >>14]
beq[mpacket_receive_loop#]
alu[--, 1, and, $rsw0, >>10]
bne[rxerr#]
alu[$stemp, --, b, _buffer_handle]
scratch[put, $stemp, zero, 4, 1], ctx_swap[zzz]
cap[fast_wr, 0, XSCALE_INT_A]
br[mpacket_receive_loop#]
rxerr#:
alu[$stemp, --, b, _buffer_handle]
scratch[put, $stemp, zero, 0, 1], ctx_swap[zzz]
br[mpacket_receive_loop#]
.end
.end
abort_rswerr#:
halt
abort_proterr#:
halt
state_corrupted#:
halt
buffer_overflow#:
halt
rx_done_ring_overflow#:
halt

View file

@ -0,0 +1,130 @@
static struct ixp2000_uengine_code ixp2400_rx =
{
.cpu_model_bitmask = 0x000003fe,
.cpu_min_revision = 0,
.cpu_max_revision = 255,
.uengine_parameters = IXP2000_UENGINE_8_CONTEXTS |
IXP2000_UENGINE_PRN_UPDATE_EVERY |
IXP2000_UENGINE_NN_FROM_PREVIOUS |
IXP2000_UENGINE_ASSERT_EMPTY_AT_0 |
IXP2000_UENGINE_LM_ADDR1_PER_CONTEXT |
IXP2000_UENGINE_LM_ADDR0_PER_CONTEXT,
.initial_reg_values = (struct ixp2000_reg_value []) {
{ -1, -1 }
},
.num_insns = 109,
.insns = (u8 []) {
0xf0, 0x00, 0x0c, 0xc0, 0x05,
0xf4, 0x44, 0x0c, 0x00, 0x05,
0xfc, 0x04, 0x4c, 0x00, 0x00,
0xf0, 0x00, 0x00, 0x3b, 0x00,
0xb4, 0x40, 0xf0, 0x3b, 0x1f,
0x8a, 0xc0, 0x50, 0x3e, 0x05,
0xb4, 0x40, 0xf0, 0x3b, 0x80,
0x9a, 0xe0, 0x00, 0x3e, 0x05,
0xf0, 0x00, 0x00, 0x07, 0x00,
0xd8, 0x05, 0xc0, 0x00, 0x11,
0xf0, 0x00, 0x00, 0x0f, 0x00,
0x91, 0xb0, 0x20, 0x0e, 0x00,
0xfc, 0x06, 0x60, 0x0b, 0x00,
0xf0, 0x00, 0x0c, 0x03, 0x00,
0xf0, 0x00, 0x0c, 0x03, 0x00,
0xf0, 0x00, 0x0c, 0x03, 0x00,
0xf0, 0x00, 0x0c, 0x02, 0x00,
0xb0, 0xc0, 0x30, 0x0f, 0x01,
0xa4, 0x70, 0x00, 0x0f, 0x20,
0xd8, 0x02, 0xc0, 0x01, 0x00,
0xfc, 0x10, 0xac, 0x23, 0x08,
0xfc, 0x10, 0xac, 0x43, 0x10,
0xfc, 0x10, 0xac, 0x63, 0x18,
0xe0, 0x00, 0x00, 0x00, 0x02,
0xfc, 0x10, 0xae, 0x23, 0x88,
0x3d, 0x00, 0x04, 0x03, 0x20,
0xe0, 0x00, 0x00, 0x00, 0x10,
0x84, 0x82, 0x02, 0x01, 0x3b,
0xd8, 0x1a, 0x00, 0x01, 0x01,
0xb4, 0x00, 0x8c, 0x7d, 0x80,
0x91, 0xb0, 0x80, 0x22, 0x00,
0xfc, 0x06, 0x60, 0x23, 0x00,
0xf0, 0x00, 0x0c, 0x03, 0x00,
0xf0, 0x00, 0x0c, 0x03, 0x00,
0xf0, 0x00, 0x0c, 0x03, 0x00,
0x94, 0xf0, 0x92, 0x01, 0x21,
0xac, 0x40, 0x60, 0x26, 0x00,
0xa4, 0x30, 0x0c, 0x04, 0x06,
0xd8, 0x1a, 0x40, 0x01, 0x00,
0x94, 0xe0, 0xa2, 0x01, 0x21,
0xac, 0x20, 0x00, 0x28, 0x06,
0x84, 0xf2, 0x02, 0x01, 0x21,
0xd8, 0x0b, 0x40, 0x01, 0x00,
0xf0, 0x00, 0x0c, 0x02, 0x01,
0xf0, 0x00, 0x0c, 0x02, 0x02,
0xa0, 0x00, 0x08, 0x04, 0x00,
0x95, 0x00, 0xc6, 0x01, 0xff,
0xa0, 0x80, 0x10, 0x30, 0x00,
0xa0, 0x60, 0x1c, 0x00, 0x01,
0xf0, 0x0f, 0xf0, 0x33, 0xff,
0xb4, 0x00, 0xc0, 0x31, 0x81,
0xb0, 0x80, 0xb0, 0x32, 0x02,
0xa0, 0x20, 0x20, 0x2c, 0x00,
0x94, 0xf0, 0xd2, 0x01, 0x21,
0xd8, 0x0f, 0x40, 0x01, 0x00,
0x19, 0x40, 0x10, 0x04, 0x20,
0xa0, 0x00, 0x26, 0x04, 0x00,
0xd8, 0x0d, 0xc0, 0x01, 0x00,
0x00, 0x42, 0x10, 0x80, 0x02,
0xb0, 0x00, 0x46, 0x04, 0x00,
0xb0, 0x00, 0x56, 0x08, 0x00,
0xe0, 0x00, 0x00, 0x00, 0x04,
0xfc, 0x10, 0xae, 0x43, 0x90,
0x84, 0xf0, 0x32, 0x01, 0x21,
0xd8, 0x11, 0x40, 0x01, 0x00,
0xa0, 0x60, 0x3c, 0x00, 0x02,
0xa0, 0x20, 0x40, 0x10, 0x00,
0xa0, 0x20, 0x50, 0x14, 0x00,
0xd8, 0x12, 0x00, 0x00, 0x18,
0xa0, 0x00, 0x28, 0x0c, 0x00,
0xb0, 0x00, 0x48, 0x10, 0x00,
0xb0, 0x00, 0x58, 0x14, 0x00,
0xaa, 0xf0, 0x00, 0x14, 0x01,
0xd8, 0x1a, 0xc0, 0x01, 0x05,
0x85, 0x80, 0x42, 0x01, 0xff,
0x95, 0x00, 0x66, 0x01, 0xff,
0xba, 0xc0, 0x60, 0x1b, 0x01,
0x9a, 0x30, 0x60, 0x19, 0x30,
0x9a, 0xb0, 0x70, 0x1a, 0x30,
0x9b, 0x50, 0x78, 0x1e, 0x04,
0x8a, 0xe2, 0x08, 0x1e, 0x21,
0x6a, 0x4e, 0x00, 0x13, 0x00,
0xe0, 0x00, 0x00, 0x00, 0x30,
0x9b, 0x00, 0x7a, 0x92, 0x04,
0x3d, 0x00, 0x04, 0x1f, 0x20,
0x84, 0xe2, 0x02, 0x01, 0x21,
0xd8, 0x16, 0x80, 0x01, 0x00,
0xa4, 0x18, 0x0c, 0x7d, 0x80,
0xa0, 0x58, 0x1c, 0x00, 0x01,
0x01, 0x42, 0x00, 0xa0, 0x02,
0xe0, 0x00, 0x00, 0x00, 0x08,
0xfc, 0x10, 0xae, 0x63, 0x98,
0xd8, 0x1b, 0x00, 0xc2, 0x14,
0x84, 0xe2, 0x02, 0x01, 0x21,
0xd8, 0x05, 0xc0, 0x01, 0x00,
0x84, 0xa2, 0x02, 0x01, 0x21,
0xd8, 0x19, 0x40, 0x01, 0x01,
0xa0, 0x58, 0x0c, 0x00, 0x02,
0x1a, 0x40, 0x00, 0x04, 0x24,
0x33, 0x00, 0x01, 0x2f, 0x20,
0xd8, 0x05, 0xc0, 0x00, 0x18,
0xa0, 0x58, 0x0c, 0x00, 0x02,
0x1a, 0x40, 0x00, 0x04, 0x20,
0xd8, 0x05, 0xc0, 0x00, 0x18,
0xe0, 0x00, 0x02, 0x00, 0x00,
0xe0, 0x00, 0x02, 0x00, 0x00,
0xe0, 0x00, 0x02, 0x00, 0x00,
0xe0, 0x00, 0x02, 0x00, 0x00,
0xe0, 0x00, 0x02, 0x00, 0x00,
}
};

View file

@ -0,0 +1,272 @@
/*
* TX ucode for the Intel IXP2400 in POS-PHY mode.
* Copyright (C) 2004, 2005 Lennert Buytenhek
* Dedicated to Marija Kulikova.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Assumptions made in this code:
* - The IXP2400 MSF is configured for POS-PHY mode, in a mode where
* only one TBUF partition is used. This includes, for example,
* 1x32 SPHY and 1x32 MPHY32, but not 4x8 SPHY or 1x32 MPHY4. (This
* is not an exhaustive list.)
* - The TBUF uses 64-byte mpackets.
* - TX descriptors reside in SRAM, and have the following format:
* struct tx_desc
* {
* // to uengine
* u32 buf_phys_addr;
* u32 pkt_length;
* u32 channel;
* };
* - Packet data resides in DRAM.
* - Packet buffer addresses are 8-byte aligned.
* - Scratch ring 2 is tx_pending.
* - Scratch ring 3 is tx_done, and has status condition 'full'.
* - This code is run on all eight threads of the microengine it runs on.
*/
#define TX_SEQUENCE_0 0x0060
#define TBUF_CTRL 0x1800
#define PARTITION_SIZE 128
#define PARTITION_THRESH 96
.sig volatile sig1
.sig volatile sig2
.sig volatile sig3
.reg @old_tx_seq_0
.reg @mpkts_in_flight
.reg @next_tbuf_mpacket
.reg @buffer_handle
.reg @buffer_start
.reg @packet_length
.reg @channel
.reg @packet_offset
.reg zero
immed[zero, 0]
/*
* Skip context 0 initialisation?
*/
.begin
br!=ctx[0, mpacket_tx_loop#]
.end
/*
* Wait until all pending TBUF elements have been transmitted.
*/
.begin
.reg read $tx
.sig zzz
loop_empty#:
msf[read, $tx, zero, TX_SEQUENCE_0, 1], ctx_swap[zzz]
alu_shf[--, --, b, $tx, >>31]
beq[loop_empty#]
alu[@old_tx_seq_0, --, b, $tx]
.end
immed[@mpkts_in_flight, 0]
alu[@next_tbuf_mpacket, @old_tx_seq_0, and, (PARTITION_SIZE - 1)]
immed[@buffer_handle, 0]
/*
* Initialise signal pipeline.
*/
.begin
local_csr_wr[SAME_ME_SIGNAL, (&sig1 << 3)]
.set_sig sig1
local_csr_wr[SAME_ME_SIGNAL, (&sig2 << 3)]
.set_sig sig2
local_csr_wr[SAME_ME_SIGNAL, (&sig3 << 3)]
.set_sig sig3
.end
mpacket_tx_loop#:
.begin
.reg tbuf_element_index
.reg buffer_handle
.reg sop_eop
.reg packet_data
.reg channel
.reg mpacket_size
/*
* If there is no packet currently being transmitted,
* dequeue the next TX descriptor, and fetch the buffer
* address, packet length and destination channel number.
*/
.begin
.reg read $stemp $stemp2 $stemp3
.xfer_order $stemp $stemp2 $stemp3
.sig zzz
ctx_arb[sig1]
alu[--, --, b, @buffer_handle]
bne[already_got_packet#]
tx_nobufs#:
scratch[get, $stemp, zero, 8, 1], ctx_swap[zzz]
alu[@buffer_handle, --, b, $stemp]
beq[tx_nobufs#]
sram[read, $stemp, $stemp, 0, 3], ctx_swap[zzz]
alu[@buffer_start, --, b, $stemp]
alu[@packet_length, --, b, $stemp2]
beq[zero_byte_packet#]
alu[@channel, --, b, $stemp3]
immed[@packet_offset, 0]
already_got_packet#:
local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig1 << 3))]
.end
/*
* Determine tbuf element index, SOP/EOP flags, mpacket
* offset and mpacket size and cache buffer_handle and
* channel number.
*/
.begin
alu[tbuf_element_index, --, b, @next_tbuf_mpacket]
alu[@next_tbuf_mpacket, @next_tbuf_mpacket, +, 1]
alu[@next_tbuf_mpacket, @next_tbuf_mpacket, and,
(PARTITION_SIZE - 1)]
alu[buffer_handle, --, b, @buffer_handle]
immed[@buffer_handle, 0]
immed[sop_eop, 1]
alu[packet_data, --, b, @packet_offset]
bne[no_sop#]
alu[sop_eop, sop_eop, or, 2]
no_sop#:
alu[packet_data, packet_data, +, @buffer_start]
alu[channel, --, b, @channel]
alu[mpacket_size, @packet_length, -, @packet_offset]
alu[--, 64, -, mpacket_size]
bhs[eop#]
alu[@buffer_handle, --, b, buffer_handle]
immed[mpacket_size, 64]
alu[sop_eop, sop_eop, and, 2]
eop#:
alu[@packet_offset, @packet_offset, +, mpacket_size]
.end
/*
* Wait until there's enough space in the TBUF.
*/
.begin
.reg read $tx
.reg temp
.sig zzz
ctx_arb[sig2]
br[test_space#]
loop_space#:
msf[read, $tx, zero, TX_SEQUENCE_0, 1], ctx_swap[zzz]
alu[temp, $tx, -, @old_tx_seq_0]
alu[temp, temp, and, 0xff]
alu[@mpkts_in_flight, @mpkts_in_flight, -, temp]
alu[@old_tx_seq_0, --, b, $tx]
test_space#:
alu[--, PARTITION_THRESH, -, @mpkts_in_flight]
blo[loop_space#]
alu[@mpkts_in_flight, @mpkts_in_flight, +, 1]
local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig2 << 3))]
.end
/*
* Copy the packet data to the TBUF.
*/
.begin
.reg temp
.sig copy_sig
alu[temp, mpacket_size, -, 1]
alu_shf[temp, 0x10, or, temp, >>3]
alu_shf[temp, 0x10, or, temp, <<21]
alu_shf[temp, temp, or, tbuf_element_index, <<11]
alu_shf[--, temp, or, 1, <<18]
dram[tbuf_wr, --, packet_data, 0, max_8],
indirect_ref, sig_done[copy_sig]
ctx_arb[copy_sig]
.end
/*
* Mark TBUF element as ready-to-be-transmitted.
*/
.begin
.reg write $tsw $tsw2
.xfer_order $tsw $tsw2
.reg temp
.sig zzz
alu_shf[temp, channel, or, mpacket_size, <<24]
alu_shf[$tsw, temp, or, sop_eop, <<8]
immed[$tsw2, 0]
immed[temp, TBUF_CTRL]
alu_shf[temp, temp, or, tbuf_element_index, <<3]
msf[write, $tsw, temp, 0, 2], ctx_swap[zzz]
.end
/*
* Resynchronise.
*/
.begin
ctx_arb[sig3]
local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig3 << 3))]
.end
/*
* If this was an EOP mpacket, recycle the TX buffer
* and signal the host.
*/
.begin
.reg write $stemp
.sig zzz
alu[--, sop_eop, and, 1]
beq[mpacket_tx_loop#]
tx_done_ring_full#:
br_inp_state[SCR_Ring3_Status, tx_done_ring_full#]
alu[$stemp, --, b, buffer_handle]
scratch[put, $stemp, zero, 12, 1], ctx_swap[zzz]
cap[fast_wr, 0, XSCALE_INT_A]
br[mpacket_tx_loop#]
.end
.end
zero_byte_packet#:
halt

View file

@ -0,0 +1,98 @@
static struct ixp2000_uengine_code ixp2400_tx =
{
.cpu_model_bitmask = 0x000003fe,
.cpu_min_revision = 0,
.cpu_max_revision = 255,
.uengine_parameters = IXP2000_UENGINE_8_CONTEXTS |
IXP2000_UENGINE_PRN_UPDATE_EVERY |
IXP2000_UENGINE_NN_FROM_PREVIOUS |
IXP2000_UENGINE_ASSERT_EMPTY_AT_0 |
IXP2000_UENGINE_LM_ADDR1_PER_CONTEXT |
IXP2000_UENGINE_LM_ADDR0_PER_CONTEXT,
.initial_reg_values = (struct ixp2000_reg_value []) {
{ -1, -1 }
},
.num_insns = 77,
.insns = (u8 []) {
0xf0, 0x00, 0x00, 0x07, 0x00,
0xd8, 0x03, 0x00, 0x00, 0x11,
0x3c, 0x40, 0x00, 0x04, 0xe0,
0x81, 0xf2, 0x02, 0x01, 0x00,
0xd8, 0x00, 0x80, 0x01, 0x00,
0xb0, 0x08, 0x06, 0x00, 0x00,
0xf0, 0x00, 0x0c, 0x00, 0x80,
0xb4, 0x49, 0x02, 0x03, 0x7f,
0xf0, 0x00, 0x02, 0x83, 0x00,
0xfc, 0x10, 0xac, 0x23, 0x08,
0xfc, 0x10, 0xac, 0x43, 0x10,
0xfc, 0x10, 0xac, 0x63, 0x18,
0xe0, 0x00, 0x00, 0x00, 0x02,
0xa0, 0x30, 0x02, 0x80, 0x00,
0xd8, 0x06, 0x00, 0x01, 0x01,
0x19, 0x40, 0x00, 0x04, 0x28,
0xb0, 0x0a, 0x06, 0x00, 0x00,
0xd8, 0x03, 0xc0, 0x01, 0x00,
0x00, 0x44, 0x00, 0x80, 0x80,
0xa0, 0x09, 0x06, 0x00, 0x00,
0xb0, 0x0b, 0x06, 0x04, 0x00,
0xd8, 0x13, 0x00, 0x01, 0x00,
0xb0, 0x0c, 0x06, 0x08, 0x00,
0xf0, 0x00, 0x0c, 0x00, 0xa0,
0xfc, 0x10, 0xae, 0x23, 0x88,
0xa0, 0x00, 0x12, 0x40, 0x00,
0xb0, 0xc9, 0x02, 0x43, 0x01,
0xb4, 0x49, 0x02, 0x43, 0x7f,
0xb0, 0x00, 0x22, 0x80, 0x00,
0xf0, 0x00, 0x02, 0x83, 0x00,
0xf0, 0x00, 0x0c, 0x04, 0x02,
0xb0, 0x40, 0x6c, 0x00, 0xa0,
0xd8, 0x08, 0x80, 0x01, 0x01,
0xaa, 0x00, 0x2c, 0x08, 0x02,
0xa0, 0xc0, 0x30, 0x18, 0x90,
0xa0, 0x00, 0x43, 0x00, 0x00,
0xba, 0xc0, 0x32, 0xc0, 0xa0,
0xaa, 0xb0, 0x00, 0x0f, 0x40,
0xd8, 0x0a, 0x80, 0x01, 0x04,
0xb0, 0x0a, 0x00, 0x08, 0x00,
0xf0, 0x00, 0x00, 0x0f, 0x40,
0xa4, 0x00, 0x2c, 0x08, 0x02,
0xa0, 0x8a, 0x00, 0x0c, 0xa0,
0xe0, 0x00, 0x00, 0x00, 0x04,
0xd8, 0x0c, 0x80, 0x00, 0x18,
0x3c, 0x40, 0x00, 0x04, 0xe0,
0xba, 0x80, 0x42, 0x01, 0x80,
0xb4, 0x40, 0x40, 0x13, 0xff,
0xaa, 0x88, 0x00, 0x10, 0x80,
0xb0, 0x08, 0x06, 0x00, 0x00,
0xaa, 0xf0, 0x0d, 0x80, 0x80,
0xd8, 0x0b, 0x40, 0x01, 0x05,
0xa0, 0x88, 0x0c, 0x04, 0x80,
0xfc, 0x10, 0xae, 0x43, 0x90,
0xba, 0xc0, 0x50, 0x0f, 0x01,
0x9a, 0x30, 0x50, 0x15, 0x30,
0x9a, 0xb0, 0x50, 0x16, 0x30,
0x9b, 0x50, 0x58, 0x16, 0x01,
0x8a, 0xe2, 0x08, 0x16, 0x21,
0x6b, 0x4e, 0x00, 0x83, 0x03,
0xe0, 0x00, 0x00, 0x00, 0x30,
0x9a, 0x80, 0x70, 0x0e, 0x04,
0x8b, 0x88, 0x08, 0x1e, 0x02,
0xf0, 0x00, 0x0c, 0x01, 0x81,
0xf0, 0x01, 0x80, 0x1f, 0x00,
0x9b, 0xd0, 0x78, 0x1e, 0x01,
0x3d, 0x42, 0x00, 0x1c, 0x20,
0xe0, 0x00, 0x00, 0x00, 0x08,
0xfc, 0x10, 0xae, 0x63, 0x98,
0xa4, 0x30, 0x0c, 0x04, 0x02,
0xd8, 0x03, 0x00, 0x01, 0x00,
0xd8, 0x11, 0xc1, 0x42, 0x14,
0xa0, 0x18, 0x00, 0x08, 0x00,
0x1a, 0x40, 0x00, 0x04, 0x2c,
0x33, 0x00, 0x01, 0x2f, 0x20,
0xd8, 0x03, 0x00, 0x00, 0x18,
0xe0, 0x00, 0x02, 0x00, 0x00,
}
};

View file

@ -0,0 +1,421 @@
/*
* IXP2000 MSF network device driver
* Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
* Dedicated to Marija Kulikova.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <asm/arch/uengine.h>
#include <asm/mach-types.h>
#include <asm/io.h>
#include "ixp2400_rx.ucode"
#include "ixp2400_tx.ucode"
#include "ixpdev_priv.h"
#include "ixpdev.h"
#define DRV_MODULE_VERSION "0.2"
static int nds_count;
static struct net_device **nds;
static int nds_open;
static void (*set_port_admin_status)(int port, int up);
static struct ixpdev_rx_desc * const rx_desc =
(struct ixpdev_rx_desc *)(IXP2000_SRAM0_VIRT_BASE + RX_BUF_DESC_BASE);
static struct ixpdev_tx_desc * const tx_desc =
(struct ixpdev_tx_desc *)(IXP2000_SRAM0_VIRT_BASE + TX_BUF_DESC_BASE);
static int tx_pointer;
static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ixpdev_priv *ip = netdev_priv(dev);
struct ixpdev_tx_desc *desc;
int entry;
if (unlikely(skb->len > PAGE_SIZE)) {
/* @@@ Count drops. */
dev_kfree_skb(skb);
return 0;
}
entry = tx_pointer;
tx_pointer = (tx_pointer + 1) % TX_BUF_COUNT;
desc = tx_desc + entry;
desc->pkt_length = skb->len;
desc->channel = ip->channel;
skb_copy_and_csum_dev(skb, phys_to_virt(desc->buf_addr));
dev_kfree_skb(skb);
ixp2000_reg_write(RING_TX_PENDING,
TX_BUF_DESC_BASE + (entry * sizeof(struct ixpdev_tx_desc)));
dev->trans_start = jiffies;
local_irq_disable();
ip->tx_queue_entries++;
if (ip->tx_queue_entries == TX_BUF_COUNT_PER_CHAN)
netif_stop_queue(dev);
local_irq_enable();
return 0;
}
static int ixpdev_rx(struct net_device *dev, int *budget)
{
while (*budget > 0) {
struct ixpdev_rx_desc *desc;
struct sk_buff *skb;
void *buf;
u32 _desc;
_desc = ixp2000_reg_read(RING_RX_DONE);
if (_desc == 0)
return 0;
desc = rx_desc +
((_desc - RX_BUF_DESC_BASE) / sizeof(struct ixpdev_rx_desc));
buf = phys_to_virt(desc->buf_addr);
if (desc->pkt_length < 4 || desc->pkt_length > PAGE_SIZE) {
printk(KERN_ERR "ixp2000: rx err, length %d\n",
desc->pkt_length);
goto err;
}
if (desc->channel < 0 || desc->channel >= nds_count) {
printk(KERN_ERR "ixp2000: rx err, channel %d\n",
desc->channel);
goto err;
}
/* @@@ Make FCS stripping configurable. */
desc->pkt_length -= 4;
if (unlikely(!netif_running(nds[desc->channel])))
goto err;
skb = dev_alloc_skb(desc->pkt_length + 2);
if (likely(skb != NULL)) {
skb->dev = nds[desc->channel];
skb_reserve(skb, 2);
eth_copy_and_sum(skb, buf, desc->pkt_length, 0);
skb_put(skb, desc->pkt_length);
skb->protocol = eth_type_trans(skb, skb->dev);
skb->dev->last_rx = jiffies;
netif_receive_skb(skb);
}
err:
ixp2000_reg_write(RING_RX_PENDING, _desc);
dev->quota--;
(*budget)--;
}
return 1;
}
/* dev always points to nds[0]. */
static int ixpdev_poll(struct net_device *dev, int *budget)
{
/* @@@ Have to stop polling when nds[0] is administratively
* downed while we are polling. */
do {
ixp2000_reg_write(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0x00ff);
if (ixpdev_rx(dev, budget))
return 1;
} while (ixp2000_reg_read(IXP2000_IRQ_THD_RAW_STATUS_A_0) & 0x00ff);
netif_rx_complete(dev);
ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0x00ff);
return 0;
}
static void ixpdev_tx_complete(void)
{
int channel;
u32 wake;
wake = 0;
while (1) {
struct ixpdev_priv *ip;
u32 desc;
int entry;
desc = ixp2000_reg_read(RING_TX_DONE);
if (desc == 0)
break;
/* @@@ Check whether entries come back in order. */
entry = (desc - TX_BUF_DESC_BASE) / sizeof(struct ixpdev_tx_desc);
channel = tx_desc[entry].channel;
if (channel < 0 || channel >= nds_count) {
printk(KERN_ERR "ixp2000: txcomp channel index "
"out of bounds (%d, %.8i, %d)\n",
channel, (unsigned int)desc, entry);
continue;
}
ip = netdev_priv(nds[channel]);
if (ip->tx_queue_entries == TX_BUF_COUNT_PER_CHAN)
wake |= 1 << channel;
ip->tx_queue_entries--;
}
for (channel = 0; wake != 0; channel++) {
if (wake & (1 << channel)) {
netif_wake_queue(nds[channel]);
wake &= ~(1 << channel);
}
}
}
static irqreturn_t ixpdev_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
u32 status;
status = ixp2000_reg_read(IXP2000_IRQ_THD_STATUS_A_0);
if (status == 0)
return IRQ_NONE;
/*
* Any of the eight receive units signaled RX?
*/
if (status & 0x00ff) {
ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff);
if (likely(__netif_rx_schedule_prep(nds[0]))) {
__netif_rx_schedule(nds[0]);
} else {
printk(KERN_CRIT "ixp2000: irq while polling!!\n");
}
}
/*
* Any of the eight transmit units signaled TXdone?
*/
if (status & 0xff00) {
ixp2000_reg_wrb(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0xff00);
ixpdev_tx_complete();
}
return IRQ_HANDLED;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
static void ixpdev_poll_controller(struct net_device *dev)
{
disable_irq(IRQ_IXP2000_THDA0);
ixpdev_interrupt(IRQ_IXP2000_THDA0, dev, NULL);
enable_irq(IRQ_IXP2000_THDA0);
}
#endif
static int ixpdev_open(struct net_device *dev)
{
struct ixpdev_priv *ip = netdev_priv(dev);
int err;
if (!nds_open++) {
err = request_irq(IRQ_IXP2000_THDA0, ixpdev_interrupt,
SA_SHIRQ, "ixp2000_eth", nds);
if (err) {
nds_open--;
return err;
}
ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0xffff);
}
set_port_admin_status(ip->channel, 1);
netif_start_queue(dev);
return 0;
}
static int ixpdev_close(struct net_device *dev)
{
struct ixpdev_priv *ip = netdev_priv(dev);
netif_stop_queue(dev);
set_port_admin_status(ip->channel, 0);
if (!--nds_open) {
ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0xffff);
free_irq(IRQ_IXP2000_THDA0, nds);
}
return 0;
}
struct net_device *ixpdev_alloc(int channel, int sizeof_priv)
{
struct net_device *dev;
struct ixpdev_priv *ip;
dev = alloc_etherdev(sizeof_priv);
if (dev == NULL)
return NULL;
dev->hard_start_xmit = ixpdev_xmit;
dev->poll = ixpdev_poll;
dev->open = ixpdev_open;
dev->stop = ixpdev_close;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = ixpdev_poll_controller;
#endif
dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
dev->weight = 64;
ip = netdev_priv(dev);
ip->channel = channel;
ip->tx_queue_entries = 0;
return dev;
}
int ixpdev_init(int __nds_count, struct net_device **__nds,
void (*__set_port_admin_status)(int port, int up))
{
int i;
int err;
if (RX_BUF_COUNT > 192 || TX_BUF_COUNT > 192) {
static void __too_many_rx_or_tx_buffers(void);
__too_many_rx_or_tx_buffers();
}
printk(KERN_INFO "IXP2000 MSF ethernet driver %s\n", DRV_MODULE_VERSION);
nds_count = __nds_count;
nds = __nds;
set_port_admin_status = __set_port_admin_status;
for (i = 0; i < RX_BUF_COUNT; i++) {
void *buf;
buf = (void *)get_zeroed_page(GFP_KERNEL);
if (buf == NULL) {
err = -ENOMEM;
while (--i >= 0)
free_page((unsigned long)phys_to_virt(rx_desc[i].buf_addr));
goto err_out;
}
rx_desc[i].buf_addr = virt_to_phys(buf);
rx_desc[i].buf_length = PAGE_SIZE;
}
/* @@@ Maybe we shouldn't be preallocating TX buffers. */
for (i = 0; i < TX_BUF_COUNT; i++) {
void *buf;
buf = (void *)get_zeroed_page(GFP_KERNEL);
if (buf == NULL) {
err = -ENOMEM;
while (--i >= 0)
free_page((unsigned long)phys_to_virt(tx_desc[i].buf_addr));
goto err_free_rx;
}
tx_desc[i].buf_addr = virt_to_phys(buf);
}
/* 256 entries, ring status set means 'empty', base address 0x0000. */
ixp2000_reg_write(RING_RX_PENDING_BASE, 0x44000000);
ixp2000_reg_write(RING_RX_PENDING_HEAD, 0x00000000);
ixp2000_reg_write(RING_RX_PENDING_TAIL, 0x00000000);
/* 256 entries, ring status set means 'full', base address 0x0400. */
ixp2000_reg_write(RING_RX_DONE_BASE, 0x40000400);
ixp2000_reg_write(RING_RX_DONE_HEAD, 0x00000000);
ixp2000_reg_write(RING_RX_DONE_TAIL, 0x00000000);
for (i = 0; i < RX_BUF_COUNT; i++) {
ixp2000_reg_write(RING_RX_PENDING,
RX_BUF_DESC_BASE + (i * sizeof(struct ixpdev_rx_desc)));
}
ixp2000_uengine_load(0, &ixp2400_rx);
ixp2000_uengine_start_contexts(0, 0xff);
/* 256 entries, ring status set means 'empty', base address 0x0800. */
ixp2000_reg_write(RING_TX_PENDING_BASE, 0x44000800);
ixp2000_reg_write(RING_TX_PENDING_HEAD, 0x00000000);
ixp2000_reg_write(RING_TX_PENDING_TAIL, 0x00000000);
/* 256 entries, ring status set means 'full', base address 0x0c00. */
ixp2000_reg_write(RING_TX_DONE_BASE, 0x40000c00);
ixp2000_reg_write(RING_TX_DONE_HEAD, 0x00000000);
ixp2000_reg_write(RING_TX_DONE_TAIL, 0x00000000);
ixp2000_uengine_load(1, &ixp2400_tx);
ixp2000_uengine_start_contexts(1, 0xff);
for (i = 0; i < nds_count; i++) {
err = register_netdev(nds[i]);
if (err) {
while (--i >= 0)
unregister_netdev(nds[i]);
goto err_free_tx;
}
}
for (i = 0; i < nds_count; i++) {
printk(KERN_INFO "%s: IXP2000 MSF ethernet (port %d), "
"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x.\n", nds[i]->name, i,
nds[i]->dev_addr[0], nds[i]->dev_addr[1],
nds[i]->dev_addr[2], nds[i]->dev_addr[3],
nds[i]->dev_addr[4], nds[i]->dev_addr[5]);
}
return 0;
err_free_tx:
for (i = 0; i < TX_BUF_COUNT; i++)
free_page((unsigned long)phys_to_virt(tx_desc[i].buf_addr));
err_free_rx:
for (i = 0; i < RX_BUF_COUNT; i++)
free_page((unsigned long)phys_to_virt(rx_desc[i].buf_addr));
err_out:
return err;
}
void ixpdev_deinit(void)
{
int i;
/* @@@ Flush out pending packets. */
for (i = 0; i < nds_count; i++)
unregister_netdev(nds[i]);
ixp2000_uengine_stop_contexts(1, 0xff);
ixp2000_uengine_stop_contexts(0, 0xff);
ixp2000_uengine_reset(0x3);
for (i = 0; i < TX_BUF_COUNT; i++)
free_page((unsigned long)phys_to_virt(tx_desc[i].buf_addr));
for (i = 0; i < RX_BUF_COUNT; i++)
free_page((unsigned long)phys_to_virt(rx_desc[i].buf_addr));
}

View file

@ -0,0 +1,27 @@
/*
* IXP2000 MSF network device driver
* Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
* Dedicated to Marija Kulikova.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __IXPDEV_H
#define __IXPDEV_H
struct ixpdev_priv
{
int channel;
int tx_queue_entries;
};
struct net_device *ixpdev_alloc(int channel, int sizeof_priv);
int ixpdev_init(int num_ports, struct net_device **nds,
void (*set_port_admin_status)(int port, int up));
void ixpdev_deinit(void);
#endif

View file

@ -0,0 +1,57 @@
/*
* IXP2000 MSF network device driver
* Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
* Dedicated to Marija Kulikova.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __IXPDEV_PRIV_H
#define __IXPDEV_PRIV_H
#define RX_BUF_DESC_BASE 0x00001000
#define RX_BUF_COUNT ((3 * PAGE_SIZE) / (4 * sizeof(struct ixpdev_rx_desc)))
#define TX_BUF_DESC_BASE 0x00002000
#define TX_BUF_COUNT ((3 * PAGE_SIZE) / (4 * sizeof(struct ixpdev_tx_desc)))
#define TX_BUF_COUNT_PER_CHAN (TX_BUF_COUNT / 4)
#define RING_RX_PENDING ((u32 *)IXP2000_SCRATCH_RING_VIRT_BASE)
#define RING_RX_DONE ((u32 *)(IXP2000_SCRATCH_RING_VIRT_BASE + 4))
#define RING_TX_PENDING ((u32 *)(IXP2000_SCRATCH_RING_VIRT_BASE + 8))
#define RING_TX_DONE ((u32 *)(IXP2000_SCRATCH_RING_VIRT_BASE + 12))
#define SCRATCH_REG(x) ((u32 *)(IXP2000_GLOBAL_REG_VIRT_BASE | 0x0800 | (x)))
#define RING_RX_PENDING_BASE SCRATCH_REG(0x00)
#define RING_RX_PENDING_HEAD SCRATCH_REG(0x04)
#define RING_RX_PENDING_TAIL SCRATCH_REG(0x08)
#define RING_RX_DONE_BASE SCRATCH_REG(0x10)
#define RING_RX_DONE_HEAD SCRATCH_REG(0x14)
#define RING_RX_DONE_TAIL SCRATCH_REG(0x18)
#define RING_TX_PENDING_BASE SCRATCH_REG(0x20)
#define RING_TX_PENDING_HEAD SCRATCH_REG(0x24)
#define RING_TX_PENDING_TAIL SCRATCH_REG(0x28)
#define RING_TX_DONE_BASE SCRATCH_REG(0x30)
#define RING_TX_DONE_HEAD SCRATCH_REG(0x34)
#define RING_TX_DONE_TAIL SCRATCH_REG(0x38)
struct ixpdev_rx_desc
{
u32 buf_addr;
u32 buf_length;
u32 channel;
u32 pkt_length;
};
struct ixpdev_tx_desc
{
u32 buf_addr;
u32 pkt_length;
u32 channel;
u32 unused;
};
#endif

View file

@ -0,0 +1,334 @@
/*
* Helper functions for the PM3386s on the Radisys ENP2611
* Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
* Dedicated to Marija Kulikova.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <asm/io.h>
#include "pm3386.h"
/*
* Read from register 'reg' of PM3386 device 'pm'.
*/
static u16 pm3386_reg_read(int pm, int reg)
{
void *_reg;
u16 value;
_reg = (void *)ENP2611_PM3386_0_VIRT_BASE;
if (pm == 1)
_reg = (void *)ENP2611_PM3386_1_VIRT_BASE;
value = *((volatile u16 *)(_reg + (reg << 1)));
// printk(KERN_INFO "pm3386_reg_read(%d, %.3x) = %.8x\n", pm, reg, value);
return value;
}
/*
* Write to register 'reg' of PM3386 device 'pm', and perform
* a readback from the identification register.
*/
static void pm3386_reg_write(int pm, int reg, u16 value)
{
void *_reg;
u16 dummy;
// printk(KERN_INFO "pm3386_reg_write(%d, %.3x, %.8x)\n", pm, reg, value);
_reg = (void *)ENP2611_PM3386_0_VIRT_BASE;
if (pm == 1)
_reg = (void *)ENP2611_PM3386_1_VIRT_BASE;
*((volatile u16 *)(_reg + (reg << 1))) = value;
dummy = *((volatile u16 *)_reg);
__asm__ __volatile__("mov %0, %0" : "+r" (dummy));
}
/*
* Read from port 'port' register 'reg', where the registers
* for the different ports are 'spacing' registers apart.
*/
static u16 pm3386_port_reg_read(int port, int _reg, int spacing)
{
int reg;
reg = _reg;
if (port & 1)
reg += spacing;
return pm3386_reg_read(port >> 1, reg);
}
/*
* Write to port 'port' register 'reg', where the registers
* for the different ports are 'spacing' registers apart.
*/
static void pm3386_port_reg_write(int port, int _reg, int spacing, u16 value)
{
int reg;
reg = _reg;
if (port & 1)
reg += spacing;
pm3386_reg_write(port >> 1, reg, value);
}
void pm3386_reset(void)
{
u8 mac[3][6];
/* Save programmed MAC addresses. */
pm3386_get_mac(0, mac[0]);
pm3386_get_mac(1, mac[1]);
pm3386_get_mac(2, mac[2]);
/* Assert analog and digital reset. */
pm3386_reg_write(0, 0x002, 0x0060);
pm3386_reg_write(1, 0x002, 0x0060);
mdelay(1);
/* Deassert analog reset. */
pm3386_reg_write(0, 0x002, 0x0062);
pm3386_reg_write(1, 0x002, 0x0062);
mdelay(10);
/* Deassert digital reset. */
pm3386_reg_write(0, 0x002, 0x0063);
pm3386_reg_write(1, 0x002, 0x0063);
mdelay(10);
/* Restore programmed MAC addresses. */
pm3386_set_mac(0, mac[0]);
pm3386_set_mac(1, mac[1]);
pm3386_set_mac(2, mac[2]);
/* Disable carrier on all ports. */
pm3386_set_carrier(0, 0);
pm3386_set_carrier(1, 0);
pm3386_set_carrier(2, 0);
}
static u16 swaph(u16 x)
{
return ((x << 8) | (x >> 8)) & 0xffff;
}
void pm3386_init_port(int port)
{
int pm = port >> 1;
/*
* Work around ENP2611 bootloader programming MAC address
* in reverse.
*/
if (pm3386_port_reg_read(port, 0x30a, 0x100) == 0x0000 &&
(pm3386_port_reg_read(port, 0x309, 0x100) & 0xff00) == 0x5000) {
u16 temp[3];
temp[0] = pm3386_port_reg_read(port, 0x308, 0x100);
temp[1] = pm3386_port_reg_read(port, 0x309, 0x100);
temp[2] = pm3386_port_reg_read(port, 0x30a, 0x100);
pm3386_port_reg_write(port, 0x308, 0x100, swaph(temp[2]));
pm3386_port_reg_write(port, 0x309, 0x100, swaph(temp[1]));
pm3386_port_reg_write(port, 0x30a, 0x100, swaph(temp[0]));
}
/*
* Initialise narrowbanding mode. See application note 2010486
* for more information. (@@@ We also need to issue a reset
* when ROOL or DOOL are detected.)
*/
pm3386_port_reg_write(port, 0x708, 0x10, 0xd055);
udelay(500);
pm3386_port_reg_write(port, 0x708, 0x10, 0x5055);
/*
* SPI-3 ingress block. Set 64 bytes SPI-3 burst size
* towards SPI-3 bridge.
*/
pm3386_port_reg_write(port, 0x122, 0x20, 0x0002);
/*
* Enable ingress protocol checking, and soft reset the
* SPI-3 ingress block.
*/
pm3386_reg_write(pm, 0x103, 0x0003);
while (!(pm3386_reg_read(pm, 0x103) & 0x80))
;
/*
* SPI-3 egress block. Gather 12288 bytes of the current
* packet in the TX fifo before initiating transmit on the
* SERDES interface. (Prevents TX underflows.)
*/
pm3386_port_reg_write(port, 0x221, 0x20, 0x0007);
/*
* Enforce odd parity from the SPI-3 bridge, and soft reset
* the SPI-3 egress block.
*/
pm3386_reg_write(pm, 0x203, 0x000d & ~(4 << (port & 1)));
while ((pm3386_reg_read(pm, 0x203) & 0x000c) != 0x000c)
;
/*
* EGMAC block. Set this channels to reject long preambles,
* not send or transmit PAUSE frames, enable preamble checking,
* disable frame length checking, enable FCS appending, enable
* TX frame padding.
*/
pm3386_port_reg_write(port, 0x302, 0x100, 0x0113);
/*
* Soft reset the EGMAC block.
*/
pm3386_port_reg_write(port, 0x301, 0x100, 0x8000);
pm3386_port_reg_write(port, 0x301, 0x100, 0x0000);
/*
* Auto-sense autonegotiation status.
*/
pm3386_port_reg_write(port, 0x306, 0x100, 0x0100);
/*
* Allow reception of jumbo frames.
*/
pm3386_port_reg_write(port, 0x310, 0x100, 9018);
/*
* Allow transmission of jumbo frames.
*/
pm3386_port_reg_write(port, 0x336, 0x100, 9018);
/* @@@ Should set 0x337/0x437 (RX forwarding threshold.) */
/*
* Set autonegotiation parameters to 'no PAUSE, full duplex.'
*/
pm3386_port_reg_write(port, 0x31c, 0x100, 0x0020);
/*
* Enable and restart autonegotiation.
*/
pm3386_port_reg_write(port, 0x318, 0x100, 0x0003);
pm3386_port_reg_write(port, 0x318, 0x100, 0x0002);
}
void pm3386_get_mac(int port, u8 *mac)
{
u16 temp;
temp = pm3386_port_reg_read(port, 0x308, 0x100);
mac[0] = temp & 0xff;
mac[1] = (temp >> 8) & 0xff;
temp = pm3386_port_reg_read(port, 0x309, 0x100);
mac[2] = temp & 0xff;
mac[3] = (temp >> 8) & 0xff;
temp = pm3386_port_reg_read(port, 0x30a, 0x100);
mac[4] = temp & 0xff;
mac[5] = (temp >> 8) & 0xff;
}
void pm3386_set_mac(int port, u8 *mac)
{
pm3386_port_reg_write(port, 0x308, 0x100, (mac[1] << 8) | mac[0]);
pm3386_port_reg_write(port, 0x309, 0x100, (mac[3] << 8) | mac[2]);
pm3386_port_reg_write(port, 0x30a, 0x100, (mac[5] << 8) | mac[4]);
}
static u32 pm3386_get_stat(int port, u16 base)
{
u32 value;
value = pm3386_port_reg_read(port, base, 0x100);
value |= pm3386_port_reg_read(port, base + 1, 0x100) << 16;
return value;
}
void pm3386_get_stats(int port, struct net_device_stats *stats)
{
/*
* Snapshot statistics counters.
*/
pm3386_port_reg_write(port, 0x500, 0x100, 0x0001);
while (pm3386_port_reg_read(port, 0x500, 0x100) & 0x0001)
;
memset(stats, 0, sizeof(*stats));
stats->rx_packets = pm3386_get_stat(port, 0x510);
stats->tx_packets = pm3386_get_stat(port, 0x590);
stats->rx_bytes = pm3386_get_stat(port, 0x514);
stats->tx_bytes = pm3386_get_stat(port, 0x594);
/* @@@ Add other stats. */
}
void pm3386_set_carrier(int port, int state)
{
pm3386_port_reg_write(port, 0x703, 0x10, state ? 0x1001 : 0x0000);
}
int pm3386_is_link_up(int port)
{
u16 temp;
temp = pm3386_port_reg_read(port, 0x31a, 0x100);
temp = pm3386_port_reg_read(port, 0x31a, 0x100);
return !!(temp & 0x0002);
}
void pm3386_enable_rx(int port)
{
u16 temp;
temp = pm3386_port_reg_read(port, 0x303, 0x100);
temp |= 0x1000;
pm3386_port_reg_write(port, 0x303, 0x100, temp);
}
void pm3386_disable_rx(int port)
{
u16 temp;
temp = pm3386_port_reg_read(port, 0x303, 0x100);
temp &= 0xefff;
pm3386_port_reg_write(port, 0x303, 0x100, temp);
}
void pm3386_enable_tx(int port)
{
u16 temp;
temp = pm3386_port_reg_read(port, 0x303, 0x100);
temp |= 0x4000;
pm3386_port_reg_write(port, 0x303, 0x100, temp);
}
void pm3386_disable_tx(int port)
{
u16 temp;
temp = pm3386_port_reg_read(port, 0x303, 0x100);
temp &= 0xbfff;
pm3386_port_reg_write(port, 0x303, 0x100, temp);
}
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,28 @@
/*
* Helper functions for the PM3386s on the Radisys ENP2611
* Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
* Dedicated to Marija Kulikova.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __PM3386_H
#define __PM3386_H
void pm3386_reset(void);
void pm3386_init_port(int port);
void pm3386_get_mac(int port, u8 *mac);
void pm3386_set_mac(int port, u8 *mac);
void pm3386_get_stats(int port, struct net_device_stats *stats);
void pm3386_set_carrier(int port, int state);
int pm3386_is_link_up(int port);
void pm3386_enable_rx(int port);
void pm3386_disable_rx(int port);
void pm3386_enable_tx(int port);
void pm3386_disable_tx(int port);
#endif

View file

@ -66,7 +66,7 @@
#include "s2io.h"
#include "s2io-regs.h"
#define DRV_VERSION "Version 2.0.9.3"
#define DRV_VERSION "Version 2.0.9.4"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@ -412,7 +412,7 @@ static int init_shared_mem(struct s2io_nic *nic)
config->tx_cfg[i].fifo_len - 1;
mac_control->fifos[i].fifo_no = i;
mac_control->fifos[i].nic = nic;
mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 1;
mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 2;
for (j = 0; j < page_num; j++) {
int k = 0;
@ -459,6 +459,10 @@ static int init_shared_mem(struct s2io_nic *nic)
}
}
nic->ufo_in_band_v = kmalloc((sizeof(u64) * size), GFP_KERNEL);
if (!nic->ufo_in_band_v)
return -ENOMEM;
/* Allocation and initialization of RXDs in Rings */
size = 0;
for (i = 0; i < config->rx_ring_num; i++) {
@ -731,6 +735,8 @@ static void free_shared_mem(struct s2io_nic *nic)
mac_control->stats_mem,
mac_control->stats_mem_phy);
}
if (nic->ufo_in_band_v)
kfree(nic->ufo_in_band_v);
}
/**
@ -2003,6 +2009,49 @@ static int start_nic(struct s2io_nic *nic)
return SUCCESS;
}
/**
* s2io_txdl_getskb - Get the skb from txdl, unmap and return skb
*/
static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, int get_off)
{
nic_t *nic = fifo_data->nic;
struct sk_buff *skb;
TxD_t *txds;
u16 j, frg_cnt;
txds = txdlp;
if (txds->Host_Control == (u64)(long)nic->ufo_in_band_v) {
pci_unmap_single(nic->pdev, (dma_addr_t)
txds->Buffer_Pointer, sizeof(u64),
PCI_DMA_TODEVICE);
txds++;
}
skb = (struct sk_buff *) ((unsigned long)
txds->Host_Control);
if (!skb) {
memset(txdlp, 0, (sizeof(TxD_t) * fifo_data->max_txds));
return NULL;
}
pci_unmap_single(nic->pdev, (dma_addr_t)
txds->Buffer_Pointer,
skb->len - skb->data_len,
PCI_DMA_TODEVICE);
frg_cnt = skb_shinfo(skb)->nr_frags;
if (frg_cnt) {
txds++;
for (j = 0; j < frg_cnt; j++, txds++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[j];
if (!txds->Buffer_Pointer)
break;
pci_unmap_page(nic->pdev, (dma_addr_t)
txds->Buffer_Pointer,
frag->size, PCI_DMA_TODEVICE);
}
}
txdlp->Host_Control = 0;
return(skb);
}
/**
* free_tx_buffers - Free all queued Tx buffers
@ -2020,7 +2069,7 @@ static void free_tx_buffers(struct s2io_nic *nic)
int i, j;
mac_info_t *mac_control;
struct config_param *config;
int cnt = 0, frg_cnt;
int cnt = 0;
mac_control = &nic->mac_control;
config = &nic->config;
@ -2029,38 +2078,11 @@ static void free_tx_buffers(struct s2io_nic *nic)
for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
txdp = (TxD_t *) mac_control->fifos[i].list_info[j].
list_virt_addr;
skb =
(struct sk_buff *) ((unsigned long) txdp->
Host_Control);
if (skb == NULL) {
memset(txdp, 0, sizeof(TxD_t) *
config->max_txds);
continue;
skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
if (skb) {
dev_kfree_skb(skb);
cnt++;
}
frg_cnt = skb_shinfo(skb)->nr_frags;
pci_unmap_single(nic->pdev, (dma_addr_t)
txdp->Buffer_Pointer,
skb->len - skb->data_len,
PCI_DMA_TODEVICE);
if (frg_cnt) {
TxD_t *temp;
temp = txdp;
txdp++;
for (j = 0; j < frg_cnt; j++, txdp++) {
skb_frag_t *frag =
&skb_shinfo(skb)->frags[j];
pci_unmap_page(nic->pdev,
(dma_addr_t)
txdp->
Buffer_Pointer,
frag->size,
PCI_DMA_TODEVICE);
}
txdp = temp;
}
dev_kfree_skb(skb);
memset(txdp, 0, sizeof(TxD_t) * config->max_txds);
cnt++;
}
DBG_PRINT(INTR_DBG,
"%s:forcibly freeing %d skbs on FIFO%d\n",
@ -2661,7 +2683,6 @@ static void tx_intr_handler(fifo_info_t *fifo_data)
tx_curr_get_info_t get_info, put_info;
struct sk_buff *skb;
TxD_t *txdlp;
u16 j, frg_cnt;
get_info = fifo_data->tx_curr_get_info;
put_info = fifo_data->tx_curr_put_info;
@ -2684,8 +2705,7 @@ to loss of link\n");
}
}
skb = (struct sk_buff *) ((unsigned long)
txdlp->Host_Control);
skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset);
if (skb == NULL) {
DBG_PRINT(ERR_DBG, "%s: Null skb ",
__FUNCTION__);
@ -2693,34 +2713,6 @@ to loss of link\n");
return;
}
frg_cnt = skb_shinfo(skb)->nr_frags;
nic->tx_pkt_count++;
pci_unmap_single(nic->pdev, (dma_addr_t)
txdlp->Buffer_Pointer,
skb->len - skb->data_len,
PCI_DMA_TODEVICE);
if (frg_cnt) {
TxD_t *temp;
temp = txdlp;
txdlp++;
for (j = 0; j < frg_cnt; j++, txdlp++) {
skb_frag_t *frag =
&skb_shinfo(skb)->frags[j];
if (!txdlp->Buffer_Pointer)
break;
pci_unmap_page(nic->pdev,
(dma_addr_t)
txdlp->
Buffer_Pointer,
frag->size,
PCI_DMA_TODEVICE);
}
txdlp = temp;
}
memset(txdlp, 0,
(sizeof(TxD_t) * fifo_data->max_txds));
/* Updating the statistics block */
nic->stats.tx_bytes += skb->len;
dev_kfree_skb_irq(skb);
@ -3331,7 +3323,7 @@ failed\n", dev->name);
s2io_msix_fifo_handle, 0, sp->desc1,
sp->s2io_entries[i].arg);
DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc1,
sp->msix_info[i].addr);
(unsigned long long)sp->msix_info[i].addr);
} else {
sprintf(sp->desc2, "%s:MSI-X-%d-RX",
dev->name, i);
@ -3339,7 +3331,7 @@ failed\n", dev->name);
s2io_msix_ring_handle, 0, sp->desc2,
sp->s2io_entries[i].arg);
DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc2,
sp->msix_info[i].addr);
(unsigned long long)sp->msix_info[i].addr);
}
if (err) {
DBG_PRINT(ERR_DBG, "%s: MSI-X-%d registration \
@ -3527,6 +3519,8 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
txdp->Control_1 = 0;
txdp->Control_2 = 0;
#ifdef NETIF_F_TSO
mss = skb_shinfo(skb)->tso_size;
if (mss) {
@ -3534,19 +3528,13 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
txdp->Control_1 |= TXD_TCP_LSO_MSS(mss);
}
#endif
frg_cnt = skb_shinfo(skb)->nr_frags;
frg_len = skb->len - skb->data_len;
txdp->Buffer_Pointer = pci_map_single
(sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
txdp->Host_Control = (unsigned long) skb;
if (skb->ip_summed == CHECKSUM_HW) {
txdp->Control_2 |=
(TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
TXD_TX_CKO_UDP_EN);
}
txdp->Control_1 |= TXD_GATHER_CODE_FIRST;
txdp->Control_1 |= TXD_LIST_OWN_XENA;
txdp->Control_2 |= config->tx_intr_type;
if (sp->vlgrp && vlan_tx_tag_present(skb)) {
@ -3554,10 +3542,40 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag);
}
txdp->Control_1 |= (TXD_BUFFER0_SIZE(frg_len) |
TXD_GATHER_CODE_FIRST);
txdp->Control_1 |= TXD_LIST_OWN_XENA;
frg_len = skb->len - skb->data_len;
if (skb_shinfo(skb)->ufo_size) {
int ufo_size;
ufo_size = skb_shinfo(skb)->ufo_size;
ufo_size &= ~7;
txdp->Control_1 |= TXD_UFO_EN;
txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
txdp->Control_1 |= TXD_BUFFER0_SIZE(8);
#ifdef __BIG_ENDIAN
sp->ufo_in_band_v[put_off] =
(u64)skb_shinfo(skb)->ip6_frag_id;
#else
sp->ufo_in_band_v[put_off] =
(u64)skb_shinfo(skb)->ip6_frag_id << 32;
#endif
txdp->Host_Control = (unsigned long)sp->ufo_in_band_v;
txdp->Buffer_Pointer = pci_map_single(sp->pdev,
sp->ufo_in_band_v,
sizeof(u64), PCI_DMA_TODEVICE);
txdp++;
txdp->Control_1 = 0;
txdp->Control_2 = 0;
}
txdp->Buffer_Pointer = pci_map_single
(sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
txdp->Host_Control = (unsigned long) skb;
txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
if (skb_shinfo(skb)->ufo_size)
txdp->Control_1 |= TXD_UFO_EN;
frg_cnt = skb_shinfo(skb)->nr_frags;
/* For fragmented SKB. */
for (i = 0; i < frg_cnt; i++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@ -3569,9 +3587,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
(sp->pdev, frag->page, frag->page_offset,
frag->size, PCI_DMA_TODEVICE);
txdp->Control_1 |= TXD_BUFFER0_SIZE(frag->size);
if (skb_shinfo(skb)->ufo_size)
txdp->Control_1 |= TXD_UFO_EN;
}
txdp->Control_1 |= TXD_GATHER_CODE_LAST;
if (skb_shinfo(skb)->ufo_size)
frg_cnt++; /* as Txd0 was used for inband header */
tx_fifo = mac_control->tx_FIFO_start[queue];
val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr;
writeq(val64, &tx_fifo->TxDL_Pointer);
@ -3583,6 +3606,8 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
if (mss)
val64 |= TX_FIFO_SPECIAL_FUNC;
#endif
if (skb_shinfo(skb)->ufo_size)
val64 |= TX_FIFO_SPECIAL_FUNC;
writeq(val64, &tx_fifo->List_Control);
mmiowb();
@ -4721,7 +4746,10 @@ static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
fail = 1;
if (ret_data != 0x012345) {
DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x4F0. Data written %llx Data read %llx\n", dev->name, (u64)0x12345, ret_data);
DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x4F0. "
"Data written %llx Data read %llx\n",
dev->name, (unsigned long long)0x12345,
(unsigned long long)ret_data);
fail = 1;
}
@ -4740,7 +4768,10 @@ static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
fail = 1;
if (ret_data != 0x012345) {
DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x7F0. Data written %llx Data read %llx\n", dev->name, (u64)0x12345, ret_data);
DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x7F0. "
"Data written %llx Data read %llx\n",
dev->name, (unsigned long long)0x12345,
(unsigned long long)ret_data);
fail = 1;
}
@ -5190,6 +5221,8 @@ static struct ethtool_ops netdev_ethtool_ops = {
.get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
#endif
.get_ufo = ethtool_op_get_ufo,
.set_ufo = ethtool_op_set_ufo,
.self_test_count = s2io_ethtool_self_test_count,
.self_test = s2io_ethtool_test,
.get_strings = s2io_ethtool_get_strings,
@ -5941,7 +5974,8 @@ Defaulting to INTA\n");
break;
}
}
config->max_txds = MAX_SKB_FRAGS + 1;
/* + 2 because one Txd for skb->data and one Txd for UFO */
config->max_txds = MAX_SKB_FRAGS + 2;
/* Rx side parameters. */
if (rx_ring_sz[0] == 0)
@ -6035,6 +6069,10 @@ Defaulting to INTA\n");
#ifdef NETIF_F_TSO
dev->features |= NETIF_F_TSO;
#endif
if (sp->device_type & XFRAME_II_DEVICE) {
dev->features |= NETIF_F_UFO;
dev->features |= NETIF_F_HW_CSUM;
}
dev->tx_timeout = &s2io_tx_watchdog;
dev->watchdog_timeo = WATCH_DOG_TIMEOUT;

View file

@ -393,7 +393,9 @@ typedef struct _TxD {
#define TXD_GATHER_CODE_LAST BIT(23)
#define TXD_TCP_LSO_EN BIT(30)
#define TXD_UDP_COF_EN BIT(31)
#define TXD_UFO_EN BIT(31) | BIT(30)
#define TXD_TCP_LSO_MSS(val) vBIT(val,34,14)
#define TXD_UFO_MSS(val) vBIT(val,34,14)
#define TXD_BUFFER0_SIZE(val) vBIT(val,48,16)
u64 Control_2;
@ -789,6 +791,7 @@ struct s2io_nic {
spinlock_t rx_lock;
atomic_t isr_cnt;
u64 *ufo_in_band_v;
};
#define RESET_ERROR 1;

View file

@ -1,6 +1,6 @@
/* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
Copyright 1999 Silicon Integrated System Corporation
Revision: 1.08.08 Jan. 22 2005
Revision: 1.08.09 Sep. 19 2005
Modified from the driver which is originally written by Donald Becker.
@ -17,6 +17,7 @@
SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
preliminary Rev. 1.0 Jan. 18, 1998
Rev 1.08.09 Sep. 19 2005 Daniele Venzano add Wake on LAN support
Rev 1.08.08 Jan. 22 2005 Daniele Venzano use netif_msg for debugging messages
Rev 1.08.07 Nov. 2 2003 Daniele Venzano <webvenza@libero.it> add suspend/resume support
Rev 1.08.06 Sep. 24 2002 Mufasa Yang bug fix for Tx timeout & add SiS963 support
@ -76,7 +77,7 @@
#include "sis900.h"
#define SIS900_MODULE_NAME "sis900"
#define SIS900_DRV_VERSION "v1.08.08 Jan. 22 2005"
#define SIS900_DRV_VERSION "v1.08.09 Sep. 19 2005"
static char version[] __devinitdata =
KERN_INFO "sis900.c: " SIS900_DRV_VERSION "\n";
@ -538,6 +539,11 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
printk("%2.2x:", (u8)net_dev->dev_addr[i]);
printk("%2.2x.\n", net_dev->dev_addr[i]);
/* Detect Wake on Lan support */
ret = inl(CFGPMC & PMESP);
if (netif_msg_probe(sis_priv) && (ret & PME_D3C) == 0)
printk(KERN_INFO "%s: Wake on LAN only available from suspend to RAM.", net_dev->name);
return 0;
err_unmap_rx:
@ -2015,6 +2021,67 @@ static int sis900_nway_reset(struct net_device *net_dev)
return mii_nway_restart(&sis_priv->mii_info);
}
/**
* sis900_set_wol - Set up Wake on Lan registers
* @net_dev: the net device to probe
* @wol: container for info passed to the driver
*
* Process ethtool command "wol" to setup wake on lan features.
* SiS900 supports sending WoL events if a correct packet is received,
* but there is no simple way to filter them to only a subset (broadcast,
* multicast, unicast or arp).
*/
static int sis900_set_wol(struct net_device *net_dev, struct ethtool_wolinfo *wol)
{
struct sis900_private *sis_priv = net_dev->priv;
long pmctrl_addr = net_dev->base_addr + pmctrl;
u32 cfgpmcsr = 0, pmctrl_bits = 0;
if (wol->wolopts == 0) {
pci_read_config_dword(sis_priv->pci_dev, CFGPMCSR, &cfgpmcsr);
cfgpmcsr |= ~PME_EN;
pci_write_config_dword(sis_priv->pci_dev, CFGPMCSR, cfgpmcsr);
outl(pmctrl_bits, pmctrl_addr);
if (netif_msg_wol(sis_priv))
printk(KERN_DEBUG "%s: Wake on LAN disabled\n", net_dev->name);
return 0;
}
if (wol->wolopts & (WAKE_MAGICSECURE | WAKE_UCAST | WAKE_MCAST
| WAKE_BCAST | WAKE_ARP))
return -EINVAL;
if (wol->wolopts & WAKE_MAGIC)
pmctrl_bits |= MAGICPKT;
if (wol->wolopts & WAKE_PHY)
pmctrl_bits |= LINKON;
outl(pmctrl_bits, pmctrl_addr);
pci_read_config_dword(sis_priv->pci_dev, CFGPMCSR, &cfgpmcsr);
cfgpmcsr |= PME_EN;
pci_write_config_dword(sis_priv->pci_dev, CFGPMCSR, cfgpmcsr);
if (netif_msg_wol(sis_priv))
printk(KERN_DEBUG "%s: Wake on LAN enabled\n", net_dev->name);
return 0;
}
static void sis900_get_wol(struct net_device *net_dev, struct ethtool_wolinfo *wol)
{
long pmctrl_addr = net_dev->base_addr + pmctrl;
u32 pmctrl_bits;
pmctrl_bits = inl(pmctrl_addr);
if (pmctrl_bits & MAGICPKT)
wol->wolopts |= WAKE_MAGIC;
if (pmctrl_bits & LINKON)
wol->wolopts |= WAKE_PHY;
wol->supported = (WAKE_PHY | WAKE_MAGIC);
}
static struct ethtool_ops sis900_ethtool_ops = {
.get_drvinfo = sis900_get_drvinfo,
.get_msglevel = sis900_get_msglevel,
@ -2023,6 +2090,8 @@ static struct ethtool_ops sis900_ethtool_ops = {
.get_settings = sis900_get_settings,
.set_settings = sis900_set_settings,
.nway_reset = sis900_nway_reset,
.get_wol = sis900_get_wol,
.set_wol = sis900_set_wol
};
/**

View file

@ -33,6 +33,7 @@ enum sis900_registers {
rxcfg=0x34, //Receive Configuration Register
flctrl=0x38, //Flow Control Register
rxlen=0x3c, //Receive Packet Length Register
cfgpmcsr=0x44, //Configuration Power Management Control/Status Register
rfcr=0x48, //Receive Filter Control Register
rfdr=0x4C, //Receive Filter Data Register
pmctrl=0xB0, //Power Management Control Register
@ -140,6 +141,50 @@ enum sis96x_eeprom_command {
EEREQ = 0x00000400, EEDONE = 0x00000200, EEGNT = 0x00000100
};
/* PCI Registers */
enum sis900_pci_registers {
CFGPMC = 0x40,
CFGPMCSR = 0x44
};
/* Power management capabilities bits */
enum sis900_cfgpmc_register_bits {
PMVER = 0x00070000,
DSI = 0x00100000,
PMESP = 0xf8000000
};
enum sis900_pmesp_bits {
PME_D0 = 0x1,
PME_D1 = 0x2,
PME_D2 = 0x4,
PME_D3H = 0x8,
PME_D3C = 0x10
};
/* Power management control/status bits */
enum sis900_cfgpmcsr_register_bits {
PMESTS = 0x00004000,
PME_EN = 0x00000100, // Power management enable
PWR_STA = 0x00000003 // Current power state
};
/* Wake-on-LAN support. */
enum sis900_power_management_control_register_bits {
LINKLOSS = 0x00000001,
LINKON = 0x00000002,
MAGICPKT = 0x00000400,
ALGORITHM = 0x00000800,
FRM1EN = 0x00100000,
FRM2EN = 0x00200000,
FRM3EN = 0x00400000,
FRM1ACS = 0x01000000,
FRM2ACS = 0x02000000,
FRM3ACS = 0x04000000,
WAKEALL = 0x40000000,
GATECLK = 0x80000000
};
/* Management Data I/O (mdio) frame */
#define MIIread 0x6000
#define MIIwrite 0x5002

View file

@ -26,8 +26,7 @@ sk98lin-objs := \
skrlmt.o \
sktimer.o \
skvpd.o \
skxmac2.o \
skproc.o
skxmac2.o
# DBGDEF = \
# -DDEBUG

View file

@ -60,7 +60,6 @@ extern SK_U64 SkOsGetTime(SK_AC*);
extern int SkPciReadCfgDWord(SK_AC*, int, SK_U32*);
extern int SkPciReadCfgWord(SK_AC*, int, SK_U16*);
extern int SkPciReadCfgByte(SK_AC*, int, SK_U8*);
extern int SkPciWriteCfgDWord(SK_AC*, int, SK_U32);
extern int SkPciWriteCfgWord(SK_AC*, int, SK_U16);
extern int SkPciWriteCfgByte(SK_AC*, int, SK_U8);
extern int SkDrvEvent(SK_AC*, SK_IOC IoC, SK_U32, SK_EVPARA);
@ -268,8 +267,6 @@ typedef struct s_DevNet DEV_NET;
struct s_DevNet {
int PortNr;
int NetNr;
int Mtu;
int Up;
SK_AC *pAC;
};
@ -298,6 +295,7 @@ struct s_RxPort {
RXD *pRxdRingTail; /* Tail of Rx rings */
RXD *pRxdRingPrev; /* descriptor given to BMU previously */
int RxdRingFree; /* # of free entrys */
int RxCsum; /* use receive checksum hardware */
spinlock_t RxDesRingLock; /* serialize descriptor accesses */
int RxFillLimit; /* limit for buffers in ring */
SK_IOC HwAddr; /* bmu registers address */
@ -390,12 +388,10 @@ struct s_AC {
SK_IOC IoBase; /* register set of adapter */
int BoardLevel; /* level of active hw init (0-2) */
char DeviceStr[80]; /* adapter string from vpd */
SK_U32 AllocFlag; /* flag allocation of resources */
struct pci_dev *PciDev; /* for access to pci config space */
SK_U32 PciDevId; /* pci device id */
struct SK_NET_DEVICE *dev[2]; /* pointer to device struct */
char Name[30]; /* driver name */
int RxBufSize; /* length of receive buffers */
struct net_device_stats stats; /* linux 'netstat -i' statistics */
@ -430,7 +426,6 @@ struct s_AC {
DIM_INFO DynIrqModInfo; /* all data related to DIM */
/* Only for tests */
int PortUp;
int PortDown;
int ChipsetType; /* Chipset family type
* 0 == Genesis family support

View file

@ -130,14 +130,12 @@ typedef struct s_vpd_key {
#ifndef VPD_DO_IO
#define VPD_OUT8(pAC,IoC,Addr,Val) (void)SkPciWriteCfgByte(pAC,Addr,Val)
#define VPD_OUT16(pAC,IoC,Addr,Val) (void)SkPciWriteCfgWord(pAC,Addr,Val)
#define VPD_OUT32(pAC,IoC,Addr,Val) (void)SkPciWriteCfgDWord(pAC,Addr,Val)
#define VPD_IN8(pAC,IoC,Addr,pVal) (void)SkPciReadCfgByte(pAC,Addr,pVal)
#define VPD_IN16(pAC,IoC,Addr,pVal) (void)SkPciReadCfgWord(pAC,Addr,pVal)
#define VPD_IN32(pAC,IoC,Addr,pVal) (void)SkPciReadCfgDWord(pAC,Addr,pVal)
#else /* VPD_DO_IO */
#define VPD_OUT8(pAC,IoC,Addr,Val) SK_OUT8(IoC,PCI_C(Addr),Val)
#define VPD_OUT16(pAC,IoC,Addr,Val) SK_OUT16(IoC,PCI_C(Addr),Val)
#define VPD_OUT32(pAC,IoC,Addr,Val) SK_OUT32(IoC,PCI_C(Addr),Val)
#define VPD_IN8(pAC,IoC,Addr,pVal) SK_IN8(IoC,PCI_C(Addr),pVal)
#define VPD_IN16(pAC,IoC,Addr,pVal) SK_IN16(IoC,PCI_C(Addr),pVal)
#define VPD_IN32(pAC,IoC,Addr,pVal) SK_IN32(IoC,PCI_C(Addr),pVal)
@ -155,12 +153,6 @@ typedef struct s_vpd_key {
else \
SK_OUT16(pAC,PCI_C(Addr),Val); \
}
#define VPD_OUT32(pAC,Ioc,Addr,Val) { \
if ((pAC)->DgT.DgUseCfgCycle) \
SkPciWriteCfgDWord(pAC,Addr,Val); \
else \
SK_OUT32(pAC,PCI_C(Addr),Val); \
}
#define VPD_IN8(pAC,Ioc,Addr,pVal) { \
if ((pAC)->DgT.DgUseCfgCycle) \
SkPciReadCfgByte(pAC,Addr,pVal); \

View file

@ -539,6 +539,48 @@ static int setPauseParams(struct net_device *dev , struct ethtool_pauseparam *ep
return ret ? -EIO : 0;
}
/* Only Yukon supports checksum offload. */
static int setScatterGather(struct net_device *dev, u32 data)
{
DEV_NET *pNet = netdev_priv(dev);
SK_AC *pAC = pNet->pAC;
if (pAC->GIni.GIChipId == CHIP_ID_GENESIS)
return -EOPNOTSUPP;
return ethtool_op_set_sg(dev, data);
}
static int setTxCsum(struct net_device *dev, u32 data)
{
DEV_NET *pNet = netdev_priv(dev);
SK_AC *pAC = pNet->pAC;
if (pAC->GIni.GIChipId == CHIP_ID_GENESIS)
return -EOPNOTSUPP;
return ethtool_op_set_tx_csum(dev, data);
}
static u32 getRxCsum(struct net_device *dev)
{
DEV_NET *pNet = netdev_priv(dev);
SK_AC *pAC = pNet->pAC;
return pAC->RxPort[pNet->PortNr].RxCsum;
}
static int setRxCsum(struct net_device *dev, u32 data)
{
DEV_NET *pNet = netdev_priv(dev);
SK_AC *pAC = pNet->pAC;
if (pAC->GIni.GIChipId == CHIP_ID_GENESIS)
return -EOPNOTSUPP;
pAC->RxPort[pNet->PortNr].RxCsum = data != 0;
return 0;
}
struct ethtool_ops SkGeEthtoolOps = {
.get_settings = getSettings,
.set_settings = setSettings,
@ -551,4 +593,10 @@ struct ethtool_ops SkGeEthtoolOps = {
.set_pauseparam = setPauseParams,
.get_link = ethtool_op_get_link,
.get_perm_addr = ethtool_op_get_perm_addr,
.get_sg = ethtool_op_get_sg,
.set_sg = setScatterGather,
.get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = setTxCsum,
.get_rx_csum = getRxCsum,
.set_rx_csum = setRxCsum,
};

View file

@ -111,7 +111,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/dma-mapping.h>
#include <linux/ip.h>
@ -207,7 +206,6 @@ static void SkGeSetRxMode(struct SK_NET_DEVICE *dev);
static struct net_device_stats *SkGeStats(struct SK_NET_DEVICE *dev);
static int SkGeIoctl(struct SK_NET_DEVICE *dev, struct ifreq *rq, int cmd);
static void GetConfiguration(SK_AC*);
static void ProductStr(SK_AC*);
static int XmitFrame(SK_AC*, TX_PORT*, struct sk_buff*);
static void FreeTxDescriptors(SK_AC*pAC, TX_PORT*);
static void FillRxRing(SK_AC*, RX_PORT*);
@ -236,28 +234,6 @@ static int SkDrvDeInitAdapter(SK_AC *pAC, int devNbr);
* Extern Function Prototypes
*
******************************************************************************/
static const char SKRootName[] = "net/sk98lin";
static struct proc_dir_entry *pSkRootDir;
extern struct file_operations sk_proc_fops;
static inline void SkGeProcCreate(struct net_device *dev)
{
struct proc_dir_entry *pe;
if (pSkRootDir &&
(pe = create_proc_entry(dev->name, S_IRUGO, pSkRootDir))) {
pe->proc_fops = &sk_proc_fops;
pe->data = dev;
pe->owner = THIS_MODULE;
}
}
static inline void SkGeProcRemove(struct net_device *dev)
{
if (pSkRootDir)
remove_proc_entry(dev->name, pSkRootDir);
}
extern void SkDimEnableModerationIfNeeded(SK_AC *pAC);
extern void SkDimDisplayModerationSettings(SK_AC *pAC);
extern void SkDimStartModerationTimer(SK_AC *pAC);
@ -278,6 +254,27 @@ extern struct ethtool_ops SkGeEthtoolOps;
static uintptr_t TxQueueAddr[SK_MAX_MACS][2] = {{0x680, 0x600},{0x780, 0x700}};
static uintptr_t RxQueueAddr[SK_MAX_MACS] = {0x400, 0x480};
/*****************************************************************************
*
* SkPciWriteCfgDWord - write a 32 bit value to pci config space
*
* Description:
* This routine writes a 32 bit value to the pci configuration
* space.
*
* Returns:
* 0 - indicate everything worked ok.
* != 0 - error indication
*/
static inline int SkPciWriteCfgDWord(
SK_AC *pAC, /* Adapter Control structure pointer */
int PciAddr, /* PCI register address */
SK_U32 Val) /* pointer to store the read value */
{
pci_write_config_dword(pAC->PciDev, PciAddr, Val);
return(0);
} /* SkPciWriteCfgDWord */
/*****************************************************************************
*
* SkGeInitPCI - Init the PCI resources
@ -301,7 +298,7 @@ int SkGeInitPCI(SK_AC *pAC)
dev->mem_start = pci_resource_start (pdev, 0);
pci_set_master(pdev);
if (pci_request_regions(pdev, pAC->Name) != 0) {
if (pci_request_regions(pdev, "sk98lin") != 0) {
retval = 2;
goto out_disable;
}
@ -579,10 +576,10 @@ SK_BOOL DualNet;
spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
if (pAC->GIni.GIMacsFound == 2) {
Ret = request_irq(dev->irq, SkGeIsr, SA_SHIRQ, pAC->Name, dev);
Ret = request_irq(dev->irq, SkGeIsr, SA_SHIRQ, "sk98lin", dev);
} else if (pAC->GIni.GIMacsFound == 1) {
Ret = request_irq(dev->irq, SkGeIsrOnePort, SA_SHIRQ,
pAC->Name, dev);
"sk98lin", dev);
} else {
printk(KERN_WARNING "sk98lin: Illegal number of ports: %d\n",
pAC->GIni.GIMacsFound);
@ -1266,7 +1263,6 @@ struct SK_NET_DEVICE *dev)
spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
pAC->MaxPorts++;
pNet->Up = 1;
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
@ -1396,7 +1392,6 @@ struct SK_NET_DEVICE *dev)
sizeof(SK_PNMI_STRUCT_DATA));
pAC->MaxPorts--;
pNet->Up = 0;
return (0);
} /* SkGeClose */
@ -2176,7 +2171,6 @@ rx_start:
pMsg->ip_summed = CHECKSUM_NONE;
#endif
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("V"));
ForRlmt = SK_RLMT_RX_PROTOCOL;
#if 0
@ -2551,7 +2545,7 @@ unsigned long Flags;
static int SkGeChangeMtu(struct SK_NET_DEVICE *dev, int NewMtu)
{
DEV_NET *pNet;
DEV_NET *pOtherNet;
struct net_device *pOtherDev;
SK_AC *pAC;
unsigned long Flags;
int i;
@ -2581,11 +2575,11 @@ SK_EVPARA EvPara;
}
#endif
pNet->Mtu = NewMtu;
pOtherNet = netdev_priv(pAC->dev[1 - pNet->NetNr]);
if ((pOtherNet->Mtu>1500) && (NewMtu<=1500) && (pOtherNet->Up==1)) {
return(0);
}
pOtherDev = pAC->dev[1 - pNet->NetNr];
if ( netif_running(pOtherDev) && (pOtherDev->mtu > 1500)
&& (NewMtu <= 1500))
return 0;
pAC->RxBufSize = NewMtu + 32;
dev->mtu = NewMtu;
@ -2747,7 +2741,8 @@ SK_EVPARA EvPara;
EvPara.Para32[1] = -1;
SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
if (pOtherNet->Up) {
if (netif_running(pOtherDev)) {
DEV_NET *pOtherNet = netdev_priv(pOtherDev);
EvPara.Para32[0] = pOtherNet->PortNr;
SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
}
@ -2821,7 +2816,7 @@ unsigned long Flags; /* for spin lock */
pAC->stats.rx_bytes = (SK_U32) pPnmiStruct->RxOctetsDeliveredCts;
pAC->stats.tx_bytes = (SK_U32) pPnmiStat->StatTxOctetsOkCts;
if (pNet->Mtu <= 1500) {
if (dev->mtu <= 1500) {
pAC->stats.rx_errors = (SK_U32) pPnmiStruct->InErrorsCts & 0xFFFFFFFF;
} else {
pAC->stats.rx_errors = (SK_U32) ((pPnmiStruct->InErrorsCts -
@ -3772,25 +3767,21 @@ int Capabilities[3][3] =
*
* Returns: N/A
*/
static void ProductStr(
SK_AC *pAC /* pointer to adapter context */
static inline int ProductStr(
SK_AC *pAC, /* pointer to adapter context */
char *DeviceStr, /* result string */
int StrLen /* length of the string */
)
{
int StrLen = 80; /* length of the string, defined in SK_AC */
char Keyword[] = VPD_NAME; /* vpd productname identifier */
int ReturnCode; /* return code from vpd_read */
unsigned long Flags;
spin_lock_irqsave(&pAC->SlowPathLock, Flags);
ReturnCode = VpdRead(pAC, pAC->IoBase, Keyword, pAC->DeviceStr,
&StrLen);
ReturnCode = VpdRead(pAC, pAC->IoBase, Keyword, DeviceStr, &StrLen);
spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
if (ReturnCode != 0) {
/* there was an error reading the vpd data */
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ERROR,
("Error reading VPD data: %d\n", ReturnCode));
pAC->DeviceStr[0] = '\0';
}
return ReturnCode;
} /* ProductStr */
/*****************************************************************************
@ -3991,28 +3982,6 @@ SK_U8 *pVal) /* pointer to store the read value */
} /* SkPciReadCfgByte */
/*****************************************************************************
*
* SkPciWriteCfgDWord - write a 32 bit value to pci config space
*
* Description:
* This routine writes a 32 bit value to the pci configuration
* space.
*
* Returns:
* 0 - indicate everything worked ok.
* != 0 - error indication
*/
int SkPciWriteCfgDWord(
SK_AC *pAC, /* Adapter Control structure pointer */
int PciAddr, /* PCI register address */
SK_U32 Val) /* pointer to store the read value */
{
pci_write_config_dword(pAC->PciDev, PciAddr, Val);
return(0);
} /* SkPciWriteCfgDWord */
/*****************************************************************************
*
* SkPciWriteCfgWord - write a 16 bit value to pci config space
@ -4151,6 +4120,7 @@ SK_BOOL DualNet;
Flags);
break;
case SK_DRV_NET_UP: /* SK_U32 PortIdx */
{ struct net_device *dev = pAC->dev[Param.Para32[0]];
/* action list 5 */
FromPort = Param.Para32[0];
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
@ -4234,22 +4204,12 @@ SK_BOOL DualNet;
printk(" irq moderation: disabled\n");
#ifdef SK_ZEROCOPY
if (pAC->ChipsetType)
#ifdef USE_SK_TX_CHECKSUM
printk(" scatter-gather: enabled\n");
#else
printk(" tx-checksum: disabled\n");
#endif
else
printk(" scatter-gather: disabled\n");
#else
printk(" scatter-gather: disabled\n");
#endif
#ifndef USE_SK_RX_CHECKSUM
printk(" rx-checksum: disabled\n");
#endif
printk(" scatter-gather: %s\n",
(dev->features & NETIF_F_SG) ? "enabled" : "disabled");
printk(" tx-checksum: %s\n",
(dev->features & NETIF_F_IP_CSUM) ? "enabled" : "disabled");
printk(" rx-checksum: %s\n",
pAC->RxPort[Param.Para32[0]].RxCsum ? "enabled" : "disabled");
} else {
DoPrintInterfaceChange = SK_TRUE;
@ -4264,9 +4224,9 @@ SK_BOOL DualNet;
}
/* Inform the world that link protocol is up. */
netif_carrier_on(pAC->dev[Param.Para32[0]]);
netif_carrier_on(dev);
break;
}
case SK_DRV_NET_DOWN: /* SK_U32 Reason */
/* action list 7 */
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
@ -4480,7 +4440,7 @@ SK_AC *pAc) /* pointer to adapter context */
pAC->DiagModeActive = DIAG_ACTIVE;
if (pAC->BoardLevel > SK_INIT_DATA) {
if (pNet->Up) {
if (netif_running(pAC->dev[0])) {
pAC->WasIfUp[0] = SK_TRUE;
pAC->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */
DoPrintInterfaceChange = SK_FALSE;
@ -4490,7 +4450,7 @@ SK_AC *pAc) /* pointer to adapter context */
}
if (pNet != netdev_priv(pAC->dev[1])) {
pNet = netdev_priv(pAC->dev[1]);
if (pNet->Up) {
if (netif_running(pAC->dev[1])) {
pAC->WasIfUp[1] = SK_TRUE;
pAC->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */
DoPrintInterfaceChange = SK_FALSE;
@ -4816,6 +4776,7 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
struct net_device *dev = NULL;
static int boards_found = 0;
int error = -ENODEV;
char DeviceStr[80];
if (pci_enable_device(pdev))
goto out;
@ -4843,14 +4804,11 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
memset(pNet->pAC, 0, sizeof(SK_AC));
pAC = pNet->pAC;
pAC->PciDev = pdev;
pAC->PciDevId = pdev->device;
pAC->dev[0] = dev;
pAC->dev[1] = dev;
sprintf(pAC->Name, "SysKonnect SK-98xx");
pAC->CheckQueue = SK_FALSE;
pNet->Mtu = 1500;
pNet->Up = 0;
dev->irq = pdev->irq;
error = SkGeInitPCI(pAC);
if (error) {
@ -4873,21 +4831,30 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
SET_NETDEV_DEV(dev, &pdev->dev);
SET_ETHTOOL_OPS(dev, &SkGeEthtoolOps);
#ifdef SK_ZEROCOPY
#ifdef USE_SK_TX_CHECKSUM
/* Use only if yukon hardware */
if (pAC->ChipsetType) {
/* Use only if yukon hardware */
/* SK and ZEROCOPY - fly baby... */
dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
#ifdef USE_SK_TX_CHECKSUM
dev->features |= NETIF_F_IP_CSUM;
#endif
#ifdef SK_ZEROCOPY
dev->features |= NETIF_F_SG;
#endif
#ifdef USE_SK_RX_CHECKSUM
pAC->RxPort[0].RxCsum = 1;
#endif
}
#endif
#endif
pAC->Index = boards_found++;
if (SkGeBoardInit(dev, pAC))
goto out_free_netdev;
/* Read Adapter name from VPD */
if (ProductStr(pAC, DeviceStr, sizeof(DeviceStr)) != 0) {
printk(KERN_ERR "sk98lin: Could not read VPD data.\n");
goto out_free_resources;
}
/* Register net device */
if (register_netdev(dev)) {
printk(KERN_ERR "sk98lin: Could not register device.\n");
@ -4895,8 +4862,7 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
}
/* Print adapter specific string from vpd */
ProductStr(pAC);
printk("%s: %s\n", dev->name, pAC->DeviceStr);
printk("%s: %s\n", dev->name, DeviceStr);
/* Print configuration settings */
printk(" PrefPort:%c RlmtMode:%s\n",
@ -4912,8 +4878,6 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
memcpy(&dev->dev_addr, &pAC->Addr.Net[0].CurrentMacAddress, 6);
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
SkGeProcCreate(dev);
pNet->PortNr = 0;
pNet->NetNr = 0;
@ -4932,8 +4896,6 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
pNet->PortNr = 1;
pNet->NetNr = 1;
pNet->pAC = pAC;
pNet->Mtu = 1500;
pNet->Up = 0;
dev->open = &SkGeOpen;
dev->stop = &SkGeClose;
@ -4946,26 +4908,28 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
SET_NETDEV_DEV(dev, &pdev->dev);
SET_ETHTOOL_OPS(dev, &SkGeEthtoolOps);
#ifdef SK_ZEROCOPY
#ifdef USE_SK_TX_CHECKSUM
if (pAC->ChipsetType) {
/* SG and ZEROCOPY - fly baby... */
dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
#ifdef USE_SK_TX_CHECKSUM
dev->features |= NETIF_F_IP_CSUM;
#endif
#ifdef SK_ZEROCOPY
dev->features |= NETIF_F_SG;
#endif
#ifdef USE_SK_RX_CHECKSUM
pAC->RxPort[1].RxCsum = 1;
#endif
}
#endif
#endif
if (register_netdev(dev)) {
printk(KERN_ERR "sk98lin: Could not register device for seconf port.\n");
free_netdev(dev);
pAC->dev[1] = pAC->dev[0];
} else {
SkGeProcCreate(dev);
memcpy(&dev->dev_addr,
&pAC->Addr.Net[1].CurrentMacAddress, 6);
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
printk("%s: %s\n", dev->name, pAC->DeviceStr);
printk("%s: %s\n", dev->name, DeviceStr);
printk(" PrefPort:B RlmtMode:Dual Check Link State\n");
}
}
@ -5001,10 +4965,7 @@ static void __devexit skge_remove_one(struct pci_dev *pdev)
SK_AC *pAC = pNet->pAC;
struct net_device *otherdev = pAC->dev[1];
SkGeProcRemove(dev);
unregister_netdev(dev);
if (otherdev != dev)
SkGeProcRemove(otherdev);
SkGeYellowLED(pAC, pAC->IoBase, 0);
@ -5089,9 +5050,9 @@ static int skge_resume(struct pci_dev *pdev)
pci_enable_device(pdev);
pci_set_master(pdev);
if (pAC->GIni.GIMacsFound == 2)
ret = request_irq(dev->irq, SkGeIsr, SA_SHIRQ, pAC->Name, dev);
ret = request_irq(dev->irq, SkGeIsr, SA_SHIRQ, "sk98lin", dev);
else
ret = request_irq(dev->irq, SkGeIsrOnePort, SA_SHIRQ, pAC->Name, dev);
ret = request_irq(dev->irq, SkGeIsrOnePort, SA_SHIRQ, "sk98lin", dev);
if (ret) {
printk(KERN_WARNING "sk98lin: unable to acquire IRQ %d\n", dev->irq);
pAC->AllocFlag &= ~SK_ALLOC_IRQ;
@ -5149,23 +5110,12 @@ static struct pci_driver skge_driver = {
static int __init skge_init(void)
{
int error;
pSkRootDir = proc_mkdir(SKRootName, NULL);
if (pSkRootDir)
pSkRootDir->owner = THIS_MODULE;
error = pci_register_driver(&skge_driver);
if (error)
remove_proc_entry(SKRootName, NULL);
return error;
return pci_module_init(&skge_driver);
}
static void __exit skge_exit(void)
{
pci_unregister_driver(&skge_driver);
remove_proc_entry(SKRootName, NULL);
}
module_init(skge_init);

View file

@ -1,265 +0,0 @@
/******************************************************************************
*
* 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
*
******************************************************************************/
/******************************************************************************
*
* (C)Copyright 1998-2002 SysKonnect GmbH.
* (C)Copyright 2002-2003 Marvell.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Created 22-Nov-2000
* Author: Mirko Lindner (mlindner@syskonnect.de)
*
* The information in this file is provided "AS IS" without warranty.
*
******************************************************************************/
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include "h/skdrv1st.h"
#include "h/skdrv2nd.h"
#include "h/skversion.h"
static int sk_seq_show(struct seq_file *seq, void *v);
static int sk_proc_open(struct inode *inode, struct file *file);
struct file_operations sk_proc_fops = {
.owner = THIS_MODULE,
.open = sk_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/*****************************************************************************
*
* sk_seq_show - show proc information of a particular adapter
*
* Description:
* This function fills the proc entry with statistic data about
* the ethernet device. It invokes the generic sk_gen_browse() to
* print out all items one per one.
*
* Returns: 0
*
*/
static int sk_seq_show(struct seq_file *seq, void *v)
{
struct net_device *dev = seq->private;
DEV_NET *pNet = netdev_priv(dev);
SK_AC *pAC = pNet->pAC;
SK_PNMI_STRUCT_DATA *pPnmiStruct = &pAC->PnmiStruct;
unsigned long Flags;
unsigned int Size;
char sens_msg[50];
int t;
int i;
/* NetIndex in GetStruct is now required, zero is only dummy */
for (t=pAC->GIni.GIMacsFound; t > 0; t--) {
if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 1)
t--;
spin_lock_irqsave(&pAC->SlowPathLock, Flags);
Size = SK_PNMI_STRUCT_SIZE;
#ifdef SK_DIAG_SUPPORT
if (pAC->BoardLevel == SK_INIT_DATA) {
SK_MEMCPY(&(pAC->PnmiStruct), &(pAC->PnmiBackup), sizeof(SK_PNMI_STRUCT_DATA));
if (pAC->DiagModeActive == DIAG_NOTACTIVE) {
pAC->Pnmi.DiagAttached = SK_DIAG_IDLE;
}
} else {
SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size, t-1);
}
#else
SkPnmiGetStruct(pAC, pAC->IoBase,
pPnmiStruct, &Size, t-1);
#endif
spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
if (pAC->dev[t-1] == dev) {
SK_PNMI_STAT *pPnmiStat = &pPnmiStruct->Stat[0];
seq_printf(seq, "\nDetailed statistic for device %s\n",
pAC->dev[t-1]->name);
seq_printf(seq, "=======================================\n");
/* Board statistics */
seq_printf(seq, "\nBoard statistics\n\n");
seq_printf(seq, "Active Port %c\n",
'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt.
Net[t-1].PrefPort]->PortNumber);
seq_printf(seq, "Preferred Port %c\n",
'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt.
Net[t-1].PrefPort]->PortNumber);
seq_printf(seq, "Bus speed (MHz) %d\n",
pPnmiStruct->BusSpeed);
seq_printf(seq, "Bus width (Bit) %d\n",
pPnmiStruct->BusWidth);
seq_printf(seq, "Driver version %s\n",
VER_STRING);
seq_printf(seq, "Hardware revision v%d.%d\n",
(pAC->GIni.GIPciHwRev >> 4) & 0x0F,
pAC->GIni.GIPciHwRev & 0x0F);
/* Print sensor informations */
for (i=0; i < pAC->I2c.MaxSens; i ++) {
/* Check type */
switch (pAC->I2c.SenTable[i].SenType) {
case 1:
strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
strcat(sens_msg, " (C)");
seq_printf(seq, "%-25s %d.%02d\n",
sens_msg,
pAC->I2c.SenTable[i].SenValue / 10,
pAC->I2c.SenTable[i].SenValue % 10);
strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
strcat(sens_msg, " (F)");
seq_printf(seq, "%-25s %d.%02d\n",
sens_msg,
((((pAC->I2c.SenTable[i].SenValue)
*10)*9)/5 + 3200)/100,
((((pAC->I2c.SenTable[i].SenValue)
*10)*9)/5 + 3200) % 10);
break;
case 2:
strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
strcat(sens_msg, " (V)");
seq_printf(seq, "%-25s %d.%03d\n",
sens_msg,
pAC->I2c.SenTable[i].SenValue / 1000,
pAC->I2c.SenTable[i].SenValue % 1000);
break;
case 3:
strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
strcat(sens_msg, " (rpm)");
seq_printf(seq, "%-25s %d\n",
sens_msg,
pAC->I2c.SenTable[i].SenValue);
break;
default:
break;
}
}
/*Receive statistics */
seq_printf(seq, "\nReceive statistics\n\n");
seq_printf(seq, "Received bytes %Lu\n",
(unsigned long long) pPnmiStat->StatRxOctetsOkCts);
seq_printf(seq, "Received packets %Lu\n",
(unsigned long long) pPnmiStat->StatRxOkCts);
#if 0
if (pAC->GIni.GP[0].PhyType == SK_PHY_XMAC &&
pAC->HWRevision < 12) {
pPnmiStruct->InErrorsCts = pPnmiStruct->InErrorsCts -
pPnmiStat->StatRxShortsCts;
pPnmiStat->StatRxShortsCts = 0;
}
#endif
if (dev->mtu > 1500)
pPnmiStruct->InErrorsCts = pPnmiStruct->InErrorsCts -
pPnmiStat->StatRxTooLongCts;
seq_printf(seq, "Receive errors %Lu\n",
(unsigned long long) pPnmiStruct->InErrorsCts);
seq_printf(seq, "Receive dropped %Lu\n",
(unsigned long long) pPnmiStruct->RxNoBufCts);
seq_printf(seq, "Received multicast %Lu\n",
(unsigned long long) pPnmiStat->StatRxMulticastOkCts);
seq_printf(seq, "Receive error types\n");
seq_printf(seq, " length %Lu\n",
(unsigned long long) pPnmiStat->StatRxRuntCts);
seq_printf(seq, " buffer overflow %Lu\n",
(unsigned long long) pPnmiStat->StatRxFifoOverflowCts);
seq_printf(seq, " bad crc %Lu\n",
(unsigned long long) pPnmiStat->StatRxFcsCts);
seq_printf(seq, " framing %Lu\n",
(unsigned long long) pPnmiStat->StatRxFramingCts);
seq_printf(seq, " missed frames %Lu\n",
(unsigned long long) pPnmiStat->StatRxMissedCts);
if (dev->mtu > 1500)
pPnmiStat->StatRxTooLongCts = 0;
seq_printf(seq, " too long %Lu\n",
(unsigned long long) pPnmiStat->StatRxTooLongCts);
seq_printf(seq, " carrier extension %Lu\n",
(unsigned long long) pPnmiStat->StatRxCextCts);
seq_printf(seq, " too short %Lu\n",
(unsigned long long) pPnmiStat->StatRxShortsCts);
seq_printf(seq, " symbol %Lu\n",
(unsigned long long) pPnmiStat->StatRxSymbolCts);
seq_printf(seq, " LLC MAC size %Lu\n",
(unsigned long long) pPnmiStat->StatRxIRLengthCts);
seq_printf(seq, " carrier event %Lu\n",
(unsigned long long) pPnmiStat->StatRxCarrierCts);
seq_printf(seq, " jabber %Lu\n",
(unsigned long long) pPnmiStat->StatRxJabberCts);
/*Transmit statistics */
seq_printf(seq, "\nTransmit statistics\n\n");
seq_printf(seq, "Transmited bytes %Lu\n",
(unsigned long long) pPnmiStat->StatTxOctetsOkCts);
seq_printf(seq, "Transmited packets %Lu\n",
(unsigned long long) pPnmiStat->StatTxOkCts);
seq_printf(seq, "Transmit errors %Lu\n",
(unsigned long long) pPnmiStat->StatTxSingleCollisionCts);
seq_printf(seq, "Transmit dropped %Lu\n",
(unsigned long long) pPnmiStruct->TxNoBufCts);
seq_printf(seq, "Transmit collisions %Lu\n",
(unsigned long long) pPnmiStat->StatTxSingleCollisionCts);
seq_printf(seq, "Transmit error types\n");
seq_printf(seq, " excessive collision %ld\n",
pAC->stats.tx_aborted_errors);
seq_printf(seq, " carrier %Lu\n",
(unsigned long long) pPnmiStat->StatTxCarrierCts);
seq_printf(seq, " fifo underrun %Lu\n",
(unsigned long long) pPnmiStat->StatTxFifoUnderrunCts);
seq_printf(seq, " heartbeat %Lu\n",
(unsigned long long) pPnmiStat->StatTxCarrierCts);
seq_printf(seq, " window %ld\n",
pAC->stats.tx_window_errors);
}
}
return 0;
}
/*****************************************************************************
*
* sk_proc_open - register the show function when proc is open'ed
*
* Description:
* This function is called whenever a sk98lin proc file is queried.
*
* Returns: the return value of single_open()
*
*/
static int sk_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, sk_seq_show, PDE(inode)->data);
}
/*******************************************************************************
*
* End of file
*
******************************************************************************/

View file

@ -44,7 +44,7 @@
#include "skge.h"
#define DRV_NAME "skge"
#define DRV_VERSION "1.2"
#define DRV_VERSION "1.3"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
@ -89,15 +89,14 @@ MODULE_DEVICE_TABLE(pci, skge_id_table);
static int skge_up(struct net_device *dev);
static int skge_down(struct net_device *dev);
static void skge_phy_reset(struct skge_port *skge);
static void skge_tx_clean(struct skge_port *skge);
static int xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
static int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
static void genesis_get_stats(struct skge_port *skge, u64 *data);
static void yukon_get_stats(struct skge_port *skge, u64 *data);
static void yukon_init(struct skge_hw *hw, int port);
static void yukon_reset(struct skge_hw *hw, int port);
static void genesis_mac_init(struct skge_hw *hw, int port);
static void genesis_reset(struct skge_hw *hw, int port);
static void genesis_link_up(struct skge_port *skge);
/* Avoid conditionals by using array */
@ -277,10 +276,9 @@ static int skge_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
skge->autoneg = ecmd->autoneg;
skge->advertising = ecmd->advertising;
if (netif_running(dev)) {
skge_down(dev);
skge_up(dev);
}
if (netif_running(dev))
skge_phy_reset(skge);
return (0);
}
@ -400,6 +398,7 @@ static int skge_set_ring_param(struct net_device *dev,
struct ethtool_ringparam *p)
{
struct skge_port *skge = netdev_priv(dev);
int err;
if (p->rx_pending == 0 || p->rx_pending > MAX_RX_RING_SIZE ||
p->tx_pending == 0 || p->tx_pending > MAX_TX_RING_SIZE)
@ -410,7 +409,9 @@ static int skge_set_ring_param(struct net_device *dev,
if (netif_running(dev)) {
skge_down(dev);
skge_up(dev);
err = skge_up(dev);
if (err)
dev_close(dev);
}
return 0;
@ -431,21 +432,11 @@ static void skge_set_msglevel(struct net_device *netdev, u32 value)
static int skge_nway_reset(struct net_device *dev)
{
struct skge_port *skge = netdev_priv(dev);
struct skge_hw *hw = skge->hw;
int port = skge->port;
if (skge->autoneg != AUTONEG_ENABLE || !netif_running(dev))
return -EINVAL;
spin_lock_bh(&hw->phy_lock);
if (hw->chip_id == CHIP_ID_GENESIS) {
genesis_reset(hw, port);
genesis_mac_init(hw, port);
} else {
yukon_reset(hw, port);
yukon_init(hw, port);
}
spin_unlock_bh(&hw->phy_lock);
skge_phy_reset(skge);
return 0;
}
@ -517,10 +508,8 @@ static int skge_set_pauseparam(struct net_device *dev,
else
skge->flow_control = FLOW_MODE_NONE;
if (netif_running(dev)) {
skge_down(dev);
skge_up(dev);
}
if (netif_running(dev))
skge_phy_reset(skge);
return 0;
}
@ -2020,6 +2009,25 @@ static void yukon_phy_intr(struct skge_port *skge)
/* XXX restart autonegotiation? */
}
static void skge_phy_reset(struct skge_port *skge)
{
struct skge_hw *hw = skge->hw;
int port = skge->port;
netif_stop_queue(skge->netdev);
netif_carrier_off(skge->netdev);
spin_lock_bh(&hw->phy_lock);
if (hw->chip_id == CHIP_ID_GENESIS) {
genesis_reset(hw, port);
genesis_mac_init(hw, port);
} else {
yukon_reset(hw, port);
yukon_init(hw, port);
}
spin_unlock_bh(&hw->phy_lock);
}
/* Basic MII support */
static int skge_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
@ -2188,6 +2196,7 @@ static int skge_up(struct net_device *dev)
kfree(skge->rx_ring.start);
free_pci_mem:
pci_free_consistent(hw->pdev, skge->mem_size, skge->mem, skge->dma);
skge->mem = NULL;
return err;
}
@ -2198,6 +2207,9 @@ static int skge_down(struct net_device *dev)
struct skge_hw *hw = skge->hw;
int port = skge->port;
if (skge->mem == NULL)
return 0;
if (netif_msg_ifdown(skge))
printk(KERN_INFO PFX "%s: disabling interface\n", dev->name);
@ -2254,6 +2266,7 @@ static int skge_down(struct net_device *dev)
kfree(skge->rx_ring.start);
kfree(skge->tx_ring.start);
pci_free_consistent(hw->pdev, skge->mem_size, skge->mem, skge->dma);
skge->mem = NULL;
return 0;
}
@ -2414,18 +2427,23 @@ static void skge_tx_timeout(struct net_device *dev)
static int skge_change_mtu(struct net_device *dev, int new_mtu)
{
int err = 0;
int running = netif_running(dev);
int err;
if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
return -EINVAL;
if (!netif_running(dev)) {
dev->mtu = new_mtu;
return 0;
}
skge_down(dev);
if (running)
skge_down(dev);
dev->mtu = new_mtu;
if (running)
skge_up(dev);
err = skge_up(dev);
if (err)
dev_close(dev);
return err;
}
@ -3399,8 +3417,8 @@ static int skge_resume(struct pci_dev *pdev)
struct net_device *dev = hw->dev[i];
if (dev) {
netif_device_attach(dev);
if (netif_running(dev))
skge_up(dev);
if (netif_running(dev) && skge_up(dev))
dev_close(dev);
}
}
return 0;

View file

@ -475,18 +475,6 @@ enum {
Q_T2 = 0x40, /* 32 bit Test Register 2 */
Q_T3 = 0x44, /* 32 bit Test Register 3 */
/* Yukon-2 */
Q_DONE = 0x24, /* 16 bit Done Index (Yukon-2 only) */
Q_WM = 0x40, /* 16 bit FIFO Watermark */
Q_AL = 0x42, /* 8 bit FIFO Alignment */
Q_RSP = 0x44, /* 16 bit FIFO Read Shadow Pointer */
Q_RSL = 0x46, /* 8 bit FIFO Read Shadow Level */
Q_RP = 0x48, /* 8 bit FIFO Read Pointer */
Q_RL = 0x4a, /* 8 bit FIFO Read Level */
Q_WP = 0x4c, /* 8 bit FIFO Write Pointer */
Q_WSP = 0x4d, /* 8 bit FIFO Write Shadow Pointer */
Q_WL = 0x4e, /* 8 bit FIFO Write Level */
Q_WSL = 0x4f, /* 8 bit FIFO Write Shadow Level */
};
#define Q_ADDR(reg, offs) (B8_Q_REGS + (reg) + (offs))
@ -675,22 +663,16 @@ enum {
LED_OFF = 1<<0, /* switch LED off */
};
/* Receive GMAC FIFO (YUKON and Yukon-2) */
/* Receive GMAC FIFO (YUKON) */
enum {
RX_GMF_EA = 0x0c40,/* 32 bit Rx GMAC FIFO End Address */
RX_GMF_AF_THR = 0x0c44,/* 32 bit Rx GMAC FIFO Almost Full Thresh. */
RX_GMF_CTRL_T = 0x0c48,/* 32 bit Rx GMAC FIFO Control/Test */
RX_GMF_FL_MSK = 0x0c4c,/* 32 bit Rx GMAC FIFO Flush Mask */
RX_GMF_FL_THR = 0x0c50,/* 32 bit Rx GMAC FIFO Flush Threshold */
RX_GMF_TR_THR = 0x0c54,/* 32 bit Rx Truncation Threshold (Yukon-2) */
RX_GMF_VLAN = 0x0c5c,/* 32 bit Rx VLAN Type Register (Yukon-2) */
RX_GMF_WP = 0x0c60,/* 32 bit Rx GMAC FIFO Write Pointer */
RX_GMF_WLEV = 0x0c68,/* 32 bit Rx GMAC FIFO Write Level */
RX_GMF_RP = 0x0c70,/* 32 bit Rx GMAC FIFO Read Pointer */
RX_GMF_RLEV = 0x0c78,/* 32 bit Rx GMAC FIFO Read Level */
};
@ -855,48 +837,6 @@ enum {
GMAC_TI_ST_TST = 0x0e1a,/* 8 bit Time Stamp Timer Test Reg */
};
/* Status BMU Registers (Yukon-2 only)*/
enum {
STAT_CTRL = 0x0e80,/* 32 bit Status BMU Control Reg */
STAT_LAST_IDX = 0x0e84,/* 16 bit Status BMU Last Index */
/* 0x0e85 - 0x0e86: reserved */
STAT_LIST_ADDR_LO = 0x0e88,/* 32 bit Status List Start Addr (low) */
STAT_LIST_ADDR_HI = 0x0e8c,/* 32 bit Status List Start Addr (high) */
STAT_TXA1_RIDX = 0x0e90,/* 16 bit Status TxA1 Report Index Reg */
STAT_TXS1_RIDX = 0x0e92,/* 16 bit Status TxS1 Report Index Reg */
STAT_TXA2_RIDX = 0x0e94,/* 16 bit Status TxA2 Report Index Reg */
STAT_TXS2_RIDX = 0x0e96,/* 16 bit Status TxS2 Report Index Reg */
STAT_TX_IDX_TH = 0x0e98,/* 16 bit Status Tx Index Threshold Reg */
STAT_PUT_IDX = 0x0e9c,/* 16 bit Status Put Index Reg */
/* FIFO Control/Status Registers (Yukon-2 only)*/
STAT_FIFO_WP = 0x0ea0,/* 8 bit Status FIFO Write Pointer Reg */
STAT_FIFO_RP = 0x0ea4,/* 8 bit Status FIFO Read Pointer Reg */
STAT_FIFO_RSP = 0x0ea6,/* 8 bit Status FIFO Read Shadow Ptr */
STAT_FIFO_LEVEL = 0x0ea8,/* 8 bit Status FIFO Level Reg */
STAT_FIFO_SHLVL = 0x0eaa,/* 8 bit Status FIFO Shadow Level Reg */
STAT_FIFO_WM = 0x0eac,/* 8 bit Status FIFO Watermark Reg */
STAT_FIFO_ISR_WM = 0x0ead,/* 8 bit Status FIFO ISR Watermark Reg */
/* Level and ISR Timer Registers (Yukon-2 only)*/
STAT_LEV_TIMER_INI = 0x0eb0,/* 32 bit Level Timer Init. Value Reg */
STAT_LEV_TIMER_CNT = 0x0eb4,/* 32 bit Level Timer Counter Reg */
STAT_LEV_TIMER_CTRL = 0x0eb8,/* 8 bit Level Timer Control Reg */
STAT_LEV_TIMER_TEST = 0x0eb9,/* 8 bit Level Timer Test Reg */
STAT_TX_TIMER_INI = 0x0ec0,/* 32 bit Tx Timer Init. Value Reg */
STAT_TX_TIMER_CNT = 0x0ec4,/* 32 bit Tx Timer Counter Reg */
STAT_TX_TIMER_CTRL = 0x0ec8,/* 8 bit Tx Timer Control Reg */
STAT_TX_TIMER_TEST = 0x0ec9,/* 8 bit Tx Timer Test Reg */
STAT_ISR_TIMER_INI = 0x0ed0,/* 32 bit ISR Timer Init. Value Reg */
STAT_ISR_TIMER_CNT = 0x0ed4,/* 32 bit ISR Timer Counter Reg */
STAT_ISR_TIMER_CTRL = 0x0ed8,/* 8 bit ISR Timer Control Reg */
STAT_ISR_TIMER_TEST = 0x0ed9,/* 8 bit ISR Timer Test Reg */
ST_LAST_IDX_MASK = 0x007f,/* Last Index Mask */
ST_TXRP_IDX_MASK = 0x0fff,/* Tx Report Index Mask */
ST_TXTH_IDX_MASK = 0x0fff,/* Tx Threshold Index Mask */
ST_WM_IDX_MASK = 0x3f,/* FIFO Watermark Index Mask */
};
enum {
LINKLED_OFF = 0x01,
@ -923,8 +863,6 @@ enum {
WOL_MATCH_CTL = 0x0f22,/* 8 bit WOL Match Control Reg */
WOL_MATCH_RES = 0x0f23,/* 8 bit WOL Match Result Reg */
WOL_MAC_ADDR = 0x0f24,/* 32 bit WOL MAC Address */
WOL_PATT_PME = 0x0f2a,/* 8 bit WOL PME Match Enable (Yukon-2) */
WOL_PATT_ASFM = 0x0f2b,/* 8 bit WOL ASF Match Enable (Yukon-2) */
WOL_PATT_RPTR = 0x0f2c,/* 8 bit WOL Pattern Read Pointer */
/* WOL Pattern Length Registers (YUKON only) */
@ -1641,15 +1579,6 @@ enum {
PHY_M_FESC_SEL_CL_A = 1<<0, /* Select Class A driver (100B-TX) */
};
/* for Yukon-2 Gigabit Ethernet PHY (88E1112 only) */
/***** PHY_MARV_PHY_CTRL (page 2) 16 bit r/w MAC Specific Ctrl *****/
enum {
PHY_M_MAC_MD_MSK = 7<<7, /* Bit 9.. 7: Mode Select Mask */
PHY_M_MAC_MD_AUTO = 3,/* Auto Copper/1000Base-X */
PHY_M_MAC_MD_COPPER = 5,/* Copper only */
PHY_M_MAC_MD_1000BX = 7,/* 1000Base-X only */
};
#define PHY_M_MAC_MODE_SEL(x) (((x)<<7) & PHY_M_MAC_MD_MSK)
/***** PHY_MARV_PHY_CTRL (page 3) 16 bit r/w LED Control Reg. *****/
enum {

3262
drivers/net/sky2.c Normal file

File diff suppressed because it is too large Load diff

1922
drivers/net/sky2.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,15 +0,0 @@
#ifndef _LMC_PROTO_H_
#define _LMC_PROTO_H_
void lmc_proto_init(lmc_softc_t * const)
void lmc_proto_attach(lmc_softc_t *sc const)
void lmc_proto_detach(lmc_softc *sc const)
void lmc_proto_reopen(lmc_softc_t *sc const)
int lmc_proto_ioctl(lmc_softc_t *sc const, struct ifreq *ifr, int cmd)
void lmc_proto_open(lmc_softc_t *sc const)
void lmc_proto_close(lmc_softc_t *sc const)
unsigned short lmc_proto_type(lmc_softc_t *sc const, struct skbuff *skb)
#endif

View file

@ -173,7 +173,7 @@ config IPW2100_MONITOR
promiscuous mode via the Wireless Tool's Monitor mode. While in this
mode, no packets can be sent.
config IPW_DEBUG
config IPW2100_DEBUG
bool "Enable full debugging output in IPW2100 module."
depends on IPW2100
---help---
@ -192,7 +192,7 @@ config IPW_DEBUG
config IPW2200
tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
depends on IEEE80211 && PCI
depends on NET_RADIO && IEEE80211 && PCI
select FW_LOADER
---help---
A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network
@ -217,7 +217,7 @@ config IPW2200
say M here and read <file:Documentation/modules.txt>. The module
will be called ipw2200.ko.
config IPW_DEBUG
config IPW2200_DEBUG
bool "Enable full debugging output in IPW2200 module."
depends on IPW2200
---help---

View file

@ -4037,7 +4037,7 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid,
Cmd cmd;
Resp rsp;
if (test_bit(FLAG_ENABLED, &ai->flags))
if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid))
printk(KERN_ERR
"%s: MAC should be disabled (rid=%04x)\n",
__FUNCTION__, rid);
@ -5093,9 +5093,9 @@ static int set_wep_key(struct airo_info *ai, u16 index,
printk(KERN_INFO "Setting key %d\n", index);
}
disable_MAC(ai, lock);
if (perm) disable_MAC(ai, lock);
writeWepKeyRid(ai, &wkr, perm, lock);
enable_MAC(ai, &rsp, lock);
if (perm) enable_MAC(ai, &rsp, lock);
return 0;
}
@ -6170,6 +6170,8 @@ static int airo_set_encode(struct net_device *dev,
{
struct airo_info *local = dev->priv;
CapabilityRid cap_rid; /* Card capability info */
int perm = ( dwrq->flags & IW_ENCODE_TEMP ? 0 : 1 );
u16 currentAuthType = local->config.authType;
/* Is WEP supported ? */
readCapabilityRid(local, &cap_rid, 1);
@ -6212,7 +6214,7 @@ static int airo_set_encode(struct net_device *dev,
/* Copy the key in the driver */
memcpy(key.key, extra, dwrq->length);
/* Send the key to the card */
set_wep_key(local, index, key.key, key.len, 1, 1);
set_wep_key(local, index, key.key, key.len, perm, 1);
}
/* WE specify that if a valid key is set, encryption
* should be enabled (user may turn it off later)
@ -6220,13 +6222,12 @@ static int airo_set_encode(struct net_device *dev,
if((index == current_index) && (key.len > 0) &&
(local->config.authType == AUTH_OPEN)) {
local->config.authType = AUTH_ENCRYPT;
set_bit (FLAG_COMMIT, &local->flags);
}
} else {
/* Do we want to just set the transmit key index ? */
int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
if ((index >= 0) && (index < ((cap_rid.softCap & 0x80)?4:1))) {
set_wep_key(local, index, NULL, 0, 1, 1);
set_wep_key(local, index, NULL, 0, perm, 1);
} else
/* Don't complain if only change the mode */
if(!dwrq->flags & IW_ENCODE_MODE) {
@ -6241,7 +6242,7 @@ static int airo_set_encode(struct net_device *dev,
if(dwrq->flags & IW_ENCODE_OPEN)
local->config.authType = AUTH_ENCRYPT; // Only Wep
/* Commit the changes to flags if needed */
if(dwrq->flags & IW_ENCODE_MODE)
if (local->config.authType != currentAuthType)
set_bit (FLAG_COMMIT, &local->flags);
return -EINPROGRESS; /* Call commit handler */
}

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,4 @@
hostap-y := hostap_main.o
obj-$(CONFIG_HOSTAP) += hostap.o
obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o

View file

@ -175,7 +175,7 @@ that only one external action is invoked at a time.
#define DRV_COPYRIGHT "Copyright(c) 2003-2005 Intel Corporation"
/* Debugging stuff */
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2100_DEBUG
#define CONFIG_IPW2100_RX_DEBUG /* Reception debugging */
#endif
@ -208,7 +208,7 @@ MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
static u32 ipw2100_debug_level = IPW_DL_NONE;
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2100_DEBUG
#define IPW_DEBUG(level, message...) \
do { \
if (ipw2100_debug_level & (level)) { \
@ -219,9 +219,9 @@ do { \
} while (0)
#else
#define IPW_DEBUG(level, message...) do {} while (0)
#endif /* CONFIG_IPW_DEBUG */
#endif /* CONFIG_IPW2100_DEBUG */
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2100_DEBUG
static const char *command_types[] = {
"undefined",
"unused", /* HOST_ATTENTION */
@ -2081,7 +2081,7 @@ static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
priv->status &= ~STATUS_SCANNING;
}
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2100_DEBUG
#define IPW2100_HANDLER(v, f) { v, f, # v }
struct ipw2100_status_indicator {
int status;
@ -2094,7 +2094,7 @@ struct ipw2100_status_indicator {
int status;
void (*cb) (struct ipw2100_priv * priv, u32 status);
};
#endif /* CONFIG_IPW_DEBUG */
#endif /* CONFIG_IPW2100_DEBUG */
static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status)
{
@ -2149,7 +2149,7 @@ static void isr_status_change(struct ipw2100_priv *priv, int status)
static void isr_rx_complete_command(struct ipw2100_priv *priv,
struct ipw2100_cmd_header *cmd)
{
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2100_DEBUG
if (cmd->host_command_reg < ARRAY_SIZE(command_types)) {
IPW_DEBUG_HC("Command completed '%s (%d)'\n",
command_types[cmd->host_command_reg],
@ -2167,7 +2167,7 @@ static void isr_rx_complete_command(struct ipw2100_priv *priv,
wake_up_interruptible(&priv->wait_command_queue);
}
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2100_DEBUG
static const char *frame_types[] = {
"COMMAND_STATUS_VAL",
"STATUS_CHANGE_VAL",
@ -2290,7 +2290,7 @@ static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
{
#ifdef CONFIG_IPW_DEBUG_C3
#ifdef CONFIG_IPW2100_DEBUG_C3
struct ipw2100_status *status = &priv->status_queue.drv[i];
u32 match, reg;
int j;
@ -2312,7 +2312,7 @@ static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
}
#endif
#ifdef CONFIG_IPW_DEBUG_C3
#ifdef CONFIG_IPW2100_DEBUG_C3
/* Halt the fimrware so we can get a good image */
write_register(priv->net_dev, IPW_REG_RESET_REG,
IPW_AUX_HOST_RESET_REG_STOP_MASTER);
@ -2716,7 +2716,7 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv)
list_del(element);
DEC_STAT(&priv->fw_pend_stat);
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2100_DEBUG
{
int i = txq->oldest;
IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
@ -2782,7 +2782,7 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv)
"something else: ids %d=%d.\n",
priv->net_dev->name, txq->oldest, packet->index);
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2100_DEBUG
if (packet->info.c_struct.cmd->host_command_reg <
sizeof(command_types) / sizeof(*command_types))
IPW_DEBUG_TX("Command '%s (%d)' processed: %d.\n",
@ -2975,7 +2975,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
IPW_DEBUG_TX("data header tbd TX%d P=%08x L=%d\n",
packet->index, tbd->host_addr, tbd->buf_length);
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2100_DEBUG
if (packet->info.d_struct.txb->nr_frags > 1)
IPW_DEBUG_FRAG("fragment Tx: %d frames\n",
packet->info.d_struct.txb->nr_frags);
@ -3827,7 +3827,7 @@ static ssize_t show_stats(struct device *d, struct device_attribute *attr,
priv->rx_interrupts, priv->inta_other);
out += sprintf(out, "firmware resets: %d\n", priv->resets);
out += sprintf(out, "firmware hangs: %d\n", priv->hangs);
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2100_DEBUG
out += sprintf(out, "packet mismatch image: %s\n",
priv->snapshot[0] ? "YES" : "NO");
#endif
@ -3982,7 +3982,7 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL);
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2100_DEBUG
static ssize_t show_debug_level(struct device_driver *d, char *buf)
{
return sprintf(buf, "0x%08X\n", ipw2100_debug_level);
@ -4011,7 +4011,7 @@ static ssize_t store_debug_level(struct device_driver *d,
static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level,
store_debug_level);
#endif /* CONFIG_IPW_DEBUG */
#endif /* CONFIG_IPW2100_DEBUG */
static ssize_t show_fatal_error(struct device *d,
struct device_attribute *attr, char *buf)
@ -4937,7 +4937,7 @@ static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid,
};
int err;
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2100_DEBUG
if (bssid != NULL)
IPW_DEBUG_HC("MANDATORY_BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n",
bssid[0], bssid[1], bssid[2], bssid[3], bssid[4],
@ -6858,7 +6858,7 @@ static int __init ipw2100_init(void)
ret = pci_module_init(&ipw2100_pci_driver);
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2100_DEBUG
ipw2100_debug_level = debug;
driver_create_file(&ipw2100_pci_driver.driver,
&driver_attr_debug_level);
@ -6873,7 +6873,7 @@ static int __init ipw2100_init(void)
static void __exit ipw2100_exit(void)
{
/* FIXME: IPG: check that we have no instances of the devices open */
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2100_DEBUG
driver_remove_file(&ipw2100_pci_driver.driver,
&driver_attr_debug_level);
#endif
@ -8558,7 +8558,7 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev)
quality = min(beacon_qual, min(tx_qual, rssi_qual));
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2100_DEBUG
if (beacon_qual == quality)
IPW_DEBUG_WX("Quality clamped by Missed Beacons\n");
else if (tx_qual == quality)

View file

@ -73,7 +73,7 @@ struct ipw2100_rx_packet;
* you simply need to add your entry to the ipw2100_debug_levels array.
*
* If you do not see debug_level in /proc/net/ipw2100 then you do not have
* CONFIG_IPW_DEBUG defined in your kernel configuration
* CONFIG_IPW2100_DEBUG defined in your kernel configuration
*
*/

View file

@ -462,7 +462,7 @@ static inline void ipw_disable_interrupts(struct ipw_priv *priv)
ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
}
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2200_DEBUG
static char *ipw_error_desc(u32 val)
{
switch (val) {
@ -1235,7 +1235,7 @@ static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
const char *buf, size_t count)
{
struct ipw_priv *priv = dev_get_drvdata(d);
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2200_DEBUG
struct net_device *dev = priv->net_dev;
#endif
char buffer[] = "00000000";
@ -1754,7 +1754,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
IPW_ERROR("Firmware error detected. Restarting.\n");
if (priv->error) {
IPW_ERROR("Sysfs 'error' log already exists.\n");
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2200_DEBUG
if (ipw_debug_level & IPW_DL_FW_ERRORS) {
struct ipw_fw_error *error =
ipw_alloc_error_log(priv);
@ -1770,7 +1770,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
else
IPW_ERROR("Error allocating sysfs 'error' "
"log.\n");
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2200_DEBUG
if (ipw_debug_level & IPW_DL_FW_ERRORS)
ipw_dump_error_log(priv, priv->error);
#endif
@ -3778,7 +3778,7 @@ static const struct ipw_status_code ipw_status_codes[] = {
{0x2E, "Cipher suite is rejected per security policy"},
};
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2200_DEBUG
static const char *ipw_get_status_code(u16 status)
{
int i;
@ -4250,7 +4250,7 @@ static inline void ipw_rx_notification(struct ipw_priv *priv,
if (priv->
status & (STATUS_ASSOCIATED |
STATUS_AUTH)) {
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2200_DEBUG
struct notif_authenticate *auth
= &notif->u.auth;
IPW_DEBUG(IPW_DL_NOTIF |
@ -4944,12 +4944,11 @@ static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *priv)
struct ipw_rx_queue *rxq;
int i;
rxq = (struct ipw_rx_queue *)kmalloc(sizeof(*rxq), GFP_KERNEL);
rxq = kzalloc(sizeof(*rxq), GFP_KERNEL);
if (unlikely(!rxq)) {
IPW_ERROR("memory allocation failed\n");
return NULL;
}
memset(rxq, 0, sizeof(*rxq));
spin_lock_init(&rxq->lock);
INIT_LIST_HEAD(&rxq->rx_free);
INIT_LIST_HEAD(&rxq->rx_used);
@ -5828,7 +5827,7 @@ static void ipw_bg_adhoc_check(void *data)
up(&priv->sem);
}
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2200_DEBUG
static void ipw_debug_config(struct ipw_priv *priv)
{
IPW_DEBUG_INFO("Scan completed, no valid APs matched "
@ -7812,7 +7811,7 @@ static void ipw_rx(struct ipw_priv *priv)
while (i != r) {
rxb = priv->rxq->queue[i];
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2200_DEBUG
if (unlikely(rxb == NULL)) {
printk(KERN_CRIT "Queue not allocated!\n");
break;
@ -10951,7 +10950,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
priv->net_dev = net_dev;
priv->pci_dev = pdev;
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2200_DEBUG
ipw_debug_level = debug;
#endif
spin_lock_init(&priv->lock);

View file

@ -1301,14 +1301,14 @@ struct ipw_priv {
/* debug macros */
#ifdef CONFIG_IPW_DEBUG
#ifdef CONFIG_IPW2200_DEBUG
#define IPW_DEBUG(level, fmt, args...) \
do { if (ipw_debug_level & (level)) \
printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \
in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
#else
#define IPW_DEBUG(level, fmt, args...) do {} while (0)
#endif /* CONFIG_IPW_DEBUG */
#endif /* CONFIG_IPW2200_DEBUG */
/*
* To use the debug system;
@ -1332,7 +1332,7 @@ do { if (ipw_debug_level & (level)) \
* you simply need to add your entry to the ipw_debug_levels array.
*
* If you do not see debug_level in /proc/net/ipw then you do not have
* CONFIG_IPW_DEBUG defined in your kernel configuration
* CONFIG_IPW2200_DEBUG defined in your kernel configuration
*
*/

View file

@ -684,6 +684,7 @@ extern int netif_rx(struct sk_buff *skb);
extern int netif_rx_ni(struct sk_buff *skb);
#define HAVE_NETIF_RECEIVE_SKB 1
extern int netif_receive_skb(struct sk_buff *skb);
extern int dev_valid_name(const char *name);
extern int dev_ioctl(unsigned int cmd, void __user *);
extern int dev_ethtool(struct ifreq *);
extern unsigned dev_get_flags(const struct net_device *);
@ -801,12 +802,16 @@ static inline u32 netif_msg_init(int debug_value, int default_msg_enable_bits)
return (1 << debug_value) - 1;
}
/* Schedule rx intr now? */
/* Test if receive needs to be scheduled */
static inline int __netif_rx_schedule_prep(struct net_device *dev)
{
return !test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state);
}
/* Test if receive needs to be scheduled but only if up */
static inline int netif_rx_schedule_prep(struct net_device *dev)
{
return netif_running(dev) &&
!test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state);
return netif_running(dev) && __netif_rx_schedule_prep(dev);
}
/* Add interface to tail of rx poll list. This assumes that _prep has

View file

@ -626,7 +626,7 @@ struct net_device * dev_get_by_flags(unsigned short if_flags, unsigned short mas
* Network device names need to be valid file names to
* to allow sysfs to work
*/
static int dev_valid_name(const char *name)
int dev_valid_name(const char *name)
{
return !(*name == '\0'
|| !strcmp(name, ".")
@ -3270,6 +3270,7 @@ EXPORT_SYMBOL(__dev_get_by_index);
EXPORT_SYMBOL(__dev_get_by_name);
EXPORT_SYMBOL(__dev_remove_pack);
EXPORT_SYMBOL(__skb_linearize);
EXPORT_SYMBOL(dev_valid_name);
EXPORT_SYMBOL(dev_add_pack);
EXPORT_SYMBOL(dev_alloc_name);
EXPORT_SYMBOL(dev_close);

View file

@ -175,7 +175,7 @@ __u32 in_aton(const char *str)
if (*str != '\0')
{
val = 0;
while (*str != '\0' && *str != '.')
while (*str != '\0' && *str != '.' && *str != '\n')
{
val *= 10;
val += *str - '0';