Commit 5bbc1722 authored by David S. Miller's avatar David S. Miller

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

parents 30902dc3 ae7b6487
...@@ -376,7 +376,8 @@ max_bonds ...@@ -376,7 +376,8 @@ max_bonds
Specifies the number of bonding devices to create for this Specifies the number of bonding devices to create for this
instance of the bonding driver. E.g., if max_bonds is 3, and instance of the bonding driver. E.g., if max_bonds is 3, and
the bonding driver is not already loaded, then bond0, bond1 the bonding driver is not already loaded, then bond0, bond1
and bond2 will be created. The default value is 1. and bond2 will be created. The default value is 1. Specifying
a value of 0 will load bonding, but will not create any devices.
miimon miimon
...@@ -539,6 +540,17 @@ mode ...@@ -539,6 +540,17 @@ mode
swapped with the new curr_active_slave that was swapped with the new curr_active_slave that was
chosen. chosen.
num_grat_arp
Specifies the number of gratuitous ARPs to be issued after a
failover event. One gratuitous ARP is issued immediately after
the failover, subsequent ARPs are sent at a rate of one per link
monitor interval (arp_interval or miimon, whichever is active).
The valid range is 0 - 255; the default value is 1. This option
affects only the active-backup mode. This option was added for
bonding version 3.3.0.
primary primary
A string (eth0, eth2, etc) specifying which slave is the A string (eth0, eth2, etc) specifying which slave is the
......
...@@ -2147,6 +2147,8 @@ P: Jesse Brandeburg ...@@ -2147,6 +2147,8 @@ P: Jesse Brandeburg
M: jesse.brandeburg@intel.com M: jesse.brandeburg@intel.com
P: Bruce Allan P: Bruce Allan
M: bruce.w.allan@intel.com M: bruce.w.allan@intel.com
P: PJ Waskiewicz
M: peter.p.waskiewicz.jr@intel.com
P: John Ronciak P: John Ronciak
M: john.ronciak@intel.com M: john.ronciak@intel.com
L: e1000-devel@lists.sourceforge.net L: e1000-devel@lists.sourceforge.net
...@@ -2690,12 +2692,10 @@ L: libertas-dev@lists.infradead.org ...@@ -2690,12 +2692,10 @@ L: libertas-dev@lists.infradead.org
S: Maintained S: Maintained
MARVELL MV643XX ETHERNET DRIVER MARVELL MV643XX ETHERNET DRIVER
P: Dale Farnsworth P: Lennert Buytenhek
M: dale@farnsworth.org M: buytenh@marvell.com
P: Manish Lachwani
M: mlachwani@mvista.com
L: netdev@vger.kernel.org L: netdev@vger.kernel.org
S: Odd Fixes for 2.4; Maintained for 2.6. S: Supported
MATROX FRAMEBUFFER DRIVER MATROX FRAMEBUFFER DRIVER
P: Petr Vandrovec P: Petr Vandrovec
...@@ -3233,14 +3233,6 @@ L: linux-kernel@vger.kernel.org ...@@ -3233,14 +3233,6 @@ L: linux-kernel@vger.kernel.org
T: git git.infradead.org/battery-2.6.git T: git git.infradead.org/battery-2.6.git
S: Maintained S: Maintained
POWERPC 4xx EMAC DRIVER
P: Eugene Surovegin
M: ebs@ebshome.net
W: http://kernel.ebshome.net/emac/
L: linuxppc-dev@ozlabs.org
L: netdev@vger.kernel.org
S: Maintained
PNP SUPPORT PNP SUPPORT
P: Adam Belay P: Adam Belay
M: ambx1@neo.rr.com M: ambx1@neo.rr.com
......
...@@ -1255,7 +1255,6 @@ config IBMVETH ...@@ -1255,7 +1255,6 @@ config IBMVETH
To compile this driver as a module, choose M here. The module will To compile this driver as a module, choose M here. The module will
be called ibmveth. be called ibmveth.
source "drivers/net/ibm_emac/Kconfig"
source "drivers/net/ibm_newemac/Kconfig" source "drivers/net/ibm_newemac/Kconfig"
config NET_PCI config NET_PCI
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
obj-$(CONFIG_E1000) += e1000/ obj-$(CONFIG_E1000) += e1000/
obj-$(CONFIG_E1000E) += e1000e/ obj-$(CONFIG_E1000E) += e1000e/
obj-$(CONFIG_IBM_EMAC) += ibm_emac/
obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/ obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/
obj-$(CONFIG_IGB) += igb/ obj-$(CONFIG_IGB) += igb/
obj-$(CONFIG_IXGBE) += ixgbe/ obj-$(CONFIG_IXGBE) += ixgbe/
......
...@@ -1189,22 +1189,21 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) ...@@ -1189,22 +1189,21 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
if (new_active) { if (new_active) {
bond_set_slave_active_flags(new_active); bond_set_slave_active_flags(new_active);
}
if (new_active && bond->params.fail_over_mac) if (bond->params.fail_over_mac)
bond_do_fail_over_mac(bond, new_active, old_active); bond_do_fail_over_mac(bond, new_active,
old_active);
bond->send_grat_arp = bond->params.num_grat_arp; bond->send_grat_arp = bond->params.num_grat_arp;
if (bond->curr_active_slave &&
test_bit(__LINK_STATE_LINKWATCH_PENDING,
&bond->curr_active_slave->dev->state)) {
dprintk("delaying gratuitous arp on %s\n",
bond->curr_active_slave->dev->name);
} else {
if (bond->send_grat_arp > 0) {
bond_send_gratuitous_arp(bond); bond_send_gratuitous_arp(bond);
bond->send_grat_arp--;
} write_unlock_bh(&bond->curr_slave_lock);
read_unlock(&bond->lock);
netdev_bonding_change(bond->dev);
read_lock(&bond->lock);
write_lock_bh(&bond->curr_slave_lock);
} }
} }
} }
...@@ -2235,17 +2234,6 @@ static int __bond_mii_monitor(struct bonding *bond, int have_locks) ...@@ -2235,17 +2234,6 @@ static int __bond_mii_monitor(struct bonding *bond, int have_locks)
* program could monitor the link itself if needed. * program could monitor the link itself if needed.
*/ */
if (bond->send_grat_arp) {
if (bond->curr_active_slave && test_bit(__LINK_STATE_LINKWATCH_PENDING,
&bond->curr_active_slave->dev->state))
dprintk("Needs to send gratuitous arp but not yet\n");
else {
dprintk("sending delayed gratuitous arp on on %s\n",
bond->curr_active_slave->dev->name);
bond_send_gratuitous_arp(bond);
bond->send_grat_arp--;
}
}
read_lock(&bond->curr_slave_lock); read_lock(&bond->curr_slave_lock);
oldcurrent = bond->curr_active_slave; oldcurrent = bond->curr_active_slave;
read_unlock(&bond->curr_slave_lock); read_unlock(&bond->curr_slave_lock);
...@@ -2486,6 +2474,13 @@ void bond_mii_monitor(struct work_struct *work) ...@@ -2486,6 +2474,13 @@ void bond_mii_monitor(struct work_struct *work)
read_unlock(&bond->lock); read_unlock(&bond->lock);
return; return;
} }
if (bond->send_grat_arp) {
read_lock(&bond->curr_slave_lock);
bond_send_gratuitous_arp(bond);
read_unlock(&bond->curr_slave_lock);
}
if (__bond_mii_monitor(bond, 0)) { if (__bond_mii_monitor(bond, 0)) {
read_unlock(&bond->lock); read_unlock(&bond->lock);
rtnl_lock(); rtnl_lock();
...@@ -2651,6 +2646,8 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) ...@@ -2651,6 +2646,8 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
/* /*
* Kick out a gratuitous ARP for an IP on the bonding master plus one * Kick out a gratuitous ARP for an IP on the bonding master plus one
* for each VLAN above us. * for each VLAN above us.
*
* Caller must hold curr_slave_lock for read or better
*/ */
static void bond_send_gratuitous_arp(struct bonding *bond) static void bond_send_gratuitous_arp(struct bonding *bond)
{ {
...@@ -2660,9 +2657,13 @@ static void bond_send_gratuitous_arp(struct bonding *bond) ...@@ -2660,9 +2657,13 @@ static void bond_send_gratuitous_arp(struct bonding *bond)
dprintk("bond_send_grat_arp: bond %s slave %s\n", bond->dev->name, dprintk("bond_send_grat_arp: bond %s slave %s\n", bond->dev->name,
slave ? slave->dev->name : "NULL"); slave ? slave->dev->name : "NULL");
if (!slave)
if (!slave || !bond->send_grat_arp ||
test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state))
return; return;
bond->send_grat_arp--;
if (bond->master_ip) { if (bond->master_ip) {
bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip, bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip,
bond->master_ip, 0); bond->master_ip, 0);
...@@ -3166,6 +3167,12 @@ void bond_activebackup_arp_mon(struct work_struct *work) ...@@ -3166,6 +3167,12 @@ void bond_activebackup_arp_mon(struct work_struct *work)
if (bond->slave_cnt == 0) if (bond->slave_cnt == 0)
goto re_arm; goto re_arm;
if (bond->send_grat_arp) {
read_lock(&bond->curr_slave_lock);
bond_send_gratuitous_arp(bond);
read_unlock(&bond->curr_slave_lock);
}
if (bond_ab_arp_inspect(bond, delta_in_ticks)) { if (bond_ab_arp_inspect(bond, delta_in_ticks)) {
read_unlock(&bond->lock); read_unlock(&bond->lock);
rtnl_lock(); rtnl_lock();
...@@ -3840,6 +3847,7 @@ static int bond_close(struct net_device *bond_dev) ...@@ -3840,6 +3847,7 @@ static int bond_close(struct net_device *bond_dev)
write_lock_bh(&bond->lock); write_lock_bh(&bond->lock);
bond->send_grat_arp = 0;
/* signal timers not to re-arm */ /* signal timers not to re-arm */
bond->kill_timers = 1; bond->kill_timers = 1;
...@@ -4742,11 +4750,11 @@ static int bond_check_params(struct bond_params *params) ...@@ -4742,11 +4750,11 @@ static int bond_check_params(struct bond_params *params)
} }
} }
if (max_bonds < 1 || max_bonds > INT_MAX) { if (max_bonds < 0 || max_bonds > INT_MAX) {
printk(KERN_WARNING DRV_NAME printk(KERN_WARNING DRV_NAME
": Warning: max_bonds (%d) not in range %d-%d, so it " ": Warning: max_bonds (%d) not in range %d-%d, so it "
"was reset to BOND_DEFAULT_MAX_BONDS (%d)\n", "was reset to BOND_DEFAULT_MAX_BONDS (%d)\n",
max_bonds, 1, INT_MAX, BOND_DEFAULT_MAX_BONDS); max_bonds, 0, INT_MAX, BOND_DEFAULT_MAX_BONDS);
max_bonds = BOND_DEFAULT_MAX_BONDS; max_bonds = BOND_DEFAULT_MAX_BONDS;
} }
...@@ -4945,7 +4953,7 @@ static int bond_check_params(struct bond_params *params) ...@@ -4945,7 +4953,7 @@ static int bond_check_params(struct bond_params *params)
printk("\n"); printk("\n");
} else { } else if (max_bonds) {
/* miimon and arp_interval not set, we need one so things /* miimon and arp_interval not set, we need one so things
* work as expected, see bonding.txt for details * work as expected, see bonding.txt for details
*/ */
......
...@@ -53,7 +53,6 @@ extern struct bond_parm_tbl arp_validate_tbl[]; ...@@ -53,7 +53,6 @@ extern struct bond_parm_tbl arp_validate_tbl[];
extern struct bond_parm_tbl fail_over_mac_tbl[]; extern struct bond_parm_tbl fail_over_mac_tbl[];
static int expected_refcount = -1; static int expected_refcount = -1;
static struct class *netdev_class;
/*--------------------------- Data Structures -----------------------------*/ /*--------------------------- Data Structures -----------------------------*/
/* Bonding sysfs lock. Why can't we just use the subsystem lock? /* Bonding sysfs lock. Why can't we just use the subsystem lock?
...@@ -1447,19 +1446,9 @@ static struct attribute_group bonding_group = { ...@@ -1447,19 +1446,9 @@ static struct attribute_group bonding_group = {
*/ */
int bond_create_sysfs(void) int bond_create_sysfs(void)
{ {
int ret = 0; int ret;
struct bonding *firstbond;
/* get the netdev class pointer */
firstbond = container_of(bond_dev_list.next, struct bonding, bond_list);
if (!firstbond)
return -ENODEV;
netdev_class = firstbond->dev->dev.class;
if (!netdev_class)
return -ENODEV;
ret = class_create_file(netdev_class, &class_attr_bonding_masters); ret = netdev_class_create_file(&class_attr_bonding_masters);
/* /*
* Permit multiple loads of the module by ignoring failures to * Permit multiple loads of the module by ignoring failures to
* create the bonding_masters sysfs file. Bonding devices * create the bonding_masters sysfs file. Bonding devices
...@@ -1478,10 +1467,6 @@ int bond_create_sysfs(void) ...@@ -1478,10 +1467,6 @@ int bond_create_sysfs(void)
printk(KERN_ERR printk(KERN_ERR
"network device named %s already exists in sysfs", "network device named %s already exists in sysfs",
class_attr_bonding_masters.attr.name); class_attr_bonding_masters.attr.name);
else {
netdev_class = NULL;
return 0;
}
} }
return ret; return ret;
...@@ -1493,8 +1478,7 @@ int bond_create_sysfs(void) ...@@ -1493,8 +1478,7 @@ int bond_create_sysfs(void)
*/ */
void bond_destroy_sysfs(void) void bond_destroy_sysfs(void)
{ {
if (netdev_class) netdev_class_remove_file(&class_attr_bonding_masters);
class_remove_file(netdev_class, &class_attr_bonding_masters);
} }
/* /*
......
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
#include "bond_3ad.h" #include "bond_3ad.h"
#include "bond_alb.h" #include "bond_alb.h"
#define DRV_VERSION "3.2.5" #define DRV_VERSION "3.3.0"
#define DRV_RELDATE "March 21, 2008" #define DRV_RELDATE "June 10, 2008"
#define DRV_NAME "bonding" #define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
......
config IBM_EMAC
tristate "PowerPC 4xx on-chip Ethernet support"
depends on 4xx && !PPC_MERGE
help
This driver supports the PowerPC 4xx EMAC family of on-chip
Ethernet controllers.
config IBM_EMAC_RXB
int "Number of receive buffers"
depends on IBM_EMAC
default "128"
config IBM_EMAC_TXB
int "Number of transmit buffers"
depends on IBM_EMAC
default "64"
config IBM_EMAC_POLL_WEIGHT
int "MAL NAPI polling weight"
depends on IBM_EMAC
default "32"
config IBM_EMAC_RX_COPY_THRESHOLD
int "RX skb copy threshold (bytes)"
depends on IBM_EMAC
default "256"
config IBM_EMAC_RX_SKB_HEADROOM
int "Additional RX skb headroom (bytes)"
depends on IBM_EMAC
default "0"
help
Additional receive skb headroom. Note, that driver
will always reserve at least 2 bytes to make IP header
aligned, so usually there is no need to add any additional
headroom.
If unsure, set to 0.
config IBM_EMAC_PHY_RX_CLK_FIX
bool "PHY Rx clock workaround"
depends on IBM_EMAC && (405EP || 440GX || 440EP || 440GR)
help
Enable this if EMAC attached to a PHY which doesn't generate
RX clock if there is no link, if this is the case, you will
see "TX disable timeout" or "RX disable timeout" in the system
log.
If unsure, say N.
config IBM_EMAC_DEBUG
bool "Debugging"
depends on IBM_EMAC
default n
config IBM_EMAC_ZMII
bool
depends on IBM_EMAC && (NP405H || NP405L || 44x)
default y
config IBM_EMAC_RGMII
bool
depends on IBM_EMAC && 440GX
default y
config IBM_EMAC_TAH
bool
depends on IBM_EMAC && 440GX
default y
#
# Makefile for the PowerPC 4xx on-chip ethernet driver
#
obj-$(CONFIG_IBM_EMAC) += ibm_emac.o
ibm_emac-objs := ibm_emac_mal.o ibm_emac_core.o ibm_emac_phy.o
ibm_emac-$(CONFIG_IBM_EMAC_ZMII) += ibm_emac_zmii.o
ibm_emac-$(CONFIG_IBM_EMAC_RGMII) += ibm_emac_rgmii.o
ibm_emac-$(CONFIG_IBM_EMAC_TAH) += ibm_emac_tah.o
ibm_emac-$(CONFIG_IBM_EMAC_DEBUG) += ibm_emac_debug.o
This diff is collapsed.
This diff is collapsed.
/*
* drivers/net/ibm_emac/ibm_emac_core.h
*
* Driver for PowerPC 4xx on-chip ethernet controller.
*
* Copyright (c) 2004, 2005 Zultys Technologies.
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
*
* Based on original work by
* Armin Kuster <akuster@mvista.com>
* Johnnie Peters <jpeters@mvista.com>
* Copyright 2000, 2001 MontaVista Softare 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.
*
*/
#ifndef __IBM_EMAC_CORE_H_
#define __IBM_EMAC_CORE_H_
#include <linux/netdevice.h>
#include <linux/dma-mapping.h>
#include <asm/ocp.h>
#include "ibm_emac.h"
#include "ibm_emac_phy.h"
#include "ibm_emac_zmii.h"
#include "ibm_emac_rgmii.h"
#include "ibm_emac_mal.h"
#include "ibm_emac_tah.h"
#define NUM_TX_BUFF CONFIG_IBM_EMAC_TXB
#define NUM_RX_BUFF CONFIG_IBM_EMAC_RXB
/* Simple sanity check */
#if NUM_TX_BUFF > 256 || NUM_RX_BUFF > 256
#error Invalid number of buffer descriptors (greater than 256)
#endif
// XXX
#define EMAC_MIN_MTU 46
#define EMAC_MAX_MTU 9000
/* Maximum L2 header length (VLAN tagged, no FCS) */
#define EMAC_MTU_OVERHEAD (6 * 2 + 2 + 4)
/* RX BD size for the given MTU */
static inline int emac_rx_size(int mtu)
{
if (mtu > ETH_DATA_LEN)
return MAL_MAX_RX_SIZE;
else
return mal_rx_size(ETH_DATA_LEN + EMAC_MTU_OVERHEAD);
}
#define EMAC_DMA_ALIGN(x) ALIGN((x), dma_get_cache_alignment())
#define EMAC_RX_SKB_HEADROOM \
EMAC_DMA_ALIGN(CONFIG_IBM_EMAC_RX_SKB_HEADROOM)
/* Size of RX skb for the given MTU */
static inline int emac_rx_skb_size(int mtu)
{
int size = max(mtu + EMAC_MTU_OVERHEAD, emac_rx_size(mtu));
return EMAC_DMA_ALIGN(size + 2) + EMAC_RX_SKB_HEADROOM;
}
/* RX DMA sync size */
static inline int emac_rx_sync_size(int mtu)
{
return EMAC_DMA_ALIGN(emac_rx_size(mtu) + 2);
}
/* Driver statistcs is split into two parts to make it more cache friendly:
* - normal statistics (packet count, etc)
* - error statistics
*
* When statistics is requested by ethtool, these parts are concatenated,
* normal one goes first.
*
* Please, keep these structures in sync with emac_stats_keys.
*/
/* Normal TX/RX Statistics */
struct ibm_emac_stats {
u64 rx_packets;
u64 rx_bytes;
u64 tx_packets;
u64 tx_bytes;
u64 rx_packets_csum;
u64 tx_packets_csum;
};
/* Error statistics */
struct ibm_emac_error_stats {
u64 tx_undo;
/* Software RX Errors */
u64 rx_dropped_stack;
u64 rx_dropped_oom;
u64 rx_dropped_error;
u64 rx_dropped_resize;
u64 rx_dropped_mtu;
u64 rx_stopped;
/* BD reported RX errors */
u64 rx_bd_errors;
u64 rx_bd_overrun;
u64 rx_bd_bad_packet;
u64 rx_bd_runt_packet;
u64 rx_bd_short_event;
u64 rx_bd_alignment_error;
u64 rx_bd_bad_fcs;
u64 rx_bd_packet_too_long;
u64 rx_bd_out_of_range;
u64 rx_bd_in_range;
/* EMAC IRQ reported RX errors */
u64 rx_parity;
u64 rx_fifo_overrun;
u64 rx_overrun;
u64 rx_bad_packet;
u64 rx_runt_packet;
u64 rx_short_event;
u64 rx_alignment_error;
u64 rx_bad_fcs;
u64 rx_packet_too_long;
u64 rx_out_of_range;
u64 rx_in_range;
/* Software TX Errors */
u64 tx_dropped;
/* BD reported TX errors */
u64 tx_bd_errors;
u64 tx_bd_bad_fcs;
u64 tx_bd_carrier_loss;
u64 tx_bd_excessive_deferral;
u64 tx_bd_excessive_collisions;
u64 tx_bd_late_collision;
u64 tx_bd_multple_collisions;
u64 tx_bd_single_collision;
u64 tx_bd_underrun;
u64 tx_bd_sqe;
/* EMAC IRQ reported TX errors */
u64 tx_parity;
u64 tx_underrun;
u64 tx_sqe;
u64 tx_errors;
};
#define EMAC_ETHTOOL_STATS_COUNT ((sizeof(struct ibm_emac_stats) + \
sizeof(struct ibm_emac_error_stats)) \
/ sizeof(u64))
struct ocp_enet_private {
struct net_device *ndev; /* 0 */
struct emac_regs __iomem *emacp;
struct mal_descriptor *tx_desc;
int tx_cnt;
int tx_slot;
int ack_slot;
struct mal_descriptor *rx_desc;
int rx_slot;
struct sk_buff *rx_sg_skb; /* 1 */
int rx_skb_size;
int rx_sync_size;
struct ibm_emac_stats stats;
struct ocp_device *tah_dev;
struct ibm_ocp_mal *mal;
struct mal_commac commac;
struct sk_buff *tx_skb[NUM_TX_BUFF];
struct sk_buff *rx_skb[NUM_RX_BUFF];
struct ocp_device *zmii_dev;
int zmii_input;
struct ocp_enet_private *mdio_dev;
struct ocp_device *rgmii_dev;
int rgmii_input;
struct ocp_def *def;
struct mii_phy phy;
struct timer_list link_timer;
int reset_failed;
int stop_timeout; /* in us */
struct ibm_emac_error_stats estats;
struct net_device_stats nstats;
struct device* ldev;
};
/* Ethtool get_regs complex data.
* We want to get not just EMAC registers, but also MAL, ZMII, RGMII, TAH
* when available.
*
* Returned BLOB consists of the ibm_emac_ethtool_regs_hdr,
* MAL registers, EMAC registers and optional ZMII, RGMII, TAH registers.
* Each register component is preceded with emac_ethtool_regs_subhdr.
* Order of the optional headers follows their relative bit posititions
* in emac_ethtool_regs_hdr.components
*/
#define EMAC_ETHTOOL_REGS_ZMII 0x00000001
#define EMAC_ETHTOOL_REGS_RGMII 0x00000002
#define EMAC_ETHTOOL_REGS_TAH 0x00000004
struct emac_ethtool_regs_hdr {
u32 components;
};
struct emac_ethtool_regs_subhdr {
u32 version;
u32 index;
};
#endif /* __IBM_EMAC_CORE_H_ */
/*
* drivers/net/ibm_emac/ibm_emac_debug.c
*
* Driver for PowerPC 4xx on-chip ethernet controller, debug print routines.
*
* Copyright (c) 2004, 2005 Zultys Technologies
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
*
* 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/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/sysrq.h>
#include <asm/io.h>
#include "ibm_emac_core.h"
static void emac_desc_dump(int idx, struct ocp_enet_private *p)
{
int i;
printk("** EMAC%d TX BDs **\n"
" tx_cnt = %d tx_slot = %d ack_slot = %d\n",
idx, p->tx_cnt, p->tx_slot, p->ack_slot);
for (i = 0; i < NUM_TX_BUFF / 2; ++i)
printk
("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n",
i, p->tx_desc[i].data_ptr, p->tx_skb[i] ? 'V' : ' ',
p->tx_desc[i].ctrl, p->tx_desc[i].data_len,
NUM_TX_BUFF / 2 + i,
p->tx_desc[NUM_TX_BUFF / 2 + i].data_ptr,
p->tx_skb[NUM_TX_BUFF / 2 + i] ? 'V' : ' ',
p->tx_desc[NUM_TX_BUFF / 2 + i].ctrl,
p->tx_desc[NUM_TX_BUFF / 2 + i].data_len);
printk("** EMAC%d RX BDs **\n"
" rx_slot = %d rx_stopped = %d rx_skb_size = %d rx_sync_size = %d\n"
" rx_sg_skb = 0x%p\n",
idx, p->rx_slot, p->commac.rx_stopped, p->rx_skb_size,
p->rx_sync_size, p->rx_sg_skb);
for (i = 0; i < NUM_RX_BUFF / 2; ++i)
printk
("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n",
i, p->rx_desc[i].data_ptr, p->rx_skb[i] ? 'V' : ' ',
p->rx_desc[i].ctrl, p->rx_desc[i].data_len,
NUM_RX_BUFF / 2 + i,
p->rx_desc[NUM_RX_BUFF / 2 + i].data_ptr,
p->rx_skb[NUM_RX_BUFF / 2 + i] ? 'V' : ' ',
p->rx_desc[NUM_RX_BUFF / 2 + i].ctrl,
p->rx_desc[NUM_RX_BUFF / 2 + i].data_len);
}
static void emac_mac_dump(int idx, struct ocp_enet_private *dev)
{
struct emac_regs __iomem *p = dev->emacp;
printk("** EMAC%d registers **\n"
"MR0 = 0x%08x MR1 = 0x%08x TMR0 = 0x%08x TMR1 = 0x%08x\n"
"RMR = 0x%08x ISR = 0x%08x ISER = 0x%08x\n"
"IAR = %04x%08x VTPID = 0x%04x VTCI = 0x%04x\n"
"IAHT: 0x%04x 0x%04x 0x%04x 0x%04x "
"GAHT: 0x%04x 0x%04x 0x%04x 0x%04x\n"
"LSA = %04x%08x IPGVR = 0x%04x\n"
"STACR = 0x%08x TRTR = 0x%08x RWMR = 0x%08x\n"
"OCTX = 0x%08x OCRX = 0x%08x IPCR = 0x%08x\n",
idx, in_be32(&p->mr0), in_be32(&p->mr1),
in_be32(&p->tmr0), in_be32(&p->tmr1),
in_be32(&p->rmr), in_be32(&p->isr), in_be32(&p->iser),
in_be32(&p->iahr), in_be32(&p->ialr), in_be32(&p->vtpid),
in_be32(&p->vtci),
in_be32(&p->iaht1), in_be32(&p->iaht2), in_be32(&p->iaht3),
in_be32(&p->iaht4),
in_be32(&p->gaht1), in_be32(&p->gaht2), in_be32(&p->gaht3),
in_be32(&p->gaht4),
in_be32(&p->lsah), in_be32(&p->lsal), in_be32(&p->ipgvr),
in_be32(&p->stacr), in_be32(&p->trtr), in_be32(&p->rwmr),
in_be32(&p->octx), in_be32(&p->ocrx), in_be32(&p->ipcr)
);
emac_desc_dump(idx, dev);
}
static void emac_mal_dump(struct ibm_ocp_mal *mal)
{
struct ocp_func_mal_data *maldata = mal->def->additions;
int i;
printk("** MAL%d Registers **\n"
"CFG = 0x%08x ESR = 0x%08x IER = 0x%08x\n"
"TX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n"
"RX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n",
mal->def->index,
get_mal_dcrn(mal, MAL_CFG), get_mal_dcrn(mal, MAL_ESR),
get_mal_dcrn(mal, MAL_IER),
get_mal_dcrn(mal, MAL_TXCASR), get_mal_dcrn(mal, MAL_TXCARR),
get_mal_dcrn(mal, MAL_TXEOBISR), get_mal_dcrn(mal, MAL_TXDEIR),
get_mal_dcrn(mal, MAL_RXCASR), get_mal_dcrn(mal, MAL_RXCARR),
get_mal_dcrn(mal, MAL_RXEOBISR), get_mal_dcrn(mal, MAL_RXDEIR)
);
printk("TX|");
for (i = 0; i < maldata->num_tx_chans; ++i) {
if (i && !(i % 4))
printk("\n ");
printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_TXCTPR(i)));
}
printk("\nRX|");
for (i = 0; i < maldata->num_rx_chans; ++i) {
if (i && !(i % 4))
printk("\n ");
printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_RXCTPR(i)));
}
printk("\n ");
for (i = 0; i < maldata->num_rx_chans; ++i) {
u32 r = get_mal_dcrn(mal, MAL_RCBS(i));
if (i && !(i % 3))
printk("\n ");
printk("RCBS%d = 0x%08x (%d) ", i, r, r * 16);
}
printk("\n");
}
static struct ocp_enet_private *__emacs[4];
static struct ibm_ocp_mal *__mals[1];
void emac_dbg_register(int idx, struct ocp_enet_private *dev)
{
unsigned long flags;
if (idx >= ARRAY_SIZE(__emacs)) {
printk(KERN_WARNING
"invalid index %d when registering EMAC for debugging\n",
idx);
return;
}
local_irq_save(flags);
__emacs[idx] = dev;
local_irq_restore(flags);
}
void mal_dbg_register(int idx, struct ibm_ocp_mal *mal)
{
unsigned long flags;
if (idx >= ARRAY_SIZE(__mals)) {
printk(KERN_WARNING
"invalid index %d when registering MAL for debugging\n",
idx);
return;
}
local_irq_save(flags);
__mals[idx] = mal;
local_irq_restore(flags);
}
void emac_dbg_dump_all(void)
{
unsigned int i;
unsigned long flags;
local_irq_save(flags);
for (i = 0; i < ARRAY_SIZE(__mals); ++i)
if (__mals[i])
emac_mal_dump(__mals[i]);
for (i = 0; i < ARRAY_SIZE(__emacs); ++i)
if (__emacs[i])
emac_mac_dump(i, __emacs[i]);
local_irq_restore(flags);
}
#if defined(CONFIG_MAGIC_SYSRQ)
static void emac_sysrq_handler(int key, struct tty_struct *tty)
{
emac_dbg_dump_all();
}
static struct sysrq_key_op emac_sysrq_op = {
.handler = emac_sysrq_handler,
.help_msg = "emaC",
.action_msg = "Show EMAC(s) status",
};
int __init emac_init_debug(void)
{
return register_sysrq_key('c', &emac_sysrq_op);
}
void __exit emac_fini_debug(void)
{
unregister_sysrq_key('c', &emac_sysrq_op);
}
#else
int __init emac_init_debug(void)
{
return 0;
}
void __exit emac_fini_debug(void)
{
}
#endif /* CONFIG_MAGIC_SYSRQ */
/*
* drivers/net/ibm_emac/ibm_emac_debug.h
*
* Driver for PowerPC 4xx on-chip ethernet controller, debug print routines.
*
* Copyright (c) 2004, 2005 Zultys Technologies
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
*
* 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 __IBM_EMAC_DEBUG_H_
#define __IBM_EMAC_DEBUG_H_
#include <linux/init.h>
#include "ibm_emac_core.h"
#include "ibm_emac_mal.h"
#if defined(CONFIG_IBM_EMAC_DEBUG)
void emac_dbg_register(int idx, struct ocp_enet_private *dev);
void mal_dbg_register(int idx, struct ibm_ocp_mal *mal);
int emac_init_debug(void) __init;
void emac_fini_debug(void) __exit;
void emac_dbg_dump_all(void);
# define DBG_LEVEL 1
#else
# define emac_dbg_register(x,y) ((void)0)
# define mal_dbg_register(x,y) ((void)0)
# define emac_init_debug() ((void)0)
# define emac_fini_debug() ((void)0)
# define emac_dbg_dump_all() ((void)0)
# define DBG_LEVEL 0
#endif
#if DBG_LEVEL > 0
# define DBG(f,x...) printk("emac" f, ##x)
# define MAL_DBG(f,x...) printk("mal" f, ##x)
# define ZMII_DBG(f,x...) printk("zmii" f, ##x)
# define RGMII_DBG(f,x...) printk("rgmii" f, ##x)
# define NL "\n"
#else
# define DBG(f,x...) ((void)0)
# define MAL_DBG(f,x...) ((void)0)
# define ZMII_DBG(f,x...) ((void)0)
# define RGMII_DBG(f,x...) ((void)0)
#endif
#if DBG_LEVEL > 1
# define DBG2(f,x...) DBG(f, ##x)
# define MAL_DBG2(f,x...) MAL_DBG(f, ##x)
# define ZMII_DBG2(f,x...) ZMII_DBG(f, ##x)
# define RGMII_DBG2(f,x...) RGMII_DBG(f, ##x)
#else
# define DBG2(f,x...) ((void)0)
# define MAL_DBG2(f,x...) ((void)0)
# define ZMII_DBG2(f,x...) ((void)0)
# define RGMII_DBG2(f,x...) ((void)0)
#endif
#endif /* __IBM_EMAC_DEBUG_H_ */
This diff is collapsed.
/*
* drivers/net/ibm_emac/ibm_emac_mal.h
*
* Memory Access Layer (MAL) support
*
* Copyright (c) 2004, 2005 Zultys Technologies.
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
*
* Based on original work by
* Armin Kuster <akuster@mvista.com>
* Copyright 2002 MontaVista Softare 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.
*
*/
#ifndef __IBM_EMAC_MAL_H_
#define __IBM_EMAC_MAL_H_
#include <linux/init.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <asm/io.h>
#include <asm/dcr.h>
/*
* These MAL "versions" probably aren't the real versions IBM uses for these
* MAL cores, I assigned them just to make #ifdefs in this file nicer and
* reflect the fact that 40x and 44x have slightly different MALs. --ebs
*/
#if defined(CONFIG_405GP) || defined(CONFIG_405GPR) || defined(CONFIG_405EP) || \
defined(CONFIG_440EP) || defined(CONFIG_440GR) || defined(CONFIG_NP405H)
#define MAL_VERSION 1
#elif defined(CONFIG_440GP) || defined(CONFIG_440GX) || defined(CONFIG_440SP) || \
defined(CONFIG_440SPE)
#define MAL_VERSION 2
#else
#error "Unknown SoC, please check chip manual and choose MAL 'version'"
#endif
/* MALx DCR registers */
#define MAL_CFG 0x00
#define MAL_CFG_SR 0x80000000
#define MAL_CFG_PLBB 0x00004000
#define MAL_CFG_OPBBL 0x00000080
#define MAL_CFG_EOPIE 0x00000004
#define MAL_CFG_LEA 0x00000002
#define MAL_CFG_SD 0x00000001
#if MAL_VERSION == 1
#define MAL_CFG_PLBP_MASK 0x00c00000
#define MAL_CFG_PLBP_10 0x00800000
#define MAL_CFG_GA 0x00200000
#define MAL_CFG_OA 0x00100000
#define MAL_CFG_PLBLE 0x00080000
#define MAL_CFG_PLBT_MASK 0x00078000
#define MAL_CFG_DEFAULT (MAL_CFG_PLBP_10 | MAL_CFG_PLBT_MASK)
#elif MAL_VERSION == 2
#define MAL_CFG_RPP_MASK 0x00c00000
#define MAL_CFG_RPP_10 0x00800000
#define MAL_CFG_RMBS_MASK 0x00300000
#define MAL_CFG_WPP_MASK 0x000c0000
#define MAL_CFG_WPP_10 0x00080000
#define MAL_CFG_WMBS_MASK 0x00030000
#define MAL_CFG_PLBLE 0x00008000
#define MAL_CFG_DEFAULT (MAL_CFG_RMBS_MASK | MAL_CFG_WMBS_MASK | \
MAL_CFG_RPP_10 | MAL_CFG_WPP_10)
#else
#error "Unknown MAL version"
#endif
#define MAL_ESR 0x01
#define MAL_ESR_EVB 0x80000000
#define MAL_ESR_CIDT 0x40000000
#define MAL_ESR_CID_MASK 0x3e000000
#define MAL_ESR_CID_SHIFT 25
#define MAL_ESR_DE 0x00100000
#define MAL_ESR_OTE 0x00040000
#define MAL_ESR_OSE 0x00020000
#define MAL_ESR_PEIN 0x00010000
#define MAL_ESR_DEI 0x00000010
#define MAL_ESR_OTEI 0x00000004
#define MAL_ESR_OSEI 0x00000002
#define MAL_ESR_PBEI 0x00000001
#if MAL_VERSION == 1
#define MAL_ESR_ONE 0x00080000
#define MAL_ESR_ONEI 0x00000008
#elif MAL_VERSION == 2
#define MAL_ESR_PTE 0x00800000
#define MAL_ESR_PRE 0x00400000
#define MAL_ESR_PWE 0x00200000
#define MAL_ESR_PTEI 0x00000080
#define MAL_ESR_PREI 0x00000040
#define MAL_ESR_PWEI 0x00000020
#else
#error "Unknown MAL version"
#endif
#define MAL_IER 0x02
#define MAL_IER_DE 0x00000010
#define MAL_IER_OTE 0x00000004
#define MAL_IER_OE 0x00000002
#define MAL_IER_PE 0x00000001
#if MAL_VERSION == 1
#define MAL_IER_NWE 0x00000008
#define MAL_IER_SOC_EVENTS MAL_IER_NWE
#elif MAL_VERSION == 2
#define MAL_IER_PT 0x00000080
#define MAL_IER_PRE 0x00000040
#define MAL_IER_PWE 0x00000020
#define MAL_IER_SOC_EVENTS (MAL_IER_PT | MAL_IER_PRE | MAL_IER_PWE)
#else
#error "Unknown MAL version"
#endif
#define MAL_IER_EVENTS (MAL_IER_SOC_EVENTS | MAL_IER_OTE | \
MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE)
#define MAL_TXCASR 0x04
#define MAL_TXCARR 0x05
#define MAL_TXEOBISR 0x06
#define MAL_TXDEIR 0x07
#define MAL_RXCASR 0x10
#define MAL_RXCARR 0x11
#define MAL_RXEOBISR 0x12
#define MAL_RXDEIR 0x13
#define MAL_TXCTPR(n) ((n) + 0x20)
#define MAL_RXCTPR(n) ((n) + 0x40)
#define MAL_RCBS(n) ((n) + 0x60)
/* In reality MAL can handle TX buffers up to 4095 bytes long,
* but this isn't a good round number :) --ebs
*/
#define MAL_MAX_TX_SIZE 4080
#define MAL_MAX_RX_SIZE 4080
static inline int mal_rx_size(int len)
{
len = (len + 0xf) & ~0xf;
return len > MAL_MAX_RX_SIZE ? MAL_MAX_RX_SIZE : len;
}
static inline int mal_tx_chunks(int len)
{
return (len + MAL_MAX_TX_SIZE - 1) / MAL_MAX_TX_SIZE;
}
#define MAL_CHAN_MASK(n) (0x80000000 >> (n))
/* MAL Buffer Descriptor structure */
struct mal_descriptor {
u16 ctrl; /* MAL / Commac status control bits */
u16 data_len; /* Max length is 4K-1 (12 bits) */
u32 data_ptr; /* pointer to actual data buffer */
};
/* the following defines are for the MadMAL status and control registers. */
/* MADMAL transmit and receive status/control bits */
#define MAL_RX_CTRL_EMPTY 0x8000
#define MAL_RX_CTRL_WRAP 0x4000
#define MAL_RX_CTRL_CM 0x2000
#define MAL_RX_CTRL_LAST 0x1000
#define MAL_RX_CTRL_FIRST 0x0800
#define MAL_RX_CTRL_INTR 0x0400
#define MAL_RX_CTRL_SINGLE (MAL_RX_CTRL_LAST | MAL_RX_CTRL_FIRST)
#define MAL_IS_SINGLE_RX(ctrl) (((ctrl) & MAL_RX_CTRL_SINGLE) == MAL_RX_CTRL_SINGLE)
#define MAL_TX_CTRL_READY 0x8000
#define MAL_TX_CTRL_WRAP 0x4000
#define MAL_TX_CTRL_CM 0x2000
#define MAL_TX_CTRL_LAST 0x1000
#define MAL_TX_CTRL_INTR 0x0400
struct mal_commac_ops {
void (*poll_tx) (void *dev);
int (*poll_rx) (void *dev, int budget);
int (*peek_rx) (void *dev);
void (*rxde) (void *dev);
};
struct mal_commac {
struct mal_commac_ops *ops;
void *dev;
struct list_head poll_list;
int rx_stopped;
u32 tx_chan_mask;
u32 rx_chan_mask;
struct list_head list;
};
struct ibm_ocp_mal {
dcr_host_t dcrhost;
struct list_head poll_list;
struct napi_struct napi;
struct list_head list;
u32 tx_chan_mask;
u32 rx_chan_mask;
dma_addr_t bd_dma;
struct mal_descriptor *bd_virt;
struct ocp_def *def;
};
static inline u32 get_mal_dcrn(struct ibm_ocp_mal *mal, int reg)
{
return dcr_read(mal->dcrhost, reg);
}
static inline void set_mal_dcrn(struct ibm_ocp_mal *mal, int reg, u32 val)
{
dcr_write(mal->dcrhost, reg, val);
}
/* Register MAL devices */
int mal_init(void) __init;
void mal_exit(void) __exit;
int mal_register_commac(struct ibm_ocp_mal *mal,
struct mal_commac *commac) __init;
void mal_unregister_commac(struct ibm_ocp_mal *mal, struct mal_commac *commac);
int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel, unsigned long size);
/* Returns BD ring offset for a particular channel
(in 'struct mal_descriptor' elements)
*/
int mal_tx_bd_offset(struct ibm_ocp_mal *mal, int channel);
int mal_rx_bd_offset(struct ibm_ocp_mal *mal, int channel);
void mal_enable_tx_channel(struct ibm_ocp_mal *mal, int channel);
void mal_disable_tx_channel(struct ibm_ocp_mal *mal, int channel);
void mal_enable_rx_channel(struct ibm_ocp_mal *mal, int channel);
void mal_disable_rx_channel(struct ibm_ocp_mal *mal, int channel);
/* Add/remove EMAC to/from MAL polling list */
void mal_poll_add(struct ibm_ocp_mal *mal, struct mal_commac *commac);
void mal_poll_del(struct ibm_ocp_mal *mal, struct mal_commac *commac);
/* Ethtool MAL registers */
struct ibm_mal_regs {
u32 tx_count;
u32 rx_count;
u32 cfg;
u32 esr;
u32 ier;
u32 tx_casr;
u32 tx_carr;
u32 tx_eobisr;
u32 tx_deir;
u32 rx_casr;
u32 rx_carr;
u32 rx_eobisr;
u32 rx_deir;
u32 tx_ctpr[32];
u32 rx_ctpr[32];
u32 rcbs[32];
};
int mal_get_regs_len(struct ibm_ocp_mal *mal);
void *mal_dump_regs(struct ibm_ocp_mal *mal, void *buf);
#endif /* __IBM_EMAC_MAL_H_ */
/*
* drivers/net/ibm_emac/ibm_emac_phy.c
*
* Driver for PowerPC 4xx on-chip ethernet controller, PHY support.
* Borrowed from sungem_phy.c, though I only kept the generic MII
* driver for now.
*
* This file should be shared with other drivers or eventually
* merged as the "low level" part of miilib
*
* (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org)
* (c) 2004-2005, Eugene Surovegin <ebs@ebshome.net>
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/delay.h>
#include <asm/ocp.h>
#include "ibm_emac_core.h"
#include "ibm_emac_phy.h"
static inline int phy_read(struct mii_phy *phy, int reg)
{
return phy->mdio_read(phy->dev, phy->address, reg);
}
static inline void phy_write(struct mii_phy *phy, int reg, int val)
{
phy->mdio_write(phy->dev, phy->address, reg, val);
}
/*
* polls MII_BMCR until BMCR_RESET bit clears or operation times out.
*
* returns:
* >= 0 => success, value in BMCR returned to caller
* -EBUSY => failure, RESET bit never cleared
* otherwise => failure, lower level PHY read failed
*/
static int mii_spin_reset_complete(struct mii_phy *phy)
{
int val;
int limit = 10000;
while (limit--) {
val = phy_read(phy, MII_BMCR);
if (val >= 0 && !(val & BMCR_RESET))
return val; /* success */
udelay(10);
}
if (val & BMCR_RESET)
val = -EBUSY;
if (net_ratelimit())
printk(KERN_ERR "emac%d: PHY reset timeout (%d)\n",
((struct ocp_enet_private *)phy->dev->priv)->def->index,
val);
return val;
}
int mii_reset_phy(struct mii_phy *phy)
{
int val;
val = phy_read(phy, MII_BMCR);
val &= ~BMCR_ISOLATE;
val |= BMCR_RESET;
phy_write(phy, MII_BMCR, val);
udelay(300);
val = mii_spin_reset_complete(phy);
if (val >= 0 && (val & BMCR_ISOLATE))
phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);
return val < 0;
}
static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
{
int ctl, adv;
phy->autoneg = AUTONEG_ENABLE;
phy->speed = SPEED_10;
phy->duplex = DUPLEX_HALF;
phy->pause = phy->asym_pause = 0;
phy->advertising = advertise;
/* Setup standard advertise */
adv = phy_read(phy, MII_ADVERTISE);
if (adv < 0)
return adv;
adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
ADVERTISE_PAUSE_ASYM);
if (advertise & ADVERTISED_10baseT_Half)
adv |= ADVERTISE_10HALF;
if (advertise & ADVERTISED_10baseT_Full)
adv |= ADVERTISE_10FULL;
if (advertise & ADVERTISED_100baseT_Half)
adv |= ADVERTISE_100HALF;
if (advertise & ADVERTISED_100baseT_Full)
adv |= ADVERTISE_100FULL;
if (advertise & ADVERTISED_Pause)
adv |= ADVERTISE_PAUSE_CAP;
if (advertise & ADVERTISED_Asym_Pause)
adv |= ADVERTISE_PAUSE_ASYM;
phy_write(phy, MII_ADVERTISE, adv);
if (phy->features &
(SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {
adv = phy_read(phy, MII_CTRL1000);
if (adv < 0)
return adv;
adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
if (advertise & ADVERTISED_1000baseT_Full)
adv |= ADVERTISE_1000FULL;
if (advertise & ADVERTISED_1000baseT_Half)
adv |= ADVERTISE_1000HALF;
phy_write(phy, MII_CTRL1000, adv);
}
/* Start/Restart aneg */
/* on some PHYs (e.g. National DP83843) a write to MII_ADVERTISE
* causes BMCR_RESET to be set on the next read of MII_BMCR, which
* if not checked for causes the PHY to be reset below */
ctl = mii_spin_reset_complete(phy);
if (ctl < 0)
return ctl;
ctl |= BMCR_ANENABLE | BMCR_ANRESTART;
phy_write(phy, MII_BMCR, ctl);
return 0;
}
static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
{
int ctl;
phy->autoneg = AUTONEG_DISABLE;
phy->speed = speed;
phy->duplex = fd;
phy->pause = phy->asym_pause = 0;
/* First reset the PHY */
mii_reset_phy(phy);
ctl = phy_read(phy, MII_BMCR);
if (ctl < 0)
return ctl;
ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE | BMCR_SPEED1000);
/* Select speed & duplex */
switch (speed) {
case SPEED_10:
break;
case SPEED_100:
ctl |= BMCR_SPEED100;
break;
case SPEED_1000:
ctl |= BMCR_SPEED1000;
break;
default:
return -EINVAL;
}
if (fd == DUPLEX_FULL)
ctl |= BMCR_FULLDPLX;
phy_write(phy, MII_BMCR, ctl);
return 0;
}
static int genmii_poll_link(struct mii_phy *phy)
{
int status;
/* Clear latched value with dummy read */
phy_read(phy, MII_BMSR);
status = phy_read(phy, MII_BMSR);
if (status < 0 || (status & BMSR_LSTATUS) == 0)
return 0;
if (phy->autoneg == AUTONEG_ENABLE && !(status & BMSR_ANEGCOMPLETE))
return 0;
return 1;
}
static int genmii_read_link(struct mii_phy *phy)
{
if (phy->autoneg == AUTONEG_ENABLE) {
int glpa = 0;
int lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE);
if (lpa < 0)
return lpa;
if (phy->features &
(SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {
int adv = phy_read(phy, MII_CTRL1000);
glpa = phy_read(phy, MII_STAT1000);
if (glpa < 0 || adv < 0)
return adv;
glpa &= adv << 2;
}
phy->speed = SPEED_10;
phy->duplex = DUPLEX_HALF;
phy->pause = phy->asym_pause = 0;
if (glpa & (LPA_1000FULL | LPA_1000HALF)) {
phy->speed = SPEED_1000;
if (glpa & LPA_1000FULL)
phy->duplex = DUPLEX_FULL;
} else if (lpa & (LPA_100FULL | LPA_100HALF)) {
phy->speed = SPEED_100;
if (lpa & LPA_100FULL)
phy->duplex = DUPLEX_FULL;
} else if (lpa & LPA_10FULL)
phy->duplex = DUPLEX_FULL;
if (phy->duplex == DUPLEX_FULL) {
phy->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
phy->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
}
} else {
int bmcr = phy_read(phy, MII_BMCR);
if (bmcr < 0)
return bmcr;
if (bmcr & BMCR_FULLDPLX)
phy->duplex = DUPLEX_FULL;
else
phy->duplex = DUPLEX_HALF;
if (bmcr & BMCR_SPEED1000)
phy->speed = SPEED_1000;
else if (bmcr & BMCR_SPEED100)
phy->speed = SPEED_100;
else
phy->speed = SPEED_10;
phy->pause = phy->asym_pause = 0;
}
return 0;
}
/* Generic implementation for most 10/100/1000 PHYs */
static struct mii_phy_ops generic_phy_ops = {
.setup_aneg = genmii_setup_aneg,
.setup_forced = genmii_setup_forced,
.poll_link = genmii_poll_link,
.read_link = genmii_read_link
};
static struct mii_phy_def genmii_phy_def = {
.phy_id = 0x00000000,
.phy_id_mask = 0x00000000,
.name = "Generic MII",
.ops = &generic_phy_ops
};
/* CIS8201 */
#define MII_CIS8201_10BTCSR 0x16
#define TENBTCSR_ECHO_DISABLE 0x2000
#define MII_CIS8201_EPCR 0x17
#define EPCR_MODE_MASK 0x3000
#define EPCR_GMII_MODE 0x0000
#define EPCR_RGMII_MODE 0x1000
#define EPCR_TBI_MODE 0x2000
#define EPCR_RTBI_MODE 0x3000
#define MII_CIS8201_ACSR 0x1c
#define ACSR_PIN_PRIO_SELECT 0x0004
static int cis8201_init(struct mii_phy *phy)
{
int epcr;
epcr = phy_read(phy, MII_CIS8201_EPCR);
if (epcr < 0)
return epcr;
epcr &= ~EPCR_MODE_MASK;
switch (phy->mode) {
case PHY_MODE_TBI:
epcr |= EPCR_TBI_MODE;
break;
case PHY_MODE_RTBI:
epcr |= EPCR_RTBI_MODE;
break;
case PHY_MODE_GMII:
epcr |= EPCR_GMII_MODE;
break;
case PHY_MODE_RGMII:
default:
epcr |= EPCR_RGMII_MODE;
}
phy_write(phy, MII_CIS8201_EPCR, epcr);
/* MII regs override strap pins */
phy_write(phy, MII_CIS8201_ACSR,
phy_read(phy, MII_CIS8201_ACSR) | ACSR_PIN_PRIO_SELECT);
/* Disable TX_EN -> CRS echo mode, otherwise 10/HDX doesn't work */
phy_write(phy, MII_CIS8201_10BTCSR,
phy_read(phy, MII_CIS8201_10BTCSR) | TENBTCSR_ECHO_DISABLE);
return 0;
}
static struct mii_phy_ops cis8201_phy_ops = {
.init = cis8201_init,
.setup_aneg = genmii_setup_aneg,
.setup_forced = genmii_setup_forced,
.poll_link = genmii_poll_link,
.read_link = genmii_read_link
};
static struct mii_phy_def cis8201_phy_def = {
.phy_id = 0x000fc410,
.phy_id_mask = 0x000ffff0,
.name = "CIS8201 Gigabit Ethernet",
.ops = &cis8201_phy_ops
};
static struct mii_phy_def *mii_phy_table[] = {
&cis8201_phy_def,
&genmii_phy_def,
NULL
};
int mii_phy_probe(struct mii_phy *phy, int address)
{
struct mii_phy_def *def;
int i;
int id;
phy->autoneg = AUTONEG_DISABLE;
phy->advertising = 0;
phy->address = address;
phy->speed = SPEED_10;
phy->duplex = DUPLEX_HALF;
phy->pause = phy->asym_pause = 0;
/* Take PHY out of isolate mode and reset it. */
if (mii_reset_phy(phy))
return -ENODEV;
/* Read ID and find matching entry */
id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2);
if (id < 0)
return -ENODEV;
for (i = 0; (def = mii_phy_table[i]) != NULL; i++)
if ((id & def->phy_id_mask) == def->phy_id)
break;
/* Should never be NULL (we have a generic entry), but... */
if (!def)
return -ENODEV;
phy->def = def;
/* Determine PHY features if needed */
phy->features = def->features;
if (!phy->features) {
u16 bmsr = phy_read(phy, MII_BMSR);
if (bmsr & BMSR_ANEGCAPABLE)
phy->features |= SUPPORTED_Autoneg;
if (bmsr & BMSR_10HALF)
phy->features |= SUPPORTED_10baseT_Half;
if (bmsr & BMSR_10FULL)
phy->features |= SUPPORTED_10baseT_Full;
if (bmsr & BMSR_100HALF)
phy->features |= SUPPORTED_100baseT_Half;
if (bmsr & BMSR_100FULL)
phy->features |= SUPPORTED_100baseT_Full;
if (bmsr & BMSR_ESTATEN) {
u16 esr = phy_read(phy, MII_ESTATUS);
if (esr & ESTATUS_1000_TFULL)
phy->features |= SUPPORTED_1000baseT_Full;
if (esr & ESTATUS_1000_THALF)
phy->features |= SUPPORTED_1000baseT_Half;
}
phy->features |= SUPPORTED_MII;
}
/* Setup default advertising */
phy->advertising = phy->features;
return 0;
}
MODULE_LICENSE("GPL");
/*
* drivers/net/ibm_emac/ibm_emac_phy.h
*
* Driver for PowerPC 4xx on-chip ethernet controller, PHY support
*
* Benjamin Herrenschmidt <benh@kernel.crashing.org>
* February 2003
*
* Minor additions by Eugene Surovegin <ebs@ebshome.net>, 2004
*
* 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.
*
* This file basically duplicates sungem_phy.{c,h} with different PHYs
* supported. I'm looking into merging that in a single mii layer more
* flexible than mii.c
*/
#ifndef _IBM_OCP_PHY_H_
#define _IBM_OCP_PHY_H_
struct mii_phy;
/* Operations supported by any kind of PHY */
struct mii_phy_ops {
int (*init) (struct mii_phy * phy);
int (*suspend) (struct mii_phy * phy, int wol_options);
int (*setup_aneg) (struct mii_phy * phy, u32 advertise);
int (*setup_forced) (struct mii_phy * phy, int speed, int fd);
int (*poll_link) (struct mii_phy * phy);
int (*read_link) (struct mii_phy * phy);
};
/* Structure used to statically define an mii/gii based PHY */
struct mii_phy_def {
u32 phy_id; /* Concatenated ID1 << 16 | ID2 */
u32 phy_id_mask; /* Significant bits */
u32 features; /* Ethtool SUPPORTED_* defines or
0 for autodetect */
int magic_aneg; /* Autoneg does all speed test for us */
const char *name;
const struct mii_phy_ops *ops;
};
/* An instance of a PHY, partially borrowed from mii_if_info */
struct mii_phy {
struct mii_phy_def *def;
u32 advertising; /* Ethtool ADVERTISED_* defines */
u32 features; /* Copied from mii_phy_def.features
or determined automaticaly */
int address; /* PHY address */
int mode; /* PHY mode */
/* 1: autoneg enabled, 0: disabled */
int autoneg;
/* forced speed & duplex (no autoneg)
* partner speed & duplex & pause (autoneg)
*/
int speed;
int duplex;
int pause;
int asym_pause;
/* Provided by host chip */
struct net_device *dev;
int (*mdio_read) (struct net_device * dev, int addr, int reg);
void (*mdio_write) (struct net_device * dev, int addr, int reg,
int val);
};
/* Pass in a struct mii_phy with dev, mdio_read and mdio_write
* filled, the remaining fields will be filled on return
*/
int mii_phy_probe(struct mii_phy *phy, int address);
int mii_reset_phy(struct mii_phy *phy);
#endif /* _IBM_OCP_PHY_H_ */
/*
* drivers/net/ibm_emac/ibm_emac_rgmii.c
*
* Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support.
*
* Copyright (c) 2004, 2005 Zultys Technologies.
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
*
* Based on original work by
* Matt Porter <mporter@kernel.crashing.org>
* Copyright 2004 MontaVista Software, 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.
*
*/
#include <linux/kernel.h>
#include <linux/ethtool.h>
#include <asm/io.h>
#include "ibm_emac_core.h"
#include "ibm_emac_debug.h"
/* RGMIIx_FER */
#define RGMII_FER_MASK(idx) (0x7 << ((idx) * 4))
#define RGMII_FER_RTBI(idx) (0x4 << ((idx) * 4))
#define RGMII_FER_RGMII(idx) (0x5 << ((idx) * 4))
#define RGMII_FER_TBI(idx) (0x6 << ((idx) * 4))
#define RGMII_FER_GMII(idx) (0x7 << ((idx) * 4))
/* RGMIIx_SSR */
#define RGMII_SSR_MASK(idx) (0x7 << ((idx) * 8))
#define RGMII_SSR_100(idx) (0x2 << ((idx) * 8))
#define RGMII_SSR_1000(idx) (0x4 << ((idx) * 8))
/* RGMII bridge supports only GMII/TBI and RGMII/RTBI PHYs */
static inline int rgmii_valid_mode(int phy_mode)
{
return phy_mode == PHY_MODE_GMII ||
phy_mode == PHY_MODE_RGMII ||
phy_mode == PHY_MODE_TBI ||
phy_mode == PHY_MODE_RTBI;
}
static inline const char *rgmii_mode_name(int mode)
{
switch (mode) {
case PHY_MODE_RGMII:
return "RGMII";
case PHY_MODE_TBI:
return "TBI";
case PHY_MODE_GMII:
return "GMII";
case PHY_MODE_RTBI:
return "RTBI";
default:
BUG();
}
}
static inline u32 rgmii_mode_mask(int mode, int input)
{
switch (mode) {
case PHY_MODE_RGMII:
return RGMII_FER_RGMII(input);
case PHY_MODE_TBI:
return RGMII_FER_TBI(input);
case PHY_MODE_GMII:
return RGMII_FER_GMII(input);
case PHY_MODE_RTBI:
return RGMII_FER_RTBI(input);
default:
BUG();
}
}
static int __init rgmii_init(struct ocp_device *ocpdev, int input, int mode)
{
struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev);
struct rgmii_regs *p;
RGMII_DBG("%d: init(%d, %d)" NL, ocpdev->def->index, input, mode);
if (!dev) {
dev = kzalloc(sizeof(struct ibm_ocp_rgmii), GFP_KERNEL);
if (!dev) {
printk(KERN_ERR
"rgmii%d: couldn't allocate device structure!\n",
ocpdev->def->index);
return -ENOMEM;
}
p = (struct rgmii_regs *)ioremap(ocpdev->def->paddr,
sizeof(struct rgmii_regs));
if (!p) {
printk(KERN_ERR
"rgmii%d: could not ioremap device registers!\n",
ocpdev->def->index);
kfree(dev);
return -ENOMEM;
}
dev->base = p;
ocp_set_drvdata(ocpdev, dev);
/* Disable all inputs by default */
out_be32(&p->fer, 0);
} else
p = dev->base;
/* Enable this input */
out_be32(&p->fer, in_be32(&p->fer) | rgmii_mode_mask(mode, input));
printk(KERN_NOTICE "rgmii%d: input %d in %s mode\n",
ocpdev->def->index, input, rgmii_mode_name(mode));
++dev->users;
return 0;
}
int __init rgmii_attach(void *emac)
{
struct ocp_enet_private *dev = emac;
struct ocp_func_emac_data *emacdata = dev->def->additions;
/* Check if we need to attach to a RGMII */
if (emacdata->rgmii_idx >= 0 && rgmii_valid_mode(emacdata->phy_mode)) {
dev->rgmii_input = emacdata->rgmii_mux;
dev->rgmii_dev =
ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_RGMII,
emacdata->rgmii_idx);
if (!dev->rgmii_dev) {
printk(KERN_ERR "emac%d: unknown rgmii%d!\n",
dev->def->index, emacdata->rgmii_idx);
return -ENODEV;
}
if (rgmii_init
(dev->rgmii_dev, dev->rgmii_input, emacdata->phy_mode)) {
printk(KERN_ERR
"emac%d: rgmii%d initialization failed!\n",
dev->def->index, emacdata->rgmii_idx);
return -ENODEV;
}
}
return 0;
}
void rgmii_set_speed(struct ocp_device *ocpdev, int input, int speed)
{
struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev);
u32 ssr = in_be32(&dev->base->ssr) & ~RGMII_SSR_MASK(input);
RGMII_DBG("%d: speed(%d, %d)" NL, ocpdev->def->index, input, speed);
if (speed == SPEED_1000)
ssr |= RGMII_SSR_1000(input);
else if (speed == SPEED_100)
ssr |= RGMII_SSR_100(input);
out_be32(&dev->base->ssr, ssr);
}
void __rgmii_fini(struct ocp_device *ocpdev, int input)
{
struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev);
BUG_ON(!dev || dev->users == 0);
RGMII_DBG("%d: fini(%d)" NL, ocpdev->def->index, input);
/* Disable this input */
out_be32(&dev->base->fer,
in_be32(&dev->base->fer) & ~RGMII_FER_MASK(input));
if (!--dev->users) {
/* Free everything if this is the last user */
ocp_set_drvdata(ocpdev, NULL);
iounmap((void *)dev->base);
kfree(dev);
}
}
int __rgmii_get_regs_len(struct ocp_device *ocpdev)
{
return sizeof(struct emac_ethtool_regs_subhdr) +
sizeof(struct rgmii_regs);
}
void *rgmii_dump_regs(struct ocp_device *ocpdev, void *buf)
{
struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev);
struct emac_ethtool_regs_subhdr *hdr = buf;
struct rgmii_regs *regs = (struct rgmii_regs *)(hdr + 1);
hdr->version = 0;
hdr->index = ocpdev->def->index;
memcpy_fromio(regs, dev->base, sizeof(struct rgmii_regs));
return regs + 1;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -441,6 +441,7 @@ enum { ...@@ -441,6 +441,7 @@ enum {
CHIP_ID_YUKON_FE = 0xb7, /* YUKON-2 FE */ CHIP_ID_YUKON_FE = 0xb7, /* YUKON-2 FE */
CHIP_ID_YUKON_FE_P = 0xb8, /* YUKON-2 FE+ */ CHIP_ID_YUKON_FE_P = 0xb8, /* YUKON-2 FE+ */
CHIP_ID_YUKON_SUPR = 0xb9, /* YUKON-2 Supreme */ CHIP_ID_YUKON_SUPR = 0xb9, /* YUKON-2 Supreme */
CHIP_ID_YUKON_UL_2 = 0xba, /* YUKON-2 Ultra 2 */
}; };
enum yukon_ec_rev { enum yukon_ec_rev {
CHIP_REV_YU_EC_A1 = 0, /* Chip Rev. for Yukon-EC A1/A0 */ CHIP_REV_YU_EC_A1 = 0, /* Chip Rev. for Yukon-EC A1/A0 */
......
This diff is collapsed.
...@@ -1479,6 +1479,7 @@ extern void __dev_addr_unsync(struct dev_addr_list **to, int *to_count, struct ...@@ -1479,6 +1479,7 @@ extern void __dev_addr_unsync(struct dev_addr_list **to, int *to_count, struct
extern void dev_set_promiscuity(struct net_device *dev, int inc); extern void dev_set_promiscuity(struct net_device *dev, int inc);
extern void dev_set_allmulti(struct net_device *dev, int inc); extern void dev_set_allmulti(struct net_device *dev, int inc);
extern void netdev_state_change(struct net_device *dev); extern void netdev_state_change(struct net_device *dev);
extern void netdev_bonding_change(struct net_device *dev);
extern void netdev_features_change(struct net_device *dev); extern void netdev_features_change(struct net_device *dev);
/* Load a device via the kmod */ /* Load a device via the kmod */
extern void dev_load(struct net *net, const char *name); extern void dev_load(struct net *net, const char *name);
...@@ -1505,6 +1506,9 @@ extern void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos); ...@@ -1505,6 +1506,9 @@ extern void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos);
extern void dev_seq_stop(struct seq_file *seq, void *v); extern void dev_seq_stop(struct seq_file *seq, void *v);
#endif #endif
extern int netdev_class_create_file(struct class_attribute *class_attr);
extern void netdev_class_remove_file(struct class_attribute *class_attr);
extern void linkwatch_run_queue(void); extern void linkwatch_run_queue(void);
extern int netdev_compute_features(unsigned long all, unsigned long one); extern int netdev_compute_features(unsigned long all, unsigned long one);
......
...@@ -197,6 +197,7 @@ static inline int notifier_to_errno(int ret) ...@@ -197,6 +197,7 @@ static inline int notifier_to_errno(int ret)
#define NETDEV_GOING_DOWN 0x0009 #define NETDEV_GOING_DOWN 0x0009
#define NETDEV_CHANGENAME 0x000A #define NETDEV_CHANGENAME 0x000A
#define NETDEV_FEAT_CHANGE 0x000B #define NETDEV_FEAT_CHANGE 0x000B
#define NETDEV_BONDING_FAILOVER 0x000C
#define SYS_DOWN 0x0001 /* Notify of system down */ #define SYS_DOWN 0x0001 /* Notify of system down */
#define SYS_RESTART SYS_DOWN #define SYS_RESTART SYS_DOWN
......
...@@ -961,6 +961,12 @@ void netdev_state_change(struct net_device *dev) ...@@ -961,6 +961,12 @@ void netdev_state_change(struct net_device *dev)
} }
} }
void netdev_bonding_change(struct net_device *dev)
{
call_netdevice_notifiers(NETDEV_BONDING_FAILOVER, dev);
}
EXPORT_SYMBOL(netdev_bonding_change);
/** /**
* dev_load - load a network module * dev_load - load a network module
* @net: the applicable net namespace * @net: the applicable net namespace
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment