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

Conflicts:
	drivers/net/e100.c
	drivers/net/e1000e/netdev.c
This commit is contained in:
David S. Miller 2010-04-27 12:49:13 -07:00
commit e1703b36c3
29 changed files with 794 additions and 120 deletions

View File

@ -273,6 +273,7 @@ obj-$(CONFIG_USB_RTL8150) += usb/
obj-$(CONFIG_USB_HSO) += usb/
obj-$(CONFIG_USB_USBNET) += usb/
obj-$(CONFIG_USB_ZD1201) += usb/
obj-$(CONFIG_USB_IPHETH) += usb/
obj-y += wireless/
obj-$(CONFIG_NET_TULIP) += tulip/

View File

@ -1006,7 +1006,7 @@ static int ems_usb_probe(struct usb_interface *intf,
netdev = alloc_candev(sizeof(struct ems_usb), MAX_TX_URBS);
if (!netdev) {
dev_err(netdev->dev.parent, "Couldn't alloc candev\n");
dev_err(&intf->dev, "ems_usb: Couldn't alloc candev\n");
return -ENOMEM;
}
@ -1036,20 +1036,20 @@ static int ems_usb_probe(struct usb_interface *intf,
dev->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->intr_urb) {
dev_err(netdev->dev.parent, "Couldn't alloc intr URB\n");
dev_err(&intf->dev, "Couldn't alloc intr URB\n");
goto cleanup_candev;
}
dev->intr_in_buffer = kzalloc(INTR_IN_BUFFER_SIZE, GFP_KERNEL);
if (!dev->intr_in_buffer) {
dev_err(netdev->dev.parent, "Couldn't alloc Intr buffer\n");
dev_err(&intf->dev, "Couldn't alloc Intr buffer\n");
goto cleanup_intr_urb;
}
dev->tx_msg_buffer = kzalloc(CPC_HEADER_SIZE +
sizeof(struct ems_cpc_msg), GFP_KERNEL);
if (!dev->tx_msg_buffer) {
dev_err(netdev->dev.parent, "Couldn't alloc Tx buffer\n");
dev_err(&intf->dev, "Couldn't alloc Tx buffer\n");
goto cleanup_intr_in_buffer;
}

View File

@ -934,7 +934,7 @@ static struct cphy_ops xaui_direct_ops = {
int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
int phy_addr, const struct mdio_ops *mdio_ops)
{
cphy_init(phy, adapter, MDIO_PRTAD_NONE, &xaui_direct_ops, mdio_ops,
cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops,
SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP,
"10GBASE-CX4");
return 0;

View File

@ -439,7 +439,7 @@ static void free_irq_resources(struct adapter *adapter)
static int await_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
unsigned long n)
{
int attempts = 5;
int attempts = 10;
while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) {
if (!--attempts)

View File

@ -168,6 +168,7 @@
#include <linux/ethtool.h>
#include <linux/string.h>
#include <linux/firmware.h>
#include <linux/rtnetlink.h>
#include <asm/unaligned.h>
@ -2280,8 +2281,13 @@ static void e100_tx_timeout_task(struct work_struct *work)
netif_printk(nic, tx_err, KERN_DEBUG, nic->netdev,
"scb.status=0x%02X\n", ioread8(&nic->csr->scb.status));
e100_down(netdev_priv(netdev));
e100_up(netdev_priv(netdev));
rtnl_lock();
if (netif_running(netdev)) {
e100_down(netdev_priv(netdev));
e100_up(netdev_priv(netdev));
}
rtnl_unlock();
}
static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)

View File

@ -336,7 +336,6 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
static int global_quad_port_a; /* global port a indication */
struct pci_dev *pdev = adapter->pdev;
u16 eeprom_data = 0;
int is_port_b = er32(STATUS) & E1000_STATUS_FUNC_1;
s32 rc;
@ -387,16 +386,15 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter)
if (pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD)
adapter->flags &= ~FLAG_HAS_WOL;
break;
case e1000_82573:
case e1000_82574:
case e1000_82583:
/* Disable ASPM L0s due to hardware errata */
e1000e_disable_aspm(adapter->pdev, PCIE_LINK_STATE_L0S);
if (pdev->device == E1000_DEV_ID_82573L) {
if (e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1,
&eeprom_data) < 0)
break;
if (!(eeprom_data & NVM_WORD1A_ASPM_MASK)) {
adapter->flags |= FLAG_HAS_JUMBO_FRAMES;
adapter->max_hw_frame_size = DEFAULT_JUMBO;
}
adapter->flags |= FLAG_HAS_JUMBO_FRAMES;
adapter->max_hw_frame_size = DEFAULT_JUMBO;
}
break;
default:
@ -1792,6 +1790,7 @@ struct e1000_info e1000_82571_info = {
| FLAG_RESET_OVERWRITES_LAA /* errata */
| FLAG_TARC_SPEED_MODE_BIT /* errata */
| FLAG_APME_CHECK_PORT_B,
.flags2 = FLAG2_DISABLE_ASPM_L1, /* errata 13 */
.pba = 38,
.max_hw_frame_size = DEFAULT_JUMBO,
.get_variants = e1000_get_variants_82571,
@ -1809,6 +1808,7 @@ struct e1000_info e1000_82572_info = {
| FLAG_RX_CSUM_ENABLED
| FLAG_HAS_CTRLEXT_ON_LOAD
| FLAG_TARC_SPEED_MODE_BIT, /* errata */
.flags2 = FLAG2_DISABLE_ASPM_L1, /* errata 13 */
.pba = 38,
.max_hw_frame_size = DEFAULT_JUMBO,
.get_variants = e1000_get_variants_82571,
@ -1820,13 +1820,11 @@ struct e1000_info e1000_82572_info = {
struct e1000_info e1000_82573_info = {
.mac = e1000_82573,
.flags = FLAG_HAS_HW_VLAN_FILTER
| FLAG_HAS_JUMBO_FRAMES
| FLAG_HAS_WOL
| FLAG_APME_IN_CTRL3
| FLAG_RX_CSUM_ENABLED
| FLAG_HAS_SMART_POWER_DOWN
| FLAG_HAS_AMT
| FLAG_HAS_ERT
| FLAG_HAS_SWSM_ON_LOAD,
.pba = 20,
.max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN,

View File

@ -37,6 +37,7 @@
#include <linux/io.h>
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/pci-aspm.h>
#include "hw.h"
@ -370,7 +371,7 @@ struct e1000_adapter {
struct e1000_info {
enum e1000_mac_type mac;
unsigned int flags;
unsigned int flags2;
unsigned int flags2;
u32 pba;
u32 max_hw_frame_size;
s32 (*get_variants)(struct e1000_adapter *);
@ -417,6 +418,7 @@ struct e1000_info {
#define FLAG2_CRC_STRIPPING (1 << 0)
#define FLAG2_HAS_PHY_WAKEUP (1 << 1)
#define FLAG2_IS_DISCARDING (1 << 2)
#define FLAG2_DISABLE_ASPM_L1 (1 << 3)
#define E1000_RX_DESC_PS(R, i) \
(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
@ -457,6 +459,7 @@ extern void e1000e_update_stats(struct e1000_adapter *adapter);
extern bool e1000e_has_link(struct e1000_adapter *adapter);
extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter);
extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter);
extern void e1000e_disable_aspm(struct pci_dev *pdev, u16 state);
extern unsigned int copybreak;

View File

@ -4310,6 +4310,14 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
return -EINVAL;
}
/* 82573 Errata 17 */
if (((adapter->hw.mac.type == e1000_82573) ||
(adapter->hw.mac.type == e1000_82574)) &&
(max_frame > ETH_FRAME_LEN + ETH_FCS_LEN)) {
adapter->flags2 |= FLAG2_DISABLE_ASPM_L1;
e1000e_disable_aspm(adapter->pdev, PCIE_LINK_STATE_L1);
}
while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
msleep(1);
/* e1000e_down -> e1000e_reset dependent on max_frame_size & mtu */
@ -4634,29 +4642,39 @@ static void e1000_complete_shutdown(struct pci_dev *pdev, bool sleep,
}
}
static void e1000e_disable_l1aspm(struct pci_dev *pdev)
#ifdef CONFIG_PCIEASPM
static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
{
pci_disable_link_state(pdev, state);
}
#else
static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
{
int pos;
u16 val;
u16 reg16;
/*
* 82573 workaround - disable L1 ASPM on mobile chipsets
*
* L1 ASPM on various mobile (ich7) chipsets do not behave properly
* resulting in lost data or garbage information on the pci-e link
* level. This could result in (false) bad EEPROM checksum errors,
* long ping times (up to 2s) or even a system freeze/hang.
*
* Unfortunately this feature saves about 1W power consumption when
* active.
* Both device and parent should have the same ASPM setting.
* Disable ASPM in downstream component first and then upstream.
*/
pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &val);
if (val & 0x2) {
dev_warn(&pdev->dev, "Disabling L1 ASPM\n");
val &= ~0x2;
pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, val);
}
pos = pci_pcie_cap(pdev);
pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &reg16);
reg16 &= ~state;
pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16);
pos = pci_pcie_cap(pdev->bus->self);
pci_read_config_word(pdev->bus->self, pos + PCI_EXP_LNKCTL, &reg16);
reg16 &= ~state;
pci_write_config_word(pdev->bus->self, pos + PCI_EXP_LNKCTL, reg16);
}
#endif
void e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
{
dev_info(&pdev->dev, "Disabling ASPM %s %s\n",
(state & PCIE_LINK_STATE_L0S) ? "L0s" : "",
(state & PCIE_LINK_STATE_L1) ? "L1" : "");
__e1000e_disable_aspm(pdev, state);
}
#ifdef CONFIG_PM_OPS
@ -4672,7 +4690,11 @@ static int __e1000_resume(struct pci_dev *pdev)
struct e1000_hw *hw = &adapter->hw;
u32 err;
e1000e_disable_l1aspm(pdev);
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
pci_save_state(pdev);
if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1)
e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1);
e1000e_set_interrupt_capability(adapter);
if (netif_running(netdev)) {
@ -4877,7 +4899,8 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
int err;
pci_ers_result_t result;
e1000e_disable_l1aspm(pdev);
if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1)
e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1);
err = pci_enable_device_mem(pdev);
if (err) {
dev_err(&pdev->dev,
@ -4971,13 +4994,6 @@ static void e1000_eeprom_checks(struct e1000_adapter *adapter)
dev_warn(&adapter->pdev->dev,
"Warning: detected DSPD enabled in EEPROM\n");
}
ret_val = e1000_read_nvm(hw, NVM_INIT_3GIO_3, 1, &buf);
if (!ret_val && (le16_to_cpu(buf) & (3 << 2))) {
/* ASPM enable */
dev_warn(&adapter->pdev->dev,
"Warning: detected ASPM enabled in EEPROM\n");
}
}
static const struct net_device_ops e1000e_netdev_ops = {
@ -5026,7 +5042,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
u16 eeprom_data = 0;
u16 eeprom_apme_mask = E1000_EEPROM_APME;
e1000e_disable_l1aspm(pdev);
if (ei->flags2 & FLAG2_DISABLE_ASPM_L1)
e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1);
err = pci_enable_device_mem(pdev);
if (err)

View File

@ -205,8 +205,6 @@ static int fsl_pq_mdio_find_free(struct mii_bus *new_bus)
static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs, struct device_node *np)
{
struct gfar __iomem *enet_regs;
u32 __iomem *ioremap_tbipa;
u64 addr, size;
/*
* This is mildly evil, but so is our hardware for doing this.
@ -220,9 +218,7 @@ static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs, struct devi
return &enet_regs->tbipa;
} else if (of_device_is_compatible(np, "fsl,etsec2-mdio") ||
of_device_is_compatible(np, "fsl,etsec2-tbi")) {
addr = of_translate_address(np, of_get_address(np, 1, &size, NULL));
ioremap_tbipa = ioremap(addr, size);
return ioremap_tbipa;
return of_iomap(np, 1);
} else
return NULL;
}
@ -279,6 +275,7 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev,
u32 __iomem *tbipa;
struct mii_bus *new_bus;
int tbiaddr = -1;
const u32 *addrp;
u64 addr = 0, size = 0;
int err = 0;
@ -297,8 +294,19 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev,
new_bus->priv = priv;
fsl_pq_mdio_bus_name(new_bus->id, np);
addrp = of_get_address(np, 0, &size, NULL);
if (!addrp) {
err = -EINVAL;
goto err_free_bus;
}
/* Set the PHY base address */
addr = of_translate_address(np, of_get_address(np, 0, &size, NULL));
addr = of_translate_address(np, addrp);
if (addr == OF_BAD_ADDR) {
err = -EINVAL;
goto err_free_bus;
}
map = ioremap(addr, size);
if (!map) {
err = -ENOMEM;

View File

@ -558,12 +558,8 @@ static int gfar_parse_group(struct device_node *np,
struct gfar_private *priv, const char *model)
{
u32 *queue_mask;
u64 addr, size;
addr = of_translate_address(np,
of_get_address(np, 0, &size, NULL));
priv->gfargrp[priv->num_grps].regs = ioremap(addr, size);
priv->gfargrp[priv->num_grps].regs = of_iomap(np, 0);
if (!priv->gfargrp[priv->num_grps].regs)
return -ENOMEM;

View File

@ -39,6 +39,8 @@
#define IXGBE_82599_MC_TBL_SIZE 128
#define IXGBE_82599_VFT_TBL_SIZE 128
void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
@ -69,8 +71,14 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw)
if (hw->phy.multispeed_fiber) {
/* Set up dual speed SFP+ support */
mac->ops.setup_link = &ixgbe_setup_mac_link_multispeed_fiber;
mac->ops.disable_tx_laser =
&ixgbe_disable_tx_laser_multispeed_fiber;
mac->ops.enable_tx_laser =
&ixgbe_enable_tx_laser_multispeed_fiber;
mac->ops.flap_tx_laser = &ixgbe_flap_tx_laser_multispeed_fiber;
} else {
mac->ops.disable_tx_laser = NULL;
mac->ops.enable_tx_laser = NULL;
mac->ops.flap_tx_laser = NULL;
if ((mac->ops.get_media_type(hw) ==
ixgbe_media_type_backplane) &&
@ -415,6 +423,44 @@ s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw,
return status;
}
/**
* ixgbe_disable_tx_laser_multispeed_fiber - Disable Tx laser
* @hw: pointer to hardware structure
*
* The base drivers may require better control over SFP+ module
* PHY states. This includes selectively shutting down the Tx
* laser on the PHY, effectively halting physical link.
**/
void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
{
u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
/* Disable tx laser; allow 100us to go dark per spec */
esdp_reg |= IXGBE_ESDP_SDP3;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
IXGBE_WRITE_FLUSH(hw);
udelay(100);
}
/**
* ixgbe_enable_tx_laser_multispeed_fiber - Enable Tx laser
* @hw: pointer to hardware structure
*
* The base drivers may require better control over SFP+ module
* PHY states. This includes selectively turning on the Tx
* laser on the PHY, effectively starting physical link.
**/
void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
{
u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
/* Enable tx laser; allow 100ms to light up */
esdp_reg &= ~IXGBE_ESDP_SDP3;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
IXGBE_WRITE_FLUSH(hw);
msleep(100);
}
/**
* ixgbe_flap_tx_laser_multispeed_fiber - Flap Tx laser
* @hw: pointer to hardware structure
@ -429,23 +475,11 @@ s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw,
**/
void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
{
u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
hw_dbg(hw, "ixgbe_flap_tx_laser_multispeed_fiber\n");
if (hw->mac.autotry_restart) {
/* Disable tx laser; allow 100us to go dark per spec */
esdp_reg |= IXGBE_ESDP_SDP3;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
IXGBE_WRITE_FLUSH(hw);
udelay(100);
/* Enable tx laser; allow 100ms to light up */
esdp_reg &= ~IXGBE_ESDP_SDP3;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
IXGBE_WRITE_FLUSH(hw);
msleep(100);
ixgbe_disable_tx_laser_multispeed_fiber(hw);
ixgbe_enable_tx_laser_multispeed_fiber(hw);
hw->mac.autotry_restart = false;
}
}

View File

@ -2991,6 +2991,10 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
else
ixgbe_configure_msi_and_legacy(adapter);
/* enable the optics */
if (hw->phy.multispeed_fiber)
hw->mac.ops.enable_tx_laser(hw);
clear_bit(__IXGBE_DOWN, &adapter->state);
ixgbe_napi_enable_all(adapter);
@ -3252,6 +3256,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
/* signal that we are down to the interrupt handler */
set_bit(__IXGBE_DOWN, &adapter->state);
/* power down the optics */
if (hw->phy.multispeed_fiber)
hw->mac.ops.disable_tx_laser(hw);
/* disable receive for all VFs and wait one second */
if (adapter->num_vfs) {
/* ping all the active vfs to let them know we are going down */
@ -6262,6 +6270,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
goto err_eeprom;
}
/* power down the optics */
if (hw->phy.multispeed_fiber)
hw->mac.ops.disable_tx_laser(hw);
init_timer(&adapter->watchdog_timer);
adapter->watchdog_timer.function = &ixgbe_watchdog;
adapter->watchdog_timer.data = (unsigned long)adapter;
@ -6409,16 +6421,6 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
del_timer_sync(&adapter->sfp_timer);
cancel_work_sync(&adapter->watchdog_task);
cancel_work_sync(&adapter->sfp_task);
if (adapter->hw.phy.multispeed_fiber) {
struct ixgbe_hw *hw = &adapter->hw;
/*
* Restart clause 37 autoneg, disable and re-enable
* the tx laser, to clear & alert the link partner
* that it needs to restart autotry
*/
hw->mac.autotry_restart = true;
hw->mac.ops.flap_tx_laser(hw);
}
cancel_work_sync(&adapter->multispeed_fiber_task);
cancel_work_sync(&adapter->sfp_config_module_task);
if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||

View File

@ -2398,6 +2398,8 @@ struct ixgbe_mac_operations {
s32 (*enable_rx_dma)(struct ixgbe_hw *, u32);
/* Link */
void (*disable_tx_laser)(struct ixgbe_hw *);
void (*enable_tx_laser)(struct ixgbe_hw *);
void (*flap_tx_laser)(struct ixgbe_hw *);
s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool, bool);
s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool);

View File

@ -717,12 +717,14 @@ static void ks8851_tx_work(struct work_struct *work)
txb = skb_dequeue(&ks->txq);
last = skb_queue_empty(&ks->txq);
ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr | RXQCR_SDA);
ks8851_wrpkt(ks, txb, last);
ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr);
ks8851_wrreg16(ks, KS_TXQCR, TXQCR_METFE);
if (txb != NULL) {
ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr | RXQCR_SDA);
ks8851_wrpkt(ks, txb, last);
ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr);
ks8851_wrreg16(ks, KS_TXQCR, TXQCR_METFE);
ks8851_done_tx(ks, txb);
ks8851_done_tx(ks, txb);
}
}
mutex_unlock(&ks->lock);

View File

@ -781,8 +781,13 @@ static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
inw(ioaddr + EL3_STATUS));
spin_lock_irqsave(&lp->window_lock, flags);
dev->stats.tx_bytes += skb->len;
/* Put out the doubleword header... */
outw(skb->len, ioaddr + TX_FIFO);
outw(0, ioaddr + TX_FIFO);
/* ... and the packet rounded to a doubleword. */
outsl(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2);
dev->trans_start = jiffies;
@ -1021,8 +1026,6 @@ static void update_stats(struct net_device *dev)
/* BadSSD */ inb(ioaddr + 12);
up = inb(ioaddr + 13);
dev->stats.tx_bytes += tx + ((up & 0xf0) << 12);
EL3WINDOW(1);
}

View File

@ -2775,6 +2775,7 @@ static void rtl8169_release_board(struct pci_dev *pdev, struct net_device *dev,
{
iounmap(ioaddr);
pci_release_regions(pdev);
pci_clear_mwi(pdev);
pci_disable_device(pdev);
free_netdev(dev);
}
@ -2841,8 +2842,13 @@ static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr)
spin_lock_irq(&tp->lock);
RTL_W8(Cfg9346, Cfg9346_Unlock);
RTL_W32(MAC4, high);
RTL_R32(MAC4);
RTL_W32(MAC0, low);
RTL_R32(MAC0);
RTL_W8(Cfg9346, Cfg9346_Lock);
spin_unlock_irq(&tp->lock);
@ -3030,9 +3036,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_free_dev_1;
}
rc = pci_set_mwi(pdev);
if (rc < 0)
goto err_out_disable_2;
if (pci_set_mwi(pdev) < 0)
netif_info(tp, probe, dev, "Mem-Wr-Inval unavailable\n");
/* make sure PCI base addr 1 is MMIO */
if (!(pci_resource_flags(pdev, region) & IORESOURCE_MEM)) {
@ -3040,7 +3045,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
"region #%d not an MMIO resource, aborting\n",
region);
rc = -ENODEV;
goto err_out_mwi_3;
goto err_out_mwi_2;
}
/* check for weird/broken PCI region reporting */
@ -3048,13 +3053,13 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
netif_err(tp, probe, dev,
"Invalid PCI region size(s), aborting\n");
rc = -ENODEV;
goto err_out_mwi_3;
goto err_out_mwi_2;
}
rc = pci_request_regions(pdev, MODULENAME);
if (rc < 0) {
netif_err(tp, probe, dev, "could not request regions\n");
goto err_out_mwi_3;
goto err_out_mwi_2;
}
tp->cp_cmd = PCIMulRW | RxChkSum;
@ -3067,7 +3072,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc < 0) {
netif_err(tp, probe, dev, "DMA configuration failed\n");
goto err_out_free_res_4;
goto err_out_free_res_3;
}
}
@ -3076,7 +3081,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!ioaddr) {
netif_err(tp, probe, dev, "cannot remap MMIO, aborting\n");
rc = -EIO;
goto err_out_free_res_4;
goto err_out_free_res_3;
}
tp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
@ -3118,7 +3123,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (i == ARRAY_SIZE(rtl_chip_info)) {
dev_err(&pdev->dev,
"driver bug, MAC version not found in rtl_chip_info\n");
goto err_out_msi_5;
goto err_out_msi_4;
}
tp->chipset = i;
@ -3183,7 +3188,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rc = register_netdev(dev);
if (rc < 0)
goto err_out_msi_5;
goto err_out_msi_4;
pci_set_drvdata(pdev, dev);
@ -3212,14 +3217,13 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
out:
return rc;
err_out_msi_5:
err_out_msi_4:
rtl_disable_msi(pdev, tp);
iounmap(ioaddr);
err_out_free_res_4:
err_out_free_res_3:
pci_release_regions(pdev);
err_out_mwi_3:
err_out_mwi_2:
pci_clear_mwi(pdev);
err_out_disable_2:
pci_disable_device(pdev);
err_out_free_dev_1:
free_netdev(dev);

View File

@ -8700,6 +8700,7 @@ static int tg3_test_msi(struct tg3 *tp)
pci_disable_msi(tp->pdev);
tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
tp->napi[0].irq_vec = tp->pdev->irq;
err = tg3_request_irq(tp, 0);
if (err)

View File

@ -385,4 +385,16 @@ config USB_CDC_PHONET
cellular modem, as found on most Nokia handsets with the
"PC suite" USB profile.
config USB_IPHETH
tristate "Apple iPhone USB Ethernet driver"
default n
---help---
Module used to share Internet connection (tethering) from your
iPhone (Original, 3G and 3GS) to your system.
Note that you need userspace libraries and programs that are needed
to pair your device with your system and that understand the iPhone
protocol.
For more information: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver
endmenu

View File

@ -23,4 +23,5 @@ obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o
obj-$(CONFIG_USB_USBNET) += usbnet.o
obj-$(CONFIG_USB_NET_INT51X1) += int51x1.o
obj-$(CONFIG_USB_CDC_PHONET) += cdc-phonet.o
obj-$(CONFIG_USB_IPHETH) += ipheth.o

568
drivers/net/usb/ipheth.c Normal file
View File

@ -0,0 +1,568 @@
/*
* ipheth.c - Apple iPhone USB Ethernet driver
*
* Copyright (c) 2009 Diego Giagio <diego@giagio.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of GIAGIO.COM nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* Alternatively, provided that this notice is retained in full, this
* software may be distributed under the terms of the GNU General
* Public License ("GPL") version 2, in which case the provisions of the
* GPL apply INSTEAD OF those given above.
*
* The provided data structures and external interfaces from this code
* are not restricted to be used by modules with a GPL compatible license.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
*
* Attention: iPhone device must be paired, otherwise it won't respond to our
* driver. For more info: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver
*
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/usb.h>
#include <linux/workqueue.h>
#define USB_VENDOR_APPLE 0x05ac
#define USB_PRODUCT_IPHONE 0x1290
#define USB_PRODUCT_IPHONE_3G 0x1292
#define USB_PRODUCT_IPHONE_3GS 0x1294
#define IPHETH_USBINTF_CLASS 255
#define IPHETH_USBINTF_SUBCLASS 253
#define IPHETH_USBINTF_PROTO 1
#define IPHETH_BUF_SIZE 1516
#define IPHETH_TX_TIMEOUT (5 * HZ)
#define IPHETH_INTFNUM 2
#define IPHETH_ALT_INTFNUM 1
#define IPHETH_CTRL_ENDP 0x00
#define IPHETH_CTRL_BUF_SIZE 0x40
#define IPHETH_CTRL_TIMEOUT (5 * HZ)
#define IPHETH_CMD_GET_MACADDR 0x00
#define IPHETH_CMD_CARRIER_CHECK 0x45
#define IPHETH_CARRIER_CHECK_TIMEOUT round_jiffies_relative(1 * HZ)
#define IPHETH_CARRIER_ON 0x04
static struct usb_device_id ipheth_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(
USB_VENDOR_APPLE, USB_PRODUCT_IPHONE,
IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
IPHETH_USBINTF_PROTO) },
{ USB_DEVICE_AND_INTERFACE_INFO(
USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_3G,
IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
IPHETH_USBINTF_PROTO) },
{ USB_DEVICE_AND_INTERFACE_INFO(
USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_3GS,
IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
IPHETH_USBINTF_PROTO) },
{ }
};
MODULE_DEVICE_TABLE(usb, ipheth_table);
struct ipheth_device {
struct usb_device *udev;
struct usb_interface *intf;
struct net_device *net;
struct sk_buff *tx_skb;
struct urb *tx_urb;
struct urb *rx_urb;
unsigned char *tx_buf;
unsigned char *rx_buf;
unsigned char *ctrl_buf;
u8 bulk_in;
u8 bulk_out;
struct delayed_work carrier_work;
};
static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags);
static int ipheth_alloc_urbs(struct ipheth_device *iphone)
{
struct urb *tx_urb = NULL;
struct urb *rx_urb = NULL;
u8 *tx_buf = NULL;
u8 *rx_buf = NULL;
tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (tx_urb == NULL)
goto error;
rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (rx_urb == NULL)
goto error;
tx_buf = usb_buffer_alloc(iphone->udev,
IPHETH_BUF_SIZE,
GFP_KERNEL,
&tx_urb->transfer_dma);
if (tx_buf == NULL)
goto error;
rx_buf = usb_buffer_alloc(iphone->udev,
IPHETH_BUF_SIZE,
GFP_KERNEL,
&rx_urb->transfer_dma);
if (rx_buf == NULL)
goto error;
iphone->tx_urb = tx_urb;
iphone->rx_urb = rx_urb;
iphone->tx_buf = tx_buf;
iphone->rx_buf = rx_buf;
return 0;
error:
usb_buffer_free(iphone->udev, IPHETH_BUF_SIZE, rx_buf,
rx_urb->transfer_dma);
usb_buffer_free(iphone->udev, IPHETH_BUF_SIZE, tx_buf,
tx_urb->transfer_dma);
usb_free_urb(rx_urb);
usb_free_urb(tx_urb);
return -ENOMEM;
}
static void ipheth_free_urbs(struct ipheth_device *iphone)
{
usb_buffer_free(iphone->udev, IPHETH_BUF_SIZE, iphone->rx_buf,
iphone->rx_urb->transfer_dma);
usb_buffer_free(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf,
iphone->tx_urb->transfer_dma);
usb_free_urb(iphone->rx_urb);
usb_free_urb(iphone->tx_urb);
}
static void ipheth_kill_urbs(struct ipheth_device *dev)
{
usb_kill_urb(dev->tx_urb);
usb_kill_urb(dev->rx_urb);
}
static void ipheth_rcvbulk_callback(struct urb *urb)
{
struct ipheth_device *dev;
struct sk_buff *skb;
int status;
char *buf;
int len;
dev = urb->context;
if (dev == NULL)
return;
status = urb->status;
switch (status) {
case -ENOENT:
case -ECONNRESET:
case -ESHUTDOWN:
return;
case 0:
break;
default:
err("%s: urb status: %d", __func__, urb->status);
return;
}
len = urb->actual_length;
buf = urb->transfer_buffer;
skb = dev_alloc_skb(NET_IP_ALIGN + len);
if (!skb) {
err("%s: dev_alloc_skb: -ENOMEM", __func__);
dev->net->stats.rx_dropped++;
return;
}
skb_reserve(skb, NET_IP_ALIGN);
memcpy(skb_put(skb, len), buf + NET_IP_ALIGN, len - NET_IP_ALIGN);
skb->dev = dev->net;
skb->protocol = eth_type_trans(skb, dev->net);
dev->net->stats.rx_packets++;
dev->net->stats.rx_bytes += len;
netif_rx(skb);
ipheth_rx_submit(dev, GFP_ATOMIC);
}
static void ipheth_sndbulk_callback(struct urb *urb)
{
struct ipheth_device *dev;
dev = urb->context;
if (dev == NULL)
return;
if (urb->status != 0 &&
urb->status != -ENOENT &&
urb->status != -ECONNRESET &&
urb->status != -ESHUTDOWN)
err("%s: urb status: %d", __func__, urb->status);
dev_kfree_skb_irq(dev->tx_skb);
netif_wake_queue(dev->net);
}
static int ipheth_carrier_set(struct ipheth_device *dev)
{
struct usb_device *udev = dev->udev;
int retval;
retval = usb_control_msg(udev,
usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP),
IPHETH_CMD_CARRIER_CHECK, /* request */
0xc0, /* request type */
0x00, /* value */
0x02, /* index */
dev->ctrl_buf, IPHETH_CTRL_BUF_SIZE,
IPHETH_CTRL_TIMEOUT);
if (retval < 0) {
err("%s: usb_control_msg: %d", __func__, retval);
return retval;
}
if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON)
netif_carrier_on(dev->net);
else
netif_carrier_off(dev->net);
return 0;
}
static void ipheth_carrier_check_work(struct work_struct *work)
{
struct ipheth_device *dev = container_of(work, struct ipheth_device,
carrier_work.work);
ipheth_carrier_set(dev);
schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT);
}
static int ipheth_get_macaddr(struct ipheth_device *dev)
{
struct usb_device *udev = dev->udev;
struct net_device *net = dev->net;
int retval;
retval = usb_control_msg(udev,
usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP),
IPHETH_CMD_GET_MACADDR, /* request */
0xc0, /* request type */
0x00, /* value */
0x02, /* index */
dev->ctrl_buf,
IPHETH_CTRL_BUF_SIZE,
IPHETH_CTRL_TIMEOUT);
if (retval < 0) {
err("%s: usb_control_msg: %d", __func__, retval);
} else if (retval < ETH_ALEN) {
err("%s: usb_control_msg: short packet: %d bytes",
__func__, retval);
retval = -EINVAL;
} else {
memcpy(net->dev_addr, dev->ctrl_buf, ETH_ALEN);
retval = 0;
}
return retval;
}
static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags)
{
struct usb_device *udev = dev->udev;
int retval;
usb_fill_bulk_urb(dev->rx_urb, udev,
usb_rcvbulkpipe(udev, dev->bulk_in),
dev->rx_buf, IPHETH_BUF_SIZE,
ipheth_rcvbulk_callback,
dev);
dev->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
retval = usb_submit_urb(dev->rx_urb, mem_flags);
if (retval)
err("%s: usb_submit_urb: %d", __func__, retval);
return retval;
}
static int ipheth_open(struct net_device *net)
{
struct ipheth_device *dev = netdev_priv(net);
struct usb_device *udev = dev->udev;
int retval = 0;
usb_set_interface(udev, IPHETH_INTFNUM, IPHETH_ALT_INTFNUM);
retval = ipheth_carrier_set(dev);
if (retval)
return retval;
retval = ipheth_rx_submit(dev, GFP_KERNEL);
if (retval)
return retval;
schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT);
netif_start_queue(net);
return retval;
}
static int ipheth_close(struct net_device *net)
{
struct ipheth_device *dev = netdev_priv(net);
cancel_delayed_work_sync(&dev->carrier_work);
netif_stop_queue(net);
return 0;
}
static int ipheth_tx(struct sk_buff *skb, struct net_device *net)
{
struct ipheth_device *dev = netdev_priv(net);
struct usb_device *udev = dev->udev;
int retval;
/* Paranoid */
if (skb->len > IPHETH_BUF_SIZE) {
WARN(1, "%s: skb too large: %d bytes", __func__, skb->len);
dev->net->stats.tx_dropped++;
dev_kfree_skb_irq(skb);
return NETDEV_TX_OK;
}
memcpy(dev->tx_buf, skb->data, skb->len);
if (skb->len < IPHETH_BUF_SIZE)
memset(dev->tx_buf + skb->len, 0, IPHETH_BUF_SIZE - skb->len);
usb_fill_bulk_urb(dev->tx_urb, udev,
usb_sndbulkpipe(udev, dev->bulk_out),
dev->tx_buf, IPHETH_BUF_SIZE,
ipheth_sndbulk_callback,
dev);
dev->tx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
retval = usb_submit_urb(dev->tx_urb, GFP_ATOMIC);
if (retval) {
err("%s: usb_submit_urb: %d", __func__, retval);
dev->net->stats.tx_errors++;
dev_kfree_skb_irq(skb);
} else {
dev->tx_skb = skb;
dev->net->stats.tx_packets++;
dev->net->stats.tx_bytes += skb->len;
netif_stop_queue(net);
}
return NETDEV_TX_OK;
}
static void ipheth_tx_timeout(struct net_device *net)
{
struct ipheth_device *dev = netdev_priv(net);
err("%s: TX timeout", __func__);
dev->net->stats.tx_errors++;
usb_unlink_urb(dev->tx_urb);
}
static struct net_device_stats *ipheth_stats(struct net_device *net)
{
struct ipheth_device *dev = netdev_priv(net);
return &dev->net->stats;
}
static u32 ipheth_ethtool_op_get_link(struct net_device *net)
{
struct ipheth_device *dev = netdev_priv(net);
return netif_carrier_ok(dev->net);
}
static struct ethtool_ops ops = {
.get_link = ipheth_ethtool_op_get_link
};
static const struct net_device_ops ipheth_netdev_ops = {
.ndo_open = &ipheth_open,
.ndo_stop = &ipheth_close,
.ndo_start_xmit = &ipheth_tx,
.ndo_tx_timeout = &ipheth_tx_timeout,
.ndo_get_stats = &ipheth_stats,
};
static struct device_type ipheth_type = {
.name = "wwan",
};
static int ipheth_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct usb_host_interface *hintf;
struct usb_endpoint_descriptor *endp;
struct ipheth_device *dev;
struct net_device *netdev;
int i;
int retval;
netdev = alloc_etherdev(sizeof(struct ipheth_device));
if (!netdev)
return -ENOMEM;
netdev->netdev_ops = &ipheth_netdev_ops;
netdev->watchdog_timeo = IPHETH_TX_TIMEOUT;
strcpy(netdev->name, "wwan%d");
dev = netdev_priv(netdev);
dev->udev = udev;
dev->net = netdev;
dev->intf = intf;
/* Set up endpoints */
hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM);
if (hintf == NULL) {
retval = -ENODEV;
err("Unable to find alternate settings interface");
goto err_endpoints;
}
for (i = 0; i < hintf->desc.bNumEndpoints; i++) {
endp = &hintf->endpoint[i].desc;
if (usb_endpoint_is_bulk_in(endp))
dev->bulk_in = endp->bEndpointAddress;
else if (usb_endpoint_is_bulk_out(endp))
dev->bulk_out = endp->bEndpointAddress;
}
if (!(dev->bulk_in && dev->bulk_out)) {
retval = -ENODEV;
err("Unable to find endpoints");
goto err_endpoints;
}
dev->ctrl_buf = kmalloc(IPHETH_CTRL_BUF_SIZE, GFP_KERNEL);
if (dev->ctrl_buf == NULL) {
retval = -ENOMEM;
goto err_alloc_ctrl_buf;
}
retval = ipheth_get_macaddr(dev);
if (retval)
goto err_get_macaddr;
INIT_DELAYED_WORK(&dev->carrier_work, ipheth_carrier_check_work);
retval = ipheth_alloc_urbs(dev);
if (retval) {
err("error allocating urbs: %d", retval);
goto err_alloc_urbs;
}
usb_set_intfdata(intf, dev);
SET_NETDEV_DEV(netdev, &intf->dev);
SET_ETHTOOL_OPS(netdev, &ops);
SET_NETDEV_DEVTYPE(netdev, &ipheth_type);
retval = register_netdev(netdev);
if (retval) {
err("error registering netdev: %d", retval);
retval = -EIO;
goto err_register_netdev;
}
dev_info(&intf->dev, "Apple iPhone USB Ethernet device attached\n");
return 0;
err_register_netdev:
ipheth_free_urbs(dev);
err_alloc_urbs:
err_get_macaddr:
err_alloc_ctrl_buf:
kfree(dev->ctrl_buf);
err_endpoints:
free_netdev(netdev);
return retval;
}
static void ipheth_disconnect(struct usb_interface *intf)
{
struct ipheth_device *dev;
dev = usb_get_intfdata(intf);
if (dev != NULL) {
unregister_netdev(dev->net);
ipheth_kill_urbs(dev);
ipheth_free_urbs(dev);
kfree(dev->ctrl_buf);
free_netdev(dev->net);
}
usb_set_intfdata(intf, NULL);
dev_info(&intf->dev, "Apple iPhone USB Ethernet now disconnected\n");
}
static struct usb_driver ipheth_driver = {
.name = "ipheth",
.probe = ipheth_probe,
.disconnect = ipheth_disconnect,
.id_table = ipheth_table,
};
static int __init ipheth_init(void)
{
int retval;
retval = usb_register(&ipheth_driver);
if (retval) {
err("usb_register failed: %d", retval);
return retval;
}
return 0;
}
static void __exit ipheth_exit(void)
{
usb_deregister(&ipheth_driver);
}
module_init(ipheth_init);
module_exit(ipheth_exit);
MODULE_AUTHOR("Diego Giagio <diego@giagio.com>");
MODULE_DESCRIPTION("Apple iPhone USB Ethernet driver");
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -1319,10 +1319,11 @@ replay:
err = ops->newlink(net, dev, tb, data);
else
err = register_netdevice(dev);
if (err < 0 && !IS_ERR(dev)) {
if (err < 0 && !IS_ERR(dev))
free_netdev(dev);
if (err < 0)
goto out;
}
err = rtnl_configure_link(dev, ifm);
if (err < 0)

View File

@ -151,6 +151,9 @@ static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg,
dev_load(sock_net(sk), ifr.ifr_name);
dev = dev_get_by_name(sock_net(sk), ifr.ifr_name);
if (!dev)
return -ENODEV;
if (dev->type == ARPHRD_IEEE802154 && dev->netdev_ops->ndo_do_ioctl)
ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd);

View File

@ -70,13 +70,17 @@ int inet_csk_bind_conflict(const struct sock *sk,
(!sk->sk_bound_dev_if ||
!sk2->sk_bound_dev_if ||
sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) {
const __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
if (!reuse || !sk2->sk_reuse ||
sk2->sk_state == TCP_LISTEN) {
const __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
if (!sk2_rcv_saddr || !sk_rcv_saddr ||
sk2_rcv_saddr == sk_rcv_saddr)
break;
}
} else if (reuse && sk2->sk_reuse &&
sk2_rcv_saddr &&
sk2_rcv_saddr == sk_rcv_saddr)
break;
}
}
return node != NULL;
@ -120,9 +124,11 @@ again:
smallest_size = tb->num_owners;
smallest_rover = rover;
if (atomic_read(&hashinfo->bsockets) > (high - low) + 1) {
spin_unlock(&head->lock);
snum = smallest_rover;
goto have_snum;
if (!inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb)) {
spin_unlock(&head->lock);
snum = smallest_rover;
goto have_snum;
}
}
}
goto next;

View File

@ -42,11 +42,16 @@ int inet6_csk_bind_conflict(const struct sock *sk,
if (sk != sk2 &&
(!sk->sk_bound_dev_if ||
!sk2->sk_bound_dev_if ||
sk->sk_bound_dev_if == sk2->sk_bound_dev_if) &&
(!sk->sk_reuse || !sk2->sk_reuse ||
sk2->sk_state == TCP_LISTEN) &&
ipv6_rcv_saddr_equal(sk, sk2))
break;
sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) {
if ((!sk->sk_reuse || !sk2->sk_reuse ||
sk2->sk_state == TCP_LISTEN) &&
ipv6_rcv_saddr_equal(sk, sk2))
break;
else if (sk->sk_reuse && sk2->sk_reuse &&
!ipv6_addr_any(inet6_rcv_saddr(sk)) &&
ipv6_rcv_saddr_equal(sk, sk2))
break;
}
}
return node != NULL;

View File

@ -625,7 +625,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
/* We must not fragment if the socket is set to force MTU discovery
* or if the skb it not generated by a local socket.
*/
if (!skb->local_df) {
if (!skb->local_df && skb->len > mtu) {
skb->dev = skb_dst(skb)->dev;
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),

View File

@ -815,7 +815,7 @@ struct dst_entry * ip6_route_output(struct net *net, struct sock *sk,
{
int flags = 0;
if (rt6_need_strict(&fl->fl6_dst))
if (fl->oif || rt6_need_strict(&fl->fl6_dst))
flags |= RT6_LOOKUP_F_IFACE;
if (!ipv6_addr_any(&fl->fl6_src))

View File

@ -94,7 +94,7 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
xdst->u.dst.dev = dev;
dev_hold(dev);
xdst->u.rt6.rt6i_idev = in6_dev_get(rt->u.dst.dev);
xdst->u.rt6.rt6i_idev = in6_dev_get(dev);
if (!xdst->u.rt6.rt6i_idev)
return -ENODEV;

View File

@ -133,7 +133,7 @@ static int __init rds_rdma_listen_init(void)
ret = PTR_ERR(cm_id);
printk(KERN_ERR "RDS/RDMA: failed to setup listener, "
"rdma_create_id() returned %d\n", ret);
goto out;
return ret;
}
sin.sin_family = AF_INET,

View File

@ -402,6 +402,7 @@ static void __x25_destroy_socket(struct sock *sk)
/*
* Queue the unaccepted socket for death
*/
skb->sk->sk_state = TCP_LISTEN;
sock_set_flag(skb->sk, SOCK_DEAD);
x25_start_heartbeat(skb->sk);
x25_sk(skb->sk)->state = X25_STATE_0;