From 6510b8917948283005a125c8337d3312a8a0561c Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 26 Feb 2010 15:10:28 +0100 Subject: airo: return from set_wep_key() when key length is zero Even if keylen == 0 is a bug and should not really happen, better avoid possibility of passing bad value to firmware. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 698d5672a07..dc5018a6d9e 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -5255,7 +5255,8 @@ static int set_wep_key(struct airo_info *ai, u16 index, const char *key, WepKeyRid wkr; int rc; - WARN_ON(keylen == 0); + if (WARN_ON(keylen == 0)) + return -1; memset(&wkr, 0, sizeof(wkr)); wkr.len = cpu_to_le16(sizeof(wkr)); -- cgit v1.2.3 From 86baf712295a00d664da8566186b67041c89b15b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 27 Feb 2010 09:12:34 +0300 Subject: zd1211rw: fix potential array underflow The first chunk fixes a debugging assert to print a warning about array underflows. The second chunk corrects a potential array underflow. I also removed an assert in the second chunk because it can no longer happen. Signed-off-by: Dan Carpenter Acked-by: Benoit Papillault Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_mac.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 2d555cc3050..e24099613d9 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -350,7 +350,7 @@ static void zd_mac_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, first_idx = info->status.rates[0].idx; ZD_ASSERT(0<=first_idx && first_idxcount); + ZD_ASSERT(1 <= retry && retry <= retries->count); info->status.rates[0].idx = retries->rate[0]; info->status.rates[0].count = 1; // (retry > 1 ? 2 : 1); @@ -360,7 +360,7 @@ static void zd_mac_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, info->status.rates[i].count = 1; // ((i==retry-1) && success ? 1:2); } for (; istatus.rates[i].idx = retries->rate[retry-1]; + info->status.rates[i].idx = retries->rate[retry - 1]; info->status.rates[i].count = 1; // (success ? 1:2); } if (istatus.rates[0].idx; ZD_ASSERT(0<=first_idx && first_idx retries->count) { + if (retry <= 0 || retry > retries->count) continue; - } - ZD_ASSERT(0<=retry && retry<=retries->count); - final_idx = retries->rate[retry-1]; + final_idx = retries->rate[retry - 1]; final_rate = zd_rates[final_idx].hw_value; if (final_rate != tx_status->rate) { -- cgit v1.2.3 From a9f042cbe5284f34ccff15f3084477e11b39b17b Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Sun, 28 Feb 2010 00:56:24 +0800 Subject: ath9k: fix lockdep warning when unloading module Since txq->axq_lock may be hold in softirq context, it must be acquired with spin_lock_bh() instead of spin_lock() if softieq is enabled. The patch fixes the lockdep warning below when unloading ath9k modules. ================================= [ INFO: inconsistent lock state ] 2.6.33-wl #12 --------------------------------- inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage. rmmod/3642 [HC0[0]:SC0[0]:HE1:SE1] takes: (&(&txq->axq_lock)->rlock){+.?...}, at: [] ath_tx_node_cleanup+0x62/0x180 [ath9k] {IN-SOFTIRQ-W} state was registered at: [] __lock_acquire+0x2f6/0xd35 [] lock_acquire+0xcd/0xf1 [] _raw_spin_lock_bh+0x3b/0x6e [] spin_lock_bh+0xe/0x10 [ath9k] [] ath_tx_tasklet+0xcd/0x391 [ath9k] [] ath9k_tasklet+0x70/0xc8 [ath9k] [] tasklet_action+0x8c/0xf4 [] __do_softirq+0xf8/0x1cd [] call_softirq+0x1c/0x30 [] do_softirq+0x4b/0xa3 [] irq_exit+0x4a/0x8c [] do_IRQ+0xac/0xc3 [] ret_from_intr+0x0/0x16 [] cpuidle_idle_call+0x9e/0xf8 [] cpu_idle+0x62/0x9d [] rest_init+0x7e/0x80 [] start_kernel+0x3e8/0x3f3 [] x86_64_start_reservations+0xa7/0xab [] x86_64_start_kernel+0xf8/0x107 irq event stamp: 42037 hardirqs last enabled at (42037): [] _raw_spin_unlock_irqrestore+0x47/0x56 hardirqs last disabled at (42036): [] _raw_spin_lock_irqsave+0x2b/0x88 softirqs last enabled at (42000): [] spin_unlock_bh+0xe/0x10 [ath9k] softirqs last disabled at (41998): [] _raw_spin_lock_bh+0x18/0x6e other info that might help us debug this: 4 locks held by rmmod/3642: #0: (rtnl_mutex){+.+.+.}, at: [] rtnl_lock+0x17/0x19 #1: (&wdev->mtx){+.+.+.}, at: [] cfg80211_netdev_notifier_call+0x28d/0x46d [cfg80211] #2: (&ifmgd->mtx){+.+.+.}, at: [] ieee80211_mgd_deauth+0x3f/0x17e [mac80211] #3: (&local->sta_mtx){+.+.+.}, at: [] sta_info_destroy_addr+0x2b/0x5e [mac80211] stack backtrace: Pid: 3642, comm: rmmod Not tainted 2.6.33-wl #12 Call Trace: [] valid_state+0x178/0x18b [] ? save_stack_trace+0x2f/0x4c [] ? check_usage_backwards+0x0/0x88 [] mark_lock+0x113/0x230 [] __lock_acquire+0x36a/0xd35 [] ? native_sched_clock+0x2d/0x5f [] ? ath_tx_node_cleanup+0x62/0x180 [ath9k] [] lock_acquire+0xcd/0xf1 [] ? ath_tx_node_cleanup+0x62/0x180 [ath9k] [] ? trace_hardirqs_off+0xd/0xf [] _raw_spin_lock+0x36/0x69 [] ? ath_tx_node_cleanup+0x62/0x180 [ath9k] [] ath_tx_node_cleanup+0x62/0x180 [ath9k] [] ? trace_hardirqs_on+0xd/0xf [] ath9k_sta_remove+0x22/0x26 [ath9k] [] __sta_info_destroy+0x1ad/0x38c [mac80211] [] sta_info_destroy_addr+0x3e/0x5e [mac80211] [] ieee80211_set_disassoc+0x175/0x180 [mac80211] [] ieee80211_mgd_deauth+0x58/0x17e [mac80211] [] ? __mutex_lock_common+0x37f/0x3a4 [] ? cfg80211_netdev_notifier_call+0x28d/0x46d [cfg80211] [] ieee80211_deauth+0x1e/0x20 [mac80211] [] __cfg80211_mlme_deauth+0x130/0x13f [cfg80211] [] ? cfg80211_netdev_notifier_call+0x28d/0x46d [cfg80211] [] ? trace_hardirqs_off+0xd/0xf [] __cfg80211_disconnect+0x111/0x189 [cfg80211] [] cfg80211_netdev_notifier_call+0x2ce/0x46d [cfg80211] [] notifier_call_chain+0x37/0x63 [] raw_notifier_call_chain+0x14/0x16 [] call_netdevice_notifiers+0x1b/0x1d [] dev_close+0x6a/0xa6 [] rollback_registered_many+0xb6/0x2f4 [] unregister_netdevice_many+0x1b/0x66 [] ieee80211_remove_interfaces+0xc5/0xd0 [mac80211] [] ieee80211_unregister_hw+0x47/0xe8 [mac80211] [] ath9k_deinit_device+0x7a/0x9b [ath9k] [] ath_pci_remove+0x38/0x76 [ath9k] [] pci_device_remove+0x2d/0x51 [] __device_release_driver+0x7b/0xd1 [] driver_detach+0x98/0xbe [] bus_remove_driver+0x94/0xb7 [] driver_unregister+0x6c/0x74 [] pci_unregister_driver+0x46/0xad [] ath_pci_exit+0x15/0x17 [ath9k] [] ath9k_exit+0xe/0x2f [ath9k] [] sys_delete_module+0x1c7/0x236 [] ? retint_swapgs+0x13/0x1b [] ? trace_hardirqs_on_caller+0x119/0x144 [] ? audit_syscall_entry+0x11e/0x14a [] system_call_fastpath+0x16/0x1b wlan1: deauthenticating from 00:23:cd:e1:f9:b2 by local choice (reason=3) PM: Removing info for No Bus:wlan1 cfg80211: Calling CRDA to update world regulatory domain PM: Removing info for No Bus:rfkill2 PM: Removing info for No Bus:phy1 ath9k 0000:16:00.0: PCI INT A disabled Signed-off-by: Ming Lei Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 47294f90bbe..b2c8207f7bc 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2258,7 +2258,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) if (ATH_TXQ_SETUP(sc, i)) { txq = &sc->tx.txq[i]; - spin_lock(&txq->axq_lock); + spin_lock_bh(&txq->axq_lock); list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) { @@ -2279,7 +2279,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) } } - spin_unlock(&txq->axq_lock); + spin_unlock_bh(&txq->axq_lock); } } } -- cgit v1.2.3 From 51b2853fd91a3c8fd9f3adc1549569d2c1dc2a2d Mon Sep 17 00:00:00 2001 From: Bryan Polk Date: Mon, 1 Mar 2010 12:23:28 -0500 Subject: rt2x00: Add USB ID for CEIVA adapter to rt73usb This adds support for CEIVA USB wireless adapters to the rt73usb driver. Signed-off-by: Bryan Polk Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt73usb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index f39a8ed1784..47f3e4a26d7 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2352,6 +2352,8 @@ static struct usb_device_id rt73usb_device_table[] = { { USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x0411, 0x0116), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x0411, 0x0119), USB_DEVICE_DATA(&rt73usb_ops) }, + /* CEIVA */ + { USB_DEVICE(0x178d, 0x02be), USB_DEVICE_DATA(&rt73usb_ops) }, /* CNet */ { USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x1371, 0x9032), USB_DEVICE_DATA(&rt73usb_ops) }, -- cgit v1.2.3 From 6e93d7195e75741e9ebe23ca5591977d0b39ecc0 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Tue, 2 Mar 2010 16:34:49 +0100 Subject: rt2x00: fix rt2800pci compilation with SoC Compiling rt2800pci with CONFIG_RT2800PCI_SOC fails with "... rt2880pci.c: error: incompatible type for argument 2 of 'rt2x00soc_probe'". Fix this by using &rt2800pci_ops instead of rt2800pci_ops. Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index aca8c124f43..91cce2d0f6d 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1225,7 +1225,7 @@ MODULE_LICENSE("GPL"); #ifdef CONFIG_RT2800PCI_SOC static int rt2800soc_probe(struct platform_device *pdev) { - return rt2x00soc_probe(pdev, rt2800pci_ops); + return rt2x00soc_probe(pdev, &rt2800pci_ops); } static struct platform_driver rt2800soc_driver = { -- cgit v1.2.3 From 535765179fd4e8af26b69d2240d7ec33702a370a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 23 Dec 2009 13:15:30 +0100 Subject: ar9170: load firmware asynchronously This converts ar9170 to load firmware asynchronously out of ->probe() and only register with mac80211 when all firmware has been loaded successfully. If, on the other hand, any firmware fails to load, it will now unbind from the device. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/ar9170.h | 1 + drivers/net/wireless/ath/ar9170/main.c | 10 +- drivers/net/wireless/ath/ar9170/usb.c | 170 +++++++++++++++++++------------ 3 files changed, 111 insertions(+), 70 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index 8c8ce67971e..dc662b76a1c 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -166,6 +166,7 @@ struct ar9170 { struct ath_common common; struct mutex mutex; enum ar9170_device_state state; + bool registered; unsigned long bad_hw_nagger; int (*open)(struct ar9170 *); diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 8a964f13036..f4650fcdebc 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -2701,7 +2701,8 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev) dev_info(pdev, "Atheros AR9170 is registered as '%s'\n", wiphy_name(ar->hw->wiphy)); - return err; + ar->registered = true; + return 0; err_unreg: ieee80211_unregister_hw(ar->hw); @@ -2712,11 +2713,14 @@ err_out: void ar9170_unregister(struct ar9170 *ar) { + if (ar->registered) { #ifdef CONFIG_AR9170_LEDS - ar9170_unregister_leds(ar); + ar9170_unregister_leds(ar); #endif /* CONFIG_AR9170_LEDS */ - kfree_skb(ar->rx_failover); ieee80211_unregister_hw(ar->hw); + } + + kfree_skb(ar->rx_failover); mutex_destroy(&ar->mutex); } diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index 0f361186b78..4e30197afff 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -582,43 +582,6 @@ static int ar9170_usb_upload(struct ar9170_usb *aru, const void *data, return 0; } -static int ar9170_usb_request_firmware(struct ar9170_usb *aru) -{ - int err = 0; - - err = request_firmware(&aru->firmware, "ar9170.fw", - &aru->udev->dev); - if (!err) { - aru->init_values = NULL; - return 0; - } - - if (aru->req_one_stage_fw) { - dev_err(&aru->udev->dev, "ar9170.fw firmware file " - "not found and is required for this device\n"); - return -EINVAL; - } - - dev_err(&aru->udev->dev, "ar9170.fw firmware file " - "not found, trying old firmware...\n"); - - err = request_firmware(&aru->init_values, "ar9170-1.fw", - &aru->udev->dev); - if (err) { - dev_err(&aru->udev->dev, "file with init values not found.\n"); - return err; - } - - err = request_firmware(&aru->firmware, "ar9170-2.fw", &aru->udev->dev); - if (err) { - release_firmware(aru->init_values); - dev_err(&aru->udev->dev, "firmware file not found.\n"); - return err; - } - - return err; -} - static int ar9170_usb_reset(struct ar9170_usb *aru) { int ret, lock = (aru->intf->condition != USB_INTERFACE_BINDING); @@ -757,6 +720,103 @@ err_out: return err; } +static void ar9170_usb_firmware_failed(struct ar9170_usb *aru) +{ + struct device *parent = aru->udev->dev.parent; + + /* unbind anything failed */ + if (parent) + down(&parent->sem); + device_release_driver(&aru->udev->dev); + if (parent) + up(&parent->sem); +} + +static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context) +{ + struct ar9170_usb *aru = context; + int err; + + aru->firmware = fw; + + if (!fw) { + dev_err(&aru->udev->dev, "firmware file not found.\n"); + goto err_freefw; + } + + err = ar9170_usb_init_device(aru); + if (err) + goto err_freefw; + + err = ar9170_usb_open(&aru->common); + if (err) + goto err_unrx; + + err = ar9170_register(&aru->common, &aru->udev->dev); + + ar9170_usb_stop(&aru->common); + if (err) + goto err_unrx; + + return; + + err_unrx: + ar9170_usb_cancel_urbs(aru); + + err_freefw: + ar9170_usb_firmware_failed(aru); +} + +static void ar9170_usb_firmware_inits(const struct firmware *fw, + void *context) +{ + struct ar9170_usb *aru = context; + int err; + + if (!fw) { + dev_err(&aru->udev->dev, "file with init values not found.\n"); + ar9170_usb_firmware_failed(aru); + return; + } + + aru->init_values = fw; + + /* ok so we have the init values -- get code for two-stage */ + + err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-2.fw", + &aru->udev->dev, GFP_KERNEL, aru, + ar9170_usb_firmware_finish); + if (err) + ar9170_usb_firmware_failed(aru); +} + +static void ar9170_usb_firmware_step2(const struct firmware *fw, void *context) +{ + struct ar9170_usb *aru = context; + int err; + + if (fw) { + ar9170_usb_firmware_finish(fw, context); + return; + } + + if (aru->req_one_stage_fw) { + dev_err(&aru->udev->dev, "ar9170.fw firmware file " + "not found and is required for this device\n"); + ar9170_usb_firmware_failed(aru); + return; + } + + dev_err(&aru->udev->dev, "ar9170.fw firmware file " + "not found, trying old firmware...\n"); + + err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-1.fw", + &aru->udev->dev, GFP_KERNEL, aru, + ar9170_usb_firmware_inits); + if (err) + ar9170_usb_firmware_failed(aru); +} + static bool ar9170_requires_one_stage(const struct usb_device_id *id) { if (!id->driver_info) @@ -814,33 +874,9 @@ static int ar9170_usb_probe(struct usb_interface *intf, if (err) goto err_freehw; - err = ar9170_usb_request_firmware(aru); - if (err) - goto err_freehw; - - err = ar9170_usb_init_device(aru); - if (err) - goto err_freefw; - - err = ar9170_usb_open(ar); - if (err) - goto err_unrx; - - err = ar9170_register(ar, &udev->dev); - - ar9170_usb_stop(ar); - if (err) - goto err_unrx; - - return 0; - -err_unrx: - ar9170_usb_cancel_urbs(aru); - -err_freefw: - release_firmware(aru->init_values); - release_firmware(aru->firmware); - + return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw", + &aru->udev->dev, GFP_KERNEL, aru, + ar9170_usb_firmware_step2); err_freehw: usb_set_intfdata(intf, NULL); usb_put_dev(udev); @@ -860,12 +896,12 @@ static void ar9170_usb_disconnect(struct usb_interface *intf) ar9170_unregister(&aru->common); ar9170_usb_cancel_urbs(aru); - release_firmware(aru->init_values); - release_firmware(aru->firmware); - usb_put_dev(aru->udev); usb_set_intfdata(intf, NULL); ieee80211_free_hw(aru->common.hw); + + release_firmware(aru->init_values); + release_firmware(aru->firmware); } #ifdef CONFIG_PM -- cgit v1.2.3 From b08dfd0435333818a03b38867c556ebcbb3abc02 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 29 Jan 2010 11:54:56 -0800 Subject: iwlwifi: load firmware asynchronously before mac80211 registration At the wireless summit in Portland we discussed a way of loading firmware asynchronously from ->probe() before registration to mac80211, in order to register with the wireless subsystems with complete information in cases where firmware is required to know parameters. This is not yet the case in iwlwifi, but for some new features we're working on it will be the case since those will only be supported by new firmware images. Hence, to start with, convert iwlwifi to load firmware asynchronously from probe, unbinding the device when firmware loading fails, and only registering with the wireless subsystems after firmware has been loaded successfully. Future patches will hook into this to register the new firmware capabilities, depending on the firmware API version. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 157 +++++++++++++++++---------------- drivers/net/wireless/iwlwifi/iwl-dev.h | 2 + 2 files changed, 81 insertions(+), 78 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6aeb82b6992..47b02147796 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1463,59 +1463,66 @@ static void iwl_nic_start(struct iwl_priv *priv) } +static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); +static int iwl_mac_setup_register(struct iwl_priv *priv); + +static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) +{ + const char *name_pre = priv->cfg->fw_name_pre; + + if (first) + priv->fw_index = priv->cfg->ucode_api_max; + else + priv->fw_index--; + + if (priv->fw_index < priv->cfg->ucode_api_min) { + IWL_ERR(priv, "no suitable firmware found!\n"); + return -ENOENT; + } + + sprintf(priv->firmware_name, "%s%d%s", + name_pre, priv->fw_index, ".ucode"); + + IWL_DEBUG_INFO(priv, "attempting to load firmware '%s'\n", + priv->firmware_name); + + return request_firmware_nowait(THIS_MODULE, 1, priv->firmware_name, + &priv->pci_dev->dev, GFP_KERNEL, priv, + iwl_ucode_callback); +} + /** - * iwl_read_ucode - Read uCode images from disk file. + * iwl_ucode_callback - callback when firmware was loaded * - * Copy into buffers for card to fetch via bus-mastering + * If loaded successfully, copies the firmware into buffers + * for the card to fetch (via DMA). */ -static int iwl_read_ucode(struct iwl_priv *priv) +static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) { + struct iwl_priv *priv = context; struct iwl_ucode_header *ucode; - int ret = -EINVAL, index; - const struct firmware *ucode_raw; - const char *name_pre = priv->cfg->fw_name_pre; const unsigned int api_max = priv->cfg->ucode_api_max; const unsigned int api_min = priv->cfg->ucode_api_min; - char buf[25]; u8 *src; size_t len; u32 api_ver, build; u32 inst_size, data_size, init_size, init_data_size, boot_size; + int err; u16 eeprom_ver; - /* Ask kernel firmware_class module to get the boot firmware off disk. - * request_firmware() is synchronous, file is in memory on return. */ - for (index = api_max; index >= api_min; index--) { - sprintf(buf, "%s%d%s", name_pre, index, ".ucode"); - ret = request_firmware(&ucode_raw, buf, &priv->pci_dev->dev); - if (ret < 0) { - IWL_ERR(priv, "%s firmware file req failed: %d\n", - buf, ret); - if (ret == -ENOENT) - continue; - else - goto error; - } else { - if (index < api_max) - IWL_ERR(priv, "Loaded firmware %s, " - "which is deprecated. " - "Please use API v%u instead.\n", - buf, api_max); - - IWL_DEBUG_INFO(priv, "Got firmware '%s' file (%zd bytes) from disk\n", - buf, ucode_raw->size); - break; - } + if (!ucode_raw) { + IWL_ERR(priv, "request for firmware file '%s' failed.\n", + priv->firmware_name); + goto try_again; } - if (ret < 0) - goto error; + IWL_DEBUG_INFO(priv, "Loaded firmware file '%s' (%zd bytes).\n", + priv->firmware_name, ucode_raw->size); /* Make sure that we got at least the v1 header! */ if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) { IWL_ERR(priv, "File size way too small!\n"); - ret = -EINVAL; - goto err_release; + goto try_again; } /* Data from ucode file: header followed by uCode images */ @@ -1540,10 +1547,9 @@ static int iwl_read_ucode(struct iwl_priv *priv) IWL_ERR(priv, "Driver unable to support your firmware API. " "Driver supports v%u, firmware is v%u.\n", api_max, api_ver); - priv->ucode_ver = 0; - ret = -EINVAL; - goto err_release; + goto try_again; } + if (api_ver != api_max) IWL_ERR(priv, "Firmware has old API version. Expected v%u, " "got v%u. New firmware can be obtained " @@ -1585,6 +1591,12 @@ static int iwl_read_ucode(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %u\n", boot_size); + /* + * For any of the failures below (before allocating pci memory) + * we will try to load a version with a smaller API -- maybe the + * user just got a corrupted version of the latest API. + */ + /* Verify size of file vs. image size info in file's header */ if (ucode_raw->size != priv->cfg->ops->ucode->get_header_size(api_ver) + @@ -1594,41 +1606,35 @@ static int iwl_read_ucode(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "uCode file size %d does not match expected size\n", (int)ucode_raw->size); - ret = -EINVAL; - goto err_release; + goto try_again; } /* Verify that uCode images will fit in card's SRAM */ if (inst_size > priv->hw_params.max_inst_size) { IWL_DEBUG_INFO(priv, "uCode instr len %d too large to fit in\n", inst_size); - ret = -EINVAL; - goto err_release; + goto try_again; } if (data_size > priv->hw_params.max_data_size) { IWL_DEBUG_INFO(priv, "uCode data len %d too large to fit in\n", data_size); - ret = -EINVAL; - goto err_release; + goto try_again; } if (init_size > priv->hw_params.max_inst_size) { IWL_INFO(priv, "uCode init instr len %d too large to fit in\n", init_size); - ret = -EINVAL; - goto err_release; + goto try_again; } if (init_data_size > priv->hw_params.max_data_size) { IWL_INFO(priv, "uCode init data len %d too large to fit in\n", init_data_size); - ret = -EINVAL; - goto err_release; + goto try_again; } if (boot_size > priv->hw_params.max_bsm_size) { IWL_INFO(priv, "uCode boot instr len %d too large to fit in\n", boot_size); - ret = -EINVAL; - goto err_release; + goto try_again; } /* Allocate ucode buffers for card's bus-master loading ... */ @@ -1712,20 +1718,36 @@ static int iwl_read_ucode(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len); memcpy(priv->ucode_boot.v_addr, src, len); + /************************************************** + * This is still part of probe() in a sense... + * + * 9. Setup and register with mac80211 and debugfs + **************************************************/ + err = iwl_mac_setup_register(priv); + if (err) + goto out_unbind; + + err = iwl_dbgfs_register(priv, DRV_NAME); + if (err) + IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); + /* We have our copies now, allow OS release its copies */ release_firmware(ucode_raw); - return 0; + return; + + try_again: + /* try next, if any */ + if (iwl_request_firmware(priv, false)) + goto out_unbind; + release_firmware(ucode_raw); + return; err_pci_alloc: IWL_ERR(priv, "failed to allocate pci memory\n"); - ret = -ENOMEM; iwl_dealloc_ucode_pci(priv); - - err_release: + out_unbind: + device_release_driver(&priv->pci_dev->dev); release_firmware(ucode_raw); - - error: - return ret; } static const char *desc_lookup_text[] = { @@ -2667,21 +2689,7 @@ static int iwl_mac_start(struct ieee80211_hw *hw) /* we should be verifying the device is ready to be opened */ mutex_lock(&priv->mutex); - - /* fetch ucode file from disk, alloc and copy to bus-master buffers ... - * ucode filename and max sizes are card-specific. */ - - if (!priv->ucode_code.len) { - ret = iwl_read_ucode(priv); - if (ret) { - IWL_ERR(priv, "Could not read microcode: %d\n", ret); - mutex_unlock(&priv->mutex); - return ret; - } - } - ret = __iwl_up(priv); - mutex_unlock(&priv->mutex); if (ret) @@ -3654,17 +3662,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_power_initialize(priv); iwl_tt_initialize(priv); - /************************************************** - * 9. Setup and register with mac80211 and debugfs - **************************************************/ - err = iwl_mac_setup_register(priv); + err = iwl_request_firmware(priv, true); if (err) goto out_remove_sysfs; - err = iwl_dbgfs_register(priv, DRV_NAME); - if (err) - IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); - return 0; out_remove_sysfs: diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index ab891b95804..6054c5fba0c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1132,6 +1132,7 @@ struct iwl_priv { u8 rev_id; /* uCode images, save to reload in case of failure */ + int fw_index; /* firmware we're trying to load */ u32 ucode_ver; /* version of ucode, copy of iwl_ucode.ver */ struct fw_desc ucode_code; /* runtime inst */ @@ -1142,6 +1143,7 @@ struct iwl_priv { struct fw_desc ucode_boot; /* bootstrap inst */ enum ucode_type ucode_type; u8 ucode_write_complete; /* the image write is complete */ + char firmware_name[25]; struct iwl_rxon_time_cmd rxon_timing; -- cgit v1.2.3 From 48a29516e8b0b8cd59f5afec90a14f49dd9cf967 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 2 Mar 2010 22:46:10 +0000 Subject: cpmac: use after free The original code dereferenced "cpmac_mii" after calling "mdiobus_free(cpmac_mii);" Signed-off-by: Dan Carpenter Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/cpmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index b85c81f60d1..9d489421535 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -1290,8 +1290,8 @@ void __devexit cpmac_exit(void) { platform_driver_unregister(&cpmac_driver); mdiobus_unregister(cpmac_mii); - mdiobus_free(cpmac_mii); iounmap(cpmac_mii->priv); + mdiobus_free(cpmac_mii); } module_init(cpmac_init); -- cgit v1.2.3 From 9fe969345b10931319b3f1e7034fbdeb786de234 Mon Sep 17 00:00:00 2001 From: Sarveshwar Bandi Date: Tue, 2 Mar 2010 22:37:28 +0000 Subject: be2net: download NCSI section during firmware update Adding code to update NCSI section while updating firmware on the controller. Signed-off-by: Sarveshwar Bandi Signed-off-by: David S. Miller --- drivers/net/benet/be_hw.h | 5 +++-- drivers/net/benet/be_main.c | 14 +++++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h index 5ffb149181a..2d4a4b82763 100644 --- a/drivers/net/benet/be_hw.h +++ b/drivers/net/benet/be_hw.h @@ -114,8 +114,7 @@ #define IMG_TYPE_ISCSI_BACKUP 9 #define IMG_TYPE_FCOE_FW_ACTIVE 10 #define IMG_TYPE_FCOE_FW_BACKUP 11 -#define IMG_TYPE_NCSI_BITFILE 13 -#define IMG_TYPE_NCSI_8051 14 +#define IMG_TYPE_NCSI_FW 13 #define FLASHROM_OPER_FLASH 1 #define FLASHROM_OPER_SAVE 2 @@ -127,6 +126,7 @@ #define FLASH_IMAGE_MAX_SIZE_g3 (2097152) /* Max fw image size */ #define FLASH_BIOS_IMAGE_MAX_SIZE_g3 (524288) /* Max OPTION ROM img sz */ #define FLASH_REDBOOT_IMAGE_MAX_SIZE_g3 (1048576) /* Max Redboot image sz */ +#define FLASH_NCSI_IMAGE_MAX_SIZE_g3 (262144) /* Max NSCI image sz */ #define FLASH_NCSI_MAGIC (0x16032009) #define FLASH_NCSI_DISABLED (0) @@ -144,6 +144,7 @@ #define FLASH_FCoE_BIOS_START_g2 (524288) #define FLASH_REDBOOT_START_g2 (0) +#define FLASH_NCSI_START_g3 (15990784) #define FLASH_iSCSI_PRIMARY_IMAGE_START_g3 (2097152) #define FLASH_iSCSI_BACKUP_IMAGE_START_g3 (4194304) #define FLASH_FCoE_PRIMARY_IMAGE_START_g3 (6291456) diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index a703ed8e24f..22f787f2a30 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1880,8 +1880,9 @@ static int be_flash_data(struct be_adapter *adapter, const u8 *p = fw->data; struct be_cmd_write_flashrom *req = flash_cmd->va; struct flash_comp *pflashcomp; + int num_comp; - struct flash_comp gen3_flash_types[8] = { + struct flash_comp gen3_flash_types[9] = { { FLASH_iSCSI_PRIMARY_IMAGE_START_g3, IMG_TYPE_ISCSI_ACTIVE, FLASH_IMAGE_MAX_SIZE_g3}, { FLASH_REDBOOT_START_g3, IMG_TYPE_REDBOOT, @@ -1897,7 +1898,9 @@ static int be_flash_data(struct be_adapter *adapter, { FLASH_FCoE_PRIMARY_IMAGE_START_g3, IMG_TYPE_FCOE_FW_ACTIVE, FLASH_IMAGE_MAX_SIZE_g3}, { FLASH_FCoE_BACKUP_IMAGE_START_g3, IMG_TYPE_FCOE_FW_BACKUP, - FLASH_IMAGE_MAX_SIZE_g3} + FLASH_IMAGE_MAX_SIZE_g3}, + { FLASH_NCSI_START_g3, IMG_TYPE_NCSI_FW, + FLASH_NCSI_IMAGE_MAX_SIZE_g3} }; struct flash_comp gen2_flash_types[8] = { { FLASH_iSCSI_PRIMARY_IMAGE_START_g2, IMG_TYPE_ISCSI_ACTIVE, @@ -1921,11 +1924,16 @@ static int be_flash_data(struct be_adapter *adapter, if (adapter->generation == BE_GEN3) { pflashcomp = gen3_flash_types; filehdr_size = sizeof(struct flash_file_hdr_g3); + num_comp = 9; } else { pflashcomp = gen2_flash_types; filehdr_size = sizeof(struct flash_file_hdr_g2); + num_comp = 8; } - for (i = 0; i < 8; i++) { + for (i = 0; i < num_comp; i++) { + if ((pflashcomp[i].optype == IMG_TYPE_NCSI_FW) && + memcmp(adapter->fw_ver, "3.102.148.0", 11) < 0) + continue; if ((pflashcomp[i].optype == IMG_TYPE_REDBOOT) && (!be_flash_redboot(adapter, fw->data, pflashcomp[i].offset, pflashcomp[i].size, -- cgit v1.2.3 From bf829370a8d664d87a61697c8a0d6d780c336aa4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 2 Mar 2010 22:22:41 +0000 Subject: cassini: fix off by one There are only 6 link_modes. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/cassini.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 7cbcfb0ade1..9bd155e4111 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -5072,7 +5072,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev, INIT_WORK(&cp->reset_task, cas_reset_task); /* Default link parameters */ - if (link_mode >= 0 && link_mode <= 6) + if (link_mode >= 0 && link_mode < 6) cp->link_cntl = link_modes[link_mode]; else cp->link_cntl = BMCR_ANENABLE; -- cgit v1.2.3 From 4d27b87785a743fdae653d395a3a4e763269c53c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 2 Mar 2010 21:07:24 +0000 Subject: davinci_emac: off by one This off by one error was found by smatch. drivers/net/davinci_emac.c +2390 emac_dev_open(13) error: buffer overflow 'priv->mac_addr' 6 <= 6 Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/davinci_emac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 1ac9440eb3f..32960b9b02a 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -2385,7 +2385,7 @@ static int emac_dev_open(struct net_device *ndev) struct emac_priv *priv = netdev_priv(ndev); netif_carrier_off(ndev); - for (cnt = 0; cnt <= ETH_ALEN; cnt++) + for (cnt = 0; cnt < ETH_ALEN; cnt++) ndev->dev_addr[cnt] = priv->mac_addr[cnt]; /* Configuration items */ -- cgit v1.2.3 From 4fa004373133ece3d9b1c0a7e243b0e53760b165 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 1 Mar 2010 14:42:57 +0530 Subject: mac80211: Fix HT rate control configuration Handling HT configuration changes involved setting the channel with the new HT parameters and then issuing a rate_update() notification to the driver. This behavior changed after the off-channel changes. Now, the channel is not updated with the new HT params in enable_ht() - instead, it is now done when the scan work terminates. This results in the driver depending on stale information, defaulting to non-HT mode always. Fix this by passing the new channel type to the driver. Cc: stable@kernel.org Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index ac34a055c71..0e79e58cf4c 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1323,7 +1323,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta, - u32 changed) + u32 changed, enum nl80211_channel_type oper_chan_type) { struct ath_softc *sc = priv; struct ath_rate_priv *ath_rc_priv = priv_sta; @@ -1340,8 +1340,8 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) return; - if (sc->hw->conf.channel_type == NL80211_CHAN_HT40MINUS || - sc->hw->conf.channel_type == NL80211_CHAN_HT40PLUS) + if (oper_chan_type == NL80211_CHAN_HT40MINUS || + oper_chan_type == NL80211_CHAN_HT40PLUS) oper_cw40 = true; oper_sgi40 = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? -- cgit v1.2.3 From 31f66be44a657a14e0ab3536e4877c66c9ce031e Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Wed, 3 Mar 2010 17:42:55 +0100 Subject: rt2x00: Export rt2x00soc_probe from rt2x00soc Export rt2x00soc_probe from rt2x00soc as it is used in rt2800pci. Otherwise loading rt2800pci gives "rt2800pci: Unknown symbol rt2x00soc_probe". Signed-off-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00soc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.c b/drivers/net/wireless/rt2x00/rt2x00soc.c index 4efdc96010f..111c0ff5c6c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00soc.c +++ b/drivers/net/wireless/rt2x00/rt2x00soc.c @@ -112,6 +112,7 @@ exit_free_device: return retval; } +EXPORT_SYMBOL_GPL(rt2x00soc_probe); int rt2x00soc_remove(struct platform_device *pdev) { -- cgit v1.2.3 From 4c020a961a812ffae9846b917304cea504c3a733 Mon Sep 17 00:00:00 2001 From: David Dillow Date: Wed, 3 Mar 2010 16:33:10 +0000 Subject: r8169: use correct barrier between cacheable and non-cacheable memory r8169 needs certain writes to be visible to other CPUs or the NIC before touching the hardware, but was using smp_wmb() which is only required to order cacheable memory access. Switch to wmb() which is required to order both cacheable and non-cacheable memory. Noticed by Catalin Marinas and Paul Mackerras. Signed-off-by: David Dillow Signed-off-by: David S. Miller --- drivers/net/r8169.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index dfc3573c91b..9d3ebf3e975 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -4270,7 +4270,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, tp->cur_tx += frags + 1; - smp_wmb(); + wmb(); RTL_W8(TxPoll, NPQ); /* set polling bit */ @@ -4621,7 +4621,7 @@ static int rtl8169_poll(struct napi_struct *napi, int budget) * until it does. */ tp->intr_mask = 0xffff; - smp_wmb(); + wmb(); RTL_W16(IntrMask, tp->intr_event); } -- cgit v1.2.3 From 0eddba525cf4c3a4aab9feaf36b12b465290d4a7 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Wed, 3 Mar 2010 08:18:58 +0000 Subject: gianfar: Fix TX ring processing on SMP machines Starting with commit a3bc1f11e9b867a4f49505 ("gianfar: Revive SKB recycling") gianfar driver sooner or later stops transmitting any packets on SMP machines. start_xmit() prepares new skb for transmitting, generally it does three things: 1. sets up all BDs (marks them ready to send), except the first one. 2. stores skb into tx_queue->tx_skbuff so that clean_tx_ring() would cleanup it later. 3. sets up the first BD, i.e. marks it ready. Here is what clean_tx_ring() does: 1. reads skbs from tx_queue->tx_skbuff 2. checks if the *last* BD is ready. If it's still ready [to send] then it it isn't transmitted, so clean_tx_ring() returns. Otherwise it actually cleanups BDs. All is OK. Now, if there is just one BD, code flow: - start_xmit(): stores skb into tx_skbuff. Note that the first BD (which is also the last one) isn't marked as ready, yet. - clean_tx_ring(): sees that skb is not null, *and* its lstatus says that it is NOT ready (like if BD was sent), so it cleans it up (bad!) - start_xmit(): marks BD as ready [to send], but it's too late. We can fix this simply by reordering lstatus/tx_skbuff writes. Reported-by: Martyn Welch Bisected-by: Paul Gortmaker Signed-off-by: Anton Vorontsov Tested-by: Paul Gortmaker Tested-by: Martyn Welch Cc: Sandeep Gopalpet Cc: Stable [2.6.33] Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 6aa526ee909..c3f061957c0 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -2021,7 +2021,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) } /* setup the TxBD length and buffer pointer for the first BD */ - tx_queue->tx_skbuff[tx_queue->skb_curtx] = skb; txbdp_start->bufPtr = dma_map_single(&priv->ofdev->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); @@ -2053,6 +2052,10 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) txbdp_start->lstatus = lstatus; + eieio(); /* force lstatus write before tx_skbuff */ + + tx_queue->tx_skbuff[tx_queue->skb_curtx] = skb; + /* Update the current skb pointer to the next entry we will use * (wrapping if necessary) */ tx_queue->skb_curtx = (tx_queue->skb_curtx + 1) & -- cgit v1.2.3 From a6f018e324ba91d0464cca6895447c2b89e6d578 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 3 Mar 2010 09:49:47 +0000 Subject: cxgb3: fix hot plug removal crash queue restart tasklets need to be stopped after napi handlers are stopped since the latter can restart them. So stop them after stopping napi. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller --- drivers/net/cxgb3/cxgb3_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 6fd968abb07..cecdec1551d 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -1280,6 +1280,7 @@ static void cxgb_down(struct adapter *adapter) free_irq_resources(adapter); quiesce_rx(adapter); + t3_sge_stop(adapter); flush_workqueue(cxgb3_wq); /* wait for external IRQ handler */ } -- cgit v1.2.3 From 12c3400a84742f8bb0e4edc822e9ccba58781e0c Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 4 Mar 2010 03:32:16 -0800 Subject: rndis_wlan: correct multicast_list handling V3 My previous patch (655ffee284dfcf9a24ac0343f3e5ee6db85b85c5) added locking in a bad way. Because rndis_set_oid can sleep, there is need to prepare multicast addresses into local buffer under netif_addr_lock first, then call rndis_set_oid outside. This caused reorganizing of the whole function. Signed-off-by: Jiri Pirko Reported-by: Jussi Kivilinna Signed-off-by: David S. Miller --- drivers/net/wireless/rndis_wlan.c | 66 ++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 25 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 9f6d6bf06b8..2887047069f 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1496,51 +1496,67 @@ static void set_multicast_list(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct dev_mc_list *mclist; - __le32 filter; - int ret, i, size; - char *buf; + __le32 filter, basefilter; + int ret; + char *mc_addrs = NULL; + int mc_count; - filter = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST; + basefilter = filter = RNDIS_PACKET_TYPE_DIRECTED | + RNDIS_PACKET_TYPE_BROADCAST; - netif_addr_lock_bh(usbdev->net); if (usbdev->net->flags & IFF_PROMISC) { filter |= RNDIS_PACKET_TYPE_PROMISCUOUS | RNDIS_PACKET_TYPE_ALL_LOCAL; - } else if (usbdev->net->flags & IFF_ALLMULTI || - netdev_mc_count(usbdev->net) > priv->multicast_size) { + } else if (usbdev->net->flags & IFF_ALLMULTI) { + filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; + } + + if (filter != basefilter) + goto set_filter; + + /* + * mc_list should be accessed holding the lock, so copy addresses to + * local buffer first. + */ + netif_addr_lock_bh(usbdev->net); + mc_count = netdev_mc_count(usbdev->net); + if (mc_count > priv->multicast_size) { filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; - } else if (!netdev_mc_empty(usbdev->net)) { - size = min(priv->multicast_size, netdev_mc_count(usbdev->net)); - buf = kmalloc(size * ETH_ALEN, GFP_KERNEL); - if (!buf) { + } else if (mc_count) { + int i = 0; + + mc_addrs = kmalloc(mc_count * ETH_ALEN, GFP_ATOMIC); + if (!mc_addrs) { netdev_warn(usbdev->net, "couldn't alloc %d bytes of memory\n", - size * ETH_ALEN); + mc_count * ETH_ALEN); netif_addr_unlock_bh(usbdev->net); return; } - i = 0; - netdev_for_each_mc_addr(mclist, usbdev->net) { - if (i == size) - break; - memcpy(buf + i++ * ETH_ALEN, mclist->dmi_addr, ETH_ALEN); - } + netdev_for_each_mc_addr(mclist, usbdev->net) + memcpy(mc_addrs + i++ * ETH_ALEN, + mclist->dmi_addr, ETH_ALEN); + } + netif_addr_unlock_bh(usbdev->net); - ret = rndis_set_oid(usbdev, OID_802_3_MULTICAST_LIST, buf, - i * ETH_ALEN); - if (ret == 0 && i > 0) + if (filter != basefilter) + goto set_filter; + + if (mc_count) { + ret = rndis_set_oid(usbdev, OID_802_3_MULTICAST_LIST, mc_addrs, + mc_count * ETH_ALEN); + kfree(mc_addrs); + if (ret == 0) filter |= RNDIS_PACKET_TYPE_MULTICAST; else filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; netdev_dbg(usbdev->net, "OID_802_3_MULTICAST_LIST(%d, max: %d) -> %d\n", - i, priv->multicast_size, ret); - - kfree(buf); + mc_count, priv->multicast_size, ret); } - netif_addr_unlock_bh(usbdev->net); +set_filter: ret = rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &filter, sizeof(filter)); if (ret < 0) { -- cgit v1.2.3 From 4b79a1aedcb9dd6e3f27b970dcb553aefcd97254 Mon Sep 17 00:00:00 2001 From: David Brown Date: Fri, 5 Mar 2010 09:12:34 +0000 Subject: net: smc91x: Support Qualcomm MSM development boards. Signed-off-by: David Brown Signed-off-by: Daniel Walker Acked-by: Nicolas Pitre Signed-off-by: David S. Miller --- drivers/net/smc91x.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 54799544bda..a6ee883d1b0 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -330,6 +330,20 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r, #include +#elif defined(CONFIG_ARCH_MSM) + +#define SMC_CAN_USE_8BIT 0 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 0 +#define SMC_NOWAIT 1 + +#define SMC_inw(a, r) readw((a) + (r)) +#define SMC_outw(v, a, r) writew(v, (a) + (r)) +#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l) +#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) + +#define SMC_IRQ_FLAGS IRQF_TRIGGER_HIGH + #else /* -- cgit v1.2.3 From 5fe88eae26dbd24eed73eb0b681e13981fd486b3 Mon Sep 17 00:00:00 2001 From: David Dillow Date: Thu, 4 Mar 2010 04:37:16 +0000 Subject: typhoon: fix incorrect use of smp_wmb() The typhoon driver was incorrectly using smp_wmb() to order memory accesses against IO to the NIC in a few instances. Use wmb() instead, which is required to actually order between memory types. Signed-off-by: David Dillow Signed-off-by: David S. Miller --- drivers/net/typhoon.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index e3ddcb8f29d..1cf012d3e07 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -480,7 +480,7 @@ typhoon_hello(struct typhoon *tp) typhoon_inc_cmd_index(&ring->lastWrite, 1); INIT_COMMAND_NO_RESPONSE(cmd, TYPHOON_CMD_HELLO_RESP); - smp_wmb(); + wmb(); iowrite32(ring->lastWrite, tp->ioaddr + TYPHOON_REG_CMD_READY); spin_unlock(&tp->command_lock); } @@ -1311,13 +1311,15 @@ typhoon_init_interface(struct typhoon *tp) tp->txlo_dma_addr = le32_to_cpu(iface->txLoAddr); tp->card_state = Sleeping; - smp_wmb(); tp->offload = TYPHOON_OFFLOAD_IP_CHKSUM | TYPHOON_OFFLOAD_TCP_CHKSUM; tp->offload |= TYPHOON_OFFLOAD_UDP_CHKSUM | TSO_OFFLOAD_ON; spin_lock_init(&tp->command_lock); spin_lock_init(&tp->state_lock); + + /* Force the writes to the shared memory area out before continuing. */ + wmb(); } static void -- cgit v1.2.3 From a80483d3722b603dae8a52495f8d88a7d4b1bf1c Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 5 Mar 2010 02:21:44 +0000 Subject: e1000e: fix packet corruption and tx hang during NFSv2 when receiving a particular type of NFS v2 UDP traffic, the hardware could DMA some bad data and then hang, possibly corrupting memory. Disable the NFS parsing in this hardware, verified to fix the bug. Originally reported and reproduced by RedHat's Neil Horman CC: nhorman@tuxdriver.com Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher Acked-by: Neil Horman Signed-off-by: David S. Miller --- drivers/net/e1000e/defines.h | 2 ++ drivers/net/e1000e/ich8lan.c | 10 ++++++++++ 2 files changed, 12 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index db05ec35574..e301e26d689 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h @@ -320,6 +320,8 @@ #define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ /* Header split receive */ +#define E1000_RFCTL_NFSW_DIS 0x00000040 +#define E1000_RFCTL_NFSR_DIS 0x00000080 #define E1000_RFCTL_ACK_DIS 0x00001000 #define E1000_RFCTL_EXTEN 0x00008000 #define E1000_RFCTL_IPV6_EX_DIS 0x00010000 diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index 54d03a0ce3c..8b5e157e9c8 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -2740,6 +2740,16 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw) reg &= ~(1 << 31); ew32(STATUS, reg); } + + /* + * work-around descriptor data corruption issue during nfs v2 udp + * traffic, just disable the nfs filtering capability + */ + reg = er32(RFCTL); + reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS); + ew32(RFCTL, reg); + + return; } /** -- cgit v1.2.3 From 3a22813a5aaf8e8c72be575dabe0ba26f9352f4d Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 4 Mar 2010 10:40:44 +0000 Subject: s2io: Fixing debug message Currently s2io is dumping debug messages using the interface name before it was allocated, showing a message like the following: s2io: eth%d: Ring Mem PHY: 0x7ef80000 s2io: s2io_reset: Resetting XFrame card eth%d This patch just fixes it, printing the pci bus information for the card instead of the interface name. Signed-off-by: Breno Leitao Signed-off-by: David S. Miller --- drivers/net/s2io.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 43bc66aa840..df70657260d 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -923,8 +923,8 @@ static int init_shared_mem(struct s2io_nic *nic) tmp_v_addr = mac_control->stats_mem; mac_control->stats_info = (struct stat_block *)tmp_v_addr; memset(tmp_v_addr, 0, size); - DBG_PRINT(INIT_DBG, "%s: Ring Mem PHY: 0x%llx\n", dev->name, - (unsigned long long)tmp_p_addr); + DBG_PRINT(INIT_DBG, "%s: Ring Mem PHY: 0x%llx\n", + dev_name(&nic->pdev->dev), (unsigned long long)tmp_p_addr); mac_control->stats_info->sw_stat.mem_allocated += mem_allocated; return SUCCESS; } @@ -3480,7 +3480,7 @@ static void s2io_reset(struct s2io_nic *sp) struct swStat *swstats; DBG_PRINT(INIT_DBG, "%s: Resetting XFrame card %s\n", - __func__, sp->dev->name); + __func__, pci_name(sp->pdev)); /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */ pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd)); -- cgit v1.2.3 From b96b894c518bc7399e6b86b635b5e8cd7356a8e9 Mon Sep 17 00:00:00 2001 From: "Figo.zhang" Date: Fri, 5 Mar 2010 16:36:02 +0000 Subject: fix a race in ks8695_poll fix a race at the end of NAPI processing in ks8695_poll() function. Signed-off-by:Figo.zhang Signed-off-by: David S. Miller --- drivers/net/arm/ks8695net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index 8ca639127db..a1d4188c430 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -575,9 +575,9 @@ static int ks8695_poll(struct napi_struct *napi, int budget) if (work_done < budget) { unsigned long flags; spin_lock_irqsave(&ksp->rx_lock, flags); + __napi_complete(napi); /*enable rx interrupt*/ writel(isr | mask_bit, KS8695_IRQ_VA + KS8695_INTEN); - __napi_complete(napi); spin_unlock_irqrestore(&ksp->rx_lock, flags); } return work_done; -- cgit v1.2.3 From ea3fb371b2a391958670f2a65e1203f7dba61671 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 6 Mar 2010 01:11:38 +0000 Subject: ems_usb: cleanup: remove uneeded check "skb" is alway non-null here, but even if it were null the check isn't needed because dev_kfree_skb() can handle it. This eliminates a smatch warning about dereferencing a variable before checking that it is non-null. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/can/usb/ems_usb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index 11c87840cc0..33451092b8e 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -876,9 +876,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne return NETDEV_TX_OK; nomem: - if (skb) - dev_kfree_skb(skb); - + dev_kfree_skb(skb); stats->tx_dropped++; return NETDEV_TX_OK; -- cgit v1.2.3 From 0e2b807234c42fab59f98ec913db30dfda0e63a7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 7 Mar 2010 02:35:42 +0000 Subject: irda-usb: add error handling and fix leak If the call to kcalloc() fails then we should return -ENOMEM. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/irda/irda-usb.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index e8e33bb9d87..2c9b3af1661 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -1651,6 +1651,8 @@ static int irda_usb_probe(struct usb_interface *intf, self->rx_urb = kcalloc(self->max_rx_urb, sizeof(struct urb *), GFP_KERNEL); + if (!self->rx_urb) + goto err_free_net; for (i = 0; i < self->max_rx_urb; i++) { self->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL); @@ -1783,6 +1785,8 @@ err_out_2: err_out_1: for (i = 0; i < self->max_rx_urb; i++) usb_free_urb(self->rx_urb[i]); + kfree(self->rx_urb); +err_free_net: free_netdev(net); err_out: return ret; -- cgit v1.2.3 From e7111eac8ebda724d1e4d9e6aaf4569744a584d5 Mon Sep 17 00:00:00 2001 From: Petko Manolov Date: Sun, 7 Mar 2010 06:10:01 +0000 Subject: another pegasus usb net device This one removes trailing whitespace in pegasus.h and more importantly adds new Pegasus compatible device. Signed-off-by: Julian Brown Signed-off-by: Petko Manolov Signed-off-by: David S. Miller --- drivers/net/usb/pegasus.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/pegasus.h b/drivers/net/usb/pegasus.h index 5d02f020073..b90d8766ab7 100644 --- a/drivers/net/usb/pegasus.h +++ b/drivers/net/usb/pegasus.h @@ -177,7 +177,7 @@ PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400c, PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0xabc1, DEFAULT_GPIO_RESET ) PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x200c, - DEFAULT_GPIO_RESET | PEGASUS_II ) + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046, DEFAULT_GPIO_RESET ) PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046, @@ -208,6 +208,8 @@ PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100, */ PEGASUS_DEV_CLASS( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121, 0x00, DEFAULT_GPIO_RESET | PEGASUS_II ) +PEGASUS_DEV( "Belkin F5U122 10/100 USB Ethernet", VENDOR_BELKIN, 0x0122, + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "Billionton USB-100", VENDOR_BILLIONTON, 0x0986, DEFAULT_GPIO_RESET ) PEGASUS_DEV( "Billionton USBLP-100", VENDOR_BILLIONTON, 0x0987, @@ -249,7 +251,7 @@ PEGASUS_DEV( "GIGABYTE GN-BR402W Wireless Router", VENDOR_GIGABYTE, 0x8002, PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c, DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "HP hn210c Ethernet USB", VENDOR_HP, 0x811c, - DEFAULT_GPIO_RESET | PEGASUS_II ) + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904, DEFAULT_GPIO_RESET ) PEGASUS_DEV( "IO DATA USB ET/TX-S", VENDOR_IODATA, 0x0913, -- cgit v1.2.3 From 30765d0502905a9248e5de72fc7ac83c23422861 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sun, 7 Mar 2010 00:55:26 +0000 Subject: cpmac: fix the receiving of 802.1q frames Despite what the comment above CPMAC_SKB_SIZE says, the hardware also needs to account for the FCS length in a received frame. This patch fix the receiving of 802.1q frames which have 4 more bytes. While at it unhardcode the definition and use the one from if_vlan.h. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/cpmac.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 9d489421535..55ee055d332 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -56,8 +57,8 @@ MODULE_PARM_DESC(debug_level, "Number of NETIF_MSG bits to enable"); MODULE_PARM_DESC(dumb_switch, "Assume switch is not connected to MDIO bus"); #define CPMAC_VERSION "0.5.1" -/* frame size + 802.1q tag */ -#define CPMAC_SKB_SIZE (ETH_FRAME_LEN + 4) +/* frame size + 802.1q tag + FCS size */ +#define CPMAC_SKB_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN) #define CPMAC_QUEUES 8 /* Ethernet registers */ -- cgit v1.2.3 From 9fba1c31f4f3f9f860a4afee0b409cde27d06741 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sun, 7 Mar 2010 00:55:47 +0000 Subject: cpmac: fallback to switch mode if no PHY chip found If we were unable to detect a PHY on any of the MDIO bus id we tried instead of bailing out with -ENODEV, assume the MAC is connected to a switch and use MDIO bus 0. This unbreaks quite a lot of devices out there whose switch cannot be detected. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/cpmac.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 55ee055d332..baeb5bab05b 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -1137,8 +1137,9 @@ static int __devinit cpmac_probe(struct platform_device *pdev) } if (phy_id == PHY_MAX_ADDR) { - dev_err(&pdev->dev, "no PHY present\n"); - return -ENODEV; + dev_err(&pdev->dev, "no PHY present, falling back to switch on MDIO bus 0\n"); + strncpy(mdio_bus_id, "0", MII_BUS_ID_SIZE); /* fixed phys bus */ + phy_id = pdev->id; } dev = alloc_etherdev_mq(sizeof(*priv), CPMAC_QUEUES); -- cgit v1.2.3 From 25dc27d17dc868aae78fd03bef3113cf586b12e5 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sun, 7 Mar 2010 00:55:50 +0000 Subject: cpmac: bump version to 0.5.2 Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/cpmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index baeb5bab05b..60777fd90b3 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -56,7 +56,7 @@ module_param(dumb_switch, int, 0444); MODULE_PARM_DESC(debug_level, "Number of NETIF_MSG bits to enable"); MODULE_PARM_DESC(dumb_switch, "Assume switch is not connected to MDIO bus"); -#define CPMAC_VERSION "0.5.1" +#define CPMAC_VERSION "0.5.2" /* frame size + 802.1q tag + FCS size */ #define CPMAC_SKB_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN) #define CPMAC_QUEUES 8 -- cgit v1.2.3 From 500ca9ba241304937c54c379e515b24400379353 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Sun, 7 Mar 2010 14:21:27 +0000 Subject: be2net: remove usage of be_pci_func When PCI functions are virtuialized in applications by assigning PCI functions to VM (PCI passthrough), the be2net driver in the VM sees a different function number. So, use of PCI function number in any calculation will break existing code. This patch takes care of it. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/benet/be.h | 5 ----- drivers/net/benet/be_cmds.c | 6 ------ drivers/net/benet/be_main.c | 2 +- 3 files changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index be81fb2d10f..8f075255368 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -290,11 +290,6 @@ extern const struct ethtool_ops be_ethtool_ops; #define drvr_stats(adapter) (&adapter->stats.drvr_stats) -static inline unsigned int be_pci_func(struct be_adapter *adapter) -{ - return PCI_FUNC(adapter->pdev->devfn); -} - #define BE_SET_NETDEV_OPS(netdev, ops) (netdev->netdev_ops = ops) #define PAGE_SHIFT_4K 12 diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 4b1f80519ca..c59215361f4 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -465,8 +465,6 @@ int be_cmd_eq_create(struct be_adapter *adapter, req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); - AMAP_SET_BITS(struct amap_eq_context, func, req->context, - be_pci_func(adapter)); AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1); /* 4byte eqe*/ AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0); @@ -629,7 +627,6 @@ int be_cmd_cq_create(struct be_adapter *adapter, AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1); AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id); AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 1); - AMAP_SET_BITS(struct amap_cq_context, func, ctxt, be_pci_func(adapter)); be_dws_cpu_to_le(ctxt, sizeof(req->context)); be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); @@ -678,7 +675,6 @@ int be_cmd_mccq_create(struct be_adapter *adapter, req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); - AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt, be_pci_func(adapter)); AMAP_SET_BITS(struct amap_mcc_context, valid, ctxt, 1); AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt, be_encoded_q_len(mccq->len)); @@ -727,8 +723,6 @@ int be_cmd_txq_create(struct be_adapter *adapter, AMAP_SET_BITS(struct amap_tx_context, tx_ring_size, ctxt, be_encoded_q_len(txq->len)); - AMAP_SET_BITS(struct amap_tx_context, pci_func_id, ctxt, - be_pci_func(adapter)); AMAP_SET_BITS(struct amap_tx_context, ctx_valid, ctxt, 1); AMAP_SET_BITS(struct amap_tx_context, cq_id_send, ctxt, cq->id); diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 22f787f2a30..7c9b57eb780 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1382,7 +1382,7 @@ rx_eq_free: /* There are 8 evt ids per func. Retruns the evt id's bit number */ static inline int be_evt_bit_get(struct be_adapter *adapter, u32 eq_id) { - return eq_id - 8 * be_pci_func(adapter); + return eq_id % 8; } static irqreturn_t be_intx(int irq, void *dev) -- cgit v1.2.3 From 7e8a9298adf7531c58d73ba9c499353e3807cf19 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Sun, 7 Mar 2010 14:23:44 +0000 Subject: be2net: remove unused code in be_load_fw This patch cleans up some unused code from be_load_fw(). Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/benet/be_main.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 7c9b57eb780..43e8032f923 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1993,16 +1993,7 @@ int be_load_fw(struct be_adapter *adapter, u8 *func) struct be_dma_mem flash_cmd; int status, i = 0; const u8 *p; - char fw_ver[FW_VER_LEN]; - char fw_cfg; - status = be_cmd_get_fw_ver(adapter, fw_ver); - if (status) - return status; - - fw_cfg = *(fw_ver + 2); - if (fw_cfg == '0') - fw_cfg = '1'; strcpy(fw_file, func); status = request_firmware(&fw, fw_file, &adapter->pdev->dev); -- cgit v1.2.3 From 8bae5698616ac336938684ce7a7370299bd55d01 Mon Sep 17 00:00:00 2001 From: Sucheta Chakraborty Date: Mon, 8 Mar 2010 00:14:45 +0000 Subject: qlcnic: fix tx csum status Kernel default tx csum function (ethtool_op_get_tx_csum) doesn't show correct csum status. It takes various FLAGS (NETIF_F_ALL_CSUM) in account to show tx csum status, which driver doesn't set while disabling tx csum. Signed-off-by: Sucheta Chakraborty Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic_ethtool.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 8da6ec8c13b..ef12792a88b 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -785,6 +785,11 @@ qlcnic_get_ethtool_stats(struct net_device *dev, } } +static u32 qlcnic_get_tx_csum(struct net_device *dev) +{ + return dev->features & NETIF_F_IP_CSUM; +} + static u32 qlcnic_get_rx_csum(struct net_device *dev) { struct qlcnic_adapter *adapter = netdev_priv(dev); @@ -995,6 +1000,7 @@ const struct ethtool_ops qlcnic_ethtool_ops = { .set_ringparam = qlcnic_set_ringparam, .get_pauseparam = qlcnic_get_pauseparam, .set_pauseparam = qlcnic_set_pauseparam, + .get_tx_csum = qlcnic_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, .set_sg = ethtool_op_set_sg, .get_tso = qlcnic_get_tso, -- cgit v1.2.3 From 8bfe8b91b8b877066c8ac788f59a40324eaac6d8 Mon Sep 17 00:00:00 2001 From: Sucheta Chakraborty Date: Mon, 8 Mar 2010 00:14:46 +0000 Subject: qlcnic: additional driver statistics. Statistics added for lro/lso bytes, count for tx stop queue and wake queue and skb alloc failure count. Signed-off-by: Sucheta Chakraborty Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 5 +++++ drivers/net/qlcnic/qlcnic_ethtool.c | 11 +++++++++++ drivers/net/qlcnic/qlcnic_hw.c | 1 + drivers/net/qlcnic/qlcnic_init.c | 8 ++++++-- drivers/net/qlcnic/qlcnic_main.c | 5 +++++ 5 files changed, 28 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index b40a851ec7d..9897b699752 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -423,6 +423,11 @@ struct qlcnic_adapter_stats { u64 lro_pkts; u64 rxbytes; u64 txbytes; + u64 lrobytes; + u64 lso_frames; + u64 xmit_on; + u64 xmit_off; + u64 skb_alloc_failure; }; /* diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index ef12792a88b..f83e15fe3e1 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -59,6 +59,17 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = { QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)}, {"tx_bytes", QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)}, + {"lrobytes", + QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)}, + {"lso_frames", + QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)}, + {"xmit_on", + QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)}, + {"xmit_off", + QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)}, + {"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure), + QLC_OFF(stats.skb_alloc_failure)}, + }; #define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats) diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index 99a4d1379d0..e95646bf7d5 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -349,6 +349,7 @@ qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter, if (nr_desc >= qlcnic_tx_avail(tx_ring)) { netif_tx_stop_queue(tx_ring->txq); __netif_tx_unlock_bh(tx_ring->txq); + adapter->stats.xmit_off++; return -EBUSY; } diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index ea00ab4d4fe..f0df9717aec 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -1114,8 +1114,10 @@ qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter, struct pci_dev *pdev = adapter->pdev; buffer->skb = dev_alloc_skb(rds_ring->skb_size); - if (!buffer->skb) + if (!buffer->skb) { + adapter->stats.skb_alloc_failure++; return -ENOMEM; + } skb = buffer->skb; @@ -1289,7 +1291,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter, netif_receive_skb(skb); adapter->stats.lro_pkts++; - adapter->stats.rxbytes += length; + adapter->stats.lrobytes += length; return buffer; } @@ -1505,6 +1507,8 @@ qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter, adapter->diag_cnt++; dev_kfree_skb_any(skb); + adapter->stats.rx_pkts++; + adapter->stats.rxbytes += length; return buffer; } diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 665e8e56b6a..fc721564e69 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -118,6 +118,7 @@ qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter, if (qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH) { netif_stop_queue(adapter->netdev); smp_mb(); + adapter->stats.xmit_off++; } } @@ -1385,6 +1386,7 @@ qlcnic_tso_check(struct net_device *netdev, int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0; struct cmd_desc_type0 *hwdesc; struct vlan_ethhdr *vh; + struct qlcnic_adapter *adapter = netdev_priv(netdev); if (protocol == cpu_to_be16(ETH_P_8021Q)) { @@ -1494,6 +1496,7 @@ qlcnic_tso_check(struct net_device *netdev, tx_ring->producer = producer; barrier(); + adapter->stats.lso_frames++; } static int @@ -1573,6 +1576,7 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (unlikely(no_of_desc + 2 > qlcnic_tx_avail(tx_ring))) { netif_stop_queue(netdev); + adapter->stats.xmit_off++; return NETDEV_TX_BUSY; } @@ -1880,6 +1884,7 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter) if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) { netif_wake_queue(netdev); adapter->tx_timeo_cnt = 0; + adapter->stats.xmit_on++; } __netif_tx_unlock(tx_ring->txq); } -- cgit v1.2.3 From 9ab17b3968f9521bb4fffd8767953d2b0148aad0 Mon Sep 17 00:00:00 2001 From: Sucheta Chakraborty Date: Mon, 8 Mar 2010 00:14:47 +0000 Subject: qlcnic: fix multicast handling For promiscuous mode, driver send request to device for deleting multicast addresses and again it send request for adding them back while exiting from this mode, this is bad for performance. Just setting device in promiscuous mode is enough, no need to del/add multicast addresses. Signed-off-by: Sucheta Chakraborty Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic_hw.c | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index e95646bf7d5..da00e162b6d 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -398,20 +398,16 @@ qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, return qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); } -static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, - u8 *addr, struct list_head *del_list) +static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, u8 *addr) { struct list_head *head; struct qlcnic_mac_list_s *cur; /* look up if already exists */ - list_for_each(head, del_list) { + list_for_each(head, &adapter->mac_list) { cur = list_entry(head, struct qlcnic_mac_list_s, list); - - if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) { - list_move_tail(head, &adapter->mac_list); + if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) return 0; - } } cur = kzalloc(sizeof(struct qlcnic_mac_list_s), GFP_ATOMIC); @@ -433,14 +429,9 @@ void qlcnic_set_multi(struct net_device *netdev) struct dev_mc_list *mc_ptr; u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; u32 mode = VPORT_MISS_MODE_DROP; - LIST_HEAD(del_list); - struct list_head *head; - struct qlcnic_mac_list_s *cur; - list_splice_tail_init(&adapter->mac_list, &del_list); - - qlcnic_nic_add_mac(adapter, adapter->mac_addr, &del_list); - qlcnic_nic_add_mac(adapter, bcast_addr, &del_list); + qlcnic_nic_add_mac(adapter, adapter->mac_addr); + qlcnic_nic_add_mac(adapter, bcast_addr); if (netdev->flags & IFF_PROMISC) { mode = VPORT_MISS_MODE_ACCEPT_ALL; @@ -455,22 +446,12 @@ void qlcnic_set_multi(struct net_device *netdev) if (!netdev_mc_empty(netdev)) { netdev_for_each_mc_addr(mc_ptr, netdev) { - qlcnic_nic_add_mac(adapter, mc_ptr->dmi_addr, - &del_list); + qlcnic_nic_add_mac(adapter, mc_ptr->dmi_addr); } } send_fw_cmd: qlcnic_nic_set_promisc(adapter, mode); - head = &del_list; - while (!list_empty(head)) { - cur = list_entry(head->next, struct qlcnic_mac_list_s, list); - - qlcnic_sre_macaddr_change(adapter, - cur->mac_addr, QLCNIC_MAC_DEL); - list_del(&cur->list); - kfree(cur); - } } int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) -- cgit v1.2.3 From b7eff1007fea3d153a9a5c0f872304ec19412bbb Mon Sep 17 00:00:00 2001 From: Sucheta Chakraborty Date: Mon, 8 Mar 2010 00:14:48 +0000 Subject: qlcnic: validate unified fw image Validate all sections of unified fw image, before accessing them, to avoid seg fault. Signed-off-by: Sucheta Chakraborty Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic_init.c | 146 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 139 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index f0df9717aec..21a6e9f3dac 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -568,21 +568,123 @@ struct uni_table_desc *qlcnic_get_table_desc(const u8 *unirom, int section) return NULL; } +#define FILEHEADER_SIZE (14 * 4) + static int -qlcnic_set_product_offs(struct qlcnic_adapter *adapter) +qlcnic_validate_header(struct qlcnic_adapter *adapter) { - struct uni_table_desc *ptab_descr; const u8 *unirom = adapter->fw->data; - u32 i; + struct uni_table_desc *directory = (struct uni_table_desc *) &unirom[0]; + __le32 fw_file_size = adapter->fw->size; __le32 entries; + __le32 entry_size; + __le32 tab_size; + + if (fw_file_size < FILEHEADER_SIZE) + return -EINVAL; + + entries = cpu_to_le32(directory->num_entries); + entry_size = cpu_to_le32(directory->entry_size); + tab_size = cpu_to_le32(directory->findex) + (entries * entry_size); + + if (fw_file_size < tab_size) + return -EINVAL; + + return 0; +} + +static int +qlcnic_validate_bootld(struct qlcnic_adapter *adapter) +{ + struct uni_table_desc *tab_desc; + struct uni_data_desc *descr; + const u8 *unirom = adapter->fw->data; + int idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] + + QLCNIC_UNI_BOOTLD_IDX_OFF)); + __le32 offs; + __le32 tab_size; + __le32 data_size; + + tab_desc = qlcnic_get_table_desc(unirom, QLCNIC_UNI_DIR_SECT_BOOTLD); + + if (!tab_desc) + return -EINVAL; + + tab_size = cpu_to_le32(tab_desc->findex) + + (cpu_to_le32(tab_desc->entry_size * (idx + 1))); + + if (adapter->fw->size < tab_size) + return -EINVAL; + + offs = cpu_to_le32(tab_desc->findex) + + (cpu_to_le32(tab_desc->entry_size) * (idx)); + descr = (struct uni_data_desc *)&unirom[offs]; + + data_size = descr->findex + cpu_to_le32(descr->size); + + if (adapter->fw->size < data_size) + return -EINVAL; + + return 0; +} + +static int +qlcnic_validate_fw(struct qlcnic_adapter *adapter) +{ + struct uni_table_desc *tab_desc; + struct uni_data_desc *descr; + const u8 *unirom = adapter->fw->data; + int idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] + + QLCNIC_UNI_FIRMWARE_IDX_OFF)); + __le32 offs; + __le32 tab_size; + __le32 data_size; + + tab_desc = qlcnic_get_table_desc(unirom, QLCNIC_UNI_DIR_SECT_FW); + + if (!tab_desc) + return -EINVAL; + + tab_size = cpu_to_le32(tab_desc->findex) + + (cpu_to_le32(tab_desc->entry_size * (idx + 1))); + + if (adapter->fw->size < tab_size) + return -EINVAL; + + offs = cpu_to_le32(tab_desc->findex) + + (cpu_to_le32(tab_desc->entry_size) * (idx)); + descr = (struct uni_data_desc *)&unirom[offs]; + data_size = descr->findex + cpu_to_le32(descr->size); + + if (adapter->fw->size < data_size) + return -EINVAL; + + return 0; +} + +static int +qlcnic_validate_product_offs(struct qlcnic_adapter *adapter) +{ + struct uni_table_desc *ptab_descr; + const u8 *unirom = adapter->fw->data; int mn_present = qlcnic_has_mn(adapter); + __le32 entries; + __le32 entry_size; + __le32 tab_size; + u32 i; ptab_descr = qlcnic_get_table_desc(unirom, QLCNIC_UNI_DIR_SECT_PRODUCT_TBL); - if (ptab_descr == NULL) - return -1; + if (!ptab_descr) + return -EINVAL; entries = cpu_to_le32(ptab_descr->num_entries); + entry_size = cpu_to_le32(ptab_descr->entry_size); + tab_size = cpu_to_le32(ptab_descr->findex) + (entries * entry_size); + + if (adapter->fw->size < tab_size) + return -EINVAL; + nomn: for (i = 0; i < entries; i++) { @@ -609,7 +711,37 @@ nomn: mn_present = 0; goto nomn; } - return -1; + return -EINVAL; +} + +static int +qlcnic_validate_unified_romimage(struct qlcnic_adapter *adapter) +{ + if (qlcnic_validate_header(adapter)) { + dev_err(&adapter->pdev->dev, + "unified image: header validation failed\n"); + return -EINVAL; + } + + if (qlcnic_validate_product_offs(adapter)) { + dev_err(&adapter->pdev->dev, + "unified image: product validation failed\n"); + return -EINVAL; + } + + if (qlcnic_validate_bootld(adapter)) { + dev_err(&adapter->pdev->dev, + "unified image: bootld validation failed\n"); + return -EINVAL; + } + + if (qlcnic_validate_fw(adapter)) { + dev_err(&adapter->pdev->dev, + "unified image: firmware validation failed\n"); + return -EINVAL; + } + + return 0; } static @@ -858,7 +990,7 @@ qlcnic_validate_firmware(struct qlcnic_adapter *adapter) u8 fw_type = adapter->fw_type; if (fw_type == QLCNIC_UNIFIED_ROMIMAGE) { - if (qlcnic_set_product_offs(adapter)) + if (qlcnic_validate_unified_romimage(adapter)) return -EINVAL; min_size = QLCNIC_UNI_FW_MIN_SIZE; -- cgit v1.2.3 From addd5abf49be31787aeb6203d266e0bd31a3fadd Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Mon, 8 Mar 2010 00:14:49 +0000 Subject: qlcnic: fix bios version check Bios sub version from unified fw image is calculated incorrect. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index 21a6e9f3dac..7c34e4e29b3 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -847,7 +847,7 @@ qlcnic_get_bios_version(struct qlcnic_adapter *adapter) bios_ver = cpu_to_le32(*((u32 *) (&fw->data[prd_off]) + QLCNIC_UNI_BIOS_VERSION_OFF)); - return (bios_ver << 24) + ((bios_ver >> 8) & 0xff00) + (bios_ver >> 24); + return (bios_ver << 16) + ((bios_ver >> 8) & 0xff00) + (bios_ver >> 24); } int -- cgit v1.2.3 From 1515faf2f995add976d4428bbc1583a4a0c81e5f Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Mon, 8 Mar 2010 00:14:50 +0000 Subject: qlcnic: remove extra space from board names Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 9897b699752..0da94b208db 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -1100,11 +1100,11 @@ struct qlcnic_brdinfo { static const struct qlcnic_brdinfo qlcnic_boards[] = { {0x1077, 0x8020, 0x1077, 0x203, - "8200 Series Single Port 10GbE Converged Network Adapter \ - (TCP/IP Networking)"}, + "8200 Series Single Port 10GbE Converged Network Adapter " + "(TCP/IP Networking)"}, {0x1077, 0x8020, 0x1077, 0x207, - "8200 Series Dual Port 10GbE Converged Network Adapter \ - (TCP/IP Networking)"}, + "8200 Series Dual Port 10GbE Converged Network Adapter " + "(TCP/IP Networking)"}, {0x1077, 0x8020, 0x1077, 0x20b, "3200 Series Dual Port 10Gb Intelligent Ethernet Adapter"}, {0x1077, 0x8020, 0x1077, 0x20c, -- cgit v1.2.3 From e9dcd1613f0ac0b3573b7d813a2c5672cd8302eb Mon Sep 17 00:00:00 2001 From: Barry Song Date: Mon, 8 Mar 2010 12:13:57 -0800 Subject: can: fix bfin_can build error after alloc_candev() change Looks like commit a6e4bc530403 didn't include updates to drivers so the Blackfin CAN driver fails to build now. Signed-off-by: Barry Song Signed-off-by: Mike Frysinger Acked-by: Wolfgang Grandegger Signed-off-by: David S. Miller --- drivers/net/can/bfin_can.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c index bf7f9ba2d90..866905fa411 100644 --- a/drivers/net/can/bfin_can.c +++ b/drivers/net/can/bfin_can.c @@ -26,6 +26,7 @@ #define DRV_NAME "bfin_can" #define BFIN_CAN_TIMEOUT 100 +#define TX_ECHO_SKB_MAX 1 /* * transmit and receive channels @@ -593,7 +594,7 @@ struct net_device *alloc_bfin_candev(void) struct net_device *dev; struct bfin_can_priv *priv; - dev = alloc_candev(sizeof(*priv)); + dev = alloc_candev(sizeof(*priv), TX_ECHO_SKB_MAX); if (!dev) return NULL; -- cgit v1.2.3 From 1d79e53c56afe0826a311c3bc1653ad938166c22 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 26 Feb 2010 11:01:36 -0800 Subject: iwl3945: fix memory corruption Recent patch "iwlwifi: move 3945 clip groups to 3945 data" exposed a memory corruption problem. When initializing the clip groups the code was mistakenly using the iwlagn rate count, not the 3945 rate count. This resulted in more memory being written than was allocated. "iwlwifi: move 3945 clip groups to 3945 data" moved the location where the clip groups are stored and the impact is now severe in that the number of configured TX queues is modified. Previously the "temperature" field was overwritten, which did not seem to affect the operation. Fix this one instance where wrong rate count was used. I also noticed one more location where the iwlagn rate count was used to index an iwl3945 array, fix this. I also modified one location that modified the iwlagn rate count to obtain the iwl3945 rate count ... just use the iwl3945 rate count directly. This fixes http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=2165 and http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=2168 Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-3945.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 303cc8193ad..e0678d92105 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -184,7 +184,7 @@ static int iwl3945_hwrate_to_plcp_idx(u8 plcp) { int idx; - for (idx = 0; idx < IWL_RATE_COUNT; idx++) + for (idx = 0; idx < IWL_RATE_COUNT_3945; idx++) if (iwl3945_rates[idx].plcp == plcp) return idx; return -1; @@ -805,7 +805,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, int sta_id, int tx_id) { u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value; - u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1); + u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT_3945); u16 rate_mask; int rate; u8 rts_retry_limit; @@ -2146,7 +2146,7 @@ static void iwl3945_hw_reg_init_channel_groups(struct iwl_priv *priv) /* fill in channel group's nominal powers for each rate */ for (rate_index = 0; - rate_index < IWL_RATE_COUNT; rate_index++, clip_pwrs++) { + rate_index < IWL_RATE_COUNT_3945; rate_index++, clip_pwrs++) { switch (rate_index) { case IWL_RATE_36M_INDEX_TABLE: if (i == 0) /* B/G */ -- cgit v1.2.3 From 1382c71c764540880d35485b033a44ce104d8e2e Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Thu, 25 Feb 2010 10:02:19 -0800 Subject: Revert "iwlwifi: Send broadcast probe request only when asked to" This reverts commit 21b2d8bd2f0d4e0f21ade147fd193c8b9c1fd2b9. As explained by Johannes: When we build a probe request frame in the buffer with the SSID, we could arrive over the limit of 200 bytes. When we build it in the buffer without the SSID (wildcard) we don't arrive over 200 bytes, but the ucode still allows direct probe in addition because it has an internal buffer that is larger when it inserts the SSID... Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- drivers/net/wireless/iwlwifi/iwl-scan.c | 49 +++++++++++---------------------- 2 files changed, 17 insertions(+), 34 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 47b02147796..818367b57ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2653,7 +2653,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv) */ hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; - hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX + 1; + hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; /* we create the 802.11 header and a zero-length SSID element */ hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2; diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index dd9ff2ed645..bd2f7c42056 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -638,20 +638,9 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, if (left < 0) return 0; *pos++ = WLAN_EID_SSID; - if (!priv->is_internal_short_scan && - priv->scan_request->n_ssids) { - struct cfg80211_ssid *ssid = - priv->scan_request->ssids; - - /* Broadcast if ssid_len is 0 */ - *pos++ = ssid->ssid_len; - memcpy(pos, ssid->ssid, ssid->ssid_len); - pos += ssid->ssid_len; - len += 2 + ssid->ssid_len; - } else { - *pos++ = 0; - len += 2; - } + *pos++ = 0; + + len += 2; if (WARN_ON(left < ie_len)) return len; @@ -780,26 +769,20 @@ static void iwl_bg_request_scan(struct work_struct *data) if (priv->is_internal_short_scan) { IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n"); } else if (priv->scan_request->n_ssids) { + int i, p = 0; IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); - /* - * The first SSID to scan is stuffed into the probe request - * template and the remaining ones are handled through the - * direct_scan array. - */ - if (priv->scan_request->n_ssids > 1) { - int i, p = 0; - for (i = 1; i < priv->scan_request->n_ssids; i++) { - if (!priv->scan_request->ssids[i].ssid_len) - continue; - scan->direct_scan[p].id = WLAN_EID_SSID; - scan->direct_scan[p].len = - priv->scan_request->ssids[i].ssid_len; - memcpy(scan->direct_scan[p].ssid, - priv->scan_request->ssids[i].ssid, - priv->scan_request->ssids[i].ssid_len); - n_probes++; - p++; - } + for (i = 0; i < priv->scan_request->n_ssids; i++) { + /* always does wildcard anyway */ + if (!priv->scan_request->ssids[i].ssid_len) + continue; + scan->direct_scan[p].id = WLAN_EID_SSID; + scan->direct_scan[p].len = + priv->scan_request->ssids[i].ssid_len; + memcpy(scan->direct_scan[p].ssid, + priv->scan_request->ssids[i].ssid, + priv->scan_request->ssids[i].ssid_len); + n_probes++; + p++; } is_active = true; } else -- cgit v1.2.3 From fe234f0e5cbb880792d2d1ac0743cf8c07e9dde3 Mon Sep 17 00:00:00 2001 From: Louis Rilling Date: Tue, 9 Mar 2010 06:14:41 +0000 Subject: tg3: Fix tg3_poll_controller() passing wrong pointer to tg3_interrupt() Commit 09943a1819a240ff4a72f924d0038818fcdd0a90 Author: Matt Carlson Date: Fri Aug 28 14:01:57 2009 +0000 tg3: Convert ISR parameter to tnapi forgot to update tg3_poll_controller(), leading to intermittent crashes with netpoll. Fix this. Signed-off-by: Louis Rilling Cc: stable@kernel.org Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 0fa7688ab48..c3b4fe74cd6 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5279,7 +5279,7 @@ static void tg3_poll_controller(struct net_device *dev) struct tg3 *tp = netdev_priv(dev); for (i = 0; i < tp->irq_cnt; i++) - tg3_interrupt(tp->napi[i].irq_vec, dev); + tg3_interrupt(tp->napi[i].irq_vec, &tp->napi[i]); } #endif -- cgit v1.2.3 From 7f29a3baa825725d29db399663790d15c78cddcf Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 9 Mar 2010 12:24:38 +0000 Subject: asix: fix setting mac address for AX88772 Setting new MAC address only worked when device was set to promiscuous mode. Fix MAC address by writing new address to device using undocumented command AX_CMD_READ_NODE_ID+1. Patch is tested with AX88772 device. Signed-off-by: Jussi Kivilinna Acked-by: David Hollis Signed-off-by: David S. Miller --- drivers/net/usb/asix.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 20e34608fa4..9e05639435f 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -54,6 +54,7 @@ static const char driver_name [] = "asix"; #define AX_CMD_WRITE_IPG0 0x12 #define AX_CMD_WRITE_IPG1 0x13 #define AX_CMD_READ_NODE_ID 0x13 +#define AX_CMD_WRITE_NODE_ID 0x14 #define AX_CMD_WRITE_IPG2 0x14 #define AX_CMD_WRITE_MULTI_FILTER 0x16 #define AX88172_CMD_READ_NODE_ID 0x17 @@ -165,6 +166,7 @@ static const char driver_name [] = "asix"; /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ struct asix_data { u8 multi_filter[AX_MCAST_FILTER_SIZE]; + u8 mac_addr[ETH_ALEN]; u8 phymode; u8 ledmode; u8 eeprom_len; @@ -732,6 +734,30 @@ static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); } +static int asix_set_mac_address(struct net_device *net, void *p) +{ + struct usbnet *dev = netdev_priv(net); + struct asix_data *data = (struct asix_data *)&dev->data; + struct sockaddr *addr = p; + + if (netif_running(net)) + return -EBUSY; + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); + + /* We use the 20 byte dev->data + * for our 6 byte mac buffer + * to avoid allocating memory that + * is tricky to free later */ + memcpy(data->mac_addr, addr->sa_data, ETH_ALEN); + asix_write_cmd_async(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, + data->mac_addr); + + return 0; +} + /* We need to override some ethtool_ops so we require our own structure so we don't interfere with other usbnet devices that may be connected at the same time. */ @@ -919,7 +945,7 @@ static const struct net_device_ops ax88772_netdev_ops = { .ndo_start_xmit = usbnet_start_xmit, .ndo_tx_timeout = usbnet_tx_timeout, .ndo_change_mtu = usbnet_change_mtu, - .ndo_set_mac_address = eth_mac_addr, + .ndo_set_mac_address = asix_set_mac_address, .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = asix_ioctl, .ndo_set_multicast_list = asix_set_multicast, @@ -1213,7 +1239,7 @@ static const struct net_device_ops ax88178_netdev_ops = { .ndo_stop = usbnet_stop, .ndo_start_xmit = usbnet_start_xmit, .ndo_tx_timeout = usbnet_tx_timeout, - .ndo_set_mac_address = eth_mac_addr, + .ndo_set_mac_address = asix_set_mac_address, .ndo_validate_addr = eth_validate_addr, .ndo_set_multicast_list = asix_set_multicast, .ndo_do_ioctl = asix_ioctl, -- cgit v1.2.3 From 717ea4b3474852057b1ce2c639ce219f4f8d3a8d Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Wed, 10 Mar 2010 07:37:06 -0800 Subject: net: add ColdFire support to the smc91x driver Some embedded ColdFire based boards use the SMC 91x family of ethernet devices. (For example the Freescale M5249C3 and MoretonBay NETtel). Add IO access support to the SMC91x driver, and allow this driver to be configured for ColdFire platforms. Signed-off-by: Greg Ungerer Signed-off-by: David S. Miller --- drivers/net/Kconfig | 2 +- drivers/net/smc91x.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 7029cd50c45..0ba5b8e50a7 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -907,7 +907,7 @@ config SMC91X select CRC32 select MII depends on ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || \ - MIPS || BLACKFIN || MN10300 + MIPS || BLACKFIN || MN10300 || COLDFIRE help This is a driver for SMC's 91x series of Ethernet chipsets, including the SMC91C94 and the SMC91C111. Say Y if you want it diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index a6ee883d1b0..8d2772cc42f 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -344,6 +344,34 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r, #define SMC_IRQ_FLAGS IRQF_TRIGGER_HIGH +#elif defined(CONFIG_COLDFIRE) + +#define SMC_CAN_USE_8BIT 0 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 0 +#define SMC_NOWAIT 1 + +static inline void mcf_insw(void *a, unsigned char *p, int l) +{ + u16 *wp = (u16 *) p; + while (l-- > 0) + *wp++ = readw(a); +} + +static inline void mcf_outsw(void *a, unsigned char *p, int l) +{ + u16 *wp = (u16 *) p; + while (l-- > 0) + writew(*wp++, a); +} + +#define SMC_inw(a, r) _swapw(readw((a) + (r))) +#define SMC_outw(v, a, r) writew(_swapw(v), (a) + (r)) +#define SMC_insw(a, r, p, l) mcf_insw(a + r, p, l) +#define SMC_outsw(a, r, p, l) mcf_outsw(a + r, p, l) + +#define SMC_IRQ_FLAGS (IRQF_DISABLED) + #else /* -- cgit v1.2.3 From e5a9a35cb9c0d92d7c986cb3696fb794be100087 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Fri, 5 Mar 2010 17:44:22 +0100 Subject: rt2x00: remove KSEG1ADDR define from rt2x00soc.h Remove the KSEG1ADDR define from rt2x00soc.h as it redefines and covers the correct one from the arch/mips/include/asm/addrspace.h. Otherwise the driver oopses on the target platform (Ralink rt3050 board). Signed-off-by: Helmut Schaa Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00soc.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.h b/drivers/net/wireless/rt2x00/rt2x00soc.h index 4739edfe2f0..474cbfc1efc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00soc.h +++ b/drivers/net/wireless/rt2x00/rt2x00soc.h @@ -26,8 +26,6 @@ #ifndef RT2X00SOC_H #define RT2X00SOC_H -#define KSEG1ADDR(__ptr) __ptr - /* * SoC driver handlers. */ -- cgit v1.2.3 From 8e59340e4fb65cfd748eaa1e23db057c52520f35 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 8 Mar 2010 13:18:03 +0800 Subject: libipw: split ieee->networks into small pieces The ieee->networks consists of 128 struct libipw_network entries. If we allocate this chunk of memory altogether, it ends up with an order 4 page allocation. High order page allocation is likely to fail on system high load. This patch splits the big chunk memory allocation into small pieces, each is 344 bytes, allocates them with 128 times. The patch fixed bug http://bugzilla.kernel.org/show_bug.cgi?id=14989 Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/libipw.h | 2 +- drivers/net/wireless/ipw2x00/libipw_module.c | 37 +++++++++++++--------------- 2 files changed, 18 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2x00/libipw.h b/drivers/net/wireless/ipw2x00/libipw.h index bf45391172f..a6d5e42647e 100644 --- a/drivers/net/wireless/ipw2x00/libipw.h +++ b/drivers/net/wireless/ipw2x00/libipw.h @@ -797,7 +797,7 @@ struct libipw_device { /* Probe / Beacon management */ struct list_head network_free_list; struct list_head network_list; - struct libipw_network *networks; + struct libipw_network *networks[MAX_NETWORK_COUNT]; int scans; int scan_age; diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c index 1ae0b2b02c3..2fa55867bd8 100644 --- a/drivers/net/wireless/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/ipw2x00/libipw_module.c @@ -67,16 +67,17 @@ void *libipw_wiphy_privid = &libipw_wiphy_privid; static int libipw_networks_allocate(struct libipw_device *ieee) { - if (ieee->networks) - return 0; - - ieee->networks = - kzalloc(MAX_NETWORK_COUNT * sizeof(struct libipw_network), - GFP_KERNEL); - if (!ieee->networks) { - printk(KERN_WARNING "%s: Out of memory allocating beacons\n", - ieee->dev->name); - return -ENOMEM; + int i, j; + + for (i = 0; i < MAX_NETWORK_COUNT; i++) { + ieee->networks[i] = kzalloc(sizeof(struct libipw_network), + GFP_KERNEL); + if (!ieee->networks[i]) { + LIBIPW_ERROR("Out of memory allocating beacons\n"); + for (j = 0; j < i; j++) + kfree(ieee->networks[j]); + return -ENOMEM; + } } return 0; @@ -97,15 +98,11 @@ static inline void libipw_networks_free(struct libipw_device *ieee) { int i; - if (!ieee->networks) - return; - - for (i = 0; i < MAX_NETWORK_COUNT; i++) - if (ieee->networks[i].ibss_dfs) - kfree(ieee->networks[i].ibss_dfs); - - kfree(ieee->networks); - ieee->networks = NULL; + for (i = 0; i < MAX_NETWORK_COUNT; i++) { + if (ieee->networks[i]->ibss_dfs) + kfree(ieee->networks[i]->ibss_dfs); + kfree(ieee->networks[i]); + } } void libipw_networks_age(struct libipw_device *ieee, @@ -130,7 +127,7 @@ static void libipw_networks_initialize(struct libipw_device *ieee) INIT_LIST_HEAD(&ieee->network_free_list); INIT_LIST_HEAD(&ieee->network_list); for (i = 0; i < MAX_NETWORK_COUNT; i++) - list_add_tail(&ieee->networks[i].list, + list_add_tail(&ieee->networks[i]->list, &ieee->network_free_list); } -- cgit v1.2.3 From 8bd8beab49fec3f7d014c328641bd94de3df744b Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Tue, 9 Mar 2010 16:55:23 +0900 Subject: ath5k: use fixed antenna for tx descriptors when using a fixed antenna we should use the antenna number in all tx descriptors, otherwise the hardware will sometimes send the frame out on the other antenna. it seems like the hardware does not always respect the default antenna and diversity settings (esp. AR5K_STA_ID1_DEFAULT_ANTENNA). also i would like to note that antenna diversity does not always work correctly on 5414 (at least) when only one antenna is connected: for example all frames might be received on antenna A but still the HW tries to send on antenna B some times, causing packet loss. this is both verified with the antenna statistics output of the previous patch and a spectrum analyzer. Signed-off-by: Bruno Randolf Acked-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/phy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 72474c0ccaf..ffe253ab9be 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1873,7 +1873,7 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode) break; case AR5K_ANTMODE_FIXED_A: def_ant = 1; - tx_ant = 0; + tx_ant = 1; use_def_for_tx = true; update_def_on_tx = false; use_def_for_rts = true; @@ -1882,7 +1882,7 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode) break; case AR5K_ANTMODE_FIXED_B: def_ant = 2; - tx_ant = 0; + tx_ant = 2; use_def_for_tx = true; update_def_on_tx = false; use_def_for_rts = true; -- cgit v1.2.3 From a3b980fd1391e75068ae25f3817728b27bfdb04c Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Tue, 9 Mar 2010 16:55:33 +0900 Subject: ath5k: fix TSF reset to reset the TSF, AR5K_BEACON_RESET_TSF has to be 1, not 0. also we have a function for that so use it. Signed-off-by: Bruno Randolf Acked-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/reset.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index a35a7db0fc4..c780b55020d 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -1379,11 +1379,10 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, ath5k_hw_set_sleep_clock(ah, true); /* - * Disable beacons and reset the register + * Disable beacons and reset the TSF */ - AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE | - AR5K_BEACON_RESET_TSF); - + AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE); + ath5k_hw_reset_tsf(ah); return 0; } -- cgit v1.2.3 From 86415d43efd4f7093979cfa8a80232114266f1a4 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Tue, 9 Mar 2010 16:56:05 +0900 Subject: ath5k: fix I/Q calibration (for real) I/Q calibration was completely broken, resulting in a high number of CRC errors on received packets. before i could see around 10% to 20% CRC errors, with this patch they are between 0% and 3%. 1.) the removal of the mask in commit "ath5k: Fix I/Q calibration (f1cf2dbd0f798b71b1590e7aca6647f2caef1649)" resulted in no mask beeing used when writing the I/Q values into the register. additional errors in the calculation of the values (see 2.) resulted too high numbers, exceeding the masks, so wrong values like 0xfffffffe were written. to be safe we should always use the bitmask when writing parts of a register. 2.) using a (s32) cast for q_coff is a wrong conversion to signed, since we convert to a signed value later by substracting 128. this resulted in too low numbers for Q many times, which were limited to -16 by the boundary check later on. 3.) checked everything against the HAL sources and took over comments and minor optimizations from there. 4.) we can't use ENABLE_BITS when we want to write a number (the number can contain zeros). also always write the correction values first and set ENABLE bit last, like the HAL does. Signed-off-by: Bruno Randolf Cc: stable@kernel.org Acked-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/phy.c | 37 ++++++++++++++++++------------------ drivers/net/wireless/ath/ath5k/reg.h | 1 + 2 files changed, 20 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index ffe253ab9be..eff3323efb4 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1386,38 +1386,39 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, goto done; /* Calibration has finished, get the results and re-run */ + + /* work around empty results which can apparently happen on 5212 */ for (i = 0; i <= 10; i++) { iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR); i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I); q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q); + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, + "iq_corr:%x i_pwr:%x q_pwr:%x", iq_corr, i_pwr, q_pwr); + if (i_pwr && q_pwr) + break; } i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7; q_coffd = q_pwr >> 7; - /* No correction */ - if (i_coffd == 0 || q_coffd == 0) + /* protect against divide by 0 and loss of sign bits */ + if (i_coffd == 0 || q_coffd < 2) goto done; - i_coff = ((-iq_corr) / i_coffd); + i_coff = (-iq_corr) / i_coffd; + i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */ - /* Boundary check */ - if (i_coff > 31) - i_coff = 31; - if (i_coff < -32) - i_coff = -32; + q_coff = (i_pwr / q_coffd) - 128; + q_coff = clamp(q_coff, -16, 15); /* signed 5 bit */ - q_coff = (((s32)i_pwr / q_coffd) - 128); + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, + "new I:%d Q:%d (i_coffd:%x q_coffd:%x)", + i_coff, q_coff, i_coffd, q_coffd); - /* Boundary check */ - if (q_coff > 15) - q_coff = 15; - if (q_coff < -16) - q_coff = -16; - - /* Commit new I/Q value */ - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE | - ((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S)); + /* Commit new I/Q values (set enable bit last to match HAL sources) */ + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_I_COFF, i_coff); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_Q_COFF, q_coff); + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE); /* Re-enable calibration -if we don't we'll commit * the same values again and again */ diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index 4cb9c5df9f4..1464f89b249 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -2187,6 +2187,7 @@ */ #define AR5K_PHY_IQ 0x9920 /* Register Address */ #define AR5K_PHY_IQ_CORR_Q_Q_COFF 0x0000001f /* Mask for q correction info */ +#define AR5K_PHY_IQ_CORR_Q_Q_COFF_S 0 #define AR5K_PHY_IQ_CORR_Q_I_COFF 0x000007e0 /* Mask for i correction info */ #define AR5K_PHY_IQ_CORR_Q_I_COFF_S 5 #define AR5K_PHY_IQ_CORR_ENABLE 0x00000800 /* Enable i/q correction */ -- cgit v1.2.3 From 5f13bfac0718ce6f83ecba3755f224c3790e8d66 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Tue, 9 Mar 2010 16:56:10 +0900 Subject: ath5k: read eeprom IQ calibration values correctly for G mode we read the IQ correction values (i_cal and q_cal) for G mode from a wrong location (the same shifts as for A mode is applied which is incorrect). use correct locations, matching the docs and HAL sources. also we should write IQ correction only when we have that information in the EEPROM, starting from version 4. also write it in the same way as we do in the periodic recalibration (enable last), just to be sure. Signed-off-by: Bruno Randolf Acked-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/eeprom.c | 4 ++-- drivers/net/wireless/ath/ath5k/reset.c | 15 +++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 6a3f4da7fb4..10b52262b23 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -429,8 +429,8 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; AR5K_EEPROM_READ(o++, val); - ee->ee_i_cal[mode] = (val >> 8) & 0x3f; - ee->ee_q_cal[mode] = (val >> 3) & 0x1f; + ee->ee_i_cal[mode] = (val >> 5) & 0x3f; + ee->ee_q_cal[mode] = val & 0x1f; if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) { AR5K_EEPROM_READ(o++, val); diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index c780b55020d..cbf28e37984 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -851,12 +851,15 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1, AR5K_INIT_CYCRSSI_THR1); - /* I/Q correction - * TODO: Per channel i/q infos ? */ - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, - AR5K_PHY_IQ_CORR_ENABLE | - (ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) | - ee->ee_q_cal[ee_mode]); + /* I/Q correction (set enable bit last to match HAL sources) */ + /* TODO: Per channel i/q infos ? */ + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_I_COFF, + ee->ee_i_cal[ee_mode]); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_Q_COFF, + ee->ee_q_cal[ee_mode]); + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE); + } /* Heavy clipping -disable for now */ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_1) -- cgit v1.2.3 From 41093167ec6c1854903a4bc38a37b5740c028984 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 9 Mar 2010 16:05:31 +0800 Subject: ipw2200: use kmalloc for large local variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed below compiler warning: drivers/net/wireless/ipw2x00/ipw2200.c: In function ‘ipw_load_firmware’: drivers/net/wireless/ipw2x00/ipw2200.c:3260: warning: the frame size of 1168 bytes is larger than 1024 bytes Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2200.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 63c2a7ade5f..5c7aa1b1eb5 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -3177,14 +3177,27 @@ static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) int total_nr = 0; int i; struct pci_pool *pool; - u32 *virts[CB_NUMBER_OF_ELEMENTS_SMALL]; - dma_addr_t phys[CB_NUMBER_OF_ELEMENTS_SMALL]; + void **virts; + dma_addr_t *phys; IPW_DEBUG_TRACE("<< : \n"); + virts = kmalloc(sizeof(void *) * CB_NUMBER_OF_ELEMENTS_SMALL, + GFP_KERNEL); + if (!virts) + return -ENOMEM; + + phys = kmalloc(sizeof(dma_addr_t) * CB_NUMBER_OF_ELEMENTS_SMALL, + GFP_KERNEL); + if (!phys) { + kfree(virts); + return -ENOMEM; + } pool = pci_pool_create("ipw2200", priv->pci_dev, CB_MAX_LENGTH, 0, 0); if (!pool) { IPW_ERROR("pci_pool_create failed\n"); + kfree(phys); + kfree(virts); return -ENOMEM; } @@ -3254,6 +3267,8 @@ static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) pci_pool_free(pool, virts[i], phys[i]); pci_pool_destroy(pool); + kfree(phys); + kfree(virts); return ret; } -- cgit v1.2.3 From 3f07d1295191cfa41125e4e61ee2064790070071 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 13 Mar 2010 12:22:16 -0800 Subject: drivers/net/tg3.c: change the field used with the TG3_FLAG_10_100_ONLY constant The constant TG3_FLAG_10_100_ONLY should be used with the tg3_flags field, not the tg3_flags2 field, as done elsewhere in the same file. Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index c3b4fe74cd6..22cf1c446de 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -9776,7 +9776,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) ADVERTISED_Pause | ADVERTISED_Asym_Pause; - if (!(tp->tg3_flags2 & TG3_FLAG_10_100_ONLY)) + if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY)) mask |= ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full; -- cgit v1.2.3 From 2a40018984c5c9647df1c18489449a3a227d9136 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Sat, 13 Mar 2010 12:24:18 -0800 Subject: sky2: Avoid rtnl_unlock without rtnl_lock Make sure we always call rtnl_lock before going down the error path in sky2_resume, which unlocks the rtnl lock. Signed-off-by: Mike McCormack Signed-off-by: David S. Miller --- drivers/net/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 653bdd76ef4..d8ec4c11fd4 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -4863,6 +4863,7 @@ static int sky2_resume(struct pci_dev *pdev) if (!hw) return 0; + rtnl_lock(); err = pci_set_power_state(pdev, PCI_D0); if (err) goto out; @@ -4884,7 +4885,6 @@ static int sky2_resume(struct pci_dev *pdev) sky2_write32(hw, B0_IMSK, Y2_IS_BASE); napi_enable(&hw->napi); - rtnl_lock(); for (i = 0; i < hw->ports; i++) { err = sky2_reattach(hw->dev[i]); if (err) -- cgit v1.2.3 From c251c7f738cd94eb3a1febda318078c661eccb4d Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 13 Mar 2010 12:26:15 -0800 Subject: drivers/net/tulip/eeprom.c: fix bogus "(null)" in tulip init messages On Wed, 2010-03-10 at 08:41 -0800, David Miller wrote: > From: Mikael Pettersson > Date: Wed, 10 Mar 2010 16:33:28 +0100 > > Booting 2.6.34-rc1 on a machine with a tulip nic I see > > a number of kernel messages that include "(null)" where > > previous kernels included the string "tulip0": > CC:'ing the guilty party :-) It's one of the following > commits: Thanks Mikael. Anonymity has some good attributes. Blame avoidance is one of them. I've broad shoulders. It's me, then Dwight Howard... There might be another few of these where ->name or ->dev was used before struct device or net_device was registered. I'll go back and check. tulip_core has: if (tp->flags & HAS_MEDIA_TABLE) { sprintf(dev->name, DRV_NAME "%d", board_idx); /* hack */ tulip_parse_eeprom(dev); strcpy(dev->name, "eth%d"); /* un-hack */ } So I don't feel _too_ bad. tulip_parse_eeprom is done before register_netdev so the logging there can not use netdev_ or dev_(&dev->dev Signed-off-by: Joe Perches Tested-by: Mikael Pettersson Signed-off-by: David S. Miller --- drivers/net/tulip/eeprom.c | 54 +++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 24 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c index 93f4e8309f8..49f05d1431f 100644 --- a/drivers/net/tulip/eeprom.c +++ b/drivers/net/tulip/eeprom.c @@ -143,6 +143,12 @@ static void __devinit tulip_build_fake_mediatable(struct tulip_private *tp) void __devinit tulip_parse_eeprom(struct net_device *dev) { + /* + dev is not registered at this point, so logging messages can't + use dev_ or netdev_ but dev->name is good via a + hack in the caller + */ + /* The last media info list parsed, for multiport boards. */ static struct mediatable *last_mediatable; static unsigned char *last_ee_data; @@ -161,15 +167,14 @@ void __devinit tulip_parse_eeprom(struct net_device *dev) if (ee_data[0] == 0xff) { if (last_mediatable) { controller_index++; - dev_info(&dev->dev, - "Controller %d of multiport board\n", - controller_index); + pr_info("%s: Controller %d of multiport board\n", + dev->name, controller_index); tp->mtable = last_mediatable; ee_data = last_ee_data; goto subsequent_board; } else - dev_info(&dev->dev, - "Missing EEPROM, this interface may not work correctly!\n"); + pr_info("%s: Missing EEPROM, this interface may not work correctly!\n", + dev->name); return; } /* Do a fix-up based on the vendor half of the station address prefix. */ @@ -181,15 +186,14 @@ void __devinit tulip_parse_eeprom(struct net_device *dev) i++; /* An Accton EN1207, not an outlaw Maxtech. */ memcpy(ee_data + 26, eeprom_fixups[i].newtable, sizeof(eeprom_fixups[i].newtable)); - dev_info(&dev->dev, - "Old format EEPROM on '%s' board. Using substitute media control info\n", - eeprom_fixups[i].name); + pr_info("%s: Old format EEPROM on '%s' board. Using substitute media control info\n", + dev->name, eeprom_fixups[i].name); break; } } if (eeprom_fixups[i].name == NULL) { /* No fixup found. */ - dev_info(&dev->dev, - "Old style EEPROM with no media selection information\n"); + pr_info("%s: Old style EEPROM with no media selection information\n", + dev->name); return; } } @@ -217,8 +221,8 @@ subsequent_board: /* there is no phy information, don't even try to build mtable */ if (count == 0) { if (tulip_debug > 0) - dev_warn(&dev->dev, - "no phy info, aborting mtable build\n"); + pr_warning("%s: no phy info, aborting mtable build\n", + dev->name); return; } @@ -234,8 +238,10 @@ subsequent_board: mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0; mtable->csr15dir = mtable->csr15val = 0; - dev_info(&dev->dev, "EEPROM default media type %s\n", - media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]); + pr_info("%s: EEPROM default media type %s\n", + dev->name, + media & 0x0800 ? "Autosense" + : medianame[media & MEDIA_MASK]); for (i = 0; i < count; i++) { struct medialeaf *leaf = &mtable->mleaf[i]; @@ -298,17 +304,17 @@ subsequent_board: } if (tulip_debug > 1 && leaf->media == 11) { unsigned char *bp = leaf->leafdata; - dev_info(&dev->dev, - "MII interface PHY %d, setup/reset sequences %d/%d long, capabilities %02x %02x\n", - bp[0], bp[1], bp[2 + bp[1]*2], - bp[5 + bp[2 + bp[1]*2]*2], - bp[4 + bp[2 + bp[1]*2]*2]); + pr_info("%s: MII interface PHY %d, setup/reset sequences %d/%d long, capabilities %02x %02x\n", + dev->name, + bp[0], bp[1], bp[2 + bp[1]*2], + bp[5 + bp[2 + bp[1]*2]*2], + bp[4 + bp[2 + bp[1]*2]*2]); } - dev_info(&dev->dev, - "Index #%d - Media %s (#%d) described by a %s (%d) block\n", - i, medianame[leaf->media & 15], leaf->media, - leaf->type < ARRAY_SIZE(block_name) ? block_name[leaf->type] : "", - leaf->type); + pr_info("%s: Index #%d - Media %s (#%d) described by a %s (%d) block\n", + dev->name, + i, medianame[leaf->media & 15], leaf->media, + leaf->type < ARRAY_SIZE(block_name) ? block_name[leaf->type] : "", + leaf->type); } if (new_advertise) tp->sym_advertise = new_advertise; -- cgit v1.2.3