#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.93"
-#define DRV_MODULE_RELDATE "May 22, 2008"
+#define DRV_MODULE_VERSION "3.94"
+#define DRV_MODULE_RELDATE "August 14, 2008"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
return 0;
switch (locknum) {
+ case TG3_APE_LOCK_GRC:
case TG3_APE_LOCK_MEM:
break;
default:
return;
switch (locknum) {
+ case TG3_APE_LOCK_GRC:
case TG3_APE_LOCK_MEM:
break;
default:
}
}
+/* tp->lock is held. */
+static inline void tg3_generate_fw_event(struct tg3 *tp)
+{
+ u32 val;
+
+ val = tr32(GRC_RX_CPU_EVENT);
+ val |= GRC_RX_CPU_DRIVER_EVENT;
+ tw32_f(GRC_RX_CPU_EVENT, val);
+
+ tp->last_event_jiffies = jiffies;
+}
+
+#define TG3_FW_EVENT_TIMEOUT_USEC 2500
+
/* tp->lock is held. */
static void tg3_wait_for_event_ack(struct tg3 *tp)
{
int i;
+ unsigned int delay_cnt;
+ long time_remain;
+
+ /* If enough time has passed, no wait is necessary. */
+ time_remain = (long)(tp->last_event_jiffies + 1 +
+ usecs_to_jiffies(TG3_FW_EVENT_TIMEOUT_USEC)) -
+ (long)jiffies;
+ if (time_remain < 0)
+ return;
- /* Wait for up to 2.5 milliseconds */
- for (i = 0; i < 250000; i++) {
+ /* Check if we can shorten the wait time. */
+ delay_cnt = jiffies_to_usecs(time_remain);
+ if (delay_cnt > TG3_FW_EVENT_TIMEOUT_USEC)
+ delay_cnt = TG3_FW_EVENT_TIMEOUT_USEC;
+ delay_cnt = (delay_cnt >> 3) + 1;
+
+ for (i = 0; i < delay_cnt; i++) {
if (!(tr32(GRC_RX_CPU_EVENT) & GRC_RX_CPU_DRIVER_EVENT))
break;
- udelay(10);
+ udelay(8);
}
}
val = 0;
tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 12, val);
- val = tr32(GRC_RX_CPU_EVENT);
- val |= GRC_RX_CPU_DRIVER_EVENT;
- tw32_f(GRC_RX_CPU_EVENT, val);
+ tg3_generate_fw_event(tp);
}
static void tg3_link_report(struct tg3 *tp)
(tp->tg3_flags & TG3_FLAG_WOL_ENABLE))
mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE;
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+ mac_mode |= tp->mac_mode &
+ (MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN);
+ if (mac_mode & MAC_MODE_APE_TX_EN)
+ mac_mode |= MAC_MODE_TDE_ENABLE;
+ }
+
tw32_f(MAC_MODE, mac_mode);
udelay(100);
return;
apedata = tg3_ape_read32(tp, TG3_APE_FW_STATUS);
- if (apedata != APE_FW_STATUS_READY)
+ if (!(apedata & APE_FW_STATUS_READY))
return;
/* Wait for up to 1 millisecond for APE to service previous event. */
tg3_mdio_stop(tp);
+ tg3_ape_lock(tp, TG3_APE_LOCK_GRC);
+
/* No matching tg3_nvram_unlock() after this because
* chip reset below will undo the nvram lock.
*/
} else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
tp->mac_mode = MAC_MODE_PORT_MODE_GMII;
tw32_f(MAC_MODE, tp->mac_mode);
+ } else if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+ tp->mac_mode &= (MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN);
+ if (tp->mac_mode & MAC_MODE_APE_TX_EN)
+ tp->mac_mode |= MAC_MODE_TDE_ENABLE;
+ tw32_f(MAC_MODE, tp->mac_mode);
} else
tw32_f(MAC_MODE, 0);
udelay(40);
tg3_mdio_start(tp);
+ tg3_ape_unlock(tp, TG3_APE_LOCK_GRC);
+
err = tg3_poll_fw(tp);
if (err)
return err;
tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg);
if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) {
tp->tg3_flags |= TG3_FLAG_ENABLE_ASF;
+ tp->last_event_jiffies = jiffies;
if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE;
}
{
if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
- u32 val;
-
/* Wait for RX cpu to ACK the previous event. */
tg3_wait_for_event_ack(tp);
tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_PAUSE_FW);
- val = tr32(GRC_RX_CPU_EVENT);
- val |= GRC_RX_CPU_DRIVER_EVENT;
- tw32(GRC_RX_CPU_EVENT, val);
+
+ tg3_generate_fw_event(tp);
/* Wait for RX cpu to ACK this event. */
tg3_wait_for_event_ack(tp);
udelay(10);
}
- tp->mac_mode = MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+ tp->mac_mode &= MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
+ else
+ tp->mac_mode = 0;
+ tp->mac_mode |= MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE;
if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) &&
!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
* resets.
*/
if (!--tp->asf_counter) {
- if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
- u32 val;
-
+ if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
+ !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
tg3_wait_for_event_ack(tp);
tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX,
tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
/* 5 seconds timeout */
tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5);
- val = tr32(GRC_RX_CPU_EVENT);
- val |= GRC_RX_CPU_DRIVER_EVENT;
- tw32_f(GRC_RX_CPU_EVENT, val);
+
+ tg3_generate_fw_event(tp);
}
tp->asf_counter = tp->asf_multiplier;
}
return ret;
}
+static inline u64 get_estat64(tg3_stat64_t *val)
+{
+ return ((u64)val->high << 32) | ((u64)val->low);
+}
+
static unsigned long calc_crc_errors(struct tg3 *tp)
{
struct tg3_hw_stats *hw_stats = tp->hw_stats;
#define ESTAT_ADD(member) \
estats->member = old_estats->member + \
- get_stat64(&hw_stats->member)
+ get_estat64(&hw_stats->member)
static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp)
{
tp->misc_host_ctrl);
}
+ /* Preserve the APE MAC_MODE bits */
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+ tp->mac_mode = tr32(MAC_MODE) |
+ MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
+ else
+ tp->mac_mode = TG3_DEF_MAC_MODE;
+
/* these are limited to 10/100 only */
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
(grc_misc_cfg == 0x8000 || grc_misc_cfg == 0x4000)) ||
tp->pdev = pdev;
tp->dev = dev;
tp->pm_cap = pm_cap;
- tp->mac_mode = TG3_DEF_MAC_MODE;
tp->rx_mode = TG3_DEF_RX_MODE;
tp->tx_mode = TG3_DEF_TX_MODE;
#define MAC_MODE_TDE_ENABLE 0x00200000
#define MAC_MODE_RDE_ENABLE 0x00400000
#define MAC_MODE_FHDE_ENABLE 0x00800000
+#define MAC_MODE_APE_RX_EN 0x08000000
+#define MAC_MODE_APE_TX_EN 0x10000000
#define MAC_STATUS 0x00000404
#define MAC_STATUS_PCS_SYNCED 0x00000001
#define MAC_STATUS_SIGNAL_DET 0x00000002
#define APE_EVENT_STATUS_EVENT_PENDING 0x80000000
/* APE convenience enumerations. */
+#define TG3_APE_LOCK_GRC 1
#define TG3_APE_LOCK_MEM 4
#define TG3_EEPROM_SB_F1R2_MBA_OFF 0x10
struct tg3_ethtool_stats estats;
struct tg3_ethtool_stats estats_prev;
+ union {
unsigned long phy_crc_errors;
+ unsigned long last_event_jiffies;
+ };
u32 rx_offset;
u32 tg3_flags;
struct net_device *dev,
int strict);
-extern int ipv6_dev_get_saddr(struct net_device *dev,
+extern int ipv6_dev_get_saddr(struct net *net,
+ struct net_device *dev,
const struct in6_addr *daddr,
unsigned int srcprefs,
struct in6_addr *saddr);
{
struct sk_buff *skb;
struct netlink_callback *cb;
+ struct net *net;
};
extern int rt6_dump_route(struct rt6_info *rt, void *p_arg);
return 0;
}
+static void rt_secret_reschedule(int old)
+{
+ struct net *net;
+ int new = ip_rt_secret_interval;
+ int diff = new - old;
+
+ if (!diff)
+ return;
+
+ rtnl_lock();
+ for_each_net(net) {
+ int deleted = del_timer_sync(&net->ipv4.rt_secret_timer);
+
+ if (!new)
+ continue;
+
+ if (deleted) {
+ long time = net->ipv4.rt_secret_timer.expires - jiffies;
+
+ if (time <= 0 || (time += diff) <= 0)
+ time = 0;
+
+ net->ipv4.rt_secret_timer.expires = time;
+ } else
+ net->ipv4.rt_secret_timer.expires = new;
+
+ net->ipv4.rt_secret_timer.expires += jiffies;
+ add_timer(&net->ipv4.rt_secret_timer);
+ }
+ rtnl_unlock();
+}
+
+static int ipv4_sysctl_rt_secret_interval(ctl_table *ctl, int write,
+ struct file *filp,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ int old = ip_rt_secret_interval;
+ int ret = proc_dointvec_jiffies(ctl, write, filp, buffer, lenp, ppos);
+
+ rt_secret_reschedule(old);
+
+ return ret;
+}
+
+static int ipv4_sysctl_rt_secret_interval_strategy(ctl_table *table,
+ int __user *name,
+ int nlen,
+ void __user *oldval,
+ size_t __user *oldlenp,
+ void __user *newval,
+ size_t newlen)
+{
+ int old = ip_rt_secret_interval;
+ int ret = sysctl_jiffies(table, name, nlen, oldval, oldlenp, newval,
+ newlen);
+
+ rt_secret_reschedule(old);
+
+ return ret;
+}
+
static ctl_table ipv4_route_table[] = {
{
.ctl_name = NET_IPV4_ROUTE_GC_THRESH,
.data = &ip_rt_secret_interval,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec_jiffies,
- .strategy = &sysctl_jiffies,
+ .proc_handler = &ipv4_sysctl_rt_secret_interval,
+ .strategy = &ipv4_sysctl_rt_secret_interval_strategy,
},
{ .ctl_name = 0 }
};
net->ipv4.rt_secret_timer.data = (unsigned long)net;
init_timer_deferrable(&net->ipv4.rt_secret_timer);
- net->ipv4.rt_secret_timer.expires =
- jiffies + net_random() % ip_rt_secret_interval +
- ip_rt_secret_interval;
- add_timer(&net->ipv4.rt_secret_timer);
+ if (ip_rt_secret_interval) {
+ net->ipv4.rt_secret_timer.expires =
+ jiffies + net_random() % ip_rt_secret_interval +
+ ip_rt_secret_interval;
+ add_timer(&net->ipv4.rt_secret_timer);
+ }
return 0;
}
return ret;
}
-int ipv6_dev_get_saddr(struct net_device *dst_dev,
+int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev,
const struct in6_addr *daddr, unsigned int prefs,
struct in6_addr *saddr)
{
struct ipv6_saddr_score scores[2],
*score = &scores[0], *hiscore = &scores[1];
- struct net *net = dev_net(dst_dev);
struct ipv6_saddr_dst dst;
struct net_device *dev;
int dst_type;
if (flags & RT6_LOOKUP_F_SRCPREF_COA)
srcprefs |= IPV6_PREFER_SRC_COA;
- if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev,
+ if (ipv6_dev_get_saddr(net,
+ ip6_dst_idev(&rt->u.dst)->dev,
&flp->fl6_dst, srcprefs,
&saddr))
goto again;
arg.skb = skb;
arg.cb = cb;
+ arg.net = net;
w->args = &arg;
for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
goto out_err_release;
if (ipv6_addr_any(&fl->fl6_src)) {
- err = ipv6_dev_get_saddr(ip6_dst_idev(*dst)->dev,
+ err = ipv6_dev_get_saddr(net, ip6_dst_idev(*dst)->dev,
&fl->fl6_dst,
sk ? inet6_sk(sk)->srcprefs : 0,
&fl->fl6_src);
override = 0;
in6_ifa_put(ifp);
} else {
- if (ipv6_dev_get_saddr(dev, daddr,
+ if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
&tmpaddr))
return;
+ nla_total_size(sizeof(struct rta_cacheinfo));
}
-static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
+static int rt6_fill_node(struct net *net,
+ struct sk_buff *skb, struct rt6_info *rt,
struct in6_addr *dst, struct in6_addr *src,
int iif, int type, u32 pid, u32 seq,
int prefix, int nowait, unsigned int flags)
} else if (dst) {
struct inet6_dev *idev = ip6_dst_idev(&rt->u.dst);
struct in6_addr saddr_buf;
- if (ipv6_dev_get_saddr(idev ? idev->dev : NULL,
+ if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
dst, 0, &saddr_buf) == 0)
NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
}
} else
prefix = 0;
- return rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
+ return rt6_fill_node(arg->net,
+ arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq,
prefix, 0, NLM_F_MULTI);
}
rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl);
skb->dst = &rt->u.dst;
- err = rt6_fill_node(skb, rt, &fl.fl6_dst, &fl.fl6_src, iif,
+ err = rt6_fill_node(net, skb, rt, &fl.fl6_dst, &fl.fl6_src, iif,
RTM_NEWROUTE, NETLINK_CB(in_skb).pid,
nlh->nlmsg_seq, 0, 0, 0);
if (err < 0) {
if (skb == NULL)
goto errout;
- err = rt6_fill_node(skb, rt, NULL, NULL, 0,
+ err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
event, info->pid, seq, 0, 0, 0);
if (err < 0) {
/* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
{
struct dst_entry *dst;
+ struct net_device *dev;
dst = xfrm6_dst_lookup(0, NULL, daddr);
if (IS_ERR(dst))
return -EHOSTUNREACH;
- ipv6_dev_get_saddr(ip6_dst_idev(dst)->dev,
+ dev = ip6_dst_idev(dst)->dev;
+ ipv6_dev_get_saddr(dev_net(dev), dev,
(struct in6_addr *)&daddr->a6, 0,
(struct in6_addr *)&saddr->a6);
dst_release(dst);
if (n->nlmsg_type == RTM_DELTFILTER && t->tcm_handle == 0) {
spin_lock_bh(root_lock);
*back = tp->next;
- spin_lock_bh(root_lock);
+ spin_unlock_bh(root_lock);
tfilter_notify(skb, n, tp, fh, RTM_DELTFILTER);
tcf_destroy(tp);
__func__, asoc, dst, NIP6(daddr->v6.sin6_addr));
if (!asoc) {
- ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL,
+ ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)),
+ dst ? ip6_dst_idev(dst)->dev : NULL,
&daddr->v6.sin6_addr,
inet6_sk(&sk->inet.sk)->srcprefs,
&saddr->v6.sin6_addr);