Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6:
  Phonet: keep TX queue disabled when the device is off
  SCHED: netem: Correct documentation comment in code.
  netfilter: update rwlock initialization for nat_table
  netlabel: Compiler warning and NULL pointer dereference fix
  e1000e: fix double release of mutex
  IA64: HP_SIMETH needs to depend upon NET
  netpoll: fix race on poll_list resulting in garbage entry
  ipv6: silence log messages for locally generated multicast
  sungem: improve ethtool output with internal pcs and serdes
  tcp: tcp_vegas cong avoid fix 
  sungem: Make PCS PHY support partially work again.
This commit is contained in:
Linus Torvalds 2008-12-15 16:30:22 -08:00
Родитель d2ff911882 4798a2b84e
Коммит 7004405cb8
11 изменённых файлов: 164 добавлений и 156 удалений

Просмотреть файл

@ -4,6 +4,7 @@ menu "HP Simulator drivers"
config HP_SIMETH config HP_SIMETH
bool "Simulated Ethernet " bool "Simulated Ethernet "
depends on NET
config HP_SIMSERIAL config HP_SIMSERIAL
bool "Simulated serial driver support" bool "Simulated serial driver support"

Просмотреть файл

@ -1893,12 +1893,17 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
ctrl |= E1000_CTRL_PHY_RST; ctrl |= E1000_CTRL_PHY_RST;
} }
ret_val = e1000_acquire_swflag_ich8lan(hw); ret_val = e1000_acquire_swflag_ich8lan(hw);
/* Whether or not the swflag was acquired, we need to reset the part */
hw_dbg(hw, "Issuing a global reset to ich8lan"); hw_dbg(hw, "Issuing a global reset to ich8lan");
ew32(CTRL, (ctrl | E1000_CTRL_RST)); ew32(CTRL, (ctrl | E1000_CTRL_RST));
msleep(20); msleep(20);
/* release the swflag because it is not reset by hardware reset */ if (!ret_val) {
/* release the swflag because it is not reset by
* hardware reset
*/
e1000_release_swflag_ich8lan(hw); e1000_release_swflag_ich8lan(hw);
}
ret_val = e1000e_get_auto_rd_done(hw); ret_val = e1000e_get_auto_rd_done(hw);
if (ret_val) { if (ret_val) {

Просмотреть файл

@ -1142,6 +1142,70 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
static void gem_pcs_reset(struct gem *gp)
{
int limit;
u32 val;
/* Reset PCS unit. */
val = readl(gp->regs + PCS_MIICTRL);
val |= PCS_MIICTRL_RST;
writel(val, gp->regs + PCS_MIICTRL);
limit = 32;
while (readl(gp->regs + PCS_MIICTRL) & PCS_MIICTRL_RST) {
udelay(100);
if (limit-- <= 0)
break;
}
if (limit <= 0)
printk(KERN_WARNING "%s: PCS reset bit would not clear.\n",
gp->dev->name);
}
static void gem_pcs_reinit_adv(struct gem *gp)
{
u32 val;
/* Make sure PCS is disabled while changing advertisement
* configuration.
*/
val = readl(gp->regs + PCS_CFG);
val &= ~(PCS_CFG_ENABLE | PCS_CFG_TO);
writel(val, gp->regs + PCS_CFG);
/* Advertise all capabilities except assymetric
* pause.
*/
val = readl(gp->regs + PCS_MIIADV);
val |= (PCS_MIIADV_FD | PCS_MIIADV_HD |
PCS_MIIADV_SP | PCS_MIIADV_AP);
writel(val, gp->regs + PCS_MIIADV);
/* Enable and restart auto-negotiation, disable wrapback/loopback,
* and re-enable PCS.
*/
val = readl(gp->regs + PCS_MIICTRL);
val |= (PCS_MIICTRL_RAN | PCS_MIICTRL_ANE);
val &= ~PCS_MIICTRL_WB;
writel(val, gp->regs + PCS_MIICTRL);
val = readl(gp->regs + PCS_CFG);
val |= PCS_CFG_ENABLE;
writel(val, gp->regs + PCS_CFG);
/* Make sure serialink loopback is off. The meaning
* of this bit is logically inverted based upon whether
* you are in Serialink or SERDES mode.
*/
val = readl(gp->regs + PCS_SCTRL);
if (gp->phy_type == phy_serialink)
val &= ~PCS_SCTRL_LOOP;
else
val |= PCS_SCTRL_LOOP;
writel(val, gp->regs + PCS_SCTRL);
}
#define STOP_TRIES 32 #define STOP_TRIES 32
/* Must be invoked under gp->lock and gp->tx_lock. */ /* Must be invoked under gp->lock and gp->tx_lock. */
@ -1168,6 +1232,9 @@ static void gem_reset(struct gem *gp)
if (limit <= 0) if (limit <= 0)
printk(KERN_ERR "%s: SW reset is ghetto.\n", gp->dev->name); printk(KERN_ERR "%s: SW reset is ghetto.\n", gp->dev->name);
if (gp->phy_type == phy_serialink || gp->phy_type == phy_serdes)
gem_pcs_reinit_adv(gp);
} }
/* Must be invoked under gp->lock and gp->tx_lock. */ /* Must be invoked under gp->lock and gp->tx_lock. */
@ -1324,7 +1391,7 @@ static int gem_set_link_modes(struct gem *gp)
gp->phy_type == phy_serdes) { gp->phy_type == phy_serdes) {
u32 pcs_lpa = readl(gp->regs + PCS_MIILP); u32 pcs_lpa = readl(gp->regs + PCS_MIILP);
if (pcs_lpa & PCS_MIIADV_FD) if ((pcs_lpa & PCS_MIIADV_FD) || gp->phy_type == phy_serdes)
full_duplex = 1; full_duplex = 1;
speed = SPEED_1000; speed = SPEED_1000;
} }
@ -1488,6 +1555,9 @@ static void gem_link_timer(unsigned long data)
val = readl(gp->regs + PCS_MIISTAT); val = readl(gp->regs + PCS_MIISTAT);
if ((val & PCS_MIISTAT_LS) != 0) { if ((val & PCS_MIISTAT_LS) != 0) {
if (gp->lstate == link_up)
goto restart;
gp->lstate = link_up; gp->lstate = link_up;
netif_carrier_on(gp->dev); netif_carrier_on(gp->dev);
(void)gem_set_link_modes(gp); (void)gem_set_link_modes(gp);
@ -1708,61 +1778,8 @@ static void gem_init_phy(struct gem *gp)
if (gp->phy_mii.def && gp->phy_mii.def->ops->init) if (gp->phy_mii.def && gp->phy_mii.def->ops->init)
gp->phy_mii.def->ops->init(&gp->phy_mii); gp->phy_mii.def->ops->init(&gp->phy_mii);
} else { } else {
u32 val; gem_pcs_reset(gp);
int limit; gem_pcs_reinit_adv(gp);
/* Reset PCS unit. */
val = readl(gp->regs + PCS_MIICTRL);
val |= PCS_MIICTRL_RST;
writel(val, gp->regs + PCS_MIICTRL);
limit = 32;
while (readl(gp->regs + PCS_MIICTRL) & PCS_MIICTRL_RST) {
udelay(100);
if (limit-- <= 0)
break;
}
if (limit <= 0)
printk(KERN_WARNING "%s: PCS reset bit would not clear.\n",
gp->dev->name);
/* Make sure PCS is disabled while changing advertisement
* configuration.
*/
val = readl(gp->regs + PCS_CFG);
val &= ~(PCS_CFG_ENABLE | PCS_CFG_TO);
writel(val, gp->regs + PCS_CFG);
/* Advertise all capabilities except assymetric
* pause.
*/
val = readl(gp->regs + PCS_MIIADV);
val |= (PCS_MIIADV_FD | PCS_MIIADV_HD |
PCS_MIIADV_SP | PCS_MIIADV_AP);
writel(val, gp->regs + PCS_MIIADV);
/* Enable and restart auto-negotiation, disable wrapback/loopback,
* and re-enable PCS.
*/
val = readl(gp->regs + PCS_MIICTRL);
val |= (PCS_MIICTRL_RAN | PCS_MIICTRL_ANE);
val &= ~PCS_MIICTRL_WB;
writel(val, gp->regs + PCS_MIICTRL);
val = readl(gp->regs + PCS_CFG);
val |= PCS_CFG_ENABLE;
writel(val, gp->regs + PCS_CFG);
/* Make sure serialink loopback is off. The meaning
* of this bit is logically inverted based upon whether
* you are in Serialink or SERDES mode.
*/
val = readl(gp->regs + PCS_SCTRL);
if (gp->phy_type == phy_serialink)
val &= ~PCS_SCTRL_LOOP;
else
val |= PCS_SCTRL_LOOP;
writel(val, gp->regs + PCS_SCTRL);
} }
/* Default aneg parameters */ /* Default aneg parameters */
@ -2680,6 +2697,21 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->speed = 0; cmd->speed = 0;
cmd->duplex = cmd->port = cmd->phy_address = cmd->duplex = cmd->port = cmd->phy_address =
cmd->transceiver = cmd->autoneg = 0; cmd->transceiver = cmd->autoneg = 0;
/* serdes means usually a Fibre connector, with most fixed */
if (gp->phy_type == phy_serdes) {
cmd->port = PORT_FIBRE;
cmd->supported = (SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE | SUPPORTED_Autoneg |
SUPPORTED_Pause | SUPPORTED_Asym_Pause);
cmd->advertising = cmd->supported;
cmd->transceiver = XCVR_INTERNAL;
if (gp->lstate == link_up)
cmd->speed = SPEED_1000;
cmd->duplex = DUPLEX_FULL;
cmd->autoneg = 1;
}
} }
cmd->maxtxpkt = cmd->maxrxpkt = 0; cmd->maxtxpkt = cmd->maxrxpkt = 0;

Просмотреть файл

@ -319,6 +319,7 @@ enum
{ {
NAPI_STATE_SCHED, /* Poll is scheduled */ NAPI_STATE_SCHED, /* Poll is scheduled */
NAPI_STATE_DISABLE, /* Disable pending */ NAPI_STATE_DISABLE, /* Disable pending */
NAPI_STATE_NPSVC, /* Netpoll - don't dequeue from poll_list */
}; };
extern void __napi_schedule(struct napi_struct *n); extern void __napi_schedule(struct napi_struct *n);
@ -1497,6 +1498,12 @@ static inline void netif_rx_complete(struct net_device *dev,
{ {
unsigned long flags; unsigned long flags;
/*
* don't let napi dequeue from the cpu poll list
* just in case its running on a different cpu
*/
if (unlikely(test_bit(NAPI_STATE_NPSVC, &napi->state)))
return;
local_irq_save(flags); local_irq_save(flags);
__netif_rx_complete(dev, napi); __netif_rx_complete(dev, napi);
local_irq_restore(flags); local_irq_restore(flags);

Просмотреть файл

@ -133,9 +133,11 @@ static int poll_one_napi(struct netpoll_info *npinfo,
npinfo->rx_flags |= NETPOLL_RX_DROP; npinfo->rx_flags |= NETPOLL_RX_DROP;
atomic_inc(&trapped); atomic_inc(&trapped);
set_bit(NAPI_STATE_NPSVC, &napi->state);
work = napi->poll(napi, budget); work = napi->poll(napi, budget);
clear_bit(NAPI_STATE_NPSVC, &napi->state);
atomic_dec(&trapped); atomic_dec(&trapped);
npinfo->rx_flags &= ~NETPOLL_RX_DROP; npinfo->rx_flags &= ~NETPOLL_RX_DROP;

Просмотреть файл

@ -61,7 +61,7 @@ static struct
static struct xt_table nat_table = { static struct xt_table nat_table = {
.name = "nat", .name = "nat",
.valid_hooks = NAT_VALID_HOOKS, .valid_hooks = NAT_VALID_HOOKS,
.lock = __RW_LOCK_UNLOCKED(__nat_table.lock), .lock = __RW_LOCK_UNLOCKED(nat_table.lock),
.me = THIS_MODULE, .me = THIS_MODULE,
.af = AF_INET, .af = AF_INET,
}; };

Просмотреть файл

@ -40,18 +40,14 @@
#include "tcp_vegas.h" #include "tcp_vegas.h"
/* Default values of the Vegas variables, in fixed-point representation static int alpha = 2;
* with V_PARAM_SHIFT bits to the right of the binary point. static int beta = 4;
*/ static int gamma = 1;
#define V_PARAM_SHIFT 1
static int alpha = 2<<V_PARAM_SHIFT;
static int beta = 4<<V_PARAM_SHIFT;
static int gamma = 1<<V_PARAM_SHIFT;
module_param(alpha, int, 0644); module_param(alpha, int, 0644);
MODULE_PARM_DESC(alpha, "lower bound of packets in network (scale by 2)"); MODULE_PARM_DESC(alpha, "lower bound of packets in network");
module_param(beta, int, 0644); module_param(beta, int, 0644);
MODULE_PARM_DESC(beta, "upper bound of packets in network (scale by 2)"); MODULE_PARM_DESC(beta, "upper bound of packets in network");
module_param(gamma, int, 0644); module_param(gamma, int, 0644);
MODULE_PARM_DESC(gamma, "limit on increase (scale by 2)"); MODULE_PARM_DESC(gamma, "limit on increase (scale by 2)");
@ -172,49 +168,13 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
return; return;
} }
/* The key players are v_beg_snd_una and v_beg_snd_nxt.
*
* These are so named because they represent the approximate values
* of snd_una and snd_nxt at the beginning of the current RTT. More
* precisely, they represent the amount of data sent during the RTT.
* At the end of the RTT, when we receive an ACK for v_beg_snd_nxt,
* we will calculate that (v_beg_snd_nxt - v_beg_snd_una) outstanding
* bytes of data have been ACKed during the course of the RTT, giving
* an "actual" rate of:
*
* (v_beg_snd_nxt - v_beg_snd_una) / (rtt duration)
*
* Unfortunately, v_beg_snd_una is not exactly equal to snd_una,
* because delayed ACKs can cover more than one segment, so they
* don't line up nicely with the boundaries of RTTs.
*
* Another unfortunate fact of life is that delayed ACKs delay the
* advance of the left edge of our send window, so that the number
* of bytes we send in an RTT is often less than our cwnd will allow.
* So we keep track of our cwnd separately, in v_beg_snd_cwnd.
*/
if (after(ack, vegas->beg_snd_nxt)) { if (after(ack, vegas->beg_snd_nxt)) {
/* Do the Vegas once-per-RTT cwnd adjustment. */ /* Do the Vegas once-per-RTT cwnd adjustment. */
u32 old_wnd, old_snd_cwnd;
/* Here old_wnd is essentially the window of data that was
* sent during the previous RTT, and has all
* been acknowledged in the course of the RTT that ended
* with the ACK we just received. Likewise, old_snd_cwnd
* is the cwnd during the previous RTT.
*/
old_wnd = (vegas->beg_snd_nxt - vegas->beg_snd_una) /
tp->mss_cache;
old_snd_cwnd = vegas->beg_snd_cwnd;
/* Save the extent of the current window so we can use this /* Save the extent of the current window so we can use this
* at the end of the next RTT. * at the end of the next RTT.
*/ */
vegas->beg_snd_una = vegas->beg_snd_nxt;
vegas->beg_snd_nxt = tp->snd_nxt; vegas->beg_snd_nxt = tp->snd_nxt;
vegas->beg_snd_cwnd = tp->snd_cwnd;
/* We do the Vegas calculations only if we got enough RTT /* We do the Vegas calculations only if we got enough RTT
* samples that we can be reasonably sure that we got * samples that we can be reasonably sure that we got
@ -252,22 +212,14 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
* *
* This is: * This is:
* (actual rate in segments) * baseRTT * (actual rate in segments) * baseRTT
* We keep it as a fixed point number with
* V_PARAM_SHIFT bits to the right of the binary point.
*/ */
target_cwnd = ((u64)old_wnd * vegas->baseRTT); target_cwnd = tp->snd_cwnd * vegas->baseRTT / rtt;
target_cwnd <<= V_PARAM_SHIFT;
do_div(target_cwnd, rtt);
/* Calculate the difference between the window we had, /* Calculate the difference between the window we had,
* and the window we would like to have. This quantity * and the window we would like to have. This quantity
* is the "Diff" from the Arizona Vegas papers. * is the "Diff" from the Arizona Vegas papers.
*
* Again, this is a fixed point number with
* V_PARAM_SHIFT bits to the right of the binary
* point.
*/ */
diff = (old_wnd << V_PARAM_SHIFT) - target_cwnd; diff = tp->snd_cwnd * (rtt-vegas->baseRTT) / vegas->baseRTT;
if (diff > gamma && tp->snd_ssthresh > 2 ) { if (diff > gamma && tp->snd_ssthresh > 2 ) {
/* Going too fast. Time to slow down /* Going too fast. Time to slow down
@ -282,16 +234,13 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
* truncation robs us of full link * truncation robs us of full link
* utilization. * utilization.
*/ */
tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_cwnd = min(tp->snd_cwnd, (u32)target_cwnd+1);
((u32)target_cwnd >>
V_PARAM_SHIFT)+1);
} else if (tp->snd_cwnd <= tp->snd_ssthresh) { } else if (tp->snd_cwnd <= tp->snd_ssthresh) {
/* Slow start. */ /* Slow start. */
tcp_slow_start(tp); tcp_slow_start(tp);
} else { } else {
/* Congestion avoidance. */ /* Congestion avoidance. */
u32 next_snd_cwnd;
/* Figure out where we would like cwnd /* Figure out where we would like cwnd
* to be. * to be.
@ -300,26 +249,17 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
/* The old window was too fast, so /* The old window was too fast, so
* we slow down. * we slow down.
*/ */
next_snd_cwnd = old_snd_cwnd - 1; tp->snd_cwnd--;
} else if (diff < alpha) { } else if (diff < alpha) {
/* We don't have enough extra packets /* We don't have enough extra packets
* in the network, so speed up. * in the network, so speed up.
*/ */
next_snd_cwnd = old_snd_cwnd + 1; tp->snd_cwnd++;
} else { } else {
/* Sending just as fast as we /* Sending just as fast as we
* should be. * should be.
*/ */
next_snd_cwnd = old_snd_cwnd;
} }
/* Adjust cwnd upward or downward, toward the
* desired value.
*/
if (next_snd_cwnd > tp->snd_cwnd)
tp->snd_cwnd++;
else if (next_snd_cwnd < tp->snd_cwnd)
tp->snd_cwnd--;
} }
if (tp->snd_cwnd < 2) if (tp->snd_cwnd < 2)

Просмотреть файл

@ -912,7 +912,12 @@ static void ndisc_recv_na(struct sk_buff *skb)
is invalid, but ndisc specs say nothing is invalid, but ndisc specs say nothing
about it. It could be misconfiguration, or about it. It could be misconfiguration, or
an smart proxy agent tries to help us :-) an smart proxy agent tries to help us :-)
We should not print the error if NA has been
received from loopback - it is just our own
unsolicited advertisement.
*/ */
if (skb->pkt_type != PACKET_LOOPBACK)
ND_PRINTK1(KERN_WARNING ND_PRINTK1(KERN_WARNING
"ICMPv6 NA: someone advertises our address on %s!\n", "ICMPv6 NA: someone advertises our address on %s!\n",
ifp->idev->dev->name); ifp->idev->dev->name);

Просмотреть файл

@ -562,7 +562,6 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
const struct in_addr *mask, const struct in_addr *mask,
struct netlbl_audit *audit_info) struct netlbl_audit *audit_info)
{ {
int ret_val = 0;
struct netlbl_af4list *list_entry; struct netlbl_af4list *list_entry;
struct netlbl_unlhsh_addr4 *entry; struct netlbl_unlhsh_addr4 *entry;
struct audit_buffer *audit_buf; struct audit_buffer *audit_buf;
@ -577,7 +576,7 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
if (list_entry != NULL) if (list_entry != NULL)
entry = netlbl_unlhsh_addr4_entry(list_entry); entry = netlbl_unlhsh_addr4_entry(list_entry);
else else
ret_val = -ENOENT; entry = NULL;
audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL, audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
audit_info); audit_info);
@ -588,19 +587,21 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
addr->s_addr, mask->s_addr); addr->s_addr, mask->s_addr);
if (dev != NULL) if (dev != NULL)
dev_put(dev); dev_put(dev);
if (entry && security_secid_to_secctx(entry->secid, if (entry != NULL &&
&secctx, security_secid_to_secctx(entry->secid,
&secctx_len) == 0) { &secctx, &secctx_len) == 0) {
audit_log_format(audit_buf, " sec_obj=%s", secctx); audit_log_format(audit_buf, " sec_obj=%s", secctx);
security_release_secctx(secctx, secctx_len); security_release_secctx(secctx, secctx_len);
} }
audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0); audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);
audit_log_end(audit_buf); audit_log_end(audit_buf);
} }
if (ret_val == 0) if (entry == NULL)
return -ENOENT;
call_rcu(&entry->rcu, netlbl_unlhsh_free_addr4); call_rcu(&entry->rcu, netlbl_unlhsh_free_addr4);
return ret_val; return 0;
} }
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@ -624,7 +625,6 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
const struct in6_addr *mask, const struct in6_addr *mask,
struct netlbl_audit *audit_info) struct netlbl_audit *audit_info)
{ {
int ret_val = 0;
struct netlbl_af6list *list_entry; struct netlbl_af6list *list_entry;
struct netlbl_unlhsh_addr6 *entry; struct netlbl_unlhsh_addr6 *entry;
struct audit_buffer *audit_buf; struct audit_buffer *audit_buf;
@ -638,7 +638,7 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
if (list_entry != NULL) if (list_entry != NULL)
entry = netlbl_unlhsh_addr6_entry(list_entry); entry = netlbl_unlhsh_addr6_entry(list_entry);
else else
ret_val = -ENOENT; entry = NULL;
audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL, audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
audit_info); audit_info);
@ -649,19 +649,21 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
addr, mask); addr, mask);
if (dev != NULL) if (dev != NULL)
dev_put(dev); dev_put(dev);
if (entry && security_secid_to_secctx(entry->secid, if (entry != NULL &&
&secctx, security_secid_to_secctx(entry->secid,
&secctx_len) == 0) { &secctx, &secctx_len) == 0) {
audit_log_format(audit_buf, " sec_obj=%s", secctx); audit_log_format(audit_buf, " sec_obj=%s", secctx);
security_release_secctx(secctx, secctx_len); security_release_secctx(secctx, secctx_len);
} }
audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0); audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);
audit_log_end(audit_buf); audit_log_end(audit_buf);
} }
if (ret_val == 0) if (entry == NULL)
return -ENOENT;
call_rcu(&entry->rcu, netlbl_unlhsh_free_addr6); call_rcu(&entry->rcu, netlbl_unlhsh_free_addr6);
return ret_val; return 0;
} }
#endif /* IPv6 */ #endif /* IPv6 */

Просмотреть файл

@ -155,12 +155,13 @@ static void gprs_data_ready(struct sock *sk, int len)
static void gprs_write_space(struct sock *sk) static void gprs_write_space(struct sock *sk)
{ {
struct gprs_dev *dev = sk->sk_user_data; struct gprs_dev *dev = sk->sk_user_data;
struct net_device *net = dev->net;
unsigned credits = pep_writeable(sk); unsigned credits = pep_writeable(sk);
spin_lock_bh(&dev->tx_lock); spin_lock_bh(&dev->tx_lock);
dev->tx_max = credits; dev->tx_max = credits;
if (credits > skb_queue_len(&dev->tx_queue)) if (credits > skb_queue_len(&dev->tx_queue) && netif_running(net))
netif_wake_queue(dev->net); netif_wake_queue(net);
spin_unlock_bh(&dev->tx_lock); spin_unlock_bh(&dev->tx_lock);
} }
@ -168,6 +169,23 @@ static void gprs_write_space(struct sock *sk)
* Network device callbacks * Network device callbacks
*/ */
static int gprs_open(struct net_device *dev)
{
struct gprs_dev *gp = netdev_priv(dev);
gprs_write_space(gp->sk);
return 0;
}
static int gprs_close(struct net_device *dev)
{
struct gprs_dev *gp = netdev_priv(dev);
netif_stop_queue(dev);
flush_work(&gp->tx_work);
return 0;
}
static int gprs_xmit(struct sk_buff *skb, struct net_device *net) static int gprs_xmit(struct sk_buff *skb, struct net_device *net)
{ {
struct gprs_dev *dev = netdev_priv(net); struct gprs_dev *dev = netdev_priv(net);
@ -254,6 +272,8 @@ static void gprs_setup(struct net_device *net)
net->tx_queue_len = 10; net->tx_queue_len = 10;
net->destructor = free_netdev; net->destructor = free_netdev;
net->open = gprs_open;
net->stop = gprs_close;
net->hard_start_xmit = gprs_xmit; /* mandatory */ net->hard_start_xmit = gprs_xmit; /* mandatory */
net->change_mtu = gprs_set_mtu; net->change_mtu = gprs_set_mtu;
net->get_stats = gprs_get_stats; net->get_stats = gprs_get_stats;
@ -318,7 +338,6 @@ int gprs_attach(struct sock *sk)
dev->sk = sk; dev->sk = sk;
printk(KERN_DEBUG"%s: attached\n", net->name); printk(KERN_DEBUG"%s: attached\n", net->name);
gprs_write_space(sk); /* kick off TX */
return net->ifindex; return net->ifindex;
out_rel: out_rel:
@ -341,7 +360,5 @@ void gprs_detach(struct sock *sk)
printk(KERN_DEBUG"%s: detached\n", net->name); printk(KERN_DEBUG"%s: detached\n", net->name);
unregister_netdev(net); unregister_netdev(net);
flush_scheduled_work();
sock_put(sk); sock_put(sk);
skb_queue_purge(&dev->tx_queue);
} }

Просмотреть файл

@ -46,9 +46,6 @@
layering other disciplines. It does not need to do bandwidth layering other disciplines. It does not need to do bandwidth
control either since that can be handled by using token control either since that can be handled by using token
bucket or other rate control. bucket or other rate control.
The simulator is limited by the Linux timer resolution
and will create packet bursts on the HZ boundary (1ms).
*/ */
struct netem_sched_data { struct netem_sched_data {