From ea1dae11e0baca5d633207fe50fc3cd30a5d68ee Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Thu, 19 Mar 2009 23:56:20 -0700 Subject: [PATCH 1/9] be2net: replenish when posting to rx-queue is starved in out of mem conditions This is a patch to replenish the rx-queue when it is in a starved state (due to out-of-mem conditions) Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/benet/be.h | 1 + drivers/net/benet/be_main.c | 50 +++++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 63d593d53153..f327be57ca96 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -194,6 +194,7 @@ struct be_adapter { struct be_eq_obj rx_eq; struct be_rx_obj rx_obj; u32 big_page_size; /* Compounded page size shared by rx wrbs */ + bool rx_post_starved; /* Zero rx frags have been posted to BE */ struct vlan_group *vlan_grp; u16 num_vlans; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 897a63de5bdb..80fe1e055d91 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -273,26 +273,6 @@ static void be_rx_eqd_update(struct be_adapter *adapter) rx_eq->cur_eqd = eqd; } -static void be_worker(struct work_struct *work) -{ - struct be_adapter *adapter = - container_of(work, struct be_adapter, work.work); - int status; - - /* Check link */ - be_link_status_update(adapter); - - /* Get Stats */ - status = be_cmd_get_stats(&adapter->ctrl, &adapter->stats.cmd); - if (!status) - netdev_stats_update(adapter); - - /* Set EQ delay */ - be_rx_eqd_update(adapter); - - schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); -} - static struct net_device_stats *be_get_stats(struct net_device *dev) { struct be_adapter *adapter = netdev_priv(dev); @@ -900,8 +880,11 @@ static void be_post_rx_frags(struct be_adapter *adapter) page_info->last_page_user = true; if (posted) { - be_rxq_notify(&adapter->ctrl, rxq->id, posted); atomic_add(posted, &rxq->used); + be_rxq_notify(&adapter->ctrl, rxq->id, posted); + } else if (atomic_read(&rxq->used) == 0) { + /* Let be_worker replenish when memory is available */ + adapter->rx_post_starved = true; } return; @@ -1305,6 +1288,31 @@ int be_poll_tx(struct napi_struct *napi, int budget) return 1; } +static void be_worker(struct work_struct *work) +{ + struct be_adapter *adapter = + container_of(work, struct be_adapter, work.work); + int status; + + /* Check link */ + be_link_status_update(adapter); + + /* Get Stats */ + status = be_cmd_get_stats(&adapter->ctrl, &adapter->stats.cmd); + if (!status) + netdev_stats_update(adapter); + + /* Set EQ delay */ + be_rx_eqd_update(adapter); + + if (adapter->rx_post_starved) { + adapter->rx_post_starved = false; + be_post_rx_frags(adapter); + } + + schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); +} + static void be_msix_enable(struct be_adapter *adapter) { int i, status; From 1ab1ab7543de53c945ea24140409ef67ed173eb4 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Thu, 19 Mar 2009 23:56:46 -0700 Subject: [PATCH 2/9] be2net: fix to restore vlan ids into BE2 during a IF DOWN->UP cycle This is a patch to reconfigure vlan-ids during an i/f down/up cycle Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/benet/be_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 80fe1e055d91..0ecaffb70e58 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -473,7 +473,7 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu) * program them in BE. If more than BE_NUM_VLANS_SUPPORTED are configured, * set the BE in promiscuous VLAN mode. */ -static void be_vids_config(struct net_device *netdev) +static void be_vid_config(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); u16 vtag[BE_NUM_VLANS_SUPPORTED]; @@ -516,7 +516,7 @@ static void be_vlan_add_vid(struct net_device *netdev, u16 vid) adapter->num_vlans++; adapter->vlan_tag[vid] = 1; - be_vids_config(netdev); + be_vid_config(netdev); } static void be_vlan_rem_vid(struct net_device *netdev, u16 vid) @@ -527,7 +527,7 @@ static void be_vlan_rem_vid(struct net_device *netdev, u16 vid) adapter->vlan_tag[vid] = 0; vlan_group_set_device(adapter->vlan_grp, vid, NULL); - be_vids_config(netdev); + be_vid_config(netdev); } static void be_set_multicast_filter(struct net_device *netdev) @@ -1430,6 +1430,8 @@ static int be_open(struct net_device *netdev) if (status != 0) goto do_none; + be_vid_config(netdev); + status = be_cmd_set_flow_control(ctrl, true, true); if (status != 0) goto if_destroy; @@ -1864,8 +1866,6 @@ static int be_resume(struct pci_dev *pdev) pci_set_power_state(pdev, 0); pci_restore_state(pdev); - be_vids_config(netdev); - if (netif_running(netdev)) { rtnl_lock(); be_open(netdev); From 5ed0102fbf36f58091089907213b4bd191ca2e0c Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 19 Mar 2009 23:58:01 -0700 Subject: [PATCH 3/9] sungem: missing net_device_ops Sungem driver only got partially converted to net_device_ops. Since this could cause bugs, please push this to 2.6.29 Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sungem.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 0fcb7503363d..c9c7650826c0 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -2998,8 +2998,11 @@ static const struct net_device_ops gem_netdev_ops = { .ndo_do_ioctl = gem_ioctl, .ndo_tx_timeout = gem_tx_timeout, .ndo_change_mtu = gem_change_mtu, - .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = gem_set_mac_address, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = gem_poll_controller, +#endif }; static int __devinit gem_init_one(struct pci_dev *pdev, @@ -3161,10 +3164,6 @@ static int __devinit gem_init_one(struct pci_dev *pdev, dev->watchdog_timeo = 5 * HZ; dev->irq = pdev->irq; dev->dma = 0; - dev->set_mac_address = gem_set_mac_address; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = gem_poll_controller; -#endif /* Set that now, in case PM kicks in now */ pci_set_drvdata(pdev, dev); From f3f9258678b081c3ef2f036aef450cd2053ef419 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 20 Mar 2009 17:57:36 +0200 Subject: [PATCH 4/9] nl80211: Check that function pointer != NULL before using it NL80211_CMD_GET_MESH_PARAMS and NL80211_CMD_SET_MESH_PARAMS handlers did not verify whether a function pointer is NULL (not supported by the driver) before trying to call the function. The former nl80211 command is available for unprivileged users, too, so this can potentially allow normal users to kill networking (or worse..) if mac80211 is built without CONFIG_MAC80211_MESH=y. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1e728fff474e..31b807af3235 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1908,6 +1908,11 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, if (err) return err; + if (!drv->ops->get_mesh_params) { + err = -EOPNOTSUPP; + goto out; + } + /* Get the mesh params */ rtnl_lock(); err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params); @@ -2017,6 +2022,11 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) if (err) return err; + if (!drv->ops->set_mesh_params) { + err = -EOPNOTSUPP; + goto out; + } + /* This makes sure that there aren't more than 32 mesh config * parameters (otherwise our bitfield scheme would not work.) */ BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32); @@ -2061,6 +2071,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask); rtnl_unlock(); + out: /* cleanup */ cfg80211_put_dev(drv); dev_put(dev); From e2fc4d19292ef2eb208f76976ddc3320cc5839b6 Mon Sep 17 00:00:00 2001 From: Maciej Sosnowski Date: Sat, 21 Mar 2009 13:31:23 -0700 Subject: [PATCH 5/9] dca: add missing copyright/license headers In two dca files copyright and license headers are missing. This patch adds them there. Signed-off-by: Maciej Sosnowski Signed-off-by: David S. Miller --- drivers/dca/dca-sysfs.c | 21 +++++++++++++++++++++ include/linux/dca.h | 20 ++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/drivers/dca/dca-sysfs.c b/drivers/dca/dca-sysfs.c index bb538b9690e0..ee916c9857ee 100644 --- a/drivers/dca/dca-sysfs.c +++ b/drivers/dca/dca-sysfs.c @@ -1,3 +1,24 @@ +/* + * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. + * + * 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. + * + * The full GNU General Public License is included in this distribution in the + * file called COPYING. + */ + #include #include #include diff --git a/include/linux/dca.h b/include/linux/dca.h index b00a753eda53..9c20c7e87d0a 100644 --- a/include/linux/dca.h +++ b/include/linux/dca.h @@ -1,3 +1,23 @@ +/* + * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. + * + * 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. + * + * The full GNU General Public License is included in this distribution in the + * file called COPYING. + */ #ifndef DCA_H #define DCA_H /* DCA Provider API */ From 4b97926ddf51b3919c859e2086fef3c8c3c46c61 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Sat, 21 Mar 2009 16:58:47 -0700 Subject: [PATCH 6/9] dnet: DNET should depend on HAS_IOMEM Signed-off-by: Ilya Yanok Signed-off-by: David S. Miller --- drivers/net/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 435e2e3a82c8..62d732a886f1 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1042,7 +1042,7 @@ config NI65 config DNET tristate "Dave ethernet support (DNET)" - depends on NET_ETHERNET + depends on NET_ETHERNET && HAS_IOMEM select PHYLIB help The Dave ethernet interface (DNET) is found on Qong Board FPGA. From 6580f57d485f70851218813fa053d971915f61fb Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Sun, 22 Mar 2009 21:22:48 -0700 Subject: [PATCH 7/9] net: update dnet.c for bus_id removal Signed-off-by: Stephen Rothwell Signed-off-by: David S. Miller --- drivers/net/dnet.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c index 5c347f70cb67..1b4063222a82 100644 --- a/drivers/net/dnet.c +++ b/drivers/net/dnet.c @@ -280,11 +280,11 @@ static int dnet_mii_probe(struct net_device *dev) /* attach the mac to the phy */ if (bp->capabilities & DNET_HAS_RMII) { - phydev = phy_connect(dev, phydev->dev.bus_id, + phydev = phy_connect(dev, dev_name(&phydev->dev), &dnet_handle_link_change, 0, PHY_INTERFACE_MODE_RMII); } else { - phydev = phy_connect(dev, phydev->dev.bus_id, + phydev = phy_connect(dev, dev_name(&phydev->dev), &dnet_handle_link_change, 0, PHY_INTERFACE_MODE_MII); } @@ -927,7 +927,7 @@ static int __devinit dnet_probe(struct platform_device *pdev) phydev = bp->phy_dev; dev_info(&pdev->dev, "attached PHY driver [%s] " "(mii_bus:phy_addr=%s, irq=%d)\n", - phydev->drv->name, phydev->dev.bus_id, phydev->irq); + phydev->drv->name, dev_name(&phydev->dev), phydev->irq); return 0; From e3162d381fc359ebe5c98a3e216888a7cb200051 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 22 Mar 2009 21:28:39 -0700 Subject: [PATCH 8/9] dm9000: locking bugfix This fixes a locking bug in the dm9000 driver. It calls request_irq() without setting IRQF_DISABLED ... which is correct for handlers that support IRQ sharing, since that behavior is not guaranteed for shared IRQs. However, its IRQ handler then wrongly assumes that IRQs are blocked. So the fix just uses the right spinlock primitives in the IRQ handler. NOTE: this is a classic example of the type of bug which lockdep currently masks by forcibly setting IRQF_DISABLED on IRQ handlers that did not request that flag. Signed-off-by: David Brownell Signed-off-by: David S. Miller --- drivers/net/dm9000.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index bcf92917bbf3..254ec62b5f58 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -930,13 +930,15 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id) struct net_device *dev = dev_id; board_info_t *db = netdev_priv(dev); int int_status; + unsigned long flags; u8 reg_save; dm9000_dbg(db, 3, "entering %s\n", __func__); /* A real interrupt coming */ - spin_lock(&db->lock); + /* holders of db->lock must always block IRQs */ + spin_lock_irqsave(&db->lock, flags); /* Save previous register address */ reg_save = readb(db->io_addr); @@ -972,7 +974,7 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id) /* Restore previous register address */ writeb(reg_save, db->io_addr); - spin_unlock(&db->lock); + spin_unlock_irqrestore(&db->lock, flags); return IRQ_HANDLED; } From 61fa9dcf9329cb92c220f7b656410fbe5e72f933 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Sun, 22 Mar 2009 21:30:52 -0700 Subject: [PATCH 9/9] ucc_geth: Fix oops when using fixed-link support commit b1c4a9dddf09fe99b8f88252718ac5b357363dc4 ("ucc_geth: Change uec phy id to the same format as gianfar's") introduced a regression in the ucc_geth driver that causes this oops when fixed-link is used: Unable to handle kernel paging request for data at address 0x00000000 Faulting instruction address: 0xc0151270 Oops: Kernel access of bad area, sig: 11 [#1] TMCUTU NIP: c0151270 LR: c0151270 CTR: c0017760 REGS: cf81fa60 TRAP: 0300 Not tainted (2.6.29-rc8) MSR: 00009032 CR: 24024042 XER: 20000000 DAR: 00000000, DSISR: 20000000 TASK = cf81cba0[1] 'swapper' THREAD: cf81e000 GPR00: c0151270 cf81fb10 cf81cba0 00000000 c0272e20 c025f354 00001e80 cf86b08c GPR08: d1068200 cffffb74 06000000 d106c200 42024042 10085148 0fffd000 0ffc81a0 GPR16: 00000001 00000001 00000000 007ffeb0 00000000 0000c000 cf83f36c cf83f000 GPR24: 00000030 cf83f360 cf81fb20 00000000 d106c200 20000000 00001e80 cf83f360 NIP [c0151270] ucc_geth_open+0x330/0x1efc LR [c0151270] ucc_geth_open+0x330/0x1efc Call Trace: [cf81fb10] [c0151270] ucc_geth_open+0x330/0x1efc (unreliable) [cf81fba0] [c0187638] dev_open+0xbc/0x12c [cf81fbc0] [c0187e38] dev_change_flags+0x8c/0x1b0 This patch fixes the issue by removing offending (and somewhat duplicate) code from init_phy() routine, and changes _probe() function to use uec_mdio_bus_name(). Also, since we fully construct phy_bus_id in the _probe() routine, we no longer need ->phy_address and ->mdio_bus fields in ucc_geth_info structure. I wish the patch would be a bit shorter, but it seems like the only way to fix the issue in a sane way. Luckily, the patch has been tested with real PHYs and fixed-link, so no further regressions expected. Reported-by: Joakim Tjernlund Signed-off-by: Anton Vorontsov Tested-by: Joakim Tjernlund Signed-off-by: David S. Miller --- drivers/net/ucc_geth.c | 34 ++++++++++------------------------ drivers/net/ucc_geth.h | 3 +-- 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index e87986867ba5..1f61e42c641d 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -1536,32 +1536,15 @@ static void adjust_link(struct net_device *dev) static int init_phy(struct net_device *dev) { struct ucc_geth_private *priv = netdev_priv(dev); - struct device_node *np = priv->node; - struct device_node *phy, *mdio; - const phandle *ph; - char bus_name[MII_BUS_ID_SIZE]; - const unsigned int *id; + struct ucc_geth_info *ug_info = priv->ug_info; struct phy_device *phydev; - char phy_id[BUS_ID_SIZE]; priv->oldlink = 0; priv->oldspeed = 0; priv->oldduplex = -1; - ph = of_get_property(np, "phy-handle", NULL); - phy = of_find_node_by_phandle(*ph); - mdio = of_get_parent(phy); - - id = of_get_property(phy, "reg", NULL); - - of_node_put(phy); - of_node_put(mdio); - - uec_mdio_bus_name(bus_name, mdio); - snprintf(phy_id, sizeof(phy_id), "%s:%02x", - bus_name, *id); - - phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface); + phydev = phy_connect(dev, ug_info->phy_bus_id, &adjust_link, 0, + priv->phy_interface); if (IS_ERR(phydev)) { printk("%s: Could not attach to PHY\n", dev->name); @@ -3629,10 +3612,12 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma ug_info->uf_info.irq = irq_of_parse_and_map(np, 0); fixed_link = of_get_property(np, "fixed-link", NULL); if (fixed_link) { - snprintf(ug_info->mdio_bus, MII_BUS_ID_SIZE, "0"); - ug_info->phy_address = fixed_link[0]; + snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id), + PHY_ID_FMT, "0", fixed_link[0]); phy = NULL; } else { + char bus_name[MII_BUS_ID_SIZE]; + ph = of_get_property(np, "phy-handle", NULL); phy = of_find_node_by_phandle(*ph); @@ -3643,7 +3628,6 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma prop = of_get_property(phy, "reg", NULL); if (prop == NULL) return -1; - ug_info->phy_address = *prop; /* Set the bus id */ mdio = of_get_parent(phy); @@ -3657,7 +3641,9 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma if (err) return -1; - snprintf(ug_info->mdio_bus, MII_BUS_ID_SIZE, "%x", res.start); + uec_mdio_bus_name(bus_name, mdio); + snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id), + "%s:%02x", bus_name, *prop); } /* get the phy interface type, or default to MII */ diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index 16cbe42ba43c..611bdef2402b 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -1091,8 +1091,7 @@ struct ucc_geth_info { u32 eventRegMask; u16 pausePeriod; u16 extensionField; - u8 phy_address; - char mdio_bus[MII_BUS_ID_SIZE]; + char phy_bus_id[BUS_ID_SIZE]; u8 weightfactor[NUM_TX_QUEUES]; u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES]; u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX];