mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6
This commit is contained in:
commit
d779188d2b
67 changed files with 11406 additions and 2392 deletions
72
Documentation/networking/gianfar.txt
Normal file
72
Documentation/networking/gianfar.txt
Normal 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.
|
|
@ -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));
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
1358
drivers/net/bonding/bond_sysfs.c
Normal file
1358
drivers/net/bonding/bond_sysfs.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 |
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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(®s->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(®s->maccfg2);
|
||||
u32 ecntrl = gfar_read(®s->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(®s->maccfg2, tempval);
|
||||
gfar_write(®s->ecntrl, ecntrl);
|
||||
|
||||
if (!priv->oldlink) {
|
||||
new_state = 1;
|
||||
|
@ -1721,6 +1736,9 @@ static void gfar_set_multi(struct net_device *dev)
|
|||
gfar_write(®s->gaddr6, 0xffffffff);
|
||||
gfar_write(®s->gaddr7, 0xffffffff);
|
||||
} else {
|
||||
int em_num;
|
||||
int idx;
|
||||
|
||||
/* zero out the hash */
|
||||
gfar_write(®s->igaddr0, 0x0);
|
||||
gfar_write(®s->igaddr1, 0x0);
|
||||
|
@ -1739,18 +1757,47 @@ static void gfar_set_multi(struct net_device *dev)
|
|||
gfar_write(®s->gaddr6, 0x0);
|
||||
gfar_write(®s->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)
|
||||
{
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
311
drivers/net/gianfar_sysfs.c
Normal 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);
|
||||
|
||||
}
|
6
drivers/net/ixp2000/Kconfig
Normal file
6
drivers/net/ixp2000/Kconfig
Normal 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.
|
3
drivers/net/ixp2000/Makefile
Normal file
3
drivers/net/ixp2000/Makefile
Normal 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
137
drivers/net/ixp2000/caleb.c
Normal 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);
|
||||
}
|
22
drivers/net/ixp2000/caleb.h
Normal file
22
drivers/net/ixp2000/caleb.h
Normal 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
|
245
drivers/net/ixp2000/enp2611.c
Normal file
245
drivers/net/ixp2000/enp2611.c
Normal 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");
|
213
drivers/net/ixp2000/ixp2400-msf.c
Normal file
213
drivers/net/ixp2000/ixp2400-msf.c
Normal 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);
|
||||
}
|
115
drivers/net/ixp2000/ixp2400-msf.h
Normal file
115
drivers/net/ixp2000/ixp2400-msf.h
Normal 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
|
408
drivers/net/ixp2000/ixp2400_rx.uc
Normal file
408
drivers/net/ixp2000/ixp2400_rx.uc
Normal 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
|
||||
|
||||
|
130
drivers/net/ixp2000/ixp2400_rx.ucode
Normal file
130
drivers/net/ixp2000/ixp2400_rx.ucode
Normal 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,
|
||||
}
|
||||
};
|
272
drivers/net/ixp2000/ixp2400_tx.uc
Normal file
272
drivers/net/ixp2000/ixp2400_tx.uc
Normal 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
|
||||
|
||||
|
98
drivers/net/ixp2000/ixp2400_tx.ucode
Normal file
98
drivers/net/ixp2000/ixp2400_tx.ucode
Normal 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,
|
||||
}
|
||||
};
|
421
drivers/net/ixp2000/ixpdev.c
Normal file
421
drivers/net/ixp2000/ixpdev.c
Normal 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));
|
||||
}
|
27
drivers/net/ixp2000/ixpdev.h
Normal file
27
drivers/net/ixp2000/ixpdev.h
Normal 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
|
57
drivers/net/ixp2000/ixpdev_priv.h
Normal file
57
drivers/net/ixp2000/ixpdev_priv.h
Normal 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
|
334
drivers/net/ixp2000/pm3386.c
Normal file
334
drivers/net/ixp2000/pm3386.c
Normal 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");
|
28
drivers/net/ixp2000/pm3386.h
Normal file
28
drivers/net/ixp2000/pm3386.h
Normal 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
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -26,8 +26,7 @@ sk98lin-objs := \
|
|||
skrlmt.o \
|
||||
sktimer.o \
|
||||
skvpd.o \
|
||||
skxmac2.o \
|
||||
skproc.o
|
||||
skxmac2.o
|
||||
|
||||
# DBGDEF = \
|
||||
# -DDEBUG
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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); \
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
*
|
||||
******************************************************************************/
|
|
@ -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;
|
||||
|
|
|
@ -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
3262
drivers/net/sky2.c
Normal file
File diff suppressed because it is too large
Load diff
1922
drivers/net/sky2.h
Normal file
1922
drivers/net/sky2.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||
|
|
@ -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---
|
||||
|
|
|
@ -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
|
@ -1,3 +1,4 @@
|
|||
hostap-y := hostap_main.o
|
||||
obj-$(CONFIG_HOSTAP) += hostap.o
|
||||
|
||||
obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
|
@ -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
|
||||
= ¬if->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);
|
||||
|
|
|
@ -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
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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';
|
||||
|
|
Loading…
Reference in a new issue