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

Pull networking changes from David Miller:

 1) Multiply in netfilter IPVS can overflow when calculating destination
    weight.  From Simon Kirby.

 2) Use after free fixes in IPVS from Julian Anastasov.

 3) SFC driver bug fixes from Daniel Pieczko.

 4) Memory leak in pcan_usb_core failure paths, from Alexey Khoroshilov.

 5) Locking and encapsulation fixes to serial line CAN driver, from
    Andrew Naujoks.

 6) Duplex and VF handling fixes to bnx2x driver from Yaniv Rosner,
    Eilon Greenstein, and Ariel Elior.

 7) In lapb, if no other packets are outstanding, T1 timeouts actually
    stall things and no packet gets sent.  Fix from Josselin Costanzi.

 8) ICMP redirects should not make it to the socket error queues, from
    Duan Jiong.

 9) Fix bugs in skge DMA mapping error handling, from Nikulas Patocka.

10) Fix setting of VLAN priority field on via-rhine driver, from Roget
    Luethi.

11) Fix TX stalls and VLAN promisc programming in be2net driver from
    Ajit Khaparde.

12) Packet padding doesn't get handled correctly in new usbnet SG
    support code, from Ming Lei.

13) Fix races in netdevice teardown wrt.  network namespace closing.
    From Eric W.  Biederman.

14) Fix potential missed initialization of net_secret if not TCP
    connections are openned.  From Eric Dumazet.

15) Cinterion PLXX product ID in qmi_wwan driver is wrong, from
    Aleksander Morgado.

16) skb_cow_head() can change skb->data and thus packet header pointers,
    don't use stale ip_hdr reference in ip_tunnel code.

17) Backend state transition handling fixes in xen-netback, from Paul
    Durrant.

18) Packet offset for AH protocol is handled wrong in flow dissector,
    from Eric Dumazet.

19) Taking down an fq packet scheduler instance can leave stale packets
    in the queues, fix from Eric Dumazet.

20) Fix performance regressions introduced by TCP Small Queues.  From
    Eric Dumazet.

21) IPV6 GRE tunneling code calculates max_headroom incorrectly, from
    Hannes Frederic Sowa.

22) Multicast timer handlers in ipv4 and ipv6 can be the last and final
    reference to the ipv4/ipv6 specific network device state, so use the
    reference put that will check and release the object if the
    reference hits zero.  From Salam Noureddine.

23) Fix memory corruption in ip_tunnel driver, and use skb_push()
    instead of __skb_push() so that similar bugs are less hard to find.
    From Steffen Klassert.

24) Add forgotten hookup of rtnl_ops in SIT and ip6tnl drivers, from
    Nicolas Dichtel.

25) fq scheduler doesn't accurately rate limit in certain circumstances,
    from Eric Dumazet.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (103 commits)
  pkt_sched: fq: rate limiting improvements
  ip6tnl: allow to use rtnl ops on fb tunnel
  sit: allow to use rtnl ops on fb tunnel
  ip_tunnel: Remove double unregister of the fallback device
  ip_tunnel_core: Change __skb_push back to skb_push
  ip_tunnel: Add fallback tunnels to the hash lists
  ip_tunnel: Fix a memory corruption in ip_tunnel_xmit
  qlcnic: Fix SR-IOV configuration
  ll_temac: Reset dma descriptors indexes on ndo_open
  skbuff: size of hole is wrong in a comment
  ipv6 mcast: use in6_dev_put in timer handlers instead of __in6_dev_put
  ipv4 igmp: use in_dev_put in timer handlers instead of __in_dev_put
  ethernet: moxa: fix incorrect placement of __initdata tag
  ipv6: gre: correct calculation of max_headroom
  powerpc/83xx: gianfar_ptp: select 1588 clock source through dts file
  Revert "powerpc/83xx: gianfar_ptp: select 1588 clock source through dts file"
  bonding: Fix broken promiscuity reference counting issue
  tcp: TSQ can use a dynamic limit
  dm9601: fix IFF_ALLMULTI handling
  pkt_sched: fq: qdisc dismantle fixes
  ...
This commit is contained in:
Linus Torvalds 2013-10-01 12:58:48 -07:00
commit c31eeaced2
107 changed files with 1305 additions and 849 deletions

View File

@ -86,6 +86,7 @@ General Properties:
Clock Properties: Clock Properties:
- fsl,cksel Timer reference clock source.
- fsl,tclk-period Timer reference clock period in nanoseconds. - fsl,tclk-period Timer reference clock period in nanoseconds.
- fsl,tmr-prsc Prescaler, divides the output clock. - fsl,tmr-prsc Prescaler, divides the output clock.
- fsl,tmr-add Frequency compensation value. - fsl,tmr-add Frequency compensation value.
@ -97,7 +98,7 @@ Clock Properties:
clock. You must choose these carefully for the clock to work right. clock. You must choose these carefully for the clock to work right.
Here is how to figure good values: Here is how to figure good values:
TimerOsc = system clock MHz TimerOsc = selected reference clock MHz
tclk_period = desired clock period nanoseconds tclk_period = desired clock period nanoseconds
NominalFreq = 1000 / tclk_period MHz NominalFreq = 1000 / tclk_period MHz
FreqDivRatio = TimerOsc / NominalFreq (must be greater that 1.0) FreqDivRatio = TimerOsc / NominalFreq (must be greater that 1.0)
@ -114,6 +115,20 @@ Clock Properties:
Pulse Per Second (PPS) signal, since this will be offered to the PPS Pulse Per Second (PPS) signal, since this will be offered to the PPS
subsystem to synchronize the Linux clock. subsystem to synchronize the Linux clock.
Reference clock source is determined by the value, which is holded
in CKSEL bits in TMR_CTRL register. "fsl,cksel" property keeps the
value, which will be directly written in those bits, that is why,
according to reference manual, the next clock sources can be used:
<0> - external high precision timer reference clock (TSEC_TMR_CLK
input is used for this purpose);
<1> - eTSEC system clock;
<2> - eTSEC1 transmit clock;
<3> - RTC clock input.
When this attribute is not used, eTSEC system clock will serve as
IEEE 1588 timer reference clock.
Example: Example:
ptp_clock@24E00 { ptp_clock@24E00 {
@ -121,6 +136,7 @@ Example:
reg = <0x24E00 0xB0>; reg = <0x24E00 0xB0>;
interrupts = <12 0x8 13 0x8>; interrupts = <12 0x8 13 0x8>;
interrupt-parent = < &ipic >; interrupt-parent = < &ipic >;
fsl,cksel = <1>;
fsl,tclk-period = <10>; fsl,tclk-period = <10>;
fsl,tmr-prsc = <100>; fsl,tmr-prsc = <100>;
fsl,tmr-add = <0x999999A4>; fsl,tmr-add = <0x999999A4>;

View File

@ -9378,6 +9378,7 @@ F: arch/arm64/include/asm/xen/
XEN NETWORK BACKEND DRIVER XEN NETWORK BACKEND DRIVER
M: Ian Campbell <ian.campbell@citrix.com> M: Ian Campbell <ian.campbell@citrix.com>
M: Wei Liu <wei.liu2@citrix.com>
L: xen-devel@lists.xenproject.org (moderated for non-subscribers) L: xen-devel@lists.xenproject.org (moderated for non-subscribers)
L: netdev@vger.kernel.org L: netdev@vger.kernel.org
S: Supported S: Supported

View File

@ -210,25 +210,6 @@ static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc)
} }
} }
static void bcma_core_pci_power_save(struct bcma_drv_pci *pc, bool up)
{
u16 data;
if (pc->core->id.rev >= 15 && pc->core->id.rev <= 20) {
data = up ? 0x74 : 0x7C;
bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
BCMA_CORE_PCI_MDIO_BLK1_MGMT1, 0x7F64);
bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
BCMA_CORE_PCI_MDIO_BLK1_MGMT3, data);
} else if (pc->core->id.rev >= 21 && pc->core->id.rev <= 22) {
data = up ? 0x75 : 0x7D;
bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
BCMA_CORE_PCI_MDIO_BLK1_MGMT1, 0x7E65);
bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
BCMA_CORE_PCI_MDIO_BLK1_MGMT3, data);
}
}
/************************************************** /**************************************************
* Init. * Init.
**************************************************/ **************************************************/
@ -255,6 +236,32 @@ void bcma_core_pci_init(struct bcma_drv_pci *pc)
bcma_core_pci_clientmode_init(pc); bcma_core_pci_clientmode_init(pc);
} }
void bcma_core_pci_power_save(struct bcma_bus *bus, bool up)
{
struct bcma_drv_pci *pc;
u16 data;
if (bus->hosttype != BCMA_HOSTTYPE_PCI)
return;
pc = &bus->drv_pci[0];
if (pc->core->id.rev >= 15 && pc->core->id.rev <= 20) {
data = up ? 0x74 : 0x7C;
bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
BCMA_CORE_PCI_MDIO_BLK1_MGMT1, 0x7F64);
bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
BCMA_CORE_PCI_MDIO_BLK1_MGMT3, data);
} else if (pc->core->id.rev >= 21 && pc->core->id.rev <= 22) {
data = up ? 0x75 : 0x7D;
bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
BCMA_CORE_PCI_MDIO_BLK1_MGMT1, 0x7E65);
bcma_pcie_mdio_writeread(pc, BCMA_CORE_PCI_MDIO_BLK1,
BCMA_CORE_PCI_MDIO_BLK1_MGMT3, data);
}
}
EXPORT_SYMBOL_GPL(bcma_core_pci_power_save);
int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
bool enable) bool enable)
{ {
@ -310,8 +317,6 @@ void bcma_core_pci_up(struct bcma_bus *bus)
pc = &bus->drv_pci[0]; pc = &bus->drv_pci[0];
bcma_core_pci_power_save(pc, true);
bcma_core_pci_extend_L1timer(pc, true); bcma_core_pci_extend_L1timer(pc, true);
} }
EXPORT_SYMBOL_GPL(bcma_core_pci_up); EXPORT_SYMBOL_GPL(bcma_core_pci_up);
@ -326,7 +331,5 @@ void bcma_core_pci_down(struct bcma_bus *bus)
pc = &bus->drv_pci[0]; pc = &bus->drv_pci[0];
bcma_core_pci_extend_L1timer(pc, false); bcma_core_pci_extend_L1timer(pc, false);
bcma_core_pci_power_save(pc, false);
} }
EXPORT_SYMBOL_GPL(bcma_core_pci_down); EXPORT_SYMBOL_GPL(bcma_core_pci_down);

View File

@ -85,6 +85,7 @@ static struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x04CA, 0x3008) }, { USB_DEVICE(0x04CA, 0x3008) },
{ USB_DEVICE(0x13d3, 0x3362) }, { USB_DEVICE(0x13d3, 0x3362) },
{ USB_DEVICE(0x0CF3, 0xE004) }, { USB_DEVICE(0x0CF3, 0xE004) },
{ USB_DEVICE(0x0CF3, 0xE005) },
{ USB_DEVICE(0x0930, 0x0219) }, { USB_DEVICE(0x0930, 0x0219) },
{ USB_DEVICE(0x0489, 0xe057) }, { USB_DEVICE(0x0489, 0xe057) },
{ USB_DEVICE(0x13d3, 0x3393) }, { USB_DEVICE(0x13d3, 0x3393) },
@ -126,6 +127,7 @@ static struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },

View File

@ -102,6 +102,7 @@ static struct usb_device_id btusb_table[] = {
/* Broadcom BCM20702A0 */ /* Broadcom BCM20702A0 */
{ USB_DEVICE(0x0b05, 0x17b5) }, { USB_DEVICE(0x0b05, 0x17b5) },
{ USB_DEVICE(0x0b05, 0x17cb) },
{ USB_DEVICE(0x04ca, 0x2003) }, { USB_DEVICE(0x04ca, 0x2003) },
{ USB_DEVICE(0x0489, 0xe042) }, { USB_DEVICE(0x0489, 0xe042) },
{ USB_DEVICE(0x413c, 0x8197) }, { USB_DEVICE(0x413c, 0x8197) },
@ -112,6 +113,9 @@ static struct usb_device_id btusb_table[] = {
/*Broadcom devices with vendor specific id */ /*Broadcom devices with vendor specific id */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) }, { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
/* Belkin F8065bf - Broadcom based */
{ USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
@ -148,6 +152,7 @@ static struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },

View File

@ -1724,6 +1724,7 @@ static int __bond_release_one(struct net_device *bond_dev,
struct bonding *bond = netdev_priv(bond_dev); struct bonding *bond = netdev_priv(bond_dev);
struct slave *slave, *oldcurrent; struct slave *slave, *oldcurrent;
struct sockaddr addr; struct sockaddr addr;
int old_flags = bond_dev->flags;
netdev_features_t old_features = bond_dev->features; netdev_features_t old_features = bond_dev->features;
/* slave is not a slave or master is not master of this slave */ /* slave is not a slave or master is not master of this slave */
@ -1855,12 +1856,18 @@ static int __bond_release_one(struct net_device *bond_dev,
* bond_change_active_slave(..., NULL) * bond_change_active_slave(..., NULL)
*/ */
if (!USES_PRIMARY(bond->params.mode)) { if (!USES_PRIMARY(bond->params.mode)) {
/* unset promiscuity level from slave */ /* unset promiscuity level from slave
if (bond_dev->flags & IFF_PROMISC) * NOTE: The NETDEV_CHANGEADDR call above may change the value
* of the IFF_PROMISC flag in the bond_dev, but we need the
* value of that flag before that change, as that was the value
* when this slave was attached, so we cache at the start of the
* function and use it here. Same goes for ALLMULTI below
*/
if (old_flags & IFF_PROMISC)
dev_set_promiscuity(slave_dev, -1); dev_set_promiscuity(slave_dev, -1);
/* unset allmulti level from slave */ /* unset allmulti level from slave */
if (bond_dev->flags & IFF_ALLMULTI) if (old_flags & IFF_ALLMULTI)
dev_set_allmulti(slave_dev, -1); dev_set_allmulti(slave_dev, -1);
bond_hw_addr_flush(bond_dev, slave_dev); bond_hw_addr_flush(bond_dev, slave_dev);

View File

@ -702,7 +702,6 @@ static int flexcan_chip_start(struct net_device *dev)
{ {
struct flexcan_priv *priv = netdev_priv(dev); struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->base; struct flexcan_regs __iomem *regs = priv->base;
unsigned int i;
int err; int err;
u32 reg_mcr, reg_ctrl; u32 reg_mcr, reg_ctrl;
@ -772,17 +771,6 @@ static int flexcan_chip_start(struct net_device *dev)
netdev_dbg(dev, "%s: writing ctrl=0x%08x", __func__, reg_ctrl); netdev_dbg(dev, "%s: writing ctrl=0x%08x", __func__, reg_ctrl);
flexcan_write(reg_ctrl, &regs->ctrl); flexcan_write(reg_ctrl, &regs->ctrl);
for (i = 0; i < ARRAY_SIZE(regs->cantxfg); i++) {
flexcan_write(0, &regs->cantxfg[i].can_ctrl);
flexcan_write(0, &regs->cantxfg[i].can_id);
flexcan_write(0, &regs->cantxfg[i].data[0]);
flexcan_write(0, &regs->cantxfg[i].data[1]);
/* put MB into rx queue */
flexcan_write(FLEXCAN_MB_CNT_CODE(0x4),
&regs->cantxfg[i].can_ctrl);
}
/* acceptance mask/acceptance code (accept everything) */ /* acceptance mask/acceptance code (accept everything) */
flexcan_write(0x0, &regs->rxgmask); flexcan_write(0x0, &regs->rxgmask);
flexcan_write(0x0, &regs->rx14mask); flexcan_write(0x0, &regs->rx14mask);

View File

@ -76,6 +76,10 @@ MODULE_PARM_DESC(maxdev, "Maximum number of slcan interfaces");
/* maximum rx buffer len: extended CAN frame with timestamp */ /* maximum rx buffer len: extended CAN frame with timestamp */
#define SLC_MTU (sizeof("T1111222281122334455667788EA5F\r")+1) #define SLC_MTU (sizeof("T1111222281122334455667788EA5F\r")+1)
#define SLC_CMD_LEN 1
#define SLC_SFF_ID_LEN 3
#define SLC_EFF_ID_LEN 8
struct slcan { struct slcan {
int magic; int magic;
@ -142,48 +146,64 @@ static void slc_bump(struct slcan *sl)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct can_frame cf; struct can_frame cf;
int i, dlc_pos, tmp; int i, tmp;
unsigned long ultmp; u32 tmpid;
char cmd = sl->rbuff[0]; char *cmd = sl->rbuff;
if ((cmd != 't') && (cmd != 'T') && (cmd != 'r') && (cmd != 'R')) cf.can_id = 0;
return;
if (cmd & 0x20) /* tiny chars 'r' 't' => standard frame format */ switch (*cmd) {
dlc_pos = 4; /* dlc position tiiid */ case 'r':
else cf.can_id = CAN_RTR_FLAG;
dlc_pos = 9; /* dlc position Tiiiiiiiid */ /* fallthrough */
case 't':
if (!((sl->rbuff[dlc_pos] >= '0') && (sl->rbuff[dlc_pos] < '9'))) /* store dlc ASCII value and terminate SFF CAN ID string */
return; cf.can_dlc = sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN];
sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN] = 0;
cf.can_dlc = sl->rbuff[dlc_pos] - '0'; /* get can_dlc from ASCII val */ /* point to payload data behind the dlc */
cmd += SLC_CMD_LEN + SLC_SFF_ID_LEN + 1;
sl->rbuff[dlc_pos] = 0; /* terminate can_id string */ break;
case 'R':
if (kstrtoul(sl->rbuff+1, 16, &ultmp)) cf.can_id = CAN_RTR_FLAG;
return; /* fallthrough */
case 'T':
cf.can_id = ultmp;
if (!(cmd & 0x20)) /* NO tiny chars => extended frame format */
cf.can_id |= CAN_EFF_FLAG; cf.can_id |= CAN_EFF_FLAG;
/* store dlc ASCII value and terminate EFF CAN ID string */
cf.can_dlc = sl->rbuff[SLC_CMD_LEN + SLC_EFF_ID_LEN];
sl->rbuff[SLC_CMD_LEN + SLC_EFF_ID_LEN] = 0;
/* point to payload data behind the dlc */
cmd += SLC_CMD_LEN + SLC_EFF_ID_LEN + 1;
break;
default:
return;
}
if ((cmd | 0x20) == 'r') /* RTR frame */ if (kstrtou32(sl->rbuff + SLC_CMD_LEN, 16, &tmpid))
cf.can_id |= CAN_RTR_FLAG; return;
cf.can_id |= tmpid;
/* get can_dlc from sanitized ASCII value */
if (cf.can_dlc >= '0' && cf.can_dlc < '9')
cf.can_dlc -= '0';
else
return;
*(u64 *) (&cf.data) = 0; /* clear payload */ *(u64 *) (&cf.data) = 0; /* clear payload */
for (i = 0, dlc_pos++; i < cf.can_dlc; i++) { /* RTR frames may have a dlc > 0 but they never have any data bytes */
tmp = hex_to_bin(sl->rbuff[dlc_pos++]); if (!(cf.can_id & CAN_RTR_FLAG)) {
for (i = 0; i < cf.can_dlc; i++) {
tmp = hex_to_bin(*cmd++);
if (tmp < 0) if (tmp < 0)
return; return;
cf.data[i] = (tmp << 4); cf.data[i] = (tmp << 4);
tmp = hex_to_bin(sl->rbuff[dlc_pos++]); tmp = hex_to_bin(*cmd++);
if (tmp < 0) if (tmp < 0)
return; return;
cf.data[i] |= tmp; cf.data[i] |= tmp;
} }
}
skb = dev_alloc_skb(sizeof(struct can_frame) + skb = dev_alloc_skb(sizeof(struct can_frame) +
sizeof(struct can_skb_priv)); sizeof(struct can_skb_priv));
@ -209,7 +229,6 @@ static void slc_bump(struct slcan *sl)
/* parse tty input stream */ /* parse tty input stream */
static void slcan_unesc(struct slcan *sl, unsigned char s) static void slcan_unesc(struct slcan *sl, unsigned char s)
{ {
if ((s == '\r') || (s == '\a')) { /* CR or BEL ends the pdu */ if ((s == '\r') || (s == '\a')) { /* CR or BEL ends the pdu */
if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && if (!test_and_clear_bit(SLF_ERROR, &sl->flags) &&
(sl->rcount > 4)) { (sl->rcount > 4)) {
@ -236,27 +255,46 @@ static void slcan_unesc(struct slcan *sl, unsigned char s)
/* Encapsulate one can_frame and stuff into a TTY queue. */ /* Encapsulate one can_frame and stuff into a TTY queue. */
static void slc_encaps(struct slcan *sl, struct can_frame *cf) static void slc_encaps(struct slcan *sl, struct can_frame *cf)
{ {
int actual, idx, i; int actual, i;
char cmd; unsigned char *pos;
unsigned char *endpos;
canid_t id = cf->can_id;
pos = sl->xbuff;
if (cf->can_id & CAN_RTR_FLAG) if (cf->can_id & CAN_RTR_FLAG)
cmd = 'R'; /* becomes 'r' in standard frame format */ *pos = 'R'; /* becomes 'r' in standard frame format (SFF) */
else else
cmd = 'T'; /* becomes 't' in standard frame format */ *pos = 'T'; /* becomes 't' in standard frame format (SSF) */
if (cf->can_id & CAN_EFF_FLAG) /* determine number of chars for the CAN-identifier */
sprintf(sl->xbuff, "%c%08X%d", cmd, if (cf->can_id & CAN_EFF_FLAG) {
cf->can_id & CAN_EFF_MASK, cf->can_dlc); id &= CAN_EFF_MASK;
else endpos = pos + SLC_EFF_ID_LEN;
sprintf(sl->xbuff, "%c%03X%d", cmd | 0x20, } else {
cf->can_id & CAN_SFF_MASK, cf->can_dlc); *pos |= 0x20; /* convert R/T to lower case for SFF */
id &= CAN_SFF_MASK;
endpos = pos + SLC_SFF_ID_LEN;
}
idx = strlen(sl->xbuff); /* build 3 (SFF) or 8 (EFF) digit CAN identifier */
pos++;
while (endpos >= pos) {
*endpos-- = hex_asc_upper[id & 0xf];
id >>= 4;
}
pos += (cf->can_id & CAN_EFF_FLAG) ? SLC_EFF_ID_LEN : SLC_SFF_ID_LEN;
*pos++ = cf->can_dlc + '0';
/* RTR frames may have a dlc > 0 but they never have any data bytes */
if (!(cf->can_id & CAN_RTR_FLAG)) {
for (i = 0; i < cf->can_dlc; i++) for (i = 0; i < cf->can_dlc; i++)
sprintf(&sl->xbuff[idx + 2*i], "%02X", cf->data[i]); pos = hex_byte_pack_upper(pos, cf->data[i]);
}
strcat(sl->xbuff, "\r"); /* add terminating character */ *pos++ = '\r';
/* Order of next two lines is *very* important. /* Order of next two lines is *very* important.
* When we are sending a little amount of data, * When we are sending a little amount of data,
@ -267,8 +305,8 @@ static void slc_encaps(struct slcan *sl, struct can_frame *cf)
* 14 Oct 1994 Dmitry Gorodchanin. * 14 Oct 1994 Dmitry Gorodchanin.
*/ */
set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
actual = sl->tty->ops->write(sl->tty, sl->xbuff, strlen(sl->xbuff)); actual = sl->tty->ops->write(sl->tty, sl->xbuff, pos - sl->xbuff);
sl->xleft = strlen(sl->xbuff) - actual; sl->xleft = (pos - sl->xbuff) - actual;
sl->xhead = sl->xbuff + actual; sl->xhead = sl->xbuff + actual;
sl->dev->stats.tx_bytes += cf->can_dlc; sl->dev->stats.tx_bytes += cf->can_dlc;
} }
@ -286,11 +324,13 @@ static void slcan_write_wakeup(struct tty_struct *tty)
if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev)) if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev))
return; return;
spin_lock(&sl->lock);
if (sl->xleft <= 0) { if (sl->xleft <= 0) {
/* Now serial buffer is almost free & we can start /* Now serial buffer is almost free & we can start
* transmission of another packet */ * transmission of another packet */
sl->dev->stats.tx_packets++; sl->dev->stats.tx_packets++;
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
spin_unlock(&sl->lock);
netif_wake_queue(sl->dev); netif_wake_queue(sl->dev);
return; return;
} }
@ -298,6 +338,7 @@ static void slcan_write_wakeup(struct tty_struct *tty)
actual = tty->ops->write(tty, sl->xhead, sl->xleft); actual = tty->ops->write(tty, sl->xhead, sl->xleft);
sl->xleft -= actual; sl->xleft -= actual;
sl->xhead += actual; sl->xhead += actual;
spin_unlock(&sl->lock);
} }
/* Send a can_frame to a TTY queue. */ /* Send a can_frame to a TTY queue. */

View File

@ -463,7 +463,7 @@ static int peak_usb_start(struct peak_usb_device *dev)
if (i < PCAN_USB_MAX_TX_URBS) { if (i < PCAN_USB_MAX_TX_URBS) {
if (i == 0) { if (i == 0) {
netdev_err(netdev, "couldn't setup any tx URB\n"); netdev_err(netdev, "couldn't setup any tx URB\n");
return err; goto err_tx;
} }
netdev_warn(netdev, "tx performance may be slow\n"); netdev_warn(netdev, "tx performance may be slow\n");
@ -472,7 +472,7 @@ static int peak_usb_start(struct peak_usb_device *dev)
if (dev->adapter->dev_start) { if (dev->adapter->dev_start) {
err = dev->adapter->dev_start(dev); err = dev->adapter->dev_start(dev);
if (err) if (err)
goto failed; goto err_adapter;
} }
dev->state |= PCAN_USB_STATE_STARTED; dev->state |= PCAN_USB_STATE_STARTED;
@ -481,19 +481,26 @@ static int peak_usb_start(struct peak_usb_device *dev)
if (dev->adapter->dev_set_bus) { if (dev->adapter->dev_set_bus) {
err = dev->adapter->dev_set_bus(dev, 1); err = dev->adapter->dev_set_bus(dev, 1);
if (err) if (err)
goto failed; goto err_adapter;
} }
dev->can.state = CAN_STATE_ERROR_ACTIVE; dev->can.state = CAN_STATE_ERROR_ACTIVE;
return 0; return 0;
failed: err_adapter:
if (err == -ENODEV) if (err == -ENODEV)
netif_device_detach(dev->netdev); netif_device_detach(dev->netdev);
netdev_warn(netdev, "couldn't submit control: %d\n", err); netdev_warn(netdev, "couldn't submit control: %d\n", err);
for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++) {
usb_free_urb(dev->tx_contexts[i].urb);
dev->tx_contexts[i].urb = NULL;
}
err_tx:
usb_kill_anchored_urbs(&dev->rx_submitted);
return err; return err;
} }

View File

@ -2481,8 +2481,7 @@ load_error_cnic2:
load_error_cnic1: load_error_cnic1:
bnx2x_napi_disable_cnic(bp); bnx2x_napi_disable_cnic(bp);
/* Update the number of queues without the cnic queues */ /* Update the number of queues without the cnic queues */
rc = bnx2x_set_real_num_queues(bp, 0); if (bnx2x_set_real_num_queues(bp, 0))
if (rc)
BNX2X_ERR("Unable to set real_num_queues not including cnic\n"); BNX2X_ERR("Unable to set real_num_queues not including cnic\n");
load_error_cnic0: load_error_cnic0:
BNX2X_ERR("CNIC-related load failed\n"); BNX2X_ERR("CNIC-related load failed\n");

View File

@ -175,6 +175,7 @@ typedef int (*read_sfp_module_eeprom_func_p)(struct bnx2x_phy *phy,
#define EDC_MODE_LINEAR 0x0022 #define EDC_MODE_LINEAR 0x0022
#define EDC_MODE_LIMITING 0x0044 #define EDC_MODE_LIMITING 0x0044
#define EDC_MODE_PASSIVE_DAC 0x0055 #define EDC_MODE_PASSIVE_DAC 0x0055
#define EDC_MODE_ACTIVE_DAC 0x0066
/* ETS defines*/ /* ETS defines*/
#define DCBX_INVALID_COS (0xFF) #define DCBX_INVALID_COS (0xFF)
@ -3684,6 +3685,41 @@ static void bnx2x_warpcore_enable_AN_KR2(struct bnx2x_phy *phy,
bnx2x_update_link_attr(params, vars->link_attr_sync); bnx2x_update_link_attr(params, vars->link_attr_sync);
} }
static void bnx2x_disable_kr2(struct link_params *params,
struct link_vars *vars,
struct bnx2x_phy *phy)
{
struct bnx2x *bp = params->bp;
int i;
static struct bnx2x_reg_set reg_set[] = {
/* Step 1 - Program the TX/RX alignment markers */
{MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL5, 0x7690},
{MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL7, 0xe647},
{MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL6, 0xc4f0},
{MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL9, 0x7690},
{MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_RX_CTRL11, 0xe647},
{MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_RX_CTRL10, 0xc4f0},
{MDIO_WC_DEVAD, MDIO_WC_REG_CL73_USERB0_CTRL, 0x000c},
{MDIO_WC_DEVAD, MDIO_WC_REG_CL73_BAM_CTRL1, 0x6000},
{MDIO_WC_DEVAD, MDIO_WC_REG_CL73_BAM_CTRL3, 0x0000},
{MDIO_WC_DEVAD, MDIO_WC_REG_CL73_BAM_CODE_FIELD, 0x0002},
{MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_OUI1, 0x0000},
{MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_OUI2, 0x0af7},
{MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_OUI3, 0x0af7},
{MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_LD_BAM_CODE, 0x0002},
{MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_LD_UD_CODE, 0x0000}
};
DP(NETIF_MSG_LINK, "Disabling 20G-KR2\n");
for (i = 0; i < ARRAY_SIZE(reg_set); i++)
bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
reg_set[i].val);
vars->link_attr_sync &= ~LINK_ATTR_SYNC_KR2_ENABLE;
bnx2x_update_link_attr(params, vars->link_attr_sync);
vars->check_kr2_recovery_cnt = CHECK_KR2_RECOVERY_CNT;
}
static void bnx2x_warpcore_set_lpi_passthrough(struct bnx2x_phy *phy, static void bnx2x_warpcore_set_lpi_passthrough(struct bnx2x_phy *phy,
struct link_params *params) struct link_params *params)
{ {
@ -3715,7 +3751,6 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
struct link_params *params, struct link_params *params,
struct link_vars *vars) { struct link_vars *vars) {
u16 lane, i, cl72_ctrl, an_adv = 0; u16 lane, i, cl72_ctrl, an_adv = 0;
u16 ucode_ver;
struct bnx2x *bp = params->bp; struct bnx2x *bp = params->bp;
static struct bnx2x_reg_set reg_set[] = { static struct bnx2x_reg_set reg_set[] = {
{MDIO_WC_DEVAD, MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7}, {MDIO_WC_DEVAD, MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7},
@ -3806,15 +3841,7 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
/* Advertise pause */ /* Advertise pause */
bnx2x_ext_phy_set_pause(params, phy, vars); bnx2x_ext_phy_set_pause(params, phy, vars);
/* Set KR Autoneg Work-Around flag for Warpcore version older than D108
*/
bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_UC_INFO_B1_VERSION, &ucode_ver);
if (ucode_ver < 0xd108) {
DP(NETIF_MSG_LINK, "Enable AN KR work-around. WC ver:0x%x\n",
ucode_ver);
vars->rx_tx_asic_rst = MAX_KR_LINK_RETRY; vars->rx_tx_asic_rst = MAX_KR_LINK_RETRY;
}
bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD, bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_DIGITAL5_MISC7, 0x100); MDIO_WC_REG_DIGITAL5_MISC7, 0x100);
@ -3838,6 +3865,8 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
bnx2x_set_aer_mmd(params, phy); bnx2x_set_aer_mmd(params, phy);
bnx2x_warpcore_enable_AN_KR2(phy, params, vars); bnx2x_warpcore_enable_AN_KR2(phy, params, vars);
} else {
bnx2x_disable_kr2(params, vars, phy);
} }
/* Enable Autoneg: only on the main lane */ /* Enable Autoneg: only on the main lane */
@ -4347,20 +4376,14 @@ static void bnx2x_warpcore_config_runtime(struct bnx2x_phy *phy,
struct bnx2x *bp = params->bp; struct bnx2x *bp = params->bp;
u32 serdes_net_if; u32 serdes_net_if;
u16 gp_status1 = 0, lnkup = 0, lnkup_kr = 0; u16 gp_status1 = 0, lnkup = 0, lnkup_kr = 0;
u16 lane = bnx2x_get_warpcore_lane(phy, params);
vars->turn_to_run_wc_rt = vars->turn_to_run_wc_rt ? 0 : 1; vars->turn_to_run_wc_rt = vars->turn_to_run_wc_rt ? 0 : 1;
if (!vars->turn_to_run_wc_rt) if (!vars->turn_to_run_wc_rt)
return; return;
/* Return if there is no link partner */
if (!(bnx2x_warpcore_get_sigdet(phy, params))) {
DP(NETIF_MSG_LINK, "bnx2x_warpcore_get_sigdet false\n");
return;
}
if (vars->rx_tx_asic_rst) { if (vars->rx_tx_asic_rst) {
u16 lane = bnx2x_get_warpcore_lane(phy, params);
serdes_net_if = (REG_RD(bp, params->shmem_base + serdes_net_if = (REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region, dev_info. offsetof(struct shmem_region, dev_info.
port_hw_config[params->port].default_cfg)) & port_hw_config[params->port].default_cfg)) &
@ -4375,14 +4398,8 @@ static void bnx2x_warpcore_config_runtime(struct bnx2x_phy *phy,
/*10G KR*/ /*10G KR*/
lnkup_kr = (gp_status1 >> (12+lane)) & 0x1; lnkup_kr = (gp_status1 >> (12+lane)) & 0x1;
DP(NETIF_MSG_LINK,
"gp_status1 0x%x\n", gp_status1);
if (lnkup_kr || lnkup) { if (lnkup_kr || lnkup) {
vars->rx_tx_asic_rst = 0; vars->rx_tx_asic_rst = 0;
DP(NETIF_MSG_LINK,
"link up, rx_tx_asic_rst 0x%x\n",
vars->rx_tx_asic_rst);
} else { } else {
/* Reset the lane to see if link comes up.*/ /* Reset the lane to see if link comes up.*/
bnx2x_warpcore_reset_lane(bp, phy, 1); bnx2x_warpcore_reset_lane(bp, phy, 1);
@ -4507,10 +4524,14 @@ static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
* enabled transmitter to avoid current leakage in case * enabled transmitter to avoid current leakage in case
* no module is connected * no module is connected
*/ */
if ((params->loopback_mode == LOOPBACK_NONE) ||
(params->loopback_mode == LOOPBACK_EXT)) {
if (bnx2x_is_sfp_module_plugged(phy, params)) if (bnx2x_is_sfp_module_plugged(phy, params))
bnx2x_sfp_module_detection(phy, params); bnx2x_sfp_module_detection(phy, params);
else else
bnx2x_sfp_e3_set_transmitter(params, phy, 1); bnx2x_sfp_e3_set_transmitter(params,
phy, 1);
}
bnx2x_warpcore_config_sfi(phy, params); bnx2x_warpcore_config_sfi(phy, params);
break; break;
@ -5757,6 +5778,11 @@ static int bnx2x_warpcore_read_status(struct bnx2x_phy *phy,
rc = bnx2x_get_link_speed_duplex(phy, params, vars, link_up, gp_speed, rc = bnx2x_get_link_speed_duplex(phy, params, vars, link_up, gp_speed,
duplex); duplex);
/* In case of KR link down, start up the recovering procedure */
if ((!link_up) && (phy->media_type == ETH_PHY_KR) &&
(!(phy->flags & FLAGS_WC_DUAL_MODE)))
vars->rx_tx_asic_rst = MAX_KR_LINK_RETRY;
DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n", DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n",
vars->duplex, vars->flow_ctrl, vars->link_status); vars->duplex, vars->flow_ctrl, vars->link_status);
return rc; return rc;
@ -6507,6 +6533,11 @@ static int bnx2x_link_initialize(struct link_params *params,
params->phy[INT_PHY].config_init(phy, params, vars); params->phy[INT_PHY].config_init(phy, params, vars);
} }
/* Re-read this value in case it was changed inside config_init due to
* limitations of optic module
*/
vars->line_speed = params->phy[INT_PHY].req_line_speed;
/* Init external phy*/ /* Init external phy*/
if (non_ext_phy) { if (non_ext_phy) {
if (params->phy[INT_PHY].supported & if (params->phy[INT_PHY].supported &
@ -8080,6 +8111,9 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
if (copper_module_type & if (copper_module_type &
SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) { SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
DP(NETIF_MSG_LINK, "Active Copper cable detected\n"); DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
*edc_mode = EDC_MODE_ACTIVE_DAC;
else
check_limiting_mode = 1; check_limiting_mode = 1;
} else if (copper_module_type & } else if (copper_module_type &
SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) { SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
@ -8555,6 +8589,7 @@ static void bnx2x_warpcore_set_limiting_mode(struct link_params *params,
mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_DEFAULT; mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_DEFAULT;
break; break;
case EDC_MODE_PASSIVE_DAC: case EDC_MODE_PASSIVE_DAC:
case EDC_MODE_ACTIVE_DAC:
mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_SFP_DAC; mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_SFP_DAC;
break; break;
default: default:
@ -9730,32 +9765,41 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL, MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
an_1000_val); an_1000_val);
/* set 100 speed advertisement */ /* Set 10/100 speed advertisement */
if ((phy->req_line_speed == SPEED_AUTO_NEG) && if (phy->req_line_speed == SPEED_AUTO_NEG) {
(phy->speed_cap_mask & if (phy->speed_cap_mask &
(PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL | PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL) {
PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF))) { /* Enable autoneg and restart autoneg for legacy speeds
an_10_100_val |= (1<<7); */
/* Enable autoneg and restart autoneg for legacy speeds */
autoneg_val |= (1<<9 | 1<<12); autoneg_val |= (1<<9 | 1<<12);
if (phy->req_duplex == DUPLEX_FULL)
an_10_100_val |= (1<<8); an_10_100_val |= (1<<8);
DP(NETIF_MSG_LINK, "Advertising 100M\n"); DP(NETIF_MSG_LINK, "Advertising 100M-FD\n");
} }
/* set 10 speed advertisement */
if (((phy->req_line_speed == SPEED_AUTO_NEG) && if (phy->speed_cap_mask &
(phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF) {
(PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL | /* Enable autoneg and restart autoneg for legacy speeds
PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)) && */
(phy->supported & autoneg_val |= (1<<9 | 1<<12);
(SUPPORTED_10baseT_Half | an_10_100_val |= (1<<7);
SUPPORTED_10baseT_Full)))) { DP(NETIF_MSG_LINK, "Advertising 100M-HD\n");
}
if ((phy->speed_cap_mask &
PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
(phy->supported & SUPPORTED_10baseT_Full)) {
an_10_100_val |= (1<<6);
autoneg_val |= (1<<9 | 1<<12);
DP(NETIF_MSG_LINK, "Advertising 10M-FD\n");
}
if ((phy->speed_cap_mask &
PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF) &&
(phy->supported & SUPPORTED_10baseT_Half)) {
an_10_100_val |= (1<<5); an_10_100_val |= (1<<5);
autoneg_val |= (1<<9 | 1<<12); autoneg_val |= (1<<9 | 1<<12);
if (phy->req_duplex == DUPLEX_FULL) DP(NETIF_MSG_LINK, "Advertising 10M-HD\n");
an_10_100_val |= (1<<6); }
DP(NETIF_MSG_LINK, "Advertising 10M\n");
} }
/* Only 10/100 are allowed to work in FORCE mode */ /* Only 10/100 are allowed to work in FORCE mode */
@ -13432,43 +13476,6 @@ static void bnx2x_sfp_tx_fault_detection(struct bnx2x_phy *phy,
} }
} }
} }
static void bnx2x_disable_kr2(struct link_params *params,
struct link_vars *vars,
struct bnx2x_phy *phy)
{
struct bnx2x *bp = params->bp;
int i;
static struct bnx2x_reg_set reg_set[] = {
/* Step 1 - Program the TX/RX alignment markers */
{MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL5, 0x7690},
{MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL7, 0xe647},
{MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL6, 0xc4f0},
{MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_TX_CTRL9, 0x7690},
{MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_RX_CTRL11, 0xe647},
{MDIO_WC_DEVAD, MDIO_WC_REG_CL82_USERB1_RX_CTRL10, 0xc4f0},
{MDIO_WC_DEVAD, MDIO_WC_REG_CL73_USERB0_CTRL, 0x000c},
{MDIO_WC_DEVAD, MDIO_WC_REG_CL73_BAM_CTRL1, 0x6000},
{MDIO_WC_DEVAD, MDIO_WC_REG_CL73_BAM_CTRL3, 0x0000},
{MDIO_WC_DEVAD, MDIO_WC_REG_CL73_BAM_CODE_FIELD, 0x0002},
{MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_OUI1, 0x0000},
{MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_OUI2, 0x0af7},
{MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_OUI3, 0x0af7},
{MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_LD_BAM_CODE, 0x0002},
{MDIO_WC_DEVAD, MDIO_WC_REG_ETA_CL73_LD_UD_CODE, 0x0000}
};
DP(NETIF_MSG_LINK, "Disabling 20G-KR2\n");
for (i = 0; i < ARRAY_SIZE(reg_set); i++)
bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
reg_set[i].val);
vars->link_attr_sync &= ~LINK_ATTR_SYNC_KR2_ENABLE;
bnx2x_update_link_attr(params, vars->link_attr_sync);
vars->check_kr2_recovery_cnt = CHECK_KR2_RECOVERY_CNT;
/* Restart AN on leading lane */
bnx2x_warpcore_restart_AN_KR(phy, params);
}
static void bnx2x_kr2_recovery(struct link_params *params, static void bnx2x_kr2_recovery(struct link_params *params,
struct link_vars *vars, struct link_vars *vars,
struct bnx2x_phy *phy) struct bnx2x_phy *phy)
@ -13546,6 +13553,8 @@ static void bnx2x_check_kr2_wa(struct link_params *params,
/* Disable KR2 on both lanes */ /* Disable KR2 on both lanes */
DP(NETIF_MSG_LINK, "BP=0x%x, NP=0x%x\n", base_page, next_page); DP(NETIF_MSG_LINK, "BP=0x%x, NP=0x%x\n", base_page, next_page);
bnx2x_disable_kr2(params, vars, phy); bnx2x_disable_kr2(params, vars, phy);
/* Restart AN on leading lane */
bnx2x_warpcore_restart_AN_KR(phy, params);
return; return;
} }
} }

View File

@ -4703,6 +4703,14 @@ bool bnx2x_chk_parity_attn(struct bnx2x *bp, bool *global, bool print)
attn.sig[3] = REG_RD(bp, attn.sig[3] = REG_RD(bp,
MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 + MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 +
port*4); port*4);
/* Since MCP attentions can't be disabled inside the block, we need to
* read AEU registers to see whether they're currently disabled
*/
attn.sig[3] &= ((REG_RD(bp,
!port ? MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0
: MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0) &
MISC_AEU_ENABLE_MCP_PRTY_BITS) |
~MISC_AEU_ENABLE_MCP_PRTY_BITS);
if (!CHIP_IS_E1x(bp)) if (!CHIP_IS_E1x(bp))
attn.sig[4] = REG_RD(bp, attn.sig[4] = REG_RD(bp,
@ -5447,27 +5455,25 @@ static void bnx2x_timer(unsigned long data)
if (IS_PF(bp) && if (IS_PF(bp) &&
!BP_NOMCP(bp)) { !BP_NOMCP(bp)) {
int mb_idx = BP_FW_MB_IDX(bp); int mb_idx = BP_FW_MB_IDX(bp);
u32 drv_pulse; u16 drv_pulse;
u32 mcp_pulse; u16 mcp_pulse;
++bp->fw_drv_pulse_wr_seq; ++bp->fw_drv_pulse_wr_seq;
bp->fw_drv_pulse_wr_seq &= DRV_PULSE_SEQ_MASK; bp->fw_drv_pulse_wr_seq &= DRV_PULSE_SEQ_MASK;
/* TBD - add SYSTEM_TIME */
drv_pulse = bp->fw_drv_pulse_wr_seq; drv_pulse = bp->fw_drv_pulse_wr_seq;
bnx2x_drv_pulse(bp); bnx2x_drv_pulse(bp);
mcp_pulse = (SHMEM_RD(bp, func_mb[mb_idx].mcp_pulse_mb) & mcp_pulse = (SHMEM_RD(bp, func_mb[mb_idx].mcp_pulse_mb) &
MCP_PULSE_SEQ_MASK); MCP_PULSE_SEQ_MASK);
/* The delta between driver pulse and mcp response /* The delta between driver pulse and mcp response
* should be 1 (before mcp response) or 0 (after mcp response) * should not get too big. If the MFW is more than 5 pulses
* behind, we should worry about it enough to generate an error
* log.
*/ */
if ((drv_pulse != mcp_pulse) && if (((drv_pulse - mcp_pulse) & MCP_PULSE_SEQ_MASK) > 5)
(drv_pulse != ((mcp_pulse + 1) & MCP_PULSE_SEQ_MASK))) { BNX2X_ERR("MFW seems hanged: drv_pulse (0x%x) != mcp_pulse (0x%x)\n",
/* someone lost a heartbeat... */
BNX2X_ERR("drv_pulse (0x%x) != mcp_pulse (0x%x)\n",
drv_pulse, mcp_pulse); drv_pulse, mcp_pulse);
} }
}
if (bp->state == BNX2X_STATE_OPEN) if (bp->state == BNX2X_STATE_OPEN)
bnx2x_stats_handle(bp, STATS_EVENT_UPDATE); bnx2x_stats_handle(bp, STATS_EVENT_UPDATE);

View File

@ -1819,7 +1819,7 @@ bnx2x_get_vf_igu_cam_info(struct bnx2x *bp)
fid = GET_FIELD((val), IGU_REG_MAPPING_MEMORY_FID); fid = GET_FIELD((val), IGU_REG_MAPPING_MEMORY_FID);
if (fid & IGU_FID_ENCODE_IS_PF) if (fid & IGU_FID_ENCODE_IS_PF)
current_pf = fid & IGU_FID_PF_NUM_MASK; current_pf = fid & IGU_FID_PF_NUM_MASK;
else if (current_pf == BP_ABS_FUNC(bp)) else if (current_pf == BP_FUNC(bp))
bnx2x_vf_set_igu_info(bp, sb_id, bnx2x_vf_set_igu_info(bp, sb_id,
(fid & IGU_FID_VF_NUM_MASK)); (fid & IGU_FID_VF_NUM_MASK));
DP(BNX2X_MSG_IOV, "%s[%d], igu_sb_id=%d, msix=%d\n", DP(BNX2X_MSG_IOV, "%s[%d], igu_sb_id=%d, msix=%d\n",
@ -3180,6 +3180,7 @@ int bnx2x_enable_sriov(struct bnx2x *bp)
/* set local queue arrays */ /* set local queue arrays */
vf->vfqs = &bp->vfdb->vfqs[qcount]; vf->vfqs = &bp->vfdb->vfqs[qcount];
qcount += vf_sb_count(vf); qcount += vf_sb_count(vf);
bnx2x_iov_static_resc(bp, vf);
} }
/* prepare msix vectors in VF configuration space */ /* prepare msix vectors in VF configuration space */
@ -3187,6 +3188,8 @@ int bnx2x_enable_sriov(struct bnx2x *bp)
bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf_idx)); bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf_idx));
REG_WR(bp, PCICFG_OFFSET + GRC_CONFIG_REG_VF_MSIX_CONTROL, REG_WR(bp, PCICFG_OFFSET + GRC_CONFIG_REG_VF_MSIX_CONTROL,
num_vf_queues); num_vf_queues);
DP(BNX2X_MSG_IOV, "set msix vec num in VF %d cfg space to %d\n",
vf_idx, num_vf_queues);
} }
bnx2x_pretend_func(bp, BP_ABS_FUNC(bp)); bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));

View File

@ -1765,28 +1765,28 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
switch (mbx->first_tlv.tl.type) { switch (mbx->first_tlv.tl.type) {
case CHANNEL_TLV_ACQUIRE: case CHANNEL_TLV_ACQUIRE:
bnx2x_vf_mbx_acquire(bp, vf, mbx); bnx2x_vf_mbx_acquire(bp, vf, mbx);
break; return;
case CHANNEL_TLV_INIT: case CHANNEL_TLV_INIT:
bnx2x_vf_mbx_init_vf(bp, vf, mbx); bnx2x_vf_mbx_init_vf(bp, vf, mbx);
break; return;
case CHANNEL_TLV_SETUP_Q: case CHANNEL_TLV_SETUP_Q:
bnx2x_vf_mbx_setup_q(bp, vf, mbx); bnx2x_vf_mbx_setup_q(bp, vf, mbx);
break; return;
case CHANNEL_TLV_SET_Q_FILTERS: case CHANNEL_TLV_SET_Q_FILTERS:
bnx2x_vf_mbx_set_q_filters(bp, vf, mbx); bnx2x_vf_mbx_set_q_filters(bp, vf, mbx);
break; return;
case CHANNEL_TLV_TEARDOWN_Q: case CHANNEL_TLV_TEARDOWN_Q:
bnx2x_vf_mbx_teardown_q(bp, vf, mbx); bnx2x_vf_mbx_teardown_q(bp, vf, mbx);
break; return;
case CHANNEL_TLV_CLOSE: case CHANNEL_TLV_CLOSE:
bnx2x_vf_mbx_close_vf(bp, vf, mbx); bnx2x_vf_mbx_close_vf(bp, vf, mbx);
break; return;
case CHANNEL_TLV_RELEASE: case CHANNEL_TLV_RELEASE:
bnx2x_vf_mbx_release_vf(bp, vf, mbx); bnx2x_vf_mbx_release_vf(bp, vf, mbx);
break; return;
case CHANNEL_TLV_UPDATE_RSS: case CHANNEL_TLV_UPDATE_RSS:
bnx2x_vf_mbx_update_rss(bp, vf, mbx); bnx2x_vf_mbx_update_rss(bp, vf, mbx);
break; return;
} }
} else { } else {
@ -1802,10 +1802,9 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
for (i = 0; i < 20; i++) for (i = 0; i < 20; i++)
DP_CONT(BNX2X_MSG_IOV, "%x ", DP_CONT(BNX2X_MSG_IOV, "%x ",
mbx->msg->req.tlv_buf_size.tlv_buffer[i]); mbx->msg->req.tlv_buf_size.tlv_buffer[i]);
}
/* test whether we can respond to the VF (do we have an address /* can we respond to VF (do we have an address for it?) */
* for it?)
*/
if (vf->state == VF_ACQUIRED || vf->state == VF_ENABLED) { if (vf->state == VF_ACQUIRED || vf->state == VF_ENABLED) {
/* mbx_resp uses the op_rc of the VF */ /* mbx_resp uses the op_rc of the VF */
vf->op_rc = PFVF_STATUS_NOT_SUPPORTED; vf->op_rc = PFVF_STATUS_NOT_SUPPORTED;
@ -1818,10 +1817,9 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
* the channel. * the channel.
*/ */
storm_memset_vf_mbx_ack(bp, vf->abs_vfid); storm_memset_vf_mbx_ack(bp, vf->abs_vfid);
/* Firmware ack should be written before unlocking channel */
mmiowb(); mmiowb();
bnx2x_unlock_vf_pf_channel(bp, vf, bnx2x_unlock_vf_pf_channel(bp, vf, mbx->first_tlv.tl.type);
mbx->first_tlv.tl.type);
}
} }
} }

View File

@ -88,6 +88,7 @@ static inline char *nic_name(struct pci_dev *pdev)
#define BE_MIN_MTU 256 #define BE_MIN_MTU 256
#define BE_NUM_VLANS_SUPPORTED 64 #define BE_NUM_VLANS_SUPPORTED 64
#define BE_UMC_NUM_VLANS_SUPPORTED 15
#define BE_MAX_EQD 96u #define BE_MAX_EQD 96u
#define BE_MAX_TX_FRAG_COUNT 30 #define BE_MAX_TX_FRAG_COUNT 30
@ -333,6 +334,7 @@ enum vf_state {
#define BE_FLAGS_LINK_STATUS_INIT 1 #define BE_FLAGS_LINK_STATUS_INIT 1
#define BE_FLAGS_WORKER_SCHEDULED (1 << 3) #define BE_FLAGS_WORKER_SCHEDULED (1 << 3)
#define BE_FLAGS_VLAN_PROMISC (1 << 4)
#define BE_FLAGS_NAPI_ENABLED (1 << 9) #define BE_FLAGS_NAPI_ENABLED (1 << 9)
#define BE_UC_PMAC_COUNT 30 #define BE_UC_PMAC_COUNT 30
#define BE_VF_UC_PMAC_COUNT 2 #define BE_VF_UC_PMAC_COUNT 2

View File

@ -180,6 +180,9 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
dev_err(&adapter->pdev->dev, dev_err(&adapter->pdev->dev,
"opcode %d-%d failed:status %d-%d\n", "opcode %d-%d failed:status %d-%d\n",
opcode, subsystem, compl_status, extd_status); opcode, subsystem, compl_status, extd_status);
if (extd_status == MCC_ADDL_STS_INSUFFICIENT_RESOURCES)
return extd_status;
} }
} }
done: done:
@ -1812,6 +1815,12 @@ int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
} else if (flags & IFF_ALLMULTI) { } else if (flags & IFF_ALLMULTI) {
req->if_flags_mask = req->if_flags = req->if_flags_mask = req->if_flags =
cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS); cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS);
} else if (flags & BE_FLAGS_VLAN_PROMISC) {
req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_VLAN_PROMISCUOUS);
if (value == ON)
req->if_flags =
cpu_to_le32(BE_IF_FLAGS_VLAN_PROMISCUOUS);
} else { } else {
struct netdev_hw_addr *ha; struct netdev_hw_addr *ha;
int i = 0; int i = 0;

View File

@ -60,6 +60,8 @@ enum {
MCC_STATUS_NOT_SUPPORTED = 66 MCC_STATUS_NOT_SUPPORTED = 66
}; };
#define MCC_ADDL_STS_INSUFFICIENT_RESOURCES 0x16
#define CQE_STATUS_COMPL_MASK 0xFFFF #define CQE_STATUS_COMPL_MASK 0xFFFF
#define CQE_STATUS_COMPL_SHIFT 0 /* bits 0 - 15 */ #define CQE_STATUS_COMPL_SHIFT 0 /* bits 0 - 15 */
#define CQE_STATUS_EXTD_MASK 0xFFFF #define CQE_STATUS_EXTD_MASK 0xFFFF
@ -1791,7 +1793,7 @@ struct be_nic_res_desc {
u8 acpi_params; u8 acpi_params;
u8 wol_param; u8 wol_param;
u16 rsvd7; u16 rsvd7;
u32 rsvd8[3]; u32 rsvd8[7];
} __packed; } __packed;
struct be_cmd_req_get_func_config { struct be_cmd_req_get_func_config {

View File

@ -855,11 +855,11 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
unsigned int eth_hdr_len; unsigned int eth_hdr_len;
struct iphdr *ip; struct iphdr *ip;
/* Lancer ASIC has a bug wherein packets that are 32 bytes or less /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or less
* may cause a transmit stall on that port. So the work-around is to * may cause a transmit stall on that port. So the work-around is to
* pad such packets to a 36-byte length. * pad short packets (<= 32 bytes) to a 36-byte length.
*/ */
if (unlikely(lancer_chip(adapter) && skb->len <= 32)) { if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) {
if (skb_padto(skb, 36)) if (skb_padto(skb, 36))
goto tx_drop; goto tx_drop;
skb->len = 36; skb->len = 36;
@ -1013,18 +1013,40 @@ static int be_vid_config(struct be_adapter *adapter)
status = be_cmd_vlan_config(adapter, adapter->if_handle, status = be_cmd_vlan_config(adapter, adapter->if_handle,
vids, num, 1, 0); vids, num, 1, 0);
/* Set to VLAN promisc mode as setting VLAN filter failed */
if (status) { if (status) {
dev_info(&adapter->pdev->dev, "Exhausted VLAN HW filters.\n"); /* Set to VLAN promisc mode as setting VLAN filter failed */
dev_info(&adapter->pdev->dev, "Disabling HW VLAN filtering.\n"); if (status == MCC_ADDL_STS_INSUFFICIENT_RESOURCES)
goto set_vlan_promisc; goto set_vlan_promisc;
dev_err(&adapter->pdev->dev,
"Setting HW VLAN filtering failed.\n");
} else {
if (adapter->flags & BE_FLAGS_VLAN_PROMISC) {
/* hw VLAN filtering re-enabled. */
status = be_cmd_rx_filter(adapter,
BE_FLAGS_VLAN_PROMISC, OFF);
if (!status) {
dev_info(&adapter->pdev->dev,
"Disabling VLAN Promiscuous mode.\n");
adapter->flags &= ~BE_FLAGS_VLAN_PROMISC;
dev_info(&adapter->pdev->dev,
"Re-Enabling HW VLAN filtering\n");
}
}
} }
return status; return status;
set_vlan_promisc: set_vlan_promisc:
status = be_cmd_vlan_config(adapter, adapter->if_handle, dev_warn(&adapter->pdev->dev, "Exhausted VLAN HW filters.\n");
NULL, 0, 1, 1);
status = be_cmd_rx_filter(adapter, BE_FLAGS_VLAN_PROMISC, ON);
if (!status) {
dev_info(&adapter->pdev->dev, "Enable VLAN Promiscuous mode\n");
dev_info(&adapter->pdev->dev, "Disabling HW VLAN filtering\n");
adapter->flags |= BE_FLAGS_VLAN_PROMISC;
} else
dev_err(&adapter->pdev->dev,
"Failed to enable VLAN Promiscuous mode.\n");
return status; return status;
} }
@ -1033,10 +1055,6 @@ static int be_vlan_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
struct be_adapter *adapter = netdev_priv(netdev); struct be_adapter *adapter = netdev_priv(netdev);
int status = 0; int status = 0;
if (!lancer_chip(adapter) && !be_physfn(adapter)) {
status = -EINVAL;
goto ret;
}
/* Packets with VID 0 are always received by Lancer by default */ /* Packets with VID 0 are always received by Lancer by default */
if (lancer_chip(adapter) && vid == 0) if (lancer_chip(adapter) && vid == 0)
@ -1059,11 +1077,6 @@ static int be_vlan_rem_vid(struct net_device *netdev, __be16 proto, u16 vid)
struct be_adapter *adapter = netdev_priv(netdev); struct be_adapter *adapter = netdev_priv(netdev);
int status = 0; int status = 0;
if (!lancer_chip(adapter) && !be_physfn(adapter)) {
status = -EINVAL;
goto ret;
}
/* Packets with VID 0 are always received by Lancer by default */ /* Packets with VID 0 are always received by Lancer by default */
if (lancer_chip(adapter) && vid == 0) if (lancer_chip(adapter) && vid == 0)
goto ret; goto ret;
@ -1188,8 +1201,8 @@ static int be_get_vf_config(struct net_device *netdev, int vf,
vi->vf = vf; vi->vf = vf;
vi->tx_rate = vf_cfg->tx_rate; vi->tx_rate = vf_cfg->tx_rate;
vi->vlan = vf_cfg->vlan_tag; vi->vlan = vf_cfg->vlan_tag & VLAN_VID_MASK;
vi->qos = 0; vi->qos = vf_cfg->vlan_tag >> VLAN_PRIO_SHIFT;
memcpy(&vi->mac, vf_cfg->mac_addr, ETH_ALEN); memcpy(&vi->mac, vf_cfg->mac_addr, ETH_ALEN);
return 0; return 0;
@ -1199,28 +1212,29 @@ static int be_set_vf_vlan(struct net_device *netdev,
int vf, u16 vlan, u8 qos) int vf, u16 vlan, u8 qos)
{ {
struct be_adapter *adapter = netdev_priv(netdev); struct be_adapter *adapter = netdev_priv(netdev);
struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
int status = 0; int status = 0;
if (!sriov_enabled(adapter)) if (!sriov_enabled(adapter))
return -EPERM; return -EPERM;
if (vf >= adapter->num_vfs || vlan > 4095) if (vf >= adapter->num_vfs || vlan > 4095 || qos > 7)
return -EINVAL; return -EINVAL;
if (vlan) { if (vlan || qos) {
if (adapter->vf_cfg[vf].vlan_tag != vlan) { vlan |= qos << VLAN_PRIO_SHIFT;
if (vf_cfg->vlan_tag != vlan) {
/* If this is new value, program it. Else skip. */ /* If this is new value, program it. Else skip. */
adapter->vf_cfg[vf].vlan_tag = vlan; vf_cfg->vlan_tag = vlan;
status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
status = be_cmd_set_hsw_config(adapter, vlan, vf_cfg->if_handle, 0);
vf + 1, adapter->vf_cfg[vf].if_handle, 0);
} }
} else { } else {
/* Reset Transparent Vlan Tagging. */ /* Reset Transparent Vlan Tagging. */
adapter->vf_cfg[vf].vlan_tag = 0; vf_cfg->vlan_tag = 0;
vlan = adapter->vf_cfg[vf].def_vid; vlan = vf_cfg->def_vid;
status = be_cmd_set_hsw_config(adapter, vlan, vf + 1, status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
adapter->vf_cfg[vf].if_handle, 0); vf_cfg->if_handle, 0);
} }
@ -2963,6 +2977,8 @@ static void BEx_get_resources(struct be_adapter *adapter,
if (adapter->function_mode & FLEX10_MODE) if (adapter->function_mode & FLEX10_MODE)
res->max_vlans = BE_NUM_VLANS_SUPPORTED/8; res->max_vlans = BE_NUM_VLANS_SUPPORTED/8;
else if (adapter->function_mode & UMC_ENABLED)
res->max_vlans = BE_UMC_NUM_VLANS_SUPPORTED;
else else
res->max_vlans = BE_NUM_VLANS_SUPPORTED; res->max_vlans = BE_NUM_VLANS_SUPPORTED;
res->max_mcast_mac = BE_MAX_MC; res->max_mcast_mac = BE_MAX_MC;

View File

@ -452,6 +452,8 @@ static int gianfar_ptp_probe(struct platform_device *dev)
err = -ENODEV; err = -ENODEV;
etsects->caps = ptp_gianfar_caps; etsects->caps = ptp_gianfar_caps;
if (get_of_u32(node, "fsl,cksel", &etsects->cksel))
etsects->cksel = DEFAULT_CKSEL; etsects->cksel = DEFAULT_CKSEL;
if (get_of_u32(node, "fsl,tclk-period", &etsects->tclk_period) || if (get_of_u32(node, "fsl,tclk-period", &etsects->tclk_period) ||

View File

@ -701,8 +701,7 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
details = I40E_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use); details = I40E_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use);
if (cmd_details) { if (cmd_details) {
memcpy(details, cmd_details, *details = *cmd_details;
sizeof(struct i40e_asq_cmd_details));
/* If the cmd_details are defined copy the cookie. The /* If the cmd_details are defined copy the cookie. The
* cpu_to_le32 is not needed here because the data is ignored * cpu_to_le32 is not needed here because the data is ignored
@ -760,7 +759,7 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
desc_on_ring = I40E_ADMINQ_DESC(hw->aq.asq, hw->aq.asq.next_to_use); desc_on_ring = I40E_ADMINQ_DESC(hw->aq.asq, hw->aq.asq.next_to_use);
/* if the desc is available copy the temp desc to the right place */ /* if the desc is available copy the temp desc to the right place */
memcpy(desc_on_ring, desc, sizeof(struct i40e_aq_desc)); *desc_on_ring = *desc;
/* if buff is not NULL assume indirect command */ /* if buff is not NULL assume indirect command */
if (buff != NULL) { if (buff != NULL) {
@ -807,7 +806,7 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
/* if ready, copy the desc back to temp */ /* if ready, copy the desc back to temp */
if (i40e_asq_done(hw)) { if (i40e_asq_done(hw)) {
memcpy(desc, desc_on_ring, sizeof(struct i40e_aq_desc)); *desc = *desc_on_ring;
if (buff != NULL) if (buff != NULL)
memcpy(buff, dma_buff->va, buff_size); memcpy(buff, dma_buff->va, buff_size);
retval = le16_to_cpu(desc->retval); retval = le16_to_cpu(desc->retval);

View File

@ -507,7 +507,7 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw,
/* save link status information */ /* save link status information */
if (link) if (link)
memcpy(link, hw_link_info, sizeof(struct i40e_link_status)); *link = *hw_link_info;
/* flag cleared so helper functions don't call AQ again */ /* flag cleared so helper functions don't call AQ again */
hw->phy.get_link_info = false; hw->phy.get_link_info = false;

View File

@ -101,10 +101,10 @@ int i40e_allocate_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem,
mem->size = ALIGN(size, alignment); mem->size = ALIGN(size, alignment);
mem->va = dma_zalloc_coherent(&pf->pdev->dev, mem->size, mem->va = dma_zalloc_coherent(&pf->pdev->dev, mem->size,
&mem->pa, GFP_KERNEL); &mem->pa, GFP_KERNEL);
if (mem->va) if (!mem->va)
return 0;
return -ENOMEM; return -ENOMEM;
return 0;
} }
/** /**
@ -136,10 +136,10 @@ int i40e_allocate_virt_mem_d(struct i40e_hw *hw, struct i40e_virt_mem *mem,
mem->size = size; mem->size = size;
mem->va = kzalloc(size, GFP_KERNEL); mem->va = kzalloc(size, GFP_KERNEL);
if (mem->va) if (!mem->va)
return 0;
return -ENOMEM; return -ENOMEM;
return 0;
} }
/** /**
@ -174,8 +174,7 @@ static int i40e_get_lump(struct i40e_pf *pf, struct i40e_lump_tracking *pile,
u16 needed, u16 id) u16 needed, u16 id)
{ {
int ret = -ENOMEM; int ret = -ENOMEM;
int i = 0; int i, j;
int j = 0;
if (!pile || needed == 0 || id >= I40E_PILE_VALID_BIT) { if (!pile || needed == 0 || id >= I40E_PILE_VALID_BIT) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
@ -186,7 +185,7 @@ static int i40e_get_lump(struct i40e_pf *pf, struct i40e_lump_tracking *pile,
/* start the linear search with an imperfect hint */ /* start the linear search with an imperfect hint */
i = pile->search_hint; i = pile->search_hint;
while (i < pile->num_entries && ret < 0) { while (i < pile->num_entries) {
/* skip already allocated entries */ /* skip already allocated entries */
if (pile->list[i] & I40E_PILE_VALID_BIT) { if (pile->list[i] & I40E_PILE_VALID_BIT) {
i++; i++;
@ -205,6 +204,7 @@ static int i40e_get_lump(struct i40e_pf *pf, struct i40e_lump_tracking *pile,
pile->list[i+j] = id | I40E_PILE_VALID_BIT; pile->list[i+j] = id | I40E_PILE_VALID_BIT;
ret = i; ret = i;
pile->search_hint = i + j; pile->search_hint = i + j;
break;
} else { } else {
/* not enough, so skip over it and continue looking */ /* not enough, so skip over it and continue looking */
i += j; i += j;
@ -1388,7 +1388,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
bool add_happened = false; bool add_happened = false;
int filter_list_len = 0; int filter_list_len = 0;
u32 changed_flags = 0; u32 changed_flags = 0;
i40e_status ret = 0; i40e_status aq_ret = 0;
struct i40e_pf *pf; struct i40e_pf *pf;
int num_add = 0; int num_add = 0;
int num_del = 0; int num_del = 0;
@ -1449,28 +1449,28 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
/* flush a full buffer */ /* flush a full buffer */
if (num_del == filter_list_len) { if (num_del == filter_list_len) {
ret = i40e_aq_remove_macvlan(&pf->hw, aq_ret = i40e_aq_remove_macvlan(&pf->hw,
vsi->seid, del_list, num_del, vsi->seid, del_list, num_del,
NULL); NULL);
num_del = 0; num_del = 0;
memset(del_list, 0, sizeof(*del_list)); memset(del_list, 0, sizeof(*del_list));
if (ret) if (aq_ret)
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"ignoring delete macvlan error, err %d, aq_err %d while flushing a full buffer\n", "ignoring delete macvlan error, err %d, aq_err %d while flushing a full buffer\n",
ret, aq_ret,
pf->hw.aq.asq_last_status); pf->hw.aq.asq_last_status);
} }
} }
if (num_del) { if (num_del) {
ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid, aq_ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid,
del_list, num_del, NULL); del_list, num_del, NULL);
num_del = 0; num_del = 0;
if (ret) if (aq_ret)
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"ignoring delete macvlan error, err %d, aq_err %d\n", "ignoring delete macvlan error, err %d, aq_err %d\n",
ret, pf->hw.aq.asq_last_status); aq_ret, pf->hw.aq.asq_last_status);
} }
kfree(del_list); kfree(del_list);
@ -1515,32 +1515,30 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
/* flush a full buffer */ /* flush a full buffer */
if (num_add == filter_list_len) { if (num_add == filter_list_len) {
ret = i40e_aq_add_macvlan(&pf->hw, aq_ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid,
vsi->seid, add_list, num_add,
add_list,
num_add,
NULL); NULL);
num_add = 0; num_add = 0;
if (ret) if (aq_ret)
break; break;
memset(add_list, 0, sizeof(*add_list)); memset(add_list, 0, sizeof(*add_list));
} }
} }
if (num_add) { if (num_add) {
ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid, aq_ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid,
add_list, num_add, NULL); add_list, num_add, NULL);
num_add = 0; num_add = 0;
} }
kfree(add_list); kfree(add_list);
add_list = NULL; add_list = NULL;
if (add_happened && (!ret)) { if (add_happened && (!aq_ret)) {
/* do nothing */; /* do nothing */;
} else if (add_happened && (ret)) { } else if (add_happened && (aq_ret)) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"add filter failed, err %d, aq_err %d\n", "add filter failed, err %d, aq_err %d\n",
ret, pf->hw.aq.asq_last_status); aq_ret, pf->hw.aq.asq_last_status);
if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOSPC) && if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOSPC) &&
!test_bit(__I40E_FILTER_OVERFLOW_PROMISC, !test_bit(__I40E_FILTER_OVERFLOW_PROMISC,
&vsi->state)) { &vsi->state)) {
@ -1556,28 +1554,27 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
if (changed_flags & IFF_ALLMULTI) { if (changed_flags & IFF_ALLMULTI) {
bool cur_multipromisc; bool cur_multipromisc;
cur_multipromisc = !!(vsi->current_netdev_flags & IFF_ALLMULTI); cur_multipromisc = !!(vsi->current_netdev_flags & IFF_ALLMULTI);
ret = i40e_aq_set_vsi_multicast_promiscuous(&vsi->back->hw, aq_ret = i40e_aq_set_vsi_multicast_promiscuous(&vsi->back->hw,
vsi->seid, vsi->seid,
cur_multipromisc, cur_multipromisc,
NULL); NULL);
if (ret) if (aq_ret)
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"set multi promisc failed, err %d, aq_err %d\n", "set multi promisc failed, err %d, aq_err %d\n",
ret, pf->hw.aq.asq_last_status); aq_ret, pf->hw.aq.asq_last_status);
} }
if ((changed_flags & IFF_PROMISC) || promisc_forced_on) { if ((changed_flags & IFF_PROMISC) || promisc_forced_on) {
bool cur_promisc; bool cur_promisc;
cur_promisc = (!!(vsi->current_netdev_flags & IFF_PROMISC) || cur_promisc = (!!(vsi->current_netdev_flags & IFF_PROMISC) ||
test_bit(__I40E_FILTER_OVERFLOW_PROMISC, test_bit(__I40E_FILTER_OVERFLOW_PROMISC,
&vsi->state)); &vsi->state));
ret = i40e_aq_set_vsi_unicast_promiscuous(&vsi->back->hw, aq_ret = i40e_aq_set_vsi_unicast_promiscuous(&vsi->back->hw,
vsi->seid, vsi->seid,
cur_promisc, cur_promisc, NULL);
NULL); if (aq_ret)
if (ret)
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"set uni promisc failed, err %d, aq_err %d\n", "set uni promisc failed, err %d, aq_err %d\n",
ret, pf->hw.aq.asq_last_status); aq_ret, pf->hw.aq.asq_last_status);
} }
clear_bit(__I40E_CONFIG_BUSY, &vsi->state); clear_bit(__I40E_CONFIG_BUSY, &vsi->state);
@ -1790,6 +1787,8 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)
* i40e_vsi_kill_vlan - Remove vsi membership for given vlan * i40e_vsi_kill_vlan - Remove vsi membership for given vlan
* @vsi: the vsi being configured * @vsi: the vsi being configured
* @vid: vlan id to be removed (0 = untagged only , -1 = any) * @vid: vlan id to be removed (0 = untagged only , -1 = any)
*
* Return: 0 on success or negative otherwise
**/ **/
int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid) int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid)
{ {
@ -1863,37 +1862,39 @@ int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid)
* i40e_vlan_rx_add_vid - Add a vlan id filter to HW offload * i40e_vlan_rx_add_vid - Add a vlan id filter to HW offload
* @netdev: network interface to be adjusted * @netdev: network interface to be adjusted
* @vid: vlan id to be added * @vid: vlan id to be added
*
* net_device_ops implementation for adding vlan ids
**/ **/
static int i40e_vlan_rx_add_vid(struct net_device *netdev, static int i40e_vlan_rx_add_vid(struct net_device *netdev,
__always_unused __be16 proto, u16 vid) __always_unused __be16 proto, u16 vid)
{ {
struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_netdev_priv *np = netdev_priv(netdev);
struct i40e_vsi *vsi = np->vsi; struct i40e_vsi *vsi = np->vsi;
int ret; int ret = 0;
if (vid > 4095) if (vid > 4095)
return 0; return -EINVAL;
netdev_info(netdev, "adding %pM vid=%d\n", netdev->dev_addr, vid);
netdev_info(vsi->netdev, "adding %pM vid=%d\n",
netdev->dev_addr, vid);
/* If the network stack called us with vid = 0, we should /* If the network stack called us with vid = 0, we should
* indicate to i40e_vsi_add_vlan() that we want to receive * indicate to i40e_vsi_add_vlan() that we want to receive
* any traffic (i.e. with any vlan tag, or untagged) * any traffic (i.e. with any vlan tag, or untagged)
*/ */
ret = i40e_vsi_add_vlan(vsi, vid ? vid : I40E_VLAN_ANY); ret = i40e_vsi_add_vlan(vsi, vid ? vid : I40E_VLAN_ANY);
if (!ret) { if (!ret && (vid < VLAN_N_VID))
if (vid < VLAN_N_VID)
set_bit(vid, vsi->active_vlans); set_bit(vid, vsi->active_vlans);
}
return 0; return ret;
} }
/** /**
* i40e_vlan_rx_kill_vid - Remove a vlan id filter from HW offload * i40e_vlan_rx_kill_vid - Remove a vlan id filter from HW offload
* @netdev: network interface to be adjusted * @netdev: network interface to be adjusted
* @vid: vlan id to be removed * @vid: vlan id to be removed
*
* net_device_ops implementation for adding vlan ids
**/ **/
static int i40e_vlan_rx_kill_vid(struct net_device *netdev, static int i40e_vlan_rx_kill_vid(struct net_device *netdev,
__always_unused __be16 proto, u16 vid) __always_unused __be16 proto, u16 vid)
@ -1901,15 +1902,16 @@ static int i40e_vlan_rx_kill_vid(struct net_device *netdev,
struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_netdev_priv *np = netdev_priv(netdev);
struct i40e_vsi *vsi = np->vsi; struct i40e_vsi *vsi = np->vsi;
netdev_info(vsi->netdev, "removing %pM vid=%d\n", netdev_info(netdev, "removing %pM vid=%d\n", netdev->dev_addr, vid);
netdev->dev_addr, vid);
/* return code is ignored as there is nothing a user /* return code is ignored as there is nothing a user
* can do about failure to remove and a log message was * can do about failure to remove and a log message was
* already printed from another function * already printed from the other function
*/ */
i40e_vsi_kill_vlan(vsi, vid); i40e_vsi_kill_vlan(vsi, vid);
clear_bit(vid, vsi->active_vlans); clear_bit(vid, vsi->active_vlans);
return 0; return 0;
} }
@ -1936,10 +1938,10 @@ static void i40e_restore_vlan(struct i40e_vsi *vsi)
* @vsi: the vsi being adjusted * @vsi: the vsi being adjusted
* @vid: the vlan id to set as a PVID * @vid: the vlan id to set as a PVID
**/ **/
i40e_status i40e_vsi_add_pvid(struct i40e_vsi *vsi, u16 vid) int i40e_vsi_add_pvid(struct i40e_vsi *vsi, u16 vid)
{ {
struct i40e_vsi_context ctxt; struct i40e_vsi_context ctxt;
i40e_status ret; i40e_status aq_ret;
vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID); vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID);
vsi->info.pvid = cpu_to_le16(vid); vsi->info.pvid = cpu_to_le16(vid);
@ -1948,14 +1950,15 @@ i40e_status i40e_vsi_add_pvid(struct i40e_vsi *vsi, u16 vid)
ctxt.seid = vsi->seid; ctxt.seid = vsi->seid;
memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info)); memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); aq_ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL);
if (ret) { if (aq_ret) {
dev_info(&vsi->back->pdev->dev, dev_info(&vsi->back->pdev->dev,
"%s: update vsi failed, aq_err=%d\n", "%s: update vsi failed, aq_err=%d\n",
__func__, vsi->back->hw.aq.asq_last_status); __func__, vsi->back->hw.aq.asq_last_status);
return -ENOENT;
} }
return ret; return 0;
} }
/** /**
@ -3326,7 +3329,8 @@ static void i40e_pf_unquiesce_all_vsi(struct i40e_pf *pf)
**/ **/
static u8 i40e_dcb_get_num_tc(struct i40e_dcbx_config *dcbcfg) static u8 i40e_dcb_get_num_tc(struct i40e_dcbx_config *dcbcfg)
{ {
int num_tc = 0, i; u8 num_tc = 0;
int i;
/* Scan the ETS Config Priority Table to find /* Scan the ETS Config Priority Table to find
* traffic class enabled for a given priority * traffic class enabled for a given priority
@ -3341,9 +3345,7 @@ static u8 i40e_dcb_get_num_tc(struct i40e_dcbx_config *dcbcfg)
/* Traffic class index starts from zero so /* Traffic class index starts from zero so
* increment to return the actual count * increment to return the actual count
*/ */
num_tc++; return num_tc + 1;
return num_tc;
} }
/** /**
@ -3451,28 +3453,27 @@ static int i40e_vsi_get_bw_info(struct i40e_vsi *vsi)
struct i40e_aqc_query_vsi_bw_config_resp bw_config = {0}; struct i40e_aqc_query_vsi_bw_config_resp bw_config = {0};
struct i40e_pf *pf = vsi->back; struct i40e_pf *pf = vsi->back;
struct i40e_hw *hw = &pf->hw; struct i40e_hw *hw = &pf->hw;
i40e_status aq_ret;
u32 tc_bw_max; u32 tc_bw_max;
int ret;
int i; int i;
/* Get the VSI level BW configuration */ /* Get the VSI level BW configuration */
ret = i40e_aq_query_vsi_bw_config(hw, vsi->seid, &bw_config, NULL); aq_ret = i40e_aq_query_vsi_bw_config(hw, vsi->seid, &bw_config, NULL);
if (ret) { if (aq_ret) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"couldn't get pf vsi bw config, err %d, aq_err %d\n", "couldn't get pf vsi bw config, err %d, aq_err %d\n",
ret, pf->hw.aq.asq_last_status); aq_ret, pf->hw.aq.asq_last_status);
return ret; return -EINVAL;
} }
/* Get the VSI level BW configuration per TC */ /* Get the VSI level BW configuration per TC */
ret = i40e_aq_query_vsi_ets_sla_config(hw, vsi->seid, aq_ret = i40e_aq_query_vsi_ets_sla_config(hw, vsi->seid, &bw_ets_config,
&bw_ets_config,
NULL); NULL);
if (ret) { if (aq_ret) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"couldn't get pf vsi ets bw config, err %d, aq_err %d\n", "couldn't get pf vsi ets bw config, err %d, aq_err %d\n",
ret, pf->hw.aq.asq_last_status); aq_ret, pf->hw.aq.asq_last_status);
return ret; return -EINVAL;
} }
if (bw_config.tc_valid_bits != bw_ets_config.tc_valid_bits) { if (bw_config.tc_valid_bits != bw_ets_config.tc_valid_bits) {
@ -3494,7 +3495,8 @@ static int i40e_vsi_get_bw_info(struct i40e_vsi *vsi)
/* 3 bits out of 4 for each TC */ /* 3 bits out of 4 for each TC */
vsi->bw_ets_max_quanta[i] = (u8)((tc_bw_max >> (i*4)) & 0x7); vsi->bw_ets_max_quanta[i] = (u8)((tc_bw_max >> (i*4)) & 0x7);
} }
return ret;
return 0;
} }
/** /**
@ -3505,30 +3507,30 @@ static int i40e_vsi_get_bw_info(struct i40e_vsi *vsi)
* *
* Returns 0 on success, negative value on failure * Returns 0 on success, negative value on failure
**/ **/
static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc,
u8 enabled_tc,
u8 *bw_share) u8 *bw_share)
{ {
struct i40e_aqc_configure_vsi_tc_bw_data bw_data; struct i40e_aqc_configure_vsi_tc_bw_data bw_data;
int i, ret = 0; i40e_status aq_ret;
int i;
bw_data.tc_valid_bits = enabled_tc; bw_data.tc_valid_bits = enabled_tc;
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
bw_data.tc_bw_credits[i] = bw_share[i]; bw_data.tc_bw_credits[i] = bw_share[i];
ret = i40e_aq_config_vsi_tc_bw(&vsi->back->hw, vsi->seid, aq_ret = i40e_aq_config_vsi_tc_bw(&vsi->back->hw, vsi->seid, &bw_data,
&bw_data, NULL); NULL);
if (ret) { if (aq_ret) {
dev_info(&vsi->back->pdev->dev, dev_info(&vsi->back->pdev->dev,
"%s: AQ command Config VSI BW allocation per TC failed = %d\n", "%s: AQ command Config VSI BW allocation per TC failed = %d\n",
__func__, vsi->back->hw.aq.asq_last_status); __func__, vsi->back->hw.aq.asq_last_status);
return ret; return -EINVAL;
} }
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
vsi->info.qs_handle[i] = bw_data.qs_handles[i]; vsi->info.qs_handle[i] = bw_data.qs_handles[i];
return ret; return 0;
} }
/** /**

View File

@ -1607,6 +1607,9 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter)
igb_write_phy_reg(hw, I347AT4_PAGE_SELECT, 0); igb_write_phy_reg(hw, I347AT4_PAGE_SELECT, 0);
igb_write_phy_reg(hw, PHY_CONTROL, 0x4140); igb_write_phy_reg(hw, PHY_CONTROL, 0x4140);
} }
} else if (hw->phy.type == e1000_phy_82580) {
/* enable MII loopback */
igb_write_phy_reg(hw, I82580_PHY_LBK_CTRL, 0x8041);
} }
/* add small delay to avoid loopback test failure */ /* add small delay to avoid loopback test failure */

View File

@ -3086,13 +3086,16 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
PCI_DMA_FROMDEVICE); PCI_DMA_FROMDEVICE);
skge_rx_reuse(e, skge->rx_buf_size); skge_rx_reuse(e, skge->rx_buf_size);
} else { } else {
struct skge_element ee;
struct sk_buff *nskb; struct sk_buff *nskb;
nskb = netdev_alloc_skb_ip_align(dev, skge->rx_buf_size); nskb = netdev_alloc_skb_ip_align(dev, skge->rx_buf_size);
if (!nskb) if (!nskb)
goto resubmit; goto resubmit;
skb = e->skb; ee = *e;
skb = ee.skb;
prefetch(skb->data); prefetch(skb->data);
if (skge_rx_setup(skge, e, nskb, skge->rx_buf_size) < 0) { if (skge_rx_setup(skge, e, nskb, skge->rx_buf_size) < 0) {
@ -3101,8 +3104,8 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
} }
pci_unmap_single(skge->hw->pdev, pci_unmap_single(skge->hw->pdev,
dma_unmap_addr(e, mapaddr), dma_unmap_addr(&ee, mapaddr),
dma_unmap_len(e, maplen), dma_unmap_len(&ee, maplen),
PCI_DMA_FROMDEVICE); PCI_DMA_FROMDEVICE);
} }

View File

@ -543,7 +543,7 @@ static const struct of_device_id moxart_mac_match[] = {
{ } { }
}; };
struct __initdata platform_driver moxart_mac_driver = { static struct platform_driver moxart_mac_driver = {
.probe = moxart_mac_probe, .probe = moxart_mac_probe,
.remove = moxart_remove, .remove = moxart_remove,
.driver = { .driver = {

View File

@ -1794,3 +1794,11 @@ const struct ethtool_ops qlcnic_sriov_vf_ethtool_ops = {
.set_msglevel = qlcnic_set_msglevel, .set_msglevel = qlcnic_set_msglevel,
.get_msglevel = qlcnic_get_msglevel, .get_msglevel = qlcnic_get_msglevel,
}; };
const struct ethtool_ops qlcnic_ethtool_failed_ops = {
.get_settings = qlcnic_get_settings,
.get_drvinfo = qlcnic_get_drvinfo,
.set_msglevel = qlcnic_set_msglevel,
.get_msglevel = qlcnic_get_msglevel,
.set_dump = qlcnic_set_dump,
};

View File

@ -431,6 +431,9 @@ static void qlcnic_82xx_cancel_idc_work(struct qlcnic_adapter *adapter)
while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
usleep_range(10000, 11000); usleep_range(10000, 11000);
if (!adapter->fw_work.work.func)
return;
cancel_delayed_work_sync(&adapter->fw_work); cancel_delayed_work_sync(&adapter->fw_work);
} }
@ -2275,8 +2278,9 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->portnum = adapter->ahw->pci_func; adapter->portnum = adapter->ahw->pci_func;
err = qlcnic_start_firmware(adapter); err = qlcnic_start_firmware(adapter);
if (err) { if (err) {
dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n"); dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n"
goto err_out_free_hw; "\t\tIf reboot doesn't help, try flashing the card\n");
goto err_out_maintenance_mode;
} }
qlcnic_get_multiq_capability(adapter); qlcnic_get_multiq_capability(adapter);
@ -2408,6 +2412,22 @@ err_out_disable_pdev:
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev); pci_disable_device(pdev);
return err; return err;
err_out_maintenance_mode:
netdev->netdev_ops = &qlcnic_netdev_failed_ops;
SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_failed_ops);
err = register_netdev(netdev);
if (err) {
dev_err(&pdev->dev, "Failed to register net device\n");
qlcnic_clr_all_drv_state(adapter, 0);
goto err_out_free_hw;
}
pci_set_drvdata(pdev, adapter);
qlcnic_add_sysfs(adapter);
return 0;
} }
static void qlcnic_remove(struct pci_dev *pdev) static void qlcnic_remove(struct pci_dev *pdev)
@ -2518,8 +2538,16 @@ static int qlcnic_resume(struct pci_dev *pdev)
static int qlcnic_open(struct net_device *netdev) static int qlcnic_open(struct net_device *netdev)
{ {
struct qlcnic_adapter *adapter = netdev_priv(netdev); struct qlcnic_adapter *adapter = netdev_priv(netdev);
u32 state;
int err; int err;
state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
if (state == QLCNIC_DEV_FAILED || state == QLCNIC_DEV_BADBAD) {
netdev_err(netdev, "%s: Device is in FAILED state\n", __func__);
return -EIO;
}
netif_carrier_off(netdev); netif_carrier_off(netdev);
err = qlcnic_attach(adapter); err = qlcnic_attach(adapter);
@ -3228,6 +3256,13 @@ void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *adapter, u32 key)
return; return;
state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE); state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
if (state == QLCNIC_DEV_FAILED || state == QLCNIC_DEV_BADBAD) {
netdev_err(adapter->netdev, "%s: Device is in FAILED state\n",
__func__);
qlcnic_api_unlock(adapter);
return;
}
if (state == QLCNIC_DEV_READY) { if (state == QLCNIC_DEV_READY) {
QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE, QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,

View File

@ -397,6 +397,7 @@ static int qlcnic_pci_sriov_disable(struct qlcnic_adapter *adapter)
{ {
struct net_device *netdev = adapter->netdev; struct net_device *netdev = adapter->netdev;
rtnl_lock();
if (netif_running(netdev)) if (netif_running(netdev))
__qlcnic_down(adapter, netdev); __qlcnic_down(adapter, netdev);
@ -407,12 +408,15 @@ static int qlcnic_pci_sriov_disable(struct qlcnic_adapter *adapter)
/* After disabling SRIOV re-init the driver in default mode /* After disabling SRIOV re-init the driver in default mode
configure opmode based on op_mode of function configure opmode based on op_mode of function
*/ */
if (qlcnic_83xx_configure_opmode(adapter)) if (qlcnic_83xx_configure_opmode(adapter)) {
rtnl_unlock();
return -EIO; return -EIO;
}
if (netif_running(netdev)) if (netif_running(netdev))
__qlcnic_up(adapter, netdev); __qlcnic_up(adapter, netdev);
rtnl_unlock();
return 0; return 0;
} }
@ -533,6 +537,7 @@ static int qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter, int num_vfs)
return -EIO; return -EIO;
} }
rtnl_lock();
if (netif_running(netdev)) if (netif_running(netdev))
__qlcnic_down(adapter, netdev); __qlcnic_down(adapter, netdev);
@ -555,6 +560,7 @@ static int qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter, int num_vfs)
__qlcnic_up(adapter, netdev); __qlcnic_up(adapter, netdev);
error: error:
rtnl_unlock();
return err; return err;
} }

View File

@ -1272,6 +1272,7 @@ void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
{ {
struct device *dev = &adapter->pdev->dev; struct device *dev = &adapter->pdev->dev;
u32 state;
if (device_create_bin_file(dev, &bin_attr_port_stats)) if (device_create_bin_file(dev, &bin_attr_port_stats))
dev_info(dev, "failed to create port stats sysfs entry"); dev_info(dev, "failed to create port stats sysfs entry");
@ -1285,8 +1286,13 @@ void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
if (device_create_bin_file(dev, &bin_attr_mem)) if (device_create_bin_file(dev, &bin_attr_mem))
dev_info(dev, "failed to create mem sysfs entry\n"); dev_info(dev, "failed to create mem sysfs entry\n");
state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
if (state == QLCNIC_DEV_FAILED || state == QLCNIC_DEV_BADBAD)
return;
if (device_create_bin_file(dev, &bin_attr_pci_config)) if (device_create_bin_file(dev, &bin_attr_pci_config))
dev_info(dev, "failed to create pci config sysfs entry"); dev_info(dev, "failed to create pci config sysfs entry");
if (device_create_file(dev, &dev_attr_beacon)) if (device_create_file(dev, &dev_attr_beacon))
dev_info(dev, "failed to create beacon sysfs entry"); dev_info(dev, "failed to create beacon sysfs entry");
@ -1307,6 +1313,7 @@ void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter) void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
{ {
struct device *dev = &adapter->pdev->dev; struct device *dev = &adapter->pdev->dev;
u32 state;
device_remove_bin_file(dev, &bin_attr_port_stats); device_remove_bin_file(dev, &bin_attr_port_stats);
@ -1315,6 +1322,11 @@ void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
device_remove_file(dev, &dev_attr_diag_mode); device_remove_file(dev, &dev_attr_diag_mode);
device_remove_bin_file(dev, &bin_attr_crb); device_remove_bin_file(dev, &bin_attr_crb);
device_remove_bin_file(dev, &bin_attr_mem); device_remove_bin_file(dev, &bin_attr_mem);
state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
if (state == QLCNIC_DEV_FAILED || state == QLCNIC_DEV_BADBAD)
return;
device_remove_bin_file(dev, &bin_attr_pci_config); device_remove_bin_file(dev, &bin_attr_pci_config);
device_remove_file(dev, &dev_attr_beacon); device_remove_file(dev, &dev_attr_beacon);
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))

View File

@ -740,8 +740,8 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
int i; int i;
if (!mpi_coredump) { if (!mpi_coredump) {
netif_err(qdev, drv, qdev->ndev, "No memory available\n"); netif_err(qdev, drv, qdev->ndev, "No memory allocated\n");
return -ENOMEM; return -EINVAL;
} }
/* Try to get the spinlock, but dont worry if /* Try to get the spinlock, but dont worry if

View File

@ -1274,7 +1274,7 @@ void ql_mpi_reset_work(struct work_struct *work)
return; return;
} }
if (!ql_core_dump(qdev, qdev->mpi_coredump)) { if (qdev->mpi_coredump && !ql_core_dump(qdev, qdev->mpi_coredump)) {
netif_err(qdev, drv, qdev->ndev, "Core is dumped!\n"); netif_err(qdev, drv, qdev->ndev, "Core is dumped!\n");
qdev->core_is_dumped = 1; qdev->core_is_dumped = 1;
queue_delayed_work(qdev->workqueue, queue_delayed_work(qdev->workqueue,

View File

@ -27,10 +27,10 @@
/* A reboot/assertion causes the MCDI status word to be set after the /* A reboot/assertion causes the MCDI status word to be set after the
* command word is set or a REBOOT event is sent. If we notice a reboot * command word is set or a REBOOT event is sent. If we notice a reboot
* via these mechanisms then wait 20ms for the status word to be set. * via these mechanisms then wait 250ms for the status word to be set.
*/ */
#define MCDI_STATUS_DELAY_US 100 #define MCDI_STATUS_DELAY_US 100
#define MCDI_STATUS_DELAY_COUNT 200 #define MCDI_STATUS_DELAY_COUNT 2500
#define MCDI_STATUS_SLEEP_MS \ #define MCDI_STATUS_SLEEP_MS \
(MCDI_STATUS_DELAY_US * MCDI_STATUS_DELAY_COUNT / 1000) (MCDI_STATUS_DELAY_US * MCDI_STATUS_DELAY_COUNT / 1000)
@ -800,9 +800,6 @@ static void efx_mcdi_ev_death(struct efx_nic *efx, int rc)
} else { } else {
int count; int count;
/* Nobody was waiting for an MCDI request, so trigger a reset */
efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
/* Consume the status word since efx_mcdi_rpc_finish() won't */ /* Consume the status word since efx_mcdi_rpc_finish() won't */
for (count = 0; count < MCDI_STATUS_DELAY_COUNT; ++count) { for (count = 0; count < MCDI_STATUS_DELAY_COUNT; ++count) {
if (efx_mcdi_poll_reboot(efx)) if (efx_mcdi_poll_reboot(efx))
@ -810,6 +807,9 @@ static void efx_mcdi_ev_death(struct efx_nic *efx, int rc)
udelay(MCDI_STATUS_DELAY_US); udelay(MCDI_STATUS_DELAY_US);
} }
mcdi->new_epoch = true; mcdi->new_epoch = true;
/* Nobody was waiting for an MCDI request, so trigger a reset */
efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
} }
spin_unlock(&mcdi->iface_lock); spin_unlock(&mcdi->iface_lock);

View File

@ -32,7 +32,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define DRV_NAME "via-rhine" #define DRV_NAME "via-rhine"
#define DRV_VERSION "1.5.0" #define DRV_VERSION "1.5.1"
#define DRV_RELDATE "2010-10-09" #define DRV_RELDATE "2010-10-09"
#include <linux/types.h> #include <linux/types.h>
@ -1704,7 +1704,12 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
if (unlikely(vlan_tx_tag_present(skb))) { if (unlikely(vlan_tx_tag_present(skb))) {
rp->tx_ring[entry].tx_status = cpu_to_le32((vlan_tx_tag_get(skb)) << 16); u16 vid_pcp = vlan_tx_tag_get(skb);
/* drop CFI/DEI bit, register needs VID and PCP */
vid_pcp = (vid_pcp & VLAN_VID_MASK) |
((vid_pcp & VLAN_PRIO_MASK) >> 1);
rp->tx_ring[entry].tx_status = cpu_to_le32((vid_pcp) << 16);
/* request tagging */ /* request tagging */
rp->tx_ring[entry].desc_length |= cpu_to_le32(0x020000); rp->tx_ring[entry].desc_length |= cpu_to_le32(0x020000);
} }

View File

@ -297,6 +297,12 @@ static int temac_dma_bd_init(struct net_device *ndev)
lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1))); lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p); lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
/* Init descriptor indexes */
lp->tx_bd_ci = 0;
lp->tx_bd_next = 0;
lp->tx_bd_tail = 0;
lp->rx_bd_ci = 0;
return 0; return 0;
out: out:

View File

@ -429,11 +429,13 @@ static void slip_write_wakeup(struct tty_struct *tty)
if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev)) if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
return; return;
spin_lock(&sl->lock);
if (sl->xleft <= 0) { if (sl->xleft <= 0) {
/* Now serial buffer is almost free & we can start /* Now serial buffer is almost free & we can start
* transmission of another packet */ * transmission of another packet */
sl->dev->stats.tx_packets++; sl->dev->stats.tx_packets++;
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
spin_unlock(&sl->lock);
sl_unlock(sl); sl_unlock(sl);
return; return;
} }
@ -441,6 +443,7 @@ static void slip_write_wakeup(struct tty_struct *tty)
actual = tty->ops->write(tty, sl->xhead, sl->xleft); actual = tty->ops->write(tty, sl->xhead, sl->xleft);
sl->xleft -= actual; sl->xleft -= actual;
sl->xhead += actual; sl->xhead += actual;
spin_unlock(&sl->lock);
} }
static void sl_tx_timeout(struct net_device *dev) static void sl_tx_timeout(struct net_device *dev)

View File

@ -303,7 +303,7 @@ static void dm9601_set_multicast(struct net_device *net)
rx_ctl |= 0x02; rx_ctl |= 0x02;
} else if (net->flags & IFF_ALLMULTI || } else if (net->flags & IFF_ALLMULTI ||
netdev_mc_count(net) > DM_MAX_MCAST) { netdev_mc_count(net) > DM_MAX_MCAST) {
rx_ctl |= 0x04; rx_ctl |= 0x08;
} else if (!netdev_mc_empty(net)) { } else if (!netdev_mc_empty(net)) {
struct netdev_hw_addr *ha; struct netdev_hw_addr *ha;

View File

@ -714,7 +714,7 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */
{QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */ {QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */
{QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */ {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */
{QMI_FIXED_INTF(0x1e2d, 0x12d1, 4)}, /* Cinterion PLxx */ {QMI_FIXED_INTF(0x1e2d, 0x0060, 4)}, /* Cinterion PLxx */
/* 4. Gobi 1000 devices */ /* 4. Gobi 1000 devices */
{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */

View File

@ -1241,7 +1241,9 @@ static int build_dma_sg(const struct sk_buff *skb, struct urb *urb)
if (num_sgs == 1) if (num_sgs == 1)
return 0; return 0;
urb->sg = kmalloc(num_sgs * sizeof(struct scatterlist), GFP_ATOMIC); /* reserve one for zero packet */
urb->sg = kmalloc((num_sgs + 1) * sizeof(struct scatterlist),
GFP_ATOMIC);
if (!urb->sg) if (!urb->sg)
return -ENOMEM; return -ENOMEM;
@ -1305,7 +1307,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
if (build_dma_sg(skb, urb) < 0) if (build_dma_sg(skb, urb) < 0)
goto drop; goto drop;
} }
entry->length = length = urb->transfer_buffer_length; length = urb->transfer_buffer_length;
/* don't assume the hardware handles USB_ZERO_PACKET /* don't assume the hardware handles USB_ZERO_PACKET
* NOTE: strictly conforming cdc-ether devices should expect * NOTE: strictly conforming cdc-ether devices should expect
@ -1317,15 +1319,18 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
if (length % dev->maxpacket == 0) { if (length % dev->maxpacket == 0) {
if (!(info->flags & FLAG_SEND_ZLP)) { if (!(info->flags & FLAG_SEND_ZLP)) {
if (!(info->flags & FLAG_MULTI_PACKET)) { if (!(info->flags & FLAG_MULTI_PACKET)) {
urb->transfer_buffer_length++; length++;
if (skb_tailroom(skb)) { if (skb_tailroom(skb) && !urb->num_sgs) {
skb->data[skb->len] = 0; skb->data[skb->len] = 0;
__skb_put(skb, 1); __skb_put(skb, 1);
} } else if (urb->num_sgs)
sg_set_buf(&urb->sg[urb->num_sgs++],
dev->padding_pkt, 1);
} }
} else } else
urb->transfer_flags |= URB_ZERO_PACKET; urb->transfer_flags |= URB_ZERO_PACKET;
} }
entry->length = urb->transfer_buffer_length = length;
spin_lock_irqsave(&dev->txq.lock, flags); spin_lock_irqsave(&dev->txq.lock, flags);
retval = usb_autopm_get_interface_async(dev->intf); retval = usb_autopm_get_interface_async(dev->intf);
@ -1509,6 +1514,7 @@ void usbnet_disconnect (struct usb_interface *intf)
usb_kill_urb(dev->interrupt); usb_kill_urb(dev->interrupt);
usb_free_urb(dev->interrupt); usb_free_urb(dev->interrupt);
kfree(dev->padding_pkt);
free_netdev(net); free_netdev(net);
} }
@ -1679,9 +1685,16 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
/* initialize max rx_qlen and tx_qlen */ /* initialize max rx_qlen and tx_qlen */
usbnet_update_max_qlen(dev); usbnet_update_max_qlen(dev);
if (dev->can_dma_sg && !(info->flags & FLAG_SEND_ZLP) &&
!(info->flags & FLAG_MULTI_PACKET)) {
dev->padding_pkt = kzalloc(1, GFP_KERNEL);
if (!dev->padding_pkt)
goto out4;
}
status = register_netdev (net); status = register_netdev (net);
if (status) if (status)
goto out4; goto out5;
netif_info(dev, probe, dev->net, netif_info(dev, probe, dev->net,
"register '%s' at usb-%s-%s, %s, %pM\n", "register '%s' at usb-%s-%s, %s, %pM\n",
udev->dev.driver->name, udev->dev.driver->name,
@ -1699,6 +1712,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
return 0; return 0;
out5:
kfree(dev->padding_pkt);
out4: out4:
usb_free_urb(dev->interrupt); usb_free_urb(dev->interrupt);
out3: out3:

View File

@ -952,8 +952,7 @@ void vxlan_sock_release(struct vxlan_sock *vs)
spin_lock(&vn->sock_lock); spin_lock(&vn->sock_lock);
hlist_del_rcu(&vs->hlist); hlist_del_rcu(&vs->hlist);
smp_wmb(); rcu_assign_sk_user_data(vs->sock->sk, NULL);
vs->sock->sk->sk_user_data = NULL;
vxlan_notify_del_rx_port(sk); vxlan_notify_del_rx_port(sk);
spin_unlock(&vn->sock_lock); spin_unlock(&vn->sock_lock);
@ -1048,8 +1047,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
port = inet_sk(sk)->inet_sport; port = inet_sk(sk)->inet_sport;
smp_read_barrier_depends(); vs = rcu_dereference_sk_user_data(sk);
vs = (struct vxlan_sock *)sk->sk_user_data;
if (!vs) if (!vs)
goto drop; goto drop;
@ -2302,8 +2300,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
atomic_set(&vs->refcnt, 1); atomic_set(&vs->refcnt, 1);
vs->rcv = rcv; vs->rcv = rcv;
vs->data = data; vs->data = data;
smp_wmb(); rcu_assign_sk_user_data(vs->sock->sk, vs);
vs->sock->sk->sk_user_data = vs;
spin_lock(&vn->sock_lock); spin_lock(&vn->sock_lock);
hlist_add_head_rcu(&vs->hlist, vs_head(net, port)); hlist_add_head_rcu(&vs->hlist, vs_head(net, port));

View File

@ -1269,13 +1269,6 @@ static void ath9k_antenna_check(struct ath_softc *sc,
if (!(ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)) if (!(ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB))
return; return;
/*
* All MPDUs in an aggregate will use the same LNA
* as the first MPDU.
*/
if (rs->rs_isaggr && !rs->rs_firstaggr)
return;
/* /*
* Change the default rx antenna if rx diversity * Change the default rx antenna if rx diversity
* chooses the other antenna 3 times in a row. * chooses the other antenna 3 times in a row.

View File

@ -399,6 +399,7 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
tbf->bf_buf_addr = bf->bf_buf_addr; tbf->bf_buf_addr = bf->bf_buf_addr;
memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len); memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
tbf->bf_state = bf->bf_state; tbf->bf_state = bf->bf_state;
tbf->bf_state.stale = false;
return tbf; return tbf;
} }
@ -1389,11 +1390,15 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tid, u16 *ssn) u16 tid, u16 *ssn)
{ {
struct ath_atx_tid *txtid; struct ath_atx_tid *txtid;
struct ath_txq *txq;
struct ath_node *an; struct ath_node *an;
u8 density; u8 density;
an = (struct ath_node *)sta->drv_priv; an = (struct ath_node *)sta->drv_priv;
txtid = ATH_AN_2_TID(an, tid); txtid = ATH_AN_2_TID(an, tid);
txq = txtid->ac->txq;
ath_txq_lock(sc, txq);
/* update ampdu factor/density, they may have changed. This may happen /* update ampdu factor/density, they may have changed. This may happen
* in HT IBSS when a beacon with HT-info is received after the station * in HT IBSS when a beacon with HT-info is received after the station
@ -1417,6 +1422,8 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
memset(txtid->tx_buf, 0, sizeof(txtid->tx_buf)); memset(txtid->tx_buf, 0, sizeof(txtid->tx_buf));
txtid->baw_head = txtid->baw_tail = 0; txtid->baw_head = txtid->baw_tail = 0;
ath_txq_unlock_complete(sc, txq);
return 0; return 0;
} }
@ -1555,8 +1562,10 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
__skb_unlink(bf->bf_mpdu, tid_q); __skb_unlink(bf->bf_mpdu, tid_q);
list_add_tail(&bf->list, &bf_q); list_add_tail(&bf->list, &bf_q);
ath_set_rates(tid->an->vif, tid->an->sta, bf); ath_set_rates(tid->an->vif, tid->an->sta, bf);
if (bf_isampdu(bf)) {
ath_tx_addto_baw(sc, tid, bf); ath_tx_addto_baw(sc, tid, bf);
bf->bf_state.bf_type &= ~BUF_AGGR; bf->bf_state.bf_type &= ~BUF_AGGR;
}
if (bf_tail) if (bf_tail)
bf_tail->bf_next = bf; bf_tail->bf_next = bf;
@ -1950,7 +1959,9 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
if (bf_is_ampdu_not_probing(bf)) if (bf_is_ampdu_not_probing(bf))
txq->axq_ampdu_depth++; txq->axq_ampdu_depth++;
bf = bf->bf_lastbf->bf_next; bf_last = bf->bf_lastbf;
bf = bf_last->bf_next;
bf_last->bf_next = NULL;
} }
} }
} }

View File

@ -464,8 +464,6 @@ static struct sdio_driver brcmf_sdmmc_driver = {
static int brcmf_sdio_pd_probe(struct platform_device *pdev) static int brcmf_sdio_pd_probe(struct platform_device *pdev)
{ {
int ret;
brcmf_dbg(SDIO, "Enter\n"); brcmf_dbg(SDIO, "Enter\n");
brcmfmac_sdio_pdata = pdev->dev.platform_data; brcmfmac_sdio_pdata = pdev->dev.platform_data;
@ -473,11 +471,7 @@ static int brcmf_sdio_pd_probe(struct platform_device *pdev)
if (brcmfmac_sdio_pdata->power_on) if (brcmfmac_sdio_pdata->power_on)
brcmfmac_sdio_pdata->power_on(); brcmfmac_sdio_pdata->power_on();
ret = sdio_register_driver(&brcmf_sdmmc_driver); return 0;
if (ret)
brcmf_err("sdio_register_driver failed: %d\n", ret);
return ret;
} }
static int brcmf_sdio_pd_remove(struct platform_device *pdev) static int brcmf_sdio_pd_remove(struct platform_device *pdev)
@ -500,6 +494,15 @@ static struct platform_driver brcmf_sdio_pd = {
} }
}; };
void brcmf_sdio_register(void)
{
int ret;
ret = sdio_register_driver(&brcmf_sdmmc_driver);
if (ret)
brcmf_err("sdio_register_driver failed: %d\n", ret);
}
void brcmf_sdio_exit(void) void brcmf_sdio_exit(void)
{ {
brcmf_dbg(SDIO, "Enter\n"); brcmf_dbg(SDIO, "Enter\n");
@ -510,18 +513,13 @@ void brcmf_sdio_exit(void)
sdio_unregister_driver(&brcmf_sdmmc_driver); sdio_unregister_driver(&brcmf_sdmmc_driver);
} }
void brcmf_sdio_init(void) void __init brcmf_sdio_init(void)
{ {
int ret; int ret;
brcmf_dbg(SDIO, "Enter\n"); brcmf_dbg(SDIO, "Enter\n");
ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe); ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe);
if (ret == -ENODEV) { if (ret == -ENODEV)
brcmf_dbg(SDIO, "No platform data available, registering without.\n"); brcmf_dbg(SDIO, "No platform data available.\n");
ret = sdio_register_driver(&brcmf_sdmmc_driver);
}
if (ret)
brcmf_err("driver registration failed: %d\n", ret);
} }

View File

@ -156,10 +156,11 @@ extern int brcmf_bus_start(struct device *dev);
#ifdef CONFIG_BRCMFMAC_SDIO #ifdef CONFIG_BRCMFMAC_SDIO
extern void brcmf_sdio_exit(void); extern void brcmf_sdio_exit(void);
extern void brcmf_sdio_init(void); extern void brcmf_sdio_init(void);
extern void brcmf_sdio_register(void);
#endif #endif
#ifdef CONFIG_BRCMFMAC_USB #ifdef CONFIG_BRCMFMAC_USB
extern void brcmf_usb_exit(void); extern void brcmf_usb_exit(void);
extern void brcmf_usb_init(void); extern void brcmf_usb_register(void);
#endif #endif
#endif /* _BRCMF_BUS_H_ */ #endif /* _BRCMF_BUS_H_ */

View File

@ -1231,21 +1231,23 @@ u32 brcmf_get_chip_info(struct brcmf_if *ifp)
return bus->chip << 4 | bus->chiprev; return bus->chip << 4 | bus->chiprev;
} }
static void brcmf_driver_init(struct work_struct *work) static void brcmf_driver_register(struct work_struct *work)
{ {
brcmf_debugfs_init();
#ifdef CONFIG_BRCMFMAC_SDIO #ifdef CONFIG_BRCMFMAC_SDIO
brcmf_sdio_init(); brcmf_sdio_register();
#endif #endif
#ifdef CONFIG_BRCMFMAC_USB #ifdef CONFIG_BRCMFMAC_USB
brcmf_usb_init(); brcmf_usb_register();
#endif #endif
} }
static DECLARE_WORK(brcmf_driver_work, brcmf_driver_init); static DECLARE_WORK(brcmf_driver_work, brcmf_driver_register);
static int __init brcmfmac_module_init(void) static int __init brcmfmac_module_init(void)
{ {
brcmf_debugfs_init();
#ifdef CONFIG_BRCMFMAC_SDIO
brcmf_sdio_init();
#endif
if (!schedule_work(&brcmf_driver_work)) if (!schedule_work(&brcmf_driver_work))
return -EBUSY; return -EBUSY;

View File

@ -1539,7 +1539,7 @@ void brcmf_usb_exit(void)
brcmf_release_fw(&fw_image_list); brcmf_release_fw(&fw_image_list);
} }
void brcmf_usb_init(void) void brcmf_usb_register(void)
{ {
brcmf_dbg(USB, "Enter\n"); brcmf_dbg(USB, "Enter\n");
INIT_LIST_HEAD(&fw_image_list); INIT_LIST_HEAD(&fw_image_list);

View File

@ -457,6 +457,8 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
if (err != 0) if (err != 0)
brcms_err(wl->wlc->hw->d11core, "%s: brcms_up() returned %d\n", brcms_err(wl->wlc->hw->d11core, "%s: brcms_up() returned %d\n",
__func__, err); __func__, err);
bcma_core_pci_power_save(wl->wlc->hw->d11core->bus, true);
return err; return err;
} }
@ -479,6 +481,8 @@ static void brcms_ops_stop(struct ieee80211_hw *hw)
return; return;
} }
bcma_core_pci_power_save(wl->wlc->hw->d11core->bus, false);
/* put driver in down state */ /* put driver in down state */
spin_lock_bh(&wl->lock); spin_lock_bh(&wl->lock);
brcms_down(wl); brcms_down(wl);

View File

@ -42,7 +42,6 @@ struct hwbus_priv {
spinlock_t lock; /* Serialize all bus operations */ spinlock_t lock; /* Serialize all bus operations */
wait_queue_head_t wq; wait_queue_head_t wq;
int claimed; int claimed;
int irq_disabled;
}; };
#define SDIO_TO_SPI_ADDR(addr) ((addr & 0x1f)>>2) #define SDIO_TO_SPI_ADDR(addr) ((addr & 0x1f)>>2)
@ -238,8 +237,6 @@ static irqreturn_t cw1200_spi_irq_handler(int irq, void *dev_id)
struct hwbus_priv *self = dev_id; struct hwbus_priv *self = dev_id;
if (self->core) { if (self->core) {
disable_irq_nosync(self->func->irq);
self->irq_disabled = 1;
cw1200_irq_handler(self->core); cw1200_irq_handler(self->core);
return IRQ_HANDLED; return IRQ_HANDLED;
} else { } else {
@ -253,8 +250,9 @@ static int cw1200_spi_irq_subscribe(struct hwbus_priv *self)
pr_debug("SW IRQ subscribe\n"); pr_debug("SW IRQ subscribe\n");
ret = request_any_context_irq(self->func->irq, cw1200_spi_irq_handler, ret = request_threaded_irq(self->func->irq, NULL,
IRQF_TRIGGER_HIGH, cw1200_spi_irq_handler,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
"cw1200_wlan_irq", self); "cw1200_wlan_irq", self);
if (WARN_ON(ret < 0)) if (WARN_ON(ret < 0))
goto exit; goto exit;
@ -273,22 +271,13 @@ exit:
static int cw1200_spi_irq_unsubscribe(struct hwbus_priv *self) static int cw1200_spi_irq_unsubscribe(struct hwbus_priv *self)
{ {
int ret = 0;
pr_debug("SW IRQ unsubscribe\n"); pr_debug("SW IRQ unsubscribe\n");
disable_irq_wake(self->func->irq); disable_irq_wake(self->func->irq);
free_irq(self->func->irq, self); free_irq(self->func->irq, self);
return 0; return ret;
}
static int cw1200_spi_irq_enable(struct hwbus_priv *self, int enable)
{
/* Disables are handled by the interrupt handler */
if (enable && self->irq_disabled) {
enable_irq(self->func->irq);
self->irq_disabled = 0;
}
return 0;
} }
static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata) static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata)
@ -368,7 +357,6 @@ static struct hwbus_ops cw1200_spi_hwbus_ops = {
.unlock = cw1200_spi_unlock, .unlock = cw1200_spi_unlock,
.align_size = cw1200_spi_align_size, .align_size = cw1200_spi_align_size,
.power_mgmt = cw1200_spi_pm, .power_mgmt = cw1200_spi_pm,
.irq_enable = cw1200_spi_irq_enable,
}; };
/* Probe Function to be called by SPI stack when device is discovered */ /* Probe Function to be called by SPI stack when device is discovered */

View File

@ -485,7 +485,7 @@ int cw1200_load_firmware(struct cw1200_common *priv)
/* Enable interrupt signalling */ /* Enable interrupt signalling */
priv->hwbus_ops->lock(priv->hwbus_priv); priv->hwbus_ops->lock(priv->hwbus_priv);
ret = __cw1200_irq_enable(priv, 2); ret = __cw1200_irq_enable(priv, 1);
priv->hwbus_ops->unlock(priv->hwbus_priv); priv->hwbus_ops->unlock(priv->hwbus_priv);
if (ret < 0) if (ret < 0)
goto unsubscribe; goto unsubscribe;

View File

@ -28,7 +28,6 @@ struct hwbus_ops {
void (*unlock)(struct hwbus_priv *self); void (*unlock)(struct hwbus_priv *self);
size_t (*align_size)(struct hwbus_priv *self, size_t size); size_t (*align_size)(struct hwbus_priv *self, size_t size);
int (*power_mgmt)(struct hwbus_priv *self, bool suspend); int (*power_mgmt)(struct hwbus_priv *self, bool suspend);
int (*irq_enable)(struct hwbus_priv *self, int enable);
}; };
#endif /* CW1200_HWBUS_H */ #endif /* CW1200_HWBUS_H */

View File

@ -273,21 +273,6 @@ int __cw1200_irq_enable(struct cw1200_common *priv, int enable)
u16 val16; u16 val16;
int ret; int ret;
/* We need to do this hack because the SPI layer can sleep on I/O
and the general path involves I/O to the device in interrupt
context.
However, the initial enable call needs to go to the hardware.
We don't worry about shutdown because we do a full reset which
clears the interrupt enabled bits.
*/
if (priv->hwbus_ops->irq_enable) {
ret = priv->hwbus_ops->irq_enable(priv->hwbus_priv, enable);
if (ret || enable < 2)
return ret;
}
if (HIF_8601_SILICON == priv->hw_type) { if (HIF_8601_SILICON == priv->hw_type) {
ret = __cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32); ret = __cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32);
if (ret < 0) { if (ret < 0) {

View File

@ -150,7 +150,7 @@ mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv,
*/ */
int int
mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
struct mwifiex_ra_list_tbl *pra_list, int headroom, struct mwifiex_ra_list_tbl *pra_list,
int ptrindex, unsigned long ra_list_flags) int ptrindex, unsigned long ra_list_flags)
__releases(&priv->wmm.ra_list_spinlock) __releases(&priv->wmm.ra_list_spinlock)
{ {
@ -160,6 +160,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
int pad = 0, ret; int pad = 0, ret;
struct mwifiex_tx_param tx_param; struct mwifiex_tx_param tx_param;
struct txpd *ptx_pd = NULL; struct txpd *ptx_pd = NULL;
int headroom = adapter->iface_type == MWIFIEX_USB ? 0 : INTF_HEADER_LEN;
skb_src = skb_peek(&pra_list->skb_head); skb_src = skb_peek(&pra_list->skb_head);
if (!skb_src) { if (!skb_src) {

View File

@ -26,7 +26,7 @@
int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv, int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv,
struct sk_buff *skb); struct sk_buff *skb);
int mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, int mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
struct mwifiex_ra_list_tbl *ptr, int headroom, struct mwifiex_ra_list_tbl *ptr,
int ptr_index, unsigned long flags) int ptr_index, unsigned long flags)
__releases(&priv->wmm.ra_list_spinlock); __releases(&priv->wmm.ra_list_spinlock);

View File

@ -1155,7 +1155,7 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
uint32_t conditions = le32_to_cpu(phs_cfg->params.hs_config.conditions); uint32_t conditions = le32_to_cpu(phs_cfg->params.hs_config.conditions);
if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE) && if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE) &&
adapter->iface_type == MWIFIEX_SDIO) { adapter->iface_type != MWIFIEX_USB) {
mwifiex_hs_activated_event(priv, true); mwifiex_hs_activated_event(priv, true);
return 0; return 0;
} else { } else {
@ -1167,8 +1167,7 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
} }
if (conditions != HS_CFG_CANCEL) { if (conditions != HS_CFG_CANCEL) {
adapter->is_hs_configured = true; adapter->is_hs_configured = true;
if (adapter->iface_type == MWIFIEX_USB || if (adapter->iface_type == MWIFIEX_USB)
adapter->iface_type == MWIFIEX_PCIE)
mwifiex_hs_activated_event(priv, true); mwifiex_hs_activated_event(priv, true);
} else { } else {
adapter->is_hs_configured = false; adapter->is_hs_configured = false;

View File

@ -447,9 +447,6 @@ static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message)
*/ */
adapter->is_suspended = true; adapter->is_suspended = true;
for (i = 0; i < adapter->priv_num; i++)
netif_carrier_off(adapter->priv[i]->netdev);
if (atomic_read(&card->rx_cmd_urb_pending) && card->rx_cmd.urb) if (atomic_read(&card->rx_cmd_urb_pending) && card->rx_cmd.urb)
usb_kill_urb(card->rx_cmd.urb); usb_kill_urb(card->rx_cmd.urb);
@ -509,10 +506,6 @@ static int mwifiex_usb_resume(struct usb_interface *intf)
MWIFIEX_RX_CMD_BUF_SIZE); MWIFIEX_RX_CMD_BUF_SIZE);
} }
for (i = 0; i < adapter->priv_num; i++)
if (adapter->priv[i]->media_connected)
netif_carrier_on(adapter->priv[i]->netdev);
/* Disable Host Sleep */ /* Disable Host Sleep */
if (adapter->hs_activated) if (adapter->hs_activated)
mwifiex_cancel_hs(mwifiex_get_priv(adapter, mwifiex_cancel_hs(mwifiex_get_priv(adapter,

View File

@ -1239,8 +1239,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
if (enable_tx_amsdu && mwifiex_is_amsdu_allowed(priv, tid) && if (enable_tx_amsdu && mwifiex_is_amsdu_allowed(priv, tid) &&
mwifiex_is_11n_aggragation_possible(priv, ptr, mwifiex_is_11n_aggragation_possible(priv, ptr,
adapter->tx_buf_size)) adapter->tx_buf_size))
mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, mwifiex_11n_aggregate_pkt(priv, ptr, ptr_index, flags);
ptr_index, flags);
/* ra_list_spinlock has been freed in /* ra_list_spinlock has been freed in
mwifiex_11n_aggregate_pkt() */ mwifiex_11n_aggregate_pkt() */
else else

View File

@ -83,6 +83,7 @@ static struct usb_device_id p54u_table[] = {
{USB_DEVICE(0x06a9, 0x000e)}, /* Westell 802.11g USB (A90-211WG-01) */ {USB_DEVICE(0x06a9, 0x000e)}, /* Westell 802.11g USB (A90-211WG-01) */
{USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */ {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
{USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */ {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
{USB_DEVICE(0x07aa, 0x0020)}, /* Corega WLUSB2GTST USB */
{USB_DEVICE(0x0803, 0x4310)}, /* Zoom 4410a */ {USB_DEVICE(0x0803, 0x4310)}, /* Zoom 4410a */
{USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */ {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
{USB_DEVICE(0x083a, 0x4531)}, /* T-Com Sinus 154 data II */ {USB_DEVICE(0x083a, 0x4531)}, /* T-Com Sinus 154 data II */
@ -979,6 +980,7 @@ static int p54u_load_firmware(struct ieee80211_hw *dev,
if (err) { if (err) {
dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s " dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
"(%d)!\n", p54u_fwlist[i].fw, err); "(%d)!\n", p54u_fwlist[i].fw, err);
usb_put_dev(udev);
} }
return err; return err;

View File

@ -2057,7 +2057,7 @@ struct rtl_priv {
that it points to the data allocated that it points to the data allocated
beyond this structure like: beyond this structure like:
rtl_pci_priv or rtl_usb_priv */ rtl_pci_priv or rtl_usb_priv */
u8 priv[0]; u8 priv[0] __aligned(sizeof(void *));
}; };
#define rtl_priv(hw) (((struct rtl_priv *)(hw)->priv)) #define rtl_priv(hw) (((struct rtl_priv *)(hw)->priv))

View File

@ -24,6 +24,12 @@
struct backend_info { struct backend_info {
struct xenbus_device *dev; struct xenbus_device *dev;
struct xenvif *vif; struct xenvif *vif;
/* This is the state that will be reflected in xenstore when any
* active hotplug script completes.
*/
enum xenbus_state state;
enum xenbus_state frontend_state; enum xenbus_state frontend_state;
struct xenbus_watch hotplug_status_watch; struct xenbus_watch hotplug_status_watch;
u8 have_hotplug_status_watch:1; u8 have_hotplug_status_watch:1;
@ -136,6 +142,8 @@ static int netback_probe(struct xenbus_device *dev,
if (err) if (err)
goto fail; goto fail;
be->state = XenbusStateInitWait;
/* This kicks hotplug scripts, so do it immediately. */ /* This kicks hotplug scripts, so do it immediately. */
backend_create_xenvif(be); backend_create_xenvif(be);
@ -208,24 +216,113 @@ static void backend_create_xenvif(struct backend_info *be)
kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE); kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
} }
static void backend_disconnect(struct backend_info *be)
static void disconnect_backend(struct xenbus_device *dev)
{ {
struct backend_info *be = dev_get_drvdata(&dev->dev);
if (be->vif) if (be->vif)
xenvif_disconnect(be->vif); xenvif_disconnect(be->vif);
} }
static void destroy_backend(struct xenbus_device *dev) static void backend_connect(struct backend_info *be)
{ {
struct backend_info *be = dev_get_drvdata(&dev->dev); if (be->vif)
connect(be);
}
if (be->vif) { static inline void backend_switch_state(struct backend_info *be,
kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE); enum xenbus_state state)
xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status"); {
xenvif_free(be->vif); struct xenbus_device *dev = be->dev;
be->vif = NULL;
pr_debug("%s -> %s\n", dev->nodename, xenbus_strstate(state));
be->state = state;
/* If we are waiting for a hotplug script then defer the
* actual xenbus state change.
*/
if (!be->have_hotplug_status_watch)
xenbus_switch_state(dev, state);
}
/* Handle backend state transitions:
*
* The backend state starts in InitWait and the following transitions are
* allowed.
*
* InitWait -> Connected
*
* ^ \ |
* | \ |
* | \ |
* | \ |
* | \ |
* | \ |
* | V V
*
* Closed <-> Closing
*
* The state argument specifies the eventual state of the backend and the
* function transitions to that state via the shortest path.
*/
static void set_backend_state(struct backend_info *be,
enum xenbus_state state)
{
while (be->state != state) {
switch (be->state) {
case XenbusStateClosed:
switch (state) {
case XenbusStateInitWait:
case XenbusStateConnected:
pr_info("%s: prepare for reconnect\n",
be->dev->nodename);
backend_switch_state(be, XenbusStateInitWait);
break;
case XenbusStateClosing:
backend_switch_state(be, XenbusStateClosing);
break;
default:
BUG();
}
break;
case XenbusStateInitWait:
switch (state) {
case XenbusStateConnected:
backend_connect(be);
backend_switch_state(be, XenbusStateConnected);
break;
case XenbusStateClosing:
case XenbusStateClosed:
backend_switch_state(be, XenbusStateClosing);
break;
default:
BUG();
}
break;
case XenbusStateConnected:
switch (state) {
case XenbusStateInitWait:
case XenbusStateClosing:
case XenbusStateClosed:
backend_disconnect(be);
backend_switch_state(be, XenbusStateClosing);
break;
default:
BUG();
}
break;
case XenbusStateClosing:
switch (state) {
case XenbusStateInitWait:
case XenbusStateConnected:
case XenbusStateClosed:
backend_switch_state(be, XenbusStateClosed);
break;
default:
BUG();
}
break;
default:
BUG();
}
} }
} }
@ -237,40 +334,33 @@ static void frontend_changed(struct xenbus_device *dev,
{ {
struct backend_info *be = dev_get_drvdata(&dev->dev); struct backend_info *be = dev_get_drvdata(&dev->dev);
pr_debug("frontend state %s\n", xenbus_strstate(frontend_state)); pr_debug("%s -> %s\n", dev->otherend, xenbus_strstate(frontend_state));
be->frontend_state = frontend_state; be->frontend_state = frontend_state;
switch (frontend_state) { switch (frontend_state) {
case XenbusStateInitialising: case XenbusStateInitialising:
if (dev->state == XenbusStateClosed) { set_backend_state(be, XenbusStateInitWait);
pr_info("%s: prepare for reconnect\n", dev->nodename);
xenbus_switch_state(dev, XenbusStateInitWait);
}
break; break;
case XenbusStateInitialised: case XenbusStateInitialised:
break; break;
case XenbusStateConnected: case XenbusStateConnected:
if (dev->state == XenbusStateConnected) set_backend_state(be, XenbusStateConnected);
break;
if (be->vif)
connect(be);
break; break;
case XenbusStateClosing: case XenbusStateClosing:
disconnect_backend(dev); set_backend_state(be, XenbusStateClosing);
xenbus_switch_state(dev, XenbusStateClosing);
break; break;
case XenbusStateClosed: case XenbusStateClosed:
xenbus_switch_state(dev, XenbusStateClosed); set_backend_state(be, XenbusStateClosed);
if (xenbus_dev_is_online(dev)) if (xenbus_dev_is_online(dev))
break; break;
destroy_backend(dev);
/* fall through if not online */ /* fall through if not online */
case XenbusStateUnknown: case XenbusStateUnknown:
set_backend_state(be, XenbusStateClosed);
device_unregister(&dev->dev); device_unregister(&dev->dev);
break; break;
@ -363,7 +453,9 @@ static void hotplug_status_changed(struct xenbus_watch *watch,
if (IS_ERR(str)) if (IS_ERR(str))
return; return;
if (len == sizeof("connected")-1 && !memcmp(str, "connected", len)) { if (len == sizeof("connected")-1 && !memcmp(str, "connected", len)) {
xenbus_switch_state(be->dev, XenbusStateConnected); /* Complete any pending state change */
xenbus_switch_state(be->dev, be->state);
/* Not interested in this watch anymore. */ /* Not interested in this watch anymore. */
unregister_hotplug_status_watch(be); unregister_hotplug_status_watch(be);
} }
@ -393,12 +485,8 @@ static void connect(struct backend_info *be)
err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch, err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch,
hotplug_status_changed, hotplug_status_changed,
"%s/%s", dev->nodename, "hotplug-status"); "%s/%s", dev->nodename, "hotplug-status");
if (err) { if (!err)
/* Switch now, since we can't do a watch. */
xenbus_switch_state(dev, XenbusStateConnected);
} else {
be->have_hotplug_status_watch = 1; be->have_hotplug_status_watch = 1;
}
netif_wake_queue(be->vif->dev); netif_wake_queue(be->vif->dev);
} }

View File

@ -242,6 +242,7 @@ extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc,
struct bcma_device *core, bool enable); struct bcma_device *core, bool enable);
extern void bcma_core_pci_up(struct bcma_bus *bus); extern void bcma_core_pci_up(struct bcma_bus *bus);
extern void bcma_core_pci_down(struct bcma_bus *bus); extern void bcma_core_pci_down(struct bcma_bus *bus);
extern void bcma_core_pci_power_save(struct bcma_bus *bus, bool up);
extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev); extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev);
extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev); extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev);

View File

@ -439,6 +439,17 @@ static inline char *hex_byte_pack(char *buf, u8 byte)
return buf; return buf;
} }
extern const char hex_asc_upper[];
#define hex_asc_upper_lo(x) hex_asc_upper[((x) & 0x0f)]
#define hex_asc_upper_hi(x) hex_asc_upper[((x) & 0xf0) >> 4]
static inline char *hex_byte_pack_upper(char *buf, u8 byte)
{
*buf++ = hex_asc_upper_hi(byte);
*buf++ = hex_asc_upper_lo(byte);
return buf;
}
static inline char * __deprecated pack_hex_byte(char *buf, u8 byte) static inline char * __deprecated pack_hex_byte(char *buf, u8 byte)
{ {
return hex_byte_pack(buf, byte); return hex_byte_pack(buf, byte);

View File

@ -498,7 +498,7 @@ struct sk_buff {
* headers if needed * headers if needed
*/ */
__u8 encapsulation:1; __u8 encapsulation:1;
/* 7/9 bit hole (depending on ndisc_nodetype presence) */ /* 6/8 bit hole (depending on ndisc_nodetype presence) */
kmemcheck_bitfield_end(flags2); kmemcheck_bitfield_end(flags2);
#if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL #if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL

View File

@ -42,6 +42,7 @@ struct usbnet {
struct usb_host_endpoint *status; struct usb_host_endpoint *status;
unsigned maxpacket; unsigned maxpacket;
struct timer_list delay; struct timer_list delay;
const char *padding_pkt;
/* protocol/interface state */ /* protocol/interface state */
struct net_device *net; struct net_device *net;

View File

@ -67,6 +67,10 @@ int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr); int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr);
#endif #endif
bool ipv6_chk_custom_prefix(const struct in6_addr *addr,
const unsigned int prefix_len,
struct net_device *dev);
int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev); int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev);
struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net,

View File

@ -104,6 +104,7 @@ enum {
enum { enum {
HCI_SETUP, HCI_SETUP,
HCI_AUTO_OFF, HCI_AUTO_OFF,
HCI_RFKILLED,
HCI_MGMT, HCI_MGMT,
HCI_PAIRABLE, HCI_PAIRABLE,
HCI_SERVICE_CACHE, HCI_SERVICE_CACHE,

View File

@ -723,8 +723,6 @@ struct ip_vs_dest_dst {
struct rcu_head rcu_head; struct rcu_head rcu_head;
}; };
/* In grace period after removing */
#define IP_VS_DEST_STATE_REMOVING 0x01
/* /*
* The real server destination forwarding entry * The real server destination forwarding entry
* with ip address, port number, and so on. * with ip address, port number, and so on.
@ -742,7 +740,7 @@ struct ip_vs_dest {
atomic_t refcnt; /* reference counter */ atomic_t refcnt; /* reference counter */
struct ip_vs_stats stats; /* statistics */ struct ip_vs_stats stats; /* statistics */
unsigned long state; /* state flags */ unsigned long idle_start; /* start time, jiffies */
/* connection counters and thresholds */ /* connection counters and thresholds */
atomic_t activeconns; /* active connections */ atomic_t activeconns; /* active connections */
@ -756,14 +754,13 @@ struct ip_vs_dest {
struct ip_vs_dest_dst __rcu *dest_dst; /* cached dst info */ struct ip_vs_dest_dst __rcu *dest_dst; /* cached dst info */
/* for virtual service */ /* for virtual service */
struct ip_vs_service *svc; /* service it belongs to */ struct ip_vs_service __rcu *svc; /* service it belongs to */
__u16 protocol; /* which protocol (TCP/UDP) */ __u16 protocol; /* which protocol (TCP/UDP) */
__be16 vport; /* virtual port number */ __be16 vport; /* virtual port number */
union nf_inet_addr vaddr; /* virtual IP address */ union nf_inet_addr vaddr; /* virtual IP address */
__u32 vfwmark; /* firewall mark of service */ __u32 vfwmark; /* firewall mark of service */
struct list_head t_list; /* in dest_trash */ struct list_head t_list; /* in dest_trash */
struct rcu_head rcu_head;
unsigned int in_rs_table:1; /* we are in rs_table */ unsigned int in_rs_table:1; /* we are in rs_table */
}; };
@ -1649,7 +1646,7 @@ static inline void ip_vs_conn_drop_conntrack(struct ip_vs_conn *cp)
/* CONFIG_IP_VS_NFCT */ /* CONFIG_IP_VS_NFCT */
#endif #endif
static inline unsigned int static inline int
ip_vs_dest_conn_overhead(struct ip_vs_dest *dest) ip_vs_dest_conn_overhead(struct ip_vs_dest *dest)
{ {
/* /*

View File

@ -112,6 +112,7 @@ struct mrp_applicant {
struct mrp_application *app; struct mrp_application *app;
struct net_device *dev; struct net_device *dev;
struct timer_list join_timer; struct timer_list join_timer;
struct timer_list periodic_timer;
spinlock_t lock; spinlock_t lock;
struct sk_buff_head queue; struct sk_buff_head queue;

View File

@ -74,6 +74,7 @@ struct net {
struct hlist_head *dev_index_head; struct hlist_head *dev_index_head;
unsigned int dev_base_seq; /* protected by rtnl_mutex */ unsigned int dev_base_seq; /* protected by rtnl_mutex */
int ifindex; int ifindex;
unsigned int dev_unreg_count;
/* core fib_rules */ /* core fib_rules */
struct list_head rules_ops; struct list_head rules_ops;

View File

@ -56,7 +56,7 @@ struct synproxy_options {
struct tcphdr; struct tcphdr;
struct xt_synproxy_info; struct xt_synproxy_info;
extern void synproxy_parse_options(const struct sk_buff *skb, unsigned int doff, extern bool synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
const struct tcphdr *th, const struct tcphdr *th,
struct synproxy_options *opts); struct synproxy_options *opts);
extern unsigned int synproxy_options_size(const struct synproxy_options *opts); extern unsigned int synproxy_options_size(const struct synproxy_options *opts);

View File

@ -3,7 +3,6 @@
#include <linux/types.h> #include <linux/types.h>
extern void net_secret_init(void);
extern __u32 secure_ip_id(__be32 daddr); extern __u32 secure_ip_id(__be32 daddr);
extern __u32 secure_ipv6_id(const __be32 daddr[4]); extern __u32 secure_ipv6_id(const __be32 daddr[4]);
extern u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport); extern u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport);

View File

@ -409,6 +409,11 @@ struct sock {
void (*sk_destruct)(struct sock *sk); void (*sk_destruct)(struct sock *sk);
}; };
#define __sk_user_data(sk) ((*((void __rcu **)&(sk)->sk_user_data)))
#define rcu_dereference_sk_user_data(sk) rcu_dereference(__sk_user_data((sk)))
#define rcu_assign_sk_user_data(sk, ptr) rcu_assign_pointer(__sk_user_data((sk)), ptr)
/* /*
* SK_CAN_REUSE and SK_NO_REUSE on a socket mean that the socket is OK * SK_CAN_REUSE and SK_NO_REUSE on a socket mean that the socket is OK
* or not whether his port will be reused by someone else. SK_FORCE_REUSE * or not whether his port will be reused by someone else. SK_FORCE_REUSE

View File

@ -14,6 +14,8 @@
const char hex_asc[] = "0123456789abcdef"; const char hex_asc[] = "0123456789abcdef";
EXPORT_SYMBOL(hex_asc); EXPORT_SYMBOL(hex_asc);
const char hex_asc_upper[] = "0123456789ABCDEF";
EXPORT_SYMBOL(hex_asc_upper);
/** /**
* hex_to_bin - convert a hex digit to its real value * hex_to_bin - convert a hex digit to its real value

View File

@ -24,6 +24,11 @@
static unsigned int mrp_join_time __read_mostly = 200; static unsigned int mrp_join_time __read_mostly = 200;
module_param(mrp_join_time, uint, 0644); module_param(mrp_join_time, uint, 0644);
MODULE_PARM_DESC(mrp_join_time, "Join time in ms (default 200ms)"); MODULE_PARM_DESC(mrp_join_time, "Join time in ms (default 200ms)");
static unsigned int mrp_periodic_time __read_mostly = 1000;
module_param(mrp_periodic_time, uint, 0644);
MODULE_PARM_DESC(mrp_periodic_time, "Periodic time in ms (default 1s)");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static const u8 static const u8
@ -595,6 +600,24 @@ static void mrp_join_timer(unsigned long data)
mrp_join_timer_arm(app); mrp_join_timer_arm(app);
} }
static void mrp_periodic_timer_arm(struct mrp_applicant *app)
{
mod_timer(&app->periodic_timer,
jiffies + msecs_to_jiffies(mrp_periodic_time));
}
static void mrp_periodic_timer(unsigned long data)
{
struct mrp_applicant *app = (struct mrp_applicant *)data;
spin_lock(&app->lock);
mrp_mad_event(app, MRP_EVENT_PERIODIC);
mrp_pdu_queue(app);
spin_unlock(&app->lock);
mrp_periodic_timer_arm(app);
}
static int mrp_pdu_parse_end_mark(struct sk_buff *skb, int *offset) static int mrp_pdu_parse_end_mark(struct sk_buff *skb, int *offset)
{ {
__be16 endmark; __be16 endmark;
@ -845,6 +868,9 @@ int mrp_init_applicant(struct net_device *dev, struct mrp_application *appl)
rcu_assign_pointer(dev->mrp_port->applicants[appl->type], app); rcu_assign_pointer(dev->mrp_port->applicants[appl->type], app);
setup_timer(&app->join_timer, mrp_join_timer, (unsigned long)app); setup_timer(&app->join_timer, mrp_join_timer, (unsigned long)app);
mrp_join_timer_arm(app); mrp_join_timer_arm(app);
setup_timer(&app->periodic_timer, mrp_periodic_timer,
(unsigned long)app);
mrp_periodic_timer_arm(app);
return 0; return 0;
err3: err3:
@ -870,6 +896,7 @@ void mrp_uninit_applicant(struct net_device *dev, struct mrp_application *appl)
* all pending messages before the applicant is gone. * all pending messages before the applicant is gone.
*/ */
del_timer_sync(&app->join_timer); del_timer_sync(&app->join_timer);
del_timer_sync(&app->periodic_timer);
spin_lock_bh(&app->lock); spin_lock_bh(&app->lock);
mrp_mad_event(app, MRP_EVENT_TX); mrp_mad_event(app, MRP_EVENT_TX);

View File

@ -1146,7 +1146,11 @@ int hci_dev_open(__u16 dev)
goto done; goto done;
} }
if (hdev->rfkill && rfkill_blocked(hdev->rfkill)) { /* Check for rfkill but allow the HCI setup stage to proceed
* (which in itself doesn't cause any RF activity).
*/
if (test_bit(HCI_RFKILLED, &hdev->dev_flags) &&
!test_bit(HCI_SETUP, &hdev->dev_flags)) {
ret = -ERFKILL; ret = -ERFKILL;
goto done; goto done;
} }
@ -1566,10 +1570,13 @@ static int hci_rfkill_set_block(void *data, bool blocked)
BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked); BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked);
if (!blocked) if (blocked) {
return 0; set_bit(HCI_RFKILLED, &hdev->dev_flags);
if (!test_bit(HCI_SETUP, &hdev->dev_flags))
hci_dev_do_close(hdev); hci_dev_do_close(hdev);
} else {
clear_bit(HCI_RFKILLED, &hdev->dev_flags);
}
return 0; return 0;
} }
@ -1591,9 +1598,13 @@ static void hci_power_on(struct work_struct *work)
return; return;
} }
if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) if (test_bit(HCI_RFKILLED, &hdev->dev_flags)) {
clear_bit(HCI_AUTO_OFF, &hdev->dev_flags);
hci_dev_do_close(hdev);
} else if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
queue_delayed_work(hdev->req_workqueue, &hdev->power_off, queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
HCI_AUTO_OFF_TIMEOUT); HCI_AUTO_OFF_TIMEOUT);
}
if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags))
mgmt_index_added(hdev); mgmt_index_added(hdev);
@ -2209,6 +2220,9 @@ int hci_register_dev(struct hci_dev *hdev)
} }
} }
if (hdev->rfkill && rfkill_blocked(hdev->rfkill))
set_bit(HCI_RFKILLED, &hdev->dev_flags);
set_bit(HCI_SETUP, &hdev->dev_flags); set_bit(HCI_SETUP, &hdev->dev_flags);
if (hdev->dev_type != HCI_AMP) if (hdev->dev_type != HCI_AMP)

View File

@ -3557,7 +3557,11 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
cp.handle = cpu_to_le16(conn->handle); cp.handle = cpu_to_le16(conn->handle);
if (ltk->authenticated) if (ltk->authenticated)
conn->sec_level = BT_SECURITY_HIGH; conn->pending_sec_level = BT_SECURITY_HIGH;
else
conn->pending_sec_level = BT_SECURITY_MEDIUM;
conn->enc_key_size = ltk->enc_size;
hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp); hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);

View File

@ -3755,6 +3755,13 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
sk = chan->sk; sk = chan->sk;
/* For certain devices (ex: HID mouse), support for authentication,
* pairing and bonding is optional. For such devices, inorder to avoid
* the ACL alive for too long after L2CAP disconnection, reset the ACL
* disc_timeout back to HCI_DISCONN_TIMEOUT during L2CAP connect.
*/
conn->hcon->disc_timeout = HCI_DISCONN_TIMEOUT;
bacpy(&bt_sk(sk)->src, conn->src); bacpy(&bt_sk(sk)->src, conn->src);
bacpy(&bt_sk(sk)->dst, conn->dst); bacpy(&bt_sk(sk)->dst, conn->dst);
chan->psm = psm; chan->psm = psm;

View File

@ -569,7 +569,6 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
{ {
struct rfcomm_dev *dev = dlc->owner; struct rfcomm_dev *dev = dlc->owner;
struct tty_struct *tty;
if (!dev) if (!dev)
return; return;
@ -581,38 +580,8 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
DPM_ORDER_DEV_AFTER_PARENT); DPM_ORDER_DEV_AFTER_PARENT);
wake_up_interruptible(&dev->port.open_wait); wake_up_interruptible(&dev->port.open_wait);
} else if (dlc->state == BT_CLOSED) { } else if (dlc->state == BT_CLOSED)
tty = tty_port_tty_get(&dev->port); tty_port_tty_hangup(&dev->port, false);
if (!tty) {
if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
/* Drop DLC lock here to avoid deadlock
* 1. rfcomm_dev_get will take rfcomm_dev_lock
* but in rfcomm_dev_add there's lock order:
* rfcomm_dev_lock -> dlc lock
* 2. tty_port_put will deadlock if it's
* the last reference
*
* FIXME: when we release the lock anything
* could happen to dev, even its destruction
*/
rfcomm_dlc_unlock(dlc);
if (rfcomm_dev_get(dev->id) == NULL) {
rfcomm_dlc_lock(dlc);
return;
}
if (!test_and_set_bit(RFCOMM_TTY_RELEASED,
&dev->flags))
tty_port_put(&dev->port);
tty_port_put(&dev->port);
rfcomm_dlc_lock(dlc);
}
} else {
tty_hangup(tty);
tty_kref_put(tty);
}
}
} }
static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig) static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)

View File

@ -5247,10 +5247,12 @@ static int dev_new_index(struct net *net)
/* Delayed registration/unregisteration */ /* Delayed registration/unregisteration */
static LIST_HEAD(net_todo_list); static LIST_HEAD(net_todo_list);
static DECLARE_WAIT_QUEUE_HEAD(netdev_unregistering_wq);
static void net_set_todo(struct net_device *dev) static void net_set_todo(struct net_device *dev)
{ {
list_add_tail(&dev->todo_list, &net_todo_list); list_add_tail(&dev->todo_list, &net_todo_list);
dev_net(dev)->dev_unreg_count++;
} }
static void rollback_registered_many(struct list_head *head) static void rollback_registered_many(struct list_head *head)
@ -5918,6 +5920,12 @@ void netdev_run_todo(void)
if (dev->destructor) if (dev->destructor)
dev->destructor(dev); dev->destructor(dev);
/* Report a network device has been unregistered */
rtnl_lock();
dev_net(dev)->dev_unreg_count--;
__rtnl_unlock();
wake_up(&netdev_unregistering_wq);
/* Free network device */ /* Free network device */
kobject_put(&dev->dev.kobj); kobject_put(&dev->dev.kobj);
} }
@ -6603,6 +6611,34 @@ static void __net_exit default_device_exit(struct net *net)
rtnl_unlock(); rtnl_unlock();
} }
static void __net_exit rtnl_lock_unregistering(struct list_head *net_list)
{
/* Return with the rtnl_lock held when there are no network
* devices unregistering in any network namespace in net_list.
*/
struct net *net;
bool unregistering;
DEFINE_WAIT(wait);
for (;;) {
prepare_to_wait(&netdev_unregistering_wq, &wait,
TASK_UNINTERRUPTIBLE);
unregistering = false;
rtnl_lock();
list_for_each_entry(net, net_list, exit_list) {
if (net->dev_unreg_count > 0) {
unregistering = true;
break;
}
}
if (!unregistering)
break;
__rtnl_unlock();
schedule();
}
finish_wait(&netdev_unregistering_wq, &wait);
}
static void __net_exit default_device_exit_batch(struct list_head *net_list) static void __net_exit default_device_exit_batch(struct list_head *net_list)
{ {
/* At exit all network devices most be removed from a network /* At exit all network devices most be removed from a network
@ -6614,7 +6650,18 @@ static void __net_exit default_device_exit_batch(struct list_head *net_list)
struct net *net; struct net *net;
LIST_HEAD(dev_kill_list); LIST_HEAD(dev_kill_list);
rtnl_lock(); /* To prevent network device cleanup code from dereferencing
* loopback devices or network devices that have been freed
* wait here for all pending unregistrations to complete,
* before unregistring the loopback device and allowing the
* network namespace be freed.
*
* The netdev todo list containing all network devices
* unregistrations that happen in default_device_exit_batch
* will run in the rtnl_unlock() at the end of
* default_device_exit_batch.
*/
rtnl_lock_unregistering(net_list);
list_for_each_entry(net, net_list, exit_list) { list_for_each_entry(net, net_list, exit_list) {
for_each_netdev_reverse(net, dev) { for_each_netdev_reverse(net, dev) {
if (dev->rtnl_link_ops) if (dev->rtnl_link_ops)

View File

@ -154,8 +154,8 @@ ipv6:
if (poff >= 0) { if (poff >= 0) {
__be32 *ports, _ports; __be32 *ports, _ports;
nhoff += poff; ports = skb_header_pointer(skb, nhoff + poff,
ports = skb_header_pointer(skb, nhoff, sizeof(_ports), &_ports); sizeof(_ports), &_ports);
if (ports) if (ports)
flow->ports = *ports; flow->ports = *ports;
} }

View File

@ -10,11 +10,24 @@
#include <net/secure_seq.h> #include <net/secure_seq.h>
static u32 net_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned; #define NET_SECRET_SIZE (MD5_MESSAGE_BYTES / 4)
void net_secret_init(void) static u32 net_secret[NET_SECRET_SIZE] ____cacheline_aligned;
static void net_secret_init(void)
{ {
get_random_bytes(net_secret, sizeof(net_secret)); u32 tmp;
int i;
if (likely(net_secret[0]))
return;
for (i = NET_SECRET_SIZE; i > 0;) {
do {
get_random_bytes(&tmp, sizeof(tmp));
} while (!tmp);
cmpxchg(&net_secret[--i], 0, tmp);
}
} }
#ifdef CONFIG_INET #ifdef CONFIG_INET
@ -42,6 +55,7 @@ __u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
u32 hash[MD5_DIGEST_WORDS]; u32 hash[MD5_DIGEST_WORDS];
u32 i; u32 i;
net_secret_init();
memcpy(hash, saddr, 16); memcpy(hash, saddr, 16);
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
secret[i] = net_secret[i] + (__force u32)daddr[i]; secret[i] = net_secret[i] + (__force u32)daddr[i];
@ -63,6 +77,7 @@ u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
u32 hash[MD5_DIGEST_WORDS]; u32 hash[MD5_DIGEST_WORDS];
u32 i; u32 i;
net_secret_init();
memcpy(hash, saddr, 16); memcpy(hash, saddr, 16);
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
secret[i] = net_secret[i] + (__force u32) daddr[i]; secret[i] = net_secret[i] + (__force u32) daddr[i];
@ -82,6 +97,7 @@ __u32 secure_ip_id(__be32 daddr)
{ {
u32 hash[MD5_DIGEST_WORDS]; u32 hash[MD5_DIGEST_WORDS];
net_secret_init();
hash[0] = (__force __u32) daddr; hash[0] = (__force __u32) daddr;
hash[1] = net_secret[13]; hash[1] = net_secret[13];
hash[2] = net_secret[14]; hash[2] = net_secret[14];
@ -96,6 +112,7 @@ __u32 secure_ipv6_id(const __be32 daddr[4])
{ {
__u32 hash[4]; __u32 hash[4];
net_secret_init();
memcpy(hash, daddr, 16); memcpy(hash, daddr, 16);
md5_transform(hash, net_secret); md5_transform(hash, net_secret);
@ -107,6 +124,7 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
{ {
u32 hash[MD5_DIGEST_WORDS]; u32 hash[MD5_DIGEST_WORDS];
net_secret_init();
hash[0] = (__force u32)saddr; hash[0] = (__force u32)saddr;
hash[1] = (__force u32)daddr; hash[1] = (__force u32)daddr;
hash[2] = ((__force u16)sport << 16) + (__force u16)dport; hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
@ -121,6 +139,7 @@ u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
{ {
u32 hash[MD5_DIGEST_WORDS]; u32 hash[MD5_DIGEST_WORDS];
net_secret_init();
hash[0] = (__force u32)saddr; hash[0] = (__force u32)saddr;
hash[1] = (__force u32)daddr; hash[1] = (__force u32)daddr;
hash[2] = (__force u32)dport ^ net_secret[14]; hash[2] = (__force u32)dport ^ net_secret[14];
@ -140,6 +159,7 @@ u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
u32 hash[MD5_DIGEST_WORDS]; u32 hash[MD5_DIGEST_WORDS];
u64 seq; u64 seq;
net_secret_init();
hash[0] = (__force u32)saddr; hash[0] = (__force u32)saddr;
hash[1] = (__force u32)daddr; hash[1] = (__force u32)daddr;
hash[2] = ((__force u16)sport << 16) + (__force u16)dport; hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
@ -164,6 +184,7 @@ u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
u64 seq; u64 seq;
u32 i; u32 i;
net_secret_init();
memcpy(hash, saddr, 16); memcpy(hash, saddr, 16);
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
secret[i] = net_secret[i] + daddr[i]; secret[i] = net_secret[i] + daddr[i];

View File

@ -263,10 +263,8 @@ void build_ehash_secret(void)
get_random_bytes(&rnd, sizeof(rnd)); get_random_bytes(&rnd, sizeof(rnd));
} while (rnd == 0); } while (rnd == 0);
if (cmpxchg(&inet_ehash_secret, 0, rnd) == 0) { if (cmpxchg(&inet_ehash_secret, 0, rnd) == 0)
get_random_bytes(&ipv6_hash_secret, sizeof(ipv6_hash_secret)); get_random_bytes(&ipv6_hash_secret, sizeof(ipv6_hash_secret));
net_secret_init();
}
} }
EXPORT_SYMBOL(build_ehash_secret); EXPORT_SYMBOL(build_ehash_secret);

View File

@ -736,7 +736,7 @@ static void igmp_gq_timer_expire(unsigned long data)
in_dev->mr_gq_running = 0; in_dev->mr_gq_running = 0;
igmpv3_send_report(in_dev, NULL); igmpv3_send_report(in_dev, NULL);
__in_dev_put(in_dev); in_dev_put(in_dev);
} }
static void igmp_ifc_timer_expire(unsigned long data) static void igmp_ifc_timer_expire(unsigned long data)
@ -749,7 +749,7 @@ static void igmp_ifc_timer_expire(unsigned long data)
igmp_ifc_start_timer(in_dev, igmp_ifc_start_timer(in_dev,
unsolicited_report_interval(in_dev)); unsolicited_report_interval(in_dev));
} }
__in_dev_put(in_dev); in_dev_put(in_dev);
} }
static void igmp_ifc_event(struct in_device *in_dev) static void igmp_ifc_event(struct in_device *in_dev)

View File

@ -623,6 +623,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
tunnel->err_count = 0; tunnel->err_count = 0;
} }
tos = ip_tunnel_ecn_encap(tos, inner_iph, skb);
ttl = tnl_params->ttl; ttl = tnl_params->ttl;
if (ttl == 0) { if (ttl == 0) {
if (skb->protocol == htons(ETH_P_IP)) if (skb->protocol == htons(ETH_P_IP))
@ -641,18 +642,17 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
max_headroom = LL_RESERVED_SPACE(rt->dst.dev) + sizeof(struct iphdr) max_headroom = LL_RESERVED_SPACE(rt->dst.dev) + sizeof(struct iphdr)
+ rt->dst.header_len; + rt->dst.header_len;
if (max_headroom > dev->needed_headroom) { if (max_headroom > dev->needed_headroom)
dev->needed_headroom = max_headroom; dev->needed_headroom = max_headroom;
if (skb_cow_head(skb, dev->needed_headroom)) { if (skb_cow_head(skb, dev->needed_headroom)) {
dev->stats.tx_dropped++; dev->stats.tx_dropped++;
dev_kfree_skb(skb); dev_kfree_skb(skb);
return; return;
} }
}
err = iptunnel_xmit(rt, skb, fl4.saddr, fl4.daddr, protocol, err = iptunnel_xmit(rt, skb, fl4.saddr, fl4.daddr, protocol,
ip_tunnel_ecn_encap(tos, inner_iph, skb), ttl, df, tos, ttl, df, !net_eq(tunnel->net, dev_net(dev)));
!net_eq(tunnel->net, dev_net(dev)));
iptunnel_xmit_stats(err, &dev->stats, dev->tstats); iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
return; return;
@ -853,8 +853,10 @@ int ip_tunnel_init_net(struct net *net, int ip_tnl_net_id,
/* FB netdevice is special: we have one, and only one per netns. /* FB netdevice is special: we have one, and only one per netns.
* Allowing to move it to another netns is clearly unsafe. * Allowing to move it to another netns is clearly unsafe.
*/ */
if (!IS_ERR(itn->fb_tunnel_dev)) if (!IS_ERR(itn->fb_tunnel_dev)) {
itn->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL; itn->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL;
ip_tunnel_add(itn, netdev_priv(itn->fb_tunnel_dev));
}
rtnl_unlock(); rtnl_unlock();
return PTR_RET(itn->fb_tunnel_dev); return PTR_RET(itn->fb_tunnel_dev);
@ -884,8 +886,6 @@ static void ip_tunnel_destroy(struct ip_tunnel_net *itn, struct list_head *head,
if (!net_eq(dev_net(t->dev), net)) if (!net_eq(dev_net(t->dev), net))
unregister_netdevice_queue(t->dev, head); unregister_netdevice_queue(t->dev, head);
} }
if (itn->fb_tunnel_dev)
unregister_netdevice_queue(itn->fb_tunnel_dev, head);
} }
void ip_tunnel_delete_net(struct ip_tunnel_net *itn, struct rtnl_link_ops *ops) void ip_tunnel_delete_net(struct ip_tunnel_net *itn, struct rtnl_link_ops *ops)

View File

@ -61,7 +61,7 @@ int iptunnel_xmit(struct rtable *rt, struct sk_buff *skb,
memset(IPCB(skb), 0, sizeof(*IPCB(skb))); memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
/* Push down and install the IP header. */ /* Push down and install the IP header. */
__skb_push(skb, sizeof(struct iphdr)); skb_push(skb, sizeof(struct iphdr));
skb_reset_network_header(skb); skb_reset_network_header(skb);
iph = ip_hdr(skb); iph = ip_hdr(skb);

View File

@ -267,7 +267,8 @@ synproxy_tg4(struct sk_buff *skb, const struct xt_action_param *par)
if (th == NULL) if (th == NULL)
return NF_DROP; return NF_DROP;
synproxy_parse_options(skb, par->thoff, th, &opts); if (!synproxy_parse_options(skb, par->thoff, th, &opts))
return NF_DROP;
if (th->syn && !(th->ack || th->fin || th->rst)) { if (th->syn && !(th->ack || th->fin || th->rst)) {
/* Initial SYN from client */ /* Initial SYN from client */
@ -350,7 +351,8 @@ static unsigned int ipv4_synproxy_hook(unsigned int hooknum,
/* fall through */ /* fall through */
case TCP_CONNTRACK_SYN_SENT: case TCP_CONNTRACK_SYN_SENT:
synproxy_parse_options(skb, thoff, th, &opts); if (!synproxy_parse_options(skb, thoff, th, &opts))
return NF_DROP;
if (!th->syn && th->ack && if (!th->syn && th->ack &&
CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) { CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
@ -373,7 +375,9 @@ static unsigned int ipv4_synproxy_hook(unsigned int hooknum,
if (!th->syn || !th->ack) if (!th->syn || !th->ack)
break; break;
synproxy_parse_options(skb, thoff, th, &opts); if (!synproxy_parse_options(skb, thoff, th, &opts))
return NF_DROP;
if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP) if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP)
synproxy->tsoff = opts.tsval - synproxy->its; synproxy->tsoff = opts.tsval - synproxy->its;

View File

@ -218,8 +218,10 @@ static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info)
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
ipv4_sk_update_pmtu(skb, sk, info); ipv4_sk_update_pmtu(skb, sk, info);
else if (type == ICMP_REDIRECT) else if (type == ICMP_REDIRECT) {
ipv4_sk_redirect(skb, sk); ipv4_sk_redirect(skb, sk);
return;
}
/* Report error on raw socket, if: /* Report error on raw socket, if:
1. User requested ip_recverr. 1. User requested ip_recverr.

View File

@ -895,8 +895,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
skb_orphan(skb); skb_orphan(skb);
skb->sk = sk; skb->sk = sk;
skb->destructor = (sysctl_tcp_limit_output_bytes > 0) ? skb->destructor = tcp_wfree;
tcp_wfree : sock_wfree;
atomic_add(skb->truesize, &sk->sk_wmem_alloc); atomic_add(skb->truesize, &sk->sk_wmem_alloc);
/* Build TCP header and checksum it. */ /* Build TCP header and checksum it. */
@ -1840,7 +1839,6 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
while ((skb = tcp_send_head(sk))) { while ((skb = tcp_send_head(sk))) {
unsigned int limit; unsigned int limit;
tso_segs = tcp_init_tso_segs(sk, skb, mss_now); tso_segs = tcp_init_tso_segs(sk, skb, mss_now);
BUG_ON(!tso_segs); BUG_ON(!tso_segs);
@ -1869,13 +1867,20 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
break; break;
} }
/* TSQ : sk_wmem_alloc accounts skb truesize, /* TCP Small Queues :
* including skb overhead. But thats OK. * Control number of packets in qdisc/devices to two packets / or ~1 ms.
* This allows for :
* - better RTT estimation and ACK scheduling
* - faster recovery
* - high rates
*/ */
if (atomic_read(&sk->sk_wmem_alloc) >= sysctl_tcp_limit_output_bytes) { limit = max(skb->truesize, sk->sk_pacing_rate >> 10);
if (atomic_read(&sk->sk_wmem_alloc) > limit) {
set_bit(TSQ_THROTTLED, &tp->tsq_flags); set_bit(TSQ_THROTTLED, &tp->tsq_flags);
break; break;
} }
limit = mss_now; limit = mss_now;
if (tso_segs > 1 && !tcp_urg_mode(tp)) if (tso_segs > 1 && !tcp_urg_mode(tp))
limit = tcp_mss_split_point(sk, skb, mss_now, limit = tcp_mss_split_point(sk, skb, mss_now,

View File

@ -658,7 +658,7 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
break; break;
case ICMP_REDIRECT: case ICMP_REDIRECT:
ipv4_sk_redirect(skb, sk); ipv4_sk_redirect(skb, sk);
break; goto out;
} }
/* /*

View File

@ -1499,6 +1499,33 @@ static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
return false; return false;
} }
/* Compares an address/prefix_len with addresses on device @dev.
* If one is found it returns true.
*/
bool ipv6_chk_custom_prefix(const struct in6_addr *addr,
const unsigned int prefix_len, struct net_device *dev)
{
struct inet6_dev *idev;
struct inet6_ifaddr *ifa;
bool ret = false;
rcu_read_lock();
idev = __in6_dev_get(dev);
if (idev) {
read_lock_bh(&idev->lock);
list_for_each_entry(ifa, &idev->addr_list, if_list) {
ret = ipv6_prefix_equal(addr, &ifa->addr, prefix_len);
if (ret)
break;
}
read_unlock_bh(&idev->lock);
}
rcu_read_unlock();
return ret;
}
EXPORT_SYMBOL(ipv6_chk_custom_prefix);
int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev) int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev)
{ {
struct inet6_dev *idev; struct inet6_dev *idev;
@ -2193,44 +2220,22 @@ ok:
else else
stored_lft = 0; stored_lft = 0;
if (!update_lft && !create && stored_lft) { if (!update_lft && !create && stored_lft) {
if (valid_lft > MIN_VALID_LIFETIME || const u32 minimum_lft = min(
valid_lft > stored_lft) stored_lft, (u32)MIN_VALID_LIFETIME);
update_lft = 1; valid_lft = max(valid_lft, minimum_lft);
else if (stored_lft <= MIN_VALID_LIFETIME) {
/* valid_lft <= stored_lft is always true */ /* RFC4862 Section 5.5.3e:
/* * "Note that the preferred lifetime of the
* RFC 4862 Section 5.5.3e: * corresponding address is always reset to
* "Note that the preferred lifetime of * the Preferred Lifetime in the received
* the corresponding address is always * Prefix Information option, regardless of
* reset to the Preferred Lifetime in * whether the valid lifetime is also reset or
* the received Prefix Information
* option, regardless of whether the
* valid lifetime is also reset or
* ignored." * ignored."
* *
* So if the preferred lifetime in * So we should always update prefered_lft here.
* this advertisement is different
* than what we have stored, but the
* valid lifetime is invalid, just
* reset prefered_lft.
*
* We must set the valid lifetime
* to the stored lifetime since we'll
* be updating the timestamp below,
* else we'll set it back to the
* minimum.
*/ */
if (prefered_lft != ifp->prefered_lft) {
valid_lft = stored_lft;
update_lft = 1; update_lft = 1;
} }
} else {
valid_lft = MIN_VALID_LIFETIME;
if (valid_lft < prefered_lft)
prefered_lft = valid_lft;
update_lft = 1;
}
}
if (update_lft) { if (update_lft) {
ifp->valid_lft = valid_lft; ifp->valid_lft = valid_lft;

View File

@ -618,7 +618,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
struct ip6_tnl *tunnel = netdev_priv(dev); struct ip6_tnl *tunnel = netdev_priv(dev);
struct net_device *tdev; /* Device to other host */ struct net_device *tdev; /* Device to other host */
struct ipv6hdr *ipv6h; /* Our new IP header */ struct ipv6hdr *ipv6h; /* Our new IP header */
unsigned int max_headroom; /* The extra header space needed */ unsigned int max_headroom = 0; /* The extra header space needed */
int gre_hlen; int gre_hlen;
struct ipv6_tel_txoption opt; struct ipv6_tel_txoption opt;
int mtu; int mtu;
@ -693,7 +693,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(dev))); skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(dev)));
max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + dst->header_len; max_headroom += LL_RESERVED_SPACE(tdev) + gre_hlen + dst->header_len;
if (skb_headroom(skb) < max_headroom || skb_shared(skb) || if (skb_headroom(skb) < max_headroom || skb_shared(skb) ||
(skb_cloned(skb) && !skb_clone_writable(skb, 0))) { (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {

View File

@ -1015,6 +1015,8 @@ static inline int ip6_ufo_append_data(struct sock *sk,
* udp datagram * udp datagram
*/ */
if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) { if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) {
struct frag_hdr fhdr;
skb = sock_alloc_send_skb(sk, skb = sock_alloc_send_skb(sk,
hh_len + fragheaderlen + transhdrlen + 20, hh_len + fragheaderlen + transhdrlen + 20,
(flags & MSG_DONTWAIT), &err); (flags & MSG_DONTWAIT), &err);
@ -1036,12 +1038,6 @@ static inline int ip6_ufo_append_data(struct sock *sk,
skb->protocol = htons(ETH_P_IPV6); skb->protocol = htons(ETH_P_IPV6);
skb->ip_summed = CHECKSUM_PARTIAL; skb->ip_summed = CHECKSUM_PARTIAL;
skb->csum = 0; skb->csum = 0;
}
err = skb_append_datato_frags(sk,skb, getfrag, from,
(length - transhdrlen));
if (!err) {
struct frag_hdr fhdr;
/* Specify the length of each IPv6 datagram fragment. /* Specify the length of each IPv6 datagram fragment.
* It has to be a multiple of 8. * It has to be a multiple of 8.
@ -1052,15 +1048,10 @@ static inline int ip6_ufo_append_data(struct sock *sk,
ipv6_select_ident(&fhdr, rt); ipv6_select_ident(&fhdr, rt);
skb_shinfo(skb)->ip6_frag_id = fhdr.identification; skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
__skb_queue_tail(&sk->sk_write_queue, skb); __skb_queue_tail(&sk->sk_write_queue, skb);
return 0;
} }
/* There is not enough support do UPD LSO,
* so follow normal path
*/
kfree_skb(skb);
return err; return skb_append_datato_frags(sk, skb, getfrag, from,
(length - transhdrlen));
} }
static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src, static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src,
@ -1227,17 +1218,18 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
* --yoshfuji * --yoshfuji
*/ */
cork->length += length; if ((length > mtu) && dontfrag && (sk->sk_protocol == IPPROTO_UDP ||
if (length > mtu) { sk->sk_protocol == IPPROTO_RAW)) {
int proto = sk->sk_protocol;
if (dontfrag && (proto == IPPROTO_UDP || proto == IPPROTO_RAW)){
ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen); ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen);
return -EMSGSIZE; return -EMSGSIZE;
} }
if (proto == IPPROTO_UDP && skb = skb_peek_tail(&sk->sk_write_queue);
cork->length += length;
if (((length > mtu) ||
(skb && skb_is_gso(skb))) &&
(sk->sk_protocol == IPPROTO_UDP) &&
(rt->dst.dev->features & NETIF_F_UFO)) { (rt->dst.dev->features & NETIF_F_UFO)) {
err = ip6_ufo_append_data(sk, getfrag, from, length, err = ip6_ufo_append_data(sk, getfrag, from, length,
hh_len, fragheaderlen, hh_len, fragheaderlen,
transhdrlen, mtu, flags, rt); transhdrlen, mtu, flags, rt);
@ -1245,9 +1237,8 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
goto error; goto error;
return 0; return 0;
} }
}
if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) if (!skb)
goto alloc_new_skb; goto alloc_new_skb;
while (length > 0) { while (length > 0) {

View File

@ -1731,8 +1731,6 @@ static void __net_exit ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n)
} }
} }
t = rtnl_dereference(ip6n->tnls_wc[0]);
unregister_netdevice_queue(t->dev, &list);
unregister_netdevice_many(&list); unregister_netdevice_many(&list);
} }
@ -1752,6 +1750,7 @@ static int __net_init ip6_tnl_init_net(struct net *net)
if (!ip6n->fb_tnl_dev) if (!ip6n->fb_tnl_dev)
goto err_alloc_dev; goto err_alloc_dev;
dev_net_set(ip6n->fb_tnl_dev, net); dev_net_set(ip6n->fb_tnl_dev, net);
ip6n->fb_tnl_dev->rtnl_link_ops = &ip6_link_ops;
/* FB netdevice is special: we have one, and only one per netns. /* FB netdevice is special: we have one, and only one per netns.
* Allowing to move it to another netns is clearly unsafe. * Allowing to move it to another netns is clearly unsafe.
*/ */

View File

@ -2034,7 +2034,7 @@ static void mld_dad_timer_expire(unsigned long data)
if (idev->mc_dad_count) if (idev->mc_dad_count)
mld_dad_start_timer(idev, idev->mc_maxdelay); mld_dad_start_timer(idev, idev->mc_maxdelay);
} }
__in6_dev_put(idev); in6_dev_put(idev);
} }
static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode, static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,
@ -2379,7 +2379,7 @@ static void mld_gq_timer_expire(unsigned long data)
idev->mc_gq_running = 0; idev->mc_gq_running = 0;
mld_send_report(idev, NULL); mld_send_report(idev, NULL);
__in6_dev_put(idev); in6_dev_put(idev);
} }
static void mld_ifc_timer_expire(unsigned long data) static void mld_ifc_timer_expire(unsigned long data)
@ -2392,7 +2392,7 @@ static void mld_ifc_timer_expire(unsigned long data)
if (idev->mc_ifc_count) if (idev->mc_ifc_count)
mld_ifc_start_timer(idev, idev->mc_maxdelay); mld_ifc_start_timer(idev, idev->mc_maxdelay);
} }
__in6_dev_put(idev); in6_dev_put(idev);
} }
static void mld_ifc_event(struct inet6_dev *idev) static void mld_ifc_event(struct inet6_dev *idev)

View File

@ -282,7 +282,8 @@ synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par)
if (th == NULL) if (th == NULL)
return NF_DROP; return NF_DROP;
synproxy_parse_options(skb, par->thoff, th, &opts); if (!synproxy_parse_options(skb, par->thoff, th, &opts))
return NF_DROP;
if (th->syn && !(th->ack || th->fin || th->rst)) { if (th->syn && !(th->ack || th->fin || th->rst)) {
/* Initial SYN from client */ /* Initial SYN from client */
@ -372,7 +373,8 @@ static unsigned int ipv6_synproxy_hook(unsigned int hooknum,
/* fall through */ /* fall through */
case TCP_CONNTRACK_SYN_SENT: case TCP_CONNTRACK_SYN_SENT:
synproxy_parse_options(skb, thoff, th, &opts); if (!synproxy_parse_options(skb, thoff, th, &opts))
return NF_DROP;
if (!th->syn && th->ack && if (!th->syn && th->ack &&
CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) { CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
@ -395,7 +397,9 @@ static unsigned int ipv6_synproxy_hook(unsigned int hooknum,
if (!th->syn || !th->ack) if (!th->syn || !th->ack)
break; break;
synproxy_parse_options(skb, thoff, th, &opts); if (!synproxy_parse_options(skb, thoff, th, &opts))
return NF_DROP;
if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP) if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP)
synproxy->tsoff = opts.tsval - synproxy->its; synproxy->tsoff = opts.tsval - synproxy->its;

View File

@ -335,8 +335,10 @@ static void rawv6_err(struct sock *sk, struct sk_buff *skb,
ip6_sk_update_pmtu(skb, sk, info); ip6_sk_update_pmtu(skb, sk, info);
harderr = (np->pmtudisc == IPV6_PMTUDISC_DO); harderr = (np->pmtudisc == IPV6_PMTUDISC_DO);
} }
if (type == NDISC_REDIRECT) if (type == NDISC_REDIRECT) {
ip6_sk_redirect(skb, sk); ip6_sk_redirect(skb, sk);
return;
}
if (np->recverr) { if (np->recverr) {
u8 *payload = skb->data; u8 *payload = skb->data;
if (!inet->hdrincl) if (!inet->hdrincl)

View File

@ -566,6 +566,70 @@ static inline bool is_spoofed_6rd(struct ip_tunnel *tunnel, const __be32 v4addr,
return false; return false;
} }
/* Checks if an address matches an address on the tunnel interface.
* Used to detect the NAT of proto 41 packets and let them pass spoofing test.
* Long story:
* This function is called after we considered the packet as spoofed
* in is_spoofed_6rd.
* We may have a router that is doing NAT for proto 41 packets
* for an internal station. Destination a.a.a.a/PREFIX:bbbb:bbbb
* will be translated to n.n.n.n/PREFIX:bbbb:bbbb. And is_spoofed_6rd
* function will return true, dropping the packet.
* But, we can still check if is spoofed against the IP
* addresses associated with the interface.
*/
static bool only_dnatted(const struct ip_tunnel *tunnel,
const struct in6_addr *v6dst)
{
int prefix_len;
#ifdef CONFIG_IPV6_SIT_6RD
prefix_len = tunnel->ip6rd.prefixlen + 32
- tunnel->ip6rd.relay_prefixlen;
#else
prefix_len = 48;
#endif
return ipv6_chk_custom_prefix(v6dst, prefix_len, tunnel->dev);
}
/* Returns true if a packet is spoofed */
static bool packet_is_spoofed(struct sk_buff *skb,
const struct iphdr *iph,
struct ip_tunnel *tunnel)
{
const struct ipv6hdr *ipv6h;
if (tunnel->dev->priv_flags & IFF_ISATAP) {
if (!isatap_chksrc(skb, iph, tunnel))
return true;
return false;
}
if (tunnel->dev->flags & IFF_POINTOPOINT)
return false;
ipv6h = ipv6_hdr(skb);
if (unlikely(is_spoofed_6rd(tunnel, iph->saddr, &ipv6h->saddr))) {
net_warn_ratelimited("Src spoofed %pI4/%pI6c -> %pI4/%pI6c\n",
&iph->saddr, &ipv6h->saddr,
&iph->daddr, &ipv6h->daddr);
return true;
}
if (likely(!is_spoofed_6rd(tunnel, iph->daddr, &ipv6h->daddr)))
return false;
if (only_dnatted(tunnel, &ipv6h->daddr))
return false;
net_warn_ratelimited("Dst spoofed %pI4/%pI6c -> %pI4/%pI6c\n",
&iph->saddr, &ipv6h->saddr,
&iph->daddr, &ipv6h->daddr);
return true;
}
static int ipip6_rcv(struct sk_buff *skb) static int ipip6_rcv(struct sk_buff *skb)
{ {
const struct iphdr *iph = ip_hdr(skb); const struct iphdr *iph = ip_hdr(skb);
@ -586,20 +650,10 @@ static int ipip6_rcv(struct sk_buff *skb)
IPCB(skb)->flags = 0; IPCB(skb)->flags = 0;
skb->protocol = htons(ETH_P_IPV6); skb->protocol = htons(ETH_P_IPV6);
if (tunnel->dev->priv_flags & IFF_ISATAP) { if (packet_is_spoofed(skb, iph, tunnel)) {
if (!isatap_chksrc(skb, iph, tunnel)) {
tunnel->dev->stats.rx_errors++; tunnel->dev->stats.rx_errors++;
goto out; goto out;
} }
} else if (!(tunnel->dev->flags&IFF_POINTOPOINT)) {
if (is_spoofed_6rd(tunnel, iph->saddr,
&ipv6_hdr(skb)->saddr) ||
is_spoofed_6rd(tunnel, iph->daddr,
&ipv6_hdr(skb)->daddr)) {
tunnel->dev->stats.rx_errors++;
goto out;
}
}
__skb_tunnel_rx(skb, tunnel->dev, tunnel->net); __skb_tunnel_rx(skb, tunnel->dev, tunnel->net);
@ -748,7 +802,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
neigh = dst_neigh_lookup(skb_dst(skb), &iph6->daddr); neigh = dst_neigh_lookup(skb_dst(skb), &iph6->daddr);
if (neigh == NULL) { if (neigh == NULL) {
net_dbg_ratelimited("sit: nexthop == NULL\n"); net_dbg_ratelimited("nexthop == NULL\n");
goto tx_error; goto tx_error;
} }
@ -777,7 +831,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
neigh = dst_neigh_lookup(skb_dst(skb), &iph6->daddr); neigh = dst_neigh_lookup(skb_dst(skb), &iph6->daddr);
if (neigh == NULL) { if (neigh == NULL) {
net_dbg_ratelimited("sit: nexthop == NULL\n"); net_dbg_ratelimited("nexthop == NULL\n");
goto tx_error; goto tx_error;
} }
@ -1612,6 +1666,7 @@ static int __net_init sit_init_net(struct net *net)
goto err_alloc_dev; goto err_alloc_dev;
} }
dev_net_set(sitn->fb_tunnel_dev, net); dev_net_set(sitn->fb_tunnel_dev, net);
sitn->fb_tunnel_dev->rtnl_link_ops = &sit_link_ops;
/* FB netdevice is special: we have one, and only one per netns. /* FB netdevice is special: we have one, and only one per netns.
* Allowing to move it to another netns is clearly unsafe. * Allowing to move it to another netns is clearly unsafe.
*/ */
@ -1646,7 +1701,6 @@ static void __net_exit sit_exit_net(struct net *net)
rtnl_lock(); rtnl_lock();
sit_destroy_tunnels(sitn, &list); sit_destroy_tunnels(sitn, &list);
unregister_netdevice_queue(sitn->fb_tunnel_dev, &list);
unregister_netdevice_many(&list); unregister_netdevice_many(&list);
rtnl_unlock(); rtnl_unlock();
} }

View File

@ -525,8 +525,10 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (type == ICMPV6_PKT_TOOBIG) if (type == ICMPV6_PKT_TOOBIG)
ip6_sk_update_pmtu(skb, sk, info); ip6_sk_update_pmtu(skb, sk, info);
if (type == NDISC_REDIRECT) if (type == NDISC_REDIRECT) {
ip6_sk_redirect(skb, sk); ip6_sk_redirect(skb, sk);
goto out;
}
np = inet6_sk(sk); np = inet6_sk(sk);

View File

@ -154,6 +154,7 @@ static void lapb_t1timer_expiry(unsigned long param)
} else { } else {
lapb->n2count++; lapb->n2count++;
lapb_requeue_frames(lapb); lapb_requeue_frames(lapb);
lapb_kick(lapb);
} }
break; break;

View File

@ -116,6 +116,7 @@ ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) { if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
struct ip_vs_cpu_stats *s; struct ip_vs_cpu_stats *s;
struct ip_vs_service *svc;
s = this_cpu_ptr(dest->stats.cpustats); s = this_cpu_ptr(dest->stats.cpustats);
s->ustats.inpkts++; s->ustats.inpkts++;
@ -123,11 +124,14 @@ ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
s->ustats.inbytes += skb->len; s->ustats.inbytes += skb->len;
u64_stats_update_end(&s->syncp); u64_stats_update_end(&s->syncp);
s = this_cpu_ptr(dest->svc->stats.cpustats); rcu_read_lock();
svc = rcu_dereference(dest->svc);
s = this_cpu_ptr(svc->stats.cpustats);
s->ustats.inpkts++; s->ustats.inpkts++;
u64_stats_update_begin(&s->syncp); u64_stats_update_begin(&s->syncp);
s->ustats.inbytes += skb->len; s->ustats.inbytes += skb->len;
u64_stats_update_end(&s->syncp); u64_stats_update_end(&s->syncp);
rcu_read_unlock();
s = this_cpu_ptr(ipvs->tot_stats.cpustats); s = this_cpu_ptr(ipvs->tot_stats.cpustats);
s->ustats.inpkts++; s->ustats.inpkts++;
@ -146,6 +150,7 @@ ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) { if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
struct ip_vs_cpu_stats *s; struct ip_vs_cpu_stats *s;
struct ip_vs_service *svc;
s = this_cpu_ptr(dest->stats.cpustats); s = this_cpu_ptr(dest->stats.cpustats);
s->ustats.outpkts++; s->ustats.outpkts++;
@ -153,11 +158,14 @@ ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
s->ustats.outbytes += skb->len; s->ustats.outbytes += skb->len;
u64_stats_update_end(&s->syncp); u64_stats_update_end(&s->syncp);
s = this_cpu_ptr(dest->svc->stats.cpustats); rcu_read_lock();
svc = rcu_dereference(dest->svc);
s = this_cpu_ptr(svc->stats.cpustats);
s->ustats.outpkts++; s->ustats.outpkts++;
u64_stats_update_begin(&s->syncp); u64_stats_update_begin(&s->syncp);
s->ustats.outbytes += skb->len; s->ustats.outbytes += skb->len;
u64_stats_update_end(&s->syncp); u64_stats_update_end(&s->syncp);
rcu_read_unlock();
s = this_cpu_ptr(ipvs->tot_stats.cpustats); s = this_cpu_ptr(ipvs->tot_stats.cpustats);
s->ustats.outpkts++; s->ustats.outpkts++;

View File

@ -460,7 +460,7 @@ static inline void
__ip_vs_bind_svc(struct ip_vs_dest *dest, struct ip_vs_service *svc) __ip_vs_bind_svc(struct ip_vs_dest *dest, struct ip_vs_service *svc)
{ {
atomic_inc(&svc->refcnt); atomic_inc(&svc->refcnt);
dest->svc = svc; rcu_assign_pointer(dest->svc, svc);
} }
static void ip_vs_service_free(struct ip_vs_service *svc) static void ip_vs_service_free(struct ip_vs_service *svc)
@ -470,17 +470,24 @@ static void ip_vs_service_free(struct ip_vs_service *svc)
kfree(svc); kfree(svc);
} }
static void static void ip_vs_service_rcu_free(struct rcu_head *head)
__ip_vs_unbind_svc(struct ip_vs_dest *dest)
{ {
struct ip_vs_service *svc = dest->svc; struct ip_vs_service *svc;
dest->svc = NULL; svc = container_of(head, struct ip_vs_service, rcu_head);
ip_vs_service_free(svc);
}
static void __ip_vs_svc_put(struct ip_vs_service *svc, bool do_delay)
{
if (atomic_dec_and_test(&svc->refcnt)) { if (atomic_dec_and_test(&svc->refcnt)) {
IP_VS_DBG_BUF(3, "Removing service %u/%s:%u\n", IP_VS_DBG_BUF(3, "Removing service %u/%s:%u\n",
svc->fwmark, svc->fwmark,
IP_VS_DBG_ADDR(svc->af, &svc->addr), IP_VS_DBG_ADDR(svc->af, &svc->addr),
ntohs(svc->port)); ntohs(svc->port));
if (do_delay)
call_rcu(&svc->rcu_head, ip_vs_service_rcu_free);
else
ip_vs_service_free(svc); ip_vs_service_free(svc);
} }
} }
@ -667,11 +674,6 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
IP_VS_DBG_ADDR(svc->af, &dest->addr), IP_VS_DBG_ADDR(svc->af, &dest->addr),
ntohs(dest->port), ntohs(dest->port),
atomic_read(&dest->refcnt)); atomic_read(&dest->refcnt));
/* We can not reuse dest while in grace period
* because conns still can use dest->svc
*/
if (test_bit(IP_VS_DEST_STATE_REMOVING, &dest->state))
continue;
if (dest->af == svc->af && if (dest->af == svc->af &&
ip_vs_addr_equal(svc->af, &dest->addr, daddr) && ip_vs_addr_equal(svc->af, &dest->addr, daddr) &&
dest->port == dport && dest->port == dport &&
@ -697,8 +699,10 @@ out:
static void ip_vs_dest_free(struct ip_vs_dest *dest) static void ip_vs_dest_free(struct ip_vs_dest *dest)
{ {
struct ip_vs_service *svc = rcu_dereference_protected(dest->svc, 1);
__ip_vs_dst_cache_reset(dest); __ip_vs_dst_cache_reset(dest);
__ip_vs_unbind_svc(dest); __ip_vs_svc_put(svc, false);
free_percpu(dest->stats.cpustats); free_percpu(dest->stats.cpustats);
kfree(dest); kfree(dest);
} }
@ -771,6 +775,7 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
struct ip_vs_dest_user_kern *udest, int add) struct ip_vs_dest_user_kern *udest, int add)
{ {
struct netns_ipvs *ipvs = net_ipvs(svc->net); struct netns_ipvs *ipvs = net_ipvs(svc->net);
struct ip_vs_service *old_svc;
struct ip_vs_scheduler *sched; struct ip_vs_scheduler *sched;
int conn_flags; int conn_flags;
@ -792,13 +797,14 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
atomic_set(&dest->conn_flags, conn_flags); atomic_set(&dest->conn_flags, conn_flags);
/* bind the service */ /* bind the service */
if (!dest->svc) { old_svc = rcu_dereference_protected(dest->svc, 1);
if (!old_svc) {
__ip_vs_bind_svc(dest, svc); __ip_vs_bind_svc(dest, svc);
} else { } else {
if (dest->svc != svc) { if (old_svc != svc) {
__ip_vs_unbind_svc(dest);
ip_vs_zero_stats(&dest->stats); ip_vs_zero_stats(&dest->stats);
__ip_vs_bind_svc(dest, svc); __ip_vs_bind_svc(dest, svc);
__ip_vs_svc_put(old_svc, true);
} }
} }
@ -998,16 +1004,6 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
return 0; return 0;
} }
static void ip_vs_dest_wait_readers(struct rcu_head *head)
{
struct ip_vs_dest *dest = container_of(head, struct ip_vs_dest,
rcu_head);
/* End of grace period after unlinking */
clear_bit(IP_VS_DEST_STATE_REMOVING, &dest->state);
}
/* /*
* Delete a destination (must be already unlinked from the service) * Delete a destination (must be already unlinked from the service)
*/ */
@ -1023,20 +1019,16 @@ static void __ip_vs_del_dest(struct net *net, struct ip_vs_dest *dest,
*/ */
ip_vs_rs_unhash(dest); ip_vs_rs_unhash(dest);
if (!cleanup) {
set_bit(IP_VS_DEST_STATE_REMOVING, &dest->state);
call_rcu(&dest->rcu_head, ip_vs_dest_wait_readers);
}
spin_lock_bh(&ipvs->dest_trash_lock); spin_lock_bh(&ipvs->dest_trash_lock);
IP_VS_DBG_BUF(3, "Moving dest %s:%u into trash, dest->refcnt=%d\n", IP_VS_DBG_BUF(3, "Moving dest %s:%u into trash, dest->refcnt=%d\n",
IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port), IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port),
atomic_read(&dest->refcnt)); atomic_read(&dest->refcnt));
if (list_empty(&ipvs->dest_trash) && !cleanup) if (list_empty(&ipvs->dest_trash) && !cleanup)
mod_timer(&ipvs->dest_trash_timer, mod_timer(&ipvs->dest_trash_timer,
jiffies + IP_VS_DEST_TRASH_PERIOD); jiffies + (IP_VS_DEST_TRASH_PERIOD >> 1));
/* dest lives in trash without reference */ /* dest lives in trash without reference */
list_add(&dest->t_list, &ipvs->dest_trash); list_add(&dest->t_list, &ipvs->dest_trash);
dest->idle_start = 0;
spin_unlock_bh(&ipvs->dest_trash_lock); spin_unlock_bh(&ipvs->dest_trash_lock);
ip_vs_dest_put(dest); ip_vs_dest_put(dest);
} }
@ -1108,24 +1100,30 @@ static void ip_vs_dest_trash_expire(unsigned long data)
struct net *net = (struct net *) data; struct net *net = (struct net *) data;
struct netns_ipvs *ipvs = net_ipvs(net); struct netns_ipvs *ipvs = net_ipvs(net);
struct ip_vs_dest *dest, *next; struct ip_vs_dest *dest, *next;
unsigned long now = jiffies;
spin_lock(&ipvs->dest_trash_lock); spin_lock(&ipvs->dest_trash_lock);
list_for_each_entry_safe(dest, next, &ipvs->dest_trash, t_list) { list_for_each_entry_safe(dest, next, &ipvs->dest_trash, t_list) {
/* Skip if dest is in grace period */
if (test_bit(IP_VS_DEST_STATE_REMOVING, &dest->state))
continue;
if (atomic_read(&dest->refcnt) > 0) if (atomic_read(&dest->refcnt) > 0)
continue; continue;
if (dest->idle_start) {
if (time_before(now, dest->idle_start +
IP_VS_DEST_TRASH_PERIOD))
continue;
} else {
dest->idle_start = max(1UL, now);
continue;
}
IP_VS_DBG_BUF(3, "Removing destination %u/%s:%u from trash\n", IP_VS_DBG_BUF(3, "Removing destination %u/%s:%u from trash\n",
dest->vfwmark, dest->vfwmark,
IP_VS_DBG_ADDR(dest->svc->af, &dest->addr), IP_VS_DBG_ADDR(dest->af, &dest->addr),
ntohs(dest->port)); ntohs(dest->port));
list_del(&dest->t_list); list_del(&dest->t_list);
ip_vs_dest_free(dest); ip_vs_dest_free(dest);
} }
if (!list_empty(&ipvs->dest_trash)) if (!list_empty(&ipvs->dest_trash))
mod_timer(&ipvs->dest_trash_timer, mod_timer(&ipvs->dest_trash_timer,
jiffies + IP_VS_DEST_TRASH_PERIOD); jiffies + (IP_VS_DEST_TRASH_PERIOD >> 1));
spin_unlock(&ipvs->dest_trash_lock); spin_unlock(&ipvs->dest_trash_lock);
} }
@ -1320,14 +1318,6 @@ out:
return ret; return ret;
} }
static void ip_vs_service_rcu_free(struct rcu_head *head)
{
struct ip_vs_service *svc;
svc = container_of(head, struct ip_vs_service, rcu_head);
ip_vs_service_free(svc);
}
/* /*
* Delete a service from the service list * Delete a service from the service list
* - The service must be unlinked, unlocked and not referenced! * - The service must be unlinked, unlocked and not referenced!
@ -1376,13 +1366,7 @@ static void __ip_vs_del_service(struct ip_vs_service *svc, bool cleanup)
/* /*
* Free the service if nobody refers to it * Free the service if nobody refers to it
*/ */
if (atomic_dec_and_test(&svc->refcnt)) { __ip_vs_svc_put(svc, true);
IP_VS_DBG_BUF(3, "Removing service %u/%s:%u\n",
svc->fwmark,
IP_VS_DBG_ADDR(svc->af, &svc->addr),
ntohs(svc->port));
call_rcu(&svc->rcu_head, ip_vs_service_rcu_free);
}
/* decrease the module use count */ /* decrease the module use count */
ip_vs_use_count_dec(); ip_vs_use_count_dec();

View File

@ -59,12 +59,13 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
struct ip_vs_cpu_stats __percpu *stats) struct ip_vs_cpu_stats __percpu *stats)
{ {
int i; int i;
bool add = false;
for_each_possible_cpu(i) { for_each_possible_cpu(i) {
struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i); struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i);
unsigned int start; unsigned int start;
__u64 inbytes, outbytes; __u64 inbytes, outbytes;
if (i) { if (add) {
sum->conns += s->ustats.conns; sum->conns += s->ustats.conns;
sum->inpkts += s->ustats.inpkts; sum->inpkts += s->ustats.inpkts;
sum->outpkts += s->ustats.outpkts; sum->outpkts += s->ustats.outpkts;
@ -76,6 +77,7 @@ static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
sum->inbytes += inbytes; sum->inbytes += inbytes;
sum->outbytes += outbytes; sum->outbytes += outbytes;
} else { } else {
add = true;
sum->conns = s->ustats.conns; sum->conns = s->ustats.conns;
sum->inpkts = s->ustats.inpkts; sum->inpkts = s->ustats.inpkts;
sum->outpkts = s->ustats.outpkts; sum->outpkts = s->ustats.outpkts;

Some files were not shown because too many files have changed in this diff Show More