From d49aba84fe775671133295658f43f4d142a517f9 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 8 Jun 2010 07:00:20 +0000 Subject: enic: fix pci_alloc_consistent argument Fix build warning on i386 (32-bit) with 32-bit dma_addr_t: drivers/net/enic/vnic_dev.c: In function 'vnic_dev_init_prov': drivers/net/enic/vnic_dev.c:716: warning: passing argument 3 of 'pci_alloc_consistent' from incompatible pointer type include/asm-generic/pci-dma-compat.h:16: note: expected 'dma_addr_t *' but argument is of type 'u64 *' Now builds without warnings on i386 and on x86_64. Signed-off-by: Randy Dunlap Cc: Scott Feldman Cc: Vasanthy Kolluri Cc: Roopa Prabhu Acked-by: Scott Feldman --- drivers/net/enic/vnic_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index 2b3e16db5c8..e0d33281ec9 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c @@ -709,7 +709,7 @@ int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len) { u64 a0, a1 = len; int wait = 1000; - u64 prov_pa; + dma_addr_t prov_pa; void *prov_buf; int ret; -- cgit v1.2.3-70-g09d2 From d08935c274b7e552e47633cf0cbd74b6e953d228 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Fri, 11 Jun 2010 13:20:29 +0000 Subject: ixgbe: fix for race with 8259(8|9) during shutdown There is a small window where the watchdog could be running as the interface is brought down on a NIC with two ports wired back to back. If ixgbe_update_status is then called can lead to a panic. This patch allows the update to bail if we are in that condition. This issue was orignally reported and fix proposed by Akihiko Saitou. CC: Akihiko Saitou Signed-off-by: Don Skidmore Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index b2af2f67f60..ce30c62a97f 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5282,6 +5282,10 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) u32 i, missed_rx = 0, mpc, bprc, lxon, lxoff, xon_off_tot; u64 non_eop_descs = 0, restart_queue = 0; + if (test_bit(__IXGBE_DOWN, &adapter->state) || + test_bit(__IXGBE_RESETTING, &adapter->state)) + return; + if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) { u64 rsc_count = 0; u64 rsc_flush = 0; -- cgit v1.2.3-70-g09d2 From 7837e58ce39bd727e0a163e7d34e479df36f6d29 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 11 Jun 2010 12:51:49 +0000 Subject: e1000: Fix message logging defect commit 675ad47375c76a7c3be4ace9554d92cd55518ced removed the capability to use ethtool.set_msglevel to control the types of messages emitted by the driver. That commit should probably be reverted. If not, then this patch fixes a message logging defect introduced by converting a printk without KERN_ to e_info. This also reduces text by about 200 bytes. Signed-off-by: Joe Perches Tested-by: Emil Tantilov Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000/e1000_main.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index ebdea089166..68a80893dce 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1047,15 +1047,14 @@ static int __devinit e1000_probe(struct pci_dev *pdev, goto err_register; /* print bus type/speed/width info */ - e_info("(PCI%s:%s:%s) ", - ((hw->bus_type == e1000_bus_type_pcix) ? "-X" : ""), - ((hw->bus_speed == e1000_bus_speed_133) ? "133MHz" : - (hw->bus_speed == e1000_bus_speed_120) ? "120MHz" : - (hw->bus_speed == e1000_bus_speed_100) ? "100MHz" : - (hw->bus_speed == e1000_bus_speed_66) ? "66MHz" : "33MHz"), - ((hw->bus_width == e1000_bus_width_64) ? "64-bit" : "32-bit")); - - e_info("%pM\n", netdev->dev_addr); + e_info("(PCI%s:%dMHz:%d-bit) %pM\n", + ((hw->bus_type == e1000_bus_type_pcix) ? "-X" : ""), + ((hw->bus_speed == e1000_bus_speed_133) ? 133 : + (hw->bus_speed == e1000_bus_speed_120) ? 120 : + (hw->bus_speed == e1000_bus_speed_100) ? 100 : + (hw->bus_speed == e1000_bus_speed_66) ? 66 : 33), + ((hw->bus_width == e1000_bus_width_64) ? 64 : 32), + netdev->dev_addr); /* carrier off reporting is important to ethtool even BEFORE open */ netif_carrier_off(netdev); -- cgit v1.2.3-70-g09d2 From 28c8e4790ca5ef75f54895ca46437f9fbb433ddf Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Fri, 11 Jun 2010 12:47:03 +0000 Subject: ixgbe: fix automatic LRO/RSC settings for low latency This patch added to 2.6.34: commit f8d1dcaf88bddc7f282722ec1fdddbcb06a72f18 Author: Jesse Brandeburg Date: Tue Apr 27 01:37:20 2010 +0000 ixgbe: enable extremely low latency introduced a feature where LRO (called RSC on the hardware) was disabled automatically when setting rx-usecs to 0 via ethtool. Some might not like the fact that LRO was disabled automatically, but I'm fine with that. What I don't like is that LRO/RSC is automatically enabled when rx-usecs is set >0 via ethtool. This would certainly be a problem if the device was used for forwarding and it was determined that the low latency wasn't needed after the device was already forwarding. I played around with saving the state of LRO in the driver, but it just didn't seem worthwhile and would require a small change to dev_disable_lro() that I did not like. This patch simply leaves LRO disabled when setting rx-usecs >0 and requires that the user enable it again. An extra informational message will also now appear in the log so users can understand why LRO isn't being enabled as they expect. Inconsistency of LRO setting first noticed by Stanislaw Gruszka. Signed-off-by: Andy Gospodarek CC: Stanislaw Gruszka CC: stable@kernel.org Tested-by: Stephen Ko Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_ethtool.c | 37 ++++++++----------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index c50a7541ffe..3a93a81872b 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -2077,25 +2077,6 @@ static int ixgbe_get_coalesce(struct net_device *netdev, return 0; } -/* - * this function must be called before setting the new value of - * rx_itr_setting - */ -static bool ixgbe_reenable_rsc(struct ixgbe_adapter *adapter, - struct ethtool_coalesce *ec) -{ - /* check the old value and enable RSC if necessary */ - if ((adapter->rx_itr_setting == 0) && - (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE)) { - adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED; - adapter->netdev->features |= NETIF_F_LRO; - DPRINTK(PROBE, INFO, "rx-usecs set to %d, re-enabling RSC\n", - ec->rx_coalesce_usecs); - return true; - } - return false; -} - static int ixgbe_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec) { @@ -2124,9 +2105,6 @@ static int ixgbe_set_coalesce(struct net_device *netdev, (1000000/ec->rx_coalesce_usecs < IXGBE_MIN_INT_RATE)) return -EINVAL; - /* check the old value and enable RSC if necessary */ - need_reset = ixgbe_reenable_rsc(adapter, ec); - /* store the value in ints/second */ adapter->rx_eitr_param = 1000000/ec->rx_coalesce_usecs; @@ -2135,9 +2113,6 @@ static int ixgbe_set_coalesce(struct net_device *netdev, /* clear the lower bit as its used for dynamic state */ adapter->rx_itr_setting &= ~1; } else if (ec->rx_coalesce_usecs == 1) { - /* check the old value and enable RSC if necessary */ - need_reset = ixgbe_reenable_rsc(adapter, ec); - /* 1 means dynamic mode */ adapter->rx_eitr_param = 20000; adapter->rx_itr_setting = 1; @@ -2157,10 +2132,11 @@ static int ixgbe_set_coalesce(struct net_device *netdev, */ if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) { adapter->flags2 &= ~IXGBE_FLAG2_RSC_ENABLED; - netdev->features &= ~NETIF_F_LRO; - DPRINTK(PROBE, INFO, - "rx-usecs set to 0, disabling RSC\n"); - + if (netdev->features & NETIF_F_LRO) { + netdev->features &= ~NETIF_F_LRO; + DPRINTK(PROBE, INFO, "rx-usecs set to 0, " + "disabling LRO/RSC\n"); + } need_reset = true; } } @@ -2255,6 +2231,9 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data) } } else if (!adapter->rx_itr_setting) { netdev->features &= ~ETH_FLAG_LRO; + if (data & ETH_FLAG_LRO) + DPRINTK(PROBE, INFO, "rx-usecs set to 0, " + "LRO/RSC cannot be enabled.\n"); } } -- cgit v1.2.3-70-g09d2 From da5ae1cfff4cc5b9392eab59b227ad907626d7aa Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 28 May 2010 09:28:39 -0700 Subject: iwlwifi: serialize station management actions We are seeing some race conditions between incoming station management requests (station add/remove) and the internal unassoc RXON command that modifies station table. Modify these flows to require the mutex to be held and thus serializing them. This fixes http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=2207 Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 ++++++-- drivers/net/wireless/iwlwifi/iwl-sta.c | 4 ++++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 9 +++++++-- 3 files changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 7726e67044c..24aff654fa9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3391,10 +3391,12 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, int ret; u8 sta_id; - sta_priv->common.sta_id = IWL_INVALID_STATION; - IWL_DEBUG_INFO(priv, "received request to add station %pM\n", sta->addr); + mutex_lock(&priv->mutex); + IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n", + sta->addr); + sta_priv->common.sta_id = IWL_INVALID_STATION; atomic_set(&sta_priv->pending_frames, 0); if (vif->type == NL80211_IFTYPE_AP) @@ -3406,6 +3408,7 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, IWL_ERR(priv, "Unable to add station %pM (%d)\n", sta->addr, ret); /* Should we return success if return code is EEXIST ? */ + mutex_unlock(&priv->mutex); return ret; } @@ -3415,6 +3418,7 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n", sta->addr); iwl_rs_rate_init(priv, sta, sta_id); + mutex_unlock(&priv->mutex); return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 83a26361a9b..c27c13fbb1a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1373,10 +1373,14 @@ int iwl_mac_sta_remove(struct ieee80211_hw *hw, IWL_DEBUG_INFO(priv, "received request to remove station %pM\n", sta->addr); + mutex_lock(&priv->mutex); + IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n", + sta->addr); ret = iwl_remove_station(priv, sta_common->sta_id, sta->addr); if (ret) IWL_ERR(priv, "Error removing station %pM\n", sta->addr); + mutex_unlock(&priv->mutex); return ret; } EXPORT_SYMBOL(iwl_mac_sta_remove); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 6c353cacc8d..a27872de410 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3437,10 +3437,13 @@ static int iwl3945_mac_sta_add(struct ieee80211_hw *hw, bool is_ap = vif->type == NL80211_IFTYPE_STATION; u8 sta_id; - sta_priv->common.sta_id = IWL_INVALID_STATION; - IWL_DEBUG_INFO(priv, "received request to add station %pM\n", sta->addr); + mutex_lock(&priv->mutex); + IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n", + sta->addr); + sta_priv->common.sta_id = IWL_INVALID_STATION; + ret = iwl_add_station_common(priv, sta->addr, is_ap, &sta->ht_cap, &sta_id); @@ -3448,6 +3451,7 @@ static int iwl3945_mac_sta_add(struct ieee80211_hw *hw, IWL_ERR(priv, "Unable to add station %pM (%d)\n", sta->addr, ret); /* Should we return success if return code is EEXIST ? */ + mutex_unlock(&priv->mutex); return ret; } @@ -3457,6 +3461,7 @@ static int iwl3945_mac_sta_add(struct ieee80211_hw *hw, IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n", sta->addr); iwl3945_rs_rate_init(priv, sta, sta_id); + mutex_unlock(&priv->mutex); return 0; } -- cgit v1.2.3-70-g09d2 From b561e8274f75831ee87e4ea378cbb1f9f050a51a Mon Sep 17 00:00:00 2001 From: Shanyu Zhao Date: Tue, 1 Jun 2010 17:13:58 -0700 Subject: iwlagn: verify flow id in compressed BA packet The flow id (scd_flow) in a compressed BA packet should match the txq_id of the queue from which the aggregated packets were sent. However, in some hardware like the 1000 series, sometimes the flow id is 0 for the txq_id (10 to 19). This can cause the annoying message: [ 2213.306191] iwlagn 0000:01:00.0: Received BA when not expected [ 2213.310178] iwlagn 0000:01:00.0: Read index for DMA queue txq id (0), index 5, is out of range [0-256] 7 7. And even worse, if agg->wait_for_ba is true when the bad BA is arriving, this can cause system hang due to NULL pointer dereference because the code is operating in a wrong tx queue! Signed-off-by: Shanyu Zhao Signed-off-by: Pradeep Kulkarni Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index a732f1094e5..7d614c4d3c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -1299,6 +1299,11 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, sta_id = ba_resp->sta_id; tid = ba_resp->tid; agg = &priv->stations[sta_id].tid[tid].agg; + if (unlikely(agg->txq_id != scd_flow)) { + IWL_ERR(priv, "BA scd_flow %d does not match txq_id %d\n", + scd_flow, agg->txq_id); + return; + } /* Find index just before block-ack window */ index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); -- cgit v1.2.3-70-g09d2 From 13deb23a52c13053fc509f119eb80b903c65a879 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Thu, 10 Jun 2010 08:08:42 -0400 Subject: libertas_tf: Fix warning in lbtf_rx for stats struct Fixes linux-2.6 warning: drivers/net/wireless/libertas_tf/main.c: In function 'lbtf_rx': drivers/net/wireless/libertas_tf/main.c:578: warning: 'stats.antenna' is used uninitialized in this function drivers/net/wireless/libertas_tf/main.c:578: warning: 'stats.mactime' is used uninitialized in this function stats struct needs to be set to 0 before use. Signed-off-by: Prarit Bhargava Signed-off-by: John W. Linville --- drivers/net/wireless/libertas_tf/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index 6a04c2157f7..817fffc0de4 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -549,7 +549,7 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb) prxpd = (struct rxpd *) skb->data; - stats.flag = 0; + memset(&stats, 0, sizeof(stats)); if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) stats.flag |= RX_FLAG_FAILED_FCS_CRC; stats.freq = priv->cur_freq; -- cgit v1.2.3-70-g09d2 From 50900f1698f68127e54c67fdfe829e4a97b1be2b Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Sun, 13 Jun 2010 14:22:23 +0200 Subject: p54pci: add Symbol AP-300 minipci adapters pciid Cc: stable@kernel.org Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54pci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 07c4528f6e6..a5ea89cde8c 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -41,6 +41,8 @@ static DEFINE_PCI_DEVICE_TABLE(p54p_table) = { { PCI_DEVICE(0x1260, 0x3877) }, /* Intersil PRISM Javelin/Xbow Wireless LAN adapter */ { PCI_DEVICE(0x1260, 0x3886) }, + /* Intersil PRISM Xbow Wireless LAN adapter (Symbol AP-300) */ + { PCI_DEVICE(0x1260, 0xffff) }, { }, }; -- cgit v1.2.3-70-g09d2 From a69b03e941abae00380fc6bc1877fb797a1b31e6 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 14 Jun 2010 14:30:25 -0400 Subject: iwlwifi: cancel scan watchdog in iwl_bg_abort_scan Avoids this: WARNING: at net/mac80211/scan.c:312 ieee80211_scan_completed+0x5f/0x1f1 [mac80211]() Hardware name: Latitude E5400 Modules linked in: aes_x86_64 aes_generic fuse ipt_MASQUERADE iptable_nat nf_nat rfcomm sco bridge stp llc bnep l2cap sunrpc cpufreq_ondemand acpi_cpufreq freq_table xt_physdev ip6t_REJECT nf_conntrack_ipv6 ip6table_filter ip6_tables ipv6 kvm_intel kvm uinput arc4 ecb snd_hda_codec_intelhdmi snd_hda_codec_idt snd_hda_intel iwlagn snd_hda_codec snd_hwdep snd_seq snd_seq_device iwlcore snd_pcm dell_wmi sdhci_pci sdhci iTCO_wdt tg3 dell_laptop mmc_core i2c_i801 wmi mac80211 snd_timer iTCO_vendor_support btusb joydev dcdbas cfg80211 bluetooth snd soundcore microcode rfkill snd_page_alloc firewire_ohci firewire_core crc_itu_t yenta_socket rsrc_nonstatic i915 drm_kms_helper drm i2c_algo_bit i2c_core video output [last unloaded: scsi_wait_scan] Pid: 979, comm: iwlagn Tainted: G W 2.6.33.3-85.fc13.x86_64 #1 Call Trace: [] warn_slowpath_common+0x77/0x8f [] warn_slowpath_null+0xf/0x11 [] ieee80211_scan_completed+0x5f/0x1f1 [mac80211] [] iwl_bg_scan_completed+0xbb/0x17a [iwlcore] [] worker_thread+0x1a4/0x232 [] ? iwl_bg_scan_completed+0x0/0x17a [iwlcore] [] ? autoremove_wake_function+0x0/0x34 [] ? worker_thread+0x0/0x232 [] kthread+0x7a/0x82 [] kernel_thread_helper+0x4/0x10 [] ? kthread+0x0/0x82 [] ? kernel_thread_helper+0x0/0x10 Reported here: https://bugzilla.redhat.com/show_bug.cgi?id=590436 Signed-off-by: John W. Linville Reported-by: Mihai Harpau Cc: stable@kernel.org Acked-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-scan.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 5d3f51ff2f0..386c5f96eff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -491,6 +491,7 @@ void iwl_bg_abort_scan(struct work_struct *work) mutex_lock(&priv->mutex); + cancel_delayed_work_sync(&priv->scan_check); set_bit(STATUS_SCAN_ABORTING, &priv->status); iwl_send_scan_abort(priv); -- cgit v1.2.3-70-g09d2 From d6a574ff6bfb842bdb98065da053881ff527be46 Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Tue, 8 Jun 2010 11:33:02 -0600 Subject: hostap: Protect against initialization interrupt Use an irq spinlock to hold off the IRQ handler until enough early card init is complete such that the handler can run without faulting. Signed-off-by: Tim Gardner Cc: stable@kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_cs.c | 15 +++++++++++++-- drivers/net/wireless/hostap/hostap_hw.c | 13 +++++++++++++ drivers/net/wireless/hostap/hostap_wlan.h | 2 +- 3 files changed, 27 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index db72461c486..29b31a694b5 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -594,6 +594,7 @@ static int prism2_config(struct pcmcia_device *link) local_info_t *local; int ret = 1; struct hostap_cs_priv *hw_priv; + unsigned long flags; PDEBUG(DEBUG_FLOW, "prism2_config()\n"); @@ -625,9 +626,15 @@ static int prism2_config(struct pcmcia_device *link) local->hw_priv = hw_priv; hw_priv->link = link; + /* + * Make sure the IRQ handler cannot proceed until at least + * dev->base_addr is initialized. + */ + spin_lock_irqsave(&local->irq_init_lock, flags); + ret = pcmcia_request_irq(link, prism2_interrupt); if (ret) - goto failed; + goto failed_unlock; /* * This actually configures the PCMCIA socket -- setting up @@ -636,11 +643,13 @@ static int prism2_config(struct pcmcia_device *link) */ ret = pcmcia_request_configuration(link, &link->conf); if (ret) - goto failed; + goto failed_unlock; dev->irq = link->irq; dev->base_addr = link->io.BasePort1; + spin_unlock_irqrestore(&local->irq_init_lock, flags); + /* Finally, report what we've done */ printk(KERN_INFO "%s: index 0x%02x: ", dev_info, link->conf.ConfigIndex); @@ -667,6 +676,8 @@ static int prism2_config(struct pcmcia_device *link) return ret; + failed_unlock: + spin_unlock_irqrestore(&local->irq_init_lock, flags); failed: kfree(hw_priv); prism2_release((u_long)link); diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index ff9b5c88218..2f999fc94f6 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -2621,6 +2621,18 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id) iface = netdev_priv(dev); local = iface->local; + /* Detect early interrupt before driver is fully configued */ + spin_lock(&local->irq_init_lock); + if (!dev->base_addr) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n", + dev->name); + } + spin_unlock(&local->irq_init_lock); + return IRQ_HANDLED; + } + spin_unlock(&local->irq_init_lock); + prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0); if (local->func->card_present && !local->func->card_present(local)) { @@ -3138,6 +3150,7 @@ prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx, spin_lock_init(&local->cmdlock); spin_lock_init(&local->baplock); spin_lock_init(&local->lock); + spin_lock_init(&local->irq_init_lock); mutex_init(&local->rid_bap_mtx); if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES) diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index 3d238917af0..1ba33be98b2 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -654,7 +654,7 @@ struct local_info { rwlock_t iface_lock; /* hostap_interfaces read lock; use write lock * when removing entries from the list. * TX and RX paths can use read lock. */ - spinlock_t cmdlock, baplock, lock; + spinlock_t cmdlock, baplock, lock, irq_init_lock; struct mutex rid_bap_mtx; u16 infofid; /* MAC buffer id for info frame */ /* txfid, intransmitfid, next_txtid, and next_alloc are protected by -- cgit v1.2.3-70-g09d2 From 44b496f685ca68c0d96eb3ad88e3948fad3417d6 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Fri, 11 Jun 2010 04:44:55 +0000 Subject: pcmcia: dev_node removal bugfix Patch c7c2fa07 removed one line too much from smc91c92_cs.c. Reported-by: Komuro CC: netdev@vger.kernel.org CC: linux-wireless@vger.kernel.org Signed-off-by: Dominik Brodowski Signed-off-by: David S. Miller --- drivers/net/pcmcia/smc91c92_cs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 7b6fe89f9db..64e6a84bbbb 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -322,6 +322,7 @@ static int smc91c92_probe(struct pcmcia_device *link) return -ENOMEM; smc = netdev_priv(dev); smc->p_dev = link; + link->priv = dev; spin_lock_init(&smc->lock); link->io.NumPorts1 = 16; -- cgit v1.2.3-70-g09d2 From bf445080dad9542c6bc6b693d941cae89605134c Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Sun, 13 Jun 2010 23:39:03 +0000 Subject: netxen: fix memory leaks in error path Fixes memory leak in error path when memory allocation for adapter data structures fails. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_ctx.c | 3 ++- drivers/net/netxen/netxen_nic_init.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index f26e54716c8..3a41b6a84a6 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -629,7 +629,8 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) if (addr == NULL) { dev_err(&pdev->dev, "%s: failed to allocate tx desc ring\n", netdev->name); - return -ENOMEM; + err = -ENOMEM; + goto err_out_free; } tx_ring->desc_head = (struct cmd_desc_type0 *)addr; diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 045a7c8f5bd..e08527f4b30 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -218,7 +218,7 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter) if (cmd_buf_arr == NULL) { dev_err(&pdev->dev, "%s: failed to allocate cmd buffer ring\n", netdev->name); - return -ENOMEM; + goto err_out; } memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring)); tx_ring->cmd_buf_arr = cmd_buf_arr; @@ -230,7 +230,7 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter) if (rds_ring == NULL) { dev_err(&pdev->dev, "%s: failed to allocate rds ring struct\n", netdev->name); - return -ENOMEM; + goto err_out; } recv_ctx->rds_rings = rds_ring; -- cgit v1.2.3-70-g09d2 From 2227bae22becb88b75ede022c7bb991aabfb50bb Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Sun, 13 Jun 2010 23:39:04 +0000 Subject: netxen: fix rcv buffer leak Rcv producer should be read in spin-lock. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_init.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index e08527f4b30..c865dda2adf 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1805,9 +1805,10 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid, netxen_ctx_msg msg = 0; struct list_head *head; + spin_lock(&rds_ring->lock); + producer = rds_ring->producer; - spin_lock(&rds_ring->lock); head = &rds_ring->free_list; while (!list_empty(head)) { @@ -1829,7 +1830,6 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid, producer = get_next_index(producer, rds_ring->num_desc); } - spin_unlock(&rds_ring->lock); if (count) { rds_ring->producer = producer; @@ -1853,6 +1853,8 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid, NETXEN_RCV_PRODUCER_OFFSET), msg); } } + + spin_unlock(&rds_ring->lock); } static void @@ -1864,10 +1866,11 @@ netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, int producer, count = 0; struct list_head *head; - producer = rds_ring->producer; if (!spin_trylock(&rds_ring->lock)) return; + producer = rds_ring->producer; + head = &rds_ring->free_list; while (!list_empty(head)) { -- cgit v1.2.3-70-g09d2 From 7e43cd66d36e8f0900e87d9d287c9ee649cbdd07 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Sun, 13 Jun 2010 23:39:05 +0000 Subject: netxen: fix caching window register CRB window register is not per pci-func for NX3031, so caching can result in incorrect values. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_hw.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 5c496f8d7c4..29d7b93d049 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -1159,9 +1159,6 @@ netxen_nic_pci_set_crbwindow_2M(struct netxen_adapter *adapter, ulong off) window = CRB_HI(off); - if (adapter->ahw.crb_win == window) - return; - writel(window, addr); if (readl(addr) != window) { if (printk_ratelimit()) @@ -1169,7 +1166,6 @@ netxen_nic_pci_set_crbwindow_2M(struct netxen_adapter *adapter, ulong off) "failed to set CRB window to %d off 0x%lx\n", window, off); } - adapter->ahw.crb_win = window; } static void __iomem * -- cgit v1.2.3-70-g09d2 From 97553f7f3e7a0305d017df9cc6e9589f64878437 Mon Sep 17 00:00:00 2001 From: Manfred Rudigier Date: Fri, 11 Jun 2010 01:49:05 +0000 Subject: gianfar: Fix setup of RX time stamping Previously the RCTRL_TS_ENABLE bit was set unconditionally. However, if the RCTRL_TS_ENABLE is set without TMR_CTRL[TE], the driver does not work properly on some boards (Anton had problems with the MPC8313ERDB and MPC8568EMDS). With this patch the bit will only be set if requested from user space with the SIOCSHWTSTAMP ioctl command, meaning that time stamping is disabled during normal operation. Users who are not interested in time stamps will not experience problems with buggy CPU revisions or performance drops any more. The setting of TMR_CTRL[TE] is still up to the user. This is considered safe because users wanting HW timestamps must initialize the eTSEC clock first anyway, e.g. with the recently submitted PTP clock driver. Signed-off-by: Manfred Rudigier Reviewed-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 46c69cd0655..227b628bc21 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -381,10 +381,14 @@ static void gfar_init_mac(struct net_device *ndev) /* Insert receive time stamps into padding alignment bytes */ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) { rctrl &= ~RCTRL_PAL_MASK; - rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE | RCTRL_PADDING(8); + rctrl |= RCTRL_PADDING(8); priv->padding = 8; } + /* Enable HW time stamping if requested from user space */ + if (priv->hwts_rx_en) + rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE; + /* keep vlan related bits if it's enabled */ if (priv->vlgrp) { rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT; @@ -747,7 +751,8 @@ static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev) FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN | FSL_GIANFAR_DEV_HAS_MAGIC_PACKET | - FSL_GIANFAR_DEV_HAS_EXTENDED_HASH; + FSL_GIANFAR_DEV_HAS_EXTENDED_HASH | + FSL_GIANFAR_DEV_HAS_TIMER; ctype = of_get_property(np, "phy-connection-type", NULL); @@ -805,12 +810,20 @@ static int gfar_hwtstamp_ioctl(struct net_device *netdev, switch (config.rx_filter) { case HWTSTAMP_FILTER_NONE: - priv->hwts_rx_en = 0; + if (priv->hwts_rx_en) { + stop_gfar(netdev); + priv->hwts_rx_en = 0; + startup_gfar(netdev); + } break; default: if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)) return -ERANGE; - priv->hwts_rx_en = 1; + if (!priv->hwts_rx_en) { + stop_gfar(netdev); + priv->hwts_rx_en = 1; + startup_gfar(netdev); + } config.rx_filter = HWTSTAMP_FILTER_ALL; break; } -- cgit v1.2.3-70-g09d2 From 756725064fe6abbcdb43b1e64d017649b828be35 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Tue, 15 Jun 2010 09:23:17 +0000 Subject: ixgbe: add comment on SFP+ ID for Active DA These comments were forgotten in the initial patch to add this functionality. This patch corrects that. Signed-off-by: Don Skidmore Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_phy.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index 09e1911ff51..48325a5beff 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -575,6 +575,8 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) * 4 SFP_DA_CORE1 - 82599-specific * 5 SFP_SR/LR_CORE0 - 82599-specific * 6 SFP_SR/LR_CORE1 - 82599-specific + * 7 SFP_act_lmt_DA_CORE0 - 82599-specific + * 8 SFP_act_lmt_DA_CORE1 - 82599-specific */ if (hw->mac.type == ixgbe_mac_82598EB) { if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) -- cgit v1.2.3-70-g09d2 From a91fb143de61dce847e319ca79b9937a665ad622 Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Tue, 15 Jun 2010 05:35:16 +0000 Subject: ehea: fix delayed packet processing In the eHEA poll function an rmb() is required. Without that some packets on the receive queue are not seen and thus delayed until the next interrupt is handled for the same receive queue. Signed-off-by: Jan-Bernd Themann Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/ehea/ehea_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index f547894ff48..fd890faf517 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -867,6 +867,7 @@ static int ehea_poll(struct napi_struct *napi, int budget) ehea_reset_cq_ep(pr->send_cq); ehea_reset_cq_n1(pr->recv_cq); ehea_reset_cq_n1(pr->send_cq); + rmb(); cqe = ehea_poll_rq1(pr->qp, &wqe_index); cqe_skb = ehea_poll_cq(pr->send_cq); -- cgit v1.2.3-70-g09d2 From 099473c16bac7b936994bc95b5fd96f36397e1ad Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Tue, 15 Jun 2010 05:35:42 +0000 Subject: ehea: Fix kernel deadlock in DLPAR-mem processing Port reset operations and memory add/remove operations need to be serialized to avoid a kernel deadlock. The deadlock is caused by calling the napi_disable() function twice. Therefore we have to employ the dlpar_mem_lock in the ehea_reset_port function as well Signed-off-by: Jan-Bernd Themann Signed-off-by: David S. Miller --- drivers/net/ehea/ehea.h | 2 +- drivers/net/ehea/ehea_main.c | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 0630980a272..0060e422f17 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -40,7 +40,7 @@ #include #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0103" +#define DRV_VERSION "EHEA_0105" /* eHEA capability flags */ #define DLPAR_PORT_ADD_REM 1 diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index fd890faf517..8b92acb448c 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -2860,6 +2860,7 @@ static void ehea_reset_port(struct work_struct *work) container_of(work, struct ehea_port, reset_task); struct net_device *dev = port->netdev; + mutex_lock(&dlpar_mem_lock); port->resets++; mutex_lock(&port->port_lock); netif_stop_queue(dev); @@ -2882,6 +2883,7 @@ static void ehea_reset_port(struct work_struct *work) netif_wake_queue(dev); out: mutex_unlock(&port->port_lock); + mutex_unlock(&dlpar_mem_lock); } static void ehea_rereg_mrs(struct work_struct *work) @@ -3543,10 +3545,7 @@ static int ehea_mem_notifier(struct notifier_block *nb, int ret = NOTIFY_BAD; struct memory_notify *arg = data; - if (!mutex_trylock(&dlpar_mem_lock)) { - ehea_info("ehea_mem_notifier must not be called parallelized"); - goto out; - } + mutex_lock(&dlpar_mem_lock); switch (action) { case MEM_CANCEL_OFFLINE: @@ -3575,7 +3574,6 @@ static int ehea_mem_notifier(struct notifier_block *nb, out_unlock: mutex_unlock(&dlpar_mem_lock); -out: return ret; } -- cgit v1.2.3-70-g09d2 From 63b88b9041ceef8217f34de71a2e96f0c3f0fd3b Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 11 Jun 2010 10:51:03 +0000 Subject: gianfar: Fix oversized packets handling Issuing the following command on host: $ ifconfig eth2 mtu 1600 ; ping 10.0.0.27 -s 1485 -c 1 Makes some boards (tested with MPC8315 rev 1.1 and MPC8313 rev 1.0) oops like this: skb_over_panic: text:c0195914 len:1537 put:1537 head:c79e4800 data:c79e4880 tail:0xc79e4e81 end:0xc79e4e80 dev:eth1 ------------[ cut here ]------------ kernel BUG at net/core/skbuff.c:127! Oops: Exception in kernel mode, sig: 5 [#1] MPC831x RDB last sysfs file: /sys/kernel/uevent_seqnum Modules linked in: NIP: c01c1840 LR: c01c1840 CTR: c016d918 [...] NIP [c01c1840] skb_over_panic+0x48/0x5c LR [c01c1840] skb_over_panic+0x48/0x5c Call Trace: [c0339d50] [c01c1840] skb_over_panic+0x48/0x5c (unreliable) [c0339d60] [c01c3020] skb_put+0x5c/0x60 [c0339d70] [c0195914] gfar_clean_rx_ring+0x25c/0x3d0 [c0339dc0] [c01976e8] gfar_poll+0x170/0x1bc Dumped buffer descriptors showed that eTSEC's length/truncation logic sometimes passes oversized packets, i.e. for the above ICMP packet the following two buffer descriptors may become ready: status=1400 length=1536 status=1800 length=1541 So, it seems that gianfar actually receives the whole big frame, and it tries to place the packet into two BDs. This situation confuses the driver, and so the skb_put() sanity check fails. This patch fixes the issue by adding an appropriate check, i.e. the driver should not try to process frames with buffer descriptor's length over rx_buffer_size (i.e. maxfrm and mrblr). Note that sometimes eTSEC works correctly, i.e. in the second (last) buffer descriptor bits 'truncated' and 'crcerr' are set, and so there's no oops. Though I couldn't find any logic when it works correctly and when not. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 227b628bc21..28b53d1cd4f 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -2655,6 +2655,10 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) dma_unmap_single(&priv->ofdev->dev, bdp->bufPtr, priv->rx_buffer_size, DMA_FROM_DEVICE); + if (unlikely(!(bdp->status & RXBD_ERR) && + bdp->length > priv->rx_buffer_size)) + bdp->status = RXBD_LARGE; + /* We drop the frame if we failed to allocate a new buffer */ if (unlikely(!newskb || !(bdp->status & RXBD_LAST) || bdp->status & RXBD_ERR)) { -- cgit v1.2.3-70-g09d2 From 8b1d920fa5ea8e3d941e908fa57acc9b1df9ca92 Mon Sep 17 00:00:00 2001 From: Ken Kawasaki Date: Sat, 12 Jun 2010 00:17:28 +0000 Subject: pcnet_cs: add new id (TOSHIBA Modem/LAN Card) pcnet_cs: serial_cs: add new id (TOSHIBA Modem/LAN Card) Signed-off-by: Ken Kawasaki Signed-off-by: David S. Miller --- drivers/net/pcmcia/pcnet_cs.c | 1 + drivers/serial/serial_cs.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 6f77a768ba8..bfdef72c5d5 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1727,6 +1727,7 @@ static struct pcmcia_device_id pcnet_ids[] = { PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "cis/PCMLM28.cis"), PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "cis/PCMLM28.cis"), PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "cis/PCMLM28.cis"), + PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "TOSHIBA", "Modem/LAN Card", 0xb4585a1a, 0x53f922f8, "cis/PCMLM28.cis"), PCMCIA_MFC_DEVICE_CIS_PROD_ID12(0, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "cis/DP83903.cis"), PCMCIA_MFC_DEVICE_CIS_PROD_ID4(0, "NSC MF LAN/Modem", 0x58fc6056, "cis/DP83903.cis"), PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0175, 0x0000, "cis/DP83903.cis"), diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index dadd686c980..8bb715a1a7a 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -807,6 +807,7 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "cis/PCMLM28.cis"), PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "cis/PCMLM28.cis"), PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "cis/PCMLM28.cis"), + PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "TOSHIBA", "Modem/LAN Card", 0xb4585a1a, 0x53f922f8, "cis/PCMLM28.cis"), PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "cis/DP83903.cis"), PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "cis/DP83903.cis"), PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "cis/3CCFEM556.cis"), -- cgit v1.2.3-70-g09d2 From db176edc89abbf22e6db6853f8581f9475fe8ec1 Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Mon, 14 Jun 2010 06:35:20 +0000 Subject: ucc_geth: fix for RX skb buffers recycling This patch implements a proper modification of RX skb buffers before recycling. Adjusting only skb->data is not enough because after that skb->tail and skb->len become incorrect. Signed-off-by: Sergey Matyukevich Signed-off-by: David S. Miller --- drivers/net/ucc_geth.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 4a34833b85d..807470e156a 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3215,6 +3215,8 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit __func__, __LINE__, (u32) skb); if (skb) { skb->data = skb->head + NET_SKB_PAD; + skb->len = 0; + skb_reset_tail_pointer(skb); __skb_queue_head(&ugeth->rx_recycle, skb); } -- cgit v1.2.3-70-g09d2 From aabef8b240880439b91574c9a9e33dcc44bfd8c7 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 17 Jun 2010 08:56:05 -0700 Subject: bnx2: fix dma_get_ops compilation breakage This removes dma_get_ops() prefetch optimization in bnx2. bnx2 uses dma_get_ops() to see if dma_sync_single_for_cpu() is noop. bnx2 does prefetch if it's noop. But dma_get_ops() isn't available on all the architectures (only the architectures that uses dma_map_ops struct have it). Using dma_get_ops() in drivers leads to compilation breakage on many architectures. This patch removes dma_get_ops() and changes bnx2 to do prefetch on all the architectures. This adds useless prefetch on non-coherent architectures but this is harmless. It is also unlikely to cause the performance drop. [ Remove now unused local variable 'pdev' -DaveM ] Signed-off-by: FUJITA Tomonori Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 949d7a9dcf9..117432222a0 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -3073,7 +3073,6 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod; struct l2_fhdr *rx_hdr; int rx_pkt = 0, pg_ring_used = 0; - struct pci_dev *pdev = bp->pdev; hw_cons = bnx2_get_hw_rx_cons(bnapi); sw_cons = rxr->rx_cons; @@ -3099,12 +3098,10 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) skb = rx_buf->skb; prefetchw(skb); - if (!get_dma_ops(&pdev->dev)->sync_single_for_cpu) { - next_rx_buf = - &rxr->rx_buf_ring[ - RX_RING_IDX(NEXT_RX_BD(sw_cons))]; - prefetch(next_rx_buf->desc); - } + next_rx_buf = + &rxr->rx_buf_ring[RX_RING_IDX(NEXT_RX_BD(sw_cons))]; + prefetch(next_rx_buf->desc); + rx_buf->skb = NULL; dma_addr = dma_unmap_addr(rx_buf, mapping); -- cgit v1.2.3-70-g09d2 From b6855772f4a22c4fbdd4fcaceff5c8a527035123 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 18 Jun 2010 13:15:23 -0400 Subject: ath5k: initialize ah->ah_current_channel ath5k assumes ah_current_channel is always a valid pointer in several places, but a newly created interface may not have a channel. To avoid null pointer dereferences, set it up to point to the first available channel until later reconfigured. This fixes the following oops: $ rmmod ath5k $ insmod ath5k $ iw phy0 set distance 11000 BUG: unable to handle kernel NULL pointer dereference at 00000006 IP: [] ath5k_hw_set_coverage_class+0x74/0x1b0 [ath5k] *pde = 00000000 Oops: 0000 [#1] last sysfs file: /sys/devices/pci0000:00/0000:00:0e.0/ieee80211/phy0/index Modules linked in: usbhid option usb_storage usbserial usblp evdev lm90 scx200_acb i2c_algo_bit i2c_dev i2c_core via_rhine ohci_hcd ne2k_pci 8390 leds_alix2 xt_IMQ imq nf_nat_tftp nf_conntrack_tftp nf_nat_irc nf_cc Pid: 1597, comm: iw Not tainted (2.6.32.14 #8) EIP: 0060:[] EFLAGS: 00010296 CPU: 0 EIP is at ath5k_hw_set_coverage_class+0x74/0x1b0 [ath5k] EAX: 000000c2 EBX: 00000000 ECX: ffffffff EDX: c12d2080 ESI: 00000019 EDI: cf8c0000 EBP: d0a30edc ESP: cfa09bf4 DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068 Process iw (pid: 1597, ti=cfa09000 task=cf88a000 task.ti=cfa09000) Stack: d0a34f35 d0a353f8 d0a30edc 000000fe cf8c0000 00000000 1900063d cfa8c9e0 <0> cfa8c9e8 cfa8c0c0 cfa8c000 d0a27f0c 199d84b4 cfa8c200 00000010 d09bfdc7 <0> 00000000 00000000 ffffffff d08e0d28 cf9263c0 00000001 cfa09cc4 00000000 Call Trace: [] ? ath5k_hw_attach+0xc8c/0x3c10 [ath5k] [] ? __ieee80211_request_smps+0x1347/0x1580 [mac80211] [] ? nl80211_send_scan_start+0x7b8/0x4520 [cfg80211] [] ? nla_parse+0x59/0xc0 [] ? genl_rcv_msg+0x169/0x1a0 [] ? genl_rcv_msg+0x0/0x1a0 [] ? netlink_rcv_skb+0x38/0x90 [] ? genl_rcv+0x19/0x30 [] ? netlink_unicast+0x1b3/0x220 [] ? netlink_sendmsg+0x26e/0x290 [] ? sock_sendmsg+0xbe/0xf0 [] ? autoremove_wake_function+0x0/0x50 [] ? __alloc_pages_nodemask+0x106/0x530 [] ? do_lookup+0x53/0x1b0 [] ? __link_path_walk+0x9b9/0x9e0 [] ? verify_iovec+0x50/0x90 [] ? sys_sendmsg+0x1e1/0x270 [] ? find_get_page+0x10/0x50 [] ? filemap_fault+0x5f/0x370 [] ? __do_fault+0x319/0x370 [] ? sys_socketcall+0x244/0x290 [] ? do_page_fault+0x1ec/0x270 [] ? do_page_fault+0x0/0x270 [] ? syscall_call+0x7/0xb Code: 00 b8 fe 00 00 00 b9 f8 53 a3 d0 89 5c 24 14 89 7c 24 10 89 44 24 0c 89 6c 24 08 89 4c 24 04 c7 04 24 35 4f a3 d0 e8 7c 30 60 f0 <0f> b7 43 06 ba 06 00 00 00 a8 10 75 0e 83 e0 20 83 f8 01 19 d2 EIP: [] ath5k_hw_set_coverage_class+0x74/0x1b0 [ath5k] SS:ESP 0068:cfa09bf4 CR2: 0000000000000006 ---[ end trace 54f73d6b10ceb87b ]--- Cc: stable@kernel.org Reported-by: Steve Brown Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/attach.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index e0c244b02f0..31c008042bf 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -126,6 +126,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) ah->ah_ant_mode = AR5K_ANTMODE_DEFAULT; ah->ah_noise_floor = -95; /* until first NF calibration is run */ sc->ani_state.ani_mode = ATH5K_ANI_MODE_AUTO; + ah->ah_current_channel = &sc->channels[0]; /* * Find the mac version -- cgit v1.2.3-70-g09d2 From ade2d3db21b0625f9528bcd6f1656dd7c8d0fe08 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 21 Jun 2010 03:44:50 +0000 Subject: NET: MIPSsim: Fix modpost warning. $ make CONFIG_DEBUG_SECTION_MISMATCH=y [...] WARNING: drivers/net/built-in.o(.data+0x0): Section mismatch in reference from the variable mipsnet_driver to the function .init.text:mipsnet_probe() The variable mipsnet_driver references the function __init mipsnet_probe() If the reference is valid then annotate the variable with __init* or __refdata (see linux/init.h) or name the variable: *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console, [...] Fixed by making mipsnet_probe __devinit. Signed-off-by: Ralf Baechle drivers/net/mipsnet.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) Signed-off-by: David S. Miller --- drivers/net/mipsnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index 8e9704f5c12..869f0ea43a5 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c @@ -247,7 +247,7 @@ static const struct net_device_ops mipsnet_netdev_ops = { .ndo_set_mac_address = eth_mac_addr, }; -static int __init mipsnet_probe(struct platform_device *dev) +static int __devinit mipsnet_probe(struct platform_device *dev) { struct net_device *netdev; int err; -- cgit v1.2.3-70-g09d2 From 13fea6d4f73942e6961aec97ba4c593619d18f6f Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 21 Jun 2010 13:50:18 -0700 Subject: lasi82596: fix netdev_mc_count conversion Fix commit 4cd24eaf0 (net: use netdev_mc_count and netdev_mc_empty when appropriate) Signed-off-by: Helge Deller Signed-off-by: David S. Miller --- drivers/net/lib82596.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index ce5d6e90921..c27f4291b35 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -1343,7 +1343,7 @@ static void set_multicast_list(struct net_device *dev) DEB(DEB_MULTI, printk(KERN_DEBUG "%s: set multicast list, %d entries, promisc %s, allmulti %s\n", - dev->name, dev->mc_count, + dev->name, netdev_mc_count(dev), dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF")); -- cgit v1.2.3-70-g09d2 From d5dc0ae4df9db00b8122378d56a071039b17a1eb Mon Sep 17 00:00:00 2001 From: Filip Aben Date: Tue, 22 Jun 2010 10:10:35 -0700 Subject: hso: remove setting of low_latency flag This patch removes the setting of the low_latency flag. tty_flip_buffer_push() is occasionally being called in irq context, which causes a hang if the low_latency flag is set. Removing the low_latency flag only seems to impact the flush to ldisc, which will now be put on a workqueue. Signed-off-by: Filip Aben Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 0a3c41faea9..4dd23513c5a 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -1334,7 +1334,6 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) /* check for port already opened, if not set the termios */ serial->open_count++; if (serial->open_count == 1) { - tty->low_latency = 1; serial->rx_state = RX_IDLE; /* Force default termio settings */ _hso_serial_set_termios(tty, NULL); -- cgit v1.2.3-70-g09d2 From 06aeb78b85d8c04af03eb37353aa0df98d3db170 Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Wed, 23 Jun 2010 11:49:42 -0700 Subject: net: add dependency on fw class module to qlcnic and netxen_nic netxen_nic and qlcnic driver depends on firmware_class module. Signed-off-by: Anirban Chakraborty Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 2decc597bda..ce2fcdd4ab9 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2754,6 +2754,7 @@ config MYRI10GE_DCA config NETXEN_NIC tristate "NetXen Multi port (1/10) Gigabit Ethernet NIC" depends on PCI + select FW_LOADER help This enables the support for NetXen's Gigabit Ethernet card. @@ -2819,6 +2820,7 @@ config BNX2X config QLCNIC tristate "QLOGIC QLCNIC 1/10Gb Converged Ethernet NIC Support" depends on PCI + select FW_LOADER help This driver supports QLogic QLE8240 and QLE8242 Converged Ethernet devices. -- cgit v1.2.3-70-g09d2 From 6b2a541db58dba5860ccbcfaf36caee064b8a9fd Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Wed, 23 Jun 2010 11:57:09 -0700 Subject: cnic: Disable statistics initialization for eth clients that do not support statistics Disable statistics initialization for eth clients that do not support statistics. This prevents memory corruption on bnx2x hw. Signed-off-by: Dmitry Kravkov Signed-off-by: Michael Chan Signed-off-by: Eilon Greenstein --- drivers/net/cnic.c | 55 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index fe925663d39..80471269977 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c @@ -3919,8 +3919,9 @@ static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev) HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS; context->cstorm_st_context.status_block_id = BNX2X_DEF_SB_ID; - context->xstorm_st_context.statistics_data = (cli | - XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE); + if (cli < MAX_X_STAT_COUNTER_ID) + context->xstorm_st_context.statistics_data = cli | + XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE; context->xstorm_ag_context.cdu_reserved = CDU_RSRVD_VALUE_TYPE_A(BNX2X_HW_CID(BNX2X_ISCSI_L2_CID, func), @@ -3928,10 +3929,12 @@ static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev) ETH_CONNECTION_TYPE); /* reset xstorm per client statistics */ - val = BAR_XSTRORM_INTMEM + - XSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli); - for (i = 0; i < sizeof(struct xstorm_per_client_stats) / 4; i++) - CNIC_WR(dev, val + i * 4, 0); + if (cli < MAX_X_STAT_COUNTER_ID) { + val = BAR_XSTRORM_INTMEM + + XSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli); + for (i = 0; i < sizeof(struct xstorm_per_client_stats) / 4; i++) + CNIC_WR(dev, val + i * 4, 0); + } cp->tx_cons_ptr = &cp->bnx2x_def_status_blk->c_def_status_block.index_values[ @@ -3978,9 +3981,11 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev) BNX2X_ISCSI_RX_SB_INDEX_NUM; context->ustorm_st_context.common.clientId = cli; context->ustorm_st_context.common.status_block_id = BNX2X_DEF_SB_ID; - context->ustorm_st_context.common.flags = - USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS; - context->ustorm_st_context.common.statistics_counter_id = cli; + if (cli < MAX_U_STAT_COUNTER_ID) { + context->ustorm_st_context.common.flags = + USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS; + context->ustorm_st_context.common.statistics_counter_id = cli; + } context->ustorm_st_context.common.mc_alignment_log_size = 0; context->ustorm_st_context.common.bd_buff_size = cp->l2_single_buf_size; @@ -4011,10 +4016,13 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev) /* client tstorm info */ tstorm_client.mtu = cp->l2_single_buf_size - 14; - tstorm_client.config_flags = - (TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE | - TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE); - tstorm_client.statistics_counter_id = cli; + tstorm_client.config_flags = TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE; + + if (cli < MAX_T_STAT_COUNTER_ID) { + tstorm_client.config_flags |= + TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE; + tstorm_client.statistics_counter_id = cli; + } CNIC_WR(dev, BAR_TSTRORM_INTMEM + TSTORM_CLIENT_CONFIG_OFFSET(port, cli), @@ -4024,16 +4032,21 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev) ((u32 *)&tstorm_client)[1]); /* reset tstorm per client statistics */ - val = BAR_TSTRORM_INTMEM + - TSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli); - for (i = 0; i < sizeof(struct tstorm_per_client_stats) / 4; i++) - CNIC_WR(dev, val + i * 4, 0); + if (cli < MAX_T_STAT_COUNTER_ID) { + + val = BAR_TSTRORM_INTMEM + + TSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli); + for (i = 0; i < sizeof(struct tstorm_per_client_stats) / 4; i++) + CNIC_WR(dev, val + i * 4, 0); + } /* reset ustorm per client statistics */ - val = BAR_USTRORM_INTMEM + - USTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli); - for (i = 0; i < sizeof(struct ustorm_per_client_stats) / 4; i++) - CNIC_WR(dev, val + i * 4, 0); + if (cli < MAX_U_STAT_COUNTER_ID) { + val = BAR_USTRORM_INTMEM + + USTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli); + for (i = 0; i < sizeof(struct ustorm_per_client_stats) / 4; i++) + CNIC_WR(dev, val + i * 4, 0); + } cp->rx_cons_ptr = &cp->bnx2x_def_status_blk->u_def_status_block.index_values[ -- cgit v1.2.3-70-g09d2 From 38000a94a902e94ca8b5498f7871c6316de8957a Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Wed, 16 Jun 2010 16:21:58 +0000 Subject: sky2: enable rx/tx in sky2_phy_reinit() sky2_phy_reinit is called by the ethtool helpers sky2_set_settings, sky2_nway_reset and sky2_set_pauseparam when netif_running. However, at the end of sky2_phy_init GM_GP_CTRL has GM_GPCR_RX_ENA and GM_GPCR_TX_ENA cleared. So, doing these commands causes the device to stop working: $ ethtool -r eth0 $ ethtool -A eth0 autoneg off Fix this issue by enabling Rx/Tx after running sky2_phy_init in sky2_phy_reinit. Signed-off-by: Brandon Philips Tested-by: Brandon Philips Cc: stable@kernel.org Tested-by: Mike McCormack Signed-off-by: David S. Miller --- drivers/net/sky2.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 2111c7bbf57..7985165e84f 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -717,11 +717,24 @@ static void sky2_phy_power_down(struct sky2_hw *hw, unsigned port) sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); } +/* Enable Rx/Tx */ +static void sky2_enable_rx_tx(struct sky2_port *sky2) +{ + struct sky2_hw *hw = sky2->hw; + unsigned port = sky2->port; + u16 reg; + + reg = gma_read16(hw, port, GM_GP_CTRL); + reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA; + gma_write16(hw, port, GM_GP_CTRL, reg); +} + /* Force a renegotiation */ static void sky2_phy_reinit(struct sky2_port *sky2) { spin_lock_bh(&sky2->phy_lock); sky2_phy_init(sky2->hw, sky2->port); + sky2_enable_rx_tx(sky2); spin_unlock_bh(&sky2->phy_lock); } @@ -2040,7 +2053,6 @@ static void sky2_link_up(struct sky2_port *sky2) { struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; - u16 reg; static const char *fc_name[] = { [FC_NONE] = "none", [FC_TX] = "tx", @@ -2048,10 +2060,7 @@ static void sky2_link_up(struct sky2_port *sky2) [FC_BOTH] = "both", }; - /* enable Rx/Tx */ - reg = gma_read16(hw, port, GM_GP_CTRL); - reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA; - gma_write16(hw, port, GM_GP_CTRL, reg); + sky2_enable_rx_tx(sky2); gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK); -- cgit v1.2.3-70-g09d2 From 9735b7ef005aaef5e5905cddba893f8725cd8867 Mon Sep 17 00:00:00 2001 From: Ken Kawasaki Date: Sat, 19 Jun 2010 15:24:27 +0000 Subject: smc91c92_cs: fix the problem that lan & modem does not work simultaneously smc91c92_cs: Fix the problem that lan & modem does not work simultaneously in the Megahertz multi-function card. We need to write MEGAHERTZ_ISR to retrigger interrupt. Signed-off-by: Ken Kawasaki Signed-off-by: David S. Miller --- drivers/net/pcmcia/smc91c92_cs.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 64e6a84bbbb..307cd1721e9 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -1505,12 +1505,20 @@ irq_done: writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_LAN + CISREG_COR); writeb(cor, smc->base + MOT_LAN + CISREG_COR); } -#ifdef DOES_NOT_WORK - if (smc->base != NULL) { /* Megahertz MFC's */ - readb(smc->base+MEGAHERTZ_ISR); - readb(smc->base+MEGAHERTZ_ISR); + + if ((smc->base != NULL) && /* Megahertz MFC's */ + (smc->manfid == MANFID_MEGAHERTZ) && + (smc->cardid == PRODID_MEGAHERTZ_EM3288)) { + + u_char tmp; + tmp = readb(smc->base+MEGAHERTZ_ISR); + tmp = readb(smc->base+MEGAHERTZ_ISR); + + /* Retrigger interrupt if needed */ + writeb(tmp, smc->base + MEGAHERTZ_ISR); + writeb(tmp, smc->base + MEGAHERTZ_ISR); } -#endif + spin_unlock(&smc->lock); return IRQ_RETVAL(handled); } -- cgit v1.2.3-70-g09d2 From ed770f01360b392564650bf1553ce723fa46afec Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sun, 20 Jun 2010 22:07:48 +0000 Subject: cpmac: do not leak struct net_device on phy_connect errors If the call to phy_connect fails, we will return directly instead of freeing the previously allocated struct net_device. Signed-off-by: Florian Fainelli CC: stable@kernel.org Signed-off-by: David S. Miller --- drivers/net/cpmac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 3c58db59528..23786ee34be 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -1181,7 +1181,8 @@ static int __devinit cpmac_probe(struct platform_device *pdev) if (netif_msg_drv(priv)) printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); - return PTR_ERR(priv->phy); + rc = PTR_ERR(priv->phy); + goto fail; } if ((rc = register_netdev(dev))) { -- cgit v1.2.3-70-g09d2 From e7752ee280608a24e27f163641121bdc2c68d6af Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Mon, 21 Jun 2010 13:54:19 +0000 Subject: isdn/gigaset: honor CAPI application's buffer size request Fix the Gigaset CAPI driver to limit the length of a connection's payload data receive buffers to the corresponding CAPI application's data buffer size, as some real-life CAPI applications tend to be rather unhappy if they receive bigger data blocks than requested. Impact: bugfix Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller --- drivers/isdn/gigaset/asyncdata.c | 44 ++++++------------------ drivers/isdn/gigaset/capi.c | 8 +++++ drivers/isdn/gigaset/common.c | 32 +++++------------- drivers/isdn/gigaset/gigaset.h | 29 +++++++++++----- drivers/isdn/gigaset/i4l.c | 21 ++++++++++++ drivers/isdn/gigaset/isocdata.c | 72 ++++++++++++++-------------------------- 6 files changed, 94 insertions(+), 112 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index c5016bd2d94..c3b1dc3a13a 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c @@ -126,26 +126,6 @@ static unsigned lock_loop(unsigned numbytes, struct inbuf_t *inbuf) return numbytes; } -/* set up next receive skb for data mode - */ -static void new_rcv_skb(struct bc_state *bcs) -{ - struct cardstate *cs = bcs->cs; - unsigned short hw_hdr_len = cs->hw_hdr_len; - - if (bcs->ignore) { - bcs->skb = NULL; - return; - } - - bcs->skb = dev_alloc_skb(SBUFSIZE + hw_hdr_len); - if (bcs->skb == NULL) { - dev_warn(cs->dev, "could not allocate new skb\n"); - return; - } - skb_reserve(bcs->skb, hw_hdr_len); -} - /* process a block of received bytes in HDLC data mode * (mstate != MS_LOCKED && !(inputstate & INS_command) && proto2 == L2_HDLC) * Collect HDLC frames, undoing byte stuffing and watching for DLE escapes. @@ -159,8 +139,8 @@ static unsigned hdlc_loop(unsigned numbytes, struct inbuf_t *inbuf) struct cardstate *cs = inbuf->cs; struct bc_state *bcs = cs->bcs; int inputstate = bcs->inputstate; - __u16 fcs = bcs->fcs; - struct sk_buff *skb = bcs->skb; + __u16 fcs = bcs->rx_fcs; + struct sk_buff *skb = bcs->rx_skb; unsigned char *src = inbuf->data + inbuf->head; unsigned procbytes = 0; unsigned char c; @@ -245,8 +225,7 @@ byte_stuff: /* prepare reception of next frame */ inputstate &= ~INS_have_data; - new_rcv_skb(bcs); - skb = bcs->skb; + skb = gigaset_new_rx_skb(bcs); } else { /* empty frame (7E 7E) */ #ifdef CONFIG_GIGASET_DEBUG @@ -255,8 +234,7 @@ byte_stuff: if (!skb) { /* skipped (?) */ gigaset_isdn_rcv_err(bcs); - new_rcv_skb(bcs); - skb = bcs->skb; + skb = gigaset_new_rx_skb(bcs); } } @@ -279,11 +257,11 @@ byte_stuff: #endif inputstate |= INS_have_data; if (skb) { - if (skb->len == SBUFSIZE) { + if (skb->len >= bcs->rx_bufsize) { dev_warn(cs->dev, "received packet too long\n"); dev_kfree_skb_any(skb); /* skip remainder of packet */ - bcs->skb = skb = NULL; + bcs->rx_skb = skb = NULL; } else { *__skb_put(skb, 1) = c; fcs = crc_ccitt_byte(fcs, c); @@ -292,7 +270,7 @@ byte_stuff: } bcs->inputstate = inputstate; - bcs->fcs = fcs; + bcs->rx_fcs = fcs; return procbytes; } @@ -308,18 +286,18 @@ static unsigned iraw_loop(unsigned numbytes, struct inbuf_t *inbuf) struct cardstate *cs = inbuf->cs; struct bc_state *bcs = cs->bcs; int inputstate = bcs->inputstate; - struct sk_buff *skb = bcs->skb; + struct sk_buff *skb = bcs->rx_skb; unsigned char *src = inbuf->data + inbuf->head; unsigned procbytes = 0; unsigned char c; if (!skb) { /* skip this block */ - new_rcv_skb(bcs); + gigaset_new_rx_skb(bcs); return numbytes; } - while (procbytes < numbytes && skb->len < SBUFSIZE) { + while (procbytes < numbytes && skb->len < bcs->rx_bufsize) { c = *src++; procbytes++; @@ -343,7 +321,7 @@ static unsigned iraw_loop(unsigned numbytes, struct inbuf_t *inbuf) if (inputstate & INS_have_data) { gigaset_skb_rcvd(bcs, skb); inputstate &= ~INS_have_data; - new_rcv_skb(bcs); + gigaset_new_rx_skb(bcs); } bcs->inputstate = inputstate; diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index 8f78f15c8ef..245a6083f79 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c @@ -80,6 +80,7 @@ struct gigaset_capi_appl { struct list_head ctrlist; struct gigaset_capi_appl *bcnext; u16 id; + struct capi_register_params rp; u16 nextMessageNumber; u32 listenInfoMask; u32 listenCIPmask; @@ -945,6 +946,7 @@ static void gigaset_register_appl(struct capi_ctr *ctr, u16 appl, return; } ap->id = appl; + ap->rp = *rp; list_add(&ap->ctrlist, &iif->appls); } @@ -1166,6 +1168,9 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, } ap->bcnext = NULL; bcs->ap = ap; + bcs->rx_bufsize = ap->rp.datablklen; + dev_kfree_skb(bcs->rx_skb); + gigaset_new_rx_skb(bcs); cmsg->adr.adrPLCI |= (bcs->channel + 1) << 8; /* build command table */ @@ -1435,6 +1440,9 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, CapiCallGivenToOtherApplication); ap->bcnext = NULL; bcs->ap = ap; + bcs->rx_bufsize = ap->rp.datablklen; + dev_kfree_skb(bcs->rx_skb); + gigaset_new_rx_skb(bcs); bcs->chstate |= CHS_NOTIFY_LL; /* check/encode B channel protocol */ diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index f6f45f22192..9778fabbc48 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -399,8 +399,8 @@ static void gigaset_freebcs(struct bc_state *bcs) gig_dbg(DEBUG_INIT, "clearing bcs[%d]->at_state", bcs->channel); clear_at_state(&bcs->at_state); gig_dbg(DEBUG_INIT, "freeing bcs[%d]->skb", bcs->channel); - dev_kfree_skb(bcs->skb); - bcs->skb = NULL; + dev_kfree_skb(bcs->rx_skb); + bcs->rx_skb = NULL; for (i = 0; i < AT_NUM; ++i) { kfree(bcs->commands[i]); @@ -634,19 +634,10 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, bcs->emptycount = 0; #endif - gig_dbg(DEBUG_INIT, "allocating bcs[%d]->skb", channel); - bcs->fcs = PPP_INITFCS; + bcs->rx_bufsize = 0; + bcs->rx_skb = NULL; + bcs->rx_fcs = PPP_INITFCS; bcs->inputstate = 0; - if (cs->ignoreframes) { - bcs->skb = NULL; - } else { - bcs->skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len); - if (bcs->skb != NULL) - skb_reserve(bcs->skb, cs->hw_hdr_len); - else - pr_err("out of memory\n"); - } - bcs->channel = channel; bcs->cs = cs; @@ -663,11 +654,6 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, return bcs; gig_dbg(DEBUG_INIT, " failed"); - - gig_dbg(DEBUG_INIT, " freeing bcs[%d]->skb", channel); - dev_kfree_skb(bcs->skb); - bcs->skb = NULL; - return NULL; } @@ -839,14 +825,12 @@ void gigaset_bcs_reinit(struct bc_state *bcs) bcs->emptycount = 0; #endif - bcs->fcs = PPP_INITFCS; + bcs->rx_fcs = PPP_INITFCS; bcs->chstate = 0; bcs->ignore = cs->ignoreframes; - if (bcs->ignore) { - dev_kfree_skb(bcs->skb); - bcs->skb = NULL; - } + dev_kfree_skb(bcs->rx_skb); + bcs->rx_skb = NULL; cs->ops->reinitbcshw(bcs); } diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 05947f9c184..f77ec54eb07 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -45,10 +45,6 @@ #define MAX_EVENTS 64 /* size of event queue */ #define RBUFSIZE 8192 -#define SBUFSIZE 4096 /* sk_buff payload size */ - -#define TRANSBUFSIZE 768 /* bytes per skb for transparent receive */ -#define MAX_BUF_SIZE (SBUFSIZE - 2) /* Max. size of a data packet from LL */ /* compile time options */ #define GIG_MAJOR 0 @@ -380,8 +376,10 @@ struct bc_state { struct at_state_t at_state; - __u16 fcs; - struct sk_buff *skb; + /* receive buffer */ + unsigned rx_bufsize; /* max size accepted by application */ + struct sk_buff *rx_skb; + __u16 rx_fcs; int inputstate; /* see INS_XXXX */ int channel; @@ -801,8 +799,23 @@ static inline void gigaset_bchannel_up(struct bc_state *bcs) gigaset_schedule_event(bcs->cs); } -/* handling routines for sk_buff */ -/* ============================= */ +/* set up next receive skb for data mode */ +static inline struct sk_buff *gigaset_new_rx_skb(struct bc_state *bcs) +{ + struct cardstate *cs = bcs->cs; + unsigned short hw_hdr_len = cs->hw_hdr_len; + + if (bcs->ignore) { + bcs->rx_skb = NULL; + } else { + bcs->rx_skb = dev_alloc_skb(bcs->rx_bufsize + hw_hdr_len); + if (bcs->rx_skb == NULL) + dev_warn(cs->dev, "could not allocate skb\n"); + else + skb_reserve(bcs->rx_skb, hw_hdr_len); + } + return bcs->rx_skb; +} /* append received bytes to inbuf */ int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src, diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c index c22e5ace827..f01c3c2e2e4 100644 --- a/drivers/isdn/gigaset/i4l.c +++ b/drivers/isdn/gigaset/i4l.c @@ -16,7 +16,10 @@ #include "gigaset.h" #include +#define SBUFSIZE 4096 /* sk_buff payload size */ +#define TRANSBUFSIZE 768 /* bytes per skb for transparent receive */ #define HW_HDR_LEN 2 /* Header size used to store ack info */ +#define MAX_BUF_SIZE (SBUFSIZE - HW_HDR_LEN) /* max data packet from LL */ /* == Handling of I4L IO =====================================================*/ @@ -231,6 +234,15 @@ static int command_from_LL(isdn_ctrl *cntrl) dev_err(cs->dev, "ISDN_CMD_DIAL: channel not free\n"); return -EBUSY; } + switch (bcs->proto2) { + case L2_HDLC: + bcs->rx_bufsize = SBUFSIZE; + break; + default: /* assume transparent */ + bcs->rx_bufsize = TRANSBUFSIZE; + } + dev_kfree_skb(bcs->rx_skb); + gigaset_new_rx_skb(bcs); commands = kzalloc(AT_NUM*(sizeof *commands), GFP_ATOMIC); if (!commands) { @@ -314,6 +326,15 @@ static int command_from_LL(isdn_ctrl *cntrl) return -EINVAL; } bcs = cs->bcs + ch; + switch (bcs->proto2) { + case L2_HDLC: + bcs->rx_bufsize = SBUFSIZE; + break; + default: /* assume transparent */ + bcs->rx_bufsize = TRANSBUFSIZE; + } + dev_kfree_skb(bcs->rx_skb); + gigaset_new_rx_skb(bcs); if (!gigaset_add_event(cs, &bcs->at_state, EV_ACCEPT, NULL, 0, NULL)) return -ENOMEM; diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index 16fd3bd4888..2dfd346fc88 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -500,19 +500,18 @@ int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len) */ static inline void hdlc_putbyte(unsigned char c, struct bc_state *bcs) { - bcs->fcs = crc_ccitt_byte(bcs->fcs, c); - if (unlikely(bcs->skb == NULL)) { + bcs->rx_fcs = crc_ccitt_byte(bcs->rx_fcs, c); + if (bcs->rx_skb == NULL) /* skipping */ return; - } - if (unlikely(bcs->skb->len == SBUFSIZE)) { + if (bcs->rx_skb->len >= bcs->rx_bufsize) { dev_warn(bcs->cs->dev, "received oversized packet discarded\n"); bcs->hw.bas->giants++; - dev_kfree_skb_any(bcs->skb); - bcs->skb = NULL; + dev_kfree_skb_any(bcs->rx_skb); + bcs->rx_skb = NULL; return; } - *__skb_put(bcs->skb, 1) = c; + *__skb_put(bcs->rx_skb, 1) = c; } /* hdlc_flush @@ -521,18 +520,13 @@ static inline void hdlc_putbyte(unsigned char c, struct bc_state *bcs) static inline void hdlc_flush(struct bc_state *bcs) { /* clear skb or allocate new if not skipping */ - if (likely(bcs->skb != NULL)) - skb_trim(bcs->skb, 0); - else if (!bcs->ignore) { - bcs->skb = dev_alloc_skb(SBUFSIZE + bcs->cs->hw_hdr_len); - if (bcs->skb) - skb_reserve(bcs->skb, bcs->cs->hw_hdr_len); - else - dev_err(bcs->cs->dev, "could not allocate skb\n"); - } + if (bcs->rx_skb != NULL) + skb_trim(bcs->rx_skb, 0); + else + gigaset_new_rx_skb(bcs); /* reset packet state */ - bcs->fcs = PPP_INITFCS; + bcs->rx_fcs = PPP_INITFCS; } /* hdlc_done @@ -549,7 +543,7 @@ static inline void hdlc_done(struct bc_state *bcs) hdlc_flush(bcs); return; } - procskb = bcs->skb; + procskb = bcs->rx_skb; if (procskb == NULL) { /* previous error */ gig_dbg(DEBUG_ISO, "%s: skb=NULL", __func__); @@ -560,8 +554,8 @@ static inline void hdlc_done(struct bc_state *bcs) bcs->hw.bas->runts++; dev_kfree_skb_any(procskb); gigaset_isdn_rcv_err(bcs); - } else if (bcs->fcs != PPP_GOODFCS) { - dev_notice(cs->dev, "frame check error (0x%04x)\n", bcs->fcs); + } else if (bcs->rx_fcs != PPP_GOODFCS) { + dev_notice(cs->dev, "frame check error\n"); bcs->hw.bas->fcserrs++; dev_kfree_skb_any(procskb); gigaset_isdn_rcv_err(bcs); @@ -574,13 +568,8 @@ static inline void hdlc_done(struct bc_state *bcs) bcs->hw.bas->goodbytes += len; gigaset_skb_rcvd(bcs, procskb); } - - bcs->skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len); - if (bcs->skb) - skb_reserve(bcs->skb, cs->hw_hdr_len); - else - dev_err(cs->dev, "could not allocate skb\n"); - bcs->fcs = PPP_INITFCS; + gigaset_new_rx_skb(bcs); + bcs->rx_fcs = PPP_INITFCS; } /* hdlc_frag @@ -597,8 +586,8 @@ static inline void hdlc_frag(struct bc_state *bcs, unsigned inbits) dev_notice(bcs->cs->dev, "received partial byte (%d bits)\n", inbits); bcs->hw.bas->alignerrs++; gigaset_isdn_rcv_err(bcs); - __skb_trim(bcs->skb, 0); - bcs->fcs = PPP_INITFCS; + __skb_trim(bcs->rx_skb, 0); + bcs->rx_fcs = PPP_INITFCS; } /* bit counts lookup table for HDLC bit unstuffing @@ -847,7 +836,6 @@ static inline void hdlc_unpack(unsigned char *src, unsigned count, static inline void trans_receive(unsigned char *src, unsigned count, struct bc_state *bcs) { - struct cardstate *cs = bcs->cs; struct sk_buff *skb; int dobytes; unsigned char *dst; @@ -857,17 +845,11 @@ static inline void trans_receive(unsigned char *src, unsigned count, hdlc_flush(bcs); return; } - skb = bcs->skb; - if (unlikely(skb == NULL)) { - bcs->skb = skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len); - if (!skb) { - dev_err(cs->dev, "could not allocate skb\n"); - return; - } - skb_reserve(skb, cs->hw_hdr_len); - } + skb = bcs->rx_skb; + if (skb == NULL) + skb = gigaset_new_rx_skb(bcs); bcs->hw.bas->goodbytes += skb->len; - dobytes = TRANSBUFSIZE - skb->len; + dobytes = bcs->rx_bufsize - skb->len; while (count > 0) { dst = skb_put(skb, count < dobytes ? count : dobytes); while (count > 0 && dobytes > 0) { @@ -879,14 +861,10 @@ static inline void trans_receive(unsigned char *src, unsigned count, dump_bytes(DEBUG_STREAM_DUMP, "rcv data", skb->data, skb->len); gigaset_skb_rcvd(bcs, skb); - bcs->skb = skb = - dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len); - if (!skb) { - dev_err(cs->dev, "could not allocate skb\n"); + skb = gigaset_new_rx_skb(bcs); + if (skb == NULL) return; - } - skb_reserve(skb, cs->hw_hdr_len); - dobytes = TRANSBUFSIZE; + dobytes = bcs->rx_bufsize; } } } -- cgit v1.2.3-70-g09d2 From 278a582989ade4cb5335762d6c5999562018859d Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Mon, 21 Jun 2010 13:54:35 +0000 Subject: isdn/gigaset: correct CAPI voice connection encoding Make the Gigaset CAPI driver select L2_VOICE (AT^SBPR=2) as the layer 2 encoding for transparent connections, like the ISDN4Linux variant. L2_BITSYNC (AT^SBPR=0) mutes internal connections and distorts external ones. Impact: bugfix Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller --- drivers/isdn/gigaset/capi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index 245a6083f79..cb55ead557c 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c @@ -1327,13 +1327,13 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, bcs->proto2 = L2_HDLC; break; case 1: - bcs->proto2 = L2_BITSYNC; + bcs->proto2 = L2_VOICE; break; default: dev_warn(cs->dev, "B1 Protocol %u unsupported, using Transparent\n", cmsg->B1protocol); - bcs->proto2 = L2_BITSYNC; + bcs->proto2 = L2_VOICE; } if (cmsg->B2protocol != 1) dev_warn(cs->dev, @@ -1456,13 +1456,13 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, bcs->proto2 = L2_HDLC; break; case 1: - bcs->proto2 = L2_BITSYNC; + bcs->proto2 = L2_VOICE; break; default: dev_warn(cs->dev, "B1 Protocol %u unsupported, using Transparent\n", cmsg->B1protocol); - bcs->proto2 = L2_BITSYNC; + bcs->proto2 = L2_VOICE; } if (cmsg->B2protocol != 1) dev_warn(cs->dev, -- cgit v1.2.3-70-g09d2 From 23b36778b4c82577746d26e4ac0ae66c6f462475 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Mon, 21 Jun 2010 13:54:50 +0000 Subject: isdn/gigaset: correct CAPI DATA_B3 Delivery Confirmation The Gigaset CAPI driver handled all DATA_B3_REQ messages as if the Delivery Confirmation flag bit was set, delaying the emission of the DATA_B3_CONF reply until the data was actually transmitted. Some CAPI applications (notably Asterisk) aren't happy with that behaviour. Change it to actually evaluate the Delivery Confirmation flag as described the CAPI specification. Impact: bugfix Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller --- drivers/isdn/gigaset/capi.c | 83 ++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index cb55ead557c..e685123fef4 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c @@ -320,6 +320,39 @@ static const char *format_ie(const char *ie) return result; } +/* + * emit DATA_B3_CONF message + */ +static void send_data_b3_conf(struct cardstate *cs, struct capi_ctr *ctr, + u16 appl, u16 msgid, int channel, + u16 handle, u16 info) +{ + struct sk_buff *cskb; + u8 *msg; + + cskb = alloc_skb(CAPI_DATA_B3_CONF_LEN, GFP_ATOMIC); + if (!cskb) { + dev_err(cs->dev, "%s: out of memory\n", __func__); + return; + } + /* frequent message, avoid _cmsg overhead */ + msg = __skb_put(cskb, CAPI_DATA_B3_CONF_LEN); + CAPIMSG_SETLEN(msg, CAPI_DATA_B3_CONF_LEN); + CAPIMSG_SETAPPID(msg, appl); + CAPIMSG_SETCOMMAND(msg, CAPI_DATA_B3); + CAPIMSG_SETSUBCOMMAND(msg, CAPI_CONF); + CAPIMSG_SETMSGID(msg, msgid); + CAPIMSG_SETCONTROLLER(msg, ctr->cnr); + CAPIMSG_SETPLCI_PART(msg, channel); + CAPIMSG_SETNCCI_PART(msg, 1); + CAPIMSG_SETHANDLE_CONF(msg, handle); + CAPIMSG_SETINFO_CONF(msg, info); + + /* emit message */ + dump_rawmsg(DEBUG_MCMD, __func__, msg); + capi_ctr_handle_message(ctr, appl, cskb); +} + /* * driver interface functions @@ -340,7 +373,6 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb) struct gigaset_capi_ctr *iif = cs->iif; struct gigaset_capi_appl *ap = bcs->ap; unsigned char *req = skb_mac_header(dskb); - struct sk_buff *cskb; u16 flags; /* update statistics */ @@ -357,34 +389,17 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb) return; } - /* ToDo: honor unset "delivery confirmation" bit */ + /* + * send DATA_B3_CONF if "delivery confirmation" bit was set in request; + * otherwise it has already been sent by do_data_b3_req() + */ flags = CAPIMSG_FLAGS(req); - - /* build DATA_B3_CONF message */ - cskb = alloc_skb(CAPI_DATA_B3_CONF_LEN, GFP_ATOMIC); - if (!cskb) { - dev_err(cs->dev, "%s: out of memory\n", __func__); - return; - } - /* frequent message, avoid _cmsg overhead */ - CAPIMSG_SETLEN(cskb->data, CAPI_DATA_B3_CONF_LEN); - CAPIMSG_SETAPPID(cskb->data, ap->id); - CAPIMSG_SETCOMMAND(cskb->data, CAPI_DATA_B3); - CAPIMSG_SETSUBCOMMAND(cskb->data, CAPI_CONF); - CAPIMSG_SETMSGID(cskb->data, CAPIMSG_MSGID(req)); - CAPIMSG_SETCONTROLLER(cskb->data, iif->ctr.cnr); - CAPIMSG_SETPLCI_PART(cskb->data, bcs->channel + 1); - CAPIMSG_SETNCCI_PART(cskb->data, 1); - CAPIMSG_SETHANDLE_CONF(cskb->data, CAPIMSG_HANDLE_REQ(req)); - if (flags & ~CAPI_FLAGS_DELIVERY_CONFIRMATION) - CAPIMSG_SETINFO_CONF(cskb->data, - CapiFlagsNotSupportedByProtocol); - else - CAPIMSG_SETINFO_CONF(cskb->data, CAPI_NOERROR); - - /* emit message */ - dump_rawmsg(DEBUG_LLDATA, "DATA_B3_CONF", cskb->data); - capi_ctr_handle_message(&iif->ctr, ap->id, cskb); + if (flags & CAPI_FLAGS_DELIVERY_CONFIRMATION) + send_data_b3_conf(cs, &iif->ctr, ap->id, CAPIMSG_MSGID(req), + bcs->channel + 1, CAPIMSG_HANDLE_REQ(req), + (flags & ~CAPI_FLAGS_DELIVERY_CONFIRMATION) ? + CapiFlagsNotSupportedByProtocol : + CAPI_NOERROR); } EXPORT_SYMBOL_GPL(gigaset_skb_sent); @@ -1795,6 +1810,8 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, u16 msglen = CAPIMSG_LEN(skb->data); u16 datalen = CAPIMSG_DATALEN(skb->data); u16 flags = CAPIMSG_FLAGS(skb->data); + u16 msgid = CAPIMSG_MSGID(skb->data); + u16 handle = CAPIMSG_HANDLE_REQ(skb->data); /* frequent message, avoid _cmsg overhead */ dump_rawmsg(DEBUG_LLDATA, "DATA_B3_REQ", skb->data); @@ -1845,12 +1862,14 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, return; } - /* DATA_B3_CONF reply will be sent by gigaset_skb_sent() */ - /* - * ToDo: honor unset "delivery confirmation" bit - * (send DATA_B3_CONF immediately?) + * DATA_B3_CONF will be sent by gigaset_skb_sent() only if "delivery + * confirmation" bit is set; otherwise we have to send it now */ + if (!(flags & CAPI_FLAGS_DELIVERY_CONFIRMATION)) + send_data_b3_conf(cs, &iif->ctr, ap->id, msgid, channel, handle, + flags ? CapiFlagsNotSupportedByProtocol + : CAPI_NOERROR); } /* -- cgit v1.2.3-70-g09d2 From 1ce368ff288ed872a8fee93b8a2b7706111feb9a Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Mon, 21 Jun 2010 13:55:05 +0000 Subject: isdn/gigaset: encode HLC and BC together Adapt to buggy device firmware which accepts setting HLC only in the same command line as BC, by encoding HLC and BC in a single command if both are specified, and rejecting HLC without BC. Impact: bugfix Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller --- drivers/isdn/gigaset/capi.c | 81 +++++++++++++++++++++++++---------------- drivers/isdn/gigaset/ev-layer.c | 4 +- drivers/isdn/gigaset/gigaset.h | 5 +-- 3 files changed, 52 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index e685123fef4..665673f4d66 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c @@ -1166,7 +1166,7 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, char **commands; char *s; u8 *pp; - int i, l; + int i, l, lbc, lhlc; u16 info; /* decode message */ @@ -1293,42 +1293,59 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, goto error; } - /* check/encode parameter: BC */ - if (cmsg->BC && cmsg->BC[0]) { - /* explicit BC overrides CIP */ - l = 2*cmsg->BC[0] + 7; + /* + * check/encode parameters: BC & HLC + * must be encoded together as device doesn't accept HLC separately + * explicit parameters override values derived from CIP + */ + + /* determine lengths */ + if (cmsg->BC && cmsg->BC[0]) /* BC specified explicitly */ + lbc = 2*cmsg->BC[0]; + else if (cip2bchlc[cmsg->CIPValue].bc) /* BC derived from CIP */ + lbc = strlen(cip2bchlc[cmsg->CIPValue].bc); + else /* no BC */ + lbc = 0; + if (cmsg->HLC && cmsg->HLC[0]) /* HLC specified explicitly */ + lhlc = 2*cmsg->HLC[0]; + else if (cip2bchlc[cmsg->CIPValue].hlc) /* HLC derived from CIP */ + lhlc = strlen(cip2bchlc[cmsg->CIPValue].hlc); + else /* no HLC */ + lhlc = 0; + + if (lbc) { + /* have BC: allocate and assemble command string */ + l = lbc + 7; /* "^SBC=" + value + "\r" + null byte */ + if (lhlc) + l += lhlc + 7; /* ";^SHLC=" + value */ commands[AT_BC] = kmalloc(l, GFP_KERNEL); if (!commands[AT_BC]) goto oom; strcpy(commands[AT_BC], "^SBC="); - decode_ie(cmsg->BC, commands[AT_BC]+5); + if (cmsg->BC && cmsg->BC[0]) /* BC specified explicitly */ + decode_ie(cmsg->BC, commands[AT_BC] + 5); + else /* BC derived from CIP */ + strcpy(commands[AT_BC] + 5, + cip2bchlc[cmsg->CIPValue].bc); + if (lhlc) { + strcpy(commands[AT_BC] + lbc + 5, ";^SHLC="); + if (cmsg->HLC && cmsg->HLC[0]) + /* HLC specified explicitly */ + decode_ie(cmsg->HLC, + commands[AT_BC] + lbc + 12); + else /* HLC derived from CIP */ + strcpy(commands[AT_BC] + lbc + 12, + cip2bchlc[cmsg->CIPValue].hlc); + } strcpy(commands[AT_BC] + l - 2, "\r"); - } else if (cip2bchlc[cmsg->CIPValue].bc) { - l = strlen(cip2bchlc[cmsg->CIPValue].bc) + 7; - commands[AT_BC] = kmalloc(l, GFP_KERNEL); - if (!commands[AT_BC]) - goto oom; - snprintf(commands[AT_BC], l, "^SBC=%s\r", - cip2bchlc[cmsg->CIPValue].bc); - } - - /* check/encode parameter: HLC */ - if (cmsg->HLC && cmsg->HLC[0]) { - /* explicit HLC overrides CIP */ - l = 2*cmsg->HLC[0] + 7; - commands[AT_HLC] = kmalloc(l, GFP_KERNEL); - if (!commands[AT_HLC]) - goto oom; - strcpy(commands[AT_HLC], "^SHLC="); - decode_ie(cmsg->HLC, commands[AT_HLC]+5); - strcpy(commands[AT_HLC] + l - 2, "\r"); - } else if (cip2bchlc[cmsg->CIPValue].hlc) { - l = strlen(cip2bchlc[cmsg->CIPValue].hlc) + 7; - commands[AT_HLC] = kmalloc(l, GFP_KERNEL); - if (!commands[AT_HLC]) - goto oom; - snprintf(commands[AT_HLC], l, "^SHLC=%s\r", - cip2bchlc[cmsg->CIPValue].hlc); + } else { + /* no BC */ + if (lhlc) { + dev_notice(cs->dev, "%s: cannot set HLC without BC\n", + "CONNECT_REQ"); + info = CapiIllMessageParmCoding; /* ? */ + goto error; + } } /* check/encode parameter: B Protocol */ diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index 206c380c523..ceaef9a04a4 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -282,9 +282,7 @@ struct reply_t gigaset_tab_cid[] = /* dial */ {EV_DIAL, -1, -1, -1, -1, -1, {ACT_DIAL} }, {RSP_INIT, 0, 0, SEQ_DIAL, 601, 5, {ACT_CMD+AT_BC} }, -{RSP_OK, 601, 601, -1, 602, 5, {ACT_CMD+AT_HLC} }, -{RSP_NULL, 602, 602, -1, 603, 5, {ACT_CMD+AT_PROTO} }, -{RSP_OK, 602, 602, -1, 603, 5, {ACT_CMD+AT_PROTO} }, +{RSP_OK, 601, 601, -1, 603, 5, {ACT_CMD+AT_PROTO} }, {RSP_OK, 603, 603, -1, 604, 5, {ACT_CMD+AT_TYPE} }, {RSP_OK, 604, 604, -1, 605, 5, {ACT_CMD+AT_MSN} }, {RSP_NULL, 605, 605, -1, 606, 5, {ACT_CMD+AT_CLIP} }, diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index f77ec54eb07..c4e6c26897e 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -186,10 +186,9 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg, #define AT_BC 3 #define AT_PROTO 4 #define AT_TYPE 5 -#define AT_HLC 6 -#define AT_CLIP 7 +#define AT_CLIP 6 /* total number */ -#define AT_NUM 8 +#define AT_NUM 7 /* variables in struct at_state_t */ #define VAR_ZSAU 0 -- cgit v1.2.3-70-g09d2 From 1b4843c5e8cbab86830da8a53b8288882060c059 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Mon, 21 Jun 2010 13:55:20 +0000 Subject: isdn/gigaset: correct CAPI connection state storage CAPI applications can handle several connections in parallel, so one connection state per application isn't sufficient. Store the connection state in the channel structure instead. Impact: bugfix Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller --- drivers/isdn/gigaset/capi.c | 225 +++++++++++++++++++++++++++++++---------- drivers/isdn/gigaset/common.c | 4 + drivers/isdn/gigaset/gigaset.h | 4 +- 3 files changed, 180 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index 665673f4d66..6fbe8999c41 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c @@ -70,7 +70,7 @@ #define MAX_NUMBER_DIGITS 20 #define MAX_FMT_IE_LEN 20 -/* values for gigaset_capi_appl.connected */ +/* values for bcs->apconnstate */ #define APCONN_NONE 0 /* inactive/listening */ #define APCONN_SETUP 1 /* connecting */ #define APCONN_ACTIVE 2 /* B channel up */ @@ -84,7 +84,6 @@ struct gigaset_capi_appl { u16 nextMessageNumber; u32 listenInfoMask; u32 listenCIPmask; - int connected; }; /* CAPI specific controller data structure */ @@ -384,7 +383,7 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb) } /* don't send further B3 messages if disconnected */ - if (ap->connected < APCONN_ACTIVE) { + if (bcs->apconnstate < APCONN_ACTIVE) { gig_dbg(DEBUG_LLDATA, "disconnected, discarding ack"); return; } @@ -428,7 +427,7 @@ void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb) } /* don't send further B3 messages if disconnected */ - if (ap->connected < APCONN_ACTIVE) { + if (bcs->apconnstate < APCONN_ACTIVE) { gig_dbg(DEBUG_LLDATA, "disconnected, discarding data"); dev_kfree_skb_any(skb); return; @@ -500,6 +499,7 @@ int gigaset_isdn_icall(struct at_state_t *at_state) u32 actCIPmask; struct sk_buff *skb; unsigned int msgsize; + unsigned long flags; int i; /* @@ -624,7 +624,14 @@ int gigaset_isdn_icall(struct at_state_t *at_state) format_ie(iif->hcmsg.CalledPartyNumber)); /* scan application list for matching listeners */ - bcs->ap = NULL; + spin_lock_irqsave(&bcs->aplock, flags); + if (bcs->ap != NULL || bcs->apconnstate != APCONN_NONE) { + dev_warn(cs->dev, "%s: channel not properly cleared (%p/%d)\n", + __func__, bcs->ap, bcs->apconnstate); + bcs->ap = NULL; + bcs->apconnstate = APCONN_NONE; + } + spin_unlock_irqrestore(&bcs->aplock, flags); actCIPmask = 1 | (1 << iif->hcmsg.CIPValue); list_for_each_entry(ap, &iif->appls, ctrlist) if (actCIPmask & ap->listenCIPmask) { @@ -642,10 +649,12 @@ int gigaset_isdn_icall(struct at_state_t *at_state) dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); /* add to listeners on this B channel, update state */ + spin_lock_irqsave(&bcs->aplock, flags); ap->bcnext = bcs->ap; bcs->ap = ap; bcs->chstate |= CHS_NOTIFY_LL; - ap->connected = APCONN_SETUP; + bcs->apconnstate = APCONN_SETUP; + spin_unlock_irqrestore(&bcs->aplock, flags); /* emit message */ capi_ctr_handle_message(&iif->ctr, ap->id, skb); @@ -670,7 +679,7 @@ static void send_disconnect_ind(struct bc_state *bcs, struct gigaset_capi_ctr *iif = cs->iif; struct sk_buff *skb; - if (ap->connected == APCONN_NONE) + if (bcs->apconnstate == APCONN_NONE) return; capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT, CAPI_IND, @@ -684,7 +693,6 @@ static void send_disconnect_ind(struct bc_state *bcs, } capi_cmsg2message(&iif->hcmsg, __skb_put(skb, CAPI_DISCONNECT_IND_LEN)); dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); - ap->connected = APCONN_NONE; capi_ctr_handle_message(&iif->ctr, ap->id, skb); } @@ -701,9 +709,9 @@ static void send_disconnect_b3_ind(struct bc_state *bcs, struct sk_buff *skb; /* nothing to do if no logical connection active */ - if (ap->connected < APCONN_ACTIVE) + if (bcs->apconnstate < APCONN_ACTIVE) return; - ap->connected = APCONN_SETUP; + bcs->apconnstate = APCONN_SETUP; capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT_B3, CAPI_IND, ap->nextMessageNumber++, @@ -730,14 +738,25 @@ void gigaset_isdn_connD(struct bc_state *bcs) { struct cardstate *cs = bcs->cs; struct gigaset_capi_ctr *iif = cs->iif; - struct gigaset_capi_appl *ap = bcs->ap; + struct gigaset_capi_appl *ap; struct sk_buff *skb; unsigned int msgsize; + unsigned long flags; + spin_lock_irqsave(&bcs->aplock, flags); + ap = bcs->ap; if (!ap) { + spin_unlock_irqrestore(&bcs->aplock, flags); dev_err(cs->dev, "%s: no application\n", __func__); return; } + if (bcs->apconnstate == APCONN_NONE) { + spin_unlock_irqrestore(&bcs->aplock, flags); + dev_warn(cs->dev, "%s: application %u not connected\n", + __func__, ap->id); + return; + } + spin_unlock_irqrestore(&bcs->aplock, flags); while (ap->bcnext) { /* this should never happen */ dev_warn(cs->dev, "%s: dropping extra application %u\n", @@ -746,11 +765,6 @@ void gigaset_isdn_connD(struct bc_state *bcs) CapiCallGivenToOtherApplication); ap->bcnext = ap->bcnext->bcnext; } - if (ap->connected == APCONN_NONE) { - dev_warn(cs->dev, "%s: application %u not connected\n", - __func__, ap->id); - return; - } /* prepare CONNECT_ACTIVE_IND message * Note: LLC not supported by device @@ -788,17 +802,24 @@ void gigaset_isdn_connD(struct bc_state *bcs) void gigaset_isdn_hupD(struct bc_state *bcs) { struct gigaset_capi_appl *ap; + unsigned long flags; /* * ToDo: pass on reason code reported by device * (requires ev-layer state machine extension to collect * ZCAU device reply) */ - for (ap = bcs->ap; ap != NULL; ap = ap->bcnext) { + spin_lock_irqsave(&bcs->aplock, flags); + while (bcs->ap != NULL) { + ap = bcs->ap; + bcs->ap = ap->bcnext; + spin_unlock_irqrestore(&bcs->aplock, flags); send_disconnect_b3_ind(bcs, ap); send_disconnect_ind(bcs, ap, 0); + spin_lock_irqsave(&bcs->aplock, flags); } - bcs->ap = NULL; + bcs->apconnstate = APCONN_NONE; + spin_unlock_irqrestore(&bcs->aplock, flags); } /** @@ -812,24 +833,21 @@ void gigaset_isdn_connB(struct bc_state *bcs) { struct cardstate *cs = bcs->cs; struct gigaset_capi_ctr *iif = cs->iif; - struct gigaset_capi_appl *ap = bcs->ap; + struct gigaset_capi_appl *ap; struct sk_buff *skb; + unsigned long flags; unsigned int msgsize; u8 command; + spin_lock_irqsave(&bcs->aplock, flags); + ap = bcs->ap; if (!ap) { + spin_unlock_irqrestore(&bcs->aplock, flags); dev_err(cs->dev, "%s: no application\n", __func__); return; } - while (ap->bcnext) { - /* this should never happen */ - dev_warn(cs->dev, "%s: dropping extra application %u\n", - __func__, ap->bcnext->id); - send_disconnect_ind(bcs, ap->bcnext, - CapiCallGivenToOtherApplication); - ap->bcnext = ap->bcnext->bcnext; - } - if (!ap->connected) { + if (!bcs->apconnstate) { + spin_unlock_irqrestore(&bcs->aplock, flags); dev_warn(cs->dev, "%s: application %u not connected\n", __func__, ap->id); return; @@ -841,13 +859,26 @@ void gigaset_isdn_connB(struct bc_state *bcs) * CONNECT_B3_ACTIVE_IND in reply to CONNECT_B3_RESP * Parameters in both cases always: NCCI = 1, NCPI empty */ - if (ap->connected >= APCONN_ACTIVE) { + if (bcs->apconnstate >= APCONN_ACTIVE) { command = CAPI_CONNECT_B3_ACTIVE; msgsize = CAPI_CONNECT_B3_ACTIVE_IND_BASELEN; } else { command = CAPI_CONNECT_B3; msgsize = CAPI_CONNECT_B3_IND_BASELEN; } + bcs->apconnstate = APCONN_ACTIVE; + + spin_unlock_irqrestore(&bcs->aplock, flags); + + while (ap->bcnext) { + /* this should never happen */ + dev_warn(cs->dev, "%s: dropping extra application %u\n", + __func__, ap->bcnext->id); + send_disconnect_ind(bcs, ap->bcnext, + CapiCallGivenToOtherApplication); + ap->bcnext = ap->bcnext->bcnext; + } + capi_cmsg_header(&iif->hcmsg, ap->id, command, CAPI_IND, ap->nextMessageNumber++, iif->ctr.cnr | ((bcs->channel + 1) << 8) | (1 << 16)); @@ -858,7 +889,6 @@ void gigaset_isdn_connB(struct bc_state *bcs) } capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize)); dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); - ap->connected = APCONN_ACTIVE; capi_ctr_handle_message(&iif->ctr, ap->id, skb); } @@ -964,6 +994,61 @@ static void gigaset_register_appl(struct capi_ctr *ctr, u16 appl, ap->rp = *rp; list_add(&ap->ctrlist, &iif->appls); + dev_info(cs->dev, "application %u registered\n", ap->id); +} + +/* + * remove CAPI application from channel + * helper function to keep indentation levels down and stay in 80 columns + */ + +static inline void remove_appl_from_channel(struct bc_state *bcs, + struct gigaset_capi_appl *ap) +{ + struct cardstate *cs = bcs->cs; + struct gigaset_capi_appl *bcap; + unsigned long flags; + int prevconnstate; + + spin_lock_irqsave(&bcs->aplock, flags); + bcap = bcs->ap; + if (bcap == NULL) { + spin_unlock_irqrestore(&bcs->aplock, flags); + return; + } + + /* check first application on channel */ + if (bcap == ap) { + bcs->ap = ap->bcnext; + if (bcs->ap != NULL) { + spin_unlock_irqrestore(&bcs->aplock, flags); + return; + } + + /* none left, clear channel state */ + prevconnstate = bcs->apconnstate; + bcs->apconnstate = APCONN_NONE; + spin_unlock_irqrestore(&bcs->aplock, flags); + + if (prevconnstate == APCONN_ACTIVE) { + dev_notice(cs->dev, "%s: hanging up channel %u\n", + __func__, bcs->channel); + gigaset_add_event(cs, &bcs->at_state, + EV_HUP, NULL, 0, NULL); + gigaset_schedule_event(cs); + } + return; + } + + /* check remaining list */ + do { + if (bcap->bcnext == ap) { + bcap->bcnext = bcap->bcnext->bcnext; + return; + } + bcap = bcap->bcnext; + } while (bcap != NULL); + spin_unlock_irqrestore(&bcs->aplock, flags); } /* @@ -975,19 +1060,19 @@ static void gigaset_release_appl(struct capi_ctr *ctr, u16 appl) = container_of(ctr, struct gigaset_capi_ctr, ctr); struct cardstate *cs = iif->ctr.driverdata; struct gigaset_capi_appl *ap, *tmp; + unsigned ch; list_for_each_entry_safe(ap, tmp, &iif->appls, ctrlist) if (ap->id == appl) { - if (ap->connected != APCONN_NONE) { - dev_err(cs->dev, - "%s: application %u still connected\n", - __func__, ap->id); - /* ToDo: clear active connection */ - } + /* remove from any channels */ + for (ch = 0; ch < cs->channels; ch++) + remove_appl_from_channel(&cs->bcs[ch], ap); + + /* remove from registration list */ list_del(&ap->ctrlist); kfree(ap); + dev_info(cs->dev, "application %u released\n", appl); } - } /* @@ -1166,6 +1251,7 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, char **commands; char *s; u8 *pp; + unsigned long flags; int i, l, lbc, lhlc; u16 info; @@ -1181,8 +1267,15 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, send_conf(iif, ap, skb, CapiNoPlciAvailable); return; } + spin_lock_irqsave(&bcs->aplock, flags); + if (bcs->ap != NULL || bcs->apconnstate != APCONN_NONE) + dev_warn(cs->dev, "%s: channel not properly cleared (%p/%d)\n", + __func__, bcs->ap, bcs->apconnstate); ap->bcnext = NULL; bcs->ap = ap; + bcs->apconnstate = APCONN_SETUP; + spin_unlock_irqrestore(&bcs->aplock, flags); + bcs->rx_bufsize = ap->rp.datablklen; dev_kfree_skb(bcs->rx_skb); gigaset_new_rx_skb(bcs); @@ -1419,7 +1512,6 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, goto error; } gigaset_schedule_event(cs); - ap->connected = APCONN_SETUP; send_conf(iif, ap, skb, CapiSuccess); return; @@ -1447,6 +1539,7 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, _cmsg *cmsg = &iif->acmsg; struct bc_state *bcs; struct gigaset_capi_appl *oap; + unsigned long flags; int channel; /* decode message */ @@ -1466,12 +1559,21 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, switch (cmsg->Reject) { case 0: /* Accept */ /* drop all competing applications, keep only this one */ - for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) - if (oap != ap) + spin_lock_irqsave(&bcs->aplock, flags); + while (bcs->ap != NULL) { + oap = bcs->ap; + bcs->ap = oap->bcnext; + if (oap != ap) { + spin_unlock_irqrestore(&bcs->aplock, flags); send_disconnect_ind(bcs, oap, CapiCallGivenToOtherApplication); + spin_lock_irqsave(&bcs->aplock, flags); + } + } ap->bcnext = NULL; bcs->ap = ap; + spin_unlock_irqrestore(&bcs->aplock, flags); + bcs->rx_bufsize = ap->rp.datablklen; dev_kfree_skb(bcs->rx_skb); gigaset_new_rx_skb(bcs); @@ -1542,31 +1644,45 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, send_disconnect_ind(bcs, ap, 0); /* remove it from the list of listening apps */ + spin_lock_irqsave(&bcs->aplock, flags); if (bcs->ap == ap) { bcs->ap = ap->bcnext; - if (bcs->ap == NULL) + if (bcs->ap == NULL) { /* last one: stop ev-layer hupD notifications */ + bcs->apconnstate = APCONN_NONE; bcs->chstate &= ~CHS_NOTIFY_LL; + } + spin_unlock_irqrestore(&bcs->aplock, flags); return; } for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) { if (oap->bcnext == ap) { oap->bcnext = oap->bcnext->bcnext; + spin_unlock_irqrestore(&bcs->aplock, flags); return; } } + spin_unlock_irqrestore(&bcs->aplock, flags); dev_err(cs->dev, "%s: application %u not found\n", __func__, ap->id); return; default: /* Reject */ /* drop all competing applications, keep only this one */ - for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) - if (oap != ap) + spin_lock_irqsave(&bcs->aplock, flags); + while (bcs->ap != NULL) { + oap = bcs->ap; + bcs->ap = oap->bcnext; + if (oap != ap) { + spin_unlock_irqrestore(&bcs->aplock, flags); send_disconnect_ind(bcs, oap, CapiCallGivenToOtherApplication); + spin_lock_irqsave(&bcs->aplock, flags); + } + } ap->bcnext = NULL; bcs->ap = ap; + spin_unlock_irqrestore(&bcs->aplock, flags); /* reject call - will trigger DISCONNECT_IND for this app */ dev_info(cs->dev, "%s: Reject=%x\n", @@ -1589,6 +1705,7 @@ static void do_connect_b3_req(struct gigaset_capi_ctr *iif, { struct cardstate *cs = iif->ctr.driverdata; _cmsg *cmsg = &iif->acmsg; + struct bc_state *bcs; int channel; /* decode message */ @@ -1603,9 +1720,10 @@ static void do_connect_b3_req(struct gigaset_capi_ctr *iif, send_conf(iif, ap, skb, CapiIllContrPlciNcci); return; } + bcs = &cs->bcs[channel-1]; /* mark logical connection active */ - ap->connected = APCONN_ACTIVE; + bcs->apconnstate = APCONN_ACTIVE; /* build NCCI: always 1 (one B3 connection only) */ cmsg->adr.adrNCCI |= 1 << 16; @@ -1651,7 +1769,7 @@ static void do_connect_b3_resp(struct gigaset_capi_ctr *iif, if (cmsg->Reject) { /* Reject: clear B3 connect received flag */ - ap->connected = APCONN_SETUP; + bcs->apconnstate = APCONN_SETUP; /* trigger hangup, causing eventual DISCONNECT_IND */ if (!gigaset_add_event(cs, &bcs->at_state, @@ -1723,11 +1841,11 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif, } /* skip if DISCONNECT_IND already sent */ - if (!ap->connected) + if (!bcs->apconnstate) return; /* check for active logical connection */ - if (ap->connected >= APCONN_ACTIVE) { + if (bcs->apconnstate >= APCONN_ACTIVE) { /* * emit DISCONNECT_B3_IND with cause 0x3301 * use separate cmsg structure, as the content of iif->acmsg @@ -1776,6 +1894,7 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif, { struct cardstate *cs = iif->ctr.driverdata; _cmsg *cmsg = &iif->acmsg; + struct bc_state *bcs; int channel; /* decode message */ @@ -1791,17 +1910,17 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif, send_conf(iif, ap, skb, CapiIllContrPlciNcci); return; } + bcs = &cs->bcs[channel-1]; /* reject if logical connection not active */ - if (ap->connected < APCONN_ACTIVE) { + if (bcs->apconnstate < APCONN_ACTIVE) { send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState); return; } /* trigger hangup, causing eventual DISCONNECT_B3_IND */ - if (!gigaset_add_event(cs, &cs->bcs[channel-1].at_state, - EV_HUP, NULL, 0, NULL)) { + if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) { send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); return; } @@ -1822,6 +1941,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, struct sk_buff *skb) { struct cardstate *cs = iif->ctr.driverdata; + struct bc_state *bcs; int channel = CAPIMSG_PLCI_PART(skb->data); u16 ncci = CAPIMSG_NCCI_PART(skb->data); u16 msglen = CAPIMSG_LEN(skb->data); @@ -1844,6 +1964,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, send_conf(iif, ap, skb, CapiIllContrPlciNcci); return; } + bcs = &cs->bcs[channel-1]; if (msglen != CAPI_DATA_B3_REQ_LEN && msglen != CAPI_DATA_B3_REQ_LEN64) dev_notice(cs->dev, "%s: unexpected length %d\n", "DATA_B3_REQ", msglen); @@ -1863,7 +1984,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, } /* reject if logical connection not active */ - if (ap->connected < APCONN_ACTIVE) { + if (bcs->apconnstate < APCONN_ACTIVE) { send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState); return; } @@ -1874,7 +1995,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, skb_pull(skb, msglen); /* pass to device-specific module */ - if (cs->ops->send_skb(&cs->bcs[channel-1], skb) < 0) { + if (cs->ops->send_skb(bcs, skb) < 0) { send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); return; } diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 9778fabbc48..5d4befb8105 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -649,6 +649,10 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, for (i = 0; i < AT_NUM; ++i) bcs->commands[i] = NULL; + spin_lock_init(&bcs->aplock); + bcs->ap = NULL; + bcs->apconnstate = 0; + gig_dbg(DEBUG_INIT, " setting up bcs[%d]->hw", channel); if (cs->ops->initbcshw(bcs)) return bcs; diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index c4e6c26897e..8738b0821fc 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -403,7 +403,9 @@ struct bc_state { struct bas_bc_state *bas; /* usb hardware driver (base) */ } hw; - void *ap; /* LL application structure */ + void *ap; /* associated LL application */ + int apconnstate; /* LL application connection state */ + spinlock_t aplock; }; struct cardstate { -- cgit v1.2.3-70-g09d2 From cc413d9097dfc6237f37dcaf52346db1061a6119 Mon Sep 17 00:00:00 2001 From: Michal Schmidt Date: Thu, 24 Jun 2010 04:13:44 +0000 Subject: vxge: fix memory leak in vxge_alloc_msix() error path When pci_enable_msix() returned ret<0, entries and vxge_entries were leaked. While at it, use the centralized exit idiom in the function. Signed-off-by: Michal Schmidt Acked-by: Ram Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-main.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index b504bd56136..d14e207de1d 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -2262,7 +2262,8 @@ start: vxge_debug_init(VXGE_ERR, "%s: memory allocation failed", VXGE_DRIVER_NAME); - return -ENOMEM; + ret = -ENOMEM; + goto alloc_entries_failed; } vdev->vxge_entries = @@ -2271,8 +2272,8 @@ start: if (!vdev->vxge_entries) { vxge_debug_init(VXGE_ERR, "%s: memory allocation failed", VXGE_DRIVER_NAME); - kfree(vdev->entries); - return -ENOMEM; + ret = -ENOMEM; + goto alloc_vxge_entries_failed; } for (i = 0, j = 0; i < vdev->no_of_vpath; i++) { @@ -2303,22 +2304,32 @@ start: vxge_debug_init(VXGE_ERR, "%s: MSI-X enable failed for %d vectors, ret: %d", VXGE_DRIVER_NAME, vdev->intr_cnt, ret); + if ((max_config_vpath != VXGE_USE_DEFAULT) || (ret < 3)) { + ret = -ENODEV; + goto enable_msix_failed; + } + kfree(vdev->entries); kfree(vdev->vxge_entries); vdev->entries = NULL; vdev->vxge_entries = NULL; - - if ((max_config_vpath != VXGE_USE_DEFAULT) || (ret < 3)) - return -ENODEV; /* Try with less no of vector by reducing no of vpaths count */ temp = (ret - 1)/2; vxge_close_vpaths(vdev, temp); vdev->no_of_vpath = temp; goto start; - } else if (ret < 0) - return -ENODEV; - + } else if (ret < 0) { + ret = -ENODEV; + goto enable_msix_failed; + } return 0; + +enable_msix_failed: + kfree(vdev->vxge_entries); +alloc_vxge_entries_failed: + kfree(vdev->entries); +alloc_entries_failed: + return ret; } static int vxge_enable_msix(struct vxgedev *vdev) -- cgit v1.2.3-70-g09d2 From d41de3c10047d5f0b661593a8f4610a19f87621f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 22 Jun 2010 01:41:36 +0000 Subject: ISDN: hysdn, fix potential NULL dereference Stanse found that lp is dereferenced earlier than checked for being NULL in hysdn_rx_netpkt. Move the initialization below the test. Signed-off-by: Jiri Slaby Cc: Karsten Keil Cc: "David S. Miller" Cc: Stephen Hemminger Cc: Patrick McHardy Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller --- drivers/isdn/hysdn/hysdn_net.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c index 72eb92647c1..feec8d89d71 100644 --- a/drivers/isdn/hysdn/hysdn_net.c +++ b/drivers/isdn/hysdn/hysdn_net.c @@ -187,12 +187,13 @@ void hysdn_rx_netpkt(hysdn_card * card, unsigned char *buf, unsigned short len) { struct net_local *lp = card->netif; - struct net_device *dev = lp->dev; + struct net_device *dev; struct sk_buff *skb; if (!lp) return; /* non existing device */ + dev = lp->dev; dev->stats.rx_bytes += len; skb = dev_alloc_skb(len); -- cgit v1.2.3-70-g09d2 From e2f5b04563786d4b7d7648868de7e941a0649372 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 22 Jun 2010 02:38:13 +0000 Subject: phylib: Add autoload support for the LXT973 phy. Commit e13647c1 (phylib: Add support for the LXT973 phy.) added a new ID but neglected to also add it to the MODULE_DEVICE_TABLE. Signed-off-by: David Woodhouse Signed-off-by: David S. Miller --- drivers/net/phy/lxt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c index dbd00345373..29c39ff85de 100644 --- a/drivers/net/phy/lxt.c +++ b/drivers/net/phy/lxt.c @@ -226,6 +226,7 @@ module_exit(lxt_exit); static struct mdio_device_id lxt_tbl[] = { { 0x78100000, 0xfffffff0 }, { 0x001378e0, 0xfffffff0 }, + { 0x00137a10, 0xfffffff0 }, { } }; -- cgit v1.2.3-70-g09d2