diff options
Diffstat (limited to 'drivers/net')
98 files changed, 2272 insertions, 476 deletions
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index f142cc21e453..deaa8bc16cf8 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -711,14 +711,14 @@ static int __devinit a2065_init_one(struct zorro_dev *z, return -EBUSY; r2 = request_mem_region(mem_start, A2065_RAM_SIZE, "RAM"); if (!r2) { - release_resource(r1); + release_mem_region(base_addr, sizeof(struct lance_regs)); return -EBUSY; } dev = alloc_etherdev(sizeof(struct lance_private)); if (dev == NULL) { - release_resource(r1); - release_resource(r2); + release_mem_region(base_addr, sizeof(struct lance_regs)); + release_mem_region(mem_start, A2065_RAM_SIZE); return -ENOMEM; } @@ -764,8 +764,8 @@ static int __devinit a2065_init_one(struct zorro_dev *z, err = register_netdev(dev); if (err) { - release_resource(r1); - release_resource(r2); + release_mem_region(base_addr, sizeof(struct lance_regs)); + release_mem_region(mem_start, A2065_RAM_SIZE); free_netdev(dev); return err; } diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 7ca0eded2561..b7f45cd756a2 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -182,14 +182,14 @@ static int __devinit ariadne_init_one(struct zorro_dev *z, return -EBUSY; r2 = request_mem_region(mem_start, ARIADNE_RAM_SIZE, "RAM"); if (!r2) { - release_resource(r1); + release_mem_region(base_addr, sizeof(struct Am79C960)); return -EBUSY; } dev = alloc_etherdev(sizeof(struct ariadne_private)); if (dev == NULL) { - release_resource(r1); - release_resource(r2); + release_mem_region(base_addr, sizeof(struct Am79C960)); + release_mem_region(mem_start, ARIADNE_RAM_SIZE); return -ENOMEM; } @@ -213,8 +213,8 @@ static int __devinit ariadne_init_one(struct zorro_dev *z, err = register_netdev(dev); if (err) { - release_resource(r1); - release_resource(r2); + release_mem_region(base_addr, sizeof(struct Am79C960)); + release_mem_region(mem_start, ARIADNE_RAM_SIZE); free_netdev(dev); return err; } diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index e637e9f28fd4..937ef1afa5db 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -1996,13 +1996,15 @@ static int atl2_set_eeprom(struct net_device *netdev, if (!eeprom_buff) return -ENOMEM; - ptr = (u32 *)eeprom_buff; + ptr = eeprom_buff; if (eeprom->offset & 3) { /* need read/modify/write of first changed EEPROM word */ /* only the second byte of the word is being modified */ - if (!atl2_read_eeprom(hw, first_dword*4, &(eeprom_buff[0]))) - return -EIO; + if (!atl2_read_eeprom(hw, first_dword*4, &(eeprom_buff[0]))) { + ret_val = -EIO; + goto out; + } ptr++; } if (((eeprom->offset + eeprom->len) & 3)) { @@ -2011,18 +2013,22 @@ static int atl2_set_eeprom(struct net_device *netdev, * only the first byte of the word is being modified */ if (!atl2_read_eeprom(hw, last_dword * 4, - &(eeprom_buff[last_dword - first_dword]))) - return -EIO; + &(eeprom_buff[last_dword - first_dword]))) { + ret_val = -EIO; + goto out; + } } /* Device's eeprom is always little-endian, word addressable */ memcpy(ptr, bytes, eeprom->len); for (i = 0; i < last_dword - first_dword + 1; i++) { - if (!atl2_write_eeprom(hw, ((first_dword+i)*4), eeprom_buff[i])) - return -EIO; + if (!atl2_write_eeprom(hw, ((first_dword+i)*4), eeprom_buff[i])) { + ret_val = -EIO; + goto out; + } } - + out: kfree(eeprom_buff); return ret_val; } diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 22abfb39d813..68d45ba2d9b9 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -1237,8 +1237,17 @@ static int bfin_mac_enable(struct phy_device *phydev) if (phydev->interface == PHY_INTERFACE_MODE_RMII) { opmode |= RMII; /* For Now only 100MBit are supported */ -#if (defined(CONFIG_BF537) || defined(CONFIG_BF536)) && CONFIG_BF_REV_0_2 - opmode |= TE; +#if defined(CONFIG_BF537) || defined(CONFIG_BF536) + if (__SILICON_REVISION__ < 3) { + /* + * This isn't publicly documented (fun times!), but in + * silicon <=0.2, the RX and TX pins are clocked together. + * So in order to recv, we must enable the transmit side + * as well. This will cause a spurious TX interrupt too, + * but we can easily consume that. + */ + opmode |= TE; + } #endif } diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index d1865cc97313..8e6d618b5305 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -8317,7 +8317,7 @@ static const struct net_device_ops bnx2_netdev_ops = { #endif }; -static void inline vlan_features_add(struct net_device *dev, u32 flags) +static inline void vlan_features_add(struct net_device *dev, u32 flags) { dev->vlan_features |= flags; } diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index 118c28aa471e..4b3e35878406 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -74,7 +74,7 @@ struct tlb_client_info { * packets to a Client that the Hash function * gave this entry index. */ - u32 tx_bytes; /* Each Client acumulates the BytesTx that + u32 tx_bytes; /* Each Client accumulates the BytesTx that * were tranmitted to it, and after each * CallBack the LoadHistory is devided * by the balance interval diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 1a6e9eb7af43..16d6fe954695 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1482,21 +1482,16 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) { struct sk_buff *skb = *pskb; struct slave *slave; - struct net_device *bond_dev; struct bonding *bond; - slave = bond_slave_get_rcu(skb->dev); - bond_dev = ACCESS_ONCE(slave->dev->master); - if (unlikely(!bond_dev)) - return RX_HANDLER_PASS; - skb = skb_share_check(skb, GFP_ATOMIC); if (unlikely(!skb)) return RX_HANDLER_CONSUMED; *pskb = skb; - bond = netdev_priv(bond_dev); + slave = bond_slave_get_rcu(skb->dev); + bond = slave->bond; if (bond->params.arp_interval) slave->dev->last_rx = jiffies; @@ -1505,10 +1500,10 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) return RX_HANDLER_EXACT; } - skb->dev = bond_dev; + skb->dev = bond->dev; if (bond->params.mode == BOND_MODE_ALB && - bond_dev->priv_flags & IFF_BRIDGE_PORT && + bond->dev->priv_flags & IFF_BRIDGE_PORT && skb->pkt_type == PACKET_HOST) { if (unlikely(skb_cow_head(skb, @@ -1516,7 +1511,7 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) kfree_skb(skb); return RX_HANDLER_CONSUMED; } - memcpy(eth_hdr(skb)->h_dest, bond_dev->dev_addr, ETH_ALEN); + memcpy(eth_hdr(skb)->h_dest, bond->dev->dev_addr, ETH_ALEN); } return RX_HANDLER_ANOTHER; @@ -1698,20 +1693,15 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) pr_debug("Error %d calling netdev_set_bond_master\n", res); goto err_restore_mac; } - res = netdev_rx_handler_register(slave_dev, bond_handle_frame, - new_slave); - if (res) { - pr_debug("Error %d calling netdev_rx_handler_register\n", res); - goto err_unset_master; - } /* open the slave since the application closed it */ res = dev_open(slave_dev); if (res) { pr_debug("Opening slave %s failed\n", slave_dev->name); - goto err_unreg_rxhandler; + goto err_unset_master; } + new_slave->bond = bond; new_slave->dev = slave_dev; slave_dev->priv_flags |= IFF_BONDING; @@ -1907,6 +1897,13 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (res) goto err_close; + res = netdev_rx_handler_register(slave_dev, bond_handle_frame, + new_slave); + if (res) { + pr_debug("Error %d calling netdev_rx_handler_register\n", res); + goto err_dest_symlinks; + } + pr_info("%s: enslaving %s as a%s interface with a%s link.\n", bond_dev->name, slave_dev->name, bond_is_active_slave(new_slave) ? "n active" : " backup", @@ -1916,13 +1913,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) return 0; /* Undo stages on error */ +err_dest_symlinks: + bond_destroy_slave_symlinks(bond_dev, slave_dev); + err_close: dev_close(slave_dev); -err_unreg_rxhandler: - netdev_rx_handler_unregister(slave_dev); - synchronize_net(); - err_unset_master: netdev_set_bond_master(slave_dev, NULL); @@ -1988,6 +1984,14 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) return -EINVAL; } + /* unregister rx_handler early so bond_handle_frame wouldn't be called + * for this slave anymore. + */ + netdev_rx_handler_unregister(slave_dev); + write_unlock_bh(&bond->lock); + synchronize_net(); + write_lock_bh(&bond->lock); + if (!bond->params.fail_over_mac) { if (!compare_ether_addr(bond_dev->dev_addr, slave->perm_hwaddr) && bond->slave_cnt > 1) @@ -2104,8 +2108,6 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) netif_addr_unlock_bh(bond_dev); } - netdev_rx_handler_unregister(slave_dev); - synchronize_net(); netdev_set_bond_master(slave_dev, NULL); slave_disable_netpoll(slave); @@ -2130,7 +2132,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) } /* -* First release a slave and than destroy the bond if no more slaves are left. +* First release a slave and then destroy the bond if no more slaves are left. * Must be under rtnl_lock when this function is called. */ static int bond_release_and_destroy(struct net_device *bond_dev, @@ -2186,6 +2188,12 @@ static int bond_release_all(struct net_device *bond_dev) */ write_unlock_bh(&bond->lock); + /* unregister rx_handler early so bond_handle_frame wouldn't + * be called for this slave anymore. + */ + netdev_rx_handler_unregister(slave_dev); + synchronize_net(); + if (bond_is_lb(bond)) { /* must be called only after the slave * has been detached from the list @@ -2217,8 +2225,6 @@ static int bond_release_all(struct net_device *bond_dev) netif_addr_unlock_bh(bond_dev); } - netdev_rx_handler_unregister(slave_dev); - synchronize_net(); netdev_set_bond_master(slave_dev, NULL); slave_disable_netpoll(slave); diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 6b26962fd0ec..90736cb4d975 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -187,6 +187,7 @@ struct slave { struct net_device *dev; /* first - useful for panic debug */ struct slave *next; struct slave *prev; + struct bonding *bond; /* our master */ int delay; unsigned long jiffies; unsigned long last_arp_rx; diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile index b38d987da67d..9560b9d624bd 100644 --- a/drivers/net/caif/Makefile +++ b/drivers/net/caif/Makefile @@ -1,6 +1,4 @@ -ifeq ($(CONFIG_CAIF_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG -endif +ccflags-$(CONFIG_CAIF_DEBUG) := -DDEBUG # Serial interface obj-$(CONFIG_CAIF_TTY) += caif_serial.o diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index 14050786218a..31552959aed7 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -588,14 +588,9 @@ static void c_can_chip_config(struct net_device *dev) { struct c_can_priv *priv = netdev_priv(dev); - if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT) - /* disable automatic retransmission */ - priv->write_reg(priv, &priv->regs->control, - CONTROL_DISABLE_AR); - else - /* enable automatic retransmission */ - priv->write_reg(priv, &priv->regs->control, - CONTROL_ENABLE_AR); + /* enable automatic retransmission */ + priv->write_reg(priv, &priv->regs->control, + CONTROL_ENABLE_AR); if (priv->can.ctrlmode & (CAN_CTRLMODE_LISTENONLY & CAN_CTRLMODE_LOOPBACK)) { @@ -633,9 +628,6 @@ static void c_can_start(struct net_device *dev) { struct c_can_priv *priv = netdev_priv(dev); - /* enable status change, error and module interrupts */ - c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS); - /* basic c_can configuration */ c_can_chip_config(dev); @@ -643,6 +635,9 @@ static void c_can_start(struct net_device *dev) /* reset tx helper pointers */ priv->tx_next = priv->tx_echo = 0; + + /* enable status change, error and module interrupts */ + c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS); } static void c_can_stop(struct net_device *dev) @@ -704,7 +699,6 @@ static void c_can_do_tx(struct net_device *dev) for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) { msg_obj_no = get_tx_echo_msg_obj(priv); - c_can_inval_msg_object(dev, 0, msg_obj_no); val = c_can_read_reg32(priv, &priv->regs->txrqst1); if (!(val & (1 << msg_obj_no))) { can_get_echo_skb(dev, @@ -713,6 +707,7 @@ static void c_can_do_tx(struct net_device *dev) &priv->regs->ifregs[0].msg_cntrl) & IF_MCONT_DLC_MASK; stats->tx_packets++; + c_can_inval_msg_object(dev, 0, msg_obj_no); } } @@ -1112,8 +1107,7 @@ struct net_device *alloc_c_can_dev(void) priv->can.bittiming_const = &c_can_bittiming_const; priv->can.do_set_mode = c_can_set_mode; priv->can.do_get_berr_counter = c_can_get_berr_counter; - priv->can.ctrlmode_supported = CAN_CTRLMODE_ONE_SHOT | - CAN_CTRLMODE_LOOPBACK | + priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_BERR_REPORTING; diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index e629b961ae2d..cc90824f2c9c 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c @@ -73,7 +73,8 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev) void __iomem *addr; struct net_device *dev; struct c_can_priv *priv; - struct resource *mem, *irq; + struct resource *mem; + int irq; #ifdef CONFIG_HAVE_CLK struct clk *clk; @@ -88,8 +89,8 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev) /* get the platform data */ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!mem || (irq <= 0)) { + irq = platform_get_irq(pdev, 0); + if (!mem || irq <= 0) { ret = -ENODEV; goto exit_free_clk; } @@ -117,7 +118,7 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev) priv = netdev_priv(dev); - dev->irq = irq->start; + dev->irq = irq; priv->regs = addr; #ifdef CONFIG_HAVE_CLK priv->can.clock.freq = clk_get_rate(clk); diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index 366f5cc050ae..102b16c6cc97 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -15,6 +15,7 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/platform_device.h> +#include <linux/mfd/core.h> #include <linux/netdevice.h> #include <linux/can.h> @@ -1643,7 +1644,7 @@ static int __devinit ican3_probe(struct platform_device *pdev) struct device *dev; int ret; - pdata = pdev->dev.platform_data; + pdata = mfd_get_data(pdev); if (!pdata) return -ENXIO; diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 4d538a4e9d55..910893143295 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -1983,14 +1983,20 @@ static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) { struct port_info *pi = netdev_priv(dev); struct adapter *adapter = pi->adapter; - struct qset_params *qsp = &adapter->params.sge.qset[0]; - struct sge_qset *qs = &adapter->sge.qs[0]; + struct qset_params *qsp; + struct sge_qset *qs; + int i; if (c->rx_coalesce_usecs * 10 > M_NEWTIMER) return -EINVAL; - qsp->coalesce_usecs = c->rx_coalesce_usecs; - t3_update_qset_coalesce(qs, qsp); + for (i = 0; i < pi->nqsets; i++) { + qsp = &adapter->params.sge.qset[i]; + qs = &adapter->sge.qs[i]; + qsp->coalesce_usecs = c->rx_coalesce_usecs; + t3_update_qset_coalesce(qs, qsp); + } + return 0; } diff --git a/drivers/net/davinci_cpdma.c b/drivers/net/davinci_cpdma.c index e92b2b6cd8c4..ae47f23ba930 100644 --- a/drivers/net/davinci_cpdma.c +++ b/drivers/net/davinci_cpdma.c @@ -76,6 +76,7 @@ struct cpdma_desc { struct cpdma_desc_pool { u32 phys; + u32 hw_addr; void __iomem *iomap; /* ioremap map */ void *cpumap; /* dma_alloc map */ int desc_size, mem_size; @@ -137,7 +138,8 @@ struct cpdma_chan { * abstract out these details */ static struct cpdma_desc_pool * -cpdma_desc_pool_create(struct device *dev, u32 phys, int size, int align) +cpdma_desc_pool_create(struct device *dev, u32 phys, u32 hw_addr, + int size, int align) { int bitmap_size; struct cpdma_desc_pool *pool; @@ -161,10 +163,12 @@ cpdma_desc_pool_create(struct device *dev, u32 phys, int size, int align) if (phys) { pool->phys = phys; pool->iomap = ioremap(phys, size); + pool->hw_addr = hw_addr; } else { pool->cpumap = dma_alloc_coherent(dev, size, &pool->phys, GFP_KERNEL); pool->iomap = (void __force __iomem *)pool->cpumap; + pool->hw_addr = pool->phys; } if (pool->iomap) @@ -201,14 +205,14 @@ static inline dma_addr_t desc_phys(struct cpdma_desc_pool *pool, { if (!desc) return 0; - return pool->phys + (__force dma_addr_t)desc - + return pool->hw_addr + (__force dma_addr_t)desc - (__force dma_addr_t)pool->iomap; } static inline struct cpdma_desc __iomem * desc_from_phys(struct cpdma_desc_pool *pool, dma_addr_t dma) { - return dma ? pool->iomap + dma - pool->phys : NULL; + return dma ? pool->iomap + dma - pool->hw_addr : NULL; } static struct cpdma_desc __iomem * @@ -260,6 +264,7 @@ struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params) ctlr->pool = cpdma_desc_pool_create(ctlr->dev, ctlr->params.desc_mem_phys, + ctlr->params.desc_hw_addr, ctlr->params.desc_mem_size, ctlr->params.desc_align); if (!ctlr->pool) { diff --git a/drivers/net/davinci_cpdma.h b/drivers/net/davinci_cpdma.h index 868e50ebde45..afa19a0c0d81 100644 --- a/drivers/net/davinci_cpdma.h +++ b/drivers/net/davinci_cpdma.h @@ -33,6 +33,7 @@ struct cpdma_params { bool has_soft_reset; int min_packet_size; u32 desc_mem_phys; + u32 desc_hw_addr; int desc_mem_size; int desc_align; diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 082d6ea69920..baca6bfcb089 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -1854,10 +1854,13 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev) dma_params.rxcp = priv->emac_base + 0x660; dma_params.num_chan = EMAC_MAX_TXRX_CHANNELS; dma_params.min_packet_size = EMAC_DEF_MIN_ETHPKTSIZE; - dma_params.desc_mem_phys = hw_ram_addr; + dma_params.desc_hw_addr = hw_ram_addr; dma_params.desc_mem_size = pdata->ctrl_ram_size; dma_params.desc_align = 16; + dma_params.desc_mem_phys = pdata->no_bd_ram ? 0 : + (u32 __force)res->start + pdata->ctrl_ram_offset; + priv->dma = cpdma_ctlr_create(&dma_params); if (!priv->dma) { dev_err(emac_dev, "DaVinci EMAC: Error initializing DMA\n"); diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 317708113601..b7af5bab9937 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -621,9 +621,9 @@ static int dm9000_set_wol(struct net_device *dev, struct ethtool_wolinfo *w) /* change in wol state, update IRQ state */ if (!dm->wake_state) - set_irq_wake(dm->irq_wake, 1); + irq_set_irq_wake(dm->irq_wake, 1); else if (dm->wake_state & !opts) - set_irq_wake(dm->irq_wake, 0); + irq_set_irq_wake(dm->irq_wake, 0); } dm->wake_state = opts; @@ -1424,13 +1424,13 @@ dm9000_probe(struct platform_device *pdev) } else { /* test to see if irq is really wakeup capable */ - ret = set_irq_wake(db->irq_wake, 1); + ret = irq_set_irq_wake(db->irq_wake, 1); if (ret) { dev_err(db->dev, "irq %d cannot set wakeup (%d)\n", db->irq_wake, ret); ret = 0; } else { - set_irq_wake(db->irq_wake, 0); + irq_set_irq_wake(db->irq_wake, 0); db->wake_supported = 1; } } diff --git a/drivers/net/ftmac100.c b/drivers/net/ftmac100.c index 1d6f4b8d393a..a31661948c42 100644 --- a/drivers/net/ftmac100.c +++ b/drivers/net/ftmac100.c @@ -1102,7 +1102,7 @@ static int ftmac100_probe(struct platform_device *pdev) goto err_req_mem; } - priv->base = ioremap(res->start, res->end - res->start); + priv->base = ioremap(res->start, resource_size(res)); if (!priv->base) { dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n"); err = -EIO; diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index ccb231c4d933..2a0ad9a501bb 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -949,6 +949,11 @@ static void gfar_detect_errata(struct gfar_private *priv) (pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0)) priv->errata |= GFAR_ERRATA_A002; + /* MPC8313 Rev < 2.0, MPC8548 rev 2.0 */ + if ((pvr == 0x80850010 && mod == 0x80b0 && rev < 0x0020) || + (pvr == 0x80210020 && mod == 0x8030 && rev == 0x0020)) + priv->errata |= GFAR_ERRATA_12; + if (priv->errata) dev_info(dev, "enabled errata workarounds, flags: 0x%x\n", priv->errata); @@ -2154,8 +2159,15 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Set up checksumming */ if (CHECKSUM_PARTIAL == skb->ip_summed) { fcb = gfar_add_fcb(skb); - lstatus |= BD_LFLAG(TXBD_TOE); - gfar_tx_checksum(skb, fcb); + /* as specified by errata */ + if (unlikely(gfar_has_errata(priv, GFAR_ERRATA_12) + && ((unsigned long)fcb % 0x20) > 0x18)) { + __skb_pull(skb, GMAC_FCB_LEN); + skb_checksum_help(skb); + } else { + lstatus |= BD_LFLAG(TXBD_TOE); + gfar_tx_checksum(skb, fcb); + } } if (vlan_tx_tag_present(skb)) { diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 54de4135e932..ec5d595ce2e2 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -1039,6 +1039,7 @@ enum gfar_errata { GFAR_ERRATA_74 = 0x01, GFAR_ERRATA_76 = 0x02, GFAR_ERRATA_A002 = 0x04, + GFAR_ERRATA_12 = 0x08, /* a.k.a errata eTSEC49 */ }; /* Struct stolen almost completely (and shamelessly) from the FCC enet source diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 67c0ad42d818..186cd28a61cc 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -75,15 +75,9 @@ static int dongle_id = 0; /* default: probe */ /* We can't guess the type of connected dongle, user *must* supply it. */ module_param(dongle_id, int, 0); -/* FIXME : we should not need this, because instances should be automatically - * managed by the PCI layer. Especially that we seem to only be using the - * first entry. Jean II */ -/* Max 4 instances for now */ -static struct via_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL }; - /* Some prototypes */ -static int via_ircc_open(int i, chipio_t * info, unsigned int id); -static int via_ircc_close(struct via_ircc_cb *self); +static int via_ircc_open(struct pci_dev *pdev, chipio_t * info, + unsigned int id); static int via_ircc_dma_receive(struct via_ircc_cb *self); static int via_ircc_dma_receive_complete(struct via_ircc_cb *self, int iobase); @@ -215,7 +209,7 @@ static int __devinit via_init_one (struct pci_dev *pcidev, const struct pci_devi pci_write_config_byte(pcidev,0x42,(bTmp | 0xf0)); pci_write_config_byte(pcidev,0x5a,0xc0); WriteLPCReg(0x28, 0x70 ); - if (via_ircc_open(0, &info,0x3076) == 0) + if (via_ircc_open(pcidev, &info, 0x3076) == 0) rc=0; } else rc = -ENODEV; //IR not turn on @@ -254,7 +248,7 @@ static int __devinit via_init_one (struct pci_dev *pcidev, const struct pci_devi info.irq=FirIRQ; info.dma=FirDRQ1; info.dma2=FirDRQ0; - if (via_ircc_open(0, &info,0x3096) == 0) + if (via_ircc_open(pcidev, &info, 0x3096) == 0) rc=0; } else rc = -ENODEV; //IR not turn on !!!!! @@ -264,48 +258,10 @@ static int __devinit via_init_one (struct pci_dev *pcidev, const struct pci_devi return rc; } -/* - * Function via_ircc_clean () - * - * Close all configured chips - * - */ -static void via_ircc_clean(void) -{ - int i; - - IRDA_DEBUG(3, "%s()\n", __func__); - - for (i=0; i < ARRAY_SIZE(dev_self); i++) { - if (dev_self[i]) - via_ircc_close(dev_self[i]); - } -} - -static void __devexit via_remove_one (struct pci_dev *pdev) -{ - IRDA_DEBUG(3, "%s()\n", __func__); - - /* FIXME : This is ugly. We should use pci_get_drvdata(pdev); - * to get our driver instance and call directly via_ircc_close(). - * See vlsi_ir for details... - * Jean II */ - via_ircc_clean(); - - /* FIXME : This should be in via_ircc_close(), because here we may - * theoritically disable still configured devices :-( - Jean II */ - pci_disable_device(pdev); -} - static void __exit via_ircc_cleanup(void) { IRDA_DEBUG(3, "%s()\n", __func__); - /* FIXME : This should be redundant, as pci_unregister_driver() - * should call via_remove_one() on each device. - * Jean II */ - via_ircc_clean(); - /* Cleanup all instances of the driver */ pci_unregister_driver (&via_driver); } @@ -324,12 +280,13 @@ static const struct net_device_ops via_ircc_fir_ops = { }; /* - * Function via_ircc_open (iobase, irq) + * Function via_ircc_open(pdev, iobase, irq) * * Open driver instance * */ -static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) +static __devinit int via_ircc_open(struct pci_dev *pdev, chipio_t * info, + unsigned int id) { struct net_device *dev; struct via_ircc_cb *self; @@ -337,9 +294,6 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) IRDA_DEBUG(3, "%s()\n", __func__); - if (i >= ARRAY_SIZE(dev_self)) - return -ENOMEM; - /* Allocate new instance of the driver */ dev = alloc_irdadev(sizeof(struct via_ircc_cb)); if (dev == NULL) @@ -349,13 +303,8 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) self->netdev = dev; spin_lock_init(&self->lock); - /* FIXME : We should store our driver instance in the PCI layer, - * using pci_set_drvdata(), not in this array. - * See vlsi_ir for details... - Jean II */ - /* FIXME : 'i' is always 0 (see via_init_one()) :-( - Jean II */ - /* Need to store self somewhere */ - dev_self[i] = self; - self->index = i; + pci_set_drvdata(pdev, self); + /* Initialize Resource */ self->io.cfg_base = info->cfg_base; self->io.fir_base = info->fir_base; @@ -414,7 +363,7 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) /* Allocate memory if needed */ self->rx_buff.head = - dma_alloc_coherent(NULL, self->rx_buff.truesize, + dma_alloc_coherent(&pdev->dev, self->rx_buff.truesize, &self->rx_buff_dma, GFP_KERNEL); if (self->rx_buff.head == NULL) { err = -ENOMEM; @@ -423,7 +372,7 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) memset(self->rx_buff.head, 0, self->rx_buff.truesize); self->tx_buff.head = - dma_alloc_coherent(NULL, self->tx_buff.truesize, + dma_alloc_coherent(&pdev->dev, self->tx_buff.truesize, &self->tx_buff_dma, GFP_KERNEL); if (self->tx_buff.head == NULL) { err = -ENOMEM; @@ -455,33 +404,32 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) via_hw_init(self); return 0; err_out4: - dma_free_coherent(NULL, self->tx_buff.truesize, + dma_free_coherent(&pdev->dev, self->tx_buff.truesize, self->tx_buff.head, self->tx_buff_dma); err_out3: - dma_free_coherent(NULL, self->rx_buff.truesize, + dma_free_coherent(&pdev->dev, self->rx_buff.truesize, self->rx_buff.head, self->rx_buff_dma); err_out2: release_region(self->io.fir_base, self->io.fir_ext); err_out1: + pci_set_drvdata(pdev, NULL); free_netdev(dev); - dev_self[i] = NULL; return err; } /* - * Function via_ircc_close (self) + * Function via_remove_one(pdev) * * Close driver instance * */ -static int via_ircc_close(struct via_ircc_cb *self) +static void __devexit via_remove_one(struct pci_dev *pdev) { + struct via_ircc_cb *self = pci_get_drvdata(pdev); int iobase; IRDA_DEBUG(3, "%s()\n", __func__); - IRDA_ASSERT(self != NULL, return -1;); - iobase = self->io.fir_base; ResetChip(iobase, 5); //hardware reset. @@ -493,16 +441,16 @@ static int via_ircc_close(struct via_ircc_cb *self) __func__, self->io.fir_base); release_region(self->io.fir_base, self->io.fir_ext); if (self->tx_buff.head) - dma_free_coherent(NULL, self->tx_buff.truesize, + dma_free_coherent(&pdev->dev, self->tx_buff.truesize, self->tx_buff.head, self->tx_buff_dma); if (self->rx_buff.head) - dma_free_coherent(NULL, self->rx_buff.truesize, + dma_free_coherent(&pdev->dev, self->rx_buff.truesize, self->rx_buff.head, self->rx_buff_dma); - dev_self[self->index] = NULL; + pci_set_drvdata(pdev, NULL); free_netdev(self->netdev); - return 0; + pci_disable_device(pdev); } /* diff --git a/drivers/net/jme.c b/drivers/net/jme.c index f690474f4409..994c80939c7a 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -273,7 +273,7 @@ jme_clear_pm(struct jme_adapter *jme) { jwrite32(jme, JME_PMCS, 0xFFFF0000 | jme->reg_pmcs); pci_set_power_state(jme->pdev, PCI_D0); - pci_enable_wake(jme->pdev, PCI_D0, false); + device_set_wakeup_enable(&jme->pdev->dev, false); } static int @@ -2538,6 +2538,8 @@ jme_set_wol(struct net_device *netdev, jwrite32(jme, JME_PMCS, jme->reg_pmcs); + device_set_wakeup_enable(&jme->pdev->dev, jme->reg_pmcs); + return 0; } @@ -3172,9 +3174,9 @@ jme_shutdown(struct pci_dev *pdev) } #ifdef CONFIG_PM -static int -jme_suspend(struct pci_dev *pdev, pm_message_t state) +static int jme_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); struct jme_adapter *jme = netdev_priv(netdev); @@ -3206,22 +3208,18 @@ jme_suspend(struct pci_dev *pdev, pm_message_t state) tasklet_hi_enable(&jme->rxclean_task); tasklet_hi_enable(&jme->rxempty_task); - pci_save_state(pdev); jme_powersave_phy(jme); - pci_enable_wake(jme->pdev, PCI_D3hot, true); - pci_set_power_state(pdev, PCI_D3hot); return 0; } -static int -jme_resume(struct pci_dev *pdev) +static int jme_resume(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); struct jme_adapter *jme = netdev_priv(netdev); - jme_clear_pm(jme); - pci_restore_state(pdev); + jwrite32(jme, JME_PMCS, 0xFFFF0000 | jme->reg_pmcs); jme_phy_on(jme); if (test_bit(JME_FLAG_SSET, &jme->flags)) @@ -3238,6 +3236,13 @@ jme_resume(struct pci_dev *pdev) return 0; } + +static SIMPLE_DEV_PM_OPS(jme_pm_ops, jme_suspend, jme_resume); +#define JME_PM_OPS (&jme_pm_ops) + +#else + +#define JME_PM_OPS NULL #endif static DEFINE_PCI_DEVICE_TABLE(jme_pci_tbl) = { @@ -3251,11 +3256,8 @@ static struct pci_driver jme_driver = { .id_table = jme_pci_tbl, .probe = jme_init_one, .remove = __devexit_p(jme_remove_one), -#ifdef CONFIG_PM - .suspend = jme_suspend, - .resume = jme_resume, -#endif /* CONFIG_PM */ .shutdown = jme_shutdown, + .driver.pm = JME_PM_OPS, }; static int __init diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c index 928b2b83cef5..efd44afeae83 100644 --- a/drivers/net/ks8842.c +++ b/drivers/net/ks8842.c @@ -26,6 +26,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/mfd/core.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> @@ -1145,7 +1146,7 @@ static int __devinit ks8842_probe(struct platform_device *pdev) struct resource *iomem; struct net_device *netdev; struct ks8842_adapter *adapter; - struct ks8842_platform_data *pdata = pdev->dev.platform_data; + struct ks8842_platform_data *pdata = mfd_get_data(pdev); u16 id; unsigned i; diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c index 540a8dcbcc46..7f7d5708a658 100644 --- a/drivers/net/ksz884x.c +++ b/drivers/net/ksz884x.c @@ -4898,7 +4898,7 @@ static netdev_tx_t netdev_tx(struct sk_buff *skb, struct net_device *dev) goto unlock; } skb_copy_and_csum_dev(org_skb, skb->data); - org_skb->ip_summed = 0; + org_skb->ip_summed = CHECKSUM_NONE; skb->len = org_skb->len; copy_old_skb(org_skb, skb); } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 5b37d3c191e4..78e34e9e4f00 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -39,8 +39,11 @@ struct macvlan_port { struct list_head vlans; struct rcu_head rcu; bool passthru; + int count; }; +static void macvlan_port_destroy(struct net_device *dev); + #define macvlan_port_get_rcu(dev) \ ((struct macvlan_port *) rcu_dereference(dev->rx_handler_data)) #define macvlan_port_get(dev) ((struct macvlan_port *) dev->rx_handler_data) @@ -457,8 +460,13 @@ static int macvlan_init(struct net_device *dev) static void macvlan_uninit(struct net_device *dev) { struct macvlan_dev *vlan = netdev_priv(dev); + struct macvlan_port *port = vlan->port; free_percpu(vlan->pcpu_stats); + + port->count -= 1; + if (!port->count) + macvlan_port_destroy(port->dev); } static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev, @@ -691,12 +699,13 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); if (vlan->mode == MACVLAN_MODE_PASSTHRU) { - if (!list_empty(&port->vlans)) + if (port->count) return -EINVAL; port->passthru = true; memcpy(dev->dev_addr, lowerdev->dev_addr, ETH_ALEN); } + port->count += 1; err = register_netdevice(dev); if (err < 0) goto destroy_port; @@ -707,7 +716,8 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, return 0; destroy_port: - if (list_empty(&port->vlans)) + port->count -= 1; + if (!port->count) macvlan_port_destroy(lowerdev); return err; @@ -725,13 +735,9 @@ static int macvlan_newlink(struct net *src_net, struct net_device *dev, void macvlan_dellink(struct net_device *dev, struct list_head *head) { struct macvlan_dev *vlan = netdev_priv(dev); - struct macvlan_port *port = vlan->port; list_del(&vlan->list); unregister_netdevice_queue(dev, head); - - if (list_empty(&port->vlans)) - macvlan_port_destroy(port->dev); } EXPORT_SYMBOL_GPL(macvlan_dellink); diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/mlx4/alloc.c index 3a4277f6fac4..116cae334dad 100644 --- a/drivers/net/mlx4/alloc.c +++ b/drivers/net/mlx4/alloc.c @@ -62,6 +62,9 @@ u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap) } else obj = -1; + if (obj != -1) + --bitmap->avail; + spin_unlock(&bitmap->lock); return obj; @@ -101,11 +104,19 @@ u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align) } else obj = -1; + if (obj != -1) + bitmap->avail -= cnt; + spin_unlock(&bitmap->lock); return obj; } +u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap) +{ + return bitmap->avail; +} + void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt) { obj &= bitmap->max + bitmap->reserved_top - 1; @@ -115,6 +126,7 @@ void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt) bitmap->last = min(bitmap->last, obj); bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) & bitmap->mask; + bitmap->avail += cnt; spin_unlock(&bitmap->lock); } @@ -130,6 +142,7 @@ int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, bitmap->max = num - reserved_top; bitmap->mask = mask; bitmap->reserved_top = reserved_top; + bitmap->avail = num - reserved_top - reserved_bot; spin_lock_init(&bitmap->lock); bitmap->table = kzalloc(BITS_TO_LONGS(bitmap->max) * sizeof (long), GFP_KERNEL); diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c index 7cd34e9c7c7e..bd8ef9f2fa71 100644 --- a/drivers/net/mlx4/cq.c +++ b/drivers/net/mlx4/cq.c @@ -198,7 +198,7 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, u64 mtt_addr; int err; - if (vector >= dev->caps.num_comp_vectors) + if (vector > dev->caps.num_comp_vectors + dev->caps.comp_pool) return -EINVAL; cq->vector = vector; diff --git a/drivers/net/mlx4/en_cq.c b/drivers/net/mlx4/en_cq.c index 21786ad4455e..ec4b6d047fe0 100644 --- a/drivers/net/mlx4/en_cq.c +++ b/drivers/net/mlx4/en_cq.c @@ -51,13 +51,10 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv, int err; cq->size = entries; - if (mode == RX) { + if (mode == RX) cq->buf_size = cq->size * sizeof(struct mlx4_cqe); - cq->vector = ring % mdev->dev->caps.num_comp_vectors; - } else { + else cq->buf_size = sizeof(struct mlx4_cqe); - cq->vector = 0; - } cq->ring = ring; cq->is_tx = mode; @@ -80,7 +77,8 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv, int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) { struct mlx4_en_dev *mdev = priv->mdev; - int err; + int err = 0; + char name[25]; cq->dev = mdev->pndev[priv->port]; cq->mcq.set_ci_db = cq->wqres.db.db; @@ -89,6 +87,29 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) *cq->mcq.arm_db = 0; memset(cq->buf, 0, cq->buf_size); + if (cq->is_tx == RX) { + if (mdev->dev->caps.comp_pool) { + if (!cq->vector) { + sprintf(name , "%s-rx-%d", priv->dev->name, cq->ring); + if (mlx4_assign_eq(mdev->dev, name, &cq->vector)) { + cq->vector = (cq->ring + 1 + priv->port) % + mdev->dev->caps.num_comp_vectors; + mlx4_warn(mdev, "Failed Assigning an EQ to " + "%s_rx-%d ,Falling back to legacy EQ's\n", + priv->dev->name, cq->ring); + } + } + } else { + cq->vector = (cq->ring + 1 + priv->port) % + mdev->dev->caps.num_comp_vectors; + } + } else { + if (!cq->vector || !mdev->dev->caps.comp_pool) { + /*Fallback to legacy pool in case of error*/ + cq->vector = 0; + } + } + if (!cq->is_tx) cq->size = priv->rx_ring[cq->ring].actual_size; @@ -112,12 +133,15 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) return 0; } -void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) +void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, + bool reserve_vectors) { struct mlx4_en_dev *mdev = priv->mdev; mlx4_en_unmap_buffer(&cq->wqres.buf); mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); + if (priv->mdev->dev->caps.comp_pool && cq->vector && !reserve_vectors) + mlx4_release_eq(priv->mdev->dev, cq->vector); cq->buf_size = 0; cq->buf = NULL; } diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c index 056152b3ff58..d54b7abf0225 100644 --- a/drivers/net/mlx4/en_ethtool.c +++ b/drivers/net/mlx4/en_ethtool.c @@ -45,7 +45,7 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; - sprintf(drvinfo->driver, DRV_NAME " (%s)", mdev->dev->board_id); + strncpy(drvinfo->driver, DRV_NAME, 32); strncpy(drvinfo->version, DRV_VERSION " (" DRV_RELDATE ")", 32); sprintf(drvinfo->fw_version, "%d.%d.%d", (u16) (mdev->dev->caps.fw_ver >> 32), @@ -131,8 +131,65 @@ static void mlx4_en_set_msglevel(struct net_device *dev, u32 val) static void mlx4_en_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { - wol->supported = 0; - wol->wolopts = 0; + struct mlx4_en_priv *priv = netdev_priv(netdev); + int err = 0; + u64 config = 0; + + if (!priv->mdev->dev->caps.wol) { + wol->supported = 0; + wol->wolopts = 0; + return; + } + + err = mlx4_wol_read(priv->mdev->dev, &config, priv->port); + if (err) { + en_err(priv, "Failed to get WoL information\n"); + return; + } + + if (config & MLX4_EN_WOL_MAGIC) + wol->supported = WAKE_MAGIC; + else + wol->supported = 0; + + if (config & MLX4_EN_WOL_ENABLED) + wol->wolopts = WAKE_MAGIC; + else + wol->wolopts = 0; +} + +static int mlx4_en_set_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct mlx4_en_priv *priv = netdev_priv(netdev); + u64 config = 0; + int err = 0; + + if (!priv->mdev->dev->caps.wol) + return -EOPNOTSUPP; + + if (wol->supported & ~WAKE_MAGIC) + return -EINVAL; + + err = mlx4_wol_read(priv->mdev->dev, &config, priv->port); + if (err) { + en_err(priv, "Failed to get WoL info, unable to modify\n"); + return err; + } + + if (wol->wolopts & WAKE_MAGIC) { + config |= MLX4_EN_WOL_DO_MODIFY | MLX4_EN_WOL_ENABLED | + MLX4_EN_WOL_MAGIC; + } else { + config &= ~(MLX4_EN_WOL_ENABLED | MLX4_EN_WOL_MAGIC); + config |= MLX4_EN_WOL_DO_MODIFY; + } + + err = mlx4_wol_write(priv->mdev->dev, config, priv->port); + if (err) + en_err(priv, "Failed to set WoL information\n"); + + return err; } static int mlx4_en_get_sset_count(struct net_device *dev, int sset) @@ -388,7 +445,7 @@ static int mlx4_en_set_ringparam(struct net_device *dev, mlx4_en_stop_port(dev); } - mlx4_en_free_resources(priv); + mlx4_en_free_resources(priv, true); priv->prof->tx_ring_size = tx_size; priv->prof->rx_ring_size = rx_size; @@ -442,6 +499,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { .get_ethtool_stats = mlx4_en_get_ethtool_stats, .self_test = mlx4_en_self_test, .get_wol = mlx4_en_get_wol, + .set_wol = mlx4_en_set_wol, .get_msglevel = mlx4_en_get_msglevel, .set_msglevel = mlx4_en_set_msglevel, .get_coalesce = mlx4_en_get_coalesce, diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c index 1ff6ca6466ed..9317b61a75b8 100644 --- a/drivers/net/mlx4/en_main.c +++ b/drivers/net/mlx4/en_main.c @@ -241,16 +241,18 @@ static void *mlx4_en_add(struct mlx4_dev *dev) mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) mdev->port_cnt++; - /* If we did not receive an explicit number of Rx rings, default to - * the number of completion vectors populated by the mlx4_core */ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { - mlx4_info(mdev, "Using %d tx rings for port:%d\n", - mdev->profile.prof[i].tx_ring_num, i); - mdev->profile.prof[i].rx_ring_num = min_t(int, - roundup_pow_of_two(dev->caps.num_comp_vectors), - MAX_RX_RINGS); - mlx4_info(mdev, "Defaulting to %d rx rings for port:%d\n", - mdev->profile.prof[i].rx_ring_num, i); + if (!dev->caps.comp_pool) { + mdev->profile.prof[i].rx_ring_num = + rounddown_pow_of_two(max_t(int, MIN_RX_RINGS, + min_t(int, + dev->caps.num_comp_vectors, + MAX_RX_RINGS))); + } else { + mdev->profile.prof[i].rx_ring_num = rounddown_pow_of_two( + min_t(int, dev->caps.comp_pool/ + dev->caps.num_ports - 1 , MAX_MSIX_P_PORT - 1)); + } } /* Create our own workqueue for reset/multicast tasks @@ -294,7 +296,7 @@ static struct mlx4_interface mlx4_en_interface = { .remove = mlx4_en_remove, .event = mlx4_en_event, .get_dev = mlx4_en_get_netdev, - .protocol = MLX4_PROTOCOL_EN, + .protocol = MLX4_PROT_ETH, }; static int __init mlx4_en_init(void) diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 897f576b8b17..4f158baa0246 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -156,9 +156,8 @@ static void mlx4_en_do_set_mac(struct work_struct *work) mutex_lock(&mdev->state_lock); if (priv->port_up) { /* Remove old MAC and insert the new one */ - mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index); - err = mlx4_register_mac(mdev->dev, priv->port, - priv->mac, &priv->mac_index); + err = mlx4_replace_mac(mdev->dev, priv->port, + priv->base_qpn, priv->mac, 0); if (err) en_err(priv, "Failed changing HW MAC address\n"); } else @@ -214,6 +213,7 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) struct mlx4_en_dev *mdev = priv->mdev; struct net_device *dev = priv->dev; u64 mcast_addr = 0; + u8 mc_list[16] = {0}; int err; mutex_lock(&mdev->state_lock); @@ -239,8 +239,12 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) priv->flags |= MLX4_EN_FLAG_PROMISC; /* Enable promiscouos mode */ - err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, - priv->base_qpn, 1); + if (!mdev->dev->caps.vep_uc_steering) + err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, + priv->base_qpn, 1); + else + err = mlx4_unicast_promisc_add(mdev->dev, priv->base_qpn, + priv->port); if (err) en_err(priv, "Failed enabling " "promiscous mode\n"); @@ -252,10 +256,21 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) en_err(priv, "Failed disabling " "multicast filter\n"); - /* Disable port VLAN filter */ - err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, NULL); - if (err) - en_err(priv, "Failed disabling VLAN filter\n"); + /* Add the default qp number as multicast promisc */ + if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) { + err = mlx4_multicast_promisc_add(mdev->dev, priv->base_qpn, + priv->port); + if (err) + en_err(priv, "Failed entering multicast promisc mode\n"); + priv->flags |= MLX4_EN_FLAG_MC_PROMISC; + } + + if (priv->vlgrp) { + /* Disable port VLAN filter */ + err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, NULL); + if (err) + en_err(priv, "Failed disabling VLAN filter\n"); + } } goto out; } @@ -270,11 +285,24 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) priv->flags &= ~MLX4_EN_FLAG_PROMISC; /* Disable promiscouos mode */ - err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, - priv->base_qpn, 0); + if (!mdev->dev->caps.vep_uc_steering) + err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, + priv->base_qpn, 0); + else + err = mlx4_unicast_promisc_remove(mdev->dev, priv->base_qpn, + priv->port); if (err) en_err(priv, "Failed disabling promiscous mode\n"); + /* Disable Multicast promisc */ + if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { + err = mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn, + priv->port); + if (err) + en_err(priv, "Failed disabling multicast promiscous mode\n"); + priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; + } + /* Enable port VLAN filter */ err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp); if (err) @@ -287,14 +315,38 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) 0, MLX4_MCAST_DISABLE); if (err) en_err(priv, "Failed disabling multicast filter\n"); + + /* Add the default qp number as multicast promisc */ + if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) { + err = mlx4_multicast_promisc_add(mdev->dev, priv->base_qpn, + priv->port); + if (err) + en_err(priv, "Failed entering multicast promisc mode\n"); + priv->flags |= MLX4_EN_FLAG_MC_PROMISC; + } } else { int i; + /* Disable Multicast promisc */ + if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { + err = mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn, + priv->port); + if (err) + en_err(priv, "Failed disabling multicast promiscous mode\n"); + priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; + } err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 0, MLX4_MCAST_DISABLE); if (err) en_err(priv, "Failed disabling multicast filter\n"); + /* Detach our qp from all the multicast addresses */ + for (i = 0; i < priv->mc_addrs_cnt; i++) { + memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN); + mc_list[5] = priv->port; + mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, + mc_list, MLX4_PROT_ETH); + } /* Flush mcast filter and init it with broadcast address */ mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST, 1, MLX4_MCAST_CONFIG); @@ -307,6 +359,10 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) for (i = 0; i < priv->mc_addrs_cnt; i++) { mcast_addr = mlx4_en_mac_to_u64(priv->mc_addrs + i * ETH_ALEN); + memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN); + mc_list[5] = priv->port; + mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp, + mc_list, 0, MLX4_PROT_ETH); mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, mcast_addr, 0, MLX4_MCAST_CONFIG); } @@ -314,8 +370,6 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) 0, MLX4_MCAST_ENABLE); if (err) en_err(priv, "Failed enabling multicast filter\n"); - - mlx4_en_clear_list(dev); } out: mutex_unlock(&mdev->state_lock); @@ -417,7 +471,6 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) unsigned long avg_pkt_size; unsigned long rx_packets; unsigned long rx_bytes; - unsigned long rx_byte_diff; unsigned long tx_packets; unsigned long tx_pkt_diff; unsigned long rx_pkt_diff; @@ -441,25 +494,20 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) rx_pkt_diff = ((unsigned long) (rx_packets - priv->last_moder_packets)); packets = max(tx_pkt_diff, rx_pkt_diff); - rx_byte_diff = rx_bytes - priv->last_moder_bytes; - rx_byte_diff = rx_byte_diff ? rx_byte_diff : 1; rate = packets * HZ / period; avg_pkt_size = packets ? ((unsigned long) (rx_bytes - priv->last_moder_bytes)) / packets : 0; /* Apply auto-moderation only when packet rate exceeds a rate that * it matters */ - if (rate > MLX4_EN_RX_RATE_THRESH) { + if (rate > MLX4_EN_RX_RATE_THRESH && avg_pkt_size > MLX4_EN_AVG_PKT_SMALL) { /* If tx and rx packet rates are not balanced, assume that * traffic is mainly BW bound and apply maximum moderation. * Otherwise, moderate according to packet rate */ - if (2 * tx_pkt_diff > 3 * rx_pkt_diff && - rx_pkt_diff / rx_byte_diff < - MLX4_EN_SMALL_PKT_SIZE) - moder_time = priv->rx_usecs_low; - else if (2 * rx_pkt_diff > 3 * tx_pkt_diff) + if (2 * tx_pkt_diff > 3 * rx_pkt_diff || + 2 * rx_pkt_diff > 3 * tx_pkt_diff) { moder_time = priv->rx_usecs_high; - else { + } else { if (rate < priv->pkt_rate_low) moder_time = priv->rx_usecs_low; else if (rate > priv->pkt_rate_high) @@ -471,9 +519,7 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) priv->rx_usecs_low; } } else { - /* When packet rate is low, use default moderation rather than - * 0 to prevent interrupt storms if traffic suddenly increases */ - moder_time = priv->rx_usecs; + moder_time = priv->rx_usecs_low; } en_dbg(INTR, priv, "tx rate:%lu rx_rate:%lu\n", @@ -565,6 +611,8 @@ int mlx4_en_start_port(struct net_device *dev) int err = 0; int i; int j; + u8 mc_list[16] = {0}; + char name[32]; if (priv->port_up) { en_dbg(DRV, priv, "start port called while port already up\n"); @@ -603,16 +651,35 @@ int mlx4_en_start_port(struct net_device *dev) ++rx_index; } + /* Set port mac number */ + en_dbg(DRV, priv, "Setting mac for port %d\n", priv->port); + err = mlx4_register_mac(mdev->dev, priv->port, + priv->mac, &priv->base_qpn, 0); + if (err) { + en_err(priv, "Failed setting port mac\n"); + goto cq_err; + } + mdev->mac_removed[priv->port] = 0; + err = mlx4_en_config_rss_steer(priv); if (err) { en_err(priv, "Failed configuring rss steering\n"); - goto cq_err; + goto mac_err; } + if (mdev->dev->caps.comp_pool && !priv->tx_vector) { + sprintf(name , "%s-tx", priv->dev->name); + if (mlx4_assign_eq(mdev->dev , name, &priv->tx_vector)) { + mlx4_warn(mdev, "Failed Assigning an EQ to " + "%s_tx ,Falling back to legacy " + "EQ's\n", priv->dev->name); + } + } /* Configure tx cq's and rings */ for (i = 0; i < priv->tx_ring_num; i++) { /* Configure cq */ cq = &priv->tx_cq[i]; + cq->vector = priv->tx_vector; err = mlx4_en_activate_cq(priv, cq); if (err) { en_err(priv, "Failed allocating Tx CQ\n"); @@ -659,24 +726,25 @@ int mlx4_en_start_port(struct net_device *dev) en_err(priv, "Failed setting default qp numbers\n"); goto tx_err; } - /* Set port mac number */ - en_dbg(DRV, priv, "Setting mac for port %d\n", priv->port); - err = mlx4_register_mac(mdev->dev, priv->port, - priv->mac, &priv->mac_index); - if (err) { - en_err(priv, "Failed setting port mac\n"); - goto tx_err; - } - mdev->mac_removed[priv->port] = 0; /* Init port */ en_dbg(HW, priv, "Initializing port\n"); err = mlx4_INIT_PORT(mdev->dev, priv->port); if (err) { en_err(priv, "Failed Initializing port\n"); - goto mac_err; + goto tx_err; } + /* Attach rx QP to bradcast address */ + memset(&mc_list[10], 0xff, ETH_ALEN); + mc_list[5] = priv->port; + if (mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp, mc_list, + 0, MLX4_PROT_ETH)) + mlx4_warn(mdev, "Failed Attaching Broadcast\n"); + + /* Must redo promiscuous mode setup. */ + priv->flags &= ~(MLX4_EN_FLAG_PROMISC | MLX4_EN_FLAG_MC_PROMISC); + /* Schedule multicast task to populate multicast list */ queue_work(mdev->workqueue, &priv->mcast_task); @@ -684,8 +752,6 @@ int mlx4_en_start_port(struct net_device *dev) netif_tx_start_all_queues(dev); return 0; -mac_err: - mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index); tx_err: while (tx_index--) { mlx4_en_deactivate_tx_ring(priv, &priv->tx_ring[tx_index]); @@ -693,6 +759,8 @@ tx_err: } mlx4_en_release_rss_steer(priv); +mac_err: + mlx4_unregister_mac(mdev->dev, priv->port, priv->base_qpn); cq_err: while (rx_index--) mlx4_en_deactivate_cq(priv, &priv->rx_cq[rx_index]); @@ -708,6 +776,7 @@ void mlx4_en_stop_port(struct net_device *dev) struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; int i; + u8 mc_list[16] = {0}; if (!priv->port_up) { en_dbg(DRV, priv, "stop port called while port already down\n"); @@ -722,8 +791,23 @@ void mlx4_en_stop_port(struct net_device *dev) /* Set port as not active */ priv->port_up = false; + /* Detach All multicasts */ + memset(&mc_list[10], 0xff, ETH_ALEN); + mc_list[5] = priv->port; + mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, mc_list, + MLX4_PROT_ETH); + for (i = 0; i < priv->mc_addrs_cnt; i++) { + memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN); + mc_list[5] = priv->port; + mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, + mc_list, MLX4_PROT_ETH); + } + mlx4_en_clear_list(dev); + /* Flush multicast filter */ + mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 1, MLX4_MCAST_CONFIG); + /* Unregister Mac address for the port */ - mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index); + mlx4_unregister_mac(mdev->dev, priv->port, priv->base_qpn); mdev->mac_removed[priv->port] = 1; /* Free TX Rings */ @@ -801,7 +885,6 @@ static int mlx4_en_open(struct net_device *dev) priv->rx_ring[i].packets = 0; } - mlx4_en_set_default_moderation(priv); err = mlx4_en_start_port(dev); if (err) en_err(priv, "Failed starting port:%d\n", priv->port); @@ -828,7 +911,7 @@ static int mlx4_en_close(struct net_device *dev) return 0; } -void mlx4_en_free_resources(struct mlx4_en_priv *priv) +void mlx4_en_free_resources(struct mlx4_en_priv *priv, bool reserve_vectors) { int i; @@ -836,14 +919,14 @@ void mlx4_en_free_resources(struct mlx4_en_priv *priv) if (priv->tx_ring[i].tx_info) mlx4_en_destroy_tx_ring(priv, &priv->tx_ring[i]); if (priv->tx_cq[i].buf) - mlx4_en_destroy_cq(priv, &priv->tx_cq[i]); + mlx4_en_destroy_cq(priv, &priv->tx_cq[i], reserve_vectors); } for (i = 0; i < priv->rx_ring_num; i++) { if (priv->rx_ring[i].rx_info) mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i]); if (priv->rx_cq[i].buf) - mlx4_en_destroy_cq(priv, &priv->rx_cq[i]); + mlx4_en_destroy_cq(priv, &priv->rx_cq[i], reserve_vectors); } } @@ -851,6 +934,13 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) { struct mlx4_en_port_profile *prof = priv->prof; int i; + int base_tx_qpn, err; + + err = mlx4_qp_reserve_range(priv->mdev->dev, priv->tx_ring_num, 256, &base_tx_qpn); + if (err) { + en_err(priv, "failed reserving range for TX rings\n"); + return err; + } /* Create tx Rings */ for (i = 0; i < priv->tx_ring_num; i++) { @@ -858,7 +948,7 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) prof->tx_ring_size, i, TX)) goto err; - if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[i], + if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[i], base_tx_qpn + i, prof->tx_ring_size, TXBB_SIZE)) goto err; } @@ -878,6 +968,7 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) err: en_err(priv, "Failed to allocate NIC resources\n"); + mlx4_qp_release_range(priv->mdev->dev, base_tx_qpn, priv->tx_ring_num); return -ENOMEM; } @@ -905,7 +996,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev) mdev->pndev[priv->port] = NULL; mutex_unlock(&mdev->state_lock); - mlx4_en_free_resources(priv); + mlx4_en_free_resources(priv, false); free_netdev(dev); } @@ -932,7 +1023,6 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) en_dbg(DRV, priv, "Change MTU called with card down!?\n"); } else { mlx4_en_stop_port(dev); - mlx4_en_set_default_moderation(priv); err = mlx4_en_start_port(dev); if (err) { en_err(priv, "Failed restarting port:%d\n", @@ -1079,7 +1169,25 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num); en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); + /* Configure port */ + err = mlx4_SET_PORT_general(mdev->dev, priv->port, + MLX4_EN_MIN_MTU, + 0, 0, 0, 0); + if (err) { + en_err(priv, "Failed setting port general configurations " + "for port %d, with error %d\n", priv->port, err); + goto out; + } + + /* Init port */ + en_warn(priv, "Initializing port\n"); + err = mlx4_INIT_PORT(mdev->dev, priv->port); + if (err) { + en_err(priv, "Failed Initializing port\n"); + goto out; + } priv->registered = 1; + mlx4_en_set_default_moderation(priv); queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); return 0; diff --git a/drivers/net/mlx4/en_port.c b/drivers/net/mlx4/en_port.c index 7f5a3221e0c1..f2a4f5dd313d 100644 --- a/drivers/net/mlx4/en_port.c +++ b/drivers/net/mlx4/en_port.c @@ -119,6 +119,10 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, struct mlx4_set_port_rqp_calc_context *context; int err; u32 in_mod; + u32 m_promisc = (dev->caps.vep_mc_steering) ? MCAST_DIRECT : MCAST_DEFAULT; + + if (dev->caps.vep_mc_steering && dev->caps.vep_uc_steering) + return 0; mailbox = mlx4_alloc_cmd_mailbox(dev); if (IS_ERR(mailbox)) @@ -127,8 +131,11 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, memset(context, 0, sizeof *context); context->base_qpn = cpu_to_be32(base_qpn); - context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_EN_SHIFT | base_qpn); - context->mcast = cpu_to_be32(1 << SET_PORT_PROMISC_MODE_SHIFT | base_qpn); + context->n_mac = 0x7; + context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | + base_qpn); + context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT | + base_qpn); context->intra_no_vlan = 0; context->no_vlan = MLX4_NO_VLAN_IDX; context->intra_vlan_miss = 0; @@ -206,7 +213,7 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) } stats->tx_packets = 0; stats->tx_bytes = 0; - for (i = 0; i <= priv->tx_ring_num; i++) { + for (i = 0; i < priv->tx_ring_num; i++) { stats->tx_packets += priv->tx_ring[i].packets; stats->tx_bytes += priv->tx_ring[i].bytes; } diff --git a/drivers/net/mlx4/en_port.h b/drivers/net/mlx4/en_port.h index 092e814b1981..e3d73e41c567 100644 --- a/drivers/net/mlx4/en_port.h +++ b/drivers/net/mlx4/en_port.h @@ -36,8 +36,8 @@ #define SET_PORT_GEN_ALL_VALID 0x7 -#define SET_PORT_PROMISC_EN_SHIFT 31 -#define SET_PORT_PROMISC_MODE_SHIFT 30 +#define SET_PORT_PROMISC_SHIFT 31 +#define SET_PORT_MC_PROMISC_SHIFT 30 enum { MLX4_CMD_SET_VLAN_FLTR = 0x47, @@ -45,6 +45,12 @@ enum { MLX4_CMD_DUMP_ETH_STATS = 0x49, }; +enum { + MCAST_DIRECT_ONLY = 0, + MCAST_DIRECT = 1, + MCAST_DEFAULT = 2 +}; + struct mlx4_set_port_general_context { u8 reserved[3]; u8 flags; @@ -60,14 +66,17 @@ struct mlx4_set_port_general_context { struct mlx4_set_port_rqp_calc_context { __be32 base_qpn; - __be32 flags; - u8 reserved[3]; + u8 rererved; + u8 n_mac; + u8 n_vlan; + u8 n_prio; + u8 reserved2[3]; u8 mac_miss; u8 intra_no_vlan; u8 no_vlan; u8 intra_vlan_miss; u8 vlan_miss; - u8 reserved2[3]; + u8 reserved3[3]; u8 no_vlan_prio; __be32 promisc; __be32 mcast; diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 570f2508fb30..05998ee297c9 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -845,16 +845,10 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) } /* Configure RSS indirection qp */ - err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &priv->base_qpn); - if (err) { - en_err(priv, "Failed to reserve range for RSS " - "indirection qp\n"); - goto rss_err; - } err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, &rss_map->indir_qp); if (err) { en_err(priv, "Failed to allocate RSS indirection QP\n"); - goto reserve_err; + goto rss_err; } rss_map->indir_qp.event = mlx4_en_sqp_event; mlx4_en_fill_qp_context(priv, 0, 0, 0, 1, priv->base_qpn, @@ -881,8 +875,6 @@ indir_err: MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); mlx4_qp_free(mdev->dev, &rss_map->indir_qp); -reserve_err: - mlx4_qp_release_range(mdev->dev, priv->base_qpn, 1); rss_err: for (i = 0; i < good_qps; i++) { mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], @@ -904,7 +896,6 @@ void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv) MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); mlx4_qp_free(mdev->dev, &rss_map->indir_qp); - mlx4_qp_release_range(mdev->dev, priv->base_qpn, 1); for (i = 0; i < priv->rx_ring_num; i++) { mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index a680cd4a5ab6..01feb8fd42ad 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -44,6 +44,7 @@ enum { MAX_INLINE = 104, /* 128 - 16 - 4 - 4 */ + MAX_BF = 256, }; static int inline_thold __read_mostly = MAX_INLINE; @@ -52,7 +53,7 @@ module_param_named(inline_thold, inline_thold, int, 0444); MODULE_PARM_DESC(inline_thold, "threshold for using inline data"); int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring *ring, u32 size, + struct mlx4_en_tx_ring *ring, int qpn, u32 size, u16 stride) { struct mlx4_en_dev *mdev = priv->mdev; @@ -103,23 +104,25 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, "buf_size:%d dma:%llx\n", ring, ring->buf, ring->size, ring->buf_size, (unsigned long long) ring->wqres.buf.direct.map); - err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &ring->qpn); - if (err) { - en_err(priv, "Failed reserving qp for tx ring.\n"); - goto err_map; - } - + ring->qpn = qpn; err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->qp); if (err) { en_err(priv, "Failed allocating qp %d\n", ring->qpn); - goto err_reserve; + goto err_map; } ring->qp.event = mlx4_en_sqp_event; + err = mlx4_bf_alloc(mdev->dev, &ring->bf); + if (err) { + en_dbg(DRV, priv, "working without blueflame (%d)", err); + ring->bf.uar = &mdev->priv_uar; + ring->bf.uar->map = mdev->uar_map; + ring->bf_enabled = false; + } else + ring->bf_enabled = true; + return 0; -err_reserve: - mlx4_qp_release_range(mdev->dev, ring->qpn, 1); err_map: mlx4_en_unmap_buffer(&ring->wqres.buf); err_hwq_res: @@ -139,6 +142,8 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_dev *mdev = priv->mdev; en_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn); + if (ring->bf_enabled) + mlx4_bf_free(mdev->dev, &ring->bf); mlx4_qp_remove(mdev->dev, &ring->qp); mlx4_qp_free(mdev->dev, &ring->qp); mlx4_qp_release_range(mdev->dev, ring->qpn, 1); @@ -171,6 +176,8 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn, ring->cqn, &ring->context); + if (ring->bf_enabled) + ring->context.usr_page = cpu_to_be32(ring->bf.uar->index); err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, &ring->context, &ring->qp, &ring->qp_state); @@ -591,6 +598,11 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb) return skb_tx_hash(dev, skb); } +static void mlx4_bf_copy(unsigned long *dst, unsigned long *src, unsigned bytecnt) +{ + __iowrite64_copy(dst, src, bytecnt / 8); +} + netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) { struct mlx4_en_priv *priv = netdev_priv(dev); @@ -609,12 +621,13 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) int desc_size; int real_size; dma_addr_t dma; - u32 index; + u32 index, bf_index; __be32 op_own; u16 vlan_tag = 0; int i; int lso_header_size; void *fragptr; + bool bounce = false; if (!priv->port_up) goto tx_drop; @@ -657,13 +670,16 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) /* Packet is good - grab an index and transmit it */ index = ring->prod & ring->size_mask; + bf_index = ring->prod; /* See if we have enough space for whole descriptor TXBB for setting * SW ownership on next descriptor; if not, use a bounce buffer. */ if (likely(index + nr_txbb <= ring->size)) tx_desc = ring->buf + index * TXBB_SIZE; - else + else { tx_desc = (struct mlx4_en_tx_desc *) ring->bounce_buf; + bounce = true; + } /* Save skb in tx_info ring */ tx_info = &ring->tx_info[index]; @@ -768,21 +784,37 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) ring->prod += nr_txbb; /* If we used a bounce buffer then copy descriptor back into place */ - if (tx_desc == (struct mlx4_en_tx_desc *) ring->bounce_buf) + if (bounce) tx_desc = mlx4_en_bounce_to_desc(priv, ring, index, desc_size); /* Run destructor before passing skb to HW */ if (likely(!skb_shared(skb))) skb_orphan(skb); - /* Ensure new descirptor hits memory - * before setting ownership of this descriptor to HW */ - wmb(); - tx_desc->ctrl.owner_opcode = op_own; + if (ring->bf_enabled && desc_size <= MAX_BF && !bounce && !vlan_tag) { + *(u32 *) (&tx_desc->ctrl.vlan_tag) |= ring->doorbell_qpn; + op_own |= htonl((bf_index & 0xffff) << 8); + /* Ensure new descirptor hits memory + * before setting ownership of this descriptor to HW */ + wmb(); + tx_desc->ctrl.owner_opcode = op_own; - /* Ring doorbell! */ - wmb(); - writel(ring->doorbell_qpn, mdev->uar_map + MLX4_SEND_DOORBELL); + wmb(); + + mlx4_bf_copy(ring->bf.reg + ring->bf.offset, (unsigned long *) &tx_desc->ctrl, + desc_size); + + wmb(); + + ring->bf.offset ^= ring->bf.buf_size; + } else { + /* Ensure new descirptor hits memory + * before setting ownership of this descriptor to HW */ + wmb(); + tx_desc->ctrl.owner_opcode = op_own; + wmb(); + writel(ring->doorbell_qpn, ring->bf.uar->map + MLX4_SEND_DOORBELL); + } /* Poll CQ here */ mlx4_en_xmit_poll(priv, tx_ind); diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index 552d0fce6f67..1ad1f6029af8 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c @@ -42,7 +42,7 @@ #include "fw.h" enum { - MLX4_IRQNAME_SIZE = 64 + MLX4_IRQNAME_SIZE = 32 }; enum { @@ -317,8 +317,8 @@ static int mlx4_num_eq_uar(struct mlx4_dev *dev) * we need to map, take the difference of highest index and * the lowest index we'll use and add 1. */ - return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs) / 4 - - dev->caps.reserved_eqs / 4 + 1; + return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs + + dev->caps.comp_pool)/4 - dev->caps.reserved_eqs/4 + 1; } static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq) @@ -496,16 +496,32 @@ static void mlx4_free_eq(struct mlx4_dev *dev, static void mlx4_free_irqs(struct mlx4_dev *dev) { struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table; - int i; + struct mlx4_priv *priv = mlx4_priv(dev); + int i, vec; if (eq_table->have_irq) free_irq(dev->pdev->irq, dev); + for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) if (eq_table->eq[i].have_irq) { free_irq(eq_table->eq[i].irq, eq_table->eq + i); eq_table->eq[i].have_irq = 0; } + for (i = 0; i < dev->caps.comp_pool; i++) { + /* + * Freeing the assigned irq's + * all bits should be 0, but we need to validate + */ + if (priv->msix_ctl.pool_bm & 1ULL << i) { + /* NO need protecting*/ + vec = dev->caps.num_comp_vectors + 1 + i; + free_irq(priv->eq_table.eq[vec].irq, + &priv->eq_table.eq[vec]); + } + } + + kfree(eq_table->irq_names); } @@ -578,7 +594,8 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) (priv->eq_table.inta_pin < 32 ? 4 : 0); priv->eq_table.irq_names = - kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1), + kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1 + + dev->caps.comp_pool), GFP_KERNEL); if (!priv->eq_table.irq_names) { err = -ENOMEM; @@ -586,7 +603,9 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) } for (i = 0; i < dev->caps.num_comp_vectors; ++i) { - err = mlx4_create_eq(dev, dev->caps.num_cqs + MLX4_NUM_SPARE_EQE, + err = mlx4_create_eq(dev, dev->caps.num_cqs - + dev->caps.reserved_cqs + + MLX4_NUM_SPARE_EQE, (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, &priv->eq_table.eq[i]); if (err) { @@ -601,6 +620,22 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) if (err) goto err_out_comp; + /*if additional completion vectors poolsize is 0 this loop will not run*/ + for (i = dev->caps.num_comp_vectors + 1; + i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) { + + err = mlx4_create_eq(dev, dev->caps.num_cqs - + dev->caps.reserved_cqs + + MLX4_NUM_SPARE_EQE, + (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, + &priv->eq_table.eq[i]); + if (err) { + --i; + goto err_out_unmap; + } + } + + if (dev->flags & MLX4_FLAG_MSI_X) { const char *eq_name; @@ -686,7 +721,7 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev) mlx4_free_irqs(dev); - for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) + for (i = 0; i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) mlx4_free_eq(dev, &priv->eq_table.eq[i]); mlx4_unmap_clr_int(dev); @@ -743,3 +778,65 @@ int mlx4_test_interrupts(struct mlx4_dev *dev) return err; } EXPORT_SYMBOL(mlx4_test_interrupts); + +int mlx4_assign_eq(struct mlx4_dev *dev, char* name, int * vector) +{ + + struct mlx4_priv *priv = mlx4_priv(dev); + int vec = 0, err = 0, i; + + spin_lock(&priv->msix_ctl.pool_lock); + for (i = 0; !vec && i < dev->caps.comp_pool; i++) { + if (~priv->msix_ctl.pool_bm & 1ULL << i) { + priv->msix_ctl.pool_bm |= 1ULL << i; + vec = dev->caps.num_comp_vectors + 1 + i; + snprintf(priv->eq_table.irq_names + + vec * MLX4_IRQNAME_SIZE, + MLX4_IRQNAME_SIZE, "%s", name); + err = request_irq(priv->eq_table.eq[vec].irq, + mlx4_msi_x_interrupt, 0, + &priv->eq_table.irq_names[vec<<5], + priv->eq_table.eq + vec); + if (err) { + /*zero out bit by fliping it*/ + priv->msix_ctl.pool_bm ^= 1 << i; + vec = 0; + continue; + /*we dont want to break here*/ + } + eq_set_ci(&priv->eq_table.eq[vec], 1); + } + } + spin_unlock(&priv->msix_ctl.pool_lock); + + if (vec) { + *vector = vec; + } else { + *vector = 0; + err = (i == dev->caps.comp_pool) ? -ENOSPC : err; + } + return err; +} +EXPORT_SYMBOL(mlx4_assign_eq); + +void mlx4_release_eq(struct mlx4_dev *dev, int vec) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + /*bm index*/ + int i = vec - dev->caps.num_comp_vectors - 1; + + if (likely(i >= 0)) { + /*sanity check , making sure were not trying to free irq's + Belonging to a legacy EQ*/ + spin_lock(&priv->msix_ctl.pool_lock); + if (priv->msix_ctl.pool_bm & 1ULL << i) { + free_irq(priv->eq_table.eq[vec].irq, + &priv->eq_table.eq[vec]); + priv->msix_ctl.pool_bm &= ~(1ULL << i); + } + spin_unlock(&priv->msix_ctl.pool_lock); + } + +} +EXPORT_SYMBOL(mlx4_release_eq); + diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c index 5de1db897835..67a209ba939d 100644 --- a/drivers/net/mlx4/fw.c +++ b/drivers/net/mlx4/fw.c @@ -274,8 +274,11 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev_cap->stat_rate_support = stat_rate; MLX4_GET(field, outbox, QUERY_DEV_CAP_UDP_RSS_OFFSET); dev_cap->udp_rss = field & 0x1; + dev_cap->vep_uc_steering = field & 0x2; + dev_cap->vep_mc_steering = field & 0x4; MLX4_GET(field, outbox, QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET); dev_cap->loopback_support = field & 0x1; + dev_cap->wol = field & 0x40; MLX4_GET(dev_cap->flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET); MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET); dev_cap->reserved_uars = field >> 4; @@ -737,6 +740,7 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) #define INIT_HCA_MC_BASE_OFFSET (INIT_HCA_MCAST_OFFSET + 0x00) #define INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x12) #define INIT_HCA_LOG_MC_HASH_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x16) +#define INIT_HCA_UC_STEERING_OFFSET (INIT_HCA_MCAST_OFFSET + 0x18) #define INIT_HCA_LOG_MC_TABLE_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x1b) #define INIT_HCA_TPT_OFFSET 0x0f0 #define INIT_HCA_DMPT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x00) @@ -797,6 +801,8 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) MLX4_PUT(inbox, param->mc_base, INIT_HCA_MC_BASE_OFFSET); MLX4_PUT(inbox, param->log_mc_entry_sz, INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET); MLX4_PUT(inbox, param->log_mc_hash_sz, INIT_HCA_LOG_MC_HASH_SZ_OFFSET); + if (dev->caps.vep_mc_steering) + MLX4_PUT(inbox, (u8) (1 << 3), INIT_HCA_UC_STEERING_OFFSET); MLX4_PUT(inbox, param->log_mc_table_sz, INIT_HCA_LOG_MC_TABLE_SZ_OFFSET); /* TPT attributes */ @@ -908,3 +914,22 @@ int mlx4_NOP(struct mlx4_dev *dev) /* Input modifier of 0x1f means "finish as soon as possible." */ return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, 100); } + +#define MLX4_WOL_SETUP_MODE (5 << 28) +int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port) +{ + u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8; + + return mlx4_cmd_imm(dev, 0, config, in_mod, 0x3, + MLX4_CMD_MOD_STAT_CFG, MLX4_CMD_TIME_CLASS_A); +} +EXPORT_SYMBOL_GPL(mlx4_wol_read); + +int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port) +{ + u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8; + + return mlx4_cmd(dev, config, in_mod, 0x1, MLX4_CMD_MOD_STAT_CFG, + MLX4_CMD_TIME_CLASS_A); +} +EXPORT_SYMBOL_GPL(mlx4_wol_write); diff --git a/drivers/net/mlx4/fw.h b/drivers/net/mlx4/fw.h index 65cc72eb899d..88003ebc6185 100644 --- a/drivers/net/mlx4/fw.h +++ b/drivers/net/mlx4/fw.h @@ -80,6 +80,9 @@ struct mlx4_dev_cap { u16 stat_rate_support; int udp_rss; int loopback_support; + int vep_uc_steering; + int vep_mc_steering; + int wol; u32 flags; int reserved_uars; int uar_size; diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 2765a3ce9c24..62fa7eec5f0c 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -39,6 +39,7 @@ #include <linux/pci.h> #include <linux/dma-mapping.h> #include <linux/slab.h> +#include <linux/io-mapping.h> #include <linux/mlx4/device.h> #include <linux/mlx4/doorbell.h> @@ -227,6 +228,9 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev->caps.stat_rate_support = dev_cap->stat_rate_support; dev->caps.udp_rss = dev_cap->udp_rss; dev->caps.loopback_support = dev_cap->loopback_support; + dev->caps.vep_uc_steering = dev_cap->vep_uc_steering; + dev->caps.vep_mc_steering = dev_cap->vep_mc_steering; + dev->caps.wol = dev_cap->wol; dev->caps.max_gso_sz = dev_cap->max_gso_sz; dev->caps.log_num_macs = log_num_mac; @@ -718,8 +722,31 @@ static void mlx4_free_icms(struct mlx4_dev *dev) mlx4_free_icm(dev, priv->fw.aux_icm, 0); } +static int map_bf_area(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + resource_size_t bf_start; + resource_size_t bf_len; + int err = 0; + + bf_start = pci_resource_start(dev->pdev, 2) + (dev->caps.num_uars << PAGE_SHIFT); + bf_len = pci_resource_len(dev->pdev, 2) - (dev->caps.num_uars << PAGE_SHIFT); + priv->bf_mapping = io_mapping_create_wc(bf_start, bf_len); + if (!priv->bf_mapping) + err = -ENOMEM; + + return err; +} + +static void unmap_bf_area(struct mlx4_dev *dev) +{ + if (mlx4_priv(dev)->bf_mapping) + io_mapping_free(mlx4_priv(dev)->bf_mapping); +} + static void mlx4_close_hca(struct mlx4_dev *dev) { + unmap_bf_area(dev); mlx4_CLOSE_HCA(dev, 0); mlx4_free_icms(dev); mlx4_UNMAP_FA(dev); @@ -772,6 +799,9 @@ static int mlx4_init_hca(struct mlx4_dev *dev) goto err_stop_fw; } + if (map_bf_area(dev)) + mlx4_dbg(dev, "Failed to map blue flame area\n"); + init_hca.log_uar_sz = ilog2(dev->caps.num_uars); err = mlx4_init_icm(dev, &dev_cap, &init_hca, icm_size); @@ -802,6 +832,7 @@ err_free_icm: mlx4_free_icms(dev); err_stop_fw: + unmap_bf_area(dev); mlx4_UNMAP_FA(dev); mlx4_free_icm(dev, priv->fw.fw_icm, 0); @@ -969,13 +1000,15 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); struct msix_entry *entries; - int nreq; + int nreq = min_t(int, dev->caps.num_ports * + min_t(int, num_online_cpus() + 1, MAX_MSIX_P_PORT) + + MSIX_LEGACY_SZ, MAX_MSIX); int err; int i; if (msi_x) { nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs, - num_possible_cpus() + 1); + nreq); entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL); if (!entries) goto no_msi; @@ -998,7 +1031,15 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) goto no_msi; } - dev->caps.num_comp_vectors = nreq - 1; + if (nreq < + MSIX_LEGACY_SZ + dev->caps.num_ports * MIN_MSIX_P_PORT) { + /*Working in legacy mode , all EQ's shared*/ + dev->caps.comp_pool = 0; + dev->caps.num_comp_vectors = nreq - 1; + } else { + dev->caps.comp_pool = nreq - MSIX_LEGACY_SZ; + dev->caps.num_comp_vectors = MSIX_LEGACY_SZ - 1; + } for (i = 0; i < nreq; ++i) priv->eq_table.eq[i].irq = entries[i].vector; @@ -1010,6 +1051,7 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) no_msi: dev->caps.num_comp_vectors = 1; + dev->caps.comp_pool = 0; for (i = 0; i < 2; ++i) priv->eq_table.eq[i].irq = dev->pdev->irq; @@ -1049,6 +1091,59 @@ static void mlx4_cleanup_port_info(struct mlx4_port_info *info) device_remove_file(&info->dev->pdev->dev, &info->port_attr); } +static int mlx4_init_steering(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int num_entries = dev->caps.num_ports; + int i, j; + + priv->steer = kzalloc(sizeof(struct mlx4_steer) * num_entries, GFP_KERNEL); + if (!priv->steer) + return -ENOMEM; + + for (i = 0; i < num_entries; i++) { + for (j = 0; j < MLX4_NUM_STEERS; j++) { + INIT_LIST_HEAD(&priv->steer[i].promisc_qps[j]); + INIT_LIST_HEAD(&priv->steer[i].steer_entries[j]); + } + INIT_LIST_HEAD(&priv->steer[i].high_prios); + } + return 0; +} + +static void mlx4_clear_steering(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_steer_index *entry, *tmp_entry; + struct mlx4_promisc_qp *pqp, *tmp_pqp; + int num_entries = dev->caps.num_ports; + int i, j; + + for (i = 0; i < num_entries; i++) { + for (j = 0; j < MLX4_NUM_STEERS; j++) { + list_for_each_entry_safe(pqp, tmp_pqp, + &priv->steer[i].promisc_qps[j], + list) { + list_del(&pqp->list); + kfree(pqp); + } + list_for_each_entry_safe(entry, tmp_entry, + &priv->steer[i].steer_entries[j], + list) { + list_del(&entry->list); + list_for_each_entry_safe(pqp, tmp_pqp, + &entry->duplicates, + list) { + list_del(&pqp->list); + kfree(pqp); + } + kfree(entry); + } + } + } + kfree(priv->steer); +} + static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { struct mlx4_priv *priv; @@ -1109,6 +1204,9 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } } + /* Allow large DMA segments, up to the firmware limit of 1 GB */ + dma_set_max_seg_size(&pdev->dev, 1024 * 1024 * 1024); + priv = kzalloc(sizeof *priv, GFP_KERNEL); if (!priv) { dev_err(&pdev->dev, "Device struct alloc failed, " @@ -1127,6 +1225,11 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) INIT_LIST_HEAD(&priv->pgdir_list); mutex_init(&priv->pgdir_mutex); + pci_read_config_byte(pdev, PCI_REVISION_ID, &dev->rev_id); + + INIT_LIST_HEAD(&priv->bf_list); + mutex_init(&priv->bf_mutex); + /* * Now reset the HCA before we touch the PCI capabilities or * attempt a firmware command, since a boot ROM may have left @@ -1151,8 +1254,15 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) if (err) goto err_close; + priv->msix_ctl.pool_bm = 0; + spin_lock_init(&priv->msix_ctl.pool_lock); + mlx4_enable_msi_x(dev); + err = mlx4_init_steering(dev); + if (err) + goto err_free_eq; + err = mlx4_setup_hca(dev); if (err == -EBUSY && (dev->flags & MLX4_FLAG_MSI_X)) { dev->flags &= ~MLX4_FLAG_MSI_X; @@ -1161,7 +1271,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } if (err) - goto err_free_eq; + goto err_steer; for (port = 1; port <= dev->caps.num_ports; port++) { err = mlx4_init_port_info(dev, port); @@ -1194,6 +1304,9 @@ err_port: mlx4_cleanup_pd_table(dev); mlx4_cleanup_uar_table(dev); +err_steer: + mlx4_clear_steering(dev); + err_free_eq: mlx4_free_eq_table(dev); @@ -1253,6 +1366,7 @@ static void mlx4_remove_one(struct pci_dev *pdev) iounmap(priv->kar); mlx4_uar_free(dev, &priv->driver_uar); mlx4_cleanup_uar_table(dev); + mlx4_clear_steering(dev); mlx4_free_eq_table(dev); mlx4_close_hca(dev); mlx4_cmd_cleanup(dev); diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c index 79cf42db2ea9..c6d336aed2d9 100644 --- a/drivers/net/mlx4/mcg.c +++ b/drivers/net/mlx4/mcg.c @@ -32,6 +32,7 @@ */ #include <linux/string.h> +#include <linux/etherdevice.h> #include <linux/mlx4/cmd.h> @@ -40,38 +41,40 @@ #define MGM_QPN_MASK 0x00FFFFFF #define MGM_BLCK_LB_BIT 30 -struct mlx4_mgm { - __be32 next_gid_index; - __be32 members_count; - u32 reserved[2]; - u8 gid[16]; - __be32 qp[MLX4_QP_PER_MGM]; -}; - static const u8 zero_gid[16]; /* automatically initialized to 0 */ -static int mlx4_READ_MCG(struct mlx4_dev *dev, int index, - struct mlx4_cmd_mailbox *mailbox) +static int mlx4_READ_ENTRY(struct mlx4_dev *dev, int index, + struct mlx4_cmd_mailbox *mailbox) { return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG, MLX4_CMD_TIME_CLASS_A); } -static int mlx4_WRITE_MCG(struct mlx4_dev *dev, int index, - struct mlx4_cmd_mailbox *mailbox) +static int mlx4_WRITE_ENTRY(struct mlx4_dev *dev, int index, + struct mlx4_cmd_mailbox *mailbox) { return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG, MLX4_CMD_TIME_CLASS_A); } -static int mlx4_MGID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - u16 *hash) +static int mlx4_WRITE_PROMISC(struct mlx4_dev *dev, u8 vep_num, u8 port, u8 steer, + struct mlx4_cmd_mailbox *mailbox) +{ + u32 in_mod; + + in_mod = (u32) vep_num << 24 | (u32) port << 16 | steer << 1; + return mlx4_cmd(dev, mailbox->dma, in_mod, 0x1, + MLX4_CMD_WRITE_MCG, MLX4_CMD_TIME_CLASS_A); +} + +static int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + u16 *hash, u8 op_mod) { u64 imm; int err; - err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, 0, MLX4_CMD_MGID_HASH, - MLX4_CMD_TIME_CLASS_A); + err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, op_mod, + MLX4_CMD_MGID_HASH, MLX4_CMD_TIME_CLASS_A); if (!err) *hash = imm; @@ -79,6 +82,458 @@ static int mlx4_MGID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox return err; } +static struct mlx4_promisc_qp *get_promisc_qp(struct mlx4_dev *dev, u8 pf_num, + enum mlx4_steer_type steer, + u32 qpn) +{ + struct mlx4_steer *s_steer = &mlx4_priv(dev)->steer[pf_num]; + struct mlx4_promisc_qp *pqp; + + list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) { + if (pqp->qpn == qpn) + return pqp; + } + /* not found */ + return NULL; +} + +/* + * Add new entry to steering data structure. + * All promisc QPs should be added as well + */ +static int new_steering_entry(struct mlx4_dev *dev, u8 vep_num, u8 port, + enum mlx4_steer_type steer, + unsigned int index, u32 qpn) +{ + struct mlx4_steer *s_steer; + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_mgm *mgm; + u32 members_count; + struct mlx4_steer_index *new_entry; + struct mlx4_promisc_qp *pqp; + struct mlx4_promisc_qp *dqp = NULL; + u32 prot; + int err; + u8 pf_num; + + pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1); + s_steer = &mlx4_priv(dev)->steer[pf_num]; + new_entry = kzalloc(sizeof *new_entry, GFP_KERNEL); + if (!new_entry) + return -ENOMEM; + + INIT_LIST_HEAD(&new_entry->duplicates); + new_entry->index = index; + list_add_tail(&new_entry->list, &s_steer->steer_entries[steer]); + + /* If the given qpn is also a promisc qp, + * it should be inserted to duplicates list + */ + pqp = get_promisc_qp(dev, pf_num, steer, qpn); + if (pqp) { + dqp = kmalloc(sizeof *dqp, GFP_KERNEL); + if (!dqp) { + err = -ENOMEM; + goto out_alloc; + } + dqp->qpn = qpn; + list_add_tail(&dqp->list, &new_entry->duplicates); + } + + /* if no promisc qps for this vep, we are done */ + if (list_empty(&s_steer->promisc_qps[steer])) + return 0; + + /* now need to add all the promisc qps to the new + * steering entry, as they should also receive the packets + * destined to this address */ + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) { + err = -ENOMEM; + goto out_alloc; + } + mgm = mailbox->buf; + + err = mlx4_READ_ENTRY(dev, index, mailbox); + if (err) + goto out_mailbox; + + members_count = be32_to_cpu(mgm->members_count) & 0xffffff; + prot = be32_to_cpu(mgm->members_count) >> 30; + list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) { + /* don't add already existing qpn */ + if (pqp->qpn == qpn) + continue; + if (members_count == MLX4_QP_PER_MGM) { + /* out of space */ + err = -ENOMEM; + goto out_mailbox; + } + + /* add the qpn */ + mgm->qp[members_count++] = cpu_to_be32(pqp->qpn & MGM_QPN_MASK); + } + /* update the qps count and update the entry with all the promisc qps*/ + mgm->members_count = cpu_to_be32(members_count | (prot << 30)); + err = mlx4_WRITE_ENTRY(dev, index, mailbox); + +out_mailbox: + mlx4_free_cmd_mailbox(dev, mailbox); + if (!err) + return 0; +out_alloc: + if (dqp) { + list_del(&dqp->list); + kfree(dqp); + } + list_del(&new_entry->list); + kfree(new_entry); + return err; +} + +/* update the data structures with existing steering entry */ +static int existing_steering_entry(struct mlx4_dev *dev, u8 vep_num, u8 port, + enum mlx4_steer_type steer, + unsigned int index, u32 qpn) +{ + struct mlx4_steer *s_steer; + struct mlx4_steer_index *tmp_entry, *entry = NULL; + struct mlx4_promisc_qp *pqp; + struct mlx4_promisc_qp *dqp; + u8 pf_num; + + pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1); + s_steer = &mlx4_priv(dev)->steer[pf_num]; + + pqp = get_promisc_qp(dev, pf_num, steer, qpn); + if (!pqp) + return 0; /* nothing to do */ + + list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) { + if (tmp_entry->index == index) { + entry = tmp_entry; + break; + } + } + if (unlikely(!entry)) { + mlx4_warn(dev, "Steering entry at index %x is not registered\n", index); + return -EINVAL; + } + + /* the given qpn is listed as a promisc qpn + * we need to add it as a duplicate to this entry + * for future refernce */ + list_for_each_entry(dqp, &entry->duplicates, list) { + if (qpn == dqp->qpn) + return 0; /* qp is already duplicated */ + } + + /* add the qp as a duplicate on this index */ + dqp = kmalloc(sizeof *dqp, GFP_KERNEL); + if (!dqp) + return -ENOMEM; + dqp->qpn = qpn; + list_add_tail(&dqp->list, &entry->duplicates); + + return 0; +} + +/* Check whether a qpn is a duplicate on steering entry + * If so, it should not be removed from mgm */ +static bool check_duplicate_entry(struct mlx4_dev *dev, u8 vep_num, u8 port, + enum mlx4_steer_type steer, + unsigned int index, u32 qpn) +{ + struct mlx4_steer *s_steer; + struct mlx4_steer_index *tmp_entry, *entry = NULL; + struct mlx4_promisc_qp *dqp, *tmp_dqp; + u8 pf_num; + + pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1); + s_steer = &mlx4_priv(dev)->steer[pf_num]; + + /* if qp is not promisc, it cannot be duplicated */ + if (!get_promisc_qp(dev, pf_num, steer, qpn)) + return false; + + /* The qp is promisc qp so it is a duplicate on this index + * Find the index entry, and remove the duplicate */ + list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) { + if (tmp_entry->index == index) { + entry = tmp_entry; + break; + } + } + if (unlikely(!entry)) { + mlx4_warn(dev, "Steering entry for index %x is not registered\n", index); + return false; + } + list_for_each_entry_safe(dqp, tmp_dqp, &entry->duplicates, list) { + if (dqp->qpn == qpn) { + list_del(&dqp->list); + kfree(dqp); + } + } + return true; +} + +/* I a steering entry contains only promisc QPs, it can be removed. */ +static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 vep_num, u8 port, + enum mlx4_steer_type steer, + unsigned int index, u32 tqpn) +{ + struct mlx4_steer *s_steer; + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_mgm *mgm; + struct mlx4_steer_index *entry = NULL, *tmp_entry; + u32 qpn; + u32 members_count; + bool ret = false; + int i; + u8 pf_num; + + pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1); + s_steer = &mlx4_priv(dev)->steer[pf_num]; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return false; + mgm = mailbox->buf; + + if (mlx4_READ_ENTRY(dev, index, mailbox)) + goto out; + members_count = be32_to_cpu(mgm->members_count) & 0xffffff; + for (i = 0; i < members_count; i++) { + qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK; + if (!get_promisc_qp(dev, pf_num, steer, qpn) && qpn != tqpn) { + /* the qp is not promisc, the entry can't be removed */ + goto out; + } + } + /* All the qps currently registered for this entry are promiscuous, + * Checking for duplicates */ + ret = true; + list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) { + if (entry->index == index) { + if (list_empty(&entry->duplicates)) { + list_del(&entry->list); + kfree(entry); + } else { + /* This entry contains duplicates so it shouldn't be removed */ + ret = false; + goto out; + } + } + } + +out: + mlx4_free_cmd_mailbox(dev, mailbox); + return ret; +} + +static int add_promisc_qp(struct mlx4_dev *dev, u8 vep_num, u8 port, + enum mlx4_steer_type steer, u32 qpn) +{ + struct mlx4_steer *s_steer; + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_mgm *mgm; + struct mlx4_steer_index *entry; + struct mlx4_promisc_qp *pqp; + struct mlx4_promisc_qp *dqp; + u32 members_count; + u32 prot; + int i; + bool found; + int last_index; + int err; + u8 pf_num; + struct mlx4_priv *priv = mlx4_priv(dev); + pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1); + s_steer = &mlx4_priv(dev)->steer[pf_num]; + + mutex_lock(&priv->mcg_table.mutex); + + if (get_promisc_qp(dev, pf_num, steer, qpn)) { + err = 0; /* Noting to do, already exists */ + goto out_mutex; + } + + pqp = kmalloc(sizeof *pqp, GFP_KERNEL); + if (!pqp) { + err = -ENOMEM; + goto out_mutex; + } + pqp->qpn = qpn; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) { + err = -ENOMEM; + goto out_alloc; + } + mgm = mailbox->buf; + + /* the promisc qp needs to be added for each one of the steering + * entries, if it already exists, needs to be added as a duplicate + * for this entry */ + list_for_each_entry(entry, &s_steer->steer_entries[steer], list) { + err = mlx4_READ_ENTRY(dev, entry->index, mailbox); + if (err) + goto out_mailbox; + + members_count = be32_to_cpu(mgm->members_count) & 0xffffff; + prot = be32_to_cpu(mgm->members_count) >> 30; + found = false; + for (i = 0; i < members_count; i++) { + if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) { + /* Entry already exists, add to duplicates */ + dqp = kmalloc(sizeof *dqp, GFP_KERNEL); + if (!dqp) + goto out_mailbox; + dqp->qpn = qpn; + list_add_tail(&dqp->list, &entry->duplicates); + found = true; + } + } + if (!found) { + /* Need to add the qpn to mgm */ + if (members_count == MLX4_QP_PER_MGM) { + /* entry is full */ + err = -ENOMEM; + goto out_mailbox; + } + mgm->qp[members_count++] = cpu_to_be32(qpn & MGM_QPN_MASK); + mgm->members_count = cpu_to_be32(members_count | (prot << 30)); + err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); + if (err) + goto out_mailbox; + } + last_index = entry->index; + } + + /* add the new qpn to list of promisc qps */ + list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); + /* now need to add all the promisc qps to default entry */ + memset(mgm, 0, sizeof *mgm); + members_count = 0; + list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) + mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); + mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); + + err = mlx4_WRITE_PROMISC(dev, vep_num, port, steer, mailbox); + if (err) + goto out_list; + + mlx4_free_cmd_mailbox(dev, mailbox); + mutex_unlock(&priv->mcg_table.mutex); + return 0; + +out_list: + list_del(&pqp->list); +out_mailbox: + mlx4_free_cmd_mailbox(dev, mailbox); +out_alloc: + kfree(pqp); +out_mutex: + mutex_unlock(&priv->mcg_table.mutex); + return err; +} + +static int remove_promisc_qp(struct mlx4_dev *dev, u8 vep_num, u8 port, + enum mlx4_steer_type steer, u32 qpn) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_steer *s_steer; + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_mgm *mgm; + struct mlx4_steer_index *entry; + struct mlx4_promisc_qp *pqp; + struct mlx4_promisc_qp *dqp; + u32 members_count; + bool found; + bool back_to_list = false; + int loc, i; + int err; + u8 pf_num; + + pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1); + s_steer = &mlx4_priv(dev)->steer[pf_num]; + mutex_lock(&priv->mcg_table.mutex); + + pqp = get_promisc_qp(dev, pf_num, steer, qpn); + if (unlikely(!pqp)) { + mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn); + /* nothing to do */ + err = 0; + goto out_mutex; + } + + /*remove from list of promisc qps */ + list_del(&pqp->list); + + /* set the default entry not to include the removed one */ + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) { + err = -ENOMEM; + back_to_list = true; + goto out_list; + } + mgm = mailbox->buf; + members_count = 0; + list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) + mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); + mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); + + err = mlx4_WRITE_PROMISC(dev, vep_num, port, steer, mailbox); + if (err) + goto out_mailbox; + + /* remove the qp from all the steering entries*/ + list_for_each_entry(entry, &s_steer->steer_entries[steer], list) { + found = false; + list_for_each_entry(dqp, &entry->duplicates, list) { + if (dqp->qpn == qpn) { + found = true; + break; + } + } + if (found) { + /* a duplicate, no need to change the mgm, + * only update the duplicates list */ + list_del(&dqp->list); + kfree(dqp); + } else { + err = mlx4_READ_ENTRY(dev, entry->index, mailbox); + if (err) + goto out_mailbox; + members_count = be32_to_cpu(mgm->members_count) & 0xffffff; + for (loc = -1, i = 0; i < members_count; ++i) + if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) + loc = i; + + mgm->members_count = cpu_to_be32(--members_count | + (MLX4_PROT_ETH << 30)); + mgm->qp[loc] = mgm->qp[i - 1]; + mgm->qp[i - 1] = 0; + + err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); + if (err) + goto out_mailbox; + } + + } + +out_mailbox: + mlx4_free_cmd_mailbox(dev, mailbox); +out_list: + if (back_to_list) + list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); + else + kfree(pqp); +out_mutex: + mutex_unlock(&priv->mcg_table.mutex); + return err; +} + /* * Caller must hold MCG table semaphore. gid and mgm parameters must * be properly aligned for command interface. @@ -94,15 +549,17 @@ static int mlx4_MGID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox * If no AMGM exists for given gid, *index = -1, *prev = index of last * entry in hash chain and *mgm holds end of hash chain. */ -static int find_mgm(struct mlx4_dev *dev, - u8 *gid, enum mlx4_protocol protocol, - struct mlx4_cmd_mailbox *mgm_mailbox, - u16 *hash, int *prev, int *index) +static int find_entry(struct mlx4_dev *dev, u8 port, + u8 *gid, enum mlx4_protocol prot, + enum mlx4_steer_type steer, + struct mlx4_cmd_mailbox *mgm_mailbox, + u16 *hash, int *prev, int *index) { struct mlx4_cmd_mailbox *mailbox; struct mlx4_mgm *mgm = mgm_mailbox->buf; u8 *mgid; int err; + u8 op_mod = (prot == MLX4_PROT_ETH) ? !!(dev->caps.vep_mc_steering) : 0; mailbox = mlx4_alloc_cmd_mailbox(dev); if (IS_ERR(mailbox)) @@ -111,7 +568,7 @@ static int find_mgm(struct mlx4_dev *dev, memcpy(mgid, gid, 16); - err = mlx4_MGID_HASH(dev, mailbox, hash); + err = mlx4_GID_HASH(dev, mailbox, hash, op_mod); mlx4_free_cmd_mailbox(dev, mailbox); if (err) return err; @@ -123,11 +580,11 @@ static int find_mgm(struct mlx4_dev *dev, *prev = -1; do { - err = mlx4_READ_MCG(dev, *index, mgm_mailbox); + err = mlx4_READ_ENTRY(dev, *index, mgm_mailbox); if (err) return err; - if (!memcmp(mgm->gid, zero_gid, 16)) { + if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) { if (*index != *hash) { mlx4_err(dev, "Found zero MGID in AMGM.\n"); err = -EINVAL; @@ -136,7 +593,7 @@ static int find_mgm(struct mlx4_dev *dev, } if (!memcmp(mgm->gid, gid, 16) && - be32_to_cpu(mgm->members_count) >> 30 == protocol) + be32_to_cpu(mgm->members_count) >> 30 == prot) return err; *prev = *index; @@ -147,8 +604,9 @@ static int find_mgm(struct mlx4_dev *dev, return err; } -int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - int block_mcast_loopback, enum mlx4_protocol protocol) +int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], + int block_mcast_loopback, enum mlx4_protocol prot, + enum mlx4_steer_type steer) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_cmd_mailbox *mailbox; @@ -159,6 +617,8 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], int link = 0; int i; int err; + u8 port = gid[5]; + u8 new_entry = 0; mailbox = mlx4_alloc_cmd_mailbox(dev); if (IS_ERR(mailbox)) @@ -166,14 +626,16 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], mgm = mailbox->buf; mutex_lock(&priv->mcg_table.mutex); - - err = find_mgm(dev, gid, protocol, mailbox, &hash, &prev, &index); + err = find_entry(dev, port, gid, prot, steer, + mailbox, &hash, &prev, &index); if (err) goto out; if (index != -1) { - if (!memcmp(mgm->gid, zero_gid, 16)) + if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) { + new_entry = 1; memcpy(mgm->gid, gid, 16); + } } else { link = 1; @@ -209,26 +671,34 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], else mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK); - mgm->members_count = cpu_to_be32(members_count | (u32) protocol << 30); + mgm->members_count = cpu_to_be32(members_count | (u32) prot << 30); - err = mlx4_WRITE_MCG(dev, index, mailbox); + err = mlx4_WRITE_ENTRY(dev, index, mailbox); if (err) goto out; if (!link) goto out; - err = mlx4_READ_MCG(dev, prev, mailbox); + err = mlx4_READ_ENTRY(dev, prev, mailbox); if (err) goto out; mgm->next_gid_index = cpu_to_be32(index << 6); - err = mlx4_WRITE_MCG(dev, prev, mailbox); + err = mlx4_WRITE_ENTRY(dev, prev, mailbox); if (err) goto out; out: + if (prot == MLX4_PROT_ETH) { + /* manage the steering entry for promisc mode */ + if (new_entry) + new_steering_entry(dev, 0, port, steer, index, qp->qpn); + else + existing_steering_entry(dev, 0, port, steer, + index, qp->qpn); + } if (err && link && index != -1) { if (index < dev->caps.num_mgms) mlx4_warn(dev, "Got AMGM index %d < %d", @@ -242,10 +712,9 @@ out: mlx4_free_cmd_mailbox(dev, mailbox); return err; } -EXPORT_SYMBOL_GPL(mlx4_multicast_attach); -int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - enum mlx4_protocol protocol) +int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], + enum mlx4_protocol prot, enum mlx4_steer_type steer) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_cmd_mailbox *mailbox; @@ -255,6 +724,8 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], int prev, index; int i, loc; int err; + u8 port = gid[5]; + bool removed_entry = false; mailbox = mlx4_alloc_cmd_mailbox(dev); if (IS_ERR(mailbox)) @@ -263,7 +734,8 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], mutex_lock(&priv->mcg_table.mutex); - err = find_mgm(dev, gid, protocol, mailbox, &hash, &prev, &index); + err = find_entry(dev, port, gid, prot, steer, + mailbox, &hash, &prev, &index); if (err) goto out; @@ -273,6 +745,11 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], goto out; } + /* if this pq is also a promisc qp, it shouldn't be removed */ + if (prot == MLX4_PROT_ETH && + check_duplicate_entry(dev, 0, port, steer, index, qp->qpn)) + goto out; + members_count = be32_to_cpu(mgm->members_count) & 0xffffff; for (loc = -1, i = 0; i < members_count; ++i) if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) @@ -285,26 +762,31 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], } - mgm->members_count = cpu_to_be32(--members_count | (u32) protocol << 30); + mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30); mgm->qp[loc] = mgm->qp[i - 1]; mgm->qp[i - 1] = 0; - if (i != 1) { - err = mlx4_WRITE_MCG(dev, index, mailbox); + if (prot == MLX4_PROT_ETH) + removed_entry = can_remove_steering_entry(dev, 0, port, steer, index, qp->qpn); + if (i != 1 && (prot != MLX4_PROT_ETH || !removed_entry)) { + err = mlx4_WRITE_ENTRY(dev, index, mailbox); goto out; } + /* We are going to delete the entry, members count should be 0 */ + mgm->members_count = cpu_to_be32((u32) prot << 30); + if (prev == -1) { /* Remove entry from MGM */ int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6; if (amgm_index) { - err = mlx4_READ_MCG(dev, amgm_index, mailbox); + err = mlx4_READ_ENTRY(dev, amgm_index, mailbox); if (err) goto out; } else memset(mgm->gid, 0, 16); - err = mlx4_WRITE_MCG(dev, index, mailbox); + err = mlx4_WRITE_ENTRY(dev, index, mailbox); if (err) goto out; @@ -319,13 +801,13 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], } else { /* Remove entry from AMGM */ int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; - err = mlx4_READ_MCG(dev, prev, mailbox); + err = mlx4_READ_ENTRY(dev, prev, mailbox); if (err) goto out; mgm->next_gid_index = cpu_to_be32(cur_next_index << 6); - err = mlx4_WRITE_MCG(dev, prev, mailbox); + err = mlx4_WRITE_ENTRY(dev, prev, mailbox); if (err) goto out; @@ -343,8 +825,85 @@ out: mlx4_free_cmd_mailbox(dev, mailbox); return err; } + + +int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], + int block_mcast_loopback, enum mlx4_protocol prot) +{ + enum mlx4_steer_type steer; + + steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER; + + if (prot == MLX4_PROT_ETH && !dev->caps.vep_mc_steering) + return 0; + + if (prot == MLX4_PROT_ETH) + gid[7] |= (steer << 1); + + return mlx4_qp_attach_common(dev, qp, gid, + block_mcast_loopback, prot, + steer); +} +EXPORT_SYMBOL_GPL(mlx4_multicast_attach); + +int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], + enum mlx4_protocol prot) +{ + enum mlx4_steer_type steer; + + steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER; + + if (prot == MLX4_PROT_ETH && !dev->caps.vep_mc_steering) + return 0; + + if (prot == MLX4_PROT_ETH) { + gid[7] |= (steer << 1); + } + + return mlx4_qp_detach_common(dev, qp, gid, prot, steer); +} EXPORT_SYMBOL_GPL(mlx4_multicast_detach); + +int mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port) +{ + if (!dev->caps.vep_mc_steering) + return 0; + + + return add_promisc_qp(dev, 0, port, MLX4_MC_STEER, qpn); +} +EXPORT_SYMBOL_GPL(mlx4_multicast_promisc_add); + +int mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port) +{ + if (!dev->caps.vep_mc_steering) + return 0; + + + return remove_promisc_qp(dev, 0, port, MLX4_MC_STEER, qpn); +} +EXPORT_SYMBOL_GPL(mlx4_multicast_promisc_remove); + +int mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port) +{ + if (!dev->caps.vep_mc_steering) + return 0; + + + return add_promisc_qp(dev, 0, port, MLX4_UC_STEER, qpn); +} +EXPORT_SYMBOL_GPL(mlx4_unicast_promisc_add); + +int mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port) +{ + if (!dev->caps.vep_mc_steering) + return 0; + + return remove_promisc_qp(dev, 0, port, MLX4_UC_STEER, qpn); +} +EXPORT_SYMBOL_GPL(mlx4_unicast_promisc_remove); + int mlx4_init_mcg_table(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index 0da5bb7285b4..c1e0e5f1bcdb 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -105,6 +105,7 @@ struct mlx4_bitmap { u32 max; u32 reserved_top; u32 mask; + u32 avail; spinlock_t lock; unsigned long *table; }; @@ -162,6 +163,27 @@ struct mlx4_fw { u8 catas_bar; }; +#define MGM_QPN_MASK 0x00FFFFFF +#define MGM_BLCK_LB_BIT 30 + +struct mlx4_promisc_qp { + struct list_head list; + u32 qpn; +}; + +struct mlx4_steer_index { + struct list_head list; + unsigned int index; + struct list_head duplicates; +}; + +struct mlx4_mgm { + __be32 next_gid_index; + __be32 members_count; + u32 reserved[2]; + u8 gid[16]; + __be32 qp[MLX4_QP_PER_MGM]; +}; struct mlx4_cmd { struct pci_pool *pool; void __iomem *hcr; @@ -265,6 +287,10 @@ struct mlx4_vlan_table { int max; }; +struct mlx4_mac_entry { + u64 mac; +}; + struct mlx4_port_info { struct mlx4_dev *dev; int port; @@ -272,7 +298,9 @@ struct mlx4_port_info { struct device_attribute port_attr; enum mlx4_port_type tmp_type; struct mlx4_mac_table mac_table; + struct radix_tree_root mac_tree; struct mlx4_vlan_table vlan_table; + int base_qpn; }; struct mlx4_sense { @@ -282,6 +310,17 @@ struct mlx4_sense { struct delayed_work sense_poll; }; +struct mlx4_msix_ctl { + u64 pool_bm; + spinlock_t pool_lock; +}; + +struct mlx4_steer { + struct list_head promisc_qps[MLX4_NUM_STEERS]; + struct list_head steer_entries[MLX4_NUM_STEERS]; + struct list_head high_prios; +}; + struct mlx4_priv { struct mlx4_dev dev; @@ -313,6 +352,11 @@ struct mlx4_priv { struct mlx4_port_info port[MLX4_MAX_PORTS + 1]; struct mlx4_sense sense; struct mutex port_mutex; + struct mlx4_msix_ctl msix_ctl; + struct mlx4_steer *steer; + struct list_head bf_list; + struct mutex bf_mutex; + struct io_mapping *bf_mapping; }; static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev) @@ -328,6 +372,7 @@ u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap); void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj); u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align); void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt); +u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap); int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, u32 reserved_bot, u32 resetrved_top); void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap); @@ -403,4 +448,9 @@ void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table); int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port); int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps); +int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], + enum mlx4_protocol prot, enum mlx4_steer_type steer); +int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], + int block_mcast_loopback, enum mlx4_protocol prot, + enum mlx4_steer_type steer); #endif /* MLX4_H */ diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index dfed6a07c2d7..e30f6099c0de 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -49,8 +49,8 @@ #include "en_port.h" #define DRV_NAME "mlx4_en" -#define DRV_VERSION "1.5.1.6" -#define DRV_RELDATE "August 2010" +#define DRV_VERSION "1.5.4.1" +#define DRV_RELDATE "March 2011" #define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN) @@ -62,6 +62,7 @@ #define MLX4_EN_PAGE_SHIFT 12 #define MLX4_EN_PAGE_SIZE (1 << MLX4_EN_PAGE_SHIFT) #define MAX_RX_RINGS 16 +#define MIN_RX_RINGS 4 #define TXBB_SIZE 64 #define HEADROOM (2048 / TXBB_SIZE + 1) #define STAMP_STRIDE 64 @@ -124,6 +125,7 @@ enum { #define MLX4_EN_RX_SIZE_THRESH 1024 #define MLX4_EN_RX_RATE_THRESH (1000000 / MLX4_EN_RX_COAL_TIME_HIGH) #define MLX4_EN_SAMPLE_INTERVAL 0 +#define MLX4_EN_AVG_PKT_SMALL 256 #define MLX4_EN_AUTO_CONF 0xffff @@ -214,6 +216,9 @@ struct mlx4_en_tx_desc { #define MLX4_EN_USE_SRQ 0x01000000 +#define MLX4_EN_CX3_LOW_ID 0x1000 +#define MLX4_EN_CX3_HIGH_ID 0x1005 + struct mlx4_en_rx_alloc { struct page *page; u16 offset; @@ -243,6 +248,8 @@ struct mlx4_en_tx_ring { unsigned long bytes; unsigned long packets; spinlock_t comp_lock; + struct mlx4_bf bf; + bool bf_enabled; }; struct mlx4_en_rx_desc { @@ -453,6 +460,7 @@ struct mlx4_en_priv { struct mlx4_en_rss_map rss_map; u32 flags; #define MLX4_EN_FLAG_PROMISC 0x1 +#define MLX4_EN_FLAG_MC_PROMISC 0x2 u32 tx_ring_num; u32 rx_ring_num; u32 rx_skb_size; @@ -461,6 +469,7 @@ struct mlx4_en_priv { u16 log_rx_info; struct mlx4_en_tx_ring tx_ring[MAX_TX_RINGS]; + int tx_vector; struct mlx4_en_rx_ring rx_ring[MAX_RX_RINGS]; struct mlx4_en_cq tx_cq[MAX_TX_RINGS]; struct mlx4_en_cq rx_cq[MAX_RX_RINGS]; @@ -476,6 +485,13 @@ struct mlx4_en_priv { int mc_addrs_cnt; struct mlx4_en_stat_out_mbox hw_stats; int vids[128]; + bool wol; +}; + +enum mlx4_en_wol { + MLX4_EN_WOL_MAGIC = (1ULL << 61), + MLX4_EN_WOL_ENABLED = (1ULL << 62), + MLX4_EN_WOL_DO_MODIFY = (1ULL << 63), }; @@ -486,12 +502,13 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, int mlx4_en_start_port(struct net_device *dev); void mlx4_en_stop_port(struct net_device *dev); -void mlx4_en_free_resources(struct mlx4_en_priv *priv); +void mlx4_en_free_resources(struct mlx4_en_priv *priv, bool reserve_vectors); int mlx4_en_alloc_resources(struct mlx4_en_priv *priv); int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, int entries, int ring, enum cq_type mode); -void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); +void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, + bool reserve_vectors); int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); @@ -503,7 +520,7 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb); netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev); int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, - u32 size, u16 stride); + int qpn, u32 size, u16 stride); void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring); int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, diff --git a/drivers/net/mlx4/pd.c b/drivers/net/mlx4/pd.c index c4988d6bd5b2..1286b886dcea 100644 --- a/drivers/net/mlx4/pd.c +++ b/drivers/net/mlx4/pd.c @@ -32,12 +32,17 @@ */ #include <linux/errno.h> +#include <linux/io-mapping.h> #include <asm/page.h> #include "mlx4.h" #include "icm.h" +enum { + MLX4_NUM_RESERVED_UARS = 8 +}; + int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -77,6 +82,7 @@ int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar) return -ENOMEM; uar->pfn = (pci_resource_start(dev->pdev, 2) >> PAGE_SHIFT) + uar->index; + uar->map = NULL; return 0; } @@ -88,6 +94,102 @@ void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar) } EXPORT_SYMBOL_GPL(mlx4_uar_free); +int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_uar *uar; + int err = 0; + int idx; + + if (!priv->bf_mapping) + return -ENOMEM; + + mutex_lock(&priv->bf_mutex); + if (!list_empty(&priv->bf_list)) + uar = list_entry(priv->bf_list.next, struct mlx4_uar, bf_list); + else { + if (mlx4_bitmap_avail(&priv->uar_table.bitmap) < MLX4_NUM_RESERVED_UARS) { + err = -ENOMEM; + goto out; + } + uar = kmalloc(sizeof *uar, GFP_KERNEL); + if (!uar) { + err = -ENOMEM; + goto out; + } + err = mlx4_uar_alloc(dev, uar); + if (err) + goto free_kmalloc; + + uar->map = ioremap(uar->pfn << PAGE_SHIFT, PAGE_SIZE); + if (!uar->map) { + err = -ENOMEM; + goto free_uar; + } + + uar->bf_map = io_mapping_map_wc(priv->bf_mapping, uar->index << PAGE_SHIFT); + if (!uar->bf_map) { + err = -ENOMEM; + goto unamp_uar; + } + uar->free_bf_bmap = 0; + list_add(&uar->bf_list, &priv->bf_list); + } + + bf->uar = uar; + idx = ffz(uar->free_bf_bmap); + uar->free_bf_bmap |= 1 << idx; + bf->uar = uar; + bf->offset = 0; + bf->buf_size = dev->caps.bf_reg_size / 2; + bf->reg = uar->bf_map + idx * dev->caps.bf_reg_size; + if (uar->free_bf_bmap == (1 << dev->caps.bf_regs_per_page) - 1) + list_del_init(&uar->bf_list); + + goto out; + +unamp_uar: + bf->uar = NULL; + iounmap(uar->map); + +free_uar: + mlx4_uar_free(dev, uar); + +free_kmalloc: + kfree(uar); + +out: + mutex_unlock(&priv->bf_mutex); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_bf_alloc); + +void mlx4_bf_free(struct mlx4_dev *dev, struct mlx4_bf *bf) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int idx; + + if (!bf->uar || !bf->uar->bf_map) + return; + + mutex_lock(&priv->bf_mutex); + idx = (bf->reg - bf->uar->bf_map) / dev->caps.bf_reg_size; + bf->uar->free_bf_bmap &= ~(1 << idx); + if (!bf->uar->free_bf_bmap) { + if (!list_empty(&bf->uar->bf_list)) + list_del(&bf->uar->bf_list); + + io_mapping_unmap(bf->uar->bf_map); + iounmap(bf->uar->map); + mlx4_uar_free(dev, bf->uar); + kfree(bf->uar); + } else if (list_empty(&bf->uar->bf_list)) + list_add(&bf->uar->bf_list, &priv->bf_list); + + mutex_unlock(&priv->bf_mutex); +} +EXPORT_SYMBOL_GPL(mlx4_bf_free); + int mlx4_init_uar_table(struct mlx4_dev *dev) { if (dev->caps.num_uars <= 128) { diff --git a/drivers/net/mlx4/port.c b/drivers/net/mlx4/port.c index 451339559bdc..eca7d8596f87 100644 --- a/drivers/net/mlx4/port.c +++ b/drivers/net/mlx4/port.c @@ -90,12 +90,79 @@ static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port, return err; } -int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index) +static int mlx4_uc_steer_add(struct mlx4_dev *dev, u8 port, + u64 mac, int *qpn, u8 reserve) { - struct mlx4_mac_table *table = &mlx4_priv(dev)->port[port].mac_table; + struct mlx4_qp qp; + u8 gid[16] = {0}; + int err; + + if (reserve) { + err = mlx4_qp_reserve_range(dev, 1, 1, qpn); + if (err) { + mlx4_err(dev, "Failed to reserve qp for mac registration\n"); + return err; + } + } + qp.qpn = *qpn; + + mac &= 0xffffffffffffULL; + mac = cpu_to_be64(mac << 16); + memcpy(&gid[10], &mac, ETH_ALEN); + gid[5] = port; + gid[7] = MLX4_UC_STEER << 1; + + err = mlx4_qp_attach_common(dev, &qp, gid, 0, + MLX4_PROT_ETH, MLX4_UC_STEER); + if (err && reserve) + mlx4_qp_release_range(dev, *qpn, 1); + + return err; +} + +static void mlx4_uc_steer_release(struct mlx4_dev *dev, u8 port, + u64 mac, int qpn, u8 free) +{ + struct mlx4_qp qp; + u8 gid[16] = {0}; + + qp.qpn = qpn; + mac &= 0xffffffffffffULL; + mac = cpu_to_be64(mac << 16); + memcpy(&gid[10], &mac, ETH_ALEN); + gid[5] = port; + gid[7] = MLX4_UC_STEER << 1; + + mlx4_qp_detach_common(dev, &qp, gid, MLX4_PROT_ETH, MLX4_UC_STEER); + if (free) + mlx4_qp_release_range(dev, qpn, 1); +} + +int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *qpn, u8 wrap) +{ + struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; + struct mlx4_mac_table *table = &info->mac_table; + struct mlx4_mac_entry *entry; int i, err = 0; int free = -1; + if (dev->caps.vep_uc_steering) { + err = mlx4_uc_steer_add(dev, port, mac, qpn, 1); + if (!err) { + entry = kmalloc(sizeof *entry, GFP_KERNEL); + if (!entry) { + mlx4_uc_steer_release(dev, port, mac, *qpn, 1); + return -ENOMEM; + } + entry->mac = mac; + err = radix_tree_insert(&info->mac_tree, *qpn, entry); + if (err) { + mlx4_uc_steer_release(dev, port, mac, *qpn, 1); + return err; + } + } else + return err; + } mlx4_dbg(dev, "Registering MAC: 0x%llx\n", (unsigned long long) mac); mutex_lock(&table->mutex); for (i = 0; i < MLX4_MAX_MAC_NUM - 1; i++) { @@ -106,7 +173,6 @@ int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index) if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { /* MAC already registered, increase refernce count */ - *index = i; ++table->refs[i]; goto out; } @@ -137,7 +203,8 @@ int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index) goto out; } - *index = free; + if (!dev->caps.vep_uc_steering) + *qpn = info->base_qpn + free; ++table->total; out: mutex_unlock(&table->mutex); @@ -145,20 +212,52 @@ out: } EXPORT_SYMBOL_GPL(mlx4_register_mac); -void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int index) +static int validate_index(struct mlx4_dev *dev, + struct mlx4_mac_table *table, int index) { - struct mlx4_mac_table *table = &mlx4_priv(dev)->port[port].mac_table; + int err = 0; - mutex_lock(&table->mutex); - if (!table->refs[index]) { - mlx4_warn(dev, "No MAC entry for index %d\n", index); - goto out; + if (index < 0 || index >= table->max || !table->entries[index]) { + mlx4_warn(dev, "No valid Mac entry for the given index\n"); + err = -EINVAL; } - if (--table->refs[index]) { - mlx4_warn(dev, "Have more references for index %d," - "no need to modify MAC table\n", index); - goto out; + return err; +} + +static int find_index(struct mlx4_dev *dev, + struct mlx4_mac_table *table, u64 mac) +{ + int i; + for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { + if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) + return i; } + /* Mac not found */ + return -EINVAL; +} + +void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int qpn) +{ + struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; + struct mlx4_mac_table *table = &info->mac_table; + int index = qpn - info->base_qpn; + struct mlx4_mac_entry *entry; + + if (dev->caps.vep_uc_steering) { + entry = radix_tree_lookup(&info->mac_tree, qpn); + if (entry) { + mlx4_uc_steer_release(dev, port, entry->mac, qpn, 1); + radix_tree_delete(&info->mac_tree, qpn); + index = find_index(dev, table, entry->mac); + kfree(entry); + } + } + + mutex_lock(&table->mutex); + + if (validate_index(dev, table, index)) + goto out; + table->entries[index] = 0; mlx4_set_port_mac_table(dev, port, table->entries); --table->total; @@ -167,6 +266,44 @@ out: } EXPORT_SYMBOL_GPL(mlx4_unregister_mac); +int mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac, u8 wrap) +{ + struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; + struct mlx4_mac_table *table = &info->mac_table; + int index = qpn - info->base_qpn; + struct mlx4_mac_entry *entry; + int err; + + if (dev->caps.vep_uc_steering) { + entry = radix_tree_lookup(&info->mac_tree, qpn); + if (!entry) + return -EINVAL; + index = find_index(dev, table, entry->mac); + mlx4_uc_steer_release(dev, port, entry->mac, qpn, 0); + entry->mac = new_mac; + err = mlx4_uc_steer_add(dev, port, entry->mac, &qpn, 0); + if (err || index < 0) + return err; + } + + mutex_lock(&table->mutex); + + err = validate_index(dev, table, index); + if (err) + goto out; + + table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID); + + err = mlx4_set_port_mac_table(dev, port, table->entries); + if (unlikely(err)) { + mlx4_err(dev, "Failed adding MAC: 0x%llx\n", (unsigned long long) new_mac); + table->entries[index] = 0; + } +out: + mutex_unlock(&table->mutex); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_replace_mac); static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, __be32 *entries) { diff --git a/drivers/net/mlx4/profile.c b/drivers/net/mlx4/profile.c index e749f82865fe..b967647d0c76 100644 --- a/drivers/net/mlx4/profile.c +++ b/drivers/net/mlx4/profile.c @@ -107,9 +107,7 @@ u64 mlx4_make_profile(struct mlx4_dev *dev, profile[MLX4_RES_AUXC].num = request->num_qp; profile[MLX4_RES_SRQ].num = request->num_srq; profile[MLX4_RES_CQ].num = request->num_cq; - profile[MLX4_RES_EQ].num = min_t(unsigned, dev_cap->max_eqs, - dev_cap->reserved_eqs + - num_possible_cpus() + 1); + profile[MLX4_RES_EQ].num = min_t(unsigned, dev_cap->max_eqs, MAX_MSIX); profile[MLX4_RES_DMPT].num = request->num_mpt; profile[MLX4_RES_CMPT].num = MLX4_NUM_CMPTS; profile[MLX4_RES_MTT].num = request->num_mtt; diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index a7f2eed9a08a..673dc600c891 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1312,17 +1312,26 @@ myri10ge_unmap_rx_page(struct pci_dev *pdev, * page into an skb */ static inline int -myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx, - int bytes, int len, __wsum csum) +myri10ge_rx_done(struct myri10ge_slice_state *ss, int len, __wsum csum, + int lro_enabled) { struct myri10ge_priv *mgp = ss->mgp; struct sk_buff *skb; struct skb_frag_struct rx_frags[MYRI10GE_MAX_FRAGS_PER_FRAME]; - int i, idx, hlen, remainder; + struct myri10ge_rx_buf *rx; + int i, idx, hlen, remainder, bytes; struct pci_dev *pdev = mgp->pdev; struct net_device *dev = mgp->dev; u8 *va; + if (len <= mgp->small_bytes) { + rx = &ss->rx_small; + bytes = mgp->small_bytes; + } else { + rx = &ss->rx_big; + bytes = mgp->big_bytes; + } + len += MXGEFW_PAD; idx = rx->cnt & rx->mask; va = page_address(rx->info[idx].page) + rx->info[idx].page_offset; @@ -1341,7 +1350,7 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx, remainder -= MYRI10GE_ALLOC_SIZE; } - if (dev->features & NETIF_F_LRO) { + if (lro_enabled) { rx_frags[0].page_offset += MXGEFW_PAD; rx_frags[0].size -= MXGEFW_PAD; len -= MXGEFW_PAD; @@ -1463,7 +1472,7 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget) { struct myri10ge_rx_done *rx_done = &ss->rx_done; struct myri10ge_priv *mgp = ss->mgp; - struct net_device *netdev = mgp->dev; + unsigned long rx_bytes = 0; unsigned long rx_packets = 0; unsigned long rx_ok; @@ -1474,18 +1483,18 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget) u16 length; __wsum checksum; + /* + * Prevent compiler from generating more than one ->features memory + * access to avoid theoretical race condition with functions that + * change NETIF_F_LRO flag at runtime. + */ + bool lro_enabled = ACCESS_ONCE(mgp->dev->features) & NETIF_F_LRO; + while (rx_done->entry[idx].length != 0 && work_done < budget) { length = ntohs(rx_done->entry[idx].length); rx_done->entry[idx].length = 0; checksum = csum_unfold(rx_done->entry[idx].checksum); - if (length <= mgp->small_bytes) - rx_ok = myri10ge_rx_done(ss, &ss->rx_small, - mgp->small_bytes, - length, checksum); - else - rx_ok = myri10ge_rx_done(ss, &ss->rx_big, - mgp->big_bytes, - length, checksum); + rx_ok = myri10ge_rx_done(ss, length, checksum, lro_enabled); rx_packets += rx_ok; rx_bytes += rx_ok * (unsigned long)length; cnt++; @@ -1497,7 +1506,7 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget) ss->stats.rx_packets += rx_packets; ss->stats.rx_bytes += rx_bytes; - if (netdev->features & NETIF_F_LRO) + if (lro_enabled) lro_flush_all(&rx_done->lro_mgr); /* restock receive rings if needed */ @@ -3645,6 +3654,7 @@ static void myri10ge_free_slices(struct myri10ge_priv *mgp) dma_free_coherent(&pdev->dev, bytes, ss->fw_stats, ss->fw_stats_bus); ss->fw_stats = NULL; + netif_napi_del(&ss->napi); } } kfree(mgp->ss); diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 653d308e0f5d..3bdcc803ec68 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -871,7 +871,7 @@ static int netxen_nic_set_flags(struct net_device *netdev, u32 data) struct netxen_adapter *adapter = netdev_priv(netdev); int hw_lro; - if (data & ~ETH_FLAG_LRO) + if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) return -EINVAL; if (!(adapter->capabilities & NX_FW_CAPABILITY_HW_LRO)) diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 40fa59e2fd5c..32678b6c6b39 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -9501,7 +9501,7 @@ static struct niu_parent * __devinit niu_new_parent(struct niu *np, struct niu_parent *p; int i; - plat_dev = platform_device_register_simple("niu", niu_parent_index, + plat_dev = platform_device_register_simple("niu-board", niu_parent_index, NULL, 0); if (IS_ERR(plat_dev)) return NULL; diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 8c66e22c3a0a..50986840c99c 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -2441,7 +2441,7 @@ static struct pci_error_handlers pch_gbe_err_handler = { .resume = pch_gbe_io_resume }; -static struct pci_driver pch_gbe_pcidev = { +static struct pci_driver pch_gbe_driver = { .name = KBUILD_MODNAME, .id_table = pch_gbe_pcidev_id, .probe = pch_gbe_probe, @@ -2458,7 +2458,7 @@ static int __init pch_gbe_init_module(void) { int ret; - ret = pci_register_driver(&pch_gbe_pcidev); + ret = pci_register_driver(&pch_gbe_driver); if (copybreak != PCH_GBE_COPYBREAK_DEFAULT) { if (copybreak == 0) { pr_info("copybreak disabled\n"); @@ -2472,7 +2472,7 @@ static int __init pch_gbe_init_module(void) static void __exit pch_gbe_exit_module(void) { - pci_unregister_driver(&pch_gbe_pcidev); + pci_unregister_driver(&pch_gbe_driver); } module_init(pch_gbe_init_module); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 993c52c82aeb..e870c0698bbe 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -442,11 +442,11 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, u32 flags, phy_interface_t interface) { struct device *d = &phydev->dev; + int err; /* Assume that if there is no driver, that it doesn't * exist, and we should use the genphy driver. */ if (NULL == d->driver) { - int err; d->driver = &genphy_driver.driver; err = d->driver->probe(d); @@ -474,7 +474,11 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, /* Do initial configuration here, now that * we have certain key parameters * (dev_flags and interface) */ - return phy_init_hw(phydev); + err = phy_init_hw(phydev); + if (err) + phy_detach(phydev); + + return err; } /** diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c index 43583309a65d..31e9407a0739 100644 --- a/drivers/net/ppp_deflate.c +++ b/drivers/net/ppp_deflate.c @@ -129,7 +129,7 @@ static void *z_comp_alloc(unsigned char *options, int opt_len) state->strm.next_in = NULL; state->w_size = w_size; - state->strm.workspace = vmalloc(zlib_deflate_workspacesize()); + state->strm.workspace = vmalloc(zlib_deflate_workspacesize(-w_size, 8)); if (state->strm.workspace == NULL) goto out_free; diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 4c14510e2a87..45b2755d6cba 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -1003,7 +1003,7 @@ static int qlcnic_set_flags(struct net_device *netdev, u32 data) struct qlcnic_adapter *adapter = netdev_priv(netdev); int hw_lro; - if (data & ~ETH_FLAG_LRO) + if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) return -EINVAL; if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)) diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 5e403511289d..493b0de3848b 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -2685,9 +2685,9 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp) rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL, ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | - tp->mii.supports_gmii ? + (tp->mii.supports_gmii ? ADVERTISED_1000baseT_Half | - ADVERTISED_1000baseT_Full : 0); + ADVERTISED_1000baseT_Full : 0)); if (RTL_R8(PHYstatus) & TBI_Enable) netif_info(tp, link, dev, "TBI auto-negotiating\n"); diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index 44150f2f7bfd..26afbaae23f0 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -382,7 +382,7 @@ static void rionet_remove(struct rio_dev *rdev) struct rionet_peer *peer, *tmp; free_pages((unsigned long)rionet_active, rdev->net->hport->sys_size ? - __ilog2(sizeof(void *)) + 4 : 0); + __fls(sizeof(void *)) + 4 : 0); unregister_netdev(ndev); free_netdev(ndev); @@ -450,7 +450,7 @@ static int rionet_setup_netdev(struct rio_mport *mport) } rionet_active = (struct rio_dev **)__get_free_pages(GFP_KERNEL, - mport->sys_size ? __ilog2(sizeof(void *)) + 4 : 0); + mport->sys_size ? __fls(sizeof(void *)) + 4 : 0); if (!rionet_active) { rc = -ENOMEM; goto out; @@ -571,5 +571,5 @@ static void __exit rionet_exit(void) rio_unregister_driver(&rionet_driver); } -module_init(rionet_init); +late_initcall(rionet_init); module_exit(rionet_exit); diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 2ad6364103ea..356e74d20b80 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -6726,7 +6726,7 @@ static int s2io_ethtool_set_flags(struct net_device *dev, u32 data) int rc = 0; int changed = 0; - if (data & ~ETH_FLAG_LRO) + if (ethtool_invalid_flags(dev, data, ETH_FLAG_LRO)) return -EINVAL; if (data & ETH_FLAG_LRO) { diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index b8bd936374f2..d890679e4c4d 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1054,6 +1054,7 @@ static int efx_init_io(struct efx_nic *efx) { struct pci_dev *pci_dev = efx->pci_dev; dma_addr_t dma_mask = efx->type->max_dma_mask; + bool use_wc; int rc; netif_dbg(efx, probe, efx->net_dev, "initialising I/O\n"); @@ -1104,8 +1105,21 @@ static int efx_init_io(struct efx_nic *efx) rc = -EIO; goto fail3; } - efx->membase = ioremap_wc(efx->membase_phys, - efx->type->mem_map_size); + + /* bug22643: If SR-IOV is enabled then tx push over a write combined + * mapping is unsafe. We need to disable write combining in this case. + * MSI is unsupported when SR-IOV is enabled, and the firmware will + * have removed the MSI capability. So write combining is safe if + * there is an MSI capability. + */ + use_wc = (!EFX_WORKAROUND_22643(efx) || + pci_find_capability(pci_dev, PCI_CAP_ID_MSI)); + if (use_wc) + efx->membase = ioremap_wc(efx->membase_phys, + efx->type->mem_map_size); + else + efx->membase = ioremap_nocache(efx->membase_phys, + efx->type->mem_map_size); if (!efx->membase) { netif_err(efx, probe, efx->net_dev, "could not map memory BAR at %llx+%x\n", diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h index e4dd3a7f304b..99ff11400cef 100644 --- a/drivers/net/sfc/workarounds.h +++ b/drivers/net/sfc/workarounds.h @@ -38,6 +38,8 @@ #define EFX_WORKAROUND_15783 EFX_WORKAROUND_ALWAYS /* Legacy interrupt storm when interrupt fifo fills */ #define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA +/* Write combining and sriov=enabled are incompatible */ +#define EFX_WORKAROUND_22643 EFX_WORKAROUND_SIENA /* Spurious parity errors in TSORT buffers */ #define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A diff --git a/drivers/net/skfp/Makefile b/drivers/net/skfp/Makefile index cb23580fcffa..b0be0234abf6 100644 --- a/drivers/net/skfp/Makefile +++ b/drivers/net/skfp/Makefile @@ -17,4 +17,4 @@ skfp-objs := skfddi.o hwmtm.o fplustm.o smt.o cfm.o \ # projects. To keep the source common for all those drivers (and # thus simplify fixes to it), please do not clean it up! -EXTRA_CFLAGS += -Idrivers/net/skfp -DPCI -DMEM_MAPPED_IO -Wno-strict-prototypes +ccflags-y := -Idrivers/net/skfp -DPCI -DMEM_MAPPED_IO -Wno-strict-prototypes diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index a4f2bd52e546..36045f3b0327 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -144,11 +144,7 @@ static int full_duplex[MAX_UNITS] = {0, }; /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (2 * HZ) -/* - * This SUCKS. - * We need a much better method to determine if dma_addr_t is 64-bit. - */ -#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || (defined(CONFIG_MIPS) && ((defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) || defined(CONFIG_64BIT))) || (defined(__powerpc64__) || defined(CONFIG_PHYS_64BIT)) +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT /* 64-bit dma_addr_t */ #define ADDR_64BITS /* This chip uses 64 bit addresses. */ #define netdrv_addr_t __le64 diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ebec88882c3b..73c942d85f07 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -48,9 +48,9 @@ #include <net/ip.h> #include <asm/system.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/byteorder.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #ifdef CONFIG_SPARC #include <asm/idprom.h> @@ -13118,7 +13118,7 @@ done: static struct pci_dev * __devinit tg3_find_peer(struct tg3 *); -static void inline vlan_features_add(struct net_device *dev, unsigned long flags) +static inline void vlan_features_add(struct net_device *dev, unsigned long flags) { dev->vlan_features |= flags; } diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 6f600cced6e1..3ec22c307797 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -433,4 +433,19 @@ config USB_SIERRA_NET To compile this driver as a module, choose M here: the module will be called sierra_net. +config USB_VL600 + tristate "LG VL600 modem dongle" + depends on USB_NET_CDCETHER + select USB_ACM + help + Select this if you want to use an LG Electronics 4G/LTE usb modem + called VL600. This driver only handles the ethernet + interface exposed by the modem firmware. To establish a connection + you will first need a userspace program that sends the right + command to the modem through its CDC ACM port, and most + likely also a DHCP client. See this thread about using the + 4G modem from Verizon: + + http://ubuntuforums.org/showpost.php?p=10589647&postcount=17 + endmenu diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index cac170301187..c7ec8a5f0a90 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile @@ -27,4 +27,5 @@ obj-$(CONFIG_USB_IPHETH) += ipheth.o obj-$(CONFIG_USB_SIERRA_NET) += sierra_net.o obj-$(CONFIG_USB_NET_CX82310_ETH) += cx82310_eth.o obj-$(CONFIG_USB_NET_CDC_NCM) += cdc_ncm.o +obj-$(CONFIG_USB_VL600) += lg-vl600.o diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c index 5f3b97668e63..8f128541656d 100644 --- a/drivers/net/usb/cdc_eem.c +++ b/drivers/net/usb/cdc_eem.c @@ -340,7 +340,7 @@ next: static const struct driver_info eem_info = { .description = "CDC EEM Device", - .flags = FLAG_ETHER, + .flags = FLAG_ETHER | FLAG_POINTTOPOINT, .bind = eem_bind, .rx_fixup = eem_rx_fixup, .tx_fixup = eem_tx_fixup, diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 9a60e415d76b..341f7056a800 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -378,7 +378,7 @@ static void dumpspeed(struct usbnet *dev, __le32 *speeds) __le32_to_cpu(speeds[1]) / 1000); } -static void cdc_status(struct usbnet *dev, struct urb *urb) +void usbnet_cdc_status(struct usbnet *dev, struct urb *urb) { struct usb_cdc_notification *event; @@ -418,8 +418,9 @@ static void cdc_status(struct usbnet *dev, struct urb *urb) break; } } +EXPORT_SYMBOL_GPL(usbnet_cdc_status); -static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) +int usbnet_cdc_bind(struct usbnet *dev, struct usb_interface *intf) { int status; struct cdc_state *info = (void *) &dev->data; @@ -441,6 +442,7 @@ static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) */ return 0; } +EXPORT_SYMBOL_GPL(usbnet_cdc_bind); static int cdc_manage_power(struct usbnet *dev, int on) { @@ -450,20 +452,20 @@ static int cdc_manage_power(struct usbnet *dev, int on) static const struct driver_info cdc_info = { .description = "CDC Ethernet Device", - .flags = FLAG_ETHER, + .flags = FLAG_ETHER | FLAG_POINTTOPOINT, // .check_connect = cdc_check_connect, - .bind = cdc_bind, + .bind = usbnet_cdc_bind, .unbind = usbnet_cdc_unbind, - .status = cdc_status, + .status = usbnet_cdc_status, .manage_power = cdc_manage_power, }; static const struct driver_info mbm_info = { .description = "Mobile Broadband Network Device", .flags = FLAG_WWAN, - .bind = cdc_bind, + .bind = usbnet_cdc_bind, .unbind = usbnet_cdc_unbind, - .status = cdc_status, + .status = usbnet_cdc_status, .manage_power = cdc_manage_power, }; @@ -560,6 +562,13 @@ static const struct usb_device_id products [] = { .driver_info = 0, }, +/* LG Electronics VL600 wants additional headers on every frame */ +{ + USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM, + USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), + .driver_info = 0, +}, + /* * WHITELIST!!! * diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 7113168473cf..967371f04454 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1237,7 +1237,7 @@ static int cdc_ncm_manage_power(struct usbnet *dev, int status) static const struct driver_info cdc_ncm_info = { .description = "CDC NCM", - .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET, + .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET, .bind = cdc_ncm_bind, .unbind = cdc_ncm_unbind, .check_connect = cdc_ncm_check_connect, diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c index ca39ace0b0eb..fc5f13d47ad9 100644 --- a/drivers/net/usb/cdc_subset.c +++ b/drivers/net/usb/cdc_subset.c @@ -89,6 +89,7 @@ static int always_connected (struct usbnet *dev) static const struct driver_info ali_m5632_info = { .description = "ALi M5632", + .flags = FLAG_POINTTOPOINT, }; #endif @@ -110,6 +111,7 @@ static const struct driver_info ali_m5632_info = { static const struct driver_info an2720_info = { .description = "AnchorChips/Cypress 2720", + .flags = FLAG_POINTTOPOINT, // no reset available! // no check_connect available! @@ -132,6 +134,7 @@ static const struct driver_info an2720_info = { static const struct driver_info belkin_info = { .description = "Belkin, eTEK, or compatible", + .flags = FLAG_POINTTOPOINT, }; #endif /* CONFIG_USB_BELKIN */ @@ -157,6 +160,7 @@ static const struct driver_info belkin_info = { static const struct driver_info epson2888_info = { .description = "Epson USB Device", .check_connect = always_connected, + .flags = FLAG_POINTTOPOINT, .in = 4, .out = 3, }; @@ -173,6 +177,7 @@ static const struct driver_info epson2888_info = { #define HAVE_HARDWARE static const struct driver_info kc2190_info = { .description = "KC Technology KC-190", + .flags = FLAG_POINTTOPOINT, }; #endif /* CONFIG_USB_KC2190 */ @@ -200,16 +205,19 @@ static const struct driver_info kc2190_info = { static const struct driver_info linuxdev_info = { .description = "Linux Device", .check_connect = always_connected, + .flags = FLAG_POINTTOPOINT, }; static const struct driver_info yopy_info = { .description = "Yopy", .check_connect = always_connected, + .flags = FLAG_POINTTOPOINT, }; static const struct driver_info blob_info = { .description = "Boot Loader OBject", .check_connect = always_connected, + .flags = FLAG_POINTTOPOINT, }; #endif /* CONFIG_USB_ARMLINUX */ diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c index dcd57c37ef73..c4cfd1dea881 100644 --- a/drivers/net/usb/gl620a.c +++ b/drivers/net/usb/gl620a.c @@ -193,7 +193,7 @@ static int genelink_bind(struct usbnet *dev, struct usb_interface *intf) static const struct driver_info genelink_info = { .description = "Genesys GeneLink", - .flags = FLAG_FRAMING_GL | FLAG_NO_SETINT, + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_GL | FLAG_NO_SETINT, .bind = genelink_bind, .rx_fixup = genelink_rx_fixup, .tx_fixup = genelink_tx_fixup, diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c new file mode 100644 index 000000000000..1d83ccfd7277 --- /dev/null +++ b/drivers/net/usb/lg-vl600.c @@ -0,0 +1,346 @@ +/* + * Ethernet interface part of the LG VL600 LTE modem (4G dongle) + * + * Copyright (C) 2011 Intel Corporation + * Author: Andrzej Zaborowski <balrogg@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/mii.h> +#include <linux/usb.h> +#include <linux/usb/cdc.h> +#include <linux/usb/usbnet.h> +#include <linux/if_ether.h> +#include <linux/if_arp.h> +#include <linux/inetdevice.h> + +/* + * The device has a CDC ACM port for modem control (it claims to be + * CDC ACM anyway) and a CDC Ethernet port for actual network data. + * It will however ignore data on both ports that is not encapsulated + * in a specific way, any data returned is also encapsulated the same + * way. The headers don't seem to follow any popular standard. + * + * This driver adds and strips these headers from the ethernet frames + * sent/received from the CDC Ethernet port. The proprietary header + * replaces the standard ethernet header in a packet so only actual + * ethernet frames are allowed. The headers allow some form of + * multiplexing by using non standard values of the .h_proto field. + * Windows/Mac drivers do send a couple of such frames to the device + * during initialisation, with protocol set to 0x0906 or 0x0b06 and (what + * seems to be) a flag in the .dummy_flags. This doesn't seem necessary + * for modem operation but can possibly be used for GPS or other funcitons. + */ + +struct vl600_frame_hdr { + __le32 len; + __le32 serial; + __le32 pkt_cnt; + __le32 dummy_flags; + __le32 dummy; + __le32 magic; +} __attribute__((packed)); + +struct vl600_pkt_hdr { + __le32 dummy[2]; + __le32 len; + __be16 h_proto; +} __attribute__((packed)); + +struct vl600_state { + struct sk_buff *current_rx_buf; +}; + +static int vl600_bind(struct usbnet *dev, struct usb_interface *intf) +{ + int ret; + struct vl600_state *s = kzalloc(sizeof(struct vl600_state), GFP_KERNEL); + + if (!s) + return -ENOMEM; + + ret = usbnet_cdc_bind(dev, intf); + if (ret) { + kfree(s); + return ret; + } + + dev->driver_priv = s; + + /* ARP packets don't go through, but they're also of no use. The + * subnet has only two hosts anyway: us and the gateway / DHCP + * server (probably simulated by modem firmware or network operator) + * whose address changes everytime we connect to the intarwebz and + * who doesn't bother answering ARP requests either. So hardware + * addresses have no meaning, the destination and the source of every + * packet depend only on whether it is on the IN or OUT endpoint. */ + dev->net->flags |= IFF_NOARP; + + return ret; +} + +static void vl600_unbind(struct usbnet *dev, struct usb_interface *intf) +{ + struct vl600_state *s = dev->driver_priv; + + if (s->current_rx_buf) + dev_kfree_skb(s->current_rx_buf); + + kfree(s); + + return usbnet_cdc_unbind(dev, intf); +} + +static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + struct vl600_frame_hdr *frame; + struct vl600_pkt_hdr *packet; + struct ethhdr *ethhdr; + int packet_len, count; + struct sk_buff *buf = skb; + struct sk_buff *clone; + struct vl600_state *s = dev->driver_priv; + + /* Frame lengths are generally 4B multiplies but every couple of + * hours there's an odd number of bytes sized yet correct frame, + * so don't require this. */ + + /* Allow a packet (or multiple packets batched together) to be + * split across many frames. We don't allow a new batch to + * begin in the same frame another one is ending however, and no + * leading or trailing pad bytes. */ + if (s->current_rx_buf) { + frame = (struct vl600_frame_hdr *) s->current_rx_buf->data; + if (skb->len + s->current_rx_buf->len > + le32_to_cpup(&frame->len)) { + netif_err(dev, ifup, dev->net, "Fragment too long\n"); + dev->net->stats.rx_length_errors++; + goto error; + } + + buf = s->current_rx_buf; + memcpy(skb_put(buf, skb->len), skb->data, skb->len); + } else if (skb->len < 4) { + netif_err(dev, ifup, dev->net, "Frame too short\n"); + dev->net->stats.rx_length_errors++; + goto error; + } + + frame = (struct vl600_frame_hdr *) buf->data; + /* NOTE: Should check that frame->magic == 0x53544448? + * Otherwise if we receive garbage at the beginning of the frame + * we may end up allocating a huge buffer and saving all the + * future incoming data into it. */ + + if (buf->len < sizeof(*frame) || + buf->len != le32_to_cpup(&frame->len)) { + /* Save this fragment for later assembly */ + if (s->current_rx_buf) + return 0; + + s->current_rx_buf = skb_copy_expand(skb, 0, + le32_to_cpup(&frame->len), GFP_ATOMIC); + if (!s->current_rx_buf) { + netif_err(dev, ifup, dev->net, "Reserving %i bytes " + "for packet assembly failed.\n", + le32_to_cpup(&frame->len)); + dev->net->stats.rx_errors++; + } + + return 0; + } + + count = le32_to_cpup(&frame->pkt_cnt); + + skb_pull(buf, sizeof(*frame)); + + while (count--) { + if (buf->len < sizeof(*packet)) { + netif_err(dev, ifup, dev->net, "Packet too short\n"); + goto error; + } + + packet = (struct vl600_pkt_hdr *) buf->data; + packet_len = sizeof(*packet) + le32_to_cpup(&packet->len); + if (packet_len > buf->len) { + netif_err(dev, ifup, dev->net, + "Bad packet length stored in header\n"); + goto error; + } + + /* Packet header is same size as the ethernet header + * (sizeof(*packet) == sizeof(*ethhdr)), additionally + * the h_proto field is in the same place so we just leave it + * alone and fill in the remaining fields. + */ + ethhdr = (struct ethhdr *) skb->data; + if (be16_to_cpup(ðhdr->h_proto) == ETH_P_ARP && + buf->len > 0x26) { + /* Copy the addresses from packet contents */ + memcpy(ethhdr->h_source, + &buf->data[sizeof(*ethhdr) + 0x8], + ETH_ALEN); + memcpy(ethhdr->h_dest, + &buf->data[sizeof(*ethhdr) + 0x12], + ETH_ALEN); + } else { + memset(ethhdr->h_source, 0, ETH_ALEN); + memcpy(ethhdr->h_dest, dev->net->dev_addr, ETH_ALEN); + } + + if (count) { + /* Not the last packet in this batch */ + clone = skb_clone(buf, GFP_ATOMIC); + if (!clone) + goto error; + + skb_trim(clone, packet_len); + usbnet_skb_return(dev, clone); + + skb_pull(buf, (packet_len + 3) & ~3); + } else { + skb_trim(buf, packet_len); + + if (s->current_rx_buf) { + usbnet_skb_return(dev, buf); + s->current_rx_buf = NULL; + return 0; + } + + return 1; + } + } + +error: + if (s->current_rx_buf) { + dev_kfree_skb_any(s->current_rx_buf); + s->current_rx_buf = NULL; + } + dev->net->stats.rx_errors++; + return 0; +} + +static struct sk_buff *vl600_tx_fixup(struct usbnet *dev, + struct sk_buff *skb, gfp_t flags) +{ + struct sk_buff *ret; + struct vl600_frame_hdr *frame; + struct vl600_pkt_hdr *packet; + static uint32_t serial = 1; + int orig_len = skb->len - sizeof(struct ethhdr); + int full_len = (skb->len + sizeof(struct vl600_frame_hdr) + 3) & ~3; + + frame = (struct vl600_frame_hdr *) skb->data; + if (skb->len > sizeof(*frame) && skb->len == le32_to_cpup(&frame->len)) + return skb; /* Already encapsulated? */ + + if (skb->len < sizeof(struct ethhdr)) + /* Drop, device can only deal with ethernet packets */ + return NULL; + + if (!skb_cloned(skb)) { + int headroom = skb_headroom(skb); + int tailroom = skb_tailroom(skb); + + if (tailroom >= full_len - skb->len - sizeof(*frame) && + headroom >= sizeof(*frame)) + /* There's enough head and tail room */ + goto encapsulate; + + if (headroom + tailroom + skb->len >= full_len) { + /* There's enough total room, just readjust */ + skb->data = memmove(skb->head + sizeof(*frame), + skb->data, skb->len); + skb_set_tail_pointer(skb, skb->len); + goto encapsulate; + } + } + + /* Alloc a new skb with the required size */ + ret = skb_copy_expand(skb, sizeof(struct vl600_frame_hdr), full_len - + skb->len - sizeof(struct vl600_frame_hdr), flags); + dev_kfree_skb_any(skb); + if (!ret) + return ret; + skb = ret; + +encapsulate: + /* Packet header is same size as ethernet packet header + * (sizeof(*packet) == sizeof(struct ethhdr)), additionally the + * h_proto field is in the same place so we just leave it alone and + * overwrite the remaining fields. + */ + packet = (struct vl600_pkt_hdr *) skb->data; + memset(&packet->dummy, 0, sizeof(packet->dummy)); + packet->len = cpu_to_le32(orig_len); + + frame = (struct vl600_frame_hdr *) skb_push(skb, sizeof(*frame)); + memset(frame, 0, sizeof(*frame)); + frame->len = cpu_to_le32(full_len); + frame->serial = cpu_to_le32(serial++); + frame->pkt_cnt = cpu_to_le32(1); + + if (skb->len < full_len) /* Pad */ + skb_put(skb, full_len - skb->len); + + return skb; +} + +static const struct driver_info vl600_info = { + .description = "LG VL600 modem", + .flags = FLAG_ETHER | FLAG_RX_ASSEMBLE, + .bind = vl600_bind, + .unbind = vl600_unbind, + .status = usbnet_cdc_status, + .rx_fixup = vl600_rx_fixup, + .tx_fixup = vl600_tx_fixup, +}; + +static const struct usb_device_id products[] = { + { + USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM, + USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &vl600_info, + }, + {}, /* End */ +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver lg_vl600_driver = { + .name = "lg-vl600", + .id_table = products, + .probe = usbnet_probe, + .disconnect = usbnet_disconnect, + .suspend = usbnet_suspend, + .resume = usbnet_resume, +}; + +static int __init vl600_init(void) +{ + return usb_register(&lg_vl600_driver); +} +module_init(vl600_init); + +static void __exit vl600_exit(void) +{ + usb_deregister(&lg_vl600_driver); +} +module_exit(vl600_exit); + +MODULE_AUTHOR("Anrzej Zaborowski"); +MODULE_DESCRIPTION("LG-VL600 modem's ethernet link"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c index ba72a7281cb0..01db4602a39e 100644 --- a/drivers/net/usb/net1080.c +++ b/drivers/net/usb/net1080.c @@ -560,7 +560,7 @@ static int net1080_bind(struct usbnet *dev, struct usb_interface *intf) static const struct driver_info net1080_info = { .description = "NetChip TurboCONNECT", - .flags = FLAG_FRAMING_NC, + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_NC, .bind = net1080_bind, .reset = net1080_reset, .check_connect = net1080_check_connect, diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c index 08ad269f6b4e..823c53751307 100644 --- a/drivers/net/usb/plusb.c +++ b/drivers/net/usb/plusb.c @@ -96,7 +96,7 @@ static int pl_reset(struct usbnet *dev) static const struct driver_info prolific_info = { .description = "Prolific PL-2301/PL-2302", - .flags = FLAG_NO_SETINT, + .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT, /* some PL-2302 versions seem to fail usb_set_interface() */ .reset = pl_reset, }; diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index dd8a4adf48ca..5994a25c56ac 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -573,7 +573,7 @@ EXPORT_SYMBOL_GPL(rndis_tx_fixup); static const struct driver_info rndis_info = { .description = "RNDIS device", - .flags = FLAG_ETHER | FLAG_FRAMING_RN | FLAG_NO_SETINT, + .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT, .bind = rndis_bind, .unbind = rndis_unbind, .status = rndis_status, diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index bc86f4b6ecc2..727874d9deb6 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -49,6 +49,8 @@ struct smsc95xx_priv { u32 mac_cr; + u32 hash_hi; + u32 hash_lo; spinlock_t mac_cr_lock; bool use_tx_csum; bool use_rx_csum; @@ -370,10 +372,11 @@ static void smsc95xx_set_multicast(struct net_device *netdev) { struct usbnet *dev = netdev_priv(netdev); struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - u32 hash_hi = 0; - u32 hash_lo = 0; unsigned long flags; + pdata->hash_hi = 0; + pdata->hash_lo = 0; + spin_lock_irqsave(&pdata->mac_cr_lock, flags); if (dev->net->flags & IFF_PROMISC) { @@ -394,13 +397,13 @@ static void smsc95xx_set_multicast(struct net_device *netdev) u32 bitnum = smsc95xx_hash(ha->addr); u32 mask = 0x01 << (bitnum & 0x1F); if (bitnum & 0x20) - hash_hi |= mask; + pdata->hash_hi |= mask; else - hash_lo |= mask; + pdata->hash_lo |= mask; } netif_dbg(dev, drv, dev->net, "HASHH=0x%08X, HASHL=0x%08X\n", - hash_hi, hash_lo); + pdata->hash_hi, pdata->hash_lo); } else { netif_dbg(dev, drv, dev->net, "receive own packets only\n"); pdata->mac_cr &= @@ -410,8 +413,8 @@ static void smsc95xx_set_multicast(struct net_device *netdev) spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); /* Initiate async writes, as we can't wait for completion here */ - smsc95xx_write_reg_async(dev, HASHH, &hash_hi); - smsc95xx_write_reg_async(dev, HASHL, &hash_lo); + smsc95xx_write_reg_async(dev, HASHH, &pdata->hash_hi); + smsc95xx_write_reg_async(dev, HASHL, &pdata->hash_lo); smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr); } diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 95c41d56631c..069c1cf0fdf7 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -387,8 +387,12 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) { if (dev->driver_info->rx_fixup && - !dev->driver_info->rx_fixup (dev, skb)) - goto error; + !dev->driver_info->rx_fixup (dev, skb)) { + /* With RX_ASSEMBLE, rx_fixup() must update counters */ + if (!(dev->driver_info->flags & FLAG_RX_ASSEMBLE)) + dev->net->stats.rx_errors++; + goto done; + } // else network stack removes extra byte if we forced a short packet if (skb->len) { @@ -401,8 +405,8 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) } netif_dbg(dev, rx_err, dev->net, "drop\n"); -error: dev->net->stats.rx_errors++; +done: skb_queue_tail(&dev->done, skb); } @@ -1376,7 +1380,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) // else "eth%d" when there's reasonable doubt. userspace // can rename the link if it knows better. if ((dev->driver_info->flags & FLAG_ETHER) != 0 && - (net->dev_addr [0] & 0x02) == 0) + ((dev->driver_info->flags & FLAG_POINTTOPOINT) == 0 || + (net->dev_addr [0] & 0x02) == 0)) strcpy (net->name, "eth%d"); /* WLAN devices should always be named "wlan%d" */ if ((dev->driver_info->flags & FLAG_WLAN) != 0) diff --git a/drivers/net/usb/zaurus.c b/drivers/net/usb/zaurus.c index 3eb0b167b5b4..241756e0e86f 100644 --- a/drivers/net/usb/zaurus.c +++ b/drivers/net/usb/zaurus.c @@ -102,7 +102,7 @@ static int always_connected (struct usbnet *dev) static const struct driver_info zaurus_sl5x00_info = { .description = "Sharp Zaurus SL-5x00", - .flags = FLAG_FRAMING_Z, + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z, .check_connect = always_connected, .bind = zaurus_bind, .unbind = usbnet_cdc_unbind, @@ -112,7 +112,7 @@ static const struct driver_info zaurus_sl5x00_info = { static const struct driver_info zaurus_pxa_info = { .description = "Sharp Zaurus, PXA-2xx based", - .flags = FLAG_FRAMING_Z, + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z, .check_connect = always_connected, .bind = zaurus_bind, .unbind = usbnet_cdc_unbind, @@ -122,7 +122,7 @@ static const struct driver_info zaurus_pxa_info = { static const struct driver_info olympus_mxl_info = { .description = "Olympus R1000", - .flags = FLAG_FRAMING_Z, + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z, .check_connect = always_connected, .bind = zaurus_bind, .unbind = usbnet_cdc_unbind, @@ -258,7 +258,7 @@ bad_desc: static const struct driver_info bogus_mdlm_info = { .description = "pseudo-MDLM (BLAN) device", - .flags = FLAG_FRAMING_Z, + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z, .check_connect = always_connected, .tx_fixup = zaurus_tx_fixup, .bind = blan_mdlm_bind, diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 105d7f0630cc..2de9b90c5f8f 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -171,7 +171,7 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->ip_summed == CHECKSUM_NONE) skb->ip_summed = rcv_priv->ip_summed; - length = skb->len + ETH_HLEN; + length = skb->len; if (dev_forward_skb(rcv, skb) != NET_RX_SUCCESS) goto rx_drop; diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index 81254be85b92..51f2ef142a5b 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -304,8 +304,8 @@ vmxnet3_set_flags(struct net_device *netdev, u32 data) u8 lro_present = (netdev->features & NETIF_F_LRO) == 0 ? 0 : 1; unsigned long flags; - if (data & ~ETH_FLAG_LRO) - return -EOPNOTSUPP; + if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) + return -EINVAL; if (lro_requested ^ lro_present) { /* toggle the LRO feature*/ diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c index 1dd3a21b3a43..c5eb034107fd 100644 --- a/drivers/net/vxge/vxge-ethtool.c +++ b/drivers/net/vxge/vxge-ethtool.c @@ -1117,8 +1117,8 @@ static int vxge_set_flags(struct net_device *dev, u32 data) struct vxgedev *vdev = netdev_priv(dev); enum vxge_hw_status status; - if (data & ~ETH_FLAG_RXHASH) - return -EOPNOTSUPP; + if (ethtool_invalid_flags(dev, data, ETH_FLAG_RXHASH)) + return -EINVAL; if (!!(data & ETH_FLAG_RXHASH) == vdev->devh->config.rth_en) return 0; diff --git a/drivers/net/wan/lmc/Makefile b/drivers/net/wan/lmc/Makefile index dabdcfed4efd..609710d64eb5 100644 --- a/drivers/net/wan/lmc/Makefile +++ b/drivers/net/wan/lmc/Makefile @@ -14,4 +14,4 @@ lmc-objs := lmc_debug.o lmc_media.o lmc_main.o lmc_proto.o # -DDEBUG \ # -DLMC_PACKET_LOG -EXTRA_CFLAGS += -I. $(DBGDEF) +ccflags-y := -I. $(DBGDEF) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 115f162c617a..dddb85de622d 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1048,6 +1048,8 @@ static int ath9k_start(struct ieee80211_hw *hw) "Starting driver with initial channel: %d MHz\n", curchan->center_freq); + ath9k_ps_wakeup(sc); + mutex_lock(&sc->mutex); /* setup initial channel */ @@ -1143,6 +1145,8 @@ static int ath9k_start(struct ieee80211_hw *hw) mutex_unlock: mutex_unlock(&sc->mutex); + ath9k_ps_restore(sc); + return r; } @@ -2160,6 +2164,8 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) if (!ath_drain_all_txq(sc, false)) ath_reset(sc, false); + ieee80211_wake_queues(hw); + out: ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); mutex_unlock(&sc->mutex); diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 960d717ca7c2..a3241cd089b1 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1328,7 +1328,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + for (i = 0; i < sc->hw->max_rates; i++) { struct ieee80211_tx_rate *rate = &tx_info->status.rates[i]; if (!rate->count) break; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index ef22096d40c9..26734e53b37f 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1725,8 +1725,8 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, u8 tidno; spin_lock_bh(&txctl->txq->axq_lock); - - if (ieee80211_is_data_qos(hdr->frame_control) && txctl->an) { + if ((sc->sc_flags & SC_OP_TXAGGR) && txctl->an && + ieee80211_is_data_qos(hdr->frame_control)) { tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; tid = ATH_AN_2_TID(txctl->an, tidno); diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index c6a5fae634a0..9cad061cc1d2 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -443,6 +443,7 @@ struct carl9170_ba_stats { u8 ampdu_len; u8 ampdu_ack_len; bool clear; + bool req; }; struct carl9170_sta_info { diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index ede3d7e5a048..89fe60accf85 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1355,6 +1355,7 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw, tid_info = rcu_dereference(sta_info->agg[tid]); sta_info->stats[tid].clear = true; + sta_info->stats[tid].req = false; if (tid_info) { bitmap_zero(tid_info->bitmap, CARL9170_BAW_SIZE); diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index 0ef70b6fc512..cb70ed7ec5cc 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -383,6 +383,7 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar, if (sta_info->stats[tid].clear) { sta_info->stats[tid].clear = false; + sta_info->stats[tid].req = false; sta_info->stats[tid].ampdu_len = 0; sta_info->stats[tid].ampdu_ack_len = 0; } @@ -391,10 +392,16 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar, if (txinfo->status.rates[0].count == 1) sta_info->stats[tid].ampdu_ack_len++; + if (!(txinfo->flags & IEEE80211_TX_STAT_ACK)) + sta_info->stats[tid].req = true; + if (super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_IMM_BA)) { super->s.rix = sta_info->stats[tid].ampdu_len; super->s.cnt = sta_info->stats[tid].ampdu_ack_len; txinfo->flags |= IEEE80211_TX_STAT_AMPDU; + if (sta_info->stats[tid].req) + txinfo->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; + sta_info->stats[tid].clear = true; } spin_unlock_bh(&tid_info->lock); diff --git a/drivers/net/wireless/hostap/hostap_config.h b/drivers/net/wireless/hostap/hostap_config.h index 30acd39d76a2..2c8f71f0ed45 100644 --- a/drivers/net/wireless/hostap/hostap_config.h +++ b/drivers/net/wireless/hostap/hostap_config.h @@ -30,9 +30,9 @@ /* Following defines can be used to remove unneeded parts of the driver, e.g., * to limit the size of the kernel module. Definitions can be added here in - * hostap_config.h or they can be added to make command with EXTRA_CFLAGS, + * hostap_config.h or they can be added to make command with ccflags-y, * e.g., - * 'make pccard EXTRA_CFLAGS="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"' + * 'make pccard ccflags-y="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"' */ /* Do not include debug messages into the driver */ diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index d418b647be80..a209a0e76bf0 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -1805,6 +1805,15 @@ iwl_legacy_mac_change_interface(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); + if (!ctx->vif || !iwl_legacy_is_ready_rf(priv)) { + /* + * Huh? But wait ... this can maybe happen when + * we're in the middle of a firmware restart! + */ + err = -EBUSY; + goto out; + } + interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes; if (!(interface_modes & BIT(newtype))) { @@ -1832,6 +1841,7 @@ iwl_legacy_mac_change_interface(struct ieee80211_hw *hw, /* success */ iwl_legacy_teardown_interface(priv, vif, true); vif->type = newtype; + vif->p2p = newp2p; err = iwl_legacy_setup_interface(priv, ctx); WARN_ON(err); /* diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c index ab87e1b73529..28eb3d885ba1 100644 --- a/drivers/net/wireless/iwlegacy/iwl3945-base.c +++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c @@ -93,6 +93,7 @@ MODULE_LICENSE("GPL"); struct iwl_mod_params iwl3945_mod_params = { .sw_crypto = 1, .restart_fw = 1, + .disable_hw_scan = 1, /* the rest are 0 by default */ }; @@ -3960,8 +3961,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e * "the hard way", rather than using device's scan. */ if (iwl3945_mod_params.disable_hw_scan) { - dev_printk(KERN_DEBUG, &(pdev->dev), - "sw scan support is deprecated\n"); + IWL_DEBUG_INFO(priv, "Disabling hw_scan\n"); iwl3945_hw_ops.hw_scan = NULL; } @@ -4280,8 +4280,7 @@ MODULE_PARM_DESC(swcrypto, "using software crypto (default 1 [software])"); module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, S_IRUGO); -MODULE_PARM_DESC(disable_hw_scan, - "disable hardware scanning (default 0) (deprecated)"); +MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 1)"); #ifdef CONFIG_IWLWIFI_LEGACY_DEBUG module_param_named(debug, iwlegacy_debug_level, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "debug output mask"); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 2003c1d4295f..08ccb9496f76 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2265,7 +2265,7 @@ signed long iwlagn_wait_notification(struct iwl_priv *priv, int ret; ret = wait_event_timeout(priv->_agn.notif_waitq, - &wait_entry->triggered, + wait_entry->triggered, timeout); spin_lock_bh(&priv->_agn.notif_wait_lock); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 581dc9f10273..321b18b59135 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3009,14 +3009,17 @@ static int iwl_mac_offchannel_tx_cancel_wait(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); - if (!priv->_agn.offchan_tx_skb) - return -EINVAL; + if (!priv->_agn.offchan_tx_skb) { + ret = -EINVAL; + goto unlock; + } priv->_agn.offchan_tx_skb = NULL; ret = iwl_scan_cancel_timeout(priv, 200); if (ret) ret = -EIO; +unlock: mutex_unlock(&priv->mutex); return ret; diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c index 09fae2f0ea08..736bbb9bd1d0 100644 --- a/drivers/net/wireless/orinoco/cfg.c +++ b/drivers/net/wireless/orinoco/cfg.c @@ -153,6 +153,9 @@ static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev, priv->scan_request = request; err = orinoco_hw_trigger_scan(priv, request->ssids); + /* On error the we aren't processing the request */ + if (err) + priv->scan_request = NULL; return err; } diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index f3d396e7544b..62c6b2b37dbe 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -1376,13 +1376,13 @@ static void orinoco_process_scan_results(struct work_struct *work) spin_lock_irqsave(&priv->scan_lock, flags); list_for_each_entry_safe(sd, temp, &priv->scan_list, list) { - spin_unlock_irqrestore(&priv->scan_lock, flags); buf = sd->buf; len = sd->len; type = sd->type; list_del(&sd->list); + spin_unlock_irqrestore(&priv->scan_lock, flags); kfree(sd); if (len > 0) { diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 18d24b7b1e34..7ecc0bda57b3 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -649,8 +649,7 @@ static int __devinit p54spi_probe(struct spi_device *spi) goto err_free_common; } - set_irq_type(gpio_to_irq(p54spi_gpio_irq), - IRQ_TYPE_EDGE_RISING); + irq_set_irq_type(gpio_to_irq(p54spi_gpio_irq), IRQ_TYPE_EDGE_RISING); disable_irq(gpio_to_irq(p54spi_gpio_irq)); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index f1a92144996f..37509d019910 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -719,6 +719,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1761, 0x0b05), USB_DEVICE_DATA(&rt2800usb_ops) }, /* AzureWave */ { USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -729,8 +730,12 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x050d, 0x815c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x050d, 0x825b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x050d, 0x935a), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x050d, 0x935b), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Buffalo */ { USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0411, 0x016f), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Conceptronic */ { USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -817,6 +822,7 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Pegatron */ { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1d4d, 0x0011), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Philips */ { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Planex */ @@ -898,6 +904,8 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Sitecom */ { USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Toshiba */ + { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Zinwell */ { USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) }, #endif @@ -913,7 +921,6 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0b05, 0x1790), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1761, 0x0b05), USB_DEVICE_DATA(&rt2800usb_ops) }, /* AzureWave */ { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -937,6 +944,8 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c17), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Edimax */ + { USB_DEVICE(0x7392, 0x4085), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Encore */ { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Gemtek */ @@ -959,8 +968,8 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x05a6, 0x0101), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1d4d, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1d4d, 0x0011), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Planex */ + { USB_DEVICE(0x2019, 0x5201), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Qcom */ { USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) }, diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c index 4f92cba6810a..f74a8701c67d 100644 --- a/drivers/net/wireless/rtlwifi/efuse.c +++ b/drivers/net/wireless/rtlwifi/efuse.c @@ -410,8 +410,8 @@ bool efuse_shadow_update(struct ieee80211_hw *hw) if (!efuse_shadow_update_chk(hw)) { efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); - memcpy((void *)&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], - (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], + &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, @@ -446,9 +446,9 @@ bool efuse_shadow_update(struct ieee80211_hw *hw) if (word_en != 0x0F) { u8 tmpdata[8]; - memcpy((void *)tmpdata, - (void *)(&rtlefuse-> - efuse_map[EFUSE_MODIFY_MAP][base]), 8); + memcpy(tmpdata, + &rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base], + 8); RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, ("U-efuse\n"), tmpdata, 8); @@ -465,8 +465,8 @@ bool efuse_shadow_update(struct ieee80211_hw *hw) efuse_power_switch(hw, true, false); efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); - memcpy((void *)&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], - (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], + &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("<---\n")); @@ -479,13 +479,12 @@ void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw) struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); if (rtlefuse->autoload_failflag == true) { - memset((void *)(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0]), 128, - 0xFF); + memset(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 0xFF, 128); } else efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); - memcpy((void *)&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], - (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], + &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); } @@ -694,8 +693,8 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) if (offset > 15) return false; - memset((void *)data, PGPKT_DATA_SIZE * sizeof(u8), 0xff); - memset((void *)tmpdata, PGPKT_DATA_SIZE * sizeof(u8), 0xff); + memset(data, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); + memset(tmpdata, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); while (bcontinual && (efuse_addr < EFUSE_MAX_SIZE)) { if (readstate & PG_STATE_HEADER) { @@ -862,7 +861,7 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en); - memset((void *)originaldata, 8 * sizeof(u8), 0xff); + memset(originaldata, 0xff, 8 * sizeof(u8)); if (efuse_pg_packet_read(hw, tmp_pkt.offset, originaldata)) { badworden = efuse_word_enable_data_write(hw, @@ -917,7 +916,7 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, target_pkt.offset = offset; target_pkt.word_en = word_en; - memset((void *)target_pkt.data, 8 * sizeof(u8), 0xFF); + memset(target_pkt.data, 0xFF, 8 * sizeof(u8)); efuse_word_enable_data_read(word_en, data, target_pkt.data); target_word_cnts = efuse_calculate_word_cnts(target_pkt.word_en); @@ -1022,7 +1021,7 @@ static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw, u8 badworden = 0x0F; u8 tmpdata[8]; - memset((void *)tmpdata, PGPKT_DATA_SIZE, 0xff); + memset(tmpdata, 0xff, PGPKT_DATA_SIZE); RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("word_en = %x efuse_addr=%x\n", word_en, efuse_addr)); diff --git a/drivers/net/wireless/wl1251/sdio.c b/drivers/net/wireless/wl1251/sdio.c index d550b5e68d3c..f51a0241a440 100644 --- a/drivers/net/wireless/wl1251/sdio.c +++ b/drivers/net/wireless/wl1251/sdio.c @@ -265,7 +265,7 @@ static int wl1251_sdio_probe(struct sdio_func *func, goto disable; } - set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); + irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); disable_irq(wl->irq); wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq; diff --git a/drivers/net/wireless/wl1251/spi.c b/drivers/net/wireless/wl1251/spi.c index ac872b38960f..af6448c4d3e2 100644 --- a/drivers/net/wireless/wl1251/spi.c +++ b/drivers/net/wireless/wl1251/spi.c @@ -286,7 +286,7 @@ static int __devinit wl1251_spi_probe(struct spi_device *spi) goto out_free; } - set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); + irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); disable_irq(wl->irq); diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile index 1907eafb9b16..5728a918e508 100644 --- a/drivers/net/wireless/zd1211rw/Makefile +++ b/drivers/net/wireless/zd1211rw/Makefile @@ -5,7 +5,5 @@ zd1211rw-objs := zd_chip.o zd_mac.o \ zd_rf_al7230b.o zd_rf_uw2453.o \ zd_rf.o zd_usb.o -ifeq ($(CONFIG_ZD1211RW_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG -endif +ccflags-$(CONFIG_ZD1211RW_DEBUG) := -DDEBUG diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 81e80489a052..58236e6d0921 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -60,6 +60,7 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x157e, 0x3207), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 }, /* ZD1211B */ |