Commit 167c6274 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 5c7f0333 a8272061
......@@ -194,6 +194,48 @@ or, for backwards compatibility, the option value. E.g.,
The parameters are as follows:
ad_select
Specifies the 802.3ad aggregation selection logic to use. The
possible values and their effects are:
stable or 0
The active aggregator is chosen by largest aggregate
bandwidth.
Reselection of the active aggregator occurs only when all
slaves of the active aggregator are down or the active
aggregator has no slaves.
This is the default value.
bandwidth or 1
The active aggregator is chosen by largest aggregate
bandwidth. Reselection occurs if:
- A slave is added to or removed from the bond
- Any slave's link state changes
- Any slave's 802.3ad association state changes
- The bond's adminstrative state changes to up
count or 2
The active aggregator is chosen by the largest number of
ports (slaves). Reselection occurs as described under the
"bandwidth" setting, above.
The bandwidth and count selection policies permit failover of
802.3ad aggregations when partial failure of the active aggregator
occurs. This keeps the aggregator with the highest availability
(either in bandwidth or in number of ports) active at all times.
This option was added in bonding version 3.4.0.
arp_interval
Specifies the ARP link monitoring frequency in milliseconds.
......@@ -551,6 +593,16 @@ num_grat_arp
affects only the active-backup mode. This option was added for
bonding version 3.3.0.
num_unsol_na
Specifies the number of unsolicited IPv6 Neighbor Advertisements
to be issued after a failover event. One unsolicited NA is issued
immediately after the failover.
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.4.0.
primary
A string (eth0, eth2, etc) specifying which slave is the
......
......@@ -3853,6 +3853,12 @@ M: mhoffman@lightlink.com
L: lm-sensors@lm-sensors.org
S: Maintained
SMSC911x ETHERNET DRIVER
P: Steve Glendinning
M: steve.glendinning@smsc.com
L: netdev@vger.kernel.org
S: Supported
SMX UIO Interface
P: Ben Nizette
M: bn@niasdigital.com
......
......@@ -61,6 +61,7 @@ config DUMMY
config BONDING
tristate "Bonding driver support"
depends on INET
depends on IPV6 || IPV6=n
---help---
Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet
Channels together. This is called 'Etherchannel' by Cisco,
......@@ -978,6 +979,20 @@ config SMC911X
called smc911x. If you want to compile it as a module, say M
here and read <file:Documentation/kbuild/modules.txt>
config SMSC911X
tristate "SMSC LAN911x/LAN921x families embedded ethernet support"
depends on ARM || SUPERH
select CRC32
select MII
select PHYLIB
---help---
Say Y here if you want support for SMSC LAN911x and LAN921x families
of ethernet controllers.
To compile this driver as a module, choose M here and read
<file:Documentation/networking/net-modules.txt>. The module
will be called smsc911x.
config NET_VENDOR_RACAL
bool "Racal-Interlan (Micom) NI cards"
depends on ISA
......
......@@ -219,6 +219,7 @@ obj-$(CONFIG_S2IO) += s2io.o
obj-$(CONFIG_MYRI10GE) += myri10ge/
obj-$(CONFIG_SMC91X) += smc91x.o
obj-$(CONFIG_SMC911X) += smc911x.o
obj-$(CONFIG_SMSC911X) += smsc911x.o
obj-$(CONFIG_BFIN_MAC) += bfin_mac.o
obj-$(CONFIG_DM9000) += dm9000.o
obj-$(CONFIG_PASEMI_MAC) += pasemi_mac_driver.o
......
......@@ -6,3 +6,6 @@ obj-$(CONFIG_BONDING) += bonding.o
bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o
ipv6-$(subst m,y,$(CONFIG_IPV6)) += bond_ipv6.o
bonding-objs += $(ipv6-y)
This diff is collapsed.
......@@ -42,10 +42,11 @@ typedef struct mac_addr {
u8 mac_addr_value[ETH_ALEN];
} mac_addr_t;
typedef enum {
AD_BANDWIDTH = 0,
AD_COUNT
} agg_selection_t;
enum {
BOND_AD_STABLE = 0,
BOND_AD_BANDWIDTH = 1,
BOND_AD_COUNT = 2,
};
// rx machine states(43.4.11 in the 802.3ad standard)
typedef enum {
......@@ -277,6 +278,7 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fas
int bond_3ad_bind_slave(struct slave *slave);
void bond_3ad_unbind_slave(struct slave *slave);
void bond_3ad_state_machine_handler(struct work_struct *);
void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout);
void bond_3ad_adapter_speed_changed(struct slave *slave);
void bond_3ad_adapter_duplex_changed(struct slave *slave);
void bond_3ad_handle_link_change(struct slave *slave, char link);
......
......@@ -346,14 +346,18 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct packet_type *ptype, struct net_device *orig_dev)
{
struct bonding *bond = bond_dev->priv;
struct bonding *bond;
struct arp_pkt *arp = (struct arp_pkt *)skb->data;
int res = NET_RX_DROP;
if (dev_net(bond_dev) != &init_net)
goto out;
if (!(bond_dev->flags & IFF_MASTER))
while (bond_dev->priv_flags & IFF_802_1Q_VLAN)
bond_dev = vlan_dev_real_dev(bond_dev);
if (!(bond_dev->priv_flags & IFF_BONDING) ||
!(bond_dev->flags & IFF_MASTER))
goto out;
if (!arp) {
......@@ -368,6 +372,9 @@ static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct
if (arp->op_code == htons(ARPOP_REPLY)) {
/* update rx hash table for this ARP */
printk("rar: update orig %s bond_dev %s\n", orig_dev->name,
bond_dev->name);
bond = bond_dev->priv;
rlb_update_entry_from_arp(bond, arp);
dprintk("Server received an ARP Reply from client\n");
}
......@@ -818,7 +825,7 @@ static int rlb_initialize(struct bonding *bond)
/*initialize packet type*/
pk_type->type = __constant_htons(ETH_P_ARP);
pk_type->dev = bond->dev;
pk_type->dev = NULL;
pk_type->func = rlb_arp_recv;
/* register to receive ARPs */
......
/*
* Copyright(c) 2008 Hewlett-Packard Development Company, L.P.
*
* 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 program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
*/
//#define BONDING_DEBUG 1
#include <linux/types.h>
#include <linux/if_vlan.h>
#include <net/ipv6.h>
#include <net/ndisc.h>
#include <net/addrconf.h>
#include "bonding.h"
/*
* Assign bond->master_ipv6 to the next IPv6 address in the list, or
* zero it out if there are none.
*/
static void bond_glean_dev_ipv6(struct net_device *dev, struct in6_addr *addr)
{
struct inet6_dev *idev;
struct inet6_ifaddr *ifa;
if (!dev)
return;
idev = in6_dev_get(dev);
if (!idev)
return;
read_lock_bh(&idev->lock);
ifa = idev->addr_list;
if (ifa)
ipv6_addr_copy(addr, &ifa->addr);
else
ipv6_addr_set(addr, 0, 0, 0, 0);
read_unlock_bh(&idev->lock);
in6_dev_put(idev);
}
static void bond_na_send(struct net_device *slave_dev,
struct in6_addr *daddr,
int router,
unsigned short vlan_id)
{
struct in6_addr mcaddr;
struct icmp6hdr icmp6h = {
.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
};
struct sk_buff *skb;
icmp6h.icmp6_router = router;
icmp6h.icmp6_solicited = 0;
icmp6h.icmp6_override = 1;
addrconf_addr_solict_mult(daddr, &mcaddr);
dprintk("ipv6 na on slave %s: dest %pI6, src %pI6\n",
slave->name, &mcaddr, daddr);
skb = ndisc_build_skb(slave_dev, &mcaddr, daddr, &icmp6h, daddr,
ND_OPT_TARGET_LL_ADDR);
if (!skb) {
printk(KERN_ERR DRV_NAME ": NA packet allocation failed\n");
return;
}
if (vlan_id) {
skb = vlan_put_tag(skb, vlan_id);
if (!skb) {
printk(KERN_ERR DRV_NAME ": failed to insert VLAN tag\n");
return;
}
}
ndisc_send_skb(skb, slave_dev, NULL, &mcaddr, daddr, &icmp6h);
}
/*
* Kick out an unsolicited Neighbor Advertisement for an IPv6 address on
* the bonding master. This will help the switch learn our address
* if in active-backup mode.
*
* Caller must hold curr_slave_lock for read or better
*/
void bond_send_unsolicited_na(struct bonding *bond)
{
struct slave *slave = bond->curr_active_slave;
struct vlan_entry *vlan;
struct inet6_dev *idev;
int is_router;
dprintk("bond_send_unsol_na: bond %s slave %s\n", bond->dev->name,
slave ? slave->dev->name : "NULL");
if (!slave || !bond->send_unsol_na ||
test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state))
return;
bond->send_unsol_na--;
idev = in6_dev_get(bond->dev);
if (!idev)
return;
is_router = !!idev->cnf.forwarding;
in6_dev_put(idev);
if (!ipv6_addr_any(&bond->master_ipv6))
bond_na_send(slave->dev, &bond->master_ipv6, is_router, 0);
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
if (!ipv6_addr_any(&vlan->vlan_ipv6)) {
bond_na_send(slave->dev, &vlan->vlan_ipv6, is_router,
vlan->vlan_id);
}
}
}
/*
* bond_inet6addr_event: handle inet6addr notifier chain events.
*
* We keep track of device IPv6 addresses primarily to use as source
* addresses in NS probes.
*
* We track one IPv6 for the main device (if it has one).
*/
static int bond_inet6addr_event(struct notifier_block *this,
unsigned long event,
void *ptr)
{
struct inet6_ifaddr *ifa = ptr;
struct net_device *vlan_dev, *event_dev = ifa->idev->dev;
struct bonding *bond;
struct vlan_entry *vlan;
if (dev_net(event_dev) != &init_net)
return NOTIFY_DONE;
list_for_each_entry(bond, &bond_dev_list, bond_list) {
if (bond->dev == event_dev) {
switch (event) {
case NETDEV_UP:
if (ipv6_addr_any(&bond->master_ipv6))
ipv6_addr_copy(&bond->master_ipv6,
&ifa->addr);
return NOTIFY_OK;
case NETDEV_DOWN:
if (ipv6_addr_equal(&bond->master_ipv6,
&ifa->addr))
bond_glean_dev_ipv6(bond->dev,
&bond->master_ipv6);
return NOTIFY_OK;
default:
return NOTIFY_DONE;
}
}
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
vlan_dev = vlan_group_get_device(bond->vlgrp,
vlan->vlan_id);
if (vlan_dev == event_dev) {
switch (event) {
case NETDEV_UP:
if (ipv6_addr_any(&vlan->vlan_ipv6))
ipv6_addr_copy(&vlan->vlan_ipv6,
&ifa->addr);
return NOTIFY_OK;
case NETDEV_DOWN:
if (ipv6_addr_equal(&vlan->vlan_ipv6,
&ifa->addr))
bond_glean_dev_ipv6(vlan_dev,
&vlan->vlan_ipv6);
return NOTIFY_OK;
default:
return NOTIFY_DONE;
}
}
}
}
return NOTIFY_DONE;
}
static struct notifier_block bond_inet6addr_notifier = {
.notifier_call = bond_inet6addr_event,
};
void bond_register_ipv6_notifier(void)
{
register_inet6addr_notifier(&bond_inet6addr_notifier);
}
void bond_unregister_ipv6_notifier(void)
{
unregister_inet6addr_notifier(&bond_inet6addr_notifier);
}
......@@ -89,6 +89,7 @@
static int max_bonds = BOND_DEFAULT_MAX_BONDS;
static int num_grat_arp = 1;
static int num_unsol_na = 1;
static int miimon = BOND_LINK_MON_INTERV;
static int updelay = 0;
static int downdelay = 0;
......@@ -96,6 +97,7 @@ static int use_carrier = 1;
static char *mode = NULL;
static char *primary = NULL;
static char *lacp_rate = NULL;
static char *ad_select = NULL;
static char *xmit_hash_policy = NULL;
static int arp_interval = BOND_LINK_ARP_INTERV;
static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };
......@@ -107,6 +109,8 @@ module_param(max_bonds, int, 0);
MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
module_param(num_grat_arp, int, 0644);
MODULE_PARM_DESC(num_grat_arp, "Number of gratuitous ARP packets to send on failover event");
module_param(num_unsol_na, int, 0644);
MODULE_PARM_DESC(num_unsol_na, "Number of unsolicited IPv6 Neighbor Advertisements packets to send on failover event");
module_param(miimon, int, 0);
MODULE_PARM_DESC(miimon, "Link check interval in milliseconds");
module_param(updelay, int, 0);
......@@ -127,6 +131,8 @@ MODULE_PARM_DESC(primary, "Primary network device to use");
module_param(lacp_rate, charp, 0);
MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner "
"(slow/fast)");
module_param(ad_select, charp, 0);
MODULE_PARM_DESC(ad_select, "803.ad aggregation selection logic: stable (0, default), bandwidth (1), count (2)");
module_param(xmit_hash_policy, charp, 0);
MODULE_PARM_DESC(xmit_hash_policy, "XOR hashing method: 0 for layer 2 (default)"
", 1 for layer 3+4");
......@@ -197,6 +203,13 @@ struct bond_parm_tbl fail_over_mac_tbl[] = {
{ NULL, -1},
};
struct bond_parm_tbl ad_select_tbl[] = {
{ "stable", BOND_AD_STABLE},
{ "bandwidth", BOND_AD_BANDWIDTH},
{ "count", BOND_AD_COUNT},
{ NULL, -1},
};
/*-------------------------- Forward declarations ---------------------------*/
static void bond_send_gratuitous_arp(struct bonding *bond);
......@@ -242,14 +255,13 @@ static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id)
dprintk("bond: %s, vlan id %d\n",
(bond ? bond->dev->name: "None"), vlan_id);
vlan = kmalloc(sizeof(struct vlan_entry), GFP_KERNEL);
vlan = kzalloc(sizeof(struct vlan_entry), GFP_KERNEL);
if (!vlan) {
return -ENOMEM;
}
INIT_LIST_HEAD(&vlan->vlan_list);
vlan->vlan_id = vlan_id;
vlan->vlan_ip = 0;
write_lock_bh(&bond->lock);
......@@ -1208,6 +1220,9 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
bond->send_grat_arp = bond->params.num_grat_arp;
bond_send_gratuitous_arp(bond);
bond->send_unsol_na = bond->params.num_unsol_na;
bond_send_unsolicited_na(bond);
write_unlock_bh(&bond->curr_slave_lock);
read_unlock(&bond->lock);
......@@ -2463,6 +2478,12 @@ void bond_mii_monitor(struct work_struct *work)
read_unlock(&bond->curr_slave_lock);
}
if (bond->send_unsol_na) {
read_lock(&bond->curr_slave_lock);
bond_send_unsolicited_na(bond);
read_unlock(&bond->curr_slave_lock);
}
if (bond_miimon_inspect(bond)) {
read_unlock(&bond->lock);
rtnl_lock();
......@@ -3158,6 +3179,12 @@ void bond_activebackup_arp_mon(struct work_struct *work)
read_unlock(&bond->curr_slave_lock);
}
if (bond->send_unsol_na) {
read_lock(&bond->curr_slave_lock);
bond_send_unsolicited_na(bond);
read_unlock(&bond->curr_slave_lock);
}
if (bond_ab_arp_inspect(bond, delta_in_ticks)) {
read_unlock(&bond->lock);
rtnl_lock();
......@@ -3301,6 +3328,8 @@ static void bond_info_show_master(struct seq_file *seq)
seq_puts(seq, "\n802.3ad info\n");
seq_printf(seq, "LACP rate: %s\n",
(bond->params.lacp_fast) ? "fast" : "slow");
seq_printf(seq, "Aggregator selection policy (ad_select): %s\n",
ad_select_tbl[bond->params.ad_select].modename);
if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
seq_printf(seq, "bond %s has no active aggregator\n",
......@@ -3807,6 +3836,7 @@ static int bond_open(struct net_device *bond_dev)
queue_delayed_work(bond->wq, &bond->ad_work, 0);
/* register to receive LACPDUs */
bond_register_lacpdu(bond);
bond_3ad_initiate_agg_selection(bond, 1);
}
return 0;
......@@ -3827,6 +3857,7 @@ static int bond_close(struct net_device *bond_dev)
write_lock_bh(&bond->lock);
bond->send_grat_arp = 0;
bond->send_unsol_na = 0;
/* signal timers not to re-arm */
bond->kill_timers = 1;
......@@ -4542,6 +4573,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params)
bond->primary_slave = NULL;
bond->dev = bond_dev;
bond->send_grat_arp = 0;
bond->send_unsol_na = 0;
bond->setup_by_slave = 0;
INIT_LIST_HEAD(&bond->vlan_list);
......@@ -4744,6 +4776,23 @@ static int bond_check_params(struct bond_params *params)
}
}
if (ad_select) {
params->ad_select = bond_parse_parm(ad_select, ad_select_tbl);
if (params->ad_select == -1) {
printk(KERN_ERR DRV_NAME
": Error: Invalid ad_select \"%s\"\n",
ad_select == NULL ? "NULL" : ad_select);
return -EINVAL;
}
if (bond_mode != BOND_MODE_8023AD) {
printk(KERN_WARNING DRV_NAME
": ad_select param only affects 802.3ad mode\n");
}
} else {
params->ad_select = BOND_AD_STABLE;
}
if (max_bonds < 0 || max_bonds > INT_MAX) {
printk(KERN_WARNING DRV_NAME
": Warning: max_bonds (%d) not in range %d-%d, so it "
......@@ -4791,6 +4840,13 @@ static int bond_check_params(struct bond_params *params)
num_grat_arp = 1;
}
if (num_unsol_na < 0 || num_unsol_na > 255) {
printk(KERN_WARNING DRV_NAME
": Warning: num_unsol_na (%d) not in range 0-255 so it "
"was reset to 1 \n", num_unsol_na);
num_unsol_na = 1;
}
/* reset values for 802.3ad */
if (bond_mode == BOND_MODE_8023AD) {
if (!miimon) {
......@@ -4992,6 +5048,7 @@ static int bond_check_params(struct bond_params *params)
params->xmit_policy = xmit_hashtype;
params->miimon = miimon;
params->num_grat_arp = num_grat_arp;
params->num_unsol_na = num_unsol_na;
params->arp_interval = arp_interval;
params->arp_validate = arp_validate_value;
params->updelay = updelay;
......@@ -5144,6 +5201,7 @@ static int __init bonding_init(void)
register_netdevice_notifier(&bond_netdev_notifier);
register_inetaddr_notifier(&bond_inetaddr_notifier);
bond_register_ipv6_notifier();
goto out;
err:
......@@ -5166,6 +5224,7 @@ static void __exit bonding_exit(void)
{
unregister_netdevice_notifier(&bond_netdev_notifier);
unregister_inetaddr_notifier(&bond_inetaddr_notifier);
bond_unregister_ipv6_notifier();
bond_destroy_sysfs();
......
......@@ -48,6 +48,7 @@ extern struct list_head bond_dev_list;
extern struct bond_params bonding_defaults;
extern struct bond_parm_tbl bond_mode_tbl[];
extern struct bond_parm_tbl bond_lacp_tbl[];
extern struct bond_parm_tbl ad_select_tbl[];
extern struct bond_parm_tbl xmit_hashtype_tbl[];
extern struct bond_parm_tbl arp_validate_tbl[];
extern struct bond_parm_tbl fail_over_mac_tbl[];
......@@ -944,6 +945,53 @@ static ssize_t bonding_store_lacp(struct device *d,
}
static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp);
static ssize_t bonding_show_ad_select(struct device *d,
struct device_attribute *attr,
char *buf)
{
struct bonding *bond = to_bond(d);
return sprintf(buf, "%s %d\n",
ad_select_tbl[bond->params.ad_select].modename,
bond->params.ad_select);
}
static ssize_t bonding_store_ad_select(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
int new_value, ret = count;
struct bonding *bond = to_bond(d);
if (bond->dev->flags & IFF_UP) {
printk(KERN_ERR DRV_NAME
": %s: Unable to update ad_select because interface "
"is up.\n", bond->dev->name);
ret = -EPERM;
goto out;
}
new_value = bond_parse_parm(buf, ad_select_tbl);
if (new_value != -1) {
bond->params.ad_select = new_value;
printk(KERN_INFO DRV_NAME
": %s: Setting ad_select to %s (%d).\n",
bond->dev->name, ad_select_tbl[new_value].modename,
new_value);
} else {
printk(KERN_ERR DRV_NAME
": %s: Ignoring invalid ad_select value %.*s.\n",
bond->dev->name, (int)strlen(buf) - 1, buf);
ret = -EINVAL;
}
out:
return ret;
}
static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, bonding_show_ad_select, bonding_store_ad_select);
/*
* Show and set the number of grat ARP to send after a failover event.
*/
......@@ -983,6 +1031,47 @@ static ssize_t bonding_store_n_grat_arp(struct device *d,
return ret;
}
static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, bonding_show_n_grat_arp, bonding_store_n_grat_arp);
/*
* Show and set the number of unsolicted NA's to send after a failover event.
*/
static ssize_t bonding_show_n_unsol_na(struct device *d,
struct device_attribute *attr,
char *buf)
{
struct bonding *bond = to_bond(d);
return sprintf(buf, "%d\n", bond->params.num_unsol_na);
}
static ssize_t bonding_store_n_unsol_na(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
int new_value, ret = count;
struct bonding *bond = to_bond(d);
if (sscanf(buf, "%d", &new_value) != 1) {
printk(KERN_ERR DRV_NAME
": %s: no num_unsol_na value specified.\n",
bond->dev->name);
ret = -EINVAL;
goto out;
}
if (new_value < 0 || new_value > 255) {
printk(KERN_ERR DRV_NAME
": %s: Invalid num_unsol_na value %d not in range 0-255; rejected.\n",
bond->dev->name, new_value);
ret = -EINVAL;
goto out;
} else {
bond->params.num_unsol_na = new_value;
}
out:
return ret;
}
static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR, bonding_show_n_unsol_na, bonding_store_n_unsol_na);
/*
* Show and set the MII monitor interval. There are two tricky bits
* here. First, if MII monitoring is activated, then we must disable
......@@ -1418,8 +1507,10 @@ static struct attribute *per_bond_attrs[] = {
&dev_attr_downdelay.attr,
&dev_attr_updelay.attr,
&dev_attr_lacp_rate.attr,
&dev_attr_ad_select.attr,
&dev_attr_xmit_hash_policy.attr,
&dev_attr_num_grat_arp.attr,
&dev_attr_num_unsol_na.attr,
&dev_attr_miimon.attr,
&dev_attr_primary.attr,
&dev_attr_use_carrier.attr,
......
......@@ -19,16 +19,19 @@
#include <linux/proc_fs.h>
#include <linux/if_bonding.h>
#include <linux/kobject.h>
#include <linux/in6.h>
#include "bond_3ad.h"
#include "bond_alb.h"
#define DRV_VERSION "3.3.0"
#define DRV_RELDATE "June 10, 2008"
#define DRV_VERSION "3.5.0"
#define DRV_RELDATE "November 4, 2008"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
#define BOND_MAX_ARP_TARGETS 16
extern struct list_head bond_dev_list;
#ifdef BONDING_DEBUG
#define dprintk(fmt, args...) \
printk(KERN_DEBUG \
......@@ -126,6 +129,7 @@ struct bond_params {
int xmit_policy;
int miimon;
int num_grat_arp;
int num_unsol_na;
int arp_interval;
int arp_validate;
int use_carrier;
......@@ -133,6 +137,7 @@ struct bond_params {
int updelay;
int downdelay;
int lacp_fast;
int ad_select;
char primary[IFNAMSIZ];
__be32 arp_targets[BOND_MAX_ARP_TARGETS];
};
......@@ -148,6 +153,9 @@ struct vlan_entry {
struct list_head vlan_list;
__be32 vlan_ip;
unsigned short vlan_id;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct in6_addr vlan_ipv6;
#endif
};
struct slave {
......@@ -195,6 +203,7 @@ struct bonding {
rwlock_t curr_slave_lock;
s8 kill_timers;
s8 send_grat_arp;
s8 send_unsol_na;
s8 setup_by_slave;
struct net_device_stats stats;
#ifdef CONFIG_PROC_FS
......@@ -218,6 +227,9 @@ struct bonding {
struct delayed_work arp_work;
struct delayed_work alb_work;
struct delayed_work ad_work;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct in6_addr master_ipv6;
#endif
};
/**
......@@ -341,5 +353,24 @@ extern struct bond_parm_tbl xmit_hashtype_tbl[];
extern struct bond_parm_tbl arp_validate_tbl[];
extern struct bond_parm_tbl fail_over_mac_tbl[];
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
void bond_send_unsolicited_na(struct bonding *bond);
void bond_register_ipv6_notifier(void);
void bond_unregister_ipv6_notifier(void);
#else
static inline void bond_send_unsolicited_na(struct bonding *bond)
{
return;
}
static inline void bond_register_ipv6_notifier(void)
{
return;
}
static inline void bond_unregister_ipv6_notifier(void)
{
return;
}
#endif
#endif /* _LINUX_BONDING_H */
......@@ -40,7 +40,7 @@
#include <asm/io.h>
#define DRV_NAME "ehea"
#define DRV_VERSION "EHEA_0095"
#define DRV_VERSION "EHEA_0096"
/* eHEA capability flags */
#define DLPAR_PORT_ADD_REM 1
......
......@@ -653,7 +653,7 @@ static int ehea_update_busmap(unsigned long pfn, unsigned long nr_pages, int add
int top = ehea_calc_index(i, EHEA_TOP_INDEX_SHIFT);
int dir = ehea_calc_index(i, EHEA_DIR_INDEX_SHIFT);
int idx = i & EHEA_INDEX_MASK;
if (add) {
int ret = ehea_init_bmap(ehea_bmap, top, dir);
if (ret)
......@@ -780,7 +780,7 @@ void ehea_destroy_busmap(void)
kfree(ehea_bmap);
ehea_bmap = NULL;
out_destroy:
out_destroy:
mutex_unlock(&ehea_busmap_mutex);
}
......@@ -858,10 +858,10 @@ static u64 ehea_reg_mr_sections(int top, int dir, u64 *pt,
for (idx = 0; idx < EHEA_MAP_ENTRIES; idx++) {
if (!ehea_bmap->top[top]->dir[dir]->ent[idx])
continue;
hret = ehea_reg_mr_section(top, dir, idx, pt, adapter, mr);
if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
return hret;
return hret;
}
return hret;
}
......@@ -879,7 +879,7 @@ static u64 ehea_reg_mr_dir_sections(int top, u64 *pt,
hret = ehea_reg_mr_sections(top, dir, pt, adapter, mr);
if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
return hret;
return hret;
}
return hret;
}
......
......@@ -125,6 +125,7 @@ typedef struct local_info_t {
u_short tx_queue_len;
cardtype_t cardtype;
u_short sent;
u_char __iomem *base;
} local_info_t;
#define MC_FILTERBREAK 64
......@@ -242,6 +243,7 @@ static int fmvj18x_probe(struct pcmcia_device *link)
lp = netdev_priv(dev);
link->priv = dev;
lp->p_dev = link;
lp->base = NULL;
/* The io structure describes IO port mapping */
link->io.NumPorts1 = 32;
......@@ -442,8 +444,10 @@ static int fmvj18x_config(struct pcmcia_device *link)
dev->irq = link->irq.AssignedIRQ;
dev->base_addr = link->io.BasePort1;
if (link->io.BasePort2 != 0)
fmvj18x_setup_mfc(link);
if (link->io.BasePort2 != 0) {
ret = fmvj18x_setup_mfc(link);
if (ret != 0) goto failed;
}
ioaddr = dev->base_addr;
......@@ -610,10 +614,10 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link)
{
win_req_t req;
memreq_t mem;
u_char __iomem *base;
int i, j;
int i;
struct net_device *dev = link->priv;
unsigned int ioaddr;
local_info_t *lp = netdev_priv(dev);
/* Allocate a small memory window */
req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
......@@ -625,25 +629,32 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link)
return -1;
}
base = ioremap(req.Base, req.Size);
lp->base = ioremap(req.Base, req.Size);
if (lp->base == NULL) {
printk(KERN_NOTICE "fmvj18x_cs: ioremap failed\n");
return -1;
}
mem.Page = 0;
mem.CardOffset = 0;
pcmcia_map_mem_page(link->win, &mem);
i = pcmcia_map_mem_page(link->win, &mem);
if (i != 0) {
iounmap(lp->base);
lp->base = NULL;
cs_error(link, MapMemPage, i);
return -1;
}
ioaddr = dev->base_addr;
writeb(0x47, base+0x800); /* Config Option Register of LAN */
writeb(0x0, base+0x802); /* Config and Status Register */
writeb(0x47, lp->base+0x800); /* Config Option Register of LAN */
writeb(0x0, lp->base+0x802); /* Config and Status Register */
writeb(ioaddr & 0xff, base+0x80a); /* I/O Base(Low) of LAN */
writeb((ioaddr >> 8) & 0xff, base+0x80c); /* I/O Base(High) of LAN */
writeb(ioaddr & 0xff, lp->base+0x80a); /* I/O Base(Low) of LAN */
writeb((ioaddr >> 8) & 0xff, lp->base+0x80c); /* I/O Base(High) of LAN */
writeb(0x45, base+0x820); /* Config Option Register of Modem */
writeb(0x8, base+0x822); /* Config and Status Register */
writeb(0x45, lp->base+0x820); /* Config Option Register of Modem */
writeb(0x8, lp->base+0x822); /* Config and Status Register */
iounmap(base);
j = pcmcia_release_window(link->win);
if (j != 0)
cs_error(link, ReleaseWindow, j);
return 0;
}
......@@ -651,8 +662,25 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link)
static void fmvj18x_release(struct pcmcia_device *link)
{
DEBUG(0, "fmvj18x_release(0x%p)\n", link);
pcmcia_disable_device(link);
struct net_device *dev = link->priv;
local_info_t *lp = netdev_priv(dev);
u_char __iomem *tmp;
int j;
DEBUG(0, "fmvj18x_release(0x%p)\n", link);
if (lp->base != NULL) {
tmp = lp->base;
lp->base = NULL; /* set NULL before iounmap */
iounmap(tmp);
j = pcmcia_release_window(link->win);
if (j != 0)
cs_error(link, ReleaseWindow, j);
}
pcmcia_disable_device(link);
}
static int fmvj18x_suspend(struct pcmcia_device *link)
......@@ -783,6 +811,13 @@ static irqreturn_t fjn_interrupt(int dummy, void *dev_id)
outb(D_TX_INTR, ioaddr + TX_INTR);
outb(D_RX_INTR, ioaddr + RX_INTR);
if (lp->base != NULL) {
/* Ack interrupt for multifunction card */
writeb(0x01, lp->base+0x802);
writeb(0x09, lp->base+0x822);
}
return IRQ_HANDLED;
} /* fjn_interrupt */
......
......@@ -126,6 +126,27 @@ static struct phy_driver lan8700_driver = {
.driver = { .owner = THIS_MODULE, }
};
static struct phy_driver lan911x_int_driver = {
.phy_id = 0x0007c0d0, /* OUI=0x00800f, Model#=0x0d */
.phy_id_mask = 0xfffffff0,
.name = "SMSC LAN911x Internal PHY",
.features = (PHY_BASIC_FEATURES | SUPPORTED_Pause
| SUPPORTED_Asym_Pause),
.flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
/* basic functions */
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.config_init = smsc_phy_config_init,
/* IRQ related */
.ack_interrupt = smsc_phy_ack_interrupt,
.config_intr = smsc_phy_config_intr,
.driver = { .owner = THIS_MODULE, }
};
static int __init smsc_init(void)
{
int ret;
......@@ -142,8 +163,14 @@ static int __init smsc_init(void)
if (ret)
goto err3;
ret = phy_driver_register (&lan911x_int_driver);
if (ret)
goto err4;
return 0;
err4:
phy_driver_unregister (&lan8700_driver);
err3:
phy_driver_unregister (&lan8187_driver);
err2:
......@@ -154,6 +181,7 @@ static int __init smsc_init(void)
static void __exit smsc_exit(void)
{
phy_driver_unregister (&lan911x_int_driver);
phy_driver_unregister (&lan8700_driver);
phy_driver_unregister (&lan8187_driver);
phy_driver_unregister (&lan83c185_driver);
......
......@@ -12,3 +12,11 @@ config SFC
To compile this driver as a module, choose M here. The module
will be called sfc.
config SFC_MTD
bool "Solarflare Solarstorm SFC4000 flash MTD support"
depends on SFC && MTD
default y
help
This exposes the on-board flash memory as an MTD device (e.g.
/dev/mtd1). This makes it possible to upload new boot code
to the NIC.
sfc-y += efx.o falcon.o tx.o rx.o falcon_xmac.o \
selftest.o ethtool.o xfp_phy.o \
mdio_10g.o tenxpress.o boards.o sfe4001.o
sfc-$(CONFIG_SFC_MTD) += mtd.o
obj-$(CONFIG_SFC) += sfc.o
......@@ -11,6 +11,7 @@
#include "phy.h"
#include "boards.h"
#include "efx.h"
#include "workarounds.h"
/* Macros for unpacking the board revision */
/* The revision info is in host byte order. */
......@@ -51,10 +52,129 @@ static void board_blink(struct efx_nic *efx, bool blink)
}
}
/*****************************************************************************
* Support for LM87 sensor chip used on several boards
*/
#define LM87_REG_ALARMS1 0x41
#define LM87_REG_ALARMS2 0x42
#define LM87_IN_LIMITS(nr, _min, _max) \
0x2B + (nr) * 2, _max, 0x2C + (nr) * 2, _min
#define LM87_AIN_LIMITS(nr, _min, _max) \
0x3B + (nr), _max, 0x1A + (nr), _min
#define LM87_TEMP_INT_LIMITS(_min, _max) \
0x39, _max, 0x3A, _min
#define LM87_TEMP_EXT1_LIMITS(_min, _max) \
0x37, _max, 0x38, _min
#define LM87_ALARM_TEMP_INT 0x10
#define LM87_ALARM_TEMP_EXT1 0x20
#if defined(CONFIG_SENSORS_LM87) || defined(CONFIG_SENSORS_LM87_MODULE)
static int efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info,
const u8 *reg_values)
{
struct i2c_client *client = i2c_new_device(&efx->i2c_adap, info);
int rc;
if (!client)
return -EIO;
while (*reg_values) {
u8 reg = *reg_values++;
u8 value = *reg_values++;
rc = i2c_smbus_write_byte_data(client, reg, value);
if (rc)
goto err;
}
efx->board_info.hwmon_client = client;
return 0;
err:
i2c_unregister_device(client);
return rc;
}
static void efx_fini_lm87(struct efx_nic *efx)
{
i2c_unregister_device(efx->board_info.hwmon_client);
}
static int efx_check_lm87(struct efx_nic *efx, unsigned mask)
{
struct i2c_client *client = efx->board_info.hwmon_client;
s32 alarms1, alarms2;
/* If link is up then do not monitor temperature */
if (EFX_WORKAROUND_7884(efx) && efx->link_up)
return 0;
alarms1 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1);
alarms2 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2);
if (alarms1 < 0)
return alarms1;
if (alarms2 < 0)
return alarms2;
alarms1 &= mask;
alarms2 &= mask >> 8;
if (alarms1 || alarms2) {
EFX_ERR(efx,
"LM87 detected a hardware failure (status %02x:%02x)"
"%s%s\n",
alarms1, alarms2,
(alarms1 & LM87_ALARM_TEMP_INT) ? " INTERNAL" : "",
(alarms1 & LM87_ALARM_TEMP_EXT1) ? " EXTERNAL" : "");
return -ERANGE;
}
return 0;
}
#else /* !CONFIG_SENSORS_LM87 */
static inline int
efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info,
const u8 *reg_values)
{
return 0;
}
static inline void efx_fini_lm87(struct efx_nic *efx)
{
}
static inline int efx_check_lm87(struct efx_nic *efx, unsigned mask)
{
return 0;
}
#endif /* CONFIG_SENSORS_LM87 */
/*****************************************************************************
* Support for the SFE4002
*
*/
static u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */
static const u8 sfe4002_lm87_regs[] = {
LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */
LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */
LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */
LM87_IN_LIMITS(3, 0xb0, 0xc9), /* 5V: 4.6-5.2V */
LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */
LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */
LM87_AIN_LIMITS(0, 0xa0, 0xb2), /* AIN1: 1.66V +/- 5% */
LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */
LM87_TEMP_INT_LIMITS(10, 60), /* board */
LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */
0
};
static struct i2c_board_info sfe4002_hwmon_info = {
I2C_BOARD_INFO("lm87", 0x2e),
.platform_data = &sfe4002_lm87_channel,
.irq = -1,
};
/****************************************************************************/
/* LED allocations. Note that on rev A0 boards the schematic and the reality
* differ: red and green are swapped. Below is the fixed (A1) layout (there
......@@ -84,11 +204,27 @@ static void sfe4002_fault_led(struct efx_nic *efx, bool state)
QUAKE_LED_OFF);
}
static int sfe4002_check_hw(struct efx_nic *efx)
{
/* A0 board rev. 4002s report a temperature fault the whole time
* (bad sensor) so we mask it out. */
unsigned alarm_mask =
(efx->board_info.major == 0 && efx->board_info.minor == 0) ?
~LM87_ALARM_TEMP_EXT1 : ~0;
return efx_check_lm87(efx, alarm_mask);
}
static int sfe4002_init(struct efx_nic *efx)
{
int rc = efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs);
if (rc)
return rc;
efx->board_info.monitor = sfe4002_check_hw;
efx->board_info.init_leds = sfe4002_init_leds;
efx->board_info.set_fault_led = sfe4002_fault_led;
efx->board_info.blink = board_blink;
efx->board_info.fini = efx_fini_lm87;
return 0;
}
......
......@@ -77,11 +77,6 @@ static int napi_weight = 64;
*/
unsigned int efx_monitor_interval = 1 * HZ;
/* This controls whether or not the hardware monitor will trigger a
* reset when it detects an error condition.
*/
static unsigned int monitor_reset = true;
/* This controls whether or not the driver will initialise devices
* with invalid MAC addresses stored in the EEPROM or flash. If true,
* such devices will be initialised with a random locally-generated
......@@ -1176,17 +1171,6 @@ static void efx_monitor(struct work_struct *data)
rc = falcon_check_xmac(efx);
mutex_unlock(&efx->mac_lock);
if (rc) {
if (monitor_reset) {
EFX_ERR(efx, "hardware monitor detected a fault: "
"triggering reset\n");
efx_schedule_reset(efx, RESET_TYPE_MONITOR);
} else {
EFX_ERR(efx, "hardware monitor detected a fault, "
"skipping reset\n");
}
}
queue_delayed_work(efx->workqueue, &efx->monitor_work,
efx_monitor_interval);
}
......@@ -1358,12 +1342,11 @@ static void efx_watchdog(struct net_device *net_dev)
{
struct efx_nic *efx = netdev_priv(net_dev);
EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d: %s\n",
atomic_read(&efx->netif_stop_count), efx->port_enabled,
monitor_reset ? "resetting channels" : "skipping reset");
EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d:"
" resetting channels\n",
atomic_read(&efx->netif_stop_count), efx->port_enabled);
if (monitor_reset)
efx_schedule_reset(efx, RESET_TYPE_MONITOR);
efx_schedule_reset(efx, RESET_TYPE_TX_WATCHDOG);
}
......@@ -1459,6 +1442,7 @@ static int efx_netdev_event(struct notifier_block *this,
struct efx_nic *efx = netdev_priv(net_dev);
strcpy(efx->name, net_dev->name);
efx_mtd_rename(efx);
}
return NOTIFY_DONE;
......@@ -1550,6 +1534,7 @@ void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd)
efx_stop_all(efx);
mutex_lock(&efx->mac_lock);
mutex_lock(&efx->spi_lock);
rc = falcon_xmac_get_settings(efx, ecmd);
if (rc)
......@@ -1582,6 +1567,7 @@ int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, bool ok)
EFX_ERR(efx, "could not restore PHY settings\n");
}
mutex_unlock(&efx->spi_lock);
mutex_unlock(&efx->mac_lock);
if (ok) {
......@@ -1777,6 +1763,7 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
memset(efx, 0, sizeof(*efx));
spin_lock_init(&efx->biu_lock);
spin_lock_init(&efx->phy_lock);
mutex_init(&efx->spi_lock);
INIT_WORK(&efx->reset_work, efx_reset_work);
INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor);
efx->pci_dev = pci_dev;
......@@ -1911,6 +1898,8 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
if (!efx)
return;
efx_mtd_remove(efx);
/* Mark the NIC as fini, then stop the interface */
rtnl_lock();
efx->state = STATE_FINI;
......@@ -2077,6 +2066,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
EFX_LOG(efx, "initialisation successful\n");
efx_mtd_probe(efx); /* allowed to fail */
return 0;
fail5:
......
......@@ -58,6 +58,16 @@ extern int efx_port_dummy_op_int(struct efx_nic *efx);
extern void efx_port_dummy_op_void(struct efx_nic *efx);
extern void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink);
/* MTD */
#ifdef CONFIG_SFC_MTD
extern int efx_mtd_probe(struct efx_nic *efx);
extern void efx_mtd_rename(struct efx_nic *efx);
extern void efx_mtd_remove(struct efx_nic *efx);
#else
static inline int efx_mtd_probe(struct efx_nic *efx) { return 0; }
static inline void efx_mtd_rename(struct efx_nic *efx) {}
static inline void efx_mtd_remove(struct efx_nic *efx) {}
#endif
extern unsigned int efx_monitor_interval;
......
......@@ -72,7 +72,7 @@ extern const char *efx_loopback_mode_names[];
* @RESET_TYPE_ALL: reset everything but PCI core blocks
* @RESET_TYPE_WORLD: reset everything, save & restore PCI config
* @RESET_TYPE_DISABLE: disable NIC
* @RESET_TYPE_MONITOR: reset due to hardware monitor
* @RESET_TYPE_TX_WATCHDOG: reset due to TX watchdog
* @RESET_TYPE_INT_ERROR: reset due to internal error
* @RESET_TYPE_RX_RECOVERY: reset to recover from RX datapath errors
* @RESET_TYPE_RX_DESC_FETCH: pcie error during rx descriptor fetch
......@@ -86,7 +86,7 @@ enum reset_type {
RESET_TYPE_WORLD = 2,
RESET_TYPE_DISABLE = 3,
RESET_TYPE_MAX_METHOD,
RESET_TYPE_MONITOR,
RESET_TYPE_TX_WATCHDOG,
RESET_TYPE_INT_ERROR,
RESET_TYPE_RX_RECOVERY,
RESET_TYPE_RX_DESC_FETCH,
......
......@@ -172,10 +172,7 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = {
/* Number of ethtool statistics */
#define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats)
/* EEPROM range with gPXE configuration */
#define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB
#define EFX_ETHTOOL_EEPROM_MIN 0x100U
#define EFX_ETHTOOL_EEPROM_MAX 0x400U
/**************************************************************************
*
......@@ -545,8 +542,8 @@ static int efx_ethtool_get_eeprom_len(struct net_device *net_dev)
if (!spi)
return 0;
return min(spi->size, EFX_ETHTOOL_EEPROM_MAX) -
min(spi->size, EFX_ETHTOOL_EEPROM_MIN);
return min(spi->size, EFX_EEPROM_BOOTCONFIG_END) -
min(spi->size, EFX_EEPROM_BOOTCONFIG_START);
}
static int efx_ethtool_get_eeprom(struct net_device *net_dev,
......@@ -557,8 +554,10 @@ static int efx_ethtool_get_eeprom(struct net_device *net_dev,
size_t len;
int rc;
rc = falcon_spi_read(spi, eeprom->offset + EFX_ETHTOOL_EEPROM_MIN,
mutex_lock(&efx->spi_lock);
rc = falcon_spi_read(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START,
eeprom->len, &len, buf);
mutex_unlock(&efx->spi_lock);
eeprom->magic = EFX_ETHTOOL_EEPROM_MAGIC;
eeprom->len = len;
return rc;
......@@ -575,8 +574,10 @@ static int efx_ethtool_set_eeprom(struct net_device *net_dev,
if (eeprom->magic != EFX_ETHTOOL_EEPROM_MAGIC)
return -EINVAL;
rc = falcon_spi_write(spi, eeprom->offset + EFX_ETHTOOL_EEPROM_MIN,
mutex_lock(&efx->spi_lock);
rc = falcon_spi_write(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START,
eeprom->len, &len, buf);
mutex_unlock(&efx->spi_lock);
eeprom->len = len;
return rc;
}
......
......@@ -1628,9 +1628,9 @@ static int falcon_spi_wait(struct efx_nic *efx)
}
}
static int falcon_spi_cmd(const struct efx_spi_device *spi,
unsigned int command, int address,
const void *in, void *out, unsigned int len)
int falcon_spi_cmd(const struct efx_spi_device *spi,
unsigned int command, int address,
const void *in, void *out, unsigned int len)
{
struct efx_nic *efx = spi->efx;
bool addressed = (address >= 0);
......@@ -1641,6 +1641,7 @@ static int falcon_spi_cmd(const struct efx_spi_device *spi,
/* Input validation */
if (len > FALCON_SPI_MAX_LEN)
return -EINVAL;
BUG_ON(!mutex_is_locked(&efx->spi_lock));
/* Check SPI not currently being accessed */
rc = falcon_spi_wait(efx);
......@@ -1699,8 +1700,7 @@ efx_spi_munge_command(const struct efx_spi_device *spi,
return command | (((address >> 8) & spi->munge_address) << 3);
}
static int falcon_spi_fast_wait(const struct efx_spi_device *spi)
int falcon_spi_fast_wait(const struct efx_spi_device *spi)
{
u8 status;
int i, rc;
......@@ -2253,13 +2253,15 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
__le16 *word, *limit;
u32 csum;
region = kmalloc(NVCONFIG_END, GFP_KERNEL);
region = kmalloc(FALCON_NVCONFIG_END, GFP_KERNEL);
if (!region)
return -ENOMEM;
nvconfig = region + NVCONFIG_OFFSET;
spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom;
rc = falcon_spi_read(spi, 0, NVCONFIG_END, NULL, region);
mutex_lock(&efx->spi_lock);
rc = falcon_spi_read(spi, 0, FALCON_NVCONFIG_END, NULL, region);
mutex_unlock(&efx->spi_lock);
if (rc) {
EFX_ERR(efx, "Failed to read %s\n",
efx->spi_flash ? "flash" : "EEPROM");
......@@ -2283,7 +2285,7 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
limit = (__le16 *) (nvconfig + 1);
} else {
word = region;
limit = region + NVCONFIG_END;
limit = region + FALCON_NVCONFIG_END;
}
for (csum = 0; word < limit; ++word)
csum += le16_to_cpu(*word);
......@@ -2555,6 +2557,11 @@ static int falcon_spi_device_init(struct efx_nic *efx,
SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ADDR_LEN);
spi_device->munge_address = (spi_device->size == 1 << 9 &&
spi_device->addr_len == 1);
spi_device->erase_command =
SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ERASE_CMD);
spi_device->erase_size =
1 << SPI_DEV_TYPE_FIELD(device_type,
SPI_DEV_TYPE_ERASE_SIZE);
spi_device->block_size =
1 << SPI_DEV_TYPE_FIELD(device_type,
SPI_DEV_TYPE_BLOCK_SIZE);
......
......@@ -1150,7 +1150,6 @@ struct falcon_nvconfig_board_v3 {
(((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(EFX_WIDTH(field)))
#define NVCONFIG_OFFSET 0x300
#define NVCONFIG_END 0x400
#define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C
struct falcon_nvconfig {
......
......@@ -260,6 +260,41 @@ void mdio_clause45_phy_reconfigure(struct efx_nic *efx)
MDIO_MMDREG_CTRL1, ctrl2);
}
static void mdio_clause45_set_mmd_lpower(struct efx_nic *efx,
int lpower, int mmd)
{
int phy = efx->mii.phy_id;
int stat = mdio_clause45_read(efx, phy, mmd, MDIO_MMDREG_STAT1);
int ctrl1, ctrl2;
EFX_TRACE(efx, "Setting low power mode for MMD %d to %d\n",
mmd, lpower);
if (stat & (1 << MDIO_MMDREG_STAT1_LPABLE_LBN)) {
ctrl1 = ctrl2 = mdio_clause45_read(efx, phy,
mmd, MDIO_MMDREG_CTRL1);
if (lpower)
ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LPOWER_LBN);
else
ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LPOWER_LBN);
if (ctrl1 != ctrl2)
mdio_clause45_write(efx, phy, mmd,
MDIO_MMDREG_CTRL1, ctrl2);
}
}
void mdio_clause45_set_mmds_lpower(struct efx_nic *efx,
int low_power, unsigned int mmd_mask)
{
int mmd = 0;
while (mmd_mask) {
if (mmd_mask & 1)
mdio_clause45_set_mmd_lpower(efx, low_power, mmd);
mmd_mask = (mmd_mask >> 1);
mmd++;
}
}
/**
* mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO.
* @efx: Efx NIC
......
......@@ -54,6 +54,9 @@
/* Loopback bit for WIS, PCS, PHYSX and DTEXS */
#define MDIO_MMDREG_CTRL1_LBACK_LBN (14)
#define MDIO_MMDREG_CTRL1_LBACK_WIDTH (1)
/* Low power */
#define MDIO_MMDREG_CTRL1_LPOWER_LBN (11)
#define MDIO_MMDREG_CTRL1_LPOWER_WIDTH (1)
/* Bits in MMDREG_STAT1 */
#define MDIO_MMDREG_STAT1_FAULT_LBN (7)
......@@ -240,6 +243,10 @@ extern void mdio_clause45_transmit_disable(struct efx_nic *efx);
/* Generic part of reconfigure: set/clear loopback bits */
extern void mdio_clause45_phy_reconfigure(struct efx_nic *efx);
/* Set the power state of the specified MMDs */
extern void mdio_clause45_set_mmds_lpower(struct efx_nic *efx,
int low_power, unsigned int mmd_mask);
/* Read (some of) the PHY settings over MDIO */
extern void mdio_clause45_get_settings(struct efx_nic *efx,
struct ethtool_cmd *ecmd);
......
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2008 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#include <linux/module.h>
#include <linux/mtd/mtd.h>
#include <linux/delay.h>
#define EFX_DRIVER_NAME "sfc_mtd"
#include "net_driver.h"
#include "spi.h"
#define EFX_SPI_VERIFY_BUF_LEN 16
struct efx_mtd {
const struct efx_spi_device *spi;
struct mtd_info mtd;
char name[IFNAMSIZ + 20];
};
/* SPI utilities */
static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible)
{
const struct efx_spi_device *spi = efx_mtd->spi;
struct efx_nic *efx = spi->efx;
u8 status;
int rc, i;
/* Wait up to 4s for flash/EEPROM to finish a slow operation. */
for (i = 0; i < 40; i++) {
__set_current_state(uninterruptible ?
TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE);
schedule_timeout(HZ / 10);
rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL,
&status, sizeof(status));
if (rc)
return rc;
if (!(status & SPI_STATUS_NRDY))
return 0;
if (signal_pending(current))
return -EINTR;
}
EFX_ERR(efx, "timed out waiting for %s\n", efx_mtd->name);
return -ETIMEDOUT;
}
static int efx_spi_unlock(const struct efx_spi_device *spi)
{
const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 |
SPI_STATUS_BP0);
u8 status;
int rc;
rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, &status, sizeof(status));
if (rc)
return rc;
if (!(status & unlock_mask))
return 0; /* already unlocked */
rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0);
if (rc)
return rc;
rc = falcon_spi_cmd(spi, SPI_SST_EWSR, -1, NULL, NULL, 0);
if (rc)
return rc;
status &= ~unlock_mask;
rc = falcon_spi_cmd(spi, SPI_WRSR, -1, &status, NULL, sizeof(status));
if (rc)
return rc;
rc = falcon_spi_fast_wait(spi);
if (rc)
return rc;
return 0;
}
static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len)
{
const struct efx_spi_device *spi = efx_mtd->spi;
unsigned pos, block_len;
u8 empty[EFX_SPI_VERIFY_BUF_LEN];
u8 buffer[EFX_SPI_VERIFY_BUF_LEN];
int rc;
if (len != spi->erase_size)
return -EINVAL;
if (spi->erase_command == 0)
return -EOPNOTSUPP;
rc = efx_spi_unlock(spi);
if (rc)
return rc;
rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0);
if (rc)
return rc;
rc = falcon_spi_cmd(spi, spi->erase_command, start, NULL, NULL, 0);
if (rc)
return rc;
rc = efx_spi_slow_wait(efx_mtd, false);
/* Verify the entire region has been wiped */
memset(empty, 0xff, sizeof(empty));
for (pos = 0; pos < len; pos += block_len) {
block_len = min(len - pos, sizeof(buffer));
rc = falcon_spi_read(spi, start + pos, block_len, NULL, buffer);
if (rc)
return rc;
if (memcmp(empty, buffer, block_len))
return -EIO;
/* Avoid locking up the system */
cond_resched();
if (signal_pending(current))
return -EINTR;
}
return rc;
}
/* MTD interface */
static int efx_mtd_read(struct mtd_info *mtd, loff_t start, size_t len,
size_t *retlen, u8 *buffer)
{
struct efx_mtd *efx_mtd = mtd->priv;
const struct efx_spi_device *spi = efx_mtd->spi;
struct efx_nic *efx = spi->efx;
int rc;
rc = mutex_lock_interruptible(&efx->spi_lock);
if (rc)
return rc;
rc = falcon_spi_read(spi, FALCON_FLASH_BOOTCODE_START + start,
len, retlen, buffer);
mutex_unlock(&efx->spi_lock);
return rc;
}
static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
{
struct efx_mtd *efx_mtd = mtd->priv;
struct efx_nic *efx = efx_mtd->spi->efx;
int rc;
rc = mutex_lock_interruptible(&efx->spi_lock);
if (rc)
return rc;
rc = efx_spi_erase(efx_mtd, FALCON_FLASH_BOOTCODE_START + erase->addr,
erase->len);
mutex_unlock(&efx->spi_lock);
if (rc == 0) {
erase->state = MTD_ERASE_DONE;
} else {
erase->state = MTD_ERASE_FAILED;
erase->fail_addr = 0xffffffff;
}
mtd_erase_callback(erase);
return rc;
}
static int efx_mtd_write(struct mtd_info *mtd, loff_t start,
size_t len, size_t *retlen, const u8 *buffer)
{
struct efx_mtd *efx_mtd = mtd->priv;
const struct efx_spi_device *spi = efx_mtd->spi;
struct efx_nic *efx = spi->efx;
int rc;
rc = mutex_lock_interruptible(&efx->spi_lock);
if (rc)
return rc;
rc = falcon_spi_write(spi, FALCON_FLASH_BOOTCODE_START + start,
len, retlen, buffer);
mutex_unlock(&efx->spi_lock);
return rc;
}
static void efx_mtd_sync(struct mtd_info *mtd)
{
struct efx_mtd *efx_mtd = mtd->priv;
struct efx_nic *efx = efx_mtd->spi->efx;
int rc;
mutex_lock(&efx->spi_lock);
rc = efx_spi_slow_wait(efx_mtd, true);
mutex_unlock(&efx->spi_lock);
if (rc)
EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc);
return;
}
void efx_mtd_remove(struct efx_nic *efx)
{
if (efx->spi_flash && efx->spi_flash->mtd) {
struct efx_mtd *efx_mtd = efx->spi_flash->mtd;
int rc;
for (;;) {
rc = del_mtd_device(&efx_mtd->mtd);
if (rc != -EBUSY)
break;
ssleep(1);
}
WARN_ON(rc);
kfree(efx_mtd);
}
}
void efx_mtd_rename(struct efx_nic *efx)
{
if (efx->spi_flash && efx->spi_flash->mtd) {
struct efx_mtd *efx_mtd = efx->spi_flash->mtd;
snprintf(efx_mtd->name, sizeof(efx_mtd->name),
"%s sfc_flash_bootrom", efx->name);
}
}
int efx_mtd_probe(struct efx_nic *efx)
{
struct efx_spi_device *spi = efx->spi_flash;
struct efx_mtd *efx_mtd;
if (!spi || spi->size <= FALCON_FLASH_BOOTCODE_START)
return -ENODEV;
efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL);
if (!efx_mtd)
return -ENOMEM;
efx_mtd->spi = spi;
spi->mtd = efx_mtd;
efx_mtd->mtd.type = MTD_NORFLASH;
efx_mtd->mtd.flags = MTD_CAP_NORFLASH;
efx_mtd->mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START;
efx_mtd->mtd.erasesize = spi->erase_size;
efx_mtd->mtd.writesize = 1;
efx_mtd_rename(efx);
efx_mtd->mtd.owner = THIS_MODULE;
efx_mtd->mtd.priv = efx_mtd;
efx_mtd->mtd.name = efx_mtd->name;
efx_mtd->mtd.erase = efx_mtd_erase;
efx_mtd->mtd.read = efx_mtd_read;
efx_mtd->mtd.write = efx_mtd_write;
efx_mtd->mtd.sync = efx_mtd_sync;
if (add_mtd_device(&efx_mtd->mtd)) {
kfree(efx_mtd);
spi->mtd = NULL;
/* add_mtd_device() returns 1 if the MTD table is full */
return -ENOMEM;
}
return 0;
}
......@@ -414,6 +414,7 @@ struct efx_blinker {
* @init_leds: Sets up board LEDs
* @set_fault_led: Turns the fault LED on or off
* @blink: Starts/stops blinking
* @monitor: Board-specific health check function
* @fini: Cleanup function
* @blinker: used to blink LEDs in software
* @hwmon_client: I2C client for hardware monitor
......@@ -428,6 +429,7 @@ struct efx_board {
* have a separate init callback that happens later than
* board init. */
int (*init_leds)(struct efx_nic *efx);
int (*monitor) (struct efx_nic *nic);
void (*set_fault_led) (struct efx_nic *efx, bool state);
void (*blink) (struct efx_nic *efx, bool start);
void (*fini) (struct efx_nic *nic);
......@@ -525,11 +527,15 @@ struct efx_phy_operations {
* @enum efx_phy_mode - PHY operating mode flags
* @PHY_MODE_NORMAL: on and should pass traffic
* @PHY_MODE_TX_DISABLED: on with TX disabled
* @PHY_MODE_LOW_POWER: set to low power through MDIO
* @PHY_MODE_OFF: switched off through external control
* @PHY_MODE_SPECIAL: on but will not pass traffic
*/
enum efx_phy_mode {
PHY_MODE_NORMAL = 0,
PHY_MODE_TX_DISABLED = 1,
PHY_MODE_LOW_POWER = 2,
PHY_MODE_OFF = 4,
PHY_MODE_SPECIAL = 8,
};
......@@ -655,6 +661,7 @@ union efx_multicast_hash {
* This field will be %NULL if no flash device is present.
* @spi_eeprom: SPI EEPROM device
* This field will be %NULL if no EEPROM device is present.
* @spi_lock: SPI bus lock
* @n_rx_nodesc_drop_cnt: RX no descriptor drop count
* @nic_data: Hardware dependant state
* @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode,
......@@ -731,6 +738,7 @@ struct efx_nic {
struct efx_spi_device *spi_flash;
struct efx_spi_device *spi_eeprom;
struct mutex spi_lock;
unsigned n_rx_nodesc_drop_cnt;
......
......@@ -21,6 +21,7 @@
#include "falcon_hwdefs.h"
#include "falcon_io.h"
#include "mac.h"
#include "workarounds.h"
/**************************************************************************
*
......@@ -65,48 +66,9 @@
#define P1_SPARE_LBN 4
#define P1_SPARE_WIDTH 4
/**************************************************************************
*
* Temperature Sensor
*
**************************************************************************/
#define MAX6647 0x4e
#define RLTS 0x00
#define RLTE 0x01
#define RSL 0x02
#define RCL 0x03
#define RCRA 0x04
#define RLHN 0x05
#define RLLI 0x06
#define RRHI 0x07
#define RRLS 0x08
#define WCRW 0x0a
#define WLHO 0x0b
#define WRHA 0x0c
#define WRLN 0x0e
#define OSHT 0x0f
#define REET 0x10
#define RIET 0x11
#define RWOE 0x19
#define RWOI 0x20
#define HYS 0x21
#define QUEUE 0x22
#define MFID 0xfe
#define REVID 0xff
/* Status bits */
#define MAX6647_BUSY (1 << 7) /* ADC is converting */
#define MAX6647_LHIGH (1 << 6) /* Local high temp. alarm */
#define MAX6647_LLOW (1 << 5) /* Local low temp. alarm */
#define MAX6647_RHIGH (1 << 4) /* Remote high temp. alarm */
#define MAX6647_RLOW (1 << 3) /* Remote low temp. alarm */
#define MAX6647_FAULT (1 << 2) /* DXN/DXP short/open circuit */
#define MAX6647_EOT (1 << 1) /* Remote junction overtemp. */
#define MAX6647_IOT (1 << 0) /* Local junction overtemp. */
static const u8 xgphy_max_temperature = 90;
/* Temperature Sensor */
#define MAX664X_REG_RSL 0x02
#define MAX664X_REG_WLHO 0x0B
static void sfe4001_poweroff(struct efx_nic *efx)
{
......@@ -119,7 +81,7 @@ static void sfe4001_poweroff(struct efx_nic *efx)
i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff);
/* Clear any over-temperature alert */
i2c_smbus_read_byte_data(hwmon_client, RSL);
i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL);
}
static int sfe4001_poweron(struct efx_nic *efx)
......@@ -131,7 +93,7 @@ static int sfe4001_poweron(struct efx_nic *efx)
u8 out;
/* Clear any previous over-temperature alert */
rc = i2c_smbus_read_byte_data(hwmon_client, RSL);
rc = i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL);
if (rc < 0)
return rc;
......@@ -209,6 +171,34 @@ static int sfe4001_poweron(struct efx_nic *efx)
return rc;
}
static int sfe4001_check_hw(struct efx_nic *efx)
{
s32 status;
/* If XAUI link is up then do not monitor */
if (EFX_WORKAROUND_7884(efx) && falcon_xaui_link_ok(efx))
return 0;
/* Check the powered status of the PHY. Lack of power implies that
* the MAX6647 has shut down power to it, probably due to a temp.
* alarm. Reading the power status rather than the MAX6647 status
* directly because the later is read-to-clear and would thus
* start to power up the PHY again when polled, causing us to blip
* the power undesirably.
* We know we can read from the IO expander because we did
* it during power-on. Assume failure now is bad news. */
status = i2c_smbus_read_byte_data(efx->board_info.ioexp_client, P1_IN);
if (status >= 0 &&
(status & ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN))) != 0)
return 0;
/* Use board power control, not PHY power control */
sfe4001_poweroff(efx);
efx->phy_mode = PHY_MODE_OFF;
return (status < 0) ? -EIO : -ERANGE;
}
/* On SFE4001 rev A2 and later, we can control the FLASH_CFG_1 pin
* using the 3V3X output of the IO-expander. Allow the user to set
* this when the device is stopped, and keep it stopped then.
......@@ -261,35 +251,34 @@ static void sfe4001_fini(struct efx_nic *efx)
i2c_unregister_device(efx->board_info.hwmon_client);
}
static struct i2c_board_info sfe4001_hwmon_info = {
I2C_BOARD_INFO("max6647", 0x4e),
.irq = -1,
};
/* This board uses an I2C expander to provider power to the PHY, which needs to
* be turned on before the PHY can be used.
* Context: Process context, rtnl lock held
*/
int sfe4001_init(struct efx_nic *efx)
{
struct i2c_client *hwmon_client;
int rc;
hwmon_client = i2c_new_dummy(&efx->i2c_adap, MAX6647);
if (!hwmon_client)
#if defined(CONFIG_SENSORS_LM90) || defined(CONFIG_SENSORS_LM90_MODULE)
efx->board_info.hwmon_client =
i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info);
#else
efx->board_info.hwmon_client =
i2c_new_dummy(&efx->i2c_adap, sfe4001_hwmon_info.addr);
#endif
if (!efx->board_info.hwmon_client)
return -EIO;
efx->board_info.hwmon_client = hwmon_client;
/* Set DSP over-temperature alert threshold */
EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature);
rc = i2c_smbus_write_byte_data(hwmon_client, WLHO,
xgphy_max_temperature);
/* Raise board/PHY high limit from 85 to 90 degrees Celsius */
rc = i2c_smbus_write_byte_data(efx->board_info.hwmon_client,
MAX664X_REG_WLHO, 90);
if (rc)
goto fail_ioexp;
/* Read it back and verify */
rc = i2c_smbus_read_byte_data(hwmon_client, RLHN);
if (rc < 0)
goto fail_ioexp;
if (rc != xgphy_max_temperature) {
rc = -EFAULT;
goto fail_ioexp;
}
goto fail_hwmon;
efx->board_info.ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539);
if (!efx->board_info.ioexp_client) {
......@@ -301,6 +290,7 @@ int sfe4001_init(struct efx_nic *efx)
* blink code. */
efx->board_info.blink = tenxpress_phy_blink;
efx->board_info.monitor = sfe4001_check_hw;
efx->board_info.fini = sfe4001_fini;
rc = sfe4001_poweron(efx);
......@@ -319,6 +309,6 @@ int sfe4001_init(struct efx_nic *efx)
fail_ioexp:
i2c_unregister_device(efx->board_info.ioexp_client);
fail_hwmon:
i2c_unregister_device(hwmon_client);
i2c_unregister_device(efx->board_info.hwmon_client);
return rc;
}
......@@ -25,6 +25,7 @@
#define SPI_WRDI 0x04 /* Reset write enable latch */
#define SPI_RDSR 0x05 /* Read status register */
#define SPI_WREN 0x06 /* Set write enable latch */
#define SPI_SST_EWSR 0x50 /* SST: Enable write to status register */
#define SPI_STATUS_WPEN 0x80 /* Write-protect pin enabled */
#define SPI_STATUS_BP2 0x10 /* Block protection bit 2 */
......@@ -36,6 +37,7 @@
/**
* struct efx_spi_device - an Efx SPI (Serial Peripheral Interface) device
* @efx: The Efx controller that owns this device
* @mtd: MTD state
* @device_id: Controller's id for the device
* @size: Size (in bytes)
* @addr_len: Number of address bytes in read/write commands
......@@ -44,23 +46,51 @@
* use bit 3 of the command byte as address bit A8, rather
* than having a two-byte address. If this flag is set, then
* commands should be munged in this way.
* @erase_command: Erase command (or 0 if sector erase not needed).
* @erase_size: Erase sector size (in bytes)
* Erase commands affect sectors with this size and alignment.
* This must be a power of two.
* @block_size: Write block size (in bytes).
* Write commands are limited to blocks with this size and alignment.
* @read: Read function for the device
* @write: Write function for the device
*/
struct efx_spi_device {
struct efx_nic *efx;
#ifdef CONFIG_SFC_MTD
void *mtd;
#endif
int device_id;
unsigned int size;
unsigned int addr_len;
unsigned int munge_address:1;
u8 erase_command;
unsigned int erase_size;
unsigned int block_size;
};
int falcon_spi_cmd(const struct efx_spi_device *spi, unsigned int command,
int address, const void* in, void *out, unsigned int len);
int falcon_spi_fast_wait(const struct efx_spi_device *spi);
int falcon_spi_read(const struct efx_spi_device *spi, loff_t start,
size_t len, size_t *retlen, u8 *buffer);
int falcon_spi_write(const struct efx_spi_device *spi, loff_t start,
size_t len, size_t *retlen, const u8 *buffer);
/*
* SFC4000 flash is partitioned into:
* 0-0x400 chip and board config (see falcon_hwdefs.h)
* 0x400-0x8000 unused (or may contain VPD if EEPROM not present)
* 0x8000-end boot code (mapped to PCI expansion ROM)
* SFC4000 small EEPROM (size < 0x400) is used for VPD only.
* SFC4000 large EEPROM (size >= 0x400) is partitioned into:
* 0-0x400 chip and board config
* configurable VPD
* 0x800-0x1800 boot config
* Aside from the chip and board config, all of these are optional and may
* be absent or truncated depending on the devices used.
*/
#define FALCON_NVCONFIG_END 0x400U
#define FALCON_FLASH_BOOTCODE_START 0x8000U
#define EFX_EEPROM_BOOTCONFIG_START 0x800U
#define EFX_EEPROM_BOOTCONFIG_END 0x1800U
#endif /* EFX_SPI_H */
......@@ -376,6 +376,7 @@ static int tenxpress_phy_check_hw(struct efx_nic *efx)
{
struct tenxpress_phy_data *phy_data = efx->phy_data;
bool link_ok;
int rc = 0;
link_ok = tenxpress_link_ok(efx, true);
......@@ -391,7 +392,22 @@ static int tenxpress_phy_check_hw(struct efx_nic *efx)
atomic_set(&phy_data->bad_crc_count, 0);
}
return 0;
rc = efx->board_info.monitor(efx);
if (rc) {
EFX_ERR(efx, "Board sensor %s; shutting down PHY\n",
(rc == -ERANGE) ? "reported fault" : "failed");
if (efx->phy_mode & PHY_MODE_OFF) {
/* Assume that board has shut PHY off */
phy_data->phy_mode = PHY_MODE_OFF;
} else {
efx->phy_mode |= PHY_MODE_LOW_POWER;
mdio_clause45_set_mmds_lpower(efx, true,
efx->phy_op->mmds);
phy_data->phy_mode |= PHY_MODE_LOW_POWER;
}
}
return rc;
}
static void tenxpress_phy_fini(struct efx_nic *efx)
......
......@@ -22,6 +22,8 @@
#define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS
/* RX PCIe double split performance issue */
#define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS
/* Bit-bashed I2C reads cause performance drop */
#define EFX_WORKAROUND_7884 EFX_WORKAROUND_ALWAYS
/* TX pkt parser problem with <= 16 byte TXes */
#define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS
/* Low rate CRC errors require XAUI reset */
......
......@@ -128,6 +128,15 @@ static int xfp_phy_check_hw(struct efx_nic *efx)
if (link_up != efx->link_up)
falcon_xmac_sim_phy_event(efx);
rc = efx->board_info.monitor(efx);
if (rc) {
struct xfp_phy_data *phy_data = efx->phy_data;
EFX_ERR(efx, "XFP sensor alert; putting PHY into low power\n");
efx->phy_mode |= PHY_MODE_LOW_POWER;
mdio_clause45_set_mmds_lpower(efx, 1, XFP_REQUIRED_DEVS);
phy_data->phy_mode |= PHY_MODE_LOW_POWER;
}
return rc;
}
......
This diff is collapsed.
This diff is collapsed.
/***************************************************************************
*
* Copyright (C) 2004-2008 SMSC
* Copyright (C) 2005-2008 ARM
*
* 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 program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
***************************************************************************/
#ifndef __LINUX_SMSC911X_H__
#define __LINUX_SMSC911X_H__
#include <linux/phy.h>
/* platform_device configuration data, should be assigned to
* the platform_device's dev.platform_data */
struct smsc911x_platform_config {
unsigned int irq_polarity;
unsigned int irq_type;
phy_interface_t phy_interface;
};
/* Constants for platform_device irq polarity configuration */
#define SMSC911X_IRQ_POLARITY_ACTIVE_LOW 0
#define SMSC911X_IRQ_POLARITY_ACTIVE_HIGH 1
/* Constants for platform_device irq type configuration */
#define SMSC911X_IRQ_TYPE_OPEN_DRAIN 0
#define SMSC911X_IRQ_TYPE_PUSH_PULL 1
#endif /* __LINUX_SMSC911X_H__ */
This diff is collapsed.
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